Merge "sched: add PF_WAKE_UP_IDLE"
diff --git a/Documentation/ABI/testing/sysfs-bus-msm_subsys b/Documentation/ABI/testing/sysfs-bus-msm_subsys
new file mode 100644
index 0000000..fcfb1d4
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-msm_subsys
@@ -0,0 +1,18 @@
+What:		/sys/bus/msm_subsys/devices/.../name
+Date:		July 2012
+Contact:	Stephen Boyd <sboyd@codeaurora.org>
+Description:
+		Shows the name of the subsystem.
+
+What:		/sys/bus/msm_subsys/devices/.../state
+Date:		July 2012
+Contact:	Stephen Boyd <sboyd@codeaurora.org>
+Description:
+		Shows the state state of a subsystem. Current states
+		supported are:
+
+			OFFLINE - subsystem is offline
+			ONLINE  - subsystem is online
+
+		This file supports poll(3) to detect when a subsystem changes
+		state. Use POLLPRI to detect state changes.
diff --git a/Documentation/devicetree/bindings/arm/msm/bam_dmux.txt b/Documentation/devicetree/bindings/arm/msm/bam_dmux.txt
new file mode 100644
index 0000000..d82284d
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/bam_dmux.txt
@@ -0,0 +1,14 @@
+Qualcomm BAM Data Multiplexer Driver
+
+Required properties:
+- compatible : should be "qcom,bam_dmux"
+- reg : the location and size of the BAM hardware
+- interrupts : the BAM hardware to apps processor interrupt line
+
+Example:
+
+	qcom,bam_dmux@fc834000 {
+		compatible = "qcom,bam_dmux";
+		reg = <0xfc834000 0x7000>;
+		interrupts = <0 29 1>;
+	};
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_bus.txt b/Documentation/devicetree/bindings/arm/msm/msm_bus.txt
new file mode 100644
index 0000000..1ec3081
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/msm_bus.txt
@@ -0,0 +1,34 @@
+MSM Bus Scaling Driver
+
+The msm bus scaling driver provides the ability to configure
+bus performance parameters across the entire chip-set.
+Various clients use MSM scaling APIs to request bandwidth
+between multiple master-slave pairs. The bus driver then finds
+the optimal path between the master and the slave, and aggregates
+the bandwidth and clock requests for all master-slave pairs on
+that path, and programs hardware accordingly.
+
+The device-tree data required for bus-scaling can be embedded within
+the clients' device nodes. The clients can register with the bus driver
+using the following properties:
+
+- qcom,msm_bus,name:		String representing the client-name
+- qcom,msm_bus,num_cases:	Total number of usecases
+- qcom,msm_bus,active_only:	Context flag for requests in active or
+				dual (active & sleep) contex
+- qcom,msm_bus,num_paths:	Total number of master-slave pairs
+- qcom,msm_bus,vectors:		Arrays of unsigned integers representing:
+				master-id, slave-id, arbitrated bandwidth,
+				instantaneous bandwidth
+
+Example:
+
+	qcom,msm_bus,name = "client-name";
+	qcom,msm_bus,num_cases = <3>;
+	qcom,msm_bus,active_only = <0>;
+	qcom,msm_bus,num_paths = <2>;
+	qcom,msm_bus,vectors =
+			<22 512 0 0>, <26 512 0 0>,
+			<22 512 320000 320000000>, <26 512 3200000 320000000>,
+			<22 512 160000 160000000>, <26 512 1600000 160000000>;
+
diff --git a/Documentation/devicetree/bindings/arm/msm/spm-v2.txt b/Documentation/devicetree/bindings/arm/msm/spm-v2.txt
index d8784db..1a19dbb 100644
--- a/Documentation/devicetree/bindings/arm/msm/spm-v2.txt
+++ b/Documentation/devicetree/bindings/arm/msm/spm-v2.txt
@@ -31,7 +31,6 @@
 - qcom,saw2-avs-limit: The AVS limit register
 - qcom,saw2-avs-dly: The AVS delay register is used to specify the delay values
 	between AVS controller requests
-- qcom,saw2-pmic-dly: The delay values for waiting on PMIC response
 - qcom,saw2-pmic-data0..7: Specify the pmic data value and the associated FTS
 	index to send the PMIC data to
 - qcom,saw2-vctl-port: The FTS port used for changing voltage
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
index 6db1150..82e76fc 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
@@ -14,6 +14,16 @@
 - qcom,mdss-pan-bpp:			Specifies the panel bits per pixel. Default value is 24(rgb888).
 					18 = for rgb666
 					16 = for rgb565
+- qcom,panel-phy-regulatorSettings:	An array of length 8 that specifies the PHY
+					regulator settings for the panel.
+- qcom,panel-phy-timingSettings:	An array of length 12 that specifies the PHY
+					timing settings for the panel.
+- qcom,panel-phy-strengthCtrl:		An array of length 2 that specifies the PHY
+					strengthCtrl settings for the panel.
+- qcom,panel-phy-bistCtrl:		An array of length 6 that specifies the PHY
+					BIST ctrl settings for the panel.
+- qcom,panel-phy-laneConfig:		An array of length 45 that specifies the PHY
+					lane configuration settings for the panel.
 - 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:
@@ -42,9 +52,16 @@
 
 Optional properties:
 - label:		        	A string used as a descriptive name of the panel
+- qcom,enable-gpio:			Specifies the panel lcd/display enable gpio.
+- qcom,rst-gpio:			Specifies the panel reset gpio.
 - 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-ctrl:		A string that specifies the implementation of backlight
+					control for this panel.
+					"bl_ctrl_pwm" = Backlight controlled by PWM gpio.
+					"bl_ctrl_wled" = Backlight controlled by WLED.
+					"bl_ctrl_dcs_cmds" = Backlight controlled by DCS commands.
 - qcom,mdss-pan-bl-levels:		Specifies the backlight levels supported by the panel.
 					Default range is 1 to 255.
 
diff --git a/Documentation/devicetree/bindings/fb/mdss-mdp.txt b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
new file mode 100644
index 0000000..478e335
--- /dev/null
+++ b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
@@ -0,0 +1,23 @@
+Qualcomm MDSS MDP
+
+MDSS is Mobile Display SubSystem which implements Linux framebuffer APIs to
+drive user interface to different panel interfaces. MDP driver is the core of
+MDSS which manage all data paths to different panel interfaces.
+
+Required properties
+- compatible :		Must be "qcom,mdss_mdp"
+- reg :			offset and length of the register set for the device.
+- reg-names :		names to refer to register sets related to this device
+- interrupts :		Interrupt associated with MDSS.
+- vdd-supply :		Phandle for vdd regulator device node.
+
+Example:
+	qcom,mdss_mdp@fd900000 {
+		compatible = "qcom,mdss_mdp";
+		reg = <0xfd900000 0x22100>,
+			<0xfd924000 0x1000>;
+		reg-names = "mdp_phys", "vbif_phys";
+		interrupts = <0 72 0>;
+		vdd-supply = <&gdsc_mdss>;
+	};
+
diff --git a/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt b/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt
new file mode 100644
index 0000000..70fea73
--- /dev/null
+++ b/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt
@@ -0,0 +1,50 @@
+* Qualcomm HDMI Tx
+
+Required properties:
+- cell-index: hdmi tx controller index
+- compatible: must be "qcom,hdmi-tx"
+- reg: offset and length of the register regions(s) for the device.
+- reg-names: a list of strings that map in order to the list of regs.
+
+- <supply-name>-supply: phandle to the regulator device tree node.
+- <compatible-name>-supply-names: a list of strings that map in order
+  to the list of supplies.
+- <<compatible-name>-supply-type: a type of supply(ies) mentioned above.
+    0 = supply with controlled output
+    1 = supply without controlled output. i.e. voltage switch
+- <compatible-name>-min-voltage-level: specifies minimum voltage level
+  of supply(ies) mentioned above.
+- <compatible-name>-max-voltage-level: specifies maximum voltage level
+  of supply(ies) mentioned above.
+- <compatible-name>-op-mode: specifies optimum operating mode of
+  supply(ies) mentioned above.
+
+- gpios: specifies gpios assigned for the device.
+- <compatible-name>-gpio-names: a list of strings that map in order to
+  the list of gpios
+
+Example:
+	qcom,hdmi_tx@fd922100 {
+		cell-index = <0>;
+		compatible = "qcom,hdmi-tx";
+		reg =	<0xfd922100 0x35C>,
+			<0xfd922500 0x7C>,
+			<0xfc4b8000 0x60F0>;
+		reg-names = "core_physical", "phy_physical", "qfprom_physical";
+
+		hpd-5v-supply = <&pm8941_mvs2>;
+		core-vdda-supply = <&pm8941_l12>;
+		core-vcc-supply = <&pm8941_s3>;
+		qcom,hdmi-tx-supply-names = "hpd-5v", "core-vdda", "core-vcc";
+		qcom,hdmi-tx-supply-type = <0 1 1>;
+		qcom,hdmi-tx-min-voltage-level = <0 1800000 1800000>;
+		qcom,hdmi-tx-max-voltage-level = <0 1800000 1800000>;
+		qcom,hdmi-tx-op-mode = <0 1800000 0>;
+
+		gpios = <&msmgpio 31 0>,
+			<&msmgpio 32 0>,
+			<&msmgpio 33 0>,
+			<&msmgpio 34 0>;
+		qcom,hdmi-tx-gpio-names =
+			"cec-pin", "hpd-ddc-clk", "hpd-ddc-data", "hpd-pin";
+	};
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/input/touchscreen/atmel-mxt-ts.txt b/Documentation/devicetree/bindings/input/touchscreen/atmel-mxt-ts.txt
new file mode 100644
index 0000000..a6c83d0
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/atmel-mxt-ts.txt
@@ -0,0 +1,128 @@
+Atmel touch controller
+
+Required properties:
+
+ - compatible	: should be "atmel,mxt-ts"
+ - reg			: i2c slave address of the device
+ - interrupt-parent	: parent of interrupt
+ - interrupts		: touch sample interrupt to indicate presense or release
+				of fingers on the panel.
+ - atmel,panel-coords	: touch panel minimum x, minimum y, maximum x and
+				maximum y resolution
+ - atmel,display-coords : LCD display minimum x, minimum y, maximum x and
+				maximum y resolution
+ - vdd_ana-supply	: Analog power supply needed to power device
+ - atmel,irq-gpio	: irq gpio
+ - atmel,reset-gpio	: reset gpio
+ - atmel,family-id	: family identification of the controller
+ - atmel,variant-id	: variant identification of the controller
+ - atmel,version	: firmware version of the controller
+ - atmel,build	i	: firmware build number of the controller
+ - atmel,bootldr-id	: bootloader identification of the controller
+ - atmel,fw-name	: firmware name to used for flashing firmware
+
+Optional property:
+ - atmel,config			: configuration parameter for the controller
+ - atmel,i2c-pull-up		: specify to indicate pull up is needed
+ - vcc_i2c-supply		: Power source required to pull up i2c bus
+ - atmel,dig-reg-support	: specify to indicate digital regulator is
+					needed
+
+Example:
+	i2c@f9966000 {
+		cell-index = <3>;
+		compatible = "qcom,i2c-qup";
+		reg = <0xf9966000 0x1000>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg-names = "qup_phys_addr";
+		interrupts = <0 104 0>;
+		interrupt-names = "qup_err_intr";
+		qcom,i2c-bus-freq = <100000>;
+		qcom,i2c-src-freq = <24000000>;
+
+		atmel_mxt_ts@4a {
+			compatible = "atmel,mxt-ts";
+			reg = <0x4a>
+			interrupt-parent = <&msmgpio>
+			interrupts = <48 0x0>;
+			vdd_ana-supply = <&pm8941_l18>;
+			vcc_i2c-supply = <&pm8941_lvs1>;
+			atmel,panel-coords = <0 0 479 799>;
+			atmel,display-coords = <0 0 479 799>;
+			atmel,i2c-pull-up = <1>;
+			atmel,dig-reg-support;
+			atmel,key-codes = <
+				102 139 0 0 0 0 0 0
+				0 158 217 0 0 0 0 0
+				0 0 0 0 0 0 0 0
+				0 0 0 0 0 0 0 0 >;
+			atmel,irq-gpio = <&msmgpio 48 0>;
+			atmel,reset-gpio = <&msmgpio 26 0>;
+			atmel,cfg_1 {
+				atmel,family-id = <0x81>;
+				atmel,variant-id = <0x01>;
+				atmel,version = <0x10>;
+				atmel,build = <0xaa>;
+				atmel,config = [
+					/* Object 6, Instance = 0 */
+					00 00 00 00 00 00
+					/* Object 38, Instance = 0 */
+					15 00 02 10 08 0C 00 00
+					/* Object 7, Instance = 0 */
+					FF FF 32 03
+					/* Object 8, Instance = 0 */
+					0F 00 0A 0A 00 00 0A 00 00 00
+					/* Object 9, Instance = 0 */
+					83 00 00 18 0E 00 70 32 02 01
+					00 03 01 01 05 0A 0A 0A 90 05
+					F8 02 00 00 0F 0F 00 00 48 2D
+					07 0C 00 00 00 00
+					/* Object 15, Instance = 0 */
+					00 00 00 00 00 00 00 00 00 00
+					00
+					/* Object 18, Instance = 0 */
+					00 00
+					/* Object 19, Instance = 0 */
+					00 00 00 00 00 00
+					/* Object 23, Instance = 0 */
+					00 00 00 00 00 00 00 00 00 00
+					00 00 00 00 00
+					/* Object 25, Instance = 0 */
+					00 00 00 00 00 00 00 00 00 00
+					00 00 00 00 00
+					/* Object 40, Instance = 0 */
+					00 00 00 00 00
+					/* Object 42, Instance = 0 */
+					00 00 00 00 00 00 00 00 00 00
+					/* Object 46, Instance = 0 */
+					00 00 10 10 00 00 03 00 00 01
+					/* Object 47, Instance = 0 */
+					08 0A 28 0A 02 0A 00 8C 00 20
+					00 00 00
+					/* Object 55, Instance = 0 */
+					00 00 00 00 00 00
+					/* Object 56, Instance = 0 */
+					03 00 01 18 05 05 05 05 05 05
+					05 05 05 05 05 05 05 05 05 05
+					05 05 05 05 05 05 05 05 00 00
+					00 00 00 00 00 00 00 00 00 00
+					00 00
+					/* Object 57, Instance = 0 */
+					00 00 00
+					/* Object 61, Instance = 0 */
+					00 00 00 00 00
+					/* Object 61, Instance = 1 */
+					00 00 00 00 00
+					/* Object 62, Instance = 0 */
+					7F 03 00 16 00 00 00 00 00 00
+					04 08 10 18 05 00 0A 05 05 50
+					14 19 34 1A 64 00 00 04 40 00
+					00 00 00 00 30 32 02 00 01 00
+					05 00 00 00 00 00 00 00 00 00
+					00 00 0C 00
+					];
+			}
+
+		}
+	};
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp.txt b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
new file mode 100644
index 0000000..51bf9e6
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
@@ -0,0 +1,57 @@
+Qualcomm QPNP Leds
+
+QPNP (Qualcomm Plug N Play) LEDs driver is used for
+controlling LEDs that are part of PMIC on Qualcomm reference
+platforms. The PMIC is connected to Host processor via
+SPMI bus. This driver supports various LED modules such as
+WLED (white LED), RGB LED and flash LED. The first version of
+the driver supports WLED and other features are added in the
+next versions.
+
+Required Properties:
+- compatible	: should be "qcom,leds-qpnp"
+
+Each LED module is represented as a node of "leds-qpnp". This
+node will furthur contain the type of LED supported and its
+properties.
+
+Required properties:
+- qcom,id		: must be one of values supported in enum qpnp_led
+- qcom,label		: type of led that will be used, ie "wled"
+- qcom,max-current	: maximum current that the LED can sustain
+= qcom,name		: name the led will be called by in sysfs entry
+
+WLED is primarily used as display backlight. Display subsystem uses
+LED triggers for WLED to control the brightness as needed.
+
+Optional properties for WLED:
+- qcom,num-strings: number of wled strings supported
+- qcom,ovp_val: over voltage protection threshold,
+		follows enum wled_ovp_threshold
+- qcom,boost_curr_lim: boot currnet limit, follows enum wled_current_bost_limit
+- qcom,ctrl_delay_us: delay in activation of led
+- qcom,dig_mod_gen_en: digital module generator
+- qcom,cs_out_en: current sink output enable
+- qcom,op_fdbck: selection of output as feedback for the boost
+- qcom,cp_select: high pole capacitance
+- linux,default-trigger: trigger the led from external modules such as display
+- qcom,default-state:  default state of the led, should be "on" or "off"
+
+Example:
+
+	qcom,leds@d800 {
+			compatible = "qcom,leds-qpnp";
+			reg = <0xD800 0x100>;
+			linux,default-trigger = "bkl-trigger"
+			qcom,label = "wled";
+			qcom,cs-out-en;
+			qcom,op-fdbck;
+			qcom,default-state "off";
+			qcom,max-current = <25>;
+			qcom,ctrl-delay-us = <0>;
+			qcom,boost-curr-lim = <3>;
+			qcom,cp-sel = <0>;
+			qcom,switch-freq = <2>;
+			qcom,ovp-val = <2>;
+			qcom,num-strings = <1>;
+	}
diff --git a/Documentation/devicetree/bindings/media/video/msm-cci.txt b/Documentation/devicetree/bindings/media/video/msm-cci.txt
index 75916e5..6b03fab 100644
--- a/Documentation/devicetree/bindings/media/video/msm-cci.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-cci.txt
@@ -1,5 +1,6 @@
 * Qualcomm MSM CCI
 
+[First level nodes]
 Required properties:
 - cell-index: cci hardware core index
 - compatible :
@@ -11,6 +12,102 @@
 - interrupt-names : should specify relevant names to each interrupts
   property defined.
 
+[Second level nodes]
+* Qualcomm MSM Sensor
+
+MSM sensor node contains properties of camera sensor
+
+Required properties:
+- compatible : should be "qcom" followed by sensor name
+    - "qcom,s5k3l1yx"
+- reg : should contain i2c slave address of the camera sensor and
+    length of data field which is 0x0
+- qcom,csi-if : should contain number of csid cores required at the receiver
+    side
+    - 1 for 2D sensor
+    - 2 for 3D sensor
+- qcom,csid-core : should contain csid core instance that will used to receive
+    sensor data
+    - 0, 1, 2, 3
+- qcom,is-vpe : should be enabled if VPE module is required for post processing
+    of this sensor
+    - 1 if required, 0 otherwise
+- qcom,sensor-name : should contain unique sensor name to differentiate from
+    other sensor
+    - "s5k3l1yx"
+- cam_vdig-supply : should contain regulator from which digital voltage is
+    supplied
+- cam_vana-supply : should contain regulator from which analog voltage is
+    supplied
+- cam_vio-supply : should contain regulator from which IO voltage is supplied
+- qcom,cam-vreg-name : should contain names of all regulators needed by this
+    sensor
+    - "cam_vdig", "cam_vana", "cam_vio", "cam_vaf"
+- qcom,cam-vreg-type : should contain regulator type for regulators mentioned in
+    qcom,cam-vreg-name property (in the same order)
+    - 0 for LDO and 1 for LVS
+- qcom,cam-vreg-min-voltage : should contain minimum voltage level for
+    regulators mentioned in qcom,cam-vreg-name property (in the same order)
+- qcom,cam-vreg-max-voltage : should contain maximum voltage level for
+    regulators mentioned in qcom,cam-vreg-name property (in the same order)
+- qcom,cam-vreg-op-mode : should contain optimum voltage level for regulators
+    mentioned in qcom,cam-vreg-name property (in the same order)
+- qcom,camera-type : should contain sensor type
+    - 0 -> back camera 2D
+    - 1 -> front camera 2D
+    - 2 -> back camera 3D
+    - 3 -> back camera int 3D
+- qcom,sensor-type : should contain format of data that sensor streams
+    - 0 -> bayer format
+    - 1 -> yuv format
+
+Optional properties:
+- qcom,flash-type : should contain flash type if flash is supported for this
+    sensor
+    - 0 if flash is not supported, 1 if flash is supported
+- qcom,mount-angle : should contain the physical mount angle of the sensor on
+    the target
+    - 0, 90, 180, 360
+- qcom,gpio-no-mux : should contain field to indicate whether gpio mux table is
+    available
+    - 1 if gpio mux is not available, 0 otherwise
+- cam_vaf-supply : should contain regulator from which AF voltage is supplied
+- gpios : should contain phandle to gpio controller node and array of
+    #gpio-cells specifying specific gpio (controller specific)
+- qcom,gpio-common-tbl-num : should contain index to gpios shared between
+    different sensors
+- qcom,gpio-common-tbl-flags : should contain direction of gpios present in
+    qcom,gpio-common-tbl-num property (in the same order)
+- qcom,gpio-common-tbl-label : should contain name of gpios present in
+    qcom,gpio-common-tbl-num property (in the same order)
+- qcom,gpio-req-tbl-num : should contain index to gpios specific to this sensor
+- qcom,gpio-req-tbl-flags : should contain direction of gpios present in
+    qcom,gpio-req-tbl-num property (in the same order)
+- qcom,gpio-req-tbl-label : should contain name of gpios present in
+    qcom,gpio-req-tbl-num property (in the same order)
+- qcom,gpio-set-tbl-num : should contain index of gpios that need to be
+    configured by msm
+- qcom,gpio-set-tbl-flags : should contain value to be configured for the gpios
+    present in qcom,gpio-set-tbl-num property (in the same order)
+- qcom,gpio-set-tbl-delay : should contain amount of delay after configuring
+    gpios as specified in gpio_set_tbl_flags property (in the same order)
+- qcom,csi-lane-assign : should contain lane assignment value to map CSIPHY
+    lanes to CSID lanes
+    - 0x4320
+- qcom,csi-lane-mask : should contain lane mask that specifies CSIPHY lanes to
+    be enabled
+- qcom,csi-phy-sel : should contain CSIPHY core instance from which CSID should
+    receive data
+- qcom,actuator-cam-name : should contain actuator cam name associated with
+    this sensor
+    - If actuator does not exist, this property should not be initialized
+    - If actuator exist, this field should indicate the index of actuator to
+      be used
+- qcom,actuator-vcm-pwd : should contain the gpio pin of vcm power to be enabled
+    for actuator
+- qcom,actuator-vcm-enable : should contain value to be set for actuator vcm
+    gpio
+
 Example:
 
    qcom,cci@0xfda0c000 {
@@ -20,4 +117,43 @@
        reg-names = "cci";
        interrupts = <0 50 0>;
        interrupt-names = "cci";
+       qcom,s5k3l1yx@6e {
+               compatible = "qcom,s5k3l1yx";
+               reg = <0x6e 0x0>;
+               qcom,csi-if = <1>;
+               qcom,csid-core = <0>;
+               qcom,is-vpe = <1>;
+               qcom,flash-type = <0>;
+               qcom,mount-angle = <90>;
+               qcom,sensor-name = "s5k3l1yx";
+               cam_vdig-supply = <&pm8941_l3>;
+               cam_vana-supply = <&pm8941_l17>;
+               cam_vio-supply = <&pm8941_lvs3>;
+               cam_vaf-supply = <&pm8941_l23>;
+               qcom,cam-vreg-name = "cam_vdig", "cam_vana", "cam_vio", "cam_vaf";
+               qcom,cam-vreg-type = <0 0 1 0>;
+               qcom,cam-vreg-min-voltage = <1225000 2850000 0 3000000>;
+               qcom,cam-vreg-max-voltage = <1225000 2850000 0 3000000>;
+               qcom,cam-vreg-op-mode = <105000 80000 0 100000>;
+               qcom,gpio-no-mux = <0>;
+               gpios = <&msmgpio 15 0>,
+                       <&msmgpio 19 0>,
+                       <&msmgpio 20 0>,
+                       <&msmgpio 90 0>;
+               qcom,gpio-common-tbl-num = <0 1 2>;
+               qcom,gpio-common-tbl-flags = <1 1 1>;
+               qcom,gpio-common-tbl-label = "CAMIF_MCLK", "CAMIF_I2C_DATA",
+                                            "CAMIF_I2C_CLK";
+               qcom,gpio-req-tbl-num = <3>;
+               qcom,gpio-req-tbl-flags = <0>;
+               qcom,gpio-req-tbl-label = "CAM_RESET1";
+               qcom,gpio-set-tbl-num = <3 3>;
+               qcom,gpio-set-tbl-flags = <0 2>;
+               qcom,gpio-set-tbl-delay = <1000 4000>;
+               qcom,csi-lane-assign = <0x4320>;
+               qcom,csi-lane-mask = <0x1F>;
+               qcom,csi-phy-sel = <0>;
+               qcom,camera-type = <0>;
+               qcom,sensor-type = <0>;
+       };
    };
diff --git a/Documentation/devicetree/bindings/mmc/msm_sdcc.txt b/Documentation/devicetree/bindings/mmc/msm_sdcc.txt
index c674a13..5f7651a 100644
--- a/Documentation/devicetree/bindings/mmc/msm_sdcc.txt
+++ b/Documentation/devicetree/bindings/mmc/msm_sdcc.txt
@@ -5,8 +5,12 @@
 
 Required properties:
   - compatible : should be "qcom,msm-sdcc"
-  - reg : should contain SDCC, BAM register map.
+  - reg : should contain SDCC, SDCC-DML and BAM register map.
+  - reg-names : indicates various resources passed to driver (via reg proptery) by name.
+  "reg-names" examples are "core_mem", "dml_mem" and "bam_mem"
   - interrupts : should contain SDCC core interrupt.
+  - interrupt-names : indicates interrupts passed to driver (via interrupts property) by name.
+  "interrupt-names" examples are "core_irq", "bam_irq" and "status_irq"
   - qcom,sdcc-clk-rates : specifies supported SDCC clock frequencies, Units - Hz.
   - qcom,sdcc-sup-voltages: specifies supported voltage ranges for card. Should always be
 			specified in pairs (min, max), Units - mV.
diff --git a/Documentation/devicetree/bindings/mtd/msm_qpic_nand.txt b/Documentation/devicetree/bindings/mtd/msm_qpic_nand.txt
index bddbbae..8cef7f0 100644
--- a/Documentation/devicetree/bindings/mtd/msm_qpic_nand.txt
+++ b/Documentation/devicetree/bindings/mtd/msm_qpic_nand.txt
@@ -38,14 +38,15 @@
 	       #size-cells = <1>;
                partition@0 {
                        label = "boot";
-                       reg = <0x00000000 0x1000>;
+                       reg = <0x0 0x1000>;
+		       read-only;
                };
-               partition@00020000 {
+               partition@20000 {
                        label = "userdata";
-                       reg = <0x00020000 0x1000>;
+                       reg = <0x20000 0x1000>;
                };
-               partition@00040000 {
+               partition@40000 {
                        label = "system";
-                       reg = <0x00040000 0x1000>;
+                       reg = <0x40000 0x1000>;
                };
        };
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/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/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 84f0c24..0eb186e 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -30,6 +30,12 @@
 
  - compatible : "qcom,msm-voip-dsp"
 
+* msm-pcm-voice
+
+Required properties:
+
+ - compatible : "qcom,msm-pcm-voice"
+
 * msm-stub-codec
 
 Required properties:
@@ -196,3 +202,55 @@
 		qcom,msm-ocmem-audio-ib = <471859200>;
 	};
 
+* MSM8974 ASoC Machine driver
+
+Required properties:
+- compatible : "qcom,msm8974-audio-taiko"
+- qcom,model : The user-visible name of this sound card.
+- qcom,audio-routing : A list of the connections between audio components.
+  Each entry is a pair of strings, the first being the connection's sink,
+  the second being the connection's source.
+- qcom,cdc-mclk-gpios : GPIO on which mclk signal is comming.
+- taiko-mclk-clk : phandle to PMIC8941 clkdiv1 node.
+- qcom,taiko-mclk-clk-freq : Taiko mclk Freq in Hz. currently only 9600000Hz
+				is supported.
+
+Example:
+
+sound {
+	compatible = "qcom,msm8974-audio-taiko";
+	qcom,model = "msm8974-taiko-snd-card";
+
+	qcom,audio-routing =
+		"RX_BIAS", "MCLK",
+		"LDO_H", "MCLK",
+		"HEADPHONE", "LDO_H",
+		"Ext Spk Bottom Pos", "LINEOUT1",
+		"Ext Spk Bottom Neg", "LINEOUT3",
+		"Ext Spk Top Pos", "LINEOUT2",
+		"Ext Spk Top Neg", "LINEOUT4",
+		"AMIC1", "MIC BIAS1 Internal1",
+		"MIC BIAS1 Internal1", "Handset Mic",
+		"AMIC2", "MIC BIAS2 External",
+		"MIC BIAS2 External", "Headset Mic",
+		"AMIC3", "MIC BIAS3 Internal1",
+		"MIC BIAS3 Internal1", "ANCRight Headset Mic",
+		"AMIC4", "MIC BIAS1 Internal2",
+		"MIC BIAS1 Internal2", "ANCLeft Headset Mic",
+		"DMIC1", "MIC BIAS1 External",
+		"MIC BIAS1 External", "Digital Mic1",
+		"DMIC2", "MIC BIAS1 External",
+		"MIC BIAS1 External", "Digital Mic2",
+		"DMIC3", "MIC BIAS3 External",
+		"MIC BIAS3 External", "Digital Mic3",
+		"DMIC4", "MIC BIAS3 External",
+		"MIC BIAS3 External", "Digital Mic4",
+		"DMIC5", "MIC BIAS4 External",
+		"MIC BIAS4 External", "Digital Mic5",
+		"DMIC6", "MIC BIAS4 External",
+		"MIC BIAS4 External", "Digital Mic6";
+
+	qcom,cdc-mclk-gpios = <&pm8941_gpios 15 0>;
+	taiko-mclk-clk = <&pm8941_clkdiv1>;
+	qcom,taiko-mclk-clk-freq = <9600000>;
+};
diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
index 8a4b833..9c2ce6c 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -35,6 +35,13 @@
   0 will be treated as 500mA
 - qcom,hsusb-otg-pclk-src-name: The source of pclk
 - qcom,hsusb-otg-pmic-id-irq: ID, routed to PMIC IRQ number
+- Refer to "Documentation/devicetree/bindings/arm/msm/msm_bus.txt" for
+  below optional properties:
+    - qcom,msm_bus,name
+    - qcom,msm_bus,num_cases
+    - qcom,msm_bus,active_only
+    - qcom,msm_bus,num_paths
+    - qcom,msm_bus,vectors
 
 Example HSUSB OTG controller device node :
 	usb@f9690000 {
@@ -51,17 +58,49 @@
 		qcom,hsusb-otg-power-budget = <500>;
 		qcom,hsusb-otg-pclk-src-name = "dfab_usb_clk";
 		qcom,hsusb-otg-pmic-id-irq = <47>
+
+		qcom,msm_bus,name = "usb2";
+		qcom,msm_bus,num_cases = <2>;
+		qcom,msm_bus,active_only = <0>;
+		qcom,msm_bus,num_paths = <1>;
+		qcom,msm_bus,vectors =
+				<87 512 0 0>,
+				<87 512 60000000 960000000>;
 	};
 
+ANDROID USB:
+
+Required properties:
+- compatible: should be "qcom,android-usb"
+
+Optional properties :
+- reg  : offset and length of memory region that is used by driver to
+  update USB PID and serial numbers used by bootloader in DLOAD mode.
+
+Example Android USB device node :
+	android_usb@fc42b0c8 {
+		compatible = "qcom,android-usb";
+		reg = <0xfc42b0c8 0xc8>;
+	};
+
+
 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
+- reg  : pairs of physical base addresses and region sizes
+            of all the memory mapped BAM devices present
+- reg-names : Register region name(s) referenced in reg above
+            SSUSB BAM expects "ssusb" and "hsusb" for HSSUB BAM.
+            Specify "qscratch_ram1_reg" to provide QSCRATCH's RAM1
+            register to control USB3 private memory for uses as BAM FIFOs.
+- interrupts: IRQ lines for BAM devices
+- interrupt-names: BAM interrupt name(s) referenced in interrupts above
+            SSUSB BAM expects "ssusb" and "hsusb" for HSSUB BAM
 - qcom,usb-active-bam: active BAM type. Can be one of
-            0 - HSUSB_BAM
-            1 - HSIC_BAM
+            0 - SSUSB_BAM
+            1 - HSUSB_BAM
+            2 - 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
@@ -69,10 +108,15 @@
 A number of USB BAM pipe parameters are represented as sub-nodes:
 
 Subnode Required:
-- label: a string describing the pipe's direction and use
+- label: a string describing the pipe's direction and BAM instance under use
 - qcom,usb-bam-type: BAM type. Can be one of
-            0 - HSUSB_BAM
-            1 - HSIC_BAM
+            0 - SSUSB_BAM
+            1 - HSUSB_BAM
+            2 - HSIC_BAM
+- qcom,usb-bam-mem-type: Type of memory used by this PIPE. Can be one of
+            0 - Uses SPS's dedicated pipe memory
+            1 - USB's private memory residing @ 'qcom,usb-base-address'
+            2 - System RAM allocated by driver
 - 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
@@ -82,20 +126,30 @@
 - qcom,descriptor-fifo-offset: descriptor fifo offset address
 - qcom,descriptor-fifo-size: descriptor fifo size
 
+Optional properties :
+- qcom,ignore-core-reset-ack: If present then BAM ignores ACK from USB core
+	    while performing PIPE RESET
+
 Example USB BAM controller device node:
 
 	qcom,usbbam@f9304000 {
 		compatible = "qcom,usb-bam-msm";
-		reg = <0xf9304000 0x9000>;
-		interrupts = <0 132 0>;
+		reg = <0xf9304000 0x5000>,
+		      <0xf9a44000 0x11000>,
+		      <0xf92f880c 0x4>;
+		reg-names = "ssusb", "hsusb", "qscratch_ram1_reg";
+		interrupts = <0 132 0 0 135 0>;
+		interrupt-names = "ssusb", "hsusb";
 		qcom,usb-active-bam = <0>;
-		qcom,usb-total-bam-num = <1>;
+		qcom,usb-total-bam-num = <2>;
 		qcom,usb-bam-num-pipes = <16>;
 		qcom,usb-base-address = <0xf9200000>;
+		qcom,ignore-core-reset-ack;
 
 		qcom,pipe1 {
 			label = "usb-to-peri-qdss-dwc3";
 			qcom,usb-bam-type = <0>;
+			qcom,usb-bam-mem-type = <1>;
 			qcom,src-bam-physical-address = <0>;
 			qcom,src-bam-pipe-index = <0>;
 			qcom,dst-bam-physical-address = <0>;
@@ -109,6 +163,7 @@
 		qcom,pipe2 {
 			label = "peri-to-usb-qdss-dwc3";
 			qcom,usb-bam-type = <0>;
+			qcom,usb-bam-mem-type = <1>;
 			qcom,src-bam-physical-address = <0xfc37C000>;
 			qcom,src-bam-pipe-index = <0>;
 			qcom,dst-bam-physical-address = <0xf9304000>;
@@ -118,4 +173,32 @@
 			qcom,descriptor-fifo-offset = <0xf4000>;
 			qcom,descriptor-fifo-size = <0x1400>;
 		};
+
+		qcom,pipe3 {
+			label = "usb-to-peri-qdss-hsusb";
+			qcom,usb-bam-type = <1>;
+			qcom,usb-bam-mem-type = <1>;
+			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,pipe4 {
+			label = "peri-to-usb-qdss-hsusb";
+			qcom,usb-bam-type = <1>;
+			qcom,usb-bam-mem-type = <1>;
+			qcom,src-bam-physical-address = <0xfc37c000>;
+			qcom,src-bam-pipe-index = <0>;
+			qcom,dst-bam-physical-address = <0xf9a44000>;
+			qcom,dst-bam-pipe-index = <2>;
+			qcom,data-fifo-offset = <0xf4000>;
+			qcom,data-fifo-size = <0x1000>;
+			qcom,descriptor-fifo-offset = <0xf5000>;
+			qcom,descriptor-fifo-size = <0x400>;
+		};
 	};
diff --git a/Documentation/devicetree/bindings/usb/msm-ssusb.txt b/Documentation/devicetree/bindings/usb/msm-ssusb.txt
index a2b7dfc..9cc9e6e 100644
--- a/Documentation/devicetree/bindings/usb/msm-ssusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-ssusb.txt
@@ -3,6 +3,8 @@
 Required properties :
 - compatible : should be "qcom,dwc-usb3-msm"
 - reg : offset and length of the register set in the memory map
+	offset and length of the TCSR register for routing USB
+	signals to either picoPHY0 or picoPHY1.
 - interrupts: IRQ lines used by this controller
 - interrupt-names : Required interrupt resource entries are:
 	"irq" : Interrupt for DWC3 core
@@ -15,10 +17,20 @@
   the MSM USB3.0 core (which also includes the Synopsys DesignWare
   USB3.0 controller)
 
+Optional properties :
+- Refer to "Documentation/devicetree/bindings/arm/msm/msm_bus.txt" for
+  below optional properties:
+    - qcom,msm_bus,name
+    - qcom,msm_bus,num_cases
+    - qcom,msm_bus,active_only
+    - qcom,msm_bus,num_paths
+    - qcom,msm_bus,vectors
+
 Example MSM USB3.0 controller device node :
 	usb@f9200000 {
 		compatible = "qcom,dwc-usb3-msm";
-		reg = <0xF9200000 0xFA000>;
+		reg = <0xF9200000 0xFA000>,
+		      <0xFD4AB000 0x4>;
 		interrupts = <0 131 0 0 179 0>;
 		interrupt-names = "irq", "otg_irq";
 		SSUSB_VDDCX-supply = <&pm8841_s2>;
@@ -27,4 +39,12 @@
 		HSUSB_1p8-supply = <&pm8941_l6>;
 		HSUSB_3p3-supply = <&pm8941_l24>;
 		qcom,dwc-usb3-msm-dbm-eps = <4>
+
+		qcom,msm_bus,name = "usb3";
+		qcom,msm_bus,num_cases = <2>;
+		qcom,msm_bus,active_only = <0>;
+		qcom,msm_bus,num_paths = <1>;
+		qcom,msm_bus,vectors =
+				<61 512 0 0>,
+				<61 512 240000000 960000000>;
 	};
diff --git a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
new file mode 100644
index 0000000..e394b56
--- /dev/null
+++ b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
@@ -0,0 +1,45 @@
+* Qualcomm WCNSS Platform Driver
+
+WCNSS driver is the platform driver. It is used for performing the cold
+boot-up of the wireless device. It is responsible for adjusting
+the necessary I/O rails and enabling appropriate gpios for wireless
+connectivity subsystem.
+
+Required properties:
+- compatible: "wcnss_wlan"
+- reg: offset and length of the register set for the device. The pair
+  corresponds to PRONTO.
+- interupts: Pronto to Apps interrupts for tx done and rx pending.
+- qcom,pronto-vddmx-supply: regulator to supply pronto pll.
+- qcom,pronto-vddcx-supply: regulator to supply WLAN/BT/FM digital module.
+- qcom,pronto-vddpx-supply: regulator to supply WLAN DAC.
+- qcom,iris-vddxo-supply  : regulator to supply RF XO.
+- qcom,iris-vddrfa-supply : regulator to supply RFA digital.
+- qcom,iris-vddpa-supply  : regulator to supply RF PA.
+- qcom,iris-vdddig-supply : regulator to supply RF digital(BT/FM).
+- gpios: gpio numbers to configure 5-wire interface of WLAN connectivity
+- qcom,has_48mhz_xo: boolean flag to determine the usage of 24MHz XO from RF
+- qcom,has_pronto_hw: boolean flag to determine the revId of the WLAN subsystem
+
+Example:
+
+    qcom,wcnss-wlan@fb000000 {
+        compatible = "qcom,wcnss_wlan";
+        reg = <0xfb000000 0x280000>;
+        reg-names = "wcnss_mmio";
+        interrupts = <0 145 0 0 146 0>;
+        interrupt-names = "wcnss_wlantx_irq", "wcnss_wlanrx_irq";
+
+        qcom,pronto-vddmx-supply = <&pm8841_s1>;
+        qcom,pronto-vddcx-supply = <&pm8841_s2>;
+        qcom,pronto-vddpx-supply = <&pm8941_s3>;
+        qcom,iris-vddxo-supply = <&pm8941_l6>;
+        qcom,iris-vddrfa-supply = <&pm8941_l11>;
+        qcom,iris-vddpa-supply = <&pm8941_l19>;
+        qcom,iris-vdddig-supply = <&pm8941_l3>;
+
+        gpios = <&msmgpio 36 0>, <&msmgpio 37 0>, <&msmgpio 38 0>,
+                <&msmgpio 39 0>, <&msmgpio 40 0>;
+        qcom,has_48mhz_xo;
+        qcom,has_pronto_hw;
+    };
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 7930de5..d7ebcfe 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -5,6 +5,7 @@
 	select HAVE_DMA_API_DEBUG
 	select HAVE_IDE if PCI || ISA || PCMCIA
 	select HAVE_DMA_CONTIGUOUS if (CPU_V6 || CPU_V6K || CPU_V7)
+	select HAVE_DMA_ATTRS
 	select HAVE_MEMBLOCK
 	select RTC_LIB
 	select SYS_SUPPORTS_APM_EMULATION
@@ -46,6 +47,14 @@
 config ARM_HAS_SG_CHAIN
 	bool
 
+config NEED_SG_DMA_LENGTH
+	bool
+
+config ARM_DMA_USE_IOMMU
+	select NEED_SG_DMA_LENGTH
+	select ARM_HAS_SG_CHAIN
+	bool
+
 config HAVE_PWM
 	bool
 
diff --git a/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
new file mode 100644
index 0000000..1f7e488
--- /dev/null
+++ b/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
@@ -0,0 +1,119 @@
+/* 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_toshiba_720p_video {
+		compatible = "qcom,mdss-dsi-panel";
+		label = "toshiba 720p video mode dsi panel";
+		status = "disable";
+		qcom,enable-gpio = <&msmgpio 58 0>;
+		qcom,rst-gpio = <&pm8941_gpios 19 0>;
+		qcom,mdss-pan-res = <720 1280>;
+		qcom,mdss-pan-bpp = <24>;
+		qcom,mdss-pan-porch-values = <32 12 144 3 4 9>;
+		qcom,mdss-pan-underflow-clr = <0xff>;
+		qcom,mdss-pan-bl-ctrl = "bl_ctrl_wled";
+		qcom,mdss-pan-bl-levels = <1 255>;
+		qcom,mdss-pan-dsi-mode = <0>;
+		qcom,mdss-pan-dsi-h-pulse-mode = <0>;
+		qcom,mdss-pan-dsi-h-power-stop = <0 0 0>;
+		qcom,mdss-pan-dsi-bllp-power-stop = <1 1>;
+		qcom,mdss-pan-dsi-traffic-mode = <1>;
+		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 1 1>;
+		qcom,mdss-pan-dsi-t-clk = <0x1b 0x04>;
+		qcom,mdss-pan-dsi-stream = <0>;
+		qcom,mdss-pan-dsi-mdp-tr = <0x0>;
+		qcom,mdss-pan-dsi-dma-tr = <0x04>;
+		qcom,mdss-pan-frame-rate = <60>;
+		qcom,panel-phy-regulatorSettings = [03 01 01 00  /* Regualotor settings */
+						    20 00 01 00];
+		qcom,panel-phy-timingSettings = [69 29 1f 00 55 55
+						    19 2a 2a 03 04 00];
+		qcom,panel-phy-strengthCtrl = [77 06];
+		qcom,panel-phy-bistCtrl = [00 00 01 ff           /* BIST Ctrl settings */
+					   00 00];
+		qcom,panel-phy-laneConfig = [05 c2 00 00 00 00 00 01 75 /* lane0 config */
+					     05 c2 00 00 00 00 00 01 75 /* lane1 config */
+					     05 c2 00 00 00 00 00 01 75 /* lane2 config */
+					     05 c2 00 00 00 00 00 01 75 /* lane3 config */
+					     00 c2 00 00 00 00 00 01 97]; /* Clk ln config */
+
+		qcom,panel-on-cmds = [23 01 00 00 0a 02 b0 00
+					23 01 00 00 0a 02 b2 00
+					23 01 00 00 0a 02 b3 0c
+					23 01 00 00 0a 02 b4 02
+					29 01 00 00 00 06
+						c0 40 02 7f c8 08
+					29 01 00 00 00 10
+						c1 00 a8 00 00 00
+						00 00 9d 08 27 00
+						00 00 00 00
+					29 01 00 00 00 06
+						c2 00 00 09 00 00
+					23 01 00 00 0a 02 c3 04
+					29 01 00 00 00 04
+						c4 4d 83 00
+					29 01 00 00 00 0b
+						c6 12 00 08 71 00
+						00 00 80 00 04
+					23 01 00 00 0a 02 c7 22
+					29 01 00 00 00 05
+						c8 4c 0c 0c 0c
+					29 01 00 00 00 0e
+						c9 00 40 00 16 32
+						2e 3a 43 3e 3c 45
+						79 3f
+					29 01 00 00 00 0e
+						ca 00 46 1a 23 21
+						1c 25 31 2d 49 5f
+						7f 3f
+					29 01 00 00 00 0e
+						cb 00 4c 20 3a 42
+						40 47 4b 42 3e 46
+						7e 3f
+					29 01 00 00 00 0e
+						cc 00 41 19 21 1d
+						14 18 1f 1d 25 3f
+						73 3f
+					29 01 00 00 00 0e
+						cd 23 79 5a 5f 57
+						4c 51 51 45 3f 4b
+						7f 3f
+					29 01 00 00 00 0e
+						ce 00 40 14 20 1a
+						0e 0e 13 08 00 05
+						46 1c
+					29 01 00 00 00 04
+						d0 6a 64 01
+					29 01 00 00 00 03 d1 77 d4
+					23 01 00 00 0a 02 d3 33
+					29 01 00 00 00 03 d5 0f 0f
+					29 01 00 00 00 07
+						d8 34 64 23 25 62
+						32
+					29 01 00 00 00 0c
+						de 10 7b 11 0a 00
+						00 00 00 00 00 00
+					29 01 00 00 00 09
+						fd 04 55 53 00 70
+						ff 10 73
+					23 01 00 00 0a 02 e2 00
+					05 01 00 00 78 02 11 00
+					05 01 00 00 32 02 29 00];
+		qcom,panel-off-cmds = [05 01 00 00 32 02 28 00
+					05 01 00 00 78 02 10 00];
+	};
+};
diff --git a/arch/arm/boot/dts/mpq8092-sim.dts b/arch/arm/boot/dts/mpq8092-sim.dts
new file mode 100644
index 0000000..f73abe7
--- /dev/null
+++ b/arch/arm/boot/dts/mpq8092-sim.dts
@@ -0,0 +1,49 @@
+/* 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.
+ */
+
+/dts-v1/;
+
+/include/ "skeleton.dtsi"
+
+/ {
+	model = "Qualcomm MPQ8092 Simulator";
+	compatible = "qcom,mpq8092-sim", "qcom,mpq8092";
+	interrupt-parent = <&intc>;
+
+	intc: interrupt-controller@f9000000 {
+		compatible = "qcom,msm-qgic2";
+		interrupt-controller;
+		#interrupt-cells = <3>;
+		reg = <0xf9000000 0x1000>,
+		<0xf9002000 0x1000>;
+	};
+
+	timer {
+		compatible = "qcom,msm-qtimer", "arm,armv7-timer";
+		interrupts = <1 2 0>, <1 3 0>;
+		clock-frequency = <19200000>;
+	};
+
+	serial@f991f000 {
+		compatible = "qcom,msm-lsuart-v14";
+		reg = <0xf991f000 0x1000>;
+		interrupts = <0 109 0>;
+	};
+
+	serial@f995e000 {
+		compatible = "qcom,msm-lsuart-v14";
+		reg = <0xf995e000 0x1000>;
+		interrupts = <0 114 0>;
+	};
+
+};
+
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
old mode 100644
new mode 100755
index 67adcd6..751a823
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -25,11 +25,45 @@
 		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>;
+			};
+		};
+
+		clkdiv@5b00 {
+			reg = <0x5b00 0x100>;
+			compatible = "qcom,qpnp-clkdiv";
+			qcom,cxo-freq = <19200000>;
+		};
+
+		clkdiv@5c00 {
+			reg = <0x5c00 0x100>;
+			compatible = "qcom,qpnp-clkdiv";
+			qcom,cxo-freq = <19200000>;
+		};
+
+		clkdiv@5d00 {
+			reg = <0x5d00 0x1000>;
+			compatible = "qcom,qpnp-clkdiv";
+			qcom,cxo-freq = <19200000>;
 		};
 
 		pm8941_gpios {
@@ -344,12 +378,155 @@
 				label = "usb_in";
 				qcom,channel-num = <0>;
 				qcom,decimation = <0>;
-				qcom,pre-div-channel-scaling = <20>;
+				qcom,pre-div-channel-scaling = <4>;
 				qcom,calibration-type = "absolute";
 				qcom,scale-function = <0>;
 				qcom,hw-settle-time = <0>;
 				qcom,fast-avg-setup = <0>;
 			};
+
+			chan@1 {
+				label = "dc_in";
+				qcom,channel-num = <1>;
+				qcom,decimation = <0>;
+				qcom,pre-div-channel-scaling = <4>;
+				qcom,calibration-type = "absolute";
+				qcom,scale-function = <0>;
+				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 = <3>;
+				qcom,calibration-type = "absolute";
+				qcom,scale-function = <0>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+			};
+
+			chan@3 {
+				label = "spare1";
+				qcom,channel-num = <3>;
+				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@4 {
+				label = "spare2";
+				qcom,channel-num = <4>;
+				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 = <1>;
+				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 = <1>;
+				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 = <1>;
+				qcom,calibration-type = "absolute";
+				qcom,scale-function = <0>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+			};
+
+			chan@8 {
+				label = "die_temp";
+				qcom,channel-num = <8>;
+				qcom,decimation = <0>;
+				qcom,pre-div-channel-scaling = <0>;
+				qcom,calibration-type = "absolute";
+				qcom,scale-function = <3>;
+				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 = <0>;
+				qcom,calibration-type = "absolute";
+				qcom,scale-function = <0>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+			};
+
+			chan@10 {
+				label = "ref_1250v";
+				qcom,channel-num = <10>;
+				qcom,decimation = <0>;
+				qcom,pre-div-channel-scaling = <0>;
+				qcom,calibration-type = "absolute";
+				qcom,scale-function = <0>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+			};
+
+			chan@48 {
+				label = "batt_therm";
+				qcom,channel-num = <48>;
+				qcom,decimation = <0>;
+				qcom,pre-div-channel-scaling = <0>;
+				qcom,calibration-type = "ratiometric";
+				qcom,scale-function = <1>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+			};
+
+			chan@49 {
+				label = "batt_id";
+				qcom,channel-num = <49>;
+				qcom,decimation = <0>;
+				qcom,pre-div-channel-scaling = <0>;
+				qcom,calibration-type = "ratiometric";
+				qcom,scale-function = <0>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+			};
+
+			chan@50 {
+				label = "xo_therm1";
+				qcom,channel-num = <49>;
+				qcom,decimation = <0>;
+				qcom,pre-div-channel-scaling = <0>;
+				qcom,calibration-type = "ratiometric";
+				qcom,scale-function = <4>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+			};
 		};
 
 		iadc@3600 {
@@ -478,6 +655,7 @@
 			regulator-name = "8941_l5";
 			reg = <0x4400 0x100>;
 			compatible = "qcom,qpnp-regulator";
+			qcom,force-type = <0x04 0x10>;
 			status = "disabled";
 		};
 
@@ -492,6 +670,7 @@
 			regulator-name = "8941_l7";
 			reg = <0x4600 0x100>;
 			compatible = "qcom,qpnp-regulator";
+			qcom,force-type = <0x04 0x10>;
 			status = "disabled";
 		};
 
@@ -648,5 +827,66 @@
 			compatible = "qcom,qpnp-regulator";
 			status = "disabled";
 		};
+
+		qcom,leds@d800 {
+			compatible = "qcom,leds-qpnp";
+			reg = <0xd800 0x100>;
+			qcom,label = "wled";
+		};
+
+		qcom,leds@d900 {
+			compatible = "qcom,leds-qpnp";
+			reg = <0xd900 0x100>;
+			qcom,label = "wled";
+		};
+
+		qcom,leds@da00 {
+			compatible = "qcom,leds-qpnp";
+			reg = <0xda00 0x100>;
+			qcom,label = "wled";
+		};
+
+		qcom,leds@db00 {
+			compatible = "qcom,leds-qpnp";
+			reg = <0xdb00 0x100>;
+			qcom,label = "wled";
+		};
+
+		qcom,leds@dc00 {
+			compatible = "qcom,leds-qpnp";
+			reg = <0xdc00 0x100>;
+			qcom,label = "wled";
+		};
+
+		qcom,leds@dd00 {
+			compatible = "qcom,leds-qpnp";
+			reg = <0xdd00 0x100>;
+			qcom,label = "wled";
+		};
+
+		qcom,leds@de00 {
+			compatible = "qcom,leds-qpnp";
+			reg = <0xde00 0x100>;
+			qcom,label = "wled";
+		};
+
+		qcom,leds@df00 {
+			compatible = "qcom,leds-qpnp";
+			reg = <0xdf00 0x100>;
+			qcom,label = "wled";
+		};
+
+		qcom,leds@e000 {
+			compatible = "qcom,leds-qpnp";
+			reg = <0xe000 0x100>;
+			qcom,label = "wled";
+		};
+
+		qcom,leds@e100 {
+			compatible = "qcom,leds-qpnp";
+			reg = <0xe100 0x100>;
+			qcom,label = "wled";
+		};
+
 	};
 };
diff --git a/arch/arm/boot/dts/msm8974-camera.dtsi b/arch/arm/boot/dts/msm8974-camera.dtsi
index 0375e93..c92188a 100644
--- a/arch/arm/boot/dts/msm8974-camera.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera.dtsi
@@ -19,6 +19,7 @@
 		reg = <0xfd8C0000 0x10000>;
 		reg-names = "server";
 	};
+
 	qcom,csiphy@fda0ac00 {
 		cell-index = <0>;
 		compatible = "qcom,csiphy";
@@ -27,6 +28,7 @@
 		interrupts = <0 78 0>;
 		interrupt-names = "csiphy";
 	};
+
 	qcom,csiphy@fda0b000 {
 		cell-index = <1>;
 		compatible = "qcom,csiphy";
@@ -35,6 +37,7 @@
 		interrupts = <0 79 0>;
 		interrupt-names = "csiphy";
 	};
+
 	qcom,csiphy@fda0b400 {
 		cell-index = <2>;
 		compatible = "qcom,csiphy";
@@ -43,6 +46,7 @@
 		interrupts = <0 80 0>;
 		interrupt-names = "csiphy";
 	};
+
 	qcom,csid@fda08000  {
 		cell-index = <0>;
 		compatible = "qcom,csid";
@@ -50,7 +54,9 @@
 		reg-names = "csid";
 		interrupts = <0 51 0>;
 		interrupt-names = "csid";
+                mipi_csi_vdd-supply = <&pm8941_l12>;
 	};
+
 	qcom,csid@fda08400 {
 		cell-index = <1>;
 		compatible = "qcom,csid";
@@ -58,7 +64,9 @@
 		reg-names = "csid";
 		interrupts = <0 52 0>;
 		interrupt-names = "csid";
+                mipi_csi_vdd-supply = <&pm8941_l12>;
 	};
+
 	qcom,csid@fda08800 {
 		cell-index = <2>;
 		compatible = "qcom,csid";
@@ -66,7 +74,9 @@
 		reg-names = "csid";
 		interrupts = <0 53 0>;
 		interrupt-names = "csid";
+                mipi_csi_vdd-supply = <&pm8941_l12>;
 	};
+
 	qcom,csid@fda08C00 {
 		cell-index = <3>;
 		compatible = "qcom,csid";
@@ -74,7 +84,9 @@
 		reg-names = "csid";
 		interrupts = <0 54 0>;
 		interrupt-names = "csid";
+                mipi_csi_vdd-supply = <&pm8941_l12>;
 	};
+
 	qcom,ispif@fda0A000 {
 		cell-index = <0>;
 		compatible = "qcom,ispif";
@@ -83,32 +95,29 @@
 		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";
+		reg = <0xfda10000 0x1000>,
+                      <0xfda40000 0x200>;
+		reg-names = "vfe", "vfe_vbif";
 		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";
+		reg = <0xfda14000 0x1000>,
+                      <0xfda40000 0x200>;
+		reg-names = "vfe", "vfe_vbif";
 		interrupts = <0 58 0>;
 		interrupt-names = "vfe";
 		vdd-supply = <&gdsc_vfe>;
 	};
+
 	qcom,jpeg@fda1c000 {
 		cell-index = <0>;
 		compatible = "qcom,jpeg";
@@ -116,7 +125,9 @@
 		reg-names = "jpeg";
 		interrupts = <0 59 0>;
 		interrupt-names = "jpeg";
+                vdd-supply = <&gdsc_jpeg>;
 	};
+
 	qcom,jpeg@fda20000 {
 		cell-index = <1>;
 		compatible = "qcom,jpeg";
@@ -124,7 +135,9 @@
 		reg-names = "jpeg";
 		interrupts = <0 60 0>;
 		interrupt-names = "jpeg";
+		vdd-supply = <&gdsc_jpeg>;
 	};
+
 	qcom,jpeg@fda24000 {
 		cell-index = <2>;
 		compatible = "qcom,jpeg";
@@ -132,13 +145,16 @@
 		reg-names = "jpeg";
 		interrupts = <0 61 0>;
 		interrupt-names = "jpeg";
+		vdd-supply = <&gdsc_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";
@@ -148,4 +164,98 @@
 		interrupt-names = "cpp";
 		vdd-supply = <&gdsc_vfe>;
 	};
+
+	qcom,cci@fda0C000 {
+		cell-index = <0>;
+		compatible = "qcom,cci";
+		reg = <0xfda0C000 0x1000>;
+                #address-cells = <1>;
+                #size-cells = <1>;
+                ranges;
+		reg-names = "cci";
+		interrupts = <0 50 0>;
+		interrupt-names = "cci";
+
+		qcom,camera@6e {
+			compatible = "qcom,s5k3l1yx";
+			reg = <0x6e 0x0>;
+			qcom,csi-if = <1>;
+			qcom,csid-core = <0>;
+			qcom,is-vpe = <1>;
+			qcom,flash-type = <0>;
+			qcom,mount-angle = <90>;
+			qcom,sensor-name = "s5k3l1yx";
+			cam_vdig-supply = <&pm8941_l3>;
+			cam_vana-supply = <&pm8941_l17>;
+			cam_vio-supply = <&pm8941_lvs3>;
+			cam_vaf-supply = <&pm8941_l23>;
+			qcom,cam-vreg-name = "cam_vdig", "cam_vana", "cam_vio",
+					     "cam_vaf";
+			qcom,cam-vreg-type = <0 0 1 0>;
+			qcom,cam-vreg-min-voltage = <1225000 2850000 0 3000000>;
+			qcom,cam-vreg-max-voltage = <1225000 2850000 0 3000000>;
+			qcom,cam-vreg-op-mode = <105000 80000 0 100000>;
+			qcom,gpio-no-mux = <0>;
+			gpios = <&msmgpio 15 0>,
+				<&msmgpio 19 0>,
+				<&msmgpio 20 0>,
+				<&msmgpio 90 0>;
+			qcom,gpio-common-tbl-num = <0 1 2>;
+			qcom,gpio-common-tbl-flags = <1 1 1>;
+			qcom,gpio-common-tbl-label = "CAMIF_MCLK",
+						     "CAMIF_I2C_DATA",
+						     "CAMIF_I2C_CLK";
+			qcom,gpio-req-tbl-num = <3>;
+			qcom,gpio-req-tbl-flags = <0>;
+			qcom,gpio-req-tbl-label = "CAM_RESET1";
+			qcom,gpio-set-tbl-num = <3 3>;
+			qcom,gpio-set-tbl-flags = <0 2>;
+			qcom,gpio-set-tbl-delay = <1000 30000>;
+			qcom,csi-lane-assign = <0x4320>;
+			qcom,csi-lane-mask = <0x1F>;
+			qcom,csi-phy-sel = <0>;
+			qcom,camera-type = <0>;
+			qcom,sensor-type = <0>;
+		};
+
+		qcom,camera@6c {
+			compatible = "qcom,ov2720";
+			reg = <0x6c 0x0>;
+			qcom,csi-if = <1>;
+			qcom,csid-core = <1>;
+			qcom,is-vpe = <1>;
+			qcom,flash-type = <0>;
+			qcom,mount-angle = <0>;
+			qcom,sensor-name = "ov2720";
+			cam_vdig-supply = <&pm8941_l3>;
+			cam_vana-supply = <&pm8941_l17>;
+			cam_vio-supply = <&pm8941_lvs3>;
+			qcom,cam-vreg-name = "cam_vdig", "cam_vana", "cam_vio";
+			qcom,cam-vreg-type = <0 0 1>;
+			qcom,cam-vreg-min-voltage = <1225000 2850000 0>;
+			qcom,cam-vreg-max-voltage = <1225000 2850000 0>;
+			qcom,cam-vreg-op-mode = <105000 80000 0>;
+			qcom,gpio-no-mux = <0>;
+			gpios = <&msmgpio 16 0>,
+				<&msmgpio 19 0>,
+				<&msmgpio 20 0>,
+				<&msmgpio 92 0>;
+			qcom,gpio-common-tbl-num = <0 1 2>;
+			qcom,gpio-common-tbl-flags = <1 1 1>;
+			qcom,gpio-common-tbl-label = "CAMIF_MCLK",
+						     "CAMIF_I2C_DATA",
+						     "CAMIF_I2C_CLK";
+			qcom,gpio-req-tbl-num = <3>;
+			qcom,gpio-req-tbl-flags = <0>;
+			qcom,gpio-req-tbl-label = "CAM_RESET1";
+			qcom,gpio-set-tbl-num = <3 3>;
+			qcom,gpio-set-tbl-flags = <0 2>;
+			qcom,gpio-set-tbl-delay = <1000 4000>;
+			qcom,csi-lane-assign = <0x4320>;
+			qcom,csi-lane-mask = <0x7>;
+			qcom,csi-phy-sel = <1>;
+			qcom,camera-type = <1>;
+			qcom,sensor-type = <0>;
+		};
+	};
 };
diff --git a/arch/arm/boot/dts/msm8974-cdp.dts b/arch/arm/boot/dts/msm8974-cdp.dts
index 29edf30..7aeb33c 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dts
+++ b/arch/arm/boot/dts/msm8974-cdp.dts
@@ -13,9 +13,158 @@
 /dts-v1/;
 
 /include/ "msm8974.dtsi"
+/include/ "dsi-panel-toshiba-720p-video.dtsi"
 
 / {
 	model = "Qualcomm MSM 8974 CDP";
 	compatible = "qcom,msm8974-cdp", "qcom,msm8974";
 	qcom,msm-id = <126 1 0>;
+
+	serial@f991e000 {
+		status = "ok";
+	};
+
+	qcom,mdss_dsi@fd922800 {
+		qcom,mdss_dsi_toshiba_720p_video {
+			status = "ok";
+		};
+	};
+
+	i2c@f9924000 {
+		atmel_mxt_ts@4a {
+			compatible = "atmel,mxt-ts";
+			reg = <0x4a>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <61 0x2>;
+			vdd_ana-supply = <&pm8941_l18>;
+			vcc_i2c-supply = <&pm8941_lvs1>;
+			atmel,reset-gpio = <&msmgpio 60 0x00>;
+			atmel,irq-gpio = <&msmgpio 61 0x00>;
+			atmel,panel-coords = <0  0 760 1424>;
+			atmel,display-coords = <0 0 720 1280>;
+			atmel,i2c-pull-up = <1>;
+			atmel,cfg_1 {
+				atmel,family-id = <0x82>;
+				atmel,variant-id = <0x19>;
+				atmel,version = <0x10>;
+				atmel,build = <0xaa>;
+				atmel,config = [
+					/* Object 6, Instance = 0 */
+					00 00 00 00 00 00
+					/* Object 38, Instance = 0 */
+					15 00 02 10 08 0C 00 00
+					/* Object 7, Instance = 0 */
+					FF FF 32 03
+					/* Object 8, Instance = 0 */
+					0F 00 0A 0A 00 00 0A 00 00 00
+					/* Object 9, Instance = 0 */
+					83 00 00 18 0E 00 70 32 02 01
+					00 03 01 01 05 0A 0A 0A 90 05
+					F8 02 00 00 0F 0F 00 00 48 2D
+					07 0C 00 00 00 00
+					/* Object 15, Instance = 0 */
+					00 00 00 00 00 00 00 00 00 00
+					00
+					/* Object 18, Instance = 0 */
+					00 00
+					/* Object 19, Instance = 0 */
+					00 00 00 00 00 00
+					/* Object 23, Instance = 0 */
+					00 00 00 00 00 00 00 00 00 00
+					00 00 00 00 00
+					/* Object 25, Instance = 0 */
+					00 00 00 00 00 00 00 00 00 00
+					00 00 00 00 00
+					/* Object 40, Instance = 0 */
+					00 00 00 00 00
+					/* Object 42, Instance = 0 */
+					00 00 00 00 00 00 00 00 00 00
+					/* Object 46, Instance = 0 */
+					00 00 10 10 00 00 03 00 00 01
+					/* Object 47, Instance = 0 */
+					08 0A 28 0A 02 0A 00 8C 00 20
+					00 00 00
+					/* Object 55, Instance = 0 */
+					00 00 00 00 00 00
+					/* Object 56, Instance = 0 */
+					03 00 01 18 05 05 05 05 05 05
+					05 05 05 05 05 05 05 05 05 05
+					05 05 05 05 05 05 05 05 00 00
+					00 00 00 00 00 00 00 00 00 00
+					00 00
+					/* Object 57, Instance = 0 */
+					00 00 00
+					/* Object 61, Instance = 0 */
+					00 00 00 00 00
+					/* Object 61, Instance = 1 */
+					00 00 00 00 00
+					/* Object 62, Instance = 0 */
+					7F 03 00 16 00 00 00 00 00 00
+					04 08 10 18 05 00 0A 05 05 50
+					14 19 34 1A 64 00 00 04 40 00
+					00 00 00 00 30 32 02 00 01 00
+					05 00 00 00 00 00 00 00 00 00
+					00 00 0C 00
+					];
+			};
+		};
+	};
+
+	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>;
+		};
+	};
+
+	spi@f9923000 {
+		ethernet-switch@2 {
+			compatible = "micrel,ks8851";
+			reg = <2>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <94 0>;
+			spi-max-frequency = <4800000>;
+			rst-gpio = <&pm8941_mpps 6 0>;
+			vdd-io-supply = <&spi_eth_vreg>;
+			vdd-phy-supply = <&spi_eth_vreg>;
+		};
+	};
+};
+
+&sdcc2 {
+	#address-cells = <0>;
+	interrupt-parent = <&sdcc2>;
+	interrupts = <0 1 2>;
+	#interrupt-cells = <1>;
+	interrupt-map-mask = <0xffffffff>;
+	interrupt-map = <0 &intc 0 125 0
+			1 &intc 0 220 0
+			2 &msmgpio 62 0x3>;
+	interrupt-names = "core_irq", "bam_irq", "status_irq";
+	cd-gpios = <&msmgpio 62 0x1>;
+	wp-gpios = <&pm8941_gpios 29 0x1>;
 };
diff --git a/arch/arm/boot/dts/msm8974-clock.dtsi b/arch/arm/boot/dts/msm8974-clock.dtsi
new file mode 100644
index 0000000..043346f
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974-clock.dtsi
@@ -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.
+ */
+
+&spmi_bus {
+
+	qcom,pm8941@0 {
+
+		pm8941_clkdiv1: clkdiv@5b00 {
+			qcom,cxo-div = <2>;
+		};
+
+		pm8941_clkdiv2: clkdiv@5c00 {
+		};
+
+		pm8941_clkdiv3: clkdiv@5d00 {
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/msm8974-coresight.dtsi b/arch/arm/boot/dts/msm8974-coresight.dtsi
new file mode 100644
index 0000000..0b09bc8
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974-coresight.dtsi
@@ -0,0 +1,190 @@
+/* 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>,
+		      <0xfc37c000 0x3000>;
+
+		qcom,memory-reservation-type = "EBI1";
+		qcom,memory-reservation-size = <0x100000>; /* 1M EBI1 buffer */
+
+		coresight-id = <0>;
+		coresight-name = "coresight-tmc-etr";
+		coresight-nr-inports = <1>;
+	};
+
+	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>;
+		coresight-default-sink;
+	};
+
+	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>;
+	};
+
+	csr: csr@fc302000 {
+		compatible = "qcom,coresight-csr";
+		reg = <0xfc302000 0x1000>;
+
+		coresight-id = <14>;
+		coresight-name = "coresight-csr";
+		coresight-nr-inports = <0>;
+	};
+};
diff --git a/arch/arm/boot/dts/msm8974-gpio.dtsi b/arch/arm/boot/dts/msm8974-gpio.dtsi
index 323fac4..e7c742c 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";
 			};
 
@@ -74,6 +86,13 @@
 
 			gpio@ce00 {
 				status = "ok";
+				qcom,mode = <1>;
+				qcom,output-type = <0>;
+				qcom,pull = <5>;
+				qcom,vin-sel = <2>;
+				qcom,out-strength = <3>;
+				qcom,src-select = <2>;
+				qcom,master-en = <1>;
 			};
 
 			gpio@cf00 {
@@ -133,7 +152,9 @@
 			};
 
 			gpio@dc00 {
-				qcom,out-strength = <1>;
+				qcom,pull = <0>; /* set to default pull */
+				qcom,master-en = <1>;
+				qcom,vin-sel = <2>; /* select 1.8 V source */
 				status = "ok";
 			};
 
@@ -193,10 +214,22 @@
 
 			mpp@a400 {
 				status = "ok";
+				/* SPI_ETH config */
+				qcom,mode = <1>; /* DIG_OUT */
+				qcom,output-type = <0>; /* CMOS */
+				qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
+				qcom,src-select = <0>; /* CONSTANT */
+				qcom,master-en = <1>; /* ENABLE MPP */
 			};
 
 			mpp@a500 {
 				status = "ok";
+				/* SPI_ETH_RST config */
+				qcom,mode = <1>; /* DIG_OUT */
+				qcom,output-type = <0>; /* CMOS */
+				qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
+				qcom,src-select = <0>; /* CONSTANT */
+				qcom,master-en = <1>; /* ENABLE MPP */
 			};
 
 			mpp@a600 {
diff --git a/arch/arm/boot/dts/msm8974-gpu.dtsi b/arch/arm/boot/dts/msm8974-gpu.dtsi
index a972d7f..2312b02 100644
--- a/arch/arm/boot/dts/msm8974-gpu.dtsi
+++ b/arch/arm/boot/dts/msm8974-gpu.dtsi
@@ -52,14 +52,14 @@
 
 			qcom,gpu-pwrlevel@0 {
 				reg = <0>;
-				qcom,gpu-freq = <500000000>;
+				qcom,gpu-freq = <450000000>;
 				qcom,bus-freq = <3>;
 				qcom,io-fraction = <0>;
 			};
 
 			qcom,gpu-pwrlevel@1 {
 				reg = <1>;
-				qcom,gpu-freq = <333000000>;
+				qcom,gpu-freq = <300000000>;
 				qcom,bus-freq = <2>;
 				qcom,io-fraction = <33>;
 			};
diff --git a/arch/arm/boot/dts/msm8974-mdss.dtsi b/arch/arm/boot/dts/msm8974-mdss.dtsi
new file mode 100644
index 0000000..0382021
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974-mdss.dtsi
@@ -0,0 +1,61 @@
+/* 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>,
+			<0xfd924000 0x1000>;
+		reg-names = "mdp_phys", "vbif_phys";
+		interrupts = <0 72 0>;
+		vdd-supply = <&gdsc_mdss>;
+	};
+
+	mdss_dsi: qcom,mdss_dsi@fd922800 {
+		compatible = "qcom,msm-mdss-dsi";
+		reg = <0xfd922800 0x600>,
+			<0xfd8c2000 0x01000>;
+		vdd-supply = <&pm8941_l22>;
+		vdd_io-supply = <&pm8941_l12>;
+		vreg-supply = <&pm8941_l2>;
+	};
+
+	qcom,hdmi_tx@fd922100 {
+		cell-index = <0>;
+		compatible = "qcom,hdmi-tx";
+		reg =	<0xfd922100 0x35C>,
+			<0xfd922500 0x7C>,
+			<0xfc4b8000 0x60F0>;
+		reg-names = "core_physical", "phy_physical", "qfprom_physical";
+
+		hpd-5v-supply = <&pm8941_mvs2>;
+		core-vdda-supply = <&pm8941_l12>;
+		core-vcc-supply = <&pm8941_s3>;
+		qcom,hdmi-tx-supply-names = "hpd-5v", "core-vdda", "core-vcc";
+		qcom,hdmi-tx-supply-type = <0 1 1>;
+		qcom,hdmi-tx-min-voltage-level = <0 1800000 1800000>;
+		qcom,hdmi-tx-max-voltage-level = <0 1800000 1800000>;
+		qcom,hdmi-tx-op-mode = <0 1800000 0>;
+
+		gpios = <&msmgpio 31 0>,
+			<&msmgpio 32 0>,
+			<&msmgpio 33 0>,
+			<&msmgpio 34 0>;
+		qcom,hdmi-tx-gpio-names = "cec-pin", "hpd-ddc-clk", "hpd-ddc-data", "hpd-pin";
+	};
+
+	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-mtp.dts b/arch/arm/boot/dts/msm8974-mtp.dts
new file mode 100644
index 0000000..d3e0bc3
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974-mtp.dts
@@ -0,0 +1,169 @@
+/* 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.
+ */
+
+/dts-v1/;
+
+/include/ "msm8974.dtsi"
+/include/ "dsi-panel-toshiba-720p-video.dtsi"
+
+/ {
+	model = "Qualcomm MSM 8974 MTP";
+	compatible = "qcom,msm8974-mtp", "qcom,msm8974";
+	qcom,msm-id = <126 8 0>;
+
+	serial@f991e000 {
+		status = "ok";
+	};
+
+	qcom,mdss_dsi@fd922800 {
+		qcom,mdss_dsi_toshiba_720p_video {
+			status = "ok";
+		};
+	};
+
+	i2c@f9924000 {
+		atmel_mxt_ts@4a {
+			compatible = "atmel,mxt-ts";
+			reg = <0x4a>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <61 0x2>;
+			vdd_ana-supply = <&pm8941_l18>;
+			vcc_i2c-supply = <&pm8941_lvs1>;
+			atmel,reset-gpio = <&msmgpio 60 0x00>;
+			atmel,irq-gpio = <&msmgpio 61 0x00>;
+			atmel,panel-coords = <0  0 760 1424>;
+			atmel,display-coords = <0 0 720 1280>;
+			atmel,i2c-pull-up = <1>;
+			atmel,cfg_1 {
+				atmel,family-id = <0x82>;
+				atmel,variant-id = <0x19>;
+				atmel,version = <0x10>;
+				atmel,build = <0xaa>;
+				atmel,config = [
+					/* Object 6, Instance = 0 */
+					00 00 00 00 00 00
+					/* Object 38, Instance = 0 */
+					15 00 02 10 08 0C 00 00
+					/* Object 7, Instance = 0 */
+					FF FF 32 03
+					/* Object 8, Instance = 0 */
+					0F 00 0A 0A 00 00 0A 00 00 00
+					/* Object 9, Instance = 0 */
+					83 00 00 18 0E 00 70 32 02 01
+					00 03 01 01 05 0A 0A 0A 90 05
+					F8 02 00 00 0F 0F 00 00 48 2D
+					07 0C 00 00 00 00
+					/* Object 15, Instance = 0 */
+					00 00 00 00 00 00 00 00 00 00
+					00
+					/* Object 18, Instance = 0 */
+					00 00
+					/* Object 19, Instance = 0 */
+					00 00 00 00 00 00
+					/* Object 23, Instance = 0 */
+					00 00 00 00 00 00 00 00 00 00
+					00 00 00 00 00
+					/* Object 25, Instance = 0 */
+					00 00 00 00 00 00 00 00 00 00
+					00 00 00 00 00
+					/* Object 40, Instance = 0 */
+					00 00 00 00 00
+					/* Object 42, Instance = 0 */
+					00 00 00 00 00 00 00 00 00 00
+					/* Object 46, Instance = 0 */
+					00 00 10 10 00 00 03 00 00 01
+					/* Object 47, Instance = 0 */
+					08 0A 28 0A 02 0A 00 8C 00 20
+					00 00 00
+					/* Object 55, Instance = 0 */
+					00 00 00 00 00 00
+					/* Object 56, Instance = 0 */
+					03 00 01 18 05 05 05 05 05 05
+					05 05 05 05 05 05 05 05 05 05
+					05 05 05 05 05 05 05 05 00 00
+					00 00 00 00 00 00 00 00 00 00
+					00 00
+					/* Object 57, Instance = 0 */
+					00 00 00
+					/* Object 61, Instance = 0 */
+					00 00 00 00 00
+					/* Object 61, Instance = 1 */
+					00 00 00 00 00
+					/* Object 62, Instance = 0 */
+					7F 03 00 16 00 00 00 00 00 00
+					04 08 10 18 05 00 0A 05 05 50
+					14 19 34 1A 64 00 00 04 40 00
+					00 00 00 00 30 32 02 00 01 00
+					05 00 00 00 00 00 00 00 00 00
+					00 00 0C 00
+					];
+			};
+		};
+	};
+
+	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>;
+		};
+	};
+
+	spi@f9923000 {
+		ethernet-switch@2 {
+			compatible = "micrel,ks8851";
+			reg = <2>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <94 0>;
+			spi-max-frequency = <4800000>;
+			rst-gpio = <&pm8941_mpps 6 0>;
+			vdd-io-supply = <&spi_eth_vreg>;
+			vdd-phy-supply = <&spi_eth_vreg>;
+		};
+	};
+};
+
+&sdcc2 {
+	#address-cells = <0>;
+	interrupt-parent = <&sdcc2>;
+	interrupts = <0 1 2>;
+	#interrupt-cells = <1>;
+	interrupt-map-mask = <0xffffffff>;
+	interrupt-map = <0 &intc 0 125 0
+			1 &intc 0 220 0
+			2 &msmgpio 62 0x3>;
+	interrupt-names = "core_irq", "bam_irq", "status_irq";
+	cd-gpios = <&msmgpio 62 0x1>;
+};
diff --git a/arch/arm/boot/dts/msm8974-regulator.dtsi b/arch/arm/boot/dts/msm8974-regulator.dtsi
index 5c8fd9a..1fd96f9 100644
--- a/arch/arm/boot/dts/msm8974-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8974-regulator.dtsi
@@ -192,9 +192,9 @@
 		status = "okay";
 		pm8941_l4: regulator-l4 {
 			parent-supply = <&pm8941_s1>;
-			regulator-min-microvolt = <12250000>;
-			regulator-max-microvolt = <12250000>;
-			qcom,init-voltage = <12250000>;
+			regulator-min-microvolt = <1225000>;
+			regulator-max-microvolt = <1225000>;
+			qcom,init-voltage = <1225000>;
 			status = "okay";
 		};
 	};
@@ -472,4 +472,11 @@
 		regulator-min-microvolt = <500000>;
 		regulator-max-microvolt = <1100000>;
 	};
+
+	spi_eth_vreg: spi_eth_phy_vreg {
+		compatible = "regulator-fixed";
+		regulator-name = "ethernet_phy";
+		gpio = <&pm8941_mpps 5 0>;
+		enable-active-high;
+	};
 };
diff --git a/arch/arm/boot/dts/msm8974-sim.dts b/arch/arm/boot/dts/msm8974-sim.dts
index 8cd925e..d5368fa 100644
--- a/arch/arm/boot/dts/msm8974-sim.dts
+++ b/arch/arm/boot/dts/msm8974-sim.dts
@@ -34,3 +34,65 @@
 		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 446f310..fe60c83 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -14,9 +14,11 @@
 /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";
@@ -53,11 +55,9 @@
 		vidc-cp-map = <0x1000000 0x40000000>;
 		vidc-ns-map = <0x40000000 0x40000000>;
 		load-freq-tbl = <979200 410000000>,
-				<560145 266670000>,
-				<421161 200000000>,
-				<243000 133330000>,
-				<108000 100000000>,
-				<36000 50000000>;
+			<783360 410000000>,
+			<489600 266670000>,
+			<244800 133330000>;
 	};
 
 	serial@f991f000 {
@@ -74,30 +74,56 @@
 		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>;
 
 		qcom,hsusb-otg-phy-type = <2>;
+		qcom,hsusb-otg-phy-init-seq = <0x63 0x81 0xffffffff>;
 		qcom,hsusb-otg-mode = <1>;
 		qcom,hsusb-otg-otg-control = <1>;
 		qcom,hsusb-otg-disable-reset;
+
+		qcom,msm_bus,name = "usb2";
+		qcom,msm_bus,num_cases = <2>;
+		qcom,msm_bus,active_only = <0>;
+		qcom,msm_bus,num_paths = <1>;
+		qcom,msm_bus,vectors =
+				<87 512 0 0>,
+				<87 512 60000000 960000000>;
 	};
 
-	qcom,sdcc@f9824000 {
+	android_usb@fc42b0c8 {
+		compatible = "qcom,android-usb";
+		reg = <0xfc42b0c8 0xc8>;
+	};
+
+	sdcc1: 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";
+		reg = <0xf9824000 0x800>,
+			<0xf9824800 0x100>,
+			<0xf9804000 0x7000>;
+		reg-names = "core_mem", "dml_mem", "bam_mem";
+		interrupts = <0 123 0>, <0 137 0>;
+		interrupt-names = "core_irq", "bam_irq";
 		vdd-supply = <&pm8941_l20>;
 		vdd-io-supply = <&pm8941_s3>;
 
+		qcom,sdcc-vdd-always_on;
+		qcom,sdcc-vdd-lpm_sup;
 		qcom,sdcc-vdd-voltage_level = <2950000 2950000>;
 		qcom,sdcc-vdd-current_level = <800 500000>;
 
@@ -117,13 +143,15 @@
 		qcom,sdcc-bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
 	};
 
-	qcom,sdcc@f98a4000 {
+	sdcc2: qcom,sdcc@f98a4000 {
 		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";
+		reg = <0xf98a4000 0x800>,
+			<0xf98a4800 0x100>,
+			<0xf9884000 0x7000>;
+		reg-names = "core_mem", "dml_mem", "bam_mem";
+		interrupts = <0 125 0>, <0 220 0>;
+		interrupt-names = "core_irq", "bam_irq";
 		vdd-supply = <&pm8941_l21>;
 		vdd-io-supply = <&pm8941_l13>;
 
@@ -148,13 +176,15 @@
 		qcom,sdcc-current-limit = <800>;
 	};
 
-	qcom,sdcc@f9864000 {
+	sdcc3: qcom,sdcc@f9864000 {
 		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";
+		reg = <0xf9864000 0x800>,
+			<0xf9864800 0x100>,
+			<0xf9844000 0x7000>;
+		reg-names = "core_mem", "dml_mem", "bam_mem";
+		interrupts = <0 127 0>, <0 223 0>;
+		interrupt-names = "core_irq", "bam_irq";
 
 		gpios = <&msmgpio 40 0>, /* CLK */
 			<&msmgpio 39 0>, /* CMD */
@@ -171,13 +201,15 @@
 		status = "disable";
 	};
 
-	qcom,sdcc@f98e4000 {
+	sdcc4: qcom,sdcc@f98e4000 {
 		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";
+		reg = <0xf98e4000 0x800>,
+			<0xf98e4800 0x100>,
+			<0xf98c4000 0x7000>;
+		reg-names = "core_mem", "dml_mem", "bam_mem";
+		interrupts = <0 129 0>, <0 226 0>;
+		interrupt-names = "core_irq", "bam_irq";
 
 		gpios = <&msmgpio 93 0>, /* CLK */
 			<&msmgpio 91 0>, /* CMD */
@@ -204,13 +236,6 @@
 	};
 
 
-	spi@f9924000 {
-		compatible = "qcom,spi-qup-v2";
-		reg = <0xf9924000 0x1000>;
-		interrupts = <0 96 0>;
-		spi-max-frequency = <25000000>;
-	};
-
 	slim@fe12f000 {
 		cell-index = <1>;
 		compatible = "qcom,slim-msm";
@@ -221,6 +246,91 @@
 		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];
+		};
+	};
+
+	sound {
+		compatible = "qcom,msm8974-audio-taiko";
+		qcom,model = "msm8974-taiko-snd-card";
+
+		qcom,audio-routing =
+			"RX_BIAS", "MCLK",
+			"LDO_H", "MCLK",
+			"HEADPHONE", "LDO_H",
+			"Ext Spk Bottom Pos", "LINEOUT1",
+			"Ext Spk Bottom Neg", "LINEOUT3",
+			"Ext Spk Top Pos", "LINEOUT2",
+			"Ext Spk Top Neg", "LINEOUT4",
+			"AMIC1", "MIC BIAS1 Internal1",
+			"MIC BIAS1 Internal1", "Handset Mic",
+			"AMIC2", "MIC BIAS2 External",
+			"MIC BIAS2 External", "Headset Mic",
+			"AMIC3", "MIC BIAS3 Internal1",
+			"MIC BIAS3 Internal1", "ANCRight Headset Mic",
+			"AMIC4", "MIC BIAS1 Internal2",
+			"MIC BIAS1 Internal2", "ANCLeft Headset Mic",
+			"DMIC1", "MIC BIAS1 External",
+			"MIC BIAS1 External", "Digital Mic1",
+			"DMIC2", "MIC BIAS1 External",
+			"MIC BIAS1 External", "Digital Mic2",
+			"DMIC3", "MIC BIAS3 External",
+			"MIC BIAS3 External", "Digital Mic3",
+			"DMIC4", "MIC BIAS3 External",
+			"MIC BIAS3 External", "Digital Mic4",
+			"DMIC5", "MIC BIAS4 External",
+			"MIC BIAS4 External", "Digital Mic5",
+			"DMIC6", "MIC BIAS4 External",
+			"MIC BIAS4 External", "Digital Mic6";
+
+		qcom,cdc-mclk-gpios = <&pm8941_gpios 15 0>;
+		taiko-mclk-clk = <&pm8941_clkdiv1>;
+		qcom,taiko-mclk-clk-freq = <9600000>;
 	};
 
 	spmi_bus: qcom,spmi@fc4c0000 {
@@ -233,110 +343,236 @@
 		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 */
+
+		qcom,pm8941@1 {
+			qcom,leds@d800 {
+				qcom,name = "wled:backlight";
+				linux,default-trigger = "bkl-trigger";
+				qcom,cs-out-en;
+				qcom,op-fdbck;
+				qcom,default-state = "on";
+				qcom,max-current = <25>;
+				qcom,ctrl-delay-us = <0>;
+				qcom,boost-curr-lim = <3>;
+				qcom,cp-sel = <0>;
+				qcom,switch-freq = <2>;
+				qcom,ovp-val = <2>;
+				qcom,num-strings = <1>;
+				status = "okay";
+			};
+
+			qcom,leds@d900 {
+				status = "disabled";
+			};
+
+			qcom,leds@da00 {
+				status = "disabled";
+			};
+
+			qcom,leds@db00 {
+				status = "disabled";
+			};
+
+			qcom,leds@dc00 {
+				status = "disabled";
+			};
+
+			qcom,leds@dd00 {
+				status = "disabled";
+			};
+
+			qcom,leds@de00 {
+				status = "disabled";
+			};
+
+			qcom,leds@df00 {
+				status = "disabled";
+			};
+
+			qcom,leds@e000 {
+				status = "disabled";
+			};
+
+			qcom,leds@e100 {
+				status = "disabled";
+			};
+		};
 	};
 
-	i2c@f9966000 {
+	i2c@f9967000 {
 		cell-index = <0>;
 		compatible = "qcom,i2c-qup";
-		reg = <0Xf9966000 0x1000>;
+		reg = <0Xf9967000 0x1000>;
 		reg-names = "qup_phys_addr";
-		interrupts = <0 104 0>;
+		interrupts = <0 105 0>;
 		interrupt-names = "qup_err_intr";
 		qcom,i2c-bus-freq = <100000>;
 		qcom,i2c-src-freq = <24000000>;
 	};
 
+	i2c@f9924000 {
+		cell-index = <2>;
+		compatible = "qcom,i2c-qup";
+		reg = <0xf9924000 0x1000>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg-names = "qup_phys_addr";
+		interrupts = <0 96 0>;
+		interrupt-names = "qup_err_intr";
+		qcom,i2c-bus-freq = <100000>;
+		qcom,i2c-src-freq = <24000000>;
+	};
+
+	spi@f9923000 {
+		cell-index = <0>;
+		compatible = "qcom,spi-qup-v2";
+		reg = <0xf9923000 0x1000>;
+		interrupts = <0 95 0>;
+		spi-max-frequency = <19200000>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		gpios = <&msmgpio 3 0>, /* CLK  */
+			<&msmgpio 1 0>, /* MISO */
+			<&msmgpio 0 0>; /* MOSI */
+		cs-gpios = <&msmgpio 9 0>;
+	};
+
 	qcom,acpuclk@f9000000 {
 		compatible = "qcom,acpuclk-8974";
 		krait0-supply = <&krait0_vreg>;
@@ -365,7 +601,8 @@
 
 	qcom,ssusb@f9200000 {
 		compatible = "qcom,dwc-usb3-msm";
-		reg = <0xf9200000 0xfc000>;
+		reg = <0xf9200000 0xfc000>,
+			  <0xfd4ab000 0x4>;
 		interrupts = <0 131 0 0 179 0>;
 		interrupt-names = "irq", "otg_irq";
 		SSUSB_VDDCX-supply = <&pm8841_s2>;
@@ -374,6 +611,14 @@
 		HSUSB_1p8-supply = <&pm8941_l6>;
 		HSUSB_3p3-supply = <&pm8941_l24>;
 		qcom,dwc-usb3-msm-dbm-eps = <4>;
+
+		qcom,msm_bus,name = "usb3";
+		qcom,msm_bus,num_cases = <2>;
+		qcom,msm_bus,active_only = <0>;
+		qcom,msm_bus,num_paths = <1>;
+		qcom,msm_bus,vectors =
+				<61 512 0 0>,
+				<61 512 240000000 960000000>;
 	};
 
 	gdsc_oxili_gx: qcom,gdsc@fd8c4024 {
@@ -388,6 +633,10 @@
 		qcom,firmware-name = "adsp";
 	};
 
+	qcom,msm-adsp-loader {
+		compatible = "qcom,adsp-loader";
+	};
+
 	qcom,msm-pcm {
 		compatible = "qcom,msm-pcm-dsp";
 	};
@@ -408,6 +657,10 @@
 		compatible = "qcom,msm-voip-dsp";
 	};
 
+	qcom,msm-pcm-voice {
+		compatible = "qcom,msm-pcm-voice";
+	};
+
 	qcom,msm-stub-codec {
 		compatible = "qcom,msm-stub-codec";
 	};
@@ -468,7 +721,8 @@
 		reg = <0xfc880000 0x100>,
 		      <0xfd485000 0x400>,
 		      <0xfc820000 0x020>,
-		      <0xfc401680 0x004>;
+		      <0xfc401680 0x004>,
+		      <0xfc980008 0x004>;
 		vdd_mss-supply = <&pm8841_s3>;
 
 		qcom,firmware-name = "mba";
@@ -494,6 +748,26 @@
 		qcom,firmware-name = "wcnss";
 	};
 
+	qcom,wcnss-wlan@fb000000 {
+		compatible = "qcom,wcnss_wlan";
+		reg = <0xfb000000 0x280000>;
+		reg-names = "wcnss_mmio";
+		interrupts = <0 145 0 0 146 0>;
+		interrupt-names = "wcnss_wlantx_irq", "wcnss_wlanrx_irq";
+
+		qcom,pronto-vddmx-supply = <&pm8841_s1>;
+		qcom,pronto-vddcx-supply = <&pm8841_s2>;
+		qcom,pronto-vddpx-supply = <&pm8941_s3>;
+		qcom,iris-vddxo-supply = <&pm8941_l6>;
+		qcom,iris-vddrfa-supply = <&pm8941_l11>;
+		qcom,iris-vddpa-supply = <&pm8941_l19>;
+		qcom,iris-vdddig-supply = <&pm8941_l3>;
+
+		gpios = <&msmgpio 36 0>, <&msmgpio 37 0>, <&msmgpio 38 0>, <&msmgpio 39 0>, <&msmgpio 40 0>;
+		qcom,has_48mhz_xo;
+		qcom,has_pronto_hw;
+	};
+
 	qcom,ocmem@fdd00000 {
 		compatible = "qcom,msm-ocmem";
 		reg = <0xfdd00000 0x2000>,
@@ -555,28 +829,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>;
-	};
-
-	mdss_dsi: qcom,mdss_dsi@fd922800 {
-		cell-index = <1>;
-		compatible = "qcom,msm-mdss-dsi";
-		reg = <0xfd922800 0x5ac>,
-			<0xfd8c0000 0x01000>;
-	};
-
-	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>;
@@ -629,30 +881,38 @@
 		compatible = "qcom,qcedev";
 		reg = <0xfd440000 0x20000>,
 		      <0xfd444000 0x8000>;
-		interrupts = <0 235 0>;
-		qcom,bam-pipes = <0>;
+		reg-names = "crypto-base","crypto-bam-base";
+		interrupts = <0 236 0>;
+		qcom,bam-pipe-pair = <1>;
 	};
 
         qcom,qcrypto@fd444000 {
 		compatible = "qcom,qcrypto";
 		reg = <0xfd440000 0x20000>,
 		      <0xfd444000 0x8000>;
-		interrupts = <0 235 0>;
-		qcom,bam-pipes = <1>;
+		reg-names = "crypto-base","crypto-bam-base";
+		interrupts = <0 236 0>;
+		qcom,bam-pipe-pair = <2>;
 	};
 
 	qcom,usbbam@f9304000 {
 		compatible = "qcom,usb-bam-msm";
-		reg = <0xf9304000 0x9000>;
-		interrupts = <0 132 0>;
+		reg = <0xf9304000 0x5000>,
+		      <0xf9a44000 0x11000>,
+		      <0xf92f880c 0x4>;
+		reg-names = "ssusb", "hsusb", "qscratch_ram1_reg";
+		interrupts = <0 132 0 0 135 0>;
+		interrupt-names = "ssusb", "hsusb";
 		qcom,usb-active-bam = <0>;
-		qcom,usb-total-bam-num = <1>;
+		qcom,usb-total-bam-num = <2>;
 		qcom,usb-bam-num-pipes = <16>;
 		qcom,usb-base-address = <0xf9200000>;
+		qcom,ignore-core-reset-ack;
 
 		qcom,pipe1 {
 			label = "usb-to-peri-qdss-dwc3";
 			qcom,usb-bam-type = <0>;
+			qcom,usb-bam-mem-type = <1>;
 			qcom,src-bam-physical-address = <0>;
 			qcom,src-bam-pipe-index = <0>;
 			qcom,dst-bam-physical-address = <0>;
@@ -666,6 +926,7 @@
 		qcom,pipe2 {
 			label = "peri-to-usb-qdss-dwc3";
 			qcom,usb-bam-type = <0>;
+			qcom,usb-bam-mem-type = <1>;
 			qcom,src-bam-physical-address = <0xfc37C000>;
 			qcom,src-bam-pipe-index = <0>;
 			qcom,dst-bam-physical-address = <0xf9304000>;
@@ -675,6 +936,49 @@
 			qcom,descriptor-fifo-offset = <0xf4000>;
 			qcom,descriptor-fifo-size = <0x1400>;
 		};
+
+		qcom,pipe3 {
+			label = "usb-to-peri-qdss-hsusb";
+			qcom,usb-bam-type = <1>;
+			qcom,usb-bam-mem-type = <1>;
+			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,pipe4 {
+			label = "peri-to-usb-qdss-hsusb";
+			qcom,usb-bam-type = <1>;
+			qcom,usb-bam-mem-type = <1>;
+			qcom,src-bam-physical-address = <0xfc37c000>;
+			qcom,src-bam-pipe-index = <0>;
+			qcom,dst-bam-physical-address = <0xf9a44000>;
+			qcom,dst-bam-pipe-index = <2>;
+			qcom,data-fifo-offset = <0xf4000>;
+			qcom,data-fifo-size = <0x1000>;
+			qcom,descriptor-fifo-offset = <0xf5000>;
+			qcom,descriptor-fifo-size = <0x400>;
+		};
+	};
+
+	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>;
+	};
+
+	qcom,bam_dmux@fc834000 {
+		compatible = "qcom,bam_dmux";
+		reg = <0xfc834000 0x7000>;
+		interrupts = <0 29 1>;
 	};
 };
 
@@ -683,3 +987,4 @@
 /include/ "msm-pm8941.dtsi"
 /include/ "msm8974-regulator.dtsi"
 /include/ "msm8974-gpio.dtsi"
+/include/ "msm8974-clock.dtsi"
diff --git a/arch/arm/boot/dts/msm8974_pm.dtsi b/arch/arm/boot/dts/msm8974_pm.dtsi
index 476f2b5..79de997 100644
--- a/arch/arm/boot/dts/msm8974_pm.dtsi
+++ b/arch/arm/boot/dts/msm8974_pm.dtsi
@@ -20,7 +20,7 @@
 		reg = <0xf9089000 0x1000>;
 		qcom,core-id = <0>;
 		qcom,saw2-ver-reg = <0xfd0>;
-		qcom,saw2-cfg = <0x1b>;
+		qcom,saw2-cfg = <0x01>;
 		qcom,saw2-avs-ctl = <0>;
 		qcom,saw2-avs-hysteresis = <0>;
 		qcom,saw2-avs-limit = <0>;
@@ -28,11 +28,10 @@
 		qcom,saw2-spm-dly= <0x20000400>;
 		qcom,saw2-spm-ctl = <0x1>;
 		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
-		qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 92
-				a0 b0 03 68 70 3b 92 a0 b0
-				82 2b 50 10 30 02 22 30 0f];
-		qcom,saw2-spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
-				a0 b0 82 10 30 02 22 30 0f];
+		qcom,saw2-spm-cmd-spc = [00 20 80 10 90 a0 b0 03 3b 98 a2 b0 82
+				10 0b 30 06 26 30 0f];
+		qcom,saw2-spm-cmd-pc = [00 20 80 10 90 a0 b0 07 3b 98 a2 b0 82
+				10 0b 30 06 26 30 0f];
 	};
 
 	qcom,spm@f9099000 {
@@ -42,7 +41,7 @@
 		reg = <0xf9099000 0x1000>;
 		qcom,core-id = <1>;
 		qcom,saw2-ver-reg = <0xfd0>;
-		qcom,saw2-cfg = <0x1b>;
+		qcom,saw2-cfg = <0x01>;
 		qcom,saw2-avs-ctl = <0>;
 		qcom,saw2-avs-hysteresis = <0>;
 		qcom,saw2-avs-limit = <0>;
@@ -50,11 +49,10 @@
 		qcom,saw2-spm-dly= <0x20000400>;
 		qcom,saw2-spm-ctl = <0x1>;
 		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
-		qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 92
-				a0 b0 03 68 70 3b 92 a0 b0
-				82 2b 50 10 30 02 22 30 0f];
-		qcom,saw2-spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
-				a0 b0 82 10 30 02 22 30 0f];
+		qcom,saw2-spm-cmd-spc = [00 20 80 10 90 a0 b0 03 3b 98 a2 b0 82
+				10 0b 30 06 26 30 0f];
+		qcom,saw2-spm-cmd-pc = [00 20 80 10 90 a0 b0 07 3b 98 a2 b0 82
+				10 0b 30 06 26 30 0f];
 	};
 
 	qcom,spm@f90a9000 {
@@ -64,7 +62,7 @@
 		reg = <0xf90a9000 0x1000>;
 		qcom,core-id = <2>;
 		qcom,saw2-ver-reg = <0xfd0>;
-		qcom,saw2-cfg = <0x1b>;
+		qcom,saw2-cfg = <0x01>;
 		qcom,saw2-avs-ctl = <0>;
 		qcom,saw2-avs-hysteresis = <0>;
 		qcom,saw2-avs-limit = <0>;
@@ -72,11 +70,10 @@
 		qcom,saw2-spm-dly= <0x20000400>;
 		qcom,saw2-spm-ctl = <0x1>;
 		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
-		qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 92
-				a0 b0 03 68 70 3b 92 a0 b0
-				82 2b 50 10 30 02 22 30 0f];
-		qcom,saw2-spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
-				a0 b0 82 10 30 02 22 30 0f];
+		qcom,saw2-spm-cmd-spc = [00 20 80 10 90 a0 b0 03 3b 98 a2 b0 82
+				10 0b 30 06 26 30 0f];
+		qcom,saw2-spm-cmd-pc = [00 20 80 10 90 a0 b0 07 3b 98 a2 b0 82
+				10 0b 30 06 26 30 0f];
 	};
 
 	qcom,spm@f90b9000 {
@@ -86,7 +83,7 @@
 		reg = <0xf90b9000 0x1000>;
 		qcom,core-id = <3>;
 		qcom,saw2-ver-reg = <0xfd0>;
-		qcom,saw2-cfg = <0x1b>;
+		qcom,saw2-cfg = <0x01>;
 		qcom,saw2-avs-ctl = <0>;
 		qcom,saw2-avs-hysteresis = <0>;
 		qcom,saw2-avs-limit = <0>;
@@ -94,11 +91,10 @@
 		qcom,saw2-spm-dly= <0x20000400>;
 		qcom,saw2-spm-ctl = <0x1>;
 		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
-		qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 92
-				a0 b0 03 68 70 3b 92 a0 b0
-				82 2b 50 10 30 02 22 30 0f];
-		qcom,saw2-spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
-				a0 b0 82 10 30 02 22 30 0f];
+		qcom,saw2-spm-cmd-spc = [00 20 80 10 90 a0 b0 03 3b 98 a2 b0 82
+				10 0b 30 06 26 30 0f];
+		qcom,saw2-spm-cmd-pc = [00 20 80 10 90 a0 b0 07 3b 98 a2 b0 82
+				10 0b 30 06 26 30 0f];
 	};
 
 	qcom,spm@f9012000 {
@@ -108,28 +104,23 @@
 		reg = <0xf9012000 0x1000>;
 		qcom,core-id = <0xffff>; /* L2/APCS SAW */
 		qcom,saw2-ver-reg = <0xfd0>;
-		qcom,saw2-cfg = <0x1a>;
+		qcom,saw2-cfg = <0x14>;
 		qcom,saw2-avs-ctl = <0>;
 		qcom,saw2-avs-hysteresis = <0>;
 		qcom,saw2-avs-limit = <0>;
 		qcom,saw2-avs-dly= <0>;
 		qcom,saw2-spm-dly= <0x20000400>;
-		qcom,saw2-spm-ctl = <0x0>; /* TODO: Enable L2 SPM */
-		qcom,saw2-pmic-dly = <0x02020204>;
-		qcom,saw2-pmic-data0 = <0x0400009c>;
-		qcom,saw2-pmic-data1 = <0x00000060>;
-		qcom,saw2-pmic-data2 = <0x0000001c>;
-		qcom,saw2-pmic-data3 = <0x04000000>;
+		qcom,saw2-spm-ctl = <0x1>;
+		qcom,saw2-pmic-data0 = <0x02030080>;
+		qcom,saw2-pmic-data1 = <0x00030000>;
 		qcom,vctl-timeout-us = <50>;
-		qcom,vctl-port = <0x0>; /* TODO: */
-		qcom,phase-port = <0x1>; /* TODO: */
-		qcom,saw2-spm-cmd-ret = [0b 00 20 03 22 00 0f];
-		qcom,saw2-spm-cmd-gdhs =  [00 20 32 60 70 80 0b 42 07
-				      78 80 44 22 50 3b 60 02 32
-				      50 0f];
-		qcom,saw2-spm-cmd-pc = [00 10 32 60 70 80 b0 11 0b
-				42 07 01 b0 78 80 12 44 a0 50
-				3b 60 02 32 a0 50 0f];
+		qcom,vctl-port = <0x0>;
+		qcom,phase-port = <0x1>;
+		qcom,saw2-spm-cmd-ret = [00 20 03 22 00 0f];
+		qcom,saw2-spm-cmd-gdhs = [00 20 32 0b 42 07 44 22 50 02 32 50
+				0f];
+		qcom,saw2-spm-cmd-pc = [00 10 32 b0 11 0b 42 07 01 b0 12 44 a0
+				50 02 32 a0 50 0f];
 	};
 
 	qcom,lpm-resources {
@@ -311,14 +302,14 @@
 	qcom,mpm@fc4281d0 {
 		compatible = "qcom,mpm-v2";
 		reg = <0xfc4281d0 0x1000>, /* MSM_RPM_MPM_BASE 4K */
-		    <0xfa006000 0x1000>;   /* MSM_APCS_GCC_BASE 4K */
+		    <0xf9011008 0x4>;   /* MSM_APCS_GCC_BASE 4K */
 		reg-names = "vmpm", "ipc";
 		interrupts = <0 171 1>;
 
-		qcom,ipc-bit-offset = <0>;
+		qcom,ipc-bit-offset = <1>;
 
 		qcom,gic-parent = <&intc>;
-		qcom,gic-map = <41 180>, /* usb2_hsic_async_wakeup_irq */
+		qcom,gic-map = <47 180>, /* usb2_hsic_async_wakeup_irq */
 			<53 104>, /* mdss_irq */
 			<0xff 57>,  /* mss_to_apps_irq(0) */
 			<0xff 58>,  /* mss_to_apps_irq(1) */
diff --git a/arch/arm/boot/dts/msm9625-cdp.dts b/arch/arm/boot/dts/msm9625-cdp.dts
new file mode 100644
index 0000000..6733f59
--- /dev/null
+++ b/arch/arm/boot/dts/msm9625-cdp.dts
@@ -0,0 +1,21 @@
+/* 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.
+ */
+
+/dts-v1/;
+
+/include/ "msm9625.dtsi"
+
+/ {
+	model = "Qualcomm MSM 9625 CDP";
+	compatible = "qcom,msm9625-cdp", "qcom,msm9625";
+	qcom,msm-id = <134 1 0>;
+};
diff --git a/arch/arm/boot/dts/msm9625-mtp.dts b/arch/arm/boot/dts/msm9625-mtp.dts
new file mode 100644
index 0000000..32185dc
--- /dev/null
+++ b/arch/arm/boot/dts/msm9625-mtp.dts
@@ -0,0 +1,21 @@
+/* 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.
+ */
+
+/dts-v1/;
+
+/include/ "msm9625.dtsi"
+
+/ {
+	model = "Qualcomm MSM 9625 MTP";
+	compatible = "qcom,msm9625-mtp", "qcom,msm9625";
+	qcom,msm-id = <134 8 0>;
+};
diff --git a/arch/arm/boot/dts/msm9625-rumi.dts b/arch/arm/boot/dts/msm9625-rumi.dts
new file mode 100644
index 0000000..e4fa000
--- /dev/null
+++ b/arch/arm/boot/dts/msm9625-rumi.dts
@@ -0,0 +1,21 @@
+/* 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.
+ */
+
+/dts-v1/;
+
+/include/ "msm9625.dtsi"
+
+/ {
+	model = "Qualcomm MSM 9625 RUMI";
+	compatible = "qcom,msm9625-rumi", "qcom,msm9625";
+	qcom,msm-id = <134 15 0>;
+};
diff --git a/arch/arm/boot/dts/msm9625.dts b/arch/arm/boot/dts/msm9625.dtsi
similarity index 73%
rename from arch/arm/boot/dts/msm9625.dts
rename to arch/arm/boot/dts/msm9625.dtsi
index 42425ed..7b7adca 100644
--- a/arch/arm/boot/dts/msm9625.dts
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -10,7 +10,6 @@
  * GNU General Public License for more details.
  */
 
-/dts-v1/;
 /include/ "skeleton.dtsi"
 
 / {
@@ -76,4 +75,35 @@
 		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>;
+		};
+	};
+
+	qcom,wdt@f9017000 {
+		compatible = "qcom,msm-watchdog";
+		reg = <0xf9017000 0x1000>;
+		interrupts = <1 2 0>, <1 1 0>;
+		qcom,bark-time = <11000>;
+		qcom,pet-time = <10000>;
+		qcom,ipi-ping = <0>;
+	};
 };
diff --git a/arch/arm/common/cpaccess.c b/arch/arm/common/cpaccess.c
index 12e2c38..85cd09f 100644
--- a/arch/arm/common/cpaccess.c
+++ b/arch/arm/common/cpaccess.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, 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
@@ -149,7 +149,8 @@
 
 	asm volatile (".globl cpaccess_dummy_inst\n"
 			"cpaccess_dummy_inst:\n\t"
-			"mrc p15, 0, %0, c0, c0, 0\n\t" : "=r" (ret));
+			"mrc p15, 0, %0, c0, c0, 0\n\t" : "=r" (ret) :
+				"r" (write_val));
 	return ret;
 } __attribute__((aligned(32)))
 
diff --git a/arch/arm/common/dmabounce.c b/arch/arm/common/dmabounce.c
index 595ecd29..9d7eb53 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",
@@ -307,8 +308,9 @@
  * substitute the safe buffer for the unsafe one.
  * (basically move the buffer from an unsafe area to a safe one)
  */
-dma_addr_t __dma_map_page(struct device *dev, struct page *page,
-		unsigned long offset, size_t size, enum dma_data_direction dir)
+static dma_addr_t dmabounce_map_page(struct device *dev, struct page *page,
+		unsigned long offset, size_t size, enum dma_data_direction dir,
+		struct dma_attrs *attrs)
 {
 	dma_addr_t dma_addr;
 	int ret;
@@ -320,21 +322,20 @@
 
 	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);
+		arm_dma_ops.sync_single_for_device(dev, dma_addr, size, dir);
 		return dma_addr;
 	}
 
 	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);
 }
-EXPORT_SYMBOL(__dma_map_page);
 
 /*
  * see if a mapped address was really a "safe" buffer and if so, copy
@@ -342,8 +343,8 @@
  * the safe buffer.  (basically return things back to the way they
  * should be)
  */
-void __dma_unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size,
-		enum dma_data_direction dir)
+static void dmabounce_unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size,
+		enum dma_data_direction dir, struct dma_attrs *attrs)
 {
 	struct safe_buffer *buf;
 
@@ -352,19 +353,18 @@
 
 	buf = find_safe_buffer_dev(dev, dma_addr, __func__);
 	if (!buf) {
-		__dma_page_dev_to_cpu(pfn_to_page(dma_to_pfn(dev, dma_addr)),
-			dma_addr & ~PAGE_MASK, size, dir);
+		arm_dma_ops.sync_single_for_cpu(dev, dma_addr, size, dir);
 		return;
 	}
 
 	unmap_single(dev, buf, size, dir);
 }
-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)
+static int __dmabounce_sync_for_cpu(struct device *dev, dma_addr_t addr,
+		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 +373,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",
@@ -388,12 +390,21 @@
 	}
 	return 0;
 }
-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)
+static void dmabounce_sync_for_cpu(struct device *dev,
+		dma_addr_t handle, size_t size, enum dma_data_direction dir)
+{
+	if (!__dmabounce_sync_for_cpu(dev, handle, size, dir))
+		return;
+
+	arm_dma_ops.sync_single_for_cpu(dev, handle, size, dir);
+}
+
+static int __dmabounce_sync_for_device(struct device *dev, dma_addr_t addr,
+		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 +413,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",
@@ -417,7 +430,38 @@
 	}
 	return 0;
 }
-EXPORT_SYMBOL(dmabounce_sync_for_device);
+
+static void dmabounce_sync_for_device(struct device *dev,
+		dma_addr_t handle, size_t size, enum dma_data_direction dir)
+{
+	if (!__dmabounce_sync_for_device(dev, handle, size, dir))
+		return;
+
+	arm_dma_ops.sync_single_for_device(dev, handle, size, dir);
+}
+
+static int dmabounce_set_mask(struct device *dev, u64 dma_mask)
+{
+	if (dev->archdata.dmabounce)
+		return 0;
+
+	return arm_dma_ops.set_dma_mask(dev, dma_mask);
+}
+
+static struct dma_map_ops dmabounce_ops = {
+	.alloc			= arm_dma_alloc,
+	.free			= arm_dma_free,
+	.mmap			= arm_dma_mmap,
+	.map_page		= dmabounce_map_page,
+	.unmap_page		= dmabounce_unmap_page,
+	.sync_single_for_cpu	= dmabounce_sync_for_cpu,
+	.sync_single_for_device	= dmabounce_sync_for_device,
+	.map_sg			= arm_dma_map_sg,
+	.unmap_sg		= arm_dma_unmap_sg,
+	.sync_sg_for_cpu	= arm_dma_sync_sg_for_cpu,
+	.sync_sg_for_device	= arm_dma_sync_sg_for_device,
+	.set_dma_mask		= dmabounce_set_mask,
+};
 
 static int dmabounce_init_pool(struct dmabounce_pool *pool, struct device *dev,
 		const char *name, unsigned long size)
@@ -479,6 +523,7 @@
 #endif
 
 	dev->archdata.dmabounce = device_info;
+	set_dma_ops(dev, &dmabounce_ops);
 
 	dev_info(dev, "dmabounce: registered device\n");
 
@@ -497,6 +542,7 @@
 	struct dmabounce_device_info *device_info = dev->archdata.dmabounce;
 
 	dev->archdata.dmabounce = NULL;
+	set_dma_ops(dev, NULL);
 
 	if (!device_info) {
 		dev_warn(dev,
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
index bbd6c63..9dd4347 100644
--- a/arch/arm/common/gic.c
+++ b/arch/arm/common/gic.c
@@ -367,7 +367,8 @@
 	if (gic_arch_extn.irq_retrigger)
 		return gic_arch_extn.irq_retrigger(d);
 
-	return -ENXIO;
+	/* the genirq layer expects 0 for a failure */
+	return 0;
 }
 
 #ifdef CONFIG_SMP
diff --git a/arch/arm/configs/msm7627a-perf_defconfig b/arch/arm/configs/msm7627a-perf_defconfig
index a8abb30..1b792d9 100644
--- a/arch/arm/configs/msm7627a-perf_defconfig
+++ b/arch/arm/configs/msm7627a-perf_defconfig
@@ -53,6 +53,8 @@
 CONFIG_PM8XXX_RPC_VIBRATOR=y
 CONFIG_MSM_SPM_V2=y
 CONFIG_MSM_MULTIMEDIA_USE_ION=y
+CONFIG_MSM_CPR=y
+CONFIG_MSM_VP_REGULATOR=y
 CONFIG_ARM_THUMBEE=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
@@ -81,9 +83,13 @@
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
+CONFIG_NET_KEY=y
 CONFIG_INET=y
 CONFIG_IP_ADVANCED_ROUTER=y
 CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_INET_AH=y
+CONFIG_INET_ESP=y
+CONFIG_INET_IPCOMP=y
 CONFIG_IPV6=y
 CONFIG_IPV6_PRIVACY=y
 CONFIG_IPV6_ROUTER_PREF=y
@@ -154,10 +160,20 @@
 CONFIG_IP_NF_TARGET_NETMAP=y
 CONFIG_IP_NF_TARGET_REDIRECT=y
 CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
 CONFIG_IP_NF_ARPTABLES=y
 CONFIG_IP_NF_ARPFILTER=y
 CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
 CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_ATM=y
+CONFIG_L2TP=y
+CONFIG_L2TP_DEBUGFS=y
+CONFIG_L2TP_V3=y
+CONFIG_L2TP_IP=y
+CONFIG_L2TP_ETH=y
 CONFIG_BT=y
 CONFIG_BT_RFCOMM=y
 CONFIG_BT_RFCOMM_TTY=y
@@ -196,6 +212,19 @@
 CONFIG_TUN=y
 CONFIG_SMC91X=y
 CONFIG_SMSC911X=y
+CONFIG_PPP=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_MPPE=y
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPPOATM=m
+CONFIG_PPPOE=y
+CONFIG_PPPOL2TP=y
+CONFIG_PPPOLAC=y
+CONFIG_PPPOPNS=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_SYNC_TTY=y
 CONFIG_LIBRA_SDIOIF=m
 # CONFIG_INPUT_MOUSEDEV is not set
 CONFIG_INPUT_EVDEV=y
diff --git a/arch/arm/configs/msm7627a_defconfig b/arch/arm/configs/msm7627a_defconfig
index 00325c9..25d97af 100644
--- a/arch/arm/configs/msm7627a_defconfig
+++ b/arch/arm/configs/msm7627a_defconfig
@@ -53,6 +53,8 @@
 CONFIG_PM8XXX_RPC_VIBRATOR=y
 CONFIG_MSM_SPM_V2=y
 CONFIG_MSM_MULTIMEDIA_USE_ION=y
+CONFIG_MSM_CPR=y
+CONFIG_MSM_VP_REGULATOR=y
 CONFIG_ARM_THUMBEE=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
@@ -81,9 +83,13 @@
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
+CONFIG_NET_KEY=y
 CONFIG_INET=y
 CONFIG_IP_ADVANCED_ROUTER=y
 CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_INET_AH=y
+CONFIG_INET_ESP=y
+CONFIG_INET_IPCOMP=y
 CONFIG_IPV6=y
 CONFIG_IPV6_PRIVACY=y
 CONFIG_IPV6_ROUTER_PREF=y
@@ -154,10 +160,20 @@
 CONFIG_IP_NF_TARGET_NETMAP=y
 CONFIG_IP_NF_TARGET_REDIRECT=y
 CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
 CONFIG_IP_NF_ARPTABLES=y
 CONFIG_IP_NF_ARPFILTER=y
 CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
 CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_ATM=y
+CONFIG_L2TP=y
+CONFIG_L2TP_DEBUGFS=y
+CONFIG_L2TP_V3=y
+CONFIG_L2TP_IP=y
+CONFIG_L2TP_ETH=y
 CONFIG_BT=y
 CONFIG_BT_RFCOMM=y
 CONFIG_BT_RFCOMM_TTY=y
@@ -196,6 +212,19 @@
 CONFIG_TUN=y
 CONFIG_SMC91X=y
 CONFIG_SMSC911X=y
+CONFIG_PPP=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_MPPE=y
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPPOATM=m
+CONFIG_PPPOE=y
+CONFIG_PPPOL2TP=y
+CONFIG_PPPOLAC=y
+CONFIG_PPPOPNS=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_SYNC_TTY=y
 CONFIG_LIBRA_SDIOIF=m
 # CONFIG_INPUT_MOUSEDEV is not set
 CONFIG_INPUT_EVDEV=y
diff --git a/arch/arm/configs/msm8660-perf_defconfig b/arch/arm/configs/msm8660-perf_defconfig
index a51b76d..957dbcf 100644
--- a/arch/arm/configs/msm8660-perf_defconfig
+++ b/arch/arm/configs/msm8660-perf_defconfig
@@ -70,6 +70,7 @@
 CONFIG_MSM_PIL_DSPS=y
 CONFIG_MSM_PIL_VIDC=y
 CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_SYSMON_COMM=y
 CONFIG_MSM_TZ_LOG=y
 CONFIG_MSM_RPM_LOG=y
 CONFIG_MSM_RPM_STATS_LOG=y
@@ -86,6 +87,7 @@
 CONFIG_AEABI=y
 CONFIG_HIGHMEM=y
 CONFIG_VMALLOC_RESERVE=0x19000000
+CONFIG_COMPACTION=y
 CONFIG_CP_ACCESS=y
 CONFIG_CPU_FREQ=y
 CONFIG_CPU_FREQ_GOV_POWERSAVE=y
@@ -181,12 +183,14 @@
 CONFIG_IP_NF_TARGET_NETMAP=y
 CONFIG_IP_NF_TARGET_REDIRECT=y
 CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
 CONFIG_IP_NF_ARPTABLES=y
 CONFIG_IP_NF_ARPFILTER=y
 CONFIG_IP_NF_ARP_MANGLE=y
 CONFIG_IP6_NF_IPTABLES=y
 CONFIG_IP6_NF_FILTER=y
 CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
 CONFIG_NET_SCHED=y
 CONFIG_NET_SCH_HTB=y
 CONFIG_NET_SCH_PRIO=y
diff --git a/arch/arm/configs/msm8660_defconfig b/arch/arm/configs/msm8660_defconfig
index 0efe658..4e5479a 100644
--- a/arch/arm/configs/msm8660_defconfig
+++ b/arch/arm/configs/msm8660_defconfig
@@ -69,6 +69,7 @@
 CONFIG_MSM_PIL_DSPS=y
 CONFIG_MSM_PIL_VIDC=y
 CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_SYSMON_COMM=y
 CONFIG_MSM_TZ_LOG=y
 CONFIG_MSM_RPM_LOG=y
 CONFIG_MSM_RPM_STATS_LOG=y
@@ -86,6 +87,7 @@
 CONFIG_AEABI=y
 CONFIG_HIGHMEM=y
 CONFIG_VMALLOC_RESERVE=0x19000000
+CONFIG_COMPACTION=y
 CONFIG_CP_ACCESS=y
 CONFIG_CPU_FREQ=y
 CONFIG_CPU_FREQ_GOV_POWERSAVE=y
@@ -181,12 +183,14 @@
 CONFIG_IP_NF_TARGET_NETMAP=y
 CONFIG_IP_NF_TARGET_REDIRECT=y
 CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
 CONFIG_IP_NF_ARPTABLES=y
 CONFIG_IP_NF_ARPFILTER=y
 CONFIG_IP_NF_ARP_MANGLE=y
 CONFIG_IP6_NF_IPTABLES=y
 CONFIG_IP6_NF_FILTER=y
 CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
 CONFIG_NET_SCHED=y
 CONFIG_NET_SCH_HTB=y
 CONFIG_NET_SCH_PRIO=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index 3854403..2c8f71e 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
@@ -77,6 +77,7 @@
 CONFIG_MSM_PIL_VIDC=y
 CONFIG_MSM_PIL_GSS=y
 CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_SYSMON_COMM=y
 CONFIG_MSM_MODEM_8960=y
 CONFIG_MSM_LPASS_8960=y
 CONFIG_MSM_WCNSS_SSR_8960=y
@@ -114,6 +115,7 @@
 CONFIG_CPU_FREQ_GOV_POWERSAVE=y
 CONFIG_CPU_FREQ_GOV_USERSPACE=y
 CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
 CONFIG_CPU_IDLE=y
 CONFIG_VFP=y
 CONFIG_NEON=y
@@ -203,6 +205,7 @@
 CONFIG_IP_NF_TARGET_NETMAP=y
 CONFIG_IP_NF_TARGET_REDIRECT=y
 CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
 CONFIG_IP_NF_ARPTABLES=y
 CONFIG_IP_NF_ARPFILTER=y
 CONFIG_IP_NF_ARP_MANGLE=y
@@ -211,6 +214,7 @@
 CONFIG_IP6_NF_FILTER=y
 CONFIG_IP6_NF_TARGET_REJECT=y
 CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
 CONFIG_NET_SCHED=y
 CONFIG_NET_SCH_HTB=y
 CONFIG_NET_SCH_PRIO=y
@@ -225,6 +229,7 @@
 CONFIG_NET_EMATCH_META=y
 CONFIG_NET_EMATCH_TEXT=y
 CONFIG_NET_CLS_ACT=y
+CONFIG_MARIMBA_CORE=y
 CONFIG_BT=y
 CONFIG_BT_RFCOMM=y
 CONFIG_BT_RFCOMM_TTY=y
@@ -234,6 +239,8 @@
 CONFIG_BT_HIDP=y
 CONFIG_BT_HCISMD=y
 CONFIG_BT_HCIUART=y
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_IBS=y
 CONFIG_BT_HCIUART_ATH3K=y
 CONFIG_MSM_BT_POWER=y
 CONFIG_CFG80211=m
@@ -291,6 +298,7 @@
 CONFIG_STM_LIS3DH=y
 CONFIG_INPUT_MPU3050=y
 # CONFIG_LEGACY_PTYS is not set
+CONFIG_MSM_IPC_LOGGING=y
 CONFIG_N_SMUX=y
 CONFIG_N_SMUX_LOOPBACK=y
 CONFIG_SMUX_CTL=y
@@ -317,6 +325,7 @@
 CONFIG_SMB349_CHARGER=y
 CONFIG_PM8921_CHARGER=y
 CONFIG_PM8921_BMS=y
+CONFIG_BATTERY_BCL=y
 CONFIG_SENSORS_PM8XXX_ADC=y
 CONFIG_SENSORS_EPM_ADC=y
 CONFIG_THERMAL=y
@@ -415,11 +424,11 @@
 CONFIG_USB_STORAGE_KARMA=y
 CONFIG_USB_STORAGE_CYPRESS_ATACB=y
 CONFIG_USB_SERIAL=y
-CONFIG_USB_SERIAL_QUALCOMM=y
 CONFIG_USB_SERIAL_CSVT=y
 CONFIG_USB_EHSET_TEST_FIXTURE=y
 CONFIG_USB_QCOM_DIAG_BRIDGE=y
 CONFIG_USB_QCOM_MDM_BRIDGE=y
+CONFIG_USB_QCOM_KS_BRIDGE=y
 CONFIG_USB_GADGET=y
 CONFIG_USB_GADGET_DEBUG_FILES=y
 CONFIG_USB_CI13XXX_MSM=y
@@ -492,3 +501,4 @@
 CONFIG_CRYPTO_DEV_QCE=m
 CONFIG_CRYPTO_DEV_QCEDEV=m
 CONFIG_CRC_CCITT=y
+CONFIG_WCNSS_MEM_PRE_ALLOC=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 06501ba..a2deab2 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
@@ -76,6 +76,7 @@
 CONFIG_MSM_PIL_VIDC=y
 CONFIG_MSM_PIL_GSS=y
 CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_SYSMON_COMM=y
 CONFIG_MSM_MODEM_8960=y
 CONFIG_MSM_LPASS_8960=y
 CONFIG_MSM_WCNSS_SSR_8960=y
@@ -118,6 +119,7 @@
 CONFIG_CPU_FREQ_GOV_POWERSAVE=y
 CONFIG_CPU_FREQ_GOV_USERSPACE=y
 CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
 CONFIG_CPU_IDLE=y
 CONFIG_VFP=y
 CONFIG_NEON=y
@@ -207,6 +209,7 @@
 CONFIG_IP_NF_TARGET_NETMAP=y
 CONFIG_IP_NF_TARGET_REDIRECT=y
 CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
 CONFIG_IP_NF_ARPTABLES=y
 CONFIG_IP_NF_ARPFILTER=y
 CONFIG_IP_NF_ARP_MANGLE=y
@@ -215,6 +218,7 @@
 CONFIG_IP6_NF_FILTER=y
 CONFIG_IP6_NF_TARGET_REJECT=y
 CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
 CONFIG_NET_SCHED=y
 CONFIG_NET_SCH_HTB=y
 CONFIG_NET_SCH_PRIO=y
@@ -229,6 +233,7 @@
 CONFIG_NET_EMATCH_META=y
 CONFIG_NET_EMATCH_TEXT=y
 CONFIG_NET_CLS_ACT=y
+CONFIG_MARIMBA_CORE=y
 CONFIG_BT=y
 CONFIG_BT_RFCOMM=y
 CONFIG_BT_RFCOMM_TTY=y
@@ -239,6 +244,8 @@
 CONFIG_BT_HCISMD=y
 CONFIG_BT_HCIUART=y
 CONFIG_BT_HCIUART_ATH3K=y
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_IBS=y
 CONFIG_MSM_BT_POWER=y
 CONFIG_CFG80211=m
 # CONFIG_CFG80211_WEXT is not set
@@ -295,6 +302,7 @@
 CONFIG_STM_LIS3DH=y
 CONFIG_INPUT_MPU3050=y
 # CONFIG_LEGACY_PTYS is not set
+CONFIG_MSM_IPC_LOGGING=y
 CONFIG_N_SMUX=y
 CONFIG_N_SMUX_LOOPBACK=y
 CONFIG_SMUX_CTL=y
@@ -321,6 +329,7 @@
 CONFIG_SMB349_CHARGER=y
 CONFIG_PM8921_CHARGER=y
 CONFIG_PM8921_BMS=y
+CONFIG_BATTERY_BCL=y
 CONFIG_SENSORS_PM8XXX_ADC=y
 CONFIG_SENSORS_EPM_ADC=y
 CONFIG_THERMAL=y
@@ -417,11 +426,11 @@
 CONFIG_USB_STORAGE_KARMA=y
 CONFIG_USB_STORAGE_CYPRESS_ATACB=y
 CONFIG_USB_SERIAL=y
-CONFIG_USB_SERIAL_QUALCOMM=y
 CONFIG_USB_SERIAL_CSVT=y
 CONFIG_USB_EHSET_TEST_FIXTURE=y
 CONFIG_USB_QCOM_DIAG_BRIDGE=y
 CONFIG_USB_QCOM_MDM_BRIDGE=y
+CONFIG_USB_QCOM_KS_BRIDGE=y
 CONFIG_USB_GADGET=y
 CONFIG_USB_GADGET_DEBUG_FILES=y
 CONFIG_USB_CI13XXX_MSM=y
@@ -509,3 +518,4 @@
 CONFIG_CRYPTO_DEV_QCE=m
 CONFIG_CRYPTO_DEV_QCEDEV=m
 CONFIG_CRC_CCITT=y
+CONFIG_WCNSS_MEM_PRE_ALLOC=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index da7bfd4..53c2211 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -48,15 +48,25 @@
 CONFIG_MSM_PIL_MBA=y
 CONFIG_MSM_PIL_VENUS=y
 CONFIG_MSM_PIL_PRONTO=y
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_MODEM_SSR_8974=y
+CONFIG_MSM_ADSP_SSR_8974=y
 CONFIG_MSM_TZ_LOG=y
 CONFIG_MSM_DIRECT_SCLK_ACCESS=y
+CONFIG_MSM_QDSS=y
 CONFIG_MSM_OCMEM=y
 CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
+CONFIG_MSM_OCMEM_DEBUG=y
+CONFIG_MSM_OCMEM_NONSECURE=y
 CONFIG_MSM_MEMORY_DUMP=y
+CONFIG_MSM_WATCHDOG_V2=y
+CONFIG_MSM_DLOAD_MODE=y
+CONFIG_PANIC_TIMEOUT=5
 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_MSM_ADSP_LOADER=m
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_SMP=y
@@ -77,6 +87,7 @@
 CONFIG_VFP=y
 CONFIG_NEON=y
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_WAKELOCK=y
 CONFIG_PM_RUNTIME=y
 CONFIG_NET=y
 CONFIG_PACKET=y
@@ -102,6 +113,12 @@
 CONFIG_IPV6_MIP6=y
 CONFIG_IPV6_MULTIPLE_TABLES=y
 CONFIG_IPV6_SUBTREES=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_PRIO=y
+CONFIG_NET_CLS_FW=y
+CONFIG_GENLOCK=y
+CONFIG_GENLOCK_MISCDEVICE=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_QSEECOM=y
@@ -121,10 +138,14 @@
 CONFIG_DUMMY=y
 CONFIG_KS8851=m
 # CONFIG_MSM_RMNET is not set
+CONFIG_MSM_RMNET_BAM=y
 CONFIG_INPUT_EVDEV=y
 CONFIG_INPUT_EVBUG=m
+CONFIG_KEYBOARD_GPIO=y
 CONFIG_INPUT_JOYSTICK=y
 CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH=n
+CONFIG_TOUCHSCREEN_ATMEL_MXT=y
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_UINPUT=y
 CONFIG_SERIAL_MSM_HSL=y
@@ -132,10 +153,10 @@
 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_QUP=y
+CONFIG_MSM_BUS_SCALING=y
 CONFIG_SPI=y
 CONFIG_SPI_QUP=y
 CONFIG_SPI_SPIDEV=m
@@ -150,18 +171,36 @@
 CONFIG_GPIO_QPNP_PIN_DEBUG=y
 CONFIG_POWER_SUPPLY=y
 # CONFIG_BATTERY_MSM is not set
-# CONFIG_HWMON is not set
+CONFIG_HWMON=y
+CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
+CONFIG_SENSORS_QPNP_ADC_CURRENT=y
 CONFIG_THERMAL=y
 CONFIG_THERMAL_TSENS8974=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
 CONFIG_REGULATOR_STUB=y
 CONFIG_REGULATOR_QPNP=y
 CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
 CONFIG_VIDEO_DEV=y
-# CONFIG_RC_CORE is not set
-# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
 CONFIG_VIDEOBUF2_MSM_MEM=y
-# CONFIG_VIDEO_CAPTURE_DRIVERS is not set
-# CONFIG_RADIO_ADAPTERS is not set
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_MSM_CAMERA_V4L2=y
+CONFIG_MSM_CAMERA_SENSOR=y
+CONFIG_MSM_ACTUATOR=y
+CONFIG_MSM_CAM_IRQ_ROUTER=n
+CONFIG_MSM_CCI=y
+CONFIG_MSM_CSI30_HEADER=y
+CONFIG_MSM_CSIPHY=y
+CONFIG_MSM_CSID=y
+CONFIG_MSM_CSI2_REGISTER=y
+CONFIG_MSM_ISPIF=y
+CONFIG_S5K3L1YX=y
+CONFIG_OV2720=y
+CONFIG_MSM_JPEG=y
+CONFIG_RADIO_IRIS=y
+CONFIG_RADIO_IRIS_TRANSPORT=m
+CONFIG_RADIO_ADAPTERS=y
 CONFIG_ION=y
 CONFIG_ION_MSM=y
 CONFIG_MSM_KGSL=y
@@ -170,6 +209,7 @@
 # CONFIG_FB_MSM_BACKLIGHT is not set
 CONFIG_FB_MSM_MDSS=y
 CONFIG_FB_MSM_MDSS_WRITEBACK=y
+CONFIG_FB_MSM_MDSS_HDMI_PANEL=y
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 # CONFIG_LCD_CLASS_DEVICE is not set
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
@@ -195,6 +235,7 @@
 CONFIG_USB_STORAGE_CYPRESS_ATACB=y
 CONFIG_USB_STORAGE_ENE_UB6250=y
 CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
 CONFIG_USB_CI13XXX_MSM=y
 CONFIG_USB_G_ANDROID=y
 CONFIG_MMC=y
@@ -206,6 +247,13 @@
 # CONFIG_MMC_BLOCK_BOUNCE is not set
 CONFIG_MMC_TEST=m
 CONFIG_MMC_MSM=y
+CONFIG_MMC_MSM_SPS_SUPPORT=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_QPNP=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_BACKLIGHT=y
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
 CONFIG_SWITCH=y
 CONFIG_RTC_CLASS=y
 # CONFIG_RTC_DRV_MSM is not set
@@ -219,9 +267,11 @@
 CONFIG_ANDROID_LOW_MEMORY_KILLER=y
 CONFIG_MSM_SSBI=y
 CONFIG_SPS=y
+CONFIG_USB_BAM=y
 CONFIG_SPS_SUPPORT_BAMDMA=y
 CONFIG_SPS_SUPPORT_NDP_BAM=y
 CONFIG_QPNP_POWER_ON=y
+CONFIG_QPNP_CLKDIV=y
 CONFIG_MSM_IOMMU=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
@@ -242,6 +292,7 @@
 # CONFIG_DEBUG_PREEMPT is not set
 CONFIG_DEBUG_INFO=y
 CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_ENABLE_DEFAULT_TRACERS=y
 CONFIG_DYNAMIC_DEBUG=y
 CONFIG_DEBUG_USER=y
 CONFIG_KEYS=y
@@ -255,4 +306,28 @@
 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
+CONFIG_MSM_BAM_DMUX=y
+CONFIG_WCNSS_CORE=y
+CONFIG_WCNSS_CORE_PRONTO=y
+CONFIG_CFG80211=m
+CONFIG_RFKILL=y
+CONFIG_VIDEO_V4L2=y
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_COMMON=y
+CONFIG_VIDEO_MEDIA=y
diff --git a/arch/arm/configs/msm9615_defconfig b/arch/arm/configs/msm9615_defconfig
index db94f13..2cc801e 100644
--- a/arch/arm/configs/msm9615_defconfig
+++ b/arch/arm/configs/msm9615_defconfig
@@ -147,6 +147,10 @@
 CONFIG_IP6_NF_TARGET_REJECT_SKERR=y
 CONFIG_IP6_NF_MANGLE=y
 CONFIG_IP6_NF_RAW=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_PRIO=y
+CONFIG_NET_CLS_FW=y
 CONFIG_MTD=y
 CONFIG_MTD_TESTS=m
 CONFIG_MTD_CMDLINE_PARTS=y
@@ -211,9 +215,9 @@
 CONFIG_SND=y
 CONFIG_SND_SOC=y
 CONFIG_SND_SOC_MDM9615=y
-# CONFIG_HID_SUPPORT is not set
 CONFIG_USB=y
 CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_SUSPEND=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_EHCI_EHSET=y
 CONFIG_USB_EHCI_MSM=y
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index 9094db7..0057062 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -36,6 +36,7 @@
 # CONFIG_MSM_FIQ_SUPPORT is not set
 # CONFIG_MSM_PROC_COMM is not set
 CONFIG_MSM_DIRECT_SCLK_ACCESS=y
+CONFIG_MSM_WATCHDOG_V2=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_ARM_ARCH_TIMER=y
@@ -56,9 +57,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 +90,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/device.h b/arch/arm/include/asm/device.h
index 7aa3680..b69c0d3 100644
--- a/arch/arm/include/asm/device.h
+++ b/arch/arm/include/asm/device.h
@@ -7,12 +7,16 @@
 #define ASMARM_DEVICE_H
 
 struct dev_archdata {
+	struct dma_map_ops	*dma_ops;
 #ifdef CONFIG_DMABOUNCE
 	struct dmabounce_device_info *dmabounce;
 #endif
 #ifdef CONFIG_IOMMU_API
 	void *iommu; /* private IOMMU data */
 #endif
+#ifdef CONFIG_ARM_DMA_USE_IOMMU
+	struct dma_iommu_mapping	*mapping;
+#endif
 };
 
 struct omap_device;
diff --git a/arch/arm/include/asm/dma-iommu.h b/arch/arm/include/asm/dma-iommu.h
new file mode 100644
index 0000000..799b094
--- /dev/null
+++ b/arch/arm/include/asm/dma-iommu.h
@@ -0,0 +1,34 @@
+#ifndef ASMARM_DMA_IOMMU_H
+#define ASMARM_DMA_IOMMU_H
+
+#ifdef __KERNEL__
+
+#include <linux/mm_types.h>
+#include <linux/scatterlist.h>
+#include <linux/dma-debug.h>
+#include <linux/kmemcheck.h>
+
+struct dma_iommu_mapping {
+	/* iommu specific data */
+	struct iommu_domain	*domain;
+
+	void			*bitmap;
+	size_t			bits;
+	unsigned int		order;
+	dma_addr_t		base;
+
+	spinlock_t		lock;
+	struct kref		kref;
+};
+
+struct dma_iommu_mapping *
+arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, size_t size,
+			 int order);
+
+void arm_iommu_release_mapping(struct dma_iommu_mapping *mapping);
+
+int arm_iommu_attach_device(struct device *dev,
+					struct dma_iommu_mapping *mapping);
+
+#endif /* __KERNEL__ */
+#endif
diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
index dc988ff..5f28327 100644
--- a/arch/arm/include/asm/dma-mapping.h
+++ b/arch/arm/include/asm/dma-mapping.h
@@ -5,11 +5,35 @@
 
 #include <linux/mm_types.h>
 #include <linux/scatterlist.h>
+#include <linux/dma-attrs.h>
 #include <linux/dma-debug.h>
 
 #include <asm-generic/dma-coherent.h>
 #include <asm/memory.h>
 
+#define DMA_ERROR_CODE	(~0)
+extern struct dma_map_ops arm_dma_ops;
+
+static inline struct dma_map_ops *get_dma_ops(struct device *dev)
+{
+	if (dev && dev->archdata.dma_ops)
+		return dev->archdata.dma_ops;
+	return &arm_dma_ops;
+}
+
+static inline void set_dma_ops(struct device *dev, struct dma_map_ops *ops)
+{
+	BUG_ON(!dev);
+	dev->archdata.dma_ops = ops;
+}
+
+#include <asm-generic/dma-mapping-common.h>
+
+static inline int dma_set_mask(struct device *dev, u64 mask)
+{
+	return get_dma_ops(dev)->set_dma_mask(dev, mask);
+}
+
 #ifdef __arch_page_to_dma
 #error Please update to __arch_pfn_to_dma
 #endif
@@ -62,68 +86,11 @@
 #endif
 
 /*
- * The DMA API is built upon the notion of "buffer ownership".  A buffer
- * is either exclusively owned by the CPU (and therefore may be accessed
- * by it) or exclusively owned by the DMA device.  These helper functions
- * represent the transitions between these two ownership states.
- *
- * Note, however, that on later ARMs, this notion does not work due to
- * speculative prefetches.  We model our approach on the assumption that
- * the CPU does do speculative prefetches, which means we clean caches
- * before transfers and delay cache invalidation until transfer completion.
- *
- * Private support functions: these are not part of the API and are
- * liable to change.  Drivers must not use these.
- */
-static inline void __dma_single_cpu_to_dev(const void *kaddr, size_t size,
-	enum dma_data_direction dir)
-{
-	extern void ___dma_single_cpu_to_dev(const void *, size_t,
-		enum dma_data_direction);
-
-	if (!arch_is_coherent())
-		___dma_single_cpu_to_dev(kaddr, size, dir);
-}
-
-static inline void __dma_single_dev_to_cpu(const void *kaddr, size_t size,
-	enum dma_data_direction dir)
-{
-	extern void ___dma_single_dev_to_cpu(const void *, size_t,
-		enum dma_data_direction);
-
-	if (!arch_is_coherent())
-		___dma_single_dev_to_cpu(kaddr, size, dir);
-}
-
-static inline void __dma_page_cpu_to_dev(struct page *page, unsigned long off,
-	size_t size, enum dma_data_direction dir)
-{
-	extern void ___dma_page_cpu_to_dev(struct page *, unsigned long,
-		size_t, enum dma_data_direction);
-
-	if (!arch_is_coherent())
-		___dma_page_cpu_to_dev(page, off, size, dir);
-}
-
-static inline void __dma_page_dev_to_cpu(struct page *page, unsigned long off,
-	size_t size, enum dma_data_direction dir)
-{
-	extern void ___dma_page_dev_to_cpu(struct page *, unsigned long,
-		size_t, enum dma_data_direction);
-
-	if (!arch_is_coherent())
-		___dma_page_dev_to_cpu(page, off, size, dir);
-}
-
-extern int dma_supported(struct device *, u64);
-extern int dma_set_mask(struct device *, u64);
-
-/*
  * DMA errors are defined by all-bits-set in the DMA address.
  */
 static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
 {
-	return dma_addr == ~0;
+	return dma_addr == DMA_ERROR_CODE;
 }
 
 /*
@@ -181,69 +148,118 @@
 #endif
 }
 
+extern int dma_supported(struct device *dev, u64 mask);
+
 /**
- * dma_alloc_coherent - allocate consistent memory for DMA
+ * arm_dma_alloc - allocate consistent memory for DMA
  * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
  * @size: required memory size
  * @handle: bus-specific DMA address
+ * @attrs: optinal attributes that specific mapping properties
  *
- * Allocate some uncached, unbuffered memory for a device for
- * performing DMA.  This function allocates pages, and will
- * return the CPU-viewed address, and sets @handle to be the
- * device-viewed address.
+ * Allocate some memory for a device for performing DMA.  This function
+ * allocates pages, and will return the CPU-viewed address, and sets @handle
+ * to be the device-viewed address.
  */
-extern void *dma_alloc_coherent(struct device *, size_t, dma_addr_t *, gfp_t);
+extern void *arm_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
+			   gfp_t gfp, struct dma_attrs *attrs);
+
+#define dma_alloc_coherent(d, s, h, f) dma_alloc_attrs(d, s, h, f, NULL)
+
+static inline void *dma_alloc_attrs(struct device *dev, size_t size,
+				       dma_addr_t *dma_handle, gfp_t flag,
+				       struct dma_attrs *attrs)
+{
+	struct dma_map_ops *ops = get_dma_ops(dev);
+	void *cpu_addr;
+	BUG_ON(!ops);
+
+	cpu_addr = ops->alloc(dev, size, dma_handle, flag, attrs);
+	debug_dma_alloc_coherent(dev, size, *dma_handle, cpu_addr);
+	return cpu_addr;
+}
 
 /**
- * dma_free_coherent - free memory allocated by dma_alloc_coherent
+ * arm_dma_free - free memory allocated by arm_dma_alloc
  * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
  * @size: size of memory originally requested in dma_alloc_coherent
  * @cpu_addr: CPU-view address returned from dma_alloc_coherent
  * @handle: device-view address returned from dma_alloc_coherent
+ * @attrs: optinal attributes that specific mapping properties
  *
  * Free (and unmap) a DMA buffer previously allocated by
- * dma_alloc_coherent().
+ * arm_dma_alloc().
  *
  * References to memory and mappings associated with cpu_addr/handle
  * during and after this call executing are illegal.
  */
-extern void dma_free_coherent(struct device *, size_t, void *, dma_addr_t);
+extern void arm_dma_free(struct device *dev, size_t size, void *cpu_addr,
+			 dma_addr_t handle, struct dma_attrs *attrs);
+
+#define dma_free_coherent(d, s, c, h) dma_free_attrs(d, s, c, h, NULL)
+
+static inline void dma_free_attrs(struct device *dev, size_t size,
+				     void *cpu_addr, dma_addr_t dma_handle,
+				     struct dma_attrs *attrs)
+{
+	struct dma_map_ops *ops = get_dma_ops(dev);
+	BUG_ON(!ops);
+
+	debug_dma_free_coherent(dev, size, cpu_addr, dma_handle);
+	ops->free(dev, size, cpu_addr, dma_handle, attrs);
+}
 
 /**
- * dma_mmap_coherent - map a coherent DMA allocation into user space
+ * arm_dma_mmap - map a coherent DMA allocation into user space
  * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
  * @vma: vm_area_struct describing requested user mapping
  * @cpu_addr: kernel CPU-view address returned from dma_alloc_coherent
  * @handle: device-view address returned from dma_alloc_coherent
  * @size: size of memory originally requested in dma_alloc_coherent
+ * @attrs: optinal attributes that specific mapping properties
  *
  * Map a coherent DMA buffer previously allocated by dma_alloc_coherent
  * into user space.  The coherent DMA buffer must not be freed by the
  * driver until the user space mapping has been released.
  */
-int dma_mmap_coherent(struct device *, struct vm_area_struct *,
-		void *, dma_addr_t, size_t);
+extern int arm_dma_mmap(struct device *dev, struct vm_area_struct *vma,
+			void *cpu_addr, dma_addr_t dma_addr, size_t size,
+			struct dma_attrs *attrs);
 
+#define dma_mmap_coherent(d, v, c, h, s) dma_mmap_attrs(d, v, c, h, s, NULL)
 
-/**
- * dma_alloc_writecombine - allocate writecombining memory for DMA
- * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
- * @size: required memory size
- * @handle: bus-specific DMA address
- *
- * Allocate some uncached, buffered memory for a device for
- * performing DMA.  This function allocates pages, and will
- * return the CPU-viewed address, and sets @handle to be the
- * device-viewed address.
- */
-extern void *dma_alloc_writecombine(struct device *, size_t, dma_addr_t *,
-		gfp_t);
+static inline int dma_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
+				  void *cpu_addr, dma_addr_t dma_addr,
+				  size_t size, struct dma_attrs *attrs)
+{
+	struct dma_map_ops *ops = get_dma_ops(dev);
+	BUG_ON(!ops);
+	return ops->mmap(dev, vma, cpu_addr, dma_addr, size, attrs);
+}
 
-#define dma_free_writecombine(dev,size,cpu_addr,handle) \
-	dma_free_coherent(dev,size,cpu_addr,handle)
+static inline void *dma_alloc_writecombine(struct device *dev, size_t size,
+				       dma_addr_t *dma_handle, gfp_t flag)
+{
+	DEFINE_DMA_ATTRS(attrs);
+	dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs);
+	return dma_alloc_attrs(dev, size, dma_handle, flag, &attrs);
+}
 
-int dma_mmap_writecombine(struct device *, struct vm_area_struct *,
-		void *, dma_addr_t, size_t);
+static inline void dma_free_writecombine(struct device *dev, size_t size,
+				     void *cpu_addr, dma_addr_t dma_handle)
+{
+	DEFINE_DMA_ATTRS(attrs);
+	dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs);
+	return dma_free_attrs(dev, size, cpu_addr, dma_handle, &attrs);
+}
+
+static inline int dma_mmap_writecombine(struct device *dev, struct vm_area_struct *vma,
+		      void *cpu_addr, dma_addr_t dma_addr, size_t size)
+{
+	DEFINE_DMA_ATTRS(attrs);
+	dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs);
+	return dma_mmap_attrs(dev, vma, cpu_addr, dma_addr, size, &attrs);
+}
 
 /*
  * This can be called during boot to increase the size of the consistent
@@ -252,8 +268,6 @@
  */
 extern void __init init_consistent_dma_size(unsigned long size);
 
-
-#ifdef CONFIG_DMABOUNCE
 /*
  * For SA-1111, IXP425, and ADI systems  the dma-mapping functions are "magic"
  * and utilize bounce buffers as needed to work around limited DMA windows.
@@ -293,82 +307,7 @@
  */
 extern void dmabounce_unregister_dev(struct device *);
 
-/*
- * The DMA API, implemented by dmabounce.c.  See below for descriptions.
- */
-extern dma_addr_t __dma_map_page(struct device *, struct page *,
-		unsigned long, size_t, enum dma_data_direction);
-extern void __dma_unmap_page(struct device *, dma_addr_t, size_t,
-		enum dma_data_direction);
 
-/*
- * 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);
-#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)
-{
-	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)
-{
-	return 1;
-}
-
-
-static inline dma_addr_t __dma_map_page(struct device *dev, struct page *page,
-	     unsigned long offset, size_t size, enum dma_data_direction dir)
-{
-	__dma_page_cpu_to_dev(page, offset, size, dir);
-	return pfn_to_dma(dev, page_to_pfn(page)) + offset;
-}
-
-static inline void __dma_unmap_page(struct device *dev, dma_addr_t handle,
-		size_t size, enum dma_data_direction dir)
-{
-	__dma_page_dev_to_cpu(pfn_to_page(dma_to_pfn(dev, handle)),
-		handle & ~PAGE_MASK, size, dir);
-}
-#endif /* CONFIG_DMABOUNCE */
-
-/**
- * dma_map_single - map a single buffer for streaming DMA
- * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
- * @cpu_addr: CPU direct mapped address of buffer
- * @size: size of buffer to map
- * @dir: DMA transfer direction
- *
- * Ensure that any data held in the cache is appropriately discarded
- * or written back.
- *
- * The device owns this memory once this call has completed.  The CPU
- * can regain ownership by calling dma_unmap_single() or
- * dma_sync_single_for_cpu().
- */
-static inline dma_addr_t dma_map_single(struct device *dev, void *cpu_addr,
-		size_t size, enum dma_data_direction dir)
-{
-	unsigned long offset;
-	struct page *page;
-	dma_addr_t addr;
-
-	BUG_ON(!virt_addr_valid(cpu_addr));
-	BUG_ON(!virt_addr_valid(cpu_addr + size - 1));
-	BUG_ON(!valid_dma_direction(dir));
-
-	page = virt_to_page(cpu_addr);
-	offset = (unsigned long)cpu_addr & ~PAGE_MASK;
-	addr = __dma_map_page(dev, page, offset, size, dir);
-	debug_dma_map_page(dev, page, offset, size, dir, addr, true);
-
-	return addr;
-}
 
 /**
  * dma_cache_pre_ops - clean or invalidate cache before dma transfer is
@@ -421,146 +360,17 @@
 		___dma_single_cpu_to_dev(virtual_addr,
 					 size, DMA_FROM_DEVICE);
 }
-
-/**
- * dma_map_page - map a portion of a page for streaming DMA
- * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
- * @page: page that buffer resides in
- * @offset: offset into page for start of buffer
- * @size: size of buffer to map
- * @dir: DMA transfer direction
- *
- * Ensure that any data held in the cache is appropriately discarded
- * or written back.
- *
- * The device owns this memory once this call has completed.  The CPU
- * can regain ownership by calling dma_unmap_page().
- */
-static inline dma_addr_t dma_map_page(struct device *dev, struct page *page,
-	     unsigned long offset, size_t size, enum dma_data_direction dir)
-{
-	dma_addr_t addr;
-
-	BUG_ON(!valid_dma_direction(dir));
-
-	addr = __dma_map_page(dev, page, offset, size, dir);
-	debug_dma_map_page(dev, page, offset, size, dir, addr, false);
-
-	return addr;
-}
-
-/**
- * dma_unmap_single - unmap a single buffer previously mapped
- * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
- * @handle: DMA address of buffer
- * @size: size of buffer (same as passed to dma_map_single)
- * @dir: DMA transfer direction (same as passed to dma_map_single)
- *
- * Unmap a single streaming mode DMA translation.  The handle and size
- * must match what was provided in the previous dma_map_single() call.
- * All other usages are undefined.
- *
- * After this call, reads by the CPU to the buffer are guaranteed to see
- * whatever the device wrote there.
- */
-static inline void dma_unmap_single(struct device *dev, dma_addr_t handle,
-		size_t size, enum dma_data_direction dir)
-{
-	debug_dma_unmap_page(dev, handle, size, dir, true);
-	__dma_unmap_page(dev, handle, size, dir);
-}
-
-/**
- * dma_unmap_page - unmap a buffer previously mapped through dma_map_page()
- * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
- * @handle: DMA address of buffer
- * @size: size of buffer (same as passed to dma_map_page)
- * @dir: DMA transfer direction (same as passed to dma_map_page)
- *
- * Unmap a page streaming mode DMA translation.  The handle and size
- * must match what was provided in the previous dma_map_page() call.
- * All other usages are undefined.
- *
- * After this call, reads by the CPU to the buffer are guaranteed to see
- * whatever the device wrote there.
- */
-static inline void dma_unmap_page(struct device *dev, dma_addr_t handle,
-		size_t size, enum dma_data_direction dir)
-{
-	debug_dma_unmap_page(dev, handle, size, dir, false);
-	__dma_unmap_page(dev, handle, size, dir);
-}
-
-/**
- * dma_sync_single_range_for_cpu
- * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
- * @handle: DMA address of buffer
- * @offset: offset of region to start sync
- * @size: size of region to sync
- * @dir: DMA transfer direction (same as passed to dma_map_single)
- *
- * Make physical memory consistent for a single streaming mode DMA
- * translation after a transfer.
- *
- * If you perform a dma_map_single() but wish to interrogate the
- * buffer using the cpu, yet do not wish to teardown the PCI dma
- * mapping, you must call this function before doing so.  At the
- * next point you give the PCI dma address back to the card, you
- * must first the perform a dma_sync_for_device, and then the
- * device again owns the buffer.
- */
-static inline void dma_sync_single_range_for_cpu(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_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);
-}
-
-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);
-}
-
 /*
  * The scatter list versions of the above methods.
  */
-extern int dma_map_sg(struct device *, struct scatterlist *, int,
+extern int arm_dma_map_sg(struct device *, struct scatterlist *, int,
+		enum dma_data_direction, struct dma_attrs *attrs);
+extern void arm_dma_unmap_sg(struct device *, struct scatterlist *, int,
+		enum dma_data_direction, struct dma_attrs *attrs);
+extern void arm_dma_sync_sg_for_cpu(struct device *, struct scatterlist *, int,
 		enum dma_data_direction);
-extern void dma_unmap_sg(struct device *, struct scatterlist *, int,
+extern void arm_dma_sync_sg_for_device(struct device *, struct scatterlist *, int,
 		enum dma_data_direction);
-extern void dma_sync_sg_for_cpu(struct device *, struct scatterlist *, int,
-		enum dma_data_direction);
-extern void dma_sync_sg_for_device(struct device *, struct scatterlist *, int,
-		enum dma_data_direction);
-
 
 #endif /* __KERNEL__ */
 #endif
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 0d0103a..88d0872 100644
--- a/arch/arm/include/asm/pmu.h
+++ b/arch/arm/include/asm/pmu.h
@@ -113,7 +113,6 @@
 	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);
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/kernel/arch_timer.c b/arch/arm/kernel/arch_timer.c
index 43c627d..2455d1f 100644
--- a/arch/arm/kernel/arch_timer.c
+++ b/arch/arm/kernel/arch_timer.c
@@ -192,11 +192,17 @@
 static void arch_timer_set_mode(enum clock_event_mode mode,
 				struct clock_event_device *clk)
 {
+	unsigned long ctrl;
+
 	switch (mode) {
 	case CLOCK_EVT_MODE_UNUSED:
 	case CLOCK_EVT_MODE_SHUTDOWN:
 		arch_timer_disable();
 		break;
+	case CLOCK_EVT_MODE_ONESHOT:
+		ctrl = arch_specific_timer->reg_read(ARCH_TIMER_REG_CTRL);
+		ctrl |= ARCH_TIMER_CTRL_ENABLE;
+		arch_specific_timer->reg_write(ARCH_TIMER_REG_CTRL, ctrl);
 	default:
 		break;
 	}
@@ -208,9 +214,7 @@
 	unsigned long ctrl;
 
 	ctrl = arch_specific_timer->reg_read(ARCH_TIMER_REG_CTRL);
-	ctrl |= ARCH_TIMER_CTRL_ENABLE;
 	ctrl &= ~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);
 
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index e97aef2..3f6a6d3 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -41,6 +41,7 @@
  */
 #define ARMPMU_MAX_HWEVENTS		32
 
+static DEFINE_PER_CPU(u32, from_idle);
 static DEFINE_PER_CPU(struct perf_event * [ARMPMU_MAX_HWEVENTS], hw_events);
 static DEFINE_PER_CPU(unsigned long [BITS_TO_LONGS(ARMPMU_MAX_HWEVENTS)], used_mask);
 static DEFINE_PER_CPU(struct pmu_hw_events, cpu_hw_events);
@@ -602,7 +603,7 @@
 	int enabled = bitmap_weight(hw_events->used_mask, armpmu->num_events);
 	int idx;
 
-	if (armpmu->from_idle) {
+	if (__get_cpu_var(from_idle)) {
 		for (idx = 0; idx <= cpu_pmu->num_events; ++idx) {
 			struct perf_event *event = hw_events->events[idx];
 
@@ -613,9 +614,12 @@
 		}
 
 		/* Reset bit so we don't needlessly re-enable counters.*/
-		armpmu->from_idle = 0;
+		__get_cpu_var(from_idle) = 0;
 	}
 
+	/* So we don't start the PMU before enabling counters after idle. */
+	barrier();
+
 	if (enabled)
 		armpmu->start();
 }
@@ -731,7 +735,6 @@
  * 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)
 {
@@ -805,7 +808,7 @@
 			 * Flip this bit so armpmu_enable knows it needs
 			 * to re-enable active counters.
 			 */
-			cpu_pmu->from_idle = 1;
+			__get_cpu_var(from_idle) = 1;
 			cpu_pmu->reset(NULL);
 			perf_pmu_enable(&cpu_pmu->pmu);
 		}
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index a9582f9..af21496 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -300,6 +300,7 @@
 
 void machine_shutdown(void)
 {
+	preempt_disable();
 #ifdef CONFIG_SMP
 	smp_send_stop();
 #endif
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 5331f2c..badee85 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -249,18 +249,56 @@
 	select MSM_PIL
 	select MSM_SPM_V2
 	select MSM_L2_SPM
+	select MSM_NATIVE_RESTART
+	select MSM_RESTART_V2
 	select MSM_PM8X60 if PM
 	select MAY_HAVE_SPARSE_IRQ
 	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_MPQ8092
+	bool "MPQ8092"
+	select ARCH_MSM_KRAITMP
+	select GPIO_MSM_V3
+	select ARM_GIC
+	select MULTI_IRQ_HANDLER
+	select CPU_V7
+	select MSM_GPIOMUX
+	select MAY_HAVE_SPARSE_IRQ
+	select SPARSE_IRQ
+	select MSM_NOPM
+
+config ARCH_MSM8226
+	bool "MSM8226"
+	select ARCH_MSM_KRAITMP
+	select GPIO_MSM_V3
+	select ARM_GIC
+	select CPU_V7
+	select MSM_SCM if SMP
+	select MSM_GPIOMUX
+	select MULTI_IRQ_HANDLER
+	select MSM_MULTIMEDIA_USE_ION
+	select MSM_PIL
+	select MSM_SPM_V2
+	select MSM_L2_SPM
+	select MSM_PM8X60 if PM
+	select MAY_HAVE_SPARSE_IRQ
+	select SPARSE_IRQ
+	select MSM_RPM_SMD
+	select REGULATOR
+	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
+
 config ARCH_FSM9XXX
 	bool "FSM9XXX"
 	select ARCH_MSM_SCORPION
@@ -305,6 +343,7 @@
 	select ARM_TICKET_LOCKS
 	select MSM_RUN_QUEUE_STATS
 	select MIGHT_HAVE_CACHE_L2X0
+	select ARM_HAS_SG_CHAIN
 
 config ARCH_MSM9625
 	bool "MSM9625"
@@ -318,7 +357,6 @@
 	select MSM_GPIOMUX
 	select MULTI_IRQ_HANDLER
 	select GPIO_MSM_V3
-
 endmenu
 
 choice
@@ -381,6 +419,9 @@
 config  MSM_KRAIT_WFE_FIXUP
 	bool
 
+config  MSM_RESTART_V2
+	bool
+
 config  ARCH_MSM_CORTEX_A5
 	bool
 	select HAVE_HW_BRKPT_RESERVED_RW_ACCESS
@@ -393,6 +434,7 @@
 	select ARM_GIC
 	select ARCH_MSM_CORTEXMP
 	select MIGHT_HAVE_CACHE_L2X0
+	select ARM_HAS_SG_CHAIN
 
 config  MSM_VIC
 	bool
@@ -882,6 +924,8 @@
 	default "0x80200000" if ARCH_MSM8960
 	default "0x80200000" if ARCH_MSM8930
 	default "0x00000000" if ARCH_MSM8974
+	default "0x00000000" if ARCH_MPQ8092
+	default "0x00000000" if ARCH_MSM8226
 	default "0x10000000" if ARCH_FSM9XXX
 	default "0x20200000" if ARCH_MSM9625
 	default "0x00200000" if !MSM_STACKED_MEMORY
@@ -890,12 +934,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"
@@ -1018,6 +1065,14 @@
 		help
 		  Say Y here if you want the debug print routines to direct
 		  their output to the serial port on MSM 8974 devices.
+
+	config DEBUG_MPQ8092_UART
+                bool "Kernel low-level debugging messages via MPQ8092 UART"
+                depends on ARCH_MPQ8092
+                select MSM_HAS_DEBUG_UART_HS_V14
+                help
+                  Say Y here if you want the debug print routines to direct
+                  their output to the serial port on MPQ8092 devices.
 endchoice
 
 choice
@@ -1818,6 +1873,24 @@
 	  be used on systems which contain an RPM which communicates with the
 	  application processor over SMD.
 
+config MSM_SUBSYSTEM_RESTART
+	bool "MSM Subsystem Restart"
+	help
+	  This option enables the MSM subsystem restart framework.
+
+	  The MSM subsystem restart framework provides support to boot,
+	  shutdown, and restart subsystems with a reference counted API.
+	  It also notifies userspace of transitions between these states via
+	  sysfs.
+
+config MSM_SYSMON_COMM
+	bool "MSM System Monitor communication support"
+	depends on MSM_SMD && MSM_SUBSYSTEM_RESTART
+	help
+	  This option adds support for MSM System Monitor library, which
+	  provides an API that may be used for notifying subsystems within
+	  the SoC about other subsystems' power-up/down state-changes.
+
 config MSM_PIL
 	bool "Peripheral image loading"
 	select FW_LOADER
@@ -1929,23 +2002,6 @@
 	bool "Secure Channel Manager (SCM) support"
 	default n
 
-config MSM_SUBSYSTEM_RESTART
-	bool "MSM Subsystem Restart Driver"
-	depends on (ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_MSM9615)
-	default n
-	help
-	  This option enables the MSM subsystem restart driver, which provides
-	  a framework to handle subsystem crashes.
-
-config MSM_SYSMON_COMM
-	bool "MSM System Monitor communication support"
-	depends on MSM_SMD && MSM_SUBSYSTEM_RESTART
-	default y
-	help
-	  This option adds support for MSM System Monitor library, which
-	  provides an API that may be used for notifying subsystems within
-	  the SoC about other subsystems' power-up/down state-changes.
-
 config MSM_MODEM_8960
 	bool "MSM 8960 Modem driver"
 	depends on (ARCH_MSM8960 || ARCH_MSM9615)
@@ -1978,6 +2034,24 @@
 	 gss hardware watchdog interrupt lines and plugs into the subsystem
 	 restart and PIL drivers.
 
+config MSM_MODEM_SSR_8974
+	bool "MSM 8974 Modem restart driver"
+	depends on (ARCH_MSM8974)
+	help
+	 This option enables the modem subsystem restart driver for the MSM8974.
+	 It monitors the modem SMSM status bits and the modem watchdog line and
+	 restarts the modem or the 8974 when the modem encounters a fatal error,
+	 depending on the restart level selected in the subsystem restart driver.
+
+config MSM_ADSP_SSR_8974
+	bool "MSM 8974 adsp restart driver"
+	depends on (ARCH_MSM8974)
+	help
+	 This option enables the adsp restart driver for the MSM8974.
+	 It monitors the adsp SMSM status bits and the adsp watchdog line and
+	 restarts the adsp or the 8974 when the adsp encounters a fatal error,
+	 depending on the restart level selected in the subsystem restart driver.
+
 config SCORPION_Uni_45nm_BUG
 	bool "Scorpion Uni 45nm(SC45U): Workaround for ICIMVAU and BPIMVA"
 	depends on ARCH_MSM7X30 || (ARCH_QSD8X50 && MSM_SOC_REV_A)
@@ -2107,7 +2181,7 @@
 
 config MSM_DLOAD_MODE
 	bool "Enable download mode on crashes"
-	depends on ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_MSM9615
+	depends on ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_MSM9615 || ARCH_MSM8974
 	default n
 	help
 		This makes the SoC enter download mode when it resets
@@ -2133,11 +2207,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"
 
@@ -2204,6 +2273,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
@@ -2241,6 +2320,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
@@ -2318,6 +2407,16 @@
 	  Choosing one of these options allows debugging of each
 	  individual subsystem separately.
 
+config MSM_OCMEM_NONSECURE
+	bool "OCMEM Non Secure Mode"
+	depends on MSM_OCMEM_DEBUG
+	help
+	  Disable OCMEM interaction with secure processor.
+	  By default OCMEM is secured and accesses for each master
+	  is requested by the OCMEM driver. Selecting this option
+	  causes the OCMEM memory to be in non-secure state unless
+	  its locked down by the secure processor.
+
 config MSM_OCMEM_POWER_DEBUG
 	bool "OCMEM Power Debug Support"
 	depends on MSM_OCMEM_DEBUG
@@ -2451,6 +2550,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 5e3a980..505048c 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -103,6 +103,7 @@
 ifndef CONFIG_ARCH_MSM8960
 ifndef CONFIG_ARCH_MSM8X60
 ifndef CONFIG_ARCH_MSM8974
+ifndef CONFIG_ARCH_MPQ8092
 	obj-$(CONFIG_MSM_SMD) += pmic.o
 	obj-$(CONFIG_MSM_ONCRPCROUTER) += rpc_hsusb.o rpc_pmapp.o rpc_fsusb.o
 endif
@@ -110,17 +111,20 @@
 endif
 endif
 endif
+endif
 ifndef CONFIG_ARCH_MSM8960
 ifndef CONFIG_ARCH_MSM8X60
 ifndef CONFIG_ARCH_APQ8064
 ifndef CONFIG_ARCH_MSM8974
 ifndef CONFIG_ARCH_MSM9625
+ifndef CONFIG_ARCH_MPQ8092
 	obj-y += nand_partitions.o
 endif
 endif
 endif
 endif
 endif
+endif
 obj-$(CONFIG_MSM_SDIO_TTY) += sdio_tty.o
 obj-$(CONFIG_MSM_SMD_TTY) += smd_tty.o
 obj-$(CONFIG_MSM_SMD_QMI) += smd_qmi.o
@@ -206,7 +210,9 @@
 endif
 obj-$(CONFIG_MSM_SYSMON_COMM) += sysmon.o
 obj-$(CONFIG_MSM_MODEM_8960) += modem-8960.o
+obj-$(CONFIG_MSM_MODEM_SSR_8974) += modem-ssr-8974.o
 obj-$(CONFIG_MSM_LPASS_8960) += lpass-8960.o
+obj-$(CONFIG_MSM_ADSP_SSR_8974) += adsp-8974.o
 obj-$(CONFIG_MSM_WCNSS_SSR_8960) += wcnss-ssr-8960.o
 obj-$(CONFIG_MSM_GSS_SSR_8064) += gss-8064.o
 
@@ -244,6 +250,7 @@
 obj-$(CONFIG_MACH_MSM7X27_FFA) += board-msm7x27.o devices-msm7x27.o
 obj-$(CONFIG_ARCH_MSM7X27A) += clock-pcom-lookup.o devices-msm7x27a.o
 board-7627a-all-objs += board-msm7627a-storage.o board-msm7627a-bt.o board-msm7627a-camera.o
+board-7627a-all-objs += audio-7627a-devices.o
 board-7627a-all-objs += board-msm7627a-display.o board-msm7627a-wlan.o board-msm7627a-io.o
 obj-$(CONFIG_MACH_MSM7X27A_RUMI3) += board-msm7x27a.o board-7627a-all.o
 obj-$(CONFIG_MACH_MSM7X27A_SURF) += board-msm7x27a.o board-7627a-all.o
@@ -264,7 +271,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
@@ -276,9 +283,9 @@
 obj-$(CONFIG_MACH_MSM8960_CDP) += board-8960-all.o board-8960-regulator.o
 obj-$(CONFIG_MACH_MSM8960_MTP) += board-8960-all.o board-8960-regulator.o
 obj-$(CONFIG_MACH_MSM8960_FLUID) += board-8960-all.o board-8960-regulator.o
-obj-$(CONFIG_MACH_MSM8930_CDP) += board-8930-all.o board-8930-regulator.o
-obj-$(CONFIG_MACH_MSM8930_MTP) += board-8930-all.o board-8930-regulator.o
-obj-$(CONFIG_MACH_MSM8930_FLUID) += board-8930-all.o board-8930-regulator.o
+obj-$(CONFIG_MACH_MSM8930_CDP) += board-8930-all.o board-8930-regulator-pm8038.o board-8930-regulator-pm8917.o
+obj-$(CONFIG_MACH_MSM8930_MTP) += board-8930-all.o board-8930-regulator-pm8038.o board-8930-regulator-pm8917.o
+obj-$(CONFIG_MACH_MSM8930_FLUID) += board-8930-all.o board-8930-regulator-pm8038.o board-8930-regulator-pm8917.o
 obj-$(CONFIG_PM8921_BMS) += bms-batterydata.o bms-batterydata-desay.o
 obj-$(CONFIG_MACH_APQ8064_CDP) += board-8064-all.o board-8064-regulator.o
 obj-$(CONFIG_MACH_APQ8064_MTP) += board-8064-all.o board-8064-regulator.o
@@ -289,11 +296,12 @@
 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-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) += clock-local2.o clock-pll.o clock-8974.o clock-rpm.o clock-voter.o clock-mdss-8974.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
+obj-$(CONFIG_ARCH_MPQ8092) += board-8092.o board-8092-gpiomux.o
 
 obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire.o board-sapphire-gpio.o
 obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-keypad.o board-sapphire-panel.o
@@ -348,9 +356,8 @@
 obj-$(CONFIG_ARCH_MSM9615) += gpiomux-v2.o gpiomux.o
 obj-$(CONFIG_ARCH_MSM8974) += gpiomux-v2.o gpiomux.o
 obj-$(CONFIG_ARCH_MSM9625) += gpiomux-v2.o gpiomux.o
+obj-$(CONFIG_ARCH_MPQ8092) += 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
@@ -379,3 +386,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/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index b57d4e1..437933e 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -58,3 +58,7 @@
    zreladdr-$(CONFIG_ARCH_FSM9XXX)	:= 0x10008000
 params_phys-$(CONFIG_ARCH_FSM9XXX)	:= 0x10000100
 initrd_phys-$(CONFIG_ARCH_FSM9XXX)	:= 0x12000000
+
+# MPQ8092
+   zreladdr-$(CONFIG_ARCH_MPQ8092)	:= 0x00008000
+
diff --git a/arch/arm/mach-msm/acpuclock-8064.c b/arch/arm/mach-msm/acpuclock-8064.c
index a9521f0..3c80875 100644
--- a/arch/arm/mach-msm/acpuclock-8064.c
+++ b/arch/arm/mach-msm/acpuclock-8064.c
@@ -122,6 +122,7 @@
 	[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 = {
diff --git a/arch/arm/mach-msm/acpuclock-8627.c b/arch/arm/mach-msm/acpuclock-8627.c
index 1642dae..07a7f8f 100644
--- a/arch/arm/mach-msm/acpuclock-8627.c
+++ b/arch/arm/mach-msm/acpuclock-8627.c
@@ -104,6 +104,7 @@
 	[9]  = { {  864000, HFPLL, 1, 0, 0x20 }, LVL_HIGH, 1150000, 4 },
 	[10] = { {  918000, HFPLL, 1, 0, 0x22 }, LVL_HIGH, 1150000, 4 },
 	[11] = { {  972000, HFPLL, 1, 0, 0x24 }, LVL_HIGH, 1150000, 4 },
+	{ }
 };
 
 /* TODO: Update core voltages when data is available. */
diff --git a/arch/arm/mach-msm/acpuclock-8930.c b/arch/arm/mach-msm/acpuclock-8930.c
index 5647d14..77876ee 100644
--- a/arch/arm/mach-msm/acpuclock-8930.c
+++ b/arch/arm/mach-msm/acpuclock-8930.c
@@ -45,6 +45,39 @@
 	.vdd[HFPLL_VDD_HIGH] = LVL_HIGH,
 };
 
+static struct scalable scalable_pm8917[] __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 scalable scalable[] __initdata = {
 	[CPU0] = {
 		.hfpll_phys_base = 0x00903200,
@@ -111,6 +144,7 @@
 	[13] = { { 1080000, HFPLL, 1, 0, 0x28 }, LVL_HIGH, 1150000, 7 },
 	[14] = { { 1134000, HFPLL, 1, 0, 0x2A }, LVL_HIGH, 1150000, 7 },
 	[15] = { { 1188000, HFPLL, 1, 0, 0x2C }, LVL_HIGH, 1150000, 7 },
+	{ }
 };
 
 static struct acpu_level acpu_freq_tbl_slow[] __initdata = {
@@ -193,6 +227,10 @@
 
 static int __init acpuclk_8930_probe(struct platform_device *pdev)
 {
+	struct acpuclk_platform_data *pdata = pdev->dev.platform_data;
+	if (pdata && pdata->uses_pm8917)
+		acpuclk_8930_params.scalable = scalable_pm8917;
+
 	return acpuclk_krait_init(&pdev->dev, &acpuclk_8930_params);
 }
 
diff --git a/arch/arm/mach-msm/acpuclock-8930aa.c b/arch/arm/mach-msm/acpuclock-8930aa.c
index 34ba1da..dbc3e32 100644
--- a/arch/arm/mach-msm/acpuclock-8930aa.c
+++ b/arch/arm/mach-msm/acpuclock-8930aa.c
@@ -111,6 +111,7 @@
 	[13] = { { 1080000, HFPLL, 1, 0, 0x28 }, LVL_HIGH, 1150000, 7 },
 	[14] = { { 1134000, HFPLL, 1, 0, 0x2A }, LVL_HIGH, 1150000, 7 },
 	[15] = { { 1188000, HFPLL, 1, 0, 0x2C }, LVL_HIGH, 1150000, 7 },
+	{ }
 };
 
 static struct acpu_level acpu_freq_tbl_slow[] __initdata = {
diff --git a/arch/arm/mach-msm/acpuclock-8960.c b/arch/arm/mach-msm/acpuclock-8960.c
index 8cc4b13..631bd7e 100644
--- a/arch/arm/mach-msm/acpuclock-8960.c
+++ b/arch/arm/mach-msm/acpuclock-8960.c
@@ -109,6 +109,7 @@
 	[16] = { { 1242000, HFPLL, 1, 0, 0x2E }, 1150000, 1150000, 6 },
 	[17] = { { 1296000, HFPLL, 1, 0, 0x30 }, 1150000, 1150000, 6 },
 	[18] = { { 1350000, HFPLL, 1, 0, 0x32 }, 1150000, 1150000, 6 },
+	{ }
 };
 
 static struct acpu_level acpu_freq_tbl_slow[] __initdata = {
diff --git a/arch/arm/mach-msm/acpuclock-8960ab.c b/arch/arm/mach-msm/acpuclock-8960ab.c
new file mode 100644
index 0000000..63bff55
--- /dev/null
+++ b/arch/arm/mach-msm/acpuclock-8960ab.c
@@ -0,0 +1,170 @@
+/*
+ * 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 },
+	{ 1, {  1566000, HFPLL, 1, 0, 0x3A }, L2(9),  1250000 },
+	{ 1, {  1620000, HFPLL, 1, 0, 0x3C }, L2(9),  1250000 },
+	{ 1, {  1674000, HFPLL, 1, 0, 0x3E }, L2(9),  1250000 },
+	{ 1, {  1728000, HFPLL, 1, 0, 0x40 }, 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,
+	.stby_khz = 384000,
+};
+
+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 22275b4..16f77ba 100644
--- a/arch/arm/mach-msm/acpuclock-8974.c
+++ b/arch/arm/mach-msm/acpuclock-8974.c
@@ -134,6 +134,7 @@
 	[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 = {
@@ -148,12 +149,12 @@
 	{ 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 },
+	{ 1, { 1113600, HFPLL, 1, 0,  58 }, L2(12), 1050000, 3200000 },
+	{ 1, { 1190400, HFPLL, 1, 0,  62 }, L2(12), 1050000, 3200000 },
+	{ 1, { 1267200, HFPLL, 1, 0,  66 }, L2(12), 1050000, 3200000 },
+	{ 1, { 1344000, HFPLL, 1, 0,  70 }, L2(15), 1050000, 3200000 },
+	{ 1, { 1420800, HFPLL, 1, 0,  74 }, L2(15), 1050000, 3200000 },
+	{ 1, { 1497600, HFPLL, 1, 0,  78 }, L2(16), 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 },
diff --git a/arch/arm/mach-msm/acpuclock-krait.h b/arch/arm/mach-msm/acpuclock-krait.h
index 5a95e76..1b891b1 100644
--- a/arch/arm/mach-msm/acpuclock-krait.h
+++ b/arch/arm/mach-msm/acpuclock-krait.h
@@ -253,9 +253,16 @@
 };
 
 /**
+ * struct acpuclk_platform_data - PMIC configuration data.
+ * @uses_pm8917: Boolean indicates presence of pm8917.
+ */
+struct acpuclk_platform_data {
+	bool uses_pm8917;
+};
+
+/**
  * acpuclk_krait_init - Initialize the Krait CPU clock driver give SoC params.
  */
 extern int acpuclk_krait_init(struct device *dev,
 			      const struct acpuclk_krait_params *params);
-
 #endif
diff --git a/arch/arm/mach-msm/acpuclock.c b/arch/arm/mach-msm/acpuclock.c
index be056e6..2b33c4c 100644
--- a/arch/arm/mach-msm/acpuclock.c
+++ b/arch/arm/mach-msm/acpuclock.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
@@ -13,6 +13,7 @@
 #include <linux/cpu.h>
 #include <linux/smp.h>
 #include "acpuclock.h"
+#include <trace/events/power.h>
 
 static struct acpuclk_data *acpuclk_data;
 
@@ -26,10 +27,19 @@
 
 int acpuclk_set_rate(int cpu, unsigned long rate, enum setrate_reason reason)
 {
+	int ret;
+
 	if (!acpuclk_data->set_rate)
 		return 0;
 
-	return acpuclk_data->set_rate(cpu, rate, reason);
+	trace_cpu_frequency_switch_start(acpuclk_get_rate(cpu), rate, cpu);
+	ret = acpuclk_data->set_rate(cpu, rate, reason);
+	if (!ret) {
+		trace_cpu_frequency_switch_end(cpu);
+		trace_cpu_frequency(rate, cpu);
+	}
+
+	return ret;
 }
 
 uint32_t acpuclk_get_switch_time(void)
diff --git a/arch/arm/mach-msm/adsp-8974.c b/arch/arm/mach-msm/adsp-8974.c
new file mode 100644
index 0000000..050a24b
--- /dev/null
+++ b/arch/arm/mach-msm/adsp-8974.c
@@ -0,0 +1,297 @@
+/* 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/interrupt.h>
+#include <linux/reboot.h>
+#include <linux/workqueue.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/err.h>
+
+#include <mach/irqs.h>
+#include <mach/scm.h>
+#include <mach/peripheral-loader.h>
+#include <mach/subsystem_restart.h>
+#include <mach/subsystem_notif.h>
+
+#include "smd_private.h"
+#include "ramdump.h"
+#include "sysmon.h"
+
+#define SCM_Q6_NMI_CMD			0x1
+#define MODULE_NAME			"adsp_8974"
+#define MAX_BUF_SIZE			0x51
+
+/* Interrupt line for WDOG bite*/
+#define ADSP_Q6SS_WDOG_EXPIRED		194
+
+/* Subsystem restart: QDSP6 data, functions */
+static void adsp_fatal_fn(struct work_struct *);
+static DECLARE_WORK(adsp_fatal_work, adsp_fatal_fn);
+
+struct adsp_ssr {
+	void *adsp_ramdump_dev;
+} adsp_ssr;
+
+static struct adsp_ssr adsp_ssr_8974;
+static int q6_crash_shutdown;
+
+static int riva_notifier_cb(struct notifier_block *this, unsigned long code,
+								void *ss_handle)
+{
+	int ret;
+	switch (code) {
+	case SUBSYS_BEFORE_SHUTDOWN:
+		pr_debug("%s: R-Notify: Shutdown started\n", __func__);
+		ret = sysmon_send_event(SYSMON_SS_LPASS, "wcnss",
+				SUBSYS_BEFORE_SHUTDOWN);
+		if (ret < 0)
+			pr_err("%s: sysmon_send_event error %d", __func__,
+				ret);
+		break;
+	}
+	return NOTIFY_DONE;
+}
+
+static void *ssr_notif_hdle;
+static struct notifier_block rnb = {
+	.notifier_call = riva_notifier_cb,
+};
+
+static int modem_notifier_cb(struct notifier_block *this, unsigned long code,
+								void *ss_handle)
+{
+	int ret;
+	switch (code) {
+	case SUBSYS_BEFORE_SHUTDOWN:
+		pr_debug("%s: M-Notify: Shutdown started\n", __func__);
+		ret = sysmon_send_event(SYSMON_SS_LPASS, "modem",
+				SUBSYS_BEFORE_SHUTDOWN);
+		if (ret < 0)
+			pr_err("%s: sysmon_send_event error %d", __func__,
+				ret);
+		break;
+	}
+	return NOTIFY_DONE;
+}
+
+static void *ssr_modem_notif_hdle;
+static struct notifier_block mnb = {
+	.notifier_call = modem_notifier_cb,
+};
+
+static void adsp_log_failure_reason(void)
+{
+	char *reason;
+	char buffer[MAX_BUF_SIZE];
+	unsigned size;
+
+	reason = smem_get_entry(SMEM_SSR_REASON_LPASS0, &size);
+
+	if (!reason) {
+		pr_err("%s: subsystem failure reason: (unknown, smem_get_entry failed).",
+			 MODULE_NAME);
+		return;
+	}
+
+	if (reason[0] == '\0') {
+		pr_err("%s: subsystem failure reason: (unknown, init value found)",
+			 MODULE_NAME);
+		return;
+	}
+
+	size = size < MAX_BUF_SIZE ? size : (MAX_BUF_SIZE-1);
+	memcpy(buffer, reason, size);
+	buffer[size] = '\0';
+	pr_err("%s: subsystem failure reason: %s", MODULE_NAME, buffer);
+	memset((void *)reason, 0x0, size);
+	wmb();
+}
+
+static void adsp_fatal_fn(struct work_struct *work)
+{
+	pr_err("%s %s: Watchdog bite received from Q6!\n", MODULE_NAME,
+		__func__);
+	adsp_log_failure_reason();
+	panic(MODULE_NAME ": Resetting the SoC");
+}
+
+static void adsp_smsm_state_cb(void *data, uint32_t old_state,
+				uint32_t new_state)
+{
+	/* Ignore if we're the one that set SMSM_RESET */
+	if (q6_crash_shutdown)
+		return;
+
+	if (new_state & SMSM_RESET) {
+		pr_debug("%s: ADSP SMSM state changed to SMSM_RESET, new_state= 0x%x, old_state = 0x%x\n",
+			 __func__, new_state, old_state);
+		adsp_log_failure_reason();
+		panic(MODULE_NAME ": Resetting the SoC");
+	}
+}
+
+static void send_q6_nmi(void)
+{
+	/* Send NMI to QDSP6 via an SCM call. */
+	scm_call_atomic1(SCM_SVC_UTIL, SCM_Q6_NMI_CMD, 0x1);
+	pr_debug("%s: Q6 NMI was sent.\n", __func__);
+}
+
+static int adsp_shutdown(const struct subsys_desc *subsys)
+{
+	send_q6_nmi();
+
+	/* The write needs to go through before the q6 is shutdown. */
+	mb();
+
+	pil_force_shutdown("q6");
+	disable_irq_nosync(ADSP_Q6SS_WDOG_EXPIRED);
+
+	return 0;
+}
+
+static int adsp_powerup(const struct subsys_desc *subsys)
+{
+	int ret;
+
+	if (get_restart_level() == RESET_SUBSYS_INDEPENDENT) {
+		pr_debug("%s: Wait for ADSP power up!", __func__);
+		msleep(10000);
+	}
+
+	ret = pil_force_boot("q6");
+	enable_irq(ADSP_Q6SS_WDOG_EXPIRED);
+	return ret;
+}
+/* RAM segments - address and size for 8974 */
+static struct ramdump_segment q6_segment = {0xdc00000, 0x1800000};
+
+static int adsp_ramdump(int enable, const struct subsys_desc *subsys)
+{
+	pr_debug("%s: enable[%d]\n", __func__, enable);
+	if (enable)
+		return do_ramdump(adsp_ssr_8974.adsp_ramdump_dev,
+				&q6_segment, 1);
+	else
+		return 0;
+}
+
+static void adsp_crash_shutdown(const struct subsys_desc *subsys)
+{
+	q6_crash_shutdown = 1;
+	send_q6_nmi();
+}
+
+static irqreturn_t adsp_wdog_bite_irq(int irq, void *dev_id)
+{
+	int ret;
+
+	pr_debug("%s: rxed irq[0x%x]", __func__, irq);
+	disable_irq_nosync(ADSP_Q6SS_WDOG_EXPIRED);
+	ret = schedule_work(&adsp_fatal_work);
+
+	return IRQ_HANDLED;
+}
+
+static struct subsys_device *adsp_8974_dev;
+
+static struct subsys_desc adsp_8974 = {
+	.name = "adsp",
+	.shutdown = adsp_shutdown,
+	.powerup = adsp_powerup,
+	.ramdump = adsp_ramdump,
+	.crash_shutdown = adsp_crash_shutdown
+};
+
+static int __init adsp_restart_init(void)
+{
+	adsp_8974_dev = subsys_register(&adsp_8974);
+	if (IS_ERR(adsp_8974_dev))
+		return PTR_ERR(adsp_8974_dev);
+	return 0;
+}
+
+static int __init adsp_fatal_init(void)
+{
+	int ret;
+
+	ret = smsm_state_cb_register(SMSM_Q6_STATE, SMSM_RESET,
+		adsp_smsm_state_cb, 0);
+
+	if (ret < 0)
+		pr_err("%s: Unable to register SMSM callback! (%d)\n",
+				__func__, ret);
+
+	ret = request_irq(ADSP_Q6SS_WDOG_EXPIRED, adsp_wdog_bite_irq,
+			IRQF_TRIGGER_RISING, "q6_wdog", NULL);
+
+	if (ret < 0) {
+		pr_err("%s: Unable to request ADSP_Q6SS_WDOG_EXPIRED irq.",
+			__func__);
+		goto out;
+	}
+	ret = adsp_restart_init();
+	if (ret < 0) {
+		pr_err("%s: Unable to reg with adsp ssr. (%d)\n",
+				__func__, ret);
+		goto out;
+	}
+
+	adsp_ssr_8974.adsp_ramdump_dev = create_ramdump_device("adsp");
+
+	if (!adsp_ssr_8974.adsp_ramdump_dev) {
+		pr_err("%s: Unable to create ramdump device.\n",
+				__func__);
+		ret = -ENOMEM;
+		goto out;
+	}
+	ssr_notif_hdle = subsys_notif_register_notifier("riva",
+							&rnb);
+	if (IS_ERR(ssr_notif_hdle) < 0) {
+		ret = PTR_ERR(ssr_notif_hdle);
+		pr_err("%s: subsys_register_notifier for Riva: err = %d\n",
+			__func__, ret);
+		free_irq(ADSP_Q6SS_WDOG_EXPIRED, NULL);
+		goto out;
+	}
+
+	ssr_modem_notif_hdle = subsys_notif_register_notifier("modem",
+							&mnb);
+	if (IS_ERR(ssr_modem_notif_hdle) < 0) {
+		ret = PTR_ERR(ssr_modem_notif_hdle);
+		pr_err("%s: subsys_register_notifier for Modem: err = %d\n",
+			__func__, ret);
+		subsys_notif_unregister_notifier(ssr_notif_hdle, &rnb);
+		free_irq(ADSP_Q6SS_WDOG_EXPIRED, NULL);
+		goto out;
+	}
+
+	pr_info("%s: adsp ssr driver init'ed.\n", __func__);
+out:
+	return ret;
+}
+
+static void __exit adsp_fatal_exit(void)
+{
+	subsys_notif_unregister_notifier(ssr_notif_hdle, &rnb);
+	subsys_notif_unregister_notifier(ssr_modem_notif_hdle, &mnb);
+	subsys_unregister(adsp_8974_dev);
+	free_irq(ADSP_Q6SS_WDOG_EXPIRED, NULL);
+}
+
+module_init(adsp_fatal_init);
+module_exit(adsp_fatal_exit);
+
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/audio-7627a-devices.c b/arch/arm/mach-msm/audio-7627a-devices.c
new file mode 100644
index 0000000..3a636e8
--- /dev/null
+++ b/arch/arm/mach-msm/audio-7627a-devices.c
@@ -0,0 +1,220 @@
+/* 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/init.h>
+#include <linux/platform_device.h>
+#include <linux/android_pmem.h>
+#include <mach/board.h>
+
+#include "board-msm7627a.h"
+
+#define SND(desc, num) { .name = #desc, .id = num }
+static struct snd_endpoint snd_endpoints_list[] = {
+	SND(HANDSET, 0),
+	SND(MONO_HEADSET, 2),
+	SND(HEADSET, 3),
+	SND(SPEAKER, 6),
+	SND(TTY_HEADSET, 8),
+	SND(TTY_VCO, 9),
+	SND(TTY_HCO, 10),
+	SND(BT, 12),
+	SND(IN_S_SADC_OUT_HANDSET, 16),
+	SND(IN_S_SADC_OUT_SPEAKER_PHONE, 25),
+	SND(FM_DIGITAL_STEREO_HEADSET, 26),
+	SND(FM_DIGITAL_SPEAKER_PHONE, 27),
+	SND(FM_DIGITAL_BT_A2DP_HEADSET, 28),
+	SND(STEREO_HEADSET_AND_SPEAKER, 31),
+	SND(CURRENT, 0x7FFFFFFE),
+	SND(FM_ANALOG_STEREO_HEADSET, 35),
+	SND(FM_ANALOG_STEREO_HEADSET_CODEC, 36),
+};
+#undef SND
+
+static struct msm_snd_endpoints msm_device_snd_endpoints = {
+	.endpoints = snd_endpoints_list,
+	.num = sizeof(snd_endpoints_list) / sizeof(struct snd_endpoint)
+};
+
+struct platform_device msm_device_snd = {
+	.name = "msm_snd",
+	.id = -1,
+	.dev    = {
+		.platform_data = &msm_device_snd_endpoints
+	},
+};
+
+#define DEC0_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)| \
+	(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_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)| \
+	(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))
+#define DEC2_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)| \
+	(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))
+#define DEC3_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)| \
+	(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))
+#define DEC4_FORMAT (1<<MSM_ADSP_CODEC_MIDI)
+
+static unsigned int dec_concurrency_table[] = {
+	/* Audio LP */
+	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DMA)), 0,
+	0, 0, 0,
+
+	/* Concurrency 1 */
+	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC1_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC2_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC3_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC4_FORMAT),
+
+	 /* Concurrency 2 */
+	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC1_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC2_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC3_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC4_FORMAT),
+
+	/* Concurrency 3 */
+	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC1_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC2_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC3_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC4_FORMAT),
+
+	/* Concurrency 4 */
+	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC1_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC2_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC3_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC4_FORMAT),
+
+	/* Concurrency 5 */
+	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC1_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC2_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC3_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC4_FORMAT),
+
+	/* Concurrency 6 */
+	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|
+			(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	0, 0, 0, 0,
+
+	/* Concurrency 7 */
+	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC1_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC2_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC3_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC4_FORMAT),
+};
+
+#define DEC_INFO(name, queueid, decid, nr_codec) { .module_name = name, \
+	.module_queueid = queueid, .module_decid = decid, \
+	.nr_codec_support = nr_codec}
+
+static struct msm_adspdec_info dec_info_list[] = {
+	DEC_INFO("AUDPLAY0TASK", 13, 0, 11), /* AudPlay0BitStreamCtrlQueue */
+	DEC_INFO("AUDPLAY1TASK", 14, 1, 11),  /* AudPlay1BitStreamCtrlQueue */
+	DEC_INFO("AUDPLAY2TASK", 15, 2, 11),  /* AudPlay2BitStreamCtrlQueue */
+	DEC_INFO("AUDPLAY3TASK", 16, 3, 11),  /* AudPlay3BitStreamCtrlQueue */
+	DEC_INFO("AUDPLAY4TASK", 17, 4, 1),  /* AudPlay4BitStreamCtrlQueue */
+};
+
+static struct msm_adspdec_database msm_device_adspdec_database = {
+	.num_dec = ARRAY_SIZE(dec_info_list),
+	.num_concurrency_support = (ARRAY_SIZE(dec_concurrency_table) / \
+					ARRAY_SIZE(dec_info_list)),
+	.dec_concurrency_table = dec_concurrency_table,
+	.dec_info_list = dec_info_list,
+};
+
+struct platform_device msm_device_adspdec = {
+	.name = "msm_adspdec",
+	.id = -1,
+	.dev    = {
+		.platform_data = &msm_device_adspdec_database
+	},
+};
+
+#define SNDDEV_CAP_NONE 0x0
+#define SNDDEV_CAP_RX 0x1 /* RX direction */
+#define SNDDEV_CAP_TX 0x2 /* TX direction */
+#define SNDDEV_CAP_VOICE 0x4 /* Support voice call */
+#define SNDDEV_CAP_FM 0x10 /* Support FM radio */
+#define SNDDEV_CAP_TTY 0x20 /* Support TTY */
+#define CAD(desc, num, cap) { .name = #desc, .id = num, .capability = cap, }
+static struct cad_endpoint cad_endpoints_list[] = {
+	CAD(NONE, 0, SNDDEV_CAP_NONE),
+	CAD(HANDSET_SPKR, 1, (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE)),
+	CAD(HANDSET_MIC, 2, (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE)),
+	CAD(HEADSET_MIC, 3, (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE)),
+	CAD(HEADSET_SPKR_MONO, 4, (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE)),
+	CAD(HEADSET_SPKR_STEREO, 5, (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE)),
+	CAD(SPEAKER_PHONE_MIC, 6, (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE)),
+	CAD(SPEAKER_PHONE_MONO, 7, (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE)),
+	CAD(SPEAKER_PHONE_STEREO, 8, (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE)),
+	CAD(BT_SCO_MIC, 9, (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE)),
+	CAD(BT_SCO_SPKR, 10, (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE)),
+	CAD(BT_A2DP_SPKR, 11, (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE)),
+	CAD(TTY_HEADSET_MIC, 12, (SNDDEV_CAP_TX | \
+			SNDDEV_CAP_VOICE | SNDDEV_CAP_TTY)),
+	CAD(TTY_HEADSET_SPKR, 13, (SNDDEV_CAP_RX | \
+			SNDDEV_CAP_VOICE | SNDDEV_CAP_TTY)),
+	CAD(HEADSET_STEREO_PLUS_SPKR_MONO_RX, 19, (SNDDEV_CAP_TX | \
+				SNDDEV_CAP_VOICE)),
+	CAD(LP_FM_HEADSET_SPKR_STEREO_RX, 25, (SNDDEV_CAP_TX | SNDDEV_CAP_FM)),
+	CAD(I2S_RX, 26, (SNDDEV_CAP_RX)),
+	CAD(SPEAKER_PHONE_MIC_ENDFIRE, 45, (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE)),
+	CAD(HANDSET_MIC_ENDFIRE, 46, (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE)),
+	CAD(I2S_TX, 48, (SNDDEV_CAP_TX)),
+	CAD(LP_FM_HEADSET_SPKR_STEREO_PLUS_HEADSET_SPKR_STEREO_RX, 57, \
+			(SNDDEV_CAP_FM | SNDDEV_CAP_RX)),
+	CAD(FM_DIGITAL_HEADSET_SPKR_STEREO, 65, \
+			(SNDDEV_CAP_FM | SNDDEV_CAP_RX)),
+	CAD(FM_DIGITAL_SPEAKER_PHONE_MONO, 67, \
+			(SNDDEV_CAP_FM | SNDDEV_CAP_RX)),
+	CAD(FM_DIGITAL_SPEAKER_PHONE_MIC, 68, \
+			(SNDDEV_CAP_FM | SNDDEV_CAP_TX)),
+	CAD(FM_DIGITAL_BT_A2DP_SPKR, 69, \
+			(SNDDEV_CAP_FM | SNDDEV_CAP_RX)),
+	CAD(MAX, 80, SNDDEV_CAP_NONE),
+};
+#undef CAD
+
+static struct msm_cad_endpoints msm_device_cad_endpoints = {
+	.endpoints = cad_endpoints_list,
+	.num = sizeof(cad_endpoints_list) / sizeof(struct cad_endpoint)
+};
+
+struct platform_device msm_device_cad = {
+	.name = "msm_cad",
+	.id = -1,
+	.dev    = {
+		.platform_data = &msm_device_cad_endpoints
+	},
+};
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index b35e949..1a02fce 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -27,6 +27,7 @@
 #include <linux/clk.h>
 #include <linux/wakelock.h>
 #include <linux/kfifo.h>
+#include <linux/of.h>
 
 #include <mach/sps.h>
 #include <mach/bam_dmux.h>
@@ -47,16 +48,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;
@@ -162,6 +176,14 @@
 #define A2_PHYS_SIZE		0x2000
 #define BUFFER_SIZE		2048
 #define NUM_BUFFERS		32
+
+#ifndef A2_BAM_IRQ
+#define A2_BAM_IRQ -1
+#endif
+
+static void *a2_phys_base;
+static uint32_t a2_phys_size;
+static int a2_bam_irq;
 static struct sps_bam_props a2_props;
 static u32 a2_device_handle;
 static struct sps_pipe *bam_tx_pipe;
@@ -177,6 +199,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 +1139,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 +1186,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);
+		}
 	}
 }
 
@@ -1652,6 +1711,20 @@
 	}
 
 	/*
+	 * if this gets hit, that means restart_notifier_cb() has started
+	 * but probably not finished, thus we know SSR has happened, but
+	 * haven't been able to send that info to our clients yet.
+	 * in that case, abort the ul_wakeup() so that we don't undo any
+	 * work restart_notifier_cb() has done.  The clients will be notified
+	 * shortly.  No cleanup necessary (reschedule the wakeup) as our and
+	 * their SSR handling will cover it
+	 */
+	if (unlikely(in_global_reset == 1)) {
+		mutex_unlock(&wakeup_lock);
+		return;
+	}
+
+	/*
 	 * if someone is voting for UL before bam is inited (modem up first
 	 * time), set flag for init to kickoff ul wakeup once bam is inited
 	 */
@@ -1826,12 +1899,18 @@
 		mutex_unlock(&dfab_status_lock);
 		return;
 	}
-	rc = clk_prepare_enable(dfab_clk);
-	if (rc)
-		DMUX_LOG_KERR("bam_dmux vote for dfab failed rc = %d\n", rc);
-	rc = clk_prepare_enable(xo_clk);
-	if (rc)
-		DMUX_LOG_KERR("bam_dmux vote for xo failed rc = %d\n", rc);
+	if (dfab_clk) {
+		rc = clk_prepare_enable(dfab_clk);
+		if (rc)
+			DMUX_LOG_KERR("bam_dmux vote for dfab failed rc = %d\n",
+									rc);
+	}
+	if (xo_clk) {
+		rc = clk_prepare_enable(xo_clk);
+		if (rc)
+			DMUX_LOG_KERR("bam_dmux vote for xo failed rc = %d\n",
+									rc);
+	}
 	dfab_is_on = 1;
 	mutex_unlock(&dfab_status_lock);
 }
@@ -1846,8 +1925,10 @@
 		mutex_unlock(&dfab_status_lock);
 		return;
 	}
-	clk_disable_unprepare(dfab_clk);
-	clk_disable_unprepare(xo_clk);
+	if (dfab_clk)
+		clk_disable_unprepare(dfab_clk);
+	if (xo_clk)
+		clk_disable_unprepare(xo_clk);
 	dfab_is_on = 0;
 	mutex_unlock(&dfab_status_lock);
 }
@@ -1970,16 +2051,17 @@
 
 	vote_dfab();
 	/* init BAM */
-	a2_virt_addr = ioremap_nocache(A2_PHYS_BASE, A2_PHYS_SIZE);
+	a2_virt_addr = ioremap_nocache((unsigned long)(a2_phys_base),
+							a2_phys_size);
 	if (!a2_virt_addr) {
 		pr_err("%s: ioremap failed\n", __func__);
 		ret = -ENOMEM;
 		goto ioremap_failed;
 	}
-	a2_props.phys_addr = A2_PHYS_BASE;
+	a2_props.phys_addr = (u32)(a2_phys_base);
 	a2_props.virt_addr = a2_virt_addr;
-	a2_props.virt_size = A2_PHYS_SIZE;
-	a2_props.irq = A2_BAM_IRQ;
+	a2_props.virt_size = a2_phys_size;
+	a2_props.irq = a2_bam_irq;
 	a2_props.options = SPS_BAM_OPT_IRQ_WAKEUP;
 	a2_props.num_pipes = A2_NUM_PIPES;
 	a2_props.summing_threshold = A2_SUMMING_THRESHOLD;
@@ -2141,16 +2223,17 @@
 	void *a2_virt_addr;
 
 	/* init BAM */
-	a2_virt_addr = ioremap_nocache(A2_PHYS_BASE, A2_PHYS_SIZE);
+	a2_virt_addr = ioremap_nocache((unsigned long)(a2_phys_base),
+							a2_phys_size);
 	if (!a2_virt_addr) {
 		pr_err("%s: ioremap failed\n", __func__);
 		ret = -ENOMEM;
 		goto ioremap_failed;
 	}
-	a2_props.phys_addr = A2_PHYS_BASE;
+	a2_props.phys_addr = (u32)(a2_phys_base);
 	a2_props.virt_addr = a2_virt_addr;
-	a2_props.virt_size = A2_PHYS_SIZE;
-	a2_props.irq = A2_BAM_IRQ;
+	a2_props.virt_size = a2_phys_size;
+	a2_props.irq = a2_bam_irq;
 	a2_props.options = SPS_BAM_OPT_IRQ_WAKEUP;
 	a2_props.num_pipes = A2_NUM_PIPES;
 	a2_props.summing_threshold = A2_SUMMING_THRESHOLD;
@@ -2263,26 +2346,50 @@
 static int bam_dmux_probe(struct platform_device *pdev)
 {
 	int rc;
+	struct resource *r;
 
 	DBG("%s probe called\n", __func__);
 	if (bam_mux_initialized)
 		return 0;
 
+	if (pdev->dev.of_node) {
+		r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+		if (!r) {
+			pr_err("%s: reg field missing\n", __func__);
+			return -ENODEV;
+		}
+		a2_phys_base = (void *)(r->start);
+		a2_phys_size = (uint32_t)(resource_size(r));
+		a2_bam_irq = platform_get_irq(pdev, 0);
+		if (a2_bam_irq == -ENXIO) {
+			pr_err("%s: irq field missing\n", __func__);
+			return -ENODEV;
+		}
+		DBG("%s: base:%p size:%x irq:%d\n", __func__,
+							a2_phys_base,
+							a2_phys_size,
+							a2_bam_irq);
+	} else { /* fallback to default init data */
+		a2_phys_base = (void *)(A2_PHYS_BASE);
+		a2_phys_size = A2_PHYS_SIZE;
+		a2_bam_irq = A2_BAM_IRQ;
+	}
+
 	xo_clk = clk_get(&pdev->dev, "xo");
 	if (IS_ERR(xo_clk)) {
-		pr_err("%s: did not get xo clock\n", __func__);
-		return PTR_ERR(xo_clk);
+		bam_dmux_log("%s: did not get xo clock\n", __func__);
+		xo_clk = NULL;
 	}
 	dfab_clk = clk_get(&pdev->dev, "bus_clk");
 	if (IS_ERR(dfab_clk)) {
-		pr_err("%s: did not get dfab clock\n", __func__);
-		return -EFAULT;
+		bam_dmux_log("%s: did not get dfab clock\n", __func__);
+		dfab_clk = NULL;
+	} else {
+		rc = clk_set_rate(dfab_clk, 64000000);
+		if (rc)
+			pr_err("%s: unable to set dfab clock rate\n", __func__);
 	}
 
-	rc = clk_set_rate(dfab_clk, 64000000);
-	if (rc)
-		pr_err("%s: unable to set dfab clock rate\n", __func__);
-
 	/*
 	 * setup the workqueue so that it can be pinned to core 0 and not
 	 * block the watchdog pet function, so that netif_rx() in rmnet
@@ -2351,11 +2458,17 @@
 	return 0;
 }
 
+static struct of_device_id msm_match_table[] = {
+	{.compatible = "qcom,bam_dmux"},
+	{},
+};
+
 static struct platform_driver bam_dmux_driver = {
 	.probe		= bam_dmux_probe,
 	.driver		= {
 		.name	= "BAM_RMNT",
 		.owner	= THIS_MODULE,
+		.of_match_table = msm_match_table,
 	},
 };
 
@@ -2379,6 +2492,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/bms-batterydata.c b/arch/arm/mach-msm/bms-batterydata.c
index 77e7dab..81ab121 100644
--- a/arch/arm/mach-msm/bms-batterydata.c
+++ b/arch/arm/mach-msm/bms-batterydata.c
@@ -12,116 +12,97 @@
 
 #include <linux/mfd/pm8xxx/pm8921-bms.h>
 
-static struct single_row_lut palladium_1500_fcc_temp = {
-	.x	= {-30, -20, -10, 0, 10, 25, 40, 60},
-	.y	= {1103, 1179, 1284, 1330, 1420, 1511, 1541, 1571},
-	.cols	= 8,
+static struct single_row_lut fcc_temp = {
+	.x		= {-20, 0, 25, 40, 65},
+	.y		= {1492, 1492, 1493, 1483, 1502},
+	.cols	= 5
 };
 
-static struct single_row_lut palladium_1500_fcc_sf = {
-	.x	= {100, 200, 300, 400, 500},
-	.y	= {97, 93, 93, 90, 87},
-	.cols	= 5,
-};
-
-static struct sf_lut palladium_1500_pc_sf = {
-	.rows		= 10,
+static struct pc_temp_ocv_lut pc_temp_ocv = {
+	.rows		= 29,
 	.cols		= 5,
-	/* row_entries are chargecycles */
-	.row_entries	= {100, 200, 300, 400, 500},
-	.percent	= {100, 90, 80, 70, 60, 50, 40, 30, 20, 10},
-	.sf		= {
-			{97, 93, 93, 90, 87},
-			{97, 93, 93, 90, 87},
-			{98, 94, 92, 89, 86},
-			{98, 94, 92, 89, 86},
-			{99, 94, 92, 88, 86},
-			{99, 95, 92, 88, 87},
-			{99, 95, 92, 88, 87},
-			{99, 95, 92, 88, 87},
-			{99, 95, 92, 88, 87},
-			{99, 95, 92, 88, 87}
-	},
+	.temp		= {-20, 0, 25, 40, 65},
+	.percent	= {100, 95, 90, 85, 80, 75, 70, 65, 60, 55, 50, 45, 40,
+					35, 30, 25, 20, 15, 10, 9, 8, 7, 6, 5,
+					4, 3, 2, 1, 0},
+	.ocv		= {
+				{4173, 4167, 4163, 4156, 4154},
+				{4104, 4107, 4108, 4102, 4104},
+				{4057, 4072, 4069, 4061, 4060},
+				{3973, 4009, 4019, 4016, 4020},
+				{3932, 3959, 3981, 3982, 3983},
+				{3899, 3928, 3954, 3950, 3950},
+				{3868, 3895, 3925, 3921, 3920},
+				{3837, 3866, 3898, 3894, 3892},
+				{3812, 3841, 3853, 3856, 3862},
+				{3794, 3818, 3825, 3823, 3822},
+				{3780, 3799, 3804, 3804, 3803},
+				{3768, 3787, 3790, 3788, 3788},
+				{3757, 3779, 3778, 3775, 3776},
+				{3747, 3772, 3771, 3766, 3765},
+				{3736, 3763, 3766, 3760, 3746},
+				{3725, 3749, 3756, 3747, 3729},
+				{3714, 3718, 3734, 3724, 3706},
+				{3701, 3703, 3696, 3689, 3668},
+				{3675, 3695, 3682, 3675, 3662},
+				{3670, 3691, 3680, 3673, 3661},
+				{3661, 3686, 3679, 3672, 3656},
+				{3649, 3680, 3676, 3669, 3641},
+				{3633, 3669, 3667, 3655, 3606},
+				{3610, 3647, 3640, 3620, 3560},
+				{3580, 3607, 3596, 3572, 3501},
+				{3533, 3548, 3537, 3512, 3425},
+				{3457, 3468, 3459, 3429, 3324},
+				{3328, 3348, 3340, 3297, 3172},
+				{3000, 3000, 3000, 3000, 3000}
+	}
 };
 
-static struct sf_lut palladium_1500_rbatt_sf = {
-	.rows		= 19,
+static struct sf_lut rbatt_sf = {
+	.rows		= 29,
 	.cols		= 5,
 	/* row_entries are temperature */
 	.row_entries	= {-20, 0, 20, 40, 65},
-	.percent	= {100, 95, 90, 85, 80, 75, 70, 65, 60, 55, 50,
-				45, 40, 35, 30, 25, 20, 15, 10
-	},
+	.percent	= {100, 95, 90, 85, 80, 75, 70, 65, 60, 55, 50, 45, 40,
+					35, 30, 25, 20, 15, 10, 9, 8, 7, 6, 5,
+					4, 3, 2, 1, 0},
 	.sf		= {
-					{645, 301, 100, 80, 69},
-					{616, 290, 100, 79, 69},
-					{586, 279, 100, 78, 68},
-					{564, 270, 100, 78, 68},
-					{546, 262, 100, 78, 68},
-					{537, 256, 100, 79, 68},
-					{536, 253, 100, 79, 69},
-					{552, 258, 100, 81, 71},
-					{618, 284, 100, 80, 72},
-					{643, 290, 100, 77, 68},
-					{673, 294, 100, 77, 68},
-					{720, 296, 100, 77, 69},
-					{769, 294, 100, 76, 68},
-					{821, 288, 100, 74, 67},
-					{892, 284, 100, 74, 61},
-					{1003, 290, 100, 71, 58},
-					{1192, 307, 100, 70, 58},
-					{1579, 345, 100, 68, 57},
-					{1261, 324, 100, 68, 57},
+				{357, 187, 100, 91, 91},
+				{400, 208, 105, 94, 94},
+				{390, 204, 106, 95, 96},
+				{391, 201, 108, 98, 98},
+				{391, 202, 110, 98, 100},
+				{390, 200, 110, 99, 102},
+				{389, 200, 110, 99, 102},
+				{393, 202, 101, 93, 100},
+				{407, 205, 99, 89, 94},
+				{428, 208, 100, 91, 96},
+				{455, 212, 102, 92, 98},
+				{495, 220, 104, 93, 101},
+				{561, 232, 107, 95, 102},
+				{634, 245, 112, 98, 98},
+				{714, 258, 114, 98, 98},
+				{791, 266, 114, 97, 100},
+				{871, 289, 108, 95, 97},
+				{973, 340, 124, 108, 105},
+				{489, 241, 109, 96, 99},
+				{511, 246, 110, 96, 99},
+				{534, 252, 111, 95, 98},
+				{579, 263, 112, 96, 96},
+				{636, 276, 111, 95, 97},
+				{730, 294, 109, 96, 99},
+				{868, 328, 112, 98, 104},
+				{1089, 374, 119, 101, 115},
+				{1559, 457, 128, 105, 213},
+				{12886, 1026, 637, 422, 3269},
+				{170899, 127211, 98968, 88907, 77102},
 	}
 };
-static struct pc_temp_ocv_lut palladium_1500_pc_temp_ocv = {
-	.rows		= 29,
-	.cols		= 8,
-	.temp		= {-30, -20, -10, 0, 10, 25, 40, 60},
-	.percent	= {100, 95, 90, 85, 80, 75, 70, 65, 60, 55,
-				50, 45, 40, 35, 30, 25, 20, 15, 10, 9,
-				8, 7, 6, 5, 4, 3, 2, 1, 0
-	},
-	.ocv		= {
-			{3673, 3814, 3945, 4025, 4106, 4176, 4218, 4260},
-			{3613, 3751, 3880, 3959, 4038, 4107, 4149, 4190},
-			{3573, 3710, 3837, 3916, 3994, 4062, 4103, 4144},
-			{3534, 3670, 3796, 3873, 3951, 4019, 4059, 4099},
-			{3491, 3625, 3749, 3826, 3902, 3969, 4009, 4049},
-			{3464, 3597, 3721, 3796, 3872, 3939, 3978, 4018},
-			{3436, 3568, 3691, 3766, 3841, 3907, 3946, 3985},
-			{3407, 3537, 3659, 3733, 3808, 3873, 3912, 3951},
-			{3377, 3507, 3627, 3701, 3775, 3840, 3878, 3917},
-			{3355, 3484, 3604, 3677, 3751, 3815, 3853, 3891},
-			{3339, 3467, 3586, 3659, 3732, 3796, 3834, 3872},
-			{3324, 3452, 3570, 3643, 3716, 3780, 3818, 3855},
-			{3312, 3440, 3558, 3630, 3703, 3766, 3804, 3842},
-			{3303, 3430, 3548, 3620, 3692, 3756, 3793, 3831},
-			{3297, 3424, 3541, 3614, 3686, 3749, 3787, 3824},
-			{3288, 3414, 3531, 3603, 3675, 3738, 3776, 3813},
-			{3272, 3398, 3514, 3586, 3658, 3720, 3757, 3795},
-			{3240, 3365, 3480, 3551, 3622, 3684, 3721, 3758},
-			{3224, 3348, 3463, 3533, 3604, 3666, 3702, 3739},
-			{3221, 3344, 3459, 3530, 3600, 3662, 3695, 3728},
-			{3216, 3340, 3454, 3525, 3595, 3657, 3686, 3715},
-			{3212, 3335, 3449, 3520, 3590, 3652, 3677, 3703},
-			{3203, 3326, 3440, 3510, 3580, 3642, 3664, 3686},
-			{3185, 3307, 3420, 3490, 3560, 3621, 3639, 3657},
-			{3176, 3298, 3411, 3481, 3550, 3611, 3626, 3640},
-			{3151, 3272, 3384, 3453, 3522, 3583, 3593, 3604},
-			{3106, 3225, 3335, 3446, 3472, 3531, 3538, 3545},
-			{3021, 3217, 3245, 3417, 3429, 3435, 3439, 3442},
-			{3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000}
-	},
-};
 
 struct pm8921_bms_battery_data palladium_1500_data = {
 	.fcc			= 1500,
-	.fcc_temp_lut		= &palladium_1500_fcc_temp,
-	.fcc_sf_lut		= &palladium_1500_fcc_sf,
-	.pc_temp_ocv_lut	= &palladium_1500_pc_temp_ocv,
-	.pc_sf_lut		= &palladium_1500_pc_sf,
-	.rbatt_sf_lut		= &palladium_1500_rbatt_sf,
-	.default_rbatt_mohm	= 254,
-	.delta_rbatt_mohm	= 60,
+	.fcc_temp_lut		= &fcc_temp,
+	.pc_temp_ocv_lut	= &pc_temp_ocv,
+	.rbatt_sf_lut		= &rbatt_sf,
+	.default_rbatt_mohm	= 236,
 };
diff --git a/arch/arm/mach-msm/board-8064-camera.c b/arch/arm/mach-msm/board-8064-camera.c
index 40995bb..bc1eded 100644
--- a/arch/arm/mach-msm/board-8064-camera.c
+++ b/arch/arm/mach-msm/board-8064-camera.c
@@ -16,7 +16,7 @@
 
 #include <asm/mach-types.h>
 
-#include <mach/board.h>
+#include <mach/camera.h>
 #include <mach/msm_bus_board.h>
 #include <mach/gpiomux.h>
 
@@ -323,6 +323,40 @@
 	},
 };
 
+static struct msm_bus_vectors cam_dual_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 348192000,
+		.ib  = 1208286720,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 206807040,
+		.ib  = 488816640,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 540000000,
+		.ib  = 1350000000,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_MM_IMEM,
+		.ab  = 43200000,
+		.ib  = 69120000,
+	},
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_MM_IMEM,
+		.ab  = 43200000,
+		.ib  = 69120000,
+	},
+};
+
+
 static struct msm_bus_paths cam_bus_client_config[] = {
 	{
 		ARRAY_SIZE(cam_init_vectors),
@@ -348,6 +382,10 @@
 		ARRAY_SIZE(cam_video_ls_vectors),
 		cam_video_ls_vectors,
 	},
+	{
+		ARRAY_SIZE(cam_dual_vectors),
+		cam_dual_vectors,
+	},
 };
 
 static struct msm_bus_scale_pdata cam_bus_client_pdata = {
@@ -369,20 +407,13 @@
 	},
 };
 
-static struct camera_vreg_t apq_8064_back_cam_vreg[] = {
+static struct camera_vreg_t apq_8064_cam_vreg[] = {
 	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
 	{"cam_vio", REG_VS, 0, 0, 0},
 	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
 	{"cam_vaf", REG_LDO, 2800000, 2850000, 300000},
 };
 
-static struct camera_vreg_t apq_8064_front_cam_vreg[] = {
-	{"cam_vio", REG_VS, 0, 0, 0},
-	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
-	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
-	{"cam_vaf", REG_LDO, 2800000, 2850000, 300000},
-};
-
 #define CAML_RSTN PM8921_GPIO_PM_TO_SYS(28)
 #define CAMR_RSTN 34
 
@@ -482,8 +513,8 @@
 
 static struct msm_camera_sensor_platform_info sensor_board_info_imx074 = {
 	.mount_angle	= 90,
-	.cam_vreg = apq_8064_back_cam_vreg,
-	.num_vreg = ARRAY_SIZE(apq_8064_back_cam_vreg),
+	.cam_vreg = apq_8064_cam_vreg,
+	.num_vreg = ARRAY_SIZE(apq_8064_cam_vreg),
 	.gpio_conf = &apq8064_back_cam_gpio_conf,
 	.i2c_conf = &apq8064_back_cam_i2c_conf,
 	.csi_lane_params = &imx074_csi_lane_params,
@@ -515,21 +546,14 @@
 	.csi_lane_mask = 0xF,
 };
 
-static struct camera_vreg_t apq_8064_imx091_vreg[] = {
-	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
-	{"cam_vaf", REG_LDO, 2800000, 2850000, 300000},
-	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
-	{"cam_vio", REG_VS, 0, 0, 0},
-};
-
 static struct msm_camera_sensor_flash_data flash_imx091 = {
 	.flash_type	= MSM_CAMERA_FLASH_NONE,
 };
 
 static struct msm_camera_sensor_platform_info sensor_board_info_imx091 = {
 	.mount_angle	= 0,
-	.cam_vreg = apq_8064_imx091_vreg,
-	.num_vreg = ARRAY_SIZE(apq_8064_imx091_vreg),
+	.cam_vreg = apq_8064_cam_vreg,
+	.num_vreg = ARRAY_SIZE(apq_8064_cam_vreg),
 	.gpio_conf = &apq8064_back_cam_gpio_conf,
 	.i2c_conf = &apq8064_back_cam_i2c_conf,
 	.csi_lane_params = &imx091_csi_lane_params,
@@ -556,13 +580,6 @@
 	.eeprom_info = &imx091_eeprom_info,
 };
 
-static struct camera_vreg_t apq_8064_s5k3l1yx_vreg[] = {
-	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
-	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
-	{"cam_vio", REG_VS, 0, 0, 0},
-	{"cam_vaf", REG_LDO, 2800000, 2850000, 300000},
-};
-
 static struct msm_camera_sensor_flash_data flash_s5k3l1yx = {
 	.flash_type	= MSM_CAMERA_FLASH_NONE,
 };
@@ -574,8 +591,8 @@
 
 static struct msm_camera_sensor_platform_info sensor_board_info_s5k3l1yx = {
 	.mount_angle	= 90,
-	.cam_vreg = apq_8064_s5k3l1yx_vreg,
-	.num_vreg = ARRAY_SIZE(apq_8064_s5k3l1yx_vreg),
+	.cam_vreg = apq_8064_cam_vreg,
+	.num_vreg = ARRAY_SIZE(apq_8064_cam_vreg),
 	.gpio_conf = &apq8064_back_cam_gpio_conf,
 	.i2c_conf = &apq8064_back_cam_i2c_conf,
 	.csi_lane_params = &s5k3l1yx_csi_lane_params,
@@ -591,13 +608,6 @@
 	.sensor_type = BAYER_SENSOR,
 };
 
-static struct camera_vreg_t apq_8064_mt9m114_vreg[] = {
-	{"cam_vio", REG_VS, 0, 0, 0},
-	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
-	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
-	{"cam_vaf", REG_LDO, 2800000, 2850000, 300000},
-};
-
 static struct msm_camera_sensor_flash_data flash_mt9m114 = {
 	.flash_type = MSM_CAMERA_FLASH_NONE
 };
@@ -609,8 +619,8 @@
 
 static struct msm_camera_sensor_platform_info sensor_board_info_mt9m114 = {
 	.mount_angle = 90,
-	.cam_vreg = apq_8064_mt9m114_vreg,
-	.num_vreg = ARRAY_SIZE(apq_8064_mt9m114_vreg),
+	.cam_vreg = apq_8064_cam_vreg,
+	.num_vreg = ARRAY_SIZE(apq_8064_cam_vreg),
 	.gpio_conf = &apq8064_front_cam_gpio_conf,
 	.i2c_conf = &apq8064_front_cam_i2c_conf,
 	.csi_lane_params = &mt9m114_csi_lane_params,
@@ -637,8 +647,8 @@
 
 static struct msm_camera_sensor_platform_info sensor_board_info_ov2720 = {
 	.mount_angle	= 0,
-	.cam_vreg = apq_8064_front_cam_vreg,
-	.num_vreg = ARRAY_SIZE(apq_8064_front_cam_vreg),
+	.cam_vreg = apq_8064_cam_vreg,
+	.num_vreg = ARRAY_SIZE(apq_8064_cam_vreg),
 	.gpio_conf = &apq8064_front_cam_gpio_conf,
 	.i2c_conf = &apq8064_front_cam_i2c_conf,
 	.csi_lane_params = &ov2720_csi_lane_params,
diff --git a/arch/arm/mach-msm/board-8064-display.c b/arch/arm/mach-msm/board-8064-display.c
index 330d7a8..d0f1e87 100644
--- a/arch/arm/mach-msm/board-8064-display.c
+++ b/arch/arm/mach-msm/board-8064-display.c
@@ -62,6 +62,7 @@
 #define MIPI_VIDEO_TOSHIBA_WSVGA_PANEL_NAME "mipi_video_toshiba_wsvga"
 #define MIPI_VIDEO_CHIMEI_WXGA_PANEL_NAME "mipi_video_chimei_wxga"
 #define HDMI_PANEL_NAME "hdmi_msm"
+#define MHL_PANEL_NAME "hdmi_msm,mhl_8334"
 #define TVOUT_PANEL_NAME "tvout_msm"
 
 #define LVDS_PIXEL_MAP_PATTERN_1	1
@@ -73,11 +74,18 @@
 static unsigned char hdmi_is_primary;
 #endif
 
+static unsigned char mhl_display_enabled;
+
 unsigned char apq8064_hdmi_as_primary_selected(void)
 {
 	return hdmi_is_primary;
 }
 
+unsigned char apq8064_mhl_display_enabled(void)
+{
+	return mhl_display_enabled;
+}
+
 static void set_mdp_clocks_for_wuxga(void);
 
 static int msm_fb_detect_panel(const char *name)
@@ -236,18 +244,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
@@ -469,7 +468,11 @@
 
 		gpio_set_value_cansleep(gpio36, 0);
 		gpio_set_value_cansleep(gpio25, 1);
+		if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917)
+			gpio_set_value_cansleep(gpio26, 1);
 	} else {
+		if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917)
+			gpio_set_value_cansleep(gpio26, 0);
 		gpio_set_value_cansleep(gpio25, 0);
 		gpio_set_value_cansleep(gpio36, 1);
 
@@ -600,7 +603,11 @@
 
 		gpio_set_value_cansleep(gpio36, 0);
 		gpio_set_value_cansleep(mpp3, 1);
+		if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917)
+			gpio_set_value_cansleep(gpio26, 1);
 	} else {
+		if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917)
+			gpio_set_value_cansleep(gpio26, 0);
 		gpio_set_value_cansleep(mpp3, 0);
 		gpio_set_value_cansleep(gpio36, 1);
 
@@ -626,14 +633,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 +1033,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 +1042,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;
@@ -1080,7 +1083,15 @@
 			PANEL_NAME_MAX_LEN);
 		pr_debug("msm_fb_pdata.ext_panel_name %s\n",
 			msm_fb_pdata.ext_panel_name);
+
+		if (!strncmp((char *)msm_fb_pdata.ext_panel_name,
+			MHL_PANEL_NAME, strnlen(MHL_PANEL_NAME,
+				PANEL_NAME_MAX_LEN))) {
+			pr_debug("MHL is external display by boot parameter\n");
+			mhl_display_enabled = 1;
+		}
 	}
 
 	msm_fb_pdata.ext_resolution = resolution;
+	hdmi_msm_data.is_mhl_enabled = mhl_display_enabled;
 }
diff --git a/arch/arm/mach-msm/board-8064-gpiomux.c b/arch/arm/mach-msm/board-8064-gpiomux.c
index 4c7ea58..f4e9a8f 100644
--- a/arch/arm/mach-msm/board-8064-gpiomux.c
+++ b/arch/arm/mach-msm/board-8064-gpiomux.c
@@ -336,6 +336,13 @@
 	.pull = GPIOMUX_PULL_NONE,
 };
 
+static struct gpiomux_setting gpio_i2c_2ma_config = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+
 static struct gpiomux_setting gpio_i2c_config_sus = {
 	.func = GPIOMUX_FUNC_1,
 	.drv = GPIOMUX_DRV_2MA,
@@ -428,6 +435,20 @@
 	.pull = GPIOMUX_PULL_DOWN,
 };
 
+static struct gpiomux_setting hdmi_active_3_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_UP,
+	.dir = GPIOMUX_IN,
+};
+
+static struct gpiomux_setting hdmi_active_4_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_UP,
+	.dir = GPIOMUX_OUT_HIGH,
+};
+
 static struct gpiomux_setting gsbi5_suspended_cfg = {
 	.func = GPIOMUX_FUNC_2,
 	.drv = GPIOMUX_DRV_12MA,
@@ -617,6 +638,23 @@
 	},
 };
 
+static struct msm_gpiomux_config apq8064_mhl_configs[] __initdata = {
+	{
+		.gpio = 30,
+		.settings = {
+		[GPIOMUX_ACTIVE]    = &hdmi_active_3_cfg,
+		[GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 35,
+		.settings = {
+		[GPIOMUX_ACTIVE]    = &hdmi_active_4_cfg,
+		[GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+		},
+	},
+};
+
 static struct msm_gpiomux_config apq8064_gsbi_configs[] __initdata = {
 	{
 		.gpio      = 8,			/* GSBI3 I2C QUP SDA */
@@ -683,12 +721,6 @@
 		},
 	},
 	{
-		.gpio      = 32,		/* EPM CS */
-		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_epm_spi_cs_config,
-		},
-	},
-	{
 		.gpio      = 53,		/* NOR CS */
 		.settings = {
 			[GPIOMUX_SUSPENDED] = &gpio_spi_cs_config,
@@ -706,6 +738,35 @@
 			[GPIOMUX_SUSPENDED] = &gsbi7_func1_cfg,
 		},
 	},
+};
+
+static struct msm_gpiomux_config apq8064_non_mi2s_gsbi_configs[] __initdata = {
+	{
+		.gpio      = 32,		/* EPM CS */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_epm_spi_cs_config,
+		},
+	},
+};
+
+static struct msm_gpiomux_config apq8064_gsbi1_i2c_2ma_configs[] __initdata = {
+	{
+		.gpio      = 21,		/* GSBI1 QUP I2C_CLK */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_i2c_config_sus,
+			[GPIOMUX_ACTIVE] = &gpio_i2c_2ma_config,
+		},
+	},
+	{
+		.gpio      = 20,		/* GSBI1 QUP I2C_DATA */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_i2c_config_sus,
+			[GPIOMUX_ACTIVE] = &gpio_i2c_2ma_config,
+		},
+	},
+};
+
+static struct msm_gpiomux_config apq8064_gsbi1_i2c_8ma_configs[] __initdata = {
 	{
 		.gpio      = 21,		/* GSBI1 QUP I2C_CLK */
 		.settings = {
@@ -737,7 +798,7 @@
 	},
 };
 
-static struct gpiomux_setting spkr_i2c = {
+static struct gpiomux_setting spkr_i2s = {
 	.func = GPIOMUX_FUNC_1,
 	.drv = GPIOMUX_DRV_8MA,
 	.pull = GPIOMUX_PULL_KEEPER,
@@ -747,25 +808,25 @@
 	{
 		.gpio   = 47,           /* spkr i2c sck */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &spkr_i2c,
+			[GPIOMUX_SUSPENDED] = &spkr_i2s,
 		},
 	},
 	{
 		.gpio   = 48,           /* spkr_i2s_ws */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &spkr_i2c,
+			[GPIOMUX_SUSPENDED] = &spkr_i2s,
 		},
 	},
 	{
 		.gpio   = 49,           /* spkr_i2s_dout */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &spkr_i2c,
+			[GPIOMUX_SUSPENDED] = &spkr_i2s,
 		},
 	},
 	{
 		.gpio   = 50,           /* spkr_i2s_mclk */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &spkr_i2c,
+			[GPIOMUX_SUSPENDED] = &spkr_i2s,
 		},
 	},
 };
@@ -937,13 +998,19 @@
 	},
 };
 
-static struct gpiomux_setting mi2s_act_cfg = {
+static struct gpiomux_setting i2s_act_cfg = {
 	.func = GPIOMUX_FUNC_1,
 	.drv = GPIOMUX_DRV_8MA,
 	.pull = GPIOMUX_PULL_NONE,
 };
 
-static struct gpiomux_setting mi2s_sus_cfg = {
+static struct gpiomux_setting i2s_act_func_2_cfg = {
+	.func = GPIOMUX_FUNC_2,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting i2s_sus_cfg = {
 	.func = GPIOMUX_FUNC_GPIO,
 	.drv = GPIOMUX_DRV_2MA,
 	.pull = GPIOMUX_PULL_DOWN,
@@ -953,55 +1020,145 @@
 	{
 		.gpio	= 27,		/* mi2s ws */
 		.settings = {
-			[GPIOMUX_ACTIVE]    = &mi2s_act_cfg,
-			[GPIOMUX_SUSPENDED] = &mi2s_sus_cfg,
+			[GPIOMUX_ACTIVE]    = &i2s_act_cfg,
+			[GPIOMUX_SUSPENDED] = &i2s_sus_cfg,
 		},
 	},
 	{
 		.gpio	= 28,		/* mi2s sclk */
 		.settings = {
-			[GPIOMUX_ACTIVE]    = &mi2s_act_cfg,
-			[GPIOMUX_SUSPENDED] = &mi2s_sus_cfg,
+			[GPIOMUX_ACTIVE]    = &i2s_act_cfg,
+			[GPIOMUX_SUSPENDED] = &i2s_sus_cfg,
 		},
 	},
 	{
 		.gpio	= 29,		/* mi2s dout3 */
 		.settings = {
-			[GPIOMUX_ACTIVE]    = &mi2s_act_cfg,
-			[GPIOMUX_SUSPENDED] = &mi2s_sus_cfg,
+			[GPIOMUX_ACTIVE]    = &i2s_act_cfg,
+			[GPIOMUX_SUSPENDED] = &i2s_sus_cfg,
 		},
 	},
 	{
 		.gpio	= 30,		/* mi2s dout2 */
 		.settings = {
-			[GPIOMUX_ACTIVE]    = &mi2s_act_cfg,
-			[GPIOMUX_SUSPENDED] = &mi2s_sus_cfg,
+			[GPIOMUX_ACTIVE]    = &i2s_act_cfg,
+			[GPIOMUX_SUSPENDED] = &i2s_sus_cfg,
 		},
 	},
 
 	{
 		.gpio	= 31,		/* mi2s dout1 */
 		.settings = {
-			[GPIOMUX_ACTIVE]    = &mi2s_act_cfg,
-			[GPIOMUX_SUSPENDED] = &mi2s_sus_cfg,
+			[GPIOMUX_ACTIVE]    = &i2s_act_cfg,
+			[GPIOMUX_SUSPENDED] = &i2s_sus_cfg,
 		},
 	},
 	{
 		.gpio	= 32,		/* mi2s dout0 */
 		.settings = {
-			[GPIOMUX_ACTIVE]    = &mi2s_act_cfg,
-			[GPIOMUX_SUSPENDED] = &mi2s_sus_cfg,
+			[GPIOMUX_ACTIVE]    = &i2s_act_cfg,
+			[GPIOMUX_SUSPENDED] = &i2s_sus_cfg,
 		},
 	},
 
 	{
 		.gpio	= 33,		/* mi2s mclk */
 		.settings = {
-			[GPIOMUX_ACTIVE]    = &mi2s_act_cfg,
-			[GPIOMUX_SUSPENDED] = &mi2s_sus_cfg,
+			[GPIOMUX_ACTIVE]    = &i2s_act_cfg,
+			[GPIOMUX_SUSPENDED] = &i2s_sus_cfg,
 		},
 	},
 };
+
+static struct msm_gpiomux_config apq8064_mi2s_configs[] __initdata = {
+	{
+		.gpio	= 27,		/* mi2s ws */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &i2s_act_cfg,
+			[GPIOMUX_SUSPENDED] = &i2s_sus_cfg,
+		},
+	},
+	{
+		.gpio	= 28,		/* mi2s sclk */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &i2s_act_cfg,
+			[GPIOMUX_SUSPENDED] = &i2s_sus_cfg,
+		},
+	},
+	{
+		.gpio	= 29,		/* mi2s dout3 - TX*/
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &i2s_act_cfg,
+			[GPIOMUX_SUSPENDED] = &i2s_sus_cfg,
+		},
+	},
+	{
+		.gpio	= 32,		/* mi2s dout0 - RX */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &i2s_act_cfg,
+			[GPIOMUX_SUSPENDED] = &i2s_sus_cfg,
+		},
+	},
+
+	{
+		.gpio	= 33,		/* mi2s mclk */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &i2s_act_cfg,
+			[GPIOMUX_SUSPENDED] = &i2s_sus_cfg,
+		},
+	},
+};
+
+static struct msm_gpiomux_config apq8064_mic_i2s_configs[] __initdata = {
+	{
+		.gpio	= 35,		/* mic i2s sclk */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &i2s_act_cfg,
+			[GPIOMUX_SUSPENDED] = &i2s_sus_cfg,
+		},
+	},
+	{
+		.gpio	= 36,		/* mic i2s ws */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &i2s_act_cfg,
+			[GPIOMUX_SUSPENDED] = &i2s_sus_cfg,
+		},
+	},
+	{
+		.gpio	= 37,		/* mic i2s din0 */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &i2s_act_cfg,
+			[GPIOMUX_SUSPENDED] = &i2s_sus_cfg,
+		},
+	},
+};
+
+
+static struct msm_gpiomux_config apq8064_spkr_i2s_configs[] __initdata = {
+	{
+		.gpio	= 40,		/* spkr i2s sclk */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &i2s_act_func_2_cfg,
+			[GPIOMUX_SUSPENDED] = &i2s_sus_cfg,
+		},
+	},
+	{
+		.gpio	= 41,		/* spkr i2s dout */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &i2s_act_func_2_cfg,
+			[GPIOMUX_SUSPENDED] = &i2s_sus_cfg,
+		},
+	},
+	{
+		.gpio	= 42,		/* spkr i2s ws */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &i2s_act_cfg,
+			[GPIOMUX_SUSPENDED] = &i2s_sus_cfg,
+		},
+	},
+};
+
+
 static struct msm_gpiomux_config apq8064_mxt_configs[] __initdata = {
 	{	/* TS INTERRUPT */
 		.gpio = 6,
@@ -1267,6 +1424,49 @@
 	},
 };
 
+static struct gpiomux_setting gsbi6_uartdm_active = {
+	.func = GPIOMUX_FUNC_2,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting gsbi6_uartdm_suspended = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct msm_gpiomux_config mpq8064_uartdm_configs[] __initdata = {
+	{ /* UARTDM_TX */
+		.gpio      = 14,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &gsbi6_uartdm_active,
+			[GPIOMUX_SUSPENDED] = &gsbi6_uartdm_suspended,
+		},
+	},
+	{ /* UARTDM_RX */
+		.gpio      = 15,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &gsbi6_uartdm_active,
+			[GPIOMUX_SUSPENDED] = &gsbi6_uartdm_suspended,
+		},
+	},
+	{ /* UARTDM_CTS */
+		.gpio      = 16,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &gsbi6_uartdm_active,
+			[GPIOMUX_SUSPENDED] = &gsbi6_uartdm_suspended,
+		},
+	},
+	{ /* UARTDM_RFR */
+		.gpio      = 17,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &gsbi6_uartdm_active,
+			[GPIOMUX_SUSPENDED] = &gsbi6_uartdm_suspended,
+		},
+	},
+};
+
 void __init apq8064_init_gpiomux(void)
 {
 	int rc;
@@ -1299,10 +1499,28 @@
 
 		msm_gpiomux_install(apq8064_gsbi_configs,
 				ARRAY_SIZE(apq8064_gsbi_configs));
-	}
 
-	msm_gpiomux_install(apq8064_slimbus_config,
-			ARRAY_SIZE(apq8064_slimbus_config));
+		if (!(machine_is_apq8064_mtp() &&
+		(SOCINFO_VERSION_MINOR(platform_version) == 1)))
+			msm_gpiomux_install(apq8064_non_mi2s_gsbi_configs,
+				ARRAY_SIZE(apq8064_non_mi2s_gsbi_configs));
+	}
+	if (machine_is_apq8064_mtp() &&
+	(SOCINFO_VERSION_MINOR(platform_version) == 1)) {
+			msm_gpiomux_install(apq8064_mic_i2s_configs,
+				ARRAY_SIZE(apq8064_mic_i2s_configs));
+			msm_gpiomux_install(apq8064_spkr_i2s_configs,
+				ARRAY_SIZE(apq8064_spkr_i2s_configs));
+			msm_gpiomux_install(apq8064_mi2s_configs,
+				ARRAY_SIZE(apq8064_mi2s_configs));
+			msm_gpiomux_install(apq8064_gsbi1_i2c_2ma_configs,
+				ARRAY_SIZE(apq8064_gsbi1_i2c_2ma_configs));
+	} else {
+		msm_gpiomux_install(apq8064_slimbus_config,
+				ARRAY_SIZE(apq8064_slimbus_config));
+		msm_gpiomux_install(apq8064_gsbi1_i2c_8ma_configs,
+				ARRAY_SIZE(apq8064_gsbi1_i2c_8ma_configs));
+	}
 
 	msm_gpiomux_install(apq8064_audio_codec_configs,
 			ARRAY_SIZE(apq8064_audio_codec_configs));
@@ -1357,6 +1575,10 @@
 	msm_gpiomux_install(apq8064_hdmi_configs,
 			ARRAY_SIZE(apq8064_hdmi_configs));
 
+	if (apq8064_mhl_display_enabled())
+		msm_gpiomux_install(apq8064_mhl_configs,
+				ARRAY_SIZE(apq8064_mhl_configs));
+
 	 if (machine_is_mpq8064_cdp())
 		msm_gpiomux_install(mpq8064_ir_configs,
 				ARRAY_SIZE(mpq8064_ir_configs));
@@ -1373,4 +1595,7 @@
 
 	msm_gpiomux_install(apq8064_sdc3_configs,
 			ARRAY_SIZE(apq8064_sdc3_configs));
+	 if (machine_is_mpq8064_hrd() || machine_is_mpq8064_dtv())
+		msm_gpiomux_install(mpq8064_uartdm_configs,
+				ARRAY_SIZE(mpq8064_uartdm_configs));
 }
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index e77e7c0..3b47d2e 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -26,6 +26,7 @@
 #include <mach/board.h>
 #include <mach/gpiomux.h>
 #include <mach/restart.h>
+#include <mach/socinfo.h>
 #include "devices.h"
 #include "board-8064.h"
 
@@ -125,7 +126,7 @@
 	PM8921_GPIO_INPUT(35, PM_GPIO_PULL_UP_30),
 	PM8921_GPIO_INPUT(38, PM_GPIO_PULL_UP_30),
 	/* TABLA CODEC RESET */
-	PM8921_GPIO_OUTPUT(34, 1, MED),
+	PM8921_GPIO_OUTPUT(34, 1, HIGH),
 	PM8921_GPIO_OUTPUT(13, 0, HIGH),               /* PCIE_CLK_PWR_EN */
 	PM8921_GPIO_INPUT(12, PM_GPIO_PULL_UP_30),     /* PCIE_WAKE_N */
 };
@@ -141,6 +142,35 @@
 	PM8921_GPIO_INPUT(17, PM_GPIO_PULL_UP_1P5),	/* SD_WP */
 };
 
+static struct pm8xxx_gpio_init pm8921_mpq8064_hrd_gpios[] __initdata = {
+	PM8921_GPIO_OUTPUT(37, 0, LOW),	/* MUX1_SEL */
+};
+
+/* Initial PM8917 GPIO configurations */
+static struct pm8xxx_gpio_init pm8917_gpios[] __initdata = {
+	PM8921_GPIO_OUTPUT(14, 1, HIGH),	/* HDMI Mux Selector */
+	PM8921_GPIO_OUTPUT(23, 0, HIGH),	/* touchscreen power FET */
+	PM8921_GPIO_OUTPUT_BUFCONF(25, 0, LOW, CMOS), /* DISP_RESET_N */
+	PM8921_GPIO_OUTPUT(26, 1, HIGH), /* Backlight: on */
+	PM8921_GPIO_OUTPUT_BUFCONF(36, 1, LOW, OPEN_DRAIN),
+	PM8921_GPIO_OUTPUT_FUNC(38, 0, PM_GPIO_FUNC_2),
+	PM8921_GPIO_OUTPUT(33, 0, HIGH),
+	PM8921_GPIO_OUTPUT(20, 0, HIGH),
+	PM8921_GPIO_INPUT(35, PM_GPIO_PULL_UP_30),
+	PM8921_GPIO_INPUT(30, PM_GPIO_PULL_UP_30),
+	/* 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 */
+};
+
+/* PM8921 GPIO 42 remaps to PM8917 GPIO 8 */
+static struct pm8xxx_gpio_init pm8917_cdp_kp_gpios[] __initdata = {
+	PM8921_GPIO_INPUT(27, PM_GPIO_PULL_UP_30),
+	PM8921_GPIO_INPUT(8, PM_GPIO_PULL_UP_30),
+	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,
@@ -157,52 +187,49 @@
 	PM8921_MPP_INIT(1, D_OUTPUT, PM8921_MPP_DIG_LEVEL_VPH, DOUT_CTRL_HIGH),
 };
 
+
+void __init apq8064_configure_gpios(struct pm8xxx_gpio_init *data, int len)
+{
+	int i, rc;
+
+	for (i = 0; i < len; i++) {
+		rc = pm8xxx_gpio_config(data[i].gpio, &data[i].config);
+		if (rc)
+			pr_err("%s: pm8xxx_gpio_config(%u) failed: rc=%d\n",
+				__func__, data[i].gpio, rc);
+	}
+}
+
 void __init apq8064_pm8xxx_gpio_mpp_init(void)
 {
 	int i, rc;
 
-	for (i = 0; i < ARRAY_SIZE(pm8921_gpios); i++) {
-		rc = pm8xxx_gpio_config(pm8921_gpios[i].gpio,
-					&pm8921_gpios[i].config);
-		if (rc) {
-			pr_err("%s: pm8xxx_gpio_config: rc=%d\n", __func__, rc);
-			break;
-		}
+	if (socinfo_get_pmic_model() != PMIC_MODEL_PM8917)
+		apq8064_configure_gpios(pm8921_gpios, ARRAY_SIZE(pm8921_gpios));
+	else
+		apq8064_configure_gpios(pm8917_gpios, ARRAY_SIZE(pm8917_gpios));
+
+	if (machine_is_apq8064_cdp() || machine_is_apq8064_liquid()) {
+		if (socinfo_get_pmic_model() != PMIC_MODEL_PM8917)
+			apq8064_configure_gpios(pm8921_cdp_kp_gpios,
+					ARRAY_SIZE(pm8921_cdp_kp_gpios));
+		else
+			apq8064_configure_gpios(pm8917_cdp_kp_gpios,
+					ARRAY_SIZE(pm8917_cdp_kp_gpios));
 	}
 
-	if (machine_is_apq8064_cdp() || machine_is_apq8064_liquid())
-		for (i = 0; i < ARRAY_SIZE(pm8921_cdp_kp_gpios); i++) {
-			rc = pm8xxx_gpio_config(pm8921_cdp_kp_gpios[i].gpio,
-						&pm8921_cdp_kp_gpios[i].config);
-			if (rc) {
-				pr_err("%s: pm8xxx_gpio_config: rc=%d\n",
-					__func__, rc);
-				break;
-			}
-		}
-
 	if (machine_is_apq8064_mtp())
-		for (i = 0; i < ARRAY_SIZE(pm8921_mtp_kp_gpios); i++) {
-			rc = pm8xxx_gpio_config(pm8921_mtp_kp_gpios[i].gpio,
-						&pm8921_mtp_kp_gpios[i].config);
-			if (rc) {
-				pr_err("%s: pm8xxx_gpio_config: rc=%d\n",
-					__func__, rc);
-				break;
-			}
-		}
+		apq8064_configure_gpios(pm8921_mtp_kp_gpios,
+					ARRAY_SIZE(pm8921_mtp_kp_gpios));
 
 	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;
-			}
-		}
+	    || machine_is_mpq8064_dtv())
+		apq8064_configure_gpios(pm8921_mpq_gpios,
+					ARRAY_SIZE(pm8921_mpq_gpios));
+
+	if (machine_is_mpq8064_hrd())
+		apq8064_configure_gpios(pm8921_mpq8064_hrd_gpios,
+					ARRAY_SIZE(pm8921_mpq8064_hrd_gpios));
 
 	for (i = 0; i < ARRAY_SIZE(pm8xxx_mpps); i++) {
 		rc = pm8xxx_mpp_config(pm8xxx_mpps[i].mpp,
@@ -360,6 +387,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,
@@ -368,7 +396,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,
@@ -379,6 +407,7 @@
 	.warm_bat_voltage	= 4100,
 	.thermal_mitigation	= apq8064_pm8921_therm_mitigation,
 	.thermal_levels		= ARRAY_SIZE(apq8064_pm8921_therm_mitigation),
+	.rconn_mohm		= 18,
 };
 
 static struct pm8xxx_ccadc_platform_data
@@ -389,16 +418,18 @@
 
 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
 apq8064_pm8921_platform_data __devinitdata = {
-	.regulator_pdatas	= msm8064_pm8921_regulator_pdata,
 	.irq_pdata		= &apq8064_pm8921_irq_pdata,
 	.gpio_pdata		= &apq8064_pm8921_gpio_pdata,
 	.mpp_pdata		= &apq8064_pm8921_mpp_pdata,
@@ -455,12 +486,23 @@
 						&apq8064_ssbi_pm8921_pdata;
 	apq8064_device_ssbi_pmic2.dev.platform_data =
 				&apq8064_ssbi_pm8821_pdata;
-	apq8064_pm8921_platform_data.num_regulators =
-					msm8064_pm8921_regulator_pdata_len;
+	if (socinfo_get_pmic_model() != PMIC_MODEL_PM8917) {
+		apq8064_pm8921_platform_data.regulator_pdatas
+			= msm8064_pm8921_regulator_pdata;
+		apq8064_pm8921_platform_data.num_regulators
+			= msm8064_pm8921_regulator_pdata_len;
+	} else {
+		apq8064_pm8921_platform_data.regulator_pdatas
+			= msm8064_pm8917_regulator_pdata;
+		apq8064_pm8921_platform_data.num_regulators
+			= msm8064_pm8917_regulator_pdata_len;
+	}
 
 	if (machine_is_apq8064_mtp()) {
 		apq8064_pm8921_bms_pdata.battery_type = BATT_PALLADIUM;
 	} else if (machine_is_apq8064_liquid()) {
 		apq8064_pm8921_bms_pdata.battery_type = BATT_DESAY;
+	} else if (machine_is_apq8064_cdp()) {
+		apq8064_pm8921_chg_pdata.has_dc_supply = true;
 	}
 }
diff --git a/arch/arm/mach-msm/board-8064-regulator.c b/arch/arm/mach-msm/board-8064-regulator.c
index 10b7034..d41eef3 100644
--- a/arch/arm/mach-msm/board-8064-regulator.c
+++ b/arch/arm/mach-msm/board-8064-regulator.c
@@ -18,6 +18,7 @@
 #define VREG_CONSUMERS(_id) \
 	static struct regulator_consumer_supply vreg_consumers_##_id[]
 
+/* Regulators that are present when using either PM8921 or PM8917 */
 /*
  * Consumer specific regulator names:
  *			 regulator name		consumer dev_name
@@ -32,6 +33,8 @@
 	REGULATOR_SUPPLY("mipi_csi_vdd",	"msm_csid.2"),
 	REGULATOR_SUPPLY("lvds_pll_vdda",	"lvds.0"),
 	REGULATOR_SUPPLY("dsi1_pll_vdda",	"mipi_dsi.1"),
+	REGULATOR_SUPPLY("HRD_VDDD_CDC_D",		"tabla2x-slim"),
+	REGULATOR_SUPPLY("HRD_CDC_VDDA_A_1P2V",	"tabla2x-slim"),
 };
 VREG_CONSUMERS(L3) = {
 	REGULATOR_SUPPLY("8921_l3",		NULL),
@@ -84,6 +87,9 @@
 	REGULATOR_SUPPLY("cam_vdig",		"4-0020"),
 	REGULATOR_SUPPLY("8921_l12",		NULL),
 };
+VREG_CONSUMERS(L13) = {
+	REGULATOR_SUPPLY("8921_l13",		NULL),
+};
 VREG_CONSUMERS(L14) = {
 	REGULATOR_SUPPLY("8921_l14",		NULL),
 };
@@ -127,6 +133,8 @@
 	REGULATOR_SUPPLY("CDC_VDDA_A_1P2V",	"tabla-slim"),
 	REGULATOR_SUPPLY("VDDD_CDC_D",		"tabla2x-slim"),
 	REGULATOR_SUPPLY("CDC_VDDA_A_1P2V",	"tabla2x-slim"),
+	REGULATOR_SUPPLY("VDDD_CDC_D",		"0-000d"),
+	REGULATOR_SUPPLY("CDC_VDDA_A_1P2V",	"0-000d"),
 };
 VREG_CONSUMERS(L26) = {
 	REGULATOR_SUPPLY("8921_l26",		NULL),
@@ -143,9 +151,6 @@
 VREG_CONSUMERS(L29) = {
 	REGULATOR_SUPPLY("8921_l29",		NULL),
 };
-VREG_CONSUMERS(S1) = {
-	REGULATOR_SUPPLY("8921_s1",		NULL),
-};
 VREG_CONSUMERS(S2) = {
 	REGULATOR_SUPPLY("8921_s2",		NULL),
 	REGULATOR_SUPPLY("iris_vddrfa",		"wcnss_wlan.0"),
@@ -171,6 +176,10 @@
 	REGULATOR_SUPPLY("CDC_VDD_CP",		"tabla2x-slim"),
 	REGULATOR_SUPPLY("CDC_VDDA_TX",		"tabla2x-slim"),
 	REGULATOR_SUPPLY("CDC_VDDA_RX",		"tabla2x-slim"),
+	REGULATOR_SUPPLY("VDDIO_CDC",		"0-000d"),
+	REGULATOR_SUPPLY("CDC_VDD_CP",		"0-000d"),
+	REGULATOR_SUPPLY("CDC_VDDA_TX",		"0-000d"),
+	REGULATOR_SUPPLY("CDC_VDDA_RX",		"0-000d"),
 	REGULATOR_SUPPLY("riva_vddpx",		"wcnss_wlan.0"),
 	REGULATOR_SUPPLY("vcc_i2c",		"3-005b"),
 	REGULATOR_SUPPLY("vcc_i2c",		"3-0024"),
@@ -195,10 +204,6 @@
 	REGULATOR_SUPPLY("8921_lvs1",		NULL),
 	REGULATOR_SUPPLY("iris_vddio",		"wcnss_wlan.0"),
 };
-VREG_CONSUMERS(LVS2) = {
-	REGULATOR_SUPPLY("8921_lvs2",		NULL),
-	REGULATOR_SUPPLY("iris_vdddig",		"wcnss_wlan.0"),
-};
 VREG_CONSUMERS(LVS3) = {
 	REGULATOR_SUPPLY("8921_lvs3",		NULL),
 };
@@ -228,13 +233,6 @@
 	REGULATOR_SUPPLY("8921_usb_otg",	NULL),
 	REGULATOR_SUPPLY("vbus_otg",		"msm_otg"),
 };
-VREG_CONSUMERS(HDMI_MVS) = {
-	REGULATOR_SUPPLY("8921_hdmi_mvs",	NULL),
-	REGULATOR_SUPPLY("hdmi_mvs",		"hdmi_msm.0"),
-};
-VREG_CONSUMERS(NCP) = {
-	REGULATOR_SUPPLY("8921_ncp",		NULL),
-};
 VREG_CONSUMERS(8821_S0) = {
 	REGULATOR_SUPPLY("8821_s0",		NULL),
 	REGULATOR_SUPPLY("krait2",		"acpuclk-8064"),
@@ -243,11 +241,6 @@
 	REGULATOR_SUPPLY("8821_s1",		NULL),
 	REGULATOR_SUPPLY("krait3",		"acpuclk-8064"),
 };
-VREG_CONSUMERS(EXT_5V) = {
-	REGULATOR_SUPPLY("ext_5v",		NULL),
-	REGULATOR_SUPPLY("ext_ddr3",		NULL),
-	REGULATOR_SUPPLY("vbus",		"msm_ehci_host.0"),
-};
 VREG_CONSUMERS(EXT_MPP8) = {
 	REGULATOR_SUPPLY("ext_mpp8",		NULL),
 	REGULATOR_SUPPLY("vbus",		"msm_ehci_host.1"),
@@ -281,6 +274,60 @@
 	REGULATOR_SUPPLY("avc_3p3v",	NULL),
 };
 
+/* Regulators that are only present when using PM8921 */
+VREG_CONSUMERS(S1) = {
+	REGULATOR_SUPPLY("8921_s1",		NULL),
+};
+VREG_CONSUMERS(LVS2) = {
+	REGULATOR_SUPPLY("8921_lvs2",		NULL),
+	REGULATOR_SUPPLY("iris_vdddig",		"wcnss_wlan.0"),
+};
+VREG_CONSUMERS(HDMI_MVS) = {
+	REGULATOR_SUPPLY("8921_hdmi_mvs",	NULL),
+	REGULATOR_SUPPLY("hdmi_mvs",		"hdmi_msm.0"),
+};
+VREG_CONSUMERS(NCP) = {
+	REGULATOR_SUPPLY("8921_ncp",		NULL),
+};
+VREG_CONSUMERS(EXT_5V) = {
+	REGULATOR_SUPPLY("ext_5v",		NULL),
+	REGULATOR_SUPPLY("ext_ddr3",		NULL),
+	REGULATOR_SUPPLY("vbus",		"msm_ehci_host.0"),
+};
+
+/* Regulators that are only present when using PM8917 */
+VREG_CONSUMERS(8917_S1) = {
+	REGULATOR_SUPPLY("8921_s1",		NULL),
+	REGULATOR_SUPPLY("iris_vdddig",		"wcnss_wlan.0"),
+};
+VREG_CONSUMERS(L30) = {
+	REGULATOR_SUPPLY("8917_l30",		NULL),
+};
+VREG_CONSUMERS(L31) = {
+	REGULATOR_SUPPLY("8917_l31",		NULL),
+};
+VREG_CONSUMERS(L32) = {
+	REGULATOR_SUPPLY("8917_l32",		NULL),
+};
+VREG_CONSUMERS(L33) = {
+	REGULATOR_SUPPLY("8917_l33",		NULL),
+};
+VREG_CONSUMERS(L34) = {
+	REGULATOR_SUPPLY("8917_l34",		NULL),
+};
+VREG_CONSUMERS(L35) = {
+	REGULATOR_SUPPLY("8917_l35",		NULL),
+};
+VREG_CONSUMERS(L36) = {
+	REGULATOR_SUPPLY("8917_l36",		NULL),
+};
+VREG_CONSUMERS(BOOST) = {
+	REGULATOR_SUPPLY("8917_boost",		NULL),
+	REGULATOR_SUPPLY("ext_ddr3",		NULL),
+	REGULATOR_SUPPLY("vbus",		"msm_ehci_host.0"),
+	REGULATOR_SUPPLY("hdmi_mvs",		"hdmi_msm.0"),
+};
+
 #define PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, _modes, _ops, \
 			 _apply_uV, _pull_down, _always_on, _supply_regulator, \
 			 _system_uA, _enable_time, _reg_id) \
@@ -356,6 +403,12 @@
 		REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, 0, 0, \
 		_always_on, _supply_regulator, 0, _enable_time, _reg_id)
 
+#define PM8XXX_BOOST(_id, _name, _always_on, _min_uV, _max_uV, _enable_time, \
+		_supply_regulator, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, 0, \
+		REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, 0, 0, \
+		_always_on, _supply_regulator, 0, _enable_time, _reg_id)
+
 /* Pin control initialization */
 #define PM8XXX_PC(_id, _name, _always_on, _pin_fn, _pin_ctrl, \
 		  _supply_regulator, _reg_id) \
@@ -553,6 +606,39 @@
 	PM8XXX_VS300(HDMI_MVS, "8921_hdmi_mvs", 0, 1,         0, "ext_5v", 3),
 };
 
+/* PM8917 regulator constraints */
+struct pm8xxx_regulator_platform_data
+msm8064_pm8917_regulator_pdata[] __devinitdata = {
+	/*
+	 *		ID   name always_on pd min_uV   max_uV   en_t supply
+	 *	system_uA reg_ID
+	 */
+	PM8XXX_NLDO1200(L26, "8921_l26", 0, 1, 375000, 1050000, 200, "8921_s7",
+		0, 1),
+	PM8XXX_LDO(L30,      "8917_l30", 0, 1, 1800000, 1800000, 200, NULL,
+		0, 2),
+	PM8XXX_LDO(L31,      "8917_l31", 0, 1, 1800000, 1800000, 200, NULL,
+		0, 3),
+	PM8XXX_LDO(L32,      "8917_l32", 0, 1, 2800000, 2800000, 200, NULL,
+		0, 4),
+	PM8XXX_LDO(L33,      "8917_l33", 0, 1, 2800000, 2800000, 200, NULL,
+		0, 5),
+	PM8XXX_LDO(L34,      "8917_l34", 0, 1, 1800000, 1800000, 200, NULL,
+		0, 6),
+	PM8XXX_LDO(L35,      "8917_l35", 0, 1, 3000000, 3000000, 200, NULL,
+		0, 7),
+	PM8XXX_LDO(L36,      "8917_l36", 0, 1, 1800000, 1800000, 200, NULL,
+		0, 8),
+
+	/*
+	 *           ID     name   always_on  min_uV   max_uV en_t supply reg_ID
+	 */
+	PM8XXX_BOOST(BOOST, "8917_boost", 0,  5000000, 5000000, 500, NULL, 9),
+
+	/*	     ID        name      always_on pd en_t supply    reg_ID */
+	PM8XXX_VS300(USB_OTG,  "8921_usb_otg",  0, 1, 0,   "8917_boost", 10),
+};
+
 static struct rpm_regulator_init_data
 apq8064_rpm_regulator_init_data[] __devinitdata = {
 	/*	ID a_on pd ss min_uV   max_uV  supply sys_uA  freq  fm  ss_fm */
@@ -576,6 +662,7 @@
 	RPM_LDO(L10, 0, 1, 0, 2900000, 2900000, NULL,          0,     0),
 	RPM_LDO(L11, 0, 1, 0, 3000000, 3000000, NULL,          0,     0),
 	RPM_LDO(L12, 0, 1, 0, 1200000, 1200000, "8921_s4",     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(L16, 0, 1, 0, 2800000, 2800000, NULL,          0,     0),
@@ -592,12 +679,17 @@
 
 	/*     ID  a_on pd ss                   supply */
 	RPM_VS(LVS1, 0, 1, 0,                   "8921_s4"),
-	RPM_VS(LVS2, 0, 1, 0,                   "8921_s1"),
 	RPM_VS(LVS3, 0, 1, 0,                   "8921_s4"),
 	RPM_VS(LVS4, 0, 1, 0,                   "8921_s4"),
 	RPM_VS(LVS5, 0, 1, 0,                   "8921_s4"),
 	RPM_VS(LVS6, 0, 1, 0,                   "8921_s4"),
 	RPM_VS(LVS7, 0, 1, 1,                   "8921_s4"),
+};
+
+static struct rpm_regulator_init_data
+apq8064_rpm_regulator_pm8921_init_data[] __devinitdata = {
+	/*     ID  a_on pd ss                   supply */
+	RPM_VS(LVS2, 0, 1, 0,                   "8921_s1"),
 
 	/*	ID a_on    ss min_uV   max_uV   supply     freq */
 	RPM_NCP(NCP, 0,    0, 1800000, 1800000, "8921_l6", 1p60),
@@ -605,6 +697,8 @@
 
 int msm8064_pm8921_regulator_pdata_len __devinitdata =
 	ARRAY_SIZE(msm8064_pm8921_regulator_pdata);
+int msm8064_pm8917_regulator_pdata_len __devinitdata =
+	ARRAY_SIZE(msm8064_pm8917_regulator_pdata);
 
 #define RPM_REG_MAP(_id, _sleep_also, _voter, _supply, _dev_name) \
 	{ \
@@ -641,3 +735,34 @@
 	.consumer_map		  = msm_rpm_regulator_consumer_mapping,
 	.consumer_map_len = ARRAY_SIZE(msm_rpm_regulator_consumer_mapping),
 };
+
+/* Regulators that are only present when using PM8921 */
+struct rpm_regulator_platform_data
+apq8064_rpm_regulator_pm8921_pdata __devinitdata = {
+	.init_data		  = apq8064_rpm_regulator_pm8921_init_data,
+	.num_regulators	= ARRAY_SIZE(apq8064_rpm_regulator_pm8921_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,
+};
+
+/*
+ * Fix up regulator consumer data that moves to a different regulator when
+ * PM8917 is used.
+ */
+void __init configure_apq8064_pm8917_power_grid(void)
+{
+	static struct rpm_regulator_init_data *rpm_data;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(apq8064_rpm_regulator_init_data); i++) {
+		rpm_data = &apq8064_rpm_regulator_init_data[i];
+		if (rpm_data->id == RPM_VREG_ID_PM8921_S1) {
+			rpm_data->init_data.consumer_supplies
+				= vreg_consumers_8917_S1;
+			rpm_data->init_data.num_consumer_supplies
+				= ARRAY_SIZE(vreg_consumers_8917_S1);
+		}
+	}
+}
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 665b861..ec52d1a 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -27,7 +27,7 @@
 #include <linux/spi/spi.h>
 #include <linux/dma-mapping.h>
 #include <linux/platform_data/qcom_crypto_device.h>
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
 #include <linux/memory.h>
 #include <linux/memblock.h>
 #include <linux/msm_thermal.h>
@@ -68,6 +68,7 @@
 #include <linux/msm_tsens.h>
 #include <mach/msm_xo.h>
 #include <mach/msm_rtb.h>
+#include <mach/msm_serial_hs.h>
 #include <sound/cs8427.h>
 #include <media/gpio-ir-recv.h>
 #include <linux/fmem.h>
@@ -85,6 +86,9 @@
 #include "devices-msm8x60.h"
 #include "smd_private.h"
 
+#define MHL_GPIO_INT           30
+#define MHL_GPIO_RESET         35
+
 #define MSM_PMEM_ADSP_SIZE         0x7800000
 #define MSM_PMEM_AUDIO_SIZE        0x4CF000
 #ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
@@ -95,7 +99,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 +115,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
 
@@ -133,14 +137,14 @@
 #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
@@ -213,6 +217,13 @@
 #endif /* CONFIG_MSM_MULTIMEDIA_USE_ION */
 #endif /* CONFIG_ANDROID_PMEM */
 
+#ifdef CONFIG_BATTERY_BCL
+static struct platform_device battery_bcl_device = {
+	.name = "battery_current_limit",
+	.id = -1,
+};
+#endif
+
 struct fmem_platform_data apq8064_fmem_pdata = {
 };
 
@@ -263,7 +274,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*/
 }
 
@@ -883,7 +894,7 @@
 };
 
 static int phy_init_seq[] = {
-	0x38, 0x81, /* update DC voltage level */
+	0x68, 0x81, /* update DC voltage level */
 	0x24, 0x82, /* set pre-emphasis and rise/fall time */
 	-1
 };
@@ -960,18 +971,14 @@
 };
 
 static struct epm_chan_properties ads_adc_channel_data[] = {
-	{10, 100}, {500, 50}, {1, 1}, {1, 1},
-	{20, 50}, {10, 100}, {1, 1}, {1, 1},
-	{10, 100}, {10, 100}, {100, 100}, {200, 100},
-	{100, 50}, {2000, 50}, {1000, 50}, {200, 50},
-	{200, 100}, {1, 1}, {20, 50}, {500, 50},
-	{50, 50}, {200, 100}, {500, 100}, {20, 50},
-	{200, 50}, {2000, 100}, {1000, 50}, {100, 50},
-	{200, 100}, {500, 50}, {1000, 100}, {200, 50},
-	{1000, 50}, {50, 50}, {100, 50}, {100, 50},
-	{1, 1}, {1, 1}, {20, 100}, {20, 50},
-	{500, 100}, {1000, 100}, {100, 50}, {1000, 50},
-	{100, 50}, {1000, 100}, {100, 50}, {100, 50},
+	{10, 100}, {1000, 1}, {10, 100}, {1000, 1},
+	{10, 100}, {1000, 1}, {10, 100}, {1000, 1},
+	{10, 100}, {20, 100}, {500, 100}, {5, 100},
+	{1000, 1}, {200, 100}, {50, 100}, {10, 100},
+	{510, 100}, {50, 100}, {20, 100}, {100, 100},
+	{510, 100}, {20, 100}, {50, 100}, {200, 100},
+	{10, 100}, {20, 100}, {1000, 1}, {10, 100},
+	{200, 100}, {510, 100}, {1000, 100}, {200, 100},
 };
 
 static struct epm_adc_platform_data epm_adc_pdata = {
@@ -1022,7 +1029,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,
@@ -1089,7 +1096,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,
@@ -1144,6 +1151,152 @@
 	},
 };
 
+static struct wcd9xxx_pdata apq8064_tabla_i2c_platform_data = {
+	.irq = MSM_GPIO_TO_INT(77),
+	.irq_base = TABLA_INTERRUPT_BASE,
+	.num_irqs = NR_WCD9XXX_IRQS,
+	.reset_gpio = PM8921_GPIO_PM_TO_SYS(34),
+	.micbias = {
+		.ldoh_v = TABLA_LDOH_2P85_V,
+		.cfilt1_mv = 1800,
+		.cfilt2_mv = 1800,
+		.cfilt3_mv = 1800,
+		.bias1_cfilt_sel = TABLA_CFILT1_SEL,
+		.bias2_cfilt_sel = TABLA_CFILT2_SEL,
+		.bias3_cfilt_sel = TABLA_CFILT3_SEL,
+		.bias4_cfilt_sel = TABLA_CFILT3_SEL,
+	},
+	.regulator = {
+	{
+		.name = "CDC_VDD_CP",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_CP_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_RX",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_RX_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_TX",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_TX_CUR_MAX,
+	},
+	{
+		.name = "VDDIO_CDC",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_VDDIO_CDC_CUR_MAX,
+	},
+	{
+		.name = "VDDD_CDC_D",
+		.min_uV = 1225000,
+		.max_uV = 1250000,
+		.optimum_uA = WCD9XXX_VDDD_CDC_D_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_A_1P2V",
+		.min_uV = 1225000,
+		.max_uV = 1250000,
+		.optimum_uA = WCD9XXX_VDDD_CDC_A_CUR_MAX,
+	},
+	},
+};
+
+static struct i2c_board_info apq8064_tabla_i2c_device_info[] __initdata = {
+	{
+		I2C_BOARD_INFO("tabla top level",
+				APQ_8064_TABLA_I2C_SLAVE_ADDR),
+		.platform_data = &apq8064_tabla_i2c_platform_data,
+	},
+	{
+		I2C_BOARD_INFO("tabla analog",
+				APQ_8064_TABLA_ANALOG_I2C_SLAVE_ADDR),
+		.platform_data = &apq8064_tabla_i2c_platform_data,
+	},
+	{
+		I2C_BOARD_INFO("tabla digital1",
+				APQ_8064_TABLA_DIGITAL1_I2C_SLAVE_ADDR),
+		.platform_data = &apq8064_tabla_i2c_platform_data,
+	},
+	{
+		I2C_BOARD_INFO("tabla digital2",
+				APQ_8064_TABLA_DIGITAL2_I2C_SLAVE_ADDR),
+		.platform_data = &apq8064_tabla_i2c_platform_data,
+	},
+};
+
+static struct wcd9xxx_pdata mpq8064_ashiko20_platform_data = {
+	.slimbus_slave_device = {
+		.name = "tabla-slave",
+		.e_addr = {0, 0, 0x60, 0, 0x17, 2},
+	},
+	.irq = MSM_GPIO_TO_INT(42),
+	.irq_base = TABLA_INTERRUPT_BASE,
+	.num_irqs = NR_WCD9XXX_IRQS,
+	.reset_gpio = PM8921_GPIO_PM_TO_SYS(34),
+	.micbias = {
+		.ldoh_v = TABLA_LDOH_2P85_V,
+		.cfilt1_mv = 1800,
+		.cfilt2_mv = 1800,
+		.cfilt3_mv = 1800,
+		.bias1_cfilt_sel = TABLA_CFILT1_SEL,
+		.bias2_cfilt_sel = TABLA_CFILT2_SEL,
+		.bias3_cfilt_sel = TABLA_CFILT3_SEL,
+		.bias4_cfilt_sel = TABLA_CFILT3_SEL,
+	},
+	.regulator = {
+	{
+		.name = "CDC_VDD_CP",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_CP_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_RX",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_RX_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_TX",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_TX_CUR_MAX,
+	},
+	{
+		.name = "VDDIO_CDC",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_VDDIO_CDC_CUR_MAX,
+	},
+	{
+		.name = "HRD_VDDD_CDC_D",
+		.min_uV = 1200000,
+		.max_uV = 1200000,
+		.optimum_uA = WCD9XXX_VDDD_CDC_D_CUR_MAX,
+	},
+	{
+		.name = "HRD_CDC_VDDA_A_1P2V",
+		.min_uV = 1200000,
+		.max_uV = 1200000,
+		.optimum_uA = WCD9XXX_VDDD_CDC_A_CUR_MAX,
+	},
+	},
+};
+
+static struct slim_device mpq8064_slim_ashiko20 = {
+	.name = "tabla2x-slim",
+	.e_addr = {0, 1, 0x60, 0, 0x17, 2},
+	.dev = {
+		.platform_data = &mpq8064_ashiko20_platform_data,
+	},
+};
+
+
 /* enable the level shifter for cs8427 to make sure the I2C
  * clock is running at 100KHz and voltage levels are at 3.3
  * and 5 volts
@@ -1160,8 +1313,10 @@
 			return ret;
 		}
 		gpio_direction_output(SX150X_GPIO(1, 10), 1);
-	} else
+	} else {
+		gpio_direction_output(SX150X_GPIO(1, 10), 0);
 		gpio_free(SX150X_GPIO(1, 10));
+	}
 	return ret;
 }
 
@@ -1181,13 +1336,18 @@
 #define HAP_SHIFT_LVL_OE_GPIO		PM8921_MPP_PM_TO_SYS(8)
 #define ISA1200_HAP_EN_GPIO		PM8921_GPIO_PM_TO_SYS(33)
 #define ISA1200_HAP_LEN_GPIO		PM8921_GPIO_PM_TO_SYS(20)
-#define ISA1200_HAP_CLK			PM8921_GPIO_PM_TO_SYS(44)
+#define ISA1200_HAP_CLK_PM8921		PM8921_GPIO_PM_TO_SYS(44)
+#define ISA1200_HAP_CLK_PM8917		PM8921_GPIO_PM_TO_SYS(38)
 
 static int isa1200_clk_enable(bool on)
 {
+	unsigned int gpio = ISA1200_HAP_CLK_PM8921;
 	int rc = 0;
 
-	gpio_set_value_cansleep(ISA1200_HAP_CLK, on);
+	if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917)
+		gpio = ISA1200_HAP_CLK_PM8917;
+
+	gpio_set_value_cansleep(gpio, on);
 
 	if (on) {
 		rc = pm8xxx_aux_clk_control(CLK_MP3_2, XO_DIV_1, true);
@@ -1206,25 +1366,29 @@
 	return rc;
 
 err_gpio_dis:
-	gpio_set_value_cansleep(ISA1200_HAP_CLK, !on);
+	gpio_set_value_cansleep(gpio, !on);
 	return rc;
 }
 
 static int isa1200_dev_setup(bool enable)
 {
+	unsigned int gpio = ISA1200_HAP_CLK_PM8921;
 	int rc = 0;
 
+	if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917)
+		gpio = ISA1200_HAP_CLK_PM8917;
+
 	if (!enable)
 		goto free_gpio;
 
-	rc = gpio_request(ISA1200_HAP_CLK, "haptics_clk");
+	rc = gpio_request(gpio, "haptics_clk");
 	if (rc) {
 		pr_err("%s: unable to request gpio %d config(%d)\n",
-			__func__, ISA1200_HAP_CLK, rc);
+			__func__, gpio, rc);
 		return rc;
 	}
 
-	rc = gpio_direction_output(ISA1200_HAP_CLK, 0);
+	rc = gpio_direction_output(gpio, 0);
 	if (rc) {
 		pr_err("%s: unable to set direction\n", __func__);
 		goto free_gpio;
@@ -1233,7 +1397,7 @@
 	return 0;
 
 free_gpio:
-	gpio_free(ISA1200_HAP_CLK);
+	gpio_free(gpio);
 	return rc;
 }
 
@@ -1277,7 +1441,7 @@
 	/* T6 Object */
 	0, 0, 0, 0, 0, 0,
 	/* T38 Object */
-	14, 2, 0, 24, 5, 12, 0, 0, 0, 0,
+	14, 3, 0, 5, 7, 12, 0, 0, 0, 0,
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -1285,12 +1449,12 @@
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	0, 0, 0, 0,
 	/* T7 Object */
-	100, 10, 50,
+	32, 10, 50,
 	/* T8 Object */
 	25, 0, 20, 20, 0, 0, 0, 0, 0, 0,
 	/* T9 Object */
 	139, 0, 0, 26, 42, 0, 32, 80, 2, 5,
-	0, 5, 5, 0, 10, 30, 10, 10, 255, 2,
+	0, 5, 5, 79, 10, 30, 10, 10, 255, 2,
 	85, 5, 0, 5, 9, 5, 12, 35, 70, 40,
 	20, 5, 0, 0, 0,
 	/* T18 Object */
@@ -1542,10 +1706,16 @@
 /* qseecom bus scaling */
 static struct msm_bus_vectors qseecom_clks_init_vectors[] = {
 	{
-		.src = MSM_BUS_MASTER_SPS,
+		.src = MSM_BUS_MASTER_ADM_PORT0,
 		.dst = MSM_BUS_SLAVE_EBI_CH0,
-		.ib = 0,
 		.ab = 0,
+		.ib = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_ADM_PORT1,
+		.dst = MSM_BUS_SLAVE_GSBI1_UART,
+		.ab = 0,
+		.ib = 0,
 	},
 	{
 		.src = MSM_BUS_MASTER_SPDM,
@@ -1557,10 +1727,16 @@
 
 static struct msm_bus_vectors qseecom_enable_dfab_vectors[] = {
 	{
-		.src = MSM_BUS_MASTER_SPS,
+		.src = MSM_BUS_MASTER_ADM_PORT0,
 		.dst = MSM_BUS_SLAVE_EBI_CH0,
-		.ib = (492 * 8) * 1000000UL,
-		.ab = (492 * 8) *  100000UL,
+		.ab = 70000000UL,
+		.ib = 70000000UL,
+	},
+	{
+		.src = MSM_BUS_MASTER_ADM_PORT1,
+		.dst = MSM_BUS_SLAVE_GSBI1_UART,
+		.ab = 2480000000UL,
+		.ib = 2480000000UL,
 	},
 	{
 		.src = MSM_BUS_MASTER_SPDM,
@@ -1572,10 +1748,16 @@
 
 static struct msm_bus_vectors qseecom_enable_sfpb_vectors[] = {
 	{
-		.src = MSM_BUS_MASTER_SPS,
+		.src = MSM_BUS_MASTER_ADM_PORT0,
 		.dst = MSM_BUS_SLAVE_EBI_CH0,
-		.ib = 0,
 		.ab = 0,
+		.ib = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_ADM_PORT1,
+		.dst = MSM_BUS_SLAVE_GSBI1_UART,
+		.ab = 0,
+		.ib = 0,
 	},
 	{
 		.src = MSM_BUS_MASTER_SPDM,
@@ -1592,7 +1774,7 @@
 	},
 	{
 		ARRAY_SIZE(qseecom_enable_dfab_vectors),
-		qseecom_enable_sfpb_vectors,
+		qseecom_enable_dfab_vectors,
 	},
 	{
 		ARRAY_SIZE(qseecom_enable_sfpb_vectors),
@@ -1796,6 +1978,26 @@
 						(void *)MSM_QGIC_CPU_BASE);
 }
 
+static struct msm_mhl_platform_data mhl_platform_data = {
+	.irq = MSM_GPIO_TO_INT(MHL_GPIO_INT),
+	.gpio_mhl_int = MHL_GPIO_INT,
+	.gpio_mhl_reset = MHL_GPIO_RESET,
+	.gpio_mhl_power = 0,
+	.gpio_hdmi_mhl_mux = 0,
+};
+
+static struct i2c_board_info sii_device_info[] __initdata = {
+	{
+		/*
+		 * keeps SI 8334 as the default
+		 * MHL TX
+		 */
+		I2C_BOARD_INFO("sii8334", 0x39),
+		.platform_data = &mhl_platform_data,
+		.flags = I2C_CLIENT_WAKE,
+	},
+};
+
 static struct platform_device msm8064_device_saw_regulator_core0 = {
 	.name	= "saw-regulator",
 	.id	= 0,
@@ -1838,6 +2040,13 @@
 	},
 
 	{
+		MSM_PM_SLEEP_MODE_RETENTION,
+		MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE),
+		true,
+		415, 715, 340827, 475,
+	},
+
+	{
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE,
 		MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE),
 		true,
@@ -1929,6 +2138,11 @@
 	0x24, 0x30, 0x0f,
 };
 
+static uint8_t spm_retention_cmd_sequence[] __initdata = {
+	0x00, 0x05, 0x03, 0x0D,
+	0x0B, 0x00, 0x0f,
+};
+
 static uint8_t spm_power_collapse_with_rpm[] __initdata = {
 	0x00, 0x24, 0x54, 0x10,
 	0x09, 0x07, 0x01, 0x0B,
@@ -1936,7 +2150,29 @@
 	0x24, 0x30, 0x0f,
 };
 
-static struct msm_spm_seq_entry msm_spm_seq_list[] __initdata = {
+static struct msm_spm_seq_entry msm_spm_boot_cpu_seq_list[] __initdata = {
+	[0] = {
+		.mode = MSM_SPM_MODE_CLOCK_GATING,
+		.notify_rpm = false,
+		.cmd = spm_wfi_cmd_sequence,
+	},
+	[1] = {
+		.mode = MSM_SPM_MODE_POWER_RETENTION,
+		.notify_rpm = false,
+		.cmd = spm_retention_cmd_sequence,
+	},
+	[2] = {
+		.mode = MSM_SPM_MODE_POWER_COLLAPSE,
+		.notify_rpm = false,
+		.cmd = spm_power_collapse_without_rpm,
+	},
+	[3] = {
+		.mode = MSM_SPM_MODE_POWER_COLLAPSE,
+		.notify_rpm = true,
+		.cmd = spm_power_collapse_with_rpm,
+	},
+};
+static struct msm_spm_seq_entry msm_spm_nonboot_cpu_seq_list[] __initdata = {
 	[0] = {
 		.mode = MSM_SPM_MODE_CLOCK_GATING,
 		.notify_rpm = false,
@@ -2012,12 +2248,12 @@
 		.reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x00,
 #endif
 		.reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01,
-		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020204,
-		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0060009C,
-		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x0000001C,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x03020004,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0084009C,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x00A4001C,
 		.vctl_timeout_us = 50,
-		.num_modes = ARRAY_SIZE(msm_spm_seq_list),
-		.modes = msm_spm_seq_list,
+		.num_modes = ARRAY_SIZE(msm_spm_boot_cpu_seq_list),
+		.modes = msm_spm_boot_cpu_seq_list,
 	},
 	[1] = {
 		.reg_base_addr = MSM_SAW1_BASE,
@@ -2031,8 +2267,8 @@
 		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0060009C,
 		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x0000001C,
 		.vctl_timeout_us = 50,
-		.num_modes = ARRAY_SIZE(msm_spm_seq_list),
-		.modes = msm_spm_seq_list,
+		.num_modes = ARRAY_SIZE(msm_spm_nonboot_cpu_seq_list),
+		.modes = msm_spm_nonboot_cpu_seq_list,
 	},
 	[2] = {
 		.reg_base_addr = MSM_SAW2_BASE,
@@ -2046,8 +2282,8 @@
 		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0060009C,
 		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x0000001C,
 		.vctl_timeout_us = 50,
-		.num_modes = ARRAY_SIZE(msm_spm_seq_list),
-		.modes = msm_spm_seq_list,
+		.num_modes = ARRAY_SIZE(msm_spm_nonboot_cpu_seq_list),
+		.modes = msm_spm_nonboot_cpu_seq_list,
 	},
 	[3] = {
 		.reg_base_addr = MSM_SAW3_BASE,
@@ -2061,8 +2297,8 @@
 		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0060009C,
 		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x0000001C,
 		.vctl_timeout_us = 50,
-		.num_modes = ARRAY_SIZE(msm_spm_seq_list),
-		.modes = msm_spm_seq_list,
+		.num_modes = ARRAY_SIZE(msm_spm_nonboot_cpu_seq_list),
+		.modes = msm_spm_nonboot_cpu_seq_list,
 	},
 };
 
@@ -2147,12 +2383,21 @@
 
 static struct platform_device apq8064_device_rpm_regulator __devinitdata = {
 	.name	= "rpm-regulator",
-	.id	= -1,
+	.id	= 0,
 	.dev	= {
 		.platform_data = &apq8064_rpm_regulator_pdata,
 	},
 };
 
+static struct platform_device
+apq8064_pm8921_device_rpm_regulator __devinitdata = {
+	.name	= "rpm-regulator",
+	.id	= 1,
+	.dev	= {
+		.platform_data = &apq8064_rpm_regulator_pm8921_pdata,
+	},
+};
+
 static struct gpio_ir_recv_platform_data gpio_ir_recv_pdata = {
 	.gpio_nr = 88,
 	.active_low = 1,
@@ -2171,16 +2416,41 @@
 	&apq8064_device_qup_i2c_gsbi4,
 };
 
-static struct platform_device *common_devices[] __initdata = {
+static struct platform_device *common_mpq_devices[] __initdata = {
+	&mpq_cpudai_sec_i2s_rx,
+	&mpq_cpudai_mi2s_tx,
+};
+
+static struct platform_device *common_i2s_devices[] __initdata = {
+	&apq_cpudai_mi2s,
+	&apq_cpudai_i2s_rx,
+	&apq_cpudai_i2s_tx,
+};
+
+static struct platform_device *early_common_devices[] __initdata = {
 	&apq8064_device_acpuclk,
 	&apq8064_device_dmov,
 	&apq8064_device_qup_spi_gsbi5,
+};
+
+static struct platform_device *pm8921_common_devices[] __initdata = {
 	&apq8064_device_ext_5v_vreg,
 	&apq8064_device_ext_mpp8_vreg,
 	&apq8064_device_ext_3p3v_vreg,
 	&apq8064_device_ssbi_pmic1,
 	&apq8064_device_ssbi_pmic2,
 	&apq8064_device_ext_ts_sw_vreg,
+};
+
+static struct platform_device *pm8917_common_devices[] __initdata = {
+	&apq8064_device_ext_mpp8_vreg,
+	&apq8064_device_ext_3p3v_vreg,
+	&apq8064_device_ssbi_pmic1,
+	&apq8064_device_ssbi_pmic2,
+	&apq8064_device_ext_ts_sw_vreg,
+};
+
+static struct platform_device *common_devices[] __initdata = {
 	&msm_device_smd_apq8064,
 	&apq8064_device_otg,
 	&apq8064_device_gadget_peripheral,
@@ -2228,8 +2498,6 @@
 	&apq_pcm_routing,
 	&apq_cpudai0,
 	&apq_cpudai1,
-	&mpq_cpudai_sec_i2s_rx,
-	&mpq_cpudai_mi2s_tx,
 	&apq_cpudai_hdmi_rx,
 	&apq_cpudai_bt_rx,
 	&apq_cpudai_bt_tx,
@@ -2242,6 +2510,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,
@@ -2292,6 +2561,10 @@
 	&apq8064_iommu_domain_device,
 	&msm_tsens_device,
 	&apq8064_cache_dump_device,
+	&msm_8064_device_tspp,
+#ifdef CONFIG_BATTERY_BCL
+	&battery_bcl_device,
+#endif
 };
 
 static struct platform_device *cdp_devices[] __initdata = {
@@ -2360,7 +2633,9 @@
 
 static int rf4ce_gpio_init(void)
 {
-	if (!machine_is_mpq8064_cdp())
+	if (!machine_is_mpq8064_cdp() &&
+		!machine_is_mpq8064_hrd() &&
+			!machine_is_mpq8064_dtv())
 		return -EINVAL;
 
 	/* CC2533 SRDY Input */
@@ -2385,6 +2660,40 @@
 }
 late_initcall(rf4ce_gpio_init);
 
+#ifdef CONFIG_SERIAL_MSM_HS
+static int configure_uart_gpios(int on)
+{
+	int ret = 0, i;
+	int uart_gpios[] = {14, 15, 16, 17};
+
+	for (i = 0; i < ARRAY_SIZE(uart_gpios); i++) {
+		if (on) {
+			ret = gpio_request(uart_gpios[i], NULL);
+			if (ret) {
+				pr_err("%s:unable to request uart gpio[%d]\n",
+						__func__, uart_gpios[i]);
+				break;
+			}
+		} else {
+			gpio_free(uart_gpios[i]);
+		}
+	}
+
+	if (ret && on && i)
+		for (; i >= 0; i--)
+			gpio_free(uart_gpios[i]);
+	return ret;
+}
+
+static struct msm_serial_hs_platform_data mpq8064_gsbi6_uartdm_pdata = {
+	.inject_rx_on_wakeup	= 1,
+	.rx_to_inject		= 0xFD,
+	.gpio_config		= configure_uart_gpios,
+};
+#else
+static struct msm_serial_hs_platform_data msm_uart_dm9_pdata;
+#endif
+
 static struct platform_device *mpq_devices[] __initdata = {
 	&msm_device_sps_apq8064,
 	&mpq8064_device_qup_i2c_gsbi5,
@@ -2504,14 +2813,16 @@
 }
 #endif
 
-#define GPIO_KEY_HOME		PM8921_GPIO_PM_TO_SYS(27)
-#define GPIO_KEY_VOLUME_UP	PM8921_GPIO_PM_TO_SYS(35)
-#define GPIO_KEY_VOLUME_DOWN	PM8921_GPIO_PM_TO_SYS(38)
-#define GPIO_KEY_CAM_FOCUS	PM8921_GPIO_PM_TO_SYS(3)
-#define GPIO_KEY_CAM_SNAP	PM8921_GPIO_PM_TO_SYS(4)
-#define GPIO_KEY_ROTATION	PM8921_GPIO_PM_TO_SYS(42)
+#define GPIO_KEY_HOME			PM8921_GPIO_PM_TO_SYS(27)
+#define GPIO_KEY_VOLUME_UP		PM8921_GPIO_PM_TO_SYS(35)
+#define GPIO_KEY_VOLUME_DOWN_PM8921	PM8921_GPIO_PM_TO_SYS(38)
+#define GPIO_KEY_VOLUME_DOWN_PM8917	PM8921_GPIO_PM_TO_SYS(30)
+#define GPIO_KEY_CAM_FOCUS		PM8921_GPIO_PM_TO_SYS(3)
+#define GPIO_KEY_CAM_SNAP		PM8921_GPIO_PM_TO_SYS(4)
+#define GPIO_KEY_ROTATION_PM8921	PM8921_GPIO_PM_TO_SYS(42)
+#define GPIO_KEY_ROTATION_PM8917	PM8921_GPIO_PM_TO_SYS(8)
 
-static struct gpio_keys_button cdp_keys[] = {
+static struct gpio_keys_button cdp_keys_pm8921[] = {
 	{
 		.code           = KEY_HOME,
 		.gpio           = GPIO_KEY_HOME,
@@ -2532,7 +2843,7 @@
 	},
 	{
 		.code           = KEY_VOLUMEDOWN,
-		.gpio           = GPIO_KEY_VOLUME_DOWN,
+		.gpio           = GPIO_KEY_VOLUME_DOWN_PM8921,
 		.desc           = "volume_down_key",
 		.active_low     = 1,
 		.type		= EV_KEY,
@@ -2541,7 +2852,45 @@
 	},
 	{
 		.code           = SW_ROTATE_LOCK,
-		.gpio           = GPIO_KEY_ROTATION,
+		.gpio           = GPIO_KEY_ROTATION_PM8921,
+		.desc           = "rotate_key",
+		.active_low     = 1,
+		.type		= EV_SW,
+		.debounce_interval = 15,
+	},
+};
+
+static struct gpio_keys_button cdp_keys_pm8917[] = {
+	{
+		.code           = KEY_HOME,
+		.gpio           = GPIO_KEY_HOME,
+		.desc           = "home_key",
+		.active_low     = 1,
+		.type		= EV_KEY,
+		.wakeup		= 1,
+		.debounce_interval = 15,
+	},
+	{
+		.code           = KEY_VOLUMEUP,
+		.gpio           = GPIO_KEY_VOLUME_UP,
+		.desc           = "volume_up_key",
+		.active_low     = 1,
+		.type		= EV_KEY,
+		.wakeup		= 1,
+		.debounce_interval = 15,
+	},
+	{
+		.code           = KEY_VOLUMEDOWN,
+		.gpio           = GPIO_KEY_VOLUME_DOWN_PM8917,
+		.desc           = "volume_down_key",
+		.active_low     = 1,
+		.type		= EV_KEY,
+		.wakeup		= 1,
+		.debounce_interval = 15,
+	},
+	{
+		.code           = SW_ROTATE_LOCK,
+		.gpio           = GPIO_KEY_ROTATION_PM8917,
 		.desc           = "rotate_key",
 		.active_low     = 1,
 		.type		= EV_SW,
@@ -2550,8 +2899,8 @@
 };
 
 static struct gpio_keys_platform_data cdp_keys_data = {
-	.buttons        = cdp_keys,
-	.nbuttons       = ARRAY_SIZE(cdp_keys),
+	.buttons        = cdp_keys_pm8921,
+	.nbuttons       = ARRAY_SIZE(cdp_keys_pm8921),
 };
 
 static struct platform_device cdp_kp_pdev = {
@@ -2583,7 +2932,7 @@
 	},
 	{
 		.code           = KEY_VOLUMEDOWN,
-		.gpio           = GPIO_KEY_VOLUME_DOWN,
+		.gpio           = GPIO_KEY_VOLUME_DOWN_PM8921,
 		.desc           = "volume_down_key",
 		.active_low     = 1,
 		.type		= EV_KEY,
@@ -2616,7 +2965,7 @@
 static struct gpio_keys_button mpq_keys[] = {
 	{
 		.code           = KEY_VOLUMEDOWN,
-		.gpio           = GPIO_KEY_VOLUME_DOWN,
+		.gpio           = GPIO_KEY_VOLUME_DOWN_PM8921,
 		.desc           = "volume_down_key",
 		.active_low     = 1,
 		.type		= EV_KEY,
@@ -2759,6 +3108,20 @@
 		cs8427_device_info,
 		ARRAY_SIZE(cs8427_device_info),
 	},
+	{
+		I2C_SURF | I2C_FFA | I2C_LIQUID,
+		APQ_8064_GSBI1_QUP_I2C_BUS_ID,
+		sii_device_info,
+		ARRAY_SIZE(sii_device_info),
+	}
+};
+
+static struct i2c_registry apq8064_tabla_i2c_devices[] __initdata = {
+	{
+		.bus = APQ_8064_GSBI1_QUP_I2C_BUS_ID,
+		.info = apq8064_tabla_i2c_device_info,
+		.len = ARRAY_SIZE(apq8064_tabla_i2c_device_info),
+	},
 };
 
 #define SX150X_EXP1_INT_N	PM8921_MPP_IRQ(PM8921_IRQ_BASE, 9)
@@ -2839,6 +3202,7 @@
 {
 	u8 mach_mask = 0;
 	int i;
+	u32 version;
 
 #ifdef CONFIG_MSM_CAMERA
 	struct i2c_registry apq8064_camera_i2c_devices = {
@@ -2881,6 +3245,18 @@
 					mpq8064_i2c_devices[i].info,
 					mpq8064_i2c_devices[i].len);
 	}
+
+	if (machine_is_apq8064_mtp()) {
+		version = socinfo_get_platform_version();
+		if (SOCINFO_VERSION_MINOR(version) == 1)
+			for (i = 0; i < ARRAY_SIZE(apq8064_tabla_i2c_devices);
+				 ++i)
+				i2c_register_board_info(
+				apq8064_tabla_i2c_devices[i].bus,
+				apq8064_tabla_i2c_devices[i].info,
+				apq8064_tabla_i2c_devices[i].len);
+	}
+
 }
 
 static void enable_ddr3_regulator(void)
@@ -2910,9 +3286,19 @@
 		gpio_set_value_cansleep(avc_i2c_en_mpp, 1);
 }
 
+/* Modify platform data values to match requirements for PM8917. */
+static void __init apq8064_pm8917_pdata_fixup(void)
+{
+	cdp_keys_data.buttons = cdp_keys_pm8917;
+	cdp_keys_data.nbuttons = ARRAY_SIZE(cdp_keys_pm8917);
+}
+
 static void __init apq8064_common_init(void)
 {
-	u32 platform_version;
+	u32 platform_version = socinfo_get_platform_version();
+
+	if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917)
+		apq8064_pm8917_pdata_fixup();
 	platform_device_register(&msm_gpio_device);
 	msm_tsens_early_init(&apq_tsens_pdata);
 	msm_thermal_init(&msm_thermal_pdata);
@@ -2921,7 +3307,11 @@
 	BUG_ON(msm_rpm_init(&apq8064_rpm_data));
 	BUG_ON(msm_rpmrs_levels_init(&msm_rpmrs_data));
 	regulator_suppress_info_printing();
+	if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917)
+		configure_apq8064_pm8917_power_grid();
 	platform_device_register(&apq8064_device_rpm_regulator);
+	if (socinfo_get_pmic_model() != PMIC_MODEL_PM8917)
+		platform_device_register(&apq8064_pm8921_device_rpm_regulator);
 	if (msm_xo_init())
 		pr_err("Failed to initialize XO votes\n");
 	msm_clock_init(&apq8064_clock_init_data);
@@ -2935,19 +3325,46 @@
 	if (machine_is_apq8064_liquid())
 		msm_otg_pdata.mhl_enable = true;
 
+	if (apq8064_mhl_display_enabled())
+		mhl_platform_data.mhl_enabled = true;
+
 	android_usb_pdata.swfi_latency =
 		msm_rpmrs_levels[0].latency_us;
 
 	apq8064_device_otg.dev.platform_data = &msm_otg_pdata;
 	apq8064_ehci_host_init();
 	apq8064_init_buses();
+
+	platform_add_devices(early_common_devices,
+				ARRAY_SIZE(early_common_devices));
+	if (socinfo_get_pmic_model() != PMIC_MODEL_PM8917)
+		platform_add_devices(pm8921_common_devices,
+					ARRAY_SIZE(pm8921_common_devices));
+	else
+		platform_add_devices(pm8917_common_devices,
+					ARRAY_SIZE(pm8917_common_devices));
 	platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
 	if (!(machine_is_mpq8064_cdp() || machine_is_mpq8064_hrd() ||
 			machine_is_mpq8064_dtv()))
 		platform_add_devices(common_not_mpq_devices,
 			ARRAY_SIZE(common_not_mpq_devices));
-	enable_ddr3_regulator();
+
+	if ((machine_is_mpq8064_cdp() || machine_is_mpq8064_hrd() ||
+			machine_is_mpq8064_dtv()))
+		platform_add_devices(common_mpq_devices,
+			ARRAY_SIZE(common_mpq_devices));
+
 	if (machine_is_apq8064_mtp()) {
+		if (SOCINFO_VERSION_MINOR(platform_version) == 1)
+			platform_add_devices(common_i2s_devices,
+			ARRAY_SIZE(common_i2s_devices));
+	}
+
+	enable_ddr3_regulator();
+	msm_hsic_pdata.swfi_latency =
+		msm_rpmrs_levels[0].latency_us;
+	if (machine_is_apq8064_mtp()) {
+		msm_hsic_pdata.log2_irq_thresh = 5,
 		apq8064_device_hsic_host.dev.platform_data = &msm_hsic_pdata;
 		device_initialize(&apq8064_device_hsic_host.dev);
 	}
@@ -2956,7 +3373,6 @@
 
 	if (machine_is_apq8064_mtp()) {
 		mdm_8064_device.dev.platform_data = &mdm_platform_data;
-		platform_version = socinfo_get_platform_version();
 		if (SOCINFO_VERSION_MINOR(platform_version) == 1) {
 			i2s_mdm_8064_device.dev.platform_data =
 				&mdm_platform_data;
@@ -2967,6 +3383,10 @@
 		}
 	}
 	platform_device_register(&apq8064_slim_ctrl);
+	if (machine_is_mpq8064_hrd() || machine_is_mpq8064_dtv()) {
+		apq8064_slim_devices[ARRAY_SIZE(apq8064_slim_devices) - 1].\
+			slim_slave = &mpq8064_slim_ashiko20;
+	}
 	slim_register_board_info(apq8064_slim_devices,
 		ARRAY_SIZE(apq8064_slim_devices));
 	if (!PLATFORM_IS_MPQ8064()) {
@@ -2977,6 +3397,7 @@
 	msm_spm_l2_init(msm_spm_l2_data);
 	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
 	apq8064_epm_adc_init();
+	msm_pm_set_tz_retention_flag(1);
 }
 
 static void __init apq8064_allocate_memory_regions(void)
@@ -3012,6 +3433,16 @@
 	apq8064_init_cam();
 #endif
 
+	if (machine_is_mpq8064_hrd() || machine_is_mpq8064_dtv()) {
+		platform_device_register(&mpq8064_device_uartdm_gsbi6);
+#ifdef CONFIG_SERIAL_MSM_HS
+		/* GSBI6(2) - UARTDM_RX */
+		mpq8064_gsbi6_uartdm_pdata.wakeup_irq = gpio_to_irq(15);
+		mpq8064_device_uartdm_gsbi6.dev.platform_data =
+					&mpq8064_gsbi6_uartdm_pdata;
+#endif
+	}
+
 	if (machine_is_apq8064_cdp() || machine_is_apq8064_liquid())
 		platform_device_register(&cdp_kp_pdev);
 
@@ -3097,4 +3528,3 @@
 	.init_very_early = apq8064_early_reserve,
 	.restart = msm_restart,
 MACHINE_END
-
diff --git a/arch/arm/mach-msm/board-8064.h b/arch/arm/mach-msm/board-8064.h
index 2258b8d..740fa39 100644
--- a/arch/arm/mach-msm/board-8064.h
+++ b/arch/arm/mach-msm/board-8064.h
@@ -40,6 +40,11 @@
 
 extern int msm8064_pm8921_regulator_pdata_len __devinitdata;
 
+extern struct pm8xxx_regulator_platform_data
+	msm8064_pm8917_regulator_pdata[] __devinitdata;
+
+extern int msm8064_pm8917_regulator_pdata_len __devinitdata;
+
 #define GPIO_VREG_ID_EXT_5V		0
 #define GPIO_VREG_ID_EXT_3P3V		1
 #define GPIO_VREG_ID_EXT_TS_SW		2
@@ -62,6 +67,9 @@
 extern struct rpm_regulator_platform_data
 	apq8064_rpm_regulator_pdata __devinitdata;
 
+extern struct rpm_regulator_platform_data
+	apq8064_rpm_regulator_pm8921_pdata __devinitdata;
+
 extern struct regulator_init_data msm8064_saw_regulator_pdata_8921_s5;
 extern struct regulator_init_data msm8064_saw_regulator_pdata_8921_s6;
 extern struct regulator_init_data msm8064_saw_regulator_pdata_8821_s0;
@@ -78,12 +86,20 @@
 extern struct msm_camera_board_info apq8064_camera_board_info;
 void apq8064_init_cam(void);
 
+
+/* Tabla slave address for I2C */
+#define APQ_8064_TABLA_I2C_SLAVE_ADDR		0x0d
+#define APQ_8064_TABLA_ANALOG_I2C_SLAVE_ADDR	0x77
+#define APQ_8064_TABLA_DIGITAL1_I2C_SLAVE_ADDR	0x66
+#define APQ_8064_TABLA_DIGITAL2_I2C_SLAVE_ADDR	0x55
+
 #define APQ_8064_GSBI1_QUP_I2C_BUS_ID 0
 #define APQ_8064_GSBI3_QUP_I2C_BUS_ID 3
 #define APQ_8064_GSBI4_QUP_I2C_BUS_ID 4
 #define APQ_8064_GSBI5_QUP_I2C_BUS_ID 5
 
 unsigned char apq8064_hdmi_as_primary_selected(void);
+unsigned char apq8064_mhl_display_enabled(void);
 void apq8064_init_fb(void);
 void apq8064_allocate_fb_region(void);
 void apq8064_mdp_writeback(struct memtype_reserve *reserve_table);
@@ -92,6 +108,7 @@
 
 void apq8064_init_gpu(void);
 void apq8064_pm8xxx_gpio_mpp_init(void);
+void __init configure_apq8064_pm8917_power_grid(void);
 
 #define PLATFORM_IS_MPQ8064() \
 	(machine_is_mpq8064_hrd() || \
diff --git a/arch/arm/mach-msm/board-8092-gpiomux.c b/arch/arm/mach-msm/board-8092-gpiomux.c
new file mode 100644
index 0000000..823ef70
--- /dev/null
+++ b/arch/arm/mach-msm/board-8092-gpiomux.c
@@ -0,0 +1,53 @@
+/* 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/ioport.h>
+#include <mach/board.h>
+#include <mach/gpio.h>
+#include <mach/gpiomux.h>
+
+static struct gpiomux_setting gpio_uart_config = {
+	.func = GPIOMUX_FUNC_2,
+	.drv = GPIOMUX_DRV_16MA,
+	.pull = GPIOMUX_PULL_NONE,
+	.dir = GPIOMUX_OUT_HIGH,
+};
+
+static struct msm_gpiomux_config msm_blsp_configs[] __initdata = {
+	{
+		.gpio      = 45,	       /* BLSP8 UART TX */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_uart_config,
+		},
+	},
+	{
+		.gpio      = 46,	       /* BLSP8 UART RX */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_uart_config,
+		},
+	},
+};
+
+void __init mpq8092_init_gpiomux(void)
+{
+	int rc;
+
+	rc = msm_gpiomux_init(NR_GPIO_IRQS);
+	if (rc) {
+		pr_err(KERN_ERR "mpq8092_init_gpiomux failed %d\n", rc);
+		return;
+	}
+
+	msm_gpiomux_install(msm_blsp_configs, ARRAY_SIZE(msm_blsp_configs));
+}
diff --git a/arch/arm/mach-msm/board-8092.c b/arch/arm/mach-msm/board-8092.c
new file mode 100644
index 0000000..0471ff4
--- /dev/null
+++ b/arch/arm/mach-msm/board-8092.c
@@ -0,0 +1,110 @@
+/* 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/errno.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/of_fdt.h>
+#include <linux/of_irq.h>
+#include <asm/hardware/gic.h>
+#include <asm/arch_timer.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <mach/socinfo.h>
+#include <mach/board.h>
+
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+
+#include "clock.h"
+
+static struct of_device_id irq_match[] __initdata  = {
+	{ .compatible = "qcom,msm-qgic2", .data = gic_of_init, },
+	{ .compatible = "qcom,msm-gpio", .data = msm_gpio_of_init, },
+	{}
+};
+
+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),
+};
+
+struct clock_init_data mpq8092_clock_init_data __initdata = {
+	.table = msm_clocks_dummy,
+	.size = ARRAY_SIZE(msm_clocks_dummy),
+};
+
+void __init mpq8092_init_irq(void)
+{
+	of_irq_init(irq_match);
+}
+
+static void __init mpq8092_dt_timer_init(void)
+{
+	arch_timer_of_register();
+}
+
+static struct sys_timer mpq8092_dt_timer = {
+	.init = mpq8092_dt_timer_init
+};
+
+static void __init mpq8092_dt_init_irq(void)
+{
+	mpq8092_init_irq();
+}
+
+static void __init mpq8092_dt_map_io(void)
+{
+	msm_map_mpq8092_io();
+	if (socinfo_init() < 0)
+		pr_err("%s: socinfo_init() failed\n", __func__);
+
+}
+
+static struct of_dev_auxdata mpq8092_auxdata_lookup[] __initdata = {
+	OF_DEV_AUXDATA("qcom,msm-lsuart-v14", 0xF991F000, \
+			"msm_serial_hsl.0", NULL),
+	{}
+};
+
+static void __init mpq8092_init(struct of_dev_auxdata **adata)
+{
+	mpq8092_init_gpiomux();
+	*adata = mpq8092_auxdata_lookup;
+	msm_clock_init(&mpq8092_clock_init_data);
+}
+
+static void __init mpq8092_dt_init(void)
+{
+	struct of_dev_auxdata *adata = NULL;
+
+	mpq8092_init(&adata);
+	of_platform_populate(NULL, of_default_bus_match_table, adata, NULL);
+}
+
+static const char *mpq8092_dt_match[] __initconst = {
+	"qcom,mpq8092-sim",
+	NULL
+};
+
+DT_MACHINE_START(MSM_DT, "Qualcomm MSM (Flattened Device Tree)")
+	.map_io = mpq8092_dt_map_io,
+	.init_irq = mpq8092_dt_init_irq,
+	.init_machine = mpq8092_dt_init,
+	.handle_irq = gic_handle_irq,
+	.timer = &mpq8092_dt_timer,
+	.dt_compat = mpq8092_dt_match,
+MACHINE_END
diff --git a/arch/arm/mach-msm/board-8930-camera.c b/arch/arm/mach-msm/board-8930-camera.c
index d3e37cd..883e04d 100644
--- a/arch/arm/mach-msm/board-8930-camera.c
+++ b/arch/arm/mach-msm/board-8930-camera.c
@@ -13,7 +13,7 @@
 
 #include <asm/mach-types.h>
 #include <linux/gpio.h>
-#include <mach/board.h>
+#include <mach/camera.h>
 #include <mach/msm_bus_board.h>
 #include <mach/gpiomux.h>
 #include "devices.h"
@@ -331,6 +331,28 @@
 	},
 };
 
+static struct msm_bus_vectors cam_dual_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 302071680,
+		.ib  = 1208286720,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 206807040,
+		.ib  = 488816640,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 540000000,
+		.ib  = 1350000000,
+	},
+};
+
+
 static struct msm_bus_paths cam_bus_client_config[] = {
 	{
 		ARRAY_SIZE(cam_init_vectors),
@@ -356,6 +378,10 @@
 		ARRAY_SIZE(cam_video_ls_vectors),
 		cam_video_ls_vectors,
 	},
+	{
+		ARRAY_SIZE(cam_dual_vectors),
+		cam_dual_vectors,
+	},
 };
 
 static struct msm_bus_scale_pdata cam_bus_client_pdata = {
@@ -377,19 +403,13 @@
 	},
 };
 
-static struct camera_vreg_t msm_8930_back_cam_vreg[] = {
+static struct camera_vreg_t msm_8930_cam_vreg[] = {
 	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
 	{"cam_vio", REG_VS, 0, 0, 0},
 	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
 	{"cam_vaf", REG_LDO, 2800000, 2850000, 300000},
 };
 
-static struct camera_vreg_t msm_8930_front_cam_vreg[] = {
-	{"cam_vio", REG_VS, 0, 0, 0},
-	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
-	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
-};
-
 static struct gpio msm8930_common_cam_gpio[] = {
 	{20, GPIOF_DIR_IN, "CAMIF_I2C_DATA"},
 	{21, GPIOF_DIR_IN, "CAMIF_I2C_CLK"},
@@ -466,8 +486,8 @@
 
 static struct msm_camera_sensor_platform_info sensor_board_info_imx074 = {
 	.mount_angle	= 90,
-	.cam_vreg = msm_8930_back_cam_vreg,
-	.num_vreg = ARRAY_SIZE(msm_8930_back_cam_vreg),
+	.cam_vreg = msm_8930_cam_vreg,
+	.num_vreg = ARRAY_SIZE(msm_8930_cam_vreg),
 	.gpio_conf = &msm_8930_back_cam_gpio_conf,
 	.csi_lane_params = &imx074_csi_lane_params,
 };
@@ -484,13 +504,6 @@
 	.actuator_info = &msm_act_main_cam_0_info,
 };
 
-static struct camera_vreg_t msm_8930_mt9m114_vreg[] = {
-	{"cam_vio", REG_VS, 0, 0, 0},
-	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
-	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
-	{"cam_vaf", REG_LDO, 2800000, 2850000, 300000},
-};
-
 static struct msm_camera_sensor_flash_data flash_mt9m114 = {
 	.flash_type = MSM_CAMERA_FLASH_NONE
 };
@@ -502,8 +515,8 @@
 
 static struct msm_camera_sensor_platform_info sensor_board_info_mt9m114 = {
 	.mount_angle = 90,
-	.cam_vreg = msm_8930_mt9m114_vreg,
-	.num_vreg = ARRAY_SIZE(msm_8930_mt9m114_vreg),
+	.cam_vreg = msm_8930_cam_vreg,
+	.num_vreg = ARRAY_SIZE(msm_8930_cam_vreg),
 	.gpio_conf = &msm_8930_front_cam_gpio_conf,
 	.csi_lane_params = &mt9m114_csi_lane_params,
 };
@@ -529,8 +542,8 @@
 
 static struct msm_camera_sensor_platform_info sensor_board_info_ov2720 = {
 	.mount_angle	= 0,
-	.cam_vreg = msm_8930_front_cam_vreg,
-	.num_vreg = ARRAY_SIZE(msm_8930_front_cam_vreg),
+	.cam_vreg = msm_8930_cam_vreg,
+	.num_vreg = ARRAY_SIZE(msm_8930_cam_vreg),
 	.gpio_conf = &msm_8930_front_cam_gpio_conf,
 	.csi_lane_params = &ov2720_csi_lane_params,
 };
@@ -545,13 +558,6 @@
 	.sensor_type = BAYER_SENSOR,
 };
 
-static struct camera_vreg_t msm_8930_s5k3l1yx_vreg[] = {
-	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
-	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
-	{"cam_vio", REG_VS, 0, 0, 0},
-	{"cam_vaf", REG_LDO, 2800000, 2850000, 300000},
-};
-
 static struct msm_camera_sensor_flash_data flash_s5k3l1yx = {
 	.flash_type = MSM_CAMERA_FLASH_LED,
 	.flash_src = &msm_flash_src
@@ -564,8 +570,8 @@
 
 static struct msm_camera_sensor_platform_info sensor_board_info_s5k3l1yx = {
 	.mount_angle  = 90,
-	.cam_vreg = msm_8930_s5k3l1yx_vreg,
-	.num_vreg = ARRAY_SIZE(msm_8930_s5k3l1yx_vreg),
+	.cam_vreg = msm_8930_cam_vreg,
+	.num_vreg = ARRAY_SIZE(msm_8930_cam_vreg),
 	.gpio_conf = &msm_8930_back_cam_gpio_conf,
 	.csi_lane_params = &s5k3l1yx_csi_lane_params,
 };
diff --git a/arch/arm/mach-msm/board-8930-display.c b/arch/arm/mach-msm/board-8930-display.c
index d975997..b454184 100644
--- a/arch/arm/mach-msm/board-8930-display.c
+++ b/arch/arm/mach-msm/board-8930-display.c
@@ -59,8 +59,16 @@
 #define MIPI_VIDEO_SIMULATOR_VGA_PANEL_NAME	"mipi_video_simulator_vga"
 #define MIPI_CMD_RENESAS_FWVGA_PANEL_NAME	"mipi_cmd_renesas_fwvga"
 #define HDMI_PANEL_NAME	"hdmi_msm"
+#define MHL_PANEL_NAME "hdmi_msm,mhl_8334"
 #define TVOUT_PANEL_NAME	"tvout_msm"
 
+static unsigned char mhl_display_enabled;
+
+unsigned char msm8930_mhl_display_enabled(void)
+{
+	return mhl_display_enabled;
+}
+
 static struct resource msm_fb_resources[] = {
 	{
 		.flags = IORESOURCE_DMA,
@@ -135,6 +143,8 @@
 static int mipi_dsi_cdp_panel_power(int on)
 {
 	static struct regulator *reg_l8, *reg_l23, *reg_l2;
+	/* Control backlight GPIO (24) directly when using PM8917 */
+	int gpio24 = PM8917_GPIO_PM_TO_SYS(24);
 	int rc;
 
 	pr_debug("%s: state : %d\n", __func__, on);
@@ -190,13 +200,21 @@
 				 rc);
 			gpio_free(DISP_3D_2D_MODE);
 			return -ENODEV;
-			}
+		}
 		rc = gpio_direction_output(DISP_3D_2D_MODE, 0);
 		if (rc) {
 			pr_err("gpio_direction_output failed for %d gpio rc=%d\n",
 			DISP_3D_2D_MODE, rc);
 			return -ENODEV;
+		}
+		if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917) {
+			rc = gpio_request(gpio24, "disp_bl");
+			if (rc) {
+				pr_err("request for gpio 24 failed, rc=%d\n",
+					rc);
+				return -ENODEV;
 			}
+		}
 		dsi_power_on = true;
 	}
 	if (on) {
@@ -238,6 +256,8 @@
 		gpio_set_value(DISP_RST_GPIO, 1);
 		gpio_set_value(DISP_3D_2D_MODE, 1);
 		usleep(20);
+		if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917)
+			gpio_set_value_cansleep(gpio24, 1);
 	} else {
 
 		gpio_set_value(DISP_RST_GPIO, 0);
@@ -274,6 +294,8 @@
 		}
 		gpio_set_value(DISP_3D_2D_MODE, 0);
 		usleep(20);
+		if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917)
+			gpio_set_value_cansleep(gpio24, 0);
 	}
 	return 0;
 }
@@ -413,31 +435,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
@@ -841,3 +841,28 @@
 	pr_info("allocating %lu bytes at %p (%lx physical) for fb\n",
 			size, addr, __pa(addr));
 }
+
+void __init msm8930_set_display_params(char *prim_panel, char *ext_panel)
+{
+	if (strnlen(prim_panel, PANEL_NAME_MAX_LEN)) {
+		strlcpy(msm_fb_pdata.prim_panel_name, prim_panel,
+			PANEL_NAME_MAX_LEN);
+		pr_debug("msm_fb_pdata.prim_panel_name %s\n",
+			msm_fb_pdata.prim_panel_name);
+	}
+	if (strnlen(ext_panel, PANEL_NAME_MAX_LEN)) {
+		strlcpy(msm_fb_pdata.ext_panel_name, ext_panel,
+			PANEL_NAME_MAX_LEN);
+		pr_debug("msm_fb_pdata.ext_panel_name %s\n",
+			msm_fb_pdata.ext_panel_name);
+
+		if (!strncmp((char *)msm_fb_pdata.ext_panel_name,
+			MHL_PANEL_NAME, strnlen(MHL_PANEL_NAME,
+				PANEL_NAME_MAX_LEN))) {
+			pr_debug("MHL is external display by boot parameter\n");
+			mhl_display_enabled = 1;
+		}
+	}
+
+	hdmi_msm_data.is_mhl_enabled = mhl_display_enabled;
+}
diff --git a/arch/arm/mach-msm/board-8930-gpiomux.c b/arch/arm/mach-msm/board-8930-gpiomux.c
index e0f012a..fcb5abd 100644
--- a/arch/arm/mach-msm/board-8930-gpiomux.c
+++ b/arch/arm/mach-msm/board-8930-gpiomux.c
@@ -45,14 +45,14 @@
 
 static struct gpiomux_setting gsbi5 = {
 	.func = GPIOMUX_FUNC_1,
-	.drv = GPIOMUX_DRV_8MA,
-	.pull = GPIOMUX_PULL_NONE,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
 };
 
 static struct gpiomux_setting gsbi9 = {
 	.func = GPIOMUX_FUNC_2,
-	.drv = GPIOMUX_DRV_8MA,
-	.pull = GPIOMUX_PULL_NONE,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
 };
 
 static struct gpiomux_setting gsbi10 = {
@@ -96,14 +96,20 @@
 
 static struct gpiomux_setting audio_spkr_boost = {
 	.func = GPIOMUX_FUNC_GPIO,
-	.drv = GPIOMUX_DRV_8MA,
-	.pull = GPIOMUX_PULL_NONE,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
 };
 
 #if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
-static struct gpiomux_setting gpio_eth_config = {
+static struct gpiomux_setting gpio_eth_suspend_1_cfg = {
+	.pull = GPIOMUX_PULL_DOWN,
+	.drv = GPIOMUX_DRV_2MA,
+	.func = GPIOMUX_FUNC_GPIO,
+};
+
+static struct gpiomux_setting gpio_eth_suspend_2_cfg = {
 	.pull = GPIOMUX_PULL_NONE,
-	.drv = GPIOMUX_DRV_8MA,
+	.drv = GPIOMUX_DRV_2MA,
 	.func = GPIOMUX_FUNC_GPIO,
 };
 #endif
@@ -274,18 +280,25 @@
 
 #endif
 
+static struct gpiomux_setting sitar_reset = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_NONE,
+	.dir = GPIOMUX_OUT_LOW,
+};
+
 #if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
 static struct msm_gpiomux_config msm8960_ethernet_configs[] = {
 	{
-		.gpio = 90,
+		.gpio = 89,
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_eth_config,
+			[GPIOMUX_SUSPENDED] = &gpio_eth_suspend_1_cfg,
 		}
 	},
 	{
-		.gpio = 89,
+		.gpio = 90,
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_eth_config,
+			[GPIOMUX_SUSPENDED] = &gpio_eth_suspend_2_cfg,
 		}
 	},
 };
@@ -688,6 +701,31 @@
 	},
 };
 
+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,
+		},
+	},
+};
+
+static struct msm_gpiomux_config msm_sitar_config[] __initdata = {
+	{
+		.gpio   = 42,           /* SYS_RST_N */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &sitar_reset,
+		},
+	}
+};
+
 int __init msm8930_init_gpiomux(void)
 {
 	int rc = msm_gpiomux_init(NR_GPIO_IRQS);
@@ -747,7 +785,7 @@
 #ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
 	msm_gpiomux_install(msm8960_hdmi_configs,
 			ARRAY_SIZE(msm8960_hdmi_configs));
-	if (machine_is_msm8930_fluid())
+	if (msm8930_mhl_display_enabled())
 		msm_gpiomux_install(msm8930_mhl_configs,
 				ARRAY_SIZE(msm8930_mhl_configs));
 #endif
@@ -758,5 +796,11 @@
 	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));
+
+	msm_gpiomux_install(msm_sitar_config, ARRAY_SIZE(msm_sitar_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..cc5651d 100644
--- a/arch/arm/mach-msm/board-8930-pmic.c
+++ b/arch/arm/mach-msm/board-8930-pmic.c
@@ -18,6 +18,7 @@
 #include <asm/mach-types.h>
 #include <mach/msm_bus_board.h>
 #include <mach/restart.h>
+#include <mach/socinfo.h>
 #include "devices.h"
 #include "board-8930.h"
 
@@ -31,7 +32,7 @@
 	struct pm8xxx_mpp_config_data	config;
 };
 
-#define PM8XXX_GPIO_INIT(_gpio, _dir, _buf, _val, _pull, _vin, _out_strength, \
+#define PM8038_GPIO_INIT(_gpio, _dir, _buf, _val, _pull, _vin, _out_strength, \
 			_func, _inv, _disable) \
 { \
 	.gpio	= PM8038_GPIO_PM_TO_SYS(_gpio), \
@@ -48,7 +49,7 @@
 	} \
 }
 
-#define PM8XXX_MPP_INIT(_mpp, _type, _level, _control) \
+#define PM8038_MPP_INIT(_mpp, _type, _level, _control) \
 { \
 	.mpp	= PM8038_MPP_PM_TO_SYS(_mpp), \
 	.config	= { \
@@ -58,49 +59,128 @@
 	} \
 }
 
-#define PM8XXX_GPIO_DISABLE(_gpio) \
-	PM8XXX_GPIO_INIT(_gpio, PM_GPIO_DIR_IN, 0, 0, 0, PM8038_GPIO_VIN_L11, \
+#define PM8038_GPIO_DISABLE(_gpio) \
+	PM8038_GPIO_INIT(_gpio, PM_GPIO_DIR_IN, 0, 0, 0, PM8038_GPIO_VIN_L11, \
 			 0, 0, 0, 1)
 
-#define PM8XXX_GPIO_OUTPUT(_gpio, _val) \
-	PM8XXX_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+#define PM8038_GPIO_OUTPUT(_gpio, _val) \
+	PM8038_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
 			PM_GPIO_PULL_NO, PM8038_GPIO_VIN_L11, \
 			PM_GPIO_STRENGTH_HIGH, \
 			PM_GPIO_FUNC_NORMAL, 0, 0)
 
-#define PM8XXX_GPIO_INPUT(_gpio, _pull) \
-	PM8XXX_GPIO_INIT(_gpio, PM_GPIO_DIR_IN, PM_GPIO_OUT_BUF_CMOS, 0, \
+#define PM8038_GPIO_INPUT(_gpio, _pull) \
+	PM8038_GPIO_INIT(_gpio, PM_GPIO_DIR_IN, PM_GPIO_OUT_BUF_CMOS, 0, \
 			_pull, PM8038_GPIO_VIN_L11, \
 			PM_GPIO_STRENGTH_NO, \
 			PM_GPIO_FUNC_NORMAL, 0, 0)
 
-#define PM8XXX_GPIO_OUTPUT_FUNC(_gpio, _val, _func) \
-	PM8XXX_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+#define PM8038_GPIO_OUTPUT_FUNC(_gpio, _val, _func) \
+	PM8038_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
 			PM_GPIO_PULL_NO, PM8038_GPIO_VIN_L11, \
 			PM_GPIO_STRENGTH_HIGH, \
 			_func, 0, 0)
 
-#define PM8XXX_GPIO_OUTPUT_VIN(_gpio, _val, _vin) \
-	PM8XXX_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+#define PM8038_GPIO_OUTPUT_VIN(_gpio, _val, _vin) \
+	PM8038_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
 			PM_GPIO_PULL_NO, _vin, \
 			PM_GPIO_STRENGTH_HIGH, \
 			PM_GPIO_FUNC_NORMAL, 0, 0)
 
-/* Initial pm8038 GPIO configurations */
+#define PM8917_GPIO_INIT(_gpio, _dir, _buf, _val, _pull, _vin, _out_strength, \
+			_func, _inv, _disable) \
+{ \
+	.gpio	= PM8917_GPIO_PM_TO_SYS(_gpio), \
+	.config	= { \
+		.direction	= _dir, \
+		.output_buffer	= _buf, \
+		.output_value	= _val, \
+		.pull		= _pull, \
+		.vin_sel	= _vin, \
+		.out_strength	= _out_strength, \
+		.function	= _func, \
+		.inv_int_pol	= _inv, \
+		.disable_pin	= _disable, \
+	} \
+}
+
+#define PM8917_MPP_INIT(_mpp, _type, _level, _control) \
+{ \
+	.mpp	= PM8917_MPP_PM_TO_SYS(_mpp), \
+	.config	= { \
+		.type		= PM8XXX_MPP_TYPE_##_type, \
+		.level		= _level, \
+		.control	= PM8XXX_MPP_##_control, \
+	} \
+}
+
+#define PM8917_GPIO_DISABLE(_gpio) \
+	PM8917_GPIO_INIT(_gpio, PM_GPIO_DIR_IN, 0, 0, 0, PM_GPIO_VIN_S4, \
+			 0, 0, 0, 1)
+
+#define PM8917_GPIO_OUTPUT(_gpio, _val) \
+	PM8917_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+			PM_GPIO_PULL_NO, PM_GPIO_VIN_S4, \
+			PM_GPIO_STRENGTH_HIGH, \
+			PM_GPIO_FUNC_NORMAL, 0, 0)
+
+#define PM8917_GPIO_INPUT(_gpio, _pull) \
+	PM8917_GPIO_INIT(_gpio, PM_GPIO_DIR_IN, PM_GPIO_OUT_BUF_CMOS, 0, \
+			_pull, PM_GPIO_VIN_S4, \
+			PM_GPIO_STRENGTH_NO, \
+			PM_GPIO_FUNC_NORMAL, 0, 0)
+
+#define PM8917_GPIO_OUTPUT_FUNC(_gpio, _val, _func) \
+	PM8917_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+			PM_GPIO_PULL_NO, PM_GPIO_VIN_S4, \
+			PM_GPIO_STRENGTH_HIGH, \
+			_func, 0, 0)
+
+#define PM8917_GPIO_OUTPUT_VIN(_gpio, _val, _vin) \
+	PM8917_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+			PM_GPIO_PULL_NO, _vin, \
+			PM_GPIO_STRENGTH_HIGH, \
+			PM_GPIO_FUNC_NORMAL, 0, 0)
+
+/* GPIO and MPP configurations for MSM8930 + PM8038 targets */
+
+/* Initial PM8038 GPIO configurations */
 static struct pm8xxx_gpio_init pm8038_gpios[] __initdata = {
 	/* keys GPIOs */
-	PM8XXX_GPIO_INPUT(3, PM_GPIO_PULL_UP_30),
-	PM8XXX_GPIO_INPUT(8, PM_GPIO_PULL_UP_30),
-	PM8XXX_GPIO_INPUT(10, PM_GPIO_PULL_UP_30),
-	PM8XXX_GPIO_INPUT(11, PM_GPIO_PULL_UP_30),
+	PM8038_GPIO_INPUT(3, PM_GPIO_PULL_UP_30),
+	PM8038_GPIO_INPUT(8, PM_GPIO_PULL_UP_30),
+	PM8038_GPIO_INPUT(10, PM_GPIO_PULL_UP_30),
+	PM8038_GPIO_INPUT(11, PM_GPIO_PULL_UP_30),
 	/* haptics gpio */
-	PM8XXX_GPIO_OUTPUT_FUNC(7, 0, PM_GPIO_FUNC_1),
+	PM8038_GPIO_OUTPUT_FUNC(7, 0, PM_GPIO_FUNC_1),
 	/* MHL PWR EN */
-	PM8XXX_GPIO_OUTPUT_VIN(5, 1, PM_GPIO_VIN_VPH),
+	PM8038_GPIO_OUTPUT_VIN(5, 1, PM8038_GPIO_VIN_VPH),
 };
 
-/* Initial pm8038 MPP configurations */
-static struct pm8xxx_mpp_init pm8038_mpps[] __initdata = {};
+/* Initial PM8038 MPP configurations */
+static struct pm8xxx_mpp_init pm8038_mpps[] __initdata = {
+};
+
+/* GPIO and MPP configurations for MSM8930 + PM8917 targets */
+
+/* Initial PM8917 GPIO configurations */
+static struct pm8xxx_gpio_init pm8917_gpios[] __initdata = {
+	/* Backlight enable control */
+	PM8917_GPIO_OUTPUT(24, 1),
+	/* keys GPIOs */
+	PM8917_GPIO_INPUT(27, PM_GPIO_PULL_UP_30),
+	PM8917_GPIO_INPUT(28, PM_GPIO_PULL_UP_30),
+	PM8917_GPIO_INPUT(36, PM_GPIO_PULL_UP_30),
+	PM8917_GPIO_INPUT(37, PM_GPIO_PULL_UP_30),
+	/* haptics gpio */
+	PM8917_GPIO_OUTPUT_FUNC(38, 0, PM_GPIO_FUNC_2),
+	/* MHL PWR EN */
+	PM8917_GPIO_OUTPUT_VIN(25, 1, PM_GPIO_VIN_VPH),
+};
+
+/* Initial PM8917 MPP configurations */
+static struct pm8xxx_mpp_init pm8917_mpps[] __initdata = {
+};
 
 void __init msm8930_pm8038_gpio_mpp_init(void)
 {
@@ -126,7 +206,31 @@
 	}
 }
 
-static struct pm8xxx_adc_amux pm8xxx_adc_channels_data[] = {
+void __init msm8930_pm8917_gpio_mpp_init(void)
+{
+	int i, rc;
+
+	for (i = 0; i < ARRAY_SIZE(pm8917_gpios); i++) {
+		rc = pm8xxx_gpio_config(pm8917_gpios[i].gpio,
+					&pm8917_gpios[i].config);
+		if (rc) {
+			pr_err("%s: pm8xxx_gpio_config: rc=%d\n", __func__, rc);
+			break;
+		}
+	}
+
+	/* Initial MPP configuration. */
+	for (i = 0; i < ARRAY_SIZE(pm8917_mpps); i++) {
+		rc = pm8xxx_mpp_config(pm8917_mpps[i].mpp,
+					&pm8917_mpps[i].config);
+		if (rc) {
+			pr_err("%s: pm8xxx_mpp_config: rc=%d\n", __func__, rc);
+			break;
+		}
+	}
+}
+
+static struct pm8xxx_adc_amux pm8038_adc_channels_data[] = {
 	{"vcoin", CHANNEL_VCOIN, CHAN_PATH_SCALING2, AMUX_RSV1,
 		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
 	{"vbat", CHANNEL_VBAT, CHAN_PATH_SCALING2, AMUX_RSV1,
@@ -161,16 +265,16 @@
 		ADC_DECIMATION_TYPE2, ADC_SCALE_PA_THERM},
 };
 
-static struct pm8xxx_adc_properties pm8xxx_adc_data = {
+static struct pm8xxx_adc_properties pm8038_adc_data = {
 	.adc_vdd_reference	= 1800, /* milli-voltage for this adc */
 	.bitresolution		= 15,
 	.bipolar                = 0,
 };
 
-static struct pm8xxx_adc_platform_data pm8xxx_adc_pdata = {
-	.adc_channel            = pm8xxx_adc_channels_data,
-	.adc_num_board_channel  = ARRAY_SIZE(pm8xxx_adc_channels_data),
-	.adc_prop               = &pm8xxx_adc_data,
+static struct pm8xxx_adc_platform_data pm8038_adc_pdata = {
+	.adc_channel            = pm8038_adc_channels_data,
+	.adc_num_board_channel  = ARRAY_SIZE(pm8038_adc_channels_data),
+	.adc_prop               = &pm8038_adc_data,
 	.adc_mpp_base		= PM8038_MPP_PM_TO_SYS(1),
 };
 
@@ -207,6 +311,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 +319,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,
@@ -226,6 +331,7 @@
 	.thermal_mitigation	= pm8921_therm_mitigation,
 	.thermal_levels		= ARRAY_SIZE(pm8921_therm_mitigation),
 	.led_src_config		= LED_SRC_VPH_PWR,
+	.rconn_mohm		= 18,
 };
 
 #define PM8038_WLED_MAX_CURRENT		25
@@ -335,16 +441,33 @@
 	.priority		= 0,
 };
 
+/*
+ *	0x254=0xC8 (Threshold=110, preamp bias=01)
+ *	0x255=0xC1 (Hold=110, max attn=0000, mute=1)
+ *	0x256=0xB0 (decay=101, attack=10, delay=0)
+ */
+
 static struct pm8xxx_spk_platform_data pm8xxx_spk_pdata = {
 	.spk_add_enable		= false,
+	.cd_ng_threshold	= 0x6,
+	.cd_nf_preamp_bias	= 0x1,
+	.cd_ng_hold		= 0x6,
+	.cd_ng_max_atten	= 0x0,
+	.noise_mute		= 1,
+	.cd_ng_decay_rate	= 0x5,
+	.cd_ng_attack_rate	= 0x2,
+	.cd_delay		= 0x0,
 };
 
 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,
+	.rconn_mohm			= 18,
 };
 
 static struct pm8038_platform_data pm8038_platform_data __devinitdata = {
@@ -357,7 +480,7 @@
 	.regulator_pdatas	= msm8930_pm8038_regulator_pdata,
 	.charger_pdata		= &pm8921_chg_pdata,
 	.bms_pdata		= &pm8921_bms_pdata,
-	.adc_pdata		= &pm8xxx_adc_pdata,
+	.adc_pdata		= &pm8038_adc_pdata,
 	.leds_pdata		= &pm8xxx_leds_pdata,
 	.ccadc_pdata		= &pm8xxx_ccadc_pdata,
 	.spk_pdata		= &pm8xxx_spk_pdata,
@@ -371,15 +494,99 @@
 	},
 };
 
+/* PM8917 platform data */
+
+static struct pm8xxx_adc_amux pm8917_adc_channels_data[] = {
+	{"vcoin", CHANNEL_VCOIN, CHAN_PATH_SCALING2, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"vbat", CHANNEL_VBAT, CHAN_PATH_SCALING2, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"dcin", CHANNEL_DCIN, CHAN_PATH_SCALING4, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"ichg", CHANNEL_ICHG, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"vph_pwr", CHANNEL_VPH_PWR, CHAN_PATH_SCALING2, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"ibat", CHANNEL_IBAT, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"batt_therm", CHANNEL_BATT_THERM, CHAN_PATH_SCALING1, AMUX_RSV2,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_BATT_THERM},
+	{"batt_id", CHANNEL_BATT_ID, CHAN_PATH_SCALING1, AMUX_RSV2,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"usbin", CHANNEL_USBIN, CHAN_PATH_SCALING3, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"pmic_therm", CHANNEL_DIE_TEMP, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_PMIC_THERM},
+	{"625mv", CHANNEL_625MV, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"125v", CHANNEL_125V, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"chg_temp", CHANNEL_CHG_TEMP, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"xo_therm", CHANNEL_MUXOFF, CHAN_PATH_SCALING1, AMUX_RSV0,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_XOTHERM},
+	{"pa_therm0", ADC_MPP_1_AMUX3, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_PA_THERM},
+};
+
+static struct pm8xxx_adc_properties pm8917_adc_data = {
+	.adc_vdd_reference	= 1800, /* milli-voltage for this adc */
+	.bitresolution		= 15,
+	.bipolar                = 0,
+};
+
+static struct pm8xxx_adc_platform_data pm8917_adc_pdata = {
+	.adc_channel            = pm8917_adc_channels_data,
+	.adc_num_board_channel  = ARRAY_SIZE(pm8917_adc_channels_data),
+	.adc_prop               = &pm8917_adc_data,
+	.adc_mpp_base		= PM8917_MPP_PM_TO_SYS(1),
+};
+
+static struct pm8921_platform_data pm8917_platform_data __devinitdata = {
+	.irq_pdata		= &pm8xxx_irq_pdata,
+	.gpio_pdata		= &pm8xxx_gpio_pdata,
+	.mpp_pdata		= &pm8xxx_mpp_pdata,
+	.rtc_pdata              = &pm8xxx_rtc_pdata,
+	.pwrkey_pdata		= &pm8xxx_pwrkey_pdata,
+	.misc_pdata		= &pm8xxx_misc_pdata,
+	.regulator_pdatas	= msm8930_pm8917_regulator_pdata,
+	.charger_pdata		= &pm8921_chg_pdata,
+	.bms_pdata		= &pm8921_bms_pdata,
+	.adc_pdata		= &pm8917_adc_pdata,
+	.ccadc_pdata		= &pm8xxx_ccadc_pdata,
+};
+
+static struct msm_ssbi_platform_data msm8930_ssbi_pm8917_pdata __devinitdata = {
+	.controller_type = MSM_SBI_CTRL_PMIC_ARBITER,
+	.slave	= {
+		.name			= "pm8921-core",
+		.platform_data		= &pm8917_platform_data,
+	},
+};
+
 void __init msm8930_init_pmic(void)
 {
-	pmic_reset_irq = PM8038_IRQ_BASE + PM8038_RESOUT_IRQ;
-	msm8960_device_ssbi_pmic.dev.platform_data =
-				&msm8930_ssbi_pm8038_pdata;
-	pm8038_platform_data.num_regulators
-		= msm8930_pm8038_regulator_pdata_len;
-	if (machine_is_apq8064_mtp())
-		pm8921_bms_pdata.battery_type = BATT_PALLADIUM;
-	else if (machine_is_apq8064_liquid())
-		pm8921_bms_pdata.battery_type = BATT_DESAY;
+	if (socinfo_get_pmic_model() != PMIC_MODEL_PM8917) {
+		/* PM8038 configuration */
+		pmic_reset_irq = PM8038_IRQ_BASE + PM8038_RESOUT_IRQ;
+		msm8960_device_ssbi_pmic.dev.platform_data =
+					&msm8930_ssbi_pm8038_pdata;
+		pm8038_platform_data.num_regulators
+			= msm8930_pm8038_regulator_pdata_len;
+		if (machine_is_msm8930_mtp())
+			pm8921_bms_pdata.battery_type = BATT_PALLADIUM;
+		else if (machine_is_msm8930_cdp())
+			pm8921_chg_pdata.has_dc_supply = true;
+	} else {
+		/* PM8917 configuration */
+		pmic_reset_irq = PM8917_IRQ_BASE + PM8921_RESOUT_IRQ;
+		msm8960_device_ssbi_pmic.dev.platform_data =
+					&msm8930_ssbi_pm8917_pdata;
+		pm8917_platform_data.num_regulators
+			= msm8930_pm8917_regulator_pdata_len;
+		if (machine_is_msm8930_mtp())
+			pm8921_bms_pdata.battery_type = BATT_PALLADIUM;
+		else if (machine_is_msm8930_cdp())
+			pm8921_chg_pdata.has_dc_supply = true;
+	}
 }
diff --git a/arch/arm/mach-msm/board-8930-regulator.c b/arch/arm/mach-msm/board-8930-regulator-pm8038.c
similarity index 96%
rename from arch/arm/mach-msm/board-8930-regulator.c
rename to arch/arm/mach-msm/board-8930-regulator-pm8038.c
index d3a4960..ed9d802 100644
--- a/arch/arm/mach-msm/board-8930-regulator.c
+++ b/arch/arm/mach-msm/board-8930-regulator-pm8038.c
@@ -11,6 +11,11 @@
  * GNU General Public License for more details.
  */
 
+/*
+ * This file contains regulator configuration and mappings for targets
+ * consisting of MSM8930 and PM8038.
+ */
+
 #include <linux/regulator/pm8xxx-regulator.h>
 
 #include "board-8930.h"
@@ -99,6 +104,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 +156,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),
 };
@@ -443,17 +454,17 @@
 
 /* GPIO regulator constraints */
 struct gpio_regulator_platform_data
-msm8930_gpio_regulator_pdata[] __devinitdata = {
+msm8930_pm8038_gpio_regulator_pdata[] __devinitdata = {
 	/*        ID          vreg_name     gpio_label     gpio  supply */
 	GPIO_VREG(EXT_5V,     "ext_5v",     "ext_5v_en",     63, NULL),
 	GPIO_VREG(EXT_OTG_SW, "ext_otg_sw", "ext_otg_sw_en", 97, "ext_5v"),
 };
 
 /* SAW regulator constraints */
-struct regulator_init_data msm8930_saw_regulator_core0_pdata =
+struct regulator_init_data msm8930_pm8038_saw_regulator_core0_pdata =
 	/*	      ID  vreg_name	       min_uV   max_uV */
 	SAW_VREG_INIT(S5, "8038_s5",	       850000, 1300000);
-struct regulator_init_data msm8930_saw_regulator_core1_pdata =
+struct regulator_init_data msm8930_pm8038_saw_regulator_core1_pdata =
 	SAW_VREG_INIT(S6, "8038_s6",	       850000, 1300000);
 
 /* PM8038 regulator constraints */
@@ -492,6 +503,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 +513,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 */
@@ -550,7 +563,8 @@
 	RPM_REG_MAP(VDD_DIG_CORNER, 0, 2, "krait1_dig",   "acpuclk-8930aa"),
 };
 
-struct rpm_regulator_platform_data msm8930_rpm_regulator_pdata __devinitdata = {
+struct rpm_regulator_platform_data
+msm8930_pm8038_rpm_regulator_pdata __devinitdata = {
 	.init_data		= msm8930_rpm_regulator_init_data,
 	.num_regulators		= ARRAY_SIZE(msm8930_rpm_regulator_init_data),
 	.version		= RPM_VREG_VERSION_8930,
diff --git a/arch/arm/mach-msm/board-8930-regulator.c b/arch/arm/mach-msm/board-8930-regulator-pm8917.c
similarity index 72%
copy from arch/arm/mach-msm/board-8930-regulator.c
copy to arch/arm/mach-msm/board-8930-regulator-pm8917.c
index d3a4960..db40e5d 100644
--- a/arch/arm/mach-msm/board-8930-regulator.c
+++ b/arch/arm/mach-msm/board-8930-regulator-pm8917.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2012, 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
@@ -11,6 +11,11 @@
  * GNU General Public License for more details.
  */
 
+/*
+ * This file contains regulator configuration and mappings for targets
+ * consisting of MSM8930 and PM8917.
+ */
+
 #include <linux/regulator/pm8xxx-regulator.h>
 
 #include "board-8930.h"
@@ -23,11 +28,10 @@
  *			 regulator name		consumer dev_name
  */
 VREG_CONSUMERS(L1) = {
-	REGULATOR_SUPPLY("8038_l1",		NULL),
-	REGULATOR_SUPPLY("iris_vddrfa",		"wcnss_wlan.0"),
+	REGULATOR_SUPPLY("8917_l1",		NULL),
 };
 VREG_CONSUMERS(L2) = {
-	REGULATOR_SUPPLY("8038_l2",		NULL),
+	REGULATOR_SUPPLY("8917_l2",		NULL),
 	REGULATOR_SUPPLY("iris_vdddig",		"wcnss_wlan.0"),
 	REGULATOR_SUPPLY("dsi_vdda",		"mipi_dsi.1"),
 	REGULATOR_SUPPLY("mipi_csi_vdd",	"msm_csid.0"),
@@ -35,53 +39,152 @@
 	REGULATOR_SUPPLY("mipi_csi_vdd",	"msm_csid.2"),
 };
 VREG_CONSUMERS(L3) = {
-	REGULATOR_SUPPLY("8038_l3",		NULL),
+	REGULATOR_SUPPLY("8917_l3",		NULL),
 	REGULATOR_SUPPLY("HSUSB_3p3",		"msm_otg"),
 };
 VREG_CONSUMERS(L4) = {
-	REGULATOR_SUPPLY("8038_l4",		NULL),
+	REGULATOR_SUPPLY("8917_l4",		NULL),
 	REGULATOR_SUPPLY("HSUSB_1p8",		"msm_otg"),
 	REGULATOR_SUPPLY("iris_vddxo",		"wcnss_wlan.0"),
 };
 VREG_CONSUMERS(L5) = {
-	REGULATOR_SUPPLY("8038_l5",		NULL),
+	REGULATOR_SUPPLY("8917_l5",		NULL),
 	REGULATOR_SUPPLY("sdc_vdd",		"msm_sdcc.1"),
 };
 VREG_CONSUMERS(L6) = {
-	REGULATOR_SUPPLY("8038_l6",		NULL),
+	REGULATOR_SUPPLY("8917_l6",		NULL),
 	REGULATOR_SUPPLY("sdc_vdd",		"msm_sdcc.3"),
 };
 VREG_CONSUMERS(L7) = {
-	REGULATOR_SUPPLY("8038_l7",		NULL),
+	REGULATOR_SUPPLY("8917_l7",		NULL),
+	REGULATOR_SUPPLY("sdc_vdd_io",		"msm_sdcc.3"),
 };
 VREG_CONSUMERS(L8) = {
-	REGULATOR_SUPPLY("8038_l8",		NULL),
+	REGULATOR_SUPPLY("8917_l8",		NULL),
 	REGULATOR_SUPPLY("dsi_vdc",		"mipi_dsi.1"),
 };
 VREG_CONSUMERS(L9) = {
-	REGULATOR_SUPPLY("8038_l9",		NULL),
+	REGULATOR_SUPPLY("8917_l9",		NULL),
 	REGULATOR_SUPPLY("vdd_ana",		"3-004a"),
 	REGULATOR_SUPPLY("vdd",			"3-0024"),
-	REGULATOR_SUPPLY("cam_vana",		"4-001a"),
-	REGULATOR_SUPPLY("cam_vana",		"4-006c"),
-	REGULATOR_SUPPLY("cam_vana",		"4-0048"),
-	REGULATOR_SUPPLY("cam_vaf",		"4-001a"),
-	REGULATOR_SUPPLY("cam_vaf",		"4-006c"),
-	REGULATOR_SUPPLY("cam_vaf",		"4-0048"),
-	REGULATOR_SUPPLY("cam_vana",            "4-0020"),
-	REGULATOR_SUPPLY("cam_vaf",             "4-0020"),
 	REGULATOR_SUPPLY("vdd",			"12-0018"),
 	REGULATOR_SUPPLY("vdd",			"12-0068"),
 };
 VREG_CONSUMERS(L10) = {
-	REGULATOR_SUPPLY("8038_l10",		NULL),
+	REGULATOR_SUPPLY("8917_l10",		NULL),
 	REGULATOR_SUPPLY("iris_vddpa",		"wcnss_wlan.0"),
 };
 VREG_CONSUMERS(L11) = {
-	REGULATOR_SUPPLY("8038_l11",		NULL),
+	REGULATOR_SUPPLY("8917_l11",		NULL),
+	REGULATOR_SUPPLY("cam_vana",		"4-001a"),
+	REGULATOR_SUPPLY("cam_vana",		"4-006c"),
+	REGULATOR_SUPPLY("cam_vana",		"4-0048"),
+	REGULATOR_SUPPLY("cam_vana",            "4-0020"),
+};
+VREG_CONSUMERS(L12) = {
+	REGULATOR_SUPPLY("8917_l12",		NULL),
+	REGULATOR_SUPPLY("cam_vdig",		"4-001a"),
+	REGULATOR_SUPPLY("cam_vdig",		"4-006c"),
+	REGULATOR_SUPPLY("cam_vdig",		"4-0048"),
+	REGULATOR_SUPPLY("cam_vdig",            "4-0020"),
+};
+VREG_CONSUMERS(L14) = {
+	REGULATOR_SUPPLY("8917_l14",		NULL),
+	REGULATOR_SUPPLY("pa_therm",		"pm8xxx-adc"),
+};
+VREG_CONSUMERS(L15) = {
+	REGULATOR_SUPPLY("8917_l15",		NULL),
+};
+VREG_CONSUMERS(L16) = {
+	REGULATOR_SUPPLY("8917_l16",		NULL),
+	REGULATOR_SUPPLY("cam_vaf",		"4-001a"),
+	REGULATOR_SUPPLY("cam_vaf",		"4-006c"),
+	REGULATOR_SUPPLY("cam_vaf",		"4-0048"),
+	REGULATOR_SUPPLY("cam_vaf",             "4-0020"),
+};
+VREG_CONSUMERS(L17) = {
+	REGULATOR_SUPPLY("8917_l17",		NULL),
+};
+VREG_CONSUMERS(L18) = {
+	REGULATOR_SUPPLY("8917_l18",		NULL),
+};
+VREG_CONSUMERS(L21) = {
+	REGULATOR_SUPPLY("8917_l21",		NULL),
+};
+VREG_CONSUMERS(L22) = {
+	REGULATOR_SUPPLY("8917_l22",		NULL),
+};
+VREG_CONSUMERS(L23) = {
+	REGULATOR_SUPPLY("8917_l23",		NULL),
+	REGULATOR_SUPPLY("dsi_vddio",		"mipi_dsi.1"),
+	REGULATOR_SUPPLY("hdmi_avdd",		"hdmi_msm.0"),
+	REGULATOR_SUPPLY("hdmi_vcc",		"hdmi_msm.0"),
+	REGULATOR_SUPPLY("pll_vdd",		"pil_riva"),
+	REGULATOR_SUPPLY("pll_vdd",		"pil_qdsp6v4.1"),
+	REGULATOR_SUPPLY("pll_vdd",		"pil_qdsp6v4.2"),
+};
+VREG_CONSUMERS(L24) = {
+	REGULATOR_SUPPLY("8917_l24",		NULL),
+	REGULATOR_SUPPLY("riva_vddmx",		"wcnss_wlan.0"),
+};
+VREG_CONSUMERS(L25) = {
+	REGULATOR_SUPPLY("8917_l25",		NULL),
+	REGULATOR_SUPPLY("VDDD_CDC_D",		"sitar-slim"),
+	REGULATOR_SUPPLY("CDC_VDDA_A_1P2V",	"sitar-slim"),
+	REGULATOR_SUPPLY("VDDD_CDC_D",		"sitar1p1-slim"),
+	REGULATOR_SUPPLY("CDC_VDDA_A_1P2V",	"sitar1p1-slim"),
+	REGULATOR_SUPPLY("mhl_avcc12",		"0-0039"),
+};
+VREG_CONSUMERS(L26) = {
+	REGULATOR_SUPPLY("8921_l26",		NULL),
+	REGULATOR_SUPPLY("core_vdd",		"pil_qdsp6v4.0"),
+};
+VREG_CONSUMERS(L27) = {
+	REGULATOR_SUPPLY("8921_l27",		NULL),
+	REGULATOR_SUPPLY("core_vdd",		"pil_qdsp6v4.2"),
+};
+VREG_CONSUMERS(L28) = {
+	REGULATOR_SUPPLY("8921_l28",		NULL),
+	REGULATOR_SUPPLY("core_vdd",		"pil_qdsp6v4.1"),
+};
+VREG_CONSUMERS(L29) = {
+	REGULATOR_SUPPLY("8921_l29",		NULL),
+};
+VREG_CONSUMERS(L30) = {
+	REGULATOR_SUPPLY("8917_l30",		NULL),
+};
+VREG_CONSUMERS(L31) = {
+	REGULATOR_SUPPLY("8917_l31",		NULL),
+};
+VREG_CONSUMERS(L32) = {
+	REGULATOR_SUPPLY("8917_l32",		NULL),
+};
+VREG_CONSUMERS(L33) = {
+	REGULATOR_SUPPLY("8917_l33",		NULL),
+};
+VREG_CONSUMERS(L34) = {
+	REGULATOR_SUPPLY("8917_l34",		NULL),
+};
+VREG_CONSUMERS(L35) = {
+	REGULATOR_SUPPLY("8917_l35",		NULL),
+};
+VREG_CONSUMERS(L36) = {
+	REGULATOR_SUPPLY("8917_l36",		NULL),
+};
+VREG_CONSUMERS(S1) = {
+	REGULATOR_SUPPLY("8917_s1",		NULL),
+};
+VREG_CONSUMERS(S2) = {
+	REGULATOR_SUPPLY("8917_s2",		NULL),
+	REGULATOR_SUPPLY("iris_vddrfa",		"wcnss_wlan.0"),
+};
+VREG_CONSUMERS(S3) = {
+	REGULATOR_SUPPLY("8917_s3",		NULL),
+	REGULATOR_SUPPLY("riva_vddcx",		"wcnss_wlan.0"),
+};
+VREG_CONSUMERS(S4) = {
+	REGULATOR_SUPPLY("8917_s4",		NULL),
 	REGULATOR_SUPPLY("vdd_dig",		"3-004a"),
-	REGULATOR_SUPPLY("iris_vddio",		"wcnss_wlan.0"),
-	REGULATOR_SUPPLY("riva_vddpx",		"wcnss_wlan.0"),
 	REGULATOR_SUPPLY("sdc_vdd_io",		"msm_sdcc.1"),
 	REGULATOR_SUPPLY("VDDIO_CDC",		"sitar-slim"),
 	REGULATOR_SUPPLY("CDC_VDDA_TX",		"sitar-slim"),
@@ -91,126 +194,71 @@
 	REGULATOR_SUPPLY("CDC_VDDA_RX",		"sitar1p1-slim"),
 	REGULATOR_SUPPLY("vddp",		"0-0048"),
 	REGULATOR_SUPPLY("mhl_iovcc18",		"0-0039"),
-};
-VREG_CONSUMERS(L12) = {
-	REGULATOR_SUPPLY("8038_l12",		NULL),
-	REGULATOR_SUPPLY("cam_vdig",		"4-001a"),
-	REGULATOR_SUPPLY("cam_vdig",		"4-006c"),
-	REGULATOR_SUPPLY("cam_vdig",		"4-0048"),
-	REGULATOR_SUPPLY("cam_vdig",            "4-0020"),
-};
-VREG_CONSUMERS(L14) = {
-	REGULATOR_SUPPLY("8038_l14",		NULL),
-	REGULATOR_SUPPLY("pa_therm",		"pm8xxx-adc"),
-};
-VREG_CONSUMERS(L15) = {
-	REGULATOR_SUPPLY("8038_l15",		NULL),
-};
-VREG_CONSUMERS(L16) = {
-	REGULATOR_SUPPLY("8038_l16",		NULL),
-	REGULATOR_SUPPLY("core_vdd",		"pil_qdsp6v4.2"),
-};
-VREG_CONSUMERS(L17) = {
-	REGULATOR_SUPPLY("8038_l17",		NULL),
-};
-VREG_CONSUMERS(L18) = {
-	REGULATOR_SUPPLY("8038_l18",		NULL),
-};
-VREG_CONSUMERS(L19) = {
-	REGULATOR_SUPPLY("8038_l19",		NULL),
-	REGULATOR_SUPPLY("core_vdd",		"pil_qdsp6v4.1"),
-};
-VREG_CONSUMERS(L20) = {
-	REGULATOR_SUPPLY("8038_l20",		NULL),
-	REGULATOR_SUPPLY("VDDD_CDC_D",		"sitar-slim"),
-	REGULATOR_SUPPLY("CDC_VDDA_A_1P2V",	"sitar-slim"),
-	REGULATOR_SUPPLY("VDDD_CDC_D",		"sitar1p1-slim"),
-	REGULATOR_SUPPLY("CDC_VDDA_A_1P2V",	"sitar1p1-slim"),
-	REGULATOR_SUPPLY("mhl_avcc12",		"0-0039"),
-};
-VREG_CONSUMERS(L21) = {
-	REGULATOR_SUPPLY("8038_l21",		NULL),
-};
-VREG_CONSUMERS(L22) = {
-	REGULATOR_SUPPLY("8038_l22",		NULL),
-	REGULATOR_SUPPLY("sdc_vdd_io",		"msm_sdcc.3"),
-};
-VREG_CONSUMERS(L23) = {
-	REGULATOR_SUPPLY("8038_l23",		NULL),
-	REGULATOR_SUPPLY("dsi_vddio",		"mipi_dsi.1"),
-	REGULATOR_SUPPLY("hdmi_avdd",		"hdmi_msm.0"),
-	REGULATOR_SUPPLY("hdmi_vcc",		"hdmi_msm.0"),
-	REGULATOR_SUPPLY("pll_vdd",		"pil_riva"),
-	REGULATOR_SUPPLY("pll_vdd",		"pil_qdsp6v4.1"),
-	REGULATOR_SUPPLY("pll_vdd",		"pil_qdsp6v4.2"),
-};
-VREG_CONSUMERS(L24) = {
-	REGULATOR_SUPPLY("8038_l24",		NULL),
-	REGULATOR_SUPPLY("riva_vddmx",		"wcnss_wlan.0"),
-};
-VREG_CONSUMERS(L26) = {
-	REGULATOR_SUPPLY("8038_l26",		NULL),
-};
-VREG_CONSUMERS(L27) = {
-	REGULATOR_SUPPLY("8038_l27",		NULL),
-	REGULATOR_SUPPLY("core_vdd",		"pil_qdsp6v4.0"),
-};
-VREG_CONSUMERS(S1) = {
-	REGULATOR_SUPPLY("8038_s1",		NULL),
-	REGULATOR_SUPPLY("riva_vddcx",		"wcnss_wlan.0"),
-};
-VREG_CONSUMERS(S2) = {
-	REGULATOR_SUPPLY("8038_s2",		NULL),
-};
-VREG_CONSUMERS(S3) = {
-	REGULATOR_SUPPLY("8038_s3",		NULL),
-};
-VREG_CONSUMERS(S4) = {
-	REGULATOR_SUPPLY("8038_s4",		NULL),
 	REGULATOR_SUPPLY("CDC_VDD_CP",		"sitar-slim"),
 	REGULATOR_SUPPLY("CDC_VDD_CP",		"sitar1p1-slim"),
 };
 VREG_CONSUMERS(S5) = {
-	REGULATOR_SUPPLY("8038_s5",		NULL),
+	REGULATOR_SUPPLY("8917_s5",		NULL),
 	REGULATOR_SUPPLY("krait0",		"acpuclk-8627"),
 	REGULATOR_SUPPLY("krait0",		"acpuclk-8930"),
 	REGULATOR_SUPPLY("krait0",		"acpuclk-8930aa"),
 };
 VREG_CONSUMERS(S6) = {
-	REGULATOR_SUPPLY("8038_s6",		NULL),
+	REGULATOR_SUPPLY("8917_s6",		NULL),
 	REGULATOR_SUPPLY("krait1",		"acpuclk-8627"),
 	REGULATOR_SUPPLY("krait1",		"acpuclk-8930"),
 	REGULATOR_SUPPLY("krait1",		"acpuclk-8930aa"),
 };
-VREG_CONSUMERS(LVS1) = {
-	REGULATOR_SUPPLY("8038_lvs1",		NULL),
-	REGULATOR_SUPPLY("cam_vio",		"4-001a"),
-	REGULATOR_SUPPLY("cam_vio",		"4-006c"),
-	REGULATOR_SUPPLY("cam_vio",		"4-0048"),
-	REGULATOR_SUPPLY("cam_vio",             "4-0020"),
+VREG_CONSUMERS(S7) = {
+	REGULATOR_SUPPLY("8917_s7",		NULL),
 };
-VREG_CONSUMERS(LVS2) = {
-	REGULATOR_SUPPLY("8038_lvs2",		NULL),
+VREG_CONSUMERS(S8) = {
+	REGULATOR_SUPPLY("8917_s8",		NULL),
+};
+VREG_CONSUMERS(LVS1) = {
+	REGULATOR_SUPPLY("8917_lvs1",		NULL),
+	REGULATOR_SUPPLY("iris_vddio",		"wcnss_wlan.0"),
+	REGULATOR_SUPPLY("riva_vddpx",		"wcnss_wlan.0"),
+};
+VREG_CONSUMERS(LVS3) = {
+	REGULATOR_SUPPLY("8917_lvs3",		NULL),
+};
+VREG_CONSUMERS(LVS4) = {
+	REGULATOR_SUPPLY("8917_lvs4",		NULL),
 	REGULATOR_SUPPLY("vcc_i2c",		"3-004a"),
 	REGULATOR_SUPPLY("vcc_i2c",		"3-0024"),
 	REGULATOR_SUPPLY("vcc_i2c",		"0-0048"),
 	REGULATOR_SUPPLY("vddio",		"12-0018"),
 	REGULATOR_SUPPLY("vlogic",		"12-0068"),
 };
-VREG_CONSUMERS(EXT_5V) = {
-	REGULATOR_SUPPLY("ext_5v",		NULL),
+VREG_CONSUMERS(LVS5) = {
+	REGULATOR_SUPPLY("8917_lvs5",		NULL),
+	REGULATOR_SUPPLY("cam_vio",		"4-001a"),
+	REGULATOR_SUPPLY("cam_vio",		"4-006c"),
+	REGULATOR_SUPPLY("cam_vio",		"4-0048"),
+	REGULATOR_SUPPLY("cam_vio",             "4-0020"),
+};
+VREG_CONSUMERS(LVS6) = {
+	REGULATOR_SUPPLY("8917_lvs6",		NULL),
+};
+VREG_CONSUMERS(LVS7) = {
+	REGULATOR_SUPPLY("8917_lvs7",		NULL),
+};
+VREG_CONSUMERS(USB_OTG) = {
+	REGULATOR_SUPPLY("8921_usb_otg",	NULL),
+	REGULATOR_SUPPLY("vbus_otg",		"msm_otg"),
+};
+VREG_CONSUMERS(BOOST) = {
+	REGULATOR_SUPPLY("8917_boost",		NULL),
 	REGULATOR_SUPPLY("hdmi_mvs",		"hdmi_msm.0"),
 	REGULATOR_SUPPLY("mhl_usb_hs_switch",	"msm_otg"),
 };
-VREG_CONSUMERS(EXT_OTG_SW) = {
-	REGULATOR_SUPPLY("ext_otg_sw",		NULL),
-	REGULATOR_SUPPLY("vbus_otg",		"msm_otg"),
-};
 VREG_CONSUMERS(VDD_DIG_CORNER) = {
 	REGULATOR_SUPPLY("vdd_dig_corner",	NULL),
 	REGULATOR_SUPPLY("hsusb_vdd_dig",	"msm_otg"),
 };
 
+
 #define PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, _modes, _ops, \
 			 _apply_uV, _pull_down, _always_on, _supply_regulator, \
 			 _system_uA, _enable_time, _reg_id) \
@@ -280,7 +328,7 @@
 		_pull_down, _always_on, _supply_regulator, 0, _enable_time, \
 		_reg_id)
 
-#define PM8XXX_NCP(_id, _name, _always_on, _min_uV, _max_uV, _enable_time, \
+#define PM8XXX_BOOST(_id, _name, _always_on, _min_uV, _max_uV, _enable_time, \
 		_supply_regulator, _reg_id) \
 	PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, 0, \
 		REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, 0, 0, \
@@ -326,7 +374,7 @@
 			.consumer_supplies	= vreg_consumers_##_id, \
 			.supply_regulator	= _supply_regulator, \
 		}, \
-		.id			= RPM_VREG_ID_PM8038_##_id, \
+		.id			= RPM_VREG_ID_PM8917_##_id, \
 		.default_uV		= _default_uV, \
 		.peak_uA		= _peak_uA, \
 		.avg_uA			= _avg_uA, \
@@ -408,7 +456,7 @@
 			.consumer_supplies	= vreg_consumers_##_id##_PC, \
 			.supply_regulator	= _supply_regulator, \
 		}, \
-		.id	  = RPM_VREG_ID_PM8038_##_id##_PC, \
+		.id	  = RPM_VREG_ID_PM8917_##_id##_PC, \
 		.pin_fn	  = RPM_VREG_PIN_FN_8930_##_pin_fn, \
 		.pin_ctrl = _pin_ctrl, \
 	}
@@ -443,91 +491,122 @@
 
 /* GPIO regulator constraints */
 struct gpio_regulator_platform_data
-msm8930_gpio_regulator_pdata[] __devinitdata = {
+msm8930_pm8917_gpio_regulator_pdata[] __devinitdata = {
 	/*        ID          vreg_name     gpio_label     gpio  supply */
-	GPIO_VREG(EXT_5V,     "ext_5v",     "ext_5v_en",     63, NULL),
-	GPIO_VREG(EXT_OTG_SW, "ext_otg_sw", "ext_otg_sw_en", 97, "ext_5v"),
 };
 
 /* SAW regulator constraints */
-struct regulator_init_data msm8930_saw_regulator_core0_pdata =
+struct regulator_init_data msm8930_pm8917_saw_regulator_core0_pdata =
 	/*	      ID  vreg_name	       min_uV   max_uV */
-	SAW_VREG_INIT(S5, "8038_s5",	       850000, 1300000);
-struct regulator_init_data msm8930_saw_regulator_core1_pdata =
-	SAW_VREG_INIT(S6, "8038_s6",	       850000, 1300000);
+	SAW_VREG_INIT(S5, "8917_s5",	       850000, 1300000);
+struct regulator_init_data msm8930_pm8917_saw_regulator_core1_pdata =
+	SAW_VREG_INIT(S6, "8917_s6",	       850000, 1300000);
 
-/* PM8038 regulator constraints */
+/* PM8917 regulator constraints */
 struct pm8xxx_regulator_platform_data
-msm8930_pm8038_regulator_pdata[] __devinitdata = {
+msm8930_pm8917_regulator_pdata[] __devinitdata = {
 	/*
-	 *	    ID  name always_on pd min_uV   max_uV   en_t supply
+	 *               ID  name always_on pd min_uV   max_uV   en_t supply
 	 *	system_uA reg_ID
 	 */
-	PM8XXX_NLDO1200(L16, "8038_l16", 0, 1, 375000, 1050000, 200, "8038_s3",
+	PM8XXX_NLDO1200(L26, "8921_l26", 0, 1,  375000, 1050000, 200, "8917_s7",
 		0, 0),
-	PM8XXX_NLDO1200(L19, "8038_l19", 0, 1, 375000, 1050000, 200, "8038_s3",
+	PM8XXX_NLDO1200(L27, "8921_l27", 0, 1,  375000, 1050000, 200, "8917_s7",
 		0, 1),
-	PM8XXX_NLDO1200(L27, "8038_l27", 0, 1, 375000, 1050000, 200, "8038_s3",
+	PM8XXX_NLDO1200(L28, "8921_l28", 0, 1,  375000, 1050000, 200, "8917_s7",
 		0, 2),
+	PM8XXX_LDO(L29,      "8921_l29", 0, 1, 1800000, 1800000, 200, "8917_s8",
+		0, 3),
+	PM8XXX_LDO(L30,      "8917_l30", 0, 1, 1800000, 1800000, 200, NULL,
+		0, 4),
+	PM8XXX_LDO(L31,      "8917_l31", 0, 1, 1800000, 1800000, 200, NULL,
+		0, 5),
+	PM8XXX_LDO(L32,      "8917_l32", 0, 1, 2800000, 2800000, 200, NULL,
+		0, 6),
+	PM8XXX_LDO(L33,      "8917_l33", 0, 1, 2800000, 2800000, 200, NULL,
+		0, 7),
+	PM8XXX_LDO(L34,      "8917_l34", 0, 1, 1800000, 1800000, 200, NULL,
+		0, 8),
+	PM8XXX_LDO(L35,      "8917_l35", 0, 1, 3000000, 3000000, 200, NULL,
+		0, 9),
+	PM8XXX_LDO(L36,      "8917_l36", 0, 1, 1800000, 1800000, 200, NULL,
+		0, 10),
+	/*
+	 *           ID     name  always_on   min_uV   max_uV en_t supply reg_ID
+	 */
+	PM8XXX_BOOST(BOOST, "8917_boost", 0,  5000000, 5000000, 500, NULL, 11),
+
+	/*	     ID        name      always_on pd en_t supply    reg_ID */
+	PM8XXX_VS300(USB_OTG,  "8921_usb_otg",  0, 1, 0,   "8917_boost", 12),
 };
 
 static struct rpm_regulator_init_data
 msm8930_rpm_regulator_init_data[] __devinitdata = {
 	/*	ID a_on pd ss min_uV   max_uV  supply sys_uA  freq  fm  ss_fm */
-	RPM_SMPS(S1, 0, 1, 1,  500000, 1150000, NULL, 100000, 4p80, AUTO, LPM),
-	RPM_SMPS(S2, 1, 1, 1, 1400000, 1400000, NULL, 100000, 1p60, AUTO, LPM),
-	RPM_SMPS(S3, 0, 1, 1, 1150000, 1150000, NULL, 100000, 3p20, AUTO, LPM),
-	RPM_SMPS(S4, 1, 1, 1, 1950000, 2200000, NULL, 100000, 1p60, AUTO, LPM),
+	RPM_SMPS(S1, 1, 1, 0, 1300000, 1300000, NULL, 100000, 3p20, NONE, NONE),
+	RPM_SMPS(S2, 0, 1, 0, 1300000, 1300000, NULL,      0, 1p60, NONE, NONE),
+	RPM_SMPS(S3, 0, 1, 1,  500000, 1150000, NULL, 100000, 4p80, AUTO, LPM),
+	RPM_SMPS(S4, 1, 1, 0, 1800000, 1800000, NULL, 100000, 1p60, AUTO, LPM),
+	RPM_SMPS(S7, 0, 1, 0, 1150000, 1150000, NULL, 100000, 3p20, NONE, NONE),
+	RPM_SMPS(S8, 1, 1, 1, 2050000, 2050000, NULL, 100000, 1p60, NONE, NONE),
 
 	/*	ID     a_on pd ss min_uV   max_uV  supply  sys_uA init_ip */
-	RPM_LDO(L1,	 0, 1, 0, 1300000, 1300000, "8038_s2", 0, 0),
-	RPM_LDO(L2,	 0, 1, 0, 1200000, 1200000, "8038_s2", 0, 0),
+	RPM_LDO(L1,	 1, 1, 0, 1050000, 1050000, "8917_s4", 0, 10000),
+	RPM_LDO(L2,	 0, 1, 0, 1200000, 1200000, "8917_s4", 0, 0),
 	RPM_LDO(L3,	 0, 1, 0, 3075000, 3075000, NULL,      0, 0),
 	RPM_LDO(L4,	 1, 1, 0, 1800000, 1800000, NULL,      10000, 10000),
 	RPM_LDO(L5,	 0, 1, 0, 2950000, 2950000, NULL,      0, 0),
 	RPM_LDO(L6,	 0, 1, 0, 2950000, 2950000, NULL,      0, 0),
-	RPM_LDO(L7,	 0, 1, 0, 2050000, 2050000, "8038_s4", 0, 0),
+	RPM_LDO(L7,	 1, 1, 0, 1850000, 2950000, NULL,      10000, 10000),
 	RPM_LDO(L8,	 0, 1, 0, 2800000, 2800000, NULL,      0, 0),
 	RPM_LDO(L9,	 0, 1, 0, 2850000, 2850000, NULL,      0, 0),
 	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(L11,	 0, 1, 0, 2850000, 2850000, NULL,      0, 0),
+	RPM_LDO(L12,	 0, 1, 0, 1200000, 1200000, "8917_s4", 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(L16,	 0, 1, 0, 2850000, 2850000, NULL,      0, 0),
 	RPM_LDO(L17,	 0, 1, 0, 1800000, 2950000, NULL,      0, 0),
-	RPM_LDO(L18,	 0, 1, 0, 1800000, 1800000, NULL,      0, 0),
-	RPM_LDO(L20,	 1, 1, 0, 1250000, 1250000, "8038_s2", 10000, 10000),
-	RPM_LDO(L21,	 0, 1, 0, 1900000, 1900000, "8038_s4", 0, 0),
-	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(L26,     1, 1, 0, 1050000, 1050000, "8038_s2", 10000, 10000),
+	RPM_LDO(L18,	 0, 1, 0, 1200000, 1200000, "8917_s4", 0, 0),
+	RPM_LDO(L21,	 0, 1, 0, 1900000, 1900000, "8917_s8", 0, 0),
+	RPM_LDO(L22,	 0, 1, 0, 2750000, 2750000, NULL,      0, 0),
+	RPM_LDO(L23,	 1, 1, 1, 1800000, 1800000, "8917_s8", 10000, 10000),
+	RPM_LDO(L24,	 0, 1, 1,  500000, 1150000, "8917_s1", 10000, 10000),
+	RPM_LDO(L25,	 1, 1, 0, 1250000, 1250000, "8917_s1", 10000, 10000),
 
 	/*	ID     a_on pd ss		    supply */
-	RPM_VS(LVS1,	 0, 1, 0,		    "8038_l11"),
-	RPM_VS(LVS2,	 0, 1, 0,		    "8038_l11"),
+	RPM_VS(LVS1,	 0, 1, 0,		    "8917_s4"),
+	RPM_VS(LVS3,	 0, 1, 0,		    "8917_s4"),
+	RPM_VS(LVS4,	 0, 1, 0,		    "8917_s4"),
+	RPM_VS(LVS5,	 0, 1, 0,		    "8917_s4"),
+	RPM_VS(LVS6,	 0, 1, 0,		    "8917_s4"),
+	RPM_VS(LVS7,	 0, 1, 0,		    "8917_s4"),
 
 	/*	   ID            a_on ss min_corner  max_corner  supply */
 	RPM_CORNER(VDD_DIG_CORNER, 0, 1, RPM_VREG_CORNER_NONE,
 		RPM_VREG_CORNER_HIGH, NULL),
 };
 
-int msm8930_pm8038_regulator_pdata_len __devinitdata =
-	ARRAY_SIZE(msm8930_pm8038_regulator_pdata);
+int msm8930_pm8917_regulator_pdata_len __devinitdata =
+	ARRAY_SIZE(msm8930_pm8917_regulator_pdata);
 
 #define RPM_REG_MAP(_id, _sleep_also, _voter, _supply, _dev_name) \
 	{ \
-		.vreg_id = RPM_VREG_ID_PM8038_##_id, \
+		.vreg_id = RPM_VREG_ID_PM8917_##_id, \
 		.sleep_also = _sleep_also, \
 		.voter = _voter, \
 		.supply = _supply, \
 		.dev_name = _dev_name, \
 	}
+
 static struct rpm_regulator_consumer_mapping
 	      msm_rpm_regulator_consumer_mapping[] __devinitdata = {
-	RPM_REG_MAP(L23,            0, 1, "krait0_hfpll", "acpuclk-8930"),
-	RPM_REG_MAP(L23,            0, 2, "krait1_hfpll", "acpuclk-8930"),
-	RPM_REG_MAP(L23,            0, 6, "l2_hfpll",     "acpuclk-8930"),
+	RPM_REG_MAP(L23,            0, 1, "krait0_l23",   "acpuclk-8930"),
+	RPM_REG_MAP(S8,             0, 1, "krait0_s8",    "acpuclk-8930"),
+	RPM_REG_MAP(L23,            0, 2, "krait1_l23",   "acpuclk-8930"),
+	RPM_REG_MAP(S8,             0, 2, "krait1_s8",    "acpuclk-8930"),
+	RPM_REG_MAP(L23,            0, 6, "l2_l23",       "acpuclk-8930"),
+	RPM_REG_MAP(S8,             0, 6, "l2_s8",        "acpuclk-8930"),
 	RPM_REG_MAP(L24,            0, 1, "krait0_mem",   "acpuclk-8930"),
 	RPM_REG_MAP(L24,            0, 2, "krait1_mem",   "acpuclk-8930"),
 	RPM_REG_MAP(VDD_DIG_CORNER, 0, 1, "krait0_dig",   "acpuclk-8930"),
@@ -550,12 +629,13 @@
 	RPM_REG_MAP(VDD_DIG_CORNER, 0, 2, "krait1_dig",   "acpuclk-8930aa"),
 };
 
-struct rpm_regulator_platform_data msm8930_rpm_regulator_pdata __devinitdata = {
+struct rpm_regulator_platform_data
+msm8930_pm8917_rpm_regulator_pdata __devinitdata = {
 	.init_data		= msm8930_rpm_regulator_init_data,
 	.num_regulators		= ARRAY_SIZE(msm8930_rpm_regulator_init_data),
-	.version		= RPM_VREG_VERSION_8930,
-	.vreg_id_vdd_mem	= RPM_VREG_ID_PM8038_L24,
-	.vreg_id_vdd_dig	= RPM_VREG_ID_PM8038_VDD_DIG_CORNER,
+	.version		= RPM_VREG_VERSION_8930_PM8917,
+	.vreg_id_vdd_mem	= RPM_VREG_ID_PM8917_L24,
+	.vreg_id_vdd_dig	= RPM_VREG_ID_PM8917_VDD_DIG_CORNER,
 	.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-8930.c b/arch/arm/mach-msm/board-8930.c
index b80d62d..aad0f3d 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -76,7 +76,7 @@
 #include <mach/msm_xo.h>
 #include <mach/restart.h>
 
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
 #include <mach/ion.h>
 #include <mach/mdm2.h>
 #include <mach/msm_rtb.h>
@@ -100,6 +100,7 @@
 #include "pm-boot.h"
 #include "msm_watchdog.h"
 #include "board-8930.h"
+#include "acpuclock-krait.h"
 
 static struct platform_device msm_fm_platform_init = {
 	.name = "iris_fm",
@@ -141,7 +142,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 +169,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 +323,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*/
 }
 
@@ -729,8 +730,28 @@
 	place_movable_zone();
 }
 
+static char prim_panel_name[PANEL_NAME_MAX_LEN];
+static char ext_panel_name[PANEL_NAME_MAX_LEN];
+
+static int __init prim_display_setup(char *param)
+{
+	if (strnlen(param, PANEL_NAME_MAX_LEN))
+		strlcpy(prim_panel_name, param, PANEL_NAME_MAX_LEN);
+	return 0;
+}
+early_param("prim_display", prim_display_setup);
+
+static int __init ext_display_setup(char *param)
+{
+	if (strnlen(param, PANEL_NAME_MAX_LEN))
+		strlcpy(ext_panel_name, param, PANEL_NAME_MAX_LEN);
+	return 0;
+}
+early_param("ext_display", ext_display_setup);
+
 static void __init msm8930_reserve(void)
 {
+	msm8930_set_display_params(prim_panel_name, ext_panel_name);
 	msm_reserve();
 	if (msm8930_fmem_pdata.size) {
 #if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
@@ -791,7 +812,7 @@
 	.regulator = {
 	{
 		.name = "CDC_VDD_CP",
-		.min_uV = 1950000,
+		.min_uV = 1800000,
 		.max_uV = 2200000,
 		.optimum_uA = WCD9XXX_CDC_VDDA_CP_CUR_MAX,
 	},
@@ -857,7 +878,7 @@
 	.regulator = {
 	{
 		.name = "CDC_VDD_CP",
-		.min_uV = 1950000,
+		.min_uV = 1800000,
 		.max_uV = 2200000,
 		.optimum_uA = WCD9XXX_CDC_VDDA_CP_CUR_MAX,
 	},
@@ -970,6 +991,12 @@
 		.ab = 0,
 	},
 	{
+		.src = MSM_BUS_MASTER_SPS,
+		.dst = MSM_BUS_SLAVE_SPS,
+		.ib = 0,
+		.ab = 0,
+	},
+	{
 		.src = MSM_BUS_MASTER_SPDM,
 		.dst = MSM_BUS_SLAVE_SPDM,
 		.ib = 0,
@@ -985,6 +1012,12 @@
 		.ab = (492 * 8) *  100000UL,
 	},
 	{
+		.src = MSM_BUS_MASTER_SPS,
+		.dst = MSM_BUS_SLAVE_SPS,
+		.ib = (492 * 8) * 1000000UL,
+		.ab = (492 * 8) *  100000UL,
+	},
+	{
 		.src = MSM_BUS_MASTER_SPDM,
 		.dst = MSM_BUS_SLAVE_SPDM,
 		.ib = 0,
@@ -1000,6 +1033,12 @@
 		.ab = 0,
 	},
 	{
+		.src = MSM_BUS_MASTER_SPS,
+		.dst = MSM_BUS_SLAVE_SPS,
+		.ib = 0,
+		.ab = 0,
+	},
+	{
 		.src = MSM_BUS_MASTER_SPDM,
 		.dst = MSM_BUS_SLAVE_SPDM,
 		.ib = (64 * 8) * 1000000UL,
@@ -1450,7 +1489,7 @@
 static int hsusb_phy_init_seq[] = {
 	0x44, 0x80, /* set VBUS valid threshold
 			and disconnect valid threshold */
-	0x38, 0x81, /* update DC voltage level */
+	0x68, 0x81, /* update DC voltage level */
 	0x24, 0x82, /* set preemphasis and rise/fall time */
 	0x13, 0x83, /* set source impedance adjusment */
 	-1};
@@ -1541,6 +1580,11 @@
 	0x03, 0x0f,
 };
 
+static uint8_t spm_retention_cmd_sequence[] __initdata = {
+	0x00, 0x05, 0x03, 0x0D,
+	0x0B, 0x00, 0x0f,
+};
+
 static uint8_t spm_power_collapse_without_rpm[] __initdata = {
 	0x00, 0x24, 0x54, 0x10,
 	0x09, 0x03, 0x01,
@@ -1555,7 +1599,30 @@
 	0x24, 0x30, 0x0f,
 };
 
-static struct msm_spm_seq_entry msm_spm_seq_list[] __initdata = {
+static struct msm_spm_seq_entry msm_spm_boot_cpu_seq_list[] __initdata = {
+	[0] = {
+		.mode = MSM_SPM_MODE_CLOCK_GATING,
+		.notify_rpm = false,
+		.cmd = spm_wfi_cmd_sequence,
+	},
+	[1] = {
+		.mode = MSM_SPM_MODE_POWER_RETENTION,
+		.notify_rpm = false,
+		.cmd = spm_retention_cmd_sequence,
+	},
+	[2] = {
+		.mode = MSM_SPM_MODE_POWER_COLLAPSE,
+		.notify_rpm = false,
+		.cmd = spm_power_collapse_without_rpm,
+	},
+	[3] = {
+		.mode = MSM_SPM_MODE_POWER_COLLAPSE,
+		.notify_rpm = true,
+		.cmd = spm_power_collapse_with_rpm,
+	},
+};
+
+static struct msm_spm_seq_entry msm_spm_nonboot_cpu_seq_list[] __initdata = {
 	[0] = {
 		.mode = MSM_SPM_MODE_CLOCK_GATING,
 		.notify_rpm = false,
@@ -1582,12 +1649,12 @@
 		.reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x00,
 #endif
 		.reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01,
-		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020204,
-		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0060009C,
-		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x0000001C,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x03020004,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0084009C,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x00A4001C,
 		.vctl_timeout_us = 50,
-		.num_modes = ARRAY_SIZE(msm_spm_seq_list),
-		.modes = msm_spm_seq_list,
+		.num_modes = ARRAY_SIZE(msm_spm_boot_cpu_seq_list),
+		.modes = msm_spm_boot_cpu_seq_list,
 	},
 	[1] = {
 		.reg_base_addr = MSM_SAW1_BASE,
@@ -1601,8 +1668,8 @@
 		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0060009C,
 		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x0000001C,
 		.vctl_timeout_us = 50,
-		.num_modes = ARRAY_SIZE(msm_spm_seq_list),
-		.modes = msm_spm_seq_list,
+		.num_modes = ARRAY_SIZE(msm_spm_nonboot_cpu_seq_list),
+		.modes = msm_spm_nonboot_cpu_seq_list,
 	},
 };
 
@@ -1656,18 +1723,26 @@
 
 #define ISA1200_HAP_EN_GPIO	77
 #define ISA1200_HAP_LEN_GPIO	78
-#define ISA1200_HAP_CLK		PM8038_GPIO_PM_TO_SYS(7)
+#define ISA1200_HAP_CLK_PM8038	PM8038_GPIO_PM_TO_SYS(7)
+#define ISA1200_HAP_CLK_PM8917	PM8917_GPIO_PM_TO_SYS(38)
 
 static int isa1200_power(int on)
 {
+	unsigned int gpio = ISA1200_HAP_CLK_PM8038;
+	enum pm8xxx_aux_clk_id clk_id = CLK_MP3_1;
 	int rc = 0;
 
-	gpio_set_value_cansleep(ISA1200_HAP_CLK, !!on);
+	if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917) {
+		gpio = ISA1200_HAP_CLK_PM8917;
+		clk_id = CLK_MP3_2;
+	}
+
+	gpio_set_value_cansleep(gpio, !!on);
 
 	if (on)
-		rc = pm8xxx_aux_clk_control(CLK_MP3_1, XO_DIV_1, true);
+		rc = pm8xxx_aux_clk_control(clk_id, XO_DIV_1, true);
 	else
-		rc = pm8xxx_aux_clk_control(CLK_MP3_1, XO_DIV_NONE, true);
+		rc = pm8xxx_aux_clk_control(clk_id, XO_DIV_NONE, true);
 
 	if (rc) {
 		pr_err("%s: unable to write aux clock register(%d)\n",
@@ -1679,29 +1754,33 @@
 
 static int isa1200_dev_setup(bool enable)
 {
+	unsigned int gpio = ISA1200_HAP_CLK_PM8038;
 	int rc = 0;
 
+	if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917)
+		gpio = ISA1200_HAP_CLK_PM8917;
+
 	if (!enable)
 		goto fail_gpio_dir;
 
-	rc = gpio_request(ISA1200_HAP_CLK, "haptics_clk");
+	rc = gpio_request(gpio, "haptics_clk");
 	if (rc) {
 		pr_err("%s: gpio_request for %d gpio failed rc(%d)\n",
-					__func__, ISA1200_HAP_CLK, rc);
+					__func__, gpio, rc);
 		goto fail_gpio_req;
 	}
 
-	rc = gpio_direction_output(ISA1200_HAP_CLK, 0);
+	rc = gpio_direction_output(gpio, 0);
 	if (rc) {
 		pr_err("%s: gpio_direction_output failed for %d gpio rc(%d)\n",
-						__func__, ISA1200_HAP_CLK, rc);
+						__func__, gpio, rc);
 		goto fail_gpio_dir;
 	}
 
 	return 0;
 
 fail_gpio_dir:
-	gpio_free(ISA1200_HAP_CLK);
+	gpio_free(gpio);
 fail_gpio_req:
 	return rc;
 
@@ -1938,12 +2017,13 @@
 	},
 };
 
-#define MHL_POWER_GPIO       PM8038_GPIO_PM_TO_SYS(MHL_GPIO_PWR_EN)
+#define MHL_POWER_GPIO_PM8038	PM8038_GPIO_PM_TO_SYS(MHL_GPIO_PWR_EN)
+#define MHL_POWER_GPIO_PM8917	PM8917_GPIO_PM_TO_SYS(25)
 static struct msm_mhl_platform_data mhl_platform_data = {
 	.irq = MSM_GPIO_TO_INT(MHL_GPIO_INT),
 	.gpio_mhl_int = MHL_GPIO_INT,
 	.gpio_mhl_reset = MHL_GPIO_RESET,
-	.gpio_mhl_power = MHL_POWER_GPIO,
+	.gpio_mhl_power = MHL_POWER_GPIO_PM8038,
 	.gpio_hdmi_mhl_mux = HDMI_MHL_MUX_GPIO,
 };
 
@@ -1962,17 +2042,22 @@
 
 #ifdef MSM8930_PHASE_2
 
-#define GPIO_VOLUME_UP		PM8038_GPIO_PM_TO_SYS(3)
-#define GPIO_VOLUME_DOWN	PM8038_GPIO_PM_TO_SYS(8)
-#define GPIO_CAMERA_SNAPSHOT	PM8038_GPIO_PM_TO_SYS(10)
-#define GPIO_CAMERA_FOCUS	PM8038_GPIO_PM_TO_SYS(11)
+#define GPIO_VOLUME_UP_PM8038		PM8038_GPIO_PM_TO_SYS(3)
+#define GPIO_VOLUME_DOWN_PM8038		PM8038_GPIO_PM_TO_SYS(8)
+#define GPIO_CAMERA_SNAPSHOT_PM8038	PM8038_GPIO_PM_TO_SYS(10)
+#define GPIO_CAMERA_FOCUS_PM8038	PM8038_GPIO_PM_TO_SYS(11)
 
-static struct gpio_keys_button keys_8930[] = {
+#define GPIO_VOLUME_UP_PM8917		PM8917_GPIO_PM_TO_SYS(27)
+#define GPIO_VOLUME_DOWN_PM8917		PM8917_GPIO_PM_TO_SYS(28)
+#define GPIO_CAMERA_SNAPSHOT_PM8917	PM8917_GPIO_PM_TO_SYS(36)
+#define GPIO_CAMERA_FOCUS_PM8917	PM8917_GPIO_PM_TO_SYS(37)
+
+static struct gpio_keys_button keys_8930_pm8038[] = {
 	{
 		.code = KEY_VOLUMEUP,
 		.type = EV_KEY,
 		.desc = "volume_up",
-		.gpio = GPIO_VOLUME_UP,
+		.gpio = GPIO_VOLUME_UP_PM8038,
 		.wakeup = 1,
 		.active_low = 1,
 		.debounce_interval = 15,
@@ -1981,7 +2066,7 @@
 		.code = KEY_VOLUMEDOWN,
 		.type = EV_KEY,
 		.desc = "volume_down",
-		.gpio = GPIO_VOLUME_DOWN,
+		.gpio = GPIO_VOLUME_DOWN_PM8038,
 		.wakeup = 1,
 		.active_low = 1,
 		.debounce_interval = 15,
@@ -1990,7 +2075,7 @@
 		.code = KEY_CAMERA_FOCUS,
 		.type = EV_KEY,
 		.desc = "camera_focus",
-		.gpio = GPIO_CAMERA_FOCUS,
+		.gpio = GPIO_CAMERA_FOCUS_PM8038,
 		.wakeup = 1,
 		.active_low = 1,
 		.debounce_interval = 15,
@@ -1999,7 +2084,46 @@
 		.code = KEY_CAMERA_SNAPSHOT,
 		.type = EV_KEY,
 		.desc = "camera_snapshot",
-		.gpio = GPIO_CAMERA_SNAPSHOT,
+		.gpio = GPIO_CAMERA_SNAPSHOT_PM8038,
+		.wakeup = 1,
+		.active_low = 1,
+		.debounce_interval = 15,
+	},
+};
+
+static struct gpio_keys_button keys_8930_pm8917[] = {
+	{
+		.code = KEY_VOLUMEUP,
+		.type = EV_KEY,
+		.desc = "volume_up",
+		.gpio = GPIO_VOLUME_UP_PM8917,
+		.wakeup = 1,
+		.active_low = 1,
+		.debounce_interval = 15,
+	},
+	{
+		.code = KEY_VOLUMEDOWN,
+		.type = EV_KEY,
+		.desc = "volume_down",
+		.gpio = GPIO_VOLUME_DOWN_PM8917,
+		.wakeup = 1,
+		.active_low = 1,
+		.debounce_interval = 15,
+	},
+	{
+		.code = KEY_CAMERA_FOCUS,
+		.type = EV_KEY,
+		.desc = "camera_focus",
+		.gpio = GPIO_CAMERA_FOCUS_PM8917,
+		.wakeup = 1,
+		.active_low = 1,
+		.debounce_interval = 15,
+	},
+	{
+		.code = KEY_CAMERA_SNAPSHOT,
+		.type = EV_KEY,
+		.desc = "camera_snapshot",
+		.gpio = GPIO_CAMERA_SNAPSHOT_PM8917,
 		.wakeup = 1,
 		.active_low = 1,
 		.debounce_interval = 15,
@@ -2008,8 +2132,8 @@
 
 /* Add GPIO keys for 8930 */
 static struct gpio_keys_platform_data gpio_keys_8930_pdata = {
-	.buttons = keys_8930,
-	.nbuttons = 4,
+	.buttons = keys_8930_pm8038,
+	.nbuttons = ARRAY_SIZE(keys_8930_pm8038),
 };
 
 static struct platform_device gpio_keys_8930 = {
@@ -2075,7 +2199,7 @@
 	.name	= "saw-regulator",
 	.id	= 0,
 	.dev	= {
-		.platform_data = &msm8930_saw_regulator_core0_pdata,
+		.platform_data = &msm8930_pm8038_saw_regulator_core0_pdata,
 	},
 };
 
@@ -2083,7 +2207,7 @@
 	.name	= "saw-regulator",
 	.id	= 1,
 	.dev	= {
-		.platform_data = &msm8930_saw_regulator_core1_pdata,
+		.platform_data = &msm8930_pm8038_saw_regulator_core1_pdata,
 	},
 };
 
@@ -2140,8 +2264,8 @@
 	.name	= GPIO_REGULATOR_DEV_NAME,
 	.id	= 63,
 	.dev	= {
-		.platform_data =
-		     &msm8930_gpio_regulator_pdata[MSM8930_GPIO_VREG_ID_EXT_5V],
+		.platform_data = &msm8930_pm8038_gpio_regulator_pdata[
+					MSM8930_GPIO_VREG_ID_EXT_5V],
 	},
 };
 
@@ -2149,8 +2273,8 @@
 	.name	= GPIO_REGULATOR_DEV_NAME,
 	.id	= 97,
 	.dev	= {
-		.platform_data =
-		 &msm8930_gpio_regulator_pdata[MSM8930_GPIO_VREG_ID_EXT_OTG_SW],
+		.platform_data = &msm8930_pm8038_gpio_regulator_pdata[
+					MSM8930_GPIO_VREG_ID_EXT_OTG_SW],
 	},
 };
 
@@ -2163,18 +2287,22 @@
 #ifndef MSM8930_PHASE_2
 		.platform_data = &msm_rpm_regulator_pdata,
 #else
-		.platform_data = &msm8930_rpm_regulator_pdata,
+		.platform_data = &msm8930_pm8038_rpm_regulator_pdata,
 #endif
 	},
 };
 
-static struct platform_device *common_devices[] __initdata = {
+static struct platform_device *early_common_devices[] __initdata = {
 	&msm8960_device_dmov,
 	&msm_device_smd,
 	&msm8960_device_uart_gsbi5,
 	&msm_device_uart_dm6,
 	&msm_device_saw_core0,
 	&msm_device_saw_core1,
+};
+
+/* ext_5v and ext_otg_sw are present when using PM8038 */
+static struct platform_device *pmic_pm8038_devices[] __initdata = {
 	&msm8930_device_ext_5v_vreg,
 #ifndef MSM8930_PHASE_2
 	&msm8930_device_ext_l2_vreg,
@@ -2183,6 +2311,14 @@
 #ifdef MSM8930_PHASE_2
 	&msm8930_device_ext_otg_sw_vreg,
 #endif
+};
+
+/* ext_5v and ext_otg_sw are not present when using PM8917 */
+static struct platform_device *pmic_pm8917_devices[] __initdata = {
+	&msm8960_device_ssbi_pmic,
+};
+
+static struct platform_device *common_devices[] __initdata = {
 	&msm_8960_q6_lpass,
 	&msm_8960_q6_mss_fw,
 	&msm_8960_q6_mss_sw,
@@ -2297,6 +2433,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)
@@ -2326,6 +2464,13 @@
 	},
 
 	{
+		MSM_PM_SLEEP_MODE_RETENTION,
+		MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE),
+		true,
+		415, 715, 340827, 475,
+	},
+
+	{
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE,
 		MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE),
 		true,
@@ -2402,6 +2547,33 @@
 	},
 };
 
+static struct msm_rpmrs_platform_data msm_rpmrs_data_pm8917 __initdata = {
+	.levels = &msm_rpmrs_levels[0],
+	.num_levels = ARRAY_SIZE(msm_rpmrs_levels),
+	.vdd_mem_levels  = {
+		[MSM_RPMRS_VDD_MEM_RET_LOW]	= 750000,
+		[MSM_RPMRS_VDD_MEM_RET_HIGH]	= 750000,
+		[MSM_RPMRS_VDD_MEM_ACTIVE]	= 1050000,
+		[MSM_RPMRS_VDD_MEM_MAX]		= 1150000,
+	},
+	.vdd_dig_levels = {
+		[MSM_RPMRS_VDD_DIG_RET_LOW]	= 0,
+		[MSM_RPMRS_VDD_DIG_RET_HIGH]	= 0,
+		[MSM_RPMRS_VDD_DIG_ACTIVE]	= 1,
+		[MSM_RPMRS_VDD_DIG_MAX]		= 3,
+	},
+	.vdd_mask = 0x7FFFFF,
+	.rpmrs_target_id = {
+		[MSM_RPMRS_ID_PXO_CLK]		= MSM_RPM_ID_PXO_CLK,
+		[MSM_RPMRS_ID_L2_CACHE_CTL]	= MSM_RPM_ID_LAST,
+		[MSM_RPMRS_ID_VDD_DIG_0]	= MSM_RPM_ID_VOLTAGE_CORNER,
+		[MSM_RPMRS_ID_VDD_DIG_1]	= MSM_RPM_ID_LAST,
+		[MSM_RPMRS_ID_VDD_MEM_0]	= MSM_RPM_ID_PM8917_L24_0,
+		[MSM_RPMRS_ID_VDD_MEM_1]	= MSM_RPM_ID_PM8917_L24_1,
+		[MSM_RPMRS_ID_RPM_CTL]		= MSM_RPM_ID_RPM_CTL,
+	},
+};
+
 static struct msm_pm_boot_platform_data msm_pm_boot_pdata __initdata = {
 	.mode = MSM_PM_BOOT_CONFIG_TZ,
 };
@@ -2431,6 +2603,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,
 	},
 };
@@ -2567,23 +2740,59 @@
 #endif
 }
 
+/* Modify platform data values to match requirements for PM8917. */
+static void __init msm8930_pm8917_pdata_fixup(void)
+{
+	struct acpuclk_platform_data *pdata;
+
+	mhl_platform_data.gpio_mhl_power = MHL_POWER_GPIO_PM8917;
+
+	gpio_keys_8930_pdata.buttons = keys_8930_pm8917;
+	gpio_keys_8930_pdata.nbuttons = ARRAY_SIZE(keys_8930_pm8917);
+
+	msm_device_saw_core0.dev.platform_data
+		= &msm8930_pm8038_saw_regulator_core0_pdata;
+	msm_device_saw_core1.dev.platform_data
+		= &msm8930_pm8038_saw_regulator_core1_pdata;
+
+	msm8930_device_rpm_regulator.dev.platform_data
+		= &msm8930_pm8917_rpm_regulator_pdata;
+
+	pdata = msm8930_device_acpuclk.dev.platform_data;
+	pdata->uses_pm8917 = true;
+}
+
 static void __init msm8930_cdp_init(void)
 {
+	if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917)
+		msm8930_pm8917_pdata_fixup();
 	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));
-	BUG_ON(msm_rpmrs_levels_init(&msm_rpmrs_data));
+	if (socinfo_get_pmic_model() != PMIC_MODEL_PM8917) {
+		BUG_ON(msm_rpm_init(&msm8930_rpm_data));
+		BUG_ON(msm_rpmrs_levels_init(&msm_rpmrs_data));
+	} else {
+		BUG_ON(msm_rpm_init(&msm8930_rpm_data_pm8917));
+		BUG_ON(msm_rpmrs_levels_init(&msm_rpmrs_data_pm8917));
+	}
 
 	regulator_suppress_info_printing();
 	if (msm_xo_init())
 		pr_err("Failed to initialize XO votes\n");
 	platform_device_register(&msm8930_device_rpm_regulator);
-	msm_clock_init(&msm8930_clock_init_data);
+	if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917)
+		msm_clock_init(&msm8930_pm8917_clock_init_data);
+	else
+		msm_clock_init(&msm8930_clock_init_data);
 	msm_otg_pdata.phy_init_seq = hsusb_phy_init_seq;
+	if (msm8930_mhl_display_enabled()) {
+		mhl_platform_data.mhl_enabled = true;
+		msm_otg_pdata.mhl_enable = true;
+	}
 	msm8960_device_otg.dev.platform_data = &msm_otg_pdata;
 	android_usb_pdata.swfi_latency =
 			msm_rpmrs_levels[0].latency_us;
@@ -2619,6 +2828,14 @@
 		platform_device_register(&msm8930_device_acpuclk);
 	else if (cpu_is_msm8930aa())
 		platform_device_register(&msm8930aa_device_acpuclk);
+	platform_add_devices(early_common_devices,
+				ARRAY_SIZE(early_common_devices));
+	if (socinfo_get_pmic_model() != PMIC_MODEL_PM8917)
+		platform_add_devices(pmic_pm8038_devices,
+					ARRAY_SIZE(pmic_pm8038_devices));
+	else
+		platform_add_devices(pmic_pm8917_devices,
+					ARRAY_SIZE(pmic_pm8917_devices));
 	platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
 	msm8930_add_vidc_device();
 	/*
@@ -2629,7 +2846,10 @@
 #ifndef MSM8930_PHASE_2
 	msm8960_pm8921_gpio_mpp_init();
 #else
-	msm8930_pm8038_gpio_mpp_init();
+	if (socinfo_get_pmic_model() != PMIC_MODEL_PM8917)
+		msm8930_pm8038_gpio_mpp_init();
+	else
+		msm8930_pm8917_gpio_mpp_init();
 #endif
 	platform_add_devices(cdp_devices, ARRAY_SIZE(cdp_devices));
 #ifdef CONFIG_MSM_CAMERA
@@ -2643,6 +2863,7 @@
 		ARRAY_SIZE(msm_slim_devices));
 	change_memory_power = &msm8930_change_memory_power;
 	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
+	msm_pm_set_tz_retention_flag(1);
 
 	if (PLATFORM_IS_CHARM25())
 		platform_add_devices(mdm_devices, ARRAY_SIZE(mdm_devices));
diff --git a/arch/arm/mach-msm/board-8930.h b/arch/arm/mach-msm/board-8930.h
index 9f6276c..055576f 100644
--- a/arch/arm/mach-msm/board-8930.h
+++ b/arch/arm/mach-msm/board-8930.h
@@ -17,6 +17,7 @@
 
 #include <linux/regulator/msm-gpio-regulator.h>
 #include <linux/mfd/pm8xxx/pm8038.h>
+#include <linux/mfd/pm8xxx/pm8921.h>
 #include <linux/i2c.h>
 #include <linux/i2c/sx150x.h>
 #include <mach/irqs.h>
@@ -37,12 +38,23 @@
 #endif
 
 /* Macros assume PMIC GPIOs and MPPs start at 1 */
+/*
+ * PM8917 has more GPIOs and MPPs than PM8038; therefore, use PM8038 sizes at
+ * all times so that PM8038 vs PM8917 can be chosen at runtime.  This results in
+ * the Linux GPIO address space being contiguous for PM8917 and discontiguous
+ * for PM8038.
+ */
 #define PM8038_GPIO_BASE		NR_GPIO_IRQS
 #define PM8038_GPIO_PM_TO_SYS(pm_gpio)	(pm_gpio - 1 + PM8038_GPIO_BASE)
-#define PM8038_MPP_BASE			(PM8038_GPIO_BASE + PM8038_NR_GPIOS)
+#define PM8038_MPP_BASE			(PM8038_GPIO_BASE + PM8917_NR_GPIOS)
 #define PM8038_MPP_PM_TO_SYS(pm_gpio)	(pm_gpio - 1 + PM8038_MPP_BASE)
 #define PM8038_IRQ_BASE			(NR_MSM_IRQS + NR_GPIO_IRQS)
 
+/* These PM8917 alias macros are used to provide context in board files. */
+#define PM8917_GPIO_PM_TO_SYS(pm_gpio)	PM8038_GPIO_PM_TO_SYS(pm_gpio)
+#define PM8917_MPP_PM_TO_SYS(pm_gpio)	PM8038_MPP_PM_TO_SYS(pm_gpio)
+#define PM8917_IRQ_BASE			PM8038_IRQ_BASE
+
 /*
  * TODO: When physical 8930/PM8038 hardware becomes
  * available, replace this block with 8930/pm8038 regulator
@@ -64,27 +76,36 @@
 #define GPIO_VREG_ID_EXT_3P3V		2
 #endif
 
-extern struct regulator_init_data msm8930_saw_regulator_core0_pdata;
-extern struct regulator_init_data msm8930_saw_regulator_core1_pdata;
+extern struct regulator_init_data msm8930_pm8038_saw_regulator_core0_pdata;
+extern struct regulator_init_data msm8930_pm8038_saw_regulator_core1_pdata;
+extern struct regulator_init_data msm8930_pm8917_saw_regulator_core0_pdata;
+extern struct regulator_init_data msm8930_pm8917_saw_regulator_core1_pdata;
 
 extern struct pm8xxx_regulator_platform_data
 	msm8930_pm8038_regulator_pdata[] __devinitdata;
-
 extern int msm8930_pm8038_regulator_pdata_len __devinitdata;
 
+extern struct pm8xxx_regulator_platform_data
+	msm8930_pm8917_regulator_pdata[] __devinitdata;
+extern int msm8930_pm8917_regulator_pdata_len __devinitdata;
+
 #define MSM8930_GPIO_VREG_ID_EXT_5V		0
 #define MSM8930_GPIO_VREG_ID_EXT_OTG_SW		1
 
 extern struct gpio_regulator_platform_data
-	msm8930_gpio_regulator_pdata[] __devinitdata;
+	msm8930_pm8038_gpio_regulator_pdata[] __devinitdata;
+extern struct gpio_regulator_platform_data
+	msm8930_pm8917_gpio_regulator_pdata[] __devinitdata;
 
 extern struct rpm_regulator_platform_data
-	msm8930_rpm_regulator_pdata __devinitdata;
+	msm8930_pm8038_rpm_regulator_pdata __devinitdata;
+extern struct rpm_regulator_platform_data
+	msm8930_pm8917_rpm_regulator_pdata __devinitdata;
 
 #if defined(CONFIG_GPIO_SX150X) || defined(CONFIG_GPIO_SX150X_MODULE)
 enum {
 	GPIO_EXPANDER_IRQ_BASE = (PM8038_IRQ_BASE + PM8038_NR_IRQS),
-	GPIO_EXPANDER_GPIO_BASE = (PM8038_MPP_BASE + PM8038_NR_MPPS),
+	GPIO_EXPANDER_GPIO_BASE = (PM8038_MPP_BASE + PM8917_NR_MPPS),
 	/* CAM Expander */
 	GPIO_CAM_EXPANDER_BASE = GPIO_EXPANDER_GPIO_BASE,
 	GPIO_CAM_GP_STROBE_READY = GPIO_CAM_EXPANDER_BASE,
@@ -111,6 +132,7 @@
 void msm8930_init_fb(void);
 void msm8930_init_pmic(void);
 extern void msm8930_add_vidc_device(void);
+unsigned char msm8930_mhl_display_enabled(void);
 
 /*
  * TODO: When physical 8930/PM8038 hardware becomes
@@ -126,6 +148,8 @@
 int msm8930_init_gpiomux(void);
 void msm8930_allocate_fb_region(void);
 void msm8930_pm8038_gpio_mpp_init(void);
+void msm8930_pm8917_gpio_mpp_init(void);
+void msm8930_set_display_params(char *prim_panel, char *ext_panel);
 void msm8930_mdp_writeback(struct memtype_reserve *reserve_table);
 void __init msm8930_init_gpu(void);
 
diff --git a/arch/arm/mach-msm/board-8960-camera.c b/arch/arm/mach-msm/board-8960-camera.c
index a21c4c3..792eea4 100644
--- a/arch/arm/mach-msm/board-8960-camera.c
+++ b/arch/arm/mach-msm/board-8960-camera.c
@@ -13,7 +13,7 @@
 
 #include <asm/mach-types.h>
 #include <linux/gpio.h>
-#include <mach/board.h>
+#include <mach/camera.h>
 #include <mach/msm_bus_board.h>
 #include <mach/gpiomux.h>
 #include "devices.h"
@@ -400,6 +400,40 @@
 	},
 };
 
+static struct msm_bus_vectors cam_dual_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 348192000,
+		.ib  = 1208286720,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 206807040,
+		.ib  = 488816640,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 540000000,
+		.ib  = 1350000000,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_MM_IMEM,
+		.ab  = 43200000,
+		.ib  = 69120000,
+	},
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_MM_IMEM,
+		.ab  = 43200000,
+		.ib  = 69120000,
+	},
+};
+
+
 
 static struct msm_bus_paths cam_bus_client_config[] = {
 	{
@@ -426,6 +460,10 @@
 		ARRAY_SIZE(cam_video_ls_vectors),
 		cam_video_ls_vectors,
 	},
+	{
+		ARRAY_SIZE(cam_dual_vectors),
+		cam_dual_vectors,
+	},
 };
 
 static struct msm_bus_scale_pdata cam_bus_client_pdata = {
@@ -452,19 +490,13 @@
 	},
 };
 
-static struct camera_vreg_t msm_8960_back_cam_vreg[] = {
+static struct camera_vreg_t msm_8960_cam_vreg[] = {
 	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
 	{"cam_vio", REG_VS, 0, 0, 0},
 	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
 	{"cam_vaf", REG_LDO, 2800000, 2800000, 300000},
 };
 
-static struct camera_vreg_t msm_8960_front_cam_vreg[] = {
-	{"cam_vio", REG_VS, 0, 0, 0},
-	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
-	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
-};
-
 static struct gpio msm8960_common_cam_gpio[] = {
 	{5, GPIOF_DIR_IN, "CAMIF_MCLK"},
 	{20, GPIOF_DIR_IN, "CAMIF_I2C_DATA"},
@@ -549,8 +581,8 @@
 
 static struct msm_camera_sensor_platform_info sensor_board_info_imx074 = {
 	.mount_angle	= 90,
-	.cam_vreg = msm_8960_back_cam_vreg,
-	.num_vreg = ARRAY_SIZE(msm_8960_back_cam_vreg),
+	.cam_vreg = msm_8960_cam_vreg,
+	.num_vreg = ARRAY_SIZE(msm_8960_cam_vreg),
 	.gpio_conf = &msm_8960_back_cam_gpio_conf,
 	.csi_lane_params = &imx074_csi_lane_params,
 };
@@ -577,13 +609,6 @@
 	.eeprom_info = &imx074_eeprom_info,
 };
 
-static struct camera_vreg_t msm_8960_mt9m114_vreg[] = {
-	{"cam_vio", REG_VS, 0, 0, 0},
-	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
-	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
-	{"cam_vaf", REG_LDO, 2800000, 2800000, 300000},
-};
-
 static struct msm_camera_sensor_flash_data flash_mt9m114 = {
 	.flash_type = MSM_CAMERA_FLASH_NONE
 };
@@ -593,10 +618,16 @@
 	.csi_lane_mask = 0x1,
 };
 
+static struct camera_vreg_t mt9m114_cam_vreg[] = {
+	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000, 50},
+	{"cam_vio", REG_VS, 0, 0, 0, 50},
+	{"cam_vana", REG_LDO, 2800000, 2850000, 85600, 50},
+};
+
 static struct msm_camera_sensor_platform_info sensor_board_info_mt9m114 = {
 	.mount_angle = 90,
-	.cam_vreg = msm_8960_mt9m114_vreg,
-	.num_vreg = ARRAY_SIZE(msm_8960_mt9m114_vreg),
+	.cam_vreg = mt9m114_cam_vreg,
+	.num_vreg = ARRAY_SIZE(mt9m114_cam_vreg),
 	.gpio_conf = &msm_8960_front_cam_gpio_conf,
 	.csi_lane_params = &mt9m114_csi_lane_params,
 };
@@ -622,8 +653,8 @@
 
 static struct msm_camera_sensor_platform_info sensor_board_info_ov2720 = {
 	.mount_angle	= 0,
-	.cam_vreg = msm_8960_front_cam_vreg,
-	.num_vreg = ARRAY_SIZE(msm_8960_front_cam_vreg),
+	.cam_vreg = msm_8960_cam_vreg,
+	.num_vreg = ARRAY_SIZE(msm_8960_cam_vreg),
 	.gpio_conf = &msm_8960_front_cam_gpio_conf,
 	.csi_lane_params = &ov2720_csi_lane_params,
 };
@@ -638,13 +669,6 @@
 	.sensor_type = BAYER_SENSOR,
 };
 
-static struct camera_vreg_t msm_8960_s5k3l1yx_vreg[] = {
-	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
-	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
-	{"cam_vio", REG_VS, 0, 0, 0},
-	{"cam_vaf", REG_LDO, 2800000, 2800000, 300000},
-};
-
 static struct msm_camera_sensor_flash_data flash_s5k3l1yx = {
 	.flash_type = MSM_CAMERA_FLASH_NONE,
 };
@@ -656,8 +680,8 @@
 
 static struct msm_camera_sensor_platform_info sensor_board_info_s5k3l1yx = {
 	.mount_angle  = 0,
-	.cam_vreg = msm_8960_s5k3l1yx_vreg,
-	.num_vreg = ARRAY_SIZE(msm_8960_s5k3l1yx_vreg),
+	.cam_vreg = msm_8960_cam_vreg,
+	.num_vreg = ARRAY_SIZE(msm_8960_cam_vreg),
 	.gpio_conf = &msm_8960_back_cam_gpio_conf,
 	.csi_lane_params = &s5k3l1yx_csi_lane_params,
 };
@@ -686,13 +710,6 @@
 	.csi_lane_mask = 0xF,
 };
 
-static struct camera_vreg_t msm_8960_imx091_vreg[] = {
-	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
-	{"cam_vaf", REG_LDO, 2800000, 2800000, 300000},
-	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
-	{"cam_vio", REG_VS, 0, 0, 0},
-};
-
 static struct msm_camera_sensor_flash_data flash_imx091 = {
 	.flash_type	= MSM_CAMERA_FLASH_LED,
 #ifdef CONFIG_MSM_CAMERA_FLASH
@@ -702,8 +719,8 @@
 
 static struct msm_camera_sensor_platform_info sensor_board_info_imx091 = {
 	.mount_angle	= 0,
-	.cam_vreg = msm_8960_imx091_vreg,
-	.num_vreg = ARRAY_SIZE(msm_8960_imx091_vreg),
+	.cam_vreg = msm_8960_cam_vreg,
+	.num_vreg = ARRAY_SIZE(msm_8960_cam_vreg),
 	.gpio_conf = &msm_8960_back_cam_gpio_conf,
 	.csi_lane_params = &imx091_csi_lane_params,
 };
@@ -715,6 +732,9 @@
 static struct msm_eeprom_info imx091_eeprom_info = {
 	.board_info     = &imx091_eeprom_i2c_info,
 	.bus_id         = MSM_8960_GSBI4_QUP_I2C_BUS_ID,
+	.eeprom_i2c_slave_addr = 0xA1,
+	.eeprom_reg_addr = 0x05,
+	.eeprom_read_length = 6,
 };
 
 static struct msm_camera_sensor_info msm_camera_sensor_imx091_data = {
diff --git a/arch/arm/mach-msm/board-8960-display.c b/arch/arm/mach-msm/board-8960-display.c
index ddeba32..3052902 100644
--- a/arch/arm/mach-msm/board-8960-display.c
+++ b/arch/arm/mach-msm/board-8960-display.c
@@ -15,7 +15,7 @@
 #include <linux/ioport.h>
 #include <linux/platform_device.h>
 #include <linux/bootmem.h>
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
 #include <linux/gpio.h>
 #include <asm/mach-types.h>
 #include <mach/msm_bus_board.h>
@@ -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
@@ -595,6 +586,8 @@
 	.mem_hid = MEMTYPE_EBI1,
 #endif
 	.cont_splash_enabled = 0x01,
+	.splash_screen_addr = 0x00,
+	.splash_screen_size = 0x00,
 	.mdp_iommu_split_domain = 0,
 };
 
@@ -1043,8 +1036,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 +1045,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-pmic.c b/arch/arm/mach-msm/board-8960-pmic.c
index 5950026..244125c 100644
--- a/arch/arm/mach-msm/board-8960-pmic.c
+++ b/arch/arm/mach-msm/board-8960-pmic.c
@@ -109,7 +109,7 @@
 	PM8XXX_GPIO_OUTPUT(43, 1),                       /* DISP_RESET_N */
 	PM8XXX_GPIO_OUTPUT(42, 0),                      /* USB 5V reg enable */
 	/* TABLA CODEC RESET */
-	PM8XXX_GPIO_OUTPUT_STRENGTH(34, 1, PM_GPIO_STRENGTH_MED)
+	PM8XXX_GPIO_OUTPUT_STRENGTH(34, 0, PM_GPIO_STRENGTH_MED)
 };
 
 /* Initial PM8921 MPP configurations */
@@ -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,
@@ -401,7 +402,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,
@@ -420,12 +421,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 */
@@ -600,6 +603,8 @@
 		pm8921_platform_data.bms_pdata->battery_type = BATT_DESAY;
 	} else if (machine_is_msm8960_mtp()) {
 		pm8921_platform_data.bms_pdata->battery_type = BATT_PALLADIUM;
+	} else if (machine_is_msm8960_cdp()) {
+		pm8921_chg_pdata.has_dc_supply = true;
 	}
 
 	if (machine_is_msm8960_fluid())
diff --git a/arch/arm/mach-msm/board-8960-regulator.c b/arch/arm/mach-msm/board-8960-regulator.c
index 6ad44d8..8fc26ea 100644
--- a/arch/arm/mach-msm/board-8960-regulator.c
+++ b/arch/arm/mach-msm/board-8960-regulator.c
@@ -14,6 +14,7 @@
 #include <linux/regulator/pm8xxx-regulator.h>
 #include <linux/regulator/msm-gpio-regulator.h>
 #include <mach/rpm-regulator.h>
+#include <mach/socinfo.h>
 
 #include "board-8960.h"
 
@@ -182,10 +183,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),
@@ -217,9 +220,16 @@
 	REGULATOR_SUPPLY("cam_vio",		"4-0020"),
 	REGULATOR_SUPPLY("cam_vio",		"4-0034"),
 };
+/* This mapping is used for CDP only. */
+VREG_CONSUMERS(CDP_LVS6) = {
+	REGULATOR_SUPPLY("8921_lvs6",		NULL),
+	REGULATOR_SUPPLY("vdd-io",		"spi0.0"),
+};
+/* This mapping is used for non-CDP targets only. */
 VREG_CONSUMERS(LVS6) = {
 	REGULATOR_SUPPLY("8921_lvs6",		NULL),
-	REGULATOR_SUPPLY("vdd_io",		"spi0.0"),
+	REGULATOR_SUPPLY("vdd-io",		"spi0.0"),
+	REGULATOR_SUPPLY("vdd-phy",		"spi0.0"),
 };
 VREG_CONSUMERS(LVS7) = {
 	REGULATOR_SUPPLY("8921_lvs7",		NULL),
@@ -239,7 +249,7 @@
 };
 VREG_CONSUMERS(EXT_L2) = {
 	REGULATOR_SUPPLY("ext_l2",		NULL),
-	REGULATOR_SUPPLY("vdd_phy",		"spi0.0"),
+	REGULATOR_SUPPLY("vdd-phy",		"spi0.0"),
 };
 VREG_CONSUMERS(EXT_3P3V) = {
 	REGULATOR_SUPPLY("ext_3p3v",		NULL),
@@ -581,6 +591,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 = {
@@ -592,3 +613,26 @@
 	.consumer_map		= msm_rpm_regulator_consumer_mapping,
 	.consumer_map_len = ARRAY_SIZE(msm_rpm_regulator_consumer_mapping),
 };
+
+/*
+ * Fix up regulator consumer data that moves to a different regulator based on
+ * the current target.
+ */
+void __init configure_msm8960_power_grid(void)
+{
+	static struct rpm_regulator_init_data *rpm_data;
+	int i;
+
+	if (machine_is_msm8960_cdp()) {
+		/* Only modify LVS6 consumers for CDP targets. */
+		for (i = 0; i < ARRAY_SIZE(msm_rpm_regulator_init_data); i++) {
+			rpm_data = &msm_rpm_regulator_init_data[i];
+			if (rpm_data->id == RPM_VREG_ID_PM8921_LVS6) {
+				rpm_data->init_data.consumer_supplies
+					= vreg_consumers_CDP_LVS6;
+				rpm_data->init_data.num_consumer_supplies
+					= ARRAY_SIZE(vreg_consumers_CDP_LVS6);
+			}
+		}
+	}
+}
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index ad788bc..a54c3e2 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -77,7 +77,7 @@
 #endif
 
 #include <linux/smsc3503.h>
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
 #include <mach/ion.h>
 #include <mach/mdm2.h>
 #include <mach/mdm-peripheral.h>
@@ -145,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
@@ -173,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
@@ -336,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
 }
 
@@ -1056,6 +1056,12 @@
 		.ab = 0,
 	},
 	{
+		.src = MSM_BUS_MASTER_SPS,
+		.dst = MSM_BUS_SLAVE_SPS,
+		.ib = 0,
+		.ab = 0,
+	},
+	{
 		.src = MSM_BUS_MASTER_SPDM,
 		.dst = MSM_BUS_SLAVE_SPDM,
 		.ib = 0,
@@ -1071,6 +1077,12 @@
 		.ab = (492 * 8) *  100000UL,
 	},
 	{
+		.src = MSM_BUS_MASTER_SPS,
+		.dst = MSM_BUS_SLAVE_SPS,
+		.ib = (492 * 8) * 1000000UL,
+		.ab = (492 * 8) * 100000UL,
+	},
+	{
 		.src = MSM_BUS_MASTER_SPDM,
 		.dst = MSM_BUS_SLAVE_SPDM,
 		.ib = 0,
@@ -1086,6 +1098,12 @@
 		.ab = 0,
 	},
 	{
+		.src = MSM_BUS_MASTER_SPS,
+		.dst = MSM_BUS_SLAVE_SPS,
+		.ib = 0,
+		.ab = 0,
+	},
+	{
 		.src = MSM_BUS_MASTER_SPDM,
 		.dst = MSM_BUS_SLAVE_SPDM,
 		.ib = (64 * 8) * 1000000UL,
@@ -1100,7 +1118,7 @@
 	},
 	{
 		ARRAY_SIZE(qseecom_enable_dfab_vectors),
-		qseecom_enable_sfpb_vectors,
+		qseecom_enable_dfab_vectors,
 	},
 	{
 		ARRAY_SIZE(qseecom_enable_sfpb_vectors),
@@ -1425,7 +1443,7 @@
 
 static struct msm_spi_platform_data msm8960_qup_spi_gsbi1_pdata = {
 	.max_clock_speed = 15060000,
-	.infinite_mode	 = 1
+	.infinite_mode	 = 0xFFC0,
 };
 
 #ifdef CONFIG_USB_MSM_OTG_72K
@@ -1434,7 +1452,7 @@
 static int wr_phy_init_seq[] = {
 	0x44, 0x80, /* set VBUS valid threshold
 			and disconnect valid threshold */
-	0x38, 0x81, /* update DC voltage level */
+	0x68, 0x81, /* update DC voltage level */
 	0x14, 0x82, /* set preemphasis and rise/fall time */
 	0x13, 0x83, /* set source impedance adjusment */
 	-1};
@@ -1442,11 +1460,19 @@
 static int liquid_v1_phy_init_seq[] = {
 	0x44, 0x80,/* set VBUS valid threshold
 			and disconnect valid threshold */
-	0x3C, 0x81,/* update DC voltage level */
+	0x6C, 0x81,/* update DC voltage level */
 	0x18, 0x82,/* set preemphasis and rise/fall time */
 	0x23, 0x83,/* set source impedance sdjusment */
 	-1};
 
+static int sglte_phy_init_seq[] = {
+	0x44, 0x80, /* set VBUS valid threshold
+			and disconnect valid threshold */
+	0x6A, 0x81, /* update DC voltage level */
+	0x24, 0x82, /* set preemphasis and rise/fall time */
+	0x13, 0x83, /* set source impedance adjusment */
+	-1};
+
 #ifdef CONFIG_MSM_BUS_SCALING
 /* Bandwidth requests (zero) if no vote placed */
 static struct msm_bus_vectors usb_init_vectors[] = {
@@ -1595,6 +1621,11 @@
 			0x03, 0x0f,
 };
 
+static uint8_t spm_retention_cmd_sequence[] __initdata = {
+			0x00, 0x05, 0x03, 0x0D,
+			0x0B, 0x00, 0x0f,
+};
+
 static uint8_t spm_power_collapse_without_rpm[] __initdata = {
 			0x00, 0x24, 0x54, 0x10,
 			0x09, 0x03, 0x01,
@@ -1609,7 +1640,32 @@
 			0x24, 0x30, 0x0f,
 };
 
-static struct msm_spm_seq_entry msm_spm_seq_list[] __initdata = {
+static struct msm_spm_seq_entry msm_spm_boot_cpu_seq_list[] __initdata = {
+	[0] = {
+		.mode = MSM_SPM_MODE_CLOCK_GATING,
+		.notify_rpm = false,
+		.cmd = spm_wfi_cmd_sequence,
+	},
+
+	[1] = {
+		.mode = MSM_SPM_MODE_POWER_RETENTION,
+		.notify_rpm = false,
+		.cmd = spm_retention_cmd_sequence,
+	},
+
+	[2] = {
+		.mode = MSM_SPM_MODE_POWER_COLLAPSE,
+		.notify_rpm = false,
+		.cmd = spm_power_collapse_without_rpm,
+	},
+	[3] = {
+		.mode = MSM_SPM_MODE_POWER_COLLAPSE,
+		.notify_rpm = true,
+		.cmd = spm_power_collapse_with_rpm,
+	},
+};
+
+static struct msm_spm_seq_entry msm_spm_nonboot_cpu_seq_list[] __initdata = {
 	[0] = {
 		.mode = MSM_SPM_MODE_CLOCK_GATING,
 		.notify_rpm = false,
@@ -1636,12 +1692,12 @@
 		.reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x00,
 #endif
 		.reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01,
-		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020204,
-		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0060009C,
-		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x0000001C,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x03020004,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0084009C,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x00A4001C,
 		.vctl_timeout_us = 50,
-		.num_modes = ARRAY_SIZE(msm_spm_seq_list),
-		.modes = msm_spm_seq_list,
+		.num_modes = ARRAY_SIZE(msm_spm_boot_cpu_seq_list),
+		.modes = msm_spm_boot_cpu_seq_list,
 	},
 	[1] = {
 		.reg_base_addr = MSM_SAW1_BASE,
@@ -1655,8 +1711,8 @@
 		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0060009C,
 		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x0000001C,
 		.vctl_timeout_us = 50,
-		.num_modes = ARRAY_SIZE(msm_spm_seq_list),
-		.modes = msm_spm_seq_list,
+		.num_modes = ARRAY_SIZE(msm_spm_nonboot_cpu_seq_list),
+		.modes = msm_spm_nonboot_cpu_seq_list,
 	},
 };
 
@@ -2409,6 +2465,13 @@
 };
 #endif
 
+#ifdef CONFIG_BATTERY_BCL
+static struct platform_device battery_bcl_device = {
+	.name = "battery_current_limit",
+	.id = -1,
+};
+#endif
+
 static struct platform_device msm8960_device_ext_5v_vreg __devinitdata = {
 	.name	= GPIO_REGULATOR_DEV_NAME,
 	.id	= PM8921_MPP_PM_TO_SYS(7),
@@ -2550,43 +2613,42 @@
 {
 	int rc;
 
+	pr_debug("%s on= %d\n", __func__, on);
+
 	if (on) {
-		rc = gpio_direction_output(gpio_bt_sys_rest_en, 1);
+		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);
+			goto out;
+		}
+		rc = gpio_direction_output(gpio_bt_sys_rest_en, 0);
+		if (rc) {
+			pr_err("%s: Unable to set gpio %d direction\n",
+				__func__, gpio_bt_sys_rest_en);
+			goto free_gpio;
+		}
 		msleep(100);
+		gpio_set_value(gpio_bt_sys_rest_en, 1);
+		msleep(100);
+		goto out;
 	} 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;
+
+free_gpio:
+	gpio_free(gpio_bt_sys_rest_en);
+out:
+	return rc;
 }
 
 static void __init bt_power_init(void)
 {
-	int rc;
-
+	pr_debug("%s enter\n", __func__);
 	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
@@ -2594,7 +2656,6 @@
 #endif
 
 static struct platform_device *common_devices[] __initdata = {
-	&msm8960_device_acpuclk,
 	&msm8960_device_dmov,
 	&msm_device_smd,
 	&msm_device_uart_dm6,
@@ -2635,6 +2696,9 @@
 #ifdef CONFIG_MSM_FAKE_BATTERY
 	&fish_battery_device,
 #endif
+#ifdef CONFIG_BATTERY_BCL
+	&battery_bcl_device,
+#endif
 	&msm8960_fmem_device,
 #ifdef CONFIG_ANDROID_PMEM
 #ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
@@ -2643,7 +2707,6 @@
 	&msm8960_android_pmem_audio_device,
 #endif
 #endif
-	&msm_device_vidc,
 	&msm_device_bam_dmux,
 	&msm_fm_platform_init,
 #if defined(CONFIG_TSIF) || defined(CONFIG_TSIF_MODULE)
@@ -2684,8 +2747,6 @@
 
 static struct platform_device *cdp_devices[] __initdata = {
 	&msm_8960_q6_lpass,
-	&msm_8960_q6_mss_fw,
-	&msm_8960_q6_mss_sw,
 	&msm_8960_riva,
 	&msm_pil_tzapps,
 	&msm_pil_dsps,
@@ -2696,6 +2757,7 @@
 	&android_usb_device,
 	&msm_pcm,
 	&msm_multi_ch_pcm,
+	&msm_lowlatency_pcm,
 	&msm_pcm_routing,
 	&msm_cpudai0,
 	&msm_cpudai1,
@@ -2710,11 +2772,6 @@
 	&msm_cpudai_auxpcm_tx,
 	&msm_cpu_fe,
 	&msm_stub_codec,
-	&msm_kgsl_3d0,
-#ifdef CONFIG_MSM_KGSL_2D
-	&msm_kgsl_2d0,
-	&msm_kgsl_2d1,
-#endif
 #ifdef CONFIG_MSM_GEMINI
 	&msm8960_gemini_device,
 #endif
@@ -2743,6 +2800,9 @@
 
 static void __init msm8960_i2c_init(void)
 {
+	if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE)
+		msm8960_i2c_qup_gsbi4_pdata.keep_ahb_clk_on = 1;
+
 	msm8960_device_qup_i2c_gsbi4.dev.platform_data =
 					&msm8960_i2c_qup_gsbi4_pdata;
 
@@ -2762,21 +2822,28 @@
 		msm_kgsl_3d0.dev.platform_data;
 	uint32_t soc_platform_version = socinfo_get_version();
 
-	if (SOCINFO_VERSION_MAJOR(soc_platform_version) == 1) {
-		kgsl_3d0_pdata->pwrlevel[0].gpu_freq = 320000000;
-		kgsl_3d0_pdata->pwrlevel[1].gpu_freq = 266667000;
-	}
 	if (cpu_is_msm8960ab()) {
 		kgsl_3d0_pdata->chipid = ADRENO_CHIPID(3, 2, 1, 0);
-	} else {
-
+		/* 8960PRO nominal clock rate is 325Mhz instead of 320Mhz */
+		kgsl_3d0_pdata->pwrlevel[1].gpu_freq = 325000000;
+	} else if (SOCINFO_VERSION_MAJOR(soc_platform_version) == 1) {
+		kgsl_3d0_pdata->pwrlevel[0].gpu_freq = 320000000;
+		kgsl_3d0_pdata->pwrlevel[1].gpu_freq = 266667000;
+	} else if (SOCINFO_VERSION_MAJOR(soc_platform_version) >= 3) {
 		/* 8960v3 GPU registers returns 5 for patch release
 		 * but it should be 6, so dummy up the chipid here
 		 * based the platform type
 		 */
+		kgsl_3d0_pdata->chipid = ADRENO_CHIPID(2, 2, 0, 6);
+	}
 
-		if (SOCINFO_VERSION_MAJOR(soc_platform_version) >= 3)
-			kgsl_3d0_pdata->chipid = ADRENO_CHIPID(2, 2, 0, 6);
+	/* Register the 3D core */
+	platform_device_register(&msm_kgsl_3d0);
+
+	/* Register the 2D cores if we are not 8960PRO */
+	if (!cpu_is_msm8960ab()) {
+		platform_device_register(&msm_kgsl_2d0);
+		platform_device_register(&msm_kgsl_2d1);
 	}
 }
 
@@ -2789,6 +2856,13 @@
 	},
 
 	{
+		MSM_PM_SLEEP_MODE_RETENTION,
+		MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE),
+		true,
+		415, 715, 340827, 475,
+	},
+
+	{
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE,
 		MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE),
 		true,
@@ -2838,6 +2912,7 @@
 	},
 };
 
+
 static struct msm_rpmrs_platform_data msm_rpmrs_data __initdata = {
 	.levels = &msm_rpmrs_levels[0],
 	.num_levels = ARRAY_SIZE(msm_rpmrs_levels),
@@ -3091,6 +3166,7 @@
 	regulator_suppress_info_printing();
 	if (msm_xo_init())
 		pr_err("Failed to initialize XO votes\n");
+	configure_msm8960_power_grid();
 	platform_device_register(&msm8960_device_rpm_regulator);
 	msm_clock_init(&msm8960_clock_init_data);
 	if (machine_is_msm8960_liquid())
@@ -3098,7 +3174,14 @@
 	msm8960_device_otg.dev.platform_data = &msm_otg_pdata;
 	if (machine_is_msm8960_mtp() || machine_is_msm8960_fluid() ||
 		machine_is_msm8960_cdp()) {
-		msm_otg_pdata.phy_init_seq = wr_phy_init_seq;
+		/* Due to availability of USB Switch in SGLTE Platform
+		 * it requires different HSUSB PHY settings compare to
+		 * 8960 MTP/CDP platform.
+		 */
+		if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE)
+			msm_otg_pdata.phy_init_seq = sglte_phy_init_seq;
+		else
+			msm_otg_pdata.phy_init_seq = wr_phy_init_seq;
 	} else if (machine_is_msm8960_liquid()) {
 			msm_otg_pdata.phy_init_seq =
 				liquid_v1_phy_init_seq;
@@ -3148,8 +3231,19 @@
 		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_add_vidc_device();
+
 	msm8960_pm8921_gpio_mpp_init();
+	/* Don't add modem devices on APQ targets */
+	if (socinfo_get_id() != 124) {
+		platform_device_register(&msm_8960_q6_mss_fw);
+		platform_device_register(&msm_8960_q6_mss_sw);
+	}
 	platform_add_devices(cdp_devices, ARRAY_SIZE(cdp_devices));
 	msm8960_init_smsc_hub();
 	msm8960_init_hsic();
@@ -3171,6 +3265,7 @@
 		mdm_sglte_device.dev.platform_data = &sglte_platform_data;
 		platform_device_register(&mdm_sglte_device);
 	}
+	msm_pm_set_tz_retention_flag(1);
 }
 
 MACHINE_START(MSM8960_CDP, "QCT MSM8960 CDP")
diff --git a/arch/arm/mach-msm/board-8960.h b/arch/arm/mach-msm/board-8960.h
index d986670..382723c 100644
--- a/arch/arm/mach-msm/board-8960.h
+++ b/arch/arm/mach-msm/board-8960.h
@@ -81,6 +81,7 @@
 void msm8960_init_pmic(void);
 void msm8960_init_mmc(void);
 int msm8960_init_gpiomux(void);
+void __init configure_msm8960_power_grid(void);
 unsigned char msm8960_hdmi_as_primary_selected(void);
 void msm8960_allocate_fb_region(void);
 void msm8960_set_display_params(char *prim_panel, char *ext_panel);
@@ -92,3 +93,4 @@
 
 extern struct msm_rtb_platform_data msm8960_rtb_pdata;
 extern struct msm_cache_dump_platform_data msm8960_cache_dump_pdata;
+extern void msm8960_add_vidc_device(void);
diff --git a/arch/arm/mach-msm/board-8974-gpiomux.c b/arch/arm/mach-msm/board-8974-gpiomux.c
index 6fcc779..479dec6 100644
--- a/arch/arm/mach-msm/board-8974-gpiomux.c
+++ b/arch/arm/mach-msm/board-8974-gpiomux.c
@@ -17,7 +17,7 @@
 #include <mach/gpio.h>
 #include <mach/gpiomux.h>
 
-#define KS8851_IRQ_GPIO 90
+#define KS8851_IRQ_GPIO 94
 
 static struct gpiomux_setting gpio_uart_config = {
 	.func = GPIOMUX_FUNC_2,
@@ -26,17 +26,23 @@
 	.dir = GPIOMUX_OUT_HIGH,
 };
 
+static struct gpiomux_setting slimbus = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_KEEPER,
+};
+
 #if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
 static struct gpiomux_setting gpio_eth_config = {
-	.pull = GPIOMUX_PULL_NONE,
-	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_UP,
+	.drv = GPIOMUX_DRV_2MA,
 	.func = GPIOMUX_FUNC_GPIO,
 };
 
-static struct gpiomux_setting gpio_spi_cs_config = {
+static struct gpiomux_setting gpio_spi_cs2_config = {
 	.func = GPIOMUX_FUNC_4,
-	.drv = GPIOMUX_DRV_12MA,
-	.pull = GPIOMUX_PULL_NONE,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_DOWN,
 };
 
 static struct gpiomux_setting gpio_spi_config = {
@@ -45,6 +51,12 @@
 	.pull = GPIOMUX_PULL_NONE,
 };
 
+static struct gpiomux_setting gpio_spi_cs1_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
 static struct msm_gpiomux_config msm_eth_configs[] = {
 	{
 		.gpio = KS8851_IRQ_GPIO,
@@ -54,12 +66,134 @@
 	},
 };
 #endif
+
+static struct gpiomux_setting wcnss_5wire_suspend_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv  = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting wcnss_5wire_active_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv  = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
 static struct gpiomux_setting gpio_i2c_config = {
 	.func = GPIOMUX_FUNC_3,
 	.drv = GPIOMUX_DRV_8MA,
 	.pull = GPIOMUX_PULL_NONE,
 };
 
+static struct gpiomux_setting lcd_en_act_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting lcd_en_sus_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting atmel_resout_sus_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting atmel_resout_act_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting atmel_int_act_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting atmel_int_sus_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting taiko_reset = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_NONE,
+	.dir = GPIOMUX_OUT_LOW,
+};
+
+static struct msm_gpiomux_config msm_touch_configs[] __initdata = {
+	{
+		.gpio      = 60,		/* TOUCH RESET */
+		.settings = {
+			[GPIOMUX_ACTIVE] = &atmel_resout_act_cfg,
+			[GPIOMUX_SUSPENDED] = &atmel_resout_sus_cfg,
+		},
+	},
+	{
+		.gpio      = 61,		/* TOUCH IRQ */
+		.settings = {
+			[GPIOMUX_ACTIVE] = &atmel_int_act_cfg,
+			[GPIOMUX_SUSPENDED] = &atmel_int_sus_cfg,
+		},
+	},
+
+};
+
+static struct gpiomux_setting hdmi_suspend_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting hdmi_active_1_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting hdmi_active_2_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_16MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct msm_gpiomux_config msm_hdmi_configs[] __initdata = {
+	{
+		.gpio = 31,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &hdmi_active_1_cfg,
+			[GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 32,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &hdmi_active_1_cfg,
+			[GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 33,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &hdmi_active_1_cfg,
+			[GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 34,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &hdmi_active_2_cfg,
+			[GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+		},
+	},
+};
 
 static struct msm_gpiomux_config msm_blsp_configs[] __initdata = {
 #if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
@@ -82,13 +216,38 @@
 		},
 	},
 	{
-		.gpio      = 9,		/* BLSP1 QUP SPI_CS_N */
+		.gpio      = 9,		/* BLSP1 QUP SPI_CS2A_N */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_cs_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_cs2_config,
+		},
+	},
+	{
+		.gpio      = 8,		/* BLSP1 QUP SPI_CS1_N */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_spi_cs1_config,
 		},
 	},
 #endif
 	{
+		.gpio = 58,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &lcd_en_act_cfg,
+			[GPIOMUX_SUSPENDED] = &lcd_en_sus_cfg,
+		},
+	},
+	{
+		.gpio      = 6,		/* BLSP1 QUP2 I2C_DAT */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+		},
+	},
+	{
+		.gpio      = 7,		/* BLSP1 QUP2 I2C_CLK */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+		},
+	},
+	{
 		.gpio      = 83,		/* BLSP11 QUP I2C_DAT */
 		.settings = {
 			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
@@ -101,19 +260,229 @@
 		},
 	},
 	{
-		.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,
 		},
 	},
 };
 
+static struct msm_gpiomux_config msm8974_slimbus_config[] __initdata = {
+	{
+		.gpio	= 70,		/* slimbus clk */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &slimbus,
+		},
+	},
+	{
+		.gpio	= 71,		/* slimbus data */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &slimbus,
+		},
+	},
+};
+
+static struct gpiomux_setting cam_settings[] = {
+	{
+		.func = GPIOMUX_FUNC_1, /*active 1*/
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_NONE,
+	},
+
+	{
+		.func = GPIOMUX_FUNC_1, /*suspend*/
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_DOWN,
+	},
+
+	{
+		.func = GPIOMUX_FUNC_1, /*i2c suspend*/
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_KEEPER,
+	},
+};
+
+static struct msm_gpiomux_config msm_sensor_configs[] __initdata = {
+	{
+		.gpio = 15, /* CAM_MCLK0 */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[0],
+			[GPIOMUX_SUSPENDED] = &cam_settings[1],
+		},
+	},
+	{
+		.gpio = 16, /* CAM_MCLK1 */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[0],
+			[GPIOMUX_SUSPENDED] = &cam_settings[1],
+		},
+	},
+	{
+		.gpio = 17, /* CAM_MCLK2 */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[0],
+			[GPIOMUX_SUSPENDED] = &cam_settings[1],
+		},
+	},
+	{
+		.gpio = 18, /* WEBCAM1_RESET_N / CAM_MCLK3 */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[0],
+			[GPIOMUX_SUSPENDED] = &cam_settings[1],
+		},
+	},
+	{
+		.gpio = 19, /* CCI_I2C_SDA0 */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[0],
+			[GPIOMUX_SUSPENDED] = &cam_settings[2],
+		},
+	},
+	{
+		.gpio = 20, /* CCI_I2C_SCL0 */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[0],
+			[GPIOMUX_SUSPENDED] = &cam_settings[2],
+		},
+	},
+	{
+		.gpio = 21, /* CCI_I2C_SDA1 */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[0],
+			[GPIOMUX_SUSPENDED] = &cam_settings[2],
+		},
+	},
+	{
+		.gpio = 22, /* CCI_I2C_SCL1 */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[0],
+			[GPIOMUX_SUSPENDED] = &cam_settings[2],
+		},
+	},
+	{
+		.gpio = 23, /* FLASH_LED_EN */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[0],
+			[GPIOMUX_SUSPENDED] = &cam_settings[1],
+		},
+	},
+	{
+		.gpio = 24, /* FLASH_LED_NOW */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[0],
+			[GPIOMUX_SUSPENDED] = &cam_settings[1],
+		},
+	},
+	{
+		.gpio = 25, /* WEBCAM2_RESET_N */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[0],
+			[GPIOMUX_SUSPENDED] = &cam_settings[1],
+		},
+	},
+	{
+		.gpio = 26, /* CAM_IRQ */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[0],
+			[GPIOMUX_SUSPENDED] = &cam_settings[1],
+		},
+	},
+	{
+		.gpio = 27, /* OIS_SYNC */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[0],
+			[GPIOMUX_SUSPENDED] = &cam_settings[1],
+		},
+	},
+	{
+		.gpio = 28, /* WEBCAM1_STANDBY */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[0],
+			[GPIOMUX_SUSPENDED] = &cam_settings[1],
+		},
+	},
+	{
+		.gpio = 89, /* CAM1_STANDBY_N */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[0],
+			[GPIOMUX_SUSPENDED] = &cam_settings[1],
+		},
+	},
+	{
+		.gpio = 90, /* CAM1_RST_N */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[0],
+			[GPIOMUX_SUSPENDED] = &cam_settings[1],
+		},
+	},
+	{
+		.gpio = 91, /* CAM2_STANDBY_N */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[0],
+			[GPIOMUX_SUSPENDED] = &cam_settings[1],
+		},
+	},
+	{
+		.gpio = 92, /* CAM2_RST_N */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[0],
+			[GPIOMUX_SUSPENDED] = &cam_settings[1],
+		},
+	},
+};
+static struct msm_gpiomux_config wcnss_5wire_interface[] = {
+	{
+		.gpio = 36,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &wcnss_5wire_active_cfg,
+			[GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 37,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &wcnss_5wire_active_cfg,
+			[GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 38,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &wcnss_5wire_active_cfg,
+			[GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 39,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &wcnss_5wire_active_cfg,
+			[GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 40,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &wcnss_5wire_active_cfg,
+			[GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+		},
+	},
+};
+
+static struct msm_gpiomux_config msm_taiko_config[] __initdata = {
+	{
+		.gpio	= 63,		/* SYS_RST_N */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &taiko_reset,
+		},
+	}
+};
+
 void __init msm_8974_init_gpiomux(void)
 {
 	int rc;
@@ -128,4 +497,17 @@
 	msm_gpiomux_install(msm_eth_configs, ARRAY_SIZE(msm_eth_configs));
 #endif
 	msm_gpiomux_install(msm_blsp_configs, ARRAY_SIZE(msm_blsp_configs));
+	msm_gpiomux_install(wcnss_5wire_interface,
+				ARRAY_SIZE(wcnss_5wire_interface));
+
+	msm_gpiomux_install(msm8974_slimbus_config,
+			ARRAY_SIZE(msm8974_slimbus_config));
+
+	msm_gpiomux_install(msm_touch_configs, ARRAY_SIZE(msm_touch_configs));
+
+	msm_gpiomux_install(msm_sensor_configs, ARRAY_SIZE(msm_sensor_configs));
+
+	msm_gpiomux_install(msm_taiko_config, ARRAY_SIZE(msm_taiko_config));
+
+	msm_gpiomux_install(msm_hdmi_configs, ARRAY_SIZE(msm_hdmi_configs));
 }
diff --git a/arch/arm/mach-msm/board-8974.c b/arch/arm/mach-msm/board-8974.c
index 1b75a0a..dcc0d01 100644
--- a/arch/arm/mach-msm/board-8974.c
+++ b/arch/arm/mach-msm/board-8974.c
@@ -26,6 +26,7 @@
 #endif
 #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>
@@ -267,11 +268,6 @@
 	msm_reserve();
 }
 
-static struct platform_device android_usb_device = {
-	.name	= "android_usb",
-	.id	= -1,
-};
-
 #define BIMC_BASE	0xfc380000
 #define BIMC_SIZE	0x0006A000
 #define SYS_NOC_BASE	0xfc460000
@@ -382,6 +378,11 @@
 	.id    = MSM_BUS_FAB_OCMEM_VNOC,
 };
 
+static struct platform_device msm_fm_platform_init = {
+	.name  = "iris_fm",
+	.id    = -1,
+};
+
 static struct platform_device *msm_bus_8974_devices[] = {
 	&msm_bus_sys_noc,
 	&msm_bus_bimc,
@@ -390,8 +391,54 @@
 	&msm_bus_periph_noc,
 	&msm_bus_config_noc,
 	&msm_bus_ocmem_vnoc,
+	&msm_fm_platform_init,
 };
 
+static ssize_t mxt336s_vkeys_show(struct kobject *kobj,
+			struct kobj_attribute *attr, char *buf)
+{
+	return snprintf(buf, 200,
+	__stringify(EV_KEY) ":" __stringify(KEY_BACK) ":62:1345:90:90" \
+	":" __stringify(EV_KEY) ":" __stringify(KEY_MENU) ":240:1345:90:90" \
+	":" __stringify(EV_KEY) ":" __stringify(KEY_HOME) ":470:1345:90:90" \
+	":" __stringify(EV_KEY) ":" __stringify(KEY_SEARCH) ":658:1345:90:90" \
+	"\n");
+}
+
+static struct kobj_attribute mxt336s_vkeys_attr = {
+	.attr = {
+		.mode = S_IRUGO,
+	},
+	.show = &mxt336s_vkeys_show,
+};
+
+static struct attribute *mxt336s_properties_attrs[] = {
+	&mxt336s_vkeys_attr.attr,
+	NULL
+};
+
+static struct attribute_group mxt336s_properties_attr_group = {
+	.attrs = mxt336s_properties_attrs,
+};
+
+static void mxt_init_vkeys_8974(void)
+{
+	int rc = 0;
+	static struct kobject *mxt336s_properties_kobj;
+
+	mxt336s_vkeys_attr.attr.name = "virtualkeys.atmel_mxt_ts";
+	mxt336s_properties_kobj = kobject_create_and_add("board_properties",
+								NULL);
+	if (mxt336s_properties_kobj)
+		rc = sysfs_create_group(mxt336s_properties_kobj,
+					&mxt336s_properties_attr_group);
+	if (!mxt336s_properties_kobj || rc)
+		pr_err("%s: failed to create board_properties\n",
+				__func__);
+
+	return;
+}
+
 static void __init msm8974_init_buses(void)
 {
 #ifdef CONFIG_MSM_BUS_SCALING
@@ -411,7 +458,6 @@
 void __init msm_8974_add_devices(void)
 {
 	platform_device_register(&msm_device_smd_8974);
-	platform_device_register(&android_usb_device);
 }
 
 /*
@@ -434,6 +480,8 @@
 	else
 		msm_clock_init(&msm8974_clock_init_data);
 	msm8974_init_buses();
+	msm_thermal_device_init();
+	mxt_init_vkeys_8974();
 }
 
 static struct of_device_id irq_match[] __initdata  = {
@@ -461,8 +509,6 @@
 }
 
 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, \
diff --git a/arch/arm/mach-msm/board-9615-display.c b/arch/arm/mach-msm/board-9615-display.c
index 74bc984..4e4ce7a 100644
--- a/arch/arm/mach-msm/board-9615-display.c
+++ b/arch/arm/mach-msm/board-9615-display.c
@@ -15,7 +15,7 @@
 #include <linux/ioport.h>
 #include <linux/platform_device.h>
 #include <linux/bootmem.h>
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
 #include <asm/mach-types.h>
 #include <mach/msm_memtypes.h>
 #include <mach/board.h>
diff --git a/arch/arm/mach-msm/board-9615-gpiomux.c b/arch/arm/mach-msm/board-9615-gpiomux.c
index 47a9835..9339638 100644
--- a/arch/arm/mach-msm/board-9615-gpiomux.c
+++ b/arch/arm/mach-msm/board-9615-gpiomux.c
@@ -119,6 +119,13 @@
 	.dir = GPIOMUX_IN,
 };
 
+static struct gpiomux_setting tabla_reset = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_NONE,
+	.dir = GPIOMUX_OUT_LOW,
+};
+
 static struct msm_gpiomux_config msm9615_audio_codec_configs[] __initdata = {
 	{
 		.gpio = 24,
@@ -126,6 +133,12 @@
 			[GPIOMUX_SUSPENDED] = &cdc_mclk,
 		},
 	},
+	{
+		.gpio	= 84,		/* SYS_RST_N */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &tabla_reset,
+		},
+	}
 };
 
 static struct msm_gpiomux_config msm9615_sdcc2_configs[] __initdata = {
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index f885774..4523cf7 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -29,7 +29,7 @@
 #include <linux/power/ltc4088-charger.h>
 #include <linux/gpio.h>
 #include <linux/msm_tsens.h>
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
 #include <linux/memory.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -612,7 +612,7 @@
 static int shelby_phy_init_seq[] = {
 	0x44, 0x80,/* set VBUS valid threshold and
 			disconnect valid threshold */
-	0x38, 0x81, /* update DC voltage level */
+	0x68, 0x81, /* update DC voltage level */
 	0x24, 0x82,/* set preemphasis and rise/fall time */
 	0x13, 0x83,/* set source impedance adjustment */
 	-1};
@@ -620,8 +620,8 @@
 #define USB_BAM_PHY_BASE	0x12502000
 #define HSIC_BAM_PHY_BASE	0x12542000
 #define A2_BAM_PHY_BASE		0x124C2000
-static struct usb_bam_pipe_connect msm_usb_bam_connections[2][4][2] = {
-	[0][0][USB_TO_PEER_PERIPHERAL] = {
+static struct usb_bam_pipe_connect msm_usb_bam_connections[MAX_BAMS][4][2] = {
+	[HSUSB_BAM][0][USB_TO_PEER_PERIPHERAL] = {
 		.src_phy_addr = USB_BAM_PHY_BASE,
 		.src_pipe_index = 11,
 		.dst_phy_addr = A2_BAM_PHY_BASE,
@@ -631,7 +631,7 @@
 		.desc_fifo_base_offset = 0x1700,
 		.desc_fifo_size = 0x300,
 	},
-	[0][0][PEER_PERIPHERAL_TO_USB] = {
+	[HSUSB_BAM][0][PEER_PERIPHERAL_TO_USB] = {
 		.src_phy_addr = A2_BAM_PHY_BASE,
 		.src_pipe_index = 1,
 		.dst_phy_addr = USB_BAM_PHY_BASE,
@@ -641,7 +641,7 @@
 		.desc_fifo_base_offset = 0x1000,
 		.desc_fifo_size = 0x100,
 	},
-	[0][1][USB_TO_PEER_PERIPHERAL] = {
+	[HSUSB_BAM][1][USB_TO_PEER_PERIPHERAL] = {
 		.src_phy_addr = USB_BAM_PHY_BASE,
 		.src_pipe_index = 13,
 		.dst_phy_addr = A2_BAM_PHY_BASE,
@@ -651,7 +651,7 @@
 		.desc_fifo_base_offset = 0x2700,
 		.desc_fifo_size = 0x300,
 	},
-	[0][1][PEER_PERIPHERAL_TO_USB] = {
+	[HSUSB_BAM][1][PEER_PERIPHERAL_TO_USB] = {
 		.src_phy_addr = A2_BAM_PHY_BASE,
 		.src_pipe_index = 3,
 		.dst_phy_addr = USB_BAM_PHY_BASE,
@@ -661,7 +661,7 @@
 		.desc_fifo_base_offset = 0x2000,
 		.desc_fifo_size = 0x100,
 	},
-	[0][2][USB_TO_PEER_PERIPHERAL] = {
+	[HSUSB_BAM][2][USB_TO_PEER_PERIPHERAL] = {
 		.src_phy_addr = USB_BAM_PHY_BASE,
 		.src_pipe_index = 15,
 		.dst_phy_addr = A2_BAM_PHY_BASE,
@@ -671,7 +671,7 @@
 		.desc_fifo_base_offset = 0x3700,
 		.desc_fifo_size = 0x300,
 	},
-	[0][2][PEER_PERIPHERAL_TO_USB] = {
+	[HSUSB_BAM][2][PEER_PERIPHERAL_TO_USB] = {
 		.src_phy_addr = A2_BAM_PHY_BASE,
 		.src_pipe_index = 5,
 		.dst_phy_addr = USB_BAM_PHY_BASE,
@@ -681,7 +681,7 @@
 		.desc_fifo_base_offset = 0x3000,
 		.desc_fifo_size = 0x100,
 	},
-	[1][0][USB_TO_PEER_PERIPHERAL] = {
+	[HSIC_BAM][0][USB_TO_PEER_PERIPHERAL] = {
 		.src_phy_addr = HSIC_BAM_PHY_BASE,
 		.src_pipe_index = 1,
 		.dst_phy_addr = A2_BAM_PHY_BASE,
@@ -691,7 +691,7 @@
 		.desc_fifo_base_offset = 0x1700,
 		.desc_fifo_size = 0x300,
 	},
-	[1][0][PEER_PERIPHERAL_TO_USB] = {
+	[HSIC_BAM][0][PEER_PERIPHERAL_TO_USB] = {
 		.src_phy_addr = A2_BAM_PHY_BASE,
 		.src_pipe_index = 1,
 		.dst_phy_addr = HSIC_BAM_PHY_BASE,
@@ -701,7 +701,7 @@
 		.desc_fifo_base_offset = 0x1000,
 		.desc_fifo_size = 0x100,
 	},
-	[1][1][USB_TO_PEER_PERIPHERAL] = {
+	[HSIC_BAM][1][USB_TO_PEER_PERIPHERAL] = {
 		.src_phy_addr = HSIC_BAM_PHY_BASE,
 		.src_pipe_index = 3,
 		.dst_phy_addr = A2_BAM_PHY_BASE,
@@ -711,7 +711,7 @@
 		.desc_fifo_base_offset = 0x2700,
 		.desc_fifo_size = 0x300,
 	},
-	[1][1][PEER_PERIPHERAL_TO_USB] = {
+	[HSIC_BAM][1][PEER_PERIPHERAL_TO_USB] = {
 		.src_phy_addr = A2_BAM_PHY_BASE,
 		.src_pipe_index = 3,
 		.dst_phy_addr = HSIC_BAM_PHY_BASE,
@@ -721,7 +721,7 @@
 		.desc_fifo_base_offset = 0x2000,
 		.desc_fifo_size = 0x100,
 	},
-	[1][2][USB_TO_PEER_PERIPHERAL] = {
+	[HSIC_BAM][2][USB_TO_PEER_PERIPHERAL] = {
 		.src_phy_addr = HSIC_BAM_PHY_BASE,
 		.src_pipe_index = 5,
 		.dst_phy_addr = A2_BAM_PHY_BASE,
@@ -731,7 +731,7 @@
 		.desc_fifo_base_offset = 0x3700,
 		.desc_fifo_size = 0x300,
 	},
-	[1][2][PEER_PERIPHERAL_TO_USB] = {
+	[HSIC_BAM][2][PEER_PERIPHERAL_TO_USB] = {
 		.src_phy_addr = A2_BAM_PHY_BASE,
 		.src_pipe_index = 5,
 		.dst_phy_addr = HSIC_BAM_PHY_BASE,
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 4a9bbcd..e7ef1a9 100644
--- a/arch/arm/mach-msm/board-9625.c
+++ b/arch/arm/mach-msm/board-9625.c
@@ -46,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),
@@ -72,6 +72,8 @@
 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),
 	{}
 };
 
@@ -94,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-dt.c b/arch/arm/mach-msm/board-dt.c
index b2a4ce2..8f9a0ef 100644
--- a/arch/arm/mach-msm/board-dt.c
+++ b/arch/arm/mach-msm/board-dt.c
@@ -23,6 +23,7 @@
 #include <asm/mach/time.h>
 #include <mach/socinfo.h>
 #include <mach/board.h>
+#include <mach/restart.h>
 
 static void __init msm_dt_timer_init(void)
 {
@@ -87,4 +88,5 @@
 	.dt_compat = msm_dt_match,
 	.reserve = msm_dt_reserve,
 	.init_very_early = msm_dt_init_very_early,
+	.restart = msm_restart,
 MACHINE_END
diff --git a/arch/arm/mach-msm/board-fsm9xxx.c b/arch/arm/mach-msm/board-fsm9xxx.c
index 0e2aa3b..24d54e4 100644
--- a/arch/arm/mach-msm/board-fsm9xxx.c
+++ b/arch/arm/mach-msm/board-fsm9xxx.c
@@ -193,7 +193,7 @@
 		PM8XXX_MPP_INIT(PMIC_MPP_6, A_OUTPUT,
 			PM8XXX_MPP_AOUT_LVL_1V25_2, AOUT_CTRL_ENABLE),
 		PM8XXX_MPP_INIT(PMIC_MPP_UIM_M_DATA, D_BI_DIR,
-			PM8058_MPP_DIG_LEVEL_L3, BI_PULLUP_30KOHM),
+			PM8058_MPP_DIG_LEVEL_S3, BI_PULLUP_1KOHM),
 		PM8XXX_MPP_INIT(PMIC_MPP_UIM_DATA, D_BI_DIR,
 			PM8058_MPP_DIG_LEVEL_L3, BI_PULLUP_30KOHM),
 	};
@@ -261,7 +261,7 @@
 			REGULATOR_CHANGE_STATUS, 0, 0, 1)
 
 static struct pm8058_vreg_pdata pm8058_vreg_init[] = {
-	PM8058_VREG_INIT_LDO(PM8058_VREG_ID_L3, 1800000, 1800000),
+	PM8058_VREG_INIT_LDO(PM8058_VREG_ID_L3, 3000000, 3000000),
 	PM8058_VREG_INIT_LDO(PM8058_VREG_ID_L8, 2200000, 2200000),
 	PM8058_VREG_INIT_LDO(PM8058_VREG_ID_L9, 2050000, 2050000),
 	PM8058_VREG_INIT_LDO(PM8058_VREG_ID_L14, 2850000, 2850000),
@@ -614,11 +614,11 @@
 
 static struct msm_gpio uart3_uim_config_data[] = {
 	{ GPIO_CFG(GPIO_UIM_RESET, 0, GPIO_CFG_OUTPUT,
-		GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "UIM_Reset" },
+		GPIO_CFG_PULL_UP, GPIO_CFG_2MA), "UIM_Reset" },
 	{ GPIO_CFG(GPIO_UIM_DATA_IO, 2, GPIO_CFG_OUTPUT,
-		GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "UIM_Data" },
+		GPIO_CFG_PULL_UP, GPIO_CFG_2MA), "UIM_Data" },
 	{ GPIO_CFG(GPIO_UIM_CLOCK, 2, GPIO_CFG_OUTPUT,
-		GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "UIM_Clock" },
+		GPIO_CFG_PULL_UP, GPIO_CFG_2MA), "UIM_Clock" },
 };
 
 static void fsm9xxx_init_uart3_uim(void)
diff --git a/arch/arm/mach-msm/board-msm7627a-camera.c b/arch/arm/mach-msm/board-msm7627a-camera.c
index 1e198a7..7a1e2ff 100644
--- a/arch/arm/mach-msm/board-msm7627a-camera.c
+++ b/arch/arm/mach-msm/board-msm7627a-camera.c
@@ -19,7 +19,7 @@
 #include <linux/module.h>
 #include <asm/mach-types.h>
 #include <mach/msm_iomap.h>
-#include <mach/board.h>
+#include <mach/camera.h>
 #include <mach/irqs-7xxx.h>
 #include "devices-msm7x2xa.h"
 #include "board-msm7627a.h"
@@ -396,8 +396,10 @@
 		sensor_board_info_ov8825.num_vreg = 0;
 
 	}
-	if (machine_is_msm8625_evb()
-			|| machine_is_msm8625_evt()) {
+	if (machine_is_msm8625_evb() || machine_is_msm7627a_evb()
+				||  machine_is_msm8625_evt()
+				|| machine_is_msm7627a_qrd3()
+				|| machine_is_msm8625_qrd7()) {
 		sensor_board_info_ov7692.cam_vreg =
 			ov7692_gpio_vreg;
 		sensor_board_info_ov7692.num_vreg =
diff --git a/arch/arm/mach-msm/board-msm7627a-display.c b/arch/arm/mach-msm/board-msm7627a-display.c
index e305fe6..d62254a 100644
--- a/arch/arm/mach-msm/board-msm7627a-display.c
+++ b/arch/arm/mach-msm/board-msm7627a-display.c
@@ -65,6 +65,8 @@
 #define SKU3_LCDC_LCD_CAMERA_LDO_1V8	34  /*LCD_CAMERA_LDO_1V8*/
 #define SKU3_1_LCDC_LCD_CAMERA_LDO_1V8	58  /*LCD_CAMERA_LDO_1V8*/
 
+static struct regulator *gpio_reg_2p85v_sku3, *gpio_reg_1p8v_sku3;
+
 static uint32_t lcdc_truly_gpio_table[] = {
 	19,
 	20,
@@ -133,7 +135,7 @@
 }
 
 
-void sku3_lcdc_lcd_camera_power_init(void)
+void sku3_lcdc_power_init(void)
 {
 	int rc = 0;
 	u32 socinfo = socinfo_get_platform_type();
@@ -188,6 +190,29 @@
 		}
 	}
 
+	if (socinfo == 0x0B)
+		gpio_free(SKU3_LCDC_LCD_CAMERA_LDO_1V8);
+	else if (socinfo == 0x0F || machine_is_msm8625_qrd7())
+		gpio_free(SKU3_1_LCDC_LCD_CAMERA_LDO_1V8);
+
+	gpio_free(SKU3_LCDC_LCD_CAMERA_LDO_2V8);
+
+	gpio_reg_2p85v_sku3 = regulator_get(&msm_lcdc_device.dev,
+							"lcd_vdd_sku3");
+	if (IS_ERR(gpio_reg_2p85v_sku3)) {
+		pr_err("%s:ext_2p85v regulator get failed", __func__);
+		regulator_put(gpio_reg_2p85v_sku3);
+		return;
+	}
+
+	gpio_reg_1p8v_sku3 = regulator_get(&msm_lcdc_device.dev,
+							"lcd_vddi_sku3");
+	if (IS_ERR(gpio_reg_1p8v_sku3)) {
+		pr_err("%s:ext_1p8v regulator get failed", __func__);
+		regulator_put(gpio_reg_1p8v_sku3);
+		return;
+	}
+
 	rc = regulator_bulk_get(NULL, ARRAY_SIZE(regs_truly_lcdc),
 			regs_truly_lcdc);
 	if (rc)
@@ -210,41 +235,48 @@
 	return;
 }
 
-int sku3_lcdc_lcd_camera_power_onoff(int on)
+int sku3_lcdc_power_onoff(int on)
 {
 	int rc = 0;
-	u32 socinfo = socinfo_get_platform_type();
 
 	if (on) {
-		if (socinfo == 0x0B)
-			gpio_set_value_cansleep(SKU3_LCDC_LCD_CAMERA_LDO_1V8,
-				1);
-		else if (socinfo == 0x0F || machine_is_msm8625_qrd7())
-			gpio_set_value_cansleep(SKU3_1_LCDC_LCD_CAMERA_LDO_1V8,
-				1);
-
-		gpio_set_value_cansleep(SKU3_LCDC_LCD_CAMERA_LDO_2V8, 1);
+		rc = regulator_enable(gpio_reg_2p85v_sku3);
+		if (rc < 0) {
+			pr_err("%s: reg enable failed\n", __func__);
+			return -EINVAL;
+		}
+		rc = regulator_enable(gpio_reg_1p8v_sku3);
+		if (rc < 0) {
+			pr_err("%s: reg enable failed\n", __func__);
+			return -EINVAL;
+		}
 
 		rc = regulator_bulk_enable(ARRAY_SIZE(regs_truly_lcdc),
 				regs_truly_lcdc);
-		if (rc)
+		if (rc) {
 			pr_err("%s: could not enable regulators: %d\n",
 				__func__, rc);
+			return -EINVAL;
+		}
 	} else {
-		if (socinfo == 0x0B)
-			gpio_set_value_cansleep(SKU3_LCDC_LCD_CAMERA_LDO_1V8,
-				0);
-		else if (socinfo == 0x0F || machine_is_msm8625_qrd7())
-			gpio_set_value_cansleep(SKU3_1_LCDC_LCD_CAMERA_LDO_1V8,
-				0);
-
-		gpio_set_value_cansleep(SKU3_LCDC_LCD_CAMERA_LDO_2V8, 0);
+		rc = regulator_disable(gpio_reg_2p85v_sku3);
+		if (rc < 0) {
+			pr_err("%s: reg disable failed\n", __func__);
+			return -EINVAL;
+		}
+		rc = regulator_disable(gpio_reg_1p8v_sku3);
+		if (rc < 0) {
+			pr_err("%s: reg disable failed\n", __func__);
+			return -EINVAL;
+		}
 
 		rc = regulator_bulk_disable(ARRAY_SIZE(regs_truly_lcdc),
 				regs_truly_lcdc);
-		if (rc)
+		if (rc) {
 			pr_err("%s: could not disable regulators: %d\n",
 				__func__, rc);
+			return -EINVAL;
+		}
 	}
 
 	return rc;
@@ -256,7 +288,7 @@
 	static int cont_splash_done;
 
 	if (on) {
-		sku3_lcdc_lcd_camera_power_onoff(1);
+		sku3_lcdc_power_onoff(1);
 		rc = lcdc_truly_gpio_init();
 		if (rc < 0) {
 			pr_err("%s(): Truly GPIO initializations failed",
@@ -285,7 +317,7 @@
 		gpio_set_value(SKU3_LCDC_GPIO_SPI_CS0_N, 0);
 		gpio_set_value(SKU3_LCDC_GPIO_DISPLAY_RESET, 0);
 
-		sku3_lcdc_lcd_camera_power_onoff(0);
+		sku3_lcdc_power_onoff(0);
 	}
 	return rc;
 }
@@ -1353,21 +1385,19 @@
 {
 	int rc = 0;
 	msm7x27a_set_display_params(prim_panel_name);
-	if (machine_is_msm7627a_qrd1())
+	if (machine_is_msm7627a_qrd1()) {
 		platform_add_devices(qrd_fb_devices,
 				ARRAY_SIZE(qrd_fb_devices));
-	else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()
+	} else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()
 						|| 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));
@@ -1382,6 +1412,8 @@
 			machine_is_msm8625_surf() || machine_is_msm7627a_qrd3()
 			|| machine_is_msm8625_qrd7())
 		msm_fb_register_device("lcdc", &lcdc_pdata);
+	if (machine_is_msm7627a_qrd3() || machine_is_msm8625_qrd7())
+		sku3_lcdc_power_init();
 #ifdef CONFIG_FB_MSM_MIPI_DSI
 	msm_fb_register_device("mipi_dsi", &mipi_dsi_pdata);
 #endif
diff --git a/arch/arm/mach-msm/board-msm7627a-wlan.c b/arch/arm/mach-msm/board-msm7627a-wlan.c
index 0949c5f..79f213e 100644
--- a/arch/arm/mach-msm/board-msm7627a-wlan.c
+++ b/arch/arm/mach-msm/board-msm7627a-wlan.c
@@ -336,6 +336,10 @@
 				goto set_gpio_fail;
 			}
 			gpio_free(gpio_wlan_sys_rest_en);
+		} else {
+			pr_err("%s: WLAN sys_rest_en GPIO %d request failed %d\n",
+				__func__, gpio_wlan_sys_rest_en, rc);
+			goto out;
 		}
 	}
 
@@ -373,6 +377,7 @@
 		gpio_free(GPIO_WLAN_3V3_EN);
 reg_disable:
 	wlan_switch_regulators(0);
+out:
 	pr_info("WLAN power-down failed\n");
 	return rc;
 }
diff --git a/arch/arm/mach-msm/board-msm7627a.h b/arch/arm/mach-msm/board-msm7627a.h
index 4357e01..cd7c1df 100644
--- a/arch/arm/mach-msm/board-msm7627a.h
+++ b/arch/arm/mach-msm/board-msm7627a.h
@@ -102,6 +102,10 @@
 void __init msm7627a_bt_power_init(void);
 #endif
 
+extern struct platform_device msm_device_snd;
+extern struct platform_device msm_device_adspdec;
+extern struct platform_device msm_device_cad;
+
 void __init msm7627a_camera_init(void);
 int lcd_camera_power_onoff(int on);
 
diff --git a/arch/arm/mach-msm/board-msm7x27a.c b/arch/arm/mach-msm/board-msm7x27a.c
index 7b50db5..2a51e66 100644
--- a/arch/arm/mach-msm/board-msm7x27a.c
+++ b/arch/arm/mach-msm/board-msm7x27a.c
@@ -38,7 +38,6 @@
 #include <linux/i2c.h>
 #include <linux/i2c/sx150x.h>
 #include <linux/gpio.h>
-#include <linux/android_pmem.h>
 #include <linux/bootmem.h>
 #include <linux/mfd/marimba.h>
 #include <mach/vreg.h>
@@ -49,7 +48,7 @@
 #include <linux/smsc911x.h>
 #include <linux/atmel_maxtouch.h>
 #include <linux/msm_adc.h>
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
 #include "devices.h"
 #include "timer.h"
 #include "board-msm7x27a-regulator.h"
@@ -60,8 +59,8 @@
 #include "pm-boot.h"
 #include "board-msm7627a.h"
 
-#define PMEM_KERNEL_EBI1_SIZE	0x3A000
-#define MSM_PMEM_AUDIO_SIZE	0x1F4000
+#define RESERVE_KERNEL_EBI1_SIZE	0x3A000
+#define MSM_RESERVE_AUDIO_SIZE	0x1F4000
 
 #if defined(CONFIG_GPIO_SX150X)
 enum {
@@ -159,12 +158,11 @@
 };
 
 #ifdef CONFIG_ARCH_MSM7X27A
-#define MSM_PMEM_MDP_SIZE                0x1B00000
-#define MSM7x25A_MSM_PMEM_MDP_SIZE       0x1500000
-
-#define MSM_PMEM_ADSP_SIZE      0x1200000
-#define MSM7x25A_MSM_PMEM_ADSP_SIZE      0xB91000
-
+#define MSM_RESERVE_MDP_SIZE		0x1B00000
+#define MSM7x25A_MSM_RESERVE_MDP_SIZE   0x1500000
+#define MSM_RESERVE_ADSP_SIZE		0x1200000
+#define MSM7x25A_MSM_RESERVE_ADSP_SIZE	0xB91000
+#define CAMERA_ZSL_SIZE			(SZ_1M * 60)
 #endif
 
 #ifdef CONFIG_ION_MSM
@@ -442,203 +440,23 @@
 	.v_addr = MSM_CFG_CTL_BASE,
 };
 
-static struct android_pmem_platform_data android_pmem_adsp_pdata = {
-	.name = "pmem_adsp",
-	.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
-	.cached = 1,
-	.memory_type = MEMTYPE_EBI1,
-};
-
-static struct platform_device android_pmem_adsp_device = {
-	.name = "android_pmem",
-	.id = 1,
-	.dev = { .platform_data = &android_pmem_adsp_pdata },
-};
-
-static unsigned pmem_mdp_size = MSM_PMEM_MDP_SIZE;
-static int __init pmem_mdp_size_setup(char *p)
+static unsigned reserve_mdp_size = MSM_RESERVE_MDP_SIZE;
+static int __init reserve_mdp_size_setup(char *p)
 {
-	pmem_mdp_size = memparse(p, NULL);
+	reserve_mdp_size = memparse(p, NULL);
 	return 0;
 }
 
-early_param("pmem_mdp_size", pmem_mdp_size_setup);
+early_param("reserve_mdp_size", reserve_mdp_size_setup);
 
-static unsigned pmem_adsp_size = MSM_PMEM_ADSP_SIZE;
-static int __init pmem_adsp_size_setup(char *p)
+static unsigned reserve_adsp_size = MSM_RESERVE_ADSP_SIZE;
+static int __init reserve_adsp_size_setup(char *p)
 {
-	pmem_adsp_size = memparse(p, NULL);
+	reserve_adsp_size = memparse(p, NULL);
 	return 0;
 }
 
-early_param("pmem_adsp_size", pmem_adsp_size_setup);
-
-#define SND(desc, num) { .name = #desc, .id = num }
-static struct snd_endpoint snd_endpoints_list[] = {
-	SND(HANDSET, 0),
-	SND(MONO_HEADSET, 2),
-	SND(HEADSET, 3),
-	SND(SPEAKER, 6),
-	SND(TTY_HEADSET, 8),
-	SND(TTY_VCO, 9),
-	SND(TTY_HCO, 10),
-	SND(BT, 12),
-	SND(IN_S_SADC_OUT_HANDSET, 16),
-	SND(IN_S_SADC_OUT_SPEAKER_PHONE, 25),
-	SND(FM_DIGITAL_STEREO_HEADSET, 26),
-	SND(FM_DIGITAL_SPEAKER_PHONE, 27),
-	SND(FM_DIGITAL_BT_A2DP_HEADSET, 28),
-	SND(STEREO_HEADSET_AND_SPEAKER, 31),
-	SND(CURRENT, 0x7FFFFFFE),
-	SND(FM_ANALOG_STEREO_HEADSET, 35),
-	SND(FM_ANALOG_STEREO_HEADSET_CODEC, 36),
-};
-#undef SND
-
-static struct msm_snd_endpoints msm_device_snd_endpoints = {
-	.endpoints = snd_endpoints_list,
-	.num = sizeof(snd_endpoints_list) / sizeof(struct snd_endpoint)
-};
-
-static struct platform_device msm_device_snd = {
-	.name = "msm_snd",
-	.id = -1,
-	.dev    = {
-		.platform_data = &msm_device_snd_endpoints
-	},
-};
-
-#define DEC0_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)| \
-	(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))
-#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)| \
-	(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))
-#define DEC2_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)| \
-	(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))
-#define DEC3_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)| \
-	(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))
-#define DEC4_FORMAT (1<<MSM_ADSP_CODEC_MIDI)
-
-static unsigned int dec_concurrency_table[] = {
-	/* Audio LP */
-	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DMA)), 0,
-	0, 0, 0,
-
-	/* Concurrency 1 */
-	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC1_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC2_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC3_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC4_FORMAT),
-
-	 /* Concurrency 2 */
-	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC1_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC2_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC3_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC4_FORMAT),
-
-	/* Concurrency 3 */
-	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC1_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC2_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC3_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC4_FORMAT),
-
-	/* Concurrency 4 */
-	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC1_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC2_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC3_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC4_FORMAT),
-
-	/* Concurrency 5 */
-	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC1_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC2_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC3_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC4_FORMAT),
-
-	/* Concurrency 6 */
-	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|
-			(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	0, 0, 0, 0,
-
-	/* Concurrency 7 */
-	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC1_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC2_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC3_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC4_FORMAT),
-};
-
-#define DEC_INFO(name, queueid, decid, nr_codec) { .module_name = name, \
-	.module_queueid = queueid, .module_decid = decid, \
-	.nr_codec_support = nr_codec}
-
-static struct msm_adspdec_info dec_info_list[] = {
-	DEC_INFO("AUDPLAY0TASK", 13, 0, 11), /* AudPlay0BitStreamCtrlQueue */
-	DEC_INFO("AUDPLAY1TASK", 14, 1, 11),  /* AudPlay1BitStreamCtrlQueue */
-	DEC_INFO("AUDPLAY2TASK", 15, 2, 11),  /* AudPlay2BitStreamCtrlQueue */
-	DEC_INFO("AUDPLAY3TASK", 16, 3, 11),  /* AudPlay3BitStreamCtrlQueue */
-	DEC_INFO("AUDPLAY4TASK", 17, 4, 1),  /* AudPlay4BitStreamCtrlQueue */
-};
-
-static struct msm_adspdec_database msm_device_adspdec_database = {
-	.num_dec = ARRAY_SIZE(dec_info_list),
-	.num_concurrency_support = (ARRAY_SIZE(dec_concurrency_table) / \
-					ARRAY_SIZE(dec_info_list)),
-	.dec_concurrency_table = dec_concurrency_table,
-	.dec_info_list = dec_info_list,
-};
-
-static struct platform_device msm_device_adspdec = {
-	.name = "msm_adspdec",
-	.id = -1,
-	.dev    = {
-		.platform_data = &msm_device_adspdec_database
-	},
-};
-
-static struct android_pmem_platform_data android_pmem_audio_pdata = {
-	.name = "pmem_audio",
-	.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
-	.cached = 0,
-	.memory_type = MEMTYPE_EBI1,
-};
-
-static struct platform_device android_pmem_audio_device = {
-	.name = "android_pmem",
-	.id = 2,
-	.dev = { .platform_data = &android_pmem_audio_pdata },
-};
-
-static struct android_pmem_platform_data android_pmem_pdata = {
-	.name = "pmem",
-	.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
-	.cached = 1,
-	.memory_type = MEMTYPE_EBI1,
-};
-static struct platform_device android_pmem_device = {
-	.name = "android_pmem",
-	.id = 0,
-	.dev = { .platform_data = &android_pmem_pdata },
-};
+early_param("reserve_adsp_size", reserve_adsp_size_setup);
 
 static u32 msm_calculate_batt_capacity(u32 current_voltage);
 
@@ -725,6 +543,30 @@
 	},
 };
 
+#ifdef CONFIG_MSM_RTB
+static struct msm_rtb_platform_data msm7x27a_rtb_pdata = {
+	.size = SZ_1M,
+};
+
+static int __init msm_rtb_set_buffer_size(char *p)
+{
+	int s;
+
+	s = memparse(p, NULL);
+	msm7x27a_rtb_pdata.size = ALIGN(s, SZ_4K);
+	return 0;
+}
+early_param("msm_rtb_size", msm_rtb_set_buffer_size);
+
+struct platform_device msm7x27a_rtb_device = {
+	.name = "msm_rtb",
+	.id   = -1,
+	.dev  = {
+		.platform_data = &msm7x27a_rtb_pdata,
+	},
+};
+#endif
+
 #define ETH_FIFO_SEL_GPIO	49
 static void msm7x27a_cfg_smsc911x(void)
 {
@@ -808,17 +650,18 @@
 
 static struct platform_device *common_devices[] __initdata = {
 	&android_usb_device,
-	&android_pmem_device,
-	&android_pmem_adsp_device,
-	&android_pmem_audio_device,
 	&msm_device_nand,
 	&msm_device_snd,
+	&msm_device_cad,
 	&msm_device_adspdec,
 	&asoc_msm_pcm,
 	&asoc_msm_dai0,
 	&asoc_msm_dai1,
 	&msm_batt_device,
 	&msm_adc_device,
+#ifdef CONFIG_MSM_RTB
+	&msm7x27a_rtb_device,
+#endif
 #ifdef CONFIG_ION_MSM
 	&ion_dev,
 #endif
@@ -837,35 +680,39 @@
 	&msm8625_kgsl_3d0,
 };
 
-static unsigned pmem_kernel_ebi1_size = PMEM_KERNEL_EBI1_SIZE;
-static int __init pmem_kernel_ebi1_size_setup(char *p)
+static unsigned reserve_kernel_ebi1_size = RESERVE_KERNEL_EBI1_SIZE;
+static int __init reserve_kernel_ebi1_size_setup(char *p)
 {
-	pmem_kernel_ebi1_size = memparse(p, NULL);
+	reserve_kernel_ebi1_size = memparse(p, NULL);
 	return 0;
 }
-early_param("pmem_kernel_ebi1_size", pmem_kernel_ebi1_size_setup);
+early_param("reserve_kernel_ebi1_size", reserve_kernel_ebi1_size_setup);
 
-static unsigned pmem_audio_size = MSM_PMEM_AUDIO_SIZE;
-static int __init pmem_audio_size_setup(char *p)
+static unsigned reserve_audio_size = MSM_RESERVE_AUDIO_SIZE;
+static int __init reserve_audio_size_setup(char *p)
 {
-	pmem_audio_size = memparse(p, NULL);
+	reserve_audio_size = memparse(p, NULL);
 	return 0;
 }
-early_param("pmem_audio_size", pmem_audio_size_setup);
+early_param("reserve_audio_size", reserve_audio_size_setup);
 
 static void fix_sizes(void)
 {
 	if (machine_is_msm7625a_surf() || machine_is_msm7625a_ffa()) {
-		pmem_mdp_size = MSM7x25A_MSM_PMEM_MDP_SIZE;
-		pmem_adsp_size = MSM7x25A_MSM_PMEM_ADSP_SIZE;
+		reserve_mdp_size = MSM7x25A_MSM_RESERVE_MDP_SIZE;
+		reserve_adsp_size = MSM7x25A_MSM_RESERVE_ADSP_SIZE;
 	} else {
-		pmem_mdp_size = MSM_PMEM_MDP_SIZE;
-		pmem_adsp_size = MSM_PMEM_ADSP_SIZE;
+		reserve_mdp_size = MSM_RESERVE_MDP_SIZE;
+		reserve_adsp_size = MSM_RESERVE_ADSP_SIZE;
 	}
+
+	if (get_ddr_size() > SZ_512M)
+		reserve_adsp_size = CAMERA_ZSL_SIZE;
 #ifdef CONFIG_ION_MSM
-	msm_ion_camera_size = pmem_adsp_size;
-	msm_ion_audio_size = (MSM_PMEM_AUDIO_SIZE + PMEM_KERNEL_EBI1_SIZE);
-	msm_ion_sf_size = pmem_mdp_size;
+	msm_ion_camera_size = reserve_adsp_size;
+	msm_ion_audio_size = (MSM_RESERVE_AUDIO_SIZE +
+					RESERVE_KERNEL_EBI1_SIZE);
+	msm_ion_sf_size = reserve_mdp_size;
 #endif
 }
 
@@ -891,7 +738,7 @@
 			.name	= ION_VMALLOC_HEAP_NAME,
 		},
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
-		/* PMEM_ADSP = CAMERA */
+		/* ION_ADSP = CAMERA */
 		{
 			.id	= ION_CAMERA_HEAP_ID,
 			.type	= ION_HEAP_TYPE_CARVEOUT,
@@ -899,7 +746,7 @@
 			.memory_type = ION_EBI_TYPE,
 			.extra_data = (void *)&co_ion_pdata,
 		},
-		/* PMEM_AUDIO */
+		/* ION_AUDIO */
 		{
 			.id	= ION_AUDIO_HEAP_ID,
 			.type	= ION_HEAP_TYPE_CARVEOUT,
@@ -907,7 +754,7 @@
 			.memory_type = ION_EBI_TYPE,
 			.extra_data = (void *)&co_ion_pdata,
 		},
-		/* PMEM_MDP = SF */
+		/* ION_MDP = SF */
 		{
 			.id	= ION_SF_HEAP_ID,
 			.type	= ION_HEAP_TYPE_CARVEOUT,
@@ -937,49 +784,16 @@
 	},
 };
 
-#ifdef CONFIG_ANDROID_PMEM
-#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
-static struct android_pmem_platform_data *pmem_pdata_array[] __initdata = {
-		&android_pmem_adsp_pdata,
-		&android_pmem_audio_pdata,
-		&android_pmem_pdata,
-};
-#endif
-#endif
-
-static void __init size_pmem_devices(void)
+#ifdef CONFIG_MSM_RTB
+static void __init reserve_rtb_memory(void)
 {
-#ifdef CONFIG_ANDROID_PMEM
-#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
-	android_pmem_adsp_pdata.size = pmem_adsp_size;
-	android_pmem_pdata.size = pmem_mdp_size;
-	android_pmem_audio_pdata.size = pmem_audio_size;
-
-#endif
-#endif
+	msm7x27a_reserve_table[MEMTYPE_EBI1].size += msm7x27a_rtb_pdata.size;
 }
-
-#ifdef CONFIG_ANDROID_PMEM
-#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
-static void __init reserve_memory_for(struct android_pmem_platform_data *p)
+#else
+static void __init reserve_rtb_memory(void)
 {
-	msm7x27a_reserve_table[p->memory_type].size += p->size;
 }
 #endif
-#endif
-
-static void __init reserve_pmem_memory(void)
-{
-#ifdef CONFIG_ANDROID_PMEM
-#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
-	unsigned int i;
-	for (i = 0; i < ARRAY_SIZE(pmem_pdata_array); ++i)
-		reserve_memory_for(pmem_pdata_array[i]);
-
-	msm7x27a_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size;
-#endif
-#endif
-}
 
 static void __init size_ion_devices(void)
 {
@@ -1002,10 +816,9 @@
 static void __init msm7x27a_calculate_reserve_sizes(void)
 {
 	fix_sizes();
-	size_pmem_devices();
-	reserve_pmem_memory();
 	size_ion_devices();
 	reserve_ion_memory();
+	reserve_rtb_memory();
 }
 
 static int msm7x27a_paddr_to_memtype(unsigned int paddr)
@@ -1130,6 +943,7 @@
 			 ARRAY_SIZE(msm8625_pm_data));
 	BUG_ON(msm_pm_boot_init(&msm_pm_8625_boot_pdata));
 	msm8x25_spm_device_init();
+	msm_pm_register_cpr_ops();
 }
 
 #define UART1DM_RX_GPIO		45
@@ -1208,6 +1022,7 @@
 				ARRAY_SIZE(msm8625_pm_data));
 		BUG_ON(msm_pm_boot_init(&msm_pm_8625_boot_pdata));
 		msm8x25_spm_device_init();
+		msm_pm_register_cpr_ops();
 	} else {
 		msm_pm_set_platform_data(msm7x27a_pm_data,
 				ARRAY_SIZE(msm7x27a_pm_data));
diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c
index 8adfdab..f16751d 100644
--- a/arch/arm/mach-msm/board-msm7x30.c
+++ b/arch/arm/mach-msm/board-msm7x30.c
@@ -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,
 };
@@ -7182,7 +7173,6 @@
 			.type	= ION_HEAP_TYPE_CARVEOUT,
 			.name	= ION_CAMERA_HEAP_NAME,
 			.memory_type = ION_EBI_TYPE,
-			.has_outer_cache = 1,
 			.extra_data = (void *)&co_ion_pdata,
 		},
 		/* PMEM_AUDIO */
@@ -7191,7 +7181,6 @@
 			.type	= ION_HEAP_TYPE_CARVEOUT,
 			.name	= ION_AUDIO_HEAP_NAME,
 			.memory_type = ION_EBI_TYPE,
-			.has_outer_cache = 1,
 			.extra_data = (void *)&co_ion_pdata,
 		},
 		/* PMEM_MDP = SF */
@@ -7200,7 +7189,6 @@
 			.type	= ION_HEAP_TYPE_CARVEOUT,
 			.name	= ION_SF_HEAP_NAME,
 			.memory_type = ION_EBI_TYPE,
-			.has_outer_cache = 1,
 			.extra_data = (void *)&co_ion_pdata,
 		},
 #endif
diff --git a/arch/arm/mach-msm/board-msm8x60-camera.c b/arch/arm/mach-msm/board-msm8x60-camera.c
index cd95630..acd7f74 100644
--- a/arch/arm/mach-msm/board-msm8x60-camera.c
+++ b/arch/arm/mach-msm/board-msm8x60-camera.c
@@ -15,7 +15,7 @@
 #include <linux/gpio.h>
 #include <linux/i2c.h>
 #include <linux/mfd/pmic8901.h>
-#include <mach/board.h>
+#include <mach/camera.h>
 #include <mach/board-msm8660.h>
 #include <mach/gpiomux.h>
 #include <mach/msm_bus_board.h>
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index 38f1170..281d055 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -103,7 +103,7 @@
 #include "pm-boot.h"
 #include "board-storage-common-a.h"
 
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
 #include <mach/ion.h>
 #include <mach/msm_rtb.h>
 
@@ -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)) && \
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
index 95ec7ca..f6b0c4f 100644
--- a/arch/arm/mach-msm/board-qrd7627a.c
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -20,7 +20,6 @@
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/i2c.h>
-#include <linux/android_pmem.h>
 #include <linux/bootmem.h>
 #include <linux/mfd/marimba.h>
 #include <linux/power_supply.h>
@@ -32,7 +31,7 @@
 #include <linux/input/ft5x06_ts.h>
 #include <linux/msm_adc.h>
 #include <linux/regulator/msm-gpio-regulator.h>
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
 #include <asm/mach/mmc.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -61,8 +60,8 @@
 #include "board-msm7x27a-regulator.h"
 #include "board-msm7627a.h"
 
-#define PMEM_KERNEL_EBI1_SIZE	0x3A000
-#define MSM_PMEM_AUDIO_SIZE	0x1F4000
+#define RESERVE_KERNEL_EBI1_SIZE	0x3A000
+#define MSM_RESERVE_AUDIO_SIZE	0x1F4000
 #define BAHAMA_SLAVE_ID_FM_REG 0x02
 #define FM_GPIO	83
 #define BT_PCM_BCLK_MODE  0x88
@@ -75,6 +74,7 @@
 #define I2C_PIN_CTL       0x15
 #define I2C_NORMAL        0x40
 
+
 static struct platform_device msm_wlan_ar6000_pm_device = {
 	.name           = "wlan_ar6000_pm_dev",
 	.id             = -1,
@@ -129,15 +129,17 @@
 };
 
 #ifdef CONFIG_ARCH_MSM7X27A
-#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)
-#define MSM_ION_CAMERA_SIZE	MSM_PMEM_ADSP_SIZE
-#define MSM_ION_SF_SIZE		MSM_PMEM_MDP_SIZE
-#define MSM_ION_HEAP_NUM	4
+#define MSM_RESERVE_MDP_SIZE       0x1B00000
+#define MSM_RESERVE_ADSP_SIZE      0x1200000
+#define CAMERA_ZSL_SIZE            (SZ_1M * 60)
+
 #ifdef CONFIG_ION_MSM
+#define MSM_ION_HEAP_NUM	4
 static struct platform_device ion_dev;
+static int msm_ion_camera_size;
+static int msm_ion_audio_size;
+static int msm_ion_sf_size;
 #endif
 #endif
 
@@ -388,203 +390,23 @@
 	.v_addr = MSM_CFG_CTL_BASE,
 };
 
-static struct android_pmem_platform_data android_pmem_adsp_pdata = {
-	.name = "pmem_adsp",
-	.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
-	.cached = 1,
-	.memory_type = MEMTYPE_EBI1,
-};
-
-static struct platform_device android_pmem_adsp_device = {
-	.name = "android_pmem",
-	.id = 1,
-	.dev = { .platform_data = &android_pmem_adsp_pdata },
-};
-
-static unsigned pmem_mdp_size = MSM_PMEM_MDP_SIZE;
-static int __init pmem_mdp_size_setup(char *p)
+static unsigned reserve_mdp_size = MSM_RESERVE_MDP_SIZE;
+static int __init reserve_mdp_size_setup(char *p)
 {
-	pmem_mdp_size = memparse(p, NULL);
+	reserve_mdp_size = memparse(p, NULL);
 	return 0;
 }
 
-early_param("pmem_mdp_size", pmem_mdp_size_setup);
+early_param("reserve_mdp_size", reserve_mdp_size_setup);
 
-static unsigned pmem_adsp_size = MSM_PMEM_ADSP_SIZE;
-static int __init pmem_adsp_size_setup(char *p)
+static unsigned reserve_adsp_size = MSM_RESERVE_ADSP_SIZE;
+static int __init reserve_adsp_size_setup(char *p)
 {
-	pmem_adsp_size = memparse(p, NULL);
+	reserve_adsp_size = memparse(p, NULL);
 	return 0;
 }
 
-early_param("pmem_adsp_size", pmem_adsp_size_setup);
-
-#define SND(desc, num) { .name = #desc, .id = num }
-static struct snd_endpoint snd_endpoints_list[] = {
-	SND(HANDSET, 0),
-	SND(MONO_HEADSET, 2),
-	SND(HEADSET, 3),
-	SND(SPEAKER, 6),
-	SND(TTY_HEADSET, 8),
-	SND(TTY_VCO, 9),
-	SND(TTY_HCO, 10),
-	SND(BT, 12),
-	SND(IN_S_SADC_OUT_HANDSET, 16),
-	SND(IN_S_SADC_OUT_SPEAKER_PHONE, 25),
-	SND(FM_DIGITAL_STEREO_HEADSET, 26),
-	SND(FM_DIGITAL_SPEAKER_PHONE, 27),
-	SND(FM_DIGITAL_BT_A2DP_HEADSET, 28),
-	SND(STEREO_HEADSET_AND_SPEAKER, 31),
-	SND(CURRENT, 0x7FFFFFFE),
-	SND(FM_ANALOG_STEREO_HEADSET, 35),
-	SND(FM_ANALOG_STEREO_HEADSET_CODEC, 36),
-};
-#undef SND
-
-static struct msm_snd_endpoints msm_device_snd_endpoints = {
-	.endpoints = snd_endpoints_list,
-	.num = sizeof(snd_endpoints_list) / sizeof(struct snd_endpoint)
-};
-
-static struct platform_device msm_device_snd = {
-	.name = "msm_snd",
-	.id = -1,
-	.dev    = {
-		.platform_data = &msm_device_snd_endpoints
-	},
-};
-
-#define DEC0_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)| \
-	(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))
-#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)| \
-	(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))
-#define DEC2_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)| \
-	(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))
-#define DEC3_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)| \
-	(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))
-#define DEC4_FORMAT (1<<MSM_ADSP_CODEC_MIDI)
-
-static unsigned int dec_concurrency_table[] = {
-	/* Audio LP */
-	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DMA)), 0,
-	0, 0, 0,
-
-	/* Concurrency 1 */
-	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC1_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC2_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC3_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC4_FORMAT),
-
-	 /* Concurrency 2 */
-	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC1_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC2_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC3_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC4_FORMAT),
-
-	/* Concurrency 3 */
-	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC1_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC2_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC3_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC4_FORMAT),
-
-	/* Concurrency 4 */
-	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC1_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC2_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC3_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC4_FORMAT),
-
-	/* Concurrency 5 */
-	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC1_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC2_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC3_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC4_FORMAT),
-
-	/* Concurrency 6 */
-	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|
-			(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	0, 0, 0, 0,
-
-	/* Concurrency 7 */
-	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC1_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC2_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC3_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC4_FORMAT),
-};
-
-#define DEC_INFO(name, queueid, decid, nr_codec) { .module_name = name, \
-	.module_queueid = queueid, .module_decid = decid, \
-	.nr_codec_support = nr_codec}
-
-static struct msm_adspdec_info dec_info_list[] = {
-	DEC_INFO("AUDPLAY0TASK", 13, 0, 11), /* AudPlay0BitStreamCtrlQueue */
-	DEC_INFO("AUDPLAY1TASK", 14, 1, 11),  /* AudPlay1BitStreamCtrlQueue */
-	DEC_INFO("AUDPLAY2TASK", 15, 2, 11),  /* AudPlay2BitStreamCtrlQueue */
-	DEC_INFO("AUDPLAY3TASK", 16, 3, 11),  /* AudPlay3BitStreamCtrlQueue */
-	DEC_INFO("AUDPLAY4TASK", 17, 4, 1),  /* AudPlay4BitStreamCtrlQueue */
-};
-
-static struct msm_adspdec_database msm_device_adspdec_database = {
-	.num_dec = ARRAY_SIZE(dec_info_list),
-	.num_concurrency_support = (ARRAY_SIZE(dec_concurrency_table) / \
-					ARRAY_SIZE(dec_info_list)),
-	.dec_concurrency_table = dec_concurrency_table,
-	.dec_info_list = dec_info_list,
-};
-
-static struct platform_device msm_device_adspdec = {
-	.name = "msm_adspdec",
-	.id = -1,
-	.dev    = {
-		.platform_data = &msm_device_adspdec_database
-	},
-};
-
-static struct android_pmem_platform_data android_pmem_audio_pdata = {
-	.name = "pmem_audio",
-	.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
-	.cached = 0,
-	.memory_type = MEMTYPE_EBI1,
-};
-
-static struct platform_device android_pmem_audio_device = {
-	.name = "android_pmem",
-	.id = 2,
-	.dev = { .platform_data = &android_pmem_audio_pdata },
-};
-
-static struct android_pmem_platform_data android_pmem_pdata = {
-	.name = "pmem",
-	.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
-	.cached = 1,
-	.memory_type = MEMTYPE_EBI1,
-};
-static struct platform_device android_pmem_device = {
-	.name = "android_pmem",
-	.id = 0,
-	.dev = { .platform_data = &android_pmem_pdata },
-};
+early_param("reserve_adsp_size", reserve_adsp_size_setup);
 
 static u32 msm_calculate_batt_capacity(u32 current_voltage);
 
@@ -635,6 +457,30 @@
 	},
 };
 
+#ifdef CONFIG_MSM_RTB
+static struct msm_rtb_platform_data msm7627a_rtb_pdata = {
+	.size = SZ_1M,
+};
+
+static int __init msm_rtb_set_buffer_size(char *p)
+{
+	int s;
+
+	s = memparse(p, NULL);
+	msm7627a_rtb_pdata.size = ALIGN(s, SZ_4K);
+	return 0;
+}
+early_param("msm_rtb_size", msm_rtb_set_buffer_size);
+
+struct platform_device msm7627a_rtb_device = {
+	.name = "msm_rtb",
+	.id   = -1,
+	.dev  = {
+		 .platform_data = &msm7627a_rtb_pdata,
+	},
+};
+#endif
+
 #define GPIO_VREG_INIT(_id, _reg_name, _gpio_label, _gpio, _active_low) \
 	[GPIO_VREG_ID_##_id] = { \
 		.init_data = { \
@@ -653,6 +499,9 @@
 
 #define GPIO_VREG_ID_EXT_2P85V	0
 #define GPIO_VREG_ID_EXT_1P8V	1
+#define GPIO_VREG_ID_EXT_2P85V_SKU3	2
+#define GPIO_VREG_ID_EXT_1P8V_SKU3	3
+#define GPIO_VREG_ID_EXT_1P8V_SKU3_1	4
 
 static struct regulator_consumer_supply vreg_consumers_EXT_2P85V[] = {
 	REGULATOR_SUPPLY("cam_ov5647_avdd", "0-006c"),
@@ -668,10 +517,37 @@
 	REGULATOR_SUPPLY("lcd_vddi", "mipi_dsi.1"),
 };
 
+static struct regulator_consumer_supply vreg_consumers_EXT_2P85V_SKU3[] = {
+	REGULATOR_SUPPLY("cam_ov5647_avdd", "0-006c"),
+	REGULATOR_SUPPLY("cam_ov7692_avdd", "0-0078"),
+	REGULATOR_SUPPLY("cam_ov8825_avdd", "0-000d"),
+	REGULATOR_SUPPLY("lcd_vdd_sku3", "lcdc.0"),
+};
+
+static struct regulator_consumer_supply vreg_consumers_EXT_1P8V_SKU3[] = {
+	REGULATOR_SUPPLY("cam_ov5647_vdd", "0-006c"),
+	REGULATOR_SUPPLY("cam_ov7692_vdd", "0-0078"),
+	REGULATOR_SUPPLY("cam_ov8825_vdd", "0-000d"),
+	REGULATOR_SUPPLY("lcd_vddi_sku3", "lcdc.0"),
+};
+
+static struct regulator_consumer_supply vreg_consumers_EXT_1P8V_SKU3_1[] = {
+	REGULATOR_SUPPLY("cam_ov5647_vdd", "0-006c"),
+	REGULATOR_SUPPLY("cam_ov7692_vdd", "0-0078"),
+	REGULATOR_SUPPLY("cam_ov8825_vdd", "0-000d"),
+	REGULATOR_SUPPLY("lcd_vddi_sku3", "lcdc.0"),
+};
+
 /* GPIO regulator constraints */
 static struct gpio_regulator_platform_data msm_gpio_regulator_pdata[] = {
 	GPIO_VREG_INIT(EXT_2P85V, "ext_2p85v", "ext_2p85v_en", 35, 0),
 	GPIO_VREG_INIT(EXT_1P8V, "ext_1p8v", "ext_1p8v_en", 40, 0),
+	GPIO_VREG_INIT(EXT_2P85V_SKU3, "ext_2p85v_sku3", "ext_2p85v_sku3_en",
+								35, 0),
+	GPIO_VREG_INIT(EXT_1P8V_SKU3, "ext_1p8v_sku3", "ext_1p8v_sku3_en",
+								34, 0),
+	GPIO_VREG_INIT(EXT_1P8V_SKU3_1, "ext_1p8v_sku3_1", "ext_1p8v_sku3_1_en",
+								58, 0),
 };
 
 /* GPIO regulator */
@@ -693,18 +569,46 @@
 	},
 };
 
+static struct platform_device qrd_vreg_gpio_ext_2p85v_sku3 __devinitdata = {
+	.name	= GPIO_REGULATOR_DEV_NAME,
+	.id	= 35,
+	.dev	= {
+		.platform_data =
+			&msm_gpio_regulator_pdata[GPIO_VREG_ID_EXT_2P85V_SKU3],
+	},
+};
+
+static struct platform_device qrd_vreg_gpio_ext_1p8v_sku3 __devinitdata = {
+	.name	= GPIO_REGULATOR_DEV_NAME,
+	.id	= 34,
+	.dev	= {
+		.platform_data =
+			&msm_gpio_regulator_pdata[GPIO_VREG_ID_EXT_1P8V_SKU3],
+	},
+};
+
+static struct platform_device qrd_vreg_gpio_ext_1p8v_sku3_1 __devinitdata = {
+	.name	= GPIO_REGULATOR_DEV_NAME,
+	.id	= 58,
+	.dev	= {
+		.platform_data =
+			&msm_gpio_regulator_pdata[GPIO_VREG_ID_EXT_1P8V_SKU3_1],
+	},
+};
+
 static struct platform_device *common_devices[] __initdata = {
 	&android_usb_device,
-	&android_pmem_device,
-	&android_pmem_adsp_device,
-	&android_pmem_audio_device,
 	&msm_batt_device,
 	&msm_device_adspdec,
 	&msm_device_snd,
+	&msm_device_cad,
 	&asoc_msm_pcm,
 	&asoc_msm_dai0,
 	&asoc_msm_dai1,
 	&msm_adc_device,
+#ifdef CONFIG_MSM_RTB
+	&msm7627a_rtb_device,
+#endif
 #ifdef CONFIG_ION_MSM
 	&ion_dev,
 #endif
@@ -720,10 +624,23 @@
 	&msm_device_otg,
 	&msm_device_gadget_peripheral,
 	&msm_kgsl_3d0,
+};
+
+static struct platform_device *msm8625_lcd_camera_devices[] __initdata = {
 	&qrd_vreg_gpio_ext_2p85v,
 	&qrd_vreg_gpio_ext_1p8v,
 };
 
+static struct platform_device *sku3_lcd_camera_devices[] __initdata = {
+	&qrd_vreg_gpio_ext_2p85v_sku3,
+	&qrd_vreg_gpio_ext_1p8v_sku3,
+};
+
+static struct platform_device *sku3_1_lcd_camera_devices[] __initdata = {
+	&qrd_vreg_gpio_ext_2p85v_sku3,
+	&qrd_vreg_gpio_ext_1p8v_sku3_1,
+};
+
 static struct platform_device *qrd3_devices[] __initdata = {
 	&msm_device_nand,
 };
@@ -738,25 +655,36 @@
 	&msm8625_device_otg,
 	&msm8625_device_gadget_peripheral,
 	&msm8625_kgsl_3d0,
-	&qrd_vreg_gpio_ext_2p85v,
-	&qrd_vreg_gpio_ext_1p8v,
 };
 
-static unsigned pmem_kernel_ebi1_size = PMEM_KERNEL_EBI1_SIZE;
-static int __init pmem_kernel_ebi1_size_setup(char *p)
+static unsigned reserve_kernel_ebi1_size = RESERVE_KERNEL_EBI1_SIZE;
+static int __init reserve_kernel_ebi1_size_setup(char *p)
 {
-	pmem_kernel_ebi1_size = memparse(p, NULL);
+	reserve_kernel_ebi1_size = memparse(p, NULL);
 	return 0;
 }
-early_param("pmem_kernel_ebi1_size", pmem_kernel_ebi1_size_setup);
+early_param("reserve_kernel_ebi1_size", reserve_kernel_ebi1_size_setup);
 
-static unsigned pmem_audio_size = MSM_PMEM_AUDIO_SIZE;
-static int __init pmem_audio_size_setup(char *p)
+
+static unsigned reserve_audio_size = MSM_RESERVE_AUDIO_SIZE;
+static int __init reserve_audio_size_setup(char *p)
 {
-	pmem_audio_size = memparse(p, NULL);
+	reserve_audio_size = memparse(p, NULL);
 	return 0;
 }
-early_param("pmem_audio_size", pmem_audio_size_setup);
+early_param("reserve_audio_size", reserve_audio_size_setup);
+
+static void fix_sizes(void)
+{
+	if (get_ddr_size() > SZ_512M)
+		reserve_adsp_size = CAMERA_ZSL_SIZE;
+#ifdef CONFIG_ION_MSM
+	msm_ion_camera_size = reserve_adsp_size;
+	msm_ion_audio_size = (MSM_RESERVE_AUDIO_SIZE +
+						RESERVE_KERNEL_EBI1_SIZE);
+	msm_ion_sf_size = reserve_mdp_size;
+#endif
+}
 
 #ifdef CONFIG_ION_MSM
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
@@ -780,30 +708,27 @@
 			.name	= ION_VMALLOC_HEAP_NAME,
 		},
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
-		/* PMEM_ADSP = CAMERA */
+		/* ION_ADSP = CAMERA */
 		{
 			.id	= ION_CAMERA_HEAP_ID,
 			.type	= ION_HEAP_TYPE_CARVEOUT,
 			.name	= ION_CAMERA_HEAP_NAME,
-			.size	= MSM_ION_CAMERA_SIZE,
 			.memory_type = ION_EBI_TYPE,
 			.extra_data = (void *)&co_ion_pdata,
 		},
-		/* PMEM_AUDIO */
+		/* ION_AUDIO */
 		{
 			.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,
 		},
-		/* PMEM_MDP = SF */
+		/* ION_MDP = SF */
 		{
 			.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,
 		},
@@ -829,63 +754,41 @@
 	},
 };
 
-#ifdef CONFIG_ANDROID_PMEM
-#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
-static struct android_pmem_platform_data *pmem_pdata_array[] __initdata = {
-		&android_pmem_adsp_pdata,
-		&android_pmem_audio_pdata,
-		&android_pmem_pdata,
-};
-#endif
-#endif
-
-static void __init size_pmem_devices(void)
+#ifdef CONFIG_MSM_RTB
+static void __init reserve_rtb_memory(void)
 {
-#ifdef CONFIG_ANDROID_PMEM
-#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
-	android_pmem_adsp_pdata.size = pmem_adsp_size;
-	android_pmem_pdata.size = pmem_mdp_size;
-	android_pmem_audio_pdata.size = pmem_audio_size;
-#endif
-#endif
+	msm7627a_reserve_table[MEMTYPE_EBI1].size += msm7627a_rtb_pdata.size;
 }
-
-#ifdef CONFIG_ANDROID_PMEM
-#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
-static void __init reserve_memory_for(struct android_pmem_platform_data *p)
+#else
+static void __init reserve_rtb_memory(void)
 {
-	msm7627a_reserve_table[p->memory_type].size += p->size;
 }
 #endif
-#endif
 
-static void __init reserve_pmem_memory(void)
+static void __init size_ion_devices(void)
 {
-#ifdef CONFIG_ANDROID_PMEM
-#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
-	unsigned int i;
-	for (i = 0; i < ARRAY_SIZE(pmem_pdata_array); ++i)
-		reserve_memory_for(pmem_pdata_array[i]);
-
-	msm7627a_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size;
-#endif
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+	ion_pdata.heaps[1].size = msm_ion_camera_size;
+	ion_pdata.heaps[2].size = msm_ion_audio_size;
+	ion_pdata.heaps[3].size = msm_ion_sf_size;
 #endif
 }
 
 static void __init reserve_ion_memory(void)
 {
 #if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
-	msm7627a_reserve_table[MEMTYPE_EBI1].size += MSM_ION_CAMERA_SIZE;
-	msm7627a_reserve_table[MEMTYPE_EBI1].size += MSM_ION_AUDIO_SIZE;
-	msm7627a_reserve_table[MEMTYPE_EBI1].size += MSM_ION_SF_SIZE;
+	msm7627a_reserve_table[MEMTYPE_EBI1].size += msm_ion_camera_size;
+	msm7627a_reserve_table[MEMTYPE_EBI1].size += msm_ion_audio_size;
+	msm7627a_reserve_table[MEMTYPE_EBI1].size += msm_ion_sf_size;
 #endif
 }
 
 static void __init msm7627a_calculate_reserve_sizes(void)
 {
-	size_pmem_devices();
-	reserve_pmem_memory();
+	fix_sizes();
+	size_ion_devices();
 	reserve_ion_memory();
+	reserve_rtb_memory();
 }
 
 static int msm7627a_paddr_to_memtype(unsigned int paddr)
@@ -994,6 +897,23 @@
 		platform_add_devices(qrd3_devices,
 				ARRAY_SIZE(qrd3_devices));
 
+	if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()
+				|| machine_is_msm8625_evt())
+		platform_add_devices(msm8625_lcd_camera_devices,
+				ARRAY_SIZE(msm8625_lcd_camera_devices));
+	else if (machine_is_msm8625_qrd7())
+		platform_add_devices(sku3_1_lcd_camera_devices,
+				ARRAY_SIZE(sku3_1_lcd_camera_devices));
+	else if (machine_is_msm7627a_qrd3()) {
+		u32 socinfo = socinfo_get_platform_type();
+		if (socinfo == 0x0B)
+			platform_add_devices(sku3_lcd_camera_devices,
+					ARRAY_SIZE(sku3_lcd_camera_devices));
+		else if (socinfo == 0x0F)
+			platform_add_devices(sku3_1_lcd_camera_devices,
+					ARRAY_SIZE(sku3_1_lcd_camera_devices));
+	}
+
 	platform_add_devices(common_devices,
 			ARRAY_SIZE(common_devices));
 }
@@ -1039,6 +959,7 @@
 				ARRAY_SIZE(msm8625_pm_data));
 		BUG_ON(msm_pm_boot_init(&msm_pm_8625_boot_pdata));
 		msm8x25_spm_device_init();
+		msm_pm_register_cpr_ops();
 	}
 }
 
diff --git a/arch/arm/mach-msm/clock-7x30.c b/arch/arm/mach-msm/clock-7x30.c
index f3ac7d7..8cce34b 100644
--- a/arch/arm/mach-msm/clock-7x30.c
+++ b/arch/arm/mach-msm/clock-7x30.c
@@ -239,7 +239,6 @@
 		.rate = 19200000,
 		.ops = &clk_ops_tcxo,
 		CLK_INIT(tcxo_clk.c),
-		.warned = true,
 	},
 };
 
@@ -266,7 +265,6 @@
 		.rate = 24576000,
 		.ops = &clk_ops_lpxo,
 		CLK_INIT(lpxo_clk.c),
-		.warned = true,
 	},
 };
 
@@ -281,7 +279,6 @@
 		.rate = 768000000,
 		.ops = &clk_ops_pll_vote,
 		CLK_INIT(pll1_clk.c),
-		.warned = true,
 	},
 };
 
@@ -296,7 +293,6 @@
 		.rate = 806400000, /* TODO: Support scaling */
 		.ops = &clk_ops_pll_vote,
 		CLK_INIT(pll2_clk.c),
-		.warned = true,
 	},
 };
 
@@ -325,7 +321,6 @@
 		.rate = 891000000,
 		.ops = &clk_ops_pll_vote,
 		CLK_INIT(pll4_clk.c),
-		.warned = true,
 	},
 };
 
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 21b6c0a..01bc9dd 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -393,6 +393,7 @@
 
 static DEFINE_VDD_CLASS(vdd_dig, set_vdd_dig_8960);
 
+static int rpm_vreg_dig_8930 = RPM_VREG_ID_PM8038_VDD_DIG_CORNER;
 static int set_vdd_dig_8930(struct clk_vdd_class *vdd_class, int level)
 {
 	static const int vdd_corner[] = {
@@ -401,7 +402,7 @@
 		[VDD_DIG_NOMINAL] = RPM_VREG_CORNER_NOMINAL,
 		[VDD_DIG_HIGH]    = RPM_VREG_CORNER_HIGH,
 	};
-	return rpm_vreg_set_voltage(RPM_VREG_ID_PM8038_VDD_DIG_CORNER,
+	return rpm_vreg_set_voltage(rpm_vreg_dig_8930,
 					RPM_VREG_VOTER3,
 					vdd_corner[level],
 					RPM_VREG_CORNER_HIGH, 1);
@@ -467,6 +468,36 @@
 				    sr2_lreg_uv[level], sr2_lreg_uv[level], 1);
 }
 
+static int set_vdd_sr2_hdmi_pll_8930_pm8917(struct clk_vdd_class *vdd_class,
+	int level)
+{
+	int rc = 0;
+
+	if (level == VDD_SR2_HDMI_PLL_OFF) {
+		rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8917_L23,
+				RPM_VREG_VOTER3, 0, 0, 1);
+		if (rc)
+			return rc;
+		rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8917_S8,
+				RPM_VREG_VOTER3, 0, 0, 1);
+		if (rc)
+			rpm_vreg_set_voltage(RPM_VREG_ID_PM8917_L23,
+				RPM_VREG_VOTER3, 1800000, 1800000, 1);
+	} else {
+		rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8917_S8,
+				RPM_VREG_VOTER3, 2050000, 2100000, 1);
+		if (rc)
+			return rc;
+		rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8917_L23,
+				RPM_VREG_VOTER3, 1800000, 1800000, 1);
+		if (rc)
+			rpm_vreg_set_voltage(RPM_VREG_ID_PM8917_S8,
+					RPM_VREG_VOTER3, 0, 0, 1);
+	}
+
+	return rc;
+}
+
 static int set_vdd_sr2_hdmi_pll_8930(struct clk_vdd_class *vdd_class, int level)
 {
 	return rpm_vreg_set_voltage(RPM_VREG_ID_PM8038_L23, RPM_VREG_VOTER3,
@@ -488,7 +519,6 @@
 		.rate = 800000000,
 		.ops = &clk_ops_local_pll,
 		CLK_INIT(pll2_clk.c),
-		.warned = true,
 	},
 };
 
@@ -502,7 +532,6 @@
 		.vdd_class = &vdd_sr2_hdmi_pll,
 		.fmax[VDD_SR2_HDMI_PLL_ON] = ULONG_MAX,
 		CLK_INIT(pll3_clk.c),
-		.warned = true,
 	},
 };
 
@@ -517,7 +546,6 @@
 		.rate = 393216000,
 		.ops = &clk_ops_pll_vote,
 		CLK_INIT(pll4_clk.c),
-		.warned = true,
 	},
 };
 
@@ -532,7 +560,6 @@
 		.rate = 384000000,
 		.ops = &clk_ops_pll_vote,
 		CLK_INIT(pll8_clk.c),
-		.warned = true,
 	},
 };
 
@@ -547,7 +574,6 @@
 		.rate = 480000000,
 		.ops = &clk_ops_pll_vote,
 		CLK_INIT(pll14_clk.c),
-		.warned = true,
 	},
 };
 
@@ -559,7 +585,6 @@
 		.rate = 975000000,
 		.ops = &clk_ops_local_pll,
 		CLK_INIT(pll15_clk.c),
-		.warned = true,
 	},
 };
 
@@ -2689,7 +2714,6 @@
 		.ops = &clk_ops_rcg,
 		VDD_DIG_FMAX_MAP2(LOW, 86000000, NOMINAL, 178000000),
 		CLK_INIT(csi0_src_clk.c),
-		.warned = true,
 	},
 };
 
@@ -2707,7 +2731,6 @@
 		.dbg_name = "csi0_clk",
 		.ops = &clk_ops_branch,
 		CLK_INIT(csi0_clk.c),
-		.warned = true,
 	},
 };
 
@@ -2747,7 +2770,6 @@
 		.ops = &clk_ops_rcg,
 		VDD_DIG_FMAX_MAP2(LOW, 86000000, NOMINAL, 178000000),
 		CLK_INIT(csi1_src_clk.c),
-		.warned = true,
 	},
 };
 
@@ -2765,7 +2787,6 @@
 		.dbg_name = "csi1_clk",
 		.ops = &clk_ops_branch,
 		CLK_INIT(csi1_clk.c),
-		.warned = true,
 	},
 };
 
@@ -2805,7 +2826,6 @@
 		.ops = &clk_ops_rcg,
 		VDD_DIG_FMAX_MAP2(LOW, 86000000, NOMINAL, 178000000),
 		CLK_INIT(csi2_src_clk.c),
-		.warned = true,
 	},
 };
 
@@ -2823,7 +2843,6 @@
 		.dbg_name = "csi2_clk",
 		.ops = &clk_ops_branch,
 		CLK_INIT(csi2_clk.c),
-		.warned = true,
 	},
 };
 
@@ -2852,6 +2871,7 @@
 };
 
 struct pix_rdi_clk {
+	bool prepared;
 	bool enabled;
 	unsigned long cur_rate;
 
@@ -2877,6 +2897,7 @@
 	unsigned long flags;
 	struct pix_rdi_clk *rdi = to_pix_rdi_clk(c);
 	struct clk **mux_map = pix_rdi_mux_map;
+	unsigned long old_rate = rdi->cur_rate;
 
 	/*
 	 * These clocks select three inputs via two muxes. One mux selects
@@ -2887,7 +2908,7 @@
 	 * needs to be on at what time.
 	 */
 	for (i = 0; mux_map[i]; i++) {
-		ret = clk_enable(mux_map[i]);
+		ret = clk_prepare_enable(mux_map[i]);
 		if (ret)
 			goto err;
 	}
@@ -2896,11 +2917,21 @@
 		goto err;
 	}
 	/* Keep the new source on when switching inputs of an enabled clock */
-	if (rdi->enabled) {
-		clk_disable(mux_map[rdi->cur_rate]);
-		clk_enable(mux_map[rate]);
+	if (rdi->prepared) {
+		ret = clk_prepare(mux_map[rate]);
+		if (ret)
+			goto err;
 	}
-	spin_lock_irqsave(&local_clock_reg_lock, flags);
+	spin_lock_irqsave(&c->lock, flags);
+	if (rdi->enabled) {
+		ret = clk_enable(mux_map[rate]);
+		if (ret) {
+			spin_unlock_irqrestore(&c->lock, flags);
+			clk_unprepare(mux_map[rate]);
+			goto err;
+		}
+	}
+	spin_lock(&local_clock_reg_lock);
 	reg = readl_relaxed(rdi->s2_reg);
 	reg &= ~rdi->s2_mask;
 	reg |= rate == 2 ? rdi->s2_mask : 0;
@@ -2922,10 +2953,16 @@
 	mb();
 	udelay(1);
 	rdi->cur_rate = rate;
-	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+	spin_unlock(&local_clock_reg_lock);
+
+	if (rdi->enabled)
+		clk_disable(mux_map[old_rate]);
+	spin_unlock_irqrestore(&c->lock, flags);
+	if (rdi->prepared)
+		clk_unprepare(mux_map[old_rate]);
 err:
 	for (i--; i >= 0; i--)
-		clk_disable(mux_map[i]);
+		clk_disable_unprepare(mux_map[i]);
 
 	return 0;
 }
@@ -2935,6 +2972,13 @@
 	return to_pix_rdi_clk(c)->cur_rate;
 }
 
+static int pix_rdi_clk_prepare(struct clk *c)
+{
+	struct pix_rdi_clk *rdi = to_pix_rdi_clk(c);
+	rdi->prepared = true;
+	return 0;
+}
+
 static int pix_rdi_clk_enable(struct clk *c)
 {
 	unsigned long flags;
@@ -2959,6 +3003,12 @@
 	rdi->enabled = false;
 }
 
+static void pix_rdi_clk_unprepare(struct clk *c)
+{
+	struct pix_rdi_clk *rdi = to_pix_rdi_clk(c);
+	rdi->prepared = false;
+}
+
 static int pix_rdi_clk_reset(struct clk *c, enum clk_reset_action action)
 {
 	return branch_reset(&to_pix_rdi_clk(c)->b, action);
@@ -2995,8 +3045,10 @@
 }
 
 static struct clk_ops clk_ops_pix_rdi_8960 = {
+	.prepare = pix_rdi_clk_prepare,
 	.enable = pix_rdi_clk_enable,
 	.disable = pix_rdi_clk_disable,
+	.unprepare = pix_rdi_clk_unprepare,
 	.handoff = pix_rdi_clk_handoff,
 	.set_rate = pix_rdi_clk_set_rate,
 	.get_rate = pix_rdi_clk_get_rate,
@@ -3527,6 +3579,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
 };
 
@@ -4705,7 +4763,6 @@
 static DEFINE_CLK_VOTER(dfab_sps_clk, &dfab_clk.c, 0);
 static DEFINE_CLK_VOTER(dfab_bam_dmux_clk, &dfab_clk.c, 0);
 static DEFINE_CLK_VOTER(dfab_scm_clk, &dfab_clk.c, 0);
-static DEFINE_CLK_VOTER(dfab_qseecom_clk, &dfab_clk.c, 0);
 static DEFINE_CLK_VOTER(dfab_msmbus_clk, &dfab_clk.c, 0);
 static DEFINE_CLK_VOTER(dfab_msmbus_a_clk, &dfab_a_clk.c, 0);
 
@@ -5197,7 +5254,7 @@
 	CLK_LOOKUP("core_clk",		gsbi3_uart_clk.c,	""),
 	CLK_LOOKUP("core_clk",		gsbi4_uart_clk.c,	""),
 	CLK_LOOKUP("core_clk",		gsbi5_uart_clk.c,	""),
-	CLK_LOOKUP("core_clk",		gsbi6_uart_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi6_uart_clk.c, "msm_serial_hs.0"),
 	CLK_LOOKUP("core_clk",		gsbi7_uart_clk.c, "msm_serial_hsl.0"),
 	CLK_LOOKUP("core_clk",		gsbi1_qup_clk.c,	"qup_i2c.0"),
 	CLK_LOOKUP("core_clk",		gsbi2_qup_clk.c,	""),
@@ -5247,7 +5304,7 @@
 	CLK_LOOKUP("iface_clk",		gsbi4_p_clk.c,		"qup_i2c.4"),
 	CLK_LOOKUP("iface_clk",		gsbi5_p_clk.c,		"spi_qsd.0"),
 	CLK_LOOKUP("iface_clk",		gsbi5_p_clk.c,		"qup_i2c.5"),
-	CLK_LOOKUP("iface_clk",		gsbi6_p_clk.c,		""),
+	CLK_LOOKUP("iface_clk",		gsbi6_p_clk.c,	"msm_serial_hs.0"),
 	CLK_LOOKUP("iface_clk",		gsbi7_p_clk.c,	"msm_serial_hsl.0"),
 	CLK_LOOKUP("ref_clk",	tsif_ref_clk.c,	"msm_tspp.0"),
 	CLK_LOOKUP("iface_clk",		tsif_p_clk.c,		"msm_tspp.0"),
@@ -5425,7 +5482,6 @@
 	CLK_LOOKUP("dfab_clk",		dfab_sps_clk.c,	"msm_sps"),
 	CLK_LOOKUP("bus_clk",		dfab_bam_dmux_clk.c,	"BAM_RMNT"),
 	CLK_LOOKUP("bus_clk",		dfab_scm_clk.c,	"scm"),
-	CLK_LOOKUP("bus_clk",		dfab_qseecom_clk.c,	"qseecom"),
 
 	CLK_LOOKUP("alt_core_clk",    usb_hsic_xcvr_fs_clk.c,  "msm_hsic_host"),
 	CLK_LOOKUP("phy_clk",	      usb_hsic_hsic_clk.c,     "msm_hsic_host"),
@@ -5776,7 +5832,6 @@
 	CLK_LOOKUP("dfab_clk",		dfab_sps_clk.c,	"msm_sps"),
 	CLK_LOOKUP("bus_clk",		dfab_bam_dmux_clk.c,	"BAM_RMNT"),
 	CLK_LOOKUP("bus_clk",		dfab_scm_clk.c,	"scm"),
-	CLK_LOOKUP("bus_clk",		dfab_qseecom_clk.c,	"qseecom"),
 
 	CLK_LOOKUP("mem_clk",		ebi1_adm_clk.c, "msm_dmov"),
 	CLK_LOOKUP("mem_clk",		ebi1_acpu_a_clk.c, ""),
@@ -5812,6 +5867,7 @@
 
 static struct clk_lookup msm_clocks_8960ab_only[] __initdata = {
 	CLK_LOOKUP("bus_clk", gfx3d_axi_clk.c, "footswitch-8x60.2"),
+	CLK_LOOKUP("core_clk", gfx3d_axi_clk.c, "msm_iommu.10"),
 	CLK_LOOKUP("div_clk",	tv_src_div_clk.c,	""),
 };
 
@@ -6107,7 +6163,6 @@
 	CLK_LOOKUP("dfab_clk",		dfab_sps_clk.c,	"msm_sps"),
 	CLK_LOOKUP("bus_clk",		dfab_bam_dmux_clk.c,	"BAM_RMNT"),
 	CLK_LOOKUP("bus_clk",		dfab_scm_clk.c,	"scm"),
-	CLK_LOOKUP("bus_clk",		dfab_qseecom_clk.c,	"qseecom"),
 
 	CLK_LOOKUP("mem_clk",		ebi1_adm_clk.c, "msm_dmov"),
 	CLK_LOOKUP("mem_clk",		ebi1_acpu_a_clk.c, ""),
@@ -6230,7 +6285,7 @@
 		rmwreg(0x00000003, AHB_EN_REG,  0x6C000103);
 		writel_relaxed(0x000007F9, AHB_EN2_REG);
 	} else {
-		rmwreg(0x44000000, AHB_EN_REG,  0x6C000103);
+		rmwreg(0x40000000, AHB_EN_REG,  0x6C000103);
 		writel_relaxed(0x3C7097F9, AHB_EN2_REG);
 	}
 
@@ -6414,12 +6469,8 @@
 	/* Initialize clock registers. */
 	reg_init();
 
-	if (cpu_is_apq8064()) {
+	if (cpu_is_apq8064())
 		vdd_sr2_hdmi_pll.set_vdd = set_vdd_sr2_hdmi_pll_8064;
-	} else if (cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627()) {
-		vdd_dig.set_vdd = set_vdd_dig_8930;
-		vdd_sr2_hdmi_pll.set_vdd = set_vdd_sr2_hdmi_pll_8930;
-	}
 
 	/* Detect PLL4 programmed for alternate 491.52MHz clock plan. */
 	if (readl_relaxed(LCC_PLL0_L_VAL_REG) == 0x12) {
@@ -6450,6 +6501,8 @@
 			msm_clocks_8960ab_only, sizeof(msm_clocks_8960ab_only));
 		msm8960_clock_init_data.size -=
 			ARRAY_SIZE(msm_clocks_8960_only);
+
+		gmem_axi_clk.c.depends = &gfx3d_axi_clk.c;
 	} else if (cpu_is_msm8960()) {
 		memcpy(msm_clocks_8960 + ARRAY_SIZE(msm_clocks_8960_common),
 			 msm_clocks_8960_only, sizeof(msm_clocks_8960_only));
@@ -6481,12 +6534,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;
 	}
@@ -6498,6 +6554,25 @@
 	clk_ops_local_pll.enable = sr_pll_clk_enable;
 }
 
+static void __init msm8930_pm8917_clock_pre_init(void)
+{
+	/* detect pmic8917 from board file, and call this init function */
+
+	vdd_dig.set_vdd = set_vdd_dig_8930;
+	rpm_vreg_dig_8930 = RPM_VREG_ID_PM8917_VDD_DIG_CORNER;
+	vdd_sr2_hdmi_pll.set_vdd = set_vdd_sr2_hdmi_pll_8930_pm8917;
+
+	msm8960_clock_pre_init();
+}
+
+static void __init msm8930_clock_pre_init(void)
+{
+	vdd_dig.set_vdd = set_vdd_dig_8930;
+	vdd_sr2_hdmi_pll.set_vdd = set_vdd_sr2_hdmi_pll_8930;
+
+	msm8960_clock_pre_init();
+}
+
 static void __init msm8960_clock_post_init(void)
 {
 	/* Keep PXO on whenever APPS cpu is active */
@@ -6608,7 +6683,15 @@
 struct clock_init_data msm8930_clock_init_data __initdata = {
 	.table = msm_clocks_8930,
 	.size = ARRAY_SIZE(msm_clocks_8930),
-	.pre_init = msm8960_clock_pre_init,
+	.pre_init = msm8930_clock_pre_init,
+	.post_init = msm8960_clock_post_init,
+	.late_init = msm8960_clock_late_init,
+};
+
+struct clock_init_data msm8930_pm8917_clock_init_data __initdata = {
+	.table = msm_clocks_8930,
+	.size = ARRAY_SIZE(msm_clocks_8930),
+	.pre_init = msm8930_pm8917_clock_pre_init,
 	.post_init = msm8960_clock_post_init,
 	.late_init = msm8960_clock_late_init,
 };
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 1ab60d2..b054e08 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -18,21 +18,23 @@
 #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"
 #include "clock-rpm.h"
 #include "clock-voter.h"
+#include "clock-mdss-8974.h"
 
 enum {
 	GCC_BASE,
 	MMSS_BASE,
 	LPASS_BASE,
-	MSS_BASE,
 	APCS_BASE,
 	N_BASES,
 };
@@ -42,7 +44,6 @@
 #define GCC_REG_BASE(x) (void __iomem *)(virt_bases[GCC_BASE] + (x))
 #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
@@ -103,12 +104,12 @@
 #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
 #define LPASS_DEBUG_CLK_CTL_REG        0x29000
 #define LPASS_LPA_PLL_VOTE_APPS_REG    0x2000
-#define MSS_DEBUG_CLK_CTL_REG          0x0078
 
 #define GLB_CLK_DIAG_REG               0x001C
 
@@ -118,6 +119,10 @@
 #define USB_HSIC_CMD_RCGR              0x0440
 #define USB_HSIC_IO_CAL_CMD_RCGR       0x0458
 #define USB_HS_SYSTEM_CMD_RCGR         0x0490
+#define SYS_NOC_USB3_AXI_CBCR	       0x0108
+#define USB30_SLEEP_CBCR	       0x03CC
+#define USB2A_PHY_SLEEP_CBCR	       0x04AC
+#define USB2B_PHY_SLEEP_CBCR	       0x04B4
 #define SDCC1_APPS_CMD_RCGR            0x04D0
 #define SDCC2_APPS_CMD_RCGR            0x0510
 #define SDCC3_APPS_CMD_RCGR            0x0550
@@ -292,7 +297,6 @@
 #define OXILI_BCR                 0x4020
 #define OXILICX_BCR               0x4030
 #define LPASS_Q6SS_BCR            0x6000
-#define MSS_Q6SS_BCR              0x1068
 
 #define OCMEM_SYS_NOC_AXI_CBCR                   0x0244
 #define OCMEM_NOC_CFG_AHB_CBCR                   0x0248
@@ -383,6 +387,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
@@ -485,10 +491,11 @@
 #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 AUDIO_WRAPPER_BR_CBCR			 0x24000
 #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
@@ -511,8 +518,9 @@
 #define edppll_270_mm_source_val 4
 #define edppll_350_mm_source_val 4
 #define dsipll_750_mm_source_val 1
-#define dsipll_250_mm_source_val 2
-#define hdmipll_297_mm_source_val 3
+#define dsipll0_byte_mm_source_val 1
+#define dsipll0_pixel_mm_source_val 1
+#define hdmipll_mm_source_val 3
 
 #define F(f, s, div, m, n) \
 	{ \
@@ -536,6 +544,17 @@
 			| BVAL(10, 8, s##_mm_source_val), \
 	}
 
+#define F_HDMI(f, s, div, m, n) \
+	{ \
+		.freq_hz = (f), \
+		.src_clk = &s##_clk_src, \
+		.m_val = (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), \
+	}
+
 #define F_MDSS(f, s, div, m, n) \
 	{ \
 		.freq_hz = (f), \
@@ -609,24 +628,28 @@
 #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
+#define OXILI_ID	0x1
+#define OCMEM_ID	0x2
 
-enum {
-	D0_ID = 1,
-	D1_ID,
-	A0_ID,
-	A1_ID,
-	A2_ID,
-};
+#define D0_ID		 1
+#define D1_ID		 2
+#define A0_ID		 3
+#define A1_ID		 4
+#define A2_ID		 5
+#define DIFF_CLK_ID	 7
+#define DIV_CLK_ID	11
 
 DEFINE_CLK_RPM_SMD(pnoc_clk, pnoc_a_clk, RPM_BUS_CLK_TYPE, PNOC_ID, NULL);
 DEFINE_CLK_RPM_SMD(snoc_clk, snoc_a_clk, RPM_BUS_CLK_TYPE, SNOC_ID, NULL);
@@ -637,6 +660,8 @@
 DEFINE_CLK_RPM_SMD(bimc_clk, bimc_a_clk, RPM_MEM_CLK_TYPE, BIMC_ID, NULL);
 DEFINE_CLK_RPM_SMD(ocmemgx_clk, ocmemgx_a_clk, RPM_MEM_CLK_TYPE, OCMEM_ID,
 			NULL);
+DEFINE_CLK_RPM_SMD(gfx3d_clk_src, gfx3d_a_clk_src, RPM_MEM_CLK_TYPE, OXILI_ID,
+			NULL);
 
 DEFINE_CLK_RPM_SMD_BRANCH(cxo_clk_src, cxo_a_clk_src,
 				RPM_MISC_CLK_TYPE, CXO_ID, 19200000);
@@ -647,6 +672,8 @@
 DEFINE_CLK_RPM_SMD_XO_BUFFER(cxo_a0, cxo_a0_a, A0_ID);
 DEFINE_CLK_RPM_SMD_XO_BUFFER(cxo_a1, cxo_a1_a, A1_ID);
 DEFINE_CLK_RPM_SMD_XO_BUFFER(cxo_a2, cxo_a2_a, A2_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER(div_clk, div_a_clk, DIV_CLK_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER(diff_clk, diff_a_clk, DIFF_CLK_ID);
 
 DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(cxo_d0_pin, cxo_d0_a_pin, D0_ID);
 DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(cxo_d1_pin, cxo_d1_a_pin, D1_ID);
@@ -664,7 +691,6 @@
 		.rate = 600000000,
 		.dbg_name = "gpll0_clk_src",
 		.ops = &clk_ops_pll_vote,
-		.warned = true,
 		CLK_INIT(gpll0_clk_src.c),
 	},
 };
@@ -680,7 +706,6 @@
 		.rate = 480000000,
 		.dbg_name = "gpll1_clk_src",
 		.ops = &clk_ops_pll_vote,
-		.warned = true,
 		CLK_INIT(gpll1_clk_src.c),
 	},
 };
@@ -696,7 +721,6 @@
 		.rate = 491520000,
 		.dbg_name = "lpapll0_clk_src",
 		.ops = &clk_ops_pll_vote,
-		.warned = true,
 		CLK_INIT(lpapll0_clk_src.c),
 	},
 };
@@ -712,7 +736,6 @@
 		.dbg_name = "mmpll0_clk_src",
 		.rate = 800000000,
 		.ops = &clk_ops_pll_vote,
-		.warned = true,
 		CLK_INIT(mmpll0_clk_src.c),
 	},
 };
@@ -728,7 +751,6 @@
 		.dbg_name = "mmpll1_clk_src",
 		.rate = 846000000,
 		.ops = &clk_ops_pll_vote,
-		.warned = true,
 		CLK_INIT(mmpll1_clk_src.c),
 	},
 };
@@ -742,7 +764,6 @@
 		.dbg_name = "mmpll3_clk_src",
 		.rate = 1000000000,
 		.ops = &clk_ops_local_pll,
-		.warned = true,
 		CLK_INIT(mmpll3_clk_src.c),
 	},
 };
@@ -757,8 +778,10 @@
 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(oxili_gfx3d_clk_src, &gfx3d_clk_src.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);
@@ -1965,9 +1988,9 @@
 	.en_mask = BIT(0),
 	.base = &virt_bases[GCC_BASE],
 	.c = {
-		.dbg_name = "gcc_ce1_ahb_clk",
+		.dbg_name = "gcc_ce2_ahb_clk",
 		.ops = &clk_ops_vote,
-		CLK_INIT(gcc_ce1_ahb_clk.c),
+		CLK_INIT(gcc_ce2_ahb_clk.c),
 	},
 };
 
@@ -1977,7 +2000,7 @@
 	.en_mask = BIT(1),
 	.base = &virt_bases[GCC_BASE],
 	.c = {
-		.dbg_name = "gcc_ce1_axi_clk",
+		.dbg_name = "gcc_ce2_axi_clk",
 		.ops = &clk_ops_vote,
 		CLK_INIT(gcc_ce2_axi_clk.c),
 	},
@@ -2184,6 +2207,51 @@
 	},
 };
 
+struct branch_clk gcc_sys_noc_usb3_axi_clk = {
+	.cbcr_reg = SYS_NOC_USB3_AXI_CBCR,
+	.parent = &usb30_master_clk_src.c,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sys_noc_usb3_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sys_noc_usb3_axi_clk.c),
+	},
+};
+
+struct branch_clk gcc_usb30_sleep_clk = {
+	.cbcr_reg = USB30_SLEEP_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb30_sleep_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb30_sleep_clk.c),
+	},
+};
+
+struct branch_clk gcc_usb2a_phy_sleep_clk = {
+	.cbcr_reg = USB2A_PHY_SLEEP_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb2a_phy_sleep_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb2a_phy_sleep_clk.c),
+	},
+};
+
+struct branch_clk gcc_usb2b_phy_sleep_clk = {
+	.cbcr_reg = USB2B_PHY_SLEEP_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb2b_phy_sleep_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb2b_phy_sleep_clk.c),
+	},
+};
+
 static struct branch_clk gcc_usb_hs_ahb_clk = {
 	.cbcr_reg = USB_HS_AHB_CBCR,
 	.has_sibling = 1,
@@ -2285,6 +2353,17 @@
 	},
 };
 
+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),
@@ -2304,7 +2383,7 @@
 		.dbg_name = "axi_clk_src",
 		.ops = &clk_ops_rcg,
 		VDD_DIG_FMAX_MAP3(LOW, 150000000, NOMINAL, 282000000,
-				  HIGH, 320000000),
+				  HIGH, 400000000),
 		CLK_INIT(axi_clk_src.c),
 	},
 };
@@ -2581,6 +2660,7 @@
 };
 
 static struct clk_freq_tbl ftbl_camss_mclk0_3_clk[] = {
+	F_MM(19200000,    cxo,   1,   0,   0),
 	F_MM(66670000,  gpll0,   9,   0,   0),
 	F_END
 };
@@ -2711,21 +2791,101 @@
 	},
 };
 
-static struct clk_freq_tbl ftbl_mdss_byte0_1_clk[] = {
-	F_MDSS( 93750000, dsipll_750,   8,   0,   0),
-	F_MDSS(187500000, dsipll_750,   4,   0,   0),
-	F_END
+static struct clk *dsi_pll_clk_get_parent(struct clk *c)
+{
+	return &cxo_clk_src.c;
+}
+
+static struct clk dsipll0_byte_clk_src = {
+	.dbg_name = "dsipll0_byte_clk_src",
+	.ops = &clk_ops_dsi_byte_pll,
+	CLK_INIT(dsipll0_byte_clk_src),
 };
 
+static struct clk dsipll0_pixel_clk_src = {
+	.dbg_name = "dsipll0_pixel_clk_src",
+	.ops = &clk_ops_dsi_pixel_pll,
+	CLK_INIT(dsipll0_pixel_clk_src),
+};
+
+static struct clk_freq_tbl byte_freq = {
+	.src_clk = &dsipll0_byte_clk_src,
+	.div_src_val = BVAL(10, 8, dsipll0_byte_mm_source_val),
+};
+static struct clk_freq_tbl pixel_freq = {
+	.src_clk = &dsipll0_byte_clk_src,
+	.div_src_val = BVAL(10, 8, dsipll0_byte_mm_source_val),
+};
+static struct clk_ops clk_ops_byte;
+static struct clk_ops clk_ops_pixel;
+
+#define CFG_RCGR_DIV_MASK		BM(4, 0)
+
+static int set_rate_byte(struct clk *clk, unsigned long rate)
+{
+	struct rcg_clk *rcg = to_rcg_clk(clk);
+	struct clk *pll = &dsipll0_byte_clk_src;
+	unsigned long source_rate, div;
+	int rc;
+
+	if (rate == 0)
+		return -EINVAL;
+
+	rc = clk_set_rate(pll, rate);
+	if (rc)
+		return rc;
+
+	source_rate = clk_round_rate(pll, rate);
+	if ((2 * source_rate) % rate)
+		return -EINVAL;
+
+	div = ((2 * source_rate)/rate) - 1;
+	if (div > CFG_RCGR_DIV_MASK)
+		return -EINVAL;
+
+	byte_freq.div_src_val &= ~CFG_RCGR_DIV_MASK;
+	byte_freq.div_src_val |= BVAL(4, 0, div);
+	set_rate_mnd(rcg, &byte_freq);
+
+	return 0;
+}
+
+static int set_rate_pixel(struct clk *clk, unsigned long rate)
+{
+	struct rcg_clk *rcg = to_rcg_clk(clk);
+	struct clk *pll = &dsipll0_pixel_clk_src;
+	unsigned long source_rate, div;
+	int rc;
+
+	if (rate == 0)
+		return -EINVAL;
+
+	rc = clk_set_rate(pll, rate);
+	if (rc)
+		return rc;
+
+	source_rate = clk_round_rate(pll, rate);
+	if ((2 * source_rate) % rate)
+		return -EINVAL;
+
+	div = ((2 * source_rate)/rate) - 1;
+	if (div > CFG_RCGR_DIV_MASK)
+		return -EINVAL;
+
+	pixel_freq.div_src_val &= ~CFG_RCGR_DIV_MASK;
+	pixel_freq.div_src_val |= BVAL(4, 0, div);
+	set_rate_hid(rcg, &pixel_freq);
+
+	return 0;
+}
+
 static struct rcg_clk byte0_clk_src = {
 	.cmd_rcgr_reg = BYTE0_CMD_RCGR,
-	.set_rate = set_rate_hid,
-	.freq_tbl = ftbl_mdss_byte0_1_clk,
-	.current_freq = &rcg_dummy_freq,
+	.current_freq = &byte_freq,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "byte0_clk_src",
-		.ops = &clk_ops_rcg,
+		.ops = &clk_ops_byte,
 		VDD_DIG_FMAX_MAP3(LOW, 93800000, NOMINAL, 187500000,
 				  HIGH, 188000000),
 		CLK_INIT(byte0_clk_src.c),
@@ -2734,13 +2894,11 @@
 
 static struct rcg_clk byte1_clk_src = {
 	.cmd_rcgr_reg = BYTE1_CMD_RCGR,
-	.set_rate = set_rate_hid,
-	.freq_tbl = ftbl_mdss_byte0_1_clk,
-	.current_freq = &rcg_dummy_freq,
+	.current_freq = &byte_freq,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "byte1_clk_src",
-		.ops = &clk_ops_rcg,
+		.ops = &clk_ops_byte,
 		VDD_DIG_FMAX_MAP3(LOW, 93800000, NOMINAL, 187500000,
 				  HIGH, 188000000),
 		CLK_INIT(byte1_clk_src.c),
@@ -2839,14 +2997,84 @@
 	},
 };
 
+static int hdmi_pll_clk_enable(struct clk *c)
+{
+	int ret;
+	unsigned long flags;
+
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+	ret = hdmi_pll_enable();
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+	return ret;
+}
+
+static void hdmi_pll_clk_disable(struct clk *c)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+	hdmi_pll_disable();
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+}
+
+static int hdmi_pll_clk_set_rate(struct clk *c, unsigned long rate)
+{
+	unsigned long flags;
+	int rc;
+
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+	rc = hdmi_pll_set_rate(rate);
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+
+	return rc;
+}
+
+static struct clk *hdmi_pll_clk_get_parent(struct clk *c)
+{
+	return &cxo_clk_src.c;
+}
+
+static struct clk_ops clk_ops_hdmi_pll = {
+	.enable = hdmi_pll_clk_enable,
+	.disable = hdmi_pll_clk_disable,
+	.set_rate = hdmi_pll_clk_set_rate,
+	.get_parent = hdmi_pll_clk_get_parent,
+};
+
+static struct clk hdmipll_clk_src = {
+	.dbg_name = "hdmipll_clk_src",
+	.ops = &clk_ops_hdmi_pll,
+	CLK_INIT(hdmipll_clk_src),
+};
+
 static struct clk_freq_tbl ftbl_mdss_extpclk_clk[] = {
-	F_MDSS(148500000, hdmipll_297,   2,   0,   0),
+	/*
+	 * The zero rate is required since suspend/resume wipes out the HDMI PHY
+	 * registers. This entry allows the HDMI driver to switch the cached
+	 * rate to zero before suspend and back to the real rate after resume.
+	 */
+	F_HDMI(        0, hdmipll, 1, 0, 0),
+	F_HDMI( 25200000, hdmipll, 1, 0, 0),
+	F_HDMI( 27030000, hdmipll, 1, 0, 0),
+	F_HDMI( 74250000, hdmipll, 1, 0, 0),
+	F_HDMI(148500000, hdmipll, 1, 0, 0),
+	F_HDMI(297000000, hdmipll, 1, 0, 0),
 	F_END
 };
 
+/*
+ * Unlike other clocks, the HDMI rate is adjusted through PLL
+ * re-programming. It is also routed through an HID divider.
+ */
+static void set_rate_hdmi(struct rcg_clk *rcg, struct clk_freq_tbl *nf)
+{
+	clk_set_rate(nf->src_clk, nf->freq_hz);
+	set_rate_hid(rcg, nf);
+}
+
 static struct rcg_clk extpclk_clk_src = {
 	.cmd_rcgr_reg = EXTPCLK_CMD_RCGR,
-	.set_rate = set_rate_hid,
+	.set_rate = set_rate_hdmi,
 	.freq_tbl = ftbl_mdss_extpclk_clk,
 	.current_freq = &rcg_dummy_freq,
 	.base = &virt_bases[MMSS_BASE],
@@ -2877,21 +3105,14 @@
 	},
 };
 
-static struct clk_freq_tbl ftbl_mdss_pclk0_1_clk[] = {
-	F_MDSS(125000000, dsipll_250,   2,   0,   0),
-	F_MDSS(250000000, dsipll_250,   1,   0,   0),
-	F_END
-};
 
 static struct rcg_clk pclk0_clk_src = {
 	.cmd_rcgr_reg = PCLK0_CMD_RCGR,
-	.set_rate = set_rate_mnd,
-	.freq_tbl = ftbl_mdss_pclk0_1_clk,
-	.current_freq = &rcg_dummy_freq,
+	.current_freq = &pixel_freq,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "pclk0_clk_src",
-		.ops = &clk_ops_rcg_mnd,
+		.ops = &clk_ops_pixel,
 		VDD_DIG_FMAX_MAP2(LOW, 125000000, NOMINAL, 250000000),
 		CLK_INIT(pclk0_clk_src.c),
 	},
@@ -2899,13 +3120,11 @@
 
 static struct rcg_clk pclk1_clk_src = {
 	.cmd_rcgr_reg = PCLK1_CMD_RCGR,
-	.set_rate = set_rate_mnd,
-	.freq_tbl = ftbl_mdss_pclk0_1_clk,
-	.current_freq = &rcg_dummy_freq,
+	.current_freq = &pixel_freq,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "pclk1_clk_src",
-		.ops = &clk_ops_rcg_mnd,
+		.ops = &clk_ops_pixel,
 		VDD_DIG_FMAX_MAP2(LOW, 125000000, NOMINAL, 250000000),
 		CLK_INIT(pclk1_clk_src.c),
 	},
@@ -3759,8 +3978,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",
@@ -3772,12 +3990,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,
 	},
 };
 
@@ -3867,7 +4087,7 @@
 
 static struct branch_clk oxili_gfx3d_clk = {
 	.cbcr_reg = OXILI_GFX3D_CBCR,
-	.has_sibling = 1,
+	.parent = &oxili_gfx3d_clk_src.c,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "oxili_gfx3d_clk",
@@ -3889,7 +4109,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
 };
 
@@ -3933,7 +4153,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),
@@ -4304,6 +4524,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,
@@ -4327,28 +4569,14 @@
 	},
 };
 
-static struct branch_clk mss_xo_q6_clk = {
-	.cbcr_reg = MSS_XO_Q6_CBCR,
-	.bcr_reg = MSS_Q6SS_BCR,
+static struct branch_clk audio_wrapper_br_clk = {
+	.cbcr_reg = AUDIO_WRAPPER_BR_CBCR,
 	.has_sibling = 1,
-	.base = &virt_bases[MSS_BASE],
+	.base = &virt_bases[LPASS_BASE],
 	.c = {
-		.dbg_name = "mss_xo_q6_clk",
+		.dbg_name = "audio_wrapper_br_clk",
 		.ops = &clk_ops_branch,
-		CLK_INIT(mss_xo_q6_clk.c),
-		.depends = &gcc_mss_cfg_ahb_clk.c,
-	},
-};
-
-static struct branch_clk mss_bus_q6_clk = {
-	.cbcr_reg = MSS_BUS_Q6_CBCR,
-	.has_sibling = 1,
-	.base = &virt_bases[MSS_BASE],
-	.c = {
-		.dbg_name = "mss_bus_q6_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(mss_bus_q6_clk.c),
-		.depends = &gcc_mss_cfg_ahb_clk.c,
+		CLK_INIT(audio_wrapper_br_clk.c),
 	},
 };
 
@@ -4435,8 +4663,14 @@
 	{&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_usb30_sleep_clk.c,		GCC_BASE, 0x0051},
+	{&gcc_usb2a_phy_sleep_clk.c,		GCC_BASE, 0x0063},
+	{&gcc_usb2b_phy_sleep_clk.c,		GCC_BASE, 0x0064},
+	{&gcc_sys_noc_usb3_axi_clk.c,		GCC_BASE, 0x0001},
 	{&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},
@@ -4489,6 +4723,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},
@@ -4518,8 +4762,8 @@
 	{&q6ss_xo_clk.c,			LPASS_BASE, 0x002b},
 	{&q6ss_ahb_lfabif_clk.c,		LPASS_BASE, 0x001e},
 	{&q6ss_ahbm_clk.c,			LPASS_BASE, 0x001d},
-	{&mss_bus_q6_clk.c,			MSS_BASE, 0x003c},
-	{&mss_xo_q6_clk.c,			MSS_BASE, 0x0007},
+	{&audio_core_ixfabric_clk.c,		LPASS_BASE, 0x0059},
+	{&audio_wrapper_br_clk.c,		LPASS_BASE, 0x0022},
 
 	{&l2_m_clk,				APCS_BASE, 0x0081},
 	{&krait0_m_clk,				APCS_BASE, 0x0080},
@@ -4554,18 +4798,15 @@
 	clk->sample_ticks = 0x10000;
 	clk->multiplier = 1;
 
-	writel_relaxed(0, MSS_REG_BASE(MSS_DEBUG_CLK_CTL_REG));
-	writel_relaxed(0, LPASS_REG_BASE(LPASS_DEBUG_CLK_CTL_REG));
-	writel_relaxed(0, MMSS_REG_BASE(MMSS_DEBUG_CLK_CTL_REG));
-	writel_relaxed(0, GCC_REG_BASE(GCC_DEBUG_CLK_CTL_REG));
-
 	switch (measure_mux[i].base) {
 
 	case GCC_BASE:
+		writel_relaxed(0, GCC_REG_BASE(GCC_DEBUG_CLK_CTL_REG));
 		clk_sel = measure_mux[i].debug_mux;
 		break;
 
 	case MMSS_BASE:
+		writel_relaxed(0, MMSS_REG_BASE(MMSS_DEBUG_CLK_CTL_REG));
 		clk_sel = 0x02C;
 		regval = BVAL(11, 0, measure_mux[i].debug_mux);
 		writel_relaxed(regval, MMSS_REG_BASE(MMSS_DEBUG_CLK_CTL_REG));
@@ -4576,21 +4817,16 @@
 		break;
 
 	case LPASS_BASE:
-		clk_sel = 0x169;
+		writel_relaxed(0, LPASS_REG_BASE(LPASS_DEBUG_CLK_CTL_REG));
+		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;
 
-	case MSS_BASE:
-		clk_sel = 0x32;
-		regval = BVAL(5, 0, measure_mux[i].debug_mux);
-		writel_relaxed(regval, MSS_REG_BASE(MSS_DEBUG_CLK_CTL_REG));
-		break;
-
 	case APCS_BASE:
 		clk->multiplier = 4;
 		clk_sel = 0x16A;
@@ -4687,6 +4923,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);
@@ -4735,8 +4972,8 @@
 	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,	"msm_serial_hsl.0",	OFF),
-	CLK_DUMMY("iface_clk",	BLSP2_UART_CLK,	"msm_serial_hsl.0",	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),
@@ -4766,16 +5003,19 @@
 	CLK_LOOKUP("xo",	cxo_clk_src.c,	"pil-q6v5-lpass"),
 	CLK_LOOKUP("xo",	cxo_clk_src.c,	"pil-q6v5-mss"),
 	CLK_LOOKUP("xo",	cxo_clk_src.c,	"pil-mba"),
+	CLK_LOOKUP("xo",	cxo_clk_src.c,	"fb000000.qcom,wcnss-wlan"),
 	CLK_LOOKUP("xo",	cxo_clk_src.c,	"pil_pronto"),
 	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, "spi_qsd.1"),
+	CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f991f000.serial"),
+	CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9924000.i2c"),
+	CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f991e000.serial"),
 	CLK_LOOKUP("core_clk", gcc_blsp1_qup1_i2c_apps_clk.c, ""),
-	CLK_LOOKUP("core_clk", gcc_blsp1_qup1_spi_apps_clk.c, ""),
-	CLK_LOOKUP("core_clk", gcc_blsp1_qup2_i2c_apps_clk.c, ""),
-	CLK_LOOKUP("core_clk", gcc_blsp1_qup2_spi_apps_clk.c, "spi_qsd.1"),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup2_i2c_apps_clk.c, "f9924000.i2c"),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup2_spi_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup1_spi_apps_clk.c, "f9923000.spi"),
+	CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9923000.spi"),
 	CLK_LOOKUP("core_clk", gcc_blsp1_qup3_i2c_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk", gcc_blsp1_qup3_spi_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk", gcc_blsp1_qup4_i2c_apps_clk.c, ""),
@@ -4785,13 +5025,13 @@
 	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, ""),
 
-	CLK_LOOKUP("iface_clk", gcc_blsp2_ahb_clk.c, "f9966000.i2c"),
+	CLK_LOOKUP("iface_clk", gcc_blsp2_ahb_clk.c, "f9967000.i2c"),
 	CLK_LOOKUP("iface_clk", gcc_blsp2_ahb_clk.c, "f995e000.serial"),
 	CLK_LOOKUP("core_clk", gcc_blsp2_qup1_i2c_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk", gcc_blsp2_qup1_spi_apps_clk.c, ""),
@@ -4799,9 +5039,9 @@
 	CLK_LOOKUP("core_clk", gcc_blsp2_qup2_spi_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk", gcc_blsp2_qup3_i2c_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk", gcc_blsp2_qup3_spi_apps_clk.c, ""),
-	CLK_LOOKUP("core_clk", gcc_blsp2_qup4_i2c_apps_clk.c, "f9966000.i2c"),
+	CLK_LOOKUP("core_clk", gcc_blsp2_qup4_i2c_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk", gcc_blsp2_qup4_spi_apps_clk.c, ""),
-	CLK_LOOKUP("core_clk", gcc_blsp2_qup5_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp2_qup5_i2c_apps_clk.c, "f9967000.i2c"),
 	CLK_LOOKUP("core_clk", gcc_blsp2_qup5_spi_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk", gcc_blsp2_qup6_i2c_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk", gcc_blsp2_qup6_spi_apps_clk.c, ""),
@@ -4812,6 +5052,7 @@
 	CLK_LOOKUP("core_clk", gcc_blsp2_uart5_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk", gcc_blsp2_uart6_apps_clk.c, ""),
 
+	CLK_LOOKUP("core_clk_src", ce1_clk_src.c, ""),
 	CLK_LOOKUP("core_clk", gcc_ce1_clk.c, ""),
 	CLK_LOOKUP("core_clk", gcc_ce2_clk.c, ""),
 	CLK_LOOKUP("iface_clk", gcc_ce1_ahb_clk.c, ""),
@@ -4853,8 +5094,15 @@
 	CLK_LOOKUP("iface_clk", gcc_tsif_ahb_clk.c, ""),
 	CLK_LOOKUP("ref_clk", gcc_tsif_ref_clk.c, ""),
 
+	CLK_LOOKUP("mem_clk", gcc_usb30_master_clk.c,           "usb_bam"),
+	CLK_LOOKUP("mem_iface_clk", gcc_sys_noc_usb3_axi_clk.c, "usb_bam"),
 	CLK_LOOKUP("core_clk", gcc_usb30_master_clk.c,    "msm_dwc3"),
 	CLK_LOOKUP("utmi_clk", gcc_usb30_mock_utmi_clk.c, "msm_dwc3"),
+	CLK_LOOKUP("iface_clk", gcc_sys_noc_usb3_axi_clk.c, "msm_dwc3"),
+	CLK_LOOKUP("sleep_clk", gcc_usb30_sleep_clk.c, "msm_dwc3"),
+	CLK_LOOKUP("sleep_a_clk", gcc_usb2a_phy_sleep_clk.c, "msm_dwc3"),
+	CLK_LOOKUP("sleep_b_clk", gcc_usb2b_phy_sleep_clk.c, "msm_dwc3"),
+	CLK_LOOKUP("ref_clk", diff_clk.c, "msm_dwc3"),
 	CLK_LOOKUP("iface_clk", gcc_usb_hs_ahb_clk.c,     "msm_otg"),
 	CLK_LOOKUP("core_clk", gcc_usb_hs_system_clk.c,   "msm_otg"),
 	CLK_LOOKUP("iface_clk", gcc_usb_hsic_ahb_clk.c,	  "msm_hsic_host"),
@@ -4871,71 +5119,157 @@
 	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, ""),
+	CLK_LOOKUP("pixel_clk", mdss_pclk0_clk.c, "fd922800.qcom,mdss_dsi"),
+	CLK_LOOKUP("pixel_clk", mdss_pclk1_clk.c, ""),
+	CLK_LOOKUP("iface_clk", mdss_hdmi_ahb_clk.c, "fd922100.qcom,hdmi_tx"),
+	CLK_LOOKUP("core_clk", mdss_hdmi_clk.c, "fd922100.qcom,hdmi_tx"),
+	CLK_LOOKUP("extp_clk", mdss_extpclk_clk.c, "fd922100.qcom,hdmi_tx"),
 	CLK_LOOKUP("core_clk", mdss_mdp_clk.c, "mdp.0"),
 	CLK_LOOKUP("lut_clk", mdss_mdp_lut_clk.c, "mdp.0"),
 	CLK_LOOKUP("core_clk_src", mdp_clk_src.c, "mdp.0"),
 	CLK_LOOKUP("vsync_clk", mdss_vsync_clk.c, "mdp.0"),
-	CLK_LOOKUP("iface_clk", camss_cci_cci_ahb_clk.c, ""),
-	CLK_LOOKUP("core_clk", camss_cci_cci_clk.c, ""),
-	CLK_LOOKUP("iface_clk", camss_csi0_ahb_clk.c, ""),
-	CLK_LOOKUP("camss_csi0_clk", camss_csi0_clk.c, ""),
-	CLK_LOOKUP("camss_csi0phy_clk", camss_csi0phy_clk.c, ""),
-	CLK_LOOKUP("camss_csi0pix_clk", camss_csi0pix_clk.c, ""),
-	CLK_LOOKUP("camss_csi0rdi_clk", camss_csi0rdi_clk.c, ""),
-	CLK_LOOKUP("iface_clk", camss_csi1_ahb_clk.c, ""),
-	CLK_LOOKUP("camss_csi1_clk", camss_csi1_clk.c, ""),
-	CLK_LOOKUP("camss_csi1phy_clk", camss_csi1phy_clk.c, ""),
-	CLK_LOOKUP("camss_csi1pix_clk", camss_csi1pix_clk.c, ""),
-	CLK_LOOKUP("camss_csi1rdi_clk", camss_csi1rdi_clk.c, ""),
-	CLK_LOOKUP("iface_clk", camss_csi2_ahb_clk.c, ""),
-	CLK_LOOKUP("camss_csi2_clk", camss_csi2_clk.c, ""),
-	CLK_LOOKUP("camss_csi2phy_clk", camss_csi2phy_clk.c, ""),
-	CLK_LOOKUP("camss_csi2pix_clk", camss_csi2pix_clk.c, ""),
-	CLK_LOOKUP("camss_csi2rdi_clk", camss_csi2rdi_clk.c, ""),
-	CLK_LOOKUP("iface_clk", camss_csi3_ahb_clk.c, ""),
-	CLK_LOOKUP("camss_csi3_clk", camss_csi3_clk.c, ""),
-	CLK_LOOKUP("camss_csi3phy_clk", camss_csi3phy_clk.c, ""),
-	CLK_LOOKUP("camss_csi3pix_clk", camss_csi3pix_clk.c, ""),
-	CLK_LOOKUP("camss_csi3rdi_clk", camss_csi3rdi_clk.c, ""),
-	CLK_LOOKUP("camss_csi0_clk_src", csi0_clk_src.c, ""),
-	CLK_LOOKUP("camss_csi1_clk_src", csi1_clk_src.c, ""),
-	CLK_LOOKUP("camss_csi2_clk_src", csi2_clk_src.c, ""),
-	CLK_LOOKUP("camss_csi3_clk_src", csi3_clk_src.c, ""),
-	CLK_LOOKUP("camss_csi_vfe0_clk", camss_csi_vfe0_clk.c, ""),
-	CLK_LOOKUP("camss_csi_vfe1_clk", camss_csi_vfe1_clk.c, ""),
-	CLK_LOOKUP("core_clk", camss_gp0_clk.c, ""),
-	CLK_LOOKUP("core_clk", camss_gp1_clk.c, ""),
-	CLK_LOOKUP("iface_clk", camss_ispif_ahb_clk.c, ""),
-	CLK_LOOKUP("core_clk", camss_jpeg_jpeg0_clk.c, ""),
-	CLK_LOOKUP("core_clk", camss_jpeg_jpeg1_clk.c, ""),
-	CLK_LOOKUP("core_clk", camss_jpeg_jpeg2_clk.c, ""),
+
+	/* MM sensor clocks */
+	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6e.qcom,camera"),
+	CLK_LOOKUP("cam_src_clk", mclk1_clk_src.c, "6c.qcom,camera"),
+	CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "6e.qcom,camera"),
+	CLK_LOOKUP("cam_clk", camss_mclk1_clk.c, "6c.qcom,camera"),
+	CLK_LOOKUP("cam_clk", camss_mclk1_clk.c, ""),
+	CLK_LOOKUP("cam_clk", camss_mclk2_clk.c, ""),
+	CLK_LOOKUP("cam_clk", camss_mclk3_clk.c, ""),
+	CLK_LOOKUP("cam_gp0_src_clk", mmss_gp0_clk_src.c, ""),
+	CLK_LOOKUP("cam_gp1_src_clk", mmss_gp1_clk_src.c, ""),
+	CLK_LOOKUP("cam_gp0_clk", camss_gp0_clk.c, ""),
+	CLK_LOOKUP("cam_gp1_clk", camss_gp1_clk.c, ""),
+	/* CCI clocks */
+	CLK_LOOKUP("camss_top_ahb_clk", camss_top_ahb_clk.c,
+		"fda0c000.qcom,cci"),
+	CLK_LOOKUP("cci_ahb_clk", camss_cci_cci_ahb_clk.c, "fda0c000.qcom,cci"),
+	CLK_LOOKUP("cci_src_clk", cci_clk_src.c, "fda0c000.qcom,cci"),
+	CLK_LOOKUP("cci_clk", camss_cci_cci_clk.c, "fda0c000.qcom,cci"),
+	/* CSIPHY clocks */
+	CLK_LOOKUP("ispif_ahb_clk", camss_ispif_ahb_clk.c,
+		"fda0ac00.qcom,csiphy"),
+	CLK_LOOKUP("csiphy_timer_src_clk", csi0phytimer_clk_src.c,
+		"fda0ac00.qcom,csiphy"),
+	CLK_LOOKUP("csiphy_timer_clk", camss_phy0_csi0phytimer_clk.c,
+		"fda0ac00.qcom,csiphy"),
+	CLK_LOOKUP("ispif_ahb_clk", camss_ispif_ahb_clk.c,
+		"fda0b000.qcom,csiphy"),
+	CLK_LOOKUP("csiphy_timer_src_clk", csi1phytimer_clk_src.c,
+		"fda0b000.qcom,csiphy"),
+	CLK_LOOKUP("csiphy_timer_clk", camss_phy1_csi1phytimer_clk.c,
+		"fda0b000.qcom,csiphy"),
+	CLK_LOOKUP("ispif_ahb_clk", camss_ispif_ahb_clk.c,
+		"fda0b400.qcom,csiphy"),
+	CLK_LOOKUP("csiphy_timer_src_clk", csi2phytimer_clk_src.c,
+		"fda0b400.qcom,csiphy"),
+	CLK_LOOKUP("csiphy_timer_clk", camss_phy2_csi2phytimer_clk.c,
+		"fda0b400.qcom,csiphy"),
+	/* CSID clocks */
+	CLK_LOOKUP("csi0_ahb_clk", camss_csi0_ahb_clk.c, "fda08000.qcom,csid"),
+	CLK_LOOKUP("csi0_src_clk", csi0_clk_src.c, "fda08000.qcom,csid"),
+	CLK_LOOKUP("csi0_phy_clk", camss_csi0phy_clk.c, "fda08000.qcom,csid"),
+	CLK_LOOKUP("csi0_clk", camss_csi0_clk.c, "fda08000.qcom,csid"),
+	CLK_LOOKUP("csi0_pix_clk", camss_csi0pix_clk.c, "fda08000.qcom,csid"),
+	CLK_LOOKUP("csi0_rdi_clk", camss_csi0rdi_clk.c, "fda08000.qcom,csid"),
+
+	CLK_LOOKUP("csi0_ahb_clk", camss_csi0_ahb_clk.c, "fda08400.qcom,csid"),
+	CLK_LOOKUP("csi1_ahb_clk", camss_csi1_ahb_clk.c, "fda08400.qcom,csid"),
+	CLK_LOOKUP("csi0_src_clk", csi0_clk_src.c, "fda08400.qcom,csid"),
+	CLK_LOOKUP("csi1_src_clk", csi1_clk_src.c, "fda08400.qcom,csid"),
+	CLK_LOOKUP("csi0_phy_clk", camss_csi0phy_clk.c, "fda08400.qcom,csid"),
+	CLK_LOOKUP("csi1_phy_clk", camss_csi1phy_clk.c, "fda08400.qcom,csid"),
+	CLK_LOOKUP("csi0_clk", camss_csi0_clk.c, "fda08400.qcom,csid"),
+	CLK_LOOKUP("csi1_clk", camss_csi1_clk.c, "fda08400.qcom,csid"),
+	CLK_LOOKUP("csi0_pix_clk", camss_csi0pix_clk.c, "fda08400.qcom,csid"),
+	CLK_LOOKUP("csi1_pix_clk", camss_csi1pix_clk.c, "fda08400.qcom,csid"),
+	CLK_LOOKUP("csi0_rdi_clk", camss_csi0rdi_clk.c, "fda08400.qcom,csid"),
+	CLK_LOOKUP("csi1_rdi_clk", camss_csi1rdi_clk.c, "fda08400.qcom,csid"),
+
+	CLK_LOOKUP("csi0_ahb_clk", camss_csi0_ahb_clk.c, "fda08800.qcom,csid"),
+	CLK_LOOKUP("csi2_ahb_clk", camss_csi2_ahb_clk.c, "fda08800.qcom,csid"),
+	CLK_LOOKUP("csi0_src_clk", csi0_clk_src.c, "fda08800.qcom,csid"),
+	CLK_LOOKUP("csi2_src_clk", csi2_clk_src.c, "fda08800.qcom,csid"),
+	CLK_LOOKUP("csi0_phy_clk", camss_csi0phy_clk.c, "fda08800.qcom,csid"),
+	CLK_LOOKUP("csi2_phy_clk", camss_csi2phy_clk.c, "fda08800.qcom,csid"),
+	CLK_LOOKUP("csi0_clk", camss_csi0_clk.c, "fda08800.qcom,csid"),
+	CLK_LOOKUP("csi2_clk", camss_csi2_clk.c, "fda08800.qcom,csid"),
+	CLK_LOOKUP("csi0_pix_clk", camss_csi0pix_clk.c, "fda08800.qcom,csid"),
+	CLK_LOOKUP("csi2_pix_clk", camss_csi2pix_clk.c, "fda08800.qcom,csid"),
+	CLK_LOOKUP("csi0_rdi_clk", camss_csi0rdi_clk.c, "fda08800.qcom,csid"),
+	CLK_LOOKUP("csi2_rdi_clk", camss_csi2rdi_clk.c, "fda08800.qcom,csid"),
+
+	CLK_LOOKUP("csi0_ahb_clk", camss_csi0_ahb_clk.c, "fda08c00.qcom,csid"),
+	CLK_LOOKUP("csi3_ahb_clk", camss_csi3_ahb_clk.c, "fda08c00.qcom,csid"),
+	CLK_LOOKUP("csi0_src_clk", csi0_clk_src.c, "fda08c00.qcom,csid"),
+	CLK_LOOKUP("csi3_src_clk", csi3_clk_src.c, "fda08c00.qcom,csid"),
+	CLK_LOOKUP("csi0_phy_clk", camss_csi0phy_clk.c, "fda08c00.qcom,csid"),
+	CLK_LOOKUP("csi3_phy_clk", camss_csi3phy_clk.c, "fda08c00.qcom,csid"),
+	CLK_LOOKUP("csi0_clk", camss_csi0_clk.c, "fda08c00.qcom,csid"),
+	CLK_LOOKUP("csi3_clk", camss_csi3_clk.c, "fda08c00.qcom,csid"),
+	CLK_LOOKUP("csi0_pix_clk", camss_csi0pix_clk.c, "fda08c00.qcom,csid"),
+	CLK_LOOKUP("csi3_pix_clk", camss_csi3pix_clk.c, "fda08c00.qcom,csid"),
+	CLK_LOOKUP("csi0_rdi_clk", camss_csi0rdi_clk.c, "fda08c00.qcom,csid"),
+	CLK_LOOKUP("csi3_rdi_clk", camss_csi3rdi_clk.c, "fda08c00.qcom,csid"),
+
+	/*VFE clocks*/
+	CLK_LOOKUP("camss_top_ahb_clk", camss_top_ahb_clk.c,
+					"fda10000.qcom,vfe"),
+	CLK_LOOKUP("vfe_clk_src", vfe0_clk_src.c,	 "fda10000.qcom,vfe"),
+	CLK_LOOKUP("camss_vfe_vfe_clk", camss_vfe_vfe0_clk.c,
+					"fda10000.qcom,vfe"),
+	CLK_LOOKUP("camss_csi_vfe_clk", camss_csi_vfe0_clk.c,
+					"fda10000.qcom,vfe"),
+	CLK_LOOKUP("iface_clk", camss_vfe_vfe_ahb_clk.c, "fda10000.qcom,vfe"),
+	CLK_LOOKUP("bus_clk", camss_vfe_vfe_axi_clk.c,	 "fda10000.qcom,vfe"),
+	CLK_LOOKUP("alt_bus_clk", camss_vfe_vfe_ocmemnoc_clk.c,
+					"fda10000.qcom,vfe"),
+	CLK_LOOKUP("camss_top_ahb_clk", camss_top_ahb_clk.c,
+					"fda14000.qcom,vfe"),
+	CLK_LOOKUP("vfe_clk_src", vfe1_clk_src.c,	 "fda14000.qcom,vfe"),
+	CLK_LOOKUP("camss_vfe_vfe_clk", camss_vfe_vfe1_clk.c,
+					"fda14000.qcom,vfe"),
+	CLK_LOOKUP("camss_csi_vfe_clk", camss_csi_vfe1_clk.c,
+					"fda14000.qcom,vfe"),
+	CLK_LOOKUP("iface_clk", camss_vfe_vfe_ahb_clk.c, "fda14000.qcom,vfe"),
+	CLK_LOOKUP("bus_clk", camss_vfe_vfe_axi_clk.c,	 "fda14000.qcom,vfe"),
+	CLK_LOOKUP("alt_bus_clk", camss_vfe_vfe_ocmemnoc_clk.c,
+					"fda14000.qcom,vfe"),
+	/*Jpeg Clocks*/
+	CLK_LOOKUP("core_clk", camss_jpeg_jpeg0_clk.c, "fda1c000.qcom,jpeg"),
+	CLK_LOOKUP("core_clk", camss_jpeg_jpeg1_clk.c, "fda20000.qcom,jpeg"),
+	CLK_LOOKUP("core_clk", camss_jpeg_jpeg2_clk.c, "fda24000.qcom,jpeg"),
+	CLK_LOOKUP("iface_clk", camss_jpeg_jpeg_ahb_clk.c,
+						"fda1c000.qcom,jpeg"),
+	CLK_LOOKUP("iface_clk", camss_jpeg_jpeg_ahb_clk.c,
+						"fda20000.qcom,jpeg"),
+	CLK_LOOKUP("iface_clk", camss_jpeg_jpeg_ahb_clk.c,
+						"fda24000.qcom,jpeg"),
 	CLK_LOOKUP("iface_clk", camss_jpeg_jpeg_ahb_clk.c,
 						"fda64000.qcom,iommu"),
 	CLK_LOOKUP("core_clk", camss_jpeg_jpeg_axi_clk.c,
 						"fda64000.qcom,iommu"),
-	CLK_LOOKUP("bus_clk", camss_jpeg_jpeg_axi_clk.c, ""),
-	CLK_LOOKUP("bus_clk", camss_jpeg_jpeg_ocmemnoc_clk.c, ""),
-	CLK_LOOKUP("core_clk", camss_mclk0_clk.c, ""),
-	CLK_LOOKUP("core_clk", camss_mclk1_clk.c, ""),
-	CLK_LOOKUP("core_clk", camss_mclk2_clk.c, ""),
-	CLK_LOOKUP("core_clk", camss_mclk3_clk.c, ""),
+	CLK_LOOKUP("bus_clk0", camss_jpeg_jpeg_axi_clk.c, "fda1c000.qcom,jpeg"),
+	CLK_LOOKUP("bus_clk0", camss_jpeg_jpeg_axi_clk.c, "fda20000.qcom,jpeg"),
+	CLK_LOOKUP("bus_clk0", camss_jpeg_jpeg_axi_clk.c, "fda24000.qcom,jpeg"),
+	CLK_LOOKUP("alt_bus_clk", camss_jpeg_jpeg_ocmemnoc_clk.c,
+						"fda1c000.qcom,jpeg"),
+	CLK_LOOKUP("alt_bus_clk", camss_jpeg_jpeg_ocmemnoc_clk.c,
+						"fda20000.qcom,jpeg"),
+	CLK_LOOKUP("alt_bus_clk", camss_jpeg_jpeg_ocmemnoc_clk.c,
+						"fda24000.qcom,jpeg"),
+	CLK_LOOKUP("camss_top_ahb_clk", camss_top_ahb_clk.c,
+						"fda1c000.qcom,jpeg"),
+	CLK_LOOKUP("camss_top_ahb_clk", camss_top_ahb_clk.c,
+						"fda20000.qcom,jpeg"),
+	CLK_LOOKUP("camss_top_ahb_clk", camss_top_ahb_clk.c,
+						"fda24000.qcom,jpeg"),
 	CLK_LOOKUP("iface_clk", camss_micro_ahb_clk.c, ""),
-	CLK_LOOKUP("core_clk", camss_phy0_csi0phytimer_clk.c, ""),
-	CLK_LOOKUP("core_clk", camss_phy1_csi1phytimer_clk.c, ""),
-	CLK_LOOKUP("core_clk", camss_phy2_csi2phytimer_clk.c, ""),
-	CLK_LOOKUP("iface_clk", camss_top_ahb_clk.c, ""),
 	CLK_LOOKUP("iface_clk", camss_vfe_cpp_ahb_clk.c, "fda44000.qcom,iommu"),
 	CLK_LOOKUP("core_clk", camss_vfe_cpp_clk.c, "fda44000.qcom,iommu"),
-	CLK_LOOKUP("camss_vfe_vfe0_clk", camss_vfe_vfe0_clk.c, ""),
-	CLK_LOOKUP("camss_vfe_vfe1_clk", camss_vfe_vfe1_clk.c, ""),
-	CLK_LOOKUP("vfe0_clk_src", vfe0_clk_src.c, ""),
-	CLK_LOOKUP("vfe1_clk_src", vfe1_clk_src.c, ""),
-	CLK_LOOKUP("iface_clk", camss_vfe_vfe_ahb_clk.c, ""),
-	CLK_LOOKUP("bus_clk", camss_vfe_vfe_axi_clk.c, ""),
-	CLK_LOOKUP("bus_clk", camss_vfe_vfe_ocmemnoc_clk.c, ""),
 	CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "mdp.0"),
+	CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "mdss_dsi_clk_ctrl"),
 	CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "fd928000.qcom,iommu"),
 	CLK_LOOKUP("core_clk", mdss_axi_clk.c, "fd928000.qcom,iommu"),
 	CLK_LOOKUP("bus_clk", mdss_axi_clk.c, "mdp.0"),
@@ -4946,6 +5280,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"),
@@ -4962,6 +5298,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"),
@@ -4998,14 +5335,16 @@
 						"msm-dai-q6.4106"),
 	CLK_LOOKUP("core_oe_clk", audio_core_lpaif_pcmoe_clk.c,
 						"msm-dai-q6.4106"),
+	CLK_LOOKUP("br_clk", audio_wrapper_br_clk.c, "fdd00000.qcom,ocmem"),
 
-	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("reg_clk",        q6ss_ahbm_clk.c, "pil-q6v5-lpass"),
+	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("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"),
 
 	CLK_LOOKUP("dfab_clk", pnoc_sps_clk.c, "msm_sps"),
@@ -5035,8 +5374,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, ""),
 
@@ -5234,9 +5573,24 @@
 #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))
@@ -5266,6 +5620,44 @@
 	 * 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 mdss_clock_setup(void)
+{
+	clk_ops_byte = clk_ops_rcg_mnd;
+	clk_ops_byte.set_rate = set_rate_byte;
+	clk_ops_dsi_byte_pll.get_parent = dsi_pll_clk_get_parent;
+
+	clk_ops_pixel = clk_ops_rcg;
+	clk_ops_pixel.set_rate = set_rate_pixel;
+	clk_ops_dsi_pixel_pll.get_parent = dsi_pll_clk_get_parent;
+
+	mdss_clk_ctrl_init();
 }
 
 static void __init msm8974_clock_post_init(void)
@@ -5286,6 +5678,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.
@@ -5293,6 +5690,8 @@
 	clk_prepare_enable(&gcc_mmss_noc_cfg_ahb_clk.c);
 	clk_prepare_enable(&gcc_ocmem_noc_cfg_ahb_clk.c);
 
+	mdss_clock_setup();
+
 	/* Set rates for single-rate clocks. */
 	clk_set_rate(&usb30_master_clk_src.c,
 			usb30_master_clk_src.freq_tbl[0].freq_hz);
@@ -5331,12 +5730,27 @@
 #define LPASS_CC_PHYS		0xFE000000
 #define LPASS_CC_SIZE		SZ_256K
 
-#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)
 {
 	virt_bases[GCC_BASE] = ioremap(GCC_CC_PHYS, GCC_CC_SIZE);
@@ -5351,10 +5765,6 @@
 	if (!virt_bases[LPASS_BASE])
 		panic("clock-8974: Unable to ioremap LPASS_CC memory!");
 
-	virt_bases[MSS_BASE] = ioremap(MSS_CC_PHYS, MSS_CC_SIZE);
-	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!");
@@ -5374,6 +5784,8 @@
 	vote_vdd_level(&vdd_dig, VDD_DIG_HIGH);
 	rpm_regulator_enable(vdd_dig_reg);
 
+	enable_rpm_scaling();
+
 	reg_init();
 }
 
diff --git a/arch/arm/mach-msm/clock-8x60.c b/arch/arm/mach-msm/clock-8x60.c
index bc57c3b..24c06c9 100644
--- a/arch/arm/mach-msm/clock-8x60.c
+++ b/arch/arm/mach-msm/clock-8x60.c
@@ -313,7 +313,6 @@
 		.rate = 384000000,
 		.ops = &clk_ops_pll_vote,
 		CLK_INIT(pll8_clk.c),
-		.warned = true,
 	},
 };
 
@@ -325,7 +324,6 @@
 		.rate = 800000000,
 		.ops = &clk_ops_local_pll,
 		CLK_INIT(pll2_clk.c),
-		.warned = true,
 	},
 };
 
@@ -337,7 +335,6 @@
 		.rate = 0, /* TODO: Detect rate dynamically */
 		.ops = &clk_ops_local_pll,
 		CLK_INIT(pll3_clk.c),
-		.warned = true,
 	},
 };
 
@@ -387,7 +384,6 @@
 		.rate = 540672000,
 		.ops = &clk_ops_pll4,
 		CLK_INIT(pll4_clk.c),
-		.warned = true,
 	},
 };
 
diff --git a/arch/arm/mach-msm/clock-9615.c b/arch/arm/mach-msm/clock-9615.c
index 494823b..648a8d4 100644
--- a/arch/arm/mach-msm/clock-9615.c
+++ b/arch/arm/mach-msm/clock-9615.c
@@ -272,7 +272,6 @@
 		.rate = 276000000,
 		.ops = &clk_ops_pll_acpu_vote,
 		CLK_INIT(pll0_clk.c),
-		.warned = true,
 	},
 };
 
@@ -288,7 +287,6 @@
 		.rate = 276000000,
 		.ops = &clk_ops_pll_acpu_vote,
 		CLK_INIT(pll0_activeonly_clk.c),
-		.warned = true,
 	},
 };
 
@@ -303,7 +301,6 @@
 		.rate = 393216000,
 		.ops = &clk_ops_pll_vote,
 		CLK_INIT(pll4_clk.c),
-		.warned = true,
 	},
 };
 
@@ -322,7 +319,6 @@
 		.rate = 384000000,
 		.ops = &clk_ops_pll_acpu_vote,
 		CLK_INIT(pll8_clk.c),
-		.warned = true,
 	},
 };
 
@@ -338,7 +334,6 @@
 		.rate = 384000000,
 		.ops = &clk_ops_pll_acpu_vote,
 		CLK_INIT(pll8_activeonly_clk.c),
-		.warned = true,
 	},
 };
 
@@ -349,7 +344,6 @@
 		.rate = 440000000,
 		.ops = &clk_ops_local_pll,
 		CLK_INIT(pll9_activeonly_clk.c),
-		.warned = true,
 	},
 };
 
@@ -364,7 +358,6 @@
 		.rate = 480000000,
 		.ops = &clk_ops_pll_vote,
 		CLK_INIT(pll14_clk.c),
-		.warned = true,
 	},
 };
 
diff --git a/arch/arm/mach-msm/clock-debug.c b/arch/arm/mach-msm/clock-debug.c
index 099b012..c996ff4 100644
--- a/arch/arm/mach-msm/clock-debug.c
+++ b/arch/arm/mach-msm/clock-debug.c
@@ -175,16 +175,18 @@
 {
 	char *start = "";
 
-	if (!c || !c->count)
+	if (!c || !c->prepare_count)
 		return 0;
 
 	pr_info("\t");
 	do {
 		if (c->vdd_class)
-			pr_cont("%s%s [%ld, %lu]", start, c->dbg_name, c->rate,
+			pr_cont("%s%s:%u:%u [%ld, %lu]", start, c->dbg_name,
+				c->prepare_count, c->count, c->rate,
 				c->vdd_class->cur_level);
 		else
-			pr_cont("%s%s [%ld]", start, c->dbg_name, c->rate);
+			pr_cont("%s%s:%u:%u [%ld]", start, c->dbg_name,
+				c->prepare_count, c->count, c->rate);
 		start = " -> ";
 	} while ((c = clk_get_parent(c)));
 
@@ -250,6 +252,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;
@@ -293,6 +329,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 2df1cd1..b952f2f 100644
--- a/arch/arm/mach-msm/clock-local.c
+++ b/arch/arm/mach-msm/clock-local.c
@@ -320,10 +320,6 @@
 	u32 reg_val;
 	void __iomem *const reg = rcg->b.ctl_reg;
 
-	WARN(rcg->current_freq == &rcg_dummy_freq,
-		"Attempting to enable %s before setting its rate. "
-		"Set the rate first!\n", rcg->c.dbg_name);
-
 	/*
 	 * Program the NS register, if applicable. NS registers are not
 	 * set in the set_rate path because power can be saved by deferring
@@ -419,6 +415,18 @@
 	}
 }
 
+static int rcg_clk_prepare(struct clk *c)
+{
+	struct rcg_clk *rcg = to_rcg_clk(c);
+
+	WARN(rcg->current_freq == &rcg_dummy_freq,
+		"Attempting to prepare %s before setting its rate. "
+		"Set the rate first!\n", rcg->c.dbg_name);
+	rcg->prepared = true;
+
+	return 0;
+}
+
 /* Enable a rate-settable clock. */
 static int rcg_clk_enable(struct clk *c)
 {
@@ -445,6 +453,12 @@
 	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
 }
 
+static void rcg_clk_unprepare(struct clk *c)
+{
+	struct rcg_clk *rcg = to_rcg_clk(c);
+	rcg->prepared = false;
+}
+
 /*
  * Frequency-related functions
  */
@@ -456,6 +470,7 @@
 	struct clk_freq_tbl *nf, *cf;
 	struct clk *chld;
 	int rc = 0;
+	unsigned long flags;
 
 	for (nf = rcg->freq_tbl; nf->freq_hz != FREQ_END
 			&& nf->freq_hz != rate; nf++)
@@ -466,11 +481,22 @@
 
 	cf = rcg->current_freq;
 
-	if (rcg->enabled) {
-		/* Enable source clock dependency for the new freq. */
-		rc = clk_enable(nf->src_clk);
+	/* Enable source clock dependency for the new frequency */
+	if (rcg->prepared) {
+		rc = clk_prepare(nf->src_clk);
 		if (rc)
 			return rc;
+
+	}
+
+	spin_lock_irqsave(&c->lock, flags);
+	if (rcg->enabled) {
+		rc = clk_enable(nf->src_clk);
+		if (rc) {
+			spin_unlock_irqrestore(&c->lock, flags);
+			clk_unprepare(nf->src_clk);
+			return rc;
+		}
 	}
 
 	spin_lock(&local_clock_reg_lock);
@@ -519,6 +545,10 @@
 	/* Release source requirements of the old freq. */
 	if (rcg->enabled)
 		clk_disable(cf->src_clk);
+	spin_unlock_irqrestore(&c->lock, flags);
+
+	if (rcg->prepared)
+		clk_unprepare(cf->src_clk);
 
 	return rc;
 }
@@ -819,8 +849,10 @@
 }
 
 struct clk_ops clk_ops_rcg = {
+	.prepare = rcg_clk_prepare,
 	.enable = rcg_clk_enable,
 	.disable = rcg_clk_disable,
+	.unprepare = rcg_clk_unprepare,
 	.enable_hwcg = rcg_clk_enable_hwcg,
 	.disable_hwcg = rcg_clk_disable_hwcg,
 	.in_hwcg_mode = rcg_clk_in_hwcg_mode,
diff --git a/arch/arm/mach-msm/clock-local.h b/arch/arm/mach-msm/clock-local.h
index 034e09c..81085ef 100644
--- a/arch/arm/mach-msm/clock-local.h
+++ b/arch/arm/mach-msm/clock-local.h
@@ -164,6 +164,7 @@
  * Generic clock-definition struct and macros
  */
 struct rcg_clk {
+	bool		prepared;
 	bool		enabled;
 	void		*const ns_reg;
 	void		*const md_reg;
diff --git a/arch/arm/mach-msm/clock-local2.c b/arch/arm/mach-msm/clock-local2.c
index d5ee35b..3f19b2a 100644
--- a/arch/arm/mach-msm/clock-local2.c
+++ b/arch/arm/mach-msm/clock-local2.c
@@ -110,20 +110,26 @@
 void set_rate_hid(struct rcg_clk *rcg, struct clk_freq_tbl *nf)
 {
 	u32 cfg_regval;
+	unsigned long flags;
 
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
 	cfg_regval = readl_relaxed(CFG_RCGR_REG(rcg));
 	cfg_regval &= ~(CFG_RCGR_DIV_MASK | CFG_RCGR_SRC_SEL_MASK);
 	cfg_regval |= nf->div_src_val;
 	writel_relaxed(cfg_regval, CFG_RCGR_REG(rcg));
 
 	rcg_update_config(rcg);
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
 }
 
 /* RCG set rate function for clocks with MND & Half Integer Dividers. */
 void set_rate_mnd(struct rcg_clk *rcg, struct clk_freq_tbl *nf)
 {
 	u32 cfg_regval;
+	unsigned long flags;
 
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+	cfg_regval = readl_relaxed(CFG_RCGR_REG(rcg));
 	writel_relaxed(nf->m_val, M_REG(rcg));
 	writel_relaxed(nf->n_val, N_REG(rcg));
 	writel_relaxed(nf->d_val, D_REG(rcg));
@@ -139,14 +145,15 @@
 	writel_relaxed(cfg_regval, CFG_RCGR_REG(rcg));
 
 	rcg_update_config(rcg);
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
 }
 
-static int rcg_clk_enable(struct clk *c)
+static int rcg_clk_prepare(struct clk *c)
 {
 	struct rcg_clk *rcg = to_rcg_clk(c);
 
 	WARN(rcg->current_freq == &rcg_dummy_freq,
-		"Attempting to enable %s before setting its rate. "
+		"Attempting to prepare %s before setting its rate. "
 		"Set the rate first!\n", rcg->c.dbg_name);
 
 	return 0;
@@ -156,7 +163,7 @@
 {
 	struct clk_freq_tbl *cf, *nf;
 	struct rcg_clk *rcg = to_rcg_clk(c);
-	int rc = 0;
+	int rc;
 	unsigned long flags;
 
 	for (nf = rcg->freq_tbl; nf->freq_hz != FREQ_END
@@ -168,30 +175,39 @@
 
 	cf = rcg->current_freq;
 
-	if (rcg->c.count) {
-		/* TODO: Modify to use the prepare API */
-		/* Enable source clock dependency for the new freq. */
-		rc = clk_enable(nf->src_clk);
+	/* Enable source clock dependency for the new freq. */
+	if (c->prepare_count) {
+		rc = clk_prepare(nf->src_clk);
 		if (rc)
-			goto out;
+			return rc;
+	}
+
+	spin_lock_irqsave(&c->lock, flags);
+	if (c->count) {
+		rc = clk_enable(nf->src_clk);
+		if (rc) {
+			spin_unlock_irqrestore(&c->lock, flags);
+			clk_unprepare(nf->src_clk);
+			return rc;
+		}
 	}
 
 	BUG_ON(!rcg->set_rate);
 
-	spin_lock_irqsave(&local_clock_reg_lock, flags);
-
 	/* Perform clock-specific frequency switch operations. */
 	rcg->set_rate(rcg, nf);
 
-	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
-
 	/* Release source requirements of the old freq. */
-	if (rcg->c.count)
+	if (c->count)
 		clk_disable(cf->src_clk);
+	spin_unlock_irqrestore(&c->lock, flags);
+
+	if (c->prepare_count)
+		clk_unprepare(cf->src_clk);
 
 	rcg->current_freq = nf;
-out:
-	return rc;
+
+	return 0;
 }
 
 /* Return a supported rate that's at least the specified rate. */
@@ -583,7 +599,7 @@
 struct clk_ops clk_ops_empty;
 
 struct clk_ops clk_ops_rcg = {
-	.enable = rcg_clk_enable,
+	.enable = rcg_clk_prepare,
 	.set_rate = rcg_clk_set_rate,
 	.list_rate = rcg_clk_list_rate,
 	.round_rate = rcg_clk_round_rate,
@@ -592,7 +608,7 @@
 };
 
 struct clk_ops clk_ops_rcg_mnd = {
-	.enable = rcg_clk_enable,
+	.enable = rcg_clk_prepare,
 	.set_rate = rcg_clk_set_rate,
 	.list_rate = rcg_clk_list_rate,
 	.round_rate = rcg_clk_round_rate,
diff --git a/arch/arm/mach-msm/clock-local2.h b/arch/arm/mach-msm/clock-local2.h
index 572cec6f..46e9e0c 100644
--- a/arch/arm/mach-msm/clock-local2.h
+++ b/arch/arm/mach-msm/clock-local2.h
@@ -36,7 +36,7 @@
 	const u32	m_val;
 	const u32	n_val;
 	const u32	d_val;
-	const u32	div_src_val;
+	u32	div_src_val;
 	const unsigned	sys_vdd;
 };
 
diff --git a/arch/arm/mach-msm/clock-mdss-8974.c b/arch/arm/mach-msm/clock-mdss-8974.c
new file mode 100644
index 0000000..4d147c3
--- /dev/null
+++ b/arch/arm/mach-msm/clock-mdss-8974.c
@@ -0,0 +1,467 @@
+/* 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/io.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/iopoll.h>
+#include <linux/clk.h>
+
+#include <asm/processor.h>
+#include <mach/msm_iomap.h>
+
+#include "clock.h"
+#include "clock-mdss-8974.h"
+
+#define REG_R(addr)		readl_relaxed(addr)
+#define REG_W(data, addr)	writel_relaxed(data, addr)
+
+#define DSI_PHY_PHYS		0xFD922800
+#define DSI_PHY_SIZE		0x00000800
+
+#define HDMI_PHY_PHYS		0xFD922500
+#define HDMI_PHY_SIZE		0x0000007C
+
+#define HDMI_PHY_PLL_PHYS	0xFD922700
+#define HDMI_PHY_PLL_SIZE	0x000000D4
+
+/* hdmi phy registers */
+#define HDMI_PHY_PD_CTRL0		(0x0010)
+#define HDMI_PHY_GLB_CFG		(0x0018)
+#define HDMI_PHY_STATUS			(0x005C)
+
+/* hdmi phy unified pll registers */
+#define	 HDMI_UNI_PLL_REFCLK_CF		(0x0000)
+#define	 HDMI_UNI_PLL_POSTDIV1_CFG	(0x0004)
+#define	 HDMI_UNI_PLL_VCOLPF_CFG	(0x000C)
+#define	 HDMI_UNI_PLL_GLB_CFG		(0x0020)
+#define	 HDMI_UNI_PLL_POSTDIV2_CFG	(0x0024)
+#define	 HDMI_UNI_PLL_POSTDIV3_CFG	(0x0028)
+#define	 HDMI_UNI_PLL_SDM_CFG0		(0x0038)
+#define	 HDMI_UNI_PLL_SDM_CFG1		(0x003C)
+#define	 HDMI_UNI_PLL_SDM_CFG2		(0x0040)
+#define	 HDMI_UNI_PLL_SDM_CFG3		(0x0044)
+#define	 HDMI_UNI_PLL_SDM_CFG4		(0x0048)
+#define	 HDMI_UNI_PLL_LKDET_CFG0	(0x005C)
+#define	 HDMI_UNI_PLL_LKDET_CFG1	(0x0060)
+#define	 HDMI_UNI_PLL_LKDET_CFG2	(0x0064)
+#define	 HDMI_UNI_PLL_CAL_CFG8		(0x008C)
+#define	 HDMI_UNI_PLL_CAL_CFG9		(0x0090)
+#define	 HDMI_UNI_PLL_CAL_CFG10		(0x0094)
+#define	 HDMI_UNI_PLL_CAL_CFG11		(0x0098)
+#define  HDMI_UNI_PLL_STATUS		(0x00C0)
+
+#define VCO_CLK				424000000
+static unsigned char *mdss_dsi_base;
+static int pll_byte_clk_rate;
+static int pll_pclk_rate;
+static int pll_initialized;
+static struct clk *mdss_dsi_ahb_clk;
+
+static void __iomem *hdmi_phy_base;
+static void __iomem *hdmi_phy_pll_base;
+static unsigned hdmi_pll_on;
+
+void __init mdss_clk_ctrl_init(void)
+{
+	mdss_dsi_base = ioremap(DSI_PHY_PHYS, DSI_PHY_SIZE);
+	if (!mdss_dsi_base)
+		pr_err("%s: unable to remap dsi base", __func__);
+
+	mdss_dsi_ahb_clk = clk_get_sys("mdss_dsi_clk_ctrl", "iface_clk");
+	if (!IS_ERR(mdss_dsi_ahb_clk)) {
+		clk_prepare(mdss_dsi_ahb_clk);
+	} else {
+		mdss_dsi_ahb_clk = NULL;
+		pr_err("%s:%d unable to get dsi iface clock\n",
+			       __func__, __LINE__);
+	}
+
+	hdmi_phy_base = ioremap(HDMI_PHY_PHYS, HDMI_PHY_SIZE);
+	if (!hdmi_phy_base)
+		pr_err("%s: unable to ioremap hdmi phy base", __func__);
+
+	hdmi_phy_pll_base = ioremap(HDMI_PHY_PLL_PHYS, HDMI_PHY_PLL_SIZE);
+	if (!hdmi_phy_pll_base)
+		pr_err("%s: unable to ioremap hdmi phy pll base", __func__);
+}
+
+static long mdss_dsi_pll_byte_round_rate(struct clk *c, unsigned long rate)
+{
+	if (pll_initialized)
+		return pll_byte_clk_rate;
+	else {
+		pr_err("%s: DSI PLL not configured\n",
+				__func__);
+		return -EINVAL;
+	}
+}
+
+static long mdss_dsi_pll_pixel_round_rate(struct clk *c, unsigned long rate)
+{
+	if (pll_initialized)
+		return pll_pclk_rate;
+	else {
+		pr_err("%s: Configure Byte clk first\n",
+				__func__);
+		return -EINVAL;
+	}
+}
+
+static int mdss_dsi_pll_pixel_set_rate(struct clk *c, unsigned long rate)
+{
+	if (pll_initialized)
+		return 0;
+	else {
+		pr_err("%s: Configure Byte clk first\n",
+				__func__);
+		return -EINVAL;
+	}
+}
+
+static int mdss_dsi_pll_byte_set_rate(struct clk *c, unsigned long rate)
+{
+	int pll_divcfg1, pll_divcfg2;
+	int half_bitclk_rate;
+
+	if (pll_initialized)
+		return 0;
+
+	if (!mdss_dsi_ahb_clk) {
+		pr_err("%s: mdss_dsi_ahb_clk not initialized\n",
+				__func__);
+		return -EINVAL;
+	}
+
+	clk_enable(mdss_dsi_ahb_clk);
+
+	half_bitclk_rate = rate * 4;
+
+	pll_divcfg1 = (VCO_CLK / half_bitclk_rate) - 2;
+
+	/* Configuring the VCO to 424 Mhz */
+	/* Configuring the half rate Bit clk to 212 Mhz */
+
+	pll_divcfg2 = 3; /* ByteClk is 1/4 the half-bitClk rate */
+
+	/* Configure the Loop filter */
+	/* Loop filter resistance value */
+	REG_W(0x08, mdss_dsi_base + 0x022c);
+	/* Loop filter capacitance values : c1 and c2 */
+	REG_W(0x70, mdss_dsi_base + 0x0230);
+	REG_W(0x15, mdss_dsi_base + 0x0234);
+
+	REG_W(0x02, mdss_dsi_base + 0x0208); /* ChgPump */
+	REG_W(pll_divcfg1, mdss_dsi_base + 0x0204); /* postDiv1 */
+	REG_W(pll_divcfg2, mdss_dsi_base + 0x0224); /* postDiv2 */
+	REG_W(0x03, mdss_dsi_base + 0x0228); /* postDiv3 */
+
+	REG_W(0x2b, mdss_dsi_base + 0x0278); /* Cal CFG3 */
+	REG_W(0x06, mdss_dsi_base + 0x027c); /* Cal CFG4 */
+	REG_W(0x05, mdss_dsi_base + 0x0264); /* Cal CFG4 */
+
+	REG_W(0x0a, mdss_dsi_base + 0x023c); /* SDM CFG1 */
+	REG_W(0xab, mdss_dsi_base + 0x0240); /* SDM CFG2 */
+	REG_W(0x0a, mdss_dsi_base + 0x0244); /* SDM CFG3 */
+	REG_W(0x00, mdss_dsi_base + 0x0248); /* SDM CFG4 */
+
+	udelay(10);
+
+	REG_W(0x01, mdss_dsi_base + 0x0200); /* REFCLK CFG */
+	REG_W(0x00, mdss_dsi_base + 0x0214); /* PWRGEN CFG */
+	REG_W(0x01, mdss_dsi_base + 0x020c); /* VCOLPF CFG */
+	REG_W(0x02, mdss_dsi_base + 0x0210); /* VREG CFG */
+	REG_W(0x00, mdss_dsi_base + 0x0238); /* SDM CFG0 */
+
+	REG_W(0x5f, mdss_dsi_base + 0x028c); /* CAL CFG8 */
+	REG_W(0xa8, mdss_dsi_base + 0x0294); /* CAL CFG10 */
+	REG_W(0x01, mdss_dsi_base + 0x0298); /* CAL CFG11 */
+	REG_W(0x0a, mdss_dsi_base + 0x026c); /* CAL CFG0 */
+	REG_W(0x30, mdss_dsi_base + 0x0284); /* CAL CFG6 */
+	REG_W(0x00, mdss_dsi_base + 0x0288); /* CAL CFG7 */
+	REG_W(0x00, mdss_dsi_base + 0x0290); /* CAL CFG9 */
+	REG_W(0x20, mdss_dsi_base + 0x029c); /* EFUSE CFG */
+
+	pll_byte_clk_rate = 53000000;
+	pll_pclk_rate = 105000000;
+
+	clk_disable(mdss_dsi_ahb_clk);
+	pll_initialized = 1;
+
+	return 0;
+}
+
+static int mdss_dsi_pll_enable(struct clk *c)
+{
+	u32 status;
+	u32 max_reads, timeout_us;
+	static int pll_enabled;
+
+	if (pll_enabled)
+		return 0;
+
+	if (!mdss_dsi_ahb_clk) {
+		pr_err("%s: mdss_dsi_ahb_clk not initialized\n",
+				__func__);
+		return -EINVAL;
+	}
+
+	clk_enable(mdss_dsi_ahb_clk);
+	/* PLL power up */
+	REG_W(0x01, mdss_dsi_base + 0x0220); /* GLB CFG */
+	REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
+	udelay(20);
+	REG_W(0x07, mdss_dsi_base + 0x0220); /* GLB CFG */
+	udelay(20);
+	REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
+
+	/* poll for PLL ready status */
+	max_reads = 20;
+	timeout_us = 100;
+	if (readl_poll_timeout_noirq((mdss_dsi_base + 0x02c0),
+			   status,
+			   ((status & 0x01) == 1),
+				     max_reads, timeout_us)) {
+		pr_err("%s: DSI PLL status=%x failed to Lock\n",
+		       __func__, status);
+		clk_disable(mdss_dsi_ahb_clk);
+		return -EINVAL;
+	}
+	clk_disable(mdss_dsi_ahb_clk);
+	pll_enabled = 1;
+
+	return 0;
+}
+
+static void mdss_dsi_pll_disable(struct clk *c)
+{
+	if (!mdss_dsi_ahb_clk)
+		pr_err("%s: mdss_dsi_ahb_clk not initialized\n",
+				__func__);
+
+	clk_enable(mdss_dsi_ahb_clk);
+	writel_relaxed(0x00, mdss_dsi_base + 0x0220); /* GLB CFG */
+	clk_disable(mdss_dsi_ahb_clk);
+}
+
+void hdmi_pll_disable(void)
+{
+	REG_W(0x0, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
+	udelay(5);
+	REG_W(0x0, hdmi_phy_base + HDMI_PHY_GLB_CFG);
+
+	hdmi_pll_on = 0;
+} /* hdmi_pll_disable */
+
+int hdmi_pll_enable(void)
+{
+	u32 status;
+	u32 max_reads, timeout_us;
+
+	/* Global Enable */
+	REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
+	/* Power up power gen */
+	REG_W(0x00, hdmi_phy_base + HDMI_PHY_PD_CTRL0);
+	udelay(350);
+
+	/* PLL Power-Up */
+	REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
+	udelay(5);
+	/* Power up PLL LDO */
+	REG_W(0x03, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
+	udelay(350);
+
+	/* PLL Power-Up */
+	REG_W(0x0F, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
+	udelay(350);
+
+	/* poll for PLL ready status */
+	max_reads = 20;
+	timeout_us = 100;
+	if (readl_poll_timeout_noirq((hdmi_phy_pll_base + HDMI_UNI_PLL_STATUS),
+		status, ((status & BIT(0)) == 1), max_reads, timeout_us)) {
+		pr_err("%s: hdmi phy pll status=%x failed to Lock\n",
+		       __func__, status);
+		hdmi_pll_disable();
+		return -EINVAL;
+	}
+	pr_debug("%s: hdmi phy pll is locked\n", __func__);
+
+	udelay(350);
+	/* poll for PHY ready status */
+	max_reads = 20;
+	timeout_us = 100;
+	if (readl_poll_timeout_noirq((hdmi_phy_base + HDMI_PHY_STATUS),
+		status, ((status & BIT(0)) == 1), max_reads, timeout_us)) {
+		pr_err("%s: hdmi phy status=%x failed to Lock\n",
+		       __func__, status);
+		hdmi_pll_disable();
+		return -EINVAL;
+	}
+	pr_debug("%s: hdmi phy is locked\n", __func__);
+
+	hdmi_pll_on = 1;
+
+	return 0;
+} /* hdmi_pll_enable */
+
+int hdmi_pll_set_rate(unsigned long rate)
+{
+	unsigned int set_power_dwn = 0;
+
+	if (hdmi_pll_on) {
+		hdmi_pll_disable();
+		set_power_dwn = 1;
+	}
+
+	pr_debug("%s: rate=%ld\n", __func__, rate);
+	switch (rate) {
+	case 0:
+		/* This case is needed for suspend/resume. */
+	break;
+
+	case 25200000:
+		/* 640x480p60 */
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CF);
+		REG_W(0x20, hdmi_phy_pll_base + HDMI_UNI_PLL_VCOLPF_CFG);
+		REG_W(0x36, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG0);
+		REG_W(0x4C, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG1);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG2);
+		REG_W(0x20, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG3);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG4);
+		REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
+		REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
+		REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
+		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
+		REG_W(0x60, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG8);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG9);
+		REG_W(0xFC, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG10);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG11);
+	break;
+
+	case 27030000:
+		/* 480p60/480i60 case */
+		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CF);
+		REG_W(0x18, hdmi_phy_pll_base + HDMI_UNI_PLL_VCOLPF_CFG);
+		REG_W(0x36, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG0);
+		REG_W(0x14, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG1);
+		REG_W(0x63, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG2);
+		REG_W(0x1D, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG3);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG4);
+		REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
+		REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
+		REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
+		REG_W(0x03, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
+		REG_W(0x60, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG8);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG9);
+		REG_W(0x2A, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG10);
+		REG_W(0x03, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG11);
+	break;
+
+	case 74250000:
+		/*
+		 * 720p60/720p50/1080i60/1080i50
+		 * 1080p24/1080p30/1080p25 case
+		 */
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CF);
+		REG_W(0x20, hdmi_phy_pll_base + HDMI_UNI_PLL_VCOLPF_CFG);
+		REG_W(0x36, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG0);
+		REG_W(0x52, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG1);
+		REG_W(0xFD, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG2);
+		REG_W(0x55, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG3);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG4);
+		REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
+		REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
+		REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
+		REG_W(0x60, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG8);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG9);
+		REG_W(0x73, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG10);
+		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG11);
+	break;
+
+	case 148500000:
+		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CF);
+		REG_W(0x18, hdmi_phy_pll_base + HDMI_UNI_PLL_VCOLPF_CFG);
+		REG_W(0x36, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG0);
+		REG_W(0x52, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG1);
+		REG_W(0xFD, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG2);
+		REG_W(0x55, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG3);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG4);
+		REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
+		REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
+		REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
+		REG_W(0x60, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG8);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG9);
+		REG_W(0xE6, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG10);
+		REG_W(0x02, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG11);
+	break;
+
+	case 297000000:
+		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CF);
+		REG_W(0x18, hdmi_phy_pll_base + HDMI_UNI_PLL_VCOLPF_CFG);
+		REG_W(0x36, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG0);
+		REG_W(0x65, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG1);
+		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG2);
+		REG_W(0xAC, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG3);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG4);
+		REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
+		REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
+		REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
+		REG_W(0x60, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG8);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG9);
+		REG_W(0xCD, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG10);
+		REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG11);
+	break;
+
+	case 27000000:
+		/* 576p50/576i50 case */
+	default:
+		pr_err("%s: not supported rate=%ld\n", __func__, rate);
+	}
+
+	/* Make sure writes complete before disabling iface clock */
+	mb();
+
+	if (set_power_dwn)
+		hdmi_pll_enable();
+
+	return 0;
+} /* hdmi_pll_set_rate */
+
+struct clk_ops clk_ops_dsi_pixel_pll = {
+	.enable = mdss_dsi_pll_enable,
+	.disable = mdss_dsi_pll_disable,
+	.set_rate = mdss_dsi_pll_pixel_set_rate,
+	.round_rate = mdss_dsi_pll_pixel_round_rate,
+};
+
+struct clk_ops clk_ops_dsi_byte_pll = {
+	.enable = mdss_dsi_pll_enable,
+	.disable = mdss_dsi_pll_disable,
+	.set_rate = mdss_dsi_pll_byte_set_rate,
+	.round_rate = mdss_dsi_pll_byte_round_rate,
+};
diff --git a/arch/arm/mach-msm/clock-mdss-8974.h b/arch/arm/mach-msm/clock-mdss-8974.h
new file mode 100644
index 0000000..509a220
--- /dev/null
+++ b/arch/arm/mach-msm/clock-mdss-8974.h
@@ -0,0 +1,24 @@
+/* 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_CLOCK_MDSS_8974
+#define __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8974
+
+extern struct clk_ops clk_ops_dsi_byte_pll;
+extern struct clk_ops clk_ops_dsi_pixel_pll;
+
+void mdss_clk_ctrl_init(void);
+int hdmi_pll_enable(void);
+void hdmi_pll_disable(void);
+int hdmi_pll_set_rate(unsigned long rate);
+
+#endif
diff --git a/arch/arm/mach-msm/clock-rpm.c b/arch/arm/mach-msm/clock-rpm.c
index 207dbef..149a0511 100644
--- a/arch/arm/mach-msm/clock-rpm.c
+++ b/arch/arm/mach-msm/clock-rpm.c
@@ -54,6 +54,24 @@
 	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;
+		if (!r->active_only)
+			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 +89,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 +106,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 +283,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 +291,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-rpm.h b/arch/arm/mach-msm/clock-rpm.h
index e203028..7952a33 100644
--- a/arch/arm/mach-msm/clock-rpm.h
+++ b/arch/arm/mach-msm/clock-rpm.h
@@ -110,7 +110,6 @@
 			.dbg_name = #name, \
 			.rate = (r), \
 			CLK_INIT(name.c), \
-			.warned = true, \
 		}, \
 	}; \
 	static struct rpm_clk active = { \
@@ -129,7 +128,6 @@
 			.dbg_name = #active, \
 			.rate = (r), \
 			CLK_INIT(active.c), \
-			.warned = true, \
 		}, \
 	};
 
@@ -148,7 +146,6 @@
 			.ops = &clk_ops_rpm, \
 			.dbg_name = #name, \
 			CLK_INIT(name.c), \
-			.warned = true, \
 		}, \
 	}; \
 	static struct rpm_clk active = { \
@@ -164,7 +161,6 @@
 			.ops = &clk_ops_rpm, \
 			.dbg_name = #active, \
 			CLK_INIT(active.c), \
-			.warned = true, \
 		}, \
 	};
 
diff --git a/arch/arm/mach-msm/clock-voter.c b/arch/arm/mach-msm/clock-voter.c
index 4cd9b1c..3e1cbb9 100644
--- a/arch/arm/mach-msm/clock-voter.c
+++ b/arch/arm/mach-msm/clock-voter.c
@@ -12,13 +12,13 @@
  */
 
 #include <linux/err.h>
-#include <linux/spinlock.h>
+#include <linux/mutex.h>
 #include <linux/clk.h>
 
 #include "clock.h"
 #include "clock-voter.h"
 
-static DEFINE_SPINLOCK(voter_clk_lock);
+static DEFINE_MUTEX(voter_clk_lock);
 
 /* Aggregate the rate of clocks that are currently on. */
 static unsigned long voter_clk_aggregate_rate(const struct clk *parent)
@@ -37,12 +37,11 @@
 static int voter_clk_set_rate(struct clk *clk, unsigned long rate)
 {
 	int ret = 0;
-	unsigned long flags;
 	struct clk *clkp;
 	struct clk_voter *clkh, *v = to_clk_voter(clk);
 	unsigned long cur_rate, new_rate, other_rate = 0;
 
-	spin_lock_irqsave(&voter_clk_lock, flags);
+	mutex_lock(&voter_clk_lock);
 
 	if (v->enabled) {
 		struct clk *parent = v->parent;
@@ -68,20 +67,19 @@
 	}
 	clk->rate = rate;
 unlock:
-	spin_unlock_irqrestore(&voter_clk_lock, flags);
+	mutex_unlock(&voter_clk_lock);
 
 	return ret;
 }
 
-static int voter_clk_enable(struct clk *clk)
+static int voter_clk_prepare(struct clk *clk)
 {
 	int ret = 0;
-	unsigned long flags;
 	unsigned long cur_rate;
 	struct clk *parent;
 	struct clk_voter *v = to_clk_voter(clk);
 
-	spin_lock_irqsave(&voter_clk_lock, flags);
+	mutex_lock(&voter_clk_lock);
 	parent = v->parent;
 
 	/*
@@ -96,18 +94,18 @@
 	}
 	v->enabled = true;
 out:
-	spin_unlock_irqrestore(&voter_clk_lock, flags);
+	mutex_unlock(&voter_clk_lock);
 
 	return ret;
 }
 
-static void voter_clk_disable(struct clk *clk)
+static void voter_clk_unprepare(struct clk *clk)
 {
-	unsigned long flags, cur_rate, new_rate;
+	unsigned long cur_rate, new_rate;
 	struct clk *parent;
 	struct clk_voter *v = to_clk_voter(clk);
 
-	spin_lock_irqsave(&voter_clk_lock, flags);
+	mutex_lock(&voter_clk_lock);
 	parent = v->parent;
 
 	/*
@@ -121,7 +119,7 @@
 	if (new_rate < cur_rate)
 		clk_set_rate(parent, new_rate);
 
-	spin_unlock_irqrestore(&voter_clk_lock, flags);
+	mutex_unlock(&voter_clk_lock);
 }
 
 static int voter_clk_is_enabled(struct clk *clk)
@@ -157,8 +155,8 @@
 }
 
 struct clk_ops clk_ops_voter = {
-	.enable = voter_clk_enable,
-	.disable = voter_clk_disable,
+	.prepare = voter_clk_prepare,
+	.unprepare = voter_clk_unprepare,
 	.set_rate = voter_clk_set_rate,
 	.is_enabled = voter_clk_is_enabled,
 	.round_rate = voter_clk_round_rate,
diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c
index da8c3a9..27f2405 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;
 
@@ -156,6 +156,9 @@
 		if (ret)
 			goto err_prepare_depends;
 
+		ret = vote_rate_vdd(clk, clk->rate);
+		if (ret)
+			goto err_vote_vdd;
 		if (clk->ops->prepare)
 			ret = clk->ops->prepare(clk);
 		if (ret)
@@ -166,6 +169,8 @@
 	mutex_unlock(&clk->prepare_lock);
 	return ret;
 err_prepare_clock:
+	unvote_rate_vdd(clk, clk->rate);
+err_vote_vdd:
 	clk_unprepare(clk->depends);
 err_prepare_depends:
 	clk_unprepare(parent);
@@ -181,6 +186,7 @@
 	int ret = 0;
 	unsigned long flags;
 	struct clk *parent;
+	const char *name = clk ? clk->dbg_name : NULL;
 
 	if (!clk)
 		return 0;
@@ -188,10 +194,8 @@
 		return -EINVAL;
 
 	spin_lock_irqsave(&clk->lock, flags);
-	if (WARN(!clk->warned && !clk->prepare_count,
-				"%s: Don't call enable on unprepared clocks\n",
-				clk->dbg_name))
-		clk->warned = true;
+	WARN(!clk->prepare_count,
+			"%s: Don't call enable on unprepared clocks\n", name);
 	if (clk->count == 0) {
 		parent = clk_get_parent(clk);
 
@@ -202,10 +206,7 @@
 		if (ret)
 			goto err_enable_depends;
 
-		ret = vote_rate_vdd(clk, clk->rate);
-		if (ret)
-			goto err_vote_vdd;
-		trace_clock_enable(clk->dbg_name, 1, smp_processor_id());
+		trace_clock_enable(name, 1, smp_processor_id());
 		if (clk->ops->enable)
 			ret = clk->ops->enable(clk);
 		if (ret)
@@ -217,8 +218,6 @@
 	return 0;
 
 err_enable_clock:
-	unvote_rate_vdd(clk, clk->rate);
-err_vote_vdd:
 	clk_disable(clk->depends);
 err_enable_depends:
 	clk_disable(parent);
@@ -230,26 +229,24 @@
 
 void clk_disable(struct clk *clk)
 {
+	const char *name = clk ? clk->dbg_name : NULL;
 	unsigned long flags;
 
 	if (IS_ERR_OR_NULL(clk))
 		return;
 
 	spin_lock_irqsave(&clk->lock, flags);
-	if (WARN(!clk->warned && !clk->prepare_count,
-				"%s: Never called prepare or calling disable "
-				"after unprepare\n",
-				clk->dbg_name))
-		clk->warned = true;
-	if (WARN(clk->count == 0, "%s is unbalanced", clk->dbg_name))
+	WARN(!clk->prepare_count,
+			"%s: Never called prepare or calling disable after unprepare\n",
+			name);
+	if (WARN(clk->count == 0, "%s is unbalanced", name))
 		goto out;
 	if (clk->count == 1) {
 		struct clk *parent = clk_get_parent(clk);
 
-		trace_clock_disable(clk->dbg_name, 0, smp_processor_id());
+		trace_clock_disable(name, 0, smp_processor_id());
 		if (clk->ops->disable)
 			clk->ops->disable(clk);
-		unvote_rate_vdd(clk, clk->rate);
 		clk_disable(clk->depends);
 		clk_disable(parent);
 	}
@@ -261,26 +258,24 @@
 
 void clk_unprepare(struct clk *clk)
 {
+	const char *name = clk ? clk->dbg_name : NULL;
+
 	if (IS_ERR_OR_NULL(clk))
 		return;
 
 	mutex_lock(&clk->prepare_lock);
-	if (!clk->prepare_count) {
-		if (WARN(!clk->warned, "%s is unbalanced (prepare)",
-				clk->dbg_name))
-			clk->warned = true;
+	if (WARN(!clk->prepare_count, "%s is unbalanced (prepare)", name))
 		goto out;
-	}
 	if (clk->prepare_count == 1) {
 		struct clk *parent = clk_get_parent(clk);
 
-		if (WARN(!clk->warned && clk->count,
+		WARN(clk->count,
 			"%s: Don't call unprepare when the clock is enabled\n",
-				clk->dbg_name))
-			clk->warned = true;
+			name);
 
 		if (clk->ops->unprepare)
 			clk->ops->unprepare(clk);
+		unvote_rate_vdd(clk, clk->rate);
 		clk_unprepare(clk->depends);
 		clk_unprepare(parent);
 	}
@@ -316,8 +311,9 @@
 
 int clk_set_rate(struct clk *clk, unsigned long rate)
 {
-	unsigned long start_rate, flags;
+	unsigned long start_rate;
 	int rc = 0;
+	const char *name = clk ? clk->dbg_name : NULL;
 
 	if (IS_ERR_OR_NULL(clk))
 		return -EINVAL;
@@ -325,14 +321,14 @@
 	if (!clk->ops->set_rate)
 		return -ENOSYS;
 
-	spin_lock_irqsave(&clk->lock, flags);
+	mutex_lock(&clk->prepare_lock);
 
 	/* Return early if the rate isn't going to change */
 	if (clk->rate == rate)
 		goto out;
 
-	trace_clock_set_rate(clk->dbg_name, rate, smp_processor_id());
-	if (clk->count) {
+	trace_clock_set_rate(name, rate, raw_smp_processor_id());
+	if (clk->prepare_count) {
 		start_rate = clk->rate;
 		/* Enforce vdd requirements for target frequency. */
 		rc = vote_rate_vdd(clk, rate);
@@ -350,14 +346,13 @@
 	if (!rc)
 		clk->rate = rate;
 out:
-	spin_unlock_irqrestore(&clk->lock, flags);
+	mutex_unlock(&clk->prepare_lock);
 	return rc;
 
 err_set_rate:
 	unvote_rate_vdd(clk, rate);
 err_vote_vdd:
-	spin_unlock_irqrestore(&clk->lock, flags);
-	return rc;
+	goto out;
 }
 EXPORT_SYMBOL(clk_set_rate);
 
diff --git a/arch/arm/mach-msm/clock.h b/arch/arm/mach-msm/clock.h
index ff0e973..45d2f71 100644
--- a/arch/arm/mach-msm/clock.h
+++ b/arch/arm/mach-msm/clock.h
@@ -114,7 +114,6 @@
  * @depends: non-direct parent of clock to enable when this clock is enabled
  * @vdd_class: voltage scaling requirement class
  * @fmax: maximum frequency in Hz supported at each voltage level
- * @warned: true if the clock has warned of incorrect usage, false otherwise
  */
 struct clk {
 	uint32_t flags;
@@ -128,7 +127,6 @@
 	struct list_head children;
 	struct list_head siblings;
 
-	bool warned;
 	unsigned count;
 	spinlock_t lock;
 	unsigned prepare_count;
@@ -169,12 +167,14 @@
 extern struct clock_init_data qds8x50_clock_init_data;
 extern struct clock_init_data msm8625_dummy_clock_init_data;
 extern struct clock_init_data msm8930_clock_init_data;
+extern struct clock_init_data msm8930_pm8917_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/cpufreq.c b/arch/arm/mach-msm/cpufreq.c
index 0fa1e2d..05bd56ef 100644
--- a/arch/arm/mach-msm/cpufreq.c
+++ b/arch/arm/mach-msm/cpufreq.c
@@ -92,6 +92,34 @@
 }
 
 #ifdef CONFIG_SMP
+static int __cpuinit msm_cpufreq_cpu_callback(struct notifier_block *nfb,
+					unsigned long action, void *hcpu)
+{
+	unsigned int cpu = (unsigned long)hcpu;
+
+	switch (action) {
+	case CPU_ONLINE:
+	case CPU_ONLINE_FROZEN:
+		per_cpu(cpufreq_suspend, cpu).device_suspended = 0;
+		break;
+	case CPU_DOWN_PREPARE:
+	case CPU_DOWN_PREPARE_FROZEN:
+		mutex_lock(&per_cpu(cpufreq_suspend, cpu).suspend_mutex);
+		per_cpu(cpufreq_suspend, cpu).device_suspended = 1;
+		mutex_unlock(&per_cpu(cpufreq_suspend, cpu).suspend_mutex);
+		break;
+	case CPU_DOWN_FAILED:
+	case CPU_DOWN_FAILED_FROZEN:
+		per_cpu(cpufreq_suspend, cpu).device_suspended = 0;
+		break;
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block __refdata msm_cpufreq_cpu_notifier = {
+	.notifier_call = msm_cpufreq_cpu_callback,
+};
+
 static void set_cpu_work(struct work_struct *work)
 {
 	struct cpufreq_work_struct *cpu_work =
@@ -385,6 +413,7 @@
 
 #ifdef CONFIG_SMP
 	msm_cpufreq_wq = create_workqueue("msm-cpufreq");
+	register_hotcpu_notifier(&msm_cpufreq_cpu_notifier);
 #endif
 
 	register_pm_notifier(&msm_cpufreq_pm_notifier);
diff --git a/arch/arm/mach-msm/cpuidle.c b/arch/arm/mach-msm/cpuidle.c
index e4ec4d4..dd2dc1d 100644
--- a/arch/arm/mach-msm/cpuidle.c
+++ b/arch/arm/mach-msm/cpuidle.c
@@ -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
@@ -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,23 +75,13 @@
 	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
 
 	pm_mode = msm_pm_idle_prepare(dev, drv, index);
-	msm_pm_idle_enter(pm_mode);
+	dev->last_residency = msm_pm_idle_enter(pm_mode);
 	for (i = 0; i < dev->state_count; i++) {
 		st_usage = &dev->states_usage[i];
 		if ((enum msm_pm_sleep_mode) cpuidle_get_statedata(st_usage)
@@ -128,10 +95,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 +182,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 90e0089..4ad5580 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -29,13 +29,14 @@
 #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>
 #include <mach/msm_smd.h>
 #include <mach/msm_dcvs.h>
 #include <mach/msm_rtb.h>
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
 #include "clock.h"
 #include "devices.h"
 #include "footswitch.h"
@@ -57,6 +58,7 @@
 /* GSBI UART devices */
 #define MSM_UART1DM_PHYS	(MSM_GSBI1_PHYS + 0x10000)
 #define MSM_UART3DM_PHYS	(MSM_GSBI3_PHYS + 0x40000)
+#define MSM_UART6DM_PHYS	(MSM_GSBI6_PHYS + 0x40000)
 #define MSM_UART7DM_PHYS	(MSM_GSBI7_PHYS + 0x40000)
 
 /* GSBI QUP devices */
@@ -102,6 +104,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 = {
@@ -110,6 +121,8 @@
 	.dev = {
 		.platform_data = &msm_watchdog_pdata,
 	},
+	.num_resources	= ARRAY_SIZE(msm_watchdog_resources),
+	.resource	= msm_watchdog_resources,
 };
 
 static struct resource msm_dmov_resource[] = {
@@ -381,6 +394,50 @@
 	.resource	= resources_qup_i2c_gsbi5,
 };
 
+/* GSBI 6 used into UARTDM Mode */
+static struct resource msm_uart_dm6_resources[] = {
+	{
+		.start  = MSM_UART6DM_PHYS,
+		.end    = MSM_UART6DM_PHYS + PAGE_SIZE - 1,
+		.name   = "uartdm_resource",
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.start  = GSBI6_UARTDM_IRQ,
+		.end    = GSBI6_UARTDM_IRQ,
+		.flags  = IORESOURCE_IRQ,
+	},
+	{
+		.start  = MSM_GSBI6_PHYS,
+		.end    = MSM_GSBI6_PHYS + 4 - 1,
+		.name   = "gsbi_resource",
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.start  = DMOV_MPQ8064_HSUART_GSBI6_TX_CHAN,
+		.end    = DMOV_MPQ8064_HSUART_GSBI6_RX_CHAN,
+		.name   = "uartdm_channels",
+		.flags  = IORESOURCE_DMA,
+	},
+	{
+		.start  = DMOV_MPQ8064_HSUART_GSBI6_TX_CRCI,
+		.end    = DMOV_MPQ8064_HSUART_GSBI6_RX_CRCI,
+		.name   = "uartdm_crci",
+		.flags  = IORESOURCE_DMA,
+	},
+};
+static u64 msm_uart_dm6_dma_mask = DMA_BIT_MASK(32);
+struct platform_device mpq8064_device_uartdm_gsbi6 = {
+	.name   = "msm_serial_hs",
+	.id     = 0,
+	.num_resources  = ARRAY_SIZE(msm_uart_dm6_resources),
+	.resource       = msm_uart_dm6_resources,
+	.dev    = {
+		.dma_mask		= &msm_uart_dm6_dma_mask,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+	},
+};
+
 static struct resource resources_uart_gsbi7[] = {
 	{
 		.start	= GSBI7_UARTDM_IRQ,
@@ -572,6 +629,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.
@@ -628,6 +746,29 @@
 	},
 };
 
+struct msm_mi2s_pdata apq_mi2s_data = {
+	.rx_sd_lines = MSM_MI2S_SD0,
+	.tx_sd_lines = MSM_MI2S_SD3,
+};
+
+struct platform_device apq_cpudai_mi2s = {
+	.name	= "msm-dai-q6-mi2s",
+	.id	= -1,
+	.dev = {
+		.platform_data = &apq_mi2s_data,
+	},
+};
+
+struct platform_device apq_cpudai_i2s_rx = {
+	.name	= "msm-dai-q6",
+	.id	= PRIMARY_I2S_RX,
+};
+
+struct platform_device apq_cpudai_i2s_tx = {
+	.name	= "msm-dai-q6",
+	.id	= PRIMARY_I2S_TX,
+};
+
 struct platform_device apq_cpu_fe = {
 	.name	= "msm-dai-fe",
 	.id	= -1,
@@ -663,6 +804,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,
@@ -2686,7 +2832,7 @@
 static struct coresight_platform_data coresight_funnel_pdata = {
 	.id		= 2,
 	.name		= "coresight-funnel",
-	.nr_inports	= 4,
+	.nr_inports	= 8,
 	.outports	= coresight_funnel_outports,
 	.child_ids	= coresight_funnel_child_ids,
 	.child_ports	= coresight_funnel_child_ports,
@@ -2718,7 +2864,7 @@
 static struct coresight_platform_data coresight_etm2_pdata = {
 	.id		= 6,
 	.name		= "coresight-etm2",
-	.nr_inports	= 1,
+	.nr_inports	= 0,
 	.outports	= coresight_etm2_outports,
 	.child_ids	= coresight_etm2_child_ids,
 	.child_ports	= coresight_etm2_child_ports,
@@ -2750,7 +2896,7 @@
 static struct coresight_platform_data coresight_etm3_pdata = {
 	.id		= 7,
 	.name		= "coresight-etm3",
-	.nr_inports	= 3,
+	.nr_inports	= 0,
 	.outports	= coresight_etm3_outports,
 	.child_ids	= coresight_etm3_child_ids,
 	.child_ports	= coresight_etm3_child_ports,
@@ -2770,26 +2916,6 @@
 struct msm_iommu_domain_name apq8064_iommu_ctx_names[] = {
 	/* Camera */
 	{
-		.name = "vpe_src",
-		.domain = CAMERA_DOMAIN,
-	},
-	/* Camera */
-	{
-		.name = "vpe_dst",
-		.domain = CAMERA_DOMAIN,
-	},
-	/* Camera */
-	{
-		.name = "vfe_imgwr",
-		.domain = CAMERA_DOMAIN,
-	},
-	/* Camera */
-	{
-		.name = "vfe_misc",
-		.domain = CAMERA_DOMAIN,
-	},
-	/* Camera */
-	{
 		.name = "ijpeg_src",
 		.domain = CAMERA_DOMAIN,
 	},
diff --git a/arch/arm/mach-msm/devices-8930.c b/arch/arm/mach-msm/devices-8930.c
index eac2140..dfef866 100644
--- a/arch/arm/mach-msm/devices-8930.c
+++ b/arch/arm/mach-msm/devices-8930.c
@@ -14,7 +14,7 @@
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
 #include <asm/io.h>
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
 #include <mach/msm_iomap.h>
 #include <mach/irqs-8930.h>
 #include <mach/rpm.h>
@@ -32,6 +32,7 @@
 #include "rpm_stats.h"
 #include "rpm_rbcpr_stats.h"
 #include "footswitch.h"
+#include "acpuclock-krait.h"
 
 #ifdef CONFIG_MSM_MPM
 #include <mach/mpm.h>
@@ -228,13 +229,13 @@
 		MSM_RPM_STATUS_ID_MAP(8930, PM8038_CLK2_1),
 		MSM_RPM_STATUS_ID_MAP(8930, PM8038_LVS1),
 		MSM_RPM_STATUS_ID_MAP(8930, PM8038_LVS2),
-		MSM_RPM_STATUS_ID_MAP(8930, NCP_0),
-		MSM_RPM_STATUS_ID_MAP(8930, NCP_1),
-		MSM_RPM_STATUS_ID_MAP(8930, CXO_BUFFERS),
-		MSM_RPM_STATUS_ID_MAP(8930, USB_OTG_SWITCH),
-		MSM_RPM_STATUS_ID_MAP(8930, HDMI_SWITCH),
-		MSM_RPM_STATUS_ID_MAP(8930, QDSS_CLK),
-		MSM_RPM_STATUS_ID_MAP(8930, VOLTAGE_CORNER),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_NCP_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_NCP_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_CXO_BUFFERS),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_USB_OTG_SWITCH),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_HDMI_SWITCH),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_QDSS_CLK),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_VOLTAGE_CORNER),
 	},
 	.target_ctrl_id = {
 		MSM_RPM_CTRL_MAP(8930, VERSION_MAJOR),
@@ -251,6 +252,259 @@
 	.ver = {3, 0, 0},
 };
 
+struct msm_rpm_platform_data msm8930_rpm_data_pm8917 __initdata = {
+	.reg_base_addrs = {
+		[MSM_RPM_PAGE_STATUS] = MSM_RPM_BASE,
+		[MSM_RPM_PAGE_CTRL] = MSM_RPM_BASE + 0x400,
+		[MSM_RPM_PAGE_REQ] = MSM_RPM_BASE + 0x600,
+		[MSM_RPM_PAGE_ACK] = MSM_RPM_BASE + 0xa00,
+	},
+	.irq_ack = RPM_APCC_CPU0_GP_HIGH_IRQ,
+	.irq_err = RPM_APCC_CPU0_GP_LOW_IRQ,
+	.irq_wakeup = RPM_APCC_CPU0_WAKE_UP_IRQ,
+	.ipc_rpm_reg = MSM_APCS_GCC_BASE + 0x008,
+	.ipc_rpm_val = 4,
+	.target_id = {
+		MSM_RPM_MAP(8930, NOTIFICATION_CONFIGURED_0, NOTIFICATION, 4),
+		MSM_RPM_MAP(8930, NOTIFICATION_REGISTERED_0, NOTIFICATION, 4),
+		MSM_RPM_MAP(8930, INVALIDATE_0, INVALIDATE, 8),
+		MSM_RPM_MAP(8960, TRIGGER_TIMED_TO, TRIGGER_TIMED, 1),
+		MSM_RPM_MAP(8960, TRIGGER_TIMED_SCLK_COUNT, TRIGGER_TIMED, 1),
+		MSM_RPM_MAP(8930, RPM_CTL, RPM_CTL, 1),
+		MSM_RPM_MAP(8930, CXO_CLK, CXO_CLK, 1),
+		MSM_RPM_MAP(8930, PXO_CLK, PXO_CLK, 1),
+		MSM_RPM_MAP(8930, APPS_FABRIC_CLK, APPS_FABRIC_CLK, 1),
+		MSM_RPM_MAP(8930, SYSTEM_FABRIC_CLK, SYSTEM_FABRIC_CLK, 1),
+		MSM_RPM_MAP(8930, MM_FABRIC_CLK, MM_FABRIC_CLK, 1),
+		MSM_RPM_MAP(8930, DAYTONA_FABRIC_CLK, DAYTONA_FABRIC_CLK, 1),
+		MSM_RPM_MAP(8930, SFPB_CLK, SFPB_CLK, 1),
+		MSM_RPM_MAP(8930, CFPB_CLK, CFPB_CLK, 1),
+		MSM_RPM_MAP(8930, MMFPB_CLK, MMFPB_CLK, 1),
+		MSM_RPM_MAP(8930, EBI1_CLK, EBI1_CLK, 1),
+		MSM_RPM_MAP(8930, APPS_FABRIC_CFG_HALT_0,
+				APPS_FABRIC_CFG_HALT, 2),
+		MSM_RPM_MAP(8930, APPS_FABRIC_CFG_CLKMOD_0,
+				APPS_FABRIC_CFG_CLKMOD, 3),
+		MSM_RPM_MAP(8930, APPS_FABRIC_CFG_IOCTL,
+				APPS_FABRIC_CFG_IOCTL, 1),
+		MSM_RPM_MAP(8930, APPS_FABRIC_ARB_0, APPS_FABRIC_ARB, 6),
+		MSM_RPM_MAP(8930, SYS_FABRIC_CFG_HALT_0,
+				SYS_FABRIC_CFG_HALT, 2),
+		MSM_RPM_MAP(8930, SYS_FABRIC_CFG_CLKMOD_0,
+				SYS_FABRIC_CFG_CLKMOD, 3),
+		MSM_RPM_MAP(8930, SYS_FABRIC_CFG_IOCTL,
+				SYS_FABRIC_CFG_IOCTL, 1),
+		MSM_RPM_MAP(8930, SYSTEM_FABRIC_ARB_0,
+				SYSTEM_FABRIC_ARB, 20),
+		MSM_RPM_MAP(8930, MMSS_FABRIC_CFG_HALT_0,
+				MMSS_FABRIC_CFG_HALT, 2),
+		MSM_RPM_MAP(8930, MMSS_FABRIC_CFG_CLKMOD_0,
+				MMSS_FABRIC_CFG_CLKMOD, 3),
+		MSM_RPM_MAP(8930, MMSS_FABRIC_CFG_IOCTL,
+				MMSS_FABRIC_CFG_IOCTL, 1),
+		MSM_RPM_MAP(8930, MM_FABRIC_ARB_0, MM_FABRIC_ARB, 11),
+		MSM_RPM_MAP(8930, PM8917_S1_0, PM8917_S1, 2),
+		MSM_RPM_MAP(8930, PM8917_S2_0, PM8917_S2, 2),
+		MSM_RPM_MAP(8930, PM8917_S3_0, PM8917_S3, 2),
+		MSM_RPM_MAP(8930, PM8917_S4_0, PM8917_S4, 2),
+		MSM_RPM_MAP(8930, PM8917_S5_0, PM8917_S5, 2),
+		MSM_RPM_MAP(8930, PM8917_S6_0, PM8917_S6, 2),
+		MSM_RPM_MAP(8930, PM8917_S7_0, PM8917_S7, 2),
+		MSM_RPM_MAP(8930, PM8917_S8_0, PM8917_S8, 2),
+		MSM_RPM_MAP(8930, PM8917_L1_0, PM8917_L1, 2),
+		MSM_RPM_MAP(8930, PM8917_L2_0, PM8917_L2, 2),
+		MSM_RPM_MAP(8930, PM8917_L3_0, PM8917_L3, 2),
+		MSM_RPM_MAP(8930, PM8917_L4_0, PM8917_L4, 2),
+		MSM_RPM_MAP(8930, PM8917_L5_0, PM8917_L5, 2),
+		MSM_RPM_MAP(8930, PM8917_L6_0, PM8917_L6, 2),
+		MSM_RPM_MAP(8930, PM8917_L7_0, PM8917_L7, 2),
+		MSM_RPM_MAP(8930, PM8917_L8_0, PM8917_L8, 2),
+		MSM_RPM_MAP(8930, PM8917_L9_0, PM8917_L9, 2),
+		MSM_RPM_MAP(8930, PM8917_L10_0, PM8917_L10, 2),
+		MSM_RPM_MAP(8930, PM8917_L11_0, PM8917_L11, 2),
+		MSM_RPM_MAP(8930, PM8917_L12_0, PM8917_L12, 2),
+		MSM_RPM_MAP(8930, PM8917_L14_0, PM8917_L14, 2),
+		MSM_RPM_MAP(8930, PM8917_L15_0, PM8917_L15, 2),
+		MSM_RPM_MAP(8930, PM8917_L16_0, PM8917_L16, 2),
+		MSM_RPM_MAP(8930, PM8917_L17_0, PM8917_L17, 2),
+		MSM_RPM_MAP(8930, PM8917_L18_0, PM8917_L18, 2),
+		MSM_RPM_MAP(8930, PM8917_L21_0, PM8917_L21, 2),
+		MSM_RPM_MAP(8930, PM8917_L22_0, PM8917_L22, 2),
+		MSM_RPM_MAP(8930, PM8917_L23_0, PM8917_L23, 2),
+		MSM_RPM_MAP(8930, PM8917_L24_0, PM8917_L24, 2),
+		MSM_RPM_MAP(8930, PM8917_L25_0, PM8917_L25, 2),
+		MSM_RPM_MAP(8930, PM8917_L26_0, PM8917_L26, 2),
+		MSM_RPM_MAP(8930, PM8917_L27_0, PM8917_L27, 2),
+		MSM_RPM_MAP(8930, PM8917_L28_0, PM8917_L28, 2),
+		MSM_RPM_MAP(8930, PM8917_L29_0, PM8917_L29, 2),
+		MSM_RPM_MAP(8930, PM8917_L30_0, PM8917_L30, 2),
+		MSM_RPM_MAP(8930, PM8917_L31_0, PM8917_L31, 2),
+		MSM_RPM_MAP(8930, PM8917_L32_0, PM8917_L32, 2),
+		MSM_RPM_MAP(8930, PM8917_L33_0, PM8917_L33, 2),
+		MSM_RPM_MAP(8930, PM8917_L34_0, PM8917_L34, 2),
+		MSM_RPM_MAP(8930, PM8917_L35_0, PM8917_L35, 2),
+		MSM_RPM_MAP(8930, PM8917_L36_0, PM8917_L36, 2),
+		MSM_RPM_MAP(8930, PM8917_CLK1_0, PM8917_CLK1, 2),
+		MSM_RPM_MAP(8930, PM8917_CLK2_0, PM8917_CLK2, 2),
+		MSM_RPM_MAP(8930, PM8917_LVS1, PM8917_LVS1, 1),
+		MSM_RPM_MAP(8930, PM8917_LVS3, PM8917_LVS3, 1),
+		MSM_RPM_MAP(8930, PM8917_LVS4, PM8917_LVS4, 1),
+		MSM_RPM_MAP(8930, PM8917_LVS5, PM8917_LVS5, 1),
+		MSM_RPM_MAP(8930, PM8917_LVS6, PM8917_LVS6, 1),
+		MSM_RPM_MAP(8930, PM8917_LVS7, PM8917_LVS7, 1),
+		MSM_RPM_MAP(8930, NCP_0, NCP, 2),
+		MSM_RPM_MAP(8930, CXO_BUFFERS, CXO_BUFFERS, 1),
+		MSM_RPM_MAP(8930, USB_OTG_SWITCH, USB_OTG_SWITCH, 1),
+		MSM_RPM_MAP(8930, HDMI_SWITCH, HDMI_SWITCH, 1),
+		MSM_RPM_MAP(8930, QDSS_CLK, QDSS_CLK, 1),
+		MSM_RPM_MAP(8930, VOLTAGE_CORNER, VOLTAGE_CORNER, 1),
+	},
+	.target_status = {
+		MSM_RPM_STATUS_ID_MAP(8930, VERSION_MAJOR),
+		MSM_RPM_STATUS_ID_MAP(8930, VERSION_MINOR),
+		MSM_RPM_STATUS_ID_MAP(8930, VERSION_BUILD),
+		MSM_RPM_STATUS_ID_MAP(8930, SUPPORTED_RESOURCES_0),
+		MSM_RPM_STATUS_ID_MAP(8930, SUPPORTED_RESOURCES_1),
+		MSM_RPM_STATUS_ID_MAP(8930, SUPPORTED_RESOURCES_2),
+		MSM_RPM_STATUS_ID_MAP(8930, RESERVED_SUPPORTED_RESOURCES_0),
+		MSM_RPM_STATUS_ID_MAP(8930, SEQUENCE),
+		MSM_RPM_STATUS_ID_MAP(8930, RPM_CTL),
+		MSM_RPM_STATUS_ID_MAP(8930, CXO_CLK),
+		MSM_RPM_STATUS_ID_MAP(8930, PXO_CLK),
+		MSM_RPM_STATUS_ID_MAP(8930, APPS_FABRIC_CLK),
+		MSM_RPM_STATUS_ID_MAP(8930, SYSTEM_FABRIC_CLK),
+		MSM_RPM_STATUS_ID_MAP(8930, MM_FABRIC_CLK),
+		MSM_RPM_STATUS_ID_MAP(8930, DAYTONA_FABRIC_CLK),
+		MSM_RPM_STATUS_ID_MAP(8930, SFPB_CLK),
+		MSM_RPM_STATUS_ID_MAP(8930, CFPB_CLK),
+		MSM_RPM_STATUS_ID_MAP(8930, MMFPB_CLK),
+		MSM_RPM_STATUS_ID_MAP(8930, EBI1_CLK),
+		MSM_RPM_STATUS_ID_MAP(8930, APPS_FABRIC_CFG_HALT),
+		MSM_RPM_STATUS_ID_MAP(8930, APPS_FABRIC_CFG_CLKMOD),
+		MSM_RPM_STATUS_ID_MAP(8930, APPS_FABRIC_CFG_IOCTL),
+		MSM_RPM_STATUS_ID_MAP(8930, APPS_FABRIC_ARB),
+		MSM_RPM_STATUS_ID_MAP(8930, SYS_FABRIC_CFG_HALT),
+		MSM_RPM_STATUS_ID_MAP(8930, SYS_FABRIC_CFG_CLKMOD),
+		MSM_RPM_STATUS_ID_MAP(8930, SYS_FABRIC_CFG_IOCTL),
+		MSM_RPM_STATUS_ID_MAP(8930, SYSTEM_FABRIC_ARB),
+		MSM_RPM_STATUS_ID_MAP(8930, MMSS_FABRIC_CFG_HALT),
+		MSM_RPM_STATUS_ID_MAP(8930, MMSS_FABRIC_CFG_CLKMOD),
+		MSM_RPM_STATUS_ID_MAP(8930, MMSS_FABRIC_CFG_IOCTL),
+		MSM_RPM_STATUS_ID_MAP(8930, MM_FABRIC_ARB),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_S1_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_S1_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_S2_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_S2_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_S3_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_S3_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_S4_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_S4_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_S5_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_S5_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_S6_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_S6_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_S7_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_S7_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_S8_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_S8_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L1_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L1_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L2_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L2_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L3_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L3_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L4_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L4_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L5_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L5_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L6_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L6_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L7_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L7_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L8_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L8_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L9_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L9_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L10_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L10_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L11_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L11_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L12_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L12_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L14_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L14_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L15_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L15_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L16_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L16_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L17_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L17_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L18_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L18_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L21_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L21_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L22_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L22_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L23_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L23_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L24_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L24_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L25_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L25_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L26_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L26_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L27_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L27_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L28_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L28_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L29_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L29_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L30_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L30_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L31_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L31_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L32_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L32_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L33_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L33_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L34_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L34_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L35_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L35_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L36_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_L36_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_CLK1_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_CLK1_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_CLK2_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_CLK2_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_LVS1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_LVS3),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_LVS4),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_LVS5),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_LVS6),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_LVS7),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_NCP_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_NCP_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_CXO_BUFFERS),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_USB_OTG_SWITCH),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_HDMI_SWITCH),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_QDSS_CLK),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8917_VOLTAGE_CORNER),
+	},
+	.target_ctrl_id = {
+		MSM_RPM_CTRL_MAP(8930, VERSION_MAJOR),
+		MSM_RPM_CTRL_MAP(8930, VERSION_MINOR),
+		MSM_RPM_CTRL_MAP(8930, VERSION_BUILD),
+		MSM_RPM_CTRL_MAP(8930, REQ_CTX_0),
+		MSM_RPM_CTRL_MAP(8930, REQ_SEL_0),
+		MSM_RPM_CTRL_MAP(8930, ACK_CTX_0),
+		MSM_RPM_CTRL_MAP(8930, ACK_SEL_0),
+	},
+	.sel_invalidate = MSM_RPM_8930_SEL_INVALIDATE,
+	.sel_notification = MSM_RPM_8930_SEL_NOTIFICATION,
+	.sel_last = MSM_RPM_8930_SEL_LAST,
+	.ver = {3, 0, 0},
+};
 struct platform_device msm8930_rpm_device = {
 	.name   = "msm_rpm",
 	.id     = -1,
@@ -386,9 +640,16 @@
 	.id		= -1,
 };
 
+static struct acpuclk_platform_data acpuclk_8930_pdata = {
+	.uses_pm8917 = false,
+};
+
 struct platform_device msm8930_device_acpuclk = {
 	.name		= "acpuclk-8930",
 	.id		= -1,
+	.dev = {
+		.platform_data = &acpuclk_8930_pdata,
+	},
 };
 
 struct platform_device msm8930aa_device_acpuclk = {
@@ -853,26 +1114,6 @@
 struct msm_iommu_domain_name msm8930_iommu_ctx_names[] = {
 	/* Camera */
 	{
-		.name = "vpe_src",
-		.domain = CAMERA_DOMAIN,
-	},
-	/* Camera */
-	{
-		.name = "vpe_dst",
-		.domain = CAMERA_DOMAIN,
-	},
-	/* Camera */
-	{
-		.name = "vfe_imgwr",
-		.domain = CAMERA_DOMAIN,
-	},
-	/* Camera */
-	{
-		.name = "vfe_misc",
-		.domain = CAMERA_DOMAIN,
-	},
-	/* Camera */
-	{
 		.name = "ijpeg_src",
 		.domain = CAMERA_DOMAIN,
 	},
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 680770e..d22690c 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -15,7 +15,7 @@
 #include <linux/list.h>
 #include <linux/platform_device.h>
 #include <linux/msm_rotator.h>
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
 #include <linux/gpio.h>
 #include <linux/coresight.h>
 #include <asm/clkdev.h>
@@ -50,6 +50,7 @@
 #include "scm-pas.h"
 #include <mach/msm_dcvs.h>
 #include <mach/iommu_domains.h>
+#include <mach/socinfo.h>
 
 #ifdef CONFIG_MSM_MPM
 #include <mach/mpm.h>
@@ -207,6 +208,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[] = {
 	{
@@ -712,7 +718,7 @@
 	},
 	{
 		ARRAY_SIZE(vidc_venc_1080p_turbo_vectors),
-		vidc_vdec_1080p_turbo_vectors,
+		vidc_venc_1080p_turbo_vectors,
 	},
 	{
 		ARRAY_SIZE(vidc_vdec_1080p_turbo_vectors),
@@ -725,6 +731,286 @@
 	ARRAY_SIZE(vidc_bus_client_config),
 	.name = "vidc",
 };
+
+static struct msm_bus_vectors vidc_pro_init_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VIDEO_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_VIDEO_DEC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+};
+static struct msm_bus_vectors vidc_pro_venc_vga_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VIDEO_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 54525952,
+		.ib  = 436207616,
+	},
+	{
+		.src = MSM_BUS_MASTER_VIDEO_DEC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 72351744,
+		.ib  = 289406976,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 500000,
+		.ib  = 1000000,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 500000,
+		.ib  = 1000000,
+	},
+};
+static struct msm_bus_vectors vidc_pro_vdec_vga_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VIDEO_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 40894464,
+		.ib  = 327155712,
+	},
+	{
+		.src = MSM_BUS_MASTER_VIDEO_DEC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 48234496,
+		.ib  = 192937984,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 500000,
+		.ib  = 2000000,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 500000,
+		.ib  = 2000000,
+	},
+};
+static struct msm_bus_vectors vidc_pro_venc_720p_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VIDEO_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 163577856,
+		.ib  = 1308622848,
+	},
+	{
+		.src = MSM_BUS_MASTER_VIDEO_DEC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 219152384,
+		.ib  = 876609536,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 1750000,
+		.ib  = 3500000,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 1750000,
+		.ib  = 3500000,
+	},
+};
+static struct msm_bus_vectors vidc_pro_vdec_720p_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VIDEO_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 121634816,
+		.ib  = 973078528,
+	},
+	{
+		.src = MSM_BUS_MASTER_VIDEO_DEC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 155189248,
+		.ib  = 620756992,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 1750000,
+		.ib  = 7000000,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 1750000,
+		.ib  = 7000000,
+	},
+};
+static struct msm_bus_vectors vidc_pro_venc_1080p_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VIDEO_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 372244480,
+		.ib  = 2560000000U,
+	},
+	{
+		.src = MSM_BUS_MASTER_VIDEO_DEC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 501219328,
+		.ib  = 2560000000U,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 2500000,
+		.ib  = 5000000,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 2500000,
+		.ib  = 5000000,
+	},
+};
+static struct msm_bus_vectors vidc_pro_vdec_1080p_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VIDEO_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 222298112,
+		.ib  = 2560000000U,
+	},
+	{
+		.src = MSM_BUS_MASTER_VIDEO_DEC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 330301440,
+		.ib  = 2560000000U,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 2500000,
+		.ib  = 700000000,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 2500000,
+		.ib  = 10000000,
+	},
+};
+static struct msm_bus_vectors vidc_pro_venc_1080p_turbo_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VIDEO_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 222298112,
+		.ib  = 3522000000U,
+	},
+	{
+		.src = MSM_BUS_MASTER_VIDEO_DEC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 330301440,
+		.ib  = 3522000000U,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 2500000,
+		.ib  = 700000000,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 2500000,
+		.ib  = 10000000,
+	},
+};
+static struct msm_bus_vectors vidc_pro_vdec_1080p_turbo_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VIDEO_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 222298112,
+		.ib  = 3522000000U,
+	},
+	{
+		.src = MSM_BUS_MASTER_VIDEO_DEC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 330301440,
+		.ib  = 3522000000U,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 2500000,
+		.ib  = 700000000,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 2500000,
+		.ib  = 10000000,
+	},
+};
+
+static struct msm_bus_paths vidc_pro_bus_client_config[] = {
+	{
+		ARRAY_SIZE(vidc_pro_init_vectors),
+		vidc_pro_init_vectors,
+	},
+	{
+		ARRAY_SIZE(vidc_pro_venc_vga_vectors),
+		vidc_pro_venc_vga_vectors,
+	},
+	{
+		ARRAY_SIZE(vidc_pro_vdec_vga_vectors),
+		vidc_pro_vdec_vga_vectors,
+	},
+	{
+		ARRAY_SIZE(vidc_pro_venc_720p_vectors),
+		vidc_pro_venc_720p_vectors,
+	},
+	{
+		ARRAY_SIZE(vidc_pro_vdec_720p_vectors),
+		vidc_pro_vdec_720p_vectors,
+	},
+	{
+		ARRAY_SIZE(vidc_pro_venc_1080p_vectors),
+		vidc_pro_venc_1080p_vectors,
+	},
+	{
+		ARRAY_SIZE(vidc_pro_vdec_1080p_vectors),
+		vidc_pro_vdec_1080p_vectors,
+	},
+	{
+		ARRAY_SIZE(vidc_pro_venc_1080p_turbo_vectors),
+		vidc_pro_venc_1080p_turbo_vectors,
+	},
+	{
+		ARRAY_SIZE(vidc_vdec_1080p_turbo_vectors),
+		vidc_pro_vdec_1080p_turbo_vectors,
+	},
+};
+
+static struct msm_bus_scale_pdata vidc_pro_bus_client_data = {
+	vidc_pro_bus_client_config,
+	ARRAY_SIZE(vidc_bus_client_config),
+	.name = "vidc",
+};
 #endif
 
 #ifdef CONFIG_HW_RANDOM_MSM
@@ -1331,6 +1617,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 +1634,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 +2235,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,
@@ -2012,20 +2314,20 @@
 	.mode_8k = {
 		.mode = AFE_PCM_CFG_MODE_PCM,
 		.sync = AFE_PCM_CFG_SYNC_INT,
-		.frame = AFE_PCM_CFG_FRM_256BPF,
+		.frame = AFE_PCM_CFG_FRM_32BPF,
 		.quant = AFE_PCM_CFG_QUANT_LINEAR_NOPAD,
 		.slot = 0,
 		.data = AFE_PCM_CFG_CDATAOE_MASTER,
-		.pcm_clk_rate = 2048000,
+		.pcm_clk_rate = 256000,
 	},
 	.mode_16k = {
 		.mode = AFE_PCM_CFG_MODE_PCM,
 		.sync = AFE_PCM_CFG_SYNC_INT,
-		.frame = AFE_PCM_CFG_FRM_256BPF,
+		.frame = AFE_PCM_CFG_FRM_32BPF,
 		.quant = AFE_PCM_CFG_QUANT_LINEAR_NOPAD,
 		.slot = 0,
 		.data = AFE_PCM_CFG_CDATAOE_MASTER,
-		.pcm_clk_rate = 4096000,
+		.pcm_clk_rate = 512000,
 	}
 };
 
@@ -3759,26 +4061,6 @@
 struct msm_iommu_domain_name msm8960_iommu_ctx_names[] = {
 	/* Camera */
 	{
-		.name = "vpe_src",
-		.domain = CAMERA_DOMAIN,
-	},
-	/* Camera */
-	{
-		.name = "vpe_dst",
-		.domain = CAMERA_DOMAIN,
-	},
-	/* Camera */
-	{
-		.name = "vfe_imgwr",
-		.domain = CAMERA_DOMAIN,
-	},
-	/* Camera */
-	{
-		.name = "vfe_misc",
-		.domain = CAMERA_DOMAIN,
-	},
-	/* Camera */
-	{
 		.name = "ijpeg_src",
 		.domain = CAMERA_DOMAIN,
 	},
@@ -4028,3 +4310,19 @@
 	.num_resources	= ARRAY_SIZE(sglte_resources),
 	.resource	= sglte_resources,
 };
+
+struct platform_device *msm8960_vidc_device[] __initdata = {
+	&msm_device_vidc
+};
+
+void __init msm8960_add_vidc_device(void)
+{
+	if (cpu_is_msm8960ab()) {
+		struct msm_vidc_platform_data *pdata;
+		pdata = (struct msm_vidc_platform_data *)
+			msm_device_vidc.dev.platform_data;
+		pdata->vidc_bus_client_pdata = &vidc_pro_bus_client_data;
+	}
+	platform_add_devices(msm8960_vidc_device,
+		ARRAY_SIZE(msm8960_vidc_device));
+}
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index fff8e0d..0a9bbf6 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[] = {
@@ -163,25 +174,25 @@
 
 static struct resource resources_usb_bam[] = {
 	{
-		.name	= "usb_bam_addr",
+		.name	= "hsusb",
 		.start	= MSM_USB_BAM_BASE,
 		.end	= MSM_USB_BAM_BASE + MSM_USB_BAM_SIZE - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
-		.name	= "usb_bam_irq",
+		.name	= "hsusb",
 		.start	= USB1_HS_BAM_IRQ,
 		.end	= USB1_HS_BAM_IRQ,
 		.flags	= IORESOURCE_IRQ,
 	},
 	{
-		.name	= "hsic_bam_addr",
+		.name	= "hsic",
 		.start	= MSM_HSIC_BAM_BASE,
 		.end	= MSM_HSIC_BAM_BASE + MSM_HSIC_BAM_SIZE - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
-		.name	= "hsic_bam_irq",
+		.name	= "hsic",
 		.start	= USB_HSIC_BAM_IRQ,
 		.end	= USB_HSIC_BAM_IRQ,
 		.flags	= IORESOURCE_IRQ,
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-iommu.c b/arch/arm/mach-msm/devices-iommu.c
index ae8a8fe..b65bd1f 100644
--- a/arch/arm/mach-msm/devices-iommu.c
+++ b/arch/arm/mach-msm/devices-iommu.c
@@ -939,8 +939,11 @@
 	&msm_device_iommu_gfx2d1,
 };
 
-static struct platform_device *msm_iommu_8064_devs[] = {
+static struct platform_device *msm_iommu_adreno3xx_gfx_devs[] = {
 	&msm_device_iommu_gfx3d1,
+};
+
+static struct platform_device *msm_iommu_vcap_devs[] = {
 	&msm_device_iommu_vcap,
 };
 
@@ -973,9 +976,12 @@
 	&msm_device_gfx2d1_2d1_ctx,
 };
 
-static struct platform_device *msm_iommu_8064_ctx_devs[] = {
+static struct platform_device *msm_iommu_adreno3xx_ctx_devs[] = {
 	&msm_device_gfx3d1_user_ctx,
 	&msm_device_gfx3d1_priv_ctx,
+};
+
+static struct platform_device *msm_iommu_vcap_ctx_devs[] = {
 	&msm_device_vcap_vc_ctx,
 	&msm_device_vcap_vp_ctx,
 };
@@ -1014,9 +1020,12 @@
 	if (cpu_is_apq8064() || cpu_is_msm8960ab()) {
 		platform_add_devices(msm_iommu_jpegd_devs,
 				ARRAY_SIZE(msm_iommu_jpegd_devs));
-		platform_add_devices(msm_iommu_8064_devs,
-				ARRAY_SIZE(msm_iommu_8064_devs));
+		platform_add_devices(msm_iommu_adreno3xx_gfx_devs,
+				ARRAY_SIZE(msm_iommu_adreno3xx_gfx_devs));
 	}
+	if (cpu_is_apq8064())
+		platform_add_devices(msm_iommu_vcap_devs,
+				ARRAY_SIZE(msm_iommu_vcap_devs));
 
 	/* Initialize common ctx_devs */
 	ret = platform_add_devices(msm_iommu_common_ctx_devs,
@@ -1033,9 +1042,13 @@
 	if (cpu_is_apq8064() || cpu_is_msm8960ab()) {
 		platform_add_devices(msm_iommu_jpegd_ctx_devs,
 				ARRAY_SIZE(msm_iommu_jpegd_ctx_devs));
-		platform_add_devices(msm_iommu_8064_ctx_devs,
-				ARRAY_SIZE(msm_iommu_8064_ctx_devs));
+
+		platform_add_devices(msm_iommu_adreno3xx_ctx_devs,
+				ARRAY_SIZE(msm_iommu_adreno3xx_ctx_devs));
 	}
+	if (cpu_is_apq8064())
+		platform_add_devices(msm_iommu_vcap_ctx_devs,
+			ARRAY_SIZE(msm_iommu_vcap_ctx_devs));
 
 	return 0;
 
@@ -1068,16 +1081,33 @@
 		for (i = 0; i < ARRAY_SIZE(msm_iommu_jpegd_devs); i++)
 			platform_device_unregister(msm_iommu_jpegd_devs[i]);
 	}
+	if (cpu_is_apq8064()) {
+		for (i = 0; i < ARRAY_SIZE(msm_iommu_vcap_ctx_devs); i++)
+			platform_device_unregister(msm_iommu_vcap_ctx_devs[i]);
+	}
 
 	if (cpu_is_apq8064() || cpu_is_msm8960ab()) {
-		for (i = 0; i < ARRAY_SIZE(msm_iommu_8064_ctx_devs); i++)
-			platform_device_unregister(msm_iommu_8064_ctx_devs[i]);
+		for (i = 0; i < ARRAY_SIZE(msm_iommu_adreno3xx_ctx_devs);
+			   i++)
+			platform_device_unregister(
+				msm_iommu_adreno3xx_ctx_devs[i]);
 
-		for (i = 0; i < ARRAY_SIZE(msm_iommu_jpegd_ctx_devs); i++)
-			platform_device_unregister(msm_iommu_jpegd_ctx_devs[i]);
+		for (i = 0; i < ARRAY_SIZE(msm_iommu_jpegd_ctx_devs);
+			   i++)
+			platform_device_unregister(
+				msm_iommu_jpegd_ctx_devs[i]);
 
-		for (i = 0; i < ARRAY_SIZE(msm_iommu_8064_devs); i++)
-			platform_device_unregister(msm_iommu_8064_devs[i]);
+		if (cpu_is_apq8064()) {
+			for (i = 0; i < ARRAY_SIZE(msm_iommu_vcap_devs);
+			   i++)
+				platform_device_unregister(
+				msm_iommu_vcap_devs[i]);
+		}
+
+		for (i = 0; i < ARRAY_SIZE(msm_iommu_adreno3xx_gfx_devs);
+			   i++)
+			platform_device_unregister(
+				msm_iommu_adreno3xx_gfx_devs[i]);
 
 		for (i = 0; i < ARRAY_SIZE(msm_iommu_jpegd_devs); i++)
 			platform_device_unregister(msm_iommu_jpegd_devs[i]);
diff --git a/arch/arm/mach-msm/devices-msm7x01a.c b/arch/arm/mach-msm/devices-msm7x01a.c
index 1b9eb86..6472fc4 100644
--- a/arch/arm/mach-msm/devices-msm7x01a.c
+++ b/arch/arm/mach-msm/devices-msm7x01a.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2008 Google, Inc.
- * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -648,7 +648,7 @@
 	.resource       = msm_ebi2_lcd_resources,
 };
 
-static struct platform_device msm_lcdc_device = {
+struct platform_device msm_lcdc_device = {
 	.name   = "lcdc",
 	.id     = 0,
 };
diff --git a/arch/arm/mach-msm/devices-msm7x25.c b/arch/arm/mach-msm/devices-msm7x25.c
index 99b2960..6f89007 100644
--- a/arch/arm/mach-msm/devices-msm7x25.c
+++ b/arch/arm/mach-msm/devices-msm7x25.c
@@ -777,7 +777,7 @@
 	.resource       = msm_ebi2_lcd_resources,
 };
 
-static struct platform_device msm_lcdc_device = {
+struct platform_device msm_lcdc_device = {
 	.name   = "lcdc",
 	.id     = 0,
 };
diff --git a/arch/arm/mach-msm/devices-msm7x27.c b/arch/arm/mach-msm/devices-msm7x27.c
index 82c5eed..f869965 100644
--- a/arch/arm/mach-msm/devices-msm7x27.c
+++ b/arch/arm/mach-msm/devices-msm7x27.c
@@ -715,7 +715,7 @@
 	.resource       = msm_ebi2_lcd_resources,
 };
 
-static struct platform_device msm_lcdc_device = {
+struct platform_device msm_lcdc_device = {
 	.name   = "lcdc",
 	.id     = 0,
 };
diff --git a/arch/arm/mach-msm/devices-msm7x27a.c b/arch/arm/mach-msm/devices-msm7x27a.c
index 1fcf7dc..cd5b2e5 100644
--- a/arch/arm/mach-msm/devices-msm7x27a.c
+++ b/arch/arm/mach-msm/devices-msm7x27a.c
@@ -39,6 +39,8 @@
 #include "mpm-8625.h"
 #include "irq.h"
 #include "pm.h"
+#include "msm_cpr.h"
+#include "msm_smem_iface.h"
 
 /* Address of GSBI blocks */
 #define MSM_GSBI0_PHYS		0xA1200000
@@ -48,6 +50,12 @@
 #define MSM_GSBI0_QUP_PHYS	(MSM_GSBI0_PHYS + 0x80000)
 #define MSM_GSBI1_QUP_PHYS	(MSM_GSBI1_PHYS + 0x80000)
 
+#define A11S_TEST_BUS_SEL_ADDR (MSM_CSR_BASE + 0x518)
+#define RBCPR_CLK_MUX_SEL (1 << 13)
+
+/* Reset Address of RBCPR (Active Low)*/
+#define RBCPR_SW_RESET_N       (MSM_CSR_BASE + 0x64)
+
 static struct resource gsbi0_qup_i2c_resources[] = {
 	{
 		.name	= "qup_phys_addr",
@@ -501,6 +509,19 @@
 
 }
 
+static struct msm_pm_cpr_ops msm8625_pm_cpr_ops = {
+	.cpr_suspend = msm_cpr_pm_suspend,
+	.cpr_resume = msm_cpr_pm_resume,
+};
+
+void __init msm_pm_register_cpr_ops(void)
+{
+	/* CPR presents on revision >= v2.0 chipsets */
+	if (cpu_is_msm8625() &&
+			SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 2)
+		msm_pm_set_cpr_ops(&msm8625_pm_cpr_ops);
+}
+
 #define MSM_SDC1_BASE         0xA0400000
 #define MSM_SDC2_BASE         0xA0500000
 #define MSM_SDC3_BASE         0xA0600000
@@ -827,7 +848,7 @@
 	.resource       = msm_mdp_resources,
 };
 
-static struct platform_device msm_lcdc_device = {
+struct platform_device msm_lcdc_device = {
 	.name   = "lcdc",
 	.id     = 0,
 };
@@ -897,8 +918,13 @@
 	if (cpu_is_msm8625()) {
 		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 = 320000000;
+
+		if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 2)
+			/* 8x25 v2.0 & above supports a higher GPU frequency */
+			kgsl_3d0_pdata.pwrlevel[0].gpu_freq = 320000000;
+		else
+			kgsl_3d0_pdata.pwrlevel[0].gpu_freq = 300000000;
+
 		kgsl_3d0_pdata.pwrlevel[0].bus_freq = 200000000;
 	}
 }
@@ -1250,8 +1276,8 @@
 	},
 	{
 		.name	= "dma_chnl",
-		.start	= DMOV_SDC3_CHAN,
-		.end	= DMOV_SDC3_CHAN,
+		.start	= DMOV_NAND_CHAN,
+		.end	= DMOV_NAND_CHAN,
 		.flags	= IORESOURCE_DMA,
 	},
 	{
@@ -1579,6 +1605,244 @@
 	},
 };
 
+enum {
+	MSM8625,
+	MSM8625A,
+	MSM8625AB,
+};
+
+static int __init msm8625_cpu_id(void)
+{
+	int raw_id, cpu;
+
+	raw_id = socinfo_get_raw_id();
+	switch (raw_id) {
+	/* 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 0x779:
+	case 0x77D:
+	case 0x782:
+	case 0x8D2:
+		cpu = MSM8625AB;
+		break;
+	default:
+		pr_err("Invalid Raw ID\n");
+		return -ENODEV;
+	}
+	return cpu;
+}
+
+static struct resource cpr_resources[] = {
+	{
+		.start = MSM8625_INT_CPR_IRQ0,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = MSM8625_CPR_PHYS,
+		.end = MSM8625_CPR_PHYS + SZ_4K - 1,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+/**
+ * These are various Vdd levels supported by PMIC
+ */
+static uint32_t msm_c2_pmic_mv[] __initdata = {
+	1300000, 1287500, 1275000, 1262500, 1250000,
+	1237500, 1225000, 1212500, 1200000, 1187500,
+	1175000, 1162500, 1150000, 1137500, 1125000,
+	1112500, 1100000, 1087500, 1075000, 1062500,
+	1050000, 1037500, 1025000, 1012500, 0, 0, 0,
+	0, 0, 0, 0, 1000,
+};
+
+/**
+ * This data will be based on CPR mode of operation
+ */
+static struct msm_cpr_mode msm_cpr_mode_data[] = {
+	[NORMAL_MODE] = {
+			.ring_osc_data = {
+				{0, },
+				{0, },
+				{0, },
+				{0, },
+				{0, },
+				{0, },
+				{0, },
+				{0, },
+			},
+			.ring_osc = 0,
+			.step_quot = ~0,
+			.tgt_volt_offset = 0,
+			.nom_Vmax = 1350000,
+			.nom_Vmin = 1250000,
+			.calibrated_uV = 1100000,
+	},
+	[TURBO_MODE] = {
+			.ring_osc_data = {
+				{0, },
+				{0, },
+				{0, },
+				{0, },
+				{0, },
+				{0, },
+				{0, },
+				{0, },
+			},
+			.ring_osc = 0,
+			.step_quot = ~0,
+			.tgt_volt_offset = 0,
+			.turbo_Vmax = 1350000,
+			.turbo_Vmin = 950000,
+			.nom_Vmax = 1350000,
+			.nom_Vmin = 950000,
+			.calibrated_uV = 1300000,
+	},
+};
+
+struct msm_cpr_vp_data vp_data = {
+	.min_volt = 1000000,
+	.max_volt = 1350000,
+	.default_volt = 1300000,
+	.step_size = 12500,
+};
+
+static uint32_t
+msm_cpr_get_quot(uint32_t max_quot, uint32_t max_freq, uint32_t new_freq)
+{
+	uint32_t quot;
+
+	/* This formula is as per chip characterization data */
+	quot = max_quot - ((max_freq / 10 - new_freq / 10) * 5);
+
+	return quot;
+}
+
+static void msm_cpr_clk_enable(void)
+{
+	uint32_t reg_val;
+
+	/* Select TCXO (19.2MHz) as clock source */
+	reg_val = readl_relaxed(A11S_TEST_BUS_SEL_ADDR);
+	reg_val |= RBCPR_CLK_MUX_SEL;
+	writel_relaxed(reg_val, A11S_TEST_BUS_SEL_ADDR);
+
+	/* Get CPR out of reset */
+	writel_relaxed(0x1, RBCPR_SW_RESET_N);
+}
+
+static struct msm_cpr_config msm_cpr_pdata = {
+	.ref_clk_khz = 19200,
+	.delay_us = 25000,
+	.irq_line = 0,
+	.cpr_mode_data = msm_cpr_mode_data,
+	.tgt_count_div_N = 1,
+	.floor = 0,
+	.ceiling = 40,
+	.sw_vlevel = 20,
+	.up_threshold = 1,
+	.dn_threshold = 2,
+	.up_margin = 0,
+	.dn_margin = 0,
+	.max_nom_freq = 700800,
+	.max_freq = 1401600,
+	.max_quot = 0,
+	.vp_data = &vp_data,
+	.get_quot = msm_cpr_get_quot,
+	.clk_enable = msm_cpr_clk_enable,
+};
+
+static struct platform_device msm8625_device_cpr = {
+	.name           = "msm-cpr",
+	.id             = -1,
+	.num_resources  = ARRAY_SIZE(cpr_resources),
+	.resource       = cpr_resources,
+	.dev = {
+		.platform_data = &msm_cpr_pdata,
+	},
+};
+
+static struct platform_device msm8625_vp_device = {
+	.name           = "vp-regulator",
+	.id             = -1,
+};
+
+static void __init msm_cpr_init(void)
+{
+	struct cpr_info_type *cpr_info = NULL;
+	uint8_t ring_osc = 0;
+
+	cpr_info = kzalloc(sizeof(struct cpr_info_type), GFP_KERNEL);
+	if (!cpr_info) {
+		pr_err("%s: Out of memory %d\n", __func__, -ENOMEM);
+		return;
+	}
+
+	msm_smem_get_cpr_info(cpr_info);
+
+	/**
+	 * Set the ring_osc based on efuse BIT(0)
+	 * CPR_fuse[0] = 0 selects 2nd RO (010)
+	 * CPR_fuse[0] = 1 select  3rd RO (011)
+	 */
+	if (cpr_info->ring_osc == 0x0)
+		ring_osc = 0x2;
+	else if (cpr_info->ring_osc == 0x1)
+		ring_osc = 0x3;
+
+	msm_cpr_mode_data[TURBO_MODE].ring_osc = ring_osc;
+	msm_cpr_mode_data[NORMAL_MODE].ring_osc = ring_osc;
+
+	/* GCNT = 1000 nsec/52nsec (@TCX0=19.2Mhz) = 19.2 */
+	msm_cpr_mode_data[TURBO_MODE].ring_osc_data[ring_osc].gcnt = 19;
+	msm_cpr_mode_data[NORMAL_MODE].ring_osc_data[ring_osc].gcnt = 19;
+
+	/**
+	 * The scaling factor and offset are as per chip characterization data
+	 * This formula is used since available fuse bits in the chip are not
+	 * enough to represent the value of maximum quot
+	 */
+	msm_cpr_pdata.max_quot = cpr_info->turbo_quot * 10 + 600;
+
+	/**
+	 * Bits 4:0 of pvs_fuse provide mapping to the safe boot up voltage.
+	 * Boot up mode is by default Turbo.
+	 */
+	msm_cpr_mode_data[TURBO_MODE].calibrated_uV =
+				msm_c2_pmic_mv[cpr_info->pvs_fuse & 0x1F];
+
+	pr_debug("%s: cpr: ring_osc: 0x%x\n", __func__,
+		msm_cpr_mode_data[TURBO_MODE].ring_osc);
+	pr_debug("%s: cpr: turbo_quot: 0x%x\n", __func__, cpr_info->turbo_quot);
+	pr_debug("%s: cpr: pvs_fuse: 0x%x\n", __func__, cpr_info->pvs_fuse);
+	kfree(cpr_info);
+
+	if (msm8625_cpu_id() == MSM8625A)
+		msm_cpr_pdata.max_freq = 1209600;
+	else if (msm8625_cpu_id() == MSM8625)
+		msm_cpr_pdata.max_freq = 1008000;
+
+	msm_cpr_clk_enable();
+
+	platform_device_register(&msm8625_vp_device);
+	platform_device_register(&msm8625_device_cpr);
+}
+
 static struct clk_lookup msm_clock_8625_dummy[] = {
 	CLK_DUMMY("core_clk",		adm_clk.c,	"msm_dmov", 0),
 	CLK_DUMMY("adsp_clk",		adsp_clk.c,	NULL, 0),
@@ -1646,51 +1910,11 @@
 	.size = ARRAY_SIZE(msm_clock_8625_dummy),
 };
 
-enum {
-	MSM8625,
-	MSM8625A,
-	MSM8625AB,
-};
-
-static int __init msm8625_cpu_id(void)
-{
-	int raw_id, cpu;
-
-	raw_id = socinfo_get_raw_id();
-	switch (raw_id) {
-	/* 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:
-		pr_err("Invalid Raw ID\n");
-		return -ENODEV;
-	}
-	return cpu;
-}
-
 int __init msm7x2x_misc_init(void)
 {
 	if (machine_is_msm8625_rumi3()) {
 		msm_clock_init(&msm8625_dummy_clock_init_data);
+		msm_cpr_init();
 		return 0;
 	}
 
@@ -1707,6 +1931,11 @@
 	} else {
 		platform_device_register(&msm7x27a_device_acpuclk);
 	}
+
+	if (cpu_is_msm8625() &&
+			(SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 2))
+		msm_cpr_init();
+
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/devices-msm7x2xa.h b/arch/arm/mach-msm/devices-msm7x2xa.h
index 8febe26..8b59b14 100644
--- a/arch/arm/mach-msm/devices-msm7x2xa.h
+++ b/arch/arm/mach-msm/devices-msm7x2xa.h
@@ -31,6 +31,7 @@
 void __init msm8625_map_io(void);
 int  ar600x_wlan_power(bool on);
 void __init msm8x25_spm_device_init(void);
+void __init msm_pm_register_cpr_ops(void);
 void __init msm8x25_kgsl_3d0_init(void);
 void __iomem *core1_reset_base(void);
 extern void setup_mm_for_reboot(void);
diff --git a/arch/arm/mach-msm/devices-msm7x30.c b/arch/arm/mach-msm/devices-msm7x30.c
index a6473c6..b456f50 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 <linux/msm_ion.h>
 #include "devices.h"
 #include "footswitch.h"
 
@@ -1092,7 +1092,7 @@
 	.resource       = msm_ebi2_lcd_resources,
 };
 
-static struct platform_device msm_lcdc_device = {
+struct platform_device msm_lcdc_device = {
 	.name   = "lcdc",
 	.id     = 0,
 };
@@ -1329,7 +1329,7 @@
 static struct kgsl_device_platform_data kgsl_2d0_pdata = {
 	.pwrlevel = {
 		{
-			.gpu_freq = 192000000,
+			.gpu_freq = 0,
 			.bus_freq = 192000000,
 		},
 	},
diff --git a/arch/arm/mach-msm/devices-msm8x60.c b/arch/arm/mach-msm/devices-msm8x60.c
index 5402251..7bffd9b 100644
--- a/arch/arm/mach-msm/devices-msm8x60.c
+++ b/arch/arm/mach-msm/devices-msm8x60.c
@@ -15,7 +15,7 @@
 #include <linux/platform_device.h>
 #include <linux/regulator/machine.h>
 #include <linux/regulator/consumer.h>
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
 #include <mach/irqs.h>
 #include <mach/dma.h>
 #include <asm/mach/mmc.h>
@@ -1733,7 +1733,7 @@
 			  __func__, ret);
 }
 
-static struct platform_device msm_lcdc_device = {
+struct platform_device msm_lcdc_device = {
 	.name   = "lcdc",
 	.id     = 0,
 };
@@ -1996,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 = {
@@ -2004,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[] = {
@@ -2304,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,
@@ -2988,26 +3003,6 @@
 struct msm_iommu_domain_name msm8660_iommu_ctx_names[] = {
 	/* Camera */
 	{
-		.name = "vpe_src",
-		.domain = CAMERA_DOMAIN,
-	},
-	/* Camera */
-	{
-		.name = "vpe_dst",
-		.domain = CAMERA_DOMAIN,
-	},
-	/* Camera */
-	{
-		.name = "vfe_imgwr",
-		.domain = CAMERA_DOMAIN,
-	},
-	/* Camera */
-	{
-		.name = "vfe_misc",
-		.domain = CAMERA_DOMAIN,
-	},
-	/* Camera */
-	{
 		.name = "ijpeg_src",
 		.domain = CAMERA_DOMAIN,
 	},
diff --git a/arch/arm/mach-msm/devices-qsd8x50.c b/arch/arm/mach-msm/devices-qsd8x50.c
index 03ffa2f..626367e 100644
--- a/arch/arm/mach-msm/devices-qsd8x50.c
+++ b/arch/arm/mach-msm/devices-qsd8x50.c
@@ -757,7 +757,7 @@
 	.resource       = msm_ebi2_lcd_resources,
 };
 
-static struct platform_device msm_lcdc_device = {
+struct platform_device msm_lcdc_device = {
 	.name   = "lcdc",
 	.id     = 0,
 };
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 8e2ab7d..e66bf27 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -55,6 +55,7 @@
 extern struct platform_device msm_device_uart_dm6;
 extern struct platform_device msm_device_uart_dm8;
 extern struct platform_device msm_device_uart_dm9;
+extern struct platform_device mpq8064_device_uartdm_gsbi6;
 
 extern struct platform_device msm8960_device_uart_gsbi2;
 extern struct platform_device msm8960_device_uart_gsbi5;
@@ -190,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;
@@ -205,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;
@@ -268,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;
@@ -309,6 +313,7 @@
 
 extern struct platform_device msm_mipi_dsi1_device;
 extern struct platform_device mipi_dsi_device;
+extern struct platform_device msm_lcdc_device;
 extern struct platform_device msm_lvds_device;
 extern struct platform_device msm_ebi2_lcdc_device;
 
@@ -435,6 +440,12 @@
 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;
+
+extern struct platform_device apq_cpudai_mi2s;
+extern struct platform_device apq_cpudai_i2s_rx;
+extern struct platform_device apq_cpudai_i2s_tx;
+
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 1770b97..306011a 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -64,18 +64,6 @@
 	uint8_t is_vpe;
 	struct msm_bus_scale_pdata *cam_bus_scale_table;
 };
-enum msm_camera_csi_data_format {
-	CSI_8BIT,
-	CSI_10BIT,
-	CSI_12BIT,
-};
-struct msm_camera_csi_params {
-	enum msm_camera_csi_data_format data_format;
-	uint8_t lane_cnt;
-	uint8_t lane_assign;
-	uint8_t settle_cnt;
-	uint8_t dpcm_scheme;
-};
 
 #ifdef CONFIG_SENSORS_MT9T013
 struct msm_camera_legacy_device_platform_data {
@@ -180,21 +168,6 @@
 	YUV_SENSOR,
 };
 
-enum camera_vreg_type {
-	REG_LDO,
-	REG_VS,
-	REG_GPIO,
-	REG_MAX
-};
-
-struct camera_vreg_t {
-	const char *reg_name;
-	enum camera_vreg_type type;
-	int min_voltage;
-	int max_voltage;
-	int op_mode;
-};
-
 struct msm_gpio_set_tbl {
 	unsigned gpio;
 	unsigned long flags;
@@ -204,6 +177,7 @@
 struct msm_camera_csi_lane_params {
 	uint16_t csi_lane_assign;
 	uint16_t csi_lane_mask;
+	uint8_t csi_phy_sel;
 };
 
 struct msm_camera_gpio_conf {
@@ -234,6 +208,13 @@
 	enum msm_camera_i2c_mux_mode i2c_mux_mode;
 };
 
+enum msm_camera_vreg_name_t {
+	CAM_VDIG,
+	CAM_VIO,
+	CAM_VANA,
+	CAM_VAF,
+};
+
 struct msm_camera_sensor_platform_info {
 	int mount_angle;
 	int sensor_reset;
@@ -268,6 +249,9 @@
 struct msm_eeprom_info {
 	struct i2c_board_info const *board_info;
 	int bus_id;
+	int eeprom_reg_addr;
+	int eeprom_read_length;
+	int eeprom_i2c_slave_addr;
 };
 
 struct msm_camera_sensor_info {
@@ -285,7 +269,6 @@
 	uint8_t num_resources;
 	struct msm_camera_sensor_flash_data *flash_data;
 	int csi_if;
-	struct msm_camera_csi_params csi_params;
 	struct msm_camera_sensor_strobe_flash_data *strobe_flash_data;
 	char *eeprom_data;
 	enum msm_camera_type camera_type;
@@ -314,6 +297,17 @@
 	unsigned num;
 };
 
+struct cad_endpoint {
+	int id;
+	const char *name;
+	uint32_t capability;
+};
+
+struct msm_cad_endpoints {
+	struct cad_endpoint *endpoints;
+	unsigned num;
+};
+
 #define MSM_MAX_DEC_CNT 14
 /* 7k target ADSP information */
 /* Bit 23:0, for codec identification like mp3, wav etc *
@@ -334,6 +328,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 +386,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
@@ -402,6 +395,8 @@
 	u32 ov1_wb_size;  /* overlay1 writeback size */
 	u32 mem_hid;
 	char cont_splash_enabled;
+	u32 splash_screen_addr;
+	u32 splash_screen_size;
 	char mdp_iommu_split_domain;
 };
 
@@ -510,6 +505,7 @@
 	uint32_t gpio_mhl_power;
 	/* GPIO no. for hdmi-mhl mux */
 	uint32_t gpio_hdmi_mhl_mux;
+	bool mhl_enabled;
 };
 
 struct msm_i2c_platform_data {
@@ -523,6 +519,7 @@
 	int aux_dat;
 	int src_clk_rate;
 	int use_gsbi_shared_mode;
+	int keep_ahb_clk_on;
 	void (*msm_i2c_config_gpio)(int iface, int config_type);
 };
 
@@ -583,6 +580,9 @@
 void msm_8974_reserve(void);
 void msm_8974_very_early(void);
 void msm_8974_init_gpiomux(void);
+void msm9625_init_gpiomux(void);
+void msm_map_mpq8092_io(void);
+void mpq8092_init_gpiomux(void);
 
 struct mmc_platform_data;
 int msm_add_sdcc(unsigned int controller,
diff --git a/arch/arm/mach-msm/include/mach/camera.h b/arch/arm/mach-msm/include/mach/camera.h
index a51a6b5..60ccded 100644
--- a/arch/arm/mach-msm/include/mach/camera.h
+++ b/arch/arm/mach-msm/include/mach/camera.h
@@ -127,30 +127,6 @@
 	uint32_t frame_id;
 };
 
-struct msm_camera_csid_lut_params {
-	uint8_t num_cid;
-	struct msm_camera_csid_vc_cfg *vc_cfg;
-};
-
-struct msm_camera_csid_params {
-	uint8_t lane_cnt;
-	uint16_t lane_assign;
-	uint8_t phy_sel;
-	struct msm_camera_csid_lut_params lut_params;
-};
-
-struct msm_camera_csiphy_params {
-	uint8_t lane_cnt;
-	uint8_t settle_cnt;
-	uint16_t lane_mask;
-	uint8_t combo_mode;
-};
-
-struct msm_camera_csi2_params {
-	struct msm_camera_csid_params csid_params;
-	struct msm_camera_csiphy_params csiphy_params;
-};
-
 #ifndef CONFIG_MSM_CAMERA_V4L2
 #define VFE31_OUTPUT_MODE_PT (0x1 << 0)
 #define VFE31_OUTPUT_MODE_S (0x1 << 1)
@@ -332,21 +308,6 @@
 	uint16_t i2c_queue;
 };
 
-enum msm_camera_i2c_reg_addr_type {
-	MSM_CAMERA_I2C_BYTE_ADDR = 1,
-	MSM_CAMERA_I2C_WORD_ADDR,
-};
-
-enum msm_camera_i2c_data_type {
-	MSM_CAMERA_I2C_BYTE_DATA = 1,
-	MSM_CAMERA_I2C_WORD_DATA,
-	MSM_CAMERA_I2C_SET_BYTE_MASK,
-	MSM_CAMERA_I2C_UNSET_BYTE_MASK,
-	MSM_CAMERA_I2C_SET_WORD_MASK,
-	MSM_CAMERA_I2C_UNSET_WORD_MASK,
-	MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA,
-};
-
 enum msm_camera_i2c_cmd_type {
 	MSM_CAMERA_I2C_CMD_WRITE,
 	MSM_CAMERA_I2C_CMD_POLL,
@@ -406,6 +367,7 @@
 	atomic_t on_heap;
 	struct timespec ts;
 	uint32_t error_code;
+	uint32_t trans_code;
 };
 
 struct msm_device_queue {
@@ -670,14 +632,10 @@
 	S_STEREO_CAPTURE,
 	S_DEFAULT,
 	S_LIVESHOT,
+	S_DUAL,
 	S_EXIT
 };
 
-struct msm_cam_clk_info {
-	const char *clk_name;
-	long clk_rate;
-};
-
 int msm_camio_enable(struct platform_device *dev);
 int msm_camio_vpe_clk_enable(uint32_t);
 int msm_camio_vpe_clk_disable(void);
@@ -733,12 +691,16 @@
 int msm_cam_core_reset(void);
 
 int msm_camera_config_vreg(struct device *dev, struct camera_vreg_t *cam_vreg,
-		int num_vreg, struct regulator **reg_ptr, int config);
+		int num_vreg, enum msm_camera_vreg_name_t *vreg_seq,
+		int num_vreg_seq, struct regulator **reg_ptr, int config);
 int msm_camera_enable_vreg(struct device *dev, struct camera_vreg_t *cam_vreg,
-		int num_vreg, struct regulator **reg_ptr, int enable);
+		int num_vreg, enum msm_camera_vreg_name_t *vreg_seq,
+		int num_vreg_seq, struct regulator **reg_ptr, int enable);
 
 int msm_camera_config_gpio_table
 	(struct msm_camera_sensor_info *sinfo, int gpio_en);
 int msm_camera_request_gpio_table
 	(struct msm_camera_sensor_info *sinfo, int gpio_en);
+void msm_camera_bus_scale_cfg(uint32_t bus_perf_client,
+		enum msm_bus_perf_setting perf_setting);
 #endif
diff --git a/arch/arm/mach-msm/include/mach/cpuidle.h b/arch/arm/mach-msm/include/mach/cpuidle.h
index 8566e7f..af773a0 100644
--- a/arch/arm/mach-msm/include/mach/cpuidle.h
+++ b/arch/arm/mach-msm/include/mach/cpuidle.h
@@ -37,23 +37,4 @@
 static inline int msm_cpuidle_init(void) { return -ENOSYS; }
 #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);
-#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; }
-#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/diag_dload.h b/arch/arm/mach-msm/include/mach/diag_dload.h
new file mode 100644
index 0000000..83c7f2d
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/diag_dload.h
@@ -0,0 +1,32 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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_DIAG_DLOAD_H__
+#define __LINUX_DIAG_DLOAD_H__
+
+
+#define PID_MAGIC_ID		0x71432909
+#define SERIAL_NUM_MAGIC_ID	0x61945374
+#define SERIAL_NUMBER_LENGTH	128
+
+struct magic_num_struct {
+	uint32_t pid;
+	uint32_t serial_num;
+};
+
+struct dload_struct {
+	uint32_t	pid;
+	char		serial_number[SERIAL_NUMBER_LENGTH];
+	struct magic_num_struct magic_struct;
+};
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/dma.h b/arch/arm/mach-msm/include/mach/dma.h
index 6a389de..988b249 100644
--- a/arch/arm/mach-msm/include/mach/dma.h
+++ b/arch/arm/mach-msm/include/mach/dma.h
@@ -272,6 +272,12 @@
 #define DMOV8064_TSIF_CHAN         2
 #define DMOV8064_TSIF_CRCI         1
 
+/* channels for MPQ8064 */
+#define DMOV_MPQ8064_HSUART_GSBI6_TX_CHAN	7
+#define DMOV_MPQ8064_HSUART_GSBI6_TX_CRCI	6
+
+#define DMOV_MPQ8064_HSUART_GSBI6_RX_CHAN	6
+#define DMOV_MPQ8064_HSUART_GSBI6_RX_CRCI	11
 
 /* no client rate control ifc (eg, ram) */
 #define DMOV_NONE_CRCI        0
diff --git a/arch/arm/mach-msm/include/mach/irqs-8092.h b/arch/arm/mach-msm/include/mach/irqs-8092.h
new file mode 100644
index 0000000..ae9634e
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/irqs-8092.h
@@ -0,0 +1,45 @@
+/* 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 __ASM_ARCH_MSM_IRQS_8092_H
+#define __ASM_ARCH_MSM_IRQS_8092_H
+
+/* MSM ACPU Interrupt Numbers */
+
+/*
+ * 0-15:  STI/SGI (software triggered/generated interrupts)
+ * 16-31: PPI (private peripheral interrupts)
+ * 32+:   SPI (shared peripheral interrupts)
+ */
+
+#define GIC_PPI_START 16
+#define GIC_SPI_START 32
+
+#define AVS_SVICINT				(GIC_PPI_START + 6)
+#define AVS_SVICINTSWDONE			(GIC_PPI_START + 7)
+#define INT_ARMQC_PERFMON			(GIC_PPI_START + 10)
+/* PPI 15 is unused */
+
+#define APCC_QGICL2PERFMONIRPTREQ	(GIC_SPI_START + 1)
+#define SC_SICL2PERFMONIRPTREQ		APCC_QGICL2PERFMONIRPTREQ
+#define TLMM_MSM_SUMMARY_IRQ		(GIC_SPI_START + 208)
+#define SPS_BAM_DMA_IRQ			(GIC_SPI_START + 105)
+
+#define NR_MSM_IRQS 1020 /* Should be 256 - but higher due to bug in sim */
+#define NR_GPIO_IRQS 146
+#define NR_QPNP_IRQS 32768 /* SPARSE_IRQ is required to support this */
+#define NR_BOARD_IRQS NR_QPNP_IRQS
+#define NR_TLMM_MSM_DIR_CONN_IRQ 8
+#define NR_MSM_GPIOS NR_GPIO_IRQS
+
+#endif
+
diff --git a/arch/arm/mach-msm/include/mach/irqs-8226.h b/arch/arm/mach-msm/include/mach/irqs-8226.h
new file mode 100644
index 0000000..fad7b90
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/irqs-8226.h
@@ -0,0 +1,44 @@
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 __ASM_ARCH_MSM_IRQS_8226_H
+#define __ASM_ARCH_MSM_IRQS_8226_H
+
+/* MSM ACPU Interrupt Numbers */
+
+/*
+ * 0-15:  STI/SGI (software triggered/generated interrupts)
+ * 16-31: PPI (private peripheral interrupts)
+ * 32+:   SPI (shared peripheral interrupts)
+ */
+
+#define GIC_PPI_START 16
+#define GIC_SPI_START 32
+
+#define AVS_SVICINT				(GIC_PPI_START + 6)
+#define AVS_SVICINTSWDONE			(GIC_PPI_START + 7)
+#define INT_ARMQC_PERFMON			(GIC_PPI_START + 10)
+/* PPI 15 is unused */
+
+#define APCC_QGICL2PERFMONIRPTREQ	(GIC_SPI_START + 1)
+#define SC_SICL2PERFMONIRPTREQ		APCC_QGICL2PERFMONIRPTREQ
+#define TLMM_MSM_SUMMARY_IRQ		(GIC_SPI_START + 208)
+#define SPS_BAM_DMA_IRQ			(GIC_SPI_START + 105)
+
+#define NR_MSM_IRQS 256
+#define NR_GPIO_IRQS 146
+#define NR_QPNP_IRQS 32768 /* SPARSE_IRQ is required to support this */
+#define NR_BOARD_IRQS NR_QPNP_IRQS
+#define NR_TLMM_MSM_DIR_CONN_IRQ 8
+#define NR_MSM_GPIOS NR_GPIO_IRQS
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/irqs-8625.h b/arch/arm/mach-msm/include/mach/irqs-8625.h
index 3ff73eb..413a778 100644
--- a/arch/arm/mach-msm/include/mach/irqs-8625.h
+++ b/arch/arm/mach-msm/include/mach/irqs-8625.h
@@ -84,6 +84,9 @@
 #define MSM8625_INT_L2CC_EM		(GIC_SPI_START + 32 + 22)
 #define MSM8625_INT_L2CC_INTR		(GIC_SPI_START + 32 + 23)
 #define MSM8625_INT_CE_IRQ		(GIC_SPI_START + 32 + 24)
+#define MSM8625_INT_CPR_IRQ0		(GIC_SPI_START + 32 + 25)
+#define MSM8625_INT_CPR_IRQ1		(GIC_SPI_START + 32 + 26)
+#define MSM8625_INT_CPR_IRQ2		(GIC_SPI_START + 32 + 27)
 
 #define MSM8625_INT_ADSP_A11_SMSM	MSM8625_INT_ADSP_A11
 #endif
diff --git a/arch/arm/mach-msm/include/mach/irqs.h b/arch/arm/mach-msm/include/mach/irqs.h
index 143159e..f562c40 100644
--- a/arch/arm/mach-msm/include/mach/irqs.h
+++ b/arch/arm/mach-msm/include/mach/irqs.h
@@ -60,10 +60,14 @@
 
 #if defined(CONFIG_ARCH_MSM8974)
 #include "irqs-8974.h"
+#elif defined(CONFIG_ARCH_MPQ8092)
+#include "irqs-8092.h"
 #elif defined(CONFIG_ARCH_MSM9615)
 #include "irqs-9615.h"
 #elif defined(CONFIG_ARCH_MSM9625)
 #include "irqs-9625.h"
+#elif defined(CONFIG_ARCH_MSM8226)
+#include "irqs-8226.h"
 #elif defined(CONFIG_ARCH_MSM7X30)
 #include "irqs-7x30.h"
 #elif defined(CONFIG_ARCH_QSD8X50)
diff --git a/arch/arm/mach-msm/include/mach/memory.h b/arch/arm/mach-msm/include/mach/memory.h
index 6b7ad9a..acfbe4a 100644
--- a/arch/arm/mach-msm/include/mach/memory.h
+++ b/arch/arm/mach-msm/include/mach/memory.h
@@ -79,6 +79,7 @@
 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);
+unsigned long get_ddr_size(void);
 
 extern int (*change_memory_power)(u64, u64, int);
 
diff --git a/arch/arm/mach-msm/include/mach/msm_bus.h b/arch/arm/mach-msm/include/mach/msm_bus.h
index 6d7a533..c94bf80 100644
--- a/arch/arm/mach-msm/include/mach/msm_bus.h
+++ b/arch/arm/mach-msm/include/mach/msm_bus.h
@@ -15,6 +15,7 @@
 
 #include <linux/types.h>
 #include <linux/input.h>
+#include <linux/platform_device.h>
 
 /*
  * Macros for clients to convert their data to ib and ab
@@ -77,11 +78,24 @@
 uint32_t msm_bus_scale_register_client(struct msm_bus_scale_pdata *pdata);
 int msm_bus_scale_client_update_request(uint32_t cl, unsigned int index);
 void msm_bus_scale_unregister_client(uint32_t cl);
+struct msm_bus_scale_pdata *msm_bus_cl_get_pdata(struct platform_device *pdev);
+void msm_bus_cl_clear_pdata(struct msm_bus_scale_pdata *pdata);
 /* AXI Port configuration APIs */
 int msm_bus_axi_porthalt(int master_port);
 int msm_bus_axi_portunhalt(int master_port);
 
 #else
+static inline struct msm_bus_scale_pdata
+*msm_bus_cl_get_pdata(struct platform_device *pdev)
+{
+	return NULL;
+}
+
+static inline void
+msm_bus_cl_clear_pdata(struct msm_bus_scale_pdata *pdata)
+{
+}
+
 static inline uint32_t
 msm_bus_scale_register_client(struct msm_bus_scale_pdata *pdata)
 {
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8092.h b/arch/arm/mach-msm/include/mach/msm_iomap-8092.h
new file mode 100644
index 0000000..dec8a58
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8092.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ASM_ARCH_MSM_IOMAP_8092_H
+#define __ASM_ARCH_MSM_IOMAP_8092_H
+
+/* Physical base address and size of peripherals.
+ * Ordered by the virtual base addresses they will be mapped at.
+ *
+ * If you add or remove entries here, you'll want to edit the
+ * io desc array in arch/arm/mach-msm/io.c to reflect your
+ * changes.
+ *
+ */
+
+#define MPQ8092_SHARED_RAM_PHYS	0x0FA00000
+
+#define MPQ8092_QGIC_DIST_PHYS	0xF9000000
+#define MPQ8092_QGIC_DIST_SIZE	SZ_4K
+
+#define MPQ8092_QGIC_CPU_PHYS	0xF9002000
+#define MPQ8092_QGIC_CPU_SIZE	SZ_4K
+
+#define MPQ8092_APCS_GCC_PHYS	0xF9011000
+#define MPQ8092_APCS_GCC_SIZE	SZ_4K
+
+#define MPQ8092_TLMM_PHYS	0xFD510000
+#define MPQ8092_TLMM_SIZE	SZ_16K
+
+#ifdef CONFIG_DEBUG_MPQ8092_UART
+#define MSM_DEBUG_UART_BASE	IOMEM(0xFA71E000)
+#define MSM_DEBUG_UART_PHYS	0xF991E000
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8226.h b/arch/arm/mach-msm/include/mach/msm_iomap-8226.h
new file mode 100644
index 0000000..c03b513
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8226.h
@@ -0,0 +1,48 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ASM_ARCH_MSM_IOMAP_MSM8226_H
+#define __ASM_ARCH_MSM_IOMAP_MSM8226_H
+
+/* Physical base address and size of peripherals.
+ * Ordered by the virtual base addresses they will be mapped at.
+ *
+ * If you add or remove entries here, you'll want to edit the
+ * io desc array in arch/arm/mach-msm/io.c to reflect your
+ * changes.
+ *
+ */
+
+#define MSM8226_MSM_SHARED_RAM_PHYS	0x0FA00000
+
+#define MSM8226_QGIC_DIST_PHYS	0xF9000000
+#define MSM8226_QGIC_DIST_SIZE	SZ_4K
+
+#define MSM8226_QGIC_CPU_PHYS	0xF9002000
+#define MSM8226_QGIC_CPU_SIZE	SZ_4K
+
+#define MSM8226_APCS_GCC_PHYS	0xF9011000
+#define MSM8226_APCS_GCC_SIZE	SZ_4K
+
+#define MSM8226_TLMM_PHYS	0xFD510000
+#define MSM8226_TLMM_SIZE	SZ_16K
+
+#define MSM8226_IMEM_PHYS	0xFC42B000
+#define MSM8226_IMEM_SIZE	SZ_4K
+
+#ifdef CONFIG_DEBUG_MSM8226_UART
+#define MSM_DEBUG_UART_BASE	IOMEM(0xFA71E000)
+#define MSM_DEBUG_UART_PHYS	0xF991E000
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8625.h b/arch/arm/mach-msm/include/mach/msm_iomap-8625.h
index 3435c2a..43250f5 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8625.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8625.h
@@ -57,4 +57,7 @@
 #define MSM8625_CFG_CTL_PHYS		0xA9800000
 #define MSM8625_CFG_CTL_SIZE		SZ_4K
 
+#define MSM8625_CPR_PHYS		0xC0900000
+#define MSM8625_CPR_SIZE		SZ_4K
+
 #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..15be294 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8974.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8974.h
@@ -37,9 +37,30 @@
 #define MSM8974_TLMM_PHYS	0xFD510000
 #define MSM8974_TLMM_SIZE	SZ_16K
 
+#define MSM8974_MPM2_PSHOLD_PHYS	0xFC4AB000
+#define MSM8974_MPM2_PSHOLD_SIZE	SZ_4K
+
+/*
+ * TODO: Revert IMEM_PHYS back to actual
+ * address 0xfe805000
+ * after IMEM issues resolved.
+ *
+ */
+#define MSM8974_IMEM_PHYS	0xFC42B000
+#define MSM8974_IMEM_SIZE	SZ_4K
+
 #ifdef CONFIG_DEBUG_MSM8974_UART
 #define MSM_DEBUG_UART_BASE	IOMEM(0xFA71E000)
 #define MSM_DEBUG_UART_PHYS	0xF991E000
 #endif
 
+/*
+ * IMEM is retained for secure watchdog reset
+ * Debug Image looks at actual IMEM to
+ * do memory dumping.
+ */
+
+#define MSM8974_DBG_IMEM_PHYS	0xFE805000
+#define MSM8974_DBG_IMEM_SIZE	SZ_4K
+
 #endif
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..17156b1 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..21bea4f 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap.h
@@ -53,7 +53,8 @@
 	defined(CONFIG_ARCH_MSM8974) || defined(CONFIG_ARCH_MSM7X27) || \
 	defined(CONFIG_ARCH_MSM7X25) || defined(CONFIG_ARCH_MSM7X01A) || \
 	defined(CONFIG_ARCH_MSM8625) || defined(CONFIG_ARCH_MSM7X30) || \
-	defined(CONFIG_ARCH_MSM9625)
+	defined(CONFIG_ARCH_MSM9625) || defined(CONFIG_ARCH_MPQ8092) || \
+	defined(CONFIG_ARCH_MSM8226)
 
 /* Unified iomap */
 
@@ -93,9 +94,11 @@
 #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 */
+#define MSM_DBG_IMEM_BASE	IOMEM(0xFB600000)	/*  4K */
 
 #define MSM_STRONGLY_ORDERED_PAGE	0xFA0F0000
 #define MSM8625_SECONDARY_PHYS		0x0FE00000
@@ -117,6 +120,8 @@
 #include "msm_iomap-9615.h"
 #include "msm_iomap-8974.h"
 #include "msm_iomap-9625.h"
+#include "msm_iomap-8092.h"
+#include "msm_iomap-8226.h"
 
 #else
 /* Legacy single-target iomap */
diff --git a/arch/arm/mach-msm/include/mach/msm_serial_hs.h b/arch/arm/mach-msm/include/mach/msm_serial_hs.h
index b96640d..d2905d4 100644
--- a/arch/arm/mach-msm/include/mach/msm_serial_hs.h
+++ b/arch/arm/mach-msm/include/mach/msm_serial_hs.h
@@ -25,6 +25,7 @@
 	unsigned char inject_rx_on_wakeup;
 	char rx_to_inject;
 	int (*gpio_config)(int);
+	int userid;
 };
 
 unsigned int msm_hs_tx_empty(struct uart_port *uport);
diff --git a/arch/arm/mach-msm/include/mach/msm_smd.h b/arch/arm/mach-msm/include/mach/msm_smd.h
index 97c03e7..0c452f8 100644
--- a/arch/arm/mach-msm/include/mach/msm_smd.h
+++ b/arch/arm/mach-msm/include/mach/msm_smd.h
@@ -309,6 +309,24 @@
  */
 int smd_is_pkt_avail(smd_channel_t *ch);
 
+/**
+ * smd_module_init_notifier_register() - Register a smd module
+ *					 init notifier block
+ * @nb: Notifier block to be registered
+ *
+ * In order to mark the dependency on SMD Driver module initialization
+ * register a notifier using this API. Once the smd module_init is
+ * done, notification will be passed to the registered module.
+ */
+int smd_module_init_notifier_register(struct notifier_block *nb);
+
+/**
+ * smd_module_init_notifier_register() - Unregister a smd module
+ *					 init notifier block
+ * @nb: Notifier block to be registered
+ */
+int smd_module_init_notifier_unregister(struct notifier_block *nb);
+
 /*
  * SMD initialization function that registers for a SMD platform driver.
  *
@@ -438,6 +456,16 @@
 	return -ENODEV;
 }
 
+static inline int smd_module_init_notifier_register(struct notifier_block *nb)
+{
+	return -ENODEV;
+}
+
+static inline int smd_module_init_notifier_unregister(struct notifier_block *nb)
+{
+	return -ENODEV;
+}
+
 static inline int __init msm_smd_init(void)
 {
 	return 0;
diff --git a/arch/arm/mach-msm/include/mach/msm_smsm.h b/arch/arm/mach-msm/include/mach/msm_smsm.h
index e19f39d..133a1b3 100644
--- a/arch/arm/mach-msm/include/mach/msm_smsm.h
+++ b/arch/arm/mach-msm/include/mach/msm_smsm.h
@@ -133,8 +133,6 @@
 	void *data);
 int smsm_state_cb_deregister(uint32_t smsm_entry, uint32_t mask,
 	void (*notify)(void *, uint32_t, uint32_t), void *data);
-int smsm_driver_state_notifier_register(struct notifier_block *nb);
-int smsm_driver_state_notifier_unregister(struct notifier_block *nb);
 void smsm_print_sleep_info(uint32_t sleep_delay, uint32_t sleep_limit,
 	uint32_t irq_mask, uint32_t wakeup_reason, uint32_t pending_irqs);
 void smsm_reset_modem(unsigned mode);
diff --git a/arch/arm/mach-msm/include/mach/msm_tspp.h b/arch/arm/mach-msm/include/mach/msm_tspp.h
index 6912f0c..48be504 100644
--- a/arch/arm/mach-msm/include/mach/msm_tspp.h
+++ b/arch/arm/mach-msm/include/mach/msm_tspp.h
@@ -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
@@ -13,6 +13,8 @@
 #ifndef _MSM_TSPP_H_
 #define _MSM_TSPP_H_
 
+#include <linux/tspp.h> /* tspp_source */
+
 struct msm_tspp_platform_data {
 	int num_gpios;
 	const struct msm_gpio *gpios;
@@ -20,5 +22,34 @@
 	const char *tsif_ref_clk;
 };
 
+struct tspp_data_descriptor {
+	void *virt_base;   /* logical address of the actual data */
+	u32 phys_base;     /* physical address of the actual data */
+	int size;			 /* size of buffer in bytes */
+	int id;            /* unique identifier */
+	void *user;        /* user-defined data */
+};
+
+typedef void (tspp_notifier)(int channel, void *user);
+typedef void* (tspp_allocator)(int channel, int size,
+	u32 *phys_base, void *user);
+
+/* Kernel API functions */
+int tspp_open_stream(u32 dev, u32 channel_id, enum tspp_source src,
+	enum tspp_tsif_mode mode);
+int tspp_close_stream(u32 dev, u32 channel_id);
+int tspp_open_channel(u32 dev, u32 channel_id);
+int tspp_close_channel(u32 dev, u32 channel_id);
+int tspp_add_filter(u32 dev, u32 channel_id,	struct tspp_filter *filter);
+int tspp_remove_filter(u32 dev, u32 channel_id,	struct tspp_filter *filter);
+int tspp_set_key(u32 dev, u32 channel_id, struct tspp_key *key);
+int tspp_register_notification(u32 dev, u32 channel, tspp_notifier *notify,
+	void *data, u32 timer_ms);
+int tspp_unregister_notification(u32 dev, u32 channel);
+const struct tspp_data_descriptor *tspp_get_buffer(u32 dev, u32 channel);
+int tspp_release_buffer(u32 dev, u32 channel, u32 descriptor_id);
+int tspp_allocate_buffers(u32 dev, u32 channel_id, u32 count,
+	u32 size, u32 int_freq, tspp_allocator *alloc, void *user);
+
 #endif /* _MSM_TSPP_H_ */
 
diff --git a/arch/arm/mach-msm/include/mach/ocmem_priv.h b/arch/arm/mach-msm/include/mach/ocmem_priv.h
index 49e283d..09dfac0 100644
--- a/arch/arm/mach-msm/include/mach/ocmem_priv.h
+++ b/arch/arm/mach-msm/include/mach/ocmem_priv.h
@@ -10,13 +10,14 @@
  * GNU General Public License for more details.
  */
 
-#ifndef _ARCH_ARM_MACH_MSM_OCMEM_CORE_H
-#define _ARCH_ARM_MACH_MSM_OCMEM_CORE_H
+#ifndef _ARCH_ARM_MACH_MSM_OCMEM_PRIV_H
+#define _ARCH_ARM_MACH_MSM_OCMEM_PRIV_H
 
 /** All interfaces in this header should only be used by OCMEM driver
  *  Client drivers should use wrappers available in ocmem.h
  **/
 #include <linux/platform_device.h>
+#include <linux/clk.h>
 #include <asm/io.h>
 #include <mach/msm_iomap.h>
 #include "ocmem.h"
@@ -35,7 +36,31 @@
 	int (*free) (struct ocmem_zone *, unsigned long, unsigned long);
 };
 
+/* OCMEM Zone specific counters */
+/* Must be in sync with zstat_names */
+enum ocmem_zstat_item {
+	NR_REQUESTS = 0x0,
+	NR_SYNC_ALLOCATIONS,
+	NR_RANGE_ALLOCATIONS,
+	NR_ASYNC_ALLOCATIONS,
+	NR_ALLOCATION_FAILS,
+	NR_GROWTHS,
+	NR_FREES,
+	NR_SHRINKS,
+	NR_MAPS,
+	NR_MAP_FAILS,
+	NR_UNMAPS,
+	NR_UNMAP_FAILS,
+	NR_TRANSFERS_TO_OCMEM,
+	NR_TRANSFERS_TO_DDR,
+	NR_TRANSFER_FAILS,
+	NR_EVICTIONS,
+	NR_RESTORES,
+	NR_OCMEM_ZSTAT_ITEMS,
+};
+
 struct ocmem_zone {
+	bool active;
 	int owner;
 	int active_regions;
 	int max_regions;
@@ -45,6 +70,7 @@
 	unsigned long z_head;
 	unsigned long z_tail;
 	unsigned long z_free;
+	atomic_long_t z_stat[NR_OCMEM_ZSTAT_ITEMS];
 	struct gen_pool *z_pool;
 	struct ocmem_zone_ops *z_ops;
 };
@@ -64,20 +90,25 @@
 
 /* Operational modes of each region */
 enum region_mode {
-	WIDE_MODE = 0x0,
+	MODE_NOT_SET = 0x0,
+	WIDE_MODE,
 	THIN_MODE,
-	MODE_DEFAULT = WIDE_MODE,
+	MODE_DEFAULT = MODE_NOT_SET,
 };
 
 struct ocmem_plat_data {
 	void __iomem *vbase;
 	unsigned long size;
 	unsigned long base;
+	struct clk *core_clk;
+	struct clk *iface_clk;
+	struct clk *br_clk;
 	struct ocmem_partition *parts;
 	int nr_parts;
 	void __iomem *reg_base;
 	void __iomem *br_base;
 	void __iomem *dm_base;
+	struct dentry *debug_node;
 	unsigned nr_regions;
 	unsigned nr_macros;
 	unsigned nr_ports;
@@ -133,51 +164,17 @@
 	struct ocmem_req *req;
 };
 
-static inline struct ocmem_buf *handle_to_buffer(struct ocmem_handle *handle)
-{
-	if (handle)
-		return &handle->buffer;
-	else
-		return NULL;
-}
-
-static inline struct ocmem_handle *buffer_to_handle(struct ocmem_buf *buffer)
-{
-	if (buffer)
-		return container_of(buffer, struct ocmem_handle, buffer);
-	else
-		return NULL;
-}
-
-static inline struct ocmem_req *handle_to_req(struct ocmem_handle *handle)
-{
-	if (handle)
-		return handle->req;
-	else
-		return NULL;
-}
-
-static inline struct ocmem_handle *req_to_handle(struct ocmem_req *req)
-{
-	if (req && req->buffer)
-		return container_of(req->buffer, struct ocmem_handle, buffer);
-	else
-		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_buf *handle_to_buffer(struct ocmem_handle *);
+struct ocmem_handle *buffer_to_handle(struct ocmem_buf *);
+struct ocmem_req *handle_to_req(struct ocmem_handle *);
+struct ocmem_handle *req_to_handle(struct ocmem_req *);
+int ocmem_read(void *);
+int ocmem_write(unsigned long, void *);
+void inc_ocmem_stat(struct ocmem_zone *, enum ocmem_zstat_item);
+unsigned long get_ocmem_stat(struct ocmem_zone *z,
+				enum ocmem_zstat_item item);
 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);
@@ -191,7 +188,7 @@
 int check_id(int);
 int dispatch_notification(int, enum ocmem_notif_type, struct ocmem_buf *);
 
-int ocmem_sched_init(void);
+int ocmem_sched_init(struct platform_device *);
 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,
@@ -203,7 +200,17 @@
 int process_shrink(int, struct ocmem_handle *, unsigned long);
 int ocmem_rdm_transfer(int, struct ocmem_map_list *,
 				unsigned long, int);
+int ocmem_clear(unsigned long, unsigned long);
 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);
+int ocmem_enable_br_clock(void);
+void ocmem_disable_core_clock(void);
+void ocmem_disable_iface_clock(void);
+void ocmem_disable_br_clock(void);
+int ocmem_lock(enum ocmem_client, unsigned long, unsigned long,
+				enum region_mode);
+int ocmem_unlock(enum ocmem_client, unsigned long, unsigned long);
 #endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/acdb_commands.h b/arch/arm/mach-msm/include/mach/qdsp5/acdb_commands.h
new file mode 100644
index 0000000..188af9f
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5/acdb_commands.h
@@ -0,0 +1,303 @@
+/* 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 _MACH_QDSP5_V2_ACDB_COMMANDS_H
+#define _MACH_QDSP5_V2_ACDB_COMMANDS_H
+
+#define ACDB_VOICE_NETWORK_ID_DEFAULT		0x00010037
+#define ACDB_INITIALISING			0
+#define ACDB_READY				1
+
+
+/* 4KB */
+#define ACDB_PAGE_SIZE				0x1000
+
+#define ACDB_CDMA_NB		0x0108b153
+#define ACDB_CDMA_WB		0x0108b154
+#define ACDB_GSM_NB		0x0108b155
+#define ACDB_GSM_WB		0x0108b156
+#define ACDB_WCDMA_NB		0x0108b157
+#define ACDB_WCDMA_WB		0x0108b158
+
+
+/* ACDB commands */
+
+
+/* struct acdb_cmd_install_device */
+#define ACDB_INSTALL_DEVICE		0x0108d245
+
+/* struct acdb_cmd_install_device */
+#define ACDB_UNINSTALL_DEVICE		0x0108d246
+
+/* struct acdb_cmd_device */
+#define ACDB_GET_DEVICE			0x0108bb92
+
+/* struct acdb_cmd_device */
+#define ACDB_SET_DEVICE			0x0108bb93
+
+/* struct acdb_cmd_get_device_table */
+#define ACDB_GET_DEVICE_TABLE		0x0108bb97
+
+/* struct acdb_cmd_get_device_capabilities */
+#define ACDB_GET_DEVICE_CAPABILITIES	0x0108f5ca
+
+/* struct acdb_cmd_get_device_info */
+#define ACDB_GET_DEVICE_INFO		0x0108f5cb
+
+/*command to intitialize ACDB based on codec type*/
+#define ACDB_CMD_INITIALIZE_FOR_ADIE	0x00011283
+
+
+/* ACDB Error codes */
+
+#define ACDB_RES_SUCCESS		0
+#define ACDB_RES_FAILURE		-1
+#define ACDB_RES_BADPARM		-2
+#define ACDB_RES_BADSTATE		-3
+
+#define TGTVERS_MSM7x30_BRING_UP	0x00010064
+
+
+
+/* Algorithm Aspect IDs */
+
+#define IID_ENABLE_FLAG			0x0108b6b9
+
+
+#define IID_ENABLE_FLAG_SIZE					1
+#define IID_ECHO_CANCELLER_VERSION_SIZE				2
+#define IID_ECHO_CANCELLER_MODE_SIZE				2
+#define IID_ECHO_CANCELLER_NOISE_SUPPRESSOR_ENABLE_SIZE		1
+#define IID_ECHO_CANCELLER_PARAMETERS_SIZE			32
+#define IID_ECHO_CANCELLER_NEXTGEN_NB_PARAMETERS_SIZE		(38 * 2)
+#define IID_ECHO_CANCELLER_NEXTGEN_WB_PARAMETERS_SIZE		(38 * 2)
+#define IID_FLUENCE_PARAMETERS_SIZE				486
+#define IID_AFE_VOLUME_CONTROL_SIZE				6
+#define IID_GAIN_SIZE						2
+#define IID_VOICE_FIR_FILTER_SIZE				14
+#define IID_VOICE_IIR_FILTER_SIZE				114
+#define IID_RX_DBM_OFFSET_SIZE					2
+#define IID_AGC_SIZE						36
+#define IID_AVC_SIZE						80
+
+#define IID_AUDIO_IIR_COEFF_SIZE				100
+#define IID_MBADRC_PARAMETERS_SIZE				8
+#define IID_MBADRC_EXT_BUFF_SIZE				392
+#define IID_MBADRC_BAND_CONFIG_SIZE				100
+#define IID_QAFX_PARAMETERS_SIZE				2
+#define IID_QCONCERT_PARAMETERS_SIZE				2
+#define IID_AUDIO_AGC_PARAMETERS_SIZE				42
+#define IID_NS_PARAMETERS_SIZE					14
+
+#define IID_ECHO_CANCELLER_VERSION			0x00010042
+#define IID_ECHO_CANCELLER_MODE				0x00010043
+#define IID_ECHO_CANCELLER_NOISE_SUPPRESSOR_ENABLE	0x00010044
+#define IID_ECHO_CANCELLER_PARAMETERS			0x00010045
+#define IID_ECHO_CANCELLER_NEXTGEN_NB_PARAMETERS	0x00010046
+#define IID_ECHO_CANCELLER_NEXTGEN_WB_PARAMETERS	0x00010047
+#define IID_FLUENCE_PARAMETERS				0x00010048
+#define IID_AFE_VOLUME_CONTROL				0x00010049
+#define IID_GAIN					0x0001004A
+#define IID_VOICE_FIR_FILTER				0x0001004B
+#define IID_VOICE_IIR_FILTER				0x0001004C
+#define IID_AGC						0x0001004E
+#define IID_AVC						0x0001004F
+#define ABID_SIDETONE_GAIN				0x00010050
+#define ABID_TX_VOICE_GAIN				0x00010051
+#define ABID_TX_DTMF_GAIN				0x00010052
+#define ABID_CODEC_TX_GAIN				0x00010053
+#define ABID_HSSD					0x00010054
+#define ABID_TX_AGC					0x00010055
+#define ABID_TX_VOICE_FIR				0x00010056
+#define ABID_TX_VOICE_IIR				0x00010057
+#define ABID_ECHO_CANCELLER				0x00010058
+#define ABID_ECHO_CANCELLER_NB_LVHF			0x00010059
+#define ABID_ECHO_CANCELLER_WB_LVHF			0x0001005A
+#define ABID_FLUENCE					0x0001005B
+#define ABID_CODEC_RX_GAIN				0x0001005C
+#define ABID_RX_DBM_OFFSET				0x0001005D
+#define ABID_RX_AGC					0x0001005E
+#define ABID_AVC					0x0001005F
+#define ABID_RX_VOICE_FIR				0x00010060
+#define ABID_RX_VOICE_IIR				0x00010061
+#define ABID_AFE_VOL_CTRL				0x00010067
+
+
+/* AUDIO IDs */
+#define ABID_AUDIO_AGC_TX		0x00010068
+#define ABID_AUDIO_NS_TX		0x00010069
+#define ABID_VOICE_NS			0x0001006A
+#define ABID_AUDIO_IIR_TX		0x0001006B
+#define ABID_AUDIO_IIR_RX		0x0001006C
+#define ABID_AUDIO_MBADRC_RX		0x0001006E
+#define ABID_AUDIO_QAFX_RX		0x0001006F
+#define ABID_AUDIO_QCONCERT_RX		0x00010070
+#define ABID_AUDIO_STF_RX		0x00010071
+#define ABID_AUDIO_CALIBRATION_GAIN_RX  0x00011162
+#define ABID_AUDIO_CALIBRATION_GAIN_TX  0x00011149
+#define ABID_AUDIO_PBE_RX               0x00011197
+#define ABID_AUDIO_RMC_TX		0x00011226
+#define ABID_AUDIO_FLUENCE_TX		0x00011244
+
+
+#define IID_AUDIO_AGC_PARAMETERS	0x0001007E
+#define IID_NS_PARAMETERS		0x00010072
+#define IID_AUDIO_IIR_COEFF		0x00010073
+#define IID_MBADRC_EXT_BUFF		0x00010075
+#define IID_MBADRC_BAND_CONFIG		0x00010076
+#define IID_MBADRC_PARAMETERS		0x00010077
+#define IID_QAFX_PARAMETERS		0x00010079
+#define IID_QCONCERT_PARAMETERS		0x0001007A
+#define IID_STF_COEFF			0x0001007B
+#define IID_AUDIO_CALIBRATION_GAIN_RX   0x00011163
+#define IID_AUDIO_CALIBRATION_GAIN_TX   0x00011171
+#define IID_PBE_CONFIG_PARAMETERS       0x00011198
+#define IID_AUDIO_PBE_RX_ENABLE_FLAG    0x00011199
+#define IID_AUDIO_RMC_PARAM		0x00011227
+#define IID_AUDIO_FLUENCE_TX		0x00011245
+
+
+#define TOPID_RX_TOPOLOGY_1		0x00010062
+#define TOPID_TX_TOPOLOGY_1		0x00010063
+#define AFERID_INT_SINK			0x00010065
+#define AFERID_INT_SOURCE		0x00010066
+#define AFERID_NO_SINK			0x00000000
+#define AFERID_NULL_SINK		0x0108ea92
+
+
+struct acdb_cmd_install_device {
+	u32	command_id;
+	u32	device_id;
+	u32	topology_id;
+	u32	afe_routing_id;
+	u32	cad_routing_id;		/* see "Sample Rate Bit Mask" below */
+	u32	sample_rate_mask;
+
+	/* represents device direction: Tx, Rx (aux pga - loopback) */
+	u8	device_type;
+	u8	channel_config;		/* Mono or Stereo */
+	u32	adie_codec_path_id;
+};
+
+
+struct acdb_cmd_get_device_capabilities {
+	u32	command_id;
+	u32	total_bytes;	/* Length in bytes allocated for buffer */
+	u32	*phys_buf;	/* Physical Address of data */
+};
+
+
+struct acdb_cmd_get_device_info {
+	u32	command_id;
+	u32	device_id;
+	u32	total_bytes;	/* Length in bytes allocated for buffer */
+	u32	*phys_buf;	/* Physical Address of data */
+};
+
+struct acdb_cmd_device {
+	u32	command_id;
+	u32	device_id;
+	u32	network_id;
+	u32	sample_rate_id;		/* Actual sample rate value */
+	u32	interface_id;		/* See interface id's above */
+	u32	algorithm_block_id;	/* See enumerations above */
+	u32	total_bytes;		/* Length in bytes used by buffer */
+	u32	*phys_buf;		/* Physical Address of data */
+};
+
+struct acdb_cmd_get_device_table {
+	u32	command_id;
+	u32	device_id;
+	u32	network_id;
+	u32	sample_rate_id;		/* Actual sample rate value */
+	u32	total_bytes;		/* Length in bytes used by buffer */
+	u32	*phys_buf;		/* Physical Address of data */
+};
+
+struct acdb_result {
+	/* This field is populated in response to the */
+	/* ACDB_GET_DEVICE_CAPABILITIES command and indicates the total */
+	/* devices whose capabilities are copied to the physical memory. */
+	u32	total_devices;
+	u32	*buf;			/* Physical Address of data */
+	u32	used_bytes;		/* The size in bytes of the data */
+	u32	result;			/* See ACDB Error codes above */
+};
+
+struct acdb_device_capability {
+	u32	device_id;
+	u32	sample_rate_mask;	/* See "Sample Rate Bit Mask" below */
+};
+
+struct acdb_dev_info {
+	u32	cad_routing_id;
+	u32	sample_rate_mask;	/* See "Sample Rate Bit Mask" below */
+	u32	adsp_device_id;		/* QDSP6 device ID */
+	u32	device_type;		/* Tx, Rx  (aux pga - loopback) */
+	u32	channel_config;		/* Mono or Stereo */
+	s32	min_volume;		/* Min volume (mB) */
+	s32	max_volume;		/* Max volume (mB) */
+};
+
+/*structure is used to intialize ACDB software on modem
+based on adie type detected*/
+struct acdb_cmd_init_adie {
+	u32 command_id;
+	u32 adie_type;
+};
+
+#define ACDB_CURRENT_ADIE_MODE_UNKNOWN 0
+#define ACDB_CURRENT_ADIE_MODE_TIMPANI 1
+#define ACDB_CURRENT_ADIE_MODE_MARIMBA 2
+
+/* Sample Rate Bit Mask */
+
+/* AUX PGA devices will have a sample rate mask of 0xFFFFFFFF */
+/* 8kHz              0x00000001 */
+/* 11.025kHz         0x00000002 */
+/* 12kHz             0x00000004 */
+/* 16kHz             0x00000008 */
+/* 22.5kHz           0x00000010 */
+/* 24kHz             0x00000020 */
+/* 32kHz             0x00000040 */
+/* 44.1kHz           0x00000080 */
+/* 48kHz             0x00000100 */
+
+
+/* Device type enumeration */
+enum {
+	RX_DEVICE = 1,
+	TX_DEVICE,
+	AUXPGA_DEVICE,
+	DEVICE_TYPE_MAX
+};
+
+#ifdef CONFIG_DEBUG_FS
+/*These are ABID used for RTC*/
+#define ABID_AUDIO_RTC_MBADRC_RX 0x0001118A
+#define ABID_AUDIO_RTC_VOLUME_PAN_RX 0x0001118C
+#define ABID_AUDIO_RTC_SPA 0x0001118E
+#define ABID_AUDIO_RTC_EQUALIZER_PARAMETERS 0x0001119F
+
+/*These are IID used for RTC*/
+#define IID_AUDIO_RTC_MBADRC_PARAMETERS 0x0001118B
+#define IID_AUDIO_RTC_VOLUME_PAN_PARAMETERS 0x0001118D
+#define IID_AUDIO_RTC_SPA_PARAMETERS 0x0001118F
+#define IID_AUDIO_RTC_EQUALIZER_PARAMETERS 0x0001119E
+#define IID_AUDIO_RTC_AGC_PARAMETERS 0x000111A7
+#define IID_AUDIO_RTC_TX_IIR_COEFF 0x000111A8
+
+#endif
+
+
+#endif
+
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/audio_acdb_def.h b/arch/arm/mach-msm/include/mach/qdsp5/audio_acdb_def.h
new file mode 100644
index 0000000..e1fc0cd
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5/audio_acdb_def.h
@@ -0,0 +1,51 @@
+/* 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 _MACH_QDSP5_V2_AUDIO_ACDB_DEF_H
+#define _MACH_QDSP5_V2_AUDIO_ACDB_DEF_H
+
+/* Define ACDB device ID */
+#define ACDB_ID_HANDSET_SPKR				1
+#define ACDB_ID_HANDSET_MIC				2
+#define ACDB_ID_HEADSET_MIC				3
+#define ACDB_ID_HEADSET_SPKR_MONO			4
+#define ACDB_ID_HEADSET_SPKR_STEREO			5
+#define ACDB_ID_SPKR_PHONE_MIC				6
+#define ACDB_ID_SPKR_PHONE_MONO				7
+#define ACDB_ID_SPKR_PHONE_STEREO			8
+#define ACDB_ID_BT_SCO_MIC				9
+#define ACDB_ID_BT_SCO_SPKR				0x0A
+#define ACDB_ID_BT_A2DP_SPKR				0x0B
+#define ACDB_ID_BT_A2DP_TX				0x10
+#define ACDB_ID_TTY_HEADSET_MIC				0x0C
+#define ACDB_ID_TTY_HEADSET_SPKR			0x0D
+#define ACDB_ID_HEADSET_MONO_PLUS_SPKR_MONO_RX		0x11
+#define ACDB_ID_HEADSET_STEREO_PLUS_SPKR_STEREO_RX	0x14
+#define ACDB_ID_FM_TX_LOOPBACK				0x17
+#define ACDB_ID_FM_TX					0x18
+#define ACDB_ID_LP_FM_SPKR_PHONE_STEREO_RX		0x19
+#define ACDB_ID_LP_FM_HEADSET_SPKR_STEREO_RX		0x1A
+#define ACDB_ID_I2S_RX					0x20
+#define ACDB_ID_SPKR_PHONE_MIC_BROADSIDE		0x2B
+#define ACDB_ID_HANDSET_MIC_BROADSIDE			0x2C
+#define ACDB_ID_SPKR_PHONE_MIC_ENDFIRE			0x2D
+#define ACDB_ID_HANDSET_MIC_ENDFIRE			0x2E
+#define ACDB_ID_I2S_TX					0x30
+#define ACDB_ID_HDMI					0x40
+#define ACDB_ID_FM_RX					0x4F
+/*Replace the max device ID,if any new device is added Specific to RTC only*/
+#define ACDB_ID_MAX                                 ACDB_ID_FM_RX
+
+/* ID used for virtual devices */
+#define PSEUDO_ACDB_ID					0xFFFF
+
+#endif /* _MACH_QDSP5_V2_AUDIO_ACDB_DEF_H */
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/audio_acdbi.h b/arch/arm/mach-msm/include/mach/qdsp5/audio_acdbi.h
new file mode 100644
index 0000000..5bad4fa
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5/audio_acdbi.h
@@ -0,0 +1,132 @@
+/* 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 _MACH_QDSP5_V2_AUDIO_ACDBI_H
+#define _MACH_QDSP5_V2_AUDIO_ACDBI_H
+
+#define DBOR_SIGNATURE	0x524F4244
+
+void acdb_rtc_set_err(u32 err_code);
+
+
+struct header {
+	u32 dbor_signature;
+	u32 abid;
+	u32 iid;
+	u32 data_len;
+};
+
+enum {
+	ACDB_AGC_BLOCK			= 197,
+	ACDB_IIR_BLOCK			= 245,
+	ACDB_MBADRC_BLOCK		= 343
+};
+
+/* Structure to query for acdb parameter */
+struct acdb_get_block {
+	u32	acdb_id;
+	u32	sample_rate_id;		/* Actual sample rate value */
+	u32	interface_id;		/* Interface id's */
+	u32	algorithm_block_id;	/* Algorithm block id */
+	u32	total_bytes;		/* Length in bytes used by buffer for
+						configuration */
+	u32	*buf_ptr;		/* Address for storing configuration
+						data */
+};
+
+struct acdb_agc_block {
+	u16	enable_status;
+	u16	comp_rlink_static_gain;
+	u16	comp_rlink_aig_flag;
+	u16	exp_rlink_threshold;
+	u16	exp_rlink_slope;
+	u16	comp_rlink_threshold;
+	u16	comp_rlink_slope;
+	u16	comp_rlink_aig_attack_k;
+	u16	comp_rlink_aig_leak_down;
+	u16	comp_rlink_aig_leak_up;
+	u16	comp_rlink_aig_max;
+	u16	comp_rlink_aig_min;
+	u16	comp_rlink_aig_release_k;
+	u16	comp_rlink_aig_sm_leak_rate_fast;
+	u16	comp_rlink_aig_sm_leak_rate_slow;
+	u16	comp_rlink_attack_k_msw;
+	u16	comp_rlink_attack_k_lsw;
+	u16	comp_rlink_delay;
+	u16	comp_rlink_release_k_msw;
+	u16	comp_rlink_release_k_lsw;
+	u16	comp_rlink_rms_trav;
+};
+
+
+struct iir_coeff_type {
+	u16	b0_lo;
+	u16	b0_hi;
+	u16	b1_lo;
+	u16	b1_hi;
+	u16	b2_lo;
+	u16	b2_hi;
+};
+
+struct iir_coeff_stage_a {
+	u16	a1_lo;
+	u16	a1_hi;
+	u16	a2_lo;
+	u16	a2_hi;
+};
+
+struct acdb_iir_block {
+	u16			enable_flag;
+	u16			stage_count;
+	struct iir_coeff_type	stages[4];
+	struct iir_coeff_stage_a stages_a[4];
+	u16			shift_factor[4];
+	u16			pan[4];
+};
+
+struct mbadrc_band_config_type {
+	u16	mbadrc_sub_band_enable;
+	u16	mbadrc_sub_mute;
+	u16	mbadrc_comp_rms_tav;
+	u16	mbadrc_comp_threshold;
+	u16	mbadrc_comp_slop;
+	u16	mbadrc_comp_attack_msw;
+	u16	mbadrc_comp_attack_lsw;
+	u16	mbadrc_comp_release_msw;
+	u16	mbadrc_comp_release_lsw;
+	u16	mbadrc_make_up_gain;
+};
+
+struct mbadrc_parameter {
+	u16				mbadrc_enable;
+	u16				mbadrc_num_bands;
+	u16				mbadrc_down_sample_level;
+	u16				mbadrc_delay;
+};
+
+struct acdb_mbadrc_block {
+	u16				ext_buf[196];
+	struct mbadrc_band_config_type	band_config[5];
+	struct mbadrc_parameter		parameters;
+};
+
+struct acdb_ns_tx_block {
+	unsigned short	ec_mode_new;
+	unsigned short	dens_gamma_n;
+	unsigned short	dens_nfe_block_size;
+	unsigned short	dens_limit_ns;
+	unsigned short	dens_limit_ns_d;
+	unsigned short	wb_gamma_e;
+	unsigned short	wb_gamma_n;
+};
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audpp.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audpp.h
new file mode 100644
index 0000000..bbd82a0
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audpp.h
@@ -0,0 +1,93 @@
+/*arch/arm/mach-msm/qdsp5audpp.h
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+*/
+
+#ifndef _MACH_QDSP5_AUDPP_H
+#define _MACH_QDSP5_AUDPP_H
+
+#include <mach/qdsp5/qdsp5audppcmdi.h>
+
+typedef void (*audpp_event_func)(void *private, unsigned id, uint16_t *msg);
+
+/* worst case delay of 1sec for response */
+#define MSM_AUD_DECODER_WAIT_MS 1000
+#define MSM_AUD_MODE_TUNNEL  0x00000100
+#define MSM_AUD_MODE_NONTUNNEL  0x00000200
+#define MSM_AUD_DECODER_MASK  0x0000FFFF
+#define MSM_AUD_OP_MASK  0xFFFF0000
+
+/*Playback mode*/
+#define NON_TUNNEL_MODE_PLAYBACK 1
+#define TUNNEL_MODE_PLAYBACK 0
+
+enum msm_aud_decoder_state {
+	MSM_AUD_DECODER_STATE_NONE = 0,
+	MSM_AUD_DECODER_STATE_FAILURE = 1,
+	MSM_AUD_DECODER_STATE_SUCCESS = 2,
+	MSM_AUD_DECODER_STATE_CLOSE = 3,
+};
+
+int audpp_adec_alloc(unsigned dec_attrb, const char **module_name,
+			unsigned *queueid);
+void audpp_adec_free(int decid);
+
+struct audpp_event_callback {
+	audpp_event_func fn;
+	void *private;
+};
+
+int audpp_register_event_callback(struct audpp_event_callback *eh);
+int audpp_unregister_event_callback(struct audpp_event_callback *eh);
+int is_audpp_enable(void);
+
+int audpp_enable(int id, audpp_event_func func, void *private);
+void audpp_disable(int id, void *private);
+
+int audpp_send_queue1(void *cmd, unsigned len);
+int audpp_send_queue2(void *cmd, unsigned len);
+int audpp_send_queue3(void *cmd, unsigned len);
+
+int audpp_set_volume_and_pan(unsigned id, unsigned volume, int pan);
+int audpp_pause(unsigned id, int pause);
+int audpp_flush(unsigned id);
+void audpp_avsync(int id, unsigned rate);
+unsigned audpp_avsync_sample_count(int id);
+unsigned audpp_avsync_byte_count(int id);
+int audpp_dsp_set_mbadrc(unsigned id, unsigned enable,
+			audpp_cmd_cfg_object_params_mbadrc *mbadrc);
+int audpp_dsp_set_eq(unsigned id, unsigned enable,
+			audpp_cmd_cfg_object_params_eqalizer *eq);
+int audpp_dsp_set_rx_iir(unsigned id, unsigned enable,
+				audpp_cmd_cfg_object_params_pcm *iir);
+
+int audpp_dsp_set_rx_srs_trumedia_g
+	(struct audpp_cmd_cfg_object_params_srstm_g *srstm);
+int audpp_dsp_set_rx_srs_trumedia_w
+	(struct audpp_cmd_cfg_object_params_srstm_w *srstm);
+int audpp_dsp_set_rx_srs_trumedia_c
+	(struct audpp_cmd_cfg_object_params_srstm_c *srstm);
+int audpp_dsp_set_rx_srs_trumedia_h
+	(struct audpp_cmd_cfg_object_params_srstm_h *srstm);
+int audpp_dsp_set_rx_srs_trumedia_p
+	(struct audpp_cmd_cfg_object_params_srstm_p *srstm);
+int audpp_dsp_set_rx_srs_trumedia_l
+	(struct audpp_cmd_cfg_object_params_srstm_l *srstm);
+
+int audpp_dsp_set_vol_pan(unsigned id,
+				audpp_cmd_cfg_object_params_volume *vol_pan);
+int audpp_dsp_set_qconcert_plus(unsigned id, unsigned enable,
+			audpp_cmd_cfg_object_params_qconcert *qconcert_plus);
+
+#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..de30c65 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
  */
 
@@ -517,6 +530,18 @@
   unsigned short  arm_to_dsp_buf_len;
 } __attribute__((packed)) audpp_cmd_pcm_intf_send_buffer;
 
+#define AUDPP_CMD_PP_FEAT_QUERY_PARAMS  0x0003
+
+struct rtc_audpp_read_data {
+	unsigned short  cmd_id;
+	unsigned short  obj_id;
+	unsigned short  feature_id;
+	unsigned short  extbufsizemsw;
+	unsigned short  extbufsizelsw;
+	unsigned short	extpart;
+	unsigned short	extbufstartmsw;
+	unsigned short	extbufstartlsw;
+} __packed ;
 
 /*
  * Commands Related to uPAudPPCmd3Queue
@@ -551,6 +576,8 @@
 #define AUDPP_CMD_COMMON_CFG_UPDATE		0x8000
 #define AUDPP_CMD_COMMON_CFG_DONT_UPDATE	0x0000
 
+#define AUDPP_CMD_COPP_STREAM   0x0006
+
 typedef struct {
 	unsigned short  cmd_id;
 	unsigned short	obj0_cfg;
@@ -567,6 +594,7 @@
  * Command Structure to configure post processing params (Volume)
  */
 
+#define AUDPP_CMD_VOLUME_PAN		0
 #define AUDPP_CMD_CFG_OBJECT_PARAMS_VOLUME_LEN		\
 	sizeof(audpp_cmd_cfg_object_params_volume)
 
@@ -632,6 +660,7 @@
 		pan			pan_filter[4];
 } __attribute__((packed)) filter_4;
 
+#define AUDPP_CMD_IIR_TUNING_FILTER	1
 #define AUDPP_CMD_CFG_OBJECT_PARAMS_PCM_LEN		\
 	sizeof(audpp_cmd_cfg_object_params_pcm)
 
@@ -653,6 +682,7 @@
  * Command Structure to configure post processing parameters (equalizer) 
  */
 
+#define AUDPP_CMD_EQUALIZER		2
 #define AUDPP_CMD_CFG_OBJECT_PARAMS_EQALIZER_LEN		\
 	sizeof(audpp_cmd_cfg_object_params_eqalizer)
 
@@ -774,6 +804,7 @@
  * Command Structure to configure post processing parameters (ADRC) 
  */
 
+#define AUDPP_CMD_ADRC			3
 #define AUDPP_CMD_CFG_OBJECT_PARAMS_ADRC_LEN		\
 	sizeof(audpp_cmd_cfg_object_params_adrc)
 
@@ -781,6 +812,7 @@
 #define AUDPP_CMD_ADRC_FLAG_DIS		0x0000
 #define AUDPP_CMD_ADRC_FLAG_ENA		-1
 
+#define AUDPP_CMD_MBADRC		10
 #define	AUDPP_MAX_MBADRC_BANDS		5
 #define	AUDPP_MBADRC_EXTERNAL_BUF_SIZE	196
 
@@ -826,6 +858,7 @@
  * Command Structure to configure post processing parameters(Spectrum Analizer)
  */
 
+#define AUDPP_CMD_SPECTROGRAM		4
 #define AUDPP_CMD_CFG_OBJECT_PARAMS_SPECTRAM_LEN		\
 	sizeof(audpp_cmd_cfg_object_params_spectram)
 
@@ -840,6 +873,7 @@
  * Command Structure to configure post processing parameters (QConcert) 
  */
 
+#define AUDPP_CMD_QCONCERT		5
 #define AUDPP_CMD_CFG_OBJECT_PARAMS_QCONCERT_LEN		\
 	sizeof(audpp_cmd_cfg_object_params_qconcert)
 
@@ -886,6 +920,7 @@
  * Command Structure to configure post processing parameters (Side Chain) 
  */
 
+#define AUDPP_CMD_SIDECHAIN_TUNING_FILTER	6
 #define AUDPP_CMD_CFG_OBJECT_PARAMS_SIDECHAIN_LEN		\
 	sizeof(audpp_cmd_cfg_object_params_sidechain)
 
@@ -910,6 +945,7 @@
  * Command Structure to configure post processing parameters (QAFX)
  */
 
+#define AUDPP_CMD_QAFX			8
 #define AUDPP_CMD_CFG_OBJECT_PARAMS_QAFX_LEN		\
 	sizeof(audpp_cmd_cfg_object_params_qafx)
 
@@ -1033,6 +1069,8 @@
 	audpp_cmd_cfg_object_params_common	common;
 	unsigned short				v[SRS_PARAMS_MAX_L];
 } __packed;
+#define AUDPP_CMD_SAMPLING_FREQUENCY	7
+#define AUDPP_CMD_QRUMBLE		9
 
 #endif /* QDSP5AUDPPCMDI_H */
 
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audppmsg.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audppmsg.h
index 0ba8261..fef4c35 100644
--- a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audppmsg.h
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audppmsg.h
@@ -2,29 +2,29 @@
 #define QDSP5AUDPPMSG_H
 
 /*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
-
-       Q D S P 5  A U D I O   P O S T   P R O C E S S I N G   M S G
-
-GENERAL DESCRIPTION
-  Messages sent by AUDPPTASK to ARM 
-
-REFERENCES
-  None
-
-EXTERNALIZED FUNCTIONS
-  None  
-  
-Copyright (c) 1992-2009, Code Aurora Forum. All rights reserved.
-
-This software is licensed under the terms of the GNU General Public
-License version 2, as published by the Free Software Foundation, and
-may be copied, distributed, and modified under those terms.
- 
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
+*
+*       Q D S P 5  A U D I O   P O S T   P R O C E S S I N G   M S G
+*
+* GENERAL DESCRIPTION
+*   Messages sent by AUDPPTASK to ARM
+*
+* REFERENCES
+*   None
+*
+* EXTERNALIZED FUNCTIONS
+*   None
+*
+* Copyright (c) 1992-2009, 2012 Code Aurora Forum. All rights reserved.
+*
+* This software is licensed under the terms of the GNU General Public
+* License version 2, as published by the Free Software Foundation, and
+* may be copied, distributed, and modified under those terms.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
 *====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
 /*===========================================================================
 
@@ -318,4 +318,5 @@
 
 #define ADSP_MESSAGE_ID 0xFFFF
 
+#define AUDPP_MSG_FEAT_QUERY_DM_DONE 0x000b
 #endif /* QDSP5AUDPPMSG_H */
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audpreproc.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audpreproc.h
index 234c4ac..5c7c5dc 100644
--- a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audpreproc.h
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audpreproc.h
@@ -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
@@ -25,9 +25,49 @@
 #define MSM_ADSP_ENC_MODE_TUNNEL 24
 #define MSM_ADSP_ENC_MODE_NON_TUNNEL 25
 
+/* event callback routine prototype*/
+typedef void (*audpreproc_event_func)(void *private, unsigned id, void *msg);
+
+struct audpreproc_event_callback {
+	audpreproc_event_func fn;
+	void *private;
+};
+
+/*holds audrec information*/
+struct audrec_session_info {
+	int session_id;
+	int sampling_freq;
+};
+
 /* Exported common api's from audpreproc layer */
 int audpreproc_aenc_alloc(unsigned enc_type, const char **module_name,
 		unsigned *queue_id);
 void audpreproc_aenc_free(int enc_id);
 
+int audpreproc_enable(int enc_id, audpreproc_event_func func, void *private);
+void audpreproc_disable(int enc_id, void *private);
+
+int audpreproc_unregister_event_callback(struct audpreproc_event_callback *ecb);
+
+int audpreproc_register_event_callback(struct audpreproc_event_callback *ecb);
+
+int audpreproc_update_audrec_info(struct audrec_session_info
+						*audrec_session_info);
+int get_audrec_session_info(struct audrec_session_info *info);
+
+int audpreproc_dsp_set_agc(audpreproc_cmd_cfg_agc_params *agc,
+	unsigned len);
+int audpreproc_dsp_set_ns(audpreproc_cmd_cfg_ns_params *ns,
+	unsigned len);
+int audpreproc_dsp_set_iir(audpreproc_cmd_cfg_iir_tuning_filter_params *iir,
+	unsigned len);
+
+int audpreproc_send_preproccmdqueue(void *cmd, unsigned len);
+typedef void (*audrec_event_func)(void *private, unsigned id, uint16_t *msg);
+int audrectask_enable(unsigned enc_type, audrec_event_func func, void *private);
+void audrectask_disable(unsigned enc_type, void *private);
+
+int audrectask_send_cmdqueue(void *cmd, unsigned len);
+int audrectask_send_bitstreamqueue(void *cmd, unsigned len);
+
 #endif /* QDSP5AUDPREPROC_H */
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audpreproccmdi.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audpreproccmdi.h
index 8efc916..a38d224 100644
--- a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audpreproccmdi.h
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audpreproccmdi.h
@@ -2,30 +2,30 @@
 #define QDSP5AUDPREPROCCMDI_H
 
 /*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
-
-    A U D I O   P R E   P R O C E S S I N G  I N T E R N A L  C O M M A N D S
-
-GENERAL DESCRIPTION
-  This file contains defintions of format blocks of commands 
-  that are accepted by AUDPREPROC Task
-
-REFERENCES
-  None
-
-EXTERNALIZED FUNCTIONS
-  None
-
-Copyright (c) 1992-2009, Code Aurora Forum. All rights reserved.
-
-This software is licensed under the terms of the GNU General Public
-License version 2, as published by the Free Software Foundation, and
-may be copied, distributed, and modified under those terms.
- 
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
+*
+*    A U D I O   P R E   P R O C E S S I N G  I N T E R N A L  C O M M A N D S
+*
+* GENERAL DESCRIPTION
+*   This file contains defintions of format blocks of commands
+*   that are accepted by AUDPREPROC Task
+*
+* REFERENCES
+*   None
+*
+* EXTERNALIZED FUNCTIONS
+*   None
+*
+* Copyright (c) 1992-2009, 2012 Code Aurora Forum. All rights reserved.
+*
+* This software is licensed under the terms of the GNU General Public
+* License version 2, as published by the Free Software Foundation, and
+* may be copied, distributed, and modified under those terms.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
 *====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
 /*===========================================================================
 
@@ -84,29 +84,29 @@
 typedef struct {
 	unsigned short	cmd_id;
 	unsigned short	tx_agc_param_mask;
-	unsigned short	tx_agc_enable_flag;
-	unsigned short	static_gain;
-	signed short	adaptive_gain_flag;
-	unsigned short	expander_th;
-	unsigned short	expander_slope;
-	unsigned short	compressor_th;
-	unsigned short	compressor_slope;
-	unsigned short	param_mask;
-	unsigned short	aig_attackk;
-	unsigned short	aig_leak_down;
-	unsigned short	aig_leak_up;
-	unsigned short	aig_max;
-	unsigned short	aig_min;
-	unsigned short	aig_releasek;
-	unsigned short	aig_leakrate_fast;
-	unsigned short	aig_leakrate_slow;
-	unsigned short	attackk_msw;
-	unsigned short	attackk_lsw;
-	unsigned short	delay;
-	unsigned short	releasek_msw;
-	unsigned short	releasek_lsw;
-	unsigned short	rms_tav;
-} __attribute__((packed)) audpreproc_cmd_cfg_agc_params;
+	signed short	tx_agc_enable_flag;
+	unsigned short	comp_rlink_static_gain;
+	signed short	comp_rlink_aig_flag;
+	unsigned short	expander_rlink_th;
+	unsigned short	expander_rlink_slope;
+	unsigned short	compressor_rlink_th;
+	unsigned short	compressor_rlink_slope;
+	unsigned short	tx_adc_agc_param_mask;
+	unsigned short	comp_rlink_aig_attackk;
+	unsigned short	comp_rlink_aig_leak_down;
+	unsigned short	comp_rlink_aig_leak_up;
+	unsigned short	comp_rlink_aig_max;
+	unsigned short	comp_rlink_aig_min;
+	unsigned short	comp_rlink_aig_releasek;
+	unsigned short	comp_rlink_aig_leakrate_fast;
+	unsigned short	comp_rlink_aig_leakrate_slow;
+	unsigned short	comp_rlink_attackk_msw;
+	unsigned short	comp_rlink_attackk_lsw;
+	unsigned short	comp_rlink_delay;
+	unsigned short	comp_rlink_releasek_msw;
+	unsigned short	comp_rlink_releasek_lsw;
+	unsigned short	comp_rlink_rms_tav;
+} __packed audpreproc_cmd_cfg_agc_params;
 
 
 /*
@@ -253,4 +253,16 @@
 	unsigned short	channel_selected3;
 } __attribute__((packed))audpreproc_cmd_cfg_iir_tuning_filter_params;
 
+#define AUDPREPROC_CMD_FEAT_QUERY_PARAMS 0x0004
+
+struct rtc_audpreproc_read_data {
+	unsigned short	cmd_id;
+	unsigned short	stream_id;
+	unsigned short  feature_id;
+	unsigned short  extbufsizemsw;
+	unsigned short  extbufsizelsw;
+	unsigned short  extpart;
+	unsigned short  extbufstartmsw;
+	unsigned short	extbufstartlsw;
+} __packed ;
 #endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audpreprocmsg.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audpreprocmsg.h
index 0696066..d299995 100644
--- a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audpreprocmsg.h
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audpreprocmsg.h
@@ -2,30 +2,30 @@
 #define QDSP5AUDPREPROCMSG_H
 
 /*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
-
-    A U D I O   P R E   P R O C E S S I N G  M E S S A G E S
-
-GENERAL DESCRIPTION
-  This file contains defintions of format blocks of messages 
-  that are rcvd by AUDPREPROC Task
-
-REFERENCES
-  None
-
-EXTERNALIZED FUNCTIONS
-  None
-
-Copyright (c) 1992-2009, Code Aurora Forum. All rights reserved.
-
-This software is licensed under the terms of the GNU General Public
-License version 2, as published by the Free Software Foundation, and
-may be copied, distributed, and modified under those terms.
- 
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
+*
+*     A U D I O   P R E   P R O C E S S I N G  M E S S A G E S
+*
+* GENERAL DESCRIPTION
+*   This file contains defintions of format blocks of messages
+*   that are rcvd by AUDPREPROC Task
+*
+* REFERENCES
+*   None
+*
+* EXTERNALIZED FUNCTIONS
+*   None
+*
+* Copyright (c) 1992-2009, 2012 Code Aurora Forum. All rights reserved.
+*
+* This software is licensed under the terms of the GNU General Public
+* License version 2, as published by the Free Software Foundation, and
+* may be copied, distributed, and modified under those terms.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
 *====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
 /*===========================================================================
 
@@ -82,4 +82,5 @@
 	 unsigned short	err_index;
 } __attribute__((packed)) audpreproc_msg_error_msg_id;
 
+#define AUDPREPROC_MSG_FEAT_QUERY_DM_DONE 0x0003
 #endif
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-8930.h b/arch/arm/mach-msm/include/mach/rpm-8930.h
index 6fd9cf4..4ac9192 100644
--- a/arch/arm/mach-msm/include/mach/rpm-8930.h
+++ b/arch/arm/mach-msm/include/mach/rpm-8930.h
@@ -59,6 +59,8 @@
 	MSM_RPM_8930_SEL_MMSS_FABRIC_CFG_CLKMOD			= 27,
 	MSM_RPM_8930_SEL_MMSS_FABRIC_CFG_IOCTL			= 28,
 	MSM_RPM_8930_SEL_MM_FABRIC_ARB				= 29,
+
+	/* PMIC 8038 */
 	MSM_RPM_8930_SEL_PM8038_S1				= 30,
 	MSM_RPM_8930_SEL_PM8038_S2				= 31,
 	MSM_RPM_8930_SEL_PM8038_S3				= 32,
@@ -96,12 +98,65 @@
 	MSM_RPM_8930_SEL_PM8038_CLK2				= 64,
 	MSM_RPM_8930_SEL_PM8038_LVS1				= 65,
 	MSM_RPM_8930_SEL_PM8038_LVS2				= 66,
+
+	/* PMIC 8917 */
+	MSM_RPM_8930_SEL_PM8917_S1				= 30,
+	MSM_RPM_8930_SEL_PM8917_S2				= 31,
+	MSM_RPM_8930_SEL_PM8917_S3				= 32,
+	MSM_RPM_8930_SEL_PM8917_S4				= 33,
+	MSM_RPM_8930_SEL_PM8917_S5				= 34,
+	MSM_RPM_8930_SEL_PM8917_S6				= 35,
+	MSM_RPM_8930_SEL_PM8917_S7				= 36,
+	MSM_RPM_8930_SEL_PM8917_S8				= 37,
+	MSM_RPM_8930_SEL_PM8917_L1				= 38,
+	MSM_RPM_8930_SEL_PM8917_L2				= 39,
+	MSM_RPM_8930_SEL_PM8917_L3				= 40,
+	MSM_RPM_8930_SEL_PM8917_L4				= 41,
+	MSM_RPM_8930_SEL_PM8917_L5				= 42,
+	MSM_RPM_8930_SEL_PM8917_L6				= 43,
+	MSM_RPM_8930_SEL_PM8917_L7				= 44,
+	MSM_RPM_8930_SEL_PM8917_L8				= 45,
+	MSM_RPM_8930_SEL_PM8917_L9				= 46,
+	MSM_RPM_8930_SEL_PM8917_L10				= 47,
+	MSM_RPM_8930_SEL_PM8917_L11				= 48,
+	MSM_RPM_8930_SEL_PM8917_L12				= 49,
+	MSM_RPM_8930_SEL_PM8917_L14				= 50,
+	MSM_RPM_8930_SEL_PM8917_L15				= 51,
+	MSM_RPM_8930_SEL_PM8917_L16				= 52,
+	MSM_RPM_8930_SEL_PM8917_L17				= 53,
+	MSM_RPM_8930_SEL_PM8917_L18				= 54,
+	MSM_RPM_8930_SEL_PM8917_L21				= 55,
+	MSM_RPM_8930_SEL_PM8917_L22				= 56,
+	MSM_RPM_8930_SEL_PM8917_L23				= 57,
+	MSM_RPM_8930_SEL_PM8917_L24				= 58,
+	MSM_RPM_8930_SEL_PM8917_L25				= 59,
+	MSM_RPM_8930_SEL_PM8917_L26				= 60,
+	MSM_RPM_8930_SEL_PM8917_L27				= 61,
+	MSM_RPM_8930_SEL_PM8917_L28				= 62,
+	MSM_RPM_8930_SEL_PM8917_L29				= 63,
+	MSM_RPM_8930_SEL_PM8917_L30				= 64,
+	MSM_RPM_8930_SEL_PM8917_L31				= 65,
+	MSM_RPM_8930_SEL_PM8917_L32				= 66,
+	MSM_RPM_8930_SEL_PM8917_L33				= 67,
+	MSM_RPM_8930_SEL_PM8917_L34				= 68,
+	MSM_RPM_8930_SEL_PM8917_L35				= 69,
+	MSM_RPM_8930_SEL_PM8917_L36				= 70,
+	MSM_RPM_8930_SEL_PM8917_CLK1				= 71,
+	MSM_RPM_8930_SEL_PM8917_CLK2				= 72,
+	MSM_RPM_8930_SEL_PM8917_LVS1				= 73,
+	MSM_RPM_8930_SEL_PM8917_LVS3				= 74,
+	MSM_RPM_8930_SEL_PM8917_LVS4				= 75,
+	MSM_RPM_8930_SEL_PM8917_LVS5				= 76,
+	MSM_RPM_8930_SEL_PM8917_LVS6				= 77,
+	MSM_RPM_8930_SEL_PM8917_LVS7				= 78,
+
 	MSM_RPM_8930_SEL_NCP					= 80,
 	MSM_RPM_8930_SEL_CXO_BUFFERS				= 81,
 	MSM_RPM_8930_SEL_USB_OTG_SWITCH				= 82,
 	MSM_RPM_8930_SEL_HDMI_SWITCH				= 83,
 	MSM_RPM_8930_SEL_DDR_DMM				= 84,
 	MSM_RPM_8930_SEL_VOLTAGE_CORNER				= 87,
+
 	MSM_RPM_8930_SEL_LAST = MSM_RPM_8930_SEL_VOLTAGE_CORNER,
 };
 
@@ -163,6 +218,7 @@
 	MSM_RPM_8930_ID_MM_FABRIC_ARB_10 =
 		MSM_RPM_8930_ID_MM_FABRIC_ARB_0	+ 10,
 
+	/* PMIC 8038 */
 	MSM_RPM_8930_ID_PM8038_S1_0	= 90,
 	MSM_RPM_8930_ID_PM8038_S1_1	= 91,
 	MSM_RPM_8930_ID_PM8038_S2_0	= 92,
@@ -235,13 +291,109 @@
 	MSM_RPM_8930_ID_PM8038_CLK2_1	= 159,
 	MSM_RPM_8930_ID_PM8038_LVS1	= 160,
 	MSM_RPM_8930_ID_PM8038_LVS2	= 161,
-	MSM_RPM_8930_ID_NCP_0	= 162,
-	MSM_RPM_8930_ID_NCP_1	= 163,
-	MSM_RPM_8930_ID_CXO_BUFFERS	= 164,
-	MSM_RPM_8930_ID_USB_OTG_SWITCH	= 165,
-	MSM_RPM_8930_ID_HDMI_SWITCH	= 166,
-	MSM_RPM_8930_ID_QDSS_CLK	= 167,
-	MSM_RPM_8930_ID_VOLTAGE_CORNER	= 168,
+
+	/* PMIC 8917 */
+	MSM_RPM_8930_ID_PM8917_S1_0	= 90,
+	MSM_RPM_8930_ID_PM8917_S1_1	= 91,
+	MSM_RPM_8930_ID_PM8917_S2_0	= 92,
+	MSM_RPM_8930_ID_PM8917_S2_1	= 93,
+	MSM_RPM_8930_ID_PM8917_S3_0	= 94,
+	MSM_RPM_8930_ID_PM8917_S3_1	= 95,
+	MSM_RPM_8930_ID_PM8917_S4_0	= 96,
+	MSM_RPM_8930_ID_PM8917_S4_1	= 97,
+	MSM_RPM_8930_ID_PM8917_S5_0	= 98,
+	MSM_RPM_8930_ID_PM8917_S5_1	= 99,
+	MSM_RPM_8930_ID_PM8917_S6_0	= 100,
+	MSM_RPM_8930_ID_PM8917_S6_1	= 101,
+	MSM_RPM_8930_ID_PM8917_S7_0	= 102,
+	MSM_RPM_8930_ID_PM8917_S7_1	= 103,
+	MSM_RPM_8930_ID_PM8917_S8_0	= 104,
+	MSM_RPM_8930_ID_PM8917_S8_1	= 105,
+	MSM_RPM_8930_ID_PM8917_L1_0	= 106,
+	MSM_RPM_8930_ID_PM8917_L1_1	= 107,
+	MSM_RPM_8930_ID_PM8917_L2_0	= 108,
+	MSM_RPM_8930_ID_PM8917_L2_1	= 109,
+	MSM_RPM_8930_ID_PM8917_L3_0	= 110,
+	MSM_RPM_8930_ID_PM8917_L3_1	= 111,
+	MSM_RPM_8930_ID_PM8917_L4_0	= 112,
+	MSM_RPM_8930_ID_PM8917_L4_1	= 113,
+	MSM_RPM_8930_ID_PM8917_L5_0	= 114,
+	MSM_RPM_8930_ID_PM8917_L5_1	= 115,
+	MSM_RPM_8930_ID_PM8917_L6_0	= 116,
+	MSM_RPM_8930_ID_PM8917_L6_1	= 117,
+	MSM_RPM_8930_ID_PM8917_L7_0	= 118,
+	MSM_RPM_8930_ID_PM8917_L7_1	= 119,
+	MSM_RPM_8930_ID_PM8917_L8_0	= 120,
+	MSM_RPM_8930_ID_PM8917_L8_1	= 121,
+	MSM_RPM_8930_ID_PM8917_L9_0	= 122,
+	MSM_RPM_8930_ID_PM8917_L9_1	= 123,
+	MSM_RPM_8930_ID_PM8917_L10_0	= 124,
+	MSM_RPM_8930_ID_PM8917_L10_1	= 125,
+	MSM_RPM_8930_ID_PM8917_L11_0	= 126,
+	MSM_RPM_8930_ID_PM8917_L11_1	= 127,
+	MSM_RPM_8930_ID_PM8917_L12_0	= 128,
+	MSM_RPM_8930_ID_PM8917_L12_1	= 129,
+	MSM_RPM_8930_ID_PM8917_L14_0	= 130,
+	MSM_RPM_8930_ID_PM8917_L14_1	= 131,
+	MSM_RPM_8930_ID_PM8917_L15_0	= 132,
+	MSM_RPM_8930_ID_PM8917_L15_1	= 133,
+	MSM_RPM_8930_ID_PM8917_L16_0	= 134,
+	MSM_RPM_8930_ID_PM8917_L16_1	= 135,
+	MSM_RPM_8930_ID_PM8917_L17_0	= 136,
+	MSM_RPM_8930_ID_PM8917_L17_1	= 137,
+	MSM_RPM_8930_ID_PM8917_L18_0	= 138,
+	MSM_RPM_8930_ID_PM8917_L18_1	= 139,
+	MSM_RPM_8930_ID_PM8917_L21_0	= 140,
+	MSM_RPM_8930_ID_PM8917_L21_1	= 141,
+	MSM_RPM_8930_ID_PM8917_L22_0	= 142,
+	MSM_RPM_8930_ID_PM8917_L22_1	= 143,
+	MSM_RPM_8930_ID_PM8917_L23_0	= 144,
+	MSM_RPM_8930_ID_PM8917_L23_1	= 145,
+	MSM_RPM_8930_ID_PM8917_L24_0	= 146,
+	MSM_RPM_8930_ID_PM8917_L24_1	= 147,
+	MSM_RPM_8930_ID_PM8917_L25_0	= 148,
+	MSM_RPM_8930_ID_PM8917_L25_1	= 149,
+	MSM_RPM_8930_ID_PM8917_L26_0	= 150,
+	MSM_RPM_8930_ID_PM8917_L26_1	= 151,
+	MSM_RPM_8930_ID_PM8917_L27_0	= 152,
+	MSM_RPM_8930_ID_PM8917_L27_1	= 153,
+	MSM_RPM_8930_ID_PM8917_L28_0	= 154,
+	MSM_RPM_8930_ID_PM8917_L28_1	= 155,
+	MSM_RPM_8930_ID_PM8917_L29_0	= 156,
+	MSM_RPM_8930_ID_PM8917_L29_1	= 157,
+	MSM_RPM_8930_ID_PM8917_L30_0	= 158,
+	MSM_RPM_8930_ID_PM8917_L30_1	= 159,
+	MSM_RPM_8930_ID_PM8917_L31_0	= 160,
+	MSM_RPM_8930_ID_PM8917_L31_1	= 161,
+	MSM_RPM_8930_ID_PM8917_L32_0	= 162,
+	MSM_RPM_8930_ID_PM8917_L32_1	= 163,
+	MSM_RPM_8930_ID_PM8917_L33_0	= 164,
+	MSM_RPM_8930_ID_PM8917_L33_1	= 165,
+	MSM_RPM_8930_ID_PM8917_L34_0	= 166,
+	MSM_RPM_8930_ID_PM8917_L34_1	= 167,
+	MSM_RPM_8930_ID_PM8917_L35_0	= 168,
+	MSM_RPM_8930_ID_PM8917_L35_1	= 169,
+	MSM_RPM_8930_ID_PM8917_L36_0	= 170,
+	MSM_RPM_8930_ID_PM8917_L36_1	= 171,
+	MSM_RPM_8930_ID_PM8917_CLK1_0	= 172,
+	MSM_RPM_8930_ID_PM8917_CLK1_1	= 173,
+	MSM_RPM_8930_ID_PM8917_CLK2_0	= 174,
+	MSM_RPM_8930_ID_PM8917_CLK2_1	= 175,
+	MSM_RPM_8930_ID_PM8917_LVS1	= 176,
+	MSM_RPM_8930_ID_PM8917_LVS3	= 177,
+	MSM_RPM_8930_ID_PM8917_LVS4	= 178,
+	MSM_RPM_8930_ID_PM8917_LVS5	= 179,
+	MSM_RPM_8930_ID_PM8917_LVS6	= 180,
+	MSM_RPM_8930_ID_PM8917_LVS7	= 181,
+
+	MSM_RPM_8930_ID_NCP_0		= 182,
+	MSM_RPM_8930_ID_NCP_1		= 183,
+	MSM_RPM_8930_ID_CXO_BUFFERS	= 184,
+	MSM_RPM_8930_ID_USB_OTG_SWITCH	= 185,
+	MSM_RPM_8930_ID_HDMI_SWITCH	= 186,
+	MSM_RPM_8930_ID_QDSS_CLK	= 187,
+	MSM_RPM_8930_ID_VOLTAGE_CORNER	= 188,
+
 	MSM_RPM_8930_ID_LAST = MSM_RPM_8930_ID_VOLTAGE_CORNER,
 };
 
@@ -278,6 +430,8 @@
 	MSM_RPM_8930_STATUS_ID_MMSS_FABRIC_CFG_CLKMOD		= 28,
 	MSM_RPM_8930_STATUS_ID_MMSS_FABRIC_CFG_IOCTL		= 29,
 	MSM_RPM_8930_STATUS_ID_MM_FABRIC_ARB			= 30,
+
+	/* PMIC 8038 */
 	MSM_RPM_8930_STATUS_ID_PM8038_S1_0			= 31,
 	MSM_RPM_8930_STATUS_ID_PM8038_S1_1			= 32,
 	MSM_RPM_8930_STATUS_ID_PM8038_S2_0			= 33,
@@ -346,14 +500,119 @@
 	MSM_RPM_8930_STATUS_ID_PM8038_CLK2_1			= 100,
 	MSM_RPM_8930_STATUS_ID_PM8038_LVS1			= 101,
 	MSM_RPM_8930_STATUS_ID_PM8038_LVS2			= 102,
-	MSM_RPM_8930_STATUS_ID_NCP_0				= 103,
-	MSM_RPM_8930_STATUS_ID_NCP_1				= 104,
-	MSM_RPM_8930_STATUS_ID_CXO_BUFFERS			= 105,
-	MSM_RPM_8930_STATUS_ID_USB_OTG_SWITCH			= 106,
-	MSM_RPM_8930_STATUS_ID_HDMI_SWITCH			= 107,
-	MSM_RPM_8930_STATUS_ID_QDSS_CLK				= 108,
-	MSM_RPM_8930_STATUS_ID_VOLTAGE_CORNER			= 109,
-	MSM_RPM_8930_STATUS_ID_LAST = MSM_RPM_8930_STATUS_ID_VOLTAGE_CORNER,
+	MSM_RPM_8930_STATUS_ID_PM8038_NCP_0			= 103,
+	MSM_RPM_8930_STATUS_ID_PM8038_NCP_1			= 104,
+	MSM_RPM_8930_STATUS_ID_PM8038_CXO_BUFFERS		= 105,
+	MSM_RPM_8930_STATUS_ID_PM8038_USB_OTG_SWITCH		= 106,
+	MSM_RPM_8930_STATUS_ID_PM8038_HDMI_SWITCH		= 107,
+	MSM_RPM_8930_STATUS_ID_PM8038_QDSS_CLK			= 108,
+	MSM_RPM_8930_STATUS_ID_PM8038_VOLTAGE_CORNER		= 109,
+
+	MSM_RPM_8930_STATUS_ID_PM8038_LAST
+		= MSM_RPM_8930_STATUS_ID_PM8038_VOLTAGE_CORNER,
+
+	/* PMIC 8917 */
+	MSM_RPM_8930_STATUS_ID_PM8917_S1_0			= 31,
+	MSM_RPM_8930_STATUS_ID_PM8917_S1_1			= 32,
+	MSM_RPM_8930_STATUS_ID_PM8917_S2_0			= 33,
+	MSM_RPM_8930_STATUS_ID_PM8917_S2_1			= 34,
+	MSM_RPM_8930_STATUS_ID_PM8917_S3_0			= 35,
+	MSM_RPM_8930_STATUS_ID_PM8917_S3_1			= 36,
+	MSM_RPM_8930_STATUS_ID_PM8917_S4_0			= 37,
+	MSM_RPM_8930_STATUS_ID_PM8917_S4_1			= 38,
+	MSM_RPM_8930_STATUS_ID_PM8917_S5_0			= 39,
+	MSM_RPM_8930_STATUS_ID_PM8917_S5_1			= 40,
+	MSM_RPM_8930_STATUS_ID_PM8917_S6_0			= 41,
+	MSM_RPM_8930_STATUS_ID_PM8917_S6_1			= 42,
+	MSM_RPM_8930_STATUS_ID_PM8917_S7_0			= 43,
+	MSM_RPM_8930_STATUS_ID_PM8917_S7_1			= 44,
+	MSM_RPM_8930_STATUS_ID_PM8917_S8_0			= 45,
+	MSM_RPM_8930_STATUS_ID_PM8917_S8_1			= 46,
+	MSM_RPM_8930_STATUS_ID_PM8917_L1_0			= 47,
+	MSM_RPM_8930_STATUS_ID_PM8917_L1_1			= 48,
+	MSM_RPM_8930_STATUS_ID_PM8917_L2_0			= 49,
+	MSM_RPM_8930_STATUS_ID_PM8917_L2_1			= 50,
+	MSM_RPM_8930_STATUS_ID_PM8917_L3_0			= 51,
+	MSM_RPM_8930_STATUS_ID_PM8917_L3_1			= 52,
+	MSM_RPM_8930_STATUS_ID_PM8917_L4_0			= 53,
+	MSM_RPM_8930_STATUS_ID_PM8917_L4_1			= 54,
+	MSM_RPM_8930_STATUS_ID_PM8917_L5_0			= 55,
+	MSM_RPM_8930_STATUS_ID_PM8917_L5_1			= 56,
+	MSM_RPM_8930_STATUS_ID_PM8917_L6_0			= 57,
+	MSM_RPM_8930_STATUS_ID_PM8917_L6_1			= 58,
+	MSM_RPM_8930_STATUS_ID_PM8917_L7_0			= 59,
+	MSM_RPM_8930_STATUS_ID_PM8917_L7_1			= 60,
+	MSM_RPM_8930_STATUS_ID_PM8917_L8_0			= 61,
+	MSM_RPM_8930_STATUS_ID_PM8917_L8_1			= 62,
+	MSM_RPM_8930_STATUS_ID_PM8917_L9_0			= 63,
+	MSM_RPM_8930_STATUS_ID_PM8917_L9_1			= 64,
+	MSM_RPM_8930_STATUS_ID_PM8917_L10_0			= 65,
+	MSM_RPM_8930_STATUS_ID_PM8917_L10_1			= 66,
+	MSM_RPM_8930_STATUS_ID_PM8917_L11_0			= 67,
+	MSM_RPM_8930_STATUS_ID_PM8917_L11_1			= 68,
+	MSM_RPM_8930_STATUS_ID_PM8917_L12_0			= 69,
+	MSM_RPM_8930_STATUS_ID_PM8917_L12_1			= 70,
+	MSM_RPM_8930_STATUS_ID_PM8917_L14_0			= 71,
+	MSM_RPM_8930_STATUS_ID_PM8917_L14_1			= 72,
+	MSM_RPM_8930_STATUS_ID_PM8917_L15_0			= 73,
+	MSM_RPM_8930_STATUS_ID_PM8917_L15_1			= 74,
+	MSM_RPM_8930_STATUS_ID_PM8917_L16_0			= 75,
+	MSM_RPM_8930_STATUS_ID_PM8917_L16_1			= 76,
+	MSM_RPM_8930_STATUS_ID_PM8917_L17_0			= 77,
+	MSM_RPM_8930_STATUS_ID_PM8917_L17_1			= 78,
+	MSM_RPM_8930_STATUS_ID_PM8917_L18_0			= 79,
+	MSM_RPM_8930_STATUS_ID_PM8917_L18_1			= 80,
+	MSM_RPM_8930_STATUS_ID_PM8917_L21_0			= 81,
+	MSM_RPM_8930_STATUS_ID_PM8917_L21_1			= 82,
+	MSM_RPM_8930_STATUS_ID_PM8917_L22_0			= 83,
+	MSM_RPM_8930_STATUS_ID_PM8917_L22_1			= 84,
+	MSM_RPM_8930_STATUS_ID_PM8917_L23_0			= 85,
+	MSM_RPM_8930_STATUS_ID_PM8917_L23_1			= 86,
+	MSM_RPM_8930_STATUS_ID_PM8917_L24_0			= 87,
+	MSM_RPM_8930_STATUS_ID_PM8917_L24_1			= 88,
+	MSM_RPM_8930_STATUS_ID_PM8917_L25_0			= 89,
+	MSM_RPM_8930_STATUS_ID_PM8917_L25_1			= 90,
+	MSM_RPM_8930_STATUS_ID_PM8917_L26_0			= 91,
+	MSM_RPM_8930_STATUS_ID_PM8917_L26_1			= 92,
+	MSM_RPM_8930_STATUS_ID_PM8917_L27_0			= 93,
+	MSM_RPM_8930_STATUS_ID_PM8917_L27_1			= 94,
+	MSM_RPM_8930_STATUS_ID_PM8917_L28_0			= 95,
+	MSM_RPM_8930_STATUS_ID_PM8917_L28_1			= 96,
+	MSM_RPM_8930_STATUS_ID_PM8917_L29_0			= 97,
+	MSM_RPM_8930_STATUS_ID_PM8917_L29_1			= 98,
+	MSM_RPM_8930_STATUS_ID_PM8917_L30_0			= 99,
+	MSM_RPM_8930_STATUS_ID_PM8917_L30_1			= 100,
+	MSM_RPM_8930_STATUS_ID_PM8917_L31_0			= 101,
+	MSM_RPM_8930_STATUS_ID_PM8917_L31_1			= 102,
+	MSM_RPM_8930_STATUS_ID_PM8917_L32_0			= 103,
+	MSM_RPM_8930_STATUS_ID_PM8917_L32_1			= 104,
+	MSM_RPM_8930_STATUS_ID_PM8917_L33_0			= 105,
+	MSM_RPM_8930_STATUS_ID_PM8917_L33_1			= 106,
+	MSM_RPM_8930_STATUS_ID_PM8917_L34_0			= 107,
+	MSM_RPM_8930_STATUS_ID_PM8917_L34_1			= 108,
+	MSM_RPM_8930_STATUS_ID_PM8917_L35_0			= 109,
+	MSM_RPM_8930_STATUS_ID_PM8917_L35_1			= 110,
+	MSM_RPM_8930_STATUS_ID_PM8917_L36_0			= 111,
+	MSM_RPM_8930_STATUS_ID_PM8917_L36_1			= 112,
+	MSM_RPM_8930_STATUS_ID_PM8917_CLK1_0			= 113,
+	MSM_RPM_8930_STATUS_ID_PM8917_CLK1_1			= 114,
+	MSM_RPM_8930_STATUS_ID_PM8917_CLK2_0			= 115,
+	MSM_RPM_8930_STATUS_ID_PM8917_CLK2_1			= 116,
+	MSM_RPM_8930_STATUS_ID_PM8917_LVS1			= 117,
+	MSM_RPM_8930_STATUS_ID_PM8917_LVS3			= 118,
+	MSM_RPM_8930_STATUS_ID_PM8917_LVS4			= 119,
+	MSM_RPM_8930_STATUS_ID_PM8917_LVS5			= 120,
+	MSM_RPM_8930_STATUS_ID_PM8917_LVS6			= 121,
+	MSM_RPM_8930_STATUS_ID_PM8917_LVS7			= 122,
+	MSM_RPM_8930_STATUS_ID_PM8917_NCP_0			= 123,
+	MSM_RPM_8930_STATUS_ID_PM8917_NCP_1			= 124,
+	MSM_RPM_8930_STATUS_ID_PM8917_CXO_BUFFERS		= 125,
+	MSM_RPM_8930_STATUS_ID_PM8917_USB_OTG_SWITCH		= 126,
+	MSM_RPM_8930_STATUS_ID_PM8917_HDMI_SWITCH		= 127,
+	MSM_RPM_8930_STATUS_ID_PM8917_QDSS_CLK			= 128,
+	MSM_RPM_8930_STATUS_ID_PM8917_VOLTAGE_CORNER		= 129,
+	MSM_RPM_8930_STATUS_ID_PM8917_PM8917_LAST
+			= MSM_RPM_8930_STATUS_ID_PM8917_VOLTAGE_CORNER,
 };
 
 #endif /* __ARCH_ARM_MACH_MSM_RPM_8930_H */
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..f8f53f6 100644
--- a/arch/arm/mach-msm/include/mach/rpm-regulator-8930.h
+++ b/arch/arm/mach-msm/include/mach/rpm-regulator-8930.h
@@ -85,9 +85,10 @@
 };
 
 /**
- * enum rpm_vreg_id - RPM regulator ID numbers (both real and pin control)
+ * enum rpm_vreg_id_8930_pm8038 - RPM regulator ID numbers (both real and
+ *		pin control) used with MSM8930 + PM8038
  */
-enum rpm_vreg_id_8930 {
+enum rpm_vreg_id_8930_pm8038 {
 	RPM_VREG_ID_PM8038_L1,
 	RPM_VREG_ID_PM8038_L2,
 	RPM_VREG_ID_PM8038_L3,
@@ -100,6 +101,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 +113,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,
@@ -153,7 +156,111 @@
 	RPM_VREG_ID_PM8038_MAX = RPM_VREG_ID_PM8038_LVS2_PC,
 };
 
+/**
+ * enum rpm_vreg_id_8930_pm8917 - RPM regulator ID numbers (both real and
+ *		pin control) used with MSM8930 + PM8917
+ */
+enum rpm_vreg_id_8930_pm8917 {
+	RPM_VREG_ID_PM8917_L1,
+	RPM_VREG_ID_PM8917_L2,
+	RPM_VREG_ID_PM8917_L3,
+	RPM_VREG_ID_PM8917_L4,
+	RPM_VREG_ID_PM8917_L5,
+	RPM_VREG_ID_PM8917_L6,
+	RPM_VREG_ID_PM8917_L7,
+	RPM_VREG_ID_PM8917_L8,
+	RPM_VREG_ID_PM8917_L9,
+	RPM_VREG_ID_PM8917_L10,
+	RPM_VREG_ID_PM8917_L11,
+	RPM_VREG_ID_PM8917_L12,
+	RPM_VREG_ID_PM8917_L14,
+	RPM_VREG_ID_PM8917_L15,
+	RPM_VREG_ID_PM8917_L16,
+	RPM_VREG_ID_PM8917_L17,
+	RPM_VREG_ID_PM8917_L18,
+	RPM_VREG_ID_PM8917_L21,
+	RPM_VREG_ID_PM8917_L22,
+	RPM_VREG_ID_PM8917_L23,
+	RPM_VREG_ID_PM8917_L24,
+	RPM_VREG_ID_PM8917_L25,
+	RPM_VREG_ID_PM8917_L26,
+	RPM_VREG_ID_PM8917_L27,
+	RPM_VREG_ID_PM8917_L28,
+	RPM_VREG_ID_PM8917_L29,
+	RPM_VREG_ID_PM8917_L30,
+	RPM_VREG_ID_PM8917_L31,
+	RPM_VREG_ID_PM8917_L32,
+	RPM_VREG_ID_PM8917_L33,
+	RPM_VREG_ID_PM8917_L34,
+	RPM_VREG_ID_PM8917_L35,
+	RPM_VREG_ID_PM8917_L36,
+	RPM_VREG_ID_PM8917_S1,
+	RPM_VREG_ID_PM8917_S2,
+	RPM_VREG_ID_PM8917_S3,
+	RPM_VREG_ID_PM8917_S4,
+	RPM_VREG_ID_PM8917_S5,
+	RPM_VREG_ID_PM8917_S6,
+	RPM_VREG_ID_PM8917_S7,
+	RPM_VREG_ID_PM8917_S8,
+	RPM_VREG_ID_PM8917_LVS1,
+	RPM_VREG_ID_PM8917_LVS3,
+	RPM_VREG_ID_PM8917_LVS4,
+	RPM_VREG_ID_PM8917_LVS5,
+	RPM_VREG_ID_PM8917_LVS6,
+	RPM_VREG_ID_PM8917_LVS7,
+	RPM_VREG_ID_PM8917_USB_OTG,
+	RPM_VREG_ID_PM8917_VDD_DIG_CORNER,
+	RPM_VREG_ID_PM8917_MAX_REAL = RPM_VREG_ID_PM8917_VDD_DIG_CORNER,
+
+	/* The following are IDs for regulator devices to enable pin control. */
+	RPM_VREG_ID_PM8917_L1_PC,
+	RPM_VREG_ID_PM8917_L2_PC,
+	RPM_VREG_ID_PM8917_L3_PC,
+	RPM_VREG_ID_PM8917_L4_PC,
+	RPM_VREG_ID_PM8917_L5_PC,
+	RPM_VREG_ID_PM8917_L6_PC,
+	RPM_VREG_ID_PM8917_L7_PC,
+	RPM_VREG_ID_PM8917_L8_PC,
+	RPM_VREG_ID_PM8917_L9_PC,
+	RPM_VREG_ID_PM8917_L10_PC,
+	RPM_VREG_ID_PM8917_L11_PC,
+	RPM_VREG_ID_PM8917_L12_PC,
+	RPM_VREG_ID_PM8917_L14_PC,
+	RPM_VREG_ID_PM8917_L15_PC,
+	RPM_VREG_ID_PM8917_L16_PC,
+	RPM_VREG_ID_PM8917_L17_PC,
+	RPM_VREG_ID_PM8917_L18_PC,
+	RPM_VREG_ID_PM8917_L21_PC,
+	RPM_VREG_ID_PM8917_L22_PC,
+	RPM_VREG_ID_PM8917_L23_PC,
+
+	RPM_VREG_ID_PM8917_L29_PC,
+	RPM_VREG_ID_PM8917_L30_PC,
+	RPM_VREG_ID_PM8917_L31_PC,
+	RPM_VREG_ID_PM8917_L32_PC,
+	RPM_VREG_ID_PM8917_L33_PC,
+	RPM_VREG_ID_PM8917_L34_PC,
+	RPM_VREG_ID_PM8917_L35_PC,
+	RPM_VREG_ID_PM8917_L36_PC,
+	RPM_VREG_ID_PM8917_S1_PC,
+	RPM_VREG_ID_PM8917_S2_PC,
+	RPM_VREG_ID_PM8917_S3_PC,
+	RPM_VREG_ID_PM8917_S4_PC,
+
+	RPM_VREG_ID_PM8917_S7_PC,
+	RPM_VREG_ID_PM8917_S8_PC,
+	RPM_VREG_ID_PM8917_LVS1_PC,
+	RPM_VREG_ID_PM8917_LVS3_PC,
+	RPM_VREG_ID_PM8917_LVS4_PC,
+	RPM_VREG_ID_PM8917_LVS5_PC,
+	RPM_VREG_ID_PM8917_LVS6_PC,
+	RPM_VREG_ID_PM8917_LVS7_PC,
+
+	RPM_VREG_ID_PM8917_MAX = RPM_VREG_ID_PM8917_LVS7_PC,
+};
+
 /* 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-8960.h b/arch/arm/mach-msm/include/mach/rpm-regulator-8960.h
index 6de47bd..abcdbb8 100644
--- a/arch/arm/mach-msm/include/mach/rpm-regulator-8960.h
+++ b/arch/arm/mach-msm/include/mach/rpm-regulator-8960.h
@@ -100,6 +100,7 @@
 	RPM_VREG_ID_PM8921_L10,
 	RPM_VREG_ID_PM8921_L11,
 	RPM_VREG_ID_PM8921_L12,
+	RPM_VREG_ID_PM8921_L13,
 	RPM_VREG_ID_PM8921_L14,
 	RPM_VREG_ID_PM8921_L15,
 	RPM_VREG_ID_PM8921_L16,
@@ -176,6 +177,7 @@
 };
 
 /* Minimum high power mode loads in uA. */
+#define RPM_VREG_8960_LDO_5_HPM_MIN_LOAD		0
 #define RPM_VREG_8960_LDO_50_HPM_MIN_LOAD		5000
 #define RPM_VREG_8960_LDO_150_HPM_MIN_LOAD		10000
 #define RPM_VREG_8960_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 d2ff2fe..f6e082d 100644
--- a/arch/arm/mach-msm/include/mach/rpm-regulator.h
+++ b/arch/arm/mach-msm/include/mach/rpm-regulator.h
@@ -31,7 +31,8 @@
 	RPM_VREG_VERSION_8960,
 	RPM_VREG_VERSION_9615,
 	RPM_VREG_VERSION_8930,
-	RPM_VREG_VERSION_MAX = RPM_VREG_VERSION_8930,
+	RPM_VREG_VERSION_8930_PM8917,
+	RPM_VREG_VERSION_MAX = RPM_VREG_VERSION_8930_PM8917,
 };
 
 #define RPM_VREG_PIN_CTRL_NONE		0x00
diff --git a/arch/arm/mach-msm/include/mach/rpm.h b/arch/arm/mach-msm/include/mach/rpm.h
index f6b9a6e..4ee1997 100644
--- a/arch/arm/mach-msm/include/mach/rpm.h
+++ b/arch/arm/mach-msm/include/mach/rpm.h
@@ -451,6 +451,100 @@
 	MSM_RPM_ID_PM8038_CLK2_1,
 	MSM_RPM_ID_PM8038_LVS1,
 	MSM_RPM_ID_PM8038_LVS2,
+
+	/* PM8917 specific */
+	MSM_RPM_ID_PM8917_S1_0,
+	MSM_RPM_ID_PM8917_S1_1,
+	MSM_RPM_ID_PM8917_S2_0,
+	MSM_RPM_ID_PM8917_S2_1,
+	MSM_RPM_ID_PM8917_S3_0,
+	MSM_RPM_ID_PM8917_S3_1,
+	MSM_RPM_ID_PM8917_S4_0,
+	MSM_RPM_ID_PM8917_S4_1,
+	MSM_RPM_ID_PM8917_S5_0,
+	MSM_RPM_ID_PM8917_S5_1,
+	MSM_RPM_ID_PM8917_S6_0,
+	MSM_RPM_ID_PM8917_S6_1,
+	MSM_RPM_ID_PM8917_S7_0,
+	MSM_RPM_ID_PM8917_S7_1,
+	MSM_RPM_ID_PM8917_S8_0,
+	MSM_RPM_ID_PM8917_S8_1,
+	MSM_RPM_ID_PM8917_L1_0,
+	MSM_RPM_ID_PM8917_L1_1,
+	MSM_RPM_ID_PM8917_L2_0,
+	MSM_RPM_ID_PM8917_L2_1,
+	MSM_RPM_ID_PM8917_L3_0,
+	MSM_RPM_ID_PM8917_L3_1,
+	MSM_RPM_ID_PM8917_L4_0,
+	MSM_RPM_ID_PM8917_L4_1,
+	MSM_RPM_ID_PM8917_L5_0,
+	MSM_RPM_ID_PM8917_L5_1,
+	MSM_RPM_ID_PM8917_L6_0,
+	MSM_RPM_ID_PM8917_L6_1,
+	MSM_RPM_ID_PM8917_L7_0,
+	MSM_RPM_ID_PM8917_L7_1,
+	MSM_RPM_ID_PM8917_L8_0,
+	MSM_RPM_ID_PM8917_L8_1,
+	MSM_RPM_ID_PM8917_L9_0,
+	MSM_RPM_ID_PM8917_L9_1,
+	MSM_RPM_ID_PM8917_L10_0,
+	MSM_RPM_ID_PM8917_L10_1,
+	MSM_RPM_ID_PM8917_L11_0,
+	MSM_RPM_ID_PM8917_L11_1,
+	MSM_RPM_ID_PM8917_L12_0,
+	MSM_RPM_ID_PM8917_L12_1,
+	MSM_RPM_ID_PM8917_L14_0,
+	MSM_RPM_ID_PM8917_L14_1,
+	MSM_RPM_ID_PM8917_L15_0,
+	MSM_RPM_ID_PM8917_L15_1,
+	MSM_RPM_ID_PM8917_L16_0,
+	MSM_RPM_ID_PM8917_L16_1,
+	MSM_RPM_ID_PM8917_L17_0,
+	MSM_RPM_ID_PM8917_L17_1,
+	MSM_RPM_ID_PM8917_L18_0,
+	MSM_RPM_ID_PM8917_L18_1,
+	MSM_RPM_ID_PM8917_L21_0,
+	MSM_RPM_ID_PM8917_L21_1,
+	MSM_RPM_ID_PM8917_L22_0,
+	MSM_RPM_ID_PM8917_L22_1,
+	MSM_RPM_ID_PM8917_L23_0,
+	MSM_RPM_ID_PM8917_L23_1,
+	MSM_RPM_ID_PM8917_L24_0,
+	MSM_RPM_ID_PM8917_L24_1,
+	MSM_RPM_ID_PM8917_L25_0,
+	MSM_RPM_ID_PM8917_L25_1,
+	MSM_RPM_ID_PM8917_L26_0,
+	MSM_RPM_ID_PM8917_L26_1,
+	MSM_RPM_ID_PM8917_L27_0,
+	MSM_RPM_ID_PM8917_L27_1,
+	MSM_RPM_ID_PM8917_L28_0,
+	MSM_RPM_ID_PM8917_L28_1,
+	MSM_RPM_ID_PM8917_L29_0,
+	MSM_RPM_ID_PM8917_L29_1,
+	MSM_RPM_ID_PM8917_L30_0,
+	MSM_RPM_ID_PM8917_L30_1,
+	MSM_RPM_ID_PM8917_L31_0,
+	MSM_RPM_ID_PM8917_L31_1,
+	MSM_RPM_ID_PM8917_L32_0,
+	MSM_RPM_ID_PM8917_L32_1,
+	MSM_RPM_ID_PM8917_L33_0,
+	MSM_RPM_ID_PM8917_L33_1,
+	MSM_RPM_ID_PM8917_L34_0,
+	MSM_RPM_ID_PM8917_L34_1,
+	MSM_RPM_ID_PM8917_L35_0,
+	MSM_RPM_ID_PM8917_L35_1,
+	MSM_RPM_ID_PM8917_L36_0,
+	MSM_RPM_ID_PM8917_L36_1,
+	MSM_RPM_ID_PM8917_CLK1_0,
+	MSM_RPM_ID_PM8917_CLK1_1,
+	MSM_RPM_ID_PM8917_CLK2_0,
+	MSM_RPM_ID_PM8917_CLK2_1,
+	MSM_RPM_ID_PM8917_LVS1,
+	MSM_RPM_ID_PM8917_LVS3,
+	MSM_RPM_ID_PM8917_LVS4,
+	MSM_RPM_ID_PM8917_LVS5,
+	MSM_RPM_ID_PM8917_LVS6,
+	MSM_RPM_ID_PM8917_LVS7,
 	MSM_RPM_ID_VOLTAGE_CORNER,
 
 	/* 8064 specific */
@@ -605,6 +699,29 @@
 	MSM_RPM_STATUS_ID_EBI1_CH1_RANGE,
 	MSM_RPM_STATUS_ID_QDSS_CLK,
 
+	/* 8930 aliases to simplify device mapping */
+	MSM_RPM_STATUS_ID_PM8038_NCP_0 = MSM_RPM_STATUS_ID_NCP_0,
+	MSM_RPM_STATUS_ID_PM8038_NCP_1 = MSM_RPM_STATUS_ID_NCP_1,
+	MSM_RPM_STATUS_ID_PM8038_CXO_BUFFERS
+		= MSM_RPM_STATUS_ID_CXO_BUFFERS,
+	MSM_RPM_STATUS_ID_PM8038_USB_OTG_SWITCH
+		= MSM_RPM_STATUS_ID_USB_OTG_SWITCH,
+	MSM_RPM_STATUS_ID_PM8038_HDMI_SWITCH
+		= MSM_RPM_STATUS_ID_HDMI_SWITCH,
+	MSM_RPM_STATUS_ID_PM8038_QDSS_CLK
+		= MSM_RPM_STATUS_ID_QDSS_CLK,
+
+	MSM_RPM_STATUS_ID_PM8917_NCP_0 = MSM_RPM_STATUS_ID_NCP_0,
+		MSM_RPM_STATUS_ID_PM8917_NCP_1 = MSM_RPM_STATUS_ID_NCP_1,
+	MSM_RPM_STATUS_ID_PM8917_CXO_BUFFERS
+		= MSM_RPM_STATUS_ID_CXO_BUFFERS,
+	MSM_RPM_STATUS_ID_PM8917_USB_OTG_SWITCH
+		= MSM_RPM_STATUS_ID_USB_OTG_SWITCH,
+	MSM_RPM_STATUS_ID_PM8917_HDMI_SWITCH
+		= MSM_RPM_STATUS_ID_HDMI_SWITCH,
+	MSM_RPM_STATUS_ID_PM8917_QDSS_CLK
+		= MSM_RPM_STATUS_ID_QDSS_CLK,
+
 	/* 8660 Specific */
 	MSM_RPM_STATUS_ID_PLL_4,
 	MSM_RPM_STATUS_ID_SMI_CLK,
@@ -817,7 +934,105 @@
 	MSM_RPM_STATUS_ID_PM8038_CLK2_1,
 	MSM_RPM_STATUS_ID_PM8038_LVS1,
 	MSM_RPM_STATUS_ID_PM8038_LVS2,
+
+	/* PMIC 8917 */
+	MSM_RPM_STATUS_ID_PM8917_S1_0,
+	MSM_RPM_STATUS_ID_PM8917_S1_1,
+	MSM_RPM_STATUS_ID_PM8917_S2_0,
+	MSM_RPM_STATUS_ID_PM8917_S2_1,
+	MSM_RPM_STATUS_ID_PM8917_S3_0,
+	MSM_RPM_STATUS_ID_PM8917_S3_1,
+	MSM_RPM_STATUS_ID_PM8917_S4_0,
+	MSM_RPM_STATUS_ID_PM8917_S4_1,
+	MSM_RPM_STATUS_ID_PM8917_S5_0,
+	MSM_RPM_STATUS_ID_PM8917_S5_1,
+	MSM_RPM_STATUS_ID_PM8917_S6_0,
+	MSM_RPM_STATUS_ID_PM8917_S6_1,
+	MSM_RPM_STATUS_ID_PM8917_S7_0,
+	MSM_RPM_STATUS_ID_PM8917_S7_1,
+	MSM_RPM_STATUS_ID_PM8917_S8_0,
+	MSM_RPM_STATUS_ID_PM8917_S8_1,
+	MSM_RPM_STATUS_ID_PM8917_L1_0,
+	MSM_RPM_STATUS_ID_PM8917_L1_1,
+	MSM_RPM_STATUS_ID_PM8917_L2_0,
+	MSM_RPM_STATUS_ID_PM8917_L2_1,
+	MSM_RPM_STATUS_ID_PM8917_L3_0,
+	MSM_RPM_STATUS_ID_PM8917_L3_1,
+	MSM_RPM_STATUS_ID_PM8917_L4_0,
+	MSM_RPM_STATUS_ID_PM8917_L4_1,
+	MSM_RPM_STATUS_ID_PM8917_L5_0,
+	MSM_RPM_STATUS_ID_PM8917_L5_1,
+	MSM_RPM_STATUS_ID_PM8917_L6_0,
+	MSM_RPM_STATUS_ID_PM8917_L6_1,
+	MSM_RPM_STATUS_ID_PM8917_L7_0,
+	MSM_RPM_STATUS_ID_PM8917_L7_1,
+	MSM_RPM_STATUS_ID_PM8917_L8_0,
+	MSM_RPM_STATUS_ID_PM8917_L8_1,
+	MSM_RPM_STATUS_ID_PM8917_L9_0,
+	MSM_RPM_STATUS_ID_PM8917_L9_1,
+	MSM_RPM_STATUS_ID_PM8917_L10_0,
+	MSM_RPM_STATUS_ID_PM8917_L10_1,
+	MSM_RPM_STATUS_ID_PM8917_L11_0,
+	MSM_RPM_STATUS_ID_PM8917_L11_1,
+	MSM_RPM_STATUS_ID_PM8917_L12_0,
+	MSM_RPM_STATUS_ID_PM8917_L12_1,
+	MSM_RPM_STATUS_ID_PM8917_L14_0,
+	MSM_RPM_STATUS_ID_PM8917_L14_1,
+	MSM_RPM_STATUS_ID_PM8917_L15_0,
+	MSM_RPM_STATUS_ID_PM8917_L15_1,
+	MSM_RPM_STATUS_ID_PM8917_L16_0,
+	MSM_RPM_STATUS_ID_PM8917_L16_1,
+	MSM_RPM_STATUS_ID_PM8917_L17_0,
+	MSM_RPM_STATUS_ID_PM8917_L17_1,
+	MSM_RPM_STATUS_ID_PM8917_L18_0,
+	MSM_RPM_STATUS_ID_PM8917_L18_1,
+	MSM_RPM_STATUS_ID_PM8917_L21_0,
+	MSM_RPM_STATUS_ID_PM8917_L21_1,
+	MSM_RPM_STATUS_ID_PM8917_L22_0,
+	MSM_RPM_STATUS_ID_PM8917_L22_1,
+	MSM_RPM_STATUS_ID_PM8917_L23_0,
+	MSM_RPM_STATUS_ID_PM8917_L23_1,
+	MSM_RPM_STATUS_ID_PM8917_L24_0,
+	MSM_RPM_STATUS_ID_PM8917_L24_1,
+	MSM_RPM_STATUS_ID_PM8917_L25_0,
+	MSM_RPM_STATUS_ID_PM8917_L25_1,
+	MSM_RPM_STATUS_ID_PM8917_L26_0,
+	MSM_RPM_STATUS_ID_PM8917_L26_1,
+	MSM_RPM_STATUS_ID_PM8917_L27_0,
+	MSM_RPM_STATUS_ID_PM8917_L27_1,
+	MSM_RPM_STATUS_ID_PM8917_L28_0,
+	MSM_RPM_STATUS_ID_PM8917_L28_1,
+	MSM_RPM_STATUS_ID_PM8917_L29_0,
+	MSM_RPM_STATUS_ID_PM8917_L29_1,
+	MSM_RPM_STATUS_ID_PM8917_L30_0,
+	MSM_RPM_STATUS_ID_PM8917_L30_1,
+	MSM_RPM_STATUS_ID_PM8917_L31_0,
+	MSM_RPM_STATUS_ID_PM8917_L31_1,
+	MSM_RPM_STATUS_ID_PM8917_L32_0,
+	MSM_RPM_STATUS_ID_PM8917_L32_1,
+	MSM_RPM_STATUS_ID_PM8917_L33_0,
+	MSM_RPM_STATUS_ID_PM8917_L33_1,
+	MSM_RPM_STATUS_ID_PM8917_L34_0,
+	MSM_RPM_STATUS_ID_PM8917_L34_1,
+	MSM_RPM_STATUS_ID_PM8917_L35_0,
+	MSM_RPM_STATUS_ID_PM8917_L35_1,
+	MSM_RPM_STATUS_ID_PM8917_L36_0,
+	MSM_RPM_STATUS_ID_PM8917_L36_1,
+	MSM_RPM_STATUS_ID_PM8917_CLK1_0,
+	MSM_RPM_STATUS_ID_PM8917_CLK1_1,
+	MSM_RPM_STATUS_ID_PM8917_CLK2_0,
+	MSM_RPM_STATUS_ID_PM8917_CLK2_1,
+	MSM_RPM_STATUS_ID_PM8917_LVS1,
+	MSM_RPM_STATUS_ID_PM8917_LVS3,
+	MSM_RPM_STATUS_ID_PM8917_LVS4,
+	MSM_RPM_STATUS_ID_PM8917_LVS5,
+	MSM_RPM_STATUS_ID_PM8917_LVS6,
+	MSM_RPM_STATUS_ID_PM8917_LVS7,
 	MSM_RPM_STATUS_ID_VOLTAGE_CORNER,
+	MSM_RPM_STATUS_ID_PM8917_VOLTAGE_CORNER
+		= MSM_RPM_STATUS_ID_VOLTAGE_CORNER,
+	MSM_RPM_STATUS_ID_PM8038_VOLTAGE_CORNER
+		= MSM_RPM_STATUS_ID_VOLTAGE_CORNER,
 
 	/* 8064 specific */
 	MSM_RPM_STATUS_ID_PM8821_S1_0,
@@ -899,6 +1114,7 @@
 extern struct msm_rpm_platform_data msm8960_rpm_data;
 extern struct msm_rpm_platform_data msm9615_rpm_data;
 extern struct msm_rpm_platform_data msm8930_rpm_data;
+extern struct msm_rpm_platform_data msm8930_rpm_data_pm8917;
 extern struct msm_rpm_platform_data apq8064_rpm_data;
 
 #if defined(CONFIG_MSM_RPM)
diff --git a/arch/arm/mach-msm/include/mach/socinfo.h b/arch/arm/mach-msm/include/mach/socinfo.h
index f7ba507..546cbaf 100644
--- a/arch/arm/mach-msm/include/mach/socinfo.h
+++ b/arch/arm/mach-msm/include/mach/socinfo.h
@@ -44,6 +44,16 @@
 	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msm9625")
 #define machine_is_msm9625()		\
 	of_machine_is_compatible("qcom,msm9625")
+#define early_machine_is_mpq8092()	\
+	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,mpq8092")
+#define machine_is_mpq8092_sim()           \
+	of_machine_is_compatible("qcom,mpq8092-sim")
+#define early_machine_is_msm8226()	\
+	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msm8226")
+#define machine_is_msm8226()		\
+	of_machine_is_compatible("qcom,msm8226")
+#define machine_is_msm8226_sim()		\
+	of_machine_is_compatible("qcom,msm8226-sim")
 #else
 #define early_machine_is_msm8974()	0
 #define machine_is_msm8974()		0
@@ -51,6 +61,12 @@
 #define machine_is_msm8974_rumi()	0
 #define early_machine_is_msm9625()	0
 #define machine_is_msm9625()		0
+#define early_machine_is_mpq8092()	0
+#define machine_is_mpq8092_sim()	0
+#define early_machine_is_msm8226()	0
+#define machine_is_msm8226()		0
+#define machine_is_msm8226_sim()	0
+
 #endif
 
 #define PLATFORM_SUBTYPE_SGLTE	6
@@ -80,7 +96,26 @@
 	MSM_CPU_8974,
 	MSM_CPU_8627,
 	MSM_CPU_8625,
-	MSM_CPU_9625
+	MSM_CPU_9625,
+	MSM_CPU_8092,
+	MSM_CPU_8226
+};
+
+enum pmic_model {
+	PMIC_MODEL_PM8058	= 13,
+	PMIC_MODEL_PM8028	= 14,
+	PMIC_MODEL_PM8901	= 15,
+	PMIC_MODEL_PM8027	= 16,
+	PMIC_MODEL_ISL_9519	= 17,
+	PMIC_MODEL_PM8921	= 18,
+	PMIC_MODEL_PM8018	= 19,
+	PMIC_MODEL_PM8015	= 20,
+	PMIC_MODEL_PM8014	= 21,
+	PMIC_MODEL_PM8821	= 22,
+	PMIC_MODEL_PM8038	= 23,
+	PMIC_MODEL_PM8922	= 24,
+	PMIC_MODEL_PM8917	= 25,
+	PMIC_MODEL_UNKNOWN	= 0xFFFFFFFF
 };
 
 enum msm_cpu socinfo_get_msm_cpu(void);
@@ -91,12 +126,15 @@
 uint32_t socinfo_get_platform_type(void);
 uint32_t socinfo_get_platform_subtype(void);
 uint32_t socinfo_get_platform_version(void);
+enum pmic_model socinfo_get_pmic_model(void);
+uint32_t socinfo_get_pmic_die_revision(void);
 int __init socinfo_init(void) __must_check;
 const int read_msm_cpu_type(void);
 const int get_core_count(void);
 const int cpu_is_krait(void);
 const int cpu_is_krait_v1(void);
 const int cpu_is_krait_v2(void);
+const int cpu_is_krait_v3(void);
 
 static inline int cpu_is_msm7x01(void)
 {
@@ -342,4 +380,29 @@
 #endif
 }
 
+static inline int cpu_is_mpq8092(void)
+{
+#ifdef CONFIG_ARCH_MPQ8092
+	enum msm_cpu cpu = socinfo_get_msm_cpu();
+
+	BUG_ON(cpu == MSM_CPU_UNKNOWN);
+	return cpu == MSM_CPU_8092;
+#else
+	return 0;
+#endif
+
+}
+
+static inline int cpu_is_msm8226(void)
+{
+#ifdef CONFIG_ARCH_MSM8226
+	enum msm_cpu cpu = socinfo_get_msm_cpu();
+
+	BUG_ON(cpu == MSM_CPU_UNKNOWN);
+	return cpu == MSM_CPU_8226;
+#else
+	return 0;
+#endif
+}
+
 #endif
diff --git a/arch/arm/mach-msm/include/mach/sps.h b/arch/arm/mach-msm/include/mach/sps.h
index edc4b39..5333c2e 100644
--- a/arch/arm/mach-msm/include/mach/sps.h
+++ b/arch/arm/mach-msm/include/mach/sps.h
@@ -75,6 +75,8 @@
 #define SPS_BAM_OPT_BAMDMA          (1UL << 2)
 /* BAM IRQ is registered for apps wakeup */
 #define SPS_BAM_OPT_IRQ_WAKEUP      (1UL << 3)
+/* Ignore external block pipe reset */
+#define SPS_BAM_NO_EXT_P_RST        (1UL << 4)
 
 /* BAM device management flags */
 
@@ -1247,10 +1249,15 @@
  *
  * @para - parameter used for an option (such as pipe combination)
  *
+ * @tb_sel - testbus selection
+ *
+ * @pre_level - prescreening level
+ *
  * @return 0 on success, negative value on error
  *
  */
-int sps_get_bam_debug_info(u32 dev, u32 option, u32 para);
+int sps_get_bam_debug_info(u32 dev, u32 option, u32 para,
+		u32 tb_sel, u8 pre_level);
 
 #else
 static inline int sps_register_bam_device(const struct sps_bam_props
@@ -1409,7 +1416,8 @@
 	return -EPERM;
 }
 
-static inline int sps_get_bam_debug_info(u32 dev, u32 option, u32 para)
+static inline int sps_get_bam_debug_info(u32 dev, u32 option, u32 para,
+		u32 tb_sel, u8 pre_level)
 {
 	return -EPERM;
 }
diff --git a/arch/arm/mach-msm/include/mach/subsystem_restart.h b/arch/arm/mach-msm/include/mach/subsystem_restart.h
index 6d15f47..d3c4eb8 100644
--- a/arch/arm/mach-msm/include/mach/subsystem_restart.h
+++ b/arch/arm/mach-msm/include/mach/subsystem_restart.h
@@ -27,8 +27,21 @@
 	RESET_LEVEL_MAX
 };
 
+struct device;
+struct module;
+
+/**
+ * struct subsys_desc - subsystem descriptor
+ * @name: name of subsystem
+ * @depends_on: subsystem this subsystem depends on to operate
+ * @dev: parent device
+ * @owner: module the descriptor belongs to
+ */
 struct subsys_desc {
 	const char *name;
+	const char *depends_on;
+	struct device *dev;
+	struct module *owner;
 
 	int (*shutdown)(const struct subsys_desc *desc);
 	int (*powerup)(const struct subsys_desc *desc);
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index a2f2c31..9dff013 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -300,6 +300,8 @@
 	MSM_CHIP_DEVICE(QGIC_CPU, MSM8974),
 	MSM_CHIP_DEVICE(APCS_GCC, MSM8974),
 	MSM_CHIP_DEVICE(TLMM, MSM8974),
+	MSM_CHIP_DEVICE(MPM2_PSHOLD, MSM8974),
+	MSM_CHIP_DEVICE(IMEM, MSM8974),
 	{
 		.virtual =  (unsigned long) MSM_SHARED_RAM_BASE,
 		.length =   MSM_SHARED_RAM_SIZE,
@@ -308,6 +310,7 @@
 #ifdef CONFIG_DEBUG_MSM8974_UART
 	MSM_DEVICE(DEBUG_UART),
 #endif
+	MSM_CHIP_DEVICE(DBG_IMEM, MSM8974),
 };
 
 void __init msm_map_8974_io(void)
@@ -475,3 +478,51 @@
 	msm_map_io(msm9625_io_desc, ARRAY_SIZE(msm9625_io_desc));
 }
 #endif /* CONFIG_ARCH_MSM9625 */
+
+#ifdef CONFIG_ARCH_MPQ8092
+static struct map_desc mpq8092_io_desc[] __initdata = {
+	MSM_CHIP_DEVICE(QGIC_DIST, MPQ8092),
+	MSM_CHIP_DEVICE(QGIC_CPU, MPQ8092),
+	MSM_CHIP_DEVICE(APCS_GCC, MPQ8092),
+	MSM_CHIP_DEVICE(TLMM, MPQ8092),
+	{
+		.virtual =  (unsigned long) MSM_SHARED_RAM_BASE,
+		.length =   MSM_SHARED_RAM_SIZE,
+		.type =     MT_DEVICE,
+	},
+#ifdef CONFIG_DEBUG_MPQ8092_UART
+	MSM_DEVICE(DEBUG_UART),
+#endif
+};
+
+void __init msm_map_mpq8092_io(void)
+{
+	msm_shared_ram_phys = MSM8974_MSM_SHARED_RAM_PHYS;
+	msm_map_io(mpq8092_io_desc, ARRAY_SIZE(mpq8092_io_desc));
+}
+#endif /* CONFIG_ARCH_MPQ8092 */
+
+#ifdef CONFIG_ARCH_MSM8226
+static struct map_desc msm_8226_io_desc[] __initdata = {
+	MSM_CHIP_DEVICE(QGIC_DIST, MSM8226),
+	MSM_CHIP_DEVICE(QGIC_CPU, MSM8226),
+	MSM_CHIP_DEVICE(APCS_GCC, MSM8226),
+	MSM_CHIP_DEVICE(TLMM, MSM8226),
+	MSM_CHIP_DEVICE(IMEM, MSM8226),
+	{
+		.virtual =  (unsigned long) MSM_SHARED_RAM_BASE,
+		.length =   MSM_SHARED_RAM_SIZE,
+		.type =     MT_DEVICE,
+	},
+#ifdef CONFIG_DEBUG_MPQ8226_UART
+	MSM_DEVICE(DEBUG_UART),
+#endif
+};
+
+
+void __init msm_map_msm8226_io(void)
+{
+	msm_shared_ram_phys = MSM8226_MSM_SHARED_RAM_PHYS;
+	msm_map_io(msm_8226_io_desc, ARRAY_SIZE(msm_8226_io_desc));
+}
+#endif /* CONFIG_ARCH_MSM8226 */
diff --git a/arch/arm/mach-msm/iommu_domains.c b/arch/arm/mach-msm/iommu_domains.c
index 8f9464c..3acb6d8 100644
--- a/arch/arm/mach-msm/iommu_domains.c
+++ b/arch/arm/mach-msm/iommu_domains.c
@@ -191,6 +191,7 @@
 
 	return ret;
 }
+EXPORT_SYMBOL(msm_iommu_map_contig_buffer);
 
 void msm_iommu_unmap_contig_buffer(unsigned long iova,
 					unsigned int domain_no,
@@ -203,6 +204,7 @@
 	iommu_unmap_range(msm_get_iommu_domain(domain_no), iova, size);
 	msm_free_iova_address(iova, domain_no, partition_no, size);
 }
+EXPORT_SYMBOL(msm_iommu_unmap_contig_buffer);
 
 static struct msm_iova_data *find_domain(int domain_num)
 {
@@ -402,6 +404,7 @@
 
 	return -EINVAL;
 }
+EXPORT_SYMBOL(msm_register_domain);
 
 static int __init iommu_domain_probe(struct platform_device *pdev)
 {
diff --git a/arch/arm/mach-msm/ipc_logging_debug.c b/arch/arm/mach-msm/ipc_logging_debug.c
index 5f7a95e..ee3672e 100644
--- a/arch/arm/mach-msm/ipc_logging_debug.c
+++ b/arch/arm/mach-msm/ipc_logging_debug.c
@@ -186,6 +186,15 @@
 {
 	tsv_timestamp_read(ectxt, dctxt, " ");
 	tsv_byte_array_read(ectxt, dctxt, "");
+
+	/* add trailing \n if necessary */
+	if (*(dctxt->buff - 1) != '\n') {
+		if (dctxt->size) {
+			++dctxt->buff;
+			--dctxt->size;
+		}
+		*(dctxt->buff - 1) = '\n';
+	}
 }
 
 void check_and_create_debugfs(void)
diff --git a/arch/arm/mach-msm/jtag.c b/arch/arm/mach-msm/jtag.c
index bf5857c..3b7c5d6 100644
--- a/arch/arm/mach-msm/jtag.c
+++ b/arch/arm/mach-msm/jtag.c
@@ -1070,6 +1070,20 @@
 
 	cpu = raw_smp_processor_id();
 
+	/* Attempt restore only if save has been done. If power collapse
+	 * is disabled, hotplug off of non-boot core will result in WFI
+	 * and hence msm_jtag_save_state will not occur. Subsequently,
+	 * during hotplug on of non-boot core when msm_jtag_restore_state
+	 * is called via msm_platform_secondary_init, this check will help
+	 * bail us out without restoring.
+	 */
+	if (msm_jtag_save_cntr[cpu] == msm_jtag_restore_cntr[cpu])
+		return;
+	else if (msm_jtag_save_cntr[cpu] != msm_jtag_restore_cntr[cpu] + 1)
+		pr_err_ratelimited("jtag imbalance, save:%lu, restore:%lu\n",
+				   (unsigned long)msm_jtag_save_cntr[cpu],
+				   (unsigned long)msm_jtag_restore_cntr[cpu]);
+
 	msm_jtag_restore_cntr[cpu]++;
 	/* ensure counter is updated before moving forward */
 	mb();
diff --git a/arch/arm/mach-msm/krait-regulator.c b/arch/arm/mach-msm/krait-regulator.c
index 63b00c2..96c4809 100644
--- a/arch/arm/mach-msm/krait-regulator.c
+++ b/arch/arm/mach-msm/krait-regulator.c
@@ -61,17 +61,16 @@
 #define PMIC_VOLTAGE_MIN		350000
 #define PMIC_VOLTAGE_MAX		1355000
 #define LV_RANGE_STEP			5000
-#define LV_RANGE_MIN			80000
 
 /* use LDO for core voltage below LDO_THRESH */
 #define CORE_VOLTAGE_LDO_THRESH		750000
 
 #define LOAD_PER_PHASE			3200000
 
-#define CORE_VOLTAGE_MIN		500000
+#define CORE_VOLTAGE_MIN		900000
 
 #define KRAIT_LDO_VOLTAGE_MIN		465000
-#define KRAIT_LDO_VOLTAGE_OFFSET	460000
+#define KRAIT_LDO_VOLTAGE_OFFSET	465000
 #define KRAIT_LDO_STEP			5000
 
 #define BHS_SETTLING_DELAY_US		1
@@ -291,7 +290,7 @@
 		uV = PMIC_VOLTAGE_MAX;
 	}
 
-	setpoint = DIV_ROUND_UP(uV - LV_RANGE_MIN, LV_RANGE_STEP);
+	setpoint = DIV_ROUND_UP(uV, LV_RANGE_STEP);
 	return msm_spm_apcs_set_vdd(setpoint);
 }
 
@@ -735,6 +734,22 @@
 
 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");
diff --git a/arch/arm/mach-msm/lpm_resources.c b/arch/arm/mach-msm/lpm_resources.c
index 0758651..48d31f3 100644
--- a/arch/arm/mach-msm/lpm_resources.c
+++ b/arch/arm/mach-msm/lpm_resources.c
@@ -353,18 +353,21 @@
 
 /* lpm resource handling functions */
 /* Common */
-static void msm_lpm_notify_common(struct msm_rpm_notifier_data *rpm_notifier_cb,
+static void msm_lpm_notify_common(struct msm_rpm_notifier_data *cb,
 				struct msm_lpm_resource *rs)
 {
-	if ((rpm_notifier_cb->rsc_type == rs->rs_data.type) &&
-			(rpm_notifier_cb->rsc_id == rs->rs_data.id) &&
-			(rpm_notifier_cb->key == rs->rs_data.key)) {
-		BUG_ON(rpm_notifier_cb->size > MAX_RS_SIZE);
+	if ((cb->rsc_type == rs->rs_data.type) &&
+		(cb->rsc_id == rs->rs_data.id) &&
+		(cb->key == rs->rs_data.key)) {
+
+		BUG_ON(cb->size > MAX_RS_SIZE);
 
 		if (rs->valid) {
-			if (rpm_notifier_cb->value)
-				memcpy(&rs->rs_data.value,
-				rpm_notifier_cb->value, rpm_notifier_cb->size);
+			if (cb->value) {
+				memcpy(&rs->rs_data.value, cb->value, cb->size);
+				msm_rpm_add_kvp_data_noirq(rs->rs_data.handle,
+						cb->key, cb->value, cb->size);
+			}
 			else
 				rs->rs_data.value = rs->rs_data.default_value;
 
@@ -695,7 +698,7 @@
 	case CPU_DEAD_FROZEN:
 	case CPU_DEAD:
 		if (num_online_cpus() == 1)
-			rs->rs_data.value = MSM_LPM_L2_CACHE_GDHS;
+			rs->rs_data.value = MSM_LPM_L2_CACHE_HSFS_OPEN;
 		break;
 	}
 	return NOTIFY_OK;
@@ -848,6 +851,7 @@
 		msm_lpm_l2.rs_data.default_value = MSM_LPM_L2_CACHE_HSFS_OPEN;
 		msm_lpm_l2.rs_data.value = MSM_LPM_L2_CACHE_HSFS_OPEN;
 	}
+	msm_pm_set_l2_flush_flag(0);
 	return 0;
 fail:
 	return ret;
diff --git a/arch/arm/mach-msm/mdm2.c b/arch/arm/mach-msm/mdm2.c
index 2073856..43c85bb 100644
--- a/arch/arm/mach-msm/mdm2.c
+++ b/arch/arm/mach-msm/mdm2.c
@@ -108,6 +108,8 @@
 	int soft_reset_direction =
 		mdm_drv->pdata->soft_reset_inverted ? 1 : 0;
 
+	mdm_peripheral_disconnect(mdm_drv);
+
 	/* Wait for the modem to complete its power down actions. */
 	for (i = 20; i > 0; i--) {
 		if (gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0)
@@ -127,7 +129,6 @@
 		*/
 		msleep(4000);
 	}
-	mdm_peripheral_disconnect(mdm_drv);
 }
 
 static void mdm_do_first_power_on(struct mdm_modem_drv *mdm_drv)
diff --git a/arch/arm/mach-msm/memory.c b/arch/arm/mach-msm/memory.c
index 4a2fd7c..74c1c4a 100644
--- a/arch/arm/mach-msm/memory.c
+++ b/arch/arm/mach-msm/memory.c
@@ -505,3 +505,14 @@
 out:
 	return 0;
 }
+
+unsigned long get_ddr_size(void)
+{
+	unsigned int i;
+	unsigned long ret = 0;
+
+	for (i = 0; i < meminfo.nr_banks; i++)
+		ret += meminfo.bank[i].size;
+
+	return ret;
+}
diff --git a/arch/arm/mach-msm/modem-8960.c b/arch/arm/mach-msm/modem-8960.c
index 844a78b..f0a123b 100644
--- a/arch/arm/mach-msm/modem-8960.c
+++ b/arch/arm/mach-msm/modem-8960.c
@@ -258,8 +258,7 @@
 {
 	int ret;
 
-	if (!cpu_is_msm8960() && !cpu_is_msm8930() && !cpu_is_msm8930aa() &&
-	    !cpu_is_msm9615() && !cpu_is_msm8627())
+	if (cpu_is_apq8064())
 		return -ENODEV;
 
 	ret = smsm_state_cb_register(SMSM_MODEM_STATE, SMSM_RESET,
diff --git a/arch/arm/mach-msm/modem-ssr-8974.c b/arch/arm/mach-msm/modem-ssr-8974.c
new file mode 100644
index 0000000..fec578f
--- /dev/null
+++ b/arch/arm/mach-msm/modem-ssr-8974.c
@@ -0,0 +1,141 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/interrupt.h>
+#include <linux/module.h>
+#include <linux/err.h>
+
+#include <mach/subsystem_restart.h>
+#include <mach/msm_smsm.h>
+
+static int crash_shutdown;
+static struct subsys_device *modem_ssr_dev;
+
+#define MAX_SSR_REASON_LEN 81U
+#define Q6SS_WDOG_ENABLE		0xFC802004
+#define MSS_Q6SS_WDOG_EXP_IRQ		56
+
+static void log_modem_sfr(void)
+{
+	u32 size;
+	char *smem_reason, reason[MAX_SSR_REASON_LEN];
+
+	smem_reason = smem_get_entry(SMEM_SSR_REASON_MSS0, &size);
+	if (!smem_reason || !size) {
+		pr_err("modem subsystem failure reason: (unknown, smem_get_entry failed).\n");
+		return;
+	}
+	if (!smem_reason[0]) {
+		pr_err("modem subsystem failure reason: (unknown, empty string found).\n");
+		return;
+	}
+
+	strlcpy(reason, smem_reason, min(size, sizeof(reason)));
+	pr_err("modem subsystem failure reason: %s.\n", reason);
+
+	smem_reason[0] = '\0';
+	wmb();
+}
+
+static void restart_modem(void)
+{
+	log_modem_sfr();
+	subsystem_restart("modem");
+}
+
+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 */
+	if (crash_shutdown)
+		return;
+
+	if (new_state & SMSM_RESET) {
+		pr_err("Probable fatal error on the modem.\n");
+		restart_modem();
+	}
+}
+
+static int modem_shutdown(const struct subsys_desc *subsys)
+{
+	return 0;
+}
+
+static int modem_powerup(const struct subsys_desc *subsys)
+{
+	return 0;
+}
+
+void modem_crash_shutdown(const struct subsys_desc *subsys)
+{
+	crash_shutdown = 1;
+	smsm_reset_modem(SMSM_RESET);
+}
+
+static int modem_ramdump(int enable,
+				const struct subsys_desc *crashed_subsys)
+{
+	return 0;
+}
+
+static irqreturn_t modem_wdog_bite_irq(int irq, void *dev_id)
+{
+	pr_err("Watchdog bite received from modem software!\n");
+	restart_modem();
+	return IRQ_HANDLED;
+}
+
+static struct subsys_desc modem_8974 = {
+	.name = "modem",
+	.shutdown = modem_shutdown,
+	.powerup = modem_powerup,
+	.ramdump = modem_ramdump,
+	.crash_shutdown = modem_crash_shutdown
+};
+
+static int __init modem_8974_init(void)
+{
+	int ret;
+
+	ret = smsm_state_cb_register(SMSM_MODEM_STATE, SMSM_RESET,
+		smsm_state_cb, 0);
+
+	if (ret < 0) {
+		pr_err("%s: Unable to register SMSM callback! (%d)\n",
+				__func__, ret);
+		goto out;
+	}
+
+	ret = request_irq(MSS_Q6SS_WDOG_EXP_IRQ, modem_wdog_bite_irq,
+			IRQF_TRIGGER_RISING, "modem_wdog_sw", NULL);
+
+	if (ret < 0) {
+		pr_err("%s: Unable to request q6sw watchdog IRQ. (%d)\n",
+				__func__, ret);
+		goto out;
+	}
+
+	modem_ssr_dev = subsys_register(&modem_8974);
+
+	if (IS_ERR_OR_NULL(modem_ssr_dev)) {
+		pr_err("%s: Unable to reg with subsystem restart. (%ld)\n",
+				__func__, PTR_ERR(modem_ssr_dev));
+		ret = PTR_ERR(modem_ssr_dev);
+		goto out;
+	}
+
+	pr_info("%s: modem subsystem restart driver init'ed.\n", __func__);
+out:
+	return ret;
+}
+
+arch_initcall(modem_8974_init);
diff --git a/arch/arm/mach-msm/mpm-8625.c b/arch/arm/mach-msm/mpm-8625.c
index 3c219be..fe7ffff 100644
--- a/arch/arm/mach-msm/mpm-8625.c
+++ b/arch/arm/mach-msm/mpm-8625.c
@@ -98,6 +98,22 @@
 	[MSM8625_INT_ADSP_A11]		= SMSM_FAKE_IRQ,
 };
 
+static uint16_t msm_bypassed_apps_irqs[] = {
+	MSM8625_INT_CPR_IRQ0,
+};
+
+/* Check IRQ falls into bypassed list are not */
+static bool msm_mpm_bypass_apps_irq(unsigned int irq)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(msm_bypassed_apps_irqs); i++)
+		if (irq == msm_bypassed_apps_irqs[i])
+			return true;
+
+	return false;
+}
+
 static void msm_gic_mask_irq(struct irq_data *d)
 {
 	unsigned int index = GIC_IRQ_INDEX(d->irq);
@@ -106,6 +122,10 @@
 
 	mask = GIC_IRQ_MASK(d->irq);
 
+	/* check whether irq to be bypassed are not */
+	if (msm_mpm_bypass_apps_irq(d->irq))
+		return;
+
 	if (smsm_irq == 0) {
 		msm_gic_irq_idle_disable[index] &= ~mask;
 	} else {
@@ -122,6 +142,10 @@
 
 	mask = GIC_IRQ_MASK(d->irq);
 
+	/* check whether irq to be bypassed are not */
+	if (msm_mpm_bypass_apps_irq(d->irq))
+		return;
+
 	if (smsm_irq == 0) {
 		msm_gic_irq_idle_disable[index] |= mask;
 	} else {
@@ -140,6 +164,10 @@
 		return  -EINVAL;
 	}
 
+	/* check whether irq to be bypassed are not */
+	if (msm_mpm_bypass_apps_irq(d->irq))
+		return 0;
+
 	if (smsm_irq == SMSM_FAKE_IRQ)
 		return 0;
 
diff --git a/arch/arm/mach-msm/msm_bus/Makefile b/arch/arm/mach-msm/msm_bus/Makefile
index 924577f..bdc6fac 100644
--- a/arch/arm/mach-msm/msm_bus/Makefile
+++ b/arch/arm/mach-msm/msm_bus/Makefile
@@ -2,7 +2,7 @@
 # Makefile for msm-bus driver specific files
 #
 obj-y += msm_bus_core.o msm_bus_fabric.o msm_bus_config.o msm_bus_arb.o
-obj-y += msm_bus_bimc.o msm_bus_noc.o
+obj-y += msm_bus_bimc.o msm_bus_noc.o msm_bus_of.o
 obj-$(CONFIG_MSM_RPM) += msm_bus_rpm.o
 obj-$(CONFIG_MSM_RPM_SMD) += msm_bus_rpm_smd.o
 obj-$(CONFIG_ARCH_MSM8X60) += msm_bus_board_8660.o
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_board_8960.c b/arch/arm/mach-msm/msm_bus/msm_bus_board_8960.c
index 9ba9f7b1..70bb406 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_board_8960.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_board_8960.c
@@ -21,7 +21,7 @@
 #include <mach/rpm.h>
 #include "msm_bus_core.h"
 
-#define NMASTERS 45
+#define NMASTERS 55
 #define NSLAVES 75
 #define NFAB_8960 5
 
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_board_8974.c b/arch/arm/mach-msm/msm_bus/msm_bus_board_8974.c
index 265716d..1b8c07e 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_board_8974.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_board_8974.c
@@ -804,7 +804,7 @@
 		.num_tiers = ARRAY_SIZE(tier2),
 		.hw_sel = MSM_BUS_NOC,
 		.perm_mode = NOC_QOS_MODES_ALL_PERM,
-		.mode = NOC_QOS_MODE_FIXED,
+		.mode = NOC_QOS_MODE_BYPASS,
 		.ws = 10000,
 		.qport = qports_oxili,
 		.mas_hw_id = MAS_GFX3D,
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..be3e06f 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
@@ -20,12 +20,12 @@
 #include <linux/clk.h>
 #include <linux/radix-tree.h>
 #include <mach/board.h>
-#include <mach/socinfo.h>
 #include "msm_bus_core.h"
 
 enum {
 	SLAVE_NODE,
 	MASTER_NODE,
+	CLK_NODE,
 };
 
 enum {
@@ -57,7 +57,7 @@
 static int msm_bus_fabric_add_node(struct msm_bus_fabric *fabric,
 	struct msm_bus_inode_info *info)
 {
-	int status = -ENOMEM;
+	int status = -ENOMEM, ctx;
 	MSM_BUS_DBG("msm_bus_fabric_add_node: ID %d Gw: %d\n",
 		info->node_info->priv_id, info->node_info->gateway);
 	status = radix_tree_preload(GFP_ATOMIC);
@@ -71,17 +71,15 @@
 		radix_tree_tag_set(&fabric->fab_tree, info->node_info->priv_id,
 			SLAVE_NODE);
 
-	if (info->node_info->slaveclk[DUAL_CTX]) {
-		info->nodeclk[DUAL_CTX].clk = clk_get_sys("msm_bus",
-			info->node_info->slaveclk[DUAL_CTX]);
-		if (IS_ERR(info->nodeclk[DUAL_CTX].clk)) {
-			MSM_BUS_ERR("Could not get clock for %s\n",
-				info->node_info->slaveclk[DUAL_CTX]);
-			status = -EINVAL;
-			goto out;
+	for (ctx = 0; ctx < NUM_CTX; ctx++) {
+		if (info->node_info->slaveclk[ctx]) {
+			radix_tree_tag_set(&fabric->fab_tree,
+				info->node_info->priv_id, CLK_NODE);
+			break;
 		}
-		info->nodeclk[DUAL_CTX].enable = false;
-		info->nodeclk[DUAL_CTX].dirty = false;
+
+		info->nodeclk[ctx].enable = false;
+		info->nodeclk[ctx].dirty = false;
 	}
 
 out:
@@ -139,7 +137,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 +187,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,10 +341,7 @@
 {
 	struct msm_bus_fabric *fabric = to_msm_bus_fabric(fabdev);
 	void *sel_cdata;
-
-	/* Temporarily stub out arbitration settings for msm8974 */
-	if (machine_is_msm8974())
-		return;
+	int i;
 
 	sel_cdata = fabric->cdata[ctx];
 
@@ -354,8 +355,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;
 }
 
@@ -422,11 +429,7 @@
 	unsigned int i, nfound = 0, status = 0;
 	struct msm_bus_inode_info *info[fabric->pdata->nslaves];
 
-	if (fabric->clk_dirty == false) {
-		MSM_BUS_DBG("No clocks have been touched for fabric: %d\n",
-			fabric->fabdev.id);
-		goto out;
-	} else
+	if (fabric->clk_dirty == true)
 		status = msm_bus_fabric_clk_set(enable, &fabric->info);
 
 	if (status)
@@ -434,9 +437,9 @@
 			fabric->fabdev.id);
 
 	nfound = radix_tree_gang_lookup_tag(&fabric->fab_tree, (void **)&info,
-		fabric->fabdev.id, fabric->pdata->nslaves, SLAVE_NODE);
+		fabric->fabdev.id, fabric->pdata->nslaves, CLK_NODE);
 	if (nfound == 0) {
-		MSM_BUS_DBG("No slaves found for fabric: %d\n",
+		MSM_BUS_DBG("No clock nodes found for fabric: %d\n",
 			fabric->fabdev.id);
 		goto out;
 	}
@@ -490,7 +493,7 @@
 	 */
 	status = msm_bus_fabric_clk_commit(DISABLE, fabric);
 	if (status)
-		MSM_BUS_DBG("Error disabling clocks on fabric: %d\n",
+		MSM_BUS_WARN("Error disabling clocks on fabric: %d\n",
 			fabric->fabdev.id);
 	fabric->clk_dirty = false;
 	return status;
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..049e8c7 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_noc.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_noc.c
@@ -189,10 +189,10 @@
 }
 
 static void noc_set_qos_mode(struct msm_bus_noc_info *ninfo, uint32_t mport,
-	uint8_t mode)
+	uint8_t mode, uint8_t perm_mode)
 {
 	if (mode < NOC_QOS_MODE_MAX &&
-		((1 << mode) & ninfo->mas_modes[mport])) {
+		((1 << mode) & perm_mode)) {
 		uint32_t reg_val;
 
 		reg_val = readl_relaxed(NOC_QOS_MODEn_ADDR(ninfo->base,
@@ -297,13 +297,13 @@
 }
 
 uint8_t msm_bus_noc_get_qos_mode(struct msm_bus_noc_info *ninfo,
-	uint32_t mport)
+	uint32_t mport, uint32_t mode, uint32_t perm_mode)
 {
-	if (NOC_QOS_MODES_ALL_PERM == ninfo->mas_modes[mport])
+	if (NOC_QOS_MODES_ALL_PERM == perm_mode)
 		return readl_relaxed(NOC_QOS_MODEn_ADDR(ninfo->base,
 			mport)) & NOC_QOS_MODEn_MODE_BMSK;
 	else
-		return 31 - __CLZ(ninfo->mas_modes[mport] &
+		return 31 - __CLZ(mode &
 			NOC_QOS_MODES_ALL_PERM);
 }
 
@@ -320,9 +320,9 @@
 }
 
 void msm_bus_noc_get_qos_bw(struct msm_bus_noc_info *ninfo,
-	uint32_t mport, struct msm_bus_noc_qos_bw *qbw)
+	uint32_t mport, uint8_t perm_mode, struct msm_bus_noc_qos_bw *qbw)
 {
-	if (ninfo->mas_modes[mport] & (NOC_QOS_PERM_MODE_LIMITER |
+	if (perm_mode & (NOC_QOS_PERM_MODE_LIMITER |
 		NOC_QOS_PERM_MODE_REGULATOR)) {
 		uint32_t bw_val = readl_relaxed(NOC_QOS_BWn_ADDR(ninfo->
 			base, mport)) & NOC_QOS_BWn_BW_BMSK;
@@ -375,7 +375,7 @@
 		}
 
 		noc_set_qos_mode(ninfo, info->node_info->qport[i], info->
-			node_info->mode);
+			node_info->mode, info->node_info->perm_mode);
 	}
 
 	return 0;
@@ -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_bus/msm_bus_noc.h b/arch/arm/mach-msm/msm_bus/msm_bus_noc.h
index 407d3ec..35af884 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_noc.h
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_noc.h
@@ -64,10 +64,10 @@
 
 void msm_bus_noc_init(struct msm_bus_noc_info *ninfo);
 uint8_t msm_bus_noc_get_qos_mode(struct msm_bus_noc_info *ninfo,
-	uint32_t mport);
+	uint32_t mport, uint32_t mode, uint32_t perm_mode);
 void msm_bus_noc_get_qos_priority(struct msm_bus_noc_info *ninfo,
 	uint32_t mport, struct msm_bus_noc_qos_priority *qprio);
 void msm_bus_noc_get_qos_bw(struct msm_bus_noc_info *ninfo,
-	uint32_t mport, struct msm_bus_noc_qos_bw *qbw);
+	uint32_t mport, uint8_t perm_mode, struct msm_bus_noc_qos_bw *qbw);
 
 #endif /*_ARCH_ARM_MACH_MSM_BUS_NOC_H */
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_of.c b/arch/arm/mach-msm/msm_bus/msm_bus_of.c
new file mode 100644
index 0000000..24b0ce2
--- /dev/null
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_of.c
@@ -0,0 +1,150 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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) "AXI: %s(): " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <mach/msm_bus.h>
+
+/**
+ * msm_bus_cl_get_pdata() - Generate bus client data from device tree
+ * provided by clients.
+ *
+ * of_node: Device tree node to extract information from
+ *
+ * The function returns a valid pointer to the allocated bus-scale-pdata
+ * if the vectors were correctly read from the client's device node.
+ * Any error in reading or parsing the device node will return NULL
+ * to the caller.
+ */
+struct msm_bus_scale_pdata *msm_bus_cl_get_pdata(struct platform_device *pdev)
+{
+	struct device_node *of_node;
+	struct msm_bus_scale_pdata *pdata = NULL;
+	struct msm_bus_paths *usecase = NULL;
+	int i = 0, j, ret, num_usecases = 0, num_paths, len;
+	const uint32_t *vec_arr = NULL;
+	bool mem_err = false;
+
+	if (!pdev) {
+		pr_err("Error: Null Platform device\n");
+		return NULL;
+	}
+
+	of_node = pdev->dev.of_node;
+	pdata = devm_kzalloc(&pdev->dev, sizeof(struct msm_bus_scale_pdata),
+		GFP_KERNEL);
+	if (!pdata) {
+		pr_err("Error: Memory allocation for pdata failed\n");
+		mem_err = true;
+		goto err;
+	}
+
+	ret = of_property_read_string(of_node, "qcom,msm_bus,name",
+		&pdata->name);
+	if (ret) {
+		pr_err("Error: Client name not found\n");
+		goto err;
+	}
+
+	ret = of_property_read_u32(of_node, "qcom,msm_bus,num_cases",
+		&num_usecases);
+	if (ret) {
+		pr_err("Error: num_usecases not found\n");
+		goto err;
+	}
+
+	pdata->num_usecases = num_usecases;
+	ret = of_property_read_u32(of_node, "qcom,msm_bus,active_only",
+		&pdata->active_only);
+	if (ret) {
+		pr_info("active_only flag absent.\n");
+		pr_info("Using dual context by default\n");
+	}
+
+	usecase = devm_kzalloc(&pdev->dev, (sizeof(struct msm_bus_paths) *
+		pdata->num_usecases), GFP_KERNEL);
+	if (!usecase) {
+		pr_err("Error: Memory allocation for paths failed\n");
+		mem_err = true;
+		goto err;
+	}
+
+	ret = of_property_read_u32(of_node, "qcom,msm_bus,num_paths",
+		&num_paths);
+	if (ret) {
+		pr_err("Error: num_paths not found\n");
+		goto err;
+	}
+
+	vec_arr = of_get_property(of_node, "qcom,msm_bus,vectors", &len);
+	if (len != num_usecases * num_paths * sizeof(struct msm_bus_vectors)) {
+		pr_err("Error: Length-error on getting vectors\n");
+		goto err;
+	}
+
+	for (i = 0; i < num_usecases; i++) {
+		usecase[i].num_paths = num_paths;
+		usecase[i].vectors = devm_kzalloc(&pdev->dev, num_paths *
+			sizeof(struct msm_bus_vectors), GFP_KERNEL);
+		if (!usecase[i].vectors) {
+			mem_err = true;
+			pr_err("Error: Mem alloc failure in vectors\n");
+			goto err;
+		}
+
+		for (j = 0; j < num_paths; j++) {
+			int index = ((i * num_paths) + j) * 4;
+			usecase[i].vectors[j].src = be32_to_cpu(vec_arr[index]);
+			usecase[i].vectors[j].dst =
+				be32_to_cpu(vec_arr[index + 1]);
+			usecase[i].vectors[j].ab =
+				be32_to_cpu(vec_arr[index + 2]);
+			usecase[i].vectors[j].ib =
+				be32_to_cpu(vec_arr[index + 3]);
+		}
+	}
+
+	pdata->usecase = usecase;
+	return pdata;
+err:
+	if (mem_err) {
+		for (; i > 0; i--)
+			kfree(usecase[i-1].vectors);
+
+		kfree(usecase);
+		kfree(pdata);
+	}
+
+	return NULL;
+}
+EXPORT_SYMBOL(msm_bus_cl_get_pdata);
+
+/**
+ * msm_bus_cl_clear_pdata() - Clear pdata allocated from device-tree
+ * of_node: Device tree node to extract information from
+ */
+void msm_bus_cl_clear_pdata(struct msm_bus_scale_pdata *pdata)
+{
+	int i;
+
+	for (i = 0; i < pdata->num_usecases; i++)
+		kfree(pdata->usecase[i].vectors);
+
+	kfree(pdata->usecase);
+	kfree(pdata);
+}
+EXPORT_SYMBOL(msm_bus_cl_clear_pdata);
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..e2640a2
--- /dev/null
+++ b/arch/arm/mach-msm/msm_cpr.c
@@ -0,0 +1,928 @@
+/*
+ * 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/moduleparam.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"
+
+/**
+ * Convert the Delay time to Timer Count Register
+ * e.g if frequency is 19200 kHz and delay required is
+ * 20000us, so timer count will be 19200 * 20000 / 1000
+ */
+#define TIMER_COUNT(freq, delay) ((freq * delay) / 1000)
+#define ALL_CPR_IRQ 0x3F
+
+/* Need platform device handle for suspend and resume APIs */
+static struct platform_device *cpr_pdev;
+
+static bool enable = 1;
+module_param(enable, bool, 0644);
+MODULE_PARM_DESC(enable, "CPR Enable");
+
+struct msm_cpr {
+	int curr_osc;
+	int cpr_mode;
+	int prev_mode;
+	uint32_t floor;
+	uint32_t ceiling;
+	bool max_volt_set;
+	void __iomem *base;
+	unsigned int irq;
+	uint32_t cur_Vmin;
+	uint32_t cur_Vmax;
+	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 level_uV = 0, 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.
+	 *
+	 */
+	level_uV = chip_data->turbo_Vmax -
+		(chip_data->tgt_volt_offset * cpr->vp->step_size);
+	pr_debug("tgt_volt_uV = %d\n", level_uV);
+
+	/* 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;
+	}
+
+	/* 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 -= 4 * cpr->vp->step_size;
+	pr_debug("tgt_volt_uV = %d\n", level_uV);
+
+	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_info("%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, ALL_CPR_IRQ);
+	/* 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, ALL_CPR_IRQ);
+	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_uV;
+	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_uV = (new_volt < cpr->cur_Vmax ? new_volt
+				: cpr->cur_Vmax);
+	rc = regulator_set_voltage(cpr->vreg_cx, set_volt_uV,
+					set_volt_uV);
+	if (rc) {
+		pr_err("%s: Voltage set at %duV failed. %d\n",
+			__func__, set_volt_uV, rc);
+		cpr_irq_clr_and_nack(cpr, BIT(4) | BIT(0));
+		return;
+	}
+	pr_info("(railway_voltage: %d uV)\n", set_volt_uV);
+
+	cpr->max_volt_set = (set_volt_uV == cpr->cur_Vmax) ? 1 : 0;
+
+	/* Clear all the interrupts */
+	cpr_write_reg(cpr, RBIF_IRQ_CLEAR, ALL_CPR_IRQ);
+
+	/* 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_uV;
+	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_uV = (new_volt > cpr->cur_Vmin ? new_volt
+				: cpr->cur_Vmin);
+	rc = regulator_set_voltage(cpr->vreg_cx, set_volt_uV,
+					set_volt_uV);
+	if (rc) {
+		pr_err("%s: Voltage at %duV failed %d\n",
+			__func__, set_volt_uV, rc);
+		cpr_irq_clr_and_nack(cpr, BIT(2) | BIT(0));
+		return;
+	}
+	pr_info("(railway_voltage: %d uV)\n", set_volt_uV);
+
+	cpr->max_volt_set = 0;
+
+	/* Clear all the interrupts */
+	cpr_write_reg(cpr, RBIF_IRQ_CLEAR, ALL_CPR_IRQ);
+
+	if (new_volt <= cpr->cur_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 = regulator_get_voltage(cpr->vreg_cx);
+
+	if (action == UP) {
+		/* Clear IRQ, ACK and return if Vdd already at Vmax */
+		if (cpr->max_volt_set == 1) {
+			cpr_write_reg(cpr, RBIF_IRQ_CLEAR, ALL_CPR_IRQ);
+			cpr_write_reg(cpr, RBIF_CONT_NACK_CMD, 0x1);
+			return;
+		}
+
+		/**
+		 * 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)) {
+			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);
+		pr_info("(UP Voltage recommended by CPR: %d uV)\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)) {
+			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);
+		pr_info("(DN Voltage recommended by CPR: %d uV)\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;
+	chip_data->ring_osc_data[cpr->curr_osc].quot =
+		cpr->config->max_quot;
+
+	/**
+	 * 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].quot));
+		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_uV +=  cpr->vp->step_size;
+	tmp_uV = chip_data->calibrated_uV;
+	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 Register for delay between CPR measurements
+	 * This is required to allow the device sufficient time for idle
+	 * power collapse.
+	 */
+	delay_count = TIMER_COUNT(cpr->config->ref_clk_khz,
+					cpr->config->delay_us);
+	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 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;
+	uint32_t quot, new_freq, ctl_reg;
+
+	switch (val) {
+	case CPUFREQ_PRECHANGE:
+		pr_debug("pre freq change notification to cpr\n");
+
+		/* Disable Measurement to stop generation of CPR IRQs */
+		cpr_disable(cpr);
+		/* Disable routing of IRQ to App */
+		cpr_irq_set(cpr, INT_MASK & ~MID_INT, 0);
+		disable_irq(cpr->irq);
+		cpr_write_reg(cpr, RBIF_IRQ_CLEAR, ALL_CPR_IRQ);
+		pr_debug("RBCPR_CTL: 0x%x\n",
+			readl_relaxed(cpr->base + RBCPR_CTL));
+		pr_debug("RBIF_IRQ_STATUS: 0x%x\n",
+			cpr_read_reg(cpr, RBIF_IRQ_STATUS));
+		pr_debug("RBIF_IRQ_EN(0): 0x%x\n",
+			cpr_read_reg(cpr, RBIF_IRQ_EN(cpr->config->irq_line)));
+
+		cpr->prev_mode = cpr->cpr_mode;
+		break;
+
+	case CPUFREQ_POSTCHANGE:
+		pr_debug("post freq change notification to cpr\n");
+		ctl_reg = cpr_read_reg(cpr, RBCPR_CTL);
+		/**
+		 * As per chip characterization data, use max nominal freq
+		 * to calculate quot for all lower frequencies too
+		 */
+		if (freqs->new > cpr->config->max_nom_freq) {
+			new_freq = freqs->new;
+			cpr->cur_Vmin = cpr->config->cpr_mode_data[1].turbo_Vmin;
+			cpr->cur_Vmax = cpr->config->cpr_mode_data[1].turbo_Vmax;
+		} else {
+			new_freq = cpr->config->max_nom_freq;
+			cpr->cur_Vmin = cpr->config->cpr_mode_data[1].nom_Vmin;
+			cpr->cur_Vmax = cpr->config->cpr_mode_data[1].nom_Vmax;
+		}
+
+		/* Configure CPR for the new frequency */
+		quot = cpr->config->get_quot(cpr->config->max_quot,
+						cpr->config->max_freq / 1000,
+						new_freq / 1000);
+		cpr_modify_reg(cpr, RBCPR_GCNT_TARGET(cpr->curr_osc), TARGET_M,
+				quot);
+		pr_debug("RBCPR_GCNT_TARGET(%d): = 0x%x\n", cpr->curr_osc,
+			readl_relaxed(cpr->base +
+					RBCPR_GCNT_TARGET(cpr->curr_osc)));
+		pr_debug("%s: new_freq: %d, set_freq: %d, quot: %d\n", __func__,
+			freqs->new, new_freq, quot);
+
+		enable_irq(cpr->irq);
+		/**
+		 * Enable all interrupts. One of them could be in a disabled
+		 * state if vdd had hit Vmax / Vmin earlier
+		 */
+		cpr_irq_set(cpr, INT_MASK & ~MID_INT, 1);
+
+		/**
+		 * Clear the auto NACK down bit if enabled in the freq.
+		 * transition phase.
+		 */
+		if (ctl_reg & SW_AUTO_CONT_NACK_DN_EN)
+			cpr_modify_reg(cpr, RBCPR_CTL,
+				 SW_AUTO_CONT_NACK_DN_EN_M, 0);
+		pr_debug("RBIF_IRQ_EN(0): 0x%x\n",
+			cpr_read_reg(cpr, RBIF_IRQ_EN(cpr->config->irq_line)));
+		pr_debug("RBCPR_CTL: 0x%x\n",
+			readl_relaxed(cpr->base + RBCPR_CTL));
+		pr_debug("RBIF_IRQ_STATUS: 0x%x\n",
+			cpr_read_reg(cpr, RBIF_IRQ_STATUS));
+		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->config->clk_enable();
+
+	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_write_reg(cpr, RBCPR_CTL,
+		cpr_save_state.rbcpr_ctl);
+
+	enable_irq(cpr->irq);
+	cpr_enable(cpr);
+
+	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;
+
+	/* Disable CPR measurement before IRQ to avoid pending interrupts */
+	cpr_disable(cpr);
+	disable_irq(cpr->irq);
+
+	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);
+
+	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;
+	struct msm_cpr_mode *chip_data;
+
+	if (!enable)
+		return -EPERM;
+
+	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;
+
+	/* Set initial Vmin,Vmax equal to turbo */
+	cpr->cur_Vmin = cpr->config->cpr_mode_data[1].turbo_Vmin;
+	cpr->cur_Vmax = cpr->config->cpr_mode_data[1].turbo_Vmax;
+
+	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);
+
+	chip_data = &cpr->config->cpr_mode_data[cpr->cpr_mode];
+	pr_info("CPR Platform Data (upside_steps: %d) (downside_steps: %d) ",
+		cpr->config->up_threshold, cpr->config->dn_threshold);
+	pr_info("(nominal_voltage: %duV) (turbo_voltage: %duV)\n",
+		cpr->config->cpr_mode_data[NORMAL_MODE].calibrated_uV,
+		cpr->config->cpr_mode_data[TURBO_MODE].calibrated_uV);
+	pr_info("(Current corner: TURBO) (gcnt_target: %d) (quot: %d)\n",
+		chip_data->ring_osc_data[chip_data->ring_osc].gcnt,
+		chip_data->ring_osc_data[chip_data->ring_osc].quot);
+
+	/* 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..e690c63
--- /dev/null
+++ b/arch/arm/mach-msm/msm_cpr.h
@@ -0,0 +1,233 @@
+/*
+ * 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: minimum microvolt level for VP
+ * @max_volt: maximum microvolt level for VP
+ * @default_volt: default microvolt for VP
+ * @step_size: step size of voltage in microvolt
+ */
+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
+ * @quot: target value for ring oscillator
+ */
+struct msm_cpr_osc {
+	int gcnt;
+	uint32_t quot;
+};
+
+/**
+ * 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 turbo_Vmax;
+	uint32_t turbo_Vmin;
+	uint32_t nom_Vmax;
+	uint32_t nom_Vmin;
+	uint32_t calibrated_uV;
+};
+
+/**
+ * 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 max_nom_freq;
+	uint32_t max_freq;
+	uint32_t max_quot;
+	struct msm_cpr_vp_data *vp_data;
+	uint32_t (*get_quot)(uint32_t max_quot, uint32_t max_freq,
+				uint32_t new_freq);
+	void (*clk_enable)(void);
+};
+
+/**
+* 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_memory_dump.c b/arch/arm/mach-msm/msm_memory_dump.c
index 4f48a0d..154b4fe 100644
--- a/arch/arm/mach-msm/msm_memory_dump.c
+++ b/arch/arm/mach-msm/msm_memory_dump.c
@@ -20,7 +20,7 @@
 
 
 /*TODO: Needs to be set to correct value */
-#define DUMP_TABLE_OFFSET	0x20
+#define DUMP_TABLE_OFFSET	0x14
 #define MSM_DUMP_TABLE_VERSION	MK_TABLE(1, 0)
 
 static struct msm_memory_dump mem_dump_data;
@@ -67,7 +67,14 @@
 	table = mem_dump_data.dump_table_ptr;
 	table->version = MSM_DUMP_TABLE_VERSION;
 	mem_dump_data.dump_table_phys = virt_to_phys(table);
-	/* TODO: Need to write physical address of table to IMEM */
+	writel_relaxed(mem_dump_data.dump_table_phys,
+				MSM_IMEM_BASE + DUMP_TABLE_OFFSET);
+	/* TODO: Write to Debug image IMEM.
+	 * Once IMEM issues are resolved MSM_IMEM_BASE
+	 * will have actual mapping.
+	 */
+	writel_relaxed(mem_dump_data.dump_table_phys,
+				MSM_DBG_IMEM_BASE + DUMP_TABLE_OFFSET);
 	atomic_notifier_chain_register(&panic_notifier_list,
 						&msm_memory_dump_blk);
 	printk(KERN_INFO "MSM Memory Dump table set up\n");
diff --git a/arch/arm/mach-msm/msm_rq_stats.c b/arch/arm/mach-msm/msm_rq_stats.c
index 2ea7ed3..ea08f4b 100644
--- a/arch/arm/mach-msm/msm_rq_stats.c
+++ b/arch/arm/mach-msm/msm_rq_stats.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, 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
@@ -11,7 +11,7 @@
  *
  */
 /*
- * Qualcomm MSM Runqueue Stats Interface for Userspace
+ * Qualcomm MSM Runqueue Stats and cpu utilization Interface for Userspace
  */
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -26,12 +26,183 @@
 #include <linux/sched.h>
 #include <linux/spinlock.h>
 #include <linux/rq_stats.h>
+#include <linux/cpufreq.h>
+#include <linux/kernel_stat.h>
+#include <linux/tick.h>
 #include <asm/smp_plat.h>
 
 #define MAX_LONG_SIZE 24
 #define DEFAULT_RQ_POLL_JIFFIES 1
 #define DEFAULT_DEF_TIMER_JIFFIES 5
 
+struct notifier_block freq_transition;
+struct notifier_block cpu_hotplug;
+
+struct cpu_load_data {
+	cputime64_t prev_cpu_idle;
+	cputime64_t prev_cpu_wall;
+	cputime64_t prev_cpu_iowait;
+	unsigned int avg_load_maxfreq;
+	unsigned int samples;
+	unsigned int window_size;
+	unsigned int cur_freq;
+	unsigned int policy_max;
+	cpumask_var_t related_cpus;
+	struct mutex cpu_load_mutex;
+};
+
+static DEFINE_PER_CPU(struct cpu_load_data, cpuload);
+
+static inline u64 get_cpu_idle_time_jiffy(unsigned int cpu, u64 *wall)
+{
+	u64 idle_time;
+	u64 cur_wall_time;
+	u64 busy_time;
+
+	cur_wall_time = jiffies64_to_cputime64(get_jiffies_64());
+
+	busy_time  = kcpustat_cpu(cpu).cpustat[CPUTIME_USER];
+	busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_SYSTEM];
+	busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_IRQ];
+	busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_SOFTIRQ];
+	busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_STEAL];
+	busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_NICE];
+
+	idle_time = cur_wall_time - busy_time;
+	if (wall)
+		*wall = jiffies_to_usecs(cur_wall_time);
+
+	return jiffies_to_usecs(idle_time);
+}
+
+static inline cputime64_t get_cpu_idle_time(unsigned int cpu, cputime64_t *wall)
+{
+	u64 idle_time = get_cpu_idle_time_us(cpu, NULL);
+
+	if (idle_time == -1ULL)
+		return get_cpu_idle_time_jiffy(cpu, wall);
+	else
+		idle_time += get_cpu_iowait_time_us(cpu, wall);
+
+	return idle_time;
+}
+
+static inline cputime64_t get_cpu_iowait_time(unsigned int cpu,
+							cputime64_t *wall)
+{
+	u64 iowait_time = get_cpu_iowait_time_us(cpu, wall);
+
+	if (iowait_time == -1ULL)
+		return 0;
+
+	return iowait_time;
+}
+
+static int update_average_load(unsigned int freq, unsigned int cpu)
+{
+
+	struct cpu_load_data *pcpu = &per_cpu(cpuload, cpu);
+	cputime64_t cur_wall_time, cur_idle_time, cur_iowait_time;
+	unsigned int idle_time, wall_time, iowait_time;
+	unsigned int cur_load, load_at_max_freq;
+
+	cur_idle_time = get_cpu_idle_time(cpu, &cur_wall_time);
+	cur_iowait_time = get_cpu_iowait_time(cpu, &cur_wall_time);
+
+	wall_time = (unsigned int) (cur_wall_time - pcpu->prev_cpu_wall);
+	pcpu->prev_cpu_wall = cur_wall_time;
+
+	idle_time = (unsigned int) (cur_idle_time - pcpu->prev_cpu_idle);
+	pcpu->prev_cpu_idle = cur_idle_time;
+
+	iowait_time = (unsigned int) (cur_iowait_time - pcpu->prev_cpu_iowait);
+	pcpu->prev_cpu_iowait = cur_iowait_time;
+
+	if (idle_time >= iowait_time)
+		idle_time -= iowait_time;
+
+	if (unlikely(!wall_time || wall_time < idle_time))
+		return 0;
+
+	cur_load = 100 * (wall_time - idle_time) / wall_time;
+
+	/* Calculate the scaled load across CPU */
+	load_at_max_freq = (cur_load * freq) / pcpu->policy_max;
+
+	if (!pcpu->avg_load_maxfreq) {
+		/* This is the first sample in this window*/
+		pcpu->avg_load_maxfreq = load_at_max_freq;
+		pcpu->window_size = wall_time;
+	} else {
+		/*
+		 * The is already a sample available in this window.
+		 * Compute weighted average with prev entry, so that we get
+		 * the precise weighted load.
+		 */
+		pcpu->avg_load_maxfreq =
+			((pcpu->avg_load_maxfreq * pcpu->window_size) +
+			(load_at_max_freq * wall_time)) /
+			(wall_time + pcpu->window_size);
+
+		pcpu->window_size += wall_time;
+	}
+
+	return 0;
+}
+
+static unsigned int report_load_at_max_freq(void)
+{
+	int cpu;
+	struct cpu_load_data *pcpu;
+	unsigned int total_load = 0;
+
+	for_each_online_cpu(cpu) {
+		pcpu = &per_cpu(cpuload, cpu);
+		mutex_lock(&pcpu->cpu_load_mutex);
+		update_average_load(pcpu->cur_freq, cpu);
+		total_load += pcpu->avg_load_maxfreq;
+		pcpu->avg_load_maxfreq = 0;
+		mutex_unlock(&pcpu->cpu_load_mutex);
+	}
+	return total_load;
+}
+
+static int cpufreq_transition_handler(struct notifier_block *nb,
+			unsigned long val, void *data)
+{
+	struct cpufreq_freqs *freqs = data;
+	struct cpu_load_data *this_cpu = &per_cpu(cpuload, freqs->cpu);
+	int j;
+
+	switch (val) {
+	case CPUFREQ_POSTCHANGE:
+		for_each_cpu(j, this_cpu->related_cpus) {
+			struct cpu_load_data *pcpu = &per_cpu(cpuload, j);
+			mutex_lock(&pcpu->cpu_load_mutex);
+			update_average_load(freqs->old, freqs->cpu);
+			pcpu->cur_freq = freqs->new;
+			mutex_unlock(&pcpu->cpu_load_mutex);
+		}
+		break;
+	}
+	return 0;
+}
+
+static int cpu_hotplug_handler(struct notifier_block *nb,
+			unsigned long val, void *data)
+{
+	unsigned int cpu = (unsigned long)data;
+	struct cpu_load_data *this_cpu = &per_cpu(cpuload, cpu);
+
+	switch (val) {
+	case CPU_ONLINE:
+	case CPU_ONLINE_FROZEN:
+		this_cpu->avg_load_maxfreq = 0;
+	}
+
+	return NOTIFY_OK;
+}
+
 static void def_work_fn(struct work_struct *work)
 {
 	int64_t diff;
@@ -121,7 +292,18 @@
 	__ATTR(def_timer_ms, S_IWUSR | S_IRUSR, show_def_timer_ms,
 			store_def_timer_ms);
 
+static ssize_t show_cpu_normalized_load(struct kobject *kobj,
+		struct kobj_attribute *attr, char *buf)
+{
+	return snprintf(buf, MAX_LONG_SIZE, "%u\n", report_load_at_max_freq());
+}
+
+static struct kobj_attribute cpu_normalized_load_attr =
+	__ATTR(cpu_normalized_load, S_IWUSR | S_IRUSR, show_cpu_normalized_load,
+			NULL);
+
 static struct attribute *rq_attrs[] = {
+	&cpu_normalized_load_attr.attr,
 	&def_timer_ms_attr.attr,
 	&run_queue_avg_attr.attr,
 	&run_queue_poll_ms_attr.attr,
@@ -157,7 +339,8 @@
 static int __init msm_rq_stats_init(void)
 {
 	int ret;
-
+	int i;
+	struct cpufreq_policy cpu_policy;
 	/* Bail out if this is not an SMP Target */
 	if (!is_smp()) {
 		rq_info.init = 0;
@@ -175,6 +358,20 @@
 	ret = init_rq_attribs();
 
 	rq_info.init = 1;
+
+	for_each_possible_cpu(i) {
+		struct cpu_load_data *pcpu = &per_cpu(cpuload, i);
+		mutex_init(&pcpu->cpu_load_mutex);
+		cpufreq_get_policy(&cpu_policy, i);
+		pcpu->policy_max = cpu_policy.cpuinfo.max_freq;
+		cpumask_copy(pcpu->related_cpus, cpu_policy.cpus);
+	}
+	freq_transition.notifier_call = cpufreq_transition_handler;
+	cpu_hotplug.notifier_call = cpu_hotplug_handler;
+	cpufreq_register_notifier(&freq_transition,
+					CPUFREQ_TRANSITION_NOTIFIER);
+	register_hotcpu_notifier(&cpu_hotplug);
+
 	return ret;
 }
 late_initcall(msm_rq_stats_init);
diff --git a/arch/arm/mach-msm/msm_vp.c b/arch/arm/mach-msm/msm_vp.c
new file mode 100644
index 0000000..4404f0a
--- /dev/null
+++ b/arch/arm/mach-msm/msm_vp.c
@@ -0,0 +1,244 @@
+/*
+ * 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_VREF_SEL_SHIFT	(0x5)
+#define VREG_PD_EN		(1 << 6)
+#define VREG_PD_EN_SHIFT	(0x6)
+#define VREG_LVL_M		(0x1F)
+
+/**
+ * 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 7 bits */
+	cur_plevel &= ~(0x7F);
+	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)
+{
+	uint32_t reg_val, perf_level, vlevel, cur_plevel;
+	uint32_t vref_sel, pd_en;
+	uint32_t cur_voltage;
+
+	reg_val = readl_relaxed(VDD_SVS_PLEVEL_ADDR);
+	perf_level = reg_val & 0x07;
+
+	cur_plevel = readl_relaxed(VDD_APC_PLEVEL(perf_level));
+	vref_sel = (cur_plevel >> VREG_VREF_SEL_SHIFT) & 0x1;
+	pd_en = (cur_plevel >> VREG_PD_EN_SHIFT) & 0x1;
+	vlevel = cur_plevel & VREG_LVL_M;
+
+	cur_voltage = (750000 + (pd_en * 12500) +
+				(vlevel * 25000)) * (2 - vref_sel);
+	return cur_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 a65cd21..48a57cd 100644
--- a/arch/arm/mach-msm/msm_watchdog_v2.c
+++ b/arch/arm/mach-msm/msm_watchdog_v2.c
@@ -17,8 +17,11 @@
 #include <linux/workqueue.h>
 #include <linux/slab.h>
 #include <linux/jiffies.h>
+#include <linux/mutex.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/percpu.h>
 #include <linux/of.h>
 #include <linux/cpu.h>
 #include <linux/platform_device.h>
@@ -36,6 +39,7 @@
 
 #define MASK_SIZE		32
 #define SCM_SET_REGSAVE_CMD	0x2
+#define SCM_SVC_SEC_WDOG_DIS	0x7
 
 struct msm_watchdog_data {
 	unsigned int __iomem phys_base;
@@ -52,8 +56,11 @@
 	unsigned long long min_slack_ns;
 	void *scm_regsave;
 	cpumask_t alive_mask;
+	struct mutex disable_lock;
 	struct work_struct init_dogwork_struct;
 	struct delayed_work dogwork_struct;
+	bool irq_ppi;
+	struct msm_watchdog_data __percpu **wdog_cpu_dd;
 	struct notifier_block panic_blk;
 };
 
@@ -73,30 +80,15 @@
 static long WDT_HZ = 32765;
 module_param(WDT_HZ, long, 0);
 
-/*
- * If the watchdog is enabled at bootup (enable=1),
- * the runtime_disable sysfs node at
- * /sys/module/msm_watchdog/parameters/runtime_disable
- * can be used to deactivate the watchdog.
- * This is a one-time setting. The watchdog
- * cannot be re-enabled once it is disabled.
- */
-static int runtime_disable;
-static int wdog_enable_set(const char *val, struct kernel_param *kp);
-module_param_call(runtime_disable, wdog_enable_set, param_get_int,
-			&runtime_disable, 0644);
-
 static void pet_watchdog_work(struct work_struct *work);
 static void init_watchdog_work(struct work_struct *work);
 
 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)
@@ -140,14 +132,99 @@
 	}
 	return NOTIFY_DONE;
 }
-/*
- * TODO: implement enable/disable.
- */
-static int wdog_enable_set(const char *val, struct kernel_param *kp)
+
+static void wdog_disable(struct msm_watchdog_data *wdog_dd)
 {
-	return 0;
+	__raw_writel(0, wdog_dd->base + WDT0_EN);
+	mb();
+	if (wdog_dd->irq_ppi) {
+		disable_percpu_irq(wdog_dd->bark_irq);
+		free_percpu_irq(wdog_dd->bark_irq, wdog_dd->wdog_cpu_dd);
+	} else
+		devm_free_irq(wdog_dd->dev, wdog_dd->bark_irq, wdog_dd);
+	enable = 0;
+	/*Ensure all cpus see update to enable*/
+	smp_mb();
+	atomic_notifier_chain_unregister(&panic_notifier_list,
+						&wdog_dd->panic_blk);
+	cancel_delayed_work_sync(&wdog_dd->dogwork_struct);
+	/* may be suspended after the first write above */
+	__raw_writel(0, wdog_dd->base + WDT0_EN);
+	mb();
+	pr_info("MSM Apps Watchdog deactivated.\n");
 }
 
+struct wdog_disable_work_data {
+	struct work_struct work;
+	struct completion complete;
+	struct msm_watchdog_data *wdog_dd;
+};
+
+static void wdog_disable_work(struct work_struct *work)
+{
+	struct wdog_disable_work_data *work_data =
+		container_of(work, struct wdog_disable_work_data, work);
+	wdog_disable(work_data->wdog_dd);
+	complete(&work_data->complete);
+}
+
+static ssize_t wdog_disable_get(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int ret;
+	struct msm_watchdog_data *wdog_dd = dev_get_drvdata(dev);
+
+	mutex_lock(&wdog_dd->disable_lock);
+	ret = snprintf(buf, PAGE_SIZE, "%d\n", enable == 0 ? 1 : 0);
+	mutex_unlock(&wdog_dd->disable_lock);
+	return ret;
+}
+
+static ssize_t wdog_disable_set(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	int ret;
+	u8 disable;
+	struct wdog_disable_work_data work_data;
+	struct msm_watchdog_data *wdog_dd = dev_get_drvdata(dev);
+
+	ret = kstrtou8(buf, 10, &disable);
+	if (ret) {
+		dev_err(wdog_dd->dev, "invalid user input\n");
+		return ret;
+	}
+	if (disable == 1) {
+		mutex_lock(&wdog_dd->disable_lock);
+		if (enable == 0) {
+			pr_info("MSM Apps Watchdog already disabled\n");
+			mutex_unlock(&wdog_dd->disable_lock);
+			return count;
+		}
+		disable = 1;
+		ret = scm_call(SCM_SVC_BOOT, SCM_SVC_SEC_WDOG_DIS, &disable,
+						sizeof(disable), NULL, 0);
+		if (ret) {
+			dev_err(wdog_dd->dev,
+					"Failed to deactivate secure wdog\n");
+			mutex_unlock(&wdog_dd->disable_lock);
+			return -EIO;
+		}
+		work_data.wdog_dd = wdog_dd;
+		init_completion(&work_data.complete);
+		INIT_WORK_ONSTACK(&work_data.work, wdog_disable_work);
+		schedule_work_on(0, &work_data.work);
+		wait_for_completion(&work_data.complete);
+		mutex_unlock(&wdog_dd->disable_lock);
+	} else {
+		pr_err("invalid operation, only disable = 1 supported\n");
+		return -EINVAL;
+	}
+	return count;
+}
+
+static DEVICE_ATTR(disable, S_IWUSR | S_IRUSR, wdog_disable_get,
+							wdog_disable_set);
 
 static void pet_watchdog(struct msm_watchdog_data *wdog_dd)
 {
@@ -197,33 +274,38 @@
 						struct msm_watchdog_data,
 							dogwork_struct);
 	delay_time = msecs_to_jiffies(wdog_dd->pet_time);
-	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) {
+		if (wdog_dd->do_ipi_ping)
+			ping_other_cpus(wdog_dd);
+		pet_watchdog(wdog_dd);
+	}
+	/* Check again before scheduling *
+	 * Could have been changed on other cpu */
 	if (enable)
-		schedule_delayed_work(&wdog_dd->dogwork_struct,
+		schedule_delayed_work_on(0, &wdog_dd->dogwork_struct,
 							delay_time);
 }
 
 static int msm_watchdog_remove(struct platform_device *pdev)
 {
+	struct wdog_disable_work_data work_data;
 	struct msm_watchdog_data *wdog_dd =
 			(struct msm_watchdog_data *)platform_get_drvdata(pdev);
+
+	mutex_lock(&wdog_dd->disable_lock);
 	if (enable) {
-		__raw_writel(0, wdog_dd->base + WDT0_EN);
-		mb();
-		enable = 0;
-		/*
-		 * TODO: Not sure if we need to call into TZ to disable
-		 * secure wdog.
-		 */
-		/* In case we got suspended mid-exit */
-		__raw_writel(0, wdog_dd->base + WDT0_EN);
+		work_data.wdog_dd = wdog_dd;
+		init_completion(&work_data.complete);
+		INIT_WORK_ONSTACK(&work_data.work, wdog_disable_work);
+		schedule_work_on(0, &work_data.work);
+		wait_for_completion(&work_data.complete);
 	}
+	mutex_unlock(&wdog_dd->disable_lock);
+	device_remove_file(wdog_dd->dev, &dev_attr_disable);
+	if (wdog_dd->irq_ppi)
+		free_percpu(wdog_dd->wdog_cpu_dd);
 	printk(KERN_INFO "MSM Watchdog Exit - Deactivated\n");
-	kzfree(wdog_dd);
+	kfree(wdog_dd);
 	return 0;
 }
 
@@ -246,6 +328,13 @@
 	return IRQ_HANDLED;
 }
 
+static irqreturn_t wdog_ppi_bark(int irq, void *dev_id)
+{
+	struct msm_watchdog_data *wdog_dd =
+			*(struct msm_watchdog_data **)(dev_id);
+	return wdog_bark_handler(irq, wdog_dd);
+}
+
 static void configure_bark_dump(struct msm_watchdog_data *wdog_dd)
 {
 	int ret;
@@ -290,7 +379,34 @@
 						struct msm_watchdog_data,
 							init_dogwork_struct);
 	unsigned long delay_time;
+	int error;
 	u64 timeout;
+	int ret;
+
+	if (wdog_dd->irq_ppi) {
+		wdog_dd->wdog_cpu_dd = alloc_percpu(struct msm_watchdog_data *);
+		if (!wdog_dd->wdog_cpu_dd) {
+			dev_err(wdog_dd->dev, "fail to allocate cpu data\n");
+			return;
+		}
+		*__this_cpu_ptr(wdog_dd->wdog_cpu_dd) = wdog_dd;
+		ret = request_percpu_irq(wdog_dd->bark_irq, wdog_ppi_bark,
+					"apps_wdog_bark",
+					wdog_dd->wdog_cpu_dd);
+		if (ret) {
+			dev_err(wdog_dd->dev, "failed to request bark irq\n");
+			free_percpu(wdog_dd->wdog_cpu_dd);
+			return;
+		}
+	} else {
+		ret = devm_request_irq(wdog_dd->dev, wdog_dd->bark_irq,
+				wdog_bark_handler, IRQF_TRIGGER_RISING,
+						"apps_wdog_bark", wdog_dd);
+		if (ret) {
+			dev_err(wdog_dd->dev, "failed to request bark irq\n");
+			return;
+		}
+	}
 	delay_time = msecs_to_jiffies(wdog_dd->pet_time);
 	wdog_dd->min_slack_ticks = UINT_MAX;
 	wdog_dd->min_slack_ns = ULLONG_MAX;
@@ -302,12 +418,17 @@
 	wdog_dd->panic_blk.notifier_call = panic_wdog_handler;
 	atomic_notifier_chain_register(&panic_notifier_list,
 				       &wdog_dd->panic_blk);
-	schedule_delayed_work(&wdog_dd->dogwork_struct, delay_time);
-
+	mutex_init(&wdog_dd->disable_lock);
+	schedule_delayed_work_on(0, &wdog_dd->dogwork_struct, delay_time);
 	__raw_writel(1, wdog_dd->base + WDT0_EN);
 	__raw_writel(1, wdog_dd->base + WDT0_RST);
 	wdog_dd->last_pet = sched_clock();
-	printk(KERN_INFO "MSM Watchdog Initialized\n");
+	error = device_create_file(wdog_dd->dev, &dev_attr_disable);
+	if (error)
+		dev_err(wdog_dd->dev, "cannot create sysfs attribute\n");
+	if (wdog_dd->irq_ppi)
+		enable_percpu_irq(wdog_dd->bark_irq, 0);
+	dev_info(wdog_dd->dev, "MSM Watchdog Initialized\n");
 	return;
 }
 
@@ -381,6 +502,7 @@
 								__func__);
 		return -ENXIO;
 	}
+	pdata->irq_ppi = irq_is_per_cpu(pdata->bark_irq);
 	dump_pdata(pdata);
 	return 0;
 }
@@ -400,13 +522,6 @@
 		goto err;
 	wdog_dd->dev = &pdev->dev;
 	platform_set_drvdata(pdev, wdog_dd);
-	ret = devm_request_irq(&pdev->dev, wdog_dd->bark_irq, wdog_bark_handler,
-				IRQF_TRIGGER_RISING, "apps_wdog_bark", wdog_dd);
-	if (ret) {
-		dev_err(&pdev->dev, "failed to request bark irq\n");
-		ret = -ENXIO;
-		goto err;
-	}
 	cpumask_clear(&wdog_dd->alive_mask);
 	INIT_WORK(&wdog_dd->init_dogwork_struct, init_watchdog_work);
 	INIT_DELAYED_WORK(&wdog_dd->dogwork_struct, pet_watchdog_work);
diff --git a/arch/arm/mach-msm/ocmem.c b/arch/arm/mach-msm/ocmem.c
index a9c3f4c..793fcc5 100644
--- a/arch/arm/mach-msm/ocmem.c
+++ b/arch/arm/mach-msm/ocmem.c
@@ -63,6 +63,27 @@
 	"other_os",
 };
 
+/* Must be in sync with enum ocmem_zstat_item */
+static const char *zstat_names[NR_OCMEM_ZSTAT_ITEMS] = {
+	"Allocation requests",
+	"Synchronous allocations",
+	"Ranged allocations",
+	"Asynchronous allocations",
+	"Allocation failures",
+	"Allocations grown",
+	"Allocations freed",
+	"Allocations shrunk",
+	"OCMEM maps",
+	"Map failures",
+	"OCMEM unmaps",
+	"Unmap failures",
+	"Transfers to OCMEM",
+	"Transfers to DDR",
+	"Transfer failures",
+	"Evictions",
+	"Restorations",
+};
+
 struct ocmem_quota_table {
 	const char *name;
 	int id;
@@ -103,7 +124,7 @@
 const char *get_name(int id)
 {
 	if (!check_id(id))
-		return NULL;
+		return "Unknown";
 	return client_names[id];
 }
 
@@ -126,6 +147,32 @@
 	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;
+}
+
+inline void inc_ocmem_stat(struct ocmem_zone *z,
+				enum ocmem_zstat_item item)
+{
+	if (!z)
+		return;
+	atomic_long_inc(&z->z_stat[item]);
+}
+
+inline unsigned long get_ocmem_stat(struct ocmem_zone *z,
+				enum ocmem_zstat_item item)
+{
+	if (!z)
+		return 0;
+	else
+		return atomic_long_read(&z->z_stat[item]);
+}
+
 static struct ocmem_plat_data *parse_static_config(struct platform_device *pdev)
 {
 	struct ocmem_plat_data *pdata = NULL;
@@ -287,6 +334,65 @@
 }
 #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");
+}
+
+/* Block-Remapper Clock Operations */
+int ocmem_enable_br_clock(void)
+{
+	int ret;
+
+	ret = clk_prepare_enable(ocmem_pdata->br_clk);
+
+	if (ret) {
+		pr_err("ocmem: Failed to enable br clock\n");
+		return ret;
+	}
+	pr_debug("ocmem: Enabled br clock\n");
+	return 0;
+}
+
+void ocmem_disable_br_clock(void)
+{
+	clk_disable_unprepare(ocmem_pdata->br_clk);
+	pr_debug("ocmem: Disabled br clock\n");
+}
+
 static struct ocmem_plat_data *parse_dt_config(struct platform_device *pdev)
 {
 	struct device   *dev = &pdev->dev;
@@ -426,6 +532,60 @@
 	return NULL;
 }
 
+static int ocmem_zones_show(struct seq_file *f, void *dummy)
+{
+	unsigned i = 0;
+	for (i = OCMEM_GRAPHICS; i < OCMEM_CLIENT_MAX; i++) {
+		struct ocmem_zone *z = get_zone(i);
+		if (z && z->active == true)
+			seq_printf(f, "zone %s\t:0x%08lx - 0x%08lx (%4ld KB)\n",
+				get_name(z->owner), z->z_start, z->z_end - 1,
+				(z->z_end - z->z_start)/SZ_1K);
+	}
+	return 0;
+}
+
+static int ocmem_zones_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, ocmem_zones_show, inode->i_private);
+}
+
+static const struct file_operations zones_show_fops = {
+	.open = ocmem_zones_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = seq_release,
+};
+
+static int ocmem_stats_show(struct seq_file *f, void *dummy)
+{
+	unsigned i = 0;
+	unsigned j = 0;
+	for (i = OCMEM_GRAPHICS; i < OCMEM_CLIENT_MAX; i++) {
+		struct ocmem_zone *z = get_zone(i);
+		if (z && z->active == true) {
+			seq_printf(f, "zone %s:\n", get_name(z->owner));
+			for (j = 0 ; j < ARRAY_SIZE(zstat_names); j++) {
+				seq_printf(f, "\t %s: %lu\n", zstat_names[j],
+					get_ocmem_stat(z, j));
+			}
+		}
+	}
+	return 0;
+}
+
+static int ocmem_stats_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, ocmem_stats_show, inode->i_private);
+}
+
+static const struct file_operations stats_show_fops = {
+	.open = ocmem_stats_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = seq_release,
+};
+
 static int ocmem_zone_init(struct platform_device *pdev)
 {
 
@@ -444,6 +604,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,
@@ -501,6 +662,9 @@
 			z_ops->allocate = allocate_head;
 			z_ops->free = free_head;
 		}
+		/* zap the counters */
+		memset(zone->z_stat, 0 , sizeof(zone->z_stat));
+		zone->active = true;
 		active_zones++;
 
 		if (active_zones == 1)
@@ -508,17 +672,75 @@
 
 		pr_info(" zone %s\t: 0x%08lx - 0x%08lx (%4ld KB)\n",
 				client_names[part->id], zone->z_start,
-				zone->z_end, part->p_size/SZ_1K);
+				zone->z_end - 1, part->p_size/SZ_1K);
+	}
+
+	if (!debugfs_create_file("zones", S_IRUGO, pdata->debug_node,
+					NULL, &zones_show_fops)) {
+		dev_err(dev, "Unable to create debugfs node for zones\n");
+		return -EBUSY;
+	}
+
+	if (!debugfs_create_file("stats", S_IRUGO, pdata->debug_node,
+					NULL, &stats_show_fops)) {
+		dev_err(dev, "Unable to create debugfs node for stats\n");
+		return -EBUSY;
 	}
 
 	dev_dbg(dev, "Total active zones = %d\n", active_zones);
 	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 ocmem_debugfs_init(struct platform_device *pdev)
+{
+	struct dentry *debug_dir = NULL;
+	struct ocmem_plat_data *pdata = platform_get_drvdata(pdev);
+
+	debug_dir = debugfs_create_dir("ocmem", NULL);
+	if (!debug_dir || IS_ERR(debug_dir)) {
+		pr_err("ocmem: Unable to create debugfs root\n");
+		return PTR_ERR(debug_dir);
+	}
+
+	pdata->debug_node =  debug_dir;
+	return 0;
+}
+
+static void __devexit ocmem_debugfs_exit(struct platform_device *pdev)
+{
+	struct ocmem_plat_data *pdata = platform_get_drvdata(pdev);
+	debugfs_remove_recursive(pdata->debug_node);
+}
+
 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;
+	struct clk *ocmem_br_clk = NULL;
 
 	if (!pdev->dev.of_node) {
 		dev_info(dev, "Missing Configuration in Device Tree\n");
@@ -537,8 +759,42 @@
 
 	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_br_clk = devm_clk_get(dev, "br_clk");
+
+	if (IS_ERR(ocmem_br_clk)) {
+		dev_err(dev, "Unable to get the BR clock\n");
+		return PTR_ERR(ocmem_br_clk);
+	}
+
+	ocmem_pdata->core_clk = ocmem_core_clk;
+	ocmem_pdata->iface_clk = ocmem_iface_clk;
+	ocmem_pdata->br_clk = ocmem_br_clk;
+
 	platform_set_drvdata(pdev, ocmem_pdata);
 
+	if (ocmem_debugfs_init(pdev))
+		return -EBUSY;
+
 	if (ocmem_core_init(pdev))
 		return -EBUSY;
 
@@ -548,27 +804,24 @@
 	if (ocmem_notifier_init())
 		return -EBUSY;
 
-	if (ocmem_sched_init())
+	if (ocmem_sched_init(pdev))
 		return -EBUSY;
 
-	ocmem_region_vbase = devm_ioremap_nocache(dev, OCMEM_REGION_CTL_BASE,
-							OCMEM_REGION_CTL_SIZE);
-	if (!ocmem_region_vbase)
-		return -EBUSY;
-
-	/* 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;
 }
 
 static int __devexit msm_ocmem_remove(struct platform_device *pdev)
 {
+	ocmem_debugfs_exit(pdev);
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/ocmem_api.c b/arch/arm/mach-msm/ocmem_api.c
index a5aed5e..6e094fd 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);
@@ -125,6 +131,7 @@
 	return __ocmem_allocate_range(client_id, size, size,
 					size, can_block, can_wait);
 }
+EXPORT_SYMBOL(ocmem_allocate);
 
 struct ocmem_buf *ocmem_allocate_nowait(int client_id, unsigned long size)
 {
@@ -136,6 +143,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);
@@ -150,6 +163,7 @@
 	return __ocmem_allocate_range(client_id, size, size,
 					size, can_block, can_wait);
 }
+EXPORT_SYMBOL(ocmem_allocate_nowait);
 
 struct ocmem_buf *ocmem_allocate_range(int client_id, unsigned long min,
 		unsigned long goal, unsigned long step)
@@ -162,6 +176,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",
@@ -184,6 +204,7 @@
 	return __ocmem_allocate_range(client_id, min, goal,
 				step, can_block, can_wait);
 }
+EXPORT_SYMBOL(ocmem_allocate_range);
 
 struct ocmem_buf *ocmem_allocate_nb(int client_id, unsigned long size)
 {
@@ -202,6 +223,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);
@@ -218,6 +245,7 @@
 						can_block, can_wait);
 
 }
+EXPORT_SYMBOL(ocmem_allocate_nb);
 
 int ocmem_free(int client_id, struct ocmem_buf *buffer)
 {
@@ -226,6 +254,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;
@@ -233,6 +267,7 @@
 
 	return __ocmem_free(client_id, buffer);
 }
+EXPORT_SYMBOL(ocmem_free);
 
 int ocmem_shrink(int client_id, struct ocmem_buf *buffer, unsigned long len)
 {
@@ -240,8 +275,16 @@
 		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);
 }
+EXPORT_SYMBOL(ocmem_shrink);
 
 int pre_validate_chunk_list(struct ocmem_map_list *list)
 {
@@ -282,6 +325,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",
@@ -307,6 +356,7 @@
 	mutex_unlock(&handle->handle_mutex);
 	return ret;
 }
+EXPORT_SYMBOL(ocmem_map);
 
 int ocmem_unmap(int client_id, struct ocmem_buf *buffer,
 			struct ocmem_map_list *list)
@@ -320,6 +370,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",
@@ -341,6 +397,7 @@
 	mutex_unlock(&handle->handle_mutex);
 	return ret;
 }
+EXPORT_SYMBOL(ocmem_unmap);
 
 unsigned long get_max_quota(int client_id)
 {
@@ -378,6 +435,7 @@
 	mutex_unlock(&ocmem_eviction_lock);
 	return ret;
 }
+EXPORT_SYMBOL(ocmem_evict);
 
 int ocmem_restore(int client_id)
 {
@@ -399,6 +457,7 @@
 	mutex_unlock(&ocmem_eviction_lock);
 	return ret;
 }
+EXPORT_SYMBOL(ocmem_restore);
 
 /* Wrappers until power control is transitioned to clients */
 enum ocmem_power_state ocmem_get_power_state(int client_id,
diff --git a/arch/arm/mach-msm/ocmem_core.c b/arch/arm/mach-msm/ocmem_core.c
index d8cfefc..5a85eec 100644
--- a/arch/arm/mach-msm/ocmem_core.c
+++ b/arch/arm/mach-msm/ocmem_core.c
@@ -38,6 +38,7 @@
 	unsigned psgsc_ctrl;
 	bool interleaved;
 	unsigned int mode;
+	atomic_t mode_counter;
 	unsigned int num_macros;
 	struct ocmem_hw_macro *macro;
 	struct msm_rpm_request *rpm_req;
@@ -50,16 +51,20 @@
 
 #define OCMEM_V1_REGIONS 3
 #define OCMEM_V1_MACROS 8
+#define OCMEM_V1_MACRO_SZ (SZ_64K)
 
 #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 OC_REGION_MODE_CTL (0x1000)
+#define OC_GFX_MPU_START (0x1004)
+#define OC_GFX_MPU_END (0x1008)
 
 #define NUM_PORTS_MASK (0xF << 0)
 #define NUM_PORTS_SHIFT (0)
+#define GFX_MPU_SHIFT (12)
 
 #define NUM_MACROS_MASK (0xF << 8)
 #define NUM_MACROS_SHIFT (8)
@@ -72,7 +77,7 @@
 #define CORE_ON (0x2)
 #define PERI_ON (0x1)
 #define CLK_OFF (0x4)
-#define MACRO_ON (CORE_ON|PERI_ON)
+#define MACRO_ON (0x0)
 #define MACRO_SLEEP_RETENTION (CLK_OFF|CORE_ON)
 #define MACRO_SLEEP_RETENTION_PERI_ON (CLK_OFF|MACRO_ON)
 #define MACRO_OFF (CLK_OFF)
@@ -92,7 +97,7 @@
 #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_ON REGION_NORMAL_PASSTHROUGH
 #define REGION_DEFAULT_RETENTION REGION_SLEEP_PERI_OFF
 
 enum rpm_macro_state {
@@ -165,6 +170,8 @@
 	else
 		rc = ocmem_write(new_state,
 					ocmem_base + PSCGC_CTL_n(region_num));
+	/* Barrier to commit the region state */
+	mb();
 	return 0;
 }
 
@@ -324,6 +331,9 @@
 	/* 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++) {
+			pr_debug("aggregated region state %x\n", r_state);
+			pr_debug("macro %d\n state %x\n", i,
+						region->macro[i].m_state);
 			r_state &= ~M_PSCGC_CTL_n(i);
 			r_state |= region->macro[i].m_state << (i * 4);
 		}
@@ -383,7 +393,218 @@
 	return 0;
 }
 
+
+static int switch_region_mode(unsigned long offset, unsigned long len,
+						enum region_mode new_mode)
+{
+	unsigned region_start = num_regions;
+	unsigned region_end = num_regions;
+	int i = 0;
+
+	if (offset < 0)
+		return -EINVAL;
+
+	if (len < region_size)
+		return -EINVAL;
+
+	pr_debug("ocmem: mode_transistion to %x\n", new_mode);
+
+	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;
+
+	for (i = region_start; i <= region_end; i++) {
+		struct ocmem_hw_region *region = &region_ctrl[i];
+		if (region->mode == MODE_DEFAULT) {
+			/* No prior mode programming on this region */
+			/* Set the region to its new mode */
+			region->mode = new_mode;
+			atomic_inc(&region->mode_counter);
+			pr_debug("Region  (%d) switching to mode %d\n",
+					i, new_mode);
+			continue;
+		} else if (region->mode != new_mode) {
+			/* The region is currently set to a different mode */
+			if (new_mode == MODE_DEFAULT) {
+				if (atomic_dec_and_test
+						(&region->mode_counter)) {
+					region->mode = MODE_DEFAULT;
+					pr_debug("Region (%d) restoring to default mode\n",
+								i);
+				} else {
+					/* More than 1 client in region */
+					/* Cannot move to default mode */
+					pr_debug("Region (%d) using current mode %d\n",
+							i, region->mode);
+					continue;
+				}
+			} else {
+				/* Do not switch modes */
+				pr_err("Region (%d) requested mode %x conflicts with current\n",
+							i, new_mode);
+				goto mode_switch_fail;
+			}
+		}
+	}
+	return 0;
+
+mode_switch_fail:
+	return -EINVAL;
+}
+
+#ifdef CONFIG_MSM_OCMEM_NONSECURE
+
+static int commit_region_modes(void)
+{
+	uint32_t region_mode_ctrl = 0x0;
+	unsigned pos = 0;
+	unsigned i = 0;
+
+	for (i = 0; i < num_regions; i++) {
+		struct ocmem_hw_region *region = &region_ctrl[i];
+		pos = i << 2;
+		if (region->mode == THIN_MODE)
+			region_mode_ctrl |= BIT(pos);
+	}
+	pr_debug("ocmem_region_mode_control %x\n", region_mode_ctrl);
+	ocmem_write(region_mode_ctrl, ocmem_base + OC_REGION_MODE_CTL);
+	/* Barrier to commit the region mode */
+	mb();
+	return 0;
+}
+
+static int ocmem_gfx_mpu_set(unsigned long offset, unsigned long len)
+{
+	int mpu_start = 0x0;
+	int mpu_end = 0x0;
+
+	if (offset)
+		mpu_start = (offset >> GFX_MPU_SHIFT) - 1;
+	if (mpu_start < 0)
+		/* Avoid underflow */
+		mpu_start = 0;
+	mpu_end = ((offset+len) >> GFX_MPU_SHIFT) - 1;
+	BUG_ON(mpu_end < 0);
+
+	pr_debug("ocmem: mpu: start %x end %x\n", mpu_start, mpu_end);
+	ocmem_write(mpu_start << GFX_MPU_SHIFT, ocmem_base + OC_GFX_MPU_START);
+	ocmem_write(mpu_end << GFX_MPU_SHIFT, ocmem_base + OC_GFX_MPU_END);
+	return 0;
+}
+
+static void ocmem_gfx_mpu_remove(void)
+{
+	ocmem_write(0x0, ocmem_base + OC_GFX_MPU_START);
+	ocmem_write(0x0, ocmem_base + OC_GFX_MPU_END);
+}
+
+static int do_lock(enum ocmem_client id, unsigned long offset,
+			unsigned long len, enum region_mode mode)
+{
+	return 0;
+}
+
+static int do_unlock(enum ocmem_client id, unsigned long offset,
+			unsigned long len)
+{
+	ocmem_clear(offset, len);
+	return 0;
+}
+#else
+static int ocmem_gfx_mpu_set(unsigned long offset, unsigned long len)
+{
+	return 0;
+}
+
+static void ocmem_gfx_mpu_remove(void)
+{
+}
+
+static int commit_region_modes(void)
+{
+	return 0;
+}
+
+static int do_lock(enum ocmem_client id, unsigned long offset,
+			unsigned long len, enum region_mode mode)
+{
+	return 0;
+}
+
+static int do_unlock(enum ocmem_client id, unsigned long offset,
+			unsigned long len)
+{
+	return 0;
+}
+#endif /* CONFIG_MSM_OCMEM_NONSECURE */
+
+int ocmem_lock(enum ocmem_client id, unsigned long offset, unsigned long len,
+					enum region_mode mode)
+{
+
+	if (len < OCMEM_MIN_ALLOC) {
+		pr_err("ocmem: Invalid len %lx for lock\n", len);
+		return -EINVAL;
+	}
+
+	if (id == OCMEM_GRAPHICS)
+		ocmem_gfx_mpu_set(offset, len);
+
+	mutex_lock(&region_ctrl_lock);
+
+	if (switch_region_mode(offset, len, mode) < 0)
+			goto switch_region_fail;
+
+	commit_region_modes();
+
+	do_lock(id, offset, len, mode);
+
+	mutex_unlock(&region_ctrl_lock);
+	return 0;
+
+switch_region_fail:
+	mutex_unlock(&region_ctrl_lock);
+	return -EINVAL;
+}
+
+int ocmem_unlock(enum ocmem_client id, unsigned long offset, unsigned long len)
+{
+	if (id == OCMEM_GRAPHICS)
+		ocmem_gfx_mpu_remove();
+
+	mutex_lock(&region_ctrl_lock);
+	do_unlock(id, offset, len);
+	switch_region_mode(offset, len , MODE_DEFAULT);
+	commit_region_modes();
+	mutex_unlock(&region_ctrl_lock);
+	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;
+
+	rc = ocmem_enable_br_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)
 {
@@ -408,6 +629,11 @@
 {
 	return 0;
 }
+
+static int ocmem_core_set_default_state(void)
+{
+	return 0;
+}
 #endif
 
 #if defined(CONFIG_MSM_OCMEM_POWER_DEBUG)
@@ -535,6 +761,7 @@
 	unsigned start_m = num_banks;
 	unsigned end_m = num_banks;
 	unsigned long region_offset = 0;
+	int rc = 0;
 
 	if (offset < 0)
 		return -EINVAL;
@@ -555,6 +782,14 @@
 		(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++) {
@@ -605,9 +840,11 @@
 
 	}
 	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);
@@ -632,6 +869,81 @@
 	return switch_power_state(id, offset, len, REGION_DEFAULT_RETENTION);
 }
 
+static int ocmem_power_show_sw_state(struct seq_file *f, void *dummy)
+{
+	unsigned i, j;
+	unsigned m_state;
+	mutex_lock(&region_ctrl_lock);
+
+	seq_printf(f, "OCMEM Aggregated Power States\n");
+	for (i = 0 ; i < num_regions; i++) {
+		struct ocmem_hw_region *region = &region_ctrl[i];
+		seq_printf(f, "Region %u mode %x\n", i, region->mode);
+		for (j = 0; j < num_banks; j++) {
+			m_state = read_macro_state(i, j);
+			if (m_state == MACRO_ON)
+				seq_printf(f, "M%u:%s\t", j, "ON");
+			else if (m_state == MACRO_SLEEP_RETENTION)
+				seq_printf(f, "M%u:%s\t", j, "RETENTION");
+			else
+				seq_printf(f, "M%u:%s\t", j, "OFF");
+		}
+		seq_printf(f, "\n");
+	}
+	mutex_unlock(&region_ctrl_lock);
+	return 0;
+}
+
+#ifdef CONFIG_MSM_OCMEM_POWER_DEBUG
+static int ocmem_power_show_hw_state(struct seq_file *f, void *dummy)
+{
+	unsigned i = 0;
+	unsigned r_state;
+
+	mutex_lock(&region_ctrl_lock);
+
+	seq_printf(f, "OCMEM Hardware Power States\n");
+	for (i = 0 ; i < num_regions; i++) {
+		struct ocmem_hw_region *region = &region_ctrl[i];
+		seq_printf(f, "Region %u mode %x ", i, region->mode);
+		r_state = read_hw_region_state(i);
+		if (r_state == REGION_DEFAULT_ON)
+			seq_printf(f, "state: %s\t", "REGION_ON");
+		else if (r_state == MACRO_SLEEP_RETENTION)
+			seq_printf(f, "state: %s\t", "REGION_RETENTION");
+		else
+			seq_printf(f, "state: %s\t", "REGION_OFF");
+		seq_printf(f, "\n");
+	}
+	mutex_unlock(&region_ctrl_lock);
+	return 0;
+}
+#else
+static int ocmem_power_show_hw_state(struct seq_file *f, void *dummy)
+{
+	return 0;
+}
+#endif
+
+static int ocmem_power_show(struct seq_file *f, void *dummy)
+{
+	ocmem_power_show_sw_state(f, dummy);
+	ocmem_power_show_hw_state(f, dummy);
+	return 0;
+}
+
+static int ocmem_power_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, ocmem_power_show, inode->i_private);
+}
+
+static const struct file_operations power_show_fops = {
+	.open = ocmem_power_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = seq_release,
+};
+
 int ocmem_core_init(struct platform_device *pdev)
 {
 	struct device   *dev = &pdev->dev;
@@ -640,10 +952,16 @@
 	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) {
@@ -671,9 +989,9 @@
 	pdata->interleaved = true;
 	pdata->nr_macros = num_macros;
 	pdata->nr_ports = num_ports;
-	macro_size = SZ_64K;
-	region_size = macro_size * num_ports;
+	macro_size = OCMEM_V1_MACRO_SZ * 2;
 	num_banks = num_ports / 2;
+	region_size = macro_size * num_banks;
 	rsc_type = pdata->rpm_rsc_type;
 
 	pr_debug("ocmem_core: ports %d regions %d macros %d interleaved %d\n",
@@ -684,8 +1002,7 @@
 					 * num_regions, GFP_KERNEL);
 
 	if (!region_ctrl) {
-		pr_err("ocmem: Unable to allocate memory\n");
-		return -EINVAL;
+		goto err_no_mem;
 	}
 
 	mutex_init(&region_ctrl_lock);
@@ -695,6 +1012,7 @@
 		struct msm_rpm_request *req = NULL;
 		region->interleaved = interleaved;
 		region->mode = MODE_DEFAULT;
+		atomic_set(&region->mode_counter, 0);
 		region->r_state = REGION_DEFAULT_OFF;
 		region->num_macros = num_banks;
 
@@ -702,8 +1020,7 @@
 					sizeof(struct ocmem_hw_macro) *
 						num_banks, GFP_KERNEL);
 		if (!region->macro) {
-			pr_err("ocmem: Unable to allocate memory\n");
-			return -EINVAL;
+			goto err_no_mem;
 		}
 
 		for (j = 0; j < num_banks; j++) {
@@ -722,7 +1039,7 @@
 
 			if (!req) {
 				pr_err("Unable to create RPM request\n");
-				return -EINVAL;
+				goto region_init_error;
 			}
 
 			pr_debug("rpm request type %x (rsc: %d) with %d elements\n",
@@ -733,16 +1050,34 @@
 
 		if (ocmem_region_toggle(i)) {
 			pr_err("Failed to verify region %d\n", i);
-			goto hw_not_supported;
+			goto region_init_error;
 		}
 
 		if (ocmem_region_set_default_state(i)) {
 			pr_err("Failed to initialize region %d\n", i);
-			goto hw_not_supported;
+			goto region_init_error;
 		}
 	}
+
+	rc = ocmem_core_set_default_state();
+
+	if (rc < 0)
+		return rc;
+
+	ocmem_disable_core_clock();
+
+	if (!debugfs_create_file("power_state", S_IRUGO, pdata->debug_node,
+					NULL, &power_show_fops)) {
+		dev_err(dev, "Unable to create debugfs node for power state\n");
+		return -EBUSY;
+	}
+
 	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 5649021..85dc85d 100644
--- a/arch/arm/mach-msm/ocmem_rdm.c
+++ b/arch/arm/mach-msm/ocmem_rdm.c
@@ -38,8 +38,12 @@
 
 #define DM_INTR_CLR (0x8)
 #define DM_INTR_MASK (0xC)
-#define DM_GEN_STATUS (0x10)
-#define DM_STATUS (0x14)
+#define DM_INT_STATUS (0x10)
+#define DM_GEN_STATUS (0x14)
+#define DM_CLR_OFFSET (0x18)
+#define DM_CLR_SIZE (0x1C)
+#define DM_CLR_PATTERN (0x20)
+#define DM_CLR_TRIGGER (0x24)
 #define DM_CTRL (0x1000)
 #define DM_TBL_BASE (0x1010)
 #define DM_TBL_IDX(x) ((x) * 0x18)
@@ -82,8 +86,9 @@
 #define DM_DIR_SHIFT 0x0
 
 #define DM_DONE 0x1
-#define DM_INTR_ENABLE 0x0
-#define DM_INTR_DISABLE 0x1
+#define DM_MASK_RESET 0x0
+#define DM_INTR_RESET 0x20003
+#define DM_CLR_ENABLE 0x1
 
 static void *br_base;
 static void *dm_base;
@@ -122,12 +127,59 @@
 
 static irqreturn_t ocmem_dm_irq_handler(int irq, void *dev_id)
 {
+	unsigned status;
+	unsigned irq_status;
+	status = ocmem_read(dm_base + DM_GEN_STATUS);
+	irq_status = ocmem_read(dm_base + DM_INT_STATUS);
+	pr_debug("irq:dm_status %x irq_status %x\n", status, irq_status);
+	if (irq_status & BIT(0)) {
+		pr_debug("Data mover completed\n");
+		irq_status &= ~BIT(0);
+		ocmem_write(irq_status, dm_base + DM_INTR_CLR);
+	} else if (irq_status & BIT(1)) {
+		pr_debug("Data clear engine completed\n");
+		irq_status &= ~BIT(1);
+		ocmem_write(irq_status, dm_base + DM_INTR_CLR);
+	} else {
+		BUG_ON(1);
+	}
 	atomic_set(&dm_pending, 0);
-	ocmem_write(DM_INTR_DISABLE, dm_base + DM_INTR_CLR);
 	wake_up_interruptible(&dm_wq);
 	return IRQ_HANDLED;
 }
 
+#ifdef CONFIG_MSM_OCMEM_NONSECURE
+int ocmem_clear(unsigned long start, unsigned long size)
+{
+	atomic_set(&dm_pending, 1);
+	/* Clear DM Mask */
+	ocmem_write(DM_MASK_RESET, dm_base + DM_INTR_MASK);
+	/* Clear DM Interrupts */
+	ocmem_write(DM_INTR_RESET, dm_base + DM_INTR_CLR);
+	/* DM CLR offset */
+	ocmem_write(start, dm_base + DM_CLR_OFFSET);
+	/* DM CLR size */
+	ocmem_write(size, dm_base + DM_CLR_SIZE);
+	/* Wipe out memory as "OCMM" */
+	ocmem_write(0x4D4D434F, dm_base + DM_CLR_PATTERN);
+	/* The offset, size and pattern for clearing must be set
+	 * before triggering the clearing engine
+	 */
+	mb();
+	/* Trigger Data Clear */
+	ocmem_write(DM_CLR_ENABLE, dm_base + DM_CLR_TRIGGER);
+
+	wait_event_interruptible(dm_wq,
+		atomic_read(&dm_pending) == 0);
+	return 0;
+}
+#else
+int ocmem_clear(unsigned long start, unsigned long size)
+{
+	return 0;
+}
+#endif
+
 /* Lock during transfers */
 int ocmem_rdm_transfer(int id, struct ocmem_map_list *clist,
 			unsigned long start, int direction)
@@ -142,6 +194,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++) {
 
@@ -186,9 +247,13 @@
 	dm_ctrl |= (DM_BLOCK_256 << DM_BR_BLK_SHIFT);
 	dm_ctrl |= (direction << DM_DIR_SHIFT);
 
-	status = ocmem_read(dm_base + DM_STATUS);
+	status = ocmem_read(dm_base + DM_GEN_STATUS);
 	pr_debug("Transfer status before %x\n", status);
 	atomic_set(&dm_pending, 1);
+	/* The DM and BR tables must be programmed before triggering the
+	 * Data Mover else the coherent transfer would be corrupted
+	 */
+	mb();
 	/* Trigger DM */
 	ocmem_write(dm_ctrl, dm_base + DM_CTRL);
 	pr_debug("ocmem: rdm: dm_ctrl %x br_ctrl %x\n", dm_ctrl, br_ctrl);
@@ -196,6 +261,7 @@
 	wait_event_interruptible(dm_wq,
 		atomic_read(&dm_pending) == 0);
 
+	ocmem_disable_core_clock();
 	return 0;
 }
 
@@ -218,8 +284,18 @@
 		return -EINVAL;
 	}
 
+	rc = ocmem_enable_core_clock();
+
+	if (rc < 0) {
+		pr_err("RDM initialization failed\n");
+		return rc;
+	}
+
 	init_waitqueue_head(&dm_wq);
+	/* Clear DM Mask */
+	ocmem_write(DM_MASK_RESET, dm_base + DM_INTR_MASK);
 	/* enable dm interrupts */
-	ocmem_write(DM_INTR_ENABLE, dm_base + DM_INTR_MASK);
+	ocmem_write(DM_INTR_RESET, dm_base + DM_INTR_CLR);
+	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 70e6860..e8854d5 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},
@@ -158,6 +158,59 @@
 	return ocmem_client_table[id].hw_interconnect == OCMEM_BLOCKED ? 1 : 0;
 }
 
+inline struct ocmem_buf *handle_to_buffer(struct ocmem_handle *handle)
+{
+	if (handle)
+		return &handle->buffer;
+	else
+		return NULL;
+}
+
+inline struct ocmem_handle *buffer_to_handle(struct ocmem_buf *buffer)
+{
+	if (buffer)
+		return container_of(buffer, struct ocmem_handle, buffer);
+	else
+		return NULL;
+}
+
+inline struct ocmem_req *handle_to_req(struct ocmem_handle *handle)
+{
+	if (handle)
+		return handle->req;
+	else
+		return NULL;
+}
+
+inline struct ocmem_handle *req_to_handle(struct ocmem_req *req)
+{
+	if (req && req->buffer)
+		return container_of(req->buffer, struct ocmem_handle, buffer);
+	else
+		return NULL;
+}
+
+/* Simple wrappers which will have debug features added later */
+inline int ocmem_read(void *at)
+{
+	return readl_relaxed(at);
+}
+
+inline int ocmem_write(unsigned long val, void *at)
+{
+	writel_relaxed(val, at);
+	return 0;
+}
+
+inline int get_mode(int id)
+{
+	if (!check_id(id))
+		return MODE_NOT_SET;
+	else
+		return ocmem_client_table[id].mode == OCMEM_PERFORMANCE ?
+							WIDE_MODE : THIN_MODE;
+}
+
 /* Returns the address that can be used by a device core to access OCMEM */
 static unsigned long device_address(int id, unsigned long addr)
 {
@@ -200,6 +253,15 @@
 	return ret_addr;
 }
 
+static inline struct ocmem_zone *zone_of(struct ocmem_req *req)
+{
+	int owner;
+	if (!req)
+		return NULL;
+	owner = req->owner;
+	return get_zone(owner);
+}
+
 static int insert_region(struct ocmem_region *region)
 {
 
@@ -511,18 +573,84 @@
 	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)
 {
-	return do_map(req);
+	int rc = 0;
+
+	rc = ocmem_enable_core_clock();
+
+	if (rc < 0)
+		goto core_clock_fail;
+
+	rc = ocmem_enable_iface_clock();
+
+	if (rc < 0)
+		goto iface_clock_fail;
+
+	rc = ocmem_enable_br_clock();
+
+	if (rc < 0)
+		goto br_clock_fail;
+
+	rc = do_map(req);
+
+	if (rc < 0) {
+		pr_err("ocmem: Failed to map request %p for %d\n",
+							req, req->owner);
+		goto process_map_fail;
+
+	}
+
+	if (ocmem_lock(req->owner, phys_to_offset(req->req_start), req->req_sz,
+							get_mode(req->owner))) {
+		pr_err("ocmem: Failed to secure request %p for %d\n", req,
+				req->owner);
+		rc = -EINVAL;
+		goto lock_failed;
+	}
+
+	return 0;
+lock_failed:
+	do_unmap(req);
+process_map_fail:
+	ocmem_disable_br_clock();
+br_clock_fail:
+	ocmem_disable_iface_clock();
+iface_clock_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;
+
+	if (ocmem_unlock(req->owner, phys_to_offset(req->req_start),
+							req->req_sz)) {
+		pr_err("ocmem: Failed to un-secure request %p for %d\n", req,
+				req->owner);
+		rc = -EINVAL;
+		goto unlock_failed;
+	}
+
+	rc = do_unmap(req);
+
+	if (rc < 0)
+		goto process_unmap_fail;
+
+	ocmem_disable_br_clock();
+	ocmem_disable_iface_clock();
+	ocmem_disable_core_clock();
+	return 0;
+
+unlock_failed:
+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)
@@ -764,7 +892,6 @@
 	if (matched_req != req)
 		goto invalid_op_error;
 
-
 	ret = zone->z_ops->free(zone,
 		matched_req->req_start, matched_req->req_sz);
 
@@ -1224,7 +1351,6 @@
 			return -EINVAL;
 	}
 
-
 	if (req->req_sz != 0) {
 
 		offset = phys_to_offset(req->req_start);
@@ -1239,10 +1365,11 @@
 	}
 
 	rc = do_free(req);
-
 	if (rc < 0)
 		return -EINVAL;
 
+	inc_ocmem_stat(zone_of(req), NR_FREES);
+
 	ocmem_destroy_req(req);
 	handle->req = NULL;
 
@@ -1319,14 +1446,16 @@
 		goto transfer_out_error;
 	}
 
+	inc_ocmem_stat(zone_of(req), NR_TRANSFERS_TO_DDR);
+
 	rc = queue_transfer(req, handle, list, TO_DDR);
 
 	if (rc < 0) {
 		pr_err("Failed to queue rdm transfer to DDR\n");
+		inc_ocmem_stat(zone_of(req), NR_TRANSFER_FAILS);
 		goto transfer_out_error;
 	}
 
-
 	return 0;
 
 transfer_out_error:
@@ -1355,10 +1484,13 @@
 		goto transfer_in_error;
 	}
 
+	inc_ocmem_stat(zone_of(req), NR_TRANSFERS_TO_OCMEM);
+
 	rc = queue_transfer(req, handle, list, TO_OCMEM);
 
 	if (rc < 0) {
 		pr_err("Failed to queue rdm transfer to OCMEM\n");
+		inc_ocmem_stat(zone_of(req), NR_TRANSFER_FAILS);
 		goto transfer_in_error;
 	}
 
@@ -1395,6 +1527,8 @@
 	if (is_tcm(req->owner))
 		do_unmap(req);
 
+	inc_ocmem_stat(zone_of(req), NR_SHRINKS);
+
 	if (size == 0) {
 		pr_info("req %p being shrunk to zero\n", req);
 		rc = do_free(req);
@@ -1477,6 +1611,8 @@
 					req->edata = edata;
 					buffer.addr = req->req_start;
 					buffer.len = 0x0;
+					inc_ocmem_stat(zone_of(req),
+								NR_EVICTIONS);
 					dispatch_notification(req->owner,
 						OCMEM_ALLOC_SHRINK, &buffer);
 				}
@@ -1506,8 +1642,10 @@
 	rc = __sched_allocate(req, can_block, can_wait);
 	mutex_unlock(&sched_mutex);
 
-	if (rc == OP_FAIL)
+	if (rc == OP_FAIL) {
+		inc_ocmem_stat(zone_of(req), NR_ALLOCATION_FAILS);
 		goto err_allocate_fail;
+	}
 
 	if (rc == OP_RESCHED) {
 		buffer->addr = 0x0;
@@ -1517,6 +1655,7 @@
 	} else if (rc == OP_PARTIAL) {
 		buffer->addr = device_address(req->owner, req->req_start);
 		buffer->len = req->req_sz;
+		inc_ocmem_stat(zone_of(req), NR_RANGE_ALLOCATIONS);
 		pr_debug("ocmem: Enqueuing req %p\n", req);
 		sched_enqueue(req);
 	} else if (rc == OP_COMPLETE) {
@@ -1548,6 +1687,7 @@
 			list_del(&req->sched_list);
 			req->op = SCHED_ALLOCATE;
 			sched_enqueue(req);
+			inc_ocmem_stat(zone_of(req), NR_RESTORES);
 		}
 	}
 	kfree(edata);
@@ -1594,11 +1734,15 @@
 	req->op = SCHED_ALLOCATE;
 	req->buffer = buffer;
 
+	inc_ocmem_stat(zone_of(req), NR_REQUESTS);
+
 	rc = do_allocate(req, can_block, can_wait);
 
 	if (rc < 0)
 		goto do_allocate_error;
 
+	inc_ocmem_stat(zone_of(req), NR_SYNC_ALLOCATIONS);
+
 	handle->req = req;
 
 	if (is_tcm(id)) {
@@ -1643,10 +1787,11 @@
 
 	rc = do_allocate(req, true, false);
 
-
 	if (rc < 0)
 		goto do_allocate_error;
 
+	inc_ocmem_stat(zone_of(req), NR_ASYNC_ALLOCATIONS);
+
 	if (is_tcm(id)) {
 		rc = process_map(req, req->req_start, req->req_end);
 		if (rc < 0)
@@ -1714,10 +1859,51 @@
 	return;
 }
 
-int ocmem_sched_init(void)
+static int ocmem_allocations_show(struct seq_file *f, void *dummy)
+{
+	struct rb_node *rb_node = NULL;
+	struct ocmem_req *req = NULL;
+	unsigned j;
+	mutex_lock(&sched_mutex);
+	for (rb_node = rb_first(&sched_tree); rb_node;
+				rb_node = rb_next(rb_node)) {
+		struct ocmem_region *tmp_region = NULL;
+		tmp_region = rb_entry(rb_node, struct ocmem_region, region_rb);
+		for (j = MAX_OCMEM_PRIO - 1; j > NO_PRIO; j--) {
+			req = find_req_match(j, tmp_region);
+			if (req) {
+				seq_printf(f,
+					"owner: %s 0x%lx -- 0x%lx size 0x%lx [state: %2lx]\n",
+					get_name(req->owner),
+					req->req_start, req->req_end,
+					req->req_sz, req->state);
+			}
+		}
+	}
+	mutex_unlock(&sched_mutex);
+	return 0;
+}
+
+static int ocmem_allocations_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, ocmem_allocations_show, inode->i_private);
+}
+
+static const struct file_operations allocations_show_fops = {
+	.open = ocmem_allocations_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = seq_release,
+};
+
+int ocmem_sched_init(struct platform_device *pdev)
 {
 	int i = 0;
+	struct ocmem_plat_data *pdata = NULL;
+	struct device   *dev = &pdev->dev;
+
 	sched_tree = RB_ROOT;
+	pdata = platform_get_drvdata(pdev);
 	mutex_init(&sched_mutex);
 	mutex_init(&sched_queue_mutex);
 	for (i = MIN_PRIO; i < MAX_OCMEM_PRIO; i++)
@@ -1731,5 +1917,11 @@
 	ocmem_eviction_wq = alloc_workqueue("ocmem_eviction_wq", 0, 0);
 	if (!ocmem_eviction_wq)
 		return -ENOMEM;
+
+	if (!debugfs_create_file("allocations", S_IRUGO, pdata->debug_node,
+					NULL, &allocations_show_fops)) {
+		dev_err(dev, "Unable to create debugfs node for scheduler\n");
+		return -EBUSY;
+	}
 	return 0;
 }
diff --git a/arch/arm/mach-msm/peripheral-loader.c b/arch/arm/mach-msm/peripheral-loader.c
index 540ffbb..4ff34bf 100644
--- a/arch/arm/mach-msm/peripheral-loader.c
+++ b/arch/arm/mach-msm/peripheral-loader.c
@@ -34,6 +34,15 @@
 
 #include "peripheral-loader.h"
 
+/**
+ * proxy_timeout - Override for proxy vote timeouts
+ * -1: Use driver-specified timeout
+ *  0: Hold proxy votes until shutdown
+ * >0: Specify a custom timeout in ms
+ */
+static int proxy_timeout_ms = -1;
+module_param(proxy_timeout_ms, int, S_IRUGO | S_IWUSR);
+
 enum pil_state {
 	PIL_OFFLINE,
 	PIL_ONLINE,
@@ -127,7 +136,10 @@
 
 static void pil_proxy_unvote(struct pil_device *pil, unsigned long timeout)
 {
-	if (pil->desc->ops->proxy_unvote)
+	if (proxy_timeout_ms >= 0)
+		timeout = proxy_timeout_ms;
+
+	if (timeout && pil->desc->ops->proxy_unvote)
 		schedule_delayed_work(&pil->proxy, msecs_to_jiffies(timeout));
 }
 
@@ -393,7 +405,11 @@
 static void pil_shutdown(struct pil_device *pil)
 {
 	pil->desc->ops->shutdown(pil->desc);
-	flush_delayed_work(&pil->proxy);
+	if (proxy_timeout_ms == 0 && pil->desc->ops->proxy_unvote)
+		pil->desc->ops->proxy_unvote(pil->desc);
+	else
+		flush_delayed_work(&pil->proxy);
+
 	pil_set_state(pil, PIL_OFFLINE);
 }
 
diff --git a/arch/arm/mach-msm/pil-mba.c b/arch/arm/mach-msm/pil-mba.c
index d0ba7d0..5e67d4f 100644
--- a/arch/arm/mach-msm/pil-mba.c
+++ b/arch/arm/mach-msm/pil-mba.c
@@ -37,12 +37,13 @@
 
 #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
 #define POLL_INTERVAL_US		50
 
+static int modem_auth_timeout_ms = 10000;
+module_param(modem_auth_timeout_ms, int, S_IRUGO | S_IWUSR);
+
 struct mba_data {
 	void __iomem *reg_base;
 	void __iomem *metadata_base;
@@ -75,7 +76,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 +90,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,
-		POLL_INTERVAL_US, AUTH_TIMEOUT_US);
-	if (ret)
+		status == STATUS_META_DATA_AUTH_SUCCESS || status < 0,
+		POLL_INTERVAL_US, modem_auth_timeout_ms * 1000);
+	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 +106,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 +117,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,
-			50, AUTH_TIMEOUT_US);
-	if (ret)
-		return ret;
+			status == STATUS_AUTH_COMPLETE || status < 0,
+			50, modem_auth_timeout_ms * 1000);
+	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-q6v5-lpass.c b/arch/arm/mach-msm/pil-q6v5-lpass.c
index 99223f2..ed072ea 100644
--- a/arch/arm/mach-msm/pil-q6v5-lpass.c
+++ b/arch/arm/mach-msm/pil-q6v5-lpass.c
@@ -18,13 +18,57 @@
 #include <linux/err.h>
 #include <linux/of.h>
 #include <linux/clk.h>
-
+#include <mach/clk.h>
 #include "peripheral-loader.h"
 #include "pil-q6v5.h"
+#include "scm-pas.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 +81,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 +96,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 +106,7 @@
 
 	ret = pil_q6v5_reset(pil);
 	if (ret) {
-		pil_q6v5_disable_clks(pil);
+		pil_lpass_disable_clks(drv);
 		return ret;
 	}
 
@@ -79,6 +123,30 @@
 	.shutdown = pil_lpass_shutdown,
 };
 
+static int pil_lpass_init_image_trusted(struct pil_desc *pil,
+		const u8 *metadata, size_t size)
+{
+	return pas_init_image(PAS_Q6, metadata, size);
+}
+
+static int pil_lpass_reset_trusted(struct pil_desc *pil)
+{
+	return pas_auth_and_reset(PAS_Q6);
+}
+
+static int pil_lpass_shutdown_trusted(struct pil_desc *pil)
+{
+	return pas_shutdown(PAS_Q6);
+}
+
+static struct pil_reset_ops pil_lpass_ops_trusted = {
+	.init_image = pil_lpass_init_image_trusted,
+	.proxy_vote = pil_q6v5_make_proxy_votes,
+	.proxy_unvote = pil_q6v5_remove_proxy_votes,
+	.auth_and_reset = pil_lpass_reset_trusted,
+	.shutdown = pil_lpass_shutdown_trusted,
+};
+
 static int __devinit pil_lpass_driver_probe(struct platform_device *pdev)
 {
 	struct q6v5_data *drv;
@@ -96,9 +164,29 @@
 	desc->owner = THIS_MODULE;
 	desc->proxy_timeout = PROXY_TIMEOUT_MS;
 
-	drv->ss_clk = devm_clk_get(&pdev->dev, "reg_clk");
-	if (IS_ERR(drv->ss_clk))
-		return PTR_ERR(drv->ss_clk);
+	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);
+
+	if (pas_supported(PAS_Q6) > 0) {
+		desc->ops = &pil_lpass_ops_trusted;
+		dev_info(&pdev->dev, "using secure boot\n");
+	} else {
+		desc->ops = &pil_lpass_ops;
+		dev_info(&pdev->dev, "using non-secure boot\n");
+	}
 
 	drv->pil = msm_pil_register(desc);
 	if (IS_ERR(drv->pil))
diff --git a/arch/arm/mach-msm/pil-q6v5-mss.c b/arch/arm/mach-msm/pil-q6v5-mss.c
index 72ea57cc..1fdd342 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
@@ -48,10 +51,12 @@
 #define RMB_PBL_STATUS			0x04
 #define RMB_MBA_STATUS			0x0C
 
-#define PBL_MBA_WAIT_TIMEOUT_US		100000
 #define PROXY_TIMEOUT_MS		10000
 #define POLL_INTERVAL_US		50
 
+static int pbl_mba_boot_timeout_ms = 100;
+module_param(pbl_mba_boot_timeout_ms, int, S_IRUGO | S_IWUSR);
+
 static int pil_mss_power_up(struct device *dev)
 {
 	int ret;
@@ -71,6 +76,44 @@
 	return regulator_disable(drv->vreg);
 }
 
+static int pil_mss_enable_clks(struct q6v5_data *drv)
+{
+	int ret;
+	void __iomem *mpll1_config_ctl;
+
+	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->rom_clk);
+	if (ret)
+		goto err_rom_clk;
+
+	/* TODO: Remove when support for 8974v1.0 HW is dropped. */
+	mpll1_config_ctl = ioremap(0xFC981034, 0x4);
+	writel_relaxed(0x0300403D, mpll1_config_ctl);
+	mb();
+	iounmap(mpll1_config_ctl);
+
+	return 0;
+
+err_rom_clk:
+	clk_disable_unprepare(drv->axi_clk);
+err_axi_clk:
+	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->axi_clk);
+	clk_disable_unprepare(drv->ahb_clk);
+}
+
 static int wait_for_mba_ready(struct device *dev)
 {
 	struct q6v5_data *drv = dev_get_drvdata(dev);
@@ -79,7 +122,7 @@
 
 	/* Wait for PBL completion. */
 	ret = readl_poll_timeout(drv->rmb_base + RMB_PBL_STATUS, status,
-		status != 0, POLL_INTERVAL_US, PBL_MBA_WAIT_TIMEOUT_US);
+		status != 0, POLL_INTERVAL_US, pbl_mba_boot_timeout_ms * 1000);
 	if (ret) {
 		dev_err(dev, "PBL boot timed out\n");
 		return ret;
@@ -91,7 +134,7 @@
 
 	/* Wait for MBA completion. */
 	ret = readl_poll_timeout(drv->rmb_base + RMB_MBA_STATUS, status,
-		status != 0, POLL_INTERVAL_US, PBL_MBA_WAIT_TIMEOUT_US);
+		status != 0, POLL_INTERVAL_US, pbl_mba_boot_timeout_ms * 1000);
 	if (ret) {
 		dev_err(dev, "MBA boot timed out\n");
 		return ret;
@@ -120,11 +163,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);
@@ -152,7 +195,7 @@
 	if (ret)
 		goto err_power;
 
-	ret = pil_q6v5_enable_clks(pil);
+	ret = pil_mss_enable_clks(drv);
 	if (ret)
 		goto err_clks;
 
@@ -166,6 +209,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;
@@ -184,7 +230,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:
@@ -233,6 +279,12 @@
 	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);
@@ -247,9 +299,17 @@
 		return ret;
 	}
 
-	drv->ss_clk = devm_clk_get(&pdev->dev, "mem_clk");
-	if (IS_ERR(drv->ss_clk))
-		return PTR_ERR(drv->ss_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->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 d8d23c0..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"
 
@@ -112,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_prepare_enable(drv->bus_clk);
-	if (ret)
-		goto err_bus_clk;
-	if (drv->ss_clk) {
-		ret = clk_prepare_enable(drv->ss_clk);
-		if (ret)
-			goto err_ss_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;
-
-	return 0;
-
-err_core_clk:
-	clk_reset(drv->core_clk, CLK_RESET_ASSERT);
-err_reset:
-	clk_disable_unprepare(drv->ss_clk);
-err_ss_clk:
-	clk_disable_unprepare(drv->bus_clk);
-err_bus_clk:
-	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->core_clk);
-	clk_reset(drv->core_clk, CLK_RESET_ASSERT);
-	clk_disable_unprepare(drv->ss_clk);
-	clk_disable_unprepare(drv->bus_clk);
-}
-EXPORT_SYMBOL(pil_q6v5_disable_clks);
-
 void pil_q6v5_shutdown(struct pil_desc *pil)
 {
 	u32 val;
@@ -277,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 f94129d..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 *ss_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 2749098..b2681b7 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>
@@ -83,7 +84,7 @@
 	if (!base_ptr)
 		return -ENODEV;
 
-	if (machine_is_msm8974_sim()) {
+	if (machine_is_msm8974_sim() || machine_is_mpq8092_sim()) {
 		writel_relaxed(0x800, base_ptr+0x04);
 		writel_relaxed(0x3FFF, base_ptr+0x14);
 	}
@@ -101,17 +102,23 @@
 
 	msm_spm_turn_on_cpu_rail(cpu);
 
-	writel_relaxed(0x109, base_ptr+0x04);
-	writel_relaxed(0x101, base_ptr+0x04);
-	ndelay(300);
-
-	writel_relaxed(0x121, base_ptr+0x04);
+	if (cpu_is_krait_v1() || cpu_is_krait_v2()) {
+		writel_relaxed(0x109, base_ptr+0x04);
+		writel_relaxed(0x101, base_ptr+0x04);
+		mb();
+		ndelay(300);
+		writel_relaxed(0x121, base_ptr+0x04);
+	} else
+		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();
 	udelay(100);
 
 	writel_relaxed(0x080, base_ptr+0x04);
@@ -120,6 +127,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());
@@ -127,13 +159,16 @@
 	if (cpu_is_msm8x60())
 		return scorpion_release_secondary();
 
-	if (machine_is_msm8974_sim())
+	if (machine_is_msm8974_sim() || machine_is_mpq8092_sim())
 		return krait_release_secondary_sim(0xf9088000, cpu);
 
 	if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm8930aa() ||
 	    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;
 }
@@ -149,7 +184,7 @@
 int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
 {
 	int ret;
-	int flag = 0;
+	unsigned int flag = 0;
 	unsigned long timeout;
 
 	pr_debug("Starting secondary CPU %d\n", cpu);
@@ -163,8 +198,7 @@
 		__WARN();
 
 	if (per_cpu(cold_boot_done, cpu) == false) {
-		ret = scm_set_boot_addr((void *)
-					virt_to_phys(msm_secondary_startup),
+		ret = scm_set_boot_addr(virt_to_phys(msm_secondary_startup),
 					flag);
 		if (ret == 0)
 			release_secondary(cpu);
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index e203667..8ddb9e1 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -27,6 +27,8 @@
 #include <mach/msm_iomap.h>
 #include <mach/socinfo.h>
 #include <mach/system.h>
+#include <mach/scm.h>
+#include <mach/socinfo.h>
 #include <asm/cacheflush.h>
 #include <asm/hardware/gic.h>
 #include <asm/pgtable.h>
@@ -67,6 +69,7 @@
 module_param_named(
 	debug_mask, msm_pm_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP
 );
+static int msm_pm_retention_tz_call;
 
 
 /******************************************************************************
@@ -78,6 +81,9 @@
 	MSM_PM_MODE_ATTR_NR,
 };
 
+#define SCM_L2_RETENTION	(0x2)
+#define SCM_CMD_TERMINATE_PC	(0x2)
+
 static char *msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_NR] = {
 	[MSM_PM_MODE_ATTR_SUSPEND] = "suspend_enabled",
 	[MSM_PM_MODE_ATTR_IDLE] = "idle_enabled",
@@ -332,7 +338,6 @@
  */
 static void msm_pm_config_hw_after_power_up(void)
 {
-	return;
 }
 
 /*
@@ -343,6 +348,22 @@
 	return;
 }
 
+/*
+ * Configure/Restore hardware registers in preparation for Retention.
+ */
+
+static void msm_pm_config_hw_after_retention(void)
+{
+	int ret;
+	ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING, false);
+	WARN_ON(ret);
+}
+
+static void msm_pm_config_hw_before_retention(void)
+{
+	return;
+}
+
 
 /******************************************************************************
  * Suspend Max Sleep Time
@@ -409,12 +430,17 @@
 {
 	int ret = 0;
 
-	msm_pm_config_hw_before_swfi();
+	msm_pm_config_hw_before_retention();
 	ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_POWER_RETENTION, false);
 	WARN_ON(ret);
-	msm_arch_idle();
-	ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING, false);
-	WARN_ON(ret);
+
+	if (msm_pm_retention_tz_call)
+		scm_call_atomic1(SCM_SVC_BOOT, SCM_CMD_TERMINATE_PC,
+					SCM_L2_RETENTION);
+	else
+		msm_arch_idle();
+
+	msm_pm_config_hw_after_retention();
 }
 
 #ifdef CONFIG_CACHE_L2X0
@@ -659,6 +685,7 @@
 
 		switch (mode) {
 		case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
+		case MSM_PM_SLEEP_MODE_RETENTION:
 			if (!allow)
 				break;
 
@@ -673,11 +700,6 @@
 				break;
 			/* fall through */
 
-		case MSM_PM_SLEEP_MODE_RETENTION:
-			if (!allow)
-				break;
-			/* fall through */
-
 		case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
 			if (!allow)
 				break;
@@ -819,7 +841,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();
 }
 
@@ -923,6 +945,11 @@
 		pm_sleep_ops = *ops;
 }
 
+void __init msm_pm_set_tz_retention_flag(unsigned int flag)
+{
+	msm_pm_retention_tz_call = flag;
+}
+
 static int __init msm_pm_init(void)
 {
 	pgd_t *pc_pgd;
diff --git a/arch/arm/mach-msm/pm-boot.c b/arch/arm/mach-msm/pm-boot.c
index 079ed9c..ed15a0c 100644
--- a/arch/arm/mach-msm/pm-boot.c
+++ b/arch/arm/mach-msm/pm-boot.c
@@ -43,7 +43,7 @@
 #ifdef CONFIG_MSM_SCM
 static int __devinit msm_pm_tz_boot_init(void)
 {
-	int flag = 0;
+	unsigned int flag = 0;
 	if (num_possible_cpus() == 1)
 		flag = SCM_FLAG_WARMBOOT_CPU0;
 	else if (num_possible_cpus() == 2)
@@ -54,7 +54,7 @@
 	else
 		__WARN();
 
-	return scm_set_boot_addr((void *)virt_to_phys(msm_pm_boot_entry), flag);
+	return scm_set_boot_addr(virt_to_phys(msm_pm_boot_entry), flag);
 }
 
 static void msm_pm_config_tz_before_pc(unsigned int cpu,
diff --git a/arch/arm/mach-msm/pm.h b/arch/arm/mach-msm/pm.h
index c722ff6..552fb16 100644
--- a/arch/arm/mach-msm/pm.h
+++ b/arch/arm/mach-msm/pm.h
@@ -80,12 +80,18 @@
 			bool notify_rpm, bool collapsed);
 };
 
+struct msm_pm_cpr_ops {
+	void (*cpr_suspend)(void);
+	void (*cpr_resume)(void);
+};
+
 void msm_pm_set_platform_data(struct msm_pm_platform_data *data, int count);
 int msm_pm_idle_prepare(struct cpuidle_device *dev,
 			struct cpuidle_driver *drv, int index);
 void msm_pm_set_irq_extns(struct msm_pm_irq_calls *irq_calls);
 int msm_pm_idle_enter(enum msm_pm_sleep_mode sleep_mode);
 void msm_pm_cpu_enter_lowpower(unsigned int cpu);
+void __init msm_pm_set_tz_retention_flag(unsigned int flag);
 
 #ifdef CONFIG_MSM_PM8X60
 void msm_pm_set_rpm_wakeup_irq(unsigned int irq);
@@ -124,4 +130,6 @@
 static inline void msm_pm_add_stat(enum msm_pm_time_stats_id id, int64_t t) {}
 #endif
 
+void msm_pm_set_cpr_ops(struct msm_pm_cpr_ops *ops);
+
 #endif  /* __ARCH_ARM_MACH_MSM_PM_H */
diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c
index 8fccda4..10c5445 100644
--- a/arch/arm/mach-msm/pm2.c
+++ b/arch/arm/mach-msm/pm2.c
@@ -152,6 +152,7 @@
 
 static struct msm_pm_platform_data *msm_pm_modes;
 static struct msm_pm_irq_calls *msm_pm_irq_extns;
+static struct msm_pm_cpr_ops *msm_cpr_ops;
 
 struct msm_pm_kobj_attribute {
 	unsigned int cpu;
@@ -415,6 +416,11 @@
 	msm_pm_irq_extns = irq_calls;
 }
 
+void __init msm_pm_set_cpr_ops(struct msm_pm_cpr_ops *ops)
+{
+	msm_cpr_ops = ops;
+}
+
 /******************************************************************************
  * Sleep Limitations
  *****************************************************************************/
@@ -876,6 +882,10 @@
 		WARN_ON(ret);
 	}
 
+	/* Call CPR suspend only for "idlePC" case */
+	if (msm_cpr_ops && from_idle)
+		msm_cpr_ops->cpr_suspend();
+
 	msm_pm_irq_extns->enter_sleep1(true, from_idle,
 						&msm_pm_smem_data->irq_mask);
 	msm_sirc_enter_sleep();
@@ -1113,6 +1123,10 @@
 		WARN_ON(ret);
 	}
 
+	/* Call CPR resume only for "idlePC" case */
+	if (msm_cpr_ops && from_idle)
+		msm_cpr_ops->cpr_resume();
+
 	return 0;
 
 power_collapse_early_exit:
@@ -1165,6 +1179,10 @@
 	if (collapsed)
 		smd_sleep_exit();
 
+	/* Call CPR resume only for "idlePC" case */
+	if (msm_cpr_ops && from_idle)
+		msm_cpr_ops->cpr_resume();
+
 power_collapse_bail:
 	if (cpu_is_msm8625()) {
 		ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING,
diff --git a/arch/arm/mach-msm/qdsp5/Makefile b/arch/arm/mach-msm/qdsp5/Makefile
index 2ce0031..f4fe052 100644
--- a/arch/arm/mach-msm/qdsp5/Makefile
+++ b/arch/arm/mach-msm/qdsp5/Makefile
@@ -14,7 +14,7 @@
 obj-y += audio_out.o audio_mp3.o audmgr.o audpp.o audrec.o audpreproc.o
 obj-y += audio_evrc.o audio_qcelp.o audio_amrnb.o audio_aac.o audio_amrnb_in.o
 obj-y += audio_wma.o audio_voicememo.o audio_pcm.o audio_amrwb.o audio_wmapro.o
-obj-y += snd.o snd_adie.o
+obj-y += snd.o snd_cad.o snd_adie.o audio_acdb.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.c b/arch/arm/mach-msm/qdsp5/adsp.c
index 11f6b28..6189da8 100644
--- a/arch/arm/mach-msm/qdsp5/adsp.c
+++ b/arch/arm/mach-msm/qdsp5/adsp.c
@@ -720,11 +720,22 @@
 	mutex_lock(&module->lock);
 	switch (event) {
 	case RPC_ADSP_RTOS_MOD_READY:
-		MM_INFO("module %s: READY\n", module->name);
-		module->state = ADSP_STATE_ENABLED;
-		wake_up(&module->state_wait);
-		adsp_set_image(module->info, image);
-		break;
+		if (module->state == ADSP_STATE_ENABLING) {
+			MM_INFO("module %s: READY\n", module->name);
+			module->state = ADSP_STATE_ENABLED;
+			wake_up(&module->state_wait);
+			adsp_set_image(module->info, image);
+			break;
+		} else {
+			MM_ERR("module %s got READY event in state[%d]\n",
+								module->name,
+								module->state);
+			rpc_send_accepted_void_reply(rpc_cb_server_client,
+						req->xid,
+						RPC_ACCEPTSTAT_GARBAGE_ARGS);
+			mutex_unlock(&module->lock);
+			return;
+		}
 	case RPC_ADSP_RTOS_MOD_DISABLE:
 		MM_INFO("module %s: DISABLED\n", module->name);
 		module->state = ADSP_STATE_DISABLED;
diff --git a/arch/arm/mach-msm/qdsp5/adsp.h b/arch/arm/mach-msm/qdsp5/adsp.h
index 06e2f22..50f5b83 100644
--- a/arch/arm/mach-msm/qdsp5/adsp.h
+++ b/arch/arm/mach-msm/qdsp5/adsp.h
@@ -20,7 +20,7 @@
 
 #include <linux/types.h>
 #include <linux/msm_adsp.h>
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
 #include <mach/msm_rpcrouter.h>
 #include <mach/msm_adsp.h>
 
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_aac.c b/arch/arm/mach-msm/qdsp5/audio_aac.c
index 15e0590..ac7cca3 100644
--- a/arch/arm/mach-msm/qdsp5/audio_aac.c
+++ b/arch/arm/mach-msm/qdsp5/audio_aac.c
@@ -34,13 +34,14 @@
 #include <linux/slab.h>
 #include <linux/msm_audio_aac.h>
 #include <linux/memory_alloc.h>
-#include <linux/ion.h>
+#include <linux/msm_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/qdsp5audpp.h>
 #include <mach/qdsp5/qdsp5audplaycmdi.h>
 #include <mach/qdsp5/qdsp5audplaymsg.h>
 #include <mach/qdsp5/qdsp5rmtcmdi.h>
diff --git a/arch/arm/mach-msm/qdsp5/audio_aac_in.c b/arch/arm/mach-msm/qdsp5/audio_aac_in.c
index 99e10a4..2e64a09 100644
--- a/arch/arm/mach-msm/qdsp5/audio_aac_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_aac_in.c
@@ -33,7 +33,7 @@
 #include <linux/delay.h>
 #include <linux/msm_audio_aac.h>
 #include <linux/memory_alloc.h>
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
 
 #include "audmgr.h"
 
@@ -109,7 +109,6 @@
 	int out_frame_cnt;
 
 	struct msm_adsp_module *audrec;
-	struct msm_adsp_module *audpre;
 
 
 	/* configuration to use on next enable */
@@ -150,6 +149,8 @@
 	struct ion_client *client;
 	struct ion_handle *input_buff_handle;
 	struct ion_handle *output_buff_handle;
+
+	struct audrec_session_info session_info; /*audrec session info*/
 };
 
 struct audio_frame {
@@ -273,6 +274,31 @@
 	return temp;
 }
 
+/* ------------------- dsp --------------------- */
+static void audpre_dsp_event(void *data, unsigned id,  void *event_data)
+{
+
+	uint16_t *msg = event_data;
+
+	if (!msg)
+		return;
+
+	switch (id) {
+	case AUDPREPROC_MSG_CMD_CFG_DONE_MSG:
+		MM_DBG("type %d, status_flag %d\n",\
+			msg[0], msg[1]);
+		break;
+	case AUDPREPROC_MSG_ERROR_MSG_ID:
+		MM_INFO("err_index %d\n", msg[0]);
+		break;
+	case ADSP_MESSAGE_ID:
+		MM_DBG("Received ADSP event: module enable(audpreproctask)\n");
+		break;
+	default:
+		MM_ERR("unknown event %d\n", id);
+	}
+}
+
 /* must be called with audio->lock held */
 static int audaac_in_enable(struct audio_aac_in *audio)
 {
@@ -293,16 +319,24 @@
 		if (rc < 0)
 			return rc;
 
-		if (msm_adsp_enable(audio->audpre)) {
+		if (audpreproc_enable(audio->enc_id,
+				&audpre_dsp_event, audio)) {
+			MM_ERR("msm_adsp_enable(audpreproc) failed\n");
 			audmgr_disable(&audio->audmgr);
-			MM_ERR("msm_adsp_enable(audpre) failed\n");
 			return -ENODEV;
 		}
+
+		/*update aurec session info in audpreproc layer*/
+		audio->session_info.session_id = audio->enc_id;
+		audio->session_info.sampling_freq =
+			convert_samp_index(audio->samp_rate);
+		audpreproc_update_audrec_info(&audio->session_info);
 	}
+
 	if (msm_adsp_enable(audio->audrec)) {
 		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
+			audpreproc_disable(audio->enc_id, audio);
 			audmgr_disable(&audio->audmgr);
-			msm_adsp_disable(audio->audpre);
 		}
 		MM_ERR("msm_adsp_enable(audrec) failed\n");
 		return -ENODEV;
@@ -328,36 +362,17 @@
 		wake_up(&audio->wait);
 		msm_adsp_disable(audio->audrec);
 		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
-			msm_adsp_disable(audio->audpre);
+			audpreproc_disable(audio->enc_id, audio);
+			/*reset the sampling frequency information at
+			audpreproc layer*/
+			audio->session_info.sampling_freq = 0;
+			audpreproc_update_audrec_info(&audio->session_info);
 			audmgr_disable(&audio->audmgr);
 		}
 	}
 	return 0;
 }
 
-/* ------------------- dsp --------------------- */
-static void audpre_dsp_event(void *data, unsigned id, size_t len,
-			    void (*getevent)(void *ptr, size_t len))
-{
-	uint16_t msg[2];
-	getevent(msg, sizeof(msg));
-
-	switch (id) {
-	case AUDPREPROC_MSG_CMD_CFG_DONE_MSG:
-		MM_DBG("type %d, status_flag %d\n", msg[0], msg[1]);
-		break;
-	case AUDPREPROC_MSG_ERROR_MSG_ID:
-		MM_ERR("err_index %d\n", msg[0]);
-		break;
-	case ADSP_MESSAGE_ID:
-		MM_DBG("Received ADSP event: module enable(audpreproctask)\n");
-		break;
-	default:
-		MM_ERR("unknown event %d\n", id);
-	}
-}
-
-
 static void audaac_in_get_dsp_frames(struct audio_aac_in *audio)
 {
 	struct audio_frame *frame;
@@ -596,11 +611,7 @@
 	}
 }
 
-struct msm_adsp_ops audpre_aac_adsp_ops = {
-	.event = audpre_dsp_event,
-};
-
-struct msm_adsp_ops audrec_aac_adsp_ops = {
+static struct msm_adsp_ops audrec_aac_adsp_ops = {
 	.event = audrec_dsp_event,
 };
 
@@ -1241,12 +1252,9 @@
 	audaac_in_flush(audio);
 	msm_adsp_put(audio->audrec);
 
-	if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
-		msm_adsp_put(audio->audpre);
 
 	audpreproc_aenc_free(audio->enc_id);
 	audio->audrec = NULL;
-	audio->audpre = NULL;
 	audio->opened = 0;
 
 	if ((audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) && \
@@ -1342,16 +1350,6 @@
 		goto done;
 	}
 
-	if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
-		rc = msm_adsp_get("AUDPREPROCTASK", &audio->audpre,
-				&audpre_aac_adsp_ops, audio);
-		if (rc) {
-			msm_adsp_put(audio->audrec);
-			audpreproc_aenc_free(audio->enc_id);
-			goto done;
-		}
-	}
-
 	audio->dsp_cnt = 0;
 	audio->stopped = 0;
 	audio->wflush = 0;
@@ -1493,8 +1491,6 @@
 	ion_client_destroy(client);
 client_create_error:
 	msm_adsp_put(audio->audrec);
-	if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
-		msm_adsp_put(audio->audpre);
 
 	audpreproc_aenc_free(audio->enc_id);
 	mutex_unlock(&audio->lock);
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..63904fb
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/audio_ac3.c
@@ -0,0 +1,1754 @@
+/* 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/msm_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/qdsp5audpp.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/audio_acdb.c b/arch/arm/mach-msm/qdsp5/audio_acdb.c
new file mode 100644
index 0000000..16f23f4
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/audio_acdb.c
@@ -0,0 +1,2646 @@
+/* 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/miscdevice.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/mutex.h>
+#include <linux/io.h>
+#include <linux/android_pmem.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/uaccess.h>
+#include <linux/msm_audio.h>
+#include <linux/slab.h>
+#include <linux/debugfs.h>
+#include <linux/memory_alloc.h>
+#include <linux/mfd/marimba.h>
+#include <mach/dal.h>
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
+#include <mach/socinfo.h>
+#include <mach/qdsp5/qdsp5audpp.h>
+#include <mach/qdsp5/qdsp5audpreproc.h>
+#include <mach/qdsp5/qdsp5audppcmdi.h>
+#include <mach/qdsp5/qdsp5audpreproccmdi.h>
+#include <mach/qdsp5/qdsp5audpreprocmsg.h>
+#include <mach/qdsp5/qdsp5audppmsg.h>
+#include <mach/qdsp5/audio_acdbi.h>
+#include <mach/qdsp5/acdb_commands.h>
+#include <mach/qdsp5/audio_acdb_def.h>
+#include <mach/debug_mm.h>
+#include <mach/msm_memtypes.h>
+
+#include "audmgr.h"
+
+/* this is the ACDB device ID */
+#define DALDEVICEID_ACDB		0x02000069
+#define ACDB_PORT_NAME			"DAL00"
+#define ACDB_CPU			SMD_APPS_MODEM
+#define ACDB_BUF_SIZE			4096
+#define FLUENCE_BUF_SIZE	498
+
+#define ACDB_VALUES_NOT_FILLED		0
+#define ACDB_VALUES_FILLED		1
+#define MAX_RETRY			10
+
+#define COMMON_OBJ_ID                   6
+
+/*below macro is used to align the session info received from
+Devctl driver with the state mentioned as not to alter the
+Existing code*/
+#define AUDREC_OFFSET	2
+/* rpc table index */
+enum {
+	ACDB_DAL_IOCTL = DALDEVICE_FIRST_DEVICE_API_IDX
+};
+
+enum {
+	CAL_DATA_READY	= 0x1,
+	AUDPP_READY	= 0x2,
+	AUDREC_READY	= 0x4,
+};
+
+struct acdb_data {
+	void *handle;
+
+	u32 phys_addr;
+	u8 *virt_addr;
+
+	struct task_struct *cb_thread_task;
+	struct device_info_callback dev_cb;
+
+	u32 acdb_state;
+	struct audpp_event_callback audpp_cb;
+	struct audpreproc_event_callback audpreproc_cb;
+	struct dev_evt_msg *device_info;
+
+	audpp_cmd_cfg_object_params_pcm *pp_iir;
+	audpp_cmd_cfg_object_params_mbadrc *pp_mbadrc;
+	audpreproc_cmd_cfg_agc_params *preproc_agc;
+	audpreproc_cmd_cfg_iir_tuning_filter_params *preproc_iir;
+	audpreproc_cmd_cfg_ns_params *preproc_ns;
+	struct acdb_mbadrc_block mbadrc_block;
+
+	wait_queue_head_t wait;
+	struct mutex acdb_mutex;
+	u32 device_cb_compl;
+	u32 audpp_cb_compl;
+	u32 preproc_cb_compl;
+	u8 preproc_stream_id;
+	u8 audrec_applied;
+	u32 multiple_sessions;
+	u32 cur_tx_session;
+	struct acdb_result acdb_result;
+
+	spinlock_t dsp_lock;
+	int dec_id;
+	audpp_cmd_cfg_object_params_eqalizer eq;
+	struct audrec_session_info session_info;
+	/*pmem info*/
+	int pmem_fd;
+	unsigned long paddr;
+	unsigned long kvaddr;
+	unsigned long pmem_len;
+	struct file *file;
+	/* pmem for get acdb blk */
+	unsigned long	get_blk_paddr;
+	u8		*get_blk_kvaddr;
+	void *map_v_get_blk;
+};
+
+static struct acdb_data		acdb_data;
+
+struct acdb_cache_node {
+	u32 node_status;
+	s32 stream_id;
+	u32 phys_addr_acdb_values;
+	void *map_v_addr;
+	u8 *virt_addr_acdb_values;
+	struct dev_evt_msg device_info;
+};
+
+struct acdb_cache_node acdb_cache_rx;
+
+/*for TX devices acdb values are applied based on AUDREC session and
+the depth of the tx cache is define by number of AUDREC sessions supported*/
+struct acdb_cache_node acdb_cache_tx;
+
+/*Audrec session info includes Attributes Sampling frequency and enc_id */
+struct audrec_session_info session_info;
+#ifdef CONFIG_DEBUG_FS
+
+#define RTC_MAX_TIMEOUT 500 /* 500 ms */
+#define PMEM_RTC_ACDB_QUERY_MEM 4096
+#define EXTRACT_HIGH_WORD(x) ((x & 0xFFFF0000)>>16)
+#define EXTRACT_LOW_WORD(x) (0x0000FFFF & x)
+#define	ACDB_RTC_TX 0xF1
+#define	ACDB_RTC_RX 0x1F
+
+
+static u32 acdb_audpp_entry[][4] = {
+
+	{
+	ABID_AUDIO_RTC_VOLUME_PAN_RX,\
+	IID_AUDIO_RTC_VOLUME_PAN_PARAMETERS,\
+	AUDPP_CMD_VOLUME_PAN,\
+	ACDB_RTC_RX
+	},
+	{
+	ABID_AUDIO_IIR_RX,\
+	IID_AUDIO_IIR_COEFF,\
+	AUDPP_CMD_IIR_TUNING_FILTER,
+	ACDB_RTC_RX
+	},
+	{
+	ABID_AUDIO_RTC_EQUALIZER_PARAMETERS,\
+	IID_AUDIO_RTC_EQUALIZER_PARAMETERS,\
+	AUDPP_CMD_EQUALIZER,\
+	ACDB_RTC_RX
+	},
+	{
+	ABID_AUDIO_RTC_SPA,\
+	IID_AUDIO_RTC_SPA_PARAMETERS,\
+	AUDPP_CMD_SPECTROGRAM,
+	ACDB_RTC_RX
+	},
+	{
+	ABID_AUDIO_STF_RX,\
+	IID_AUDIO_IIR_COEFF,\
+	AUDPP_CMD_SIDECHAIN_TUNING_FILTER,\
+	ACDB_RTC_RX
+	},
+	{
+	ABID_AUDIO_MBADRC_RX,\
+	IID_AUDIO_RTC_MBADRC_PARAMETERS,\
+	AUDPP_CMD_MBADRC,\
+	ACDB_RTC_RX
+	},
+	{
+	ABID_AUDIO_AGC_TX,\
+	IID_AUDIO_AGC_PARAMETERS,\
+	AUDPREPROC_CMD_CFG_AGC_PARAMS,\
+	ACDB_RTC_TX
+	},
+	{
+	ABID_AUDIO_AGC_TX,\
+	IID_AUDIO_RTC_AGC_PARAMETERS,\
+	AUDPREPROC_CMD_CFG_AGC_PARAMS,\
+	ACDB_RTC_TX
+	},
+	{
+	ABID_AUDIO_NS_TX,\
+	IID_NS_PARAMETERS,\
+	AUDPREPROC_CMD_CFG_NS_PARAMS,\
+	ACDB_RTC_TX
+	},
+	{
+	ABID_AUDIO_IIR_TX,\
+	IID_AUDIO_RTC_TX_IIR_COEFF,\
+	AUDPREPROC_CMD_CFG_IIR_TUNING_FILTER_PARAMS,\
+	ACDB_RTC_TX
+	},
+	{
+	ABID_AUDIO_IIR_TX,\
+	IID_AUDIO_IIR_COEFF,\
+	AUDPREPROC_CMD_CFG_IIR_TUNING_FILTER_PARAMS,\
+	ACDB_RTC_TX
+	}
+ /*Any new entries should be added here*/
+};
+
+static struct dentry *get_set_abid_dentry;
+static struct dentry *get_set_abid_data_dentry;
+
+struct rtc_acdb_pmem {
+	u8 *viraddr;
+	int32_t phys;
+	void *map_v_rtc;
+};
+
+struct rtc_acdb_data {
+	u32 acdb_id;
+	u32 cmd_id;
+	u32 set_abid;
+	u32 set_iid;
+	u32 abid;
+	u32 err;
+	bool valid_abid;
+	u32 tx_rx_ctl;
+	struct rtc_acdb_pmem rtc_read;
+	struct rtc_acdb_pmem rtc_write;
+	wait_queue_head_t  wait;
+};
+
+struct get_abid {
+	u32	cmd_id;
+	u32	acdb_id;
+	u32	set_abid;
+	u32	set_iid;
+};
+
+struct acdb_block_mbadrc_rtc {
+	u16 enable;
+	u16 num_bands;
+	u16 down_samp_level;
+	u16 adrc_delay;
+	u16 ext_buf_size;
+	u16 ext_partition;
+	u16 ext_buf_msw;
+	u16 ext_buf_lsw;
+	struct adrc_config adrc_band[AUDPP_MAX_MBADRC_BANDS];
+	signed int ext_buff[196];
+} __packed;
+
+enum {
+	ACDB_RTC_SUCCESS,
+	ACDB_RTC_ERR_INVALID_DEVICE,
+	ACDB_RTC_ERR_DEVICE_INACTIVE,
+	ACDB_RTC_ERR_INVALID_ABID,
+	ACDB_RTC_DSP_FAILURE,
+	ACDB_RTC_DSP_FEATURE_NOT_AVAILABLE,
+	ACDB_RTC_ERR_INVALID_LEN,
+	ACDB_RTC_ERR_UNKNOWN_FAILURE,
+	ACDB_RTC_PENDING_RESPONSE,
+	ACDB_RTC_INIT_FAILURE,
+};
+
+static  struct rtc_acdb_data rtc_acdb;
+
+static int rtc_getsetabid_dbg_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	MM_DBG("GET-SET ABID Open debug intf %s\n",\
+			(char *) file->private_data);
+	return 0;
+}
+
+static bool get_feature_id(u32 set_abid, u32 iid, unsigned short *feature_id)
+{
+	bool ret_value = false;
+	int i = 0;
+
+	for (; i < (sizeof(acdb_audpp_entry) / sizeof(acdb_audpp_entry[0]));\
+		i++) {
+		if (acdb_audpp_entry[i][0] == set_abid &&
+			acdb_audpp_entry[i][1] == iid) {
+			*feature_id =  acdb_audpp_entry[i][2];
+			rtc_acdb.tx_rx_ctl = acdb_audpp_entry[i][3];
+			ret_value = true;
+			break;
+		}
+	}
+	return ret_value;
+}
+static ssize_t rtc_getsetabid_dbg_write(struct file *filp,
+					const char __user *ubuf,
+					size_t cnt, loff_t *ppos)
+{
+	struct  get_abid write_abid;
+	unsigned short feat_id = 0;
+	rtc_acdb.valid_abid = false;
+
+	if (copy_from_user(&write_abid, \
+		(void *)ubuf, sizeof(struct get_abid))) {
+		MM_ERR("ACDB DATA WRITE - INVALID READ LEN\n");
+		rtc_acdb.err = ACDB_RTC_ERR_INVALID_LEN;
+		return cnt;
+	}
+	MM_DBG("SET ABID : Cmd ID: %d Device:%d ABID:%d IID : %d cnt: %d\n",\
+		write_abid.cmd_id, write_abid.acdb_id,\
+		write_abid.set_abid, write_abid.set_iid, cnt);
+	if (write_abid.acdb_id > ACDB_ID_MAX ||
+		write_abid.acdb_id < ACDB_ID_HANDSET_SPKR){
+		rtc_acdb.err = ACDB_RTC_ERR_INVALID_DEVICE;
+		return cnt;
+	}
+
+	rtc_acdb.err = ACDB_RTC_ERR_INVALID_ABID;
+	rtc_acdb.abid = write_abid.set_abid;
+	if (get_feature_id(write_abid.set_abid, \
+		write_abid.set_iid, &feat_id)) {
+		rtc_acdb.err = ACDB_RTC_SUCCESS;
+		rtc_acdb.cmd_id = write_abid.cmd_id;
+		rtc_acdb.acdb_id = write_abid.acdb_id;
+		rtc_acdb.set_abid = feat_id;
+		rtc_acdb.valid_abid = true;
+		rtc_acdb.set_iid = write_abid.set_iid;
+	}
+	return cnt;
+}
+static ssize_t	rtc_getsetabid_dbg_read(struct file *file, char __user *buf,
+					size_t count, loff_t *ppos)
+{
+	static char buffer[1024];
+	int n = 0;
+	u32 msg = rtc_acdb.err;
+	memcpy(buffer, &rtc_acdb.cmd_id, sizeof(struct get_abid));
+	memcpy(buffer+16, &msg, 4);
+	n = 20;
+	MM_INFO("SET ABID : Cmd ID: %x Device:%x ABID:%x IID : %x Err: %d\n",\
+		rtc_acdb.cmd_id, rtc_acdb.acdb_id, rtc_acdb.set_abid,\
+		rtc_acdb.set_iid, rtc_acdb.err);
+	return simple_read_from_buffer(buf, count, ppos, buffer, n);
+}
+
+static int rtc_getsetabid_data_dbg_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	MM_INFO("GET-SET ABID DATA Open debug intf %s\n",
+		(char *) file->private_data);
+	return 0;
+}
+
+void acdb_rtc_set_err(u32 err_code)
+{
+	if (rtc_acdb.err == ACDB_RTC_PENDING_RESPONSE) {
+		if (err_code == 0xFFFF) {
+			rtc_acdb.err = ACDB_RTC_SUCCESS;
+			MM_INFO("RTC READ SUCCESS---\n");
+		} else if (err_code == 0) {
+			rtc_acdb.err = ACDB_RTC_DSP_FAILURE;
+			MM_INFO("RTC READ FAIL---\n");
+		} else if (err_code == 1) {
+			rtc_acdb.err = ACDB_RTC_DSP_FEATURE_NOT_AVAILABLE;
+			MM_INFO("RTC READ FEAT UNAVAILABLE---\n");
+		} else {
+			rtc_acdb.err = ACDB_RTC_DSP_FAILURE;
+			MM_INFO("RTC Err CODE---\n");
+		}
+	} else {
+		rtc_acdb.err = ACDB_RTC_DSP_FAILURE;
+		MM_ERR("RTC Err code Invalid State\n");
+	}
+	wake_up(&rtc_acdb.wait);
+}
+
+static ssize_t	rtc_getsetabid_data_dbg_read(struct file *file,
+					char __user *buf, size_t count,
+					loff_t *ppos)
+{
+	static char buffer[PMEM_RTC_ACDB_QUERY_MEM];
+	int rc, n = 0;
+	int counter = 0;
+	struct rtc_acdb_pmem *rtc_read = &rtc_acdb.rtc_read;
+	memset(&buffer, 0, PMEM_RTC_ACDB_QUERY_MEM);
+
+	if (rtc_acdb.valid_abid != true) {
+		MM_ERR("ACDB DATA READ ---INVALID ABID\n");
+		n = 0;
+		rtc_acdb.err = ACDB_RTC_ERR_INVALID_ABID;
+	} else {
+		if (PMEM_RTC_ACDB_QUERY_MEM < count) {
+			MM_ERR("ACDB DATA READ ---"\
+				"INVALID READ LEN %x\n", count);
+			n = 0;
+			rtc_acdb.err = ACDB_RTC_ERR_INVALID_LEN;
+		} else {
+			rtc_acdb.err = ACDB_RTC_PENDING_RESPONSE;
+			if (rtc_read->viraddr != NULL) {
+				memset(rtc_read->viraddr,
+					0, PMEM_RTC_ACDB_QUERY_MEM);
+			}
+			if (rtc_acdb.tx_rx_ctl == ACDB_RTC_RX) {
+				struct rtc_audpp_read_data rtc_read_cmd;
+				rtc_read_cmd.cmd_id =
+					AUDPP_CMD_PP_FEAT_QUERY_PARAMS;
+				rtc_read_cmd.obj_id =
+					AUDPP_CMD_COPP_STREAM;
+				rtc_read_cmd.feature_id = rtc_acdb.set_abid;
+				rtc_read_cmd.extbufsizemsw =
+					EXTRACT_HIGH_WORD(\
+						PMEM_RTC_ACDB_QUERY_MEM);
+				rtc_read_cmd.extbufsizelsw =
+					EXTRACT_LOW_WORD(\
+						PMEM_RTC_ACDB_QUERY_MEM);
+				rtc_read_cmd.extpart = 0x0000;
+				rtc_read_cmd.extbufstartmsw =
+					EXTRACT_HIGH_WORD(rtc_read->phys);
+				rtc_read_cmd.extbufstartlsw =
+					EXTRACT_LOW_WORD(rtc_read->phys);
+				rc = audpp_send_queue2(&rtc_read_cmd,
+						sizeof(rtc_read_cmd));
+			} else if (rtc_acdb.tx_rx_ctl == ACDB_RTC_TX) {
+				struct rtc_audpreproc_read_data rtc_audpreproc;
+				rtc_audpreproc.cmd_id =
+					AUDPREPROC_CMD_FEAT_QUERY_PARAMS;
+				rtc_audpreproc.feature_id = rtc_acdb.set_abid;
+				 /*AUDREC1 is used for pcm recording */
+				rtc_audpreproc.stream_id = 1;
+				rtc_audpreproc.extbufsizemsw =
+					EXTRACT_HIGH_WORD(\
+						PMEM_RTC_ACDB_QUERY_MEM);
+				rtc_audpreproc.extbufsizelsw =
+					EXTRACT_LOW_WORD(\
+						PMEM_RTC_ACDB_QUERY_MEM);
+				rtc_audpreproc.extpart = 0x0000;
+				rtc_audpreproc.extbufstartmsw =
+					EXTRACT_HIGH_WORD(rtc_read->phys);
+				rtc_audpreproc.extbufstartlsw =
+					EXTRACT_LOW_WORD(rtc_read->phys);
+				rc =  audpreproc_send_preproccmdqueue(
+						&rtc_audpreproc,\
+						sizeof(rtc_audpreproc));
+				MM_INFO("ACDB READ Command RC --->%x,"\
+					"stream_id %x\n", rc,
+					acdb_data.preproc_stream_id);
+			}
+		rc = wait_event_timeout(rtc_acdb.wait,
+					(rtc_acdb.err !=
+					ACDB_RTC_PENDING_RESPONSE),
+					msecs_to_jiffies(RTC_MAX_TIMEOUT));
+		MM_INFO("ACDB READ ACK Count = %x Err = %x\n",
+			count, rtc_acdb.err);
+		{
+			if (rtc_acdb.err == ACDB_RTC_SUCCESS
+				&& rtc_read->viraddr != NULL) {
+				memcpy(buffer, rtc_read->viraddr, count);
+				n = count;
+				while (counter < count) {
+					MM_DBG("%x", \
+						rtc_read->viraddr[counter]);
+					counter++;
+					}
+				}
+		}
+	}
+	}
+	return simple_read_from_buffer(buf, count, ppos, buffer, n);
+}
+
+static bool acdb_set_tx_rtc(const char *ubuf, size_t writecount)
+{
+	audpreproc_cmd_cfg_iir_tuning_filter_params *preproc_iir;
+	audpreproc_cmd_cfg_agc_params *preproc_agc;
+	audpreproc_cmd_cfg_ns_params *preproc_ns;
+	s32	result = 0;
+	bool retval = false;
+	unsigned short iircmdsize =
+		sizeof(audpreproc_cmd_cfg_iir_tuning_filter_params);
+	unsigned short iircmdid = AUDPREPROC_CMD_CFG_IIR_TUNING_FILTER_PARAMS;
+
+	rtc_acdb.err = ACDB_RTC_ERR_UNKNOWN_FAILURE;
+
+	switch (rtc_acdb.set_abid) {
+
+	case AUDPREPROC_CMD_CFG_AGC_PARAMS:
+	{
+		preproc_agc = kmalloc(sizeof(\
+					audpreproc_cmd_cfg_agc_params),\
+					GFP_KERNEL);
+		if ((sizeof(audpreproc_cmd_cfg_agc_params) -\
+			(sizeof(unsigned short)))
+			< writecount) {
+				MM_ERR("ACDB DATA WRITE --"\
+					"AGC TX writecount > DSP struct\n");
+		} else {
+			if (preproc_agc != NULL) {
+				char *base; unsigned short offset;
+				unsigned short *offset_addr;
+				base = (char *)preproc_agc;
+				offset = offsetof(\
+					audpreproc_cmd_cfg_agc_params,\
+						tx_agc_param_mask);
+				offset_addr = (unsigned short *)(base + offset);
+				if ((copy_from_user(offset_addr,\
+					(void *)ubuf, writecount)) == 0x00) {
+					preproc_agc->cmd_id =
+						AUDPREPROC_CMD_CFG_AGC_PARAMS;
+
+					result = audpreproc_dsp_set_agc(
+						preproc_agc,
+						sizeof(\
+						audpreproc_cmd_cfg_agc_params));
+					if (result) {
+						MM_ERR("ACDB=> Failed to "\
+							"send AGC data to "\
+							"preproc)\n");
+					} else {
+						retval = true;
+					       }
+				} else {
+					MM_ERR("ACDB DATA WRITE ---"\
+						"GC Tx copy_from_user Fail\n");
+				}
+			} else {
+				MM_ERR("ACDB DATA WRITE --"\
+					"AGC TX kalloc Failed LEN\n");
+			}
+		}
+		if (preproc_agc != NULL)
+			kfree(preproc_agc);
+		break;
+	}
+	case AUDPREPROC_CMD_CFG_NS_PARAMS:
+	{
+
+		preproc_ns = kmalloc(sizeof(\
+					audpreproc_cmd_cfg_ns_params),\
+					GFP_KERNEL);
+		if ((sizeof(audpreproc_cmd_cfg_ns_params) -\
+				(sizeof(unsigned short)))
+				< writecount) {
+				MM_ERR("ACDB DATA WRITE --"\
+					"NS TX writecount > DSP struct\n");
+		} else {
+			if (preproc_ns != NULL) {
+				char *base; unsigned short offset;
+				unsigned short *offset_addr;
+				base = (char *)preproc_ns;
+				offset = offsetof(\
+						audpreproc_cmd_cfg_ns_params,\
+						ec_mode_new);
+				offset_addr = (unsigned short *)(base + offset);
+				if ((copy_from_user(offset_addr,\
+					(void *)ubuf, writecount)) == 0x00) {
+					preproc_ns->cmd_id =
+						AUDPREPROC_CMD_CFG_NS_PARAMS;
+					result = audpreproc_dsp_set_ns(
+						preproc_ns,
+						sizeof(\
+						audpreproc_cmd_cfg_ns_params));
+					if (result) {
+						MM_ERR("ACDB=> Failed to send "\
+							"NS data to preproc\n");
+					} else {
+						retval = true;
+					}
+				} else {
+					MM_ERR("ACDB DATA WRITE ---NS Tx "\
+						"copy_from_user Fail\n");
+					}
+			} else {
+				MM_ERR("ACDB DATA WRITE --NS TX "\
+					"kalloc Failed LEN\n");
+			}
+		}
+		if (preproc_ns != NULL)
+			kfree(preproc_ns);
+		break;
+	}
+	case AUDPREPROC_CMD_CFG_IIR_TUNING_FILTER_PARAMS:
+	{
+
+		preproc_iir = kmalloc(sizeof(\
+				audpreproc_cmd_cfg_iir_tuning_filter_params),\
+				GFP_KERNEL);
+		if ((sizeof(\
+			audpreproc_cmd_cfg_iir_tuning_filter_params)-\
+			(sizeof(unsigned short)))
+			< writecount) {
+			MM_ERR("ACDB DATA WRITE --IIR TX writecount "\
+						"> DSP struct\n");
+		} else {
+			if (preproc_iir != NULL) {
+				char *base; unsigned short offset;
+				unsigned short *offset_addr;
+				base = (char *)preproc_iir;
+				offset = offsetof(\
+				audpreproc_cmd_cfg_iir_tuning_filter_params,\
+				active_flag);
+				offset_addr = (unsigned short *)(base + \
+						offset);
+				if ((copy_from_user(offset_addr,\
+					(void *)ubuf, writecount)) == 0x00) {
+					preproc_iir->cmd_id = iircmdid;
+					result = audpreproc_dsp_set_iir(\
+							preproc_iir,
+							iircmdsize);
+					if (result) {
+						MM_ERR("ACDB=> Failed to send "\
+						"IIR data to preproc\n");
+					} else {
+						retval = true;
+					}
+				} else {
+					MM_ERR("ACDB DATA WRITE ---IIR Tx "\
+						"copy_from_user Fail\n");
+				}
+			} else {
+				MM_ERR("ACDB DATA WRITE --IIR TX kalloc "\
+					"Failed LEN\n");
+		     }
+		}
+		if (preproc_iir != NULL)
+			kfree(preproc_iir);
+		break;
+	}
+	}
+	return retval;
+}
+
+static bool acdb_set_rx_rtc(const char *ubuf, size_t writecount)
+{
+
+	audpp_cmd_cfg_object_params_volume *volpan_config;
+	audpp_cmd_cfg_object_params_mbadrc *mbadrc_config;
+	struct acdb_block_mbadrc_rtc *acdb_mbadrc_rtc;
+	audpp_cmd_cfg_object_params_eqalizer *eq_config;
+	audpp_cmd_cfg_object_params_pcm *iir_config;
+	struct rtc_acdb_pmem *rtc_write = &rtc_acdb.rtc_write;
+	s32	result = 0;
+	bool retval = false;
+
+	switch (rtc_acdb.set_abid) {
+	case AUDPP_CMD_VOLUME_PAN:
+	{
+		volpan_config =  kmalloc(sizeof(\
+					 audpp_cmd_cfg_object_params_volume),\
+					 GFP_KERNEL);
+		if ((sizeof(audpp_cmd_cfg_object_params_volume) -\
+			sizeof(audpp_cmd_cfg_object_params_common))
+			< writecount) {
+			MM_ERR("ACDB DATA WRITE -- "\
+				"VolPan writecount > DSP struct\n");
+		} else {
+			if (volpan_config != NULL) {
+				char *base; unsigned short offset;
+				unsigned short *offset_addr;
+				base = (char *)volpan_config;
+				offset = offsetof(\
+					audpp_cmd_cfg_object_params_volume,\
+					volume);
+				offset_addr = (unsigned short *)(base+offset);
+				if ((copy_from_user(offset_addr,\
+					(void *)ubuf, writecount)) == 0x00) {
+					MM_ERR("ACDB RX WRITE DATA: "\
+						"AUDPP_CMD_VOLUME_PAN\n");
+					result = audpp_set_volume_and_pan(
+						COMMON_OBJ_ID,
+						volpan_config->volume,
+						volpan_config->pan);
+					if (result) {
+						MM_ERR("ACDB=> Failed to "\
+							"send VOLPAN data to"
+							" postproc\n");
+					} else {
+						retval = true;
+					}
+				} else {
+					MM_ERR("ACDB DATA WRITE ---"\
+						"copy_from_user Fail\n");
+				}
+			} else {
+				MM_ERR("ACDB DATA WRITE --"\
+					"Vol Pan kalloc Failed LEN\n");
+			}
+		}
+	if (volpan_config != NULL)
+		kfree(volpan_config);
+	break;
+	}
+
+	case AUDPP_CMD_IIR_TUNING_FILTER:
+	{
+		iir_config =  kmalloc(sizeof(\
+				audpp_cmd_cfg_object_params_pcm),\
+				GFP_KERNEL);
+		if ((sizeof(audpp_cmd_cfg_object_params_pcm) -\
+			sizeof(audpp_cmd_cfg_object_params_common))
+			< writecount) {
+			MM_ERR("ACDB DATA WRITE --"\
+					"IIR RX writecount > DSP struct\n");
+		} else {
+			if (iir_config != NULL) {
+				char *base; unsigned short offset;
+				unsigned short *offset_addr;
+				base = (char *)iir_config;
+				offset = offsetof(\
+					audpp_cmd_cfg_object_params_pcm,\
+					active_flag);
+				offset_addr = (unsigned short *)(base+offset);
+				if ((copy_from_user(offset_addr,\
+					(void *)ubuf, writecount)) == 0x00) {
+					MM_ERR("ACDB RX WRITE DATA:"\
+					"AUDPP_CMD_IIR_TUNING_FILTER\n");
+					result = audpp_dsp_set_rx_iir(
+						COMMON_OBJ_ID,
+						iir_config->active_flag,\
+						iir_config);
+					if (result) {
+						MM_ERR("ACDB=> Failed to send"\
+							"IIR data to"\
+							"postproc\n");
+					} else {
+						retval = true;
+					}
+				} else {
+					MM_ERR("ACDB DATA WRITE ---"\
+						"IIR Rx copy_from_user Fail\n");
+				      }
+			 } else {
+				MM_ERR("ACDB DATA WRITE --"\
+					"acdb_iir_block kalloc Failed LEN\n");
+			}
+		}
+		if (iir_config != NULL)
+			kfree(iir_config);
+		break;
+	}
+	case AUDPP_CMD_EQUALIZER:
+	{
+		eq_config =  kmalloc(sizeof(\
+				audpp_cmd_cfg_object_params_eqalizer),\
+				GFP_KERNEL);
+	if ((sizeof(audpp_cmd_cfg_object_params_eqalizer) -\
+			sizeof(audpp_cmd_cfg_object_params_common))
+			< writecount) {
+			MM_ERR("ACDB DATA WRITE --"\
+			"EQ RX writecount > DSP struct\n");
+		} else {
+			if (eq_config != NULL) {
+				char *base; unsigned short offset;
+				unsigned short *offset_addr;
+				base = (char *)eq_config;
+				offset = offsetof(\
+					audpp_cmd_cfg_object_params_eqalizer,\
+					eq_flag);
+				offset_addr = (unsigned short *)(base+offset);
+				if ((copy_from_user(offset_addr,\
+					(void *)ubuf, writecount)) == 0x00) {
+					MM_ERR("ACDB RX WRITE"\
+					"DATA:AUDPP_CMD_EQUALIZER\n");
+					result = audpp_dsp_set_eq(
+						COMMON_OBJ_ID,
+						eq_config->eq_flag,\
+						eq_config);
+					if (result) {
+						MM_ERR("ACDB=> Failed to "\
+						"send EQ data to postproc\n");
+					} else {
+						retval = true;
+					}
+				} else {
+					MM_ERR("ACDB DATA WRITE ---"\
+					"EQ Rx copy_from_user Fail\n");
+				}
+			} else {
+				MM_ERR("ACDB DATA WRITE --"\
+					"EQ kalloc Failed LEN\n");
+			}
+		}
+		if (eq_config != NULL)
+			kfree(eq_config);
+		break;
+	}
+
+	case AUDPP_CMD_MBADRC:
+	{
+		acdb_mbadrc_rtc =  kmalloc(sizeof(struct \
+					acdb_block_mbadrc_rtc),\
+					GFP_KERNEL);
+		mbadrc_config =  kmalloc(sizeof(\
+					audpp_cmd_cfg_object_params_mbadrc),\
+					GFP_KERNEL);
+		if (mbadrc_config != NULL && acdb_mbadrc_rtc != NULL) {
+			if ((copy_from_user(acdb_mbadrc_rtc,\
+				(void *)ubuf,
+				sizeof(struct acdb_block_mbadrc_rtc)))
+				== 0x00) {
+
+				memset(mbadrc_config, 0,
+					sizeof(\
+					audpp_cmd_cfg_object_params_mbadrc));
+
+				mbadrc_config->enable =
+						acdb_mbadrc_rtc->enable;
+				mbadrc_config->num_bands =
+						acdb_mbadrc_rtc->num_bands;
+				mbadrc_config->down_samp_level =
+				acdb_mbadrc_rtc->down_samp_level;
+				mbadrc_config->adrc_delay =
+					acdb_mbadrc_rtc->adrc_delay;
+				memcpy(mbadrc_config->adrc_band,\
+					acdb_mbadrc_rtc->adrc_band,\
+					AUDPP_MAX_MBADRC_BANDS *\
+					sizeof(struct adrc_config));
+				if (mbadrc_config->num_bands > 1) {
+					mbadrc_config->ext_buf_size =
+						(97 * 2) + (33 * 2 * \
+					(mbadrc_config->num_bands - 2));
+				}
+				mbadrc_config->ext_partition = 0;
+				mbadrc_config->ext_buf_lsw =
+					(u16) EXTRACT_LOW_WORD(\
+						rtc_write->phys);
+				mbadrc_config->ext_buf_msw =
+					(u16) EXTRACT_HIGH_WORD(\
+						rtc_write->phys);
+				memcpy(rtc_write->viraddr,
+					acdb_mbadrc_rtc->ext_buff,
+					(196*sizeof(signed int)));
+				result = audpp_dsp_set_mbadrc(
+						COMMON_OBJ_ID,
+						mbadrc_config->enable,
+						mbadrc_config);
+				if (result) {
+					MM_ERR("ACDB=> Failed to "\
+						"Send MBADRC data "\
+						"to postproc\n");
+				} else {
+					retval = true;
+				}
+			} else {
+				MM_ERR("ACDB DATA WRITE ---"\
+					"MBADRC Rx copy_from_user Fail\n");
+			}
+		} else {
+			MM_ERR("ACDB DATA WRITE --MBADRC kalloc Failed LEN\n");
+		}
+		if (mbadrc_config != NULL)
+			kfree(mbadrc_config);
+		if (acdb_mbadrc_rtc != NULL)
+			kfree(acdb_mbadrc_rtc);
+	break;
+	}
+	}
+	return retval;
+}
+static ssize_t rtc_getsetabid_data_dbg_write(struct file *filp,
+						const char __user *ubuf,
+						size_t cnt, loff_t *ppos)
+{
+	if (rtc_acdb.valid_abid != true) {
+		MM_INFO("ACDB DATA READ ---INVALID ABID\n");
+		rtc_acdb.err = ACDB_RTC_ERR_INVALID_ABID;
+	} else {
+		if (rtc_acdb.tx_rx_ctl == ACDB_RTC_RX) {
+			if (acdb_set_rx_rtc(ubuf, cnt)) {
+				rtc_acdb.err = ACDB_RTC_SUCCESS;
+			} else {
+				rtc_acdb.err = ACDB_RTC_ERR_UNKNOWN_FAILURE;
+				cnt = 0;
+			}
+		} else if (rtc_acdb.tx_rx_ctl == ACDB_RTC_TX) {
+			if (acdb_set_tx_rtc(ubuf, cnt)) {
+				rtc_acdb.err = ACDB_RTC_SUCCESS;
+			} else {
+				rtc_acdb.err = ACDB_RTC_ERR_UNKNOWN_FAILURE;
+				cnt = 0;
+			}
+		}
+	}
+	return cnt;
+}
+
+
+static const	struct file_operations rtc_acdb_data_debug_fops = {
+	.open = rtc_getsetabid_data_dbg_open,
+	.write = rtc_getsetabid_data_dbg_write,
+	.read = rtc_getsetabid_data_dbg_read
+};
+
+static const	struct file_operations rtc_acdb_debug_fops = {
+	.open = rtc_getsetabid_dbg_open,
+	.write = rtc_getsetabid_dbg_write,
+	.read = rtc_getsetabid_dbg_read
+};
+
+static void rtc_acdb_deinit(void)
+{
+	struct rtc_acdb_pmem *rtc_read = &rtc_acdb.rtc_read;
+	struct rtc_acdb_pmem *rtc_write = &rtc_acdb.rtc_write;
+	if (get_set_abid_dentry) {
+		MM_DBG("GetSet ABID remove debugfs\n");
+		debugfs_remove(get_set_abid_dentry);
+	}
+
+	if (get_set_abid_data_dentry) {
+		MM_DBG("GetSet ABID remove debugfs\n");
+		debugfs_remove(get_set_abid_data_dentry);
+	}
+	rtc_acdb.abid = 0;
+	rtc_acdb.acdb_id = 0;
+	rtc_acdb.cmd_id = 0;
+	rtc_acdb.err = 1;
+	rtc_acdb.set_abid = 0;
+	rtc_acdb.set_iid = 0;
+	rtc_acdb.tx_rx_ctl = 0;
+	rtc_acdb.valid_abid = false;
+
+	if (rtc_read->viraddr != NULL || ((void *)rtc_read->phys) != NULL) {
+		iounmap(rtc_read->map_v_rtc);
+		free_contiguous_memory_by_paddr(rtc_read->phys);
+	}
+	if (rtc_write->viraddr != NULL || ((void *)rtc_write->phys) != NULL) {
+		iounmap(rtc_write->map_v_rtc);
+		free_contiguous_memory_by_paddr(rtc_write->phys);
+	}
+}
+
+static bool rtc_acdb_init(void)
+{
+	struct rtc_acdb_pmem *rtc_read = &rtc_acdb.rtc_read;
+	struct rtc_acdb_pmem *rtc_write = &rtc_acdb.rtc_write;
+	s32 result = 0;
+	char name[sizeof "get_set_abid"+1];
+	char name1[sizeof "get_set_abid_data"+1];
+	rtc_acdb.abid = 0;
+	rtc_acdb.acdb_id = 0;
+	rtc_acdb.cmd_id = 0;
+	rtc_acdb.err = 1;
+	rtc_acdb.set_abid = 0;
+	rtc_acdb.set_iid = 0;
+	rtc_acdb.valid_abid = false;
+	rtc_acdb.tx_rx_ctl = 0;
+
+	snprintf(name, sizeof name, "get_set_abid");
+	get_set_abid_dentry = debugfs_create_file(name,
+			S_IFREG | S_IRUGO | S_IWUGO,
+			NULL, NULL, &rtc_acdb_debug_fops);
+	if (IS_ERR(get_set_abid_dentry)) {
+		MM_ERR("SET GET ABID debugfs_create_file failed\n");
+		return false;
+	}
+
+	snprintf(name1, sizeof name1, "get_set_abid_data");
+	get_set_abid_data_dentry = debugfs_create_file(name1,
+			S_IFREG | S_IRUGO | S_IWUGO,
+			NULL, NULL,
+			&rtc_acdb_data_debug_fops);
+	if (IS_ERR(get_set_abid_data_dentry)) {
+		MM_ERR("SET GET ABID DATA"\
+				" debugfs_create_file failed\n");
+		return false;
+	}
+
+	rtc_read->phys = allocate_contiguous_ebi_nomap(PMEM_RTC_ACDB_QUERY_MEM,
+								 SZ_4K);
+
+	if (!rtc_read->phys) {
+		MM_ERR("ACDB Cannot allocate physical memory\n");
+		result = -ENOMEM;
+		goto error;
+	}
+	rtc_read->map_v_rtc = ioremap(rtc_read->phys,
+				PMEM_RTC_ACDB_QUERY_MEM);
+
+	if (IS_ERR(rtc_read->map_v_rtc)) {
+		MM_ERR("ACDB Could not map physical address\n");
+		result = -ENOMEM;
+		goto error;
+	}
+	rtc_read->viraddr = rtc_read->map_v_rtc;
+	memset(rtc_read->viraddr, 0, PMEM_RTC_ACDB_QUERY_MEM);
+
+	rtc_write->phys = allocate_contiguous_ebi_nomap(PMEM_RTC_ACDB_QUERY_MEM,
+								SZ_4K);
+
+	if (!rtc_write->phys) {
+		MM_ERR("ACDB Cannot allocate physical memory\n");
+		result = -ENOMEM;
+		goto error;
+	}
+	rtc_write->map_v_rtc = ioremap(rtc_write->phys,
+				PMEM_RTC_ACDB_QUERY_MEM);
+
+	if (IS_ERR(rtc_write->map_v_rtc)) {
+		MM_ERR("ACDB Could not map physical address\n");
+		result = -ENOMEM;
+		goto error;
+	}
+	rtc_write->viraddr = rtc_write->map_v_rtc;
+	memset(rtc_write->viraddr, 0, PMEM_RTC_ACDB_QUERY_MEM);
+	init_waitqueue_head(&rtc_acdb.wait);
+	return true;
+error:
+	MM_DBG("INIT RTC FAILED REMOVING RTC DEBUG FS\n");
+	if (get_set_abid_dentry) {
+		MM_DBG("GetSet ABID remove debugfs\n");
+		debugfs_remove(get_set_abid_dentry);
+	}
+
+	if (get_set_abid_data_dentry) {
+		MM_DBG("GetSet ABID remove debugfs\n");
+		debugfs_remove(get_set_abid_data_dentry);
+	}
+	if (rtc_read->viraddr != NULL || ((void *)rtc_read->phys) != NULL) {
+		iounmap(rtc_read->map_v_rtc);
+		free_contiguous_memory_by_paddr(rtc_read->phys);
+	}
+	if (rtc_write->viraddr != NULL || ((void *)rtc_write->phys) != NULL) {
+		iounmap(rtc_write->map_v_rtc);
+		free_contiguous_memory_by_paddr(rtc_write->phys);
+	}
+	return false;
+}
+#else
+void acdb_rtc_set_err(u32 err_code)
+{
+	return 0
+}
+#endif /*CONFIG_DEBUG_FS*/
+static s32 acdb_set_calibration_blk(unsigned long arg)
+{
+	struct acdb_cmd_device acdb_cmd;
+	s32 result = 0;
+
+	MM_DBG("acdb_set_calibration_blk\n");
+	if (copy_from_user(&acdb_cmd, (struct acdb_cmd_device *)arg,
+			sizeof(acdb_cmd))) {
+		MM_ERR("Failed copy command struct from user in"\
+			"acdb_set_calibration_blk\n");
+		return -EFAULT;
+	}
+	acdb_cmd.phys_buf = (u32 *)acdb_data.paddr;
+
+	MM_DBG("acdb_cmd.phys_buf %x\n", (u32)acdb_cmd.phys_buf);
+
+	result = dalrpc_fcn_8(ACDB_DAL_IOCTL, acdb_data.handle,
+			(const void *)&acdb_cmd, sizeof(acdb_cmd),
+			&acdb_data.acdb_result,
+			sizeof(acdb_data.acdb_result));
+
+	if (result < 0) {
+		MM_ERR("ACDB=> Device Set RPC failure"\
+			" result = %d\n", result);
+		return -EINVAL;
+	} else {
+		MM_ERR("ACDB=> Device Set RPC success\n");
+		if (acdb_data.acdb_result.result == ACDB_RES_SUCCESS)
+			MM_DBG("ACDB_SET_DEVICE Success\n");
+		else if (acdb_data.acdb_result.result == ACDB_RES_FAILURE)
+			MM_ERR("ACDB_SET_DEVICE Failure\n");
+		else if (acdb_data.acdb_result.result == ACDB_RES_BADPARM)
+			MM_ERR("ACDB_SET_DEVICE BadParams\n");
+		else
+			MM_ERR("Unknown error\n");
+	}
+	return result;
+}
+
+static s32 acdb_get_calibration_blk(unsigned long arg)
+{
+	s32 result = 0;
+	struct acdb_cmd_device acdb_cmd;
+
+	MM_DBG("acdb_get_calibration_blk\n");
+
+	if (copy_from_user(&acdb_cmd, (struct acdb_cmd_device *)arg,
+			sizeof(acdb_cmd))) {
+		MM_ERR("Failed copy command struct from user in"\
+			"acdb_get_calibration_blk\n");
+		return -EFAULT;
+	}
+	acdb_cmd.phys_buf = (u32 *)acdb_data.paddr;
+	MM_ERR("acdb_cmd.phys_buf %x\n", (u32)acdb_cmd.phys_buf);
+
+	result = dalrpc_fcn_8(ACDB_DAL_IOCTL, acdb_data.handle,
+			(const void *)&acdb_cmd, sizeof(acdb_cmd),
+			&acdb_data.acdb_result,
+			sizeof(acdb_data.acdb_result));
+
+	if (result < 0) {
+		MM_ERR("ACDB=> Device Get RPC failure"\
+			" result = %d\n", result);
+		return -EINVAL;
+	} else {
+		MM_ERR("ACDB=> Device Get RPC Success\n");
+		if (acdb_data.acdb_result.result == ACDB_RES_SUCCESS)
+			MM_DBG("ACDB_GET_DEVICE Success\n");
+		else if (acdb_data.acdb_result.result == ACDB_RES_FAILURE)
+			MM_ERR("ACDB_GET_DEVICE Failure\n");
+		else if (acdb_data.acdb_result.result == ACDB_RES_BADPARM)
+			MM_ERR("ACDB_GET_DEVICE BadParams\n");
+		else
+			MM_ERR("Unknown error\n");
+	}
+	return result;
+}
+
+static int audio_acdb_open(struct inode *inode, struct file *file)
+{
+	MM_DBG("%s\n", __func__);
+	return 0;
+}
+static int audio_acdb_release(struct inode *inode, struct file *file)
+{
+	MM_DBG("%s\n", __func__);
+	return 0;
+}
+
+static long audio_acdb_ioctl(struct file *file, unsigned int cmd,
+					unsigned long arg)
+{
+	int rc = 0;
+	unsigned long flags = 0;
+	struct msm_audio_pmem_info info;
+
+	MM_DBG("%s\n", __func__);
+
+	switch (cmd) {
+	case AUDIO_SET_EQ:
+		MM_DBG("IOCTL SET_EQ_CONFIG\n");
+		if (copy_from_user(&acdb_data.eq.num_bands, (void *) arg,
+				sizeof(acdb_data.eq) -
+				(AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN + 2))) {
+			rc = -EFAULT;
+			break;
+		}
+		spin_lock_irqsave(&acdb_data.dsp_lock, flags);
+		rc = audpp_dsp_set_eq(COMMON_OBJ_ID, 1,
+			&acdb_data.eq);
+		if (rc < 0)
+			MM_ERR("AUDPP returned err =%d\n", rc);
+		spin_unlock_irqrestore(&acdb_data.dsp_lock, flags);
+		break;
+	case AUDIO_REGISTER_PMEM:
+		MM_DBG("AUDIO_REGISTER_PMEM\n");
+		if (copy_from_user(&info, (void *) arg, sizeof(info))) {
+			MM_ERR("Cannot copy from user\n");
+			return -EFAULT;
+		}
+		rc = get_pmem_file(info.fd, &acdb_data.paddr,
+					&acdb_data.kvaddr,
+					&acdb_data.pmem_len,
+					&acdb_data.file);
+		if (rc == 0)
+			acdb_data.pmem_fd = info.fd;
+		break;
+	case AUDIO_DEREGISTER_PMEM:
+		if (acdb_data.pmem_fd)
+			put_pmem_file(acdb_data.file);
+		break;
+	case AUDIO_SET_ACDB_BLK:
+		MM_DBG("IOCTL AUDIO_SET_ACDB_BLK\n");
+		rc = acdb_set_calibration_blk(arg);
+		break;
+	case AUDIO_GET_ACDB_BLK:
+		MM_DBG("IOiCTL AUDIO_GET_ACDB_BLK\n");
+		rc = acdb_get_calibration_blk(arg);
+		break;
+	default:
+		MM_DBG("Unknown IOCTL%d\n", cmd);
+		rc = -EINVAL;
+	}
+	return rc;
+}
+
+static const struct file_operations acdb_fops = {
+	.owner = THIS_MODULE,
+	.open = audio_acdb_open,
+	.release = audio_acdb_release,
+	.llseek = no_llseek,
+	.unlocked_ioctl = audio_acdb_ioctl
+};
+
+struct miscdevice acdb_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_acdb",
+	.fops	= &acdb_fops,
+};
+
+static s32 acdb_get_calibration(void)
+{
+	struct acdb_cmd_get_device_table	acdb_cmd;
+	s32					result = 0;
+	u32 iterations = 0;
+
+	MM_DBG("acdb state = %d\n", acdb_data.acdb_state);
+
+	acdb_cmd.command_id = ACDB_GET_DEVICE_TABLE;
+	acdb_cmd.device_id = acdb_data.device_info->acdb_id;
+	acdb_cmd.network_id = 0x0108B153;
+	acdb_cmd.sample_rate_id = acdb_data.device_info->sample_rate;
+	acdb_cmd.total_bytes = ACDB_BUF_SIZE;
+	acdb_cmd.phys_buf = (u32 *)acdb_data.phys_addr;
+	MM_DBG("device_id = %d, sampling_freq = %d\n",
+				acdb_cmd.device_id, acdb_cmd.sample_rate_id);
+
+	do {
+		result = dalrpc_fcn_8(ACDB_DAL_IOCTL, acdb_data.handle,
+				(const void *)&acdb_cmd, sizeof(acdb_cmd),
+				&acdb_data.acdb_result,
+				sizeof(acdb_data.acdb_result));
+
+		if (result < 0) {
+			MM_ERR("ACDB=> Device table RPC failure"\
+				" result = %d\n", result);
+			goto error;
+		}
+		/*following check is introduced to handle boot up race
+		condition between AUDCAL SW peers running on apps
+		and modem (ACDB_RES_BADSTATE indicates modem AUDCAL SW is
+		not in initialized sate) we need to retry to get ACDB
+		values*/
+		if (acdb_data.acdb_result.result == ACDB_RES_BADSTATE) {
+			msleep(500);
+			iterations++;
+		} else if (acdb_data.acdb_result.result == ACDB_RES_SUCCESS) {
+			MM_DBG("Modem query for acdb values is successful"\
+					" (iterations = %d)\n", iterations);
+			acdb_data.acdb_state |= CAL_DATA_READY;
+			return result;
+		} else {
+			MM_ERR("ACDB=> modem failed to fill acdb values,"\
+					" reuslt = %d, (iterations = %d)\n",
+					acdb_data.acdb_result.result,
+					iterations);
+			goto error;
+		}
+	} while (iterations < MAX_RETRY);
+	MM_ERR("ACDB=> AUDCAL SW on modem is not in intiailized state (%d)\n",
+			acdb_data.acdb_result.result);
+error:
+	result = -EINVAL;
+	return result;
+}
+
+s32 acdb_get_calibration_data(struct acdb_get_block *get_block)
+{
+	s32 result = -EINVAL;
+	struct acdb_cmd_device acdb_cmd;
+	struct acdb_result acdb_result;
+
+	MM_DBG("acdb_get_calibration_data\n");
+
+	acdb_cmd.command_id = ACDB_GET_DEVICE;
+	acdb_cmd.network_id = 0x0108B153;
+	acdb_cmd.device_id = get_block->acdb_id;
+	acdb_cmd.sample_rate_id = get_block->sample_rate_id;
+	acdb_cmd.interface_id = get_block->interface_id;
+	acdb_cmd.algorithm_block_id = get_block->algorithm_block_id;
+	acdb_cmd.total_bytes = get_block->total_bytes;
+	acdb_cmd.phys_buf = (u32 *)acdb_data.get_blk_paddr;
+
+	result = dalrpc_fcn_8(ACDB_DAL_IOCTL, acdb_data.handle,
+			(const void *)&acdb_cmd, sizeof(acdb_cmd),
+			&acdb_result,
+			sizeof(acdb_result));
+
+	if (result < 0) {
+		MM_ERR("ACDB=> Device Get RPC failure"\
+			" result = %d\n", result);
+		goto err_state;
+	} else {
+		MM_DBG("ACDB=> Device Get RPC Success\n");
+		if (acdb_result.result == ACDB_RES_SUCCESS) {
+			MM_DBG("ACDB_GET_DEVICE Success\n");
+			result = 0;
+			memcpy(get_block->buf_ptr, acdb_data.get_blk_kvaddr,
+					get_block->total_bytes);
+		} else if (acdb_result.result == ACDB_RES_FAILURE)
+			MM_ERR("ACDB_GET_DEVICE Failure\n");
+		else if (acdb_result.result == ACDB_RES_BADPARM)
+			MM_ERR("ACDB_GET_DEVICE BadParams\n");
+		else
+			MM_ERR("Unknown error\n");
+	}
+err_state:
+	return result;
+}
+EXPORT_SYMBOL(acdb_get_calibration_data);
+
+static u8 check_device_info_already_present(
+		struct dev_evt_msg device_info,
+			struct acdb_cache_node *acdb_cache_free_node)
+{
+	if ((device_info.sample_rate ==
+				acdb_cache_free_node->device_info.\
+				sample_rate) &&
+			(device_info.acdb_id ==
+				acdb_cache_free_node->device_info.acdb_id)) {
+		MM_DBG("acdb values are already present\n");
+		/*if acdb state is not set for CAL_DATA_READY and node status
+		is filled, acdb state should be updated with CAL_DATA_READY
+		state*/
+		acdb_data.acdb_state |= CAL_DATA_READY;
+		return 1; /*node is present but status as filled*/
+	}
+	MM_DBG("copying device info into node\n");
+	/*as device information is not present in cache copy
+	the current device information into the node*/
+	memcpy(&acdb_cache_free_node->device_info,
+				 &device_info, sizeof(device_info));
+	return 0; /*cant find the node*/
+}
+
+static struct acdb_iir_block *get_audpp_irr_block(void)
+{
+	struct header *prs_hdr;
+	u32 index = 0;
+
+	while (index < acdb_data.acdb_result.used_bytes) {
+		prs_hdr = (struct header *)(acdb_data.virt_addr + index);
+		if (prs_hdr->dbor_signature == DBOR_SIGNATURE) {
+			if (prs_hdr->abid == ABID_AUDIO_IIR_RX) {
+				if (prs_hdr->iid == IID_AUDIO_IIR_COEFF)
+					return (struct acdb_iir_block *)
+						(acdb_data.virt_addr + index
+						 + sizeof(struct header));
+			} else {
+				index += prs_hdr->data_len +
+						sizeof(struct header);
+			}
+		} else {
+			break;
+		}
+	}
+	return NULL;
+}
+
+
+static s32 acdb_fill_audpp_iir(void)
+{
+	struct acdb_iir_block *acdb_iir;
+	s32 i = 0;
+
+	acdb_iir = get_audpp_irr_block();
+	if (acdb_iir == NULL) {
+		MM_ERR("unable to find  audpp iir block returning\n");
+		return -EINVAL;
+	}
+	memset(acdb_data.pp_iir, 0, sizeof(*acdb_data.pp_iir));
+
+	acdb_data.pp_iir->active_flag = acdb_iir->enable_flag;
+	acdb_data.pp_iir->num_bands = acdb_iir->stage_count;
+	for (; i < acdb_iir->stage_count; i++) {
+		acdb_data.pp_iir->params_filter.filter_4_params.
+			numerator_filter[i].numerator_b0_filter_lsw =
+			acdb_iir->stages[i].b0_lo;
+		acdb_data.pp_iir->params_filter.filter_4_params.
+			numerator_filter[i].numerator_b0_filter_msw =
+			acdb_iir->stages[i].b0_hi;
+		acdb_data.pp_iir->params_filter.filter_4_params.
+			numerator_filter[i].numerator_b1_filter_lsw =
+			acdb_iir->stages[i].b1_lo;
+		acdb_data.pp_iir->params_filter.filter_4_params.
+			numerator_filter[i].numerator_b1_filter_msw =
+			acdb_iir->stages[i].b1_hi;
+		acdb_data.pp_iir->params_filter.filter_4_params.
+			numerator_filter[i].numerator_b2_filter_lsw =
+			acdb_iir->stages[i].b2_lo;
+		acdb_data.pp_iir->params_filter.filter_4_params.
+			numerator_filter[i].numerator_b2_filter_msw =
+			acdb_iir->stages[i].b2_hi;
+		acdb_data.pp_iir->params_filter.filter_4_params.
+			denominator_filter[i].denominator_a0_filter_lsw =
+			acdb_iir->stages_a[i].a1_lo;
+		acdb_data.pp_iir->params_filter.filter_4_params.
+			denominator_filter[i].denominator_a0_filter_msw =
+			acdb_iir->stages_a[i].a1_hi;
+		acdb_data.pp_iir->params_filter.filter_4_params.
+			denominator_filter[i].denominator_a1_filter_lsw =
+			acdb_iir->stages_a[i].a2_lo;
+		acdb_data.pp_iir->params_filter.filter_4_params.
+			denominator_filter[i].denominator_a1_filter_msw =
+			acdb_iir->stages_a[i].a2_hi;
+		acdb_data.pp_iir->params_filter.filter_4_params.
+			shift_factor_filter[i].shift_factor_0 =
+			acdb_iir->shift_factor[i];
+		acdb_data.pp_iir->params_filter.filter_4_params.pan_filter[i].
+			pan_filter_0 = acdb_iir->pan[i];
+	}
+	return 0;
+}
+
+static void extract_mbadrc(u32 *phy_addr, struct header *prs_hdr, u32 *index)
+{
+	if (prs_hdr->iid == IID_MBADRC_EXT_BUFF) {
+		MM_DBG("Got IID = IID_MBADRC_EXT_BUFF\n");
+		*phy_addr = acdb_data.phys_addr	+ *index +
+					sizeof(struct header);
+		memcpy(acdb_data.mbadrc_block.ext_buf,
+				(acdb_data.virt_addr + *index +
+					sizeof(struct header)), 196*2);
+		MM_DBG("phy_addr = %x\n", *phy_addr);
+		*index += prs_hdr->data_len + sizeof(struct header);
+	} else if (prs_hdr->iid == IID_MBADRC_BAND_CONFIG) {
+		MM_DBG("Got IID == IID_MBADRC_BAND_CONFIG\n");
+		memcpy(acdb_data.mbadrc_block.band_config, (acdb_data.virt_addr
+					+ *index + sizeof(struct header)),
+				sizeof(struct mbadrc_band_config_type) *
+					 acdb_data.mbadrc_block.parameters.\
+						mbadrc_num_bands);
+		*index += prs_hdr->data_len + sizeof(struct header);
+	} else if (prs_hdr->iid == IID_MBADRC_PARAMETERS) {
+		struct mbadrc_parameter *tmp;
+		tmp = (struct mbadrc_parameter *)(acdb_data.virt_addr + *index
+						+ sizeof(struct header));
+		MM_DBG("Got IID == IID_MBADRC_PARAMETERS");
+		acdb_data.mbadrc_block.parameters.mbadrc_enable =
+							tmp->mbadrc_enable;
+		acdb_data.mbadrc_block.parameters.mbadrc_num_bands =
+							tmp->mbadrc_num_bands;
+		acdb_data.mbadrc_block.parameters.mbadrc_down_sample_level =
+						tmp->mbadrc_down_sample_level;
+		acdb_data.mbadrc_block.parameters.mbadrc_delay =
+							tmp->mbadrc_delay;
+		*index += prs_hdr->data_len + sizeof(struct header);
+	}
+}
+
+static void get_audpp_mbadrc_block(u32 *phy_addr)
+{
+	struct header *prs_hdr;
+	u32 index = 0;
+
+	while (index < acdb_data.acdb_result.used_bytes) {
+		prs_hdr = (struct header *)(acdb_data.virt_addr + index);
+
+		if (prs_hdr->dbor_signature == DBOR_SIGNATURE) {
+			if (prs_hdr->abid == ABID_AUDIO_MBADRC_RX) {
+				if ((prs_hdr->iid == IID_MBADRC_EXT_BUFF)
+					|| (prs_hdr->iid ==
+						IID_MBADRC_BAND_CONFIG)
+					|| (prs_hdr->iid ==
+						IID_MBADRC_PARAMETERS)) {
+					extract_mbadrc(phy_addr, prs_hdr,
+								&index);
+				}
+			} else {
+				index += prs_hdr->data_len +
+						sizeof(struct header);
+			}
+		} else {
+			break;
+		}
+	}
+}
+
+static s32 acdb_fill_audpp_mbadrc(void)
+{
+	u32 mbadrc_phys_addr = -1;
+	get_audpp_mbadrc_block(&mbadrc_phys_addr);
+	if (IS_ERR_VALUE(mbadrc_phys_addr)) {
+		MM_ERR("failed to get mbadrc block\n");
+		return -EINVAL;
+	}
+
+	memset(acdb_data.pp_mbadrc, 0, sizeof(*acdb_data.pp_mbadrc));
+
+	acdb_data.pp_mbadrc->enable = acdb_data.mbadrc_block.\
+					parameters.mbadrc_enable;
+	acdb_data.pp_mbadrc->num_bands =
+				acdb_data.mbadrc_block.\
+					parameters.mbadrc_num_bands;
+	acdb_data.pp_mbadrc->down_samp_level =
+				acdb_data.mbadrc_block.parameters.\
+					mbadrc_down_sample_level;
+	acdb_data.pp_mbadrc->adrc_delay =
+				acdb_data.mbadrc_block.parameters.\
+					mbadrc_delay;
+
+	if (acdb_data.mbadrc_block.parameters.mbadrc_num_bands > 1)
+		acdb_data.pp_mbadrc->ext_buf_size = (97 * 2) +
+			(33 * 2 * (acdb_data.mbadrc_block.parameters.\
+					mbadrc_num_bands - 2));
+
+	acdb_data.pp_mbadrc->ext_partition = 0;
+	acdb_data.pp_mbadrc->ext_buf_lsw = (u16)(mbadrc_phys_addr\
+						 & 0xFFFF);
+	acdb_data.pp_mbadrc->ext_buf_msw = (u16)((mbadrc_phys_addr\
+						 & 0xFFFF0000) >> 16);
+	memcpy(acdb_data.pp_mbadrc->adrc_band, acdb_data.mbadrc_block.\
+					band_config,
+		sizeof(struct mbadrc_band_config_type) *
+		acdb_data.mbadrc_block.parameters.mbadrc_num_bands);
+	return 0;
+}
+
+static s32 acdb_calibrate_audpp(void)
+{
+	s32	result = 0;
+
+	result = acdb_fill_audpp_iir();
+	if (!IS_ERR_VALUE(result)) {
+		result = audpp_dsp_set_rx_iir(COMMON_OBJ_ID,
+				acdb_data.pp_iir->active_flag,
+					acdb_data.pp_iir);
+		if (result) {
+			MM_ERR("ACDB=> Failed to send IIR data to postproc\n");
+			result = -EINVAL;
+			goto done;
+		} else
+			MM_DBG("AUDPP is calibrated with IIR parameters");
+	}
+	result = acdb_fill_audpp_mbadrc();
+	if (!IS_ERR_VALUE(result)) {
+		result = audpp_dsp_set_mbadrc(COMMON_OBJ_ID,
+					acdb_data.pp_mbadrc->enable,
+					acdb_data.pp_mbadrc);
+		if (result) {
+			MM_ERR("ACDB=> Failed to send MBADRC data to"\
+					" postproc\n");
+			result = -EINVAL;
+			goto done;
+		} else
+			MM_DBG("AUDPP is calibrated with MBADRC parameters");
+	}
+done:
+	return result;
+}
+
+static struct acdb_agc_block *get_audpreproc_agc_block(void)
+{
+	struct header *prs_hdr;
+	u32 index = 0;
+
+	while (index < acdb_data.acdb_result.used_bytes) {
+		prs_hdr = (struct header *)(acdb_data.virt_addr + index);
+		if (prs_hdr->dbor_signature == DBOR_SIGNATURE) {
+			if (prs_hdr->abid == ABID_AUDIO_AGC_TX) {
+				if (prs_hdr->iid == IID_AUDIO_AGC_PARAMETERS) {
+					MM_DBG("GOT ABID_AUDIO_AGC_TX\n");
+					return (struct acdb_agc_block *)
+						(acdb_data.virt_addr + index
+						 + sizeof(struct header));
+				}
+			} else {
+				index += prs_hdr->data_len +
+						sizeof(struct header);
+			}
+		} else {
+			break;
+		}
+	}
+	return NULL;
+}
+
+static s32 acdb_fill_audpreproc_agc(void)
+{
+	struct acdb_agc_block	*acdb_agc;
+
+	acdb_agc = get_audpreproc_agc_block();
+	if (!acdb_agc) {
+		MM_DBG("unable to find preproc agc parameters winding up\n");
+		return -EINVAL;
+	}
+	memset(acdb_data.preproc_agc, 0, sizeof(*acdb_data.preproc_agc));
+	acdb_data.preproc_agc->cmd_id = AUDPREPROC_CMD_CFG_AGC_PARAMS;
+	/* 0xFE00 to configure all parameters */
+	acdb_data.preproc_agc->tx_agc_param_mask = 0xFFFF;
+	if (acdb_agc->enable_status)
+		acdb_data.preproc_agc->tx_agc_enable_flag =
+			AUDPREPROC_CMD_TX_AGC_ENA_FLAG_ENA;
+	else
+		acdb_data.preproc_agc->tx_agc_enable_flag =
+			AUDPREPROC_CMD_TX_AGC_ENA_FLAG_DIS;
+
+	acdb_data.preproc_agc->comp_rlink_static_gain =
+		acdb_agc->comp_rlink_static_gain;
+	acdb_data.preproc_agc->comp_rlink_aig_flag =
+		acdb_agc->comp_rlink_aig_flag;
+	acdb_data.preproc_agc->expander_rlink_th =
+		acdb_agc->exp_rlink_threshold;
+	acdb_data.preproc_agc->expander_rlink_slope =
+		acdb_agc->exp_rlink_slope;
+	acdb_data.preproc_agc->compressor_rlink_th =
+		acdb_agc->comp_rlink_threshold;
+	acdb_data.preproc_agc->compressor_rlink_slope =
+		acdb_agc->comp_rlink_slope;
+
+	/* 0xFFF0 to configure all parameters */
+	acdb_data.preproc_agc->tx_adc_agc_param_mask = 0xFFFF;
+
+	acdb_data.preproc_agc->comp_rlink_aig_attackk =
+		acdb_agc->comp_rlink_aig_attack_k;
+	acdb_data.preproc_agc->comp_rlink_aig_leak_down =
+		acdb_agc->comp_rlink_aig_leak_down;
+	acdb_data.preproc_agc->comp_rlink_aig_leak_up =
+		acdb_agc->comp_rlink_aig_leak_up;
+	acdb_data.preproc_agc->comp_rlink_aig_max =
+		acdb_agc->comp_rlink_aig_max;
+	acdb_data.preproc_agc->comp_rlink_aig_min =
+		acdb_agc->comp_rlink_aig_min;
+	acdb_data.preproc_agc->comp_rlink_aig_releasek =
+		acdb_agc->comp_rlink_aig_release_k;
+	acdb_data.preproc_agc->comp_rlink_aig_leakrate_fast =
+		acdb_agc->comp_rlink_aig_sm_leak_rate_fast;
+	acdb_data.preproc_agc->comp_rlink_aig_leakrate_slow =
+		acdb_agc->comp_rlink_aig_sm_leak_rate_slow;
+	acdb_data.preproc_agc->comp_rlink_attackk_msw =
+		acdb_agc->comp_rlink_attack_k_msw;
+	acdb_data.preproc_agc->comp_rlink_attackk_lsw =
+		acdb_agc->comp_rlink_attack_k_lsw;
+	acdb_data.preproc_agc->comp_rlink_delay =
+		acdb_agc->comp_rlink_delay;
+	acdb_data.preproc_agc->comp_rlink_releasek_msw =
+		acdb_agc->comp_rlink_release_k_msw;
+	acdb_data.preproc_agc->comp_rlink_releasek_lsw =
+		acdb_agc->comp_rlink_release_k_lsw;
+	acdb_data.preproc_agc->comp_rlink_rms_tav =
+		acdb_agc->comp_rlink_rms_trav;
+	return 0;
+}
+
+static struct acdb_iir_block *get_audpreproc_irr_block(void)
+{
+
+	struct header *prs_hdr;
+	u32 index = 0;
+
+	while (index < acdb_data.acdb_result.used_bytes) {
+		prs_hdr = (struct header *)(acdb_data.virt_addr + index);
+
+		if (prs_hdr->dbor_signature == DBOR_SIGNATURE) {
+			if (prs_hdr->abid == ABID_AUDIO_IIR_TX) {
+				if (prs_hdr->iid == IID_AUDIO_IIR_COEFF)
+					return (struct acdb_iir_block *)
+						(acdb_data.virt_addr + index
+						 + sizeof(struct header));
+			} else {
+				index += prs_hdr->data_len +
+						sizeof(struct header);
+			}
+		} else {
+			break;
+		}
+	}
+	return NULL;
+}
+
+
+static s32 acdb_fill_audpreproc_iir(void)
+{
+	struct acdb_iir_block	*acdb_iir;
+
+
+	acdb_iir =  get_audpreproc_irr_block();
+	if (!acdb_iir) {
+		MM_DBG("unable to find preproc iir parameters winding up\n");
+		return -EINVAL;
+	}
+	memset(acdb_data.preproc_iir, 0, sizeof(*acdb_data.preproc_iir));
+
+	acdb_data.preproc_iir->cmd_id =
+		AUDPREPROC_CMD_CFG_IIR_TUNING_FILTER_PARAMS;
+	acdb_data.preproc_iir->active_flag = acdb_iir->enable_flag;
+	acdb_data.preproc_iir->num_bands = acdb_iir->stage_count;
+
+	acdb_data.preproc_iir->numerator_coeff_b0_filter0_lsw =
+		acdb_iir->stages[0].b0_lo;
+	acdb_data.preproc_iir->numerator_coeff_b0_filter0_msw =
+		acdb_iir->stages[0].b0_hi;
+	acdb_data.preproc_iir->numerator_coeff_b1_filter0_lsw =
+		acdb_iir->stages[0].b1_lo;
+	acdb_data.preproc_iir->numerator_coeff_b1_filter0_msw =
+		acdb_iir->stages[0].b1_hi;
+	acdb_data.preproc_iir->numerator_coeff_b2_filter0_lsw =
+		acdb_iir->stages[0].b2_lo;
+	acdb_data.preproc_iir->numerator_coeff_b2_filter0_msw =
+		acdb_iir->stages[0].b2_hi;
+
+	acdb_data.preproc_iir->numerator_coeff_b0_filter1_lsw =
+		acdb_iir->stages[1].b0_lo;
+	acdb_data.preproc_iir->numerator_coeff_b0_filter1_msw =
+		acdb_iir->stages[1].b0_hi;
+	acdb_data.preproc_iir->numerator_coeff_b1_filter1_lsw =
+		acdb_iir->stages[1].b1_lo;
+	acdb_data.preproc_iir->numerator_coeff_b1_filter1_msw =
+		acdb_iir->stages[1].b1_hi;
+	acdb_data.preproc_iir->numerator_coeff_b2_filter1_lsw =
+		acdb_iir->stages[1].b2_lo;
+	acdb_data.preproc_iir->numerator_coeff_b2_filter1_msw =
+		acdb_iir->stages[1].b2_hi;
+
+	acdb_data.preproc_iir->numerator_coeff_b0_filter2_lsw =
+		acdb_iir->stages[2].b0_lo;
+	acdb_data.preproc_iir->numerator_coeff_b0_filter2_msw =
+		acdb_iir->stages[2].b0_hi;
+	acdb_data.preproc_iir->numerator_coeff_b1_filter2_lsw =
+		acdb_iir->stages[2].b1_lo;
+	acdb_data.preproc_iir->numerator_coeff_b1_filter2_msw =
+		acdb_iir->stages[2].b1_hi;
+	acdb_data.preproc_iir->numerator_coeff_b2_filter2_lsw =
+		acdb_iir->stages[2].b2_lo;
+	acdb_data.preproc_iir->numerator_coeff_b2_filter2_msw =
+		acdb_iir->stages[2].b2_hi;
+
+	acdb_data.preproc_iir->numerator_coeff_b0_filter3_lsw =
+		acdb_iir->stages[3].b0_lo;
+	acdb_data.preproc_iir->numerator_coeff_b0_filter3_msw =
+		acdb_iir->stages[3].b0_hi;
+	acdb_data.preproc_iir->numerator_coeff_b1_filter3_lsw =
+		acdb_iir->stages[3].b1_lo;
+	acdb_data.preproc_iir->numerator_coeff_b1_filter3_msw =
+		acdb_iir->stages[3].b1_hi;
+	acdb_data.preproc_iir->numerator_coeff_b2_filter3_lsw =
+		acdb_iir->stages[3].b2_lo;
+	acdb_data.preproc_iir->numerator_coeff_b2_filter3_msw =
+		acdb_iir->stages[3].b2_hi;
+
+	acdb_data.preproc_iir->denominator_coeff_a0_filter0_lsw =
+		acdb_iir->stages_a[0].a1_lo;
+	acdb_data.preproc_iir->denominator_coeff_a0_filter0_msw =
+		acdb_iir->stages_a[0].a1_hi;
+	acdb_data.preproc_iir->denominator_coeff_a1_filter0_lsw =
+		acdb_iir->stages_a[0].a2_lo;
+	acdb_data.preproc_iir->denominator_coeff_a1_filter0_msw =
+		acdb_iir->stages_a[0].a2_hi;
+
+	acdb_data.preproc_iir->denominator_coeff_a0_filter1_lsw =
+		acdb_iir->stages_a[1].a1_lo;
+	acdb_data.preproc_iir->denominator_coeff_a0_filter1_msw =
+		acdb_iir->stages_a[1].a1_hi;
+	acdb_data.preproc_iir->denominator_coeff_a1_filter1_lsw =
+		acdb_iir->stages_a[1].a2_lo;
+	acdb_data.preproc_iir->denominator_coeff_a1_filter1_msw =
+		acdb_iir->stages_a[1].a2_hi;
+
+	acdb_data.preproc_iir->denominator_coeff_a0_filter2_lsw =
+		acdb_iir->stages_a[2].a1_lo;
+	acdb_data.preproc_iir->denominator_coeff_a0_filter2_msw =
+		acdb_iir->stages_a[2].a1_hi;
+	acdb_data.preproc_iir->denominator_coeff_a1_filter2_lsw =
+		acdb_iir->stages_a[2].a2_lo;
+	acdb_data.preproc_iir->denominator_coeff_a1_filter2_msw =
+		acdb_iir->stages_a[2].a2_hi;
+
+	acdb_data.preproc_iir->denominator_coeff_a0_filter3_lsw =
+		acdb_iir->stages_a[3].a1_lo;
+	acdb_data.preproc_iir->denominator_coeff_a0_filter3_msw =
+		acdb_iir->stages_a[3].a1_hi;
+	acdb_data.preproc_iir->denominator_coeff_a1_filter3_lsw =
+		acdb_iir->stages_a[3].a2_lo;
+	acdb_data.preproc_iir->denominator_coeff_a1_filter3_msw =
+		acdb_iir->stages_a[3].a2_hi;
+
+	acdb_data.preproc_iir->shift_factor_filter0 =
+		acdb_iir->shift_factor[0];
+	acdb_data.preproc_iir->shift_factor_filter1 =
+		acdb_iir->shift_factor[1];
+	acdb_data.preproc_iir->shift_factor_filter2 =
+		acdb_iir->shift_factor[2];
+	acdb_data.preproc_iir->shift_factor_filter3 =
+		acdb_iir->shift_factor[3];
+
+	acdb_data.preproc_iir->channel_selected0 =
+		acdb_iir->pan[0];
+	acdb_data.preproc_iir->channel_selected1 =
+		acdb_iir->pan[1];
+	acdb_data.preproc_iir->channel_selected2 =
+		acdb_iir->pan[2];
+	acdb_data.preproc_iir->channel_selected3 =
+		acdb_iir->pan[3];
+	return 0;
+}
+
+static struct acdb_ns_tx_block *get_audpreproc_ns_block(void)
+{
+
+	struct header *prs_hdr;
+	u32 index = 0;
+
+	while (index < acdb_data.acdb_result.used_bytes) {
+		prs_hdr = (struct header *)(acdb_data.virt_addr + index);
+
+		if (prs_hdr->dbor_signature == DBOR_SIGNATURE) {
+			if (prs_hdr->abid == ABID_AUDIO_NS_TX) {
+				if (prs_hdr->iid == IID_NS_PARAMETERS)
+					return (struct acdb_ns_tx_block *)
+						(acdb_data.virt_addr + index
+						 + sizeof(struct header));
+			} else {
+				index += prs_hdr->data_len +
+						sizeof(struct header);
+			}
+		} else {
+			break;
+		}
+	}
+	return NULL;
+}
+
+static s32 acdb_fill_audpreproc_ns(void)
+{
+	struct acdb_ns_tx_block	*acdb_ns;
+	/* TO DO: do we enable_status_filled */
+	acdb_ns = get_audpreproc_ns_block();
+	if (!acdb_ns) {
+		MM_DBG("unable to find preproc ns parameters winding up\n");
+		return -EINVAL;
+	}
+	memset(acdb_data.preproc_ns, 0, sizeof(*acdb_data.preproc_ns));
+	acdb_data.preproc_ns->cmd_id = AUDPREPROC_CMD_CFG_NS_PARAMS;
+
+	acdb_data.preproc_ns->ec_mode_new  = acdb_ns->ec_mode_new;
+	acdb_data.preproc_ns->dens_gamma_n = acdb_ns->dens_gamma_n;
+	acdb_data.preproc_ns->dens_nfe_block_size  =
+					acdb_ns->dens_nfe_block_size;
+	acdb_data.preproc_ns->dens_limit_ns = acdb_ns->dens_limit_ns;
+	acdb_data.preproc_ns->dens_limit_ns_d  = acdb_ns->dens_limit_ns_d;
+	acdb_data.preproc_ns->wb_gamma_e  = acdb_ns->wb_gamma_e;
+	acdb_data.preproc_ns->wb_gamma_n  = acdb_ns->wb_gamma_n;
+
+	return 0;
+}
+
+s32 acdb_calibrate_audpreproc(void)
+{
+	s32	result = 0;
+
+	result = acdb_fill_audpreproc_agc();
+	if (!IS_ERR_VALUE(result)) {
+		result = audpreproc_dsp_set_agc(acdb_data.preproc_agc, sizeof(
+					audpreproc_cmd_cfg_agc_params));
+		if (result) {
+			MM_ERR("ACDB=> Failed to send AGC data to preproc)\n");
+			result = -EINVAL;
+			goto done;
+		} else
+			MM_DBG("AUDPREC is calibrated with AGC parameters");
+	}
+	result = acdb_fill_audpreproc_iir();
+	if (!IS_ERR_VALUE(result)) {
+		result = audpreproc_dsp_set_iir(acdb_data.preproc_iir,
+				sizeof(\
+				audpreproc_cmd_cfg_iir_tuning_filter_params));
+		if (result) {
+			MM_ERR("ACDB=> Failed to send IIR data to preproc\n");
+			result = -EINVAL;
+			goto done;
+		} else
+			MM_DBG("audpreproc is calibrated with iir parameters");
+	}
+
+	result = acdb_fill_audpreproc_ns();
+	if (!IS_ERR_VALUE(result)) {
+		result = audpreproc_dsp_set_ns(acdb_data.preproc_ns,
+						sizeof(\
+						audpreproc_cmd_cfg_ns_params));
+		if (result) {
+			MM_ERR("ACDB=> Failed to send NS data to preproc\n");
+			result = -EINVAL;
+			goto done;
+		} else
+			MM_DBG("audpreproc is calibrated with NS parameters");
+	}
+done:
+	return result;
+}
+
+static s32 acdb_send_calibration(void)
+{
+	s32 result = 0;
+
+	if (acdb_data.device_info->dev_type.rx_device) {
+		result = acdb_calibrate_audpp();
+		if (result)
+			goto done;
+	} else if (acdb_data.device_info->dev_type.tx_device) {
+		result = acdb_calibrate_audpreproc();
+		if (result)
+			goto done;
+		acdb_data.audrec_applied |= AUDREC_READY;
+		MM_DBG("acdb_data.audrec_applied = %x\n",
+					acdb_data.audrec_applied);
+	}
+done:
+	return result;
+}
+
+static u8 check_tx_acdb_values_cached(void)
+{
+	if ((acdb_data.device_info->sample_rate ==
+		acdb_cache_tx.device_info.sample_rate) &&
+		(acdb_data.device_info->acdb_id ==
+		acdb_cache_tx.device_info.acdb_id) &&
+		(acdb_cache_tx.node_status ==
+						ACDB_VALUES_FILLED))
+		return 0;
+	else
+		return 1;
+}
+
+static void handle_tx_device_ready_callback(void)
+{
+	u8 acdb_value_apply = 0;
+	u8 result = 0;
+
+	/*check wheather AUDREC enabled before device call backs*/
+	if ((acdb_data.acdb_state & AUDREC_READY) &&
+			!(acdb_data.audrec_applied & AUDREC_READY)) {
+		MM_DBG("AUDREC already enabled apply acdb values\n");
+		acdb_value_apply |= AUDREC_READY;
+	}
+	if (acdb_value_apply) {
+		if (session_info.sampling_freq)
+			acdb_data.device_info->sample_rate =
+					session_info.sampling_freq;
+		result = check_tx_acdb_values_cached();
+		if (result) {
+			result = acdb_get_calibration();
+			if (result < 0) {
+				MM_ERR("Not able to get calibration"\
+						" data continue\n");
+				return;
+			}
+		}
+		acdb_cache_tx.node_status = ACDB_VALUES_FILLED;
+		acdb_send_calibration();
+	}
+}
+
+static struct acdb_cache_node *get_acdb_values_from_cache_tx(u32 stream_id)
+{
+	MM_DBG("searching node with stream_id");
+	if ((acdb_cache_tx.stream_id == stream_id) &&
+			(acdb_cache_tx.node_status ==
+					ACDB_VALUES_NOT_FILLED)) {
+			return &acdb_cache_tx;
+	}
+	MM_DBG("Error! in finding node\n");
+	return NULL;
+}
+
+static void update_acdb_data_struct(struct acdb_cache_node *cur_node)
+{
+	if (cur_node) {
+		acdb_data.device_info = &cur_node->device_info;
+		acdb_data.virt_addr = cur_node->virt_addr_acdb_values;
+		acdb_data.phys_addr = cur_node->phys_addr_acdb_values;
+	} else
+		MM_ERR("error in curent node\n");
+}
+
+static void send_acdb_values_for_active_devices(void)
+{
+	if (acdb_cache_rx.node_status ==
+			ACDB_VALUES_FILLED) {
+		update_acdb_data_struct(&acdb_cache_rx);
+		if (acdb_data.acdb_state & CAL_DATA_READY)
+			acdb_send_calibration();
+	}
+}
+
+static s32 initialize_rpc(void)
+{
+	s32 result = 0;
+
+	result = daldevice_attach(DALDEVICEID_ACDB, ACDB_PORT_NAME,
+			ACDB_CPU, &acdb_data.handle);
+
+	if (result) {
+		MM_ERR("ACDB=> Device Attach failed\n");
+		result = -ENODEV;
+		goto done;
+	}
+done:
+	return result;
+}
+
+static u32 allocate_memory_acdb_cache_tx(void)
+{
+	u32 result = 0;
+	/*initialize local cache */
+	acdb_cache_tx.phys_addr_acdb_values =
+		allocate_contiguous_ebi_nomap(ACDB_BUF_SIZE,
+				SZ_4K);
+
+	if (!acdb_cache_tx.phys_addr_acdb_values) {
+		MM_ERR("ACDB=> Cannot allocate physical memory\n");
+		result = -ENOMEM;
+		goto error;
+	}
+	acdb_cache_tx.map_v_addr = ioremap(
+			acdb_cache_tx.phys_addr_acdb_values,
+			ACDB_BUF_SIZE);
+	if (IS_ERR(acdb_cache_tx.map_v_addr)) {
+		MM_ERR("ACDB=> Could not map physical address\n");
+		result = -ENOMEM;
+		free_contiguous_memory_by_paddr(
+				acdb_cache_tx.phys_addr_acdb_values);
+		goto error;
+	}
+	acdb_cache_tx.virt_addr_acdb_values =
+		acdb_cache_tx.map_v_addr;
+	memset(acdb_cache_tx.virt_addr_acdb_values, 0,
+			ACDB_BUF_SIZE);
+	return result;
+error:
+	iounmap(acdb_cache_tx.map_v_addr);
+	free_contiguous_memory_by_paddr(
+			acdb_cache_tx.phys_addr_acdb_values);
+	return result;
+}
+
+static u32 allocate_memory_acdb_cache_rx(void)
+{
+	u32 result = 0;
+
+	/*initialize local cache */
+	acdb_cache_rx.phys_addr_acdb_values =
+		allocate_contiguous_ebi_nomap(
+				ACDB_BUF_SIZE, SZ_4K);
+
+	if (!acdb_cache_rx.phys_addr_acdb_values) {
+		MM_ERR("ACDB=> Can not allocate physical memory\n");
+		result = -ENOMEM;
+		goto error;
+	}
+	acdb_cache_rx.map_v_addr =
+		ioremap(acdb_cache_rx.phys_addr_acdb_values,
+				ACDB_BUF_SIZE);
+	if (IS_ERR(acdb_cache_rx.map_v_addr)) {
+		MM_ERR("ACDB=> Could not map physical address\n");
+		result = -ENOMEM;
+		free_contiguous_memory_by_paddr(
+				acdb_cache_rx.phys_addr_acdb_values);
+		goto error;
+	}
+	acdb_cache_rx.virt_addr_acdb_values =
+		acdb_cache_rx.map_v_addr;
+	memset(acdb_cache_rx.virt_addr_acdb_values, 0,
+			ACDB_BUF_SIZE);
+	return result;
+error:
+	iounmap(acdb_cache_rx.map_v_addr);
+	free_contiguous_memory_by_paddr(
+			acdb_cache_rx.phys_addr_acdb_values);
+	return result;
+}
+
+static u32 allocate_memory_acdb_get_blk(void)
+{
+	u32 result = 0;
+	acdb_data.get_blk_paddr = allocate_contiguous_ebi_nomap(
+						ACDB_BUF_SIZE, SZ_4K);
+	if (!acdb_data.get_blk_paddr) {
+		MM_ERR("ACDB=> Cannot allocate physical memory\n");
+		result = -ENOMEM;
+		goto error;
+	}
+	acdb_data.map_v_get_blk = ioremap(acdb_data.get_blk_paddr,
+					ACDB_BUF_SIZE);
+	if (IS_ERR(acdb_data.map_v_get_blk)) {
+		MM_ERR("ACDB=> Could not map physical address\n");
+		result = -ENOMEM;
+		free_contiguous_memory_by_paddr(
+					acdb_data.get_blk_paddr);
+		goto error;
+	}
+	acdb_data.get_blk_kvaddr = acdb_data.map_v_get_blk;
+	memset(acdb_data.get_blk_kvaddr, 0, ACDB_BUF_SIZE);
+error:
+	return result;
+}
+
+static void free_memory_acdb_cache_rx(void)
+{
+	iounmap(acdb_cache_rx.map_v_addr);
+	free_contiguous_memory_by_paddr(
+			acdb_cache_rx.phys_addr_acdb_values);
+}
+
+static void free_memory_acdb_cache_tx(void)
+{
+
+	iounmap(acdb_cache_tx.map_v_addr);
+	free_contiguous_memory_by_paddr(
+			acdb_cache_tx.phys_addr_acdb_values);
+}
+
+static void free_memory_acdb_get_blk(void)
+{
+	iounmap(acdb_data.map_v_get_blk);
+	free_contiguous_memory_by_paddr(acdb_data.get_blk_paddr);
+}
+
+static s32 initialize_memory(void)
+{
+	s32 result = 0;
+
+	result = allocate_memory_acdb_get_blk();
+	if (result < 0) {
+		MM_ERR("memory allocation for get blk failed\n");
+		goto done;
+	}
+
+	result = allocate_memory_acdb_cache_rx();
+	if (result < 0) {
+		MM_ERR("memory allocation for rx cache is failed\n");
+		free_memory_acdb_get_blk();
+		goto done;
+	}
+	result = allocate_memory_acdb_cache_tx();
+	if (result < 0) {
+		MM_ERR("memory allocation for tx cache is failed\n");
+		free_memory_acdb_get_blk();
+		free_memory_acdb_cache_rx();
+		goto done;
+	}
+	acdb_data.pp_iir = kmalloc(sizeof(*acdb_data.pp_iir),
+		GFP_KERNEL);
+	if (acdb_data.pp_iir == NULL) {
+		MM_ERR("ACDB=> Could not allocate postproc iir memory\n");
+		free_memory_acdb_get_blk();
+		free_memory_acdb_cache_rx();
+		free_memory_acdb_cache_tx();
+		result = -ENOMEM;
+		goto done;
+	}
+
+	acdb_data.pp_mbadrc = kmalloc(sizeof(*acdb_data.pp_mbadrc), GFP_KERNEL);
+	if (acdb_data.pp_mbadrc == NULL) {
+		MM_ERR("ACDB=> Could not allocate postproc mbadrc memory\n");
+		free_memory_acdb_get_blk();
+		free_memory_acdb_cache_rx();
+		free_memory_acdb_cache_tx();
+		kfree(acdb_data.pp_iir);
+		result = -ENOMEM;
+		goto done;
+	}
+
+	acdb_data.preproc_agc = kmalloc(sizeof(*acdb_data.preproc_agc),
+							GFP_KERNEL);
+	if (acdb_data.preproc_agc == NULL) {
+		MM_ERR("ACDB=> Could not allocate preproc agc memory\n");
+		free_memory_acdb_get_blk();
+		free_memory_acdb_cache_rx();
+		free_memory_acdb_cache_tx();
+		kfree(acdb_data.pp_iir);
+		kfree(acdb_data.pp_mbadrc);
+		result = -ENOMEM;
+		goto done;
+	}
+
+	acdb_data.preproc_iir = kmalloc(sizeof(*acdb_data.preproc_iir),
+							GFP_KERNEL);
+	if (acdb_data.preproc_iir == NULL) {
+		MM_ERR("ACDB=> Could not allocate preproc iir memory\n");
+		free_memory_acdb_get_blk();
+		free_memory_acdb_cache_rx();
+		free_memory_acdb_cache_tx();
+		kfree(acdb_data.pp_iir);
+		kfree(acdb_data.pp_mbadrc);
+		kfree(acdb_data.preproc_agc);
+		result = -ENOMEM;
+		goto done;
+	}
+
+	acdb_data.preproc_ns = kmalloc(sizeof(*acdb_data.preproc_ns),
+							GFP_KERNEL);
+	if (acdb_data.preproc_ns == NULL) {
+		MM_ERR("ACDB=> Could not allocate preproc ns memory\n");
+		free_memory_acdb_get_blk();
+		free_memory_acdb_cache_rx();
+		free_memory_acdb_cache_tx();
+		kfree(acdb_data.pp_iir);
+		kfree(acdb_data.pp_mbadrc);
+		kfree(acdb_data.preproc_agc);
+		kfree(acdb_data.preproc_iir);
+		result = -ENOMEM;
+		goto done;
+	}
+done:
+	return result;
+}
+
+static u8 check_device_change(struct dev_evt_msg device_info)
+{
+	if (!acdb_data.device_info) {
+		MM_ERR("not pointing to previous valid device detail\n");
+		return 1; /*device info will not be pointing to*/
+			/* valid device when acdb driver comes up*/
+	}
+	if ((device_info.sample_rate ==
+				acdb_data.device_info->sample_rate) &&
+		(device_info.acdb_id == acdb_data.device_info->acdb_id)) {
+		return 0;
+	}
+	return 1;
+}
+
+static void device_cb(struct dev_evt_msg *evt, void *private)
+{
+	struct cad_device_info_type dev_type;
+	struct acdb_cache_node *acdb_cache_free_node =  NULL;
+	u32 session_id = 0;
+	u8 ret = 0;
+	u8 device_change = 0;
+
+	/*if session value is zero it indicates that device call back is for
+	voice call we will drop the request as acdb values for voice call is
+	not applied from acdb driver*/
+	if (!evt->session_info) {
+		MM_DBG("no active sessions and call back is for"\
+				" voice call\n");
+		goto done;
+	}
+
+	if ((evt->dev_type.rx_device) &&
+			(evt->acdb_id == PSEUDO_ACDB_ID)) {
+		MM_INFO("device cb is for rx device with pseudo acdb id\n");
+		goto done;
+	}
+	dev_type = evt->dev_type;
+	MM_DBG("sample_rate = %d\n", evt->sample_rate);
+	MM_DBG("acdb_id = %d\n", evt->acdb_id);
+	MM_DBG("sessions = %d\n", evt->session_info);
+	MM_DBG("acdb_state = %x\n", acdb_data.acdb_state);
+	mutex_lock(&acdb_data.acdb_mutex);
+	device_change = check_device_change(*evt);
+	if (!device_change) {
+		if (dev_type.tx_device) {
+			if (!(acdb_data.acdb_state & AUDREC_READY))
+				acdb_data.audrec_applied &= ~AUDREC_READY;
+
+			acdb_data.acdb_state &= ~CAL_DATA_READY;
+			goto update_cache;
+		}
+	} else
+		/* state is updated to query the modem for values */
+		acdb_data.acdb_state &= ~CAL_DATA_READY;
+
+update_cache:
+	if (dev_type.tx_device) {
+		/*Only one recording session possible*/
+		session_id = 0;
+		acdb_cache_free_node =	&acdb_cache_tx;
+		ret  = check_device_info_already_present(
+				*evt,
+				acdb_cache_free_node);
+		acdb_cache_free_node->stream_id = session_id;
+		acdb_data.cur_tx_session = session_id;
+	} else {
+		acdb_cache_free_node = &acdb_cache_rx;
+		ret = check_device_info_already_present(*evt,
+						acdb_cache_free_node);
+		if (ret == 1) {
+			MM_DBG("got device ready call back for another "\
+					"audplay task sessions on same COPP\n");
+			/*stream_id is used to keep track of number of active*/
+			/*sessions active on this device*/
+			acdb_cache_free_node->stream_id++;
+			mutex_unlock(&acdb_data.acdb_mutex);
+			goto done;
+		}
+		acdb_cache_free_node->stream_id++;
+	}
+	update_acdb_data_struct(acdb_cache_free_node);
+	acdb_data.device_cb_compl = 1;
+	mutex_unlock(&acdb_data.acdb_mutex);
+	wake_up(&acdb_data.wait);
+done:
+	return;
+}
+
+static s32 register_device_cb(void)
+{
+	s32 result = 0;
+	acdb_data.dev_cb.func = device_cb;
+	acdb_data.dev_cb.private = (void *)&acdb_data;
+
+	result = audmgr_register_device_info_callback(&acdb_data.dev_cb);
+
+	if (result) {
+		MM_ERR("ACDB=> Could not register device callback\n");
+		result = -ENODEV;
+		goto done;
+	}
+done:
+	return result;
+}
+
+static void audpp_cb(void *private, u32 id, u16 *msg)
+{
+	MM_DBG("\n");
+	if (id != AUDPP_MSG_CFG_MSG)
+		goto done;
+
+	if (msg[0] == AUDPP_MSG_ENA_DIS) {
+		if (--acdb_cache_rx.stream_id <= 0) {
+			acdb_data.acdb_state &= ~AUDPP_READY;
+			acdb_cache_rx.stream_id = 0;
+			MM_DBG("AUDPP_MSG_ENA_DIS\n");
+		}
+		goto done;
+	}
+
+	acdb_data.acdb_state |= AUDPP_READY;
+	acdb_data.audpp_cb_compl = 1;
+	wake_up(&acdb_data.wait);
+done:
+	return;
+}
+
+static s8 handle_audpreproc_cb(void)
+{
+	struct acdb_cache_node *acdb_cached_values;
+	s8 result = 0;
+	u8 stream_id = acdb_data.preproc_stream_id;
+	acdb_data.preproc_cb_compl = 0;
+	acdb_cached_values = get_acdb_values_from_cache_tx(stream_id);
+	if (acdb_cached_values == NULL) {
+		MM_DBG("ERROR: to get chached acdb values\n");
+		return -EPERM;
+	}
+	update_acdb_data_struct(acdb_cached_values);
+
+	if (session_info.sampling_freq)
+		acdb_data.device_info->sample_rate =
+			session_info.sampling_freq;
+
+	if (!(acdb_data.acdb_state & CAL_DATA_READY)) {
+		result = check_tx_acdb_values_cached();
+		if (result) {
+			result = acdb_get_calibration();
+			if (result < 0) {
+				MM_ERR("failed to get calibration data\n");
+				return result;
+			}
+		}
+		acdb_cached_values->node_status = ACDB_VALUES_FILLED;
+	}
+	return result;
+}
+
+static void audpreproc_cb(void *private, u32 id, void *event_data)
+{
+	u8 result = 0;
+	uint16_t *msg = event_data;
+	int stream_id = 0; /* Only single tunnel mode recording supported */
+	if (id != AUDPREPROC_MSG_CMD_CFG_DONE_MSG)
+		goto done;
+
+	acdb_data.preproc_stream_id = stream_id;
+	get_audrec_session_info(&session_info);
+	MM_DBG("status_flag = %x\n", msg[0]);
+	if (msg[0]  == AUDPREPROC_MSG_STATUS_FLAG_DIS) {
+		acdb_data.acdb_state &= ~AUDREC_READY;
+		acdb_cache_tx.node_status =\
+						ACDB_VALUES_NOT_FILLED;
+		acdb_data.acdb_state &= ~CAL_DATA_READY;
+		goto done;
+	}
+	/*Following check is added to make sure that device info
+	  is updated. audpre proc layer enabled without device
+	  callback at this scenario we should not access
+	  device information
+	 */
+	if (acdb_data.device_info &&
+			session_info.sampling_freq) {
+		acdb_data.device_info->sample_rate =
+			session_info.sampling_freq;
+		result = check_tx_acdb_values_cached();
+		if (!result) {
+			MM_INFO("acdb values for the stream is" \
+					" querried from modem");
+			acdb_data.acdb_state |= CAL_DATA_READY;
+		} else {
+			acdb_data.acdb_state &= ~CAL_DATA_READY;
+		}
+	}
+	acdb_data.acdb_state |= AUDREC_READY;
+
+	acdb_data.preproc_cb_compl = 1;
+	MM_DBG("acdb_data.acdb_state = %x\n", acdb_data.acdb_state);
+	wake_up(&acdb_data.wait);
+done:
+	return;
+}
+
+static s32 register_audpp_cb(void)
+{
+	s32 result = 0;
+
+	acdb_data.audpp_cb.fn = audpp_cb;
+	acdb_data.audpp_cb.private = NULL;
+	result = audpp_register_event_callback(&acdb_data.audpp_cb);
+	if (result) {
+		MM_ERR("ACDB=> Could not register audpp callback\n");
+		result = -ENODEV;
+		goto done;
+	}
+done:
+	return result;
+}
+
+static s32 register_audpreproc_cb(void)
+{
+	s32 result = 0;
+
+	acdb_data.audpreproc_cb.fn = audpreproc_cb;
+	acdb_data.audpreproc_cb.private = NULL;
+	result = audpreproc_register_event_callback(&acdb_data.audpreproc_cb);
+	if (result) {
+		MM_ERR("ACDB=> Could not register audpreproc callback\n");
+		result = -ENODEV;
+		goto done;
+	}
+
+done:
+	return result;
+}
+
+static s32 acdb_initialize_data(void)
+{
+	s32	result = 0;
+
+	mutex_init(&acdb_data.acdb_mutex);
+
+	result = initialize_rpc();
+	if (result)
+		goto err;
+
+	result = initialize_memory();
+	if (result)
+		goto err1;
+
+	result = register_device_cb();
+	if (result)
+		goto err2;
+
+	result = register_audpp_cb();
+	if (result)
+		goto err3;
+
+	result = register_audpreproc_cb();
+	if (result)
+		goto err4;
+
+
+	return result;
+
+err4:
+	result = audpreproc_unregister_event_callback(&acdb_data.audpreproc_cb);
+	if (result)
+		MM_ERR("ACDB=> Could not unregister audpreproc callback\n");
+err3:
+	result = audpp_unregister_event_callback(&acdb_data.audpp_cb);
+	if (result)
+		MM_ERR("ACDB=> Could not unregister audpp callback\n");
+err2:
+	result = audmgr_deregister_device_info_callback(&acdb_data.dev_cb);
+	if (result)
+		MM_ERR("ACDB=> Could not unregister device callback\n");
+err1:
+	daldevice_detach(acdb_data.handle);
+	acdb_data.handle = NULL;
+err:
+	return result;
+}
+
+static s32 acdb_calibrate_device(void *data)
+{
+	s32 result = 0;
+
+	/* initialize driver */
+	result = acdb_initialize_data();
+	if (result)
+		goto done;
+
+	while (!kthread_should_stop()) {
+		MM_DBG("Waiting for call back events\n");
+		wait_event_interruptible(acdb_data.wait,
+					(acdb_data.device_cb_compl
+					| acdb_data.audpp_cb_compl
+					| acdb_data.preproc_cb_compl));
+		mutex_lock(&acdb_data.acdb_mutex);
+		if (acdb_data.device_cb_compl) {
+			acdb_data.device_cb_compl = 0;
+			if (!(acdb_data.acdb_state & CAL_DATA_READY)) {
+				if (acdb_data.device_info->dev_type.rx_device) {
+					/*we need to get calibration values
+					only for RX device as resampler
+					moved to start of the pre - proc chain
+					tx calibration value will be based on
+					sampling frequency what audrec is
+					configured, calibration values for tx
+					device are fetch in audpreproc
+					callback*/
+					result = acdb_get_calibration();
+					if (result < 0) {
+						mutex_unlock(
+							&acdb_data.acdb_mutex);
+						MM_ERR("Not able to get "\
+							"calibration "\
+							"data continue\n");
+						continue;
+					}
+				}
+			}
+			MM_DBG("acdb state = %d\n",
+					 acdb_data.acdb_state);
+			if (acdb_data.device_info->dev_type.tx_device)
+				handle_tx_device_ready_callback();
+			else {
+				acdb_cache_rx.node_status =\
+						ACDB_VALUES_FILLED;
+				if (acdb_data.acdb_state &
+						AUDPP_READY) {
+					MM_DBG("AUDPP already enabled "\
+							"apply acdb values\n");
+					goto apply;
+				}
+			}
+		}
+
+		if (!(acdb_data.audpp_cb_compl ||
+				acdb_data.preproc_cb_compl)) {
+			MM_DBG("need to wait for either AUDPP / AUDPREPROC "\
+					"Event\n");
+			mutex_unlock(&acdb_data.acdb_mutex);
+			continue;
+		} else {
+			MM_DBG("got audpp / preproc call back\n");
+			if (acdb_data.audpp_cb_compl) {
+				send_acdb_values_for_active_devices();
+				acdb_data.audpp_cb_compl = 0;
+				mutex_unlock(&acdb_data.acdb_mutex);
+				continue;
+			} else {
+				result = handle_audpreproc_cb();
+				if (result < 0) {
+					mutex_unlock(&acdb_data.acdb_mutex);
+					continue;
+				}
+			}
+		}
+apply:
+		if (acdb_data.acdb_state & CAL_DATA_READY)
+			result = acdb_send_calibration();
+
+		mutex_unlock(&acdb_data.acdb_mutex);
+	}
+done:
+	return 0;
+}
+
+static int __init acdb_init(void)
+{
+
+	s32 result = 0;
+
+	memset(&acdb_data, 0, sizeof(acdb_data));
+	spin_lock_init(&acdb_data.dsp_lock);
+	acdb_data.cb_thread_task = kthread_run(acdb_calibrate_device,
+		NULL, "acdb_cb_thread");
+
+	if (IS_ERR(acdb_data.cb_thread_task)) {
+		MM_ERR("ACDB=> Could not register cb thread\n");
+		result = -ENODEV;
+		goto err;
+	}
+
+#ifdef CONFIG_DEBUG_FS
+	/*This is RTC specific INIT used only with debugfs*/
+	if (!rtc_acdb_init())
+		MM_ERR("RTC ACDB=>INIT Failure\n");
+
+#endif
+	init_waitqueue_head(&acdb_data.wait);
+
+	return misc_register(&acdb_misc);
+err:
+	return result;
+}
+
+static void __exit acdb_exit(void)
+{
+	s32	result = 0;
+
+	result = audmgr_deregister_device_info_callback(&acdb_data.dev_cb);
+	if (result)
+		MM_ERR("ACDB=> Could not unregister device callback\n");
+
+	result = audpp_unregister_event_callback(&acdb_data.audpp_cb);
+	if (result)
+		MM_ERR("ACDB=> Could not unregister audpp callback\n");
+
+	result = audpreproc_unregister_event_callback(&acdb_data.\
+				audpreproc_cb);
+	if (result)
+		MM_ERR("ACDB=> Could not unregister audpreproc callback\n");
+
+	result = kthread_stop(acdb_data.cb_thread_task);
+	if (result)
+		MM_ERR("ACDB=> Could not stop kthread\n");
+
+	free_memory_acdb_get_blk();
+
+	iounmap(acdb_cache_tx.map_v_addr);
+	free_contiguous_memory_by_paddr(
+			acdb_cache_tx.phys_addr_acdb_values);
+	iounmap(acdb_cache_rx.map_v_addr);
+	free_contiguous_memory_by_paddr(
+			acdb_cache_rx.phys_addr_acdb_values);
+	kfree(acdb_data.device_info);
+	kfree(acdb_data.pp_iir);
+	kfree(acdb_data.pp_mbadrc);
+	kfree(acdb_data.preproc_agc);
+	kfree(acdb_data.preproc_iir);
+	kfree(acdb_data.preproc_ns);
+	mutex_destroy(&acdb_data.acdb_mutex);
+	memset(&acdb_data, 0, sizeof(acdb_data));
+	#ifdef CONFIG_DEBUG_FS
+	rtc_acdb_deinit();
+	#endif
+}
+
+late_initcall(acdb_init);
+module_exit(acdb_exit);
+
+MODULE_DESCRIPTION("MSM 8x25 Audio ACDB driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp5/audio_amrnb.c b/arch/arm/mach-msm/qdsp5/audio_amrnb.c
index 45fa045..8aa102a 100644
--- a/arch/arm/mach-msm/qdsp5/audio_amrnb.c
+++ b/arch/arm/mach-msm/qdsp5/audio_amrnb.c
@@ -42,7 +42,7 @@
 #include <linux/slab.h>
 #include <linux/msm_audio.h>
 #include <linux/memory_alloc.h>
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
 
 #include <mach/msm_adsp.h>
 #include <mach/iommu.h>
@@ -51,6 +51,7 @@
 #include <mach/qdsp5/qdsp5audppmsg.h>
 #include <mach/qdsp5/qdsp5audplaycmdi.h>
 #include <mach/qdsp5/qdsp5audplaymsg.h>
+#include <mach/qdsp5/qdsp5audpp.h>
 #include <mach/qdsp5/qdsp5rmtcmdi.h>
 #include <mach/debug_mm.h>
 #include <mach/msm_memtypes.h>
diff --git a/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c b/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c
index 39578c1..4effc8e 100644
--- a/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c
@@ -37,7 +37,7 @@
 #include <linux/delay.h>
 #include <linux/msm_audio_amrnb.h>
 #include <linux/memory_alloc.h>
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
 
 #include "audmgr.h"
 
@@ -114,8 +114,6 @@
 	uint32_t out_frame_cnt;
 
 	struct msm_adsp_module *audrec;
-	struct msm_adsp_module *audpre;
-
 
 	/* configuration to use on next enable */
 	uint32_t samp_rate;
@@ -154,6 +152,7 @@
 	struct ion_client *client;
 	struct ion_handle *input_buff_handle;
 
+	struct audrec_session_info session_info; /*audrec session info*/
 };
 
 struct audio_frame {
@@ -232,6 +231,30 @@
 	}
 }
 
+/* ------------------- dsp --------------------- */
+static void audpre_dsp_event(void *data, unsigned id,  void *event_data)
+{
+
+	uint16_t *msg = event_data;
+
+	if (!msg)
+		return;
+
+	switch (id) {
+	case AUDPREPROC_MSG_CMD_CFG_DONE_MSG:
+		MM_DBG("type %d, status_flag %d\n",\
+			msg[0], msg[1]);
+		break;
+	case AUDPREPROC_MSG_ERROR_MSG_ID:
+		MM_INFO("err_index %d\n", msg[0]);
+		break;
+	case ADSP_MESSAGE_ID:
+		MM_DBG("Received ADSP event: module enable(audpreproctask)\n");
+		break;
+	default:
+		MM_ERR("unknown event %d\n", id);
+	}
+}
 /* must be called with audio->lock held */
 static int audamrnb_in_enable(struct audio_amrnb_in *audio)
 {
@@ -252,16 +275,23 @@
 		if (rc < 0)
 			return rc;
 
-		if (msm_adsp_enable(audio->audpre)) {
+		if (audpreproc_enable(audio->enc_id,
+				&audpre_dsp_event, audio)) {
+			MM_ERR("msm_adsp_enable(audpreproc) failed\n");
 			audmgr_disable(&audio->audmgr);
-			MM_ERR("msm_adsp_enable(audpre) failed\n");
 			return -ENODEV;
 		}
+		/*update aurec session info in audpreproc layer*/
+		audio->session_info.session_id = audio->enc_id;
+		audio->session_info.sampling_freq =
+			convert_samp_index(audio->samp_rate);
+		audpreproc_update_audrec_info(&audio->session_info);
 	}
+
 	if (msm_adsp_enable(audio->audrec)) {
 		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
+			audpreproc_disable(audio->enc_id, audio);
 			audmgr_disable(&audio->audmgr);
-			msm_adsp_disable(audio->audpre);
 		}
 		MM_ERR("msm_adsp_enable(audrec) failed\n");
 		return -ENODEV;
@@ -286,35 +316,17 @@
 				audio->running == 0, 1*HZ);
 		msm_adsp_disable(audio->audrec);
 		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
-			msm_adsp_disable(audio->audpre);
+			/*reset the sampling frequency information at
+			audpreproc layer*/
+			audio->session_info.sampling_freq = 0;
+			audpreproc_update_audrec_info(&audio->session_info);
+			audpreproc_disable(audio->enc_id, audio);
 			audmgr_disable(&audio->audmgr);
 		}
 	}
 	return 0;
 }
 
-/* ------------------- dsp --------------------- */
-static void audpre_dsp_event(void *data, unsigned id, size_t len,
-			    void (*getevent)(void *ptr, size_t len))
-{
-	uint16_t msg[2];
-	getevent(msg, sizeof(msg));
-
-	switch (id) {
-	case AUDPREPROC_MSG_CMD_CFG_DONE_MSG:
-		MM_DBG("type %d, status_flag %d\n", msg[0], msg[1]);
-		break;
-	case AUDPREPROC_MSG_ERROR_MSG_ID:
-		MM_ERR("err_index %d\n", msg[0]);
-		break;
-	case ADSP_MESSAGE_ID:
-		MM_DBG("Received ADSP event: module enable(audpreproctask)\n");
-		break;
-	default:
-		MM_ERR("unknown event %d\n", id);
-	}
-}
-
 static void audamrnb_in_get_dsp_frames(struct audio_amrnb_in *audio)
 {
 	struct audio_frame *frame;
@@ -555,10 +567,6 @@
 	}
 }
 
-struct msm_adsp_ops audpre_amrnb_adsp_ops = {
-	.event = audpre_dsp_event,
-};
-
 struct msm_adsp_ops audrec_amrnb_adsp_ops = {
 	.event = audrec_dsp_event,
 };
@@ -1201,12 +1209,8 @@
 	audamrnb_in_flush(audio);
 	msm_adsp_put(audio->audrec);
 
-	if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
-		msm_adsp_put(audio->audpre);
-
 	audpreproc_aenc_free(audio->enc_id);
 	audio->audrec = NULL;
-	audio->audpre = NULL;
 	audio->opened = 0;
 	if ((audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) && \
 	   (audio->out_data)) {
@@ -1304,15 +1308,6 @@
 		goto done;
 	}
 
-	if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
-		rc = msm_adsp_get("AUDPREPROCTASK", &audio->audpre,
-				&audpre_amrnb_adsp_ops, audio);
-		if (rc) {
-			msm_adsp_put(audio->audrec);
-			audpreproc_aenc_free(audio->enc_id);
-			goto done;
-		}
-	}
 	audio->dsp_cnt = 0;
 	audio->stopped = 0;
 	audio->wflush = 0;
@@ -1414,8 +1409,6 @@
 	dma_free_coherent(NULL, dma_size, audio->data, audio->phys);
 evt_error:
 	msm_adsp_put(audio->audrec);
-	if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
-		msm_adsp_put(audio->audpre);
 
 	audpreproc_aenc_free(audio->enc_id);
 	mutex_unlock(&audio->lock);
diff --git a/arch/arm/mach-msm/qdsp5/audio_amrwb.c b/arch/arm/mach-msm/qdsp5/audio_amrwb.c
index 66b9354..83320f3 100644
--- a/arch/arm/mach-msm/qdsp5/audio_amrwb.c
+++ b/arch/arm/mach-msm/qdsp5/audio_amrwb.c
@@ -41,13 +41,14 @@
 #include <linux/slab.h>
 #include <linux/msm_audio.h>
 #include <linux/memory_alloc.h>
-#include <linux/ion.h>
+#include <linux/msm_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/qdsp5audpp.h>
 #include <mach/qdsp5/qdsp5audplaycmdi.h>
 #include <mach/qdsp5/qdsp5audplaymsg.h>
 #include <mach/qdsp5/qdsp5rmtcmdi.h>
diff --git a/arch/arm/mach-msm/qdsp5/audio_evrc.c b/arch/arm/mach-msm/qdsp5/audio_evrc.c
index 1d4148a..c0486db 100644
--- a/arch/arm/mach-msm/qdsp5/audio_evrc.c
+++ b/arch/arm/mach-msm/qdsp5/audio_evrc.c
@@ -36,13 +36,14 @@
 #include <linux/slab.h>
 #include <linux/msm_audio.h>
 #include <linux/memory_alloc.h>
-#include <linux/ion.h>
+#include <linux/msm_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/qdsp5audpp.h>
 #include <mach/qdsp5/qdsp5audplaycmdi.h>
 #include <mach/qdsp5/qdsp5audplaymsg.h>
 #include <mach/qdsp5/qdsp5rmtcmdi.h>
diff --git a/arch/arm/mach-msm/qdsp5/audio_evrc_in.c b/arch/arm/mach-msm/qdsp5/audio_evrc_in.c
index e955c4b..9bf0e83 100644
--- a/arch/arm/mach-msm/qdsp5/audio_evrc_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_evrc_in.c
@@ -33,7 +33,7 @@
 
 
 #include <linux/memory_alloc.h>
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
 
 #include <asm/atomic.h>
 #include <asm/ioctls.h>
@@ -111,7 +111,6 @@
 	int out_frame_cnt;
 
 	struct msm_adsp_module *audrec;
-	struct msm_adsp_module *audpre;
 
 
 	/* configuration to use on next enable */
@@ -154,6 +153,8 @@
 	struct ion_client *client;
 	struct ion_handle *input_buff_handle;
 	struct ion_handle *output_buff_handle;
+
+	struct audrec_session_info session_info; /*audrec session info*/
 };
 
 struct audio_frame {
@@ -232,6 +233,32 @@
 	}
 }
 
+/* ------------------- dsp --------------------- */
+static void audpre_dsp_event(void *data, unsigned id,  void *event_data)
+{
+
+	uint16_t *msg = event_data;
+
+	if (!msg)
+		return;
+
+	switch (id) {
+	case AUDPREPROC_MSG_CMD_CFG_DONE_MSG:
+		MM_DBG("type %d, status_flag %d\n",\
+			msg[0], msg[1]);
+		break;
+	case AUDPREPROC_MSG_ERROR_MSG_ID:
+		MM_INFO("err_index %d\n", msg[0]);
+		break;
+	case ADSP_MESSAGE_ID:
+		MM_DBG("Received ADSP event: module enable(audpreproctask)\n");
+		break;
+	default:
+		MM_ERR("unknown event %d\n", id);
+	}
+}
+
+
 /* must be called with audio->lock held */
 static int audevrc_in_enable(struct audio_evrc_in *audio)
 {
@@ -252,16 +279,24 @@
 		if (rc < 0)
 			return rc;
 
-		if (msm_adsp_enable(audio->audpre)) {
+		if (audpreproc_enable(audio->enc_id,
+				&audpre_dsp_event, audio)) {
+			MM_ERR("msm_adsp_enable(audpreproc) failed\n");
 			audmgr_disable(&audio->audmgr);
-			MM_ERR("msm_adsp_enable(audpre) failed\n");
 			return -ENODEV;
 		}
+
+		/*update aurec session info in audpreproc layer*/
+		audio->session_info.session_id = audio->enc_id;
+		audio->session_info.sampling_freq =
+			convert_samp_index(audio->samp_rate);
+		audpreproc_update_audrec_info(&audio->session_info);
 	}
+
 	if (msm_adsp_enable(audio->audrec)) {
 		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
+			audpreproc_disable(audio->enc_id, audio);
 			audmgr_disable(&audio->audmgr);
-			msm_adsp_disable(audio->audpre);
 		}
 		MM_ERR("msm_adsp_enable(audrec) failed\n");
 		return -ENODEV;
@@ -288,35 +323,17 @@
 		wake_up(&audio->wait);
 		msm_adsp_disable(audio->audrec);
 		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
-			msm_adsp_disable(audio->audpre);
+			audpreproc_disable(audio->enc_id, audio);
+			/*reset the sampling frequency information at
+			audpreproc layer*/
+			audio->session_info.sampling_freq = 0;
+			audpreproc_update_audrec_info(&audio->session_info);
 			audmgr_disable(&audio->audmgr);
 		}
 	}
 	return 0;
 }
 
-/* ------------------- dsp --------------------- */
-static void audpre_dsp_event(void *data, unsigned id, size_t len,
-			    void (*getevent)(void *ptr, size_t len))
-{
-	uint16_t msg[2];
-	getevent(msg, sizeof(msg));
-
-	switch (id) {
-	case AUDPREPROC_MSG_CMD_CFG_DONE_MSG:
-		MM_DBG("type %d, status_flag %d\n", msg[0], msg[1]);
-		break;
-	case AUDPREPROC_MSG_ERROR_MSG_ID:
-		MM_ERR("err_index %d\n", msg[0]);
-		break;
-	case ADSP_MESSAGE_ID:
-		MM_DBG("Received ADSP event: module enable(audpreproctask)\n");
-		break;
-	default:
-		MM_ERR("unknown event %d\n", id);
-	}
-}
-
 static void audevrc_in_get_dsp_frames(struct audio_evrc_in *audio)
 {
 	struct audio_frame *frame;
@@ -557,10 +574,6 @@
 	}
 }
 
-static struct msm_adsp_ops audpre_evrc_adsp_ops = {
-	.event = audpre_dsp_event,
-};
-
 static struct msm_adsp_ops audrec_evrc_adsp_ops = {
 	.event = audrec_dsp_event,
 };
@@ -1186,12 +1199,8 @@
 	audevrc_in_flush(audio);
 	msm_adsp_put(audio->audrec);
 
-	if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
-		msm_adsp_put(audio->audpre);
-
 	audpreproc_aenc_free(audio->enc_id);
 	audio->audrec = NULL;
-	audio->audpre = NULL;
 	audio->opened = 0;
 	if ((audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) && \
 	   (audio->out_data)) {
@@ -1282,16 +1291,6 @@
 		goto done;
 	}
 
-	if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
-		rc = msm_adsp_get("AUDPREPROCTASK", &audio->audpre,
-				&audpre_evrc_adsp_ops, audio);
-		if (rc) {
-			msm_adsp_put(audio->audrec);
-			audpreproc_aenc_free(audio->enc_id);
-			goto done;
-		}
-	}
-
 	audio->dsp_cnt = 0;
 	audio->stopped = 0;
 	audio->wflush = 0;
@@ -1429,8 +1428,6 @@
 	ion_client_destroy(client);
 client_create_error:
 	msm_adsp_put(audio->audrec);
-	if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
-		msm_adsp_put(audio->audpre);
 
 	audpreproc_aenc_free(audio->enc_id);
 	mutex_unlock(&audio->lock);
diff --git a/arch/arm/mach-msm/qdsp5/audio_lpa.c b/arch/arm/mach-msm/qdsp5/audio_lpa.c
index fe7b270..a067b83 100644
--- a/arch/arm/mach-msm/qdsp5/audio_lpa.c
+++ b/arch/arm/mach-msm/qdsp5/audio_lpa.c
@@ -37,7 +37,7 @@
 #include <linux/debugfs.h>
 #include <linux/delay.h>
 #include <linux/earlysuspend.h>
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
 #include <linux/list.h>
 #include <linux/slab.h>
 #include <linux/msm_audio.h>
@@ -48,6 +48,7 @@
 #include <mach/iommu_domains.h>
 #include <mach/qdsp5/qdsp5audppcmdi.h>
 #include <mach/qdsp5/qdsp5audppmsg.h>
+#include <mach/qdsp5/qdsp5audpp.h>
 #include <mach/qdsp5/qdsp5audplaycmdi.h>
 #include <mach/qdsp5/qdsp5audplaymsg.h>
 #include <mach/qdsp5/qdsp5rmtcmdi.h>
diff --git a/arch/arm/mach-msm/qdsp5/audio_mp3.c b/arch/arm/mach-msm/qdsp5/audio_mp3.c
index 427dc8f..cef3d99 100644
--- a/arch/arm/mach-msm/qdsp5/audio_mp3.c
+++ b/arch/arm/mach-msm/qdsp5/audio_mp3.c
@@ -34,7 +34,7 @@
 #include <linux/slab.h>
 #include <linux/msm_audio.h>
 #include <linux/memory_alloc.h>
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
 
 #include <mach/msm_adsp.h>
 #include <mach/iommu.h>
@@ -42,6 +42,7 @@
 #include <mach/msm_memtypes.h>
 #include <mach/qdsp5/qdsp5audppcmdi.h>
 #include <mach/qdsp5/qdsp5audppmsg.h>
+#include <mach/qdsp5/qdsp5audpp.h>
 #include <mach/qdsp5/qdsp5audplaycmdi.h>
 #include <mach/qdsp5/qdsp5audplaymsg.h>
 #include <mach/qdsp5/qdsp5rmtcmdi.h>
@@ -2297,7 +2298,10 @@
 		if (rc) {
 			MM_ERR("audmgr open failed, freeing instance \
 					0x%08x\n", (int)audio);
-			goto err;
+			if (!(file->f_flags & O_NONBLOCK))
+				goto err;
+			else
+				goto resource_err;
 		}
 	}
 
@@ -2309,7 +2313,10 @@
 				audio->module_name, (int)audio);
 		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
 			audmgr_close(&audio->audmgr);
-		goto err;
+		if (!(file->f_flags & O_NONBLOCK))
+			goto err;
+		else
+			goto resource_err;
 	}
 
 	rc = rmt_get_resource(audio);
@@ -2319,7 +2326,10 @@
 		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
 			audmgr_close(&audio->audmgr);
 		msm_adsp_put(audio->audplay);
-		goto err;
+		if (!(file->f_flags & O_NONBLOCK))
+			goto err;
+		else
+			goto resource_err;
 	}
 
 	if (file->f_flags & O_NONBLOCK) {
@@ -2409,6 +2419,7 @@
 output_buff_alloc_error:
 	ion_client_destroy(client);
 client_create_error:
+resource_err:
 	audpp_adec_free(audio->dec_id);
 	kfree(audio);
 	return rc;
diff --git a/arch/arm/mach-msm/qdsp5/audio_out.c b/arch/arm/mach-msm/qdsp5/audio_out.c
index 0c8034c..6f3bf91 100644
--- a/arch/arm/mach-msm/qdsp5/audio_out.c
+++ b/arch/arm/mach-msm/qdsp5/audio_out.c
@@ -41,6 +41,7 @@
 
 #include <mach/qdsp5/qdsp5audppcmdi.h>
 #include <mach/qdsp5/qdsp5audppmsg.h>
+#include <mach/qdsp5/qdsp5audpp.h>
 
 #include <mach/htc_pwrsink.h>
 #include <mach/debug_mm.h>
diff --git a/arch/arm/mach-msm/qdsp5/audio_pcm.c b/arch/arm/mach-msm/qdsp5/audio_pcm.c
index 880de09..340bcc6 100644
--- a/arch/arm/mach-msm/qdsp5/audio_pcm.c
+++ b/arch/arm/mach-msm/qdsp5/audio_pcm.c
@@ -38,7 +38,7 @@
 #include <linux/delay.h>
 #include <linux/earlysuspend.h>
 #include <linux/list.h>
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
 #include <linux/slab.h>
 #include <linux/msm_audio.h>
 
@@ -48,6 +48,7 @@
 #include <mach/iommu_domains.h>
 #include <mach/qdsp5/qdsp5audppcmdi.h>
 #include <mach/qdsp5/qdsp5audppmsg.h>
+#include <mach/qdsp5/qdsp5audpp.h>
 #include <mach/qdsp5/qdsp5audplaycmdi.h>
 #include <mach/qdsp5/qdsp5audplaymsg.h>
 #include <mach/qdsp5/qdsp5rmtcmdi.h>
diff --git a/arch/arm/mach-msm/qdsp5/audio_pcm_in.c b/arch/arm/mach-msm/qdsp5/audio_pcm_in.c
index 716dbd2..2da1f19 100644
--- a/arch/arm/mach-msm/qdsp5/audio_pcm_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_pcm_in.c
@@ -26,7 +26,7 @@
 #include <linux/kthread.h>
 #include <linux/wait.h>
 #include <linux/dma-mapping.h>
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
 
 #include <linux/delay.h>
 
@@ -75,7 +75,6 @@
 	struct mutex read_lock;
 	wait_queue_head_t wait;
 
-	struct msm_adsp_module *audpre;
 	struct msm_adsp_module *audrec;
 	const char *module_name;
 	unsigned queue_ids;
@@ -105,6 +104,7 @@
 	int enabled;
 	int running;
 	int stopped; /* set when stopped, cleared on flush */
+	struct audrec_session_info session_info; /*audrec session info*/
 
 	/* audpre settings */
 	int tx_agc_enable;
@@ -176,6 +176,32 @@
 	}
 }
 
+/* ------------------- dsp --------------------- */
+static void audpre_dsp_event(void *data, unsigned id,  void *event_data)
+{
+
+	uint16_t *msg = event_data;
+
+	if (!msg)
+		return;
+
+	switch (id) {
+	case AUDPREPROC_MSG_CMD_CFG_DONE_MSG:
+		MM_DBG("type %d, status_flag %d\n",\
+			msg[0], msg[1]);
+		break;
+	case AUDPREPROC_MSG_ERROR_MSG_ID:
+		MM_INFO("err_index %d\n", msg[0]);
+		break;
+	case ADSP_MESSAGE_ID:
+		MM_DBG("Received ADSP event: module enable(audpreproctask)\n");
+		break;
+	default:
+		MM_ERR("unknown event %d\n", id);
+	}
+}
+
+
 /* must be called with audio->lock held */
 static int audpcm_in_enable(struct audio_in *audio)
 {
@@ -195,14 +221,15 @@
 	if (rc < 0)
 		return rc;
 
-	if (msm_adsp_enable(audio->audpre)) {
-		MM_ERR("msm_adsp_enable(audpre) failed\n");
+	if (audpreproc_enable(audio->enc_id, &audpre_dsp_event, audio)) {
+		MM_ERR("msm_adsp_enable(audpreproc) failed\n");
 		audmgr_disable(&audio->audmgr);
 		return -ENODEV;
 	}
+
 	if (msm_adsp_enable(audio->audrec)) {
+		audpreproc_disable(audio->enc_id, audio);
 		audmgr_disable(&audio->audmgr);
-		msm_adsp_disable(audio->audpre);
 		MM_ERR("msm_adsp_enable(audrec) failed\n");
 		return -ENODEV;
 	}
@@ -210,6 +237,12 @@
 	audio->enabled = 1;
 	audpcm_in_dsp_enable(audio, 1);
 
+	/*update aurec session info in audpreproc layer*/
+	audio->session_info.session_id = audio->enc_id;
+	audio->session_info.sampling_freq =
+			convert_samp_index(audio->samp_rate);
+	audpreproc_update_audrec_info(&audio->session_info);
+
 	return 0;
 }
 
@@ -225,34 +258,15 @@
 		wake_up(&audio->wait);
 
 		msm_adsp_disable(audio->audrec);
-		msm_adsp_disable(audio->audpre);
+		audpreproc_disable(audio->enc_id, audio);
+		/*reset the sampling frequency information at audpreproc layer*/
+		audio->session_info.sampling_freq = 0;
+		audpreproc_update_audrec_info(&audio->session_info);
 		audmgr_disable(&audio->audmgr);
 	}
 	return 0;
 }
 
-/* ------------------- dsp --------------------- */
-static void audpre_dsp_event(void *data, unsigned id, size_t len,
-			    void (*getevent)(void *ptr, size_t len))
-{
-	uint16_t msg[2];
-	getevent(msg, sizeof(msg));
-
-	switch (id) {
-	case AUDPREPROC_MSG_CMD_CFG_DONE_MSG:
-		MM_INFO("type %d, status_flag %d\n", msg[0], msg[1]);
-		break;
-	case AUDPREPROC_MSG_ERROR_MSG_ID:
-		MM_ERR("err_index %d\n", msg[0]);
-		break;
-	case ADSP_MESSAGE_ID:
-		MM_DBG("Received ADSP event: module enable(audpreproctask)\n");
-		break;
-	default:
-		MM_ERR("unknown event %d\n", id);
-	}
-}
-
 struct audio_frame {
 	uint16_t count_low;
 	uint16_t count_high;
@@ -360,18 +374,10 @@
 	}
 }
 
-static struct msm_adsp_ops audpre_adsp_ops = {
-	.event = audpre_dsp_event,
-};
-
 static struct msm_adsp_ops audrec_adsp_ops = {
 	.event = audrec_dsp_event,
 };
 
-
-#define audio_send_queue_pre(audio, cmd, len) \
-	msm_adsp_write(audio->audpre, QDSP_uPAudPreProcCmdQueue, cmd, len)
-
 #define audio_send_queue_recbs(audio, cmd, len) \
 	msm_adsp_write(audio->audrec, ((audio->queue_ids & 0xFFFF0000) >> 16),\
 			cmd, len)
@@ -399,7 +405,7 @@
 		audio->tx_agc_cfg.tx_agc_enable_flag =
 			AUDPREPROC_CMD_TX_AGC_ENA_FLAG_ENA;
 		/* cmd.param_mask = 0xFFF0 from sample code */
-		audio->tx_agc_cfg.param_mask =
+		audio->tx_agc_cfg.tx_agc_param_mask =
 			(1 << AUDPREPROC_CMD_PARAM_MASK_RMS_TAY) |
 			(1 << AUDPREPROC_CMD_PARAM_MASK_RELEASEK) |
 			(1 << AUDPREPROC_CMD_PARAM_MASK_DELAY) |
@@ -420,7 +426,7 @@
 	}
 	cmd = audio->tx_agc_cfg;
 
-	return audio_send_queue_pre(audio, &cmd, sizeof(cmd));
+	return audpreproc_dsp_set_agc(&cmd, sizeof(cmd));
 }
 
 static int audio_enable_tx_agc(struct audio_in *audio, int enable)
@@ -466,7 +472,7 @@
 	}
 	cmd = audio->ns_cfg;
 
-	return audio_send_queue_pre(audio, &cmd, sizeof(cmd));
+	return audpreproc_dsp_set_ns(&cmd, sizeof(cmd));
 }
 
 static int audio_enable_ns(struct audio_in *audio, int enable)
@@ -495,7 +501,7 @@
 
 	cmd = audio->iir_cfg;
 
-	return audio_send_queue_pre(audio, &cmd, sizeof(cmd));
+	return audpreproc_dsp_set_iir(&cmd, sizeof(cmd));
 }
 
 static int audio_enable_iir(struct audio_in *audio, int enable)
@@ -762,9 +768,7 @@
 	audpcm_in_flush(audio);
 	audpreproc_aenc_free(audio->enc_id);
 	msm_adsp_put(audio->audrec);
-	msm_adsp_put(audio->audpre);
 	audio->audrec = NULL;
-	audio->audpre = NULL;
 	audio->opened = 0;
 	if (audio->data) {
 		ion_unmap_kernel(audio->client, audio->output_buff_handle);
@@ -824,14 +828,6 @@
 		goto done;
 	}
 
-	rc = msm_adsp_get("AUDPREPROCTASK", &audio->audpre,
-				&audpre_adsp_ops, audio);
-	if (rc) {
-		msm_adsp_put(audio->audrec);
-		audpreproc_aenc_free(audio->enc_id);
-		goto done;
-	}
-
 	audio->dsp_cnt = 0;
 	audio->stopped = 0;
 
@@ -899,7 +895,6 @@
 	ion_client_destroy(client);
 client_create_error:
 	msm_adsp_put(audio->audrec);
-	msm_adsp_put(audio->audpre);
 	audpreproc_aenc_free(audio->enc_id);
 	mutex_unlock(&audio->lock);
 	return rc;
diff --git a/arch/arm/mach-msm/qdsp5/audio_qcelp.c b/arch/arm/mach-msm/qdsp5/audio_qcelp.c
index dc257cd..1a0c333 100644
--- a/arch/arm/mach-msm/qdsp5/audio_qcelp.c
+++ b/arch/arm/mach-msm/qdsp5/audio_qcelp.c
@@ -37,13 +37,14 @@
 #include <linux/slab.h>
 #include <linux/msm_audio.h>
 #include <linux/memory_alloc.h>
-#include <linux/ion.h>
+#include <linux/msm_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/qdsp5audpp.h>
 #include <mach/qdsp5/qdsp5audplaycmdi.h>
 #include <mach/qdsp5/qdsp5audplaymsg.h>
 #include <mach/qdsp5/qdsp5rmtcmdi.h>
diff --git a/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c b/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c
index 99a169d..ee079bc 100644
--- a/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c
@@ -33,7 +33,7 @@
 
 
 #include <linux/memory_alloc.h>
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
 
 #include <asm/atomic.h>
 #include <asm/ioctls.h>
@@ -112,7 +112,6 @@
 	int out_frame_cnt;
 
 	struct msm_adsp_module *audrec;
-	struct msm_adsp_module *audpre;
 
 
 	/* configuration to use on next enable */
@@ -155,6 +154,8 @@
 	struct ion_client *client;
 	struct ion_handle *input_buff_handle;
 	struct ion_handle *output_buff_handle;
+
+	struct audrec_session_info session_info; /*audrec session info*/
 };
 
 struct audio_frame {
@@ -233,6 +234,32 @@
 	}
 }
 
+/* ------------------- dsp --------------------- */
+static void audpre_dsp_event(void *data, unsigned id,  void *event_data)
+{
+
+	uint16_t *msg = event_data;
+
+	if (!msg)
+		return;
+
+	switch (id) {
+	case AUDPREPROC_MSG_CMD_CFG_DONE_MSG:
+		MM_DBG("type %d, status_flag %d\n",\
+			msg[0], msg[1]);
+		break;
+	case AUDPREPROC_MSG_ERROR_MSG_ID:
+		MM_INFO("err_index %d\n", msg[0]);
+		break;
+	case ADSP_MESSAGE_ID:
+		MM_DBG("Received ADSP event: module enable(audpreproctask)\n");
+		break;
+	default:
+		MM_ERR("unknown event %d\n", id);
+	}
+}
+
+
 /* must be called with audio->lock held */
 static int audqcelp_in_enable(struct audio_qcelp_in *audio)
 {
@@ -253,16 +280,23 @@
 		if (rc < 0)
 			return rc;
 
-		if (msm_adsp_enable(audio->audpre)) {
+		if (audpreproc_enable(audio->enc_id,
+				&audpre_dsp_event, audio)) {
+			MM_ERR("msm_adsp_enable(audpreproc) failed\n");
 			audmgr_disable(&audio->audmgr);
-			MM_ERR("msm_adsp_enable(audpre) failed\n");
 			return -ENODEV;
 		}
+
+		/*update aurec session info in audpreproc layer*/
+		audio->session_info.session_id = audio->enc_id;
+		audio->session_info.sampling_freq =
+			convert_samp_index(audio->samp_rate);
+		audpreproc_update_audrec_info(&audio->session_info);
 	}
 	if (msm_adsp_enable(audio->audrec)) {
 		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
+			audpreproc_disable(audio->enc_id, audio);
 			audmgr_disable(&audio->audmgr);
-			msm_adsp_disable(audio->audpre);
 		}
 		MM_ERR("msm_adsp_enable(audrec) failed\n");
 		return -ENODEV;
@@ -288,35 +322,17 @@
 		wake_up(&audio->wait);
 		msm_adsp_disable(audio->audrec);
 		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
-			msm_adsp_disable(audio->audpre);
+			audpreproc_disable(audio->enc_id, audio);
 			audmgr_disable(&audio->audmgr);
+			/*reset the sampling frequency information at
+			  audpreproc layer*/
+			audio->session_info.sampling_freq = 0;
+			audpreproc_update_audrec_info(&audio->session_info);
 		}
 	}
 	return 0;
 }
 
-/* ------------------- dsp --------------------- */
-static void audpre_dsp_event(void *data, unsigned id, size_t len,
-			    void (*getevent)(void *ptr, size_t len))
-{
-	uint16_t msg[2];
-	getevent(msg, sizeof(msg));
-
-	switch (id) {
-	case AUDPREPROC_MSG_CMD_CFG_DONE_MSG:
-		MM_DBG("type %d, status_flag %d\n", msg[0], msg[1]);
-		break;
-	case AUDPREPROC_MSG_ERROR_MSG_ID:
-		MM_ERR("err_index %d\n", msg[0]);
-		break;
-	case ADSP_MESSAGE_ID:
-		MM_DBG("Received ADSP event: module enable(audpreproctask)\n");
-		break;
-	default:
-		MM_ERR("unknown event %d\n", id);
-	}
-}
-
 static void audqcelp_in_get_dsp_frames(struct audio_qcelp_in *audio)
 {
 	struct audio_frame *frame;
@@ -557,10 +573,6 @@
 	}
 }
 
-static struct msm_adsp_ops audpre_qcelp_adsp_ops = {
-	.event = audpre_dsp_event,
-};
-
 static struct msm_adsp_ops audrec_qcelp_adsp_ops = {
 	.event = audrec_dsp_event,
 };
@@ -1187,12 +1199,8 @@
 	audqcelp_in_flush(audio);
 	msm_adsp_put(audio->audrec);
 
-	if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
-		msm_adsp_put(audio->audpre);
-
 	audpreproc_aenc_free(audio->enc_id);
 	audio->audrec = NULL;
-	audio->audpre = NULL;
 	audio->opened = 0;
 
 	if ((audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) && \
@@ -1285,16 +1293,6 @@
 		goto done;
 	}
 
-	if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
-		rc = msm_adsp_get("AUDPREPROCTASK", &audio->audpre,
-				&audpre_qcelp_adsp_ops, audio);
-		if (rc) {
-			msm_adsp_put(audio->audrec);
-			audpreproc_aenc_free(audio->enc_id);
-			goto done;
-		}
-	}
-
 	audio->dsp_cnt = 0;
 	audio->stopped = 0;
 	audio->wflush = 0;
@@ -1434,8 +1432,6 @@
 	ion_client_destroy(client);
 client_create_error:
 	msm_adsp_put(audio->audrec);
-	if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
-		msm_adsp_put(audio->audpre);
 
 	audpreproc_aenc_free(audio->enc_id);
 	mutex_unlock(&audio->lock);
diff --git a/arch/arm/mach-msm/qdsp5/audio_wma.c b/arch/arm/mach-msm/qdsp5/audio_wma.c
index e28e704..0a77b58 100644
--- a/arch/arm/mach-msm/qdsp5/audio_wma.c
+++ b/arch/arm/mach-msm/qdsp5/audio_wma.c
@@ -41,13 +41,14 @@
 #include <linux/msm_audio.h>
 #include <linux/msm_audio_wma.h>
 #include <linux/memory_alloc.h>
-#include <linux/ion.h>
+#include <linux/msm_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/qdsp5audpp.h>
 #include <mach/qdsp5/qdsp5audplaycmdi.h>
 #include <mach/qdsp5/qdsp5audplaymsg.h>
 #include <mach/qdsp5/qdsp5rmtcmdi.h>
diff --git a/arch/arm/mach-msm/qdsp5/audio_wmapro.c b/arch/arm/mach-msm/qdsp5/audio_wmapro.c
index 87afcf0..82fc3f9 100644
--- a/arch/arm/mach-msm/qdsp5/audio_wmapro.c
+++ b/arch/arm/mach-msm/qdsp5/audio_wmapro.c
@@ -40,11 +40,12 @@
 #include <linux/msm_audio.h>
 #include <linux/memory_alloc.h>
 #include <linux/msm_audio_wmapro.h>
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
 
 #include <mach/msm_adsp.h>
 #include <mach/qdsp5/qdsp5audppcmdi.h>
 #include <mach/qdsp5/qdsp5audppmsg.h>
+#include <mach/qdsp5/qdsp5audpp.h>
 #include <mach/qdsp5/qdsp5audplaycmdi.h>
 #include <mach/qdsp5/qdsp5audplaymsg.h>
 #include <mach/qdsp5/qdsp5rmtcmdi.h>
diff --git a/arch/arm/mach-msm/qdsp5/audmgr.c b/arch/arm/mach-msm/qdsp5/audmgr.c
index 231a28c..666323b 100644
--- a/arch/arm/mach-msm/qdsp5/audmgr.c
+++ b/arch/arm/mach-msm/qdsp5/audmgr.c
@@ -3,7 +3,7 @@
  * interface to "audmgr" service on the baseband cpu
  *
  * Copyright (C) 2008 Google, Inc.
- * Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009, 2012 Code Aurora Forum. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -35,6 +35,10 @@
 #define STATE_ENABLED   3
 #define STATE_DISABLING 4
 #define STATE_ERROR	5
+#define MAX_DEVICE_INFO_CALLBACK 1
+#define SESSION_VOICE 0
+#define SESSION_PLAYBACK 1
+#define SESSION_RECORDING 2
 
 /* store information used across complete audmgr sessions */
 struct audmgr_global {
@@ -42,6 +46,9 @@
 	struct msm_rpc_endpoint *ept;
 	struct task_struct *task;
 	uint32_t rpc_version;
+	int cad;
+	struct device_info_callback *device_cb[MAX_DEVICE_INFO_CALLBACK];
+
 };
 static DEFINE_MUTEX(audmgr_lock);
 
@@ -49,6 +56,59 @@
 	.lock = &audmgr_lock,
 };
 
+static void audmgr_rpc_connect(struct audmgr_global *amg)
+{
+	amg->cad = 0;
+	amg->ept = msm_rpc_connect_compatible(AUDMGR_PROG,
+			AUDMGR_VERS_COMP_VER3,
+			MSM_RPC_UNINTERRUPTIBLE);
+	if (IS_ERR(amg->ept)) {
+		MM_DBG("connect failed with current VERS"\
+				"= %x, trying again with  Cad API\n",
+				AUDMGR_VERS_COMP_VER3);
+		amg->ept = msm_rpc_connect_compatible(AUDMGR_PROG,
+				AUDMGR_VERS_COMP_VER4,
+				MSM_RPC_UNINTERRUPTIBLE);
+		if (IS_ERR(amg->ept)) {
+			amg->ept = msm_rpc_connect_compatible(AUDMGR_PROG,
+					AUDMGR_VERS_COMP_VER2,
+					MSM_RPC_UNINTERRUPTIBLE);
+			if (IS_ERR(amg->ept)) {
+				MM_ERR("connect failed with current VERS" \
+					"= %x, trying again with another API\n",
+					AUDMGR_VERS_COMP_VER2);
+				amg->ept = msm_rpc_connect_compatible(
+						AUDMGR_PROG,
+						AUDMGR_VERS_COMP,
+						MSM_RPC_UNINTERRUPTIBLE);
+				if (IS_ERR(amg->ept)) {
+					MM_ERR("connect failed with current" \
+						"VERS=%x, trying again with" \
+						"another API\n",
+						AUDMGR_VERS_COMP);
+					amg->ept = msm_rpc_connect(AUDMGR_PROG,
+						AUDMGR_VERS,
+						MSM_RPC_UNINTERRUPTIBLE);
+					amg->rpc_version = AUDMGR_VERS;
+				} else
+					amg->rpc_version = AUDMGR_VERS_COMP;
+			} else
+				amg->rpc_version = AUDMGR_VERS_COMP_VER2;
+		} else {
+			amg->rpc_version = AUDMGR_VERS_COMP_VER4;
+			amg->cad = 1;
+		}
+	} else
+		amg->rpc_version = AUDMGR_VERS_COMP_VER3;
+
+	if (IS_ERR(amg->ept)) {
+		amg->ept = NULL;
+		MM_ERR("failed to connect to audmgr svc\n");
+	}
+
+	return;
+}
+
 static void rpc_ack(struct msm_rpc_endpoint *ept, uint32_t xid)
 {
 	uint32_t rep[6];
@@ -64,34 +124,45 @@
 }
 
 static void process_audmgr_callback(struct audmgr_global *amg,
-				   struct rpc_audmgr_cb_func_ptr *args,
-				   int len)
+				   void *args, int len)
 {
 	struct audmgr *am;
+	int i = 0;
+	struct rpc_audmgr_cb_device_info *temp;
 
-	/* Allow only if complete arguments recevied */
-	if (len < (sizeof(struct rpc_audmgr_cb_func_ptr)))
+	/* Allow only if complete arguments recevied*/
+	if (len < MIN_RPC_DATA_LENGTH)
 		return;
 
 	/* Allow only if valid argument */
-	if (be32_to_cpu(args->set_to_one) != 1)
+	if (be32_to_cpu(((struct rpc_audmgr_cb_common *)args)->set_to_one) != 1)
 		return;
 
-	am = (struct audmgr *) be32_to_cpu(args->client_data);
-
-	if (!am)
-		return;
-
-	switch (be32_to_cpu(args->status)) {
+	switch (be32_to_cpu(((struct rpc_audmgr_cb_common *)args)->status)) {
 	case RPC_AUDMGR_STATUS_READY:
-		am->handle = be32_to_cpu(args->u.handle);
+		am = (struct audmgr *) be32_to_cpu(
+			((struct rpc_audmgr_cb_ready *)args)->client_data);
+		if (!am)
+			return;
+		am->handle = be32_to_cpu(
+				((struct rpc_audmgr_cb_ready *)args)->u.handle);
 		MM_INFO("rpc READY handle=0x%08x\n", am->handle);
 		break;
 	case RPC_AUDMGR_STATUS_CODEC_CONFIG: {
-		uint32_t volume;
-		volume = be32_to_cpu(args->u.volume);
-		MM_INFO("rpc CODEC_CONFIG volume=0x%08x\n", volume);
-		am->state = STATE_ENABLED;
+		MM_INFO("rpc CODEC_CONFIG\n");
+		am = (struct audmgr *) be32_to_cpu(
+			((struct rpc_audmgr_cb_ready *)args)->client_data);
+		if (!am)
+			return;
+		if (am->state != STATE_ENABLED)
+			am->state = STATE_ENABLED;
+		while ((amg->device_cb[i] != NULL) &&
+				(i < MAX_DEVICE_INFO_CALLBACK) &&
+				(amg->cad)) {
+			amg->device_cb[i]->func(&(am->evt),
+					amg->device_cb[i]->private);
+			i++;
+		}
 		wake_up(&am->wait);
 		break;
 	}
@@ -109,14 +180,51 @@
 		break;
 	case RPC_AUDMGR_STATUS_DISABLED:
 		MM_ERR("DISABLED\n");
+		am = (struct audmgr *) be32_to_cpu(
+			((struct rpc_audmgr_cb_ready *)args)->client_data);
+		if (!am)
+			return;
 		am->state = STATE_DISABLED;
 		wake_up(&am->wait);
 		break;
 	case RPC_AUDMGR_STATUS_ERROR:
 		MM_ERR("ERROR?\n");
+		am = (struct audmgr *) be32_to_cpu(
+			((struct rpc_audmgr_cb_ready *)args)->client_data);
+		if (!am)
+			return;
 		am->state = STATE_ERROR;
 		wake_up(&am->wait);
 		break;
+	case RPC_AUDMGR_STATUS_DEVICE_INFO:
+		MM_INFO("rpc DEVICE_INFO\n");
+		if (!amg->cad)
+			break;
+		temp = (struct rpc_audmgr_cb_device_info *)args;
+		am = (struct audmgr *) be32_to_cpu(temp->client_data);
+		if (!am)
+			return;
+		if (am->evt.session_info == SESSION_PLAYBACK) {
+			am->evt.dev_type.rx_device =
+					be32_to_cpu(temp->d.rx_device);
+			am->evt.dev_type.tx_device = 0;
+			am->evt.acdb_id = am->evt.dev_type.rx_device;
+		} else if (am->evt.session_info == SESSION_RECORDING) {
+			am->evt.dev_type.rx_device = 0;
+			am->evt.dev_type.tx_device =
+					be32_to_cpu(temp->d.tx_device);
+			am->evt.acdb_id = am->evt.dev_type.tx_device;
+		}
+		am->evt.dev_type.ear_mute =
+					be32_to_cpu(temp->d.ear_mute);
+		am->evt.dev_type.mic_mute =
+					be32_to_cpu(temp->d.mic_mute);
+		am->evt.dev_type.volume =
+					be32_to_cpu(temp->d.volume);
+		break;
+	case RPC_AUDMGR_STATUS_DEVICE_CONFIG:
+		MM_ERR("rpc DEVICE_CONFIG\n");
+		break;
 	default:
 		break;
 	}
@@ -201,6 +309,36 @@
 	return 0;
 }
 
+static unsigned convert_samp_index(unsigned index)
+{
+	switch (index) {
+	case RPC_AUD_DEF_SAMPLE_RATE_48000:	return 48000;
+	case RPC_AUD_DEF_SAMPLE_RATE_44100:	return 44100;
+	case RPC_AUD_DEF_SAMPLE_RATE_32000:	return 32000;
+	case RPC_AUD_DEF_SAMPLE_RATE_24000:	return 24000;
+	case RPC_AUD_DEF_SAMPLE_RATE_22050:	return 22050;
+	case RPC_AUD_DEF_SAMPLE_RATE_16000:	return 16000;
+	case RPC_AUD_DEF_SAMPLE_RATE_12000:	return 12000;
+	case RPC_AUD_DEF_SAMPLE_RATE_11025:	return 11025;
+	case RPC_AUD_DEF_SAMPLE_RATE_8000:	return 8000;
+	default:				return 11025;
+	}
+}
+
+static void get_current_session_info(struct audmgr *am,
+				struct audmgr_config *cfg)
+{
+	if (cfg->def_method == RPC_AUD_DEF_METHOD_PLAYBACK ||
+	   (cfg->def_method == RPC_AUD_DEF_METHOD_HOST_PCM && cfg->rx_rate)) {
+		am->evt.session_info = SESSION_PLAYBACK; /* playback */
+		am->evt.sample_rate = convert_samp_index(cfg->rx_rate);
+	} else if (cfg->def_method == RPC_AUD_DEF_METHOD_RECORD) {
+		am->evt.session_info = SESSION_RECORDING; /* recording */
+		am->evt.sample_rate = convert_samp_index(cfg->tx_rate);
+	} else
+		am->evt.session_info = SESSION_VOICE;
+}
+
 struct audmgr_enable_msg {
 	struct rpc_request_hdr hdr;
 	struct rpc_audmgr_enable_client_args args;
@@ -223,39 +361,7 @@
 
 	/* connect to audmgr end point and polling thread only once */
 	if (amg->ept == NULL) {
-		amg->ept = msm_rpc_connect_compatible(AUDMGR_PROG,
-				AUDMGR_VERS_COMP_VER3,
-				MSM_RPC_UNINTERRUPTIBLE);
-		if (IS_ERR(amg->ept)) {
-			MM_ERR("connect failed with current VERS \
-				= %x, trying again with another API\n",
-				AUDMGR_VERS_COMP_VER3);
-			amg->ept = msm_rpc_connect_compatible(AUDMGR_PROG,
-					AUDMGR_VERS_COMP_VER2,
-					MSM_RPC_UNINTERRUPTIBLE);
-			if (IS_ERR(amg->ept)) {
-				MM_ERR("connect failed with current VERS \
-					= %x, trying again with another API\n",
-					AUDMGR_VERS_COMP_VER2);
-				amg->ept = msm_rpc_connect_compatible(
-						AUDMGR_PROG,
-						AUDMGR_VERS_COMP,
-						MSM_RPC_UNINTERRUPTIBLE);
-				if (IS_ERR(amg->ept)) {
-					MM_ERR("connect failed with current \
-					VERS=%x, trying again with another \
-					API\n", AUDMGR_VERS_COMP);
-					amg->ept = msm_rpc_connect(AUDMGR_PROG,
-						AUDMGR_VERS,
-						MSM_RPC_UNINTERRUPTIBLE);
-					amg->rpc_version = AUDMGR_VERS;
-				} else
-					amg->rpc_version = AUDMGR_VERS_COMP;
-			} else
-				amg->rpc_version = AUDMGR_VERS_COMP_VER2;
-		} else
-			amg->rpc_version = AUDMGR_VERS_COMP_VER3;
-
+		audmgr_rpc_connect(amg);
 		if (IS_ERR(amg->ept)) {
 			rc = PTR_ERR(amg->ept);
 			amg->ept = NULL;
@@ -312,6 +418,7 @@
 	msg.args.cb_func = cpu_to_be32(0x11111111);
 	msg.args.client_data = cpu_to_be32((int)am);
 
+	get_current_session_info(am, cfg);
 	msm_rpc_setup_req(&msg.hdr, AUDMGR_PROG, amg->rpc_version,
 			  AUDMGR_ENABLE_CLIENT);
 
@@ -326,6 +433,7 @@
 	if (am->state == STATE_ENABLED)
 		return 0;
 
+	am->evt.session_info = -1;
 	MM_ERR("unexpected state %d while enabling?!\n", am->state);
 	return -ENODEV;
 }
@@ -341,6 +449,7 @@
 		return 0;
 
 	MM_INFO("session 0x%08x\n", (int) am);
+	am->evt.session_info = -1;
 	msg.handle = cpu_to_be32(am->handle);
 	msm_rpc_setup_req(&msg.hdr, AUDMGR_PROG, amg->rpc_version,
 			  AUDMGR_DISABLE_CLIENT);
@@ -363,3 +472,33 @@
 	return -ENODEV;
 }
 EXPORT_SYMBOL(audmgr_disable);
+
+int audmgr_register_device_info_callback(struct device_info_callback *dcb)
+{
+	struct audmgr_global *amg = &the_audmgr_state;
+	int i;
+
+	for (i = 0; i < MAX_DEVICE_INFO_CALLBACK; i++) {
+		if (NULL == amg->device_cb[i]) {
+			amg->device_cb[i] = dcb;
+			return 0;
+		}
+	}
+	return -EINVAL;
+}
+EXPORT_SYMBOL(audmgr_register_device_info_callback);
+
+int audmgr_deregister_device_info_callback(struct device_info_callback *dcb)
+{
+	struct audmgr_global *amg = &the_audmgr_state;
+	int i;
+
+	for (i = 0; i < MAX_DEVICE_INFO_CALLBACK; i++) {
+		if (dcb == amg->device_cb[i]) {
+			amg->device_cb[i] = NULL;
+			return 0;
+		}
+	}
+	return -EINVAL;
+}
+EXPORT_SYMBOL(audmgr_deregister_device_info_callback);
diff --git a/arch/arm/mach-msm/qdsp5/audmgr.h b/arch/arm/mach-msm/qdsp5/audmgr.h
index 34c8488..15dd954 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,
 };
 
@@ -124,6 +125,9 @@
 	RPC_AUDMGR_STATUS_VOLUME_CHANGE,
 	RPC_AUDMGR_STATUS_DISABLED,
 	RPC_AUDMGR_STATUS_ERROR,
+	RPC_AUDMGR_STATUS_DEVICE_CONFIG,
+	RPC_AUDMGR_STATUS_DEVICE_INFO
+
 };
 
 struct rpc_audmgr_enable_client_args {
@@ -147,6 +151,7 @@
 #define AUDMGR_GET_RX_SAMPLE_RATE		8
 #define AUDMGR_GET_TX_SAMPLE_RATE		9
 #define AUDMGR_SET_DEVICE_MODE			10
+#define MIN_RPC_DATA_LENGTH 16
 
 #define AUDMGR_PROG_VERS "rs30000013:0x7feccbff"
 #define AUDMGR_PROG 0x30000013
@@ -154,8 +159,17 @@
 #define AUDMGR_VERS_COMP 0x00010001
 #define AUDMGR_VERS_COMP_VER2 0x00020001
 #define AUDMGR_VERS_COMP_VER3 0x00030001
+#define AUDMGR_VERS_COMP_VER4 0x00040001
 
-struct rpc_audmgr_cb_func_ptr {
+struct cad_device_info_type {
+	uint32_t rx_device;
+	uint32_t tx_device;
+	uint32_t ear_mute;
+	uint32_t mic_mute;
+	uint32_t volume;
+};
+
+struct rpc_audmgr_cb_common {
 	uint32_t cb_id; /* cb_func */
 	uint32_t status; /* Audmgr status */
 	uint32_t set_to_one;  /* Pointer status (1 = valid, 0  = invalid) */
@@ -164,6 +178,10 @@
 	   disc = AUDMGR_STATUS_CODEC_CONFIG => data = volume
 	   disc = AUDMGR_STATUS_DISABLED => data =status_disabled
 	   disc = AUDMGR_STATUS_VOLUME_CHANGE => data = volume_change */
+};
+
+struct rpc_audmgr_cb_ready {
+	struct rpc_audmgr_cb_common c_data;
 	union {
 		uint32_t handle;
 		uint32_t volume;
@@ -173,18 +191,35 @@
 	uint32_t client_data;
 };
 
+struct rpc_audmgr_cb_device_info {
+	struct rpc_audmgr_cb_common c_data;
+	struct cad_device_info_type d;
+	uint32_t client_data;
+};
+
 #define AUDMGR_CB_FUNC_PTR			1
 #define AUDMGR_OPR_LSTNR_CB_FUNC_PTR		2
 #define AUDMGR_CODEC_LSTR_FUNC_PTR		3
 
-#define AUDMGR_CB_PROG_VERS "rs31000013:0xf8e3e2d9"
-#define AUDMGR_CB_PROG 0x31000013
-#define AUDMGR_CB_VERS 0xf8e3e2d9
+struct dev_evt_msg {
+	struct cad_device_info_type dev_type;
+	uint32_t acdb_id;
+	int session_info;
+	uint32_t sample_rate;
+};
+
+typedef void (*device_info_func)(struct dev_evt_msg *evt_msg, void *private);
+
+struct device_info_callback {
+	device_info_func func;
+	void *private;
+};
 
 struct audmgr {
 	wait_queue_head_t wait;
 	uint32_t handle;
 	int state;
+	struct dev_evt_msg evt;
 };
 
 struct audmgr_config {
@@ -195,86 +230,11 @@
 	uint32_t snd_method;
 };
 
+int audmgr_register_device_info_callback(struct device_info_callback *dcb);
+int audmgr_deregister_device_info_callback(struct device_info_callback *dcb);
+
 int audmgr_open(struct audmgr *am);
 int audmgr_close(struct audmgr *am);
 int audmgr_enable(struct audmgr *am, struct audmgr_config *cfg);
 int audmgr_disable(struct audmgr *am);
-
-typedef void (*audpp_event_func)(void *private, unsigned id, uint16_t *msg);
-typedef void (*audrec_event_func)(void *private, unsigned id, uint16_t *msg);
-
-/* worst case delay of 1sec for response */
-#define MSM_AUD_DECODER_WAIT_MS 1000
-#define MSM_AUD_MODE_TUNNEL  0x00000100
-#define MSM_AUD_MODE_NONTUNNEL  0x00000200
-#define MSM_AUD_DECODER_MASK  0x0000FFFF
-#define MSM_AUD_OP_MASK  0xFFFF0000
-
-/*Playback mode*/
-#define NON_TUNNEL_MODE_PLAYBACK 1
-#define TUNNEL_MODE_PLAYBACK 0
-
-enum msm_aud_decoder_state {
-	MSM_AUD_DECODER_STATE_NONE = 0,
-	MSM_AUD_DECODER_STATE_FAILURE = 1,
-	MSM_AUD_DECODER_STATE_SUCCESS = 2,
-	MSM_AUD_DECODER_STATE_CLOSE = 3,
-};
-
-int audpp_adec_alloc(unsigned dec_attrb, const char **module_name,
-			unsigned *queueid);
-void audpp_adec_free(int decid);
-
-struct audpp_event_callback {
-	audpp_event_func fn;
-	void *private;
-};
-
-int audpp_register_event_callback(struct audpp_event_callback *eh);
-int audpp_unregister_event_callback(struct audpp_event_callback *eh);
-int is_audpp_enable(void);
-
-int audpp_enable(int id, audpp_event_func func, void *private);
-void audpp_disable(int id, void *private);
-
-int audpp_send_queue1(void *cmd, unsigned len);
-int audpp_send_queue2(void *cmd, unsigned len);
-int audpp_send_queue3(void *cmd, unsigned len);
-
-int audpp_set_volume_and_pan(unsigned id, unsigned volume, int pan);
-int audpp_pause(unsigned id, int pause);
-int audpp_flush(unsigned id);
-void audpp_avsync(int id, unsigned rate);
-unsigned audpp_avsync_sample_count(int id);
-unsigned audpp_avsync_byte_count(int id);
-int audpp_dsp_set_mbadrc(unsigned id, unsigned enable,
-			audpp_cmd_cfg_object_params_mbadrc *mbadrc);
-int audpp_dsp_set_eq(unsigned id, unsigned enable,
-			audpp_cmd_cfg_object_params_eqalizer *eq);
-int audpp_dsp_set_rx_iir(unsigned id, unsigned enable,
-				audpp_cmd_cfg_object_params_pcm *iir);
-
-int audpp_dsp_set_rx_srs_trumedia_g
-	(struct audpp_cmd_cfg_object_params_srstm_g *srstm);
-int audpp_dsp_set_rx_srs_trumedia_w
-	(struct audpp_cmd_cfg_object_params_srstm_w *srstm);
-int audpp_dsp_set_rx_srs_trumedia_c
-	(struct audpp_cmd_cfg_object_params_srstm_c *srstm);
-int audpp_dsp_set_rx_srs_trumedia_h
-	(struct audpp_cmd_cfg_object_params_srstm_h *srstm);
-int audpp_dsp_set_rx_srs_trumedia_p
-	(struct audpp_cmd_cfg_object_params_srstm_p *srstm);
-int audpp_dsp_set_rx_srs_trumedia_l
-	(struct audpp_cmd_cfg_object_params_srstm_l *srstm);
-
-int audpp_dsp_set_vol_pan(unsigned id,
-				audpp_cmd_cfg_object_params_volume *vol_pan);
-int audpp_dsp_set_qconcert_plus(unsigned id, unsigned enable,
-			audpp_cmd_cfg_object_params_qconcert *qconcert_plus);
-int audrectask_enable(unsigned enc_type, audrec_event_func func, void *private);
-void audrectask_disable(unsigned enc_type, void *private);
-
-int audrectask_send_cmdqueue(void *cmd, unsigned len);
-int audrectask_send_bitstreamqueue(void *cmd, unsigned len);
-
 #endif
diff --git a/arch/arm/mach-msm/qdsp5/audmgr_new.h b/arch/arm/mach-msm/qdsp5/audmgr_new.h
index 3604405..20e27f1 100644
--- a/arch/arm/mach-msm/qdsp5/audmgr_new.h
+++ b/arch/arm/mach-msm/qdsp5/audmgr_new.h
@@ -1,6 +1,6 @@
 /* arch/arm/mach-msm/qdsp5/audmgr.h
  *
- * Copyright 2008 (c) Code Aurora Forum. All rights reserved.
+ * Copyright 2008,2012 (c) Code Aurora Forum. All rights reserved.
  * Copyright (C) 2008 Google, Inc.
  *
  * This software is licensed under the terms of the GNU General Public
@@ -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,
 };
 
@@ -193,21 +194,4 @@
 int audmgr_close(struct audmgr *am);
 int audmgr_enable(struct audmgr *am, struct audmgr_config *cfg);
 int audmgr_disable(struct audmgr *am);
-
-typedef void (*audpp_event_func)(void *private, unsigned id, uint16_t *msg);
-
-int audpp_enable(int id, audpp_event_func func, void *private);
-void audpp_disable(int id, void *private);
-
-int audpp_send_queue1(void *cmd, unsigned len);
-int audpp_send_queue2(void *cmd, unsigned len);
-int audpp_send_queue3(void *cmd, unsigned len);
-
-int audpp_set_volume_and_pan(unsigned id, unsigned volume, int pan);
-int audpp_pause(unsigned id, int pause);
-int audpp_flush(unsigned id);
-void audpp_avsync(int id, unsigned rate);
-unsigned audpp_avsync_sample_count(int id);
-unsigned audpp_avsync_byte_count(int id);
-
 #endif
diff --git a/arch/arm/mach-msm/qdsp5/audpp.c b/arch/arm/mach-msm/qdsp5/audpp.c
index 1616ad0..b4ead5c 100644
--- a/arch/arm/mach-msm/qdsp5/audpp.c
+++ b/arch/arm/mach-msm/qdsp5/audpp.c
@@ -34,6 +34,8 @@
 
 #include <mach/qdsp5/qdsp5audppcmdi.h>
 #include <mach/qdsp5/qdsp5audppmsg.h>
+#include <mach/qdsp5/qdsp5audpp.h>
+#include <mach/qdsp5v2/audio_acdbi.h>
 #include <mach/debug_mm.h>
 
 #include "evlog.h"
@@ -85,19 +87,7 @@
 #define AUDPP_CMD_IIR_FLAG_DIS	  0x0000
 #define AUDPP_CMD_IIR_FLAG_ENA	  -1
 
-#define AUDPP_CMD_VOLUME_PAN		0
-#define AUDPP_CMD_IIR_TUNING_FILTER	1
-#define AUDPP_CMD_EQUALIZER		2
-#define AUDPP_CMD_ADRC			3
-#define AUDPP_CMD_SPECTROGRAM		4
-#define AUDPP_CMD_QCONCERT		5
-#define AUDPP_CMD_SIDECHAIN_TUNING_FILTER	6
-#define AUDPP_CMD_SAMPLING_FREQUENCY	7
-#define AUDPP_CMD_QAFX			8
-#define AUDPP_CMD_QRUMBLE		9
-#define AUDPP_CMD_MBADRC		10
-
-#define MAX_EVENT_CALLBACK_CLIENTS 	1
+#define MAX_EVENT_CALLBACK_CLIENTS	2
 
 #define AUDPP_CONCURRENCY_DEFAULT 6	/* All non tunnel mode */
 #define AUDPP_MAX_DECODER_CNT 5
@@ -335,6 +325,11 @@
 	case ADSP_MESSAGE_ID:
 		MM_DBG("Received ADSP event: module enable/disable(audpptask)");
 		break;
+	case AUDPP_MSG_FEAT_QUERY_DM_DONE:
+		MM_INFO(" RTC ACK --> %x %x %x\n", msg[0],\
+			msg[1], msg[2]);
+		acdb_rtc_set_err(msg[2]);
+		break;
 	default:
 		MM_ERR("unhandled msg id %x\n", id);
 	}
diff --git a/arch/arm/mach-msm/qdsp5/audpreproc.c b/arch/arm/mach-msm/qdsp5/audpreproc.c
index 230429f..92e54f8 100644
--- a/arch/arm/mach-msm/qdsp5/audpreproc.c
+++ b/arch/arm/mach-msm/qdsp5/audpreproc.c
@@ -1,7 +1,7 @@
 /*
  * Common code to deal with the AUDPREPROC dsp task (audio preprocessing)
  *
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * Based on the audpp layer in arch/arm/mach-msm/qdsp5/audpp.c
  *
@@ -23,6 +23,8 @@
 #include <mach/debug_mm.h>
 #include <mach/qdsp5/qdsp5audpreproc.h>
 #include <mach/qdsp5/qdsp5audreccmdi.h>
+#include <mach/qdsp5v2/audio_acdbi.h>
+
 
 static DEFINE_MUTEX(audpreproc_lock);
 
@@ -56,6 +58,9 @@
 		(1<<AUDREC_CMD_TYPE_0_INDEX_QCELP))
 #endif
 
+#define MAX_ENC_COUNT 2
+#define MAX_EVENT_CALLBACK_CLIENTS 2
+
 struct msm_adspenc_database {
 	unsigned num_enc;
 	struct msm_adspenc_info *enc_info_list;
@@ -90,15 +95,237 @@
 
 struct audpreproc_state {
 	struct msm_adsp_module *mod;
+	audpreproc_event_func func[MAX_ENC_COUNT];
+	void *private[MAX_ENC_COUNT];
 	struct mutex *lock;
 	unsigned open_count;
 	unsigned enc_inuse;
+	struct audpreproc_event_callback *cb_tbl[MAX_EVENT_CALLBACK_CLIENTS];
 };
 
+static struct audrec_session_info session_info;
+
 static struct audpreproc_state the_audpreproc_state = {
 	.lock = &audpreproc_lock,
 };
 
+/* DSP preproc event handler */
+static void audpreproc_dsp_event(void *data, unsigned id, size_t len,
+			    void (*getevent)(void *ptr, size_t len))
+{
+	struct audpreproc_state *audpreproc = data;
+	uint16_t msg[2];
+	MM_ERR("audpreproc_dsp_event %id", id);
+
+	getevent(msg, sizeof(msg));
+
+	switch (id) {
+	case AUDPREPROC_MSG_CMD_CFG_DONE_MSG:
+		MM_DBG("type %d, status_flag %d\n", msg[0], msg[1]);
+		if (audpreproc->func[0])
+			audpreproc->func[0](
+			audpreproc->private[0], id,
+			&msg);
+		break;
+	case AUDPREPROC_MSG_ERROR_MSG_ID:
+		MM_INFO("err_index %d\n", msg[0]);
+		if (audpreproc->func[0])
+			audpreproc->func[0](
+			audpreproc->private[0], id,
+			&msg);
+		break;
+	case ADSP_MESSAGE_ID:
+		MM_DBG("Received ADSP event: module enable(audpreproctask)\n");
+		if (audpreproc->func[0])
+			audpreproc->func[0](
+			audpreproc->private[0], id,
+			&msg);
+		break;
+	case AUDPREPROC_MSG_FEAT_QUERY_DM_DONE:
+	   {
+	    uint16_t msg[3];
+	    getevent(msg, sizeof(msg));
+	    MM_INFO("RTC ACK --> %x %x %x\n", msg[0], msg[1], msg[2]);
+	    acdb_rtc_set_err(msg[2]);
+	   }
+	break;
+	default:
+		MM_ERR("unknown event %d\n", id);
+	}
+	return;
+}
+
+static struct msm_adsp_ops adsp_ops = {
+	.event = audpreproc_dsp_event,
+};
+
+/* EXPORTED API's */
+int audpreproc_enable(int enc_id, audpreproc_event_func func, void *private)
+{
+	struct audpreproc_state *audpreproc = &the_audpreproc_state;
+	int res = 0;
+	uint16_t msg[2];
+	int n = 0;
+	MM_DBG("audpreproc_enable %d\n", enc_id);
+
+	if (enc_id < 0 || enc_id > (MAX_ENC_COUNT - 1))
+		return -EINVAL;
+
+	mutex_lock(audpreproc->lock);
+	if (audpreproc->func[enc_id]) {
+		res = -EBUSY;
+		goto out;
+	}
+
+	audpreproc->func[enc_id] = func;
+	audpreproc->private[enc_id] = private;
+
+	/* First client to enable preproc task */
+	if (audpreproc->open_count++ == 0) {
+		MM_DBG("Get AUDPREPROCTASK\n");
+		res = msm_adsp_get("AUDPREPROCTASK", &audpreproc->mod,
+				&adsp_ops, audpreproc);
+		if (res < 0) {
+			MM_ERR("Can not get AUDPREPROCTASK\n");
+			audpreproc->open_count = 0;
+			audpreproc->func[enc_id] = NULL;
+			audpreproc->private[enc_id] = NULL;
+			goto out;
+		}
+		if (msm_adsp_enable(audpreproc->mod)) {
+			audpreproc->open_count = 0;
+			audpreproc->func[enc_id] = NULL;
+			audpreproc->private[enc_id] = NULL;
+			msm_adsp_put(audpreproc->mod);
+			audpreproc->mod = NULL;
+			res = -ENODEV;
+			goto out;
+		}
+	}
+	msg[0] = AUDPREPROC_MSG_STATUS_FLAG_ENA;
+	/* Generate audpre enabled message for registered clients */
+	for (n = 0; n < MAX_EVENT_CALLBACK_CLIENTS; ++n) {
+			if (audpreproc->cb_tbl[n] &&
+					audpreproc->cb_tbl[n]->fn) {
+				audpreproc->cb_tbl[n]->fn( \
+						audpreproc->cb_tbl[n]->private,\
+						AUDPREPROC_MSG_CMD_CFG_DONE_MSG,
+						(void *) &msg);
+			}
+	}
+	res = 0;
+out:
+	mutex_unlock(audpreproc->lock);
+	return res;
+}
+EXPORT_SYMBOL(audpreproc_enable);
+
+
+void audpreproc_disable(int enc_id, void *private)
+{
+	struct audpreproc_state *audpreproc = &the_audpreproc_state;
+	uint16_t msg[2];
+	int n = 0;
+
+	if (enc_id < 0 || enc_id > (MAX_ENC_COUNT - 1))
+		return;
+
+	mutex_lock(audpreproc->lock);
+	if (!audpreproc->func[enc_id])
+		goto out;
+	if (audpreproc->private[enc_id] != private)
+		goto out;
+
+	audpreproc->func[enc_id] = NULL;
+	audpreproc->private[enc_id] = NULL;
+
+	/* Last client then disable preproc task */
+	if (--audpreproc->open_count == 0) {
+		msm_adsp_disable(audpreproc->mod);
+		MM_DBG("Put AUDPREPROCTASK\n");
+		msm_adsp_put(audpreproc->mod);
+		audpreproc->mod = NULL;
+	}
+	msg[0] = AUDPREPROC_MSG_STATUS_FLAG_DIS;
+	/* Generate audpre enabled message for registered clients */
+	for (n = 0; n < MAX_EVENT_CALLBACK_CLIENTS; ++n) {
+			if (audpreproc->cb_tbl[n] &&
+					audpreproc->cb_tbl[n]->fn) {
+				audpreproc->cb_tbl[n]->fn( \
+						audpreproc->cb_tbl[n]->private,\
+						AUDPREPROC_MSG_CMD_CFG_DONE_MSG,
+						(void *) &msg);
+			}
+	}
+out:
+	mutex_unlock(audpreproc->lock);
+	return;
+}
+EXPORT_SYMBOL(audpreproc_disable);
+
+int audpreproc_update_audrec_info(
+			struct audrec_session_info *audrec_session_info)
+{
+	if (!audrec_session_info) {
+		MM_ERR("error in audrec session info address\n");
+		return -EINVAL;
+	}
+	if (audrec_session_info->session_id < MAX_ENC_COUNT) {
+		memcpy(&session_info,
+				audrec_session_info,
+				sizeof(struct audrec_session_info));
+		return 0;
+	}
+	return -EINVAL;
+}
+EXPORT_SYMBOL(audpreproc_update_audrec_info);
+
+int get_audrec_session_info(struct audrec_session_info *info)
+{
+	if (!info) {
+		MM_ERR("error in audrec session info address\n");
+		return -EINVAL;
+	}
+
+	if (the_audpreproc_state.open_count == 0) {
+		MM_ERR("No aud pre session active\n");
+		return -EINVAL;
+	}
+
+	memcpy(info, &session_info, sizeof(struct audrec_session_info));
+
+	return 0;
+}
+EXPORT_SYMBOL(get_audrec_session_info);
+
+int audpreproc_register_event_callback(struct audpreproc_event_callback *ecb)
+{
+	struct audpreproc_state *audpreproc = &the_audpreproc_state;
+	int i;
+
+	for (i = 0; i < MAX_EVENT_CALLBACK_CLIENTS; ++i) {
+		if (NULL == audpreproc->cb_tbl[i]) {
+			audpreproc->cb_tbl[i] = ecb;
+			return 0;
+		}
+	}
+	return -EINVAL;
+}
+EXPORT_SYMBOL(audpreproc_register_event_callback);
+
+int audpreproc_unregister_event_callback(struct audpreproc_event_callback *ecb)
+{
+	struct audpreproc_state *audpreproc = &the_audpreproc_state;
+	int i;
+
+	for (i = 0; i < MAX_EVENT_CALLBACK_CLIENTS; ++i) {
+		if (ecb == audpreproc->cb_tbl[i]) {
+			audpreproc->cb_tbl[i] = NULL;
+			return 0;
+		}
+	}
+	return -EINVAL;
+}
 /* enc_type = supported encode format *
  * like pcm, aac, sbc, evrc, qcelp, amrnb etc ... *
  */
@@ -167,3 +394,37 @@
 
 }
 EXPORT_SYMBOL(audpreproc_aenc_free);
+
+int audpreproc_dsp_set_agc(
+		audpreproc_cmd_cfg_agc_params *agc_cfg,
+		unsigned len)
+{
+	return msm_adsp_write(the_audpreproc_state.mod,
+			QDSP_uPAudPreProcCmdQueue, agc_cfg, len);
+}
+EXPORT_SYMBOL(audpreproc_dsp_set_agc);
+
+int audpreproc_dsp_set_ns(
+	audpreproc_cmd_cfg_ns_params *ns_cfg,
+	unsigned len)
+{
+	return msm_adsp_write(the_audpreproc_state.mod,
+			QDSP_uPAudPreProcCmdQueue, ns_cfg, len);
+}
+EXPORT_SYMBOL(audpreproc_dsp_set_ns);
+
+int audpreproc_dsp_set_iir(
+		audpreproc_cmd_cfg_iir_tuning_filter_params *iir_cfg,
+		unsigned len)
+{
+	return msm_adsp_write(the_audpreproc_state.mod,
+			QDSP_uPAudPreProcCmdQueue, iir_cfg, len);
+}
+EXPORT_SYMBOL(audpreproc_dsp_set_iir);
+
+int audpreproc_send_preproccmdqueue(void *cmd, unsigned len)
+{
+	return msm_adsp_write(the_audpreproc_state.mod,
+			QDSP_uPAudPreProcCmdQueue, cmd, len);
+}
+EXPORT_SYMBOL(audpreproc_send_preproccmdqueue);
diff --git a/arch/arm/mach-msm/qdsp5/audrec.c b/arch/arm/mach-msm/qdsp5/audrec.c
index d5cb168..e238e32 100644
--- a/arch/arm/mach-msm/qdsp5/audrec.c
+++ b/arch/arm/mach-msm/qdsp5/audrec.c
@@ -2,7 +2,7 @@
  *
  * common code to deal with the AUDREC dsp task (audio recording)
  *
- * Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009,2012 Code Aurora Forum. All rights reserved.
  *
  * Based on the audpp layer in arch/arm/mach-msm/qdsp5/audpp.c
  *
@@ -34,6 +34,7 @@
 
 #include <mach/qdsp5/qdsp5audreccmdi.h>
 #include <mach/qdsp5/qdsp5audrecmsg.h>
+#include <mach/qdsp5/qdsp5audpreproc.h>
 
 #include "audmgr.h"
 #include <mach/debug_mm.h>
diff --git a/arch/arm/mach-msm/qdsp5/snd_cad.c b/arch/arm/mach-msm/qdsp5/snd_cad.c
new file mode 100644
index 0000000..c0efa3b
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/snd_cad.c
@@ -0,0 +1,607 @@
+/* arch/arm/mach-msm/qdsp5/snd_cad.c
+ *
+ * interface to "snd" service on the baseband cpu
+ * This code also borrows from snd.c, which is
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2009, 2012 Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/delay.h>
+#include <linux/msm_audio.h>
+#include <linux/seq_file.h>
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include <mach/board.h>
+#include <mach/msm_rpcrouter.h>
+#include <mach/debug_mm.h>
+#include <linux/debugfs.h>
+
+struct snd_cad_ctxt {
+	struct mutex lock;
+	int opened;
+	struct msm_rpc_endpoint *ept;
+	struct msm_cad_endpoints *cad_epts;
+};
+
+struct snd_cad_sys_ctxt {
+	struct mutex lock;
+	struct msm_rpc_endpoint *ept;
+};
+
+struct snd_curr_dev_info {
+	int rx_dev;
+	int tx_dev;
+};
+
+static struct snd_cad_sys_ctxt the_snd_cad_sys;
+
+static struct snd_cad_ctxt the_snd;
+static struct snd_curr_dev_info curr_dev;
+
+#define RPC_SND_PROG	0x30000002
+#define RPC_SND_CB_PROG	0x31000002
+
+#define RPC_SND_VERS	0x00030003
+
+#define SND_CAD_SET_DEVICE_PROC 40
+#define SND_CAD_SET_VOLUME_PROC 39
+#define MAX_SND_ACTIVE_DEVICE 2
+
+struct rpc_cad_set_device_args {
+	struct cad_devices_type device;
+	uint32_t ear_mute;
+	uint32_t mic_mute;
+
+	uint32_t cb_func;
+	uint32_t client_data;
+};
+
+struct rpc_cad_set_volume_args {
+	struct cad_devices_type device;
+	uint32_t method;
+	uint32_t volume;
+
+	uint32_t cb_func;
+	uint32_t client_data;
+};
+
+struct snd_cad_set_device_msg {
+	struct rpc_request_hdr hdr;
+	struct rpc_cad_set_device_args args;
+};
+
+struct snd_cad_set_volume_msg {
+	struct rpc_request_hdr hdr;
+	struct rpc_cad_set_volume_args args;
+};
+
+struct cad_endpoint *get_cad_endpoints(int *size);
+
+#ifdef CONFIG_DEBUG_FS
+static struct dentry *dentry;
+
+static int rtc_getdevice_dbg_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	MM_INFO("debug intf %s\n", (char *) file->private_data);
+	return 0;
+}
+
+static ssize_t rtc_getdevice_dbg_read(struct file *file, char __user *buf,
+			  size_t count, loff_t *ppos)
+{
+	int n = 0;
+	static char *buffer;
+	static char *swap_buf;
+	const int debug_bufmax = 1024;
+	int swap_count = 0;
+	int rc = 0;
+	int dev_count = 0;
+	int dev_id = 0;
+	struct msm_cad_endpoints *msm_cad_epts = the_snd.cad_epts;
+	struct cad_endpoint *cad_epts;
+
+	buffer = kmalloc(sizeof(char) * 1024, GFP_KERNEL);
+	if (buffer == NULL) {
+		MM_ERR("Memory allocation failed for buffer failed\n");
+		return -EFAULT;
+	}
+
+	swap_buf = kmalloc(sizeof(char) * 1024, GFP_KERNEL);
+	if (swap_buf == NULL) {
+		MM_ERR("Memory allocation failed for swap buffer failed\n");
+		kfree(buffer);
+		return -EFAULT;
+	}
+
+	if (msm_cad_epts->num <= 0) {
+		dev_count = 0;
+		n = scnprintf(buffer, debug_bufmax, "DEV_NO:0x%x\n",
+				msm_cad_epts->num);
+	} else {
+		for (dev_id = 0; dev_id < msm_cad_epts->num; dev_id++) {
+			cad_epts = &msm_cad_epts->endpoints[dev_id];
+			if (IS_ERR(cad_epts)) {
+				MM_ERR("invalid snd endpoint for dev_id %d\n",
+					dev_id);
+				rc = PTR_ERR(cad_epts);
+				continue;
+			}
+
+			if ((cad_epts->id != curr_dev.tx_dev) &&
+				(cad_epts->id != curr_dev.rx_dev))
+				continue;
+
+			n += scnprintf(swap_buf + n, debug_bufmax - n,
+					"ACDB_ID:0x%x;CAPB:0x%x\n",
+					cad_epts->id,
+					cad_epts->capability);
+			dev_count++;
+			MM_DBG("RTC Get Device %x Capb %x Dev Count %x\n",
+					dev_id, cad_epts->capability,
+					dev_count);
+
+		}
+	}
+	swap_count = scnprintf(buffer, debug_bufmax, \
+			"DEV_NO:0x%x\n", dev_count);
+
+	memcpy(buffer+swap_count, swap_buf, n*sizeof(char));
+	n = n+swap_count;
+
+	buffer[n] = 0;
+	rc =  simple_read_from_buffer(buf, count, ppos, buffer, n);
+	kfree(buffer);
+	kfree(swap_buf);
+	return rc;
+}
+
+static const struct file_operations rtc_acdb_debug_fops = {
+	.open = rtc_getdevice_dbg_open,
+	.read = rtc_getdevice_dbg_read
+};
+
+static int rtc_debugfs_create_entry(void)
+{
+	int rc = 0;
+	char name[sizeof "rtc_get_device"+1];
+
+	snprintf(name, sizeof name, "rtc_get_device");
+	dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+			NULL, NULL, &rtc_acdb_debug_fops);
+	if (IS_ERR(dentry)) {
+		MM_ERR("debugfs_create_file failed\n");
+		rc = PTR_ERR(dentry);
+	}
+	return rc;
+}
+#else
+static int rtc_debugfs_create_entry()
+{
+	return 0;
+}
+#endif
+
+static inline int check_mute(int mute)
+{
+	return (mute == SND_MUTE_MUTED ||
+		mute == SND_MUTE_UNMUTED) ? 0 : -EINVAL;
+}
+
+static int get_endpoint(struct snd_cad_ctxt *snd, unsigned long arg)
+{
+	int rc = 0, index;
+	struct msm_cad_endpoint ept;
+
+	if (copy_from_user(&ept, (void __user *)arg, sizeof(ept))) {
+		MM_ERR("cad_ioctl get endpoint: invalid read pointer\n");
+		return -EFAULT;
+	}
+
+	index = ept.id;
+	if (index < 0 || index >= snd->cad_epts->num) {
+		MM_ERR("snd_ioctl get endpoint: invalid index!\n");
+		return -EINVAL;
+	}
+
+	ept.id = snd->cad_epts->endpoints[index].id;
+	strlcpy(ept.name,
+		snd->cad_epts->endpoints[index].name,
+		sizeof(ept.name));
+
+	if (copy_to_user((void __user *)arg, &ept, sizeof(ept))) {
+		MM_ERR("snd_ioctl get endpoint: invalid write pointer\n");
+		rc = -EFAULT;
+	}
+
+	return rc;
+}
+
+static long snd_cad_ioctl(struct file *file, unsigned int cmd,
+		unsigned long arg)
+{
+	struct snd_cad_set_device_msg dmsg;
+	struct snd_cad_set_volume_msg vmsg;
+
+	struct msm_cad_device_config dev;
+	struct msm_cad_volume_config vol;
+	struct snd_cad_ctxt *snd = file->private_data;
+	int rc = 0;
+
+	mutex_lock(&snd->lock);
+	switch (cmd) {
+	case SND_SET_DEVICE:
+		if (copy_from_user(&dev, (void __user *) arg, sizeof(dev))) {
+			MM_ERR("set device: invalid pointer\n");
+			rc = -EFAULT;
+			break;
+		}
+
+		dmsg.args.device.rx_device = cpu_to_be32(dev.device.rx_device);
+		dmsg.args.device.tx_device = cpu_to_be32(dev.device.tx_device);
+		dmsg.args.device.pathtype = cpu_to_be32(dev.device.pathtype);
+		dmsg.args.ear_mute = cpu_to_be32(dev.ear_mute);
+		dmsg.args.mic_mute = cpu_to_be32(dev.mic_mute);
+		if (check_mute(dev.ear_mute) < 0 ||
+				check_mute(dev.mic_mute) < 0) {
+			MM_ERR("set device: invalid mute status\n");
+			rc = -EINVAL;
+			break;
+		}
+		dmsg.args.cb_func = -1;
+		dmsg.args.client_data = 0;
+		curr_dev.tx_dev = dev.device.tx_device;
+		curr_dev.rx_dev = dev.device.rx_device;
+		MM_ERR("snd_cad_set_device %d %d %d %d\n", dev.device.rx_device,
+			dev.device.tx_device, dev.ear_mute, dev.mic_mute);
+
+		rc = msm_rpc_call(snd->ept,
+			SND_CAD_SET_DEVICE_PROC,
+			&dmsg, sizeof(dmsg), 5 * HZ);
+		break;
+
+	case SND_SET_VOLUME:
+		if (copy_from_user(&vol, (void __user *) arg, sizeof(vol))) {
+			MM_ERR("set volume: invalid pointer\n");
+			rc = -EFAULT;
+			break;
+		}
+
+		vmsg.args.device.rx_device = cpu_to_be32(dev.device.rx_device);
+		vmsg.args.device.tx_device = cpu_to_be32(dev.device.tx_device);
+		vmsg.args.method = cpu_to_be32(vol.method);
+		if (vol.method != SND_METHOD_VOICE) {
+			MM_ERR("set volume: invalid method\n");
+			rc = -EINVAL;
+			break;
+		}
+
+		vmsg.args.volume = cpu_to_be32(vol.volume);
+		vmsg.args.cb_func = -1;
+		vmsg.args.client_data = 0;
+
+		MM_ERR("snd_cad_set_volume %d %d %d %d\n", vol.device.rx_device,
+				vol.device.tx_device, vol.method, vol.volume);
+
+		rc = msm_rpc_call(snd->ept,
+			SND_CAD_SET_VOLUME_PROC,
+			&vmsg, sizeof(vmsg), 5 * HZ);
+
+		break;
+
+	case SND_GET_NUM_ENDPOINTS:
+		if (copy_to_user((void __user *)arg,
+				&snd->cad_epts->num, sizeof(unsigned))) {
+			MM_ERR("get endpoint: invalid pointer\n");
+			rc = -EFAULT;
+		}
+		break;
+
+	case SND_GET_ENDPOINT:
+		rc = get_endpoint(snd, arg);
+		break;
+
+	default:
+		MM_ERR("unknown command\n");
+		rc = -EINVAL;
+		break;
+	}
+	mutex_unlock(&snd->lock);
+
+	return rc;
+}
+
+static int snd_cad_release(struct inode *inode, struct file *file)
+{
+	struct snd_cad_ctxt *snd = file->private_data;
+	int rc;
+
+	mutex_lock(&snd->lock);
+	rc = msm_rpc_close(snd->ept);
+	if (rc < 0)
+		MM_ERR("msm_rpc_close failed\n");
+	snd->ept = NULL;
+	snd->opened = 0;
+	mutex_unlock(&snd->lock);
+	return 0;
+}
+static int snd_cad_sys_release(void)
+{
+	struct snd_cad_sys_ctxt *snd_cad_sys = &the_snd_cad_sys;
+	int rc = 0;
+
+	mutex_lock(&snd_cad_sys->lock);
+	rc = msm_rpc_close(snd_cad_sys->ept);
+	if (rc < 0)
+		MM_ERR("msm_rpc_close failed\n");
+	snd_cad_sys->ept = NULL;
+	mutex_unlock(&snd_cad_sys->lock);
+	return rc;
+}
+static int snd_cad_open(struct inode *inode, struct file *file)
+{
+	struct snd_cad_ctxt *snd = &the_snd;
+	int rc = 0;
+
+	mutex_lock(&snd->lock);
+	if (snd->opened == 0) {
+		if (snd->ept == NULL) {
+			snd->ept = msm_rpc_connect_compatible(RPC_SND_PROG,
+					RPC_SND_VERS, 0);
+			if (IS_ERR(snd->ept)) {
+				rc = PTR_ERR(snd->ept);
+				snd->ept = NULL;
+				MM_ERR("cad connect failed with VERS %x\n",
+					RPC_SND_VERS);
+				goto err;
+			}
+		}
+		file->private_data = snd;
+		snd->opened = 1;
+	} else {
+		MM_ERR("snd already opened\n");
+		rc = -EBUSY;
+	}
+
+err:
+	mutex_unlock(&snd->lock);
+	return rc;
+}
+static int snd_cad_sys_open(void)
+{
+	struct snd_cad_sys_ctxt *snd_cad_sys = &the_snd_cad_sys;
+	int rc = 0;
+
+	mutex_lock(&snd_cad_sys->lock);
+	if (snd_cad_sys->ept == NULL) {
+		snd_cad_sys->ept = msm_rpc_connect_compatible(RPC_SND_PROG,
+			RPC_SND_VERS, 0);
+		if (IS_ERR(snd_cad_sys->ept)) {
+			rc = PTR_ERR(snd_cad_sys->ept);
+			snd_cad_sys->ept = NULL;
+			MM_ERR("func %s : cad connect failed with VERS %x\n",
+				__func__, RPC_SND_VERS);
+			goto err;
+		}
+	} else
+		MM_DBG("snd already opened\n");
+err:
+	mutex_unlock(&snd_cad_sys->lock);
+	return rc;
+}
+
+static const struct file_operations snd_cad_fops = {
+	.owner		= THIS_MODULE,
+	.open		= snd_cad_open,
+	.release	= snd_cad_release,
+	.unlocked_ioctl	= snd_cad_ioctl,
+};
+
+struct miscdevice snd_cad_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_cad",
+	.fops	= &snd_cad_fops,
+};
+
+static long snd_cad_vol_enable(const char *arg)
+{
+	struct snd_cad_sys_ctxt *snd_cad_sys = &the_snd_cad_sys;
+	struct snd_cad_set_volume_msg vmsg;
+	struct msm_cad_volume_config vol;
+	int rc = 0;
+
+	rc = sscanf(arg, "%d %d %d %d", &vol.device.rx_device,
+			&vol.device.tx_device, &vol.method, &vol.volume);
+	if (rc != 4) {
+		MM_ERR("Invalid arguments. Usage: <rx_device> <tx_device>" \
+			"method> <volume>\n");
+		rc = -EINVAL;
+		return rc;
+	}
+
+	vmsg.args.device.rx_device = cpu_to_be32(vol.device.rx_device);
+	vmsg.args.device.tx_device = cpu_to_be32(vol.device.tx_device);
+	vmsg.args.method = cpu_to_be32(vol.method);
+	if (vol.method != SND_METHOD_VOICE) {
+		MM_ERR("snd_cad_ioctl set volume: invalid method\n");
+		rc = -EINVAL;
+		return rc;
+	}
+
+	vmsg.args.volume = cpu_to_be32(vol.volume);
+	vmsg.args.cb_func = -1;
+	vmsg.args.client_data = 0;
+
+	MM_DBG("snd_cad_set_volume %d %d %d %d\n", vol.device.rx_device,
+			vol.device.rx_device, vol.method, vol.volume);
+
+	rc = msm_rpc_call(snd_cad_sys->ept,
+		SND_CAD_SET_VOLUME_PROC,
+		&vmsg, sizeof(vmsg), 5 * HZ);
+	return rc;
+}
+
+static long snd_cad_dev_enable(const char *arg)
+{
+	struct snd_cad_sys_ctxt *snd_cad_sys = &the_snd_cad_sys;
+	struct snd_cad_set_device_msg dmsg;
+	struct msm_cad_device_config dev;
+	int rc = 0;
+
+
+	rc = sscanf(arg, "%d %d %d %d", &dev.device.rx_device,
+			&dev.device.tx_device, &dev.ear_mute, &dev.mic_mute);
+	if (rc != 4) {
+		MM_ERR("Invalid arguments. Usage: <rx_device> <tx_device> "\
+			"<ear_mute> <mic_mute>\n");
+		rc = -EINVAL;
+		return rc;
+	}
+	dmsg.args.device.rx_device = cpu_to_be32(dev.device.rx_device);
+	dmsg.args.device.tx_device = cpu_to_be32(dev.device.tx_device);
+	dmsg.args.device.pathtype = cpu_to_be32(CAD_DEVICE_PATH_RX_TX);
+	dmsg.args.ear_mute = cpu_to_be32(dev.ear_mute);
+	dmsg.args.mic_mute = cpu_to_be32(dev.mic_mute);
+	if (check_mute(dev.ear_mute) < 0 ||
+			check_mute(dev.mic_mute) < 0) {
+		MM_ERR("snd_cad_ioctl set device: invalid mute status\n");
+		rc = -EINVAL;
+		return rc;
+	}
+	dmsg.args.cb_func = -1;
+	dmsg.args.client_data = 0;
+	curr_dev.tx_dev = dev.device.tx_device;
+	curr_dev.rx_dev = dev.device.rx_device;
+
+	MM_INFO("snd_cad_set_device %d %d %d %d\n", dev.device.rx_device,
+			dev.device.tx_device, dev.ear_mute, dev.mic_mute);
+
+	rc = msm_rpc_call(snd_cad_sys->ept,
+		SND_CAD_SET_DEVICE_PROC,
+		&dmsg, sizeof(dmsg), 5 * HZ);
+	return rc;
+}
+
+static ssize_t snd_cad_dev_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t size)
+{
+	ssize_t status;
+	struct snd_cad_sys_ctxt *snd_cad_sys = &the_snd_cad_sys;
+	int rc = 0;
+
+	rc = snd_cad_sys_open();
+	if (rc)
+		return rc;
+
+	mutex_lock(&snd_cad_sys->lock);
+	status = snd_cad_dev_enable(buf);
+	mutex_unlock(&snd_cad_sys->lock);
+
+	rc = snd_cad_sys_release();
+	if (rc)
+		return rc;
+
+	return status ? : size;
+}
+
+static ssize_t snd_cad_vol_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t size)
+{
+	ssize_t status;
+	struct snd_cad_sys_ctxt *snd_cad_sys = &the_snd_cad_sys;
+	int rc = 0;
+
+	rc = snd_cad_sys_open();
+	if (rc)
+		return rc;
+
+	mutex_lock(&snd_cad_sys->lock);
+	status = snd_cad_vol_enable(buf);
+	mutex_unlock(&snd_cad_sys->lock);
+
+	rc = snd_cad_sys_release();
+	if (rc)
+		return rc;
+
+	return status ? : size;
+}
+
+static DEVICE_ATTR(device, S_IWUSR | S_IRUGO,
+		NULL, snd_cad_dev_store);
+
+static DEVICE_ATTR(volume, S_IWUSR | S_IRUGO,
+		NULL, snd_cad_vol_store);
+
+static int snd_cad_probe(struct platform_device *pdev)
+{
+	struct snd_cad_ctxt *snd = &the_snd;
+	struct snd_cad_sys_ctxt *snd_cad_sys = &the_snd_cad_sys;
+	int rc = 0;
+
+	mutex_init(&snd->lock);
+	mutex_init(&snd_cad_sys->lock);
+	snd_cad_sys->ept = NULL;
+	snd->cad_epts =
+			(struct msm_cad_endpoints *)pdev->dev.platform_data;
+	rc = misc_register(&snd_cad_misc);
+	if (rc)
+		return rc;
+
+	rc = device_create_file(snd_cad_misc.this_device, &dev_attr_device);
+	if (rc) {
+		misc_deregister(&snd_cad_misc);
+		return rc;
+	}
+
+	rc = device_create_file(snd_cad_misc.this_device, &dev_attr_volume);
+	if (rc) {
+		device_remove_file(snd_cad_misc.this_device,
+						&dev_attr_device);
+		misc_deregister(&snd_cad_misc);
+	}
+
+#ifdef CONFIG_DEBUG_FS
+	rc = rtc_debugfs_create_entry();
+	if (rc) {
+		device_remove_file(snd_cad_misc.this_device,
+						&dev_attr_volume);
+		device_remove_file(snd_cad_misc.this_device,
+						&dev_attr_device);
+		misc_deregister(&snd_cad_misc);
+	}
+#endif
+	return rc;
+}
+
+static struct platform_driver snd_cad_plat_driver = {
+	.probe = snd_cad_probe,
+	.driver = {
+		.name = "msm_cad",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init snd_cad_init(void)
+{
+	return platform_driver_register(&snd_cad_plat_driver);
+}
+
+module_init(snd_cad_init);
+
+MODULE_DESCRIPTION("MSM CAD SND driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_amrnb_in.c b/arch/arm/mach-msm/qdsp5v2/audio_amrnb_in.c
index 790c510..2f03cd0 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_amrnb_in.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_amrnb_in.c
@@ -27,7 +27,7 @@
 #include <linux/wait.h>
 #include <linux/dma-mapping.h>
 #include <linux/msm_audio_amrnb.h>
-#include <linux/android_pmem.h>
+#include <linux/msm_ion.h>
 #include <linux/memory_alloc.h>
 
 #include <mach/iommu.h>
@@ -105,6 +105,8 @@
 	int running;
 	int stopped; /* set when stopped, cleared on flush */
 	char *build_id;
+	struct ion_client *client;
+	struct ion_handle *buff_handle;
 };
 
 struct audio_frame {
@@ -766,8 +768,9 @@
 	audio->audrec = NULL;
 	audio->opened = 0;
 	if (audio->data) {
-		iounmap(audio->map_v_read);
-		free_contiguous_memory_by_paddr(audio->phys);
+		ion_unmap_kernel(audio->client, audio->buff_handle);
+		ion_free(audio->client, audio->buff_handle);
+		ion_client_destroy(audio->client);
 		audio->data = NULL;
 	}
 	mutex_unlock(&audio->lock);
@@ -779,27 +782,62 @@
 	struct audio_in *audio = &the_audio_amrnb_in;
 	int rc;
 	int encid;
+	int len = 0;
+	unsigned long ionflag = 0;
+	ion_phys_addr_t addr = 0;
+	struct ion_handle *handle = NULL;
+	struct ion_client *client = NULL;
 
 	mutex_lock(&audio->lock);
 	if (audio->opened) {
 		rc = -EBUSY;
 		goto done;
 	}
-	audio->phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
-	if (audio->phys) {
-		audio->map_v_read = ioremap(audio->phys, DMASZ);
-		if (IS_ERR(audio->map_v_read)) {
-			MM_ERR("could not map DMA buffers\n");
-			rc = -ENOMEM;
-			free_contiguous_memory_by_paddr(audio->phys);
-			goto done;
-		}
-		audio->data = audio->map_v_read;
-	} else {
-		MM_ERR("could not allocate DMA buffers\n");
+
+	client = msm_ion_client_create(UINT_MAX, "Audio_AMR_In_Client");
+	if (IS_ERR_OR_NULL(client)) {
+		MM_ERR("Unable to create ION client\n");
 		rc = -ENOMEM;
-		goto done;
+		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 buff_alloc_error;
+	}
+	audio->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 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 buff_get_flags_error;
+	}
+
+	audio->map_v_read = ion_map_kernel(client, handle, ionflag);
+	if (IS_ERR(audio->map_v_read)) {
+		MM_ERR("could not map write buffers\n");
+		rc = -ENOMEM;
+		goto buff_map_error;
+	}
+	audio->data = audio->map_v_read;
+	MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
+		audio->phys, (int)audio->data);
+
 	MM_DBG("Memory addr = 0x%8x  phy addr = 0x%8x\n",\
 		(int) audio->data, (int) audio->phys);
 	if ((file->f_mode & FMODE_WRITE) &&
@@ -871,6 +909,14 @@
 	msm_adsp_put(audio->audrec);
 	audpreproc_aenc_free(audio->enc_id);
 	mutex_unlock(&audio->lock);
+	ion_unmap_kernel(client, audio->buff_handle);
+buff_map_error:
+buff_get_phys_error:
+buff_get_flags_error:
+	ion_free(client, audio->buff_handle);
+buff_alloc_error:
+	ion_client_destroy(client);
+client_create_error:
 	return rc;
 }
 
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_evrc_in.c b/arch/arm/mach-msm/qdsp5v2/audio_evrc_in.c
index 1ee5029..1180e8d 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_evrc_in.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_evrc_in.c
@@ -27,7 +27,7 @@
 #include <linux/wait.h>
 #include <linux/dma-mapping.h>
 #include <linux/msm_audio_qcp.h>
-#include <linux/android_pmem.h>
+#include <linux/msm_ion.h>
 #include <linux/memory_alloc.h>
 
 #include <mach/msm_adsp.h>
@@ -137,6 +137,9 @@
 	int running;
 	int stopped; /* set when stopped, cleared on flush */
 	char *build_id;
+	struct ion_client *client;
+	struct ion_handle *input_buff_handle;
+	struct ion_handle *output_buff_handle;
 };
 
 struct audio_frame {
@@ -1318,15 +1321,16 @@
 	audio->audrec = NULL;
 	audio->opened = 0;
 	if (audio->data) {
-		iounmap(audio->map_v_read);
-		free_contiguous_memory_by_paddr(audio->phys);
+		ion_unmap_kernel(audio->client, audio->input_buff_handle);
+		ion_free(audio->client, audio->input_buff_handle);
 		audio->data = NULL;
 	}
 	if (audio->out_data) {
-		iounmap(audio->map_v_write);
-		free_contiguous_memory_by_paddr(audio->out_phys);
+		ion_unmap_kernel(audio->client, audio->output_buff_handle);
+		ion_free(audio->client, audio->output_buff_handle);
 		audio->out_data = NULL;
 	}
+	ion_client_destroy(audio->client);
 	mutex_unlock(&audio->lock);
 	return 0;
 }
@@ -1337,27 +1341,65 @@
 	struct audio_in *audio = &the_audio_evrc_in;
 	int rc;
 	int encid;
+	int len = 0;
+	unsigned long ionflag = 0;
+	ion_phys_addr_t addr = 0;
+	struct ion_handle *handle = NULL;
+	struct ion_client *client = NULL;
 
 	mutex_lock(&audio->lock);
 	if (audio->opened) {
 		rc = -EBUSY;
 		goto done;
 	}
-	audio->phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
-	if (audio->phys) {
-		audio->map_v_read = ioremap(audio->phys, DMASZ);
-		if (IS_ERR(audio->map_v_read)) {
-			MM_ERR("failed to map read physical address\n");
-			rc = -ENOMEM;
-			free_contiguous_memory_by_paddr(audio->phys);
-			goto done;
-		}
-		audio->data = audio->map_v_read;
-	} else {
-		MM_ERR("could not allocate DMA buffers\n");
+
+	client = msm_ion_client_create(UINT_MAX, "Audio_EVRC_in_client");
+	if (IS_ERR_OR_NULL(client)) {
+		MM_ERR("Unable to create ION client\n");
 		rc = -ENOMEM;
-		goto done;
+		goto client_create_error;
 	}
+	audio->client = client;
+
+	MM_DBG("allocating mem sz = %d\n", DMASZ);
+	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);
+		rc = -ENOMEM;
+		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");
+		rc = -ENOMEM;
+		goto output_buff_get_flags_error;
+	}
+
+	audio->map_v_read = ion_map_kernel(client, handle, ionflag);
+	if (IS_ERR(audio->map_v_read)) {
+		MM_ERR("could not map read buffers,freeing instance 0x%08x\n",
+				(int)audio);
+		rc = -ENOMEM;
+		goto output_buff_map_error;
+	}
+	audio->data = audio->map_v_read;
+
 	MM_DBG("Memory addr = 0x%8x  phy addr = 0x%8x\n",\
 		(int) audio->data, (int) audio->phys);
 	if ((file->f_mode & FMODE_WRITE) &&
@@ -1414,25 +1456,50 @@
 	audevrc_in_flush(audio);
 	audevrc_out_flush(audio);
 
-	audio->out_phys = allocate_contiguous_ebi_nomap(BUFFER_SIZE,
-								SZ_4K);
-	if (!audio->out_phys) {
-		MM_ERR("could not allocate write buffers\n");
+	MM_DBG("allocating BUFFER_SIZE  %d\n", BUFFER_SIZE);
+	handle = ion_alloc(client, BUFFER_SIZE,
+			SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+	if (IS_ERR_OR_NULL(handle)) {
+		MM_ERR("Unable to create allocate I/P buffers\n");
 		rc = -ENOMEM;
-		goto evt_error;
-	} else {
-		audio->map_v_write = ioremap(audio->out_phys, BUFFER_SIZE);
-		if (IS_ERR(audio->map_v_write)) {
-			MM_ERR("could map write buffers\n");
-			rc = -ENOMEM;
-			free_contiguous_memory_by_paddr(audio->out_phys);
-			goto evt_error;
-		}
-		audio->out_data = audio->map_v_write;
-		MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
-				audio->out_phys, (int)audio->out_data);
+		goto input_buff_alloc_error;
 	}
 
+	audio->input_buff_handle = handle;
+
+	rc = ion_phys(client , handle, &addr, &len);
+	if (rc) {
+		MM_ERR("I/P buffers:Invalid phy: %x sz: %x\n",
+			(unsigned int) addr, (unsigned int) len);
+		rc = -ENOMEM;
+		goto input_buff_alloc_error;
+	} else {
+		MM_INFO("Got valid phy: %x sz: %x\n",
+			(unsigned int) addr,
+			(unsigned int) len);
+	}
+	audio->out_phys = (int32_t)addr;
+
+	rc = ion_handle_get_flags(client,
+		handle, &ionflag);
+	if (rc) {
+		MM_ERR("could not get flags for the handle\n");
+		rc = -ENOMEM;
+		goto input_buff_alloc_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\n");
+		rc = -ENOMEM;
+		goto input_buff_map_error;
+	}
+	audio->out_data = audio->map_v_write;
+	MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
+				(unsigned int)addr,
+				(unsigned int)audio->out_data);
+
 		/* Initialize buffer */
 	audio->out[0].data = audio->out_data + 0;
 	audio->out[0].addr = audio->out_phys + 0;
@@ -1472,6 +1539,17 @@
 	msm_adsp_put(audio->audrec);
 	audpreproc_aenc_free(audio->enc_id);
 	mutex_unlock(&audio->lock);
+input_buff_map_error:
+	ion_free(client, audio->input_buff_handle);
+input_buff_alloc_error:
+	ion_unmap_kernel(client, audio->output_buff_handle);
+output_buff_map_error:
+output_buff_get_phys_error:
+output_buff_get_flags_error:
+	ion_free(client, audio->output_buff_handle);
+output_buff_alloc_error:
+	ion_client_destroy(client);
+client_create_error:
 	return rc;
 }
 
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c b/arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c
index e1af2ad..7fac2ea 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c
@@ -27,7 +27,7 @@
 #include <linux/wait.h>
 #include <linux/dma-mapping.h>
 #include <linux/msm_audio_qcp.h>
-#include <linux/android_pmem.h>
+#include <linux/msm_ion.h>
 #include <linux/memory_alloc.h>
 
 #include <mach/msm_adsp.h>
@@ -140,6 +140,9 @@
 	int running;
 	int stopped; /* set when stopped, cleared on flush */
 	char *build_id;
+	struct ion_client *client;
+	struct ion_handle *input_buff_handle;
+	struct ion_handle *output_buff_handle;
 };
 
 struct audio_frame {
@@ -1324,15 +1327,16 @@
 	audio->audrec = NULL;
 	audio->opened = 0;
 	if (audio->data) {
-		iounmap(audio->map_v_read);
-		free_contiguous_memory_by_paddr(audio->phys);
+		ion_unmap_kernel(audio->client, audio->input_buff_handle);
+		ion_free(audio->client, audio->input_buff_handle);
 		audio->data = NULL;
 	}
 	if (audio->out_data) {
-		iounmap(audio->map_v_write);
-		free_contiguous_memory_by_paddr(audio->out_phys);
+		ion_unmap_kernel(audio->client, audio->output_buff_handle);
+		ion_free(audio->client, audio->output_buff_handle);
 		audio->out_data = NULL;
 	}
+	ion_client_destroy(audio->client);
 	mutex_unlock(&audio->lock);
 	return 0;
 }
@@ -1343,27 +1347,64 @@
 	struct audio_in *audio = &the_audio_qcelp_in;
 	int rc;
 	int encid;
+	int len = 0;
+	unsigned long ionflag = 0;
+	ion_phys_addr_t addr = 0;
+	struct ion_handle *handle = NULL;
+	struct ion_client *client = NULL;
 
 	mutex_lock(&audio->lock);
 	if (audio->opened) {
 		rc = -EBUSY;
 		goto done;
 	}
-	audio->phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
-	if (audio->phys) {
-		audio->map_v_read = ioremap(audio->phys, DMASZ);
-		if (IS_ERR(audio->map_v_read)) {
-			MM_ERR("could not map DMA buffers\n");
-			rc = -ENOMEM;
-			free_contiguous_memory_by_paddr(audio->phys);
-			goto done;
-		}
-		audio->data = audio->map_v_read;
-	} else {
-		MM_ERR("could not allocate DMA buffers\n");
+	client = msm_ion_client_create(UINT_MAX, "Audio_EVRC_in_client");
+	if (IS_ERR_OR_NULL(client)) {
+		MM_ERR("Unable to create ION client\n");
 		rc = -ENOMEM;
-		goto done;
+		goto client_create_error;
 	}
+	audio->client = client;
+
+	MM_DBG("allocating mem sz = %d\n", DMASZ);
+	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);
+		rc = -ENOMEM;
+		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");
+		rc = -ENOMEM;
+		goto output_buff_get_flags_error;
+	}
+
+	audio->map_v_read = ion_map_kernel(client, handle, ionflag);
+	if (IS_ERR(audio->map_v_read)) {
+		MM_ERR("could not map read buffers,freeing instance 0x%08x\n",
+				(int)audio);
+		rc = -ENOMEM;
+		goto output_buff_map_error;
+	}
+	audio->data = audio->map_v_read;
+
 	MM_DBG("Memory addr = 0x%8x  phy addr = 0x%8x\n",\
 		(int) audio->data, (int) audio->phys);
 	if ((file->f_mode & FMODE_WRITE) &&
@@ -1422,24 +1463,50 @@
 	audqcelp_in_flush(audio);
 	audqcelp_out_flush(audio);
 
-	audio->out_phys = allocate_contiguous_ebi_nomap(BUFFER_SIZE, SZ_4K);
-	if (!audio->out_phys) {
-		MM_ERR("could not allocate write buffers\n");
+	MM_DBG("allocating BUFFER_SIZE  %d\n", BUFFER_SIZE);
+	handle = ion_alloc(client, BUFFER_SIZE,
+			SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+	if (IS_ERR_OR_NULL(handle)) {
+		MM_ERR("Unable to create allocate I/P buffers\n");
 		rc = -ENOMEM;
-		goto evt_error;
-	} else {
-		audio->map_v_write = ioremap(audio->out_phys, BUFFER_SIZE);
-		if (IS_ERR(audio->map_v_write)) {
-			MM_ERR("could not map write buffers\n");
-			rc = -ENOMEM;
-			free_contiguous_memory_by_paddr(audio->out_phys);
-			goto evt_error;
-		}
-		audio->out_data = audio->map_v_write;
-		MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
-				audio->out_phys, (int)audio->out_data);
+		goto input_buff_alloc_error;
 	}
 
+	audio->input_buff_handle = handle;
+
+	rc = ion_phys(client , handle, &addr, &len);
+	if (rc) {
+		MM_ERR("I/P buffers:Invalid phy: %x sz: %x\n",
+			(unsigned int) addr, (unsigned int) len);
+		rc = -ENOMEM;
+		goto input_buff_alloc_error;
+	} else {
+		MM_INFO("Got valid phy: %x sz: %x\n",
+			(unsigned int) addr,
+			(unsigned int) len);
+	}
+	audio->out_phys = (int32_t)addr;
+
+	rc = ion_handle_get_flags(client,
+		handle, &ionflag);
+	if (rc) {
+		MM_ERR("could not get flags for the handle\n");
+		rc = -ENOMEM;
+		goto input_buff_alloc_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\n");
+		rc = -ENOMEM;
+		goto input_buff_map_error;
+	}
+	audio->out_data = audio->map_v_write;
+	MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
+				(unsigned int)addr,
+				(unsigned int)audio->out_data);
+
 		/* Initialize buffer */
 	audio->out[0].data = audio->out_data + 0;
 	audio->out[0].addr = audio->out_phys + 0;
@@ -1478,6 +1545,17 @@
 	msm_adsp_put(audio->audrec);
 	audpreproc_aenc_free(audio->enc_id);
 	mutex_unlock(&audio->lock);
+input_buff_map_error:
+	ion_free(client, audio->input_buff_handle);
+input_buff_alloc_error:
+	ion_unmap_kernel(client, audio->output_buff_handle);
+output_buff_map_error:
+output_buff_get_phys_error:
+output_buff_get_flags_error:
+	ion_free(client, audio->output_buff_handle);
+output_buff_alloc_error:
+	ion_client_destroy(client);
+client_create_error:
 	return rc;
 }
 
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_wma.c b/arch/arm/mach-msm/qdsp5v2/audio_wma.c
index 80adebd..4ba5821 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_wma.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_wma.c
@@ -35,12 +35,11 @@
 #include <linux/delay.h>
 #include <linux/list.h>
 #include <linux/earlysuspend.h>
-#include <linux/android_pmem.h>
 #include <linux/slab.h>
 #include <linux/msm_audio.h>
 #include <linux/msm_audio_wma.h>
 #include <linux/memory_alloc.h>
-#include <mach/qdsp5v2/audio_dev_ctl.h>
+#include <linux/msm_ion.h>
 
 #include <mach/msm_adsp.h>
 #include <mach/iommu.h>
@@ -190,6 +189,9 @@
 	int eq_needs_commit;
 	struct audpp_cmd_cfg_object_params_eqalizer eq;
 	struct 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);
@@ -814,6 +816,10 @@
 	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);
 
@@ -1052,24 +1058,54 @@
 				MM_DBG("allocate PCM buffer %d\n",
 						config.buffer_count *
 						config.buffer_size);
-				audio->read_phys =
-						allocate_contiguous_ebi_nomap(
-							config.buffer_size *
-							config.buffer_count,
-							SZ_4K);
-				if (!audio->read_phys) {
+				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->map_v_read = ioremap(
-							audio->read_phys,
-							config.buffer_size *
-							config.buffer_count);
-				if (IS_ERR(audio->map_v_read)) {
-					MM_ERR("read buf alloc fail\n");
+
+				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;
-					free_contiguous_memory_by_paddr(
-							audio->read_phys);
+					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;
@@ -1455,12 +1491,13 @@
 	audio->event_abort = 1;
 	wake_up(&audio->event_wait);
 	audwma_reset_event_queue(audio);
-	iounmap(audio->map_v_write);
-	free_contiguous_memory_by_paddr(audio->phys);
-	if (audio->read_data) {
-		iounmap(audio->map_v_read);
-		free_contiguous_memory_by_paddr(audio->read_phys);
+	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)
@@ -1601,8 +1638,13 @@
 {
 	struct audio *audio = NULL;
 	int rc, dec_attrb, decid, i;
-	unsigned pmem_sz = DMASZ_MAX;
+	unsigned mem_sz = DMASZ_MAX;
 	struct audwma_event *e_node = NULL;
+	unsigned long ionflag = 0;
+	ion_phys_addr_t addr = 0;
+	struct ion_handle *handle = NULL;
+	struct ion_client *client = NULL;
+	int len = 0;
 #ifdef CONFIG_DEBUG_FS
 	/* 4 bytes represents decoder number, 1 byte for terminate string */
 	char name[sizeof "msm_wma_" + 5];
@@ -1645,36 +1687,52 @@
 	}
 	audio->dec_id = decid & MSM_AUD_DECODER_MASK;
 
-	while (pmem_sz >= DMASZ_MIN) {
-		MM_DBG("pmemsz = %d\n", pmem_sz);
-		audio->phys = allocate_contiguous_ebi_nomap(pmem_sz, SZ_4K);
-		if (audio->phys) {
-			audio->map_v_write = ioremap(audio->phys, pmem_sz);
-			if (IS_ERR(audio->map_v_write)) {
-				MM_ERR("could not allocate write buffers, \
-						freeing instance 0x%08x\n",
-						(int)audio);
-				rc = -ENOMEM;
-				free_contiguous_memory_by_paddr(audio->phys);
-				audpp_adec_free(audio->dec_id);
-				kfree(audio);
-				goto done;
-			}
-			audio->data = audio->map_v_write;
-			MM_DBG("write buf: phy addr 0x%08x kernel addr \
-				0x%08x\n", audio->phys, (int)audio->data);
-			break;
-		} else if (pmem_sz == DMASZ_MIN) {
-			MM_ERR("could not allocate write buffers, freeing \
-					instance 0x%08x\n", (int)audio);
-			rc = -ENOMEM;
-			audpp_adec_free(audio->dec_id);
-			kfree(audio);
-			goto done;
-		} else
-		pmem_sz >>= 1;
+	client = msm_ion_client_create(UINT_MAX, "Audio_WMA_Client");
+	if (IS_ERR_OR_NULL(client)) {
+		pr_err("Unable to create ION client\n");
+		rc = -ENOMEM;
+		goto client_create_error;
 	}
-	audio->out_dma_sz = pmem_sz;
+	audio->client = client;
+
+	handle = ion_alloc(client, mem_sz, 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\n");
+		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);
+
+	audio->out_dma_sz = mem_sz;
 
 	rc = msm_adsp_get(audio->module_name, &audio->audplay,
 			&audplay_adsp_ops_wma, audio);
@@ -1766,8 +1824,14 @@
 event_err:
 	msm_adsp_put(audio->audplay);
 err:
-	iounmap(audio->map_v_write);
-	free_contiguous_memory_by_paddr(audio->phys);
+	ion_unmap_kernel(client, audio->output_buff_handle);
+output_buff_map_error:
+output_buff_get_phys_error:
+output_buff_get_flags_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;
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..8ac1fea 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:
@@ -668,10 +687,10 @@
 				spin_lock_init(&client[i][j].svc[k].w_lock);
 			}
 		}
+	apr_set_subsys_state();
 	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,8 +702,6 @@
 	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);
 	return ret;
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 5c1e7ce..7298fa1 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
@@ -15,7 +15,7 @@
 #include <linux/miscdevice.h>
 #include <linux/mutex.h>
 #include <linux/uaccess.h>
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
 #include <linux/mm.h>
 #include <mach/qdsp6v2/audio_acdb.h>
 
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_lpa.c b/arch/arm/mach-msm/qdsp6v2/audio_lpa.c
index cbfee70..b5a382e 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_lpa.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_lpa.c
@@ -28,7 +28,7 @@
 #include <linux/debugfs.h>
 #include <linux/delay.h>
 #include <linux/earlysuspend.h>
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
 #include <linux/list.h>
 #include <linux/slab.h>
 #include <asm/atomic.h>
@@ -707,6 +707,15 @@
 	case RESET_EVENTS:
 		reset_device();
 		break;
+	case APR_BASIC_RSP_RESULT:
+		switch (payload[0]) {
+		case ASM_STREAM_CMD_CLOSE:
+			audlpa_unmap_ion_region(audio);
+			break;
+		default:
+			break;
+		}
+		break;
 	default:
 		break;
 	}
@@ -1126,7 +1135,6 @@
 	if (audio->out_enabled)
 		audlpa_async_flush(audio);
 	audio->wflush = 0;
-	audlpa_unmap_ion_region(audio);
 	audio_disable(audio);
 	msm_clear_session_id(audio->ac->session);
 	auddev_unregister_evt_listner(AUDDEV_CLNT_DEC, audio->ac->session);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
index e9f5c0a..a7e34d9 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
@@ -21,7 +21,7 @@
 #include <linux/wait.h>
 #include <linux/dma-mapping.h>
 #include <linux/slab.h>
-#include <asm/atomic.h>
+#include <linux/atomic.h>
 #include <asm/ioctls.h>
 #include <linux/debugfs.h>
 #include "audio_utils_aio.h"
@@ -93,39 +93,6 @@
 		sizeof(meta_data->meta_out_dsp[0]);
 }
 
-void extract_meta_out_info(struct q6audio_aio *audio,
-		struct audio_aio_buffer_node *buf_node, int dir)
-{
-	struct dec_meta_out *meta_data = buf_node->kvaddr;
-	if (dir) { /* input buffer - Write */
-		if (audio->buf_cfg.meta_info_enable)
-			memcpy(&buf_node->meta_info.meta_in,
-			(char *)buf_node->kvaddr, sizeof(struct dec_meta_in));
-		else
-			memset(&buf_node->meta_info.meta_in,
-			0, sizeof(struct dec_meta_in));
-		pr_debug("%s[%p]:i/p: msw_ts 0x%lx lsw_ts 0x%lx nflags 0x%8x\n",
-			__func__, audio,
-			buf_node->meta_info.meta_in.ntimestamp.highpart,
-			buf_node->meta_info.meta_in.ntimestamp.lowpart,
-			buf_node->meta_info.meta_in.nflags);
-	} else { /* output buffer - Read */
-		memcpy((char *)buf_node->kvaddr,
-			&buf_node->meta_info.meta_out,
-			sizeof(struct dec_meta_out));
-		meta_data->meta_out_dsp[0].nflags = 0x00000000;
-		pr_debug("%s[%p]:o/p: msw_ts 0x%8x lsw_ts 0x%8x nflags 0x%8x, num_frames = %d\n",
-		__func__, audio,
-		((struct dec_meta_out *)buf_node->kvaddr)->\
-			meta_out_dsp[0].msw_ts,
-		((struct dec_meta_out *)buf_node->kvaddr)->\
-			meta_out_dsp[0].lsw_ts,
-		((struct dec_meta_out *)buf_node->kvaddr)->\
-			meta_out_dsp[0].nflags,
-		((struct dec_meta_out *)buf_node->kvaddr)->num_of_frames);
-	}
-}
-
 static int audio_aio_ion_lookup_vaddr(struct q6audio_aio *audio, void *addr,
 					unsigned long len,
 					struct audio_aio_ion_region **region)
@@ -198,7 +165,7 @@
 
 static int audio_aio_pause(struct q6audio_aio  *audio)
 {
-	int rc = 0;
+	int rc = -EINVAL;
 
 	pr_debug("%s[%p], enabled = %d\n", __func__, audio,
 			audio->enabled);
@@ -436,7 +403,7 @@
 	return;
 }
 
-static void audio_aio_unmap_ion_region(struct q6audio_aio *audio)
+void audio_aio_unmap_ion_region(struct q6audio_aio *audio)
 {
 	struct audio_aio_ion_region *region;
 	struct list_head *ptr, *next;
@@ -468,7 +435,6 @@
 	audio->wflush = 0;
 	audio->drv_ops.out_flush(audio);
 	audio->drv_ops.in_flush(audio);
-	audio_aio_unmap_ion_region(audio);
 	audio_aio_disable(audio);
 	audio_aio_reset_ion_region(audio);
 	ion_client_destroy(audio->client);
@@ -1163,9 +1129,12 @@
 		mutex_lock(&audio->lock);
 		if (arg == 1) {
 			rc = audio_aio_pause(audio);
-			if (rc < 0)
+			if (rc < 0) {
 				pr_err("%s[%p]: pause FAILED rc=%d\n",
 					__func__, audio, rc);
+				mutex_unlock(&audio->lock);
+				break;
+			}
 			audio->drv_status |= ADRV_STATUS_PAUSE;
 		} else if (arg == 0) {
 			if (audio->drv_status & ADRV_STATUS_PAUSE) {
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.h b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.h
index 811baf0..2b936c5 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.h
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.h
@@ -24,7 +24,7 @@
 #include <linux/debugfs.h>
 #include <linux/list.h>
 #include <linux/slab.h>
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
 #include <asm/ioctls.h>
 #include <asm/atomic.h>
 #include "q6audio_common.h"
@@ -210,6 +210,7 @@
 int audio_aio_fsync(struct file *file, loff_t start, loff_t end, int datasync);
 void audio_aio_async_out_flush(struct q6audio_aio *audio);
 void audio_aio_async_in_flush(struct q6audio_aio *audio);
+void audio_aio_unmap_ion_region(struct q6audio_aio *audio);
 #ifdef CONFIG_DEBUG_FS
 ssize_t audio_aio_debug_open(struct inode *inode, struct file *file);
 ssize_t audio_aio_debug_read(struct file *file, char __user *buf,
diff --git a/arch/arm/mach-msm/qdsp6v2/q6audio_v1_aio.c b/arch/arm/mach-msm/qdsp6v2/q6audio_v1_aio.c
index 078eea8..b46e0d3 100644
--- a/arch/arm/mach-msm/qdsp6v2/q6audio_v1_aio.c
+++ b/arch/arm/mach-msm/qdsp6v2/q6audio_v1_aio.c
@@ -19,7 +19,7 @@
 #include <linux/wait.h>
 #include <linux/dma-mapping.h>
 #include <linux/slab.h>
-#include <asm/atomic.h>
+#include <linux/atomic.h>
 #include <asm/ioctls.h>
 #include "audio_utils_aio.h"
 
@@ -37,6 +37,7 @@
 	case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
 	case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY:
 	case ASM_DATA_EVENT_ENC_SR_CM_NOTIFY:
+	case APR_BASIC_RSP_RESULT:
 		audio_aio_cb(opcode, token, payload, audio);
 		break;
 	default:
@@ -106,11 +107,53 @@
 		e_payload.stream_info.sample_rate = audio->pcm_cfg.sample_rate;
 		audio_aio_post_event(audio, AUDIO_EVENT_STREAM_INFO, e_payload);
 		break;
+	case APR_BASIC_RSP_RESULT:
+		switch (payload[0]) {
+		case ASM_STREAM_CMD_CLOSE:
+			audio_aio_unmap_ion_region(audio);
+			break;
+		default:
+			break;
+		}
+		break;
 	default:
 		break;
 	}
 }
 
+void extract_meta_out_info(struct q6audio_aio *audio,
+		struct audio_aio_buffer_node *buf_node, int dir)
+{
+	struct dec_meta_out *meta_data = buf_node->kvaddr;
+	if (dir) { /* input buffer - Write */
+		if (audio->buf_cfg.meta_info_enable)
+			memcpy(&buf_node->meta_info.meta_in,
+			(char *)buf_node->kvaddr, sizeof(struct dec_meta_in));
+		else
+			memset(&buf_node->meta_info.meta_in,
+			0, sizeof(struct dec_meta_in));
+		pr_debug("%s[%p]:i/p: msw_ts 0x%lx lsw_ts 0x%lx nflags 0x%8x\n",
+			__func__, audio,
+			buf_node->meta_info.meta_in.ntimestamp.highpart,
+			buf_node->meta_info.meta_in.ntimestamp.lowpart,
+			buf_node->meta_info.meta_in.nflags);
+	} else { /* output buffer - Read */
+		memcpy((char *)buf_node->kvaddr,
+			&buf_node->meta_info.meta_out,
+			sizeof(struct dec_meta_out));
+		meta_data->meta_out_dsp[0].nflags = 0x00000000;
+		pr_debug("%s[%p]:o/p: msw_ts 0x%8x lsw_ts 0x%8x nflags 0x%8x, num_frames = %d\n",
+		__func__, audio,
+		((struct dec_meta_out *)buf_node->kvaddr)->\
+			meta_out_dsp[0].msw_ts,
+		((struct dec_meta_out *)buf_node->kvaddr)->\
+			meta_out_dsp[0].lsw_ts,
+		((struct dec_meta_out *)buf_node->kvaddr)->\
+			meta_out_dsp[0].nflags,
+		((struct dec_meta_out *)buf_node->kvaddr)->num_of_frames);
+	}
+}
+
 /* Read buffer from DSP / Handle Ack from DSP */
 void audio_aio_async_read_ack(struct q6audio_aio *audio, uint32_t token,
 			uint32_t *payload)
diff --git a/arch/arm/mach-msm/qdsp6v2/q6audio_v2_aio.c b/arch/arm/mach-msm/qdsp6v2/q6audio_v2_aio.c
index ad4fc6f..10adc26 100644
--- a/arch/arm/mach-msm/qdsp6v2/q6audio_v2_aio.c
+++ b/arch/arm/mach-msm/qdsp6v2/q6audio_v2_aio.c
@@ -19,7 +19,7 @@
 #include <linux/wait.h>
 #include <linux/dma-mapping.h>
 #include <linux/slab.h>
-#include <asm/atomic.h>
+#include <linux/atomic.h>
 #include <asm/ioctls.h>
 #include "audio_utils_aio.h"
 
@@ -110,6 +110,46 @@
 	}
 }
 
+void extract_meta_out_info(struct q6audio_aio *audio,
+		struct audio_aio_buffer_node *buf_node, int dir)
+{
+	struct dec_meta_out *meta_data = buf_node->kvaddr;
+	uint32_t temp;
+
+	if (dir) { /* input buffer - Write */
+		if (audio->buf_cfg.meta_info_enable)
+			memcpy(&buf_node->meta_info.meta_in,
+			(char *)buf_node->kvaddr, sizeof(struct dec_meta_in));
+		else
+			memset(&buf_node->meta_info.meta_in,
+			0, sizeof(struct dec_meta_in));
+		pr_debug("%s[%p]:i/p: msw_ts 0x%lx lsw_ts 0x%lx nflags 0x%8x\n",
+			__func__, audio,
+			buf_node->meta_info.meta_in.ntimestamp.highpart,
+			buf_node->meta_info.meta_in.ntimestamp.lowpart,
+			buf_node->meta_info.meta_in.nflags);
+	} else { /* output buffer - Read */
+		memcpy((char *)buf_node->kvaddr,
+			&buf_node->meta_info.meta_out,
+			sizeof(struct dec_meta_out));
+		meta_data->meta_out_dsp[0].nflags = 0x00000000;
+		temp = meta_data->meta_out_dsp[0].msw_ts;
+		meta_data->meta_out_dsp[0].msw_ts =
+				meta_data->meta_out_dsp[0].lsw_ts;
+		meta_data->meta_out_dsp[0].lsw_ts = temp;
+
+		pr_debug("%s[%p]:o/p: msw_ts 0x%8x lsw_ts 0x%8x nflags 0x%8x, num_frames = %d\n",
+		__func__, audio,
+		((struct dec_meta_out *)buf_node->kvaddr)->\
+			meta_out_dsp[0].msw_ts,
+		((struct dec_meta_out *)buf_node->kvaddr)->\
+			meta_out_dsp[0].lsw_ts,
+		((struct dec_meta_out *)buf_node->kvaddr)->\
+			meta_out_dsp[0].nflags,
+		((struct dec_meta_out *)buf_node->kvaddr)->num_of_frames);
+	}
+}
+
 /* Read buffer from DSP / Handle Ack from DSP */
 void audio_aio_async_read_ack(struct q6audio_aio *audio, uint32_t token,
 			uint32_t *payload)
diff --git a/arch/arm/mach-msm/qdsp6v2/q6core.c b/arch/arm/mach-msm/qdsp6v2/q6core.c
index edb1e7d..d7de50e 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/qdsp6v2/rtac.c b/arch/arm/mach-msm/qdsp6v2/rtac.c
index 8808375..cae0f3a 100644
--- a/arch/arm/mach-msm/qdsp6v2/rtac.c
+++ b/arch/arm/mach-msm/qdsp6v2/rtac.c
@@ -353,7 +353,7 @@
 	return;
 }
 
-static int get_voice_index(u32 cvs_handle)
+static int get_voice_index_cvs(u32 cvs_handle)
 {
 	u32 i;
 
@@ -367,6 +367,32 @@
 	return 0;
 }
 
+static int get_voice_index_cvp(u32 cvp_handle)
+{
+	u32 i;
+
+	for (i = 0; i < rtac_voice_data.num_of_voice_combos; i++) {
+		if (rtac_voice_data.voice[i].cvp_handle == cvp_handle)
+			return i;
+	}
+
+	pr_err("%s: No voice index for CVP handle %d found returning 0\n",
+	       __func__, cvp_handle);
+	return 0;
+}
+
+static int get_voice_index(u32 mode, u32 handle)
+{
+	if (mode == RTAC_CVP)
+		return get_voice_index_cvp(handle);
+	if (mode == RTAC_CVS)
+		return get_voice_index_cvs(handle);
+
+	pr_err("%s: Invalid mode %d, returning 0\n",
+	       __func__, mode);
+	return 0;
+}
+
 
 /* ADM APR */
 void rtac_set_adm_handle(void *handle)
@@ -752,7 +778,7 @@
 	u32	count = 0;
 	u32	bytes_returned = 0;
 	u32	payload_size;
-	u16	dest_port;
+	u32	dest_port;
 	struct	apr_hdr	voice_params;
 	pr_debug("%s\n", __func__);
 
@@ -768,7 +794,8 @@
 		goto done;
 	}
 
-	if (copy_from_user(&payload_size, buf + sizeof(u32), sizeof(u32))) {
+	if (copy_from_user(&payload_size, buf + sizeof(payload_size),
+						sizeof(payload_size))) {
 		pr_err("%s: Could not copy payload size from user buffer\n",
 			__func__);
 		goto done;
@@ -780,7 +807,8 @@
 		goto done;
 	}
 
-	if (copy_from_user(&dest_port, buf + 2 * sizeof(u32), sizeof(u32))) {
+	if (copy_from_user(&dest_port, buf + 2 * sizeof(dest_port),
+						sizeof(dest_port))) {
 		pr_err("%s: Could not copy port id from user buffer\n",
 			__func__);
 		goto done;
@@ -817,10 +845,10 @@
 	voice_params.src_svc = 0;
 	voice_params.src_domain = APR_DOMAIN_APPS;
 	voice_params.src_port = voice_session_id[
-					get_voice_index(dest_port)];
+					get_voice_index(mode, dest_port)];
 	voice_params.dest_svc = 0;
 	voice_params.dest_domain = APR_DOMAIN_MODEM;
-	voice_params.dest_port = dest_port;
+	voice_params.dest_port = (u16)dest_port;
 	voice_params.token = 0;
 	voice_params.opcode = opcode;
 
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.c
index 2874700..5400ccc 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.c
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.c
@@ -10,8 +10,6 @@
  * GNU General Public License for more details.
  *
  */
-
-#include <linux/module.h>
 #include <linux/fs.h>
 #include <linux/mutex.h>
 #include <linux/wait.h>
@@ -355,8 +353,6 @@
 						usc->priv);
 				break;
 			default:
-				pr_debug("%s: command[0x%x] wrong response\n",
-					 __func__, payload[0]);
 				break;
 			}
 		}
@@ -367,19 +363,6 @@
 	case USM_DATA_EVENT_READ_DONE: {
 		struct us_port_data *port = &usc->port[OUT];
 
-		pr_debug("%s: R-D: stat=%d; buff=%x; size=%d; off=%d\n",
-			 __func__,
-			 payload[READDONE_IDX_STATUS],
-			 payload[READDONE_IDX_BUFFER],
-			 payload[READDONE_IDX_SIZE],
-			 payload[READDONE_IDX_OFFSET]);
-		pr_debug("msw_ts=%d; lsw_ts=%d; flags=%d; id=%d; num=%d\n",
-			 payload[READDONE_IDX_MSW_TS],
-			 payload[READDONE_IDX_LSW_TS],
-			 payload[READDONE_IDX_FLAGS],
-			 payload[READDONE_IDX_ID],
-			 payload[READDONE_IDX_NUMFRAMES]);
-
 		spin_lock_irqsave(&port->dsp_lock, dsp_flags);
 		if (payload[READDONE_IDX_STATUS]) {
 			pr_err("%s: wrong READDONE[%d]; token[%d]\n",
@@ -425,10 +408,6 @@
 	case USM_DATA_EVENT_WRITE_DONE: {
 		struct us_port_data *port = &usc->port[IN];
 
-		pr_debug("%s W-D: code[0x%x]; status[0x%x]; token[%d]",
-			 __func__,
-			 payload[0], payload[1], token);
-
 		if (payload[WRITEDONE_IDX_STATUS]) {
 			pr_err("%s: wrong WRITEDONE_IDX_STATUS[%d]\n",
 			       __func__,
@@ -442,10 +421,6 @@
 			port->dsp_buf = 0;
 		spin_unlock_irqrestore(&port->dsp_lock, dsp_flags);
 
-		pr_debug("%s: WRITE_DONE: token=%d; dsp_buf=%d; cpu_buf=%d\n",
-			__func__,
-			token, port->dsp_buf, port->cpu_buf);
-
 		break;
 	} /* case USM_DATA_EVENT_WRITE_DONE */
 
@@ -458,8 +433,6 @@
 	} /* case USM_SESSION_EVENT_SIGNAL_DETECT_RESULT */
 
 	default:
-		pr_debug("%s: not supported code [0x%x]",
-			 __func__, data->opcode);
 		return 0;
 
 	} /* switch */
@@ -498,9 +471,6 @@
 static void q6usm_add_hdr(struct us_client *usc, struct apr_hdr *hdr,
 			  uint32_t pkt_size, bool cmd_flg)
 {
-	pr_debug("%s: pkt size=%d; cmd_flg=%d\n",
-		 __func__, pkt_size, cmd_flg);
-	pr_debug("**************\n");
 	mutex_lock(&usc->cmd_lock);
 	hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, \
 				       APR_HDR_LEN(sizeof(struct apr_hdr)),\
@@ -523,9 +493,6 @@
 static void q6usm_add_mmaphdr(struct us_client *usc, struct apr_hdr *hdr,
 			      uint32_t pkt_size, bool cmd_flg)
 {
-	pr_debug("%s: pkt size=%d cmd_flg=%d\n",
-		 __func__, pkt_size, cmd_flg);
-	pr_debug("**************\n");
 	hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, \
 				       APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
 	hdr->src_port = 0;
@@ -1067,11 +1034,6 @@
 		cmd_write.uid = port->cpu_buf;
 		cmd_write.hdr.token = port->cpu_buf;
 
-		pr_debug("%s:buf addr[0x%x] size[%d] token[%d] uid[%d]\n",
-			 __func__, cmd_write.buf_add, cmd_write.buf_size,
-			 cmd_write.hdr.token, cmd_write.uid);
-		pr_debug("%s: data=0x%p\n", __func__, port->data);
-
 		++(port->cpu_buf);
 		if (port->cpu_buf == port->buf_cnt)
 			port->cpu_buf = 0;
@@ -1089,9 +1051,6 @@
 		rc = 0;
 	}
 
-	pr_debug("%s:exit: rc=%d; write_ind=%d; cpu_buf=%d; dsp_buf=%d\n",
-		__func__, rc, write_ind, port->cpu_buf, port->dsp_buf);
-
 	return rc;
 }
 
@@ -1136,8 +1095,6 @@
 		goto fail_cmd;
 	}
 
-	pr_debug("%s:session[%d]opcode[0x%x] ", __func__,
-		 usc->session,  hdr.opcode);
 	rc = apr_send_pkt(usc->apr, (uint32_t *) &hdr);
 	if (rc < 0) {
 		pr_err("%s: Command 0x%x failed\n", __func__, hdr.opcode);
@@ -1204,6 +1161,3 @@
 }
 
 device_initcall(q6usm_init);
-
-MODULE_DESCRIPTION("Interface with QDSP6:USM");
-MODULE_VERSION(DRV_VERSION);
diff --git a/arch/arm/mach-msm/restart.c b/arch/arm/mach-msm/restart.c
index 7288c1d..25723d5 100644
--- a/arch/arm/mach-msm/restart.c
+++ b/arch/arm/mach-msm/restart.c
@@ -47,6 +47,12 @@
 
 #define SCM_IO_DISABLE_PMIC_ARBITER	1
 
+#ifdef CONFIG_MSM_RESTART_V2
+#define use_restart_v2()	1
+#else
+#define use_restart_v2()	0
+#endif
+
 static int restart_mode;
 void *restart_reason;
 
@@ -123,7 +129,11 @@
 	pm8xxx_reset_pwr_off(0);
 
 	if (lower_pshold) {
-		__raw_writel(0, PSHOLD_CTL_SU);
+		if (!use_restart_v2())
+			__raw_writel(0, PSHOLD_CTL_SU);
+		else
+			__raw_writel(0, MSM_MPM2_PSHOLD_BASE);
+
 		mdelay(10000);
 		printk(KERN_ERR "Powering off has failed\n");
 	}
@@ -177,9 +187,8 @@
 	return IRQ_HANDLED;
 }
 
-void msm_restart(char mode, const char *cmd)
+static void msm_restart_prepare(const char *cmd)
 {
-
 #ifdef CONFIG_MSM_DLOAD_MODE
 
 	/* This looks like a normal reboot at this point. */
@@ -197,8 +206,6 @@
 		set_dload_mode(0);
 #endif
 
-	printk(KERN_NOTICE "Going down for restart now\n");
-
 	pm8xxx_reset_pwr_off(1);
 
 	if (cmd != NULL) {
@@ -214,19 +221,31 @@
 			__raw_writel(0x77665501, restart_reason);
 		}
 	}
+}
 
-	__raw_writel(0, msm_tmr0_base + WDT0_EN);
-	if (!(machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa())) {
-		mb();
-		__raw_writel(0, PSHOLD_CTL_SU); /* Actually reset the chip */
-		mdelay(5000);
-		pr_notice("PS_HOLD didn't work, falling back to watchdog\n");
-	}
+void msm_restart(char mode, const char *cmd)
+{
+	printk(KERN_NOTICE "Going down for restart now\n");
 
-	__raw_writel(1, msm_tmr0_base + WDT0_RST);
-	__raw_writel(5*0x31F3, msm_tmr0_base + WDT0_BARK_TIME);
-	__raw_writel(0x31F3, msm_tmr0_base + WDT0_BITE_TIME);
-	__raw_writel(1, msm_tmr0_base + WDT0_EN);
+	msm_restart_prepare(cmd);
+
+	if (!use_restart_v2()) {
+		__raw_writel(0, msm_tmr0_base + WDT0_EN);
+		if (!(machine_is_msm8x60_fusion() ||
+		      machine_is_msm8x60_fusn_ffa())) {
+			mb();
+			 /* Actually reset the chip */
+			__raw_writel(0, PSHOLD_CTL_SU);
+			mdelay(5000);
+			pr_notice("PS_HOLD didn't work, falling back to watchdog\n");
+		}
+
+		__raw_writel(1, msm_tmr0_base + WDT0_RST);
+		__raw_writel(5*0x31F3, msm_tmr0_base + WDT0_BARK_TIME);
+		__raw_writel(0x31F3, msm_tmr0_base + WDT0_BITE_TIME);
+		__raw_writel(1, msm_tmr0_base + WDT0_EN);
+	} else
+		__raw_writel(0, MSM_MPM2_PSHOLD_BASE);
 
 	mdelay(10000);
 	printk(KERN_ERR "Restarting has failed\n");
diff --git a/arch/arm/mach-msm/rpm-regulator-8930.c b/arch/arm/mach-msm/rpm-regulator-8930.c
index 0de67b1..9133856 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,57 +104,71 @@
 	&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, _requires_cxo) \
-	[RPM_VREG_ID_PM8038_##_id] = { \
+	[RPM_VREG_ID_PM##_id] = { \
 		.req = { \
-			[0] = { .id = MSM_RPM_ID_PM8038_##_id##_0, }, \
-			[1] = { .id = MSM_RPM_ID_PM8038_##_id##_1, }, \
+			[0] = { .id = MSM_RPM_ID_PM##_id##_0, }, \
+			[1] = { .id = MSM_RPM_ID_PM##_id##_1, }, \
 		}, \
 		.hpm_min_load  = RPM_VREG_8930_##_hpm_min_load##_HPM_MIN_LOAD, \
 		.type		 = RPM_REGULATOR_TYPE_LDO, \
 		.set_points	 = &_ranges##_set_points, \
 		.part		 = &ldo_parts, \
-		.id		 = RPM_VREG_ID_PM8038_##_id, \
+		.id		 = RPM_VREG_ID_PM##_id, \
 		.rdesc.name	 = _name, \
 		.rdesc_pc.name	 = _name_pc, \
 		.requires_cxo	 = _requires_cxo, \
 	}
 
 #define SMPS(_id, _name, _name_pc, _ranges, _hpm_min_load) \
-	[RPM_VREG_ID_PM8038_##_id] = { \
+	[RPM_VREG_ID_PM##_id] = { \
 		.req = { \
-			[0] = { .id = MSM_RPM_ID_PM8038_##_id##_0, }, \
-			[1] = { .id = MSM_RPM_ID_PM8038_##_id##_1, }, \
+			[0] = { .id = MSM_RPM_ID_PM##_id##_0, }, \
+			[1] = { .id = MSM_RPM_ID_PM##_id##_1, }, \
 		}, \
 		.hpm_min_load  = RPM_VREG_8930_##_hpm_min_load##_HPM_MIN_LOAD, \
 		.type		 = RPM_REGULATOR_TYPE_SMPS, \
 		.set_points	 = &_ranges##_set_points, \
 		.part		 = &smps_parts, \
-		.id		 = RPM_VREG_ID_PM8038_##_id, \
+		.id		 = RPM_VREG_ID_PM##_id, \
 		.rdesc.name	 = _name, \
 		.rdesc_pc.name	 = _name_pc, \
 	}
 
 #define LVS(_id, _name, _name_pc) \
-	[RPM_VREG_ID_PM8038_##_id] = { \
+	[RPM_VREG_ID_PM##_id] = { \
 		.req = { \
-			[0] = { .id = MSM_RPM_ID_PM8038_##_id, }, \
+			[0] = { .id = MSM_RPM_ID_PM##_id, }, \
 			[1] = { .id = -1, }, \
 		}, \
 		.type		 = RPM_REGULATOR_TYPE_VS, \
 		.part		 = &switch_parts, \
-		.id		 = RPM_VREG_ID_PM8038_##_id, \
+		.id		 = RPM_VREG_ID_PM##_id, \
+		.rdesc.name	 = _name, \
+		.rdesc_pc.name	 = _name_pc, \
+	}
+
+#define MVS(_vreg_id, _name, _name_pc, _rpm_id) \
+	[RPM_VREG_ID_PM##_vreg_id] = { \
+		.req = { \
+			[0] = { .id = MSM_RPM_ID_##_rpm_id, }, \
+			[1] = { .id = -1, }, \
+		}, \
+		.type		 = RPM_REGULATOR_TYPE_VS, \
+		.part		 = &switch_parts, \
+		.id		 = RPM_VREG_ID_PM##_vreg_id, \
 		.rdesc.name	 = _name, \
 		.rdesc_pc.name	 = _name_pc, \
 	}
 
 #define CORNER(_id, _rpm_id, _name, _ranges) \
-	[RPM_VREG_ID_PM8038_##_id] = { \
+	[RPM_VREG_ID_PM##_id] = { \
 		.req = { \
 			[0] = { .id = MSM_RPM_ID_##_rpm_id, }, \
 			[1] = { .id = -1, }, \
@@ -156,48 +176,105 @@
 		.type		 = RPM_REGULATOR_TYPE_CORNER, \
 		.set_points	 = &_ranges##_set_points, \
 		.part		 = &corner_parts, \
-		.id		 = RPM_VREG_ID_PM8038_##_id, \
+		.id		 = RPM_VREG_ID_PM##_id, \
 		.rdesc.name	 = _name, \
 	}
 
-static struct vreg vregs[] = {
-	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(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(L26,  "8038_l26",  "8038_l26_pc", nldo,     LDO_150,  1),
-	LDO(L27,  "8038_l27",  NULL,          nldo1200, LDO_1200, 1),
+static struct vreg vregs_msm8930_pm8038[] = {
+	LDO(8038_L1,   "8038_l1",   NULL,          nldo1200, LDO_1200, 1),
+	LDO(8038_L2,   "8038_l2",   "8038_l2_pc",  nldo,     LDO_150,  1),
+	LDO(8038_L3,   "8038_l3",   "8038_l3_pc",  pldo,     LDO_50,   0),
+	LDO(8038_L4,   "8038_l4",   "8038_l4_pc",  pldo,     LDO_50,   0),
+	LDO(8038_L5,   "8038_l5",   "8038_l5_pc",  pldo,     LDO_600,  0),
+	LDO(8038_L6,   "8038_l6",   "8038_l6_pc",  pldo,     LDO_600,  0),
+	LDO(8038_L7,   "8038_l7",   "8038_l7_pc",  pldo,     LDO_600,  0),
+	LDO(8038_L8,   "8038_l8",   "8038_l8_pc",  pldo,     LDO_300,  0),
+	LDO(8038_L9,   "8038_l9",   "8038_l9_pc",  pldo,     LDO_300,  0),
+	LDO(8038_L10,  "8038_l10",  "8038_l10_pc", pldo,     LDO_600,  0),
+	LDO(8038_L11,  "8038_l11",  "8038_l11_pc", pldo,     LDO_600,  0),
+	LDO(8038_L12,  "8038_l12",  "8038_l12_pc", nldo,     LDO_300,  1),
+	LDO(8038_L13,  "8038_l13",  NULL,          ln_ldo,   LDO_5,    0),
+	LDO(8038_L14,  "8038_l14",  "8038_l14_pc", pldo,     LDO_50,   0),
+	LDO(8038_L15,  "8038_l15",  "8038_l15_pc", pldo,     LDO_150,  0),
+	LDO(8038_L16,  "8038_l16",  NULL,          nldo1200, LDO_1200, 1),
+	LDO(8038_L17,  "8038_l17",  "8038_l17_pc", pldo,     LDO_150,  0),
+	LDO(8038_L18,  "8038_l18",  "8038_l18_pc", pldo,     LDO_50,   0),
+	LDO(8038_L19,  "8038_l19",  NULL,          nldo1200, LDO_1200, 1),
+	LDO(8038_L20,  "8038_l20",  NULL,          nldo1200, LDO_1200, 1),
+	LDO(8038_L21,  "8038_l21",  "8038_l21_pc", pldo,     LDO_150,  0),
+	LDO(8038_L22,  "8038_l22",  "8038_l22_pc", pldo,     LDO_50,   0),
+	LDO(8038_L23,  "8038_l23",  "8038_l23_pc", pldo,     LDO_50,   0),
+	LDO(8038_L24,  "8038_l24",  NULL,          nldo1200, LDO_1200, 1),
+	LDO(8038_L25,  "8038_l25",  NULL,          ln_ldo,   LDO_5,    0),
+	LDO(8038_L26,  "8038_l26",  "8038_l26_pc", nldo,     LDO_150,  1),
+	LDO(8038_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),
-	SMPS(S3,  "8038_s3",   "8038_s3_pc",  smps,     SMPS_1500),
-	SMPS(S4,  "8038_s4",   "8038_s4_pc",  smps,     SMPS_1500),
-	SMPS(S5,  "8038_s5",   NULL,          ftsmps,   SMPS_2000),
-	SMPS(S6,  "8038_s6",   NULL,          ftsmps,   SMPS_2000),
+	SMPS(8038_S1,  "8038_s1",   "8038_s1_pc",  smps,     SMPS_1500),
+	SMPS(8038_S2,  "8038_s2",   "8038_s2_pc",  smps,     SMPS_1500),
+	SMPS(8038_S3,  "8038_s3",   "8038_s3_pc",  smps,     SMPS_1500),
+	SMPS(8038_S4,  "8038_s4",   "8038_s4_pc",  smps,     SMPS_1500),
+	SMPS(8038_S5,  "8038_s5",   NULL,          ftsmps,   SMPS_2000),
+	SMPS(8038_S6,  "8038_s6",   NULL,          ftsmps,   SMPS_2000),
 
-	LVS(LVS1, "8038_lvs1", "8038_lvs1_pc"),
-	LVS(LVS2, "8038_lvs2", "8038_lvs2_pc"),
+	LVS(8038_LVS1, "8038_lvs1", "8038_lvs1_pc"),
+	LVS(8038_LVS2, "8038_lvs2", "8038_lvs2_pc"),
 
-	CORNER(VDD_DIG_CORNER, VOLTAGE_CORNER, "vdd_dig_corner", corner),
+	CORNER(8038_VDD_DIG_CORNER, VOLTAGE_CORNER, "vdd_dig_corner", corner),
+};
+
+static struct vreg vregs_msm8930_pm8917[] = {
+	LDO(8917_L1,   "8917_l1",   "8917_l1_pc",  nldo,     LDO_150,  1),
+	LDO(8917_L2,   "8917_l2",   "8917_l2_pc",  nldo,     LDO_150,  1),
+	LDO(8917_L3,   "8917_l3",   "8917_l3_pc",  pldo,     LDO_150,  0),
+	LDO(8917_L4,   "8917_l4",   "8917_l4_pc",  pldo,     LDO_50,   0),
+	LDO(8917_L5,   "8917_l5",   "8917_l5_pc",  pldo,     LDO_300,  0),
+	LDO(8917_L6,   "8917_l6",   "8917_l6_pc",  pldo,     LDO_600,  0),
+	LDO(8917_L7,   "8917_l7",   "8917_l7_pc",  pldo,     LDO_150,  0),
+	LDO(8917_L8,   "8917_l8",   "8917_l8_pc",  pldo,     LDO_300,  0),
+	LDO(8917_L9,   "8917_l9",   "8917_l9_pc",  pldo,     LDO_300,  0),
+	LDO(8917_L10,  "8917_l10",  "8917_l10_pc", pldo,     LDO_600,  0),
+	LDO(8917_L11,  "8917_l11",  "8917_l11_pc", pldo,     LDO_150,  0),
+	LDO(8917_L12,  "8917_l12",  "8917_l12_pc", nldo,     LDO_150,  1),
+	LDO(8917_L14,  "8917_l14",  "8917_l14_pc", pldo,     LDO_50,   0),
+	LDO(8917_L15,  "8917_l15",  "8917_l15_pc", pldo,     LDO_150,  0),
+	LDO(8917_L16,  "8917_l16",  "8917_l16_pc", pldo,     LDO_300,  0),
+	LDO(8917_L17,  "8917_l17",  "8917_l17_pc", pldo,     LDO_150,  0),
+	LDO(8917_L18,  "8917_l18",  "8917_l18_pc", nldo,     LDO_150,  1),
+	LDO(8917_L21,  "8917_l21",  "8917_l21_pc", pldo,     LDO_150,  0),
+	LDO(8917_L22,  "8917_l22",  "8917_l22_pc", pldo,     LDO_150,  0),
+	LDO(8917_L23,  "8917_l23",  "8917_l23_pc", pldo,     LDO_150,  0),
+	LDO(8917_L24,  "8917_l24",  NULL,          nldo1200, LDO_1200, 0),
+	LDO(8917_L25,  "8917_l25",  NULL,          nldo1200, LDO_1200, 0),
+	LDO(8917_L26,  "8917_l26",  NULL,          nldo1200, LDO_1200, 0),
+	LDO(8917_L27,  "8917_l27",  NULL,          nldo1200, LDO_1200, 0),
+	LDO(8917_L28,  "8917_l28",  NULL,          nldo1200, LDO_1200, 0),
+	LDO(8917_L29,  "8917_l29",  "8917_l29_pc", pldo,     LDO_150,  0),
+	LDO(8917_L30,  "8917_l30",  "8917_l30_pc", pldo,     LDO_150,  0),
+	LDO(8917_L31,  "8917_l31",  "8917_l31_pc", pldo,     LDO_150,  0),
+	LDO(8917_L32,  "8917_l32",  "8917_l32_pc", pldo,     LDO_150,  0),
+	LDO(8917_L33,  "8917_l33",  "8917_l33_pc", pldo,     LDO_150,  0),
+	LDO(8917_L34,  "8917_l34",  "8917_l34_pc", pldo,     LDO_150,  0),
+	LDO(8917_L35,  "8917_l35",  "8917_l35_pc", pldo,     LDO_300,  0),
+	LDO(8917_L36,  "8917_l36",  "8917_l36_pc", pldo,     LDO_50,   0),
+
+	SMPS(8917_S1,  "8917_s1",   "8917_s1_pc",  smps,     SMPS_1500),
+	SMPS(8917_S2,  "8917_s2",   "8917_s2_pc",  smps,     SMPS_1500),
+	SMPS(8917_S3,  "8917_s3",   "8917_s3_pc",  smps,     SMPS_1500),
+	SMPS(8917_S4,  "8917_s4",   "8917_s4_pc",  smps,     SMPS_1500),
+	SMPS(8917_S5,  "8917_s5",   NULL,          ftsmps,   SMPS_2000),
+	SMPS(8917_S6,  "8917_s6",   NULL,          ftsmps,   SMPS_2000),
+	SMPS(8917_S7,  "8917_s7",   "8917_s7_pc",  smps,     SMPS_1500),
+	SMPS(8917_S8,  "8917_s8",   "8917_s8_pc",  smps,     SMPS_1500),
+
+	LVS(8917_LVS1, "8917_lvs1", "8917_lvs1_pc"),
+	LVS(8917_LVS3, "8917_lvs3", "8917_lvs3_pc"),
+	LVS(8917_LVS4, "8917_lvs4", "8917_lvs4_pc"),
+	LVS(8917_LVS5, "8917_lvs5", "8917_lvs5_pc"),
+	LVS(8917_LVS6, "8917_lvs6", "8917_lvs6_pc"),
+	LVS(8917_LVS7, "8917_lvs7", "8917_lvs7_pc"),
+	MVS(8917_USB_OTG,  "8917_usb_otg",  NULL, USB_OTG_SWITCH),
+
+	CORNER(8917_VDD_DIG_CORNER, VOLTAGE_CORNER, "vdd_dig_corner", corner),
 };
 
 static const char *pin_func_label[] = {
@@ -228,17 +305,22 @@
 	" A2",
 };
 
-static int is_real_id(int id)
+static int is_real_id_msm8930_pm8038(int id)
 {
 	return (id >= 0) && (id <= RPM_VREG_ID_PM8038_MAX_REAL);
 }
 
-static int pc_id_to_real_id(int id)
+static int pc_id_to_real_id_msm8930_pm8038(int id)
 {
 	int real_id = 0;
 
-	if (id >= RPM_VREG_ID_PM8038_L2_PC && id <= RPM_VREG_ID_PM8038_L15_PC)
-		real_id = id - RPM_VREG_ID_PM8038_L2_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
+				+ RPM_VREG_ID_PM8038_L2;
+	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
@@ -261,9 +343,33 @@
 	return real_id;
 }
 
-static struct vreg_config config = {
-	.vregs			= vregs,
-	.vregs_len		= ARRAY_SIZE(vregs),
+static int is_real_id_msm8930_pm8917(int id)
+{
+	return (id >= 0) && (id <= RPM_VREG_ID_PM8917_MAX_REAL);
+}
+
+static int pc_id_to_real_id_msm8930_pm8917(int id)
+{
+	int real_id = 0;
+
+	if (id >= RPM_VREG_ID_PM8917_L1_PC && id <= RPM_VREG_ID_PM8917_L23_PC)
+		real_id = id - RPM_VREG_ID_PM8917_L1_PC
+				+ RPM_VREG_ID_PM8917_L1;
+	else if (id >= RPM_VREG_ID_PM8917_L29_PC
+			&& id <= RPM_VREG_ID_PM8917_S4_PC)
+		real_id = id - RPM_VREG_ID_PM8917_L29_PC
+				+ RPM_VREG_ID_PM8917_L29;
+	else if (id >= RPM_VREG_ID_PM8917_S7_PC
+			&& id <= RPM_VREG_ID_PM8917_LVS7_PC)
+		real_id = id - RPM_VREG_ID_PM8917_S7_PC
+				+ RPM_VREG_ID_PM8917_S7;
+
+	return real_id;
+}
+
+static struct vreg_config config_msm8930_pm8038 = {
+	.vregs			= vregs_msm8930_pm8038,
+	.vregs_len		= ARRAY_SIZE(vregs_msm8930_pm8038),
 
 	.vreg_id_min		= RPM_VREG_ID_PM8038_L1,
 	.vreg_id_max		= RPM_VREG_ID_PM8038_MAX,
@@ -286,11 +392,45 @@
 	.label_power_mode	= power_mode_label,
 	.label_power_mode_len	= ARRAY_SIZE(power_mode_label),
 
-	.is_real_id		= is_real_id,
-	.pc_id_to_real_id	= pc_id_to_real_id,
+	.is_real_id		= is_real_id_msm8930_pm8038,
+	.pc_id_to_real_id	= pc_id_to_real_id_msm8930_pm8038,
+};
+
+static struct vreg_config config_msm8930_pm8917 = {
+	.vregs			= vregs_msm8930_pm8917,
+	.vregs_len		= ARRAY_SIZE(vregs_msm8930_pm8917),
+
+	.vreg_id_min		= RPM_VREG_ID_PM8917_L1,
+	.vreg_id_max		= RPM_VREG_ID_PM8917_MAX,
+
+	.pin_func_none		= RPM_VREG_PIN_FN_8930_NONE,
+	.pin_func_sleep_b	= RPM_VREG_PIN_FN_8930_SLEEP_B,
+
+	.mode_lpm		= REGULATOR_MODE_IDLE,
+	.mode_hpm		= REGULATOR_MODE_NORMAL,
+
+	.set_points		= all_set_points,
+	.set_points_len		= ARRAY_SIZE(all_set_points),
+
+	.label_pin_ctrl		= pin_control_label,
+	.label_pin_ctrl_len	= ARRAY_SIZE(pin_control_label),
+	.label_pin_func		= pin_func_label,
+	.label_pin_func_len	= ARRAY_SIZE(pin_func_label),
+	.label_force_mode	= force_mode_label,
+	.label_force_mode_len	= ARRAY_SIZE(force_mode_label),
+	.label_power_mode	= power_mode_label,
+	.label_power_mode_len	= ARRAY_SIZE(power_mode_label),
+
+	.is_real_id		= is_real_id_msm8930_pm8917,
+	.pc_id_to_real_id	= pc_id_to_real_id_msm8930_pm8917,
 };
 
 struct vreg_config *get_config_8930(void)
 {
-	return &config;
+	return &config_msm8930_pm8038;
+}
+
+struct vreg_config *get_config_8930_pm8917(void)
+{
+	return &config_msm8930_pm8917;
 }
diff --git a/arch/arm/mach-msm/rpm-regulator-8960.c b/arch/arm/mach-msm/rpm-regulator-8960.c
index e75d730..8fe3571 100644
--- a/arch/arm/mach-msm/rpm-regulator-8960.c
+++ b/arch/arm/mach-msm/rpm-regulator-8960.c
@@ -74,6 +74,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),
@@ -93,6 +98,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 ncp_set_points = SET_POINTS(ncp_ranges);
@@ -101,6 +107,7 @@
 	&pldo_set_points,
 	&nldo_set_points,
 	&nldo1200_set_points,
+	&ln_ldo_set_points,
 	&smps_set_points,
 	&ftsmps_set_points,
 	&ncp_set_points,
@@ -190,6 +197,7 @@
 	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(L13,  "8921_l13",  NULL,          ln_ldo,   LDO_5,    0),
 	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),
@@ -264,8 +272,12 @@
 {
 	int real_id;
 
-	if (id >= RPM_VREG_ID_PM8921_L1_PC && id <= RPM_VREG_ID_PM8921_L23_PC)
+	if (id >= RPM_VREG_ID_PM8921_L1_PC && id <= RPM_VREG_ID_PM8921_L12_PC)
 		real_id = id - RPM_VREG_ID_PM8921_L1_PC;
+	else if (id >= RPM_VREG_ID_PM8921_L14_PC
+			&& id <= RPM_VREG_ID_PM8921_L23_PC)
+		real_id = id - RPM_VREG_ID_PM8921_L14_PC
+				+ RPM_VREG_ID_PM8921_L14;
 	else if (id >= RPM_VREG_ID_PM8921_L29_PC
 			&& id <= RPM_VREG_ID_PM8921_S4_PC)
 		real_id = id - RPM_VREG_ID_PM8921_L29_PC
diff --git a/arch/arm/mach-msm/rpm-regulator-private.h b/arch/arm/mach-msm/rpm-regulator-private.h
index c3ddc33..d55bd73 100644
--- a/arch/arm/mach-msm/rpm-regulator-private.h
+++ b/arch/arm/mach-msm/rpm-regulator-private.h
@@ -176,11 +176,16 @@
 
 #if defined(CONFIG_MSM_RPM_REGULATOR) && defined(CONFIG_ARCH_MSM8930)
 struct vreg_config *get_config_8930(void);
+struct vreg_config *get_config_8930_pm8917(void);
 #else
 static inline struct vreg_config *get_config_8930(void)
 {
 	return NULL;
 }
+static inline struct vreg_config *get_config_8930_pm8917(void)
+{
+	return NULL;
+}
 #endif
 
 #endif
diff --git a/arch/arm/mach-msm/rpm-regulator.c b/arch/arm/mach-msm/rpm-regulator.c
index 68ff55b..424a4fe 100644
--- a/arch/arm/mach-msm/rpm-regulator.c
+++ b/arch/arm/mach-msm/rpm-regulator.c
@@ -62,6 +62,7 @@
 	[RPM_VREG_VERSION_8960] = get_config_8960,
 	[RPM_VREG_VERSION_9615] = get_config_9615,
 	[RPM_VREG_VERSION_8930] = get_config_8930,
+	[RPM_VREG_VERSION_8930_PM8917] = get_config_8930_pm8917,
 };
 
 static struct rpm_regulator_consumer_mapping *consumer_map;
diff --git a/arch/arm/mach-msm/rpm-smd.c b/arch/arm/mach-msm/rpm-smd.c
index 0faafc8..a190342 100644
--- a/arch/arm/mach-msm/rpm-smd.c
+++ b/arch/arm/mach-msm/rpm-smd.c
@@ -62,9 +62,10 @@
 
 #define DEFAULT_BUFFER_SIZE 256
 #define GFP_FLAG(noirq) (noirq ? GFP_ATOMIC : GFP_KERNEL)
-#define INV_HDR "resource does not exist"
+#define INV_RSC "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;
@@ -171,8 +172,10 @@
 	int i;
 	int data_size, msg_size;
 
-	if (!handle)
+	if (!handle) {
+		pr_err("%s(): Invalid handle\n", __func__);
 		return -EINVAL;
+	}
 
 	data_size = ALIGN(size, SZ_4);
 	msg_size = data_size + sizeof(struct rpm_request_header);
@@ -190,8 +193,11 @@
 		break;
 	}
 
-	if (i >= handle->num_elements)
+	if (i >= handle->num_elements) {
+		pr_err("%s(): Number of resources exceeds max allocated\n",
+				__func__);
 		return -ENOMEM;
+	}
 
 	if (i == handle->write_idx)
 		handle->write_idx++;
@@ -199,8 +205,10 @@
 	if (!handle->kvp[i].value) {
 		handle->kvp[i].value = kzalloc(data_size, GFP_FLAG(noirq));
 
-		if (!handle->kvp[i].value)
+		if (!handle->kvp[i].value) {
+			pr_err("%s(): Failed malloc\n", __func__);
 			return -ENOMEM;
+		}
 	} else {
 		/* We enter the else case, if a key already exists but the
 		 * data doesn't match. In which case, we should zero the data
@@ -365,13 +373,20 @@
 	return elem;
 }
 
-static int msm_rpm_get_next_msg_id(void)
+static uint32_t msm_rpm_get_next_msg_id(void)
 {
-	int id;
+	uint32_t id;
+
+	/*
+	 * A message id of 0 is used by the driver to indicate a error
+	 * condition. The RPM driver uses a id of 1 to indicate unsent data
+	 * when the data sent over hasn't been modified. This isn't a error
+	 * scenario and wait for ack returns a success when the message id is 1.
+	 */
 
 	do {
 		id = atomic_inc_return(&msm_rpm_msg_id);
-	} while ((id == 0) || msm_rpm_get_entry_from_msg_id(id));
+	} while ((id == 0) || (id == 1) || msm_rpm_get_entry_from_msg_id(id));
 
 	return id;
 }
@@ -388,6 +403,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);
@@ -457,25 +473,30 @@
 
 	tmp += 2 * sizeof(uint32_t);
 
-	if (!(memcmp(tmp, INV_HDR, min(req_len, sizeof(INV_HDR))-1)))
+	if (!(memcmp(tmp, INV_RSC, min(req_len, sizeof(INV_RSC))-1))) {
+		pr_err("%s(): RPM NACK Unsupported resource\n", __func__);
 		rc = -EINVAL;
+	} else {
+		pr_err("%s(): RPM NACK Invalid header\n", __func__);
+	}
 
 	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;
 
 	pkt_sz = smd_cur_packet_size(msm_rpm_data.ch_info);
 
+	if (!pkt_sz)
+		return -EAGAIN;
+
 	BUG_ON(pkt_sz > MAX_ERR_BUFFER_SIZE);
 
 	if (pkt_sz != smd_read_avail(msm_rpm_data.ch_info))
-		return;
-
-	BUG_ON(pkt_sz == 0);
+		return -EAGAIN;
 
 	do {
 		int len;
@@ -487,6 +508,8 @@
 	} while (pkt_sz > 0);
 
 	BUG_ON(pkt_sz < 0);
+
+	return 0;
 }
 
 static void msm_rpm_smd_work(struct work_struct *work)
@@ -498,11 +521,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);
 	}
 }
 
@@ -650,7 +677,8 @@
 	int req_hdr_sz, msg_hdr_sz;
 
 	if (!cdata->msg_hdr.data_len)
-		return 0;
+		return 1;
+
 	req_hdr_sz = sizeof(cdata->req_hdr);
 	msg_hdr_sz = sizeof(cdata->msg_hdr);
 
@@ -668,8 +696,10 @@
 		cdata->buf = kzalloc(msg_size, GFP_FLAG(noirq));
 	}
 
-	if (!cdata->buf)
+	if (!cdata->buf) {
+		pr_err("%s(): Failed malloc\n", __func__);
 		return 0;
+	}
 
 	tmpbuff = cdata->buf;
 
@@ -714,7 +744,7 @@
 	ret = smd_write_avail(msm_rpm_data.ch_info);
 
 	if (ret < 0) {
-		pr_warn("%s(): SMD not initialized\n", __func__);
+		pr_err("%s(): SMD not initialized\n", __func__);
 		spin_unlock_irqrestore(&msm_rpm_data.smd_lock_write, flags);
 		return 0;
 	}
@@ -741,7 +771,7 @@
 	} else if (ret < msg_size) {
 		struct msm_rpm_wait_data *rc;
 		ret = 0;
-		pr_info("Failed to write data msg_size:%d ret:%d\n",
+		pr_err("Failed to write data msg_size:%d ret:%d\n",
 				msg_size, ret);
 		rc = msm_rpm_get_entry_from_msg_id(cdata->msg_hdr.msg_id);
 		if (rc)
@@ -765,10 +795,14 @@
 int msm_rpm_wait_for_ack(uint32_t msg_id)
 {
 	struct msm_rpm_wait_data *elem;
-	int rc = 0;
 
-	if (!msg_id)
-		return -EINVAL;
+	if (!msg_id) {
+		pr_err("%s(): Invalid msg id\n", __func__);
+		return -ENOMEM;
+	}
+
+	if (msg_id == 1)
+		return 0;
 
 	if (standalone)
 		return 0;
@@ -777,15 +811,9 @@
 	if (!elem)
 		return 0;
 
-	rc = wait_for_completion_timeout(&elem->ack, msecs_to_jiffies(1));
-	if (!rc) {
-		pr_warn("%s(): Timed out after 1 ms\n", __func__);
-		rc = -ETIMEDOUT;
-	} else {
-		rc = elem->errno;
-		msm_rpm_free_list_entry(elem);
-	}
-	return rc;
+	wait_for_completion(&elem->ack);
+	msm_rpm_free_list_entry(elem);
+	return elem->errno;
 }
 EXPORT_SYMBOL(msm_rpm_wait_for_ack);
 
@@ -795,10 +823,14 @@
 	unsigned long flags;
 	int rc = 0;
 	uint32_t id = 0;
-	int count = 0;
 
-	if (!msg_id)
-		return -EINVAL;
+	if (!msg_id)  {
+		pr_err("%s(): Invalid msg id\n", __func__);
+		return -ENOMEM;
+	}
+
+	if (msg_id == 1)
+		return 0;
 
 	if (standalone)
 		return 0;
@@ -814,7 +846,13 @@
 		 */
 		goto wait_ack_cleanup;
 
-	while ((id != msg_id) && (count++ < 10)) {
+	if (elem->errno != INIT_ERROR) {
+		rc = elem->errno;
+		msm_rpm_free_list_entry(elem);
+		goto wait_ack_cleanup;
+	}
+
+	while (id != msg_id) {
 		if (smd_is_pkt_avail(msm_rpm_data.ch_info)) {
 			int errno;
 			char buf[MAX_ERR_BUFFER_SIZE] = {};
@@ -823,17 +861,11 @@
 			id = msm_rpm_get_msg_id_from_ack(buf);
 			errno = msm_rpm_get_error_from_ack(buf);
 			msm_rpm_process_ack(id, errno);
-		} else
-			udelay(100);
+		}
 	}
 
-	if (count == 10) {
-		rc = -ETIMEDOUT;
-		pr_warn("%s(): Timed out after 1ms\n", __func__);
-	} else {
-		rc = elem->errno;
-		msm_rpm_free_list_entry(elem);
-	}
+	rc = elem->errno;
+	msm_rpm_free_list_entry(elem);
 wait_ack_cleanup:
 	irq_process = false;
 	spin_unlock_irqrestore(&msm_rpm_data.smd_lock_read, flags);
@@ -950,10 +982,7 @@
 		complete(&msm_rpm_data.smd_open);
 	}
 
-	ret = wait_for_completion_timeout(&msm_rpm_data.smd_open,
-			msecs_to_jiffies(5));
-
-	BUG_ON(!ret);
+	wait_for_completion(&msm_rpm_data.smd_open);
 
 	smd_disable_read_intr(msm_rpm_data.ch_info);
 
diff --git a/arch/arm/mach-msm/scm-boot.c b/arch/arm/mach-msm/scm-boot.c
index e377633..01d0853 100644
--- a/arch/arm/mach-msm/scm-boot.c
+++ b/arch/arm/mach-msm/scm-boot.c
@@ -19,11 +19,11 @@
 /*
  * Set the cold/warm boot address for one of the CPU cores.
  */
-int scm_set_boot_addr(void *addr, int flags)
+int scm_set_boot_addr(phys_addr_t addr, unsigned int flags)
 {
 	struct {
 		unsigned int flags;
-		void *addr;
+		unsigned long addr;
 	} cmd;
 
 	cmd.addr = addr;
diff --git a/arch/arm/mach-msm/scm-boot.h b/arch/arm/mach-msm/scm-boot.h
index 221ffca..0d0e6aa 100644
--- a/arch/arm/mach-msm/scm-boot.h
+++ b/arch/arm/mach-msm/scm-boot.h
@@ -22,9 +22,12 @@
 #define SCM_FLAG_WARMBOOT_CPU3		0x40
 
 #ifdef CONFIG_MSM_SCM
-int scm_set_boot_addr(void *addr, int flags);
+int scm_set_boot_addr(phys_addr_t addr, unsigned int flags);
 #else
-static inline int scm_set_boot_addr(void *addr, int flags) { return 0; }
+static inline int scm_set_boot_addr(phys_addr_t addr, unsigned int flags)
+{
+	return 0;
+}
 #endif
 
 #endif
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index decee95..e33f87b 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -361,9 +361,15 @@
 static DEFINE_MUTEX(smsm_lock);
 static struct smsm_state_info *smsm_states;
 static int spinlocks_initialized;
-static RAW_NOTIFIER_HEAD(smsm_driver_state_notifier_list);
-static DEFINE_MUTEX(smsm_driver_state_notifier_lock);
-static void smsm_driver_state_notify(uint32_t state, void *data);
+
+/**
+ * Variables to indicate smd module initialization.
+ * Dependents to register for smd module init notifier.
+ */
+static int smd_module_inited;
+static RAW_NOTIFIER_HEAD(smd_module_init_notifier_list);
+static DEFINE_MUTEX(smd_module_init_notifier_lock);
+static void smd_module_init_notify(uint32_t state, void *data);
 
 static inline void smd_write_intr(unsigned int val,
 				const void __iomem *addr)
@@ -372,24 +378,6 @@
 	__raw_writel(val, addr);
 }
 
-#ifdef CONFIG_WCNSS
-static inline void wakeup_v1_riva(void)
-{
-	/*
-	 * workaround hack for RIVA v1 hardware bug
-	 * trigger GPIO 40 to wake up RIVA from power collaspe
-	 * not to be sent to customers
-	 */
-	if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 1) {
-		__raw_writel(0x0, MSM_TLMM_BASE + 0x1284);
-		__raw_writel(0x2, MSM_TLMM_BASE + 0x1284);
-	}
-	/* end workaround */
-}
-#else
-static inline void wakeup_v1_riva(void) {}
-#endif
-
 static inline void notify_modem_smd(void)
 {
 	static const struct interrupt_config_item *intr
@@ -436,7 +424,6 @@
 {
 	static const struct interrupt_config_item *intr
 		= &private_intr_config[SMD_WCNSS].smd;
-	wakeup_v1_riva();
 
 	if (intr->out_base) {
 		++interrupt_stats[SMD_WCNSS].smd_out_config_count;
@@ -506,7 +493,6 @@
 {
 	static const struct interrupt_config_item *intr
 		= &private_intr_config[SMD_WCNSS].smsm;
-	wakeup_v1_riva();
 
 	if (intr->out_base) {
 		++interrupt_stats[SMD_WCNSS].smsm_out_config_count;
@@ -796,17 +782,21 @@
  * @pid:       Processor ID of processor on edge
  * @local_ch:  Channel that belongs to processor @pid
  * @remote_ch: Other side of edge contained @pid
+ * @is_word_access_ch: Bool, is this a word aligned access channel
  *
  * Returns 0 for not on edge, 1 for found on edge
  */
-static int pid_is_on_edge(struct smd_shared_v2 *shared2,
+static int pid_is_on_edge(void *shared2,
 		uint32_t type, uint32_t pid,
-		struct smd_half_channel **local_ch,
-		struct smd_half_channel **remote_ch
+		void **local_ch,
+		void **remote_ch,
+		int is_word_access_ch
 		)
 {
 	int ret = 0;
 	struct edge_to_pid *edge;
+	void *ch0;
+	void *ch1;
 
 	*local_ch = 0;
 	*remote_ch = 0;
@@ -814,15 +804,23 @@
 	if (!shared2 || (type >= ARRAY_SIZE(edge_to_pids)))
 		return 0;
 
+	if (is_word_access_ch) {
+		ch0 = &((struct smd_shared_v2_word_access *)(shared2))->ch0;
+		ch1 = &((struct smd_shared_v2_word_access *)(shared2))->ch1;
+	} else {
+		ch0 = &((struct smd_shared_v2 *)(shared2))->ch0;
+		ch1 = &((struct smd_shared_v2 *)(shared2))->ch1;
+	}
+
 	edge = &edge_to_pids[type];
 	if (edge->local_pid != edge->remote_pid) {
 		if (pid == edge->local_pid) {
-			*local_ch = &shared2->ch0;
-			*remote_ch = &shared2->ch1;
+			*local_ch = ch0;
+			*remote_ch = ch1;
 			ret = 1;
 		} else if (pid == edge->remote_pid) {
-			*local_ch = &shared2->ch1;
-			*remote_ch = &shared2->ch0;
+			*local_ch = ch1;
+			*remote_ch = ch0;
 			ret = 1;
 		}
 	}
@@ -874,14 +872,29 @@
 }
 EXPORT_SYMBOL(smd_pid_to_subsystem);
 
-static void smd_reset_edge(struct smd_half_channel *ch, unsigned new_state)
+static void smd_reset_edge(void *void_ch, unsigned new_state,
+				int is_word_access_ch)
 {
-	if (ch->state != SMD_SS_CLOSED) {
-		ch->state = new_state;
-		ch->fDSR = 0;
-		ch->fCTS = 0;
-		ch->fCD = 0;
-		ch->fSTATE = 1;
+	if (is_word_access_ch) {
+		struct smd_half_channel_word_access *ch =
+			(struct smd_half_channel_word_access *)(void_ch);
+		if (ch->state != SMD_SS_CLOSED) {
+			ch->state = new_state;
+			ch->fDSR = 0;
+			ch->fCTS = 0;
+			ch->fCD = 0;
+			ch->fSTATE = 1;
+		}
+	} else {
+		struct smd_half_channel *ch =
+			(struct smd_half_channel *)(void_ch);
+		if (ch->state != SMD_SS_CLOSED) {
+			ch->state = new_state;
+			ch->fDSR = 0;
+			ch->fCTS = 0;
+			ch->fCD = 0;
+			ch->fSTATE = 1;
+		}
 	}
 }
 
@@ -889,10 +902,11 @@
 		unsigned new_state, unsigned pid)
 {
 	unsigned n;
-	struct smd_shared_v2 *shared2;
+	void *shared2;
 	uint32_t type;
-	struct smd_half_channel *local_ch;
-	struct smd_half_channel *remote_ch;
+	void *local_ch;
+	void *remote_ch;
+	int is_word_access;
 
 	for (n = 0; n < SMD_CHANNELS; n++) {
 		if (!shared[n].ref_count)
@@ -901,12 +915,19 @@
 			continue;
 
 		type = SMD_CHANNEL_TYPE(shared[n].type);
-		shared2 = smem_alloc(SMEM_SMD_BASE_ID + n, sizeof(*shared2));
+		is_word_access = is_word_access_ch(type);
+		if (is_word_access)
+			shared2 = smem_alloc(SMEM_SMD_BASE_ID + n,
+				sizeof(struct smd_shared_v2_word_access));
+		else
+			shared2 = smem_alloc(SMEM_SMD_BASE_ID + n,
+				sizeof(struct smd_shared_v2));
 		if (!shared2)
 			continue;
 
-		if (pid_is_on_edge(shared2, type, pid, &local_ch, &remote_ch))
-			smd_reset_edge(local_ch, new_state);
+		if (pid_is_on_edge(shared2, type, pid, &local_ch, &remote_ch,
+							is_word_access))
+			smd_reset_edge(local_ch, new_state, is_word_access);
 
 		/*
 		 * ModemFW is in the same subsystem as ModemSW, but has
@@ -914,8 +935,8 @@
 		 */
 		if (pid == SMSM_MODEM &&
 				pid_is_on_edge(shared2, type, SMD_MODEM_Q6_FW,
-				 &local_ch, &remote_ch))
-			smd_reset_edge(local_ch, new_state);
+				 &local_ch, &remote_ch, is_word_access))
+			smd_reset_edge(local_ch, new_state, is_word_access);
 	}
 }
 
@@ -926,16 +947,17 @@
 	unsigned long flags;
 
 	SMD_DBG("%s: starting reset\n", __func__);
+
+	/* release any held spinlocks */
+	remote_spin_release(&remote_spinlock, restart_pid);
+	remote_spin_release_all(restart_pid);
+
 	shared = smem_find(ID_CH_ALLOC_TBL, sizeof(*shared) * 64);
 	if (!shared) {
 		pr_err("%s: allocation table not initialized\n", __func__);
 		return;
 	}
 
-	/* release any held spinlocks */
-	remote_spin_release(&remote_spinlock, restart_pid);
-	remote_spin_release_all(restart_pid);
-
 	/* reset SMSM entry */
 	if (smsm_info.state) {
 		writel_relaxed(0, SMSM_STATE_ADDR(restart_pid));
@@ -2264,13 +2286,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;
 }
@@ -2461,13 +2487,6 @@
 	int i;
 	struct smsm_size_info_type *smsm_size_info;
 
-	i = remote_spin_lock_init(&remote_spinlock, SMEM_SPINLOCK_SMEM_ALLOC);
-	if (i) {
-		pr_err("%s: remote spinlock init failed %d\n", __func__, i);
-		return i;
-	}
-	spinlocks_initialized = 1;
-
 	smsm_size_info = smem_alloc(SMEM_SMSM_SIZE_INFO,
 				sizeof(struct smsm_size_info_type));
 	if (smsm_size_info) {
@@ -2526,7 +2545,6 @@
 		return i;
 
 	wmb();
-	smsm_driver_state_notify(SMSM_INIT, NULL);
 	return 0;
 }
 
@@ -3100,37 +3118,40 @@
 }
 EXPORT_SYMBOL(smsm_state_cb_deregister);
 
-int smsm_driver_state_notifier_register(struct notifier_block *nb)
+int smd_module_init_notifier_register(struct notifier_block *nb)
 {
 	int ret;
 	if (!nb)
 		return -EINVAL;
-	mutex_lock(&smsm_driver_state_notifier_lock);
-	ret = raw_notifier_chain_register(&smsm_driver_state_notifier_list, nb);
-	mutex_unlock(&smsm_driver_state_notifier_lock);
+	mutex_lock(&smd_module_init_notifier_lock);
+	ret = raw_notifier_chain_register(&smd_module_init_notifier_list, nb);
+	if (smd_module_inited)
+		nb->notifier_call(nb, 0, NULL);
+	mutex_unlock(&smd_module_init_notifier_lock);
 	return ret;
 }
-EXPORT_SYMBOL(smsm_driver_state_notifier_register);
+EXPORT_SYMBOL(smd_module_init_notifier_register);
 
-int smsm_driver_state_notifier_unregister(struct notifier_block *nb)
+int smd_module_init_notifier_unregister(struct notifier_block *nb)
 {
 	int ret;
 	if (!nb)
 		return -EINVAL;
-	mutex_lock(&smsm_driver_state_notifier_lock);
-	ret = raw_notifier_chain_unregister(&smsm_driver_state_notifier_list,
+	mutex_lock(&smd_module_init_notifier_lock);
+	ret = raw_notifier_chain_unregister(&smd_module_init_notifier_list,
 					    nb);
-	mutex_unlock(&smsm_driver_state_notifier_lock);
+	mutex_unlock(&smd_module_init_notifier_lock);
 	return ret;
 }
-EXPORT_SYMBOL(smsm_driver_state_notifier_unregister);
+EXPORT_SYMBOL(smd_module_init_notifier_unregister);
 
-static void smsm_driver_state_notify(uint32_t state, void *data)
+static void smd_module_init_notify(uint32_t state, void *data)
 {
-	mutex_lock(&smsm_driver_state_notifier_lock);
-	raw_notifier_call_chain(&smsm_driver_state_notifier_list,
+	mutex_lock(&smd_module_init_notifier_lock);
+	smd_module_inited = 1;
+	raw_notifier_call_chain(&smd_module_init_notifier_list,
 				state, data);
-	mutex_unlock(&smsm_driver_state_notifier_lock);
+	mutex_unlock(&smd_module_init_notifier_lock);
 }
 
 int smd_core_init(void)
@@ -3543,12 +3564,29 @@
 int __init msm_smd_init(void)
 {
 	static bool registered;
+	int rc;
 
 	if (registered)
 		return 0;
 
 	registered = true;
-	return platform_driver_register(&msm_smd_driver);
+	rc = remote_spin_lock_init(&remote_spinlock, SMEM_SPINLOCK_SMEM_ALLOC);
+	if (rc) {
+		pr_err("%s: remote spinlock init failed %d\n", __func__, rc);
+		return rc;
+	}
+	spinlocks_initialized = 1;
+
+	rc = platform_driver_register(&msm_smd_driver);
+	if (rc) {
+		pr_err("%s: msm_smd_driver register failed %d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	smd_module_init_notify(0, NULL);
+
+	return 0;
 }
 
 module_init(msm_smd_init);
diff --git a/arch/arm/mach-msm/smd_pkt.c b/arch/arm/mach-msm/smd_pkt.c
index b9fe341..5962d71 100644
--- a/arch/arm/mach-msm/smd_pkt.c
+++ b/arch/arm/mach-msm/smd_pkt.c
@@ -143,6 +143,13 @@
 	if (msm_smd_pkt_debug_mask & SMD_PKT_POLL) \
 		pr_info("Poll: "x); \
 } while (0)
+
+#define E_SMD_PKT_SSR(x) \
+do { \
+	if (x->do_reset_notification) \
+		pr_err("%s notifying reset for smd_pkt_dev id:%d\n", \
+			__func__, x->i); \
+} while (0)
 #else
 #define D_STATUS(x...) do {} while (0)
 #define D_READ(x...) do {} while (0)
@@ -150,6 +157,7 @@
 #define D_READ_DUMP_BUFFER(prestr, cnt, buf) do {} while (0)
 #define D_WRITE_DUMP_BUFFER(prestr, cnt, buf) do {} while (0)
 #define D_POLL(x...) do {} while (0)
+#define E_SMD_PKT_SSR(x) do {} while (0)
 #endif
 
 static ssize_t open_timeout_store(struct device *d,
@@ -310,8 +318,7 @@
 
 	if (smd_pkt_devp->do_reset_notification) {
 		/* notify client that a reset occurred */
-		pr_err("%s notifying reset for smd_pkt_dev id:%d\n",
-			__func__, smd_pkt_devp->i);
+		E_SMD_PKT_SSR(smd_pkt_devp);
 		return notify_reset(smd_pkt_devp);
 	}
 	D_READ("Begin %s on smd_pkt_dev id:%d buffer_size %d\n",
@@ -327,8 +334,7 @@
 	mutex_lock(&smd_pkt_devp->rx_lock);
 	if (smd_pkt_devp->has_reset) {
 		mutex_unlock(&smd_pkt_devp->rx_lock);
-		pr_err("%s notifying reset for smd_pkt_dev id:%d\n",
-			__func__, smd_pkt_devp->i);
+		E_SMD_PKT_SSR(smd_pkt_devp);
 		return notify_reset(smd_pkt_devp);
 	}
 
@@ -377,8 +383,7 @@
 		if (r < 0) {
 			mutex_unlock(&smd_pkt_devp->rx_lock);
 			if (smd_pkt_devp->has_reset) {
-				pr_err("%s notifying reset for smd_pkt_dev"
-				       " id:%d\n", __func__, smd_pkt_devp->i);
+				E_SMD_PKT_SSR(smd_pkt_devp);
 				return notify_reset(smd_pkt_devp);
 			}
 			pr_err("%s Error while reading %d\n", __func__, r);
@@ -391,8 +396,7 @@
 				   smd_pkt_devp->has_reset);
 		if (smd_pkt_devp->has_reset) {
 			mutex_unlock(&smd_pkt_devp->rx_lock);
-			pr_err("%s notifying reset for smd_pkt_dev  id:%d\n",
-				__func__, smd_pkt_devp->i);
+			E_SMD_PKT_SSR(smd_pkt_devp);
 			return notify_reset(smd_pkt_devp);
 		}
 	} while (pkt_size != bytes_read);
@@ -444,8 +448,7 @@
 	}
 
 	if (smd_pkt_devp->do_reset_notification || smd_pkt_devp->has_reset) {
-		pr_err("%s notifying reset for smd_pkt_dev id:%d\n",
-			__func__, smd_pkt_devp->i);
+		E_SMD_PKT_SSR(smd_pkt_devp);
 		/* notify client that a reset occurred */
 		return notify_reset(smd_pkt_devp);
 	}
@@ -484,8 +487,7 @@
 
 		if (smd_pkt_devp->has_reset) {
 			mutex_unlock(&smd_pkt_devp->tx_lock);
-			pr_err("%s notifying reset for smd_pkt_dev id:%d\n",
-				__func__, smd_pkt_devp->i);
+			E_SMD_PKT_SSR(smd_pkt_devp);
 			return notify_reset(smd_pkt_devp);
 		} else {
 			r = smd_write_segment(smd_pkt_devp->ch,
@@ -494,9 +496,7 @@
 			if (r < 0) {
 				mutex_unlock(&smd_pkt_devp->tx_lock);
 				if (smd_pkt_devp->has_reset) {
-					pr_err("%s notifying reset for"
-					       " smd_pkt_dev id:%d\n",
-						__func__, smd_pkt_devp->i);
+					E_SMD_PKT_SSR(smd_pkt_devp);
 					return notify_reset(smd_pkt_devp);
 				}
 				pr_err("%s on smd_pkt_dev id:%d failed r:%d\n",
@@ -532,8 +532,6 @@
 	mutex_lock(&smd_pkt_devp->ch_lock);
 	if (smd_pkt_devp->has_reset || !smd_pkt_devp->ch) {
 		mutex_unlock(&smd_pkt_devp->ch_lock);
-		pr_err("%s notifying reset for smd_pkt_dev id:%d\n",
-			__func__, smd_pkt_devp->i);
 		return POLLERR;
 	}
 
diff --git a/arch/arm/mach-msm/smem_log.c b/arch/arm/mach-msm/smem_log.c
index 2e9a97c..fd8144a 100644
--- a/arch/arm/mach-msm/smem_log.c
+++ b/arch/arm/mach-msm/smem_log.c
@@ -2008,25 +2008,23 @@
 	return ret;
 }
 
-static int smsm_driver_state_notifier(struct notifier_block *this,
-				      unsigned long code,
-				      void *_cmd)
+static int smd_module_init_notifier(struct notifier_block *this,
+				    unsigned long code,
+				    void *_cmd)
 {
 	int ret = 0;
-	if (code & SMSM_INIT) {
-		if (!smem_log_initialized)
-			ret = smem_log_initialize();
-	}
+	if (!smem_log_initialized)
+		ret = smem_log_initialize();
 	return ret;
 }
 
 static struct notifier_block nb = {
-	.notifier_call = smsm_driver_state_notifier,
+	.notifier_call = smd_module_init_notifier,
 };
 
 static int __init smem_log_init(void)
 {
-	return smsm_driver_state_notifier_register(&nb);
+	return smd_module_init_notifier_register(&nb);
 }
 
 
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index 39fbba8..86de130 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -114,6 +114,14 @@
 	uint32_t hw_platform_subtype;
 };
 
+struct socinfo_v7 {
+	struct socinfo_v6 v6;
+
+	/* only valid when format==7 */
+	uint32_t pmic_model;
+	uint32_t pmic_die_revision;
+};
+
 static union {
 	struct socinfo_v1 v1;
 	struct socinfo_v2 v2;
@@ -121,6 +129,7 @@
 	struct socinfo_v4 v4;
 	struct socinfo_v5 v5;
 	struct socinfo_v6 v6;
+	struct socinfo_v7 v7;
 } *socinfo;
 
 static enum msm_cpu cpu_of_id[] = {
@@ -246,6 +255,7 @@
 	[127] = MSM_CPU_8625,
 	[128] = MSM_CPU_8625,
 	[129] = MSM_CPU_8625,
+	[137] = MSM_CPU_8625,
 
 	/* 8064 MPQ ID */
 	[130] = MSM_CPU_8064,
@@ -270,6 +280,12 @@
 	[143] = MSM_CPU_8930AA,
 	[144] = MSM_CPU_8930AA,
 
+	/* 8226 IDs */
+	[145] = MSM_CPU_8226,
+
+	/* 8092 IDs */
+	[146] = MSM_CPU_8092,
+
 	/* Uninitialized IDs are not known to run Linux.
 	   MSM_CPU_UNKNOWN is set to 0 to ensure these IDs are
 	   considered as unknown CPU. */
@@ -343,6 +359,21 @@
 		: 0;
 }
 
+enum pmic_model socinfo_get_pmic_model(void)
+{
+	return socinfo ?
+		(socinfo->v1.format >= 7 ? socinfo->v7.pmic_model
+			: PMIC_MODEL_UNKNOWN)
+		: PMIC_MODEL_UNKNOWN;
+}
+
+uint32_t socinfo_get_pmic_die_revision(void)
+{
+	return socinfo ?
+		(socinfo->v1.format >= 7 ? socinfo->v7.pmic_die_revision : 0)
+		: 0;
+}
+
 enum msm_cpu socinfo_get_msm_cpu(void)
 {
 	return cur_cpu;
@@ -515,6 +546,42 @@
 		hw_platform_subtype[hw_subtype]);
 }
 
+static ssize_t
+socinfo_show_pmic_model(struct sys_device *dev,
+			struct sysdev_attribute *attr,
+			char *buf)
+{
+	if (!socinfo) {
+		pr_err("%s: No socinfo found!\n", __func__);
+		return 0;
+	}
+	if (socinfo->v1.format < 7) {
+		pr_err("%s: pmic_model not available!\n", __func__);
+		return 0;
+	}
+
+	return snprintf(buf, PAGE_SIZE, "%u\n",
+		socinfo_get_pmic_model());
+}
+
+static ssize_t
+socinfo_show_pmic_die_revision(struct sys_device *dev,
+			       struct sysdev_attribute *attr,
+			       char *buf)
+{
+	if (!socinfo) {
+		pr_err("%s: No socinfo found!\n", __func__);
+		return 0;
+	}
+	if (socinfo->v1.format < 7) {
+		pr_err("%s: pmic_die_revision not available!\n", __func__);
+		return 0;
+	}
+
+	return snprintf(buf, PAGE_SIZE, "%u\n",
+		socinfo_get_pmic_die_revision());
+}
+
 static struct sysdev_attribute socinfo_v1_files[] = {
 	_SYSDEV_ATTR(id, 0444, socinfo_show_id, NULL),
 	_SYSDEV_ATTR(version, 0444, socinfo_show_version, NULL),
@@ -545,6 +612,13 @@
 			socinfo_show_platform_subtype, NULL),
 };
 
+static struct sysdev_attribute socinfo_v7_files[] = {
+	_SYSDEV_ATTR(pmic_model, 0444,
+			socinfo_show_pmic_model, NULL),
+	_SYSDEV_ATTR(pmic_die_revision, 0444,
+			socinfo_show_pmic_die_revision, NULL),
+};
+
 static struct sysdev_class soc_sysdev_class = {
 	.name = "soc",
 };
@@ -619,9 +693,14 @@
 	if (socinfo->v1.format < 6)
 		return err;
 
-	return socinfo_create_files(&soc_sys_device, socinfo_v6_files,
+	socinfo_create_files(&soc_sys_device, socinfo_v6_files,
 				ARRAY_SIZE(socinfo_v6_files));
 
+	if (socinfo->v1.format < 7)
+		return err;
+
+	return socinfo_create_files(&soc_sys_device, socinfo_v7_files,
+				ARRAY_SIZE(socinfo_v7_files));
 }
 
 arch_initcall(socinfo_init_sysdev);
@@ -640,8 +719,17 @@
 		dummy_socinfo.id = 134;
 		strlcpy(dummy_socinfo.build_id, "msm9625 - ",
 			sizeof(dummy_socinfo.build_id));
+	} else if (early_machine_is_msm8226()) {
+		dummy_socinfo.id = 145;
+		strlcpy(dummy_socinfo.build_id, "msm8226 - ",
+			sizeof(dummy_socinfo.build_id));
 	} else if (machine_is_msm8625_rumi3())
 		dummy_socinfo.id = 127;
+	else if (early_machine_is_mpq8092()) {
+		dummy_socinfo.id = 146;
+		strlcpy(dummy_socinfo.build_id, "mpq8092 - ",
+		sizeof(dummy_socinfo.build_id));
+	}
 	strlcat(dummy_socinfo.build_id, "Dummy socinfo",
 		sizeof(dummy_socinfo.build_id));
 	return (void *) &dummy_socinfo;
@@ -649,7 +737,11 @@
 
 int __init socinfo_init(void)
 {
-	socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID, sizeof(struct socinfo_v6));
+	socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID, sizeof(struct socinfo_v7));
+
+	if (!socinfo)
+		socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID,
+				sizeof(struct socinfo_v6));
 
 	if (!socinfo)
 		socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID,
@@ -741,6 +833,20 @@
 			socinfo->v5.accessory_chip,
 			socinfo->v6.hw_platform_subtype);
 		break;
+	case 7:
+		pr_info("%s: v%u, id=%u, ver=%u.%u, raw_id=%u, raw_ver=%u, hw_plat=%u, hw_plat_ver=%u\n accessory_chip=%u, hw_plat_subtype=%u, pmic_model=%u, pmic_die_revision=%u\n",
+			__func__,
+			socinfo->v1.format,
+			socinfo->v1.id,
+			SOCINFO_VERSION_MAJOR(socinfo->v1.version),
+			SOCINFO_VERSION_MINOR(socinfo->v1.version),
+			socinfo->v2.raw_id, socinfo->v2.raw_version,
+			socinfo->v3.hw_platform, socinfo->v4.platform_version,
+			socinfo->v5.accessory_chip,
+			socinfo->v6.hw_platform_subtype,
+			socinfo->v7.pmic_model,
+			socinfo->v7.pmic_die_revision);
+		break;
 	default:
 		pr_err("%s: Unknown format found\n", __func__);
 		break;
@@ -830,3 +936,17 @@
 		return 0;
 	};
 }
+
+const int cpu_is_krait_v3(void)
+{
+	switch (read_cpuid_id()) {
+	case 0x512F04D0:
+	case 0x511F06F0:
+	case 0x511F06F1:
+	case 0x510F05D0:
+		return 1;
+
+	default:
+		return 0;
+	};
+}
diff --git a/arch/arm/mach-msm/spm-v2.c b/arch/arm/mach-msm/spm-v2.c
index b6d5324..26dfdff 100644
--- a/arch/arm/mach-msm/spm-v2.c
+++ b/arch/arm/mach-msm/spm-v2.c
@@ -139,6 +139,10 @@
 
 	dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_DATA_1] &= ~0x3F;
 	dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_DATA_1] |= (vlevel & 0x3F);
+
+	dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_DATA_1] &= ~0x3F0000;
+	dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_DATA_1] |=
+						((vlevel & 0x3F) << 16);
 }
 
 static inline void msm_spm_drv_set_vctl2(struct msm_spm_driver_data *dev,
@@ -151,9 +155,6 @@
 
 	dev->reg_shadow[MSM_SPM_REG_SAW2_VCTL] &= ~0x700FF;
 	dev->reg_shadow[MSM_SPM_REG_SAW2_VCTL] |= pmic_data;
-
-	dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_DATA_0] &= ~0x700FF;
-	dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_DATA_0] |= pmic_data;
 }
 
 static inline void msm_spm_drv_apcs_set_vctl(struct msm_spm_driver_data *dev,
diff --git a/arch/arm/mach-msm/spm_devices.c b/arch/arm/mach-msm/spm_devices.c
index 9e9b661..05d11d2 100644
--- a/arch/arm/mach-msm/spm_devices.c
+++ b/arch/arm/mach-msm/spm_devices.c
@@ -247,10 +247,10 @@
 		{"qcom,saw2-cfg", MSM_SPM_REG_SAW2_CFG},
 		{"qcom,saw2-avs-ctl", MSM_SPM_REG_SAW2_AVS_CTL},
 		{"qcom,saw2-avs-hysteresis", MSM_SPM_REG_SAW2_AVS_HYSTERESIS},
-		{"qcom,saw2-spm-ctl", MSM_SPM_REG_SAW2_SPM_CTL},
-		{"qcom,saw2-pmic-dly", MSM_SPM_REG_SAW2_PMIC_DLY},
 		{"qcom,saw2-avs-limit", MSM_SPM_REG_SAW2_AVS_LIMIT},
+		{"qcom,saw2-avs-dly", MSM_SPM_REG_SAW2_AVS_DLY},
 		{"qcom,saw2-spm-dly", MSM_SPM_REG_SAW2_SPM_DLY},
+		{"qcom,saw2-spm-ctl", MSM_SPM_REG_SAW2_SPM_CTL},
 		{"qcom,saw2-pmic-data0", MSM_SPM_REG_SAW2_PMIC_DATA_0},
 		{"qcom,saw2-pmic-data1", MSM_SPM_REG_SAW2_PMIC_DATA_1},
 		{"qcom,saw2-pmic-data2", MSM_SPM_REG_SAW2_PMIC_DATA_2},
diff --git a/arch/arm/mach-msm/subsystem_restart.c b/arch/arm/mach-msm/subsystem_restart.c
index 65da903..0318a70 100644
--- a/arch/arm/mach-msm/subsystem_restart.c
+++ b/arch/arm/mach-msm/subsystem_restart.c
@@ -27,6 +27,9 @@
 #include <linux/mutex.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/idr.h>
+#include <linux/debugfs.h>
 
 #include <asm/current.h>
 
@@ -52,31 +55,77 @@
 	struct list_head list;
 };
 
+enum subsys_state {
+	SUBSYS_OFFLINE,
+	SUBSYS_ONLINE,
+};
+
+static const char * const subsys_states[] = {
+	[SUBSYS_OFFLINE] = "OFFLINE",
+	[SUBSYS_ONLINE] = "ONLINE",
+};
+
 struct subsys_device {
 	struct subsys_desc *desc;
-	struct list_head list;
 	struct wake_lock wake_lock;
 	char wlname[64];
 	struct work_struct work;
 	spinlock_t restart_lock;
-	bool restarting;
+	int restart_count;
 
 	void *notify;
+	struct device dev;
+	struct module *owner;
+	int count;
+	enum subsys_state state;
+	int id;
 
 	struct mutex shutdown_lock;
 	struct mutex powerup_lock;
 
 	void *restart_order;
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dentry;
+#endif
 };
 
+static struct subsys_device *to_subsys(struct device *d)
+{
+	return container_of(d, struct subsys_device, dev);
+}
+
+static ssize_t name_show(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%s\n", to_subsys(dev)->desc->name);
+}
+
+static ssize_t state_show(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	enum subsys_state state = to_subsys(dev)->state;
+	return snprintf(buf, PAGE_SIZE, "%s\n", subsys_states[state]);
+}
+
+static struct device_attribute subsys_attrs[] = {
+	__ATTR_RO(name),
+	__ATTR_RO(state),
+	__ATTR_NULL,
+};
+
+static struct bus_type subsys_bus_type = {
+	.name		= "msm_subsys",
+	.dev_attrs	= subsys_attrs,
+};
+
+static DEFINE_IDA(subsys_ida);
+
 static int enable_ramdumps;
 module_param(enable_ramdumps, int, S_IRUGO | S_IWUSR);
 
 struct workqueue_struct *ssr_wq;
 
 static LIST_HEAD(restart_log_list);
-static LIST_HEAD(subsystem_list);
-static DEFINE_MUTEX(subsystem_list_lock);
 static DEFINE_MUTEX(soc_order_reg_lock);
 static DEFINE_MUTEX(restart_log_mutex);
 
@@ -101,28 +150,16 @@
 static const char * const _order_8x60_modems[] = {"external_modem", "modem"};
 DEFINE_SINGLE_RESTART_ORDER(orders_8x60_modems, _order_8x60_modems);
 
-/* MSM 8960 restart ordering info */
-static const char * const order_8960[] = {"modem", "lpass"};
 /*SGLTE restart ordering info*/
 static const char * const order_8960_sglte[] = {"external_modem",
 						"modem"};
 
-static struct subsys_soc_restart_order restart_orders_8960_one = {
-	.subsystem_list = order_8960,
-	.count = ARRAY_SIZE(order_8960),
-	.subsys_ptrs = {[ARRAY_SIZE(order_8960)] = NULL}
-	};
-
 static struct subsys_soc_restart_order restart_orders_8960_fusion_sglte = {
 	.subsystem_list = order_8960_sglte,
 	.count = ARRAY_SIZE(order_8960_sglte),
 	.subsys_ptrs = {[ARRAY_SIZE(order_8960_sglte)] = NULL}
 	};
 
-static struct subsys_soc_restart_order *restart_orders_8960[] = {
-	&restart_orders_8960_one,
-	};
-
 static struct subsys_soc_restart_order *restart_orders_8960_sglte[] = {
 	&restart_orders_8960_fusion_sglte,
 	};
@@ -156,9 +193,13 @@
 		return ret;
 
 	switch (restart_level) {
-	case RESET_SOC:
-	case RESET_SUBSYS_COUPLED:
 	case RESET_SUBSYS_INDEPENDENT:
+		if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE) {
+			pr_info("Phase 3 is currently unsupported. Using phase 2 instead.\n");
+			restart_level = RESET_SUBSYS_COUPLED;
+		}
+	case RESET_SUBSYS_COUPLED:
+	case RESET_SOC:
 		pr_info("Phase %d behavior activated.\n", restart_level);
 		break;
 	default:
@@ -312,6 +353,24 @@
 		panic("[%p]: Failed to powerup %s!", current, name);
 }
 
+static int __find_subsys(struct device *dev, void *data)
+{
+	struct subsys_device *subsys = to_subsys(dev);
+	return !strcmp(subsys->desc->name, data);
+}
+
+static struct subsys_device *find_subsys(const char *str)
+{
+	struct device *dev;
+
+	if (!str)
+		return NULL;
+
+	dev = bus_find_device(&subsys_bus_type, NULL, (void *)str,
+			__find_subsys);
+	return dev ? to_subsys(dev) : NULL;
+}
+
 static void subsystem_restart_wq_func(struct work_struct *work)
 {
 	struct subsys_device *dev = container_of(work,
@@ -406,8 +465,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);
 }
 
@@ -416,22 +476,36 @@
 	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)
 {
-	const char *name = dev->desc->name;
+	const char *name;
 
+	if (!get_device(&dev->dev))
+		return -ENODEV;
+
+	if (!try_module_get(dev->owner)) {
+		put_device(&dev->dev);
+		return -ENODEV;
+	}
+
+	name = dev->desc->name;
 	pr_info("Restart sequence requested for %s, restart_level = %d.\n",
 		name, restart_level);
 
@@ -448,6 +522,8 @@
 		panic("subsys-restart: Unknown restart level!\n");
 		break;
 	}
+	module_put(dev->owner);
+	put_device(&dev->dev);
 
 	return 0;
 }
@@ -455,69 +531,192 @@
 
 int subsystem_restart(const char *name)
 {
-	struct subsys_device *dev;
+	int ret;
+	struct subsys_device *dev = find_subsys(name);
 
-	mutex_lock(&subsystem_list_lock);
-	list_for_each_entry(dev, &subsystem_list, list)
-		if (!strncmp(dev->desc->name, name, SUBSYS_NAME_MAX_LENGTH))
-			goto found;
-	dev = NULL;
-found:
-	mutex_unlock(&subsystem_list_lock);
-	if (dev)
-		return subsystem_restart_dev(dev);
-	return -ENODEV;
+	if (!dev)
+		return -ENODEV;
+
+	ret = subsystem_restart_dev(dev);
+	put_device(&dev->dev);
+	return ret;
 }
 EXPORT_SYMBOL(subsystem_restart);
 
+#ifdef CONFIG_DEBUG_FS
+static ssize_t subsys_debugfs_read(struct file *filp, char __user *ubuf,
+		size_t cnt, loff_t *ppos)
+{
+	int r;
+	char buf[40];
+	struct subsys_device *subsys = filp->private_data;
+
+	r = snprintf(buf, sizeof(buf), "%d\n", subsys->count);
+	return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
+}
+
+static ssize_t subsys_debugfs_write(struct file *filp,
+		const char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+	struct subsys_device *subsys = filp->private_data;
+	char buf[10];
+	char *cmp;
+
+	cnt = min(cnt, sizeof(buf) - 1);
+	if (copy_from_user(&buf, ubuf, cnt))
+		return -EFAULT;
+	buf[cnt] = '\0';
+	cmp = strstrip(buf);
+
+	if (!strcmp(cmp, "restart")) {
+		if (subsystem_restart_dev(subsys))
+			return -EIO;
+	} else {
+		return -EINVAL;
+	}
+
+	return cnt;
+}
+
+static const struct file_operations subsys_debugfs_fops = {
+	.open	= simple_open,
+	.read	= subsys_debugfs_read,
+	.write	= subsys_debugfs_write,
+};
+
+static struct dentry *subsys_base_dir;
+
+static int __init subsys_debugfs_init(void)
+{
+	subsys_base_dir = debugfs_create_dir("msm_subsys", NULL);
+	return !subsys_base_dir ? -ENOMEM : 0;
+}
+
+static void subsys_debugfs_exit(void)
+{
+	debugfs_remove_recursive(subsys_base_dir);
+}
+
+static int subsys_debugfs_add(struct subsys_device *subsys)
+{
+	if (!subsys_base_dir)
+		return -ENOMEM;
+
+	subsys->dentry = debugfs_create_file(subsys->desc->name,
+				S_IRUGO | S_IWUSR, subsys_base_dir,
+				subsys, &subsys_debugfs_fops);
+	return !subsys->dentry ? -ENOMEM : 0;
+}
+
+static void subsys_debugfs_remove(struct subsys_device *subsys)
+{
+	debugfs_remove(subsys->dentry);
+}
+#else
+static int __init subsys_debugfs_init(void) { return 0; };
+static void subsys_debugfs_exit(void) { }
+static int subsys_debugfs_add(struct subsys_device *subsys) { return 0; }
+static void subsys_debugfs_remove(struct subsys_device *subsys) { }
+#endif
+
+static void subsys_device_release(struct device *dev)
+{
+	struct subsys_device *subsys = to_subsys(dev);
+
+	wake_lock_destroy(&subsys->wake_lock);
+	mutex_destroy(&subsys->shutdown_lock);
+	mutex_destroy(&subsys->powerup_lock);
+	ida_simple_remove(&subsys_ida, subsys->id);
+	kfree(subsys);
+}
+
 struct subsys_device *subsys_register(struct subsys_desc *desc)
 {
-	struct subsys_device *dev;
+	struct subsys_device *subsys;
+	int ret;
 
-	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
-	if (!dev)
+	subsys = kzalloc(sizeof(*subsys), GFP_KERNEL);
+	if (!subsys)
 		return ERR_PTR(-ENOMEM);
 
-	dev->desc = desc;
-	dev->notify = subsys_notif_add_subsys(desc->name);
-	dev->restart_order = update_restart_order(dev);
+	subsys->desc = desc;
+	subsys->owner = desc->owner;
+	subsys->dev.parent = desc->dev;
+	subsys->dev.bus = &subsys_bus_type;
+	subsys->dev.release = subsys_device_release;
 
-	snprintf(dev->wlname, sizeof(dev->wlname), "ssr(%s)", desc->name);
-	wake_lock_init(&dev->wake_lock, WAKE_LOCK_SUSPEND, dev->wlname);
-	INIT_WORK(&dev->work, subsystem_restart_wq_func);
-	spin_lock_init(&dev->restart_lock);
+	subsys->notify = subsys_notif_add_subsys(desc->name);
+	subsys->restart_order = update_restart_order(subsys);
 
-	mutex_init(&dev->shutdown_lock);
-	mutex_init(&dev->powerup_lock);
+	snprintf(subsys->wlname, sizeof(subsys->wlname), "ssr(%s)", desc->name);
+	wake_lock_init(&subsys->wake_lock, WAKE_LOCK_SUSPEND, subsys->wlname);
+	INIT_WORK(&subsys->work, subsystem_restart_wq_func);
+	spin_lock_init(&subsys->restart_lock);
 
-	mutex_lock(&subsystem_list_lock);
-	list_add(&dev->list, &subsystem_list);
-	mutex_unlock(&subsystem_list_lock);
+	subsys->id = ida_simple_get(&subsys_ida, 0, 0, GFP_KERNEL);
+	if (subsys->id < 0) {
+		ret = subsys->id;
+		goto err_ida;
+	}
+	dev_set_name(&subsys->dev, "subsys%d", subsys->id);
 
-	return dev;
+	mutex_init(&subsys->shutdown_lock);
+	mutex_init(&subsys->powerup_lock);
+
+	ret = subsys_debugfs_add(subsys);
+	if (ret)
+		goto err_debugfs;
+
+	ret = device_register(&subsys->dev);
+	if (ret) {
+		put_device(&subsys->dev);
+		goto err_register;
+	}
+
+	return subsys;
+
+err_register:
+	subsys_debugfs_remove(subsys);
+err_debugfs:
+	mutex_destroy(&subsys->shutdown_lock);
+	mutex_destroy(&subsys->powerup_lock);
+	ida_simple_remove(&subsys_ida, subsys->id);
+err_ida:
+	wake_lock_destroy(&subsys->wake_lock);
+	kfree(subsys);
+	return ERR_PTR(ret);
 }
 EXPORT_SYMBOL(subsys_register);
 
-void subsys_unregister(struct subsys_device *dev)
+void subsys_unregister(struct subsys_device *subsys)
 {
-	if (IS_ERR_OR_NULL(dev))
+	if (IS_ERR_OR_NULL(subsys))
 		return;
-	mutex_lock(&subsystem_list_lock);
-	list_del(&dev->list);
-	mutex_unlock(&subsystem_list_lock);
-	wake_lock_destroy(&dev->wake_lock);
-	kfree(dev);
+
+	if (get_device(&subsys->dev)) {
+		mutex_lock(&subsys->powerup_lock);
+		WARN_ON(subsys->count);
+		device_unregister(&subsys->dev);
+		mutex_unlock(&subsys->powerup_lock);
+		subsys_debugfs_remove(subsys);
+		put_device(&subsys->dev);
+	}
 }
 EXPORT_SYMBOL(subsys_unregister);
 
+static int subsys_panic(struct device *dev, void *data)
+{
+	struct subsys_device *subsys = to_subsys(dev);
+
+	if (subsys->desc->crash_shutdown)
+		subsys->desc->crash_shutdown(subsys->desc);
+	return 0;
+}
+
 static int ssr_panic_handler(struct notifier_block *this,
 				unsigned long event, void *ptr)
 {
-	struct subsys_device *dev;
-
-	list_for_each_entry(dev, &subsystem_list, list)
-		if (dev->desc->crash_shutdown)
-			dev->desc->crash_shutdown(dev->desc);
+	bus_for_each_dev(&subsys_bus_type, NULL, NULL, subsys_panic);
 	return NOTIFY_DONE;
 }
 
@@ -547,26 +746,18 @@
 		n_restart_orders = ARRAY_SIZE(orders_8x60_all);
 	}
 
-	if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm8930aa() ||
-	    cpu_is_msm9615() || cpu_is_apq8064() || cpu_is_msm8627() ||
-	    cpu_is_msm8960ab()) {
-		if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE) {
-			restart_orders = restart_orders_8960_sglte;
-			n_restart_orders =
-				ARRAY_SIZE(restart_orders_8960_sglte);
-		} else {
-			restart_orders = restart_orders_8960;
-			n_restart_orders = ARRAY_SIZE(restart_orders_8960);
-		}
-		for (i = 0; i < n_restart_orders; i++) {
-			mutex_init(&restart_orders[i]->powerup_lock);
-			mutex_init(&restart_orders[i]->shutdown_lock);
-		}
+	if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE) {
+		restart_orders = restart_orders_8960_sglte;
+		n_restart_orders = ARRAY_SIZE(restart_orders_8960_sglte);
+	}
+
+	for (i = 0; i < n_restart_orders; i++) {
+		mutex_init(&restart_orders[i]->powerup_lock);
+		mutex_init(&restart_orders[i]->shutdown_lock);
 	}
 
 	if (restart_orders == NULL || n_restart_orders < 1) {
 		WARN_ON(1);
-		return -EINVAL;
 	}
 
 	return 0;
@@ -574,11 +765,29 @@
 
 static int __init subsys_restart_init(void)
 {
-	ssr_wq = alloc_workqueue("ssr_wq", 0, 0);
-	if (!ssr_wq)
-		panic("Couldn't allocate workqueue for subsystem restart.\n");
+	int ret;
 
-	return ssr_init_soc_restart_orders();
+	ssr_wq = alloc_workqueue("ssr_wq", WQ_CPU_INTENSIVE, 0);
+	BUG_ON(!ssr_wq);
+
+	ret = bus_register(&subsys_bus_type);
+	if (ret)
+		goto err_bus;
+	ret = subsys_debugfs_init();
+	if (ret)
+		goto err_debugfs;
+	ret = ssr_init_soc_restart_orders();
+	if (ret)
+		goto err_soc;
+	return 0;
+
+err_soc:
+	subsys_debugfs_exit();
+err_debugfs:
+	bus_unregister(&subsys_bus_type);
+err_bus:
+	destroy_workqueue(ssr_wq);
+	return ret;
 }
 arch_initcall(subsys_restart_init);
 
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..8404601 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -21,6 +21,8 @@
 #include <linux/highmem.h>
 #include <linux/memblock.h>
 #include <linux/slab.h>
+#include <linux/iommu.h>
+#include <linux/vmalloc.h>
 
 #include <asm/memory.h>
 #include <asm/highmem.h>
@@ -31,9 +33,109 @@
 #include <asm/mach/map.h>
 #include <asm/system_info.h>
 #include <asm/dma-contiguous.h>
+#include <asm/dma-iommu.h>
 
 #include "mm.h"
 
+/*
+ * The DMA API is built upon the notion of "buffer ownership".  A buffer
+ * is either exclusively owned by the CPU (and therefore may be accessed
+ * by it) or exclusively owned by the DMA device.  These helper functions
+ * represent the transitions between these two ownership states.
+ *
+ * Note, however, that on later ARMs, this notion does not work due to
+ * speculative prefetches.  We model our approach on the assumption that
+ * the CPU does do speculative prefetches, which means we clean caches
+ * before transfers and delay cache invalidation until transfer completion.
+ *
+ */
+static void __dma_page_cpu_to_dev(struct page *, unsigned long,
+		size_t, enum dma_data_direction);
+static void __dma_page_dev_to_cpu(struct page *, unsigned long,
+		size_t, enum dma_data_direction);
+
+/**
+ * arm_dma_map_page - map a portion of a page for streaming DMA
+ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
+ * @page: page that buffer resides in
+ * @offset: offset into page for start of buffer
+ * @size: size of buffer to map
+ * @dir: DMA transfer direction
+ *
+ * Ensure that any data held in the cache is appropriately discarded
+ * or written back.
+ *
+ * The device owns this memory once this call has completed.  The CPU
+ * can regain ownership by calling dma_unmap_page().
+ */
+static dma_addr_t arm_dma_map_page(struct device *dev, struct page *page,
+	     unsigned long offset, size_t size, enum dma_data_direction dir,
+	     struct dma_attrs *attrs)
+{
+	if (!arch_is_coherent())
+		__dma_page_cpu_to_dev(page, offset, size, dir);
+	return pfn_to_dma(dev, page_to_pfn(page)) + offset;
+}
+
+/**
+ * arm_dma_unmap_page - unmap a buffer previously mapped through dma_map_page()
+ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
+ * @handle: DMA address of buffer
+ * @size: size of buffer (same as passed to dma_map_page)
+ * @dir: DMA transfer direction (same as passed to dma_map_page)
+ *
+ * Unmap a page streaming mode DMA translation.  The handle and size
+ * must match what was provided in the previous dma_map_page() call.
+ * All other usages are undefined.
+ *
+ * After this call, reads by the CPU to the buffer are guaranteed to see
+ * whatever the device wrote there.
+ */
+static void arm_dma_unmap_page(struct device *dev, dma_addr_t handle,
+		size_t size, enum dma_data_direction dir,
+		struct dma_attrs *attrs)
+{
+	if (!arch_is_coherent())
+		__dma_page_dev_to_cpu(pfn_to_page(dma_to_pfn(dev, handle)),
+				      handle & ~PAGE_MASK, size, dir);
+}
+
+static void arm_dma_sync_single_for_cpu(struct device *dev,
+		dma_addr_t handle, size_t size, enum dma_data_direction dir)
+{
+	unsigned int offset = handle & (PAGE_SIZE - 1);
+	struct page *page = pfn_to_page(dma_to_pfn(dev, handle-offset));
+	if (!arch_is_coherent())
+		__dma_page_dev_to_cpu(page, offset, size, dir);
+}
+
+static void arm_dma_sync_single_for_device(struct device *dev,
+		dma_addr_t handle, size_t size, enum dma_data_direction dir)
+{
+	unsigned int offset = handle & (PAGE_SIZE - 1);
+	struct page *page = pfn_to_page(dma_to_pfn(dev, handle-offset));
+	if (!arch_is_coherent())
+		__dma_page_cpu_to_dev(page, offset, size, dir);
+}
+
+static int arm_dma_set_mask(struct device *dev, u64 dma_mask);
+
+struct dma_map_ops arm_dma_ops = {
+	.alloc			= arm_dma_alloc,
+	.free			= arm_dma_free,
+	.mmap			= arm_dma_mmap,
+	.map_page		= arm_dma_map_page,
+	.unmap_page		= arm_dma_unmap_page,
+	.map_sg			= arm_dma_map_sg,
+	.unmap_sg		= arm_dma_unmap_sg,
+	.sync_single_for_cpu	= arm_dma_sync_single_for_cpu,
+	.sync_single_for_device	= arm_dma_sync_single_for_device,
+	.sync_sg_for_cpu	= arm_dma_sync_sg_for_cpu,
+	.sync_sg_for_device	= arm_dma_sync_sg_for_device,
+	.set_dma_mask		= arm_dma_set_mask,
+};
+EXPORT_SYMBOL(arm_dma_ops);
+
 static u64 get_coherent_dma_mask(struct device *dev)
 {
 	u64 mask = (u64)arm_dma_limit;
@@ -69,9 +171,11 @@
 	 * lurking in the kernel direct-mapped region is invalidated.
 	 */
 	ptr = page_address(page);
-	memset(ptr, 0, size);
-	dmac_flush_range(ptr, ptr + size);
-	outer_flush_range(__pa(ptr), __pa(ptr) + size);
+	if (ptr) {
+		memset(ptr, 0, size);
+		dmac_flush_range(ptr, ptr + size);
+		outer_flush_range(__pa(ptr), __pa(ptr) + size);
+	}
 }
 
 /*
@@ -124,7 +228,7 @@
 
 #define DEFAULT_CONSISTENT_DMA_SIZE (7*SZ_2M)
 
-unsigned long consistent_base = CONSISTENT_END - DEFAULT_CONSISTENT_DMA_SIZE;
+static unsigned long consistent_base = CONSISTENT_END - DEFAULT_CONSISTENT_DMA_SIZE;
 
 void __init init_consistent_dma_size(unsigned long size)
 {
@@ -181,14 +285,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 +300,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;
 		}
@@ -217,7 +321,7 @@
 	.vm_list	= LIST_HEAD_INIT(coherent_head.vm_list),
 };
 
-size_t coherent_pool_size = DEFAULT_CONSISTENT_DMA_SIZE / 8;
+static size_t coherent_pool_size = DEFAULT_CONSISTENT_DMA_SIZE / 8;
 
 static int __init early_coherent_pool(char *p)
 {
@@ -295,7 +399,7 @@
 		 * Clear previous low-memory mapping
 		 */
 		for (addr = __phys_to_virt(start); addr < __phys_to_virt(end);
-		     addr += PGDIR_SIZE)
+		     addr += PMD_SIZE)
 			pmd_clear(pmd_off_k(addr));
 
 		iotable_init(&map, 1);
@@ -311,7 +415,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;
 	}
@@ -338,7 +442,7 @@
 		u32 off = CONSISTENT_OFFSET(c->vm_start) & (PTRS_PER_PTE-1);
 
 		pte = consistent_pte[idx] + off;
-		c->vm_pages = page;
+		c->priv = page;
 
 		do {
 			BUG_ON(!pte_none(*pte));
@@ -370,14 +474,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 +503,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);
@@ -524,6 +628,14 @@
 	dma_release_from_contiguous(dev, page, size >> PAGE_SHIFT);
 }
 
+static inline pgprot_t __get_dma_pgprot(struct dma_attrs *attrs, pgprot_t prot)
+{
+	prot = dma_get_attr(DMA_ATTR_WRITE_COMBINE, attrs) ?
+			    pgprot_writecombine(prot) :
+			    pgprot_dmacoherent(prot);
+	return prot;
+}
+
 #define nommu() 0
 
 #else	/* !CONFIG_MMU */
@@ -536,6 +648,7 @@
 #define __free_from_pool(cpu_addr, size)			0
 #define __free_from_contiguous(dev, page, size)			do { } while (0)
 #define __dma_free_remap(cpu_addr, size)			do { } while (0)
+#define __get_dma_pgprot(attrs, prot)				__pgprot(0)
 
 #endif	/* CONFIG_MMU */
 
@@ -584,7 +697,7 @@
 	 */
 	gfp &= ~(__GFP_COMP);
 
-	*handle = ~0;
+	*handle = DMA_ERROR_CODE;
 	size = PAGE_ALIGN(size);
 
 	if (arch_is_coherent() || nommu())
@@ -606,39 +719,34 @@
  * Allocate DMA-coherent memory space and return both the kernel remapped
  * virtual and bus address for that space.
  */
-void *dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle,
-			 gfp_t gfp)
+void *arm_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
+		    gfp_t gfp, struct dma_attrs *attrs)
 {
+	pgprot_t prot = __get_dma_pgprot(attrs, pgprot_kernel);
 	void *memory;
 
 	if (dma_alloc_from_coherent(dev, size, handle, &memory))
 		return memory;
 
-	return __dma_alloc(dev, size, handle, gfp,
-			   pgprot_dmacoherent(pgprot_kernel),
+	return __dma_alloc(dev, size, handle, gfp, prot,
 			   __builtin_return_address(0));
 }
-EXPORT_SYMBOL(dma_alloc_coherent);
 
 /*
- * Allocate a writecombining region, in much the same way as
- * dma_alloc_coherent above.
+ * Create userspace mapping for the DMA-coherent memory.
  */
-void *
-dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp)
-{
-	return __dma_alloc(dev, size, handle, gfp,
-			   pgprot_writecombine(pgprot_kernel),
-			   __builtin_return_address(0));
-}
-EXPORT_SYMBOL(dma_alloc_writecombine);
-
-static int dma_mmap(struct device *dev, struct vm_area_struct *vma,
-		    void *cpu_addr, dma_addr_t dma_addr, size_t size)
+int arm_dma_mmap(struct device *dev, struct vm_area_struct *vma,
+		 void *cpu_addr, dma_addr_t dma_addr, size_t size,
+		 struct dma_attrs *attrs)
 {
 	int ret = -ENXIO;
 #ifdef CONFIG_MMU
 	unsigned long pfn = dma_to_pfn(dev, dma_addr);
+	vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot);
+
+	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,
@@ -648,27 +756,11 @@
 	return ret;
 }
 
-int dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
-		      void *cpu_addr, dma_addr_t dma_addr, size_t size)
-{
-	vma->vm_page_prot = pgprot_dmacoherent(vma->vm_page_prot);
-	return dma_mmap(dev, vma, cpu_addr, dma_addr, size);
-}
-EXPORT_SYMBOL(dma_mmap_coherent);
-
-int dma_mmap_writecombine(struct device *dev, struct vm_area_struct *vma,
-			  void *cpu_addr, dma_addr_t dma_addr, size_t size)
-{
-	vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
-	return dma_mmap(dev, vma, cpu_addr, dma_addr, size);
-}
-EXPORT_SYMBOL(dma_mmap_writecombine);
-
-
 /*
  * Free a buffer as defined by the above mapping.
  */
-void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr_t handle)
+void arm_dma_free(struct device *dev, size_t size, void *cpu_addr,
+		  dma_addr_t handle, struct dma_attrs *attrs)
 {
 	struct page *page = pfn_to_page(dma_to_pfn(dev, handle));
 
@@ -692,53 +784,6 @@
 		__free_from_contiguous(dev, page, size);
 	}
 }
-EXPORT_SYMBOL(dma_free_coherent);
-
-/*
- * Make an area consistent for devices.
- * Note: Drivers should NOT use this function directly, as it will break
- * platforms with CONFIG_DMABOUNCE.
- * Use the driver DMA support - see dma-mapping.h (dma_sync_*)
- */
-void ___dma_single_cpu_to_dev(const void *kaddr, size_t size,
-	enum dma_data_direction dir)
-{
-#ifdef CONFIG_OUTER_CACHE
-	unsigned long paddr;
-
-	BUG_ON(!virt_addr_valid(kaddr) || !virt_addr_valid(kaddr + size - 1));
-#endif
-
-	dmac_map_area(kaddr, size, dir);
-
-#ifdef CONFIG_OUTER_CACHE
-	paddr = __pa(kaddr);
-	if (dir == DMA_FROM_DEVICE) {
-		outer_inv_range(paddr, paddr + size);
-	} else {
-		outer_clean_range(paddr, paddr + size);
-	}
-#endif
-	/* FIXME: non-speculating: flush on bidirectional mappings? */
-}
-EXPORT_SYMBOL(___dma_single_cpu_to_dev);
-
-void ___dma_single_dev_to_cpu(const void *kaddr, size_t size,
-	enum dma_data_direction dir)
-{
-#ifdef CONFIG_OUTER_CACHE
-	BUG_ON(!virt_addr_valid(kaddr) || !virt_addr_valid(kaddr + size - 1));
-
-	/* FIXME: non-speculating: not required */
-	/* don't bother invalidating if DMA to device */
-	if (dir != DMA_TO_DEVICE) {
-		unsigned long paddr = __pa(kaddr);
-		outer_inv_range(paddr, paddr + size);
-	}
-#endif
-	dmac_unmap_area(kaddr, size, dir);
-}
-EXPORT_SYMBOL(___dma_single_dev_to_cpu);
 
 static void dma_cache_maint_page(struct page *page, unsigned long offset,
 	size_t size, enum dma_data_direction dir,
@@ -784,7 +829,13 @@
 	} while (left);
 }
 
-void ___dma_page_cpu_to_dev(struct page *page, unsigned long off,
+/*
+ * Make an area consistent for devices.
+ * Note: Drivers should NOT use this function directly, as it will break
+ * platforms with CONFIG_DMABOUNCE.
+ * Use the driver DMA support - see dma-mapping.h (dma_sync_*)
+ */
+static void __dma_page_cpu_to_dev(struct page *page, unsigned long off,
 	size_t size, enum dma_data_direction dir)
 {
 	unsigned long paddr;
@@ -799,9 +850,8 @@
 	}
 	/* FIXME: non-speculating: flush on bidirectional mappings? */
 }
-EXPORT_SYMBOL(___dma_page_cpu_to_dev);
 
-void ___dma_page_dev_to_cpu(struct page *page, unsigned long off,
+static void __dma_page_dev_to_cpu(struct page *page, unsigned long off,
 	size_t size, enum dma_data_direction dir)
 {
 	unsigned long paddr = page_to_phys(page) + off;
@@ -819,10 +869,9 @@
 	if (dir != DMA_TO_DEVICE && off == 0 && size >= PAGE_SIZE)
 		set_bit(PG_dcache_clean, &page->flags);
 }
-EXPORT_SYMBOL(___dma_page_dev_to_cpu);
 
 /**
- * dma_map_sg - map a set of SG buffers for streaming mode DMA
+ * arm_dma_map_sg - map a set of SG buffers for streaming mode DMA
  * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
  * @sg: list of buffers
  * @nents: number of buffers to map
@@ -837,32 +886,32 @@
  * Device ownership issues as mentioned for dma_map_single are the same
  * here.
  */
-int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
-		enum dma_data_direction dir)
+int arm_dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
+		enum dma_data_direction dir, struct dma_attrs *attrs)
 {
+	struct dma_map_ops *ops = get_dma_ops(dev);
 	struct scatterlist *s;
 	int i, j;
 
-	BUG_ON(!valid_dma_direction(dir));
-
 	for_each_sg(sg, s, nents, i) {
-		s->dma_address = __dma_map_page(dev, sg_page(s), s->offset,
-						s->length, dir);
+#ifdef CONFIG_NEED_SG_DMA_LENGTH
+		s->dma_length = s->length;
+#endif
+		s->dma_address = ops->map_page(dev, sg_page(s), s->offset,
+						s->length, dir, attrs);
 		if (dma_mapping_error(dev, s->dma_address))
 			goto bad_mapping;
 	}
-	debug_dma_map_sg(dev, sg, nents, nents, dir);
 	return nents;
 
  bad_mapping:
 	for_each_sg(sg, s, i, j)
-		__dma_unmap_page(dev, sg_dma_address(s), sg_dma_len(s), dir);
+		ops->unmap_page(dev, sg_dma_address(s), sg_dma_len(s), dir, attrs);
 	return 0;
 }
-EXPORT_SYMBOL(dma_map_sg);
 
 /**
- * dma_unmap_sg - unmap a set of SG buffers mapped by dma_map_sg
+ * arm_dma_unmap_sg - unmap a set of SG buffers mapped by dma_map_sg
  * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
  * @sg: list of buffers
  * @nents: number of buffers to unmap (same as was passed to dma_map_sg)
@@ -871,70 +920,55 @@
  * Unmap a set of streaming mode DMA translations.  Again, CPU access
  * rules concerning calls here are the same as for dma_unmap_single().
  */
-void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
-		enum dma_data_direction dir)
+void arm_dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
+		enum dma_data_direction dir, struct dma_attrs *attrs)
 {
+	struct dma_map_ops *ops = get_dma_ops(dev);
 	struct scatterlist *s;
-	int i;
 
-	debug_dma_unmap_sg(dev, sg, nents, dir);
+	int i;
 
 	for_each_sg(sg, s, nents, i)
-		__dma_unmap_page(dev, sg_dma_address(s), sg_dma_len(s), dir);
+		ops->unmap_page(dev, sg_dma_address(s), sg_dma_len(s), dir, attrs);
 }
-EXPORT_SYMBOL(dma_unmap_sg);
 
 /**
- * dma_sync_sg_for_cpu
+ * arm_dma_sync_sg_for_cpu
  * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
  * @sg: list of buffers
  * @nents: number of buffers to map (returned from dma_map_sg)
  * @dir: DMA transfer direction (same as was passed to dma_map_sg)
  */
-void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
+void arm_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
 			int nents, enum dma_data_direction dir)
 {
+	struct dma_map_ops *ops = get_dma_ops(dev);
 	struct scatterlist *s;
 	int i;
 
-	for_each_sg(sg, s, nents, i) {
-		if (!dmabounce_sync_for_cpu(dev, sg_dma_address(s), 0,
-					    sg_dma_len(s), dir))
-			continue;
-
-		__dma_page_dev_to_cpu(sg_page(s), s->offset,
-				      s->length, dir);
-	}
-
-	debug_dma_sync_sg_for_cpu(dev, sg, nents, dir);
+	for_each_sg(sg, s, nents, i)
+		ops->sync_single_for_cpu(dev, sg_dma_address(s), s->length,
+					 dir);
 }
-EXPORT_SYMBOL(dma_sync_sg_for_cpu);
 
 /**
- * dma_sync_sg_for_device
+ * arm_dma_sync_sg_for_device
  * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
  * @sg: list of buffers
  * @nents: number of buffers to map (returned from dma_map_sg)
  * @dir: DMA transfer direction (same as was passed to dma_map_sg)
  */
-void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
+void arm_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
 			int nents, enum dma_data_direction dir)
 {
+	struct dma_map_ops *ops = get_dma_ops(dev);
 	struct scatterlist *s;
 	int i;
 
-	for_each_sg(sg, s, nents, i) {
-		if (!dmabounce_sync_for_device(dev, sg_dma_address(s), 0,
-					sg_dma_len(s), dir))
-			continue;
-
-		__dma_page_cpu_to_dev(sg_page(s), s->offset,
-				      s->length, dir);
-	}
-
-	debug_dma_sync_sg_for_device(dev, sg, nents, dir);
+	for_each_sg(sg, s, nents, i)
+		ops->sync_single_for_device(dev, sg_dma_address(s), s->length,
+					    dir);
 }
-EXPORT_SYMBOL(dma_sync_sg_for_device);
 
 /*
  * Return whether the given device DMA address mask can be supported
@@ -950,18 +984,15 @@
 }
 EXPORT_SYMBOL(dma_supported);
 
-int dma_set_mask(struct device *dev, u64 dma_mask)
+static int arm_dma_set_mask(struct device *dev, u64 dma_mask)
 {
 	if (!dev->dma_mask || !dma_supported(dev, dma_mask))
 		return -EIO;
 
-#ifndef CONFIG_DMABOUNCE
 	*dev->dma_mask = dma_mask;
-#endif
 
 	return 0;
 }
-EXPORT_SYMBOL(dma_set_mask);
 
 #define PREALLOC_DMA_DEBUG_ENTRIES	4096
 
@@ -974,3 +1005,679 @@
 	return 0;
 }
 fs_initcall(dma_debug_do_init);
+
+#ifdef CONFIG_ARM_DMA_USE_IOMMU
+
+/* IOMMU */
+
+static inline dma_addr_t __alloc_iova(struct dma_iommu_mapping *mapping,
+				      size_t size)
+{
+	unsigned int order = get_order(size);
+	unsigned int align = 0;
+	unsigned int count, start;
+	unsigned long flags;
+
+	count = ((PAGE_ALIGN(size) >> PAGE_SHIFT) +
+		 (1 << mapping->order) - 1) >> mapping->order;
+
+	if (order > mapping->order)
+		align = (1 << (order - mapping->order)) - 1;
+
+	spin_lock_irqsave(&mapping->lock, flags);
+	start = bitmap_find_next_zero_area(mapping->bitmap, mapping->bits, 0,
+					   count, align);
+	if (start > mapping->bits) {
+		spin_unlock_irqrestore(&mapping->lock, flags);
+		return DMA_ERROR_CODE;
+	}
+
+	bitmap_set(mapping->bitmap, start, count);
+	spin_unlock_irqrestore(&mapping->lock, flags);
+
+	return mapping->base + (start << (mapping->order + PAGE_SHIFT));
+}
+
+static inline void __free_iova(struct dma_iommu_mapping *mapping,
+			       dma_addr_t addr, size_t size)
+{
+	unsigned int start = (addr - mapping->base) >>
+			     (mapping->order + PAGE_SHIFT);
+	unsigned int count = ((size >> PAGE_SHIFT) +
+			      (1 << mapping->order) - 1) >> mapping->order;
+	unsigned long flags;
+
+	spin_lock_irqsave(&mapping->lock, flags);
+	bitmap_clear(mapping->bitmap, start, count);
+	spin_unlock_irqrestore(&mapping->lock, flags);
+}
+
+static struct page **__iommu_alloc_buffer(struct device *dev, size_t size, gfp_t gfp)
+{
+	struct page **pages;
+	int count = size >> PAGE_SHIFT;
+	int array_size = count * sizeof(struct page *);
+	int i = 0;
+
+	if (array_size <= PAGE_SIZE)
+		pages = kzalloc(array_size, gfp);
+	else
+		pages = vzalloc(array_size);
+	if (!pages)
+		return NULL;
+
+	while (count) {
+		int j, order = __fls(count);
+
+		pages[i] = alloc_pages(gfp | __GFP_NOWARN, order);
+		while (!pages[i] && order)
+			pages[i] = alloc_pages(gfp | __GFP_NOWARN, --order);
+		if (!pages[i])
+			goto error;
+
+		if (order)
+			split_page(pages[i], order);
+		j = 1 << order;
+		while (--j)
+			pages[i + j] = pages[i] + j;
+
+		__dma_clear_buffer(pages[i], PAGE_SIZE << order);
+		i += 1 << order;
+		count -= 1 << order;
+	}
+
+	return pages;
+error:
+	while (--i)
+		if (pages[i])
+			__free_pages(pages[i], 0);
+	if (array_size < PAGE_SIZE)
+		kfree(pages);
+	else
+		vfree(pages);
+	return NULL;
+}
+
+static int __iommu_free_buffer(struct device *dev, struct page **pages, size_t size)
+{
+	int count = size >> PAGE_SHIFT;
+	int array_size = count * sizeof(struct page *);
+	int i;
+	for (i = 0; i < count; i++)
+		if (pages[i])
+			__free_pages(pages[i], 0);
+	if (array_size < PAGE_SIZE)
+		kfree(pages);
+	else
+		vfree(pages);
+	return 0;
+}
+
+/*
+ * Create a CPU mapping for a specified pages
+ */
+static void *
+__iommu_alloc_remap(struct page **pages, size_t size, gfp_t gfp, pgprot_t prot)
+{
+	struct arm_vmregion *c;
+	size_t align;
+	size_t count = size >> PAGE_SHIFT;
+	int bit;
+
+	if (!consistent_pte[0]) {
+		pr_err("%s: not initialised\n", __func__);
+		dump_stack();
+		return NULL;
+	}
+
+	/*
+	 * Align the virtual region allocation - maximum alignment is
+	 * a section size, minimum is a page size.  This helps reduce
+	 * fragmentation of the DMA space, and also prevents allocations
+	 * smaller than a section from crossing a section boundary.
+	 */
+	bit = fls(size - 1);
+	if (bit > SECTION_SHIFT)
+		bit = SECTION_SHIFT;
+	align = 1 << bit;
+
+	/*
+	 * Allocate a virtual address in the consistent mapping region.
+	 */
+	c = arm_vmregion_alloc(&consistent_head, align, size,
+			    gfp & ~(__GFP_DMA | __GFP_HIGHMEM), NULL);
+	if (c) {
+		pte_t *pte;
+		int idx = CONSISTENT_PTE_INDEX(c->vm_start);
+		int i = 0;
+		u32 off = CONSISTENT_OFFSET(c->vm_start) & (PTRS_PER_PTE-1);
+
+		pte = consistent_pte[idx] + off;
+		c->priv = pages;
+
+		do {
+			BUG_ON(!pte_none(*pte));
+
+			set_pte_ext(pte, mk_pte(pages[i], prot), 0);
+			pte++;
+			off++;
+			i++;
+			if (off >= PTRS_PER_PTE) {
+				off = 0;
+				pte = consistent_pte[++idx];
+			}
+		} while (i < count);
+
+		dsb();
+
+		return (void *)c->vm_start;
+	}
+	return NULL;
+}
+
+/*
+ * Create a mapping in device IO address space for specified pages
+ */
+static dma_addr_t
+__iommu_create_mapping(struct device *dev, struct page **pages, size_t size)
+{
+	struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+	unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
+	dma_addr_t dma_addr, iova;
+	int i, ret = DMA_ERROR_CODE;
+
+	dma_addr = __alloc_iova(mapping, size);
+	if (dma_addr == DMA_ERROR_CODE)
+		return dma_addr;
+
+	iova = dma_addr;
+	for (i = 0; i < count; ) {
+		unsigned int next_pfn = page_to_pfn(pages[i]) + 1;
+		phys_addr_t phys = page_to_phys(pages[i]);
+		unsigned int len, j;
+
+		for (j = i + 1; j < count; j++, next_pfn++)
+			if (page_to_pfn(pages[j]) != next_pfn)
+				break;
+
+		len = (j - i) << PAGE_SHIFT;
+		ret = iommu_map(mapping->domain, iova, phys, len, 0);
+		if (ret < 0)
+			goto fail;
+		iova += len;
+		i = j;
+	}
+	return dma_addr;
+fail:
+	iommu_unmap(mapping->domain, dma_addr, iova-dma_addr);
+	__free_iova(mapping, dma_addr, size);
+	return DMA_ERROR_CODE;
+}
+
+static int __iommu_remove_mapping(struct device *dev, dma_addr_t iova, size_t size)
+{
+	struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+
+	/*
+	 * add optional in-page offset from iova to size and align
+	 * result to page size
+	 */
+	size = PAGE_ALIGN((iova & ~PAGE_MASK) + size);
+	iova &= PAGE_MASK;
+
+	iommu_unmap(mapping->domain, iova, size);
+	__free_iova(mapping, iova, size);
+	return 0;
+}
+
+static void *arm_iommu_alloc_attrs(struct device *dev, size_t size,
+	    dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs)
+{
+	pgprot_t prot = __get_dma_pgprot(attrs, pgprot_kernel);
+	struct page **pages;
+	void *addr = NULL;
+
+	*handle = DMA_ERROR_CODE;
+	size = PAGE_ALIGN(size);
+
+	pages = __iommu_alloc_buffer(dev, size, gfp);
+	if (!pages)
+		return NULL;
+
+	*handle = __iommu_create_mapping(dev, pages, size);
+	if (*handle == DMA_ERROR_CODE)
+		goto err_buffer;
+
+	addr = __iommu_alloc_remap(pages, size, gfp, prot);
+	if (!addr)
+		goto err_mapping;
+
+	return addr;
+
+err_mapping:
+	__iommu_remove_mapping(dev, *handle, size);
+err_buffer:
+	__iommu_free_buffer(dev, pages, size);
+	return NULL;
+}
+
+static int arm_iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
+		    void *cpu_addr, dma_addr_t dma_addr, size_t size,
+		    struct dma_attrs *attrs)
+{
+	struct arm_vmregion *c;
+
+	vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot);
+	c = arm_vmregion_find(&consistent_head, (unsigned long)cpu_addr);
+
+	if (c) {
+		struct page **pages = c->priv;
+
+		unsigned long uaddr = vma->vm_start;
+		unsigned long usize = vma->vm_end - vma->vm_start;
+		int i = 0;
+
+		do {
+			int ret;
+
+			ret = vm_insert_page(vma, uaddr, pages[i++]);
+			if (ret) {
+				pr_err("Remapping memory, error: %d\n", ret);
+				return ret;
+			}
+
+			uaddr += PAGE_SIZE;
+			usize -= PAGE_SIZE;
+		} while (usize > 0);
+	}
+	return 0;
+}
+
+/*
+ * free a page as defined by the above mapping.
+ * Must not be called with IRQs disabled.
+ */
+void arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,
+			  dma_addr_t handle, struct dma_attrs *attrs)
+{
+	struct arm_vmregion *c;
+	size = PAGE_ALIGN(size);
+
+	c = arm_vmregion_find(&consistent_head, (unsigned long)cpu_addr);
+	if (c) {
+		struct page **pages = c->priv;
+		__dma_free_remap(cpu_addr, size);
+		__iommu_remove_mapping(dev, handle, size);
+		__iommu_free_buffer(dev, pages, size);
+	}
+}
+
+/*
+ * Map a part of the scatter-gather list into contiguous io address space
+ */
+static int __map_sg_chunk(struct device *dev, struct scatterlist *sg,
+			  size_t size, dma_addr_t *handle,
+			  enum dma_data_direction dir)
+{
+	struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+	dma_addr_t iova, iova_base;
+	int ret = 0;
+	unsigned int count;
+	struct scatterlist *s;
+
+	size = PAGE_ALIGN(size);
+	*handle = DMA_ERROR_CODE;
+
+	iova_base = iova = __alloc_iova(mapping, size);
+	if (iova == DMA_ERROR_CODE)
+		return -ENOMEM;
+
+	for (count = 0, s = sg; count < (size >> PAGE_SHIFT); s = sg_next(s)) {
+		phys_addr_t phys = page_to_phys(sg_page(s));
+		unsigned int len = PAGE_ALIGN(s->offset + s->length);
+
+		if (!arch_is_coherent())
+			__dma_page_cpu_to_dev(sg_page(s), s->offset, s->length, dir);
+
+		ret = iommu_map(mapping->domain, iova, phys, len, 0);
+		if (ret < 0)
+			goto fail;
+		count += len >> PAGE_SHIFT;
+		iova += len;
+	}
+	*handle = iova_base;
+
+	return 0;
+fail:
+	iommu_unmap(mapping->domain, iova_base, count * PAGE_SIZE);
+	__free_iova(mapping, iova_base, size);
+	return ret;
+}
+
+/**
+ * arm_iommu_map_sg - map a set of SG buffers for streaming mode DMA
+ * @dev: valid struct device pointer
+ * @sg: list of buffers
+ * @nents: number of buffers to map
+ * @dir: DMA transfer direction
+ *
+ * Map a set of buffers described by scatterlist in streaming mode for DMA.
+ * The scatter gather list elements are merged together (if possible) and
+ * tagged with the appropriate dma address and length. They are obtained via
+ * sg_dma_{address,length}.
+ */
+int arm_iommu_map_sg(struct device *dev, struct scatterlist *sg, int nents,
+		     enum dma_data_direction dir, struct dma_attrs *attrs)
+{
+	struct scatterlist *s = sg, *dma = sg, *start = sg;
+	int i, count = 0;
+	unsigned int offset = s->offset;
+	unsigned int size = s->offset + s->length;
+	unsigned int max = dma_get_max_seg_size(dev);
+
+	for (i = 1; i < nents; i++) {
+		s = sg_next(s);
+
+		s->dma_address = DMA_ERROR_CODE;
+		s->dma_length = 0;
+
+		if (s->offset || (size & ~PAGE_MASK) || size + s->length > max) {
+			if (__map_sg_chunk(dev, start, size, &dma->dma_address,
+			    dir) < 0)
+				goto bad_mapping;
+
+			dma->dma_address += offset;
+			dma->dma_length = size - offset;
+
+			size = offset = s->offset;
+			start = s;
+			dma = sg_next(dma);
+			count += 1;
+		}
+		size += s->length;
+	}
+	if (__map_sg_chunk(dev, start, size, &dma->dma_address, dir) < 0)
+		goto bad_mapping;
+
+	dma->dma_address += offset;
+	dma->dma_length = size - offset;
+
+	return count+1;
+
+bad_mapping:
+	for_each_sg(sg, s, count, i)
+		__iommu_remove_mapping(dev, sg_dma_address(s), sg_dma_len(s));
+	return 0;
+}
+
+/**
+ * arm_iommu_unmap_sg - unmap a set of SG buffers mapped by dma_map_sg
+ * @dev: valid struct device pointer
+ * @sg: list of buffers
+ * @nents: number of buffers to unmap (same as was passed to dma_map_sg)
+ * @dir: DMA transfer direction (same as was passed to dma_map_sg)
+ *
+ * Unmap a set of streaming mode DMA translations.  Again, CPU access
+ * rules concerning calls here are the same as for dma_unmap_single().
+ */
+void arm_iommu_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
+			enum dma_data_direction dir, struct dma_attrs *attrs)
+{
+	struct scatterlist *s;
+	int i;
+
+	for_each_sg(sg, s, nents, i) {
+		if (sg_dma_len(s))
+			__iommu_remove_mapping(dev, sg_dma_address(s),
+					       sg_dma_len(s));
+		if (!arch_is_coherent())
+			__dma_page_dev_to_cpu(sg_page(s), s->offset,
+					      s->length, dir);
+	}
+}
+
+/**
+ * arm_iommu_sync_sg_for_cpu
+ * @dev: valid struct device pointer
+ * @sg: list of buffers
+ * @nents: number of buffers to map (returned from dma_map_sg)
+ * @dir: DMA transfer direction (same as was passed to dma_map_sg)
+ */
+void arm_iommu_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
+			int nents, enum dma_data_direction dir)
+{
+	struct scatterlist *s;
+	int i;
+
+	for_each_sg(sg, s, nents, i)
+		if (!arch_is_coherent())
+			__dma_page_dev_to_cpu(sg_page(s), s->offset, s->length, dir);
+
+}
+
+/**
+ * arm_iommu_sync_sg_for_device
+ * @dev: valid struct device pointer
+ * @sg: list of buffers
+ * @nents: number of buffers to map (returned from dma_map_sg)
+ * @dir: DMA transfer direction (same as was passed to dma_map_sg)
+ */
+void arm_iommu_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
+			int nents, enum dma_data_direction dir)
+{
+	struct scatterlist *s;
+	int i;
+
+	for_each_sg(sg, s, nents, i)
+		if (!arch_is_coherent())
+			__dma_page_cpu_to_dev(sg_page(s), s->offset, s->length, dir);
+}
+
+
+/**
+ * arm_iommu_map_page
+ * @dev: valid struct device pointer
+ * @page: page that buffer resides in
+ * @offset: offset into page for start of buffer
+ * @size: size of buffer to map
+ * @dir: DMA transfer direction
+ *
+ * IOMMU aware version of arm_dma_map_page()
+ */
+static dma_addr_t arm_iommu_map_page(struct device *dev, struct page *page,
+	     unsigned long offset, size_t size, enum dma_data_direction dir,
+	     struct dma_attrs *attrs)
+{
+	struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+	dma_addr_t dma_addr;
+	int ret, len = PAGE_ALIGN(size + offset);
+
+	if (!arch_is_coherent())
+		__dma_page_cpu_to_dev(page, offset, size, dir);
+
+	dma_addr = __alloc_iova(mapping, len);
+	if (dma_addr == DMA_ERROR_CODE)
+		return dma_addr;
+
+	ret = iommu_map(mapping->domain, dma_addr, page_to_phys(page), len, 0);
+	if (ret < 0)
+		goto fail;
+
+	return dma_addr + offset;
+fail:
+	__free_iova(mapping, dma_addr, len);
+	return DMA_ERROR_CODE;
+}
+
+/**
+ * arm_iommu_unmap_page
+ * @dev: valid struct device pointer
+ * @handle: DMA address of buffer
+ * @size: size of buffer (same as passed to dma_map_page)
+ * @dir: DMA transfer direction (same as passed to dma_map_page)
+ *
+ * IOMMU aware version of arm_dma_unmap_page()
+ */
+static void arm_iommu_unmap_page(struct device *dev, dma_addr_t handle,
+		size_t size, enum dma_data_direction dir,
+		struct dma_attrs *attrs)
+{
+	struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+	dma_addr_t iova = handle & PAGE_MASK;
+	struct page *page = phys_to_page(iommu_iova_to_phys(mapping->domain, iova));
+	int offset = handle & ~PAGE_MASK;
+	int len = PAGE_ALIGN(size + offset);
+
+	if (!iova)
+		return;
+
+	if (!arch_is_coherent())
+		__dma_page_dev_to_cpu(page, offset, size, dir);
+
+	iommu_unmap(mapping->domain, iova, len);
+	__free_iova(mapping, iova, len);
+}
+
+static void arm_iommu_sync_single_for_cpu(struct device *dev,
+		dma_addr_t handle, size_t size, enum dma_data_direction dir)
+{
+	struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+	dma_addr_t iova = handle & PAGE_MASK;
+	struct page *page = phys_to_page(iommu_iova_to_phys(mapping->domain, iova));
+	unsigned int offset = handle & ~PAGE_MASK;
+
+	if (!iova)
+		return;
+
+	if (!arch_is_coherent())
+		__dma_page_dev_to_cpu(page, offset, size, dir);
+}
+
+static void arm_iommu_sync_single_for_device(struct device *dev,
+		dma_addr_t handle, size_t size, enum dma_data_direction dir)
+{
+	struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+	dma_addr_t iova = handle & PAGE_MASK;
+	struct page *page = phys_to_page(iommu_iova_to_phys(mapping->domain, iova));
+	unsigned int offset = handle & ~PAGE_MASK;
+
+	if (!iova)
+		return;
+
+	__dma_page_cpu_to_dev(page, offset, size, dir);
+}
+
+struct dma_map_ops iommu_ops = {
+	.alloc		= arm_iommu_alloc_attrs,
+	.free		= arm_iommu_free_attrs,
+	.mmap		= arm_iommu_mmap_attrs,
+
+	.map_page		= arm_iommu_map_page,
+	.unmap_page		= arm_iommu_unmap_page,
+	.sync_single_for_cpu	= arm_iommu_sync_single_for_cpu,
+	.sync_single_for_device	= arm_iommu_sync_single_for_device,
+
+	.map_sg			= arm_iommu_map_sg,
+	.unmap_sg		= arm_iommu_unmap_sg,
+	.sync_sg_for_cpu	= arm_iommu_sync_sg_for_cpu,
+	.sync_sg_for_device	= arm_iommu_sync_sg_for_device,
+};
+
+/**
+ * arm_iommu_create_mapping
+ * @bus: pointer to the bus holding the client device (for IOMMU calls)
+ * @base: start address of the valid IO address space
+ * @size: size of the valid IO address space
+ * @order: accuracy of the IO addresses allocations
+ *
+ * Creates a mapping structure which holds information about used/unused
+ * IO address ranges, which is required to perform memory allocation and
+ * mapping with IOMMU aware functions.
+ *
+ * The client device need to be attached to the mapping with
+ * arm_iommu_attach_device function.
+ */
+struct dma_iommu_mapping *
+arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, size_t size,
+			 int order)
+{
+	unsigned int count = size >> (PAGE_SHIFT + order);
+	unsigned int bitmap_size = BITS_TO_LONGS(count) * sizeof(long);
+	struct dma_iommu_mapping *mapping;
+	int err = -ENOMEM;
+
+	if (!count)
+		return ERR_PTR(-EINVAL);
+
+	mapping = kzalloc(sizeof(struct dma_iommu_mapping), GFP_KERNEL);
+	if (!mapping)
+		goto err;
+
+	mapping->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
+	if (!mapping->bitmap)
+		goto err2;
+
+	mapping->base = base;
+	mapping->bits = BITS_PER_BYTE * bitmap_size;
+	mapping->order = order;
+	spin_lock_init(&mapping->lock);
+
+	mapping->domain = iommu_domain_alloc(bus);
+	if (!mapping->domain)
+		goto err3;
+
+	kref_init(&mapping->kref);
+	return mapping;
+err3:
+	kfree(mapping->bitmap);
+err2:
+	kfree(mapping);
+err:
+	return ERR_PTR(err);
+}
+
+static void release_iommu_mapping(struct kref *kref)
+{
+	struct dma_iommu_mapping *mapping =
+		container_of(kref, struct dma_iommu_mapping, kref);
+
+	iommu_domain_free(mapping->domain);
+	kfree(mapping->bitmap);
+	kfree(mapping);
+}
+
+void arm_iommu_release_mapping(struct dma_iommu_mapping *mapping)
+{
+	if (mapping)
+		kref_put(&mapping->kref, release_iommu_mapping);
+}
+
+/**
+ * arm_iommu_attach_device
+ * @dev: valid struct device pointer
+ * @mapping: io address space mapping structure (returned from
+ *	arm_iommu_create_mapping)
+ *
+ * Attaches specified io address space mapping to the provided device,
+ * this replaces the dma operations (dma_map_ops pointer) with the
+ * IOMMU aware version. More than one client might be attached to
+ * the same io address space mapping.
+ */
+int arm_iommu_attach_device(struct device *dev,
+			    struct dma_iommu_mapping *mapping)
+{
+	int err;
+
+	err = iommu_attach_device(mapping->domain, dev);
+	if (err)
+		return err;
+
+	kref_get(&mapping->kref);
+	dev->archdata.mapping = mapping;
+	set_dma_ops(dev, &iommu_ops);
+
+	pr_info("Attached IOMMU controller to %s device.\n", dev_name(dev));
+	return 0;
+}
+
+#endif
diff --git a/arch/arm/mm/mm.h b/arch/arm/mm/mm.h
index bd41abc..8877ddd 100644
--- a/arch/arm/mm/mm.h
+++ b/arch/arm/mm/mm.h
@@ -55,6 +55,9 @@
 /* permanent static mappings from iotable_init() */
 #define VM_ARM_STATIC_MAPPING	0x40000000
 
+/* empty mapping */
+#define VM_ARM_EMPTY_MAPPING	0x20000000
+
 /* mapping type (attributes) for permanent static mappings */
 #define VM_ARM_MTYPE(mt)		((mt) << 20)
 #define VM_ARM_MTYPE_MASK	(0x1f << 20)
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/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index da33be0..bae23b0 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -861,7 +861,7 @@
 	vm = early_alloc_aligned(sizeof(*vm), __alignof__(*vm));
 	vm->addr = (void *)addr;
 	vm->size = SECTION_SIZE;
-	vm->flags = VM_IOREMAP | VM_ARM_STATIC_MAPPING;
+	vm->flags = VM_IOREMAP | VM_ARM_EMPTY_MAPPING;
 	vm->caller = pmd_empty_section_gap;
 	vm_area_add_early(vm);
 }
@@ -874,7 +874,7 @@
 
 	/* we're still single threaded hence no lock needed here */
 	for (vm = vmlist; vm; vm = vm->next) {
-		if (!(vm->flags & VM_ARM_STATIC_MAPPING))
+		if (!(vm->flags & (VM_ARM_STATIC_MAPPING | VM_ARM_EMPTY_MAPPING)))
 			continue;
 		addr = (unsigned long)vm->addr;
 		if (addr < next)
diff --git a/arch/arm/mm/vmregion.h b/arch/arm/mm/vmregion.h
index 162be66..bf312c3 100644
--- a/arch/arm/mm/vmregion.h
+++ b/arch/arm/mm/vmregion.h
@@ -17,7 +17,7 @@
 	struct list_head	vm_list;
 	unsigned long		vm_start;
 	unsigned long		vm_end;
-	struct page		*vm_pages;
+	void			*priv;
 	int			vm_active;
 	const void		*caller;
 };
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/base/power/main.c b/drivers/base/power/main.c
index 95d2f17..b5d38d5 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -1010,8 +1010,16 @@
 int dpm_suspend_end(pm_message_t state)
 {
 	int error = dpm_suspend_late(state);
+	if (error)
+		return error;
 
-	return error ? : dpm_suspend_noirq(state);
+	error = dpm_suspend_noirq(state);
+	if (error) {
+		dpm_resume_early(state);
+		return error;
+	}
+
+	return 0;
 }
 EXPORT_SYMBOL_GPL(dpm_suspend_end);
 
diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c
index b117309..50b3362 100644
--- a/drivers/bluetooth/hci_ath.c
+++ b/drivers/bluetooth/hci_ath.c
@@ -44,7 +44,7 @@
 
 #include "hci_uart.h"
 
-unsigned int enableuartsleep;
+unsigned int enableuartsleep = 1;
 module_param(enableuartsleep, uint, 0644);
 /*
  * Global variables
@@ -93,7 +93,7 @@
 
 static void hostwake_interrupt(unsigned long data)
 {
-	printk(KERN_INFO " wakeup host\n");
+	BT_INFO(" wakeup host\n");
 }
 
 static void modify_timer_task(void)
@@ -109,10 +109,10 @@
 {
 	int status = 0;
 	if (test_bit(BT_TXEXPIRED, &flags)) {
-		printk(KERN_INFO "wakeup device\n");
-		gpio_set_value(bsi->ext_wake, 1);
-		msleep(20);
+		BT_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;
@@ -138,12 +138,114 @@
 	hci_uart_tx_wakeup(hu);
 }
 
+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 int ath_bluesleep_gpio_config(int on)
+{
+	int ret = 0;
+
+	BT_INFO("%s config: %d", __func__, on);
+	if (!on) {
+		if (disable_irq_wake(bsi->host_wake_irq))
+			BT_ERR("Couldn't disable hostwake IRQ wakeup mode\n");
+		goto free_host_wake_irq;
+	}
+
+	ret = gpio_request(bsi->host_wake, "bt_host_wake");
+	if (ret < 0) {
+		BT_ERR("failed to request gpio pin %d, error %d\n",
+			bsi->host_wake, ret);
+		goto gpio_config_failed;
+	}
+
+	/* configure host_wake as input */
+	ret = gpio_direction_input(bsi->host_wake);
+	if (ret < 0) {
+		BT_ERR("failed to config GPIO %d as input pin, err %d\n",
+			bsi->host_wake, ret);
+		goto gpio_host_wake;
+	}
+
+	ret = gpio_request(bsi->ext_wake, "bt_ext_wake");
+	if (ret < 0) {
+		BT_ERR("failed to request gpio pin %d, error %d\n",
+			bsi->ext_wake, ret);
+		goto gpio_host_wake;
+	}
+
+	ret = gpio_direction_output(bsi->ext_wake, 1);
+	if (ret < 0) {
+		BT_ERR("failed to config GPIO %d as output pin, err %d\n",
+			bsi->ext_wake, ret);
+		goto gpio_ext_wake;
+	}
+
+	gpio_set_value(bsi->ext_wake, 1);
+
+	/* 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 delete_timer;
+	}
+
+	ret = enable_irq_wake(bsi->host_wake_irq);
+	if (ret < 0) {
+		BT_ERR("Couldn't enable BT_HOST_WAKE as wakeup interrupt");
+		goto free_host_wake_irq;
+	}
+
+	return 0;
+
+free_host_wake_irq:
+	free_irq(bsi->host_wake_irq, NULL);
+delete_timer:
+	del_timer(&tx_timer);
+gpio_ext_wake:
+	gpio_free(bsi->ext_wake);
+gpio_host_wake:
+	gpio_free(bsi->host_wake);
+gpio_config_failed:
+	return ret;
+}
+
 /* Initialize protocol */
 static int ath_open(struct hci_uart *hu)
 {
 	struct ath_struct *ath;
 
-	BT_DBG("hu %p", hu);
+	BT_DBG("hu %p, bsi %p", hu, bsi);
+
+	if (!bsi)
+		return -EIO;
+
+	if (ath_bluesleep_gpio_config(1) < 0) {
+		BT_ERR("HCIATH3K GPIO Config failed");
+		return -EIO;
+	}
 
 	ath = kzalloc(sizeof(*ath), GFP_ATOMIC);
 	if (!ath)
@@ -190,6 +292,9 @@
 	hu->priv = NULL;
 	kfree(ath);
 
+	if (bsi)
+		ath_bluesleep_gpio_config(0);
+
 	return 0;
 }
 
@@ -200,6 +305,8 @@
 {
 	struct ath_struct *ath = hu->priv;
 
+	BT_DBG("");
+
 	if (bt_cb(skb)->pkt_type == HCI_SCODATA_PKT) {
 		kfree_skb(skb);
 		return 0;
@@ -243,6 +350,8 @@
 	struct ath_struct *ath = hu->priv;
 	unsigned int type;
 
+	BT_DBG("");
+
 	if (hci_recv_stream_fragment(hu->hdev, data, count) < 0)
 		BT_ERR("Frame Reassembly Failed");
 
@@ -260,7 +369,7 @@
 
 		if (type == HCI_EVENT_PKT) {
 			clear_bit(BT_SLEEPCMD, &flags);
-			printk(KERN_INFO "cur_sleep:%d\n", ath->cur_sleep);
+			BT_INFO("cur_sleep:%d\n", ath->cur_sleep);
 			if (ath->cur_sleep == 1)
 				set_bit(BT_SLEEPENABLE, &flags);
 			else
@@ -276,19 +385,11 @@
 {
 	if (!test_bit(BT_SLEEPENABLE, &flags))
 		return;
-	BT_DBG("Tx timer expired");
-	printk(KERN_INFO "Tx timer expired\n");
+	BT_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,
@@ -304,6 +405,8 @@
 	int ret;
 	struct resource *res;
 
+	BT_DBG("");
+
 	bsi = kzalloc(sizeof(struct bluesleep_info), GFP_KERNEL);
 	if (!bsi) {
 		ret = -ENOMEM;
@@ -319,107 +422,35 @@
 	}
 	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;
+		goto free_bsi;
 	}
 	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, 0);
-
 	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;
+		goto free_bsi;
 	}
 
 	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);
+	bsi = NULL;
 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;
 }
diff --git a/drivers/bluetooth/hci_ibs.c b/drivers/bluetooth/hci_ibs.c
index fb084f5..6253605 100644
--- a/drivers/bluetooth/hci_ibs.c
+++ b/drivers/bluetooth/hci_ibs.c
@@ -112,6 +112,13 @@
 	unsigned long rx_vote;		/* clock must be on for RX */
 	struct	timer_list tx_idle_timer;
 	struct	timer_list wake_retrans_timer;
+	struct	workqueue_struct *workqueue;
+	struct	work_struct ws_awake_rx;
+	struct	work_struct ws_awake_device;
+	struct	work_struct ws_rx_vote_off;
+	struct	work_struct ws_tx_vote_off;
+	void *ibs_hu; /* keeps the hci_uart pointer for reference */
+
 	/* debug */
 	unsigned long ibs_sent_wacks;
 	unsigned long ibs_sent_slps;
@@ -242,12 +249,90 @@
 	return err;
 }
 
+static void ibs_wq_awake_device(struct work_struct *work)
+{
+	struct ibs_struct *ibs = container_of(work, struct ibs_struct,
+					ws_awake_device);
+	struct hci_uart *hu = (struct hci_uart *)ibs->ibs_hu;
+
+	BT_DBG(" %p ", hu);
+
+	/* Vote for serial clock */
+	ibs_msm_serial_clock_vote(HCI_IBS_TX_VOTE_CLOCK_ON, hu);
+
+	spin_lock(&ibs->hci_ibs_lock);
+
+	/* send wake indication to device */
+	if (send_hci_ibs_cmd(HCI_IBS_WAKE_IND, hu) < 0)
+		BT_ERR("cannot send WAKE to device");
+
+	ibs->ibs_sent_wakes++; /* debug */
+
+	/* start retransmit timer */
+	mod_timer(&ibs->wake_retrans_timer, jiffies + wake_retrans);
+
+	spin_unlock(&ibs->hci_ibs_lock);
+}
+
+static void ibs_wq_awake_rx(struct work_struct *work)
+{
+	struct ibs_struct *ibs = container_of(work, struct ibs_struct,
+					ws_awake_rx);
+	struct hci_uart *hu = (struct hci_uart *)ibs->ibs_hu;
+
+	BT_DBG(" %p ", hu);
+
+	ibs_msm_serial_clock_vote(HCI_IBS_RX_VOTE_CLOCK_ON, hu);
+
+	spin_lock(&ibs->hci_ibs_lock);
+	ibs->rx_ibs_state = HCI_IBS_RX_AWAKE;
+	/* Always acknowledge device wake up,
+	 * sending IBS message doesn't count as TX ON
+	 */
+	if (send_hci_ibs_cmd(HCI_IBS_WAKE_ACK, hu) < 0)
+		BT_ERR("cannot acknowledge device wake up");
+
+	ibs->ibs_sent_wacks++; /* debug */
+
+	spin_unlock(&ibs->hci_ibs_lock);
+	/* actually send the packets */
+	hci_uart_tx_wakeup(hu);
+
+}
+
+static void ibs_wq_serial_rx_clock_vote_off(struct work_struct *work)
+{
+	struct ibs_struct *ibs = container_of(work, struct ibs_struct,
+					ws_rx_vote_off);
+	struct hci_uart *hu = (struct hci_uart *)ibs->ibs_hu;
+
+	BT_DBG(" %p ", hu);
+
+	ibs_msm_serial_clock_vote(HCI_IBS_RX_VOTE_CLOCK_OFF, hu);
+
+}
+
+static void ibs_wq_serial_tx_clock_vote_off(struct work_struct *work)
+{
+	struct ibs_struct *ibs = container_of(work, struct ibs_struct,
+					ws_tx_vote_off);
+	struct hci_uart *hu = (struct hci_uart *)ibs->ibs_hu;
+
+	BT_DBG(" %p ", hu);
+
+	hci_uart_tx_wakeup(hu);  /* run HCI tx handling unlocked */
+
+	/* now that message queued to tty driver, vote for tty clocks off */
+	/* It is up to the tty driver to pend the clocks off until tx done. */
+	ibs_msm_serial_clock_vote(HCI_IBS_TX_VOTE_CLOCK_OFF, hu);
+
+}
+
 static void hci_ibs_tx_idle_timeout(unsigned long arg)
 {
 	struct hci_uart *hu = (struct hci_uart *) arg;
 	struct ibs_struct *ibs = hu->priv;
 	unsigned long flags;
-	unsigned long vote_tx_sleep = 0;
 
 	BT_DBG("hu %p idle timeout in %lu state", hu, ibs->tx_ibs_state);
 
@@ -267,22 +352,11 @@
 		}
 		ibs->tx_ibs_state = HCI_IBS_TX_ASLEEP;
 		ibs->ibs_sent_slps++; /* debug */
-		vote_tx_sleep = 1;
 		break;
 	}
 
-	spin_unlock_irqrestore(&ibs->hci_ibs_lock, flags);
+	queue_work(ibs->workqueue, &ibs->ws_tx_vote_off);
 
-	hci_uart_tx_wakeup(hu);  /* run HCI tx handling unlocked */
-
-	if (!vote_tx_sleep)
-		return;
-	/* now that message queued to tty driver, vote for tty clocks off */
-	/* It is up to the tty driver to pend the clocks off until tx done. */
-
-	spin_lock_irqsave_nested(&ibs->hci_ibs_lock,
-					flags, SINGLE_DEPTH_NESTING);
-	ibs_msm_serial_clock_vote(HCI_IBS_TX_VOTE_CLOCK_OFF, hu);
 out:
 	spin_unlock_irqrestore(&ibs->hci_ibs_lock, flags);
 }
@@ -336,6 +410,19 @@
 	skb_queue_head_init(&ibs->txq);
 	skb_queue_head_init(&ibs->tx_wait_q);
 	spin_lock_init(&ibs->hci_ibs_lock);
+	ibs->workqueue = create_singlethread_workqueue("ibs_wq");
+	if (!ibs->workqueue) {
+		BT_ERR("IBS Workqueue not initialized properly");
+		kfree(ibs);
+		return -ENOMEM;
+	}
+
+	INIT_WORK(&ibs->ws_awake_rx, ibs_wq_awake_rx);
+	INIT_WORK(&ibs->ws_awake_device, ibs_wq_awake_device);
+	INIT_WORK(&ibs->ws_rx_vote_off, ibs_wq_serial_rx_clock_vote_off);
+	INIT_WORK(&ibs->ws_tx_vote_off, ibs_wq_serial_tx_clock_vote_off);
+
+	ibs->ibs_hu = (void *)hu;
 
 	/* Assume we start with both sides asleep -- extra wakes OK */
 	ibs->tx_ibs_state = HCI_IBS_TX_ASLEEP;
@@ -432,6 +519,8 @@
 	skb_queue_purge(&ibs->txq);
 	del_timer(&ibs->tx_idle_timer);
 	del_timer(&ibs->wake_retrans_timer);
+	destroy_workqueue(ibs->workqueue);
+	ibs->ibs_hu = NULL;
 
 	kfree_skb(ibs->rx_skb);
 
@@ -463,9 +552,10 @@
 		/* Make sure clock is on - we may have turned clock off since
 		 * receiving the wake up indicator
 		 */
-		ibs_msm_serial_clock_vote(HCI_IBS_RX_VOTE_CLOCK_ON, hu);
-		ibs->rx_ibs_state = HCI_IBS_RX_AWAKE;
-		/* deliberate fall-through */
+		/* awake rx clock */
+		queue_work(ibs->workqueue, &ibs->ws_awake_rx);
+		spin_unlock_irqrestore(&ibs->hci_ibs_lock, flags);
+		return;
 	case HCI_IBS_RX_AWAKE:
 		/* Always acknowledge device wake up,
 		 * sending IBS message doesn't count as TX ON.
@@ -510,7 +600,8 @@
 	case HCI_IBS_RX_AWAKE:
 		/* update state */
 		ibs->rx_ibs_state = HCI_IBS_RX_ASLEEP;
-		ibs_msm_serial_clock_vote(HCI_IBS_RX_VOTE_CLOCK_OFF, hu);
+		/* vote off rx clock under workqueue */
+		queue_work(ibs->workqueue, &ibs->ws_rx_vote_off);
 		break;
 	case HCI_IBS_RX_ASLEEP:
 		/* deliberate fall-through */
@@ -595,20 +686,12 @@
 
 	case HCI_IBS_TX_ASLEEP:
 		BT_DBG("device asleep, waking up and queueing packet");
-		ibs_msm_serial_clock_vote(HCI_IBS_TX_VOTE_CLOCK_ON, hu);
 		/* save packet for later */
 		skb_queue_tail(&ibs->tx_wait_q, skb);
-		/* awake device */
-		if (send_hci_ibs_cmd(HCI_IBS_WAKE_IND, hu) < 0) {
-			BT_ERR("cannot send WAKE to device");
-			break;
-		}
-		ibs->ibs_sent_wakes++; /* debug */
-
-		/* start retransmit timer */
-		mod_timer(&ibs->wake_retrans_timer, jiffies + wake_retrans);
 
 		ibs->tx_ibs_state = HCI_IBS_TX_WAKING;
+		/* schedule a work queue to wake up device */
+		queue_work(ibs->workqueue, &ibs->ws_awake_device);
 		break;
 
 	case HCI_IBS_TX_WAKING:
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 0febaf3..1c14859 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -17,6 +17,7 @@
 #include <linux/module.h>
 #include <linux/mempool.h>
 #include <linux/mutex.h>
+#include <linux/spinlock.h>
 #include <linux/workqueue.h>
 #include <linux/sched.h>
 #include <mach/msm_smd.h>
@@ -35,6 +36,8 @@
 #define POOL_TYPE_COPY		1
 #define POOL_TYPE_HDLC		2
 #define POOL_TYPE_WRITE_STRUCT	4
+#define POOL_TYPE_HSIC		8
+#define POOL_TYPE_HSIC_WRITE	16
 #define POOL_TYPE_ALL		7
 #define MODEM_DATA 		1
 #define QDSP_DATA  		2
@@ -272,20 +275,20 @@
 	unsigned char *buf_in_smux;
 	int in_busy_smux;
 	int diag_smux_enabled;
+	int smux_connected;
+	struct diag_request *write_ptr_mdm;
 	/* HSIC variables */
-	unsigned char *buf_in_hsic;
 	int hsic_ch;
 	int hsic_device_enabled;
 	int hsic_device_opened;
 	int hsic_suspend;
 	int in_busy_hsic_read_on_device;
-	int in_busy_hsic_write_on_device;
 	int in_busy_hsic_write;
-	int in_busy_hsic_read;
 	struct work_struct diag_read_hsic_work;
 	/* USB MDM channel variables */
 	int usb_mdm_connected;
 	int read_len_mdm;
+	int write_len_mdm;
 	unsigned char *usb_buf_mdm_out;
 	struct usb_diag_ch *mdm_ch;
 	struct workqueue_struct *diag_bridge_wq;
@@ -293,7 +296,17 @@
 	struct work_struct diag_disconnect_work;
 	struct work_struct diag_usb_read_complete_work;
 	struct diag_request *usb_read_mdm_ptr;
-	struct diag_request *write_ptr_mdm;
+	int count_hsic_pool;
+	int count_hsic_write_pool;
+	unsigned int poolsize_hsic;
+	unsigned int poolsize_hsic_write;
+	unsigned int itemsize_hsic;
+	unsigned int itemsize_hsic_write;
+	mempool_t *diag_hsic_pool;
+	mempool_t *diag_hsic_write_pool;
+	int num_hsic_buf_tbl_entries;
+	struct diag_write_device *hsic_buf_tbl;
+	spinlock_t hsic_spinlock;
 #endif
 };
 
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 30504bc..7e827b9 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -122,6 +122,27 @@
 	mutex_unlock(&driver->diagchar_mutex);
 }
 
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+void diag_clear_hsic_tbl(void)
+{
+	int i;
+
+	driver->num_hsic_buf_tbl_entries = 0;
+	for (i = 0; i < driver->poolsize_hsic_write; i++) {
+		if (driver->hsic_buf_tbl[i].buf) {
+			/* Return the buffer to the pool */
+			diagmem_free(driver, (unsigned char *)
+				(driver->hsic_buf_tbl[i].buf),
+				POOL_TYPE_HSIC);
+			driver->hsic_buf_tbl[i].buf = 0;
+		}
+		driver->hsic_buf_tbl[i].length = 0;
+	}
+}
+#else
+void diag_clear_hsic_tbl(void) { }
+#endif
+
 void diag_read_smd_work_fn(struct work_struct *work)
 {
 	__diag_smd_send_req();
@@ -243,6 +264,7 @@
 		driver->logging_mode = USB_MODE;
 		diagfwd_connect();
 #ifdef CONFIG_DIAG_BRIDGE_CODE
+		diag_clear_hsic_tbl();
 		diagfwd_cancel_hsic();
 		diagfwd_connect_bridge(0);
 #endif
@@ -489,6 +511,7 @@
 		temp = driver->logging_mode;
 		driver->logging_mode = (int)ioarg;
 		if (driver->logging_mode == MEMORY_DEVICE_MODE) {
+			diag_clear_hsic_tbl();
 			driver->mask_check = 1;
 			if (driver->socket_process) {
 				/*
@@ -506,10 +529,12 @@
 			}
 		}
 		if (driver->logging_mode == UART_MODE) {
+			diag_clear_hsic_tbl();
 			driver->mask_check = 0;
 			driver->logging_mode = MEMORY_DEVICE_MODE;
 		}
 		if (driver->logging_mode == SOCKET_MODE) {
+			diag_clear_hsic_tbl();
 			driver->socket_process = current;
 			driver->mask_check = 0;
 			driver->logging_mode = MEMORY_DEVICE_MODE;
@@ -529,6 +554,7 @@
 #endif
 #ifdef CONFIG_DIAG_BRIDGE_CODE
 			diagfwd_disconnect_bridge(0);
+			diag_clear_hsic_tbl();
 #endif
 		} else if (temp == NO_LOGGING_MODE && driver->logging_mode
 							== MEMORY_DEVICE_MODE) {
@@ -581,6 +607,7 @@
 			driver->in_busy_qdsp_2 = 0;
 			driver->in_busy_wcnss_1 = 0;
 			driver->in_busy_wcnss_2 = 0;
+
 			/* Poll SMD channels to check for data*/
 			if (driver->ch)
 				queue_work(driver->diag_wq,
@@ -606,6 +633,7 @@
 				 driver->logging_mode == USB_MODE) {
 			diagfwd_connect();
 #ifdef CONFIG_DIAG_BRIDGE_CODE
+			diag_clear_hsic_tbl();
 			diagfwd_cancel_hsic();
 			diagfwd_connect_bridge(0);
 #endif
@@ -637,6 +665,11 @@
 
 	if ((driver->data_ready[index] & USER_SPACE_LOG_TYPE) && (driver->
 					logging_mode == MEMORY_DEVICE_MODE)) {
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+		unsigned long spin_lock_flags;
+		struct diag_write_device hsic_buf_tbl[NUM_HSIC_BUF_TBL_ENTRIES];
+#endif
+
 		pr_debug("diag: process woken up\n");
 		/*Copy the type of data being passed*/
 		data_type = driver->data_ready[index] & USER_SPACE_LOG_TYPE;
@@ -767,20 +800,51 @@
 		}
 #endif
 #ifdef CONFIG_DIAG_BRIDGE_CODE
-		pr_debug("diag: Copy data to user space %d\n",
-			 driver->in_busy_hsic_write_on_device);
-		if (driver->in_busy_hsic_write_on_device == 1) {
-			num_data++;
-			/*Copy the length of data being passed*/
-			COPY_USER_SPACE_OR_EXIT(buf+ret,
-				 (driver->write_ptr_mdm->length), 4);
-			/*Copy the actual data being passed*/
-			COPY_USER_SPACE_OR_EXIT(buf+ret,
-					*(driver->buf_in_hsic),
-					 driver->write_ptr_mdm->length);
-			pr_debug("diag: data copied\n");
-			/* call the write complete function */
-			diagfwd_write_complete_hsic();
+		spin_lock_irqsave(&driver->hsic_spinlock, spin_lock_flags);
+		for (i = 0; i < driver->poolsize_hsic_write; i++) {
+			hsic_buf_tbl[i].buf = driver->hsic_buf_tbl[i].buf;
+			driver->hsic_buf_tbl[i].buf = 0;
+			hsic_buf_tbl[i].length =
+					driver->hsic_buf_tbl[i].length;
+			driver->hsic_buf_tbl[i].length = 0;
+		}
+		driver->num_hsic_buf_tbl_entries = 0;
+		spin_unlock_irqrestore(&driver->hsic_spinlock,
+					spin_lock_flags);
+
+		for (i = 0; i < driver->poolsize_hsic_write; i++) {
+			if (hsic_buf_tbl[i].length > 0) {
+				pr_debug("diag: HSIC copy to user, i: %d, buf: %x, len: %d\n",
+					 i, (unsigned int)hsic_buf_tbl[i].buf,
+					hsic_buf_tbl[i].length);
+				num_data++;
+				/* Copy the length of data being passed */
+				if (copy_to_user(buf+ret,
+					(void *)&(hsic_buf_tbl[i].length),
+					4)) {
+					num_data--;
+					goto drop_hsic;
+				}
+				ret += 4;
+
+				/* Copy the actual data being passed */
+				if (copy_to_user(buf+ret,
+						(void *)hsic_buf_tbl[i].buf,
+						hsic_buf_tbl[i].length)) {
+					ret -= 4;
+					num_data--;
+					goto drop_hsic;
+				}
+				ret += hsic_buf_tbl[i].length;
+drop_hsic:
+				/* Return the buffer to the pool */
+				diagmem_free(driver,
+					(unsigned char *)(hsic_buf_tbl[i].buf),
+					POOL_TYPE_HSIC);
+
+				/* Call the write complete function */
+				diagfwd_write_complete_hsic(NULL);
+			}
 		}
 #endif
 		/* copy number of data fields */
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 5a74e8c..c827ec7 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -16,6 +16,7 @@
 #include <linux/err.h>
 #include <linux/platform_device.h>
 #include <linux/sched.h>
+#include <linux/ratelimit.h>
 #include <linux/workqueue.h>
 #include <linux/pm_runtime.h>
 #include <linux/diagchar.h>
@@ -66,6 +67,9 @@
 	msg_mask_tbl_ptr += 4;						\
 	*(int *)(msg_mask_tbl_ptr) = MSG_SSID_ ## XX ## _LAST;		\
 	msg_mask_tbl_ptr += 4;						\
+	/* mimic the last entry as actual_last while creation */	\
+	*(int *)(msg_mask_tbl_ptr) = MSG_SSID_ ## XX ## _LAST;		\
+	msg_mask_tbl_ptr += 4;						\
 	/* increment by MAX_SSID_PER_RANGE cells */			\
 	msg_mask_tbl_ptr += MAX_SSID_PER_RANGE * sizeof(int);		\
 } while (0)
@@ -307,6 +311,32 @@
 					break;
 				}
 		}
+
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+		else if (proc_num == HSIC_DATA) {
+			unsigned long flags;
+			int foundIndex = -1;
+
+			spin_lock_irqsave(&driver->hsic_spinlock, flags);
+			for (i = 0; i < driver->poolsize_hsic_write; i++) {
+				if (driver->hsic_buf_tbl[i].length == 0) {
+					driver->hsic_buf_tbl[i].buf = buf;
+					driver->hsic_buf_tbl[i].length =
+							driver->write_len_mdm;
+					driver->num_hsic_buf_tbl_entries++;
+					foundIndex = i;
+					break;
+				}
+			}
+			spin_unlock_irqrestore(&driver->hsic_spinlock, flags);
+			if (foundIndex == -1)
+				err = -1;
+			else
+				pr_debug("diag: ENQUEUE HSIC buf ptr and length is %x , %d\n",
+					(unsigned int)buf,
+					driver->write_len_mdm);
+		}
+#endif
 		for (i = 0; i < driver->num_clients; i++)
 			if (driver->client_map[i].pid ==
 						 driver->logging_process_id)
@@ -343,8 +373,6 @@
 #endif
 #ifdef CONFIG_DIAG_BRIDGE_CODE
 		else if (proc_num == HSIC_DATA) {
-			driver->in_busy_hsic_read = 0;
-			driver->in_busy_hsic_write_on_device = 0;
 			if (driver->hsic_ch)
 				queue_work(driver->diag_bridge_wq,
 					&(driver->diag_read_hsic_work));
@@ -396,11 +424,34 @@
 #ifdef CONFIG_DIAG_BRIDGE_CODE
 		else if (proc_num == HSIC_DATA) {
 			if (driver->hsic_device_enabled) {
-				write_ptr->buf = buf;
-				err = usb_diag_write(driver->mdm_ch, write_ptr);
-			} else
+				struct diag_request *write_ptr_mdm;
+				write_ptr_mdm = (struct diag_request *)
+						diagmem_alloc(driver,
+						sizeof(struct diag_request),
+							POOL_TYPE_HSIC_WRITE);
+				if (write_ptr_mdm) {
+					write_ptr_mdm->buf = buf;
+					write_ptr_mdm->length =
+						driver->write_len_mdm;
+					err = usb_diag_write(driver->mdm_ch,
+								write_ptr_mdm);
+					/* Return to the pool immediately */
+					if (err) {
+						diagmem_free(driver,
+							write_ptr_mdm,
+							POOL_TYPE_HSIC_WRITE);
+						pr_err_ratelimited("diag: HSIC write failure, err: %d\n",
+							err);
+					}
+				} else {
+					pr_err("diag: allocate write fail\n");
+					err = -1;
+				}
+			} else {
 				pr_err("diag: Incorrect hsic data "
 						"while USB write\n");
+				err = -1;
+			}
 		} else if (proc_num == SMUX_DATA) {
 				write_ptr->buf = buf;
 				pr_debug("diag: writing SMUX data\n");
@@ -512,8 +563,7 @@
 {
 /* Enable this to print mask table when updated */
 #ifdef MASK_DEBUG
-	int first;
-	int last;
+	int first, last, actual_last;
 	uint8_t *ptr = driver->msg_masks;
 	int i = 0;
 	pr_info("diag: F3 message mask table\n");
@@ -522,11 +572,12 @@
 		ptr += 4;
 		last = *(uint32_t *)ptr;
 		ptr += 4;
-		printk(KERN_INFO "SSID %d - %d\n", first, last);
-		for (i = 0 ; i <= last - first ; i++)
-			printk(KERN_INFO "MASK:%x\n", *((uint32_t *)ptr + i));
+		actual_last = *(uint32_t *)ptr;
+		ptr += 4;
+		pr_info("diag: SSID %d, %d - %d\n", first, last, actual_last);
+		for (i = 0 ; i <= actual_last - first ; i++)
+			pr_info("diag: MASK:%x\n", *((uint32_t *)ptr + i));
 		ptr += MAX_SSID_PER_RANGE*4;
-
 	}
 #endif
 }
@@ -569,7 +620,7 @@
 	mutex_lock(&driver->diagchar_mutex);
 	while (*(uint32_t *)(ptr + 4)) {
 		first_ssid = *(uint32_t *)ptr;
-		ptr += 4;
+		ptr += 8; /* increment by 8 to skip 'last' */
 		last_ssid = *(uint32_t *)ptr;
 		ptr += 4;
 		parse_ptr = ptr;
@@ -585,9 +636,8 @@
 
 static void diag_update_msg_mask(int start, int end , uint8_t *buf)
 {
-	int found = 0;
-	int first;
-	int last;
+	int found = 0, first, last, actual_last;
+	uint8_t *actual_last_ptr;
 	uint8_t *ptr = driver->msg_masks;
 	uint8_t *ptr_buffer_start = &(*(driver->msg_masks));
 	uint8_t *ptr_buffer_end = &(*(driver->msg_masks)) + MSG_MASK_SIZE;
@@ -600,23 +650,23 @@
 		ptr += 4;
 		last = *(uint32_t *)ptr;
 		ptr += 4;
-		if (start >= first && start <= last) {
+		actual_last = *(uint32_t *)ptr;
+		actual_last_ptr = ptr;
+		ptr += 4;
+		if (start >= first && start <= actual_last) {
 			ptr += (start - first)*4;
-			if (end <= last)
-				if (CHK_OVERFLOW(ptr_buffer_start, ptr,
-						  ptr_buffer_end,
-						  (((end - start)+1)*4))) {
-					pr_debug("diag: update ssid start %d,"
-						 " end %d\n", start, end);
-					memcpy(ptr, buf , ((end - start)+1)*4);
-				} else
-					printk(KERN_CRIT "Not enough"
-							 " buffer space for"
-							 " MSG_MASK\n");
-			else
-				printk(KERN_INFO "Unable to copy"
-						 " mask change\n");
-
+			if (end > actual_last) {
+				pr_info("diag: ssid range mismatch\n");
+				actual_last = end;
+				*(uint32_t *)(actual_last_ptr) = end;
+			}
+			if (CHK_OVERFLOW(ptr_buffer_start, ptr, ptr_buffer_end,
+					  (((end - start)+1)*4))) {
+				pr_debug("diag: update ssid start %d, end %d\n",
+								 start, end);
+				memcpy(ptr, buf , ((end - start)+1)*4);
+			} else
+				pr_alert("diag: Not enough space MSG_MASK\n");
 			found = 1;
 			break;
 		} else {
@@ -631,16 +681,16 @@
 			ptr += 4;
 			memcpy(ptr, &(end), 4);
 			ptr += 4;
+			memcpy(ptr, &(end), 4); /* create actual_last entry */
+			ptr += 4;
 			pr_debug("diag: adding NEW ssid start %d, end %d\n",
 								 start, end);
 			memcpy(ptr, buf , ((end - start) + 1)*4);
 		} else
-			printk(KERN_CRIT " Not enough buffer"
-					 " space for MSG_MASK\n");
+			pr_alert("diag: Not enough buffer space for MSG_MASK\n");
 	}
 	mutex_unlock(&driver->diagchar_mutex);
 	diag_print_mask_table();
-
 }
 
 void diag_toggle_event_mask(int toggle)
@@ -691,6 +741,30 @@
 	mutex_unlock(&driver->diagchar_mutex);
 }
 
+int chk_equip_id_and_mask(int equip_id, uint8_t *buf)
+{
+	int i = 0, flag = 0, num_items, offset;
+	unsigned char *ptr_data;
+	struct mask_info *ptr = (struct mask_info *)(driver->log_masks);
+
+	pr_debug("diag: received equip id = %d\n", equip_id);
+	/* Check if this is valid equipment ID */
+	for (i = 0; i < MAX_EQUIP_ID; i++) {
+		if ((ptr->equip_id == equip_id) && (ptr->index != 0)) {
+			offset = ptr->index;
+			num_items = ptr->num_items;
+			flag = 1;
+			break;
+		}
+		ptr++;
+	}
+	if (!flag)
+		return -EPERM;
+	ptr_data = driver->log_masks + offset;
+	memcpy(buf, ptr_data, (num_items+7)/8);
+	return 0;
+}
+
 static void diag_update_log_mask(int equip_id, uint8_t *buf, int num_items)
 {
 	uint8_t *temp = buf;
@@ -916,7 +990,7 @@
 						int updated_ssid_last, int proc)
 {
 	void *buf = driver->buf_msg_mask_update;
-	int first, last, size = -ENOMEM, retry_count = 0, timer;
+	int first, last, actual_last, size = -ENOMEM, retry_count = 0, timer;
 	int header_size = sizeof(struct diag_ctrl_msg_mask);
 	uint8_t *ptr = driver->msg_masks;
 
@@ -926,18 +1000,21 @@
 		ptr += 4;
 		last = *(uint32_t *)ptr;
 		ptr += 4;
-		if ((updated_ssid_first >= first && updated_ssid_last <= last)
-					 || (updated_ssid_first == ALL_SSID)) {
+		actual_last = *(uint32_t *)ptr;
+		ptr += 4;
+		if ((updated_ssid_first >= first && updated_ssid_last <=
+			 actual_last) || (updated_ssid_first == ALL_SSID)) {
 			/* send f3 mask update */
 			driver->msg_mask->cmd_type = DIAG_CTRL_MSG_F3_MASK;
-			driver->msg_mask->msg_mask_size = last - first + 1;
+			driver->msg_mask->msg_mask_size = actual_last -
+								 first + 1;
 			driver->msg_mask->data_len = 11 +
 					 4 * (driver->msg_mask->msg_mask_size);
 			driver->msg_mask->stream_id = 1; /* 2, if dual stream */
 			driver->msg_mask->status = 3; /* status valid mask */
 			driver->msg_mask->msg_mode = 0; /* Legcay mode */
 			driver->msg_mask->ssid_first = first;
-			driver->msg_mask->ssid_last = last;
+			driver->msg_mask->ssid_last = actual_last;
 			memcpy(buf, driver->msg_mask, header_size);
 			memcpy(buf+header_size, ptr,
 				 4 * (driver->msg_mask->msg_mask_size));
@@ -959,8 +1036,8 @@
 	 "fail %d, tried %d\n", proc, size,
 	 header_size + 4*(driver->msg_mask->msg_mask_size));
 				else
-					pr_debug("diag: sending mask update for"
-		"ssid first %d, last %d on PROC %d\n", first, last, proc);
+					pr_debug("diag: sending mask update for ssid first %d, last %d on PROC %d\n",
+						first, actual_last, proc);
 			} else
 				pr_err("diag: proc %d, ch invalid msg mask"
 						 "update\n", proc);
@@ -978,7 +1055,7 @@
 	int rt_mask, rt_first_ssid, rt_last_ssid, rt_mask_size;
 	unsigned char *temp = buf;
 	uint8_t *rt_mask_ptr;
-	int data_type;
+	int data_type, equip_id, num_items;
 #if defined(CONFIG_DIAG_OVER_USB)
 	int payload_length;
 	unsigned char *ptr;
@@ -1012,6 +1089,29 @@
 		} else
 			buf = temp;
 #endif
+	} /* Get log masks */
+	else if (*buf == 0x73 && *(int *)(buf+4) == 4) {
+#if defined(CONFIG_DIAG_OVER_USB)
+		if (!(driver->ch) && chk_apps_only()) {
+			equip_id = *(int *)(buf + 8);
+			num_items = *(int *)(buf + 12);
+			driver->apps_rsp_buf[0] = 0x73;
+			driver->apps_rsp_buf[1] = 0x0;
+			driver->apps_rsp_buf[2] = 0x0;
+			driver->apps_rsp_buf[3] = 0x0;
+			*(int *)(driver->apps_rsp_buf + 4) = 0x4;
+			if (!chk_equip_id_and_mask(equip_id,
+						 driver->apps_rsp_buf+20))
+				*(int *)(driver->apps_rsp_buf + 8) = 0x0;
+			else
+				*(int *)(driver->apps_rsp_buf + 8) = 0x1;
+			*(int *)(driver->apps_rsp_buf + 12) = equip_id;
+			*(int *)(driver->apps_rsp_buf + 16) = num_items;
+			ENCODE_RSP_AND_SEND(20+(num_items+7)/8-1);
+			return 0;
+		} else
+			buf = temp;
+#endif
 	} /* Disable log masks */
 	else if (*buf == 0x73 && *(int *)(buf+4) == 0) {
 		/* Disable mask for each log code */
@@ -1052,7 +1152,7 @@
 			rt_mask_ptr = driver->msg_masks;
 			while (*(uint32_t *)(rt_mask_ptr + 4)) {
 				rt_first_ssid = *(uint32_t *)rt_mask_ptr;
-				rt_mask_ptr += 4;
+				rt_mask_ptr += 8; /* +8 to skip 'last' */
 				rt_last_ssid = *(uint32_t *)rt_mask_ptr;
 				rt_mask_ptr += 4;
 				if (ssid_first == rt_first_ssid && ssid_last ==
diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c
index 95abd21..52fd673 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.c
@@ -401,7 +401,8 @@
 		"in_busy_qdsp_2: %d\n"
 		"in_busy_wcnss_1: %d\n"
 		"in_busy_wcnss_2: %d\n"
-		"in_busy_dci: %d\n",
+		"in_busy_dci: %d\n"
+		"logging_mode: %d\n",
 		(unsigned int)driver->ch,
 		(unsigned int)driver->chqdsp,
 		(unsigned int)driver->ch_wcnss,
@@ -421,7 +422,8 @@
 		driver->in_busy_qdsp_2,
 		driver->in_busy_wcnss_1,
 		driver->in_busy_wcnss_2,
-		driver->in_busy_dci);
+		driver->in_busy_dci,
+		driver->logging_mode);
 
 #ifdef CONFIG_DIAG_OVER_USB
 	ret += scnprintf(buf+ret, DEBUG_BUF_SIZE,
@@ -541,7 +543,7 @@
 	return ret;
 }
 
-#ifdef CONFIG_DIAG_HSIC_PIPE
+#ifdef CONFIG_DIAG_BRIDGE_CODE
 static ssize_t diag_dbgfs_read_hsic(struct file *file, char __user *ubuf,
 				    size_t count, loff_t *ppos)
 {
@@ -555,29 +557,35 @@
 	}
 
 	ret = scnprintf(buf, DEBUG_BUF_SIZE,
-		"hsic initialized: %d\n"
 		"hsic ch: %d\n"
 		"hsic enabled: %d\n"
 		"hsic_opened: %d\n"
-		"hisc_suspend: %d\n"
-		"in_busy_hsic_read_on_mdm: %d\n"
-		"in_busy_hsic_write_on_mdm: %d\n"
+		"hsic_suspend: %d\n"
+		"in_busy_hsic_read_on_device: %d\n"
 		"in_busy_hsic_write: %d\n"
-		"in_busy_hsic_read: %d\n"
+		"count_hsic_pool: %d\n"
+		"count_hsic_write_pool: %d\n"
+		"diag_hsic_pool: %x\n"
+		"diag_hsic_write_pool: %x\n"
+		"write_len_mdm: %d\n"
+		"num_hsic_buf_tbl_entries: %d\n"
 		"usb_mdm_connected: %d\n"
 		"diag_read_mdm_work: %d\n"
 		"diag_read_hsic_work: %d\n"
 		"diag_disconnect_work: %d\n"
 		"diag_usb_read_complete_work: %d\n",
-		driver->hsic_initialized,
 		driver->hsic_ch,
 		driver->hsic_device_enabled,
 		driver->hsic_device_opened,
 		driver->hsic_suspend,
 		driver->in_busy_hsic_read_on_device,
-		driver->in_busy_hsic_write_on_device,
 		driver->in_busy_hsic_write,
-		driver->in_busy_hsic_read,
+		driver->count_hsic_pool,
+		driver->count_hsic_write_pool,
+		(unsigned int)driver->diag_hsic_pool,
+		(unsigned int)driver->diag_hsic_write_pool,
+		driver->write_len_mdm,
+		driver->num_hsic_buf_tbl_entries,
 		driver->usb_mdm_connected,
 		work_pending(&(driver->diag_read_mdm_work)),
 		work_pending(&(driver->diag_read_hsic_work)),
@@ -622,7 +630,7 @@
 	debugfs_create_file("work_pending", 0444, diag_dbgfs_dent, 0,
 		&diag_dbgfs_workpending_ops);
 
-#ifdef CONFIG_DIAG_HSIC_PIPE
+#ifdef CONFIG_DIAG_BRIDGE_CODE
 	debugfs_create_file("hsic", 0444, diag_dbgfs_dent, 0,
 		&diag_dbgfs_hsic_ops);
 #endif
diff --git a/drivers/char/diag/diagfwd_hsic.c b/drivers/char/diag/diagfwd_hsic.c
index fedcf03..3878a82 100644
--- a/drivers/char/diag/diagfwd_hsic.c
+++ b/drivers/char/diag/diagfwd_hsic.c
@@ -32,48 +32,90 @@
 #include "diagfwd_hsic.h"
 #include "diagfwd_smux.h"
 
+#define READ_HSIC_BUF_SIZE 2048
+
 static void diag_read_hsic_work_fn(struct work_struct *work)
 {
+	unsigned char *buf_in_hsic = NULL;
+	int num_reads_submitted = 0;
+	int err = 0;
+	int write_ptrs_available;
+
 	if (!driver->hsic_ch) {
 		pr_err("DIAG in %s: driver->hsic_ch == 0\n", __func__);
 		return;
 	}
 
-	/* If there is no hsic data being read from the hsic and there
-	 * is no hsic data being written to the device
+	/*
+	 * Determine the current number of available buffers for writing after
+	 * reading from the HSIC has completed.
 	 */
-	if (!driver->in_busy_hsic_read &&
-			 !driver->in_busy_hsic_write_on_device) {
-		/*
-		 * Initiate the read from the hsic.  The hsic read is
-		 * asynchronous.  Once the read is complete the read
-		 * callback function will be called.
-		 */
-		int err;
-		driver->in_busy_hsic_read = 1;
-		APPEND_DEBUG('i');
-		pr_debug("diag: read from HSIC\n");
-		err = diag_bridge_read((char *)driver->buf_in_hsic,
-					IN_BUF_SIZE);
-		if (err) {
-			pr_err_ratelimited("DIAG: Error initiating HSIC read, err: %d\n",
-				err);
-			/*
-			 * If the error is recoverable, then clear
-			 * the read flag, so we will resubmit a
-			 * read on the next frame.  Otherwise, don't
-			 * resubmit a read on the next frame.
-			 */
-			if ((-ENODEV) != err)
-				driver->in_busy_hsic_read = 0;
-		}
-	}
+	if (driver->logging_mode == MEMORY_DEVICE_MODE)
+		write_ptrs_available = driver->poolsize_hsic_write -
+					driver->num_hsic_buf_tbl_entries;
+	else
+		write_ptrs_available = driver->poolsize_hsic_write -
+					driver->count_hsic_write_pool;
 
 	/*
-	 * If for some reason there was no hsic data, set up
-	 * the next read
+	 * Queue up a read on the HSIC for all available buffers in the
+	 * pool, exhausting the pool.
 	 */
-	if (!driver->in_busy_hsic_read)
+	do {
+		/*
+		 * If no more write buffers are available,
+		 * stop queuing reads
+		 */
+		if (write_ptrs_available <= 0)
+			break;
+
+		write_ptrs_available--;
+
+		/*
+		 * No sense queuing a read if the hsic bridge was
+		 * closed in another thread
+		 */
+		if (!driver->hsic_ch)
+			break;
+
+		buf_in_hsic = diagmem_alloc(driver, READ_HSIC_BUF_SIZE,
+							POOL_TYPE_HSIC);
+		if (buf_in_hsic) {
+			/*
+			 * Initiate the read from the hsic.  The hsic read is
+			 * asynchronous.  Once the read is complete the read
+			 * callback function will be called.
+			 */
+			pr_debug("diag: read from HSIC\n");
+			num_reads_submitted++;
+			err = diag_bridge_read((char *)buf_in_hsic,
+							READ_HSIC_BUF_SIZE);
+			if (err) {
+				num_reads_submitted--;
+
+				/* Return the buffer to the pool */
+				diagmem_free(driver, buf_in_hsic,
+						POOL_TYPE_HSIC);
+
+				pr_err_ratelimited("diag: Error initiating HSIC read, err: %d\n",
+					err);
+				/*
+				 * An error occurred, discontinue queuing
+				 * reads
+				 */
+				break;
+			}
+		}
+	} while (buf_in_hsic);
+
+	/*
+	 * If there are read buffers available and for some reason the
+	 * read was not queued, and if no unrecoverable error occurred
+	 * (-ENODEV is an unrecoverable error), then set up the next read
+	 */
+	if ((driver->count_hsic_pool < driver->poolsize_hsic) &&
+		(num_reads_submitted == 0) && (err != -ENODEV) &&
+		(driver->hsic_ch != 0))
 		queue_work(driver->diag_bridge_wq,
 				 &driver->diag_read_hsic_work);
 }
@@ -81,45 +123,62 @@
 static void diag_hsic_read_complete_callback(void *ctxt, char *buf,
 					int buf_size, int actual_size)
 {
-	/* The read of the data from the HSIC bridge is complete */
-	driver->in_busy_hsic_read = 0;
+	int err = -2;
 
 	if (!driver->hsic_ch) {
-		pr_err("DIAG in %s: driver->hsic_ch == 0\n", __func__);
+		/*
+		 * The hsic channel is closed. Return the buffer to
+		 * the pool.  Do not send it on.
+		 */
+		diagmem_free(driver, buf, POOL_TYPE_HSIC);
+		pr_debug("diag: In %s: driver->hsic_ch == 0, actual_size: %d\n",
+			__func__, actual_size);
 		return;
 	}
 
-	APPEND_DEBUG('j');
-	if (actual_size > 0) {
+	/*
+	 * Note that zero length is valid and still needs to be sent to
+	 * the USB only when we are logging data to the USB
+	 */
+	if ((actual_size > 0) ||
+		((actual_size == 0) && (driver->logging_mode == USB_MODE))) {
 		if (!buf) {
-			pr_err("Out of diagmem for HSIC\n");
+			pr_err("diag: Out of diagmem for HSIC\n");
 		} else {
-			driver->write_ptr_mdm->length = actual_size;
 			/*
-			 * Set flag to denote hsic data is currently
-			 * being written to the usb mdm channel.
-			 * driver->buf_in_hsic was given to
-			 * diag_bridge_read(), so buf here should be
-			 * driver->buf_in_hsic
+			 * Send data in buf to be written on the
+			 * appropriate device, e.g. USB MDM channel
 			 */
-			driver->in_busy_hsic_write_on_device = 1;
-			pr_debug("diag: write to device\n");
-			diag_device_write((void *)buf, HSIC_DATA,
-						driver->write_ptr_mdm);
+			driver->write_len_mdm = actual_size;
+			err = diag_device_write((void *)buf, HSIC_DATA, NULL);
+			/* If an error, return buffer to the pool */
+			if (err) {
+				diagmem_free(driver, buf, POOL_TYPE_HSIC);
+				pr_err_ratelimited("diag: In %s, error calling diag_device_write, err: %d\n",
+					__func__, err);
+			}
 		}
 	} else {
-		pr_debug("%s: actual_size: %d\n", __func__, actual_size);
+		/*
+		 * The buffer has an error status associated with it. Do not
+		 * pass it on. Note that -ENOENT is sent when the diag bridge
+		 * is closed.
+		 */
+		diagmem_free(driver, buf, POOL_TYPE_HSIC);
+		pr_debug("diag: In %s: error status: %d\n", __func__,
+			actual_size);
 	}
 
 	/*
 	 * If for some reason there was no hsic data to write to the
 	 * mdm channel, set up another read
 	 */
-	if (!driver->in_busy_hsic_write_on_device && ((driver->logging_mode
-			== MEMORY_DEVICE_MODE) || (driver->usb_mdm_connected &&
-						    !driver->hsic_suspend)))
+	if (err &&
+		((driver->logging_mode == MEMORY_DEVICE_MODE) ||
+		(driver->usb_mdm_connected && !driver->hsic_suspend))) {
 		queue_work(driver->diag_bridge_wq,
 				 &driver->diag_read_hsic_work);
+	}
 }
 
 static void diag_hsic_write_complete_callback(void *ctxt, char *buf,
@@ -143,6 +202,8 @@
 static int diag_hsic_suspend(void *ctxt)
 {
 	pr_debug("diag: hsic_suspend\n");
+
+	/* Don't allow suspend if a write in the HSIC is in progress */
 	if (driver->in_busy_hsic_write)
 		return -EBUSY;
 
@@ -160,8 +221,9 @@
 	pr_debug("diag: hsic_resume\n");
 	driver->hsic_suspend = 0;
 
-	if (!driver->in_busy_hsic_write_on_device && (driver->logging_mode
-			== MEMORY_DEVICE_MODE || driver->usb_mdm_connected))
+	if ((driver->count_hsic_pool < driver->poolsize_hsic) &&
+		((driver->logging_mode == MEMORY_DEVICE_MODE) ||
+				(driver->usb_mdm_connected)))
 		queue_work(driver->diag_bridge_wq,
 			 &driver->diag_read_hsic_work);
 }
@@ -202,10 +264,10 @@
 			diag_bridge_close();
 			err = diag_bridge_open(&hsic_diag_bridge_ops);
 			if (err) {
-				pr_err("DIAG: HSIC channel open error: %d\n",
+				pr_err("diag: HSIC channel open error: %d\n",
 					err);
 			} else {
-				pr_debug("DIAG: opened HSIC channel\n");
+				pr_debug("diag: opened HSIC channel\n");
 				driver->hsic_device_opened = 1;
 				driver->hsic_ch = 1;
 			}
@@ -234,10 +296,8 @@
 	}
 
 	if (driver->hsic_device_enabled) {
-		driver->in_busy_hsic_write_on_device = 0;
 		driver->in_busy_hsic_read_on_device = 0;
 		driver->in_busy_hsic_write = 0;
-		driver->in_busy_hsic_read = 0;
 	} else if (driver->diag_smux_enabled) {
 		driver->in_busy_smux = 0;
 		diagfwd_connect_smux();
@@ -288,7 +348,7 @@
  */
 int diagfwd_disconnect_bridge(int process_cable)
 {
-	pr_debug("DIAG in %s\n", __func__);
+	pr_debug("diag: In %s, process_cable: %d\n", __func__, process_cable);
 
 	/* If the usb cable is being disconnected */
 	if (process_cable) {
@@ -296,20 +356,19 @@
 		usb_diag_free_req(driver->mdm_ch);
 	}
 
-	if (driver->logging_mode != MEMORY_DEVICE_MODE) {
-		if (driver->hsic_device_enabled) {
-			driver->in_busy_hsic_write_on_device = 1;
-			driver->in_busy_hsic_read_on_device = 1;
-			driver->in_busy_hsic_write = 1;
-			driver->in_busy_hsic_read = 1;
-			/* Turn off communication over usb mdm and hsic */
-			return diag_hsic_close();
-		} else if (driver->diag_smux_enabled) {
-			driver->in_busy_smux = 1;
-			driver->lcid = LCID_INVALID;
-			/* Turn off communication over usb mdm and smux */
-			msm_smux_close(LCID_VALID);
-		}
+	if (driver->hsic_device_enabled &&
+		driver->logging_mode != MEMORY_DEVICE_MODE) {
+		driver->in_busy_hsic_read_on_device = 1;
+		driver->in_busy_hsic_write = 1;
+		/* Turn off communication over usb mdm and hsic */
+		return diag_hsic_close();
+	} else if (driver->diag_smux_enabled &&
+		driver->logging_mode == USB_MODE) {
+		driver->in_busy_smux = 1;
+		driver->lcid = LCID_INVALID;
+		driver->smux_connected = 0;
+		/* Turn off communication over usb mdm and smux */
+		msm_smux_close(LCID_VALID);
 	}
 	return 0;
 }
@@ -318,19 +377,21 @@
  * diagfwd_write_complete_hsic is called after the asynchronous
  * usb_diag_write() on mdm channel is complete
  */
-int diagfwd_write_complete_hsic(void)
+int diagfwd_write_complete_hsic(struct diag_request *diag_write_ptr)
 {
-	/*
-	 * Clear flag to denote that the write of the hsic data on the
-	 * usb mdm channel is complete
-	 */
-	driver->in_busy_hsic_write_on_device = 0;
-	if (!driver->hsic_ch) {
-		pr_err("DIAG in %s: driver->hsic_ch == 0\n", __func__);
-		return 0;
+	unsigned char *buf = (diag_write_ptr) ? diag_write_ptr->buf : NULL;
+
+	if (buf) {
+		/* Return buffers to their pools */
+		diagmem_free(driver, (unsigned char *)buf, POOL_TYPE_HSIC);
+		diagmem_free(driver, (unsigned char *)diag_write_ptr,
+							POOL_TYPE_HSIC_WRITE);
 	}
 
-	APPEND_DEBUG('q');
+	if (!driver->hsic_ch) {
+		pr_err("diag: In %s: driver->hsic_ch == 0\n", __func__);
+		return 0;
+	}
 
 	/* Read data from the hsic */
 	queue_work(driver->diag_bridge_wq, &driver->diag_read_hsic_work);
@@ -374,7 +435,7 @@
 		err = diag_bridge_write(driver->usb_buf_mdm_out,
 					driver->read_len_mdm);
 		if (err) {
-			pr_err_ratelimited("DIAG: mdm data on hsic write err: %d\n",
+			pr_err_ratelimited("diag: mdm data on hsic write err: %d\n",
 					err);
 			/*
 			 * If the error is recoverable, then clear
@@ -414,7 +475,7 @@
 		break;
 	case USB_DIAG_WRITE_DONE:
 		if (driver->hsic_device_enabled)
-			diagfwd_write_complete_hsic();
+			diagfwd_write_complete_hsic(d_req);
 		else if (driver->diag_smux_enabled)
 			diagfwd_write_complete_smux();
 		break;
@@ -440,7 +501,8 @@
 	int ret;
 	if (driver->diag_smux_enabled) {
 		if (driver->lcid && driver->usb_buf_mdm_out &&
-					 (driver->read_len_mdm > 0)) {
+				(driver->read_len_mdm > 0) &&
+				driver->smux_connected) {
 			ret = msm_smux_write(driver->lcid,  NULL,
 		 driver->usb_buf_mdm_out, driver->read_len_mdm);
 			if (ret)
@@ -490,8 +552,7 @@
 	int err = 0;
 	pr_debug("diag: in %s\n", __func__);
 	if (!driver->hsic_device_enabled) {
-		if (driver->buf_in_hsic == NULL)
-			driver->buf_in_hsic = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
+		diagmem_hsic_init(driver);
 		INIT_WORK(&(driver->diag_read_hsic_work),
 					 diag_read_hsic_work_fn);
 		driver->hsic_device_enabled = 1;
@@ -515,10 +576,9 @@
 		pr_info("diag: opened HSIC channel\n");
 		driver->hsic_device_opened = 1;
 		driver->hsic_ch = 1;
-		driver->in_busy_hsic_write_on_device = 0;
+
 		driver->in_busy_hsic_read_on_device = 0;
 		driver->in_busy_hsic_write = 0;
-		driver->in_busy_hsic_read = 0;
 
 		if (driver->usb_mdm_connected) {
 			/* Poll USB mdm channel to check for data */
@@ -536,7 +596,7 @@
 
 static int diag_hsic_remove(struct platform_device *pdev)
 {
-	pr_debug("DIAG: %s called\n", __func__);
+	pr_debug("diag: %s called\n", __func__);
 	diag_hsic_close();
 	return 0;
 }
@@ -576,11 +636,15 @@
 	driver->diag_bridge_wq = create_singlethread_workqueue(
 							"diag_bridge_wq");
 	driver->read_len_mdm = 0;
+	driver->write_len_mdm = 0;
+	driver->num_hsic_buf_tbl_entries = 0;
+	spin_lock_init(&driver->hsic_spinlock);
 	if (driver->usb_buf_mdm_out  == NULL)
 		driver->usb_buf_mdm_out = kzalloc(USB_MAX_OUT_BUF,
 							 GFP_KERNEL);
 	if (driver->usb_buf_mdm_out == NULL)
 		goto err;
+	/* Only used by smux move to smux probe function */
 	if (driver->write_ptr_mdm == NULL)
 		driver->write_ptr_mdm = kzalloc(
 		sizeof(struct diag_request), GFP_KERNEL);
@@ -592,6 +656,20 @@
 	if (driver->usb_read_mdm_ptr == NULL)
 		goto err;
 
+	if (driver->hsic_buf_tbl == NULL)
+		driver->hsic_buf_tbl = kzalloc(NUM_HSIC_BUF_TBL_ENTRIES *
+				sizeof(struct diag_write_device), GFP_KERNEL);
+	if (driver->hsic_buf_tbl == NULL)
+		goto err;
+
+	driver->count_hsic_pool = 0;
+	driver->count_hsic_write_pool = 0;
+
+	driver->itemsize_hsic = READ_HSIC_BUF_SIZE;
+	driver->poolsize_hsic = N_MDM_WRITE;
+	driver->itemsize_hsic_write = sizeof(struct diag_request);
+	driver->poolsize_hsic_write = N_MDM_WRITE;
+
 #ifdef CONFIG_DIAG_OVER_USB
 	INIT_WORK(&(driver->diag_read_mdm_work), diag_read_mdm_work_fn);
 #endif
@@ -606,10 +684,6 @@
 		goto err;
 	}
 #endif
-#ifdef CONFIG_DIAG_BRIDGE_CODE
-	INIT_WORK(&(driver->diag_disconnect_work), diag_disconnect_work_fn);
-	INIT_WORK(&(driver->diag_usb_read_complete_work),
-			diag_usb_read_complete_fn);
 	/* register HSIC device */
 	ret = platform_driver_register(&msm_hsic_ch_driver);
 	if (ret)
@@ -618,11 +692,12 @@
 	ret = platform_driver_register(&msm_diagfwd_smux_driver);
 	if (ret)
 		pr_err("diag: could not register SMUX device, ret: %d\n", ret);
-#endif
+
 	return;
 err:
 	pr_err("diag: Could not initialize for bridge forwarding\n");
 	kfree(driver->usb_buf_mdm_out);
+	kfree(driver->hsic_buf_tbl);
 	kfree(driver->write_ptr_mdm);
 	kfree(driver->usb_read_mdm_ptr);
 	if (driver->diag_bridge_wq)
@@ -637,8 +712,8 @@
 
 	if (driver->hsic_device_enabled) {
 		diag_hsic_close();
-		kfree(driver->buf_in_hsic);
 		driver->hsic_device_enabled = 0;
+		diagmem_exit(driver, POOL_TYPE_ALL);
 	}
 	if (driver->diag_smux_enabled) {
 		driver->lcid = LCID_INVALID;
@@ -654,6 +729,7 @@
 	usb_diag_close(driver->mdm_ch);
 #endif
 	kfree(driver->usb_buf_mdm_out);
+	kfree(driver->hsic_buf_tbl);
 	kfree(driver->write_ptr_mdm);
 	kfree(driver->usb_read_mdm_ptr);
 	destroy_workqueue(driver->diag_bridge_wq);
diff --git a/drivers/char/diag/diagfwd_hsic.h b/drivers/char/diag/diagfwd_hsic.h
index b189c94..19ed3c7 100644
--- a/drivers/char/diag/diagfwd_hsic.h
+++ b/drivers/char/diag/diagfwd_hsic.h
@@ -14,12 +14,15 @@
 #define DIAGFWD_HSIC_H
 
 #include <mach/diag_bridge.h>
-#define N_MDM_WRITE	1 /* Upgrade to 2 with ping pong buffer */
+
+#define N_MDM_WRITE	8
 #define N_MDM_READ	1
 
+#define NUM_HSIC_BUF_TBL_ENTRIES N_MDM_WRITE
+
 int diagfwd_connect_bridge(int);
 int diagfwd_disconnect_bridge(int);
-int diagfwd_write_complete_hsic(void);
+int diagfwd_write_complete_hsic(struct diag_request *);
 int diagfwd_cancel_hsic(void);
 void diagfwd_bridge_init(void);
 void diagfwd_bridge_exit(void);
diff --git a/drivers/char/diag/diagfwd_smux.c b/drivers/char/diag/diagfwd_smux.c
index 8bbc67e..ae90686 100644
--- a/drivers/char/diag/diagfwd_smux.c
+++ b/drivers/char/diag/diagfwd_smux.c
@@ -26,13 +26,17 @@
 
 	switch (event_type) {
 	case SMUX_CONNECTED:
-		pr_debug("diag: SMUX_CONNECTED received\n");
+		pr_info("diag: SMUX_CONNECTED received\n");
+		driver->smux_connected = 1;
 		driver->in_busy_smux = 0;
 		/* read data from USB MDM channel & Initiate first write */
 		queue_work(driver->diag_bridge_wq,
 				 &(driver->diag_read_mdm_work));
 		break;
 	case SMUX_DISCONNECTED:
+		driver->smux_connected = 0;
+		driver->lcid = LCID_INVALID;
+		msm_smux_close(LCID_VALID);
 		pr_info("diag: SMUX_DISCONNECTED received\n");
 		break;
 	case SMUX_WRITE_DONE:
@@ -112,6 +116,7 @@
 			pr_info("diag: open SMUX ch, r = %d\n", ret);
 		} else {
 			pr_err("diag: failed to open SMUX ch, r = %d\n", ret);
+			return ret;
 		}
 	}
 	/* Poll USB channel to check for data*/
@@ -146,8 +151,20 @@
 	return ret;
 }
 
+static int diagfwd_smux_remove(struct platform_device *pdev)
+{
+	driver->lcid = LCID_INVALID;
+	driver->smux_connected = 0;
+	driver->diag_smux_enabled = 0;
+	driver->in_busy_smux = 1;
+	kfree(driver->buf_in_smux);
+	driver->buf_in_smux = NULL;
+	return 0;
+}
+
 struct platform_driver msm_diagfwd_smux_driver = {
 	.probe = diagfwd_smux_probe,
+	.remove = diagfwd_smux_remove,
 	.driver = {
 		   .name = "SMUX_DIAG",
 		   .owner = THIS_MODULE,
diff --git a/drivers/char/diag/diagmem.c b/drivers/char/diag/diagmem.c
index 0b5c27a..82c47af 100644
--- a/drivers/char/diag/diagmem.c
+++ b/drivers/char/diag/diagmem.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2010, 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
@@ -51,6 +51,28 @@
 				driver->diag_write_struct_pool, GFP_ATOMIC);
 			}
 		}
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+	} else if (pool_type == POOL_TYPE_HSIC) {
+		if (driver->diag_hsic_pool) {
+			if (driver->count_hsic_pool < driver->poolsize_hsic) {
+				atomic_add(1,
+					(atomic_t *)&driver->count_hsic_pool);
+				buf = mempool_alloc(driver->diag_hsic_pool,
+								GFP_ATOMIC);
+			}
+		}
+	} else if (pool_type == POOL_TYPE_HSIC_WRITE) {
+		if (driver->diag_hsic_write_pool) {
+			if (driver->count_hsic_write_pool <
+				driver->poolsize_hsic_write) {
+				atomic_add(1, (atomic_t *)
+					&driver->count_hsic_write_pool);
+				buf = mempool_alloc(
+					driver->diag_hsic_write_pool,
+					GFP_ATOMIC);
+			}
+		}
+#endif
 	}
 	return buf;
 }
@@ -63,7 +85,7 @@
 			driver->diagpool = NULL;
 		} else if (driver->ref_count == 0 && pool_type == POOL_TYPE_ALL)
 			printk(KERN_ALERT "Unable to destroy COPY mempool");
-		}
+	}
 
 	if (driver->diag_hdlc_pool) {
 		if (driver->count_hdlc_pool == 0 && driver->ref_count == 0) {
@@ -71,7 +93,7 @@
 			driver->diag_hdlc_pool = NULL;
 		} else if (driver->ref_count == 0 && pool_type == POOL_TYPE_ALL)
 			printk(KERN_ALERT "Unable to destroy HDLC mempool");
-		}
+	}
 
 	if (driver->diag_write_struct_pool) {
 		/* Free up struct pool ONLY if there are no outstanding
@@ -82,7 +104,30 @@
 			driver->diag_write_struct_pool = NULL;
 		} else if (driver->ref_count == 0 && pool_type == POOL_TYPE_ALL)
 			printk(KERN_ALERT "Unable to destroy STRUCT mempool");
-		}
+	}
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+	if (driver->diag_hsic_pool && (driver->hsic_device_enabled == 0)) {
+		if (driver->count_hsic_pool == 0) {
+			mempool_destroy(driver->diag_hdlc_pool);
+			driver->diag_hdlc_pool = NULL;
+		} else if (pool_type == POOL_TYPE_ALL)
+			pr_err("Unable to destroy HDLC mempool");
+	}
+
+	if (driver->diag_hsic_write_pool &&
+		(driver->hsic_device_enabled == 0)) {
+		/*
+		 * Free up struct pool ONLY if there are no outstanding
+		 * transactions(aggregation buffer) with USB
+		 */
+		if (driver->count_hsic_write_pool == 0 &&
+			driver->count_hsic_pool == 0) {
+			mempool_destroy(driver->diag_hsic_write_pool);
+			driver->diag_hsic_write_pool = NULL;
+		} else if (pool_type == POOL_TYPE_ALL)
+			pr_err("Unable to destroy HSIC USB struct mempool");
+	}
+#endif
 }
 
 void diagmem_free(struct diagchar_dev *driver, void *buf, int pool_type)
@@ -112,6 +157,29 @@
 			pr_err("diag: Attempt to free up DIAG driver "
 			   "USB structure mempool which is already free %d ",
 				    driver->count_write_struct_pool);
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+	} else if (pool_type == POOL_TYPE_HSIC) {
+		if (driver->diag_hsic_pool != NULL &&
+			driver->count_hsic_pool > 0) {
+			mempool_free(buf, driver->diag_hsic_pool);
+			atomic_add(-1, (atomic_t *)&driver->count_hsic_pool);
+		} else
+			pr_err("diag: Attempt to free up DIAG driver HSIC mempool which is already free %d ",
+				driver->count_hsic_pool);
+	} else if (pool_type == POOL_TYPE_HSIC_WRITE) {
+		if (driver->diag_hsic_write_pool != NULL &&
+			driver->count_hsic_write_pool > 0) {
+			mempool_free(buf, driver->diag_hsic_write_pool);
+			atomic_add(-1,
+				(atomic_t *)&driver->count_hsic_write_pool);
+		} else
+			pr_err("diag: Attempt to free up DIAG driver HSIC USB structure mempool which is already free %d ",
+				driver->count_write_struct_pool);
+#endif
+	} else {
+		pr_err("diag: In %s, unknown pool type: %d\n",
+			__func__, pool_type);
+
 	}
 
 	diagmem_exit(driver, pool_type);
@@ -143,3 +211,25 @@
 		printk(KERN_INFO "Cannot allocate diag USB struct mempool\n");
 }
 
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+void diagmem_hsic_init(struct diagchar_dev *driver)
+{
+	if (driver->count_hsic_pool == 0)
+		driver->diag_hsic_pool = mempool_create_kmalloc_pool(
+					driver->poolsize_hsic,
+					driver->itemsize_hsic);
+
+	if (driver->count_hsic_write_pool == 0)
+		driver->diag_hsic_write_pool = mempool_create_kmalloc_pool(
+					driver->poolsize_hsic_write,
+					driver->itemsize_hsic_write);
+
+	if (!driver->diag_hsic_pool)
+		pr_err("Cannot allocate diag HSIC mempool\n");
+
+	if (!driver->diag_hsic_write_pool)
+		pr_err("Cannot allocate diag HSIC struct mempool\n");
+
+}
+#endif
+
diff --git a/drivers/char/diag/diagmem.h b/drivers/char/diag/diagmem.h
index 43829ae..8665c75 100644
--- a/drivers/char/diag/diagmem.h
+++ b/drivers/char/diag/diagmem.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2010, 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
@@ -18,5 +18,7 @@
 void diagmem_free(struct diagchar_dev *driver, void *buf, int pool_type);
 void diagmem_init(struct diagchar_dev *driver);
 void diagmem_exit(struct diagchar_dev *driver, int pool_type);
-
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+void diagmem_hsic_init(struct diagchar_dev *driver);
+#endif
 #endif
diff --git a/drivers/coresight/Makefile b/drivers/coresight/Makefile
index 76aef4c..4ee93cf 100644
--- a/drivers/coresight/Makefile
+++ b/drivers/coresight/Makefile
@@ -1,2 +1,3 @@
 
-obj-$(CONFIG_MSM_QDSS) += coresight.o coresight-tpiu.o coresight-etb.o coresight-funnel.o coresight-replicator.o coresight-stm.o coresight-etm.o
+obj-$(CONFIG_OF) += of_coresight.o
+obj-$(CONFIG_MSM_QDSS) += coresight.o coresight-csr.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-csr.c b/drivers/coresight/coresight-csr.c
new file mode 100644
index 0000000..e9ac904
--- /dev/null
+++ b/drivers/coresight/coresight-csr.c
@@ -0,0 +1,202 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/of_coresight.h>
+#include <linux/coresight.h>
+
+#include "coresight-priv.h"
+
+#define csr_writel(drvdata, val, off)	__raw_writel((val), drvdata->base + off)
+#define csr_readl(drvdata, off)		__raw_readl(drvdata->base + off)
+
+#define CSR_LOCK(drvdata)						\
+do {									\
+	mb();								\
+	csr_writel(drvdata, 0x0, CORESIGHT_LAR);			\
+} while (0)
+#define CSR_UNLOCK(drvdata)						\
+do {									\
+	csr_writel(drvdata, CORESIGHT_UNLOCK, CORESIGHT_LAR);		\
+	mb();								\
+} while (0)
+
+#define CSR_SWDBGPWRCTRL	(0x000)
+#define CSR_SWDBGPWRACK		(0x004)
+#define CSR_SWSPADREG0		(0x008)
+#define CSR_SWSPADREG1		(0x00C)
+#define CSR_STMTRANSCTRL	(0x010)
+#define CSR_STMAWIDCTRL		(0x014)
+#define CSR_STMCHNOFST0		(0x018)
+#define CSR_STMCHNOFST1		(0x01C)
+#define CSR_STMEXTHWCTRL0	(0x020)
+#define CSR_STMEXTHWCTRL1	(0x024)
+#define CSR_STMEXTHWCTRL2	(0x028)
+#define CSR_STMEXTHWCTRL3	(0x02C)
+#define CSR_USBBAMCTRL		(0x030)
+#define CSR_USBFLSHCTRL		(0x034)
+#define CSR_TIMESTAMPCTRL	(0x038)
+#define CSR_AOTIMEVAL0		(0x03C)
+#define CSR_AOTIMEVAL1		(0x040)
+#define CSR_QDSSTIMEVAL0	(0x044)
+#define CSR_QDSSTIMEVAL1	(0x048)
+#define CSR_QDSSTIMELOAD0	(0x04C)
+#define CSR_QDSSTIMELOAD1	(0x050)
+#define CSR_DAPMSAVAL		(0x054)
+#define CSR_QDSSCLKVOTE		(0x058)
+#define CSR_QDSSCLKIPI		(0x05C)
+#define CSR_QDSSPWRREQIGNORE	(0x060)
+#define CSR_QDSSSPARE		(0x064)
+#define CSR_IPCAT		(0x068)
+
+#define BLKSIZE_256		0
+#define BLKSIZE_512		1
+#define BLKSIZE_1024		2
+#define BLKSIZE_2048		3
+
+struct csr_drvdata {
+	void __iomem		*base;
+	struct device		*dev;
+	struct coresight_device	*csdev;
+};
+
+static struct csr_drvdata *csrdrvdata;
+
+void msm_qdss_csr_enable_bam_to_usb(void)
+{
+	struct csr_drvdata *drvdata = csrdrvdata;
+	uint32_t usbbamctrl, usbflshctrl;
+
+	CSR_UNLOCK(drvdata);
+
+	usbbamctrl = csr_readl(drvdata, CSR_USBBAMCTRL);
+	usbbamctrl = (usbbamctrl & ~0x3) | BLKSIZE_256;
+	csr_writel(drvdata, usbbamctrl, CSR_USBBAMCTRL);
+
+	usbflshctrl = csr_readl(drvdata, CSR_USBFLSHCTRL);
+	usbflshctrl = (usbflshctrl & ~0x3FFFC) | (0x1000 << 2);
+	csr_writel(drvdata, usbflshctrl, CSR_USBFLSHCTRL);
+	usbflshctrl |= 0x2;
+	csr_writel(drvdata, usbflshctrl, CSR_USBFLSHCTRL);
+
+	usbbamctrl |= 0x4;
+	csr_writel(drvdata, usbbamctrl, CSR_USBBAMCTRL);
+
+	CSR_LOCK(drvdata);
+}
+EXPORT_SYMBOL_GPL(msm_qdss_csr_enable_bam_to_usb);
+
+void msm_qdss_csr_disable_bam_to_usb(void)
+{
+	struct csr_drvdata *drvdata = csrdrvdata;
+	uint32_t usbbamctrl;
+
+	CSR_UNLOCK(drvdata);
+
+	usbbamctrl = csr_readl(drvdata, CSR_USBBAMCTRL);
+	usbbamctrl &= (~0x4);
+	csr_writel(drvdata, usbbamctrl, CSR_USBBAMCTRL);
+
+	CSR_LOCK(drvdata);
+}
+EXPORT_SYMBOL_GPL(msm_qdss_csr_disable_bam_to_usb);
+
+static int __devinit csr_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct coresight_platform_data *pdata;
+	struct csr_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;
+	/* Store the driver data pointer for use in exported functions */
+	csrdrvdata = drvdata;
+	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;
+
+	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
+	if (!desc)
+		return -ENOMEM;
+	desc->type = CORESIGHT_DEV_TYPE_NONE;
+	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, "CSR initialized\n");
+	return 0;
+}
+
+static int __devexit csr_remove(struct platform_device *pdev)
+{
+	struct csr_drvdata *drvdata = platform_get_drvdata(pdev);
+
+	coresight_unregister(drvdata->csdev);
+	return 0;
+}
+
+static struct of_device_id csr_match[] = {
+	{.compatible = "qcom,coresight-csr"},
+	{}
+};
+
+static struct platform_driver csr_driver = {
+	.probe          = csr_probe,
+	.remove         = __devexit_p(csr_remove),
+	.driver         = {
+		.name   = "coresight-csr",
+		.owner	= THIS_MODULE,
+		.of_match_table = csr_match,
+	},
+};
+
+static int __init csr_init(void)
+{
+	return platform_driver_register(&csr_driver);
+}
+module_init(csr_init);
+
+static void __exit csr_exit(void)
+{
+	platform_driver_unregister(&csr_driver);
+}
+module_exit(csr_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CoreSight CSR driver");
diff --git a/drivers/coresight/coresight-etb.c b/drivers/coresight/coresight-etb.c
index a9283ee2..bd5bf8e 100644
--- a/drivers/coresight/coresight-etb.c
+++ b/drivers/coresight/coresight-etb.c
@@ -25,11 +25,11 @@
 #include <linux/delay.h>
 #include <linux/spinlock.h>
 #include <linux/clk.h>
+#include <linux/of_coresight.h>
 #include <linux/coresight.h>
 
 #include "coresight-priv.h"
 
-
 #define etb_writel(drvdata, val, off)	__raw_writel((val), drvdata->base + off)
 #define etb_readl(drvdata, off)		__raw_readl(drvdata->base + off)
 
@@ -44,7 +44,6 @@
 	mb();								\
 } while (0)
 
-
 #define ETB_RAM_DEPTH_REG	(0x004)
 #define ETB_STATUS_REG		(0x00C)
 #define ETB_RAM_READ_DATA_REG	(0x010)
@@ -63,12 +62,10 @@
 #define ETB_ITATBCTR1		(0xEF4)
 #define ETB_ITATBCTR0		(0xEF8)
 
-
 #define BYTES_PER_WORD		4
 #define ETB_SIZE_WORDS		4096
 #define FRAME_SIZE_WORDS	4
 
-
 struct etb_drvdata {
 	void __iomem		*base;
 	struct device		*dev;
@@ -83,7 +80,6 @@
 	uint32_t		trigger_cntr;
 };
 
-
 static void __etb_enable(struct etb_drvdata *drvdata)
 {
 	int i;
@@ -131,7 +127,9 @@
 	ETB_UNLOCK(drvdata);
 
 	ffcr = etb_readl(drvdata, ETB_FFCR);
-	ffcr |= (BIT(12) | BIT(6));
+	ffcr |= BIT(12);
+	etb_writel(drvdata, ffcr, ETB_FFCR);
+	ffcr |= BIT(6);
 	etb_writel(drvdata, ffcr, ETB_FFCR);
 	for (count = TIMEOUT_US; BVAL(etb_readl(drvdata, ETB_FFCR), 6) != 0
 				&& count > 0; count--)
@@ -219,9 +217,24 @@
 	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 = {
@@ -344,10 +357,18 @@
 {
 	int ret;
 	struct device *dev = &pdev->dev;
+	struct coresight_platform_data *pdata;
 	struct etb_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;
@@ -357,6 +378,7 @@
 	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;
@@ -366,6 +388,7 @@
 	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;
@@ -414,7 +437,7 @@
 }
 
 static struct of_device_id etb_match[] = {
-	{.compatible = "coresight-etb"},
+	{.compatible = "arm,coresight-etb"},
 	{}
 };
 
diff --git a/drivers/coresight/coresight-etm.c b/drivers/coresight/coresight-etm.c
index d7f657d..182e50c 100644
--- a/drivers/coresight/coresight-etm.c
+++ b/drivers/coresight/coresight-etm.c
@@ -23,18 +23,17 @@
 #include <linux/delay.h>
 #include <linux/smp.h>
 #include <linux/wakelock.h>
-#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, val, off)	\
 			__raw_writel((val), drvdata->base + off)
 #define etm_readl(drvdata, off)		\
@@ -51,7 +50,6 @@
 	mb();								\
 } while (0)
 
-
 /*
  * Device registers:
  * 0x000 - 0x2FC: Trace		registers
@@ -116,7 +114,6 @@
 #define ETMPDCR			(0x310)
 #define ETMPDSR			(0x314)
 
-
 #define ETM_MAX_ADDR_CMP	(16)
 #define ETM_MAX_CNTR		(4)
 #define ETM_MAX_CTXID_CMP	(3)
@@ -142,7 +139,6 @@
 	ETM_ADDR_TYPE_STOP,
 };
 
-
 #ifdef CONFIG_MSM_QDSS_ETM_DEFAULT_ENABLE
 static int boot_enable = 1;
 #else
@@ -159,7 +155,6 @@
 	struct clk			*clk;
 	struct mutex			mutex;
 	struct wake_lock		wake_lock;
-	struct pm_qos_request		qos_req;
 	int				cpu;
 	uint8_t				arch;
 	uint8_t				nr_addr_cmp;
@@ -198,6 +193,7 @@
 	uint32_t			timestamp_event;
 };
 
+static struct etm_drvdata *etm0drvdata;
 
 /* ETM clock is derived from the processor clock and gets enabled on a
  * logical OR of below items on Krait (pass2 onwards):
@@ -262,9 +258,10 @@
 	     etm_readl(drvdata, ETMSR));
 }
 
-static void __etm_enable(struct etm_drvdata *drvdata)
+static void __etm_enable(void *info)
 {
 	int i;
+	struct etm_drvdata *drvdata = info;
 
 	ETM_UNLOCK(drvdata);
 	/* Vote for ETM power/clock enable */
@@ -309,6 +306,8 @@
 
 	etm_clr_prog(drvdata);
 	ETM_LOCK(drvdata);
+
+	dev_dbg(drvdata->dev, "cpu: %d enable smp call done\n", drvdata->cpu);
 }
 
 static int etm_enable(struct coresight_device *csdev)
@@ -317,36 +316,31 @@
 	int ret;
 
 	wake_lock(&drvdata->wake_lock);
-	/* 1. causes all online cpus to come out of idle PC
-	 * 2. prevents idle PC until save restore flag is enabled atomically
-	 *
-	 * we rely on the user to prevent hotplug on/off racing with this
-	 * operation and to ensure cores where trace is expected to be turned
-	 * on are already hotplugged on
-	 */
-	pm_qos_update_request(&drvdata->qos_req, 0);
 
 	ret = clk_prepare_enable(drvdata->clk);
 	if (ret)
 		goto err_clk;
 
 	mutex_lock(&drvdata->mutex);
-	__etm_enable(drvdata);
+	/* executing __etm_enable on the cpu whose ETM is being enabled
+	 * ensures that register writes occur when cpu is powered.
+	 */
+	smp_call_function_single(drvdata->cpu, __etm_enable, drvdata, 1);
 	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_clk:
-	pm_qos_update_request(&drvdata->qos_req, PM_QOS_DEFAULT_VALUE);
 	wake_unlock(&drvdata->wake_lock);
 	return ret;
 }
 
-static void __etm_disable(struct etm_drvdata *drvdata)
+static void __etm_disable(void *info)
 {
+	struct etm_drvdata *drvdata = info;
+
 	ETM_UNLOCK(drvdata);
 	etm_set_prog(drvdata);
 
@@ -356,6 +350,8 @@
 	/* Vote for ETM power/clock disable */
 	etm_set_pwrdwn(drvdata);
 	ETM_LOCK(drvdata);
+
+	dev_dbg(drvdata->dev, "cpu: %d disable smp call done\n", drvdata->cpu);
 }
 
 static void etm_disable(struct coresight_device *csdev)
@@ -363,22 +359,16 @@
 	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
-	 * 2. prevents idle PC until save restore flag is disabled atomically
-	 *
-	 * we rely on the user to prevent hotplug on/off racing with this
-	 * operation and to ensure cores where trace is expected to be turned
-	 * off are already hotplugged on
-	 */
-	pm_qos_update_request(&drvdata->qos_req, 0);
 
 	mutex_lock(&drvdata->mutex);
-	__etm_disable(drvdata);
+	/* executing __etm_disable on the cpu whose ETM is being disabled
+	 * ensures that register writes occur when cpu is powered.
+	 */
+	smp_call_function_single(drvdata->cpu, __etm_disable, drvdata, 1);
 	mutex_unlock(&drvdata->mutex);
 
 	clk_disable_unprepare(drvdata->clk);
 
-	pm_qos_update_request(&drvdata->qos_req, PM_QOS_DEFAULT_VALUE);
 	wake_unlock(&drvdata->wake_lock);
 
 	dev_info(drvdata->dev, "ETM tracing disabled\n");
@@ -481,7 +471,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);
@@ -1459,6 +1453,16 @@
 	return ret;
 }
 
+static void __devinit etm_copy_arch_data(struct etm_drvdata *drvdata)
+{
+	drvdata->arch = etm0drvdata->arch;
+	drvdata->nr_addr_cmp = etm0drvdata->nr_addr_cmp;
+	drvdata->nr_cntr = etm0drvdata->nr_cntr;
+	drvdata->nr_ext_inp = etm0drvdata->nr_ext_inp;
+	drvdata->nr_ext_out = etm0drvdata->nr_ext_out;
+	drvdata->nr_ctxid_cmp = etm0drvdata->nr_ctxid_cmp;
+}
+
 static void __devinit etm_init_default_data(struct etm_drvdata *drvdata)
 {
 	int i;
@@ -1483,7 +1487,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 */
@@ -1506,11 +1514,25 @@
 {
 	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;
 
+	/* Fail probe for Krait pass3 until supported */
+	if (cpu_is_krait_v3()) {
+		dev_info(dev, "ETM: failing probe for Krait pass3\n");
+		return -EINVAL;
+	}
+
+	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;
@@ -1520,20 +1542,20 @@
 	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;
 
 	mutex_init(&drvdata->mutex);
 	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->clk = devm_clk_get(dev, "core_clk");
 	if (IS_ERR(drvdata->clk)) {
 		ret = PTR_ERR(drvdata->clk);
 		goto err0;
 	}
+
 	ret = clk_set_rate(drvdata->clk, CORESIGHT_CLK_RATE_TRACE);
 	if (ret)
 		goto err0;
@@ -1543,10 +1565,23 @@
 	ret = clk_prepare_enable(drvdata->clk);
 	if (ret)
 		goto err0;
-	ret = etm_init_arch_data(drvdata);
-	if (ret)
-		goto err1;
+
+	/* Use CPU0 to populate read-only configuration data for ETM0. For other
+	 * ETMs copy it over from ETM0.
+	 */
+	if (drvdata->cpu == 0) {
+		ret = etm_init_arch_data(drvdata);
+		if (ret)
+			goto err1;
+		etm0drvdata = drvdata;
+	} else {
+		if (etm0drvdata)
+			etm_copy_arch_data(drvdata);
+		else
+			goto err1;
+	}
 	etm_init_default_data(drvdata);
+
 	clk_disable_unprepare(drvdata->clk);
 
 	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
@@ -1576,7 +1611,6 @@
 err1:
 	clk_disable_unprepare(drvdata->clk);
 err0:
-	pm_qos_remove_request(&drvdata->qos_req);
 	wake_lock_destroy(&drvdata->wake_lock);
 	mutex_destroy(&drvdata->mutex);
 	return ret;
@@ -1587,14 +1621,13 @@
 	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);
 	return 0;
 }
 
 static struct of_device_id etm_match[] = {
-	{.compatible = "coresight-etm"},
+	{.compatible = "arm,coresight-etm"},
 	{}
 };
 
diff --git a/drivers/coresight/coresight-funnel.c b/drivers/coresight/coresight-funnel.c
index 5072f7a..3d5c0c2 100644
--- a/drivers/coresight/coresight-funnel.c
+++ b/drivers/coresight/coresight-funnel.c
@@ -20,11 +20,11 @@
 #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, val, off)	\
 			__raw_writel((val), drvdata->base + off)
 #define funnel_readl(drvdata, off)		\
@@ -41,7 +41,6 @@
 	mb();								\
 } while (0)
 
-
 #define FUNNEL_FUNCTL		(0x000)
 #define FUNNEL_PRICTL		(0x004)
 #define FUNNEL_ITATBDATA0	(0xEEC)
@@ -49,12 +48,10 @@
 #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;
 	struct device		*dev;
@@ -63,7 +60,6 @@
 	uint32_t		priority;
 };
 
-
 static void __funnel_enable(struct funnel_drvdata *drvdata, int port)
 {
 	uint32_t functl;
@@ -173,10 +169,18 @@
 {
 	int ret;
 	struct device *dev = &pdev->dev;
+	struct coresight_platform_data *pdata;
 	struct funnel_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;
@@ -186,6 +190,7 @@
 	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;
@@ -193,6 +198,7 @@
 	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;
@@ -224,7 +230,7 @@
 }
 
 static struct of_device_id funnel_match[] = {
-	{.compatible = "coresight-funnel"},
+	{.compatible = "arm,coresight-funnel"},
 	{}
 };
 
diff --git a/drivers/coresight/coresight-priv.h b/drivers/coresight/coresight-priv.h
index a6486da..2b00242 100644
--- a/drivers/coresight/coresight-priv.h
+++ b/drivers/coresight/coresight-priv.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -15,7 +15,6 @@
 
 #include <linux/bitops.h>
 
-
 /* Coresight management registers (0xF00-0xFCC)
  * 0xFA0 - 0xFA4: Management	registers in PFTv1.0
  *		  Trace		registers in PFTv1.1
@@ -29,7 +28,6 @@
 #define CORESIGHT_DEVID		(0xFC8)
 #define CORESIGHT_DEVTYPE	(0xFCC)
 
-
 #define CORESIGHT_UNLOCK	(0xC5ACCE55)
 
 #define TIMEOUT_US		(100)
@@ -38,4 +36,12 @@
 #define BMVAL(val, lsb, msb)	((val & BM(lsb, msb)) >> lsb)
 #define BVAL(val, n)		((val & BIT(n)) >> n)
 
+#ifdef CONFIG_MSM_QDSS
+extern void msm_qdss_csr_enable_bam_to_usb(void);
+extern void msm_qdss_csr_disable_bam_to_usb(void);
+#else
+static inline void msm_qdss_csr_enable_bam_to_usb(void) {}
+static inline void msm_qdss_csr_disable_bam_to_usb(void) {}
+#endif
+
 #endif
diff --git a/drivers/coresight/coresight-replicator.c b/drivers/coresight/coresight-replicator.c
index 7fe355d..fec76c5 100644
--- a/drivers/coresight/coresight-replicator.c
+++ b/drivers/coresight/coresight-replicator.c
@@ -19,11 +19,11 @@
 #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)		\
@@ -40,13 +40,11 @@
 	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;
@@ -54,7 +52,6 @@
 	struct clk		*clk;
 };
 
-
 static void __replicator_enable(struct replicator_drvdata *drvdata, int outport)
 {
 	REPLICATOR_UNLOCK(drvdata);
@@ -124,10 +121,18 @@
 {
 	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;
@@ -137,6 +142,7 @@
 	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;
@@ -144,6 +150,7 @@
 	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;
@@ -174,7 +181,7 @@
 }
 
 static struct of_device_id replicator_match[] = {
-	{.compatible = "coresight-replicator"},
+	{.compatible = "qcom,coresight-replicator"},
 	{}
 };
 
diff --git a/drivers/coresight/coresight-stm.c b/drivers/coresight/coresight-stm.c
index 242418c..70b2c43 100644
--- a/drivers/coresight/coresight-stm.c
+++ b/drivers/coresight/coresight-stm.c
@@ -24,13 +24,13 @@
 #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, off)		__raw_readl(drvdata->base + off)
 
@@ -45,12 +45,37 @@
 	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)
@@ -73,7 +98,6 @@
 					(ch * BYTES_PER_CHANNEL))
 #define stm_channel_off(type, opts)	(type & ~opts)
 
-
 #ifdef CONFIG_MSM_QDSS_STM_DEFAULT_ENABLE
 static int boot_enable = 1;
 #else
@@ -101,6 +125,7 @@
 	struct coresight_device	*csdev;
 	struct miscdevice	miscdev;
 	struct clk		*clk;
+	spinlock_t		spinlock;
 	struct channel_space	chs;
 	bool			enable;
 	uint32_t		entity;
@@ -108,15 +133,93 @@
 
 static struct stm_drvdata *stmdrvdata;
 
+static int stm_hwevent_isenable(struct stm_drvdata *drvdata)
+{
+	int ret = 0;
 
-static void __stm_enable(struct stm_drvdata *drvdata)
+	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);
+
+	return ret;
+}
+
+static void __stm_hwevent_enable(struct stm_drvdata *drvdata)
 {
 	STM_UNLOCK(drvdata);
 
-	stm_writel(drvdata, 0x80, STMSYNCR);
-	stm_writel(drvdata, 0xFFFFFFFF, STMSPTER);
+	/* Program STMHETER to ensure TRIGOUTHETE (fed to CTI) is asserted
+	   for HW events.
+	*/
+	stm_writel(drvdata, 0xFFFFFFFF, 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, 0x10, STMSPTRIGCSR);
 	stm_writel(drvdata, 0xFFFFFFFF, STMSPER);
-	stm_writel(drvdata, 0x30003, STMTCSR);
+
+	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, 0xFFF, STMSYNCR);
+	/* SYNCEN is read-only and HWTEN is not implemented */
+	stm_writel(drvdata, 0x100003, STMTCSR);
 
 	STM_LOCK(drvdata);
 }
@@ -130,30 +233,73 @@
 	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, STMHEMCR);
+	stm_writel(drvdata, 0x0, STMHEER);
+	stm_writel(drvdata, 0x0, STMHETER);
+
+	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, STMSPTRIGCSR);
+
+	STM_LOCK(drvdata);
+}
+
+static void stm_port_disable(struct stm_drvdata *drvdata)
+{
+	spin_lock(&drvdata->spinlock);
+	if (drvdata->enable)
+		__stm_port_disable(drvdata);
+	spin_unlock(&drvdata->spinlock);
+}
+
 static void __stm_disable(struct stm_drvdata *drvdata)
 {
 	STM_UNLOCK(drvdata);
 
-	stm_writel(drvdata, 0x30000, STMTCSR);
-	stm_writel(drvdata, 0x0, STMSPER);
-	stm_writel(drvdata, 0x0, STMSPTER);
+	stm_writel(drvdata, 0x100000, STMTCSR);
 
 	STM_LOCK(drvdata);
+
+	__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);
 
@@ -384,6 +530,70 @@
 	.llseek		= no_llseek,
 };
 
+static ssize_t stm_show_hwevent_enable(struct device *dev,
+				       struct device_attribute *attr, char *buf)
+{
+	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_hwevent_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_hwevent_enable(drvdata);
+	else
+		stm_hwevent_disable(drvdata);
+
+	if (ret)
+		return ret;
+	return size;
+}
+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)
 {
@@ -410,6 +620,8 @@
 		   stm_store_entity);
 
 static struct attribute *stm_attrs[] = {
+	&dev_attr_hwevent_enable.attr,
+	&dev_attr_port_enable.attr,
 	&dev_attr_entity.attr,
 	NULL,
 };
@@ -427,11 +639,19 @@
 {
 	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;
 
+	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;
@@ -443,6 +663,7 @@
 	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;
@@ -450,6 +671,7 @@
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
 	if (!res)
 		return -ENODEV;
+
 	if (boot_nr_channel) {
 		res_size = min((resource_size_t)(boot_nr_channel *
 				  BYTES_PER_CHANNEL), resource_size(res));
@@ -466,9 +688,12 @@
 	if (!drvdata->chs.bitmap)
 		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;
@@ -518,7 +743,7 @@
 }
 
 static struct of_device_id stm_match[] = {
-	{.compatible = "coresight-stm"},
+	{.compatible = "arm,coresight-stm"},
 	{}
 };
 
diff --git a/drivers/coresight/coresight-tmc.c b/drivers/coresight/coresight-tmc.c
new file mode 100644
index 0000000..995ad86
--- /dev/null
+++ b/drivers/coresight/coresight-tmc.c
@@ -0,0 +1,1167 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 <linux/usb/usb_qdss.h>
+#include <mach/memory.h>
+#include <mach/sps.h>
+#include <mach/usb_bam.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
+#define TMC_ETR_BAM_PIPE_INDEX	0
+#define TMC_ETR_BAM_NR_PIPES	2
+
+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_etr_out_mode {
+	TMC_ETR_OUT_MODE_NONE,
+	TMC_ETR_OUT_MODE_MEM,
+	TMC_ETR_OUT_MODE_USB,
+};
+
+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_etr_bam_data {
+	struct sps_bam_props	props;
+	uint32_t		handle;
+	struct sps_pipe		*pipe;
+	struct sps_connect	connect;
+	uint32_t		src_pipe_idx;
+	uint32_t		dest;
+	uint32_t		dest_pipe_idx;
+	struct sps_mem_buffer	desc_fifo;
+	struct sps_mem_buffer	data_fifo;
+	bool			enable;
+};
+
+struct tmc_drvdata {
+	void __iomem		*base;
+	struct device		*dev;
+	struct coresight_device	*csdev;
+	struct miscdevice	miscdev;
+	struct clk		*clk;
+	spinlock_t		spinlock;
+	struct mutex		read_lock;
+	int			read_count;
+	bool			reading;
+	char			*buf;
+	unsigned long		paddr;
+	void __iomem		*vaddr;
+	uint32_t		size;
+	struct mutex		usb_lock;
+	struct usb_qdss_ch	*usbch;
+	struct tmc_etr_bam_data	*bamdata;
+	enum tmc_etr_out_mode	out_mode;
+	bool			enable_to_bam;
+	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_etr_fill_usb_bam_data(struct tmc_drvdata *drvdata)
+{
+	struct tmc_etr_bam_data *bamdata = drvdata->bamdata;
+
+	get_bam2bam_connection_info(0, PEER_PERIPHERAL_TO_USB,
+				    &bamdata->dest,
+				    &bamdata->dest_pipe_idx,
+				    &bamdata->src_pipe_idx,
+				    &bamdata->desc_fifo,
+				    &bamdata->data_fifo);
+}
+
+static void __tmc_etr_enable_to_bam(struct tmc_drvdata *drvdata)
+{
+	struct tmc_etr_bam_data *bamdata = drvdata->bamdata;
+	uint32_t axictl;
+
+	if (drvdata->enable_to_bam)
+		return;
+
+	/* Configure and enable required CSR registers */
+	msm_qdss_csr_enable_bam_to_usb();
+
+	/* Configure and enable ETR for usb bam output */
+
+	TMC_UNLOCK(drvdata);
+
+	tmc_writel(drvdata, bamdata->data_fifo.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, bamdata->data_fifo.phys_base, TMC_DBALO);
+	tmc_writel(drvdata, 0x0, TMC_DBAHI);
+	tmc_writel(drvdata, 0x133, TMC_FFCR);
+	tmc_writel(drvdata, drvdata->trigger_cntr, TMC_TRG);
+	__tmc_enable(drvdata);
+
+	TMC_LOCK(drvdata);
+
+	drvdata->enable_to_bam = true;
+}
+
+static int tmc_etr_bam_enable(struct tmc_drvdata *drvdata)
+{
+	struct tmc_etr_bam_data *bamdata = drvdata->bamdata;
+	int ret;
+
+	if (bamdata->enable)
+		return 0;
+
+	/* Configure and enable ndp bam */
+
+	bamdata->pipe = sps_alloc_endpoint();
+	if (!bamdata->pipe)
+		return -ENOMEM;
+
+	ret = sps_get_config(bamdata->pipe, &bamdata->connect);
+	if (ret)
+		goto err;
+
+	bamdata->connect.mode = SPS_MODE_SRC;
+	bamdata->connect.source = bamdata->handle;
+	bamdata->connect.event_thresh = 0x4;
+	bamdata->connect.src_pipe_index = TMC_ETR_BAM_PIPE_INDEX;
+	bamdata->connect.options = SPS_O_AUTO_ENABLE;
+
+	bamdata->connect.destination = bamdata->dest;
+	bamdata->connect.dest_pipe_index = bamdata->dest_pipe_idx;
+	bamdata->connect.desc = bamdata->desc_fifo;
+	bamdata->connect.data = bamdata->data_fifo;
+
+	ret = sps_connect(bamdata->pipe, &bamdata->connect);
+	if (ret)
+		goto err;
+
+	bamdata->enable = true;
+	return 0;
+err:
+	sps_free_endpoint(bamdata->pipe);
+	return ret;
+}
+
+static void __tmc_etr_disable_to_bam(struct tmc_drvdata *drvdata)
+{
+	if (!drvdata->enable_to_bam)
+		return;
+
+	TMC_UNLOCK(drvdata);
+
+	tmc_flush_and_stop(drvdata);
+	__tmc_disable(drvdata);
+
+	TMC_LOCK(drvdata);
+
+	/* Disable CSR registers */
+	msm_qdss_csr_disable_bam_to_usb();
+	drvdata->enable_to_bam = false;
+}
+
+static void tmc_etr_bam_disable(struct tmc_drvdata *drvdata)
+{
+	struct tmc_etr_bam_data *bamdata = drvdata->bamdata;
+
+	if (!bamdata->enable)
+		return;
+
+	sps_disconnect(bamdata->pipe);
+	sps_free_endpoint(bamdata->pipe);
+	bamdata->enable = false;
+}
+
+static void usb_notifier(void *priv, unsigned int event,
+			struct qdss_request *d_req, struct usb_qdss_ch *ch)
+{
+	struct tmc_drvdata *drvdata = priv;
+	unsigned long flags;
+	int ret = 0;
+
+	mutex_lock(&drvdata->usb_lock);
+	if (event == USB_QDSS_CONNECT) {
+		tmc_etr_fill_usb_bam_data(drvdata);
+		ret = tmc_etr_bam_enable(drvdata);
+		if (ret)
+			dev_err(drvdata->dev, "ETR BAM enable failed\n");
+
+		spin_lock_irqsave(&drvdata->spinlock, flags);
+		__tmc_etr_enable_to_bam(drvdata);
+		spin_unlock_irqrestore(&drvdata->spinlock, flags);
+	} else if (event == USB_QDSS_DISCONNECT) {
+		spin_lock_irqsave(&drvdata->spinlock, flags);
+		__tmc_etr_disable_to_bam(drvdata);
+		spin_unlock_irqrestore(&drvdata->spinlock, flags);
+		tmc_etr_bam_disable(drvdata);
+	}
+	mutex_unlock(&drvdata->usb_lock);
+}
+
+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_to_mem(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_writel(drvdata, drvdata->trigger_cntr, TMC_TRG);
+	__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;
+
+	mutex_lock(&drvdata->usb_lock);
+	if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
+		if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB) {
+			drvdata->usbch = usb_qdss_open("qdss", drvdata,
+						       usb_notifier);
+			if (IS_ERR(drvdata->usbch)) {
+				dev_err(drvdata->dev, "usb_qdss_open failed\n");
+				ret = PTR_ERR(drvdata->usbch);
+				goto err0;
+			}
+		}
+	}
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+	if (drvdata->reading) {
+		ret = -EBUSY;
+		goto err1;
+	}
+
+	if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
+		__tmc_etb_enable(drvdata);
+	} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
+		if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM)
+			__tmc_etr_enable_to_mem(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);
+	mutex_unlock(&drvdata->usb_lock);
+
+	dev_info(drvdata->dev, "TMC enabled\n");
+	return 0;
+err1:
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+	if (drvdata->config_type == TMC_CONFIG_TYPE_ETR)
+		if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB)
+			usb_qdss_close(drvdata->usbch);
+err0:
+	mutex_unlock(&drvdata->usb_lock);
+	clk_disable_unprepare(drvdata->clk);
+	return ret;
+}
+
+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 - drvdata->paddr;
+	else
+		drvdata->buf = drvdata->vaddr;
+}
+
+static void __tmc_etr_disable_to_mem(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;
+	bool etr_bam_disable = false;
+
+	mutex_lock(&drvdata->usb_lock);
+	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) {
+		if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM)
+			__tmc_etr_disable_to_mem(drvdata);
+		else if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB)
+			etr_bam_disable = true;
+	} 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);
+
+	if (etr_bam_disable) {
+		if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
+			if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB) {
+				spin_lock_irqsave(&drvdata->spinlock, flags);
+				__tmc_etr_disable_to_bam(drvdata);
+				spin_unlock_irqrestore(&drvdata->spinlock,
+						       flags);
+				tmc_etr_bam_disable(drvdata);
+				usb_qdss_close(drvdata->usbch);
+			}
+		}
+	}
+	mutex_unlock(&drvdata->usb_lock);
+
+	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) {
+		if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM)
+			__tmc_etr_disable_to_mem(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) {
+		if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM) {
+			__tmc_etr_disable_to_mem(drvdata);
+		} else {
+			ret = -ENODEV;
+			goto err;
+		}
+	} 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) {
+		if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM)
+			__tmc_etr_enable_to_mem(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;
+
+	mutex_lock(&drvdata->read_lock);
+	if (drvdata->read_count++)
+		goto out;
+
+	ret = tmc_read_prepare(drvdata);
+	if (ret)
+		goto err;
+out:
+	mutex_unlock(&drvdata->read_lock);
+	nonseekable_open(inode, file);
+
+	dev_dbg(drvdata->dev, "%s: successfully opened\n", __func__);
+	return 0;
+err:
+	drvdata->read_count--;
+	mutex_unlock(&drvdata->read_lock);
+	return ret;
+}
+
+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;
+		else if (bufp > (char *)(drvdata->vaddr + drvdata->size))
+			bufp -= drvdata->size;
+		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);
+
+	mutex_lock(&drvdata->read_lock);
+	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:
+	mutex_unlock(&drvdata->read_lock);
+	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 ssize_t tmc_etr_show_out_mode(struct device *dev,
+				      struct device_attribute *attr, char *buf)
+{
+	struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	return scnprintf(buf, PAGE_SIZE, "%s\n",
+			 drvdata->out_mode == TMC_ETR_OUT_MODE_MEM ?
+			 "mem" : "usb");
+}
+
+static ssize_t tmc_etr_store_out_mode(struct device *dev,
+				       struct device_attribute *attr,
+				       const char *buf, size_t size)
+{
+	struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	char str[10] = "";
+	unsigned long flags;
+	bool etr_bam_flag = false;
+	int ret;
+
+	if (strlen(buf) >= 10)
+		return -EINVAL;
+	if (sscanf(buf, "%s", str) != 1)
+		return -EINVAL;
+
+	mutex_lock(&drvdata->usb_lock);
+	if (!strcmp(str, "mem")) {
+		if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM)
+			goto out;
+
+		spin_lock_irqsave(&drvdata->spinlock, flags);
+		if (drvdata->enable) {
+			__tmc_etr_disable_to_bam(drvdata);
+			__tmc_etr_enable_to_mem(drvdata);
+			etr_bam_flag = true;
+		}
+		drvdata->out_mode = TMC_ETR_OUT_MODE_MEM;
+		spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+		if (etr_bam_flag) {
+			tmc_etr_bam_disable(drvdata);
+			usb_qdss_close(drvdata->usbch);
+		}
+	} else if (!strcmp(str, "usb")) {
+		if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB)
+			goto out;
+
+		spin_lock_irqsave(&drvdata->spinlock, flags);
+		if (drvdata->enable) {
+			if (drvdata->reading) {
+				ret = -EBUSY;
+				goto err1;
+			}
+			__tmc_etr_disable_to_mem(drvdata);
+			etr_bam_flag = true;
+		}
+		drvdata->out_mode = TMC_ETR_OUT_MODE_USB;
+		spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+		if (etr_bam_flag) {
+			drvdata->usbch = usb_qdss_open("qdss", drvdata,
+						       usb_notifier);
+			if (IS_ERR(drvdata->usbch)) {
+				dev_err(drvdata->dev, "usb_qdss_open failed\n");
+				ret = PTR_ERR(drvdata->usbch);
+				goto err0;
+			}
+		}
+	}
+out:
+	mutex_unlock(&drvdata->usb_lock);
+	return size;
+err1:
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+err0:
+	mutex_unlock(&drvdata->usb_lock);
+	return ret;
+}
+static DEVICE_ATTR(out_mode, S_IRUGO | S_IWUSR, tmc_etr_show_out_mode,
+		   tmc_etr_store_out_mode);
+
+static struct attribute *tmc_attrs[] = {
+	&dev_attr_trigger_cntr.attr,
+	NULL,
+};
+
+static struct attribute_group tmc_attr_grp = {
+	.attrs = tmc_attrs,
+};
+
+static struct attribute *tmc_etr_attrs[] = {
+	&dev_attr_out_mode.attr,
+	NULL,
+};
+
+static struct attribute_group tmc_etr_attr_grp = {
+	.attrs = tmc_etr_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,
+	&tmc_etr_attr_grp,
+	NULL,
+};
+
+static const struct attribute_group *tmc_etf_attr_grps[] = {
+	&tmc_attr_grp,
+	NULL,
+};
+
+static int __devinit tmc_etr_bam_init(struct platform_device *pdev,
+				      struct tmc_drvdata *drvdata)
+{
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	struct tmc_etr_bam_data *bamdata;
+
+	bamdata = devm_kzalloc(dev, sizeof(*bamdata), GFP_KERNEL);
+	if (!bamdata)
+		return -ENOMEM;
+	drvdata->bamdata = bamdata;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!res)
+		return -ENODEV;
+
+	bamdata->props.phys_addr = res->start;
+	bamdata->props.virt_addr = devm_ioremap(dev, res->start,
+						resource_size(res));
+	if (!bamdata->props.virt_addr)
+		return -ENOMEM;
+	bamdata->props.virt_size = resource_size(res);
+
+	bamdata->props.event_threshold = 0x4; /* Pipe event threshold */
+	bamdata->props.summing_threshold = 0x10; /* BAM event threshold */
+	bamdata->props.irq = 0;
+	bamdata->props.num_pipes = TMC_ETR_BAM_NR_PIPES;
+
+	return sps_register_bam_device(&bamdata->props, &bamdata->handle);
+}
+
+static void tmc_etr_bam_exit(struct tmc_drvdata *drvdata)
+{
+	struct tmc_etr_bam_data *bamdata = drvdata->bamdata;
+
+	if (!bamdata->handle)
+		return;
+	sps_deregister_bam_device(bamdata->handle);
+}
+
+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);
+	mutex_init(&drvdata->read_lock);
+	mutex_init(&drvdata->usb_lock);
+
+	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);
+		drvdata->out_mode = TMC_ETR_OUT_MODE_MEM;
+
+		ret = tmc_etr_bam_init(pdev, drvdata);
+		if (ret)
+			goto err0;
+	} 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 err1;
+	}
+	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 err1;
+		}
+	} 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 err1;
+		}
+	} 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 err1;
+		}
+	}
+
+	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 err2;
+
+	dev_info(dev, "TMC initialized\n");
+	return 0;
+err2:
+	coresight_unregister(drvdata->csdev);
+err1:
+	tmc_etr_bam_exit(drvdata);
+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);
+	tmc_etr_bam_exit(drvdata);
+	free_contiguous_memory_by_paddr(drvdata->paddr);
+	return 0;
+}
+
+static struct of_device_id tmc_match[] = {
+	{.compatible = "arm,coresight-tmc"},
+	{}
+};
+EXPORT_COMPAT("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 fc00ff2..290ae7f 100644
--- a/drivers/coresight/coresight-tpiu.c
+++ b/drivers/coresight/coresight-tpiu.c
@@ -19,11 +19,11 @@
 #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 tpiu_writel(drvdata, val, off)	__raw_writel((val), drvdata->base + off)
 #define tpiu_readl(drvdata, off)	__raw_readl(drvdata->base + off)
 
@@ -38,7 +38,6 @@
 	mb();								\
 } while (0)
 
-
 #define TPIU_SUPP_PORTSZ	(0x000)
 #define TPIU_CURR_PORTSZ	(0x004)
 #define TPIU_SUPP_TRIGMODES	(0x100)
@@ -59,7 +58,6 @@
 #define TPIU_ITATBCTR1		(0xEF4)
 #define TPIU_ITATBCTR0		(0xEF8)
 
-
 struct tpiu_drvdata {
 	void __iomem		*base;
 	struct device		*dev;
@@ -67,7 +65,6 @@
 	struct clk		*clk;
 };
 
-
 static void __tpiu_enable(struct tpiu_drvdata *drvdata)
 {
 	TPIU_UNLOCK(drvdata);
@@ -113,9 +110,19 @@
 	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 = {
@@ -126,10 +133,18 @@
 {
 	int ret;
 	struct device *dev = &pdev->dev;
+	struct coresight_platform_data *pdata;
 	struct tpiu_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;
@@ -139,6 +154,7 @@
 	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;
@@ -146,15 +162,18 @@
 	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;
 
-	/* Disable tpiu to support older targets that need this */
 	ret = clk_prepare_enable(drvdata->clk);
 	if (ret)
 		return ret;
+
+	/* Disable tpiu to support older targets that need this */
 	__tpiu_disable(drvdata);
+
 	clk_disable_unprepare(drvdata->clk);
 
 	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
@@ -183,7 +202,7 @@
 }
 
 static struct of_device_id tpiu_match[] = {
-	{.compatible = "coresight-tpiu"},
+	{.compatible = "arm,coresight-tpiu"},
 	{}
 };
 
diff --git a/drivers/coresight/coresight.c b/drivers/coresight/coresight.c
index 0c6b56a..cccb5a7 100644
--- a/drivers/coresight/coresight.c
+++ b/drivers/coresight/coresight.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -26,16 +26,13 @@
 
 #include "coresight-priv.h"
 
-
 #define NO_SINK		(-1)
 
-
 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;
@@ -367,6 +364,28 @@
 }
 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)
 {
@@ -477,6 +496,9 @@
 
 static struct device_type coresight_dev_type[] = {
 	{
+		.name = "none",
+	},
+	{
 		.name = "sink",
 		.groups = coresight_attr_grps_sink,
 	},
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/cpufreq/cpufreq_interactive.c b/drivers/cpufreq/cpufreq_interactive.c
index 989bd00..f834ea8 100644
--- a/drivers/cpufreq/cpufreq_interactive.c
+++ b/drivers/cpufreq/cpufreq_interactive.c
@@ -845,6 +845,9 @@
 			pcpu->hispeed_validate_time =
 				pcpu->target_set_time;
 			pcpu->governor_enabled = 1;
+			pcpu->idle_exit_time = pcpu->target_set_time;
+			mod_timer(&pcpu->cpu_timer,
+				jiffies + usecs_to_jiffies(timer_rate));
 			smp_wmb();
 		}
 
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c
index 4ccd89d..de5f10f 100644
--- a/drivers/crypto/msm/qce50.c
+++ b/drivers/crypto/msm/qce50.c
@@ -66,6 +66,7 @@
 	struct clk *ce_core_src_clk;	/* Handle to CE src clk*/
 	struct clk *ce_core_clk;	/* Handle to CE clk */
 	struct clk *ce_clk;		/* Handle to CE clk */
+	struct clk *ce_bus_clk;	/* Handle to CE AXI clk*/
 
 	qce_comp_func_ptr_t qce_cb;	/* qce callback function pointer */
 
@@ -647,6 +648,21 @@
 	return 0;
 };
 
+static int _qce_unlock_other_pipes(struct qce_device *pce_dev)
+{
+	int rc = 0;
+
+	pce_dev->ce_sps.consumer.event.callback = NULL;
+	rc = sps_transfer_one(pce_dev->ce_sps.consumer.pipe,
+	GET_PHYS_ADDR(pce_dev->ce_sps.cmdlistptr.unlock_all_pipes.cmdlist),
+	0, NULL, (SPS_IOVEC_FLAG_CMD | SPS_IOVEC_FLAG_UNLOCK));
+	if (rc) {
+		pr_err("sps_xfr_one() fail rc=%d", rc);
+		rc = -EINVAL;
+	}
+	return rc;
+}
+
 static int _aead_complete(struct qce_device *pce_dev)
 {
 	struct aead_request *areq;
@@ -665,6 +681,9 @@
 	/* check MAC */
 	memcpy(mac, (char *)(&pce_dev->ce_sps.result->auth_iv[0]),
 						SHA256_DIGEST_SIZE);
+	if (_qce_unlock_other_pipes(pce_dev))
+		return -EINVAL;
+
 	if (pce_dev->mode == QCE_MODE_CCM) {
 		uint32_t result_status;
 		result_status = pce_dev->ce_sps.result->status;
@@ -690,7 +709,7 @@
 	return 0;
 };
 
-static void _sha_complete(struct qce_device *pce_dev)
+static int _sha_complete(struct qce_device *pce_dev)
 {
 	struct ahash_request *areq;
 	unsigned char digest[SHA256_DIGEST_SIZE];
@@ -700,9 +719,12 @@
 				DMA_TO_DEVICE);
 	memcpy(digest, (char *)(&pce_dev->ce_sps.result->auth_iv[0]),
 						SHA256_DIGEST_SIZE);
+	if (_qce_unlock_other_pipes(pce_dev))
+		return -EINVAL;
 	pce_dev->qce_cb(areq, digest,
 			(char *)pce_dev->ce_sps.result->auth_byte_count,
 				pce_dev->ce_sps.consumer_status);
+	return 0;
 };
 
 static int _ablk_cipher_complete(struct qce_device *pce_dev)
@@ -719,6 +741,8 @@
 	dma_unmap_sg(pce_dev->pdev, areq->src, pce_dev->src_nents,
 		(areq->src == areq->dst) ? DMA_BIDIRECTIONAL :
 						DMA_TO_DEVICE);
+	if (_qce_unlock_other_pipes(pce_dev))
+		return -EINVAL;
 
 	if (pce_dev->mode == QCE_MODE_ECB) {
 		pce_dev->qce_cb(areq, NULL, NULL,
@@ -760,7 +784,7 @@
 {
 	int i, j, ents;
 	struct sps_iovec *iovec = pce_dev->ce_sps.in_transfer.iovec;
-	uint32_t cmd_flags = SPS_IOVEC_FLAG_CMD | SPS_IOVEC_FLAG_NWD;
+	uint32_t cmd_flags = SPS_IOVEC_FLAG_CMD;
 
 	printk(KERN_INFO "==============================================\n");
 	printk(KERN_INFO "CONSUMER (TX/IN/DEST) PIPE DESCRIPTOR\n");
@@ -806,11 +830,11 @@
 	pce_dev->ce_sps.out_transfer.iovec_count = 0;
 }
 
-static void _qce_set_eot_flag(struct sps_transfer *sps_bam_pipe)
+static void _qce_set_flag(struct sps_transfer *sps_bam_pipe, uint32_t flag)
 {
 	struct sps_iovec *iovec = sps_bam_pipe->iovec +
 					(sps_bam_pipe->iovec_count - 1);
-	iovec->flags |= SPS_IOVEC_FLAG_EOT;
+	iovec->flags |= flag;
 }
 
 static void _qce_sps_add_data(uint32_t addr, uint32_t len,
@@ -870,7 +894,7 @@
 					sps_bam_pipe->iovec_count;
 	iovec->size = cmdptr->size;
 	iovec->addr = GET_PHYS_ADDR(cmdptr->cmdlist);
-	iovec->flags = SPS_IOVEC_FLAG_CMD | SPS_IOVEC_FLAG_NWD | flag;
+	iovec->flags = SPS_IOVEC_FLAG_CMD | flag;
 	sps_bam_pipe->iovec_count++;
 
 	return 0;
@@ -959,7 +983,7 @@
 		/* Producer pipe will handle this connection */
 		sps_connect_info->mode = SPS_MODE_SRC;
 		sps_connect_info->options =
-			SPS_O_AUTO_ENABLE | SPS_O_EOT;
+			SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_DESC_DONE;
 	} else {
 		/* For CE consumer transfer, source should be
 		 * system memory where as destination should
@@ -976,6 +1000,8 @@
 	sps_connect_info->src_pipe_index = pce_dev->ce_sps.src_pipe_index;
 	/* Consumer pipe index */
 	sps_connect_info->dest_pipe_index = pce_dev->ce_sps.dest_pipe_index;
+	/* Set pipe group */
+	sps_connect_info->lock_group = pce_dev->ce_sps.pipe_pair_index;
 	sps_connect_info->event_thresh = 0x10;
 	/*
 	 * Max. no of scatter/gather buffers that can
@@ -1009,7 +1035,10 @@
 	}
 
 	sps_event->mode = SPS_TRIGGER_CALLBACK;
-	sps_event->options = SPS_O_EOT;
+	if (is_producer)
+		sps_event->options = SPS_O_EOT | SPS_O_DESC_DONE;
+	else
+		sps_event->options = SPS_O_EOT;
 	sps_event->xfer_done = NULL;
 	sps_event->user = (void *)pce_dev;
 
@@ -1093,6 +1122,7 @@
 	/* SPS driver wll handle the crypto BAM IRQ */
 	bam.irq = (u32)pce_dev->ce_sps.bam_irq;
 	bam.manage = SPS_BAM_MGR_LOCAL;
+	bam.ee = 1;
 
 	pr_debug("bam physical base=0x%x\n", (u32)bam.phys_addr);
 	pr_debug("bam virtual base=0x%x\n", (u32)bam.virt_addr);
@@ -1178,15 +1208,8 @@
 			notify->data.transfer.iovec.addr,
 			notify->data.transfer.iovec.size,
 			notify->data.transfer.iovec.flags);
-
-	pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_COMP;
-	if (pce_dev->ce_sps.consumer_state == QCE_PIPE_STATE_COMP) {
-		pce_dev->ce_sps.consumer_state = QCE_PIPE_STATE_IDLE;
-		pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_IDLE;
-
-		/* done */
-		_aead_complete(pce_dev);
-	}
+	/* done */
+	_aead_complete(pce_dev);
 };
 
 static void _aead_sps_consumer_callback(struct sps_event_notify *notify)
@@ -1200,15 +1223,6 @@
 			notify->data.transfer.iovec.addr,
 			notify->data.transfer.iovec.size,
 			notify->data.transfer.iovec.flags);
-
-	pce_dev->ce_sps.consumer_state = QCE_PIPE_STATE_COMP;
-	if (pce_dev->ce_sps.producer_state == QCE_PIPE_STATE_COMP) {
-		pce_dev->ce_sps.consumer_state = QCE_PIPE_STATE_IDLE;
-		pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_IDLE;
-
-		/* done */
-		_aead_complete(pce_dev);
-	}
 };
 
 static void _sha_sps_producer_callback(struct sps_event_notify *notify)
@@ -1222,15 +1236,8 @@
 			notify->data.transfer.iovec.addr,
 			notify->data.transfer.iovec.size,
 			notify->data.transfer.iovec.flags);
-
-	pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_COMP;
-	if (pce_dev->ce_sps.consumer_state == QCE_PIPE_STATE_COMP) {
-		pce_dev->ce_sps.consumer_state = QCE_PIPE_STATE_IDLE;
-		pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_IDLE;
-
-		/* done */
-		_sha_complete(pce_dev);
-	}
+	/* done */
+	_sha_complete(pce_dev);
 };
 
 static void _sha_sps_consumer_callback(struct sps_event_notify *notify)
@@ -1244,15 +1251,6 @@
 			notify->data.transfer.iovec.addr,
 			notify->data.transfer.iovec.size,
 			notify->data.transfer.iovec.flags);
-
-	pce_dev->ce_sps.consumer_state = QCE_PIPE_STATE_COMP;
-	if (pce_dev->ce_sps.producer_state == QCE_PIPE_STATE_COMP) {
-		pce_dev->ce_sps.consumer_state = QCE_PIPE_STATE_IDLE;
-		pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_IDLE;
-
-		/* done */
-	_sha_complete(pce_dev);
-	}
 };
 
 static void _ablk_cipher_sps_producer_callback(struct sps_event_notify *notify)
@@ -1266,15 +1264,8 @@
 			notify->data.transfer.iovec.addr,
 			notify->data.transfer.iovec.size,
 			notify->data.transfer.iovec.flags);
-
-	pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_COMP;
-	if (pce_dev->ce_sps.consumer_state == QCE_PIPE_STATE_COMP) {
-		pce_dev->ce_sps.consumer_state = QCE_PIPE_STATE_IDLE;
-		pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_IDLE;
-
-		/* done */
-		_ablk_cipher_complete(pce_dev);
-	}
+	/* done */
+	_ablk_cipher_complete(pce_dev);
 };
 
 static void _ablk_cipher_sps_consumer_callback(struct sps_event_notify *notify)
@@ -1288,15 +1279,6 @@
 			notify->data.transfer.iovec.addr,
 			notify->data.transfer.iovec.size,
 			notify->data.transfer.iovec.flags);
-
-	pce_dev->ce_sps.consumer_state = QCE_PIPE_STATE_COMP;
-	if (pce_dev->ce_sps.producer_state == QCE_PIPE_STATE_COMP) {
-		pce_dev->ce_sps.consumer_state = QCE_PIPE_STATE_IDLE;
-		pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_IDLE;
-
-		/* done */
-		_ablk_cipher_complete(pce_dev);
-	}
 };
 
 static void qce_add_cmd_element(struct qce_device *pdev,
@@ -1315,9 +1297,8 @@
 		unsigned char **pvaddr, enum qce_cipher_mode_enum mode,
 		bool key_128)
 {
-	struct sps_command_element *ce_vaddr =
-				(struct sps_command_element *)(*pvaddr);
-	uint32_t ce_vaddr_start = (uint32_t)(*pvaddr);
+	struct sps_command_element *ce_vaddr;
+	uint32_t ce_vaddr_start;
 	struct qce_cmdlistptr_ops *cmdlistptr = &pdev->ce_sps.cmdlistptr;
 	struct qce_cmdlist_info *pcl_info = NULL;
 	int i = 0;
@@ -1329,6 +1310,10 @@
 	uint32_t beats = (pdev->ce_sps.ce_burst_size >> 3) - 1;
 	uint32_t pipe_pair = pdev->ce_sps.pipe_pair_index;
 
+	*pvaddr = (unsigned char *) ALIGN(((unsigned int)(*pvaddr)),
+					pdev->ce_sps.ce_burst_size);
+	ce_vaddr = (struct sps_command_element *)(*pvaddr);
+	ce_vaddr_start = (uint32_t)(*pvaddr);
 	crypto_cfg = (beats << CRYPTO_REQ_SIZE) |
 			BIT(CRYPTO_MASK_DOUT_INTR) |
 			BIT(CRYPTO_MASK_DIN_INTR) |
@@ -1480,10 +1465,16 @@
 						0, &pcl_info->auth_seg_size);
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
 						0, &pcl_info->auth_seg_size);
+	} else {
+		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_SIZE_REG,
+						0, &pcl_info->auth_seg_size);
+		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
+						0, &pcl_info->auth_seg_size);
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_START_REG,
 						0, &pcl_info->auth_seg_size);
-
 	}
+	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
+				(crypto_cfg | CRYPTO_LITTLE_ENDIAN_MASK), NULL);
 
 	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_GOPROC_REG,
 			((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
@@ -1500,9 +1491,8 @@
 		bool mode_cbc)
 {
 
-	struct sps_command_element *ce_vaddr =
-				(struct sps_command_element *)(*pvaddr);
-	uint32_t ce_vaddr_start = (uint32_t)(*pvaddr);
+	struct sps_command_element *ce_vaddr;
+	uint32_t ce_vaddr_start;
 	struct qce_cmdlistptr_ops *cmdlistptr = &pdev->ce_sps.cmdlistptr;
 	struct qce_cmdlist_info *pcl_info = NULL;
 	int i = 0;
@@ -1513,6 +1503,10 @@
 	uint32_t beats = (pdev->ce_sps.ce_burst_size >> 3) - 1;
 	uint32_t pipe_pair = pdev->ce_sps.pipe_pair_index;
 
+	*pvaddr = (unsigned char *) ALIGN(((unsigned int)(*pvaddr)),
+					pdev->ce_sps.ce_burst_size);
+	ce_vaddr = (struct sps_command_element *)(*pvaddr);
+	ce_vaddr_start = (uint32_t)(*pvaddr);
 	crypto_cfg = (beats << CRYPTO_REQ_SIZE) |
 			BIT(CRYPTO_MASK_DOUT_INTR) |
 			BIT(CRYPTO_MASK_DIN_INTR) |
@@ -1613,9 +1607,6 @@
 						&pcl_info->encr_cntr_iv);
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CNTR1_IV1_REG, 0,
 								NULL);
-		/* Add 2 dummy to  align size to burst-size multiple */
-		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CNTR2_IV2_REG, 0,
-								NULL);
 	}
 	/* Add dummy to  align size to burst-size multiple */
 	if (!mode_cbc) {
@@ -1623,10 +1614,17 @@
 						0, &pcl_info->auth_seg_size);
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
 						0, &pcl_info->auth_seg_size);
+	} else {
+		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_SIZE_REG,
+						0, &pcl_info->auth_seg_size);
+		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
+						0, &pcl_info->auth_seg_size);
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_START_REG,
 						0, &pcl_info->auth_seg_size);
-
 	}
+	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
+			(crypto_cfg | CRYPTO_LITTLE_ENDIAN_MASK),
+			NULL);
 
 	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_GOPROC_REG,
 			((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
@@ -1642,9 +1640,8 @@
 		unsigned char **pvaddr, enum qce_hash_alg_enum alg,
 		bool key_128)
 {
-	struct sps_command_element *ce_vaddr =
-			(struct sps_command_element *)(*pvaddr);
-	uint32_t ce_vaddr_start = (uint32_t)(*pvaddr);
+	struct sps_command_element *ce_vaddr;
+	uint32_t ce_vaddr_start;
 	struct qce_cmdlistptr_ops *cmdlistptr = &pdev->ce_sps.cmdlistptr;
 	struct qce_cmdlist_info *pcl_info = NULL;
 	int i = 0;
@@ -1655,6 +1652,10 @@
 	uint32_t beats = (pdev->ce_sps.ce_burst_size >> 3) - 1;
 	uint32_t pipe_pair = pdev->ce_sps.pipe_pair_index;
 
+	*pvaddr = (unsigned char *) ALIGN(((unsigned int)(*pvaddr)),
+					pdev->ce_sps.ce_burst_size);
+	ce_vaddr_start = (uint32_t)(*pvaddr);
+	ce_vaddr = (struct sps_command_element *)(*pvaddr);
 	crypto_cfg = (beats << CRYPTO_REQ_SIZE) |
 			BIT(CRYPTO_MASK_DOUT_INTR) |
 			BIT(CRYPTO_MASK_DIN_INTR) |
@@ -1678,9 +1679,6 @@
 		iv_reg = 5;
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
 					crypto_cfg, &pcl_info->crypto_cfg);
-		/* 1 dummy write */
-		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG,
-								0, NULL);
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
 							0, NULL);
 
@@ -1696,9 +1694,7 @@
 		iv_reg = 8;
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
 					crypto_cfg, &pcl_info->crypto_cfg);
-		/* 2 dummy writes */
-		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG,
-								0, NULL);
+		/* 1 dummy write */
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG,
 								0, NULL);
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
@@ -1716,9 +1712,6 @@
 		iv_reg = 5;
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
 					crypto_cfg, &pcl_info->crypto_cfg);
-		/* 1 dummy write */
-		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG,
-								0, NULL);
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
 							0, NULL);
 	break;
@@ -1736,9 +1729,7 @@
 		iv_reg = 5;
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
 					crypto_cfg, &pcl_info->crypto_cfg);
-		/* 2 dummy writes */
-		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG,
-								0, NULL);
+		/* 1 dummy write */
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG,
 								0, NULL);
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
@@ -1757,9 +1748,7 @@
 
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
 					crypto_cfg, &pcl_info->crypto_cfg);
-		/* 2 dummy writes */
-		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG,
-								0, NULL);
+		/* 1 dummy write */
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG,
 								0, NULL);
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
@@ -1797,9 +1786,7 @@
 		}
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
 					crypto_cfg, &pcl_info->crypto_cfg);
-		/* 2 dummy writes */
-		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG,
-								0, NULL);
+		/* 1 dummy write */
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG,
 								0, NULL);
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
@@ -1852,6 +1839,10 @@
 				(CRYPTO_AUTH_KEY0_REG + i*sizeof(uint32_t)),
 				0, NULL);
 	}
+	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
+			(crypto_cfg | CRYPTO_LITTLE_ENDIAN_MASK),
+			NULL);
+
 	if (alg != QCE_AEAD_SHA1_HMAC)
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_GOPROC_REG,
 			((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
@@ -1866,9 +1857,8 @@
 static int _setup_aead_cmdlistptrs(struct qce_device *pdev,
 				unsigned char **pvaddr, bool key_128)
 {
-	struct sps_command_element *ce_vaddr =
-				(struct sps_command_element *)(*pvaddr);
-	uint32_t ce_vaddr_start = (uint32_t)(*pvaddr);
+	struct sps_command_element *ce_vaddr;
+	uint32_t ce_vaddr_start;
 	struct qce_cmdlistptr_ops *cmdlistptr = &pdev->ce_sps.cmdlistptr;
 	struct qce_cmdlist_info *pcl_info = NULL;
 	int i = 0;
@@ -1879,6 +1869,10 @@
 	uint32_t beats = (pdev->ce_sps.ce_burst_size >> 3) - 1;
 	uint32_t pipe_pair = pdev->ce_sps.pipe_pair_index;
 
+	*pvaddr = (unsigned char *) ALIGN(((unsigned int)(*pvaddr)),
+					pdev->ce_sps.ce_burst_size);
+	ce_vaddr_start = (uint32_t)(*pvaddr);
+	ce_vaddr = (struct sps_command_element *)(*pvaddr);
 	crypto_cfg = (beats << CRYPTO_REQ_SIZE) |
 			BIT(CRYPTO_MASK_DOUT_INTR) |
 			BIT(CRYPTO_MASK_DIN_INTR) |
@@ -1927,8 +1921,6 @@
 	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_CFG_REG, 0, NULL);
 	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_START_REG, 0,
 									NULL);
-	/* add 1 dummy */
-	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG, 0, NULL);
 	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_SEG_SIZE_REG, 0,
 						&pcl_info->seg_size);
 	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_CFG_REG,
@@ -1992,6 +1984,10 @@
 			(CRYPTO_ENCR_CCM_INT_CNTR0_REG + i * sizeof(uint32_t)),
 			0, NULL);
 
+	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
+			(crypto_cfg | CRYPTO_LITTLE_ENDIAN_MASK),
+			NULL);
+
 	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_GOPROC_REG,
 			((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
 			&pcl_info->go_proc);
@@ -2005,12 +2001,14 @@
 static int _setup_unlock_pipe_cmdlistptrs(struct qce_device *pdev,
 		unsigned char **pvaddr)
 {
-	struct sps_command_element *ce_vaddr =
-			(struct sps_command_element *)(*pvaddr);
+	struct sps_command_element *ce_vaddr;
 	uint32_t ce_vaddr_start = (uint32_t)(*pvaddr);
 	struct qce_cmdlistptr_ops *cmdlistptr = &pdev->ce_sps.cmdlistptr;
 	struct qce_cmdlist_info *pcl_info = NULL;
 
+	*pvaddr = (unsigned char *) ALIGN(((unsigned int)(*pvaddr)),
+					pdev->ce_sps.ce_burst_size);
+	ce_vaddr = (struct sps_command_element *)(*pvaddr);
 	cmdlistptr->unlock_all_pipes.cmdlist = (uint32_t)ce_vaddr;
 	pcl_info = &(cmdlistptr->unlock_all_pipes);
 
@@ -2020,12 +2018,6 @@
 	 */
 	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
 					CRYPTO_CONFIG_RESET, NULL);
-	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
-					CRYPTO_CONFIG_RESET, NULL);
-	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
-					CRYPTO_CONFIG_RESET, NULL);
-	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
-					CRYPTO_CONFIG_RESET, NULL);
 	pcl_info->size = (uint32_t)ce_vaddr - (uint32_t)ce_vaddr_start;
 	*pvaddr = (unsigned char *) ce_vaddr;
 
@@ -2044,7 +2036,7 @@
 	 */
 	ce_vaddr =
 		(struct sps_command_element *) ALIGN(((unsigned int) ce_vaddr),
-									16);
+					pdev->ce_sps.ce_burst_size);
 	*pvaddr = (unsigned char *) ce_vaddr;
 
 	_setup_cipher_aes_cmdlistptrs(pdev, pvaddr, QCE_MODE_CBC, true);
@@ -2084,8 +2076,8 @@
 	unsigned char *vaddr;
 
 	vaddr = pce_dev->coh_vmem;
-	vaddr = (unsigned char *) ALIGN(((unsigned int)vaddr),  16);
-
+	vaddr = (unsigned char *) ALIGN(((unsigned int)vaddr),
+					pce_dev->ce_sps.ce_burst_size);
 	/* Allow for 256 descriptor (cmd and data) entries per pipe */
 	pce_dev->ce_sps.in_transfer.iovec = (struct sps_iovec *)vaddr;
 	pce_dev->ce_sps.in_transfer.iovec_phys =
@@ -2098,6 +2090,8 @@
 	vaddr += MAX_BAM_DESCRIPTORS * 8;
 
 	qce_setup_cmdlistptrs(pce_dev, &vaddr);
+	vaddr = (unsigned char *) ALIGN(((unsigned int)vaddr),
+					pce_dev->ce_sps.ce_burst_size);
 	pce_dev->ce_sps.result_dump = (uint32_t)vaddr;
 	pce_dev->ce_sps.result = (struct ce_result_dump_format *)vaddr;
 	vaddr += 128;
@@ -2235,20 +2229,24 @@
 
 	_qce_sps_iovec_count_init(pce_dev);
 
-	_qce_sps_add_cmd(pce_dev, 0, cmdlistinfo,
+	_qce_sps_add_cmd(pce_dev, SPS_IOVEC_FLAG_LOCK, cmdlistinfo,
 					&pce_dev->ce_sps.in_transfer);
 
 	if (pce_dev->ce_sps.minor_version == 0) {
 		_qce_sps_add_sg_data(pce_dev, areq->src, totallen_in,
 					&pce_dev->ce_sps.in_transfer);
 
-		_qce_set_eot_flag(&pce_dev->ce_sps.in_transfer);
+		_qce_set_flag(&pce_dev->ce_sps.in_transfer,
+				SPS_IOVEC_FLAG_EOT|SPS_IOVEC_FLAG_NWD);
+
 		_qce_sps_add_sg_data(pce_dev, areq->dst, out_len +
 					areq->assoclen + hw_pad_out,
 				&pce_dev->ce_sps.out_transfer);
 		_qce_sps_add_data(GET_PHYS_ADDR(pce_dev->ce_sps.result_dump),
 					CRYPTO_RESULT_DUMP_SIZE,
 					&pce_dev->ce_sps.out_transfer);
+		_qce_set_flag(&pce_dev->ce_sps.out_transfer,
+					SPS_IOVEC_FLAG_INT);
 	} else {
 		_qce_sps_add_sg_data(pce_dev, areq->assoc, areq->assoclen,
 					 &pce_dev->ce_sps.in_transfer);
@@ -2256,7 +2254,8 @@
 					&pce_dev->ce_sps.in_transfer);
 		_qce_sps_add_sg_data(pce_dev, areq->src, areq->cryptlen,
 					&pce_dev->ce_sps.in_transfer);
-		_qce_set_eot_flag(&pce_dev->ce_sps.in_transfer);
+		_qce_set_flag(&pce_dev->ce_sps.in_transfer,
+				SPS_IOVEC_FLAG_EOT|SPS_IOVEC_FLAG_NWD);
 
 		/* Pass through to ignore associated (+iv, if applicable) data*/
 		_qce_sps_add_data(GET_PHYS_ADDR(pce_dev->ce_sps.ignore_buffer),
@@ -2270,6 +2269,8 @@
 
 		_qce_sps_add_data(GET_PHYS_ADDR(pce_dev->ce_sps.result_dump),
 			CRYPTO_RESULT_DUMP_SIZE, &pce_dev->ce_sps.out_transfer);
+		_qce_set_flag(&pce_dev->ce_sps.out_transfer,
+					SPS_IOVEC_FLAG_INT);
 	}
 	rc = _qce_sps_transfer(pce_dev);
 	if (rc)
@@ -2356,17 +2357,19 @@
 
 	_qce_sps_iovec_count_init(pce_dev);
 
-	_qce_sps_add_cmd(pce_dev, 0, cmdlistinfo,
+	_qce_sps_add_cmd(pce_dev, SPS_IOVEC_FLAG_LOCK, cmdlistinfo,
 					&pce_dev->ce_sps.in_transfer);
 	_qce_sps_add_sg_data(pce_dev, areq->src, areq->nbytes,
 					&pce_dev->ce_sps.in_transfer);
-	_qce_set_eot_flag(&pce_dev->ce_sps.in_transfer);
+	_qce_set_flag(&pce_dev->ce_sps.in_transfer,
+				SPS_IOVEC_FLAG_EOT|SPS_IOVEC_FLAG_NWD);
 
 	_qce_sps_add_sg_data(pce_dev, areq->dst, areq->nbytes,
 					&pce_dev->ce_sps.out_transfer);
 	_qce_sps_add_data(GET_PHYS_ADDR(pce_dev->ce_sps.result_dump),
 					CRYPTO_RESULT_DUMP_SIZE,
 					  &pce_dev->ce_sps.out_transfer);
+	_qce_set_flag(&pce_dev->ce_sps.out_transfer, SPS_IOVEC_FLAG_INT);
 	rc = _qce_sps_transfer(pce_dev);
 	if (rc)
 		goto bad;
@@ -2425,15 +2428,17 @@
 
 	_qce_sps_iovec_count_init(pce_dev);
 
-	_qce_sps_add_cmd(pce_dev, 0, cmdlistinfo,
+	_qce_sps_add_cmd(pce_dev, SPS_IOVEC_FLAG_LOCK, cmdlistinfo,
 					&pce_dev->ce_sps.in_transfer);
 	_qce_sps_add_sg_data(pce_dev, areq->src, areq->nbytes,
 						 &pce_dev->ce_sps.in_transfer);
-	_qce_set_eot_flag(&pce_dev->ce_sps.in_transfer);
+	_qce_set_flag(&pce_dev->ce_sps.in_transfer,
+				SPS_IOVEC_FLAG_EOT|SPS_IOVEC_FLAG_NWD);
 
 	_qce_sps_add_data(GET_PHYS_ADDR(pce_dev->ce_sps.result_dump),
 					CRYPTO_RESULT_DUMP_SIZE,
 					  &pce_dev->ce_sps.out_transfer);
+	_qce_set_flag(&pce_dev->ce_sps.out_transfer, SPS_IOVEC_FLAG_INT);
 	rc = _qce_sps_transfer(pce_dev);
 	if (rc)
 		goto bad;
@@ -2527,6 +2532,7 @@
 	struct clk *ce_core_clk;
 	struct clk *ce_clk;
 	struct clk *ce_core_src_clk;
+	struct clk *ce_bus_clk;
 
 	/* Get CE3 src core clk. */
 	ce_core_src_clk = clk_get(pce_dev->pdev, "core_clk_src");
@@ -2568,6 +2574,19 @@
 	}
 	pce_dev->ce_clk = ce_clk;
 
+	/* Get CE AXI clk */
+	ce_bus_clk = clk_get(pce_dev->pdev, "bus_clk");
+	if (IS_ERR(ce_bus_clk)) {
+		rc = PTR_ERR(ce_bus_clk);
+		pr_err("Unable to get CE BUS interface clk\n");
+		if (pce_dev->ce_core_src_clk != NULL)
+			clk_put(pce_dev->ce_core_src_clk);
+		clk_put(pce_dev->ce_core_clk);
+		clk_put(pce_dev->ce_clk);
+		goto err_clk;
+	}
+	pce_dev->ce_bus_clk = ce_bus_clk;
+
 	/* Enable CE core clk */
 	rc = clk_prepare_enable(pce_dev->ce_core_clk);
 	if (rc) {
@@ -2589,6 +2608,18 @@
 			clk_put(pce_dev->ce_clk);
 			goto err_clk;
 		}
+		/* Enable AXI clk */
+		rc = clk_prepare_enable(pce_dev->ce_bus_clk);
+		if (rc) {
+			pr_err("Unable to enable/prepare CE BUS clk\n");
+			clk_disable_unprepare(pce_dev->ce_core_clk);
+			if (pce_dev->ce_core_src_clk != NULL)
+				clk_put(pce_dev->ce_core_src_clk);
+			clk_put(pce_dev->ce_core_clk);
+			clk_put(pce_dev->ce_clk);
+			clk_put(pce_dev->ce_bus_clk);
+			goto err_clk;
+		}
 	}
 err_clk:
 	if (rc)
@@ -2680,10 +2711,12 @@
 
 	clk_disable_unprepare(pce_dev->ce_clk);
 	clk_disable_unprepare(pce_dev->ce_core_clk);
+	clk_disable_unprepare(pce_dev->ce_bus_clk);
 	if (pce_dev->ce_core_src_clk != NULL)
 		clk_put(pce_dev->ce_core_src_clk);
 	clk_put(pce_dev->ce_clk);
 	clk_put(pce_dev->ce_core_clk);
+	clk_put(pce_dev->ce_bus_clk);
 
 	qce_sps_exit(pce_dev);
 	kfree(handle);
diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index 63f7fd9..f1c31c1 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -2038,18 +2038,6 @@
 	podev->pdev = pdev;
 	platform_set_drvdata(pdev, podev);
 
-	if (podev->platform_support.bus_scale_table != NULL) {
-		podev->bus_scale_handle =
-			msm_bus_scale_register_client(
-				(struct msm_bus_scale_pdata *)
-				podev->platform_support.bus_scale_table);
-		if (!podev->bus_scale_handle) {
-			printk(KERN_ERR "%s not able to get bus scale\n",
-								__func__);
-			rc =  -ENOMEM;
-			goto err;
-		}
-	}
 	rc = misc_register(&podev->miscdevice);
 	qce_hw_support(podev->qce, &podev->ce_support);
 	if (podev->ce_support.bam) {
@@ -2070,6 +2058,18 @@
 				platform_support->bus_scale_table;
 		podev->platform_support.sha_hmac = platform_support->sha_hmac;
 	}
+	if (podev->platform_support.bus_scale_table != NULL) {
+		podev->bus_scale_handle =
+			msm_bus_scale_register_client(
+				(struct msm_bus_scale_pdata *)
+				podev->platform_support.bus_scale_table);
+		if (!podev->bus_scale_handle) {
+			pr_err("%s not able to get bus scale\n",
+				__func__);
+			rc =  -ENOMEM;
+			goto err;
+		}
+	}
 	if (rc >= 0)
 		return 0;
 	else
diff --git a/drivers/crypto/msm/qcryptohw_50.h b/drivers/crypto/msm/qcryptohw_50.h
index 898109e..1c904ed 100644
--- a/drivers/crypto/msm/qcryptohw_50.h
+++ b/drivers/crypto/msm/qcryptohw_50.h
@@ -345,6 +345,7 @@
 #define CRYPTO_IRQ_ENABLES_MASK			(0xF << CRYPTO_IRQ_ENABLES)
 
 #define CRYPTO_LITTLE_ENDIAN_MODE		9
+#define CRYPTO_LITTLE_ENDIAN_MASK		(1 << CRYPTO_LITTLE_ENDIAN_MODE)
 #define CRYPTO_PIPE_SET_SELECT			5 /* bit 8-5 */
 #define CRYPTO_PIPE_SET_SELECT_MASK		(0xF << CRYPTO_PIPE_SET_SELECT)
 
diff --git a/drivers/gpio/gpio-msm-v3.c b/drivers/gpio/gpio-msm-v3.c
index e0b01cd..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)
@@ -167,15 +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);
+	cfg = INTR_RAW_STATUS_EN | INTR_TARGET_PROC_APPS;
 	__raw_writel(cfg, GPIO_INTR_CFG(gpio));
-	cfg = __raw_readl(GPIO_INTR_CFG(gpio));
 	cfg &= ~INTR_DECT_CTL_MASK;
 	if (type == IRQ_TYPE_EDGE_RISING)
 		cfg |= INTR_DECT_CTL_POS_EDGE;
@@ -186,10 +183,10 @@
 	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_writel(cfg, GPIO_INTR_CFG(gpio));
 	/* Sometimes it might take a little while to update
diff --git a/drivers/gpio/qpnp-pin.c b/drivers/gpio/qpnp-pin.c
index bbcba81..67a2e6b 100644
--- a/drivers/gpio/qpnp-pin.c
+++ b/drivers/gpio/qpnp-pin.c
@@ -31,25 +31,35 @@
 		((q_spec)->offset + reg_index)
 
 #define Q_REG_STATUS1			0x8
+#define Q_REG_STATUS1_VAL_MASK		0x1
+#define Q_REG_STATUS1_GPIO_EN_REV0_MASK	0x2
+#define Q_REG_STATUS1_GPIO_EN_MASK	0x80
+#define Q_REG_STATUS1_MPP_EN_MASK	0x80
+
 #define Q_NUM_CTL_REGS			0xD
 
+/* revision registers base address offsets */
+#define Q_REG_DIG_MINOR_REV		0x0
+#define Q_REG_DIG_MAJOR_REV		0x1
+#define Q_REG_ANA_MINOR_REV		0x2
+
 /* type registers base address offsets */
 #define Q_REG_TYPE			0x4
 #define Q_REG_SUBTYPE			0x5
 
 /* 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 +139,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
@@ -153,6 +164,7 @@
 	u8 num_ctl_regs;		/* usable number on this pin */
 	u8 type;			/* peripheral type */
 	u8 subtype;			/* peripheral subtype */
+	u8 dig_major_rev;
 	struct device_node *node;
 	enum qpnp_pin_param_type params[Q_NUM_PARAMS];
 	struct qpnp_pin_chip *q_chip;
@@ -225,8 +237,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 +343,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 +429,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 +474,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 +547,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 +557,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 +637,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 +649,22 @@
 	/* 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];
+
+		if (q_spec->type == Q_GPIO_TYPE && q_spec->dig_major_rev == 0)
+			en_mask = Q_REG_STATUS1_GPIO_EN_REV0_MASK;
+		else if (q_spec->type == Q_GPIO_TYPE &&
+			 q_spec->dig_major_rev > 0)
+			en_mask = Q_REG_STATUS1_GPIO_EN_MASK;
+		else /* MPP */
+			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 +691,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 +724,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 +735,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 +819,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);
@@ -1075,6 +1111,28 @@
 }
 #endif
 
+static int qpnp_pin_is_valid_pin(struct qpnp_pin_spec *q_spec)
+{
+	if (q_spec->type == Q_GPIO_TYPE)
+		switch (q_spec->subtype) {
+		case Q_GPIO_SUBTYPE_GPIO_4CH:
+		case Q_GPIO_SUBTYPE_GPIOC_4CH:
+		case Q_GPIO_SUBTYPE_GPIO_8CH:
+		case Q_GPIO_SUBTYPE_GPIOC_8CH:
+			return 1;
+		}
+	else if (q_spec->type == Q_MPP_TYPE)
+		switch (q_spec->subtype) {
+		case Q_MPP_SUBTYPE_4CH_NO_ANA_OUT:
+		case Q_MPP_SUBTYPE_4CH_NO_SINK:
+		case Q_MPP_SUBTYPE_4CH_FULL_FUNC:
+		case Q_MPP_SUBTYPE_8CH_FULL_FUNC:
+			return 1;
+		}
+
+	return 0;
+}
+
 static int qpnp_pin_probe(struct spmi_device *spmi)
 {
 	struct qpnp_pin_chip *q_chip;
@@ -1084,7 +1142,7 @@
 	int i, rc;
 	int lowest_gpio = UINT_MAX, highest_gpio = 0;
 	u32 intspec[3], gpio;
-	char buf[2];
+	char version[Q_REG_SUBTYPE - Q_REG_DIG_MAJOR_REV + 1];
 	const char *dev_name;
 
 	dev_name = spmi_get_primary_dev_name(spmi);
@@ -1194,14 +1252,23 @@
 		q_spec->q_chip = q_chip;
 
 		rc = spmi_ext_register_readl(spmi->ctrl, q_spec->slave,
-				Q_REG_ADDR(q_spec, Q_REG_TYPE), &buf[0], 2);
+				Q_REG_ADDR(q_spec, Q_REG_DIG_MAJOR_REV),
+				&version[0], ARRAY_SIZE(version));
 		if (rc) {
 			dev_err(&spmi->dev, "%s: unable to read type regs\n",
 						__func__);
 			goto err_probe;
 		}
-		q_spec->type	= buf[0];
-		q_spec->subtype = buf[1];
+		q_spec->dig_major_rev = version[Q_REG_DIG_MAJOR_REV -
+						Q_REG_DIG_MAJOR_REV];
+		q_spec->type	= version[Q_REG_TYPE - Q_REG_DIG_MAJOR_REV];
+		q_spec->subtype = version[Q_REG_SUBTYPE - Q_REG_DIG_MAJOR_REV];
+
+		if (!qpnp_pin_is_valid_pin(q_spec)) {
+			dev_err(&spmi->dev, "%s: invalid pin type (type=0x%x subtype=0x%x)\n",
+				       __func__, q_spec->type, q_spec->subtype);
+			goto err_probe;
+		}
 
 		rc = qpnp_pin_ctl_regs_init(q_spec);
 		if (rc)
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index 4fe1f01..31bbb1f 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -330,8 +330,6 @@
 	struct ion_client *client = handle->client;
 	struct ion_buffer *buffer = handle->buffer;
 
-	mutex_lock(&client->lock);
-
 	mutex_lock(&buffer->lock);
 	while (handle->kmap_cnt)
 		ion_handle_kmap_put(handle);
@@ -339,7 +337,6 @@
 
 	if (!RB_EMPTY_NODE(&handle->node))
 		rb_erase(&handle->node, &client->handles);
-	mutex_unlock(&client->lock);
 
 	ion_buffer_put(buffer);
 	kfree(handle);
@@ -514,8 +511,8 @@
 		WARN(1, "%s: invalid handle passed to free.\n", __func__);
 		return;
 	}
-	mutex_unlock(&client->lock);
 	ion_handle_put(handle);
+	mutex_unlock(&client->lock);
 }
 EXPORT_SYMBOL(ion_free);
 
diff --git a/drivers/gpu/msm/a3xx_reg.h b/drivers/gpu/msm/a3xx_reg.h
index 33fcbfd..05c7967 100644
--- a/drivers/gpu/msm/a3xx_reg.h
+++ b/drivers/gpu/msm/a3xx_reg.h
@@ -77,6 +77,9 @@
 #define A3XX_CP_PFP_UCODE_DATA 0x1CA
 #define A3XX_CP_ROQ_ADDR 0x1CC
 #define A3XX_CP_ROQ_DATA 0x1CD
+#define A3XX_CP_MERCIU_ADDR 0x1D1
+#define A3XX_CP_MERCIU_DATA 0x1D2
+#define A3XX_CP_MERCIU_DATA2 0x1D3
 #define A3XX_CP_MEQ_ADDR 0x1DA
 #define A3XX_CP_MEQ_DATA 0x1DB
 #define A3XX_CP_HW_FAULT  0x45C
@@ -151,9 +154,11 @@
 #define A3XX_GRAS_CL_USER_PLANE_Y5 0xCB5
 #define A3XX_GRAS_CL_USER_PLANE_Z5 0xCB6
 #define A3XX_GRAS_CL_USER_PLANE_W5 0xCB7
+#define A3XX_RB_GMEM_BASE_ADDR 0xCC0
 #define A3XX_VFD_PERFCOUNTER0_SELECT 0xE44
 #define A3XX_VPC_VPC_DEBUG_RAM_SEL 0xE61
 #define A3XX_VPC_VPC_DEBUG_RAM_READ 0xE62
+#define A3XX_UCHE_CACHE_MODE_CONTROL_REG 0xE82
 #define A3XX_UCHE_CACHE_INVALIDATE0_REG 0xEA0
 #define A3XX_GRAS_CL_CLIP_CNTL 0x2040
 #define A3XX_GRAS_CL_GB_CLIP_ADJ 0x2044
@@ -234,6 +239,7 @@
 #define A3XX_TPL1_TP_VS_TEX_OFFSET 0x2340
 #define A3XX_TPL1_TP_FS_TEX_OFFSET 0x2342
 #define A3XX_TPL1_TP_FS_BORDER_COLOR_BASE_ADDR 0x2343
+#define A3XX_VBIF_CLKON 0x3001
 #define A3XX_VBIF_FIXED_SORT_EN 0x300C
 #define A3XX_VBIF_FIXED_SORT_SEL0 0x300D
 #define A3XX_VBIF_FIXED_SORT_SEL1 0x300E
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 6a894c8..cf7f3ce 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -111,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,
 };
 
@@ -179,7 +179,7 @@
 		"a300_pm4.fw", "a300_pfp.fw", &adreno_a3xx_gpudev,
 		512, 0, 2, SZ_256K },
 	/* A3XX doesn't use the pix_shader_start */
-	{ ADRENO_REV_A320, 3, 2, 0, ANY_ID,
+	{ ADRENO_REV_A320, 3, 2, ANY_ID, ANY_ID,
 		"a300_pm4.fw", "a300_pfp.fw", &adreno_a3xx_gpudev,
 		512, 0, 2, SZ_512K },
 	{ ADRENO_REV_A330, 3, 3, 0, 0,
@@ -275,25 +275,20 @@
 	unsigned int *cmds = &link[0];
 	int sizedwords = 0;
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
-	struct kgsl_memdesc **reg_map_desc;
-	void *reg_map_array = NULL;
 	int num_iommu_units, i;
 	struct kgsl_context *context;
 	struct adreno_context *adreno_ctx = NULL;
 
 	if (!adreno_dev->drawctxt_active)
 		return kgsl_mmu_device_setstate(&device->mmu, flags);
-	num_iommu_units = kgsl_mmu_get_reg_map_desc(&device->mmu,
-							&reg_map_array);
+	num_iommu_units = kgsl_mmu_get_num_iommu_units(&device->mmu);
 
 	context = idr_find(&device->context_idr, context_id);
 	adreno_ctx = context->devctxt;
 
-	reg_map_desc = reg_map_array;
-
 	if (kgsl_mmu_enable_clk(&device->mmu,
 				KGSL_IOMMU_CONTEXT_USER))
-		goto done;
+		return;
 
 	cmds += __adreno_add_idle_indirect_cmds(cmds,
 		device->mmu.setstate_memory.gpuaddr +
@@ -309,26 +304,23 @@
 					device->mmu.setstate_memory.gpuaddr +
 					KGSL_IOMMU_SETSTATE_NOP_OFFSET);
 
-	pt_val = kgsl_mmu_pt_get_base_addr(device->mmu.hwpagetable);
+	pt_val = kgsl_mmu_get_pt_base_addr(&device->mmu,
+					device->mmu.hwpagetable);
 	if (flags & KGSL_MMUFLAGS_PTUPDATE) {
 		/*
 		 * We need to perfrom the following operations for all
 		 * IOMMU units
 		 */
 		for (i = 0; i < num_iommu_units; i++) {
-			reg_pt_val = (pt_val &
-				(KGSL_IOMMU_TTBR0_PA_MASK <<
-				KGSL_IOMMU_TTBR0_PA_SHIFT)) +
-				kgsl_mmu_get_pt_lsb(&device->mmu, i,
-					KGSL_IOMMU_CONTEXT_USER);
+			reg_pt_val = (pt_val + kgsl_mmu_get_pt_lsb(&device->mmu,
+						i, KGSL_IOMMU_CONTEXT_USER));
 			/*
 			 * Set address of the new pagetable by writng to IOMMU
 			 * TTBR0 register
 			 */
 			*cmds++ = cp_type3_packet(CP_MEM_WRITE, 2);
-			*cmds++ = reg_map_desc[i]->gpuaddr +
-				(KGSL_IOMMU_CONTEXT_USER <<
-				KGSL_IOMMU_CTX_SHIFT) + KGSL_IOMMU_TTBR0;
+			*cmds++ = kgsl_mmu_get_reg_gpuaddr(&device->mmu, i,
+				KGSL_IOMMU_CONTEXT_USER, KGSL_IOMMU_CTX_TTBR0);
 			*cmds++ = reg_pt_val;
 			*cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
 			*cmds++ = 0x00000000;
@@ -338,36 +330,24 @@
 			 * above writes have completed
 			 */
 			cmds += adreno_add_read_cmds(device, cmds,
-				reg_map_desc[i]->gpuaddr +
-				(KGSL_IOMMU_CONTEXT_USER <<
-				KGSL_IOMMU_CTX_SHIFT) + KGSL_IOMMU_TTBR0,
+				kgsl_mmu_get_reg_gpuaddr(&device->mmu, i,
+				KGSL_IOMMU_CONTEXT_USER, KGSL_IOMMU_CTX_TTBR0),
 				reg_pt_val,
 				device->mmu.setstate_memory.gpuaddr +
 				KGSL_IOMMU_SETSTATE_NOP_OFFSET);
 		}
-		/* invalidate all base pointers */
-		*cmds++ = cp_type3_packet(CP_INVALIDATE_STATE, 1);
-		*cmds++ = 0x7fff;
-
-		cmds += __adreno_add_idle_indirect_cmds(cmds,
-			device->mmu.setstate_memory.gpuaddr +
-			KGSL_IOMMU_SETSTATE_NOP_OFFSET);
 	}
 	if (flags & KGSL_MMUFLAGS_TLBFLUSH) {
 		/*
 		 * tlb flush
 		 */
 		for (i = 0; i < num_iommu_units; i++) {
-			reg_pt_val = (pt_val &
-				(KGSL_IOMMU_TTBR0_PA_MASK <<
-				KGSL_IOMMU_TTBR0_PA_SHIFT)) +
-				kgsl_mmu_get_pt_lsb(&device->mmu, i,
-					KGSL_IOMMU_CONTEXT_USER);
+			reg_pt_val = (pt_val + kgsl_mmu_get_pt_lsb(&device->mmu,
+						i, KGSL_IOMMU_CONTEXT_USER));
 
 			*cmds++ = cp_type3_packet(CP_MEM_WRITE, 2);
-			*cmds++ = (reg_map_desc[i]->gpuaddr +
-				(KGSL_IOMMU_CONTEXT_USER <<
-				KGSL_IOMMU_CTX_SHIFT) +
+			*cmds++ = kgsl_mmu_get_reg_gpuaddr(&device->mmu, i,
+				KGSL_IOMMU_CONTEXT_USER,
 				KGSL_IOMMU_CTX_TLBIALL);
 			*cmds++ = 1;
 
@@ -376,9 +356,9 @@
 			KGSL_IOMMU_SETSTATE_NOP_OFFSET);
 
 			cmds += adreno_add_read_cmds(device, cmds,
-				reg_map_desc[i]->gpuaddr +
-				(KGSL_IOMMU_CONTEXT_USER <<
-				KGSL_IOMMU_CTX_SHIFT) + KGSL_IOMMU_TTBR0,
+				kgsl_mmu_get_reg_gpuaddr(&device->mmu, i,
+					KGSL_IOMMU_CONTEXT_USER,
+					KGSL_IOMMU_CTX_TTBR0),
 				reg_pt_val,
 				device->mmu.setstate_memory.gpuaddr +
 				KGSL_IOMMU_SETSTATE_NOP_OFFSET);
@@ -387,7 +367,8 @@
 
 	if (cpu_is_msm8960())
 		cmds += adreno_add_change_mh_phys_limit_cmds(cmds,
-			reg_map_desc[num_iommu_units - 1]->gpuaddr - PAGE_SIZE,
+			kgsl_mmu_get_reg_gpuaddr(&device->mmu, 0,
+						0, KGSL_IOMMU_GLOBAL_BASE),
 			device->mmu.setstate_memory.gpuaddr +
 			KGSL_IOMMU_SETSTATE_NOP_OFFSET);
 	else
@@ -398,6 +379,10 @@
 
 	sizedwords += (cmds - &link[0]);
 	if (sizedwords) {
+		/* invalidate all base pointers */
+		*cmds++ = cp_type3_packet(CP_INVALIDATE_STATE, 1);
+		*cmds++ = 0x7fff;
+		sizedwords += 2;
 		/*
 		 * add an interrupt at the end of commands so that the smmu
 		 * disable clock off function will get called
@@ -413,9 +398,6 @@
 		kgsl_mmu_disable_clk_on_ts(&device->mmu,
 		adreno_dev->ringbuffer.timestamp[KGSL_MEMSTORE_GLOBAL], true);
 	}
-done:
-	if (num_iommu_units)
-		kfree(reg_map_array);
 }
 
 static void adreno_gpummu_setstate(struct kgsl_device *device,
@@ -453,7 +435,7 @@
 
 			/* set page table base */
 			*cmds++ = cp_type0_packet(MH_MMU_PT_BASE, 1);
-			*cmds++ = kgsl_mmu_pt_get_base_addr(
+			*cmds++ = kgsl_mmu_get_pt_base_addr(&device->mmu,
 					device->mmu.hwpagetable);
 			sizedwords += 4;
 		}
@@ -1109,7 +1091,7 @@
 static int
 adreno_ocmem_gmem_malloc(struct adreno_device *adreno_dev)
 {
-	if (adreno_dev->gpurev != ADRENO_REV_A330)
+	if (!adreno_is_a330(adreno_dev))
 		return 0;
 
 	/* OCMEM is only needed once, do not support consective allocation */
@@ -1122,7 +1104,7 @@
 		return -ENOMEM;
 
 	adreno_dev->gmem_size = adreno_dev->ocmem_hdl->len;
-	adreno_dev->gmem_base = adreno_dev->ocmem_hdl->addr;
+	adreno_dev->ocmem_base = adreno_dev->ocmem_hdl->addr;
 
 	return 0;
 }
@@ -1130,7 +1112,7 @@
 static void
 adreno_ocmem_gmem_free(struct adreno_device *adreno_dev)
 {
-	if (adreno_dev->gpurev != ADRENO_REV_A330)
+	if (!adreno_is_a330(adreno_dev))
 		return;
 
 	if (adreno_dev->ocmem_hdl == NULL)
@@ -1481,7 +1463,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) {
@@ -1524,7 +1506,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 */
@@ -1806,61 +1788,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);
@@ -1876,7 +1871,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;
 		}
@@ -1887,7 +1882,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;
@@ -1934,7 +1929,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;
@@ -1956,7 +1951,8 @@
 
 		adreno_context = (struct adreno_context *)context->devctxt;
 
-		if (kgsl_mmu_pt_equal(adreno_context->pagetable, pt_base)) {
+		if (kgsl_mmu_pt_equal(&device->mmu, adreno_context->pagetable,
+					pt_base)) {
 			struct kgsl_memdesc *desc;
 
 			desc = &adreno_context->gpustate;
@@ -1995,7 +1991,7 @@
 					size))
 		return &device->mmu.setstate_memory;
 
-	entry = kgsl_get_mem_entry(pt_base, gpuaddr, size);
+	entry = kgsl_get_mem_entry(device, pt_base, gpuaddr, size);
 
 	if (entry)
 		return &entry->memdesc;
@@ -2184,12 +2180,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));
 
@@ -2207,11 +2202,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
@@ -2250,8 +2252,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) {
@@ -2264,11 +2266,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:
 	/*
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index b923049e..66402fe 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -55,6 +55,12 @@
 
 #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,
@@ -92,6 +98,7 @@
 	unsigned int ib_check_level;
 	unsigned int fast_hang_detect;
 	struct ocmem_buf *ocmem_hdl;
+	unsigned int ocmem_base;
 };
 
 struct adreno_gpudev {
@@ -158,11 +165,14 @@
 extern const unsigned int a3xx_registers[];
 extern const unsigned int a3xx_registers_count;
 
+extern const unsigned int a330_registers[];
+extern const unsigned int a330_registers_count;
+
 extern unsigned int hang_detect_regs[];
 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,
@@ -245,6 +255,11 @@
 	return (adreno_dev->gpurev == ADRENO_REV_A320);
 }
 
+static inline int adreno_is_a330(struct adreno_device *adreno_dev)
+{
+	return (adreno_dev->gpurev == ADRENO_REV_A330);
+}
+
 static inline int adreno_rb_ctxtswitch(unsigned int *cmd)
 {
 	return (cmd[0] == cp_nop_packet(1) &&
diff --git a/drivers/gpu/msm/adreno_a2xx.c b/drivers/gpu/msm/adreno_a2xx.c
index 5ba3778..3fb729b 100644
--- a/drivers/gpu/msm/adreno_a2xx.c
+++ b/drivers/gpu/msm/adreno_a2xx.c
@@ -1507,7 +1507,7 @@
 {
 	struct kgsl_device *device = &adreno_dev->dev;
 
-	if (context == NULL)
+	if (context == NULL || (context->flags & CTXT_FLAGS_BEING_DESTOYED))
 		return;
 
 	if (context->flags & CTXT_FLAGS_GPU_HANG)
@@ -1840,7 +1840,7 @@
 	unsigned int *cmds, cmds_gpu;
 
 	/* ME_INIT */
-	cmds = adreno_ringbuffer_allocspace(rb, 19);
+	cmds = adreno_ringbuffer_allocspace(rb, NULL, 19);
 	cmds_gpu = rb->buffer_desc.gpuaddr + sizeof(uint)*(rb->wptr-19);
 
 	GSL_RB_WRITE(cmds, cmds_gpu, cp_type3_packet(CP_ME_INIT, 18));
@@ -1983,10 +1983,10 @@
 			0x18000000);
 	}
 
-	if (adreno_is_a203(adreno_dev))
-		/* For A203 increase number of clocks that RBBM
-		 * will wait before de-asserting Register Clock
-		 * Active signal */
+	if (adreno_is_a20x(adreno_dev))
+		/* For A20X based targets 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);
diff --git a/drivers/gpu/msm/adreno_a2xx_snapshot.c b/drivers/gpu/msm/adreno_a2xx_snapshot.c
index 2368264..282440c 100644
--- a/drivers/gpu/msm/adreno_a2xx_snapshot.c
+++ b/drivers/gpu/msm/adreno_a2xx_snapshot.c
@@ -232,6 +232,7 @@
 	int *remain, int hang)
 {
 	struct kgsl_device *device = &adreno_dev->dev;
+	struct kgsl_snapshot_registers_list list;
 	struct kgsl_snapshot_registers regs;
 	unsigned int pmoverride;
 
@@ -248,10 +249,13 @@
 		regs.count = a225_registers_count;
 	}
 
+	list.registers = &regs;
+	list.count = 1;
+
 	/* Master set of (non debug) registers */
 	snapshot = kgsl_snapshot_add_section(device,
 		KGSL_SNAPSHOT_SECTION_REGS, snapshot, remain,
-		kgsl_snapshot_dump_regs, &regs);
+		kgsl_snapshot_dump_regs, &list);
 
 	/* CP_STATE_DEBUG indexed registers */
 	snapshot = kgsl_snapshot_indexed_registers(device, snapshot,
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index 2dbfd8f..8611b6b 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -69,6 +69,14 @@
 
 const unsigned int a3xx_registers_count = ARRAY_SIZE(a3xx_registers) / 2;
 
+/* The set of additional registers to be dumped for A330 */
+
+const unsigned int a330_registers[] = {
+	0x1d0, 0x1d0, 0x1d4, 0x1d4, 0x453, 0x453,
+};
+
+const unsigned int a330_registers_count = ARRAY_SIZE(a330_registers) / 2;
+
 /* Simple macro to facilitate bit setting in the gmem2sys and sys2gmem
  * functions.
  */
@@ -2290,9 +2298,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,
@@ -2350,7 +2355,7 @@
 {
 	struct kgsl_device *device = &adreno_dev->dev;
 
-	if (context == NULL)
+	if (context == NULL || (context->flags & CTXT_FLAGS_BEING_DESTOYED))
 		return;
 
 	if (context->flags & CTXT_FLAGS_GPU_HANG)
@@ -2458,7 +2463,7 @@
 			 struct adreno_ringbuffer *rb)
 {
 	unsigned int *cmds, cmds_gpu;
-	cmds = adreno_ringbuffer_allocspace(rb, 18);
+	cmds = adreno_ringbuffer_allocspace(rb, NULL, 18);
 	cmds_gpu = rb->buffer_desc.gpuaddr + sizeof(uint) * (rb->wptr - 18);
 
 	GSL_RB_WRITE(cmds, cmds_gpu, cp_type3_packet(CP_ME_INIT, 17));
@@ -2701,16 +2706,16 @@
 	struct kgsl_device *device = &adreno_dev->dev;
 
 	/* Set up 16 deep read/write request queues */
-	if (adreno_dev->gpurev == ADRENO_REV_A330) {
+	if (adreno_is_a330(adreno_dev)) {
 		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_IN_RD_LIM_CONF1, 0x18181818);
+		adreno_regwrite(device, A3XX_VBIF_OUT_RD_LIM_CONF0, 0x18181818);
+		adreno_regwrite(device, A3XX_VBIF_OUT_WR_LIM_CONF0, 0x18181818);
 		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);
+		adreno_regwrite(device, A3XX_VBIF_IN_WR_LIM_CONF1, 0x18181818);
 		/* Enable WR-REQ */
-		adreno_regwrite(device, A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x0000FF);
+		adreno_regwrite(device, A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x00003F);
 
 		/* Set up round robin arbitration between both AXI ports */
 		adreno_regwrite(device, A3XX_VBIF_ARB_CTL, 0x00000030);
@@ -2718,12 +2723,17 @@
 		adreno_regwrite(device, A3XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x0001);
 
 		/* Set up AOOO */
-		adreno_regwrite(device, A3XX_VBIF_OUT_AXI_AOOO_EN, 0x00000FFF);
-		adreno_regwrite(device, A3XX_VBIF_OUT_AXI_AOOO, 0x0FFF0FFF);
+		adreno_regwrite(device, A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000FFFF);
+		adreno_regwrite(device, A3XX_VBIF_OUT_AXI_AOOO, 0xFFFFFFFF);
 
-		/* VBIF AXI AMEMTYPE CONFIG */
-		adreno_regwrite(device, A3XX_VBIF_OUT_AXI_AMEMTYPE_CONF0,
-			0x22222222);
+		/* Enable 1K sort */
+		adreno_regwrite(device, A3XX_VBIF_ABIT_SORT, 0x1FFFF);
+		adreno_regwrite(device, A3XX_VBIF_ABIT_SORT_CONF, 0x000000A4);
+
+		/* Diable VBIF clock gating. This is to enable AXI running
+		 * higher frequency than GPU.
+		 */
+		adreno_regwrite(device, A3XX_VBIF_CLKON, 1);
 	} else {
 		adreno_regwrite(device, A3XX_VBIF_IN_RD_LIM_CONF0, 0x10101010);
 		adreno_regwrite(device, A3XX_VBIF_IN_RD_LIM_CONF1, 0x10101010);
@@ -2771,10 +2781,18 @@
 	adreno_regwrite(device, A3XX_RBBM_INTERFACE_HANG_INT_CTL,
 			(1 << 16) | 0xFFF);
 
+	/* Enable 64-byte cacheline size. HW Default is 32-byte (0x000000E0). */
+	adreno_regwrite(device, A3XX_UCHE_CACHE_MODE_CONTROL_REG, 0x00000001);
+
 	/* Enable Clock gating */
 	adreno_regwrite(device, A3XX_RBBM_CLOCK_CTL,
 			A3XX_RBBM_CLOCK_CTL_DEFAULT);
 
+	/* Set the OCMEM base address for A330 */
+	if (adreno_is_a330(adreno_dev)) {
+		adreno_regwrite(device, A3XX_RB_GMEM_BASE_ADDR,
+			(unsigned int)(adreno_dev->ocmem_base >> 14));
+	}
 }
 
 /* Defined in adreno_a3xx_snapshot.c */
diff --git a/drivers/gpu/msm/adreno_a3xx_snapshot.c b/drivers/gpu/msm/adreno_a3xx_snapshot.c
index a3bee4d..d49fc23 100644
--- a/drivers/gpu/msm/adreno_a3xx_snapshot.c
+++ b/drivers/gpu/msm/adreno_a3xx_snapshot.c
@@ -156,28 +156,68 @@
 	return DEBUG_SECTION_SZ(size);
 }
 
-#define CP_ROQ_SIZE 128
+/* This is the ROQ buffer size on both the A305 and A320 */
+#define A320_CP_ROQ_SIZE 128
+/* This is the ROQ buffer size on the A330 */
+#define A330_CP_ROQ_SIZE 512
 
 static int a3xx_snapshot_cp_roq(struct kgsl_device *device, void *snapshot,
 		int remain, void *priv)
 {
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 	struct kgsl_snapshot_debug *header = snapshot;
 	unsigned int *data = snapshot + sizeof(*header);
-	int i;
+	int i, size;
 
-	if (remain < DEBUG_SECTION_SZ(CP_ROQ_SIZE)) {
+	/* The size of the ROQ buffer is core dependent */
+	size = adreno_is_a330(adreno_dev) ?
+		A330_CP_ROQ_SIZE : A320_CP_ROQ_SIZE;
+
+	if (remain < DEBUG_SECTION_SZ(size)) {
 		SNAPSHOT_ERR_NOMEM(device, "CP ROQ DEBUG");
 		return 0;
 	}
 
 	header->type = SNAPSHOT_DEBUG_CP_ROQ;
-	header->size = CP_ROQ_SIZE;
+	header->size = size;
 
 	adreno_regwrite(device, A3XX_CP_ROQ_ADDR, 0x0);
-	for (i = 0; i < CP_ROQ_SIZE; i++)
+	for (i = 0; i < size; i++)
 		adreno_regread(device, A3XX_CP_ROQ_DATA, &data[i]);
 
-	return DEBUG_SECTION_SZ(CP_ROQ_SIZE);
+	return DEBUG_SECTION_SZ(size);
+}
+
+#define A330_CP_MERCIU_QUEUE_SIZE 32
+
+static int a330_snapshot_cp_merciu(struct kgsl_device *device, void *snapshot,
+		int remain, void *priv)
+{
+	struct kgsl_snapshot_debug *header = snapshot;
+	unsigned int *data = snapshot + sizeof(*header);
+	int i, size;
+
+	/* The MERCIU data is two dwords per entry */
+	size = A330_CP_MERCIU_QUEUE_SIZE << 1;
+
+	if (remain < DEBUG_SECTION_SZ(size)) {
+		SNAPSHOT_ERR_NOMEM(device, "CP MERCIU DEBUG");
+		return 0;
+	}
+
+	header->type = SNAPSHOT_DEBUG_CP_MERCIU;
+	header->size = size;
+
+	adreno_regwrite(device, A3XX_CP_MERCIU_ADDR, 0x0);
+
+	for (i = 0; i < A330_CP_MERCIU_QUEUE_SIZE; i++) {
+		adreno_regread(device, A3XX_CP_MERCIU_DATA,
+			&data[(i * 2)]);
+		adreno_regread(device, A3XX_CP_MERCIU_DATA2,
+			&data[(i * 2) + 1]);
+	}
+
+	return DEBUG_SECTION_SZ(size);
 }
 
 #define DEBUGFS_BLOCK_SIZE 0x40
@@ -265,15 +305,26 @@
 	int *remain, int hang)
 {
 	struct kgsl_device *device = &adreno_dev->dev;
-	struct kgsl_snapshot_registers regs;
+	struct kgsl_snapshot_registers_list list;
+	struct kgsl_snapshot_registers regs[2];
 
-	regs.regs = (unsigned int *) a3xx_registers;
-	regs.count = a3xx_registers_count;
+	regs[0].regs = (unsigned int *) a3xx_registers;
+	regs[0].count = a3xx_registers_count;
+
+	list.registers = regs;
+	list.count = 1;
+
+	/* For A330, append the additional list of new registers to grab */
+	if (adreno_is_a330(adreno_dev)) {
+		regs[1].regs = (unsigned int *) a330_registers;
+		regs[1].count = a330_registers_count;
+		list.count++;
+	}
 
 	/* Master set of (non debug) registers */
 	snapshot = kgsl_snapshot_add_section(device,
 		KGSL_SNAPSHOT_SECTION_REGS, snapshot, remain,
-		kgsl_snapshot_dump_regs, &regs);
+		kgsl_snapshot_dump_regs, &list);
 
 	/* CP_STATE_DEBUG indexed registers */
 	snapshot = kgsl_snapshot_indexed_registers(device, snapshot,
@@ -322,6 +373,12 @@
 			KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain,
 			a3xx_snapshot_cp_roq, NULL);
 
+	if (adreno_is_a330(adreno_dev)) {
+		snapshot = kgsl_snapshot_add_section(device,
+			KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain,
+			a330_snapshot_cp_merciu, NULL);
+	}
+
 	snapshot = a3xx_snapshot_debugbus(device, snapshot, remain);
 
 	/* Enable Clock gating */
diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c
index 6c74dfa..a50747d 100644
--- a/drivers/gpu/msm/adreno_drawctxt.c
+++ b/drivers/gpu/msm/adreno_drawctxt.c
@@ -221,10 +221,16 @@
 				     CTXT_FLAGS_GMEM_SHADOW |
 				     CTXT_FLAGS_STATE_SHADOW);
 
+		drawctxt->flags |= CTXT_FLAGS_BEING_DESTOYED;
+
 		adreno_drawctxt_switch(adreno_dev, NULL, 0);
 	}
 
-	adreno_idle(device, KGSL_TIMEOUT_DEFAULT);
+	adreno_idle(device);
+
+	if (adreno_is_a20x(adreno_dev) && adreno_dev->drawctxt_active)
+		kgsl_setstate(&device->mmu, adreno_dev->drawctxt_active->id,
+			KGSL_MMUFLAGS_PTUPDATE);
 
 	kgsl_sharedmem_free(&drawctxt->gpustate);
 	kgsl_sharedmem_free(&drawctxt->context_gmem_shadow.gmemshadow);
diff --git a/drivers/gpu/msm/adreno_drawctxt.h b/drivers/gpu/msm/adreno_drawctxt.h
index 5b14a69..d58f2da 100644
--- a/drivers/gpu/msm/adreno_drawctxt.h
+++ b/drivers/gpu/msm/adreno_drawctxt.h
@@ -46,6 +46,8 @@
 #define CTXT_FLAGS_PER_CONTEXT_TS	0x00040000
 /* Context has caused a GPU hang and recovered properly */
 #define CTXT_FLAGS_GPU_HANG_RECOVERED	0x00008000
+/* Context is being destroyed so dont save it */
+#define CTXT_FLAGS_BEING_DESTOYED	0x00010000
 
 struct kgsl_device;
 struct adreno_device;
diff --git a/drivers/gpu/msm/adreno_postmortem.c b/drivers/gpu/msm/adreno_postmortem.c
index 2038c10..620b82c 100644
--- a/drivers/gpu/msm/adreno_postmortem.c
+++ b/drivers/gpu/msm/adreno_postmortem.c
@@ -697,8 +697,6 @@
 
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 
-	struct kgsl_memdesc **reg_map;
-	void *reg_map_array;
 	int num_iommu_units = 0;
 
 	mb();
@@ -783,9 +781,7 @@
 	ib_list.count = 0;
 	i = 0;
 	/* get the register mapped array in case we are using IOMMU */
-	num_iommu_units = kgsl_mmu_get_reg_map_desc(&device->mmu,
-							&reg_map_array);
-	reg_map = reg_map_array;
+	num_iommu_units = kgsl_mmu_get_num_iommu_units(&device->mmu);
 	for (read_idx = 0; read_idx < num_item; ) {
 		uint32_t this_cmd = rb_copy[read_idx++];
 		if (adreno_cmd_is_ib(this_cmd)) {
@@ -799,13 +795,14 @@
 					ib_list.bases[i],
 					ib_list.sizes[i], 0);
 		} else if (this_cmd == cp_type0_packet(MH_MMU_PT_BASE, 1) ||
-			(num_iommu_units && this_cmd == (reg_map[0]->gpuaddr +
-			(KGSL_IOMMU_CONTEXT_USER << KGSL_IOMMU_CTX_SHIFT) +
-			KGSL_IOMMU_TTBR0))) {
-
+			(num_iommu_units && this_cmd ==
+			kgsl_mmu_get_reg_gpuaddr(&device->mmu, 0,
+						KGSL_IOMMU_CONTEXT_USER,
+						KGSL_IOMMU_CTX_TTBR0))) {
 			KGSL_LOG_DUMP(device, "Current pagetable: %x\t"
 				"pagetable base: %x\n",
-				kgsl_mmu_get_ptname_from_ptbase(cur_pt_base),
+				kgsl_mmu_get_ptname_from_ptbase(&device->mmu,
+								cur_pt_base),
 				cur_pt_base);
 
 			/* Set cur_pt_base to the new pagetable base */
@@ -813,12 +810,11 @@
 
 			KGSL_LOG_DUMP(device, "New pagetable: %x\t"
 				"pagetable base: %x\n",
-				kgsl_mmu_get_ptname_from_ptbase(cur_pt_base),
+				kgsl_mmu_get_ptname_from_ptbase(&device->mmu,
+								cur_pt_base),
 				cur_pt_base);
 		}
 	}
-	if (num_iommu_units)
-		kfree(reg_map_array);
 
 	/* Restore cur_pt_base back to the pt_base of
 	   the process in whose context the GPU hung */
@@ -873,9 +869,14 @@
 		else if (adreno_is_a225(adreno_dev))
 			adreno_dump_regs(device, a225_registers,
 				a225_registers_count);
-		else if (adreno_is_a3xx(adreno_dev))
+		else if (adreno_is_a3xx(adreno_dev)) {
 			adreno_dump_regs(device, a3xx_registers,
 					a3xx_registers_count);
+
+			if (adreno_is_a330(adreno_dev))
+				adreno_dump_regs(device, a330_registers,
+					a330_registers_count);
+		}
 	}
 
 error_vfree:
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index ca9e335..db913a5 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -44,19 +44,18 @@
 	adreno_regwrite(rb->device, REG_CP_RB_WPTR, rb->wptr);
 }
 
-static void
-adreno_ringbuffer_waitspace(struct adreno_ringbuffer *rb, unsigned int numcmds,
-			  int wptr_ahead)
+static int
+adreno_ringbuffer_waitspace(struct adreno_ringbuffer *rb,
+				struct adreno_context *context,
+				unsigned int numcmds, int wptr_ahead)
 {
 	int nopcount;
 	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));
@@ -87,7 +86,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);
@@ -101,7 +100,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,
@@ -122,19 +121,28 @@
 		continue;
 
 err:
-		if (!adreno_dump_and_recover(rb->device))
-				wait_time = jiffies + wait_timeout;
-			else
-				/* GPU is hung and we cannot recover */
-				BUG();
+		if (!adreno_dump_and_recover(rb->device)) {
+			if (context && context->flags & CTXT_FLAGS_GPU_HANG) {
+				KGSL_CTXT_WARN(rb->device,
+				"Context %p caused a gpu hang. Will not accept commands for context %d\n",
+				context, context->id);
+				return -EDEADLK;
+			}
+			wait_time = jiffies + wait_timeout;
+		} else {
+			/* GPU is hung and we cannot recover */
+			BUG();
+		}
 	}
+	return 0;
 }
 
 unsigned int *adreno_ringbuffer_allocspace(struct adreno_ringbuffer *rb,
-					     unsigned int numcmds)
+					struct adreno_context *context,
+					unsigned int numcmds)
 {
-	unsigned int	*ptr = NULL;
-
+	unsigned int *ptr = NULL;
+	int ret = 0;
 	BUG_ON(numcmds >= rb->sizedwords);
 
 	GSL_RB_GET_READPTR(rb, &rb->rptr);
@@ -144,20 +152,25 @@
 		/* reserve dwords for nop packet */
 		if ((rb->wptr + numcmds) > (rb->sizedwords -
 				GSL_RB_NOP_SIZEDWORDS))
-			adreno_ringbuffer_waitspace(rb, numcmds, 1);
+			ret = adreno_ringbuffer_waitspace(rb, context,
+							numcmds, 1);
 	} else {
 		/* wptr behind rptr */
 		if ((rb->wptr + numcmds) >= rb->rptr)
-			adreno_ringbuffer_waitspace(rb, numcmds, 0);
+			ret = adreno_ringbuffer_waitspace(rb, context,
+							numcmds, 0);
 		/* check for remaining space */
 		/* reserve dwords for nop packet */
-		if ((rb->wptr + numcmds) > (rb->sizedwords -
+		if (!ret && (rb->wptr + numcmds) > (rb->sizedwords -
 				GSL_RB_NOP_SIZEDWORDS))
-			adreno_ringbuffer_waitspace(rb, numcmds, 1);
+			ret = adreno_ringbuffer_waitspace(rb, context,
+							numcmds, 1);
 	}
 
-	ptr = (unsigned int *)rb->buffer_desc.hostptr + rb->wptr;
-	rb->wptr += numcmds;
+	if (!ret) {
+		ptr = (unsigned int *)rb->buffer_desc.hostptr + rb->wptr;
+		rb->wptr += numcmds;
+	}
 
 	return ptr;
 }
@@ -393,7 +406,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;
@@ -403,8 +416,15 @@
 
 void adreno_ringbuffer_stop(struct adreno_ringbuffer *rb)
 {
-	if (rb->flags & KGSL_FLAGS_STARTED)
+	struct kgsl_device *device = rb->device;
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+
+	if (rb->flags & KGSL_FLAGS_STARTED) {
+		if (adreno_is_a200(adreno_dev))
+			adreno_regwrite(rb->device, REG_CP_ME_CNTL, 0x10000000);
+
 		rb->flags &= ~KGSL_FLAGS_STARTED;
+	}
 }
 
 int adreno_ringbuffer_init(struct kgsl_device *device)
@@ -507,13 +527,12 @@
 		total_sizedwords += 4; /* global timestamp for recovery*/
 	}
 
-	ringcmds = adreno_ringbuffer_allocspace(rb, total_sizedwords);
-	/* GPU may hang during space allocation, if thats the case the current
-	 * context may have hung the GPU */
-	if (context->flags & CTXT_FLAGS_GPU_HANG) {
-		KGSL_CTXT_WARN(rb->device,
-		"Context %p caused a gpu hang. Will not accept commands for context %d\n",
-		context, context->id);
+	ringcmds = adreno_ringbuffer_allocspace(rb, context, total_sizedwords);
+	if (!ringcmds) {
+		/*
+		 * We could not allocate space in ringbuffer, just return the
+		 * last timestamp
+		 */
 		return rb->timestamp[context_id];
 	}
 
@@ -961,7 +980,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 6c3d9b1..4f58a15 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.h
+++ b/drivers/gpu/msm/adreno_ringbuffer.h
@@ -127,7 +127,8 @@
 			int num_rb_contents);
 
 unsigned int *adreno_ringbuffer_allocspace(struct adreno_ringbuffer *rb,
-					     unsigned int numcmds);
+						struct adreno_context *context,
+						unsigned int numcmds);
 
 static inline int adreno_ringbuffer_count(struct adreno_ringbuffer *rb,
 	unsigned int rptr)
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 3d83508..7241201 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -25,7 +25,7 @@
 #include <linux/rbtree.h>
 #include <linux/ashmem.h>
 #include <linux/major.h>
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
 #include <linux/io.h>
 #include <mach/socinfo.h>
 
@@ -193,13 +193,14 @@
 EXPORT_SYMBOL(kgsl_cancel_events);
 
 /* kgsl_get_mem_entry - get the mem_entry structure for the specified object
+ * @device - Pointer to the device structure
  * @ptbase - the pagetable base of the object
  * @gpuaddr - the GPU address of the object
  * @size - Size of the region to search
  */
 
-struct kgsl_mem_entry *kgsl_get_mem_entry(unsigned int ptbase,
-	unsigned int gpuaddr, unsigned int size)
+struct kgsl_mem_entry *kgsl_get_mem_entry(struct kgsl_device *device,
+	unsigned int ptbase, unsigned int gpuaddr, unsigned int size)
 {
 	struct kgsl_process_private *priv;
 	struct kgsl_mem_entry *entry;
@@ -207,7 +208,7 @@
 	mutex_lock(&kgsl_driver.process_mutex);
 
 	list_for_each_entry(priv, &kgsl_driver.process_list, list) {
-		if (!kgsl_mmu_pt_equal(priv->pagetable, ptbase))
+		if (!kgsl_mmu_pt_equal(&device->mmu, priv->pagetable, ptbase))
 			continue;
 		spin_lock(&priv->mem_lock);
 		entry = kgsl_sharedmem_find_region(priv, gpuaddr, size);
@@ -559,7 +560,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. */
@@ -1769,8 +1770,10 @@
 		return -ENODEV;
 
 	handle = ion_import_dma_buf(kgsl_ion_client, fd);
-	if (IS_ERR_OR_NULL(handle))
+	if (IS_ERR(handle))
 		return PTR_ERR(handle);
+	else if (!handle)
+		return -EINVAL;
 
 	entry->memtype = KGSL_MEM_ENTRY_ION;
 	entry->priv_data = handle;
@@ -2605,7 +2608,7 @@
 		}
 
 		if (device->state == KGSL_STATE_ACTIVE)
-			kgsl_idle(device,  KGSL_TIMEOUT_DEFAULT);
+			kgsl_idle(device);
 
 	}
 	KGSL_LOG_DUMP(device, "|%s| Dump Started\n", device->name);
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index ac04c56..416eda9 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -175,8 +175,8 @@
 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);
+struct kgsl_mem_entry *kgsl_get_mem_entry(struct kgsl_device *device,
+		unsigned int ptbase, unsigned int gpuaddr, unsigned int size);
 
 struct kgsl_mem_entry *kgsl_sharedmem_find_region(
 	struct kgsl_process_private *private, unsigned int gpuaddr,
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index d0932ef..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);
@@ -287,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 d8472f2..326e79d 100644
--- a/drivers/gpu/msm/kgsl_gpummu.c
+++ b/drivers/gpu/msm/kgsl_gpummu.c
@@ -355,8 +355,9 @@
 	return NULL;
 }
 
-int kgsl_gpummu_pt_equal(struct kgsl_pagetable *pt,
-					unsigned int pt_base)
+int kgsl_gpummu_pt_equal(struct kgsl_mmu *mmu,
+			struct kgsl_pagetable *pt,
+			unsigned int pt_base)
 {
 	struct kgsl_gpummu_pt *gpummu_pt = pt ? pt->priv : NULL;
 	return gpummu_pt && pt_base && (gpummu_pt->base.gpuaddr == pt_base);
@@ -409,10 +410,10 @@
 	KGSL_MEM_CRIT(mmu->device,
 			"mmu page fault: page=0x%lx pt=%d op=%s axi=%d\n",
 			reg & ~(PAGE_SIZE - 1),
-			kgsl_mmu_get_ptname_from_ptbase(ptbase),
+			kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase),
 			reg & 0x02 ? "WRITE" : "READ", (reg >> 4) & 0xF);
 	trace_kgsl_mmu_pagefault(mmu->device, reg & ~(PAGE_SIZE - 1),
-			kgsl_mmu_get_ptname_from_ptbase(ptbase),
+			kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase),
 			reg & 0x02 ? "WRITE" : "READ");
 }
 
@@ -472,7 +473,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 +553,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,
@@ -714,12 +715,18 @@
 }
 
 static unsigned int
-kgsl_gpummu_pt_get_base_addr(struct kgsl_pagetable *pt)
+kgsl_gpummu_get_pt_base_addr(struct kgsl_mmu *mmu,
+			struct kgsl_pagetable *pt)
 {
 	struct kgsl_gpummu_pt *gpummu_pt = pt->priv;
 	return gpummu_pt->base.gpuaddr;
 }
 
+static int kgsl_gpummu_get_num_iommu_units(struct kgsl_mmu *mmu)
+{
+	return 1;
+}
+
 struct kgsl_mmu_ops gpummu_ops = {
 	.mmu_init = kgsl_gpummu_init,
 	.mmu_close = kgsl_gpummu_close,
@@ -729,10 +736,13 @@
 	.mmu_device_setstate = kgsl_gpummu_default_setstate,
 	.mmu_pagefault = kgsl_gpummu_pagefault,
 	.mmu_get_current_ptbase = kgsl_gpummu_get_current_ptbase,
+	.mmu_pt_equal = kgsl_gpummu_pt_equal,
+	.mmu_get_pt_base_addr = kgsl_gpummu_get_pt_base_addr,
 	.mmu_enable_clk = NULL,
 	.mmu_disable_clk_on_ts = NULL,
 	.mmu_get_pt_lsb = NULL,
-	.mmu_get_reg_map_desc = NULL,
+	.mmu_get_reg_gpuaddr = NULL,
+	.mmu_get_num_iommu_units = kgsl_gpummu_get_num_iommu_units,
 };
 
 struct kgsl_mmu_pt_ops gpummu_pt_ops = {
@@ -740,6 +750,4 @@
 	.mmu_unmap = kgsl_gpummu_unmap,
 	.mmu_create_pagetable = kgsl_gpummu_create_pagetable,
 	.mmu_destroy_pagetable = kgsl_gpummu_destroy_pagetable,
-	.mmu_pt_equal = kgsl_gpummu_pt_equal,
-	.mmu_pt_get_base_addr = kgsl_gpummu_pt_get_base_addr,
 };
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index e858651..87e8746 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -28,7 +28,24 @@
 #include "adreno.h"
 #include "kgsl_trace.h"
 
-static struct kgsl_iommu_unit *get_iommu_unit(struct device *dev)
+static struct kgsl_iommu_register_list kgsl_iommuv1_reg[KGSL_IOMMU_REG_MAX] = {
+	{ 0, 0, 0 },				/* GLOBAL_BASE */
+	{ 0x10, 0x0003FFFF, 14 },		/* TTBR0 */
+	{ 0x14, 0x0003FFFF, 14 },		/* TTBR1 */
+	{ 0x20, 0, 0 },				/* FSR */
+	{ 0x800, 0, 0 },			/* TLBIALL */
+};
+
+static struct kgsl_iommu_register_list kgsl_iommuv2_reg[KGSL_IOMMU_REG_MAX] = {
+	{ 0, 0, 0 },				/* GLOBAL_BASE */
+	{ 0x20, 0x00FFFFFF, 14 },		/* TTBR0 */
+	{ 0x28, 0x00FFFFFF, 14 },		/* TTBR1 */
+	{ 0x58, 0, 0 },				/* FSR */
+	{ 0x618, 0, 0 }				/* TLBIALL */
+};
+
+static int get_iommu_unit(struct device *dev, struct kgsl_mmu **mmu_out,
+			struct kgsl_iommu_unit **iommu_unit_out)
 {
 	int i, j, k;
 
@@ -49,13 +66,16 @@
 			struct kgsl_iommu_unit *iommu_unit =
 				&iommu->iommu_units[j];
 			for (k = 0; k < iommu_unit->dev_count; k++) {
-				if (iommu_unit->dev[k].dev == dev)
-					return iommu_unit;
+				if (iommu_unit->dev[k].dev == dev) {
+					*mmu_out = mmu;
+					*iommu_unit_out = iommu_unit;
+					return 0;
+				}
 			}
 		}
 	}
 
-	return NULL;
+	return -EINVAL;
 }
 
 static struct kgsl_iommu_device *get_iommu_device(struct kgsl_iommu_unit *unit,
@@ -74,31 +94,41 @@
 static int kgsl_iommu_fault_handler(struct iommu_domain *domain,
 	struct device *dev, unsigned long addr, int flags)
 {
-	struct kgsl_iommu_unit *iommu_unit = get_iommu_unit(dev);
-	struct kgsl_iommu_device *iommu_dev = get_iommu_device(iommu_unit, dev);
+	int ret = 0;
+	struct kgsl_mmu *mmu;
+	struct kgsl_iommu *iommu;
+	struct kgsl_iommu_unit *iommu_unit;
+	struct kgsl_iommu_device *iommu_dev;
 	unsigned int ptbase, fsr;
 
+	ret = get_iommu_unit(dev, &mmu, &iommu_unit);
+	if (ret)
+		goto done;
+	iommu_dev = get_iommu_device(iommu_unit, dev);
 	if (!iommu_dev) {
 		KGSL_CORE_ERR("Invalid IOMMU device %p\n", dev);
-		return -ENOSYS;
+		ret = -ENOSYS;
+		goto done;
 	}
+	iommu = mmu->priv;
 
-	ptbase = KGSL_IOMMU_GET_IOMMU_REG(iommu_unit->reg_map.hostptr,
+	ptbase = KGSL_IOMMU_GET_CTX_REG(iommu, iommu_unit,
 					iommu_dev->ctx_id, TTBR0);
 
-	fsr = KGSL_IOMMU_GET_IOMMU_REG(iommu_unit->reg_map.hostptr,
+	fsr = KGSL_IOMMU_GET_CTX_REG(iommu, iommu_unit,
 		iommu_dev->ctx_id, FSR);
 
 	KGSL_MEM_CRIT(iommu_dev->kgsldev,
 		"GPU PAGE FAULT: addr = %lX pid = %d\n",
-		addr, kgsl_mmu_get_ptname_from_ptbase(ptbase));
+		addr, kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase));
 	KGSL_MEM_CRIT(iommu_dev->kgsldev, "context = %d FSR = %X\n",
 		iommu_dev->ctx_id, fsr);
 
 	trace_kgsl_mmu_pagefault(iommu_dev->kgsldev, addr,
-			kgsl_mmu_get_ptname_from_ptbase(ptbase), 0);
+			kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase), 0);
 
-	return 0;
+done:
+	return ret;
 }
 
 /*
@@ -121,6 +151,8 @@
 				continue;
 			iommu_drvdata = dev_get_drvdata(
 					iommu_unit->dev[j].dev->parent);
+			if (iommu_drvdata->aclk)
+				clk_disable_unprepare(iommu_drvdata->aclk);
 			if (iommu_drvdata->clk)
 				clk_disable_unprepare(iommu_drvdata->clk);
 			clk_disable_unprepare(iommu_drvdata->pclk);
@@ -247,6 +279,17 @@
 					goto done;
 				}
 			}
+			if (iommu_drvdata->aclk) {
+				ret = clk_prepare_enable(iommu_drvdata->aclk);
+				if (ret) {
+					if (iommu_drvdata->clk)
+						clk_disable_unprepare(
+							iommu_drvdata->clk);
+					clk_disable_unprepare(
+							iommu_drvdata->pclk);
+					goto done;
+				}
+			}
 			iommu_unit->dev[j].clk_enabled = true;
 		}
 	}
@@ -258,6 +301,7 @@
 
 /*
  * kgsl_iommu_pt_equal - Check if pagetables are equal
+ * @mmu - Pointer to mmu structure
  * @pt - Pointer to pagetable
  * @pt_base - Address of a pagetable that the IOMMU register is
  * programmed with
@@ -266,17 +310,23 @@
  * the pagetable which is contained in the pt structure
  * Return - Non-zero if the pagetable addresses are equal else 0
  */
-static int kgsl_iommu_pt_equal(struct kgsl_pagetable *pt,
-					unsigned int pt_base)
+static int kgsl_iommu_pt_equal(struct kgsl_mmu *mmu,
+				struct kgsl_pagetable *pt,
+				unsigned int pt_base)
 {
+	struct kgsl_iommu *iommu = mmu->priv;
 	struct kgsl_iommu_pt *iommu_pt = pt ? pt->priv : NULL;
 	unsigned int domain_ptbase = iommu_pt ?
 				iommu_get_pt_base_addr(iommu_pt->domain) : 0;
 	/* Only compare the valid address bits of the pt_base */
-	domain_ptbase &= (KGSL_IOMMU_TTBR0_PA_MASK <<
-				KGSL_IOMMU_TTBR0_PA_SHIFT);
-	pt_base &= (KGSL_IOMMU_TTBR0_PA_MASK <<
-				KGSL_IOMMU_TTBR0_PA_SHIFT);
+	domain_ptbase &=
+		(iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
+		iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
+
+	pt_base &=
+		(iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
+		iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
+
 	return domain_ptbase && pt_base &&
 		(domain_ptbase == pt_base);
 }
@@ -312,8 +362,13 @@
 				sizeof(struct kgsl_iommu_pt));
 		return NULL;
 	}
-	iommu_pt->domain = iommu_domain_alloc(&platform_bus_type,
-										  MSM_IOMMU_DOMAIN_PT_CACHEABLE);
+	/* L2 redirect is not stable on IOMMU v2 */
+	if (msm_soc_version_supports_iommu_v1())
+		iommu_pt->domain = iommu_domain_alloc(&platform_bus_type,
+					MSM_IOMMU_DOMAIN_PT_CACHEABLE);
+	else
+		iommu_pt->domain = iommu_domain_alloc(&platform_bus_type,
+					0);
 	if (!iommu_pt->domain) {
 		KGSL_CORE_ERR("Failed to create iommu domain\n");
 		kfree(iommu_pt);
@@ -551,8 +606,10 @@
 		}
 		iommu_unit->reg_map.size = data.physend - data.physstart + 1;
 		iommu_unit->reg_map.physaddr = data.physstart;
-		memdesc_sg_phys(&iommu_unit->reg_map, data.physstart,
+		ret = memdesc_sg_phys(&iommu_unit->reg_map, data.physstart,
 				iommu_unit->reg_map.size);
+		if (ret)
+			goto err;
 	}
 	iommu->unit_count = pdata_dev->iommu_count;
 	return ret;
@@ -568,17 +625,22 @@
 }
 
 /*
- * kgsl_iommu_pt_get_base_addr - Get the address of the pagetable that the
+ * kgsl_iommu_get_pt_base_addr - Get the address of the pagetable that the
  * IOMMU ttbr0 register is programmed with
+ * @mmu - Pointer to mmu
  * @pt - kgsl pagetable pointer that contains the IOMMU domain pointer
  *
  * Return - actual pagetable address that the ttbr0 register is programmed
  * with
  */
-static unsigned int kgsl_iommu_pt_get_base_addr(struct kgsl_pagetable *pt)
+static unsigned int kgsl_iommu_get_pt_base_addr(struct kgsl_mmu *mmu,
+						struct kgsl_pagetable *pt)
 {
+	struct kgsl_iommu *iommu = mmu->priv;
 	struct kgsl_iommu_pt *iommu_pt = pt->priv;
-	return iommu_get_pt_base_addr(iommu_pt->domain);
+	return iommu_get_pt_base_addr(iommu_pt->domain) &
+			(iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
+			iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
 }
 
 /*
@@ -653,6 +715,17 @@
 	if (status)
 		goto done;
 
+	iommu->iommu_reg_list = kgsl_iommuv1_reg;
+	iommu->ctx_offset = KGSL_IOMMU_CTX_OFFSET_V1;
+
+	if (msm_soc_version_supports_iommu_v1()) {
+		iommu->iommu_reg_list = kgsl_iommuv1_reg;
+		iommu->ctx_offset = KGSL_IOMMU_CTX_OFFSET_V1;
+	} else {
+		iommu->iommu_reg_list = kgsl_iommuv2_reg;
+		iommu->ctx_offset = KGSL_IOMMU_CTX_OFFSET_V2;
+	}
+
 	/* A nop is required in an indirect buffer when switching
 	 * pagetables in-stream */
 	kgsl_sharedmem_writel(&mmu->setstate_memory,
@@ -683,19 +756,17 @@
 	int status = 0;
 	int i = 0;
 	struct kgsl_iommu *iommu = mmu->priv;
-	struct kgsl_iommu_pt *iommu_pt;
 	struct kgsl_pagetable *pagetable = NULL;
 
 	/* If chip is not 8960 then we use the 2nd context bank for pagetable
 	 * switching on the 3D side for which a separate table is allocated */
-	if (!cpu_is_msm8960()) {
+	if (!cpu_is_msm8960() && msm_soc_version_supports_iommu_v1()) {
 		mmu->priv_bank_table =
 			kgsl_mmu_getpagetable(KGSL_MMU_PRIV_BANK_TABLE_NAME);
 		if (mmu->priv_bank_table == NULL) {
 			status = -ENOMEM;
 			goto err;
 		}
-		iommu_pt = mmu->priv_bank_table->priv;
 	}
 	mmu->defaultpagetable = kgsl_mmu_getpagetable(KGSL_MMU_GLOBAL_PT);
 	/* Return error if the default pagetable doesn't exist */
@@ -706,15 +777,18 @@
 	pagetable = mmu->priv_bank_table ? mmu->priv_bank_table :
 				mmu->defaultpagetable;
 	/* Map the IOMMU regsiters to only defaultpagetable */
-	for (i = 0; i < iommu->unit_count; i++) {
-		iommu->iommu_units[i].reg_map.priv |= KGSL_MEMFLAGS_GLOBAL;
-		status = kgsl_mmu_map(pagetable,
-			&(iommu->iommu_units[i].reg_map),
-			GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
-		if (status) {
-			iommu->iommu_units[i].reg_map.priv &=
+	if (msm_soc_version_supports_iommu_v1()) {
+		for (i = 0; i < iommu->unit_count; i++) {
+			iommu->iommu_units[i].reg_map.priv |=
+						KGSL_MEMFLAGS_GLOBAL;
+			status = kgsl_mmu_map(pagetable,
+				&(iommu->iommu_units[i].reg_map),
+				GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
+			if (status) {
+				iommu->iommu_units[i].reg_map.priv &=
 							~KGSL_MEMFLAGS_GLOBAL;
-			goto err;
+				goto err;
+			}
 		}
 	}
 	return status;
@@ -756,9 +830,7 @@
 		kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000001);
 		kgsl_regwrite(mmu->device, MH_MMU_MPU_END,
 			mh->mpu_base +
-			iommu->iommu_units
-				[iommu->unit_count - 1].reg_map.gpuaddr -
-				PAGE_SIZE);
+			iommu->iommu_units[0].reg_map.gpuaddr);
 	} else {
 		kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000);
 	}
@@ -788,9 +860,9 @@
 	for (i = 0; i < iommu->unit_count; i++) {
 		struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
 		for (j = 0; j < iommu_unit->dev_count; j++)
-			iommu_unit->dev[j].pt_lsb = KGSL_IOMMMU_PT_LSB(
-						KGSL_IOMMU_GET_IOMMU_REG(
-						iommu_unit->reg_map.hostptr,
+			iommu_unit->dev[j].pt_lsb = KGSL_IOMMMU_PT_LSB(iommu,
+						KGSL_IOMMU_GET_CTX_REG(iommu,
+						iommu_unit,
 						iommu_unit->dev[j].ctx_id,
 						TTBR0));
 	}
@@ -835,7 +907,7 @@
 	 * Flushing only required if per process pagetables are used. With
 	 * global case, flushing will happen inside iommu_map function
 	 */
-	if (!ret)
+	if (!ret && msm_soc_version_supports_iommu_v1())
 		*tlb_flags = UINT_MAX;
 #endif
 	return 0;
@@ -929,12 +1001,13 @@
 		return 0;
 	/* Return the current pt base by reading IOMMU pt_base register */
 	kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
-	pt_base = readl_relaxed(iommu->iommu_units[0].reg_map.hostptr +
-			(KGSL_IOMMU_CONTEXT_USER << KGSL_IOMMU_CTX_SHIFT) +
-			KGSL_IOMMU_TTBR0);
+	pt_base = KGSL_IOMMU_GET_CTX_REG(iommu, (&iommu->iommu_units[0]),
+					KGSL_IOMMU_CONTEXT_USER,
+					TTBR0);
 	kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
-	return pt_base & (KGSL_IOMMU_TTBR0_PA_MASK <<
-				KGSL_IOMMU_TTBR0_PA_SHIFT);
+	return pt_base &
+		(iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
+		iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
 }
 
 /*
@@ -955,8 +1028,8 @@
 	struct kgsl_iommu *iommu = mmu->priv;
 	int temp;
 	int i;
-	unsigned int pt_base = kgsl_iommu_pt_get_base_addr(
-					mmu->hwpagetable);
+	unsigned int pt_base = kgsl_iommu_get_pt_base_addr(mmu,
+						mmu->hwpagetable);
 	unsigned int pt_val;
 
 	if (kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER)) {
@@ -964,9 +1037,11 @@
 		return;
 	}
 	/* 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);
+	pt_base &= (iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
+			iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_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 */
@@ -974,23 +1049,20 @@
 						KGSL_IOMMU_CONTEXT_USER);
 			pt_val += pt_base;
 
-			KGSL_IOMMU_SET_IOMMU_REG(
-				iommu->iommu_units[i].reg_map.hostptr,
+			KGSL_IOMMU_SET_CTX_REG(iommu, (&iommu->iommu_units[i]),
 				KGSL_IOMMU_CONTEXT_USER, TTBR0, pt_val);
 
 			mb();
-			temp = KGSL_IOMMU_GET_IOMMU_REG(
-				iommu->iommu_units[i].reg_map.hostptr,
+			temp = KGSL_IOMMU_GET_CTX_REG(iommu,
+				(&iommu->iommu_units[i]),
 				KGSL_IOMMU_CONTEXT_USER, TTBR0);
 		}
 	}
 	/* Flush tlb */
 	if (flags & KGSL_MMUFLAGS_TLBFLUSH) {
 		for (i = 0; i < iommu->unit_count; i++) {
-			KGSL_IOMMU_SET_IOMMU_REG(
-				iommu->iommu_units[i].reg_map.hostptr,
-				KGSL_IOMMU_CONTEXT_USER, CTX_TLBIALL,
-				1);
+			KGSL_IOMMU_SET_CTX_REG(iommu, (&iommu->iommu_units[i]),
+				KGSL_IOMMU_CONTEXT_USER, TLBIALL, 1);
 			mb();
 		}
 	}
@@ -999,40 +1071,32 @@
 }
 
 /*
- * kgsl_iommu_get_reg_map_desc - Returns an array of pointers that contain
- * the address of memory descriptors which map the IOMMU registers
+ * kgsl_iommu_get_reg_gpuaddr - Returns the gpu address of IOMMU regsiter
  * @mmu - Pointer to mmu structure
- * @reg_map_desc - Out parameter in which the address of the array containing
- * pointers to register map descriptors is returned. The caller is supposed
- * to free this array
+ * @iommu_unit - The iommu unit for which base address is requested
+ * @ctx_id - The context ID of the IOMMU ctx
+ * @reg - The register for which address is required
  *
  * Return - The number of iommu units which is also the number of register
  * mapped descriptor arrays which the out parameter will have
  */
-static int kgsl_iommu_get_reg_map_desc(struct kgsl_mmu *mmu,
-					void **reg_map_desc)
+static unsigned int kgsl_iommu_get_reg_gpuaddr(struct kgsl_mmu *mmu,
+					int iommu_unit, int ctx_id, int reg)
 {
 	struct kgsl_iommu *iommu = mmu->priv;
-	void **reg_desc_ptr;
-	int i;
 
-	/*
-	 * Alocate array of pointers that will hold address of the register map
-	 * descriptors
-	 */
-	reg_desc_ptr = kmalloc(iommu->unit_count *
-			sizeof(struct kgsl_memdesc *), GFP_KERNEL);
-	if (!reg_desc_ptr) {
-		KGSL_CORE_ERR("Failed to kmalloc(%d)\n",
-			iommu->unit_count * sizeof(struct kgsl_memdesc *));
-		return -ENOMEM;
-	}
+	if (KGSL_IOMMU_GLOBAL_BASE == reg)
+		return iommu->iommu_units[iommu_unit].reg_map.gpuaddr;
+	else
+		return iommu->iommu_units[iommu_unit].reg_map.gpuaddr +
+			iommu->iommu_reg_list[reg].reg_offset +
+			(ctx_id << KGSL_IOMMU_CTX_SHIFT) + iommu->ctx_offset;
+}
 
-	for (i = 0; i < iommu->unit_count; i++)
-		reg_desc_ptr[i] = &(iommu->iommu_units[i].reg_map);
-
-	*reg_map_desc = reg_desc_ptr;
-	return i;
+static int kgsl_iommu_get_num_iommu_units(struct kgsl_mmu *mmu)
+{
+	struct kgsl_iommu *iommu = mmu->priv;
+	return iommu->unit_count;
 }
 
 struct kgsl_mmu_ops iommu_ops = {
@@ -1047,7 +1111,10 @@
 	.mmu_enable_clk = kgsl_iommu_enable_clk,
 	.mmu_disable_clk_on_ts = kgsl_iommu_disable_clk_on_ts,
 	.mmu_get_pt_lsb = kgsl_iommu_get_pt_lsb,
-	.mmu_get_reg_map_desc = kgsl_iommu_get_reg_map_desc,
+	.mmu_get_reg_gpuaddr = kgsl_iommu_get_reg_gpuaddr,
+	.mmu_get_num_iommu_units = kgsl_iommu_get_num_iommu_units,
+	.mmu_pt_equal = kgsl_iommu_pt_equal,
+	.mmu_get_pt_base_addr = kgsl_iommu_get_pt_base_addr,
 };
 
 struct kgsl_mmu_pt_ops iommu_pt_ops = {
@@ -1055,6 +1122,4 @@
 	.mmu_unmap = kgsl_iommu_unmap,
 	.mmu_create_pagetable = kgsl_iommu_create_pagetable,
 	.mmu_destroy_pagetable = kgsl_iommu_destroy_pagetable,
-	.mmu_pt_equal = kgsl_iommu_pt_equal,
-	.mmu_pt_get_base_addr = kgsl_iommu_pt_get_base_addr,
 };
diff --git a/drivers/gpu/msm/kgsl_iommu.h b/drivers/gpu/msm/kgsl_iommu.h
index f14db93..eafba7b 100644
--- a/drivers/gpu/msm/kgsl_iommu.h
+++ b/drivers/gpu/msm/kgsl_iommu.h
@@ -15,15 +15,24 @@
 
 #include <mach/iommu.h>
 
-/* IOMMU registers and masks */
-#define KGSL_IOMMU_TTBR0			0x10
-#define KGSL_IOMMU_TTBR1			0x14
-#define KGSL_IOMMU_FSR				0x20
+#define KGSL_IOMMU_CTX_OFFSET_V1	0
+#define KGSL_IOMMU_CTX_OFFSET_V2	0x8000
+#define KGSL_IOMMU_CTX_SHIFT		12
 
-#define KGSL_IOMMU_TTBR0_PA_MASK		0x0003FFFF
-#define KGSL_IOMMU_TTBR0_PA_SHIFT		14
-#define KGSL_IOMMU_CTX_TLBIALL			0x800
-#define KGSL_IOMMU_CTX_SHIFT			12
+enum kgsl_iommu_reg_map {
+	KGSL_IOMMU_GLOBAL_BASE = 0,
+	KGSL_IOMMU_CTX_TTBR0,
+	KGSL_IOMMU_CTX_TTBR1,
+	KGSL_IOMMU_CTX_FSR,
+	KGSL_IOMMU_CTX_TLBIALL,
+	KGSL_IOMMU_REG_MAX
+};
+
+struct kgsl_iommu_register_list {
+	unsigned int reg_offset;
+	unsigned int reg_mask;
+	unsigned int reg_shift;
+};
 
 /*
  * Max number of iommu units that the gpu core can have
@@ -35,20 +44,25 @@
 #define KGSL_IOMMU_MAX_DEVS_PER_UNIT 2
 
 /* Macros to read/write IOMMU registers */
-#define KGSL_IOMMU_SET_IOMMU_REG(base_addr, ctx, REG, val)		\
-		writel_relaxed(val, base_addr +				\
-				(ctx << KGSL_IOMMU_CTX_SHIFT) +		\
-				KGSL_IOMMU_##REG)
+#define KGSL_IOMMU_SET_CTX_REG(iommu, iommu_unit, ctx, REG, val)	\
+		writel_relaxed(val,					\
+		iommu_unit->reg_map.hostptr +				\
+		iommu->iommu_reg_list[KGSL_IOMMU_CTX_##REG].reg_offset +\
+		(ctx << KGSL_IOMMU_CTX_SHIFT) +				\
+		iommu->ctx_offset)
 
-#define KGSL_IOMMU_GET_IOMMU_REG(base_addr, ctx, REG)			\
-		readl_relaxed(base_addr +				\
-			(ctx << KGSL_IOMMU_CTX_SHIFT) +			\
-			KGSL_IOMMU_##REG)
+#define KGSL_IOMMU_GET_CTX_REG(iommu, iommu_unit, ctx, REG)		\
+		readl_relaxed(						\
+		iommu_unit->reg_map.hostptr +				\
+		iommu->iommu_reg_list[KGSL_IOMMU_CTX_##REG].reg_offset +\
+		(ctx << KGSL_IOMMU_CTX_SHIFT) +				\
+		iommu->ctx_offset)
 
 /* Gets the lsb value of pagetable */
-#define KGSL_IOMMMU_PT_LSB(pt_val)					\
-		(pt_val & ~(KGSL_IOMMU_TTBR0_PA_MASK <<			\
-				KGSL_IOMMU_TTBR0_PA_SHIFT))
+#define KGSL_IOMMMU_PT_LSB(iommu, pt_val) \
+	(pt_val &							\
+	~(iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<	\
+	iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift))
 
 /* offset at which a nop command is placed in setstate_memory */
 #define KGSL_IOMMU_SETSTATE_NOP_OFFSET	1024
@@ -99,6 +113,9 @@
  * @clk_event_queued: Indicates whether an event to disable clocks
  * is already queued or not
  * @device: Pointer to kgsl device
+ * @ctx_offset: The context offset to be added to base address when
+ * accessing IOMMU registers
+ * @iommu_reg_list: List of IOMMU registers { offset, map, shift } array
  */
 struct kgsl_iommu {
 	struct kgsl_iommu_unit iommu_units[KGSL_IOMMU_MAX_UNITS];
@@ -106,6 +123,8 @@
 	unsigned int iommu_last_cmd_ts;
 	bool clk_event_queued;
 	struct kgsl_device *device;
+	unsigned int ctx_offset;
+	struct kgsl_iommu_register_list *iommu_reg_list;
 };
 
 /*
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index 8e6c5c0..dee889d 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -18,6 +18,7 @@
 #include <linux/slab.h>
 #include <linux/sched.h>
 #include <linux/iommu.h>
+#include <mach/iommu.h>
 #include <mach/socinfo.h>
 
 #include "kgsl.h"
@@ -325,14 +326,16 @@
 }
 
 int
-kgsl_mmu_get_ptname_from_ptbase(unsigned int pt_base)
+kgsl_mmu_get_ptname_from_ptbase(struct kgsl_mmu *mmu, unsigned int pt_base)
 {
 	struct kgsl_pagetable *pt;
 	int ptid = -1;
 
+	if (!mmu->mmu_ops || !mmu->mmu_ops->mmu_pt_equal)
+		return KGSL_MMU_GLOBAL_PT;
 	spin_lock(&kgsl_driver.ptlock);
 	list_for_each_entry(pt, &kgsl_driver.pagetable_list, list) {
-		if (pt->pt_ops->mmu_pt_equal(pt, pt_base)) {
+		if (mmu->mmu_ops->mmu_pt_equal(mmu, pt, pt_base)) {
 			ptid = (int) pt->name;
 			break;
 		}
@@ -528,6 +531,10 @@
 #ifndef CONFIG_KGSL_PER_PROCESS_PAGE_TABLE
 	name = KGSL_MMU_GLOBAL_PT;
 #endif
+	/* We presently do not support per-process for IOMMU-v2 */
+	if (!msm_soc_version_supports_iommu_v1())
+		name = KGSL_MMU_GLOBAL_PT;
+
 	pt = kgsl_get_pagetable(name);
 
 	if (pt == NULL)
@@ -560,7 +567,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);
@@ -824,3 +831,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 5293d66..234629b 100644
--- a/drivers/gpu/msm/kgsl_mmu.h
+++ b/drivers/gpu/msm/kgsl_mmu.h
@@ -139,8 +139,15 @@
 	int (*mmu_get_pt_lsb)(struct kgsl_mmu *mmu,
 				unsigned int unit_id,
 				enum kgsl_iommu_context_id ctx_id);
-	int (*mmu_get_reg_map_desc)(struct kgsl_mmu *mmu,
-				void **reg_map_desc);
+	unsigned int (*mmu_get_reg_gpuaddr)(struct kgsl_mmu *mmu,
+			int iommu_unit_num, int ctx_id, int reg);
+	int (*mmu_get_num_iommu_units)(struct kgsl_mmu *mmu);
+	int (*mmu_pt_equal) (struct kgsl_mmu *mmu,
+			struct kgsl_pagetable *pt,
+			unsigned int pt_base);
+	unsigned int (*mmu_get_pt_base_addr)
+			(struct kgsl_mmu *mmu,
+			struct kgsl_pagetable *pt);
 };
 
 struct kgsl_mmu_pt_ops {
@@ -153,10 +160,6 @@
 			unsigned int *tlb_flags);
 	void *(*mmu_create_pagetable) (void);
 	void (*mmu_destroy_pagetable) (void *pt);
-	int (*mmu_pt_equal) (struct kgsl_pagetable *pt,
-			unsigned int pt_base);
-	unsigned int (*mmu_pt_get_base_addr)
-			(struct kgsl_pagetable *pt);
 };
 
 struct kgsl_mmu {
@@ -196,7 +199,8 @@
 unsigned int kgsl_virtaddr_to_physaddr(void *virtaddr);
 void kgsl_setstate(struct kgsl_mmu *mmu, unsigned int context_id,
 			uint32_t flags);
-int kgsl_mmu_get_ptname_from_ptbase(unsigned int pt_base);
+int kgsl_mmu_get_ptname_from_ptbase(struct kgsl_mmu *mmu,
+					unsigned int pt_base);
 int kgsl_mmu_pt_get_flags(struct kgsl_pagetable *pt,
 			enum kgsl_deviceid id);
 void kgsl_mmu_ptpool_destroy(void *ptpool);
@@ -205,6 +209,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
@@ -241,28 +246,21 @@
 		mmu->mmu_ops->mmu_stop(mmu);
 }
 
-static inline int kgsl_mmu_pt_equal(struct kgsl_pagetable *pt,
+static inline int kgsl_mmu_pt_equal(struct kgsl_mmu *mmu,
+			struct kgsl_pagetable *pt,
 			unsigned int pt_base)
 {
-	if (KGSL_MMU_TYPE_NONE == kgsl_mmu_get_mmutype())
+	if (mmu->mmu_ops && mmu->mmu_ops->mmu_pt_equal)
+		return mmu->mmu_ops->mmu_pt_equal(mmu, pt, pt_base);
+	else
 		return 1;
-	else
-		return pt->pt_ops->mmu_pt_equal(pt, pt_base);
 }
 
-static inline unsigned int kgsl_mmu_pt_get_base_addr(struct kgsl_pagetable *pt)
+static inline unsigned int kgsl_mmu_get_pt_base_addr(struct kgsl_mmu *mmu,
+						struct kgsl_pagetable *pt)
 {
-	if (KGSL_MMU_TYPE_NONE == kgsl_mmu_get_mmutype())
-		return 0;
-	else
-		return pt->pt_ops->mmu_pt_get_base_addr(pt);
-}
-
-static inline int kgsl_mmu_get_reg_map_desc(struct kgsl_mmu *mmu,
-						void **reg_map_desc)
-{
-	if (mmu->mmu_ops && mmu->mmu_ops->mmu_get_reg_map_desc)
-		return mmu->mmu_ops->mmu_get_reg_map_desc(mmu, reg_map_desc);
+	if (mmu->mmu_ops && mmu->mmu_ops->mmu_get_pt_base_addr)
+		return mmu->mmu_ops->mmu_get_pt_base_addr(mmu, pt);
 	else
 		return 0;
 }
@@ -293,12 +291,6 @@
 		mmu->mmu_ops->mmu_disable_clk_on_ts(mmu, ts, ts_valid);
 }
 
-static inline int kgsl_mmu_gpuaddr_in_range(unsigned int gpuaddr)
-{
-	return ((gpuaddr >= KGSL_PAGETABLE_BASE) &&
-		(gpuaddr < (KGSL_PAGETABLE_BASE + kgsl_mmu_get_ptsize())));
-}
-
 static inline unsigned int kgsl_mmu_get_int_mask(void)
 {
 	/* Dont enable gpummu interrupts, if iommu is enabled */
@@ -309,4 +301,23 @@
 			MH_INTERRUPT_MASK__AXI_WRITE_ERROR);
 }
 
+static inline unsigned int kgsl_mmu_get_reg_gpuaddr(struct kgsl_mmu *mmu,
+							int iommu_unit_num,
+							int ctx_id, int reg)
+{
+	if (mmu->mmu_ops && mmu->mmu_ops->mmu_get_reg_gpuaddr)
+		return mmu->mmu_ops->mmu_get_reg_gpuaddr(mmu, iommu_unit_num,
+							ctx_id, reg);
+	else
+		return 0;
+}
+
+static inline int kgsl_mmu_get_num_iommu_units(struct kgsl_mmu *mmu)
+{
+	if (mmu->mmu_ops && mmu->mmu_ops->mmu_get_num_iommu_units)
+		return mmu->mmu_ops->mmu_get_num_iommu_units(mmu);
+	else
+		return 0;
+}
+
 #endif /* __KGSL_MMU_H */
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 4b5021d..739dcb5 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,73 @@
 {
 	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);
+}
+
+static int kgsl_pwrctrl_gpu_available_frequencies_show(
+					struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	struct kgsl_device *device = kgsl_device_from_dev(dev);
+	struct kgsl_pwrctrl *pwr;
+	int index, num_chars = 0;
+
+	if (device == NULL)
+		return 0;
+	pwr = &device->pwrctrl;
+	for (index = 0; index < pwr->num_pwrlevels - 1; index++)
+		num_chars += snprintf(buf + num_chars, PAGE_SIZE, "%d ",
+		pwr->pwrlevels[index].gpu_freq);
+	buf[num_chars++] = '\n';
+	return num_chars;
+}
+
 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);
+DEVICE_ATTR(gpu_available_frequencies, 0444,
+	kgsl_pwrctrl_gpu_available_frequencies_show,
 	NULL);
 
 static const struct device_attribute *pwrctrl_attr_list[] = {
@@ -310,6 +388,8 @@
 	&dev_attr_pwrnap,
 	&dev_attr_idle_timer,
 	&dev_attr_gpubusy,
+	&dev_attr_gputop,
+	&dev_attr_gpu_available_frequencies,
 	NULL
 };
 
@@ -323,29 +403,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,
@@ -371,22 +459,32 @@
 						clk_unprepare(pwr->grp_clks[i]);
 			}
 			kgsl_pwrctrl_busy_time(device, true);
+		} else if (requested_state == KGSL_STATE_SLEEP) {
+			/* High latency clock maintenance. */
+			if ((pwr->pwrlevels[0].gpu_freq > 0))
+				clk_set_rate(pwr->grp_clks[0],
+					pwr->pwrlevels[pwr->num_pwrlevels - 1].
+					gpu_freq);
+			for (i = KGSL_MAX_CLKS - 1; i > 0; i--)
+				if (pwr->grp_clks[i])
+					clk_unprepare(pwr->grp_clks[i]);
 		}
 	} else if (state == KGSL_PWRFLAGS_ON) {
 		if (!test_and_set_bit(KGSL_PWRFLAGS_CLK_ON,
 			&pwr->power_flags)) {
 			trace_kgsl_clk(device, state);
 			/* High latency clock maintenance. */
-			if ((pwr->pwrlevels[0].gpu_freq > 0) &&
-				(device->state != KGSL_STATE_NAP)) {
+			if (device->state != KGSL_STATE_NAP) {
 				for (i = KGSL_MAX_CLKS - 1; i > 0; i--)
 					if (pwr->grp_clks[i])
 						clk_prepare(pwr->grp_clks[i]);
-				clk_set_rate(pwr->grp_clks[0],
-					pwr->pwrlevels[pwr->active_pwrlevel].
+
+				if (pwr->pwrlevels[0].gpu_freq > 0)
+					clk_set_rate(pwr->grp_clks[0],
+						pwr->pwrlevels
+						[pwr->active_pwrlevel].
 						gpu_freq);
 			}
-
 			/* as last step, enable grp_clk
 			   this is to let GPU interrupt to come */
 			for (i = KGSL_MAX_CLKS - 1; i > 0; i--)
@@ -648,10 +746,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 +852,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);
 }
@@ -761,7 +860,6 @@
 static int
 _sleep(struct kgsl_device *device)
 {
-	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
 	switch (device->state) {
 	case KGSL_STATE_ACTIVE:
 		if (!device->ftbl->isidle(device)) {
@@ -772,10 +870,6 @@
 	case KGSL_STATE_NAP:
 		kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
 		kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_OFF);
-		if (pwr->pwrlevels[0].gpu_freq > 0)
-			clk_set_rate(pwr->grp_clks[0],
-				pwr->pwrlevels[pwr->num_pwrlevels - 1].
-				gpu_freq);
 		_sleep_accounting(device);
 		kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_OFF, KGSL_STATE_SLEEP);
 		kgsl_pwrctrl_set_state(device, KGSL_STATE_SLEEP);
@@ -880,9 +974,8 @@
 		/* Re-enable HW access */
 		mod_timer(&device->idle_timer,
 				jiffies + device->pwrctrl.interval_timeout);
-		if (device->pwrctrl.restore_slumber == false)
-			pm_qos_update_request(&device->pm_qos_req_dma,
-						GPU_SWFI_LATENCY);
+		pm_qos_update_request(&device->pm_qos_req_dma,
+					GPU_SWFI_LATENCY);
 	case KGSL_STATE_ACTIVE:
 		break;
 	default:
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h
index cd44152..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 {
@@ -56,8 +57,8 @@
 	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_msm.c b/drivers/gpu/msm/kgsl_pwrscale_msm.c
index c6f8b1b..879b381 100644
--- a/drivers/gpu/msm/kgsl_pwrscale_msm.c
+++ b/drivers/gpu/msm/kgsl_pwrscale_msm.c
@@ -127,6 +127,28 @@
 	return;
 }
 
+static void msm_remove_io_fraction(struct kgsl_device *device)
+{
+	int i;
+	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
+
+	for (i = 0; i < pwr->num_pwrlevels; i++)
+		pwr->pwrlevels[i].io_fraction = 100;
+
+}
+
+static void msm_restore_io_fraction(struct kgsl_device *device)
+{
+	int i;
+	struct kgsl_device_platform_data *pdata =
+				kgsl_device_get_drvdata(device);
+	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
+
+	for (i = 0; i < pdata->num_levels; i++)
+		pwr->pwrlevels[i].io_fraction =
+			pdata->pwrlevel[i].io_fraction;
+}
+
 static int msm_init(struct kgsl_device *device,
 		     struct kgsl_pwrscale *pwrscale)
 {
@@ -177,6 +199,7 @@
 		} else {
 			priv->gpu_busy = 1;
 		}
+		msm_remove_io_fraction(device);
 		return 0;
 	}
 
@@ -201,6 +224,7 @@
 	msm_dcvs_freq_sink_unregister(&priv->freq_sink);
 	kfree(pwrscale->priv);
 	pwrscale->priv = NULL;
+	msm_restore_io_fraction(device);
 }
 
 struct kgsl_pwrscale_policy kgsl_pwrscale_policy_msm = {
diff --git a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
index 1b029b1..7c2514b 100644
--- a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
+++ b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
@@ -178,15 +178,11 @@
 	priv->no_switch_cnt = 0;
 }
 
+#ifdef CONFIG_MSM_SCM
 static int tz_init(struct kgsl_device *device, struct kgsl_pwrscale *pwrscale)
 {
 	struct tz_priv *priv;
 
-	/* Trustzone is only valid for some SOCs */
-	if (!(cpu_is_msm8x60() || cpu_is_msm8960() || cpu_is_apq8064() ||
-		cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627()))
-		return -EINVAL;
-
 	priv = pwrscale->priv = kzalloc(sizeof(struct tz_priv), GFP_KERNEL);
 	if (pwrscale->priv == NULL)
 		return -ENOMEM;
@@ -197,6 +193,12 @@
 
 	return 0;
 }
+#else
+static int tz_init(struct kgsl_device *device, struct kgsl_pwrscale *pwrscale)
+{
+	return -EINVAL;
+}
+#endif /* CONFIG_MSM_SCM */
 
 static void tz_close(struct kgsl_device *device, struct kgsl_pwrscale *pwrscale)
 {
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index b341485..c2ce5c7 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 = {
@@ -495,6 +510,25 @@
 	struct page **pages = NULL;
 	pgprot_t page_prot = pgprot_writecombine(PAGE_KERNEL);
 	void *ptr;
+	struct sysinfo si;
+
+	/*
+	 * Get the current memory information to be used in deciding if we
+	 * should go ahead with this allocation
+	 */
+
+	si_meminfo(&si);
+
+	/*
+	 * Limit the size of the allocation to the amount of free memory minus
+	 * 32MB. Why 32MB?  Because thats the buffer that page_alloc uses and
+	 * it just seems like a reasonable limit that won't make the OOM killer
+	 * go all serial on us.  Of course, if we are down this low all bets
+	 * are off but above all do no harm.
+	 */
+
+	if (size >= ((si.freeram << PAGE_SHIFT) - SZ_32M))
+		return -ENOMEM;
 
 	/*
 	 * Add guard page to the end of the allocation when the
@@ -666,7 +700,8 @@
 {
 	unsigned int protflags;
 
-	BUG_ON(size == 0);
+	if (size == 0)
+		return -EINVAL;
 
 	protflags = GSL_PT_PAGE_RV;
 	if (!(flags & KGSL_MEMFLAGS_GPUREADONLY))
diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h
index 034ade4..de89ac1 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.h
+++ b/drivers/gpu/msm/kgsl_sharedmem.h
@@ -117,6 +117,8 @@
 		unsigned int physaddr, unsigned int size)
 {
 	memdesc->sg = kgsl_sg_alloc(1);
+	if (memdesc->sg == NULL)
+		return -ENOMEM;
 
 	kmemleak_not_leak(memdesc->sg);
 
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index 824d806..a2ab5b1 100644
--- a/drivers/gpu/msm/kgsl_snapshot.c
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -175,7 +175,8 @@
 	/* Get the current PT base */
 	header->ptbase = kgsl_mmu_get_current_ptbase(&device->mmu);
 	/* And the PID for the task leader */
-	pid = header->pid = kgsl_mmu_get_ptname_from_ptbase(header->ptbase);
+	pid = header->pid = kgsl_mmu_get_ptname_from_ptbase(&device->mmu,
+								header->ptbase);
 
 	task = find_task_by_vpid(pid);
 
@@ -307,7 +308,7 @@
 	struct kgsl_snapshot_object *obj;
 	int offset;
 
-	entry = kgsl_get_mem_entry(ptbase, gpuaddr, size);
+	entry = kgsl_get_mem_entry(device, ptbase, gpuaddr, size);
 
 	if (entry == NULL) {
 		KGSL_DRV_ERR(device, "Unable to find GPU buffer %8.8X\n",
@@ -413,18 +414,24 @@
 int kgsl_snapshot_dump_regs(struct kgsl_device *device, void *snapshot,
 	int remain, void *priv)
 {
+	struct kgsl_snapshot_registers_list *list = priv;
+
 	struct kgsl_snapshot_regs *header = snapshot;
-	struct kgsl_snapshot_registers *regs = priv;
+	struct kgsl_snapshot_registers *regs;
 	unsigned int *data = snapshot + sizeof(*header);
-	int count = 0, i, j;
+	int count = 0, i, j, k;
 
 	/* Figure out how many registers we are going to dump */
 
-	for (i = 0; i < regs->count; i++) {
-		int start = regs->regs[i * 2];
-		int end = regs->regs[i * 2 + 1];
+	for (i = 0; i < list->count; i++) {
+		regs = &(list->registers[i]);
 
-		count += (end - start + 1);
+		for (j = 0; j < regs->count; j++) {
+			int start = regs->regs[j * 2];
+			int end = regs->regs[j * 2 + 1];
+
+			count += (end - start + 1);
+		}
 	}
 
 	if (remain < (count * 8) + sizeof(*header)) {
@@ -432,16 +439,20 @@
 		return 0;
 	}
 
-	for (i = 0; i < regs->count; i++) {
-		unsigned int start = regs->regs[i * 2];
-		unsigned int end = regs->regs[i * 2 + 1];
 
-		for (j = start; j <= end; j++) {
-			unsigned int val;
+	for (i = 0; i < list->count; i++) {
+		regs = &(list->registers[i]);
+		for (j = 0; j < regs->count; j++) {
+			unsigned int start = regs->regs[j * 2];
+			unsigned int end = regs->regs[j * 2 + 1];
 
-			kgsl_regread(device, j, &val);
-			*data++ = j;
-			*data++ = val;
+			for (k = start; k <= end; k++) {
+				unsigned int val;
+
+				kgsl_regread(device, k, &val);
+				*data++ = k;
+				*data++ = val;
+			}
 		}
 	}
 
diff --git a/drivers/gpu/msm/kgsl_snapshot.h b/drivers/gpu/msm/kgsl_snapshot.h
index d54afcf..6d81bcf 100644
--- a/drivers/gpu/msm/kgsl_snapshot.h
+++ b/drivers/gpu/msm/kgsl_snapshot.h
@@ -144,6 +144,7 @@
 #define SNAPSHOT_DEBUG_CP_PFP_RAM 9
 #define SNAPSHOT_DEBUG_CP_ROQ     10
 #define SNAPSHOT_DEBUG_SHADER_MEMORY 11
+#define SNAPSHOT_DEBUG_CP_MERCIU 12
 
 struct kgsl_snapshot_debug {
 	int type;    /* Type identifier for the attached tata */
@@ -240,12 +241,22 @@
 /* A common helper function to dump a range of registers.  This will be used in
  * the GPU specific devices like this:
  *
- * struct kgsl_snapshot_registers priv;
- * priv.regs = registers_array;;
- * priv.count = num_registers;
+ * struct kgsl_snapshot_registers_list list;
+ * struct kgsl_snapshot_registers priv[2];
+ *
+ * priv[0].regs = registers_array;;
+ * priv[o].count = num_registers;
+ * priv[1].regs = registers_array_new;;
+ * priv[1].count = num_registers_new;
+ *
+ * list.registers = priv;
+ * list.count = 2;
  *
  * kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_REGS, snapshot,
- *	remain, kgsl_snapshot_dump_regs, &priv).
+ *	remain, kgsl_snapshot_dump_regs, &list).
+ *
+ * Pass in a struct pointing to a list of register definitions as described
+ * below:
  *
  * Pass in an array of register range pairs in the form of:
  * start reg, stop reg
@@ -257,6 +268,13 @@
 	int count;	     /* Number of entries in the array */
 };
 
+struct kgsl_snapshot_registers_list {
+	/* Pointer to an array of register lists */
+	struct kgsl_snapshot_registers *registers;
+	/* Number of registers lists in the array */
+	int count;
+};
+
 int kgsl_snapshot_dump_regs(struct kgsl_device *device, void *snapshot,
 	int remain, void *priv);
 
diff --git a/drivers/gpu/msm/z180.c b/drivers/gpu/msm/z180.c
index 9037f3c..8ddc991 100644
--- a/drivers/gpu/msm/z180.c
+++ b/drivers/gpu/msm/z180.c
@@ -358,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);
@@ -366,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");
@@ -583,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);
 
@@ -852,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;
diff --git a/drivers/gpu/msm/z180.h b/drivers/gpu/msm/z180.h
index 6e81a9d..a8973d2 100644
--- a/drivers/gpu/msm/z180.h
+++ b/drivers/gpu/msm/z180.h
@@ -28,6 +28,9 @@
 
 #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;
diff --git a/drivers/gpu/msm/z180_postmortem.c b/drivers/gpu/msm/z180_postmortem.c
index a9b0c50..7cf3799 100644
--- a/drivers/gpu/msm/z180_postmortem.c
+++ b/drivers/gpu/msm/z180_postmortem.c
@@ -152,7 +152,8 @@
 
 			ib_gpuptr = rb_hostptr[i+1];
 
-			entry = kgsl_get_mem_entry(pt_base, ib_gpuptr, 1);
+			entry = kgsl_get_mem_entry(device, pt_base, ib_gpuptr,
+							1);
 
 			if (entry == NULL) {
 				KGSL_LOG_DUMP(device,
diff --git a/drivers/hwmon/epm_adc.c b/drivers/hwmon/epm_adc.c
index fd4524e..3969319 100644
--- a/drivers/hwmon/epm_adc.c
+++ b/drivers/hwmon/epm_adc.c
@@ -67,6 +67,42 @@
 #define GPIO_EPM_GLOBAL_ENABLE		86
 #define EPM_ADC_CONVERSION_TIME_MIN	50000
 #define EPM_ADC_CONVERSION_TIME_MAX	51000
+/* PSoc Commands */
+#define EPM_PSOC_INIT_CMD				0x1
+#define EPM_PSOC_INIT_RESPONSE_CMD			0x2
+#define EPM_PSOC_CHANNEL_ENABLE_DISABLE_CMD		0x5
+#define EPM_PSOC_CHANNEL_ENABLE_DISABLE_RESPONSE_CMD	0x6
+#define EPM_PSOC_SET_AVERAGING_CMD			0x7
+#define EPM_PSOC_SET_AVERAGING_RESPONSE_CMD		0x8
+#define EPM_PSOC_GET_LAST_MEASUREMENT_CMD		0x9
+#define EPM_PSOC_GET_LAST_MEASUREMENT_RESPONSE_CMD	0xa
+#define EPM_PSOC_GET_BUFFERED_DATA_CMD			0xb
+#define EPM_PSOC_GET_BUFFERED_RESPONSE_CMD		0xc
+#define EPM_PSOC_GET_SYSTEM_TIMESTAMP_CMD		0x11
+#define EPM_PSOC_GET_SYSTEM_TIMESTAMP_RESPONSE_CMD	0x12
+#define EPM_PSOC_SET_SYSTEM_TIMESTAMP_CMD		0x13
+#define EPM_PSOC_SET_SYSTEM_TIMESTAMP_RESPONSE_CMD	0x14
+#define EPM_PSOC_SET_CHANNEL_TYPE_CMD			0x15
+#define EPM_PSOC_SET_CHANNEL_TYPE_RESPONSE_CMD		0x16
+#define EPM_PSOC_GET_AVERAGED_DATA_CMD			0x19
+#define EPM_PSOC_GET_AVERAGED_DATA_RESPONSE_CMD		0x1a
+#define EPM_PSOC_SET_CHANNEL_SWITCH_DELAY_CMD		0x1b
+#define EPM_PSOC_SET_CHANNEL_SWITCH_DELAY_RESPONSE_CMD	0x1c
+#define EPM_PSOC_CLEAR_BUFFER_CMD			0x1d
+#define EPM_PSOC_CLEAR_BUFFER_RESPONSE_CMD		0x1e
+#define EPM_PSOC_SET_VADC_REFERENCE_CMD			0x1f
+#define EPM_PSOC_SET_VADC_REFERENCE_RESPONSE_CMD	0x20
+
+#define EPM_PSOC_GLOBAL_ENABLE				81
+#define EPM_PSOC_VREF_VOLTAGE				2048
+#define EPM_PSOC_MAX_ADC_CODE_16_BIT			32767
+#define EPM_GLOBAL_ENABLE_MIN_DELAY			5000
+#define EPM_GLOBAL_ENABLE_MAX_DELAY			5100
+
+#define EPM_PSOC_BUFFERED_DATA_LENGTH			48
+#define EPM_PSOC_BUFFERED_DATA_LENGTH2			54
+
+#define EPM_SPI_NOR_CS_N_GPIO		53
 
 struct epm_adc_drv {
 	struct platform_device		*pdev;
@@ -75,6 +111,7 @@
 	struct mutex			conv_lock;
 	uint32_t			bus_id;
 	struct miscdevice		misc;
+	struct epm_chan_properties	epm_psoc_ch_prop[0];
 };
 
 static struct epm_adc_drv *epm_adc_drv;
@@ -135,6 +172,14 @@
 {
 	int rc = 0;
 
+	rc = gpio_request(EPM_SPI_NOR_CS_N_GPIO, "SPI_NOR_CS_N");
+	if (!rc)
+		gpio_direction_output(EPM_SPI_NOR_CS_N_GPIO, 1);
+	else {
+		pr_err("Configure spi nor Failed\n");
+		return -EINVAL;
+	}
+
 	if (epm_adc_first_request) {
 		rc = gpio_request(GPIO_EPM_GLOBAL_ENABLE, "EPM_GLOBAL_EN");
 		if (!rc) {
@@ -210,13 +255,11 @@
 	if (!rc) {
 		rc = gpio_direction_output(GPIO_EPM_SPI_ADC2_CS_N, 1);
 		if (rc) {
-			pr_err("%s: Set GPIO_EPM_SPI_ADC2_CS_N "
-					"failed\n", __func__);
+			pr_err("Set GPIO_EPM_SPI_ADC2_CS_N failed\n");
 			return rc;
 		}
 	} else {
-		pr_err("%s: gpio_request GPIO_EPM_SPI_ADC2_CS_N "
-				"failed\n", __func__);
+		pr_err("gpio_request GPIO_EPM_SPI_ADC2_CS_N failed\n");
 		return rc;
 	}
 
@@ -461,8 +504,7 @@
 	mutex_lock(&epm_adc->conv_lock);
 	rc = epm_adc_gpio_configure_expander_disable();
 	if (rc != 0) {
-		pr_err("epm gpio configure expander disable failed,"
-			" rc = %d\n", rc);
+		pr_err("gpio expander disable failed with %d\n", rc);
 		goto epm_adc_hw_deinit_err;
 	}
 
@@ -479,7 +521,7 @@
 	struct epm_adc_platform_data *pdata = epm_adc->pdev->dev.platform_data;
 	uint32_t chan_idx = (conv->device_idx * pdata->chan_per_adc) +
 					conv->channel_idx;
-	int32_t *adc_scaled_data = &conv->physical;
+	int64_t *adc_scaled_data = 0;
 
 	/* Get the channel number */
 	channel_num = (adc_raw_data[0] & EPM_ADC_ADS_CHANNEL_DATA_CHID);
@@ -489,17 +531,17 @@
 	/* Obtain the internal system reading */
 	if (channel_num == EPM_ADC_ADS_CHANNEL_VCC) {
 		*adc_scaled_data *= EPM_ADC_SCALE_MILLI;
-		*adc_scaled_data /= EPM_ADC_SCALE_CODE_VOLTS;
+		do_div(*adc_scaled_data, EPM_ADC_SCALE_CODE_VOLTS);
 	} else if (channel_num == EPM_ADC_ADS_CHANNEL_GAIN) {
-		*adc_scaled_data /= EPM_ADC_SCALE_CODE_GAIN;
+		do_div(*adc_scaled_data, EPM_ADC_SCALE_CODE_GAIN);
 	} else if (channel_num == EPM_ADC_ADS_CHANNEL_REF) {
 		*adc_scaled_data *= EPM_ADC_SCALE_MILLI;
-		*adc_scaled_data /= EPM_ADC_SCALE_CODE_VOLTS;
+		do_div(*adc_scaled_data, EPM_ADC_SCALE_CODE_VOLTS);
 	} else if (channel_num == EPM_ADC_ADS_CHANNEL_TEMP) {
 		/* Convert Code to micro-volts */
 		/* Use this formula to get the temperature reading */
 		*adc_scaled_data -= EPM_ADC_TEMP_TO_DEGC_COEFF;
-		*adc_scaled_data /= EPM_ADC_TEMP_SENSOR_COEFF;
+		do_div(*adc_scaled_data, EPM_ADC_TEMP_SENSOR_COEFF);
 	} else if (channel_num == EPM_ADC_ADS_CHANNEL_OFFSET) {
 		/* The offset should be zero */
 		pr_debug("%s: ADC Channel Offset\n", __func__);
@@ -508,7 +550,7 @@
 		channel_num -= EPM_ADC_CHANNEL_AIN_OFFSET;
 		/*
 		 * Conversion for the adc channels.
-		 * mvVRef is in milli-volts and resistorValue is in micro-ohms.
+		 * mvVRef is in milli-volts and resistorvalue is in micro-ohms.
 		 * Hence, I = V/R gives us current in kilo-amps.
 		 */
 		if (*adc_scaled_data & EPM_ADC_MAX_NEGATIVE_SCALE_CODE) {
@@ -520,21 +562,35 @@
 			*adc_scaled_data *= EPM_ADC_SCALE_FACTOR;
 			 /* Device is calibrated for 1LSB = VREF/7800h.*/
 			*adc_scaled_data *= EPM_ADC_MILLI_VOLTS_SOURCE;
-			*adc_scaled_data /= EPM_ADC_VREF_CODE;
+			do_div(*adc_scaled_data, EPM_ADC_VREF_CODE);
 			 /* Data will now be in micro-volts.*/
 			*adc_scaled_data *= EPM_ADC_SCALE_MILLI;
 			 /* Divide by amplifier gain value.*/
-			*adc_scaled_data /= pdata->channel[chan_idx].gain;
+			do_div(*adc_scaled_data, pdata->channel[chan_idx].gain);
 			 /* Data will now be in nano-volts.*/
-			*adc_scaled_data /= EPM_ADC_SCALE_FACTOR;
+			do_div(*adc_scaled_data, EPM_ADC_SCALE_FACTOR);
 			*adc_scaled_data *= EPM_ADC_SCALE_MILLI;
 			 /* Data is now in micro-amps.*/
-			*adc_scaled_data /=
-				pdata->channel[chan_idx].resistorValue;
+			do_div(*adc_scaled_data,
+				pdata->channel[chan_idx].resistorvalue);
 			 /* Set the sign bit for lekage current. */
 			*adc_scaled_data *= sign_bit;
 		}
 	}
+	conv->physical = (int32_t) *adc_scaled_data;
+
+	return 0;
+}
+
+static int epm_psoc_scale_result(uint16_t *adc_raw_data, uint32_t index)
+{
+	struct epm_adc_drv *epm_adc = epm_adc_drv;
+	/* result = 2.048V/(32767 * gain * rsense) */
+	*adc_raw_data = (EPM_PSOC_VREF_VOLTAGE/EPM_PSOC_MAX_ADC_CODE_16_BIT)
+				* (*adc_raw_data);
+	*adc_raw_data = *adc_raw_data/
+		(epm_adc->epm_psoc_ch_prop[index].gain *
+			epm_adc->epm_psoc_ch_prop[index].resistorvalue);
 	return 0;
 }
 
@@ -608,6 +664,465 @@
 	return rc;
 }
 
+static int epm_adc_psoc_gpio_init(bool enable)
+{
+	int rc = 0;
+
+	if (enable) {
+		rc = gpio_request(EPM_PSOC_GLOBAL_ENABLE, "EPM_PSOC_GLOBAL_EN");
+		if (!rc) {
+			gpio_direction_output(EPM_PSOC_GLOBAL_ENABLE, 1);
+		} else {
+			pr_err("%s: Configure EPM_GLOBAL_EN Failed\n",
+								__func__);
+			return rc;
+		}
+	} else {
+		gpio_direction_output(EPM_PSOC_GLOBAL_ENABLE, 0);
+		gpio_free(EPM_PSOC_GLOBAL_ENABLE);
+	}
+
+	return 0;
+}
+
+static int epm_psoc_init(struct epm_adc_drv *epm_adc,
+					struct epm_psoc_init_resp *init_resp)
+{
+	struct spi_message m;
+	struct spi_transfer t;
+	char tx_buf[17], rx_buf[17];
+	int rc = 0;
+
+	spi_setup(epm_adc->epm_spi_client);
+
+	memset(&t, 0, sizeof t);
+	memset(tx_buf, 0, sizeof tx_buf);
+	memset(rx_buf, 0, sizeof tx_buf);
+	t.tx_buf = tx_buf;
+	t.rx_buf = rx_buf;
+	spi_message_init(&m);
+	spi_message_add_tail(&t, &m);
+
+	tx_buf[0] = init_resp->cmd;
+
+	t.len = sizeof(tx_buf);
+	t.bits_per_word = EPM_ADC_ADS_SPI_BITS_PER_WORD;
+
+	rc = spi_sync(epm_adc->epm_spi_client, &m);
+	if (rc)
+		return rc;
+
+	init_resp->cmd			= rx_buf[0];
+	init_resp->version		= rx_buf[1];
+	init_resp->compatible_ver	= rx_buf[2];
+	init_resp->firm_ver[0]		= rx_buf[3];
+	init_resp->firm_ver[1]		= rx_buf[4];
+	init_resp->firm_ver[2]		= rx_buf[5];
+	init_resp->num_dev		= rx_buf[6];
+	init_resp->num_channel		= rx_buf[7];
+
+	return rc;
+}
+
+static int epm_psoc_channel_configure(struct epm_adc_drv *epm_adc,
+		struct epm_psoc_channel_configure *psoc_chan_configure)
+{
+	struct spi_message m;
+	struct spi_transfer t;
+	char tx_buf[9], rx_buf[9];
+	int32_t rc = 0, chan_num;
+
+	spi_setup(epm_adc->epm_spi_client);
+
+	memset(&t, 0, sizeof t);
+	memset(tx_buf, 0, sizeof tx_buf);
+	memset(rx_buf, 0, sizeof tx_buf);
+	t.tx_buf = tx_buf;
+	t.rx_buf = rx_buf;
+	spi_message_init(&m);
+	spi_message_add_tail(&t, &m);
+
+	chan_num = psoc_chan_configure->channel_num;
+
+	tx_buf[0] = psoc_chan_configure->cmd;
+	tx_buf[1] = 0;
+	tx_buf[2] = (chan_num & 0xff000000) >> 24;
+	tx_buf[3] = (chan_num & 0xff0000) >> 16;
+	tx_buf[4] = (chan_num & 0xff00) >> 8;
+	tx_buf[5] = (chan_num & 0xff);
+
+	t.len = sizeof(tx_buf);
+	t.bits_per_word = EPM_ADC_ADS_SPI_BITS_PER_WORD;
+
+	rc = spi_sync(epm_adc->epm_spi_client, &m);
+	if (rc)
+		return rc;
+
+	rc = spi_sync(epm_adc->epm_spi_client, &m);
+	if (rc)
+		return rc;
+
+	psoc_chan_configure->cmd		= rx_buf[0];
+	psoc_chan_configure->device_num		= rx_buf[1];
+	chan_num = rx_buf[2] << 24 | (rx_buf[3] << 16) | (rx_buf[4] << 8) |
+						rx_buf[5];
+	psoc_chan_configure->channel_num	= chan_num;
+	pr_debug("dev_num:%d, chan_num:%d\n", rx_buf[1], chan_num);
+
+	return rc;
+}
+
+static int epm_psoc_set_averaging(struct epm_adc_drv *epm_adc,
+		struct epm_psoc_set_avg *psoc_set_avg)
+{
+	struct spi_message m;
+	struct spi_transfer t;
+	char tx_buf[4], rx_buf[4];
+	int rc = 0;
+
+	spi_setup(epm_adc->epm_spi_client);
+
+	memset(&t, 0, sizeof t);
+	memset(tx_buf, 0, sizeof tx_buf);
+	memset(rx_buf, 0, sizeof tx_buf);
+	t.tx_buf = tx_buf;
+	t.rx_buf = rx_buf;
+	spi_message_init(&m);
+	spi_message_add_tail(&t, &m);
+
+	tx_buf[0] = psoc_set_avg->cmd;
+	tx_buf[1] = psoc_set_avg->avg_period;
+
+	t.len = sizeof(tx_buf);
+	t.bits_per_word = EPM_ADC_ADS_SPI_BITS_PER_WORD;
+
+	rc = spi_sync(epm_adc->epm_spi_client, &m);
+	if (rc)
+		return rc;
+
+	rc = spi_sync(epm_adc->epm_spi_client, &m);
+	if (rc)
+		return rc;
+
+	psoc_set_avg->cmd		= rx_buf[0];
+	psoc_set_avg->return_code	= rx_buf[1];
+
+	return rc;
+}
+
+static int epm_psoc_get_data(struct epm_adc_drv *epm_adc,
+		struct epm_psoc_get_data *psoc_get_meas)
+{
+	struct spi_message m;
+	struct spi_transfer t;
+	char tx_buf[10], rx_buf[10];
+	int rc = 0;
+
+	spi_setup(epm_adc->epm_spi_client);
+
+	memset(&t, 0, sizeof t);
+	memset(tx_buf, 0, sizeof tx_buf);
+	memset(rx_buf, 0, sizeof tx_buf);
+	t.tx_buf = tx_buf;
+	t.rx_buf = rx_buf;
+	spi_message_init(&m);
+	spi_message_add_tail(&t, &m);
+
+	tx_buf[0] = psoc_get_meas->cmd;
+	tx_buf[1] = psoc_get_meas->dev_num;
+	tx_buf[2] = psoc_get_meas->chan_num;
+
+	t.len = sizeof(tx_buf);
+	t.bits_per_word = EPM_ADC_ADS_SPI_BITS_PER_WORD;
+
+	rc = spi_sync(epm_adc->epm_spi_client, &m);
+	if (rc)
+		return rc;
+
+	rc = spi_sync(epm_adc->epm_spi_client, &m);
+	if (rc)
+		return rc;
+
+	psoc_get_meas->cmd		= rx_buf[0];
+	psoc_get_meas->dev_num		= rx_buf[1];
+	psoc_get_meas->chan_num		= rx_buf[2];
+	psoc_get_meas->timestamp_resp_value = (rx_buf[3] << 24) |
+			(rx_buf[4] << 16) | (rx_buf[5] << 8) |
+			rx_buf[6];
+	psoc_get_meas->reading_value = (rx_buf[7] << 8) | rx_buf[8];
+
+	pr_debug("dev_num:%d, chan_num:%d\n", rx_buf[1], rx_buf[2]);
+	pr_debug("data %d\n", psoc_get_meas->reading_value);
+	return rc;
+}
+
+static int epm_psoc_get_buffered_data(struct epm_adc_drv *epm_adc,
+		struct epm_psoc_get_buffered_data *psoc_get_meas)
+{
+	struct spi_message m;
+	struct spi_transfer t;
+	char tx_buf[64], rx_buf[64];
+	int rc = 0, i;
+
+	spi_setup(epm_adc->epm_spi_client);
+
+	memset(&t, 0, sizeof t);
+	memset(tx_buf, 0, sizeof tx_buf);
+	memset(rx_buf, 0, sizeof tx_buf);
+	t.tx_buf = tx_buf;
+	t.rx_buf = rx_buf;
+	spi_message_init(&m);
+	spi_message_add_tail(&t, &m);
+
+	tx_buf[0] = psoc_get_meas->cmd;
+
+	t.len = sizeof(tx_buf);
+	t.bits_per_word = EPM_ADC_ADS_SPI_BITS_PER_WORD;
+
+	rc = spi_sync(epm_adc->epm_spi_client, &m);
+	if (rc)
+		return rc;
+
+	rc = spi_sync(epm_adc->epm_spi_client, &m);
+	if (rc)
+		return rc;
+
+	psoc_get_meas->cmd		= rx_buf[0];
+	psoc_get_meas->dev_num		= rx_buf[1];
+	psoc_get_meas->status_mask	= rx_buf[2];
+	psoc_get_meas->chan_idx		= rx_buf[3];
+	psoc_get_meas->chan_mask	= (rx_buf[4] << 24 |
+		rx_buf[5] << 16 | rx_buf[6] << 8
+			| rx_buf[7]);
+	psoc_get_meas->timestamp_start	= (rx_buf[8] << 24 |
+			rx_buf[9] << 16 | rx_buf[10] << 8
+			| rx_buf[11]);
+	psoc_get_meas->timestamp_end	= (rx_buf[12] << 24 |
+			rx_buf[13] << 16 | rx_buf[14] << 8
+			| rx_buf[15]);
+
+	for (i = 0; i < EPM_PSOC_BUFFERED_DATA_LENGTH; i++)
+		psoc_get_meas->buff_data[i] = rx_buf[16 + i];
+
+	return rc;
+}
+
+static int epm_psoc_timestamp(struct epm_adc_drv *epm_adc,
+		struct epm_psoc_system_time_stamp *psoc_timestamp)
+{
+	struct spi_message m;
+	struct spi_transfer t;
+	char tx_buf[10], rx_buf[10];
+	int rc = 0;
+
+	spi_setup(epm_adc->epm_spi_client);
+
+	memset(&t, 0, sizeof t);
+	memset(tx_buf, 0, sizeof tx_buf);
+	memset(rx_buf, 0, sizeof tx_buf);
+	t.tx_buf = tx_buf;
+	t.rx_buf = rx_buf;
+	spi_message_init(&m);
+	spi_message_add_tail(&t, &m);
+
+	if (psoc_timestamp->cmd == EPM_PSOC_SET_SYSTEM_TIMESTAMP_CMD) {
+		tx_buf[0] = psoc_timestamp->cmd;
+		tx_buf[1] = (psoc_timestamp->timestamp & 0xff000000) >> 24;
+		tx_buf[2] = (psoc_timestamp->timestamp & 0xff0000) >> 16;
+		tx_buf[3] = (psoc_timestamp->timestamp & 0xff00) >> 8;
+		tx_buf[4] = (psoc_timestamp->timestamp & 0xff);
+	} else if (psoc_timestamp->cmd == EPM_PSOC_GET_SYSTEM_TIMESTAMP_CMD) {
+		tx_buf[0] = psoc_timestamp->cmd;
+	}
+
+	t.len = sizeof(tx_buf);
+	t.bits_per_word = EPM_ADC_ADS_SPI_BITS_PER_WORD;
+
+	rc = spi_sync(epm_adc->epm_spi_client, &m);
+	if (rc)
+		return rc;
+
+	rc = spi_sync(epm_adc->epm_spi_client, &m);
+	if (rc)
+		return rc;
+
+	psoc_timestamp->cmd		= rx_buf[0];
+	psoc_timestamp->timestamp = rx_buf[1] << 24 | rx_buf[2] << 16 |
+					rx_buf[3] << 8 | rx_buf[4];
+
+	return rc;
+}
+
+static int epm_psoc_get_avg_buffered_switch_data(struct epm_adc_drv *epm_adc,
+		struct epm_psoc_get_avg_buffered_switch_data *psoc_get_meas)
+{
+	struct spi_message m;
+	struct spi_transfer t;
+	char tx_buf[64], rx_buf[64];
+	int rc = 0, i;
+
+	spi_setup(epm_adc->epm_spi_client);
+
+	memset(&t, 0, sizeof t);
+	memset(tx_buf, 0, sizeof tx_buf);
+	memset(rx_buf, 0, sizeof tx_buf);
+	t.tx_buf = tx_buf;
+	t.rx_buf = rx_buf;
+	spi_message_init(&m);
+	spi_message_add_tail(&t, &m);
+
+	tx_buf[0] = psoc_get_meas->cmd;
+
+	t.len = sizeof(tx_buf);
+	t.bits_per_word = EPM_ADC_ADS_SPI_BITS_PER_WORD;
+
+	rc = spi_sync(epm_adc->epm_spi_client, &m);
+	if (rc)
+		return rc;
+
+	rc = spi_sync(epm_adc->epm_spi_client, &m);
+	if (rc)
+		return rc;
+
+	psoc_get_meas->cmd		= rx_buf[0];
+	psoc_get_meas->status		= rx_buf[1];
+	psoc_get_meas->timestamp_start	= (rx_buf[2] << 24 |
+			rx_buf[3] << 16 | rx_buf[4] << 8
+			| rx_buf[5]);
+	psoc_get_meas->channel_mask	= (rx_buf[6] << 24 |
+		rx_buf[7] << 16 | rx_buf[8] << 8
+			| rx_buf[9]);
+
+	for (i = 0; i < EPM_PSOC_BUFFERED_DATA_LENGTH2; i++)
+		psoc_get_meas->avg_data[i] = rx_buf[10 + i];
+
+	return rc;
+}
+
+static int epm_psoc_set_vadc(struct epm_adc_drv *epm_adc,
+		struct epm_psoc_set_vadc *psoc_set_vadc)
+{
+	struct spi_message m;
+	struct spi_transfer t;
+	char tx_buf[10], rx_buf[10];
+	int rc = 0;
+
+	spi_setup(epm_adc->epm_spi_client);
+
+	memset(&t, 0, sizeof t);
+	memset(tx_buf, 0, sizeof tx_buf);
+	memset(rx_buf, 0, sizeof tx_buf);
+	t.tx_buf = tx_buf;
+	t.rx_buf = rx_buf;
+	spi_message_init(&m);
+	spi_message_add_tail(&t, &m);
+
+	tx_buf[0] = psoc_set_vadc->cmd;
+	tx_buf[1] = psoc_set_vadc->vadc_dev;
+	tx_buf[2] = (psoc_set_vadc->vadc_voltage & 0xff000000) >> 24;
+	tx_buf[3] = (psoc_set_vadc->vadc_voltage & 0xff0000) >> 16;
+	tx_buf[4] = (psoc_set_vadc->vadc_voltage & 0xff00) >> 8;
+	tx_buf[5] = psoc_set_vadc->vadc_voltage & 0xff;
+
+	t.len = sizeof(tx_buf);
+	t.bits_per_word = EPM_ADC_ADS_SPI_BITS_PER_WORD;
+
+	rc = spi_sync(epm_adc->epm_spi_client, &m);
+	if (rc)
+		return rc;
+
+	rc = spi_sync(epm_adc->epm_spi_client, &m);
+	if (rc)
+		return rc;
+
+	psoc_set_vadc->cmd		= rx_buf[0];
+	psoc_set_vadc->vadc_dev		= rx_buf[1];
+	psoc_set_vadc->vadc_voltage = (rx_buf[2] << 24) | (rx_buf[3] << 16) |
+					(rx_buf[4] << 8) | (rx_buf[5]);
+
+	return rc;
+}
+
+static int epm_psoc_set_channel_switch(struct epm_adc_drv *epm_adc,
+		struct epm_psoc_set_channel_switch *psoc_channel_switch)
+{
+	struct spi_message m;
+	struct spi_transfer t;
+	char tx_buf[10], rx_buf[10];
+	int rc = 0;
+
+	spi_setup(epm_adc->epm_spi_client);
+
+	memset(&t, 0, sizeof t);
+	memset(tx_buf, 0, sizeof tx_buf);
+	memset(rx_buf, 0, sizeof tx_buf);
+	t.tx_buf = tx_buf;
+	t.rx_buf = rx_buf;
+	spi_message_init(&m);
+	spi_message_add_tail(&t, &m);
+
+	tx_buf[0] = psoc_channel_switch->cmd;
+	tx_buf[1] = psoc_channel_switch->dev;
+	tx_buf[2] = (psoc_channel_switch->delay & 0xff000000) >> 24;
+	tx_buf[3] = (psoc_channel_switch->delay & 0xff0000) >> 16;
+	tx_buf[4] = (psoc_channel_switch->delay & 0xff00) >> 8;
+	tx_buf[5] = psoc_channel_switch->delay & 0xff;
+
+	t.len = sizeof(tx_buf);
+	t.bits_per_word = EPM_ADC_ADS_SPI_BITS_PER_WORD;
+
+	rc = spi_sync(epm_adc->epm_spi_client, &m);
+	if (rc)
+		return rc;
+
+	rc = spi_sync(epm_adc->epm_spi_client, &m);
+	if (rc)
+		return rc;
+
+	psoc_channel_switch->cmd		= rx_buf[0];
+	psoc_channel_switch->dev		= rx_buf[1];
+	psoc_channel_switch->delay		= rx_buf[2] << 24 |
+					rx_buf[3] << 16 |
+					rx_buf[4] << 8 | rx_buf[5];
+
+	return rc;
+}
+
+static int epm_psoc_clear_buffer(struct epm_adc_drv *epm_adc)
+{
+	struct spi_message m;
+	struct spi_transfer t;
+	char tx_buf[3], rx_buf[3];
+	int rc = 0;
+
+	spi_setup(epm_adc->epm_spi_client);
+
+	memset(&t, 0, sizeof t);
+	memset(tx_buf, 0, sizeof tx_buf);
+	memset(rx_buf, 0, sizeof tx_buf);
+	t.tx_buf = tx_buf;
+	t.rx_buf = rx_buf;
+	spi_message_init(&m);
+	spi_message_add_tail(&t, &m);
+
+	tx_buf[0] = EPM_PSOC_CLEAR_BUFFER_CMD;
+
+	t.len = sizeof(tx_buf);
+	t.bits_per_word = EPM_ADC_ADS_SPI_BITS_PER_WORD;
+
+	rc = spi_sync(epm_adc->epm_spi_client, &m);
+	if (rc)
+		return rc;
+
+	rc = spi_sync(epm_adc->epm_spi_client, &m);
+	if (rc)
+		return rc;
+
+	rc = rx_buf[2];
+
+	return rc;
+}
+
 static long epm_adc_ioctl(struct file *file, unsigned int cmd,
 						unsigned long arg)
 {
@@ -647,7 +1162,7 @@
 				epm_adc_expander_register = true;
 			}
 
-			result = epm_adc_hw_init(epm_adc_drv);
+			result = epm_adc_hw_init(epm_adc);
 
 			if (copy_to_user((void __user *)arg, &result,
 						sizeof(uint32_t)))
@@ -657,13 +1172,232 @@
 	case EPM_ADC_DEINIT:
 		{
 			uint32_t result;
-			result = epm_adc_hw_deinit(epm_adc_drv);
+			result = epm_adc_hw_deinit(epm_adc);
 
 			if (copy_to_user((void __user *)arg, &result,
 						sizeof(uint32_t)))
 				return -EFAULT;
 			break;
 		}
+	case EPM_PSOC_ADC_INIT:
+		{
+			struct epm_psoc_init_resp psoc_init;
+			int rc;
+
+			if (copy_from_user(&psoc_init, (void __user *)arg,
+					sizeof(struct epm_psoc_init_resp)))
+				return -EFAULT;
+
+			psoc_init.cmd = EPM_PSOC_INIT_CMD;
+			rc = epm_psoc_init(epm_adc, &psoc_init);
+			if (rc) {
+				pr_err("PSOC initialization failed\n");
+				return -EINVAL;
+			}
+
+			if (copy_to_user((void __user *)arg, &psoc_init,
+				sizeof(struct epm_psoc_init_resp)))
+				return -EFAULT;
+			break;
+		}
+	case EPM_PSOC_ADC_CHANNEL_ENABLE:
+	case EPM_PSOC_ADC_CHANNEL_DISABLE:
+		{
+			struct epm_psoc_channel_configure psoc_chan_configure;
+			int rc;
+
+			if (copy_from_user(&psoc_chan_configure,
+				(void __user *)arg,
+				sizeof(struct epm_psoc_channel_configure)))
+				return -EFAULT;
+
+			psoc_chan_configure.cmd =
+					EPM_PSOC_CHANNEL_ENABLE_DISABLE_CMD;
+			rc = epm_psoc_channel_configure(epm_adc,
+							&psoc_chan_configure);
+			if (rc) {
+				pr_err("PSOC channel configure failed\n");
+				return -EINVAL;
+			}
+
+			if (copy_to_user((void __user *)arg,
+				&psoc_chan_configure,
+				sizeof(struct epm_psoc_channel_configure)))
+				return -EFAULT;
+			break;
+		}
+	case EPM_PSOC_ADC_SET_AVERAGING:
+		{
+			struct epm_psoc_set_avg psoc_set_avg;
+			int rc;
+
+			if (copy_from_user(&psoc_set_avg, (void __user *)arg,
+					sizeof(struct epm_psoc_set_avg)))
+				return -EFAULT;
+
+			psoc_set_avg.cmd = EPM_PSOC_SET_AVERAGING_CMD;
+			rc = epm_psoc_set_averaging(epm_adc, &psoc_set_avg);
+			if (rc) {
+				pr_err("PSOC averaging failed\n");
+				return -EINVAL;
+			}
+
+			if (copy_to_user((void __user *)arg, &psoc_set_avg,
+					sizeof(struct epm_psoc_set_avg)))
+				return -EFAULT;
+			break;
+		}
+	case EPM_PSOC_ADC_GET_LAST_MEASUREMENT:
+		{
+			struct epm_psoc_get_data psoc_get_data;
+			int rc;
+
+			if (copy_from_user(&psoc_get_data,
+					(void __user *)arg,
+					sizeof(struct epm_psoc_get_data)))
+				return -EFAULT;
+
+			psoc_get_data.cmd = EPM_PSOC_GET_LAST_MEASUREMENT_CMD;
+			rc = epm_psoc_get_data(epm_adc, &psoc_get_data);
+			if (rc) {
+				pr_err("PSOC last measured data failed\n");
+				return -EINVAL;
+			}
+
+			if (copy_to_user((void __user *)arg, &psoc_get_data,
+				sizeof(struct epm_psoc_get_data)))
+				return -EFAULT;
+			break;
+		}
+	case EPM_PSOC_ADC_GET_BUFFERED_DATA:
+		{
+			struct epm_psoc_get_buffered_data psoc_get_data;
+			int rc;
+
+			if (copy_from_user(&psoc_get_data,
+				(void __user *)arg,
+				sizeof(struct epm_psoc_get_buffered_data)))
+				return -EFAULT;
+
+			psoc_get_data.cmd = EPM_PSOC_GET_BUFFERED_DATA_CMD;
+			rc = epm_psoc_get_buffered_data(epm_adc,
+								&psoc_get_data);
+			if (rc) {
+				pr_err("PSOC buffered measurement failed\n");
+				return -EINVAL;
+			}
+
+			if (copy_to_user((void __user *)arg, &psoc_get_data,
+				sizeof(struct epm_psoc_get_buffered_data)))
+				return -EFAULT;
+			break;
+		}
+	case EPM_PSOC_ADC_GET_SYSTEM_TIMESTAMP:
+	case EPM_PSOC_ADC_SET_SYSTEM_TIMESTAMP:
+		{
+			struct epm_psoc_system_time_stamp psoc_timestamp;
+			int rc;
+
+			if (copy_from_user(&psoc_timestamp,
+				(void __user *)arg,
+				sizeof(struct epm_psoc_system_time_stamp)))
+				return -EFAULT;
+
+			rc = epm_psoc_timestamp(epm_adc, &psoc_timestamp);
+			if (rc) {
+				pr_err("PSOC buffered measurement failed\n");
+				return -EINVAL;
+			}
+
+			if (copy_to_user((void __user *)arg, &psoc_timestamp,
+				sizeof(struct epm_psoc_system_time_stamp)))
+				return -EFAULT;
+			break;
+		}
+	case EPM_PSOC_ADC_GET_AVERAGE_DATA:
+		{
+			struct epm_psoc_get_avg_buffered_switch_data
+								psoc_get_data;
+			int rc;
+
+			if (copy_from_user(&psoc_get_data,
+				(void __user *)arg,
+				sizeof(struct
+				epm_psoc_get_avg_buffered_switch_data)))
+				return -EFAULT;
+
+			psoc_get_data.cmd = EPM_PSOC_GET_AVERAGED_DATA_CMD;
+			rc = epm_psoc_get_avg_buffered_switch_data(epm_adc,
+								&psoc_get_data);
+			if (rc) {
+				pr_err("Get averaged buffered data failed\n");
+				return -EINVAL;
+			}
+
+			if (copy_to_user((void __user *)arg, &psoc_get_data,
+				sizeof(struct
+				epm_psoc_get_avg_buffered_switch_data)))
+				return -EFAULT;
+			break;
+		}
+	case EPM_PSOC_SET_CHANNEL_SWITCH:
+		{
+			struct epm_psoc_set_channel_switch psoc_channel_switch;
+			int rc;
+
+			if (copy_from_user(&psoc_channel_switch,
+				(void __user *)arg,
+				sizeof(struct epm_psoc_set_channel_switch)))
+				return -EFAULT;
+
+			rc = epm_psoc_set_channel_switch(epm_adc,
+						&psoc_channel_switch);
+			if (rc) {
+				pr_err("PSOC channel switch failed\n");
+				return -EINVAL;
+			}
+
+			if (copy_to_user((void __user *)arg,
+				&psoc_channel_switch,
+				sizeof(struct epm_psoc_set_channel_switch)))
+				return -EFAULT;
+			break;
+		}
+	case EPM_PSOC_CLEAR_BUFFER:
+		{
+			int rc;
+			rc = epm_psoc_clear_buffer(epm_adc);
+			if (rc) {
+				pr_err("PSOC clear buffer failed\n");
+				return -EINVAL;
+			}
+
+			if (copy_to_user((void __user *)arg, &rc,
+						sizeof(uint32_t)))
+				return -EFAULT;
+			break;
+		}
+	case EPM_PSOC_ADC_SET_VADC_REFERENCE:
+		{
+			struct epm_psoc_set_vadc psoc_set_vadc;
+			int rc;
+
+			if (copy_from_user(&psoc_set_vadc,
+					(void __user *)arg,
+					sizeof(struct epm_psoc_set_vadc)))
+				return -EFAULT;
+
+			rc = epm_psoc_set_vadc(epm_adc, &psoc_set_vadc);
+			if (rc) {
+				pr_err("PSOC set VADC failed\n");
+				return -EINVAL;
+			}
+
+			if (copy_to_user((void __user *)arg, &psoc_set_vadc,
+				sizeof(struct epm_psoc_set_vadc)))
+				return -EFAULT;
+			break;
+		}
 	default:
 		return -EINVAL;
 	}
@@ -675,6 +1409,252 @@
 	.unlocked_ioctl = epm_adc_ioctl,
 };
 
+static ssize_t epm_adc_psoc_show_in(struct device *dev,
+				 struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct epm_adc_drv *epm_adc = epm_adc_drv;
+	struct epm_psoc_init_resp init_resp;
+	struct epm_psoc_channel_configure psoc_chan_configure;
+	struct epm_psoc_get_data psoc_get_meas;
+	int16_t *adc_code = 0;
+	int rc = 0;
+
+	rc = epm_adc_psoc_gpio_init(true);
+	if (rc) {
+		pr_err("GPIO init failed\n");
+		return 0;
+	}
+	usleep_range(EPM_GLOBAL_ENABLE_MIN_DELAY,
+				EPM_GLOBAL_ENABLE_MAX_DELAY);
+
+	init_resp.cmd = EPM_PSOC_INIT_CMD;
+	rc = epm_psoc_init(epm_adc, &init_resp);
+	if (rc) {
+		pr_info("PSOC init failed %d\n", rc);
+		return 0;
+	}
+
+	psoc_chan_configure.channel_num = (1 << attr->index);
+	psoc_chan_configure.cmd = EPM_PSOC_CHANNEL_ENABLE_DISABLE_CMD;
+	rc = epm_psoc_channel_configure(epm_adc, &psoc_chan_configure);
+	if (rc) {
+		pr_info("PSOC channel configure failed\n");
+		return 0;
+	}
+
+	usleep_range(EPM_GLOBAL_ENABLE_MIN_DELAY,
+				EPM_GLOBAL_ENABLE_MAX_DELAY);
+
+	psoc_get_meas.cmd = EPM_PSOC_GET_LAST_MEASUREMENT_CMD;
+	psoc_get_meas.dev_num = 0;
+	psoc_get_meas.chan_num = attr->index;
+	rc = epm_psoc_get_data(epm_adc, &psoc_get_meas);
+	if (rc) {
+		pr_info("PSOC get data failed\n");
+		return 0;
+	}
+
+	*adc_code = psoc_get_meas.reading_value;
+
+	rc = epm_psoc_scale_result(adc_code,
+			psoc_chan_configure.channel_num);
+	if (rc) {
+		pr_info("Scale result failed\n");
+		return 0;
+	}
+
+	psoc_get_meas.reading_value = *adc_code;
+
+	rc = epm_adc_psoc_gpio_init(false);
+	if (rc) {
+		pr_err("GPIO de-init failed\n");
+		return 0;
+	}
+
+	return snprintf(buf, 16, "Result: %d\n", psoc_get_meas.reading_value);
+}
+
+static struct sensor_device_attribute epm_adc_psoc_in_attrs[] = {
+	SENSOR_ATTR(ads0_chan0,  S_IRUGO, epm_adc_psoc_show_in, NULL, 0),
+	SENSOR_ATTR(ads0_chan1,  S_IRUGO, epm_adc_psoc_show_in, NULL, 1),
+	SENSOR_ATTR(ads0_chan2,  S_IRUGO, epm_adc_psoc_show_in, NULL, 2),
+	SENSOR_ATTR(ads0_chan3,  S_IRUGO, epm_adc_psoc_show_in, NULL, 3),
+	SENSOR_ATTR(ads0_chan4,  S_IRUGO, epm_adc_psoc_show_in, NULL, 4),
+	SENSOR_ATTR(ads0_chan5,  S_IRUGO, epm_adc_psoc_show_in, NULL, 5),
+	SENSOR_ATTR(ads0_chan6,  S_IRUGO, epm_adc_psoc_show_in, NULL, 6),
+	SENSOR_ATTR(ads0_chan7,  S_IRUGO, epm_adc_psoc_show_in, NULL, 7),
+	SENSOR_ATTR(ads0_chan8,  S_IRUGO, epm_adc_psoc_show_in, NULL, 8),
+	SENSOR_ATTR(ads0_chan9,  S_IRUGO, epm_adc_psoc_show_in, NULL, 9),
+	SENSOR_ATTR(ads0_chan10, S_IRUGO, epm_adc_psoc_show_in, NULL, 10),
+	SENSOR_ATTR(ads0_chan11, S_IRUGO, epm_adc_psoc_show_in, NULL, 11),
+	SENSOR_ATTR(ads0_chan12, S_IRUGO, epm_adc_psoc_show_in, NULL, 12),
+	SENSOR_ATTR(ads0_chan13, S_IRUGO, epm_adc_psoc_show_in, NULL, 13),
+	SENSOR_ATTR(ads0_chan14, S_IRUGO, epm_adc_psoc_show_in, NULL, 14),
+	SENSOR_ATTR(ads0_chan15, S_IRUGO, epm_adc_psoc_show_in, NULL, 15),
+	SENSOR_ATTR(ads1_chan0,  S_IRUGO, epm_adc_psoc_show_in, NULL, 16),
+	SENSOR_ATTR(ads1_chan1,  S_IRUGO, epm_adc_psoc_show_in, NULL, 17),
+	SENSOR_ATTR(ads1_chan2,  S_IRUGO, epm_adc_psoc_show_in, NULL, 18),
+	SENSOR_ATTR(ads1_chan3,  S_IRUGO, epm_adc_psoc_show_in, NULL, 19),
+	SENSOR_ATTR(ads1_chan4,  S_IRUGO, epm_adc_psoc_show_in, NULL, 20),
+	SENSOR_ATTR(ads1_chan5,  S_IRUGO, epm_adc_psoc_show_in, NULL, 21),
+	SENSOR_ATTR(ads1_chan6,  S_IRUGO, epm_adc_psoc_show_in, NULL, 22),
+	SENSOR_ATTR(ads1_chan7,  S_IRUGO, epm_adc_psoc_show_in, NULL, 23),
+	SENSOR_ATTR(ads1_chan8,  S_IRUGO, epm_adc_psoc_show_in, NULL, 24),
+	SENSOR_ATTR(ads1_chan9,  S_IRUGO, epm_adc_psoc_show_in, NULL, 25),
+	SENSOR_ATTR(ads1_chan10, S_IRUGO, epm_adc_psoc_show_in, NULL, 26),
+	SENSOR_ATTR(ads1_chan11, S_IRUGO, epm_adc_psoc_show_in, NULL, 27),
+	SENSOR_ATTR(ads1_chan12, S_IRUGO, epm_adc_psoc_show_in, NULL, 28),
+	SENSOR_ATTR(ads1_chan13, S_IRUGO, epm_adc_psoc_show_in, NULL, 29),
+	SENSOR_ATTR(ads1_chan14, S_IRUGO, epm_adc_psoc_show_in, NULL, 30),
+	SENSOR_ATTR(ads1_chan15, S_IRUGO, epm_adc_psoc_show_in, NULL, 31),
+};
+
+static int __devinit epm_adc_psoc_init_hwmon(struct spi_device *spi,
+						struct epm_adc_drv *epm_adc)
+{
+	int i, rc, num_chans = 15;
+
+	for (i = 0; i < num_chans; i++) {
+		rc = device_create_file(&spi->dev,
+				&epm_adc_psoc_in_attrs[i].dev_attr);
+		if (rc) {
+			dev_err(&spi->dev, "device_create_file failed\n");
+			return rc;
+		}
+	}
+
+	return 0;
+}
+
+static int get_device_tree_data(struct spi_device *spi)
+{
+	const struct device_node *node = spi->dev.of_node;
+	struct epm_adc_drv *epm_adc;
+	int32_t *epm_ch_gain, *epm_ch_rsense;
+	u32 rc = 0, epm_num_channels, i;
+
+	if (!node)
+		return -EINVAL;
+
+	rc = of_property_read_u32(node,
+			"qcom,channels", &epm_num_channels);
+	if (rc) {
+		dev_err(&spi->dev, "missing channel numbers\n");
+		return -ENODEV;
+	}
+
+	epm_ch_gain = devm_kzalloc(&spi->dev,
+				epm_num_channels, GFP_KERNEL);
+	if (!epm_ch_gain) {
+		dev_err(&spi->dev, "cannot allocate gain\n");
+		return -ENOMEM;
+	}
+
+	epm_ch_rsense = devm_kzalloc(&spi->dev,
+				epm_num_channels, GFP_KERNEL);
+	if (!epm_ch_rsense) {
+		dev_err(&spi->dev, "cannot allocate rsense\n");
+		return -ENOMEM;
+	}
+
+	rc = of_property_read_u32_array(node,
+			"qcom,gain", epm_ch_gain, epm_num_channels);
+	if (rc) {
+		dev_err(&spi->dev, "invalid gain property:%d\n", rc);
+		return rc;
+	}
+
+	rc = of_property_read_u32_array(node,
+			"qcom,rsense", epm_ch_rsense, epm_num_channels);
+	if (rc) {
+		dev_err(&spi->dev, "invalid rsense property:%d\n", rc);
+		return rc;
+	}
+
+	epm_adc = devm_kzalloc(&spi->dev,
+			sizeof(struct epm_adc_drv) +
+			(epm_num_channels *
+			sizeof(struct epm_chan_properties)),
+			GFP_KERNEL);
+	if (!epm_adc) {
+		dev_err(&spi->dev, "Unable to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < epm_num_channels; i++) {
+		epm_adc->epm_psoc_ch_prop[i].resistorvalue =
+							epm_ch_rsense[i];
+		epm_adc->epm_psoc_ch_prop[i].gain =
+							epm_ch_gain[i];
+	}
+
+	epm_adc_drv = epm_adc;
+
+	return 0;
+}
+
+static int __devinit epm_adc_psoc_spi_probe(struct spi_device *spi)
+{
+	struct epm_adc_drv *epm_adc;
+	struct device_node *node = spi->dev.of_node;
+	int rc = 0;
+
+	if (!node) {
+		dev_err(&spi->dev, "no platform data?\n");
+		pr_info("Error in the probe\n");
+		return -EINVAL;
+	}
+
+	if (node)
+		rc = get_device_tree_data(spi);
+	else
+		return -ENODEV;
+
+	epm_adc = epm_adc_drv;
+	epm_adc->misc.name = EPM_ADC_DRIVER_NAME;
+	epm_adc->misc.minor = MISC_DYNAMIC_MINOR;
+	epm_adc_drv->epm_spi_client = spi;
+	epm_adc_drv->epm_spi_client->bits_per_word =
+				EPM_ADC_ADS_SPI_BITS_PER_WORD;
+	rc = epm_adc_psoc_init_hwmon(spi, epm_adc);
+	if (rc) {
+		dev_err(&spi->dev, "msm_adc_dev_init failed\n");
+		return rc;
+	}
+
+	epm_adc->hwmon = hwmon_device_register(&spi->dev);
+	if (IS_ERR(epm_adc->hwmon)) {
+		dev_err(&spi->dev, "hwmon_device_register failed\n");
+		return rc;
+	}
+
+	mutex_init(&epm_adc->conv_lock);
+
+	return rc;
+}
+
+static int __devexit epm_adc_psoc_spi_remove(struct spi_device *spi)
+{
+	epm_adc_drv->epm_spi_client = NULL;
+	return 0;
+}
+
+static const struct of_device_id epm_adc_psoc_match_table[] = {
+	{	.compatible = "qcom,epm-adc",
+	},
+	{}
+};
+
+static struct spi_driver epm_spi_driver = {
+	.probe = epm_adc_psoc_spi_probe,
+	.remove = __devexit_p(epm_adc_psoc_spi_remove),
+	.driver = {
+		.name = EPM_ADC_DRIVER_NAME,
+		.of_match_table = epm_adc_psoc_match_table,
+	},
+};
+
 static ssize_t epm_adc_show_in(struct device *dev,
 				 struct device_attribute *devattr, char *buf)
 {
@@ -774,33 +1754,6 @@
 	return 0;
 }
 
-static int __devinit epm_adc_spi_probe(struct spi_device *spi)
-
-{
-	if (!epm_adc_drv)
-		return -ENODEV;
-	epm_adc_drv->epm_spi_client = spi;
-	epm_adc_drv->epm_spi_client->bits_per_word =
-				EPM_ADC_ADS_SPI_BITS_PER_WORD;
-
-	return 0;
-}
-
-static int __devexit epm_adc_spi_remove(struct spi_device *spi)
-{
-	epm_adc_drv->epm_spi_client = NULL;
-	return 0;
-}
-
-static struct spi_driver epm_spi_driver = {
-	.probe = epm_adc_spi_probe,
-	.remove = __devexit_p(epm_adc_spi_remove),
-	.driver = {
-		.name = EPM_ADC_DRIVER_NAME,
-		.owner = THIS_MODULE,
-	},
-};
-
 static int __devinit epm_adc_probe(struct platform_device *pdev)
 {
 	struct epm_adc_drv *epm_adc;
@@ -851,6 +1804,7 @@
 	epm_adc->bus_id = pdata->bus_id;
 	epm_gpio_expander_base_addr = pdata->gpio_expander_base_addr;
 	epm_adc_expander_register = false;
+
 	return rc;
 }
 
diff --git a/drivers/hwmon/qpnp-adc-common.c b/drivers/hwmon/qpnp-adc-common.c
index c122270..f908181 100644
--- a/drivers/hwmon/qpnp-adc-common.c
+++ b/drivers/hwmon/qpnp-adc-common.c
@@ -26,6 +26,7 @@
 #include <linux/spmi.h>
 #include <linux/of_irq.h>
 #include <linux/interrupt.h>
+#include <linux/completion.h>
 #include <linux/qpnp/qpnp-adc.h>
 #include <linux/platform_device.h>
 
@@ -33,6 +34,491 @@
 #define QPNP_VADC_MIN_ADC_CODE			0x6000
 /* Max ADC code represents full-scale range of 1.8V */
 #define QPNP_VADC_MAX_ADC_CODE			0xA800
+#define KELVINMIL_DEGMIL	273160
+
+/* Units for temperature below (on x axis) is in 0.1DegC as
+   required by the battery driver. Note the resolution used
+   here to compute the table was done for DegC to milli-volts.
+   In consideration to limit the size of the table for the given
+   temperature range below, the result is linearly interpolated
+   and provided to the battery driver in the units desired for
+   their framework which is 0.1DegC. True resolution of 0.1DegC
+   will result in the below table size to increase by 10 times */
+static const struct qpnp_vadc_map_pt adcmap_btm_threshold[] = {
+	{-300,	1642},
+	{-200,	1544},
+	{-100,	1414},
+	{0,	1260},
+	{10,	1244},
+	{20,	1228},
+	{30,	1212},
+	{40,	1195},
+	{50,	1179},
+	{60,	1162},
+	{70,	1146},
+	{80,	1129},
+	{90,	1113},
+	{100,	1097},
+	{110,	1080},
+	{120,	1064},
+	{130,	1048},
+	{140,	1032},
+	{150,	1016},
+	{160,	1000},
+	{170,	985},
+	{180,	969},
+	{190,	954},
+	{200,	939},
+	{210,	924},
+	{220,	909},
+	{230,	894},
+	{240,	880},
+	{250,	866},
+	{260,	852},
+	{270,	838},
+	{280,	824},
+	{290,	811},
+	{300,	798},
+	{310,	785},
+	{320,	773},
+	{330,	760},
+	{340,	748},
+	{350,	736},
+	{360,	725},
+	{370,	713},
+	{380,	702},
+	{390,	691},
+	{400,	681},
+	{410,	670},
+	{420,	660},
+	{430,	650},
+	{440,	640},
+	{450,	631},
+	{460,	622},
+	{470,	613},
+	{480,	604},
+	{490,	595},
+	{500,	587},
+	{510,	579},
+	{520,	571},
+	{530,	563},
+	{540,	556},
+	{550,	548},
+	{560,	541},
+	{570,	534},
+	{580,	527},
+	{590,	521},
+	{600,	514},
+	{610,	508},
+	{620,	502},
+	{630,	496},
+	{640,	490},
+	{650,	485},
+	{660,	281},
+	{670,	274},
+	{680,	267},
+	{690,	260},
+	{700,	254},
+	{710,	247},
+	{720,	241},
+	{730,	235},
+	{740,	229},
+	{750,	224},
+	{760,	218},
+	{770,	213},
+	{780,	208},
+	{790,	203}
+};
+
+static const struct qpnp_vadc_map_pt adcmap_ntcg_104ef_104fb[] = {
+	{696483,	-40960},
+	{649148,	-39936},
+	{605368,	-38912},
+	{564809,	-37888},
+	{527215,	-36864},
+	{492322,	-35840},
+	{460007,	-34816},
+	{429982,	-33792},
+	{402099,	-32768},
+	{376192,	-31744},
+	{352075,	-30720},
+	{329714,	-29696},
+	{308876,	-28672},
+	{289480,	-27648},
+	{271417,	-26624},
+	{254574,	-25600},
+	{238903,	-24576},
+	{224276,	-23552},
+	{210631,	-22528},
+	{197896,	-21504},
+	{186007,	-20480},
+	{174899,	-19456},
+	{164521,	-18432},
+	{154818,	-17408},
+	{145744,	-16384},
+	{137265,	-15360},
+	{129307,	-14336},
+	{121866,	-13312},
+	{114896,	-12288},
+	{108365,	-11264},
+	{102252,	-10240},
+	{96499,		-9216},
+	{91111,		-8192},
+	{86055,		-7168},
+	{81308,		-6144},
+	{76857,		-5120},
+	{72660,		-4096},
+	{68722,		-3072},
+	{65020,		-2048},
+	{61538,		-1024},
+	{58261,		0},
+	{55177,		1024},
+	{52274,		2048},
+	{49538,		3072},
+	{46962,		4096},
+	{44531,		5120},
+	{42243,		6144},
+	{40083,		7168},
+	{38045,		8192},
+	{36122,		9216},
+	{34308,		10240},
+	{32592,		11264},
+	{30972,		12288},
+	{29442,		13312},
+	{27995,		14336},
+	{26624,		15360},
+	{25333,		16384},
+	{24109,		17408},
+	{22951,		18432},
+	{21854,		19456},
+	{20807,		20480},
+	{19831,		21504},
+	{18899,		22528},
+	{18016,		23552},
+	{17178,		24576},
+	{16384,		25600},
+	{15631,		26624},
+	{14916,		27648},
+	{14237,		28672},
+	{13593,		29696},
+	{12976,		30720},
+	{12400,		31744},
+	{11848,		32768},
+	{11324,		33792},
+	{10825,		34816},
+	{10354,		35840},
+	{9900,		36864},
+	{9471,		37888},
+	{9062,		38912},
+	{8674,		39936},
+	{8306,		40960},
+	{7951,		41984},
+	{7616,		43008},
+	{7296,		44032},
+	{6991,		45056},
+	{6701,		46080},
+	{6424,		47104},
+	{6160,		48128},
+	{5908,		49152},
+	{5667,		50176},
+	{5439,		51200},
+	{5219,		52224},
+	{5010,		53248},
+	{4810,		54272},
+	{4619,		55296},
+	{4440,		56320},
+	{4263,		57344},
+	{4097,		58368},
+	{3938,		59392},
+	{3785,		60416},
+	{3637,		61440},
+	{3501,		62464},
+	{3368,		63488},
+	{3240,		64512},
+	{3118,		65536},
+	{2998,		66560},
+	{2889,		67584},
+	{2782,		68608},
+	{2680,		69632},
+	{2581,		70656},
+	{2490,		71680},
+	{2397,		72704},
+	{2310,		73728},
+	{2227,		74752},
+	{2147,		75776},
+	{2064,		76800},
+	{1998,		77824},
+	{1927,		78848},
+	{1860,		79872},
+	{1795,		80896},
+	{1736,		81920},
+	{1673,		82944},
+	{1615,		83968},
+	{1560,		84992},
+	{1507,		86016},
+	{1456,		87040},
+	{1407,		88064},
+	{1360,		89088},
+	{1314,		90112},
+	{1271,		91136},
+	{1228,		92160},
+	{1189,		93184},
+	{1150,		94208},
+	{1112,		95232},
+	{1076,		96256},
+	{1042,		97280},
+	{1008,		98304},
+	{976,		99328},
+	{945,		100352},
+	{915,		101376},
+	{886,		102400},
+	{859,		103424},
+	{832,		104448},
+	{807,		105472},
+	{782,		106496},
+	{756,		107520},
+	{735,		108544},
+	{712,		109568},
+	{691,		110592},
+	{670,		111616},
+	{650,		112640},
+	{631,		113664},
+	{612,		114688},
+	{594,		115712},
+	{577,		116736},
+	{560,		117760},
+	{544,		118784},
+	{528,		119808},
+	{513,		120832},
+	{498,		121856},
+	{483,		122880},
+	{470,		123904},
+	{457,		124928},
+	{444,		125952},
+	{431,		126976},
+	{419,		128000}
+};
+
+static int32_t qpnp_adc_map_linear(const struct qpnp_vadc_map_pt *pts,
+		uint32_t tablesize, int32_t input, int64_t *output)
+{
+	bool descending = 1;
+	uint32_t i = 0;
+
+	if ((pts == NULL) || (output == NULL))
+		return -EINVAL;
+
+	/* Check if table is descending or ascending */
+	if (tablesize > 1) {
+		if (pts[0].x < pts[1].x)
+			descending = 0;
+	}
+
+	while (i < tablesize) {
+		if ((descending == 1) && (pts[i].x < input)) {
+			/* table entry is less than measured
+				value and table is descending, stop */
+			break;
+		} else if ((descending == 0) &&
+				(pts[i].x > input)) {
+			/* table entry is greater than measured
+				value and table is ascending, stop */
+			break;
+		} else {
+			i++;
+		}
+	}
+
+	if (i == 0)
+		*output = pts[0].y;
+	else if (i == tablesize)
+		*output = pts[tablesize-1].y;
+	else {
+		/* result is between search_index and search_index-1 */
+		/* interpolate linearly */
+		*output = (((int32_t) ((pts[i].y - pts[i-1].y)*
+			(input - pts[i-1].x))/
+			(pts[i].x - pts[i-1].x))+
+			pts[i-1].y);
+	}
+
+	return 0;
+}
+
+static int32_t qpnp_adc_map_batt_therm(const struct qpnp_vadc_map_pt *pts,
+		uint32_t tablesize, int32_t input, int64_t *output)
+{
+	bool descending = 1;
+	uint32_t i = 0;
+
+	if ((pts == NULL) || (output == NULL))
+		return -EINVAL;
+
+	/* Check if table is descending or ascending */
+	if (tablesize > 1) {
+		if (pts[0].y < pts[1].y)
+			descending = 0;
+	}
+
+	while (i < tablesize) {
+		if ((descending == 1) && (pts[i].y < input)) {
+			/* table entry is less than measured
+				value and table is descending, stop */
+			break;
+		} else if ((descending == 0) && (pts[i].y > input)) {
+			/* table entry is greater than measured
+				value and table is ascending, stop */
+			break;
+		} else {
+			i++;
+		}
+	}
+
+	if (i == 0) {
+		*output = pts[0].x;
+	} else if (i == tablesize) {
+		*output = pts[tablesize-1].x;
+	} else {
+		/* result is between search_index and search_index-1 */
+		/* interpolate linearly */
+		*output = (((int32_t) ((pts[i].x - pts[i-1].x)*
+			(input - pts[i-1].y))/
+			(pts[i].y - pts[i-1].y))+
+			pts[i-1].x);
+	}
+
+	return 0;
+}
+
+static int64_t qpnp_adc_scale_ratiometric_calib(int32_t adc_code,
+		const struct qpnp_adc_properties *adc_properties,
+		const struct qpnp_vadc_chan_properties *chan_properties)
+{
+	int64_t adc_voltage = 0;
+	bool negative_offset = 0;
+
+	if (!chan_properties || !chan_properties->offset_gain_numerator ||
+		!chan_properties->offset_gain_denominator || !adc_properties)
+		return -EINVAL;
+
+	adc_voltage = (adc_code -
+		chan_properties->adc_graph[CALIB_RATIOMETRIC].adc_gnd)
+		* adc_properties->adc_vdd_reference;
+	if (adc_voltage < 0) {
+		negative_offset = 1;
+		adc_voltage = -adc_voltage;
+	}
+	do_div(adc_voltage,
+		chan_properties->adc_graph[CALIB_RATIOMETRIC].dy);
+	if (negative_offset)
+		adc_voltage = -adc_voltage;
+
+	return adc_voltage;
+}
+
+int32_t qpnp_adc_scale_pmic_therm(int32_t adc_code,
+		const struct qpnp_adc_properties *adc_properties,
+		const struct qpnp_vadc_chan_properties *chan_properties,
+		struct qpnp_vadc_result *adc_chan_result)
+{
+	int64_t pmic_voltage = 0;
+	bool negative_offset = 0;
+
+	if (!chan_properties || !chan_properties->offset_gain_numerator ||
+		!chan_properties->offset_gain_denominator || !adc_properties
+		|| !adc_chan_result)
+		return -EINVAL;
+
+	pmic_voltage = (adc_code -
+		chan_properties->adc_graph[CALIB_ABSOLUTE].adc_gnd)
+		* chan_properties->adc_graph[CALIB_ABSOLUTE].dx;
+	if (pmic_voltage < 0) {
+		negative_offset = 1;
+		pmic_voltage = -pmic_voltage;
+	}
+	do_div(pmic_voltage,
+		chan_properties->adc_graph[CALIB_ABSOLUTE].dy);
+	if (negative_offset)
+		pmic_voltage = -pmic_voltage;
+	pmic_voltage += chan_properties->adc_graph[CALIB_ABSOLUTE].dx;
+
+	if (pmic_voltage > 0) {
+		/* 2mV/K */
+		adc_chan_result->measurement = pmic_voltage*
+			chan_properties->offset_gain_denominator;
+
+		do_div(adc_chan_result->measurement,
+			chan_properties->offset_gain_numerator * 2);
+	} else {
+		adc_chan_result->measurement = 0;
+	}
+	/* Change to .001 deg C */
+	adc_chan_result->measurement -= KELVINMIL_DEGMIL;
+	adc_chan_result->physical = (int32_t)adc_chan_result->measurement;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(qpnp_adc_scale_pmic_therm);
+
+/* Scales the ADC code to 0.001 degrees C using the map
+ * table for the XO thermistor.
+ */
+int32_t qpnp_adc_tdkntcg_therm(int32_t adc_code,
+		const struct qpnp_adc_properties *adc_properties,
+		const struct qpnp_vadc_chan_properties *chan_properties,
+		struct qpnp_vadc_result *adc_chan_result)
+{
+	int64_t xo_thm = 0;
+
+	if (!chan_properties || !chan_properties->offset_gain_numerator ||
+		!chan_properties->offset_gain_denominator || !adc_properties
+		|| !adc_chan_result)
+		return -EINVAL;
+
+	xo_thm = qpnp_adc_scale_ratiometric_calib(adc_code,
+			adc_properties, chan_properties);
+	xo_thm <<= 4;
+	qpnp_adc_map_linear(adcmap_ntcg_104ef_104fb,
+		ARRAY_SIZE(adcmap_ntcg_104ef_104fb),
+		xo_thm, &adc_chan_result->physical);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(qpnp_adc_tdkntcg_therm);
+
+int32_t qpnp_adc_scale_batt_therm(int32_t adc_code,
+		const struct qpnp_adc_properties *adc_properties,
+		const struct qpnp_vadc_chan_properties *chan_properties,
+		struct qpnp_vadc_result *adc_chan_result)
+{
+	int64_t bat_voltage = 0;
+
+	bat_voltage = qpnp_adc_scale_ratiometric_calib(adc_code,
+			adc_properties, chan_properties);
+
+	return qpnp_adc_map_batt_therm(
+			adcmap_btm_threshold,
+			ARRAY_SIZE(adcmap_btm_threshold),
+			bat_voltage,
+			&adc_chan_result->physical);
+}
+EXPORT_SYMBOL_GPL(qpnp_adc_scale_batt_therm);
+
+int32_t qpnp_adc_scale_batt_id(int32_t adc_code,
+		const struct qpnp_adc_properties *adc_properties,
+		const struct qpnp_vadc_chan_properties *chan_properties,
+		struct qpnp_vadc_result *adc_chan_result)
+{
+	int64_t batt_id_voltage = 0;
+
+	batt_id_voltage = qpnp_adc_scale_ratiometric_calib(adc_code,
+			adc_properties, chan_properties);
+	adc_chan_result->physical = batt_id_voltage;
+	adc_chan_result->physical = adc_chan_result->measurement;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(qpnp_adc_scale_batt_id);
 
 int32_t qpnp_adc_scale_default(int32_t adc_code,
 		const struct qpnp_adc_properties *adc_properties,
@@ -203,7 +689,7 @@
 				"qcom,calibration-type", NULL);
 		if (!strncmp(calibration_param, "absolute", 8))
 			calib_type = CALIB_ABSOLUTE;
-		else if (!strncmp(calibration_param, "historical", 9))
+		else if (!strncmp(calibration_param, "ratiometric", 11))
 			calib_type = CALIB_RATIOMETRIC;
 		else {
 			pr_err("%s: Invalid calibration property\n", __func__);
@@ -252,6 +738,8 @@
 		return -ENXIO;
 	}
 
+	init_completion(&adc_qpnp->adc_rslt_completion);
+
 	mutex_init(&adc_qpnp->adc_lock);
 
 	return 0;
diff --git a/drivers/hwmon/qpnp-adc-current.c b/drivers/hwmon/qpnp-adc-current.c
index b689255..aa375d7 100644
--- a/drivers/hwmon/qpnp-adc-current.c
+++ b/drivers/hwmon/qpnp-adc-current.c
@@ -33,6 +33,15 @@
 #include <linux/platform_device.h>
 
 /* QPNP IADC register definition */
+#define QPNP_IADC_REVISION1				0x0
+#define QPNP_IADC_REVISION2				0x1
+#define QPNP_IADC_REVISION3				0x2
+#define QPNP_IADC_REVISION4				0x3
+#define QPNP_IADC_PERPH_TYPE				0x4
+#define QPNP_IADC_PERH_SUBTYPE				0x5
+
+#define QPNP_IADC_SUPPORTED_REVISION2			1
+
 #define QPNP_STATUS1					0x8
 #define QPNP_STATUS1_OP_MODE				4
 #define QPNP_STATUS1_MULTI_MEAS_EN			BIT(3)
@@ -67,13 +76,14 @@
 #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_IADC_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_IADC_EN_CTL1				0x46
+#define QPNP_IADC_ADC_EN				BIT(7)
 #define QPNP_ADC_CH_SEL_CTL				0x48
 #define QPNP_ADC_DIG_PARAM				0x50
 #define QPNP_ADC_CLK_SEL_MASK				0x3
@@ -101,13 +111,6 @@
 #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
 
@@ -121,16 +124,18 @@
 #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_CONV_TIME_MIN				8000
+#define QPNP_ADC_CONV_TIME_MAX				8200
 
-#define QPNP_ADC_GAIN_CALCULATION			2500
+#define QPNP_ADC_GAIN_CALCULATION_UV			17857
+#define QPNP_IADC_RSENSE_MILLI_FACTOR			1000
 
 struct qpnp_iadc_drv {
 	struct qpnp_adc_drv		*adc;
 	int32_t				rsense;
 	struct device			*iadc_hwmon;
 	bool				iadc_init_calib;
+	bool				iadc_initialized;
 	struct sensor_device_attribute		sens_attr[0];
 };
 
@@ -223,6 +228,31 @@
 	return IRQ_HANDLED;
 }
 
+static int32_t qpnp_iadc_enable(bool state)
+{
+	int rc = 0;
+	u8 data = 0;
+
+	data = QPNP_IADC_ADC_EN;
+	if (state) {
+		rc = qpnp_iadc_write_reg(QPNP_IADC_EN_CTL1,
+					data);
+		if (rc < 0) {
+			pr_err("IADC enable failed\n");
+			return rc;
+		}
+	} else {
+		rc = qpnp_iadc_write_reg(QPNP_IADC_EN_CTL1,
+					(~data & QPNP_IADC_ADC_EN));
+		if (rc < 0) {
+			pr_err("IADC disable failed\n");
+			return rc;
+		}
+	}
+
+	return 0;
+}
+
 static int32_t qpnp_iadc_read_conversion_result(int32_t *data)
 {
 	uint8_t rslt_lsb, rslt_msb;
@@ -242,12 +272,9 @@
 
 	*data = (rslt_msb << 8) | rslt_lsb;
 
-	rc = qpnp_vadc_check_result(data);
-	if (rc < 0) {
-		pr_err("VADC data check failed\n");
+	rc = qpnp_iadc_enable(false);
+	if (rc)
 		return rc;
-	}
-
 	return 0;
 }
 
@@ -259,10 +286,7 @@
 	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_ch_sel_reg = channel;
 
 	qpnp_iadc_dig_param_reg |= iadc->adc->amux_prop->decimation <<
 					QPNP_IADC_DEC_RATIO_SEL;
@@ -310,6 +334,10 @@
 		return rc;
 	}
 
+	rc = qpnp_iadc_enable(true);
+	if (rc)
+		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);
@@ -353,17 +381,53 @@
 	return rc;
 }
 
+static int32_t qpnp_iadc_version_check(void)
+{
+	uint8_t revision;
+	int rc;
+
+	rc = qpnp_iadc_read_reg(QPNP_IADC_REVISION2, &revision);
+	if (rc < 0) {
+		pr_err("qpnp adc result read failed with %d\n", rc);
+		return rc;
+	}
+
+	if (revision < QPNP_IADC_SUPPORTED_REVISION2) {
+		pr_err("IADC Version not supported\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+int32_t qpnp_iadc_is_ready(void)
+{
+	struct qpnp_iadc_drv *iadc = qpnp_iadc;
+
+	if (!iadc || !iadc->iadc_initialized)
+		return -EPROBE_DEFER;
+	else
+		return 0;
+}
+EXPORT_SYMBOL(qpnp_iadc_is_ready);
+
 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;
 
+	if (!iadc || !iadc->iadc_initialized)
+		return -EPROBE_DEFER;
+
 	mutex_lock(&iadc->adc->adc_lock);
 
 	if (!iadc->iadc_init_calib) {
+		rc = qpnp_iadc_version_check();
+		if (rc)
+			goto fail;
 		rc = qpnp_iadc_init_calib();
-		if (!rc) {
+		if (rc) {
 			pr_err("Calibration failed\n");
 			goto fail;
 		} else
@@ -376,12 +440,11 @@
 		goto fail;
 	}
 
-	vsense_mv = ((*result - iadc->adc->calib.offset)/
-			(iadc->adc->calib.gain - iadc->adc->calib.offset))
-			* QPNP_ADC_GAIN_CALCULATION;
+	*result = ((vsense_mv - iadc->adc->calib.offset) *
+				QPNP_ADC_GAIN_CALCULATION_UV)/
+			(iadc->adc->calib.gain - iadc->adc->calib.offset);
 
-	*result = (vsense_mv/qpnp_iadc->rsense);
-
+	*result = (*result / (qpnp_iadc->rsense));
 fail:
 	mutex_unlock(&iadc->adc->adc_lock);
 
diff --git a/drivers/hwmon/qpnp-adc-voltage.c b/drivers/hwmon/qpnp-adc-voltage.c
index 9e8a2e2..a0e7ab9 100644
--- a/drivers/hwmon/qpnp-adc-voltage.c
+++ b/drivers/hwmon/qpnp-adc-voltage.c
@@ -32,6 +32,15 @@
 #include <linux/platform_device.h>
 
 /* QPNP VADC register definition */
+#define QPNP_VADC_REVISION1				0x0
+#define QPNP_VADC_REVISION2				0x1
+#define QPNP_VADC_REVISION3				0x2
+#define QPNP_VADC_REVISION4				0x3
+#define QPNP_VADC_PERPH_TYPE				0x4
+#define QPNP_VADC_PERH_SUBTYPE				0x5
+
+#define QPNP_VADC_SUPPORTED_REVISION2			1
+
 #define QPNP_VADC_STATUS1					0x8
 #define QPNP_VADC_STATUS1_OP_MODE				4
 #define QPNP_VADC_STATUS1_MEAS_INTERVAL_EN_STS			BIT(2)
@@ -98,6 +107,8 @@
 	struct dentry			*dent;
 	struct device			*vadc_hwmon;
 	bool				vadc_init_calib;
+	bool				vadc_initialized;
+	int				max_channels_available;
 	struct sensor_device_attribute		sens_attr[0];
 };
 
@@ -105,6 +116,9 @@
 
 static struct qpnp_vadc_scale_fn vadc_scale_fn[] = {
 	[SCALE_DEFAULT] = {qpnp_adc_scale_default},
+	[SCALE_BATT_THERM] = {qpnp_adc_scale_batt_therm},
+	[SCALE_PMIC_THERM] = {qpnp_adc_scale_pmic_therm},
+	[SCALE_XOTHERM] = {qpnp_adc_tdkntcg_therm},
 };
 
 static int32_t qpnp_vadc_read_reg(int16_t reg, u8 *data)
@@ -206,32 +220,21 @@
 	u8 mode_ctrl = 0;
 	int rc = 0;
 
-	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;
-		}
+	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("Mode configure read error\n");
-		return rc;
-	}
-	mode_ctrl |= chan_prop->mode_sel << QPNP_VADC_OP_MODE_SHIFT;
+	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_enable(true);
-	if (rc)
-		return rc;
 
 	/* Channel selection */
 	rc = qpnp_vadc_write_reg(QPNP_VADC_ADC_CH_SEL_CTL,
@@ -242,12 +245,7 @@
 	}
 
 	/* 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 <<
+	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) {
@@ -296,6 +294,12 @@
 		}
 	}
 
+	INIT_COMPLETION(vadc->adc->adc_rslt_completion);
+
+	rc = qpnp_vadc_enable(true);
+	if (rc)
+		return rc;
+
 	/* Request conversion */
 	rc = qpnp_vadc_write_reg(QPNP_VADC_CONV_REQ, QPNP_VADC_CONV_REQ_SET);
 	if (rc < 0) {
@@ -402,6 +406,25 @@
 	return IRQ_HANDLED;
 }
 
+static int32_t qpnp_vadc_version_check(void)
+{
+	uint8_t revision;
+	int rc;
+
+	rc = qpnp_vadc_read_reg(QPNP_VADC_REVISION2, &revision);
+	if (rc < 0) {
+		pr_err("qpnp adc result read failed with %d\n", rc);
+		return rc;
+	}
+
+	if (revision < QPNP_VADC_SUPPORTED_REVISION2) {
+		pr_err("VADC Version not supported\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static uint32_t qpnp_vadc_calib_device(void)
 {
 	struct qpnp_vadc_drv *vadc = qpnp_vadc;
@@ -421,8 +444,7 @@
 		goto calib_fail;
 	}
 
-	while (status1 != (~QPNP_VADC_STATUS1_REQ_STS |
-					QPNP_VADC_STATUS1_EOC)) {
+	while (status1 != QPNP_VADC_STATUS1_EOC) {
 		rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
 		if (rc < 0)
 			return rc;
@@ -449,8 +471,7 @@
 	}
 
 	status1 = 0;
-	while (status1 != (~QPNP_VADC_STATUS1_REQ_STS |
-					QPNP_VADC_STATUS1_EOC)) {
+	while (status1 != QPNP_VADC_STATUS1_EOC) {
 		rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
 		if (rc < 0)
 			return rc;
@@ -459,7 +480,7 @@
 					QPNP_VADC_CONV_TIME_MAX);
 	}
 
-	rc = qpnp_vadc_read_conversion_result(&calib_read_1);
+	rc = qpnp_vadc_read_conversion_result(&calib_read_2);
 	if (rc) {
 		pr_err("qpnp adc read adc failed with %d\n", rc);
 		goto calib_fail;
@@ -467,6 +488,7 @@
 
 	vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dy =
 					(calib_read_1 - calib_read_2);
+
 	vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dx
 						= QPNP_ADC_625_UV;
 	vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].adc_vref =
@@ -486,8 +508,7 @@
 	}
 
 	status1 = 0;
-	while (status1 != (~QPNP_VADC_STATUS1_REQ_STS |
-					QPNP_VADC_STATUS1_EOC)) {
+	while (status1 != QPNP_VADC_STATUS1_EOC) {
 		rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
 		if (rc < 0)
 			return rc;
@@ -502,7 +523,7 @@
 		goto calib_fail;
 	}
 
-	conv.amux_channel = VDD_VADC;
+	conv.amux_channel = GND_REF;
 	conv.decimation = DECIMATION_TYPE2;
 	conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
 	conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
@@ -514,8 +535,7 @@
 	}
 
 	status1 = 0;
-	while (status1 != (~QPNP_VADC_STATUS1_REQ_STS |
-					QPNP_VADC_STATUS1_EOC)) {
+	while (status1 != QPNP_VADC_STATUS1_EOC) {
 		rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
 		if (rc < 0)
 			return rc;
@@ -524,7 +544,7 @@
 					QPNP_VADC_CONV_TIME_MAX);
 	}
 
-	rc = qpnp_vadc_read_conversion_result(&calib_read_1);
+	rc = qpnp_vadc_read_conversion_result(&calib_read_2);
 	if (rc) {
 		pr_err("qpnp adc read adc failed with %d\n", rc);
 		goto calib_fail;
@@ -543,14 +563,31 @@
 	return rc;
 }
 
+int32_t qpnp_vadc_is_ready(void)
+{
+	struct qpnp_vadc_drv *vadc = qpnp_vadc;
+
+	if (!vadc || !vadc->vadc_initialized)
+		return -EPROBE_DEFER;
+	else
+		return 0;
+}
+EXPORT_SYMBOL(qpnp_vadc_is_ready);
+
 int32_t qpnp_vadc_conv_seq_request(enum qpnp_vadc_trigger trigger_channel,
 					enum qpnp_vadc_channels channel,
 					struct qpnp_vadc_result *result)
 {
 	struct qpnp_vadc_drv *vadc = qpnp_vadc;
-	int rc = 0, scale_type, amux_prescaling;
+	int rc = 0, scale_type, amux_prescaling, dt_index = 0;
+
+	if (!vadc || !vadc->vadc_initialized)
+		return -EPROBE_DEFER;
 
 	if (!vadc->vadc_init_calib) {
+		rc = qpnp_vadc_version_check();
+		if (rc)
+			return rc;
 		rc = qpnp_vadc_calib_device();
 		if (rc) {
 			pr_err("Calibration failed\n");
@@ -562,12 +599,20 @@
 	mutex_lock(&vadc->adc->adc_lock);
 
 	vadc->adc->amux_prop->amux_channel = channel;
+
+	while (vadc->adc->adc_channels[dt_index].channel_num
+			!= channel || dt_index > vadc->max_channels_available)
+		dt_index++;
+
+	if (dt_index > vadc->max_channels_available)
+		goto fail_unlock;
+
 	vadc->adc->amux_prop->decimation =
-			vadc->adc->adc_channels[channel].adc_decimation;
+			vadc->adc->adc_channels[dt_index].adc_decimation;
 	vadc->adc->amux_prop->hw_settle_time =
-			vadc->adc->adc_channels[channel].hw_settle_time;
+			vadc->adc->adc_channels[dt_index].hw_settle_time;
 	vadc->adc->amux_prop->fast_avg_setup =
-			vadc->adc->adc_channels[channel].fast_avg_setup;
+			vadc->adc->adc_channels[dt_index].fast_avg_setup;
 
 	if (trigger_channel < ADC_SEQ_NONE)
 		vadc->adc->amux_prop->mode_sel = (ADC_OP_CONVERSION_SEQUENCER
@@ -602,14 +647,15 @@
 		goto fail_unlock;
 	}
 
-	amux_prescaling = vadc->adc->adc_channels[channel].chan_path_prescaling;
+	amux_prescaling =
+		vadc->adc->adc_channels[dt_index].chan_path_prescaling;
 
 	vadc->adc->amux_prop->chan_prop->offset_gain_numerator =
 		qpnp_vadc_amux_scaling_ratio[amux_prescaling].num;
 	vadc->adc->amux_prop->chan_prop->offset_gain_denominator =
 		 qpnp_vadc_amux_scaling_ratio[amux_prescaling].den;
 
-	scale_type = vadc->adc->adc_channels[channel].adc_scale_fn;
+	scale_type = vadc->adc->adc_channels[dt_index].adc_scale_fn;
 	if (scale_type >= SCALE_NONE) {
 		rc = -EBADF;
 		goto fail_unlock;
@@ -642,8 +688,10 @@
 
 	rc = qpnp_vadc_read(attr->index, &result);
 
-	if (rc)
+	if (rc) {
+		pr_err("VADC read error with %d\n", rc);
 		return 0;
+	}
 
 	return snprintf(buf, QPNP_ADC_HWMON_NAME_LENGTH,
 		"Result:%lld Raw:%d\n", result.physical, result.adc_code);
@@ -738,6 +786,8 @@
 		dev_err(&spmi->dev,
 			"failed to request adc irq with error %d\n", rc);
 		return rc;
+	} else {
+		enable_irq_wake(vadc->adc->adc_irq);
 	}
 
 	qpnp_vadc = vadc;
@@ -749,6 +799,8 @@
 	}
 	vadc->vadc_hwmon = hwmon_device_register(&vadc->adc->spmi->dev);
 	vadc->vadc_init_calib = false;
+	vadc->vadc_initialized = true;
+	vadc->max_channels_available = count_adc_channel_list;
 
 	rc = qpnp_vadc_configure_interrupt();
 	if (rc) {
@@ -777,6 +829,7 @@
 		i++;
 	}
 	free_irq(vadc->adc->adc_irq, vadc);
+	vadc->vadc_initialized = false;
 	dev_set_drvdata(&spmi->dev, NULL);
 
 	return 0;
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index 297afa7..085b632 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -328,12 +328,14 @@
 	dev->clk_state = state;
 	if (state != 0) {
 		clk_enable(dev->clk);
-		clk_enable(dev->pclk);
+		if (!dev->pdata->keep_ahb_clk_on)
+			clk_enable(dev->pclk);
 	} else {
 		qup_update_state(dev, QUP_RESET_STATE);
 		clk_disable(dev->clk);
 		qup_config_core_on_en(dev);
-		clk_disable(dev->pclk);
+		if (!dev->pdata->keep_ahb_clk_on)
+			clk_disable(dev->pclk);
 	}
 }
 
@@ -1325,6 +1327,12 @@
 	dev->clk_state = 0;
 	clk_prepare(dev->clk);
 	clk_prepare(dev->pclk);
+	/* If the same AHB clock is used on Modem side
+	 * switch it on here itself and don't switch it
+	 * on and off during suspend and resume.
+	 */
+	if (dev->pdata->keep_ahb_clk_on)
+		clk_enable(dev->pclk);
 	setup_timer(&dev->pwr_timer, qup_i2c_pwr_timer, (unsigned long) dev);
 
 	pm_runtime_set_active(&pdev->dev);
@@ -1339,8 +1347,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;
 	}
 
@@ -1394,9 +1404,11 @@
 	free_irq(dev->err_irq, dev);
 	i2c_del_adapter(&dev->adapter);
 	clk_unprepare(dev->clk);
-	clk_unprepare(dev->pclk);
+	if (!dev->pdata->keep_ahb_clk_on) {
+		clk_unprepare(dev->pclk);
+		clk_put(dev->pclk);
+	}
 	clk_put(dev->clk);
-	clk_put(dev->pclk);
 	qup_i2c_free_gpios(dev);
 	if (dev->gsbi)
 		iounmap(dev->gsbi);
@@ -1432,7 +1444,8 @@
 	if (dev->clk_state != 0)
 		qup_i2c_pwr_mgmt(dev, 0);
 	clk_unprepare(dev->clk);
-	clk_unprepare(dev->pclk);
+	if (!dev->pdata->keep_ahb_clk_on)
+		clk_unprepare(dev->pclk);
 	qup_i2c_free_gpios(dev);
 	return 0;
 }
@@ -1443,7 +1456,8 @@
 	struct qup_i2c_dev *dev = platform_get_drvdata(pdev);
 	BUG_ON(qup_i2c_request_gpios(dev) != 0);
 	clk_prepare(dev->clk);
-	clk_prepare(dev->pclk);
+	if (!dev->pdata->keep_ahb_clk_on)
+		clk_prepare(dev->pclk);
 	dev->suspended = 0;
 	return 0;
 }
diff --git a/drivers/input/misc/mpu3050.c b/drivers/input/misc/mpu3050.c
index 8b6e172..04a7598 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,8 @@
 	struct mpu3050_gyro_platform_data *platform_data;
 	struct delayed_work input_work;
 	u32    use_poll;
+	u32    poll_interval;
+	u32    dlpf_index;
 };
 
 struct sensor_regulator {
@@ -131,6 +138,39 @@
 	{NULL, "vlogic", 1800000, 1800000},
 };
 
+struct dlpf_cfg_tb {
+	u8  cfg;	/* cfg index */
+	u32 lpf_bw;	/* low pass filter bandwidth in Hz */
+	u32 sample_rate; /* analog sample rate in Khz, 1 or 8 */
+};
+
+static struct dlpf_cfg_tb dlpf_table[] = {
+	{6,   5, 1},
+	{5,  10, 1},
+	{4,  20, 1},
+	{3,  42, 1},
+	{2,  98, 1},
+	{1, 188, 1},
+	{0, 256, 8},
+};
+
+static u8 interval_to_dlpf_cfg(u32 interval)
+{
+	u32 sample_rate = 1000 / interval;
+	u32 i;
+
+	/* the filter bandwidth needs to be greater or
+	 * equal to half of the sample rate
+	 */
+	for (i = 0; i < sizeof(dlpf_table)/sizeof(dlpf_table[0]); i++) {
+		if (dlpf_table[i].lpf_bw * 2 >= sample_rate)
+			return i;
+	}
+
+	/* return the maximum possible */
+	return --i;
+}
+
 static int mpu3050_config_regulator(struct i2c_client *client, bool on)
 {
 	int rc = 0, i;
@@ -190,6 +230,96 @@
 }
 
 /**
+ *	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;
+	unsigned int  dlpf_index;
+	u8  divider, reg;
+	int ret;
+
+	if (kstrtoul(buf, 10, &interval_ms))
+		return -EINVAL;
+	if ((interval_ms < MPU3050_MIN_POLL_INTERVAL) ||
+		(interval_ms > MPU3050_MAX_POLL_INTERVAL))
+		return -EINVAL;
+
+	dlpf_index = interval_to_dlpf_cfg(interval_ms);
+	divider = interval_ms * dlpf_table[dlpf_index].sample_rate - 1;
+
+	if (sensor->dlpf_index != dlpf_index) {
+		/* Set low pass filter and full scale */
+		reg = dlpf_table[dlpf_index].cfg;
+		reg |= MPU3050_DEFAULT_FS_RANGE << 3;
+		reg |= MPU3050_EXT_SYNC_NONE << 5;
+		ret = i2c_smbus_write_byte_data(sensor->client,
+				MPU3050_DLPF_FS_SYNC, reg);
+		if (ret == 0)
+			sensor->dlpf_index = dlpf_index;
+	}
+
+	if (sensor->poll_interval != interval_ms) {
+		/* Output frequency divider. The poll interval */
+		ret = i2c_smbus_write_byte_data(sensor->client,
+				MPU3050_SMPLRT_DIV, divider);
+		if (ret == 0)
+			sensor->poll_interval = interval_ms;
+	}
+
+	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 +414,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 +496,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,13 +529,13 @@
 
 	/* 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;
 
 	/* Set low pass filter and full scale */
-	reg = MPU3050_DEFAULT_FS_RANGE;
-	reg |= MPU3050_DLPF_CFG_42HZ << 3;
+	reg = MPU3050_DLPF_CFG_42HZ;
+	reg |= MPU3050_DEFAULT_FS_RANGE << 3;
 	reg |= MPU3050_EXT_SYNC_NONE << 5;
 	ret = i2c_smbus_write_byte_data(client, MPU3050_DLPF_FS_SYNC, reg);
 	if (ret < 0)
@@ -444,6 +574,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 +627,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 +670,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 +711,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/misc/pmic8xxx-pwrkey.c b/drivers/input/misc/pmic8xxx-pwrkey.c
index 58f9661..9f64cec 100644
--- a/drivers/input/misc/pmic8xxx-pwrkey.c
+++ b/drivers/input/misc/pmic8xxx-pwrkey.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -35,6 +35,8 @@
 struct pmic8xxx_pwrkey {
 	struct input_dev *pwr;
 	int key_press_irq;
+	int key_release_irq;
+	bool press;
 	const struct pm8xxx_pwrkey_platform_data *pdata;
 };
 
@@ -42,6 +44,13 @@
 {
 	struct pmic8xxx_pwrkey *pwrkey = _pwrkey;
 
+	if (pwrkey->press == true) {
+		pwrkey->press = false;
+		return IRQ_HANDLED;
+	} else {
+		pwrkey->press = true;
+	}
+
 	input_report_key(pwrkey->pwr, KEY_POWER, 1);
 	input_sync(pwrkey->pwr);
 
@@ -52,6 +61,14 @@
 {
 	struct pmic8xxx_pwrkey *pwrkey = _pwrkey;
 
+	if (pwrkey->press == false) {
+		input_report_key(pwrkey->pwr, KEY_POWER, 1);
+		input_sync(pwrkey->pwr);
+		pwrkey->press = true;
+	} else {
+		pwrkey->press = false;
+	}
+
 	input_report_key(pwrkey->pwr, KEY_POWER, 0);
 	input_sync(pwrkey->pwr);
 
@@ -63,8 +80,10 @@
 {
 	struct pmic8xxx_pwrkey *pwrkey = dev_get_drvdata(dev);
 
-	if (device_may_wakeup(dev))
+	if (device_may_wakeup(dev)) {
 		enable_irq_wake(pwrkey->key_press_irq);
+		enable_irq_wake(pwrkey->key_release_irq);
+	}
 
 	return 0;
 }
@@ -73,8 +92,10 @@
 {
 	struct pmic8xxx_pwrkey *pwrkey = dev_get_drvdata(dev);
 
-	if (device_may_wakeup(dev))
+	if (device_may_wakeup(dev)) {
 		disable_irq_wake(pwrkey->key_press_irq);
+		disable_irq_wake(pwrkey->key_release_irq);
+	}
 
 	return 0;
 }
@@ -155,7 +176,9 @@
 	}
 
 	pwrkey->key_press_irq = key_press_irq;
+	pwrkey->key_release_irq = key_release_irq;
 	pwrkey->pwr = pwr;
+	pwrkey->press = false;
 
 	platform_set_drvdata(pdev, pwrkey);
 
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 1c70527..f10f433 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -26,7 +26,7 @@
 #include <linux/seq_file.h>
 #include <linux/regulator/consumer.h>
 #include <linux/string.h>
-
+#include <linux/of_gpio.h>
 #if defined(CONFIG_HAS_EARLYSUSPEND)
 #include <linux/earlysuspend.h>
 /* Early-suspend level */
@@ -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 */
 
@@ -283,6 +290,8 @@
 #define MXT_CFG_VERSION_LESS	1
 #define MXT_CFG_VERSION_GREATER	2
 
+#define MXT_COORDS_ARR_SIZE	4
+
 #define MXT_DEBUGFS_DIR		"atmel_mxt_ts"
 #define MXT_DEBUGFS_FILE	"object"
 
@@ -372,6 +381,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 +389,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 +398,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 +418,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 +426,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 +435,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 +1308,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);
@@ -2307,14 +2326,228 @@
 	}
 }
 
+#ifdef CONFIG_OF
+static int mxt_get_dt_coords(struct device *dev, char *name,
+				struct mxt_platform_data *pdata)
+{
+	u32 coords[MXT_COORDS_ARR_SIZE];
+	struct property *prop;
+	struct device_node *np = dev->of_node;
+	int coords_size, rc;
+
+	prop = of_find_property(np, name, NULL);
+	if (!prop)
+		return -EINVAL;
+	if (!prop->value)
+		return -ENODATA;
+
+	coords_size = prop->length / sizeof(u32);
+	if (coords_size != MXT_COORDS_ARR_SIZE) {
+		dev_err(dev, "invalid %s\n", name);
+		return -EINVAL;
+	}
+
+	rc = of_property_read_u32_array(np, name, coords, coords_size);
+	if (rc && (rc != -EINVAL)) {
+		dev_err(dev, "Unable to read %s\n", name);
+		return rc;
+	}
+
+	if (strncmp(name, "atmel,panel-coords",
+			sizeof("atmel,panel-coords")) == 0) {
+		pdata->panel_minx = coords[0];
+		pdata->panel_miny = coords[1];
+		pdata->panel_maxx = coords[2];
+		pdata->panel_maxy = coords[3];
+	} else if (strncmp(name, "atmel,display-coords",
+			sizeof("atmel,display-coords")) == 0) {
+		pdata->disp_minx = coords[0];
+		pdata->disp_miny = coords[1];
+		pdata->disp_maxx = coords[2];
+		pdata->disp_maxy = coords[3];
+	} else {
+		dev_err(dev, "unsupported property %s\n", name);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int mxt_parse_config(struct device *dev, struct device_node *np,
+				struct mxt_config_info *info)
+{
+	struct property *prop;
+	u8 *temp_cfg;
+
+	prop = of_find_property(np, "atmel,config", &info->config_length);
+	if (!prop) {
+		dev_err(dev, "Looking up %s property in node %s failed",
+			"atmel,config", np->full_name);
+		return -ENODEV;
+	} else if (!info->config_length) {
+		dev_err(dev, "Invalid length of configuration data\n");
+		return -EINVAL;
+	}
+
+	temp_cfg = devm_kzalloc(dev,
+			info->config_length * sizeof(u8), GFP_KERNEL);
+	if (!temp_cfg) {
+		dev_err(dev, "Unable to allocate memory to store cfg\n");
+		return -ENOMEM;
+	}
+
+	memcpy(temp_cfg, prop->value, info->config_length);
+	info->config = temp_cfg;
+
+	return 0;
+}
+
+static int mxt_parse_dt(struct device *dev, struct mxt_platform_data *pdata)
+{
+	int rc;
+	struct mxt_config_info *info;
+	struct device_node *temp, *np = dev->of_node;
+	struct property *prop;
+	u32 temp_val;
+
+	rc = mxt_get_dt_coords(dev, "atmel,panel-coords", pdata);
+	if (rc)
+		return rc;
+
+	rc = mxt_get_dt_coords(dev, "atmel,display-coords", pdata);
+	if (rc)
+		return rc;
+
+	/* regulator info */
+	pdata->i2c_pull_up = of_property_read_bool(np, "atmel,i2c-pull-up");
+	pdata->digital_pwr_regulator = of_property_read_bool(np,
+						"atmel,dig-reg-support");
+	/* reset, irq gpio info */
+	pdata->reset_gpio = of_get_named_gpio_flags(np, "atmel,reset-gpio",
+				0, &pdata->reset_gpio_flags);
+	pdata->irq_gpio = of_get_named_gpio_flags(np, "atmel,irq-gpio",
+				0, &pdata->irq_gpio_flags);
+
+	/* keycodes for keyarray object*/
+	prop = of_find_property(np, "atmel,key-codes", NULL);
+	if (prop) {
+		pdata->key_codes = devm_kzalloc(dev,
+				sizeof(int) * MXT_KEYARRAY_MAX_KEYS,
+				GFP_KERNEL);
+		if (!pdata->key_codes)
+			return -ENOMEM;
+		if ((prop->length/sizeof(u32)) == MXT_KEYARRAY_MAX_KEYS) {
+			rc = of_property_read_u32_array(np, "atmel,key-codes",
+				pdata->key_codes, MXT_KEYARRAY_MAX_KEYS);
+			if (rc) {
+				dev_err(dev, "Unable to read key codes\n");
+				return rc;
+			}
+		} else
+			return -EINVAL;
+	}
+
+	/* config array size */
+	pdata->config_array_size = 0;
+	temp = NULL;
+	while ((temp = of_get_next_child(np, temp)))
+		pdata->config_array_size++;
+
+	if (!pdata->config_array_size)
+		return 0;
+
+	info = devm_kzalloc(dev, pdata->config_array_size *
+				sizeof(struct mxt_config_info), GFP_KERNEL);
+	if (!info) {
+		dev_err(dev, "Unable to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	pdata->config_array  = info;
+
+	for_each_child_of_node(np, temp) {
+		rc = of_property_read_string(temp, "atmel,fw-name",
+			&info->fw_name);
+		if (rc && (rc != -EINVAL)) {
+			dev_err(dev, "Unable to read fw name\n");
+			return rc;
+		}
+
+		rc = of_property_read_u32(temp, "atmel,family-id", &temp_val);
+		if (rc) {
+			dev_err(dev, "Unable to read family id\n");
+			return rc;
+		} else
+			info->family_id = (u8) temp_val;
+
+		rc  = of_property_read_u32(temp, "atmel,variant-id", &temp_val);
+		if (rc) {
+			dev_err(dev, "Unable to read variant id\n");
+			return rc;
+		} else
+			info->variant_id = (u8) temp_val;
+
+		rc = of_property_read_u32(temp, "atmel,version", &temp_val);
+		if (rc) {
+			dev_err(dev, "Unable to read controller version\n");
+			return rc;
+		} else
+			info->version = (u8) temp_val;
+
+		rc = of_property_read_u32(temp, "atmel,build", &temp_val);
+		if (rc) {
+			dev_err(dev, "Unable to read build id\n");
+			return rc;
+		} else
+			info->build = (u8) temp_val;
+
+		info->bootldr_id = of_property_read_u32(temp,
+					"atmel,bootldr-id", &temp_val);
+		if (rc) {
+			dev_err(dev, "Unable to read bootldr-id\n");
+			return rc;
+		} else
+			info->bootldr_id = (u8) temp_val;
+
+		rc = mxt_parse_config(dev, temp, info);
+		if (rc) {
+			dev_err(dev, "Unable to parse config data\n");
+			return rc;
+		}
+		info++;
+	}
+
+	return 0;
+}
+#else
+static int mxt_parse_dt(struct device *dev, struct mxt_platform_data *pdata)
+{
+	return -ENODEV;
+}
+#endif
+
 static int __devinit mxt_probe(struct i2c_client *client,
 		const struct i2c_device_id *id)
 {
-	const struct mxt_platform_data *pdata = client->dev.platform_data;
+	struct mxt_platform_data *pdata;
 	struct mxt_data *data;
 	struct input_dev *input_dev;
 	int error, i;
 
+	if (client->dev.of_node) {
+		pdata = devm_kzalloc(&client->dev,
+			sizeof(struct mxt_platform_data), GFP_KERNEL);
+		if (!pdata) {
+			dev_err(&client->dev, "Failed to allocate memory\n");
+			return -ENOMEM;
+		}
+
+		error = mxt_parse_dt(&client->dev, pdata);
+		if (error)
+			return error;
+	} else
+		pdata = client->dev.platform_data;
+
 	if (!pdata)
 		return -EINVAL;
 
@@ -2336,7 +2569,6 @@
 	data->client = client;
 	data->input_dev = input_dev;
 	data->pdata = pdata;
-	data->irq = client->irq;
 
 	__set_bit(EV_ABS, input_dev->evbit);
 	__set_bit(EV_KEY, input_dev->evbit);
@@ -2394,46 +2626,47 @@
 
 	if (gpio_is_valid(pdata->irq_gpio)) {
 		/* configure touchscreen irq gpio */
-		error = gpio_request(pdata->irq_gpio,
-							"mxt_irq_gpio");
+		error = gpio_request(pdata->irq_gpio, "mxt_irq_gpio");
 		if (error) {
-			pr_err("%s: unable to request gpio [%d]\n", __func__,
+			dev_err(&client->dev, "unable to request gpio [%d]\n",
 						pdata->irq_gpio);
 			goto err_power_on;
 		}
 		error = gpio_direction_input(pdata->irq_gpio);
 		if (error) {
-			pr_err("%s: unable to set_direction for gpio [%d]\n",
-					__func__, pdata->irq_gpio);
+			dev_err(&client->dev,
+				"unable to set direction for gpio [%d]\n",
+				pdata->irq_gpio);
 			goto err_irq_gpio_req;
 		}
+		data->irq = client->irq = gpio_to_irq(pdata->irq_gpio);
+	} else {
+		dev_err(&client->dev, "irq gpio not provided\n");
+		goto err_power_on;
 	}
 
 	if (gpio_is_valid(pdata->reset_gpio)) {
 		/* configure touchscreen reset out gpio */
-		error = gpio_request(pdata->reset_gpio,
-						"mxt_reset_gpio");
+		error = gpio_request(pdata->reset_gpio, "mxt_reset_gpio");
 		if (error) {
-			pr_err("%s: unable to request reset gpio %d\n",
-				__func__, pdata->reset_gpio);
+			dev_err(&client->dev, "unable to request gpio [%d]\n",
+						pdata->reset_gpio);
 			goto err_irq_gpio_req;
 		}
 
-		error = gpio_direction_output(
-					pdata->reset_gpio, 1);
+		error = gpio_direction_output(pdata->reset_gpio, 1);
 		if (error) {
-			pr_err("%s: unable to set direction for gpio %d\n",
-				__func__, pdata->reset_gpio);
+			dev_err(&client->dev,
+				"unable to set direction for gpio [%d]\n",
+				pdata->reset_gpio);
 			goto err_reset_gpio_req;
 		}
 	}
 
 	mxt_reset_delay(data);
-
 	error = mxt_initialize(data);
 	if (error)
 		goto err_reset_gpio_req;
-
 	error = request_threaded_irq(client->irq, NULL, mxt_interrupt,
 			pdata->irqflags, client->dev.driver->name, data);
 	if (error) {
@@ -2540,11 +2773,20 @@
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, mxt_id);
+#ifdef CONFIG_OF
+static struct of_device_id mxt_match_table[] = {
+	{ .compatible = "atmel,mxt-ts",},
+	{ },
+};
+#else
+#define mxt_match_table NULL
+#endif
 
 static struct i2c_driver mxt_driver = {
 	.driver = {
 		.name	= "atmel_mxt_ts",
 		.owner	= THIS_MODULE,
+		.of_match_table = mxt_match_table,
 #ifdef CONFIG_PM
 		.pm	= &mxt_pm_ops,
 #endif
diff --git a/drivers/input/touchscreen/cyttsp-i2c-qc.c b/drivers/input/touchscreen/cyttsp-i2c-qc.c
index d8881a4..e54a24a 100644
--- a/drivers/input/touchscreen/cyttsp-i2c-qc.c
+++ b/drivers/input/touchscreen/cyttsp-i2c-qc.c
@@ -32,6 +32,7 @@
 #include <linux/module.h>
 #include <linux/i2c.h>
 #include <linux/input.h>
+#include <linux/input/mt.h>
 #include <linux/slab.h>
 #include <linux/gpio.h>
 #include <linux/irq.h>
@@ -422,7 +423,7 @@
 static int cyttsp_set_sysinfo_mode(struct cyttsp *ts, u8 sleep)
 {
 	int retval;
-	u8 mode = CY_SYSINFO_MODE + sleep;
+	u8 mode = CY_SYSINFO_MODE | sleep;
 
 	cyttsp_change_state(ts, CY_SYSINFO);
 
@@ -448,10 +449,10 @@
 	return retval;
 }
 
-static void cyttsp_set_opmode(struct cyttsp *ts, u8 sleep)
+static int cyttsp_set_opmode(struct cyttsp *ts, u8 sleep)
 {
 	int retval, tries = 0;
-	u8 host_reg = CY_OP_MODE + sleep;
+	u8 host_reg = CY_OP_MODE | sleep;
 
 	cyttsp_change_state(ts, CY_ACTIVE);
 	do {
@@ -460,6 +461,8 @@
 		if (retval < 0)
 			msleep(20);
 	} while (tries++ < 10 && (retval < 0));
+
+	return retval;
 }
 
 static int cyttsp_set_lp_mode(struct cyttsp *ts)
@@ -878,7 +881,8 @@
 	cyttsp_exit_bl_mode(ts);
 	msleep(100);
 	/* set low power mode and enter application mode*/
-	cyttsp_set_lp_mode(ts);
+	if (ts->platform_data->use_sleep & CY_LOW_PWR_MODE)
+		cyttsp_set_lp_mode(ts);
 }
 
 static void cyttspfw_upgrade_start(struct cyttsp *ts, const u8 *data,
@@ -1154,7 +1158,9 @@
 				tries++ < 100);
 			cyttsp_putbl(ts, 2, true, false, false);
 		}
-		cyttsp_set_lp_mode(ts);
+		if (ts->platform_data->use_sleep & CY_LOW_PWR_MODE)
+			cyttsp_set_lp_mode(ts);
+
 		goto exit_xy_handler;
 	} else {
 		cur_tch = GET_NUM_TOUCHES(g_xy_data.tt_stat);
@@ -1693,22 +1699,9 @@
 			cyttsp_debug("ST->F1:%3d X:%3d Y:%3d Z:%3d\n", \
 				cur_st_tch[CY_ST_FNGR1_IDX], \
 				st_x1, st_y1, st_z1);
-			if (cur_st_tch[CY_ST_FNGR2_IDX] < CY_NUM_TRK_ID) {
-				input_report_key(ts->input, BTN_2, CY_TCH);
-				input_report_abs(ts->input, ABS_HAT0X, st_x2);
-				input_report_abs(ts->input, ABS_HAT0Y, st_y2);
-				cyttsp_debug("ST->F2:%3d X:%3d Y:%3d Z:%3d\n", \
-					cur_st_tch[CY_ST_FNGR2_IDX],
-					st_x2, st_y2, st_z2);
-			} else {
-				input_report_key(ts->input,
-					BTN_2,
-					CY_NTCH);
-			}
 		} else {
 			input_report_abs(ts->input, ABS_PRESSURE, CY_NTCH);
 			input_report_key(ts->input, BTN_TOUCH, CY_NTCH);
-			input_report_key(ts->input, BTN_2, CY_NTCH);
 		}
 		/* update platform data for the current single touch info */
 		ts->prv_st_tch[CY_ST_FNGR1_IDX] = cur_st_tch[CY_ST_FNGR1_IDX];
@@ -1852,6 +1845,9 @@
 					id, tmp_trk[id], \
 					id, snd_trk[id]);
 				if (snd_trk[id] < CY_NUM_TRK_ID) {
+					input_mt_slot(ts->input, snd_trk[id]);
+					input_mt_report_slot_state(ts->input,
+						MT_TOOL_FINGER, true);
 					input_report_abs(ts->input,
 						ABS_MT_TOUCH_MAJOR,
 						cur_mt_z[snd_trk[id]]);
@@ -1864,7 +1860,6 @@
 					input_report_abs(ts->input,
 						ABS_MT_POSITION_Y,
 						cur_mt_pos[snd_trk[id]][CY_YPOS]);
-					CY_MT_SYNC(ts->input);
 					cyttsp_debug("MT1->TID:%2d X:%3d Y:%3d Z:%3d touch-sent\n", \
 						snd_trk[id], \
 						cur_mt_pos[snd_trk[id]][CY_XPOS], \
@@ -1872,19 +1867,10 @@
 						cur_mt_z[snd_trk[id]]);
 				} else if (ts->prv_mt_tch[id] < CY_NUM_TRK_ID) {
 					/* void out this touch */
-					input_report_abs(ts->input,
-						ABS_MT_TOUCH_MAJOR,
-						CY_NTCH);
-					input_report_abs(ts->input,
-						ABS_MT_WIDTH_MAJOR,
-						curr_tool_width);
-					input_report_abs(ts->input,
-						ABS_MT_POSITION_X,
-						ts->prv_mt_pos[ts->prv_mt_tch[id]][CY_XPOS]);
-					input_report_abs(ts->input,
-						ABS_MT_POSITION_Y,
-						ts->prv_mt_pos[ts->prv_mt_tch[id]][CY_YPOS]);
-					CY_MT_SYNC(ts->input);
+					input_mt_slot(ts->input,
+						ts->prv_mt_tch[id]);
+					input_mt_report_slot_state(ts->input,
+						MT_TOOL_FINGER, false);
 					cyttsp_debug("MT2->TID:%2d X:%3d Y:%3d Z:%3d lift off-sent\n", \
 						ts->prv_mt_tch[id], \
 						ts->prv_mt_pos[ts->prv_mt_tch[id]][CY_XPOS], \
@@ -2555,7 +2541,11 @@
 
 	/* switch to System Information mode to read versions
 	 * and set interval registers */
-	retval = cyttsp_set_sysinfo_mode(ts, CY_LOW_PWR_MODE);
+	if (ts->platform_data->use_sleep & CY_LOW_PWR_MODE)
+		retval = cyttsp_set_sysinfo_mode(ts, CY_LOW_PWR_MODE);
+	else
+		retval = cyttsp_set_opmode(ts, CY_OP_MODE);
+
 	if (!(retval < CY_OK)) {
 		retval = i2c_smbus_read_i2c_block_data(ts->client,
 			CY_REG_BASE,
@@ -2577,7 +2567,10 @@
 	/* switch back to Operational mode */
 	cyttsp_debug("switch back to operational mode\n");
 	if (!(retval < CY_OK)) {
-		cyttsp_set_opmode(ts, CY_LOW_PWR_MODE);
+		if (ts->platform_data->use_sleep & CY_LOW_PWR_MODE)
+			cyttsp_set_opmode(ts, CY_LOW_PWR_MODE);
+		else
+			cyttsp_set_opmode(ts, CY_OP_MODE);
 		/* wait for TTSP Device to complete
 		 * switch to Operational mode */
 		msleep(100);
@@ -2667,7 +2660,6 @@
 	set_bit(EV_KEY, input_device->evbit);
 	set_bit(EV_ABS, input_device->evbit);
 	set_bit(BTN_TOUCH, input_device->keybit);
-	set_bit(BTN_2, input_device->keybit);
 	set_bit(INPUT_PROP_DIRECT, input_device->propbit);
 
 	if (ts->platform_data->use_gestures)
@@ -2681,10 +2673,6 @@
 		ABS_TOOL_WIDTH, 0, CY_LARGE_TOOL_WIDTH, 0 , 0);
 	input_set_abs_params(input_device,
 		ABS_PRESSURE, 0, CY_MAXZ, 0, 0);
-	input_set_abs_params(input_device,
-		ABS_HAT0X, 0, ts->platform_data->panel_maxx, 0, 0);
-	input_set_abs_params(input_device,
-		ABS_HAT0Y, 0, ts->platform_data->panel_maxy, 0, 0);
 	if (ts->platform_data->use_gestures) {
 		input_set_abs_params(input_device,
 			ABS_HAT1X, 0, CY_MAXZ, 0, 0);
@@ -2702,6 +2690,7 @@
 			ABS_MT_TOUCH_MAJOR, 0, CY_MAXZ, 0, 0);
 		input_set_abs_params(input_device,
 			ABS_MT_WIDTH_MAJOR, 0, CY_LARGE_TOOL_WIDTH, 0, 0);
+		input_mt_init_slots(input_device, CY_NUM_TRK_ID);
 		if (ts->platform_data->use_trk_id) {
 			input_set_abs_params(input_device,
 				ABS_MT_TRACKING_ID, 0, CY_NUM_TRK_ID, 0, 0);
@@ -2982,7 +2971,8 @@
 #endif /* CONFIG_HAS_EARLYSUSPEND */
 	device_init_wakeup(&client->dev, ts->platform_data->wakeup);
 	mutex_init(&ts->mutex);
-	retval = cyttsp_set_lp_mode(ts);
+	if (ts->platform_data->use_sleep & CY_LOW_PWR_MODE)
+		retval = cyttsp_set_lp_mode(ts);
 
 	cyttsp_info("Start Probe %s\n", \
 		(retval < CY_OK) ? "FAIL" : "PASS");
@@ -3119,7 +3109,10 @@
 	cyttsp_debug("Wake Up %s\n", \
 		(retval < CY_OK) ? "FAIL" : "PASS");
 
-	return cyttsp_set_lp_mode(ts);
+	if (ts->platform_data->use_sleep & CY_LOW_PWR_MODE)
+		retval = cyttsp_set_lp_mode(ts);
+
+	return retval;
 }
 
 /* Function to manage low power suspend */
diff --git a/drivers/iommu/msm_iommu-v2.c b/drivers/iommu/msm_iommu-v2.c
index 28ad0ff..c7f6b82 100644
--- a/drivers/iommu/msm_iommu-v2.c
+++ b/drivers/iommu/msm_iommu-v2.c
@@ -256,19 +256,30 @@
 		SET_SMR_MASK(base, num, 0);
 		SET_SMR_ID(base, num, sids[i]);
 
-		/* Set VMID = 0 */
 		SET_S2CR_N(base, num, 0);
 		SET_S2CR_CBNDX(base, num, ctx);
+		SET_S2CR_MEMATTR(base, num, 0x0A);
 		/* Set security bit override to be Non-secure */
-		SET_S2CR_NSCFG(base, sids[i], 3);
-
-		SET_CBAR_N(base, ctx, 0);
-		/* Stage 1 Context with Stage 2 bypass */
-		SET_CBAR_TYPE(base, ctx, 1);
-		/* Route page faults to the non-secure interrupt */
-		SET_CBAR_IRPTNDX(base, ctx, 1);
+		SET_S2CR_NSCFG(base, num, 3);
 	}
 
+	SET_CBAR_N(base, ctx, 0);
+
+	/* Stage 1 Context with Stage 2 bypass */
+	SET_CBAR_TYPE(base, ctx, 1);
+
+	/* Route page faults to the non-secure interrupt */
+	SET_CBAR_IRPTNDX(base, ctx, 1);
+
+	/* Set VMID to non-secure HLOS */
+	SET_CBAR_VMID(base, ctx, 3);
+
+	/* Bypass is treated as inner-shareable */
+	SET_CBAR_BPSHCFG(base, ctx, 2);
+
+	/* Do not downgrade memory attributes */
+	SET_CBAR_MEMATTR(base, ctx, 0x0A);
+
        /* Find if this page table is used elsewhere, and re-use ASID */
 	found = 0;
 	for (i = 0; i < ncb; i++)
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 9240605..26e8496 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -307,6 +307,16 @@
 	  This option enables support for LEDs connected to the PCA9633
 	  LED driver chip accessed via the I2C bus.
 
+config LEDS_QPNP
+	tristate "Support for QPNP LEDs"
+	depends on SPMI && OF_SPMI
+	help
+	  This driver supports the leds functionality of Qualcomm PNP PMIC.  It
+	  includes RGB Leds, WLED and Flash Led.
+
+	  To compile this driver as a module, choose M here: the module will
+	  be called leds-qpnp.
+
 config LEDS_WM831X_STATUS
 	tristate "LED support for status LEDs on WM831x PMICs"
 	depends on LEDS_CLASS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 8edd465..c688898 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -19,6 +19,7 @@
 obj-$(CONFIG_LEDS_SUNFIRE)		+= leds-sunfire.o
 obj-$(CONFIG_LEDS_PCA9532)		+= leds-pca9532.o
 obj-$(CONFIG_LEDS_PM8XXX)		+= leds-pm8xxx.o
+obj-$(CONFIG_LEDS_QPNP)			+= leds-qpnp.o
 obj-$(CONFIG_LEDS_GPIO_REGISTER)	+= leds-gpio-register.o
 obj-$(CONFIG_LEDS_GPIO)			+= leds-gpio.o
 obj-$(CONFIG_LEDS_LP3944)		+= leds-lp3944.o
diff --git a/drivers/leds/leds-pm8xxx.c b/drivers/leds/leds-pm8xxx.c
index 04041e4..255920e 100644
--- a/drivers/leds/leds-pm8xxx.c
+++ b/drivers/leds/leds-pm8xxx.c
@@ -80,6 +80,17 @@
 
 #define WLED_SYNC_VAL			0x07
 #define WLED_SYNC_RESET_VAL		0x00
+#define WLED_SYNC_MASK			0xF8
+
+#define ONE_WLED_STRING			1
+#define TWO_WLED_STRINGS		2
+#define THREE_WLED_STRINGS		3
+
+#define WLED_CABC_ONE_STRING		0x01
+#define WLED_CABC_TWO_STRING		0x03
+#define WLED_CABC_THREE_STRING		0x07
+
+#define WLED_CABC_SHIFT			3
 
 #define SSBI_REG_ADDR_RGB_CNTL1		0x12D
 #define SSBI_REG_ADDR_RGB_CNTL2		0x12E
@@ -290,17 +301,23 @@
 			return rc;
 		}
 	}
-
+	rc = pm8xxx_readb(led->dev->parent, WLED_SYNC_REG, &val);
+	if (rc) {
+		dev_err(led->dev->parent,
+			"can't read wled sync register rc=%d\n", rc);
+		return rc;
+	}
 	/* sync */
-	val = WLED_SYNC_VAL;
+	val &= WLED_SYNC_MASK;
+	val |= WLED_SYNC_VAL;
 	rc = pm8xxx_writeb(led->dev->parent, WLED_SYNC_REG, val);
 	if (rc) {
 		dev_err(led->dev->parent,
 			"can't read wled sync register rc=%d\n", rc);
 		return rc;
 	}
-
-	val = WLED_SYNC_RESET_VAL;
+	val &= WLED_SYNC_MASK;
+	val |= WLED_SYNC_RESET_VAL;
 	rc = pm8xxx_writeb(led->dev->parent, WLED_SYNC_REG, val);
 	if (rc) {
 		dev_err(led->dev->parent,
@@ -656,6 +673,36 @@
 		}
 	}
 
+	if (led->wled_cfg->cabc_en) {
+		rc = pm8xxx_readb(led->dev->parent, WLED_SYNC_REG, &val);
+		if (rc) {
+			dev_err(led->dev->parent,
+				"can't read cabc register rc=%d\n", rc);
+			return rc;
+		}
+
+		switch (num_wled_strings) {
+		case ONE_WLED_STRING:
+			val |= (WLED_CABC_ONE_STRING << WLED_CABC_SHIFT);
+			break;
+		case TWO_WLED_STRINGS:
+			val |= (WLED_CABC_TWO_STRING << WLED_CABC_SHIFT);
+			break;
+		case THREE_WLED_STRINGS:
+			val |= (WLED_CABC_THREE_STRING << WLED_CABC_SHIFT);
+			break;
+		default:
+			break;
+		}
+
+		rc = pm8xxx_writeb(led->dev->parent, WLED_SYNC_REG, val);
+		if (rc) {
+			dev_err(led->dev->parent,
+				"can't write to enable cabc rc=%d\n", rc);
+			return rc;
+		}
+	}
+
 	/* program digital module generator, cs out and enable the module */
 	rc = pm8xxx_readb(led->dev->parent, WLED_MOD_CTRL_REG, &val);
 	if (rc) {
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
new file mode 100644
index 0000000..f42fb5e
--- /dev/null
+++ b/drivers/leds/leds-qpnp.c
@@ -0,0 +1,725 @@
+
+/* 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/slab.h>
+#include <linux/leds.h>
+#include <linux/err.h>
+#include <linux/of_platform.h>
+#include <linux/of_device.h>
+#include <linux/spmi.h>
+
+#define WLED_MOD_EN_REG(base, n)	(base + 0x60 + n*0x10)
+#define WLED_IDAC_DLY_REG(base, n)	(WLED_MOD_EN_REG(base, n) + 0x01)
+#define WLED_FULL_SCALE_REG(base, n)	(WLED_IDAC_DLY_REG(base, n) + 0x01)
+
+/* wled control registers */
+#define WLED_BRIGHTNESS_CNTL_LSB(base, n)	(base + 0x40 + 2*n)
+#define WLED_BRIGHTNESS_CNTL_MSB(base, n)	(base + 0x41 + 2*n)
+#define WLED_MOD_CTRL_REG(base)			(base + 0x46)
+#define WLED_SYNC_REG(base)			(base + 0x47)
+#define WLED_FDBCK_CTRL_REG(base)		(base + 0x48)
+#define WLED_SWITCHING_FREQ_REG(base)		(base + 0x4C)
+#define WLED_OVP_CFG_REG(base)			(base + 0x4D)
+#define WLED_BOOST_LIMIT_REG(base)		(base + 0x4E)
+#define WLED_CURR_SINK_REG(base)		(base + 0x4F)
+#define WLED_HIGH_POLE_CAP_REG(base)		(base + 0x58)
+#define WLED_CURR_SINK_MASK		0xE0
+#define WLED_CURR_SINK_SHFT		0x05
+#define WLED_SWITCH_FREQ_MASK		0x02
+#define WLED_OVP_VAL_MASK		0x03
+#define WLED_OVP_VAL_BIT_SHFT		0x00
+#define WLED_BOOST_LIMIT_MASK		0x07
+#define WLED_BOOST_LIMIT_BIT_SHFT	0x00
+#define WLED_BOOST_ON			0x80
+#define WLED_BOOST_OFF			0x00
+#define WLED_EN_MASK			0x80
+#define WLED_NO_MASK			0x00
+#define WLED_CP_SELECT_MAX		0x03
+#define WLED_CP_SELECT_MASK		0x02
+#define WLED_USE_EXT_GEN_MOD_SRC	0x01
+#define WLED_CTL_DLY_STEP		200
+#define WLED_CTL_DLY_MAX		1400
+#define WLED_MAX_CURR			25
+#define WLED_MSB_MASK			0x0F
+#define WLED_MAX_CURR_MASK		0x19
+#define WLED_OP_FDBCK_MASK		0x07
+#define WLED_OP_FDBCK_BIT_SHFT		0x00
+
+#define WLED_MAX_LEVEL			255
+#define WLED_8_BIT_MASK			0xFF
+#define WLED_4_BIT_MASK			0x0F
+#define WLED_8_BIT_SHFT			0x08
+#define WLED_MAX_DUTY_CYCLE		0xFFF
+
+#define WLED_SYNC_VAL			0x07
+#define WLED_SYNC_RESET_VAL		0x00
+
+#define WLED_TRIGGER_DEFAULT		"none"
+#define WLED_FLAGS_DEFAULT		0x00
+#define WLED_DEFAULT_STRINGS		0x01
+#define WLED_DEFAULT_OVP_VAL		0x02
+#define WLED_BOOST_LIM_DEFAULT		0x03
+#define WLED_CP_SEL_DEFAULT		0x00
+#define WLED_CTRL_DLY_DEFAULT		0x00
+#define WLED_SWITCH_FREQ_DEFAULT	0x02
+
+/**
+ * enum qpnp_leds - QPNP supported led ids
+ * @QPNP_ID_WLED - White led backlight
+ */
+enum qpnp_leds {
+	QPNP_ID_WLED,
+};
+
+/* current boost limit */
+enum wled_current_boost_limit {
+	WLED_CURR_LIMIT_105mA,
+	WLED_CURR_LIMIT_385mA,
+	WLED_CURR_LIMIT_525mA,
+	WLED_CURR_LIMIT_805mA,
+	WLED_CURR_LIMIT_980mA,
+	WLED_CURR_LIMIT_1260mA,
+	WLED_CURR_LIMIT_1400mA,
+	WLED_CURR_LIMIT_1680mA,
+};
+
+/* over voltage protection threshold */
+enum wled_ovp_threshold {
+	WLED_OVP_35V,
+	WLED_OVP_32V,
+	WLED_OVP_29V,
+	WLED_OVP_37V,
+};
+
+/* switch frquency */
+enum wled_switch_freq {
+	WLED_800kHz = 0,
+	WLED_960kHz,
+	WLED_1600kHz,
+	WLED_3200kHz,
+};
+
+static u8 wled_debug_regs[] = {
+	/* common registers */
+	0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4d, 0x4e, 0x4f,
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+	/* LED1 */
+	0x60, 0x61, 0x62, 0x63, 0x66,
+	/* LED1 */
+	0x70, 0x71, 0x72, 0x73, 0x76,
+	/* LED1 */
+	0x80, 0x81, 0x82, 0x83, 0x86,
+};
+
+/**
+ *  wled_config_data - wled configuration data
+ *  @num_strings - number of wled strings supported
+ *  @ovp_val - over voltage protection threshold
+ *  @boost_curr_lim - boot current limit
+ *  @cp_select - high pole capacitance
+ *  @ctrl_delay_us - delay in activation of led
+ *  @dig_mod_gen_en - digital module generator
+ *  @cs_out_en - current sink output enable
+ *  @op_fdbck - selection of output as feedback for the boost
+ */
+struct wled_config_data {
+	u8	num_strings;
+	u8	ovp_val;
+	u8	boost_curr_lim;
+	u8	cp_select;
+	u8	ctrl_delay_us;
+	u8	switch_freq;
+	bool	dig_mod_gen_en;
+	bool	cs_out_en;
+	bool	op_fdbck;
+};
+
+/**
+ * struct qpnp_led_data - internal led data structure
+ * @led_classdev - led class device
+ * @id - led index
+ * @base_reg - base register given in device tree
+ * @lock - to protect the transactions
+ * @reg - cached value of led register
+ * @max_current - maximum current supported by LED
+ * @default_on - true: default state max, false, default state 0
+ */
+struct qpnp_led_data {
+	struct led_classdev	cdev;
+	struct spmi_device	*spmi_dev;
+	int			id;
+	u16			base;
+	u8			reg;
+	struct mutex		lock;
+	struct wled_config_data *wled_cfg;
+	int			max_current;
+	bool			default_on;
+};
+
+static int
+qpnp_led_masked_write(struct qpnp_led_data *led, u16 addr, u8 mask, u8 val)
+{
+	int rc;
+	u8 reg;
+
+	rc = spmi_ext_register_readl(led->spmi_dev->ctrl, led->spmi_dev->sid,
+		addr, &reg, 1);
+	if (rc) {
+		dev_err(&led->spmi_dev->dev,
+			"Unable to read from addr=%x, rc(%d)\n", addr, rc);
+	}
+
+	reg &= ~mask;
+	reg |= val;
+
+	rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
+		addr, &reg, 1);
+	if (rc)
+		dev_err(&led->spmi_dev->dev,
+			"Unable to write to addr=%x, rc(%d)\n", addr, rc);
+	return rc;
+}
+
+static int qpnp_wled_set(struct qpnp_led_data *led)
+{
+	int rc, duty;
+	u8 level, val, i, num_wled_strings;
+
+	level = led->cdev.brightness;
+
+	if (level > WLED_MAX_LEVEL)
+		level = WLED_MAX_LEVEL;
+	if (level == 0) {
+		val = WLED_BOOST_OFF;
+		rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
+			led->spmi_dev->sid, WLED_MOD_CTRL_REG(led->base),
+			&val, 1);
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+				"WLED write ctrl reg failed(%d)\n", rc);
+			return rc;
+		}
+	} else {
+		val = WLED_BOOST_ON;
+		rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
+			led->spmi_dev->sid, WLED_MOD_CTRL_REG(led->base),
+			&val, 1);
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+				"WLED write ctrl reg failed(%d)\n", rc);
+			return rc;
+		}
+	}
+
+	duty = (WLED_MAX_DUTY_CYCLE * level) / WLED_MAX_LEVEL;
+
+	num_wled_strings = led->wled_cfg->num_strings;
+
+	/* program brightness control registers */
+	for (i = 0; i < num_wled_strings; i++) {
+		rc = qpnp_led_masked_write(led,
+			WLED_BRIGHTNESS_CNTL_MSB(led->base, i), WLED_MSB_MASK,
+			(duty >> WLED_8_BIT_SHFT) & WLED_4_BIT_MASK);
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+				"WLED set brightness MSB failed(%d)\n", rc);
+			return rc;
+		}
+		val = duty & WLED_8_BIT_MASK;
+		rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
+			led->spmi_dev->sid,
+			WLED_BRIGHTNESS_CNTL_LSB(led->base, i), &val, 1);
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+				"WLED set brightness LSB failed(%d)\n", rc);
+			return rc;
+		}
+	}
+
+	/* sync */
+	val = WLED_SYNC_VAL;
+	rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
+		WLED_SYNC_REG(led->base), &val, 1);
+	if (rc) {
+		dev_err(&led->spmi_dev->dev,
+				"WLED set sync reg failed(%d)\n", rc);
+		return rc;
+	}
+
+	val = WLED_SYNC_RESET_VAL;
+	rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
+		WLED_SYNC_REG(led->base), &val, 1);
+	if (rc) {
+		dev_err(&led->spmi_dev->dev,
+				"WLED reset sync reg failed(%d)\n", rc);
+		return rc;
+	}
+	return 0;
+}
+
+static void qpnp_wled_dump_regs(struct qpnp_led_data *led)
+{
+	int i;
+	u8 val;
+
+	pr_debug("===== WLED register dump start =====\n");
+	for (i = 0; i < ARRAY_SIZE(wled_debug_regs); i++) {
+		spmi_ext_register_readl(led->spmi_dev->ctrl,
+					led->spmi_dev->sid,
+					led->base + wled_debug_regs[i],
+					&val, sizeof(val));
+		pr_debug("0x%x = 0x%x\n", led->base + wled_debug_regs[i], val);
+	}
+	pr_debug("===== WLED register dump end =====\n");
+}
+
+static void qpnp_led_set(struct led_classdev *led_cdev,
+				enum led_brightness value)
+{
+	int rc;
+	struct qpnp_led_data *led;
+
+	led = container_of(led_cdev, struct qpnp_led_data, cdev);
+
+	if (value < LED_OFF || value > led->cdev.max_brightness) {
+		dev_err(led->cdev.dev, "Invalid brightness value\n");
+		return;
+	}
+
+	mutex_lock(&led->lock);
+	led->cdev.brightness = value;
+
+	switch (led->id) {
+	case QPNP_ID_WLED:
+		rc = qpnp_wled_set(led);
+		if (rc < 0)
+			dev_err(led->cdev.dev,
+				"WLED set brightness failed (%d)\n", rc);
+		break;
+	default:
+		dev_err(led->cdev.dev, "Invalid LED(%d)\n", led->id);
+		break;
+	}
+	mutex_unlock(&led->lock);
+}
+
+static int __devinit qpnp_led_set_max_brightness(struct qpnp_led_data *led)
+{
+	switch (led->id) {
+	case QPNP_ID_WLED:
+		led->cdev.max_brightness = WLED_MAX_LEVEL;
+		break;
+	default:
+		dev_err(led->cdev.dev, "Invalid LED(%d)\n", led->id);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static enum led_brightness qpnp_led_get(struct led_classdev *led_cdev)
+{
+	struct qpnp_led_data *led;
+
+	led = container_of(led_cdev, struct qpnp_led_data, cdev);
+
+	return led->cdev.brightness;
+}
+
+static int __devinit qpnp_wled_init(struct qpnp_led_data *led)
+{
+	int rc, i;
+	u8 num_wled_strings;
+
+	num_wled_strings = led->wled_cfg->num_strings;
+
+	/* verify ranges */
+	if (led->wled_cfg->ovp_val > WLED_OVP_37V) {
+		dev_err(&led->spmi_dev->dev, "Invalid ovp value\n");
+		return -EINVAL;
+	}
+
+	if (led->wled_cfg->boost_curr_lim > WLED_CURR_LIMIT_1680mA) {
+		dev_err(&led->spmi_dev->dev, "Invalid boost current limit\n");
+		return -EINVAL;
+	}
+
+	if (led->wled_cfg->cp_select > WLED_CP_SELECT_MAX) {
+		dev_err(&led->spmi_dev->dev, "Invalid pole capacitance\n");
+		return -EINVAL;
+	}
+
+	if ((led->max_current > WLED_MAX_CURR)) {
+		dev_err(&led->spmi_dev->dev, "Invalid max current\n");
+		return -EINVAL;
+	}
+
+	if ((led->wled_cfg->ctrl_delay_us % WLED_CTL_DLY_STEP) ||
+		(led->wled_cfg->ctrl_delay_us > WLED_CTL_DLY_MAX)) {
+		dev_err(&led->spmi_dev->dev, "Invalid control delay\n");
+		return -EINVAL;
+	}
+
+	/* program over voltage protection threshold */
+	rc = qpnp_led_masked_write(led, WLED_OVP_CFG_REG(led->base),
+		WLED_OVP_VAL_MASK,
+		(led->wled_cfg->ovp_val << WLED_OVP_VAL_BIT_SHFT));
+	if (rc) {
+		dev_err(&led->spmi_dev->dev,
+				"WLED OVP reg write failed(%d)\n", rc);
+		return rc;
+	}
+
+	/* program current boost limit */
+	rc = qpnp_led_masked_write(led, WLED_BOOST_LIMIT_REG(led->base),
+		WLED_BOOST_LIMIT_MASK, led->wled_cfg->boost_curr_lim);
+	if (rc) {
+		dev_err(&led->spmi_dev->dev,
+				"WLED boost limit reg write failed(%d)\n", rc);
+		return rc;
+	}
+
+	/* program output feedback */
+	rc = qpnp_led_masked_write(led, WLED_FDBCK_CTRL_REG(led->base),
+		WLED_OP_FDBCK_MASK,
+		(led->wled_cfg->op_fdbck << WLED_OP_FDBCK_BIT_SHFT));
+	if (rc) {
+		dev_err(&led->spmi_dev->dev,
+				"WLED fdbck ctrl reg write failed(%d)\n", rc);
+		return rc;
+	}
+
+	/* program switch frequency */
+	rc = qpnp_led_masked_write(led, WLED_SWITCHING_FREQ_REG(led->base),
+		WLED_SWITCH_FREQ_MASK, led->wled_cfg->switch_freq);
+	if (rc) {
+		dev_err(&led->spmi_dev->dev,
+				"WLED switch freq reg write failed(%d)\n", rc);
+		return rc;
+	}
+
+	/* program current sink */
+	if (led->wled_cfg->cs_out_en) {
+		rc = qpnp_led_masked_write(led, WLED_CURR_SINK_REG(led->base),
+			WLED_CURR_SINK_MASK,
+			(led->wled_cfg->num_strings << WLED_CURR_SINK_SHFT));
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+				"WLED curr sink reg write failed(%d)\n", rc);
+			return rc;
+		}
+	}
+
+	/* program high pole capacitance */
+	rc = qpnp_led_masked_write(led, WLED_HIGH_POLE_CAP_REG(led->base),
+		WLED_CP_SELECT_MASK, led->wled_cfg->cp_select);
+	if (rc) {
+		dev_err(&led->spmi_dev->dev,
+				"WLED pole cap reg write failed(%d)\n", rc);
+		return rc;
+	}
+
+	/* program modulator, current mod src and cabc */
+	for (i = 0; i < num_wled_strings; i++) {
+		rc = qpnp_led_masked_write(led, WLED_MOD_EN_REG(led->base, i),
+			WLED_NO_MASK, WLED_EN_MASK);
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+				"WLED mod enable reg write failed(%d)\n", rc);
+			return rc;
+		}
+
+		if (led->wled_cfg->dig_mod_gen_en) {
+			rc = qpnp_led_masked_write(led,
+				WLED_MOD_EN_REG(led->base, i),
+				WLED_NO_MASK, WLED_USE_EXT_GEN_MOD_SRC);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+				"WLED dig mod en reg write failed(%d)\n", rc);
+			}
+		}
+
+		rc = qpnp_led_masked_write(led,
+			WLED_FULL_SCALE_REG(led->base, i), WLED_MAX_CURR_MASK,
+			led->max_current);
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+				"WLED max current reg write failed(%d)\n", rc);
+			return rc;
+		}
+
+	}
+
+	/* dump wled registers */
+	qpnp_wled_dump_regs(led);
+
+	return 0;
+}
+
+static int __devinit qpnp_led_initialize(struct qpnp_led_data *led)
+{
+	int rc;
+
+	switch (led->id) {
+	case QPNP_ID_WLED:
+		rc = qpnp_wled_init(led);
+		if (rc)
+			dev_err(led->cdev.dev,
+				"WLED initialize failed(%d)\n", rc);
+		break;
+	default:
+		dev_err(led->cdev.dev, "Invalid LED(%d)\n", led->id);
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
+
+/*
+ * Handlers for alternative sources of platform_data
+ */
+static int __devinit qpnp_get_config_wled(struct qpnp_led_data *led,
+				struct device_node *node)
+{
+	u32 val;
+	int rc;
+	const char *temp_string;
+
+	led->id = QPNP_ID_WLED;
+
+	led->wled_cfg = devm_kzalloc(&led->spmi_dev->dev,
+				sizeof(struct wled_config_data), GFP_KERNEL);
+	if (!led->wled_cfg) {
+		dev_err(&led->spmi_dev->dev, "Unable to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	led->cdev.default_trigger = WLED_TRIGGER_DEFAULT;
+	rc = of_property_read_string(node, "linux,default-trigger",
+		&temp_string);
+	if (!rc)
+		led->cdev.default_trigger = temp_string;
+	else if (rc != -EINVAL)
+		return rc;
+
+
+	led->cdev.flags = WLED_FLAGS_DEFAULT;
+	rc = of_property_read_u32(node, "qcom,flags", &val);
+	if (!rc)
+		led->cdev.flags = (int) val;
+	else if (rc != -EINVAL)
+		return rc;
+
+	led->default_on = true;
+	rc = of_property_read_string(node, "qcom,default-state",
+		&temp_string);
+	if (!rc) {
+		if (!strncmp(temp_string, "off", sizeof("off")))
+			led->default_on = false;
+	} else if (rc != -EINVAL)
+		return rc;
+
+	led->wled_cfg->num_strings = WLED_DEFAULT_STRINGS;
+	rc = of_property_read_u32(node, "qcom,num-strings", &val);
+	if (!rc)
+		led->wled_cfg->num_strings = (u8) val;
+	else if (rc != -EINVAL)
+		return rc;
+
+	led->wled_cfg->ovp_val = WLED_DEFAULT_OVP_VAL;
+	rc = of_property_read_u32(node, "qcom,ovp-val", &val);
+	if (!rc)
+		led->wled_cfg->ovp_val = (u8) val;
+	else if (rc != -EINVAL)
+		return rc;
+
+	led->wled_cfg->boost_curr_lim = WLED_BOOST_LIM_DEFAULT;
+	rc = of_property_read_u32(node, "qcom,boost-curr-lim", &val);
+	if (!rc)
+		led->wled_cfg->boost_curr_lim = (u8) val;
+	else if (rc != -EINVAL)
+		return rc;
+
+	led->wled_cfg->cp_select = WLED_CP_SEL_DEFAULT;
+	rc = of_property_read_u32(node, "qcom,cp-sel", &val);
+	if (!rc)
+		led->wled_cfg->cp_select = (u8) val;
+	else if (rc != -EINVAL)
+		return rc;
+
+	led->wled_cfg->ctrl_delay_us = WLED_CTRL_DLY_DEFAULT;
+	rc = of_property_read_u32(node, "qcom,ctrl-delay-us", &val);
+	if (!rc)
+		led->wled_cfg->ctrl_delay_us = (u8) val;
+	else if (rc != -EINVAL)
+		return rc;
+
+	led->wled_cfg->switch_freq = WLED_SWITCH_FREQ_DEFAULT;
+	rc = of_property_read_u32(node, "qcom,switch-freq", &val);
+	if (!rc)
+		led->wled_cfg->switch_freq = (u8) val;
+	else if (rc != -EINVAL)
+		return rc;
+
+	led->wled_cfg->dig_mod_gen_en =
+		of_property_read_bool(node, "qcom,dig-mod-gen-en");
+
+	led->wled_cfg->cs_out_en =
+		of_property_read_bool(node, "qcom,cs-out-en");
+
+	led->wled_cfg->op_fdbck =
+		of_property_read_bool(node, "qcom,op-fdbck");
+
+	return 0;
+}
+
+static int __devinit qpnp_leds_probe(struct spmi_device *spmi)
+{
+	struct qpnp_led_data *led;
+	struct resource *led_resource;
+	struct device_node *node;
+	int rc;
+	const char *led_label;
+
+	led = devm_kzalloc(&spmi->dev, (sizeof(struct qpnp_led_data)),
+		GFP_KERNEL);
+	if (!led) {
+		dev_err(&spmi->dev, "Unable to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	led->spmi_dev = spmi;
+
+	led_resource = spmi_get_resource(spmi, NULL, IORESOURCE_MEM, 0);
+	if (!led_resource) {
+		dev_err(&spmi->dev, "Unable to get LED base address\n");
+		return -ENXIO;
+	}
+	led->base = led_resource->start;
+
+	dev_set_drvdata(&spmi->dev, led);
+
+	node = led->spmi_dev->dev.of_node;
+	if (node == NULL)
+		return -ENODEV;
+
+	rc = of_property_read_string(node, "qcom,label", &led_label);
+	if (rc < 0) {
+		dev_err(&led->spmi_dev->dev,
+			"Failure reading label, rc = %d\n", rc);
+		return rc;
+	}
+
+	rc = of_property_read_string(node, "qcom,name", &led->cdev.name);
+	if (rc < 0) {
+		dev_err(&led->spmi_dev->dev,
+			"Failure reading led name, rc = %d\n", rc);
+		return rc;
+	}
+
+	rc = of_property_read_u32(node, "qcom,max-current", &led->max_current);
+	if (rc < 0) {
+		dev_err(&led->spmi_dev->dev,
+			"Failure reading max_current, rc =  %d\n", rc);
+		return rc;
+	}
+
+	led->cdev.brightness_set    = qpnp_led_set;
+	led->cdev.brightness_get    = qpnp_led_get;
+	led->cdev.brightness	= LED_OFF;
+
+	if (strncmp(led_label, "wled", sizeof("wled")) == 0) {
+		rc = qpnp_get_config_wled(led, node);
+		if (rc < 0) {
+			dev_err(&led->spmi_dev->dev,
+				"Unable to read wled config data\n");
+			return rc;
+		}
+	} else {
+		dev_err(&led->spmi_dev->dev, "No LED matching label\n");
+		return -EINVAL;
+	}
+
+	mutex_init(&led->lock);
+
+	rc =  qpnp_led_initialize(led);
+	if (rc < 0)
+		goto fail_id_check;
+
+	rc = qpnp_led_set_max_brightness(led);
+	if (rc < 0)
+		goto fail_id_check;
+
+
+	rc = led_classdev_register(&spmi->dev, &led->cdev);
+	if (rc) {
+		dev_err(&spmi->dev, "unable to register led %d,rc=%d\n",
+					 led->id, rc);
+		goto fail_id_check;
+	}
+
+	/* configure default state */
+	if (led->default_on)
+		led->cdev.brightness = led->cdev.max_brightness;
+
+	qpnp_led_set(&led->cdev, led->cdev.brightness);
+
+	return 0;
+
+fail_id_check:
+	mutex_destroy(&led->lock);
+	led_classdev_unregister(&led->cdev);
+	return rc;
+}
+
+static int __devexit qpnp_leds_remove(struct spmi_device *spmi)
+{
+	struct qpnp_led_data *led  = dev_get_drvdata(&spmi->dev);
+
+	mutex_destroy(&led->lock);
+	led_classdev_unregister(&led->cdev);
+
+	return 0;
+}
+static struct of_device_id spmi_match_table[] = {
+	{	.compatible = "qcom,leds-qpnp",
+	}
+};
+
+static struct spmi_driver qpnp_leds_driver = {
+	.driver		= {
+		.name	= "qcom,leds-qpnp",
+		.of_match_table = spmi_match_table,
+	},
+	.probe		= qpnp_leds_probe,
+	.remove		= __devexit_p(qpnp_leds_remove),
+};
+
+static int __init qpnp_led_init(void)
+{
+	return spmi_driver_register(&qpnp_leds_driver);
+}
+module_init(qpnp_led_init);
+
+static void __exit qpnp_led_exit(void)
+{
+	spmi_driver_unregister(&qpnp_leds_driver);
+}
+module_exit(qpnp_led_exit);
+
+MODULE_DESCRIPTION("QPNP LEDs driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("leds:leds-qpnp");
diff --git a/drivers/media/dvb/mpq/Kconfig b/drivers/media/dvb/mpq/Kconfig
index 868ad8c..766312c 100644
--- a/drivers/media/dvb/mpq/Kconfig
+++ b/drivers/media/dvb/mpq/Kconfig
@@ -8,5 +8,5 @@
 	  Say Y or M if you own such a device and want to use it.
 
 source "drivers/media/dvb/mpq/demux/Kconfig"
-
+source "drivers/media/dvb/mpq/video/Kconfig"
 
diff --git a/drivers/media/dvb/mpq/Makefile b/drivers/media/dvb/mpq/Makefile
index 7ccf13e..a8d7137 100644
--- a/drivers/media/dvb/mpq/Makefile
+++ b/drivers/media/dvb/mpq/Makefile
@@ -1,5 +1,5 @@
 
 obj-$(CONFIG_DVB_MPQ)	    += adapter/
 obj-$(CONFIG_DVB_MPQ_DEMUX) += demux/
-
+obj-$(CONFIG_DVB_MPQ_VIDEO) += video/
 
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.h b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.h
index 68cfcd1..893273d 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.h
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.h
@@ -13,7 +13,7 @@
 #ifndef _MPQ_DMX_PLUGIN_COMMON_H
 #define _MPQ_DMX_PLUGIN_COMMON_H
 
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
 
 #include "dvbdev.h"
 #include "dmxdev.h"
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/dvb/mpq/video/Kconfig b/drivers/media/dvb/mpq/video/Kconfig
new file mode 100644
index 0000000..1344a67
--- /dev/null
+++ b/drivers/media/dvb/mpq/video/Kconfig
@@ -0,0 +1,16 @@
+config DVB_MPQ_VIDEO
+	tristate "DVB Video Device"
+	depends on DVB_MPQ
+
+	---help---
+	  This is a dvb/video interface with extensions for
+	  Qualcomm Chipset Video hardware. For dvb/video
+	  specification please check http://linuxtv.org/
+
+	  Say Y or M if you own such a device and want to use it.
+
+config DVB_MPQ_NUM_VIDEO_DEVICES
+	int "Number of video devices"
+	depends on DVB_MPQ_VIDEO
+	default 4
+	range 1 255
diff --git a/drivers/media/dvb/mpq/video/Makefile b/drivers/media/dvb/mpq/video/Makefile
new file mode 100644
index 0000000..38c1091
--- /dev/null
+++ b/drivers/media/dvb/mpq/video/Makefile
@@ -0,0 +1,5 @@
+
+ccflags-y += -Idrivers/media/dvb/dvb-core/
+ccflags-y += -Idrivers/media/dvb/mpq/include/
+
+obj-$(CONFIG_DVB_MPQ_VIDEO) += mpq_dvb_video.o
diff --git a/drivers/media/dvb/mpq/video/mpq_dvb_video.c b/drivers/media/dvb/mpq/video/mpq_dvb_video.c
new file mode 100644
index 0000000..68653ba
--- /dev/null
+++ b/drivers/media/dvb/mpq/video/mpq_dvb_video.c
@@ -0,0 +1,2405 @@
+/* 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
+ * 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/cdev.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/poll.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/kthread.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+#include <linux/android_pmem.h>
+#include <linux/clk.h>
+#include <linux/timer.h>
+#include <mach/msm_subsystem_map.h>
+#include <media/msm/vidc_type.h>
+#include <media/msm/vcd_api.h>
+#include <media/msm/vidc_init.h>
+#include "mpq_dvb_video_internal.h"
+
+
+#define DBG(x...) pr_debug(x)
+#define INFO(x...) pr_info(x)
+#define ERR(x...) pr_err(x)
+
+#define MPQ_VID_DEC_NAME "mpq_vidc_dec"
+static unsigned int vidc_mmu_subsystem[] = {
+	MSM_SUBSYSTEM_VIDEO};
+
+static char vid_thread_names[DVB_MPQ_NUM_VIDEO_DEVICES][10] = {
+				"dvb-vid-0",
+				"dvb-vid-1",
+				"dvb-vid-2",
+				"dvb-vid-3",
+};
+
+static int mpq_int_vid_dec_decode_frame(struct video_client_ctx *client_ctx,
+				struct video_data_buffer *input_frame);
+
+static struct mpq_dvb_video_dev *mpq_dvb_video_device;
+
+static int mpq_get_dev_frm_client(struct video_client_ctx *client_ctx,
+				struct mpq_dvb_video_inst **dev_inst)
+{
+	int i;
+
+	for (i = 0; i < DVB_MPQ_NUM_VIDEO_DEVICES; i++) {
+		if (mpq_dvb_video_device->dev_inst[i].client_ctx ==
+						client_ctx) {
+			*dev_inst = &mpq_dvb_video_device->dev_inst[i];
+			break;
+		}
+	}
+
+	if (i == DVB_MPQ_NUM_VIDEO_DEVICES)
+		return -ENODEV;
+
+	return 0;
+}
+
+static u32 mpq_int_check_bcast_mq(struct mpq_dmx_src_data *dmx_data)
+{
+	u32 islist_empty = 0;
+	mutex_lock(&dmx_data->msg_queue_lock);
+	islist_empty = list_empty(&dmx_data->msg_queue);
+	mutex_unlock(&dmx_data->msg_queue_lock);
+
+	return !islist_empty;
+}
+
+static void mpq_get_frame_and_write(struct mpq_dvb_video_inst *dev_inst,
+				unsigned int free_buf)
+{
+	struct mpq_dmx_src_data *dmx_data = dev_inst->dmx_src_data;
+	struct mpq_streambuffer *streambuff = dmx_data->stream_buffer;
+	struct mpq_streambuffer_packet_header pkt_hdr;
+	struct mpq_adapter_video_meta_data meta_data;
+	ssize_t indx = -1;
+	ssize_t bytes_read = 0;
+	size_t pktlen = 0;
+	int frame_found = true;
+	unsigned long kernel_vaddr, phy_addr, user_vaddr;
+	int pmem_fd;
+	struct file *file;
+	s32 buffer_index = -1;
+	size_t size = 0;
+
+	do {
+		wait_event_interruptible(streambuff->packet_data.queue,
+			(!dvb_ringbuffer_empty(&streambuff->packet_data) ||
+			streambuff->packet_data.error != 0) ||
+			kthread_should_stop());
+
+		if (kthread_should_stop()) {
+			DBG("STOP signal Received\n");
+			return;
+		}
+
+		DBG("Received Free Buffer : %d\n", free_buf);
+
+		indx = mpq_streambuffer_pkt_next(streambuff, -1, &pktlen);
+
+		if (-1 == indx) {
+			DBG("Invalid Index -1\n");
+			return;
+		}
+
+		bytes_read = mpq_streambuffer_pkt_read(streambuff, indx,
+			&pkt_hdr, (u8 *)&meta_data);
+
+		switch (meta_data.packet_type) {
+		case DMX_FRAMING_INFO_PACKET:
+			switch (meta_data.info.framing.pattern_type) {
+			case DMX_FRM_H264_SPS:
+			case DMX_FRM_MPEG2_SEQUENCE_HEADER:
+			case DMX_FRM_VC1_SEQUENCE_HEADER:
+				DBG("SPS FOUND\n");
+				frame_found = false;
+				break;
+			case DMX_FRM_H264_PPS:
+			case DMX_FRM_MPEG2_GOP_HEADER:
+			case DMX_FRM_VC1_ENTRY_POINT_HEADER:
+				DBG("PPS FOUND\n");
+				frame_found = false;
+				break;
+			case DMX_FRM_H264_IDR_PIC:
+			case DMX_FRM_H264_NON_IDR_PIC:
+			case DMX_FRM_MPEG2_I_PIC:
+			case DMX_FRM_MPEG2_P_PIC:
+			case DMX_FRM_MPEG2_B_PIC:
+			case DMX_FRM_VC1_FRAME_START_CODE:
+				DBG("FRAME FOUND\n");
+				frame_found = true;
+				break;
+			default:
+				break;
+			}
+			user_vaddr = (unsigned long)
+				dmx_data->in_buffer[free_buf].bufferaddr;
+			vidc_lookup_addr_table(dev_inst->client_ctx,
+				BUFFER_TYPE_INPUT, true, &user_vaddr,
+				&kernel_vaddr,	&phy_addr, &pmem_fd, &file,
+				&buffer_index);
+			bytes_read = 0;
+			bytes_read = mpq_streambuffer_data_read(streambuff,
+						(u8 *)(kernel_vaddr + size),
+						pkt_hdr.raw_data_len);
+			DBG("Data Read : %d from Packet Size : %d\n",
+				bytes_read, pkt_hdr.raw_data_len);
+			mpq_streambuffer_pkt_dispose(streambuff, indx, 0);
+			size +=	pkt_hdr.raw_data_len;
+			dmx_data->in_buffer[free_buf].pts =
+			(meta_data.info.framing.pts_dts_info.pts_exist) ?
+			(meta_data.info.framing.pts_dts_info.pts) : 0;
+			if (frame_found) {
+				dmx_data->in_buffer[free_buf].buffer_len =
+									size;
+				dmx_data->in_buffer[free_buf].client_data =
+							(void *)free_buf;
+				DBG("Size of Data Submitted : %d\n", size);
+				mpq_int_vid_dec_decode_frame(
+						dev_inst->client_ctx,
+						&dmx_data->in_buffer[free_buf]);
+			}
+			break;
+		case DMX_EOS_PACKET:
+			break;
+		case DMX_PES_PACKET:
+		case DMX_PADDING_PACKET:
+			break;
+		}
+	} while (!frame_found);
+
+}
+
+static int mpq_bcast_data_handler(void *arg)
+{
+	struct mpq_dvb_video_inst *dev_inst = arg;
+	struct mpq_dmx_src_data *dmx_data = dev_inst->dmx_src_data;
+	struct mpq_bcast_msg *pMesg;
+	struct mpq_bcast_msg_info msg = {0};
+
+	do {
+		wait_event_interruptible(dmx_data->msg_wait,
+					((dmx_data->stream_buffer != NULL) &&
+					mpq_int_check_bcast_mq(dmx_data)) ||
+					kthread_should_stop());
+
+		if (kthread_should_stop()) {
+			DBG("STOP signal Received\n");
+			break;
+		}
+
+		mutex_lock(&dmx_data->msg_queue_lock);
+		if (!list_empty(&dmx_data->msg_queue)) {
+			pMesg = list_first_entry(&dmx_data->msg_queue,
+					struct mpq_bcast_msg, list);
+			list_del(&pMesg->list);
+			memcpy(&msg, &pMesg->info,
+				sizeof(struct mpq_bcast_msg_info));
+			kfree(pMesg);
+		}
+		mutex_unlock(&dmx_data->msg_queue_lock);
+
+		switch (msg.code) {
+		case MPQ_BCAST_MSG_IBD:
+			DBG("Received IBD Mesg for :%d\n", msg.data);
+			mpq_get_frame_and_write(dev_inst, msg.data);
+			break;
+		default:
+			DBG("Received Mesg : %d\n", msg.code);
+		}
+	} while (1);
+
+	return 0;
+}
+
+static s32 mpq_int_vid_dec_get_empty_client_index(void)
+{
+	u32 i, found = false;
+
+	for (i = 0; i < VIDC_MAX_NUM_CLIENTS; i++) {
+		if (!mpq_dvb_video_device->vdec_clients[i].vcd_handle) {
+			found = true;
+			break;
+		}
+	}
+	if (!found) {
+		ERR("%s():ERROR No space for new client\n", __func__);
+		return -ENOMEM;
+	} else {
+		DBG("%s(): available client index = %u\n", __func__, i);
+		return i;
+	}
+}
+
+static u32 mpq_int_vid_dec_get_status(u32 status)
+{
+	u32 vdec_status;
+
+	switch (status) {
+	case VCD_ERR_SEQHDR_PARSE_FAIL:
+	case VCD_ERR_BITSTREAM_ERR:
+		vdec_status = VIDEO_STATUS_BITSTREAM_ERROR;
+		break;
+	case VCD_S_SUCCESS:
+		vdec_status = VIDEO_STATUS_SUCESS;
+		break;
+	case VCD_ERR_FAIL:
+		vdec_status = VIDEO_STATUS_FAILED;
+		break;
+	case VCD_ERR_ALLOC_FAIL:
+	case VCD_ERR_MAX_CLIENT:
+		vdec_status = VIDEO_STATUS_NORESOURCE;
+		break;
+	case VCD_ERR_ILLEGAL_OP:
+		vdec_status = VIDEO_STATUS_INVALID_CMD;
+		break;
+	case VCD_ERR_ILLEGAL_PARM:
+		vdec_status = VIDEO_STATUS_INVALID_PARAM;
+		break;
+	case VCD_ERR_BAD_POINTER:
+	case VCD_ERR_BAD_HANDLE:
+		vdec_status = VIDEO_STATUS_INVALID_HANDLE;
+		break;
+	case VCD_ERR_NOT_SUPPORTED:
+		vdec_status = VIDEO_STATUS_NO_SUPPORT;
+		break;
+	case VCD_ERR_BAD_STATE:
+		vdec_status = VIDEO_STATUS_INVALID_STATE;
+		break;
+	case VCD_ERR_BUSY:
+		vdec_status = VIDEO_STATUS_BUSY;
+		break;
+	default:
+		vdec_status = VIDEO_STATUS_FAILED;
+		break;
+	}
+
+	return vdec_status;
+}
+
+static void mpq_int_vid_dec_notify_client(struct video_client_ctx *client_ctx)
+{
+	if (client_ctx)
+		complete(&client_ctx->event);
+}
+
+static void mpq_int_vid_dec_vcd_open_done(struct video_client_ctx *client_ctx,
+			   struct vcd_handle_container *handle_container)
+{
+	if (client_ctx) {
+		if (handle_container)
+			client_ctx->vcd_handle = handle_container->handle;
+		else
+			DBG("%s(): ERROR. handle_container is NULL\n",
+			    __func__);
+
+		mpq_int_vid_dec_notify_client(client_ctx);
+	} else
+		DBG("%s(): ERROR. client_ctx is NULL\n", __func__);
+}
+
+static void mpq_int_vid_dec_handle_field_drop(
+	struct video_client_ctx *client_ctx,
+	u32 event, u32 status, int64_t time_stamp)
+{
+	struct vid_dec_msg *vdec_msg;
+
+	if (!client_ctx) {
+		DBG("%s() NULL pointer\n", __func__);
+		return;
+	}
+
+	vdec_msg = kzalloc(sizeof(struct vid_dec_msg), GFP_KERNEL);
+	if (!vdec_msg) {
+		DBG("%s(): cannot allocate vid_dec_msg "\
+			" buffer\n", __func__);
+		return;
+	}
+	vdec_msg->vdec_msg_info.status_code =
+		mpq_int_vid_dec_get_status(status);
+	if (event == VCD_EVT_IND_INFO_FIELD_DROPPED) {
+		vdec_msg->vdec_msg_info.msgcode =
+			VDEC_MSG_EVT_INFO_FIELD_DROPPED;
+		vdec_msg->vdec_msg_info.msgdata.output_frame.time_stamp
+		= time_stamp;
+		DBG("Send FIELD_DROPPED message to client = %p\n",
+						client_ctx);
+	} else {
+		DBG("mpq_int_vid_dec_input_frame_done(): "\
+			"invalid event type: %d\n", event);
+		vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_INVALID;
+	}
+	vdec_msg->vdec_msg_info.msgdatasize =
+		sizeof(struct vdec_output_frameinfo);
+	mutex_lock(&client_ctx->msg_queue_lock);
+	list_add_tail(&vdec_msg->list, &client_ctx->msg_queue);
+	mutex_unlock(&client_ctx->msg_queue_lock);
+	wake_up(&client_ctx->msg_wait);
+}
+
+static void mpq_int_vid_dec_input_frame_done(
+			struct video_client_ctx *client_ctx, u32 event,
+			u32 status, struct vcd_frame_data *vcd_frame_data)
+{
+	struct vid_dec_msg *vdec_msg;
+	struct mpq_bcast_msg *bcast_msg;
+	struct mpq_dvb_video_inst *dev_inst;
+	struct mpq_dmx_src_data *dmx_data;
+	int rc = 0;
+
+	if (!client_ctx || !vcd_frame_data) {
+		DBG("mpq_int_vid_dec_input_frame_done() NULL pointer\n");
+		return;
+	}
+
+	kfree(vcd_frame_data->desc_buf);
+	vcd_frame_data->desc_buf = NULL;
+	vcd_frame_data->desc_size = 0;
+
+	rc = mpq_get_dev_frm_client(client_ctx, &dev_inst);
+	if (rc) {
+		DBG("Failed to obtain device instance\n");
+		return;
+	}
+
+	if (dev_inst->source == VIDEO_SOURCE_MEMORY) {
+		vdec_msg = kzalloc(sizeof(struct vid_dec_msg), GFP_KERNEL);
+		if (!vdec_msg) {
+			DBG("mpq_int_vid_dec_input_frame_done(): "\
+			"cannot allocate vid_dec_msg buffer\n");
+			return;
+		}
+
+		vdec_msg->vdec_msg_info.status_code =
+				mpq_int_vid_dec_get_status(status);
+
+		if (event == VCD_EVT_RESP_INPUT_DONE) {
+			vdec_msg->vdec_msg_info.msgcode =
+			VDEC_MSG_RESP_INPUT_BUFFER_DONE;
+			DBG("Send INPUT_DON message to client = %p\n",
+						client_ctx);
+
+		} else if (event == VCD_EVT_RESP_INPUT_FLUSHED) {
+			vdec_msg->vdec_msg_info.msgcode =
+					VDEC_MSG_RESP_INPUT_FLUSHED;
+			DBG("Send INPUT_FLUSHED message to client = %p\n",
+						client_ctx);
+		} else {
+			DBG("mpq_int_vid_dec_input_frame_done(): "\
+				"invalid event type: %d\n", event);
+			vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_INVALID;
+		}
+
+		vdec_msg->vdec_msg_info.msgdata.input_frame_clientdata =
+			(void *)vcd_frame_data->frm_clnt_data;
+		vdec_msg->vdec_msg_info.msgdatasize = sizeof(void *);
+
+		mutex_lock(&client_ctx->msg_queue_lock);
+		list_add_tail(&vdec_msg->list, &client_ctx->msg_queue);
+		mutex_unlock(&client_ctx->msg_queue_lock);
+		wake_up(&client_ctx->msg_wait);
+	} else {
+		if (event == VCD_EVT_RESP_INPUT_DONE) {
+			bcast_msg = kzalloc(sizeof(struct mpq_bcast_msg),
+						GFP_KERNEL);
+			if (!bcast_msg) {
+				DBG("mpq_int_vid_dec_input_frame_done(): "\
+				"cannot allocate mpq_bcast_msg buffer\n");
+				return;
+			}
+
+			bcast_msg->info.code = MPQ_BCAST_MSG_IBD;
+			bcast_msg->info.data =
+				(unsigned int)vcd_frame_data->frm_clnt_data;
+
+			dmx_data = dev_inst->dmx_src_data;
+
+			mutex_lock(&dmx_data->msg_queue_lock);
+			list_add_tail(&bcast_msg->list, &dmx_data->msg_queue);
+			mutex_unlock(&dmx_data->msg_queue_lock);
+			wake_up(&dmx_data->msg_wait);
+		}
+	}
+}
+
+static void mpq_int_vid_dec_output_frame_done(
+			struct video_client_ctx *client_ctx,
+			u32 event, u32 status,
+			struct vcd_frame_data *vcd_frame_data)
+{
+	struct vid_dec_msg *vdec_msg;
+
+	unsigned long kernel_vaddr = 0, phy_addr = 0, user_vaddr = 0;
+	int pmem_fd;
+	struct file *file;
+	s32 buffer_index = -1;
+	enum vdec_picture pic_type;
+	u32 ion_flag = 0;
+	struct ion_handle *buff_handle = NULL;
+	struct vdec_output_frameinfo  *output_frame;
+
+	if (!client_ctx || !vcd_frame_data) {
+		DBG("mpq_int_vid_dec_input_frame_done() NULL pointer\n");
+		return;
+	}
+
+	vdec_msg = kzalloc(sizeof(struct vid_dec_msg), GFP_KERNEL);
+	if (!vdec_msg) {
+		DBG("mpq_int_vid_dec_input_frame_done(): "\
+		    "cannot allocate vid_dec_msg buffer\n");
+		return;
+	}
+
+	vdec_msg->vdec_msg_info.status_code =
+			mpq_int_vid_dec_get_status(status);
+
+	if (event == VCD_EVT_RESP_OUTPUT_DONE)
+		vdec_msg->vdec_msg_info.msgcode =
+		    VDEC_MSG_RESP_OUTPUT_BUFFER_DONE;
+	else if (event == VCD_EVT_RESP_OUTPUT_FLUSHED)
+		vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_RESP_OUTPUT_FLUSHED;
+	else {
+		DBG("QVD: mpq_int_vid_dec_output_frame_done"\
+			"invalid cmd type : %d\n", event);
+		vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_INVALID;
+	}
+
+	kernel_vaddr = (unsigned long)vcd_frame_data->virtual;
+
+	if (vidc_lookup_addr_table(client_ctx, BUFFER_TYPE_OUTPUT,
+				      false, &user_vaddr, &kernel_vaddr,
+				      &phy_addr, &pmem_fd, &file,
+				      &buffer_index) ||
+		(vcd_frame_data->flags & VCD_FRAME_FLAG_EOS)) {
+		/* Buffer address in user space */
+		vdec_msg->vdec_msg_info.msgdata.output_frame.bufferaddr =
+		    (u8 *) user_vaddr;
+		/* Data length */
+		vdec_msg->vdec_msg_info.msgdata.output_frame.len =
+		    vcd_frame_data->data_len;
+		vdec_msg->vdec_msg_info.msgdata.output_frame.flags =
+		    vcd_frame_data->flags;
+		/* Timestamp pass-through from input frame */
+		vdec_msg->vdec_msg_info.msgdata.output_frame.time_stamp =
+		    vcd_frame_data->time_stamp;
+		/* Output frame client data */
+		vdec_msg->vdec_msg_info.msgdata.output_frame.client_data =
+		    (void *)vcd_frame_data->frm_clnt_data;
+		/* Associated input frame client data */
+		vdec_msg->vdec_msg_info.msgdata.output_frame.
+		    input_frame_clientdata =
+		    (void *)vcd_frame_data->ip_frm_tag;
+		/* Decoded picture width and height */
+		vdec_msg->vdec_msg_info.msgdata.output_frame.framesize.
+		bottom =
+		    vcd_frame_data->dec_op_prop.disp_frm.bottom;
+		vdec_msg->vdec_msg_info.msgdata.output_frame.framesize.left =
+		    vcd_frame_data->dec_op_prop.disp_frm.left;
+		vdec_msg->vdec_msg_info.msgdata.output_frame.framesize.right =
+			vcd_frame_data->dec_op_prop.disp_frm.right;
+		vdec_msg->vdec_msg_info.msgdata.output_frame.framesize.top =
+			vcd_frame_data->dec_op_prop.disp_frm.top;
+		if (vcd_frame_data->interlaced) {
+			vdec_msg->vdec_msg_info.msgdata.
+				output_frame.interlaced_format =
+				VDEC_InterlaceInterleaveFrameTopFieldFirst;
+		} else {
+			vdec_msg->vdec_msg_info.msgdata.
+				output_frame.interlaced_format =
+				VDEC_InterlaceFrameProgressive;
+		}
+		/* Decoded picture type */
+		switch (vcd_frame_data->frame) {
+		case VCD_FRAME_I:
+			pic_type = PICTURE_TYPE_I;
+			break;
+		case VCD_FRAME_P:
+			pic_type = PICTURE_TYPE_P;
+			break;
+		case VCD_FRAME_B:
+			pic_type = PICTURE_TYPE_B;
+			break;
+		case VCD_FRAME_NOTCODED:
+			pic_type = PICTURE_TYPE_SKIP;
+			break;
+		case VCD_FRAME_IDR:
+			pic_type = PICTURE_TYPE_IDR;
+			break;
+		default:
+			pic_type = PICTURE_TYPE_UNKNOWN;
+		}
+		vdec_msg->vdec_msg_info.msgdata.output_frame.pic_type =
+			pic_type;
+		output_frame = &vdec_msg->vdec_msg_info.msgdata.output_frame;
+		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.par_width;
+		output_frame->aspect_ratio_info.par_height =
+			vcd_frame_data->aspect_ratio_info.par_height;
+		vdec_msg->vdec_msg_info.msgdatasize =
+		    sizeof(struct vdec_output_frameinfo);
+	} else {
+		DBG("mpq_int_vid_dec_output_frame_done UVA"\
+				"can not be found\n");
+		vdec_msg->vdec_msg_info.status_code = VDEC_S_EFATAL;
+	}
+	if (vcd_frame_data->data_len > 0) {
+		ion_flag = vidc_get_fd_info(client_ctx, BUFFER_TYPE_OUTPUT,
+				pmem_fd, kernel_vaddr, buffer_index,
+				&buff_handle);
+		if (ion_flag == CACHED && buff_handle) {
+			msm_ion_do_cache_op(
+				client_ctx->user_ion_client,
+				buff_handle,
+				(unsigned long *) kernel_vaddr,
+				(unsigned long)vcd_frame_data->data_len,
+				ION_IOC_INV_CACHES);
+		}
+	}
+	mutex_lock(&client_ctx->msg_queue_lock);
+	list_add_tail(&vdec_msg->list, &client_ctx->msg_queue);
+	mutex_unlock(&client_ctx->msg_queue_lock);
+	wake_up(&client_ctx->msg_wait);
+}
+
+static void mpq_int_vid_dec_lean_event(struct video_client_ctx *client_ctx,
+			       u32 event, u32 status)
+{
+	struct vid_dec_msg *vdec_msg;
+
+	if (!client_ctx) {
+		DBG("%s(): !client_ctx pointer\n", __func__);
+		return;
+	}
+
+	vdec_msg = kzalloc(sizeof(struct vid_dec_msg), GFP_KERNEL);
+	if (!vdec_msg) {
+		DBG("%s(): cannot allocate vid_dec_msg buffer\n",
+					__func__);
+		return;
+	}
+
+	vdec_msg->vdec_msg_info.status_code =
+			mpq_int_vid_dec_get_status(status);
+
+	switch (event) {
+	case VCD_EVT_IND_OUTPUT_RECONFIG:
+		DBG("msm_vidc_dec: Sending VDEC_MSG_EVT_CONFIG_CHANGED"\
+			 " to client");
+		vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_EVT_CONFIG_CHANGED;
+		break;
+	case VCD_EVT_IND_RESOURCES_LOST:
+		DBG("msm_vidc_dec: Sending VDEC_EVT_RESOURCES_LOST"\
+			 " to client");
+		vdec_msg->vdec_msg_info.msgcode = VDEC_EVT_RESOURCES_LOST;
+		break;
+	case VCD_EVT_RESP_FLUSH_INPUT_DONE:
+		DBG("msm_vidc_dec: Sending VDEC_MSG_RESP_FLUSH_INPUT_DONE"\
+			 " to client");
+		vdec_msg->vdec_msg_info.msgcode =
+		    VDEC_MSG_RESP_FLUSH_INPUT_DONE;
+		break;
+	case VCD_EVT_RESP_FLUSH_OUTPUT_DONE:
+		DBG("msm_vidc_dec: Sending VDEC_MSG_RESP_FLUSH_OUTPUT_DONE"\
+			 " to client");
+		vdec_msg->vdec_msg_info.msgcode =
+		    VDEC_MSG_RESP_FLUSH_OUTPUT_DONE;
+		break;
+	case VCD_EVT_IND_HWERRFATAL:
+		DBG("msm_vidc_dec: Sending VDEC_MSG_EVT_HW_ERROR"\
+			 " to client");
+		vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_EVT_HW_ERROR;
+		break;
+	case VCD_EVT_RESP_START:
+		DBG("msm_vidc_dec: Sending VDEC_MSG_RESP_START_DONE"\
+			 " to client");
+		vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_RESP_START_DONE;
+		break;
+	case VCD_EVT_RESP_STOP:
+		DBG("msm_vidc_dec: Sending VDEC_MSG_RESP_STOP_DONE"\
+			 " to client");
+		vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_RESP_STOP_DONE;
+		break;
+	case VCD_EVT_RESP_PAUSE:
+		DBG("msm_vidc_dec: Sending VDEC_MSG_RESP_PAUSE_DONE"\
+			 " to client");
+		vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_RESP_PAUSE_DONE;
+		break;
+	case VCD_EVT_IND_INFO_OUTPUT_RECONFIG:
+		DBG("msm_vidc_dec: Sending VDEC_MSG_EVT_INFO_CONFIG_CHANGED"\
+			 " to client");
+		vdec_msg->vdec_msg_info.msgcode =
+			 VDEC_MSG_EVT_INFO_CONFIG_CHANGED;
+		break;
+	default:
+		DBG("%s() : unknown event type\n", __func__);
+		break;
+	}
+
+	vdec_msg->vdec_msg_info.msgdatasize = 0;
+	if (client_ctx->stop_sync_cb &&
+	   (event == VCD_EVT_RESP_STOP || event == VCD_EVT_IND_HWERRFATAL)) {
+		client_ctx->stop_sync_cb = false;
+		complete(&client_ctx->event);
+		kfree(vdec_msg);
+		return;
+	}
+	mutex_lock(&client_ctx->msg_queue_lock);
+	list_add_tail(&vdec_msg->list, &client_ctx->msg_queue);
+	mutex_unlock(&client_ctx->msg_queue_lock);
+	wake_up(&client_ctx->msg_wait);
+}
+
+static void mpq_int_state_play(struct video_client_ctx *client_ctx,
+			       u32 event, u32 status)
+{
+	struct mpq_bcast_msg *bcast_msg;
+	struct mpq_dvb_video_inst *dev_inst;
+	int i;
+	int rc = 0;
+	struct mpq_dmx_src_data *dmx_data = NULL;
+
+	if (!client_ctx->seq_header_set) {
+		rc = mpq_get_dev_frm_client(client_ctx, &dev_inst);
+		if (rc) {
+			DBG("Failed to get dev_instance in %s\n", __func__);
+			return;
+		}
+
+		if (VIDEO_SOURCE_DEMUX == dev_inst->source) {
+			dmx_data = dev_inst->dmx_src_data;
+			for (i = 0; i < DVB_VID_NUM_IN_BUFFERS; i++) {
+				bcast_msg = kzalloc(
+						sizeof(struct mpq_bcast_msg),
+						GFP_KERNEL);
+				if (!bcast_msg) {
+					DBG("cannot allocate mpq_bcast_msg"\
+						"buffer\n");
+					return;
+				}
+
+				bcast_msg->info.code = MPQ_BCAST_MSG_IBD;
+				bcast_msg->info.data = (unsigned int)i;
+
+				mutex_lock(&dmx_data->msg_queue_lock);
+				list_add_tail(&bcast_msg->list,
+						&dmx_data->msg_queue);
+				mutex_unlock(&dmx_data->msg_queue_lock);
+				wake_up(&dmx_data->msg_wait);
+			}
+		}
+		mpq_int_vid_dec_lean_event(client_ctx, event, status);
+	} else
+		mpq_int_vid_dec_notify_client(client_ctx);
+
+}
+
+static void mpq_int_vid_dec_vcd_cb(u32 event, u32 status,
+		   void *info, size_t sz, void *handle,
+		   void *const client_data)
+{
+	struct video_client_ctx *client_ctx = client_data;
+
+	DBG("Entering %s()\n", __func__);
+
+	if (!client_ctx) {
+		DBG("%s(): client_ctx is NULL\n", __func__);
+		return;
+	}
+
+	client_ctx->event_status = status;
+
+	switch (event) {
+	case VCD_EVT_RESP_OPEN:
+		mpq_int_vid_dec_vcd_open_done(client_ctx,
+				      (struct vcd_handle_container *)
+				      info);
+		break;
+	case VCD_EVT_RESP_INPUT_DONE:
+	case VCD_EVT_RESP_INPUT_FLUSHED:
+		mpq_int_vid_dec_input_frame_done(client_ctx, event, status,
+					 (struct vcd_frame_data *)info);
+		break;
+	case VCD_EVT_IND_INFO_FIELD_DROPPED:
+		if (info)
+			mpq_int_vid_dec_handle_field_drop(client_ctx, event,
+			status,	*((int64_t *)info));
+		else
+			DBG("Wrong Payload for Field dropped\n");
+		break;
+	case VCD_EVT_RESP_OUTPUT_DONE:
+	case VCD_EVT_RESP_OUTPUT_FLUSHED:
+		mpq_int_vid_dec_output_frame_done(client_ctx, event, status,
+					  (struct vcd_frame_data *)info);
+		break;
+	case VCD_EVT_RESP_PAUSE:
+	case VCD_EVT_RESP_STOP:
+	case VCD_EVT_RESP_FLUSH_INPUT_DONE:
+	case VCD_EVT_RESP_FLUSH_OUTPUT_DONE:
+	case VCD_EVT_IND_OUTPUT_RECONFIG:
+	case VCD_EVT_IND_HWERRFATAL:
+	case VCD_EVT_IND_RESOURCES_LOST:
+	case VCD_EVT_IND_INFO_OUTPUT_RECONFIG:
+		mpq_int_vid_dec_lean_event(client_ctx, event, status);
+		break;
+	case VCD_EVT_RESP_START:
+		mpq_int_state_play(client_ctx, event, status);
+		break;
+	default:
+		DBG("%s() :  Error - Invalid event type =%u\n", __func__,
+		    event);
+		break;
+	}
+}
+
+static int mpq_int_vid_dec_set_cont_on_reconfig(
+			struct video_client_ctx *client_ctx)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	u32 vcd_status = VCD_ERR_FAIL;
+	u32 enable = true;
+	if (!client_ctx)
+		return -EINVAL;
+	vcd_property_hdr.prop_id = VCD_I_CONT_ON_RECONFIG;
+	vcd_property_hdr.sz = sizeof(u32);
+	vcd_status = vcd_set_property(client_ctx->vcd_handle,
+		&vcd_property_hdr, &enable);
+	if (vcd_status)
+		return -EIO;
+	return 0;
+}
+
+static int mpq_int_vid_dec_set_frame_resolution(
+				struct video_client_ctx *client_ctx,
+				struct vdec_picsize *video_resoultion)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_frame_size frame_resolution;
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	if (!client_ctx || !video_resoultion)
+		return -EINVAL;
+
+	vcd_property_hdr.prop_id = VCD_I_FRAME_SIZE;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_frame_size);
+	frame_resolution.width = video_resoultion->frame_width;
+	frame_resolution.height = video_resoultion->frame_height;
+	frame_resolution.stride = video_resoultion->stride;
+	frame_resolution.scan_lines = video_resoultion->scan_lines;
+
+	vcd_status = vcd_set_property(client_ctx->vcd_handle,
+				      &vcd_property_hdr, &frame_resolution);
+
+	if (vcd_status)
+		return -EIO;
+	else
+		return 0;
+}
+
+static int mpq_int_set_full_hd_frame_resolution(
+				struct video_client_ctx *client_ctx)
+{
+	struct vdec_picsize pic_res;
+	int rc;
+
+	pic_res.frame_height = 1080;
+	pic_res.frame_width  = 1920;
+	pic_res.scan_lines   = 1080;
+	pic_res.stride       = 1920;
+
+	rc = mpq_int_vid_dec_set_frame_resolution(client_ctx,
+						&pic_res);
+	if (rc)
+		DBG("Failed in mpq_int_vid_dec_set_frame_resolution : %d\n",\
+			rc);
+
+	rc = mpq_int_vid_dec_set_cont_on_reconfig(client_ctx);
+	if (rc)
+		DBG("Failed in mpq_int_vid_dec_set_cont_on_reconfig : %d\n",\
+			rc);
+
+	return rc;
+
+}
+
+static int mpq_int_vid_dec_get_frame_resolution(
+			struct video_client_ctx *client_ctx,
+			struct video_pic_res *video_resoultion)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_frame_size frame_resolution;
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	if (!client_ctx || !video_resoultion)
+		return -EINVAL;
+
+	vcd_property_hdr.prop_id = VCD_I_FRAME_SIZE;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_frame_size);
+
+	vcd_status = vcd_get_property(client_ctx->vcd_handle,
+				&vcd_property_hdr, &frame_resolution);
+
+	video_resoultion->width  = frame_resolution.width;
+	video_resoultion->height = frame_resolution.height;
+	video_resoultion->scan_lines = frame_resolution.scan_lines;
+	video_resoultion->stride = frame_resolution.stride;
+
+	if (vcd_status)
+		return -EINVAL;
+	else
+		return 0;
+}
+
+static int mpq_int_vid_dec_get_codec(struct video_client_ctx *client_ctx,
+					enum video_codec_t *video_codec)
+{
+	unsigned int result = 0;
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_codec codec;
+
+	if ((client_ctx == NULL) || (video_codec == NULL))
+		return -EINVAL;
+
+	vcd_property_hdr.prop_id = VCD_I_CODEC;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_codec);
+
+	result = vcd_get_property(client_ctx->vcd_handle,
+					&vcd_property_hdr, &codec);
+	if (result)
+		return -EINVAL;
+
+	switch (codec.codec) {
+	case VCD_CODEC_MPEG4:
+		*video_codec = VIDEO_CODECTYPE_MPEG4;
+		break;
+	case VCD_CODEC_H264:
+		*video_codec = VIDEO_CODECTYPE_H264;
+		break;
+	case VCD_CODEC_MPEG2:
+		*video_codec = VIDEO_CODECTYPE_MPEG2;
+		break;
+	case VCD_CODEC_VC1:
+		*video_codec = VIDEO_CODECTYPE_VC1;
+		break;
+	default:
+		*video_codec = VIDEO_CODECTYPE_NONE;
+		break;
+	}
+
+	return result;
+}
+
+static int mpq_int_vid_dec_set_codec(struct video_client_ctx *client_ctx,
+				enum video_codec_t video_codec)
+{
+	unsigned int result = 0;
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_codec codec;
+	unsigned int vcd_status = VCD_ERR_FAIL;
+
+	if (client_ctx == NULL)
+		return -EINVAL;
+
+	vcd_property_hdr.prop_id = VCD_I_CODEC;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_codec);
+
+	switch (video_codec) {
+	case VIDEO_CODECTYPE_MPEG4:
+		codec.codec = VCD_CODEC_MPEG4;
+		break;
+	case VIDEO_CODECTYPE_H264:
+		codec.codec = VCD_CODEC_H264;
+		break;
+	case VIDEO_CODECTYPE_MPEG2:
+		codec.codec = VCD_CODEC_MPEG2;
+		break;
+	case VIDEO_CODECTYPE_VC1:
+		codec.codec = VCD_CODEC_VC1;
+		break;
+	default:
+		result = -EINVAL;
+		break;
+	}
+
+	if (!result) {
+		vcd_status = vcd_set_property(client_ctx->vcd_handle,
+					      &vcd_property_hdr, &codec);
+		if (vcd_status)
+			result = -EINVAL;
+	}
+
+	result = mpq_int_set_full_hd_frame_resolution(client_ctx);
+
+	return result;
+}
+
+static int mpq_int_vid_dec_set_output_format(
+		struct video_client_ctx *client_ctx,
+		enum video_out_format_t format)
+{
+	unsigned int result = 0;
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_buffer_format vcd_prop_buffer_format;
+	unsigned int vcd_status = VCD_ERR_FAIL;
+
+	if (client_ctx == NULL)
+		return -EINVAL;
+
+	vcd_property_hdr.prop_id = VCD_I_BUFFER_FORMAT;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_buffer_format);
+
+	switch (format) {
+	case VIDEO_YUV_FORMAT_NV12:
+		vcd_prop_buffer_format.buffer_format = VCD_BUFFER_FORMAT_NV12;
+		break;
+	case VIDEO_YUV_FORMAT_TILE_4x2:
+		vcd_prop_buffer_format.buffer_format =
+					VCD_BUFFER_FORMAT_TILE_4x2;
+		break;
+	default:
+		result = -EINVAL;
+		break;
+	}
+
+	if (!result)
+		vcd_status = vcd_set_property(client_ctx->vcd_handle,
+					      &vcd_property_hdr,
+					      &vcd_prop_buffer_format);
+
+	if (vcd_status)
+		return -EINVAL;
+
+	return 0;
+
+}
+
+static int mpq_int_vid_dec_get_output_format(
+			struct video_client_ctx *client_ctx,
+			enum video_out_format_t *format)
+{
+	unsigned int result = 0;
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_buffer_format vcd_prop_buffer_format;
+
+	if ((client_ctx == NULL) || (format == NULL))
+		return -EINVAL;
+
+	vcd_property_hdr.prop_id = VCD_I_BUFFER_FORMAT;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_buffer_format);
+
+	result = vcd_get_property(client_ctx->vcd_handle, &vcd_property_hdr,
+					&vcd_prop_buffer_format);
+
+	if (result)
+		return -EINVAL;
+
+	switch (vcd_prop_buffer_format.buffer_format) {
+	case VCD_BUFFER_FORMAT_NV12:
+		*format = VIDEO_YUV_FORMAT_NV12;
+		break;
+	case VCD_BUFFER_FORMAT_TILE_4x2:
+		*format = VIDEO_YUV_FORMAT_TILE_4x2;
+		break;
+	default:
+		result = -EINVAL;
+		break;
+	}
+
+	return result;
+}
+
+static int mpq_int_vid_dec_set_h264_mv_buffers(
+				struct video_client_ctx *client_ctx,
+				struct video_h264_mv *mv_data)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_h264_mv_buffer *vcd_h264_mv_buffer = NULL;
+	struct msm_mapped_buffer *mapped_buffer = NULL;
+	u32 vcd_status = VCD_ERR_FAIL;
+	u32 len = 0, flags = 0;
+	struct file *file;
+	int rc = 0;
+	unsigned long ionflag = 0;
+	unsigned long buffer_size = 0;
+	unsigned long iova = 0;
+
+	if (!client_ctx || !mv_data)
+		return -EINVAL;
+
+	vcd_property_hdr.prop_id = VCD_I_H264_MV_BUFFER;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_h264_mv_buffer);
+	vcd_h264_mv_buffer = &client_ctx->vcd_h264_mv_buffer;
+
+	memset(&client_ctx->vcd_h264_mv_buffer, 0,
+		   sizeof(struct vcd_property_h264_mv_buffer));
+	vcd_h264_mv_buffer->size = mv_data->size;
+	vcd_h264_mv_buffer->count = mv_data->count;
+	vcd_h264_mv_buffer->pmem_fd = mv_data->ion_fd;
+	vcd_h264_mv_buffer->offset = mv_data->offset;
+
+	if (!vcd_get_ion_status()) {
+		if (get_pmem_file(vcd_h264_mv_buffer->pmem_fd,
+			(unsigned long *) (&(vcd_h264_mv_buffer->
+			physical_addr)),
+			(unsigned long *) (&vcd_h264_mv_buffer->
+						kernel_virtual_addr),
+			(unsigned long *) (&len), &file)) {
+			ERR("%s(): get_pmem_file failed\n", __func__);
+			return -EIO;
+		}
+		put_pmem_file(file);
+		flags = MSM_SUBSYSTEM_MAP_IOVA;
+		mapped_buffer = msm_subsystem_map_buffer(
+			(unsigned long)vcd_h264_mv_buffer->physical_addr, len,
+				flags, vidc_mmu_subsystem,
+				sizeof(vidc_mmu_subsystem)/
+				sizeof(unsigned int));
+		if (IS_ERR(mapped_buffer)) {
+			ERR("buffer map failed");
+			return PTR_ERR(mapped_buffer);
+		}
+		vcd_h264_mv_buffer->client_data = (void *) mapped_buffer;
+		vcd_h264_mv_buffer->dev_addr = (u8 *)mapped_buffer->iova[0];
+	} else {
+		client_ctx->h264_mv_ion_handle = ion_import_dma_buf(
+					client_ctx->user_ion_client,
+					vcd_h264_mv_buffer->pmem_fd);
+		if (IS_ERR_OR_NULL(client_ctx->h264_mv_ion_handle)) {
+			DBG("%s(): get_ION_handle failed\n", __func__);
+			goto import_ion_error;
+		}
+		rc = ion_handle_get_flags(client_ctx->user_ion_client,
+					client_ctx->h264_mv_ion_handle,
+					&ionflag);
+		if (rc) {
+			DBG("%s():get_ION_flags fail\n",
+					 __func__);
+			goto import_ion_error;
+		}
+		vcd_h264_mv_buffer->kernel_virtual_addr =
+			(u8 *) ion_map_kernel(client_ctx->user_ion_client,
+					client_ctx->h264_mv_ion_handle,
+					ionflag);
+		if (!vcd_h264_mv_buffer->kernel_virtual_addr) {
+			DBG("%s(): get_ION_kernel virtual addr failed\n",
+				 __func__);
+			goto import_ion_error;
+		}
+
+		rc = ion_map_iommu(client_ctx->user_ion_client,
+				client_ctx->h264_mv_ion_handle,
+				VIDEO_DOMAIN, VIDEO_MAIN_POOL,
+				SZ_4K, 0, (unsigned long *)&iova,
+				(unsigned long *)&buffer_size,
+				UNCACHED, 0);
+		if (rc) {
+			DBG("%s():get_ION_kernel physical addr fail\n",
+						 __func__);
+			goto ion_map_error;
+		}
+		vcd_h264_mv_buffer->physical_addr = (u8 *) iova;
+		vcd_h264_mv_buffer->client_data = NULL;
+		vcd_h264_mv_buffer->dev_addr = (u8 *) iova;
+
+	}
+	DBG("Virt: %p, Phys %p, fd: %d", vcd_h264_mv_buffer->
+		kernel_virtual_addr, vcd_h264_mv_buffer->physical_addr,
+		vcd_h264_mv_buffer->pmem_fd);
+	DBG("Dev addr %p", vcd_h264_mv_buffer->dev_addr);
+	vcd_status = vcd_set_property(client_ctx->vcd_handle,
+				      &vcd_property_hdr, vcd_h264_mv_buffer);
+
+	if (vcd_status)
+		return -EIO;
+	else
+		return 0;
+ion_map_error:
+	if (vcd_h264_mv_buffer->kernel_virtual_addr) {
+		ion_unmap_kernel(client_ctx->user_ion_client,
+				client_ctx->h264_mv_ion_handle);
+		vcd_h264_mv_buffer->kernel_virtual_addr = NULL;
+	}
+	if (!IS_ERR_OR_NULL(client_ctx->h264_mv_ion_handle)) {
+		ion_free(client_ctx->user_ion_client,
+			client_ctx->h264_mv_ion_handle);
+		 client_ctx->h264_mv_ion_handle = NULL;
+	}
+import_ion_error:
+	return -EIO;
+}
+
+static int mpq_int_vid_dec_get_h264_mv_buffer_size(
+				struct video_client_ctx *client_ctx,
+				struct video_mv_buff_size *mv_buff)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_buffer_size h264_mv_buffer_size;
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	if (!client_ctx || !mv_buff)
+		return -EINVAL;
+
+	vcd_property_hdr.prop_id = VCD_I_GET_H264_MV_SIZE;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_buffer_size);
+
+	h264_mv_buffer_size.width = mv_buff->width;
+	h264_mv_buffer_size.height = mv_buff->height;
+
+	vcd_status = vcd_get_property(client_ctx->vcd_handle,
+				      &vcd_property_hdr, &h264_mv_buffer_size);
+
+	mv_buff->width = h264_mv_buffer_size.width;
+	mv_buff->height = h264_mv_buffer_size.height;
+	mv_buff->size = h264_mv_buffer_size.size;
+	mv_buff->alignment = h264_mv_buffer_size.alignment;
+
+	if (vcd_status)
+		return -EIO;
+	else
+		return 0;
+}
+
+static int mpq_int_vid_dec_free_h264_mv_buffers(
+				struct video_client_ctx *client_ctx)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_buffer_size h264_mv_buffer_size;
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	if (!client_ctx)
+		return -EINVAL;
+	if (client_ctx->vcd_h264_mv_buffer.client_data)
+		msm_subsystem_unmap_buffer((struct msm_mapped_buffer *)
+		client_ctx->vcd_h264_mv_buffer.client_data);
+
+	vcd_property_hdr.prop_id = VCD_I_FREE_H264_MV_BUFFER;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_buffer_size);
+
+	vcd_status = vcd_set_property(client_ctx->vcd_handle,
+				      &vcd_property_hdr, &h264_mv_buffer_size);
+
+	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);
+		ion_unmap_iommu(client_ctx->user_ion_client,
+				client_ctx->h264_mv_ion_handle,
+				VIDEO_DOMAIN,
+				VIDEO_MAIN_POOL);
+		ion_free(client_ctx->user_ion_client,
+					client_ctx->h264_mv_ion_handle);
+		 client_ctx->h264_mv_ion_handle = NULL;
+	}
+
+	if (vcd_status)
+		return -EIO;
+	else
+		return 0;
+}
+
+
+static int mpq_int_vid_dec_get_buffer_req(struct video_client_ctx *client_ctx,
+				  struct video_buffer_req *vdec_buf_req)
+{
+	u32 vcd_status = VCD_ERR_FAIL;
+	struct vcd_buffer_requirement vcd_buf_req;
+
+	if (!client_ctx || !vdec_buf_req)
+		return -EINVAL;
+
+	vcd_status = vcd_get_buffer_requirements(client_ctx->vcd_handle,
+					VCD_BUFFER_INPUT, &vcd_buf_req);
+
+	if (vcd_status)
+		return -EINVAL;
+
+	vdec_buf_req->input_buf_prop.alignment  = vcd_buf_req.align;
+	vdec_buf_req->input_buf_prop.buf_poolid = vcd_buf_req.buf_pool_id;
+	vdec_buf_req->input_buf_prop.buf_size   = vcd_buf_req.sz;
+	vdec_buf_req->num_input_buffers         = vcd_buf_req.actual_count;
+
+	vcd_status = vcd_get_buffer_requirements(client_ctx->vcd_handle,
+					VCD_BUFFER_OUTPUT, &vcd_buf_req);
+
+	if (vcd_status)
+		return -EINVAL;
+
+	vdec_buf_req->output_buf_prop.alignment  = vcd_buf_req.align;
+	vdec_buf_req->output_buf_prop.buf_poolid = vcd_buf_req.buf_pool_id;
+	vdec_buf_req->output_buf_prop.buf_size   = vcd_buf_req.sz;
+	vdec_buf_req->num_output_buffers         = vcd_buf_req.actual_count;
+
+	return 0;
+}
+
+static int mpq_int_vid_dec_set_buffer(struct mpq_dvb_video_inst *dev_inst,
+			      struct video_data_buffer *data_buffer,
+			      enum buffer_dir dir_buffer)
+{
+	struct video_client_ctx *client_ctx =
+		(struct video_client_ctx *)dev_inst->client_ctx;
+	enum vcd_buffer_type buffer = VCD_BUFFER_INPUT;
+	u32 vcd_status = VCD_ERR_FAIL;
+	unsigned long kernel_vaddr, buf_adr_offset = 0, length;
+	int buffer_num = 0;
+
+	if (!client_ctx || !data_buffer)
+		return -EINVAL;
+
+	if (dir_buffer == BUFFER_TYPE_OUTPUT) {
+		buffer = VCD_BUFFER_OUTPUT;
+		buf_adr_offset = (unsigned long)data_buffer->offset;
+	}
+	length = data_buffer->buffer_len;
+	/*If buffer cannot be set, ignore */
+	if (!vidc_insert_addr_table(client_ctx, dir_buffer,
+		(unsigned long)data_buffer->bufferaddr,
+		&kernel_vaddr, data_buffer->ion_fd,
+		buf_adr_offset, MAX_VIDEO_NUM_OF_BUFF, length)) {
+		ERR("%s() : user_virt_addr = %p cannot be set.",
+		    __func__, data_buffer->bufferaddr);
+		return -EINVAL;
+	}
+
+	vcd_status = vcd_set_buffer(client_ctx->vcd_handle,
+		buffer, (u8 *) kernel_vaddr, data_buffer->buffer_len);
+
+	if (!vcd_status) {
+		mutex_lock(&client_ctx->enrty_queue_lock);
+		if ((VIDEO_SOURCE_DEMUX == dev_inst->source) &&
+			(BUFFER_TYPE_INPUT == dir_buffer)) {
+			buffer_num = client_ctx->num_of_input_buffers - 1;
+			memcpy(&dev_inst->dmx_src_data->in_buffer[buffer_num],
+				data_buffer,
+				sizeof(struct video_data_buffer));
+		}
+		mutex_unlock(&client_ctx->enrty_queue_lock);
+		return 0;
+	} else
+		return -EINVAL;
+}
+
+static int mpq_int_vid_dec_free_buffer(struct video_client_ctx *client_ctx,
+				struct video_data_buffer *data_buffer,
+				enum buffer_dir dir_buffer)
+
+{
+	enum vcd_buffer_type buffer = VCD_BUFFER_INPUT;
+	u32 vcd_status = VCD_ERR_FAIL;
+	unsigned long kernel_vaddr;
+
+	if (!client_ctx || !data_buffer)
+		return -EINVAL;
+
+	if (dir_buffer == BUFFER_TYPE_OUTPUT)
+		buffer = VCD_BUFFER_OUTPUT;
+
+	/*If buffer NOT set, ignore */
+	if (!vidc_delete_addr_table(client_ctx, dir_buffer,
+				(unsigned long)data_buffer->bufferaddr,
+				&kernel_vaddr)) {
+		DBG("%s() : user_virt_addr = %p has not been set.",
+		    __func__, data_buffer->bufferaddr);
+		return 0;
+	}
+	vcd_status = vcd_free_buffer(client_ctx->vcd_handle, buffer,
+					 (u8 *)kernel_vaddr);
+
+	if (vcd_status)
+		return -EIO;
+	else
+		return 0;
+}
+
+static int mpq_int_vid_dec_pause_resume(struct video_client_ctx *client_ctx,
+					u32 pause)
+{
+	u32 vcd_status;
+
+	if (!client_ctx) {
+		DBG("%s(): Invalid client_ctx\n", __func__);
+		return -EINVAL;
+	}
+
+	if (pause) {
+		DBG("msm_vidc_dec: PAUSE command from client = %p\n",
+			 client_ctx);
+		vcd_status = vcd_pause(client_ctx->vcd_handle);
+	} else {
+		DBG("msm_vidc_dec: RESUME command from client = %p\n",
+			 client_ctx);
+		vcd_status = vcd_resume(client_ctx->vcd_handle);
+	}
+
+	if (vcd_status)
+		return -EIO;
+	else
+		return 0;
+}
+
+static int mpq_int_vid_dec_start_stop(struct video_client_ctx *client_ctx,
+					u32 start)
+{
+	struct vid_dec_msg *vdec_msg = NULL;
+	u32 vcd_status;
+
+	DBG("Inside %s()", __func__);
+	if (!client_ctx) {
+		DBG("Invalid client_ctx\n");
+		return -EINVAL;
+	}
+
+	if (start) {
+		if (client_ctx->seq_header_set) {
+			DBG("%s(): Seq Hdr set: Send START_DONE to client",
+				 __func__);
+			vdec_msg = kzalloc(sizeof(*vdec_msg), GFP_KERNEL);
+			if (!vdec_msg) {
+				DBG("mpq_int_vid_dec_start_stop:"\
+				    " cannot allocate buffer\n");
+				return -ENOMEM;
+			}
+			vdec_msg->vdec_msg_info.msgcode =
+			    VDEC_MSG_RESP_START_DONE;
+			vdec_msg->vdec_msg_info.status_code = VDEC_S_SUCCESS;
+			vdec_msg->vdec_msg_info.msgdatasize = 0;
+			mutex_lock(&client_ctx->msg_queue_lock);
+			list_add_tail(&vdec_msg->list, &client_ctx->msg_queue);
+			mutex_unlock(&client_ctx->msg_queue_lock);
+
+			wake_up(&client_ctx->msg_wait);
+
+			DBG("Send START_DONE message to client = %p\n",
+			    client_ctx);
+
+		} else {
+			DBG("%s(): Calling decode_start()", __func__);
+			vcd_status =
+			    vcd_decode_start(client_ctx->vcd_handle, NULL);
+
+			if (vcd_status) {
+				DBG("%s(): vcd_decode_start failed."\
+				    " vcd_status = %u\n", __func__,
+				    vcd_status);
+				return -EIO;
+			}
+		}
+	} else {
+		DBG("%s(): Calling vcd_stop()", __func__);
+		mutex_lock(&mpq_dvb_video_device->lock);
+		vcd_status = VCD_ERR_FAIL;
+		if (!client_ctx->stop_called) {
+			client_ctx->stop_called = true;
+			vcd_status = vcd_stop(client_ctx->vcd_handle);
+		}
+		if (vcd_status) {
+			DBG("%s(): vcd_stop failed.  vcd_status = %u\n",
+				__func__, vcd_status);
+			mutex_unlock(&mpq_dvb_video_device->lock);
+			return -EIO;
+		}
+		DBG("Send STOP_DONE message to client = %p\n", client_ctx);
+		mutex_unlock(&mpq_dvb_video_device->lock);
+	}
+	return 0;
+}
+
+static int mpq_int_vid_dec_decode_frame(struct video_client_ctx *client_ctx,
+				struct video_data_buffer *input_frame)
+{
+	struct vcd_frame_data vcd_input_buffer;
+	unsigned long kernel_vaddr, phy_addr, user_vaddr;
+	int pmem_fd;
+	struct file *file;
+	s32 buffer_index = -1;
+	u32 vcd_status = VCD_ERR_FAIL;
+	u32 ion_flag = 0;
+	struct ion_handle *buff_handle = NULL;
+
+	if (!client_ctx || !input_frame)
+		return -EINVAL;
+
+	user_vaddr = (unsigned long)input_frame->bufferaddr;
+
+	if (vidc_lookup_addr_table(client_ctx, BUFFER_TYPE_INPUT,
+				      true, &user_vaddr, &kernel_vaddr,
+				      &phy_addr, &pmem_fd, &file,
+				      &buffer_index)) {
+
+		/* kernel_vaddr  is found. send the frame to VCD */
+		memset((void *)&vcd_input_buffer, 0,
+		       sizeof(struct vcd_frame_data));
+		vcd_input_buffer.virtual =
+		    (u8 *) (kernel_vaddr + input_frame->offset);
+		vcd_input_buffer.offset = 0;
+		vcd_input_buffer.frm_clnt_data =
+		    (u32) input_frame->client_data;
+		vcd_input_buffer.ip_frm_tag =
+		    (u32) input_frame->client_data;
+		vcd_input_buffer.data_len = input_frame->buffer_len;
+		vcd_input_buffer.time_stamp = input_frame->pts;
+		/* Rely on VCD using the same flags as OMX */
+		vcd_input_buffer.flags = 0;
+		vcd_input_buffer.desc_buf = NULL;
+		vcd_input_buffer.desc_size = 0;
+		if (vcd_input_buffer.data_len > 0) {
+			ion_flag = vidc_get_fd_info(client_ctx,
+						BUFFER_TYPE_INPUT,
+						pmem_fd,
+						kernel_vaddr,
+						buffer_index,
+						&buff_handle);
+			if (ion_flag == CACHED && buff_handle) {
+				msm_ion_do_cache_op(
+				client_ctx->user_ion_client,
+				buff_handle,
+				(unsigned long *)kernel_vaddr,
+				(unsigned long) vcd_input_buffer.data_len,
+				ION_IOC_CLEAN_CACHES);
+			}
+		}
+		vcd_status = vcd_decode_frame(client_ctx->vcd_handle,
+					      &vcd_input_buffer);
+		if (!vcd_status)
+			return 0;
+		else {
+			DBG("%s(): vcd_decode_frame failed = %u\n", __func__,
+			    vcd_status);
+			return -EIO;
+		}
+
+	} else {
+		DBG("%s(): kernel_vaddr not found\n", __func__);
+		return -EIO;
+	}
+}
+
+static int mpq_int_vid_dec_fill_output_buffer(
+		struct video_client_ctx *client_ctx,
+		struct video_data_buffer *fill_buffer)
+{
+	unsigned long kernel_vaddr, phy_addr, user_vaddr;
+	int pmem_fd;
+	struct file *file;
+	s32 buffer_index = -1;
+	u32 vcd_status = VCD_ERR_FAIL;
+	struct ion_handle *buff_handle = NULL;
+
+	struct vcd_frame_data vcd_frame;
+
+	if (!client_ctx || !fill_buffer)
+		return -EINVAL;
+
+	user_vaddr = (unsigned long)fill_buffer->bufferaddr;
+
+	if (vidc_lookup_addr_table(client_ctx, BUFFER_TYPE_OUTPUT,
+				      true, &user_vaddr, &kernel_vaddr,
+				      &phy_addr, &pmem_fd, &file,
+				      &buffer_index)) {
+
+		memset((void *)&vcd_frame, 0,
+		       sizeof(struct vcd_frame_data));
+		vcd_frame.virtual = (u8 *) kernel_vaddr;
+		vcd_frame.frm_clnt_data = (u32) fill_buffer->client_data;
+		vcd_frame.alloc_len = fill_buffer->buffer_len;
+		vcd_frame.ion_flag = vidc_get_fd_info(client_ctx,
+						 BUFFER_TYPE_OUTPUT,
+						pmem_fd, kernel_vaddr,
+						buffer_index,
+						&buff_handle);
+		vcd_frame.buff_ion_handle = buff_handle;
+		vcd_status = vcd_fill_output_buffer(client_ctx->vcd_handle,
+						    &vcd_frame);
+		if (!vcd_status)
+			return 0;
+		else {
+			DBG("%s(): vcd_fill_output_buffer failed = %u\n",
+			    __func__, vcd_status);
+			return -EINVAL;
+		}
+	} else {
+		DBG("%s(): kernel_vaddr not found\n", __func__);
+		return -EIO;
+	}
+}
+
+
+static int mpq_int_vid_dec_flush(struct video_client_ctx *client_ctx,
+			 enum vdec_bufferflush flush_dir)
+{
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	DBG("msm_vidc_dec: %s() called with dir = %u", __func__,
+		 flush_dir);
+	if (!client_ctx) {
+		DBG("Invalid client_ctx\n");
+		return -EINVAL;
+	}
+
+	switch (flush_dir) {
+	case VDEC_FLUSH_TYPE_INPUT:
+		vcd_status = vcd_flush(client_ctx->vcd_handle,
+					VCD_FLUSH_INPUT);
+		break;
+	case VDEC_FLUSH_TYPE_OUTPUT:
+		vcd_status = vcd_flush(client_ctx->vcd_handle,
+				       VCD_FLUSH_OUTPUT);
+		break;
+	case VDEC_FLUSH_TYPE_ALL:
+		vcd_status = vcd_flush(client_ctx->vcd_handle, VCD_FLUSH_ALL);
+		break;
+	default:
+		ERR("%s(): Inavlid flush cmd. flush_dir = %u\n", __func__,
+		    flush_dir);
+		return -EINVAL;
+		break;
+	}
+
+	if (!vcd_status)
+		return 0;
+	else {
+		DBG("%s(): vcd_flush failed. vcd_status = %u "\
+		    " flush_dir = %u\n", __func__, vcd_status, flush_dir);
+		return -EIO;
+	}
+}
+
+static u32 mpq_int_vid_dec_msg_pending(struct video_client_ctx *client_ctx)
+{
+	u32 islist_empty = 0;
+	mutex_lock(&client_ctx->msg_queue_lock);
+	islist_empty = list_empty(&client_ctx->msg_queue);
+	mutex_unlock(&client_ctx->msg_queue_lock);
+
+	if (islist_empty) {
+		DBG("%s(): vid_dec msg queue empty\n", __func__);
+		if (client_ctx->stop_msg) {
+			DBG("%s(): List empty and Stop Msg set\n",
+				__func__);
+			return client_ctx->stop_msg;
+		}
+	} else {
+		DBG("%s(): vid_dec msg queue Not empty\n", __func__);
+	}
+
+	return !islist_empty;
+}
+
+static int mpq_int_vid_dec_get_next_msg(struct video_client_ctx *client_ctx,
+				struct vdec_msginfo *vdec_msg_info)
+{
+	struct vid_dec_msg *vid_dec_msg = NULL;
+
+	if (!client_ctx)
+		return -EINVAL;
+
+	mutex_lock(&client_ctx->msg_queue_lock);
+	if (!list_empty(&client_ctx->msg_queue)) {
+		DBG("%s(): After Wait\n", __func__);
+		vid_dec_msg = list_first_entry(&client_ctx->msg_queue,
+					       struct vid_dec_msg, list);
+		list_del(&vid_dec_msg->list);
+		memcpy(vdec_msg_info, &vid_dec_msg->vdec_msg_info,
+		       sizeof(struct vdec_msginfo));
+		kfree(vid_dec_msg);
+	}
+	mutex_unlock(&client_ctx->msg_queue_lock);
+	return 0;
+}
+
+static u32 mpq_int_vid_dec_close_client(struct video_client_ctx *client_ctx)
+{
+	struct vid_dec_msg *vdec_msg;
+	u32 vcd_status;
+
+	DBG("msm_vidc_dec: Inside %s()", __func__);
+	if (!client_ctx || (!client_ctx->vcd_handle)) {
+		DBG("Invalid client_ctx\n");
+		return false;
+	}
+
+	mutex_lock(&mpq_dvb_video_device->lock);
+	if (!client_ctx->stop_called) {
+		client_ctx->stop_called = true;
+		client_ctx->stop_sync_cb = true;
+		vcd_status = vcd_stop(client_ctx->vcd_handle);
+		DBG("Stuck at the stop call\n");
+		if (!vcd_status)
+			wait_for_completion(&client_ctx->event);
+		DBG("Came out of wait event\n");
+	}
+	mutex_lock(&client_ctx->msg_queue_lock);
+	while (!list_empty(&client_ctx->msg_queue)) {
+		DBG("%s(): Delete remaining entries\n", __func__);
+		vdec_msg = list_first_entry(&client_ctx->msg_queue,
+						   struct vid_dec_msg, list);
+		if (vdec_msg) {
+			list_del(&vdec_msg->list);
+			kfree(vdec_msg);
+		}
+	}
+	mutex_unlock(&client_ctx->msg_queue_lock);
+	vcd_status = vcd_close(client_ctx->vcd_handle);
+
+	if (vcd_status) {
+		mutex_unlock(&mpq_dvb_video_device->lock);
+		return false;
+	}
+	client_ctx->user_ion_client = NULL;
+	mutex_destroy(&client_ctx->msg_queue_lock);
+	mutex_destroy(&client_ctx->enrty_queue_lock);
+	memset((void *)client_ctx, 0, sizeof(struct video_client_ctx));
+	mpq_dvb_video_device->num_clients--;
+	mutex_unlock(&mpq_dvb_video_device->lock);
+	return true;
+}
+
+static int mpq_int_vid_dec_open_client(struct video_client_ctx **vid_clnt_ctx,
+					int flags)
+{
+	int rc = 0;
+	s32 client_index;
+	struct video_client_ctx *client_ctx = NULL;
+	u8 client_count;
+
+	if (!vid_clnt_ctx) {
+		DBG("Invalid input\n");
+		return -EINVAL;
+	}
+	*vid_clnt_ctx = NULL;
+	client_count = vcd_get_num_of_clients();
+	if (client_count == VIDC_MAX_NUM_CLIENTS) {
+		ERR("ERROR : vid_dec_open() max number of clients"\
+			"limit reached\n");
+		return -ENOMEM;
+	}
+
+	DBG(" Virtual Address of ioremap is %p\n",
+				mpq_dvb_video_device->virt_base);
+	if (!mpq_dvb_video_device->num_clients)
+		if (!vidc_load_firmware())
+			return -ENOMEM;
+
+	client_index = mpq_int_vid_dec_get_empty_client_index();
+	if (client_index == -1) {
+		DBG("%s() : No free clients client_index == -1\n", __func__);
+		vidc_release_firmware();
+		return -ENOMEM;
+	}
+	client_ctx = &mpq_dvb_video_device->vdec_clients[client_index];
+	mpq_dvb_video_device->num_clients++;
+	init_completion(&client_ctx->event);
+	mutex_init(&client_ctx->msg_queue_lock);
+	mutex_init(&client_ctx->enrty_queue_lock);
+	INIT_LIST_HEAD(&client_ctx->msg_queue);
+	init_waitqueue_head(&client_ctx->msg_wait);
+	client_ctx->stop_msg = 0;
+	client_ctx->stop_called = false;
+	client_ctx->stop_sync_cb = false;
+	client_ctx->dmx_disable = 0;
+	if (vcd_get_ion_status()) {
+		client_ctx->user_ion_client = vcd_get_ion_client();
+		if (!client_ctx->user_ion_client) {
+			ERR("vcd_open ion client get failed");
+			rc = -ENOMEM;
+			goto client_failure;
+		}
+	}
+	rc = vcd_open(mpq_dvb_video_device->device_handle, true,
+				  mpq_int_vid_dec_vcd_cb, client_ctx, flags);
+	if (!rc) {
+		wait_for_completion(&client_ctx->event);
+		if (client_ctx->event_status) {
+			DBG("callback for vcd_open returned error: %u",
+				client_ctx->event_status);
+			rc = -ENODEV;
+			goto client_failure;
+		}
+	} else {
+		DBG("vcd_open returned error: %u", rc);
+		goto client_failure;
+	}
+	client_ctx->seq_header_set = false;
+	*vid_clnt_ctx = client_ctx;
+
+	return 0;
+
+client_failure:
+	vidc_release_firmware();
+	mpq_dvb_video_device->num_clients--;
+	mutex_destroy(&client_ctx->msg_queue_lock);
+	mutex_destroy(&client_ctx->enrty_queue_lock);
+	memset((void *)client_ctx, 0, sizeof(struct video_client_ctx));
+	return rc;
+}
+
+static int mpq_dvb_video_open(struct inode *inode, struct file *file)
+{
+	int rc;
+	struct mpq_dvb_video_inst *dev_inst   = NULL;
+	struct dvb_device         *device     = NULL;
+
+	DBG("Inside %s()", __func__);
+	mutex_lock(&mpq_dvb_video_device->lock);
+
+	/* Open the dvb/video instance */
+	rc = dvb_generic_open(inode, file);
+	if (rc) {
+		DBG("Failed in dvb_generic_open with return value :%d\n",
+					rc);
+		mutex_unlock(&mpq_dvb_video_device->lock);
+		return rc;
+
+	}
+
+	device   = (struct dvb_device *)file->private_data;
+	dev_inst = (struct mpq_dvb_video_inst *)device->priv;
+
+	if (dev_inst->client_ctx) {
+		dvb_generic_release(inode, file);
+		mutex_unlock(&mpq_dvb_video_device->lock);
+		return -EEXIST;
+	}
+
+	rc = mpq_int_vid_dec_open_client(&dev_inst->client_ctx, 0);
+	if (rc) {
+		dvb_generic_release(inode, file);
+		mutex_unlock(&mpq_dvb_video_device->lock);
+		return rc;
+	}
+
+	if (!dev_inst->client_ctx) {
+		dvb_generic_release(inode, file);
+		mutex_unlock(&mpq_dvb_video_device->lock);
+		return -ENOMEM;
+	}
+
+	/* Set default source to memory for easier handling */
+	dev_inst->source = VIDEO_SOURCE_MEMORY;
+
+	mutex_unlock(&mpq_dvb_video_device->lock);
+
+	return rc;
+}
+
+static int mpq_dvb_video_term_dmx_src(struct mpq_dvb_video_inst *dev_inst)
+{
+
+	struct mpq_dmx_src_data *dmx_data = dev_inst->dmx_src_data;
+
+	if (NULL == dmx_data)
+		return 0;
+
+	kthread_stop(dmx_data->data_task);
+	mutex_destroy(&dmx_data->msg_queue_lock);
+
+	kfree(dmx_data);
+	dev_inst->dmx_src_data = NULL;
+
+	return 0;
+
+}
+
+static int mpq_dvb_video_release(struct inode *inode, struct file *file)
+{
+	struct dvb_device *device = file->private_data;
+	struct mpq_dvb_video_inst *dev_inst = device->priv;
+
+	vidc_cleanup_addr_table(dev_inst->client_ctx, BUFFER_TYPE_OUTPUT);
+	vidc_cleanup_addr_table(dev_inst->client_ctx, BUFFER_TYPE_INPUT);
+	if (dev_inst->source == VIDEO_SOURCE_DEMUX)
+		mpq_dvb_video_term_dmx_src(dev_inst);
+	mpq_int_vid_dec_close_client(dev_inst->client_ctx);
+	memset((void *)dev_inst, 0, sizeof(struct mpq_dvb_video_inst));
+	vidc_release_firmware();
+	dvb_generic_release(inode, file);
+	return 0;
+}
+
+static void *mpq_int_vid_dec_map_dev_base_addr(void *device_name)
+{
+	return mpq_dvb_video_device->virt_base;
+}
+
+static int mpq_int_vid_dec_vcd_init(void)
+{
+	int rc;
+	struct vcd_init_config vcd_init_config;
+	u32 i;
+
+	/* init_timer(&hw_timer); */
+	DBG("msm_vidc_dec: Inside %s()", __func__);
+	mpq_dvb_video_device->num_clients = 0;
+
+	for (i = 0; i < VIDC_MAX_NUM_CLIENTS; i++) {
+		memset((void *)&mpq_dvb_video_device->vdec_clients[i], 0,
+		       sizeof(mpq_dvb_video_device->vdec_clients[i]));
+	}
+
+	mutex_init(&mpq_dvb_video_device->lock);
+	mpq_dvb_video_device->virt_base = vidc_get_ioaddr();
+	DBG("%s() : base address for VIDC core %u\n", __func__, \
+		(int)mpq_dvb_video_device->virt_base);
+
+	if (!mpq_dvb_video_device->virt_base) {
+		DBG("%s() : ioremap failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	vcd_init_config.device_name = "MPQ_VIDC";
+	vcd_init_config.map_dev_base_addr = mpq_int_vid_dec_map_dev_base_addr;
+	vcd_init_config.interrupt_clr = NULL;
+	vcd_init_config.register_isr = NULL;
+	vcd_init_config.deregister_isr = NULL;
+	vcd_init_config.timer_create = vidc_timer_create;
+	vcd_init_config.timer_release = vidc_timer_release;
+	vcd_init_config.timer_start = vidc_timer_start;
+	vcd_init_config.timer_stop = vidc_timer_stop;
+
+	rc = vcd_init(&vcd_init_config,
+			&mpq_dvb_video_device->device_handle);
+
+	if (rc) {
+		DBG("%s() : vcd_init failed\n", __func__);
+		mutex_destroy(&mpq_dvb_video_device->lock);
+		return -ENODEV;
+	}
+	return 0;
+}
+
+static int mpq_int_vdec_get_fps(struct video_client_ctx *client_ctx,
+				unsigned int *fps)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_frame_rate vcd_frame_rate;
+	u32 vcd_status = VCD_ERR_FAIL;
+
+	if (NULL == fps)
+		return -EINVAL;
+
+	vcd_property_hdr.prop_id = VCD_I_FRAME_RATE;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_frame_rate);
+	vcd_frame_rate.fps_numerator = 0;
+	vcd_frame_rate.fps_denominator = 1;
+
+	*fps = 0;
+	vcd_status = vcd_get_property(client_ctx->vcd_handle,
+				      &vcd_property_hdr, &vcd_frame_rate);
+
+	if (vcd_status)
+		return -EINVAL;
+	else {
+		*fps = (vcd_frame_rate.fps_numerator * 1000)
+			/(vcd_frame_rate.fps_denominator);
+		return 0;
+	}
+}
+
+static int mpq_dvb_video_command_handler(struct mpq_dvb_video_inst *dev_inst,
+					void *parg)
+{
+	struct video_client_ctx *client_ctx = dev_inst->client_ctx;
+	struct video_command *cmd = parg;
+	int rc = 0;
+
+	if (cmd == NULL)
+		return -EINVAL;
+
+	switch (cmd->cmd) {
+	case VIDEO_CMD_SET_CODEC:
+		DBG("cmd : VIDEO_CMD_SET_CODEC\n");
+		rc = mpq_int_vid_dec_set_codec(client_ctx, cmd->codec);
+		break;
+	case VIDEO_CMD_GET_CODEC:
+		DBG("cmd : VIDEO_CMD_GET_CODEC\n");
+		rc = mpq_int_vid_dec_get_codec(client_ctx, &cmd->codec);
+		break;
+	case VIDEO_CMD_SET_OUTPUT_FORMAT:
+		DBG("cmd : VIDEO_CMD_SET_OUTPUT_FORMAT\n");
+		rc = mpq_int_vid_dec_set_output_format(client_ctx,
+							cmd->format);
+		break;
+	case VIDEO_CMD_GET_OUTPUT_FORMAT:
+		DBG("cmd : VIDEO_CMD_GET_OUTPUT_FORMAT\n");
+		rc = mpq_int_vid_dec_get_output_format(client_ctx,
+							&cmd->format);
+		break;
+	case VIDEO_CMD_GET_PIC_RES:
+		DBG("cmd : VIDEO_CMD_GET_PIC_RES\n");
+		rc = mpq_int_vid_dec_get_frame_resolution(client_ctx,
+						&cmd->frame_res);
+		break;
+	case VIDEO_CMD_SET_INPUT_BUFFERS:
+		DBG("cmd : VIDEO_CMD_SET_INPUT_BUFFERS\n");
+		rc = mpq_int_vid_dec_set_buffer(dev_inst, &cmd->buffer,
+						BUFFER_TYPE_INPUT);
+		break;
+	case VIDEO_CMD_SET_OUTPUT_BUFFERS:
+		DBG("cmd : VIDEO_CMD_SET_OUTPUT_BUFFERS\n");
+		rc = mpq_int_vid_dec_set_buffer(dev_inst, &cmd->buffer,
+						BUFFER_TYPE_OUTPUT);
+		break;
+	case VIDEO_CMD_FREE_INPUT_BUFFERS:
+		DBG("cmd : VIDEO_CMD_FREE_INPUT_BUFFERS\n");
+		rc = mpq_int_vid_dec_free_buffer(client_ctx, &cmd->buffer,
+						BUFFER_TYPE_INPUT);
+		break;
+	case VIDEO_CMD_FREE_OUTPUT_BUFFERS:
+		DBG("cmd : VIDEO_CMD_FREE_OUTPUT_BUFFERS\n");
+		rc = mpq_int_vid_dec_free_buffer(client_ctx, &cmd->buffer,
+							BUFFER_TYPE_OUTPUT);
+		break;
+	case VIDEO_CMD_GET_BUFFER_REQ:
+		DBG("cmd : VIDEO_CMD_GET_BUFFER_REQ\n");
+		rc = mpq_int_vid_dec_get_buffer_req(client_ctx, &cmd->buf_req);
+		break;
+	case VIDEO_CMD_READ_RAW_OUTPUT:
+		DBG("cmd : VIDEO_CMD_READ_RAW_OUTPUT\n");
+		rc = mpq_int_vid_dec_fill_output_buffer(client_ctx,
+							&cmd->buffer);
+		break;
+	case VIDEO_CMD_SET_H264_MV_BUFFER:
+		DBG("cmd : VIDEO_CMD_SET_H264_MV_BUFFER\n");
+		rc = mpq_int_vid_dec_set_h264_mv_buffers(client_ctx,
+							&cmd->mv_buffer_prop);
+		break;
+	case VIDEO_CMD_GET_H264_MV_BUFFER:
+		DBG("cmd : VIDEO_CMD_GET_H264_MV_BUFFER\n");
+		rc = mpq_int_vid_dec_get_h264_mv_buffer_size(client_ctx,
+							&cmd->mv_buffer_req);
+		break;
+	case VIDEO_CMD_FREE_H264_MV_BUFFER:
+		DBG("cmd : VIDEO_CMD_FREE_H264_MV_BUFFER\n");
+		rc = mpq_int_vid_dec_free_h264_mv_buffers(client_ctx);
+		break;
+	case VIDEO_CMD_CLEAR_INPUT_BUFFER:
+		DBG("cmd : VIDEO_CMD_CLEAR_INPUT_BUFFER\n");
+		rc = mpq_int_vid_dec_flush(client_ctx, VDEC_FLUSH_TYPE_INPUT);
+		break;
+	case VIDEO_CMD_CLEAR_OUTPUT_BUFFER:
+		DBG("cmd : VIDEO_CMD_CLEAR_OUTPUT_BUFFER\n");
+		rc = mpq_int_vid_dec_flush(client_ctx, VDEC_FLUSH_TYPE_OUTPUT);
+		break;
+	default:
+		rc = -EINVAL;
+		break;
+	}
+
+	return rc;
+}
+
+
+static ssize_t mpq_dvb_video_write(struct file *file, const char __user *buf,
+					size_t count, loff_t *ppos)
+{
+	int rc = 0;
+	struct dvb_device *device = file->private_data;
+	struct mpq_dvb_video_inst *dev_inst = NULL;
+
+	struct video_data_buffer *input_frame =
+				(struct video_data_buffer *)buf;
+
+	if ((device == NULL) || (input_frame == NULL))
+		return -EINVAL;
+
+	dev_inst = device->priv;
+	if (dev_inst == NULL)
+		return -EINVAL;
+
+	rc = mpq_int_vid_dec_decode_frame(dev_inst->client_ctx, input_frame);
+	if (rc)
+		return -EIO;
+
+	return input_frame->buffer_len;
+}
+
+static int mpq_dvb_video_get_event(struct video_client_ctx *client_ctx,
+				struct video_event *ev)
+{
+	int rc;
+	struct vdec_msginfo vdec_msg_info;
+
+	memset(ev, 0, sizeof(struct video_event));
+
+	rc = mpq_int_vid_dec_get_next_msg(client_ctx, &vdec_msg_info);
+	if (rc)
+		return rc;
+
+	ev->status = vdec_msg_info.status_code;
+	/* Map the Message here */
+	switch (vdec_msg_info.msgcode) {
+	case VDEC_MSG_INVALID:
+		DBG("VDEC_MSG_INVALID\n");
+		break;
+	case VDEC_MSG_RESP_INPUT_BUFFER_DONE:
+		DBG("VIDEO_EVENT_INPUT_BUFFER_DONE\n");
+		ev->type = VIDEO_EVENT_INPUT_BUFFER_DONE;
+		ev->u.buffer.client_data =
+				vdec_msg_info.msgdata.input_frame_clientdata;
+		break;
+	case VDEC_MSG_RESP_OUTPUT_BUFFER_DONE:
+		DBG("VIDEO_EVENT_OUTPUT_BUFFER_DONE\n");
+		ev->type = VIDEO_EVENT_OUTPUT_BUFFER_DONE;
+		ev->u.buffer.bufferaddr  =
+				vdec_msg_info.msgdata.output_frame.bufferaddr;
+		ev->u.buffer.buffer_len  =
+				vdec_msg_info.msgdata.output_frame.len;
+		ev->u.buffer.ip_buffer_tag = vdec_msg_info.msgdata.\
+					output_frame.input_frame_clientdata;
+		ev->u.buffer.client_data = vdec_msg_info.msgdata.\
+					output_frame.client_data;
+		ev->u.buffer.pts         =
+				vdec_msg_info.msgdata.output_frame.time_stamp;
+		ev->u.buffer.offset      =
+				vdec_msg_info.msgdata.output_frame.offset;
+		break;
+	case VDEC_MSG_RESP_START_DONE:
+		DBG("VIDEO_EVENT_DECODER_PLAYING\n");
+		ev->type = VIDEO_EVENT_DECODER_PLAYING;
+		break;
+	case VDEC_MSG_RESP_STOP_DONE:
+		DBG("VIDEO_EVENT_DECODER_FREEZED\n");
+		ev->type = VIDEO_EVENT_DECODER_STOPPED;
+		break;
+	case VDEC_MSG_RESP_PAUSE_DONE:
+		DBG("VDEC_MSG_RESP_PAUSE_DONE\n");
+		ev->type = VIDEO_EVENT_DECODER_FREEZED;
+		break;
+	case VDEC_MSG_RESP_RESUME_DONE:
+		DBG("VIDEO_EVENT_DECODER_RESUMED\n");
+		ev->type = VIDEO_EVENT_DECODER_RESUMED;
+		break;
+	case VDEC_MSG_EVT_CONFIG_CHANGED:
+	case VDEC_MSG_EVT_INFO_CONFIG_CHANGED:
+		DBG("VIDEO_EVENT_SEQ_HDR_FOUND\n");
+		ev->type = VIDEO_EVENT_SEQ_HDR_FOUND;
+		break;
+	case VDEC_MSG_RESP_FLUSH_OUTPUT_DONE:
+		DBG("VIDEO_EVENT_OUTPUT_FLUSH_DONE\n");
+		ev->type = VIDEO_EVENT_OUTPUT_FLUSH_DONE;
+		break;
+	case VDEC_MSG_RESP_OUTPUT_FLUSHED:
+		DBG("VIDEO_EVENT_OUTPUT_FLUSHED\n");
+		ev->type = VIDEO_EVENT_OUTPUT_FLUSHED;
+		ev->u.buffer.bufferaddr  =
+				vdec_msg_info.msgdata.output_frame.bufferaddr;
+		ev->u.buffer.buffer_len  =
+				vdec_msg_info.msgdata.output_frame.len;
+		ev->u.buffer.ip_buffer_tag = vdec_msg_info.msgdata.\
+				output_frame.input_frame_clientdata;
+		ev->u.buffer.client_data = vdec_msg_info.msgdata.\
+				output_frame.client_data;
+		ev->u.buffer.pts         =
+				vdec_msg_info.msgdata.output_frame.time_stamp;
+		ev->u.buffer.offset      =
+				vdec_msg_info.msgdata.output_frame.offset;
+		break;
+	case VDEC_MSG_RESP_FLUSH_INPUT_DONE:
+		DBG("VIDEO_EVENT_INPUT_FLUSH_DONE\n");
+		ev->type = VIDEO_EVENT_INPUT_FLUSH_DONE;
+		break;
+	case VDEC_MSG_RESP_INPUT_FLUSHED:
+		DBG("VIDEO_EVENT_INPUT_FLUSHED\n");
+		ev->type = VIDEO_EVENT_INPUT_FLUSHED;
+		ev->u.buffer.client_data =
+				vdec_msg_info.msgdata.input_frame_clientdata;
+		break;
+	}
+	return 0;
+}
+
+static int mpq_dvb_video_play(struct mpq_dvb_video_inst *dev_inst)
+{
+	return mpq_int_vid_dec_start_stop(dev_inst->client_ctx, true);
+}
+
+static int mpq_dvb_video_stop(struct video_client_ctx *client_ctx)
+{
+	return mpq_int_vid_dec_start_stop(client_ctx, false);
+}
+
+static void mpq_dvb_video_get_stream_if(
+				enum mpq_adapter_stream_if interface_id,
+				void *arg)
+{
+	struct mpq_dvb_video_inst *dev_inst = arg;
+
+	DBG("In mpq_dvb_video_get_stream_if : %d\n", interface_id);
+
+	mpq_adapter_get_stream_if(interface_id,
+			&dev_inst->dmx_src_data->stream_buffer);
+
+	wake_up(&dev_inst->dmx_src_data->msg_wait);
+}
+
+static int mpq_dvb_video_init_dmx_src(struct mpq_dvb_video_inst *dev_inst,
+					int device_id)
+{
+	int rc;
+
+	dev_inst->dmx_src_data =  kzalloc(sizeof(struct mpq_dmx_src_data),
+						GFP_KERNEL);
+	if (dev_inst->dmx_src_data == NULL)
+		return -ENOMEM;
+
+	rc = mpq_adapter_get_stream_if(
+		(enum mpq_adapter_stream_if)device_id,
+		&dev_inst->dmx_src_data->stream_buffer);
+
+	if (rc) {
+		kfree(dev_inst->dmx_src_data);
+		return -ENODEV;
+	} else if (dev_inst->dmx_src_data->stream_buffer == NULL) {
+		DBG("Stream Buffer is NULL. Resigtering Notifier.\n");
+		rc = mpq_adapter_notify_stream_if(
+			(enum mpq_adapter_stream_if)device_id,
+			mpq_dvb_video_get_stream_if,
+			(void *)dev_inst);
+		if (rc) {
+			kfree(dev_inst->dmx_src_data);
+			return -ENODEV;
+		}
+	}
+
+	mutex_init(&dev_inst->dmx_src_data->msg_queue_lock);
+	INIT_LIST_HEAD(&dev_inst->dmx_src_data->msg_queue);
+	init_waitqueue_head(&dev_inst->dmx_src_data->msg_wait);
+
+	dev_inst->dmx_src_data->data_task = kthread_run(
+			mpq_bcast_data_handler,	(void *)dev_inst,
+			vid_thread_names[device_id]);
+
+	return 0;
+}
+
+static int mpq_dvb_video_set_source(struct dvb_device *device,
+				video_stream_source_t source)
+{
+	int rc = 0;
+	struct mpq_dvb_video_inst *dev_inst =
+			(struct mpq_dvb_video_inst *)device->priv;
+
+	if (dev_inst->source == source)
+		return rc;
+
+	if ((VIDEO_SOURCE_MEMORY == source) &&
+		(VIDEO_SOURCE_DEMUX == dev_inst->source))
+		mpq_dvb_video_term_dmx_src(dev_inst);
+
+	dev_inst->source = source;
+	if (VIDEO_SOURCE_DEMUX == source)
+		rc = mpq_dvb_video_init_dmx_src(dev_inst, device->id);
+
+	return rc;
+}
+
+static int mpq_dvb_video_ioctl(struct file *file,
+				unsigned int cmd, void *parg)
+{
+	int rc;
+	struct dvb_device *device = (struct dvb_device *)file->private_data;
+	struct video_client_ctx *client_ctx = NULL;
+	struct mpq_dvb_video_inst *dev_inst = NULL;
+
+	if (device == NULL)
+		return -EINVAL;
+
+	dev_inst = (struct mpq_dvb_video_inst *)device->priv;
+	if (dev_inst == NULL)
+		return -EINVAL;
+
+	client_ctx = (struct video_client_ctx *)dev_inst->client_ctx;
+	if (client_ctx == NULL)
+		return -EINVAL;
+
+	switch (cmd) {
+	case VIDEO_PLAY:
+		DBG("ioctl : VIDEO_PLAY\n");
+		rc = mpq_dvb_video_play(dev_inst);
+		break;
+	case VIDEO_STOP:
+		DBG("ioctl : VIDEO_STOP\n");
+		rc = mpq_dvb_video_stop(client_ctx);
+		break;
+	case VIDEO_FREEZE:
+		DBG("ioctl : VIDEO_FREEZE\n");
+		rc = mpq_int_vid_dec_pause_resume(client_ctx, true);
+		break;
+	case VIDEO_CONTINUE:
+		DBG("ioctl : VIDEO_CONTINUE\n");
+		rc = mpq_int_vid_dec_pause_resume(client_ctx, false);
+		break;
+	case VIDEO_CLEAR_BUFFER:
+		DBG("ioctl : VIDEO_CLEAR_BUFFER\n");
+		rc = mpq_int_vid_dec_flush(client_ctx,
+				VDEC_FLUSH_TYPE_ALL);
+		break;
+	case VIDEO_COMMAND:
+	case VIDEO_TRY_COMMAND:
+		DBG("ioctl : VIDEO_COMMAND\n");
+		rc = mpq_dvb_video_command_handler(dev_inst, parg);
+		break;
+	case VIDEO_GET_FRAME_RATE:
+		DBG("ioctl : VIDEO_GET_FRAME_RATE\n");
+		rc = mpq_int_vdec_get_fps(client_ctx,
+				(unsigned int *)parg);
+		break;
+	case VIDEO_GET_EVENT:
+		DBG("ioctl : VIDEO_GET_EVENT\n");
+		rc = mpq_dvb_video_get_event(client_ctx,
+				(struct video_event *)parg);
+		break;
+	case VIDEO_SELECT_SOURCE:
+		DBG("ioctl : VIDEO_SELECT_SOURCE\n");
+		rc = mpq_dvb_video_set_source(device,
+				(video_stream_source_t)parg);
+		break;
+	default:
+		ERR("Invalid IOCTL\n");
+		rc = -EINVAL;
+	}
+
+	return rc;
+
+}
+
+static unsigned int mpq_dvb_video_poll(struct file *file, poll_table *wait)
+{
+	struct dvb_device *device = file->private_data;
+	struct video_client_ctx *client_ctx = NULL;
+	struct mpq_dvb_video_inst *dev_inst = NULL;
+	unsigned int mask = 0;
+
+	DBG("In %s\n", __func__);
+
+	if (device == NULL)
+		return -EINVAL;
+
+	dev_inst = device->priv;
+	if (dev_inst == NULL)
+		return -EINVAL;
+
+	client_ctx = dev_inst->client_ctx;
+	if (client_ctx == NULL)
+		return -EINVAL;
+
+	poll_wait(file, &client_ctx->msg_wait, wait);
+	if (mpq_int_vid_dec_msg_pending(client_ctx))
+		mask |= POLLIN;
+	else
+		mask = 0;
+
+	return mask;
+}
+
+/*
+ * Driver Registration.
+ */
+static const struct file_operations mpq_dvb_video_fops = {
+	.owner		= THIS_MODULE,
+	.write		= mpq_dvb_video_write,
+	.unlocked_ioctl	= dvb_generic_ioctl,
+	.open		= mpq_dvb_video_open,
+	.release	= mpq_dvb_video_release,
+	.poll		= mpq_dvb_video_poll,
+	.llseek		= noop_llseek,
+};
+
+static const struct dvb_device mpq_dvb_video_device_ctrl = {
+	.priv		= NULL,
+	.users		= 4,
+	.readers	= 4,	/* arbitrary */
+	.writers	= 4,
+	.fops		= &mpq_dvb_video_fops,
+	.kernel_ioctl	= mpq_dvb_video_ioctl,
+};
+
+static int __init mpq_dvb_video_init(void)
+{
+	int rc, i = 0, j;
+
+	mpq_dvb_video_device = kzalloc(sizeof(struct mpq_dvb_video_dev),
+				GFP_KERNEL);
+	if (!mpq_dvb_video_device) {
+		ERR("%s Unable to allocate memory for mpq_dvb_video_dev\n",
+		       __func__);
+		return -ENOMEM;
+	}
+
+	mpq_dvb_video_device->mpq_adapter = mpq_adapter_get();
+	if (!mpq_dvb_video_device->mpq_adapter) {
+		ERR("%s Unable to get MPQ Adapter\n", __func__);
+		rc = -ENODEV;
+		goto free_region;
+	}
+
+	rc = mpq_int_vid_dec_vcd_init();
+	if (rc)
+		goto free_region;
+
+	for (i = 0; i < DVB_MPQ_NUM_VIDEO_DEVICES; i++) {
+
+		rc = dvb_register_device(mpq_dvb_video_device->mpq_adapter,
+				&mpq_dvb_video_device->dev_inst[i].video_dev,
+				&mpq_dvb_video_device_ctrl,
+				&mpq_dvb_video_device->dev_inst[i],
+				DVB_DEVICE_VIDEO);
+
+		if (rc) {
+			ERR("Failed in %s with at %d return value :%d\n",
+				__func__, i, rc);
+			goto free_region;
+		}
+
+	}
+
+	return 0;
+
+free_region:
+	for (j = 0; j < i; j++)
+		dvb_unregister_device(
+			mpq_dvb_video_device->dev_inst[j].video_dev);
+
+	kfree(mpq_dvb_video_device);
+	return rc;
+}
+
+static void __exit mpq_dvb_video_exit(void)
+{
+	int i;
+
+	for (i = 0; i < DVB_MPQ_NUM_VIDEO_DEVICES; i++)
+		dvb_unregister_device(
+			mpq_dvb_video_device->dev_inst[i].video_dev);
+
+	mutex_destroy(&mpq_dvb_video_device->lock);
+	kfree(mpq_dvb_video_device);
+}
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MPQ DVB Video driver");
+
+module_init(mpq_dvb_video_init);
+module_exit(mpq_dvb_video_exit);
diff --git a/drivers/media/dvb/mpq/video/mpq_dvb_video_internal.h b/drivers/media/dvb/mpq/video/mpq_dvb_video_internal.h
new file mode 100644
index 0000000..df337b9
--- /dev/null
+++ b/drivers/media/dvb/mpq/video/mpq_dvb_video_internal.h
@@ -0,0 +1,93 @@
+/* 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
+ * 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 MPQ_DVB_VIDEO_INTERNAL_H
+#define MPQ_DVB_VIDEO_INTERNAL_H
+
+#include <linux/msm_vidc_dec.h>
+#include <media/msm/vidc_init.h>
+#include <linux/dvb/video.h>
+
+/*
+ * MPQ Specific Includes.
+ */
+#include "mpq_dvb_debug.h"
+#include "mpq_adapter.h"
+#include "mpq_stream_buffer.h"
+
+#define DVB_MPQ_NUM_VIDEO_DEVICES CONFIG_DVB_MPQ_NUM_VIDEO_DEVICES
+
+/*
+ * Input Buffer Requirements for Video Decoder.
+ */
+#define DVB_VID_NUM_IN_BUFFERS (2)
+#define DVB_VID_IN_BUFFER_SIZE (2*1024*1024)
+#define DVB_VID_IN_BUFFER_ALGN (8*1024)
+
+struct vid_dec_msg {
+	struct list_head list;
+	struct vdec_msginfo vdec_msg_info;
+};
+
+enum mpq_bcast_msgcode {
+	MPQ_BCAST_MSG_START,
+	MPQ_BCAST_MSG_IBD,
+	MPQ_BCAST_MSG_FLUSH,
+	MPQ_BCAST_MSG_TERM
+};
+
+struct mpq_bcast_msg_info {
+	enum mpq_bcast_msgcode code;
+	unsigned int data;
+};
+
+struct mpq_bcast_msg {
+	struct list_head list;
+	struct mpq_bcast_msg_info info;
+};
+
+struct mpq_dmx_src_data {
+	struct mpq_streambuffer *stream_buffer;
+	struct video_data_buffer in_buffer[DVB_VID_NUM_IN_BUFFERS];
+	struct list_head msg_queue;
+	wait_queue_head_t msg_wait;
+	struct mutex msg_queue_lock;
+	struct task_struct *data_task;
+};
+
+struct mpq_dvb_video_inst {
+	struct dvb_device  *video_dev;
+	video_stream_source_t source;
+	struct mpq_dmx_src_data *dmx_src_data;
+	struct video_client_ctx *client_ctx;
+};
+
+struct mpq_dvb_video_dev {
+
+	resource_size_t phys_base;
+	void __iomem *virt_base;
+	unsigned int irq;
+	struct clk *hclk;
+	struct clk *hclk_div2;
+	struct clk *pclk;
+	unsigned long hclk_rate;
+	struct mutex lock;
+	s32 device_handle;
+	struct dvb_adapter *mpq_adapter;
+	struct mpq_dvb_video_inst dev_inst[DVB_MPQ_NUM_VIDEO_DEVICES];
+	struct video_client_ctx vdec_clients[DVB_MPQ_NUM_VIDEO_DEVICES];
+	u32 num_clients;
+	void(*timer_handler)(void *);
+};
+
+#endif /* MPQ_DVB_VIDEO_INTERNAL_H */
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index c0a35f9..ac143b1 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);
@@ -2712,7 +2653,7 @@
 		tx_ps.pi = radio->pi;
 		tx_ps.pty = radio->pty;
 		tx_ps.ps_repeatcount = radio->ps_repeatcount;
-		tx_ps.ps_len = bytes_to_copy;
+		tx_ps.ps_num = (bytes_to_copy / PS_STRING_LEN);
 
 		retval = radio_hci_request(radio->fm_hdev, hci_trans_ps_req,
 				(unsigned long)&tx_ps, RADIO_HCI_TIMEOUT);
@@ -2731,7 +2672,7 @@
 		tx_rt.rt_control =  0x01;
 		tx_rt.pi = radio->pi;
 		tx_rt.pty = radio->pty;
-		tx_rt.ps_len = bytes_to_copy;
+		tx_rt.rt_len = bytes_to_copy;
 
 		retval = radio_hci_request(radio->fm_hdev, hci_trans_rt_req,
 				(unsigned long)&tx_rt, RADIO_HCI_TIMEOUT);
@@ -3538,12 +3479,20 @@
 				struct v4l2_buffer *buffer)
 {
 	struct iris_device  *radio = video_get_drvdata(video_devdata(file));
-	enum iris_buf_t buf_type = buffer->index;
-	struct kfifo *data_fifo;
-	unsigned char *buf = (unsigned char *)buffer->m.userptr;
-	unsigned int len = buffer->length;
-	if (!access_ok(VERIFY_WRITE, buf, len))
-		return -EFAULT;
+	enum iris_buf_t buf_type = -1;
+	unsigned char buf_fifo[STD_BUF_SIZE] = {0};
+	struct kfifo *data_fifo = NULL;
+	unsigned char *buf = NULL;
+	unsigned int len = 0, retval = -1;
+
+	if ((radio == NULL) || (buffer == NULL)) {
+		FMDERR("radio/buffer is NULL\n");
+		return -ENXIO;
+	}
+	buf_type = buffer->index;
+	buf = (unsigned char *)buffer->m.userptr;
+	len = buffer->length;
+
 	if ((buf_type < IRIS_BUF_MAX) && (buf_type >= 0)) {
 		data_fifo = &radio->data_buf[buf_type];
 		if (buf_type == IRIS_BUF_EVENTS)
@@ -3554,10 +3503,20 @@
 		FMDERR("invalid buffer type\n");
 		return -EINVAL;
 	}
-	buffer->bytesused = kfifo_out_locked(data_fifo, buf, len,
-					&radio->buf_lock[buf_type]);
+	if (len <= STD_BUF_SIZE) {
+		buffer->bytesused = kfifo_out_locked(data_fifo, &buf_fifo[0],
+					len, &radio->buf_lock[buf_type]);
+	} else {
+		FMDERR("kfifo_out_locked can not use len more than 128\n");
+		return -EINVAL;
+	}
+	retval = copy_to_user(buf, &buf_fifo[0], buffer->bytesused);
+	if (retval > 0) {
+		FMDERR("Failed to copy %d bytes of data\n", retval);
+		return -EAGAIN;
+	}
 
-	return 0;
+	return retval;
 }
 
 static int iris_vidioc_g_fmt_type_private(struct file *file, void *priv,
diff --git a/drivers/media/video/msm/Kconfig b/drivers/media/video/msm/Kconfig
index c5abd76..e9b4e2b 100644
--- a/drivers/media/video/msm/Kconfig
+++ b/drivers/media/video/msm/Kconfig
@@ -254,6 +254,15 @@
         ---help---
           Enable support for Mercury Jpeg Engine
 
+config MSM_JPEG
+	tristate "Qualcomm MSM Jpeg Encoder Engine support"
+	depends on MSM_CAMERA && ARCH_MSM8974
+	---help---
+          Enable support for Jpeg Encoder/Decoder
+	  Engine for 8974.
+	  This module serves as the common driver
+	  for the JPEG 1.0 encoder and decoder.
+
 config MSM_VPE
 	tristate "Qualcomm MSM Video Pre-processing Engine support"
 	depends on MSM_CAMERA && (ARCH_MSM7X30 || ARCH_MSM8X60)
diff --git a/drivers/media/video/msm/Makefile b/drivers/media/video/msm/Makefile
index 740e424..5921632 100644
--- a/drivers/media/video/msm/Makefile
+++ b/drivers/media/video/msm/Makefile
@@ -20,7 +20,7 @@
   obj-$(CONFIG_MSM_CAMERA) += msm_camera.o
 endif
 obj-$(CONFIG_MSM_CAMERA) += vfe/
-obj-$(CONFIG_MSM_CAMERA) += msm_axi_qos.o gemini/ mercury/
+obj-$(CONFIG_MSM_CAMERA) += msm_axi_qos.o gemini/ mercury/ jpeg_10/
 obj-$(CONFIG_MSM_CAMERA_FLASH) += flash.o
 ifeq ($(CONFIG_MSM_CAMERA_V4L2),y)
   obj-$(CONFIG_ARCH_MSM8X60) += msm_vpe.o
diff --git a/drivers/media/video/msm/actuators/msm_actuator.c b/drivers/media/video/msm/actuators/msm_actuator.c
index 554cddc..b5bdaae 100644
--- a/drivers/media/video/msm/actuators/msm_actuator.c
+++ b/drivers/media/video/msm/actuators/msm_actuator.c
@@ -250,8 +250,6 @@
 			target_step_pos = dest_step_pos;
 			target_lens_pos =
 				a_ctrl->step_position_table[target_step_pos];
-			if (curr_lens_pos == target_lens_pos)
-				return rc;
 			rc = a_ctrl->func_tbl->
 				actuator_write_focus(
 					a_ctrl,
@@ -272,8 +270,6 @@
 			target_step_pos = step_boundary;
 			target_lens_pos =
 				a_ctrl->step_position_table[target_step_pos];
-			if (curr_lens_pos == target_lens_pos)
-				return rc;
 			rc = a_ctrl->func_tbl->
 				actuator_write_focus(
 					a_ctrl,
diff --git a/drivers/media/video/msm/cci/msm_cam_cci_hwreg.h b/drivers/media/video/msm/cci/msm_cam_cci_hwreg.h
index 68c78d5..2d489b9 100644
--- a/drivers/media/video/msm/cci/msm_cam_cci_hwreg.h
+++ b/drivers/media/video/msm/cci/msm_cam_cci_hwreg.h
@@ -26,6 +26,7 @@
 #define CCI_I2C_M0_SDA_CTL_2_ADDR                                   0x0000010c
 #define CCI_I2C_M0_READ_DATA_ADDR                                   0x00000118
 #define CCI_I2C_M0_MISC_CTL_ADDR                                    0x00000110
+#define CCI_I2C_M0_READ_BUF_LEVEL_ADDR                              0x0000011C
 #define CCI_HALT_REQ_ADDR                                           0x00000034
 #define CCI_M0_HALT_REQ_RMSK                                               0x1
 #define CCI_M1_HALT_REQ_RMSK                                              0x01
diff --git a/drivers/media/video/msm/cci/msm_cci.c b/drivers/media/video/msm/cci/msm_cci.c
index ad3cc6a..09dfd7c 100644
--- a/drivers/media/video/msm/cci/msm_cci.c
+++ b/drivers/media/video/msm/cci/msm_cci.c
@@ -24,11 +24,10 @@
 #include "msm_cam_cci_hwreg.h"
 
 #define V4L2_IDENT_CCI 50005
-#define CCI_I2C_QUEUE_0_SIZE 2
+#define CCI_I2C_QUEUE_0_SIZE 64
 #define CCI_I2C_QUEUE_1_SIZE 16
 
-#undef CDBG
-#define CDBG pr_debug
+#define CCI_TIMEOUT msecs_to_jiffies(100)
 
 static void msm_cci_set_clk_param(struct cci_device *cci_dev)
 {
@@ -127,8 +126,9 @@
 		msm_camera_io_w(reg_val, cci_dev->base + CCI_QUEUE_START_ADDR);
 		CDBG("%s line %d wait_for_completion_interruptible\n",
 			__func__, __LINE__);
-		wait_for_completion_interruptible(&cci_dev->
-			cci_master_info[master].reset_complete);
+		wait_for_completion_interruptible_timeout(&cci_dev->
+			cci_master_info[master].reset_complete, CCI_TIMEOUT);
+
 		rc = cci_dev->cci_master_info[master].status;
 		if (rc < 0)
 			pr_err("%s failed rc %d\n", __func__, rc);
@@ -221,7 +221,7 @@
 {
 	uint32_t rc = 0;
 	uint32_t val = 0;
-	int32_t read_bytes = 0;
+	int32_t read_words = 0, exp_words = 0;
 	int32_t index = 0, first_byte = 0;
 	uint32_t i = 0;
 	enum cci_i2c_master_t master;
@@ -234,6 +234,9 @@
 	read_cfg = &c_ctrl->cfg.cci_i2c_read_cfg;
 	mutex_lock(&cci_dev->cci_master_info[master].mutex);
 	CDBG("%s master %d, queue %d\n", __func__, master, queue);
+	CDBG("%s set param sid 0x%x retries %d id_map %d\n", __func__,
+		c_ctrl->cci_info->sid, c_ctrl->cci_info->retries,
+		c_ctrl->cci_info->id_map);
 	val = CCI_I2C_SET_PARAM_CMD | c_ctrl->cci_info->sid << 4 |
 		c_ctrl->cci_info->retries << 16 |
 		c_ctrl->cci_info->id_map << 18;
@@ -285,11 +288,18 @@
 
 	val = 1 << ((master * 2) + queue);
 	msm_camera_io_w(val, cci_dev->base + CCI_QUEUE_START_ADDR);
+	wait_for_completion_interruptible_timeout(&cci_dev->
+		cci_master_info[master].reset_complete, CCI_TIMEOUT);
 
-	wait_for_completion_interruptible(&cci_dev->
-		cci_master_info[master].reset_complete);
-
-	read_bytes = (read_cfg->num_byte / 4) + 1;
+	read_words = msm_camera_io_r(cci_dev->base +
+		CCI_I2C_M0_READ_BUF_LEVEL_ADDR + master * 0x100);
+	exp_words = ((read_cfg->num_byte / 4) + 1);
+	if (read_words != exp_words) {
+		pr_err("%s:%d read_words = %d, exp words = %d\n", __func__,
+			__LINE__, read_words, exp_words);
+		memset(read_cfg->data, 0, read_cfg->num_byte);
+		goto ERROR;
+	}
 	index = 0;
 	CDBG("%s index %d num_type %d\n", __func__, index,
 		read_cfg->num_byte);
@@ -311,7 +321,7 @@
 				index++;
 			}
 		}
-	} while (--read_bytes > 0);
+	} while (--read_words > 0);
 ERROR:
 	mutex_unlock(&cci_dev->cci_master_info[master].mutex);
 	return rc;
@@ -328,6 +338,9 @@
 	cci_dev = v4l2_get_subdevdata(sd);
 	master = c_ctrl->cci_info->cci_i2c_master;
 	CDBG("%s master %d, queue %d\n", __func__, master, queue);
+	CDBG("%s set param sid 0x%x retries %d id_map %d\n", __func__,
+		c_ctrl->cci_info->sid, c_ctrl->cci_info->retries,
+		c_ctrl->cci_info->id_map);
 	mutex_lock(&cci_dev->cci_master_info[master].mutex);
 	val = CCI_I2C_SET_PARAM_CMD | c_ctrl->cci_info->sid << 4 |
 		c_ctrl->cci_info->retries << 16 |
@@ -366,7 +379,7 @@
 
 	val = msm_camera_io_r(cci_dev->base + CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR +
 		master * 0x200 + queue * 0x100);
-	CDBG("%s line %d size of queue %d\n", __func__, __LINE__, val);
+	CDBG("%s:%d cur word count %d\n", __func__, __LINE__, val);
 	CDBG("%s:%d CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR\n", __func__, __LINE__);
 	msm_camera_io_w(val, cci_dev->base + CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR +
 		master * 0x200 + queue * 0x100);
@@ -378,8 +391,9 @@
 
 	CDBG("%s line %d wait_for_completion_interruptible\n",
 		__func__, __LINE__);
-	wait_for_completion_interruptible(&cci_dev->
-		cci_master_info[master].reset_complete);
+	wait_for_completion_interruptible_timeout(&cci_dev->
+		cci_master_info[master].reset_complete, CCI_TIMEOUT);
+
 ERROR:
 	mutex_unlock(&cci_dev->cci_master_info[master].mutex);
 	return rc;
@@ -395,7 +409,10 @@
 }
 
 static struct msm_cam_clk_info cci_clk_info[] = {
-	{"cci_clk_src", 19200000},
+	{"camss_top_ahb_clk", -1},
+	{"cci_src_clk", 19200000},
+	{"cci_ahb_clk", -1},
+	{"cci_clk", -1},
 };
 
 static int32_t msm_cci_init(struct v4l2_subdev *sd)
@@ -411,7 +428,7 @@
 	rc = msm_cam_clk_enable(&cci_dev->pdev->dev, cci_clk_info,
 		cci_dev->cci_clk, ARRAY_SIZE(cci_clk_info), 1);
 	if (rc < 0) {
-		CDBG("%s: regulator enable failed\n", __func__);
+		CDBG("%s: clk enable failed\n", __func__);
 		goto clk_enable_failed;
 	}
 
@@ -421,8 +438,9 @@
 	cci_dev->cci_master_info[MASTER_0].reset_pending = TRUE;
 	msm_camera_io_w(0xFFFFFFFF, cci_dev->base + CCI_RESET_CMD_ADDR);
 	msm_camera_io_w(0x1, cci_dev->base + CCI_RESET_CMD_ADDR);
-	wait_for_completion_interruptible(&cci_dev->cci_master_info[MASTER_0].
-		reset_complete);
+	wait_for_completion_interruptible_timeout(
+		&cci_dev->cci_master_info[MASTER_0].reset_complete,
+		CCI_TIMEOUT);
 	msm_cci_set_clk_param(cci_dev);
 	msm_camera_io_w(0xFFFFFFFF, cci_dev->base + CCI_IRQ_MASK_0_ADDR);
 	msm_camera_io_w(0xFFFFFFFF, cci_dev->base + CCI_IRQ_CLEAR_0_ADDR);
@@ -535,6 +553,12 @@
 		cci_dev->cci_master_info[MASTER_1].reset_pending = TRUE;
 		msm_camera_io_w(CCI_M1_RESET_RMSK,
 			cci_dev->base + CCI_RESET_CMD_ADDR);
+	} else {
+		pr_err("%s unhandled irq 0x%x\n", __func__, irq);
+		cci_dev->cci_master_info[MASTER_0].status = 0;
+		complete(&cci_dev->cci_master_info[MASTER_0].reset_complete);
+		cci_dev->cci_master_info[MASTER_1].status = 0;
+		complete(&cci_dev->cci_master_info[MASTER_1].reset_complete);
 	}
 	return IRQ_HANDLED;
 }
@@ -686,14 +710,11 @@
 		goto cci_release_mem;
 	}
 
-	CDBG("%s line %d cci irq start %d end %d\n", __func__,
-		__LINE__,
-		new_cci_dev->irq->start,
-		new_cci_dev->irq->end);
-
 	new_cci_dev->pdev = pdev;
 	msm_cci_initialize_cci_params(new_cci_dev);
-
+	rc = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+	if (rc)
+		pr_err("%s: failed to add child nodes, rc=%d\n", __func__, rc);
 	CDBG("%s line %d\n", __func__, __LINE__);
 	return 0;
 
diff --git a/drivers/media/video/msm/csi/Makefile b/drivers/media/video/msm/csi/Makefile
index 547eb13..5aaaff7 100644
--- a/drivers/media/video/msm/csi/Makefile
+++ b/drivers/media/video/msm/csi/Makefile
@@ -1,5 +1,5 @@
 GCC_VERSION      := $(shell $(CONFIG_SHELL) $(PWD)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc)
-ccflags-y += -Idrivers/media/video/msm
+ccflags-y += -Idrivers/media/video/msm -Idrivers/media/video/msm/server
 ifeq ($(CONFIG_MSM_CSI20_HEADER),y)
   ccflags-y += -Idrivers/media/video/msm/csi/include/csi2.0
 else ifeq ($(CONFIG_MSM_CSI30_HEADER),y)
diff --git a/drivers/media/video/msm/csi/include/csi2.0/msm_csid_hwreg.h b/drivers/media/video/msm/csi/include/csi2.0/msm_csid_hwreg.h
index c79748c..4682f8f 100644
--- a/drivers/media/video/msm/csi/include/csi2.0/msm_csid_hwreg.h
+++ b/drivers/media/video/msm/csi/include/csi2.0/msm_csid_hwreg.h
@@ -46,6 +46,7 @@
 #define CSID_RST_DONE_IRQ_BITSHIFT                  11
 #define CSID_RST_STB_ALL                            0x7FFF
 #define CSID_DL_INPUT_SEL_SHIFT                     0x2
-#define CSID_PHY_SEL_SHIFT                          0x17
+#define CSID_PHY_SEL_SHIFT                          17
+#define CSID_VERSION                                0x02000011
 
 #endif
diff --git a/drivers/media/video/msm/csi/include/csi2.0/msm_csiphy_hwreg.h b/drivers/media/video/msm/csi/include/csi2.0/msm_csiphy_hwreg.h
index 93d1fc4..2e83101 100644
--- a/drivers/media/video/msm/csi/include/csi2.0/msm_csiphy_hwreg.h
+++ b/drivers/media/video/msm/csi/include/csi2.0/msm_csiphy_hwreg.h
@@ -28,6 +28,7 @@
 #define MIPI_CSIPHY_LNCK_MISC1_ADDR              0x128
 #define MIPI_CSIPHY_GLBL_RESET_ADDR              0x140
 #define MIPI_CSIPHY_GLBL_PWR_CFG_ADDR            0x144
+#define MIPI_CSIPHY_GLBL_IRQ_CMD_ADDR            0x164
 #define MIPI_CSIPHY_INTERRUPT_STATUS0_ADDR       0x180
 #define MIPI_CSIPHY_INTERRUPT_MASK0_ADDR         0x1A0
 #define MIPI_CSIPHY_INTERRUPT_MASK_VAL           0x6F
@@ -37,5 +38,6 @@
 #define MIPI_CSIPHY_MODE_CONFIG_SHIFT            0x4
 #define MIPI_CSIPHY_GLBL_T_INIT_CFG0_ADDR        0x1E0
 #define MIPI_CSIPHY_T_WAKEUP_CFG0_ADDR           0x1E8
+#define CSIPHY_VERSION                           0x0
 
 #endif
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 c678ea2..d37d67e 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
@@ -64,16 +64,25 @@
 #define MISC_LOGIC_RST_STB           1
 #define STROBED_RST_EN               0
 
+#define ISPIF_RST_CMD_MASK           0xFE0F1FFF
+#define ISPIF_RST_CMD_1_MASK         0xFC0F1FF9
+
 #define PIX_INTF_0_OVERFLOW_IRQ      12
 #define RAW_INTF_0_OVERFLOW_IRQ      25
 #define RAW_INTF_1_OVERFLOW_IRQ      25
+#define RAW_INTF_2_OVERFLOW_IRQ      12
 #define RESET_DONE_IRQ               27
 
-#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_STATUS_MASK        0x0A493249
+#define ISPIF_IRQ_STATUS_1_MASK      0x02493249
+#define ISPIF_IRQ_STATUS_2_MASK      0x00001249
+
+#define ISPIF_IRQ_STATUS_PIX_SOF_MASK	0x249
+#define ISPIF_IRQ_STATUS_RDI0_SOF_MASK	0x492000
+#define ISPIF_IRQ_STATUS_RDI1_SOF_MASK	0x492000
+#define ISPIF_IRQ_STATUS_RDI2_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_csid_hwreg.h b/drivers/media/video/msm/csi/include/csi3.0/msm_csid_hwreg.h
index 27d5a06..11a04d5 100644
--- a/drivers/media/video/msm/csi/include/csi3.0/msm_csid_hwreg.h
+++ b/drivers/media/video/msm/csi/include/csi3.0/msm_csid_hwreg.h
@@ -46,6 +46,7 @@
 #define CSID_RST_DONE_IRQ_BITSHIFT                  11
 #define CSID_RST_STB_ALL                            0x7FFF
 #define CSID_DL_INPUT_SEL_SHIFT                     0x4
-#define CSID_PHY_SEL_SHIFT                          0x17
+#define CSID_PHY_SEL_SHIFT                          17
+#define CSID_VERSION                                0x30000000
 
 #endif
diff --git a/drivers/media/video/msm/csi/include/csi3.0/msm_csiphy_hwreg.h b/drivers/media/video/msm/csi/include/csi3.0/msm_csiphy_hwreg.h
index 79791bd..4e640e3 100644
--- a/drivers/media/video/msm/csi/include/csi3.0/msm_csiphy_hwreg.h
+++ b/drivers/media/video/msm/csi/include/csi3.0/msm_csiphy_hwreg.h
@@ -27,15 +27,17 @@
 #define MIPI_CSIPHY_LNCK_MISC1_ADDR              0x128
 #define MIPI_CSIPHY_GLBL_RESET_ADDR              0x140
 #define MIPI_CSIPHY_GLBL_PWR_CFG_ADDR            0x144
+#define MIPI_CSIPHY_GLBL_IRQ_CMD_ADDR            0x164
 #define MIPI_CSIPHY_HW_VERSION_ADDR              0x188
 #define MIPI_CSIPHY_INTERRUPT_STATUS0_ADDR       0x18C
 #define MIPI_CSIPHY_INTERRUPT_MASK0_ADDR         0x1AC
 #define MIPI_CSIPHY_INTERRUPT_MASK_VAL           0x3F
-#define MIPI_CSIPHY_INTERRUPT_MASK_ADDR          0x1B0
+#define MIPI_CSIPHY_INTERRUPT_MASK_ADDR          0x1AC
 #define MIPI_CSIPHY_INTERRUPT_CLEAR0_ADDR        0x1CC
-#define MIPI_CSIPHY_INTERRUPT_CLEAR_ADDR         0x1D0
+#define MIPI_CSIPHY_INTERRUPT_CLEAR_ADDR         0x1CC
 #define MIPI_CSIPHY_MODE_CONFIG_SHIFT            0x4
 #define MIPI_CSIPHY_GLBL_T_INIT_CFG0_ADDR        0x1EC
 #define MIPI_CSIPHY_T_WAKEUP_CFG0_ADDR           0x1F4
+#define CSIPHY_VERSION                           0x10
 
 #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 4b17538..7c09c4f 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
@@ -78,17 +78,25 @@
 #define MISC_LOGIC_RST_STB           1
 #define STROBED_RST_EN               0
 
+#define ISPIF_RST_CMD_MASK           0xFE0F1FFF
+#define ISPIF_RST_CMD_1_MASK         0xFC0F1FF9
+
 #define PIX_INTF_0_OVERFLOW_IRQ      12
 #define RAW_INTF_0_OVERFLOW_IRQ      25
 #define RAW_INTF_1_OVERFLOW_IRQ      25
+#define RAW_INTF_2_OVERFLOW_IRQ      12
 #define RESET_DONE_IRQ               27
 
-#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
+#define ISPIF_IRQ_STATUS_MASK        0x0A493249
+#define ISPIF_IRQ_STATUS_1_MASK      0x02493249
+#define ISPIF_IRQ_STATUS_2_MASK      0x00001249
 
+#define ISPIF_IRQ_STATUS_PIX_SOF_MASK	0x249
+#define ISPIF_IRQ_STATUS_RDI0_SOF_MASK	0x492000
+#define ISPIF_IRQ_STATUS_RDI1_SOF_MASK	0x492000
+#define ISPIF_IRQ_STATUS_RDI2_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_csic.c b/drivers/media/video/msm/csi/msm_csic.c
index bcb7bb3..c34d9f7 100644
--- a/drivers/media/video/msm/csi/msm_csic.c
+++ b/drivers/media/video/msm/csi/msm_csic.c
@@ -137,18 +137,17 @@
 #define MIPI_PWR_CNTL_EN	0x07
 #define MIPI_PWR_CNTL_DIS	0x0
 
-static int msm_csic_config(struct csic_cfg_params *cfg_params)
+static int msm_csic_config(struct v4l2_subdev *sd,
+	struct msm_camera_csi_params *csic_params)
 {
 	int rc = 0;
 	uint32_t val = 0;
 	struct csic_device *csic_dev;
-	struct msm_camera_csi_params *csic_params;
 	void __iomem *csicbase;
 	int i;
 
-	csic_dev = v4l2_get_subdevdata(cfg_params->subdev);
+	csic_dev = v4l2_get_subdevdata(sd);
 	csicbase = csic_dev->base;
-	csic_params = cfg_params->parms;
 
 	/* Enable error correction for DATA lane. Applies to all data lanes */
 	msm_camera_io_w(0x4, csicbase + MIPI_PHY_CONTROL);
@@ -259,7 +258,7 @@
 	{"csi_pclk", -1},
 };
 
-static int msm_csic_init(struct v4l2_subdev *sd, uint32_t *csic_version)
+static int msm_csic_init(struct v4l2_subdev *sd)
 {
 	int rc = 0;
 	struct csic_device *csic_dev;
@@ -355,17 +354,40 @@
 	return 0;
 }
 
+static long msm_csic_cmd(struct v4l2_subdev *sd, void *arg)
+{
+	long rc = 0;
+	struct csic_cfg_data cdata;
+	struct msm_camera_csi_params csic_params;
+	if (copy_from_user(&cdata,
+		(void *)arg,
+		sizeof(struct csic_cfg_data)))
+		return -EFAULT;
+	CDBG("%s cfgtype = %d\n", __func__, cdata.cfgtype);
+	switch (cdata.cfgtype) {
+	case CSIC_INIT:
+		rc = msm_csic_init(sd);
+		break;
+	case CSIC_CFG:
+		if (copy_from_user(&csic_params,
+			(void *)cdata.csic_params,
+			sizeof(struct msm_camera_csi_params)))
+			return -EFAULT;
+		rc = msm_csic_config(sd, &csic_params);
+		break;
+	default:
+		rc = -EINVAL;
+		break;
+	}
+	return rc;
+}
+
 static long msm_csic_subdev_ioctl(struct v4l2_subdev *sd,
 			unsigned int cmd, void *arg)
 {
-	struct csic_cfg_params cfg_params;
 	switch (cmd) {
 	case VIDIOC_MSM_CSIC_CFG:
-		cfg_params.subdev = sd;
-		cfg_params.parms = arg;
-		return msm_csic_config((struct csic_cfg_params *)&cfg_params);
-	case VIDIOC_MSM_CSIC_INIT:
-		return msm_csic_init(sd, (uint32_t *)arg);
+		return msm_csic_cmd(sd, arg);
 	case VIDIOC_MSM_CSIC_RELEASE:
 		return msm_csic_release(sd);
 	default:
diff --git a/drivers/media/video/msm/csi/msm_csic.h b/drivers/media/video/msm/csi/msm_csic.h
index 177e9d1..c8f1f99 100644
--- a/drivers/media/video/msm/csi/msm_csic.h
+++ b/drivers/media/video/msm/csi/msm_csic.h
@@ -33,19 +33,10 @@
 	struct clk *csic_clk[5];
 };
 
-struct csic_cfg_params {
-	struct v4l2_subdev *subdev;
-	void *parms;
-};
-
 #define VIDIOC_MSM_CSIC_CFG \
-	_IOWR('V', BASE_VIDIOC_PRIVATE + 4, struct csic_cfg_params)
-
-#define VIDIOC_MSM_CSIC_INIT \
-	_IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct v4l2_subdev*)
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 4, struct csic_cfg_data*)
 
 #define VIDIOC_MSM_CSIC_RELEASE \
-	_IOWR('V', BASE_VIDIOC_PRIVATE + 6, struct v4l2_subdev*)
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct v4l2_subdev*)
 
 #endif
-
diff --git a/drivers/media/video/msm/csi/msm_csid.c b/drivers/media/video/msm/csi/msm_csid.c
index 6ee87b7..535ea0a 100644
--- a/drivers/media/video/msm/csi/msm_csid.c
+++ b/drivers/media/video/msm/csi/msm_csid.c
@@ -11,8 +11,6 @@
  */
 
 #include <linux/delay.h>
-#include <linux/clk.h>
-#include <linux/io.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <mach/board.h>
@@ -21,11 +19,17 @@
 #include "msm_csid.h"
 #include "msm_csid_hwreg.h"
 #include "msm.h"
+#include "msm_cam_server.h"
 
 #define V4L2_IDENT_CSID                            50002
+#define CSID_VERSION_V2                      0x02000011
+#define CSID_VERSION_V3                      0x30000000
 
 #define DBG_CSID 0
 
+#define TRUE   1
+#define FALSE  0
+
 static int msm_csid_cid_lut(
 	struct msm_camera_csid_lut_params *csid_lut_params,
 	void __iomem *csidbase)
@@ -33,7 +37,17 @@
 	int rc = 0, i = 0;
 	uint32_t val = 0;
 
+	if (!csid_lut_params) {
+		pr_err("%s:%d csid_lut_params NULL\n", __func__, __LINE__);
+		return -EINVAL;
+	}
 	for (i = 0; i < csid_lut_params->num_cid && i < 16; i++) {
+		CDBG("%s lut params num_cid = %d, cid = %d, dt = %x, df = %d\n",
+			__func__,
+			csid_lut_params->num_cid,
+			csid_lut_params->vc_cfg[i].cid,
+			csid_lut_params->vc_cfg[i].dt,
+			csid_lut_params->vc_cfg[i].decode_format);
 		if (csid_lut_params->vc_cfg[i].dt < 0x12 ||
 			csid_lut_params->vc_cfg[i].dt > 0x37) {
 			CDBG("%s: unsupported data type 0x%x\n",
@@ -47,6 +61,7 @@
 			((csid_lut_params->vc_cfg[i].cid % 4) * 8));
 		msm_camera_io_w(val, csidbase + CSID_CID_LUT_VC_0_ADDR +
 			(csid_lut_params->vc_cfg[i].cid >> 2) * 4);
+
 		val = (csid_lut_params->vc_cfg[i].decode_format << 4) | 0x3;
 		msm_camera_io_w(val, csidbase + CSID_CID_n_CFG_ADDR +
 			(csid_lut_params->vc_cfg[i].cid * 4));
@@ -68,19 +83,24 @@
 	struct msm_camera_csid_params *csid_params) {}
 #endif
 
-static int msm_csid_config(struct csid_cfg_params *cfg_params)
+static int msm_csid_config(struct csid_device *csid_dev,
+	struct msm_camera_csid_params *csid_params)
 {
 	int rc = 0;
 	uint32_t val = 0;
-	struct csid_device *csid_dev;
-	struct msm_camera_csid_params *csid_params;
 	void __iomem *csidbase;
-	csid_dev = v4l2_get_subdevdata(cfg_params->subdev);
 	csidbase = csid_dev->base;
-	if (csidbase == NULL)
-		return -ENOMEM;
-	csid_params = cfg_params->parms;
+	if (!csidbase || !csid_params) {
+		pr_err("%s:%d csidbase %p, csid params %p\n", __func__,
+			__LINE__, csidbase, csid_params);
+		return -EINVAL;
+	}
 
+	CDBG("%s csid_params, lane_cnt = %d, lane_assign = %x, phy sel = %d\n",
+		__func__,
+		csid_params->lane_cnt,
+		csid_params->lane_assign,
+		csid_params->phy_sel);
 	val = csid_params->lane_cnt - 1;
 	val |= csid_params->lane_assign << CSID_DL_INPUT_SEL_SHIFT;
 	if (csid_dev->hw_version < 0x30000000) {
@@ -98,7 +118,6 @@
 		return rc;
 
 	msm_csid_set_debug_reg(csidbase, csid_params);
-
 	return rc;
 }
 
@@ -106,6 +125,10 @@
 {
 	uint32_t irq;
 	struct csid_device *csid_dev = data;
+	if (!csid_dev) {
+		pr_err("%s:%d csid_dev NULL\n", __func__, __LINE__);
+		return IRQ_HANDLED;
+	}
 	irq = msm_camera_io_r(csid_dev->base + CSID_IRQ_STATUS_ADDR);
 	CDBG("%s CSID%d_IRQ_STATUS_ADDR = 0x%x\n",
 		 __func__, csid_dev->pdev->id, irq);
@@ -115,6 +138,16 @@
 	return IRQ_HANDLED;
 }
 
+int msm_csid_irq_routine(struct v4l2_subdev *sd, u32 status, bool *handled)
+{
+	struct csid_device *csid_dev = v4l2_get_subdevdata(sd);
+	irqreturn_t ret;
+	CDBG("%s E\n", __func__);
+	ret = msm_csid_irq(csid_dev->irq->start, csid_dev);
+	*handled = TRUE;
+	return 0;
+}
+
 static void msm_csid_reset(struct csid_device *csid_dev)
 {
 	msm_camera_io_w(CSID_RST_STB_ALL, csid_dev->base + CSID_RST_CMD_ADDR);
@@ -131,53 +164,150 @@
 	return 0;
 }
 
-static struct msm_cam_clk_info csid_clk_info[] = {
+static struct msm_cam_clk_info csid_8960_clk_info[] = {
 	{"csi_src_clk", 177780000},
 	{"csi_clk", -1},
 	{"csi_phy_clk", -1},
 	{"csi_pclk", -1},
 };
 
-static struct camera_vreg_t csid_vreg_info[] = {
+static struct msm_cam_clk_info csid0_8974_clk_info[] = {
+	{"csi0_ahb_clk", -1},
+	{"csi0_src_clk", 200000000},
+	{"csi0_clk", -1},
+	{"csi0_phy_clk", -1},
+	{"csi0_pix_clk", -1},
+	{"csi0_rdi_clk", -1},
+};
+
+static struct msm_cam_clk_info csid1_8974_clk_info[] = {
+	{"csi1_ahb_clk", -1},
+	{"csi1_src_clk", 200000000},
+	{"csi1_clk", -1},
+	{"csi1_phy_clk", -1},
+	{"csi1_pix_clk", -1},
+	{"csi1_rdi_clk", -1},
+};
+
+static struct msm_cam_clk_info csid2_8974_clk_info[] = {
+	{"csi2_ahb_clk", -1},
+	{"csi2_src_clk", 200000000},
+	{"csi2_clk", -1},
+	{"csi2_phy_clk", -1},
+	{"csi2_pix_clk", -1},
+	{"csi2_rdi_clk", -1},
+};
+
+static struct msm_cam_clk_info csid3_8974_clk_info[] = {
+	{"csi3_ahb_clk", -1},
+	{"csi3_src_clk", 200000000},
+	{"csi3_clk", -1},
+	{"csi3_phy_clk", -1},
+	{"csi3_pix_clk", -1},
+	{"csi3_rdi_clk", -1},
+};
+
+static struct msm_cam_clk_setting csid_8974_clk_info[] = {
+	{&csid0_8974_clk_info[0], ARRAY_SIZE(csid0_8974_clk_info)},
+	{&csid1_8974_clk_info[0], ARRAY_SIZE(csid1_8974_clk_info)},
+	{&csid2_8974_clk_info[0], ARRAY_SIZE(csid2_8974_clk_info)},
+	{&csid3_8974_clk_info[0], ARRAY_SIZE(csid3_8974_clk_info)},
+};
+
+static struct camera_vreg_t csid_8960_vreg_info[] = {
 	{"mipi_csi_vdd", REG_LDO, 1200000, 1200000, 20000},
 };
 
-static int msm_csid_init(struct v4l2_subdev *sd, uint32_t *csid_version)
+static struct camera_vreg_t csid_8974_vreg_info[] = {
+	{"mipi_csi_vdd", REG_LDO, 1800000, 1800000, 12000},
+};
+
+static int msm_csid_init(struct csid_device *csid_dev, uint32_t *csid_version)
 {
 	int rc = 0;
-	struct csid_device *csid_dev;
-	csid_dev = v4l2_get_subdevdata(sd);
-	if (csid_dev == NULL) {
-		rc = -ENOMEM;
+	uint8_t core_id = 0;
+
+	if (!csid_version) {
+		pr_err("%s:%d csid_version NULL\n", __func__, __LINE__);
+		rc = -EINVAL;
+		return rc;
+	}
+
+	if (csid_dev->csid_state == CSID_POWER_UP) {
+		pr_err("%s: csid invalid state %d\n", __func__,
+			csid_dev->csid_state);
+		rc = -EINVAL;
 		return rc;
 	}
 
 	csid_dev->base = ioremap(csid_dev->mem->start,
 		resource_size(csid_dev->mem));
 	if (!csid_dev->base) {
+		pr_err("%s csid_dev->base NULL\n", __func__);
 		rc = -ENOMEM;
 		return rc;
 	}
 
-	rc = msm_camera_config_vreg(&csid_dev->pdev->dev, csid_vreg_info,
-		ARRAY_SIZE(csid_vreg_info), &csid_dev->csi_vdd, 1);
-	if (rc < 0) {
-		pr_err("%s: regulator on failed\n", __func__);
-		goto vreg_config_failed;
-	}
+	if (CSID_VERSION <= CSID_VERSION_V2) {
+		rc = msm_camera_config_vreg(&csid_dev->pdev->dev,
+			csid_8960_vreg_info, ARRAY_SIZE(csid_8960_vreg_info),
+			NULL, 0, &csid_dev->csi_vdd, 1);
+		if (rc < 0) {
+			pr_err("%s: regulator on failed\n", __func__);
+			goto vreg_config_failed;
+		}
 
-	rc = msm_camera_enable_vreg(&csid_dev->pdev->dev, csid_vreg_info,
-		ARRAY_SIZE(csid_vreg_info), &csid_dev->csi_vdd, 1);
-	if (rc < 0) {
-		pr_err("%s: regulator enable failed\n", __func__);
-		goto vreg_enable_failed;
-	}
+		rc = msm_camera_enable_vreg(&csid_dev->pdev->dev,
+			csid_8960_vreg_info, ARRAY_SIZE(csid_8960_vreg_info),
+			NULL, 0, &csid_dev->csi_vdd, 1);
+		if (rc < 0) {
+			pr_err("%s: regulator enable failed\n", __func__);
+			goto vreg_enable_failed;
+		}
 
-	rc = msm_cam_clk_enable(&csid_dev->pdev->dev, csid_clk_info,
-		csid_dev->csid_clk, ARRAY_SIZE(csid_clk_info), 1);
-	if (rc < 0) {
-		pr_err("%s: regulator enable failed\n", __func__);
-		goto clk_enable_failed;
+		rc = msm_cam_clk_enable(&csid_dev->pdev->dev,
+			csid_8960_clk_info, csid_dev->csid_clk,
+			ARRAY_SIZE(csid_8960_clk_info), 1);
+		if (rc < 0) {
+			pr_err("%s: clock enable failed\n", __func__);
+			goto clk_enable_failed;
+		}
+	} else if (CSID_VERSION == CSID_VERSION_V3) {
+		rc = msm_camera_config_vreg(&csid_dev->pdev->dev,
+			csid_8974_vreg_info, ARRAY_SIZE(csid_8974_vreg_info),
+			NULL, 0, &csid_dev->csi_vdd, 1);
+		if (rc < 0) {
+			pr_err("%s: regulator on failed\n", __func__);
+			goto vreg_config_failed;
+		}
+
+		rc = msm_camera_enable_vreg(&csid_dev->pdev->dev,
+			csid_8974_vreg_info, ARRAY_SIZE(csid_8974_vreg_info),
+			NULL, 0, &csid_dev->csi_vdd, 1);
+		if (rc < 0) {
+			pr_err("%s: regulator enable failed\n", __func__);
+			goto vreg_enable_failed;
+		}
+
+		rc = msm_cam_clk_enable(&csid_dev->pdev->dev,
+			csid_8974_clk_info[0].clk_info, csid_dev->csid0_clk,
+			csid_8974_clk_info[0].num_clk_info, 1);
+		if (rc < 0) {
+			pr_err("%s: clock enable failed\n", __func__);
+			goto csid0_clk_enable_failed;
+		}
+		core_id = csid_dev->pdev->id;
+		if (core_id) {
+			rc = msm_cam_clk_enable(&csid_dev->pdev->dev,
+				csid_8974_clk_info[core_id].clk_info,
+				csid_dev->csid_clk,
+				csid_8974_clk_info[core_id].num_clk_info, 1);
+			if (rc < 0) {
+				pr_err("%s: clock enable failed\n",
+					__func__);
+				goto clk_enable_failed;
+			}
+		}
 	}
 
 	csid_dev->hw_version =
@@ -186,68 +316,178 @@
 
 	init_completion(&csid_dev->reset_complete);
 
-	rc = request_irq(csid_dev->irq->start, msm_csid_irq,
-		IRQF_TRIGGER_RISING, "csid", csid_dev);
+	enable_irq(csid_dev->irq->start);
 
 	msm_csid_reset(csid_dev);
+	csid_dev->csid_state = CSID_POWER_UP;
 	return rc;
 
 clk_enable_failed:
-	msm_camera_enable_vreg(&csid_dev->pdev->dev, csid_vreg_info,
-		ARRAY_SIZE(csid_vreg_info), &csid_dev->csi_vdd, 0);
+	if (CSID_VERSION == CSID_VERSION_V3) {
+		msm_cam_clk_enable(&csid_dev->pdev->dev,
+			csid_8974_clk_info[0].clk_info, csid_dev->csid0_clk,
+			csid_8974_clk_info[0].num_clk_info, 0);
+	}
+csid0_clk_enable_failed:
+	if (CSID_VERSION <= CSID_VERSION_V2) {
+		msm_camera_enable_vreg(&csid_dev->pdev->dev,
+			csid_8960_vreg_info, ARRAY_SIZE(csid_8960_vreg_info),
+			NULL, 0, &csid_dev->csi_vdd, 0);
+	} else if (CSID_VERSION == CSID_VERSION_V3) {
+		msm_camera_enable_vreg(&csid_dev->pdev->dev,
+			csid_8974_vreg_info, ARRAY_SIZE(csid_8974_vreg_info),
+			NULL, 0, &csid_dev->csi_vdd, 0);
+	}
 vreg_enable_failed:
-	msm_camera_config_vreg(&csid_dev->pdev->dev, csid_vreg_info,
-		ARRAY_SIZE(csid_vreg_info), &csid_dev->csi_vdd, 0);
+	if (CSID_VERSION <= CSID_VERSION_V2) {
+		msm_camera_config_vreg(&csid_dev->pdev->dev,
+			csid_8960_vreg_info, ARRAY_SIZE(csid_8960_vreg_info),
+			NULL, 0, &csid_dev->csi_vdd, 0);
+	} else if (CSID_VERSION == CSID_VERSION_V3) {
+		msm_camera_config_vreg(&csid_dev->pdev->dev,
+			csid_8974_vreg_info, ARRAY_SIZE(csid_8974_vreg_info),
+			NULL, 0, &csid_dev->csi_vdd, 0);
+	}
 vreg_config_failed:
 	iounmap(csid_dev->base);
 	csid_dev->base = NULL;
 	return rc;
 }
 
-static int msm_csid_release(struct v4l2_subdev *sd)
+static int msm_csid_release(struct csid_device *csid_dev)
 {
 	uint32_t irq;
-	struct csid_device *csid_dev;
-	csid_dev = v4l2_get_subdevdata(sd);
+	uint8_t core_id = 0;
+
+	if (csid_dev->csid_state != CSID_POWER_UP) {
+		pr_err("%s: csid invalid state %d\n", __func__,
+			csid_dev->csid_state);
+		return -EINVAL;
+	}
 
 	irq = msm_camera_io_r(csid_dev->base + CSID_IRQ_STATUS_ADDR);
 	msm_camera_io_w(irq, csid_dev->base + CSID_IRQ_CLEAR_CMD_ADDR);
 	msm_camera_io_w(0, csid_dev->base + CSID_IRQ_MASK_ADDR);
 
-	free_irq(csid_dev->irq->start, csid_dev);
+	disable_irq(csid_dev->irq->start);
 
-	msm_cam_clk_enable(&csid_dev->pdev->dev, csid_clk_info,
-		csid_dev->csid_clk, ARRAY_SIZE(csid_clk_info), 0);
+	if (csid_dev->hw_version <= CSID_VERSION_V2) {
+		msm_cam_clk_enable(&csid_dev->pdev->dev, csid_8960_clk_info,
+			csid_dev->csid_clk, ARRAY_SIZE(csid_8960_clk_info), 0);
 
-	msm_camera_enable_vreg(&csid_dev->pdev->dev, csid_vreg_info,
-		ARRAY_SIZE(csid_vreg_info), &csid_dev->csi_vdd, 0);
+		msm_camera_enable_vreg(&csid_dev->pdev->dev,
+			csid_8960_vreg_info, ARRAY_SIZE(csid_8960_vreg_info),
+			NULL, 0, &csid_dev->csi_vdd, 0);
 
-	msm_camera_config_vreg(&csid_dev->pdev->dev, csid_vreg_info,
-		ARRAY_SIZE(csid_vreg_info), &csid_dev->csi_vdd, 0);
+		msm_camera_config_vreg(&csid_dev->pdev->dev,
+			csid_8960_vreg_info, ARRAY_SIZE(csid_8960_vreg_info),
+			NULL, 0, &csid_dev->csi_vdd, 0);
+	} else if (csid_dev->hw_version == CSID_VERSION_V3) {
+		core_id = csid_dev->pdev->id;
+		if (core_id)
+			msm_cam_clk_enable(&csid_dev->pdev->dev,
+				csid_8974_clk_info[core_id].clk_info,
+				csid_dev->csid_clk,
+				csid_8974_clk_info[core_id].num_clk_info, 0);
+
+		msm_cam_clk_enable(&csid_dev->pdev->dev,
+			csid_8974_clk_info[0].clk_info, csid_dev->csid0_clk,
+			csid_8974_clk_info[0].num_clk_info, 0);
+
+		msm_camera_enable_vreg(&csid_dev->pdev->dev,
+			csid_8974_vreg_info, ARRAY_SIZE(csid_8974_vreg_info),
+			NULL, 0, &csid_dev->csi_vdd, 0);
+
+		msm_camera_config_vreg(&csid_dev->pdev->dev,
+			csid_8974_vreg_info, ARRAY_SIZE(csid_8974_vreg_info),
+			NULL, 0, &csid_dev->csi_vdd, 0);
+	}
 
 	iounmap(csid_dev->base);
 	csid_dev->base = NULL;
+	csid_dev->csid_state = CSID_POWER_DOWN;
 	return 0;
 }
 
+static long msm_csid_cmd(struct csid_device *csid_dev, void *arg)
+{
+	int rc = 0;
+	struct csid_cfg_data cdata;
+
+	if (!csid_dev) {
+		pr_err("%s:%d csid_dev NULL\n", __func__, __LINE__);
+		return -EINVAL;
+	}
+
+	if (copy_from_user(&cdata,
+		(void *)arg,
+		sizeof(struct csid_cfg_data))) {
+		pr_err("%s: %d failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+	CDBG("%s cfgtype = %d\n", __func__, cdata.cfgtype);
+	switch (cdata.cfgtype) {
+	case CSID_INIT:
+		rc = msm_csid_init(csid_dev, &cdata.cfg.csid_version);
+		if (copy_to_user((void *)arg,
+			&cdata,
+			sizeof(struct csid_cfg_data))) {
+			pr_err("%s: %d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+		}
+		break;
+	case CSID_CFG: {
+		struct msm_camera_csid_params csid_params;
+		struct msm_camera_csid_vc_cfg *vc_cfg = NULL;
+		if (copy_from_user(&csid_params,
+			(void *)cdata.cfg.csid_params,
+			sizeof(struct msm_camera_csid_params))) {
+			pr_err("%s: %d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+		vc_cfg = kzalloc(csid_params.lut_params.num_cid *
+			sizeof(struct msm_camera_csid_vc_cfg),
+			GFP_KERNEL);
+		if (!vc_cfg) {
+			pr_err("%s: %d failed\n", __func__, __LINE__);
+			rc = -ENOMEM;
+			break;
+		}
+		if (copy_from_user(vc_cfg,
+			(void *)csid_params.lut_params.vc_cfg,
+			(csid_params.lut_params.num_cid *
+			sizeof(struct msm_camera_csid_vc_cfg)))) {
+			pr_err("%s: %d failed\n", __func__, __LINE__);
+			kfree(vc_cfg);
+			rc = -EFAULT;
+			break;
+		}
+		csid_params.lut_params.vc_cfg = vc_cfg;
+		rc = msm_csid_config(csid_dev, &csid_params);
+		kfree(vc_cfg);
+		break;
+	}
+	default:
+		pr_err("%s: %d failed\n", __func__, __LINE__);
+		rc = -ENOIOCTLCMD;
+		break;
+	}
+	return rc;
+}
+
 static long msm_csid_subdev_ioctl(struct v4l2_subdev *sd,
 			unsigned int cmd, void *arg)
 {
 	int rc = -ENOIOCTLCMD;
-	struct csid_cfg_params cfg_params;
 	struct csid_device *csid_dev = v4l2_get_subdevdata(sd);
 	mutex_lock(&csid_dev->mutex);
 	switch (cmd) {
 	case VIDIOC_MSM_CSID_CFG:
-		cfg_params.subdev = sd;
-		cfg_params.parms = arg;
-		rc = msm_csid_config((struct csid_cfg_params *)&cfg_params);
-		break;
-	case VIDIOC_MSM_CSID_INIT:
-		rc = msm_csid_init(sd, (uint32_t *)arg);
+		rc = msm_csid_cmd(csid_dev, arg);
 		break;
 	case VIDIOC_MSM_CSID_RELEASE:
-		rc = msm_csid_release(sd);
+		rc = msm_csid_release(csid_dev);
 		break;
 	default:
 		pr_err("%s: command not found\n", __func__);
@@ -261,6 +501,7 @@
 static struct v4l2_subdev_core_ops msm_csid_subdev_core_ops = {
 	.g_chip_ident = &msm_csid_subdev_g_chip_ident,
 	.ioctl = &msm_csid_subdev_ioctl,
+	.interrupt_service_routine = msm_csid_irq_routine,
 };
 
 static const struct v4l2_subdev_ops msm_csid_subdev_ops = {
@@ -271,9 +512,10 @@
 {
 	struct csid_device *new_csid_dev;
 	struct msm_cam_subdev_info sd_info;
+	struct intr_table_entry irq_req;
 
 	int rc = 0;
-	CDBG("%s: device id = %d\n", __func__, pdev->id);
+	CDBG("%s:%d called\n", __func__, __LINE__);
 	new_csid_dev = kzalloc(sizeof(struct csid_device), GFP_KERNEL);
 	if (!new_csid_dev) {
 		pr_err("%s: no enough memory\n", __func__);
@@ -293,6 +535,7 @@
 		of_property_read_u32((&pdev->dev)->of_node,
 			"cell-index", &pdev->id);
 
+	CDBG("%s device id %d\n", __func__, pdev->id);
 	new_csid_dev->mem = platform_get_resource_byname(pdev,
 					IORESOURCE_MEM, "csid");
 	if (!new_csid_dev->mem) {
@@ -327,6 +570,45 @@
 	new_csid_dev->subdev.entity.name = pdev->name;
 	new_csid_dev->subdev.entity.revision =
 		new_csid_dev->subdev.devnode->num;
+
+	/* Request for this device irq from the camera server. If the
+	 * IRQ Router is present on this target, the interrupt will be
+	 * handled by the camera server and the interrupt service
+	 * routine called. If the request_irq call returns ENXIO, then
+	 * the IRQ Router hardware is not present on this target. We
+	 * have to request for the irq ourselves and register the
+	 * appropriate interrupt handler. */
+	irq_req.cam_hw_idx       = MSM_CAM_HW_CSI0 + pdev->id;
+	irq_req.dev_name         = "csid";
+	irq_req.irq_idx          = CAMERA_SS_IRQ_2 + pdev->id;
+	irq_req.irq_num          = new_csid_dev->irq->start;
+	irq_req.is_composite     = 0;
+	irq_req.irq_trigger_type = IRQF_TRIGGER_RISING;
+	irq_req.num_hwcore       = 1;
+	irq_req.subdev_list[0]   = &new_csid_dev->subdev;
+	irq_req.data             = (void *)new_csid_dev;
+	rc = msm_cam_server_request_irq(&irq_req);
+	if (rc == -ENXIO) {
+		/* IRQ Router hardware is not present on this hardware.
+		 * Request for the IRQ and register the interrupt handler. */
+		rc = request_irq(new_csid_dev->irq->start, msm_csid_irq,
+			IRQF_TRIGGER_RISING, "csid", new_csid_dev);
+		if (rc < 0) {
+			release_mem_region(new_csid_dev->mem->start,
+				resource_size(new_csid_dev->mem));
+			pr_err("%s: irq request fail\n", __func__);
+			rc = -EBUSY;
+			goto csid_no_resource;
+		}
+		disable_irq(new_csid_dev->irq->start);
+	} else if (rc < 0) {
+		release_mem_region(new_csid_dev->mem->start,
+			resource_size(new_csid_dev->mem));
+		pr_err("%s Error registering irq ", __func__);
+		goto csid_no_resource;
+	}
+
+	new_csid_dev->csid_state = CSID_POWER_DOWN;
 	return 0;
 
 csid_no_resource:
diff --git a/drivers/media/video/msm/csi/msm_csid.h b/drivers/media/video/msm/csi/msm_csid.h
index 2eae49c..46e8117 100644
--- a/drivers/media/video/msm/csi/msm_csid.h
+++ b/drivers/media/video/msm/csi/msm_csid.h
@@ -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
@@ -16,6 +16,12 @@
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <media/v4l2-subdev.h>
+#include <media/msm_camera.h>
+
+enum msm_csid_state_t {
+	CSID_POWER_UP,
+	CSID_POWER_DOWN,
+};
 
 struct csid_device {
 	struct platform_device *pdev;
@@ -28,23 +34,16 @@
 	struct mutex mutex;
 	struct completion reset_complete;
 	uint32_t hw_version;
+	enum msm_csid_state_t csid_state;
 
-	struct clk *csid_clk[5];
-};
-
-struct csid_cfg_params {
-	struct v4l2_subdev *subdev;
-	void *parms;
+	struct clk *csid0_clk[6];
+	struct clk *csid_clk[6];
 };
 
 #define VIDIOC_MSM_CSID_CFG \
-	_IOWR('V', BASE_VIDIOC_PRIVATE + 4, struct csid_cfg_params)
-
-#define VIDIOC_MSM_CSID_INIT \
-	_IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct v4l2_subdev*)
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 4, struct csic_cfg_data*)
 
 #define VIDIOC_MSM_CSID_RELEASE \
-	_IOWR('V', BASE_VIDIOC_PRIVATE + 6, struct v4l2_subdev*)
-
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct v4l2_subdev*)
 #endif
 
diff --git a/drivers/media/video/msm/csi/msm_csiphy.c b/drivers/media/video/msm/csi/msm_csiphy.c
index bec7ae3..065ba34 100644
--- a/drivers/media/video/msm/csi/msm_csiphy.c
+++ b/drivers/media/video/msm/csi/msm_csiphy.c
@@ -16,7 +16,6 @@
 #include <linux/of.h>
 #include <linux/module.h>
 #include <mach/board.h>
-#include <mach/camera.h>
 #include <mach/vreg.h>
 #include <media/msm_isp.h>
 #include "msm_csiphy.h"
@@ -27,31 +26,35 @@
 #define V4L2_IDENT_CSIPHY                        50003
 #define CSIPHY_VERSION_V3                        0x10
 
-int msm_csiphy_config(struct csiphy_cfg_params *cfg_params)
+int msm_csiphy_lane_config(struct csiphy_device *csiphy_dev,
+	struct msm_camera_csiphy_params *csiphy_params)
 {
 	int rc = 0;
 	int j = 0;
 	uint32_t val = 0;
 	uint8_t lane_cnt = 0;
 	uint16_t lane_mask = 0;
-	struct csiphy_device *csiphy_dev;
-	struct msm_camera_csiphy_params *csiphy_params;
 	void __iomem *csiphybase;
-	csiphy_dev = v4l2_get_subdevdata(cfg_params->subdev);
 	csiphybase = csiphy_dev->base;
-	if (csiphybase == NULL)
-		return -ENOMEM;
+	if (!csiphybase) {
+		pr_err("%s: csiphybase NULL\n", __func__);
+		return -EINVAL;
+	}
 
-	csiphy_params = cfg_params->parms;
 	csiphy_dev->lane_mask[csiphy_dev->pdev->id] |= csiphy_params->lane_mask;
 	lane_mask = csiphy_dev->lane_mask[csiphy_dev->pdev->id];
 	lane_cnt = csiphy_params->lane_cnt;
 	if (csiphy_params->lane_cnt < 1 || csiphy_params->lane_cnt > 4) {
-		CDBG("%s: unsupported lane cnt %d\n",
+		pr_err("%s: unsupported lane cnt %d\n",
 			__func__, csiphy_params->lane_cnt);
 		return rc;
 	}
 
+	CDBG("%s csiphy_params, mask = %x, cnt = %d, settle cnt = %x\n",
+		__func__,
+		csiphy_params->lane_mask,
+		csiphy_params->lane_cnt,
+		csiphy_params->settle_cnt);
 	msm_camera_io_w(0x1, csiphybase + MIPI_CSIPHY_GLBL_T_INIT_CFG0_ADDR);
 	msm_camera_io_w(0x1, csiphybase + MIPI_CSIPHY_T_WAKEUP_CFG0_ADDR);
 
@@ -75,6 +78,7 @@
 			csiphybase + MIPI_CSIPHY_GLBL_RESET_ADDR);
 	}
 
+	lane_mask &= 0x1f;
 	while (lane_mask & 0x1f) {
 		if (!(lane_mask & 0x1)) {
 			j++;
@@ -92,7 +96,7 @@
 		j++;
 		lane_mask >>= 1;
 	}
-
+	msleep(20);
 	return rc;
 }
 
@@ -102,18 +106,23 @@
 	int i;
 	struct csiphy_device *csiphy_dev = data;
 
-	for (i = 0; i < 5; i++) {
+	for (i = 0; i < 8; i++) {
 		irq = msm_camera_io_r(
 			csiphy_dev->base +
 			MIPI_CSIPHY_INTERRUPT_STATUS0_ADDR + 0x4*i);
 		msm_camera_io_w(irq,
 			csiphy_dev->base +
 			MIPI_CSIPHY_INTERRUPT_CLEAR0_ADDR + 0x4*i);
-		CDBG("%s MIPI_CSIPHY%d_INTERRUPT_STATUS%d = 0x%x\n",
+		pr_err("%s MIPI_CSIPHY%d_INTERRUPT_STATUS%d = 0x%x\n",
 			 __func__, csiphy_dev->pdev->id, i, irq);
+		msm_camera_io_w(0x1, csiphy_dev->base +
+			MIPI_CSIPHY_GLBL_IRQ_CMD_ADDR);
+		msm_camera_io_w(0x0, csiphy_dev->base +
+			MIPI_CSIPHY_GLBL_IRQ_CMD_ADDR);
+		msm_camera_io_w(0x0,
+			csiphy_dev->base +
+			MIPI_CSIPHY_INTERRUPT_CLEAR0_ADDR + 0x4*i);
 	}
-	msm_camera_io_w(0x1, csiphy_dev->base + 0x164);
-	msm_camera_io_w(0x0, csiphy_dev->base + 0x164);
 	return IRQ_HANDLED;
 }
 
@@ -133,21 +142,33 @@
 	return 0;
 }
 
-static struct msm_cam_clk_info csiphy_clk_info[] = {
+static struct msm_cam_clk_info csiphy_8960_clk_info[] = {
 	{"csiphy_timer_src_clk", 177780000},
 	{"csiphy_timer_clk", -1},
 };
 
-static int msm_csiphy_init(struct v4l2_subdev *sd)
+static struct msm_cam_clk_info csiphy_8974_clk_info[] = {
+	{"ispif_ahb_clk", -1},
+	{"csiphy_timer_src_clk", 200000000},
+	{"csiphy_timer_clk", -1},
+};
+
+static int msm_csiphy_init(struct csiphy_device *csiphy_dev)
 {
 	int rc = 0;
-	struct csiphy_device *csiphy_dev;
-	csiphy_dev = v4l2_get_subdevdata(sd);
 	if (csiphy_dev == NULL) {
+		pr_err("%s: csiphy_dev NULL\n", __func__);
 		rc = -ENOMEM;
 		return rc;
 	}
 
+	if (csiphy_dev->csiphy_state == CSIPHY_POWER_UP) {
+		pr_err("%s: csiphy invalid state %d\n", __func__,
+			csiphy_dev->csiphy_state);
+		rc = -EINVAL;
+		return rc;
+	}
+
 	if (csiphy_dev->ref_count++) {
 		CDBG("%s csiphy refcount = %d\n", __func__,
 			csiphy_dev->ref_count);
@@ -157,15 +178,23 @@
 	csiphy_dev->base = ioremap(csiphy_dev->mem->start,
 		resource_size(csiphy_dev->mem));
 	if (!csiphy_dev->base) {
+		pr_err("%s: csiphy_dev->base NULL\n", __func__);
 		csiphy_dev->ref_count--;
 		rc = -ENOMEM;
 		return rc;
 	}
 
-	rc = msm_cam_clk_enable(&csiphy_dev->pdev->dev, csiphy_clk_info,
-			csiphy_dev->csiphy_clk, ARRAY_SIZE(csiphy_clk_info), 1);
+	if (CSIPHY_VERSION != CSIPHY_VERSION_V3)
+		rc = msm_cam_clk_enable(&csiphy_dev->pdev->dev,
+			csiphy_8960_clk_info, csiphy_dev->csiphy_clk,
+			ARRAY_SIZE(csiphy_8960_clk_info), 1);
+	else
+		rc = msm_cam_clk_enable(&csiphy_dev->pdev->dev,
+			csiphy_8974_clk_info, csiphy_dev->csiphy_clk,
+			ARRAY_SIZE(csiphy_8974_clk_info), 1);
 
 	if (rc < 0) {
+		pr_err("%s: csiphy clk enable failed\n", __func__);
 		csiphy_dev->ref_count--;
 		iounmap(csiphy_dev->base);
 		csiphy_dev->base = NULL;
@@ -180,16 +209,15 @@
 	csiphy_dev->hw_version =
 		msm_camera_io_r(csiphy_dev->base + MIPI_CSIPHY_HW_VERSION_ADDR);
 
+	csiphy_dev->csiphy_state = CSIPHY_POWER_UP;
 	return 0;
 }
 
-static int msm_csiphy_release(struct v4l2_subdev *sd, void *arg)
+static int msm_csiphy_release(struct csiphy_device *csiphy_dev, void *arg)
 {
-	struct csiphy_device *csiphy_dev;
 	int i = 0;
 	struct msm_camera_csi_lane_params *csi_lane_params;
 	uint16_t csi_lane_mask;
-	csiphy_dev = v4l2_get_subdevdata(sd);
 	csi_lane_params = (struct msm_camera_csi_lane_params *)arg;
 	csi_lane_mask = csi_lane_params->csi_lane_mask;
 
@@ -198,6 +226,17 @@
 		return 0;
 	}
 
+	if (csiphy_dev->csiphy_state != CSIPHY_POWER_UP) {
+		pr_err("%s: csiphy invalid state %d\n", __func__,
+			csiphy_dev->csiphy_state);
+		return -EINVAL;
+	}
+
+	CDBG("%s csiphy_params, lane assign %x mask = %x\n",
+		__func__,
+		csi_lane_params->csi_lane_assign,
+		csi_lane_params->csi_lane_mask);
+
 	if (csiphy_dev->hw_version != CSIPHY_VERSION_V3) {
 		csiphy_dev->lane_mask[csiphy_dev->pdev->id] = 0;
 		for (i = 0; i < 4; i++)
@@ -229,33 +268,70 @@
 #if DBG_CSIPHY
 	disable_irq(csiphy_dev->irq->start);
 #endif
-	msm_cam_clk_enable(&csiphy_dev->pdev->dev, csiphy_clk_info,
-		csiphy_dev->csiphy_clk, ARRAY_SIZE(csiphy_clk_info), 0);
+	if (CSIPHY_VERSION != CSIPHY_VERSION_V3)
+		msm_cam_clk_enable(&csiphy_dev->pdev->dev,
+			csiphy_8960_clk_info, csiphy_dev->csiphy_clk,
+			ARRAY_SIZE(csiphy_8960_clk_info), 0);
+	else
+		msm_cam_clk_enable(&csiphy_dev->pdev->dev,
+			csiphy_8974_clk_info, csiphy_dev->csiphy_clk,
+			ARRAY_SIZE(csiphy_8974_clk_info), 0);
 
 	iounmap(csiphy_dev->base);
 	csiphy_dev->base = NULL;
+	csiphy_dev->csiphy_state = CSIPHY_POWER_DOWN;
 	return 0;
 }
 
+static long msm_csiphy_cmd(struct csiphy_device *csiphy_dev, void *arg)
+{
+	int rc = 0;
+	struct csiphy_cfg_data cdata;
+	struct msm_camera_csiphy_params csiphy_params;
+	if (!csiphy_dev) {
+		pr_err("%s: csiphy_dev NULL\n", __func__);
+		return -EINVAL;
+	}
+	if (copy_from_user(&cdata,
+		(void *)arg,
+		sizeof(struct csiphy_cfg_data))) {
+		pr_err("%s: %d failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+	switch (cdata.cfgtype) {
+	case CSIPHY_INIT:
+		rc = msm_csiphy_init(csiphy_dev);
+		break;
+	case CSIPHY_CFG:
+		if (copy_from_user(&csiphy_params,
+			(void *)cdata.csiphy_params,
+			sizeof(struct msm_camera_csiphy_params))) {
+			pr_err("%s: %d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+		rc = msm_csiphy_lane_config(csiphy_dev, &csiphy_params);
+		break;
+	default:
+		pr_err("%s: %d failed\n", __func__, __LINE__);
+		rc = -ENOIOCTLCMD;
+		break;
+	}
+	return rc;
+}
+
 static long msm_csiphy_subdev_ioctl(struct v4l2_subdev *sd,
 			unsigned int cmd, void *arg)
 {
 	int rc = -ENOIOCTLCMD;
-	struct csiphy_cfg_params cfg_params;
 	struct csiphy_device *csiphy_dev = v4l2_get_subdevdata(sd);
 	mutex_lock(&csiphy_dev->mutex);
 	switch (cmd) {
 	case VIDIOC_MSM_CSIPHY_CFG:
-		cfg_params.subdev = sd;
-		cfg_params.parms = arg;
-		rc = msm_csiphy_config(
-			(struct csiphy_cfg_params *)&cfg_params);
-		break;
-	case VIDIOC_MSM_CSIPHY_INIT:
-		rc = msm_csiphy_init(sd);
+		rc = msm_csiphy_cmd(csiphy_dev, arg);
 		break;
 	case VIDIOC_MSM_CSIPHY_RELEASE:
-		rc = msm_csiphy_release(sd, arg);
+		rc = msm_csiphy_release(csiphy_dev, arg);
 		break;
 	default:
 		pr_err("%s: command not found\n", __func__);
@@ -281,7 +357,6 @@
 	int rc = 0;
 	struct msm_cam_subdev_info sd_info;
 
-	CDBG("%s: device id = %d\n", __func__, pdev->id);
 	new_csiphy_dev = kzalloc(sizeof(struct csiphy_device), GFP_KERNEL);
 	if (!new_csiphy_dev) {
 		pr_err("%s: no enough memory\n", __func__);
@@ -301,6 +376,7 @@
 	if (pdev->dev.of_node)
 		of_property_read_u32((&pdev->dev)->of_node,
 			"cell-index", &pdev->id);
+	CDBG("%s: device id = %d\n", __func__, pdev->id);
 
 	new_csiphy_dev->mem = platform_get_resource_byname(pdev,
 					IORESOURCE_MEM, "csiphy");
@@ -348,6 +424,7 @@
 	new_csiphy_dev->subdev.entity.name = pdev->name;
 	new_csiphy_dev->subdev.entity.revision =
 		new_csiphy_dev->subdev.devnode->num;
+	new_csiphy_dev->csiphy_state = CSIPHY_POWER_DOWN;
 	return 0;
 
 csiphy_no_resource:
diff --git a/drivers/media/video/msm/csi/msm_csiphy.h b/drivers/media/video/msm/csi/msm_csiphy.h
index 1fab9c1..2fb21d2 100644
--- a/drivers/media/video/msm/csi/msm_csiphy.h
+++ b/drivers/media/video/msm/csi/msm_csiphy.h
@@ -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
@@ -16,9 +16,15 @@
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <media/v4l2-subdev.h>
+#include <media/msm_camera.h>
 
 #define MAX_CSIPHY 3
 
+enum msm_csiphy_state_t {
+	CSIPHY_POWER_UP,
+	CSIPHY_POWER_DOWN,
+};
+
 struct csiphy_device {
 	struct platform_device *pdev;
 	struct v4l2_subdev subdev;
@@ -28,24 +34,16 @@
 	void __iomem *base;
 	struct mutex mutex;
 	uint32_t hw_version;
+	enum msm_csiphy_state_t csiphy_state;
 
-	struct clk *csiphy_clk[2];
+	struct clk *csiphy_clk[3];
 	uint8_t ref_count;
 	uint16_t lane_mask[MAX_CSIPHY];
 };
 
-struct csiphy_cfg_params {
-	struct v4l2_subdev *subdev;
-	void *parms;
-};
-
 #define VIDIOC_MSM_CSIPHY_CFG \
-	_IOWR('V', BASE_VIDIOC_PRIVATE + 7, void *)
-
-#define VIDIOC_MSM_CSIPHY_INIT \
-	_IOWR('V', BASE_VIDIOC_PRIVATE + 8, struct v4l2_subdev*)
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 7, struct csiphy_cfg_data*)
 
 #define VIDIOC_MSM_CSIPHY_RELEASE \
 	_IOWR('V', BASE_VIDIOC_PRIVATE + 9, void *)
-
 #endif
diff --git a/drivers/media/video/msm/csi/msm_ispif.c b/drivers/media/video/msm/csi/msm_ispif.c
index 092ee90..62858a8 100644
--- a/drivers/media/video/msm/csi/msm_ispif.c
+++ b/drivers/media/video/msm/csi/msm_ispif.c
@@ -36,7 +36,6 @@
 {
 	int rc = 0;
 	uint32_t data = (0x1 << STROBED_RST_EN);
-	uint32_t data1 = (0x1 << STROBED_RST_EN);
 	uint16_t intfnum = 0, mask = intfmask;
 
 	while (mask != 0) {
@@ -47,49 +46,29 @@
 		}
 		switch (intfnum) {
 		case PIX0:
-			if (vfe_intf == VFE0)
-				data |= (0x1 << PIX_0_VFE_RST_STB) |
-					(0x1 << PIX_0_CSID_RST_STB);
-			else
-				data1 |= (0x1 << PIX_0_VFE_RST_STB) |
-					(0x1 << PIX_0_CSID_RST_STB);
+			data |= (0x1 << PIX_0_VFE_RST_STB) |
+				(0x1 << PIX_0_CSID_RST_STB);
 			ispif->pix_sof_count = 0;
 			break;
 
 		case RDI0:
-			if (vfe_intf == VFE0)
-				data |= (0x1 << RDI_0_VFE_RST_STB) |
-					(0x1 << RDI_0_CSID_RST_STB);
-			else
-				data1 |= (0x1 << RDI_0_VFE_RST_STB) |
-					(0x1 << RDI_0_CSID_RST_STB);
+			data |= (0x1 << RDI_0_VFE_RST_STB) |
+				(0x1 << RDI_0_CSID_RST_STB);
 			break;
 
 		case PIX1:
-			if (vfe_intf == VFE0)
-				data |= (0x1 << PIX_1_VFE_RST_STB) |
-					(0x1 << PIX_1_CSID_RST_STB);
-			else
-				data1 |= (0x1 << PIX_1_VFE_RST_STB) |
-					(0x1 << PIX_1_CSID_RST_STB);
+			data |= (0x1 << PIX_1_VFE_RST_STB) |
+				(0x1 << PIX_1_CSID_RST_STB);
 			break;
 
 		case RDI1:
-			if (vfe_intf == VFE0)
-				data |= (0x1 << RDI_1_VFE_RST_STB) |
-					(0x1 << RDI_1_CSID_RST_STB);
-			else
-				data1 |= (0x1 << RDI_1_VFE_RST_STB) |
-					(0x1 << RDI_1_CSID_RST_STB);
+			data |= (0x1 << RDI_1_VFE_RST_STB) |
+				(0x1 << RDI_1_CSID_RST_STB);
 			break;
 
 		case RDI2:
-			if (vfe_intf == VFE0)
-				data |= (0x1 << RDI_2_VFE_RST_STB) |
-					(0x1 << RDI_2_CSID_RST_STB);
-			else
-				data1 |= (0x1 << RDI_2_VFE_RST_STB) |
-					(0x1 << RDI_2_CSID_RST_STB);
+			data |= (0x1 << RDI_2_VFE_RST_STB) |
+				(0x1 << RDI_2_CSID_RST_STB);
 			break;
 
 		default:
@@ -99,43 +78,26 @@
 		mask >>= 1;
 		intfnum++;
 	}	/*end while */
-	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 && data1 > 0x1) {
-		msm_camera_io_w(data1,
-			ispif->base + ISPIF_RST_CMD_1_ADDR);
-		rc = wait_for_completion_interruptible(&ispif->
-			reset_complete);
+	if (data > 0x1) {
+		if (vfe_intf == VFE0)
+			msm_camera_io_w(data, ispif->base + ISPIF_RST_CMD_ADDR);
+		else
+			msm_camera_io_w(data, ispif->base +
+				ISPIF_RST_CMD_1_ADDR);
+		rc = wait_for_completion_interruptible(&ispif->reset_complete);
 	}
-
 	return rc;
 }
 
 static int msm_ispif_reset(struct ispif_device *ispif)
 {
 	int rc = 0;
-	uint32_t data = (0x1 << STROBED_RST_EN) |
-		(0x1 << SW_REG_RST_STB) |
-		(0x1 << MISC_LOGIC_RST_STB) |
-		(0x1 << PIX_0_VFE_RST_STB) |
-		(0x1 << PIX_0_CSID_RST_STB) |
-		(0x1 << RDI_0_VFE_RST_STB) |
-		(0x1 << RDI_0_CSID_RST_STB) |
-		(0x1 << RDI_1_VFE_RST_STB) |
-		(0x1 << RDI_1_CSID_RST_STB);
-
-	if (ispif->csid_version >= CSID_VERSION_V2)
-		data |= (0x1 << PIX_1_VFE_RST_STB) |
-			(0x1 << PIX_1_CSID_RST_STB) |
-			(0x1 << RDI_2_VFE_RST_STB) |
-			(0x1 << RDI_2_CSID_RST_STB);
 	ispif->pix_sof_count = 0;
-	msm_camera_io_w(data, ispif->base + ISPIF_RST_CMD_ADDR);
+	msm_camera_io_w(ISPIF_RST_CMD_MASK, ispif->base + ISPIF_RST_CMD_ADDR);
+	if (ispif->csid_version == CSID_VERSION_V3)
+		msm_camera_io_w(ISPIF_RST_CMD_1_MASK, ispif->base +
+				ISPIF_RST_CMD_1_ADDR);
 	rc = wait_for_completion_interruptible(&ispif->reset_complete);
-	if (ispif->csid_version >= CSID_VERSION_V3) {
-		msm_camera_io_w(data, ispif->base + ISPIF_RST_CMD_1_ADDR);
-		rc = wait_for_completion_interruptible(&ispif->reset_complete);
-	}
 	return rc;
 }
 
@@ -152,48 +114,55 @@
 	uint8_t intftype, uint8_t csid, uint8_t vfe_intf)
 {
 	int rc = 0;
-	uint32_t data;
+	uint32_t data = 0;
 
-	if (ispif->ispif_clk[intftype] == NULL) {
-		pr_err("%s: ispif NULL clk\n", __func__);
-		return;
+	if (ispif->csid_version <= CSID_VERSION_V2) {
+		if (ispif->ispif_clk[intftype] == NULL) {
+			pr_err("%s: ispif NULL clk\n", __func__);
+			return;
+		}
+		rc = clk_set_rate(ispif->ispif_clk[intftype], csid);
+		if (rc < 0)
+			pr_err("%s: clk_set_rate failed %d\n", __func__, rc);
 	}
-
-	rc = clk_set_rate(ispif->ispif_clk[intftype], csid);
-	if (rc < 0)
-		pr_err("%s: clk_set_rate failed %d\n", __func__, rc);
-
 	data = msm_camera_io_r(ispif->base + ISPIF_INPUT_SEL_ADDR +
 		(0x200 * vfe_intf));
 	switch (intftype) {
 	case PIX0:
+		data &= ~(0x3);
 		data |= csid;
 		break;
 
 	case RDI0:
+		data &= ~(0x3 << 4);
 		data |= (csid << 4);
 		break;
 
 	case PIX1:
+		data &= ~(0x3 << 8);
 		data |= (csid << 8);
 		break;
 
 	case RDI1:
+		data &= ~(0x3 << 12);
 		data |= (csid << 12);
 		break;
 
 	case RDI2:
+		data &= ~(0x3 << 20);
 		data |= (csid << 20);
 		break;
 	}
-	msm_camera_io_w(data, ispif->base + ISPIF_INPUT_SEL_ADDR +
-		(0x200 * vfe_intf));
+	if (data) {
+		msm_camera_io_w(data, ispif->base + ISPIF_INPUT_SEL_ADDR +
+			(0x200 * vfe_intf));
+	}
 }
 
 static void msm_ispif_enable_intf_cids(struct ispif_device *ispif,
 	uint8_t intftype, uint16_t cid_mask, uint8_t vfe_intf)
 {
-	uint32_t data;
+	uint32_t data = 0;
 	mutex_lock(&ispif->mutex);
 	switch (intftype) {
 	case PIX0:
@@ -243,7 +212,7 @@
 	uint8_t intftype, uint8_t vfe_intf)
 {
 	int32_t rc = 0;
-	uint32_t data;
+	uint32_t data = 0;
 	mutex_lock(&ispif->mutex);
 	switch (intftype) {
 	case PIX0:
@@ -289,11 +258,13 @@
 	ispif_params = params_list->params;
 	CDBG("Enable interface\n");
 	msm_camera_io_w(0x00000000, ispif->base + ISPIF_IRQ_MASK_ADDR);
+	msm_camera_io_w(0x00000000, ispif->base + ISPIF_IRQ_MASK_1_ADDR);
+	msm_camera_io_w(0x00000000, ispif->base + ISPIF_IRQ_MASK_2_ADDR);
 	for (i = 0; i < params_len; i++) {
 		intftype = ispif_params[i].intftype;
 		vfe_intf = ispif_params[i].vfe_intf;
-		CDBG("%s intftype %x, vfe_intf %d\n", __func__, intftype,
-			vfe_intf);
+		CDBG("%s intftype %x, vfe_intf %d, csid %d\n", __func__,
+			intftype, vfe_intf, ispif_params[i].csid);
 		if ((intftype >= INTF_MAX) ||
 			(ispif->csid_version <= CSID_VERSION_V2 &&
 			vfe_intf > VFE0) ||
@@ -319,6 +290,14 @@
 					ISPIF_IRQ_MASK_ADDR);
 	msm_camera_io_w(ISPIF_IRQ_STATUS_MASK, ispif->base +
 					ISPIF_IRQ_CLEAR_ADDR);
+	msm_camera_io_w(ISPIF_IRQ_STATUS_1_MASK, ispif->base +
+					ISPIF_IRQ_MASK_1_ADDR);
+	msm_camera_io_w(ISPIF_IRQ_STATUS_1_MASK, ispif->base +
+					ISPIF_IRQ_CLEAR_1_ADDR);
+	msm_camera_io_w(ISPIF_IRQ_STATUS_2_MASK, ispif->base +
+					ISPIF_IRQ_MASK_2_ADDR);
+	msm_camera_io_w(ISPIF_IRQ_STATUS_2_MASK, ispif->base +
+					ISPIF_IRQ_CLEAR_2_ADDR);
 	msm_camera_io_w(ISPIF_IRQ_GLOBAL_CLEAR_CMD, ispif->base +
 		 ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR);
 	return rc;
@@ -363,10 +342,9 @@
 static void msm_ispif_intf_cmd(struct ispif_device *ispif, uint16_t intfmask,
 	uint8_t intf_cmd_mask, uint8_t vfe_intf)
 {
-	uint8_t vc = 0;
+	uint8_t vc = 0, val = 0;
 	uint16_t mask = intfmask, intfnum = 0;
 	uint32_t cid_mask = 0;
-	uint32_t global_intf_cmd_mask = 0xFFFFFFFF;
 	uint32_t global_intf_cmd_mask1 = 0xFFFFFFFF;
 	while (mask != 0) {
 		if (!(intfmask & (0x1 << intfnum))) {
@@ -380,12 +358,15 @@
 
 		while (cid_mask != 0) {
 			if ((cid_mask & 0xf) != 0x0) {
-				if (intfnum != RDI2)
-					global_intf_cmd_mask &=
-						~((0x3 & ~intf_cmd_mask)
-						<< ((vc * 2) +
+				if (intfnum != RDI2) {
+					val = (intf_cmd_mask>>(vc*2)) & 0x3;
+					ispif->global_intf_cmd_mask |=
+						(0x3 << ((vc * 2) +
 						(intfnum * 8)));
-				else
+					ispif->global_intf_cmd_mask &=
+						~((0x3 & ~val) << ((vc * 2) +
+						(intfnum * 8)));
+				} else
 					global_intf_cmd_mask1 &=
 						~((0x3 & ~intf_cmd_mask)
 						<< ((vc * 2) + 8));
@@ -396,7 +377,7 @@
 		mask >>= 1;
 		intfnum++;
 	}
-	msm_camera_io_w(global_intf_cmd_mask,
+	msm_camera_io_w(ispif->global_intf_cmd_mask,
 		ispif->base + ISPIF_INTF_CMD_ADDR + (0x200 * vfe_intf));
 	if (global_intf_cmd_mask1 != 0xFFFFFFFF)
 		msm_camera_io_w(global_intf_cmd_mask1,
@@ -408,11 +389,20 @@
 	uint16_t intfmask, uint8_t vfe_intf)
 {
 	int rc = 0;
-	uint8_t intf_cmd_mask = 0x02;
+	uint8_t intf_cmd_mask = 0xAA;
+	uint16_t intfnum = 0, mask = intfmask;
 	mutex_lock(&ispif->mutex);
 	CDBG("%s intfmask %x intf_cmd_mask %x\n", __func__, intfmask,
 		intf_cmd_mask);
 	msm_ispif_intf_cmd(ispif, intfmask, intf_cmd_mask, vfe_intf);
+	while (mask != 0) {
+		if (intfmask & (0x1 << intfnum))
+			ispif->global_intf_cmd_mask |= (0xFF << (intfnum * 8));
+		mask >>= 1;
+		intfnum++;
+		if (intfnum == RDI2)
+			break;
+	}
 	mutex_unlock(&ispif->mutex);
 	return rc;
 }
@@ -420,11 +410,11 @@
 static int msm_ispif_start_intf_transfer(struct ispif_device *ispif,
 	uint16_t intfmask, uint8_t vfe_intf)
 {
-	uint8_t intf_cmd_mask = 0x01;
+	uint8_t intf_cmd_mask = 0x55;
 	int rc = 0;
 	mutex_lock(&ispif->mutex);
 	rc = msm_ispif_intf_reset(ispif, intfmask, vfe_intf);
-	CDBG("%s intfmask %x intf_cmd_mask %x\n", __func__, intfmask,
+	CDBG("%s intfmask start after%x intf_cmd_mask %x\n", __func__, intfmask,
 		intf_cmd_mask);
 	msm_ispif_intf_cmd(ispif, intfmask, intf_cmd_mask, vfe_intf);
 	mutex_unlock(&ispif->mutex);
@@ -492,6 +482,9 @@
 			default:
 				break;
 			}
+			if (intfnum != RDI2)
+				ispif->global_intf_cmd_mask |= (0xFF <<
+					(intfnum * 8));
 		}
 		mask >>= 1;
 		intfnum++;
@@ -534,13 +527,24 @@
 	return rc;
 }
 
+static void send_rdi_sof(struct ispif_device *ispif,
+	enum msm_ispif_intftype interface, int count)
+{
+	struct rdi_count_msg sof_msg;
+	sof_msg.rdi_interface = interface;
+	sof_msg.count = count;
+	v4l2_subdev_notify(&ispif->subdev, NOTIFY_AXI_RDI_SOF_COUNT,
+					   (void *)&sof_msg);
+}
+
 static void ispif_do_tasklet(unsigned long data)
 {
 	unsigned long flags;
 
 	struct ispif_isr_queue_cmd *qcmd = NULL;
-	CDBG("=== ispif_do_tasklet start ===\n");
+	struct ispif_device *ispif;
 
+	ispif = (struct ispif_device *)data;
 	while (atomic_read(&ispif_irq_cnt)) {
 		spin_lock_irqsave(&ispif_tasklet_lock, flags);
 		qcmd = list_first_entry(&ispif_tasklet_q,
@@ -555,28 +559,17 @@
 		list_del(&qcmd->list);
 		spin_unlock_irqrestore(&ispif_tasklet_lock,
 			flags);
-		if (qcmd->ispifInterruptStatus0 &
-			ISPIF_IRQ_STATUS_RDI_SOF_MASK) {
-			CDBG("ispif rdi irq status\n");
-		}
-		if (qcmd->ispifInterruptStatus1 &
-			ISPIF_IRQ_STATUS_RDI_SOF_MASK) {
-			CDBG("ispif rdi1 irq status\n");
-		}
+
 		kfree(qcmd);
 	}
-	CDBG("=== ispif_do_tasklet end ===\n");
 }
 
-DECLARE_TASKLET(ispif_tasklet, ispif_do_tasklet, 0);
-
 static void ispif_process_irq(struct ispif_device *ispif,
 	struct ispif_irq_status *out)
 {
 	unsigned long flags;
 	struct ispif_isr_queue_cmd *qcmd;
 
-	CDBG("ispif_process_irq\n");
 	qcmd = kzalloc(sizeof(struct ispif_isr_queue_cmd),
 		GFP_ATOMIC);
 	if (!qcmd) {
@@ -585,12 +578,34 @@
 	}
 	qcmd->ispifInterruptStatus0 = out->ispifIrqStatus0;
 	qcmd->ispifInterruptStatus1 = out->ispifIrqStatus1;
+	qcmd->ispifInterruptStatus2 = out->ispifIrqStatus2;
 
-	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);
+	if (qcmd->ispifInterruptStatus0 &
+			ISPIF_IRQ_STATUS_PIX_SOF_MASK) {
+			CDBG("%s: ispif PIX irq status", __func__);
+			ispif->pix_sof_count++;
+			v4l2_subdev_notify(&ispif->subdev,
+				NOTIFY_VFE_PIX_SOF_COUNT,
+				(void *)&ispif->pix_sof_count);
+	}
+
+	if (qcmd->ispifInterruptStatus0 &
+			ISPIF_IRQ_STATUS_RDI0_SOF_MASK) {
+			CDBG("%s: ispif RDI0 irq status", __func__);
+			ispif->rdi0_sof_count++;
+			send_rdi_sof(ispif, RDI_0, ispif->rdi0_sof_count);
+	}
+	if (qcmd->ispifInterruptStatus1 &
+		ISPIF_IRQ_STATUS_RDI1_SOF_MASK) {
+		CDBG("%s: ispif RDI1 irq status", __func__);
+		ispif->rdi1_sof_count++;
+		send_rdi_sof(ispif, RDI_1, ispif->rdi1_sof_count);
+	}
+	if (qcmd->ispifInterruptStatus2 &
+		ISPIF_IRQ_STATUS_RDI2_SOF_MASK) {
+		CDBG("%s: ispif RDI2 irq status", __func__);
+		ispif->rdi2_sof_count++;
+		send_rdi_sof(ispif, RDI_2, ispif->rdi2_sof_count);
 	}
 
 	spin_lock_irqsave(&ispif_tasklet_lock, flags);
@@ -598,25 +613,31 @@
 
 	atomic_add(1, &ispif_irq_cnt);
 	spin_unlock_irqrestore(&ispif_tasklet_lock, flags);
-	tasklet_schedule(&ispif_tasklet);
+	tasklet_schedule(&ispif->ispif_tasklet);
 	return;
 }
 
 static inline void msm_ispif_read_irq_status(struct ispif_irq_status *out,
 	void *data)
 {
+	uint32_t status0 = 0, status1 = 0, status2 = 0;
 	struct ispif_device *ispif = (struct ispif_device *)data;
 	out->ispifIrqStatus0 = msm_camera_io_r(ispif->base +
 		ISPIF_IRQ_STATUS_ADDR);
 	out->ispifIrqStatus1 = msm_camera_io_r(ispif->base +
 		ISPIF_IRQ_STATUS_1_ADDR);
+	out->ispifIrqStatus2 = msm_camera_io_r(ispif->base +
+		ISPIF_IRQ_STATUS_2_ADDR);
 	msm_camera_io_w(out->ispifIrqStatus0,
 		ispif->base + ISPIF_IRQ_CLEAR_ADDR);
 	msm_camera_io_w(out->ispifIrqStatus1,
 		ispif->base + ISPIF_IRQ_CLEAR_1_ADDR);
+	msm_camera_io_w(out->ispifIrqStatus2,
+		ispif->base + ISPIF_IRQ_CLEAR_2_ADDR);
 
-	CDBG("%s: irq ispif->irq: Irq_status0 = 0x%x\n", __func__,
-		out->ispifIrqStatus0);
+	CDBG("%s: irq vfe0 Irq_status0 = 0x%x, 1 = 0x%x, 2 = 0x%x\n",
+		__func__, out->ispifIrqStatus0, out->ispifIrqStatus1,
+		out->ispifIrqStatus2);
 	if (out->ispifIrqStatus0 & ISPIF_IRQ_STATUS_MASK) {
 		if (out->ispifIrqStatus0 & (0x1 << RESET_DONE_IRQ))
 			complete(&ispif->reset_complete);
@@ -624,11 +645,30 @@
 			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->ispifIrqStatus1 & (0x1 << RAW_INTF_1_OVERFLOW_IRQ))
+			pr_err("%s: rdi intf 1 overflow.\n", __func__);
+		if (out->ispifIrqStatus2 & (0x1 << RAW_INTF_2_OVERFLOW_IRQ))
+			pr_err("%s: rdi intf 2 overflow.\n", __func__);
 		if ((out->ispifIrqStatus0 & ISPIF_IRQ_STATUS_SOF_MASK) ||
-			(out->ispifIrqStatus1 &
-				ISPIF_IRQ_STATUS_SOF_MASK)) {
+			(out->ispifIrqStatus1 &	ISPIF_IRQ_STATUS_SOF_MASK) ||
+			(out->ispifIrqStatus2 & ISPIF_IRQ_STATUS_RDI2_SOF_MASK))
 			ispif_process_irq(ispif, out);
-		}
+	}
+	if (ispif->csid_version == CSID_VERSION_V3) {
+		status0 = msm_camera_io_r(ispif->base +
+			ISPIF_IRQ_STATUS_ADDR + 0x200);
+		msm_camera_io_w(status0,
+			ispif->base + ISPIF_IRQ_CLEAR_ADDR + 0x200);
+		status1 = msm_camera_io_r(ispif->base +
+			ISPIF_IRQ_STATUS_1_ADDR + 0x200);
+		msm_camera_io_w(status1,
+			ispif->base + ISPIF_IRQ_CLEAR_1_ADDR + 0x200);
+		status2 = msm_camera_io_r(ispif->base +
+			ISPIF_IRQ_STATUS_2_ADDR + 0x200);
+		msm_camera_io_w(status2,
+			ispif->base + ISPIF_IRQ_CLEAR_2_ADDR + 0x200);
+		CDBG("%s: irq vfe1 Irq_status0 = 0x%x, 1 = 0x%x, 2 = 0x%x\n",
+			__func__, status0, status1, status2);
 	}
 	msm_camera_io_w(ISPIF_IRQ_GLOBAL_CLEAR_CMD, ispif->base +
 		ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR);
@@ -641,7 +681,7 @@
 	return IRQ_HANDLED;
 }
 
-static struct msm_cam_clk_info ispif_clk_info[] = {
+static struct msm_cam_clk_info ispif_8960_clk_info[] = {
 	{"csi_pix_clk", 0},
 	{"csi_rdi_clk", 0},
 	{"csi_pix1_clk", 0},
@@ -654,40 +694,61 @@
 {
 	int rc = 0;
 	CDBG("%s called %d\n", __func__, __LINE__);
+
+	if (ispif->ispif_state == ISPIF_POWER_UP) {
+		pr_err("%s: ispif invalid state %d\n", __func__,
+			ispif->ispif_state);
+		rc = -EINVAL;
+		return rc;
+	}
+
 	spin_lock_init(&ispif_tasklet_lock);
 	INIT_LIST_HEAD(&ispif_tasklet_q);
 	rc = request_irq(ispif->irq->start, msm_io_ispif_irq,
 		IRQF_TRIGGER_RISING, "ispif", ispif);
+	ispif->global_intf_cmd_mask = 0xFFFFFFFF;
 	init_completion(&ispif->reset_complete);
 
+	tasklet_init(&ispif->ispif_tasklet,
+		ispif_do_tasklet, (unsigned long)ispif);
+
 	ispif->csid_version = *csid_version;
-	if (ispif->csid_version >= CSID_VERSION_V2) {
-		rc = msm_cam_clk_enable(&ispif->pdev->dev, ispif_clk_info,
-			ispif->ispif_clk, ARRAY_SIZE(ispif_clk_info), 1);
+	if (ispif->csid_version < CSID_VERSION_V2) {
+		rc = msm_cam_clk_enable(&ispif->pdev->dev, ispif_8960_clk_info,
+			ispif->ispif_clk, 2, 1);
 		if (rc < 0)
 			return rc;
-	} else {
-		rc = msm_cam_clk_enable(&ispif->pdev->dev, ispif_clk_info,
-			ispif->ispif_clk, 2, 1);
+	} else if (ispif->csid_version == CSID_VERSION_V2) {
+		rc = msm_cam_clk_enable(&ispif->pdev->dev, ispif_8960_clk_info,
+			ispif->ispif_clk, ARRAY_SIZE(ispif_8960_clk_info), 1);
 		if (rc < 0)
 			return rc;
 	}
 	rc = msm_ispif_reset(ispif);
+	ispif->ispif_state = ISPIF_POWER_UP;
 	return rc;
 }
 
 static void msm_ispif_release(struct ispif_device *ispif)
 {
-	CDBG("%s, free_irq\n", __func__);
-	free_irq(ispif->irq->start, 0);
-	tasklet_kill(&ispif_tasklet);
+	if (ispif->ispif_state != ISPIF_POWER_UP) {
+		pr_err("%s: ispif invalid state %d\n", __func__,
+			ispif->ispif_state);
+		return;
+	}
 
-	if (ispif->csid_version == CSID_VERSION_V2)
-		msm_cam_clk_enable(&ispif->pdev->dev, ispif_clk_info,
-			ispif->ispif_clk, ARRAY_SIZE(ispif_clk_info), 0);
-	else
-		msm_cam_clk_enable(&ispif->pdev->dev, ispif_clk_info,
+	CDBG("%s, free_irq\n", __func__);
+	free_irq(ispif->irq->start, ispif);
+	tasklet_kill(&ispif->ispif_tasklet);
+
+	if (ispif->csid_version < CSID_VERSION_V2) {
+		msm_cam_clk_enable(&ispif->pdev->dev, ispif_8960_clk_info,
 			ispif->ispif_clk, 2, 0);
+	} else if (ispif->csid_version == CSID_VERSION_V2) {
+		msm_cam_clk_enable(&ispif->pdev->dev, ispif_8960_clk_info,
+			ispif->ispif_clk, ARRAY_SIZE(ispif_8960_clk_info), 0);
+	}
+	ispif->ispif_state = ISPIF_POWER_DOWN;
 }
 
 static long msm_ispif_cmd(struct v4l2_subdev *sd, void *arg)
@@ -824,6 +885,7 @@
 	ispif->subdev.entity.group_id = ISPIF_DEV;
 	ispif->subdev.entity.name = pdev->name;
 	ispif->subdev.entity.revision = ispif->subdev.devnode->num;
+	ispif->ispif_state = ISPIF_POWER_DOWN;
 	return 0;
 
 ispif_no_mem:
diff --git a/drivers/media/video/msm/csi/msm_ispif.h b/drivers/media/video/msm/csi/msm_ispif.h
index f4ad661..d4ca864 100644
--- a/drivers/media/video/msm/csi/msm_ispif.h
+++ b/drivers/media/video/msm/csi/msm_ispif.h
@@ -20,6 +20,12 @@
 struct ispif_irq_status {
 	uint32_t ispifIrqStatus0;
 	uint32_t ispifIrqStatus1;
+	uint32_t ispifIrqStatus2;
+};
+
+enum msm_ispif_state_t {
+	ISPIF_POWER_UP,
+	ISPIF_POWER_DOWN,
 };
 
 struct ispif_device {
@@ -35,12 +41,19 @@
 	uint32_t csid_version;
 	struct clk *ispif_clk[5];
 	uint32_t pix_sof_count;
+	uint32_t rdi0_sof_count;
+	uint32_t rdi1_sof_count;
+	uint32_t rdi2_sof_count;
+	uint32_t global_intf_cmd_mask;
+	struct tasklet_struct ispif_tasklet;
+	enum msm_ispif_state_t ispif_state;
 };
 
 struct ispif_isr_queue_cmd {
 	struct list_head list;
 	uint32_t    ispifInterruptStatus0;
 	uint32_t    ispifInterruptStatus1;
+	uint32_t    ispifInterruptStatus2;
 };
 
 #define VIDIOC_MSM_ISPIF_CFG \
diff --git a/drivers/media/video/msm/eeprom/imx074_eeprom.c b/drivers/media/video/msm/eeprom/imx074_eeprom.c
index 21cbafa..a99b17e 100644
--- a/drivers/media/video/msm/eeprom/imx074_eeprom.c
+++ b/drivers/media/video/msm/eeprom/imx074_eeprom.c
@@ -47,14 +47,15 @@
 	.core = &imx074_eeprom_subdev_core_ops,
 };
 
-uint8_t imx074_wbcalib_data[6];
-struct msm_calib_wb imx074_wb_data;
+static uint8_t imx074_wbcalib_data[6];
+static struct msm_calib_wb imx074_wb_data;
 
 static struct msm_camera_eeprom_info_t imx074_calib_supp_info = {
 	{FALSE, 0, 0, 1},
 	{TRUE, 6, 0, 1024},
 	{FALSE, 0, 0, 1},
 	{FALSE, 0, 0, 1},
+	{FALSE, 0, 0, 1},
 };
 
 static struct msm_camera_eeprom_read_t imx074_eeprom_read_tbl[] = {
diff --git a/drivers/media/video/msm/eeprom/imx091_eeprom.c b/drivers/media/video/msm/eeprom/imx091_eeprom.c
index 68a2361..c53eb20 100644
--- a/drivers/media/video/msm/eeprom/imx091_eeprom.c
+++ b/drivers/media/video/msm/eeprom/imx091_eeprom.c
@@ -47,16 +47,17 @@
 	.core = &imx091_eeprom_subdev_core_ops,
 };
 
-uint8_t imx091_wbcalib_data[6];
-uint8_t imx091_afcalib_data[6];
-struct msm_calib_wb imx091_wb_data;
-struct msm_calib_af imx091_af_data;
+static uint8_t imx091_wbcalib_data[6];
+static uint8_t imx091_afcalib_data[6];
+static struct msm_calib_wb imx091_wb_data;
+static struct msm_calib_af imx091_af_data;
 
 static struct msm_camera_eeprom_info_t imx091_calib_supp_info = {
 	{TRUE, 6, 1, 1},
 	{TRUE, 6, 0, 32768},
 	{FALSE, 0, 0, 1},
 	{FALSE, 0, 0, 1},
+	{FALSE, 0, 0, 1},
 };
 
 static struct msm_camera_eeprom_read_t imx091_eeprom_read_tbl[] = {
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_camera_i2c.c b/drivers/media/video/msm/io/msm_camera_i2c.c
index 82bca02..27ebac5 100644
--- a/drivers/media/video/msm/io/msm_camera_i2c.c
+++ b/drivers/media/video/msm/io/msm_camera_i2c.c
@@ -84,6 +84,7 @@
 		cci_ctrl.cci_info = client->cci_client;
 		cci_ctrl.cfg.cci_i2c_write_cfg.reg_conf_tbl = &reg_conf_tbl;
 		cci_ctrl.cfg.cci_i2c_write_cfg.data_type = data_type;
+		cci_ctrl.cfg.cci_i2c_write_cfg.addr_type = client->addr_type;
 		cci_ctrl.cfg.cci_i2c_write_cfg.size = 1;
 		rc = v4l2_subdev_call(client->cci_client->cci_subdev,
 				core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl);
@@ -336,6 +337,39 @@
 	return rc;
 }
 
+int32_t msm_camera_i2c_write_bayer_table(
+	struct msm_camera_i2c_client *client,
+	struct msm_camera_i2c_reg_setting *write_setting)
+{
+	int i;
+	int32_t rc = -EFAULT;
+	struct msm_camera_i2c_reg_array *reg_setting;
+
+	if (!client || !write_setting)
+		return rc;
+
+	reg_setting = write_setting->reg_setting;
+	client->addr_type = write_setting->addr_type;
+	if ((write_setting->addr_type != MSM_CAMERA_I2C_BYTE_ADDR
+		&& write_setting->addr_type != MSM_CAMERA_I2C_WORD_ADDR)
+		|| (write_setting->data_type != MSM_CAMERA_I2C_BYTE_DATA
+		&& write_setting->data_type != MSM_CAMERA_I2C_WORD_DATA))
+		return rc;
+	for (i = 0; i < write_setting->size; i++) {
+		rc = msm_camera_i2c_write(client, reg_setting->reg_addr,
+			reg_setting->reg_data, write_setting->data_type);
+		if (rc < 0)
+			break;
+		reg_setting++;
+	}
+	if (write_setting->delay > 20)
+		msleep(write_setting->delay);
+	else if (write_setting->delay)
+		usleep_range(write_setting->delay * 1000, (write_setting->delay
+			* 1000) + 1000);
+	return rc;
+}
+
 int32_t msm_camera_i2c_write_tbl(struct msm_camera_i2c_client *client,
 	struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint16_t size,
 	enum msm_camera_i2c_data_type data_type)
@@ -348,6 +382,7 @@
 		cci_ctrl.cci_info = client->cci_client;
 		cci_ctrl.cfg.cci_i2c_write_cfg.reg_conf_tbl = reg_conf_tbl;
 		cci_ctrl.cfg.cci_i2c_write_cfg.data_type = data_type;
+		cci_ctrl.cfg.cci_i2c_write_cfg.addr_type = client->addr_type;
 		cci_ctrl.cfg.cci_i2c_write_cfg.size = size;
 		rc = v4l2_subdev_call(client->cci_client->cci_subdev,
 				core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl);
diff --git a/drivers/media/video/msm/io/msm_camera_i2c.h b/drivers/media/video/msm/io/msm_camera_i2c.h
index 169a0b3..35b3bd4 100644
--- a/drivers/media/video/msm/io/msm_camera_i2c.h
+++ b/drivers/media/video/msm/io/msm_camera_i2c.h
@@ -17,6 +17,7 @@
 #include <linux/delay.h>
 #include <mach/camera.h>
 #include <media/v4l2-subdev.h>
+#include <media/msm_camera.h>
 
 #define CONFIG_MSM_CAMERA_I2C_DBG 0
 
@@ -92,6 +93,10 @@
 	struct msm_camera_i2c_reg_tbl *reg_tbl, uint16_t size,
 	enum msm_camera_i2c_data_type data_type);
 
+int32_t msm_camera_i2c_write_bayer_table(
+	struct msm_camera_i2c_client *client,
+	struct msm_camera_i2c_reg_setting *write_setting);
+
 int32_t msm_camera_i2c_write_tbl(struct msm_camera_i2c_client *client,
 	struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint16_t size,
 	enum msm_camera_i2c_data_type data_type);
diff --git a/drivers/media/video/msm/io/msm_camera_io_util.c b/drivers/media/video/msm/io/msm_camera_io_util.c
index 4049266..613850b 100644
--- a/drivers/media/video/msm/io/msm_camera_io_util.c
+++ b/drivers/media/video/msm/io/msm_camera_io_util.c
@@ -20,6 +20,7 @@
 #include <mach/gpiomux.h>
 
 #define BUFF_SIZE_128 128
+static int gpio_ref_count;
 
 void msm_camera_io_w(u32 data, void __iomem *addr)
 {
@@ -133,6 +134,12 @@
 					   clk_info[i].clk_name);
 				goto cam_clk_enable_err;
 			}
+			if (clk_info[i].delay > 20) {
+				msleep(clk_info[i].delay);
+			} else if (clk_info[i].delay) {
+				usleep_range(clk_info[i].delay * 1000,
+					(clk_info[i].delay * 1000) + 1000);
+			}
 		}
 	} else {
 		for (i = num_clk - 1; i >= 0; i--) {
@@ -163,26 +170,41 @@
 }
 
 int msm_camera_config_vreg(struct device *dev, struct camera_vreg_t *cam_vreg,
-		int num_vreg, struct regulator **reg_ptr, int config)
+		int num_vreg, enum msm_camera_vreg_name_t *vreg_seq,
+		int num_vreg_seq, struct regulator **reg_ptr, int config)
 {
-	int i = 0;
+	int i = 0, j = 0;
 	int rc = 0;
 	struct camera_vreg_t *curr_vreg;
+
+	if (num_vreg_seq > num_vreg) {
+		pr_err("%s:%d vreg sequence invalid\n", __func__, __LINE__);
+		return -EINVAL;
+	}
+	if (!num_vreg_seq)
+		num_vreg_seq = num_vreg;
+
 	if (config) {
-		for (i = 0; i < num_vreg; i++) {
-			curr_vreg = &cam_vreg[i];
-			reg_ptr[i] = regulator_get(dev,
+		for (i = 0; i < num_vreg_seq; i++) {
+			if (vreg_seq) {
+				j = vreg_seq[i];
+				if (j >= num_vreg)
+					continue;
+			} else
+				j = i;
+			curr_vreg = &cam_vreg[j];
+			reg_ptr[j] = regulator_get(dev,
 				curr_vreg->reg_name);
-			if (IS_ERR(reg_ptr[i])) {
+			if (IS_ERR(reg_ptr[j])) {
 				pr_err("%s: %s get failed\n",
 					 __func__,
 					 curr_vreg->reg_name);
-				reg_ptr[i] = NULL;
+				reg_ptr[j] = NULL;
 				goto vreg_get_fail;
 			}
 			if (curr_vreg->type == REG_LDO) {
 				rc = regulator_set_voltage(
-					reg_ptr[i],
+					reg_ptr[j],
 					curr_vreg->min_voltage,
 					curr_vreg->max_voltage);
 				if (rc < 0) {
@@ -193,7 +215,7 @@
 				}
 				if (curr_vreg->op_mode >= 0) {
 					rc = regulator_set_optimum_mode(
-						reg_ptr[i],
+						reg_ptr[j],
 						curr_vreg->op_mode);
 					if (rc < 0) {
 						pr_err(
@@ -206,20 +228,26 @@
 			}
 		}
 	} else {
-		for (i = num_vreg-1; i >= 0; i--) {
-			curr_vreg = &cam_vreg[i];
-			if (reg_ptr[i]) {
+		for (i = num_vreg_seq-1; i >= 0; i--) {
+			if (vreg_seq) {
+				j = vreg_seq[i];
+				if (j >= num_vreg)
+					continue;
+			} else
+				j = i;
+			curr_vreg = &cam_vreg[j];
+			if (reg_ptr[j]) {
 				if (curr_vreg->type == REG_LDO) {
 					if (curr_vreg->op_mode >= 0) {
 						regulator_set_optimum_mode(
-							reg_ptr[i], 0);
+							reg_ptr[j], 0);
 					}
 					regulator_set_voltage(
-						reg_ptr[i], 0, curr_vreg->
+						reg_ptr[j], 0, curr_vreg->
 						max_voltage);
 				}
-				regulator_put(reg_ptr[i]);
-				reg_ptr[i] = NULL;
+				regulator_put(reg_ptr[j]);
+				reg_ptr[j] = NULL;
 			}
 		}
 	}
@@ -227,52 +255,100 @@
 
 vreg_unconfig:
 if (curr_vreg->type == REG_LDO)
-	regulator_set_optimum_mode(reg_ptr[i], 0);
+	regulator_set_optimum_mode(reg_ptr[j], 0);
 
 vreg_set_opt_mode_fail:
 if (curr_vreg->type == REG_LDO)
-	regulator_set_voltage(reg_ptr[i], 0,
+	regulator_set_voltage(reg_ptr[j], 0,
 		curr_vreg->max_voltage);
 
 vreg_set_voltage_fail:
-	regulator_put(reg_ptr[i]);
-	reg_ptr[i] = NULL;
+	regulator_put(reg_ptr[j]);
+	reg_ptr[j] = NULL;
 
 vreg_get_fail:
 	for (i--; i >= 0; i--) {
-		curr_vreg = &cam_vreg[i];
+		if (vreg_seq) {
+			j = vreg_seq[i];
+			if (j >= num_vreg)
+				continue;
+		} else
+			j = i;
+		curr_vreg = &cam_vreg[j];
 		goto vreg_unconfig;
 	}
 	return -ENODEV;
 }
 
 int msm_camera_enable_vreg(struct device *dev, struct camera_vreg_t *cam_vreg,
-		int num_vreg, struct regulator **reg_ptr, int enable)
+		int num_vreg, enum msm_camera_vreg_name_t *vreg_seq,
+		int num_vreg_seq, struct regulator **reg_ptr, int enable)
 {
-	int i = 0, rc = 0;
+	int i = 0, j = 0, rc = 0;
+
+	if (num_vreg_seq > num_vreg) {
+		pr_err("%s:%d vreg sequence invalid\n", __func__, __LINE__);
+		return -EINVAL;
+	}
+	if (!num_vreg_seq)
+		num_vreg_seq = num_vreg;
+
 	if (enable) {
-		for (i = 0; i < num_vreg; i++) {
-			if (IS_ERR(reg_ptr[i])) {
+		for (i = 0; i < num_vreg_seq; i++) {
+			if (vreg_seq) {
+				j = vreg_seq[i];
+				if (j >= num_vreg)
+					continue;
+			} else
+				j = i;
+			if (IS_ERR(reg_ptr[j])) {
 				pr_err("%s: %s null regulator\n",
-					__func__, cam_vreg[i].reg_name);
+					__func__, cam_vreg[j].reg_name);
 				goto disable_vreg;
 			}
-			rc = regulator_enable(reg_ptr[i]);
+			rc = regulator_enable(reg_ptr[j]);
 			if (rc < 0) {
 				pr_err("%s: %s enable failed\n",
-					__func__, cam_vreg[i].reg_name);
+					__func__, cam_vreg[j].reg_name);
 				goto disable_vreg;
 			}
+			if (cam_vreg[j].delay > 20)
+				msleep(cam_vreg[j].delay);
+			else if (cam_vreg[j].delay)
+				usleep_range(cam_vreg[j].delay * 1000,
+					(cam_vreg[j].delay * 1000) + 1000);
 		}
 	} else {
-		for (i = num_vreg-1; i >= 0; i--)
-			regulator_disable(reg_ptr[i]);
+		for (i = num_vreg_seq-1; i >= 0; i--) {
+			if (vreg_seq) {
+				j = vreg_seq[i];
+				if (j >= num_vreg)
+					continue;
+			} else
+				j = i;
+			regulator_disable(reg_ptr[j]);
+			if (cam_vreg[j].delay > 20)
+				msleep(cam_vreg[j].delay);
+			else if (cam_vreg[j].delay)
+				usleep_range(cam_vreg[j].delay * 1000,
+					(cam_vreg[j].delay * 1000) + 1000);
+		}
 	}
 	return rc;
 disable_vreg:
 	for (i--; i >= 0; i--) {
-		regulator_disable(reg_ptr[i]);
-		goto disable_vreg;
+		if (vreg_seq) {
+			j = vreg_seq[i];
+			if (j >= num_vreg)
+				continue;
+		} else
+			j = i;
+		regulator_disable(reg_ptr[j]);
+		if (cam_vreg[j].delay > 20)
+			msleep(cam_vreg[j].delay);
+		else if (cam_vreg[j].delay)
+			usleep_range(cam_vreg[j].delay * 1000,
+				(cam_vreg[j].delay * 1000) + 1000);
 	}
 	return rc;
 }
@@ -319,7 +395,7 @@
 		config_gpio_table(gpio_conf);
 
 	if (gpio_en) {
-		if (!gpio_conf->gpio_no_mux) {
+		if (!gpio_conf->gpio_no_mux && !gpio_ref_count) {
 			if (gpio_conf->cam_gpiomux_conf_tbl != NULL) {
 				msm_gpiomux_install(
 					(struct msm_gpiomux_config *)
@@ -334,6 +410,7 @@
 				return rc;
 			}
 		}
+		gpio_ref_count++;
 		if (gpio_conf->cam_gpio_req_tbl_size) {
 			rc = gpio_request_array(gpio_conf->cam_gpio_req_tbl,
 				gpio_conf->cam_gpio_req_tbl_size);
@@ -346,9 +423,10 @@
 			}
 		}
 	} else {
+		gpio_ref_count--;
 		gpio_free_array(gpio_conf->cam_gpio_req_tbl,
 				gpio_conf->cam_gpio_req_tbl_size);
-		if (!gpio_conf->gpio_no_mux)
+		if (!gpio_conf->gpio_no_mux && !gpio_ref_count)
 			gpio_free_array(gpio_conf->cam_gpio_common_tbl,
 				gpio_conf->cam_gpio_common_tbl_size);
 	}
@@ -380,3 +458,39 @@
 	}
 	return rc;
 }
+
+void msm_camera_bus_scale_cfg(uint32_t bus_perf_client,
+		enum msm_bus_perf_setting perf_setting)
+{
+	int rc = 0;
+	if (!bus_perf_client) {
+		pr_err("%s: Bus Client NOT Registered!!!\n", __func__);
+		return;
+	}
+
+	switch (perf_setting) {
+	case S_EXIT:
+		rc = msm_bus_scale_client_update_request(bus_perf_client, 1);
+		msm_bus_scale_unregister_client(bus_perf_client);
+		break;
+	case S_PREVIEW:
+		rc = msm_bus_scale_client_update_request(bus_perf_client, 1);
+		break;
+	case S_VIDEO:
+		rc = msm_bus_scale_client_update_request(bus_perf_client, 2);
+		break;
+	case S_CAPTURE:
+		rc = msm_bus_scale_client_update_request(bus_perf_client, 3);
+		break;
+	case S_ZSL:
+		rc = msm_bus_scale_client_update_request(bus_perf_client, 4);
+		break;
+	case S_LIVESHOT:
+		rc = msm_bus_scale_client_update_request(bus_perf_client, 5);
+		break;
+	case S_DEFAULT:
+		break;
+	default:
+		pr_warning("%s: INVALID CASE\n", __func__);
+	}
+}
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/io/msm_io_8960.c b/drivers/media/video/msm/io/msm_io_8960.c
index 699425a..808cc32 100644
--- a/drivers/media/video/msm/io/msm_io_8960.c
+++ b/drivers/media/video/msm/io/msm_io_8960.c
@@ -95,6 +95,14 @@
 		} else
 			CDBG("%s: Bus Client NOT Registered!!!\n", __func__);
 		break;
+	case S_DUAL:
+		if (bus_perf_client) {
+			rc = msm_bus_scale_client_update_request(
+				bus_perf_client, 6);
+			CDBG("%s: S_DUAL rc = %d\n", __func__, rc);
+		} else
+			CDBG("%s: Bus Client NOT Registered!!!\n", __func__);
+		break;
 	case S_DEFAULT:
 		break;
 	default:
diff --git a/drivers/media/video/msm/jpeg_10/Makefile b/drivers/media/video/msm/jpeg_10/Makefile
new file mode 100644
index 0000000..d99d1a4
--- /dev/null
+++ b/drivers/media/video/msm/jpeg_10/Makefile
@@ -0,0 +1,3 @@
+GCC_VERSION      := $(shell $(CONFIG_SHELL) $(PWD)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc)
+ccflags-y += -Idrivers/media/video/msm
+obj-$(CONFIG_MSM_JPEG) += msm_jpeg_dev.o msm_jpeg_sync.o msm_jpeg_core.o msm_jpeg_hw.o msm_jpeg_platform.o
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_common.h b/drivers/media/video/msm/jpeg_10/msm_jpeg_common.h
new file mode 100644
index 0000000..88ec1ad
--- /dev/null
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_common.h
@@ -0,0 +1,38 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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_JPEG_COMMON_H
+#define MSM_JPEG_COMMON_H
+
+#ifdef MSM_JPEG_DEBUG
+#define JPEG_DBG(fmt, args...) printk(fmt, ##args)
+#else
+#define JPEG_DBG(fmt, args...) do { } while (0)
+#endif
+
+#define JPEG_PR_ERR   pr_err
+
+enum JPEG_MODE {
+	JPEG_MODE_DISABLE,
+	JPEG_MODE_OFFLINE,
+	JPEG_MODE_REALTIME,
+	JPEG_MODE_REALTIME_ROTATION
+};
+
+enum JPEG_ROTATION {
+	JPEG_ROTATION_0,
+	JPEG_ROTATION_90,
+	JPEG_ROTATION_180,
+	JPEG_ROTATION_270
+};
+
+#endif /* MSM_JPEG_COMMON_H */
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_core.c b/drivers/media/video/msm/jpeg_10/msm_jpeg_core.c
new file mode 100644
index 0000000..7905ff3
--- /dev/null
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_core.c
@@ -0,0 +1,223 @@
+/* Copyright (c) 2012,The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/sched.h>
+#include "msm_jpeg_hw.h"
+#include "msm_jpeg_core.h"
+#include "msm_jpeg_platform.h"
+#include "msm_jpeg_common.h"
+
+static struct msm_jpeg_hw_pingpong fe_pingpong_buf;
+static struct msm_jpeg_hw_pingpong we_pingpong_buf;
+static int we_pingpong_index;
+static int reset_done_ack;
+static spinlock_t reset_lock;
+static wait_queue_head_t reset_wait;
+
+int msm_jpeg_core_reset(uint8_t op_mode, void *base, int size)
+{
+	unsigned long flags;
+	int rc = 0;
+	int tm = 500; /*500ms*/
+	memset(&fe_pingpong_buf, 0, sizeof(fe_pingpong_buf));
+	fe_pingpong_buf.is_fe = 1;
+	we_pingpong_index = 0;
+	memset(&we_pingpong_buf, 0, sizeof(we_pingpong_buf));
+	spin_lock_irqsave(&reset_lock, flags);
+	reset_done_ack = 0;
+	msm_jpeg_hw_reset(base, size);
+	spin_unlock_irqrestore(&reset_lock, flags);
+	rc = wait_event_interruptible_timeout(
+			reset_wait,
+			reset_done_ack,
+			msecs_to_jiffies(tm));
+
+	if (!reset_done_ack) {
+		JPEG_DBG("%s: reset ACK failed %d", __func__, rc);
+		return -EBUSY;
+	}
+
+	JPEG_DBG("%s: reset_done_ack rc %d", __func__, rc);
+	spin_lock_irqsave(&reset_lock, flags);
+	reset_done_ack = 0;
+	spin_unlock_irqrestore(&reset_lock, flags);
+
+	return 0;
+}
+
+void msm_jpeg_core_release(int release_buf, int domain_num)
+{
+	int i = 0;
+	for (i = 0; i < 2; i++) {
+		if (we_pingpong_buf.buf_status[i] && release_buf)
+			msm_jpeg_platform_p2v(we_pingpong_buf.buf[i].file,
+				&we_pingpong_buf.buf[i].handle, domain_num);
+		we_pingpong_buf.buf_status[i] = 0;
+	}
+}
+
+void msm_jpeg_core_init(void)
+{
+	init_waitqueue_head(&reset_wait);
+	spin_lock_init(&reset_lock);
+}
+
+int msm_jpeg_core_fe_start(void)
+{
+	msm_jpeg_hw_fe_start();
+	return 0;
+}
+
+/* fetch engine */
+int msm_jpeg_core_fe_buf_update(struct msm_jpeg_core_buf *buf)
+{
+	JPEG_DBG("%s:%d] 0x%08x %d 0x%08x %d\n", __func__, __LINE__,
+		(int) buf->y_buffer_addr, buf->y_len,
+		(int) buf->cbcr_buffer_addr, buf->cbcr_len);
+	return msm_jpeg_hw_pingpong_update(&fe_pingpong_buf, buf);
+}
+
+void *msm_jpeg_core_fe_pingpong_irq(int jpeg_irq_status, void *context)
+{
+	return msm_jpeg_hw_pingpong_irq(&fe_pingpong_buf);
+}
+
+/* write engine */
+int msm_jpeg_core_we_buf_update(struct msm_jpeg_core_buf *buf)
+{
+	JPEG_DBG("%s:%d] 0x%08x 0x%08x %d\n", __func__, __LINE__,
+		(int) buf->y_buffer_addr, (int) buf->cbcr_buffer_addr,
+		buf->y_len);
+	we_pingpong_buf.buf[0] = *buf;
+	we_pingpong_buf.buf_status[0] = 1;
+	msm_jpeg_hw_we_buffer_update(
+			&we_pingpong_buf.buf[0], 0);
+
+	return 0;
+}
+
+int msm_jpeg_core_we_buf_reset(struct msm_jpeg_hw_buf *buf)
+{
+	int i = 0;
+	for (i = 0; i < 2; i++) {
+		if (we_pingpong_buf.buf[i].y_buffer_addr
+					== buf->y_buffer_addr)
+			we_pingpong_buf.buf_status[i] = 0;
+	}
+	return 0;
+}
+
+void *msm_jpeg_core_we_pingpong_irq(int jpeg_irq_status, void *context)
+{
+	JPEG_DBG("%s:%d]\n", __func__, __LINE__);
+
+	return msm_jpeg_hw_pingpong_irq(&we_pingpong_buf);
+}
+
+void *msm_jpeg_core_framedone_irq(int jpeg_irq_status, void *context)
+{
+	struct msm_jpeg_hw_buf *buf_p;
+
+	JPEG_DBG("%s:%d]\n", __func__, __LINE__);
+
+	buf_p = msm_jpeg_hw_pingpong_active_buffer(&we_pingpong_buf);
+	if (buf_p) {
+		buf_p->framedone_len = msm_jpeg_hw_encode_output_size();
+		JPEG_DBG("%s:%d] framedone_len %d\n", __func__, __LINE__,
+			buf_p->framedone_len);
+	}
+
+	return buf_p;
+}
+
+void *msm_jpeg_core_reset_ack_irq(int jpeg_irq_status, void *context)
+{
+	/* @todo return the status back to msm_jpeg_core_reset */
+	JPEG_DBG("%s:%d]\n", __func__, __LINE__);
+	return NULL;
+}
+
+void *msm_jpeg_core_err_irq(int jpeg_irq_status, void *context)
+{
+	JPEG_PR_ERR("%s:%d]\n", __func__, jpeg_irq_status);
+	return NULL;
+}
+
+static int (*msm_jpeg_irq_handler) (int, void *, void *);
+
+irqreturn_t msm_jpeg_core_irq(int irq_num, void *context)
+{
+	void *data = NULL;
+	unsigned long flags;
+	int jpeg_irq_status;
+
+	JPEG_DBG("%s:%d] irq_num = %d\n", __func__, __LINE__, irq_num);
+
+	jpeg_irq_status = msm_jpeg_hw_irq_get_status();
+
+	JPEG_DBG("%s:%d] jpeg_irq_status = %0x\n", __func__, __LINE__,
+		jpeg_irq_status);
+
+	/*For reset and framedone IRQs, clear all bits*/
+	if (jpeg_irq_status & 0x10000000) {
+		msm_jpeg_hw_irq_clear(JPEG_IRQ_CLEAR_BMSK,
+			JPEG_IRQ_CLEAR_ALL);
+	} else if (jpeg_irq_status & 0x1) {
+		msm_jpeg_hw_irq_clear(JPEG_IRQ_CLEAR_BMSK,
+			JPEG_IRQ_CLEAR_ALL);
+	} else {
+		msm_jpeg_hw_irq_clear(JPEG_IRQ_CLEAR_BMSK,
+			jpeg_irq_status);
+	}
+
+	if (msm_jpeg_hw_irq_is_frame_done(jpeg_irq_status)) {
+		data = msm_jpeg_core_framedone_irq(jpeg_irq_status,
+			context);
+		if (msm_jpeg_irq_handler)
+			msm_jpeg_irq_handler(
+				MSM_JPEG_HW_MASK_COMP_FRAMEDONE,
+				context, data);
+	}
+	if (msm_jpeg_hw_irq_is_reset_ack(jpeg_irq_status)) {
+		data = msm_jpeg_core_reset_ack_irq(jpeg_irq_status,
+			context);
+		spin_lock_irqsave(&reset_lock, flags);
+		reset_done_ack = 1;
+		spin_unlock_irqrestore(&reset_lock, flags);
+		wake_up(&reset_wait);
+		if (msm_jpeg_irq_handler)
+			msm_jpeg_irq_handler(
+				MSM_JPEG_HW_MASK_COMP_RESET_ACK,
+				context, data);
+	}
+
+	/* Unexpected/unintended HW interrupt */
+	if (msm_jpeg_hw_irq_is_err(jpeg_irq_status)) {
+		data = msm_jpeg_core_err_irq(jpeg_irq_status, context);
+		if (msm_jpeg_irq_handler)
+			msm_jpeg_irq_handler(MSM_JPEG_HW_MASK_COMP_ERR,
+				context, data);
+	}
+
+	return IRQ_HANDLED;
+}
+
+void msm_jpeg_core_irq_install(int (*irq_handler) (int, void *, void *))
+{
+	msm_jpeg_irq_handler = irq_handler;
+}
+
+void msm_jpeg_core_irq_remove(void)
+{
+	msm_jpeg_irq_handler = NULL;
+}
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_core.h b/drivers/media/video/msm/jpeg_10/msm_jpeg_core.h
new file mode 100644
index 0000000..b5c725c
--- /dev/null
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_core.h
@@ -0,0 +1,35 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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_JPEG_CORE_H
+#define MSM_JPEG_CORE_H
+
+#include <linux/interrupt.h>
+#include "msm_jpeg_hw.h"
+
+#define msm_jpeg_core_buf msm_jpeg_hw_buf
+
+irqreturn_t msm_jpeg_core_irq(int irq_num, void *context);
+
+void msm_jpeg_core_irq_install(int (*irq_handler) (int, void *, void *));
+void msm_jpeg_core_irq_remove(void);
+
+int msm_jpeg_core_fe_buf_update(struct msm_jpeg_core_buf *buf);
+int msm_jpeg_core_we_buf_update(struct msm_jpeg_core_buf *buf);
+int msm_jpeg_core_we_buf_reset(struct msm_jpeg_hw_buf *buf);
+
+int msm_jpeg_core_reset(uint8_t op_mode, void *base, int size);
+int msm_jpeg_core_fe_start(void);
+
+void msm_jpeg_core_release(int, int);
+void msm_jpeg_core_init(void);
+#endif /* MSM_JPEG_CORE_H */
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_dev.c b/drivers/media/video/msm/jpeg_10/msm_jpeg_dev.c
new file mode 100644
index 0000000..45a9a38
--- /dev/null
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_dev.c
@@ -0,0 +1,299 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/kernel.h>
+#include <linux/platform_device.h>
+#include <mach/board.h>
+#include <linux/of.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/uaccess.h>
+#include <media/msm_jpeg.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+
+#include "msm.h"
+#include "msm_jpeg_sync.h"
+#include "msm_jpeg_common.h"
+
+#define MSM_JPEG_NAME "jpeg"
+#define MSM_JPEGE1_NAME "jpege1"
+#define MSM_JPEGD_NAME "jpegd"
+
+
+static int msm_jpeg_open(struct inode *inode, struct file *filp)
+{
+	int rc = 0;
+
+	struct msm_jpeg_device *pgmn_dev = container_of(inode->i_cdev,
+		struct msm_jpeg_device, cdev);
+	filp->private_data = pgmn_dev;
+
+	JPEG_DBG("%s:%d]\n", __func__, __LINE__);
+
+	rc = __msm_jpeg_open(pgmn_dev);
+
+	JPEG_DBG(KERN_INFO "%s:%d] %s open_count = %d\n", __func__, __LINE__,
+		filp->f_path.dentry->d_name.name, pgmn_dev->open_count);
+
+	return rc;
+}
+
+static int msm_jpeg_release(struct inode *inode, struct file *filp)
+{
+	int rc;
+
+	struct msm_jpeg_device *pgmn_dev = filp->private_data;
+
+	JPEG_DBG(KERN_INFO "%s:%d]\n", __func__, __LINE__);
+
+	rc = __msm_jpeg_release(pgmn_dev);
+
+	JPEG_DBG(KERN_INFO "%s:%d] %s open_count = %d\n", __func__, __LINE__,
+		filp->f_path.dentry->d_name.name, pgmn_dev->open_count);
+	return rc;
+}
+
+static long msm_jpeg_ioctl(struct file *filp, unsigned int cmd,
+	unsigned long arg)
+{
+	int rc;
+	struct msm_jpeg_device *pgmn_dev = filp->private_data;
+
+	JPEG_DBG("%s:%d] cmd=%d pgmn_dev=0x%x arg=0x%x\n", __func__,
+		__LINE__, _IOC_NR(cmd), (uint32_t)pgmn_dev, (uint32_t)arg);
+
+	rc = __msm_jpeg_ioctl(pgmn_dev, cmd, arg);
+
+	JPEG_DBG("%s:%d]\n", __func__, __LINE__);
+	return rc;
+}
+
+static const struct file_operations msm_jpeg_fops = {
+	.owner		= THIS_MODULE,
+	.open		 = msm_jpeg_open,
+	.release	= msm_jpeg_release,
+	.unlocked_ioctl = msm_jpeg_ioctl,
+};
+
+
+int msm_jpeg_subdev_init(struct v4l2_subdev *jpeg_sd)
+{
+	int rc;
+	struct msm_jpeg_device *pgmn_dev =
+		(struct msm_jpeg_device *)jpeg_sd->host_priv;
+
+	JPEG_DBG("%s:%d: jpeg_sd=0x%x pgmn_dev=0x%x\n",
+		__func__, __LINE__, (uint32_t)jpeg_sd, (uint32_t)pgmn_dev);
+	rc = __msm_jpeg_open(pgmn_dev);
+	JPEG_DBG("%s:%d: rc=%d\n",
+		__func__, __LINE__, rc);
+	return rc;
+}
+
+static long msm_jpeg_subdev_ioctl(struct v4l2_subdev *sd,
+	unsigned int cmd, void *arg)
+{
+	long rc;
+	struct msm_jpeg_device *pgmn_dev =
+		(struct msm_jpeg_device *)sd->host_priv;
+
+	JPEG_DBG("%s: cmd=%d\n", __func__, cmd);
+
+	JPEG_DBG("%s: pgmn_dev 0x%x", __func__, (uint32_t)pgmn_dev);
+
+	JPEG_DBG("%s: Calling __msm_jpeg_ioctl\n", __func__);
+
+	rc = __msm_jpeg_ioctl(pgmn_dev, cmd, (unsigned long)arg);
+	pr_debug("%s: X\n", __func__);
+	return rc;
+}
+
+void msm_jpeg_subdev_release(struct v4l2_subdev *jpeg_sd)
+{
+	int rc;
+	struct msm_jpeg_device *pgmn_dev =
+		(struct msm_jpeg_device *)jpeg_sd->host_priv;
+	JPEG_DBG("%s:pgmn_dev=0x%x", __func__, (uint32_t)pgmn_dev);
+	rc = __msm_jpeg_release(pgmn_dev);
+	JPEG_DBG("%s:rc=%d", __func__, rc);
+}
+
+static const struct v4l2_subdev_core_ops msm_jpeg_subdev_core_ops = {
+	.ioctl = msm_jpeg_subdev_ioctl,
+};
+
+static const struct v4l2_subdev_ops msm_jpeg_subdev_ops = {
+	.core = &msm_jpeg_subdev_core_ops,
+};
+
+static int msm_jpeg_init_dev(struct platform_device *pdev)
+{
+	int rc = -1;
+	struct device *dev;
+	struct msm_jpeg_device *msm_jpeg_device_p;
+	char devname[10];
+
+	msm_jpeg_device_p = kzalloc(sizeof(struct msm_jpeg_device), GFP_ATOMIC);
+	if (!msm_jpeg_device_p) {
+		JPEG_PR_ERR("%s: no mem\n", __func__);
+		return -EFAULT;
+	}
+
+	msm_jpeg_device_p->pdev = pdev;
+
+	if (pdev->dev.of_node)
+		of_property_read_u32((&pdev->dev)->of_node, "cell-index",
+								&pdev->id);
+
+	snprintf(devname, sizeof(devname), "%s%d", MSM_JPEG_NAME, pdev->id);
+
+	rc = __msm_jpeg_init(msm_jpeg_device_p);
+	if (rc < -1) {
+		JPEG_PR_ERR("%s: initialization failed\n", __func__);
+		goto fail;
+	}
+
+	v4l2_subdev_init(&msm_jpeg_device_p->subdev, &msm_jpeg_subdev_ops);
+	v4l2_set_subdev_hostdata(&msm_jpeg_device_p->subdev, msm_jpeg_device_p);
+	JPEG_DBG("%s: msm_jpeg_device_p 0x%x", __func__,
+			(uint32_t)msm_jpeg_device_p);
+
+	rc = alloc_chrdev_region(&msm_jpeg_device_p->msm_jpeg_devno, 0, 1,
+				devname);
+	if (rc < 0) {
+		JPEG_PR_ERR("%s: failed to allocate chrdev\n", __func__);
+		goto fail_1;
+	}
+
+	if (!msm_jpeg_device_p->msm_jpeg_class) {
+		msm_jpeg_device_p->msm_jpeg_class =
+				class_create(THIS_MODULE, devname);
+		if (IS_ERR(msm_jpeg_device_p->msm_jpeg_class)) {
+			rc = PTR_ERR(msm_jpeg_device_p->msm_jpeg_class);
+			JPEG_PR_ERR("%s: create device class failed\n",
+				__func__);
+			goto fail_2;
+		}
+	}
+
+	dev = device_create(msm_jpeg_device_p->msm_jpeg_class, NULL,
+		MKDEV(MAJOR(msm_jpeg_device_p->msm_jpeg_devno),
+		MINOR(msm_jpeg_device_p->msm_jpeg_devno)), NULL,
+		"%s%d", MSM_JPEG_NAME, pdev->id);
+	if (IS_ERR(dev)) {
+		JPEG_PR_ERR("%s: error creating device\n", __func__);
+		rc = -ENODEV;
+		goto fail_3;
+	}
+
+	cdev_init(&msm_jpeg_device_p->cdev, &msm_jpeg_fops);
+	msm_jpeg_device_p->cdev.owner = THIS_MODULE;
+	msm_jpeg_device_p->cdev.ops	 =
+		(const struct file_operations *) &msm_jpeg_fops;
+	rc = cdev_add(&msm_jpeg_device_p->cdev,
+			msm_jpeg_device_p->msm_jpeg_devno, 1);
+	if (rc < 0) {
+		JPEG_PR_ERR("%s: error adding cdev\n", __func__);
+		rc = -ENODEV;
+		goto fail_4;
+	}
+
+	platform_set_drvdata(pdev, &msm_jpeg_device_p);
+
+	JPEG_DBG("%s %s%d: success\n", __func__, MSM_JPEG_NAME, pdev->id);
+
+	return rc;
+
+fail_4:
+	device_destroy(msm_jpeg_device_p->msm_jpeg_class,
+			msm_jpeg_device_p->msm_jpeg_devno);
+
+fail_3:
+	class_destroy(msm_jpeg_device_p->msm_jpeg_class);
+
+fail_2:
+	unregister_chrdev_region(msm_jpeg_device_p->msm_jpeg_devno, 1);
+
+fail_1:
+	__msm_jpeg_exit(msm_jpeg_device_p);
+
+fail:
+	kfree(msm_jpeg_device_p);
+	return rc;
+
+}
+
+static void msm_jpeg_exit(struct msm_jpeg_device *msm_jpeg_device_p)
+{
+	cdev_del(&msm_jpeg_device_p->cdev);
+	device_destroy(msm_jpeg_device_p->msm_jpeg_class,
+			msm_jpeg_device_p->msm_jpeg_devno);
+	class_destroy(msm_jpeg_device_p->msm_jpeg_class);
+	unregister_chrdev_region(msm_jpeg_device_p->msm_jpeg_devno, 1);
+
+	__msm_jpeg_exit(msm_jpeg_device_p);
+}
+
+static int __msm_jpeg_probe(struct platform_device *pdev)
+{
+	return msm_jpeg_init_dev(pdev);
+}
+
+static int __msm_jpeg_remove(struct platform_device *pdev)
+{
+	struct msm_jpeg_device *msm_jpegd_device_p;
+
+	msm_jpegd_device_p = platform_get_drvdata(pdev);
+	if (msm_jpegd_device_p)
+		msm_jpeg_exit(msm_jpegd_device_p);
+
+	return 0;
+}
+
+static const struct of_device_id msm_jpeg_dt_match[] = {
+			{.compatible = "qcom,jpeg"},
+};
+
+MODULE_DEVICE_TABLE(of, msm_jpeg_dt_match);
+
+static struct platform_driver msm_jpeg_driver = {
+	.probe	= __msm_jpeg_probe,
+	.remove = __msm_jpeg_remove,
+	.driver = {
+		.name = MSM_JPEG_DRV_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = msm_jpeg_dt_match,
+	},
+};
+
+static int __init msm_jpeg_driver_init(void)
+{
+	int rc;
+	rc = platform_driver_register(&msm_jpeg_driver);
+	return rc;
+}
+
+static void __exit msm_jpeg_driver_exit(void)
+{
+	platform_driver_unregister(&msm_jpeg_driver);
+}
+
+MODULE_DESCRIPTION("msm jpeg jpeg driver");
+
+module_init(msm_jpeg_driver_init);
+module_exit(msm_jpeg_driver_exit);
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_hw.c b/drivers/media/video/msm/jpeg_10/msm_jpeg_hw.c
new file mode 100644
index 0000000..0bfb6a8
--- /dev/null
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_hw.c
@@ -0,0 +1,380 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/delay.h>
+#include "msm_jpeg_hw.h"
+#include "msm_jpeg_common.h"
+
+#include <linux/io.h>
+
+static void *jpeg_region_base;
+static uint32_t jpeg_region_size;
+
+int msm_jpeg_hw_pingpong_update(struct msm_jpeg_hw_pingpong *pingpong_hw,
+	struct msm_jpeg_hw_buf *buf)
+{
+	int buf_free_index = -1;
+
+	if (!pingpong_hw->buf_status[0]) {
+		buf_free_index = 0;
+	} else if (!pingpong_hw->buf_status[1]) {
+		buf_free_index = 1;
+	} else {
+		JPEG_PR_ERR("%s:%d: pingpong buffer busy\n",
+		__func__, __LINE__);
+		return -EBUSY;
+	}
+
+	pingpong_hw->buf[buf_free_index] = *buf;
+	pingpong_hw->buf_status[buf_free_index] = 1;
+
+	if (pingpong_hw->is_fe) {
+		/* it is fe */
+		msm_jpeg_hw_fe_buffer_update(
+			&pingpong_hw->buf[buf_free_index], buf_free_index);
+	} else {
+		/* it is we */
+		msm_jpeg_hw_we_buffer_update(
+			&pingpong_hw->buf[buf_free_index], buf_free_index);
+	}
+	return 0;
+}
+
+void *msm_jpeg_hw_pingpong_irq(struct msm_jpeg_hw_pingpong *pingpong_hw)
+{
+	struct msm_jpeg_hw_buf *buf_p = NULL;
+
+	if (pingpong_hw->buf_status[pingpong_hw->buf_active_index]) {
+		buf_p = &pingpong_hw->buf[pingpong_hw->buf_active_index];
+		pingpong_hw->buf_status[pingpong_hw->buf_active_index] = 0;
+	}
+
+	pingpong_hw->buf_active_index = !pingpong_hw->buf_active_index;
+
+	return (void *) buf_p;
+}
+
+void *msm_jpeg_hw_pingpong_active_buffer(
+	struct msm_jpeg_hw_pingpong *pingpong_hw)
+{
+	struct msm_jpeg_hw_buf *buf_p = NULL;
+
+	if (pingpong_hw->buf_status[pingpong_hw->buf_active_index])
+		buf_p = &pingpong_hw->buf[pingpong_hw->buf_active_index];
+
+	return (void *) buf_p;
+}
+
+struct msm_jpeg_hw_cmd hw_cmd_irq_get_status[] = {
+	/* type, repeat n times, offset, mask, data or pdata */
+	{MSM_JPEG_HW_CMD_TYPE_READ, 1, JPEG_IRQ_STATUS_ADDR,
+		JPEG_IRQ_STATUS_BMSK, {0} },
+};
+
+int msm_jpeg_hw_irq_get_status(void)
+{
+	uint32_t n_irq_status = 0;
+	rmb();
+	n_irq_status = msm_jpeg_hw_read(&hw_cmd_irq_get_status[0]);
+	rmb();
+	return n_irq_status;
+}
+
+struct msm_jpeg_hw_cmd hw_cmd_encode_output_size[] = {
+	/* type, repeat n times, offset, mask, data or pdata */
+	{MSM_JPEG_HW_CMD_TYPE_READ, 1,
+	JPEG_ENCODE_OUTPUT_SIZE_STATUS_ADDR,
+	JPEG_ENCODE_OUTPUT_SIZE_STATUS_BMSK, {0} } ,
+};
+
+long msm_jpeg_hw_encode_output_size(void)
+{
+	uint32_t encode_output_size = 0;
+
+	encode_output_size = msm_jpeg_hw_read(&hw_cmd_encode_output_size[0]);
+
+	return encode_output_size;
+}
+
+struct msm_jpeg_hw_cmd hw_cmd_irq_clear[] = {
+	/* type, repeat n times, offset, mask, data or pdata */
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_IRQ_CLEAR_ADDR,
+		JPEG_IRQ_CLEAR_BMSK, {JPEG_IRQ_CLEAR_ALL} },
+};
+
+void msm_jpeg_hw_irq_clear(uint32_t mask, uint32_t data)
+{
+	JPEG_DBG("%s:%d] mask %0x data %0x", __func__, __LINE__, mask, data);
+	hw_cmd_irq_clear[0].mask = mask;
+	hw_cmd_irq_clear[0].data = data;
+	msm_jpeg_hw_write(&hw_cmd_irq_clear[0]);
+}
+
+struct msm_jpeg_hw_cmd hw_cmd_fe_ping_update[] = {
+	/* type, repeat n times, offset, mask, data or pdata */
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_IRQ_MASK_ADDR,
+		JPEG_IRQ_MASK_BMSK, {JPEG_IRQ_ALLSOURCES_ENABLE} },
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_CMD_ADDR,
+		JPEG_CMD_BMSK, {JPEG_CMD_CLEAR_WRITE_PLN_QUEUES} },
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN0_RD_OFFSET_ADDR,
+		JPEG_PLN0_RD_OFFSET_BMSK, {0} },
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN0_RD_PNTR_ADDR,
+		JPEG_PLN0_RD_PNTR_BMSK, {0} },
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN1_RD_OFFSET_ADDR,
+		JPEG_PLN1_RD_OFFSET_BMSK, {0} },
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN1_RD_PNTR_ADDR,
+		JPEG_PLN1_RD_PNTR_BMSK, {0} },
+};
+
+void msm_jpeg_hw_fe_buffer_update(struct msm_jpeg_hw_buf *p_input,
+	uint8_t pingpong_index)
+{
+	struct msm_jpeg_hw_cmd *hw_cmd_p;
+
+	if (pingpong_index == 0) {
+		hw_cmd_p = &hw_cmd_fe_ping_update[0];
+		wmb();
+		msm_jpeg_hw_write(hw_cmd_p++);
+		wmb();
+		msm_jpeg_hw_write(hw_cmd_p++);
+		wmb();
+		msm_jpeg_hw_write(hw_cmd_p++);
+		wmb();
+		hw_cmd_p->data = p_input->y_buffer_addr;
+		msm_jpeg_hw_write(hw_cmd_p++);
+		wmb();
+		msm_jpeg_hw_write(hw_cmd_p++);
+		wmb();
+		hw_cmd_p->data = p_input->cbcr_buffer_addr;
+		msm_jpeg_hw_write(hw_cmd_p++);
+		wmb();
+
+	}
+	return;
+}
+
+struct msm_jpeg_hw_cmd hw_cmd_fe_start[] = {
+	/* type, repeat n times, offset, mask, data or pdata */
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_CMD_ADDR,
+		JPEG_CMD_BMSK, {JPEG_OFFLINE_CMD_START} },
+};
+
+void msm_jpeg_hw_fe_start(void)
+{
+	msm_jpeg_hw_write(&hw_cmd_fe_start[0]);
+
+	return;
+}
+
+struct msm_jpeg_hw_cmd hw_cmd_we_ping_update[] = {
+	/* type, repeat n times, offset, mask, data or pdata */
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN0_WR_PNTR_ADDR,
+		JPEG_PLN0_WR_PNTR_BMSK, {0} },
+};
+
+void msm_jpeg_hw_we_buffer_update(struct msm_jpeg_hw_buf *p_input,
+	uint8_t pingpong_index)
+{
+	struct msm_jpeg_hw_cmd *hw_cmd_p;
+
+	if (pingpong_index == 0) {
+		hw_cmd_p = &hw_cmd_we_ping_update[0];
+		hw_cmd_p->data = p_input->y_buffer_addr;
+		JPEG_PR_ERR("%s Output buffer address is %x\n", __func__,
+						p_input->y_buffer_addr);
+		msm_jpeg_hw_write(hw_cmd_p++);
+
+	}
+	return;
+}
+
+struct msm_jpeg_hw_cmd hw_cmd_reset[] = {
+	/* type, repeat n times, offset, mask, data or pdata */
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_IRQ_MASK_ADDR,
+		JPEG_IRQ_MASK_BMSK, {JPEG_IRQ_DISABLE_ALL} },
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_IRQ_CLEAR_ADDR,
+		JPEG_IRQ_MASK_BMSK, {JPEG_IRQ_CLEAR_ALL} },
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_IRQ_MASK_ADDR,
+		JPEG_IRQ_MASK_BMSK, {JPEG_IRQ_ALLSOURCES_ENABLE} },
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_RESET_CMD_ADDR,
+		JPEG_RESET_CMD_RMSK, {JPEG_RESET_DEFAULT} },
+};
+
+void msm_jpeg_hw_init(void *base, int size)
+{
+	jpeg_region_base = base;
+	jpeg_region_size = size;
+}
+
+void msm_jpeg_hw_reset(void *base, int size)
+{
+	struct msm_jpeg_hw_cmd *hw_cmd_p;
+
+	hw_cmd_p = &hw_cmd_reset[0];
+	wmb();
+	msm_jpeg_hw_write(hw_cmd_p++);
+	wmb();
+	msm_jpeg_hw_write(hw_cmd_p++);
+	wmb();
+	msm_jpeg_hw_write(hw_cmd_p++);
+	wmb();
+	msm_jpeg_hw_write(hw_cmd_p);
+	wmb();
+
+	return;
+}
+
+uint32_t msm_jpeg_hw_read(struct msm_jpeg_hw_cmd *hw_cmd_p)
+{
+	uint32_t *paddr;
+	uint32_t data;
+
+	paddr = jpeg_region_base + hw_cmd_p->offset;
+
+	data = readl_relaxed(paddr);
+	data &= hw_cmd_p->mask;
+
+	return data;
+}
+
+void msm_jpeg_hw_write(struct msm_jpeg_hw_cmd *hw_cmd_p)
+{
+	uint32_t *paddr;
+	uint32_t old_data, new_data;
+
+	paddr = jpeg_region_base + hw_cmd_p->offset;
+
+	if (hw_cmd_p->mask == 0xffffffff) {
+		old_data = 0;
+	} else {
+		old_data = readl_relaxed(paddr);
+		old_data &= ~hw_cmd_p->mask;
+	}
+
+	new_data = hw_cmd_p->data & hw_cmd_p->mask;
+	new_data |= old_data;
+	writel_relaxed(new_data, paddr);
+}
+
+int msm_jpeg_hw_wait(struct msm_jpeg_hw_cmd *hw_cmd_p, int m_us)
+{
+	int tm = hw_cmd_p->n;
+	uint32_t data;
+	uint32_t wait_data = hw_cmd_p->data & hw_cmd_p->mask;
+
+	data = msm_jpeg_hw_read(hw_cmd_p);
+	if (data != wait_data) {
+		while (tm) {
+			udelay(m_us);
+			data = msm_jpeg_hw_read(hw_cmd_p);
+			if (data == wait_data)
+				break;
+			tm--;
+		}
+	}
+	hw_cmd_p->data = data;
+	return tm;
+}
+
+void msm_jpeg_hw_delay(struct msm_jpeg_hw_cmd *hw_cmd_p, int m_us)
+{
+	int tm = hw_cmd_p->n;
+	while (tm) {
+		udelay(m_us);
+		tm--;
+	}
+}
+
+int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *hw_cmd_p, int m_cmds)
+{
+	int is_copy_to_user = -1;
+	uint32_t data;
+
+	while (m_cmds--) {
+		if (hw_cmd_p->offset > jpeg_region_size) {
+			JPEG_PR_ERR("%s:%d] %d exceed hw region %d\n", __func__,
+				__LINE__, hw_cmd_p->offset, jpeg_region_size);
+			return -EFAULT;
+		}
+
+		switch (hw_cmd_p->type) {
+		case MSM_JPEG_HW_CMD_TYPE_READ:
+			hw_cmd_p->data = msm_jpeg_hw_read(hw_cmd_p);
+			is_copy_to_user = 1;
+			break;
+
+		case MSM_JPEG_HW_CMD_TYPE_WRITE:
+			msm_jpeg_hw_write(hw_cmd_p);
+			break;
+
+		case MSM_JPEG_HW_CMD_TYPE_WRITE_OR:
+			data = msm_jpeg_hw_read(hw_cmd_p);
+			hw_cmd_p->data = (hw_cmd_p->data & hw_cmd_p->mask) |
+				data;
+			msm_jpeg_hw_write(hw_cmd_p);
+			break;
+
+		case MSM_JPEG_HW_CMD_TYPE_UWAIT:
+			msm_jpeg_hw_wait(hw_cmd_p, 1);
+			break;
+
+		case MSM_JPEG_HW_CMD_TYPE_MWAIT:
+			msm_jpeg_hw_wait(hw_cmd_p, 1000);
+			break;
+
+		case MSM_JPEG_HW_CMD_TYPE_UDELAY:
+			msm_jpeg_hw_delay(hw_cmd_p, 1);
+			break;
+
+		case MSM_JPEG_HW_CMD_TYPE_MDELAY:
+			msm_jpeg_hw_delay(hw_cmd_p, 1000);
+			break;
+
+		default:
+			JPEG_PR_ERR("wrong hw command type\n");
+			break;
+		}
+
+		hw_cmd_p++;
+	}
+	return is_copy_to_user;
+}
+
+void msm_jpeg_io_dump(int size)
+{
+	char line_str[128], *p_str;
+	void __iomem *addr = jpeg_region_base;
+	int i;
+	u32 *p = (u32 *) addr;
+	u32 data;
+	JPEG_PR_ERR("%s: %p %d reg_size %d\n", __func__, addr, size,
+							jpeg_region_size);
+	line_str[0] = '\0';
+	p_str = line_str;
+	for (i = 0; i < size/4; i++) {
+		if (i % 4 == 0) {
+			snprintf(p_str, 12, "%08x: ", (u32) p);
+			p_str += 10;
+		}
+		data = readl_relaxed(p++);
+		snprintf(p_str, 12, "%08x ", data);
+		p_str += 9;
+		if ((i + 1) % 4 == 0) {
+			JPEG_PR_ERR("%s\n", line_str);
+			line_str[0] = '\0';
+			p_str = line_str;
+		}
+	}
+	if (line_str[0] != '\0')
+		JPEG_PR_ERR("%s\n", line_str);
+}
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_hw.h b/drivers/media/video/msm/jpeg_10/msm_jpeg_hw.h
new file mode 100644
index 0000000..73a0e27
--- /dev/null
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_hw.h
@@ -0,0 +1,101 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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_JPEG_HW_H
+#define MSM_JPEG_HW_H
+
+#include <media/msm_jpeg.h>
+#include "msm_jpeg_hw_reg.h"
+#include <linux/ion.h>
+#include <mach/iommu_domains.h>
+
+struct msm_jpeg_hw_buf {
+	struct msm_jpeg_buf vbuf;
+	struct file  *file;
+	uint32_t framedone_len;
+	uint32_t y_buffer_addr;
+	uint32_t y_len;
+	uint32_t cbcr_buffer_addr;
+	uint32_t cbcr_len;
+	uint32_t num_of_mcu_rows;
+	struct ion_handle *handle;
+};
+
+struct msm_jpeg_hw_pingpong {
+	uint8_t is_fe; /* 1: fe; 0: we */
+	struct  msm_jpeg_hw_buf buf[2];
+	int     buf_status[2];
+	int     buf_active_index;
+};
+
+int msm_jpeg_hw_pingpong_update(struct msm_jpeg_hw_pingpong *pingpong_hw,
+	struct msm_jpeg_hw_buf *buf);
+void *msm_jpeg_hw_pingpong_irq(struct msm_jpeg_hw_pingpong *pingpong_hw);
+void *msm_jpeg_hw_pingpong_active_buffer(struct msm_jpeg_hw_pingpong
+	*pingpong_hw);
+
+void msm_jpeg_hw_irq_clear(uint32_t, uint32_t);
+int msm_jpeg_hw_irq_get_status(void);
+long msm_jpeg_hw_encode_output_size(void);
+#define MSM_JPEG_HW_MASK_COMP_FRAMEDONE \
+		MSM_JPEG_HW_IRQ_STATUS_FRAMEDONE_MASK
+#define MSM_JPEG_HW_MASK_COMP_FE \
+		MSM_JPEG_HW_IRQ_STATUS_FE_RD_DONE_MASK
+#define MSM_JPEG_HW_MASK_COMP_WE \
+		(MSM_JPEG_HW_IRQ_STATUS_WE_Y_PINGPONG_MASK | \
+		 MSM_JPEG_HW_IRQ_STATUS_WE_CBCR_PINGPONG_MASK)
+#define MSM_JPEG_HW_MASK_COMP_RESET_ACK \
+		MSM_JPEG_HW_IRQ_STATUS_RESET_ACK_MASK
+#define MSM_JPEG_HW_MASK_COMP_ERR \
+		(MSM_JPEG_HW_IRQ_STATUS_FE_RTOVF_MASK | \
+		MSM_JPEG_HW_IRQ_STATUS_FE_VFE_OVERFLOW_MASK | \
+		MSM_JPEG_HW_IRQ_STATUS_WE_Y_BUFFER_OVERFLOW_MASK | \
+		MSM_JPEG_HW_IRQ_STATUS_WE_CBCR_BUFFER_OVERFLOW_MASK | \
+		MSM_JPEG_HW_IRQ_STATUS_WE_CH0_DATAFIFO_OVERFLOW_MASK | \
+		MSM_JPEG_HW_IRQ_STATUS_WE_CH1_DATAFIFO_OVERFLOW_MASK | \
+		MSM_JPEG_HW_IRQ_STATUS_BUS_ERROR_MASK | \
+		MSM_JPEG_HW_IRQ_STATUS_VIOLATION_MASK)
+
+#define msm_jpeg_hw_irq_is_frame_done(jpeg_irq_status) \
+	(jpeg_irq_status & MSM_JPEG_HW_MASK_COMP_FRAMEDONE)
+#define msm_jpeg_hw_irq_is_fe_pingpong(jpeg_irq_status) \
+	(jpeg_irq_status & MSM_JPEG_HW_MASK_COMP_FE)
+#define msm_jpeg_hw_irq_is_we_pingpong(jpeg_irq_status) \
+	(jpeg_irq_status & MSM_JPEG_HW_MASK_COMP_WE)
+#define msm_jpeg_hw_irq_is_reset_ack(jpeg_irq_status) \
+	(jpeg_irq_status & MSM_JPEG_HW_MASK_COMP_RESET_ACK)
+#define msm_jpeg_hw_irq_is_err(jpeg_irq_status) \
+	(jpeg_irq_status & MSM_JPEG_HW_MASK_COMP_ERR)
+
+void msm_jpeg_hw_fe_buffer_update(struct msm_jpeg_hw_buf *p_input,
+	uint8_t pingpong_index);
+void msm_jpeg_hw_we_buffer_update(struct msm_jpeg_hw_buf *p_input,
+	uint8_t pingpong_index);
+
+void msm_jpeg_hw_we_buffer_cfg(uint8_t is_realtime);
+
+void msm_jpeg_hw_fe_start(void);
+void msm_jpeg_hw_clk_cfg(void);
+
+void msm_jpeg_hw_reset(void *base, int size);
+void msm_jpeg_hw_irq_cfg(void);
+void msm_jpeg_hw_init(void *base, int size);
+
+uint32_t msm_jpeg_hw_read(struct msm_jpeg_hw_cmd *hw_cmd_p);
+void msm_jpeg_hw_write(struct msm_jpeg_hw_cmd *hw_cmd_p);
+int msm_jpeg_hw_wait(struct msm_jpeg_hw_cmd *hw_cmd_p, int m_us);
+void msm_jpeg_hw_delay(struct msm_jpeg_hw_cmd *hw_cmd_p, int m_us);
+int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *hw_cmd_p, int m_cmds);
+void msm_jpeg_hw_region_dump(int size);
+void msm_jpeg_io_dump(int size);
+
+#endif /* MSM_JPEG_HW_H */
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_hw_reg.h b/drivers/media/video/msm/jpeg_10/msm_jpeg_hw_reg.h
new file mode 100644
index 0000000..ae64c32
--- /dev/null
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_hw_reg.h
@@ -0,0 +1,121 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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_JPEG_HW_REG_H
+#define MSM_JPEG_HW_REG_H
+
+#define JPEG_REG_BASE 0
+
+#define MSM_JPEG_HW_IRQ_MASK_ADDR 0x00000018
+#define MSM_JPEG_HW_IRQ_MASK_RMSK 0xFFFFFFFF
+#define MSM_JPEG_HW_IRQ_ENABLE 0xFFFFFFFF
+
+#define MSM_JPEG_HW_IRQ_STATUS_FRAMEDONE_MASK 0x00000001
+#define MSM_JPEG_HW_IRQ_STATUS_FRAMEDONE_SHIFT 0x00000000
+
+#define MSM_JPEG_HW_IRQ_STATUS_FE_RD_DONE_MASK 0x00000010
+#define MSM_JPEG_HW_IRQ_STATUS_FE_RD_DONE_SHIFT 0x00000001
+
+#define MSM_JPEG_HW_IRQ_STATUS_FE_RTOVF_MASK 0x00000004
+#define MSM_JPEG_HW_IRQ_STATUS_FE_RTOVF_SHIFT 0x00000002
+
+#define MSM_JPEG_HW_IRQ_STATUS_FE_VFE_OVERFLOW_MASK 0x00000008
+#define MSM_JPEG_HW_IRQ_STATUS_FE_VFE_OVERFLOW_SHIFT 0x00000003
+
+#define MSM_JPEG_HW_IRQ_STATUS_WE_Y_PINGPONG_MASK 0x00000010
+#define MSM_JPEG_HW_IRQ_STATUS_WE_Y_PINGPONG_SHIFT 0x00000004
+
+#define MSM_JPEG_HW_IRQ_STATUS_WE_CBCR_PINGPONG_MASK 0x00000020
+#define MSM_JPEG_HW_IRQ_STATUS_WE_CBCR_PINGPONG_SHIFT 0x00000005
+
+#define MSM_JPEG_HW_IRQ_STATUS_WE_Y_BUFFER_OVERFLOW_MASK 0x00000040
+#define MSM_JPEG_HW_IRQ_STATUS_WE_Y_BUFFER_OVERFLOW_SHIFT 0x00000006
+
+#define MSM_JPEG_HW_IRQ_STATUS_WE_CBCR_BUFFER_OVERFLOW_MASK 0x00000080
+#define MSM_JPEG_HW_IRQ_STATUS_WE_CBCR_BUFFER_OVERFLOW_SHIFT 0x00000007
+
+#define MSM_JPEG_HW_IRQ_STATUS_WE_CH0_DATAFIFO_OVERFLOW_MASK 0x00000100
+#define MSM_JPEG_HW_IRQ_STATUS_WE_CH0_DATAFIFO_OVERFLOW_SHIFT 0x00000008
+
+#define MSM_JPEG_HW_IRQ_STATUS_WE_CH1_DATAFIFO_OVERFLOW_MASK 0x00000200
+#define MSM_JPEG_HW_IRQ_STATUS_WE_CH1_DATAFIFO_OVERFLOW_SHIFT 0x00000009
+
+#define MSM_JPEG_HW_IRQ_STATUS_RESET_ACK_MASK 0x10000000
+#define MSM_JPEG_HW_IRQ_STATUS_RESET_ACK_SHIFT 0x0000000a
+
+#define MSM_JPEG_HW_IRQ_STATUS_BUS_ERROR_MASK 0x00000800
+#define MSM_JPEG_HW_IRQ_STATUS_BUS_ERROR_SHIFT 0x0000000b
+
+#define MSM_JPEG_HW_IRQ_STATUS_VIOLATION_MASK 0x00001000
+#define MSM_JPEG_HW_IRQ_STATUS_VIOLATION_SHIFT 0x0000000c
+
+#define JPEG_OFFLINE_CMD_START 0x00000001
+
+#define JPEG_RESET_DEFAULT 0x00000003 /* cfff? */
+
+#define JPEG_IRQ_DISABLE_ALL 0x00000000
+#define JPEG_IRQ_CLEAR_ALL 0xFFFFFFFF
+
+#define JPEG_PLN0_RD_PNTR_ADDR (JPEG_REG_BASE + 0x00000038)
+#define JPEG_PLN0_RD_PNTR_BMSK  0xFFFFFFFF
+
+#define JPEG_PLN0_RD_OFFSET_ADDR 0x0000003C
+#define JPEG_PLN0_RD_OFFSET_BMSK 0x1FFFFFFF
+
+#define JPEG_PLN1_RD_PNTR_ADDR (JPEG_REG_BASE + 0x00000044)
+#define JPEG_PLN1_RD_PNTR_BMSK 0xFFFFFFFF
+
+#define JPEG_PLN1_RD_OFFSET_ADDR 0x00000048
+#define JPEG_PLN1_RD_OFFSET_BMSK 0x1FFFFFFF
+
+#define JPEG_CMD_ADDR (JPEG_REG_BASE + 0x00000010)
+#define JPEG_CMD_BMSK 0x00000FFF
+#define JPEG_CMD_CLEAR_WRITE_PLN_QUEUES 0x700
+
+#define JPEG_PLN0_WR_PNTR_ADDR (JPEG_REG_BASE + 0x000000cc)
+#define JPEG_PLN0_WR_PNTR_BMSK 0xFFFFFFFF
+
+#define JPEG_PLN1_WR_PNTR_ADDR (JPEG_REG_BASE + 0x000000D0)
+#define JPEG_PLN1_WR_PNTR_BMSK 0xFFFFFFFF
+
+#define JPEG_IRQ_MASK_ADDR (JPEG_REG_BASE + 0x00000018)
+#define JPEG_IRQ_MASK_BMSK 0xFFFFFFFF
+#define JPEG_IRQ_ALLSOURCES_ENABLE 0xFFFFFFFF
+
+#define JPEG_IRQ_CLEAR_ADDR (JPEG_REG_BASE + 0x0000001c)
+#define JPEG_IRQ_CLEAR_BMSK 0xFFFFFFFF
+
+#define JPEG_RESET_CMD_ADDR (JPEG_REG_BASE + 0x00000008)
+#define JPEG_RESET_CMD_RMSK 0xFFFFFFFF
+
+#define JPEG_IRQ_STATUS_ADDR (JPEG_REG_BASE + 0x00000020)
+#define JPEG_IRQ_STATUS_BMSK 0xFFFFFFFF
+
+#define JPEG_ENCODE_OUTPUT_SIZE_STATUS_ADDR (JPEG_REG_BASE + 0x00000180)
+#define JPEG_ENCODE_OUTPUT_SIZE_STATUS_BMSK 0x1FFFFFFF
+
+
+#define VBIF_BASE_ADDRESS                      0xFDA60000
+#define VBIF_REGION_SIZE                       0xC30
+#define JPEG_VBIF_CLKON                        0x4
+#define JPEG_VBIF_IN_RD_LIM_CONF0              0xB0
+#define JPEG_VBIF_IN_RD_LIM_CONF1              0xB4
+#define JPEG_VBIF_IN_RD_LIM_CONF2              0xB8
+#define JPEG_VBIF_IN_WR_LIM_CONF0              0xC0
+#define JPEG_VBIF_IN_WR_LIM_CONF1              0xC4
+#define JPEG_VBIF_IN_WR_LIM_CONF2              0xC8
+#define JPEG_VBIF_OUT_RD_LIM_CONF0             0xD0
+#define JPEG_VBIF_OUT_WR_LIM_CONF0             0xD4
+#define JPEG_VBIF_DDR_OUT_MAX_BURST            0xD8
+#define JPEG_VBIF_OCMEM_OUT_MAX_BURST          0xDC
+
+#endif /* MSM_JPEG_HW_REG_H */
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_platform.c b/drivers/media/video/msm/jpeg_10/msm_jpeg_platform.c
new file mode 100644
index 0000000..981c56c
--- /dev/null
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_platform.c
@@ -0,0 +1,288 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/pm_qos.h>
+#include <linux/clk.h>
+#include <mach/clk.h>
+#include <linux/io.h>
+#include <linux/android_pmem.h>
+#include <mach/camera.h>
+#include <mach/iommu_domains.h>
+
+#include "msm_jpeg_platform.h"
+#include "msm_jpeg_sync.h"
+#include "msm_jpeg_common.h"
+#include "msm_jpeg_hw.h"
+
+/* AXI rate in KHz */
+struct ion_client *jpeg_client;
+static void *jpeg_vbif;
+
+void msm_jpeg_platform_p2v(struct file  *file,
+				struct ion_handle **ionhandle, int domain_num)
+{
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+	ion_unmap_iommu(jpeg_client, *ionhandle, domain_num, 0);
+	ion_free(jpeg_client, *ionhandle);
+	*ionhandle = NULL;
+#elif CONFIG_ANDROID_PMEM
+	put_pmem_file(file);
+#endif
+}
+
+uint32_t msm_jpeg_platform_v2p(int fd, uint32_t len, struct file **file_p,
+				struct ion_handle **ionhandle, int domain_num)
+{
+	unsigned long paddr;
+	unsigned long size;
+	int rc;
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+	*ionhandle = ion_import_dma_buf(jpeg_client, fd);
+	if (IS_ERR_OR_NULL(*ionhandle))
+		return 0;
+
+	rc = ion_map_iommu(jpeg_client, *ionhandle, domain_num, 0,
+			 SZ_4K, 0, &paddr, (unsigned long *)&size, UNCACHED, 0);
+	JPEG_DBG("%s:%d] addr 0x%x size %ld", __func__, __LINE__,
+							(uint32_t)paddr, size);
+
+#elif CONFIG_ANDROID_PMEM
+	unsigned long kvstart;
+	rc = get_pmem_file(fd, &paddr, &kvstart, &size, file_p);
+#else
+	rc = 0;
+	paddr = 0;
+	size = 0;
+#endif
+	if (rc < 0) {
+		JPEG_PR_ERR("%s: get_pmem_file fd %d error %d\n", __func__, fd,
+			rc);
+		goto error1;
+	}
+
+	/* validate user input */
+	if (len > size) {
+		JPEG_PR_ERR("%s: invalid offset + len\n", __func__);
+		goto error1;
+	}
+
+	return paddr;
+error1:
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+	ion_free(jpeg_client, *ionhandle);
+#endif
+	return 0;
+}
+
+static struct msm_cam_clk_info jpeg_8x_clk_info[] = {
+	{"core_clk", 228570000},
+	{"iface_clk", -1},
+	{"bus_clk0", -1},
+	{"alt_bus_clk", -1},
+	{"camss_top_ahb_clk", -1},
+};
+
+static void set_vbif_params(void *jpeg_vbif_base)
+{
+	writel_relaxed(0x1,
+		jpeg_vbif_base + JPEG_VBIF_CLKON);
+	writel_relaxed(0x10101010,
+		jpeg_vbif_base + JPEG_VBIF_IN_RD_LIM_CONF0);
+	writel_relaxed(0x10101010,
+		jpeg_vbif_base + JPEG_VBIF_IN_RD_LIM_CONF1);
+	writel_relaxed(0x10101010,
+		jpeg_vbif_base + JPEG_VBIF_IN_RD_LIM_CONF2);
+	writel_relaxed(0x10101010,
+		jpeg_vbif_base + JPEG_VBIF_IN_WR_LIM_CONF0);
+	writel_relaxed(0x10101010,
+		jpeg_vbif_base + JPEG_VBIF_IN_WR_LIM_CONF1);
+	writel_relaxed(0x10101010,
+		jpeg_vbif_base + JPEG_VBIF_IN_WR_LIM_CONF2);
+	writel_relaxed(0x00001010,
+		jpeg_vbif_base + JPEG_VBIF_OUT_RD_LIM_CONF0);
+	writel_relaxed(0x00001010,
+		jpeg_vbif_base + JPEG_VBIF_OUT_WR_LIM_CONF0);
+	writel_relaxed(0x00000707,
+		jpeg_vbif_base + JPEG_VBIF_DDR_OUT_MAX_BURST);
+	writel_relaxed(0x00000707,
+		jpeg_vbif_base + JPEG_VBIF_OCMEM_OUT_MAX_BURST);
+}
+
+
+int msm_jpeg_platform_init(struct platform_device *pdev,
+	struct resource **mem,
+	void **base,
+	int *irq,
+	irqreturn_t (*handler) (int, void *),
+	void *context)
+{
+	int rc = -1;
+	int i = 0;
+	int jpeg_irq;
+	struct resource *jpeg_mem, *jpeg_io, *jpeg_irq_res;
+	void *jpeg_base;
+	struct msm_jpeg_device *pgmn_dev =
+		(struct msm_jpeg_device *) context;
+
+	jpeg_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!jpeg_mem) {
+		JPEG_PR_ERR("%s: no mem resource?\n", __func__);
+		return -ENODEV;
+	}
+
+	jpeg_irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!jpeg_irq_res) {
+		JPEG_PR_ERR("no irq resource?\n");
+		return -ENODEV;
+	}
+	jpeg_irq = jpeg_irq_res->start;
+	JPEG_DBG("%s base address: 0x%x, jpeg irq number: %d\n", __func__,
+						jpeg_mem->start, jpeg_irq);
+
+	jpeg_io = request_mem_region(jpeg_mem->start,
+					resource_size(jpeg_mem), pdev->name);
+	if (!jpeg_io) {
+		JPEG_PR_ERR("%s: region already claimed\n", __func__);
+		return -EBUSY;
+	}
+
+	jpeg_base = ioremap(jpeg_mem->start, resource_size(jpeg_mem));
+	if (!jpeg_base) {
+		rc = -ENOMEM;
+		JPEG_PR_ERR("%s: ioremap failed\n", __func__);
+		goto fail1;
+	}
+
+	jpeg_vbif = ioremap(VBIF_BASE_ADDRESS, VBIF_REGION_SIZE);
+	if (!jpeg_vbif) {
+		rc = -ENOMEM;
+		JPEG_PR_ERR("%s:%d] ioremap failed\n", __func__, __LINE__);
+		goto fail1;
+	}
+	JPEG_DBG("%s:%d] jpeg_vbif 0x%x", __func__, __LINE__,
+						(uint32_t)jpeg_vbif);
+
+	pgmn_dev->jpeg_fs = regulator_get(&pgmn_dev->pdev->dev, "vdd");
+	rc = regulator_enable(pgmn_dev->jpeg_fs);
+	if (rc) {
+		JPEG_PR_ERR("%s:%d]jpeg regulator get failed\n",
+				__func__, __LINE__); }
+
+	pgmn_dev->hw_version = JPEG_8974;
+	rc = msm_cam_clk_enable(&pgmn_dev->pdev->dev, jpeg_8x_clk_info,
+	 pgmn_dev->jpeg_clk, ARRAY_SIZE(jpeg_8x_clk_info), 1);
+	if (rc < 0) {
+		JPEG_PR_ERR("%s: clk failed rc = %d\n", __func__, rc);
+		goto fail2;
+	}
+
+#ifdef CONFIG_MSM_IOMMU
+	for (i = 0; i < pgmn_dev->iommu_cnt; i++) {
+		rc = iommu_attach_device(pgmn_dev->domain,
+				pgmn_dev->iommu_ctx_arr[i]);
+		if (rc < 0) {
+			rc = -ENODEV;
+			JPEG_PR_ERR("%s: Device attach failed\n", __func__);
+			goto fail;
+		}
+		JPEG_DBG("%s:%d] dom 0x%x ctx 0x%x", __func__, __LINE__,
+					(uint32_t)pgmn_dev->domain,
+					(uint32_t)pgmn_dev->iommu_ctx_arr[i]);
+	}
+#endif
+	set_vbif_params(jpeg_vbif);
+
+	msm_jpeg_hw_init(jpeg_base, resource_size(jpeg_mem));
+	rc = request_irq(jpeg_irq, handler, IRQF_TRIGGER_RISING, "jpeg",
+		context);
+	if (rc) {
+		JPEG_PR_ERR("%s: request_irq failed, %d\n", __func__,
+			jpeg_irq);
+		goto fail3;
+	}
+
+	*mem  = jpeg_mem;
+	*base = jpeg_base;
+	*irq  = jpeg_irq;
+
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+	jpeg_client = msm_ion_client_create(-1, "camera/jpeg");
+#endif
+	JPEG_DBG("%s:%d] success\n", __func__, __LINE__);
+
+	return rc;
+
+fail3:
+	msm_cam_clk_enable(&pgmn_dev->pdev->dev, jpeg_8x_clk_info,
+	pgmn_dev->jpeg_clk, ARRAY_SIZE(jpeg_8x_clk_info), 0);
+
+	regulator_put(pgmn_dev->jpeg_fs);
+	regulator_disable(pgmn_dev->jpeg_fs);
+	pgmn_dev->jpeg_fs = NULL;
+fail2:
+	iounmap(jpeg_base);
+fail1:
+#ifdef CONFIG_MSM_IOMMU
+	for (i = 0; i < pgmn_dev->iommu_cnt; i++) {
+		JPEG_PR_ERR("%s:%d] dom 0x%x ctx 0x%x", __func__, __LINE__,
+					(uint32_t)pgmn_dev->domain,
+					(uint32_t)pgmn_dev->iommu_ctx_arr[i]);
+		iommu_detach_device(pgmn_dev->domain,
+					pgmn_dev->iommu_ctx_arr[i]);
+	}
+#endif
+fail:
+	release_mem_region(jpeg_mem->start, resource_size(jpeg_mem));
+	JPEG_DBG("%s:%d] fail\n", __func__, __LINE__);
+	return rc;
+}
+
+int msm_jpeg_platform_release(struct resource *mem, void *base, int irq,
+	void *context)
+{
+	int result = 0;
+	int i = 0;
+	struct msm_jpeg_device *pgmn_dev =
+		(struct msm_jpeg_device *) context;
+
+	free_irq(irq, context);
+
+#ifdef CONFIG_MSM_IOMMU
+	for (i = 0; i < pgmn_dev->iommu_cnt; i++) {
+		iommu_detach_device(pgmn_dev->domain,
+				pgmn_dev->iommu_ctx_arr[i]);
+		JPEG_DBG("%s:%d]", __func__, __LINE__);
+	}
+#endif
+
+	msm_cam_clk_enable(&pgmn_dev->pdev->dev, jpeg_8x_clk_info,
+	pgmn_dev->jpeg_clk, ARRAY_SIZE(jpeg_8x_clk_info), 0);
+	JPEG_DBG("%s:%d] clock disbale done", __func__, __LINE__);
+
+	if (pgmn_dev->jpeg_fs) {
+		regulator_put(pgmn_dev->jpeg_fs);
+		regulator_disable(pgmn_dev->jpeg_fs);
+		pgmn_dev->jpeg_fs = NULL;
+	}
+	iounmap(jpeg_vbif);
+	iounmap(base);
+	release_mem_region(mem->start, resource_size(mem));
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+	ion_client_destroy(jpeg_client);
+#endif
+	JPEG_DBG("%s:%d] success\n", __func__, __LINE__);
+	return result;
+}
+
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_platform.h b/drivers/media/video/msm/jpeg_10/msm_jpeg_platform.h
new file mode 100644
index 0000000..8a37cef
--- /dev/null
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_platform.h
@@ -0,0 +1,40 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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_JPEG_PLATFORM_H
+#define MSM_JPEG_PLATFORM_H
+
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/ion.h>
+#include <linux/iommu.h>
+#include <mach/iommu.h>
+
+
+void msm_jpeg_platform_p2v(struct file  *file,
+				struct ion_handle **ionhandle, int domain_num);
+uint32_t msm_jpeg_platform_v2p(int fd, uint32_t len, struct file **file,
+				struct ion_handle **ionhandle, int domain_num);
+
+int msm_jpeg_platform_clk_enable(void);
+int msm_jpeg_platform_clk_disable(void);
+
+int msm_jpeg_platform_init(struct platform_device *pdev,
+	struct resource **mem,
+	void **base,
+	int *irq,
+	irqreturn_t (*handler) (int, void *),
+	void *context);
+int msm_jpeg_platform_release(struct resource *mem, void *base, int irq,
+	void *context);
+
+#endif /* MSM_JPEG_PLATFORM_H */
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_sync.c b/drivers/media/video/msm/jpeg_10/msm_jpeg_sync.c
new file mode 100644
index 0000000..6ac4a5e
--- /dev/null
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_sync.c
@@ -0,0 +1,897 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/sched.h>
+#include <linux/list.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <media/msm_jpeg.h>
+#include "msm_jpeg_sync.h"
+#include "msm_jpeg_core.h"
+#include "msm_jpeg_platform.h"
+#include "msm_jpeg_common.h"
+
+static int release_buf;
+
+inline void msm_jpeg_q_init(char const *name, struct msm_jpeg_q *q_p)
+{
+	JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, name);
+	q_p->name = name;
+	spin_lock_init(&q_p->lck);
+	INIT_LIST_HEAD(&q_p->q);
+	init_waitqueue_head(&q_p->wait);
+	q_p->unblck = 0;
+}
+
+inline void *msm_jpeg_q_out(struct msm_jpeg_q *q_p)
+{
+	unsigned long flags;
+	struct msm_jpeg_q_entry *q_entry_p = NULL;
+	void *data = NULL;
+
+	JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+	spin_lock_irqsave(&q_p->lck, flags);
+	if (!list_empty(&q_p->q)) {
+		q_entry_p = list_first_entry(&q_p->q, struct msm_jpeg_q_entry,
+			list);
+		list_del_init(&q_entry_p->list);
+	}
+	spin_unlock_irqrestore(&q_p->lck, flags);
+
+	if (q_entry_p) {
+		data = q_entry_p->data;
+		kfree(q_entry_p);
+	} else {
+		JPEG_DBG("%s:%d] %s no entry\n", __func__, __LINE__,
+			q_p->name);
+	}
+
+	return data;
+}
+
+inline int msm_jpeg_q_in(struct msm_jpeg_q *q_p, void *data)
+{
+	unsigned long flags;
+
+	struct msm_jpeg_q_entry *q_entry_p;
+
+	JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+
+	q_entry_p = kmalloc(sizeof(struct msm_jpeg_q_entry), GFP_ATOMIC);
+	if (!q_entry_p) {
+		JPEG_PR_ERR("%s: no mem\n", __func__);
+		return -EFAULT;
+	}
+	q_entry_p->data = data;
+
+	spin_lock_irqsave(&q_p->lck, flags);
+	list_add_tail(&q_entry_p->list, &q_p->q);
+	spin_unlock_irqrestore(&q_p->lck, flags);
+
+	return 0;
+}
+
+inline int msm_jpeg_q_in_buf(struct msm_jpeg_q *q_p,
+	struct msm_jpeg_core_buf *buf)
+{
+	struct msm_jpeg_core_buf *buf_p;
+
+	JPEG_DBG("%s:%d]\n", __func__, __LINE__);
+	buf_p = kmalloc(sizeof(struct msm_jpeg_core_buf), GFP_ATOMIC);
+	if (!buf_p) {
+		JPEG_PR_ERR("%s: no mem\n", __func__);
+		return -EFAULT;
+	}
+
+	memcpy(buf_p, buf, sizeof(struct msm_jpeg_core_buf));
+
+	msm_jpeg_q_in(q_p, buf_p);
+	return 0;
+}
+
+inline int msm_jpeg_q_wait(struct msm_jpeg_q *q_p)
+{
+	int tm = MAX_SCHEDULE_TIMEOUT; /* 500ms */
+	int rc;
+
+	JPEG_DBG("%s:%d] %s wait\n", __func__, __LINE__, q_p->name);
+	rc = wait_event_interruptible_timeout(q_p->wait,
+		(!list_empty_careful(&q_p->q) || q_p->unblck),
+		msecs_to_jiffies(tm));
+	JPEG_DBG("%s:%d] %s wait done\n", __func__, __LINE__, q_p->name);
+	if (list_empty_careful(&q_p->q)) {
+		if (rc == 0) {
+			rc = -ETIMEDOUT;
+			JPEG_PR_ERR("%s:%d] %s timeout\n", __func__, __LINE__,
+				q_p->name);
+		} else if (q_p->unblck) {
+			JPEG_DBG("%s:%d] %s unblock is true\n", __func__,
+				__LINE__, q_p->name);
+			q_p->unblck = 0;
+			rc = -ECANCELED;
+		} else if (rc < 0) {
+			JPEG_PR_ERR("%s:%d] %s rc %d\n", __func__, __LINE__,
+				q_p->name, rc);
+		}
+	}
+	return rc;
+}
+
+inline int msm_jpeg_q_wakeup(struct msm_jpeg_q *q_p)
+{
+	JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+	wake_up(&q_p->wait);
+	return 0;
+}
+
+inline int msm_jpeg_q_unblock(struct msm_jpeg_q *q_p)
+{
+	JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+	q_p->unblck = 1;
+	wake_up(&q_p->wait);
+	return 0;
+}
+
+inline void msm_jpeg_outbuf_q_cleanup(struct msm_jpeg_q *q_p,
+				int domain_num)
+{
+	struct msm_jpeg_core_buf *buf_p;
+	JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+	do {
+		buf_p = msm_jpeg_q_out(q_p);
+		if (buf_p) {
+			msm_jpeg_platform_p2v(buf_p->file,
+				&buf_p->handle, domain_num);
+			JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+			kfree(buf_p);
+		}
+	} while (buf_p);
+	q_p->unblck = 0;
+}
+
+inline void msm_jpeg_q_cleanup(struct msm_jpeg_q *q_p)
+{
+	void *data;
+	JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+	do {
+		data = msm_jpeg_q_out(q_p);
+		if (data) {
+			JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+			kfree(data);
+		}
+	} while (data);
+	q_p->unblck = 0;
+}
+
+/*************** event queue ****************/
+
+int msm_jpeg_framedone_irq(struct msm_jpeg_device *pgmn_dev,
+	struct msm_jpeg_core_buf *buf_in)
+{
+	int rc = 0;
+
+	JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+
+	if (buf_in) {
+		buf_in->vbuf.framedone_len = buf_in->framedone_len;
+		buf_in->vbuf.type = MSM_JPEG_EVT_SESSION_DONE;
+		JPEG_DBG("%s:%d] 0x%08x %d framedone_len %d\n",
+			__func__, __LINE__,
+			(int) buf_in->y_buffer_addr, buf_in->y_len,
+			buf_in->vbuf.framedone_len);
+		rc = msm_jpeg_q_in_buf(&pgmn_dev->evt_q, buf_in);
+	} else {
+		JPEG_PR_ERR("%s:%d] no output return buffer\n",
+			__func__, __LINE__);
+		rc = -1;
+	}
+
+	if (buf_in)
+		rc = msm_jpeg_q_wakeup(&pgmn_dev->evt_q);
+
+	return rc;
+}
+
+int msm_jpeg_evt_get(struct msm_jpeg_device *pgmn_dev,
+	void __user *to)
+{
+	struct msm_jpeg_core_buf *buf_p;
+	struct msm_jpeg_ctrl_cmd ctrl_cmd;
+
+	JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+
+	msm_jpeg_q_wait(&pgmn_dev->evt_q);
+	buf_p = msm_jpeg_q_out(&pgmn_dev->evt_q);
+
+	if (!buf_p) {
+		JPEG_DBG("%s:%d] no buffer\n", __func__, __LINE__);
+		return -EAGAIN;
+	}
+
+	ctrl_cmd.type = buf_p->vbuf.type;
+	kfree(buf_p);
+
+	JPEG_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
+		(int) ctrl_cmd.value, ctrl_cmd.len);
+
+	if (copy_to_user(to, &ctrl_cmd, sizeof(ctrl_cmd))) {
+		JPEG_PR_ERR("%s:%d]\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+int msm_jpeg_evt_get_unblock(struct msm_jpeg_device *pgmn_dev)
+{
+	JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+	msm_jpeg_q_unblock(&pgmn_dev->evt_q);
+	return 0;
+}
+
+void msm_jpeg_reset_ack_irq(struct msm_jpeg_device *pgmn_dev)
+{
+	JPEG_DBG("%s:%d]\n", __func__, __LINE__);
+}
+
+void msm_jpeg_err_irq(struct msm_jpeg_device *pgmn_dev,
+	int event)
+{
+	int rc = 0;
+	struct msm_jpeg_core_buf buf;
+
+	JPEG_PR_ERR("%s:%d] error: %d\n", __func__, __LINE__, event);
+
+	buf.vbuf.type = MSM_JPEG_EVT_ERR;
+	rc = msm_jpeg_q_in_buf(&pgmn_dev->evt_q, &buf);
+	if (!rc)
+		rc = msm_jpeg_q_wakeup(&pgmn_dev->evt_q);
+
+	if (!rc)
+		JPEG_PR_ERR("%s:%d] err err\n", __func__, __LINE__);
+
+	return;
+}
+
+/*************** output queue ****************/
+
+int msm_jpeg_we_pingpong_irq(struct msm_jpeg_device *pgmn_dev,
+	struct msm_jpeg_core_buf *buf_in)
+{
+	int rc = 0;
+	struct msm_jpeg_core_buf *buf_out;
+
+	JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+	if (buf_in) {
+		JPEG_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
+			(int) buf_in->y_buffer_addr, buf_in->y_len);
+		rc = msm_jpeg_q_in_buf(&pgmn_dev->output_rtn_q, buf_in);
+	} else {
+		JPEG_DBG("%s:%d] no output return buffer\n", __func__,
+			__LINE__);
+		rc = -1;
+		return rc;
+	}
+
+	buf_out = msm_jpeg_q_out(&pgmn_dev->output_buf_q);
+
+	if (buf_out) {
+		JPEG_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
+			(int) buf_out->y_buffer_addr, buf_out->y_len);
+		rc = msm_jpeg_core_we_buf_update(buf_out);
+		kfree(buf_out);
+	} else {
+		msm_jpeg_core_we_buf_reset(buf_in);
+		JPEG_DBG("%s:%d] no output buffer\n", __func__, __LINE__);
+		rc = -2;
+	}
+
+	if (buf_in)
+		rc = msm_jpeg_q_wakeup(&pgmn_dev->output_rtn_q);
+
+	return rc;
+}
+
+int msm_jpeg_output_get(struct msm_jpeg_device *pgmn_dev, void __user *to)
+{
+	struct msm_jpeg_core_buf *buf_p;
+	struct msm_jpeg_buf buf_cmd;
+
+	JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+
+	msm_jpeg_q_wait(&pgmn_dev->output_rtn_q);
+	buf_p = msm_jpeg_q_out(&pgmn_dev->output_rtn_q);
+
+	if (!buf_p) {
+		JPEG_DBG("%s:%d] no output buffer return\n",
+			__func__, __LINE__);
+		return -EAGAIN;
+	}
+
+	buf_cmd = buf_p->vbuf;
+	msm_jpeg_platform_p2v(buf_p->file, &buf_p->handle,
+		pgmn_dev->domain_num);
+	kfree(buf_p);
+
+	JPEG_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
+		(int) buf_cmd.vaddr, buf_cmd.y_len);
+
+	if (copy_to_user(to, &buf_cmd, sizeof(buf_cmd))) {
+		JPEG_PR_ERR("%s:%d]", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+int msm_jpeg_output_get_unblock(struct msm_jpeg_device *pgmn_dev)
+{
+	JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+	msm_jpeg_q_unblock(&pgmn_dev->output_rtn_q);
+	return 0;
+}
+
+int msm_jpeg_output_buf_enqueue(struct msm_jpeg_device *pgmn_dev,
+	void __user *arg)
+{
+	struct msm_jpeg_buf buf_cmd;
+	struct msm_jpeg_core_buf *buf_p;
+
+	JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+	if (copy_from_user(&buf_cmd, arg, sizeof(struct msm_jpeg_buf))) {
+		JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	buf_p = kmalloc(sizeof(struct msm_jpeg_core_buf), GFP_ATOMIC);
+	if (!buf_p) {
+		JPEG_PR_ERR("%s:%d] no mem\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	JPEG_DBG("%s:%d] vaddr = 0x%08x y_len = %d\n, fd = %d",
+		__func__, __LINE__, (int) buf_cmd.vaddr, buf_cmd.y_len,
+		buf_cmd.fd);
+
+	buf_p->y_buffer_addr = msm_jpeg_platform_v2p(buf_cmd.fd,
+		buf_cmd.y_len, &buf_p->file, &buf_p->handle,
+		pgmn_dev->domain_num);
+	if (!buf_p->y_buffer_addr) {
+		JPEG_PR_ERR("%s:%d] v2p wrong\n", __func__, __LINE__);
+		kfree(buf_p);
+		return -EFAULT;
+	}
+	JPEG_DBG("%s:%d]After v2p y_address =0x%08x, handle = %p\n",
+		__func__, __LINE__, buf_p->y_buffer_addr, buf_p->handle);
+	buf_p->y_len = buf_cmd.y_len;
+	buf_p->vbuf = buf_cmd;
+
+	msm_jpeg_q_in(&pgmn_dev->output_buf_q, buf_p);
+	return 0;
+}
+
+/*************** input queue ****************/
+
+int msm_jpeg_fe_pingpong_irq(struct msm_jpeg_device *pgmn_dev,
+	struct msm_jpeg_core_buf *buf_in)
+{
+	struct msm_jpeg_core_buf *buf_out;
+	int rc = 0;
+
+	JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+	if (buf_in) {
+		JPEG_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
+			(int) buf_in->y_buffer_addr, buf_in->y_len);
+		rc = msm_jpeg_q_in_buf(&pgmn_dev->input_rtn_q, buf_in);
+	} else {
+		JPEG_DBG("%s:%d] no input return buffer\n", __func__,
+			__LINE__);
+		rc = -EFAULT;
+	}
+
+	buf_out = msm_jpeg_q_out(&pgmn_dev->input_buf_q);
+
+	if (buf_out) {
+		rc = msm_jpeg_core_fe_buf_update(buf_out);
+		kfree(buf_out);
+		msm_jpeg_core_fe_start();
+	} else {
+		JPEG_DBG("%s:%d] no input buffer\n", __func__, __LINE__);
+		rc = -EFAULT;
+	}
+
+	if (buf_in)
+		rc = msm_jpeg_q_wakeup(&pgmn_dev->input_rtn_q);
+
+	return rc;
+}
+
+int msm_jpeg_input_get(struct msm_jpeg_device *pgmn_dev, void __user *to)
+{
+	struct msm_jpeg_core_buf *buf_p;
+	struct msm_jpeg_buf buf_cmd;
+
+	JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+	msm_jpeg_q_wait(&pgmn_dev->input_rtn_q);
+	buf_p = msm_jpeg_q_out(&pgmn_dev->input_rtn_q);
+
+	if (!buf_p) {
+		JPEG_DBG("%s:%d] no input buffer return\n",
+			__func__, __LINE__);
+		return -EAGAIN;
+	}
+
+	buf_cmd = buf_p->vbuf;
+	msm_jpeg_platform_p2v(buf_p->file, &buf_p->handle,
+					pgmn_dev->domain_num);
+	kfree(buf_p);
+
+	JPEG_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
+		(int) buf_cmd.vaddr, buf_cmd.y_len);
+
+	if (copy_to_user(to, &buf_cmd, sizeof(buf_cmd))) {
+		JPEG_PR_ERR("%s:%d]\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+int msm_jpeg_input_get_unblock(struct msm_jpeg_device *pgmn_dev)
+{
+	JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+	msm_jpeg_q_unblock(&pgmn_dev->input_rtn_q);
+	return 0;
+}
+
+int msm_jpeg_input_buf_enqueue(struct msm_jpeg_device *pgmn_dev,
+	void __user *arg)
+{
+	struct msm_jpeg_core_buf *buf_p;
+	struct msm_jpeg_buf buf_cmd;
+
+	if (copy_from_user(&buf_cmd, arg, sizeof(struct msm_jpeg_buf))) {
+		JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	buf_p = kmalloc(sizeof(struct msm_jpeg_core_buf), GFP_ATOMIC);
+	if (!buf_p) {
+		JPEG_PR_ERR("%s:%d] no mem\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	JPEG_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
+		(int) buf_cmd.vaddr, buf_cmd.y_len);
+
+	buf_p->y_buffer_addr    = msm_jpeg_platform_v2p(buf_cmd.fd,
+		buf_cmd.y_len + buf_cmd.cbcr_len, &buf_p->file,
+		&buf_p->handle, pgmn_dev->domain_num) + buf_cmd.offset
+		+ buf_cmd.y_off;
+	buf_p->y_len          = buf_cmd.y_len;
+	buf_p->cbcr_buffer_addr = buf_p->y_buffer_addr + buf_cmd.y_len
+						+ buf_cmd.cbcr_off;
+	buf_p->cbcr_len       = buf_cmd.cbcr_len;
+	buf_p->num_of_mcu_rows = buf_cmd.num_of_mcu_rows;
+	JPEG_DBG("%s: y_addr=%x, y_len=%x, cbcr_addr=%x, cbcr_len=%x, fd =%d\n",
+		__func__, buf_p->y_buffer_addr, buf_p->y_len,
+		buf_p->cbcr_buffer_addr, buf_p->cbcr_len, buf_cmd.fd);
+
+	if (!buf_p->y_buffer_addr || !buf_p->cbcr_buffer_addr) {
+		JPEG_PR_ERR("%s:%d] v2p wrong\n", __func__, __LINE__);
+		kfree(buf_p);
+		return -EFAULT;
+	}
+	buf_p->vbuf           = buf_cmd;
+
+	msm_jpeg_q_in(&pgmn_dev->input_buf_q, buf_p);
+
+	return 0;
+}
+
+int msm_jpeg_irq(int event, void *context, void *data)
+{
+	struct msm_jpeg_device *pgmn_dev =
+		(struct msm_jpeg_device *) context;
+
+	switch (event) {
+	case MSM_JPEG_EVT_SESSION_DONE:
+		msm_jpeg_framedone_irq(pgmn_dev, data);
+		msm_jpeg_we_pingpong_irq(pgmn_dev, data);
+		break;
+
+	case MSM_JPEG_HW_MASK_COMP_FE:
+		msm_jpeg_fe_pingpong_irq(pgmn_dev, data);
+		break;
+
+	case MSM_JPEG_HW_MASK_COMP_WE:
+		msm_jpeg_we_pingpong_irq(pgmn_dev, data);
+		break;
+
+	case MSM_JPEG_HW_MASK_COMP_RESET_ACK:
+		msm_jpeg_reset_ack_irq(pgmn_dev);
+		break;
+
+	case MSM_JPEG_HW_MASK_COMP_ERR:
+	default:
+		msm_jpeg_err_irq(pgmn_dev, event);
+		break;
+	}
+
+	return 0;
+}
+
+int __msm_jpeg_open(struct msm_jpeg_device *pgmn_dev)
+{
+	int rc;
+
+	mutex_lock(&pgmn_dev->lock);
+	if (pgmn_dev->open_count) {
+		/* only open once */
+		JPEG_PR_ERR("%s:%d] busy\n", __func__, __LINE__);
+		mutex_unlock(&pgmn_dev->lock);
+		return -EBUSY;
+	}
+	pgmn_dev->open_count++;
+	mutex_unlock(&pgmn_dev->lock);
+
+	msm_jpeg_core_irq_install(msm_jpeg_irq);
+	rc = msm_jpeg_platform_init(pgmn_dev->pdev,
+		&pgmn_dev->mem, &pgmn_dev->base,
+		&pgmn_dev->irq, msm_jpeg_core_irq, pgmn_dev);
+	if (rc) {
+		JPEG_PR_ERR("%s:%d] platform_init fail %d\n", __func__,
+			__LINE__, rc);
+		return rc;
+	}
+
+	JPEG_DBG("%s:%d] platform resources - mem %p, base %p, irq %d\n",
+		__func__, __LINE__,
+		pgmn_dev->mem, pgmn_dev->base, pgmn_dev->irq);
+
+	msm_jpeg_q_cleanup(&pgmn_dev->evt_q);
+	msm_jpeg_q_cleanup(&pgmn_dev->output_rtn_q);
+	msm_jpeg_outbuf_q_cleanup(&pgmn_dev->output_buf_q,
+	pgmn_dev->domain_num); msm_jpeg_q_cleanup(&pgmn_dev->input_rtn_q);
+	msm_jpeg_q_cleanup(&pgmn_dev->input_buf_q);
+	msm_jpeg_core_init();
+
+	JPEG_DBG("%s:%d] success\n", __func__, __LINE__);
+	return rc;
+}
+
+int __msm_jpeg_release(struct msm_jpeg_device *pgmn_dev)
+{
+	JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+	mutex_lock(&pgmn_dev->lock);
+	if (!pgmn_dev->open_count) {
+		JPEG_PR_ERR(KERN_ERR "%s: not opened\n", __func__);
+		mutex_unlock(&pgmn_dev->lock);
+		return -EINVAL;
+	}
+	pgmn_dev->open_count--;
+	mutex_unlock(&pgmn_dev->lock);
+
+	msm_jpeg_core_release(release_buf, pgmn_dev->domain_num);
+	msm_jpeg_q_cleanup(&pgmn_dev->evt_q);
+	msm_jpeg_q_cleanup(&pgmn_dev->output_rtn_q);
+	msm_jpeg_outbuf_q_cleanup(&pgmn_dev->output_buf_q,
+					pgmn_dev->domain_num);
+	msm_jpeg_q_cleanup(&pgmn_dev->input_rtn_q);
+	msm_jpeg_outbuf_q_cleanup(&pgmn_dev->input_buf_q, pgmn_dev->domain_num);
+
+	JPEG_DBG("%s:%d]\n", __func__, __LINE__);
+	if (pgmn_dev->open_count)
+		JPEG_PR_ERR(KERN_ERR "%s: multiple opens\n", __func__);
+
+	msm_jpeg_platform_release(pgmn_dev->mem, pgmn_dev->base,
+		pgmn_dev->irq, pgmn_dev);
+
+	return 0;
+}
+
+int msm_jpeg_ioctl_hw_cmd(struct msm_jpeg_device *pgmn_dev,
+	void * __user arg)
+{
+	struct msm_jpeg_hw_cmd hw_cmd;
+	int is_copy_to_user;
+
+	if (copy_from_user(&hw_cmd, arg, sizeof(struct msm_jpeg_hw_cmd))) {
+		JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	is_copy_to_user = msm_jpeg_hw_exec_cmds(&hw_cmd, 1);
+	JPEG_DBG("%s:%d] type %d, n %d, offset %d, mask %x, data %x,pdata %x\n",
+		__func__, __LINE__, hw_cmd.type, hw_cmd.n, hw_cmd.offset,
+		hw_cmd.mask, hw_cmd.data, (int) hw_cmd.pdata);
+
+	if (is_copy_to_user >= 0) {
+		if (copy_to_user(arg, &hw_cmd, sizeof(hw_cmd))) {
+			JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+			return -EFAULT;
+		}
+	}
+
+	return 0;
+}
+
+int msm_jpeg_ioctl_hw_cmds(struct msm_jpeg_device *pgmn_dev,
+	void * __user arg)
+{
+	int is_copy_to_user;
+	int len;
+	uint32_t m;
+	struct msm_jpeg_hw_cmds *hw_cmds_p;
+	struct msm_jpeg_hw_cmd *hw_cmd_p;
+
+	if (copy_from_user(&m, arg, sizeof(m))) {
+		JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	len = sizeof(struct msm_jpeg_hw_cmds) +
+		sizeof(struct msm_jpeg_hw_cmd) * (m - 1);
+	hw_cmds_p = kmalloc(len, GFP_KERNEL);
+	if (!hw_cmds_p) {
+		JPEG_PR_ERR("%s:%d] no mem %d\n", __func__, __LINE__, len);
+		return -EFAULT;
+	}
+
+	if (copy_from_user(hw_cmds_p, arg, len)) {
+		JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+		kfree(hw_cmds_p);
+		return -EFAULT;
+	}
+
+	hw_cmd_p = (struct msm_jpeg_hw_cmd *) &(hw_cmds_p->hw_cmd);
+
+	is_copy_to_user = msm_jpeg_hw_exec_cmds(hw_cmd_p, m);
+
+	if (is_copy_to_user >= 0) {
+		if (copy_to_user(arg, hw_cmds_p, len)) {
+			JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+			kfree(hw_cmds_p);
+			return -EFAULT;
+		}
+	}
+	kfree(hw_cmds_p);
+	return 0;
+}
+
+int msm_jpeg_start(struct msm_jpeg_device *pgmn_dev, void * __user arg)
+{
+	struct msm_jpeg_core_buf *buf_out;
+	struct msm_jpeg_core_buf *buf_out_free[2] = {NULL, NULL};
+	int i, rc;
+
+	JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+
+	release_buf = 1;
+	for (i = 0; i < 2; i++) {
+		buf_out = msm_jpeg_q_out(&pgmn_dev->input_buf_q);
+
+		if (buf_out) {
+			msm_jpeg_core_fe_buf_update(buf_out);
+			kfree(buf_out);
+		} else {
+			JPEG_DBG("%s:%d] no input buffer\n", __func__,
+					__LINE__);
+			break;
+		}
+	}
+
+	for (i = 0; i < 2; i++) {
+		buf_out_free[i] = msm_jpeg_q_out(&pgmn_dev->output_buf_q);
+
+		if (buf_out_free[i]) {
+			msm_jpeg_core_we_buf_update(buf_out_free[i]);
+			release_buf = 0;
+		} else {
+			JPEG_DBG("%s:%d] no output buffer\n",
+			__func__, __LINE__);
+			break;
+		}
+	}
+
+	for (i = 0; i < 2; i++)
+		kfree(buf_out_free[i]);
+
+	rc = msm_jpeg_ioctl_hw_cmds(pgmn_dev, arg);
+	JPEG_DBG("%s:%d]\n", __func__, __LINE__);
+	return rc;
+}
+
+int msm_jpeg_ioctl_reset(struct msm_jpeg_device *pgmn_dev,
+	void * __user arg)
+{
+	int rc;
+	struct msm_jpeg_ctrl_cmd ctrl_cmd;
+
+	JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+	if (copy_from_user(&ctrl_cmd, arg, sizeof(ctrl_cmd))) {
+		JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	pgmn_dev->op_mode = ctrl_cmd.type;
+
+	rc = msm_jpeg_core_reset(pgmn_dev->op_mode, pgmn_dev->base,
+		resource_size(pgmn_dev->mem));
+	return rc;
+}
+
+int msm_jpeg_ioctl_test_dump_region(struct msm_jpeg_device *pgmn_dev,
+	unsigned long arg)
+{
+	JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+	msm_jpeg_io_dump(arg);
+	return 0;
+}
+
+long __msm_jpeg_ioctl(struct msm_jpeg_device *pgmn_dev,
+	unsigned int cmd, unsigned long arg)
+{
+	int rc = 0;
+	switch (cmd) {
+	case MSM_JPEG_IOCTL_GET_HW_VERSION:
+		JPEG_DBG("%s:%d] VERSION 1\n", __func__, __LINE__);
+		rc = msm_jpeg_ioctl_hw_cmd(pgmn_dev, (void __user *) arg);
+		break;
+
+	case MSM_JPEG_IOCTL_RESET:
+		rc = msm_jpeg_ioctl_reset(pgmn_dev, (void __user *) arg);
+		break;
+
+	case MSM_JPEG_IOCTL_STOP:
+		rc = msm_jpeg_ioctl_hw_cmds(pgmn_dev, (void __user *) arg);
+		break;
+
+	case MSM_JPEG_IOCTL_START:
+		rc = msm_jpeg_start(pgmn_dev, (void __user *) arg);
+		break;
+
+	case MSM_JPEG_IOCTL_INPUT_BUF_ENQUEUE:
+		rc = msm_jpeg_input_buf_enqueue(pgmn_dev,
+			(void __user *) arg);
+		break;
+
+	case MSM_JPEG_IOCTL_INPUT_GET:
+		rc = msm_jpeg_input_get(pgmn_dev, (void __user *) arg);
+		break;
+
+	case MSM_JPEG_IOCTL_INPUT_GET_UNBLOCK:
+		rc = msm_jpeg_input_get_unblock(pgmn_dev);
+		break;
+
+	case MSM_JPEG_IOCTL_OUTPUT_BUF_ENQUEUE:
+		rc = msm_jpeg_output_buf_enqueue(pgmn_dev,
+			(void __user *) arg);
+		break;
+
+	case MSM_JPEG_IOCTL_OUTPUT_GET:
+		rc = msm_jpeg_output_get(pgmn_dev, (void __user *) arg);
+		break;
+
+	case MSM_JPEG_IOCTL_OUTPUT_GET_UNBLOCK:
+		rc = msm_jpeg_output_get_unblock(pgmn_dev);
+		break;
+
+	case MSM_JPEG_IOCTL_EVT_GET:
+		rc = msm_jpeg_evt_get(pgmn_dev, (void __user *) arg);
+		break;
+
+	case MSM_JPEG_IOCTL_EVT_GET_UNBLOCK:
+		rc = msm_jpeg_evt_get_unblock(pgmn_dev);
+		break;
+
+	case MSM_JPEG_IOCTL_HW_CMD:
+		rc = msm_jpeg_ioctl_hw_cmd(pgmn_dev, (void __user *) arg);
+		break;
+
+	case MSM_JPEG_IOCTL_HW_CMDS:
+		rc = msm_jpeg_ioctl_hw_cmds(pgmn_dev, (void __user *) arg);
+		break;
+
+	case MSM_JPEG_IOCTL_TEST_DUMP_REGION:
+		rc = msm_jpeg_ioctl_test_dump_region(pgmn_dev, arg);
+		break;
+
+	default:
+		JPEG_PR_ERR(KERN_INFO "%s:%d] cmd = %d not supported\n",
+			__func__, __LINE__, _IOC_NR(cmd));
+		rc = -EINVAL;
+		break;
+	}
+	return rc;
+}
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+static int camera_register_domain(void)
+{
+	struct msm_iova_partition camera_fw_partition = {
+		.start = SZ_128K,
+		.size = SZ_2G - SZ_128K,
+	};
+
+	struct msm_iova_layout camera_fw_layout = {
+		.partitions = &camera_fw_partition,
+		.npartitions = 1,
+		.client_name = "camera_jpeg",
+		.domain_flags = 0,
+	};
+	return msm_register_domain(&camera_fw_layout);
+}
+#endif
+
+int __msm_jpeg_init(struct msm_jpeg_device *pgmn_dev)
+{
+	int rc = 0, i = 0;
+	int idx = 0;
+	char *iommu_name[3] = {"jpeg_enc0", "jpeg_enc1", "jpeg_dec"};
+
+	mutex_init(&pgmn_dev->lock);
+
+	pr_err("%s:%d] Jpeg Device id %d", __func__, __LINE__,
+		   pgmn_dev->pdev->id);
+	idx = pgmn_dev->pdev->id;
+	pgmn_dev->idx = idx;
+	pgmn_dev->iommu_cnt = 1;
+
+	msm_jpeg_q_init("evt_q", &pgmn_dev->evt_q);
+	msm_jpeg_q_init("output_rtn_q", &pgmn_dev->output_rtn_q);
+	msm_jpeg_q_init("output_buf_q", &pgmn_dev->output_buf_q);
+	msm_jpeg_q_init("input_rtn_q", &pgmn_dev->input_rtn_q);
+	msm_jpeg_q_init("input_buf_q", &pgmn_dev->input_buf_q);
+
+#ifdef CONFIG_MSM_IOMMU
+/*get device context for IOMMU*/
+	for (i = 0; i < pgmn_dev->iommu_cnt; i++) {
+		pgmn_dev->iommu_ctx_arr[i] = msm_iommu_get_ctx(iommu_name[i]);
+		JPEG_DBG("%s:%d] name %s", __func__, __LINE__, iommu_name[i]);
+		JPEG_DBG("%s:%d] ctx 0x%x", __func__, __LINE__,
+					(uint32_t)pgmn_dev->iommu_ctx_arr[i]);
+		if (!pgmn_dev->iommu_ctx_arr[i]) {
+			JPEG_PR_ERR("%s: No iommu fw context found\n",
+					__func__);
+			goto error;
+		}
+	}
+	pgmn_dev->domain_num = camera_register_domain();
+	JPEG_DBG("%s:%d] dom_num 0x%x", __func__, __LINE__,
+				pgmn_dev->domain_num);
+	if (pgmn_dev->domain_num < 0) {
+		JPEG_PR_ERR("%s: could not register domain\n", __func__);
+		goto error;
+	}
+	pgmn_dev->domain = msm_get_iommu_domain(pgmn_dev->domain_num);
+	JPEG_DBG("%s:%d] dom 0x%x", __func__, __LINE__,
+					(uint32_t)pgmn_dev->domain);
+	if (!pgmn_dev->domain) {
+		JPEG_PR_ERR("%s: cannot find domain\n", __func__);
+		goto error;
+	}
+#endif
+
+	return rc;
+error:
+	mutex_destroy(&pgmn_dev->lock);
+	return -EFAULT;
+}
+
+int __msm_jpeg_exit(struct msm_jpeg_device *pgmn_dev)
+{
+	mutex_destroy(&pgmn_dev->lock);
+	kfree(pgmn_dev);
+	return 0;
+}
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_sync.h b/drivers/media/video/msm/jpeg_10/msm_jpeg_sync.h
new file mode 100644
index 0000000..1d82060
--- /dev/null
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_sync.h
@@ -0,0 +1,102 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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_JPEG_SYNC_H
+#define MSM_JPEG_SYNC_H
+
+#include <linux/fs.h>
+#include <linux/list.h>
+#include <linux/cdev.h>
+#include <linux/platform_device.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include "msm_jpeg_core.h"
+
+#define JPEG_7X 0x1
+#define JPEG_8X60 (0x1 << 1)
+#define JPEG_8960 (0x1 << 2)
+#define JPEG_8974 0x1
+
+struct msm_jpeg_q {
+	char const	*name;
+	struct list_head  q;
+	spinlock_t	lck;
+	wait_queue_head_t wait;
+	int	       unblck;
+};
+
+struct msm_jpeg_q_entry {
+	struct list_head list;
+	void   *data;
+};
+
+struct msm_jpeg_device {
+	struct platform_device *pdev;
+	struct resource        *mem;
+	int                     irq;
+	void                   *base;
+	struct clk *jpeg_clk[5];
+	struct regulator *jpeg_fs;
+	uint32_t hw_version;
+
+	struct device *device;
+	struct cdev   cdev;
+	struct mutex  lock;
+	char	  open_count;
+	uint8_t       op_mode;
+
+	/* event queue including frame done & err indications
+	 */
+	struct msm_jpeg_q evt_q;
+
+	/* output return queue
+	 */
+	struct msm_jpeg_q output_rtn_q;
+
+	/* output buf queue
+	 */
+	struct msm_jpeg_q output_buf_q;
+
+	/* input return queue
+	 */
+	struct msm_jpeg_q input_rtn_q;
+
+	/* input buf queue
+	 */
+	struct msm_jpeg_q input_buf_q;
+
+	struct v4l2_subdev subdev;
+
+	struct class *msm_jpeg_class;
+
+	dev_t msm_jpeg_devno;
+
+	/*iommu domain and context*/
+	int domain_num;
+	int idx;
+	struct iommu_domain *domain;
+	struct device *iommu_ctx_arr[3];
+	int iommu_cnt;
+};
+
+int __msm_jpeg_open(struct msm_jpeg_device *pgmn_dev);
+int __msm_jpeg_release(struct msm_jpeg_device *pgmn_dev);
+
+long __msm_jpeg_ioctl(struct msm_jpeg_device *pgmn_dev,
+	unsigned int cmd, unsigned long arg);
+
+int __msm_jpeg_init(struct msm_jpeg_device *pgmn_dev);
+int __msm_jpeg_exit(struct msm_jpeg_device *pgmn_dev);
+
+#endif /* MSM_JPEG_SYNC_H */
diff --git a/drivers/media/video/msm/msm.c b/drivers/media/video/msm/msm.c
index e5c1091..50a9776 100644
--- a/drivers/media/video/msm/msm.c
+++ b/drivers/media/video/msm/msm.c
@@ -92,6 +92,20 @@
 	return rc;
 }
 
+static int msm_camera_v4l2_private_general(struct file *f, void *pctx,
+	struct msm_camera_v4l2_ioctl_t *ioctl_ptr)
+{
+	int rc = 0;
+	struct msm_cam_v4l2_device *pcam  = video_drvdata(f);
+
+	WARN_ON(pctx != f->private_data);
+
+	rc = msm_server_private_general(pcam, ioctl_ptr);
+	if (rc < 0)
+		pr_err("%s: Private command failed rc %d\n", __func__, rc);
+	return rc;
+}
+
 static int msm_camera_v4l2_private_g_ctrl(struct file *f, void *pctx,
 	struct msm_camera_v4l2_ioctl_t *ioctl_ptr)
 {
@@ -690,6 +704,16 @@
 		return OUTPUT_TYPE_R;
 	case MSM_V4L2_EXT_CAPTURE_MODE_RDI1:
 		return OUTPUT_TYPE_R1;
+	case MSM_V4L2_EXT_CAPTURE_MODE_AEC:
+		return OUTPUT_TYPE_SAEC;
+	case MSM_V4L2_EXT_CAPTURE_MODE_AF:
+		return OUTPUT_TYPE_SAFC;
+	case MSM_V4L2_EXT_CAPTURE_MODE_AWB:
+		return OUTPUT_TYPE_SAWB;
+	case MSM_V4L2_EXT_CAPTURE_MODE_IHIST:
+		return OUTPUT_TYPE_IHST;
+	case MSM_V4L2_EXT_CAPTURE_MODE_CSTA:
+		return OUTPUT_TYPE_CSTA;
 	case MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT:
 	case MSM_V4L2_EXT_CAPTURE_MODE_PREVIEW:
 	default:
@@ -701,17 +725,22 @@
 				struct v4l2_streamparm *a)
 {
 	int rc = 0;
+	int is_bayer_sensor = 0;
 	struct msm_cam_v4l2_dev_inst *pcam_inst;
 	pcam_inst = container_of(f->private_data,
 		struct msm_cam_v4l2_dev_inst, eventHandle);
 	pcam_inst->image_mode = (a->parm.capture.extendedmode & 0x7F);
+	SET_DEVID_MODE(pcam_inst->inst_handle, pcam_inst->pcam->vnode_id);
 	SET_IMG_MODE(pcam_inst->inst_handle, pcam_inst->image_mode);
 	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);
+	if (pcam_inst->pcam->sdata->sensor_type == BAYER_SENSOR)
+		is_bayer_sensor = 1;
 	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->pcam->mctl_handle, pcam_inst->pcam->vnode_id,
+			is_bayer_sensor);
+	D("%s path=%d, rc=%d\n", __func__,
 		pcam_inst->path, rc);
 	return rc;
 }
@@ -761,6 +790,7 @@
 {
 	int rc = -EINVAL;
 	struct msm_camera_v4l2_ioctl_t *ioctl_ptr = arg;
+	struct msm_cam_v4l2_device *pcam  = video_drvdata(file);
 	D("%s: cmd %d\n", __func__, _IOC_NR(cmd));
 
 	switch (cmd) {
@@ -770,6 +800,47 @@
 	case MSM_CAM_V4L2_IOCTL_PRIVATE_G_CTRL:
 		rc = msm_camera_v4l2_private_g_ctrl(file, fh, ioctl_ptr);
 		break;
+	case MSM_CAM_V4L2_IOCTL_PRIVATE_GENERAL:
+		rc = msm_camera_v4l2_private_general(file, fh, ioctl_ptr);
+		break;
+	case MSM_CAM_V4L2_IOCTL_GET_EVENT_PAYLOAD: {
+		struct msm_queue_cmd *event_cmd;
+		void *payload;
+		mutex_lock(&pcam->event_lock);
+		event_cmd = msm_dequeue(&pcam->eventData_q, list_eventdata);
+		if (!event_cmd) {
+			pr_err("%s: No event payload\n", __func__);
+			rc = -EINVAL;
+			mutex_unlock(&pcam->event_lock);
+			return rc;
+		}
+		payload = event_cmd->command;
+		if (event_cmd->trans_code != ioctl_ptr->trans_code) {
+			pr_err("%s: Events don't match\n", __func__);
+			kfree(payload);
+			kfree(event_cmd);
+			rc = -EINVAL;
+			mutex_unlock(&pcam->event_lock);
+			break;
+		}
+		if (ioctl_ptr->len > 0) {
+			if (copy_to_user(ioctl_ptr->ioctl_ptr, payload,
+				 ioctl_ptr->len)) {
+				pr_err("%s Copy to user failed for cmd %d",
+					__func__, cmd);
+				kfree(payload);
+				kfree(event_cmd);
+				rc = -EINVAL;
+				mutex_unlock(&pcam->event_lock);
+				break;
+			}
+		}
+		kfree(payload);
+		kfree(event_cmd);
+		mutex_unlock(&pcam->event_lock);
+		rc = 0;
+		break;
+	}
 	default:
 		pr_err("%s Unsupported ioctl cmd %d ", __func__, cmd);
 		break;
@@ -868,12 +939,11 @@
 			pcam_inst->my_index,
 			pcam->vnode_id, pcam->use_count);
 	pcam->use_count++;
-	D("%s use_count %d\n", __func__, pcam->use_count);
+	D("%s Inst %p use_count %d\n", __func__, pcam_inst, pcam->use_count);
 	if (pcam->use_count == 1) {
 		server_q_idx = msm_find_free_queue();
 		if (server_q_idx < 0)
 			return server_q_idx;
-
 		rc = msm_server_begin_session(pcam, server_q_idx);
 		if (rc < 0) {
 			pr_err("%s error starting server session ", __func__);
@@ -908,6 +978,8 @@
 
 		msm_setup_v4l2_event_queue(&pcam_inst->eventHandle,
 			pcam->pvdev);
+		mutex_init(&pcam->event_lock);
+		msm_queue_init(&pcam->eventData_q, "eventData");
 	}
 	pcam_inst->vbqueue_initialized = 0;
 	rc = 0;
@@ -930,6 +1002,7 @@
 	return rc;
 
 msm_send_open_server_failed:
+	msm_drain_eventq(&pcam->eventData_q);
 	msm_destroy_v4l2_event_queue(&pcam_inst->eventHandle);
 
 	if (pmctl->mctl_release)
@@ -1071,11 +1144,17 @@
 	D("%s index %d nodeid %d count %d\n", __func__, pcam_inst->my_index,
 		pcam->vnode_id, pcam->use_count);
 	pcam->dev_inst[pcam_inst->my_index] = NULL;
-	if (pcam_inst->my_index == 0)
+	if (pcam_inst->my_index == 0) {
+		mutex_lock(&pcam->event_lock);
+		msm_drain_eventq(&pcam->eventData_q);
+		mutex_unlock(&pcam->event_lock);
+		mutex_destroy(&pcam->event_lock);
 		msm_destroy_v4l2_event_queue(&pcam_inst->eventHandle);
+	}
 
 	CLR_VIDEO_INST_IDX(pcam_inst->inst_handle);
 	CLR_IMG_MODE(pcam_inst->inst_handle);
+	CLR_DEVID_MODE(pcam_inst->inst_handle);
 	mutex_unlock(&pcam_inst->inst_lock);
 	mutex_destroy(&pcam_inst->inst_lock);
 	kfree(pcam_inst);
@@ -1135,24 +1214,60 @@
 	unsigned int cmd, unsigned long evt)
 {
 	struct v4l2_event v4l2_ev;
+	struct v4l2_event_and_payload evt_payload;
 	struct msm_cam_v4l2_device *pcam = NULL;
-
+	int rc = 0;
+	struct msm_queue_cmd *event_qcmd;
+	void *payload;
 	if (!mctl) {
 		pr_err("%s: mctl is NULL\n", __func__);
 		return -EINVAL;
 	}
 
-	if (copy_from_user(&v4l2_ev, (void __user *)evt,
-		sizeof(struct v4l2_event))) {
+	if (copy_from_user(&evt_payload, (void __user *)evt,
+		sizeof(struct v4l2_event_and_payload))) {
 		ERR_COPY_FROM_USER();
 		return -EFAULT;
 	}
 
+	v4l2_ev = evt_payload.evt;
 	v4l2_ev.id = 0;
 	pcam = mctl->pcam_ptr;
 	ktime_get_ts(&v4l2_ev.timestamp);
+	if (evt_payload.payload_length > 0 && evt_payload.payload != NULL) {
+		mutex_lock(&pcam->event_lock);
+		event_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_KERNEL);
+		if (!event_qcmd) {
+			pr_err("%s Insufficient memory. return", __func__);
+			rc = -ENOMEM;
+			goto event_qcmd_alloc_fail;
+		}
+		payload = kzalloc(evt_payload.payload_length, GFP_KERNEL);
+		if (!payload) {
+			pr_err("%s Insufficient memory. return", __func__);
+			rc = -ENOMEM;
+			goto payload_alloc_fail;
+		}
+		if (copy_from_user(payload,
+				(void __user *)evt_payload.payload,
+				evt_payload.payload_length)) {
+			ERR_COPY_FROM_USER();
+			rc = -EFAULT;
+			goto copy_from_user_failed;
+		}
+		event_qcmd->command = payload;
+		event_qcmd->trans_code = evt_payload.transaction_id;
+		msm_enqueue(&pcam->eventData_q, &event_qcmd->list_eventdata);
+		mutex_unlock(&pcam->event_lock);
+	}
 	v4l2_event_queue(pcam->pvdev, &v4l2_ev);
-	return 0;
+	return rc;
+copy_from_user_failed:
+	kfree(payload);
+payload_alloc_fail:
+	kfree(event_qcmd);
+event_qcmd_alloc_fail:
+	return rc;
 }
 
 
@@ -1169,11 +1284,21 @@
 {
 	int rc = -ENOMEM;
 	struct video_device *pvdev = NULL;
-	struct i2c_client *client = v4l2_get_subdevdata(pcam->sensor_sdev);
+	struct i2c_client *client = NULL;
+	struct platform_device *pdev = NULL;
 	D("%s\n", __func__);
 
 	/* first register the v4l2 device */
-	pcam->v4l2_dev.dev = &client->dev;
+	if (pcam->sensor_sdev->flags & V4L2_SUBDEV_FL_IS_I2C) {
+		client = v4l2_get_subdevdata(pcam->sensor_sdev);
+		pcam->v4l2_dev.dev = &client->dev;
+		pcam->media_dev.dev = &client->dev;
+	} else {
+		pdev = v4l2_get_subdevdata(pcam->sensor_sdev);
+		pcam->v4l2_dev.dev = &pdev->dev;
+		pcam->media_dev.dev = &pdev->dev;
+	}
+
 	rc = v4l2_device_register(pcam->v4l2_dev.dev, &pcam->v4l2_dev);
 	if (rc < 0)
 		return -EINVAL;
@@ -1190,7 +1315,6 @@
 
 	strlcpy(pcam->media_dev.model, QCAMERA_NAME,
 			sizeof(pcam->media_dev.model));
-	pcam->media_dev.dev = &client->dev;
 	rc = media_device_register(&pcam->media_dev);
 	pvdev->v4l2_dev = &pcam->v4l2_dev;
 	pcam->v4l2_dev.mdev = &pcam->media_dev;
@@ -1249,7 +1373,7 @@
 
 	D("%s called\n", __func__);
 
-	if (!actuator_info)
+	if (!actuator_info || !actuator_info->board_info)
 		goto probe_fail;
 
 	adapter = i2c_get_adapter(actuator_info->bus_id);
@@ -1292,7 +1416,7 @@
 
 	D("%s called\n", __func__);
 
-	if (!eeprom_info)
+	if (!eeprom_info || !eeprom_info->board_info)
 		goto probe_fail;
 
 	adapter = i2c_get_adapter(eeprom_info->bus_id);
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index a2c21bd..1e1b4ae 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -31,6 +31,7 @@
 #include <media/videobuf2-msm-mem.h>
 #include <media/msm_isp.h>
 #include <mach/camera.h>
+#include <mach/iommu.h>
 #include <media/msm_isp.h>
 #include <linux/ion.h>
 #include <linux/iommu.h>
@@ -57,6 +58,7 @@
 #define MSM_VPE_DRV_NAME "msm_vpe"
 #define MSM_GEMINI_DRV_NAME "msm_gemini"
 #define MSM_MERCURY_DRV_NAME "msm_mercury"
+#define MSM_JPEG_DRV_NAME "msm_jpeg"
 #define MSM_I2C_MUX_DRV_NAME "msm_cam_i2c_mux"
 #define MSM_IRQ_ROUTER_DRV_NAME "msm_cam_irq_router"
 #define MSM_CPP_DRV_NAME "msm_cpp"
@@ -140,6 +142,11 @@
 	uint32_t  frameCounter;
 };
 
+struct rdi_count_msg {
+	uint32_t rdi_interface;
+	uint32_t count;
+};
+
 /* message id for v4l2_subdev_notify*/
 enum msm_camera_v4l2_subdev_notify {
 	NOTIFY_ISP_MSG_EVT, /* arg = enum ISP_MESSAGE_ID */
@@ -148,11 +155,9 @@
 	NOTIFY_VFE_MSG_COMP_STATS, /* arg = struct msm_stats_buf */
 	NOTIFY_VFE_BUF_EVT, /* arg = struct msm_vfe_resp */
 	NOTIFY_VFE_CAMIF_ERROR,
-	NOTIFY_VFE_SOF_COUNT, /*arg = int*/
+	NOTIFY_VFE_PIX_SOF_COUNT, /*arg = int*/
+	NOTIFY_AXI_RDI_SOF_COUNT, /*arg = struct rdi_count_msg*/
 	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_IRQ,
 	NOTIFY_AXI_IRQ,
 	NOTIFY_GESTURE_EVT, /* arg = v4l2_event */
@@ -201,10 +206,36 @@
 	enum v4l2_colorspace colorspace;
 };
 
+struct msm_cam_return_frame_info {
+	int dirty;
+	int node_type;
+	struct timeval timestamp;
+};
+
+struct msm_cam_timestamp {
+	uint8_t present;
+	struct timeval timestamp;
+};
+
+struct msm_cam_buf_map_info {
+	int fd;
+	uint32_t data_offset;
+	unsigned long paddr;
+	unsigned long len;
+	struct file *file;
+	struct ion_handle *handle;
+};
+
+struct msm_cam_meta_frame {
+	struct msm_pp_frame frame;
+	/* Mapping information per plane */
+	struct msm_cam_buf_map_info map[VIDEO_MAX_PLANES];
+};
+
 struct msm_mctl_pp_frame_info {
 	int user_cmd;
-	struct msm_pp_frame src_frame;
-	struct msm_pp_frame dest_frame;
+	struct msm_cam_meta_frame src_frame;
+	struct msm_cam_meta_frame dest_frame;
 	struct msm_mctl_pp_frame_cmd pp_frame_cmd;
 	struct msm_cam_media_controller *p_mctl;
 };
@@ -242,6 +273,10 @@
 	int (*mctl_vbqueue_init)(struct msm_cam_v4l2_dev_inst *pcam,
 				struct vb2_queue *q, enum v4l2_buf_type type);
 	int (*mctl_ufmt_init)(struct msm_cam_media_controller *p_mctl);
+	int (*isp_config)(struct msm_cam_media_controller *pmctl,
+		 unsigned int cmd, unsigned long arg);
+	int (*isp_notify)(struct msm_cam_media_controller *pmctl,
+		struct v4l2_subdev *sd, unsigned int notification, void *arg);
 
 	/* the following reflect the HW topology information*/
 	struct v4l2_subdev *sensor_sdev; /* sensor sub device */
@@ -253,10 +288,10 @@
 	struct v4l2_subdev *gemini_sdev; /* gemini sub device */
 	struct v4l2_subdev *vpe_sdev; /* vpe sub device */
 	struct v4l2_subdev *axi_sdev; /* axi sub device */
+	struct v4l2_subdev *vfe_sdev; /* vfe sub device */
 	struct v4l2_subdev *eeprom_sdev; /* eeprom sub device */
 	struct v4l2_subdev *cpp_sdev;/*cpp sub device*/
 
-	struct msm_isp_ops *isp_sdev;    /* isp sub device : camif/VFE */
 	struct msm_cam_config_dev *config_device;
 
 	/*mctl session control information*/
@@ -282,21 +317,10 @@
 	uint32_t ping_imem_cbcr;
 	uint32_t pong_imem_y;
 	uint32_t pong_imem_cbcr;
-};
 
-/* abstract camera device represents a VFE and connected sensor */
-struct msm_isp_ops {
-	char *config_dev_name;
-
-	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);
-	int (*isp_pp_cmd)(struct msm_cam_media_controller *pmctl,
-		 struct msm_mctl_pp_cmd, void *data);
-
-	/* vfe subdevice */
-	struct v4l2_subdev *sd;
+	/*IOMMU domain for this session*/
+	int domain_num;
+	struct iommu_domain *domain;
 };
 
 struct msm_isp_buf_info {
@@ -309,7 +333,7 @@
 	uint32_t data_offset;
 };
 
-#define MSM_DEV_INST_MAX                    16
+#define MSM_DEV_INST_MAX                    24
 struct msm_cam_v4l2_dev_inst {
 	struct v4l2_fh  eventHandle;
 	struct vb2_queue vid_bufq;
@@ -373,6 +397,9 @@
 	struct v4l2_subdev *act_sdev; /* actuator sub device */
 	struct v4l2_subdev *eeprom_sdev; /* actuator sub device */
 	struct msm_camera_sensor_info *sdata;
+
+	struct msm_device_queue eventData_q; /*payload for events sent to app*/
+	struct mutex event_lock;
 };
 
 static inline struct msm_cam_v4l2_device *to_pcam(
@@ -396,6 +423,8 @@
 	struct msm_cam_media_controller *p_mctl;
 	struct msm_mem_map_info mem_map;
 	int dev_num;
+	int domain_num;
+	struct iommu_domain *domain;
 };
 
 struct msm_cam_subdev_info {
@@ -486,12 +515,14 @@
 };
 
 struct interface_map {
-	/* The interafce a particular stream belongs to.
+	/* The interface a particular stream belongs to.
 	 * PIX0, RDI0, RDI1, or RDI2
 	 */
 	int interface;
-	/* The handle of the mctl intstance interface runs on */
+	/* The handle of the mctl instance, interface runs on */
 	uint32_t mctl_handle;
+	int vnode_id;
+	int is_bayer_sensor;
 };
 
 /* abstract camera server device for all sensor successfully probed*/
@@ -510,6 +541,8 @@
 	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[MAX_NUM_ACTIVE_CAMERA];
+	/* save the opened pcam for finding the mctl when doing buf lookup */
+	struct msm_cam_v4l2_device *opened_pcam[MAX_NUM_ACTIVE_CAMERA];
 	/* number of camera devices opened*/
 	atomic_t number_pcam_active;
 	struct v4l2_queue_util server_command_queue;
@@ -555,6 +588,10 @@
 	 * dispatch the irq to the corresponding subdev. */
 	struct v4l2_subdev *subdev_table[MSM_CAM_HW_MAX];
 	struct msm_cam_server_irqmap_entry hw_irqmap[CAMERA_SS_IRQ_MAX];
+
+    /*IOMMU domain (Page table)*/
+	int domain_num;
+	struct iommu_domain *domain;
 };
 
 enum msm_cam_buf_lookup_type {
@@ -571,11 +608,13 @@
 
 /* ISP related functions */
 void msm_isp_vfe_dev_init(struct v4l2_subdev *vd);
+int msm_isp_config(struct msm_cam_media_controller *pmctl,
+			 unsigned int cmd, unsigned long arg);
+int msm_isp_notify(struct msm_cam_media_controller *pmctl,
+	struct v4l2_subdev *sd, unsigned int notification, void *arg);
 /*
 int msm_isp_register(struct msm_cam_v4l2_device *pcam);
 */
-int msm_isp_register(struct msm_cam_server_dev *psvr);
-void msm_isp_unregister(struct msm_cam_server_dev *psvr);
 int msm_sensor_register(struct v4l2_subdev *);
 int msm_isp_init_module(int g_num_config_nodes);
 
@@ -589,7 +628,8 @@
 	uint32_t frame_id);
 int msm_mctl_buf_done_pp(struct msm_cam_media_controller *pmctl,
 	struct msm_cam_buf_handle *buf_handle,
-	struct msm_free_buf *frame, int dirty, int node_type);
+	struct msm_free_buf *frame,
+	struct msm_cam_return_frame_info *ret_frame);
 int msm_mctl_reserve_free_buf(struct msm_cam_media_controller *pmctl,
 	struct msm_cam_v4l2_dev_inst *pcam_inst,
 	struct msm_cam_buf_handle *buf_handle,
@@ -599,9 +639,9 @@
 	struct msm_free_buf *free_buf);
 /*Memory(PMEM) functions*/
 int msm_register_pmem(struct hlist_head *ptype, void __user *arg,
-	struct ion_client *client);
+	struct ion_client *client, int domain_num);
 int msm_pmem_table_del(struct hlist_head *ptype, void __user *arg,
-	struct ion_client *client);
+	struct ion_client *client, int domain_num);
 int msm_pmem_region_get_phy_addr(struct hlist_head *ptype,
 	struct msm_mem_map_info *mem_map, int32_t *phyaddr);
 uint8_t msm_pmem_region_lookup(struct hlist_head *ptype,
@@ -623,7 +663,7 @@
 	struct msm_vfe_cfg_cmd *cfgcmd, void *data);
 int msm_vpe_subdev_init(struct v4l2_subdev *sd);
 int msm_gemini_subdev_init(struct v4l2_subdev *gemini_sd);
-void msm_vpe_subdev_release(void);
+void msm_vpe_subdev_release(struct v4l2_subdev *sd);
 void msm_gemini_subdev_release(struct v4l2_subdev *gemini_sd);
 int msm_mctl_is_pp_msg_type(struct msm_cam_media_controller *p_mctl,
 	int msg_type);
@@ -670,6 +710,10 @@
 	struct msm_cam_buf_handle *buf_handle);
 int msm_mctl_buf_return_buf(struct msm_cam_media_controller *pmctl,
 	int image_mode, struct msm_frame_buffer *buf);
+int msm_mctl_map_user_frame(struct msm_cam_meta_frame *meta_frame,
+	struct ion_client *client, int domain_num);
+int msm_mctl_unmap_user_frame(struct msm_cam_meta_frame *meta_frame,
+	struct ion_client *client, int domain_num);
 int msm_mctl_pp_mctl_divert_done(struct msm_cam_media_controller *p_mctl,
 	void __user *arg);
 void msm_release_ion_client(struct kref *ref);
diff --git a/drivers/media/video/msm/msm_isp.c b/drivers/media/video/msm/msm_isp.c
index 3d94afd..2613986 100644
--- a/drivers/media/video/msm/msm_isp.c
+++ b/drivers/media/video/msm/msm_isp.c
@@ -73,7 +73,7 @@
 	struct msm_camvfe_params vfe_params;
 	int rc;
 
-	cfgcmd.cmd_type = CMD_VFE_SOF_COUNT_UPDATE;
+	cfgcmd.cmd_type = CMD_VFE_PIX_SOF_COUNT_UPDATE;
 	cfgcmd.value = NULL;
 	vfe_params.vfe_cfg = &cfgcmd;
 	vfe_params.data = arg;
@@ -156,15 +156,14 @@
 	return image_mode;
 }
 
-static int msm_isp_notify_VFE_BUF_EVT(struct v4l2_subdev *sd, void *arg)
+static int msm_isp_notify_VFE_BUF_EVT(struct msm_cam_media_controller *pmctl,
+					struct v4l2_subdev *sd, void *arg)
 {
 	int rc = -EINVAL;
 	struct msm_vfe_resp *vdata = (struct msm_vfe_resp *)arg;
 	struct msm_free_buf free_buf, temp_free_buf;
 	struct msm_camvfe_params vfe_params;
 	struct msm_vfe_cfg_cmd cfgcmd;
-	struct msm_cam_media_controller *pmctl =
-		(struct msm_cam_media_controller *)v4l2_get_subdev_hostdata(sd);
 	struct msm_cam_v4l2_device *pcam = pmctl->pcam_ptr;
 	struct msm_frame_info *frame_info =
 		(struct msm_frame_info *)vdata->evt_msg.data;
@@ -172,7 +171,7 @@
 	struct msm_cam_buf_handle buf_handle;
 
 	if (!pcam) {
-		pr_debug("%s pcam is null. return\n", __func__);
+		pr_err("%s pcam is null. return\n", __func__);
 		msm_isp_sync_free(vdata);
 		return rc;
 	}
@@ -275,14 +274,12 @@
 /*
  * This function executes in interrupt context.
  */
-static int msm_isp_notify_vfe(struct v4l2_subdev *sd,
-	unsigned int notification,  void *arg)
+static int msm_isp_notify_vfe(struct msm_cam_media_controller *pmctl,
+	struct v4l2_subdev *sd,	unsigned int notification,  void *arg)
 {
 	int rc = 0;
 	struct v4l2_event v4l2_evt;
 	struct msm_isp_event_ctrl *isp_event;
-	struct msm_cam_media_controller *pmctl =
-		(struct msm_cam_media_controller *)v4l2_get_subdev_hostdata(sd);
 	struct msm_free_buf buf;
 
 	if (!pmctl) {
@@ -292,9 +289,9 @@
 	}
 
 	if (notification == NOTIFY_VFE_BUF_EVT)
-		return msm_isp_notify_VFE_BUF_EVT(sd, arg);
+		return msm_isp_notify_VFE_BUF_EVT(pmctl, sd, arg);
 
-	if (notification == NOTIFY_VFE_SOF_COUNT)
+	if (notification == NOTIFY_VFE_PIX_SOF_COUNT)
 		return msm_isp_notify_VFE_SOF_COUNT_EVT(sd, arg);
 
 	isp_event = kzalloc(sizeof(struct msm_isp_event_ctrl), GFP_ATOMIC);
@@ -493,11 +490,12 @@
 	return rc;
 }
 
-static int msm_isp_notify(struct v4l2_subdev *sd,
-	unsigned int notification, void *arg)
+int msm_isp_notify(struct msm_cam_media_controller *pmctl,
+	struct v4l2_subdev *sd,	unsigned int notification, void *arg)
 {
-	return msm_isp_notify_vfe(sd, notification, arg);
+	return msm_isp_notify_vfe(pmctl, sd, notification, arg);
 }
+EXPORT_SYMBOL(msm_isp_notify);
 
 static int msm_config_vfe(struct v4l2_subdev *sd,
 	struct msm_cam_media_controller *mctl, void __user *arg)
@@ -642,6 +640,7 @@
 {
 	struct msm_vfe_cfg_cmd cfgcmd;
 	int rc = 0;
+	v4l2_set_subdev_hostdata(sd, mctl);
 	switch (cmd) {
 	case MSM_CAM_IOCTL_STATS_REQBUF: {
 		struct msm_stats_reqbuf reqbuf;
@@ -703,13 +702,13 @@
 	return rc;
 }
 /* config function simliar to origanl msm_ioctl_config*/
-static int msm_isp_config(struct msm_cam_media_controller *pmctl,
+int msm_isp_config(struct msm_cam_media_controller *pmctl,
 			 unsigned int cmd, unsigned long arg)
 {
 
 	int rc = -EINVAL;
 	void __user *argp = (void __user *)arg;
-	struct v4l2_subdev *sd = pmctl->isp_sdev->sd;
+	struct v4l2_subdev *sd = pmctl->vfe_sdev;
 
 	D("%s: cmd %d\n", __func__, _IOC_NR(cmd));
 	switch (cmd) {
@@ -742,47 +741,7 @@
 
 	return rc;
 }
-
-static struct msm_isp_ops isp_subdev[MSM_MAX_CAMERA_CONFIGS];
-
-/**/
-int msm_isp_init_module(int g_num_config_nodes)
-{
-	int i = 0;
-
-	for (i = 0; i < g_num_config_nodes; i++) {
-		isp_subdev[i].isp_config = msm_isp_config;
-		isp_subdev[i].isp_notify = msm_isp_notify;
-	}
-	return 0;
-}
-EXPORT_SYMBOL(msm_isp_init_module);
-
-/*
-*/
-int msm_isp_register(struct msm_cam_server_dev *psvr)
-{
-	int i = 0;
-
-	D("%s\n", __func__);
-
-	BUG_ON(!psvr);
-
-	/* Initialize notify function for v4l2_dev */
-	for (i = 0; i < psvr->config_info.num_config_nodes; i++)
-		psvr->isp_subdev[i] = &(isp_subdev[i]);
-
-	return 0;
-}
-EXPORT_SYMBOL(msm_isp_register);
-
-/**/
-void msm_isp_unregister(struct msm_cam_server_dev *psvr)
-{
-	int i = 0;
-	for (i = 0; i < psvr->config_info.num_config_nodes; i++)
-		psvr->isp_subdev[i] = NULL;
-}
+EXPORT_SYMBOL(msm_isp_config);
 
 int msm_isp_subdev_ioctl(struct v4l2_subdev *isp_subdev,
 	struct msm_vfe_cfg_cmd *cfgcmd, void *data)
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index a8d74a7..c94da2a 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -138,7 +138,38 @@
 	.pxlcode	= V4L2_MBUS_FMT_YUYV8_2X8, /* YUV sensor */
 	.colorspace = V4L2_COLORSPACE_JPEG,
 	},
-
+	{
+	.name	   = "SAEC",
+	.depth	  = 16,
+	.bitsperpxl = 16,
+	.fourcc	 = V4L2_PIX_FMT_STATS_AE,
+	.pxlcode	= V4L2_MBUS_FMT_SBGGR10_1X10, /* YUV sensor */
+	.colorspace = V4L2_COLORSPACE_JPEG,
+	},
+	{
+	.name	   = "SAWB",
+	.depth	  = 16,
+	.bitsperpxl = 16,
+	.fourcc	 = V4L2_PIX_FMT_STATS_AWB,
+	.pxlcode	= V4L2_MBUS_FMT_SBGGR10_1X10, /* YUV sensor */
+	.colorspace = V4L2_COLORSPACE_JPEG,
+	},
+	{
+	.name	   = "SAFC",
+	.depth	  = 16,
+	.bitsperpxl = 16,
+	.fourcc	 = V4L2_PIX_FMT_STATS_AF,
+	.pxlcode	= V4L2_MBUS_FMT_SBGGR10_1X10, /* YUV sensor */
+	.colorspace = V4L2_COLORSPACE_JPEG,
+	},
+	{
+	.name      = "SHST",
+	.depth    = 16,
+	.bitsperpxl = 16,
+	.fourcc  = V4L2_PIX_FMT_STATS_IHST,
+	.pxlcode        = V4L2_MBUS_FMT_SBGGR10_1X10, /* YUV sensor */
+	.colorspace = V4L2_COLORSPACE_JPEG,
+	},
 };
 
 static int msm_get_sensor_info(
@@ -197,6 +228,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,
@@ -327,7 +372,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 {
@@ -370,7 +414,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;
 	}
@@ -404,21 +449,57 @@
 		break;
 			/* ISFIF config*/
 	case MSM_CAM_IOCTL_AXI_CONFIG:
-		if (p_mctl->axi_sdev)
+		if (p_mctl->axi_sdev) {
+			v4l2_set_subdev_hostdata(p_mctl->axi_sdev, p_mctl);
 			rc = v4l2_subdev_call(p_mctl->axi_sdev, core, ioctl,
 				VIDIOC_MSM_AXI_CFG, (void __user *)arg);
-		else
-			rc = p_mctl->isp_sdev->isp_config(p_mctl, cmd, arg);
+		} else
+			rc = p_mctl->isp_config(p_mctl, cmd, arg);
 		break;
 	case MSM_CAM_IOCTL_ISPIF_IO_CFG:
 		rc = v4l2_subdev_call(p_mctl->ispif_sdev,
 			core, ioctl, VIDIOC_MSM_ISPIF_CFG, argp);
 		break;
+
+	case MSM_CAM_IOCTL_CSIPHY_IO_CFG:
+		if (p_mctl->csiphy_sdev)
+			rc = v4l2_subdev_call(p_mctl->csiphy_sdev,
+				core, ioctl, VIDIOC_MSM_CSIPHY_CFG, argp);
+		break;
+
+	case MSM_CAM_IOCTL_CSIC_IO_CFG:
+		if (p_mctl->csic_sdev)
+			rc = v4l2_subdev_call(p_mctl->csic_sdev,
+				core, ioctl, VIDIOC_MSM_CSIC_CFG, argp);
+		break;
+
+	case MSM_CAM_IOCTL_CSID_IO_CFG:
+		if (p_mctl->csid_sdev)
+			rc = v4l2_subdev_call(p_mctl->csid_sdev,
+				core, ioctl, VIDIOC_MSM_CSID_CFG, argp);
+		break;
+
+	case MSM_CAM_IOCTL_AXI_INIT:
+		if (p_mctl->axi_sdev) {
+			v4l2_set_subdev_hostdata(p_mctl->axi_sdev, p_mctl);
+			rc = v4l2_subdev_call(p_mctl->axi_sdev, core, ioctl,
+				VIDIOC_MSM_AXI_INIT, (void __user *)arg);
+		}
+		break;
+
+	case MSM_CAM_IOCTL_AXI_RELEASE:
+		if (p_mctl->axi_sdev) {
+			v4l2_set_subdev_hostdata(p_mctl->axi_sdev, p_mctl);
+			rc = v4l2_subdev_call(p_mctl->axi_sdev, core, ioctl,
+				VIDIOC_MSM_AXI_RELEASE, NULL);
+		}
+		break;
+
 	default:
 		/* ISP config*/
 		D("%s:%d: go to default. Calling msm_isp_config\n",
 			__func__, __LINE__);
-		rc = p_mctl->isp_sdev->isp_config(p_mctl, cmd, arg);
+		rc = p_mctl->isp_config(p_mctl, cmd, arg);
 		break;
 	}
 	D("%s: !!! cmd = %d, rc = %d\n",
@@ -445,7 +526,6 @@
 	/* open sub devices - once only*/
 	if (!p_mctl->opencnt) {
 		struct msm_sensor_csi_info csi_info;
-		uint32_t csid_version = 0;
 		wake_lock(&p_mctl->wake_lock);
 
 		csid_core = camdev->csid_core;
@@ -471,39 +551,10 @@
 			goto act_power_up_failed;
 		}
 
-		if (p_mctl->csiphy_sdev) {
-			rc = v4l2_subdev_call(p_mctl->csiphy_sdev, core, ioctl,
-				VIDIOC_MSM_CSIPHY_INIT, NULL);
-			if (rc < 0) {
-				pr_err("%s: csiphy initialization failed %d\n",
-					__func__, rc);
-				goto csiphy_init_failed;
-			}
-		}
-
-		if (p_mctl->csid_sdev) {
-			rc = v4l2_subdev_call(p_mctl->csid_sdev, core, ioctl,
-				VIDIOC_MSM_CSID_INIT, &csid_version);
-			if (rc < 0) {
-				pr_err("%s: csid initialization failed %d\n",
-					__func__, rc);
-				goto csid_init_failed;
-			}
-			csi_info.is_csic = 0;
-		}
-
-		if (p_mctl->csic_sdev) {
-			rc = v4l2_subdev_call(p_mctl->csic_sdev, core, ioctl,
-				VIDIOC_MSM_CSIC_INIT, &csid_version);
-			if (rc < 0) {
-				pr_err("%s: csic initialization failed %d\n",
-					__func__, rc);
-				goto csic_init_failed;
-			}
+		if (p_mctl->csic_sdev)
 			csi_info.is_csic = 1;
-		}
-
-		csi_info.csid_version = csid_version;
+		else
+			csi_info.is_csic = 0;
 		rc = v4l2_subdev_call(p_mctl->sensor_sdev, core, ioctl,
 				VIDIOC_MSM_SENSOR_CSID_INFO, &csi_info);
 		if (rc < 0) {
@@ -526,26 +577,6 @@
 	return rc;
 
 msm_csi_version:
-	if (p_mctl->csic_sdev)
-		if (v4l2_subdev_call(p_mctl->csic_sdev, core, ioctl,
-			VIDIOC_MSM_CSIC_RELEASE, NULL) < 0)
-			pr_err("%s: csic release failed %d\n", __func__, rc);
-csic_init_failed:
-	if (p_mctl->csid_sdev)
-		if (v4l2_subdev_call(p_mctl->csid_sdev, core, ioctl,
-			VIDIOC_MSM_CSID_RELEASE, NULL) < 0)
-			pr_err("%s: csid release failed %d\n", __func__, rc);
-csid_init_failed:
-	if (p_mctl->csiphy_sdev)
-		if (v4l2_subdev_call(p_mctl->csiphy_sdev, core, ioctl,
-			VIDIOC_MSM_CSIPHY_RELEASE,
-			sinfo->sensor_platform_info->csi_lane_params) < 0)
-			pr_err("%s: csiphy release failed %d\n", __func__, rc);
-csiphy_init_failed:
-	if (p_mctl->act_sdev)
-		if (v4l2_subdev_call(p_mctl->act_sdev, core,
-			s_power, 0) < 0)
-			pr_err("%s: act power down failed:%d\n", __func__, rc);
 act_power_up_failed:
 	if (v4l2_subdev_call(p_mctl->sensor_sdev, core, s_power, 0) < 0)
 		pr_err("%s: sensor powerdown failed: %d\n", __func__, rc);
@@ -561,7 +592,6 @@
 	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;
-
 	v4l2_subdev_call(p_mctl->sensor_sdev, core, ioctl,
 		VIDIOC_MSM_SENSOR_RELEASE, NULL);
 
@@ -576,6 +606,7 @@
 	}
 
 	if (p_mctl->axi_sdev) {
+		v4l2_set_subdev_hostdata(p_mctl->axi_sdev, p_mctl);
 		v4l2_subdev_call(p_mctl->axi_sdev, core, ioctl,
 			VIDIOC_MSM_AXI_RELEASE, NULL);
 	}
@@ -693,6 +724,9 @@
 	pmctl->mctl_open = msm_mctl_open;
 	pmctl->mctl_cmd = msm_mctl_cmd;
 	pmctl->mctl_release = msm_mctl_release;
+	pmctl->isp_config = msm_isp_config;
+	pmctl->isp_notify = msm_isp_notify;
+
 	/* init mctl buf */
 	msm_mctl_buf_init(pcam);
 	memset(&pmctl->pp_info, 0, sizeof(pmctl->pp_info));
@@ -882,6 +916,7 @@
 	pcam->mctl_node.dev_inst[pcam_inst->my_index] = NULL;
 	msm_destroy_v4l2_event_queue(&pcam_inst->eventHandle);
 	CLR_MCTLPP_INST_IDX(pcam_inst->inst_handle);
+	CLR_DEVID_MODE(pcam_inst->inst_handle);
 	CLR_IMG_MODE(pcam_inst->inst_handle);
 	mutex_unlock(&pcam_inst->inst_lock);
 	mutex_destroy(&pcam_inst->inst_lock);
@@ -1146,7 +1181,7 @@
 static int msm_mctl_v4l2_dqbuf(struct file *f, void *pctx,
 					struct v4l2_buffer *pb)
 {
-	int rc = 0;
+	int rc = 0, i;
 	/* get the camera device */
 	struct msm_cam_v4l2_dev_inst *pcam_inst;
 	pcam_inst = container_of(f->private_data,
@@ -1163,6 +1198,26 @@
 	rc = vb2_dqbuf(&pcam_inst->vid_bufq, pb,  f->f_flags & O_NONBLOCK);
 	D("%s, videobuf_dqbuf returns %d\n", __func__, rc);
 
+	if (pb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		/* Reject the buffer if planes array was not allocated */
+		if (pb->m.planes == NULL) {
+			pr_err("%s Planes array is null\n", __func__);
+			mutex_unlock(&pcam_inst->inst_lock);
+			return -EINVAL;
+		}
+		for (i = 0; i < pcam_inst->plane_info.num_planes; i++) {
+			pb->m.planes[i].data_offset =
+				pcam_inst->buf_offset[pb->index][i].data_offset;
+			pb->m.planes[i].reserved[0] =
+				pcam_inst->buf_offset[pb->index][i].addr_offset;
+			D("%s update offsets for plane %d as A %d D %d\n",
+				__func__, i, pb->m.planes[i].reserved[0],
+				pb->m.planes[i].data_offset);
+		}
+	} else {
+		pb->reserved = pcam_inst->buf_offset[pb->index][0].addr_offset;
+		D("%s stored reserved info %d\n", __func__, pb->reserved);
+	}
 	mutex_unlock(&pcam_inst->inst_lock);
 	return rc;
 }
@@ -1440,18 +1495,30 @@
 				struct v4l2_streamparm *a)
 {
 	int rc = 0;
+	int is_bayer_sensor = 0;
+	struct msm_cam_media_controller *pmctl = NULL;
 	struct msm_cam_v4l2_dev_inst *pcam_inst;
 	pcam_inst = container_of(f->private_data,
 		struct msm_cam_v4l2_dev_inst, eventHandle);
 	pcam_inst->image_mode = (a->parm.capture.extendedmode & 0x7F);
+
+	pmctl = msm_cam_server_get_mctl(pcam_inst->pcam->mctl_handle);
+	if (!pmctl) {
+		pr_err("%s: invalid mctl controller", __func__);
+		return -EINVAL;
+	}
+	/* save msm_dev node idx for subdev notify lookup */
+	SET_DEVID_MODE(pcam_inst->inst_handle, pmctl->pcam_ptr->vnode_id);
 	SET_IMG_MODE(pcam_inst->inst_handle, pcam_inst->image_mode);
 	SET_MCTLPP_INST_IDX(pcam_inst->inst_handle, pcam_inst->my_index);
 	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);
-
+	if (pcam_inst->pcam->sdata->sensor_type == BAYER_SENSOR)
+		is_bayer_sensor = 1;
 	rc = msm_cam_server_config_interface_map(pcam_inst->image_mode,
-			pcam_inst->pcam->mctl_handle);
+			pcam_inst->pcam->mctl_handle,
+			pcam_inst->pcam->vnode_id, is_bayer_sensor);
 	D("%s path=%d, image mode = %d rc=%d\n", __func__,
 		pcam_inst->path, pcam_inst->image_mode, rc);
 	return rc;
@@ -1584,12 +1651,20 @@
 {
 	int rc = -EINVAL;
 	struct video_device *pvdev = NULL;
-	struct i2c_client *client = v4l2_get_subdevdata(pcam->sensor_sdev);
-
+	struct i2c_client *client = NULL;
+	struct platform_device *pdev = NULL;
 	D("%s\n", __func__);
 
 	/* first register the v4l2 device */
-	pcam->mctl_node.v4l2_dev.dev = &client->dev;
+	if (pcam->sensor_sdev->flags & V4L2_SUBDEV_FL_IS_I2C) {
+		client = v4l2_get_subdevdata(pcam->sensor_sdev);
+		pcam->mctl_node.v4l2_dev.dev = &client->dev;
+	} else {
+		pdev = v4l2_get_subdevdata(pcam->sensor_sdev);
+		pcam->mctl_node.v4l2_dev.dev = &pdev->dev;
+	}
+
+	/* first register the v4l2 device */
 	rc = v4l2_device_register(pcam->mctl_node.v4l2_dev.dev,
 				&pcam->mctl_node.v4l2_dev);
 	if (rc < 0)
diff --git a/drivers/media/video/msm/msm_mctl_buf.c b/drivers/media/video/msm/msm_mctl_buf.c
index 9f7f689..953f042 100644
--- a/drivers/media/video/msm/msm_mctl_buf.c
+++ b/drivers/media/video/msm/msm_mctl_buf.c
@@ -130,7 +130,8 @@
 			rc = videobuf2_pmem_contig_user_get(mem, &offset,
 				buf_type,
 				pcam_inst->buf_offset[buf_idx][i].addr_offset,
-				pcam_inst->path, pmctl->client);
+				pcam_inst->path, pmctl->client,
+				pmctl->domain_num);
 		else
 			rc = videobuf2_pmem_contig_mmap_get(mem, &offset,
 				buf_type, pcam_inst->path);
@@ -265,7 +266,8 @@
 	}
 	for (i = 0; i < vb->num_planes; i++) {
 		mem = vb2_plane_cookie(vb, i);
-		videobuf2_pmem_contig_user_put(mem, pmctl->client);
+		videobuf2_pmem_contig_user_put(mem, pmctl->client,
+			pmctl->domain_num);
 	}
 	buf->state = MSM_BUFFER_STATE_UNUSED;
 }
@@ -411,7 +413,8 @@
 		struct msm_cam_media_controller *pmctl,
 		struct msm_cam_v4l2_dev_inst *pcam_inst,
 		struct msm_free_buf *fbuf,
-		uint32_t *frame_id, int gen_timestamp)
+		uint32_t *frame_id,
+		struct msm_cam_timestamp *cam_ts)
 {
 	struct msm_frame_buffer *buf = NULL;
 	int del_buf = 1;
@@ -422,11 +425,15 @@
 			__func__, fbuf->ch_paddr[0]);
 		return -EINVAL;
 	}
-	if (gen_timestamp) {
+	if (!cam_ts->present) {
 		if (frame_id)
 			buf->vidbuf.v4l2_buf.sequence = *frame_id;
 		msm_mctl_gettimeofday(
 			&buf->vidbuf.v4l2_buf.timestamp);
+	} else {
+		D("%s Copying timestamp as %ld.%ld", __func__,
+			cam_ts->timestamp.tv_sec, cam_ts->timestamp.tv_usec);
+		buf->vidbuf.v4l2_buf.timestamp = cam_ts->timestamp;
 	}
 	vb2_buffer_done(&buf->vidbuf, VB2_BUF_STATE_DONE);
 	return 0;
@@ -442,6 +449,7 @@
 	int idx, rc;
 	int pp_divert_type = 0, pp_type = 0;
 	uint32_t image_mode;
+	struct msm_cam_timestamp cam_ts;
 
 	if (!p_mctl || !buf_handle || !fbuf) {
 		pr_err("%s Invalid argument. ", __func__);
@@ -507,8 +515,9 @@
 				__func__);
 			return -EINVAL;
 		}
+		memset(&cam_ts, 0, sizeof(cam_ts));
 		rc = msm_mctl_buf_done_proc(p_mctl, pcam_inst,
-			fbuf, &frame_id, 1);
+			fbuf, &frame_id, &cam_ts);
 	}
 	return rc;
 }
@@ -752,12 +761,14 @@
 
 int msm_mctl_buf_done_pp(struct msm_cam_media_controller *pmctl,
 	struct msm_cam_buf_handle *buf_handle,
-	struct msm_free_buf *frame, int dirty, int node_type)
+	struct msm_free_buf *frame,
+	struct msm_cam_return_frame_info *ret_frame)
 {
 	struct msm_cam_v4l2_dev_inst *pcam_inst = NULL;
 	int rc = 0, idx;
+	struct msm_cam_timestamp cam_ts;
 
-	if (!pmctl || !buf_handle) {
+	if (!pmctl || !buf_handle || !ret_frame) {
 		pr_err("%s Invalid argument ", __func__);
 		return -EINVAL;
 	}
@@ -773,13 +784,13 @@
 		}
 	} else if (buf_handle->buf_lookup_type == BUF_LOOKUP_BY_IMG_MODE) {
 		idx = msm_mctl_img_mode_to_inst_index(pmctl,
-			buf_handle->image_mode, node_type);
+			buf_handle->image_mode, ret_frame->node_type);
 		if (idx < 0) {
 			pr_err("%s Invalid instance, buffer not released\n",
 				__func__);
 			return idx;
 		}
-		if (node_type)
+		if (ret_frame->node_type)
 			pcam_inst = pmctl->pcam_ptr->mctl_node.dev_inst[idx];
 		else
 			pcam_inst = pmctl->pcam_ptr->dev_inst[idx];
@@ -791,12 +802,15 @@
 	}
 
 	D("%s:inst=0x%p, paddr=0x%x, dirty=%d",
-		__func__, pcam_inst, frame->ch_paddr[0], dirty);
-	if (dirty)
+		__func__, pcam_inst, frame->ch_paddr[0], ret_frame->dirty);
+	cam_ts.present = 1;
+	cam_ts.timestamp = ret_frame->timestamp;
+	if (ret_frame->dirty)
 		/* the frame is dirty, not going to disptach to app */
 		rc = msm_mctl_release_free_buf(pmctl, pcam_inst, frame);
 	else
-		rc = msm_mctl_buf_done_proc(pmctl, pcam_inst, frame, NULL, 0);
+		rc = msm_mctl_buf_done_proc(pmctl, pcam_inst, frame,
+			NULL, &cam_ts);
 	return rc;
 }
 
@@ -840,3 +854,199 @@
 	spin_unlock_irqrestore(&pcam_inst->vq_irqlock, flags);
 	return -EINVAL;
 }
+
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+/* Unmap using ION APIs */
+static void __msm_mctl_unmap_user_frame(struct msm_cam_meta_frame *meta_frame,
+	struct ion_client *client, int domain_num)
+{
+	int i = 0;
+	for (i = 0; i < meta_frame->frame.num_planes; i++) {
+		D("%s Plane %d handle %p", __func__, i,
+			meta_frame->map[i].handle);
+		ion_unmap_iommu(client, meta_frame->map[i].handle,
+					domain_num, 0);
+		ion_free(client, meta_frame->map[i].handle);
+	}
+}
+
+/* Map using ION APIs */
+static int __msm_mctl_map_user_frame(struct msm_cam_meta_frame *meta_frame,
+	struct ion_client *client, int domain_num)
+{
+	unsigned long paddr = 0;
+	unsigned long len = 0;
+	int i = 0, j = 0;
+
+	for (i = 0; i < meta_frame->frame.num_planes; i++) {
+		meta_frame->map[i].handle = ion_import_dma_buf(client,
+			meta_frame->frame.mp[i].fd);
+		if (IS_ERR_OR_NULL(meta_frame->map[i].handle)) {
+			pr_err("%s: ion_import failed for plane = %d fd = %d",
+				__func__, i, meta_frame->frame.mp[i].fd);
+			/* Roll back previous plane mappings, if any */
+			for (j = i-1; j >= 0; j--) {
+				ion_unmap_iommu(client,
+					meta_frame->map[j].handle,
+					domain_num, 0);
+				ion_free(client, meta_frame->map[j].handle);
+			}
+			return -EACCES;
+		}
+		D("%s Mapping fd %d plane %d handle %p", __func__,
+			meta_frame->frame.mp[i].fd, i,
+			meta_frame->map[i].handle);
+		if (ion_map_iommu(client, meta_frame->map[i].handle,
+				domain_num, 0, SZ_4K,
+				0, &paddr, &len, UNCACHED, 0) < 0) {
+			pr_err("%s: cannot map address plane %d", __func__, i);
+			ion_free(client, meta_frame->map[i].handle);
+			/* Roll back previous plane mappings, if any */
+			for (j = i-1; j >= 0; j--) {
+				if (meta_frame->map[j].handle) {
+					ion_unmap_iommu(client,
+						meta_frame->map[j].handle,
+						domain_num, 0);
+					ion_free(client,
+						meta_frame->map[j].handle);
+				}
+			}
+			return -EFAULT;
+		}
+
+		/* Validate the offsets with the mapped length. */
+		if ((meta_frame->frame.mp[i].addr_offset > len) ||
+			(meta_frame->frame.mp[i].data_offset +
+			meta_frame->frame.mp[i].length > len)) {
+			pr_err("%s: Invalid offsets A %d D %d L %d len %ld",
+				__func__, meta_frame->frame.mp[i].addr_offset,
+				meta_frame->frame.mp[i].data_offset,
+				meta_frame->frame.mp[i].length, len);
+			/* Roll back previous plane mappings, if any */
+			for (j = i; j >= 0; j--) {
+				if (meta_frame->map[j].handle) {
+					ion_unmap_iommu(client,
+						meta_frame->map[j].handle,
+						domain_num, 0);
+					ion_free(client,
+						meta_frame->map[j].handle);
+				}
+			}
+			return -EINVAL;
+		}
+		meta_frame->map[i].data_offset =
+			meta_frame->frame.mp[i].data_offset;
+		/* Add the addr_offset to the paddr here itself. The addr_offset
+		 * will be non-zero only if the user has allocated a buffer with
+		 * a single fd, but logically partitioned it into
+		 * multiple planes or buffers.*/
+		paddr += meta_frame->frame.mp[i].addr_offset;
+		meta_frame->map[i].paddr = paddr;
+		meta_frame->map[i].len = len;
+		D("%s Plane %d fd %d handle %p paddr %x", __func__,
+			i, meta_frame->frame.mp[i].fd,
+			meta_frame->map[i].handle,
+			(uint32_t)meta_frame->map[i].paddr);
+	}
+	D("%s Frame mapped successfully ", __func__);
+	return 0;
+}
+#else
+/* Unmap using PMEM APIs */
+static int __msm_mctl_unmap_user_frame(struct msm_cam_meta_frame *meta_frame,
+	struct ion_client *client, int domain_num)
+{
+	int i = 0, rc = 0;
+
+	for (i = 0; i < meta_frame->frame.num_planes; i++) {
+		D("%s Plane %d handle %p", __func__, i,
+			meta_frame->map[i].handle);
+		put_pmem_file(meta_frame->map[i].file);
+	}
+}
+
+/* Map using PMEM APIs */
+static int __msm_mctl_map_user_frame(struct msm_cam_meta_frame *meta_frame,
+	struct ion_client *client, int domain_num)
+{
+	unsigned long kvstart = 0;
+	unsigned long paddr = 0;
+	struct file *file = NULL;
+	unsigned long len;
+	int i = 0, j = 0;
+
+	for (i = 0; i < meta_frame->frame.num_planes; i++) {
+		rc = get_pmem_file(meta_frame->frame.mp[i].fd,
+			&paddr, &kvstart, &len, &file);
+		if (rc < 0) {
+			pr_err("%s: get_pmem_file fd %d error %d\n",
+				__func__, meta_frame->frame.mp[i].fd, rc);
+			/* Roll back previous plane mappings, if any */
+			for (j = i-1; j >= 0; j--)
+				if (meta_frame->map[j].file)
+					put_pmem_file(meta_frame->map[j].file);
+
+			return -EACCES;
+		}
+		D("%s Got pmem file for fd %d plane %d as %p", __func__,
+			meta_frame->frame.mp[i].fd, i, file);
+		meta_frame->map[i].file = file;
+		/* Validate the offsets with the mapped length. */
+		if ((meta_frame->frame.mp[i].addr_offset > len) ||
+			(meta_frame->frame.mp[i].data_offset +
+			meta_frame->frame.mp[i].length > len)) {
+			pr_err("%s: Invalid offsets A %d D %d L %d len %ld",
+				__func__, meta_frame->frame.mp[i].addr_offset,
+				meta_frame->frame.mp[i].data_offset,
+				meta_frame->frame.mp[i].length, len);
+			/* Roll back previous plane mappings, if any */
+			for (j = i; j >= 0; j--)
+				if (meta_frame->map[j].file)
+					put_pmem_file(meta_frame->map[j].file);
+
+			return -EINVAL;
+		}
+		meta_frame->map[i].data_offset =
+			meta_frame->frame.mp[i].data_offset;
+		/* Add the addr_offset to the paddr here itself. The addr_offset
+		 * will be non-zero only if the user has allocated a buffer with
+		 * a single fd, but logically partitioned it into
+		 * multiple planes or buffers.*/
+		paddr += meta_frame->frame.mp[i].addr_offset;
+		meta_frame->map[i].paddr = paddr;
+		meta_frame->map[i].len = len;
+		D("%s Plane %d fd %d handle %p paddr %x", __func__,
+			i, meta_frame->frame.mp[i].fd,
+			meta_frame->map[i].handle,
+			(uint32_t)meta_frame->map[i].paddr);
+	}
+	D("%s Frame mapped successfully ", __func__);
+	return 0;
+}
+#endif
+
+int msm_mctl_map_user_frame(struct msm_cam_meta_frame *meta_frame,
+	struct ion_client *client, int domain_num)
+{
+
+	if ((NULL == meta_frame) || (NULL == client)) {
+		pr_err("%s Invalid input ", __func__);
+		return -EINVAL;
+	}
+
+	memset(&meta_frame->map[0], 0,
+		sizeof(struct msm_cam_buf_map_info) * VIDEO_MAX_PLANES);
+
+	return __msm_mctl_map_user_frame(meta_frame, client, domain_num);
+}
+
+int msm_mctl_unmap_user_frame(struct msm_cam_meta_frame *meta_frame,
+	struct ion_client *client, int domain_num)
+{
+	if ((NULL == meta_frame) || (NULL == client)) {
+		pr_err("%s Invalid input ", __func__);
+		return -EINVAL;
+	}
+	__msm_mctl_unmap_user_frame(meta_frame, client, domain_num);
+	return 0;
+}
diff --git a/drivers/media/video/msm/msm_mctl_pp.c b/drivers/media/video/msm/msm_mctl_pp.c
index dcb7c51..a114b37 100644
--- a/drivers/media/video/msm/msm_mctl_pp.c
+++ b/drivers/media/video/msm/msm_mctl_pp.c
@@ -103,6 +103,10 @@
 		if (p_mctl->pp_info.pp_ctrl.pp_msg_type == OUTPUT_TYPE_T)
 			*pp_type = OUTPUT_TYPE_T;
 		break;
+	case MSM_V4L2_EXT_CAPTURE_MODE_RDI:
+		if (p_mctl->pp_info.pp_ctrl.pp_msg_type & OUTPUT_TYPE_R)
+			*pp_type = OUTPUT_TYPE_R;
+		break;
 	default:
 		break;
 	}
@@ -329,6 +333,7 @@
 	pp_frame->frame_id = vb->vidbuf.v4l2_buf.sequence;
 	pp_frame->timestamp = vb->vidbuf.v4l2_buf.timestamp;
 	pp_frame->buf_idx = buf_idx;
+	pp_frame->inst_handle = pcam_inst->inst_handle;
 	/* Get the cookie for 1st plane and store the path.
 	 * Also use this to check the number of planes in
 	 * this buffer.*/
@@ -364,49 +369,6 @@
 	return 0;
 }
 
-static int msm_mctl_pp_copy_timestamp_and_frame_id(
-	uint32_t src_handle, uint32_t dest_handle)
-{
-	struct msm_frame_buffer *src_vb;
-	struct msm_frame_buffer *dest_vb;
-
-	src_vb = (struct msm_frame_buffer *)src_handle;
-	dest_vb = (struct msm_frame_buffer *)dest_handle;
-	dest_vb->vidbuf.v4l2_buf.timestamp =
-		src_vb->vidbuf.v4l2_buf.timestamp;
-	dest_vb->vidbuf.v4l2_buf.sequence =
-		src_vb->vidbuf.v4l2_buf.sequence;
-	D("%s: timestamp=%ld:%ld,frame_id=0x%x", __func__,
-		dest_vb->vidbuf.v4l2_buf.timestamp.tv_sec,
-		dest_vb->vidbuf.v4l2_buf.timestamp.tv_usec,
-		dest_vb->vidbuf.v4l2_buf.sequence);
-	return 0;
-}
-
-static int msm_mctl_pp_path_to_inst_index(struct msm_cam_v4l2_device *pcam,
-					int out_type)
-{
-	int image_mode;
-	switch (out_type) {
-	case OUTPUT_TYPE_P:
-		image_mode = MSM_V4L2_EXT_CAPTURE_MODE_PREVIEW;
-		break;
-	case OUTPUT_TYPE_V:
-		image_mode = MSM_V4L2_EXT_CAPTURE_MODE_VIDEO;
-		break;
-	case OUTPUT_TYPE_S:
-		image_mode = MSM_V4L2_EXT_CAPTURE_MODE_MAIN;
-		break;
-	default:
-		image_mode = -1;
-		break;
-	}
-	if ((image_mode >= 0) && pcam->dev_inst_map[image_mode])
-		return pcam->dev_inst_map[image_mode]->my_index;
-	else
-		return -EINVAL;
-}
-
 static int msm_mctl_pp_path_to_img_mode(int path)
 {
 	switch (path) {
@@ -418,6 +380,16 @@
 		return MSM_V4L2_EXT_CAPTURE_MODE_MAIN;
 	case OUTPUT_TYPE_T:
 		return MSM_V4L2_EXT_CAPTURE_MODE_THUMBNAIL;
+	case OUTPUT_TYPE_SAEC:
+		return MSM_V4L2_EXT_CAPTURE_MODE_AEC;
+	case OUTPUT_TYPE_SAWB:
+		return MSM_V4L2_EXT_CAPTURE_MODE_AWB;
+	case OUTPUT_TYPE_SAFC:
+		return MSM_V4L2_EXT_CAPTURE_MODE_AF;
+	case OUTPUT_TYPE_IHST:
+		return MSM_V4L2_EXT_CAPTURE_MODE_IHIST;
+	case OUTPUT_TYPE_CSTA:
+		return MSM_V4L2_EXT_CAPTURE_MODE_CSTA;
 	default:
 		return -EINVAL;
 	}
@@ -437,8 +409,8 @@
 			ERR_COPY_FROM_USER();
 			return -EFAULT;
 		}
-		D("%s: PP_PATH, path=%d",
-			__func__, divert_pp.path);
+		D("%s: Divert Image mode =%d Enable %d",
+			__func__, divert_pp.path, divert_pp.enable);
 		spin_lock_irqsave(&p_mctl->pp_info.lock, flags);
 		if (divert_pp.enable)
 			p_mctl->pp_info.pp_ctrl.pp_msg_type |= divert_pp.path;
@@ -515,6 +487,8 @@
 		pr_err("%s Instance already closed ", __func__);
 		return -EINVAL;
 	}
+	D("%s Reserving free frame using %p inst handle %x ", __func__,
+		pcam_inst, div_frame.frame.inst_handle);
 	if (div_frame.frame.inst_handle) {
 		buf_handle.buf_lookup_type = BUF_LOOKUP_BY_INST_HANDLE;
 		buf_handle.inst_handle = div_frame.frame.inst_handle;
@@ -532,7 +506,7 @@
 			rc = -EFAULT;
 		}
 	}
-	D("%s: reserve free buf got buffer %d from %p rc = %d, phy = 0x%x",
+	D("%s: Got buffer %d from Inst %p rc = %d, phy = 0x%x",
 		__func__, div_frame.frame.buf_idx,
 		pcam_inst, rc, free_buf.ch_paddr[0]);
 	return rc;
@@ -615,6 +589,7 @@
 	struct msm_free_buf buf;
 	unsigned long flags;
 	struct msm_cam_buf_handle buf_handle;
+	struct msm_cam_return_frame_info ret_frame;
 
 	if (copy_from_user(&frame, arg, sizeof(frame))) {
 		ERR_COPY_FROM_USER();
@@ -657,7 +632,11 @@
 			buf.ch_paddr[0] = frame.sp.phy_addr + frame.sp.y_off;
 	}
 	spin_unlock_irqrestore(&p_mctl->pp_info.lock, flags);
-	rc = msm_mctl_buf_done_pp(p_mctl, &buf_handle, &buf, dirty, 0);
+
+	ret_frame.dirty = dirty;
+	ret_frame.node_type = 0;
+	ret_frame.timestamp = frame.timestamp;
+	rc = msm_mctl_buf_done_pp(p_mctl, &buf_handle, &buf, &ret_frame);
 	return rc;
 }
 
@@ -666,11 +645,11 @@
 	void __user *arg)
 {
 	struct msm_pp_frame frame;
-	int msg_type, image_mode, rc = 0;
-	int dirty = 0;
+	int rc = 0;
 	struct msm_free_buf buf;
 	unsigned long flags;
 	struct msm_cam_buf_handle buf_handle;
+	struct msm_cam_return_frame_info ret_frame;
 
 	D("%s enter\n", __func__);
 
@@ -680,35 +659,12 @@
 	}
 
 	spin_lock_irqsave(&p_mctl->pp_info.lock, flags);
-	D("%s Frame path: %d\n", __func__, frame.path);
-	switch (frame.path) {
-	case OUTPUT_TYPE_P:
-		msg_type = VFE_MSG_OUTPUT_P;
-		image_mode = MSM_V4L2_EXT_CAPTURE_MODE_PREVIEW;
-		break;
-	case OUTPUT_TYPE_S:
-		msg_type = VFE_MSG_OUTPUT_S;
-		image_mode = MSM_V4L2_EXT_CAPTURE_MODE_MAIN;
-		break;
-	case OUTPUT_TYPE_V:
-		msg_type = VFE_MSG_OUTPUT_V;
-		image_mode = MSM_V4L2_EXT_CAPTURE_MODE_VIDEO;
-		break;
-	case OUTPUT_TYPE_T:
-		msg_type = VFE_MSG_OUTPUT_T;
-		image_mode = MSM_V4L2_EXT_CAPTURE_MODE_THUMBNAIL;
-		break;
-	default:
-		rc = -EFAULT;
-		goto err;
-	}
-
 	if (frame.inst_handle) {
 		buf_handle.buf_lookup_type = BUF_LOOKUP_BY_INST_HANDLE;
 		buf_handle.inst_handle = frame.inst_handle;
 	} else {
 		buf_handle.buf_lookup_type = BUF_LOOKUP_BY_IMG_MODE;
-		buf_handle.image_mode = image_mode;
+		buf_handle.image_mode = frame.image_type;
 	}
 
 	if (frame.num_planes > 1)
@@ -718,12 +674,12 @@
 		buf.ch_paddr[0] = frame.sp.phy_addr + frame.sp.y_off;
 
 	spin_unlock_irqrestore(&p_mctl->pp_info.lock, flags);
+
+	ret_frame.dirty = 0;
+	ret_frame.node_type = frame.node_type;
+	ret_frame.timestamp = frame.timestamp;
 	D("%s Frame done id: %d\n", __func__, frame.frame_id);
-	rc = msm_mctl_buf_done_pp(p_mctl, &buf_handle,
-		&buf, dirty, frame.node_type);
-	return rc;
-err:
-	spin_unlock_irqrestore(&p_mctl->pp_info.lock, flags);
+	rc = msm_mctl_buf_done_pp(p_mctl, &buf_handle, &buf, &ret_frame);
 	return rc;
 }
 
@@ -755,54 +711,3 @@
 
 	return rc;
 }
-
-int msm_mctl_pp_get_vpe_buf_info(struct msm_mctl_pp_frame_info *zoom)
-{
-	struct msm_cam_media_controller *p_mctl;
-	struct msm_cam_v4l2_dev_inst *pcam_inst;
-	int rc = 0, idx;
-
-	if (!zoom || !zoom->p_mctl) {
-		pr_err("%s Invalid input, not sending buffer to VPE ",
-			__func__);
-		return -EINVAL;
-	}
-	p_mctl = zoom->p_mctl;
-	idx = msm_mctl_pp_path_to_inst_index(p_mctl->pcam_ptr,
-		zoom->pp_frame_cmd.path);
-	if (idx < 0) {
-		pr_err("%s Invalid path, returning\n", __func__);
-		return idx;
-	}
-	pcam_inst = p_mctl->pcam_ptr->dev_inst[idx];
-	if (!pcam_inst) {
-		pr_err("%s Invalid instance, returning\n", __func__);
-		return -EINVAL;
-	}
-
-	rc = msm_mctl_pp_get_phy_addr(pcam_inst,
-		zoom->pp_frame_cmd.src_buf_handle, &zoom->src_frame);
-	if (rc) {
-		pr_err("%s Error getting buffer address for src frame\n",
-			__func__);
-		return rc;
-	}
-
-	rc = msm_mctl_pp_get_phy_addr(pcam_inst,
-		zoom->pp_frame_cmd.dest_buf_handle, &zoom->dest_frame);
-	if (rc) {
-		pr_err("%s Error getting buffer address for dest frame\n",
-			__func__);
-		return rc;
-	}
-
-	rc = msm_mctl_pp_copy_timestamp_and_frame_id(
-		zoom->pp_frame_cmd.src_buf_handle,
-		zoom->pp_frame_cmd.dest_buf_handle);
-	if (rc < 0) {
-		pr_err("%s Error copying timestamp info\n",
-			__func__);
-		return rc;
-	}
-	return rc;
-}
diff --git a/drivers/media/video/msm/msm_mem.c b/drivers/media/video/msm/msm_mem.c
index e2e9d1b..5136d9d 100644
--- a/drivers/media/video/msm/msm_mem.c
+++ b/drivers/media/video/msm/msm_mem.c
@@ -116,7 +116,7 @@
 }
 
 static int msm_pmem_table_add(struct hlist_head *ptype,
-	struct msm_pmem_info *info, struct ion_client *client)
+	struct msm_pmem_info *info, struct ion_client *client, int domain_num)
 {
 	unsigned long paddr;
 #ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
@@ -135,7 +135,7 @@
 	region->handle = ion_import_dma_buf(client, info->fd);
 	if (IS_ERR_OR_NULL(region->handle))
 		goto out1;
-	if (ion_map_iommu(client, region->handle, CAMERA_DOMAIN, GEN_POOL,
+	if (ion_map_iommu(client, region->handle, domain_num, 0,
 				  SZ_4K, 0, &paddr, &len, UNCACHED, 0) < 0)
 		goto out2;
 #elif CONFIG_ANDROID_PMEM
@@ -180,7 +180,7 @@
 	return 0;
 out3:
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
-	ion_unmap_iommu(client, region->handle, CAMERA_DOMAIN, GEN_POOL);
+	ion_unmap_iommu(client, region->handle, domain_num, 0);
 #endif
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 out2:
@@ -195,7 +195,8 @@
 }
 
 static int __msm_register_pmem(struct hlist_head *ptype,
-			struct msm_pmem_info *pinfo, struct ion_client *client)
+			struct msm_pmem_info *pinfo, struct ion_client *client,
+			int domain_num)
 {
 	int rc = 0;
 
@@ -211,7 +212,7 @@
 	case MSM_PMEM_BAYER_GRID:
 	case MSM_PMEM_BAYER_FOCUS:
 	case MSM_PMEM_BAYER_HIST:
-		rc = msm_pmem_table_add(ptype, pinfo, client);
+		rc = msm_pmem_table_add(ptype, pinfo, client, domain_num);
 		break;
 
 	default:
@@ -223,7 +224,8 @@
 }
 
 static int __msm_pmem_table_del(struct hlist_head *ptype,
-			struct msm_pmem_info *pinfo, struct ion_client *client)
+			struct msm_pmem_info *pinfo, struct ion_client *client,
+			int domain_num)
 {
 	int rc = 0;
 	struct msm_pmem_region *region;
@@ -250,7 +252,7 @@
 				hlist_del(node);
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 				ion_unmap_iommu(client, region->handle,
-					CAMERA_DOMAIN, GEN_POOL);
+					domain_num, 0);
 				ion_free(client, region->handle);
 #else
 				put_pmem_file(region->file);
@@ -394,7 +396,8 @@
 }
 
 int msm_register_pmem(struct hlist_head *ptype, void __user *arg,
-					  struct ion_client *client)
+					struct ion_client *client,
+					int domain_num)
 {
 	struct msm_pmem_info info;
 
@@ -403,12 +406,12 @@
 			return -EFAULT;
 	}
 
-	return __msm_register_pmem(ptype, &info, client);
+	return __msm_register_pmem(ptype, &info, client, domain_num);
 }
 //EXPORT_SYMBOL(msm_register_pmem);
 
 int msm_pmem_table_del(struct hlist_head *ptype, void __user *arg,
-					   struct ion_client *client)
+			struct ion_client *client, int domain_num)
 {
 	struct msm_pmem_info info;
 
@@ -417,6 +420,6 @@
 		return -EFAULT;
 	}
 
-	return __msm_pmem_table_del(ptype, &info, client);
+	return __msm_pmem_table_del(ptype, &info, client, domain_num);
 }
 //EXPORT_SYMBOL(msm_pmem_table_del);
diff --git a/drivers/media/video/msm/msm_vpe.c b/drivers/media/video/msm/msm_vpe.c
index 5990ca7..ede0f7a 100644
--- a/drivers/media/video/msm/msm_vpe.c
+++ b/drivers/media/video/msm/msm_vpe.c
@@ -36,8 +36,8 @@
 #define D(fmt, args...) do {} while (0)
 #endif
 
-static int vpe_enable(uint32_t);
-static int vpe_disable(void);
+static int vpe_enable(uint32_t, struct msm_cam_media_controller *);
+static int vpe_disable(struct msm_cam_media_controller *);
 static int vpe_update_scaler(struct msm_pp_crop *pcrop);
 struct vpe_ctrl_type *vpe_ctrl;
 static atomic_t vpe_init_done = ATOMIC_INIT(0);
@@ -425,29 +425,37 @@
 	int rc = 0;
 	unsigned long flags;
 	unsigned long srcP0, srcP1, outP0, outP1;
-	struct msm_mctl_pp_frame_info *frame = vpe_ctrl->pp_frame_info;
+	struct msm_mctl_pp_frame_info *frame_info = vpe_ctrl->pp_frame_info;
+
+	if (!frame_info) {
+		pr_err("%s Invalid frame", __func__);
+		return -EINVAL;
+	}
 
 	spin_lock_irqsave(&vpe_ctrl->lock, flags);
-	if (frame->src_frame.num_planes > 1) {
-		srcP0 = vpe_ctrl->pp_frame_info->src_frame.mp[0].phy_addr +
-			vpe_ctrl->pp_frame_info->src_frame.mp[0].data_offset;
-		srcP1 = vpe_ctrl->pp_frame_info->src_frame.mp[1].phy_addr +
-			vpe_ctrl->pp_frame_info->src_frame.mp[1].data_offset;
-		outP0 = vpe_ctrl->pp_frame_info->dest_frame.mp[0].phy_addr +
-			vpe_ctrl->pp_frame_info->dest_frame.mp[0].data_offset;
-		outP1 = vpe_ctrl->pp_frame_info->dest_frame.mp[1].phy_addr +
-			vpe_ctrl->pp_frame_info->dest_frame.mp[1].data_offset;
+
+	if (frame_info->src_frame.frame.num_planes > 1) {
+		srcP0 = frame_info->src_frame.map[0].paddr +
+			frame_info->src_frame.map[0].data_offset;
+		srcP1 = frame_info->src_frame.map[1].paddr +
+			frame_info->src_frame.map[1].data_offset;
+		outP0 = frame_info->dest_frame.map[0].paddr +
+			frame_info->dest_frame.map[0].data_offset;
+		outP1 = frame_info->dest_frame.map[1].paddr +
+			frame_info->dest_frame.map[1].data_offset;
 	} else {
-		srcP0 = vpe_ctrl->pp_frame_info->src_frame.sp.phy_addr +
-			vpe_ctrl->pp_frame_info->src_frame.sp.y_off;
-		srcP1 = vpe_ctrl->pp_frame_info->src_frame.sp.phy_addr +
-			vpe_ctrl->pp_frame_info->src_frame.sp.cbcr_off;
-		outP0 = vpe_ctrl->pp_frame_info->dest_frame.sp.phy_addr +
-			vpe_ctrl->pp_frame_info->dest_frame.sp.y_off;
-		outP1 = vpe_ctrl->pp_frame_info->dest_frame.sp.phy_addr +
-			vpe_ctrl->pp_frame_info->dest_frame.sp.cbcr_off;
+		srcP0 = frame_info->src_frame.map[0].paddr;
+		srcP1 = frame_info->src_frame.map[0].paddr +
+			frame_info->src_frame.map[0].data_offset;
+		outP0 = frame_info->dest_frame.map[0].paddr;
+		outP1 = frame_info->dest_frame.map[0].paddr +
+			frame_info->dest_frame.map[0].data_offset;
 	}
 
+	D("%s VPE Configured with Src %x, %x Dest %x, %x",
+		__func__, (uint32_t)srcP0, (uint32_t)srcP1,
+		(uint32_t)outP0, (uint32_t)outP1);
+
 	msm_camera_io_w(srcP0, vpe_ctrl->vpebase + VPE_SRCP0_ADDR_OFFSET);
 	msm_camera_io_w(srcP1, vpe_ctrl->vpebase + VPE_SRCP1_ADDR_OFFSET);
 	msm_camera_io_w(outP0, vpe_ctrl->vpebase + VPE_OUTP0_ADDR_OFFSET);
@@ -482,7 +490,6 @@
 	v4l2_evt.type = V4L2_EVENT_PRIVATE_START + MSM_CAM_RESP_MCTL_PP_EVENT;
 	v4l2_evt.id = 0;
 	v4l2_event_queue(vpe_ctrl->subdev.devnode, &v4l2_evt);
-
 	spin_unlock_irqrestore(&vpe_ctrl->lock, flags);
 }
 
@@ -513,7 +520,7 @@
 	{"vpe_pclk", -1},
 };
 
-int vpe_enable(uint32_t clk_rate)
+int vpe_enable(uint32_t clk_rate, struct msm_cam_media_controller *mctl)
 {
 	int rc = 0;
 	unsigned long flags = 0;
@@ -542,8 +549,27 @@
 	if (rc < 0)
 		goto vpe_clk_failed;
 
+#ifdef CONFIG_MSM_IOMMU
+	rc = iommu_attach_device(mctl->domain, vpe_ctrl->iommu_ctx_src);
+	if (rc < 0) {
+		pr_err("%s: Device attach failed\n", __func__);
+		goto src_attach_failed;
+	}
+	rc = iommu_attach_device(mctl->domain, vpe_ctrl->iommu_ctx_dst);
+	if (rc < 0) {
+		pr_err("%s: Device attach failed\n", __func__);
+		goto dst_attach_failed;
+	}
+#endif
 	return rc;
 
+#ifdef CONFIG_MSM_IOMMU
+dst_attach_failed:
+	iommu_detach_device(mctl->domain, vpe_ctrl->iommu_ctx_src);
+src_attach_failed:
+#endif
+	msm_cam_clk_enable(&vpe_ctrl->pdev->dev, vpe_clk_info,
+		vpe_ctrl->vpe_clk, ARRAY_SIZE(vpe_clk_info), 0);
 vpe_clk_failed:
 	if (vpe_ctrl->fs_vpe)
 		regulator_disable(vpe_ctrl->fs_vpe);
@@ -553,7 +579,7 @@
 	return rc;
 }
 
-int vpe_disable(void)
+int vpe_disable(struct msm_cam_media_controller *mctl)
 {
 	int rc = 0;
 	unsigned long flags = 0;
@@ -565,7 +591,10 @@
 		return rc;
 	}
 	spin_unlock_irqrestore(&vpe_ctrl->lock, flags);
-
+#ifdef CONFIG_MSM_IOMMU
+	iommu_detach_device(mctl->domain, vpe_ctrl->iommu_ctx_dst);
+	iommu_detach_device(mctl->domain, vpe_ctrl->iommu_ctx_src);
+#endif
 	disable_irq(vpe_ctrl->vpeirq->start);
 	tasklet_kill(&vpe_tasklet);
 	msm_cam_clk_enable(&vpe_ctrl->pdev->dev, vpe_clk_info,
@@ -596,8 +625,8 @@
 	msm_vpe_cfg_update(
 		&vpe_ctrl->pp_frame_info->pp_frame_cmd.crop);
 	D("%s Sending frame idx %d id %d to VPE ", __func__,
-		pp_frame_info->src_frame.buf_idx,
-		pp_frame_info->src_frame.frame_id);
+		pp_frame_info->src_frame.frame.buf_idx,
+		pp_frame_info->src_frame.frame.frame_id);
 	rc = msm_send_frame_to_vpe();
 	return rc;
 }
@@ -648,23 +677,25 @@
 	return rc;  /* this rc should have error code. */
 }
 
-void msm_vpe_subdev_release(void)
+void msm_vpe_subdev_release(struct v4l2_subdev *sd)
 {
+	struct msm_cam_media_controller *mctl;
+	mctl = v4l2_get_subdev_hostdata(sd);
 	if (!atomic_read(&vpe_init_done)) {
 		/* no VPE object created */
 		pr_err("%s: no VPE object to release", __func__);
 		return;
 	}
-
 	vpe_reset();
-	vpe_disable();
+	vpe_disable(mctl);
 	iounmap(vpe_ctrl->vpebase);
 	vpe_ctrl->vpebase = NULL;
 	atomic_set(&vpe_init_done, 0);
 }
 EXPORT_SYMBOL(msm_vpe_subdev_release);
 
-static int msm_vpe_process_vpe_cmd(struct msm_vpe_cfg_cmd *vpe_cmd)
+static int msm_vpe_process_vpe_cmd(struct msm_vpe_cfg_cmd *vpe_cmd,
+				struct msm_cam_media_controller *mctl)
 {
 	int rc = 0;
 
@@ -787,19 +818,35 @@
 
 		zoom->user_cmd = vpe_cmd->cmd_type;
 		zoom->p_mctl = v4l2_get_subdev_hostdata(&vpe_ctrl->subdev);
-		D("%s: src=0x%x, dest=0x%x,cookie=0x%x,action=0x%x,path=0x%x",
-			__func__, zoom->pp_frame_cmd.src_buf_handle,
-			zoom->pp_frame_cmd.dest_buf_handle,
-			zoom->pp_frame_cmd.cookie,
+		D("%s: cookie=0x%x,action=0x%x,path=0x%x",
+			__func__, zoom->pp_frame_cmd.cookie,
 			zoom->pp_frame_cmd.vpe_output_action,
 			zoom->pp_frame_cmd.path);
-		rc = msm_mctl_pp_get_vpe_buf_info(zoom);
+
+		D("%s Mapping Source frame ", __func__);
+		zoom->src_frame.frame = zoom->pp_frame_cmd.src_frame;
+		rc = msm_mctl_map_user_frame(&zoom->src_frame,
+			zoom->p_mctl->client, mctl->domain_num);
 		if (rc < 0) {
-			pr_err("%s Error getting buffer info from mctl rc = %d",
+			pr_err("%s Error mapping source buffer rc = %d",
 				__func__, rc);
 			kfree(zoom);
 			break;
 		}
+
+		D("%s Mapping Destination frame ", __func__);
+		zoom->dest_frame.frame = zoom->pp_frame_cmd.dest_frame;
+		rc = msm_mctl_map_user_frame(&zoom->dest_frame,
+			zoom->p_mctl->client, mctl->domain_num);
+		if (rc < 0) {
+			pr_err("%s Error mapping dest buffer rc = %d",
+				__func__, rc);
+			msm_mctl_unmap_user_frame(&zoom->src_frame,
+				zoom->p_mctl->client, mctl->domain_num);
+			kfree(zoom);
+			break;
+		}
+
 		rc = msm_vpe_do_pp(zoom);
 		break;
 		}
@@ -820,13 +867,13 @@
 			return -EFAULT;
 		}
 		turbo_mode = (int)clk_rate.rate;
-		rc = turbo_mode ? vpe_enable(VPE_TURBO_MODE_CLOCK_RATE) :
-				vpe_enable(VPE_NORMAL_MODE_CLOCK_RATE);
+		rc = turbo_mode ? vpe_enable(VPE_TURBO_MODE_CLOCK_RATE, mctl) :
+				vpe_enable(VPE_NORMAL_MODE_CLOCK_RATE, mctl);
 		break;
 		}
 
 	case VPE_CMD_DISABLE:
-		rc = vpe_disable();
+		rc = vpe_disable(mctl);
 		break;
 
 	default:
@@ -841,7 +888,8 @@
 {
 	struct msm_vpe_cfg_cmd *vpe_cmd;
 	int rc = 0;
-
+	struct msm_cam_media_controller *mctl;
+	mctl = v4l2_get_subdev_hostdata(sd);
 	switch (cmd) {
 	case VIDIOC_MSM_VPE_INIT: {
 		msm_vpe_subdev_init(sd);
@@ -849,12 +897,12 @@
 		}
 
 	case VIDIOC_MSM_VPE_RELEASE:
-		msm_vpe_subdev_release();
+		msm_vpe_subdev_release(sd);
 		break;
 
 	case MSM_CAM_V4L2_IOCTL_CFG_VPE: {
 		vpe_cmd = (struct msm_vpe_cfg_cmd *)arg;
-		rc = msm_vpe_process_vpe_cmd(vpe_cmd);
+		rc = msm_vpe_process_vpe_cmd(vpe_cmd, mctl);
 		if (rc < 0) {
 			pr_err("%s Error processing VPE cmd %d ",
 				__func__, vpe_cmd->cmd_type);
@@ -876,6 +924,14 @@
 			return -EFAULT;
 		}
 		pp_frame_info = event_qcmd->command;
+
+		D("%s Unmapping source and destination buffers ",
+			__func__);
+		msm_mctl_unmap_user_frame(&pp_frame_info->src_frame,
+			pp_frame_info->p_mctl->client, mctl->domain_num);
+		msm_mctl_unmap_user_frame(&pp_frame_info->dest_frame,
+			pp_frame_info->p_mctl->client, mctl->domain_num);
+
 		pp_event_info.event = MCTL_PP_EVENT_CMD_ACK;
 		pp_event_info.ack.cmd = pp_frame_info->user_cmd;
 		pp_event_info.ack.status = 0;
@@ -884,10 +940,9 @@
 			pp_event_info.ack.cmd, pp_event_info.ack.status,
 			pp_event_info.ack.cookie);
 		if (copy_to_user((void __user *)v4l2_ioctl->ioctl_ptr,
-			&pp_event_info,
-			sizeof(struct msm_mctl_pp_event_info)))
-			pr_err("%s EVENTPAYLOAD Copy to user failed ",
-				__func__);
+			&pp_event_info,	sizeof(struct msm_mctl_pp_event_info)))
+			pr_err("%s PAYLOAD Copy to user failed ", __func__);
+
 		kfree(pp_frame_info);
 		kfree(event_qcmd);
 		break;
@@ -942,12 +997,22 @@
 	struct v4l2_subdev_fh *fh)
 {
 	struct vpe_ctrl_type *vpe_ctrl = v4l2_get_subdevdata(sd);
+	struct msm_mctl_pp_frame_info *frame_info = vpe_ctrl->pp_frame_info;
+	struct msm_cam_media_controller *mctl;
+	mctl = v4l2_get_subdev_hostdata(sd);
 	if (atomic_read(&vpe_ctrl->active) == 0) {
 		pr_err("%s already closed\n", __func__);
 		return -EINVAL;
 	}
 
 	D("%s E ", __func__);
+	if (frame_info) {
+		D("%s Unmap the pending item from the queue ", __func__);
+		msm_mctl_unmap_user_frame(&frame_info->src_frame,
+			frame_info->p_mctl->client, mctl->domain_num);
+		msm_mctl_unmap_user_frame(&frame_info->dest_frame,
+			frame_info->p_mctl->client, mctl->domain_num);
+	}
 	/* Drain the payload queue. */
 	msm_queue_drain(&vpe_ctrl->eventData_q, list_eventdata);
 	atomic_dec(&vpe_ctrl->active);
@@ -1027,6 +1092,19 @@
 
 	disable_irq(vpe_ctrl->vpeirq->start);
 
+#ifdef CONFIG_MSM_IOMMU
+	/*get device context for IOMMU*/
+	vpe_ctrl->iommu_ctx_src = msm_iommu_get_ctx("vpe_src"); /*re-confirm*/
+	vpe_ctrl->iommu_ctx_dst = msm_iommu_get_ctx("vpe_dst"); /*re-confirm*/
+	if (!vpe_ctrl->iommu_ctx_src || !vpe_ctrl->iommu_ctx_dst) {
+		release_mem_region(vpe_ctrl->vpemem->start,
+			resource_size(vpe_ctrl->vpemem));
+		pr_err("%s: No iommu fw context found\n", __func__);
+		rc = -ENODEV;
+		goto vpe_no_resource;
+	}
+#endif
+
 	atomic_set(&vpe_ctrl->active, 0);
 	vpe_ctrl->pdev = pdev;
 	sd_info.sdev_type = VPE_DEV;
diff --git a/drivers/media/video/msm/msm_vpe.h b/drivers/media/video/msm/msm_vpe.h
index 6516ea1..aad2380 100644
--- a/drivers/media/video/msm/msm_vpe.h
+++ b/drivers/media/video/msm/msm_vpe.h
@@ -121,6 +121,8 @@
 	struct msm_mctl_pp_frame_info *pp_frame_info;
 	atomic_t active;
 	struct msm_device_queue eventData_q; /*V4L2 Event Payload Queue*/
+	struct device *iommu_ctx_src;
+	struct device *iommu_ctx_dst;
 };
 
 /*
diff --git a/drivers/media/video/msm/sensors/Makefile b/drivers/media/video/msm/sensors/Makefile
index 5f3f6dd..cd228a1 100644
--- a/drivers/media/video/msm/sensors/Makefile
+++ b/drivers/media/video/msm/sensors/Makefile
@@ -3,12 +3,11 @@
 EXTRA_CFLAGS += -Idrivers/media/video/msm/io
 EXTRA_CFLAGS += -Idrivers/media/video/msm/eeprom
 EXTRA_CFLAGS += -Idrivers/media/video/msm/csi
-obj-$(CONFIG_MSM_CAMERA_SENSOR) += msm_sensor.o
+obj-$(CONFIG_MSM_CAMERA_SENSOR) += msm_sensor_common.o msm_sensor.o msm_sensor_bayer.o msm_sensor_init.o
 obj-$(CONFIG_OV5647) += ov5647_v4l2.o
 obj-$(CONFIG_OV8825) += ov8825_v4l2.o
 obj-$(CONFIG_IMX074) += imx074_v4l2.o
 obj-$(CONFIG_S5K3L1YX) += s5k3l1yx.o
-obj-$(CONFIG_IMX091) += imx091.o
 obj-$(CONFIG_OV2720) += ov2720.o
 obj-$(CONFIG_MT9M114) += mt9m114_v4l2.o
 obj-$(CONFIG_S5K4E1) += s5k4e1_v4l2.o
diff --git a/drivers/media/video/msm/sensors/imx074_v4l2.c b/drivers/media/video/msm/sensors/imx074_v4l2.c
index ddf0754..91d4797 100644
--- a/drivers/media/video/msm/sensors/imx074_v4l2.c
+++ b/drivers/media/video/msm/sensors/imx074_v4l2.c
@@ -168,44 +168,6 @@
 	},
 };
 
-static struct msm_camera_csi_params imx074_csic_params = {
-	.data_format = CSI_10BIT,
-	.lane_cnt    = 4,
-	.lane_assign = 0xe4,
-	.dpcm_scheme = 0,
-	.settle_cnt  = 0x14,
-};
-
-static struct msm_camera_csi_params *imx074_csic_params_array[] = {
-	&imx074_csic_params,
-	&imx074_csic_params,
-};
-
-static struct msm_camera_csid_vc_cfg imx074_cid_cfg[] = {
-	{0, CSI_RAW10, CSI_DECODE_10BIT},
-	{1, CSI_EMBED_DATA, CSI_DECODE_8BIT},
-	{2, CSI_RESERVED_DATA_0, CSI_DECODE_8BIT},
-};
-
-static struct msm_camera_csi2_params imx074_csi_params = {
-	.csid_params = {
-		.lane_cnt = 4,
-		.lut_params = {
-			.num_cid = ARRAY_SIZE(imx074_cid_cfg),
-			.vc_cfg = imx074_cid_cfg,
-		},
-	},
-	.csiphy_params = {
-		.lane_cnt = 4,
-		.settle_cnt = 0x1B,
-	},
-};
-
-static struct msm_camera_csi2_params *imx074_csi_params_array[] = {
-	&imx074_csi_params,
-	&imx074_csi_params,
-};
-
 static struct msm_sensor_output_reg_addr_t imx074_reg_addr = {
 	.x_output = 0x34C,
 	.y_output = 0x34E,
@@ -224,6 +186,13 @@
 	.vert_offset = 3,
 };
 
+static enum msm_camera_vreg_name_t imx074_veg_seq[] = {
+	CAM_VDIG,
+	CAM_VIO,
+	CAM_VANA,
+	CAM_VAF,
+};
+
 static const struct i2c_device_id imx074_i2c_id[] = {
 	{SENSOR_NAME, (kernel_ulong_t)&imx074_s_ctrl},
 	{ }
@@ -302,12 +271,12 @@
 	.msm_sensor_reg = &imx074_regs,
 	.sensor_i2c_client = &imx074_sensor_i2c_client,
 	.sensor_i2c_addr = 0x34,
+	.vreg_seq = imx074_veg_seq,
+	.num_vreg_seq = ARRAY_SIZE(imx074_veg_seq),
 	.sensor_output_reg_addr = &imx074_reg_addr,
 	.sensor_id_info = &imx074_id_info,
 	.sensor_exp_gain_info = &imx074_exp_gain_info,
 	.cam_mode = MSM_SENSOR_MODE_INVALID,
-	.csic_params = &imx074_csic_params_array[0],
-	.csi_params = &imx074_csi_params_array[0],
 	.msm_sensor_mutex = &imx074_mut,
 	.sensor_i2c_driver = &imx074_i2c_driver,
 	.sensor_v4l2_subdev_info = imx074_subdev_info,
diff --git a/drivers/media/video/msm/sensors/imx091.c b/drivers/media/video/msm/sensors/imx091.c
deleted file mode 100644
index 7fda037..0000000
--- a/drivers/media/video/msm/sensors/imx091.c
+++ /dev/null
@@ -1,347 +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 "msm_sensor.h"
-#define SENSOR_NAME "imx091"
-#define PLATFORM_DRIVER_NAME "msm_camera_imx091"
-#define imx091_obj imx091_##obj
-
-DEFINE_MUTEX(imx091_mut);
-static struct msm_sensor_ctrl_t imx091_s_ctrl;
-
-static struct msm_camera_i2c_reg_conf imx091_start_settings[] = {
-	{0x0100, 0x01},
-};
-
-static struct msm_camera_i2c_reg_conf imx091_stop_settings[] = {
-	{0x0100, 0x00},
-};
-
-static struct msm_camera_i2c_reg_conf imx091_groupon_settings[] = {
-	{0x0104, 0x01},
-};
-
-static struct msm_camera_i2c_reg_conf imx091_groupoff_settings[] = {
-	{0x0104, 0x00},
-};
-
-static struct msm_camera_i2c_reg_conf imx091_prev_settings[] = {
-	/* 30fps 1/2 * 1/2 */
-	/* PLL setting */
-	{0x0305, 0x02}, /* pre_pll_clk_div[7:0] */
-	{0x0307, 0x2F}, /* pll_multiplier[7:0] */
-	{0x30A4, 0x02},
-	{0x303C, 0x4B},
-	/* mode setting */
-	{0x0340, 0x06}, /* frame_length_lines[15:8] */
-	{0x0341, 0x5A}, /* frame_length_lines[7:0] */
-	{0x0342, 0x12}, /* line_length_pck[15:8] */
-	{0x0343, 0x0C}, /* line_length_pck[7:0] */
-	{0x0344, 0x00}, /* x_addr_start[15:8] */
-	{0x0345, 0x08}, /* x_addr_start[7:0] */
-	{0x0346, 0x00}, /* y_addr_start[15:8] */
-	{0x0347, 0x30}, /* y_addr_start[7:0] */
-	{0x0348, 0x10}, /* x_addr_end[15:8] */
-	{0x0349, 0x77}, /* x_addr_end[7:0] */
-	{0x034A, 0x0C}, /* y_addr_end[15:8] */
-	{0x034B, 0x5F}, /* y_addr_end[7:0] */
-	{0x034C, 0x08}, /* x_output_size[15:8] */
-	{0x034D, 0x38}, /* x_output_size[7:0] */
-	{0x034E, 0x06}, /* y_output_size[15:8] */
-	{0x034F, 0x18}, /* y_output_size[7:0] */
-	{0x0381, 0x01}, /* x_even_inc[3:0] */
-	{0x0383, 0x03}, /* x_odd_inc[3:0] */
-	{0x0385, 0x01}, /* y_even_inc[7:0] */
-	{0x0387, 0x03}, /* y_odd_inc[7:0] */
-	{0x3040, 0x08},
-	{0x3041, 0x97},
-	{0x3048, 0x01},
-	{0x3064, 0x12},
-	{0x309B, 0x28},
-	{0x309E, 0x00},
-	{0x30D5, 0x09},
-	{0x30D6, 0x01},
-	{0x30D7, 0x01},
-	{0x30D8, 0x64},
-	{0x30D9, 0x89},
-	{0x30DE, 0x02},
-	{0x3102, 0x10},
-	{0x3103, 0x44},
-	{0x3104, 0x40},
-	{0x3105, 0x00},
-	{0x3106, 0x0D},
-	{0x3107, 0x01},
-	{0x310A, 0x0A},
-	{0x315C, 0x99},
-	{0x315D, 0x98},
-	{0x316E, 0x9A},
-	{0x316F, 0x99},
-	{0x3318, 0x73},
-};
-
-static struct msm_camera_i2c_reg_conf imx091_snap_settings[] = {
-	/* full size */
-	/* PLL setting */
-	{0x0305, 0x02}, /* pre_pll_clk_div[7:0] */
-	{0x0307, 0x2B}, /* pll_multiplier[7:0] */
-	{0x30A4, 0x02},
-	{0x303C, 0x4B},
-	/* mode setting */
-	{0x0340, 0x0C}, /* frame_length_lines[15:8] */
-	{0x0341, 0x8C}, /* frame_length_lines[7:0] */
-	{0x0342, 0x12}, /* line_length_pck[15:8] */
-	{0x0343, 0x0C}, /* line_length_pck[7:0] */
-	{0x0344, 0x00}, /* x_addr_start[15:8] */
-	{0x0345, 0x08}, /* x_addr_start[7:0] */
-	{0x0346, 0x00}, /* y_addr_start[15:8] */
-	{0x0347, 0x30}, /* y_addr_start[7:0] */
-	{0x0348, 0x10}, /* x_addr_end[15:8] */
-	{0x0349, 0x77}, /* x_addr_end[7:0] */
-	{0x034A, 0x0C}, /* y_addr_end[15:8] */
-	{0x034B, 0x5F}, /* y_addr_end[7:0] */
-	{0x034C, 0x10}, /* x_output_size[15:8] */
-	{0x034D, 0x70}, /* x_output_size[7:0] */
-	{0x034E, 0x0C}, /* y_output_size[15:8] */
-	{0x034F, 0x30}, /* y_output_size[7:0] */
-	{0x0381, 0x01}, /* x_even_inc[3:0] */
-	{0x0383, 0x01}, /* x_odd_inc[3:0] */
-	{0x0385, 0x01}, /* y_even_inc[7:0] */
-	{0x0387, 0x01}, /* y_odd_inc[7:0] */
-	{0x3040, 0x08},
-	{0x3041, 0x97},
-	{0x3048, 0x00},
-	{0x3064, 0x12},
-	{0x309B, 0x20},
-	{0x309E, 0x00},
-	{0x30D5, 0x00},
-	{0x30D6, 0x85},
-	{0x30D7, 0x2A},
-	{0x30D8, 0x64},
-	{0x30D9, 0x89},
-	{0x30DE, 0x00},
-	{0x3102, 0x10},
-	{0x3103, 0x44},
-	{0x3104, 0x40},
-	{0x3105, 0x00},
-	{0x3106, 0x0D},
-	{0x3107, 0x01},
-	{0x310A, 0x0A},
-	{0x315C, 0x99},
-	{0x315D, 0x98},
-	{0x316E, 0x9A},
-	{0x316F, 0x99},
-	{0x3318, 0x64},
-};
-
-static struct msm_camera_i2c_reg_conf imx091_recommend_settings[] = {
-	/* global setting */
-	{0x3087, 0x53},
-	{0x309D, 0x94},
-	{0x30A1, 0x08},
-	{0x30C7, 0x00},
-	{0x3115, 0x0E},
-	{0x3118, 0x42},
-	{0x311D, 0x34},
-	{0x3121, 0x0D},
-	{0x3212, 0xF2},
-	{0x3213, 0x0F},
-	{0x3215, 0x0F},
-	{0x3217, 0x0B},
-	{0x3219, 0x0B},
-	{0x321B, 0x0D},
-	{0x321D, 0x0D},
-	/* black level setting */
-	{0x3032, 0x40},
-};
-
-static struct v4l2_subdev_info imx091_subdev_info[] = {
-	{
-	.code   = V4L2_MBUS_FMT_SBGGR10_1X10,
-	.colorspace = V4L2_COLORSPACE_JPEG,
-	.fmt    = 1,
-	.order    = 0,
-	},
-	/* more can be supported, to be added later */
-};
-
-static struct msm_camera_i2c_conf_array imx091_init_conf[] = {
-	{&imx091_recommend_settings[0],
-	ARRAY_SIZE(imx091_recommend_settings), 0, MSM_CAMERA_I2C_BYTE_DATA}
-};
-
-static struct msm_camera_i2c_conf_array imx091_confs[] = {
-	{&imx091_snap_settings[0],
-	ARRAY_SIZE(imx091_snap_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
-	{&imx091_prev_settings[0],
-	ARRAY_SIZE(imx091_prev_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
-};
-
-static struct msm_sensor_output_info_t imx091_dimensions[] = {
-	{
-	/* full size */
-		.x_output = 0x1070, /* 4208 */
-		.y_output = 0x0C30, /* 3120 */
-		.line_length_pclk = 0x120C, /* 4620 */
-		.frame_length_lines = 0x0C8C, /* 3212 */
-		.vt_pixel_clk = 206400000,
-		.op_pixel_clk = 206400000,
-		.binning_factor = 1,
-	},
-	{
-	/* 30 fps 1/2 * 1/2 */
-		.x_output = 0x0838, /* 2104 */
-		.y_output = 0x0618, /* 1560 */
-		.line_length_pclk = 0x120C, /* 4620 */
-		.frame_length_lines = 0x065A, /* 1626 */
-		.vt_pixel_clk = 225600000,
-		.op_pixel_clk = 225600000,
-		.binning_factor = 1,
-	},
-};
-
-static struct msm_camera_csid_vc_cfg imx091_cid_cfg[] = {
-	{0, CSI_RAW10, CSI_DECODE_10BIT},
-	{1, CSI_EMBED_DATA, CSI_DECODE_8BIT},
-	{2, CSI_RESERVED_DATA_0, CSI_DECODE_8BIT},
-};
-
-static struct msm_camera_csi2_params imx091_csi_params = {
-	.csid_params = {
-		.lane_cnt = 4,
-		.lut_params = {
-			.num_cid = ARRAY_SIZE(imx091_cid_cfg),
-			.vc_cfg = imx091_cid_cfg,
-		},
-	},
-	.csiphy_params = {
-		.lane_cnt = 4,
-		.settle_cnt = 0x12,
-	},
-};
-
-static struct msm_camera_csi2_params *imx091_csi_params_array[] = {
-	&imx091_csi_params,
-	&imx091_csi_params,
-};
-
-static struct msm_sensor_output_reg_addr_t imx091_reg_addr = {
-	.x_output = 0x034C,
-	.y_output = 0x034E,
-	.line_length_pclk = 0x0342,
-	.frame_length_lines = 0x0340,
-};
-
-static struct msm_sensor_id_info_t imx091_id_info = {
-	.sensor_id_reg_addr = 0x0000,
-	.sensor_id = 0x0091,
-};
-
-static struct msm_sensor_exp_gain_info_t imx091_exp_gain_info = {
-	.coarse_int_time_addr = 0x0202,
-	.global_gain_addr = 0x0204,
-	.vert_offset = 5,
-};
-
-static const struct i2c_device_id imx091_i2c_id[] = {
-	{SENSOR_NAME, (kernel_ulong_t)&imx091_s_ctrl},
-	{ }
-};
-
-static struct i2c_driver imx091_i2c_driver = {
-	.id_table = imx091_i2c_id,
-	.probe  = msm_sensor_i2c_probe,
-	.driver = {
-		.name = SENSOR_NAME,
-	},
-};
-
-static struct msm_camera_i2c_client imx091_sensor_i2c_client = {
-	.addr_type = MSM_CAMERA_I2C_WORD_ADDR,
-};
-
-
-static int __init imx091_sensor_init_module(void)
-{
-	return i2c_add_driver(&imx091_i2c_driver);
-}
-
-static struct v4l2_subdev_core_ops imx091_subdev_core_ops = {
-	.ioctl = msm_sensor_subdev_ioctl,
-	.s_power = msm_sensor_power,
-};
-
-static struct v4l2_subdev_video_ops imx091_subdev_video_ops = {
-	.enum_mbus_fmt = msm_sensor_v4l2_enum_fmt,
-};
-
-static struct v4l2_subdev_ops imx091_subdev_ops = {
-	.core = &imx091_subdev_core_ops,
-	.video  = &imx091_subdev_video_ops,
-};
-
-static struct msm_sensor_fn_t imx091_func_tbl = {
-	.sensor_start_stream = msm_sensor_start_stream,
-	.sensor_stop_stream = msm_sensor_stop_stream,
-	.sensor_group_hold_on = msm_sensor_group_hold_on,
-	.sensor_group_hold_off = msm_sensor_group_hold_off,
-	.sensor_set_fps = msm_sensor_set_fps,
-	.sensor_write_exp_gain = msm_sensor_write_exp_gain1,
-	.sensor_write_snapshot_exp_gain = msm_sensor_write_exp_gain1,
-	.sensor_setting = msm_sensor_setting,
-	.sensor_set_sensor_mode = msm_sensor_set_sensor_mode,
-	.sensor_mode_init = msm_sensor_mode_init,
-	.sensor_get_output_info = msm_sensor_get_output_info,
-	.sensor_config = msm_sensor_config,
-	.sensor_power_up = msm_sensor_power_up,
-	.sensor_power_down = msm_sensor_power_down,
-	.sensor_adjust_frame_lines = msm_sensor_adjust_frame_lines1,
-	.sensor_get_csi_params = msm_sensor_get_csi_params,
-};
-
-static struct msm_sensor_reg_t imx091_regs = {
-	.default_data_type = MSM_CAMERA_I2C_BYTE_DATA,
-	.start_stream_conf = imx091_start_settings,
-	.start_stream_conf_size = ARRAY_SIZE(imx091_start_settings),
-	.stop_stream_conf = imx091_stop_settings,
-	.stop_stream_conf_size = ARRAY_SIZE(imx091_stop_settings),
-	.group_hold_on_conf = imx091_groupon_settings,
-	.group_hold_on_conf_size = ARRAY_SIZE(imx091_groupon_settings),
-	.group_hold_off_conf = imx091_groupoff_settings,
-	.group_hold_off_conf_size = ARRAY_SIZE(imx091_groupoff_settings),
-	.init_settings = &imx091_init_conf[0],
-	.init_size = ARRAY_SIZE(imx091_init_conf),
-	.mode_settings = &imx091_confs[0],
-	.output_settings = &imx091_dimensions[0],
-	.num_conf = ARRAY_SIZE(imx091_confs),
-};
-
-static struct msm_sensor_ctrl_t imx091_s_ctrl = {
-	.msm_sensor_reg = &imx091_regs,
-	.sensor_i2c_client = &imx091_sensor_i2c_client,
-	.sensor_i2c_addr = 0x34,
-	.sensor_output_reg_addr = &imx091_reg_addr,
-	.sensor_id_info = &imx091_id_info,
-	.sensor_exp_gain_info = &imx091_exp_gain_info,
-	.cam_mode = MSM_SENSOR_MODE_INVALID,
-	.csi_params = &imx091_csi_params_array[0],
-	.msm_sensor_mutex = &imx091_mut,
-	.sensor_i2c_driver = &imx091_i2c_driver,
-	.sensor_v4l2_subdev_info = imx091_subdev_info,
-	.sensor_v4l2_subdev_info_size = ARRAY_SIZE(imx091_subdev_info),
-	.sensor_v4l2_subdev_ops = &imx091_subdev_ops,
-	.func_tbl = &imx091_func_tbl,
-	.clk_rate = MSM_SENSOR_MCLK_24HZ,
-};
-
-module_init(imx091_sensor_init_module);
-MODULE_DESCRIPTION("SONY 12MP Bayer sensor driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/sensors/imx091.h b/drivers/media/video/msm/sensors/imx091.h
new file mode 100644
index 0000000..3618b4c
--- /dev/null
+++ b/drivers/media/video/msm/sensors/imx091.h
@@ -0,0 +1,101 @@
+/* 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 IMX091_SENSOR_NAME "imx091"
+DEFINE_MSM_MUTEX(imx091_mut);
+
+static struct msm_sensor_ctrl_t imx091_s_ctrl;
+
+static struct v4l2_subdev_info imx091_subdev_info[] = {
+	{
+	.code   = V4L2_MBUS_FMT_SBGGR10_1X10,
+	.colorspace = V4L2_COLORSPACE_JPEG,
+	.fmt    = 1,
+	.order    = 0,
+	},
+	/* more can be supported, to be added later */
+};
+
+static struct msm_sensor_id_info_t imx091_id_info = {
+	.sensor_id_reg_addr = 0x0000,
+	.sensor_id = 0x0091,
+};
+
+static enum msm_camera_vreg_name_t imx091_veg_seq[] = {
+	CAM_VANA,
+	CAM_VAF,
+	CAM_VDIG,
+	CAM_VIO,
+};
+
+static struct msm_camera_power_seq_t imx091_power_seq[] = {
+	{REQUEST_GPIO, 0},
+	{REQUEST_VREG, 0},
+	{ENABLE_VREG, 0},
+	{ENABLE_GPIO, 0},
+	{CONFIG_CLK, 1},
+	{CONFIG_I2C_MUX, 0},
+};
+
+static const struct i2c_device_id imx091_i2c_id[] = {
+	{IMX091_SENSOR_NAME, (kernel_ulong_t)&imx091_s_ctrl},
+	{ }
+};
+
+static struct i2c_driver imx091_i2c_driver = {
+	.id_table = imx091_i2c_id,
+	.probe  = msm_sensor_bayer_i2c_probe,
+	.driver = {
+		.name = IMX091_SENSOR_NAME,
+	},
+};
+
+static struct msm_camera_i2c_client imx091_sensor_i2c_client = {
+	.addr_type = MSM_CAMERA_I2C_WORD_ADDR,
+};
+
+static struct v4l2_subdev_core_ops imx091_subdev_core_ops = {
+	.ioctl = msm_sensor_bayer_subdev_ioctl,
+	.s_power = msm_sensor_bayer_power,
+};
+
+static struct v4l2_subdev_video_ops imx091_subdev_video_ops = {
+	.enum_mbus_fmt = msm_sensor_bayer_v4l2_enum_fmt,
+};
+
+static struct v4l2_subdev_ops imx091_subdev_ops = {
+	.core = &imx091_subdev_core_ops,
+	.video  = &imx091_subdev_video_ops,
+};
+
+static struct msm_sensor_fn_t imx091_func_tbl = {
+	.sensor_config = msm_sensor_bayer_config,
+	.sensor_power_up = msm_sensor_bayer_power_up,
+	.sensor_power_down = msm_sensor_bayer_power_down,
+	.sensor_get_csi_params = msm_sensor_bayer_get_csi_params,
+};
+
+static struct msm_sensor_ctrl_t imx091_s_ctrl = {
+	.sensor_i2c_client = &imx091_sensor_i2c_client,
+	.sensor_i2c_addr = 0x34,
+	.vreg_seq = imx091_veg_seq,
+	.num_vreg_seq = ARRAY_SIZE(imx091_veg_seq),
+	.power_seq = &imx091_power_seq[0],
+	.num_power_seq = ARRAY_SIZE(imx091_power_seq),
+	.sensor_id_info = &imx091_id_info,
+	.msm_sensor_mutex = &imx091_mut,
+	.sensor_v4l2_subdev_info = imx091_subdev_info,
+	.sensor_v4l2_subdev_info_size = ARRAY_SIZE(imx091_subdev_info),
+	.sensor_v4l2_subdev_ops = &imx091_subdev_ops,
+	.func_tbl = &imx091_func_tbl,
+	.clk_rate = MSM_SENSOR_MCLK_24HZ,
+};
diff --git a/drivers/media/video/msm/sensors/msm_sensor.c b/drivers/media/video/msm/sensors/msm_sensor.c
index f687573..999783e 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.c
+++ b/drivers/media/video/msm/sensors/msm_sensor.c
@@ -9,26 +9,20 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  */
-
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
 #include "msm_sensor.h"
+#include "msm_sensor_common.h"
 #include "msm.h"
 #include "msm_ispif.h"
 #include "msm_camera_i2c_mux.h"
 
 /*=============================================================*/
-int32_t msm_sensor_adjust_frame_lines1(struct msm_sensor_ctrl_t *s_ctrl,
-	uint16_t res)
+void msm_sensor_adjust_frame_lines1(struct msm_sensor_ctrl_t *s_ctrl)
 {
 	uint16_t cur_line = 0;
 	uint16_t exp_fl_lines = 0;
 	if (s_ctrl->sensor_exp_gain_info) {
-		if (s_ctrl->prev_gain && s_ctrl->prev_line &&
-			s_ctrl->func_tbl->sensor_write_exp_gain)
-			s_ctrl->func_tbl->sensor_write_exp_gain(
-				s_ctrl,
-				s_ctrl->prev_gain,
-				s_ctrl->prev_line);
-
 		msm_camera_i2c_read(s_ctrl->sensor_i2c_client,
 			s_ctrl->sensor_exp_gain_info->coarse_int_time_addr,
 			&cur_line,
@@ -36,7 +30,7 @@
 		exp_fl_lines = cur_line +
 			s_ctrl->sensor_exp_gain_info->vert_offset;
 		if (exp_fl_lines > s_ctrl->msm_sensor_reg->
-			output_settings[res].frame_length_lines)
+			output_settings[s_ctrl->curr_res].frame_length_lines)
 			msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
 				s_ctrl->sensor_output_reg_addr->
 				frame_length_lines,
@@ -44,26 +38,18 @@
 				MSM_CAMERA_I2C_WORD_DATA);
 		CDBG("%s cur_fl_lines %d, exp_fl_lines %d\n", __func__,
 			s_ctrl->msm_sensor_reg->
-			output_settings[res].frame_length_lines,
+			output_settings[s_ctrl->curr_res].frame_length_lines,
 			exp_fl_lines);
 	}
-	return 0;
+	return;
 }
 
-int32_t msm_sensor_adjust_frame_lines2(struct msm_sensor_ctrl_t *s_ctrl,
-	uint16_t res)
+void msm_sensor_adjust_frame_lines2(struct msm_sensor_ctrl_t *s_ctrl)
 {
 	uint16_t cur_line = 0;
 	uint16_t exp_fl_lines = 0;
 	uint8_t int_time[3];
 	if (s_ctrl->sensor_exp_gain_info) {
-		if (s_ctrl->prev_gain && s_ctrl->prev_line &&
-			s_ctrl->func_tbl->sensor_write_exp_gain)
-			s_ctrl->func_tbl->sensor_write_exp_gain(
-				s_ctrl,
-				s_ctrl->prev_gain,
-				s_ctrl->prev_line);
-
 		msm_camera_i2c_read_seq(s_ctrl->sensor_i2c_client,
 			s_ctrl->sensor_exp_gain_info->coarse_int_time_addr-1,
 			&int_time[0], 3);
@@ -73,7 +59,7 @@
 		exp_fl_lines = cur_line +
 			s_ctrl->sensor_exp_gain_info->vert_offset;
 		if (exp_fl_lines > s_ctrl->msm_sensor_reg->
-			output_settings[res].frame_length_lines)
+			output_settings[s_ctrl->curr_res].frame_length_lines)
 			msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
 				s_ctrl->sensor_output_reg_addr->
 				frame_length_lines,
@@ -83,10 +69,35 @@
 			__func__,
 			cur_line,
 			s_ctrl->msm_sensor_reg->
-			output_settings[res].frame_length_lines,
+			output_settings[s_ctrl->curr_res].frame_length_lines,
 			exp_fl_lines);
 	}
-	return 0;
+	return;
+}
+
+static void msm_sensor_delay_frames(struct msm_sensor_ctrl_t *s_ctrl)
+{
+	long fps = 0;
+	uint32_t delay = 0;
+
+	if (s_ctrl->curr_res < MSM_SENSOR_INVALID_RES &&
+		s_ctrl->wait_num_frames > 0) {
+		fps = s_ctrl->msm_sensor_reg->
+			output_settings[s_ctrl->curr_res].vt_pixel_clk /
+			s_ctrl->curr_frame_length_lines /
+			s_ctrl->curr_line_length_pclk;
+		if (fps == 0)
+			delay = s_ctrl->min_delay;
+		else
+			delay = (1000 * s_ctrl->wait_num_frames) / fps / Q10;
+	}
+	CDBG("%s fps = %ld, delay = %d, min_delay %d\n", __func__, fps,
+		delay, s_ctrl->min_delay);
+	if (delay > s_ctrl->min_delay)
+		msleep(delay);
+	else if (s_ctrl->min_delay)
+		msleep(s_ctrl->min_delay);
+	return;
 }
 
 int32_t msm_sensor_write_init_settings(struct msm_sensor_ctrl_t *s_ctrl)
@@ -113,9 +124,6 @@
 	if (rc < 0)
 		return rc;
 
-	if (s_ctrl->func_tbl->sensor_adjust_frame_lines)
-		rc = s_ctrl->func_tbl->sensor_adjust_frame_lines(s_ctrl, res);
-
 	return rc;
 }
 
@@ -145,11 +153,18 @@
 
 void msm_sensor_start_stream(struct msm_sensor_ctrl_t *s_ctrl)
 {
+	if (s_ctrl->curr_res >= s_ctrl->msm_sensor_reg->num_conf)
+		return;
+
+	if (s_ctrl->func_tbl->sensor_adjust_frame_lines)
+		s_ctrl->func_tbl->sensor_adjust_frame_lines(s_ctrl);
+
 	msm_camera_i2c_write_tbl(
 		s_ctrl->sensor_i2c_client,
 		s_ctrl->msm_sensor_reg->start_stream_conf,
 		s_ctrl->msm_sensor_reg->start_stream_conf_size,
 		s_ctrl->msm_sensor_reg->default_data_type);
+	msm_sensor_delay_frames(s_ctrl);
 }
 
 void msm_sensor_stop_stream(struct msm_sensor_ctrl_t *s_ctrl)
@@ -159,6 +174,7 @@
 		s_ctrl->msm_sensor_reg->stop_stream_conf,
 		s_ctrl->msm_sensor_reg->stop_stream_conf_size,
 		s_ctrl->msm_sensor_reg->default_data_type);
+	msm_sensor_delay_frames(s_ctrl);
 }
 
 void msm_sensor_group_hold_on(struct msm_sensor_ctrl_t *s_ctrl)
@@ -244,78 +260,38 @@
 			int update_type, int res)
 {
 	int32_t rc = 0;
-	static int csi_config;
 
-	s_ctrl->func_tbl->sensor_stop_stream(s_ctrl);
-	msleep(30);
 	if (update_type == MSM_SENSOR_REG_INIT) {
 		CDBG("Register INIT\n");
-		s_ctrl->curr_csi_params = NULL;
 		msm_sensor_enable_debugfs(s_ctrl);
+		s_ctrl->func_tbl->sensor_stop_stream(s_ctrl);
 		msm_sensor_write_init_settings(s_ctrl);
-		csi_config = 0;
 	} else if (update_type == MSM_SENSOR_UPDATE_PERIODIC) {
 		CDBG("PERIODIC : %d\n", res);
 		msm_sensor_write_conf_array(
 			s_ctrl->sensor_i2c_client,
 			s_ctrl->msm_sensor_reg->mode_settings, res);
 		msleep(30);
-		if (!csi_config) {
-			s_ctrl->curr_csic_params = s_ctrl->csic_params[res];
-			CDBG("CSI config in progress\n");
-			v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
-				NOTIFY_CSIC_CFG,
-				s_ctrl->curr_csic_params);
-			CDBG("CSI config is done\n");
-			mb();
-			msleep(30);
-			csi_config = 1;
-		}
 		v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
 			NOTIFY_PCLK_CHANGE,
 			&s_ctrl->sensordata->pdata->ioclk.vfe_clk_rate);
-
-		s_ctrl->func_tbl->sensor_start_stream(s_ctrl);
-		msleep(50);
 	}
 	return rc;
 }
+
 int32_t msm_sensor_setting(struct msm_sensor_ctrl_t *s_ctrl,
 			int update_type, int res)
 {
 	int32_t rc = 0;
-	s_ctrl->func_tbl->sensor_stop_stream(s_ctrl);
-	msleep(30);
+
 	if (update_type == MSM_SENSOR_REG_INIT) {
-		s_ctrl->curr_csi_params = NULL;
-		msm_sensor_enable_debugfs(s_ctrl);
+		s_ctrl->func_tbl->sensor_stop_stream(s_ctrl);
 		msm_sensor_write_init_settings(s_ctrl);
 	} else if (update_type == MSM_SENSOR_UPDATE_PERIODIC) {
 		msm_sensor_write_res_settings(s_ctrl, res);
-		if (s_ctrl->curr_csi_params != s_ctrl->csi_params[res]) {
-			s_ctrl->curr_csi_params = s_ctrl->csi_params[res];
-			s_ctrl->curr_csi_params->csid_params.lane_assign =
-				s_ctrl->sensordata->sensor_platform_info->
-				csi_lane_params->csi_lane_assign;
-			s_ctrl->curr_csi_params->csiphy_params.lane_mask =
-				s_ctrl->sensordata->sensor_platform_info->
-				csi_lane_params->csi_lane_mask;
-			v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
-				NOTIFY_CSID_CFG,
-				&s_ctrl->curr_csi_params->csid_params);
-			mb();
-			v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
-				NOTIFY_CSIPHY_CFG,
-				&s_ctrl->curr_csi_params->csiphy_params);
-			mb();
-			msleep(20);
-		}
-
 		v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
 			NOTIFY_PCLK_CHANGE, &s_ctrl->msm_sensor_reg->
 			output_settings[res].op_pixel_clk);
-		s_ctrl->func_tbl->sensor_start_stream(s_ctrl);
-		msleep(30);
 	}
 	return rc;
 }
@@ -385,21 +361,10 @@
 	return rc;
 }
 
-int32_t msm_sensor_release(struct msm_sensor_ctrl_t *s_ctrl)
+static int32_t msm_sensor_release(struct msm_sensor_ctrl_t *s_ctrl)
 {
-	long fps = 0;
-	uint32_t delay = 0;
 	CDBG("%s called\n", __func__);
 	s_ctrl->func_tbl->sensor_stop_stream(s_ctrl);
-	if (s_ctrl->curr_res != MSM_SENSOR_INVALID_RES) {
-		fps = s_ctrl->msm_sensor_reg->
-			output_settings[s_ctrl->curr_res].vt_pixel_clk /
-			s_ctrl->curr_frame_length_lines /
-			s_ctrl->curr_line_length_pclk;
-		delay = 1000 / fps;
-		CDBG("%s fps = %ld, delay = %d\n", __func__, fps, delay);
-		msleep(delay);
-	}
 	return 0;
 }
 
@@ -408,6 +373,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);
@@ -416,7 +383,6 @@
 	case VIDIOC_MSM_SENSOR_CSID_INFO: {
 		struct msm_sensor_csi_info *csi_info =
 			(struct msm_sensor_csi_info *)arg;
-		s_ctrl->csid_version = csi_info->csid_version;
 		s_ctrl->is_csic = csi_info->is_csic;
 		return 0;
 	}
@@ -428,14 +394,21 @@
 int32_t msm_sensor_get_csi_params(struct msm_sensor_ctrl_t *s_ctrl,
 		struct csi_lane_params_t *sensor_output_info)
 {
-	sensor_output_info->csi_lane_assign = s_ctrl->sensordata->
-		sensor_platform_info->csi_lane_params->csi_lane_assign;
-	sensor_output_info->csi_lane_mask = s_ctrl->sensordata->
-		sensor_platform_info->csi_lane_params->csi_lane_mask;
+	uint8_t index;
+	struct msm_camera_csi_lane_params *csi_lane_params =
+		s_ctrl->sensordata->sensor_platform_info->csi_lane_params;
+	if (csi_lane_params) {
+		sensor_output_info->csi_lane_assign = csi_lane_params->
+			csi_lane_assign;
+		sensor_output_info->csi_lane_mask = csi_lane_params->
+			csi_lane_mask;
+		sensor_output_info->csi_phy_sel = csi_lane_params->csi_phy_sel;
+	}
 	sensor_output_info->csi_if = s_ctrl->sensordata->csi_if;
-	sensor_output_info->csid_core = s_ctrl->sensordata->
-			pdata[0].csid_core;
-	sensor_output_info->csid_version = s_ctrl->csid_version;
+	for (index = 0; index < sensor_output_info->csi_if; index++)
+		sensor_output_info->csid_core[index] = s_ctrl->sensordata->
+			pdata[index].csid_core;
+
 	return 0;
 }
 
@@ -448,9 +421,9 @@
 		sizeof(struct sensor_cfg_data)))
 		return -EFAULT;
 	mutex_lock(s_ctrl->msm_sensor_mutex);
-	CDBG("msm_sensor_config: cfgtype = %d\n",
-	cdata.cfgtype);
-		switch (cdata.cfgtype) {
+	CDBG("%s:%d %s cfgtype = %d\n", __func__, __LINE__,
+		s_ctrl->sensordata->sensor_name, cdata.cfgtype);
+	switch (cdata.cfgtype) {
 		case CFG_SET_FPS:
 		case CFG_SET_PICT_FPS:
 			if (s_ctrl->func_tbl->
@@ -476,8 +449,6 @@
 					s_ctrl,
 					cdata.cfg.exp_gain.gain,
 					cdata.cfg.exp_gain.line);
-			s_ctrl->prev_gain = cdata.cfg.exp_gain.gain;
-			s_ctrl->prev_line = cdata.cfg.exp_gain.line;
 			break;
 
 		case CFG_SET_PICT_EXP_GAIN:
@@ -571,6 +542,22 @@
 				rc = -EFAULT;
 			break;
 
+		case CFG_POWER_UP:
+			pr_err("%s calling power up\n", __func__);
+			if (s_ctrl->func_tbl->sensor_power_up)
+				rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl);
+			else
+				rc = -EFAULT;
+			break;
+
+		case CFG_POWER_DOWN:
+			if (s_ctrl->func_tbl->sensor_power_down)
+				rc = s_ctrl->func_tbl->sensor_power_down(
+					s_ctrl);
+			else
+				rc = -EFAULT;
+			break;
+
 		default:
 			rc = -EFAULT;
 			break;
@@ -581,10 +568,15 @@
 	return rc;
 }
 
-static struct msm_cam_clk_info cam_clk_info[] = {
+static struct msm_cam_clk_info cam_8960_clk_info[] = {
 	{"cam_clk", MSM_SENSOR_MCLK_24HZ},
 };
 
+static struct msm_cam_clk_info cam_8974_clk_info[] = {
+	{"cam_src_clk", 19200000},
+	{"cam_clk", -1},
+};
+
 int32_t msm_sensor_enable_i2c_mux(struct msm_camera_i2c_conf *i2c_conf)
 {
 	struct v4l2_subdev *i2c_mux_sd =
@@ -618,8 +610,8 @@
 		return -ENOMEM;
 	}
 
-	rc = of_property_read_u32(of_node, "flash_type", &val);
-	CDBG("%s flash_type %d, rc %d\n", __func__, val, rc);
+	rc = of_property_read_u32(of_node, "qcom,flash-type", &val);
+	CDBG("%s qcom,flash-type %d, rc %d\n", __func__, val, rc);
 	if (rc < 0) {
 		pr_err("%s failed %d\n", __func__, __LINE__);
 		goto ERROR;
@@ -638,8 +630,8 @@
 	uint32_t count = 0;
 	uint32_t *val_array = NULL;
 
-	count = of_property_count_strings(of_node, "cam_vreg_name");
-	CDBG("%s cam_vreg_name count %d\n", __func__, count);
+	count = of_property_count_strings(of_node, "qcom,cam-vreg-name");
+	CDBG("%s qcom,cam-vreg-name count %d\n", __func__, count);
 
 	if (!count)
 		return 0;
@@ -653,8 +645,8 @@
 
 	pinfo->num_vreg = count;
 	for (i = 0; i < count; i++) {
-		rc = of_property_read_string_index(of_node, "cam_vreg_name", i,
-			&pinfo->cam_vreg[i].reg_name);
+		rc = of_property_read_string_index(of_node,
+			"qcom,cam-vreg-name", i, &pinfo->cam_vreg[i].reg_name);
 		CDBG("%s reg_name[%d] = %s\n", __func__, i,
 			pinfo->cam_vreg[i].reg_name);
 		if (rc < 0) {
@@ -670,8 +662,8 @@
 		goto ERROR1;
 	}
 
-	rc = of_property_read_u32_array(of_node, "cam_vreg_type", val_array,
-		count);
+	rc = of_property_read_u32_array(of_node, "qcom,cam-vreg-type",
+		val_array, count);
 	if (rc < 0) {
 		pr_err("%s failed %d\n", __func__, __LINE__);
 		goto ERROR2;
@@ -682,7 +674,7 @@
 			pinfo->cam_vreg[i].type);
 	}
 
-	rc = of_property_read_u32_array(of_node, "cam_vreg_min_voltage",
+	rc = of_property_read_u32_array(of_node, "qcom,cam-vreg-min-voltage",
 		val_array, count);
 	if (rc < 0) {
 		pr_err("%s failed %d\n", __func__, __LINE__);
@@ -694,7 +686,7 @@
 			i, pinfo->cam_vreg[i].min_voltage);
 	}
 
-	rc = of_property_read_u32_array(of_node, "cam_vreg_max_voltage",
+	rc = of_property_read_u32_array(of_node, "qcom,cam-vreg-max-voltage",
 		val_array, count);
 	if (rc < 0) {
 		pr_err("%s failed %d\n", __func__, __LINE__);
@@ -706,8 +698,8 @@
 			i, pinfo->cam_vreg[i].max_voltage);
 	}
 
-	rc = of_property_read_u32_array(of_node, "cam_vreg_op_mode", val_array,
-		count);
+	rc = of_property_read_u32_array(of_node, "qcom,cam-vreg-op-mode",
+		val_array, count);
 	if (rc < 0) {
 		pr_err("%s failed %d\n", __func__, __LINE__);
 		goto ERROR2;
@@ -729,19 +721,25 @@
 }
 
 static int32_t msm_sensor_init_gpio_common_tbl_data(struct device_node *of_node,
-	struct msm_camera_gpio_conf *gconf)
+	struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array,
+	uint16_t gpio_array_size)
 {
 	int32_t rc = 0, i = 0;
 	uint32_t count = 0;
 	uint32_t *val_array = NULL;
 
-	if (!of_get_property(of_node, "gpio_common_tbl_num", &count))
+	if (!of_get_property(of_node, "qcom,gpio-common-tbl-num", &count))
 		return 0;
 
 	count /= sizeof(uint32_t);
-
-	if (!count)
+	if (!count) {
+		pr_err("%s qcom,gpio-common-tbl-num 0\n", __func__);
 		return 0;
+	} else if (count > gpio_array_size) {
+		pr_err("%s gpio common tbl size exceeds gpio array\n",
+			__func__);
+		return -EFAULT;
+	}
 
 	val_array = kzalloc(sizeof(uint32_t) * count, GFP_KERNEL);
 	if (!val_array) {
@@ -758,19 +756,24 @@
 	}
 	gconf->cam_gpio_common_tbl_size = count;
 
-	rc = of_property_read_u32_array(of_node, "gpio_common_tbl_num",
+	rc = of_property_read_u32_array(of_node, "qcom,gpio-common-tbl-num",
 		val_array, count);
 	if (rc < 0) {
 		pr_err("%s failed %d\n", __func__, __LINE__);
 		goto ERROR2;
 	}
 	for (i = 0; i < count; i++) {
-		gconf->cam_gpio_common_tbl[i].gpio = val_array[i];
+		if (val_array[i] >= gpio_array_size) {
+			pr_err("%s gpio common tbl index %d invalid\n",
+				__func__, val_array[i]);
+			return -EINVAL;
+		}
+		gconf->cam_gpio_common_tbl[i].gpio = gpio_array[val_array[i]];
 		CDBG("%s cam_gpio_common_tbl[%d].gpio = %d\n", __func__, i,
 			gconf->cam_gpio_common_tbl[i].gpio);
 	}
 
-	rc = of_property_read_u32_array(of_node, "gpio_common_tbl_flags",
+	rc = of_property_read_u32_array(of_node, "qcom,gpio-common-tbl-flags",
 		val_array, count);
 	if (rc < 0) {
 		pr_err("%s failed %d\n", __func__, __LINE__);
@@ -784,7 +787,7 @@
 
 	for (i = 0; i < count; i++) {
 		rc = of_property_read_string_index(of_node,
-			"gpio_common_tbl_label", i,
+			"qcom,gpio-common-tbl-label", i,
 			&gconf->cam_gpio_common_tbl[i].label);
 		CDBG("%s cam_gpio_common_tbl[%d].label = %s\n", __func__, i,
 			gconf->cam_gpio_common_tbl[i].label);
@@ -806,19 +809,21 @@
 }
 
 static int32_t msm_sensor_init_gpio_req_tbl_data(struct device_node *of_node,
-	struct msm_camera_gpio_conf *gconf)
+	struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array,
+	uint16_t gpio_array_size)
 {
 	int32_t rc = 0, i = 0;
 	uint32_t count = 0;
 	uint32_t *val_array = NULL;
 
-	if (!of_get_property(of_node, "gpio_req_tbl_num", &count))
+	if (!of_get_property(of_node, "qcom,gpio-req-tbl-num", &count))
 		return 0;
 
 	count /= sizeof(uint32_t);
-
-	if (!count)
+	if (!count) {
+		pr_err("%s qcom,gpio-req-tbl-num 0\n", __func__);
 		return 0;
+	}
 
 	val_array = kzalloc(sizeof(uint32_t) * count, GFP_KERNEL);
 	if (!val_array) {
@@ -835,19 +840,24 @@
 	}
 	gconf->cam_gpio_req_tbl_size = count;
 
-	rc = of_property_read_u32_array(of_node, "gpio_req_tbl_num",
+	rc = of_property_read_u32_array(of_node, "qcom,gpio-req-tbl-num",
 		val_array, count);
 	if (rc < 0) {
 		pr_err("%s failed %d\n", __func__, __LINE__);
 		goto ERROR2;
 	}
 	for (i = 0; i < count; i++) {
-		gconf->cam_gpio_req_tbl[i].gpio = val_array[i];
+		if (val_array[i] >= gpio_array_size) {
+			pr_err("%s gpio req tbl index %d invalid\n",
+				__func__, val_array[i]);
+			return -EINVAL;
+		}
+		gconf->cam_gpio_req_tbl[i].gpio = gpio_array[val_array[i]];
 		CDBG("%s cam_gpio_req_tbl[%d].gpio = %d\n", __func__, i,
 			gconf->cam_gpio_req_tbl[i].gpio);
 	}
 
-	rc = of_property_read_u32_array(of_node, "gpio_req_tbl_flags",
+	rc = of_property_read_u32_array(of_node, "qcom,gpio-req-tbl-flags",
 		val_array, count);
 	if (rc < 0) {
 		pr_err("%s failed %d\n", __func__, __LINE__);
@@ -861,7 +871,7 @@
 
 	for (i = 0; i < count; i++) {
 		rc = of_property_read_string_index(of_node,
-			"gpio_req_tbl_label", i,
+			"qcom,gpio-req-tbl-label", i,
 			&gconf->cam_gpio_req_tbl[i].label);
 		CDBG("%s cam_gpio_req_tbl[%d].label = %s\n", __func__, i,
 			gconf->cam_gpio_req_tbl[i].label);
@@ -883,19 +893,21 @@
 }
 
 static int32_t msm_sensor_init_gpio_set_tbl_data(struct device_node *of_node,
-	struct msm_camera_gpio_conf *gconf)
+	struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array,
+	uint16_t gpio_array_size)
 {
 	int32_t rc = 0, i = 0;
 	uint32_t count = 0;
 	uint32_t *val_array = NULL;
 
-	if (!of_get_property(of_node, "gpio_set_tbl_num", &count))
+	if (!of_get_property(of_node, "qcom,gpio-set-tbl-num", &count))
 		return 0;
 
 	count /= sizeof(uint32_t);
-
-	if (!count)
+	if (!count) {
+		pr_err("%s qcom,gpio-set-tbl-num 0\n", __func__);
 		return 0;
+	}
 
 	val_array = kzalloc(sizeof(uint32_t) * count, GFP_KERNEL);
 	if (!val_array) {
@@ -912,19 +924,24 @@
 	}
 	gconf->cam_gpio_set_tbl_size = count;
 
-	rc = of_property_read_u32_array(of_node, "gpio_set_tbl_num",
+	rc = of_property_read_u32_array(of_node, "qcom,gpio-set-tbl-num",
 		val_array, count);
 	if (rc < 0) {
 		pr_err("%s failed %d\n", __func__, __LINE__);
 		goto ERROR2;
 	}
 	for (i = 0; i < count; i++) {
-		gconf->cam_gpio_set_tbl[i].gpio = val_array[i];
+		if (val_array[i] >= gpio_array_size) {
+			pr_err("%s gpio set tbl index %d invalid\n",
+				__func__, val_array[i]);
+			return -EINVAL;
+		}
+		gconf->cam_gpio_set_tbl[i].gpio = gpio_array[val_array[i]];
 		CDBG("%s cam_gpio_set_tbl[%d].gpio = %d\n", __func__, i,
 			gconf->cam_gpio_set_tbl[i].gpio);
 	}
 
-	rc = of_property_read_u32_array(of_node, "gpio_set_tbl_flags",
+	rc = of_property_read_u32_array(of_node, "qcom,gpio-set-tbl-flags",
 		val_array, count);
 	if (rc < 0) {
 		pr_err("%s failed %d\n", __func__, __LINE__);
@@ -936,7 +953,7 @@
 			gconf->cam_gpio_set_tbl[i].flags);
 	}
 
-	rc = of_property_read_u32_array(of_node, "gpio_set_tbl_delay",
+	rc = of_property_read_u32_array(of_node, "qcom,gpio-set-tbl-delay",
 		val_array, count);
 	if (rc < 0) {
 		pr_err("%s failed %d\n", __func__, __LINE__);
@@ -960,7 +977,8 @@
 }
 
 static int32_t msm_sensor_init_gpio_tlmm_tbl_data(struct device_node *of_node,
-	struct msm_camera_gpio_conf *gconf)
+	struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array,
+	uint16_t gpio_array_size)
 {
 	int32_t rc = 0, i = 0;
 	uint32_t count = 0;
@@ -1011,7 +1029,12 @@
 		goto ERROR4;
 	}
 	for (i = 0; i < count; i++) {
-		tlmm_cfg[i].gpio = val_array[i];
+		if (val_array[i] >= gpio_array_size) {
+			pr_err("%s gpio set tbl index %d invalid\n",
+				__func__, val_array[i]);
+			return -EINVAL;
+		}
+		tlmm_cfg[i].gpio = gpio_array[val_array[i]];
 		CDBG("%s tlmm_cfg[%d].gpio = %d\n", __func__, i,
 			tlmm_cfg[i].gpio);
 	}
@@ -1087,8 +1110,8 @@
 	struct msm_camera_sensor_platform_info *pinfo =
 		sensordata->sensor_platform_info;
 
-	rc = of_property_read_u32(of_node, "csi_if", &count);
-	CDBG("%s csi_if %d, rc %d\n", __func__, count, rc);
+	rc = of_property_read_u32(of_node, "qcom,csi-if", &count);
+	CDBG("%s qcom,csi-if %d, rc %d\n", __func__, count, rc);
 	if (rc < 0 || !count)
 		return rc;
 	sensordata->csi_if = count;
@@ -1107,25 +1130,27 @@
 		goto ERROR1;
 	}
 
-	rc = of_property_read_u32_array(of_node, "csid_core", val_array, count);
+	rc = of_property_read_u32_array(of_node, "qcom,csid-core", val_array,
+		count);
 	if (rc < 0) {
 		pr_err("%s failed %d\n", __func__, __LINE__);
 		goto ERROR2;
 	}
 	for (i = 0; i < count; i++) {
 		sensordata->pdata[i].csid_core = val_array[i];
-		CDBG("%s csid_core[%d].csid_core = %d\n", __func__, i,
+		CDBG("%s csi_data[%d].csid_core = %d\n", __func__, i,
 			sensordata->pdata[i].csid_core);
 	}
 
-	rc = of_property_read_u32_array(of_node, "is_vpe", val_array, count);
+	rc = of_property_read_u32_array(of_node, "qcom,is-vpe", val_array,
+		count);
 	if (rc < 0) {
 		pr_err("%s failed %d\n", __func__, __LINE__);
 		goto ERROR2;
 	}
 	for (i = 0; i < count; i++) {
 		sensordata->pdata[i].is_vpe = val_array[i];
-		CDBG("%s csid_core[%d].is_vpe = %d\n", __func__, i,
+		CDBG("%s csi_data[%d].is_vpe = %d\n", __func__, i,
 			sensordata->pdata[i].is_vpe);
 	}
 
@@ -1137,22 +1162,30 @@
 		goto ERROR2;
 	}
 
-	rc = of_property_read_u32(of_node, "csi_lane_assign", &val);
-	CDBG("%s csi_lane_assign %x, rc %d\n", __func__, val, rc);
+	rc = of_property_read_u32(of_node, "qcom,csi-lane-assign", &val);
+	CDBG("%s qcom,csi-lane-assign %x, rc %d\n", __func__, val, rc);
 	if (rc < 0) {
 		pr_err("%s failed %d\n", __func__, __LINE__);
 		goto ERROR3;
 	}
 	pinfo->csi_lane_params->csi_lane_assign = val;
 
-	rc = of_property_read_u32(of_node, "csi_lane_mask", &val);
-	CDBG("%s csi_lane_mask %x, rc %d\n", __func__, val, rc);
+	rc = of_property_read_u32(of_node, "qcom,csi-lane-mask", &val);
+	CDBG("%s qcom,csi-lane-mask %x, rc %d\n", __func__, val, rc);
 	if (rc < 0) {
 		pr_err("%s failed %d\n", __func__, __LINE__);
 		goto ERROR3;
 	}
 	pinfo->csi_lane_params->csi_lane_mask = val;
 
+	rc = of_property_read_u32(of_node, "qcom,csi-phy-sel", &val);
+	CDBG("%s qcom,csi-phy-sel %x, rc %d\n", __func__, val, rc);
+	if (rc < 0) {
+		pr_err("%s failed %d\n", __func__, __LINE__);
+		goto ERROR3;
+	}
+	pinfo->csi_lane_params->csi_phy_sel = val;
+
 	kfree(val_array);
 	return rc;
 ERROR3:
@@ -1170,8 +1203,8 @@
 	int32_t rc = 0;
 	uint32_t val = 0;
 
-	rc = of_property_read_u32(of_node, "actuator_cam_name", &val);
-	CDBG("%s actuator_cam_name %d, rc %d\n", __func__, val, rc);
+	rc = of_property_read_u32(of_node, "qcom,actuator-cam-name", &val);
+	CDBG("%s qcom,actuator-cam-name %d, rc %d\n", __func__, val, rc);
 	if (rc < 0)
 		return 0;
 
@@ -1185,13 +1218,13 @@
 
 	sensordata->actuator_info->cam_name = val;
 
-	rc = of_property_read_u32(of_node, "actuator_vcm_pwd", &val);
-	CDBG("%s actuator_vcm_pwd %d, rc %d\n", __func__, val, rc);
+	rc = of_property_read_u32(of_node, "qcom,actuator-vcm-pwd", &val);
+	CDBG("%s qcom,actuator-vcm-pwd %d, rc %d\n", __func__, val, rc);
 	if (!rc)
 		sensordata->actuator_info->vcm_pwd = val;
 
-	rc = of_property_read_u32(of_node, "actuator_vcm_enable", &val);
-	CDBG("%s actuator_vcm_enable %d, rc %d\n", __func__, val, rc);
+	rc = of_property_read_u32(of_node, "qcom,actuator-vcm-enable", &val);
+	CDBG("%s qcom,actuator-vcm-enable %d, rc %d\n", __func__, val, rc);
 	if (!rc)
 		sensordata->actuator_info->vcm_enable = val;
 
@@ -1203,12 +1236,14 @@
 static int32_t msm_sensor_init_sensor_data(struct platform_device *pdev,
 	struct msm_sensor_ctrl_t *s_ctrl)
 {
-	int32_t rc = 0;
+	int32_t rc = 0, i = 0;
 	uint32_t val = 0;
 	struct device_node *of_node = pdev->dev.of_node;
 	struct msm_camera_sensor_platform_info *pinfo = NULL;
 	struct msm_camera_gpio_conf *gconf = NULL;
 	struct msm_camera_sensor_info *sensordata = NULL;
+	uint16_t *gpio_array = NULL;
+	uint16_t gpio_array_size = 0;
 
 	s_ctrl->sensordata = kzalloc(sizeof(struct msm_camera_sensor_info),
 		GFP_KERNEL);
@@ -1218,25 +1253,26 @@
 	}
 
 	sensordata = s_ctrl->sensordata;
-	rc = of_property_read_string(of_node, "sensor_name",
+
+	rc = of_property_read_string(of_node, "qcom,sensor-name",
 		&sensordata->sensor_name);
-	CDBG("%s sensor_name %s, rc %d\n", __func__,
+	CDBG("%s qcom,sensor-name %s, rc %d\n", __func__,
 		sensordata->sensor_name, rc);
 	if (rc < 0) {
 		pr_err("%s failed %d\n", __func__, __LINE__);
 		goto ERROR1;
 	}
 
-	rc = of_property_read_u32(of_node, "camera_type", &val);
-	CDBG("%s camera_type %d, rc %d\n", __func__, val, rc);
+	rc = of_property_read_u32(of_node, "qcom,camera-type", &val);
+	CDBG("%s qcom,camera-type %d, rc %d\n", __func__, val, rc);
 	if (rc < 0) {
 		pr_err("%s failed %d\n", __func__, __LINE__);
 		goto ERROR1;
 	}
 	sensordata->camera_type = val;
 
-	rc = of_property_read_u32(of_node, "sensor_type", &val);
-	CDBG("%s sensor_type %d, rc %d\n", __func__, val, rc);
+	rc = of_property_read_u32(of_node, "qcom,sensor-type", &val);
+	CDBG("%s qcom,sensor-type %d, rc %d\n", __func__, val, rc);
 	if (rc < 0) {
 		pr_err("%s failed %d\n", __func__, __LINE__);
 		goto ERROR1;
@@ -1259,8 +1295,10 @@
 
 	pinfo = sensordata->sensor_platform_info;
 
-	rc = of_property_read_u32(of_node, "mount_angle", &pinfo->mount_angle);
-	CDBG("%s mount_angle %d, rc %d\n", __func__, pinfo->mount_angle, rc);
+	rc = of_property_read_u32(of_node, "qcom,mount-angle",
+		&pinfo->mount_angle);
+	CDBG("%s qcom,mount-angle %d, rc %d\n", __func__, pinfo->mount_angle,
+		rc);
 	if (rc < 0) {
 		/* Set default mount angle */
 		pinfo->mount_angle = 0;
@@ -1287,7 +1325,8 @@
 		goto ERROR4;
 	}
 	gconf = pinfo->gpio_conf;
-	rc = of_property_read_u32(of_node, "gpio_no_mux", &gconf->gpio_no_mux);
+	rc = of_property_read_u32(of_node, "qcom,gpio-no-mux",
+		&gconf->gpio_no_mux);
 	CDBG("%s gconf->gpio_no_mux %d, rc %d\n", __func__,
 		gconf->gpio_no_mux, rc);
 	if (rc < 0) {
@@ -1295,36 +1334,57 @@
 		goto ERROR5;
 	}
 
-	rc = msm_sensor_init_gpio_common_tbl_data(of_node, gconf);
-	if (rc < 0) {
-		pr_err("%s failed %d\n", __func__, __LINE__);
-		goto ERROR5;
-	}
+	gpio_array_size = of_gpio_count(of_node);
+	CDBG("%s gpio count %d\n", __func__, gpio_array_size);
 
-	rc = msm_sensor_init_gpio_req_tbl_data(of_node, gconf);
-	if (rc < 0) {
-		pr_err("%s failed %d\n", __func__, __LINE__);
-		goto ERROR6;
-	}
+	if (gpio_array_size) {
+		gpio_array = kzalloc(sizeof(uint16_t) * gpio_array_size,
+			GFP_KERNEL);
+		if (!gpio_array) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			goto ERROR5;
+		}
+		for (i = 0; i < gpio_array_size; i++) {
+			gpio_array[i] = of_get_gpio(of_node, i);
+			CDBG("%s gpio_array[%d] = %d\n", __func__, i,
+				gpio_array[i]);
+		}
 
-	rc = msm_sensor_init_gpio_set_tbl_data(of_node, gconf);
-	if (rc < 0) {
-		pr_err("%s failed %d\n", __func__, __LINE__);
-		goto ERROR7;
-	}
+		rc = msm_sensor_init_gpio_common_tbl_data(of_node, gconf,
+			gpio_array, gpio_array_size);
+		if (rc < 0) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			goto ERROR5;
+		}
 
-	rc = msm_sensor_init_gpio_tlmm_tbl_data(of_node, gconf);
-	if (rc < 0) {
-		pr_err("%s failed %d\n", __func__, __LINE__);
-		goto ERROR8;
-	}
+		rc = msm_sensor_init_gpio_req_tbl_data(of_node, gconf,
+			gpio_array, gpio_array_size);
+		if (rc < 0) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			goto ERROR6;
+		}
 
+		rc = msm_sensor_init_gpio_set_tbl_data(of_node, gconf,
+			gpio_array, gpio_array_size);
+		if (rc < 0) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			goto ERROR7;
+		}
+
+		rc = msm_sensor_init_gpio_tlmm_tbl_data(of_node, gconf,
+			gpio_array, gpio_array_size);
+		if (rc < 0) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			goto ERROR8;
+		}
+	}
 	rc = msm_sensor_init_actuator_data(of_node, sensordata);
 	if (rc < 0) {
 		pr_err("%s failed %d\n", __func__, __LINE__);
 		goto ERROR9;
 	}
 
+	kfree(gpio_array);
 	return rc;
 
 ERROR9:
@@ -1353,6 +1413,7 @@
 	kfree(s_ctrl->sensordata->flash_data);
 ERROR1:
 	kfree(s_ctrl->sensordata);
+	kfree(gpio_array);
 	return rc;
 }
 
@@ -1384,7 +1445,11 @@
 {
 	int32_t rc = 0;
 	struct msm_camera_sensor_info *data = s_ctrl->sensordata;
-	CDBG("%s: %d\n", __func__, __LINE__);
+	struct device *dev = NULL;
+	if (s_ctrl->sensor_device_type == MSM_SENSOR_PLATFORM_DEVICE)
+		dev = &s_ctrl->pdev->dev;
+	else
+		dev = &s_ctrl->sensor_i2c_client->client->dev;
 	s_ctrl->reg_ptr = kzalloc(sizeof(struct regulator *)
 			* data->sensor_platform_info->num_vreg, GFP_KERNEL);
 	if (!s_ctrl->reg_ptr) {
@@ -1399,19 +1464,23 @@
 		goto request_gpio_failed;
 	}
 
-	rc = msm_camera_config_vreg(&s_ctrl->sensor_i2c_client->client->dev,
-			s_ctrl->sensordata->sensor_platform_info->cam_vreg,
-			s_ctrl->sensordata->sensor_platform_info->num_vreg,
-			s_ctrl->reg_ptr, 1);
+	rc = msm_camera_config_vreg(dev,
+		s_ctrl->sensordata->sensor_platform_info->cam_vreg,
+		s_ctrl->sensordata->sensor_platform_info->num_vreg,
+		s_ctrl->vreg_seq,
+		s_ctrl->num_vreg_seq,
+		s_ctrl->reg_ptr, 1);
 	if (rc < 0) {
 		pr_err("%s: regulator on failed\n", __func__);
 		goto config_vreg_failed;
 	}
 
-	rc = msm_camera_enable_vreg(&s_ctrl->sensor_i2c_client->client->dev,
-			s_ctrl->sensordata->sensor_platform_info->cam_vreg,
-			s_ctrl->sensordata->sensor_platform_info->num_vreg,
-			s_ctrl->reg_ptr, 1);
+	rc = msm_camera_enable_vreg(dev,
+		s_ctrl->sensordata->sensor_platform_info->cam_vreg,
+		s_ctrl->sensordata->sensor_platform_info->num_vreg,
+		s_ctrl->vreg_seq,
+		s_ctrl->num_vreg_seq,
+		s_ctrl->reg_ptr, 1);
 	if (rc < 0) {
 		pr_err("%s: enable regulator failed\n", __func__);
 		goto enable_vreg_failed;
@@ -1423,17 +1492,33 @@
 		goto config_gpio_failed;
 	}
 
-	if (s_ctrl->clk_rate != 0)
-		cam_clk_info->clk_rate = s_ctrl->clk_rate;
+	if (s_ctrl->sensor_device_type == MSM_SENSOR_I2C_DEVICE) {
+		if (s_ctrl->clk_rate != 0)
+			cam_8960_clk_info->clk_rate = s_ctrl->clk_rate;
 
-	rc = msm_cam_clk_enable(&s_ctrl->sensor_i2c_client->client->dev,
-		cam_clk_info, &s_ctrl->cam_clk, ARRAY_SIZE(cam_clk_info), 1);
-	if (rc < 0) {
-		pr_err("%s: clk enable failed\n", __func__);
-		goto enable_clk_failed;
+		rc = msm_cam_clk_enable(dev, cam_8960_clk_info,
+			s_ctrl->cam_clk, ARRAY_SIZE(cam_8960_clk_info), 1);
+		if (rc < 0) {
+			pr_err("%s: clk enable failed\n", __func__);
+			goto enable_clk_failed;
+		}
+	} else {
+		rc = msm_cam_clk_enable(dev, cam_8974_clk_info,
+			s_ctrl->cam_clk, ARRAY_SIZE(cam_8974_clk_info), 1);
+		if (rc < 0) {
+			pr_err("%s: clk enable failed\n", __func__);
+			goto enable_clk_failed;
+		}
 	}
 
-	usleep_range(1000, 2000);
+	if (!s_ctrl->power_seq_delay)
+		usleep_range(1000, 2000);
+	else if (s_ctrl->power_seq_delay < 20)
+		usleep_range((s_ctrl->power_seq_delay * 1000),
+			((s_ctrl->power_seq_delay * 1000) + 1000));
+	else
+		msleep(s_ctrl->power_seq_delay);
+
 	if (data->sensor_platform_info->ext_power_ctrl != NULL)
 		data->sensor_platform_info->ext_power_ctrl(1);
 
@@ -1441,7 +1526,7 @@
 		data->sensor_platform_info->i2c_conf->use_i2c_mux)
 		msm_sensor_enable_i2c_mux(data->sensor_platform_info->i2c_conf);
 
-	if (s_ctrl->sensor_i2c_client->cci_client) {
+	if (s_ctrl->sensor_device_type == MSM_SENSOR_PLATFORM_DEVICE) {
 		rc = msm_sensor_cci_util(s_ctrl->sensor_i2c_client,
 			MSM_CCI_INIT);
 		if (rc < 0) {
@@ -1449,6 +1534,7 @@
 			goto cci_init_failed;
 		}
 	}
+	s_ctrl->curr_res = MSM_SENSOR_INVALID_RES;
 	return rc;
 
 cci_init_failed:
@@ -1459,15 +1545,19 @@
 enable_clk_failed:
 		msm_camera_config_gpio_table(data, 0);
 config_gpio_failed:
-	msm_camera_enable_vreg(&s_ctrl->sensor_i2c_client->client->dev,
+	msm_camera_enable_vreg(dev,
 			s_ctrl->sensordata->sensor_platform_info->cam_vreg,
 			s_ctrl->sensordata->sensor_platform_info->num_vreg,
+			s_ctrl->vreg_seq,
+			s_ctrl->num_vreg_seq,
 			s_ctrl->reg_ptr, 0);
 
 enable_vreg_failed:
-	msm_camera_config_vreg(&s_ctrl->sensor_i2c_client->client->dev,
+	msm_camera_config_vreg(dev,
 		s_ctrl->sensordata->sensor_platform_info->cam_vreg,
 		s_ctrl->sensordata->sensor_platform_info->num_vreg,
+		s_ctrl->vreg_seq,
+		s_ctrl->num_vreg_seq,
 		s_ctrl->reg_ptr, 0);
 config_vreg_failed:
 	msm_camera_request_gpio_table(data, 0);
@@ -1479,8 +1569,12 @@
 int32_t msm_sensor_power_down(struct msm_sensor_ctrl_t *s_ctrl)
 {
 	struct msm_camera_sensor_info *data = s_ctrl->sensordata;
-	CDBG("%s\n", __func__);
-	if (s_ctrl->sensor_i2c_client->cci_client) {
+	struct device *dev = NULL;
+	if (s_ctrl->sensor_device_type == MSM_SENSOR_PLATFORM_DEVICE)
+		dev = &s_ctrl->pdev->dev;
+	else
+		dev = &s_ctrl->sensor_i2c_client->client->dev;
+	if (s_ctrl->sensor_device_type == MSM_SENSOR_PLATFORM_DEVICE) {
 		msm_sensor_cci_util(s_ctrl->sensor_i2c_client,
 			MSM_CCI_RELEASE);
 	}
@@ -1492,19 +1586,28 @@
 
 	if (data->sensor_platform_info->ext_power_ctrl != NULL)
 		data->sensor_platform_info->ext_power_ctrl(0);
-	msm_cam_clk_enable(&s_ctrl->sensor_i2c_client->client->dev,
-		cam_clk_info, &s_ctrl->cam_clk, ARRAY_SIZE(cam_clk_info), 0);
+	if (s_ctrl->sensor_device_type == MSM_SENSOR_I2C_DEVICE)
+		msm_cam_clk_enable(dev, cam_8960_clk_info, s_ctrl->cam_clk,
+			ARRAY_SIZE(cam_8960_clk_info), 0);
+	else
+		msm_cam_clk_enable(dev, cam_8974_clk_info, s_ctrl->cam_clk,
+			ARRAY_SIZE(cam_8974_clk_info), 0);
 	msm_camera_config_gpio_table(data, 0);
-	msm_camera_enable_vreg(&s_ctrl->sensor_i2c_client->client->dev,
+	msm_camera_enable_vreg(dev,
 		s_ctrl->sensordata->sensor_platform_info->cam_vreg,
 		s_ctrl->sensordata->sensor_platform_info->num_vreg,
+		s_ctrl->vreg_seq,
+		s_ctrl->num_vreg_seq,
 		s_ctrl->reg_ptr, 0);
-	msm_camera_config_vreg(&s_ctrl->sensor_i2c_client->client->dev,
+	msm_camera_config_vreg(dev,
 		s_ctrl->sensordata->sensor_platform_info->cam_vreg,
 		s_ctrl->sensordata->sensor_platform_info->num_vreg,
+		s_ctrl->vreg_seq,
+		s_ctrl->num_vreg_seq,
 		s_ctrl->reg_ptr, 0);
 	msm_camera_request_gpio_table(data, 0);
 	kfree(s_ctrl->reg_ptr);
+	s_ctrl->curr_res = MSM_SENSOR_INVALID_RES;
 	return 0;
 }
 
@@ -1522,7 +1625,7 @@
 		return rc;
 	}
 
-	CDBG("%s msm_sensor id: %x, exp id: %x\n", __func__, chipid,
+	CDBG("%s: read id: %x expected id %x:\n", __func__, chipid,
 		s_ctrl->sensor_id_info->sensor_id);
 	if (chipid != s_ctrl->sensor_id_info->sensor_id) {
 		pr_err("msm_sensor_match_id chip id doesnot match\n");
@@ -1531,11 +1634,6 @@
 	return rc;
 }
 
-struct msm_sensor_ctrl_t *get_sctrl(struct v4l2_subdev *sd)
-{
-	return container_of(sd, struct msm_sensor_ctrl_t, sensor_v4l2_subdev);
-}
-
 int32_t msm_sensor_i2c_probe(struct i2c_client *client,
 	const struct i2c_device_id *id)
 {
@@ -1550,6 +1648,7 @@
 	}
 
 	s_ctrl = (struct msm_sensor_ctrl_t *)(id->driver_data);
+	s_ctrl->sensor_device_type = MSM_SENSOR_I2C_DEVICE;
 	if (s_ctrl->sensor_i2c_client != NULL) {
 		s_ctrl->sensor_i2c_client->client = client;
 		if (s_ctrl->sensor_i2c_addr != 0)
@@ -1581,6 +1680,10 @@
 	if (rc < 0)
 		goto probe_fail;
 
+	if (!s_ctrl->wait_num_frames)
+		s_ctrl->wait_num_frames = 1 * Q10;
+
+	pr_err("%s %s probe succeeded\n", __func__, client->name);
 	snprintf(s_ctrl->sensor_v4l2_subdev.name,
 		sizeof(s_ctrl->sensor_v4l2_subdev.name), "%s", id->name);
 	v4l2_i2c_subdev_init(&s_ctrl->sensor_v4l2_subdev, client,
@@ -1601,6 +1704,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;
 }
 
@@ -1630,6 +1734,7 @@
 			return rc;
 		}
 	}
+	s_ctrl->sensor_device_type = MSM_SENSOR_PLATFORM_DEVICE;
 	s_ctrl->sensor_i2c_client->cci_client = kzalloc(sizeof(
 		struct msm_camera_cci_client), GFP_KERNEL);
 	if (!s_ctrl->sensor_i2c_client->cci_client) {
@@ -1655,7 +1760,7 @@
 	s_ctrl->sensor_i2c_client->cci_client->cci_i2c_master = MASTER_0;
 	s_ctrl->sensor_i2c_client->cci_client->sid =
 		s_ctrl->sensor_i2c_addr >> 1;
-	s_ctrl->sensor_i2c_client->cci_client->retries = 0;
+	s_ctrl->sensor_i2c_client->cci_client->retries = 3;
 	s_ctrl->sensor_i2c_client->cci_client->id_map = 0;
 
 	rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl);
@@ -1698,6 +1803,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);
@@ -1712,10 +1818,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 dc394e1..7dd0602 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.h
+++ b/drivers/media/video/msm/sensors/msm_sensor.h
@@ -24,179 +24,14 @@
 #include <linux/uaccess.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
+#include <linux/of_gpio.h>
 #include <linux/gpio.h>
 #include <mach/camera.h>
-#include <mach/gpio.h>
 #include <media/msm_camera.h>
 #include <media/v4l2-subdev.h>
 #include "msm_camera_i2c.h"
 #include "msm_camera_eeprom.h"
-#define Q8  0x00000100
-#define Q10 0x00000400
-
-#define MSM_SENSOR_MCLK_8HZ 8000000
-#define MSM_SENSOR_MCLK_16HZ 16000000
-#define MSM_SENSOR_MCLK_24HZ 24000000
-
-struct gpio_tlmm_cfg {
-	uint32_t gpio;
-	uint32_t dir;
-	uint32_t pull;
-	uint32_t drvstr;
-};
-
-enum msm_sensor_reg_update {
-	/* Sensor egisters that need to be updated during initialization */
-	MSM_SENSOR_REG_INIT,
-	/* Sensor egisters that needs periodic I2C writes */
-	MSM_SENSOR_UPDATE_PERIODIC,
-	/* All the sensor Registers will be updated */
-	MSM_SENSOR_UPDATE_ALL,
-	/* Not valid update */
-	MSM_SENSOR_UPDATE_INVALID
-};
-
-enum msm_sensor_cam_mode_t {
-	MSM_SENSOR_MODE_2D_RIGHT,
-	MSM_SENSOR_MODE_2D_LEFT,
-	MSM_SENSOR_MODE_3D,
-	MSM_SENSOR_MODE_INVALID
-};
-
-struct msm_sensor_output_reg_addr_t {
-	uint16_t x_output;
-	uint16_t y_output;
-	uint16_t line_length_pclk;
-	uint16_t frame_length_lines;
-};
-
-struct msm_sensor_id_info_t {
-	uint16_t sensor_id_reg_addr;
-	uint16_t sensor_id;
-};
-
-struct msm_sensor_exp_gain_info_t {
-	uint16_t coarse_int_time_addr;
-	uint16_t global_gain_addr;
-	uint16_t vert_offset;
-};
-
-struct msm_sensor_reg_t {
-	enum msm_camera_i2c_data_type default_data_type;
-	struct msm_camera_i2c_reg_conf *start_stream_conf;
-	uint8_t start_stream_conf_size;
-	struct msm_camera_i2c_reg_conf *stop_stream_conf;
-	uint8_t stop_stream_conf_size;
-	struct msm_camera_i2c_reg_conf *group_hold_on_conf;
-	uint8_t group_hold_on_conf_size;
-	struct msm_camera_i2c_reg_conf *group_hold_off_conf;
-	uint8_t group_hold_off_conf_size;
-	struct msm_camera_i2c_conf_array *init_settings;
-	uint8_t init_size;
-	struct msm_camera_i2c_conf_array *mode_settings;
-	struct msm_camera_i2c_conf_array *no_effect_settings;
-	struct msm_sensor_output_info_t *output_settings;
-	uint8_t num_conf;
-};
-
-struct v4l2_subdev_info {
-	enum v4l2_mbus_pixelcode code;
-	enum v4l2_colorspace colorspace;
-	uint16_t fmt;
-	uint16_t order;
-};
-
-struct msm_sensor_ctrl_t;
-
-struct msm_sensor_v4l2_ctrl_info_t {
-	uint32_t ctrl_id;
-	int16_t min;
-	int16_t max;
-	int16_t step;
-	struct msm_camera_i2c_enum_conf_array *enum_cfg_settings;
-	int (*s_v4l2_ctrl) (struct msm_sensor_ctrl_t *,
-		struct msm_sensor_v4l2_ctrl_info_t *, int);
-};
-
-struct msm_sensor_fn_t {
-	void (*sensor_start_stream) (struct msm_sensor_ctrl_t *);
-	void (*sensor_stop_stream) (struct msm_sensor_ctrl_t *);
-	void (*sensor_group_hold_on) (struct msm_sensor_ctrl_t *);
-	void (*sensor_group_hold_off) (struct msm_sensor_ctrl_t *);
-
-	int32_t (*sensor_set_fps) (struct msm_sensor_ctrl_t *,
-			struct fps_cfg *);
-	int32_t (*sensor_write_exp_gain) (struct msm_sensor_ctrl_t *,
-			uint16_t, uint32_t);
-	int32_t (*sensor_write_snapshot_exp_gain) (struct msm_sensor_ctrl_t *,
-			uint16_t, uint32_t);
-	int32_t (*sensor_setting) (struct msm_sensor_ctrl_t *,
-			int update_type, int rt);
-	int32_t (*sensor_csi_setting) (struct msm_sensor_ctrl_t *,
-			int update_type, int rt);
-	int32_t (*sensor_set_sensor_mode)
-			(struct msm_sensor_ctrl_t *, int, int);
-	int32_t (*sensor_mode_init) (struct msm_sensor_ctrl_t *,
-		int, struct sensor_init_cfg *);
-	int32_t (*sensor_get_output_info) (struct msm_sensor_ctrl_t *,
-		struct sensor_output_info_t *);
-	int (*sensor_config) (struct msm_sensor_ctrl_t *, void __user *);
-	int (*sensor_power_down)
-		(struct msm_sensor_ctrl_t *);
-	int (*sensor_power_up) (struct msm_sensor_ctrl_t *);
-	int32_t (*sensor_match_id)(struct msm_sensor_ctrl_t *s_ctrl);
-	int (*sensor_adjust_frame_lines)
-		(struct msm_sensor_ctrl_t *s_ctrl, uint16_t res);
-	int32_t (*sensor_get_csi_params)(struct msm_sensor_ctrl_t *,
-		struct csi_lane_params_t *);
-};
-
-struct msm_sensor_csi_info {
-	uint32_t csid_version;
-	uint8_t is_csic;
-};
-
-struct msm_sensor_ctrl_t {
-	struct  msm_camera_sensor_info *sensordata;
-	struct i2c_client *msm_sensor_client;
-	struct i2c_driver *sensor_i2c_driver;
-	struct msm_camera_i2c_client *sensor_i2c_client;
-	struct platform_device *pdev;
-	uint16_t sensor_i2c_addr;
-
-	struct msm_sensor_output_reg_addr_t *sensor_output_reg_addr;
-	struct msm_sensor_id_info_t *sensor_id_info;
-	struct msm_sensor_exp_gain_info_t *sensor_exp_gain_info;
-	struct msm_sensor_reg_t *msm_sensor_reg;
-	struct msm_sensor_v4l2_ctrl_info_t *msm_sensor_v4l2_ctrl_info;
-	uint16_t num_v4l2_ctrl;
-	uint32_t csid_version;
-	uint8_t is_csic;
-
-	uint16_t curr_line_length_pclk;
-	uint16_t curr_frame_length_lines;
-	uint16_t prev_gain;
-	uint16_t prev_line;
-
-	uint32_t fps_divider;
-	enum msm_sensor_resolution_t curr_res;
-	enum msm_sensor_cam_mode_t cam_mode;
-
-	struct mutex *msm_sensor_mutex;
-	struct msm_camera_csi2_params *curr_csi_params;
-	struct msm_camera_csi2_params **csi_params;
-	struct msm_camera_csi_params **csic_params;
-	struct msm_camera_csi_params *curr_csic_params;
-
-	struct v4l2_subdev sensor_v4l2_subdev;
-	struct v4l2_subdev_info *sensor_v4l2_subdev_info;
-	uint8_t sensor_v4l2_subdev_info_size;
-	struct v4l2_subdev_ops *sensor_v4l2_subdev_ops;
-	struct msm_sensor_fn_t *func_tbl;
-	struct regulator **reg_ptr;
-	struct clk *cam_clk;
-	long clk_rate;
-};
+#include "msm_sensor_common.h"
 
 void msm_sensor_start_stream(struct msm_sensor_ctrl_t *s_ctrl);
 void msm_sensor_stop_stream(struct msm_sensor_ctrl_t *s_ctrl);
@@ -250,11 +85,9 @@
 int32_t msm_sensor_write_output_settings(struct msm_sensor_ctrl_t *s_ctrl,
 	uint16_t res);
 
-int32_t msm_sensor_adjust_frame_lines1(struct msm_sensor_ctrl_t *s_ctrl,
-	uint16_t res);
+void msm_sensor_adjust_frame_lines1(struct msm_sensor_ctrl_t *s_ctrl);
 
-int32_t msm_sensor_adjust_frame_lines2(struct msm_sensor_ctrl_t *s_ctrl,
-	uint16_t res);
+void msm_sensor_adjust_frame_lines2(struct msm_sensor_ctrl_t *s_ctrl);
 
 int32_t msm_sensor_setting(struct msm_sensor_ctrl_t *s_ctrl,
 			int update_type, int res);
@@ -270,12 +103,11 @@
 int32_t msm_sensor_get_csi_params(struct msm_sensor_ctrl_t *s_ctrl,
 		struct csi_lane_params_t *sensor_output_info);
 
+struct msm_sensor_ctrl_t *get_sctrl(struct v4l2_subdev *sd);
 int32_t msm_sensor_free_sensor_data(struct msm_sensor_ctrl_t *s_ctrl);
 
-struct msm_sensor_ctrl_t *get_sctrl(struct v4l2_subdev *sd);
-
 #define VIDIOC_MSM_SENSOR_CFG \
-	_IOWR('V', BASE_VIDIOC_PRIVATE + 10, void __user *)
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 4, void __user *)
 
 #define VIDIOC_MSM_SENSOR_RELEASE \
 	_IO('V', BASE_VIDIOC_PRIVATE + 11)
diff --git a/drivers/media/video/msm/sensors/msm_sensor_bayer.c b/drivers/media/video/msm/sensors/msm_sensor_bayer.c
new file mode 100644
index 0000000..c867867
--- /dev/null
+++ b/drivers/media/video/msm/sensors/msm_sensor_bayer.c
@@ -0,0 +1,906 @@
+/* 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 "msm_sensor_bayer.h"
+#include "msm.h"
+#include "msm_ispif.h"
+#include "msm_camera_i2c_mux.h"
+/*=============================================================*/
+
+long msm_sensor_bayer_subdev_ioctl(struct v4l2_subdev *sd,
+			unsigned int cmd, void *arg)
+{
+	struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(sd);
+	void __user *argp = (void __user *)arg;
+	switch (cmd) {
+	case VIDIOC_MSM_SENSOR_CFG:
+		return s_ctrl->func_tbl->sensor_config(s_ctrl, argp);
+	case VIDIOC_MSM_SENSOR_RELEASE:
+		return 0;
+	case VIDIOC_MSM_SENSOR_CSID_INFO: {
+		struct msm_sensor_csi_info *csi_info =
+			(struct msm_sensor_csi_info *)arg;
+		s_ctrl->is_csic = csi_info->is_csic;
+		return 0;
+	}
+	default:
+		return -ENOIOCTLCMD;
+	}
+}
+
+int32_t msm_sensor_bayer_get_csi_params(struct msm_sensor_ctrl_t *s_ctrl,
+		struct csi_lane_params_t *sensor_output_info)
+{
+	uint8_t index;
+	struct msm_camera_csi_lane_params *csi_lane_params =
+		s_ctrl->sensordata->sensor_platform_info->csi_lane_params;
+	if (csi_lane_params) {
+		sensor_output_info->csi_lane_assign = csi_lane_params->
+			csi_lane_assign;
+		sensor_output_info->csi_lane_mask = csi_lane_params->
+			csi_lane_mask;
+	}
+	sensor_output_info->csi_if = s_ctrl->sensordata->csi_if;
+	for (index = 0; index < sensor_output_info->csi_if; index++)
+		sensor_output_info->csid_core[index] = s_ctrl->sensordata->
+			pdata[index].csid_core;
+
+	return 0;
+}
+
+int32_t msm_sensor_bayer_config(struct msm_sensor_ctrl_t *s_ctrl,
+	void __user *argp)
+{
+	struct sensor_cfg_data cdata;
+	long rc = 0;
+	if (copy_from_user(&cdata,
+		(void *)argp,
+		sizeof(struct sensor_cfg_data)))
+		return -EFAULT;
+	mutex_lock(s_ctrl->msm_sensor_mutex);
+	CDBG("%s:%d %s cfgtype = %d\n", __func__, __LINE__,
+		s_ctrl->sensordata->sensor_name, cdata.cfgtype);
+	switch (cdata.cfgtype) {
+	case CFG_WRITE_I2C_ARRAY: {
+		struct msm_camera_i2c_reg_setting conf_array;
+		struct msm_camera_i2c_reg_array *regs = NULL;
+
+		if (copy_from_user(&conf_array,
+			(void *)cdata.cfg.setting,
+			sizeof(struct msm_camera_i2c_reg_setting))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+
+		regs = kzalloc(conf_array.size * sizeof(
+			struct msm_camera_i2c_reg_array),
+			GFP_KERNEL);
+		if (!regs) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+
+		if (copy_from_user(regs, (void *)conf_array.reg_setting,
+			conf_array.size * sizeof(
+			struct msm_camera_i2c_reg_array))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			kfree(regs);
+			rc = -EFAULT;
+			break;
+		}
+
+		conf_array.reg_setting = regs;
+		rc = msm_camera_i2c_write_bayer_table(s_ctrl->sensor_i2c_client,
+			&conf_array);
+		kfree(regs);
+		break;
+	}
+	case CFG_READ_I2C_ARRAY: {
+		struct msm_camera_i2c_reg_setting conf_array;
+		struct msm_camera_i2c_reg_array *regs;
+		int index;
+
+		if (copy_from_user(&conf_array,
+				(void *)cdata.cfg.setting,
+				sizeof(struct msm_camera_i2c_reg_setting))) {
+				pr_err("%s:%d failed\n", __func__, __LINE__);
+				rc = -EFAULT;
+				break;
+		}
+
+		regs = kzalloc(conf_array.size * sizeof(
+				struct msm_camera_i2c_reg_array),
+				GFP_KERNEL);
+		if (!regs) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			kfree(regs);
+			break;
+		}
+
+		if (copy_from_user(regs, (void *)conf_array.reg_setting,
+				conf_array.size * sizeof(
+				struct msm_camera_i2c_reg_array))) {
+				pr_err("%s:%d failed\n", __func__, __LINE__);
+				kfree(regs);
+				rc = -EFAULT;
+				break;
+			}
+
+		s_ctrl->sensor_i2c_client->addr_type = conf_array.addr_type;
+		for (index = 0; index < conf_array.size; index++) {
+			msm_camera_i2c_read(s_ctrl->sensor_i2c_client,
+					regs[index].reg_addr,
+					&regs[index].reg_data,
+				conf_array.data_type
+				);
+		}
+
+		if (copy_to_user(conf_array.reg_setting,
+			regs,
+			conf_array.size * sizeof(
+			struct msm_camera_i2c_reg_array))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			kfree(regs);
+			rc = -EFAULT;
+			break;
+		}
+		s_ctrl->sensor_i2c_client->addr_type = conf_array.addr_type;
+		kfree(regs);
+		break;
+	}
+	case CFG_PCLK_CHANGE: {
+		uint32_t pclk = cdata.cfg.pclk;
+		v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
+			NOTIFY_PCLK_CHANGE, &pclk);
+		break;
+	}
+	case CFG_GPIO_OP: {
+		struct msm_cam_gpio_operation gop;
+		if (copy_from_user(&gop,
+			(void *)cdata.cfg.setting,
+			sizeof(struct msm_cam_gpio_operation))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+		}
+		switch (gop.op_type) {
+		case GPIO_GET_VALUE:
+			gop.value = gpio_get_value(gop.address);
+			if (copy_from_user((void *)cdata.cfg.setting,
+				&gop,
+				sizeof(struct msm_cam_gpio_operation))) {
+				pr_err("%s:%d failed\n", __func__, __LINE__);
+				rc = -EFAULT;
+				break;
+			}
+			break;
+		case GPIO_SET_VALUE:
+			gpio_set_value(gop.address, gop.value);
+			break;
+		case GPIO_SET_DIRECTION_INPUT:
+			gpio_direction_input(gop.address);
+			break;
+		case GPIO_SET_DIRECTION_OUTPUT:
+			gpio_direction_output(gop.address, gop.value);
+			break;
+		case GPIO_REQUEST:
+			gpio_request(gop.address, gop.tag);
+			break;
+		case GPIO_FREE:
+			gpio_free(gop.address);
+			break;
+		default:
+			break;
+		}
+
+		break;
+	}
+	case CFG_GET_CSI_PARAMS:
+		if (s_ctrl->func_tbl->sensor_get_csi_params == NULL) {
+			rc = -EFAULT;
+			break;
+		}
+		rc = s_ctrl->func_tbl->sensor_get_csi_params(
+			s_ctrl,
+			&cdata.cfg.csi_lane_params);
+
+		if (copy_to_user((void *)argp,
+			&cdata,
+			sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_POWER_UP:
+		if (s_ctrl->func_tbl->sensor_power_up)
+			rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl);
+		else
+			rc = -EFAULT;
+		break;
+
+	case CFG_POWER_DOWN:
+		if (s_ctrl->func_tbl->sensor_power_down)
+			rc = s_ctrl->func_tbl->sensor_power_down(
+				s_ctrl);
+		else
+			rc = -EFAULT;
+		break;
+
+	case CFG_CONFIG_VREG_ARRAY: {
+		struct msm_camera_vreg_setting vreg_setting;
+		struct camera_vreg_t *cam_vreg = NULL;
+
+		if (copy_from_user(&vreg_setting,
+			(void *)cdata.cfg.setting,
+			sizeof(struct msm_camera_vreg_setting))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+
+		cam_vreg = kzalloc(vreg_setting.num_vreg * sizeof(
+			struct camera_vreg_t),
+			GFP_KERNEL);
+		if (!cam_vreg) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+
+		if (copy_from_user(cam_vreg, (void *)vreg_setting.cam_vreg,
+			vreg_setting.num_vreg * sizeof(
+			struct camera_vreg_t))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			kfree(cam_vreg);
+			rc = -EFAULT;
+			break;
+		}
+		rc = msm_camera_config_vreg(
+			&s_ctrl->sensor_i2c_client->client->dev,
+			cam_vreg,
+			vreg_setting.num_vreg,
+			NULL,
+			0,
+			s_ctrl->reg_ptr,
+			vreg_setting.enable);
+		if (rc < 0) {
+			kfree(cam_vreg);
+			pr_err("%s: regulator on failed\n", __func__);
+			break;
+		}
+
+		rc = msm_camera_enable_vreg(
+			&s_ctrl->sensor_i2c_client->client->dev,
+			cam_vreg,
+			vreg_setting.num_vreg,
+			NULL,
+			0,
+			s_ctrl->reg_ptr,
+			vreg_setting.enable);
+		if (rc < 0) {
+			kfree(cam_vreg);
+			pr_err("%s: enable regulator failed\n", __func__);
+			break;
+		}
+		kfree(cam_vreg);
+		break;
+	}
+	case CFG_CONFIG_CLK_ARRAY: {
+		struct msm_cam_clk_setting clk_setting;
+		struct msm_cam_clk_info *clk_info = NULL;
+
+		if (copy_from_user(&clk_setting,
+			(void *)cdata.cfg.setting,
+			sizeof(struct msm_camera_vreg_setting))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+
+		clk_info = kzalloc(clk_setting.num_clk_info * sizeof(
+			struct msm_cam_clk_info),
+			GFP_KERNEL);
+		if (!clk_info) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+
+		if (copy_from_user(clk_info, (void *)clk_setting.clk_info,
+			clk_setting.num_clk_info * sizeof(
+			struct msm_cam_clk_info))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			kfree(clk_info);
+			rc = -EFAULT;
+			break;
+		}
+		rc = msm_cam_clk_enable(&s_ctrl->sensor_i2c_client->client->dev,
+			clk_info, s_ctrl->cam_clk,
+			clk_setting.num_clk_info,
+			clk_setting.enable);
+		kfree(clk_info);
+		break;
+	}
+	case CFG_GET_EEPROM_DATA: {
+		if (copy_to_user((void *)cdata.cfg.eeprom_data.eeprom_data,
+			&s_ctrl->eeprom_data, s_ctrl->eeprom_data.length)) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+		}
+		cdata.cfg.eeprom_data.index = s_ctrl->eeprom_data.length;
+		break;
+	}
+	default:
+		rc = -EFAULT;
+		break;
+	}
+
+	mutex_unlock(s_ctrl->msm_sensor_mutex);
+
+	return rc;
+}
+
+static struct msm_cam_clk_info cam_clk_info[] = {
+	{"cam_clk", MSM_SENSOR_MCLK_24HZ},
+};
+
+int32_t msm_sensor_bayer_enable_i2c_mux(struct msm_camera_i2c_conf *i2c_conf)
+{
+	struct v4l2_subdev *i2c_mux_sd =
+		dev_get_drvdata(&i2c_conf->mux_dev->dev);
+	v4l2_subdev_call(i2c_mux_sd, core, ioctl,
+		VIDIOC_MSM_I2C_MUX_INIT, NULL);
+	v4l2_subdev_call(i2c_mux_sd, core, ioctl,
+		VIDIOC_MSM_I2C_MUX_CFG, (void *)&i2c_conf->i2c_mux_mode);
+	return 0;
+}
+
+int32_t msm_sensor_bayer_disable_i2c_mux(struct msm_camera_i2c_conf *i2c_conf)
+{
+	struct v4l2_subdev *i2c_mux_sd =
+		dev_get_drvdata(&i2c_conf->mux_dev->dev);
+	v4l2_subdev_call(i2c_mux_sd, core, ioctl,
+				VIDIOC_MSM_I2C_MUX_RELEASE, NULL);
+	return 0;
+}
+
+static struct msm_camera_power_seq_t sensor_power_seq[] = {
+	{REQUEST_GPIO, 0},
+	{REQUEST_VREG, 0},
+	{ENABLE_VREG, 0},
+	{ENABLE_GPIO, 0},
+	{CONFIG_CLK, 0},
+	{CONFIG_EXT_POWER_CTRL, 0},
+	{CONFIG_I2C_MUX, 0},
+};
+
+int32_t msm_sensor_bayer_power_up(struct msm_sensor_ctrl_t *s_ctrl)
+{
+	int32_t rc = 0, size = 0, index = 0;
+	struct msm_camera_sensor_info *data = s_ctrl->sensordata;
+	struct msm_camera_power_seq_t *power_seq = NULL;
+	CDBG("%s: %d\n", __func__, __LINE__);
+	if (s_ctrl->power_seq) {
+		power_seq = s_ctrl->power_seq;
+		size = s_ctrl->num_power_seq;
+	} else {
+		power_seq = &sensor_power_seq[0];
+		size = ARRAY_SIZE(sensor_power_seq);
+	}
+
+	s_ctrl->reg_ptr = kzalloc(sizeof(struct regulator *)
+			* data->sensor_platform_info->num_vreg, GFP_KERNEL);
+	if (!s_ctrl->reg_ptr) {
+		pr_err("%s: could not allocate mem for regulators\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	for (index = 0; index < size; index++) {
+		switch (power_seq[index].power_config) {
+		case REQUEST_GPIO:
+			rc = msm_camera_request_gpio_table(data, 1);
+			if (rc < 0) {
+				pr_err("%s: request gpio failed\n", __func__);
+				goto ERROR;
+			}
+			if (power_seq[index].delay)
+				usleep_range(power_seq[index].delay * 1000,
+					(power_seq[index].delay * 1000) + 1000);
+			break;
+		case REQUEST_VREG:
+			rc = msm_camera_config_vreg(
+				&s_ctrl->sensor_i2c_client->client->dev,
+				s_ctrl->sensordata->sensor_platform_info->
+				cam_vreg,
+				s_ctrl->sensordata->sensor_platform_info->
+				num_vreg,
+				s_ctrl->vreg_seq,
+				s_ctrl->num_vreg_seq,
+				s_ctrl->reg_ptr, 1);
+			if (rc < 0) {
+				pr_err("%s: regulator on failed\n", __func__);
+				goto ERROR;
+			}
+			if (power_seq[index].delay)
+				usleep_range(power_seq[index].delay * 1000,
+					(power_seq[index].delay * 1000) + 1000);
+			break;
+		case ENABLE_VREG:
+			rc = msm_camera_enable_vreg(
+				&s_ctrl->sensor_i2c_client->client->dev,
+				s_ctrl->sensordata->sensor_platform_info->
+				cam_vreg,
+				s_ctrl->sensordata->sensor_platform_info->
+				num_vreg,
+				s_ctrl->vreg_seq,
+				s_ctrl->num_vreg_seq,
+				s_ctrl->reg_ptr, 1);
+			if (rc < 0) {
+				pr_err("%s: enable regulator failed\n",
+					__func__);
+				goto ERROR;
+			}
+			if (power_seq[index].delay)
+				usleep_range(power_seq[index].delay * 1000,
+					(power_seq[index].delay * 1000) + 1000);
+			break;
+		case ENABLE_GPIO:
+			rc = msm_camera_config_gpio_table(data, 1);
+			if (rc < 0) {
+				pr_err("%s: config gpio failed\n", __func__);
+				goto ERROR;
+			}
+			if (power_seq[index].delay)
+				usleep_range(power_seq[index].delay * 1000,
+					(power_seq[index].delay * 1000) + 1000);
+			break;
+		case CONFIG_CLK:
+			if (s_ctrl->clk_rate != 0)
+				cam_clk_info->clk_rate = s_ctrl->clk_rate;
+
+			rc = msm_cam_clk_enable(
+				&s_ctrl->sensor_i2c_client->client->dev,
+				cam_clk_info, s_ctrl->cam_clk,
+				ARRAY_SIZE(cam_clk_info), 1);
+			if (rc < 0) {
+				pr_err("%s: clk enable failed\n", __func__);
+				goto ERROR;
+			}
+			if (power_seq[index].delay)
+				usleep_range(power_seq[index].delay * 1000,
+					(power_seq[index].delay * 1000) + 1000);
+			break;
+		case CONFIG_EXT_POWER_CTRL:
+			if (data->sensor_platform_info->ext_power_ctrl != NULL)
+				data->sensor_platform_info->ext_power_ctrl(1);
+			if (power_seq[index].delay)
+				usleep_range(power_seq[index].delay * 1000,
+					(power_seq[index].delay * 1000) + 1000);
+			break;
+		case CONFIG_I2C_MUX:
+			if (data->sensor_platform_info->i2c_conf &&
+				data->sensor_platform_info->i2c_conf->
+				use_i2c_mux)
+				msm_sensor_bayer_enable_i2c_mux(
+					data->sensor_platform_info->i2c_conf);
+			if (power_seq[index].delay)
+				usleep_range(power_seq[index].delay * 1000,
+					(power_seq[index].delay * 1000) + 1000);
+			break;
+		default:
+			pr_err("%s error power config %d\n", __func__,
+				power_seq[index].power_config);
+			rc = -EINVAL;
+			break;
+		}
+	}
+
+	return rc;
+
+ERROR:
+	for (index--; index >= 0; index--) {
+		switch (power_seq[index].power_config) {
+		case CONFIG_I2C_MUX:
+			if (data->sensor_platform_info->i2c_conf &&
+				data->sensor_platform_info->i2c_conf->
+				use_i2c_mux)
+				msm_sensor_bayer_disable_i2c_mux(
+					data->sensor_platform_info->i2c_conf);
+			break;
+		case CONFIG_EXT_POWER_CTRL:
+			if (data->sensor_platform_info->ext_power_ctrl != NULL)
+				data->sensor_platform_info->ext_power_ctrl(0);
+			break;
+		case CONFIG_CLK:
+			msm_cam_clk_enable(&s_ctrl->sensor_i2c_client->client->
+				dev, cam_clk_info, s_ctrl->cam_clk,
+				ARRAY_SIZE(cam_clk_info), 0);
+			break;
+		case ENABLE_GPIO:
+			msm_camera_config_gpio_table(data, 0);
+			break;
+		case ENABLE_VREG:
+			msm_camera_enable_vreg(&s_ctrl->sensor_i2c_client->
+				client->dev,
+				s_ctrl->sensordata->sensor_platform_info->
+				cam_vreg,
+				s_ctrl->sensordata->sensor_platform_info->
+				num_vreg,
+				s_ctrl->vreg_seq,
+				s_ctrl->num_vreg_seq,
+				s_ctrl->reg_ptr, 0);
+			break;
+		case REQUEST_VREG:
+			msm_camera_config_vreg(&s_ctrl->sensor_i2c_client->
+				client->dev,
+				s_ctrl->sensordata->sensor_platform_info->
+				cam_vreg,
+				s_ctrl->sensordata->sensor_platform_info->
+				num_vreg,
+				s_ctrl->vreg_seq,
+				s_ctrl->num_vreg_seq,
+				s_ctrl->reg_ptr, 0);
+			break;
+		case REQUEST_GPIO:
+			msm_camera_request_gpio_table(data, 0);
+			break;
+		default:
+			pr_err("%s error power config %d\n", __func__,
+				power_seq[index].power_config);
+			break;
+		}
+	}
+	kfree(s_ctrl->reg_ptr);
+	return rc;
+}
+
+int32_t msm_sensor_bayer_power_down(struct msm_sensor_ctrl_t *s_ctrl)
+{
+	int32_t size = 0, index = 0;
+	struct msm_camera_sensor_info *data = s_ctrl->sensordata;
+	struct msm_camera_power_seq_t *power_seq = NULL;
+	CDBG("%s\n", __func__);
+
+	if (s_ctrl->power_seq) {
+		power_seq = s_ctrl->power_seq;
+		size = s_ctrl->num_power_seq;
+	} else {
+		power_seq = &sensor_power_seq[0];
+		size = ARRAY_SIZE(sensor_power_seq);
+	}
+
+	for (index = (size - 1); index >= 0; index--) {
+		switch (power_seq[index].power_config) {
+		case CONFIG_I2C_MUX:
+			if (data->sensor_platform_info->i2c_conf &&
+				data->sensor_platform_info->i2c_conf->
+				use_i2c_mux)
+				msm_sensor_bayer_disable_i2c_mux(
+					data->sensor_platform_info->i2c_conf);
+			break;
+		case CONFIG_EXT_POWER_CTRL:
+			if (data->sensor_platform_info->ext_power_ctrl != NULL)
+				data->sensor_platform_info->ext_power_ctrl(0);
+			break;
+		case CONFIG_CLK:
+			msm_cam_clk_enable(&s_ctrl->sensor_i2c_client->client->
+				dev, cam_clk_info, s_ctrl->cam_clk,
+				ARRAY_SIZE(cam_clk_info), 0);
+			break;
+		case ENABLE_GPIO:
+			msm_camera_config_gpio_table(data, 0);
+			break;
+		case ENABLE_VREG:
+			msm_camera_enable_vreg(&s_ctrl->sensor_i2c_client->
+				client->dev,
+				s_ctrl->sensordata->sensor_platform_info->
+				cam_vreg,
+				s_ctrl->sensordata->sensor_platform_info->
+				num_vreg,
+				s_ctrl->vreg_seq,
+				s_ctrl->num_vreg_seq,
+				s_ctrl->reg_ptr, 0);
+			break;
+		case REQUEST_VREG:
+			msm_camera_config_vreg(&s_ctrl->sensor_i2c_client->
+				client->dev,
+				s_ctrl->sensordata->sensor_platform_info->
+				cam_vreg,
+				s_ctrl->sensordata->sensor_platform_info->
+				num_vreg,
+				s_ctrl->vreg_seq,
+				s_ctrl->num_vreg_seq,
+				s_ctrl->reg_ptr, 0);
+			break;
+		case REQUEST_GPIO:
+			msm_camera_request_gpio_table(data, 0);
+			break;
+		default:
+			pr_err("%s error power config %d\n", __func__,
+				power_seq[index].power_config);
+			break;
+		}
+	}
+	kfree(s_ctrl->reg_ptr);
+	return 0;
+}
+
+int32_t msm_sensor_bayer_match_id(struct msm_sensor_ctrl_t *s_ctrl)
+{
+	int32_t rc = 0;
+	uint16_t chipid = 0;
+	rc = msm_camera_i2c_read(
+			s_ctrl->sensor_i2c_client,
+			s_ctrl->sensor_id_info->sensor_id_reg_addr, &chipid,
+			MSM_CAMERA_I2C_WORD_DATA);
+	if (rc < 0) {
+		pr_err("%s: %s: read id failed\n", __func__,
+			s_ctrl->sensordata->sensor_name);
+		return rc;
+	}
+
+	CDBG("%s: read id: %x expected id %x:\n", __func__, chipid,
+		s_ctrl->sensor_id_info->sensor_id);
+	if (chipid != s_ctrl->sensor_id_info->sensor_id) {
+		pr_err("msm_sensor_match_id chip id doesnot match\n");
+		return -ENODEV;
+	}
+	return rc;
+}
+
+static int32_t msm_sensor_bayer_eeprom_read(struct msm_sensor_ctrl_t *s_ctrl)
+{
+	uint32_t reg_addr = 0;
+	uint8_t *data = s_ctrl->eeprom_data.data;
+	uint32_t num_byte = 0;
+	int rc = 0;
+	uint32_t i2c_addr;
+	struct msm_camera_sensor_info *sensor_info = s_ctrl->sensordata;
+	i2c_addr = sensor_info->eeprom_info->eeprom_i2c_slave_addr;
+	num_byte = s_ctrl->eeprom_data.length = sensor_info->eeprom_info->
+		eeprom_read_length;
+	reg_addr = sensor_info->eeprom_info->eeprom_reg_addr;
+
+	data = kzalloc(num_byte * sizeof(uint8_t), GFP_KERNEL);
+	if (!data) {
+		pr_err("%s:%d failed\n", __func__, __LINE__);
+		rc = -EFAULT;
+		return rc;
+	}
+
+	s_ctrl->sensor_i2c_client->client->addr = i2c_addr;
+	CDBG("eeprom read: i2c addr is %x num byte %d  reg addr %x\n",
+		i2c_addr, num_byte, reg_addr);
+	rc = msm_camera_i2c_read_seq(s_ctrl->sensor_i2c_client, reg_addr, data,
+		num_byte);
+	s_ctrl->sensor_i2c_client->client->addr = s_ctrl->sensor_i2c_addr;
+	return rc;
+}
+
+int32_t msm_sensor_bayer_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	int rc = 0;
+	struct msm_sensor_ctrl_t *s_ctrl;
+	CDBG("%s %s_i2c_probe called\n", __func__, client->name);
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		pr_err("%s %s i2c_check_functionality failed\n",
+			__func__, client->name);
+		rc = -EFAULT;
+		return rc;
+	}
+
+	s_ctrl = (struct msm_sensor_ctrl_t *)(id->driver_data);
+	if (s_ctrl->sensor_i2c_client != NULL) {
+		s_ctrl->sensor_i2c_client->client = client;
+		if (s_ctrl->sensor_i2c_addr != 0)
+			s_ctrl->sensor_i2c_client->client->addr =
+				s_ctrl->sensor_i2c_addr;
+	} else {
+		pr_err("%s %s sensor_i2c_client NULL\n",
+			__func__, client->name);
+		rc = -EFAULT;
+		return rc;
+	}
+
+	s_ctrl->sensordata = client->dev.platform_data;
+	if (s_ctrl->sensordata == NULL) {
+		pr_err("%s %s NULL sensor data\n", __func__, client->name);
+		return -EFAULT;
+	}
+
+	rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl);
+	if (rc < 0) {
+		pr_err("%s %s power up failed\n", __func__, client->name);
+		return rc;
+	}
+
+	if (s_ctrl->func_tbl->sensor_match_id)
+		rc = s_ctrl->func_tbl->sensor_match_id(s_ctrl);
+	else
+		rc = msm_sensor_bayer_match_id(s_ctrl);
+	if (rc < 0)
+		goto probe_fail;
+
+	if (!s_ctrl->wait_num_frames)
+		s_ctrl->wait_num_frames = 1;
+
+	pr_err("%s %s probe succeeded\n", __func__, client->name);
+	snprintf(s_ctrl->sensor_v4l2_subdev.name,
+		sizeof(s_ctrl->sensor_v4l2_subdev.name), "%s", id->name);
+	v4l2_i2c_subdev_init(&s_ctrl->sensor_v4l2_subdev, client,
+		s_ctrl->sensor_v4l2_subdev_ops);
+	s_ctrl->sensor_v4l2_subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	media_entity_init(&s_ctrl->sensor_v4l2_subdev.entity, 0, NULL, 0);
+	s_ctrl->sensor_v4l2_subdev.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
+	s_ctrl->sensor_v4l2_subdev.entity.group_id = SENSOR_DEV;
+	s_ctrl->sensor_v4l2_subdev.entity.name =
+		s_ctrl->sensor_v4l2_subdev.name;
+	msm_sensor_register(&s_ctrl->sensor_v4l2_subdev);
+	s_ctrl->sensor_v4l2_subdev.entity.revision =
+		s_ctrl->sensor_v4l2_subdev.devnode->num;
+	msm_sensor_bayer_eeprom_read(s_ctrl);
+	goto power_down;
+probe_fail:
+	pr_err("%s %s_i2c_probe failed\n", __func__, client->name);
+power_down:
+	if (rc > 0)
+		rc = 0;
+	s_ctrl->func_tbl->sensor_power_down(s_ctrl);
+	return rc;
+}
+
+int32_t msm_sensor_delay_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	int rc = 0;
+	struct msm_sensor_ctrl_t *s_ctrl;
+	CDBG("%s %s_delay_i2c_probe called\n", __func__, client->name);
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		pr_err("%s %s i2c_check_functionality failed\n",
+			__func__, client->name);
+		rc = -EFAULT;
+		return rc;
+	}
+
+	s_ctrl = (struct msm_sensor_ctrl_t *)(id->driver_data);
+	if (s_ctrl->sensor_i2c_client != NULL) {
+		s_ctrl->sensor_i2c_client->client = client;
+		if (s_ctrl->sensor_i2c_addr != 0)
+			s_ctrl->sensor_i2c_client->client->addr =
+				s_ctrl->sensor_i2c_addr;
+	} else {
+		pr_err("%s %s sensor_i2c_client NULL\n",
+			__func__, client->name);
+		rc = -EFAULT;
+		return rc;
+	}
+
+	s_ctrl->sensordata = client->dev.platform_data;
+	if (s_ctrl->sensordata == NULL) {
+		pr_err("%s %s NULL sensor data\n", __func__, client->name);
+		return -EFAULT;
+	}
+
+	if (!s_ctrl->wait_num_frames)
+		s_ctrl->wait_num_frames = 1;
+
+	pr_err("%s %s probe succeeded\n", __func__, client->name);
+	snprintf(s_ctrl->sensor_v4l2_subdev.name,
+		sizeof(s_ctrl->sensor_v4l2_subdev.name), "%s", id->name);
+	v4l2_i2c_subdev_init(&s_ctrl->sensor_v4l2_subdev, client,
+		s_ctrl->sensor_v4l2_subdev_ops);
+	s_ctrl->sensor_v4l2_subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	media_entity_init(&s_ctrl->sensor_v4l2_subdev.entity, 0, NULL, 0);
+	s_ctrl->sensor_v4l2_subdev.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
+	s_ctrl->sensor_v4l2_subdev.entity.group_id = SENSOR_DEV;
+	s_ctrl->sensor_v4l2_subdev.entity.name =
+		s_ctrl->sensor_v4l2_subdev.name;
+	msm_sensor_register(&s_ctrl->sensor_v4l2_subdev);
+	s_ctrl->sensor_v4l2_subdev.entity.revision =
+		s_ctrl->sensor_v4l2_subdev.devnode->num;
+	if (rc > 0)
+		rc = 0;
+	return rc;
+}
+
+int32_t msm_sensor_bayer_power(struct v4l2_subdev *sd, int on)
+{
+	int rc = 0;
+	struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(sd);
+	mutex_lock(s_ctrl->msm_sensor_mutex);
+	if (!on)
+		rc = s_ctrl->func_tbl->sensor_power_down(s_ctrl);
+	mutex_unlock(s_ctrl->msm_sensor_mutex);
+	return rc;
+}
+
+int32_t msm_sensor_bayer_v4l2_enum_fmt(struct v4l2_subdev *sd,
+	unsigned int index, enum v4l2_mbus_pixelcode *code)
+{
+	struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(sd);
+
+	if ((unsigned int)index >= s_ctrl->sensor_v4l2_subdev_info_size)
+		return -EINVAL;
+
+	*code = s_ctrl->sensor_v4l2_subdev_info[index].code;
+	return 0;
+}
+
+int32_t msm_sensor_bayer_v4l2_s_ctrl(struct v4l2_subdev *sd,
+	struct v4l2_control *ctrl)
+{
+	int rc = -1, i = 0;
+	struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(sd);
+	struct msm_sensor_v4l2_ctrl_info_t *v4l2_ctrl =
+		s_ctrl->msm_sensor_v4l2_ctrl_info;
+
+	CDBG("%s\n", __func__);
+	CDBG("%d\n", ctrl->id);
+	if (v4l2_ctrl == NULL)
+		return rc;
+	for (i = 0; i < s_ctrl->num_v4l2_ctrl; i++) {
+		if (v4l2_ctrl[i].ctrl_id == ctrl->id) {
+			if (v4l2_ctrl[i].s_v4l2_ctrl != NULL) {
+				CDBG("\n calling msm_sensor_s_ctrl_by_enum\n");
+				rc = v4l2_ctrl[i].s_v4l2_ctrl(
+					s_ctrl,
+					&s_ctrl->msm_sensor_v4l2_ctrl_info[i],
+					ctrl->value);
+			}
+			break;
+		}
+	}
+
+	return rc;
+}
+
+int32_t msm_sensor_bayer_v4l2_query_ctrl(
+	struct v4l2_subdev *sd, struct v4l2_queryctrl *qctrl)
+{
+	int rc = -1, i = 0;
+	struct msm_sensor_ctrl_t *s_ctrl =
+		(struct msm_sensor_ctrl_t *) sd->dev_priv;
+
+	CDBG("%s\n", __func__);
+	CDBG("%s id: %d\n", __func__, qctrl->id);
+
+	if (s_ctrl->msm_sensor_v4l2_ctrl_info == NULL)
+		return rc;
+
+	for (i = 0; i < s_ctrl->num_v4l2_ctrl; i++) {
+		if (s_ctrl->msm_sensor_v4l2_ctrl_info[i].ctrl_id == qctrl->id) {
+			qctrl->minimum =
+				s_ctrl->msm_sensor_v4l2_ctrl_info[i].min;
+			qctrl->maximum =
+				s_ctrl->msm_sensor_v4l2_ctrl_info[i].max;
+			qctrl->flags = 1;
+			rc = 0;
+			break;
+		}
+	}
+
+	return rc;
+}
+
+int msm_sensor_bayer_s_ctrl_by_enum(struct msm_sensor_ctrl_t *s_ctrl,
+		struct msm_sensor_v4l2_ctrl_info_t *ctrl_info, int value)
+{
+	int rc = 0;
+	CDBG("%s enter\n", __func__);
+	rc = msm_sensor_write_enum_conf_array(
+		s_ctrl->sensor_i2c_client,
+		ctrl_info->enum_cfg_settings, value);
+	return rc;
+}
+
diff --git a/drivers/media/video/msm/sensors/msm_sensor_bayer.h b/drivers/media/video/msm/sensors/msm_sensor_bayer.h
new file mode 100644
index 0000000..d12244b
--- /dev/null
+++ b/drivers/media/video/msm/sensors/msm_sensor_bayer.h
@@ -0,0 +1,76 @@
+/* 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.
+ */
+
+#ifndef MSM_SENSOR_BAYER_H
+#define MSM_SENSOR_BAYER_H
+
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include <mach/camera.h>
+#include <mach/gpio.h>
+#include <media/msm_camera.h>
+#include <media/v4l2-subdev.h>
+#include "msm_camera_i2c.h"
+#include "msm_camera_eeprom.h"
+#include "msm_sensor_common.h"
+
+struct sensor_driver_t {
+	struct platform_driver *platform_pdriver;
+	int32_t (*platform_probe)(struct platform_device *pdev);
+};
+
+int32_t msm_sensor_bayer_config(struct msm_sensor_ctrl_t *s_ctrl,
+			void __user *argp);
+int32_t msm_sensor_bayer_power_up(struct msm_sensor_ctrl_t *s_ctrl);
+int32_t msm_sensor_bayer_power_down(struct msm_sensor_ctrl_t *s_ctrl);
+
+int32_t msm_sensor_bayer_match_id(struct msm_sensor_ctrl_t *s_ctrl);
+int msm_sensor_bayer_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id);
+int32_t msm_sensor_delay_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id);
+int32_t msm_sensor_bayer_power(struct v4l2_subdev *sd, int on);
+
+int32_t msm_sensor_bayer_v4l2_s_ctrl(struct v4l2_subdev *sd,
+	struct v4l2_control *ctrl);
+
+int32_t msm_sensor_bayer_v4l2_query_ctrl(
+	struct v4l2_subdev *sd, struct v4l2_queryctrl *qctrl);
+
+int msm_sensor_bayer_s_ctrl_by_enum(struct msm_sensor_ctrl_t *s_ctrl,
+		struct msm_sensor_v4l2_ctrl_info_t *ctrl_info, int value);
+
+int msm_sensor_bayer_v4l2_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+			enum v4l2_mbus_pixelcode *code);
+
+long msm_sensor_bayer_subdev_ioctl(struct v4l2_subdev *sd,
+			unsigned int cmd, void *arg);
+
+int32_t msm_sensor_bayer_get_csi_params(struct msm_sensor_ctrl_t *s_ctrl,
+		struct csi_lane_params_t *sensor_output_info);
+
+#define VIDIOC_MSM_SENSOR_CFG \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 4, void __user *)
+
+#define VIDIOC_MSM_SENSOR_RELEASE \
+	_IO('V', BASE_VIDIOC_PRIVATE + 11)
+
+#define VIDIOC_MSM_SENSOR_CSID_INFO\
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 12, struct msm_sensor_csi_info *)
+#endif
diff --git a/drivers/media/video/msm/sensors/msm_sensor_common.c b/drivers/media/video/msm/sensors/msm_sensor_common.c
new file mode 100644
index 0000000..9dac632
--- /dev/null
+++ b/drivers/media/video/msm/sensors/msm_sensor_common.c
@@ -0,0 +1,18 @@
+/* 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 "msm_sensor_common.h"
+
+struct msm_sensor_ctrl_t *get_sctrl(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct msm_sensor_ctrl_t, sensor_v4l2_subdev);
+}
diff --git a/drivers/media/video/msm/sensors/msm_sensor_common.h b/drivers/media/video/msm/sensors/msm_sensor_common.h
new file mode 100644
index 0000000..79fe52e
--- /dev/null
+++ b/drivers/media/video/msm/sensors/msm_sensor_common.h
@@ -0,0 +1,226 @@
+/* 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.
+ */
+
+#ifndef MSM_SENSOR_COMMON_H
+#define MSM_SENSOR_COMMON_H
+
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <mach/camera.h>
+#include <media/msm_camera.h>
+#include <media/v4l2-subdev.h>
+#include "msm_camera_i2c.h"
+#include "msm_camera_eeprom.h"
+#define Q8  0x00000100
+#define Q10 0x00000400
+
+#define MSM_SENSOR_MCLK_8HZ 8000000
+#define MSM_SENSOR_MCLK_16HZ 16000000
+#define MSM_SENSOR_MCLK_24HZ 24000000
+
+#define DEFINE_MSM_MUTEX(mutexname) \
+	static struct mutex mutexname = __MUTEX_INITIALIZER(mutexname)
+
+struct gpio_tlmm_cfg {
+	uint32_t gpio;
+	uint32_t dir;
+	uint32_t pull;
+	uint32_t drvstr;
+};
+
+enum msm_sensor_reg_update {
+	/* Sensor egisters that need to be updated during initialization */
+	MSM_SENSOR_REG_INIT,
+	/* Sensor egisters that needs periodic I2C writes */
+	MSM_SENSOR_UPDATE_PERIODIC,
+	/* All the sensor Registers will be updated */
+	MSM_SENSOR_UPDATE_ALL,
+	/* Not valid update */
+	MSM_SENSOR_UPDATE_INVALID
+};
+
+enum msm_sensor_cam_mode_t {
+	MSM_SENSOR_MODE_2D_RIGHT,
+	MSM_SENSOR_MODE_2D_LEFT,
+	MSM_SENSOR_MODE_3D,
+	MSM_SENSOR_MODE_INVALID
+};
+
+enum msm_camera_power_config_t {
+	REQUEST_GPIO,
+	ENABLE_GPIO,
+	REQUEST_VREG,
+	ENABLE_VREG,
+	CONFIG_CLK,
+	CONFIG_EXT_POWER_CTRL,
+	CONFIG_I2C_MUX,
+};
+
+struct msm_camera_power_seq_t {
+	enum msm_camera_power_config_t power_config;
+	uint32_t delay;
+};
+
+struct msm_sensor_id_info_t {
+	uint16_t sensor_id_reg_addr;
+	uint16_t sensor_id;
+};
+
+struct msm_sensor_reg_t {
+	enum msm_camera_i2c_data_type default_data_type;
+	struct msm_camera_i2c_reg_conf *start_stream_conf;
+	uint8_t start_stream_conf_size;
+	struct msm_camera_i2c_reg_conf *stop_stream_conf;
+	uint8_t stop_stream_conf_size;
+	struct msm_camera_i2c_reg_conf *group_hold_on_conf;
+	uint8_t group_hold_on_conf_size;
+	struct msm_camera_i2c_reg_conf *group_hold_off_conf;
+	uint8_t group_hold_off_conf_size;
+	struct msm_camera_i2c_conf_array *init_settings;
+	uint8_t init_size;
+	struct msm_camera_i2c_conf_array *mode_settings;
+	struct msm_camera_i2c_conf_array *no_effect_settings;
+	struct msm_sensor_output_info_t *output_settings;
+	uint8_t num_conf;
+};
+
+enum msm_sensor_device_type_t {
+	MSM_SENSOR_I2C_DEVICE,
+	MSM_SENSOR_PLATFORM_DEVICE,
+};
+
+struct v4l2_subdev_info {
+	enum v4l2_mbus_pixelcode code;
+	enum v4l2_colorspace colorspace;
+	uint16_t fmt;
+	uint16_t order;
+};
+
+struct msm_sensor_ctrl_t;
+
+struct msm_sensor_v4l2_ctrl_info_t {
+	uint32_t ctrl_id;
+	int16_t min;
+	int16_t max;
+	int16_t step;
+	struct msm_camera_i2c_enum_conf_array *enum_cfg_settings;
+	int (*s_v4l2_ctrl) (struct msm_sensor_ctrl_t *,
+		struct msm_sensor_v4l2_ctrl_info_t *, int);
+};
+
+struct msm_sensor_fn_t {
+	void (*sensor_start_stream) (struct msm_sensor_ctrl_t *);
+	void (*sensor_stop_stream) (struct msm_sensor_ctrl_t *);
+	void (*sensor_group_hold_on) (struct msm_sensor_ctrl_t *);
+	void (*sensor_group_hold_off) (struct msm_sensor_ctrl_t *);
+
+	int32_t (*sensor_set_fps) (struct msm_sensor_ctrl_t *,
+			struct fps_cfg *);
+	int32_t (*sensor_write_exp_gain) (struct msm_sensor_ctrl_t *,
+			uint16_t, uint32_t);
+	int32_t (*sensor_write_snapshot_exp_gain) (struct msm_sensor_ctrl_t *,
+			uint16_t, uint32_t);
+	int32_t (*sensor_setting) (struct msm_sensor_ctrl_t *,
+			int update_type, int rt);
+	int32_t (*sensor_csi_setting) (struct msm_sensor_ctrl_t *,
+			int update_type, int rt);
+	int32_t (*sensor_set_sensor_mode)
+			(struct msm_sensor_ctrl_t *, int, int);
+	int32_t (*sensor_mode_init) (struct msm_sensor_ctrl_t *,
+		int, struct sensor_init_cfg *);
+	int32_t (*sensor_get_output_info) (struct msm_sensor_ctrl_t *,
+		struct sensor_output_info_t *);
+	int (*sensor_config) (struct msm_sensor_ctrl_t *, void __user *);
+	int (*sensor_power_down)
+		(struct msm_sensor_ctrl_t *);
+	int (*sensor_power_up) (struct msm_sensor_ctrl_t *);
+	int32_t (*sensor_match_id)(struct msm_sensor_ctrl_t *s_ctrl);
+	void (*sensor_adjust_frame_lines) (struct msm_sensor_ctrl_t *s_ctrl);
+	int32_t (*sensor_get_csi_params)(struct msm_sensor_ctrl_t *,
+		struct csi_lane_params_t *);
+};
+
+struct msm_sensor_csi_info {
+	uint8_t is_csic;
+};
+
+enum msm_sensor_state {
+	MSM_SENSOR_POWER_UP,
+	MSM_SENSOR_POWER_DOWN,
+};
+
+struct msm_sensor_eeprom_data {
+	uint8_t *data;
+	uint32_t length;
+};
+
+struct msm_sensor_ctrl_t {
+	struct  msm_camera_sensor_info *sensordata;
+	struct i2c_client *msm_sensor_client;
+	struct i2c_driver *sensor_i2c_driver;
+	struct platform_device *pdev;
+	struct msm_camera_i2c_client *sensor_i2c_client;
+	uint16_t sensor_i2c_addr;
+	enum msm_camera_vreg_name_t *vreg_seq;
+	int num_vreg_seq;
+	struct msm_camera_power_seq_t *power_seq;
+	int num_power_seq;
+	enum msm_sensor_device_type_t sensor_device_type;
+
+	struct msm_sensor_output_reg_addr_t *sensor_output_reg_addr;
+	struct msm_sensor_id_info_t *sensor_id_info;
+	struct msm_sensor_exp_gain_info_t *sensor_exp_gain_info;
+	struct msm_sensor_reg_t *msm_sensor_reg;
+	struct msm_sensor_v4l2_ctrl_info_t *msm_sensor_v4l2_ctrl_info;
+	uint16_t num_v4l2_ctrl;
+	uint8_t is_csic;
+
+	uint16_t curr_line_length_pclk;
+	uint16_t curr_frame_length_lines;
+
+	uint32_t fps_divider;
+	enum msm_sensor_resolution_t curr_res;
+	enum msm_sensor_cam_mode_t cam_mode;
+
+	struct mutex *msm_sensor_mutex;
+
+	struct v4l2_subdev sensor_v4l2_subdev;
+	struct v4l2_subdev_info *sensor_v4l2_subdev_info;
+	uint8_t sensor_v4l2_subdev_info_size;
+	struct v4l2_subdev_ops *sensor_v4l2_subdev_ops;
+	struct msm_sensor_fn_t *func_tbl;
+	struct regulator **reg_ptr;
+	struct clk *cam_clk[2];
+	long clk_rate;
+	enum msm_sensor_state sensor_state;
+	/* Number of frames to delay after start / stop stream in Q10 format.
+	   Initialize to -1 for this value to be ignored */
+	int16_t wait_num_frames;
+	/* minimum delay after stop / stop stream in ms */
+	uint16_t min_delay;
+	/* delay (in ms) after power up sequence */
+	uint16_t power_seq_delay;
+	struct msm_sensor_eeprom_data eeprom_data;
+};
+
+struct msm_sensor_ctrl_t *get_sctrl(struct v4l2_subdev *sd);
+
+#endif
diff --git a/drivers/media/video/msm/sensors/msm_sensor_init.c b/drivers/media/video/msm/sensors/msm_sensor_init.c
new file mode 100644
index 0000000..41c00eb
--- /dev/null
+++ b/drivers/media/video/msm/sensors/msm_sensor_init.c
@@ -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.
+ *
+ */
+
+#include "msm_sensor.h"
+#include "msm.h"
+#include "msm_sensor_bayer.h"
+#include "imx091.h"
+
+static struct i2c_driver *sensor_i2c_driver[] = {
+	/* back camera */
+	&imx091_i2c_driver,
+	/* front camera */
+};
+
+static int __init msm_sensor_init_module(void)
+{
+	int index = 0;
+	for (index = 0; index < ARRAY_SIZE(sensor_i2c_driver); index++)
+		i2c_add_driver(sensor_i2c_driver[index]);
+	return 0;
+}
+
+module_init(msm_sensor_init_module);
+MODULE_DESCRIPTION("Sensor driver probe");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/sensors/mt9e013_v4l2.c b/drivers/media/video/msm/sensors/mt9e013_v4l2.c
index 69a5498..a38cb57 100644
--- a/drivers/media/video/msm/sensors/mt9e013_v4l2.c
+++ b/drivers/media/video/msm/sensors/mt9e013_v4l2.c
@@ -325,22 +325,6 @@
 	},
 };
 
-static struct msm_camera_csi_params mt9e013_csi_params = {
-	.data_format = CSI_10BIT,
-	.lane_cnt    = 2,
-	.lane_assign = 0xe4,
-	.dpcm_scheme = 0,
-	.settle_cnt  = 0x18,
-};
-
-static struct msm_camera_csi_params *mt9e013_csi_params_array[] = {
-	&mt9e013_csi_params,
-	&mt9e013_csi_params,
-	&mt9e013_csi_params,
-	&mt9e013_csi_params,
-	&mt9e013_csi_params,
-};
-
 static struct msm_sensor_output_reg_addr_t mt9e013_reg_addr = {
 	.x_output = 0x34C,
 	.y_output = 0x34E,
@@ -472,7 +456,6 @@
 	.sensor_config = msm_sensor_config,
 	.sensor_power_up = msm_sensor_power_up,
 	.sensor_power_down = msm_sensor_power_down,
-	.sensor_get_csi_params = msm_sensor_get_csi_params,
 };
 
 static struct msm_sensor_reg_t mt9e013_regs = {
@@ -497,7 +480,6 @@
 	.sensor_id_info = &mt9e013_id_info,
 	.sensor_exp_gain_info = &mt9e013_exp_gain_info,
 	.cam_mode = MSM_SENSOR_MODE_INVALID,
-	.csic_params = &mt9e013_csi_params_array[0],
 	.msm_sensor_mutex = &mt9e013_mut,
 	.sensor_i2c_driver = &mt9e013_i2c_driver,
 	.sensor_v4l2_subdev_info = mt9e013_subdev_info,
diff --git a/drivers/media/video/msm/sensors/mt9m114_v4l2.c b/drivers/media/video/msm/sensors/mt9m114_v4l2.c
index 806bcc2..cba9538 100644
--- a/drivers/media/video/msm/sensors/mt9m114_v4l2.c
+++ b/drivers/media/video/msm/sensors/mt9m114_v4l2.c
@@ -1184,30 +1184,6 @@
 	},
 };
 
-static struct msm_camera_csid_vc_cfg mt9m114_cid_cfg[] = {
-	{0, CSI_YUV422_8, CSI_DECODE_8BIT},
-	{1, CSI_EMBED_DATA, CSI_DECODE_8BIT},
-};
-
-static struct msm_camera_csi2_params mt9m114_csi_params = {
-	.csid_params = {
-		.lane_cnt = 1,
-		.lut_params = {
-			.num_cid = 2,
-			.vc_cfg = mt9m114_cid_cfg,
-		},
-	},
-	.csiphy_params = {
-		.lane_cnt = 1,
-		.settle_cnt = 0x14,
-	},
-};
-
-static struct msm_camera_csi2_params *mt9m114_csi_params_array[] = {
-	&mt9m114_csi_params,
-	&mt9m114_csi_params,
-};
-
 static struct msm_sensor_output_reg_addr_t mt9m114_reg_addr = {
 	.x_output = 0xC868,
 	.y_output = 0xC86A,
@@ -1215,6 +1191,12 @@
 	.frame_length_lines = 0xC86A,
 };
 
+static enum msm_camera_vreg_name_t mt9m114_veg_seq[] = {
+	CAM_VIO,
+	CAM_VDIG,
+	CAM_VANA,
+};
+
 static struct msm_sensor_id_info_t mt9m114_id_info = {
 	.sensor_id_reg_addr = 0x0,
 	.sensor_id = 0x2481,
@@ -1288,10 +1270,13 @@
 	.num_v4l2_ctrl = ARRAY_SIZE(mt9m114_v4l2_ctrl_info),
 	.sensor_i2c_client = &mt9m114_sensor_i2c_client,
 	.sensor_i2c_addr = 0x90,
+	.vreg_seq = mt9m114_veg_seq,
+	.num_vreg_seq = ARRAY_SIZE(mt9m114_veg_seq),
 	.sensor_output_reg_addr = &mt9m114_reg_addr,
 	.sensor_id_info = &mt9m114_id_info,
 	.cam_mode = MSM_SENSOR_MODE_INVALID,
-	.csi_params = &mt9m114_csi_params_array[0],
+	.min_delay = 30,
+	.power_seq_delay = 60,
 	.msm_sensor_mutex = &mt9m114_mut,
 	.sensor_i2c_driver = &mt9m114_i2c_driver,
 	.sensor_v4l2_subdev_info = mt9m114_subdev_info,
diff --git a/drivers/media/video/msm/sensors/ov2720.c b/drivers/media/video/msm/sensors/ov2720.c
index e08cd0a..bc38f62 100644
--- a/drivers/media/video/msm/sensors/ov2720.c
+++ b/drivers/media/video/msm/sensors/ov2720.c
@@ -658,34 +658,6 @@
 	},
 };
 
-static struct msm_camera_csid_vc_cfg ov2720_cid_cfg[] = {
-	{0, CSI_RAW10, CSI_DECODE_10BIT},
-	{1, CSI_EMBED_DATA, CSI_DECODE_8BIT},
-};
-
-static struct msm_camera_csi2_params ov2720_csi_params = {
-	.csid_params = {
-		.lane_cnt = 2,
-		.lut_params = {
-			.num_cid = 2,
-			.vc_cfg = ov2720_cid_cfg,
-		},
-	},
-	.csiphy_params = {
-		.lane_cnt = 2,
-		.settle_cnt = 0x1B,
-	},
-};
-
-static struct msm_camera_csi2_params *ov2720_csi_params_array[] = {
-	&ov2720_csi_params,
-	&ov2720_csi_params,
-	&ov2720_csi_params,
-	&ov2720_csi_params,
-	&ov2720_csi_params,
-	&ov2720_csi_params,
-};
-
 static struct msm_sensor_output_reg_addr_t ov2720_reg_addr = {
 	.x_output = 0x3808,
 	.y_output = 0x380a,
@@ -704,6 +676,12 @@
 	.vert_offset = 6,
 };
 
+static enum msm_camera_vreg_name_t ov2720_veg_seq[] = {
+	CAM_VIO,
+	CAM_VANA,
+	CAM_VDIG,
+};
+
 static int32_t ov2720_write_exp_gain(struct msm_sensor_ctrl_t *s_ctrl,
 		uint16_t gain, uint32_t line)
 {
@@ -722,9 +700,15 @@
 	int_time[0] = line >> 12;
 	int_time[1] = line >> 4;
 	int_time[2] = line << 4;
-	msm_camera_i2c_write_seq(s_ctrl->sensor_i2c_client,
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
 		s_ctrl->sensor_exp_gain_info->coarse_int_time_addr-1,
-		&int_time[0], 3);
+		int_time[0], MSM_CAMERA_I2C_BYTE_DATA);
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_exp_gain_info->coarse_int_time_addr,
+		int_time[1], MSM_CAMERA_I2C_BYTE_DATA);
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_exp_gain_info->coarse_int_time_addr+1,
+		int_time[2], MSM_CAMERA_I2C_BYTE_DATA);
 	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
 		s_ctrl->sensor_exp_gain_info->global_gain_addr, gain,
 		MSM_CAMERA_I2C_WORD_DATA);
@@ -849,11 +833,12 @@
 	.msm_sensor_reg = &ov2720_regs,
 	.sensor_i2c_client = &ov2720_sensor_i2c_client,
 	.sensor_i2c_addr = 0x6C,
+	.vreg_seq = ov2720_veg_seq,
+	.num_vreg_seq = ARRAY_SIZE(ov2720_veg_seq),
 	.sensor_output_reg_addr = &ov2720_reg_addr,
 	.sensor_id_info = &ov2720_id_info,
 	.sensor_exp_gain_info = &ov2720_exp_gain_info,
 	.cam_mode = MSM_SENSOR_MODE_INVALID,
-	.csi_params = &ov2720_csi_params_array[0],
 	.msm_sensor_mutex = &ov2720_mut,
 	.sensor_i2c_driver = &ov2720_i2c_driver,
 	.sensor_v4l2_subdev_info = ov2720_subdev_info,
diff --git a/drivers/media/video/msm/sensors/ov5647_v4l2.c b/drivers/media/video/msm/sensors/ov5647_v4l2.c
index d192563..eb6a8b0 100644
--- a/drivers/media/video/msm/sensors/ov5647_v4l2.c
+++ b/drivers/media/video/msm/sensors/ov5647_v4l2.c
@@ -159,7 +159,7 @@
 
 static struct msm_camera_i2c_reg_conf ov5647_zsl_settings[] = {
 	{0x3035, 0x21},
-	{0x3036, 0x2f},
+	{0x3036, 0x4f},
 	{0x3821, 0x06},
 	{0x3820, 0x00},
 	{0x3612, 0x0b},
@@ -343,14 +343,6 @@
 	ARRAY_SIZE(ov5647_zsl_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
 };
 
-static struct msm_camera_csi_params ov5647_csi_params = {
-	.data_format = CSI_8BIT,
-	.lane_cnt    = 2,
-	.lane_assign = 0xe4,
-	.dpcm_scheme = 0,
-	.settle_cnt  = 10,
-};
-
 static struct v4l2_subdev_info ov5647_subdev_info[] = {
 	{
 		.code   = V4L2_MBUS_FMT_SBGGR10_1X10,
@@ -417,14 +409,6 @@
 	.frame_length_lines = 0x380E,
 };
 
-static struct msm_camera_csi_params *ov5647_csi_params_array[] = {
-	&ov5647_csi_params, /* Snapshot */
-	&ov5647_csi_params, /* Preview */
-	&ov5647_csi_params, /* 60fps */
-	&ov5647_csi_params, /* 90fps */
-	&ov5647_csi_params, /* ZSL */
-};
-
 static struct msm_sensor_id_info_t ov5647_id_info = {
 	.sensor_id_reg_addr = 0x300a,
 	.sensor_id = 0x5647,
@@ -572,7 +556,8 @@
 	s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl);
 
 	/* adjust frame rate */
-	if (line > (fl_lines - offset))
+	if ((s_ctrl->curr_res < MSM_SENSOR_RES_2) &&
+		(line > (fl_lines - offset)))
 		fl_lines = line + offset;
 
 	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
@@ -733,13 +718,15 @@
 
 static int32_t vfe_clk = 266667000;
 
-int32_t ov5647_sensor_setting(struct msm_sensor_ctrl_t *s_ctrl,
-			int update_type, int res)
+static void ov5647_stop_stream(struct msm_sensor_ctrl_t *s_ctrl)
 {
-	int32_t rc = 0;
-	static int csi_config;
-	s_ctrl->func_tbl->sensor_stop_stream(s_ctrl);
-	if (csi_config == 0 || res == 0)
+	msm_camera_i2c_write_tbl(
+		s_ctrl->sensor_i2c_client,
+		s_ctrl->msm_sensor_reg->stop_stream_conf,
+		s_ctrl->msm_sensor_reg->stop_stream_conf_size,
+		s_ctrl->msm_sensor_reg->default_data_type);
+
+	if (s_ctrl->curr_res == MSM_SENSOR_RES_FULL)
 		msleep(66);
 	else
 		msleep(266);
@@ -748,37 +735,31 @@
 			s_ctrl->sensor_i2c_client,
 			0x4800, 0x25,
 			MSM_CAMERA_I2C_BYTE_DATA);
+}
+
+int32_t ov5647_sensor_setting(struct msm_sensor_ctrl_t *s_ctrl,
+			int update_type, int res)
+{
+	int32_t rc = 0;
 	if (update_type == MSM_SENSOR_REG_INIT) {
 		CDBG("Register INIT\n");
-		s_ctrl->curr_csi_params = NULL;
+		s_ctrl->func_tbl->sensor_stop_stream(s_ctrl);
 		msm_camera_i2c_write(
 				s_ctrl->sensor_i2c_client,
 				0x103, 0x1,
 				MSM_CAMERA_I2C_BYTE_DATA);
 		msm_sensor_enable_debugfs(s_ctrl);
 		msm_sensor_write_init_settings(s_ctrl);
-		csi_config = 0;
 	} else if (update_type == MSM_SENSOR_UPDATE_PERIODIC) {
 		CDBG("PERIODIC : %d\n", res);
 		msm_sensor_write_conf_array(
 			s_ctrl->sensor_i2c_client,
 			s_ctrl->msm_sensor_reg->mode_settings, res);
 		msleep(30);
-		if (!csi_config) {
-			s_ctrl->curr_csic_params = s_ctrl->csic_params[res];
-			CDBG("CSI config in progress\n");
-			v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
-				NOTIFY_CSIC_CFG,
-				s_ctrl->curr_csic_params);
-			CDBG("CSI config is done\n");
-			mb();
-			msleep(30);
-			csi_config = 1;
 		msm_camera_i2c_write(
 			s_ctrl->sensor_i2c_client,
 			0x100, 0x1,
 			MSM_CAMERA_I2C_BYTE_DATA);
-		}
 		msm_camera_i2c_write(
 			s_ctrl->sensor_i2c_client,
 			0x4800, 0x4,
@@ -788,14 +769,12 @@
 			v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
 					NOTIFY_PCLK_CHANGE,
 					&vfe_clk);
-		s_ctrl->func_tbl->sensor_start_stream(s_ctrl);
-		msleep(50);
 	}
 	return rc;
 }
 static struct msm_sensor_fn_t ov5647_func_tbl = {
 	.sensor_start_stream = msm_sensor_start_stream,
-	.sensor_stop_stream = msm_sensor_stop_stream,
+	.sensor_stop_stream = ov5647_stop_stream,
 	.sensor_group_hold_on = msm_sensor_group_hold_on,
 	.sensor_group_hold_off = msm_sensor_group_hold_off,
 	.sensor_set_fps = msm_sensor_set_fps,
@@ -808,7 +787,6 @@
 	.sensor_config = msm_sensor_config,
 	.sensor_power_up = ov5647_sensor_power_up,
 	.sensor_power_down = ov5647_sensor_power_down,
-	.sensor_get_csi_params = msm_sensor_get_csi_params,
 };
 
 static struct msm_sensor_reg_t ov5647_regs = {
@@ -837,7 +815,6 @@
 	.sensor_id_info = &ov5647_id_info,
 	.sensor_exp_gain_info = &ov5647_exp_gain_info,
 	.cam_mode = MSM_SENSOR_MODE_INVALID,
-	.csic_params = &ov5647_csi_params_array[0],
 	.msm_sensor_mutex = &ov5647_mut,
 	.sensor_i2c_driver = &ov5647_i2c_driver,
 	.sensor_v4l2_subdev_info = ov5647_subdev_info,
diff --git a/drivers/media/video/msm/sensors/ov7692_v4l2.c b/drivers/media/video/msm/sensors/ov7692_v4l2.c
index 71d436e..e0d4b53f 100644
--- a/drivers/media/video/msm/sensors/ov7692_v4l2.c
+++ b/drivers/media/video/msm/sensors/ov7692_v4l2.c
@@ -821,18 +821,6 @@
 
 };
 
-static struct msm_camera_csi_params ov7692_csi_params = {
-	.data_format = CSI_8BIT,
-	.lane_cnt    = 1,
-	.lane_assign = 0xe4,
-	.dpcm_scheme = 0,
-	.settle_cnt  = 0x14,
-};
-
-static struct msm_camera_csi_params *ov7692_csi_params_array[] = {
-	&ov7692_csi_params,
-};
-
 static struct msm_sensor_output_reg_addr_t ov7692_reg_addr = {
 	.x_output = 0xCC,
 	.y_output = 0xCE,
@@ -899,7 +887,6 @@
 	.sensor_config = msm_sensor_config,
 	.sensor_power_up = msm_sensor_power_up,
 	.sensor_power_down = msm_sensor_power_down,
-	.sensor_get_csi_params = msm_sensor_get_csi_params,
 };
 
 static struct msm_sensor_reg_t ov7692_regs = {
@@ -925,7 +912,6 @@
 	.sensor_output_reg_addr = &ov7692_reg_addr,
 	.sensor_id_info = &ov7692_id_info,
 	.cam_mode = MSM_SENSOR_MODE_INVALID,
-	.csic_params = &ov7692_csi_params_array[0],
 	.msm_sensor_mutex = &ov7692_mut,
 	.sensor_i2c_driver = &ov7692_i2c_driver,
 	.sensor_v4l2_subdev_info = ov7692_subdev_info,
diff --git a/drivers/media/video/msm/sensors/ov8825_v4l2.c b/drivers/media/video/msm/sensors/ov8825_v4l2.c
index 1ae3dfd..092ee72 100644
--- a/drivers/media/video/msm/sensors/ov8825_v4l2.c
+++ b/drivers/media/video/msm/sensors/ov8825_v4l2.c
@@ -510,19 +510,6 @@
 	},
 };
 
-static struct msm_camera_csi_params ov8825_csi_params = {
-	.data_format = CSI_10BIT,
-	.lane_cnt    = 2,
-	.lane_assign = 0xe4,
-	.dpcm_scheme = 0,
-	.settle_cnt  = 14,
-};
-
-static struct msm_camera_csi_params *ov8825_csi_params_array[] = {
-	&ov8825_csi_params,
-	&ov8825_csi_params,
-};
-
 static struct msm_sensor_output_reg_addr_t ov8825_reg_addr = {
 	.x_output = 0x3808,
 	.y_output = 0x380a,
@@ -868,13 +855,10 @@
 			int update_type, int res)
 {
 	int32_t rc = 0;
-	static int csi_config;
 
-	s_ctrl->func_tbl->sensor_stop_stream(s_ctrl);
-	msleep(30);
 	if (update_type == MSM_SENSOR_REG_INIT) {
 		CDBG("Register INIT\n");
-		s_ctrl->curr_csi_params = NULL;
+		s_ctrl->func_tbl->sensor_stop_stream(s_ctrl);
 		msm_sensor_enable_debugfs(s_ctrl);
 		msm_sensor_write_init_settings(s_ctrl);
 		CDBG("Update OTP\n");
@@ -885,30 +869,15 @@
 		usleep_range(10000, 11000);
 		msm_camera_i2c_write(s_ctrl->sensor_i2c_client, 0x100, 0x0,
 		  MSM_CAMERA_I2C_BYTE_DATA);
-		csi_config = 0;
 	} else if (update_type == MSM_SENSOR_UPDATE_PERIODIC) {
 		CDBG("PERIODIC : %d\n", res);
 		msm_sensor_write_conf_array(
 			s_ctrl->sensor_i2c_client,
 			s_ctrl->msm_sensor_reg->mode_settings, res);
 		msleep(30);
-		if (!csi_config) {
-			s_ctrl->curr_csic_params = s_ctrl->csic_params[res];
-			CDBG("CSI config in progress\n");
-			v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
-				NOTIFY_CSIC_CFG,
-				s_ctrl->curr_csic_params);
-			CDBG("CSI config is done\n");
-			mb();
-			msleep(30);
-			csi_config = 1;
-		}
 		v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
 			NOTIFY_PCLK_CHANGE,
 			&s_ctrl->sensordata->pdata->ioclk.vfe_clk_rate);
-
-		s_ctrl->func_tbl->sensor_start_stream(s_ctrl);
-		msleep(50);
 	}
 	return rc;
 }
@@ -955,7 +924,6 @@
 	.sensor_id_info = &ov8825_id_info,
 	.sensor_exp_gain_info = &ov8825_exp_gain_info,
 	.cam_mode = MSM_SENSOR_MODE_INVALID,
-	.csic_params = &ov8825_csi_params_array[0],
 	.msm_sensor_mutex = &ov8825_mut,
 	.sensor_i2c_driver = &ov8825_i2c_driver,
 	.sensor_v4l2_subdev_info = ov8825_subdev_info,
diff --git a/drivers/media/video/msm/sensors/ov9726_v4l2.c b/drivers/media/video/msm/sensors/ov9726_v4l2.c
index 27a8b38..50c13c6 100644
--- a/drivers/media/video/msm/sensors/ov9726_v4l2.c
+++ b/drivers/media/video/msm/sensors/ov9726_v4l2.c
@@ -155,18 +155,6 @@
 	},
 };
 
-static struct msm_camera_csi_params ov9726_csi_params = {
-	       .data_format = CSI_10BIT,
-	       .lane_cnt    = 1,
-	       .lane_assign = 0xe4,
-	       .dpcm_scheme = 0,
-	       .settle_cnt  = 7,
-};
-
-static struct msm_camera_csi_params *ov9726_csi_params_array[] = {
-	&ov9726_csi_params,
-};
-
 static struct msm_sensor_output_reg_addr_t ov9726_reg_addr = {
 	.x_output = 0x034c,
 	.y_output = 0x034e,
@@ -236,7 +224,6 @@
 	.sensor_config = msm_sensor_config,
 	.sensor_power_up = msm_sensor_power_up,
 	.sensor_power_down = msm_sensor_power_down,
-	.sensor_get_csi_params = msm_sensor_get_csi_params,
 };
 
 static struct msm_sensor_reg_t ov9726_regs = {
@@ -265,7 +252,6 @@
 	.sensor_id_info = &ov9726_id_info,
 	.sensor_exp_gain_info = &ov9726_exp_gain_info,
 	.cam_mode = MSM_SENSOR_MODE_INVALID,
-	.csic_params = &ov9726_csi_params_array[0],
 	.msm_sensor_mutex = &ov9726_mut,
 	.sensor_i2c_driver = &ov9726_i2c_driver,
 	.sensor_v4l2_subdev_info = ov9726_subdev_info,
diff --git a/drivers/media/video/msm/sensors/s5k3l1yx.c b/drivers/media/video/msm/sensors/s5k3l1yx.c
index 64b004e..6a2372e 100644
--- a/drivers/media/video/msm/sensors/s5k3l1yx.c
+++ b/drivers/media/video/msm/sensors/s5k3l1yx.c
@@ -481,7 +481,7 @@
 		.line_length_pclk = 5336,
 		.frame_length_lines = 3052,
 		.vt_pixel_clk = 330000000,
-		.op_pixel_clk = 320000000,
+		.op_pixel_clk = 264000000,
 		.binning_factor = 1,
 	},
 	/* 30 fps preview */
@@ -491,7 +491,7 @@
 		.line_length_pclk = 4480,
 		.frame_length_lines = 2412,
 		.vt_pixel_clk = 330000000,
-		.op_pixel_clk = 320000000,
+		.op_pixel_clk = 264000000,
 		.binning_factor = 1,
 	},
 	/* 60 fps video */
@@ -501,7 +501,7 @@
 		.line_length_pclk = 5336,
 		.frame_length_lines = 992,
 		.vt_pixel_clk = 330000000,
-		.op_pixel_clk = 320000000,
+		.op_pixel_clk = 264000000,
 		.binning_factor = 1,
 	},
 	/* 90 fps video */
@@ -511,7 +511,7 @@
 		.line_length_pclk = 5336,
 		.frame_length_lines = 664,
 		.vt_pixel_clk = 330000000,
-		.op_pixel_clk = 320000000,
+		.op_pixel_clk = 264000000,
 		.binning_factor = 1,
 	},
 	/* 120 fps video */
@@ -521,7 +521,7 @@
 		.line_length_pclk = 5336,
 		.frame_length_lines = 514,
 		.vt_pixel_clk = 330000000,
-		.op_pixel_clk = 320000000,
+		.op_pixel_clk = 264000000,
 		.binning_factor = 1,
 	},
 	/* 24 fps snapshot */
@@ -536,53 +536,6 @@
 	},
 };
 
-static struct msm_camera_csid_vc_cfg s5k3l1yx_cid_cfg[] = {
-	{0, CSI_RAW10, CSI_DECODE_10BIT},
-	{1, CSI_EMBED_DATA, CSI_DECODE_8BIT},
-};
-
-static struct msm_camera_csi2_params s5k3l1yx_csi_params = {
-	.csid_params = {
-		.lane_cnt = 4,
-		.lut_params = {
-			.num_cid = ARRAY_SIZE(s5k3l1yx_cid_cfg),
-			.vc_cfg = s5k3l1yx_cid_cfg,
-		},
-	},
-	.csiphy_params = {
-		.lane_cnt = 4,
-		.settle_cnt = 0x1B,
-	},
-};
-
-static struct msm_camera_csid_vc_cfg s5k3l1yx_cid_dpcm_cfg[] = {
-	{0, CSI_RAW8, CSI_DECODE_DPCM_10_8_10},
-};
-
-static struct msm_camera_csi2_params s5k3l1yx_csi_dpcm_params = {
-	.csid_params = {
-		.lane_assign = 0xe4,
-		.lane_cnt = 4,
-		.lut_params = {
-			.num_cid = ARRAY_SIZE(s5k3l1yx_cid_dpcm_cfg),
-			.vc_cfg = s5k3l1yx_cid_dpcm_cfg,
-		},
-	},
-	.csiphy_params = {
-		.lane_cnt = 4,
-		.settle_cnt = 0x1B,
-	},
-};
-
-static struct msm_camera_csi2_params *s5k3l1yx_csi_params_array[] = {
-	&s5k3l1yx_csi_params,
-	&s5k3l1yx_csi_params,
-	&s5k3l1yx_csi_params,
-	&s5k3l1yx_csi_params,
-	&s5k3l1yx_csi_params,
-	&s5k3l1yx_csi_dpcm_params,
-};
-
 static struct msm_sensor_output_reg_addr_t s5k3l1yx_reg_addr = {
 	.x_output = 0x34C,
 	.y_output = 0x34E,
@@ -590,6 +543,13 @@
 	.frame_length_lines = 0x340,
 };
 
+static enum msm_camera_vreg_name_t s5k3l1yx_veg_seq[] = {
+	CAM_VDIG,
+	CAM_VANA,
+	CAM_VIO,
+	CAM_VAF,
+};
+
 static struct msm_sensor_id_info_t s5k3l1yx_id_info = {
 	.sensor_id_reg_addr = 0x0,
 	.sensor_id = 0x3121,
@@ -717,11 +677,12 @@
 	.msm_sensor_reg = &s5k3l1yx_regs,
 	.sensor_i2c_client = &s5k3l1yx_sensor_i2c_client,
 	.sensor_i2c_addr = 0x6E,
+	.vreg_seq = s5k3l1yx_veg_seq,
+	.num_vreg_seq = ARRAY_SIZE(s5k3l1yx_veg_seq),
 	.sensor_output_reg_addr = &s5k3l1yx_reg_addr,
 	.sensor_id_info = &s5k3l1yx_id_info,
 	.sensor_exp_gain_info = &s5k3l1yx_exp_gain_info,
 	.cam_mode = MSM_SENSOR_MODE_INVALID,
-	.csi_params = &s5k3l1yx_csi_params_array[0],
 	.msm_sensor_mutex = &s5k3l1yx_mut,
 	.sensor_i2c_driver = &s5k3l1yx_i2c_driver,
 	.sensor_v4l2_subdev_info = s5k3l1yx_subdev_info,
diff --git a/drivers/media/video/msm/sensors/s5k4e1_v4l2.c b/drivers/media/video/msm/sensors/s5k4e1_v4l2.c
index e90390e..8cdadd8 100644
--- a/drivers/media/video/msm/sensors/s5k4e1_v4l2.c
+++ b/drivers/media/video/msm/sensors/s5k4e1_v4l2.c
@@ -211,19 +211,6 @@
 	},
 };
 
-static struct msm_camera_csi_params s5k4e1_csi_params = {
-	.data_format = CSI_10BIT,
-	.lane_cnt    = 1,
-	.lane_assign = 0xe4,
-	.dpcm_scheme = 0,
-	.settle_cnt  = 24,
-};
-
-static struct msm_camera_csi_params *s5k4e1_csi_params_array[] = {
-	&s5k4e1_csi_params,
-	&s5k4e1_csi_params,
-};
-
 static struct msm_sensor_output_reg_addr_t s5k4e1_reg_addr = {
 	.x_output = 0x034C,
 	.y_output = 0x034E,
@@ -487,7 +474,6 @@
 	.sensor_config = msm_sensor_config,
 	.sensor_power_up = msm_sensor_power_up,
 	.sensor_power_down = msm_sensor_power_down,
-	.sensor_get_csi_params = msm_sensor_get_csi_params,
 };
 
 static struct msm_sensor_reg_t s5k4e1_regs = {
@@ -516,7 +502,6 @@
 	.sensor_id_info = &s5k4e1_id_info,
 	.sensor_exp_gain_info = &s5k4e1_exp_gain_info,
 	.cam_mode = MSM_SENSOR_MODE_INVALID,
-	.csic_params = &s5k4e1_csi_params_array[0],
 	.msm_sensor_mutex = &s5k4e1_mut,
 	.sensor_i2c_driver = &s5k4e1_i2c_driver,
 	.sensor_v4l2_subdev_info = s5k4e1_subdev_info,
diff --git a/drivers/media/video/msm/sensors/vx6953.c b/drivers/media/video/msm/sensors/vx6953.c
index b43782c..ddc6cee 100644
--- a/drivers/media/video/msm/sensors/vx6953.c
+++ b/drivers/media/video/msm/sensors/vx6953.c
@@ -848,19 +848,6 @@
 	},
 };
 
-static struct msm_camera_csi_params vx6953_csi_params = {
-	.data_format = CSI_8BIT,
-	.lane_cnt    = 1,
-	.lane_assign = 0xe4,
-	.dpcm_scheme = 0,
-	.settle_cnt  = 7,
-};
-
-static struct msm_camera_csi_params *vx6953_csi_params_array[] = {
-	&vx6953_csi_params,
-	&vx6953_csi_params,
-};
-
 static struct msm_sensor_output_reg_addr_t vx6953_reg_addr = {
 	.x_output = 0x034C,
 	.y_output = 0x034E,
@@ -1880,13 +1867,6 @@
 				vx6953_s_ctrl.msm_sensor_reg->
 				default_data_type);
 
-
-			vx6953_s_ctrl.curr_csic_params =
-				vx6953_s_ctrl.csic_params[0];
-			v4l2_subdev_notify(&vx6953_s_ctrl.sensor_v4l2_subdev,
-				NOTIFY_CSIC_CFG,
-				vx6953_s_ctrl.curr_csic_params);
-
 			msleep(vx6953_stm5m0edof_delay_msecs_stdby);
 			if (rt == RES_PREVIEW) {
 				CDBG("%s write mode_tbl for preview\n",
@@ -2042,7 +2022,6 @@
 	.sensor_id_info = &vx6953_id_info,
 	.sensor_exp_gain_info = &vx6953_exp_gain_info,
 	.cam_mode = MSM_SENSOR_MODE_INVALID,
-	.csic_params = &vx6953_csi_params_array[0],
 	.msm_sensor_mutex = &vx6953_mut,
 	.sensor_i2c_driver = &vx6953_i2c_driver,
 	.sensor_v4l2_subdev_info = vx6953_subdev_info,
diff --git a/drivers/media/video/msm/server/msm_cam_server.c b/drivers/media/video/msm/server/msm_cam_server.c
index 7d58091..bb9a9b7 100644
--- a/drivers/media/video/msm/server/msm_cam_server.c
+++ b/drivers/media/video/msm/server/msm_cam_server.c
@@ -11,6 +11,7 @@
  *
  */
 
+#include <linux/of.h>
 #include "msm_cam_server.h"
 #include "msm_csid.h"
 #include "msm_csic.h"
@@ -108,13 +109,20 @@
 	v4l2_fh_exit(eventHandle);
 }
 
-int msm_cam_server_config_interface_map(u32 extendedmode, uint32_t mctl_handle)
+int msm_cam_server_config_interface_map(u32 extendedmode,
+	uint32_t mctl_handle, int vnode_id, int is_bayer_sensor)
 {
 	int i = 0;
 	int rc = 0;
 	int old_handle;
 	int interface;
 
+	if (vnode_id >= MAX_NUM_ACTIVE_CAMERA) {
+		pr_err("%s: invalid msm_dev node id = %d", __func__, vnode_id);
+		return -EINVAL;
+	}
+	D("%s: extendedmode = %d, vnode_id = %d, is_bayer_sensor = %d",
+		__func__, extendedmode, vnode_id, is_bayer_sensor);
 	switch (extendedmode) {
 	case MSM_V4L2_EXT_CAPTURE_MODE_RDI:
 		interface = RDI_0;
@@ -129,18 +137,50 @@
 		interface = PIX_0;
 		break;
 	}
+
 	for (i = 0; i < INTF_MAX; i++) {
 		if (g_server_dev.interface_map_table[i].interface ==
 							interface) {
+			if (is_bayer_sensor && interface == PIX_0) {
+				if (g_server_dev.
+					interface_map_table[i].mctl_handle &&
+					!g_server_dev.interface_map_table[i].
+						is_bayer_sensor) {
+					/* in simultaneous camera usecase
+					 * SoC does not use PIX interface */
+					g_server_dev.interface_map_table[i].
+						mctl_handle = 0;
+				}
+			}
 			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;
+				g_server_dev.interface_map_table[i].
+					is_bayer_sensor = is_bayer_sensor;
+				g_server_dev.interface_map_table[i].vnode_id
+					= vnode_id;
+			} else {
+				if (!g_server_dev.interface_map_table[i].
+					is_bayer_sensor &&
+					(extendedmode ==
+					MSM_V4L2_EXT_CAPTURE_MODE_PREVIEW ||
+					extendedmode ==
+					MSM_V4L2_EXT_CAPTURE_MODE_VIDEO ||
+					extendedmode ==
+					MSM_V4L2_EXT_CAPTURE_MODE_MAIN ||
+					extendedmode ==
+					MSM_V4L2_EXT_CAPTURE_MODE_THUMBNAIL)) {
+					D("%s: SoC sensor, image_mode = %d",
+					__func__, extendedmode);
+					break;
+				}
+				if (old_handle != mctl_handle) {
+					pr_err("%s: iface_map[%d] is set: %d\n",
+						__func__, i, old_handle);
+					rc = -EINVAL;
+				}
 			}
 			break;
 		}
@@ -155,9 +195,20 @@
 {
 	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;
+		if (g_server_dev.interface_map_table[i].
+			mctl_handle == mctl_handle)
+			g_server_dev.interface_map_table[i].
+				mctl_handle = 0;
+}
+
+struct iommu_domain *msm_cam_server_get_domain()
+{
+	return g_server_dev.domain;
+}
+
+int msm_cam_server_get_domain_num()
+{
+	return g_server_dev.domain_num;
 }
 
 uint32_t msm_cam_server_get_mctl_handle(void)
@@ -170,7 +221,7 @@
 			g_server_dev.mctl[i].handle =
 				(++g_server_dev.mctl_handle_cnt) << 8 | i;
 			memset(&g_server_dev.mctl[i].mctl,
-				   0, sizeof(g_server_dev.mctl[i].mctl));
+				0, sizeof(g_server_dev.mctl[i].mctl));
 			return g_server_dev.mctl[i].handle;
 		}
 	}
@@ -234,7 +285,7 @@
 	if (copy_from_user(command, (void __user *)ioctl_ptr->ioctl_ptr,
 					   sizeof(struct msm_ctrl_cmd))) {
 		pr_err("%s: copy_from_user failed, size=%d\n",
-			   __func__, sizeof(struct msm_ctrl_cmd));
+			__func__, sizeof(struct msm_ctrl_cmd));
 		goto ctrl_cmd_done_error;
 	}
 
@@ -288,9 +339,10 @@
 
 /* send control command to config and wait for results*/
 static int msm_server_control(struct msm_cam_server_dev *server_dev,
-				struct msm_ctrl_cmd *out)
+				uint32_t id, struct msm_ctrl_cmd *out)
 {
 	int rc = 0;
+	uint8_t wait_count;
 	void *value;
 	struct msm_queue_cmd *rcmd;
 	struct msm_queue_cmd *event_qcmd;
@@ -326,7 +378,7 @@
 	server_dev->server_queue[out->queue_idx].evt_id =
 		server_dev->server_evt_id;
 	v4l2_evt.type = V4L2_EVENT_PRIVATE_START + MSM_CAM_RESP_V4L2;
-	v4l2_evt.id = 0;

+	v4l2_evt.id = id;
 	v4l2_evt.u.data[0] = out->queue_idx;
 	/* setup event object to transfer the command; */
 	isp_event->resptype = MSM_CAM_RESP_V4L2;
@@ -358,9 +410,20 @@
 
 	/* wait for config return status */
 	D("Waiting for config status\n");
-	rc = wait_event_interruptible_timeout(queue->wait,
-		!list_empty_careful(&queue->list),
-		msecs_to_jiffies(out->timeout_ms));
+	/* wait event may be interrupted by sugnal,
+	 * in this case -ERESTARTSYS is returned and retry is needed.
+	 * Now we only retry once. */
+	wait_count = 2;
+	do {
+		rc = wait_event_interruptible_timeout(queue->wait,
+			!list_empty_careful(&queue->list),
+			msecs_to_jiffies(out->timeout_ms));
+		wait_count--;
+		if (rc != -ERESTARTSYS)
+			break;
+		D("%s: wait_event interrupted by signal, remain_count = %d",
+			__func__, wait_count);
+	} while (wait_count > 0);
 	D("Waiting is over for config status\n");
 	if (list_empty_careful(&queue->list)) {
 		if (!rc)
@@ -409,6 +472,49 @@
 	return rc;
 }
 
+int msm_server_private_general(struct msm_cam_v4l2_device *pcam,
+		struct msm_camera_v4l2_ioctl_t *ioctl_ptr)
+{
+	struct msm_ctrl_cmd ctrlcmd;
+	void *temp_data;
+	int rc;
+	temp_data = kzalloc(ioctl_ptr->len, GFP_KERNEL);
+	if (!temp_data) {
+		pr_err("%s could not allocate memory\n", __func__);
+		rc = -ENOMEM;
+		goto end;
+	}
+	if (copy_from_user((void *)temp_data,
+		(void __user *)ioctl_ptr->ioctl_ptr,
+		ioctl_ptr->len)) {
+		ERR_COPY_FROM_USER();
+		rc = -EFAULT;
+		goto copy_from_user_failed;
+	}
+
+	mutex_lock(&pcam->vid_lock);
+	ctrlcmd.type = MSM_V4L2_PRIVATE_CMD;
+	ctrlcmd.length = ioctl_ptr->len;
+	ctrlcmd.value = temp_data;
+	ctrlcmd.timeout_ms = 1000;
+	ctrlcmd.status = ioctl_ptr->id;
+	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];
+	/* send command to config thread in usersspace, and get return value */
+	rc = msm_server_control(&g_server_dev, 0, &ctrlcmd);
+	if (rc < 0)
+		pr_err("%s: send event failed\n", __func__);
+	mutex_unlock(&pcam->vid_lock);
+
+	kfree(temp_data);
+	return rc;
+copy_from_user_failed:
+	kfree(temp_data);
+end:
+return rc;
+}
+
 int msm_server_get_crop(struct msm_cam_v4l2_device *pcam,
 				int idx, struct v4l2_crop *crop)
 {
@@ -428,7 +534,7 @@
 						pcam->server_queue_idx];
 
 	/* send command to config thread in userspace, and get return value */
-	rc = msm_server_control(&g_server_dev, &ctrlcmd);
+	rc = msm_server_control(&g_server_dev, 0, &ctrlcmd);
 	D("%s: rc = %d\n", __func__, rc);
 
 	return rc;
@@ -452,7 +558,7 @@
 	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);
+	rc = msm_server_control(&g_server_dev, 0, &ctrlcmd);
 
 	return rc;
 }
@@ -474,7 +580,7 @@
 						pcam->server_queue_idx];
 
 	/* send command to config thread in usersspace, and get return value */
-	rc = msm_server_control(&g_server_dev, &ctrlcmd);
+	rc = msm_server_control(&g_server_dev, 0, &ctrlcmd);
 
 	return rc;
 }
@@ -520,7 +626,7 @@
 	ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
 
 	/* send command to config thread in usersspace, and get return value */
-	rc = msm_server_control(&g_server_dev, &ctrlcmd);
+	rc = msm_server_control(&g_server_dev, 0, &ctrlcmd);
 
 	if (rc >= 0) {
 		pcam->dev_inst[idx]->vid_fmt = *pfmt;
@@ -586,7 +692,7 @@
 	ctrlcmd.queue_idx = pcam->server_queue_idx;
 
 	/* send command to config thread in usersspace, and get return value */
-	rc = msm_server_control(&g_server_dev, &ctrlcmd);
+	rc = msm_server_control(&g_server_dev, 0, &ctrlcmd);
 	if (rc >= 0) {
 		pcam->dev_inst[idx]->vid_fmt = *pfmt;
 		pcam->dev_inst[idx]->sensor_pxlcode
@@ -617,7 +723,7 @@
 
 
 	/* send command to config thread in usersspace, and get return value */
-	rc = msm_server_control(&g_server_dev, &ctrlcmd);
+	rc = msm_server_control(&g_server_dev, 0, &ctrlcmd);
 
 	return rc;
 }
@@ -638,7 +744,7 @@
 	ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
 
 	/* send command to config thread in usersspace, and get return value */
-	rc = msm_server_control(&g_server_dev, &ctrlcmd);
+	rc = msm_server_control(&g_server_dev, 0, &ctrlcmd);
 
 	return rc;
 }
@@ -696,7 +802,7 @@
 	ctrlcmd.queue_idx = pcam->server_queue_idx;
 	ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
 	/* send command to config thread in usersspace, and get return value */
-	rc = msm_server_control(&g_server_dev, &ctrlcmd);
+	rc = msm_server_control(&g_server_dev, 0, &ctrlcmd);
 	D("%s: msm_server_control rc=%d\n", __func__, rc);
 	if (rc == 0) {
 		if (tmp_cmd.value && tmp_cmd.length > 0 &&
@@ -750,7 +856,7 @@
 	ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
 
 	/* send command to config thread in usersspace, and get return value */
-	rc = msm_server_control(&g_server_dev, &ctrlcmd);
+	rc = msm_server_control(&g_server_dev, 0, &ctrlcmd);
 
 	return rc;
 }
@@ -780,7 +886,7 @@
 	ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
 
 	/* send command to config thread in usersspace, and get return value */
-	rc = msm_server_control(&g_server_dev, &ctrlcmd);
+	rc = msm_server_control(&g_server_dev, 0, &ctrlcmd);
 
 	ctrl->value = ((struct v4l2_control *)ctrlcmd.value)->value;
 
@@ -807,7 +913,7 @@
 	ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
 
 	/* send command to config thread in userspace, and get return value */
-	rc = msm_server_control(&g_server_dev, &ctrlcmd);
+	rc = msm_server_control(&g_server_dev, 0, &ctrlcmd);
 	D("%s: rc = %d\n", __func__, rc);
 
 	if (rc >= 0)
@@ -974,6 +1080,7 @@
 	}
 	/* book keeping this camera session*/
 	ps->pcam_active[pcam->server_queue_idx] = pcam;
+	ps->opened_pcam[pcam->vnode_id] = pcam;
 	atomic_inc(&ps->number_pcam_active);
 
 	D("config pcam = 0x%p\n", pcam);
@@ -999,7 +1106,7 @@
 
 	atomic_dec(&ps->number_pcam_active);
 	ps->pcam_active[pcam->server_queue_idx] = NULL;
-
+	ps->opened_pcam[pcam->vnode_id] = NULL;
 	for (i = 0; i < INTF_MAX; i++) {
 		if (ps->interface_map_table[i].mctl_handle ==
 			pcam->mctl_handle)
@@ -1013,7 +1120,7 @@
 {
 	int rc = 0;
 	rc = msm_iommu_map_contig_buffer(
-		(unsigned long)IMEM_Y_PING_OFFSET, CAMERA_DOMAIN, GEN_POOL,
+		(unsigned long)IMEM_Y_PING_OFFSET, mctl->domain_num, 0,
 		((IMEM_Y_SIZE + IMEM_CBCR_SIZE + 4095) & (~4095)),
 		SZ_4K, IOMMU_WRITE | IOMMU_READ,
 		(unsigned long *)&mctl->ping_imem_y);
@@ -1025,7 +1132,7 @@
 		mctl->ping_imem_cbcr = 0;
 	}
 	msm_iommu_map_contig_buffer(
-		(unsigned long)IMEM_Y_PONG_OFFSET, CAMERA_DOMAIN, GEN_POOL,
+		(unsigned long)IMEM_Y_PONG_OFFSET, mctl->domain_num, 0,
 		((IMEM_Y_SIZE + IMEM_CBCR_SIZE + 4095) & (~4095)),
 		SZ_4K, IOMMU_WRITE | IOMMU_READ,
 		(unsigned long *)&mctl->pong_imem_y);
@@ -1042,10 +1149,10 @@
 static void unmap_imem_addresses(struct msm_cam_media_controller *mctl)
 {
 	msm_iommu_unmap_contig_buffer(mctl->ping_imem_y,
-		CAMERA_DOMAIN, GEN_POOL,
+		mctl->domain_num, 0,
 		((IMEM_Y_SIZE + IMEM_CBCR_SIZE + 4095) & (~4095)));
 	msm_iommu_unmap_contig_buffer(mctl->pong_imem_y,
-		CAMERA_DOMAIN, GEN_POOL,
+		mctl->domain_num, 0,
 		((IMEM_Y_SIZE + IMEM_CBCR_SIZE + 4095) & (~4095)));
 	mctl->ping_imem_y = 0;
 	mctl->ping_imem_cbcr = 0;
@@ -1428,6 +1535,10 @@
 		pr_err("%s: invalid mctl controller", __func__);
 		goto error;
 	}
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+		pmctl->domain = msm_cam_server_get_domain();
+		pmctl->domain_num = msm_cam_server_get_domain_num();
+#endif
 	rc = map_imem_addresses(pmctl);
 	if (rc < 0) {
 		pr_err("%sFailed to map imem addresses %d\n", __func__, rc);
@@ -1504,7 +1615,6 @@
 {
 	int i;
 	uint32_t interface;
-
 	switch (notification) {
 	case NOTIFY_ISP_MSG_EVT:
 		if (((struct isp_msg_event *)arg)->msg_id ==
@@ -1529,25 +1639,42 @@
 	case NOTIFY_VFE_BUF_EVT: {
 		struct msm_vfe_resp *rp;
 		struct msm_frame_info *frame_info;
+		uint8_t vnode_id;
+
 		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;
+		if (frame_info->inst_handle) {
+			vnode_id = GET_DEVID_MODE(frame_info->inst_handle);
+			if (vnode_id < MAX_NUM_ACTIVE_CAMERA &&
+				g_server_dev.opened_pcam[vnode_id]) {
+				return g_server_dev.
+					opened_pcam[vnode_id]->mctl_handle;
+			} else {
+				pr_err("%s: cannot find mctl handle", __func__);
+				return 0;
+			}
+		} else {
+			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_AXI_RDI_SOF_COUNT: {
+		struct rdi_count_msg *msg = (struct rdi_count_msg *)arg;
+		interface = msg->rdi_interface;
 		}
 		break;
 	case NOTIFY_VFE_MSG_STATS:
 	case NOTIFY_VFE_MSG_COMP_STATS:
 	case NOTIFY_VFE_CAMIF_ERROR:
-	case NOTIFY_VFE_IRQ:
 	default:
 		interface = PIX_0;
 		break;
 	}
-
 	for (i = 0; i < INTF_MAX; i++) {
 		if (interface == g_server_dev.interface_map_table[i].interface)
 			break;
@@ -1579,55 +1706,43 @@
 	switch (notification) {
 	case NOTIFY_ISP_MSG_EVT:
 	case NOTIFY_VFE_MSG_OUT:
-	case NOTIFY_VFE_SOF_COUNT:
+	case NOTIFY_VFE_PIX_SOF_COUNT:
 	case NOTIFY_VFE_MSG_STATS:
 	case NOTIFY_VFE_MSG_COMP_STATS:
 	case NOTIFY_VFE_BUF_EVT:
 		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 = p_mctl->isp_sdev->isp_notify(
-				p_mctl->isp_sdev->sd, notification, arg);
+		if (p_mctl->isp_notify && p_mctl->vfe_sdev)
+			rc = p_mctl->isp_notify(p_mctl,
+				p_mctl->vfe_sdev, notification, arg);
 		break;
 	case NOTIFY_VFE_IRQ:{
 		struct msm_vfe_cfg_cmd cfg_cmd;
 		struct msm_camvfe_params vfe_params;
-		p_mctl = msm_cam_server_get_mctl(mctl_handle);
 		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(sd, core, ioctl, VIDIOC_MSM_AXI_IRQ, arg);
 		break;
+	case NOTIFY_AXI_RDI_SOF_COUNT:
+		p_mctl = msm_cam_server_get_mctl(mctl_handle);
+		if (p_mctl->axi_sdev)
+			rc = v4l2_subdev_call(p_mctl->axi_sdev, core, ioctl,
+				VIDIOC_MSM_AXI_RDI_COUNT_UPDATE, 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);
 		else
-			rc = v4l2_subdev_call(p_mctl->isp_sdev->sd, video,
+			rc = v4l2_subdev_call(p_mctl->vfe_sdev, video,
 			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;
 	case NOTIFY_GESTURE_EVT:
 		rc = v4l2_subdev_call(g_server_dev.gesture_device,
 			core, ioctl, VIDIOC_MSM_GESTURE_EVT, arg);
@@ -2114,7 +2229,6 @@
 		}
 		cam_hw_idx = MSM_CAM_HW_VFE0 + index;
 		g_server_dev.vfe_device[index] = sd;
-		g_server_dev.isp_subdev[index]->sd = sd;
 		if (g_server_dev.irqr_device) {
 			g_server_dev.subdev_table[cam_hw_idx] = sd;
 			err = msm_cam_server_fill_sdev_irqnum(cam_hw_idx,
@@ -2132,7 +2246,7 @@
 		break;
 
 	case AXI_DEV:
-		if (index >= MAX_NUM_VPE_DEV) {
+		if (index >= MAX_NUM_AXI_DEV) {
 			pr_err("%s Invalid AXI idx %d", __func__, index);
 			err = -EINVAL;
 			break;
@@ -2181,6 +2295,23 @@
 	return err;
 }
 
+#ifdef CONFIG_MSM_IOMMU
+static int camera_register_domain(void)
+{
+	struct msm_iova_partition camera_fw_partition = {
+		.start = SZ_128K,
+		.size = SZ_2G - SZ_128K,
+	};
+	struct msm_iova_layout camera_fw_layout = {
+		.partitions = &camera_fw_partition,
+		.npartitions = 1,
+		.client_name = "camera_isp",
+		.domain_flags = 0,
+	};
+
+	return msm_register_domain(&camera_fw_layout);
+}
+#endif
 
 static int msm_setup_server_dev(struct platform_device *pdev)
 {
@@ -2257,6 +2388,21 @@
 		g_server_dev.interface_map_table[i].interface = 0x01 << i;
 		g_server_dev.interface_map_table[i].mctl_handle = 0;
 	}
+#ifdef CONFIG_MSM_IOMMU
+	g_server_dev.domain_num = camera_register_domain();
+	if (g_server_dev.domain_num < 0) {
+		pr_err("%s: could not register domain\n", __func__);
+		rc = -ENODEV;
+		return rc;
+	}
+	g_server_dev.domain =
+		msm_get_iommu_domain(g_server_dev.domain_num);
+	if (!g_server_dev.domain) {
+		pr_err("%s: cannot find domain\n", __func__);
+		rc = -ENODEV;
+		return rc;
+	}
+#endif
 	return rc;
 }
 
@@ -2314,6 +2460,11 @@
 		return rc;
 	}
 
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+		pmctl->domain = msm_cam_server_get_domain();
+		pmctl->domain_num = msm_cam_server_get_domain_num();
+#endif
+
 	D("%s: call mctl_open\n", __func__);
 	rc = pmctl->mctl_open(pmctl, MSM_APPS_ID_V4L2);
 
@@ -2586,6 +2737,7 @@
 		pr_err("%s: cannot find mctl\n", __func__);
 		return -ENODEV;
 	}
+
 	INIT_HLIST_HEAD(&config_cam->p_mctl->stats_info.pmem_stats_list);
 	spin_lock_init(&config_cam->p_mctl->stats_info.pmem_stats_spinlock);
 
@@ -2597,21 +2749,10 @@
 	return rc;
 }
 
-static struct msm_isp_ops *find_isp_op(struct v4l2_subdev *sdev)
-{
-	int i;
-	for (i = 0; i < g_server_dev.config_info.num_config_nodes; i++) {
-		if (g_server_dev.isp_subdev[i]->sd == sdev)
-			return g_server_dev.isp_subdev[i];
-	}
-	return NULL;
-}
-
 static int msm_set_mctl_subdev(struct msm_cam_media_controller *pmctl,
 	struct msm_mctl_set_sdev_data *set_data)
 {
 	int rc = 0;
-	struct v4l2_subdev *vfe_sdev = NULL;
 	struct v4l2_subdev *temp_sdev = NULL;
 	switch (set_data->sdev_type) {
 	case CSIPHY_DEV:
@@ -2635,11 +2776,9 @@
 		temp_sdev = pmctl->ispif_sdev;
 		break;
 	case VFE_DEV:
-		vfe_sdev = msm_cam_find_subdev_node
+		pmctl->vfe_sdev = msm_cam_find_subdev_node
 			(&g_server_dev.vfe_device[0], set_data->revision);
-		temp_sdev = vfe_sdev;
-		pmctl->isp_sdev = find_isp_op(vfe_sdev);
-		pmctl->isp_sdev->sd = vfe_sdev;
+		temp_sdev = pmctl->vfe_sdev;
 		break;
 	case AXI_DEV:
 		pmctl->axi_sdev = msm_cam_find_subdev_node
@@ -2680,7 +2819,7 @@
 		pmctl->ispif_sdev = NULL;
 		break;
 	case VFE_DEV:
-		pmctl->isp_sdev = NULL;
+		pmctl->vfe_sdev = NULL;
 		break;
 	case AXI_DEV:
 		pmctl->axi_sdev = NULL;
@@ -2712,13 +2851,15 @@
 	case MSM_CAM_IOCTL_REGISTER_PMEM:
 		return msm_register_pmem(
 			&config_cam->p_mctl->stats_info.pmem_stats_list,
-			(void __user *)arg, config_cam->p_mctl->client);
+			(void __user *)arg, config_cam->p_mctl->client,
+			config_cam->p_mctl->domain_num);
 		break;
 
 	case MSM_CAM_IOCTL_UNREGISTER_PMEM:
 		return msm_pmem_table_del(
 			&config_cam->p_mctl->stats_info.pmem_stats_list,
-			(void __user *)arg, config_cam->p_mctl->client);
+			(void __user *)arg, config_cam->p_mctl->client,
+			config_cam->p_mctl->domain_num);
 		break;
 
 	case VIDIOC_SUBSCRIBE_EVENT:
@@ -3003,12 +3144,6 @@
 	  put logic here later to know how many configs to create*/
 	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) {
-		pr_err("Failed to initialize isp\n");
-		return rc;
-	}
-
 	if (!msm_class) {
 		rc = alloc_chrdev_region(&msm_devno, 0,
 		g_server_dev.config_info.num_config_nodes+1, "msm_camera");
@@ -3044,22 +3179,27 @@
 		}
 	}
 
-	msm_isp_register(&g_server_dev);
 	return rc;
 }
 
 static int __exit msm_camera_exit(struct platform_device *pdev)
 {
-	msm_isp_unregister(&g_server_dev);
 	return 0;
 }
 
+static const struct of_device_id msm_cam_server_dt_match[] = {
+	{.compatible = "qcom,cam_server"},
+}
+
+MODULE_DEVICE_TABLE(of, msm_cam_server_dt_match);
+
 static struct platform_driver msm_cam_server_driver = {
 	.probe = msm_camera_probe,
 	.remove = msm_camera_exit,
 	.driver = {
 		.name = "msm_cam_server",
 		.owner = THIS_MODULE,
+		.of_match_table = msm_cam_server_dt_match,
 	},
 };
 
diff --git a/drivers/media/video/msm/server/msm_cam_server.h b/drivers/media/video/msm/server/msm_cam_server.h
index 229e9c9..5e39d25 100644
--- a/drivers/media/video/msm/server/msm_cam_server.h
+++ b/drivers/media/video/msm/server/msm_cam_server.h
@@ -20,6 +20,8 @@
 #include "msm.h"
 
 uint32_t msm_cam_server_get_mctl_handle(void);
+struct iommu_domain *msm_cam_server_get_domain(void);
+int msm_cam_server_get_domain_num(void);
 struct msm_cam_media_controller *msm_cam_server_get_mctl(uint32_t handle);
 void msm_cam_server_free_mctl(uint32_t handle);
 /* Server session control APIs */
@@ -37,6 +39,8 @@
 int32_t msm_find_free_queue(void);
 int msm_server_proc_ctrl_cmd(struct msm_cam_v4l2_device *pcam,
 	struct msm_camera_v4l2_ioctl_t *ioctl_ptr, int is_set_cmd);
+int msm_server_private_general(struct msm_cam_v4l2_device *pcam,
+	struct msm_camera_v4l2_ioctl_t *ioctl_ptr);
 int msm_server_s_ctrl(struct msm_cam_v4l2_device *pcam,
 	struct v4l2_control *ctrl);
 int msm_server_g_ctrl(struct msm_cam_v4l2_device *pcam,
@@ -65,5 +69,5 @@
 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);
+	uint32_t mctl_handle, int vnode_id, int is_bayer_sensor);
 #endif /* _MSM_CAM_SERVER_H */
diff --git a/drivers/media/video/msm/vfe/Makefile b/drivers/media/video/msm/vfe/Makefile
index 91f0e7f..250b55f 100644
--- a/drivers/media/video/msm/vfe/Makefile
+++ b/drivers/media/video/msm/vfe/Makefile
@@ -16,5 +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_ARCH_MSM8974) += msm_vfe40.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 0bd7b94..de32f1b 100644
--- a/drivers/media/video/msm/vfe/msm_vfe31_v4l2.c
+++ b/drivers/media/video/msm/vfe/msm_vfe31_v4l2.c
@@ -367,7 +367,7 @@
 	rc = vfe31_ctrl->stats_ops.dqbuf(vfe31_ctrl->stats_ops.stats_ctrl,
 			stats_type, &buf);
 	if (rc < 0) {
-		pr_err("%s: dq stats buf (type = %d) err = %d",
+		CDBG("%s: dq stats buf (type = %d) err = %d",
 			__func__, stats_type, rc);
 		return 0L;
 	}
@@ -401,7 +401,7 @@
 		stats_buf = &bufq->bufs[i];
 		rc = vfe31_ctrl->stats_ops.enqueue_buf(
 				vfe31_ctrl->stats_ops.stats_ctrl,
-				&(stats_buf->info), NULL);
+				&(stats_buf->info), NULL, -1);
 		if (rc < 0) {
 			pr_err("%s: dq stats buf (type = %d) err = %d",
 				__func__, stats_type, rc);
@@ -412,7 +412,7 @@
 }
 
 static unsigned long vfe31_stats_unregbuf(
-	struct msm_stats_reqbuf *req_buf)
+	struct msm_stats_reqbuf *req_buf, int domain_num)
 {
 	int i = 0, rc = 0;
 
@@ -420,7 +420,7 @@
 		rc = vfe31_ctrl->stats_ops.buf_unprepare(
 			vfe31_ctrl->stats_ops.stats_ctrl,
 			req_buf->stats_type, i,
-			vfe31_ctrl->stats_ops.client);
+			vfe31_ctrl->stats_ops.client, domain_num);
 		if (rc < 0) {
 			pr_err("%s: unreg stats buf (type = %d) err = %d",
 				__func__, req_buf->stats_type, rc);
@@ -3296,7 +3296,7 @@
 }
 
 static long vfe_stats_bufq_sub_ioctl(struct msm_vfe_cfg_cmd *cmd,
-	void *ion_client)
+	void *ion_client, int domain_num)
 {
 	long rc = 0;
 	switch (cmd->cmd_type) {
@@ -3344,7 +3344,7 @@
 		}
 		rc = vfe31_ctrl->stats_ops.enqueue_buf(&vfe31_ctrl->stats_ctrl,
 				(struct msm_stats_buf_info *)cmd->value,
-				vfe31_ctrl->stats_ops.client);
+				vfe31_ctrl->stats_ops.client, domain_num);
 	break;
 	case VFE_CMD_STATS_FLUSH_BUFQ: {
 		struct msm_stats_flush_bufq *flush_req = NULL;
@@ -3376,7 +3376,7 @@
 			rc = -EINVAL ;
 			goto end;
 		}
-		rc = vfe31_stats_unregbuf(req_buf);
+		rc = vfe31_stats_unregbuf(req_buf, domain_num);
 	}
 	break;
 	default:
@@ -3630,7 +3630,8 @@
 	case VFE_CMD_STATS_FLUSH_BUFQ:
 	case VFE_CMD_STATS_UNREGBUF:
 		/* for easy porting put in one envelope */
-		rc = vfe_stats_bufq_sub_ioctl(cmd, vfe_params->data);
+		rc = vfe_stats_bufq_sub_ioctl(cmd, vfe_params->data,
+			pmctl->domain_num);
 		return rc;
 	default:
 		if (cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
@@ -4003,10 +4004,25 @@
 			vfe31_ctrl->vfe_camif_clk,
 			ARRAY_SIZE(vfe_camif_clk_info), 1);
 		if (rc < 0)
-			goto vfe_clk_enable_failed;
+			goto vfe_camif_clk_enable_failed;
 		msm_vfe_camif_pad_reg_reset();
 	}
 
+#ifdef CONFIG_MSM_IOMMU
+	rc = iommu_attach_device(mctl->domain, vfe31_ctrl->iommu_ctx_imgwr);
+	if (rc < 0) {
+		rc = -ENODEV;
+		pr_err("%s: Device attach failed\n", __func__);
+		goto device_imgwr_attach_failed;
+	}
+	rc = iommu_attach_device(mctl->domain, vfe31_ctrl->iommu_ctx_misc);
+	if (rc < 0) {
+		rc = -ENODEV;
+		pr_err("%s: Device attach failed\n", __func__);
+		goto device_misc_attach_failed;
+	}
+#endif
+
 	msm_camio_bus_scale_cfg(
 		mctl->sdata->pdata->cam_bus_scale_table, S_INIT);
 	msm_camio_bus_scale_cfg(
@@ -4017,6 +4033,19 @@
 
 	return rc;
 
+#ifdef CONFIG_MSM_IOMMU
+device_misc_attach_failed:
+	iommu_detach_device(mctl->domain, vfe31_ctrl->iommu_ctx_imgwr);
+device_imgwr_attach_failed:
+#endif
+	if (!mctl->sdata->csi_if)
+		msm_cam_clk_enable(&vfe31_ctrl->pdev->dev,
+			vfe_camif_clk_info,
+			vfe31_ctrl->vfe_camif_clk,
+			ARRAY_SIZE(vfe_camif_clk_info), 0);
+vfe_camif_clk_enable_failed:
+	msm_cam_clk_enable(&vfe31_ctrl->pdev->dev, vfe_clk_info,
+		vfe31_ctrl->vfe_clk, ARRAY_SIZE(vfe_clk_info), 0);
 vfe_clk_enable_failed:
 	regulator_disable(vfe31_ctrl->fs_vfe);
 vfe_fs_failed:
@@ -4025,7 +4054,6 @@
 camif_remap_failed:
 	iounmap(vfe31_ctrl->vfebase);
 vfe_remap_failed:
-	disable_irq(vfe31_ctrl->vfeirq->start);
 mctl_failed:
 	return rc;
 }
@@ -4037,6 +4065,11 @@
 	disable_irq(vfe31_ctrl->vfeirq->start);
 	tasklet_kill(&vfe31_tasklet);
 
+#ifdef CONFIG_MSM_IOMMU
+	iommu_detach_device(pmctl->domain, vfe31_ctrl->iommu_ctx_misc);
+	iommu_detach_device(pmctl->domain, vfe31_ctrl->iommu_ctx_imgwr);
+#endif
+
 	if (!pmctl->sdata->csi_if)
 		msm_cam_clk_enable(&vfe31_ctrl->pdev->dev,
 			vfe_camif_clk_info,
@@ -4140,6 +4173,25 @@
 
 	disable_irq(vfe31_ctrl->vfeirq->start);
 
+#ifdef CONFIG_MSM_IOMMU
+	/*get device context for IOMMU*/
+	vfe31_ctrl->iommu_ctx_imgwr =
+		msm_iommu_get_ctx("vfe_imgwr"); /*re-confirm*/
+	vfe31_ctrl->iommu_ctx_misc =
+		msm_iommu_get_ctx("vfe_misc"); /*re-confirm*/
+	if (!vfe31_ctrl->iommu_ctx_imgwr || !vfe31_ctrl->iommu_ctx_misc) {
+		if (vfe31_ctrl->camifmem) {
+			release_mem_region(vfe31_ctrl->camifmem->start,
+				resource_size(vfe31_ctrl->camifmem));
+		}
+		release_mem_region(vfe31_ctrl->vfemem->start,
+			resource_size(vfe31_ctrl->vfemem));
+		pr_err("%s: No iommu fw context found\n", __func__);
+		rc = -ENODEV;
+		goto vfe31_no_resource;
+	}
+#endif
+
 	vfe31_ctrl->pdev = pdev;
 	vfe31_ctrl->fs_vfe = regulator_get(&vfe31_ctrl->pdev->dev, "vdd");
 	if (IS_ERR(vfe31_ctrl->fs_vfe)) {
diff --git a/drivers/media/video/msm/vfe/msm_vfe31_v4l2.h b/drivers/media/video/msm/vfe/msm_vfe31_v4l2.h
index 60db8e5..97ecd6e 100644
--- a/drivers/media/video/msm/vfe/msm_vfe31_v4l2.h
+++ b/drivers/media/video/msm/vfe/msm_vfe31_v4l2.h
@@ -928,6 +928,8 @@
 	uint32_t snapshot_frame_cnt;
 	struct msm_stats_bufq_ctrl stats_ctrl;
 	struct msm_stats_ops stats_ops;
+	struct device *iommu_ctx_imgwr;
+	struct device *iommu_ctx_misc;
 };
 
 enum VFE31_STATS_NUM {
diff --git a/drivers/media/video/msm/vfe/msm_vfe32.c b/drivers/media/video/msm/vfe/msm_vfe32.c
index 3e01437..6e22388 100644
--- a/drivers/media/video/msm/vfe/msm_vfe32.c
+++ b/drivers/media/video/msm/vfe/msm_vfe32.c
@@ -412,36 +412,259 @@
 	}
 }
 
-static void axi_disable_irq(struct axi_ctrl_t *axi_ctrl)
+static void axi_enable_wm_irq(struct vfe_share_ctrl_t *share_ctrl)
+{
+	uint32_t irq_mask, irq_comp_mask = 0;
+	uint16_t vfe_output_mode =
+		share_ctrl->outpath.output_mode &
+			~(VFE32_OUTPUT_MODE_TERTIARY1|
+			VFE32_OUTPUT_MODE_TERTIARY2);
+
+	if (vfe_output_mode)
+		irq_comp_mask =
+		msm_camera_io_r(share_ctrl->vfebase +
+			VFE_IRQ_COMP_MASK);
+	irq_mask = msm_camera_io_r(share_ctrl->vfebase +
+				VFE_IRQ_MASK_0);
+
+	if (share_ctrl->outpath.output_mode &
+			VFE32_OUTPUT_MODE_PRIMARY) {
+		if (share_ctrl->current_mode == VFE_OUTPUTS_RAW)
+			irq_comp_mask |= (
+				0x1 << share_ctrl->outpath.out0.ch0);
+		else
+			irq_comp_mask |= (
+				0x1 << share_ctrl->outpath.out0.ch0 |
+				0x1 << share_ctrl->outpath.out0.ch1);
+		irq_mask |= VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK;
+	} else if (share_ctrl->outpath.output_mode &
+			   VFE32_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
+		irq_comp_mask |= (
+			0x1 << share_ctrl->outpath.out0.ch0 |
+			0x1 << share_ctrl->outpath.out0.ch1 |
+			0x1 << share_ctrl->outpath.out0.ch2);
+		irq_mask |= VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK;
+	}
+	if (share_ctrl->outpath.output_mode &
+			VFE32_OUTPUT_MODE_SECONDARY) {
+		irq_comp_mask |= (
+			0x1 << (share_ctrl->outpath.out1.ch0 + 8) |
+			0x1 << (share_ctrl->outpath.out1.ch1 + 8));
+		irq_mask |= VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE1_MASK;
+	} else if (share_ctrl->outpath.output_mode &
+			VFE32_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
+		irq_comp_mask |= (
+			0x1 << (share_ctrl->outpath.out1.ch0 + 8) |
+			0x1 << (share_ctrl->outpath.out1.ch1 + 8) |
+			0x1 << (share_ctrl->outpath.out1.ch2 + 8));
+		irq_mask |= VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE1_MASK;
+	}
+
+	if (share_ctrl->outpath.output_mode &
+		VFE32_OUTPUT_MODE_TERTIARY1) {
+		irq_mask |= (0x1 << (share_ctrl->outpath.out2.ch0 +
+			VFE_WM_OFFSET));
+	}
+
+	if (share_ctrl->outpath.output_mode &
+		VFE32_OUTPUT_MODE_TERTIARY2) {
+		irq_mask |= (0x1 << (share_ctrl->outpath.out3.ch0 +
+			VFE_WM_OFFSET));
+	}
+
+	msm_camera_io_w(irq_mask, share_ctrl->vfebase +
+			VFE_IRQ_MASK_0);
+	if (vfe_output_mode)
+		msm_camera_io_w(irq_comp_mask,
+			share_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+}
+
+static void axi_disable_wm_irq(struct vfe_share_ctrl_t *share_ctrl,
+	uint16_t output_mode)
+{
+	uint32_t irq_mask, irq_comp_mask = 0;
+	uint16_t vfe_output_mode =
+		output_mode &
+			~(VFE32_OUTPUT_MODE_TERTIARY1|
+			VFE32_OUTPUT_MODE_TERTIARY2);
+	if (vfe_output_mode)
+		irq_comp_mask =
+		msm_camera_io_r(share_ctrl->vfebase +
+			VFE_IRQ_COMP_MASK);
+	irq_mask = msm_camera_io_r(share_ctrl->vfebase +
+				VFE_IRQ_MASK_0);
+
+	if (output_mode &
+			VFE32_OUTPUT_MODE_PRIMARY) {
+		irq_comp_mask &= ~(
+			0x1 << share_ctrl->outpath.out0.ch0 |
+			0x1 << share_ctrl->outpath.out0.ch1);
+		irq_mask &= ~VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK;
+	} else if (output_mode &
+			   VFE32_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
+		irq_comp_mask &= ~(
+			0x1 << share_ctrl->outpath.out0.ch0 |
+			0x1 << share_ctrl->outpath.out0.ch1 |
+			0x1 << share_ctrl->outpath.out0.ch2);
+		irq_mask &= ~VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK;
+	}
+	if (output_mode &
+			VFE32_OUTPUT_MODE_SECONDARY) {
+		irq_comp_mask &= ~(
+			0x1 << (share_ctrl->outpath.out1.ch0 + 8) |
+			0x1 << (share_ctrl->outpath.out1.ch1 + 8));
+		irq_mask &= ~VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE1_MASK;
+	} else if (output_mode &
+			VFE32_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
+		irq_comp_mask &= ~(
+			0x1 << (share_ctrl->outpath.out1.ch0 + 8) |
+			0x1 << (share_ctrl->outpath.out1.ch1 + 8) |
+			0x1 << (share_ctrl->outpath.out1.ch2 + 8));
+		irq_mask &= ~VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE1_MASK;
+	}
+	if (output_mode &
+			VFE32_OUTPUT_MODE_TERTIARY1) {
+			irq_mask &= ~(0x1 << (share_ctrl->outpath.out2.ch0 +
+				VFE_WM_OFFSET));
+	}
+	if (output_mode &
+		VFE32_OUTPUT_MODE_TERTIARY2) {
+		irq_mask &= ~(0x1 << (share_ctrl->outpath.out3.ch0 +
+			VFE_WM_OFFSET));
+	}
+	msm_camera_io_w(irq_mask, share_ctrl->vfebase +
+				VFE_IRQ_MASK_0);
+	if (vfe_output_mode)
+		msm_camera_io_w(irq_comp_mask,
+			share_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+}
+
+static void axi_enable_irq(struct vfe_share_ctrl_t *share_ctrl)
+{
+	uint32_t irq_mask, irq_mask1;
+	uint32_t vfe_mode =
+		share_ctrl->current_mode & ~(VFE_OUTPUTS_RDI0|
+			VFE_OUTPUTS_RDI1);
+
+	if (share_ctrl->axi_ref_cnt == 1) {
+		irq_mask1 =
+			msm_camera_io_r(share_ctrl->vfebase +
+				VFE_IRQ_MASK_1);
+
+		irq_mask1 |= VFE_IMASK_WHILE_STOPPING_1;
+			msm_camera_io_w(irq_mask1, share_ctrl->vfebase +
+				VFE_IRQ_MASK_1);
+	}
+
+	if (share_ctrl->current_mode & (VFE_OUTPUTS_RDI0|VFE_OUTPUTS_RDI1)) {
+		irq_mask1 =
+			msm_camera_io_r(share_ctrl->vfebase +
+				VFE_IRQ_MASK_1);
+
+		if (share_ctrl->current_mode & VFE_OUTPUTS_RDI0)
+			irq_mask1 |= VFE_IRQ_STATUS1_RDI0_REG_UPDATE_MASK;
+
+		if (share_ctrl->current_mode & VFE_OUTPUTS_RDI1)
+			irq_mask1 |= VFE_IRQ_STATUS1_RDI1_REG_UPDATE_MASK;
+
+		msm_camera_io_w(irq_mask1, share_ctrl->vfebase +
+			VFE_IRQ_MASK_1);
+	}
+
+	if (vfe_mode) {
+		irq_mask =
+		msm_camera_io_r(share_ctrl->vfebase +
+			VFE_IRQ_MASK_0);
+		irq_mask |= 0x00000021;
+		if (share_ctrl->stats_comp)
+			irq_mask |= VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK;
+		else
+			irq_mask |= 0x000FE000;
+		msm_camera_io_w(irq_mask, share_ctrl->vfebase +
+			VFE_IRQ_MASK_0);
+		atomic_set(&share_ctrl->vstate, 1);
+	}
+	atomic_set(&share_ctrl->handle_common_irq, 1);
+}
+
+static void axi_disable_irq(struct vfe_share_ctrl_t *share_ctrl,
+	uint32_t mode)
 {
 
 	/* disable all interrupts.  */
-	msm_camera_io_w(VFE_DISABLE_ALL_IRQS,
-		axi_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_0);
-	msm_camera_io_w(VFE_DISABLE_ALL_IRQS,
-		axi_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
 
-	/* clear all pending interrupts*/
-	msm_camera_io_w(VFE_CLEAR_ALL_IRQS,
-		axi_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_0);
-	msm_camera_io_w(VFE_CLEAR_ALL_IRQS,
-		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);
+	uint32_t irq_mask = 0, irq_mask1 = 0, clear_mask1 = 0;
+	uint32_t vfe_mode =
+		(mode & ~(VFE_OUTPUTS_RDI0|
+			VFE_OUTPUTS_RDI1));
+
+	if (mode & (VFE_OUTPUTS_RDI0|VFE_OUTPUTS_RDI1)) {
+		irq_mask1 =
+			msm_camera_io_r(share_ctrl->vfebase +
+				VFE_IRQ_MASK_1);
+
+		if (mode & VFE_OUTPUTS_RDI0) {
+			irq_mask1 &= ~(VFE_IRQ_STATUS1_RDI0_REG_UPDATE_MASK);
+			clear_mask1 |= VFE_IRQ_STATUS1_RDI0_REG_UPDATE_MASK;
+		}
+
+		if (mode & VFE_OUTPUTS_RDI1) {
+			irq_mask1 &= ~(VFE_IRQ_STATUS1_RDI1_REG_UPDATE_MASK);
+			clear_mask1 |= VFE_IRQ_STATUS1_RDI1_REG_UPDATE_MASK;
+		}
+
+		msm_camera_io_w(irq_mask1, share_ctrl->vfebase +
+			VFE_IRQ_MASK_1);
+		msm_camera_io_w(clear_mask1,
+			share_ctrl->vfebase + VFE_IRQ_CLEAR_1);
+	}
+
+	if (vfe_mode) {
+		atomic_set(&share_ctrl->vstate, 0);
+		irq_mask =
+		msm_camera_io_r(share_ctrl->vfebase +
+			VFE_IRQ_MASK_0);
+		irq_mask &= ~(0x00000021);
+		if (share_ctrl->stats_comp)
+			irq_mask &= ~(VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK);
+		else
+			irq_mask &= ~0x000FE000;
+		msm_camera_io_w(irq_mask, share_ctrl->vfebase +
+			VFE_IRQ_MASK_0);
+	}
+	/*Dont Disable for concurrent*/
+	if (share_ctrl->axi_ref_cnt == 1) {
+		atomic_set(&share_ctrl->handle_common_irq, 0);
+		msm_camera_io_w(VFE_DISABLE_ALL_IRQS,
+			share_ctrl->vfebase + VFE_IRQ_MASK_0);
+		msm_camera_io_w(VFE_DISABLE_ALL_IRQS,
+			share_ctrl->vfebase + VFE_IRQ_MASK_1);
+
+		/* clear all pending interrupts*/
+		msm_camera_io_w(VFE_CLEAR_ALL_IRQS,
+			share_ctrl->vfebase + VFE_IRQ_CLEAR_0);
+		msm_camera_io_w(VFE_CLEAR_ALL_IRQS,
+			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,
+			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_AT_FRAME_BOUNDARY,
-		vfe32_ctrl->share_ctrl->vfebase + VFE_CAMIF_COMMAND);
+	if (!vfe32_ctrl->share_ctrl->dual_enabled)
+		msm_camera_io_w_mb(CAMIF_COMMAND_STOP_IMMEDIATELY,
+			vfe32_ctrl->share_ctrl->vfebase + VFE_CAMIF_COMMAND);
+	else
+		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);
+		(VFE_OUTPUTS_RDI0|VFE_OUTPUTS_RDI1);
 }
 
 static void vfe32_subdev_notify(int id, int path, uint32_t inst_handle,
@@ -550,8 +773,6 @@
 		V32_AXI_BUS_CFG_LEN);
 	axi_cfg += V32_AXI_BUS_CFG_LEN/4;
 	for (i = 0; i < ARRAY_SIZE(vfe32_AXI_WM_CFG); i++) {
-		msm_camera_io_w(*axi_cfg,
-			axi_ctrl->share_ctrl->vfebase+vfe32_AXI_WM_CFG[i]);
 		axi_cfg += 3;
 		msm_camera_io_memcpy(
 			axi_ctrl->share_ctrl->vfebase+vfe32_AXI_WM_CFG[i]+12,
@@ -560,10 +781,47 @@
 	}
 	msm_camera_io_w(bus_cmd, axi_ctrl->share_ctrl->vfebase +
 					V32_AXI_BUS_CMD_OFF);
+	msm_camera_io_w(*ch_info++,
+		axi_ctrl->share_ctrl->vfebase + VFE_PIXEL_IF_CFG);
+	if (msm_camera_io_r(axi_ctrl->share_ctrl->vfebase +
+		V32_GET_HW_VERSION_OFF) ==
+		VFE33_HW_NUMBER) {
+		msm_camera_io_w(*ch_info++,
+			axi_ctrl->share_ctrl->vfebase + VFE_RDI0_CFG);
+		msm_camera_io_w(*ch_info++,
+			axi_ctrl->share_ctrl->vfebase + VFE_RDI1_CFG);
+	}
 	return 0;
 }
 
 static void axi_reset_internal_variables(
+	struct axi_ctrl_t *axi_ctrl,
+	struct msm_camera_vfe_params_t vfe_params)
+{
+	if (vfe_params.operation_mode & VFE_OUTPUTS_RDI0) {
+		atomic_set(&axi_ctrl->share_ctrl->rdi0_update_ack_pending, 0);
+		axi_ctrl->share_ctrl->rdi0_capture_count = -1;
+		axi_ctrl->share_ctrl->outpath.out2.capture_cnt = -1;
+		axi_ctrl->share_ctrl->rdi0FrameId = 0;
+		axi_ctrl->share_ctrl->comp_output_mode &=
+			~VFE32_OUTPUT_MODE_TERTIARY1;
+		axi_ctrl->share_ctrl->operation_mode &=
+			~(VFE_OUTPUTS_RDI0);
+	}
+
+	if (vfe_params.operation_mode & VFE_OUTPUTS_RDI1) {
+		atomic_set(&axi_ctrl->share_ctrl->rdi1_update_ack_pending, 0);
+		axi_ctrl->share_ctrl->rdi1_capture_count = -1;
+		axi_ctrl->share_ctrl->outpath.out3.capture_cnt = -1;
+		axi_ctrl->share_ctrl->rdi1FrameId = 0;
+		axi_ctrl->share_ctrl->comp_output_mode &=
+			~VFE32_OUTPUT_MODE_TERTIARY2;
+		axi_ctrl->share_ctrl->operation_mode &=
+			~(VFE_OUTPUTS_RDI1);
+	}
+}
+
+static void axi_global_reset_internal_variables(
 	struct axi_ctrl_t *axi_ctrl)
 {
 	unsigned long flags;
@@ -585,6 +843,8 @@
 	axi_ctrl->share_ctrl->liveshot_state = VFE_STATE_IDLE;
 
 	atomic_set(&axi_ctrl->share_ctrl->vstate, 0);
+	atomic_set(&axi_ctrl->share_ctrl->handle_common_irq, 0);
+	atomic_set(&axi_ctrl->share_ctrl->pix0_update_ack_pending, 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);
@@ -593,41 +853,22 @@
 	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->comp_output_mode = 0;
 	axi_ctrl->share_ctrl->vfe_capture_count = 0;
+	axi_ctrl->share_ctrl->rdi0_capture_count = -1;
+	axi_ctrl->share_ctrl->rdi1_capture_count = -1;
+	axi_ctrl->share_ctrl->outpath.out0.capture_cnt = -1;
+	axi_ctrl->share_ctrl->outpath.out1.capture_cnt = -1;
+	axi_ctrl->share_ctrl->outpath.out2.capture_cnt = -1;
+	axi_ctrl->share_ctrl->outpath.out3.capture_cnt = -1;
 
 	/* this is unsigned 32 bit integer. */
 	axi_ctrl->share_ctrl->vfeFrameId = 0;
+	axi_ctrl->share_ctrl->rdi0FrameId = 0;
+	axi_ctrl->share_ctrl->rdi1FrameId = 0;
+	axi_ctrl->share_ctrl->rdi2FrameId = 0;
 }
 
-static void vfe32_reset_internal_variables(
-	struct vfe32_ctrl_type *vfe32_ctrl)
-{
-	/* Stats control variables. */
-	memset(&(vfe32_ctrl->afbfStatsControl), 0,
-		sizeof(struct vfe_stats_control));
-
-	memset(&(vfe32_ctrl->awbStatsControl), 0,
-		sizeof(struct vfe_stats_control));
-
-	memset(&(vfe32_ctrl->aecbgStatsControl), 0,
-		sizeof(struct vfe_stats_control));
-
-	memset(&(vfe32_ctrl->bhistStatsControl), 0,
-		sizeof(struct vfe_stats_control));
-
-	memset(&(vfe32_ctrl->ihistStatsControl), 0,
-		sizeof(struct vfe_stats_control));
-
-	memset(&(vfe32_ctrl->rsStatsControl), 0,
-		sizeof(struct vfe_stats_control));
-
-	memset(&(vfe32_ctrl->csStatsControl), 0,
-		sizeof(struct vfe_stats_control));
-
-	vfe32_ctrl->frame_skip_cnt = 31;
-	vfe32_ctrl->frame_skip_pattern = 0xffffffff;
-	vfe32_ctrl->snapshot_frame_cnt = 0;
-}
 
 static void vfe32_program_dmi_cfg(
 	enum VFE32_DMI_RAM_SEL bankSel,
@@ -685,9 +926,179 @@
 	vfe32_program_dmi_cfg(NO_MEM_SELECTED, vfe32_ctrl);
 }
 
-static int axi_reset(struct axi_ctrl_t *axi_ctrl)
+static void vfe32_set_default_reg_values(
+	struct vfe32_ctrl_type *vfe32_ctrl)
 {
-	axi_reset_internal_variables(axi_ctrl);
+	msm_camera_io_w(0x800080,
+		vfe32_ctrl->share_ctrl->vfebase + VFE_DEMUX_GAIN_0);
+	msm_camera_io_w(0x800080,
+		vfe32_ctrl->share_ctrl->vfebase + VFE_DEMUX_GAIN_1);
+	/* What value should we program CGC_OVERRIDE to? */
+	msm_camera_io_w(0xFFFFF,
+		vfe32_ctrl->share_ctrl->vfebase + VFE_CGC_OVERRIDE);
+
+	/* default frame drop period and pattern */
+	msm_camera_io_w(0x1f,
+		vfe32_ctrl->share_ctrl->vfebase + VFE_FRAMEDROP_ENC_Y_CFG);
+	msm_camera_io_w(0x1f,
+		vfe32_ctrl->share_ctrl->vfebase + VFE_FRAMEDROP_ENC_CBCR_CFG);
+	msm_camera_io_w(0xFFFFFFFF,
+		vfe32_ctrl->share_ctrl->vfebase + VFE_FRAMEDROP_ENC_Y_PATTERN);
+	msm_camera_io_w(0xFFFFFFFF,
+		vfe32_ctrl->share_ctrl->vfebase +
+		VFE_FRAMEDROP_ENC_CBCR_PATTERN);
+	msm_camera_io_w(0x1f,
+		vfe32_ctrl->share_ctrl->vfebase + VFE_FRAMEDROP_VIEW_Y);
+	msm_camera_io_w(0x1f,
+		vfe32_ctrl->share_ctrl->vfebase + VFE_FRAMEDROP_VIEW_CBCR);
+	msm_camera_io_w(0xFFFFFFFF,
+		vfe32_ctrl->share_ctrl->vfebase + VFE_FRAMEDROP_VIEW_Y_PATTERN);
+	msm_camera_io_w(0xFFFFFFFF,
+		vfe32_ctrl->share_ctrl->vfebase +
+		VFE_FRAMEDROP_VIEW_CBCR_PATTERN);
+	msm_camera_io_w(0, vfe32_ctrl->share_ctrl->vfebase + VFE_CLAMP_MIN);
+	msm_camera_io_w(0xFFFFFF,
+		vfe32_ctrl->share_ctrl->vfebase + VFE_CLAMP_MAX);
+
+	/* stats UB config */
+	CDBG("%s: Use bayer stats = %d\n", __func__,
+		 vfe32_use_bayer_stats(vfe32_ctrl));
+	if (!vfe32_use_bayer_stats(vfe32_ctrl)) {
+		msm_camera_io_w(0x3980007,
+			vfe32_ctrl->share_ctrl->vfebase +
+				VFE_BUS_STATS_AEC_BG_UB_CFG);
+		msm_camera_io_w(0x3A00007,
+			vfe32_ctrl->share_ctrl->vfebase +
+				VFE_BUS_STATS_AF_BF_UB_CFG);
+		msm_camera_io_w(0x3A8000F,
+			vfe32_ctrl->share_ctrl->vfebase +
+				VFE_BUS_STATS_AWB_UB_CFG);
+		msm_camera_io_w(0x3B80007,
+			vfe32_ctrl->share_ctrl->vfebase +
+				VFE_BUS_STATS_RS_UB_CFG);
+		msm_camera_io_w(0x3C0001F,
+			vfe32_ctrl->share_ctrl->vfebase +
+				VFE_BUS_STATS_CS_UB_CFG);
+		msm_camera_io_w(0x3E0001F,
+			vfe32_ctrl->share_ctrl->vfebase +
+				VFE_BUS_STATS_HIST_UB_CFG);
+	} else {
+		msm_camera_io_w(0x350001F,
+			vfe32_ctrl->share_ctrl->vfebase +
+				VFE_BUS_STATS_HIST_UB_CFG);
+		msm_camera_io_w(0x370002F,
+			vfe32_ctrl->share_ctrl->vfebase +
+				VFE_BUS_STATS_AEC_BG_UB_CFG);
+		msm_camera_io_w(0x3A0002F,
+			vfe32_ctrl->share_ctrl->vfebase +
+				VFE_BUS_STATS_AF_BF_UB_CFG);
+		msm_camera_io_w(0x3D00007,
+			vfe32_ctrl->share_ctrl->vfebase +
+				VFE_BUS_STATS_RS_UB_CFG);
+		msm_camera_io_w(0x3D8001F,
+			vfe32_ctrl->share_ctrl->vfebase +
+				VFE_BUS_STATS_CS_UB_CFG);
+		msm_camera_io_w(0x3F80007,
+			vfe32_ctrl->share_ctrl->vfebase +
+				VFE_BUS_STATS_SKIN_BHIST_UB_CFG);
+	}
+	vfe32_reset_dmi_tables(vfe32_ctrl);
+}
+
+static void vfe32_reset_internal_variables(
+	struct vfe32_ctrl_type *vfe32_ctrl)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&vfe32_ctrl->share_ctrl->update_ack_lock,
+		flags);
+	vfe32_ctrl->share_ctrl->update_ack_pending = FALSE;
+	spin_unlock_irqrestore(&vfe32_ctrl->share_ctrl->update_ack_lock,
+		flags);
+	vfe32_ctrl->share_ctrl->vfe_capture_count = 0;
+	/* this is unsigned 32 bit integer. */
+	vfe32_ctrl->share_ctrl->vfeFrameId = 0;
+	vfe32_ctrl->share_ctrl->update_counter = 0;
+
+	/* Stats control variables. */
+	memset(&(vfe32_ctrl->afbfStatsControl), 0,
+		sizeof(struct vfe_stats_control));
+
+	memset(&(vfe32_ctrl->awbStatsControl), 0,
+		sizeof(struct vfe_stats_control));
+
+	memset(&(vfe32_ctrl->aecbgStatsControl), 0,
+		sizeof(struct vfe_stats_control));
+
+	memset(&(vfe32_ctrl->bhistStatsControl), 0,
+		sizeof(struct vfe_stats_control));
+
+	memset(&(vfe32_ctrl->ihistStatsControl), 0,
+		sizeof(struct vfe_stats_control));
+
+	memset(&(vfe32_ctrl->rsStatsControl), 0,
+		sizeof(struct vfe_stats_control));
+
+	memset(&(vfe32_ctrl->csStatsControl), 0,
+		sizeof(struct vfe_stats_control));
+	vfe32_ctrl->share_ctrl->outpath.out0.capture_cnt = -1;
+	vfe32_ctrl->share_ctrl->outpath.out1.capture_cnt = -1;
+	vfe32_ctrl->share_ctrl->recording_state = VFE_STATE_IDLE;
+	vfe32_ctrl->share_ctrl->liveshot_state = VFE_STATE_IDLE;
+
+	atomic_set(&vfe32_ctrl->share_ctrl->vstate, 0);
+	atomic_set(&vfe32_ctrl->share_ctrl->pix0_update_ack_pending, 0);
+
+	vfe32_ctrl->frame_skip_cnt = 31;
+	vfe32_ctrl->frame_skip_pattern = 0xffffffff;
+	vfe32_ctrl->snapshot_frame_cnt = 0;
+	vfe32_set_default_reg_values(vfe32_ctrl);
+}
+
+
+static int vfe32_reset(struct vfe32_ctrl_type *vfe32_ctrl)
+{
+	uint32_t irq_mask1, irq_mask;
+	atomic_set(&vfe32_ctrl->share_ctrl->vstate, 0);
+	msm_camera_io_w(VFE_MODULE_RESET_CMD,
+		vfe32_ctrl->share_ctrl->vfebase + VFE_MODULE_RESET);
+	msm_camera_io_w(0,
+		vfe32_ctrl->share_ctrl->vfebase + VFE_MODULE_RESET);
+
+	irq_mask =
+		msm_camera_io_r(vfe32_ctrl->share_ctrl->vfebase +
+			VFE_IRQ_MASK_0);
+	irq_mask &= ~(0x000FE021|VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK);
+
+	msm_camera_io_w(irq_mask, vfe32_ctrl->share_ctrl->vfebase +
+		VFE_IRQ_MASK_0);
+	vfe32_ctrl->share_ctrl->operation_mode &=
+		(VFE_OUTPUTS_RDI0|VFE_OUTPUTS_RDI1);
+	vfe32_ctrl->share_ctrl->comp_output_mode &=
+			(VFE32_OUTPUT_MODE_TERTIARY1|
+			VFE32_OUTPUT_MODE_TERTIARY2);
+
+	/* enable reset_ack interrupt.  */
+	irq_mask1 = msm_camera_io_r(
+		vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
+	irq_mask1 |= VFE_IMASK_WHILE_STOPPING_1;
+	msm_camera_io_w(irq_mask1,
+		vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
+	msm_camera_io_w_mb(VFE_ONLY_RESET_CMD,
+		vfe32_ctrl->share_ctrl->vfebase + VFE_GLOBAL_RESET);
+
+	return wait_for_completion_interruptible(
+			&vfe32_ctrl->share_ctrl->reset_complete);
+}
+
+static int axi_reset(struct axi_ctrl_t *axi_ctrl,
+	struct msm_camera_vfe_params_t vfe_params)
+{
+	int rc = 0;
+	if (vfe_params.skip_reset) {
+		axi_reset_internal_variables(axi_ctrl, vfe_params);
+		return rc;
+	}
+	axi_global_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,
@@ -729,7 +1140,6 @@
 {
 	uint32_t *p = cmd;
 
-	vfe32_ctrl->share_ctrl->operation_mode = *p;
 	vfe32_ctrl->share_ctrl->stats_comp = *(++p);
 	vfe32_ctrl->hfr_mode = *(++p);
 
@@ -738,19 +1148,6 @@
 	msm_camera_io_w(*(++p),
 		vfe32_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
 	msm_camera_io_w(*(++p),
-		vfe32_ctrl->share_ctrl->vfebase + VFE_PIXEL_IF_CFG);
-	if (msm_camera_io_r(vfe32_ctrl->share_ctrl->vfebase +
-		V32_GET_HW_VERSION_OFF) ==
-		VFE33_HW_NUMBER) {
-		msm_camera_io_w(*(++p),
-			vfe32_ctrl->share_ctrl->vfebase + VFE_RDI0_CFG);
-		msm_camera_io_w(*(++p),
-			vfe32_ctrl->share_ctrl->vfebase + VFE_RDI1_CFG);
-	}  else {
-		++p;
-		++p;
-	}
-	msm_camera_io_w(*(++p),
 		vfe32_ctrl->share_ctrl->vfebase + VFE_REALIGN_BUF);
 	msm_camera_io_w(*(++p),
 		vfe32_ctrl->share_ctrl->vfebase + VFE_CHROMA_UP);
@@ -767,7 +1164,7 @@
 	rc = vfe32_ctrl->stats_ops.dqbuf(
 			vfe32_ctrl->stats_ops.stats_ctrl, stats_type, &buf);
 	if (rc < 0) {
-		pr_err("%s: dq stats buf (type = %d) err = %d",
+		CDBG("%s: dq stats buf (type = %d) err = %d",
 			__func__, stats_type, rc);
 		return 0L;
 	}
@@ -802,7 +1199,7 @@
 		stats_buf = &bufq->bufs[i];
 		rc = vfe32_ctrl->stats_ops.enqueue_buf(
 				vfe32_ctrl->stats_ops.stats_ctrl,
-				&(stats_buf->info), NULL);
+				&(stats_buf->info), NULL, -1);
 		if (rc < 0) {
 			pr_err("%s: dq stats buf (type = %d) err = %d",
 				 __func__, stats_type, rc);
@@ -815,7 +1212,7 @@
 
 static unsigned long vfe32_stats_unregbuf(
 	struct vfe32_ctrl_type *vfe32_ctrl,
-	struct msm_stats_reqbuf *req_buf)
+	struct msm_stats_reqbuf *req_buf, int domain_num)
 {
 	int i = 0, rc = 0;
 
@@ -823,7 +1220,7 @@
 		rc = vfe32_ctrl->stats_ops.buf_unprepare(
 			vfe32_ctrl->stats_ops.stats_ctrl,
 			req_buf->stats_type, i,
-			vfe32_ctrl->stats_ops.client);
+			vfe32_ctrl->stats_ops.client, domain_num);
 		if (rc < 0) {
 			pr_err("%s: unreg stats buf (type = %d) err = %d",
 				__func__, req_buf->stats_type, rc);
@@ -1063,70 +1460,11 @@
 
 static void vfe32_start_common(struct vfe32_ctrl_type *vfe32_ctrl)
 {
-	uint32_t irq_mask = 0x00E00021, irq_mask1, reg_update;
-	uint16_t vfe_operation_mode =
-		vfe32_ctrl->share_ctrl->current_mode & ~(VFE_OUTPUTS_RDI0|
-			VFE_OUTPUTS_RDI1);
-	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->operation_mode,
 		vfe32_ctrl->share_ctrl->outpath.output_mode);
-	if (vfe32_ctrl->share_ctrl->stats_comp)
-		irq_mask |= VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK;
-	else
-		irq_mask |= 0x000FE000;
-	irq_mask |=
-		msm_camera_io_r(vfe32_ctrl->share_ctrl->vfebase +
-			VFE_IRQ_MASK_0);
-	msm_camera_io_w(irq_mask,
-		vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_0);
-	msm_camera_io_w(VFE_IMASK_WHILE_STOPPING_1,
-		vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
-
-	irq_mask1 =
-		msm_camera_io_r(vfe32_ctrl->share_ctrl->vfebase +
-			VFE_IRQ_MASK_1);
-	reg_update =
-		msm_camera_io_r_mb(vfe32_ctrl->share_ctrl->vfebase +
-			VFE_REG_UPDATE_CMD);
-
-	if (vfe32_ctrl->share_ctrl->current_mode & VFE_OUTPUTS_RDI0) {
-		irq_mask1 |= VFE_IRQ_STATUS1_RDI0_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->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);
-	}
-	if (vfe_operation_mode) {
-		msm_camera_io_w_mb(reg_update|0x1, vfe32_ctrl->share_ctrl->
-			vfebase + VFE_REG_UPDATE_CMD);
 		msm_camera_io_w_mb(1, vfe32_ctrl->share_ctrl->vfebase +
 			VFE_CAMIF_COMMAND);
-	}
-	vfe32_ctrl->share_ctrl->operation_mode |=
-		vfe32_ctrl->share_ctrl->current_mode;
-	/* Ensure the write order while writing
-	to the command register using the barrier */
-	atomic_set(&vfe32_ctrl->share_ctrl->vstate, 1);
 }
 
 static int vfe32_start_recording(
@@ -1176,6 +1514,7 @@
 	struct msm_cam_media_controller *pmctl,
 	struct vfe32_ctrl_type *vfe32_ctrl)
 {
+	vfe32_ctrl->share_ctrl->start_ack_pending = TRUE;
 	vfe32_start_common(vfe32_ctrl);
 
 	msm_camera_io_w(1, vfe32_ctrl->share_ctrl->vfebase + 0x18C);
@@ -1570,7 +1909,8 @@
 	case VFE_CMD_RESET:
 		pr_info("vfe32_proc_general: cmdID = %s\n",
 			vfe32_general_cmd[cmd->id]);
-		vfe32_reset_internal_variables(vfe32_ctrl);
+		vfe32_ctrl->share_ctrl->vfe_reset_flag = true;
+		vfe32_reset(vfe32_ctrl);
 		break;
 	case VFE_CMD_START:
 		pr_info("vfe32_proc_general: cmdID = %s\n",
@@ -2650,8 +2990,6 @@
 				goto proc_general_done;
 		}
 
-		vfe32_ctrl->share_ctrl->current_mode =
-			vfe_params.operation_mode;
 		vfe32_stop(vfe32_ctrl);
 		break;
 
@@ -3026,312 +3364,476 @@
 
 }
 
+void axi_stop_pix(struct vfe_share_ctrl_t *share_ctrl,
+	uint32_t vfe_mode, uint8_t cmd_type)
+{
+	uint32_t reg_update = 0x1;
+	switch (cmd_type) {
+	case AXI_CMD_RAW_CAPTURE:
+		msm_camera_io_w(0, share_ctrl->vfebase
+			+ vfe32_AXI_WM_CFG[share_ctrl->outpath.out0.ch0]);
+		break;
+	case AXI_CMD_PREVIEW: {
+		switch (vfe_mode) {
+		case VFE_OUTPUTS_PREVIEW:
+		case VFE_OUTPUTS_PREVIEW_AND_VIDEO:
+			if (share_ctrl->comp_output_mode &
+				VFE32_OUTPUT_MODE_PRIMARY) {
+				msm_camera_io_w(0, share_ctrl->vfebase
+					+ vfe32_AXI_WM_CFG[share_ctrl->
+					outpath.out0.ch0]);
+				msm_camera_io_w(0, share_ctrl->vfebase
+					+ vfe32_AXI_WM_CFG[share_ctrl->
+					outpath.out0.ch1]);
+			} else if (share_ctrl->comp_output_mode &
+					VFE32_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
+				msm_camera_io_w(0, share_ctrl->vfebase
+					+ vfe32_AXI_WM_CFG[share_ctrl->
+					outpath.out0.ch0]);
+				msm_camera_io_w(0, share_ctrl->vfebase
+					+ vfe32_AXI_WM_CFG[share_ctrl->
+					outpath.out0.ch1]);
+				msm_camera_io_w(0, share_ctrl->vfebase
+					+ vfe32_AXI_WM_CFG[share_ctrl->
+					outpath.out0.ch2]);
+			}
+			break;
+		default:
+			if (share_ctrl->comp_output_mode &
+				VFE32_OUTPUT_MODE_SECONDARY) {
+				msm_camera_io_w(0, share_ctrl->vfebase
+					+ vfe32_AXI_WM_CFG[share_ctrl->
+					outpath.out1.ch0]);
+				msm_camera_io_w(0, share_ctrl->vfebase
+					+ vfe32_AXI_WM_CFG[share_ctrl->
+					outpath.out1.ch1]);
+			} else if (share_ctrl->comp_output_mode &
+				VFE32_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
+				msm_camera_io_w(0, share_ctrl->vfebase
+					+ vfe32_AXI_WM_CFG[share_ctrl->
+					outpath.out1.ch0]);
+				msm_camera_io_w(0, share_ctrl->vfebase
+					+ vfe32_AXI_WM_CFG[share_ctrl->
+					outpath.out1.ch1]);
+				msm_camera_io_w(0, share_ctrl->vfebase
+					+ vfe32_AXI_WM_CFG[share_ctrl->
+					outpath.out1.ch2]);
+			}
+			break;
+			}
+		}
+		break;
+	default:
+		if (share_ctrl->comp_output_mode &
+			VFE32_OUTPUT_MODE_PRIMARY) {
+			msm_camera_io_w(0, share_ctrl->vfebase +
+				vfe32_AXI_WM_CFG[share_ctrl->
+				outpath.out0.ch0]);
+			msm_camera_io_w(0, share_ctrl->vfebase +
+				vfe32_AXI_WM_CFG[share_ctrl->
+				outpath.out0.ch1]);
+		} else if (share_ctrl->comp_output_mode &
+				VFE32_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
+			msm_camera_io_w(0, share_ctrl->vfebase +
+				vfe32_AXI_WM_CFG[share_ctrl->
+				outpath.out0.ch0]);
+			msm_camera_io_w(0, share_ctrl->vfebase +
+				vfe32_AXI_WM_CFG[share_ctrl->
+				outpath.out0.ch1]);
+			msm_camera_io_w(0, share_ctrl->vfebase +
+				vfe32_AXI_WM_CFG[share_ctrl->
+				outpath.out0.ch2]);
+		}
+
+		if (share_ctrl->comp_output_mode &
+			VFE32_OUTPUT_MODE_SECONDARY) {
+			msm_camera_io_w(0, share_ctrl->vfebase +
+				vfe32_AXI_WM_CFG[share_ctrl->
+				outpath.out1.ch0]);
+			msm_camera_io_w(0, share_ctrl->vfebase +
+				vfe32_AXI_WM_CFG[share_ctrl->outpath.out1.ch1]);
+		} else if (share_ctrl->comp_output_mode &
+			VFE32_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
+			msm_camera_io_w(0, share_ctrl->vfebase +
+				vfe32_AXI_WM_CFG[share_ctrl->outpath.out1.ch0]);
+			msm_camera_io_w(0, share_ctrl->vfebase +
+				vfe32_AXI_WM_CFG[share_ctrl->outpath.out1.ch1]);
+			msm_camera_io_w(0, share_ctrl->vfebase +
+				vfe32_AXI_WM_CFG[share_ctrl->outpath.out1.ch2]);
+		}
+		break;
+	}
+
+	msm_camera_io_w_mb(reg_update,
+		share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+}
+
+void axi_stop_rdi0(struct vfe_share_ctrl_t *share_ctrl)
+{
+	uint32_t reg_update = 0x2;
+	msm_camera_io_w(0, share_ctrl->vfebase +
+		vfe32_AXI_WM_CFG[share_ctrl->outpath.out2.ch0]);
+	msm_camera_io_w_mb(reg_update,
+		share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+}
+
+void axi_stop_rdi1(struct vfe_share_ctrl_t *share_ctrl)
+{
+	uint32_t reg_update = 0x4;
+	msm_camera_io_w(0, share_ctrl->vfebase +
+		vfe32_AXI_WM_CFG[share_ctrl->outpath.out3.ch0]);
+	msm_camera_io_w_mb(reg_update,
+		share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+}
+
+void axi_stop_process(struct vfe_share_ctrl_t *share_ctrl)
+{
+	uint32_t vfe_mode =
+	share_ctrl->current_mode & ~(VFE_OUTPUTS_RDI0|
+		VFE_OUTPUTS_RDI1);
+
+	if (share_ctrl->current_mode & VFE_OUTPUTS_RDI0) {
+		axi_stop_rdi0(share_ctrl);
+		axi_disable_wm_irq(share_ctrl,
+			VFE32_OUTPUT_MODE_TERTIARY1);
+		share_ctrl->comp_output_mode &= ~VFE32_OUTPUT_MODE_TERTIARY1;
+		share_ctrl->operation_mode &=
+			~(VFE_OUTPUTS_RDI0);
+	}
+	if (share_ctrl->current_mode & VFE_OUTPUTS_RDI1) {
+		axi_stop_rdi1(share_ctrl);
+		axi_disable_wm_irq(share_ctrl,
+			VFE32_OUTPUT_MODE_TERTIARY2);
+		share_ctrl->comp_output_mode &= ~VFE32_OUTPUT_MODE_TERTIARY2;
+		share_ctrl->operation_mode &=
+			~(VFE_OUTPUTS_RDI1);
+	}
+	if (vfe_mode) {
+		uint16_t mode = share_ctrl->comp_output_mode &
+			~(VFE32_OUTPUT_MODE_TERTIARY1|
+			VFE32_OUTPUT_MODE_TERTIARY2);
+		axi_stop_pix(share_ctrl, vfe_mode, share_ctrl->cmd_type);
+		axi_disable_wm_irq(share_ctrl, mode);
+		share_ctrl->comp_output_mode &=
+				(VFE32_OUTPUT_MODE_TERTIARY1|
+				VFE32_OUTPUT_MODE_TERTIARY2);
+	}
+}
+
 static void vfe32_process_reg_update_irq(
 		struct vfe32_ctrl_type *vfe32_ctrl)
 {
 	unsigned long flags;
+	struct vfe_share_ctrl_t *share_ctrl = vfe32_ctrl->share_ctrl;
+	if (atomic_read(
+		&share_ctrl->pix0_update_ack_pending) == 2) {
+		uint32_t vfe_mode =
+				share_ctrl->operation_mode & ~(VFE_OUTPUTS_RDI0|
+					VFE_OUTPUTS_RDI1);
 
-	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 +
-				vfe32_AXI_WM_CFG[vfe32_ctrl->
-				share_ctrl->outpath.out0.ch0]);
-			msm_camera_io_w(1, vfe32_ctrl->share_ctrl->vfebase +
-				vfe32_AXI_WM_CFG[vfe32_ctrl->
-				share_ctrl->outpath.out0.ch1]);
-		} else if (vfe32_ctrl->share_ctrl->operation_mode &
-				VFE_OUTPUTS_PREVIEW_AND_VIDEO) {
-			msm_camera_io_w(1, vfe32_ctrl->share_ctrl->vfebase +
-				vfe32_AXI_WM_CFG[vfe32_ctrl->
-				share_ctrl->outpath.out1.ch0]);
-			msm_camera_io_w(1, vfe32_ctrl->share_ctrl->vfebase +
-				vfe32_AXI_WM_CFG[vfe32_ctrl->
-				share_ctrl->outpath.out1.ch1]);
-		}
-		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->share_ctrl->recording_state ==
-			VFE_STATE_STOP_REQUESTED) {
-		if (vfe32_ctrl->share_ctrl->operation_mode &
-				VFE_OUTPUTS_VIDEO_AND_PREVIEW) {
-			msm_camera_io_w(0, vfe32_ctrl->share_ctrl->vfebase +
-				vfe32_AXI_WM_CFG[vfe32_ctrl->
-				share_ctrl->outpath.out0.ch0]);
-			msm_camera_io_w(0, vfe32_ctrl->share_ctrl->vfebase +
-				vfe32_AXI_WM_CFG[vfe32_ctrl->
-				share_ctrl->outpath.out0.ch1]);
-		} else if (vfe32_ctrl->share_ctrl->operation_mode &
-				VFE_OUTPUTS_PREVIEW_AND_VIDEO) {
-			msm_camera_io_w(0, vfe32_ctrl->share_ctrl->vfebase +
-				vfe32_AXI_WM_CFG[vfe32_ctrl->
-				share_ctrl->outpath.out1.ch0]);
-			msm_camera_io_w(0, vfe32_ctrl->share_ctrl->vfebase +
-				vfe32_AXI_WM_CFG[vfe32_ctrl->
-				share_ctrl->outpath.out1.ch1]);
-		}
-		CDBG("stop video triggered .\n");
-	}
-
-	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->share_ctrl->start_ack_lock, flags);
-		if (vfe32_ctrl->share_ctrl->recording_state ==
-				VFE_STATE_STOP_REQUESTED) {
-			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->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->share_ctrl->recording_state =
-						VFE_STATE_IDLE;
-		}
-		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->share_ctrl->update_ack_lock,
-								flags);
-			vfe32_send_isp_msg(&vfe32_ctrl->subdev,
-				vfe32_ctrl->share_ctrl->vfeFrameId,
-				MSG_ID_UPDATE_ACK);
+		if (share_ctrl->dual_enabled && !share_ctrl->update_counter) {
+			axi_stop_pix(share_ctrl, vfe_mode,
+				share_ctrl->cmd_type);
+			share_ctrl->update_counter++;
 		} else {
-			spin_unlock_irqrestore(
-				&vfe32_ctrl->share_ctrl->update_ack_lock,
-								flags);
+			uint16_t output_mode =
+				share_ctrl->comp_output_mode &
+				~(VFE32_OUTPUT_MODE_TERTIARY1|
+				VFE32_OUTPUT_MODE_TERTIARY2);
+			share_ctrl->update_counter = 0;
+			if (!share_ctrl->dual_enabled)
+				axi_stop_pix(share_ctrl, vfe_mode,
+					share_ctrl->cmd_type);
+			axi_disable_wm_irq(share_ctrl, output_mode);
+			axi_disable_irq(share_ctrl, vfe_mode);
+			atomic_set(&share_ctrl->pix0_update_ack_pending, 0);
+			msm_camera_io_w_mb(
+					CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY,
+					share_ctrl->vfebase +
+					VFE_CAMIF_COMMAND);
+			vfe32_send_isp_msg(&vfe32_ctrl->subdev,
+				share_ctrl->vfeFrameId,
+				MSG_ID_PIX0_UPDATE_ACK);
+			share_ctrl->comp_output_mode &=
+				(VFE32_OUTPUT_MODE_TERTIARY1|
+				VFE32_OUTPUT_MODE_TERTIARY2);
 		}
+	}  else {
+		if (share_ctrl->recording_state == VFE_STATE_START_REQUESTED) {
+			if (share_ctrl->operation_mode &
+					VFE_OUTPUTS_VIDEO_AND_PREVIEW) {
+				msm_camera_io_w((
+					0x1 << share_ctrl->outpath.out0.ch0 |
+					0x1 << share_ctrl->outpath.out0.ch1),
+					share_ctrl->vfebase + VFE_BUS_CMD);
+				msm_camera_io_w(1,
+					share_ctrl->vfebase + vfe32_AXI_WM_CFG[
+					share_ctrl->outpath.out0.ch0]);
+				msm_camera_io_w(1,
+					share_ctrl->vfebase + vfe32_AXI_WM_CFG[
+					share_ctrl->outpath.out0.ch1]);
+			} else if (share_ctrl->operation_mode &
+					VFE_OUTPUTS_PREVIEW_AND_VIDEO) {
+				msm_camera_io_w((
+					0x1 << share_ctrl->outpath.out1.ch0 |
+					0x1 << share_ctrl->outpath.out1.ch1),
+					share_ctrl->vfebase + VFE_BUS_CMD);
+				msm_camera_io_w(1,
+					share_ctrl->vfebase + vfe32_AXI_WM_CFG[
+					share_ctrl->outpath.out1.ch0]);
+				msm_camera_io_w(1,
+					share_ctrl->vfebase + vfe32_AXI_WM_CFG[
+					share_ctrl->outpath.out1.ch1]);
+			}
+			share_ctrl->recording_state = VFE_STATE_STARTED;
+			msm_camera_io_w_mb(1,
+				share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+			CDBG("start video triggered .\n");
+		} else if (share_ctrl->recording_state ==
+					VFE_STATE_STOP_REQUESTED) {
+			if (share_ctrl->operation_mode &
+					VFE_OUTPUTS_VIDEO_AND_PREVIEW) {
+				msm_camera_io_w(0,
+					share_ctrl->vfebase + vfe32_AXI_WM_CFG[
+					share_ctrl->outpath.out0.ch0]);
+				msm_camera_io_w(0,
+					share_ctrl->vfebase + vfe32_AXI_WM_CFG[
+					share_ctrl->outpath.out0.ch1]);
+			} else if (share_ctrl->operation_mode &
+					VFE_OUTPUTS_PREVIEW_AND_VIDEO) {
+				msm_camera_io_w(0,
+					share_ctrl->vfebase + vfe32_AXI_WM_CFG[
+					share_ctrl->outpath.out1.ch0]);
+				msm_camera_io_w(0,
+					share_ctrl->vfebase + vfe32_AXI_WM_CFG[
+					share_ctrl->outpath.out1.ch1]);
+			}
+			CDBG("stop video triggered .\n");
+		}
+
+		if (atomic_cmpxchg(
+		&share_ctrl->pix0_update_ack_pending, 1, 0) == 1) {
+			share_ctrl->comp_output_mode |=
+				(share_ctrl->outpath.output_mode
+				& ~(VFE32_OUTPUT_MODE_TERTIARY1|
+					VFE32_OUTPUT_MODE_TERTIARY2));
+			vfe32_send_isp_msg(&vfe32_ctrl->subdev,
+				share_ctrl->vfeFrameId, MSG_ID_PIX0_UPDATE_ACK);
+		} else {
+			if (share_ctrl->recording_state ==
+						VFE_STATE_STOP_REQUESTED) {
+				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, share_ctrl->vfebase +
+							VFE_REG_UPDATE_CMD);
+			} else if (share_ctrl->recording_state ==
+						VFE_STATE_STOPPED) {
+				vfe32_send_isp_msg(&vfe32_ctrl->subdev,
+					share_ctrl->vfeFrameId,
+					MSG_ID_STOP_REC_ACK);
+				share_ctrl->recording_state = VFE_STATE_IDLE;
+			}
+			spin_lock_irqsave(
+				&share_ctrl->update_ack_lock,
+				flags);
+			if (share_ctrl->update_ack_pending == TRUE) {
+				share_ctrl->update_ack_pending = FALSE;
+				spin_unlock_irqrestore(
+					&share_ctrl->update_ack_lock, flags);
+				vfe32_send_isp_msg(&vfe32_ctrl->subdev,
+					share_ctrl->vfeFrameId,
+					MSG_ID_UPDATE_ACK);
+			} else {
+				spin_unlock_irqrestore(
+					&share_ctrl->update_ack_lock, flags);
+			}
+		}
+
+		switch (share_ctrl->liveshot_state) {
+		case VFE_STATE_START_REQUESTED:
+			CDBG("%s enabling liveshot output\n", __func__);
+			if (share_ctrl->comp_output_mode &
+						VFE32_OUTPUT_MODE_PRIMARY) {
+				msm_camera_io_w((
+					0x1 << share_ctrl->outpath.out0.ch0 |
+					0x1 << share_ctrl->outpath.out0.ch1),
+					share_ctrl->vfebase + VFE_BUS_CMD);
+				msm_camera_io_w(1, share_ctrl->vfebase +
+					vfe32_AXI_WM_CFG[
+					share_ctrl->outpath.out0.ch0]);
+				msm_camera_io_w(1, share_ctrl->vfebase +
+					vfe32_AXI_WM_CFG[
+					share_ctrl->outpath.out0.ch1]);
+
+				share_ctrl->liveshot_state =
+					VFE_STATE_STARTED;
+			}
+			break;
+		case VFE_STATE_STARTED:
+			share_ctrl->vfe_capture_count--;
+			if (!share_ctrl->vfe_capture_count &&
+				(share_ctrl->comp_output_mode &
+					VFE32_OUTPUT_MODE_PRIMARY)) {
+				msm_camera_io_w(0, share_ctrl->vfebase +
+					vfe32_AXI_WM_CFG[
+					share_ctrl->outpath.out0.ch0]);
+				msm_camera_io_w(0, share_ctrl->vfebase +
+					vfe32_AXI_WM_CFG[
+					share_ctrl->outpath.out0.ch1]);
+			}
+			break;
+		case VFE_STATE_STOP_REQUESTED:
+			if (share_ctrl->comp_output_mode &
+					VFE32_OUTPUT_MODE_PRIMARY) {
+				/* Stop requested, stop write masters, and
+				 * trigger REG_UPDATE. Send STOP_LS_ACK in
+				 * next reg update. */
+				msm_camera_io_w(0, share_ctrl->vfebase +
+					vfe32_AXI_WM_CFG[
+					share_ctrl->outpath.out0.ch0]);
+				msm_camera_io_w(0, share_ctrl->vfebase +
+					vfe32_AXI_WM_CFG[
+					share_ctrl->outpath.out0.ch1]);
+
+				share_ctrl->liveshot_state = VFE_STATE_STOPPED;
+				msm_camera_io_w_mb(1, share_ctrl->vfebase +
+					VFE_REG_UPDATE_CMD);
+			}
+			break;
+		case VFE_STATE_STOPPED:
+			CDBG("%s Sending STOP_LS ACK\n", __func__);
+			vfe32_send_isp_msg(&vfe32_ctrl->subdev,
+				share_ctrl->vfeFrameId, MSG_ID_STOP_LS_ACK);
+			share_ctrl->liveshot_state = VFE_STATE_IDLE;
+			break;
+		default:
+			break;
+		}
+
+		if ((share_ctrl->operation_mode & VFE_OUTPUTS_THUMB_AND_MAIN) ||
+			(share_ctrl->operation_mode &
+				VFE_OUTPUTS_MAIN_AND_THUMB) ||
+			(share_ctrl->operation_mode &
+				VFE_OUTPUTS_THUMB_AND_JPEG) ||
+			(share_ctrl->operation_mode &
+				VFE_OUTPUTS_JPEG_AND_THUMB)) {
+			/* in snapshot mode */
+			/* later we need to add check for live snapshot mode. */
+			if (vfe32_ctrl->frame_skip_pattern & (0x1 <<
+				(vfe32_ctrl->snapshot_frame_cnt %
+					vfe32_ctrl->frame_skip_cnt))) {
+				share_ctrl->vfe_capture_count--;
+				/* if last frame to be captured: */
+				if (share_ctrl->vfe_capture_count == 0) {
+					/* stop the bus output: */
+					uint32_t vfe_mode =
+						share_ctrl->operation_mode &
+							~(VFE_OUTPUTS_RDI0|
+							VFE_OUTPUTS_RDI1);
+					axi_stop_pix(share_ctrl, vfe_mode,
+						AXI_CMD_CAPTURE);
+					msm_camera_io_w_mb
+					(CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY,
+					share_ctrl->vfebase +
+					VFE_CAMIF_COMMAND);
+					vfe32_ctrl->snapshot_frame_cnt = -1;
+					vfe32_ctrl->frame_skip_cnt = 31;
+					vfe32_ctrl->frame_skip_pattern =
+								0xffffffff;
+				} /*if snapshot count is 0*/
+			} /*if frame is not being dropped*/
+			vfe32_ctrl->snapshot_frame_cnt++;
+			/* then do reg_update. */
+			msm_camera_io_w(1,
+				share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+		} /* if snapshot mode. */
 	}
-
-	switch (vfe32_ctrl->share_ctrl->liveshot_state) {
-	case VFE_STATE_START_REQUESTED:
-		CDBG("%s enabling liveshot output\n", __func__);
-		if (vfe32_ctrl->share_ctrl->outpath.output_mode &
-			VFE32_OUTPUT_MODE_PRIMARY) {
-			msm_camera_io_w(1, vfe32_ctrl->share_ctrl->vfebase +
-				vfe32_AXI_WM_CFG[vfe32_ctrl->
-				share_ctrl->outpath.out0.ch0]);
-			msm_camera_io_w(1, vfe32_ctrl->share_ctrl->vfebase +
-				vfe32_AXI_WM_CFG[vfe32_ctrl->
-				share_ctrl->outpath.out0.ch1]);
-
-			vfe32_ctrl->share_ctrl->liveshot_state =
-				VFE_STATE_STARTED;
-		}
-		break;
-	case VFE_STATE_STARTED:
-		vfe32_ctrl->share_ctrl->vfe_capture_count--;
-		if (!vfe32_ctrl->share_ctrl->vfe_capture_count &&
-			(vfe32_ctrl->share_ctrl->outpath.output_mode &
-				VFE32_OUTPUT_MODE_PRIMARY)) {
-			msm_camera_io_w(0, vfe32_ctrl->share_ctrl->vfebase +
-				vfe32_AXI_WM_CFG[vfe32_ctrl->
-				share_ctrl->outpath.out0.ch0]);
-			msm_camera_io_w(0, vfe32_ctrl->share_ctrl->vfebase +
-				vfe32_AXI_WM_CFG[vfe32_ctrl->
-				share_ctrl->outpath.out0.ch1]);
-		}
-		break;
-	case VFE_STATE_STOP_REQUESTED:
-		if (vfe32_ctrl->share_ctrl->outpath.output_mode &
-				VFE32_OUTPUT_MODE_PRIMARY) {
-			/* Stop requested, stop write masters, and
-			 * trigger REG_UPDATE. Send STOP_LS_ACK in
-			 * next reg update. */
-			msm_camera_io_w(0, vfe32_ctrl->share_ctrl->vfebase +
-				vfe32_AXI_WM_CFG[vfe32_ctrl->
-				share_ctrl->outpath.out0.ch0]);
-			msm_camera_io_w(0, vfe32_ctrl->share_ctrl->vfebase +
-				vfe32_AXI_WM_CFG[vfe32_ctrl->
-				share_ctrl->outpath.out0.ch1]);
-
-			vfe32_ctrl->share_ctrl->liveshot_state =
-				VFE_STATE_STOPPED;
-			msm_camera_io_w_mb(1, vfe32_ctrl->share_ctrl->vfebase +
-				VFE_REG_UPDATE_CMD);
-		}
-		break;
-	case VFE_STATE_STOPPED:
-		CDBG("%s Sending STOP_LS ACK\n", __func__);
-		vfe32_send_isp_msg(&vfe32_ctrl->subdev,
-		vfe32_ctrl->share_ctrl->vfeFrameId, MSG_ID_STOP_LS_ACK);
-		vfe32_ctrl->share_ctrl->liveshot_state = VFE_STATE_IDLE;
-		break;
-	default:
-		break;
-	}
-
-	if ((vfe32_ctrl->share_ctrl->operation_mode &
-			VFE_OUTPUTS_THUMB_AND_MAIN) ||
-		(vfe32_ctrl->share_ctrl->operation_mode &
-			VFE_OUTPUTS_MAIN_AND_THUMB) ||
-		(vfe32_ctrl->share_ctrl->operation_mode &
-			VFE_OUTPUTS_THUMB_AND_JPEG) ||
-		(vfe32_ctrl->share_ctrl->operation_mode &
-			VFE_OUTPUTS_JPEG_AND_THUMB)) {
-		/* in snapshot mode */
-		/* later we need to add check for live snapshot mode. */
-		if (vfe32_ctrl->frame_skip_pattern & (0x1 <<
-			(vfe32_ctrl->snapshot_frame_cnt %
-				vfe32_ctrl->frame_skip_cnt))) {
-			vfe32_ctrl->share_ctrl->vfe_capture_count--;
-			/* if last frame to be captured: */
-			if (vfe32_ctrl->share_ctrl->vfe_capture_count == 0) {
-				/* stop the bus output:write master enable = 0*/
-				if (vfe32_ctrl->share_ctrl->outpath.output_mode
-					& VFE32_OUTPUT_MODE_PRIMARY) {
-					msm_camera_io_w(0,
-						vfe32_ctrl->share_ctrl->vfebase+
-						vfe32_AXI_WM_CFG[vfe32_ctrl->
-						share_ctrl->outpath.out0.ch0]);
-					msm_camera_io_w(0,
-						vfe32_ctrl->share_ctrl->vfebase+
-						vfe32_AXI_WM_CFG[vfe32_ctrl->
-						share_ctrl->outpath.out0.ch1]);
-				}
-				if (vfe32_ctrl->share_ctrl->outpath.output_mode&
-						VFE32_OUTPUT_MODE_SECONDARY) {
-					msm_camera_io_w(0,
-						vfe32_ctrl->share_ctrl->vfebase+
-						vfe32_AXI_WM_CFG[vfe32_ctrl->
-						share_ctrl->outpath.out1.ch0]);
-					msm_camera_io_w(0,
-						vfe32_ctrl->share_ctrl->vfebase+
-						vfe32_AXI_WM_CFG[vfe32_ctrl->
-						share_ctrl->outpath.out1.ch1]);
-				}
-				msm_camera_io_w_mb
-				(CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY,
-				vfe32_ctrl->share_ctrl->vfebase +
-				VFE_CAMIF_COMMAND);
-				vfe32_ctrl->snapshot_frame_cnt = -1;
-				vfe32_ctrl->frame_skip_cnt = 31;
-				vfe32_ctrl->frame_skip_pattern = 0xffffffff;
-			} /*if snapshot count is 0*/
-		} /*if frame is not being dropped*/
-		vfe32_ctrl->snapshot_frame_cnt++;
-		/* then do reg_update. */
-		msm_camera_io_w(1,
-			vfe32_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
-	} /* if snapshot mode. */
 }
 
 static void vfe32_process_rdi0_reg_update_irq(
 	struct vfe32_ctrl_type *vfe32_ctrl)
 {
 	if (atomic_cmpxchg(
-		&vfe32_ctrl->share_ctrl->rdi0_update_ack_pending, 1, 0)) {
+		&vfe32_ctrl->share_ctrl->rdi0_update_ack_pending, 1, 0) == 1) {
+		vfe32_ctrl->share_ctrl->comp_output_mode |=
+			VFE32_OUTPUT_MODE_TERTIARY1;
 		vfe32_send_isp_msg(&vfe32_ctrl->subdev,
-			vfe32_ctrl->share_ctrl->vfeFrameId,
+			vfe32_ctrl->share_ctrl->rdi0FrameId,
 			MSG_ID_RDI0_UPDATE_ACK);
 	}
+
+	if ((atomic_read(
+		&vfe32_ctrl->share_ctrl->rdi0_update_ack_pending) == 2)
+		|| (vfe32_ctrl->share_ctrl->rdi0_capture_count == 0)) {
+		axi_disable_wm_irq(vfe32_ctrl->share_ctrl,
+			VFE32_OUTPUT_MODE_TERTIARY1);
+		axi_disable_irq(vfe32_ctrl->share_ctrl, VFE_OUTPUTS_RDI0);
+		atomic_set(&vfe32_ctrl->share_ctrl->rdi0_update_ack_pending, 0);
+		vfe32_send_isp_msg(&vfe32_ctrl->subdev,
+			vfe32_ctrl->share_ctrl->rdi0FrameId,
+			MSG_ID_RDI0_UPDATE_ACK);
+
+		if (vfe32_ctrl->share_ctrl->rdi0_capture_count == 0)
+			vfe32_ctrl->share_ctrl->rdi0_capture_count = -1;
+		if (vfe32_ctrl->share_ctrl->outpath.out2.capture_cnt
+			== 0)
+			vfe32_ctrl->share_ctrl->outpath.out2.capture_cnt = -1;
+		vfe32_ctrl->share_ctrl->comp_output_mode &=
+			~VFE32_OUTPUT_MODE_TERTIARY1;
+		vfe32_ctrl->share_ctrl->operation_mode &=
+			~(VFE_OUTPUTS_RDI0);
+	}
+
+	if (vfe32_ctrl->share_ctrl->rdi0_capture_count > 0) {
+		vfe32_ctrl->share_ctrl->rdi0_capture_count--;
+		if (!vfe32_ctrl->share_ctrl->rdi0_capture_count)
+			axi_stop_rdi0(vfe32_ctrl->share_ctrl);
+	}
 }
 
 static void vfe32_process_rdi1_reg_update_irq(
 	struct vfe32_ctrl_type *vfe32_ctrl)
 {
+
 	if (atomic_cmpxchg(
-		&vfe32_ctrl->share_ctrl->rdi1_update_ack_pending, 1, 0)) {
+		&vfe32_ctrl->share_ctrl->rdi1_update_ack_pending, 1, 0)
+				== 1) {
+		vfe32_ctrl->share_ctrl->comp_output_mode |=
+			VFE32_OUTPUT_MODE_TERTIARY2;
 		vfe32_send_isp_msg(&vfe32_ctrl->subdev,
-			vfe32_ctrl->share_ctrl->vfeFrameId,
+			vfe32_ctrl->share_ctrl->rdi1FrameId,
 			MSG_ID_RDI1_UPDATE_ACK);
 	}
-}
 
-static void vfe32_set_default_reg_values(
-	struct vfe32_ctrl_type *vfe32_ctrl)
-{
-	msm_camera_io_w(0x800080,
-		vfe32_ctrl->share_ctrl->vfebase + VFE_DEMUX_GAIN_0);
-	msm_camera_io_w(0x800080,
-		vfe32_ctrl->share_ctrl->vfebase + VFE_DEMUX_GAIN_1);
-	/* What value should we program CGC_OVERRIDE to? */
-	msm_camera_io_w(0xFFFFF,
-		vfe32_ctrl->share_ctrl->vfebase + VFE_CGC_OVERRIDE);
+	if ((atomic_read(
+		&vfe32_ctrl->share_ctrl->rdi1_update_ack_pending) == 2)
+		|| (vfe32_ctrl->share_ctrl->rdi1_capture_count == 0)) {
+		axi_disable_wm_irq(vfe32_ctrl->share_ctrl,
+			VFE32_OUTPUT_MODE_TERTIARY2);
+		axi_disable_irq(vfe32_ctrl->share_ctrl, VFE_OUTPUTS_RDI1);
+		atomic_set(&vfe32_ctrl->share_ctrl->rdi1_update_ack_pending, 0);
+		vfe32_send_isp_msg(&vfe32_ctrl->subdev,
+			vfe32_ctrl->share_ctrl->rdi1FrameId,
+			MSG_ID_RDI1_UPDATE_ACK);
 
-	/* default frame drop period and pattern */
-	msm_camera_io_w(0x1f,
-		vfe32_ctrl->share_ctrl->vfebase + VFE_FRAMEDROP_ENC_Y_CFG);
-	msm_camera_io_w(0x1f,
-		vfe32_ctrl->share_ctrl->vfebase + VFE_FRAMEDROP_ENC_CBCR_CFG);
-	msm_camera_io_w(0xFFFFFFFF,
-		vfe32_ctrl->share_ctrl->vfebase + VFE_FRAMEDROP_ENC_Y_PATTERN);
-	msm_camera_io_w(0xFFFFFFFF,
-		vfe32_ctrl->share_ctrl->vfebase +
-		VFE_FRAMEDROP_ENC_CBCR_PATTERN);
-	msm_camera_io_w(0x1f,
-		vfe32_ctrl->share_ctrl->vfebase + VFE_FRAMEDROP_VIEW_Y);
-	msm_camera_io_w(0x1f,
-		vfe32_ctrl->share_ctrl->vfebase + VFE_FRAMEDROP_VIEW_CBCR);
-	msm_camera_io_w(0xFFFFFFFF,
-		vfe32_ctrl->share_ctrl->vfebase + VFE_FRAMEDROP_VIEW_Y_PATTERN);
-	msm_camera_io_w(0xFFFFFFFF,
-		vfe32_ctrl->share_ctrl->vfebase +
-		VFE_FRAMEDROP_VIEW_CBCR_PATTERN);
-	msm_camera_io_w(0, vfe32_ctrl->share_ctrl->vfebase + VFE_CLAMP_MIN);
-	msm_camera_io_w(0xFFFFFF,
-		vfe32_ctrl->share_ctrl->vfebase + VFE_CLAMP_MAX);
-
-	/* stats UB config */
-	CDBG("%s: Use bayer stats = %d\n", __func__,
-		 vfe32_use_bayer_stats(vfe32_ctrl));
-	if (!vfe32_use_bayer_stats(vfe32_ctrl)) {
-		msm_camera_io_w(0x3980007,
-			vfe32_ctrl->share_ctrl->vfebase +
-				VFE_BUS_STATS_AEC_BG_UB_CFG);
-		msm_camera_io_w(0x3A00007,
-			vfe32_ctrl->share_ctrl->vfebase +
-				VFE_BUS_STATS_AF_BF_UB_CFG);
-		msm_camera_io_w(0x3A8000F,
-			vfe32_ctrl->share_ctrl->vfebase +
-				VFE_BUS_STATS_AWB_UB_CFG);
-		msm_camera_io_w(0x3B80007,
-			vfe32_ctrl->share_ctrl->vfebase +
-				VFE_BUS_STATS_RS_UB_CFG);
-		msm_camera_io_w(0x3C0001F,
-			vfe32_ctrl->share_ctrl->vfebase +
-				VFE_BUS_STATS_CS_UB_CFG);
-		msm_camera_io_w(0x3E0001F,
-			vfe32_ctrl->share_ctrl->vfebase +
-				VFE_BUS_STATS_HIST_UB_CFG);
-	} else {
-		msm_camera_io_w(0x350001F,
-			vfe32_ctrl->share_ctrl->vfebase +
-				VFE_BUS_STATS_HIST_UB_CFG);
-		msm_camera_io_w(0x370002F,
-			vfe32_ctrl->share_ctrl->vfebase +
-				VFE_BUS_STATS_AEC_BG_UB_CFG);
-		msm_camera_io_w(0x3A0002F,
-			vfe32_ctrl->share_ctrl->vfebase +
-				VFE_BUS_STATS_AF_BF_UB_CFG);
-		msm_camera_io_w(0x3D00007,
-			vfe32_ctrl->share_ctrl->vfebase +
-				VFE_BUS_STATS_RS_UB_CFG);
-		msm_camera_io_w(0x3D8001F,
-			vfe32_ctrl->share_ctrl->vfebase +
-				VFE_BUS_STATS_CS_UB_CFG);
-		msm_camera_io_w(0x3F80007,
-			vfe32_ctrl->share_ctrl->vfebase +
-				VFE_BUS_STATS_SKIN_BHIST_UB_CFG);
+		if (vfe32_ctrl->share_ctrl->rdi1_capture_count == 0)
+			vfe32_ctrl->share_ctrl->rdi1_capture_count = -1;
+		if (vfe32_ctrl->share_ctrl->outpath.out3.capture_cnt
+			== 0)
+			vfe32_ctrl->share_ctrl->outpath.out3.capture_cnt = -1;
+		vfe32_ctrl->share_ctrl->comp_output_mode &=
+			~VFE32_OUTPUT_MODE_TERTIARY2;
+		vfe32_ctrl->share_ctrl->operation_mode &=
+			~(VFE_OUTPUTS_RDI1);
 	}
-	vfe32_reset_dmi_tables(vfe32_ctrl);
+
+	if (vfe32_ctrl->share_ctrl->rdi1_capture_count > 0) {
+		vfe32_ctrl->share_ctrl->rdi1_capture_count--;
+		if (!vfe32_ctrl->share_ctrl->rdi1_capture_count)
+			axi_stop_rdi1(vfe32_ctrl->share_ctrl);
+	}
 }
 
 static void vfe32_process_reset_irq(
@@ -3340,23 +3842,33 @@
 	unsigned long flags;
 
 	atomic_set(&vfe32_ctrl->share_ctrl->vstate, 0);
+	atomic_set(&vfe32_ctrl->share_ctrl->handle_common_irq, 0);
 
 	spin_lock_irqsave(&vfe32_ctrl->share_ctrl->stop_flag_lock, flags);
 	if (vfe32_ctrl->share_ctrl->stop_ack_pending) {
 		vfe32_ctrl->share_ctrl->stop_ack_pending = FALSE;
 		spin_unlock_irqrestore(
 			&vfe32_ctrl->share_ctrl->stop_flag_lock, flags);
-		vfe32_send_isp_msg(&vfe32_ctrl->subdev,
-			vfe32_ctrl->share_ctrl->vfeFrameId, MSG_ID_STOP_ACK);
+		if (vfe32_ctrl->share_ctrl->sync_abort)
+			complete(&vfe32_ctrl->share_ctrl->reset_complete);
+		else
+			vfe32_send_isp_msg(&vfe32_ctrl->subdev,
+				vfe32_ctrl->share_ctrl->vfeFrameId,
+				MSG_ID_STOP_ACK);
 	} else {
 		spin_unlock_irqrestore(
 			&vfe32_ctrl->share_ctrl->stop_flag_lock, flags);
 		/* this is from reset command. */
-		vfe32_set_default_reg_values(vfe32_ctrl);
-
-		/* reload all write masters. (frame & line)*/
-		msm_camera_io_w(0x7FFF,
-			vfe32_ctrl->share_ctrl->vfebase + VFE_BUS_CMD);
+		vfe32_reset_internal_variables(vfe32_ctrl);
+		if (vfe32_ctrl->share_ctrl->vfe_reset_flag) {
+			vfe32_ctrl->share_ctrl->vfe_reset_flag = false;
+			msm_camera_io_w(0x7F80,
+				vfe32_ctrl->share_ctrl->vfebase + VFE_BUS_CMD);
+		} else {
+			/* reload all write masters. (frame & line)*/
+			msm_camera_io_w(0x7FFF,
+				vfe32_ctrl->share_ctrl->vfebase + VFE_BUS_CMD);
+		}
 		complete(&vfe32_ctrl->share_ctrl->reset_complete);
 	}
 }
@@ -3364,14 +3876,20 @@
 static void vfe32_process_camif_sof_irq(
 		struct vfe32_ctrl_type *vfe32_ctrl)
 {
-	if (vfe32_ctrl->share_ctrl->operation_mode &
+	if (vfe32_ctrl->share_ctrl->operation_mode ==
 		VFE_OUTPUTS_RAW) {
-		if (vfe32_ctrl->share_ctrl->start_ack_pending) {
+		if (atomic_cmpxchg(
+			&vfe32_ctrl->share_ctrl->pix0_update_ack_pending,
+					1, 0) == 1) {
+			vfe32_ctrl->share_ctrl->comp_output_mode |=
+				(vfe32_ctrl->share_ctrl->outpath.output_mode
+				& ~(VFE32_OUTPUT_MODE_TERTIARY1|
+				VFE32_OUTPUT_MODE_TERTIARY2));
 			vfe32_send_isp_msg(&vfe32_ctrl->subdev,
 				vfe32_ctrl->share_ctrl->vfeFrameId,
-				MSG_ID_START_ACK);
-			vfe32_ctrl->share_ctrl->start_ack_pending = FALSE;
+				MSG_ID_PIX0_UPDATE_ACK);
 		}
+
 		vfe32_ctrl->share_ctrl->vfe_capture_count--;
 		/* if last frame to be captured: */
 		if (vfe32_ctrl->share_ctrl->vfe_capture_count == 0) {
@@ -3411,6 +3929,12 @@
 	struct axi_ctrl_t *axi_ctrl, uint32_t errStatus)
 {
 	uint32_t reg_value;
+	if (errStatus & VFE32_IMASK_VIOLATION) {
+		pr_err("vfe32_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 & VFE32_IMASK_CAMIF_ERROR) {
 		pr_err("vfe32_irq: camif errors\n");
@@ -3441,12 +3965,31 @@
 	if (errStatus & VFE32_IMASK_REALIGN_BUF_CR_OVFL)
 		pr_err("vfe32_irq: realign bug CR overflow\n");
 
-	if (errStatus & VFE32_IMASK_VIOLATION) {
-		pr_err("vfe32_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 & VFE32_IMASK_STATS_AE_BG_BUS_OVFL)
+		pr_err("vfe32_irq: ae/bg stats bus overflow\n");
+
+	if (errStatus & VFE32_IMASK_STATS_AF_BF_BUS_OVFL)
+		pr_err("vfe32_irq: af/bf stats bus overflow\n");
+
+	if (errStatus & VFE32_IMASK_STATS_AWB_BUS_OVFL)
+		pr_err("vfe32_irq: awb stats bus overflow\n");
+
+	if (errStatus & VFE32_IMASK_STATS_RS_BUS_OVFL)
+		pr_err("vfe32_irq: rs stats bus overflow\n");
+
+	if (errStatus & VFE32_IMASK_STATS_CS_BUS_OVFL)
+		pr_err("vfe32_irq: cs stats bus overflow\n");
+
+	if (errStatus & VFE32_IMASK_STATS_IHIST_BUS_OVFL)
+		pr_err("vfe32_irq: ihist stats bus overflow\n");
+
+	if (errStatus & VFE32_IMASK_STATS_SKIN_BHIST_BUS_OVFL)
+		pr_err("vfe32_irq: skin/bhist stats bus overflow\n");
+}
+
+static void vfe32_process_common_error_irq(
+	struct axi_ctrl_t *axi_ctrl, uint32_t errStatus)
+{
 
 	if (errStatus & VFE32_IMASK_IMG_MAST_0_BUS_OVFL)
 		pr_err("vfe32_irq: image master 0 bus overflow\n");
@@ -3469,31 +4012,11 @@
 	if (errStatus & VFE32_IMASK_IMG_MAST_6_BUS_OVFL)
 		pr_err("vfe32_irq: image master 6 bus overflow\n");
 
-	if (errStatus & VFE32_IMASK_STATS_AE_BG_BUS_OVFL)
-		pr_err("vfe32_irq: ae/bg stats bus overflow\n");
-
-	if (errStatus & VFE32_IMASK_STATS_AF_BF_BUS_OVFL)
-		pr_err("vfe32_irq: af/bf stats bus overflow\n");
-
-	if (errStatus & VFE32_IMASK_STATS_AWB_BUS_OVFL)
-		pr_err("vfe32_irq: awb stats bus overflow\n");
-
-	if (errStatus & VFE32_IMASK_STATS_RS_BUS_OVFL)
-		pr_err("vfe32_irq: rs stats bus overflow\n");
-
-	if (errStatus & VFE32_IMASK_STATS_CS_BUS_OVFL)
-		pr_err("vfe32_irq: cs stats bus overflow\n");
-
-	if (errStatus & VFE32_IMASK_STATS_IHIST_BUS_OVFL)
-		pr_err("vfe32_irq: ihist stats bus overflow\n");
-
-	if (errStatus & VFE32_IMASK_STATS_SKIN_BHIST_BUS_OVFL)
-		pr_err("vfe32_irq: skin/bhist stats bus overflow\n");
-
 	if (errStatus & VFE32_IMASK_AXI_ERROR)
 		pr_err("vfe32_irq: axi error\n");
 }
 
+
 static void vfe_send_outmsg(
 	struct axi_ctrl_t *axi_ctrl, uint8_t msgid,
 	uint32_t ch0_paddr, uint32_t ch1_paddr,
@@ -3506,7 +4029,17 @@
 	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;
+	switch (msgid) {
+	case MSG_ID_OUTPUT_TERTIARY1:
+		msg.frameCounter = axi_ctrl->share_ctrl->rdi0FrameId;
+		break;
+	case MSG_ID_OUTPUT_TERTIARY2:
+		msg.frameCounter = axi_ctrl->share_ctrl->rdi1FrameId;
+		break;
+	default:
+		msg.frameCounter = axi_ctrl->share_ctrl->vfeFrameId;
+		break;
+	}
 
 	v4l2_subdev_notify(&axi_ctrl->subdev,
 			NOTIFY_VFE_MSG_OUT,
@@ -3521,7 +4054,6 @@
 	uint32_t ch0_paddr, ch1_paddr, ch2_paddr;
 	uint8_t out_bool = 0;
 	struct msm_free_buf *free_buf = NULL;
-
 	free_buf = vfe32_check_free_buffer(VFE_MSG_OUTPUT_IRQ,
 		VFE_MSG_OUTPUT_PRIMARY, axi_ctrl);
 
@@ -3532,15 +4064,15 @@
 	free buffer.
 	*/
 	out_bool = (
-		(axi_ctrl->share_ctrl->operation_mode ==
+		(axi_ctrl->share_ctrl->operation_mode &
 			VFE_OUTPUTS_THUMB_AND_MAIN ||
-		axi_ctrl->share_ctrl->operation_mode ==
+		axi_ctrl->share_ctrl->operation_mode &
 			VFE_OUTPUTS_MAIN_AND_THUMB ||
-		axi_ctrl->share_ctrl->operation_mode ==
+		axi_ctrl->share_ctrl->operation_mode &
 			VFE_OUTPUTS_THUMB_AND_JPEG ||
-		axi_ctrl->share_ctrl->operation_mode ==
+		axi_ctrl->share_ctrl->operation_mode &
 			VFE_OUTPUTS_JPEG_AND_THUMB ||
-		axi_ctrl->share_ctrl->operation_mode ==
+		axi_ctrl->share_ctrl->operation_mode &
 			VFE_OUTPUTS_RAW ||
 		axi_ctrl->share_ctrl->liveshot_state ==
 			VFE_STATE_STARTED ||
@@ -3587,15 +4119,15 @@
 					axi_ctrl->share_ctrl->outpath.out0.ch2,
 					free_buf->ch_paddr[2]);
 		}
-		if (axi_ctrl->share_ctrl->operation_mode ==
+		if (axi_ctrl->share_ctrl->operation_mode &
 				VFE_OUTPUTS_THUMB_AND_MAIN ||
-			axi_ctrl->share_ctrl->operation_mode ==
+			axi_ctrl->share_ctrl->operation_mode &
 				VFE_OUTPUTS_MAIN_AND_THUMB ||
-			axi_ctrl->share_ctrl->operation_mode ==
+			axi_ctrl->share_ctrl->operation_mode &
 				VFE_OUTPUTS_THUMB_AND_JPEG ||
-			axi_ctrl->share_ctrl->operation_mode ==
+			axi_ctrl->share_ctrl->operation_mode &
 				VFE_OUTPUTS_JPEG_AND_THUMB ||
-			axi_ctrl->share_ctrl->operation_mode ==
+			axi_ctrl->share_ctrl->operation_mode &
 				VFE_OUTPUTS_RAW ||
 			axi_ctrl->share_ctrl->liveshot_state ==
 				VFE_STATE_STOPPED)
@@ -3623,13 +4155,13 @@
 
 	free_buf = vfe32_check_free_buffer(VFE_MSG_OUTPUT_IRQ,
 		VFE_MSG_OUTPUT_SECONDARY, axi_ctrl);
-	out_bool = ((axi_ctrl->share_ctrl->operation_mode ==
+	out_bool = ((axi_ctrl->share_ctrl->operation_mode &
 				VFE_OUTPUTS_THUMB_AND_MAIN ||
-			axi_ctrl->share_ctrl->operation_mode ==
+			axi_ctrl->share_ctrl->operation_mode &
 				VFE_OUTPUTS_MAIN_AND_THUMB ||
-			axi_ctrl->share_ctrl->operation_mode ==
+			axi_ctrl->share_ctrl->operation_mode &
 				VFE_OUTPUTS_RAW ||
-			axi_ctrl->share_ctrl->operation_mode ==
+			axi_ctrl->share_ctrl->operation_mode &
 				VFE_OUTPUTS_JPEG_AND_THUMB) &&
 			(axi_ctrl->share_ctrl->vfe_capture_count <= 1)) ||
 				free_buf;
@@ -3669,13 +4201,13 @@
 					axi_ctrl->share_ctrl->outpath.out1.ch2,
 					free_buf->ch_paddr[2]);
 		}
-		if (axi_ctrl->share_ctrl->operation_mode ==
+		if (axi_ctrl->share_ctrl->operation_mode &
 				VFE_OUTPUTS_THUMB_AND_MAIN ||
-			axi_ctrl->share_ctrl->operation_mode ==
+			axi_ctrl->share_ctrl->operation_mode &
 				VFE_OUTPUTS_MAIN_AND_THUMB ||
-			axi_ctrl->share_ctrl->operation_mode ==
+			axi_ctrl->share_ctrl->operation_mode &
 				VFE_OUTPUTS_RAW ||
-			axi_ctrl->share_ctrl->operation_mode ==
+			axi_ctrl->share_ctrl->operation_mode &
 				VFE_OUTPUTS_JPEG_AND_THUMB)
 			axi_ctrl->share_ctrl->outpath.out1.capture_cnt--;
 
@@ -3698,10 +4230,12 @@
 	/* this must be rdi image output. */
 	struct msm_free_buf *free_buf = NULL;
 	/*RDI0*/
+	CDBG("rdi0 out irq\n");
 	if (axi_ctrl->share_ctrl->operation_mode & VFE_OUTPUTS_RDI0) {
 		free_buf = vfe32_check_free_buffer(VFE_MSG_OUTPUT_IRQ,
 			VFE_MSG_OUTPUT_TERTIARY1, axi_ctrl);
-		if (free_buf) {
+		if (axi_ctrl->share_ctrl->outpath.out2.capture_cnt > 0 ||
+							free_buf) {
 			ping_pong = msm_camera_io_r(axi_ctrl->
 				share_ctrl->vfebase +
 				VFE_BUS_PING_PONG_STATUS);
@@ -3714,11 +4248,14 @@
 			pr_debug("%s ch0 = 0x%x\n",
 				__func__, ch0_paddr);
 
-			/* Y channel */
-			vfe32_put_ch_addr(ping_pong,
-				axi_ctrl->share_ctrl->vfebase,
-				axi_ctrl->share_ctrl->outpath.out2.ch0,
-				free_buf->ch_paddr[0]);
+			if (free_buf)
+				vfe32_put_ch_addr(ping_pong,
+					axi_ctrl->share_ctrl->vfebase,
+					axi_ctrl->share_ctrl->outpath.out2.ch0,
+					free_buf->ch_paddr[0]);
+			if (axi_ctrl->share_ctrl->outpath.out2.capture_cnt == 1)
+				axi_ctrl->share_ctrl->
+					outpath.out2.capture_cnt = 0;
 
 			vfe_send_outmsg(axi_ctrl,
 				MSG_ID_OUTPUT_TERTIARY1, ch0_paddr,
@@ -3743,7 +4280,8 @@
 	if (axi_ctrl->share_ctrl->operation_mode & VFE_OUTPUTS_RDI1) {
 		free_buf = vfe32_check_free_buffer(VFE_MSG_OUTPUT_IRQ,
 			VFE_MSG_OUTPUT_TERTIARY2, axi_ctrl);
-		if (free_buf) {
+		if (axi_ctrl->share_ctrl->outpath.out3.capture_cnt > 0 ||
+							free_buf) {
 			ping_pong = msm_camera_io_r(axi_ctrl->
 				share_ctrl->vfebase +
 				VFE_BUS_PING_PONG_STATUS);
@@ -3755,11 +4293,15 @@
 			pr_debug("%s ch0 = 0x%x\n",
 				__func__, ch0_paddr);
 
-			/* Y channel */
-			vfe32_put_ch_addr(ping_pong,
-				axi_ctrl->share_ctrl->vfebase,
-				axi_ctrl->share_ctrl->outpath.out3.ch0,
-				free_buf->ch_paddr[0]);
+			if (free_buf)
+				vfe32_put_ch_addr(ping_pong,
+					axi_ctrl->share_ctrl->vfebase,
+					axi_ctrl->share_ctrl->outpath.out3.ch0,
+					free_buf->ch_paddr[0]);
+			if (axi_ctrl->share_ctrl->
+					outpath.out3.capture_cnt == 1)
+				axi_ctrl->share_ctrl->
+				outpath.out3.capture_cnt = 0;
 
 			vfe_send_outmsg(axi_ctrl,
 				MSG_ID_OUTPUT_TERTIARY2, ch0_paddr,
@@ -4359,7 +4901,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);
 		}
@@ -4367,41 +4909,51 @@
 		/* 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))
+		if (atomic_read(&axi_ctrl->share_ctrl->handle_common_irq)) {
+			if (qcmd->vfeInterruptStatus1 &
+					VFE32_IMASK_COMMON_ERROR_ONLY_1) {
+				pr_err("irq	errorIrq\n");
+				vfe32_process_common_error_irq(
+					axi_ctrl,
+					qcmd->vfeInterruptStatus1 &
+					VFE32_IMASK_COMMON_ERROR_ONLY_1);
+			}
+
 			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) {
+					VFE32_IMASK_VFE_ERROR_ONLY_1) {
 				pr_err("irq	errorIrq\n");
 				vfe32_process_error_irq(
 					axi_ctrl,
 					qcmd->vfeInterruptStatus1 &
-					VFE32_IMASK_ERROR_ONLY_1);
+					VFE32_IMASK_VFE_ERROR_ONLY_1);
 			}
 
 			/* then process stats irq. */
@@ -4410,7 +4962,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);
 				}
@@ -4418,60 +4970,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);
 			}
@@ -4540,7 +5092,7 @@
 
 static long vfe_stats_bufq_sub_ioctl(
 	struct vfe32_ctrl_type *vfe_ctrl,
-	struct msm_vfe_cfg_cmd *cmd, void *ion_client)
+	struct msm_vfe_cfg_cmd *cmd, void *ion_client, int domain_num)
 {
 	long rc = 0;
 	switch (cmd->cmd_type) {
@@ -4589,7 +5141,7 @@
 	rc = vfe_ctrl->stats_ops.enqueue_buf(
 			&vfe_ctrl->stats_ctrl,
 			(struct msm_stats_buf_info *)cmd->value,
-			vfe_ctrl->stats_ops.client);
+			vfe_ctrl->stats_ops.client, domain_num);
 	break;
 	case VFE_CMD_STATS_FLUSH_BUFQ:
 	{
@@ -4623,7 +5175,7 @@
 			rc = -EINVAL ;
 			goto end;
 		}
-		rc = vfe32_stats_unregbuf(vfe_ctrl, req_buf);
+		rc = vfe32_stats_unregbuf(vfe_ctrl, req_buf, domain_num);
 	}
 	break;
 	default:
@@ -4678,7 +5230,7 @@
 	case VFE_CMD_STATS_UNREGBUF:
 		/* for easy porting put in one envelope */
 		rc = vfe_stats_bufq_sub_ioctl(vfe32_ctrl,
-				cmd, vfe_params->data);
+				cmd, vfe_params->data, pmctl->domain_num);
 		return rc;
 	default:
 		if (cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
@@ -4693,8 +5245,8 @@
 		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_VFE_SOF_COUNT_UPDATE &&
-		cmd->cmd_type != CMD_VFE_COUNT_SOF_ENABLE) {
+		cmd->cmd_type != CMD_VFE_PIX_SOF_COUNT_UPDATE &&
+		cmd->cmd_type != CMD_VFE_COUNT_PIX_SOF_ENABLE) {
 			if (copy_from_user(&vfecmd,
 					(void __user *)(cmd->value),
 					sizeof(vfecmd))) {
@@ -4774,7 +5326,7 @@
 	case CMD_GENERAL:
 		rc = vfe32_proc_general(pmctl, &vfecmd, vfe32_ctrl);
 	break;
-	case CMD_VFE_COUNT_SOF_ENABLE: {
+	case CMD_VFE_COUNT_PIX_SOF_ENABLE: {
 		int enable = *((int *)cmd->value);
 		if (enable)
 			vfe32_ctrl->vfe_sof_count_enable = TRUE;
@@ -4782,7 +5334,7 @@
 			vfe32_ctrl->vfe_sof_count_enable = false;
 	}
 	break;
-	case CMD_VFE_SOF_COUNT_UPDATE:
+	case CMD_VFE_PIX_SOF_COUNT_UPDATE:
 		if (!vfe32_ctrl->vfe_sof_count_enable)
 			vfe32_ctrl->share_ctrl->vfeFrameId =
 			*((uint32_t *)vfe_params->data);
@@ -4839,6 +5391,9 @@
 	int round_rate;
 	struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd);
 
+	if (axi_ctrl->share_ctrl->dual_enabled)
+		return rc;
+
 	round_rate = clk_round_rate(axi_ctrl->vfe_clk[0], freq);
 	if (rc < 0) {
 		pr_err("%s: clk_round_rate failed %d\n",
@@ -4863,17 +5418,22 @@
 	.core = &msm_vfe_subdev_core_ops,
 };
 
-int msm_axi_subdev_init(struct v4l2_subdev *sd)
+int msm_axi_subdev_init(struct v4l2_subdev *sd,
+	uint8_t dual_enabled)
 {
 	int rc = 0;
 	struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd);
-	struct msm_cam_media_controller *mctl;
-	mctl = v4l2_get_subdev_hostdata(sd);
+	struct msm_cam_media_controller *mctl =
+		v4l2_get_subdev_hostdata(sd);
 	if (mctl == NULL) {
-		pr_err("%s: mctl is NULL\n", __func__);
 		rc = -EINVAL;
 		goto mctl_failed;
 	}
+
+	axi_ctrl->share_ctrl->axi_ref_cnt++;
+	if (axi_ctrl->share_ctrl->axi_ref_cnt > 1)
+		return rc;
+	axi_ctrl->share_ctrl->dual_enabled = dual_enabled;
 	spin_lock_init(&axi_ctrl->tasklet_lock);
 	INIT_LIST_HEAD(&axi_ctrl->tasklet_q);
 	spin_lock_init(&axi_ctrl->share_ctrl->sd_notify_lock);
@@ -4899,10 +5459,30 @@
 	if (rc < 0)
 		goto clk_enable_failed;
 
+#ifdef CONFIG_MSM_IOMMU
+	rc = iommu_attach_device(mctl->domain, axi_ctrl->iommu_ctx_imgwr);
+	if (rc < 0) {
+		pr_err("%s: imgwr attach failed rc = %d\n", __func__, rc);
+		rc = -ENODEV;
+		goto device_imgwr_attach_failed;
+	}
+	rc = iommu_attach_device(mctl->domain, axi_ctrl->iommu_ctx_misc);
+	if (rc < 0) {
+		pr_err("%s: misc attach failed rc = %d\n", __func__, rc);
+		rc = -ENODEV;
+		goto device_misc_attach_failed;
+	}
+#endif
+
 	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);
+
+	if (axi_ctrl->share_ctrl->dual_enabled)
+		msm_camio_bus_scale_cfg(
+			mctl->sdata->pdata->cam_bus_scale_table, S_DUAL);
+	else
+		msm_camio_bus_scale_cfg(
+			mctl->sdata->pdata->cam_bus_scale_table, S_PREVIEW);
 
 	if (msm_camera_io_r(
 		axi_ctrl->share_ctrl->vfebase + V32_GET_HW_VERSION_OFF) ==
@@ -4911,9 +5491,21 @@
 	else
 		axi_ctrl->share_ctrl->register_total = VFE33_REGISTER_TOTAL;
 
+	spin_lock_init(&axi_ctrl->share_ctrl->stop_flag_lock);
+	spin_lock_init(&axi_ctrl->share_ctrl->update_ack_lock);
+	spin_lock_init(&axi_ctrl->share_ctrl->start_ack_lock);
+
 	enable_irq(axi_ctrl->vfeirq->start);
 
 	return rc;
+
+#ifdef CONFIG_MSM_IOMMU
+device_misc_attach_failed:
+	iommu_detach_device(mctl->domain, axi_ctrl->iommu_ctx_imgwr);
+device_imgwr_attach_failed:
+#endif
+	msm_cam_clk_enable(&axi_ctrl->pdev->dev, vfe32_clk_info,
+			axi_ctrl->vfe_clk, ARRAY_SIZE(vfe32_clk_info), 0);
 clk_enable_failed:
 	if (axi_ctrl->fs_vfe)
 		regulator_disable(axi_ctrl->fs_vfe);
@@ -4921,7 +5513,6 @@
 	iounmap(axi_ctrl->share_ctrl->vfebase);
 	axi_ctrl->share_ctrl->vfebase = NULL;
 remap_failed:
-	disable_irq(axi_ctrl->vfeirq->start);
 mctl_failed:
 	return rc;
 }
@@ -4932,11 +5523,7 @@
 	struct vfe32_ctrl_type *vfe32_ctrl =
 		(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->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;
@@ -4946,7 +5533,8 @@
 	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));
+	memset(&vfe32_ctrl->stats_ctrl, 0,
+		sizeof(struct msm_stats_bufq_ctrl));
 	memset(&vfe32_ctrl->stats_ops, 0, sizeof(struct msm_stats_ops));
 
 	return rc;
@@ -4954,17 +5542,25 @@
 
 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);
+	struct msm_cam_media_controller *pmctl =
+		v4l2_get_subdev_hostdata(sd);
+
 	if (!axi_ctrl->share_ctrl->vfebase) {
 		pr_err("%s: base address unmapped\n", __func__);
 		return;
 	}
 
-	CDBG("%s, free_irq\n", __func__);
+	axi_ctrl->share_ctrl->axi_ref_cnt--;
+	if (axi_ctrl->share_ctrl->axi_ref_cnt > 0)
+		return;
+	axi_ctrl->share_ctrl->dual_enabled = 0;
 	disable_irq(axi_ctrl->vfeirq->start);
 	tasklet_kill(&axi_ctrl->vfe32_tasklet);
+#ifdef CONFIG_MSM_IOMMU
+	iommu_detach_device(pmctl->domain, axi_ctrl->iommu_ctx_misc);
+	iommu_detach_device(pmctl->domain, axi_ctrl->iommu_ctx_imgwr);
+#endif
 	msm_cam_clk_enable(&axi_ctrl->pdev->dev, vfe32_clk_info,
 			axi_ctrl->vfe_clk, ARRAY_SIZE(vfe32_clk_info), 0);
 	if (axi_ctrl->fs_vfe)
@@ -4978,20 +5574,26 @@
 
 	msm_camio_bus_scale_cfg(
 		pmctl->sdata->pdata->cam_bus_scale_table, S_EXIT);
+
 }
 
 void msm_vfe_subdev_release(struct v4l2_subdev *sd)
 {
 	struct vfe32_ctrl_type *vfe32_ctrl =
 		(struct vfe32_ctrl_type *)v4l2_get_subdevdata(sd);
-	if (!vfe32_ctrl->share_ctrl->vfebase)
-		vfe32_ctrl->share_ctrl->vfebase = NULL;
+	CDBG("vfe subdev release %p\n",
+		vfe32_ctrl->share_ctrl->vfebase);
 }
 
 void axi_abort(struct axi_ctrl_t *axi_ctrl)
 {
 	uint8_t  axi_busy_flag = true;
+	unsigned long flags;
 	/* axi halt command. */
+
+	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);
 	msm_camera_io_w(AXI_HALT,
 		axi_ctrl->share_ctrl->vfebase + VFE_AXI_CMD);
 	wmb();
@@ -5017,6 +5619,9 @@
 	* 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);
+	if (axi_ctrl->share_ctrl->sync_abort)
+		wait_for_completion_interruptible(
+			&axi_ctrl->share_ctrl->reset_complete);
 }
 
 int axi_config_buffers(struct axi_ctrl_t *axi_ctrl,
@@ -5121,39 +5726,53 @@
 		}
 		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) {
+		if (vfe_mode) {
+			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 */
+				/* 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_JPEG_CAPTURE,
-				VFE_MSG_OUTPUT_PRIMARY,
-				axi_ctrl);
-		} else {
-			/* Configure primary channel */
+					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;
+			}
+		}
+
+		if (axi_ctrl->share_ctrl->current_mode &
+				VFE_OUTPUTS_RDI0)
 			rc = configure_pingpong_buffers(
-				VFE_MSG_CAPTURE,
-				VFE_MSG_OUTPUT_PRIMARY,
+				VFE_MSG_CAPTURE, VFE_MSG_OUTPUT_TERTIARY1,
 				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,
+		if (axi_ctrl->share_ctrl->current_mode &
+				VFE_OUTPUTS_RDI1)
+			rc = configure_pingpong_buffers(
+				VFE_MSG_CAPTURE, VFE_MSG_OUTPUT_TERTIARY2,
 				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;
@@ -5167,107 +5786,88 @@
 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;
+	uint32_t reg_update = 0;
+	uint32_t vfe_mode =
+		(axi_ctrl->share_ctrl->current_mode &
+		~(VFE_OUTPUTS_RDI0|VFE_OUTPUTS_RDI1));
 	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);
+		if (!axi_ctrl->share_ctrl->dual_enabled)
+			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);
+		if (!axi_ctrl->share_ctrl->dual_enabled)
+			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);
+		if (!axi_ctrl->share_ctrl->dual_enabled)
+			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);
+		if (!axi_ctrl->share_ctrl->dual_enabled)
+			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);
+		if (!axi_ctrl->share_ctrl->dual_enabled)
+			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 +
-			VFE_IRQ_COMP_MASK);
-
-	if (axi_ctrl->share_ctrl->outpath.output_mode &
-			VFE32_OUTPUT_MODE_PRIMARY) {
-		irq_comp_mask |= (
-			0x1 << axi_ctrl->share_ctrl->outpath.out0.ch0 |
-			0x1 << axi_ctrl->share_ctrl->outpath.out0.ch1);
-	} else if (axi_ctrl->share_ctrl->outpath.output_mode &
-			   VFE32_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
-		irq_comp_mask |= (
-			0x1 << axi_ctrl->share_ctrl->outpath.out0.ch0 |
-			0x1 << axi_ctrl->share_ctrl->outpath.out0.ch1 |
-			0x1 << axi_ctrl->share_ctrl->outpath.out0.ch2);
-	}
-	if (axi_ctrl->share_ctrl->outpath.output_mode &
-			VFE32_OUTPUT_MODE_SECONDARY) {
-		irq_comp_mask |= (
-			0x1 << (axi_ctrl->share_ctrl->outpath.out1.ch0 + 8) |
-			0x1 << (axi_ctrl->share_ctrl->outpath.out1.ch1 + 8));
-	} else if (axi_ctrl->share_ctrl->outpath.output_mode &
-			VFE32_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
-		irq_comp_mask |= (
-			0x1 << (axi_ctrl->share_ctrl->outpath.out1.ch0 + 8) |
-			0x1 << (axi_ctrl->share_ctrl->outpath.out1.ch1 + 8) |
-			0x1 << (axi_ctrl->share_ctrl->outpath.out1.ch2 + 8));
-	}
-	if (axi_ctrl->share_ctrl->outpath.output_mode &
-		VFE32_OUTPUT_MODE_TERTIARY1) {
-		irq_mask = msm_camera_io_r(axi_ctrl->share_ctrl->vfebase +
-			VFE_IRQ_MASK_0);
-		irq_mask |= (0x1 << (axi_ctrl->share_ctrl->outpath.out2.ch0 +
-			VFE_WM_OFFSET));
-		msm_camera_io_w(irq_mask, axi_ctrl->share_ctrl->vfebase +
-			VFE_IRQ_MASK_0);
-	}
-	if (axi_ctrl->share_ctrl->outpath.output_mode &
-		VFE32_OUTPUT_MODE_TERTIARY2) {
-		irq_mask = msm_camera_io_r(axi_ctrl->share_ctrl->vfebase +
-			VFE_IRQ_MASK_0);
-		irq_mask |= (0x1 << (axi_ctrl->share_ctrl->outpath.out3.ch0 +
-			VFE_WM_OFFSET));
-		msm_camera_io_w(irq_mask, axi_ctrl->share_ctrl->vfebase +
-			VFE_IRQ_MASK_0);
-	}
-
-	msm_camera_io_w(irq_comp_mask,
-		axi_ctrl->share_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+	axi_enable_wm_irq(axi_ctrl->share_ctrl);
 
 	switch (vfe_params.cmd_type) {
+	case AXI_CMD_RAW_CAPTURE:
+		msm_camera_io_w((
+			0x1 << axi_ctrl->share_ctrl->outpath.out0.ch0),
+			axi_ctrl->share_ctrl->vfebase + VFE_BUS_CMD);
+		msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase
+			+ vfe32_AXI_WM_CFG[axi_ctrl->
+			share_ctrl->outpath.out0.ch0]);
+		break;
 	case AXI_CMD_PREVIEW: {
-		uint16_t operation_mode =
-		(axi_ctrl->share_ctrl->operation_mode &
-		~(VFE_OUTPUTS_RDI0|VFE_OUTPUTS_RDI1));
-
-		switch (operation_mode) {
+		switch (vfe_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((
+					0x1 << axi_ctrl->share_ctrl->
+							outpath.out0.ch0 |
+					0x1 << axi_ctrl->share_ctrl->
+							outpath.out0.ch1),
+					axi_ctrl->share_ctrl->vfebase +
+							VFE_BUS_CMD);
 				msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase
 					+ vfe32_AXI_WM_CFG[axi_ctrl->
 					share_ctrl->outpath.out0.ch0]);
 				msm_camera_io_w(1, 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((
+					0x1 << axi_ctrl->share_ctrl->
+							outpath.out0.ch0 |
+					0x1 << axi_ctrl->share_ctrl->
+							outpath.out0.ch1 |
+					0x1 << axi_ctrl->share_ctrl->
+							outpath.out0.ch2),
+					axi_ctrl->share_ctrl->vfebase +
+							VFE_BUS_CMD);
 				msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase
 					+ vfe32_AXI_WM_CFG[axi_ctrl->
 					share_ctrl->outpath.out0.ch0]);
@@ -5282,6 +5882,13 @@
 		default:
 			if (axi_ctrl->share_ctrl->outpath.output_mode &
 				VFE32_OUTPUT_MODE_SECONDARY) {
+				msm_camera_io_w((
+					0x1 << axi_ctrl->share_ctrl->
+						outpath.out1.ch0 |
+					0x1 << axi_ctrl->share_ctrl->
+						outpath.out1.ch1),
+					axi_ctrl->share_ctrl->vfebase +
+						VFE_BUS_CMD);
 				msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase
 					+ vfe32_AXI_WM_CFG[axi_ctrl->
 					share_ctrl->outpath.out1.ch0]);
@@ -5290,6 +5897,15 @@
 					share_ctrl->outpath.out1.ch1]);
 			} else if (axi_ctrl->share_ctrl->outpath.output_mode &
 				VFE32_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
+				msm_camera_io_w((
+					0x1 << axi_ctrl->share_ctrl->
+							outpath.out1.ch0 |
+					0x1 << axi_ctrl->share_ctrl->
+							outpath.out1.ch1 |
+					0x1 << axi_ctrl->share_ctrl->
+							outpath.out1.ch2),
+					axi_ctrl->share_ctrl->vfebase +
+							VFE_BUS_CMD);
 				msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase
 					+ vfe32_AXI_WM_CFG[axi_ctrl->
 					share_ctrl->outpath.out1.ch0]);
@@ -5307,6 +5923,10 @@
 	default:
 		if (axi_ctrl->share_ctrl->outpath.output_mode &
 			VFE32_OUTPUT_MODE_PRIMARY) {
+			msm_camera_io_w((
+				0x1 << axi_ctrl->share_ctrl->outpath.out0.ch0 |
+				0x1 << axi_ctrl->share_ctrl->outpath.out0.ch1),
+				axi_ctrl->share_ctrl->vfebase + VFE_BUS_CMD);
 			msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
 				vfe32_AXI_WM_CFG[axi_ctrl->
 				share_ctrl->outpath.out0.ch0]);
@@ -5315,6 +5935,11 @@
 				share_ctrl->outpath.out0.ch1]);
 		} else if (axi_ctrl->share_ctrl->outpath.output_mode &
 				VFE32_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
+			msm_camera_io_w((
+				0x1 << axi_ctrl->share_ctrl->outpath.out0.ch0 |
+				0x1 << axi_ctrl->share_ctrl->outpath.out0.ch1 |
+				0x1 << axi_ctrl->share_ctrl->outpath.out0.ch2),
+				axi_ctrl->share_ctrl->vfebase + VFE_BUS_CMD);
 			msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
 				vfe32_AXI_WM_CFG[axi_ctrl->
 				share_ctrl->outpath.out0.ch0]);
@@ -5328,6 +5953,10 @@
 
 		if (axi_ctrl->share_ctrl->outpath.output_mode &
 			VFE32_OUTPUT_MODE_SECONDARY) {
+			msm_camera_io_w((
+				0x1 << axi_ctrl->share_ctrl->outpath.out1.ch0 |
+				0x1 << axi_ctrl->share_ctrl->outpath.out1.ch1),
+				axi_ctrl->share_ctrl->vfebase + VFE_BUS_CMD);
 			msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
 				vfe32_AXI_WM_CFG[axi_ctrl->
 				share_ctrl->outpath.out1.ch0]);
@@ -5336,6 +5965,11 @@
 				share_ctrl->outpath.out1.ch1]);
 		} else if (axi_ctrl->share_ctrl->outpath.output_mode &
 			VFE32_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
+			msm_camera_io_w((
+				0x1 << axi_ctrl->share_ctrl->outpath.out1.ch0 |
+				0x1 << axi_ctrl->share_ctrl->outpath.out1.ch1 |
+				0x1 << axi_ctrl->share_ctrl->outpath.out1.ch2),
+				axi_ctrl->share_ctrl->vfebase + VFE_BUS_CMD);
 			msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
 				vfe32_AXI_WM_CFG[axi_ctrl->
 				share_ctrl->outpath.out1.ch0]);
@@ -5348,168 +5982,121 @@
 		}
 		break;
 	}
-	if (axi_ctrl->share_ctrl->current_mode & VFE_OUTPUTS_RDI0)
+	if (axi_ctrl->share_ctrl->current_mode & VFE_OUTPUTS_RDI0) {
+		axi_ctrl->share_ctrl->outpath.out2.capture_cnt =
+						vfe_params.capture_count;
+		axi_ctrl->share_ctrl->rdi0_capture_count =
+						vfe_params.capture_count;
+		msm_camera_io_w((
+				0x1 << axi_ctrl->share_ctrl->outpath.out2.ch0),
+				axi_ctrl->share_ctrl->vfebase + VFE_BUS_CMD);
 		msm_camera_io_w(1, 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)
+	}
+	if (axi_ctrl->share_ctrl->current_mode & VFE_OUTPUTS_RDI1) {
+		axi_ctrl->share_ctrl->outpath.out3.capture_cnt =
+						vfe_params.capture_count;
+		axi_ctrl->share_ctrl->rdi1_capture_count =
+						vfe_params.capture_count;
+		msm_camera_io_w((
+				0x1 << axi_ctrl->share_ctrl->outpath.out3.ch0),
+				axi_ctrl->share_ctrl->vfebase + VFE_BUS_CMD);
 		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);
+	}
+
+	axi_enable_irq(axi_ctrl->share_ctrl);
+
+	if (axi_ctrl->share_ctrl->current_mode & VFE_OUTPUTS_RDI0) {
+		if (!atomic_cmpxchg(
+			&axi_ctrl->share_ctrl->rdi0_update_ack_pending,
+				0, 1))
+			reg_update |= 0x2;
+	}
+	if (axi_ctrl->share_ctrl->current_mode & VFE_OUTPUTS_RDI1) {
+		if (!atomic_cmpxchg(
+			&axi_ctrl->share_ctrl->rdi1_update_ack_pending,
+				0, 1))
+			reg_update |= 0x4;
+	}
+
+	if (vfe_mode) {
+		if (!atomic_cmpxchg(
+			&axi_ctrl->share_ctrl->pix0_update_ack_pending,
+				0, 1))
+			reg_update |= 0x1;
+	}
+
+	msm_camera_io_w_mb(reg_update,
+			axi_ctrl->share_ctrl->vfebase +
+			VFE_REG_UPDATE_CMD);
+	axi_ctrl->share_ctrl->operation_mode |=
+		axi_ctrl->share_ctrl->current_mode;
 }
 
 void axi_stop(struct msm_cam_media_controller *pmctl,
 	struct axi_ctrl_t *axi_ctrl, struct msm_camera_vfe_params_t vfe_params)
 {
 	uint32_t reg_update = 0;
-	unsigned long flags;
-	uint32_t operation_mode =
+	uint32_t vfe_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:
+		axi_ctrl->share_ctrl->cmd_type = vfe_params.cmd_type;
 		break;
 	case AXI_CMD_RECORD:
-		msm_camio_bus_scale_cfg(
-		pmctl->sdata->pdata->cam_bus_scale_table, S_PREVIEW);
+		if (!axi_ctrl->share_ctrl->dual_enabled)
+			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);
+		if (!axi_ctrl->share_ctrl->dual_enabled)
+			msm_camio_bus_scale_cfg(
+			pmctl->sdata->pdata->cam_bus_scale_table, S_VIDEO);
 		return;
 	default:
 		return;
 	}
 
-	if (!axi_ctrl->share_ctrl->skip_abort) {
-		atomic_set(&axi_ctrl->share_ctrl->handle_axi_irq, 0);
-		axi_disable_irq(axi_ctrl);
+	if (axi_ctrl->share_ctrl->stop_immediately) {
+		axi_disable_irq(axi_ctrl->share_ctrl,
+			axi_ctrl->share_ctrl->current_mode);
+		axi_stop_process(axi_ctrl->share_ctrl);
+		return;
 	}
 
-	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 (!atomic_cmpxchg(
+			&axi_ctrl->share_ctrl->rdi0_update_ack_pending,
+				0, 2))
+			reg_update |= 0x2;
 	}
-	if (axi_ctrl->share_ctrl->current_mode & VFE_OUTPUTS_RDI0)
+	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.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;
+				outpath.out3.ch0]);
+		if (!atomic_cmpxchg(
+			&axi_ctrl->share_ctrl->rdi1_update_ack_pending,
+				0, 2))
+			reg_update |= 0x4;
+	}
+	if (vfe_mode) {
+		if (!atomic_cmpxchg(
+			&axi_ctrl->share_ctrl->pix0_update_ack_pending,
+				0, 2))
+			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)
@@ -5520,7 +6107,6 @@
 	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__);
@@ -5716,11 +6302,6 @@
 		}
 		axi_ctrl->share_ctrl->current_mode =
 			vfe_params.operation_mode;
-		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;
@@ -5733,16 +6314,28 @@
 		}
 		axi_ctrl->share_ctrl->current_mode =
 			vfe_params.operation_mode;
-		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_ctrl->share_ctrl->stop_immediately =
+			vfe_params.stop_immediately;
 		axi_stop(pmctl, axi_ctrl, vfe_params);
 		}
 		break;
-	case CMD_AXI_RESET:
-		axi_reset(axi_ctrl);
+	case CMD_AXI_RESET: {
+		struct msm_camera_vfe_params_t vfe_params;
+		if (copy_from_user(&vfe_params,
+				(void __user *)(vfecmd.value),
+				sizeof(struct msm_camera_vfe_params_t))) {
+				return -EFAULT;
+		}
+		axi_reset(axi_ctrl, vfe_params);
+		}
+		break;
+	case CMD_AXI_ABORT:
+		if (copy_from_user(&axi_ctrl->share_ctrl->sync_abort,
+				(void __user *)(vfecmd.value),
+				sizeof(uint8_t))) {
+				return -EFAULT;
+		}
+		axi_abort(axi_ctrl);
 		break;
 	default:
 		pr_err("%s Unsupported AXI configuration %x ", __func__,
@@ -5756,12 +6349,12 @@
 {
 	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__);
 		return;
 	}
+
 	/* next, check output path related interrupts. */
 	if (irqstatus &
 		VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK) {
@@ -5774,12 +6367,12 @@
 		vfe32_process_output_path_irq_1(axi_ctrl);
 	}
 
-	if (axi_ctrl->share_ctrl->outpath.output_mode &
+	if (axi_ctrl->share_ctrl->comp_output_mode &
 		VFE32_OUTPUT_MODE_TERTIARY1)
 		if (irqstatus & (0x1 << (axi_ctrl->share_ctrl->outpath.out2.ch0
 			+ VFE_WM_OFFSET)))
 			vfe32_process_output_path_irq_rdi0(axi_ctrl);
-	if (axi_ctrl->share_ctrl->outpath.output_mode &
+	if (axi_ctrl->share_ctrl->comp_output_mode &
 		VFE32_OUTPUT_MODE_TERTIARY2)
 		if (irqstatus & (0x1 << (axi_ctrl->share_ctrl->outpath.out3.ch0
 			+ VFE_WM_OFFSET)))
@@ -5788,39 +6381,57 @@
 	/* in snapshot mode if done then send
 	snapshot done message */
 	if (
-		axi_ctrl->share_ctrl->operation_mode ==
+		axi_ctrl->share_ctrl->operation_mode &
 			VFE_OUTPUTS_THUMB_AND_MAIN ||
-		axi_ctrl->share_ctrl->operation_mode ==
+		axi_ctrl->share_ctrl->operation_mode &
 			VFE_OUTPUTS_MAIN_AND_THUMB ||
-		axi_ctrl->share_ctrl->operation_mode ==
+		axi_ctrl->share_ctrl->operation_mode &
 			VFE_OUTPUTS_THUMB_AND_JPEG ||
-		axi_ctrl->share_ctrl->operation_mode ==
+		axi_ctrl->share_ctrl->operation_mode &
 			VFE_OUTPUTS_JPEG_AND_THUMB ||
-		axi_ctrl->share_ctrl->operation_mode ==
+		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);
-			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);
+			uint32_t mode =
+				(axi_ctrl->share_ctrl->operation_mode &
+				~(VFE_OUTPUTS_RDI0|VFE_OUTPUTS_RDI1));
+			uint16_t output_mode =
+			axi_ctrl->share_ctrl->comp_output_mode &
+				~(VFE32_OUTPUT_MODE_TERTIARY1|
+				VFE32_OUTPUT_MODE_TERTIARY2);
+			if (!axi_ctrl->share_ctrl->dual_enabled)
+				msm_camera_io_w_mb(
+					CAMIF_COMMAND_STOP_IMMEDIATELY,
+					axi_ctrl->share_ctrl->vfebase +
+					VFE_CAMIF_COMMAND);
+			axi_disable_wm_irq(axi_ctrl->share_ctrl, output_mode);
+			axi_disable_irq(axi_ctrl->share_ctrl, mode);
 			vfe32_send_isp_msg(&axi_ctrl->subdev,
 				axi_ctrl->share_ctrl->vfeFrameId,
-				MSG_ID_SNAPSHOT_DONE);
+				MSG_ID_PIX0_UPDATE_ACK);
+			axi_ctrl->share_ctrl->outpath.out0.
+				capture_cnt = -1;
+			axi_ctrl->share_ctrl->outpath.out1.
+				capture_cnt = -1;
+			axi_ctrl->share_ctrl->comp_output_mode &=
+				(VFE32_OUTPUT_MODE_TERTIARY1|
+				VFE32_OUTPUT_MODE_TERTIARY2);
 		}
 	}
+
+	if (axi_ctrl->share_ctrl->outpath.out2.capture_cnt == 0) {
+		axi_ctrl->share_ctrl->comp_output_mode &=
+				~VFE32_OUTPUT_MODE_TERTIARY1;
+		axi_ctrl->share_ctrl->outpath.out2.capture_cnt = -1;
+	}
+
+	if (axi_ctrl->share_ctrl->outpath.out3.capture_cnt == 0) {
+		axi_ctrl->share_ctrl->comp_output_mode &=
+				~VFE32_OUTPUT_MODE_TERTIARY2;
+		axi_ctrl->share_ctrl->outpath.out3.capture_cnt = -1;
+	}
 }
 
 static int msm_axi_buf_cfg(struct v4l2_subdev *sd, void __user *arg)
@@ -5875,8 +6486,16 @@
 {
 	int rc = -ENOIOCTLCMD;
 	switch (cmd) {
-	case VIDIOC_MSM_AXI_INIT:
-		rc = msm_axi_subdev_init(sd);
+	case VIDIOC_MSM_AXI_INIT: {
+		uint8_t dual_enabled;
+		if (copy_from_user(&dual_enabled,
+				(void __user *)(arg),
+				sizeof(uint8_t))) {
+				rc = -EFAULT;
+				break;
+		}
+		rc = msm_axi_subdev_init(sd, dual_enabled);
+		}
 		break;
 	case VIDIOC_MSM_AXI_CFG:
 		rc = msm_axi_config(sd, arg);
@@ -5893,6 +6512,29 @@
 		msm_axi_subdev_release(sd);
 		rc = 0;
 		break;
+	case VIDIOC_MSM_AXI_RDI_COUNT_UPDATE: {
+		struct rdi_count_msg *msg = (struct rdi_count_msg *)arg;
+		struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd);
+		switch (msg->rdi_interface) {
+		case RDI_0:
+			axi_ctrl->share_ctrl->rdi0FrameId = msg->count;
+			rc = 0;
+			break;
+		case RDI_1:
+			axi_ctrl->share_ctrl->rdi1FrameId = msg->count;
+			rc = 0;
+			break;
+		case RDI_2:
+			axi_ctrl->share_ctrl->rdi2FrameId = msg->count;
+			rc = 0;
+			break;
+		default:
+			pr_err("%s: Incorrect interface sent\n", __func__);
+			rc = -EINVAL;
+			break;
+		}
+		break;
+	}
 	default:
 		pr_err("%s: command %d not found\n", __func__,
 						_IOC_NR(cmd));
@@ -5953,7 +6595,7 @@
 	share_ctrl->vfe32_ctrl = vfe32_ctrl;
 	axi_ctrl->share_ctrl = share_ctrl;
 	vfe32_ctrl->share_ctrl = share_ctrl;
-
+	axi_ctrl->share_ctrl->axi_ref_cnt = 0;
 	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;
@@ -6059,6 +6701,21 @@
 		goto vfe32_no_resource;
 	}
 
+#ifdef CONFIG_MSM_IOMMU
+	/*get device context for IOMMU*/
+	axi_ctrl->iommu_ctx_imgwr =
+		msm_iommu_get_ctx("vfe_imgwr"); /*re-confirm*/
+	axi_ctrl->iommu_ctx_misc =
+		msm_iommu_get_ctx("vfe_misc"); /*re-confirm*/
+	if (!axi_ctrl->iommu_ctx_imgwr || !axi_ctrl->iommu_ctx_misc) {
+		release_mem_region(axi_ctrl->vfemem->start,
+			resource_size(axi_ctrl->vfemem));
+		pr_err("%s: No iommu fw context found\n", __func__);
+		rc = -ENODEV;
+		goto vfe32_no_resource;
+	}
+#endif
+
 	tasklet_init(&axi_ctrl->vfe32_tasklet,
 		axi32_do_tasklet, (unsigned long)axi_ctrl);
 
diff --git a/drivers/media/video/msm/vfe/msm_vfe32.h b/drivers/media/video/msm/vfe/msm_vfe32.h
index f4b7edb..f985221 100644
--- a/drivers/media/video/msm/vfe/msm_vfe32.h
+++ b/drivers/media/video/msm/vfe/msm_vfe32.h
@@ -62,6 +62,12 @@
  * bit 26-32 = 0, domain reset, bit 0-9 = 1 for module reset. */
 #define VFE_RESET_UPON_RESET_CMD  0x000003ff
 
+/* reset the vfe only when reset command*/
+#define VFE_ONLY_RESET_CMD  0x00000002
+
+/*Vfe module reset command*/
+#define VFE_MODULE_RESET_CMD 0x07ffffff
+
 /* bit 5 is for axi status idle or busy.
  * 1 =  halted,  0 = busy */
 #define AXI_STATUS_BUSY_MASK 0x00000020
@@ -244,11 +250,11 @@
 #define V32_OUT_CLAMP_OFF         0x00000524
 #define V32_OUT_CLAMP_LEN         8
 
-#define V32_OPERATION_CFG_LEN     44
+#define V32_OPERATION_CFG_LEN     32
 
 #define V32_AXI_BUS_CMD_OFF       0x00000038
 #define V32_AXI_OUT_OFF           0x0000003C
-#define V32_AXI_OUT_LEN           240
+#define V32_AXI_OUT_LEN           252
 #define V32_AXI_CFG_LEN           47
 #define V32_AXI_BUS_FMT_OFF       1
 #define V32_AXI_BUS_FMT_LEN       4
@@ -776,7 +782,7 @@
 	int8_t ch0;
 	int8_t ch1;
 	int8_t ch2;
-	uint32_t  capture_cnt;
+	int32_t  capture_cnt;
 	uint32_t  frame_drop_cnt;
 	struct msm_free_buf ping;
 	struct msm_free_buf pong;
@@ -787,7 +793,8 @@
 #define VFE32_IMASK_ERROR_ONLY_0  0x0
 /* when normal case, don't want to block error status. */
 /* bit 0-21 are error irq bits */
-#define VFE32_IMASK_ERROR_ONLY_1               0x005FFFFF
+#define VFE32_IMASK_COMMON_ERROR_ONLY_1       0x00407F00
+#define VFE32_IMASK_VFE_ERROR_ONLY_1          0x001F80FF
 #define VFE32_IMASK_CAMIF_ERROR               (0x00000001<<0)
 #define VFE32_IMASK_BHIST_OVWR                (0x00000001<<1)
 #define VFE32_IMASK_STATS_CS_OVWR             (0x00000001<<2)
@@ -941,22 +948,34 @@
 	uint32_t register_total;
 
 	atomic_t vstate;
-	atomic_t handle_axi_irq;
+	atomic_t handle_common_irq;
 	uint32_t vfeFrameId;
+	uint32_t rdi0FrameId;
+	uint32_t rdi1FrameId;
+	uint32_t rdi2FrameId;
 	uint32_t stats_comp;
+	spinlock_t  sd_notify_lock;
 	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;
+	int32_t rdi0_capture_count;
+	int32_t rdi1_capture_count;
+	uint8_t update_counter;
 
 	uint32_t operation_mode;     /* streaming or snapshot */
 	uint32_t current_mode;
 	struct vfe32_output_path outpath;
 
 	uint16_t port_info;
-	uint32_t skip_abort;
-	spinlock_t  sd_notify_lock;
+	uint8_t stop_immediately;
+	uint8_t sync_abort;
+	uint16_t cmd_type;
+	uint8_t vfe_reset_flag;
+	uint8_t dual_enabled;
+
+	uint8_t axi_ref_cnt;
+	uint16_t comp_output_mode;
 
 	struct completion reset_complete;
 
@@ -969,9 +988,11 @@
 	int8_t update_ack_pending;
 	enum vfe_output_state recording_state;
 
+	atomic_t pix0_update_ack_pending;
 	atomic_t rdi0_update_ack_pending;
 	atomic_t rdi1_update_ack_pending;
 	atomic_t rdi2_update_ack_pending;
+
 };
 
 struct axi_ctrl_t {
@@ -989,6 +1010,8 @@
 	struct clk *vfe_clk[3];
 	struct tasklet_struct vfe32_tasklet;
 	struct vfe_share_ctrl_t *share_ctrl;
+	struct device *iommu_ctx_imgwr;
+	struct device *iommu_ctx_misc;
 };
 
 struct vfe32_ctrl_type {
diff --git a/drivers/media/video/msm/vfe/msm_vfe40.c b/drivers/media/video/msm/vfe/msm_vfe40.c
index 5a1d488..e958241 100644
--- a/drivers/media/video/msm/vfe/msm_vfe40.c
+++ b/drivers/media/video/msm/vfe/msm_vfe40.c
@@ -15,226 +15,597 @@
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 #include <linux/io.h>
+#include <linux/of.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 <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
 
 #include "msm.h"
+#include "msm_cam_server.h"
 #include "msm_vfe40.h"
 
+atomic_t irq_cnt;
+
+#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)))
+
+static uint32_t vfe_clk_rate;
+static void vfe40_send_isp_msg(struct v4l2_subdev *sd,
+	uint32_t vfeFrameId, uint32_t isp_msg_id);
+
+
 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 struct vfe40_cmd_type vfe40_cmd[] = {
+	[1] = {VFE_CMD_SET_CLK},
+	[2] = {VFE_CMD_RESET},
+	[3] = {VFE_CMD_START},
+	[4] = {VFE_CMD_TEST_GEN_START},
+	[5] = {VFE_CMD_OPERATION_CFG, V40_OPERATION_CFG_LEN},
+	[6] = {VFE_CMD_AXI_OUT_CFG, V40_AXI_OUT_LEN, V40_AXI_BUS_CMD_OFF, 0xFF},
+	[7] = {VFE_CMD_CAMIF_CFG, V40_CAMIF_LEN, V40_CAMIF_OFF, 0xFF},
+	[8] = {VFE_CMD_AXI_INPUT_CFG},
+	[9] = {VFE_CMD_BLACK_LEVEL_CFG},
+	[10] = {VFE_CMD_MESH_ROLL_OFF_CFG, V40_MESH_ROLL_OFF_CFG_LEN,
+		V40_MESH_ROLL_OFF_CFG_OFF, 0xFF},
+	[11] = {VFE_CMD_DEMUX_CFG, V40_DEMUX_LEN, V40_DEMUX_OFF, 0xFF},
+	[12] = {VFE_CMD_FOV_CFG},
+	[13] = {VFE_CMD_MAIN_SCALER_CFG},
+	[14] = {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},
+	[16] = {VFE_CMD_RGB_G_CFG, V40_RGB_G_LEN, V40_RGB_G_OFF, 0xFF},
+	[17] = {VFE_CMD_LA_CFG, V40_LA_LEN, V40_LA_OFF, 0xFF },
+	[18] = {VFE_CMD_CHROMA_EN_CFG, V40_CHROMA_EN_LEN, V40_CHROMA_EN_OFF,
+		0xFF},
+	[19] = {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},
+	[21] = {VFE_CMD_SK_ENHAN_CFG, V40_SCE_LEN, V40_SCE_OFF, 0xFF},
+	[22] = {VFE_CMD_ASF_CFG, V40_ASF_LEN, V40_ASF_OFF, 0xFF},
+	[23] = {VFE_CMD_S2Y_CFG},
+	[24] = {VFE_CMD_S2CbCr_CFG},
+	[25] = {VFE_CMD_CHROMA_SUBS_CFG},
+	[26] = {VFE_CMD_OUT_CLAMP_CFG, V40_OUT_CLAMP_LEN, V40_OUT_CLAMP_OFF,
+		0xFF},
+	[27] = {VFE_CMD_FRAME_SKIP_CFG},
+	[31] = {VFE_CMD_UPDATE},
+	[32] = {VFE_CMD_BL_LVL_UPDATE},
+	[33] = {VFE_CMD_DEMUX_UPDATE, V40_DEMUX_LEN, V40_DEMUX_OFF, 0xFF},
+	[34] = {VFE_CMD_FOV_UPDATE},
+	[35] = {VFE_CMD_MAIN_SCALER_UPDATE},
+	[36] = {VFE_CMD_WB_UPDATE, V40_WB_LEN, V40_WB_OFF, 0xFF},
+	[37] = {VFE_CMD_COLOR_COR_UPDATE, V40_COLOR_COR_LEN,
+		V40_COLOR_COR_OFF, 0xFF},
+	[38] = {VFE_CMD_RGB_G_UPDATE, V40_RGB_G_LEN, V40_CHROMA_EN_OFF, 0xFF},
+	[39] = {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},
+	[41] = {VFE_CMD_CHROMA_SUP_UPDATE, V40_CHROMA_SUP_LEN,
+		V40_CHROMA_SUP_OFF, 0xFF},
+	[42] = {VFE_CMD_MCE_UPDATE, V40_MCE_LEN, V40_MCE_OFF, 0xFF},
+	[43] = {VFE_CMD_SK_ENHAN_UPDATE, V40_SCE_LEN, V40_SCE_OFF, 0xFF},
+	[44] = {VFE_CMD_S2CbCr_UPDATE},
+	[45] = {VFE_CMD_S2Y_UPDATE},
+	[46] = {VFE_CMD_ASF_UPDATE, V40_ASF_UPDATE_LEN, V40_ASF_OFF, 0xFF},
+	[47] = {VFE_CMD_FRAME_SKIP_UPDATE},
+	[48] = {VFE_CMD_CAMIF_FRAME_UPDATE},
+	[49] = {VFE_CMD_STATS_AF_UPDATE},
+	[50] = {VFE_CMD_STATS_AE_UPDATE},
+	[51] = {VFE_CMD_STATS_AWB_UPDATE, V40_STATS_AWB_LEN,
+		V40_STATS_AWB_OFF},
+	[52] = {VFE_CMD_STATS_RS_UPDATE, V40_STATS_RS_LEN, V40_STATS_RS_OFF},
+	[53] = {VFE_CMD_STATS_CS_UPDATE, V40_STATS_CS_LEN, V40_STATS_CS_OFF},
+	[54] = {VFE_CMD_STATS_SKIN_UPDATE},
+	[55] = {VFE_CMD_STATS_IHIST_UPDATE, V40_STATS_IHIST_LEN,
+		V40_STATS_IHIST_OFF},
+	[57] = {VFE_CMD_EPOCH1_ACK},
+	[58] = {VFE_CMD_EPOCH2_ACK},
+	[59] = {VFE_CMD_START_RECORDING},
+	[60] = {VFE_CMD_STOP_RECORDING},
+	[63] = {VFE_CMD_CAPTURE, V40_CAPTURE_LEN, 0xFF},
+	[65] = {VFE_CMD_STOP},
+	[66] = {VFE_CMD_GET_HW_VERSION, V40_GET_HW_VERSION_LEN,
+		V40_GET_HW_VERSION_OFF},
+	[67] = {VFE_CMD_GET_FRAME_SKIP_COUNTS},
+	[68] = {VFE_CMD_OUTPUT1_BUFFER_ENQ},
+	[69] = {VFE_CMD_OUTPUT2_BUFFER_ENQ},
+	[70] = {VFE_CMD_OUTPUT3_BUFFER_ENQ},
+	[71] = {VFE_CMD_JPEG_OUT_BUF_ENQ},
+	[72] = {VFE_CMD_RAW_OUT_BUF_ENQ},
+	[73] = {VFE_CMD_RAW_IN_BUF_ENQ},
+	[74] = {VFE_CMD_STATS_AF_ENQ},
+	[75] = {VFE_CMD_STATS_AE_ENQ},
+	[76] = {VFE_CMD_STATS_AWB_ENQ},
+	[77] = {VFE_CMD_STATS_RS_ENQ},
+	[78] = {VFE_CMD_STATS_CS_ENQ},
+	[79] = {VFE_CMD_STATS_SKIN_ENQ},
+	[80] = {VFE_CMD_STATS_IHIST_ENQ},
+	[82] = {VFE_CMD_JPEG_ENC_CFG},
+	[84] = {VFE_CMD_STATS_AF_START},
+	[85] = {VFE_CMD_STATS_AF_STOP},
+	[86] = {VFE_CMD_STATS_AE_START},
+	[87] = {VFE_CMD_STATS_AE_STOP},
+	[88] = {VFE_CMD_STATS_AWB_START, V40_STATS_AWB_LEN, V40_STATS_AWB_OFF},
+	[89] = {VFE_CMD_STATS_AWB_STOP},
+	[90] = {VFE_CMD_STATS_RS_START, V40_STATS_RS_LEN, V40_STATS_RS_OFF},
+	[91] = {VFE_CMD_STATS_RS_STOP},
+	[92] = {VFE_CMD_STATS_CS_START, V40_STATS_CS_LEN, V40_STATS_CS_OFF},
+	[93] = {VFE_CMD_STATS_CS_STOP},
+	[94] = {VFE_CMD_STATS_SKIN_START},
+	[95] = {VFE_CMD_STATS_SKIN_STOP},
+	[96] = {VFE_CMD_STATS_IHIST_START,
+		V40_STATS_IHIST_LEN, V40_STATS_IHIST_OFF},
+	[97] = {VFE_CMD_STATS_IHIST_STOP},
+	[99] = {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},
+	[101] = {VFE_CMD_LIVESHOT},
+	[102] = {VFE_CMD_LA_SETUP},
+	[103] = {VFE_CMD_LINEARIZATION_CFG, V40_LINEARIZATION_LEN1,
+			V40_LINEARIZATION_OFF1},
+	[104] = {VFE_CMD_DEMOSAICV3},
+	[105] = {VFE_CMD_DEMOSAICV3_ABCC_CFG},
+	[106] = {VFE_CMD_DEMOSAICV3_DBCC_CFG, V40_DEMOSAICV3_DBCC_LEN,
+			V40_DEMOSAICV3_DBCC_OFF},
+	[107] = {VFE_CMD_DEMOSAICV3_DBPC_CFG},
+	[108] = {VFE_CMD_DEMOSAICV3_ABF_CFG, V40_DEMOSAICV3_ABF_LEN,
+			V40_DEMOSAICV3_ABF_OFF},
+	[109] = {VFE_CMD_DEMOSAICV3_ABCC_UPDATE},
+	[110] = {VFE_CMD_DEMOSAICV3_DBCC_UPDATE, V40_DEMOSAICV3_DBCC_LEN,
+			V40_DEMOSAICV3_DBCC_OFF},
+	[111] = {VFE_CMD_DEMOSAICV3_DBPC_UPDATE},
+	[112] = {VFE_CMD_XBAR_CFG},
+	[113] = {VFE_CMD_MODULE_CFG, V40_MODULE_CFG_LEN, V40_MODULE_CFG_OFF},
+	[114] = {VFE_CMD_ZSL},
+	[115] = {VFE_CMD_LINEARIZATION_UPDATE, V40_LINEARIZATION_LEN1,
+			V40_LINEARIZATION_OFF1},
+	[116] = {VFE_CMD_DEMOSAICV3_ABF_UPDATE, V40_DEMOSAICV3_ABF_LEN,
+			V40_DEMOSAICV3_ABF_OFF},
+	[117] = {VFE_CMD_CLF_CFG, V40_CLF_CFG_LEN, V40_CLF_CFG_OFF},
+	[118] = {VFE_CMD_CLF_LUMA_UPDATE, V40_CLF_LUMA_UPDATE_LEN,
+			V40_CLF_LUMA_UPDATE_OFF},
+	[119] = {VFE_CMD_CLF_CHROMA_UPDATE, V40_CLF_CHROMA_UPDATE_LEN,
+			V40_CLF_CHROMA_UPDATE_OFF},
+	[120] = {VFE_CMD_PCA_ROLL_OFF_CFG},
+	[121] = {VFE_CMD_PCA_ROLL_OFF_UPDATE},
+	[122] = {VFE_CMD_GET_REG_DUMP},
+	[123] = {VFE_CMD_GET_LINEARIZATON_TABLE},
+	[124] = {VFE_CMD_GET_MESH_ROLLOFF_TABLE},
+	[125] = {VFE_CMD_GET_PCA_ROLLOFF_TABLE},
+	[126] = {VFE_CMD_GET_RGB_G_TABLE},
+	[127] = {VFE_CMD_GET_LA_TABLE},
+	[128] = {VFE_CMD_DEMOSAICV3_UPDATE},
+	[129] = {VFE_CMD_ACTIVE_REGION_CFG},
+	[130] = {VFE_CMD_COLOR_PROCESSING_CONFIG},
+	[131] = {VFE_CMD_STATS_WB_AEC_CONFIG},
+	[132] = {VFE_CMD_STATS_WB_AEC_UPDATE},
+	[133] = {VFE_CMD_Y_GAMMA_CONFIG},
+	[134] = {VFE_CMD_SCALE_OUTPUT1_CONFIG},
+	[135] = {VFE_CMD_SCALE_OUTPUT2_CONFIG},
+	[136] = {VFE_CMD_CAPTURE_RAW},
+	[137] = {VFE_CMD_STOP_LIVESHOT},
+	[138] = {VFE_CMD_RECONFIG_VFE},
+	[139] = {VFE_CMD_STATS_REQBUF},
+	[140] = {VFE_CMD_STATS_ENQUEUEBUF},
+	[141] = {VFE_CMD_STATS_FLUSH_BUFQ},
+	[142] = {VFE_CMD_STATS_UNREGBUF},
+	[143] = {VFE_CMD_STATS_BG_START, V40_STATS_BG_LEN, V40_STATS_BG_OFF},
+	[144] = {VFE_CMD_STATS_BG_STOP},
+	[145] = {VFE_CMD_STATS_BF_START, V40_STATS_BF_LEN, V40_STATS_BF_OFF},
+	[146] = {VFE_CMD_STATS_BF_STOP},
+	[147] = {VFE_CMD_STATS_BHIST_START, V40_STATS_BHIST_LEN,
+			V40_STATS_BHIST_OFF},
+	[148] = {VFE_CMD_STATS_BHIST_STOP},
+	[149] = {VFE_CMD_RESET_2},
+	[150] = {VFE_CMD_FOV_ENC_CFG, V40_FOV_ENC_LEN,
+		V40_FOV_ENC_OFF, 0xFF},
+	[151] = {VFE_CMD_FOV_VIEW_CFG, V40_FOV_VIEW_LEN,
+		V40_FOV_VIEW_OFF, 0xFF},
+	[152] = {VFE_CMD_FOV_ENC_UPDATE, V40_FOV_ENC_LEN,
+		V40_FOV_ENC_OFF, 0xFF},
+	[153] = {VFE_CMD_FOV_VIEW_UPDATE, V40_FOV_VIEW_LEN,
+		V40_FOV_VIEW_OFF, 0xFF},
+	[154] = {VFE_CMD_SCALER_ENC_CFG, V40_SCALER_ENC_LEN,
+		V40_SCALER_ENC_OFF, 0xFF},
+	[155] = {VFE_CMD_SCALER_VIEW_CFG, V40_SCALER_VIEW_LEN,
+		V40_SCALER_VIEW_OFF, 0xFF},
+	[156] = {VFE_CMD_SCALER_ENC_UPDATE, V40_SCALER_ENC_LEN,
+		V40_SCALER_ENC_OFF, 0xFF},
+	[157] = {VFE_CMD_SCALER_VIEW_UPDATE, V40_SCALER_VIEW_LEN,
+		V40_SCALER_VIEW_OFF, 0xFF},
+	[158] = {VFE_CMD_COLORXFORM_ENC_CFG, V40_COLORXFORM_ENC_CFG_LEN,
+		V40_COLORXFORM_ENC_CFG_OFF, 0xFF},
+	[159] = {VFE_CMD_COLORXFORM_VIEW_CFG, V40_COLORXFORM_VIEW_CFG_LEN,
+		V40_COLORXFORM_VIEW_CFG_OFF},
+	[160] = {VFE_CMD_COLORXFORM_ENC_UPDATE, V40_COLORXFORM_ENC_CFG_LEN,
+		V40_COLORXFORM_ENC_CFG_OFF, 0xFF},
+	[161] = {VFE_CMD_COLORXFORM_VIEW_UPDATE, V40_COLORXFORM_VIEW_CFG_LEN,
+		V40_COLORXFORM_VIEW_CFG_OFF, 0xFF},
 };
 
-static void vfe40_stop(struct vfe40_ctrl_type *vfe40_ctrl)
+static const uint32_t vfe40_AXI_WM_CFG[] = {
+	0x0000006C,
+	0x00000090,
+	0x000000B4,
+	0x000000D8,
+	0x000000FC,
+	0x00000120,
+	0x00000144,
+};
+
+static const char * const vfe40_general_cmd[] = {
+	[1] = "SET_CLK",
+	[2] = "RESET",
+	[3] = "START",
+	[4] = "TEST_GEN_START",
+	[5] = "OPERATION_CFG",  /* 5 */
+	[6] = "AXI_OUT_CFG",
+	[7] = "CAMIF_CFG",
+	[8] = "AXI_INPUT_CFG",
+	[9] = "BLACK_LEVEL_CFG",
+	[10] = "ROLL_OFF_CFG",  /* 10 */
+	[11] = "DEMUX_CFG",
+	[12] = "FOV_CFG",
+	[13] = "MAIN_SCALER_CFG",
+	[14] = "WB_CFG",
+	[15] = "COLOR_COR_CFG", /* 15 */
+	[16] = "RGB_G_CFG",
+	[17] = "LA_CFG",
+	[18] = "CHROMA_EN_CFG",
+	[19] = "CHROMA_SUP_CFG",
+	[20] = "MCE_CFG", /* 20 */
+	[21] = "SK_ENHAN_CFG",
+	[22] = "ASF_CFG",
+	[23] = "S2Y_CFG",
+	[24] = "S2CbCr_CFG",
+	[25] = "CHROMA_SUBS_CFG",  /* 25 */
+	[26] = "OUT_CLAMP_CFG",
+	[27] = "FRAME_SKIP_CFG",
+	[31] = "UPDATE",
+	[32] = "BL_LVL_UPDATE",
+	[33] = "DEMUX_UPDATE",
+	[34] = "FOV_UPDATE",
+	[35] = "MAIN_SCALER_UPDATE",  /* 35 */
+	[36] = "WB_UPDATE",
+	[37] = "COLOR_COR_UPDATE",
+	[38] = "RGB_G_UPDATE",
+	[39] = "LA_UPDATE",
+	[40] = "CHROMA_EN_UPDATE",  /* 40 */
+	[41] = "CHROMA_SUP_UPDATE",
+	[42] = "MCE_UPDATE",
+	[43] = "SK_ENHAN_UPDATE",
+	[44] = "S2CbCr_UPDATE",
+	[45] = "S2Y_UPDATE",  /* 45 */
+	[46] = "ASF_UPDATE",
+	[47] = "FRAME_SKIP_UPDATE",
+	[48] = "CAMIF_FRAME_UPDATE",
+	[49] = "STATS_AF_UPDATE",
+	[50] = "STATS_AE_UPDATE",  /* 50 */
+	[51] = "STATS_AWB_UPDATE",
+	[52] = "STATS_RS_UPDATE",
+	[53] = "STATS_CS_UPDATE",
+	[54] = "STATS_SKIN_UPDATE",
+	[55] = "STATS_IHIST_UPDATE",  /* 55 */
+	[57] = "EPOCH1_ACK",
+	[58] = "EPOCH2_ACK",
+	[59] = "START_RECORDING",
+	[60] = "STOP_RECORDING",  /* 60 */
+	[63] = "CAPTURE",
+	[65] = "STOP",  /* 65 */
+	[66] = "GET_HW_VERSION",
+	[67] = "GET_FRAME_SKIP_COUNTS",
+	[68] = "OUTPUT1_BUFFER_ENQ",
+	[69] = "OUTPUT2_BUFFER_ENQ",
+	[70] = "OUTPUT3_BUFFER_ENQ",  /* 70 */
+	[71] = "JPEG_OUT_BUF_ENQ",
+	[72] = "RAW_OUT_BUF_ENQ",
+	[73] = "RAW_IN_BUF_ENQ",
+	[74] = "STATS_AF_ENQ",
+	[75] = "STATS_AE_ENQ",  /* 75 */
+	[76] = "STATS_AWB_ENQ",
+	[77] = "STATS_RS_ENQ",
+	[78] = "STATS_CS_ENQ",
+	[79] = "STATS_SKIN_ENQ",
+	[80] = "STATS_IHIST_ENQ",  /* 80 */
+	[82] = "JPEG_ENC_CFG",
+	[84] = "STATS_AF_START",
+	[85] = "STATS_AF_STOP",  /* 85 */
+	[86] = "STATS_AE_START",
+	[87] = "STATS_AE_STOP",
+	[88] = "STATS_AWB_START",
+	[89] = "STATS_AWB_STOP",
+	[90] = "STATS_RS_START",  /* 90 */
+	[91] = "STATS_RS_STOP",
+	[92] = "STATS_CS_START",
+	[93] = "STATS_CS_STOP",
+	[94] = "STATS_SKIN_START",
+	[95] = "STATS_SKIN_STOP",  /* 95 */
+	[96] = "STATS_IHIST_START",
+	[97] = "STATS_IHIST_STOP",
+	[99] = "SYNC_TIMER_SETTING",
+	[100] = "ASYNC_TIMER_SETTING",  /* 100 */
+	[101] = "LIVESHOT",
+	[102] = "LA_SETUP",
+	[103] = "LINEARIZATION_CFG",
+	[104] = "DEMOSAICV3",
+	[105] = "DEMOSAICV3_ABCC_CFG", /* 105 */
+	[106] = "DEMOSAICV3_DBCC_CFG",
+	[107] = "DEMOSAICV3_DBPC_CFG",
+	[108] = "DEMOSAICV3_ABF_CFG",
+	[109] = "DEMOSAICV3_ABCC_UPDATE",
+	[110] = "DEMOSAICV3_DBCC_UPDATE", /* 110 */
+	[111] = "DEMOSAICV3_DBPC_UPDATE",
+	[112] = "XBAR_CFG",
+	[113] = "EZTUNE_CFG",
+	[114] = "V40_ZSL",
+	[115] = "LINEARIZATION_UPDATE", /*115*/
+	[116] = "DEMOSAICV3_ABF_UPDATE",
+	[117] = "CLF_CFG",
+	[118] = "CLF_LUMA_UPDATE",
+	[119] = "CLF_CHROMA_UPDATE",
+	[120] = "PCA_ROLL_OFF_CFG", /*120*/
+	[121] = "PCA_ROLL_OFF_UPDATE",
+	[122] = "GET_REG_DUMP",
+	[123] = "GET_LINEARIZATON_TABLE",
+	[124] = "GET_MESH_ROLLOFF_TABLE",
+	[125] = "GET_PCA_ROLLOFF_TABLE", /*125*/
+	[126] = "GET_RGB_G_TABLE",
+	[127] = "GET_LA_TABLE",
+	[128] = "DEMOSAICV3_UPDATE",
+	[139] = "STATS_REQBUF",
+	[140] = "STATS_ENQUEUEBUF", /*140*/
+	[141] = "STATS_FLUSH_BUFQ",
+	[142] = "STATS_UNREGBUF",
+	[143] = "STATS_BG_START",
+	[144] = "STATS_BG_STOP",
+	[145] = "STATS_BF_START", /*145*/
+	[146] = "STATS_BF_STOP",
+	[147] = "STATS_BHIST_START",
+	[148] = "STATS_BHIST_STOP",
+	[149] = "RESET_2",
+};
+
+/*Temporary use fixed bus vectors in VFE */
+static struct msm_bus_vectors vfe_init_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+};
+
+static struct msm_bus_vectors vfe_preview_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 27648000,
+		.ib  = 110592000,
+	},
+};
+
+static struct msm_bus_vectors vfe_video_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 154275840,
+		.ib  = 617103360,
+	},
+};
+
+static struct msm_bus_vectors vfe_snapshot_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 274423680,
+		.ib  = 1097694720,
+	},
+};
+
+static struct msm_bus_vectors vfe_zsl_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 302071680,
+		.ib  = 1208286720,
+	},
+};
+
+static struct msm_bus_paths vfe_bus_client_config[] = {
+	{
+		ARRAY_SIZE(vfe_init_vectors),
+		vfe_init_vectors,
+	},
+	{
+		ARRAY_SIZE(vfe_preview_vectors),
+		vfe_preview_vectors,
+	},
+	{
+		ARRAY_SIZE(vfe_video_vectors),
+		vfe_video_vectors,
+	},
+	{
+		ARRAY_SIZE(vfe_snapshot_vectors),
+		vfe_snapshot_vectors,
+	},
+	{
+		ARRAY_SIZE(vfe_zsl_vectors),
+		vfe_zsl_vectors,
+	},
+};
+
+static struct msm_bus_scale_pdata vfe_bus_client_pdata = {
+		vfe_bus_client_config,
+		ARRAY_SIZE(vfe_bus_client_config),
+		.name = "msm_camera_vfe",
+};
+
+uint8_t vfe40_use_bayer_stats(struct vfe40_ctrl_type *vfe40_ctrl)
 {
-	unsigned long flags;
+	if (vfe40_ctrl->ver_num.main >= 4) {
+		/* VFE 4 or above uses bayer stats */
+		return TRUE;
+	} else {
+		return FALSE;
+	}
+}
 
-	atomic_set(&vfe40_ctrl->share_ctrl->vstate, 0);
+static void axi_enable_irq(struct vfe_share_ctrl_t *share_ctrl)
+{
+	uint32_t irq_mask;
+	uint16_t vfe_operation_mode =
+		share_ctrl->current_mode & ~(VFE_OUTPUTS_RDI0|
+			VFE_OUTPUTS_RDI1);
+	irq_mask =
+		msm_camera_io_r(share_ctrl->vfebase +
+			VFE_IRQ_MASK_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);
+	irq_mask |= VFE_IMASK_WHILE_STOPPING_0;
+
+	if (share_ctrl->current_mode & VFE_OUTPUTS_RDI0)
+		irq_mask |= VFE_IRQ_STATUS0_RDI0_REG_UPDATE_MASK;
+
+	if (share_ctrl->current_mode & VFE_OUTPUTS_RDI1)
+		irq_mask |= VFE_IRQ_STATUS0_RDI1_REG_UPDATE_MASK;
+
+	msm_camera_io_w(irq_mask, share_ctrl->vfebase +
+		VFE_IRQ_MASK_0);
+
+	if (vfe_operation_mode) {
+		irq_mask =
+		msm_camera_io_r(share_ctrl->vfebase +
+			VFE_IRQ_MASK_0);
+		irq_mask |= 0x00000021;
+		if (share_ctrl->stats_comp)
+			irq_mask |= VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK_0;
+		else
+			irq_mask |= 0x00FF0000;
+		msm_camera_io_w(irq_mask, share_ctrl->vfebase +
+			VFE_IRQ_MASK_0);
+		atomic_set(&share_ctrl->vstate, 1);
+	}
+	atomic_set(&share_ctrl->handle_common_irq, 1);
+}
+
+static void axi_disable_irq(struct vfe_share_ctrl_t *share_ctrl)
+{
 
 	/* disable all interrupts.  */
+
+	uint32_t irq_mask = 0;
+	uint16_t vfe_operation_mode =
+		share_ctrl->current_mode & ~(VFE_OUTPUTS_RDI0|
+			VFE_OUTPUTS_RDI1);
+
+	if (share_ctrl->current_mode & VFE_OUTPUTS_RDI0) {
+		irq_mask =
+		msm_camera_io_r(share_ctrl->vfebase +
+			VFE_IRQ_MASK_0);
+		irq_mask &= ~(VFE_IRQ_STATUS0_RDI0_REG_UPDATE_MASK);
+		msm_camera_io_w(irq_mask, share_ctrl->vfebase +
+			VFE_IRQ_MASK_0);
+		msm_camera_io_w(VFE_IRQ_STATUS0_RDI0_REG_UPDATE_MASK,
+			share_ctrl->vfebase + VFE_IRQ_CLEAR_0);
+	}
+	if (share_ctrl->current_mode & VFE_OUTPUTS_RDI1) {
+		irq_mask =
+		msm_camera_io_r(share_ctrl->vfebase +
+			VFE_IRQ_MASK_0);
+		irq_mask &= ~(VFE_IRQ_STATUS0_RDI1_REG_UPDATE_MASK);
+		msm_camera_io_w(irq_mask, share_ctrl->vfebase +
+			VFE_IRQ_MASK_0);
+		msm_camera_io_w(VFE_IRQ_STATUS0_RDI1_REG_UPDATE_MASK,
+			share_ctrl->vfebase + VFE_IRQ_CLEAR_0);
+	}
+	if (vfe_operation_mode) {
+		atomic_set(&share_ctrl->vstate, 0);
+		irq_mask =
+		msm_camera_io_r(share_ctrl->vfebase +
+			VFE_IRQ_MASK_0);
+		irq_mask &= ~(0x00000011);
+		if (share_ctrl->stats_comp)
+			irq_mask &= ~(VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK_0);
+		else
+			irq_mask &= ~0x00FF0000;
+		msm_camera_io_w(irq_mask, share_ctrl->vfebase +
+			VFE_IRQ_MASK_0);
+	}
+
+	if (share_ctrl->axi_ref_cnt == 1) {
+		atomic_set(&share_ctrl->handle_common_irq, 0);
 	msm_camera_io_w(VFE_DISABLE_ALL_IRQS,
-		vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_0);
+		share_ctrl->vfebase + VFE_IRQ_MASK_0);
 	msm_camera_io_w(VFE_DISABLE_ALL_IRQS,
-			vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
+		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);
+	msm_camera_io_w(0xFFFFFFFF,
+		share_ctrl->vfebase + VFE_IRQ_CLEAR_0);
+	msm_camera_io_w(0xFFFFFFFF,
+		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);
+		share_ctrl->vfebase + VFE_IRQ_CMD);
+	}
+}
+
+static void vfe40_stop(struct vfe40_ctrl_type *vfe40_ctrl)
+{
 
 	/* 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);
+	vfe40_ctrl->share_ctrl->operation_mode &=
+		~(vfe40_ctrl->share_ctrl->current_mode);
+	vfe40_ctrl->share_ctrl->current_mode = 0;
 }
 
-void vfe40_subdev_notify(int id, int path, int image_mode,
+static void vfe40_subdev_notify(int id, int path, uint32_t inst_handle,
 	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);
+	CDBG("vfe40_subdev_notify : msgId = %d\n", id);
 	memset(&rp, 0, sizeof(struct msm_vfe_resp));
 	rp.evt_msg.type   = MSM_CAMERA_MSG;
-	frame_info.image_mode = image_mode;
+	frame_info.inst_handle = inst_handle;
 	frame_info.path = path;
 	rp.evt_msg.data = &frame_info;
 	rp.type	   = id;
@@ -242,45 +613,249 @@
 	spin_unlock_irqrestore(&share_ctrl->sd_notify_lock, flags);
 }
 
+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;
+	int vfe_mode = (mode & ~(OUTPUT_TERT1|OUTPUT_TERT2));
+
+	/* 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.inst_handle = *ch_info++;
+
+	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.inst_handle = *ch_info++;
+
+	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++;
+	axi_ctrl->share_ctrl->outpath.out2.inst_handle = *ch_info++;
+
+	axi_ctrl->share_ctrl->outpath.out3.ch0 = 0x0000FFFF & *ch_info;
+	axi_ctrl->share_ctrl->outpath.out3.ch1 =
+		0x0000FFFF & (*ch_info++ >> 16);
+	axi_ctrl->share_ctrl->outpath.out3.ch2 = 0x0000FFFF & *ch_info++;
+	axi_ctrl->share_ctrl->outpath.out3.inst_handle = *ch_info++;
+
+	axi_ctrl->share_ctrl->outpath.output_mode = 0;
+
+	if (mode & OUTPUT_TERT1)
+		axi_ctrl->share_ctrl->outpath.output_mode |=
+			VFE40_OUTPUT_MODE_TERTIARY1;
+	if (mode & OUTPUT_TERT2)
+		axi_ctrl->share_ctrl->outpath.output_mode |=
+			VFE40_OUTPUT_MODE_TERTIARY2;
+	if (mode == OUTPUT_TERT1 || mode == OUTPUT_TERT1
+		|| mode == (OUTPUT_TERT1|OUTPUT_TERT2))
+			goto bus_cfg;
+
+	switch (vfe_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;
+	}
+
+bus_cfg:
+	msm_camera_io_memcpy(axi_ctrl->share_ctrl->vfebase +
+		vfe40_cmd[VFE_CMD_AXI_OUT_CFG].offset, axi_cfg,
+		V40_AXI_BUS_CFG_LEN);
+	msm_camera_io_w(*ch_info++,
+		axi_ctrl->share_ctrl->vfebase + VFE_RDI0_CFG);
+	msm_camera_io_w(*ch_info++,
+		axi_ctrl->share_ctrl->vfebase + VFE_RDI1_CFG);
+	msm_camera_io_w(*ch_info++,
+		axi_ctrl->share_ctrl->vfebase + VFE_RDI2_CFG);
+	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);
+
+	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->handle_common_irq, 0);
+	atomic_set(&axi_ctrl->share_ctrl->pix0_update_ack_pending, 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->comp_output_mode = 0;
+	axi_ctrl->share_ctrl->vfe_capture_count = 0;
+
+	/* this is unsigned 32 bit integer. */
+	axi_ctrl->share_ctrl->vfeFrameId = 0;
+	axi_ctrl->share_ctrl->rdi0FrameId = 0;
+	axi_ctrl->share_ctrl->rdi1FrameId = 0;
+	axi_ctrl->share_ctrl->rdi2FrameId = 0;
+}
+
+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_reset_dmi_tables(
+	struct vfe40_ctrl_type *vfe40_ctrl)
+{
+	int i = 0;
+
+	/* Reset Histogram LUTs */
+	CDBG("Reset Bayer histogram LUT : 0\n");
+	vfe40_program_dmi_cfg(STATS_BHIST_RAM0, vfe40_ctrl);
+	/* Loop for configuring LUT */
+	for (i = 0; i < 256; i++) {
+		msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase +
+			VFE_DMI_DATA_HI);
+		msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase +
+			VFE_DMI_DATA_LO);
+	}
+	vfe40_program_dmi_cfg(NO_MEM_SELECTED, vfe40_ctrl);
+
+	CDBG("Reset Bayer Histogram LUT: 1\n");
+	vfe40_program_dmi_cfg(STATS_BHIST_RAM1, vfe40_ctrl);
+	/* Loop for configuring LUT */
+	for (i = 0; i < 256; i++) {
+		msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase +
+			VFE_DMI_DATA_HI);
+		msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase +
+			VFE_DMI_DATA_LO);
+	}
+	vfe40_program_dmi_cfg(NO_MEM_SELECTED, vfe40_ctrl);
+
+	CDBG("Reset IHistogram LUT\n");
+	vfe40_program_dmi_cfg(STATS_IHIST_RAM, vfe40_ctrl);
+	/* Loop for configuring LUT */
+	for (i = 0; i < 256; i++) {
+		msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase +
+			VFE_DMI_DATA_HI);
+		msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase +
+			VFE_DMI_DATA_LO);
+	}
+	vfe40_program_dmi_cfg(NO_MEM_SELECTED, vfe40_ctrl);
+}
+
+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);
+	msm_camera_io_w(0x198FFFFF,
+		vfe40_ctrl->share_ctrl->vfebase + VFE_CGC_OVERRIDE);
+
+	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 */
+	CDBG("%s: Use bayer stats = %d\n", __func__,
+		 vfe40_use_bayer_stats(vfe40_ctrl));
+	msm_camera_io_w(0x350001F,
+	vfe40_ctrl->share_ctrl->vfebase +
+			VFE_BUS_STATS_HIST_WR_UB_CFG);
+	msm_camera_io_w(0x370002F,
+		vfe40_ctrl->share_ctrl->vfebase +
+			VFE_BUS_STATS_BG_WR_UB_CFG);
+	msm_camera_io_w(0x3A0002F,
+		vfe40_ctrl->share_ctrl->vfebase +
+			VFE_BUS_STATS_BF_WR_UB_CFG);
+	msm_camera_io_w(0x3D00007,
+		vfe40_ctrl->share_ctrl->vfebase +
+			VFE_BUS_STATS_RS_WR_UB_CFG);
+	msm_camera_io_w(0x3D8001F,
+		vfe40_ctrl->share_ctrl->vfebase +
+			VFE_BUS_STATS_CS_WR_UB_CFG);
+	msm_camera_io_w(0x3F80007,
+		vfe40_ctrl->share_ctrl->vfebase +
+			VFE_BUS_STATS_SKIN_WR_UB_CFG);
+	vfe40_reset_dmi_tables(vfe40_ctrl);
+}
+
 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,
+	memset(&(vfe40_ctrl->afbfStatsControl), 0,
 		sizeof(struct vfe_stats_control));
 
 	memset(&(vfe40_ctrl->awbStatsControl), 0,
 		sizeof(struct vfe_stats_control));
 
-	memset(&(vfe40_ctrl->aecStatsControl), 0,
+	memset(&(vfe40_ctrl->aecbgStatsControl), 0,
+		sizeof(struct vfe_stats_control));
+
+	memset(&(vfe40_ctrl->bhistStatsControl), 0,
 		sizeof(struct vfe_stats_control));
 
 	memset(&(vfe40_ctrl->ihistStatsControl), 0,
@@ -295,32 +870,59 @@
 	vfe40_ctrl->frame_skip_cnt = 31;
 	vfe40_ctrl->frame_skip_pattern = 0xffffffff;
 	vfe40_ctrl->snapshot_frame_cnt = 0;
+	vfe40_set_default_reg_values(vfe40_ctrl);
 }
 
-static void vfe40_reset(struct vfe40_ctrl_type *vfe40_ctrl)
+static int vfe40_reset(struct vfe40_ctrl_type *vfe40_ctrl)
 {
-	vfe40_reset_internal_variables(vfe40_ctrl);
+	uint32_t irq_mask;
+	atomic_set(&vfe40_ctrl->share_ctrl->vstate, 0);
+	msm_camera_io_w(VFE_MODULE_RESET_CMD,
+		vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_RESET);
+	msm_camera_io_w(0,
+		vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_RESET);
+
+	irq_mask =
+		msm_camera_io_r(vfe40_ctrl->share_ctrl->vfebase +
+			VFE_IRQ_MASK_0);
+	irq_mask &= ~(0x00FF0011|VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK_0);
+
+	/* enable reset_ack interrupt.  */
+	irq_mask |= VFE_IMASK_WHILE_STOPPING_0;
+	msm_camera_io_w(irq_mask, vfe40_ctrl->share_ctrl->vfebase +
+		VFE_IRQ_MASK_0);
+
+	msm_camera_io_w_mb(VFE_ONLY_RESET_CMD,
+		vfe40_ctrl->share_ctrl->vfebase + VFE_GLOBAL_RESET);
+
+	return wait_for_completion_interruptible(
+			&vfe40_ctrl->share_ctrl->reset_complete);
+}
+
+static int axi_reset(struct axi_ctrl_t *axi_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,
-		vfe40_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,
-		vfe40_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,
-		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);
+	msm_camera_io_w(VFE_CLEAR_ALL_IRQ0,
+		axi_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_0);
+	msm_camera_io_w(VFE_CLEAR_ALL_IRQ1,
+		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, vfe40_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,
-	vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
+	msm_camera_io_w(VFE_IMASK_WHILE_STOPPING_0,
+		axi_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_0);
 
 	/* Write to VFE_GLOBAL_RESET_CMD to reset the vfe hardware. Once reset
 	 * is done, hardware interrupt will be generated.  VFE ist processes
@@ -330,24 +932,10 @@
 	/* 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);
+		axi_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);
+	return wait_for_completion_interruptible(
+			&axi_ctrl->share_ctrl->reset_complete);
 }
 
 static int vfe40_operation_config(uint32_t *cmd,
@@ -355,7 +943,6 @@
 {
 	uint32_t *p = cmd;
 
-	vfe40_ctrl->share_ctrl->operation_mode = *p;
 	vfe40_ctrl->share_ctrl->stats_comp = *(++p);
 	vfe40_ctrl->hfr_mode = *(++p);
 
@@ -364,19 +951,6 @@
 	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);
@@ -428,7 +1002,7 @@
 		stats_buf = &bufq->bufs[i];
 		rc = vfe40_ctrl->stats_ops.enqueue_buf(
 				vfe40_ctrl->stats_ops.stats_ctrl,
-				&(stats_buf->info), NULL);
+				&(stats_buf->info), NULL, -1);
 		if (rc < 0) {
 			pr_err("%s: dq stats buf (type = %d) err = %d",
 				 __func__, stats_type, rc);
@@ -438,6 +1012,26 @@
 	return 0L;
 }
 
+
+static unsigned long vfe40_stats_unregbuf(
+	struct vfe40_ctrl_type *vfe40_ctrl,
+	struct msm_stats_reqbuf *req_buf, int domain_num)
+{
+	int i = 0, rc = 0;
+
+	for (i = 0; i < req_buf->num_buf; i++) {
+		rc = vfe40_ctrl->stats_ops.buf_unprepare(
+			vfe40_ctrl->stats_ops.stats_ctrl,
+			req_buf->stats_type, i,
+			vfe40_ctrl->stats_ops.client, domain_num);
+		if (rc < 0) {
+			pr_err("%s: unreg stats buf (type = %d) err = %d",
+				__func__, req_buf->stats_type, rc);
+		return rc;
+		}
+	}
+	return 0L;
+}
 static int vfe_stats_awb_buf_init(
 	struct vfe40_ctrl_type *vfe40_ctrl,
 	struct vfe_cmd_stats_buf *in)
@@ -469,14 +1063,18 @@
 	return 0;
 }
 
-static int vfe_stats_aec_buf_init(
-	struct vfe40_ctrl_type *vfe40_ctrl, struct vfe_cmd_stats_buf *in)
+static uint32_t vfe_stats_aec_bg_buf_init(
+	struct vfe40_ctrl_type *vfe40_ctrl)
 {
 	uint32_t addr;
 	unsigned long flags;
+	uint32_t stats_type;
 
+	stats_type =
+		(!vfe40_use_bayer_stats(vfe40_ctrl)) ? MSM_STATS_TYPE_AEC
+			: MSM_STATS_TYPE_BG;
 	spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
-	addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_AEC);
+	addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, stats_type);
 	spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
 	if (!addr) {
 		pr_err("%s: dq aec ping buf from free buf queue",
@@ -485,9 +1083,9 @@
 	}
 	msm_camera_io_w(addr,
 		vfe40_ctrl->share_ctrl->vfebase +
-		VFE_BUS_STATS_AEC_WR_PING_ADDR);
+		VFE_BUS_STATS_BG_WR_PING_ADDR);
 	spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
-	addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_AEC);
+	addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, stats_type);
 	spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
 	if (!addr) {
 		pr_err("%s: dq aec pong buf from free buf queue",
@@ -496,26 +1094,31 @@
 	}
 	msm_camera_io_w(addr,
 		vfe40_ctrl->share_ctrl->vfebase +
-		VFE_BUS_STATS_AEC_WR_PONG_ADDR);
+		VFE_BUS_STATS_BG_WR_PONG_ADDR);
 	return 0;
 }
 
-static int vfe_stats_af_buf_init(
-	struct vfe40_ctrl_type *vfe40_ctrl, struct vfe_cmd_stats_buf *in)
+static int vfe_stats_af_bf_buf_init(
+	struct vfe40_ctrl_type *vfe40_ctrl)
 {
 	uint32_t addr;
 	unsigned long flags;
 	int rc = 0;
 
+	uint32_t stats_type;
+	stats_type =
+		(!vfe40_use_bayer_stats(vfe40_ctrl)) ? MSM_STATS_TYPE_AF
+			: MSM_STATS_TYPE_BF;
+
 	spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
-	rc = vfe40_stats_flush_enqueue(vfe40_ctrl, MSM_STATS_TYPE_AF);
+	rc = vfe40_stats_flush_enqueue(vfe40_ctrl, stats_type);
 	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);
+	addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, stats_type);
 	spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
 	if (!addr) {
 		pr_err("%s: dq af ping buf from free buf queue", __func__);
@@ -523,9 +1126,9 @@
 	}
 	msm_camera_io_w(addr,
 		vfe40_ctrl->share_ctrl->vfebase +
-		VFE_BUS_STATS_AF_WR_PING_ADDR);
+		VFE_BUS_STATS_BF_WR_PING_ADDR);
 	spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
-	addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_AF);
+	addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, stats_type);
 	spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
 	if (!addr) {
 		pr_err("%s: dq af pong buf from free buf queue", __func__);
@@ -533,13 +1136,44 @@
 	}
 	msm_camera_io_w(addr,
 		vfe40_ctrl->share_ctrl->vfebase +
-		VFE_BUS_STATS_AF_WR_PONG_ADDR);
+		VFE_BUS_STATS_BF_WR_PONG_ADDR);
+	return 0;
+}
+
+static uint32_t vfe_stats_bhist_buf_init(
+	struct vfe40_ctrl_type *vfe40_ctrl)
+{
+	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_BHIST);
+	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_SKIN_WR_PING_ADDR);
+	spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_BHIST);
+	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_SKIN_WR_PONG_ADDR);
 
 	return 0;
 }
 
 static int vfe_stats_ihist_buf_init(
-	struct vfe40_ctrl_type *vfe40_ctrl, struct vfe_cmd_stats_buf *in)
+	struct vfe40_ctrl_type *vfe40_ctrl)
 {
 	uint32_t addr;
 	unsigned long flags;
@@ -571,7 +1205,7 @@
 }
 
 static int vfe_stats_rs_buf_init(
-	struct vfe40_ctrl_type *vfe40_ctrl, struct vfe_cmd_stats_buf *in)
+	struct vfe40_ctrl_type *vfe40_ctrl)
 {
 	uint32_t addr;
 	unsigned long flags;
@@ -600,7 +1234,7 @@
 }
 
 static int vfe_stats_cs_buf_init(
-	struct vfe40_ctrl_type *vfe40_ctrl, struct vfe_cmd_stats_buf *in)
+	struct vfe40_ctrl_type *vfe40_ctrl)
 {
 	uint32_t addr;
 	unsigned long flags;
@@ -627,39 +1261,51 @@
 	return 0;
 }
 
+static void vfe40_cfg_qos_parms(struct vfe40_ctrl_type *vfe40_ctrl)
+{
+	void __iomem *vfebase = vfe40_ctrl->share_ctrl->vfebase;
+	msm_camera_io_w(0xAAAAAAAA, vfebase + VFE_0_BUS_BDG_QOS_CFG_0);
+	msm_camera_io_w(0xAAAAAAAA, vfebase + VFE_0_BUS_BDG_QOS_CFG_1);
+	msm_camera_io_w(0xAAAAAAAA, vfebase + VFE_0_BUS_BDG_QOS_CFG_2);
+	msm_camera_io_w(0xAAAAAAAA, vfebase + VFE_0_BUS_BDG_QOS_CFG_3);
+	msm_camera_io_w(0xAAAAAAAA, vfebase + VFE_0_BUS_BDG_QOS_CFG_4);
+	msm_camera_io_w(0xAAAAAAAA, vfebase + VFE_0_BUS_BDG_QOS_CFG_5);
+	msm_camera_io_w(0xAAAAAAAA, vfebase + VFE_0_BUS_BDG_QOS_CFG_6);
+	msm_camera_io_w(0x0002AAAA, vfebase + VFE_0_BUS_BDG_QOS_CFG_7);
+}
+
 static void vfe40_start_common(struct vfe40_ctrl_type *vfe40_ctrl)
 {
-	uint32_t irq_mask = 0x1E000011;
-	vfe40_ctrl->start_ack_pending = TRUE;
+	uint16_t vfe_operation_mode =
+		vfe40_ctrl->share_ctrl->current_mode & ~(VFE_OUTPUTS_RDI0|
+			VFE_OUTPUTS_RDI1);
 	CDBG("VFE opertaion mode = 0x%x, output mode = 0x%x\n",
-		vfe40_ctrl->share_ctrl->operation_mode,
+		vfe40_ctrl->share_ctrl->current_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);
+	vfe40_cfg_qos_parms(vfe40_ctrl);
 
-	/* Ensure the write order while writing
-	to the command register using the barrier */
+	msm_camera_io_w_mb(0x1,
+			vfe40_ctrl->share_ctrl->vfebase +
+			VFE_REG_UPDATE_CMD);
+
+	msm_camera_io_w_mb(0x00003fff,
+			vfe40_ctrl->share_ctrl->vfebase +
+			V40_AXI_BUS_CMD_OFF);
 	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);
+			vfe40_ctrl->share_ctrl->vfebase +
+			V40_BUS_PM_CMD);
+	if (vfe_operation_mode) {
+		msm_camera_io_w_mb(1, vfe40_ctrl->share_ctrl->vfebase +
+			VFE_CAMIF_COMMAND);
+	}
 }
 
 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;
+	vfe40_ctrl->share_ctrl->recording_state = VFE_STATE_START_REQUESTED;
 	msm_camera_io_w_mb(1,
 		vfe40_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
 	return 0;
@@ -669,11 +1315,9 @@
 	struct msm_cam_media_controller *pmctl,
 	struct vfe40_ctrl_type *vfe40_ctrl)
 {
-	vfe40_ctrl->recording_state = VFE_STATE_STOP_REQUESTED;
+	vfe40_ctrl->share_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;
 }
 
@@ -691,100 +1335,22 @@
 		share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
 }
 
+static void vfe40_stop_liveshot(
+	struct msm_cam_media_controller *pmctl,
+	struct vfe40_ctrl_type *vfe40_ctrl)
+{
+	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);
+}
+
 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_ctrl->share_ctrl->start_ack_pending = TRUE;
 	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(
@@ -792,28 +1358,8 @@
 	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;
 }
@@ -823,79 +1369,25 @@
 	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 ==
+	if (vfe40_ctrl->share_ctrl->current_mode ==
 			VFE_OUTPUTS_MAIN_AND_THUMB ||
-		vfe40_ctrl->share_ctrl->operation_mode ==
+		vfe40_ctrl->share_ctrl->current_mode ==
 			VFE_OUTPUTS_THUMB_AND_MAIN ||
-		vfe40_ctrl->share_ctrl->operation_mode ==
+		vfe40_ctrl->share_ctrl->current_mode ==
 			VFE_OUTPUTS_JPEG_AND_THUMB ||
-		vfe40_ctrl->share_ctrl->operation_mode ==
+		vfe40_ctrl->share_ctrl->current_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;
 }
 
@@ -903,41 +1395,6 @@
 	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;
 }
@@ -980,9 +1437,9 @@
 		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);
+	spin_lock_irqsave(&vfe40_ctrl->share_ctrl->update_ack_lock, flags);
+	vfe40_ctrl->share_ctrl->update_ack_pending = TRUE;
+	spin_unlock_irqrestore(&vfe40_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,
@@ -1044,7 +1501,7 @@
 			 8 + ((vfe40_ctrl->sync_timer_number) * 12));
 	/* Sync Timer Pixel Duration */
 	value = *tbl++;
-	val = vfe40_ctrl->share_ctrl->vfe_clk_rate / 10000;
+	val = vfe_clk_rate / 10000;
 	val = 10000000 / val;
 	val = value * 10000 / val;
 	CDBG("%s: Pixel Clk Cycles!!! %d\n", __func__, val);
@@ -1061,19 +1518,7 @@
 		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,
@@ -1132,7 +1577,7 @@
 	vfe40_program_dmi_cfg(NO_MEM_SELECTED, vfe40_ctrl);
 }
 
-struct vfe40_output_ch *vfe40_get_ch(
+static struct vfe40_output_ch *vfe40_get_ch(
 	int path, struct vfe_share_ctrl_t *share_ctrl)
 {
 	struct vfe40_output_ch *ch = NULL;
@@ -1141,6 +1586,10 @@
 		ch = &share_ctrl->outpath.out0;
 	else if (path == VFE_MSG_OUTPUT_SECONDARY)
 		ch = &share_ctrl->outpath.out1;
+	else if (path == VFE_MSG_OUTPUT_TERTIARY1)
+		ch = &share_ctrl->outpath.out2;
+	else if (path == VFE_MSG_OUTPUT_TERTIARY2)
+		ch = &share_ctrl->outpath.out3;
 	else
 		pr_err("%s: Invalid path %d\n", __func__,
 			path);
@@ -1148,49 +1597,76 @@
 	BUG_ON(ch == NULL);
 	return ch;
 }
+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 inst_handle = 0;
 
-static int vfe40_configure_pingpong_buffers(
-	int id, int path, struct vfe40_ctrl_type *vfe40_ctrl)
+	if (path == VFE_MSG_OUTPUT_PRIMARY)
+		inst_handle = axi_ctrl->share_ctrl->outpath.out0.inst_handle;
+	else if (path == VFE_MSG_OUTPUT_SECONDARY)
+		inst_handle = axi_ctrl->share_ctrl->outpath.out1.inst_handle;
+	else if (path == VFE_MSG_OUTPUT_TERTIARY1)
+		inst_handle = axi_ctrl->share_ctrl->outpath.out2.inst_handle;
+	else if (path == VFE_MSG_OUTPUT_TERTIARY2)
+		inst_handle = axi_ctrl->share_ctrl->outpath.out3.inst_handle;
+
+	vfe40_subdev_notify(id, path, inst_handle,
+		&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 int configure_pingpong_buffers(
+	int id, int path, struct axi_ctrl_t *axi_ctrl)
 {
 	struct vfe40_output_ch *outch = NULL;
 	int rc = 0;
-	uint32_t image_mode = 0;
+	uint32_t inst_handle = 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;
+		inst_handle = axi_ctrl->share_ctrl->outpath.out0.inst_handle;
+	else if (path == VFE_MSG_OUTPUT_SECONDARY)
+		inst_handle = axi_ctrl->share_ctrl->outpath.out1.inst_handle;
+	else if (path == VFE_MSG_OUTPUT_TERTIARY1)
+		inst_handle = axi_ctrl->share_ctrl->outpath.out2.inst_handle;
+	else if (path == VFE_MSG_OUTPUT_TERTIARY2)
+		inst_handle = axi_ctrl->share_ctrl->outpath.out3.inst_handle;
 
-	vfe40_subdev_notify(id, path, image_mode,
-		&vfe40_ctrl->subdev, vfe40_ctrl->share_ctrl);
-	outch = vfe40_get_ch(path, vfe40_ctrl->share_ctrl);
+	vfe40_subdev_notify(id, path, inst_handle,
+		&axi_ctrl->subdev, axi_ctrl->share_ctrl);
+	outch = vfe40_get_ch(path, axi_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",
+		pr_info("%s Configure ping/pong address for %d\n",
 						__func__, path);
 		vfe40_put_ch_ping_addr(
-			vfe40_ctrl->share_ctrl->vfebase, outch->ch0,
+			axi_ctrl->share_ctrl->vfebase, outch->ch0,
 			outch->ping.ch_paddr[0]);
 		vfe40_put_ch_pong_addr(
-			vfe40_ctrl->share_ctrl->vfebase, outch->ch0,
+			axi_ctrl->share_ctrl->vfebase, outch->ch0,
 			outch->pong.ch_paddr[0]);
 
-		if (vfe40_ctrl->share_ctrl->operation_mode !=
-			VFE_OUTPUTS_RAW) {
+		if ((axi_ctrl->share_ctrl->current_mode !=
+			VFE_OUTPUTS_RAW) && (path != VFE_MSG_OUTPUT_TERTIARY1)
+			&& (path != VFE_MSG_OUTPUT_TERTIARY2)) {
 			vfe40_put_ch_ping_addr(
-				vfe40_ctrl->share_ctrl->vfebase, outch->ch1,
+				axi_ctrl->share_ctrl->vfebase, outch->ch1,
 				outch->ping.ch_paddr[1]);
 			vfe40_put_ch_pong_addr(
-				vfe40_ctrl->share_ctrl->vfebase, outch->ch1,
+				axi_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,
+				axi_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,
+				axi_ctrl->share_ctrl->vfebase, outch->ch2,
 				outch->pong.ch_paddr[2]);
 
 		/* avoid stale info */
@@ -1220,7 +1696,7 @@
 	vfe40_program_dmi_cfg(NO_MEM_SELECTED, vfe40_ctrl);
 }
 
-void vfe40_send_isp_msg(
+static void vfe40_send_isp_msg(
 	struct v4l2_subdev *sd,
 	uint32_t vfeFrameId,
 	uint32_t isp_msg_id)
@@ -1240,142 +1716,76 @@
 	struct vfe40_ctrl_type *vfe40_ctrl)
 {
 	int i , rc = 0;
-	uint32_t old_val = 0 , new_val = 0;
+	uint32_t old_val = 0 , new_val = 0, module_val = 0;
 	uint32_t *cmdp = NULL;
 	uint32_t *cmdp_local = NULL;
 	uint32_t snapshot_cnt = 0;
 	uint32_t temp1 = 0, temp2 = 0;
+	struct msm_camera_vfe_params_t vfe_params;
 
 	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",
+		pr_info("vfe40_proc_general: cmdID = %s\n",
 			vfe40_general_cmd[cmd->id]);
+		vfe40_ctrl->share_ctrl->vfe_reset_flag = true;
 		vfe40_reset(vfe40_ctrl);
 		break;
 	case VFE_CMD_START:
-		CDBG("vfe40_proc_general: cmdID = %s\n",
+		pr_info("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;
+		if (copy_from_user(&vfe_params,
+				(void __user *)(cmd->value),
+				sizeof(struct msm_camera_vfe_params_t))) {
+				rc = -EFAULT;
+				goto proc_general_done;
 		}
 
+		vfe40_ctrl->share_ctrl->current_mode =
+			vfe_params.operation_mode;
+
 		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;
+		pr_info("%s: cmdID = VFE_CMD_CAPTURE_RAW\n", __func__);
+		if (copy_from_user(&vfe_params,
+				(void __user *)(cmd->value),
+				sizeof(struct msm_camera_vfe_params_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;
-		}
+
+		snapshot_cnt = vfe_params.capture_count;
+		vfe40_ctrl->share_ctrl->current_mode =
+			vfe_params.operation_mode;
 		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;
+		pr_info("%s: cmdID = VFE_CMD_CAPTURE\n", __func__);
+		if (copy_from_user(&vfe_params,
+				(void __user *)(cmd->value),
+				sizeof(struct msm_camera_vfe_params_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;
-		}
+		snapshot_cnt = vfe_params.capture_count;
+		vfe40_ctrl->share_ctrl->current_mode =
+			vfe_params.operation_mode;
+
 		rc = vfe40_capture(pmctl, snapshot_cnt, vfe40_ctrl);
 		break;
 	case VFE_CMD_START_RECORDING:
-		CDBG("vfe40_proc_general: cmdID = %s\n",
+		pr_info("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",
+		pr_info("vfe40_proc_general: cmdID = %s\n",
 			vfe40_general_cmd[cmd->id]);
 		rc = vfe40_stop_recording(pmctl, vfe40_ctrl);
 		break;
@@ -1396,7 +1806,12 @@
 		break;
 
 	case VFE_CMD_STATS_AE_START: {
-		rc = vfe_stats_aec_buf_init(vfe40_ctrl, NULL);
+		if (vfe40_use_bayer_stats(vfe40_ctrl)) {
+			/* Error */
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		rc = vfe_stats_aec_bg_buf_init(vfe40_ctrl);
 		if (rc < 0) {
 			pr_err("%s: cannot config ping/pong address of AEC",
 				 __func__);
@@ -1425,7 +1840,12 @@
 		}
 		break;
 	case VFE_CMD_STATS_AF_START: {
-		rc = vfe_stats_af_buf_init(vfe40_ctrl, NULL);
+		if (vfe40_use_bayer_stats(vfe40_ctrl)) {
+			/* Error */
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		rc = vfe_stats_af_bf_buf_init(vfe40_ctrl);
 		if (rc < 0) {
 			pr_err("%s: cannot config ping/pong address of AF",
 				__func__);
@@ -1453,8 +1873,12 @@
 			cmdp, (vfe40_cmd[cmd->id].length));
 		}
 		break;
-
 	case VFE_CMD_STATS_AWB_START: {
+		if (vfe40_use_bayer_stats(vfe40_ctrl)) {
+			/* Error */
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
 		rc = vfe_stats_awb_buf_init(vfe40_ctrl, NULL);
 		if (rc < 0) {
 			pr_err("%s: cannot config ping/pong address of AWB",
@@ -1485,7 +1909,7 @@
 		break;
 
 	case VFE_CMD_STATS_IHIST_START: {
-		rc = vfe_stats_ihist_buf_init(vfe40_ctrl, NULL);
+		rc = vfe_stats_ihist_buf_init(vfe40_ctrl);
 		if (rc < 0) {
 			pr_err("%s: cannot config ping/pong address of IHIST",
 				 __func__);
@@ -1516,7 +1940,7 @@
 
 
 	case VFE_CMD_STATS_RS_START: {
-		rc = vfe_stats_rs_buf_init(vfe40_ctrl, NULL);
+		rc = vfe_stats_rs_buf_init(vfe40_ctrl);
 		if (rc < 0) {
 			pr_err("%s: cannot config ping/pong address of RS",
 				__func__);
@@ -1541,7 +1965,7 @@
 		break;
 
 	case VFE_CMD_STATS_CS_START: {
-		rc = vfe_stats_cs_buf_init(vfe40_ctrl, NULL);
+		rc = vfe_stats_cs_buf_init(vfe40_ctrl);
 		if (rc < 0) {
 			pr_err("%s: cannot config ping/pong address of CS",
 				__func__);
@@ -1565,6 +1989,65 @@
 		}
 		break;
 
+	case VFE_CMD_STATS_BG_START:
+	case VFE_CMD_STATS_BF_START:
+	case VFE_CMD_STATS_BHIST_START: {
+		if (!vfe40_use_bayer_stats(vfe40_ctrl)) {
+			/* Error */
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		old_val = msm_camera_io_r(
+			vfe40_ctrl->share_ctrl->vfebase + VFE_STATS_CFG);
+		module_val = msm_camera_io_r(
+			vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+		if (VFE_CMD_STATS_BG_START == cmd->id) {
+			module_val |= BG_ENABLE_MASK;
+			rc = vfe_stats_aec_bg_buf_init(vfe40_ctrl);
+			if (rc < 0) {
+				pr_err("%s: cannot config ping/pong address of CS",
+					__func__);
+				goto proc_general_done;
+			}
+		} else if (VFE_CMD_STATS_BF_START == cmd->id) {
+			module_val |= BF_ENABLE_MASK;
+			rc = vfe_stats_af_bf_buf_init(vfe40_ctrl);
+			if (rc < 0) {
+				pr_err("%s: cannot config ping/pong address of CS",
+					__func__);
+				goto proc_general_done;
+			}
+		} else {
+			module_val |= BHIST_ENABLE_MASK;
+			old_val |= STATS_BHIST_ENABLE_MASK;
+			rc = vfe_stats_bhist_buf_init(vfe40_ctrl);
+			if (rc < 0) {
+				pr_err("%s: cannot config ping/pong address of CS",
+					__func__);
+				goto proc_general_done;
+			}
+		}
+		msm_camera_io_w(old_val, vfe40_ctrl->share_ctrl->vfebase +
+			VFE_STATS_CFG);
+		msm_camera_io_w(module_val,
+			vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+				(void __user *)(cmd->value),
+				cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		msm_camera_io_memcpy(
+			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);
@@ -1651,6 +2134,38 @@
 		rc = -EFAULT;
 		goto proc_general_done;
 
+	case VFE_CMD_MESH_ROLL_OFF_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, V40_MESH_ROLL_OFF_CFG_LEN);
+		cmdp_local += 9;
+		vfe40_program_dmi_cfg(ROLLOFF_RAM0_BANK0, vfe40_ctrl);
+		/* for loop for extrcting table. */
+		for (i = 0; i < (V40_MESH_ROLL_OFF_TABLE_SIZE * 2); i++) {
+			msm_camera_io_w(*cmdp_local,
+				vfe40_ctrl->share_ctrl->vfebase +
+				VFE_DMI_DATA_LO);
+			cmdp_local++;
+		}
+		CDBG("done writing mesh table\n");
+		vfe40_program_dmi_cfg(NO_MEM_SELECTED, vfe40_ctrl);
+	}
+	break;
+	case VFE_CMD_GET_MESH_ROLLOFF_TABLE:
+		break;
+
 	case VFE_CMD_LA_CFG:
 		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
 		if (!cmdp) {
@@ -1759,15 +2274,6 @@
 
 	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;
 
@@ -1787,7 +2293,6 @@
 			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);
@@ -2139,6 +2644,11 @@
 		break;
 
 	case VFE_CMD_STATS_AWB_STOP: {
+		if (vfe40_use_bayer_stats(vfe40_ctrl)) {
+			/* Error */
+			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;
@@ -2146,27 +2656,30 @@
 			vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
 		}
 		break;
-
 	case VFE_CMD_STATS_AE_STOP: {
+		if (vfe40_use_bayer_stats(vfe40_ctrl)) {
+			/* Error */
+			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;
+		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: {
+		if (vfe40_use_bayer_stats(vfe40_ctrl)) {
+			/* Error */
+			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);
-		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;
 
@@ -2196,9 +2709,47 @@
 			vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
 		}
 		break;
+
+	case VFE_CMD_STATS_BG_STOP:
+	case VFE_CMD_STATS_BF_STOP:
+	case VFE_CMD_STATS_BHIST_STOP: {
+		if (!vfe40_use_bayer_stats(vfe40_ctrl)) {
+			/* Error */
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		old_val = msm_camera_io_r(
+			vfe40_ctrl->share_ctrl->vfebase + VFE_STATS_CFG);
+
+		if (VFE_CMD_STATS_BHIST_STOP == cmd->id)
+			old_val &= ~STATS_BHIST_ENABLE_MASK;
+
+		msm_camera_io_w(old_val,
+			vfe40_ctrl->share_ctrl->vfebase + VFE_STATS_CFG);
+		if (VFE_CMD_STATS_BF_STOP == cmd->id) {
+			rc = vfe40_stats_flush_enqueue(vfe40_ctrl,
+					MSM_STATS_TYPE_BF);
+			if (rc < 0) {
+				pr_err("%s: dq stats buf err = %d",
+					   __func__, rc);
+				return -EINVAL;
+			}
+		}
+		}
+		break;
+
 	case VFE_CMD_STOP:
-		CDBG("vfe40_proc_general: cmdID = %s\n",
+		pr_info("vfe40_proc_general: cmdID = %s\n",
 			vfe40_general_cmd[cmd->id]);
+		if (copy_from_user(&vfe_params,
+				(void __user *)(cmd->value),
+				sizeof(struct msm_camera_vfe_params_t))) {
+				rc = -EFAULT;
+				goto proc_general_done;
+		}
+
+		vfe40_ctrl->share_ctrl->current_mode =
+			vfe_params.operation_mode;
 		vfe40_stop(vfe40_ctrl);
 		break;
 
@@ -2242,14 +2793,15 @@
 		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;
+		if (copy_from_user(&vfe_params,
+				(void __user *)(cmd->value),
+				sizeof(struct msm_camera_vfe_params_t))) {
+				rc = -EFAULT;
+				goto proc_general_done;
+		}
+
+		vfe40_ctrl->share_ctrl->current_mode =
+			vfe_params.operation_mode;
 
 		rc = vfe40_zsl(pmctl, vfe40_ctrl);
 		break;
@@ -2344,6 +2896,10 @@
 			*cmdp & VFE_FRAME_SKIP_PERIOD_MASK) + 1;
 		vfe40_ctrl->frame_skip_pattern = (uint32_t)(*(cmdp + 2));
 		break;
+	case VFE_CMD_STOP_LIVESHOT:
+		CDBG("%s Stopping liveshot ", __func__);
+		vfe40_stop_liveshot(pmctl, vfe40_ctrl);
+		break;
 	default:
 		if (cmd->length != vfe40_cmd[cmd->id].length)
 			return -EINVAL;
@@ -2402,176 +2958,435 @@
 
 }
 
+void axi_stop_pix(struct vfe_share_ctrl_t *share_ctrl)
+{
+	uint32_t operation_mode =
+	share_ctrl->current_mode & ~(VFE_OUTPUTS_RDI0|
+		VFE_OUTPUTS_RDI1);
+	uint32_t irq_comp_mask, irq_mask;
+	uint32_t reg_update = 0x1;
+
+	irq_comp_mask =
+		msm_camera_io_r(share_ctrl->vfebase +
+			VFE_IRQ_COMP_MASK);
+	irq_mask = msm_camera_io_r(share_ctrl->vfebase +
+			VFE_IRQ_MASK_0);
+
+	switch (share_ctrl->cmd_type) {
+	case AXI_CMD_PREVIEW: {
+		switch (operation_mode) {
+		case VFE_OUTPUTS_PREVIEW:
+		case VFE_OUTPUTS_PREVIEW_AND_VIDEO:
+			if (share_ctrl->comp_output_mode &
+				VFE40_OUTPUT_MODE_PRIMARY) {
+				msm_camera_io_w(0, share_ctrl->vfebase
+					+ vfe40_AXI_WM_CFG[share_ctrl->
+					outpath.out0.ch0]);
+				msm_camera_io_w(0, share_ctrl->vfebase
+					+ vfe40_AXI_WM_CFG[share_ctrl->
+					outpath.out0.ch1]);
+				irq_comp_mask &= ~(
+					0x1 << share_ctrl->outpath.out0.ch0 |
+					0x1 << share_ctrl->outpath.out0.ch1);
+				share_ctrl->outpath.output_mode |=
+					VFE40_OUTPUT_MODE_PRIMARY;
+			} else if (share_ctrl->comp_output_mode &
+					VFE40_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
+				msm_camera_io_w(0, share_ctrl->vfebase
+					+ vfe40_AXI_WM_CFG[share_ctrl->
+					outpath.out0.ch0]);
+				msm_camera_io_w(0, share_ctrl->vfebase
+					+ vfe40_AXI_WM_CFG[share_ctrl->
+					outpath.out0.ch1]);
+				msm_camera_io_w(0, share_ctrl->vfebase
+					+ vfe40_AXI_WM_CFG[share_ctrl->
+					outpath.out0.ch2]);
+				irq_comp_mask &= ~(
+					0x1 << share_ctrl->outpath.out0.ch0 |
+					0x1 << share_ctrl->outpath.out0.ch1 |
+					0x1 << share_ctrl->outpath.out0.ch2);
+				share_ctrl->outpath.output_mode |=
+					VFE40_OUTPUT_MODE_PRIMARY_ALL_CHNLS;
+			}
+			irq_mask &= ~VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK;
+			break;
+		default:
+			if (share_ctrl->comp_output_mode &
+				VFE40_OUTPUT_MODE_SECONDARY) {
+				msm_camera_io_w(0, share_ctrl->vfebase
+					+ vfe40_AXI_WM_CFG[share_ctrl->
+					outpath.out1.ch0]);
+				msm_camera_io_w(0, share_ctrl->vfebase
+					+ vfe40_AXI_WM_CFG[share_ctrl->
+					outpath.out1.ch1]);
+				irq_comp_mask &= ~(
+					0x1 << share_ctrl->outpath.out1.ch0 |
+					0x1 << share_ctrl->outpath.out1.ch1);
+				share_ctrl->outpath.output_mode |=
+					VFE40_OUTPUT_MODE_SECONDARY;
+			} else if (share_ctrl->comp_output_mode &
+				VFE40_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
+				msm_camera_io_w(0, share_ctrl->vfebase
+					+ vfe40_AXI_WM_CFG[share_ctrl->
+					outpath.out1.ch0]);
+				msm_camera_io_w(0, share_ctrl->vfebase
+					+ vfe40_AXI_WM_CFG[share_ctrl->
+					outpath.out1.ch1]);
+				msm_camera_io_w(0, share_ctrl->vfebase
+					+ vfe40_AXI_WM_CFG[share_ctrl->
+					outpath.out1.ch2]);
+				irq_comp_mask &= ~(
+					0x1 << share_ctrl->outpath.out1.ch0 |
+					0x1 << share_ctrl->outpath.out1.ch1 |
+					0x1 << share_ctrl->outpath.out1.ch2);
+				share_ctrl->outpath.output_mode |=
+					VFE40_OUTPUT_MODE_SECONDARY_ALL_CHNLS;
+			}
+			irq_mask &= ~VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE1_MASK;
+			break;
+			}
+		}
+		break;
+	default:
+		if (share_ctrl->comp_output_mode &
+			VFE40_OUTPUT_MODE_PRIMARY) {
+			msm_camera_io_w(0, share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[share_ctrl->
+				outpath.out0.ch0]);
+			msm_camera_io_w(0, share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[share_ctrl->
+				outpath.out0.ch1]);
+			irq_comp_mask &= ~(
+				0x1 << share_ctrl->outpath.out0.ch0 |
+				0x1 << share_ctrl->outpath.out0.ch1);
+			irq_mask &= ~VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK;
+			share_ctrl->outpath.output_mode |=
+					VFE40_OUTPUT_MODE_PRIMARY;
+		} else if (share_ctrl->comp_output_mode &
+				VFE40_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
+			msm_camera_io_w(0, share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[share_ctrl->
+				outpath.out0.ch0]);
+			msm_camera_io_w(0, share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[share_ctrl->
+				outpath.out0.ch1]);
+			msm_camera_io_w(0, share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[share_ctrl->
+				outpath.out0.ch2]);
+			irq_comp_mask &= ~(
+				0x1 << share_ctrl->outpath.out0.ch0 |
+				0x1 << share_ctrl->outpath.out0.ch1 |
+				0x1 << share_ctrl->outpath.out0.ch2);
+			irq_mask &= ~VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK;
+			share_ctrl->outpath.output_mode |=
+					VFE40_OUTPUT_MODE_PRIMARY_ALL_CHNLS;
+		}
+
+		if (share_ctrl->comp_output_mode &
+			VFE40_OUTPUT_MODE_SECONDARY) {
+			msm_camera_io_w(0, share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[share_ctrl->
+				outpath.out1.ch0]);
+			msm_camera_io_w(0, share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[share_ctrl->outpath.out1.ch1]);
+			irq_comp_mask &= ~(
+				0x1 << share_ctrl->outpath.out1.ch0 |
+				0x1 << share_ctrl->outpath.out1.ch1);
+			irq_mask &= ~VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE1_MASK;
+			share_ctrl->outpath.output_mode |=
+					VFE40_OUTPUT_MODE_SECONDARY;
+		} else if (share_ctrl->comp_output_mode &
+			VFE40_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
+			msm_camera_io_w(0, share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[share_ctrl->outpath.out1.ch0]);
+			msm_camera_io_w(0, share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[share_ctrl->outpath.out1.ch1]);
+			msm_camera_io_w(0, share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[share_ctrl->outpath.out1.ch2]);
+			irq_comp_mask &= ~(
+				0x1 << share_ctrl->outpath.out1.ch0 |
+				0x1 << share_ctrl->outpath.out1.ch1 |
+				0x1 << share_ctrl->outpath.out1.ch2);
+			irq_mask &= ~VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE1_MASK;
+			share_ctrl->outpath.output_mode |=
+					VFE40_OUTPUT_MODE_SECONDARY_ALL_CHNLS;
+		}
+		break;
+	}
+
+	msm_camera_io_w_mb(reg_update,
+		share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+	msm_camera_io_w(irq_comp_mask,
+		share_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+	msm_camera_io_w(irq_mask, share_ctrl->vfebase +
+			VFE_IRQ_MASK_0);
+}
+
+void axi_stop_rdi0(struct vfe_share_ctrl_t *share_ctrl)
+{
+	uint32_t reg_update = 0x2;
+	uint32_t irq_mask;
+	irq_mask = msm_camera_io_r(share_ctrl->vfebase +
+			VFE_IRQ_MASK_0);
+
+	if (share_ctrl->current_mode & VFE_OUTPUTS_RDI0) {
+		msm_camera_io_w(0, share_ctrl->vfebase +
+			vfe40_AXI_WM_CFG[share_ctrl->outpath.out2.ch0]);
+		irq_mask &= ~(0x1 << (share_ctrl->outpath.out2.ch0 +
+				VFE_WM_OFFSET));
+	}
+	msm_camera_io_w_mb(reg_update,
+		share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+	msm_camera_io_w(irq_mask, share_ctrl->vfebase +
+			VFE_IRQ_MASK_0);
+}
+
+void axi_stop_rdi1(struct vfe_share_ctrl_t *share_ctrl)
+{
+	uint32_t reg_update = 0x4;
+	uint32_t irq_mask;
+	irq_mask = msm_camera_io_r(share_ctrl->vfebase +
+			VFE_IRQ_MASK_0);
+
+	if (share_ctrl->current_mode & VFE_OUTPUTS_RDI1) {
+		msm_camera_io_w(1, share_ctrl->vfebase +
+			vfe40_AXI_WM_CFG[share_ctrl->outpath.out3.ch0]);
+		irq_mask &= ~(0x1 << (share_ctrl->outpath.out3.ch0 +
+			VFE_WM_OFFSET));
+	}
+	msm_camera_io_w_mb(reg_update,
+		share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+	msm_camera_io_w(irq_mask, share_ctrl->vfebase +
+			VFE_IRQ_MASK_0);
+}
+
+void axi_stop_process(struct vfe_share_ctrl_t *share_ctrl)
+{
+	uint32_t operation_mode =
+	share_ctrl->current_mode & ~(VFE_OUTPUTS_RDI0|
+		VFE_OUTPUTS_RDI1);
+
+	if (share_ctrl->current_mode & VFE_OUTPUTS_RDI0) {
+		axi_stop_rdi0(share_ctrl);
+		share_ctrl->comp_output_mode &= ~VFE40_OUTPUT_MODE_TERTIARY1;
+	}
+	if (share_ctrl->current_mode & VFE_OUTPUTS_RDI1) {
+		axi_stop_rdi1(share_ctrl);
+		share_ctrl->comp_output_mode &= ~VFE40_OUTPUT_MODE_TERTIARY2;
+	}
+	if (operation_mode) {
+		axi_stop_pix(share_ctrl);
+		share_ctrl->comp_output_mode &=
+				~(share_ctrl->outpath.output_mode);
+	}
+}
+
 static void vfe40_process_reg_update_irq(
 		struct vfe40_ctrl_type *vfe40_ctrl)
 {
 	unsigned long flags;
+	struct vfe_share_ctrl_t *share_ctrl = vfe40_ctrl->share_ctrl;
 
-	if (vfe40_ctrl->recording_state == VFE_STATE_START_REQUESTED) {
-		if (vfe40_ctrl->share_ctrl->operation_mode ==
+	if (atomic_cmpxchg(
+		&share_ctrl->pix0_update_ack_pending, 2, 0) == 2) {
+		axi_stop_pix(share_ctrl);
+		msm_camera_io_w_mb(
+				CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY,
+				share_ctrl->vfebase + VFE_CAMIF_COMMAND);
+		axi_disable_irq(share_ctrl);
+		vfe40_send_isp_msg(&vfe40_ctrl->subdev,
+			share_ctrl->vfeFrameId,
+			MSG_ID_PIX0_UPDATE_ACK);
+		share_ctrl->comp_output_mode &=
+				~(share_ctrl->outpath.output_mode);
+		share_ctrl->current_mode &=
+			(VFE_OUTPUTS_RDI0|VFE_OUTPUTS_RDI0);
+	}  else {
+		if (share_ctrl->recording_state == VFE_STATE_START_REQUESTED) {
+			if (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->
+				msm_camera_io_w(1,
+					share_ctrl->vfebase + vfe40_AXI_WM_CFG[
 				share_ctrl->outpath.out0.ch0]);
-			msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
-				vfe40_AXI_WM_CFG[vfe40_ctrl->
+				msm_camera_io_w(1,
+					share_ctrl->vfebase + vfe40_AXI_WM_CFG[
 				share_ctrl->outpath.out0.ch1]);
-		} else if (vfe40_ctrl->share_ctrl->operation_mode ==
+			} else if (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->
+				msm_camera_io_w(1,
+					share_ctrl->vfebase + vfe40_AXI_WM_CFG[
 				share_ctrl->outpath.out1.ch0]);
-			msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
-				vfe40_AXI_WM_CFG[vfe40_ctrl->
+				msm_camera_io_w(1,
+					share_ctrl->vfebase + vfe40_AXI_WM_CFG[
 				share_ctrl->outpath.out1.ch1]);
 		}
-		vfe40_ctrl->recording_state = VFE_STATE_STARTED;
+			share_ctrl->recording_state = VFE_STATE_STARTED;
 		msm_camera_io_w_mb(1,
-			vfe40_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+				share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
 		CDBG("start video triggered .\n");
-	} else if (vfe40_ctrl->recording_state ==
+		} else if (share_ctrl->recording_state ==
 			VFE_STATE_STOP_REQUESTED) {
-		if (vfe40_ctrl->share_ctrl->operation_mode ==
+			if (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->
+				msm_camera_io_w(0,
+					share_ctrl->vfebase + vfe40_AXI_WM_CFG[
 				share_ctrl->outpath.out0.ch0]);
-			msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase +
-				vfe40_AXI_WM_CFG[vfe40_ctrl->
+				msm_camera_io_w(0,
+					share_ctrl->vfebase + vfe40_AXI_WM_CFG[
 				share_ctrl->outpath.out0.ch1]);
-		} else if (vfe40_ctrl->share_ctrl->operation_mode ==
+			} else if (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->
+				msm_camera_io_w(0,
+					share_ctrl->vfebase + vfe40_AXI_WM_CFG[
 				share_ctrl->outpath.out1.ch0]);
-			msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase +
-				vfe40_AXI_WM_CFG[vfe40_ctrl->
+				msm_camera_io_w(0,
+					share_ctrl->vfebase + vfe40_AXI_WM_CFG[
 				share_ctrl->outpath.out1.ch1]);
 		}
 		CDBG("stop video triggered .\n");
 	}
 
-	if (vfe40_ctrl->start_ack_pending == TRUE) {
+		if (atomic_cmpxchg(
+			&share_ctrl->pix0_update_ack_pending, 1, 0) == 1) {
+			share_ctrl->comp_output_mode |=
+				(share_ctrl->outpath.output_mode
+				& ~(VFE40_OUTPUT_MODE_TERTIARY1|
+					VFE40_OUTPUT_MODE_TERTIARY2));
 		vfe40_send_isp_msg(&vfe40_ctrl->subdev,
-			vfe40_ctrl->share_ctrl->vfeFrameId, MSG_ID_START_ACK);
-		vfe40_ctrl->start_ack_pending = FALSE;
+				share_ctrl->vfeFrameId, MSG_ID_PIX0_UPDATE_ACK);
+			share_ctrl->current_mode &=
+				(VFE_OUTPUTS_RDI0|VFE_OUTPUTS_RDI0);
 	} else {
-		if (vfe40_ctrl->recording_state ==
-				VFE_STATE_STOP_REQUESTED) {
-			vfe40_ctrl->recording_state = VFE_STATE_STOPPED;
+		if (share_ctrl->recording_state ==
+			VFE_STATE_STOP_REQUESTED) {
+				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,
-			vfe40_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
-		} else if (vfe40_ctrl->recording_state ==
+			msm_camera_io_w_mb(1, share_ctrl->vfebase +
+						VFE_REG_UPDATE_CMD);
+		} else if (share_ctrl->recording_state ==
 					VFE_STATE_STOPPED) {
 			vfe40_send_isp_msg(&vfe40_ctrl->subdev,
-				vfe40_ctrl->share_ctrl->vfeFrameId,
+					share_ctrl->vfeFrameId,
 				MSG_ID_STOP_REC_ACK);
-			vfe40_ctrl->recording_state = VFE_STATE_IDLE;
+				share_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_lock_irqsave(&share_ctrl->update_ack_lock, flags);
+		if (share_ctrl->update_ack_pending == TRUE) {
+			share_ctrl->update_ack_pending = FALSE;
 			spin_unlock_irqrestore(
-				&vfe40_ctrl->update_ack_lock, flags);
+				&share_ctrl->update_ack_lock, flags);
 			vfe40_send_isp_msg(&vfe40_ctrl->subdev,
-				vfe40_ctrl->share_ctrl->vfeFrameId,
-				MSG_ID_UPDATE_ACK);
+				share_ctrl->vfeFrameId, MSG_ID_UPDATE_ACK);
 		} else {
 			spin_unlock_irqrestore(
-				&vfe40_ctrl->update_ack_lock, flags);
+					&share_ctrl->update_ack_lock, flags);
 		}
 	}
 
-	if (vfe40_ctrl->share_ctrl->liveshot_state ==
-		VFE_STATE_START_REQUESTED) {
+	switch (share_ctrl->liveshot_state) {
+	case 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->
+			if (share_ctrl->comp_output_mode &
+			VFE40_OUTPUT_MODE_PRIMARY) {
+				msm_camera_io_w(1, share_ctrl->vfebase +
+					vfe40_AXI_WM_CFG[
 				share_ctrl->outpath.out0.ch0]);
-			msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
-			vfe40_AXI_WM_CFG[vfe40_ctrl->
+				msm_camera_io_w(1, share_ctrl->vfebase +
+					vfe40_AXI_WM_CFG[
 				share_ctrl->outpath.out0.ch1]);
-			vfe40_ctrl->share_ctrl->liveshot_state =
+
+				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->
+		break;
+	case VFE_STATE_STARTED:
+			share_ctrl->vfe_capture_count--;
+			if (!share_ctrl->vfe_capture_count &&
+				(share_ctrl->comp_output_mode &
+				VFE40_OUTPUT_MODE_PRIMARY)) {
+				msm_camera_io_w(0, share_ctrl->vfebase +
+					vfe40_AXI_WM_CFG[
 				share_ctrl->outpath.out0.ch0]);
-			msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase +
-				vfe40_AXI_WM_CFG[vfe40_ctrl->
+				msm_camera_io_w(0, share_ctrl->vfebase +
+					vfe40_AXI_WM_CFG[
 				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 +
+		}
+		break;
+	case VFE_STATE_STOP_REQUESTED:
+		if (share_ctrl->comp_output_mode &
+			VFE40_OUTPUT_MODE_PRIMARY) {
+			/* Stop requested, stop write masters, and
+			 * trigger REG_UPDATE. Send STOP_LS_ACK in
+			 * next reg update. */
+				msm_camera_io_w(0, share_ctrl->vfebase +
+					vfe40_AXI_WM_CFG[
+				share_ctrl->outpath.out0.ch0]);
+				msm_camera_io_w(0, share_ctrl->vfebase +
+					vfe40_AXI_WM_CFG[
+				share_ctrl->outpath.out0.ch1]);
+				share_ctrl->liveshot_state = VFE_STATE_STOPPED;
+				msm_camera_io_w_mb(1, 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;
+		break;
+	case VFE_STATE_STOPPED:
+		CDBG("%s Sending STOP_LS ACK\n", __func__);
+		vfe40_send_isp_msg(&vfe40_ctrl->subdev,
+				share_ctrl->vfeFrameId, MSG_ID_STOP_LS_ACK);
+			share_ctrl->liveshot_state = VFE_STATE_IDLE;
+		break;
+	default:
+		break;
 	}
 
-	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)) {
+	if ((share_ctrl->operation_mode & VFE_OUTPUTS_THUMB_AND_MAIN) ||
+		(share_ctrl->operation_mode &
+		VFE_OUTPUTS_MAIN_AND_THUMB) ||
+		(share_ctrl->operation_mode &
+		VFE_OUTPUTS_THUMB_AND_JPEG) ||
+		(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--;
+				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
+				if (share_ctrl->vfe_capture_count == 0) {
+					/* stop the bus output: */
+					if (share_ctrl->comp_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&
+						msm_camera_io_w(0,
+							share_ctrl->vfebase+
+							vfe40_AXI_WM_CFG[
+							share_ctrl->
+							outpath.out0.ch0]);
+						msm_camera_io_w(0,
+							share_ctrl->vfebase+
+							vfe40_AXI_WM_CFG[
+							share_ctrl->
+							outpath.out0.ch1]);
+					}
+					if (share_ctrl->comp_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(0,
+							share_ctrl->vfebase+
+							vfe40_AXI_WM_CFG[
+							share_ctrl->
+							outpath.out1.ch0]);
+						msm_camera_io_w(0,
+							share_ctrl->vfebase+
+							vfe40_AXI_WM_CFG[
+							share_ctrl->
+							outpath.out1.ch1]);
 				}
 				msm_camera_io_w_mb
 				(CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY,
-				vfe40_ctrl->share_ctrl->vfebase +
-				VFE_CAMIF_COMMAND);
+					share_ctrl->vfebase +
+					VFE_CAMIF_COMMAND);
 				vfe40_ctrl->snapshot_frame_cnt = -1;
 				vfe40_ctrl->frame_skip_cnt = 31;
 				vfe40_ctrl->frame_skip_pattern = 0xffffffff;
@@ -2580,43 +3395,65 @@
 		vfe40_ctrl->snapshot_frame_cnt++;
 		/* then do reg_update. */
 		msm_camera_io_w(1,
-			vfe40_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+				share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
 	} /* if snapshot mode. */
 }
+}
 
-static void vfe40_set_default_reg_values(
-			struct vfe40_ctrl_type *vfe40_ctrl)
+static void vfe40_process_rdi0_reg_update_irq(
+	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);
+	if (atomic_cmpxchg(
+		&vfe40_ctrl->share_ctrl->rdi0_update_ack_pending, 2, 0) == 2) {
+		axi_stop_rdi0(vfe40_ctrl->share_ctrl);
+		axi_disable_irq(vfe40_ctrl->share_ctrl);
+		vfe40_send_isp_msg(&vfe40_ctrl->subdev,
+			vfe40_ctrl->share_ctrl->vfeFrameId,
+			MSG_ID_RDI0_UPDATE_ACK);
+		vfe40_ctrl->share_ctrl->comp_output_mode &=
+			~VFE40_OUTPUT_MODE_TERTIARY1;
+		vfe40_ctrl->share_ctrl->current_mode &=
+			~(VFE_OUTPUTS_RDI0);
+	}
 
-	/* 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);
+	if (atomic_cmpxchg(
+		&vfe40_ctrl->share_ctrl->rdi0_update_ack_pending, 1, 0) == 1) {
+		vfe40_ctrl->share_ctrl->comp_output_mode |=
+			VFE40_OUTPUT_MODE_TERTIARY1;
+		vfe40_send_isp_msg(&vfe40_ctrl->subdev,
+			vfe40_ctrl->share_ctrl->vfeFrameId,
+			MSG_ID_RDI0_UPDATE_ACK);
+		vfe40_ctrl->share_ctrl->current_mode &=
+			~(VFE_OUTPUTS_RDI0);
+	}
+}
 
-	/* 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_rdi1_reg_update_irq(
+	struct vfe40_ctrl_type *vfe40_ctrl)
+{
+	if (atomic_cmpxchg(
+		&vfe40_ctrl->share_ctrl->rdi1_update_ack_pending, 2, 0) == 2) {
+		axi_stop_rdi1(vfe40_ctrl->share_ctrl);
+		axi_disable_irq(vfe40_ctrl->share_ctrl);
+		vfe40_send_isp_msg(&vfe40_ctrl->subdev,
+			vfe40_ctrl->share_ctrl->vfeFrameId,
+			MSG_ID_RDI1_UPDATE_ACK);
+			vfe40_ctrl->share_ctrl->comp_output_mode &=
+				~VFE40_OUTPUT_MODE_TERTIARY2;
+		vfe40_ctrl->share_ctrl->current_mode &=
+			~(VFE_OUTPUTS_RDI1);
+	}
+
+	if (atomic_cmpxchg(
+		&vfe40_ctrl->share_ctrl->rdi1_update_ack_pending, 1, 0) == 1) {
+		vfe40_ctrl->share_ctrl->comp_output_mode |=
+			VFE40_OUTPUT_MODE_TERTIARY2;
+		vfe40_send_isp_msg(&vfe40_ctrl->subdev,
+			vfe40_ctrl->share_ctrl->vfeFrameId,
+			MSG_ID_RDI1_UPDATE_ACK);
+		vfe40_ctrl->share_ctrl->current_mode &=
+			~(VFE_OUTPUTS_RDI1);
+	}
 }
 
 static void vfe40_process_reset_irq(
@@ -2625,39 +3462,45 @@
 	unsigned long flags;
 
 	atomic_set(&vfe40_ctrl->share_ctrl->vstate, 0);
+	atomic_set(&vfe40_ctrl->share_ctrl->handle_common_irq, 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);
+		if (vfe40_ctrl->share_ctrl->sync_abort)
+			complete(&vfe40_ctrl->share_ctrl->reset_complete);
+		else
 		vfe40_send_isp_msg(&vfe40_ctrl->subdev,
-			vfe40_ctrl->share_ctrl->vfeFrameId, MSG_ID_STOP_ACK);
+				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);
-
+		vfe40_reset_internal_variables(vfe40_ctrl);
+		if (vfe40_ctrl->share_ctrl->vfe_reset_flag) {
+			vfe40_ctrl->share_ctrl->vfe_reset_flag = false;
+			msm_camera_io_w(0xFF00,
+				vfe40_ctrl->share_ctrl->vfebase + VFE_BUS_CMD);
+		} else {
 		/* reload all write masters. (frame & line)*/
-		msm_camera_io_w(0x7FFF,
+		msm_camera_io_w(0xFF7F,
 			vfe40_ctrl->share_ctrl->vfebase + VFE_BUS_CMD);
-		vfe40_send_isp_msg(&vfe40_ctrl->subdev,
-			vfe40_ctrl->share_ctrl->vfeFrameId, MSG_ID_RESET_ACK);
+		}
+		complete(&vfe40_ctrl->share_ctrl->reset_complete);
 	}
 }
 
 static void vfe40_process_camif_sof_irq(
 		struct vfe40_ctrl_type *vfe40_ctrl)
 {
-	if (vfe40_ctrl->share_ctrl->operation_mode ==
+	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;
-		}
+		if (vfe40_ctrl->share_ctrl->start_ack_pending)
+			vfe40_ctrl->share_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) {
@@ -2672,11 +3515,15 @@
 			VFE_MODE_OF_OPERATION_VIDEO) &&
 		(vfe40_ctrl->share_ctrl->vfeFrameId %
 			vfe40_ctrl->hfr_mode != 0)) {
-		vfe40_ctrl->share_ctrl->vfeFrameId++;
+		if (vfe40_ctrl->vfe_sof_count_enable)
+			vfe40_ctrl->share_ctrl->vfeFrameId++;
 		CDBG("Skip the SOF notification when HFR enabled\n");
 		return;
 	}
-	vfe40_ctrl->share_ctrl->vfeFrameId++;
+
+	if (vfe40_ctrl->vfe_sof_count_enable)
+		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",
@@ -2694,11 +3541,19 @@
 	struct axi_ctrl_t *axi_ctrl, uint32_t errStatus)
 {
 	uint32_t reg_value;
+	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_CAMIF_ERROR) {
 		pr_err("vfe40_irq: camif errors\n");
 		reg_value = msm_camera_io_r(
 			axi_ctrl->share_ctrl->vfebase + VFE_CAMIF_STATUS);
+		v4l2_subdev_notify(&axi_ctrl->subdev,
+			NOTIFY_VFE_CAMIF_ERROR, (void *)NULL);
 		pr_err("camifStatus  = 0x%x\n", reg_value);
 		vfe40_send_isp_msg(&axi_ctrl->subdev,
 			axi_ctrl->share_ctrl->vfeFrameId, MSG_ID_CAMIF_ERROR);
@@ -2722,12 +3577,36 @@
 	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_STATS_BE_BUS_OVFL)
+		pr_err("vfe40_irq: be stats bus overflow\n");
+
+	if (errStatus & VFE40_IMASK_STATS_BG_BUS_OVFL)
+		pr_err("vfe40_irq: bg stats bus overflow\n");
+
+	if (errStatus & VFE40_IMASK_STATS_BF_BUS_OVFL)
+		pr_err("vfe40_irq: 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");
+}
+
+static void vfe40_process_common_error_irq(
+	struct axi_ctrl_t *axi_ctrl, uint32_t errStatus)
+{
+	if (errStatus & VFE40_IMASK_BUS_BDG_HALT_ACK)
+		pr_err("vfe40_irq: BUS BDG HALT ACK\n");
 
 	if (errStatus & VFE40_IMASK_IMG_MAST_0_BUS_OVFL)
 		pr_err("vfe40_irq: image master 0 bus overflow\n");
@@ -2750,29 +3629,294 @@
 	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");
+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 inst_handle)
+{
+	struct isp_msg_output msg;
 
-	if (errStatus & VFE40_IMASK_STATS_AWB_BUS_OVFL)
-		pr_err("vfe40_irq: awb stats bus overflow\n");
+	msg.output_id = msgid;
+	msg.buf.inst_handle = inst_handle;
+	msg.buf.ch_paddr[0]	= ch0_paddr;
+	msg.buf.ch_paddr[1]	= ch1_paddr;
+	msg.buf.ch_paddr[2]	= ch2_paddr;
+	switch (msgid) {
+	case MSG_ID_OUTPUT_TERTIARY1:
+		msg.frameCounter = axi_ctrl->share_ctrl->rdi0FrameId;
+		break;
+	case MSG_ID_OUTPUT_TERTIARY2:
+		msg.frameCounter = axi_ctrl->share_ctrl->rdi1FrameId;
+		break;
+	default:
+		msg.frameCounter = axi_ctrl->share_ctrl->vfeFrameId;
+		break;
+	}
 
-	if (errStatus & VFE40_IMASK_STATS_RS_BUS_OVFL)
-		pr_err("vfe40_irq: rs stats bus overflow\n");
+	v4l2_subdev_notify(&axi_ctrl->subdev,
+			NOTIFY_VFE_MSG_OUT,
+			&msg);
+	return;
+}
 
-	if (errStatus & VFE40_IMASK_STATS_CS_BUS_OVFL)
-		pr_err("vfe40_irq: cs stats bus overflow\n");
+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;
 
-	if (errStatus & VFE40_IMASK_STATS_IHIST_BUS_OVFL)
-		pr_err("vfe40_irq: ihist stats bus overflow\n");
+	free_buf = vfe40_check_free_buffer(VFE_MSG_OUTPUT_IRQ,
+		VFE_MSG_OUTPUT_PRIMARY, axi_ctrl);
 
-	if (errStatus & VFE40_IMASK_STATS_SKIN_BHIST_BUS_OVFL)
-		pr_err("vfe40_irq: skin/bhist stats bus overflow\n");
+	/* 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 (errStatus & VFE40_IMASK_AXI_ERROR)
-		pr_err("vfe40_irq: axi error\n");
+	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.inst_handle);
+
+	} 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.inst_handle);
+
+	} else {
+		axi_ctrl->share_ctrl->outpath.out1.frame_drop_cnt++;
+		CDBG("path_irq_1 - no free buffer!\n");
+	}
+}
+
+static void vfe40_process_output_path_irq_rdi0(
+			struct axi_ctrl_t *axi_ctrl)
+{
+	uint32_t ping_pong;
+	uint32_t ch0_paddr = 0;
+	/* this must be rdi image output. */
+	struct msm_free_buf *free_buf = NULL;
+	/*RDI0*/
+	if (axi_ctrl->share_ctrl->operation_mode & VFE_OUTPUTS_RDI0) {
+		free_buf = vfe40_check_free_buffer(VFE_MSG_OUTPUT_IRQ,
+			VFE_MSG_OUTPUT_TERTIARY1, axi_ctrl);
+		if (free_buf) {
+			ping_pong = msm_camera_io_r(axi_ctrl->
+				share_ctrl->vfebase +
+				VFE_BUS_PING_PONG_STATUS);
+
+			/* Y only channel */
+			ch0_paddr = vfe40_get_ch_addr(ping_pong,
+				axi_ctrl->share_ctrl->vfebase,
+				axi_ctrl->share_ctrl->outpath.out2.ch0);
+
+			pr_debug("%s ch0 = 0x%x\n",
+				__func__, ch0_paddr);
+
+			/* Y channel */
+			vfe40_put_ch_addr(ping_pong,
+				axi_ctrl->share_ctrl->vfebase,
+				axi_ctrl->share_ctrl->outpath.out2.ch0,
+				free_buf->ch_paddr[0]);
+
+			vfe_send_outmsg(axi_ctrl,
+				MSG_ID_OUTPUT_TERTIARY1, ch0_paddr,
+				0, 0,
+				axi_ctrl->share_ctrl->outpath.out2.inst_handle);
+
+		} else {
+			axi_ctrl->share_ctrl->outpath.out2.frame_drop_cnt++;
+			pr_err("path_irq_2 irq - no free buffer for rdi0!\n");
+		}
+	}
+}
+
+static void vfe40_process_output_path_irq_rdi1(
+	struct axi_ctrl_t *axi_ctrl)
+{
+	uint32_t ping_pong;
+	uint32_t ch0_paddr = 0;
+	/* this must be rdi image output. */
+	struct msm_free_buf *free_buf = NULL;
+	/*RDI1*/
+	if (axi_ctrl->share_ctrl->operation_mode & VFE_OUTPUTS_RDI1) {
+		free_buf = vfe40_check_free_buffer(VFE_MSG_OUTPUT_IRQ,
+			VFE_MSG_OUTPUT_TERTIARY2, axi_ctrl);
+		if (free_buf) {
+			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.out3.ch0);
+			pr_debug("%s ch0 = 0x%x\n",
+				__func__, ch0_paddr);
+
+			/* Y channel */
+			vfe40_put_ch_addr(ping_pong,
+				axi_ctrl->share_ctrl->vfebase,
+				axi_ctrl->share_ctrl->outpath.out3.ch0,
+				free_buf->ch_paddr[0]);
+
+			vfe_send_outmsg(axi_ctrl,
+				MSG_ID_OUTPUT_TERTIARY2, ch0_paddr,
+				0, 0,
+				axi_ctrl->share_ctrl->outpath.out3.inst_handle);
+		} else {
+			axi_ctrl->share_ctrl->outpath.out3.frame_drop_cnt++;
+			pr_err("path_irq irq - no free buffer for rdi1!\n");
+		}
+	}
 }
 
 static uint32_t  vfe40_process_stats_irq_common(
@@ -2799,8 +3943,8 @@
 	return returnAddr;
 }
 
-static void
-vfe_send_stats_msg(struct vfe40_ctrl_type *vfe40_ctrl,
+static void vfe_send_stats_msg(
+	struct vfe40_ctrl_type *vfe40_ctrl,
 	uint32_t bufAddress, uint32_t statsNum)
 {
 	int rc = 0;
@@ -2809,24 +3953,36 @@
 	/* @todo This is causing issues, need further investigate */
 	/* spin_lock_irqsave(&ctrl->state_lock, flags); */
 	struct isp_msg_stats msgStats;
+	uint32_t stats_type;
 	msgStats.frameCounter = vfe40_ctrl->share_ctrl->vfeFrameId;
+	if (vfe40_ctrl->simultaneous_sof_stat)
+		msgStats.frameCounter--;
 	msgStats.buffer = bufAddress;
-
 	switch (statsNum) {
 	case statsAeNum:{
-		msgStats.id = MSG_ID_STATS_AEC;
+		msgStats.id =
+			(!vfe40_use_bayer_stats(vfe40_ctrl)) ? MSG_ID_STATS_AEC
+				: MSG_ID_STATS_BG;
+		stats_type =
+			(!vfe40_use_bayer_stats(vfe40_ctrl)) ?
+				MSM_STATS_TYPE_AEC : MSM_STATS_TYPE_BG;
 		rc = vfe40_ctrl->stats_ops.dispatch(
 				vfe40_ctrl->stats_ops.stats_ctrl,
-				MSM_STATS_TYPE_AEC, bufAddress,
+				stats_type, bufAddress,
 				&msgStats.buf_idx, &vaddr, &msgStats.fd,
 				vfe40_ctrl->stats_ops.client);
 		}
 		break;
 	case statsAfNum:{
-		msgStats.id = MSG_ID_STATS_AF;
+		msgStats.id =
+			(!vfe40_use_bayer_stats(vfe40_ctrl)) ? MSG_ID_STATS_AF
+				: MSG_ID_STATS_BF;
+		stats_type =
+			(!vfe40_use_bayer_stats(vfe40_ctrl)) ? MSM_STATS_TYPE_AF
+				: MSM_STATS_TYPE_BF;
 		rc = vfe40_ctrl->stats_ops.dispatch(
 				vfe40_ctrl->stats_ops.stats_ctrl,
-				MSM_STATS_TYPE_AF, bufAddress,
+				stats_type, bufAddress,
 				&msgStats.buf_idx, &vaddr, &msgStats.fd,
 				vfe40_ctrl->stats_ops.client);
 		}
@@ -2868,6 +4024,15 @@
 				vfe40_ctrl->stats_ops.client);
 		}
 		break;
+	case statsSkinNum: {
+		msgStats.id = MSG_ID_STATS_BHIST;
+		rc = vfe40_ctrl->stats_ops.dispatch(
+				vfe40_ctrl->stats_ops.stats_ctrl,
+				MSM_STATS_TYPE_BHIST, bufAddress,
+				&msgStats.buf_idx, &vaddr, &msgStats.fd,
+				vfe40_ctrl->stats_ops.client);
+		}
+		break;
 
 	default:
 		goto stats_done;
@@ -2882,7 +4047,7 @@
 			 __func__, msgStats.id, msgStats.buffer);
 	}
 stats_done:
-	spin_unlock_irqrestore(&ctrl->state_lock, flags);
+	/* spin_unlock_irqrestore(&ctrl->state_lock, flags); */
 	return;
 }
 
@@ -2893,11 +4058,14 @@
 	uint32_t temp;
 
 	msgStats.frame_id = vfe40_ctrl->share_ctrl->vfeFrameId;
+	if (vfe40_ctrl->simultaneous_sof_stat)
+		msgStats.frame_id--;
+
 	msgStats.status_bits = status_bits;
 
-	msgStats.aec.buff = vfe40_ctrl->aecStatsControl.bufToRender;
+	msgStats.aec.buff = vfe40_ctrl->aecbgStatsControl.bufToRender;
 	msgStats.awb.buff = vfe40_ctrl->awbStatsControl.bufToRender;
-	msgStats.af.buff = vfe40_ctrl->afStatsControl.bufToRender;
+	msgStats.af.buff = vfe40_ctrl->afbfStatsControl.bufToRender;
 
 	msgStats.ihist.buff = vfe40_ctrl->ihistStatsControl.bufToRender;
 	msgStats.rs.buff = vfe40_ctrl->rsStatsControl.bufToRender;
@@ -2912,6 +4080,31 @@
 				&msgStats);
 }
 
+static void vfe40_process_stats_bg_irq(struct vfe40_ctrl_type *vfe40_ctrl)
+{
+	unsigned long flags;
+	uint32_t addr;
+	uint32_t stats_type;
+	stats_type =
+		(!vfe40_use_bayer_stats(vfe40_ctrl)) ? MSM_STATS_TYPE_AEC
+			: MSM_STATS_TYPE_BG;
+	spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, stats_type);
+	spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+	if (addr) {
+		vfe40_ctrl->aecbgStatsControl.bufToRender =
+			vfe40_process_stats_irq_common(vfe40_ctrl, statsAeNum,
+			addr);
+
+		vfe_send_stats_msg(vfe40_ctrl,
+			vfe40_ctrl->aecbgStatsControl.bufToRender, statsAeNum);
+	} else{
+		vfe40_ctrl->aecbgStatsControl.droppedStatsFrameCount++;
+		CDBG("%s: droppedStatsFrameCount = %d", __func__,
+			vfe40_ctrl->aecbgStatsControl.droppedStatsFrameCount);
+	}
+}
+
 static void vfe40_process_stats_awb_irq(struct vfe40_ctrl_type *vfe40_ctrl)
 {
 	unsigned long flags;
@@ -2933,6 +4126,53 @@
 	}
 }
 
+static void vfe40_process_stats_bf_irq(struct vfe40_ctrl_type *vfe40_ctrl)
+{
+	unsigned long flags;
+	uint32_t addr;
+	uint32_t stats_type;
+	stats_type =
+		(!vfe40_use_bayer_stats(vfe40_ctrl)) ? MSM_STATS_TYPE_AF
+			: MSM_STATS_TYPE_BF;
+	spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, stats_type);
+	spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+	if (addr) {
+		vfe40_ctrl->afbfStatsControl.bufToRender =
+			vfe40_process_stats_irq_common(vfe40_ctrl, statsAfNum,
+			addr);
+
+		vfe_send_stats_msg(vfe40_ctrl,
+			vfe40_ctrl->afbfStatsControl.bufToRender, statsAfNum);
+	} else{
+		vfe40_ctrl->afbfStatsControl.droppedStatsFrameCount++;
+		CDBG("%s: droppedStatsFrameCount = %d", __func__,
+			vfe40_ctrl->afbfStatsControl.droppedStatsFrameCount);
+	}
+}
+
+static void vfe40_process_stats_bhist_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_BHIST);
+	spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+	if (addr) {
+		vfe40_ctrl->bhistStatsControl.bufToRender =
+			vfe40_process_stats_irq_common(vfe40_ctrl,
+				statsSkinNum, addr);
+
+		vfe_send_stats_msg(vfe40_ctrl,
+			vfe40_ctrl->bhistStatsControl.bufToRender,
+			statsSkinNum);
+	} else{
+		vfe40_ctrl->bhistStatsControl.droppedStatsFrameCount++;
+		CDBG("%s: droppedStatsFrameCount = %d", __func__,
+			vfe40_ctrl->bhistStatsControl.droppedStatsFrameCount);
+	}
+}
+
 static void vfe40_process_stats_ihist_irq(struct vfe40_ctrl_type *vfe40_ctrl)
 {
 	unsigned long flags;
@@ -2988,8 +4228,9 @@
 			vfe40_process_stats_irq_common(vfe40_ctrl, statsCsNum,
 			addr);
 
-		vfe_send_stats_msg(vfe40_ctrl,
-			vfe40_ctrl->csStatsControl.bufToRender, statsCsNum);
+			vfe_send_stats_msg(vfe40_ctrl,
+				vfe40_ctrl->csStatsControl.bufToRender,
+				statsCsNum);
 	} else {
 		vfe40_ctrl->csStatsControl.droppedStatsFrameCount++;
 		CDBG("%s: droppedStatsFrameCount = %d", __func__,
@@ -3003,9 +4244,30 @@
 	unsigned long flags;
 	int32_t process_stats = false;
 	uint32_t addr;
+	uint32_t stats_type;
 
 	CDBG("%s, stats = 0x%x\n", __func__, status_bits);
 	spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+	stats_type =
+		(!vfe40_use_bayer_stats(vfe40_ctrl)) ? MSM_STATS_TYPE_AEC
+			: MSM_STATS_TYPE_BG;
+
+	if (status_bits & VFE_IRQ_STATUS0_STATS_BG) {
+		addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl,
+				stats_type);
+		if (addr) {
+			vfe40_ctrl->aecbgStatsControl.bufToRender =
+				vfe40_process_stats_irq_common(
+				vfe40_ctrl, statsAeNum,	addr);
+			process_stats = true;
+		} else{
+			vfe40_ctrl->aecbgStatsControl.bufToRender = 0;
+			vfe40_ctrl->aecbgStatsControl.droppedStatsFrameCount++;
+		}
+	} else {
+		vfe40_ctrl->aecbgStatsControl.bufToRender = 0;
+	}
+
 	if (status_bits & VFE_IRQ_STATUS0_STATS_AWB) {
 		addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl,
 			MSM_STATS_TYPE_AWB);
@@ -3023,6 +4285,26 @@
 		vfe40_ctrl->awbStatsControl.bufToRender = 0;
 	}
 
+	stats_type =
+		(!vfe40_use_bayer_stats(vfe40_ctrl)) ? MSM_STATS_TYPE_AF
+			: MSM_STATS_TYPE_BF;
+	if (status_bits & VFE_IRQ_STATUS0_STATS_BF) {
+		addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl,
+					stats_type);
+		if (addr) {
+			vfe40_ctrl->afbfStatsControl.bufToRender =
+				vfe40_process_stats_irq_common(
+				vfe40_ctrl, statsAfNum,
+				addr);
+			process_stats = true;
+		} else {
+			vfe40_ctrl->afbfStatsControl.bufToRender = 0;
+			vfe40_ctrl->afbfStatsControl.droppedStatsFrameCount++;
+		}
+	} else {
+		vfe40_ctrl->afbfStatsControl.bufToRender = 0;
+	}
+
 	if (status_bits & VFE_IRQ_STATUS0_STATS_IHIST) {
 		addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl,
 					MSM_STATS_TYPE_IHIST);
@@ -3084,7 +4366,6 @@
 	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)) {
@@ -3114,14 +4395,34 @@
 		CDBG("irq	regUpdateIrq\n");
 		vfe40_process_reg_update_irq(vfe40_ctrl);
 		break;
+	case VFE_IRQ_STATUS0_RDI0_REG_UPDATE:
+		CDBG("irq	rdi0 regUpdateIrq\n");
+		vfe40_process_rdi0_reg_update_irq(vfe40_ctrl);
+		break;
+	case VFE_IRQ_STATUS0_RDI1_REG_UPDATE:
+		CDBG("irq	rdi1 regUpdateIrq\n");
+		vfe40_process_rdi1_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_BG:
+		CDBG("Stats BG irq occured.\n");
+		vfe40_process_stats_bg_irq(vfe40_ctrl);
+		break;
+	case VFE_IRQ_STATUS0_STATS_BF:
+		CDBG("Stats BF irq occured.\n");
+		vfe40_process_stats_bf_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_SKIN_BHIST:
+		CDBG("Stats BHIST irq occured.\n");
+		vfe40_process_stats_bhist_irq(vfe40_ctrl);
+		break;
 	case VFE_IRQ_STATUS0_STATS_IHIST:
 		CDBG("Stats IHIST irq occured.\n");
 		vfe40_process_stats_ihist_irq(vfe40_ctrl);
@@ -3161,15 +4462,17 @@
 {
 	unsigned long flags;
 	struct axi_ctrl_t *axi_ctrl = (struct axi_ctrl_t *)data;
+	struct vfe40_ctrl_type *vfe40_ctrl = axi_ctrl->share_ctrl->vfe40_ctrl;
 	struct vfe40_isr_queue_cmd *qcmd = NULL;
+	int stat_interrupt;
 
 	CDBG("=== axi40_do_tasklet start ===\n");
 
-	while (atomic_read(&axi_ctrl->share_ctrl->irq_cnt)) {
+	while (atomic_read(&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);
+		atomic_sub(1, &irq_cnt);
 
 		if (!qcmd) {
 			spin_unlock_irqrestore(&axi_ctrl->tasklet_lock,
@@ -3181,38 +4484,82 @@
 		spin_unlock_irqrestore(&axi_ctrl->tasklet_lock,
 			flags);
 
+		if (axi_ctrl->share_ctrl->stats_comp) {
+			stat_interrupt = (qcmd->vfeInterruptStatus0 &
+					VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK_0);
+		} else {
+			stat_interrupt =
+				(qcmd->vfeInterruptStatus0 &
+					VFE_IRQ_STATUS0_STATS_BG) |
+				(qcmd->vfeInterruptStatus0 &
+					VFE_IRQ_STATUS0_STATS_AWB) |
+				(qcmd->vfeInterruptStatus0 &
+					VFE_IRQ_STATUS0_STATS_BF) |
+				(qcmd->vfeInterruptStatus0 &
+					VFE_IRQ_STATUS0_STATS_IHIST) |
+				(qcmd->vfeInterruptStatus0 &
+					VFE_IRQ_STATUS0_STATS_RS) |
+				(qcmd->vfeInterruptStatus0 &
+					VFE_IRQ_STATUS0_STATS_CS);
+		}
 		if (qcmd->vfeInterruptStatus0 &
-				VFE_IRQ_STATUS0_CAMIF_SOF_MASK)
-			v4l2_subdev_notify(&axi_ctrl->subdev,
+				VFE_IRQ_STATUS0_CAMIF_SOF_MASK) {
+			if (stat_interrupt)
+				vfe40_ctrl->simultaneous_sof_stat = 1;
+			v4l2_subdev_notify(&vfe40_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,
+				VFE_IRQ_STATUS0_REG_UPDATE_MASK)
+			v4l2_subdev_notify(&vfe40_ctrl->subdev,
 				NOTIFY_VFE_IRQ,
 				(void *)VFE_IRQ_STATUS0_REG_UPDATE_MASK);
-		}
+
+		if (qcmd->vfeInterruptStatus1 &
+				VFE_IRQ_STATUS0_RDI0_REG_UPDATE_MASK)
+			v4l2_subdev_notify(&vfe40_ctrl->subdev,
+				NOTIFY_VFE_IRQ,
+				(void *)VFE_IRQ_STATUS0_RDI0_REG_UPDATE);
+
+		if (qcmd->vfeInterruptStatus1 &
+				VFE_IRQ_STATUS0_RDI1_REG_UPDATE_MASK)
+			v4l2_subdev_notify(&vfe40_ctrl->subdev,
+				NOTIFY_VFE_IRQ,
+				(void *)VFE_IRQ_STATUS0_RDI1_REG_UPDATE);
 
 		if (qcmd->vfeInterruptStatus0 &
 				VFE_IMASK_WHILE_STOPPING_0)
-			v4l2_subdev_notify(&axi_ctrl->subdev,
+			v4l2_subdev_notify(&vfe40_ctrl->subdev,
 				NOTIFY_VFE_IRQ,
 				(void *)VFE_IMASK_WHILE_STOPPING_0);
 
+		if (atomic_read(&axi_ctrl->share_ctrl->handle_common_irq)) {
+			if (qcmd->vfeInterruptStatus1 &
+					VFE40_IMASK_COMMON_ERROR_ONLY_1) {
+				pr_err("irq	errorIrq\n");
+				vfe40_process_common_error_irq(
+					axi_ctrl,
+					qcmd->vfeInterruptStatus1 &
+					VFE40_IMASK_COMMON_ERROR_ONLY_1);
+			}
+
+			v4l2_subdev_notify(&axi_ctrl->subdev,
+				NOTIFY_AXI_IRQ,
+				(void *)qcmd->vfeInterruptStatus0);
+		}
+
 		if (atomic_read(&axi_ctrl->share_ctrl->vstate)) {
 			if (qcmd->vfeInterruptStatus1 &
-					VFE40_IMASK_ERROR_ONLY_1) {
+					VFE40_IMASK_VFE_ERROR_ONLY_1) {
 				pr_err("irq	errorIrq\n");
 				vfe40_process_error_irq(
 					axi_ctrl,
 					qcmd->vfeInterruptStatus1 &
-					VFE40_IMASK_ERROR_ONLY_1);
+					VFE40_IMASK_VFE_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) {
@@ -3220,54 +4567,74 @@
 				if (qcmd->vfeInterruptStatus0 &
 					VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK_0) {
 					CDBG("Stats composite irq occured.\n");
-					v4l2_subdev_notify(&axi_ctrl->subdev,
+					v4l2_subdev_notify(&vfe40_ctrl->subdev,
 					NOTIFY_VFE_IRQ,
 					(void *)qcmd->vfeInterruptStatus0);
 				}
 			} else {
 				/* process individual stats interrupt. */
 				if (qcmd->vfeInterruptStatus0 &
+						VFE_IRQ_STATUS0_STATS_BG)
+					v4l2_subdev_notify(&vfe40_ctrl->subdev,
+					NOTIFY_VFE_IRQ,
+					(void *)VFE_IRQ_STATUS0_STATS_BG);
+
+				if (qcmd->vfeInterruptStatus0 &
 						VFE_IRQ_STATUS0_STATS_AWB)
-					v4l2_subdev_notify(&axi_ctrl->subdev,
+					v4l2_subdev_notify(&vfe40_ctrl->subdev,
 					NOTIFY_VFE_IRQ,
 					(void *)VFE_IRQ_STATUS0_STATS_AWB);
+
+				if (qcmd->vfeInterruptStatus0 &
+						VFE_IRQ_STATUS0_STATS_BF)
+					v4l2_subdev_notify(&vfe40_ctrl->subdev,
+					NOTIFY_VFE_IRQ,
+					(void *)VFE_IRQ_STATUS0_STATS_BF);
+				if (qcmd->vfeInterruptStatus0 &
+					VFE_IRQ_STATUS0_STATS_SKIN_BHIST)
+					v4l2_subdev_notify(&vfe40_ctrl->subdev,
+					NOTIFY_VFE_IRQ,
+					(void *)
+					VFE_IRQ_STATUS0_STATS_SKIN_BHIST);
+
 				if (qcmd->vfeInterruptStatus0 &
 						VFE_IRQ_STATUS0_STATS_IHIST)
-					v4l2_subdev_notify(&axi_ctrl->subdev,
+					v4l2_subdev_notify(&vfe40_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(&vfe40_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(&vfe40_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,
+					v4l2_subdev_notify(&vfe40_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,
+					v4l2_subdev_notify(&vfe40_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,
+					v4l2_subdev_notify(&vfe40_ctrl->subdev,
 					NOTIFY_VFE_IRQ,
 					(void *)VFE_IRQ_STATUS1_SYNC_TIMER2);
 			}
 		}
+		vfe40_ctrl->simultaneous_sof_stat = 0;
 		kfree(qcmd);
 	}
 	CDBG("=== axi40_do_tasklet end ===\n");
@@ -3312,16 +4679,26 @@
 	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);
+	atomic_add(1, &irq_cnt);
 	spin_unlock_irqrestore(&axi_ctrl->tasklet_lock, flags);
 	tasklet_schedule(&axi_ctrl->vfe40_tasklet);
 	return IRQ_HANDLED;
 }
 
+int msm_axi_subdev_isr_routine(struct v4l2_subdev *sd,
+	u32 status, bool *handled)
+{
+	struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd);
+	irqreturn_t ret;
+	CDBG("%s E ", __func__);
+	ret = vfe40_parse_irq(axi_ctrl->vfeirq->start, axi_ctrl);
+	*handled = TRUE;
+	return 0;
+}
 
 static long vfe_stats_bufq_sub_ioctl(
 	struct vfe40_ctrl_type *vfe_ctrl,
-	struct msm_vfe_cfg_cmd *cmd, void *ion_client)
+	struct msm_vfe_cfg_cmd *cmd, void *ion_client, int domain_num)
 {
 	long rc = 0;
 	switch (cmd->cmd_type) {
@@ -3370,7 +4747,7 @@
 	rc = vfe_ctrl->stats_ops.enqueue_buf(
 			&vfe_ctrl->stats_ctrl,
 			(struct msm_stats_buf_info *)cmd->value,
-			vfe_ctrl->stats_ops.client);
+			vfe_ctrl->stats_ops.client, domain_num);
 	break;
 	case VFE_CMD_STATS_FLUSH_BUFQ:
 	{
@@ -3391,6 +4768,22 @@
 			vfe_ctrl->stats_ops.client);
 	}
 	break;
+	case VFE_CMD_STATS_UNREGBUF:
+	{
+		struct msm_stats_reqbuf *req_buf = NULL;
+		req_buf = (struct msm_stats_reqbuf *)cmd->value;
+		if (sizeof(struct msm_stats_reqbuf) != cmd->length) {
+			/* error. the length not match */
+			pr_err("%s: stats reqbuf input size = %d,\n"
+				"struct size = %d, mitch match\n",
+				 __func__, cmd->length,
+				sizeof(struct msm_stats_reqbuf));
+			rc = -EINVAL ;
+			goto end;
+		}
+		rc = vfe40_stats_unregbuf(vfe_ctrl, req_buf, domain_num);
+	}
+	break;
 	default:
 		rc = -1;
 		pr_err("%s: cmd_type %d not supported", __func__,
@@ -3409,10 +4802,9 @@
 	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;
+	struct msm_camvfe_params *vfe_params;
+	struct msm_vfe_cfg_cmd *cmd;
+	void *data;
 
 	long rc = 0;
 	struct vfe_cmd_stats_buf *scfg = NULL;
@@ -3423,6 +4815,17 @@
 		return -EFAULT;
 	}
 
+	CDBG("%s\n", __func__);
+	if (subdev_cmd == VIDIOC_MSM_VFE_INIT) {
+		CDBG("%s init\n", __func__);
+		return msm_vfe_subdev_init(sd);
+	} else if (subdev_cmd == VIDIOC_MSM_VFE_RELEASE) {
+		msm_vfe_subdev_release(sd);
+		return 0;
+	}
+	vfe_params = (struct msm_camvfe_params *)arg;
+	cmd = vfe_params->vfe_cfg;
+	data = vfe_params->data;
 	switch (cmd->cmd_type) {
 	case CMD_VFE_PROCESS_IRQ:
 		vfe40_process_irq(vfe40_ctrl, (uint32_t) data);
@@ -3430,27 +4833,33 @@
 	case VFE_CMD_STATS_REQBUF:
 	case VFE_CMD_STATS_ENQUEUEBUF:
 	case VFE_CMD_STATS_FLUSH_BUFQ:
+	case VFE_CMD_STATS_UNREGBUF:
 		/* for easy porting put in one envelope */
 		rc = vfe_stats_bufq_sub_ioctl(vfe40_ctrl,
-				cmd, vfe_params->data);
+				cmd, vfe_params->data, pmctl->domain_num);
 		return rc;
 	default:
 		if (cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
-			cmd->cmd_type != CMD_CONFIG_PONG_ADDR &&
-			cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR &&
-			cmd->cmd_type != CMD_STATS_AEC_BUF_RELEASE &&
-			cmd->cmd_type != CMD_STATS_AWB_BUF_RELEASE &&
-			cmd->cmd_type != CMD_STATS_IHIST_BUF_RELEASE &&
-			cmd->cmd_type != CMD_STATS_RS_BUF_RELEASE &&
-			cmd->cmd_type != CMD_STATS_CS_BUF_RELEASE &&
-			cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE) {
-				if (copy_from_user(&vfecmd,
+		cmd->cmd_type != CMD_CONFIG_PONG_ADDR &&
+		cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR &&
+		cmd->cmd_type != CMD_STATS_AEC_BUF_RELEASE &&
+		cmd->cmd_type != CMD_STATS_AWB_BUF_RELEASE &&
+		cmd->cmd_type != CMD_STATS_IHIST_BUF_RELEASE &&
+		cmd->cmd_type != CMD_STATS_RS_BUF_RELEASE &&
+		cmd->cmd_type != CMD_STATS_CS_BUF_RELEASE &&
+		cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE &&
+		cmd->cmd_type != CMD_STATS_BG_BUF_RELEASE &&
+		cmd->cmd_type != CMD_STATS_BF_BUF_RELEASE &&
+		cmd->cmd_type != CMD_STATS_BHIST_BUF_RELEASE &&
+		cmd->cmd_type != CMD_VFE_PIX_SOF_COUNT_UPDATE &&
+		cmd->cmd_type != CMD_VFE_COUNT_PIX_SOF_ENABLE) {
+			if (copy_from_user(&vfecmd,
 					(void __user *)(cmd->value),
 					sizeof(vfecmd))) {
-						pr_err("%s %d: copy_from_user failed\n",
-							__func__, __LINE__);
-					return -EFAULT;
-				}
+				pr_err("%s %d: copy_from_user failed\n",
+					__func__, __LINE__);
+				return -EFAULT;
+			}
 		} else {
 			/* here eith stats release or frame release. */
 			if (cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
@@ -3472,6 +4881,25 @@
 				sack->nextStatsBuf = *(uint32_t *)data;
 			}
 		}
+	}
+
+	CDBG("%s: cmdType = %d\n", __func__, cmd->cmd_type);
+
+	if ((cmd->cmd_type == CMD_STATS_AF_ENABLE)    ||
+		(cmd->cmd_type == CMD_STATS_AWB_ENABLE)   ||
+		(cmd->cmd_type == CMD_STATS_IHIST_ENABLE) ||
+		(cmd->cmd_type == CMD_STATS_RS_ENABLE)    ||
+		(cmd->cmd_type == CMD_STATS_CS_ENABLE)    ||
+		(cmd->cmd_type == CMD_STATS_AEC_ENABLE)   ||
+		(cmd->cmd_type == CMD_STATS_BG_ENABLE)    ||
+		(cmd->cmd_type == CMD_STATS_BF_ENABLE)    ||
+		(cmd->cmd_type == CMD_STATS_BHIST_ENABLE)) {
+		struct axidata *axid;
+		axid = data;
+		if (!axid) {
+			rc = -EFAULT;
+			goto vfe40_config_done;
+		}
 		CDBG("%s: cmdType = %d\n", __func__, cmd->cmd_type);
 
 		if ((cmd->cmd_type == CMD_STATS_AF_ENABLE)    ||
@@ -3485,39 +4913,69 @@
 				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;
+		case CMD_STATS_AEC_ENABLE:
+		case CMD_STATS_BG_ENABLE:
+		case CMD_STATS_BF_ENABLE:
+		case CMD_STATS_BHIST_ENABLE:
+		case CMD_STATS_AWB_ENABLE:
+		case CMD_STATS_IHIST_ENABLE:
+		case CMD_STATS_RS_ENABLE:
+		case CMD_STATS_CS_ENABLE:
 		default:
-			pr_err("%s Unsupported AXI configuration %x ", __func__,
-				cmd->cmd_type);
-		break;
+			pr_err("%s Unsupported cmd type %d",
+				__func__, cmd->cmd_type);
+			break;
 		}
+		goto vfe40_config_done;
+	}
+	switch (cmd->cmd_type) {
+	case CMD_GENERAL:
+		rc = vfe40_proc_general(pmctl, &vfecmd, vfe40_ctrl);
+	break;
+	case CMD_VFE_COUNT_PIX_SOF_ENABLE: {
+		int enable = *((int *)cmd->value);
+		if (enable)
+			vfe40_ctrl->vfe_sof_count_enable = TRUE;
+		else
+			vfe40_ctrl->vfe_sof_count_enable = false;
+	}
+	break;
+	case CMD_VFE_PIX_SOF_COUNT_UPDATE:
+		if (!vfe40_ctrl->vfe_sof_count_enable)
+			vfe40_ctrl->share_ctrl->vfeFrameId =
+			*((uint32_t *)vfe_params->data);
+	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);
@@ -3526,6 +4984,39 @@
 	return rc;
 }
 
+static struct msm_cam_clk_info vfe40_clk_info[] = {
+	{"camss_top_ahb_clk", -1},
+	{"vfe_clk_src", 266670000},
+	{"camss_vfe_vfe_clk", -1},
+	{"camss_csi_vfe_clk", -1},
+	{"iface_clk", -1},
+	{"bus_clk", -1},
+	{"alt_bus_clk", -1},
+};
+
+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[1], freq);
+	if (rc < 0) {
+		pr_err("%s: clk_round_rate failed %d\n",
+					__func__, rc);
+		return rc;
+	}
+
+	vfe_clk_rate = round_rate;
+	rc = clk_set_rate(axi_ctrl->vfe_clk[1], round_rate);
+	if (rc < 0)
+		pr_err("%s: clk_set_rate failed %d\n",
+					__func__, rc);
+
+	return rc;
+}
+
 static const struct v4l2_subdev_core_ops msm_vfe_subdev_core_ops = {
 	.ioctl = msm_vfe_subdev_ioctl,
 };
@@ -3534,46 +5025,1103 @@
 	.core = &msm_vfe_subdev_core_ops,
 };
 
-int msm_vfe_subdev_init(struct v4l2_subdev *sd,
-			struct msm_cam_media_controller *mctl)
+static void msm_vfe40_init_vbif_parms(void __iomem *vfe_vbif_base)
+{
+	msm_camera_io_w_mb(0x1,
+		vfe_vbif_base + VFE40_VBIF_CLKON);
+	msm_camera_io_w_mb(0x1,
+		vfe_vbif_base + VFE40_VBIF_ROUND_ROBIN_QOS_ARB);
+	msm_camera_io_w_mb(0xFFFF,
+		vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO_EN);
+	msm_camera_io_w_mb(0xFFFFFFFF,
+		vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO);
+
+	msm_camera_io_w_mb(0x10101010,
+		vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF0);
+	msm_camera_io_w_mb(0x10101010,
+		vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF1);
+	msm_camera_io_w_mb(0x10101010,
+		vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF2);
+	msm_camera_io_w_mb(0x10101010,
+		vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF0);
+	msm_camera_io_w_mb(0x10101010,
+		vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF1);
+	msm_camera_io_w_mb(0x10101010,
+		vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF2);
+	msm_camera_io_w_mb(0x00001010,
+		vfe_vbif_base + VFE40_VBIF_OUT_RD_LIM_CONF0);
+	msm_camera_io_w_mb(0x00001010,
+		vfe_vbif_base + VFE40_VBIF_OUT_WR_LIM_CONF0);
+	msm_camera_io_w_mb(0x00000707,
+		vfe_vbif_base + VFE40_VBIF_DDR_OUT_MAX_BURST);
+	msm_camera_io_w_mb(0x00000030,
+		vfe_vbif_base + VFE40_VBIF_ARB_CTL);
+	msm_camera_io_w_mb(0x04210842,
+		vfe_vbif_base + VFE40_VBIF_DDR_ARB_CONF0);
+	msm_camera_io_w_mb(0x04210842,
+		vfe_vbif_base + VFE40_VBIF_DDR_ARB_CONF1);
+}
+
+int msm_axi_subdev_init(struct v4l2_subdev *sd)
+{
+	int rc = 0;
+	struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd);
+	struct msm_cam_media_controller *mctl;
+	mctl = v4l2_get_subdev_hostdata(sd);
+	if (mctl == NULL) {
+		pr_err("%s: mctl is NULL\n", __func__);
+		rc = -EINVAL;
+		goto mctl_failed;
+	}
+	axi_ctrl->share_ctrl->axi_ref_cnt++;
+	if (axi_ctrl->share_ctrl->axi_ref_cnt > 1)
+		return rc;
+
+	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;
+	}
+
+	axi_ctrl->share_ctrl->vfe_vbif_base =
+		ioremap(axi_ctrl->vfe_vbif_mem->start,
+			resource_size(axi_ctrl->vfe_vbif_mem));
+	if (!axi_ctrl->share_ctrl->vfe_vbif_base) {
+		rc = -ENOMEM;
+		pr_err("%s: vfe ioremap failed\n", __func__);
+		goto remap_failed;
+	}
+
+	if (axi_ctrl->fs_vfe) {
+		rc = regulator_enable(axi_ctrl->fs_vfe);
+		if (rc) {
+			pr_err("%s: Regulator enable failed\n",	__func__);
+			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;
+
+	axi_ctrl->bus_perf_client =
+		msm_bus_scale_register_client(&vfe_bus_client_pdata);
+	if (!axi_ctrl->bus_perf_client) {
+		pr_err("%s: Registration Failed!\n", __func__);
+		axi_ctrl->bus_perf_client = 0;
+		goto bus_scale_register_failed;
+	}
+
+	msm_camera_bus_scale_cfg(axi_ctrl->bus_perf_client, S_PREVIEW);
+
+	rc = iommu_attach_device(mctl->domain, axi_ctrl->iommu_ctx);
+	if (rc < 0) {
+		pr_err("%s: imgwr attach failed rc = %d\n", __func__, rc);
+		rc = -ENODEV;
+		goto device_imgwr_attach_failed;
+	}
+
+	msm_vfe40_init_vbif_parms(axi_ctrl->share_ctrl->vfe_vbif_base);
+
+	axi_ctrl->share_ctrl->register_total = VFE40_REGISTER_TOTAL;
+
+	spin_lock_init(&axi_ctrl->share_ctrl->stop_flag_lock);
+	spin_lock_init(&axi_ctrl->share_ctrl->update_ack_lock);
+	spin_lock_init(&axi_ctrl->share_ctrl->start_ack_lock);
+	init_completion(&axi_ctrl->share_ctrl->reset_complete);
+
+	if (!axi_ctrl->use_irq_router)
+		enable_irq(axi_ctrl->vfeirq->start);
+
+	return rc;
+
+bus_scale_register_failed:
+	msm_cam_clk_enable(&axi_ctrl->pdev->dev, vfe40_clk_info,
+		axi_ctrl->vfe_clk, ARRAY_SIZE(vfe40_clk_info), 0);
+clk_enable_failed:
+	if (axi_ctrl->fs_vfe)
+		regulator_disable(axi_ctrl->fs_vfe);
+fs_failed:
+	iounmap(axi_ctrl->share_ctrl->vfebase);
+	axi_ctrl->share_ctrl->vfebase = NULL;
+remap_failed:
+	iommu_detach_device(mctl->domain, axi_ctrl->iommu_ctx);
+device_imgwr_attach_failed:
+	if (!axi_ctrl->use_irq_router)
+		disable_irq(axi_ctrl->vfeirq->start);
+mctl_failed:
+	return rc;
+}
+
+int msm_vfe_subdev_init(struct v4l2_subdev *sd)
 {
 	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->vfe_sof_count_enable = true;
 	vfe40_ctrl->hfr_mode = HFR_MODE_OFF;
 
+	memset(&vfe40_ctrl->stats_ctrl, 0,
+		   sizeof(struct msm_stats_bufq_ctrl));
+	memset(&vfe40_ctrl->stats_ops, 0, sizeof(struct msm_stats_ops));
+
 	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__);
+	axi_ctrl->share_ctrl->axi_ref_cnt--;
+	if (axi_ctrl->share_ctrl->axi_ref_cnt > 0)
+		return;
+	if (!axi_ctrl->use_irq_router)
+		disable_irq(axi_ctrl->vfeirq->start);
+	tasklet_kill(&axi_ctrl->vfe40_tasklet);
+
+	iommu_detach_device(pmctl->domain, axi_ctrl->iommu_ctx);
+
+	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);
+
+	iounmap(axi_ctrl->share_ctrl->vfebase);
+	iounmap(axi_ctrl->share_ctrl->vfe_vbif_base);
+	axi_ctrl->share_ctrl->vfebase = NULL;
+
+	if (atomic_read(&irq_cnt))
+		pr_warning("%s, Warning IRQ Count not ZERO\n", __func__);
+
+	msm_camera_bus_scale_cfg(axi_ctrl->bus_perf_client, S_EXIT);
+	axi_ctrl->bus_perf_client = 0;
+
+	msm_vfe_subdev_release(&axi_ctrl->share_ctrl->vfe40_ctrl->subdev);
+}
+
 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;
+	CDBG("vfe subdev release %p\n",
+		vfe40_ctrl->share_ctrl->vfebase);
 }
 
+void axi_abort(struct axi_ctrl_t *axi_ctrl)
+{
+	uint8_t  axi_busy_flag = true;
+	unsigned long flags;
+	/* axi halt command. */
+
+	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);
+	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(0x80000000,
+		axi_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_0);
+	msm_camera_io_w(0xF0000000,
+		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);
+	if (axi_ctrl->share_ctrl->sync_abort)
+		wait_for_completion_interruptible(
+			&axi_ctrl->share_ctrl->reset_complete);
+}
+
+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;
+	uint32_t reg_update = 0;
+	uint16_t operation_mode =
+		(axi_ctrl->share_ctrl->current_mode &
+		~(VFE_OUTPUTS_RDI0|VFE_OUTPUTS_RDI1));
+	rc = axi_config_buffers(axi_ctrl, vfe_params);
+	if (rc < 0)
+		return;
+
+	switch (vfe_params.cmd_type) {
+	case AXI_CMD_PREVIEW:
+		msm_camera_bus_scale_cfg(axi_ctrl->bus_perf_client, S_PREVIEW);
+		break;
+	case AXI_CMD_CAPTURE:
+	case AXI_CMD_RAW_CAPTURE:
+		msm_camera_bus_scale_cfg(axi_ctrl->bus_perf_client, S_CAPTURE);
+		break;
+	case AXI_CMD_RECORD:
+		msm_camera_bus_scale_cfg(axi_ctrl->bus_perf_client, S_VIDEO);
+		return;
+	case AXI_CMD_ZSL:
+		msm_camera_bus_scale_cfg(axi_ctrl->bus_perf_client, S_ZSL);
+		break;
+	case AXI_CMD_LIVESHOT:
+		msm_camera_bus_scale_cfg(axi_ctrl->bus_perf_client, S_LIVESHOT);
+		return;
+	default:
+		return;
+	}
+
+	irq_comp_mask =
+		msm_camera_io_r(axi_ctrl->share_ctrl->vfebase +
+			VFE_IRQ_COMP_MASK);
+	irq_mask = msm_camera_io_r(axi_ctrl->share_ctrl->vfebase +
+			VFE_IRQ_MASK_0);
+
+	if (axi_ctrl->share_ctrl->outpath.output_mode &
+			VFE40_OUTPUT_MODE_PRIMARY) {
+		if (vfe_params.cmd_type == AXI_CMD_RAW_CAPTURE) {
+			irq_comp_mask |=
+				0x1 << axi_ctrl->share_ctrl->outpath.out0.ch0;
+		} else {
+			irq_comp_mask |= (
+				0x1 << axi_ctrl->share_ctrl->outpath.out0.ch0 |
+				0x1 << axi_ctrl->share_ctrl->outpath.out0.ch1);
+		}
+		irq_mask |= VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK;
+	} else if (axi_ctrl->share_ctrl->outpath.output_mode &
+			   VFE40_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
+		irq_comp_mask |= (
+			0x1 << axi_ctrl->share_ctrl->outpath.out0.ch0 |
+			0x1 << axi_ctrl->share_ctrl->outpath.out0.ch1 |
+			0x1 << axi_ctrl->share_ctrl->outpath.out0.ch2);
+		irq_mask |= VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK;
+	}
+	if (axi_ctrl->share_ctrl->outpath.output_mode &
+			VFE40_OUTPUT_MODE_SECONDARY) {
+		irq_comp_mask |= (
+			0x1 << (axi_ctrl->share_ctrl->outpath.out1.ch0 + 8) |
+			0x1 << (axi_ctrl->share_ctrl->outpath.out1.ch1 + 8));
+		irq_mask |= VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE1_MASK;
+	} else if (axi_ctrl->share_ctrl->outpath.output_mode &
+			VFE40_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
+		irq_comp_mask |= (
+			0x1 << (axi_ctrl->share_ctrl->outpath.out1.ch0 + 8) |
+			0x1 << (axi_ctrl->share_ctrl->outpath.out1.ch1 + 8) |
+			0x1 << (axi_ctrl->share_ctrl->outpath.out1.ch2 + 8));
+		irq_mask |= VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE1_MASK;
+	}
+	if (axi_ctrl->share_ctrl->outpath.output_mode &
+		VFE40_OUTPUT_MODE_TERTIARY1) {
+		irq_mask |= (0x1 << (axi_ctrl->share_ctrl->outpath.out2.ch0 +
+			VFE_WM_OFFSET));
+	}
+	if (axi_ctrl->share_ctrl->outpath.output_mode &
+		VFE40_OUTPUT_MODE_TERTIARY2) {
+		irq_mask |= (0x1 << (axi_ctrl->share_ctrl->outpath.out3.ch0 +
+			VFE_WM_OFFSET));
+	}
+
+	msm_camera_io_w(irq_comp_mask,
+		axi_ctrl->share_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+	msm_camera_io_w(irq_mask, axi_ctrl->share_ctrl->vfebase +
+			VFE_IRQ_MASK_0);
+
+	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 &
+				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;
+			}
+		}
+		break;
+	default:
+		if (axi_ctrl->share_ctrl->outpath.output_mode &
+			VFE40_OUTPUT_MODE_PRIMARY) {
+			if (vfe_params.cmd_type == AXI_CMD_RAW_CAPTURE) {
+				msm_camera_io_w(1,
+					axi_ctrl->share_ctrl->vfebase +
+					vfe40_AXI_WM_CFG[axi_ctrl->
+					share_ctrl->outpath.out0.ch0]);
+			} else {
+				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]);
+		}
+
+		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;
+	}
+
+	if (axi_ctrl->share_ctrl->current_mode & VFE_OUTPUTS_RDI0)
+		msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
+			vfe40_AXI_WM_CFG[axi_ctrl->share_ctrl->
+			outpath.out2.ch0]);
+	if (axi_ctrl->share_ctrl->current_mode & VFE_OUTPUTS_RDI1)
+		msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
+			vfe40_AXI_WM_CFG[axi_ctrl->share_ctrl->
+			outpath.out3.ch0]);
+
+	if (axi_ctrl->share_ctrl->current_mode & VFE_OUTPUTS_RDI0) {
+		irq_mask |= VFE_IRQ_STATUS0_RDI0_REG_UPDATE_MASK;
+		if (!atomic_cmpxchg(
+			&axi_ctrl->share_ctrl->rdi0_update_ack_pending,
+				0, 1))
+			reg_update |= 0x2;
+	}
+	if (axi_ctrl->share_ctrl->current_mode & VFE_OUTPUTS_RDI1) {
+		irq_mask |= VFE_IRQ_STATUS0_RDI1_REG_UPDATE_MASK;
+		if (!atomic_cmpxchg(
+			&axi_ctrl->share_ctrl->rdi1_update_ack_pending,
+				0, 1))
+			reg_update |= 0x4;
+	}
+	msm_camera_io_w(irq_mask, axi_ctrl->share_ctrl->vfebase +
+		VFE_IRQ_MASK_0);
+	if (operation_mode) {
+		if (!atomic_cmpxchg(
+			&axi_ctrl->share_ctrl->pix0_update_ack_pending,
+				0, 1))
+			reg_update |= 0x1;
+	}
+
+	msm_camera_io_w_mb(reg_update,
+			axi_ctrl->share_ctrl->vfebase +
+			VFE_REG_UPDATE_CMD);
+	axi_ctrl->share_ctrl->operation_mode |=
+		axi_ctrl->share_ctrl->current_mode;
+	axi_enable_irq(axi_ctrl->share_ctrl);
+}
+
+void axi_stop(struct msm_cam_media_controller *pmctl,
+	struct axi_ctrl_t *axi_ctrl, struct msm_camera_vfe_params_t vfe_params)
+{
+	uint32_t reg_update = 0;
+	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_camera_bus_scale_cfg(axi_ctrl->bus_perf_client, S_PREVIEW);
+		return;
+	case AXI_CMD_LIVESHOT:
+		msm_camera_bus_scale_cfg(axi_ctrl->bus_perf_client, S_VIDEO);
+		return;
+	default:
+		return;
+	}
+
+	if (axi_ctrl->share_ctrl->stop_immediately) {
+		axi_disable_irq(axi_ctrl->share_ctrl);
+		axi_stop_process(axi_ctrl->share_ctrl);
+		return;
+	}
+
+	if (axi_ctrl->share_ctrl->current_mode & VFE_OUTPUTS_RDI0) {
+		if (!atomic_cmpxchg(
+			&axi_ctrl->share_ctrl->rdi0_update_ack_pending, 0, 2))
+			reg_update |= 0x2;
+	}
+	if (axi_ctrl->share_ctrl->current_mode & VFE_OUTPUTS_RDI1) {
+		if (!atomic_cmpxchg(
+			&axi_ctrl->share_ctrl->rdi1_update_ack_pending, 0, 2))
+			reg_update |= 0x4;
+	}
+	if (operation_mode) {
+		if (!atomic_cmpxchg(
+			&axi_ctrl->share_ctrl->pix0_update_ack_pending, 0, 2))
+			reg_update |= 0x1;
+	}
+	msm_camera_io_w_mb(reg_update,
+		axi_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+}
+
+static int msm_axi_config(struct v4l2_subdev *sd, void __user *arg)
+{
+	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;
+
+	if (!axi_ctrl->share_ctrl->vfebase) {
+		pr_err("%s: base address unmapped\n", __func__);
+		return -EFAULT;
+	}
+	memset(&cfgcmd, 0, sizeof(struct msm_vfe_cfg_cmd));
+	if (NULL != arg) {
+		if (copy_from_user(&cfgcmd, arg, sizeof(cfgcmd))) {
+			ERR_COPY_FROM_USER();
+			return -EFAULT;
+		}
+	}
+	memset(&vfecmd, 0, sizeof(struct msm_isp_cmd));
+	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;
+		}
+	}
+
+	vfe_cmd_type = (cfgcmd.cmd_type & ~(CMD_AXI_CFG_TERT1|
+		CMD_AXI_CFG_TERT2));
+	switch (cfgcmd.cmd_type) {
+	case CMD_AXI_CFG_TERT1:{
+		uint32_t *axio = NULL;
+		axio = kmalloc(vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length,
+				GFP_ATOMIC);
+		if (!axio)
+			return -ENOMEM;
+
+		if (copy_from_user(axio, (void __user *)(vfecmd.value),
+				vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length)) {
+			kfree(axio);
+			return -EFAULT;
+		}
+		vfe40_config_axi(axi_ctrl, OUTPUT_TERT1, axio);
+		kfree(axio);
+		return rc;
+		}
+	case CMD_AXI_CFG_TERT2:{
+		uint32_t *axio = NULL;
+		axio = kmalloc(vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length,
+				GFP_ATOMIC);
+		if (!axio)
+			return -ENOMEM;
+
+		if (copy_from_user(axio, (void __user *)(vfecmd.value),
+				vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length)) {
+			kfree(axio);
+			return -EFAULT;
+		}
+		vfe40_config_axi(axi_ctrl, OUTPUT_TERT2, axio);
+		kfree(axio);
+		return rc;
+		}
+	case CMD_AXI_CFG_TERT1|CMD_AXI_CFG_TERT2:{
+		uint32_t *axio = NULL;
+		axio = kmalloc(vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length,
+				GFP_ATOMIC);
+		if (!axio)
+			return -ENOMEM;
+
+		if (copy_from_user(axio, (void __user *)(vfecmd.value),
+				vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length)) {
+			kfree(axio);
+			return -EFAULT;
+		}
+		vfe40_config_axi(axi_ctrl, OUTPUT_TERT1|OUTPUT_TERT2, axio);
+		kfree(axio);
+		return rc;
+		}
+	default:
+		if (cfgcmd.cmd_type & CMD_AXI_CFG_TERT1)
+			rdi_mode |= OUTPUT_TERT1;
+		if (cfgcmd.cmd_type & CMD_AXI_CFG_TERT2)
+			rdi_mode |= OUTPUT_TERT2;
+	}
+	switch (vfe_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, rdi_mode|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, rdi_mode|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,
+			rdi_mode|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,
+			rdi_mode|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,
+			rdi_mode|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: {
+		struct msm_camera_vfe_params_t vfe_params;
+		if (copy_from_user(&vfe_params,
+				(void __user *)(vfecmd.value),
+				sizeof(struct msm_camera_vfe_params_t))) {
+				return -EFAULT;
+		}
+		axi_ctrl->share_ctrl->current_mode =
+			vfe_params.operation_mode;
+		axi_start(pmctl, axi_ctrl, vfe_params);
+		}
+		break;
+	case CMD_AXI_STOP: {
+		struct msm_camera_vfe_params_t vfe_params;
+		if (copy_from_user(&vfe_params,
+				(void __user *)(vfecmd.value),
+				sizeof(struct msm_camera_vfe_params_t))) {
+				return -EFAULT;
+		}
+		axi_ctrl->share_ctrl->current_mode =
+			vfe_params.operation_mode;
+		axi_ctrl->share_ctrl->stop_immediately =
+			vfe_params.stop_immediately;
+		axi_stop(pmctl, axi_ctrl, vfe_params);
+		}
+		break;
+	case CMD_AXI_RESET:
+		axi_reset(axi_ctrl);
+		break;
+	case CMD_AXI_ABORT:
+		if (copy_from_user(&axi_ctrl->share_ctrl->sync_abort,
+				(void __user *)(vfecmd.value),
+				sizeof(uint8_t))) {
+				return -EFAULT;
+		}
+		axi_abort(axi_ctrl);
+		break;
+	default:
+		pr_err("%s Unsupported AXI configuration %x ", __func__,
+			cfgcmd.cmd_type);
+		break;
+	}
+	return rc;
+}
+
+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);
+	}
+
+	if (axi_ctrl->share_ctrl->comp_output_mode &
+		VFE40_OUTPUT_MODE_TERTIARY1)
+		if (irqstatus & (0x1 << (axi_ctrl->share_ctrl->outpath.out2.ch0
+			+ VFE_WM_OFFSET)))
+			vfe40_process_output_path_irq_rdi0(axi_ctrl);
+	if (axi_ctrl->share_ctrl->comp_output_mode &
+		VFE40_OUTPUT_MODE_TERTIARY2)
+		if (irqstatus & (0x1 << (axi_ctrl->share_ctrl->outpath.out3.ch0
+			+ VFE_WM_OFFSET)))
+			vfe40_process_output_path_irq_rdi1(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);
+			axi_disable_irq(axi_ctrl->share_ctrl);
+			vfe40_send_isp_msg(&axi_ctrl->subdev,
+				axi_ctrl->share_ctrl->vfeFrameId,
+				MSG_ID_PIX0_UPDATE_ACK);
+			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 const struct v4l2_subdev_internal_ops msm_vfe_internal_ops;
 
+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);
+		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;
+	case VIDIOC_MSM_AXI_RDI_COUNT_UPDATE: {
+		struct rdi_count_msg *msg = (struct rdi_count_msg *)arg;
+		struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd);
+		switch (msg->rdi_interface) {
+		case RDI_0:
+			axi_ctrl->share_ctrl->rdi0FrameId = msg->count;
+			rc = 0;
+			break;
+		case RDI_1:
+			axi_ctrl->share_ctrl->rdi1FrameId = msg->count;
+			rc = 0;
+			break;
+		case RDI_2:
+			axi_ctrl->share_ctrl->rdi2FrameId = msg->count;
+			rc = 0;
+			break;
+		default:
+			pr_err("%s: Incorrect interface sent\n", __func__);
+			rc = -EINVAL;
+			break;
+		}
+		break;
+	}
+	default:
+		pr_err("%s: command %d not found\n", __func__,
+						_IOC_NR(cmd));
+		break;
+	}
+	return rc;
+}
+
+static const struct v4l2_subdev_core_ops msm_axi_subdev_core_ops = {
+	.ioctl = msm_axi_subdev_ioctl,
+	.interrupt_service_routine = msm_axi_subdev_isr_routine,
+};
+
+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;
+
 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 intr_table_entry irq_req;
 	struct msm_cam_subdev_info sd_info;
 	CDBG("%s: device id = %d\n", __func__, pdev->id);
 
@@ -3606,8 +6154,25 @@
 	share_ctrl->vfe40_ctrl = vfe40_ctrl;
 	axi_ctrl->share_ctrl = share_ctrl;
 	vfe40_ctrl->share_ctrl = share_ctrl;
+	axi_ctrl->share_ctrl->axi_ref_cnt = 0;
+	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);
 	axi_ctrl->pdev = pdev;
-	vfe40_axi_probe(axi_ctrl);
+
+	sd_info.sdev_type = AXI_DEV;
+	sd_info.sd_index = pdev->id;
+	sd_info.irq_num = 0;
+	msm_cam_register_subdev_node(&axi_ctrl->subdev, &sd_info);
+
+	media_entity_init(&axi_ctrl->subdev.entity, 0, NULL, 0);
+	axi_ctrl->subdev.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
+	axi_ctrl->subdev.entity.group_id = AXI_DEV;
+	axi_ctrl->subdev.entity.name = pdev->name;
+	axi_ctrl->subdev.entity.revision = axi_ctrl->subdev.devnode->num;
 
 	v4l2_subdev_init(&vfe40_ctrl->subdev, &msm_vfe_subdev_ops);
 	vfe40_ctrl->subdev.internal_ops = &msm_vfe_internal_ops;
@@ -3624,6 +6189,15 @@
 		rc = -ENODEV;
 		goto vfe40_no_resource;
 	}
+
+	axi_ctrl->vfe_vbif_mem = platform_get_resource_byname(pdev,
+					IORESOURCE_MEM, "vfe_vbif");
+	if (!axi_ctrl->vfe_vbif_mem) {
+		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) {
@@ -3640,26 +6214,83 @@
 		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;
+	axi_ctrl->fs_vfe = regulator_get(&pdev->dev, "vdd");
+	if (IS_ERR(axi_ctrl->fs_vfe)) {
+		pr_err("%s: Regulator get failed %ld\n", __func__,
+			PTR_ERR(axi_ctrl->fs_vfe));
+		axi_ctrl->fs_vfe = NULL;
+	}
+
+	/* Register subdev node before requesting irq since
+	 * irq_num is needed by msm_cam_server */
+	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);
+
+	media_entity_init(&vfe40_ctrl->subdev.entity, 0, NULL, 0);
+	vfe40_ctrl->subdev.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
+	vfe40_ctrl->subdev.entity.group_id = VFE_DEV;
+	vfe40_ctrl->subdev.entity.name = pdev->name;
+	vfe40_ctrl->subdev.entity.revision = vfe40_ctrl->subdev.devnode->num;
+
+	/* Request for this device irq from the camera server. If the
+	 * IRQ Router is present on this target, the interrupt will be
+	 * handled by the camera server and the interrupt service
+	 * routine called. If the request_irq call returns ENXIO, then
+	 * the IRQ Router hardware is not present on this target. We
+	 * have to request for the irq ourselves and register the
+	 * appropriate interrupt handler. */
+	axi_ctrl->use_irq_router = true;
+	irq_req.cam_hw_idx       = MSM_CAM_HW_VFE0 + pdev->id;
+	irq_req.dev_name         = "vfe";
+	irq_req.irq_idx          = CAMERA_SS_IRQ_8;
+	irq_req.irq_num          = axi_ctrl->vfeirq->start;
+	irq_req.is_composite     = 0;
+	irq_req.irq_trigger_type = IRQF_TRIGGER_RISING;
+	irq_req.num_hwcore       = 1;
+	irq_req.subdev_list[0]   = &axi_ctrl->subdev;
+	irq_req.data             = (void *)axi_ctrl;
+	rc = msm_cam_server_request_irq(&irq_req);
+	if (rc == -ENXIO) {
+		/* IRQ Router hardware is not present on this hardware.
+		 * Request for the IRQ and register the interrupt handler. */
+		axi_ctrl->use_irq_router = false;
+		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);
+	} else if (rc < 0) {
+		pr_err("%s Error registering irq ", __func__);
 		goto vfe40_no_resource;
 	}
 
-	disable_irq(axi_ctrl->vfeirq->start);
+	/*get device context for IOMMU*/
+	if (pdev->id == 0)
+		axi_ctrl->iommu_ctx = msm_iommu_get_ctx("vfe0");
+	else if (pdev->id == 1)
+		axi_ctrl->iommu_ctx = msm_iommu_get_ctx("vfe1");
+	if (!axi_ctrl->iommu_ctx) {
+		release_mem_region(axi_ctrl->vfemem->start,
+			resource_size(axi_ctrl->vfemem));
+		pr_err("%s: No iommu fw context found\n", __func__);
+		rc = -ENODEV;
+		goto vfe40_no_resource;
+	}
 
 	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);
+	/*disable bayer stats by default*/
+	vfe40_ctrl->ver_num.main = 0;
+
 	return 0;
 
 vfe40_no_resource:
diff --git a/drivers/media/video/msm/vfe/msm_vfe40.h b/drivers/media/video/msm/vfe/msm_vfe40.h
index c8b0cb8..8201d18 100644
--- a/drivers/media/video/msm/vfe/msm_vfe40.h
+++ b/drivers/media/video/msm/vfe/msm_vfe40.h
@@ -50,7 +50,16 @@
 
 /* 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
+#define VFE_RESET_UPON_RESET_CMD  0x000003ff
+
+/* reset the vfe only when reset command*/
+#define VFE_ONLY_RESET_CMD  0x00000002
+
+/*Vfe module reset command*/
+#define VFE_MODULE_RESET_CMD 0x07ffffff
+
+/* wm bit offset for IRQ MASK and IRQ STATUS register */
+#define VFE_WM_OFFSET 6
 
 /* constants for irq registers */
 #define VFE_DISABLE_ALL_IRQS 0
@@ -60,6 +69,9 @@
 
 #define VFE_IRQ_STATUS0_CAMIF_SOF_MASK            (0x00000001<<0)
 #define VFE_IRQ_STATUS0_REG_UPDATE_MASK           (0x00000001<<4)
+#define VFE_IRQ_STATUS0_RDI0_REG_UPDATE_MASK      (0x00000001<<5)
+#define VFE_IRQ_STATUS0_RDI1_REG_UPDATE_MASK      (0x00000001<<6)
+#define VFE_IRQ_STATUS0_RDI2_REG_UPDATE_MASK      (0x00000001<<7)
 #define VFE_IRQ_STATUS0_STATS_BE                  (0x00000001<<16)
 #define VFE_IRQ_STATUS0_STATS_BG                  (0x00000001<<17)
 #define VFE_IRQ_STATUS0_STATS_BF                  (0x00000001<<18)
@@ -84,13 +96,22 @@
 #define VFE_IRQ_STATUS1_ASYNC_TIMER2              (0x00000001<<30)
 #define VFE_IRQ_STATUS1_ASYNC_TIMER3              (0x00000001<<31)
 
+/*TODOs the irq status passed from axi to vfe irq handler does not account
+* for 2 irq status registers. So below macro is added to differentiate between
+* same bit set on both irq status registers. This wil be fixed later by passing
+*entire payload to vfe irq handler and parsing there instead of passing just the
+*status bit*/
+
+#define VFE_IRQ_STATUS0_RDI0_REG_UPDATE  VFE_IRQ_STATUS0_RDI0_REG_UPDATE_MASK
+#define VFE_IRQ_STATUS0_RDI1_REG_UPDATE  VFE_IRQ_STATUS0_RDI1_REG_UPDATE_MASK
+
 /* 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
+ * For irq_status_1, bit 28-32 are for async timer. For
+ * irq_status_0, bit 31 for reset irq, bit 23 for axi_halt_ack
    irq */
 #define VFE_IMASK_WHILE_STOPPING_0  0x80000000
-#define VFE_IMASK_WHILE_STOPPING_1  0x00000100
+#define VFE_IMASK_WHILE_STOPPING_1  0xF0000000
 
 /* For ABF bit 4 is set to zero and other's 1 */
 #define ABF_MASK 0xFFFFFFF7
@@ -118,9 +139,12 @@
 #define CS_ENABLE_MASK    (0x00000001<<10)
 #define CLF_ENABLE_MASK   (0x00000001<<12)
 #define IHIST_ENABLE_MASK (0x00000001<<15)
+#define BHIST_ENABLE_MASK (0x00000001<<18)
 #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 STATS_BHIST_ENABLE_MASK (0x00000001<<1)
+
 #define VFE_DMI_CFG_DEFAULT              0x00000100
 
 #define HFR_MODE_OFF 1
@@ -173,13 +197,14 @@
 #define V40_OUT_CLAMP_OFF         0x00000874
 #define V40_OUT_CLAMP_LEN         16
 
-#define V40_OPERATION_CFG_LEN     44
+#define V40_OPERATION_CFG_LEN     32
 
-#define V40_AXI_OUT_OFF           0x0000004C
-#define V40_AXI_OUT_LEN           412
-#define V40_AXI_CH_INF_LEN        32
+#define V40_AXI_BUS_CMD_OFF       0x0000004C
+#define V40_AXI_BUS_CFG_LEN       284
+#define V40_AXI_OUT_LEN           344
 #define V40_AXI_CFG_LEN           71
 
+#define V40_BUS_PM_CMD            0x00000270
 #define V40_FOV_ENC_OFF           0x00000854
 #define V40_FOV_ENC_LEN           16
 #define V40_FOV_VIEW_OFF          0x00000864
@@ -213,7 +238,6 @@
 #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
 
@@ -309,29 +333,6 @@
 
 #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;
@@ -704,7 +705,7 @@
 struct vfe40_output_ch {
 	struct list_head free_buf_queue;
 	spinlock_t free_buf_lock;
-	uint16_t image_mode;
+	uint32_t inst_handle;
 	int8_t ch0;
 	int8_t ch1;
 	int8_t ch2;
@@ -719,7 +720,8 @@
 #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_COMMON_ERROR_ONLY_1       0x0000FF00
+#define VFE40_IMASK_VFE_ERROR_ONLY_1          0x00FF01FF
 #define VFE40_IMASK_CAMIF_ERROR               (0x00000001<<0)
 #define VFE40_IMASK_BHIST_OVWR                (0x00000001<<1)
 #define VFE40_IMASK_STATS_CS_OVWR             (0x00000001<<2)
@@ -728,21 +730,22 @@
 #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 VFE40_IMASK_BUS_BDG_HALT_ACK          (0x00000001<<8)
+#define VFE40_IMASK_IMG_MAST_0_BUS_OVFL       (0x00000001<<9)
+#define VFE40_IMASK_IMG_MAST_1_BUS_OVFL       (0x00000001<<10)
+#define VFE40_IMASK_IMG_MAST_2_BUS_OVFL       (0x00000001<<11)
+#define VFE40_IMASK_IMG_MAST_3_BUS_OVFL       (0x00000001<<12)
+#define VFE40_IMASK_IMG_MAST_4_BUS_OVFL       (0x00000001<<13)
+#define VFE40_IMASK_IMG_MAST_5_BUS_OVFL       (0x00000001<<14)
+#define VFE40_IMASK_IMG_MAST_6_BUS_OVFL       (0x00000001<<15)
+#define VFE40_IMASK_STATS_BE_BUS_OVFL         (0x00000001<<16)
+#define VFE40_IMASK_STATS_BG_BUS_OVFL         (0x00000001<<17)
+#define VFE40_IMASK_STATS_BF_BUS_OVFL         (0x00000001<<18)
+#define VFE40_IMASK_STATS_AWB_BUS_OVFL        (0x00000001<<19)
+#define VFE40_IMASK_STATS_RS_BUS_OVFL         (0x00000001<<10)
+#define VFE40_IMASK_STATS_CS_BUS_OVFL         (0x00000001<<21)
+#define VFE40_IMASK_STATS_IHIST_BUS_OVFL      (0x00000001<<22)
+#define VFE40_IMASK_STATS_SKIN_BHIST_BUS_OVFL (0x00000001<<23)
 
 #define VFE_COM_STATUS 0x000FE000
 
@@ -751,7 +754,8 @@
 
 	struct vfe40_output_ch out0; /* preview and thumbnail */
 	struct vfe40_output_ch out1; /* snapshot */
-	struct vfe40_output_ch out2; /* video    */
+	struct vfe40_output_ch out2; /* rdi0    */
+	struct vfe40_output_ch out3; /* rdi01   */
 };
 
 struct vfe40_frame_extra {
@@ -769,9 +773,7 @@
 	uint32_t  frameCounter;
 };
 
-#define VFE_CLEAR_ALL_IRQS              0xffffffff
-
-#define VFE_HW_VERSION			        0x00000000
+#define VFE_HW_VERSION			0x00000000
 #define VFE_GLOBAL_RESET                0x0000000C
 #define VFE_MODULE_RESET                0x00000010
 #define VFE_CGC_OVERRIDE                0x00000014
@@ -786,32 +788,67 @@
 #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_PING_PONG_STATUS        0x00000268
+#define VFE_AXI_CMD                     0x000002C0
+#define VFE_AXI_STATUS                  0x000002E4
+#define VFE_BUS_STATS_PING_PONG_BASE    0x00000168
 
-#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_BUS_STATS_BE_WR_PING_ADDR    0x00000168
+#define VFE_BUS_STATS_BE_WR_PONG_ADDR    0x0000016C
+#define VFE_BUS_STATS_BE_WR_ADDR_CFG    0x00000170
+#define VFE_BUS_STATS_BE_UB_CFG          0x00000174
+#define VFE_BUS_STATS_BE_WR_FRAMEDROP_PATTERN  0x00000178
+#define VFE_BUS_STATS_BE_WR_IRQ_SUBSAMPLE_PATTERN 0x0000017C
+
+#define VFE_BUS_STATS_BG_WR_PING_ADDR     0x00000180
+#define VFE_BUS_STATS_BG_WR_PONG_ADDR     0x00000184
+#define VFE_BUS_STATS_BG_WR_ADDR_CFG      0x00000188
+#define VFE_BUS_STATS_BG_WR_UB_CFG        0x0000018C
+#define VFE_BUS_STATS_BG_WR_FRAMEDROP_PATTERN 0x00000190
+#define VFE_BUS_STATS_BG_WR_IRQ_SUBSAMPLE_PATTERN 0x00000194
+
+#define VFE_BUS_STATS_BF_WR_PING_ADDR     0x00000198
+#define VFE_BUS_STATS_BF_WR_PONG_ADDR     0x0000019C
+#define VFE_BUS_STATS_BF_WR_ADDR_CFG      0x000001A0
+#define VFE_BUS_STATS_BF_WR_UB_CFG        0x000001A4
+#define VFE_BUS_STATS_BF_WR_FRAMEDROP_PATTERN  0x000001A8
+#define VFE_BUS_STATS_BF_WR_IRQ_SUBSAMPLE_PATTERN  0x000001AC
+
+#define VFE_BUS_STATS_AWB_WR_PING_ADDR    0x000001B0
+#define VFE_BUS_STATS_AWB_WR_PONG_ADDR    0x000001B4
+#define VFE_BUS_STATS_AWB_WR_ADDR_CFG     0x000001B8
+#define VFE_BUS_STATS_AWB_WR_UB_CFG       0x000001BC
+#define VFE_BUS_STATS_AWB_WR_FRAMEDROP_PATTERN  0x000001C0
+#define VFE_BUS_STATS_AWB_WR_IRQ_SUBSAMPLE_PATTERN  0x000001C4
+
+#define VFE_BUS_STATS_RS_WR_PING_ADDR     0x000001C8
+#define VFE_BUS_STATS_RS_WR_PONG_ADDR     0x000001CC
+#define VFE_BUS_STATS_RS_WR_ADDR_CFG      0x000001D0
+#define VFE_BUS_STATS_RS_WR_UB_CFG    0x000001D4
+#define VFE_BUS_STATS_RS_WR_FRAMEDROP_PATTERN      0x000001D8
+#define VFE_BUS_STATS_RS_WR_IRQ_SUBSAMPLE_PATTERN  0x000001DC
+
+#define VFE_BUS_STATS_CS_WR_PING_ADDR     0x000001E0
+#define VFE_BUS_STATS_CS_WR_PONG_ADDR     0x000001E4
+#define VFE_BUS_STATS_CS_WR_ADDR_CFG      0x000001E8
+#define VFE_BUS_STATS_CS_WR_UB_CFG        0x000001EC
+#define VFE_BUS_STATS_CS_WR_FRAMEDROP_PATTERN     0x000001F0
+#define VFE_BUS_STATS_CS_WR_IRQ_SUBSAMPLE_PATTERN 0x000001F4
+
+#define VFE_BUS_STATS_HIST_WR_PING_ADDR   0x000001F8
+#define VFE_BUS_STATS_HIST_WR_PONG_ADDR   0x000001FC
+#define VFE_BUS_STATS_HIST_WR_ADDR_CFG    0x00000200
+#define VFE_BUS_STATS_HIST_WR_UB_CFG      0x00000204
+#define VFE_BUS_STATS_HIST_WR_FRAMEDROP_PATTERN      0x00000208
+#define VFE_BUS_STATS_HIST_WR_IRQ_SUBSAMPLE_PATTERN  0x0000020C
+
+
+#define VFE_BUS_STATS_SKIN_WR_PING_ADDR   0x00000210
+#define VFE_BUS_STATS_SKIN_WR_PONG_ADDR   0x00000214
+#define VFE_BUS_STATS_SKIN_WR_ADDR_CFG    0x00000218
+#define VFE_BUS_STATS_SKIN_WR_UB_CFG      0x0000021C
+#define VFE_BUS_STATS_SKIN_WR_FRAMEDROP_PATTERN       0x00000220
+#define VFE_BUS_STATS_SKIN_WR_IRQ_SUBSAMPLE_PATTERN   0x00000224
 
 #define VFE_0_BUS_BDG_QOS_CFG_0     0x000002C4
 #define VFE_0_BUS_BDG_QOS_CFG_1     0x000002C8
@@ -839,13 +876,14 @@
 #define VFE_STATS_AWB_SGW_CFG           0x000008CC
 #define VFE_DMI_CFG                     0x00000910
 #define VFE_DMI_ADDR                    0x00000914
+#define VFE_DMI_DATA_HI                 0x00000918
 #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 VFE_VIOLATION_STATUS            0x00000048
 
 #define VFE40_DMI_DATA_HI               0x00000918
 #define VFE40_DMI_DATA_LO               0x0000091C
@@ -860,6 +898,25 @@
 #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)
+#define VFE40_OUTPUT_MODE_TERTIARY1		BIT(10)
+#define VFE40_OUTPUT_MODE_TERTIARY2		BIT(11)
+
+#define VFE40_VBIF_CLKON				0x4
+#define VFE40_VBIF_IN_RD_LIM_CONF0		0xB0
+#define VFE40_VBIF_IN_RD_LIM_CONF1		0xB4
+#define VFE40_VBIF_IN_RD_LIM_CONF2		0xB8
+#define VFE40_VBIF_IN_WR_LIM_CONF0		0xC0
+#define VFE40_VBIF_IN_WR_LIM_CONF1		0xC4
+#define VFE40_VBIF_IN_WR_LIM_CONF2		0xC8
+#define VFE40_VBIF_OUT_RD_LIM_CONF0		0xD0
+#define VFE40_VBIF_OUT_WR_LIM_CONF0		0xD4
+#define VFE40_VBIF_DDR_OUT_MAX_BURST	0xD8
+#define VFE40_VBIF_ARB_CTL				0xF0
+#define VFE40_VBIF_DDR_ARB_CONF0		0xF4
+#define VFE40_VBIF_DDR_ARB_CONF1		0xF8
+#define VFE40_VBIF_ROUND_ROBIN_QOS_ARB	0x124
+#define VFE40_VBIF_OUT_AXI_AOOO_EN		0x178
+#define VFE40_VBIF_OUT_AXI_AOOO			0x17C
 
 struct vfe_stats_control {
 	uint32_t droppedStatsFrameCount;
@@ -870,26 +927,50 @@
 
 struct vfe_share_ctrl_t {
 	void __iomem *vfebase;
+	void __iomem *vfe_vbif_base;
 	uint32_t register_total;
 
 	atomic_t vstate;
+	atomic_t handle_common_irq;
 	uint32_t vfeFrameId;
+	uint32_t rdi0FrameId;
+	uint32_t rdi1FrameId;
+	uint32_t rdi2FrameId;
 	uint32_t stats_comp;
+	spinlock_t  sd_notify_lock;
 	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 */
+	uint32_t operation_mode;     /* streaming or snapshot */
+	uint32_t current_mode;
 	struct vfe40_output_path outpath;
 
-	uint32_t ref_count;
-	spinlock_t  sd_notify_lock;
-	uint32_t vfe_clk_rate;
+	uint16_t port_info;
+	uint8_t stop_immediately;
+	uint8_t sync_abort;
+	uint16_t cmd_type;
+	uint8_t vfe_reset_flag;
 
-	atomic_t irq_cnt;
+	uint8_t axi_ref_cnt;
+	uint16_t comp_output_mode;
+
+	struct completion reset_complete;
+
+	spinlock_t  update_ack_lock;
+	spinlock_t  start_ack_lock;
+
 	struct axi_ctrl_t *axi_ctrl;
 	struct vfe40_ctrl_type *vfe40_ctrl;
+	int8_t start_ack_pending;
+	int8_t update_ack_pending;
+	enum vfe_output_state recording_state;
+
+	atomic_t pix0_update_ack_pending;
+	atomic_t rdi0_update_ack_pending;
+	atomic_t rdi1_update_ack_pending;
+	atomic_t rdi2_update_ack_pending;
 };
 
 struct axi_ctrl_t {
@@ -902,27 +983,25 @@
 	void *syncdata;
 
 	struct resource	*vfemem;
+	struct resource	*vfe_vbif_mem;
 	struct resource *vfeio;
+	struct resource *vfe_vbif_io;
 	struct regulator *fs_vfe;
-	struct clk *vfe_clk[3];
+	struct clk *vfe_clk[7];
 	struct tasklet_struct vfe40_tasklet;
 	struct vfe_share_ctrl_t *share_ctrl;
+	struct device *iommu_ctx;
+	uint32_t bus_perf_client;
+	uint32_t use_irq_router;
 };
 
 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 vfe_sof_count_enable;
 	int8_t update_linear;
 	int8_t update_rolloff;
 	int8_t update_la;
@@ -934,18 +1013,14 @@
 	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 msm_ver_num_info ver_num;
+	struct vfe_stats_control afbfStatsControl;
 	struct vfe_stats_control awbStatsControl;
-	struct vfe_stats_control aecStatsControl;
+	struct vfe_stats_control aecbgStatsControl;
 	struct vfe_stats_control ihistStatsControl;
 	struct vfe_stats_control rsStatsControl;
 	struct vfe_stats_control csStatsControl;
+	struct vfe_stats_control bhistStatsControl;
 
 	/* v4l2 subdev */
 	struct v4l2_subdev subdev;
@@ -956,6 +1031,8 @@
 	uint32_t snapshot_frame_cnt;
 	struct msm_stats_bufq_ctrl stats_ctrl;
 	struct msm_stats_ops stats_ops;
+
+	uint32_t simultaneous_sof_stat;
 };
 
 #define statsAeNum      0
@@ -976,227 +1053,4 @@
 	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
index 35d5207..41d1cdd 100644
--- a/drivers/media/video/msm/vfe/msm_vfe40_axi.c
+++ b/drivers/media/video/msm/vfe/msm_vfe40_axi.c
@@ -193,6 +193,16 @@
 	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);
+	msm_camera_io_w(*ch_info++,
+		axi_ctrl->share_ctrl->vfebase + VFE_RDI0_CFG);
+	if (msm_camera_io_r(axi_ctrl->share_ctrl->vfebase +
+		V40_GET_HW_VERSION_OFF) ==
+		VFE40_HW_NUMBER) {
+		msm_camera_io_w(*ch_info++,
+			axi_ctrl->share_ctrl->vfebase + VFE_RDI1_CFG);
+		msm_camera_io_w(*ch_info++,
+			axi_ctrl->share_ctrl->vfebase + VFE_RDI2_CFG);
+	}
 	return 0;
 }
 
@@ -331,6 +341,8 @@
 	case CMD_AXI_STOP:
 		axi_stop(axi_ctrl);
 		break;
+	case CMD_AXI_RESET:
+		break;
 	default:
 		pr_err("%s Unsupported AXI configuration %x ", __func__,
 			cfgcmd.cmd_type);
diff --git a/drivers/media/video/msm/vfe/msm_vfe7x27a_v4l2.c b/drivers/media/video/msm/vfe/msm_vfe7x27a_v4l2.c
index e1d8b48..15c38af 100644
--- a/drivers/media/video/msm/vfe/msm_vfe7x27a_v4l2.c
+++ b/drivers/media/video/msm/vfe/msm_vfe7x27a_v4l2.c
@@ -360,7 +360,7 @@
 	rc = vfe2x_ctrl->stats_ops.dqbuf(vfe2x_ctrl->stats_ops.stats_ctrl,
 							  stats_type, &buf);
 	if (rc < 0) {
-		pr_err("%s: dq stats buf (type = %d) err = %d",
+		CDBG("%s: dq stats buf (type = %d) err = %d",
 			   __func__, stats_type, rc);
 		return 0;
 	}
@@ -395,7 +395,7 @@
 		stats_buf = &bufq->bufs[i];
 		rc = vfe2x_ctrl->stats_ops.enqueue_buf(
 				vfe2x_ctrl->stats_ops.stats_ctrl,
-				&(stats_buf->info), NULL);
+				&(stats_buf->info), NULL, -1);
 			if (rc < 0) {
 				pr_err("%s: dq stats buf (type = %d) err = %d",
 					 __func__, stats_type, rc);
@@ -414,7 +414,7 @@
 		rc = vfe2x_ctrl->stats_ops.buf_unprepare(
 			vfe2x_ctrl->stats_ops.stats_ctrl,
 			req_buf->stats_type, i,
-			vfe2x_ctrl->stats_ops.client);
+			vfe2x_ctrl->stats_ops.client, -1);
 		if (rc < 0) {
 			pr_err("%s: unreg stats buf (type = %d) err = %d",
 				__func__, req_buf->stats_type, rc);
@@ -473,7 +473,7 @@
 		stats_buf->state == MSM_STATS_BUFFER_STATE_PREPARED) {
 		rc = vfe2x_ctrl->stats_ops.enqueue_buf(
 				&vfe2x_ctrl->stats_ctrl,
-				info, vfe2x_ctrl->stats_ops.client);
+				info, vfe2x_ctrl->stats_ops.client, -1);
 		if (rc < 0) {
 			pr_err("%s: enqueue_buf (type = %d), index : %d, err = %d",
 				 __func__, info->type, info->buf_idx, rc);
@@ -555,7 +555,7 @@
 		rc = vfe2x_ctrl->stats_ops.enqueue_buf(
 				&vfe2x_ctrl->stats_ctrl,
 				(struct msm_stats_buf_info *)cmd->value,
-				vfe2x_ctrl->stats_ops.client);
+				vfe2x_ctrl->stats_ops.client, -1);
 	}
 	break;
 	case VFE_CMD_STATS_FLUSH_BUFQ: {
@@ -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,
@@ -2353,7 +2352,7 @@
 	return 0;
 }
 
-void msm_vpe_subdev_release(void)
+void msm_vpe_subdev_release(struct v4l2_subdev *sd)
 {
 	return;
 }
diff --git a/drivers/media/video/msm/vfe/msm_vfe_stats_buf.c b/drivers/media/video/msm/vfe/msm_vfe_stats_buf.c
index 5fbcdb1..a813e09 100644
--- a/drivers/media/video/msm/vfe/msm_vfe_stats_buf.c
+++ b/drivers/media/video/msm/vfe/msm_vfe_stats_buf.c
@@ -182,7 +182,8 @@
 #endif
 
 static int msm_stats_buf_prepare(struct msm_stats_bufq_ctrl *stats_ctrl,
-	struct msm_stats_buf_info *info, struct ion_client *client)
+	struct msm_stats_buf_info *info, struct ion_client *client,
+	int domain_num)
 {
 	unsigned long paddr;
 #ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
@@ -219,7 +220,7 @@
 		goto out1;
 	}
 	if (ion_map_iommu(client, stats_buf->handle,
-			CAMERA_DOMAIN, GEN_POOL, SZ_4K,
+			domain_num, 0, SZ_4K,
 			0, &paddr, &len, UNCACHED, 0) < 0) {
 		rc = -EINVAL;
 		pr_err("%s: cannot map address", __func__);
@@ -257,7 +258,7 @@
 	return 0;
 out3:
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
-	ion_unmap_iommu(client, stats_buf->handle, CAMERA_DOMAIN, GEN_POOL);
+	ion_unmap_iommu(client, stats_buf->handle, domain_num, 0);
 #endif
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 out2:
@@ -270,7 +271,7 @@
 }
 static int msm_stats_buf_unprepare(struct msm_stats_bufq_ctrl *stats_ctrl,
 	enum msm_stats_enum_type stats_type, int buf_idx,
-	struct ion_client *client)
+	struct ion_client *client, int domain_num)
 {
 	int rc = 0;
 	struct msm_stats_bufq *bufq = NULL;
@@ -292,7 +293,7 @@
 	}
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 	ion_unmap_iommu(client, stats_buf->handle,
-					CAMERA_DOMAIN, GEN_POOL);
+					domain_num, 0);
 	ion_free(client, stats_buf->handle);
 #else
 	put_pmem_file(stats_buf->file);
@@ -362,7 +363,7 @@
 		}
 	}
 	if (!(*pp_stats_buf)) {
-		pr_err("%s: no free stats buf, type = %d",
+		D("%s: no free stats buf, type = %d",
 			__func__, stats_type);
 		rc = -1;
 		return rc;
@@ -472,12 +473,13 @@
 	return rc;
 }
 static int msm_stats_enqueue_buf(struct msm_stats_bufq_ctrl *stats_ctrl,
-	struct msm_stats_buf_info *info, struct ion_client *client)
+	struct msm_stats_buf_info *info, struct ion_client *client,
+	int domain_num)
 {
 	int rc = 0;
 	D("%s: stats type : %d, idx : %d\n", __func__,
 		info->type, info->buf_idx);
-	rc = msm_stats_buf_prepare(stats_ctrl, info, client);
+	rc = msm_stats_buf_prepare(stats_ctrl, info, client, domain_num);
 	if (rc < 0) {
 		pr_err("%s: buf_prepare failed, rc = %d", __func__, rc);
 		return -EINVAL;
diff --git a/drivers/media/video/msm/vfe/msm_vfe_stats_buf.h b/drivers/media/video/msm/vfe/msm_vfe_stats_buf.h
index 18fd425..bf3e70e 100644
--- a/drivers/media/video/msm/vfe/msm_vfe_stats_buf.h
+++ b/drivers/media/video/msm/vfe/msm_vfe_stats_buf.h
@@ -55,8 +55,8 @@
 	struct msm_stats_bufq_ctrl *stats_ctrl;
 	struct ion_client *client;
 	int (*enqueue_buf) (struct msm_stats_bufq_ctrl *stats_ctrl,
-						struct msm_stats_buf_info *info,
-						struct ion_client *client);
+				struct msm_stats_buf_info *info,
+				struct ion_client *client, int domain_num);
 	int (*qbuf) (struct msm_stats_bufq_ctrl *stats_ctrl,
 				 enum msm_stats_enum_type stats_type,
 				 int buf_idx);
@@ -69,10 +69,10 @@
 	int (*buf_unprepare) (struct msm_stats_bufq_ctrl *stats_ctrl,
 		enum msm_stats_enum_type stats_type,
 		int buf_idx,
-		struct ion_client *client);
+		struct ion_client *client, int domain_num);
 	int (*buf_prepare) (struct msm_stats_bufq_ctrl *stats_ctrl,
-						struct msm_stats_buf_info *info,
-						struct ion_client *client);
+				struct msm_stats_buf_info *info,
+				struct ion_client *client, int domain_num);
 	int (*reqbuf) (struct msm_stats_bufq_ctrl *stats_ctrl,
 				   struct msm_stats_reqbuf *reqbuf,
 				   struct ion_client *client);
diff --git a/drivers/media/video/msm_vidc/Makefile b/drivers/media/video/msm_vidc/Makefile
index e145229..2a1f40f 100644
--- a/drivers/media/video/msm_vidc/Makefile
+++ b/drivers/media/video/msm_vidc/Makefile
@@ -4,5 +4,6 @@
 				msm_vdec.o \
 				msm_venc.o \
 				msm_smem.o \
+				msm_vidc_debug.o \
 				vidc_hal.o \
 				vidc_hal_interrupt_handler.o \
diff --git a/drivers/media/video/msm_vidc/msm_smem.c b/drivers/media/video/msm_vidc/msm_smem.c
index ff12a5c..156a721 100644
--- a/drivers/media/video/msm_vidc/msm_smem.c
+++ b/drivers/media/video/msm_vidc/msm_smem.c
@@ -14,6 +14,7 @@
 #include <linux/slab.h>
 #include <mach/iommu_domains.h>
 #include "msm_smem.h"
+#include "msm_vidc_debug.h"
 
 struct smem_client {
 	int mem_type;
@@ -26,28 +27,29 @@
 		unsigned long *buffer_size,	unsigned long flags)
 {
 	int rc;
-
 	if (!iova || !buffer_size || !hndl || !clnt) {
-		pr_err("Invalid params: %p, %p, %p, %p\n",
+		dprintk(VIDC_ERR, "Invalid params: %p, %p, %p, %p\n",
 				clnt, hndl, iova, buffer_size);
 		return -EINVAL;
 	}
 	if (align < 4096)
 		align = 4096;
-	flags |= UNCACHED;
+	dprintk(VIDC_DBG, "domain: %d, partition: %d\n",
+		domain_num, partition_num);
 	rc = ion_map_iommu(clnt, hndl, domain_num, partition_num, align,
-			0, iova, buffer_size, flags, 0);
+			0, iova, buffer_size, UNCACHED, 0);
 	if (rc)
-		pr_err("ion_map_iommu failed(%d).domain: %d,partition: %d\n",
-				rc, domain_num, partition_num);
+		dprintk(VIDC_ERR,
+		"ion_map_iommu failed(%d).domain: %d,partition: %d\n",
+		rc, domain_num, partition_num);
 
 	return rc;
 }
 
 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,
@@ -61,36 +63,32 @@
 	int rc = 0;
 	hndl = ion_import_dma_buf(client->clnt, fd);
 	if (IS_ERR_OR_NULL(hndl)) {
-		pr_err("Failed to get handle: %p, %d, %d, %p\n",
+		dprintk(VIDC_ERR, "Failed to get handle: %p, %d, %d, %p\n",
 				client, fd, offset, hndl);
 		rc = -ENOMEM;
 		goto fail_import_fd;
 	}
 	rc = ion_handle_get_flags(client->clnt, hndl, &ionflag);
 	if (rc) {
-		pr_err("Failed to get ion flags: %d", rc);
+		dprintk(VIDC_ERR, "Failed to get ion flags: %d", rc);
 		goto fail_map;
 	}
-	mem->kvaddr = ion_map_kernel(client->clnt, hndl, ionflag);
-	if (!mem->kvaddr) {
-		pr_err("Failed to map shared mem in kernel\n");
-		rc = -EIO;
-		goto fail_map;
-	}
+	mem->kvaddr = NULL;
 	mem->domain = domain;
 	mem->partition_num = partition;
 	rc = get_device_address(client->clnt, hndl, mem->domain,
-		mem->partition_num, 4096, &iova, &buffer_size, UNCACHED);
+		mem->partition_num, 4096, &iova, &buffer_size, ionflag);
 	if (rc) {
-		pr_err("Failed to get device address: %d\n", rc);
+		dprintk(VIDC_ERR, "Failed to get device address: %d\n", rc);
 		goto fail_device_address;
 	}
 
-	mem->kvaddr += offset;
 	mem->mem_type = client->mem_type;
 	mem->smem_priv = hndl;
-	mem->device_addr = iova + offset;
+	mem->device_addr = iova;
 	mem->size = buffer_size;
+	dprintk(VIDC_DBG, "NOTE: Buffer device address: 0x%lx, size: %d\n",
+		mem->device_addr, mem->size);
 	return rc;
 fail_device_address:
 	ion_unmap_kernel(client->clnt, hndl);
@@ -102,20 +100,29 @@
 
 static int alloc_ion_mem(struct smem_client *client, size_t size,
 		u32 align, u32 flags, int domain, int partition,
-		struct msm_smem *mem)
+		struct msm_smem *mem, int map_kernel)
 {
 	struct ion_handle *hndl;
 	unsigned long iova = 0;
 	unsigned long buffer_size = 0;
+	unsigned long ionflags = 0;
 	int rc = 0;
-	flags = flags | ION_HEAP(ION_CP_MM_HEAP_ID);
+	if (flags == SMEM_CACHED)
+		ionflags |= ION_SET_CACHE(CACHED);
+	else
+		ionflags |= ION_SET_CACHE(UNCACHED);
+
+	ionflags = ionflags | ION_HEAP(ION_CP_MM_HEAP_ID);
 	if (align < 4096)
 		align = 4096;
 	size = (size + 4095) & (~4095);
-	hndl = ion_alloc(client->clnt, size, align, flags);
+	dprintk(VIDC_DBG, "domain: %d, partition: %d\n",
+		domain, partition);
+	hndl = ion_alloc(client->clnt, size, align, ionflags);
 	if (IS_ERR_OR_NULL(hndl)) {
-		pr_err("Failed to allocate shared memory = %p, %d, %d, 0x%x\n",
-				client, size, align, flags);
+		dprintk(VIDC_ERR,
+		"Failed to allocate shared memory = %p, %d, %d, 0x%lx\n",
+		client, size, align, ionflags);
 		rc = -ENOMEM;
 		goto fail_shared_mem_alloc;
 	}
@@ -123,21 +130,28 @@
 	mem->smem_priv = hndl;
 	mem->domain = domain;
 	mem->partition_num = partition;
-	mem->kvaddr = ion_map_kernel(client->clnt, hndl, 0);
-	if (!mem->kvaddr) {
-		pr_err("Failed to map shared mem in kernel\n");
-		rc = -EIO;
-		goto fail_map;
-	}
+	if (map_kernel) {
+		mem->kvaddr = ion_map_kernel(client->clnt, hndl, 0);
+		if (!mem->kvaddr) {
+			dprintk(VIDC_ERR,
+				"Failed to map shared mem in kernel\n");
+			rc = -EIO;
+			goto fail_map;
+		}
+	} else
+		mem->kvaddr = NULL;
+
 	rc = get_device_address(client->clnt, hndl, mem->domain,
 		mem->partition_num, align, &iova, &buffer_size, UNCACHED);
 	if (rc) {
-		pr_err("Failed to get device address: %d\n", rc);
+		dprintk(VIDC_ERR, "Failed to get device address: %d\n",
+			rc);
 		goto fail_device_address;
 	}
 	mem->device_addr = iova;
-	pr_err("device_address = 0x%lx, kvaddr = 0x%p\n",
-		mem->device_addr, mem->kvaddr);
+	dprintk(VIDC_DBG,
+		"device_address = 0x%lx, kvaddr = 0x%p, size = %d\n",
+		mem->device_addr, mem->kvaddr, size);
 	mem->size = size;
 	return rc;
 fail_device_address:
@@ -150,10 +164,13 @@
 
 static void free_ion_mem(struct smem_client *client, struct msm_smem *mem)
 {
-	put_device_address(client->clnt,
-		mem->smem_priv, mem->domain);
-	ion_unmap_kernel(client->clnt, mem->smem_priv);
-	ion_free(client->clnt, mem->smem_priv);
+	if (mem->device_addr)
+		put_device_address(client->clnt,
+			mem->smem_priv, mem->domain, mem->partition_num);
+	if (mem->kvaddr)
+		ion_unmap_kernel(client->clnt, mem->smem_priv);
+	if (mem->smem_priv)
+		ion_free(client->clnt, mem->smem_priv);
 }
 
 static void *ion_new_client(void)
@@ -161,7 +178,7 @@
 	struct ion_client *client = NULL;
 	client = msm_ion_client_create(-1, "video_client");
 	if (!client)
-		pr_err("Failed to create smem client\n");
+		dprintk(VIDC_ERR, "Failed to create smem client\n");
 	return client;
 };
 
@@ -177,12 +194,12 @@
 	int rc = 0;
 	struct msm_smem *mem;
 	if (fd < 0) {
-		pr_err("Invalid fd: %d\n", fd);
+		dprintk(VIDC_ERR, "Invalid fd: %d\n", fd);
 		return NULL;
 	}
 	mem = kzalloc(sizeof(*mem), GFP_KERNEL);
 	if (!mem) {
-		pr_err("Failed to allocte shared mem\n");
+		dprintk(VIDC_ERR, "Failed to allocte shared mem\n");
 		return NULL;
 	}
 	switch (client->mem_type) {
@@ -191,18 +208,48 @@
 			domain, partition, mem);
 		break;
 	default:
-		pr_err("Mem type not supported\n");
+		dprintk(VIDC_ERR, "Mem type not supported\n");
 		rc = -EINVAL;
 		break;
 	}
 	if (rc) {
-		pr_err("Failed to allocate shared memory\n");
+		dprintk(VIDC_ERR, "Failed to allocate shared memory\n");
 		kfree(mem);
 		mem = NULL;
 	}
 	return mem;
 }
 
+static int ion_mem_clean_invalidate(struct smem_client *clt,
+	struct msm_smem *mem)
+{
+	/*
+	 * Note: We're always mapping into iommu as uncached
+	 * as a result we don't need to flush/clean anything
+	 */
+	return 0;
+}
+
+int msm_smem_clean_invalidate(void *clt, struct msm_smem *mem)
+{
+	struct smem_client *client = clt;
+	int rc;
+	if (!client || !mem) {
+		dprintk(VIDC_ERR, "Invalid  client/handle passed\n");
+		return -EINVAL;
+	}
+	switch (client->mem_type) {
+	case SMEM_ION:
+		rc = ion_mem_clean_invalidate(client, mem);
+		break;
+	default:
+		dprintk(VIDC_ERR, "Mem type not supported\n");
+		rc = -EINVAL;
+		break;
+	}
+	return rc;
+}
+
 void *msm_smem_new_client(enum smem_type mtype)
 {
 	struct smem_client *client = NULL;
@@ -212,7 +259,7 @@
 		clnt = ion_new_client();
 		break;
 	default:
-		pr_err("Mem type not supported\n");
+		dprintk(VIDC_ERR, "Mem type not supported\n");
 		break;
 	}
 	if (clnt) {
@@ -222,43 +269,45 @@
 			client->clnt = clnt;
 		}
 	} else {
-		pr_err("Failed to create new client: mtype = %d\n", mtype);
+		dprintk(VIDC_ERR, "Failed to create new client: mtype = %d\n",
+			mtype);
 	}
 	return client;
 };
 
 struct msm_smem *msm_smem_alloc(void *clt, size_t size, u32 align, u32 flags,
-		int domain, int partition)
+		int domain, int partition, int map_kernel)
 {
 	struct smem_client *client;
 	int rc = 0;
 	struct msm_smem *mem;
 	client = clt;
 	if (!client) {
-		pr_err("Invalid  client passed\n");
+		dprintk(VIDC_ERR, "Invalid  client passed\n");
 		return NULL;
 	}
 	if (!size) {
-		pr_err("No need to allocate memory of size: %d\n", size);
+		dprintk(VIDC_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");
+		dprintk(VIDC_ERR, "Failed to allocate shared mem\n");
 		return NULL;
 	}
 	switch (client->mem_type) {
 	case SMEM_ION:
 		rc = alloc_ion_mem(client, size, align, flags,
-			domain, partition, mem);
+			domain, partition, mem, map_kernel);
 		break;
 	default:
-		pr_err("Mem type not supported\n");
+		dprintk(VIDC_ERR, "Mem type not supported\n");
 		rc = -EINVAL;
 		break;
 	}
 	if (rc) {
-		pr_err("Failed to allocate shared memory\n");
+		dprintk(VIDC_ERR, "Failed to allocate shared memory\n");
 		kfree(mem);
 		mem = NULL;
 	}
@@ -269,7 +318,7 @@
 {
 	struct smem_client *client = clt;
 	if (!client || !mem) {
-		pr_err("Invalid  client/handle passed\n");
+		dprintk(VIDC_ERR, "Invalid  client/handle passed\n");
 		return;
 	}
 	switch (client->mem_type) {
@@ -277,7 +326,7 @@
 		free_ion_mem(client, mem);
 		break;
 	default:
-		pr_err("Mem type not supported\n");
+		dprintk(VIDC_ERR, "Mem type not supported\n");
 		break;
 	}
 	kfree(mem);
@@ -287,7 +336,7 @@
 {
 	struct smem_client *client = clt;
 	if (!client) {
-		pr_err("Invalid  client passed\n");
+		dprintk(VIDC_ERR, "Invalid  client passed\n");
 		return;
 	}
 	switch (client->mem_type) {
@@ -295,7 +344,7 @@
 		ion_delete_client(client);
 		break;
 	default:
-		pr_err("Mem type not supported\n");
+		dprintk(VIDC_ERR, "Mem type not supported\n");
 		break;
 	}
 	kfree(client);
diff --git a/drivers/media/video/msm_vidc/msm_smem.h b/drivers/media/video/msm_vidc/msm_smem.h
index b742c79..37816e1 100644
--- a/drivers/media/video/msm_vidc/msm_smem.h
+++ b/drivers/media/video/msm_vidc/msm_smem.h
@@ -20,6 +20,11 @@
 	SMEM_ION,
 };
 
+enum smem_cache_prop {
+	SMEM_CACHED,
+	SMEM_UNCACHED,
+};
+
 struct msm_smem {
 	int mem_type;
 	size_t size;
@@ -32,9 +37,10 @@
 
 void *msm_smem_new_client(enum smem_type mtype);
 struct msm_smem *msm_smem_alloc(void *clt, size_t size, u32 align, u32 flags,
-		int domain, int partition);
+		int domain, int partition, int map_kernel);
 void msm_smem_free(void *clt, struct msm_smem *mem);
 void msm_smem_delete_client(void *clt);
 struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset, int
 		domain, int partition);
+int msm_smem_clean_invalidate(void *clt, struct msm_smem *mem);
 #endif
diff --git a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
index cf1ebbb..dd2a207 100644
--- a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
@@ -26,75 +26,217 @@
 #include <mach/iommu_domains.h>
 #include <media/msm_vidc.h>
 #include "msm_vidc_internal.h"
+#include "msm_vidc_debug.h"
 #include "vidc_hal_api.h"
 #include "msm_smem.h"
 
 #define BASE_DEVICE_NUMBER 32
 #define MAX_EVENTS 30
+#define SHARED_QSIZE 0x1000000
 
-
-static struct msm_bus_vectors ocmem_init_vectors[]  = {
+static struct msm_bus_vectors enc_ocmem_init_vectors[]  = {
 	{
 		.src = MSM_BUS_MASTER_VIDEO_P0_OCMEM,
-		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.dst = MSM_BUS_SLAVE_OCMEM,
 		.ab = 0,
 		.ib = 0,
 	},
 };
 
-static struct msm_bus_vectors ocmem_perf0_vectors[]  = {
+static struct msm_bus_vectors enc_ocmem_perf1_vectors[]  = {
 	{
 		.src = MSM_BUS_MASTER_VIDEO_P0_OCMEM,
 		.dst = MSM_BUS_SLAVE_OCMEM,
-		.ab = 176900000,
-		.ib = 221125000,
+		.ab = 414700000,
+		.ib = 1222000000,
 	},
 };
 
-static struct msm_bus_vectors ocmem_perf1_vectors[]  = {
+static struct msm_bus_vectors enc_ocmem_perf2_vectors[]  = {
+	{
+		.src = MSM_BUS_MASTER_VIDEO_P0_OCMEM,
+		.dst = MSM_BUS_SLAVE_OCMEM,
+		.ab = 940000000,
+		.ib = 1222000000,
+	},
+};
+
+static struct msm_bus_vectors enc_ocmem_perf3_vectors[]  = {
+	{
+		.src = MSM_BUS_MASTER_VIDEO_P0_OCMEM,
+		.dst = MSM_BUS_SLAVE_OCMEM,
+		.ab = 1880000000,
+		.ib = 2444000000U,
+	},
+};
+
+static struct msm_bus_vectors enc_ocmem_perf4_vectors[]  = {
+	{
+		.src = MSM_BUS_MASTER_VIDEO_P0_OCMEM,
+		.dst = MSM_BUS_SLAVE_OCMEM,
+		.ab = 1880000000,
+		.ib = 2444000000U,
+	},
+};
+
+static struct msm_bus_vectors enc_ocmem_perf5_vectors[]  = {
+	{
+		.src = MSM_BUS_MASTER_VIDEO_P0_OCMEM,
+		.dst = MSM_BUS_SLAVE_OCMEM,
+		.ab = 3008000000U,
+		.ib = 3910400000U,
+	},
+};
+
+static struct msm_bus_vectors enc_ocmem_perf6_vectors[]  = {
+	{
+		.src = MSM_BUS_MASTER_VIDEO_P0_OCMEM,
+		.dst = MSM_BUS_SLAVE_OCMEM,
+		.ab = 3760000000U,
+		.ib = 3910400000U,
+	},
+};
+
+
+static struct msm_bus_vectors dec_ocmem_init_vectors[]  = {
+	{
+		.src = MSM_BUS_MASTER_VIDEO_P0_OCMEM,
+		.dst = MSM_BUS_SLAVE_OCMEM,
+		.ab = 0,
+		.ib = 0,
+	},
+};
+
+static struct msm_bus_vectors dec_ocmem_perf1_vectors[]  = {
 	{
 		.src = MSM_BUS_MASTER_VIDEO_P0_OCMEM,
 		.dst = MSM_BUS_SLAVE_OCMEM,
 		.ab = 456200000,
-		.ib = 570250000,
+		.ib = 1556640000,
 	},
 };
 
-static struct msm_bus_vectors ocmem_perf2_vectors[]  = {
+static struct msm_bus_vectors dec_ocmem_perf2_vectors[]  = {
 	{
 		.src = MSM_BUS_MASTER_VIDEO_P0_OCMEM,
 		.dst = MSM_BUS_SLAVE_OCMEM,
 		.ab = 864800000,
-		.ib = 1081000000,
+		.ib = 1556640000,
 	},
 };
 
-static struct msm_bus_paths ocmem_perf_vectors[]  = {
+static struct msm_bus_vectors dec_ocmem_perf3_vectors[]  = {
 	{
-		ARRAY_SIZE(ocmem_init_vectors),
-		ocmem_init_vectors,
-	},
-	{
-		ARRAY_SIZE(ocmem_perf0_vectors),
-		ocmem_perf0_vectors,
-	},
-	{
-		ARRAY_SIZE(ocmem_perf1_vectors),
-		ocmem_perf1_vectors,
-	},
-	{
-		ARRAY_SIZE(ocmem_perf2_vectors),
-		ocmem_perf2_vectors,
+		.src = MSM_BUS_MASTER_VIDEO_P0_OCMEM,
+		.dst = MSM_BUS_SLAVE_OCMEM,
+		.ab = 1729600000,
+		.ib = 3113280000U,
 	},
 };
 
-static struct msm_bus_scale_pdata ocmem_bus_data = {
-	.usecase = ocmem_perf_vectors,
-	.num_usecases = ARRAY_SIZE(ocmem_perf_vectors),
-	.name = "msm_vidc_ocmem",
+static struct msm_bus_vectors dec_ocmem_perf4_vectors[]  = {
+	{
+		.src = MSM_BUS_MASTER_VIDEO_P0_OCMEM,
+		.dst = MSM_BUS_SLAVE_OCMEM,
+		.ab = 1729600000,
+		.ib = 3113280000U,
+	},
 };
 
-static struct msm_bus_vectors vcodec_init_vectors[]  = {
+static struct msm_bus_vectors dec_ocmem_perf5_vectors[]  = {
+	{
+		.src = MSM_BUS_MASTER_VIDEO_P0_OCMEM,
+		.dst = MSM_BUS_SLAVE_OCMEM,
+		.ab = 2767360000U,
+		.ib = 3113280000U,
+	},
+};
+
+static struct msm_bus_vectors dec_ocmem_perf6_vectors[]  = {
+	{
+		.src = MSM_BUS_MASTER_VIDEO_P0_OCMEM,
+		.dst = MSM_BUS_SLAVE_OCMEM,
+		.ab = 3459200000U,
+		.ib = 3459200000U,
+	},
+};
+
+static struct msm_bus_paths enc_ocmem_perf_vectors[]  = {
+	{
+		ARRAY_SIZE(enc_ocmem_init_vectors),
+		enc_ocmem_init_vectors,
+	},
+	{
+		ARRAY_SIZE(enc_ocmem_perf1_vectors),
+		enc_ocmem_perf1_vectors,
+	},
+	{
+		ARRAY_SIZE(enc_ocmem_perf2_vectors),
+		enc_ocmem_perf2_vectors,
+	},
+	{
+		ARRAY_SIZE(enc_ocmem_perf3_vectors),
+		enc_ocmem_perf3_vectors,
+	},
+	{
+		ARRAY_SIZE(enc_ocmem_perf4_vectors),
+		enc_ocmem_perf4_vectors,
+	},
+	{
+		ARRAY_SIZE(enc_ocmem_perf5_vectors),
+		enc_ocmem_perf5_vectors,
+	},
+	{
+		ARRAY_SIZE(enc_ocmem_perf6_vectors),
+		enc_ocmem_perf6_vectors,
+	},
+};
+
+static struct msm_bus_paths dec_ocmem_perf_vectors[]  = {
+	{
+		ARRAY_SIZE(dec_ocmem_init_vectors),
+		dec_ocmem_init_vectors,
+	},
+	{
+		ARRAY_SIZE(dec_ocmem_perf1_vectors),
+		dec_ocmem_perf1_vectors,
+	},
+	{
+		ARRAY_SIZE(dec_ocmem_perf2_vectors),
+		dec_ocmem_perf2_vectors,
+	},
+	{
+		ARRAY_SIZE(dec_ocmem_perf3_vectors),
+		dec_ocmem_perf3_vectors,
+	},
+	{
+		ARRAY_SIZE(dec_ocmem_perf4_vectors),
+		dec_ocmem_perf4_vectors,
+	},
+	{
+		ARRAY_SIZE(dec_ocmem_perf5_vectors),
+		dec_ocmem_perf5_vectors,
+	},
+	{
+		ARRAY_SIZE(dec_ocmem_perf6_vectors),
+		dec_ocmem_perf6_vectors,
+	},
+};
+
+
+static struct msm_bus_scale_pdata enc_ocmem_bus_data = {
+	.usecase = enc_ocmem_perf_vectors,
+	.num_usecases = ARRAY_SIZE(enc_ocmem_perf_vectors),
+	.name = "msm_vidc_enc_ocmem",
+};
+
+static struct msm_bus_scale_pdata dec_ocmem_bus_data = {
+	.usecase = dec_ocmem_perf_vectors,
+	.num_usecases = ARRAY_SIZE(dec_ocmem_perf_vectors),
+	.name = "msm_vidc_dec_ocmem",
+};
+
+static struct msm_bus_vectors enc_ddr_init_vectors[]  = {
 	{
 		.src = MSM_BUS_MASTER_VIDEO_P0,
 		.dst = MSM_BUS_SLAVE_EBI_CH0,
@@ -103,56 +245,196 @@
 	},
 };
 
-static struct msm_bus_vectors vcodec_perf0_vectors[]  = {
+
+static struct msm_bus_vectors enc_ddr_perf1_vectors[]  = {
+	{
+		.src = MSM_BUS_MASTER_VIDEO_P0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 60000000,
+		.ib = 664950000,
+	},
+};
+
+static struct msm_bus_vectors enc_ddr_perf2_vectors[]  = {
+	{
+		.src = MSM_BUS_MASTER_VIDEO_P0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 181000000,
+		.ib = 664950000,
+	},
+};
+
+static struct msm_bus_vectors enc_ddr_perf3_vectors[]  = {
+	{
+		.src = MSM_BUS_MASTER_VIDEO_P0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 403000000,
+		.ib = 664950000,
+	},
+};
+
+static struct msm_bus_vectors enc_ddr_perf4_vectors[]  = {
+	{
+		.src = MSM_BUS_MASTER_VIDEO_P0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 806000000,
+		.ib = 1329900000,
+	},
+};
+
+static struct msm_bus_vectors enc_ddr_perf5_vectors[]  = {
+	{
+		.src = MSM_BUS_MASTER_VIDEO_P0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 1289600000,
+		.ib = 2127840000U,
+	},
+};
+
+static struct msm_bus_vectors enc_ddr_perf6_vectors[]  = {
+	{
+		.src = MSM_BUS_MASTER_VIDEO_P0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 161200000,
+		.ib = 2659800000U,
+	},
+};
+
+static struct msm_bus_vectors dec_ddr_init_vectors[]  = {
+	{
+		.src = MSM_BUS_MASTER_VIDEO_P0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+};
+
+static struct msm_bus_vectors dec_ddr_perf1_vectors[]  = {
 	{
 		.src = MSM_BUS_MASTER_VIDEO_P0,
 		.dst = MSM_BUS_SLAVE_EBI_CH0,
 		.ab = 110000000,
-		.ib = 137500000,
+		.ib = 909000000,
 	},
 };
 
-static struct msm_bus_vectors vcodec_perf1_vectors[]  = {
+static struct msm_bus_vectors dec_ddr_perf2_vectors[]  = {
 	{
 		.src = MSM_BUS_MASTER_VIDEO_P0,
 		.dst = MSM_BUS_SLAVE_EBI_CH0,
 		.ab = 268000000,
-		.ib = 335000000,
+		.ib = 909000000,
 	},
 };
 
-static struct msm_bus_vectors vcodec_perf2_vectors[]  = {
+static struct msm_bus_vectors dec_ddr_perf3_vectors[]  = {
 	{
 		.src = MSM_BUS_MASTER_VIDEO_P0,
 		.dst = MSM_BUS_SLAVE_EBI_CH0,
 		.ab = 505000000,
-		.ib = 631250000,
+		.ib = 909000000,
 	},
 };
 
-static struct msm_bus_paths vcodec_perf_vectors[]  = {
+static struct msm_bus_vectors dec_ddr_perf4_vectors[]  = {
 	{
-		ARRAY_SIZE(vcodec_init_vectors),
-		vcodec_init_vectors,
-	},
-	{
-		ARRAY_SIZE(vcodec_perf0_vectors),
-		vcodec_perf0_vectors,
-	},
-	{
-		ARRAY_SIZE(vcodec_perf1_vectors),
-		vcodec_perf1_vectors,
-	},
-	{
-		ARRAY_SIZE(vcodec_perf2_vectors),
-		vcodec_perf2_vectors,
+		.src = MSM_BUS_MASTER_VIDEO_P0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 1010000000,
+		.ib = 1818000000,
 	},
 };
 
-static struct msm_bus_scale_pdata vcodec_bus_data = {
-	.usecase = vcodec_perf_vectors,
-	.num_usecases = ARRAY_SIZE(vcodec_perf_vectors),
-	.name = "msm_vidc_vcodec",
+static struct msm_bus_vectors dec_ddr_perf5_vectors[]  = {
+	{
+		.src = MSM_BUS_MASTER_VIDEO_P0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 1616000000,
+		.ib = 2908800000U,
+	},
+};
+
+static struct msm_bus_vectors dec_ddr_perf6_vectors[]  = {
+	{
+		.src = MSM_BUS_MASTER_VIDEO_P0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 2020000000U,
+		.ib = 3636000000U,
+	},
+};
+
+static struct msm_bus_paths enc_ddr_perf_vectors[]  = {
+	{
+		ARRAY_SIZE(enc_ddr_init_vectors),
+		enc_ddr_init_vectors,
+	},
+	{
+		ARRAY_SIZE(enc_ddr_perf1_vectors),
+		enc_ddr_perf1_vectors,
+	},
+	{
+		ARRAY_SIZE(enc_ddr_perf2_vectors),
+		enc_ddr_perf2_vectors,
+	},
+	{
+		ARRAY_SIZE(enc_ddr_perf3_vectors),
+		enc_ddr_perf3_vectors,
+	},
+	{
+		ARRAY_SIZE(enc_ddr_perf4_vectors),
+		enc_ddr_perf4_vectors,
+	},
+	{
+		ARRAY_SIZE(enc_ddr_perf5_vectors),
+		enc_ddr_perf5_vectors,
+	},
+	{
+		ARRAY_SIZE(enc_ddr_perf6_vectors),
+		enc_ddr_perf6_vectors,
+	},
+};
+
+static struct msm_bus_paths dec_ddr_perf_vectors[]  = {
+	{
+		ARRAY_SIZE(dec_ddr_init_vectors),
+		dec_ddr_init_vectors,
+	},
+	{
+		ARRAY_SIZE(dec_ddr_perf1_vectors),
+		dec_ddr_perf1_vectors,
+	},
+	{
+		ARRAY_SIZE(dec_ddr_perf2_vectors),
+		dec_ddr_perf2_vectors,
+	},
+	{
+		ARRAY_SIZE(dec_ddr_perf3_vectors),
+		dec_ddr_perf3_vectors,
+	},
+	{
+		ARRAY_SIZE(dec_ddr_perf4_vectors),
+		dec_ddr_perf4_vectors,
+	},
+	{
+		ARRAY_SIZE(dec_ddr_perf5_vectors),
+		dec_ddr_perf5_vectors,
+	},
+	{
+		ARRAY_SIZE(dec_ddr_perf6_vectors),
+		dec_ddr_perf6_vectors,
+	},
+};
+
+static struct msm_bus_scale_pdata enc_ddr_bus_data = {
+	.usecase = enc_ddr_perf_vectors,
+	.num_usecases = ARRAY_SIZE(enc_ddr_perf_vectors),
+	.name = "msm_vidc_enc_ddr",
+};
+
+static struct msm_bus_scale_pdata dec_ddr_bus_data = {
+	.usecase = dec_ddr_perf_vectors,
+	.num_usecases = ARRAY_SIZE(dec_ddr_perf_vectors),
+	.name = "msm_vidc_dec_ddr",
 };
 
 struct msm_vidc_drv *vidc_driver;
@@ -164,6 +446,7 @@
 	int buff_off;
 	int size;
 	u32 uvaddr;
+	u32 device_addr;
 	struct msm_smem *handle;
 };
 
@@ -209,7 +492,7 @@
 	struct buffer_info *temp;
 	struct buffer_info *ret = NULL;
 	if (!list || fd < 0) {
-		pr_err("%s Invalid input\n", __func__);
+		dprintk(VIDC_ERR, "Invalid input\n");
 		goto err_invalid_input;
 	}
 	if (!list_empty(list)) {
@@ -219,7 +502,30 @@
 			|| CONTAINS(buff_off, size, temp->buff_off)
 			|| OVERLAPS(buff_off, size,
 				temp->buff_off, temp->size))) {
-				pr_err("This memory region is already mapped\n");
+				dprintk(VIDC_WARN,
+				"This memory region is already mapped\n");
+				ret = temp;
+				break;
+			}
+		}
+	}
+err_invalid_input:
+	return ret;
+}
+
+struct buffer_info *get_same_fd_buffer(struct list_head *list,
+		int fd)
+{
+	struct buffer_info *temp;
+	struct buffer_info *ret = NULL;
+	if (!list || fd < 0) {
+		dprintk(VIDC_ERR, "Invalid input\n");
+		goto err_invalid_input;
+	}
+	if (!list_empty(list)) {
+		list_for_each_entry(temp, list, list) {
+			if (temp && temp->fd == fd)  {
+				dprintk(VIDC_ERR, "Found same fd buffer\n");
 				ret = temp;
 				break;
 			}
@@ -239,20 +545,22 @@
 	struct msm_v4l2_vid_inst *v4l2_inst = kzalloc(sizeof(*v4l2_inst),
 						GFP_KERNEL);
 	if (!v4l2_inst) {
-		pr_err("Failed to allocate memory for this instance\n");
+		dprintk(VIDC_ERR,
+			"Failed to allocate memory for this instance\n");
 		rc = -ENOMEM;
 		goto fail_nomem;
 	}
 	v4l2_inst->mem_client = msm_smem_new_client(SMEM_ION);
 	if (!v4l2_inst->mem_client) {
-		pr_err("Failed to create memory client\n");
+		dprintk(VIDC_ERR, "Failed to create memory client\n");
 		rc = -ENOMEM;
 		goto fail_mem_client;
 	}
 	rc = msm_vidc_open(&v4l2_inst->vidc_inst, core->id, vid_dev->type);
 	if (rc) {
-		pr_err("Failed to create video instance, core: %d, type = %d\n",
-			core->id, vid_dev->type);
+		dprintk(VIDC_ERR,
+		"Failed to create video instance, core: %d, type = %d\n",
+		core->id, vid_dev->type);
 		rc = -ENOMEM;
 		goto fail_open;
 	}
@@ -351,18 +659,20 @@
 				plane.reserved[0] = bi->fd;
 				plane.reserved[1] = bi->buff_off;
 				plane.length = bi->size;
-				plane.m.userptr = bi->uvaddr;
+				plane.m.userptr = bi->device_addr;
 				buffer_info.m.planes = &plane;
 				buffer_info.length = 1;
-				pr_info("Releasing buffer: %d, %d, %d\n",
-				buffer_info.m.planes[0].reserved[0],
-				buffer_info.m.planes[0].reserved[1],
-				buffer_info.m.planes[0].length);
+				dprintk(VIDC_DBG,
+					"Releasing buffer: %d, %d, %d\n",
+					buffer_info.m.planes[0].reserved[0],
+					buffer_info.m.planes[0].reserved[1],
+					buffer_info.m.planes[0].length);
 				rc = msm_vidc_release_buf(&v4l2_inst->vidc_inst,
 					&buffer_info);
 				list_del(&bi->list);
-				msm_smem_free(v4l2_inst->mem_client,
-					bi->handle);
+				if (bi->handle)
+					msm_smem_free(v4l2_inst->mem_client,
+							bi->handle);
 				kfree(bi);
 			}
 		}
@@ -373,15 +683,16 @@
 int msm_v4l2_prepare_buf(struct file *file, void *fh,
 				struct v4l2_buffer *b)
 {
-	struct msm_smem *handle;
+	struct msm_smem *handle = NULL;
 	struct buffer_info *binfo;
+	struct buffer_info *temp;
 	struct msm_vidc_inst *vidc_inst;
 	struct msm_v4l2_vid_inst *v4l2_inst;
 	int i, rc = 0;
 	vidc_inst = get_vidc_inst(file, fh);
 	v4l2_inst = get_v4l2_inst(file, fh);
 	if (!v4l2_inst->mem_client) {
-		pr_err("Failed to get memory client\n");
+		dprintk(VIDC_ERR, "Failed to get memory client\n");
 		rc = -ENOMEM;
 		goto exit;
 	}
@@ -391,38 +702,55 @@
 				b->m.planes[i].reserved[1],
 				b->m.planes[i].length);
 		if (binfo) {
-			pr_err("This memory region has already been prepared\n");
+			dprintk(VIDC_WARN,
+				"This memory region has already been prepared\n");
 			rc = -EINVAL;
 			goto exit;
 		}
 		binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
 		if (!binfo) {
-			pr_err("Out of memory\n");
+			dprintk(VIDC_ERR, "Out of memory\n");
 			rc = -ENOMEM;
 			goto exit;
 		}
-		handle = msm_smem_user_to_kernel(v4l2_inst->mem_client,
+		temp = get_same_fd_buffer(&v4l2_inst->registered_bufs,
+				b->m.planes[i].reserved[0]);
+		if (temp) {
+			binfo->type = b->type;
+			binfo->fd = b->m.planes[i].reserved[0];
+			binfo->buff_off = b->m.planes[i].reserved[1];
+			binfo->size = b->m.planes[i].length;
+			binfo->uvaddr = b->m.planes[i].m.userptr;
+			binfo->device_addr =
+				temp->handle->device_addr + binfo->buff_off;
+			binfo->handle = NULL;
+		} else {
+			handle = msm_smem_user_to_kernel(v4l2_inst->mem_client,
 			b->m.planes[i].reserved[0],
 			b->m.planes[i].reserved[1],
 			vidc_inst->core->resources.io_map[NS_MAP].domain,
 			0);
-		if (!handle) {
-			pr_err("Failed to get device buffer address\n");
-			kfree(binfo);
-			goto exit;
+			if (!handle) {
+				dprintk(VIDC_ERR,
+					"Failed to get device buffer address\n");
+				kfree(binfo);
+				goto exit;
+			}
+			binfo->type = b->type;
+			binfo->fd = b->m.planes[i].reserved[0];
+			binfo->buff_off = b->m.planes[i].reserved[1];
+			binfo->size = b->m.planes[i].length;
+			binfo->uvaddr = b->m.planes[i].m.userptr;
+			binfo->device_addr =
+				handle->device_addr + binfo->buff_off;
+			binfo->handle = handle;
+			dprintk(VIDC_DBG, "Registering buffer: %d, %d, %d\n",
+					b->m.planes[i].reserved[0],
+					b->m.planes[i].reserved[1],
+					b->m.planes[i].length);
 		}
-		binfo->type = b->type;
-		binfo->fd = b->m.planes[i].reserved[0];
-		binfo->buff_off = b->m.planes[i].reserved[1];
-		binfo->size = b->m.planes[i].length;
-		binfo->uvaddr = b->m.planes[i].m.userptr;
-		binfo->handle = handle;
-		pr_debug("Registering buffer: %d, %d, %d\n",
-				b->m.planes[i].reserved[0],
-				b->m.planes[i].reserved[1],
-				b->m.planes[i].length);
 		list_add_tail(&binfo->list, &v4l2_inst->registered_bufs);
-		b->m.planes[i].m.userptr = handle->device_addr;
+		b->m.planes[i].m.userptr = binfo->device_addr;
 	}
 	rc = msm_vidc_prepare_buf(&v4l2_inst->vidc_inst, b);
 exit:
@@ -445,16 +773,26 @@
 				b->m.planes[i].reserved[1],
 				b->m.planes[i].length);
 		if (!binfo) {
-			pr_err("This buffer is not registered: %d, %d, %d\n",
+			dprintk(VIDC_ERR,
+				"This buffer is not registered: %d, %d, %d\n",
 				b->m.planes[i].reserved[0],
 				b->m.planes[i].reserved[1],
 				b->m.planes[i].length);
 			rc = -EINVAL;
 			goto err_invalid_buff;
 		}
-		b->m.planes[i].m.userptr = binfo->handle->device_addr;
-		pr_debug("Queueing device address = %ld\n",
-				binfo->handle->device_addr);
+		b->m.planes[i].m.userptr = binfo->device_addr;
+		dprintk(VIDC_DBG, "Queueing device address = 0x%x\n",
+				binfo->device_addr);
+		if (binfo->handle) {
+			rc = msm_smem_clean_invalidate(v4l2_inst->mem_client,
+					binfo->handle);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"Failed to clean caches: %d\n", rc);
+				goto err_invalid_buff;
+			}
+		}
 	}
 	rc = msm_vidc_qbuf(&v4l2_inst->vidc_inst, b);
 err_invalid_buff:
@@ -505,6 +843,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 +869,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 = {
@@ -555,21 +901,24 @@
 	size_t sz = 0;
 	struct device_node *np = pdev->dev.of_node;
 	if (!of_get_property(np, name, &len)) {
-		pr_err("Failed to read %s from device tree\n",
+		dprintk(VIDC_ERR, "Failed to read %s from device tree\n",
 			name);
 		goto fail_read;
 	}
 	sz = len / sizeof(u32);
 	if (sz <= 0) {
-		pr_err("%s not specified in device tree\n", name);
+		dprintk(VIDC_ERR, "%s not specified in device tree\n",
+			name);
 		goto fail_read;
 	}
 	if (sz > size) {
-		pr_err("Not enough memory to store %s values\n", name);
+		dprintk(VIDC_ERR, "Not enough memory to store %s values\n",
+			name);
 		goto fail_read;
 	}
 	if (of_property_read_u32_array(np, name, arr, sz)) {
-		pr_err("error while reading %s from device tree\n",
+		dprintk(VIDC_ERR,
+			"error while reading %s from device tree\n",
 			name);
 		goto fail_read;
 	}
@@ -583,7 +932,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;
@@ -602,21 +951,36 @@
 				io_map[i].addr_range,
 				(sizeof(io_map[i].addr_range)/sizeof(u32)));
 		if (!len) {
-			pr_err("Error in reading cp address range\n");
+			dprintk(VIDC_ERR,
+				"Error in reading cp address range\n");
 			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);
+		dprintk(VIDC_DBG, "Registering domain 1 with: %lx, %lx, %s\n",
+			partition[0].start, partition[0].size,
+			layout.client_name);
+		dprintk(VIDC_DBG, "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");
+			dprintk(VIDC_ERR, "Failed to register cp domain\n");
 			rc = -EINVAL;
 			break;
 		}
@@ -636,7 +1000,7 @@
 	int rc = 0;
 	struct core_clock *clock;
 	if (!core) {
-		pr_err("Invalid params: %p\n", core);
+		dprintk(VIDC_ERR, "Invalid params: %p\n", core);
 		return -EINVAL;
 	}
 	clock = core->resources.clock;
@@ -653,13 +1017,14 @@
 		"load-freq-tbl", (u32 *)clock[VCODEC_CLK].load_freq_tbl,
 		(sizeof(clock[VCODEC_CLK].load_freq_tbl)/sizeof(u32)));
 	clock[VCODEC_CLK].count /= 2;
-	pr_err("NOTE: Count = %d\n", clock[VCODEC_CLK].count);
+	dprintk(VIDC_DBG, "count = %d\n", clock[VCODEC_CLK].count);
 	if (!clock[VCODEC_CLK].count) {
-		pr_err("Failed to read clock frequency\n");
+		dprintk(VIDC_ERR, "Failed to read clock frequency\n");
 		goto fail_init_clocks;
 	}
 	for (i = 0; i <	clock[VCODEC_CLK].count; i++) {
-		pr_err("NOTE: load = %d, freq = %d\n",
+		dprintk(VIDC_DBG,
+				"load = %d, freq = %d\n",
 				clock[VCODEC_CLK].load_freq_tbl[i].load,
 				clock[VCODEC_CLK].load_freq_tbl[i].freq
 			  );
@@ -670,7 +1035,8 @@
 		if (!cl->clk) {
 			cl->clk = devm_clk_get(&pdev->dev, cl->name);
 			if (IS_ERR_OR_NULL(cl->clk)) {
-				pr_err("Failed to get clock: %s\n", cl->name);
+				dprintk(VIDC_ERR,
+					"Failed to get clock: %s\n", cl->name);
 				rc = PTR_ERR(cl->clk);
 				break;
 			}
@@ -691,7 +1057,7 @@
 {
 	int i;
 	if (!core) {
-		pr_err("Invalid args\n");
+		dprintk(VIDC_ERR, "Invalid args\n");
 		return;
 	}
 	for (i = 0; i < VCODEC_MAX_CLKS; i++)
@@ -709,7 +1075,7 @@
 		return -EINVAL;
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res) {
-		pr_err("Failed to get IORESOURCE_MEM\n");
+		dprintk(VIDC_ERR, "Failed to get IORESOURCE_MEM\n");
 		rc = -ENODEV;
 		goto core_init_failed;
 	}
@@ -717,7 +1083,7 @@
 	core->register_size = resource_size(res);
 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 	if (!res) {
-		pr_err("Failed to get IORESOURCE_IRQ\n");
+		dprintk(VIDC_ERR, "Failed to get IORESOURCE_IRQ\n");
 		rc = -ENODEV;
 		goto core_init_failed;
 	}
@@ -733,25 +1099,37 @@
 	}
 	rc = msm_vidc_init_clocks(pdev, core);
 	if (rc) {
-		pr_err("Failed to init clocks\n");
+		dprintk(VIDC_ERR, "Failed to init clocks\n");
 		rc = -ENODEV;
 		goto core_init_failed;
 	}
-	core->resources.bus_info.vcodec_handle =
-		msm_bus_scale_register_client(&vcodec_bus_data);
-	if (!core->resources.bus_info.vcodec_handle) {
-		pr_err("Failed to register bus scale client\n");
-		goto fail_register_vcodec_bus;
+	core->resources.bus_info.ddr_handle[MSM_VIDC_ENCODER] =
+		msm_bus_scale_register_client(&enc_ddr_bus_data);
+	if (!core->resources.bus_info.ddr_handle[MSM_VIDC_ENCODER]) {
+		dprintk(VIDC_ERR, "Failed to register bus scale client\n");
+		goto fail_register_enc_ddr_bus;
 	}
-	core->resources.bus_info.ocmem_handle =
-		msm_bus_scale_register_client(&ocmem_bus_data);
-	if (!core->resources.bus_info.ocmem_handle) {
-		pr_err("Failed to register bus scale client\n");
-		goto fail_register_ocmem;
+	core->resources.bus_info.ddr_handle[MSM_VIDC_DECODER] =
+		msm_bus_scale_register_client(&dec_ddr_bus_data);
+	if (!core->resources.bus_info.ddr_handle[MSM_VIDC_DECODER]) {
+		dprintk(VIDC_ERR, "Failed to register bus scale client\n");
+		goto fail_register_dec_ddr_bus;
+	}
+	core->resources.bus_info.ocmem_handle[MSM_VIDC_ENCODER] =
+		msm_bus_scale_register_client(&enc_ocmem_bus_data);
+	if (!core->resources.bus_info.ocmem_handle[MSM_VIDC_ENCODER]) {
+		dprintk(VIDC_ERR, "Failed to register bus scale client\n");
+		goto fail_register_enc_ocmem;
+	}
+	core->resources.bus_info.ocmem_handle[MSM_VIDC_DECODER] =
+		msm_bus_scale_register_client(&dec_ocmem_bus_data);
+	if (!core->resources.bus_info.ocmem_handle[MSM_VIDC_DECODER]) {
+		dprintk(VIDC_ERR, "Failed to register bus scale client\n");
+		goto fail_register_dec_ocmem;
 	}
 	rc = register_iommu_domains(pdev, core);
 	if (rc) {
-		pr_err("Failed to register iommu domains: %d\n", rc);
+		dprintk(VIDC_ERR, "Failed to register iommu domains: %d\n", rc);
 		goto fail_register_domains;
 	}
 	ocmem = &core->resources.ocmem;
@@ -759,17 +1137,23 @@
 	ocmem->handle =
 		ocmem_notifier_register(OCMEM_VIDEO, &ocmem->vidc_ocmem_nb);
 	if (!ocmem->handle) {
-		pr_warn("Failed to register OCMEM notifier.");
-		pr_warn(" Performance will be impacted\n");
+		dprintk(VIDC_WARN, "Failed to register OCMEM notifier.");
+		dprintk(VIDC_WARN, " Performance will be impacted\n");
 	}
 	return rc;
 fail_register_domains:
 	msm_bus_scale_unregister_client(
-		core->resources.bus_info.ocmem_handle);
-fail_register_ocmem:
+		core->resources.bus_info.ocmem_handle[MSM_VIDC_DECODER]);
+fail_register_dec_ocmem:
 	msm_bus_scale_unregister_client(
-		core->resources.bus_info.vcodec_handle);
-fail_register_vcodec_bus:
+		core->resources.bus_info.ocmem_handle[MSM_VIDC_ENCODER]);
+fail_register_enc_ocmem:
+	msm_bus_scale_unregister_client(
+		core->resources.bus_info.ddr_handle[MSM_VIDC_DECODER]);
+fail_register_dec_ddr_bus:
+	msm_bus_scale_unregister_client(
+		core->resources.bus_info.ddr_handle[MSM_VIDC_ENCODER]);
+fail_register_enc_ddr_bus:
 	msm_vidc_deinit_clocks(core);
 core_init_failed:
 	return rc;
@@ -780,22 +1164,21 @@
 	int rc = 0;
 	struct msm_vidc_core *core;
 	unsigned long flags;
-	char debugfs_name[MAX_DEBUGFS_NAME];
-
 	core = kzalloc(sizeof(*core), GFP_KERNEL);
 	if (!core || !vidc_driver) {
-		pr_err("Failed to allocate memory for device core\n");
+		dprintk(VIDC_ERR,
+			"Failed to allocate memory for device core\n");
 		rc = -ENOMEM;
 		goto err_no_mem;
 	}
 	rc = msm_vidc_initialize_core(pdev, core);
 	if (rc) {
-		pr_err("Failed to init core\n");
+		dprintk(VIDC_ERR, "Failed to init core\n");
 		goto err_v4l2_register;
 	}
 	rc = v4l2_device_register(&pdev->dev, &core->v4l2_dev);
 	if (rc) {
-		pr_err("Failed to register v4l2 device\n");
+		dprintk(VIDC_ERR, "Failed to register v4l2 device\n");
 		goto err_v4l2_register;
 	}
 	core->vdev[MSM_VIDC_DECODER].vdev.release =
@@ -806,7 +1189,7 @@
 	rc = video_register_device(&core->vdev[MSM_VIDC_DECODER].vdev,
 					VFL_TYPE_GRABBER, BASE_DEVICE_NUMBER);
 	if (rc) {
-		pr_err("Failed to register video decoder device");
+		dprintk(VIDC_ERR, "Failed to register video decoder device");
 		goto err_dec_register;
 	}
 	video_set_drvdata(&core->vdev[MSM_VIDC_DECODER].vdev, core);
@@ -819,7 +1202,7 @@
 	rc = video_register_device(&core->vdev[MSM_VIDC_ENCODER].vdev,
 				VFL_TYPE_GRABBER, BASE_DEVICE_NUMBER + 1);
 	if (rc) {
-		pr_err("Failed to register video encoder device");
+		dprintk(VIDC_ERR, "Failed to register video encoder device");
 		goto err_enc_register;
 	}
 	video_set_drvdata(&core->vdev[MSM_VIDC_ENCODER].vdev, core);
@@ -827,14 +1210,14 @@
 			core->register_base, core->register_size, core->irq,
 			&handle_cmd_response);
 	if (!core->device) {
-		pr_err("Failed to create interrupt handler");
+		dprintk(VIDC_ERR, "Failed to create interrupt handler");
 		goto err_cores_exceeded;
 	}
 
 	spin_lock_irqsave(&vidc_driver->lock, flags);
 	if (vidc_driver->num_cores  + 1 > MSM_VIDC_CORES_MAX) {
 		spin_unlock_irqrestore(&vidc_driver->lock, flags);
-		pr_err("Maximum cores already exist, core_no = %d\n",
+		dprintk(VIDC_ERR, "Maximum cores already exist, core_no = %d\n",
 				vidc_driver->num_cores);
 		goto err_cores_exceeded;
 	}
@@ -842,9 +1225,8 @@
 	core->id = vidc_driver->num_cores++;
 	list_add_tail(&core->list, &vidc_driver->cores);
 	spin_unlock_irqrestore(&vidc_driver->lock, flags);
-	snprintf(debugfs_name, MAX_DEBUGFS_NAME, "core%d", core->id);
-	core->debugfs_root = debugfs_create_dir(debugfs_name,
-						vidc_driver->debugfs_root);
+	core->debugfs_root = msm_vidc_debugfs_init_core(
+		core, vidc_driver->debugfs_root);
 	pdev->dev.platform_data = core;
 	return rc;
 
@@ -864,8 +1246,13 @@
 {
 	int rc = 0;
 	struct msm_vidc_core *core = pdev->dev.platform_data;
-	msm_bus_scale_unregister_client(core->resources.bus_info.vcodec_handle);
-	msm_bus_scale_unregister_client(core->resources.bus_info.ocmem_handle);
+	int i;
+	for (i = 0; i < MSM_VIDC_MAX_DEVICES; ++i) {
+		msm_bus_scale_unregister_client(
+			core->resources.bus_info.ddr_handle[i]);
+		msm_bus_scale_unregister_client(
+			core->resources.bus_info.ocmem_handle[i]);
+	}
 	vidc_hal_delete_device(core->device);
 	video_unregister_device(&core->vdev[MSM_VIDC_ENCODER].vdev);
 	video_unregister_device(&core->vdev[MSM_VIDC_DECODER].vdev);
@@ -898,7 +1285,8 @@
 	vidc_driver = kzalloc(sizeof(*vidc_driver),
 						GFP_KERNEL);
 	if (!vidc_driver) {
-		pr_err("Failed to allocate memroy for msm_vidc_drv\n");
+		dprintk(VIDC_ERR,
+			"Failed to allocate memroy for msm_vidc_drv\n");
 		return -ENOMEM;
 	}
 
@@ -906,11 +1294,13 @@
 	spin_lock_init(&vidc_driver->lock);
 	vidc_driver->debugfs_root = debugfs_create_dir("msm_vidc", NULL);
 	if (!vidc_driver->debugfs_root)
-		pr_err("Failed to create debugfs for msm_vidc\n");
+		dprintk(VIDC_ERR,
+			"Failed to create debugfs for msm_vidc\n");
 
 	rc = platform_driver_register(&msm_vidc_driver);
 	if (rc) {
-		pr_err("Failed to register platform driver\n");
+		dprintk(VIDC_ERR,
+			"Failed to register platform driver\n");
 		kfree(vidc_driver);
 		vidc_driver = NULL;
 	}
diff --git a/drivers/media/video/msm_vidc/msm_vdec.c b/drivers/media/video/msm_vidc/msm_vdec.c
index c87211a..8240890 100644
--- a/drivers/media/video/msm_vidc/msm_vdec.c
+++ b/drivers/media/video/msm_vidc/msm_vdec.c
@@ -17,14 +17,15 @@
 #include "msm_vidc_common.h"
 #include "vidc_hal_api.h"
 #include "msm_smem.h"
+#include "msm_vidc_debug.h"
 
 #define MSM_VDEC_DVC_NAME "msm_vdec_8974"
 #define MAX_PLANES 1
 #define DEFAULT_HEIGHT 720
 #define DEFAULT_WIDTH 1280
-#define MAX_SUPPORTED_WIDTH 4096
-#define MAX_SUPPORTED_HEIGHT 2160
-#define MIN_NUM_OUTPUT_BUFFERS 2
+#define MAX_SUPPORTED_WIDTH 1920
+#define MAX_SUPPORTED_HEIGHT 1088
+#define MIN_NUM_OUTPUT_BUFFERS 4
 #define MAX_NUM_OUTPUT_BUFFERS 6
 
 static const char *const mpeg_video_vidc_divx_format[] = {
@@ -156,11 +157,23 @@
 static u32 get_frame_size_nv12(int plane,
 					u32 height, u32 width)
 {
-	int luma_stride = ALIGN(width, 32);
-	int luma_slice = ALIGN(height, 32);
-	int chroma_stride = ALIGN(roundup(width, 2)/2, 32);
-	int chroma_slice = ALIGN(roundup(height, 2)/2, 32);
-	return (luma_stride * luma_slice) + (chroma_stride * chroma_slice) * 2;
+	int size;
+	int luma_h, luma_w, luma_stride, luma_scanl, luma_size;
+	int chroma_h, chroma_w, chroma_stride, chroma_scanl, chroma_size;
+
+	luma_w = width;
+	luma_h = height;
+
+	chroma_w = luma_w;
+	chroma_h = luma_h/2;
+	NV12_IL_CALC_Y_STRIDE(luma_stride, luma_w, 32);
+	NV12_IL_CALC_Y_BUFHEIGHT(luma_scanl, luma_h, 32);
+	NV12_IL_CALC_UV_STRIDE(chroma_stride, chroma_w, 32);
+	NV12_IL_CALC_UV_BUFHEIGHT(chroma_scanl, luma_h, 32);
+	NV12_IL_CALC_BUF_SIZE(size, luma_size, luma_stride,
+		luma_scanl, chroma_size, chroma_stride, chroma_scanl, 32);
+	size = ALIGN(size, SZ_4K);
+	return size;
 }
 static u32 get_frame_size_nv21(int plane,
 					u32 height, u32 width)
@@ -263,13 +276,14 @@
 	struct vb2_queue *q;
 	q = msm_comm_get_vb2q(inst, i);
 	if (!q) {
-		pr_err("Failed to find buffer queue for type = %d\n", i);
+		dprintk(VIDC_ERR,
+			"Failed to find buffer queue for type = %d\n", i);
 		return -EINVAL;
 	}
-	pr_debug("Calling streamon\n");
+	dprintk(VIDC_DBG, "Calling streamon\n");
 	rc = vb2_streamon(q, i);
 	if (rc)
-		pr_err("streamon failed on port: %d\n", i);
+		dprintk(VIDC_ERR, "streamon failed on port: %d\n", i);
 	return rc;
 }
 
@@ -280,13 +294,14 @@
 
 	q = msm_comm_get_vb2q(inst, i);
 	if (!q) {
-		pr_err("Failed to find buffer queue for type = %d\n", i);
+		dprintk(VIDC_ERR,
+			"Failed to find buffer queue for type = %d\n", i);
 		return -EINVAL;
 	}
-	pr_debug("Calling streamoff\n");
+	dprintk(VIDC_DBG, "Calling streamoff\n");
 	rc = vb2_streamoff(q, i);
 	if (rc)
-		pr_err("streamoff failed on port: %d\n", i);
+		dprintk(VIDC_ERR, "streamoff failed on port: %d\n", i);
 	return rc;
 }
 
@@ -301,7 +316,7 @@
 		break;
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
 		for (i = 0; i < b->length; i++) {
-			pr_err("device_addr = %ld, size = %d\n",
+			dprintk(VIDC_DBG, "device_addr = %ld, size = %d\n",
 				b->m.planes[i].m.userptr,
 				b->m.planes[i].length);
 			buffer_info.buffer_size = b->m.planes[i].length;
@@ -312,11 +327,12 @@
 			if (!inst->extradata_handle) {
 				inst->extradata_handle =
 				msm_smem_alloc(inst->mem_client,
-				4096 * 1024, 1, 0,
+				4096 * 1024, 1, SMEM_UNCACHED,
 				inst->core->resources.io_map[NS_MAP].domain,
-				0);
+				0, 0);
 				if (!inst->extradata_handle) {
-					pr_err("Failed to allocate extradta memory\n");
+					dprintk(VIDC_ERR,
+						"Failed to allocate extradta memory\n");
 					rc = -ENOMEM;
 					break;
 				}
@@ -327,13 +343,14 @@
 			rc = vidc_hal_session_set_buffers((void *)inst->session,
 					&buffer_info);
 			if (rc) {
-				pr_err("vidc_hal_session_set_buffers failed");
+				dprintk(VIDC_ERR,
+					"vidc_hal_session_set_buffers failed\n");
 				break;
 			}
 		}
 		break;
 	default:
-		pr_err("Buffer type not recognized: %d\n", b->type);
+		dprintk(VIDC_ERR, "Buffer type not recognized: %d\n", b->type);
 		break;
 	}
 	return rc;
@@ -351,7 +368,8 @@
 		break;
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
 		for (i = 0; i < b->length; i++) {
-			pr_debug("Release device_addr = %ld, size = %d\n",
+			dprintk(VIDC_DBG,
+				"Release device_addr = %ld, size = %d\n",
 				b->m.planes[i].m.userptr,
 				b->m.planes[i].length);
 			buffer_info.buffer_size = b->m.planes[i].length;
@@ -364,11 +382,12 @@
 			rc = vidc_hal_session_release_buffers(
 				(void *)inst->session, &buffer_info);
 			if (rc)
-				pr_err("vidc_hal_session_release_buffers failed");
+				dprintk(VIDC_ERR,
+					"vidc_hal_session_release_buffers failed\n");
 		}
 		break;
 	default:
-		pr_err("Buffer type not recognized: %d\n", b->type);
+		dprintk(VIDC_ERR, "Buffer type not recognized: %d\n", b->type);
 		break;
 	}
 	return rc;
@@ -380,12 +399,13 @@
 	int rc = 0;
 	q = msm_comm_get_vb2q(inst, b->type);
 	if (!q) {
-		pr_err("Failed to find buffer queue for type = %d\n", b->type);
+		dprintk(VIDC_ERR, "Failed to find buffer queue for type = %d\n"
+			, b->type);
 		return -EINVAL;
 	}
 	rc = vb2_qbuf(q, b);
 	if (rc)
-		pr_err("Failed to qbuf, %d\n", rc);
+		dprintk(VIDC_ERR, "Failed to qbuf, %d\n", rc);
 	return rc;
 }
 int msm_vdec_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
@@ -394,12 +414,13 @@
 	int rc = 0;
 	q = msm_comm_get_vb2q(inst, b->type);
 	if (!q) {
-		pr_err("Failed to find buffer queue for type = %d\n", b->type);
+		dprintk(VIDC_ERR, "Failed to find buffer queue for type = %d\n"
+			, b->type);
 		return -EINVAL;
 	}
 	rc = vb2_dqbuf(q, b, true);
 	if (rc)
-		pr_err("Failed to dqbuf, %d\n", rc);
+		dprintk(VIDC_WARN, "Failed to dqbuf, %d\n", rc);
 	return rc;
 }
 
@@ -408,18 +429,20 @@
 	struct vb2_queue *q = NULL;
 	int rc = 0;
 	if (!inst || !b) {
-		pr_err("Invalid input, inst = %p, buffer = %p\n", inst, b);
+		dprintk(VIDC_ERR,
+			"Invalid input, inst = %p, buffer = %p\n", inst, b);
 		return -EINVAL;
 	}
 	q = msm_comm_get_vb2q(inst, b->type);
 	if (!q) {
-		pr_err("Failed to find buffer queue for type = %d\n", b->type);
+		dprintk(VIDC_ERR, "Failed to find buffer queue for type = %d\n"
+			, b->type);
 		return -EINVAL;
 	}
 
 	rc = vb2_reqbufs(q, b);
 	if (rc)
-		pr_err("Failed to get reqbufs, %d\n", rc);
+		dprintk(VIDC_ERR, "Failed to get reqbufs, %d\n", rc);
 	return rc;
 }
 
@@ -429,7 +452,8 @@
 	int rc = 0;
 	int i;
 	if (!inst || !f) {
-		pr_err("Invalid input, inst = %p, format = %p\n", inst, f);
+		dprintk(VIDC_ERR,
+			"Invalid input, inst = %p, format = %p\n", inst, f);
 		return -EINVAL;
 	}
 	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
@@ -452,7 +476,7 @@
 				inst->prop.width);
 		}
 	} else {
-		pr_err("Buf type not recognized, type = %d\n",
+		dprintk(VIDC_ERR, "Buf type not recognized, type = %d\n",
 					f->type);
 		rc = -EINVAL;
 	}
@@ -465,28 +489,48 @@
 	int rc = 0;
 	int i;
 	if (!inst || !f) {
-		pr_err("Invalid input, inst = %p, format = %p\n", inst, f);
+		dprintk(VIDC_ERR,
+			"Invalid input, inst = %p, format = %p\n", inst, f);
 		return -EINVAL;
 	}
 	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
-		inst->prop.width = f->fmt.pix_mp.width;
-		inst->prop.height = f->fmt.pix_mp.height;
+		struct hal_frame_size frame_sz;
+
 		fmt = msm_comm_get_pixel_fmt_fourcc(vdec_formats,
 			ARRAY_SIZE(vdec_formats), f->fmt.pix_mp.pixelformat,
 			CAPTURE_PORT);
 		if (fmt && fmt->type != CAPTURE_PORT) {
-			pr_err("Format: %d not supported on CAPTURE port\n",
-					f->fmt.pix_mp.pixelformat);
+			dprintk(VIDC_ERR,
+				"Format: %d not supported on CAPTURE"
+				"port\n", f->fmt.pix_mp.pixelformat);
 			rc = -EINVAL;
 			goto err_invalid_fmt;
 		}
+
+		inst->prop.width = f->fmt.pix_mp.width;
+		inst->prop.height = f->fmt.pix_mp.height;
+
+		frame_sz.buffer_type = HAL_BUFFER_OUTPUT;
+		frame_sz.width = inst->prop.width;
+		frame_sz.height = inst->prop.height;
+		dprintk(VIDC_DBG,
+			"width = %d, height = %d\n",
+			frame_sz.width, frame_sz.height);
+		rc = vidc_hal_session_set_property((void *)inst->session,
+				HAL_PARAM_FRAME_SIZE, &frame_sz);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"Failed to set hal property for framesize\n");
+			goto err_invalid_fmt;
+		}
 	} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
 		fmt = msm_comm_get_pixel_fmt_fourcc(vdec_formats,
 			ARRAY_SIZE(vdec_formats), f->fmt.pix_mp.pixelformat,
 			OUTPUT_PORT);
 		if (fmt && fmt->type != OUTPUT_PORT) {
-			pr_err("Format: %d not supported on OUTPUT port\n",
-					f->fmt.pix_mp.pixelformat);
+			dprintk(VIDC_ERR,
+				"Format: %d not supported on OUTPUT port\n",
+				f->fmt.pix_mp.pixelformat);
 			rc = -EINVAL;
 			goto err_invalid_fmt;
 		}
@@ -503,13 +547,13 @@
 		if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
 			rc = msm_comm_try_state(inst, MSM_VIDC_OPEN);
 			if (rc) {
-				pr_err("Failed to open instance\n");
+				dprintk(VIDC_ERR, "Failed to open instance\n");
 				goto err_invalid_fmt;
 			}
 		}
 	} else {
-		pr_err("Buf type not recognized, type = %d\n",
-					f->type);
+		dprintk(VIDC_ERR,
+			"Buf type not recognized, type = %d\n", f->type);
 		rc = -EINVAL;
 	}
 err_invalid_fmt:
@@ -519,7 +563,8 @@
 int msm_vdec_querycap(struct msm_vidc_inst *inst, struct v4l2_capability *cap)
 {
 	if (!inst || !cap) {
-		pr_err("Invalid input, inst = %p, cap = %p\n", inst, cap);
+		dprintk(VIDC_ERR,
+			"Invalid input, inst = %p, cap = %p\n", inst, cap);
 		return -EINVAL;
 	}
 	strlcpy(cap->driver, MSM_VIDC_DRV_NAME, sizeof(cap->driver));
@@ -538,7 +583,8 @@
 	const struct msm_vidc_format *fmt = NULL;
 	int rc = 0;
 	if (!inst || !f) {
-		pr_err("Invalid input, inst = %p, f = %p\n", inst, f);
+		dprintk(VIDC_ERR,
+			"Invalid input, inst = %p, f = %p\n", inst, f);
 		return -EINVAL;
 	}
 	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
@@ -556,7 +602,7 @@
 				sizeof(f->description));
 		f->pixelformat = fmt->fourcc;
 	} else {
-		pr_err("No more formats found\n");
+		dprintk(VIDC_WARN, "No more formats found\n");
 		rc = -EINVAL;
 	}
 	return rc;
@@ -570,10 +616,10 @@
 {
 	int i, rc = 0;
 	struct msm_vidc_inst *inst;
-	struct hal_frame_size frame_sz;
 	unsigned long flags;
+	struct hal_buffer_requirements *bufreq;
 	if (!q || !q->drv_priv) {
-		pr_err("Invalid input, q = %p\n", q);
+		dprintk(VIDC_ERR, "Invalid input, q = %p\n", q);
 		return -EINVAL;
 	}
 	inst = q->drv_priv;
@@ -589,33 +635,41 @@
 		}
 		break;
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
-		pr_debug("Getting bufreqs on capture plane\n");
+		dprintk(VIDC_DBG, "Getting bufreqs on capture plane\n");
 		rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
 		if (rc) {
-			pr_err("Failed to open instance\n");
-			break;
-		}
-		frame_sz.buffer_type = HAL_BUFFER_OUTPUT;
-		frame_sz.width = inst->prop.width;
-		frame_sz.height = inst->prop.height;
-		pr_debug("width = %d, height = %d\n",
-				frame_sz.width, frame_sz.height);
-		rc = vidc_hal_session_set_property((void *)inst->session,
-				HAL_PARAM_FRAME_SIZE, &frame_sz);
-		if (rc) {
-			pr_err("Failed to set hal property for framesize\n");
+			dprintk(VIDC_ERR, "Failed to open instance\n");
 			break;
 		}
 		rc = msm_comm_try_get_bufreqs(inst);
 		if (rc) {
-			pr_err("Failed to get buffer requirements: %d\n", rc);
+			dprintk(VIDC_ERR,
+				"Failed to get buffer requirements: %d\n", rc);
 			break;
 		}
 		*num_planes = 1;
 		spin_lock_irqsave(&inst->lock, flags);
-		*num_buffers = inst->buff_req.buffer[1].buffer_count_actual;
+		if (*num_buffers && *num_buffers >
+			inst->buff_req.buffer[HAL_BUFFER_OUTPUT].
+				buffer_count_actual) {
+			struct hal_buffer_count_actual new_buf_count;
+			enum hal_property property_id =
+				HAL_PARAM_BUFFER_COUNT_ACTUAL;
+
+			new_buf_count.buffer_type = HAL_BUFFER_OUTPUT;
+			new_buf_count.buffer_count_actual = *num_buffers;
+			rc = vidc_hal_session_set_property(inst->session,
+					property_id, &new_buf_count);
+
+		}
+		bufreq = &inst->buff_req.buffer[HAL_BUFFER_OUTPUT];
+		if (bufreq->buffer_count_actual > *num_buffers)
+			*num_buffers =  bufreq->buffer_count_actual;
+		else
+			bufreq->buffer_count_actual = *num_buffers ;
 		spin_unlock_irqrestore(&inst->lock, flags);
-		pr_debug("size = %d, alignment = %d\n",
+		dprintk(VIDC_DBG, "count =  %d, size = %d, alignment = %d\n",
+				inst->buff_req.buffer[1].buffer_count_actual,
 				inst->buff_req.buffer[1].buffer_size,
 				inst->buff_req.buffer[1].buffer_alignment);
 		for (i = 0; i < *num_planes; i++) {
@@ -625,7 +679,7 @@
 
 		break;
 	default:
-		pr_err("Invalid q type = %d\n", q->type);
+		dprintk(VIDC_ERR, "Invalid q type = %d\n", q->type);
 		rc = -EINVAL;
 		break;
 	}
@@ -638,29 +692,39 @@
 	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;
-	}
+	inst->in_reconfig = false;
 	rc = msm_comm_set_scratch_buffers(inst);
 	if (rc) {
-		pr_err("Failed to set scratch buffers: %d\n", rc);
+		dprintk(VIDC_ERR,
+			"Failed to set scratch buffers: %d\n", rc);
 		goto fail_start;
 	}
+	rc = msm_comm_set_persist_buffers(inst);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to set persist buffers: %d\n", rc);
+		goto fail_start;
+	}
+	if (msm_comm_scale_clocks(inst->core, inst->session_type)) {
+		dprintk(VIDC_WARN,
+			"Failed to scale clocks. Performance might be impacted\n");
+	}
+
 	rc = msm_comm_try_state(inst, MSM_VIDC_START_DONE);
 	if (rc) {
-		pr_err("Failed to move inst: %p to start done state\n",
-			inst);
+		dprintk(VIDC_ERR,
+			"Failed to move inst: %p to start done state\n", inst);
 		goto fail_start;
 	}
+
 	spin_lock_irqsave(&inst->lock, flags);
 	if (!list_empty(&inst->pendingq)) {
 		list_for_each_safe(ptr, next, &inst->pendingq) {
 			temp = list_entry(ptr, struct vb2_buf_entry, list);
 			rc = msm_comm_qbuf(temp->vb);
 			if (rc) {
-				pr_err("Failed to qbuf to hardware\n");
+				dprintk(VIDC_ERR,
+					"Failed to qbuf to hardware\n");
 				break;
 			}
 			list_del(&temp->list);
@@ -678,26 +742,23 @@
 	struct msm_vidc_inst *inst;
 	int rc = 0;
 	if (!q || !q->drv_priv) {
-		pr_err("Invalid input, q = %p\n", q);
+		dprintk(VIDC_ERR, "Invalid input, q = %p\n", q);
 		return -EINVAL;
 	}
 	inst = q->drv_priv;
-	pr_debug("Streamon called on: %d capability\n", q->type);
+	dprintk(VIDC_DBG,
+		"Streamon called on: %d capability\n", q->type);
 	switch (q->type) {
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
-		if (msm_comm_scale_clocks(inst->core))
-			pr_err("Failed to scale clocks. Performance/power might be impacted\n");
 		if (inst->vb2_bufq[CAPTURE_PORT].streaming)
 			rc = start_streaming(inst);
 		break;
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
-		if (msm_comm_scale_clocks(inst->core))
-			pr_err("Failed to scale clocks. Performance/power might be impacted\n");
 		if (inst->vb2_bufq[OUTPUT_PORT].streaming)
 			rc = start_streaming(inst);
 		break;
 	default:
-		pr_err("Q-type is not supported: %d\n", q->type);
+		dprintk(VIDC_ERR, "Q-type is not supported: %d\n", q->type);
 		rc = -EINVAL;
 		break;
 	}
@@ -709,28 +770,37 @@
 	struct msm_vidc_inst *inst;
 	int rc = 0;
 	if (!q || !q->drv_priv) {
-		pr_err("Invalid input, q = %p\n", q);
+		dprintk(VIDC_ERR, "Invalid input, q = %p\n", q);
 		return -EINVAL;
 	}
 	inst = q->drv_priv;
-	pr_debug("Streamoff called on: %d capability\n", q->type);
+	dprintk(VIDC_DBG, "Streamoff called on: %d capability\n", q->type);
 	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);
+		dprintk(VIDC_ERR,
+			"Q-type is not supported: %d\n", q->type);
 		rc = -EINVAL;
 		break;
 	}
+	if (msm_comm_scale_clocks(inst->core, inst->session_type)) {
+		dprintk(VIDC_WARN,
+			"Failed to scale clocks. Power might be impacted\n");
+	}
+
 	if (rc)
-		pr_err("Failed to move inst: %p, cap = %d to state: %d\n",
-				inst, q->type, MSM_VIDC_CLOSE_DONE);
+		dprintk(VIDC_ERR,
+			"Failed to move inst: %p, cap = %d to state: %d\n",
+			inst, q->type, MSM_VIDC_RELEASE_RESOURCES_DONE);
 	return rc;
 }
 
@@ -739,9 +809,33 @@
 	int rc;
 	rc = msm_comm_qbuf(vb);
 	if (rc)
-		pr_err("Failed to queue buffer: %d\n", rc);
+		dprintk(VIDC_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;
+	switch (dec->cmd) {
+	case V4L2_DEC_QCOM_CMD_FLUSH:
+		rc = msm_comm_flush(inst, dec->flags);
+		break;
+	case V4L2_DEC_CMD_STOP:
+		rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
+		break;
+	default:
+		dprintk(VIDC_ERR, "Unknown Decoder Command\n");
+		rc = -ENOTSUPP;
+		goto exit;
+	}
+	if (rc) {
+		dprintk(VIDC_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,
@@ -758,7 +852,7 @@
 {
 	int rc = 0;
 	if (!inst) {
-		pr_err("Invalid input = %p\n", inst);
+		dprintk(VIDC_ERR, "Invalid input = %p\n", inst);
 		return -EINVAL;
 	}
 	inst->fmts[OUTPUT_PORT] = &vdec_formats[1];
@@ -785,8 +879,8 @@
 	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);
+		dprintk(VIDC_ERR,
+			"Failed to move inst: %p to start done state\n", inst);
 		goto failed_open_done;
 	}
 
@@ -845,16 +939,17 @@
 		break;
 		}
 	if (property_id) {
-		pr_debug("Control: HAL property=%d,ctrl_id=%d,ctrl_value=%d\n",
-			   property_id,
-			   msm_vdec_ctrls[control_idx].id,
-			   control.value);
+		dprintk(VIDC_DBG,
+			"Control: HAL property=%d,ctrl_id=%d,ctrl_value=%d\n",
+			property_id,
+			msm_vdec_ctrls[control_idx].id,
+			control.value);
 			rc = vidc_hal_session_set_property((void *)
 				inst->session, property_id,
 					pdata);
 		}
 	if (rc)
-		pr_err("Failed to set hal property for framesize\n");
+		dprintk(VIDC_ERR, "Failed to set hal property for framesize\n");
 
 failed_open_done:
 
@@ -893,7 +988,7 @@
 	ret_val = v4l2_ctrl_handler_init(&inst->ctrl_handler, NUM_CTRLS);
 
 	if (ret_val) {
-		pr_err("CTRL ERR: Control handler init failed, %d\n",
+		dprintk(VIDC_ERR, "CTRL ERR: Control handler init failed, %d\n",
 				inst->ctrl_handler.error);
 		return ret_val;
 	}
@@ -941,7 +1036,8 @@
 	}
 	ret_val = inst->ctrl_handler.error;
 	if (ret_val)
-		pr_err("CTRL ERR: Error adding ctrls to ctrl handle, %d\n",
-				inst->ctrl_handler.error);
+		dprintk(VIDC_ERR,
+			"Error adding ctrls to ctrl handle, %d\n",
+			inst->ctrl_handler.error);
 	return ret_val;
 }
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 14baf79..6c0f224 100644
--- a/drivers/media/video/msm_vidc/msm_venc.c
+++ b/drivers/media/video/msm_vidc/msm_venc.c
@@ -16,19 +16,20 @@
 #include "msm_vidc_common.h"
 #include "vidc_hal_api.h"
 #include "msm_smem.h"
+#include "msm_vidc_debug.h"
 
 #define MSM_VENC_DVC_NAME "msm_venc_8974"
 #define DEFAULT_HEIGHT 720
 #define DEFAULT_WIDTH 1280
-#define MIN_NUM_OUTPUT_BUFFERS 2
+#define MIN_NUM_OUTPUT_BUFFERS 4
 #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
@@ -449,7 +450,23 @@
 
 static u32 get_frame_size_nv12(int plane, u32 height, u32 width)
 {
-	return ((height + 31) & (~31)) * ((width + 31) & (~31)) * 3/2;
+	int size;
+	int luma_h, luma_w, luma_stride, luma_scanl, luma_size;
+	int chroma_h, chroma_w, chroma_stride, chroma_scanl, chroma_size;
+
+	luma_w = width;
+	luma_h = height;
+
+	chroma_w = luma_w;
+	chroma_h = luma_h/2;
+	NV12_IL_CALC_Y_STRIDE(luma_stride, luma_w, 32);
+	NV12_IL_CALC_Y_BUFHEIGHT(luma_scanl, luma_h, 32);
+	NV12_IL_CALC_UV_STRIDE(chroma_stride, chroma_w, 32);
+	NV12_IL_CALC_UV_BUFHEIGHT(chroma_scanl, luma_h, 32);
+	NV12_IL_CALC_BUF_SIZE(size, luma_size, luma_stride,
+		luma_scanl, chroma_size, chroma_stride, chroma_scanl, 32);
+	size = ALIGN(size, SZ_4K);
+	return size;
 }
 
 static u32 get_frame_size_nv21(int plane, u32 height, u32 width)
@@ -549,7 +566,7 @@
 	struct hal_frame_size frame_sz;
 	unsigned long flags;
 	if (!q || !q->drv_priv) {
-		pr_err("Invalid input, q = %p\n", q);
+		dprintk(VIDC_ERR, "Invalid input, q = %p\n", q);
 		return -EINVAL;
 	}
 	inst = q->drv_priv;
@@ -560,55 +577,58 @@
 				*num_buffers > MAX_NUM_OUTPUT_BUFFERS)
 			*num_buffers = MIN_NUM_OUTPUT_BUFFERS;
 		for (i = 0; i < *num_planes; i++) {
-			sizes[i] = inst->fmts[OUTPUT_PORT]->get_frame_size(
+			sizes[i] = inst->fmts[CAPTURE_PORT]->get_frame_size(
 					i, inst->prop.height, inst->prop.width);
 		}
 		break;
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
 		rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
 		if (rc) {
-			pr_err("Failed to open instance\n");
+			dprintk(VIDC_ERR, "Failed to open instance\n");
 			break;
 		}
 		frame_sz.buffer_type = HAL_BUFFER_INPUT;
 		frame_sz.width = inst->prop.width;
 		frame_sz.height = inst->prop.height;
-		pr_debug("width = %d, height = %d\n",
+		dprintk(VIDC_DBG, "width = %d, height = %d\n",
 				frame_sz.width, frame_sz.height);
 		rc = vidc_hal_session_set_property((void *)inst->session,
 				HAL_PARAM_FRAME_SIZE, &frame_sz);
 		if (rc) {
-			pr_err("Failed to set framesize for Output port\n");
+			dprintk(VIDC_ERR,
+				"Failed to set framesize for Output port\n");
 			break;
 		}
 		frame_sz.buffer_type = HAL_BUFFER_OUTPUT;
 		rc = vidc_hal_session_set_property((void *)inst->session,
 				HAL_PARAM_FRAME_SIZE, &frame_sz);
 		if (rc) {
-			pr_err("Failed to set framesize for Capture port\n");
+			dprintk(VIDC_ERR,
+				"Failed to set hal property for framesize\n");
 			break;
 		}
 		rc = msm_comm_try_get_bufreqs(inst);
 		if (rc) {
-			pr_err("Failed to get buffer requirements: %d\n", rc);
+			dprintk(VIDC_ERR,
+				"Failed to get buffer requirements: %d\n", rc);
 			break;
 		}
 		*num_planes = 1;
 		spin_lock_irqsave(&inst->lock, flags);
 		*num_buffers = inst->buff_req.buffer[0].buffer_count_actual;
 		spin_unlock_irqrestore(&inst->lock, flags);
-		pr_debug("size = %d, alignment = %d, count = %d\n",
+		dprintk(VIDC_DBG, "size = %d, alignment = %d, count = %d\n",
 				inst->buff_req.buffer[0].buffer_size,
 				inst->buff_req.buffer[0].buffer_alignment,
 				inst->buff_req.buffer[0].buffer_count_actual);
 		for (i = 0; i < *num_planes; i++) {
-			sizes[i] = inst->fmts[CAPTURE_PORT]->get_frame_size(
+			sizes[i] = inst->fmts[OUTPUT_PORT]->get_frame_size(
 					i, inst->prop.height, inst->prop.width);
 		}
 
 		break;
 	default:
-		pr_err("Invalid q type = %d\n", q->type);
+		dprintk(VIDC_ERR, "Invalid q type = %d\n", q->type);
 		rc = -EINVAL;
 		break;
 	}
@@ -621,15 +641,31 @@
 	unsigned long flags;
 	struct vb2_buf_entry *temp;
 	struct list_head *ptr, *next;
-	rc = msm_comm_set_scratch_buffers(inst);
+	rc = msm_comm_try_get_bufreqs(inst);
 	if (rc) {
-		pr_err("Failed to set scratch buffers: %d\n", rc);
+		dprintk(VIDC_ERR,
+			"Failed to get Buffer Requirements : %d\n", rc);
 		goto fail_start;
 	}
+	rc = msm_comm_set_scratch_buffers(inst);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to set scratch buffers: %d\n", rc);
+		goto fail_start;
+	}
+	rc = msm_comm_set_persist_buffers(inst);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to set persist buffers: %d\n", rc);
+		goto fail_start;
+	}
+	if (msm_comm_scale_clocks(inst->core, inst->session_type)) {
+		dprintk(VIDC_WARN,
+			"Failed to scale clocks. Performance might be impacted\n");
+	}
+
 	rc = msm_comm_try_state(inst, MSM_VIDC_START_DONE);
 	if (rc) {
-		pr_err("Failed to move inst: %p to start done state\n",
-				inst);
+		dprintk(VIDC_ERR,
+			"Failed to move inst: %p to start done state\n", inst);
 		goto fail_start;
 	}
 	spin_lock_irqsave(&inst->lock, flags);
@@ -638,7 +674,8 @@
 			temp = list_entry(ptr, struct vb2_buf_entry, list);
 			rc = msm_comm_qbuf(temp->vb);
 			if (rc) {
-				pr_err("Failed to qbuf to hardware\n");
+				dprintk(VIDC_ERR,
+					"Failed to qbuf to hardware\n");
 				break;
 			}
 			list_del(&temp->list);
@@ -656,26 +693,22 @@
 	struct msm_vidc_inst *inst;
 	int rc = 0;
 	if (!q || !q->drv_priv) {
-		pr_err("Invalid input, q = %p\n", q);
+		dprintk(VIDC_ERR, "Invalid input, q = %p\n", q);
 		return -EINVAL;
 	}
 	inst = q->drv_priv;
-	pr_debug("Streamon called on: %d capability\n", q->type);
+	dprintk(VIDC_DBG, "Streamon called on: %d capability\n", q->type);
 	switch (q->type) {
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
-		if (msm_comm_scale_clocks(inst->core))
-			pr_err("Failed to scale clocks. Performance/power might be impacted\n");
 		if (inst->vb2_bufq[CAPTURE_PORT].streaming)
 			rc = start_streaming(inst);
 		break;
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
-		if (msm_comm_scale_clocks(inst->core))
-			pr_err("Failed to scale clocks. Performance/power might be impacted\n");
 		if (inst->vb2_bufq[OUTPUT_PORT].streaming)
 			rc = start_streaming(inst);
 		break;
 	default:
-		pr_err("Q-type is not supported: %d\n", q->type);
+		dprintk(VIDC_ERR, "Q-type is not supported: %d\n", q->type);
 		rc = -EINVAL;
 		break;
 	}
@@ -687,25 +720,31 @@
 	struct msm_vidc_inst *inst;
 	int rc = 0;
 	if (!q || !q->drv_priv) {
-		pr_err("Invalid input, q = %p\n", q);
+		dprintk(VIDC_ERR, "Invalid input, q = %p\n", q);
 		return -EINVAL;
 	}
 	inst = q->drv_priv;
-	pr_debug("Streamoff called on: %d capability\n", q->type);
+	dprintk(VIDC_DBG, "Streamoff called on: %d capability\n", q->type);
 	switch (q->type) {
 	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);
+		dprintk(VIDC_ERR, "Q-type is not supported: %d\n", q->type);
 		rc = -EINVAL;
 		break;
 	}
+	if (msm_comm_scale_clocks(inst->core, inst->session_type)) {
+		dprintk(VIDC_WARN,
+			"Failed to scale clocks. Power might be impacted\n");
+	}
+
 	if (rc)
-		pr_err("Failed to move inst: %p, cap = %d to state: %d\n",
-				inst, q->type, MSM_VIDC_CLOSE_DONE);
+		dprintk(VIDC_ERR,
+			"Failed to move inst: %p, cap = %d to state: %d\n",
+			inst, q->type, MSM_VIDC_CLOSE_DONE);
 	return rc;
 }
 
@@ -714,7 +753,7 @@
 	int rc;
 	rc = msm_comm_qbuf(vb);
 	if (rc)
-		pr_err("Failed to queue buffer: %d\n", rc);
+		dprintk(VIDC_ERR, "Failed to queue buffer: %d\n", rc);
 }
 
 static const struct vb2_ops msm_venc_vb2q_ops = {
@@ -746,13 +785,17 @@
 	struct hal_intra_refresh intra_refresh;
 	struct hal_multi_slice_control multi_slice_control;
 	struct hal_h264_db_control h264_db_control;
-	u32 control_idx = 0;
 	u32 property_id = 0;
 	u32 property_val = 0;
 	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) {
+		dprintk(VIDC_ERR,
+			"Failed to move inst: %p to start done state\n", inst);
+		goto failed_open_done;
+	}
 	control.id = ctrl->id;
 	control.value = ctrl->val;
 
@@ -906,7 +949,7 @@
 		venc_h264_profile_level.profile = control.value;
 		profile_level.level = venc_h264_profile_level.level;
 		pdata = &profile_level;
-		pr_debug("\nprofile: %d\n",
+		dprintk(VIDC_DBG, "\nprofile: %d\n",
 			   profile_level.profile);
 		break;
 	case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
@@ -970,7 +1013,7 @@
 		profile_level.profile = venc_h264_profile_level.profile;
 		pdata = &profile_level;
 		pdata = &profile_level;
-		pr_debug("\nLevel: %d\n",
+		dprintk(VIDC_DBG, "\nLevel: %d\n",
 			   profile_level.level);
 		break;
 	case V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE:
@@ -1154,24 +1197,26 @@
 			HAL_PARAM_VENC_H264_DEBLOCK_CONTROL;
 		h264_db_control.slice_alpha_offset = control.value;
 		pdata = &h264_db_control;
+		break;
 	case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA:
 		property_id =
 			HAL_PARAM_VENC_H264_DEBLOCK_CONTROL;
 		h264_db_control.slice_beta_offset = control.value;
 		pdata = &h264_db_control;
+		break;
 	default:
 		break;
 	}
 	if (property_id) {
-		pr_debug("Control: HAL property=%d,ctrl_id=%d,ctrl_value=%d\n",
+		dprintk(VIDC_DBG, "Control: HAL property=%d,ctrl_value=%d\n",
 				property_id,
-				msm_venc_ctrls[control_idx].id,
 				control.value);
 		rc = vidc_hal_session_set_property((void *)inst->session,
 				property_id, pdata);
 	}
 	if (rc)
-		pr_err("Failed to set hal property for framesize\n");
+		dprintk(VIDC_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)
@@ -1194,7 +1239,7 @@
 {
 	int rc = 0;
 	if (!inst) {
-		pr_err("Invalid input = %p\n", inst);
+		dprintk(VIDC_ERR, "Invalid input = %p\n", inst);
 		return -EINVAL;
 	}
 	inst->fmts[CAPTURE_PORT] = &venc_formats[1];
@@ -1214,10 +1259,28 @@
 	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;
+	switch (enc->cmd) {
+	case V4L2_ENC_QCOM_CMD_FLUSH:
+		rc = msm_comm_flush(inst, enc->flags);
+		break;
+	case V4L2_ENC_CMD_STOP:
+		rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
+		break;
+	}
+	if (rc)
+		dprintk(VIDC_ERR,
+			"Command: %d failed with rc = %d\n", enc->cmd, rc);
+	return rc;
+}
+
 int msm_venc_querycap(struct msm_vidc_inst *inst, struct v4l2_capability *cap)
 {
 	if (!inst || !cap) {
-		pr_err("Invalid input, inst = %p, cap = %p\n", inst, cap);
+		dprintk(VIDC_ERR,
+			"Invalid input, inst = %p, cap = %p\n", inst, cap);
 		return -EINVAL;
 	}
 	strlcpy(cap->driver, MSM_VIDC_DRV_NAME, sizeof(cap->driver));
@@ -1236,7 +1299,8 @@
 	const struct msm_vidc_format *fmt = NULL;
 	int rc = 0;
 	if (!inst || !f) {
-		pr_err("Invalid input, inst = %p, f = %p\n", inst, f);
+		dprintk(VIDC_ERR,
+			"Invalid input, inst = %p, f = %p\n", inst, f);
 		return -EINVAL;
 	}
 	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
@@ -1254,7 +1318,7 @@
 				sizeof(f->description));
 		f->pixelformat = fmt->fourcc;
 	} else {
-		pr_err("No more formats found\n");
+		dprintk(VIDC_ERR, "No more formats found\n");
 		rc = -EINVAL;
 	}
 	return rc;
@@ -1266,7 +1330,8 @@
 	int rc = 0;
 	int i;
 	if (!inst || !f) {
-		pr_err("Invalid input, inst = %p, format = %p\n", inst, f);
+		dprintk(VIDC_ERR,
+			"Invalid input, inst = %p, format = %p\n", inst, f);
 		return -EINVAL;
 	}
 	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
@@ -1274,8 +1339,9 @@
 			ARRAY_SIZE(venc_formats), f->fmt.pix_mp.pixelformat,
 			CAPTURE_PORT);
 		if (fmt && fmt->type != CAPTURE_PORT) {
-			pr_err("Format: %d not supported on CAPTURE port\n",
-					f->fmt.pix_mp.pixelformat);
+			dprintk(VIDC_ERR,
+				"Format: %d not supported on CAPTURE port\n",
+				f->fmt.pix_mp.pixelformat);
 			rc = -EINVAL;
 			goto exit;
 		}
@@ -1286,8 +1352,9 @@
 			ARRAY_SIZE(venc_formats), f->fmt.pix_mp.pixelformat,
 			OUTPUT_PORT);
 		if (fmt && fmt->type != OUTPUT_PORT) {
-			pr_err("Format: %d not supported on OUTPUT port\n",
-					f->fmt.pix_mp.pixelformat);
+			dprintk(VIDC_ERR,
+				"Format: %d not supported on OUTPUT port\n",
+				f->fmt.pix_mp.pixelformat);
 			rc = -EINVAL;
 			goto exit;
 		}
@@ -1304,12 +1371,12 @@
 		if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
 			rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
 			if (rc) {
-				pr_err("Failed to open instance\n");
+				dprintk(VIDC_ERR, "Failed to open instance\n");
 				goto exit;
 			}
 		}
 	} else {
-		pr_err("Buf type not recognized, type = %d\n",
+		dprintk(VIDC_ERR, "Buf type not recognized, type = %d\n",
 					f->type);
 		rc = -EINVAL;
 	}
@@ -1323,7 +1390,8 @@
 	int rc = 0;
 	int i;
 	if (!inst || !f) {
-		pr_err("Invalid input, inst = %p, format = %p\n", inst, f);
+		dprintk(VIDC_ERR,
+			"Invalid input, inst = %p, format = %p\n", inst, f);
 		return -EINVAL;
 	}
 	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
@@ -1342,8 +1410,8 @@
 					inst->prop.width);
 		}
 	} else {
-		pr_err("Buf type not recognized, type = %d\n",
-					f->type);
+		dprintk(VIDC_ERR,
+			"Buf type not recognized, type = %d\n",	f->type);
 		rc = -EINVAL;
 	}
 	return rc;
@@ -1354,18 +1422,20 @@
 	struct vb2_queue *q = NULL;
 	int rc = 0;
 	if (!inst || !b) {
-		pr_err("Invalid input, inst = %p, buffer = %p\n", inst, b);
+		dprintk(VIDC_ERR,
+			"Invalid input, inst = %p, buffer = %p\n", inst, b);
 		return -EINVAL;
 	}
 	q = msm_comm_get_vb2q(inst, b->type);
 	if (!q) {
-		pr_err("Failed to find buffer queue for type = %d\n", b->type);
+		dprintk(VIDC_ERR,
+		"Failed to find buffer queue for type = %d\n", b->type);
 		return -EINVAL;
 	}
 
 	rc = vb2_reqbufs(q, b);
 	if (rc)
-		pr_err("Failed to get reqbufs, %d\n", rc);
+		dprintk(VIDC_ERR, "Failed to get reqbufs, %d\n", rc);
 	return rc;
 }
 
@@ -1381,7 +1451,8 @@
 		break;
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
 		for (i = 0; i < b->length; i++) {
-			pr_debug("device_addr = %ld, size = %d\n",
+			dprintk(VIDC_DBG,
+				"device_addr = %ld, size = %d\n",
 				b->m.planes[i].m.userptr,
 				b->m.planes[i].length);
 			buffer_info.buffer_size = b->m.planes[i].length;
@@ -1394,11 +1465,13 @@
 			rc = vidc_hal_session_set_buffers((void *)inst->session,
 					&buffer_info);
 			if (rc)
-				pr_err("vidc_hal_session_set_buffers failed");
+				dprintk(VIDC_ERR,
+					"vidc_hal_session_set_buffers failed");
 		}
 		break;
 	default:
-		pr_err("Buffer type not recognized: %d\n", b->type);
+		dprintk(VIDC_ERR,
+			"Buffer type not recognized: %d\n", b->type);
 		break;
 	}
 	return rc;
@@ -1410,12 +1483,13 @@
 	int rc = 0;
 	q = msm_comm_get_vb2q(inst, b->type);
 	if (!q) {
-		pr_err("Failed to find buffer queue for type = %d\n", b->type);
+		dprintk(VIDC_ERR,
+			"Failed to find buffer queue for type = %d\n", b->type);
 		return -EINVAL;
 	}
 	rc = vb2_qbuf(q, b);
 	if (rc)
-		pr_err("Failed to qbuf, %d\n", rc);
+		dprintk(VIDC_ERR, "Failed to qbuf, %d\n", rc);
 	return rc;
 }
 
@@ -1425,12 +1499,13 @@
 	int rc = 0;
 	q = msm_comm_get_vb2q(inst, b->type);
 	if (!q) {
-		pr_err("Failed to find buffer queue for type = %d\n", b->type);
+		dprintk(VIDC_ERR,
+			"Failed to find buffer queue for type = %d\n", b->type);
 		return -EINVAL;
 	}
 	rc = vb2_dqbuf(q, b, true);
 	if (rc)
-		pr_err("Failed to dqbuf, %d\n", rc);
+		dprintk(VIDC_DBG, "Failed to dqbuf, %d\n", rc);
 	return rc;
 }
 
@@ -1440,13 +1515,14 @@
 	struct vb2_queue *q;
 	q = msm_comm_get_vb2q(inst, i);
 	if (!q) {
-		pr_err("Failed to find buffer queue for type = %d\n", i);
+		dprintk(VIDC_ERR,
+			"Failed to find buffer queue for type = %d\n", i);
 		return -EINVAL;
 	}
-	pr_debug("Calling streamon\n");
+	dprintk(VIDC_DBG, "Calling streamon\n");
 	rc = vb2_streamon(q, i);
 	if (rc)
-		pr_err("streamon failed on port: %d\n", i);
+		dprintk(VIDC_ERR, "streamon failed on port: %d\n", i);
 	return rc;
 }
 
@@ -1456,13 +1532,14 @@
 	struct vb2_queue *q;
 	q = msm_comm_get_vb2q(inst, i);
 	if (!q) {
-		pr_err("Failed to find buffer queue for type = %d\n", i);
+		dprintk(VIDC_ERR,
+			"Failed to find buffer queue for type = %d\n", i);
 		return -EINVAL;
 	}
-	pr_debug("Calling streamoff\n");
+	dprintk(VIDC_DBG, "Calling streamoff on port: %d\n", i);
 	rc = vb2_streamoff(q, i);
 	if (rc)
-		pr_err("streamoff failed on port: %d\n", i);
+		dprintk(VIDC_ERR, "streamoff failed on port: %d\n", i);
 	return rc;
 }
 
@@ -1474,7 +1551,7 @@
 	int ret_val = 0;
 	ret_val = v4l2_ctrl_handler_init(&inst->ctrl_handler, NUM_CTRLS);
 	if (ret_val) {
-		pr_err("CTRL ERR: Control handler init failed, %d\n",
+		dprintk(VIDC_ERR, "CTRL ERR: Control handler init failed, %d\n",
 			inst->ctrl_handler.error);
 		return ret_val;
 	}
@@ -1516,7 +1593,8 @@
 	}
 	ret_val = inst->ctrl_handler.error;
 	if (ret_val)
-		pr_err("CTRL ERR: Error adding ctrls to ctrl handle, %d\n",
-				inst->ctrl_handler.error);
+		dprintk(VIDC_ERR,
+			"CTRL ERR: Error adding ctrls to ctrl handle, %d\n",
+			inst->ctrl_handler.error);
 	return ret_val;
 }
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..449dab2 100644
--- a/drivers/media/video/msm_vidc/msm_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_vidc.c
@@ -14,10 +14,12 @@
 #include <linux/slab.h>
 #include <media/msm_vidc.h>
 #include "msm_vidc_internal.h"
+#include "msm_vidc_debug.h"
 #include "msm_vdec.h"
 #include "msm_venc.h"
 #include "msm_vidc_common.h"
 #include "msm_smem.h"
+#include <linux/delay.h>
 
 int msm_vidc_poll(void *instance, struct file *filp,
 		struct poll_table_struct *wait)
@@ -29,11 +31,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 +137,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;
@@ -204,7 +217,7 @@
 	} else if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
 		q = &inst->vb2_bufq[OUTPUT_PORT];
 	} else {
-		pr_err("buf_type = %d not recognised\n", type);
+		dprintk(VIDC_ERR, "buf_type = %d not recognised\n", type);
 		return -EINVAL;
 	}
 	q->type = type;
@@ -228,13 +241,14 @@
 	int i = 0;
 	if (core_id >= MSM_VIDC_CORES_MAX ||
 			session_type >= MSM_VIDC_MAX_DEVICES) {
-		pr_err("Invalid input, core_id = %d, session = %d\n",
+		dprintk(VIDC_ERR, "Invalid input, core_id = %d, session = %d\n",
 			core_id, session_type);
 		goto err_invalid_core;
 	}
 	core = get_vidc_core(core_id);
 	if (!core) {
-		pr_err("Failed to find core for core_id = %d\n", core_id);
+		dprintk(VIDC_ERR,
+			"Failed to find core for core_id = %d\n", core_id);
 		goto err_invalid_core;
 	}
 
@@ -243,6 +257,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);
@@ -251,7 +266,7 @@
 	}
 	inst->mem_client = msm_smem_new_client(SMEM_ION);
 	if (!inst->mem_client) {
-		pr_err("Failed to create memory client\n");
+		dprintk(VIDC_ERR, "Failed to create memory client\n");
 		goto fail_mem_client;
 	}
 	if (session_type == MSM_VIDC_DECODER) {
@@ -264,20 +279,25 @@
 	rc = vb2_bufq_init(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
 			session_type);
 	if (rc) {
-		pr_err("Failed to initialize vb2 queue on capture port\n");
+		dprintk(VIDC_ERR,
+			"Failed to initialize vb2 queue on capture port\n");
 		goto fail_init;
 	}
 	rc = vb2_bufq_init(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
 			session_type);
 	if (rc) {
-		pr_err("Failed to initialize vb2 queue on capture port\n");
+		dprintk(VIDC_ERR,
+			"Failed to initialize vb2 queue on capture port\n");
 		goto fail_init;
 	}
 	rc = msm_comm_try_state(inst, MSM_VIDC_CORE_INIT);
 	if (rc) {
-		pr_err("Failed to move video instance to init state\n");
+		dprintk(VIDC_ERR,
+			"Failed to move video instance to init state\n");
 		goto fail_init;
 	}
+	inst->debugfs_root =
+		msm_vidc_debugfs_init_inst(inst, core->debugfs_root);
 	spin_lock_irqsave(&core->lock, flags);
 	list_add_tail(&inst->list, &core->instances);
 	spin_unlock_irqrestore(&core->lock, flags);
@@ -316,10 +336,20 @@
 				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);
 		msm_smem_delete_client(inst->mem_client);
+		debugfs_remove_recursive(inst->debugfs_root);
 	}
 }
 
@@ -340,8 +370,9 @@
 	mutex_unlock(&core->sync_lock);
 	rc = msm_comm_try_state(inst, MSM_VIDC_CORE_UNINIT);
 	if (rc)
-		pr_err("Failed to move video instance to uninit state\n");
+		dprintk(VIDC_ERR,
+			"Failed to move video instance to uninit state\n");
 	cleanup_instance(inst);
-	pr_debug("Closed the instance\n");
+	dprintk(VIDC_DBG, "Closed the instance\n");
 	return 0;
 }
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.c b/drivers/media/video/msm_vidc/msm_vidc_common.c
index b07c63b..5b83cfb 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.c
@@ -14,6 +14,7 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/iommu.h>
+#include <asm/div64.h>
 #include <mach/iommu.h>
 #include <mach/iommu_domains.h>
 #include <mach/peripheral-loader.h>
@@ -21,8 +22,9 @@
 #include "msm_vidc_common.h"
 #include "vidc_hal_api.h"
 #include "msm_smem.h"
+#include "msm_vidc_debug.h"
 
-#define HW_RESPONSE_TIMEOUT 5000
+#define HW_RESPONSE_TIMEOUT (5 * 60 * 1000)
 
 #define IS_ALREADY_IN_STATE(__p, __d) ({\
 	int __rc = (__p >= __d);\
@@ -47,96 +49,50 @@
 	__mbs;\
 })
 
-/*While adding entries to this array make sure
- * they are in descending order.
- * Look @ msm_comm_get_load function*/
-static const u32 clocks_table[][2] = {
-	{979200, 410000000},
-	{560145, 266670000},
-	{421161, 200000000},
-	{243000, 133330000},
-	{108000, 100000000},
-	{36000, 50000000},
-};
-
 static const u32 bus_table[] = {
 	0,
-	9216000,
-	27648000,
-	62208000,
+	36000,
+	110400,
+	244800,
+	489000,
+	783360,
+	979200,
 };
 
-static int msm_comm_get_bus_load(struct msm_vidc_core *core)
-{
-	struct msm_vidc_inst *inst = NULL;
-	int load = 0;
-	if (!core) {
-		pr_err("Invalid args: %p\n", core);
-		return -EINVAL;
-	}
-	list_for_each_entry(inst, &core->instances, list) {
-		load += VIDC_BUS_LOAD(inst->prop.height,
-				inst->prop.width, inst->prop.fps,
-				2000000);
-	}
-	return load;
-}
-
 static int get_bus_vector(int load)
 {
 	int num_rows = sizeof(bus_table)/(sizeof(u32));
 	int i;
-	for (i = num_rows - 1; i > 0; i--) {
-		if ((load >= bus_table[i]) || (i == 1))
+	if (!load)
+		return 0;
+	for (i = num_rows - 1; i > 1; i--) {
+		if (load >= bus_table[i])
 			break;
 	}
-	pr_err("Required bus = %d\n", i);
+	dprintk(VIDC_DBG, "Required bus = %d\n", i);
 	return i;
 }
 
-int msm_comm_scale_bus(struct msm_vidc_core *core)
-{
-	int load;
-	int rc = 0;
-	if (!core) {
-		pr_err("Invalid args: %p\n", core);
-		return -EINVAL;
-	}
-	load = msm_comm_get_bus_load(core);
-	if (load <= 0) {
-		pr_err("Failed to scale bus for %d load\n",
-			load);
-		goto fail_scale_bus;
-	}
-	rc = msm_bus_scale_client_update_request(
-			core->resources.bus_info.vcodec_handle,
-			get_bus_vector(load));
-	if (rc) {
-		pr_err("Failed to scale bus: %d\n", rc);
-		goto fail_scale_bus;
-	}
-	rc = msm_bus_scale_client_update_request(
-			core->resources.bus_info.ocmem_handle,
-			get_bus_vector(load));
-	if (rc) {
-		pr_err("Failed to scale bus: %d\n", rc);
-		goto fail_scale_bus;
-	}
-fail_scale_bus:
-	return rc;
-}
-
-static int msm_comm_get_load(struct msm_vidc_core *core)
+static int msm_comm_get_load(struct msm_vidc_core *core,
+	enum session_type type)
 {
 	struct msm_vidc_inst *inst = NULL;
 	int num_mbs_per_sec = 0;
+	unsigned long flags;
 	if (!core) {
-		pr_err("Invalid args: %p\n", core);
+		dprintk(VIDC_ERR, "Invalid args: %p\n", core);
 		return -EINVAL;
 	}
-	list_for_each_entry(inst, &core->instances, list)
-		num_mbs_per_sec += NUM_MBS_PER_SEC(inst->prop.height,
-				inst->prop.width, inst->prop.fps);
+	list_for_each_entry(inst, &core->instances, list) {
+		spin_lock_irqsave(&inst->lock, flags);
+		if (inst->session_type == type &&
+			inst->state >= MSM_VIDC_OPEN_DONE &&
+			inst->state < MSM_VIDC_STOP_DONE) {
+			num_mbs_per_sec += NUM_MBS_PER_SEC(inst->prop.height,
+					inst->prop.width, inst->prop.fps);
+		}
+		spin_unlock_irqrestore(&inst->lock, flags);
+	}
 	return num_mbs_per_sec;
 }
 
@@ -152,17 +108,44 @@
 			break;
 		ret = table[i].freq;
 	}
-	pr_err("Required clock rate = %lu\n", ret);
+	dprintk(VIDC_INFO, "Required clock rate = %lu\n", ret);
 	return ret;
 }
 
+int msm_comm_scale_bus(struct msm_vidc_core *core, enum session_type type)
+{
+	int load;
+	int rc = 0;
+	if (!core || type >= MSM_VIDC_MAX_DEVICES) {
+		dprintk(VIDC_ERR, "Invalid args: %p, %d\n", core, type);
+		return -EINVAL;
+	}
+	load = msm_comm_get_load(core, type);
+	rc = msm_bus_scale_client_update_request(
+			core->resources.bus_info.ddr_handle[type],
+			get_bus_vector(load));
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to scale bus: %d\n", rc);
+		goto fail_scale_bus;
+	}
+	rc = msm_bus_scale_client_update_request(
+			core->resources.bus_info.ocmem_handle[type],
+			get_bus_vector(load));
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to scale bus: %d\n", rc);
+		goto fail_scale_bus;
+	}
+fail_scale_bus:
+	return rc;
+}
+
 struct msm_vidc_core *get_vidc_core(int core_id)
 {
 	struct msm_vidc_core *core;
 	int found = 0;
 	unsigned long flags;
 	if (core_id > MSM_VIDC_CORES_MAX) {
-		pr_err("Core id = %d is greater than max = %d\n",
+		dprintk(VIDC_ERR, "Core id = %d is greater than max = %d\n",
 			core_id, MSM_VIDC_CORES_MAX);
 		return NULL;
 	}
@@ -190,13 +173,15 @@
 		dev = msm_iommu_get_ctx(io_map->ctx);
 		domain = msm_get_iommu_domain(io_map->domain);
 		if (IS_ERR_OR_NULL(domain)) {
-			pr_err("Failed to get domain: %s\n", io_map->name);
+			dprintk(VIDC_ERR,
+				"Failed to get domain: %s\n", io_map->name);
 			rc = PTR_ERR(domain);
 			break;
 		}
 		rc = iommu_attach_device(domain, dev);
 		if (rc) {
-			pr_err("IOMMU attach failed: %s\n", io_map->name);
+			dprintk(VIDC_ERR,
+				"IOMMU attach failed: %s\n", io_map->name);
 			break;
 		}
 	}
@@ -220,7 +205,7 @@
 	struct iommu_info *io_map;
 	int i;
 	if (!core) {
-		pr_err("Invalid paramter: %p\n", core);
+		dprintk(VIDC_ERR, "Invalid paramter: %p\n", core);
 		return;
 	}
 	for (i = 0; i < MAX_MAP; i++) {
@@ -237,7 +222,7 @@
 {
 	int i, k = 0;
 	if (!fmt || index < 0) {
-		pr_err("Invalid inputs, fmt = %p, index = %d\n",
+		dprintk(VIDC_ERR, "Invalid inputs, fmt = %p, index = %d\n",
 						fmt, index);
 		return NULL;
 	}
@@ -249,7 +234,7 @@
 		k++;
 	}
 	if (i == size) {
-		pr_err("Format not found\n");
+		dprintk(VIDC_WARN, "Format not found\n");
 		return NULL;
 	}
 	return &fmt[i];
@@ -259,7 +244,7 @@
 {
 	int i;
 	if (!fmt) {
-		pr_err("Invalid inputs, fmt = %p\n", fmt);
+		dprintk(VIDC_ERR, "Invalid inputs, fmt = %p\n", fmt);
 		return NULL;
 	}
 	for (i = 0; i < size; i++) {
@@ -267,7 +252,7 @@
 				break;
 	}
 	if (i == size) {
-		pr_err("Format not found\n");
+		dprintk(VIDC_WARN, "Format not found\n");
 		return NULL;
 	}
 	return &fmt[i];
@@ -290,20 +275,21 @@
 	struct vidc_hal_sys_init_done *sys_init_msg;
 	int index = SYS_MSG_INDEX(cmd);
 	if (!response) {
-		pr_err("Failed to get valid response for sys init\n");
+		dprintk(VIDC_ERR,
+			"Failed to get valid response for sys init\n");
 		return;
 	}
 	core = get_vidc_core(response->device_id);
 	if (!core) {
-		pr_err("Wrong device_id received\n");
+		dprintk(VIDC_ERR, "Wrong device_id received\n");
 		return;
 	}
-	pr_debug("index = %d\n", index);
-	pr_debug("ptr = %p\n", &(core->completions[index]));
+	dprintk(VIDC_DBG, "index = %d\n", index);
+	dprintk(VIDC_DBG, "ptr = %p\n", &(core->completions[index]));
 	complete(&(core->completions[index]));
 	sys_init_msg = response->data;
 	if (!sys_init_msg) {
-		pr_err("sys_init_done message not proper\n");
+		dprintk(VIDC_ERR, "sys_init_done message not proper\n");
 		return;
 	}
 }
@@ -314,12 +300,13 @@
 	struct msm_vidc_cb_cmd_done *response = data;
 	struct msm_vidc_core *core;
 	if (!response) {
-		pr_err("Failed to get valid response for sys init\n");
+		dprintk(VIDC_ERR,
+			"Failed to get valid response for sys init\n");
 		return;
 	}
 	core = get_vidc_core(response->device_id);
 	if (!core) {
-		pr_err("Wrong device_id received\n");
+		dprintk(VIDC_ERR, "Wrong device_id received\n");
 		return;
 	}
 	complete(&core->completions[SYS_MSG_INDEX(cmd)]);
@@ -330,7 +317,7 @@
 {
 	unsigned long flags;
 	spin_lock_irqsave(&inst->lock, flags);
-	pr_debug("Moved inst: %p from state: %d to state: %d\n",
+	dprintk(VIDC_DBG, "Moved inst: %p from state: %d to state: %d\n",
 		   inst, inst->state, state);
 	inst->state = state;
 	spin_unlock_irqrestore(&inst->lock, flags);
@@ -340,7 +327,7 @@
 		struct msm_vidc_inst *inst)
 {
 	if (!inst) {
-		pr_err("Invalid(%p) instance id\n", inst);
+		dprintk(VIDC_ERR, "Invalid(%p) instance id\n", inst);
 		return -EINVAL;
 	}
 	complete(&inst->completions[SESSION_MSG_INDEX(cmd)]);
@@ -355,7 +342,7 @@
 		&inst->completions[SESSION_MSG_INDEX(cmd)],
 		msecs_to_jiffies(HW_RESPONSE_TIMEOUT));
 	if (!rc) {
-		pr_err("Wait interrupted or timeout: %d\n", rc);
+		dprintk(VIDC_ERR, "Wait interrupted or timeout: %d\n", rc);
 		rc = -EIO;
 	} else {
 		rc = 0;
@@ -370,10 +357,11 @@
 {
 	int rc = 0;
 	if (IS_ALREADY_IN_STATE(flipped_state, desired_state)) {
-		pr_err("inst: %p is already in state: %d\n", inst, inst->state);
+		dprintk(VIDC_INFO, "inst: %p is already in state: %d\n",
+						inst, inst->state);
 		goto err_same_state;
 	}
-	pr_debug("Waiting for hal_cmd: %d\n", hal_cmd);
+	dprintk(VIDC_DBG, "Waiting for hal_cmd: %d\n", hal_cmd);
 	rc = wait_for_sess_signal_receipt(inst, hal_cmd);
 	if (!rc)
 		change_inst_state(inst, desired_state);
@@ -389,7 +377,8 @@
 		inst = (struct msm_vidc_inst *)response->session_id;
 		signal_session_msg_receipt(cmd, inst);
 	} else {
-		pr_err("Failed to get valid response for session init\n");
+		dprintk(VIDC_ERR,
+			"Failed to get valid response for session init\n");
 	}
 }
 
@@ -421,7 +410,8 @@
 		v4l2_event_queue_fh(&inst->event_handler, &dqevent);
 		return;
 	} else {
-		pr_err("Failed to get valid response for event_change\n");
+		dprintk(VIDC_ERR,
+			"Failed to get valid response for event_change\n");
 	}
 }
 
@@ -430,8 +420,10 @@
 	struct msm_vidc_cb_cmd_done *response = data;
 	struct msm_vidc_inst *inst;
 	unsigned long flags;
+	int i;
 	if (!response || !response->data) {
-		pr_err("Failed to get valid response for prop info\n");
+		dprintk(VIDC_ERR,
+			"Failed to get valid response for prop info\n");
 		return;
 	}
 	inst = (struct msm_vidc_inst *)response->session_id;
@@ -439,6 +431,13 @@
 	memcpy(&inst->buff_req, response->data,
 			sizeof(struct buffer_requirements));
 	spin_unlock_irqrestore(&inst->lock, flags);
+	for (i = 0; i < 8; i++) {
+		dprintk(VIDC_DBG,
+			"buffer type: %d, count : %d, size: %d\n",
+			inst->buff_req.buffer[i].buffer_type,
+			inst->buff_req.buffer[i].buffer_count_actual,
+			inst->buff_req.buffer[i].buffer_size);
+	}
 	signal_session_msg_receipt(cmd, inst);
 }
 
@@ -449,7 +448,8 @@
 	if (response)
 		inst = (struct msm_vidc_inst *)response->session_id;
 	else
-		pr_err("Failed to get valid response for load resource\n");
+		dprintk(VIDC_ERR,
+			"Failed to get valid response for load resource\n");
 }
 
 static void handle_start_done(enum command_response cmd, void *data)
@@ -460,7 +460,8 @@
 		inst = (struct msm_vidc_inst *)response->session_id;
 		signal_session_msg_receipt(cmd, inst);
 	} else {
-		pr_err("Failed to get valid response for start\n");
+		dprintk(VIDC_ERR,
+			"Failed to get valid response for start\n");
 	}
 }
 
@@ -472,7 +473,8 @@
 		inst = (struct msm_vidc_inst *)response->session_id;
 		signal_session_msg_receipt(cmd, inst);
 	} else {
-		pr_err("Failed to get valid response for stop\n");
+		dprintk(VIDC_ERR,
+			"Failed to get valid response for stop\n");
 	}
 }
 
@@ -484,7 +486,8 @@
 		inst = (struct msm_vidc_inst *)response->session_id;
 		signal_session_msg_receipt(cmd, inst);
 	} else {
-		pr_err("Failed to get valid response for release resource\n");
+		dprintk(VIDC_ERR,
+			"Failed to get valid response for release resource\n");
 	}
 }
 
@@ -499,7 +502,7 @@
 		dqevent.id = 0;
 		v4l2_event_queue_fh(&inst->event_handler, &dqevent);
 	} else {
-		pr_err("Failed to get valid response for flush\n");
+		dprintk(VIDC_ERR, "Failed to get valid response for flush\n");
 	}
 }
 
@@ -516,7 +519,8 @@
 		dqevent.id = 0;
 		v4l2_event_queue_fh(&inst->event_handler, &dqevent);
 	} else {
-		pr_err("Failed to get valid response for session close\n");
+		dprintk(VIDC_ERR,
+			"Failed to get valid response for session close\n");
 	}
 }
 
@@ -526,7 +530,7 @@
 	struct vb2_buffer *vb = NULL;
 	int found = 0;
 	if (!q) {
-		pr_err("Invalid parameter\n");
+		dprintk(VIDC_ERR, "Invalid parameter\n");
 		return NULL;
 	}
 	list_for_each_entry(vb, &q->queued_list, queued_entry) {
@@ -536,7 +540,8 @@
 		}
 	}
 	if (!found) {
-		pr_err("Failed to find the buffer in queued list: %d, %d\n",
+		dprintk(VIDC_ERR,
+			"Failed to find the buffer in queued list: %d, %d\n",
 			dev_addr, q->type);
 		vb = NULL;
 	}
@@ -548,7 +553,7 @@
 	struct msm_vidc_cb_data_done *response = data;
 	struct vb2_buffer *vb;
 	if (!response) {
-		pr_err("Invalid response from vidc_hal\n");
+		dprintk(VIDC_ERR, "Invalid response from vidc_hal\n");
 		return;
 	}
 	vb = response->clnt_data;
@@ -563,7 +568,7 @@
 	struct vb2_buffer *vb;
 	struct vidc_hal_fbd *fill_buf_done;
 	if (!response) {
-		pr_err("Invalid response from vidc_hal\n");
+		dprintk(VIDC_ERR, "Invalid response from vidc_hal\n");
 		return;
 	}
 	inst = (struct msm_vidc_inst *)response->session_id;
@@ -572,9 +577,50 @@
 		(u32)fill_buf_done->packet_buffer1);
 	if (vb) {
 		vb->v4l2_planes[0].bytesused = fill_buf_done->filled_len1;
-		pr_debug("Filled length = %d\n", vb->v4l2_planes[0].bytesused);
+
+		if (!(fill_buf_done->flags1 &
+			HAL_BUFFERFLAG_TIMESTAMPINVALID)) {
+			int64_t time_usec = fill_buf_done->timestamp_hi;
+			time_usec = (time_usec << 32) |
+				fill_buf_done->timestamp_lo;
+
+			vb->v4l2_buf.timestamp =
+				ns_to_timeval(time_usec * NSEC_PER_USEC);
+		}
+		vb->v4l2_buf.flags = 0;
+
 		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_EOS)
 			vb->v4l2_buf.flags |= V4L2_BUF_FLAG_EOS;
+		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_CODECCONFIG)
+			vb->v4l2_buf.flags &= ~V4L2_QCOM_BUF_FLAG_CODECCONFIG;
+
+		if (!inst->fbd_count)
+			vb->v4l2_buf.flags = V4L2_BUF_FLAG_KEYFRAME;
+		++inst->fbd_count;
+
+		switch (fill_buf_done->picture_type) {
+		case HAL_PICTURE_IDR:
+		case HAL_PICTURE_I:
+			vb->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
+			break;
+		case HAL_PICTURE_P:
+			vb->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME;
+			break;
+		case HAL_PICTURE_B:
+			vb->v4l2_buf.flags |= V4L2_BUF_FLAG_BFRAME;
+			break;
+		case HAL_FRAME_NOTCODED:
+		case HAL_UNUSED_PICT:
+			/* Do we need to care about these? */
+		case HAL_FRAME_YUV:
+			break;
+		default:
+			break;
+		}
+
+		dprintk(VIDC_DBG, "Filled length = %d; flags %x\n",
+				vb->v4l2_planes[0].bytesused,
+				vb->v4l2_buf.flags);
 		vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
 	} else {
 		/*
@@ -606,9 +652,34 @@
 	}
 }
 
+static void  handle_seq_hdr_done(enum command_response cmd, void *data)
+{
+	struct msm_vidc_cb_data_done *response = data;
+	struct msm_vidc_inst *inst;
+	struct vb2_buffer *vb;
+	struct vidc_hal_fbd *fill_buf_done;
+	if (!response) {
+		pr_err("Invalid response from vidc_hal\n");
+		return;
+	}
+	inst = (struct msm_vidc_inst *)response->session_id;
+	fill_buf_done = (struct vidc_hal_fbd *)&response->output_done;
+	vb = get_vb_from_device_addr(&inst->vb2_bufq[CAPTURE_PORT],
+		(u32)fill_buf_done->packet_buffer1);
+	if (vb)
+		vb->v4l2_planes[0].bytesused = fill_buf_done->filled_len1;
+
+	vb->v4l2_buf.flags = V4L2_QCOM_BUF_FLAG_CODECCONFIG;
+
+	dprintk(VIDC_DBG, "Filled length = %d; flags %x\n",
+				vb->v4l2_planes[0].bytesused,
+				vb->v4l2_buf.flags);
+	vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+}
+
 void handle_cmd_response(enum command_response cmd, void *data)
 {
-	pr_debug("Command response = %d\n", cmd);
+	dprintk(VIDC_DBG, "Command response = %d\n", cmd);
 	switch (cmd) {
 	case SYS_INIT_DONE:
 		handle_sys_init_done(cmd, data);
@@ -649,32 +720,36 @@
 	case SESSION_FLUSH_DONE:
 		handle_session_flush(cmd, data);
 		break;
+	case SESSION_GET_SEQ_HDR_DONE:
+		handle_seq_hdr_done(cmd, data);
+		break;
 	default:
-		pr_err("response unhandled\n");
+		dprintk(VIDC_ERR, "response unhandled\n");
 		break;
 	}
 }
 
-int msm_comm_scale_clocks(struct msm_vidc_core *core)
+int msm_comm_scale_clocks(struct msm_vidc_core *core, enum session_type type)
 {
 	int num_mbs_per_sec;
 	int rc = 0;
 	if (!core) {
-		pr_err("Invalid args: %p\n", core);
+		dprintk(VIDC_ERR, "Invalid args: %p\n", core);
 		return -EINVAL;
 	}
-	num_mbs_per_sec = msm_comm_get_load(core);
-	pr_err("num_mbs_per_sec = %d\n", num_mbs_per_sec);
+	num_mbs_per_sec = 2 * msm_comm_get_load(core, MSM_VIDC_ENCODER);
+	num_mbs_per_sec += msm_comm_get_load(core, MSM_VIDC_DECODER);
+	dprintk(VIDC_INFO, "num_mbs_per_sec = %d\n", num_mbs_per_sec);
 	rc = clk_set_rate(core->resources.clock[VCODEC_CLK].clk,
 			get_clock_rate(&core->resources.clock[VCODEC_CLK],
 				num_mbs_per_sec));
 	if (rc) {
-		pr_err("Failed to set clock rate: %d\n", rc);
+		dprintk(VIDC_ERR, "Failed to set clock rate: %d\n", rc);
 		goto fail_clk_set_rate;
 	}
-	rc = msm_comm_scale_bus(core);
+	rc = msm_comm_scale_bus(core, type);
 	if (rc)
-		pr_err("Failed to scale bus bandwidth\n");
+		dprintk(VIDC_ERR, "Failed to scale bus bandwidth\n");
 fail_clk_set_rate:
 	return rc;
 }
@@ -685,17 +760,17 @@
 	struct core_clock *cl;
 	int rc = 0;
 	if (!core) {
-		pr_err("Invalid params: %p\n", core);
+		dprintk(VIDC_ERR, "Invalid params: %p\n", core);
 		return -EINVAL;
 	}
 	for (i = 0; i < VCODEC_MAX_CLKS; i++) {
 		cl = &core->resources.clock[i];
 		rc = clk_prepare_enable(cl->clk);
 		if (rc) {
-			pr_err("Failed to enable clocks\n");
+			dprintk(VIDC_ERR, "Failed to enable clocks\n");
 			goto fail_clk_enable;
 		} else {
-			pr_err("Clock: %s enabled\n", cl->name);
+			dprintk(VIDC_DBG, "Clock: %s enabled\n", cl->name);
 		}
 	}
 	return rc;
@@ -712,7 +787,7 @@
 	int i;
 	struct core_clock *cl;
 	if (!core) {
-		pr_err("Invalid params: %p\n", core);
+		dprintk(VIDC_ERR, "Invalid params: %p\n", core);
 		return;
 	}
 	for (i = 0; i < VCODEC_MAX_CLKS; i++) {
@@ -725,33 +800,28 @@
 {
 	int rc = 0;
 	if (!core) {
-		pr_err("Invalid paramter: %p\n", core);
+		dprintk(VIDC_ERR, "Invalid paramter: %p\n", core);
 		return -EINVAL;
 	}
-	rc = msm_comm_scale_clocks(core);
-	if (rc) {
-		pr_err("Failed to set clock rate: %d\n", rc);
-		goto fail_pil_get;
-	}
 
 	if (!core->resources.fw.cookie)
 		core->resources.fw.cookie = pil_get("venus");
 
 	if (IS_ERR_OR_NULL(core->resources.fw.cookie)) {
-		pr_err("Failed to download firmware\n");
+		dprintk(VIDC_ERR, "Failed to download firmware\n");
 		rc = -ENOMEM;
 		goto fail_pil_get;
 	}
 
 	rc = msm_comm_enable_clks(core);
 	if (rc) {
-		pr_err("Failed to enable clocks: %d\n", rc);
+		dprintk(VIDC_ERR, "Failed to enable clocks: %d\n", rc);
 		goto fail_enable_clks;
 	}
 
 	rc = msm_comm_iommu_attach(core);
 	if (rc) {
-		pr_err("Failed to attach iommu");
+		dprintk(VIDC_ERR, "Failed to attach iommu");
 		goto fail_iommu_attach;
 	}
 	return rc;
@@ -767,7 +837,7 @@
 static void msm_comm_unload_fw(struct msm_vidc_core *core)
 {
 	if (!core) {
-		pr_err("Invalid paramter: %p\n", core);
+		dprintk(VIDC_ERR, "Invalid paramter: %p\n", core);
 		return;
 	}
 	if (core->resources.fw.cookie) {
@@ -793,7 +863,7 @@
 	struct vidc_resource_hdr rhdr;
 	int rc = 0;
 	if (!core || !ocmem) {
-		pr_err("Invalid params, core:%p, ocmem: %p\n",
+		dprintk(VIDC_ERR, "Invalid params, core:%p, ocmem: %p\n",
 			core, ocmem);
 		return -EINVAL;
 	}
@@ -802,10 +872,10 @@
 	rhdr.size =	ocmem->len;
 	rc = vidc_hal_core_set_resource(core->device, &rhdr, ocmem);
 	if (rc) {
-		pr_err("Failed to set OCMEM on driver\n");
+		dprintk(VIDC_ERR, "Failed to set OCMEM on driver\n");
 		goto ocmem_set_failed;
 	}
-	pr_debug("OCMEM set, addr = %lx, size: %ld\n",
+	dprintk(VIDC_DBG, "OCMEM set, addr = %lx, size: %ld\n",
 		ocmem->addr, ocmem->len);
 ocmem_set_failed:
 	return rc;
@@ -816,7 +886,7 @@
 	struct vidc_resource_hdr rhdr;
 	int rc = 0;
 	if (!core || !core->resources.ocmem.buf) {
-		pr_err("Invalid params, core:%p\n",	core);
+		dprintk(VIDC_ERR, "Invalid params, core:%p\n",	core);
 		return -EINVAL;
 	}
 	rhdr.resource_id = VIDC_RESOURCE_OCMEM;
@@ -825,14 +895,14 @@
 		&core->completions[SYS_MSG_INDEX(RELEASE_RESOURCE_DONE)]);
 	rc = vidc_hal_core_release_resource(core->device, &rhdr);
 	if (rc) {
-		pr_err("Failed to set OCMEM on driver\n");
+		dprintk(VIDC_ERR, "Failed to set OCMEM on driver\n");
 		goto release_ocmem_failed;
 	}
 	rc = wait_for_completion_timeout(
 		&core->completions[SYS_MSG_INDEX(RELEASE_RESOURCE_DONE)],
 		msecs_to_jiffies(HW_RESPONSE_TIMEOUT));
 	if (!rc) {
-		pr_err("Wait interrupted or timeout: %d\n", rc);
+		dprintk(VIDC_ERR, "Wait interrupted or timeout: %d\n", rc);
 		rc = -EIO;
 		goto release_ocmem_failed;
 	}
@@ -844,49 +914,48 @@
 		unsigned long size)
 {
 	int rc = 0;
-	unsigned long flags;
 	struct ocmem_buf *ocmem_buffer;
+	mutex_lock(&core->sync_lock);
 	if (!core || !size) {
-		pr_err("Invalid param, core: %p, size: %lu\n", core, size);
+		dprintk(VIDC_ERR,
+			"Invalid param, core: %p, size: %lu\n", core, size);
 		return -EINVAL;
 	}
-	spin_lock_irqsave(&core->lock, flags);
 	ocmem_buffer = core->resources.ocmem.buf;
 	if (!ocmem_buffer ||
 		ocmem_buffer->len < size) {
 		ocmem_buffer = ocmem_allocate_nb(OCMEM_VIDEO, size);
 		if (IS_ERR_OR_NULL(ocmem_buffer)) {
-			pr_err("ocmem_allocate_nb failed: %d\n",
+			dprintk(VIDC_ERR,
+				"ocmem_allocate_nb failed: %d\n",
 				(u32) ocmem_buffer);
 			rc = -ENOMEM;
 		}
 		core->resources.ocmem.buf = ocmem_buffer;
 		rc = msm_comm_set_ocmem(core, ocmem_buffer);
 		if (rc) {
-			pr_err("Failed to set ocmem: %d\n", rc);
+			dprintk(VIDC_ERR, "Failed to set ocmem: %d\n", rc);
 			goto ocmem_set_failed;
 		}
 	} else
-		pr_debug("OCMEM is enough. reqd: %lu, available: %lu\n",
+		dprintk(VIDC_DBG,
+			"OCMEM is enough. reqd: %lu, available: %lu\n",
 			size, ocmem_buffer->len);
 
 ocmem_set_failed:
-	spin_unlock_irqrestore(&core->lock, flags);
+	mutex_unlock(&core->sync_lock);
 	return rc;
 }
 
 static int msm_comm_free_ocmem(struct msm_vidc_core *core)
 {
 	int rc = 0;
-	unsigned long flags;
-	spin_lock_irqsave(&core->lock, flags);
 	if (core->resources.ocmem.buf) {
 		rc = ocmem_free(OCMEM_VIDEO, core->resources.ocmem.buf);
 		if (rc)
-			pr_err("Failed to free ocmem\n");
+			dprintk(VIDC_ERR, "Failed to free ocmem\n");
 	}
 	core->resources.ocmem.buf = NULL;
-	spin_unlock_irqrestore(&core->lock, flags);
 	return rc;
 }
 
@@ -901,7 +970,7 @@
 	if (event == OCMEM_ALLOC_GROW) {
 		ocmem = container_of(this, struct on_chip_mem, vidc_ocmem_nb);
 		if (!ocmem) {
-			pr_err("Wrong handler passed\n");
+			dprintk(VIDC_ERR, "Wrong handler passed\n");
 			rc = NOTIFY_BAD;
 			goto bad_notfier;
 		}
@@ -910,7 +979,7 @@
 		core = container_of(resources,
 			struct msm_vidc_core, resources);
 		if (msm_comm_set_ocmem(core, buff)) {
-			pr_err("Failed to set ocmem: %d\n", rc);
+			dprintk(VIDC_ERR, "Failed to set ocmem: %d\n", rc);
 			goto ocmem_set_failed;
 		}
 		rc = NOTIFY_OK;
@@ -927,16 +996,16 @@
 	int rc = 0;
 	mutex_lock(&core->sync_lock);
 	if (core->state >= VIDC_CORE_INIT_DONE) {
-		pr_err("Video core: %d is already in state: %d\n",
+		dprintk(VIDC_INFO, "Video core: %d is already in state: %d\n",
 				core->id, core->state);
 		goto core_already_inited;
 	}
-	pr_debug("Waiting for SYS_INIT_DONE\n");
+	dprintk(VIDC_DBG, "Waiting for SYS_INIT_DONE\n");
 	rc = wait_for_completion_timeout(
 		&core->completions[SYS_MSG_INDEX(SYS_INIT_DONE)],
 		msecs_to_jiffies(HW_RESPONSE_TIMEOUT));
 	if (!rc) {
-		pr_err("Wait interrupted or timeout: %d\n", rc);
+		dprintk(VIDC_ERR, "Wait interrupted or timeout: %d\n", rc);
 		rc = -EIO;
 		goto exit;
 	} else {
@@ -944,7 +1013,7 @@
 		core->state = VIDC_CORE_INIT_DONE;
 		spin_unlock_irqrestore(&core->lock, flags);
 	}
-	pr_debug("SYS_INIT_DONE!!!\n");
+	dprintk(VIDC_DBG, "SYS_INIT_DONE!!!\n");
 core_already_inited:
 	change_inst_state(inst, MSM_VIDC_CORE_INIT_DONE);
 	rc = 0;
@@ -960,20 +1029,25 @@
 	unsigned long flags;
 	mutex_lock(&core->sync_lock);
 	if (core->state >= VIDC_CORE_INIT) {
-		pr_err("Video core: %d is already in state: %d\n",
+		dprintk(VIDC_INFO, "Video core: %d is already in state: %d\n",
 				core->id, core->state);
 		goto core_already_inited;
 	}
+	rc = msm_comm_scale_clocks(core, inst->session_type);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to set clock rate: %d\n", rc);
+		goto fail_load_fw;
+	}
 	rc = msm_comm_load_fw(core);
 	if (rc) {
-		pr_err("Failed to load video firmware\n");
+		dprintk(VIDC_ERR, "Failed to load video firmware\n");
 		goto fail_load_fw;
 	}
 	init_completion(&core->completions[SYS_MSG_INDEX(SYS_INIT_DONE)]);
 	rc = vidc_hal_core_init(core->device,
 		core->resources.io_map[NS_MAP].domain);
 	if (rc) {
-		pr_err("Failed to init core, id = %d\n", core->id);
+		dprintk(VIDC_ERR, "Failed to init core, id = %d\n", core->id);
 		goto fail_core_init;
 	}
 	spin_lock_irqsave(&core->lock, flags);
@@ -997,16 +1071,22 @@
 	unsigned long flags;
 	mutex_lock(&core->sync_lock);
 	if (core->state == VIDC_CORE_UNINIT) {
-		pr_err("Video core: %d is already in state: %d\n",
+		dprintk(VIDC_INFO, "Video core: %d is already in state: %d\n",
 				core->id, core->state);
 		goto core_already_uninited;
 	}
+	if (msm_comm_scale_clocks(core, inst->session_type)) {
+		dprintk(VIDC_WARN, "Failed to scale clocks while closing\n");
+		dprintk(VIDC_WARN, "Power might be impacted\n");
+	}
 	if (list_empty(&core->instances)) {
 		msm_comm_unset_ocmem(core);
 		msm_comm_free_ocmem(core);
+		dprintk(VIDC_DBG, "Calling vidc_hal_core_release\n");
 		rc = vidc_hal_core_release(core->device);
 		if (rc) {
-			pr_err("Failed to release core, id = %d\n", core->id);
+			dprintk(VIDC_ERR, "Failed to release core, id = %d\n",
+							core->id);
 			goto exit;
 		}
 		spin_lock_irqsave(&core->lock, flags);
@@ -1032,7 +1112,7 @@
 		domain = HAL_VIDEO_DOMAIN_DECODER;
 		break;
 	default:
-		pr_err("Wrong domain\n");
+		dprintk(VIDC_ERR, "Wrong domain\n");
 		domain = HAL_UNUSED_DOMAIN;
 		break;
 	}
@@ -1042,7 +1122,7 @@
 static enum hal_video_codec get_hal_codec_type(int fourcc)
 {
 	enum hal_video_codec codec;
-	pr_debug("codec in %s is 0x%x", __func__, fourcc);
+	dprintk(VIDC_DBG, "codec is 0x%x", fourcc);
 	switch (fourcc) {
 	case V4L2_PIX_FMT_H264:
 	case V4L2_PIX_FMT_H264_NO_SC:
@@ -1078,7 +1158,7 @@
 		  HAL_VIDEO_CODEC_VP6
 		  HAL_VIDEO_CODEC_VP7*/
 	default:
-		pr_err("Wrong codec: %d\n", fourcc);
+		dprintk(VIDC_ERR, "Wrong codec: %d\n", fourcc);
 		codec = HAL_UNUSED_CODEC;
 	}
 	return codec;
@@ -1090,7 +1170,8 @@
 	int rc = 0;
 	int fourcc = 0;
 	if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_OPEN)) {
-		pr_err("inst: %p is already in state: %d\n", inst, inst->state);
+		dprintk(VIDC_INFO, "inst: %p is already in state: %d\n",
+						inst, inst->state);
 		goto exit;
 	}
 	if (inst->session_type == MSM_VIDC_DECODER) {
@@ -1098,7 +1179,7 @@
 	} else if (inst->session_type == MSM_VIDC_ENCODER) {
 		fourcc = inst->fmts[CAPTURE_PORT]->fourcc;
 	} else {
-		pr_err("Invalid session\n");
+		dprintk(VIDC_ERR, "Invalid session\n");
 		return -EINVAL;
 	}
 	init_completion(
@@ -1107,11 +1188,14 @@
 					get_hal_domain(inst->session_type),
 					get_hal_codec_type(fourcc));
 	if (!inst->session) {
-		pr_err("Failed to call session init for: %d, %d, %d, %d\n",
-				(int)inst->core->device, (int)inst,
-				inst->session_type, fourcc);
+		dprintk(VIDC_ERR,
+			"Failed to call session init for: %d, %d, %d, %d\n",
+			(int)inst->core->device, (int)inst,
+			inst->session_type, fourcc);
 		goto exit;
 	}
+	inst->ftb_count = 0;
+	inst->fbd_count = 0;
 	change_inst_state(inst, MSM_VIDC_OPEN);
 exit:
 	return rc;
@@ -1123,17 +1207,20 @@
 	int rc = 0;
 	u32 ocmem_sz = 0;
 	if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_LOAD_RESOURCES)) {
-		pr_err("inst: %p is already in state: %d\n", inst, inst->state);
+		dprintk(VIDC_INFO, "inst: %p is already in state: %d\n",
+						inst, inst->state);
 		goto exit;
 	}
 	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");
+		dprintk(VIDC_WARN,
+			"Failed to allocate OCMEM. Performance will be impacted\n");
 
 	rc = vidc_hal_session_load_res((void *) inst->session);
 	if (rc) {
-		pr_err("Failed to send load resources\n");
+		dprintk(VIDC_ERR,
+			"Failed to send load resources\n");
 		goto exit;
 	}
 	change_inst_state(inst, MSM_VIDC_LOAD_RESOURCES);
@@ -1145,14 +1232,17 @@
 {
 	int rc = 0;
 	if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_START)) {
-		pr_err("inst: %p is already in state: %d\n", inst, inst->state);
+		dprintk(VIDC_INFO,
+			"inst: %p is already in state: %d\n",
+			inst, inst->state);
 		goto exit;
 	}
 	init_completion(
 		&inst->completions[SESSION_MSG_INDEX(SESSION_START_DONE)]);
 	rc = vidc_hal_session_start((void *) inst->session);
 	if (rc) {
-		pr_err("Failed to send load resources\n");
+		dprintk(VIDC_ERR,
+			"Failed to send load resources\n");
 		goto exit;
 	}
 	change_inst_state(inst, MSM_VIDC_START);
@@ -1164,15 +1254,17 @@
 {
 	int rc = 0;
 	if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_STOP)) {
-		pr_err("inst: %p is already in state: %d\n", inst, inst->state);
+		dprintk(VIDC_INFO,
+			"inst: %p is already in state: %d\n",
+			inst, inst->state);
 		goto exit;
 	}
-	pr_debug("Send Stop to hal\n");
+	dprintk(VIDC_DBG, "Send Stop to hal\n");
 	init_completion(
 		&inst->completions[SESSION_MSG_INDEX(SESSION_STOP_DONE)]);
 	rc = vidc_hal_session_stop((void *) inst->session);
 	if (rc) {
-		pr_err("Failed to send stop\n");
+		dprintk(VIDC_ERR, "Failed to send stop\n");
 		goto exit;
 	}
 	change_inst_state(inst, MSM_VIDC_STOP);
@@ -1184,15 +1276,19 @@
 {
 	int rc = 0;
 	if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_RELEASE_RESOURCES)) {
-		pr_err("inst: %p is already in state: %d\n", inst, inst->state);
+		dprintk(VIDC_INFO,
+			"inst: %p is already in state: %d\n",
+			inst, inst->state);
 		goto exit;
 	}
-	pr_debug("Send release res to hal\n");
+	dprintk(VIDC_DBG,
+		"Send release res to hal\n");
 	init_completion(
 	&inst->completions[SESSION_MSG_INDEX(SESSION_RELEASE_RESOURCE_DONE)]);
 	rc = vidc_hal_session_release_res((void *) inst->session);
 	if (rc) {
-		pr_err("Failed to send load resources\n");
+		dprintk(VIDC_ERR,
+			"Failed to send load resources\n");
 		goto exit;
 	}
 	change_inst_state(inst, MSM_VIDC_RELEASE_RESOURCES);
@@ -1204,15 +1300,19 @@
 {
 	int rc = 0;
 	if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_CLOSE)) {
-		pr_err("inst: %p is already in state: %d\n", inst, inst->state);
+		dprintk(VIDC_INFO,
+			"inst: %p is already in state: %d\n",
+						inst, inst->state);
 		goto exit;
 	}
-	pr_debug("Send session close to hal\n");
+	dprintk(VIDC_DBG,
+		"Send session close to hal\n");
 	init_completion(
 		&inst->completions[SESSION_MSG_INDEX(SESSION_END_DONE)]);
 	rc = vidc_hal_session_end((void *) inst->session);
 	if (rc) {
-		pr_err("Failed to send load resources\n");
+		dprintk(VIDC_ERR,
+			"Failed to send load resources\n");
 		goto exit;
 	}
 	change_inst_state(inst, MSM_VIDC_OPEN);
@@ -1225,10 +1325,12 @@
 	int rc = 0;
 	int flipped_state;
 	if (!inst) {
-		pr_err("Invalid instance pointer = %p\n", inst);
+		dprintk(VIDC_ERR,
+			"Invalid instance pointer = %p\n", inst);
 		return -EINVAL;
 	}
-	pr_debug("Trying to move inst: %p from: 0x%x to 0x%x\n",
+	dprintk(VIDC_DBG,
+		"Trying to move inst: %p from: 0x%x to 0x%x\n",
 				inst, inst->state, state);
 	mutex_lock(&inst->sync_lock);
 	flipped_state = inst->state;
@@ -1244,7 +1346,8 @@
 		flipped_state &= 0xFFFE;
 		flipped_state = flipped_state - 1;
 	}
-	pr_debug("flipped_state = 0x%x\n", flipped_state);
+	dprintk(VIDC_DBG,
+		"flipped_state = 0x%x\n", flipped_state);
 	switch (flipped_state) {
 	case MSM_VIDC_CORE_UNINIT_DONE:
 	case MSM_VIDC_CORE_INIT:
@@ -1287,7 +1390,7 @@
 				SESSION_STOP_DONE);
 		if (rc || state <= inst->state)
 			break;
-		pr_debug("Moving to Stop Done state\n");
+		dprintk(VIDC_DBG, "Moving to Stop Done state\n");
 	case MSM_VIDC_RELEASE_RESOURCES:
 		rc = msm_vidc_release_res(flipped_state, inst);
 		if (rc || state <= inst->state)
@@ -1298,7 +1401,8 @@
 			SESSION_RELEASE_RESOURCE_DONE);
 		if (rc || state <= inst->state)
 			break;
-		pr_debug("Moving to release resources done state\n");
+		dprintk(VIDC_DBG,
+			"Moving to release resources done state\n");
 	case MSM_VIDC_CLOSE:
 		rc = msm_comm_session_close(flipped_state, inst);
 		if (rc || state <= inst->state)
@@ -1309,18 +1413,19 @@
 		if (rc || state <= inst->state)
 			break;
 	case MSM_VIDC_CORE_UNINIT:
-		pr_debug("***************Sending core uninit\n");
+		dprintk(VIDC_DBG, "Sending core uninit\n");
 		rc = msm_vidc_deinit_core(inst);
 		if (rc || state == inst->state)
 			break;
 	default:
-		pr_err("State not recognized: %d\n", flipped_state);
+		dprintk(VIDC_ERR, "State not recognized\n");
 		rc = -EINVAL;
 		break;
 	}
 	mutex_unlock(&inst->sync_lock);
 	if (rc)
-		pr_err("Failed to move from state: %d to %d\n",
+		dprintk(VIDC_ERR,
+			"Failed to move from state: %d to %d\n",
 			inst->state, state);
 	return rc;
 }
@@ -1337,39 +1442,52 @@
 	inst = q->drv_priv;
 
 	if (!inst || !vb) {
-		pr_err("Invalid input: %p, %p\n", inst, vb);
+		dprintk(VIDC_ERR, "Invalid input: %p, %p\n", inst, vb);
 		return -EINVAL;
 	}
 	if (inst->state != MSM_VIDC_START_DONE) {
 			entry = kzalloc(sizeof(*entry), GFP_KERNEL);
 			if (!entry) {
-				pr_err("Out of memory\n");
+				dprintk(VIDC_ERR, "Out of memory\n");
 				goto err_no_mem;
 			}
 			entry->vb = vb;
-			pr_debug("Queueing buffer in pendingq\n");
+			dprintk(VIDC_DBG, "Queueing buffer in pendingq\n");
 			spin_lock_irqsave(&inst->lock, flags);
 			list_add_tail(&entry->list, &inst->pendingq);
 			spin_unlock_irqrestore(&inst->lock, flags);
 	} else {
+		int64_t time_usec = timeval_to_ns(&vb->v4l2_buf.timestamp);
+		do_div(time_usec, NSEC_PER_USEC);
 		memset(&frame_data, 0 , sizeof(struct vidc_frame_data));
 		frame_data.alloc_len = vb->v4l2_planes[0].length;
 		frame_data.filled_len = vb->v4l2_planes[0].bytesused;
 		frame_data.device_addr = vb->v4l2_planes[0].m.userptr;
-		frame_data.timestamp = vb->v4l2_buf.timestamp.tv_usec;
+		frame_data.timestamp = time_usec;
+		frame_data.flags = 0;
 		frame_data.clnt_data = (u32)vb;
 		if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
 			frame_data.buffer_type = HAL_BUFFER_INPUT;
 			if (vb->v4l2_buf.flags & V4L2_BUF_FLAG_EOS) {
-				frame_data.flags = HAL_BUFFERFLAG_EOS;
-				pr_debug("Received EOS on output capability\n");
+				frame_data.flags |= HAL_BUFFERFLAG_EOS;
+				dprintk(VIDC_DBG,
+					"Received EOS on output capability\n");
 			}
-			pr_debug("Sending etb to hal: Alloc: %d :filled: %d\n",
+
+			if (vb->v4l2_buf.flags &
+					V4L2_QCOM_BUF_FLAG_CODECCONFIG) {
+				frame_data.flags |= HAL_BUFFERFLAG_CODECCONFIG;
+				dprintk(VIDC_DBG,
+					"Received CODECCONFIG on output cap\n");
+			}
+			dprintk(VIDC_DBG,
+				"Sending etb to hal: Alloc: %d :filled: %d\n",
 				frame_data.alloc_len, frame_data.filled_len);
 			rc = vidc_hal_session_etb((void *) inst->session,
 					&frame_data);
-			pr_debug("Sent etb to HAL\n");
+			dprintk(VIDC_DBG, "Sent etb to HAL\n");
 		} else if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+			struct vidc_seq_hdr seq_hdr;
 			frame_data.filled_len = 0;
 			frame_data.buffer_type = HAL_BUFFER_OUTPUT;
 			if (inst->extradata_handle) {
@@ -1378,20 +1496,38 @@
 			} else {
 				frame_data.extradata_addr = 0;
 			}
-			pr_debug("Sending ftb to hal..: Alloc: %d :filled: %d",
+			dprintk(VIDC_DBG,
+				"Sending ftb to hal: Alloc: %d :filled: %d",
 				frame_data.alloc_len, frame_data.filled_len);
-			pr_debug(" extradata_addr: %d\n",
+			dprintk(VIDC_DBG,
+				" extradata_addr: %d\n",
 				frame_data.extradata_addr);
-			rc = vidc_hal_session_ftb((void *) inst->session,
-					&frame_data);
+			if (!inst->ftb_count &&
+			   inst->session_type == MSM_VIDC_ENCODER) {
+				seq_hdr.seq_hdr = (u8 *) vb->v4l2_planes[0].
+					m.userptr;
+				seq_hdr.seq_hdr_len = vb->v4l2_planes[0].length;
+				rc = vidc_hal_session_get_seq_hdr((void *)
+						inst->session, &seq_hdr);
+				if (!rc) {
+					inst->vb2_seq_hdr = vb;
+					dprintk(VIDC_DBG, "Seq_hdr: %p\n",
+						inst->vb2_seq_hdr);
+				}
+			} else {
+				rc = vidc_hal_session_ftb((void *)
+					inst->session, &frame_data);
+			}
+			inst->ftb_count++;
 		} else {
-			pr_err("This capability is not supported: %d\n",
+			dprintk(VIDC_ERR,
+				"This capability is not supported: %d\n",
 				q->type);
 			rc = -EINVAL;
 		}
 	}
 	if (rc)
-		pr_err("Failed to queue buffer\n");
+		dprintk(VIDC_ERR, "Failed to queue buffer\n");
 err_no_mem:
 	return rc;
 }
@@ -1404,14 +1540,15 @@
 		&inst->completions[SESSION_MSG_INDEX(SESSION_PROPERTY_INFO)]);
 	rc = vidc_hal_session_get_buf_req((void *) inst->session);
 	if (rc) {
-		pr_err("Failed to get property\n");
+		dprintk(VIDC_ERR, "Failed to get property\n");
 		goto exit;
 	}
 	rc = wait_for_completion_timeout(
 		&inst->completions[SESSION_MSG_INDEX(SESSION_PROPERTY_INFO)],
 		msecs_to_jiffies(HW_RESPONSE_TIMEOUT));
 	if (!rc) {
-		pr_err("Wait interrupted or timeout: %d\n", rc);
+		dprintk(VIDC_ERR,
+			"Wait interrupted or timeout: %d\n", rc);
 		rc = -EIO;
 		goto exit;
 	}
@@ -1421,67 +1558,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;
@@ -1493,10 +1569,10 @@
 	struct hal_buffer_requirements *scratch_buf =
 		&inst->buff_req.buffer[HAL_BUFFER_INTERNAL_SCRATCH];
 	int i;
-
-	pr_debug("scratch: num = %d, size = %d\n",
-			scratch_buf->buffer_count_actual,
-			scratch_buf->buffer_size);
+	dprintk(VIDC_DBG,
+		"scratch: num = %d, size = %d\n",
+		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) {
@@ -1512,16 +1588,18 @@
 		for (i = 0; i < scratch_buf->buffer_count_actual;
 				i++) {
 			handle = msm_smem_alloc(inst->mem_client,
-				scratch_buf->buffer_size, 1, 0,
-				inst->core->resources.io_map[NS_MAP].domain, 0);
+				scratch_buf->buffer_size, 1, SMEM_UNCACHED,
+				inst->core->resources.io_map[NS_MAP].domain,
+				0, 0);
 			if (!handle) {
-				pr_err("Failed to allocate scratch memory\n");
+				dprintk(VIDC_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");
+				dprintk(VIDC_ERR, "Out of memory\n");
 				rc = -ENOMEM;
 				goto fail_kzalloc;
 			}
@@ -1533,7 +1611,8 @@
 			rc = vidc_hal_session_set_buffers(
 					(void *) inst->session,	&buffer_info);
 			if (rc) {
-				pr_err("vidc_hal_session_set_buffers failed");
+				dprintk(VIDC_ERR,
+					"vidc_hal_session_set_buffers failed");
 				goto fail_set_buffers;
 			}
 			spin_lock_irqsave(&inst->lock, flags);
@@ -1549,3 +1628,91 @@
 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;
+	dprintk(VIDC_DBG,
+		"persist: num = %d, size = %d\n",
+		persist_buf->buffer_count_actual,
+		persist_buf->buffer_size);
+	if (!list_empty(&inst->persistbufs)) {
+		dprintk(VIDC_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, SMEM_UNCACHED,
+				inst->core->resources.io_map[NS_MAP].domain,
+				0, 0);
+			if (!handle) {
+				dprintk(VIDC_ERR,
+					"Failed to allocate persist memory\n");
+				rc = -ENOMEM;
+				goto err_no_mem;
+			}
+			binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
+			if (!binfo) {
+				dprintk(VIDC_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) {
+				dprintk(VIDC_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;
+}
+
+int msm_comm_flush(struct msm_vidc_inst *inst, u32 flags)
+{
+	int rc =  0;
+	bool ip_flush = false;
+	bool op_flush = false;
+	ip_flush = flags & V4L2_QCOM_CMD_FLUSH_OUTPUT;
+	op_flush = flags & V4L2_QCOM_CMD_FLUSH_CAPTURE;
+
+	if (ip_flush && !op_flush) {
+		dprintk(VIDC_WARN, "Input only flush not supported\n");
+		return 0;
+	}
+	mutex_lock(&inst->sync_lock);
+	if (inst->in_reconfig && !ip_flush && op_flush) {
+		rc = vidc_hal_session_flush(inst->session,
+				HAL_FLUSH_OUTPUT);
+	} else {
+		rc = vidc_hal_session_flush(inst->session,
+				HAL_FLUSH_ALL);
+	}
+	mutex_unlock(&inst->sync_lock);
+	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..69aa53a 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.h
@@ -28,8 +28,10 @@
 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);
+int msm_comm_scale_clocks(struct msm_vidc_core *core, enum session_type type);
+int msm_comm_flush(struct msm_vidc_inst *inst, u32 flags);
 #define IS_PRIV_CTRL(idx) (\
 		(V4L2_CTRL_ID2CLASS(idx) == V4L2_CTRL_CLASS_MPEG) && \
 		V4L2_CTRL_DRIVER_PRIV(idx))
diff --git a/drivers/media/video/msm_vidc/msm_vidc_debug.c b/drivers/media/video/msm_vidc/msm_vidc_debug.c
new file mode 100644
index 0000000..7921f84
--- /dev/null
+++ b/drivers/media/video/msm_vidc/msm_vidc_debug.c
@@ -0,0 +1,186 @@
+/* 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 "msm_vidc_debug.h"
+
+#define MAX_DBG_BUF_SIZE 4096
+int msm_vidc_debug;
+
+struct debug_buffer {
+	char ptr[MAX_DBG_BUF_SIZE];
+	char *curr;
+	u32 filled_size;
+};
+
+static struct debug_buffer dbg_buf;
+
+#define INIT_DBG_BUF(__buf) ({ \
+	__buf.curr = __buf.ptr;\
+	__buf.filled_size = 0; \
+})
+
+static int core_info_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static u32 write_str(struct debug_buffer *buffer, const char *fmt, ...)
+{
+	va_list args;
+	u32 size;
+	va_start(args, fmt);
+	size = vscnprintf(buffer->curr, MAX_DBG_BUF_SIZE - 1, fmt, args);
+	va_end(args);
+	buffer->curr += size;
+	buffer->filled_size += size;
+	return size;
+}
+
+static ssize_t core_info_read(struct file *file, char __user *buf,
+		size_t count, loff_t *ppos)
+{
+	struct msm_vidc_core *core = file->private_data;
+	int i = 0;
+	if (!core) {
+		dprintk(VIDC_ERR, "Invalid params, core: %p\n", core);
+		return 0;
+	}
+	INIT_DBG_BUF(dbg_buf);
+	write_str(&dbg_buf, "===============================\n");
+	write_str(&dbg_buf, "CORE %d: 0x%p\n", core->id, core);
+	write_str(&dbg_buf, "===============================\n");
+	write_str(&dbg_buf, "state: %d\n", core->state);
+	write_str(&dbg_buf, "base addr: 0x%x\n", core->base_addr);
+	write_str(&dbg_buf, "register_base: 0x%x\n", core->register_base);
+	write_str(&dbg_buf, "register_size: %u\n", core->register_size);
+	write_str(&dbg_buf, "irq: %u\n", core->irq);
+	for (i = SYS_MSG_START; i < SYS_MSG_END; i++) {
+		write_str(&dbg_buf, "completions[%d]: %s\n", i,
+			completion_done(&core->completions[SYS_MSG_INDEX(i)]) ?
+			"pending" : "done");
+	}
+	return simple_read_from_buffer(buf, count, ppos,
+			dbg_buf.ptr, dbg_buf.filled_size);
+}
+
+static const struct file_operations core_info_fops = {
+	.open = core_info_open,
+	.read = core_info_read,
+};
+
+struct dentry *msm_vidc_debugfs_init_core(struct msm_vidc_core *core,
+		struct dentry *parent)
+{
+	struct dentry *dir = NULL;
+	char debugfs_name[MAX_DEBUGFS_NAME];
+	if (!core) {
+		dprintk(VIDC_ERR, "Invalid params, core: %p\n", core);
+		goto failed_create_dir;
+	}
+	msm_vidc_debug = 0;
+	snprintf(debugfs_name, MAX_DEBUGFS_NAME, "core%d", core->id);
+	dir = debugfs_create_dir(debugfs_name, parent);
+	if (!dir) {
+		dprintk(VIDC_ERR, "Failed to create debugfs for msm_vidc\n");
+		goto failed_create_dir;
+	}
+	if (!debugfs_create_file("info", S_IRUGO, dir, core, &core_info_fops)) {
+		dprintk(VIDC_ERR, "debugfs_create_file: fail\n");
+		goto failed_create_dir;
+	}
+	if (!debugfs_create_u32("debug_level", S_IRUGO | S_IWUSR,
+			parent,	&msm_vidc_debug)) {
+		dprintk(VIDC_ERR, "debugfs_create_file: fail\n");
+		goto failed_create_dir;
+	}
+failed_create_dir:
+	return dir;
+}
+
+static int inst_info_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t inst_info_read(struct file *file, char __user *buf,
+		size_t count, loff_t *ppos)
+{
+	struct msm_vidc_inst *inst = file->private_data;
+	int i, j;
+	if (!inst) {
+		dprintk(VIDC_ERR, "Invalid params, core: %p\n", inst);
+		return 0;
+	}
+	INIT_DBG_BUF(dbg_buf);
+	write_str(&dbg_buf, "===============================\n");
+	write_str(&dbg_buf, "INSTANCE: 0x%p (%s)\n", inst,
+		inst->session_type == MSM_VIDC_ENCODER ? "Encoder" : "Decoder");
+	write_str(&dbg_buf, "===============================\n");
+	write_str(&dbg_buf, "core: 0x%p\n", inst->core);
+	write_str(&dbg_buf, "height: %d\n", inst->prop.height);
+	write_str(&dbg_buf, "width: %d\n", inst->prop.width);
+	write_str(&dbg_buf, "state: %d\n", inst->state);
+	write_str(&dbg_buf, "-----------Formats-------------\n");
+	for (i = 0; i < MAX_PORT_NUM; i++) {
+		write_str(&dbg_buf, "capability: %s\n", i == OUTPUT_PORT ?
+			"Output" : "Capture");
+		write_str(&dbg_buf, "name : %s\n", inst->fmts[i]->name);
+		write_str(&dbg_buf, "planes : %d\n", inst->fmts[i]->num_planes);
+		write_str(
+		&dbg_buf, "type: %s\n", inst->fmts[i]->type == OUTPUT_PORT ?
+		"Output" : "Capture");
+		for (j = 0; j < inst->fmts[i]->num_planes; j++)
+			write_str(&dbg_buf, "size for plane %d: %u\n", j,
+			inst->fmts[i]->get_frame_size(j,
+			inst->prop.height, inst->prop.width));
+	}
+	write_str(&dbg_buf, "-------------------------------\n");
+	for (i = SESSION_MSG_START; i < SESSION_MSG_END; i++) {
+		write_str(&dbg_buf, "completions[%d]: %s\n", i,
+		completion_done(&inst->completions[SESSION_MSG_INDEX(i)]) ?
+		"pending" : "done");
+	}
+	return simple_read_from_buffer(buf, count, ppos,
+		dbg_buf.ptr, dbg_buf.filled_size);
+}
+
+static const struct file_operations inst_info_fops = {
+	.open = inst_info_open,
+	.read = inst_info_read,
+};
+
+struct dentry *msm_vidc_debugfs_init_inst(struct msm_vidc_inst *inst,
+		struct dentry *parent)
+{
+	struct dentry *dir = NULL;
+	char debugfs_name[MAX_DEBUGFS_NAME];
+	if (!inst) {
+		dprintk(VIDC_ERR, "Invalid params, inst: %p\n", inst);
+		goto failed_create_dir;
+	}
+	snprintf(debugfs_name, MAX_DEBUGFS_NAME, "inst_%p", inst);
+	dir = debugfs_create_dir(debugfs_name, parent);
+	if (!dir) {
+		dprintk(VIDC_ERR, "Failed to create debugfs for msm_vidc\n");
+		goto failed_create_dir;
+	}
+	if (!debugfs_create_file("info", S_IRUGO, dir, inst, &inst_info_fops)) {
+		dprintk(VIDC_ERR, "debugfs_create_file: fail\n");
+		goto failed_create_dir;
+	}
+
+failed_create_dir:
+	return dir;
+}
diff --git a/drivers/media/video/msm_vidc/msm_vidc_debug.h b/drivers/media/video/msm_vidc/msm_vidc_debug.h
new file mode 100644
index 0000000..b7928e9
--- /dev/null
+++ b/drivers/media/video/msm_vidc/msm_vidc_debug.h
@@ -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.
+ *
+ */
+
+#ifndef __MSM_VIDC_DEBUG__
+#define __MSM_VIDC_DEBUG__
+#include <linux/debugfs.h>
+#include "msm_vidc_internal.h"
+
+#define VIDC_DBG_TAG "msm_vidc: %d: "
+
+enum vidc_msg_prio {
+	VIDC_ERR,
+	VIDC_WARN,
+	VIDC_INFO,
+	VIDC_DBG,
+};
+
+extern int msm_vidc_debug;
+#define dprintk(level, fmt, arg...)	\
+	do {							\
+		if (msm_vidc_debug >= level) \
+			printk(KERN_DEBUG VIDC_DBG_TAG fmt, \
+				level, ## arg); \
+	} while (0)
+
+struct dentry *msm_vidc_debugfs_init_core(struct msm_vidc_core *core,
+		struct dentry *parent);
+struct dentry *msm_vidc_debugfs_init_inst(struct msm_vidc_inst *inst,
+		struct dentry *parent);
+
+#endif
diff --git a/drivers/media/video/msm_vidc/msm_vidc_internal.h b/drivers/media/video/msm_vidc/msm_vidc_internal.h
index 8c11de8..55aec74 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_internal.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_internal.h
@@ -47,6 +47,32 @@
 #define SESSION_MSG_INDEX(__msg) (__msg - SESSION_MSG_START)
 
 #define MAX_NAME_LENGTH 64
+
+#define NV12_IL_CALC_Y_STRIDE(stride, frame_width, stride_multiple) \
+	{ stride = (frame_width + stride_multiple - 1) & \
+	(0xffffffff - (stride_multiple - 1)); }
+
+#define NV12_IL_CALC_Y_BUFHEIGHT(buf_height, frame_height,\
+	min_buf_height_multiple) \
+	{ buf_height = (frame_height + min_buf_height_multiple - 1) & \
+	(0xffffffff - (min_buf_height_multiple - 1)); }
+
+#define NV12_IL_CALC_UV_STRIDE(stride, frame_width, stride_multiple) \
+	{ stride = ((((frame_width + 1) >> 1) + stride_multiple - 1) & \
+	(0xffffffff - (stride_multiple - 1))) << 1; }
+
+#define NV12_IL_CALC_UV_BUFHEIGHT(buf_height, frame_height,\
+	min_buf_height_multiple) \
+	{ buf_height = ((((frame_height + 1) >> 1) + \
+	min_buf_height_multiple - 1) & (0xffffffff - \
+	(min_buf_height_multiple - 1))); }
+
+#define NV12_IL_CALC_BUF_SIZE(buf_size, y_buf_size, y_stride, \
+	y_buf_height, uv_buf_size, uv_stride, uv_buf_height, uv_alignment) \
+	{ y_buf_size = (y_stride * y_buf_height); \
+	uv_buf_size = (uv_stride * uv_buf_height) + uv_alignment; \
+	buf_size = y_buf_size + uv_buf_size; }
+
 enum vidc_ports {
 	OUTPUT_PORT,
 	CAPTURE_PORT,
@@ -150,8 +176,8 @@
 };
 
 struct vidc_bus_info {
-	u32 vcodec_handle;
-	u32 ocmem_handle;
+	u32 ddr_handle[MSM_VIDC_MAX_DEVICES];
+	u32 ocmem_handle[MSM_VIDC_MAX_DEVICES];
 };
 
 struct on_chip_mem {
@@ -207,6 +233,7 @@
 	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;
@@ -216,6 +243,10 @@
 	bool in_reconfig;
 	u32 reconfig_width;
 	u32 reconfig_height;
+	struct dentry *debugfs_root;
+	u32 ftb_count;
+	u32 fbd_count;
+	struct vb2_buffer *vb2_seq_hdr;
 };
 
 extern struct msm_vidc_drv *vidc_driver;
diff --git a/drivers/media/video/msm_vidc/vidc_hal.c b/drivers/media/video/msm_vidc/vidc_hal.c
index 16a3ecd..12ba874 100644
--- a/drivers/media/video/msm_vidc/vidc_hal.c
+++ b/drivers/media/video/msm_vidc/vidc_hal.c
@@ -21,6 +21,7 @@
 #include <asm/memory.h>
 #include "vidc_hal.h"
 #include "vidc_hal_io.h"
+#include "msm_vidc_debug.h"
 
 #define FIRMWARE_SIZE			0X00A00000
 #define REG_ADDR_OFFSET_BITMASK	0x000FFFFF
@@ -37,7 +38,7 @@
 	u8 i;
 
 	if (!packet) {
-		HAL_MSG_ERROR("Invalid Param: %s", __func__);
+		dprintk(VIDC_ERR, "Invalid Param");
 		return;
 	}
 
@@ -129,26 +130,25 @@
 	u32 *write_ptr;
 
 	if (!info || !packet || !rx_req_is_set) {
-		HAL_MSG_ERROR("Invalid Params in %s", __func__);
+		dprintk(VIDC_ERR, "Invalid Params");
 		return -EINVAL;
 	}
 
 	qinfo =	(struct vidc_iface_q_info *) info;
-	HAL_MSG_LOW("In %s: ", __func__);
 	hal_virtio_modify_cmd_packet(packet);
 
 	queue = (struct hfi_queue_header *) qinfo->q_hdr;
 
 	if (!queue) {
-		HAL_MSG_ERROR("queue not present");
+		dprintk(VIDC_ERR, "queue not present");
 		return -ENOENT;
 	}
 
 	packet_size_in_words = (*(u32 *)packet) >> 2;
-	HAL_MSG_LOW("Packet_size in words: %d", packet_size_in_words);
+	dprintk(VIDC_DBG, "Packet_size in words: %d", packet_size_in_words);
 
 	if (packet_size_in_words == 0) {
-		HAL_MSG_ERROR("Zero packet size");
+		dprintk(VIDC_ERR, "Zero packet size");
 		return -ENODATA;
 	}
 
@@ -157,10 +157,10 @@
 	empty_space = (queue->qhdr_write_idx >=  read_idx) ?
 		(queue->qhdr_q_size - (queue->qhdr_write_idx -  read_idx)) :
 		(read_idx - queue->qhdr_write_idx);
-	HAL_MSG_LOW("Empty_space: %d", empty_space);
+	dprintk(VIDC_DBG, "Empty_space: %d", empty_space);
 	if (empty_space <= packet_size_in_words) {
 		queue->qhdr_tx_req =  1;
-		HAL_MSG_ERROR("Insufficient size (%d) to write (%d)",
+		dprintk(VIDC_ERR, "Insufficient size (%d) to write (%d)",
 					  empty_space, packet_size_in_words);
 		return -ENOTEMPTY;
 	}
@@ -170,7 +170,7 @@
 	new_write_idx = (queue->qhdr_write_idx + packet_size_in_words);
 	write_ptr = (u32 *)((qinfo->q_array.align_virtual_addr) +
 		(queue->qhdr_write_idx << 2));
-	HAL_MSG_LOW("Write Ptr: %d", (u32) write_ptr);
+	dprintk(VIDC_DBG, "Write Ptr: %d", (u32) write_ptr);
 	if (new_write_idx < queue->qhdr_q_size) {
 		memcpy(write_ptr, packet, packet_size_in_words << 2);
 	} else {
@@ -183,7 +183,7 @@
 	}
 	queue->qhdr_write_idx = new_write_idx;
 	*rx_req_is_set = (1 == queue->qhdr_rx_req) ? 1 : 0;
-	HAL_MSG_LOW("Out %s: ", __func__);
+	dprintk(VIDC_DBG, "Out : ");
 	return 0;
 }
 
@@ -193,7 +193,7 @@
 	struct hal_session *sess;
 
 	if (!packet) {
-		HAL_MSG_ERROR("Invalid Param: %s", __func__);
+		dprintk(VIDC_ERR, "Invalid Param: ");
 		return;
 	}
 
@@ -248,16 +248,15 @@
 	struct vidc_iface_q_info *qinfo;
 
 	if (!info || !packet || !pb_tx_req_is_set) {
-		HAL_MSG_ERROR("Invalid Params in %s", __func__);
+		dprintk(VIDC_ERR, "Invalid Params in ");
 		return -EINVAL;
 	}
 
 	qinfo =	(struct vidc_iface_q_info *) info;
-	HAL_MSG_LOW("In %s: ", __func__);
 	queue = (struct hfi_queue_header *) qinfo->q_hdr;
 
 	if (!queue) {
-		HAL_MSG_ERROR("Queue memory is not allocated\n");
+		dprintk(VIDC_ERR, "Queue memory is not allocated\n");
 		return -ENOMEM;
 	}
 
@@ -270,14 +269,14 @@
 	read_ptr = (u32 *)((qinfo->q_array.align_virtual_addr) +
 				(queue->qhdr_read_idx << 2));
 	packet_size_in_words = (*read_ptr) >> 2;
-	HAL_MSG_LOW("packet_size_in_words: %d", packet_size_in_words);
+	dprintk(VIDC_DBG, "packet_size_in_words: %d", packet_size_in_words);
 	if (packet_size_in_words == 0) {
-		HAL_MSG_ERROR("Zero packet size");
+		dprintk(VIDC_ERR, "Zero packet size");
 		return -ENODATA;
 	}
 
 	new_read_idx = queue->qhdr_read_idx + packet_size_in_words;
-	HAL_MSG_LOW("Read Ptr: %d", (u32) new_read_idx);
+	dprintk(VIDC_DBG, "Read Ptr: %d", (u32) new_read_idx);
 	if (new_read_idx < queue->qhdr_q_size) {
 		memcpy(packet, read_ptr,
 			packet_size_in_words << 2);
@@ -299,7 +298,7 @@
 
 	*pb_tx_req_is_set = (1 == queue->qhdr_tx_req) ? 1 : 0;
 	hal_virtio_modify_msg_packet(packet);
-	HAL_MSG_LOW("Out %s: ", __func__);
+	dprintk(VIDC_DBG, "Out : ");
 	return 0;
 }
 
@@ -308,28 +307,38 @@
 {
 	struct vidc_mem_addr *vmem;
 	struct msm_smem *alloc;
+	int rc = 0;
 
 	if (!mem || !clnt || !size) {
-		HAL_MSG_ERROR("Invalid Params in %s", __func__);
+		dprintk(VIDC_ERR, "Invalid Params in ");
 		return -EINVAL;
 	}
 	vmem = (struct vidc_mem_addr *)mem;
-	HAL_MSG_HIGH("start to alloc: size:%d, Flags: %d", size, flags);
+	dprintk(VIDC_WARN, "start to alloc: size:%d, Flags: %d", size, flags);
 
-	alloc  = msm_smem_alloc(clnt, size, align, flags, domain, 0);
-	HAL_MSG_LOW("Alloc done");
+	alloc  = msm_smem_alloc(clnt, size, align, flags, domain, 1, 1);
+	dprintk(VIDC_DBG, "Alloc done");
 	if (!alloc) {
-		HAL_MSG_HIGH("Alloc fail in %s", __func__);
-		return -ENOMEM;
-	} else {
-		HAL_MSG_MEDIUM("vidc_hal_alloc:ptr=%p,size=%d",
-					   alloc->kvaddr, size);
-		vmem->mem_size = alloc->size;
-		vmem->mem_data = alloc;
-		vmem->align_virtual_addr = (u8 *) alloc->kvaddr;
-		vmem->align_device_addr = (u8 *)alloc->device_addr;
+		dprintk(VIDC_ERR, "Alloc failed\n");
+		rc = -ENOMEM;
+		goto fail_smem_alloc;
 	}
-	return 0;
+	rc = msm_smem_clean_invalidate(clnt, alloc);
+	if (rc) {
+		dprintk(VIDC_ERR, "NOTE: Failed to clean caches\n");
+		goto fail_clean_cache;
+	}
+	dprintk(VIDC_DBG, "vidc_hal_alloc:ptr=%p,size=%d",
+			alloc->kvaddr, size);
+	vmem->mem_size = alloc->size;
+	vmem->mem_data = alloc;
+	vmem->align_virtual_addr = (u8 *) alloc->kvaddr;
+	vmem->align_device_addr = (u8 *)alloc->device_addr;
+	return rc;
+fail_clean_cache:
+	msm_smem_free(clnt, alloc);
+fail_smem_alloc:
+	return rc;
 }
 
 static void vidc_hal_free(struct smem_client *clnt, struct msm_smem *mem)
@@ -360,7 +369,7 @@
 	}
 
 	hwiosymaddr = ((u32)base_addr + (hwiosymaddr));
-	HAL_MSG_LOW("Base addr: 0x%x, written to: 0x%x, Value: 0x%x...",
+	dprintk(VIDC_DBG, "Base addr: 0x%x, written to: 0x%x, Value: 0x%x...",
 			(u32)base_addr, hwiosymaddr, value);
 	writel_relaxed(value, hwiosymaddr);
 	wmb();
@@ -380,14 +389,14 @@
 	int result = -EPERM;
 
 	if (!device || !pkt) {
-		HAL_MSG_ERROR("Invalid Params in %s", __func__);
+		dprintk(VIDC_ERR, "Invalid Params in ");
 		return -EINVAL;
 	}
 
 	spin_lock(&device->write_lock);
 	q_info = &device->iface_queues[VIDC_IFACEQ_CMDQ_IDX];
 	if (!q_info) {
-		HAL_MSG_ERROR("cannot write to shared Q's");
+		dprintk(VIDC_ERR, "cannot write to shared Q's");
 		goto err_q_write;
 	}
 
@@ -398,7 +407,7 @@
 				1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT, 0);
 		result = 0;
 	} else {
-		HAL_MSG_ERROR("vidc_hal_iface_cmdq_write:queue_full");
+		dprintk(VIDC_ERR, "vidc_hal_iface_cmdq_write:queue_full");
 	}
 err_q_write:
 	spin_unlock(&device->write_lock);
@@ -412,13 +421,13 @@
 	struct vidc_iface_q_info *q_info;
 
 	if (!pkt) {
-		HAL_MSG_ERROR("Invalid Params in %s", __func__);
+		dprintk(VIDC_ERR, "Invalid Params in ");
 		return -EINVAL;
 	}
 	spin_lock(&device->read_lock);
 	if (device->iface_queues[VIDC_IFACEQ_MSGQ_IDX].
 		q_array.align_virtual_addr == 0) {
-		HAL_MSG_ERROR("cannot read from shared MSG Q's");
+		dprintk(VIDC_ERR, "cannot read from shared MSG Q's");
 		rc = -ENODATA;
 		goto read_error;
 	}
@@ -431,7 +440,7 @@
 				1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT, 0);
 		rc = 0;
 	} else {
-		HAL_MSG_ERROR("vidc_hal_iface_msgq_read:queue_empty");
+		dprintk(VIDC_INFO, "vidc_hal_iface_msgq_read:queue_empty");
 		rc = -ENODATA;
 	}
 read_error:
@@ -446,13 +455,13 @@
 	struct vidc_iface_q_info *q_info;
 
 	if (!pkt) {
-		HAL_MSG_ERROR("Invalid Params in %s", __func__);
+		dprintk(VIDC_ERR, "Invalid Params in ");
 		return -EINVAL;
 	}
 	spin_lock(&device->read_lock);
 	if (device->iface_queues[VIDC_IFACEQ_DBGQ_IDX].
 		q_array.align_virtual_addr == 0) {
-		HAL_MSG_ERROR("cannot read from shared DBG Q's");
+		dprintk(VIDC_ERR, "cannot read from shared DBG Q's");
 		rc = -ENODATA;
 		goto dbg_error;
 	}
@@ -464,7 +473,7 @@
 			1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT, 0);
 		rc = 0;
 	} else {
-		HAL_MSG_MEDIUM("vidc_hal_iface_dbgq_read:queue_empty");
+		dprintk(VIDC_INFO, "vidc_hal_iface_dbgq_read:queue_empty");
 		rc = -ENODATA;
 	}
 dbg_error:
@@ -476,7 +485,7 @@
 {
 	q_hdr->qhdr_status = 0x1;
 	q_hdr->qhdr_type = VIDC_IFACEQ_DFLT_QHDR;
-	q_hdr->qhdr_q_size = VIDC_IFACEQ_QUEUE_SIZE;
+	q_hdr->qhdr_q_size = VIDC_IFACEQ_QUEUE_SIZE / 4;
 	q_hdr->qhdr_pkt_size = 0;
 	q_hdr->qhdr_rx_wm = 0x1;
 	q_hdr->qhdr_tx_wm = 0x1;
@@ -517,9 +526,9 @@
 
 	rc = vidc_hal_alloc((void *) &dev->iface_q_table,
 					dev->hal_client,
-			VIDC_IFACEQ_TABLE_SIZE, 1, 0, domain);
+			VIDC_IFACEQ_TABLE_SIZE, 1, SMEM_UNCACHED, domain);
 	if (rc) {
-		HAL_MSG_ERROR("%s:iface_q_table_alloc_fail", __func__);
+		dprintk(VIDC_ERR, "iface_q_table_alloc_fail");
 		return -ENOMEM;
 	}
 	q_tbl_hdr = (struct hfi_queue_table_header *)
@@ -537,10 +546,9 @@
 		iface_q = &dev->iface_queues[i];
 		rc = vidc_hal_alloc((void *) &iface_q->q_array,
 				dev->hal_client, VIDC_IFACEQ_QUEUE_SIZE,
-				1, 0, domain);
+				1, SMEM_UNCACHED, domain);
 		if (rc) {
-			HAL_MSG_ERROR("%s:iface_q_table_alloc[%d]_fail",
-						__func__, i);
+			dprintk(VIDC_ERR, "iface_q_table_alloc[%d]_fail", i);
 			vidc_hal_interface_queues_release(dev);
 			return -ENOMEM;
 		} else {
@@ -581,22 +589,55 @@
 static int vidc_hal_core_start_cpu(struct hal_device *device)
 {
 	u32 ctrl_status = 0, count = 0, rc = 0;
+	int max_tries = 100;
 	write_register(device->hal_data->register_base_addr,
 			VIDC_WRAPPER_INTR_MASK, 0, 0);
 	write_register(device->hal_data->register_base_addr,
 			VIDC_CPU_CS_SCIACMDARG3, 1, 0);
-	while (!ctrl_status && count < 25) {
+	while (!ctrl_status && count < max_tries) {
 		ctrl_status = read_register(
 		device->hal_data->register_base_addr,
 		VIDC_CPU_CS_SCIACMDARG0);
 		usleep_range(500, 1000);
 		count++;
 	}
-	if (count >= 25)
+	if (count >= max_tries)
 		rc = -ETIME;
 	return rc;
 }
 
+static void set_vbif_registers(struct hal_device *device)
+{
+	write_register(device->hal_data->register_base_addr,
+			VIDC_VBIF_OUT_AXI_AOOO_EN, 0x00000FFF, 0);
+	write_register(device->hal_data->register_base_addr,
+			VIDC_VBIF_OUT_AXI_AOOO, 0x0FFF0FFF, 0);
+	write_register(device->hal_data->register_base_addr,
+			VIDC_VENUS_VBIF_CLK_ON, 1, 0);
+	write_register(device->hal_data->register_base_addr,
+			VIDC_VBIF_IN_RD_LIM_CONF0, 0x10101001, 0);
+	write_register(device->hal_data->register_base_addr,
+			VIDC_VBIF_IN_RD_LIM_CONF1, 0x10101010, 0);
+	write_register(device->hal_data->register_base_addr,
+			VIDC_VBIF_IN_RD_LIM_CONF2, 0x10101010, 0);
+	write_register(device->hal_data->register_base_addr,
+			VIDC_VBIF_IN_RD_LIM_CONF3, 0x00000010, 0);
+	write_register(device->hal_data->register_base_addr,
+			VIDC_VBIF_IN_WR_LIM_CONF0, 0x1010100f, 0);
+	write_register(device->hal_data->register_base_addr,
+			VIDC_VBIF_IN_WR_LIM_CONF1, 0x10101010, 0);
+	write_register(device->hal_data->register_base_addr,
+			VIDC_VBIF_IN_WR_LIM_CONF2, 0x10101010, 0);
+	write_register(device->hal_data->register_base_addr,
+			VIDC_VBIF_IN_WR_LIM_CONF3, 0x00000010, 0);
+	write_register(device->hal_data->register_base_addr,
+			VIDC_VBIF_OUT_RD_LIM_CONF0, 0x00001010, 0);
+	write_register(device->hal_data->register_base_addr,
+			VIDC_VBIF_OUT_WR_LIM_CONF0, 0x00001010, 0);
+	write_register(device->hal_data->register_base_addr,
+			VIDC_VBIF_ARB_CTL, 0x00000030, 0);
+}
+
 int vidc_hal_core_init(void *device, int domain)
 {
 	struct hfi_cmd_sys_init_packet pkt;
@@ -606,7 +647,7 @@
 	if (device) {
 		dev = device;
 	} else {
-		HAL_MSG_ERROR("%s:invalid device", __func__);
+		dprintk(VIDC_ERR, "Invalid device");
 		return -ENODEV;
 	}
 	enable_irq(dev->hal_data->irq);
@@ -614,33 +655,37 @@
 	spin_lock_init(&dev->read_lock);
 	spin_lock_init(&dev->write_lock);
 
+	/*Disable Dynamic clock gating for Venus VBIF*/
+	write_register(dev->hal_data->register_base_addr,
+				   VIDC_VENUS_VBIF_CLK_ON, 1, 0);
+	set_vbif_registers(dev);
 	if (!dev->hal_client) {
 		dev->hal_client = msm_smem_new_client(SMEM_ION);
 		if (dev->hal_client == NULL) {
-			HAL_MSG_ERROR("Failed to alloc ION_Client");
+			dprintk(VIDC_ERR, "Failed to alloc ION_Client");
 			rc = -ENODEV;
 			goto err_no_mem;
 		}
 
-		HAL_MSG_ERROR("Device_Virt_Address : 0x%x,"
+		dprintk(VIDC_DBG, "Device_Virt_Address : 0x%x,"
 		"Register_Virt_Addr: 0x%x",
 		dev->hal_data->device_base_addr,
 		(u32) dev->hal_data->register_base_addr);
 
 		rc = vidc_hal_interface_queues_init(dev, domain);
 		if (rc) {
-			HAL_MSG_ERROR("failed to init queues");
+			dprintk(VIDC_ERR, "failed to init queues");
 			rc = -ENOMEM;
 			goto err_no_mem;
 		}
 	} else {
-		HAL_MSG_ERROR("hal_client exists");
+		dprintk(VIDC_ERR, "hal_client exists");
 		rc = -EEXIST;
 		goto err_no_mem;
 	}
 	rc = vidc_hal_core_start_cpu(dev);
 	if (rc) {
-		HAL_MSG_ERROR("Failed to start core");
+		dprintk(VIDC_ERR, "Failed to start core");
 		rc = -ENODEV;
 		goto err_no_dev;
 	}
@@ -665,14 +710,14 @@
 	if (device) {
 		dev = device;
 	} else {
-		HAL_MSG_ERROR("%s:invalid device", __func__);
+		dprintk(VIDC_ERR, "invalid device");
 		return -ENODEV;
 	}
 	write_register(dev->hal_data->register_base_addr,
 		VIDC_CPU_CS_SCIACMDARG3, 0, 0);
 	disable_irq_nosync(dev->hal_data->irq);
 	vidc_hal_interface_queues_release(dev);
-	HAL_MSG_INFO("\nHAL exited\n");
+	dprintk(VIDC_INFO, "HAL exited\n");
 	return 0;
 }
 
@@ -685,7 +730,7 @@
 	if (device) {
 		dev = device;
 	} else {
-		HAL_MSG_ERROR("%s:invalid device", __func__);
+		dprintk(VIDC_ERR, "invalid device");
 		return -ENODEV;
 	}
 	pkt.size = sizeof(struct hfi_cmd_sys_pc_prep_packet);
@@ -709,11 +754,11 @@
 	if ((intr_status & VIDC_WRAPPER_INTR_STATUS_A2H_BMSK) ||
 		(intr_status & VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK)) {
 		device->intr_status |= intr_status;
-		HAL_MSG_ERROR("INTERRUPT for device: 0x%x: "
+		dprintk(VIDC_DBG, "INTERRUPT for device: 0x%x: "
 			"times: %d interrupt_status: %d",
 			(u32) device, ++device->reg_count, intr_status);
 	} else {
-		HAL_MSG_ERROR("SPURIOUS_INTR for device: 0x%x: "
+		dprintk(VIDC_WARN, "SPURIOUS_INTR for device: 0x%x: "
 			"times: %d interrupt_status: %d",
 			(u32) device, ++device->spur_count, intr_status);
 	}
@@ -721,7 +766,7 @@
 			VIDC_CPU_CS_A2HSOFTINTCLR, 1, 0);
 	write_register(device->hal_data->register_base_addr,
 			VIDC_WRAPPER_INTR_CLEAR, intr_status, 0);
-	HAL_MSG_ERROR("Cleared WRAPPER/A2H interrupt");
+	dprintk(VIDC_DBG, "Cleared WRAPPER/A2H interrupt");
 }
 
 int vidc_hal_core_set_resource(void *device,
@@ -733,7 +778,7 @@
 	struct hal_device *dev;
 
 	if (!device || !resource_hdr || !resource_value) {
-		HAL_MSG_ERROR("Invalid Params in %s", __func__);
+		dprintk(VIDC_ERR, "set_res: Invalid Params");
 		return -EINVAL;
 	} else {
 		dev = device;
@@ -763,8 +808,8 @@
 		break;
 	}
 	default:
-		HAL_MSG_INFO("In %s called for resource %d",
-					 __func__, resource_hdr->resource_id);
+		dprintk(VIDC_INFO, "Invalid res_id in set_res %d",
+						resource_hdr->resource_id);
 		break;
 	}
 	return rc;
@@ -778,7 +823,7 @@
 	struct hal_device *dev;
 
 	if (!device || !resource_hdr) {
-		HAL_MSG_ERROR("Invalid Params in %s", __func__);
+		dprintk(VIDC_ERR, "Inv-Params in rel_res");
 		return -EINVAL;
 	} else {
 		dev = device;
@@ -803,7 +848,7 @@
 	if (device) {
 		dev = device;
 	} else {
-		HAL_MSG_ERROR("%s:invalid device", __func__);
+		dprintk(VIDC_ERR, "invalid device");
 		return -ENODEV;
 	}
 	pkt.size = sizeof(struct hfi_cmd_sys_ping_packet);
@@ -842,7 +887,8 @@
 		buffer = HFI_BUFFER_INTERNAL_PERSIST;
 		break;
 	default:
-		HAL_MSG_ERROR("Invalid buffer type : 0x%x\n", hal_buffer);
+		dprintk(VIDC_ERR, "Invalid buffer :0x%x\n",
+				hal_buffer);
 		buffer = 0;
 		break;
 	}
@@ -857,13 +903,13 @@
 	struct hal_session *session;
 
 	if (!sess || !pdata) {
-		HAL_MSG_ERROR("Invalid Params in %s", __func__);
+		dprintk(VIDC_ERR, "Invalid Params");
 		return -EINVAL;
 	} else {
 		session = sess;
 	}
 
-	HAL_MSG_INFO("IN func: %s, with property id: %d", __func__, ptype);
+	dprintk(VIDC_INFO, "in set_prop,with prop id: 0x%x", ptype);
 	pkt->size = sizeof(struct hfi_cmd_session_set_property_packet);
 	pkt->packet_type = HFI_CMD_SESSION_SET_PROPERTY;
 	pkt->session_id = (u32) session;
@@ -965,7 +1011,7 @@
 			(struct hal_nal_stream_format_supported *)pdata;
 		pkt->rg_property_data[0] =
 			HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SELECT;
-		HAL_MSG_ERROR("\ndata is :%d",
+		dprintk(VIDC_DBG, "data is :%d",
 				prop->nal_stream_format_supported);
 		switch (prop->nal_stream_format_supported) {
 		case HAL_NAL_FORMAT_STARTCODES:
@@ -989,7 +1035,7 @@
 				HFI_NAL_FORMAT_FOUR_BYTE_LENGTH;
 			break;
 		default:
-			HAL_MSG_ERROR("Invalid nal format: 0x%x",
+			dprintk(VIDC_ERR, "Invalid nal format: 0x%x",
 				  prop->nal_stream_format_supported);
 			break;
 		}
@@ -1009,7 +1055,7 @@
 			pkt->rg_property_data[1] = HFI_OUTPUT_ORDER_DISPLAY;
 			break;
 		default:
-			HAL_MSG_ERROR("invalid output order: 0x%x",
+			dprintk(VIDC_ERR, "invalid output order: 0x%x",
 						  *data);
 			break;
 		}
@@ -1096,7 +1142,7 @@
 			pkt->rg_property_data[1] = HFI_DIVX_FORMAT_6;
 			break;
 		default:
-			HAL_MSG_ERROR("Invalid divx format: 0x%x", *data);
+			dprintk(VIDC_ERR, "Invalid divx format: 0x%x", *data);
 			break;
 		}
 		pkt->size += sizeof(u32) * 2;
@@ -1185,13 +1231,15 @@
 				hfi->cabac_model = HFI_H264_CABAC_MODEL_2;
 				break;
 			default:
-				HAL_MSG_ERROR("Invalid cabac model 0x%x",
-							  prop->entropy_mode);
+				dprintk(VIDC_ERR,
+					"Invalid cabac model 0x%x",
+					prop->entropy_mode);
 				break;
 			}
 		break;
 		default:
-			HAL_MSG_ERROR("Invalid entropy selected: 0x%x",
+			dprintk(VIDC_ERR,
+				"Invalid entropy selected: 0x%x",
 				prop->cabac_model);
 			break;
 		}
@@ -1201,9 +1249,11 @@
 	}
 	case HAL_PARAM_VENC_RATE_CONTROL:
 	{
+		u32 *rc;
 		pkt->rg_property_data[0] =
 			HFI_PROPERTY_PARAM_VENC_RATE_CONTROL;
-		switch ((enum hal_rate_control)pdata) {
+		rc = (u32 *)pdata;
+		switch ((enum hal_rate_control) *rc) {
 		case HAL_RATE_CONTROL_OFF:
 		pkt->rg_property_data[1] = HFI_RATE_CONTROL_OFF;
 			break;
@@ -1220,7 +1270,7 @@
 		pkt->rg_property_data[1] = HFI_RATE_CONTROL_VBR_VFR;
 			break;
 		default:
-			HAL_MSG_ERROR("Invalid Rate control setting: 0x%x",
+			dprintk(VIDC_ERR, "Invalid Rate control setting: 0x%x",
 						  (int) pdata);
 			break;
 		}
@@ -1270,7 +1320,7 @@
 			hfi->mode = HFI_H264_DB_MODE_ALL_BOUNDARY;
 			break;
 		default:
-			HAL_MSG_ERROR("Invalid deblocking mode: 0x%x",
+			dprintk(VIDC_ERR, "Invalid deblocking mode: 0x%x",
 						  prop->mode);
 			break;
 		}
@@ -1338,7 +1388,7 @@
 			hfi->mode = HFI_INTRA_REFRESH_RANDOM;
 			break;
 		default:
-			HAL_MSG_ERROR("Invalid intra refresh setting: 0x%x",
+			dprintk(VIDC_ERR, "Invalid intra refresh setting: 0x%x",
 				prop->mode);
 			break;
 		}
@@ -1371,7 +1421,7 @@
 			hfi->multi_slice = HFI_MULTI_SLICE_BY_BYTE_COUNT;
 			break;
 		default:
-			HAL_MSG_ERROR("Invalid slice settings: 0x%x",
+			dprintk(VIDC_ERR, "Invalid slice settings: 0x%x",
 				prop->multi_slice);
 			break;
 		}
@@ -1421,7 +1471,7 @@
 	case HAL_CONFIG_VENC_TIMESTAMP_SCALE:
 	case HAL_PARAM_VENC_LOW_LATENCY:
 	default:
-		HAL_MSG_INFO("DEFAULT: Calling 0x%x", ptype);
+		dprintk(VIDC_INFO, "DEFAULT: Calling 0x%x", ptype);
 		break;
 	}
 	if (vidc_hal_iface_cmdq_write(session->device, pkt))
@@ -1435,12 +1485,12 @@
 	struct hal_session *session;
 
 	if (!sess || !pdata) {
-		HAL_MSG_ERROR("Invalid Params in %s", __func__);
+		dprintk(VIDC_ERR, "Invalid Params in ");
 		return -EINVAL;
 	} else {
 		session = sess;
 	}
-	HAL_MSG_INFO("IN func: %s, with property id: %d", __func__, ptype);
+	dprintk(VIDC_INFO, "IN func: , with property id: %d", ptype);
 
 	switch (ptype) {
 	case HAL_CONFIG_FRAME_RATE:
@@ -1546,7 +1596,7 @@
 	case HAL_CONFIG_VENC_TIMESTAMP_SCALE:
 	case HAL_PARAM_VENC_LOW_LATENCY:
 	default:
-		HAL_MSG_INFO("DEFAULT: Calling 0x%x", ptype);
+		dprintk(VIDC_INFO, "DEFAULT: Calling 0x%x", ptype);
 		break;
 	}
 	return 0;
@@ -1562,7 +1612,7 @@
 	if (device) {
 		dev = device;
 	} else {
-		HAL_MSG_ERROR("%s:invalid device", __func__);
+		dprintk(VIDC_ERR, ":invalid device");
 		return NULL;
 	}
 
@@ -1595,7 +1645,7 @@
 	if (session_id) {
 		session = session_id;
 	} else {
-		HAL_MSG_ERROR("%s:invalid session", __func__);
+		dprintk(VIDC_ERR, ":invalid session");
 		return -ENODEV;
 	}
 
@@ -1631,7 +1681,7 @@
 	struct hal_session *session;
 
 	if (!sess || !buffer_info) {
-		HAL_MSG_ERROR("Invalid Params in %s", __func__);
+		dprintk(VIDC_ERR, "Invalid Params in ");
 		return -EINVAL;
 	} else {
 		session = sess;
@@ -1678,7 +1728,7 @@
 		pkt->buffer_type = buffer;
 	else
 		return -EINVAL;
-	HAL_MSG_INFO("set buffers: 0x%x", buffer_info->buffer_type);
+	dprintk(VIDC_INFO, "set buffers: 0x%x", buffer_info->buffer_type);
 	if (vidc_hal_iface_cmdq_write(session->device, pkt))
 		rc = -ENOTEMPTY;
 	return rc;
@@ -1695,7 +1745,7 @@
 	struct hal_session *session;
 
 	if (!sess || !buffer_info) {
-		HAL_MSG_ERROR("Invalid Params in %s", __func__);
+		dprintk(VIDC_ERR, "Invalid Params in ");
 		return -EINVAL;
 	} else {
 		session = sess;
@@ -1739,7 +1789,7 @@
 		pkt->buffer_type = buffer;
 	else
 		return -EINVAL;
-	HAL_MSG_INFO("Release buffers: 0x%x", buffer_info->buffer_type);
+	dprintk(VIDC_INFO, "Release buffers: 0x%x", buffer_info->buffer_type);
 	if (vidc_hal_iface_cmdq_write(session->device, pkt))
 		rc = -ENOTEMPTY;
 	return rc;
@@ -1787,7 +1837,7 @@
 	struct hal_session *session;
 
 	if (!sess || !input_frame) {
-		HAL_MSG_ERROR("Invalid Params in %s", __func__);
+		dprintk(VIDC_ERR, "Invalid Params in ");
 		return -EINVAL;
 	} else {
 		session = sess;
@@ -1809,7 +1859,7 @@
 		pkt.filled_len = input_frame->filled_len;
 		pkt.input_tag = input_frame->clnt_data;
 		pkt.packet_buffer = (u8 *) input_frame->device_addr;
-		HAL_MSG_ERROR("### Q DECODER INPUT BUFFER ###");
+		dprintk(VIDC_DBG, "Q DECODER INPUT BUFFER");
 		if (vidc_hal_iface_cmdq_write(session->device, &pkt))
 			rc = -ENOTEMPTY;
 	} else {
@@ -1830,7 +1880,7 @@
 		pkt.filled_len = input_frame->filled_len;
 		pkt.input_tag = input_frame->clnt_data;
 		pkt.packet_buffer = (u8 *) input_frame->device_addr;
-		HAL_MSG_ERROR("### Q ENCODER INPUT BUFFER ###");
+		dprintk(VIDC_DBG, "Q ENCODER INPUT BUFFER");
 		if (vidc_hal_iface_cmdq_write(session->device, &pkt))
 			rc = -ENOTEMPTY;
 	}
@@ -1845,7 +1895,7 @@
 	struct hal_session *session;
 
 	if (!sess || !output_frame) {
-		HAL_MSG_ERROR("Invalid Params in %s", __func__);
+		dprintk(VIDC_ERR, "Invalid Params in ");
 		return -EINVAL;
 	} else {
 		session = sess;
@@ -1862,7 +1912,7 @@
 	pkt.extra_data_buffer =
 		(u8 *) output_frame->extradata_addr;
 
-	HAL_MSG_INFO("### Q OUTPUT BUFFER ###");
+	dprintk(VIDC_INFO, "### Q OUTPUT BUFFER ###");
 	if (vidc_hal_iface_cmdq_write(session->device, &pkt))
 		rc = -ENOTEMPTY;
 	return rc;
@@ -1877,7 +1927,7 @@
 	struct hal_session *session;
 
 	if (!sess || !seq_hdr) {
-		HAL_MSG_ERROR("Invalid Params in %s", __func__);
+		dprintk(VIDC_ERR, "Invalid Params in ");
 		return -EINVAL;
 	} else {
 		session = sess;
@@ -1904,7 +1954,7 @@
 	struct hal_session *session;
 
 	if (!sess || !seq_hdr) {
-		HAL_MSG_ERROR("Invalid Params in %s", __func__);
+		dprintk(VIDC_ERR, "Invalid Params in ");
 		return -EINVAL;
 	} else {
 		session = sess;
@@ -1931,7 +1981,7 @@
 	if (sess) {
 		session = sess;
 	} else {
-		HAL_MSG_ERROR("%s:invalid session", __func__);
+		dprintk(VIDC_ERR, ":invalid session");
 		return -ENODEV;
 	}
 
@@ -1954,7 +2004,7 @@
 	if (sess) {
 		session = sess;
 	} else {
-		HAL_MSG_ERROR("%s:invalid session", __func__);
+		dprintk(VIDC_ERR, ":invalid session");
 		return -ENODEV;
 	}
 
@@ -1975,7 +2025,7 @@
 		pkt.flush_type = HFI_FLUSH_ALL;
 		break;
 	default:
-		HAL_MSG_ERROR("Invalid flush mode: 0x%x\n", flush_mode);
+		dprintk(VIDC_ERR, "Invalid flush mode: 0x%x\n", flush_mode);
 		break;
 	}
 	if (vidc_hal_iface_cmdq_write(session->device, &pkt))
@@ -2022,12 +2072,12 @@
 						FIRMWARE_SIZE))) {
 				return 0;
 			} else {
-				HAL_MSG_INFO("Device not registered");
+				dprintk(VIDC_INFO, "Device not registered");
 				return -EINVAL;
 			}
 		}
 	} else {
-		HAL_MSG_INFO("no device Registered");
+		dprintk(VIDC_INFO, "no device Registered");
 	}
 	return -EINVAL;
 }
@@ -2037,9 +2087,9 @@
 	struct hal_device *device = list_first_entry(
 		&hal_ctxt.dev_head, struct hal_device, list);
 
-	HAL_MSG_INFO(" GOT INTERRUPT %s() ", __func__);
+	dprintk(VIDC_INFO, " GOT INTERRUPT () ");
 	if (!device->callback) {
-		HAL_MSG_ERROR("No callback function	"
+		dprintk(VIDC_ERR, "No callback function	"
 					  "to process interrupt: %p\n", device);
 		return;
 	}
@@ -2052,10 +2102,10 @@
 static irqreturn_t vidc_hal_isr(int irq, void *dev)
 {
 	struct hal_device *device = dev;
-	HAL_MSG_MEDIUM("\n vidc_hal_isr() %d ", irq);
+	dprintk(VIDC_INFO, "vidc_hal_isr() %d ", irq);
 	disable_irq_nosync(irq);
 	queue_work(device->vidc_workq, &vidc_hal_work);
-	HAL_MSG_MEDIUM("\n vidc_hal_isr() %d ", irq);
+	dprintk(VIDC_INFO, "vidc_hal_isr() %d ", irq);
 	return IRQ_HANDLED;
 }
 
@@ -2069,19 +2119,19 @@
 
 	if (device_id || !reg_base || !reg_size ||
 			!irq || !callback) {
-		HAL_MSG_ERROR("Invalid Paramters");
+		dprintk(VIDC_ERR, "Invalid Paramters");
 		return NULL;
 	} else {
-		HAL_MSG_INFO("entered %s, device_id: %d", __func__, device_id);
+		dprintk(VIDC_INFO, "entered , device_id: %d", device_id);
 	}
 
 	if (vidc_hal_check_core_registered(hal_ctxt, fw_base_addr,
 						reg_base, reg_size, irq)) {
-		HAL_MSG_LOW("HAL_DATA will be assigned now");
+		dprintk(VIDC_DBG, "HAL_DATA will be assigned now");
 		hal = (struct hal_data *)
 			kzalloc(sizeof(struct hal_data), GFP_KERNEL);
 		if (!hal) {
-			HAL_MSG_ERROR("Failed to alloc");
+			dprintk(VIDC_ERR, "Failed to alloc");
 			return NULL;
 		}
 		hal->irq = irq;
@@ -2089,20 +2139,21 @@
 		hal->register_base_addr =
 			ioremap_nocache(reg_base, reg_size);
 		if (!hal->register_base_addr) {
-			HAL_MSG_ERROR("could not map reg addr %d of size %d",
-						  reg_base, reg_size);
+			dprintk(VIDC_ERR,
+				"could not map reg addr %d of size %d",
+				reg_base, reg_size);
 			goto err_map;
 		}
 		INIT_LIST_HEAD(&hal_ctxt.dev_head);
 	} else {
-		HAL_MSG_ERROR("Core present/Already added");
+		dprintk(VIDC_ERR, "Core present/Already added");
 		return NULL;
 	}
 
 	hdevice = (struct hal_device *)
 			kzalloc(sizeof(struct hal_device), GFP_KERNEL);
 	if (!hdevice) {
-		HAL_MSG_ERROR("failed to allocate new device");
+		dprintk(VIDC_ERR, "failed to allocate new device");
 		goto err_map;
 	}
 
@@ -2116,14 +2167,14 @@
 	hdevice->vidc_workq = create_singlethread_workqueue(
 		"msm_vidc_workerq");
 	if (!hdevice->vidc_workq) {
-		HAL_MSG_ERROR("%s: create workq failed\n", __func__);
+		dprintk(VIDC_ERR, ": create workq failed\n");
 		goto error_createq;
 	}
 
 	rc = request_irq(irq, vidc_hal_isr, IRQF_TRIGGER_HIGH,
 			"msm_vidc", hdevice);
 	if (unlikely(rc)) {
-		HAL_MSG_ERROR("%s() :request_irq failed\n", __func__);
+		dprintk(VIDC_ERR, "() :request_irq failed\n");
 		goto error_irq_fail;
 	}
 	disable_irq_nosync(irq);
diff --git a/drivers/media/video/msm_vidc/vidc_hal.h b/drivers/media/video/msm_vidc/vidc_hal.h
index 8e7c3d3..c586172 100644
--- a/drivers/media/video/msm_vidc/vidc_hal.h
+++ b/drivers/media/video/msm_vidc/vidc_hal.h
@@ -20,20 +20,6 @@
 #include "msm_smem.h"
 #include "vidc_hal_helper.h"
 
-#ifdef HAL_MSG_LOG
-#define HAL_MSG_LOW(x...)		pr_info(KERN_INFO x)
-#define HAL_MSG_MEDIUM(x...)	pr_info(KERN_INFO x)
-#define HAL_MSG_HIGH(x...)		pr_info(KERN_INFO x)
-#else
-#define HAL_MSG_LOW(x...)
-#define HAL_MSG_MEDIUM(x...)
-#define HAL_MSG_HIGH(x...)
-#endif
-
-#define HAL_MSG_ERROR(x...)		pr_err(KERN_INFO x)
-#define HAL_MSG_FATAL(x...)		pr_err(KERN_INFO x)
-#define HAL_MSG_INFO(x...)		pr_info(KERN_INFO x)
-
 #define HFI_MASK_QHDR_TX_TYPE			0xFF000000
 #define HFI_MASK_QHDR_RX_TYPE			0x00FF0000
 #define HFI_MASK_QHDR_PRI_TYPE			0x0000FF00
diff --git a/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c b/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c
index 364faa9..795024d 100644
--- a/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c
+++ b/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c
@@ -14,6 +14,7 @@
 #include <linux/slab.h>
 #include <linux/list.h>
 #include "vidc_hal.h"
+#include "msm_vidc_debug.h"
 
 static enum vidc_status vidc_map_hal_err_status(int hfi_err)
 {
@@ -81,10 +82,10 @@
 	struct hfi_frame_size frame_sz;
 	u8 *data_ptr;
 	int prop_id;
-	HAL_MSG_LOW("RECEIVED:EVENT_NOTIFY");
+	dprintk(VIDC_DBG, "RECEIVED:EVENT_NOTIFY");
 	if (sizeof(struct hfi_msg_event_notify_packet)
 		> pkt->size) {
-		HAL_MSG_ERROR("hal_process_session_init_done:bad_pkt_size");
+		dprintk(VIDC_ERR, "hal_process_session_init_done:bad_pkt_size");
 		return;
 	}
 
@@ -139,30 +140,30 @@
 static void hal_process_event_notify(struct hal_device *device,
 	struct hfi_msg_event_notify_packet *pkt)
 {
-	HAL_MSG_LOW("RECVD:EVENT_NOTIFY");
+	dprintk(VIDC_DBG, "RECVD:EVENT_NOTIFY");
 
 	if (!device || !pkt ||
 		pkt->size < sizeof(struct hfi_msg_event_notify_packet)) {
-		HAL_MSG_ERROR("Invalid Params in %s", __func__);
+		dprintk(VIDC_ERR, "Invalid Params");
 		return;
 	}
 
 	switch (pkt->event_id) {
 	case HFI_EVENT_SYS_ERROR:
-		HAL_MSG_INFO("HFI_EVENT_SYS_ERROR");
+		dprintk(VIDC_INFO, "HFI_EVENT_SYS_ERROR");
 		break;
 	case HFI_EVENT_SESSION_ERROR:
-		HAL_MSG_INFO("HFI_EVENT_SESSION_ERROR");
+		dprintk(VIDC_INFO, "HFI_EVENT_SESSION_ERROR");
 		break;
 	case HFI_EVENT_SESSION_SEQUENCE_CHANGED:
-		HAL_MSG_INFO("HFI_EVENT_SESSION_SEQUENCE_CHANGED");
+		dprintk(VIDC_INFO, "HFI_EVENT_SESSION_SEQUENCE_CHANGED");
 		hal_process_sess_evt_seq_changed(device, pkt);
 		break;
 	case HFI_EVENT_SESSION_PROPERTY_CHANGED:
-		HAL_MSG_INFO("HFI_EVENT_SESSION_PROPERTY_CHANGED");
+		dprintk(VIDC_INFO, "HFI_EVENT_SESSION_PROPERTY_CHANGED");
 		break;
 	default:
-		HAL_MSG_INFO("hal_process_event_notify:unkown_event_id");
+		dprintk(VIDC_INFO, "hal_process_event_notify:unkown_event_id");
 		break;
 	}
 }
@@ -177,9 +178,9 @@
 	int prop_id;
 	enum vidc_status status = VIDC_ERR_NONE;
 
-	HAL_MSG_LOW("RECEIVED:SYS_INIT_DONE");
+	dprintk(VIDC_DBG, "RECEIVED:SYS_INIT_DONE");
 	if (sizeof(struct hfi_msg_sys_init_done_packet) > pkt->size) {
-		HAL_MSG_ERROR("hal_process_sys_init_done:bad_pkt_size: %d",
+		dprintk(VIDC_ERR, "hal_process_sys_init_done:bad_pkt_size: %d",
 				pkt->size);
 		return;
 	}
@@ -188,7 +189,7 @@
 
 	if (!status) {
 		if (pkt->num_properties == 0) {
-			HAL_MSG_ERROR("hal_process_sys_init_done:"
+			dprintk(VIDC_ERR, "hal_process_sys_init_done:"
 						"no_properties");
 			status = VIDC_ERR_FAIL;
 			goto err_no_prop;
@@ -198,7 +199,7 @@
 			hfi_msg_sys_init_done_packet) + sizeof(u32);
 
 		if (rem_bytes == 0) {
-			HAL_MSG_ERROR("hal_process_sys_init_done:"
+			dprintk(VIDC_ERR, "hal_process_sys_init_done:"
 						"missing_prop_info");
 			status = VIDC_ERR_FAIL;
 			goto err_no_prop;
@@ -231,7 +232,7 @@
 				break;
 			}
 			default:
-				HAL_MSG_ERROR("hal_process_sys_init_done:"
+				dprintk(VIDC_ERR, "hal_process_sys_init_done:"
 							"bad_prop_id");
 				status = VIDC_ERR_BAD_PARAM;
 				break;
@@ -259,11 +260,12 @@
 	enum vidc_status status = VIDC_ERR_NONE;
 	u32 pkt_size;
 	memset(&cmd_done, 0, sizeof(struct msm_vidc_cb_cmd_done));
-	HAL_MSG_ERROR("RECEIVED:SYS_RELEASE_RESOURCE_DONE");
+	dprintk(VIDC_DBG, "RECEIVED:SYS_RELEASE_RESOURCE_DONE");
 	pkt_size = sizeof(struct hfi_msg_sys_release_resource_done_packet);
 	if (pkt_size > pkt->size) {
-		HAL_MSG_ERROR("hal_process_sys_rel_resource_done:bad size:%d",
-				pkt->size);
+		dprintk(VIDC_ERR,
+			"hal_process_sys_rel_resource_done:bad size:%d",
+			pkt->size);
 		return;
 	}
 	status = vidc_map_hal_err_status((u32)pkt->error_type);
@@ -290,14 +292,15 @@
 	u32 req_bytes;
 	enum vidc_status rc = VIDC_ERR_NONE;
 
-	HAL_MSG_LOW("Entered %s", __func__);
+	dprintk(VIDC_DBG, "Entered ");
 	req_bytes = prop->size - sizeof(
 	struct hfi_msg_session_property_info_packet);
 
 	if (req_bytes == 0 || (req_bytes % sizeof(
 		struct hfi_buffer_requirements))) {
-		HAL_MSG_ERROR("hal_process_sess_get_prop_buf_req:bad_pkt_size:"
-					" %d", req_bytes);
+		dprintk(VIDC_ERR,
+			"hal_process_sess_get_prop_buf_req:bad_pkt_size: %d",
+			req_bytes);
 		return;
 	}
 
@@ -309,11 +312,11 @@
 			buffer_count_actual)
 			|| (hfi_buf_req->buffer_alignment == 0)
 			|| (hfi_buf_req->buffer_size == 0)) {
-			HAL_MSG_ERROR("hal_process_sess_get_prop_buf_req:"
+			dprintk(VIDC_ERR, "hal_process_sess_get_prop_buf_req:"
 						"bad_buf_req");
 			rc = VIDC_ERR_FAIL;
 		}
-		HAL_MSG_LOW("got buffer requirements for: %d",
+		dprintk(VIDC_DBG, "got buffer requirements for: %d",
 					hfi_buf_req->buffer_type);
 		switch (hfi_buf_req->buffer_type) {
 		case HFI_BUFFER_INPUT:
@@ -362,8 +365,9 @@
 				HAL_BUFFER_INTERNAL_PERSIST;
 			break;
 		default:
-			HAL_MSG_ERROR("%s: bad_buffer_type: %d",
-				__func__, hfi_buf_req->buffer_type);
+			dprintk(VIDC_ERR,
+			"hal_process_sess_get_prop_buf_req: bad_buffer_type: %d",
+			hfi_buf_req->buffer_type);
 			break;
 		}
 		req_bytes -= sizeof(struct hfi_buffer_requirements);
@@ -377,15 +381,16 @@
 	struct msm_vidc_cb_cmd_done cmd_done;
 	struct buffer_requirements buff_req;
 
-	HAL_MSG_INFO("Received SESSION_PROPERTY_INFO");
+	dprintk(VIDC_DBG, "Received SESSION_PROPERTY_INFO");
 
 	if (pkt->size < sizeof(struct hfi_msg_session_property_info_packet)) {
-		HAL_MSG_ERROR("hal_process_session_prop_info:bad_pkt_size");
+		dprintk(VIDC_ERR, "hal_process_session_prop_info:bad_pkt_size");
 		return;
 	}
 
 	if (pkt->num_properties == 0) {
-		HAL_MSG_ERROR("hal_process_session_prop_info:no_properties");
+		dprintk(VIDC_ERR,
+			"hal_process_session_prop_info:no_properties");
 		return;
 	}
 
@@ -404,7 +409,7 @@
 		device->callback(SESSION_PROPERTY_INFO, &cmd_done);
 		break;
 	default:
-		HAL_MSG_ERROR("hal_process_session_prop_info:"
+		dprintk(VIDC_ERR, "hal_process_session_prop_info:"
 					"unknown_prop_id: %d",
 				pkt->rg_property_data[0]);
 		break;
@@ -417,10 +422,10 @@
 	struct msm_vidc_cb_cmd_done cmd_done;
 	struct vidc_hal_session_init_done session_init_done;
 
-	HAL_MSG_LOW("RECEIVED:SESSION_INIT_DONE");
+	dprintk(VIDC_DBG, "RECEIVED:SESSION_INIT_DONE");
 	if (sizeof(struct hfi_msg_sys_session_init_done_packet)
 		> pkt->size) {
-		HAL_MSG_ERROR("hal_process_session_init_done:bad_pkt_size");
+		dprintk(VIDC_ERR, "hal_process_session_init_done:bad_pkt_size");
 		return;
 	}
 
@@ -445,11 +450,11 @@
 	struct hfi_msg_session_load_resources_done_packet *pkt)
 {
 	struct msm_vidc_cb_cmd_done cmd_done;
-	HAL_MSG_LOW("RECEIVED:SESSION_LOAD_RESOURCES_DONE");
+	dprintk(VIDC_DBG, "RECEIVED:SESSION_LOAD_RESOURCES_DONE");
 
 	if (sizeof(struct hfi_msg_session_load_resources_done_packet) !=
 		pkt->size) {
-		HAL_MSG_ERROR("hal_process_session_load_res_done:"
+		dprintk(VIDC_ERR, "hal_process_session_load_res_done:"
 		" bad packet size: %d", pkt->size);
 		return;
 	}
@@ -470,10 +475,10 @@
 {
 	struct msm_vidc_cb_cmd_done cmd_done;
 
-	HAL_MSG_LOW("RECEIVED:SESSION_FLUSH_DONE");
+	dprintk(VIDC_DBG, "RECEIVED:SESSION_FLUSH_DONE");
 
 	if (sizeof(struct hfi_msg_session_flush_done_packet) != pkt->size) {
-		HAL_MSG_ERROR("hal_process_session_flush_done: "
+		dprintk(VIDC_ERR, "hal_process_session_flush_done: "
 		"bad packet size: %d", pkt->size);
 		return;
 	}
@@ -493,11 +498,11 @@
 {
 	struct msm_vidc_cb_data_done data_done;
 
-	HAL_MSG_LOW("RECEIVED:SESSION_ETB_DONE");
+	dprintk(VIDC_DBG, "RECEIVED:SESSION_ETB_DONE");
 
 	if (!pkt || pkt->size !=
 		sizeof(struct hfi_msg_session_empty_buffer_done_packet)) {
-		HAL_MSG_ERROR("hal_process_session_etb_done:bad_pkt_size");
+		dprintk(VIDC_ERR, "hal_process_session_etb_done:bad_pkt_size");
 		return;
 	}
 
@@ -525,13 +530,13 @@
 	struct hal_session *session;
 
 	if (!msg_hdr) {
-		HAL_MSG_ERROR("Invalid Params in %s", __func__);
+		dprintk(VIDC_ERR, "Invalid Params in ");
 		return;
 	}
 
 	session = (struct hal_session *)
 		((struct hal_session *)	pack->session_id)->session_id;
-	HAL_MSG_ERROR("RECEIVED:SESSION_FTB_DONE");
+	dprintk(VIDC_DBG, "RECEIVED:SESSION_FTB_DONE");
 
 	memset(&data_done, 0, sizeof(struct msm_vidc_cb_data_done));
 
@@ -542,11 +547,13 @@
 		if (sizeof(struct
 			hfi_msg_session_fill_buffer_done_compressed_packet)
 			!= pkt->size) {
-			HAL_MSG_ERROR("%s: bad_pkt_size", __func__);
+			dprintk(VIDC_ERR,
+				"hal_process_session_ftb_done: bad_pkt_size");
 			return;
 		} else if (pkt->error_type != HFI_ERR_NONE) {
-			HAL_MSG_ERROR("%s: got buffer back with error %x",
-					__func__, pkt->error_type);
+			dprintk(VIDC_ERR,
+				"got buffer back with error %x",
+				pkt->error_type);
 			/* Proceed with the FBD */
 		}
 
@@ -570,6 +577,8 @@
 		data_done.output_done.packet_buffer1 = pkt->packet_buffer;
 		data_done.output_done.extra_data_buffer =
 			pkt->extra_data_buffer;
+		dprintk(VIDC_DBG, "FBD: Received buf: %p, of len: %d\n",
+				   pkt->packet_buffer, pkt->filled_len);
 	} else if (is_decoder == 1) {
 		struct hfi_msg_session_fbd_uncompressed_plane0_packet *pkt =
 		(struct	hfi_msg_session_fbd_uncompressed_plane0_packet *)
@@ -577,7 +586,7 @@
 		if (sizeof(struct
 		hfi_msg_session_fbd_uncompressed_plane0_packet)
 		> pkt->size) {
-			HAL_MSG_ERROR("hal_process_session_ftb_done:"
+			dprintk(VIDC_ERR, "hal_process_session_ftb_done:"
 						"bad_pkt_size");
 			return;
 		}
@@ -623,11 +632,11 @@
 {
 	struct msm_vidc_cb_cmd_done cmd_done;
 
-	HAL_MSG_LOW("RECEIVED:SESSION_START_DONE");
+	dprintk(VIDC_DBG, "RECEIVED:SESSION_START_DONE");
 
 	if (!pkt || pkt->size !=
 		sizeof(struct hfi_msg_session_start_done_packet)) {
-		HAL_MSG_ERROR("hal_process_session_start_done:"
+		dprintk(VIDC_ERR, "hal_process_session_start_done:"
 		"bad packet/packet size: %d", pkt->size);
 		return;
 	}
@@ -647,11 +656,11 @@
 {
 	struct msm_vidc_cb_cmd_done cmd_done;
 
-	HAL_MSG_LOW("RECEIVED:SESSION_STOP_DONE");
+	dprintk(VIDC_DBG, "RECEIVED:SESSION_STOP_DONE");
 
 	if (!pkt || pkt->size !=
 		sizeof(struct hfi_msg_session_stop_done_packet)) {
-		HAL_MSG_ERROR("hal_process_session_stop_done:"
+		dprintk(VIDC_ERR, "hal_process_session_stop_done:"
 		"bad packet/packet size: %d", pkt->size);
 		return;
 	}
@@ -671,11 +680,11 @@
 {
 	struct msm_vidc_cb_cmd_done cmd_done;
 
-	HAL_MSG_LOW("RECEIVED:SESSION_RELEASE_RESOURCES_DONE");
+	dprintk(VIDC_DBG, "RECEIVED:SESSION_RELEASE_RESOURCES_DONE");
 
 	if (!pkt || pkt->size !=
 		sizeof(struct hfi_msg_session_release_resources_done_packet)) {
-		HAL_MSG_ERROR("hal_process_session_rel_res_done:"
+		dprintk(VIDC_ERR, "hal_process_session_rel_res_done:"
 		"bad packet/packet size: %d", pkt->size);
 		return;
 	}
@@ -697,18 +706,18 @@
 	struct list_head *curr, *next;
 	struct hal_session *sess_close;
 
-	HAL_MSG_LOW("RECEIVED:SESSION_END_DONE");
+	dprintk(VIDC_DBG, "RECEIVED:SESSION_END_DONE");
 
 	if (!pkt || pkt->size !=
 		sizeof(struct hfi_msg_sys_session_end_done_packet)) {
-		HAL_MSG_ERROR("hal_process_session_end_done: "
+		dprintk(VIDC_ERR, "hal_process_session_end_done: "
 		"bad packet/packet size: %d", pkt->size);
 		return;
 	}
 
 	list_for_each_safe(curr, next, &device->sess_head) {
 		sess_close = list_entry(curr, struct hal_session, list);
-		HAL_MSG_MEDIUM("deleted the session: 0x%x",
+		dprintk(VIDC_INFO, "deleted the session: 0x%x",
 					   sess_close->session_id);
 		list_del(&sess_close->list);
 		kfree(sess_close);
@@ -724,18 +733,40 @@
 	device->callback(SESSION_END_DONE, &cmd_done);
 }
 
+static void hal_process_session_get_seq_hdr_done(struct hal_device *device,
+	struct hfi_msg_session_get_sequence_header_done_packet *pkt)
+{
+	struct msm_vidc_cb_data_done data_done;
+	if (!pkt || pkt->size !=
+		sizeof(struct
+		hfi_msg_session_get_sequence_header_done_packet)) {
+		dprintk(VIDC_ERR, "bad packet/packet size: %d", pkt->size);
+		return;
+	}
+	memset(&data_done, 0, sizeof(struct msm_vidc_cb_data_done));
+	data_done.device_id = device->device_id;
+	data_done.size = sizeof(struct msm_vidc_cb_data_done);
+	data_done.session_id =
+		((struct hal_session *) pkt->session_id)->session_id;
+	data_done.status = vidc_map_hal_err_status((u32)pkt->error_type);
+	data_done.output_done.packet_buffer1 = pkt->sequence_header;
+	data_done.output_done.filled_len1 = pkt->header_len;
+	dprintk(VIDC_INFO, "seq_hdr: %p, Length: %d",
+		   pkt->sequence_header, pkt->header_len);
+	device->callback(SESSION_GET_SEQ_HDR_DONE, &data_done);
+}
+
 static void hal_process_msg_packet(struct hal_device *device,
 	struct vidc_hal_msg_pkt_hdr *msg_hdr)
 {
 	if (!device || !msg_hdr || msg_hdr->size <
 		VIDC_IFACEQ_MIN_PKT_SIZE) {
-		HAL_MSG_ERROR("hal_process_msg_packet:bad"
+		dprintk(VIDC_ERR, "hal_process_msg_packet:bad"
 			"packet/packet size: %d", msg_hdr->size);
 		return;
 	}
 
-	HAL_MSG_ERROR("Received: 0x%x in %s", msg_hdr->packet, __func__);
-
+	dprintk(VIDC_INFO, "Received: 0x%x in ", msg_hdr->packet);
 	switch (msg_hdr->packet) {
 	case HFI_MSG_EVENT_NOTIFY:
 		hal_process_event_notify(device,
@@ -799,8 +830,13 @@
 			(struct hfi_msg_sys_release_resource_done_packet *)
 			msg_hdr);
 		break;
+	case HFI_MSG_SESSION_GET_SEQUENCE_HEADER_DONE:
+		hal_process_session_get_seq_hdr_done(device, (struct
+			hfi_msg_session_get_sequence_header_done_packet
+			 *) msg_hdr);
+		break;
 	default:
-		HAL_MSG_ERROR("UNKNOWN_MSG_TYPE : %d", msg_hdr->packet);
+		dprintk(VIDC_ERR, "UNKNOWN_MSG_TYPE : %d", msg_hdr->packet);
 		break;
 	}
 }
@@ -809,13 +845,13 @@
 {
 	u8 packet[VIDC_IFACEQ_MED_PKT_SIZE];
 
-	HAL_MSG_INFO("############vidc_hal_response_handler\n");
+	dprintk(VIDC_INFO, "#####vidc_hal_response_handler#####\n");
 	if (device) {
 		while (!vidc_hal_iface_msgq_read(device, packet)) {
 			hal_process_msg_packet(device,
 				(struct vidc_hal_msg_pkt_hdr *)	packet);
 		}
 	} else {
-		HAL_MSG_ERROR("SPURIOUS_INTERRUPT");
+		dprintk(VIDC_ERR, "SPURIOUS_INTERRUPT");
 	}
 }
diff --git a/drivers/media/video/msm_vidc/vidc_hal_io.h b/drivers/media/video/msm_vidc/vidc_hal_io.h
index 05a4c60..c4b1e0c 100644
--- a/drivers/media/video/msm_vidc/vidc_hal_io.h
+++ b/drivers/media/video/msm_vidc/vidc_hal_io.h
@@ -16,13 +16,12 @@
 
 #include <linux/io.h>
 
+#define VENUS_VCODEC_SS_CLOCK_HALT     0x0000000C
+#define VENUS_VPP_CORE_SW_RESET        0x00042004
+#define VENUS_VPP_CTRL_CTRL_RESET      0x00041008
+
 #define VIDC_VBIF_BASE_OFFS			0x00080000
 #define VIDC_VBIF_VERSION			(VIDC_VBIF_BASE_OFFS + 0x00)
-#define VIDC_VBIF_ADDR_TRANS_EN		(VIDC_VBIF_BASE_OFFS + 0x10)
-#define VIDC_VBIF_AT_OLD_BASE		(VIDC_VBIF_BASE_OFFS + 0x14)
-#define VIDC_VBIF_AT_OLD_HIGH		(VIDC_VBIF_BASE_OFFS + 0x18)
-#define VIDC_VBIF_AT_NEW_BASE		(VIDC_VBIF_BASE_OFFS + 0x20)
-#define VIDC_VBIF_AT_NEW_HIGH		(VIDC_VBIF_BASE_OFFS + 0x28)
 
 #define VIDC_CPU_BASE_OFFS			0x000C0000
 #define VIDC_CPU_CS_BASE_OFFS		(VIDC_CPU_BASE_OFFS + 0x00012000)
@@ -98,6 +97,38 @@
 #define VIDC_WRAPPER_AXI_HALT		(VIDC_WRAPPER_BASE_OFFS + 0x2008)
 #define VIDC_WRAPPER_AXI_HALT_STATUS	(VIDC_WRAPPER_BASE_OFFS + 0x200C)
 #define VIDC_WRAPPER_CPU_CGC_DIS	(VIDC_WRAPPER_BASE_OFFS + 0x2010)
+#define VIDC_VENUS_VBIF_CLK_ON		(VIDC_VBIF_BASE_OFFS + 0x4)
+#define VIDC_VBIF_IN_RD_LIM_CONF0       (VIDC_VBIF_BASE_OFFS + 0xB0)
+#define VIDC_VBIF_IN_RD_LIM_CONF1       (VIDC_VBIF_BASE_OFFS + 0xB4)
+#define VIDC_VBIF_IN_RD_LIM_CONF2       (VIDC_VBIF_BASE_OFFS + 0xB8)
+#define VIDC_VBIF_IN_RD_LIM_CONF3       (VIDC_VBIF_BASE_OFFS + 0xBC)
+#define VIDC_VBIF_IN_WR_LIM_CONF0       (VIDC_VBIF_BASE_OFFS + 0xC0)
+#define VIDC_VBIF_IN_WR_LIM_CONF1       (VIDC_VBIF_BASE_OFFS + 0xC4)
+#define VIDC_VBIF_IN_WR_LIM_CONF2       (VIDC_VBIF_BASE_OFFS + 0xC8)
+#define VIDC_VBIF_IN_WR_LIM_CONF3       (VIDC_VBIF_BASE_OFFS + 0xCC)
+#define VIDC_VBIF_OUT_RD_LIM_CONF0      (VIDC_VBIF_BASE_OFFS + 0xD0)
+#define VIDC_VBIF_OUT_WR_LIM_CONF0      (VIDC_VBIF_BASE_OFFS + 0xD4)
+#define VIDC_VBIF_DDR_OUT_MAX_BURST     (VIDC_VBIF_BASE_OFFS + 0xD8)
+#define VIDC_VBIF_OCMEM_OUT_MAX_BURST   (VIDC_VBIF_BASE_OFFS + 0xDC)
+#define VIDC_VBIF_DDR_ARB_CONF0         (VIDC_VBIF_BASE_OFFS + 0xF4)
+#define VIDC_VBIF_DDR_ARB_CONF1         (VIDC_VBIF_BASE_OFFS + 0xF8)
+#define VIDC_VBIF_ROUND_ROBIN_QOS_ARB   (VIDC_VBIF_BASE_OFFS + 0x124)
+#define VIDC_VBIF_OUT_AXI_AOOO_EN       (VIDC_VBIF_BASE_OFFS + 0x178)
+#define VIDC_VBIF_OUT_AXI_AOOO          (VIDC_VBIF_BASE_OFFS + 0x17C)
+#define VIDC_VBIF_ARB_CTL               (VIDC_VBIF_BASE_OFFS + 0xF0)
+#define VIDC_VBIF_OUT_AXI_AMEMTYPE_CONF0 (VIDC_VBIF_BASE_OFFS + 0x160)
+#define VIDC_VBIF_OUT_AXI_AMEMTYPE_CONF1 (VIDC_VBIF_BASE_OFFS + 0x164)
+#define VIDC_VBIF_ADDR_TRANS_EN         (VIDC_VBIF_BASE_OFFS + 0xC00)
+#define VIDC_VBIF_AT_OLD_BASE           (VIDC_VBIF_BASE_OFFS + 0xC04)
+#define VIDC_VBIF_AT_OLD_HIGH           (VIDC_VBIF_BASE_OFFS + 0xC08)
+#define VIDC_VBIF_AT_NEW_BASE           (VIDC_VBIF_BASE_OFFS + 0xC10)
+#define VIDC_VBIF_AT_NEW_HIGH           (VIDC_VBIF_BASE_OFFS + 0xC18)
+
+#define VIDC_VENUS0_VENUS_WRAPPER_VBIF_REQ_PRIORITY \
+	(VIDC_WRAPPER_BASE_OFFS + 0x20)
+#define VIDC_VENUS0_VENUS_WRAPPER_VBIF_PRIORITY_LEVEL \
+	(VIDC_WRAPPER_BASE_OFFS + 0x24)
+#define VIDC_VENUS_VBIF_REQ_PRIORITY    (VIDC_WRAPPER_BASE_OFFS + 0x20)
+#define VIDC_VENUS_VBIF_PRIORITY_LEVEL  (VIDC_WRAPPER_BASE_OFFS + 0x24)
 
 #endif
-
diff --git a/drivers/media/video/msm_wfd/enc-subdev.c b/drivers/media/video/msm_wfd/enc-subdev.c
index 8b83a98..e1cabf9 100644
--- a/drivers/media/video/msm_wfd/enc-subdev.c
+++ b/drivers/media/video/msm_wfd/enc-subdev.c
@@ -1964,13 +1964,33 @@
 				client_ctx->user_ion_client,
 				client_ctx->recon_buffer_ion_handle[i],	0);
 
-			rc = ion_map_iommu(client_ctx->user_ion_client,
-				client_ctx->recon_buffer_ion_handle[i],
-				VIDEO_DOMAIN, VIDEO_MAIN_POOL, SZ_4K,
-				0, &phy_addr, (unsigned long *)&len, 0, 0);
-			if (rc) {
-				WFD_MSG_ERR("Failed to allo recon buffers\n");
-				break;
+			if (IS_ERR_OR_NULL(ctrl->kernel_virtual_addr)) {
+				WFD_MSG_ERR("ion map kernel failed\n");
+				rc = -EINVAL;
+				goto free_ion_alloc;
+			}
+
+			if (inst->secure) {
+				rc = ion_phys(client_ctx->user_ion_client,
+					client_ctx->recon_buffer_ion_handle[i],
+					&phy_addr, (size_t *)&len);
+				if (rc || !phy_addr) {
+					WFD_MSG_ERR("ion physical failed\n");
+					goto unmap_ion_alloc;
+				}
+			} else {
+				rc = ion_map_iommu(client_ctx->user_ion_client,
+					client_ctx->recon_buffer_ion_handle[i],
+					VIDEO_DOMAIN, VIDEO_MAIN_POOL, SZ_4K,
+					0, &phy_addr, (unsigned long *)&len,
+					0, 0);
+				 if (rc || !phy_addr) {
+					WFD_MSG_ERR(
+						"ion map iommu failed, rc = %d, phy_addr = 0x%lx\n",
+						rc, phy_addr);
+					goto unmap_ion_alloc;
+				}
+
 			}
 			ctrl->physical_addr =  (u8 *) phy_addr;
 			ctrl->dev_addr = ctrl->physical_addr;
@@ -1981,13 +2001,36 @@
 					&vcd_property_hdr, ctrl);
 			if (rc) {
 				WFD_MSG_ERR("Failed to set recon buffers\n");
-				break;
+				goto unmap_ion_iommu;
 			}
 		}
 	} else {
 		WFD_MSG_ERR("PMEM not suported\n");
 		return -ENOMEM;
 	}
+	return rc;
+unmap_ion_iommu:
+	if (!inst->secure) {
+		if (client_ctx->recon_buffer_ion_handle[i]) {
+			ion_unmap_iommu(client_ctx->user_ion_client,
+				client_ctx->recon_buffer_ion_handle[i],
+				VIDEO_DOMAIN, VIDEO_MAIN_POOL);
+		}
+	}
+unmap_ion_alloc:
+	if (client_ctx->recon_buffer_ion_handle[i]) {
+		ion_unmap_kernel(client_ctx->user_ion_client,
+			client_ctx->recon_buffer_ion_handle[i]);
+		ctrl->kernel_virtual_addr = NULL;
+		ctrl->physical_addr = NULL;
+	}
+free_ion_alloc:
+	if (client_ctx->recon_buffer_ion_handle[i]) {
+		ion_free(client_ctx->user_ion_client,
+			client_ctx->recon_buffer_ion_handle[i]);
+		client_ctx->recon_buffer_ion_handle[i] = NULL;
+	}
+	WFD_MSG_ERR("Failed to allo recon buffers\n");
 err:
 	return rc;
 }
@@ -2115,10 +2158,14 @@
 			if (rc)
 				WFD_MSG_ERR("Failed to free recon buffer\n");
 
-			if (client_ctx->recon_buffer_ion_handle[i]) {
-				ion_unmap_iommu(client_ctx->user_ion_client,
-					 client_ctx->recon_buffer_ion_handle[i],
-					 VIDEO_DOMAIN, VIDEO_MAIN_POOL);
+			if (IS_ERR_OR_NULL(
+				client_ctx->recon_buffer_ion_handle[i])) {
+				if (!inst->secure) {
+					ion_unmap_iommu(
+					client_ctx->user_ion_client,
+					client_ctx->recon_buffer_ion_handle[i],
+					VIDEO_DOMAIN, VIDEO_MAIN_POOL);
+				}
 				ion_unmap_kernel(client_ctx->user_ion_client,
 					client_ctx->recon_buffer_ion_handle[i]);
 				ion_free(client_ctx->user_ion_client,
diff --git a/drivers/media/video/msm_wfd/wfd-ioctl.c b/drivers/media/video/msm_wfd/wfd-ioctl.c
index 4c27f19..8981c1a 100644
--- a/drivers/media/video/msm_wfd/wfd-ioctl.c
+++ b/drivers/media/video/msm_wfd/wfd-ioctl.c
@@ -153,7 +153,7 @@
 		bool secure, struct mem_region *mregion)
 {
 	struct ion_handle *handle;
-	void *kvaddr, *phys_addr;
+	void *kvaddr = NULL, *phys_addr = NULL;
 	unsigned long size;
 	unsigned int alloc_regions = 0;
 	int rc;
@@ -170,7 +170,7 @@
 		goto alloc_fail;
 	}
 
-	kvaddr = ion_map_kernel(client,	handle,	CACHED);
+	kvaddr = ion_map_kernel(client, handle, secure ? UNCACHED : CACHED);
 
 	if (IS_ERR_OR_NULL(kvaddr)) {
 		WFD_MSG_ERR("Failed to get virtual addr\n");
@@ -178,13 +178,23 @@
 		goto alloc_fail;
 	}
 
-	rc = ion_map_iommu(client, handle,
-			VIDEO_DOMAIN, VIDEO_MAIN_POOL, SZ_4K,
-			0, (unsigned long *)&phys_addr,
-			&size, 0, 0);
+	if (secure) {
+		WFD_MSG_INFO("%s: calling ion_phys", __func__);
+		rc = ion_phys(client,
+			handle,
+			(unsigned long *)&phys_addr, (size_t *)&size);
+	} else {
+		WFD_MSG_INFO("%s: calling ion_map_iommu", __func__);
+		rc = ion_map_iommu(client, handle,
+				VIDEO_DOMAIN, VIDEO_MAIN_POOL, SZ_4K,
+				0, (unsigned long *)&phys_addr,
+				&size, 0, 0);
+	}
 
-	if (rc) {
-		WFD_MSG_ERR("Failed to get physical addr\n");
+	if (rc || !phys_addr) {
+		WFD_MSG_ERR(
+			"Failed to get physical addr, rc = %d, phys_addr = 0x%p\n",
+			rc, phys_addr);
 		goto alloc_fail;
 	} else if (size < mregion->size) {
 		WFD_MSG_ERR("Failed to map enough memory\n");
@@ -199,7 +209,9 @@
 	return rc;
 alloc_fail:
 	if (!IS_ERR_OR_NULL(handle)) {
-		ion_unmap_kernel(client, handle);
+		if (!IS_ERR_OR_NULL(kvaddr))
+			ion_unmap_kernel(client, handle);
+
 		ion_free(client, handle);
 
 		mregion->kvaddr = NULL;
@@ -311,8 +323,10 @@
 				(unsigned long *)&mdp_mregion->size, 0, 0);
 		}
 
-		if (rc) {
-			WFD_MSG_ERR("Failed to map to mdp\n");
+		if (rc || !mdp_mregion->paddr) {
+			WFD_MSG_ERR(
+				"Failed to map to mdp, rc = %d, paddr = 0x%p\n",
+				rc, mdp_mregion->paddr);
 			mdp_mregion->kvaddr = NULL;
 			mdp_mregion->paddr = NULL;
 			mdp_mregion->ion_handle = NULL;
@@ -324,8 +338,9 @@
 		mdp_buf.kvaddr = (u32) mdp_mregion->kvaddr;
 		mdp_buf.paddr = (u32) mdp_mregion->paddr;
 
-		WFD_MSG_DBG("NOTE: mdp paddr = %p, kvaddr = %p\n",
-				mdp_mregion->paddr,
+		WFD_MSG_DBG("NOTE: mdp paddr = [%p->%p], kvaddr = %p\n",
+				mdp_mregion->paddr, (void *)
+				((int)mdp_mregion->paddr + mdp_mregion->size),
 				mdp_mregion->kvaddr);
 
 		INIT_LIST_HEAD(&mpair->list);
@@ -350,7 +365,12 @@
 		WFD_MSG_ERR("Failed to allocate recon buffers\n");
 		goto alloc_fail;
 	}
+	return rc;
+
 alloc_fail:
+	kfree(mpair);
+	kfree(enc_mregion);
+	kfree(mdp_mregion);
 	return rc;
 }
 void wfd_free_input_buffers(struct wfd_device *wfd_dev,
@@ -395,7 +415,7 @@
 				}
 			}
 
-			if (mpair->enc->paddr)
+			if (mpair->enc->paddr && !wfd_dev->secure_device)
 				ion_unmap_iommu(wfd_dev->ion_client,
 						mpair->enc->ion_handle,
 						VIDEO_DOMAIN, VIDEO_MAIN_POOL);
@@ -1290,7 +1310,10 @@
 
 	WFD_MSG_DBG("wfd_open: E\n");
 	wfd_dev = video_drvdata(filp);
-
+	if (!wfd_dev) {
+		rc = -EINVAL;
+		goto err_dev_busy;
+	}
 	mutex_lock(&wfd_dev->dev_lock);
 	if (wfd_dev->in_use) {
 		WFD_MSG_ERR("Device already in use.\n");
@@ -1303,7 +1326,7 @@
 	mutex_unlock(&wfd_dev->dev_lock);
 
 	inst = kzalloc(sizeof(struct wfd_inst), GFP_KERNEL);
-	if (!inst || !wfd_dev) {
+	if (!inst) {
 		WFD_MSG_ERR("Could not allocate memory for "
 			"wfd instance\n");
 		rc = -ENOMEM;
@@ -1361,6 +1384,9 @@
 	v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl,
 				MDP_CLOSE, (void *)inst->mdp_inst);
 err_mdp_open:
+	mutex_lock(&wfd_dev->dev_lock);
+	wfd_dev->in_use = false;
+	mutex_unlock(&wfd_dev->dev_lock);
 	kfree(inst);
 err_dev_busy:
 	return rc;
@@ -1509,10 +1535,6 @@
 	}
 
 	wfd_priv = pdev->dev.platform_data;
-	if (wfd_priv && wfd_priv->wfd_check_mdp_iommu_split) {
-		wfd_dev->mdp_iommu_split_domain =
-			wfd_priv->wfd_check_mdp_iommu_split();
-	}
 
 	pdev->dev.platform_data = (void *) wfd_dev;
 
@@ -1556,6 +1578,11 @@
 		mutex_init(&wfd_dev[c].dev_lock);
 		wfd_dev[c].ion_client = ion_client;
 		wfd_dev[c].in_use = false;
+		if (wfd_priv && wfd_priv->wfd_check_mdp_iommu_split) {
+			wfd_dev[c].mdp_iommu_split_domain =
+				wfd_priv->wfd_check_mdp_iommu_split();
+		}
+
 		switch (WFD_DEVICE_NUMBER_BASE + c) {
 		case WFD_DEVICE_SECURE:
 			wfd_dev[c].secure_device = true;
diff --git a/drivers/media/video/vcap_v4l2.c b/drivers/media/video/vcap_v4l2.c
index e8d9e04..28abb36 100644
--- a/drivers/media/video/vcap_v4l2.c
+++ b/drivers/media/video/vcap_v4l2.c
@@ -503,7 +503,7 @@
 			       unsigned int *nplanes, unsigned int sizes[],
 			       void *alloc_ctxs[])
 {
-	*nbuffers += 2;
+	*nbuffers += vcap_ctrl->vc_tot_buf;
 	if (*nbuffers > VIDEO_MAX_FRAME)
 		return -EINVAL;
 	*nplanes = 1;
@@ -524,17 +524,16 @@
 {
 	struct vcap_client_data *c_data = vb2_get_drv_priv(vb->vb2_queue);
 	struct vcap_buffer *buf = container_of(vb, struct vcap_buffer, vb);
-	struct vcap_action *vid_vc_action = &c_data->vid_vc_action;
+	struct vc_action *vc_action = &c_data->vc_action;
 	struct vb2_queue *q = vb->vb2_queue;
 	unsigned long flags = 0;
 
 	spin_lock_irqsave(&c_data->cap_slock, flags);
-	list_add_tail(&buf->list, &vid_vc_action->active);
+	list_add_tail(&buf->list, &vc_action->active);
 	spin_unlock_irqrestore(&c_data->cap_slock, flags);
 
 	if (atomic_read(&c_data->dev->vc_enabled) == 0) {
-
-		if (atomic_read(&q->queued_count) > 1)
+		if (atomic_read(&q->queued_count) >= c_data->vc_action.tot_buf)
 			if (vc_hw_kick_off(c_data) == 0)
 				atomic_set(&c_data->dev->vc_enabled, 1);
 	}
@@ -554,9 +553,9 @@
 
 	vc_stop_capture(c_data);
 
-	while (!list_empty(&c_data->vid_vc_action.active)) {
+	while (!list_empty(&c_data->vc_action.active)) {
 		struct vcap_buffer *buf;
-		buf = list_entry(c_data->vid_vc_action.active.next,
+		buf = list_entry(c_data->vc_action.active.next,
 			struct vcap_buffer, list);
 		list_del(&buf->list);
 		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
@@ -617,7 +616,7 @@
 {
 	struct vcap_client_data *cd = vb2_get_drv_priv(vb->vb2_queue);
 	struct vcap_buffer *buf = container_of(vb, struct vcap_buffer, vb);
-	struct vp_action *vp_act = &cd->vid_vp_action;
+	struct vp_action *vp_act = &cd->vp_action;
 	struct vb2_queue *q = vb->vb2_queue;
 	unsigned long flags = 0;
 
@@ -626,7 +625,7 @@
 	spin_unlock_irqrestore(&cd->cap_slock, flags);
 
 	if (atomic_read(&cd->dev->vp_enabled) == 0) {
-		if (cd->vid_vp_action.vp_state == VP_FRAME1) {
+		if (cd->vp_action.vp_state == VP_FRAME1) {
 			if (atomic_read(&q->queued_count) > 1 &&
 				atomic_read(&cd->vp_out_vidq.queued_count) > 0)
 				/* Valid code flow for VC-VP mode */
@@ -651,9 +650,9 @@
 
 	dprintk(2, "VP stop streaming\n");
 
-	while (!list_empty(&c_data->vid_vp_action.in_active)) {
+	while (!list_empty(&c_data->vp_action.in_active)) {
 		struct vcap_buffer *buf;
-		buf = list_entry(c_data->vid_vp_action.in_active.next,
+		buf = list_entry(c_data->vp_action.in_active.next,
 			struct vcap_buffer, list);
 		list_del(&buf->list);
 		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
@@ -715,7 +714,7 @@
 {
 	struct vcap_client_data *cd = vb2_get_drv_priv(vb->vb2_queue);
 	struct vcap_buffer *buf = container_of(vb, struct vcap_buffer, vb);
-	struct vp_action *vp_act = &cd->vid_vp_action;
+	struct vp_action *vp_act = &cd->vp_action;
 	struct vb2_queue *q = vb->vb2_queue;
 	unsigned long flags = 0;
 
@@ -724,7 +723,7 @@
 	spin_unlock_irqrestore(&cd->cap_slock, flags);
 
 	if (atomic_read(&cd->dev->vp_enabled) == 0) {
-		if (cd->vid_vp_action.vp_state == VP_FRAME1) {
+		if (cd->vp_action.vp_state == VP_FRAME1) {
 			if (atomic_read(&q->queued_count) > 0 &&
 				atomic_read(&
 					cd->vp_in_vidq.queued_count) > 1)
@@ -749,9 +748,9 @@
 	dprintk(2, "VP out q stop streaming\n");
 	vp_stop_capture(c_data);
 
-	while (!list_empty(&c_data->vid_vp_action.out_active)) {
+	while (!list_empty(&c_data->vp_action.out_active)) {
 		struct vcap_buffer *buf;
-		buf = list_entry(c_data->vid_vp_action.out_active.next,
+		buf = list_entry(c_data->vp_action.out_active.next,
 			struct vcap_buffer, list);
 		list_del(&buf->list);
 		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
@@ -884,6 +883,7 @@
 			  struct v4l2_requestbuffers *rb)
 {
 	struct vcap_client_data *c_data = to_client_data(file->private_data);
+	struct vcap_dev *dev = c_data->dev;
 	int rc;
 
 	dprintk(3, "In Req Buf %08x\n", (unsigned int)rb->type);
@@ -905,7 +905,7 @@
 				pr_err("VCAP Err: VP No prog support\n");
 				return -ENOTRECOVERABLE;
 			}
-			if (rb->count < 6) {
+			if (rb->count <= VCAP_VP_MIN_BUF) {
 				pr_err("VCAP Err: Not enough buf for VC_VP\n");
 				return -EINVAL;
 			}
@@ -924,10 +924,13 @@
 			rb->type = V4L2_BUF_TYPE_INTERLACED_IN_DECODER;
 			rc = vb2_reqbufs(&c_data->vp_in_vidq, rb);
 			rb->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+			c_data->vc_action.tot_buf = dev->vc_tot_buf;
 			return rc;
 
 		} else {
-			return vb2_reqbufs(&c_data->vc_vidq, rb);
+			rc = vb2_reqbufs(&c_data->vc_vidq, rb);
+			c_data->vc_action.tot_buf = dev->vc_tot_buf;
+			return rc;
 		}
 	case V4L2_BUF_TYPE_INTERLACED_IN_DECODER:
 		return vb2_reqbufs(&c_data->vp_in_vidq, rb);
@@ -1117,6 +1120,12 @@
 		return -ENOTRECOVERABLE;
 	}
 
+	if (!dev->vp_dummy_complete) {
+		pr_err("VCAP Err: %s: VP dummy read not complete",
+			__func__);
+		return -EINVAL;
+	}
+
 	switch (c_data->op_mode) {
 	case VC_VCAP_OP:
 		mutex_lock(&dev->dev_mutex);
@@ -1213,13 +1222,13 @@
 		rc = init_motion_buf(c_data);
 		if (rc < 0)
 			goto free_res;
-		if (c_data->vid_vp_action.nr_param.mode) {
+		if (dev->nr_param.mode) {
 			rc = init_nr_buf(c_data);
 			if (rc < 0)
 				goto s_on_deinit_m_buf;
 		}
 
-		c_data->vid_vp_action.vp_state = VP_FRAME1;
+		c_data->vp_action.vp_state = VP_FRAME1;
 		c_data->streaming = 1;
 
 		rc = vb2_streamon(&c_data->vp_in_vidq,
@@ -1302,14 +1311,14 @@
 		if (rc < 0)
 			goto free_res;
 
-		if (c_data->vid_vp_action.nr_param.mode) {
+		if (dev->nr_param.mode) {
 			rc = init_nr_buf(c_data);
 			if (rc < 0)
 				goto s_on_deinit_m_buf;
 		}
 
 		c_data->dev->vc_to_vp_work.cd = c_data;
-		c_data->vid_vp_action.vp_state = VP_FRAME1;
+		c_data->vp_action.vp_state = VP_FRAME1;
 		c_data->streaming = 1;
 
 		/* These stream on calls should not fail */
@@ -1335,7 +1344,7 @@
 	return 0;
 
 s_on_deinit_nr_buf:
-	if (c_data->vid_vp_action.nr_param.mode)
+	if (dev->nr_param.mode)
 		deinit_nr_buf(c_data);
 s_on_deinit_m_buf:
 	deinit_motion_buf(c_data);
@@ -1390,19 +1399,13 @@
 		}
 		dev->vc_resource = 0;
 		mutex_unlock(&dev->dev_mutex);
+		c_data->streaming = 0;
 		rc = vb2_streamoff(&c_data->vc_vidq,
 				V4L2_BUF_TYPE_VIDEO_CAPTURE);
-		if (rc >= 0) {
-			c_data->streaming = 0;
+		if (rc >= 0)
 			atomic_set(&c_data->dev->vc_enabled, 0);
-		}
 		return rc;
 	case VP_VCAP_OP:
-		if (!dev->vp_dummy_complete) {
-			pr_err("VCAP Err: %s: VP dummy read not complete",
-				__func__);
-			return -EINVAL;
-		}
 		if (c_data != dev->vp_client) {
 			pr_err("VCAP Err: %s: VP held by other client",
 				__func__);
@@ -1436,16 +1439,11 @@
 			return rc;
 
 		deinit_motion_buf(c_data);
-		if (c_data->vid_vp_action.nr_param.mode)
+		if (dev->nr_param.mode)
 			deinit_nr_buf(c_data);
 		atomic_set(&c_data->dev->vp_enabled, 0);
 		return rc;
 	case VC_AND_VP_VCAP_OP:
-		if (!dev->vp_dummy_complete) {
-			pr_err("VCAP Err: %s: VP dummy read not complete",
-				__func__);
-			return -EINVAL;
-		}
 		if (c_data != dev->vp_client || c_data != dev->vc_client) {
 			pr_err("VCAP Err: %s: VC/VP held by other client",
 				__func__);
@@ -1489,7 +1487,7 @@
 			return rc;
 
 		deinit_motion_buf(c_data);
-		if (c_data->vid_vp_action.nr_param.mode)
+		if (dev->nr_param.mode)
 			deinit_nr_buf(c_data);
 		atomic_set(&c_data->dev->vc_enabled, 0);
 		atomic_set(&c_data->dev->vp_enabled, 0);
@@ -1540,7 +1538,9 @@
 						int cmd, void *arg)
 {
 	struct vcap_client_data *c_data = to_client_data(file->private_data);
+	struct vcap_dev *dev = c_data->dev;
 	struct nr_param *param;
+	int	val;
 	unsigned long flags = 0;
 	int ret;
 
@@ -1549,7 +1549,7 @@
 
 		if (c_data->streaming != 0 &&
 				(!(!((struct nr_param *) arg)->mode) !=
-				!(!(c_data->vid_vp_action.nr_param.mode)))) {
+				!(!(dev->nr_param.mode)))) {
 			pr_err("ERR: Trying to toggle on/off while VP is already running");
 			return -EBUSY;
 		}
@@ -1562,22 +1562,28 @@
 			return ret;
 		}
 		param = (struct nr_param *) arg;
-		c_data->vid_vp_action.nr_param = *param;
+		dev->nr_param = *param;
 		if (param->mode == NR_AUTO)
-			s_default_nr_val(&c_data->vid_vp_action.nr_param);
-		c_data->vid_vp_action.nr_update = true;
+			s_default_nr_val(&dev->nr_param);
+		dev->nr_update = true;
 		spin_unlock_irqrestore(&c_data->cap_slock, flags);
 		break;
 	case VCAPIOC_NR_G_PARAMS:
-		*((struct nr_param *)arg) = c_data->vid_vp_action.nr_param;
-		if (c_data->vid_vp_action.nr_param.mode != NR_DISABLE) {
+		*((struct nr_param *)arg) = dev->nr_param;
+		if (dev->nr_param.mode != NR_DISABLE) {
 			if (c_data->streaming)
 				nr_g_param(c_data, (struct nr_param *) arg);
 			else
 				(*(struct nr_param *) arg) =
-					c_data->vid_vp_action.nr_param;
+					dev->nr_param;
 		}
 		break;
+	case VCAPIOC_S_NUM_VC_BUF:
+		val = (*(int *) arg);
+		if (val < VCAP_VC_MIN_BUF || val > VCAP_VC_MAX_BUF)
+			return -EINVAL;
+		dev->vc_tot_buf = (uint8_t) val;
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -1663,9 +1669,9 @@
 	if (ret < 0)
 		goto vp_out_q_failed;
 
-	INIT_LIST_HEAD(&c_data->vid_vc_action.active);
-	INIT_LIST_HEAD(&c_data->vid_vp_action.in_active);
-	INIT_LIST_HEAD(&c_data->vid_vp_action.out_active);
+	INIT_LIST_HEAD(&c_data->vc_action.active);
+	INIT_LIST_HEAD(&c_data->vp_action.in_active);
+	INIT_LIST_HEAD(&c_data->vp_action.out_active);
 
 	v4l2_fh_init(&c_data->vfh, dev->vfd);
 	v4l2_fh_add(&c_data->vfh);
@@ -1727,6 +1733,7 @@
 	mutex_unlock(&dev->dev_mutex);
 	if (ret == 0) {
 		vcap_disable(dev);
+		dev->vc_tot_buf = 2;
 		dev->vp_dummy_complete = false;
 	}
 	v4l2_fh_del(&c_data->vfh);
@@ -1968,6 +1975,7 @@
 		goto rel_vcap_wq;
 	}
 
+	dev->vc_tot_buf = 2;
 	atomic_set(&dev->vc_enabled, 0);
 	atomic_set(&dev->vp_enabled, 0);
 	atomic_set(&dev->open_clients, 0);
diff --git a/drivers/media/video/vcap_vc.c b/drivers/media/video/vcap_vc.c
index 62cc306..78e108f 100644
--- a/drivers/media/video/vcap_vc.c
+++ b/drivers/media/video/vcap_vc.c
@@ -107,147 +107,143 @@
 	}
 }
 
+static uint8_t correct_buf_num(uint32_t reg)
+{
+	int i;
+	bool block_found = false;
+	for (i = 0; i < VCAP_VC_MAX_BUF; i++) {
+		if (reg & (0x2 << i)) {
+			block_found = true;
+			continue;
+		}
+		if (block_found)
+			return i;
+	}
+	return 0;
+}
+
 irqreturn_t vc_handler(struct vcap_dev *dev)
 {
 	uint32_t irq, timestamp;
-	enum rdy_buf vc_buf_status, buf_ind;
 	struct vcap_buffer *buf;
 	struct vb2_buffer *vb = NULL;
 	struct vcap_client_data *c_data;
 	struct v4l2_event v4l2_evt;
+	uint8_t i, idx, buf_num, tot, done_count = 0;
+	bool work_todo = false;
 
 	irq = readl_relaxed(VCAP_VC_INT_STATUS);
 
 	dprintk(1, "%s: irq=0x%08x\n", __func__, irq);
 
+	c_data = dev->vc_client;
+	if (!c_data->streaming) {
+		writel_iowmb(irq, VCAP_VC_INT_CLEAR);
+		pr_err("VC no longer streaming\n");
+		return IRQ_HANDLED;
+	}
+
 	v4l2_evt.id = 0;
 	if (irq & 0x8000200) {
+		writel_iowmb(0x00000102, VCAP_VC_NPL_CTRL);
 		v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
 			VCAP_VC_PIX_ERR_EVENT;
 		v4l2_event_queue(dev->vfd, &v4l2_evt);
 	}
 	if (irq & 0x40000200) {
+		writel_iowmb(0x00000102, VCAP_VC_NPL_CTRL);
 		v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
 			VCAP_VC_LINE_ERR_EVENT;
 		v4l2_event_queue(dev->vfd, &v4l2_evt);
 	}
 	if (irq & 0x20000200) {
+		writel_iowmb(0x00000102, VCAP_VC_NPL_CTRL);
 		v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
 			VCAP_VC_VSYNC_ERR_EVENT;
 		v4l2_event_queue(dev->vfd, &v4l2_evt);
 	}
 	if (irq & 0x00000800) {
+		writel_iowmb(0x00000102, VCAP_VC_NPL_CTRL);
 		v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
 			VCAP_VC_NPL_OFLOW_ERR_EVENT;
 		v4l2_event_queue(dev->vfd, &v4l2_evt);
 	}
 	if (irq & 0x00000400) {
+		writel_iowmb(0x00000102, VCAP_VC_NPL_CTRL);
 		v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
 			VCAP_VC_LBUF_OFLOW_ERR_EVENT;
 		v4l2_event_queue(dev->vfd, &v4l2_evt);
 	}
 
-	vc_buf_status = irq & VC_BUFFER_WRITTEN;
-	dprintk(1, "Done buf status = %d\n", vc_buf_status);
-
-	if (vc_buf_status == VC_NO_BUF) {
+	if (!(irq & VC_BUFFER_MASK)) {
 		writel_relaxed(irq, VCAP_VC_INT_CLEAR);
 		pr_err("VC IRQ shows some error\n");
 		return IRQ_HANDLED;
 	}
 
 	if (dev->vc_client == NULL) {
+		/* This should never happen */
 		writel_relaxed(irq, VCAP_VC_INT_CLEAR);
 		pr_err("VC: There is no active vc client\n");
 		return IRQ_HANDLED;
 	}
 	c_data = dev->vc_client;
 
-	spin_lock(&dev->vc_client->cap_slock);
-	if (list_empty(&dev->vc_client->vid_vc_action.active)) {
-		/* Just leave we have no new queued buffers */
-		spin_unlock(&dev->vc_client->cap_slock);
-		writel_relaxed(irq, VCAP_VC_INT_CLEAR);
-		v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
-			VCAP_VC_BUF_OVERWRITE_EVENT;
-		v4l2_event_queue(dev->vfd, &v4l2_evt);
-		dprintk(1, "We have no more avilable buffers\n");
-		return IRQ_HANDLED;
+	for (i = 0; i < VCAP_VC_MAX_BUF; i++) {
+		if (0x2 & (irq >> i))
+			done_count++;
 	}
-	spin_unlock(&dev->vc_client->cap_slock);
 
+	/* Double check expected buffers are done */
+	buf_num = c_data->vc_action.buf_num;
+	tot = c_data->vc_action.tot_buf;
+	for (i = 0; i < done_count; i++) {
+		if (!(irq & (0x1 << (((buf_num + i) % tot) + 1)))) {
+			v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
+				VCAP_VC_UNEXPECT_BUF_DONE;
+			v4l2_event_queue(dev->vfd, &v4l2_evt);
+			pr_debug("Unexpected buffer done\n");
+			c_data->vc_action.buf_num =
+				correct_buf_num(irq) % tot;
+			writel_relaxed(irq, VCAP_VC_INT_CLEAR);
+			return IRQ_HANDLED;
+		}
+	}
+
+	/* If here we know which buffers are done */
 	timestamp = readl_relaxed(VCAP_VC_TIMESTAMP);
 
-	buf_ind = dev->vc_client->vid_vc_action.buf_ind;
-
-	if (vc_buf_status == VC_BUF1N2) {
-		/* There are 2 buffer ready */
-		writel_relaxed(irq, VCAP_VC_INT_CLEAR);
-		return IRQ_HANDLED;
-	} else if (buf_ind != vc_buf_status) {
-		/* buffer is out of sync */
-		writel_relaxed(irq, VCAP_VC_INT_CLEAR);
-		return IRQ_HANDLED;
-	}
-
-	if (buf_ind == VC_BUF1) {
-		dprintk(1, "Got BUF1\n");
-		vb = &dev->vc_client->vid_vc_action.buf1->vb;
-		spin_lock(&dev->vc_client->cap_slock);
-		if (list_empty(&dev->vc_client->vid_vc_action.active)) {
-			spin_unlock(&dev->vc_client->cap_slock);
+	c_data->vc_action.buf_num = (buf_num + done_count) % tot;
+	for (i = 0; i < done_count; i++) {
+		idx = (buf_num + i) % tot;
+		vb = &c_data->vc_action.buf[idx]->vb;
+		spin_lock(&c_data->cap_slock);
+		if (list_empty(&c_data->vc_action.active)) {
+			spin_unlock(&c_data->cap_slock);
 			v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
 				VCAP_VC_BUF_OVERWRITE_EVENT;
 			v4l2_event_queue(dev->vfd, &v4l2_evt);
-			writel_relaxed(irq, VCAP_VC_INT_CLEAR);
-			return IRQ_HANDLED;
+			continue;
 		}
-		buf = list_entry(dev->vc_client->vid_vc_action.active.next,
+		buf = list_entry(c_data->vc_action.active.next,
 				struct vcap_buffer, list);
 		list_del(&buf->list);
-		spin_unlock(&dev->vc_client->cap_slock);
+		spin_unlock(&c_data->cap_slock);
 		/* Config vc with this new buffer */
-		config_buffer(c_data, buf, VCAP_VC_Y_ADDR_1,
-				VCAP_VC_C_ADDR_1);
-
-		vb->v4l2_buf.timestamp.tv_usec = timestamp;
+		config_buffer(c_data, buf, VCAP_VC_Y_ADDR_1 + 0x8 * idx,
+				VCAP_VC_C_ADDR_1 + 0x8 * idx);
+		vb->v4l2_buf.timestamp.tv_usec = timestamp -
+			1000000 / c_data->vc_format.frame_rate *
+			(done_count - 1 - i);
 		vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
-		dev->vc_client->vid_vc_action.buf1 = buf;
-		dev->vc_client->vid_vc_action.buf_ind = VC_BUF2;
-		irq = VC_BUF1;
-	} else {
-		dprintk(1, "Got BUF2\n");
-		spin_lock(&dev->vc_client->cap_slock);
-		vb = &dev->vc_client->vid_vc_action.buf2->vb;
-		if (list_empty(&dev->vc_client->vid_vc_action.active)) {
-			spin_unlock(&dev->vc_client->cap_slock);
-			writel_relaxed(irq, VCAP_VC_INT_CLEAR);
-			v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
-				VCAP_VC_BUF_OVERWRITE_EVENT;
-			v4l2_event_queue(dev->vfd, &v4l2_evt);
-			return IRQ_HANDLED;
-		}
-		buf = list_entry(dev->vc_client->vid_vc_action.active.next,
-						 struct vcap_buffer, list);
-		list_del(&buf->list);
-		spin_unlock(&dev->vc_client->cap_slock);
-		/* Config vc with this new buffer */
-		config_buffer(c_data, buf, VCAP_VC_Y_ADDR_2,
-				VCAP_VC_C_ADDR_2);
-
-		vb->v4l2_buf.timestamp.tv_usec = timestamp;
-		vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
-
-		dev->vc_client->vid_vc_action.buf2 = buf;
-		dev->vc_client->vid_vc_action.buf_ind = VC_BUF1;
-		irq = VC_BUF2;
+		work_todo = true;
+		c_data->vc_action.buf[idx] = buf;
 	}
 
-	if (c_data->op_mode == VC_AND_VP_VCAP_OP)
+	if (work_todo && c_data->op_mode == VC_AND_VP_VCAP_OP)
 		queue_work(dev->vcap_wq, &dev->vc_to_vp_work.work);
 
 	writel_relaxed(irq, VCAP_VC_INT_CLEAR);
-
 	return IRQ_HANDLED;
 }
 
@@ -258,73 +254,93 @@
 
 int vc_hw_kick_off(struct vcap_client_data *c_data)
 {
-	struct vcap_action *vid_vc_action = &c_data->vid_vc_action;
+	struct vc_action *vc_action = &c_data->vc_action;
 	struct vcap_dev *dev;
 	unsigned long flags = 0;
-	int rc, counter = 0;
+	int rc, i, counter = 0;
 	struct vcap_buffer *buf;
 
 	dev = c_data->dev;
-	vid_vc_action->buf_ind = VC_BUF1;
 	dprintk(2, "Start Kickoff\n");
 
 	if (dev->vc_client == NULL) {
 		pr_err("No active vc client\n");
 		return -ENODEV;
 	}
+	c_data->vc_action.buf_num = 0;
 	spin_lock_irqsave(&dev->vc_client->cap_slock, flags);
-	if (list_empty(&dev->vc_client->vid_vc_action.active)) {
+	if (list_empty(&dev->vc_client->vc_action.active)) {
 		spin_unlock_irqrestore(&dev->vc_client->cap_slock, flags);
 		pr_err("%s: VC We have no more avilable buffers\n",
 				__func__);
 		return -EINVAL;
 	}
 
-	list_for_each_entry(buf, &vid_vc_action->active, list)
+	list_for_each_entry(buf, &vc_action->active, list)
 		counter++;
 
-	if (counter < 2) {
+	if (counter < c_data->vc_action.tot_buf) {
 		/* not enough buffers have been queued */
 		spin_unlock_irqrestore(&dev->vc_client->cap_slock, flags);
 		return -EINVAL;
 	}
 
-	vid_vc_action->buf1 = list_entry(vid_vc_action->active.next,
+	for (i = 0; i < c_data->vc_action.tot_buf; i++) {
+		vc_action->buf[i] = list_entry(vc_action->active.next,
 			struct vcap_buffer, list);
-	list_del(&vid_vc_action->buf1->list);
-
-	vid_vc_action->buf2 = list_entry(vid_vc_action->active.next,
-			struct vcap_buffer, list);
-	list_del(&vid_vc_action->buf2->list);
-
+		list_del(&vc_action->buf[i]->list);
+	}
 	spin_unlock_irqrestore(&dev->vc_client->cap_slock, flags);
 
-	config_buffer(c_data, vid_vc_action->buf1, VCAP_VC_Y_ADDR_1,
-			VCAP_VC_C_ADDR_1);
-	config_buffer(c_data, vid_vc_action->buf2, VCAP_VC_Y_ADDR_2,
-			VCAP_VC_C_ADDR_2);
+	for (i = 0; i < c_data->vc_action.tot_buf; i++) {
+		config_buffer(c_data, vc_action->buf[i],
+			VCAP_VC_Y_ADDR_1 + i * 8,
+			VCAP_VC_C_ADDR_1 + i * 8);
+	}
 
+	rc = 0;
+	for (i = 0; i < c_data->vc_action.tot_buf; i++)
+		rc = rc << 1 | 0x2;
+	writel_relaxed(rc, VCAP_VC_INT_MASK);
+
+	enable_irq(dev->vcirq->start);
 	rc = readl_relaxed(VCAP_VC_CTRL);
 	writel_iowmb(rc | 0x1, VCAP_VC_CTRL);
 
-	writel_relaxed(0x6, VCAP_VC_INT_MASK);
-
-	enable_irq(dev->vcirq->start);
 	return 0;
 }
 
 void vc_stop_capture(struct vcap_client_data *c_data)
 {
 	struct vcap_dev *dev = c_data->dev;
-	int rc;
+	unsigned int reg;
+	int timeout;
 
-	rc = readl_relaxed(VCAP_VC_CTRL);
-	writel_iowmb(rc & ~(0x1), VCAP_VC_CTRL);
-
-	if (atomic_read(&dev->vc_enabled) == 1)
-		disable_irq(dev->vcirq->start);
-
+	writel_iowmb(0x00000102, VCAP_VC_NPL_CTRL);
+	writel_iowmb(0x0, VCAP_VC_INT_MASK);
 	flush_workqueue(dev->vcap_wq);
+	if (atomic_read(&dev->vc_enabled) == 1)
+		disable_irq_nosync(dev->vcirq->start);
+
+	writel_iowmb(0x00000000, VCAP_VC_CTRL);
+	writel_iowmb(0x00000001, VCAP_SW_RESET_REQ);
+	timeout = 10000;
+	while (1) {
+		reg = (readl_relaxed(VCAP_SW_RESET_STATUS) & 0x1);
+		if (!reg)
+			break;
+		timeout--;
+		if (timeout == 0) {
+			/* This should not happen */
+			pr_err("VC is not resetting properly\n");
+			writel_iowmb(0x00000000, VCAP_SW_RESET_REQ);
+			break;
+		}
+	}
+
+	reg = readl_relaxed(VCAP_VC_NPL_CTRL);
+	reg = readl_relaxed(VCAP_VC_NPL_CTRL);
+	writel_iowmb(0x00000002, VCAP_VC_NPL_CTRL);
 }
 
 int config_vc_format(struct vcap_client_data *c_data)
@@ -336,21 +352,20 @@
 	dev = c_data->dev;
 
 	/* restart VC */
-	writel_relaxed(0x00000001, VCAP_SW_RESET_REQ);
+	writel_iowmb(0x00000102, VCAP_VC_NPL_CTRL);
+	writel_iowmb(0x00000001, VCAP_SW_RESET_REQ);
 	timeout = 10000;
 	while (1) {
-		rc = (readl_relaxed(VCAP_SW_RESET_STATUS) & 0x1);
-		if (!rc)
+		if (!(readl_relaxed(VCAP_SW_RESET_STATUS) & 0x1))
 			break;
 		timeout--;
 		if (timeout == 0) {
 			pr_err("VC is not resetting properly\n");
+			writel_iowmb(0x00000002, VCAP_VC_NPL_CTRL);
 			return -EINVAL;
 		}
 	}
-	writel_relaxed(0x00000000, VCAP_SW_RESET_REQ);
 
-	writel_iowmb(0x00000102, VCAP_VC_NPL_CTRL);
 	rc = readl_relaxed(VCAP_VC_NPL_CTRL);
 	rc = readl_relaxed(VCAP_VC_NPL_CTRL);
 	writel_iowmb(0x00000002, VCAP_VC_NPL_CTRL);
@@ -359,7 +374,9 @@
 	writel_iowmb(0x00000002, VCAP_VC_NPL_CTRL);
 	writel_iowmb(0x00000004 | vc_format->color_space << 1 |
 			vc_format->mode << 3 |
-			vc_format->mode << 10, VCAP_VC_CTRL);
+			(c_data->vc_action.tot_buf - 2) << 4 |
+			vc_format->mode << 10,
+			VCAP_VC_CTRL);
 
 	writel_relaxed(vc_format->h_polar << 4 |
 			vc_format->v_polar << 0, VCAP_VC_POLARITY);
diff --git a/drivers/media/video/vcap_vc.h b/drivers/media/video/vcap_vc.h
index 792fb14..7f42c7f 100644
--- a/drivers/media/video/vcap_vc.h
+++ b/drivers/media/video/vcap_vc.h
@@ -19,14 +19,8 @@
 
 #define VCAP_HARDWARE_VERSION 0x10000000
 
-#define VCAP_BASE (dev->vcapbase)
-#define VCAP_OFFSET(off) (VCAP_BASE + off)
-
 #define VCAP_HARDWARE_VERSION_REG (VCAP_BASE + 0x0000)
 
-#define VCAP_SW_RESET_REQ (VCAP_BASE + 0x0024)
-#define VCAP_SW_RESET_STATUS (VCAP_BASE + 0x0028)
-
 #define VCAP_VC_CTRL (VCAP_BASE + 0x0800)
 #define VCAP_VC_NPL_CTRL (VCAP_BASE + 0x0804)
 #define VCAP_VC_POLARITY (VCAP_BASE + 0x081c)
@@ -68,6 +62,7 @@
 #define VCAP_VC_TIMESTAMP (VCAP_BASE + 0x0034)
 
 #define VC_BUFFER_WRITTEN (0x3 << 1)
+#define VC_BUFFER_MASK 0x7E
 
 int vc_start_capture(struct vcap_client_data *c_data);
 int vc_hw_kick_off(struct vcap_client_data *c_data);
diff --git a/drivers/media/video/vcap_vp.c b/drivers/media/video/vcap_vp.c
index 9f2ead4..139de28 100644
--- a/drivers/media/video/vcap_vp.c
+++ b/drivers/media/video/vcap_vp.c
@@ -74,8 +74,14 @@
 	dev = c_data->dev;
 	dprintk(2, "Start setup buffers\n");
 
+	if (dev->vp_shutdown) {
+		dprintk(1, "%s: VP shutting down, no buf setup\n",
+			__func__);
+		return -EPERM;
+	}
+
 	/* No need to verify vp_client is not NULL caller does so */
-	vp_act = &dev->vp_client->vid_vp_action;
+	vp_act = &dev->vp_client->vp_action;
 
 	spin_lock_irqsave(&dev->vp_client->cap_slock, flags);
 	if (list_empty(&vp_act->in_active)) {
@@ -163,11 +169,10 @@
 	}
 }
 
-void update_nr_value(struct vcap_client_data *c_data)
+void update_nr_value(struct vcap_dev *dev)
 {
-	struct vcap_dev *dev = c_data->dev;
 	struct nr_param *par;
-	par = &c_data->vid_vp_action.nr_param;
+	par = &dev->nr_param;
 	if (par->mode == NR_MANUAL) {
 		writel_relaxed(par->window << 24 | par->decay_ratio << 20,
 			VCAP_VP_NR_CONFIG);
@@ -184,7 +189,7 @@
 			par->chroma.blend_limit_ratio << 0,
 			VCAP_VP_NR_CHROMA_CONFIG);
 	}
-	c_data->vid_vp_action.nr_update = false;
+	dev->nr_update = false;
 }
 
 static void vp_wq_fnc(struct work_struct *work)
@@ -204,7 +209,7 @@
 	else
 		return;
 
-	vp_act = &dev->vp_client->vid_vp_action;
+	vp_act = &dev->vp_client->vp_action;
 
 	rc = readl_relaxed(VCAP_OFFSET(0x048));
 	while (!(rc & 0x00000100))
@@ -216,8 +221,8 @@
 	writel_relaxed(0x40000000, VCAP_VP_REDUCT_AVG_MOTION2);
 
 	spin_lock_irqsave(&dev->vp_client->cap_slock, flags);
-	if (vp_act->nr_update == true)
-		update_nr_value(dev->vp_client);
+	if (dev->nr_update == true)
+		update_nr_value(dev);
 	spin_unlock_irqrestore(&dev->vp_client->cap_slock, flags);
 
 	/* Queue the done buffers */
@@ -238,7 +243,7 @@
 #endif
 
 	/* Cycle Buffers*/
-	if (vp_work->cd->vid_vp_action.nr_param.mode) {
+	if (dev->nr_param.mode) {
 		if (vp_act->bufNR.nr_pos == TM1_BUF)
 			vp_act->bufNR.nr_pos = BUF_NOT_IN_USE;
 
@@ -262,6 +267,8 @@
 		writel_relaxed(0x00000000, VCAP_VP_INTERRUPT_ENABLE);
 		writel_iowmb(irq, VCAP_VP_INT_CLEAR);
 		atomic_set(&dev->vp_enabled, 0);
+		if (dev->vp_shutdown)
+			wake_up(&dev->vp_dummy_waitq);
 		return;
 	}
 
@@ -320,7 +327,7 @@
 	}
 
 	dprintk(1, "%s: irq=0x%08x\n", __func__, irq);
-	if (!(irq & (VP_PIC_DONE || VP_MODE_CHANGE))) {
+	if (!(irq & (VP_PIC_DONE | VP_MODE_CHANGE))) {
 		writel_relaxed(irq, VCAP_VP_INT_CLEAR);
 		pr_err("VP IRQ shows some error\n");
 		return IRQ_HANDLED;
@@ -332,7 +339,7 @@
 		return IRQ_HANDLED;
 	}
 
-	vp_act = &dev->vp_client->vid_vp_action;
+	vp_act = &dev->vp_client->vp_action;
 	c_data = dev->vp_client;
 
 	if (vp_act->vp_state == VP_UNKNOWN) {
@@ -350,30 +357,60 @@
 	return IRQ_HANDLED;
 }
 
+int vp_sw_reset(struct vcap_dev *dev)
+{
+	int timeout;
+	writel_iowmb(0x00000010, VCAP_SW_RESET_REQ);
+	timeout = 10000;
+	while (1) {
+		if (!(readl_relaxed(VCAP_SW_RESET_STATUS) & 0x10))
+			break;
+		timeout--;
+		if (timeout == 0) {
+			/* This should not happen */
+			pr_err("VP is not resetting properly\n");
+			writel_iowmb(0x00000000, VCAP_SW_RESET_REQ);
+			return -EINVAL;
+		}
+	}
+	return 0;
+}
+
 void vp_stop_capture(struct vcap_client_data *c_data)
 {
 	struct vcap_dev *dev = c_data->dev;
+	int rc;
 
-	writel_iowmb(0x00000000, VCAP_VP_CTRL);
+	dev->vp_shutdown = true;
 	flush_workqueue(dev->vcap_wq);
 
-	if (atomic_read(&dev->vp_enabled) == 1)
-		disable_irq(dev->vpirq->start);
+	if (atomic_read(&dev->vp_enabled) == 1) {
+		rc = wait_event_interruptible_timeout(dev->vp_dummy_waitq,
+				!atomic_read(&dev->vp_enabled),
+				msecs_to_jiffies(50));
+		if (rc == 0 && atomic_read(&dev->vp_enabled) == 1) {
+			/* This should not happen, if it does hw is stuck */
+			pr_err("%s: VP Timeout and VP still running\n",
+				__func__);
+		}
+	}
 
-	writel_iowmb(0x00000001, VCAP_VP_SW_RESET);
-	writel_iowmb(0x00000000, VCAP_VP_SW_RESET);
+	vp_sw_reset(dev);
+	dev->vp_shutdown = false;
 }
 
 int config_vp_format(struct vcap_client_data *c_data)
 {
 	struct vcap_dev *dev = c_data->dev;
+	int rc;
 
 	INIT_WORK(&dev->vp_to_vc_work.work, mov_buf_to_vc);
 	dev->vp_to_vc_work.cd = c_data;
 
 	/* SW restart VP */
-	writel_iowmb(0x00000001, VCAP_VP_SW_RESET);
-	writel_iowmb(0x00000000, VCAP_VP_SW_RESET);
+	rc = vp_sw_reset(dev);
+	if (rc < 0)
+		return rc;
 
 	/* Film Mode related settings */
 	writel_iowmb(0x00000000, VCAP_VP_FILM_PROJECTION_T0);
@@ -429,7 +466,7 @@
 	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.motionHandle) {
+	if (c_data->vp_action.motionHandle) {
 		pr_err("Motion buffer has already been created");
 		return -ENOEXEC;
 	}
@@ -463,7 +500,7 @@
 	}
 
 	memset(vaddr, 0, size);
-	c_data->vid_vp_action.motionHandle = handle;
+	c_data->vp_action.motionHandle = handle;
 
 	vaddr = NULL;
 	ion_unmap_kernel(dev->ion_client, handle);
@@ -475,14 +512,14 @@
 void deinit_motion_buf(struct vcap_client_data *c_data)
 {
 	struct vcap_dev *dev = c_data->dev;
-	if (!c_data->vid_vp_action.motionHandle) {
+	if (!c_data->vp_action.motionHandle) {
 		pr_err("Motion buffer has not been created");
 		return;
 	}
 
 	writel_iowmb(0x00000000, VCAP_VP_MOTION_EST_ADDR);
-	ion_free(dev->ion_client, c_data->vid_vp_action.motionHandle);
-	c_data->vid_vp_action.motionHandle = NULL;
+	ion_free(dev->ion_client, c_data->vp_action.motionHandle);
+	c_data->vp_action.motionHandle = NULL;
 	return;
 }
 
@@ -494,7 +531,7 @@
 	unsigned long paddr;
 	int rc;
 
-	if (c_data->vid_vp_action.bufNR.nr_handle) {
+	if (c_data->vp_action.bufNR.nr_handle) {
 		pr_err("NR buffer has already been created");
 		return -ENOEXEC;
 	}
@@ -519,16 +556,16 @@
 		return rc;
 	}
 
-	c_data->vid_vp_action.bufNR.nr_handle = handle;
-	update_nr_value(c_data);
+	c_data->vp_action.bufNR.nr_handle = handle;
+	update_nr_value(dev);
 
-	c_data->vid_vp_action.bufNR.paddr = paddr;
+	c_data->vp_action.bufNR.paddr = paddr;
 	rc = readl_relaxed(VCAP_VP_NR_CONFIG2);
 	rc |= (((c_data->vp_out_fmt.width / 16) << 20) | 0x1);
 	writel_relaxed(rc, VCAP_VP_NR_CONFIG2);
 	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;
+	c_data->vp_action.bufNR.nr_pos = NRT2_BUF;
 	return 0;
 }
 
@@ -538,11 +575,11 @@
 	struct nr_buffer *buf;
 	uint32_t rc;
 
-	if (!c_data->vid_vp_action.bufNR.nr_handle) {
+	if (!c_data->vp_action.bufNR.nr_handle) {
 		pr_err("NR buffer has not been created");
 		return;
 	}
-	buf = &c_data->vid_vp_action.bufNR;
+	buf = &c_data->vp_action.bufNR;
 
 	rc = readl_relaxed(VCAP_VP_NR_CONFIG2);
 	rc &= !(0x0FF00001);
@@ -560,27 +597,27 @@
 		return 0;
 
 	/* Verify values in range */
-	if (param->window < VP_NR_MAX_WINDOW)
+	if (param->window > VP_NR_MAX_WINDOW)
 		return -EINVAL;
-	if (param->luma.max_blend_ratio < VP_NR_MAX_RATIO)
+	if (param->luma.max_blend_ratio > VP_NR_MAX_RATIO)
 		return -EINVAL;
-	if (param->luma.scale_diff_ratio < VP_NR_MAX_RATIO)
+	if (param->luma.scale_diff_ratio > VP_NR_MAX_RATIO)
 		return -EINVAL;
-	if (param->luma.diff_limit_ratio < VP_NR_MAX_RATIO)
+	if (param->luma.diff_limit_ratio > VP_NR_MAX_RATIO)
 		return -EINVAL;
-	if (param->luma.scale_motion_ratio < VP_NR_MAX_RATIO)
+	if (param->luma.scale_motion_ratio > VP_NR_MAX_RATIO)
 		return -EINVAL;
-	if (param->luma.blend_limit_ratio < VP_NR_MAX_RATIO)
+	if (param->luma.blend_limit_ratio > VP_NR_MAX_RATIO)
 		return -EINVAL;
-	if (param->chroma.max_blend_ratio < VP_NR_MAX_RATIO)
+	if (param->chroma.max_blend_ratio > VP_NR_MAX_RATIO)
 		return -EINVAL;
-	if (param->chroma.scale_diff_ratio < VP_NR_MAX_RATIO)
+	if (param->chroma.scale_diff_ratio > VP_NR_MAX_RATIO)
 		return -EINVAL;
-	if (param->chroma.diff_limit_ratio < VP_NR_MAX_RATIO)
+	if (param->chroma.diff_limit_ratio > VP_NR_MAX_RATIO)
 		return -EINVAL;
-	if (param->chroma.scale_motion_ratio < VP_NR_MAX_RATIO)
+	if (param->chroma.scale_motion_ratio > VP_NR_MAX_RATIO)
 		return -EINVAL;
-	if (param->chroma.blend_limit_ratio < VP_NR_MAX_RATIO)
+	if (param->chroma.blend_limit_ratio > VP_NR_MAX_RATIO)
 		return -EINVAL;
 	return 0;
 }
@@ -668,20 +705,18 @@
 
 	dev->vp_dummy_event = true;
 
+	enable_irq(dev->vpirq->start);
 	writel_relaxed(0x01100101, VCAP_VP_INTERRUPT_ENABLE);
 	writel_iowmb(0x00000000, VCAP_VP_CTRL);
 	writel_iowmb(0x00010000, VCAP_VP_CTRL);
 
-	enable_irq(dev->vpirq->start);
 	rc = wait_event_interruptible_timeout(dev->vp_dummy_waitq,
 		dev->vp_dummy_complete, msecs_to_jiffies(50));
 	if (!rc && !dev->vp_dummy_complete) {
 		pr_err("%s: VP dummy event timeout", __func__);
 		rc = -ETIME;
-		writel_iowmb(0x00000000, VCAP_VP_CTRL);
 
-		writel_iowmb(0x00000001, VCAP_VP_SW_RESET);
-		writel_iowmb(0x00000000, VCAP_VP_SW_RESET);
+		vp_sw_reset(dev);
 		dev->vp_dummy_complete = false;
 	}
 
@@ -721,7 +756,7 @@
 		pr_err("No active vp client\n");
 		return -ENODEV;
 	}
-	vp_act = &dev->vp_client->vid_vp_action;
+	vp_act = &dev->vp_client->vp_action;
 
 	spin_lock_irqsave(&dev->vp_client->cap_slock, flags);
 	if (list_empty(&vp_act->in_active)) {
@@ -789,7 +824,7 @@
 		top_field = 1;
 #endif
 	vp_act->vp_state = VP_FRAME2;
-	writel_relaxed(0x01100101, VCAP_VP_INTERRUPT_ENABLE);
+	writel_relaxed(0x01100001, VCAP_VP_INTERRUPT_ENABLE);
 #ifdef TOP_FIELD_FIX
 	writel_iowmb(0x00000000 | vp_act->top_field << 0, VCAP_VP_CTRL);
 	writel_iowmb(0x00010000 | vp_act->top_field << 0, VCAP_VP_CTRL);
@@ -818,7 +853,7 @@
 		pr_err("No active vp client\n");
 		return -ENODEV;
 	}
-	vp_act = &dev->vp_client->vid_vp_action;
+	vp_act = &dev->vp_client->vp_action;
 
 	if (vp_act->vp_state == VP_UNKNOWN) {
 		pr_err("%s: VP is in an unknown state\n",
@@ -836,7 +871,7 @@
 #endif
 
 	/* Config VP & Enable Interrupt */
-	writel_relaxed(0x01100101, VCAP_VP_INTERRUPT_ENABLE);
+	writel_relaxed(0x01100001, VCAP_VP_INTERRUPT_ENABLE);
 #ifdef TOP_FIELD_FIX
 	writel_iowmb(0x00000000 | vp_act->top_field << 0, VCAP_VP_CTRL);
 	writel_iowmb(0x00010000 | vp_act->top_field << 0, VCAP_VP_CTRL);
diff --git a/drivers/media/video/vcap_vp.h b/drivers/media/video/vcap_vp.h
index b2b00e9..2ad5848 100644
--- a/drivers/media/video/vcap_vp.h
+++ b/drivers/media/video/vcap_vp.h
@@ -17,9 +17,6 @@
 
 #include <media/vcap_v4l2.h>
 
-#define VCAP_BASE (dev->vcapbase)
-#define VCAP_OFFSET(off) (VCAP_BASE + off)
-
 #define VCAP_VP_INT_STATUS (VCAP_BASE + 0x404)
 #define VCAP_VP_INT_CLEAR (VCAP_BASE + 0x40C)
 
diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c
index 2bc0938..a7d13a8 100644
--- a/drivers/media/video/videobuf2-core.c
+++ b/drivers/media/video/videobuf2-core.c
@@ -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/media/video/videobuf2-msm-mem.c b/drivers/media/video/videobuf2-msm-mem.c
index 740d183..c1a392e2 100644
--- a/drivers/media/video/videobuf2-msm-mem.c
+++ b/drivers/media/video/videobuf2-msm-mem.c
@@ -62,7 +62,7 @@
 		goto alloc_failed;
 	}
 	rc = ion_map_iommu(mem->client, mem->ion_handle,
-			CAMERA_DOMAIN, GEN_POOL, SZ_4K, 0,
+			-1, 0, SZ_4K, 0,
 			(unsigned long *)&phyaddr,
 			(unsigned long *)&len, UNCACHED, 0);
 	if (rc < 0) {
@@ -87,7 +87,7 @@
 {
 	int32_t rc = 0;
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
-	ion_unmap_iommu(mem->client, mem->ion_handle, CAMERA_DOMAIN, GEN_POOL);
+	ion_unmap_iommu(mem->client, mem->ion_handle, -1, 0);
 	ion_free(mem->client, mem->ion_handle);
 	ion_client_destroy(mem->client);
 #else
@@ -174,7 +174,8 @@
 					struct videobuf2_msm_offset *offset,
 					enum videobuf2_buffer_type buffer_type,
 					uint32_t addr_offset, int path,
-					struct ion_client *client)
+					struct ion_client *client,
+					int domain_num)
 {
 	unsigned long len;
 	int rc = 0;
@@ -190,7 +191,7 @@
 		pr_err("%s ION import failed\n", __func__);
 		return PTR_ERR(mem->ion_handle);
 	}
-	rc = ion_map_iommu(client, mem->ion_handle, CAMERA_DOMAIN, GEN_POOL,
+	rc = ion_map_iommu(client, mem->ion_handle, domain_num, 0,
 		SZ_4K, 0, (unsigned long *)&mem->phyaddr, &len, UNCACHED, 0);
 	if (rc < 0)
 		ion_free(client, mem->ion_handle);
@@ -220,12 +221,12 @@
 EXPORT_SYMBOL_GPL(videobuf2_pmem_contig_user_get);
 
 void videobuf2_pmem_contig_user_put(struct videobuf2_contig_pmem *mem,
-					struct ion_client *client)
+				struct ion_client *client, int domain_num)
 {
 	if (mem->is_userptr) {
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 		ion_unmap_iommu(client, mem->ion_handle,
-				CAMERA_DOMAIN, GEN_POOL);
+				domain_num, 0);
 		ion_free(client, mem->ion_handle);
 #elif CONFIG_ANDROID_PMEM
 		put_pmem_file(mem->file);
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 8c392fc..464f19f 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -248,7 +248,7 @@
 
 config MARIMBA_CORE
 	tristate "Marimba Core"
-	depends on I2C && (ARCH_MSM7X30 || ARCH_MSM8X60 || ARCH_MSM7X27A)
+	depends on I2C && (ARCH_MSM7X30 || ARCH_MSM8X60 || ARCH_MSM7X27A || ARCH_MSM8960)
 	default n
 	help
 	  Enables the Marimba Core driver. The core driver provides
diff --git a/drivers/mfd/pm8018-core.c b/drivers/mfd/pm8018-core.c
index b1b64cb..a91152f 100644
--- a/drivers/mfd/pm8018-core.c
+++ b/drivers/mfd/pm8018-core.c
@@ -45,7 +45,6 @@
 #define PM8018_REVISION_MASK	0x000F
 
 #define REG_PM8018_PON_CNTRL_3	0x01D
-#define PM8018_RESTART_REASON_MASK	0x07
 
 #define SINGLE_IRQ_RESOURCE(_name, _irq) \
 { \
@@ -61,6 +60,7 @@
 	struct mfd_cell					*mfd_regulators;
 	struct pm8xxx_regulator_core_platform_data	*regulator_cdata;
 	u32						rev_registers;
+	u8						restart_reason;
 };
 
 static int pm8018_readb(const struct device *dev, u16 addr, u8 *val)
@@ -125,6 +125,14 @@
 	return pmic->rev_registers & PM8018_REVISION_MASK;
 }
 
+static u8 pm8018_restart_reason(const struct device *dev)
+{
+	const struct pm8xxx_drvdata *pm8018_drvdata = dev_get_drvdata(dev);
+	const struct pm8018 *pmic = pm8018_drvdata->pm_chip_data;
+
+	return pmic->restart_reason;
+}
+
 static struct pm8xxx_drvdata pm8018_drvdata = {
 	.pmic_readb		= pm8018_readb,
 	.pmic_writeb		= pm8018_writeb,
@@ -133,6 +141,7 @@
 	.pmic_read_irq_stat	= pm8018_read_irq_stat,
 	.pmic_get_version	= pm8018_get_version,
 	.pmic_get_revision	= pm8018_get_revision,
+	.pmic_restart_reason	= pm8018_restart_reason,
 };
 
 static const struct resource gpio_cell_resources[] __devinitconst = {
@@ -516,17 +525,6 @@
 	return ret;
 }
 
-static const char * const pm8018_restart_reason[] = {
-	[0] = "Unknown",
-	[1] = "Triggered from CBL (external charger)",
-	[2] = "Triggered from KPD (power key press)",
-	[3] = "Triggered from CHG (usb charger insertion)",
-	[4] = "Triggered from SMPL (sudden momentary power loss)",
-	[5] = "Triggered from RTC (real time clock)",
-	[6] = "Triggered by Hard Reset",
-	[7] = "Triggered by General Purpose Trigger",
-};
-
 static const char * const pm8018_rev_names[] = {
 	[PM8XXX_REVISION_8018_TEST]	= "test",
 	[PM8XXX_REVISION_8018_1p0]	= "1.0",
@@ -594,8 +592,9 @@
 		pr_err("Cannot read restart reason rc=%d\n", rc);
 		goto err_read_rev;
 	}
-	val &= PM8018_RESTART_REASON_MASK;
-	pr_info("PMIC Restart Reason: %s\n", pm8018_restart_reason[val]);
+	val &= PM8XXX_RESTART_REASON_MASK;
+	pr_info("PMIC Restart Reason: %s\n", pm8xxx_restart_reason_str[val]);
+	pmic->restart_reason = val;
 
 	rc = pm8018_add_subdevices(pdata, pmic);
 	if (rc) {
diff --git a/drivers/mfd/pm8038-core.c b/drivers/mfd/pm8038-core.c
index b32932b..9815f6e 100644
--- a/drivers/mfd/pm8038-core.c
+++ b/drivers/mfd/pm8038-core.c
@@ -34,7 +34,7 @@
 #define REG_IRQ_BASE            0x1BB
 
 #define REG_SPK_BASE		0x253
-#define REG_SPK_REGISTERS	3
+#define REG_SPK_REGISTERS	6
 
 #define REG_TEMP_ALARM_CTRL	0x01B
 #define REG_TEMP_ALARM_PWM	0x09B
@@ -44,7 +44,6 @@
 #define PM8038_REVISION_MASK	0x000F
 
 #define REG_PM8038_PON_CNTRL_3	0x01D
-#define PM8038_RESTART_REASON_MASK	0x07
 
 #define SINGLE_IRQ_RESOURCE(_name, _irq) \
 { \
@@ -60,6 +59,7 @@
 	struct mfd_cell					*mfd_regulators;
 	struct pm8xxx_regulator_core_platform_data	*regulator_cdata;
 	u32						rev_registers;
+	u8						restart_reason;
 };
 
 static int pm8038_readb(const struct device *dev, u16 addr, u8 *val)
@@ -124,6 +124,14 @@
 	return pmic->rev_registers & PM8038_REVISION_MASK;
 }
 
+static u8 pm8038_restart_reason(const struct device *dev)
+{
+	const struct pm8xxx_drvdata *pm8038_drvdata = dev_get_drvdata(dev);
+	const struct pm8038 *pmic = pm8038_drvdata->pm_chip_data;
+
+	return pmic->restart_reason;
+}
+
 static struct pm8xxx_drvdata pm8038_drvdata = {
 	.pmic_readb		= pm8038_readb,
 	.pmic_writeb		= pm8038_writeb,
@@ -132,6 +140,7 @@
 	.pmic_read_irq_stat	= pm8038_read_irq_stat,
 	.pmic_get_version	= pm8038_get_version,
 	.pmic_get_revision	= pm8038_get_revision,
+	.pmic_restart_reason	= pm8038_restart_reason,
 };
 
 static const struct resource gpio_cell_resources[] __devinitconst = {
@@ -284,7 +293,7 @@
 	[0] = {
 		.name   = PM8XXX_SPK_DEV_NAME,
 		.start  = REG_SPK_BASE,
-		.end    = REG_SPK_BASE + REG_SPK_REGISTERS,
+		.end    = REG_SPK_BASE + REG_SPK_REGISTERS - 1,
 		.flags  = IORESOURCE_IO,
 	},
 };
@@ -674,17 +683,6 @@
 	return ret;
 }
 
-static const char * const pm8038_restart_reason[] = {
-	[0] = "Unknown",
-	[1] = "Triggered from CBL (external charger)",
-	[2] = "Triggered from KPD (power key press)",
-	[3] = "Triggered from CHG (usb charger insertion)",
-	[4] = "Triggered from SMPL (sudden momentary power loss)",
-	[5] = "Triggered from RTC (real time clock)",
-	[6] = "Triggered by Hard Reset",
-	[7] = "Triggered by General Purpose Trigger",
-};
-
 static const char * const pm8038_rev_names[] = {
 	[PM8XXX_REVISION_8038_TEST]	= "test",
 	[PM8XXX_REVISION_8038_1p0]	= "1.0",
@@ -753,8 +751,9 @@
 		pr_err("Cannot read restart reason rc=%d\n", rc);
 		goto err_read_rev;
 	}
-	val &= PM8038_RESTART_REASON_MASK;
-	pr_info("PMIC Restart Reason: %s\n", pm8038_restart_reason[val]);
+	val &= PM8XXX_RESTART_REASON_MASK;
+	pr_info("PMIC Restart Reason: %s\n", pm8xxx_restart_reason_str[val]);
+	pmic->restart_reason = val;
 
 	rc = pm8038_add_subdevices(pdata, pmic);
 	if (rc) {
diff --git a/drivers/mfd/pm8821-core.c b/drivers/mfd/pm8821-core.c
index 1d3c927a..86bd5ec 100644
--- a/drivers/mfd/pm8821-core.c
+++ b/drivers/mfd/pm8821-core.c
@@ -29,6 +29,9 @@
 #define REG_MPP_BASE		0x050
 #define REG_IRQ_BASE		0x100
 
+#define REG_TEMP_ALARM_CTRL	0x01B
+#define REG_TEMP_ALARM_PWM	0x09B
+
 #define PM8821_VERSION_MASK	0xFFF0
 #define PM8821_VERSION_VALUE	0x0BF0
 #define PM8821_REVISION_MASK	0x000F
@@ -142,6 +145,29 @@
 	.pdata_size	= sizeof("pm8821-dbg"),
 };
 
+static const struct resource thermal_alarm_cell_resources[] __devinitconst = {
+	SINGLE_IRQ_RESOURCE("pm8821_tempstat_irq", PM8821_TEMPSTAT_IRQ),
+	SINGLE_IRQ_RESOURCE("pm8821_overtemp_irq", PM8821_OVERTEMP_IRQ),
+};
+
+static struct pm8xxx_tm_core_data thermal_alarm_cdata = {
+	.adc_type			= PM8XXX_TM_ADC_NONE,
+	.reg_addr_temp_alarm_ctrl	= REG_TEMP_ALARM_CTRL,
+	.reg_addr_temp_alarm_pwm	= REG_TEMP_ALARM_PWM,
+	.tm_name			= "pm8821_tz",
+	.irq_name_temp_stat		= "pm8821_tempstat_irq",
+	.irq_name_over_temp		= "pm8821_overtemp_irq",
+	.default_no_adc_temp		= 37000,
+};
+
+static struct mfd_cell thermal_alarm_cell __devinitdata = {
+	.name		= PM8XXX_TM_DEV_NAME,
+	.id		= 1,
+	.resources	= thermal_alarm_cell_resources,
+	.num_resources	= ARRAY_SIZE(thermal_alarm_cell_resources),
+	.platform_data	= &thermal_alarm_cdata,
+	.pdata_size	= sizeof(struct pm8xxx_tm_core_data),
+};
 
 static int __devinit
 pm8821_add_subdevices(const struct pm8821_platform_data *pdata,
@@ -183,6 +209,14 @@
 		goto bail;
 	}
 
+	ret = mfd_add_devices(pmic->dev, 0, &thermal_alarm_cell, 1, NULL,
+				irq_base);
+	if (ret) {
+		pr_err("Failed to add thermal alarm subdevice ret=%d\n",
+			ret);
+		goto bail;
+	}
+
 	return 0;
 bail:
 	if (pmic->irq_chip) {
diff --git a/drivers/mfd/pm8921-core.c b/drivers/mfd/pm8921-core.c
index f39a19f..7d63129 100644
--- a/drivers/mfd/pm8921-core.c
+++ b/drivers/mfd/pm8921-core.c
@@ -63,6 +63,7 @@
 	struct mfd_cell					*mfd_regulators;
 	struct pm8xxx_regulator_core_platform_data	*regulator_cdata;
 	u32						rev_registers;
+	u8						restart_reason;
 };
 
 static int pm8921_readb(const struct device *dev, u16 addr, u8 *val)
@@ -133,6 +134,14 @@
 	return pmic->rev_registers & PM8921_REVISION_MASK;
 }
 
+static u8 pm8921_restart_reason(const struct device *dev)
+{
+	const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
+	const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
+
+	return pmic->restart_reason;
+}
+
 static struct pm8xxx_drvdata pm8921_drvdata = {
 	.pmic_readb		= pm8921_readb,
 	.pmic_writeb		= pm8921_writeb,
@@ -141,6 +150,7 @@
 	.pmic_read_irq_stat	= pm8921_read_irq_stat,
 	.pmic_get_version	= pm8921_get_version,
 	.pmic_get_revision	= pm8921_get_revision,
+	.pmic_restart_reason	= pm8921_restart_reason,
 };
 
 static struct resource gpio_cell_resources[] = {
@@ -815,17 +825,6 @@
 	return ret;
 }
 
-static const char * const pm8921_restart_reason[] = {
-	[0] = "Unknown",
-	[1] = "Triggered from CBL (external charger)",
-	[2] = "Triggered from KPD (power key press)",
-	[3] = "Triggered from CHG (usb charger insertion)",
-	[4] = "Triggered from SMPL (sudden momentary power loss)",
-	[5] = "Triggered from RTC (real time clock)",
-	[6] = "Triggered by Hard Reset",
-	[7] = "Triggered by General Purpose Trigger",
-};
-
 static const char * const pm8921_rev_names[] = {
 	[PM8XXX_REVISION_8921_TEST]	= "test",
 	[PM8XXX_REVISION_8921_1p0]	= "1.0",
@@ -918,8 +917,9 @@
 		pr_err("Cannot read restart reason rc=%d\n", rc);
 		goto err_read_rev;
 	}
-	val &= PM8921_RESTART_REASON_MASK;
-	pr_info("PMIC Restart Reason: %s\n", pm8921_restart_reason[val]);
+	val &= PM8XXX_RESTART_REASON_MASK;
+	pr_info("PMIC Restart Reason: %s\n", pm8xxx_restart_reason_str[val]);
+	pmic->restart_reason = val;
 
 	rc = pm8921_add_subdevices(pdata, pmic);
 	if (rc) {
diff --git a/drivers/mfd/pm8xxx-misc.c b/drivers/mfd/pm8xxx-misc.c
index 0af013e..6bb1441 100644
--- a/drivers/mfd/pm8xxx-misc.c
+++ b/drivers/mfd/pm8xxx-misc.c
@@ -564,6 +564,7 @@
 					   : SLEEP_CTRL_SMPL_EN_PWR_OFF));
 			break;
 		case PM8XXX_VERSION_8921:
+		case PM8XXX_VERSION_8917:
 			rc = pm8xxx_misc_masked_write(chip,
 				REG_PM8921_SLEEP_CTRL, SLEEP_CTRL_SMPL_EN_MASK,
 				(enable ? SLEEP_CTRL_SMPL_EN_RESET
@@ -624,6 +625,7 @@
 				delay);
 			break;
 		case PM8XXX_VERSION_8921:
+		case PM8XXX_VERSION_8917:
 			rc = pm8xxx_misc_masked_write(chip,
 				REG_PM8921_SLEEP_CTRL, SLEEP_CTRL_SMPL_SEL_MASK,
 				delay);
@@ -703,6 +705,7 @@
 					REG_PM8058_COIN_CHG, reg);
 			break;
 		case PM8XXX_VERSION_8921:
+		case PM8XXX_VERSION_8917:
 			rc = pm8xxx_writeb(chip->dev->parent,
 					REG_PM8921_COIN_CHG, reg);
 			break;
@@ -747,6 +750,7 @@
 		case PM8XXX_VERSION_8018:
 		case PM8XXX_VERSION_8058:
 		case PM8XXX_VERSION_8921:
+		case PM8XXX_VERSION_8917:
 			rc = pm8xxx_misc_masked_write(chip,
 				REG_PM8XXX_PON_CTRL_1, PON_CTRL_1_WD_EN_MASK,
 				(enable ? PON_CTRL_1_WD_EN_RESET
@@ -793,6 +797,7 @@
 		case PM8XXX_VERSION_8018:
 		case PM8XXX_VERSION_8058:
 		case PM8XXX_VERSION_8921:
+		case PM8XXX_VERSION_8917:
 			rc = pm8xxx_writeb(chip->dev->parent,
 				REG_PM8XXX_GP_TEST_1, PM8XXX_STAY_ON_CFG);
 			break;
@@ -884,6 +889,7 @@
 				REG_PM8901_PON_CNTL_4, REG_PM8901_PON_CNTL_5);
 			break;
 		case PM8XXX_VERSION_8921:
+		case PM8XXX_VERSION_8917:
 			__pm8xxx_hard_reset_config(chip, config,
 				REG_PM8921_PON_CNTL_4, REG_PM8921_PON_CNTL_5);
 			break;
@@ -941,6 +947,7 @@
 		case PM8XXX_VERSION_8018:
 		case PM8XXX_VERSION_8058:
 		case PM8XXX_VERSION_8921:
+		case PM8XXX_VERSION_8917:
 			rc = pm8xxx_misc_masked_write(chip,
 				REG_PM8XXX_GPIO_MUX_CTRL, UART_PATH_SEL_MASK,
 				uart_path_sel << UART_PATH_SEL_SHIFT);
@@ -1091,6 +1098,7 @@
 		switch (chip->version) {
 		case PM8XXX_VERSION_8038:
 		case PM8XXX_VERSION_8921:
+		case PM8XXX_VERSION_8917:
 			pm8xxx_misc_masked_write(chip,
 					REG_PM8XXX_XO_CNTRL_2, clk_mask, value);
 			break;
diff --git a/drivers/mfd/pm8xxx-pwm.c b/drivers/mfd/pm8xxx-pwm.c
index 022cfb6..70f4cd5 100644
--- a/drivers/mfd/pm8xxx-pwm.c
+++ b/drivers/mfd/pm8xxx-pwm.c
@@ -815,8 +815,8 @@
 		if (pwm_chip->is_lpg_supported) {
 			if (pwm->dtest_mode_supported)
 				pm8xxx_pwm_set_dtest(pwm, 1);
-			rc = pm8xxx_pwm_bank_enable(pwm, 1);
 			pm8xxx_pwm_bank_sel(pwm);
+			rc = pm8xxx_pwm_bank_enable(pwm, 1);
 			pm8xxx_pwm_start(pwm, 1, 0);
 		} else {
 			pm8xxx_pwm_enable(pwm);
@@ -1065,9 +1065,9 @@
 		if (pwm->dtest_mode_supported)
 			pm8xxx_pwm_set_dtest(pwm, 1);
 
+		pm8xxx_pwm_bank_sel(pwm);
 		pm8xxx_pwm_bank_enable(pwm, 1);
 
-		pm8xxx_pwm_bank_sel(pwm);
 		pm8xxx_pwm_start(pwm, 1, 1);
 	} else {
 		if (pwm->dtest_mode_supported)
diff --git a/drivers/mfd/pm8xxx-spk.c b/drivers/mfd/pm8xxx-spk.c
index 2de70f4..8ba7372 100644
--- a/drivers/mfd/pm8xxx-spk.c
+++ b/drivers/mfd/pm8xxx-spk.c
@@ -22,8 +22,11 @@
 #include <linux/mfd/pm8xxx/spk.h>
 
 #define PM8XXX_SPK_CTL1_REG_OFF		0
-#define PM8XXX_SPK_TEST_REG_1_OFF	1
-#define PM8XXX_SPK_TEST_REG_2_OFF	2
+#define PM8XXX_SPK_CTL2_REG_OFF		1
+#define PM8XXX_SPK_CTL3_REG_OFF		2
+#define PM8XXX_SPK_CTL4_REG_OFF		3
+#define PM8XXX_SPK_TEST_REG_1_OFF	4
+#define PM8XXX_SPK_TEST_REG_2_OFF	5
 
 #define PM8XXX_SPK_BANK_SEL		4
 #define PM8XXX_SPK_BANK_WRITE		0x80
@@ -136,7 +139,7 @@
 	val = pm8xxx_spk_read(PM8XXX_SPK_CTL1_REG_OFF);
 	if (val < 0)
 		return val;
-	val |= (gain << 4);
+	val = (gain << 4) | (val & 0xF);
 	ret = pm8xxx_spk_write(PM8XXX_SPK_CTL1_REG_OFF, val);
 	if (!ret) {
 		pm8xxx_spk_bank_write(the_spk_chip->base
@@ -194,6 +197,7 @@
 {
 	const struct pm8xxx_spk_platform_data *pdata = pdev->dev.platform_data;
 	int ret = 0;
+	u8 value = 0;
 
 	if (!pdata) {
 		pr_err("missing platform data\n");
@@ -236,6 +240,23 @@
 		if (ret < 0)
 			goto err_handle;
 	}
+	value = ((the_spk_chip->pdata.cd_ng_threshold << 5) |
+		the_spk_chip->pdata.cd_nf_preamp_bias << 3);
+	pr_debug("Setting SPK_CTL2_REG = %02x\n", value);
+	pm8xxx_spk_write(PM8XXX_SPK_CTL2_REG_OFF, value);
+
+	value = ((the_spk_chip->pdata.cd_ng_hold << 5) |
+		(the_spk_chip->pdata.cd_ng_max_atten << 1) |
+		the_spk_chip->pdata.noise_mute);
+	pr_debug("Setting SPK_CTL3_REG = %02x\n", value);
+	pm8xxx_spk_write(PM8XXX_SPK_CTL3_REG_OFF, value);
+
+	value = ((the_spk_chip->pdata.cd_ng_decay_rate << 5) |
+		(the_spk_chip->pdata.cd_ng_attack_rate << 3) |
+		the_spk_chip->pdata.cd_delay << 2);
+	pr_debug("Setting SPK_CTL4_REG = %02x\n", value);
+	pm8xxx_spk_write(PM8XXX_SPK_CTL4_REG_OFF, value);
+
 	return pm8xxx_spk_config();
 err_handle:
 	pr_err("pm8xxx_spk_probe failed."
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index 05707fd..0ea843c 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -27,9 +27,9 @@
 #include <linux/i2c.h>
 #include <sound/soc.h>
 
-#define WCD9XXX_SLIM_GLA_MAX_RETRIES 5
 #define WCD9XXX_REGISTER_START_OFFSET 0x800
 #define WCD9XXX_SLIM_RW_MAX_TRIES 3
+#define SLIMBUS_PRESENT_TIMEOUT 100
 
 #define MAX_WCD9XXX_DEVICE	4
 #define TABLA_I2C_MODE	0x03
@@ -253,6 +253,18 @@
 	},
 };
 
+static struct wcd9xx_codec_type {
+	u8 byte[4];
+	struct mfd_cell *dev;
+	int size;
+} wcd9xxx_codecs[] = {
+	{{0x2, 0x0, 0x0, 0x1}, tabla_devs, ARRAY_SIZE(tabla_devs)},
+	{{0x1, 0x0, 0x0, 0x1}, tabla1x_devs, ARRAY_SIZE(tabla1x_devs)},
+	{{0x0, 0x0, 0x2, 0x1}, taiko_devs, ARRAY_SIZE(taiko_devs)},
+	{{0x0, 0x0, 0x0, 0x1}, sitar_devs, ARRAY_SIZE(sitar_devs)},
+	{{0x1, 0x0, 0x1, 0x1}, sitar_devs, ARRAY_SIZE(sitar_devs)},
+};
+
 static void wcd9xxx_bring_up(struct wcd9xxx *wcd9xxx)
 {
 	wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 0x4);
@@ -283,8 +295,6 @@
 			return ret;
 		}
 
-		gpio_direction_output(wcd9xxx->reset_gpio, 1);
-		msleep(20);
 		gpio_direction_output(wcd9xxx->reset_gpio, 0);
 		msleep(20);
 		gpio_direction_output(wcd9xxx->reset_gpio, 1);
@@ -300,6 +310,53 @@
 		wcd9xxx->reset_gpio = 0;
 	}
 }
+static int wcd9xxx_check_codec_type(struct wcd9xxx *wcd9xxx,
+					struct mfd_cell **wcd9xxx_dev,
+					int *wcd9xxx_dev_size)
+{
+	struct wcd9xx_codec_type *cdc = wcd9xxx_codecs;
+	int index;
+	int ret;
+	index = WCD9XXX_A_CHIP_ID_BYTE_0;
+	while (index <= WCD9XXX_A_CHIP_ID_BYTE_3) {
+		ret = wcd9xxx_reg_read(wcd9xxx, index);
+		if (ret < 0)
+			goto exit;
+		wcd9xxx->idbyte[index-WCD9XXX_A_CHIP_ID_BYTE_0] = (u8)ret;
+		pr_debug("%s: wcd9xx read = %x, byte = %x\n", __func__, ret,
+			index);
+		index++;
+	}
+
+	/* Read codec version */
+	ret = wcd9xxx_reg_read(wcd9xxx, WCD9XXX_A_CHIP_VERSION);
+	if (ret < 0)
+		goto exit;
+	wcd9xxx->version = (u8)ret & 0x1F;
+
+	while (cdc < (cdc + ARRAY_SIZE(wcd9xxx_codecs)) && cdc != NULL) {
+		if ((cdc->byte[0] == wcd9xxx->idbyte[0]) &&
+		    (cdc->byte[1] == wcd9xxx->idbyte[1]) &&
+		    (cdc->byte[2] == wcd9xxx->idbyte[2]) &&
+		    (cdc->byte[3] == wcd9xxx->idbyte[3])) {
+			pr_info("%s: codec is %s", __func__, cdc->dev->name);
+			*wcd9xxx_dev = cdc->dev;
+			*wcd9xxx_dev_size = cdc->size;
+			break;
+		}
+		cdc++;
+	}
+	if (*wcd9xxx_dev == NULL || *wcd9xxx_dev_size == 0)
+		ret = -ENODEV;
+	pr_info("%s: Read codec idbytes & version\n"
+		"byte_0[%08x] byte_1[%08x] byte_2[%08x]\n"
+		" byte_3[%08x] version = %x\n", __func__,
+		wcd9xxx->idbyte[0], wcd9xxx->idbyte[1],
+		wcd9xxx->idbyte[2], wcd9xxx->idbyte[3],
+		wcd9xxx->version);
+exit:
+	return ret;
+}
 
 static int wcd9xxx_device_init(struct wcd9xxx *wcd9xxx, int irq)
 {
@@ -328,31 +385,11 @@
 			goto err;
 		}
 	}
+	ret = wcd9xxx_check_codec_type(wcd9xxx, &wcd9xxx_dev,
+					&wcd9xxx_dev_size);
 
-	wcd9xxx->idbyte_0 = wcd9xxx_reg_read(wcd9xxx, WCD9XXX_A_CHIP_ID_BYTE_0);
-	wcd9xxx->idbyte_1 = wcd9xxx_reg_read(wcd9xxx, WCD9XXX_A_CHIP_ID_BYTE_1);
-	wcd9xxx->idbyte_2 = wcd9xxx_reg_read(wcd9xxx, WCD9XXX_A_CHIP_ID_BYTE_2);
-	wcd9xxx->idbyte_3 = wcd9xxx_reg_read(wcd9xxx, WCD9XXX_A_CHIP_ID_BYTE_3);
-
-	wcd9xxx->version = wcd9xxx_reg_read(wcd9xxx,
-			WCD9XXX_A_CHIP_VERSION) & 0x1F;
-	pr_info("%s : Codec version %u initialized\n",
-		__func__, wcd9xxx->version);
-
-	if (wcd9xxx->idbyte_0 == 0x2) {
-		wcd9xxx_dev = tabla_devs;
-		wcd9xxx_dev_size = ARRAY_SIZE(tabla_devs);
-	} 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);
-	}
+	if (ret < 0)
+		goto err_irq;
 	ret = mfd_add_devices(wcd9xxx->dev, -1, wcd9xxx_dev, wcd9xxx_dev_size,
 			      NULL, 0);
 	if (ret != 0) {
@@ -766,9 +803,9 @@
 		goto err_device_init;
 	}
 
-	if ((wcd9xxx->idbyte_0 == 0x2) || (wcd9xxx->idbyte_0 == 0x1))
+	if ((wcd9xxx->idbyte[0] == 0x2) || (wcd9xxx->idbyte[0] == 0x1))
 		i2c_mode = TABLA_I2C_MODE;
-	else if (wcd9xxx->idbyte_0 == 0x0)
+	else if (wcd9xxx->idbyte[0] == 0x0)
 		i2c_mode = SITAR_I2C_MODE;
 
 	ret = wcd9xxx_read(wcd9xxx, WCD9XXX_A_CHIP_STATUS, 1, &val, 0);
@@ -1046,12 +1083,31 @@
 	return NULL;
 }
 
+static int wcd9xxx_slim_get_laddr(struct slim_device *sb,
+				  const u8 *e_addr, u8 e_len, u8 *laddr)
+{
+	int ret;
+	const unsigned long timeout = jiffies +
+				      msecs_to_jiffies(SLIMBUS_PRESENT_TIMEOUT);
+
+	do {
+		ret = slim_get_logical_addr(sb, e_addr, e_len, laddr);
+		if (!ret)
+			break;
+		/* Give SLIMBUS time to report present and be ready. */
+		usleep_range(1000, 1000);
+		pr_debug_ratelimited("%s: retyring get logical addr\n",
+				     __func__);
+	} while time_before(jiffies, timeout);
+
+	return ret;
+}
+
 static int wcd9xxx_slim_probe(struct slim_device *slim)
 {
 	struct wcd9xxx *wcd9xxx;
 	struct wcd9xxx_pdata *pdata;
 	int ret = 0;
-	int sgla_retry_cnt;
 
 	if (slim->dev.of_node) {
 		dev_info(&slim->dev, "Platform data from device tree\n");
@@ -1096,10 +1152,12 @@
 		goto err_supplies;
 	}
 
-	ret = slim_get_logical_addr(wcd9xxx->slim, wcd9xxx->slim->e_addr,
-		ARRAY_SIZE(wcd9xxx->slim->e_addr), &wcd9xxx->slim->laddr);
+	ret = wcd9xxx_slim_get_laddr(wcd9xxx->slim, wcd9xxx->slim->e_addr,
+				     ARRAY_SIZE(wcd9xxx->slim->e_addr),
+				     &wcd9xxx->slim->laddr);
 	if (ret) {
-		pr_err("fail to get slimbus logical address %d\n", ret);
+		pr_err("%s: failed to get slimbus %s logical address: %d\n",
+		       __func__, wcd9xxx->slim->name, ret);
 		goto err_reset;
 	}
 	wcd9xxx->read_dev = wcd9xxx_slim_read_device;
@@ -1108,11 +1166,8 @@
 	wcd9xxx->irq_base = pdata->irq_base;
 	wcd9xxx_pgd_la = wcd9xxx->slim->laddr;
 
-	if (pdata->num_irqs < TABLA_NUM_IRQS) {
-		pr_err("%s: Error, not enough interrupt lines allocated\n",
-			__func__);
-		goto err_reset;
-	}
+	if (pdata->num_irqs < TABLA_NUM_IRQS)
+		pr_warn("%s: Not enough interrupt lines allocated\n", __func__);
 
 	wcd9xxx->slim_slave = &pdata->slimbus_slave_device;
 
@@ -1122,28 +1177,14 @@
 		goto err_reset;
 	}
 
-	sgla_retry_cnt = 0;
-
-	while (1) {
-		ret = slim_get_logical_addr(wcd9xxx->slim_slave,
-			wcd9xxx->slim_slave->e_addr,
-			ARRAY_SIZE(wcd9xxx->slim_slave->e_addr),
-			&wcd9xxx->slim_slave->laddr);
-		if (ret) {
-			if (sgla_retry_cnt++ < WCD9XXX_SLIM_GLA_MAX_RETRIES) {
-				/* Give SLIMBUS slave time to report present
-				   and be ready.
-				 */
-				usleep_range(1000, 1000);
-				pr_debug("%s: retry slim_get_logical_addr()\n",
-					__func__);
-				continue;
-			}
-			pr_err("fail to get slimbus slave logical address"
-				" %d\n", ret);
-			goto err_slim_add;
-		}
-		break;
+	ret = wcd9xxx_slim_get_laddr(wcd9xxx->slim_slave,
+				     wcd9xxx->slim_slave->e_addr,
+				     ARRAY_SIZE(wcd9xxx->slim_slave->e_addr),
+				     &wcd9xxx->slim_slave->laddr);
+	if (ret) {
+		pr_err("%s: failed to get slimbus %s logical address: %d\n",
+		       __func__, wcd9xxx->slim->name, ret);
+		goto err_slim_add;
 	}
 	wcd9xxx_inf_la = wcd9xxx->slim_slave->laddr;
 	wcd9xxx_intf = WCD9XXX_INTERFACE_TYPE_SLIMBUS;
diff --git a/drivers/mfd/wcd9xxx-slimslave.c b/drivers/mfd/wcd9xxx-slimslave.c
index 71c68ac..b4cf435 100644
--- a/drivers/mfd/wcd9xxx-slimslave.c
+++ b/drivers/mfd/wcd9xxx-slimslave.c
@@ -535,7 +535,6 @@
 				unsigned int ch_cnt)
 {
 	u16 grph = 0;
-	u32 sph[SLIM_MAX_RX_PORTS] = {0};
 	int i = 0 , idx = 0;
 	int ret = 0;
 	struct wcd9xxx_slim_sch_rx *rx = sh_ch.rx;
@@ -549,10 +548,9 @@
 			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);
+		pr_debug("%s: ch_num[%d] %d, idx %d, grph %x\n",
+			 __func__, i, ch_num[i], idx, grph);
 	}
 
 	/* slim_control_ch (REMOVE) */
@@ -561,12 +559,6 @@
 		pr_err("%s: slim_control_ch failed ret[%d]\n", __func__, ret);
 		goto err;
 	}
-	/* slim_disconnect_port */
-	ret = slim_disconnect_ports(wcd9xxx->slim, sph, ch_cnt);
-	if (ret < 0) {
-		pr_err("%s: slim_disconnect_ports failed ret[%d]\n",
-			 __func__, ret);
-	}
 	for (i = 0; i < ch_cnt; i++) {
 		idx = (ch_num[i] - BASE_CH_NUM - sh_ch.rx_port_start_offset);
 		rx[idx].grph = 0;
@@ -580,7 +572,6 @@
 			      unsigned int ch_cnt)
 {
 	u16 grph = 0;
-	u32 sph[SLIM_MAX_TX_PORTS] = {0};
 	int ret = 0;
 	int i = 0 , idx = 0;
 	struct wcd9xxx_slim_sch_tx *tx = sh_ch.tx;
@@ -594,15 +585,8 @@
 			ret = -EINVAL;
 			goto err;
 		}
-		sph[i] = tx[idx].sph;
 		grph = tx[idx].grph;
 	}
-	/* slim_disconnect_port */
-	ret = slim_disconnect_ports(wcd9xxx->slim, sph, ch_cnt);
-	if (ret < 0) {
-		pr_err("%s: slim_disconnect_ports failed ret[%d]\n",
-				__func__, ret);
-	}
 	/* slim_control_ch (REMOVE) */
 	ret = slim_control_ch(wcd9xxx->slim, grph, SLIM_CH_REMOVE, true);
 	if (ret < 0) {
@@ -633,3 +617,48 @@
 	return ret;
 }
 EXPORT_SYMBOL_GPL(wcd9xxx_get_slave_port);
+
+int wcd9xxx_disconnect_port(struct wcd9xxx *wcd9xxx, unsigned int *ch_num,
+				unsigned int ch_cnt, unsigned int rx_tx)
+{
+	u32 sph[SLIM_MAX_TX_PORTS] = {0};
+	int i = 0 , idx = 0;
+	int ret = 0;
+	struct wcd9xxx_slim_sch_rx *rx = sh_ch.rx;
+	struct wcd9xxx_slim_sch_tx *tx = sh_ch.tx;
+
+	pr_debug("%s: ch_cnt[%d], rx_tx flag = %d\n", __func__, ch_cnt, rx_tx);
+	for (i = 0; i < ch_cnt; i++) {
+		/* rx_tx will be 1 for rx, 0 for tx */
+		if (rx_tx) {
+			idx = (ch_num[i] - BASE_CH_NUM -
+				sh_ch.rx_port_start_offset);
+			if (idx < 0) {
+				pr_err("%s: Invalid index found for RX = %d\n",
+					__func__, idx);
+				ret = -EINVAL;
+				goto err;
+			}
+			sph[i] = rx[idx].sph;
+		} else {
+			idx = (ch_num[i] - BASE_CH_NUM);
+			if (idx < 0) {
+				pr_err("%s:Invalid index found for TX = %d\n",
+					__func__, idx);
+				ret = -EINVAL;
+				goto err;
+			}
+			sph[i] = tx[idx].sph;
+		}
+	}
+
+	/* slim_disconnect_port */
+	ret = slim_disconnect_ports(wcd9xxx->slim, sph, ch_cnt);
+	if (ret < 0) {
+		pr_err("%s: slim_disconnect_ports failed ret[%d]\n",
+			__func__, ret);
+	}
+err:
+	return ret;
+}
+EXPORT_SYMBOL_GPL(wcd9xxx_disconnect_port);
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 8354aa8..d6d209b 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -28,7 +28,7 @@
 #include <linux/list.h>
 #include <linux/mutex.h>
 #include <linux/io.h>
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
 #include <linux/types.h>
 #include <linux/clk.h>
 #include <linux/qseecom.h>
@@ -147,7 +147,6 @@
 
 static int qsee_bw_count;
 static int qsee_sfpb_bw_count;
-static struct clk *qseecom_bus_clk;
 static uint32_t qsee_perf_client;
 
 struct qseecom_registered_listener_list {
@@ -522,7 +521,6 @@
 	return 0;
 }
 
-
 static int __qseecom_listener_has_sent_rsp(struct qseecom_dev_handle *data)
 {
 	int ret;
@@ -771,22 +769,22 @@
 	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) {
+	if ((qseecom.qseos_version == QSEOS_VERSION_14) &&
+				(data->client.app_id > 0)) {
 		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",
+					pr_warn("Can't unload app(%d) inuse\n",
 							ptr_app->app_id);
 					break;
 				}
@@ -794,15 +792,22 @@
 		}
 		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 +845,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;
 }
@@ -1190,11 +1200,6 @@
 
 	switch (clk_type) {
 	case CLK_DFAB:
-		/* Check if the clk is valid */
-		if (IS_ERR_OR_NULL(qseecom_bus_clk)) {
-			pr_warn("qseecom bus clock is null or error");
-			return -EINVAL;
-		}
 		mutex_lock(&qsee_bw_mutex);
 		if (!qsee_bw_count) {
 			ret = msm_bus_scale_client_update_request(
@@ -1236,11 +1241,6 @@
 
 	switch (clk_type) {
 	case CLK_DFAB:
-		/* Check if the DFAB clk is valid */
-		if (IS_ERR_OR_NULL(qseecom_bus_clk)) {
-			pr_warn("qseecom bus clock is null or error");
-			return;
-		}
 		mutex_lock(&qsee_bw_mutex);
 		if (qsee_bw_count > 0) {
 			if (qsee_bw_count-- == 1) {
@@ -1722,7 +1722,6 @@
 	uint32_t system_call_id = QSEOS_CHECK_VERSION_CMD;
 
 	qsee_bw_count = 0;
-	qseecom_bus_clk = NULL;
 	qsee_perf_client = 0;
 
 	rc = alloc_chrdev_region(&qseecom_device_no, 0, 1, QSEECOM_DEV);
@@ -1790,17 +1789,8 @@
 		qsee_perf_client = msm_bus_scale_register_client(
 						qseecom_platform_support);
 
-		if (!qsee_perf_client) {
+		if (!qsee_perf_client)
 			pr_err("Unable to register bus client\n");
-		} else {
-			qseecom_bus_clk = clk_get(class_dev, "bus_clk");
-			if (IS_ERR(qseecom_bus_clk)) {
-				qseecom_bus_clk = NULL;
-			} else if (qseecom_bus_clk != NULL) {
-				pr_debug("Enabled DFAB clock");
-				clk_set_rate(qseecom_bus_clk, 64000000);
-			}
-		}
 	}
 	return 0;
 
@@ -1844,8 +1834,6 @@
 
 static void __devexit qseecom_exit(void)
 {
-	clk_put(qseecom_bus_clk);
-
 	device_destroy(driver_class, qseecom_device_no);
 	class_destroy(driver_class);
 	unregister_chrdev_region(qseecom_device_no, 1);
diff --git a/drivers/misc/tsif.c b/drivers/misc/tsif.c
index 7e59c98..1ff4468 100644
--- a/drivers/misc/tsif.c
+++ b/drivers/misc/tsif.c
@@ -32,7 +32,6 @@
 #include <linux/pm_runtime.h>
 #include <linux/slab.h>          /* kfree, kzalloc */
 #include <linux/gpio.h>
-
 #include <mach/dma.h>
 #include <mach/msm_tsif.h>
 
@@ -273,36 +272,6 @@
 /* ===clocks end=== */
 /* ===gpio begin=== */
 
-static void tsif_gpios_free(const struct msm_gpio *table, int size)
-{
-	int i;
-	const struct msm_gpio *g;
-	for (i = size-1; i >= 0; i--) {
-		g = table + i;
-		gpio_free(GPIO_PIN(g->gpio_cfg));
-	}
-}
-
-static int tsif_gpios_request(const struct msm_gpio *table, int size)
-{
-	int rc;
-	int i;
-	const struct msm_gpio *g;
-	for (i = 0; i < size; i++) {
-		g = table + i;
-		rc = gpio_request(GPIO_PIN(g->gpio_cfg), g->label);
-		if (rc) {
-			pr_err("gpio_request(%d) <%s> failed: %d\n",
-			       GPIO_PIN(g->gpio_cfg), g->label ?: "?", rc);
-			goto err;
-		}
-	}
-	return 0;
-err:
-	tsif_gpios_free(table, i);
-	return rc;
-}
-
 static int tsif_gpios_disable(const struct msm_gpio *table, int size)
 {
 	int rc = 0;
@@ -357,19 +326,14 @@
 
 static int tsif_gpios_request_enable(const struct msm_gpio *table, int size)
 {
-	int rc = tsif_gpios_request(table, size);
-	if (rc)
-		return rc;
+	int rc;
 	rc = tsif_gpios_enable(table, size);
-	if (rc)
-		tsif_gpios_free(table, size);
 	return rc;
 }
 
 static void tsif_gpios_disable_free(const struct msm_gpio *table, int size)
 {
 	tsif_gpios_disable(table, size);
-	tsif_gpios_free(table, size);
 }
 
 static int tsif_start_gpios(struct msm_tsif_device *tsif_device)
@@ -1029,6 +993,7 @@
 
 	struct msm_tsif_platform_data *pdata =
 		tsif_device->pdev->dev.platform_data;
+
 	dev_info(&tsif_device->pdev->dev, "%s\n", __func__);
 	if (tsif_device->state != tsif_state_stopped)
 		return -EAGAIN;
@@ -1039,14 +1004,6 @@
 	}
 	tsif_device->state = tsif_state_running;
 
-	/* make sure the GPIO's are set up */
-	rc = tsif_start_gpios(tsif_device);
-	if (rc) {
-		dev_err(&tsif_device->pdev->dev, "failed to start GPIOs\n");
-		tsif_dma_exit(tsif_device);
-		return rc;
-	}
-
 	/*
 	 * DMA should be scheduled prior to TSIF hardware initialization,
 	 * otherwise "bus error" will be reported by Data Mover
@@ -1062,9 +1019,20 @@
 	rc = tsif_start_hw(tsif_device);
 	if (rc) {
 		dev_err(&tsif_device->pdev->dev, "Unable to start HW\n");
-		tsif_stop_gpios(tsif_device);
 		tsif_dma_exit(tsif_device);
 		tsif_clock(tsif_device, 0);
+		disable_irq(tsif_device->irq);
+		return rc;
+	}
+
+	/* make sure the GPIO's are set up */
+	rc = tsif_start_gpios(tsif_device);
+	if (rc) {
+		dev_err(&tsif_device->pdev->dev, "failed to start GPIOs\n");
+		tsif_stop_hw(tsif_device);
+		tsif_dma_exit(tsif_device);
+		tsif_clock(tsif_device, 0);
+		disable_irq(tsif_device->irq);
 		return rc;
 	}
 
@@ -1073,11 +1041,16 @@
 		dev_err(&tsif_device->pdev->dev,
 			"Runtime PM: Unable to wake up the device, rc = %d\n",
 			result);
+		tsif_stop_gpios(tsif_device);
+		tsif_stop_hw(tsif_device);
+		tsif_dma_exit(tsif_device);
+		tsif_clock(tsif_device, 0);
+		disable_irq(tsif_device->irq);
 		return result;
 	}
 
 	wake_lock(&tsif_device->wake_lock);
-	return rc;
+	return 0;
 }
 
 static int action_close(struct msm_tsif_device *tsif_device)
@@ -1094,7 +1067,7 @@
 	 * there are any outstanding reads on the bus, and if we
 	 * stop the TSIF too quickly, it can cause a bus error.
 	 */
-	msleep(100);
+	msleep(250);
 
 	/* now we can stop the core */
 	tsif_stop_hw(tsif_device);
diff --git a/drivers/misc/tspp.c b/drivers/misc/tspp.c
index cc65929..1792104 100644
--- a/drivers/misc/tspp.c
+++ b/drivers/misc/tspp.c
@@ -10,58 +10,54 @@
  * GNU General Public License for more details.
  */
 
-#include <linux/module.h>			/* Needed by all modules */
-#include <linux/kernel.h>			/* Needed for KERN_INFO */
-#include <linux/init.h>				/* Needed for the macros */
+#include <linux/module.h>        /* Just for modules */
+#include <linux/kernel.h>        /* Only for KERN_INFO */
+#include <linux/err.h>           /* Error macros */
+#include <linux/list.h>          /* Linked list */
 #include <linux/cdev.h>
-#include <linux/err.h>				/* IS_ERR */
+#include <linux/init.h>          /* Needed for the macros */
+#include <linux/io.h>            /* IO macros */
+#include <linux/device.h>        /* Device drivers need this */
+#include <linux/sched.h>         /* Externally defined globals */
+#include <linux/pm_runtime.h>    /* Runtime power management */
 #include <linux/fs.h>
-#include <linux/device.h>
-#include <linux/sched.h>		/* TASK_INTERRUPTIBLE */
-#include <linux/uaccess.h>        /* copy_to_user */
-#include <linux/platform_device.h>
-#include <linux/pm_runtime.h>
+#include <linux/uaccess.h>       /* copy_to_user */
 #include <linux/slab.h>          /* kfree, kzalloc */
-#include <linux/wakelock.h>
-#include <linux/io.h>            /* ioXXX */
-#include <linux/ioport.h>		/* XXX_ mem_region */
-#include <linux/dma-mapping.h>		/* dma_XXX */
-#include <linux/delay.h>		/* msleep */
+#include <linux/ioport.h>        /* XXX_ mem_region */
+#include <linux/dma-mapping.h>   /* dma_XXX */
+#include <linux/delay.h>         /* msleep */
+#include <linux/platform_device.h>
 #include <linux/clk.h>
-#include <linux/poll.h>				/* poll() file op */
-#include <linux/wait.h>				/* wait() macros, sleeping */
-#include <linux/tspp.h>				/* tspp functions */
+#include <linux/poll.h>          /* poll() file op */
+#include <linux/wait.h>          /* wait() macros, sleeping */
+#include <linux/tspp.h>          /* tspp functions */
 #include <linux/bitops.h>        /* BIT() macro */
-#include <mach/sps.h>				/* BAM stuff */
+#include <mach/sps.h>            /* BAM stuff */
 #include <mach/gpio.h>
+#include <linux/wakelock.h>      /* Locking functions */
 #include <mach/dma.h>
 #include <mach/msm_tspp.h>
-
-#define TSPP_USE_DEBUGFS
-#ifdef TSPP_USE_DEBUGFS
 #include <linux/debugfs.h>
-#endif /* TSPP_USE_DEBUGFS */
 
 /*
  * General defines
  */
-#define TSPP_USE_DMA_ALLOC_COHERENT
 #define TSPP_TSIF_INSTANCES            2
 #define TSPP_FILTER_TABLES             3
-#define TSPP_MAX_DEVICES               3
+#define TSPP_MAX_DEVICES               1
 #define TSPP_NUM_CHANNELS              16
 #define TSPP_NUM_PRIORITIES            16
 #define TSPP_NUM_KEYS                  8
 #define INVALID_CHANNEL                0xFFFFFFFF
-#define TSPP_SPS_DESCRIPTOR_COUNT      32
+#define TSPP_SPS_DESCRIPTOR_COUNT      128
 #define TSPP_PACKET_LENGTH             188
 #define TSPP_MIN_BUFFER_SIZE           (TSPP_PACKET_LENGTH)
-#define TSPP_MAX_BUFFER_SIZE           (16 * 1024)	 /* maybe allow 64K? */
-#define TSPP_NUM_BUFFERS               16
+#define TSPP_MAX_BUFFER_SIZE           (32 * 1024)
+#define TSPP_NUM_BUFFERS               64
 #define TSPP_TSIF_DEFAULT_TIME_LIMIT   60
 #define SPS_DESCRIPTOR_SIZE            8
 #define MIN_ACCEPTABLE_BUFFER_COUNT    2
-#define TSPP_DEBUG(msg...)             pr_info(msg)
+#define TSPP_DEBUG(msg...)
 
 /*
  * TSIF register offsets
@@ -99,6 +95,7 @@
 #define TSIF_STS_CTL_EN_TIME_LIM  BIT(8)
 #define TSIF_STS_CTL_EN_TCR       BIT(7)
 #define TSIF_STS_CTL_TEST_MODE    BIT(6)
+#define TSIF_STS_CTL_MODE_2       BIT(5)
 #define TSIF_STS_CTL_EN_DM        BIT(4)
 #define TSIF_STS_CTL_STOP         BIT(3)
 #define TSIF_STS_CTL_START        BIT(0)
@@ -212,7 +209,6 @@
 #define TSPP_TSP_BUFF_WORD(_n)      (0xC10 + (_n << 2))
 #define TSPP_DATA_KEY               0xCD0
 
-#ifdef TSPP_USE_DEBUGFS
 struct debugfs_entry {
 	const char *name;
 	mode_t mode;
@@ -265,8 +261,6 @@
 	{"data_key",            S_IRUGO | S_IWUSR, TSPP_DATA_KEY}
 };
 
-#endif /* TSPP_USE_DEBUGFS */
-
 struct tspp_pid_filter {
 	u32 filter;			/* see FILTER_ macros */
 	u32 config;			/* see FILTER_ macros */
@@ -328,44 +322,24 @@
 	void __iomem *base;
 	u32 time_limit;
 	u32 ref_count;
+	enum tspp_tsif_mode mode;
 
 	/* debugfs */
-#ifdef TSPP_USE_DEBUGFS
 	struct dentry *dent_tsif;
 	struct dentry *debugfs_tsif_regs[ARRAY_SIZE(debugfs_tsif_regs)];
-#endif /* TSPP_USE_DEBUGFS */
-};
-
-/* this represents the actual hardware device */
-struct tspp_device {
-	struct platform_device *pdev;
-	void __iomem *base;
-	unsigned int tspp_irq;
-	unsigned int bam_irq;
-	u32 bam_handle;
-	struct sps_bam_props bam_props;
-	struct wake_lock wake_lock;
-	spinlock_t spinlock;
-	struct tasklet_struct tlet;
-	struct tspp_tsif_device tsif[TSPP_TSIF_INSTANCES];
-	/* clocks */
-	struct clk *tsif_pclk;
-	struct clk *tsif_ref_clk;
-
-#ifdef TSPP_USE_DEBUGFS
-	struct dentry *dent;
-	struct dentry *debugfs_regs[ARRAY_SIZE(debugfs_tspp_regs)];
-#endif /* TSPP_USE_DEBUGFS */
 };
 
 enum tspp_buf_state {
 	TSPP_BUF_STATE_EMPTY,	/* buffer has been allocated, but not waiting */
 	TSPP_BUF_STATE_WAITING, /* buffer is waiting to be filled */
-	TSPP_BUF_STATE_DATA     /* buffer is not empty and can be read */
+	TSPP_BUF_STATE_DATA,    /* buffer is not empty and can be read */
+	TSPP_BUF_STATE_LOCKED   /* buffer is being read by a client */
 };
 
 struct tspp_mem_buffer {
-	struct sps_mem_buffer mem;
+	struct tspp_mem_buffer *next;
+	struct sps_mem_buffer sps;
+	struct tspp_data_descriptor desc; /* buffer descriptor for kernel api */
 	enum tspp_buf_state state;
 	size_t filled;          /* how much data this buffer is holding */
 	int read_index;         /* where to start reading data from */
@@ -375,22 +349,28 @@
 struct tspp_channel {
 	struct cdev cdev;
 	struct device *dd;
-	struct tspp_device *pdev;
+	struct tspp_device *pdev; /* can use container_of instead? */
 	struct sps_pipe *pipe;
 	struct sps_connect config;
 	struct sps_register_event event;
-	struct tspp_mem_buffer buffer[TSPP_NUM_BUFFERS];
+	struct tspp_mem_buffer *data;    /* list of buffers */
+	struct tspp_mem_buffer *read;    /* first buffer ready to be read */
+	struct tspp_mem_buffer *waiting; /* first outstanding transfer */
+	struct tspp_mem_buffer *locked;  /* buffer currently being read */
 	wait_queue_head_t in_queue; /* set when data is received */
-	int read;  /* index into mem showing buffers ready to be read by user */
-	int waiting;	/* index into mem showing outstanding transfers */
-	int id;			/* channel id (0-15) */
-	int used;		/* is this channel in use? */
-	int key;			/* which encryption key index is used */
-	u32 bufsize;	/* size of the sps transfer buffers */
-	int buffer_count; /* how many buffers are actually allocated */
-	int filter_count; /* how many filters have been added to this channel */
+	u32 id;           /* channel id (0-15) */
+	int used;         /* is this channel in use? */
+	int key;          /* which encryption key index is used */
+	u32 buffer_size;  /* size of the sps transfer buffers */
+	u32 max_buffers;  /* how many buffers should be allocated */
+	u32 buffer_count; /* how many buffers are actually allocated */
+	u32 filter_count; /* how many filters have been added to this channel */
+	u32 int_freq;     /* generate interrupts every x descriptors */
 	enum tspp_source src;
 	enum tspp_mode mode;
+	tspp_notifier *notifier; /* used only with kernel api */
+	void *notify_data;       /* data to be passed with the notifier */
+	u32 notify_timer;        /* notification for partially filled buffers */
 };
 
 struct tspp_pid_filter_table {
@@ -408,21 +388,62 @@
 	struct tspp_key_entry entry[TSPP_NUM_KEYS];
 };
 
-static struct tspp_pid_filter_table *tspp_filter_table[TSPP_FILTER_TABLES];
-static struct tspp_channel channel_list[TSPP_NUM_CHANNELS];
-static struct tspp_key_table *tspp_key_table;
-static struct tspp_global_performance_regs *tspp_global_performance;
-static struct tspp_pipe_context_regs *tspp_pipe_context;
-static struct tspp_pipe_performance_regs *tspp_pipe_performance;
+/* this represents the actual hardware device */
+struct tspp_device {
+	struct list_head devlist; /* list of all devices */
+	struct platform_device *pdev;
+	void __iomem *base;
+	unsigned int tspp_irq;
+	unsigned int bam_irq;
+	u32 bam_handle;
+	struct sps_bam_props bam_props;
+	struct wake_lock wake_lock;
+	spinlock_t spinlock;
+	struct tasklet_struct tlet;
+	struct tspp_tsif_device tsif[TSPP_TSIF_INSTANCES];
+	/* clocks */
+	struct clk *tsif_pclk;
+	struct clk *tsif_ref_clk;
+	/* data */
+	struct tspp_pid_filter_table *filters[TSPP_FILTER_TABLES];
+	struct tspp_channel channels[TSPP_NUM_CHANNELS];
+	struct tspp_key_table *tspp_key_table;
+	struct tspp_global_performance_regs *tspp_global_performance;
+	struct tspp_pipe_context_regs *tspp_pipe_context;
+	struct tspp_pipe_performance_regs *tspp_pipe_performance;
+
+	struct dentry *dent;
+	struct dentry *debugfs_regs[ARRAY_SIZE(debugfs_tspp_regs)];
+};
+
+
 static struct class *tspp_class;
 static int tspp_key_entry;
 static dev_t tspp_minor;  /* next minor number to assign */
-static int loopback_mode; /* put tsif interfaces into loopback mode */
+
+static LIST_HEAD(tspp_devices);
+
+/* forward declarations */
+static ssize_t tspp_read(struct file *, char __user *, size_t, loff_t *);
+static ssize_t tspp_open(struct inode *inode, struct file *filp);
+static unsigned int tspp_poll(struct file *filp, struct poll_table_struct *p);
+static ssize_t tspp_release(struct inode *inode, struct file *filp);
+static long tspp_ioctl(struct file *, unsigned int, unsigned long);
+
+/* file operations */
+static const struct file_operations tspp_fops = {
+	.owner   = THIS_MODULE,
+	.read    = tspp_read,
+	.open    = tspp_open,
+	.poll    = tspp_poll,
+	.release = tspp_release,
+	.unlocked_ioctl   = tspp_ioctl,
+};
 
 /*** IRQ ***/
-static irqreturn_t tspp_isr(int irq, void *dev_id)
+static irqreturn_t tspp_isr(int irq, void *dev)
 {
-	struct tspp_device *device = dev_id;
+	struct tspp_device *device = dev;
 	u32 status, mask;
 	u32 data;
 
@@ -450,7 +471,7 @@
 		dev_info(&device->pdev->dev, "key switched");
 
 	if (status & 0xffff)
-		dev_info(&device->pdev->dev, "broken pipe");
+		dev_info(&device->pdev->dev, "broken pipe %i", status & 0xffff);
 
 	writel_relaxed(status, device->base + TSPP_IRQ_CLEAR);
 	wmb();
@@ -460,8 +481,8 @@
 /*** callbacks ***/
 static void tspp_sps_complete_cb(struct sps_event_notify *notify)
 {
-	struct tspp_channel *channel = notify->user;
-	tasklet_schedule(&channel->pdev->tlet);
+	struct tspp_device *pdev = notify->user;
+	tasklet_schedule(&pdev->tlet);
 }
 
 /*** tasklet ***/
@@ -473,17 +494,16 @@
 	struct sps_iovec iovec;
 	struct tspp_channel *channel;
 	struct tspp_device *device = (struct tspp_device *)data;
-	struct tspp_mem_buffer *buffer;
-
 	spin_lock_irqsave(&device->spinlock, flags);
 
 	for (i = 0; i < TSPP_NUM_CHANNELS; i++) {
 		complete = 0;
-		channel = &channel_list[i];
-		buffer = &channel->buffer[channel->waiting];
+		channel = &device->channels[i];
+		if (!channel->used || !channel->waiting)
+			continue;
 
 		/* get completions */
-		if (buffer->state == TSPP_BUF_STATE_WAITING) {
+		while (channel->waiting->state == TSPP_BUF_STATE_WAITING) {
 			if (sps_get_iovec(channel->pipe, &iovec) != 0) {
 				pr_err("tspp: Error in iovec on channel %i",
 					channel->id);
@@ -492,22 +512,27 @@
 			if (iovec.size == 0)
 				break;
 
-			if (iovec.addr != buffer->mem.phys_base)
+			if (iovec.addr != channel->waiting->sps.phys_base)
 				pr_err("tspp: buffer mismatch 0x%08x",
-					buffer->mem.phys_base);
+					channel->waiting->sps.phys_base);
 
 			complete = 1;
-			buffer->state = TSPP_BUF_STATE_DATA;
-			buffer->filled = iovec.size;
-			buffer->read_index = 0;
-			channel->waiting++;
-			if (channel->waiting == TSPP_NUM_BUFFERS)
-				channel->waiting = 0;
+			channel->waiting->state = TSPP_BUF_STATE_DATA;
+			channel->waiting->filled = iovec.size;
+			channel->waiting->read_index = 0;
+
+			/* update the pointers */
+			channel->waiting = channel->waiting->next;
 		}
 
+		/* wake any waiting processes */
 		if (complete) {
-			/* wake any waiting processes */
 			wake_up_interruptible(&channel->in_queue);
+
+			/* call notifiers */
+			if (channel->notifier)
+				channel->notifier(channel->id,
+					channel->notify_data);
 		}
 	}
 
@@ -626,6 +651,33 @@
 	tspp_gpios_disable_free(pdata->gpios, pdata->num_gpios);
 }
 
+/*** Clock functions ***/
+static int tspp_clock_start(struct tspp_device *device)
+{
+	if (device->tsif_pclk && clk_prepare_enable(device->tsif_pclk) != 0) {
+		pr_err("tspp: Can't start pclk");
+		return -EBUSY;
+	}
+
+	if (device->tsif_ref_clk &&
+		clk_prepare_enable(device->tsif_ref_clk) != 0) {
+		pr_err("tspp: Can't start ref clk");
+		clk_disable_unprepare(device->tsif_pclk);
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+static void tspp_clock_stop(struct tspp_device *device)
+{
+	if (device->tsif_pclk)
+		clk_disable(device->tsif_pclk);
+
+	if (device->tsif_ref_clk)
+		clk_disable(device->tsif_ref_clk);
+}
+
 /*** TSIF functions ***/
 static int tspp_start_tsif(struct tspp_tsif_device *tsif_device)
 {
@@ -644,18 +696,26 @@
 	}
 
 	if (start_hardware) {
-		if (loopback_mode) {
-			ctl = TSIF_STS_CTL_EN_IRQ |
-				TSIF_STS_CTL_EN_NULL |
-				TSIF_STS_CTL_EN_ERROR |
-				TSIF_STS_CTL_TEST_MODE |
+		ctl = TSIF_STS_CTL_EN_IRQ |
 				TSIF_STS_CTL_EN_DM;
-	TSPP_DEBUG("tspp: starting tsif hw in loopback mode 0x%x", ctl);
-		} else {
-			ctl = TSIF_STS_CTL_EN_IRQ |
-				TSIF_STS_CTL_EN_TIME_LIM |
-				TSIF_STS_CTL_EN_TCR |
-				TSIF_STS_CTL_EN_DM;
+		switch (tsif_device->mode) {
+		case TSPP_TSIF_MODE_LOOPBACK:
+			ctl |= TSIF_STS_CTL_EN_NULL |
+					TSIF_STS_CTL_EN_ERROR |
+					TSIF_STS_CTL_TEST_MODE;
+			break;
+		case TSPP_TSIF_MODE_1:
+			ctl |= TSIF_STS_CTL_EN_TIME_LIM |
+					TSIF_STS_CTL_EN_TCR;
+			break;
+		case TSPP_TSIF_MODE_2:
+			ctl |= TSIF_STS_CTL_EN_TIME_LIM |
+					TSIF_STS_CTL_EN_TCR |
+					TSIF_STS_CTL_MODE_2;
+			break;
+		default:
+			pr_warn("tspp: unknown tsif mode 0x%x",
+				tsif_device->mode);
 		}
 		writel_relaxed(ctl, tsif_device->base + TSIF_STS_CTL_OFF);
 		writel_relaxed(tsif_device->time_limit,
@@ -664,12 +724,12 @@
 		writel_relaxed(ctl | TSIF_STS_CTL_START,
 			  tsif_device->base + TSIF_STS_CTL_OFF);
 		wmb();
-		ctl = readl_relaxed(tsif_device->base + TSIF_STS_CTL_OFF);
 	}
 
+	ctl = readl_relaxed(tsif_device->base + TSIF_STS_CTL_OFF);
 	tsif_device->ref_count++;
 
-	return (ctl & TSIF_STS_CTL_START) ? 0 : -EFAULT;
+	return (ctl & TSIF_STS_CTL_START) ? 0 : -EBUSY;
 }
 
 static void tspp_stop_tsif(struct tspp_tsif_device *tsif_device)
@@ -686,7 +746,27 @@
 	}
 }
 
-/*** TSPP functions ***/
+/*** local TSPP functions ***/
+static int tspp_channels_in_use(struct tspp_device *pdev)
+{
+	int i;
+	int count = 0;
+	for (i = 0; i < TSPP_NUM_CHANNELS; i++)
+		count += (pdev->channels[i].used ? 1 : 0);
+
+	return count;
+}
+
+static struct tspp_device *tspp_find_by_id(int id)
+{
+	struct tspp_device *dev;
+	list_for_each_entry(dev, &tspp_devices, devlist) {
+		if (dev->pdev->id == id)
+			return dev;
+	}
+	return NULL;
+}
+
 static int tspp_get_key_entry(void)
 {
 	int i;
@@ -696,7 +776,7 @@
 			return i;
 		}
 	}
-	return 1;
+	return 1 < TSPP_NUM_KEYS;
 }
 
 static void tspp_free_key_entry(int entry)
@@ -709,61 +789,56 @@
 	tspp_key_entry &= ~(1 << entry);
 }
 
-static int tspp_alloc_buffer(struct sps_mem_buffer *mem,
-	struct tspp_channel *channel)
+static int tspp_alloc_buffer(u32 channel_id, struct tspp_data_descriptor *desc,
+	u32 size, tspp_allocator *alloc, void *user)
 {
-	if (channel->bufsize < TSPP_MIN_BUFFER_SIZE ||
-		channel->bufsize > TSPP_MAX_BUFFER_SIZE) {
-		pr_err("tspp: bad buffer size");
-		return 1;
-	}
-
-	switch (channel->mode) {
-	case TSPP_MODE_DISABLED:
-		mem->size = 0;
-		pr_err("tspp: channel is disabled");
-		return 1;
-
-	case TSPP_MODE_PES:
-		/* give the user what he asks for */
-		mem->size = channel->bufsize;
-		break;
-
-	case TSPP_MODE_RAW:
-		/* must be a multiple of 192 */
-		if (channel->bufsize < (TSPP_PACKET_LENGTH+4))
-			mem->size = (TSPP_PACKET_LENGTH+4);
-		else
-			mem->size = (channel->bufsize /
-				(TSPP_PACKET_LENGTH+4)) *
-				(TSPP_PACKET_LENGTH+4);
-		break;
-
-	case TSPP_MODE_RAW_NO_SUFFIX:
-		/* must be a multiple of 188 */
-		mem->size = (channel->bufsize / TSPP_PACKET_LENGTH) *
-			TSPP_PACKET_LENGTH;
-		break;
-	}
-
-#ifdef TSPP_USE_DMA_ALLOC_COHERENT
-	mem->base = dma_alloc_coherent(NULL, mem->size,
-		&mem->phys_base, GFP_KERNEL);
-	if (mem->base == 0) {
-		pr_err("tspp dma alloc coherent failed %i", mem->size);
+	if (size < TSPP_MIN_BUFFER_SIZE ||
+		size > TSPP_MAX_BUFFER_SIZE) {
+		pr_err("tspp: bad buffer size %i", size);
 		return -ENOMEM;
 	}
-#else
-	mem->base = kmalloc(mem->size, GFP_KERNEL);
-	if (mem->base == 0) {
-		pr_err("tspp buffer allocation failed %i", mem->size);
+
+	if (alloc) {
+		TSPP_DEBUG("tspp using alloc function");
+		desc->virt_base = alloc(channel_id, size,
+			&desc->phys_base, user);
+	} else {
+	desc->virt_base = dma_alloc_coherent(NULL, size,
+		&desc->phys_base, GFP_KERNEL);
+	if (desc->virt_base == 0) {
+		pr_err("tspp dma alloc coherent failed %i", size);
 		return -ENOMEM;
 	}
-	mem->phys_base = dma_map_single(NULL,
-		mem->base,
-		mem->size,
-		DMA_FROM_DEVICE);
-#endif
+	}
+
+	desc->size = size;
+	return 0;
+}
+
+static int tspp_queue_buffer(struct tspp_channel *channel,
+	struct tspp_mem_buffer *buffer)
+{
+	int rc;
+	u32 flags = 0;
+
+	/* make sure the interrupt frequency is valid */
+	if (channel->int_freq < 1)
+		channel->int_freq = 1;
+
+	/* generate interrupt according to requested frequency */
+	if (buffer->desc.id % channel->int_freq == channel->int_freq-1)
+		flags = SPS_IOVEC_FLAG_INT | SPS_IOVEC_FLAG_EOB;
+
+	/* start the transfer */
+	rc = sps_transfer_one(channel->pipe,
+		buffer->sps.phys_base,
+		buffer->sps.size,
+		channel->pdev,
+		flags);
+	if (rc < 0)
+		return rc;
+
+	buffer->state = TSPP_BUF_STATE_WAITING;
 
 	return 0;
 }
@@ -784,12 +859,12 @@
 	/* BAM */
 	if (sps_device_reset(pdev->bam_handle) != 0) {
 		pr_err("tspp: error resetting bam");
-		return 1;
+		return -EBUSY;
 	}
 
 	/* TSPP tables */
 	for (i = 0; i < TSPP_FILTER_TABLES; i++)
-		memset(tspp_filter_table[i],
+		memset(pdev->filters[i],
 			0, sizeof(struct tspp_pid_filter_table));
 
 	/* disable all filters */
@@ -801,11 +876,11 @@
 	writel_relaxed(val | TSPP_CLK_CONTROL_FORCE_PERF_CNT,
 		pdev->base + TSPP_CONTROL);
 	wmb();
-	memset(tspp_global_performance, 0,
+	memset(pdev->tspp_global_performance, 0,
 		sizeof(struct tspp_global_performance_regs));
-	memset(tspp_pipe_context, 0,
+	memset(pdev->tspp_pipe_context, 0,
 		sizeof(struct tspp_pipe_context_regs));
-	memset(tspp_pipe_performance, 0,
+	memset(pdev->tspp_pipe_performance, 0,
 		sizeof(struct tspp_pipe_performance_regs));
 	wmb();
 	writel_relaxed(val & ~TSPP_CLK_CONTROL_FORCE_PERF_CNT,
@@ -828,22 +903,147 @@
 	return 0;
 }
 
-int tspp_open_stream(struct tspp_channel *channel, enum tspp_source src)
+static int tspp_select_source(u32 dev, u32 channel_id,
+	struct tspp_select_source *src)
+{
+	/* make sure the requested src id is in bounds */
+	if (src->source > TSPP_SOURCE_MEM) {
+		pr_err("tspp source out of bounds");
+		return -EINVAL;
+	}
+
+	/* open the stream */
+	tspp_open_stream(dev, channel_id, src->source, src->mode);
+
+	return 0;
+}
+
+static int tspp_set_iv(struct tspp_channel *channel, struct tspp_iv *iv)
+{
+	struct tspp_device *pdev = channel->pdev;
+
+	writel_relaxed(iv->data[0], pdev->base + TSPP_CBC_INIT_VAL(0));
+	writel_relaxed(iv->data[1], pdev->base + TSPP_CBC_INIT_VAL(1));
+	return 0;
+}
+
+static int tspp_set_system_keys(struct tspp_channel *channel,
+	struct tspp_system_keys *keys)
+{
+	int i;
+	struct tspp_device *pdev = channel->pdev;
+
+	for (i = 0; i < TSPP_NUM_SYSTEM_KEYS; i++)
+		writel_relaxed(keys->data[i], pdev->base + TSPP_SYSTEM_KEY(i));
+
+	return 0;
+}
+
+static int tspp_channel_init(struct tspp_channel *channel,
+	struct tspp_device *pdev)
+{
+	channel->cdev.owner = THIS_MODULE;
+	cdev_init(&channel->cdev, &tspp_fops);
+	channel->pdev = pdev;
+	channel->data = NULL;
+	channel->read = NULL;
+	channel->waiting = NULL;
+	channel->locked = NULL;
+	channel->id = MINOR(tspp_minor);
+	channel->used = 0;
+	channel->buffer_size = TSPP_MIN_BUFFER_SIZE;
+	channel->max_buffers = TSPP_NUM_BUFFERS;
+	channel->buffer_count = 0;
+	channel->filter_count = 0;
+	channel->int_freq = 1;
+	channel->notifier = NULL;
+	channel->notify_data = NULL;
+	channel->notify_timer = 0;
+	init_waitqueue_head(&channel->in_queue);
+
+	if (cdev_add(&channel->cdev, tspp_minor++, 1) != 0) {
+		pr_err("tspp: cdev_add failed");
+		return -EBUSY;
+	}
+
+	channel->dd = device_create(tspp_class, NULL, channel->cdev.dev,
+		channel, "tspp%02d", channel->id);
+	if (IS_ERR(channel->dd)) {
+		pr_err("tspp: device_create failed: %i",
+			(int)PTR_ERR(channel->dd));
+		cdev_del(&channel->cdev);
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+static int tspp_set_buffer_size(struct tspp_channel *channel,
+	struct tspp_buffer *buf)
+{
+	if (buf->size < TSPP_MIN_BUFFER_SIZE)
+		channel->buffer_size = TSPP_MIN_BUFFER_SIZE;
+	else if (buf->size > TSPP_MAX_BUFFER_SIZE)
+		channel->buffer_size = TSPP_MAX_BUFFER_SIZE;
+	else
+		channel->buffer_size = buf->size;
+
+	return 0;
+}
+
+static void tspp_set_tsif_mode(struct tspp_channel *channel,
+	enum tspp_tsif_mode mode)
+{
+	int index;
+
+	switch (channel->src) {
+	case TSPP_SOURCE_TSIF0:
+		index = 0;
+		break;
+	case TSPP_SOURCE_TSIF1:
+		index = 1;
+		break;
+	default:
+		pr_warn("tspp: can't set mode for non-tsif source %d",
+			channel->src);
+		return;
+	}
+	channel->pdev->tsif[index].mode = mode;
+}
+
+/*** TSPP API functions ***/
+int tspp_open_stream(u32 dev, u32 channel_id, enum tspp_source src, enum tspp_tsif_mode mode)
 {
 	u32 val;
 	struct tspp_device *pdev;
+	struct tspp_channel *channel;
 
-	if (!channel)
-		return 1;
+	TSPP_DEBUG("tspp_open_stream %i %i %i %i", dev, channel_id, src, mode);
+	if (dev >= TSPP_MAX_DEVICES) {
+		pr_err("tspp: device id out of range");
+		return -ENODEV;
+	}
 
-	pdev = channel->pdev;
+	if (channel_id >= TSPP_NUM_CHANNELS) {
+		pr_err("tspp: channel id out of range");
+		return -ECHRNG;
+	}
+
+	pdev = tspp_find_by_id(dev);
+	if (!pdev) {
+		pr_err("tspp_str: can't find device %i", dev);
+		return -ENODEV;
+	}
+	channel = &pdev->channels[channel_id];
+	channel->src = src;
+	tspp_set_tsif_mode(channel, mode);
 
 	switch (src) {
 	case TSPP_SOURCE_TSIF0:
 		/* make sure TSIF0 is running & enabled */
 		if (tspp_start_tsif(&pdev->tsif[0]) != 0) {
 			pr_err("tspp: error starting tsif0");
-			return 1;
+			return -EBUSY;
 		}
 		val = readl_relaxed(pdev->base + TSPP_CONTROL);
 		writel_relaxed(val & ~TSPP_CONTROL_TSP_TSIF0_SRC_DIS,
@@ -854,7 +1054,7 @@
 		/* make sure TSIF1 is running & enabled */
 		if (tspp_start_tsif(&pdev->tsif[1]) != 0) {
 			pr_err("tspp: error starting tsif1");
-			return 1;
+			return -EBUSY;
 		}
 		val = readl_relaxed(pdev->base + TSPP_CONTROL);
 		writel_relaxed(val & ~TSPP_CONTROL_TSP_TSIF1_SRC_DIS,
@@ -864,22 +1064,30 @@
 	case TSPP_SOURCE_MEM:
 		break;
 	default:
-		pr_warn("tspp: channel %i invalid source %i", channel->id, src);
-		return 1;
+		pr_err("tspp: channel %i invalid source %i", channel->id, src);
+		return -EBUSY;
 	}
 
-	channel->src = src;
-
 	return 0;
 }
 EXPORT_SYMBOL(tspp_open_stream);
 
-int tspp_close_stream(struct tspp_channel *channel)
+int tspp_close_stream(u32 dev, u32 channel_id)
 {
 	u32 val;
 	struct tspp_device *pdev;
+	struct tspp_channel *channel;
 
-	pdev = channel->pdev;
+	if (channel_id >= TSPP_NUM_CHANNELS) {
+		pr_err("tspp: channel id out of range");
+		return -ECHRNG;
+	}
+	pdev = tspp_find_by_id(dev);
+	if (!pdev) {
+		pr_err("tspp_cs: can't find device %i", dev);
+		return -EBUSY;
+	}
+	channel = &pdev->channels[channel_id];
 
 	switch (channel->src) {
 	case TSPP_SOURCE_TSIF0:
@@ -901,22 +1109,43 @@
 		break;
 	}
 
-	channel->src = -1;
+	channel->src = TSPP_SOURCE_NONE;
 	return 0;
 }
 EXPORT_SYMBOL(tspp_close_stream);
 
-int tspp_open_channel(struct tspp_channel *channel)
+int tspp_open_channel(u32 dev, u32 channel_id)
 {
 	int rc = 0;
-	struct sps_connect *config = &channel->config;
-	struct sps_register_event *event = &channel->event;
+	struct sps_connect *config;
+	struct sps_register_event *event;
+	struct tspp_channel *channel;
+	struct tspp_device *pdev;
+
+	if (channel_id >= TSPP_NUM_CHANNELS) {
+		pr_err("tspp: channel id out of range");
+		return -ECHRNG;
+	}
+	pdev = tspp_find_by_id(dev);
+	if (!pdev) {
+		pr_err("tspp_oc: can't find device %i", dev);
+		return -ENODEV;
+	}
+	channel = &pdev->channels[channel_id];
 
 	if (channel->used) {
 		pr_err("tspp channel already in use");
-		return 1;
+		return -EBUSY;
 	}
 
+	config = &channel->config;
+	event = &channel->event;
+
+	/* start the clocks if needed */
+	tspp_clock_start(pdev);
+	if (tspp_channels_in_use(pdev) == 0)
+		wake_lock(&pdev->wake_lock);
+
 	/* mark it as used */
 	channel->used = 1;
 
@@ -931,11 +1160,14 @@
 	/* get default configuration */
 	sps_get_config(channel->pipe, config);
 
-	config->source = channel->pdev->bam_handle;
+	config->source = pdev->bam_handle;
 	config->destination = SPS_DEV_HANDLE_MEM;
 	config->mode = SPS_MODE_SRC;
-	config->options = SPS_O_AUTO_ENABLE |
-		SPS_O_EOT | SPS_O_ACK_TRANSFERS;
+	config->options =
+		SPS_O_AUTO_ENABLE | /* connection is auto-enabled */
+		SPS_O_STREAMING | /* streaming mode */
+		SPS_O_DESC_DONE | /* interrupt on end of descriptor */
+		SPS_O_ACK_TRANSFERS; /* must use sps_get_iovec() */
 	config->src_pipe_index = channel->id;
 	config->desc.size =
 		(TSPP_SPS_DESCRIPTOR_COUNT + 1) * SPS_DESCRIPTOR_SIZE;
@@ -958,10 +1190,10 @@
 	}
 
 	event->mode = SPS_TRIGGER_CALLBACK;
-	event->options = SPS_O_EOT;
+	event->options = SPS_O_DESC_DONE;
 	event->callback = tspp_sps_complete_cb;
 	event->xfer_done = NULL;
-	event->user = channel;
+	event->user = pdev;
 
 	rc = sps_register_event(channel->pipe, event);
 	if (rc) {
@@ -969,14 +1201,12 @@
 		goto err_event;
 	}
 
-	rc = pm_runtime_get(&channel->pdev->pdev->dev);
+	rc = pm_runtime_get(&pdev->pdev->dev);
 	if (rc < 0) {
-		dev_err(&channel->pdev->pdev->dev,
+		dev_err(&pdev->pdev->dev,
 			"Runtime PM: Unable to wake up tspp device, rc = %d",
 			rc);
 	}
-
-	wake_lock(&channel->pdev->wake_lock);
 	return 0;
 
 err_event:
@@ -991,16 +1221,38 @@
 }
 EXPORT_SYMBOL(tspp_open_channel);
 
-int tspp_close_channel(struct tspp_channel *channel)
+int tspp_close_channel(u32 dev, u32 channel_id)
 {
 	int i;
 	int id;
 	u32 val;
-	struct sps_connect *config = &channel->config;
-	struct tspp_device *pdev = channel->pdev;
 
-	TSPP_DEBUG("tspp_close_channel");
-	channel->used = 0;
+	struct sps_connect *config;
+	struct tspp_device *pdev;
+	struct tspp_channel *channel;
+	struct tspp_mem_buffer *pbuf, *temp;
+
+	if (channel_id >= TSPP_NUM_CHANNELS) {
+		pr_err("tspp: channel id out of range");
+		return -ECHRNG;
+	}
+	pdev = tspp_find_by_id(dev);
+	if (!pdev) {
+		pr_err("tspp_close: can't find device %i", dev);
+		return -ENODEV;
+	}
+	channel = &pdev->channels[channel_id];
+
+	/* if the channel is not used, we are done */
+	if (!channel->used)
+		return 0;
+
+	channel->notifier = NULL;
+	channel->notify_data = NULL;
+	channel->notify_timer = 0;
+
+	config = &channel->config;
+	pdev = channel->pdev;
 
 	/* disable pipe (channel) */
 	val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
@@ -1010,7 +1262,7 @@
 	/* unregister all filters for this channel */
 	for (i = 0; i < TSPP_NUM_PRIORITIES; i++) {
 		struct tspp_pid_filter *tspp_filter =
-			&tspp_filter_table[channel->src]->filter[i];
+			&pdev->filters[channel->src]->filter[i];
 		id = FILTER_GET_PIPE_NUMBER0(tspp_filter);
 		if (id == channel->id) {
 			if (FILTER_HAS_ENCRYPTION(tspp_filter))
@@ -1023,7 +1275,7 @@
 	channel->filter_count = 0;
 
 	/* stop the stream */
-	tspp_close_stream(channel);
+	tspp_close_stream(dev, channel->id);
 
 	/* disconnect the bam */
 	if (sps_disconnect(channel->pipe) != 0)
@@ -1033,68 +1285,68 @@
 	dma_free_coherent(NULL, config->desc.size, config->desc.base,
 		config->desc.phys_base);
 
-	for (i = 0; i < TSPP_NUM_BUFFERS; i++) {
-		if (channel->buffer[i].mem.phys_base) {
-#ifdef TSPP_USE_DMA_ALLOC_COHERENT
+	pbuf = channel->data;
+	for (i = 0; i < channel->buffer_count; i++) {
+		if (pbuf->desc.phys_base) {
 			dma_free_coherent(NULL,
-				channel->buffer[i].mem.size,
-				channel->buffer[i].mem.base,
-				channel->buffer[i].mem.phys_base);
-#else
-			dma_unmap_single(channel->dd,
-			channel->buffer[i].mem.phys_base,
-			channel->buffer[i].mem.size,
-			0);
-			kfree(channel->buffer[i].mem.base);
-#endif
-			channel->buffer[i].mem.phys_base = 0;
+				pbuf->desc.size,
+				pbuf->desc.virt_base,
+				pbuf->desc.phys_base);
+			pbuf->desc.phys_base = 0;
 		}
-		channel->buffer[i].mem.base = 0;
-		channel->buffer[i].state = TSPP_BUF_STATE_EMPTY;
+		pbuf->desc.virt_base = 0;
+		pbuf->state = TSPP_BUF_STATE_EMPTY;
+		temp = pbuf;
+		pbuf = pbuf->next;
+		kfree(temp);
 	}
 	channel->buffer_count = 0;
+	channel->data = NULL;
+	channel->read = NULL;
+	channel->waiting = NULL;
+	channel->locked = NULL;
+	channel->used = 0;
 
-	wake_unlock(&channel->pdev->wake_lock);
+	if (tspp_channels_in_use(pdev) == 0)
+		wake_unlock(&pdev->wake_lock);
+	tspp_clock_stop(pdev);
+
 	return 0;
 }
 EXPORT_SYMBOL(tspp_close_channel);
 
-/* picks a stream for this channel */
-int tspp_select_source(struct tspp_channel *channel,
-	struct tspp_select_source *src)
-{
-	/* make sure the requested src id is in bounds */
-	if (src->source > TSPP_SOURCE_MEM) {
-		pr_err("tspp source out of bounds");
-		return 1;
-	}
-
-	/* open the stream */
-	tspp_open_stream(channel, src->source);
-
-	return 0;
-}
-EXPORT_SYMBOL(tspp_select_source);
-
-int tspp_add_filter(struct tspp_channel *channel,
+int tspp_add_filter(u32 dev, u32 channel_id,
 	struct tspp_filter *filter)
 {
 	int i;
 	int other_channel;
 	int entry;
 	u32 val, pid, enabled;
-	struct tspp_device *pdev = channel->pdev;
+	struct tspp_device *pdev;
 	struct tspp_pid_filter p;
+	struct tspp_channel *channel;
 
-	TSPP_DEBUG("tspp_add_filter");
+	TSPP_DEBUG("tspp: add filter");
+	if (channel_id >= TSPP_NUM_CHANNELS) {
+		pr_err("tspp: channel id out of range");
+		return -ECHRNG;
+	}
+	pdev = tspp_find_by_id(dev);
+	if (!pdev) {
+		pr_err("tspp_add: can't find device %i", dev);
+		return -ENODEV;
+	}
+
+	channel = &pdev->channels[channel_id];
+
 	if (filter->source > TSPP_SOURCE_MEM) {
 		pr_err("tspp invalid source");
-		return 1;
+		return -ENOSR;
 	}
 
 	if (filter->priority >= TSPP_NUM_PRIORITIES) {
 		pr_err("tspp invalid source");
-		return 1;
+		return -ENOSR;
 	}
 
 	/* make sure this filter mode matches the channel mode */
@@ -1107,14 +1359,14 @@
 	case TSPP_MODE_RAW_NO_SUFFIX:
 		if (filter->mode != channel->mode) {
 			pr_err("tspp: wrong filter mode");
-			return 1;
+			return -EBADSLT;
 		}
 	}
 
 	if (filter->mode == TSPP_MODE_PES) {
 		for (i = 0; i < TSPP_NUM_PRIORITIES; i++) {
 			struct tspp_pid_filter *tspp_filter =
-				&tspp_filter_table[channel->src]->filter[i];
+				&pdev->filters[channel->src]->filter[i];
 			pid = FILTER_GET_PIPE_PID((tspp_filter));
 			enabled = FILTER_GET_PIPE_PROCESS0(tspp_filter);
 			if (enabled && (pid == filter->pid)) {
@@ -1122,18 +1374,18 @@
 					FILTER_GET_PIPE_NUMBER0(tspp_filter);
 				pr_err("tspp: pid 0x%x already in use by channel %i",
 					filter->pid, other_channel);
-				return 1;
+				return -EBADSLT;
 			}
 		}
 	}
 
 	/* make sure this priority is not already in use */
 	enabled = FILTER_GET_PIPE_PROCESS0(
-		(&(tspp_filter_table[channel->src]->filter[filter->priority])));
+		(&(pdev->filters[channel->src]->filter[filter->priority])));
 	if (enabled) {
 		pr_err("tspp: filter priority %i source %i is already enabled\n",
 			filter->priority, channel->src);
-		return 1;
+		return -ENOSR;
 	}
 
 	if (channel->mode == TSPP_MODE_PES) {
@@ -1147,7 +1399,7 @@
 
 	/* update entry */
 	p.filter = 0;
-	p.config = 0;
+	p.config = FILTER_TRANS_END_DISABLE;
 	FILTER_SET_PIPE_PROCESS0((&p), filter->mode);
 	FILTER_SET_PIPE_PID((&p), filter->pid);
 	FILTER_SET_PID_MASK((&p), filter->mask);
@@ -1162,68 +1414,56 @@
 			FILTER_SET_KEY_NUMBER((&p), entry);
 		}
 	}
-	TSPP_DEBUG("tspp_add_filter: mode=%i pid=%i mask=%i channel=%i",
-		filter->mode, filter->pid, filter->mask, channel->id);
 
-	tspp_filter_table[channel->src]->
+	pdev->filters[channel->src]->
 		filter[filter->priority].config = p.config;
-	tspp_filter_table[channel->src]->
+	pdev->filters[channel->src]->
 		filter[filter->priority].filter = p.filter;
 
+	/* allocate buffers if needed */
+	tspp_allocate_buffers(dev, channel->id, channel->max_buffers,
+		channel->buffer_size, channel->int_freq, 0, 0);
+	if (channel->buffer_count < MIN_ACCEPTABLE_BUFFER_COUNT) {
+		pr_err("tspp: failed to allocate at least %i buffers",
+			MIN_ACCEPTABLE_BUFFER_COUNT);
+		return -ENOMEM;
+	}
+
 	/* reenable pipe */
 	val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
 	writel_relaxed(val & ~(1 << channel->id), pdev->base + TSPP_PS_DISABLE);
 	wmb();
 	val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
 
-	/* allocate buffers if needed */
-	if (channel->buffer_count == 0) {
-		TSPP_DEBUG("tspp: no buffers need %i", TSPP_NUM_BUFFERS);
-		for (i = 0; i < TSPP_NUM_BUFFERS; i++) {
-			if (tspp_alloc_buffer(&channel->buffer[i].mem,
-				channel) != 0) {
-				pr_warn("tspp: Can't allocate buffer %i", i);
-			} else {
-				channel->buffer[i].filled = 0;
-				channel->buffer[i].read_index = 0;
-				channel->buffer_count++;
-
-				/* start the transfer */
-				if (sps_transfer_one(channel->pipe,
-					channel->buffer[i].mem.phys_base,
-					channel->buffer[i].mem.size,
-					channel,
-					SPS_IOVEC_FLAG_INT |
-					SPS_IOVEC_FLAG_EOB))
-					pr_err("tspp: can't submit transfer");
-				else
-					channel->buffer[i].state =
-						TSPP_BUF_STATE_WAITING;
-			}
-		}
-	}
-
-	if (channel->buffer_count < MIN_ACCEPTABLE_BUFFER_COUNT) {
-		pr_err("failed to allocate at least %i buffers",
-			MIN_ACCEPTABLE_BUFFER_COUNT);
-		return -ENOMEM;
-	}
-
 	channel->filter_count++;
 
 	return 0;
 }
 EXPORT_SYMBOL(tspp_add_filter);
 
-int tspp_remove_filter(struct tspp_channel *channel,
+int tspp_remove_filter(u32 dev, u32 channel_id,
 	struct tspp_filter *filter)
 {
 	int entry;
 	u32 val;
-	struct tspp_device *pdev = channel->pdev;
-	int src = channel->src;
-	struct tspp_pid_filter *tspp_filter =
-		&(tspp_filter_table[src]->filter[filter->priority]);
+	struct tspp_device *pdev;
+	int src;
+	struct tspp_pid_filter *tspp_filter;
+	struct tspp_channel *channel;
+
+	if (channel_id >= TSPP_NUM_CHANNELS) {
+		pr_err("tspp: channel id out of range");
+		return -ECHRNG;
+	}
+	pdev = tspp_find_by_id(dev);
+	if (!pdev) {
+		pr_err("tspp_remove: can't find device %i", dev);
+		return -ENODEV;
+	}
+	channel = &pdev->channels[channel_id];
+
+	src = channel->src;
+	tspp_filter = &(pdev->filters[src]->filter[filter->priority]);
 
 	/* disable pipe (channel) */
 	val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
@@ -1253,17 +1493,30 @@
 }
 EXPORT_SYMBOL(tspp_remove_filter);
 
-int tspp_set_key(struct tspp_channel *channel, struct tspp_key* key)
+int tspp_set_key(u32 dev, u32 channel_id, struct tspp_key *key)
 {
 	int i;
 	int id;
 	int key_index;
 	int data;
+	struct tspp_channel *channel;
+	struct tspp_device *pdev;
+
+	if (channel_id >= TSPP_NUM_CHANNELS) {
+		pr_err("tspp: channel id out of range");
+		return -ECHRNG;
+	}
+	pdev = tspp_find_by_id(dev);
+	if (!pdev) {
+		pr_err("tspp_set: can't find device %i", dev);
+		return -ENODEV;
+	}
+	channel = &pdev->channels[channel_id];
 
 	/* read the key index used by this channel */
 	for (i = 0; i < TSPP_NUM_PRIORITIES; i++) {
 		struct tspp_pid_filter *tspp_filter =
-			&(tspp_filter_table[channel->src]->filter[i]);
+			&(pdev->filters[channel->src]->filter[i]);
 		id = FILTER_GET_PIPE_NUMBER0(tspp_filter);
 		if (id == channel->id) {
 			if (FILTER_HAS_ENCRYPTION(tspp_filter)) {
@@ -1274,15 +1527,15 @@
 	}
 	if (i == TSPP_NUM_PRIORITIES) {
 		pr_err("tspp: no encryption on this channel");
-		return 1;
+		return -ENOKEY;
 	}
 
 	if (key->parity == TSPP_KEY_PARITY_EVEN) {
-		tspp_key_table->entry[key_index].even_lsb = key->lsb;
-		tspp_key_table->entry[key_index].even_msb = key->msb;
+		pdev->tspp_key_table->entry[key_index].even_lsb = key->lsb;
+		pdev->tspp_key_table->entry[key_index].even_msb = key->msb;
 	} else {
-		tspp_key_table->entry[key_index].odd_lsb = key->lsb;
-		tspp_key_table->entry[key_index].odd_msb = key->msb;
+		pdev->tspp_key_table->entry[key_index].odd_lsb = key->lsb;
+		pdev->tspp_key_table->entry[key_index].odd_msb = key->msb;
 	}
 	data = readl_relaxed(channel->pdev->base + TSPP_KEY_VALID);
 
@@ -1290,49 +1543,253 @@
 }
 EXPORT_SYMBOL(tspp_set_key);
 
-static int tspp_set_iv(struct tspp_channel *channel, struct tspp_iv *iv)
+int tspp_register_notification(u32 dev, u32 channel_id,
+	tspp_notifier *pNotify, void *userdata, u32 timer_ms)
 {
-	struct tspp_device *pdev = channel->pdev;
+	struct tspp_channel *channel;
+	struct tspp_device *pdev;
 
-	writel_relaxed(iv->data[0], pdev->base + TSPP_CBC_INIT_VAL(0));
-	writel_relaxed(iv->data[1], pdev->base + TSPP_CBC_INIT_VAL(1));
+	if (channel_id >= TSPP_NUM_CHANNELS) {
+		pr_err("tspp: channel id out of range");
+		return -ECHRNG;
+	}
+	pdev = tspp_find_by_id(dev);
+	if (!pdev) {
+		pr_err("tspp_reg: can't find device %i", dev);
+		return -ENODEV;
+	}
+	channel = &pdev->channels[channel_id];
+	channel->notifier = pNotify;
+	channel->notify_data = userdata;
+	channel->notify_timer = timer_ms;
 	return 0;
 }
+EXPORT_SYMBOL(tspp_register_notification);
 
-static int tspp_set_system_keys(struct tspp_channel *channel,
-	struct tspp_system_keys *keys)
+int tspp_unregister_notification(u32 dev, u32 channel_id)
 {
-	int i;
-	struct tspp_device *pdev = channel->pdev;
+	struct tspp_channel *channel;
+	struct tspp_device *pdev;
 
-	for (i = 0; i < TSPP_NUM_SYSTEM_KEYS; i++)
-		writel_relaxed(keys->data[i], pdev->base + TSPP_SYSTEM_KEY(i));
-
+	if (channel_id >= TSPP_NUM_CHANNELS) {
+		pr_err("tspp: channel id out of range");
+		return -ECHRNG;
+	}
+	pdev = tspp_find_by_id(dev);
+	if (!pdev) {
+		pr_err("tspp_unreg: can't find device %i", dev);
+		return -ENODEV;
+	}
+	channel = &pdev->channels[channel_id];
+	channel->notifier = NULL;
+	channel->notify_data = 0;
 	return 0;
 }
+EXPORT_SYMBOL(tspp_unregister_notification);
 
-static int tspp_set_buffer_size(struct tspp_channel *channel,
-	struct tspp_buffer *buf)
+const struct tspp_data_descriptor *tspp_get_buffer(u32 dev, u32 channel_id)
 {
-	if (buf->size < TSPP_MIN_BUFFER_SIZE)
-		channel->bufsize = TSPP_MIN_BUFFER_SIZE;
-	else if (buf->size > TSPP_MAX_BUFFER_SIZE)
-		channel->bufsize = TSPP_MAX_BUFFER_SIZE;
-	else
-		channel->bufsize = buf->size;
+	struct tspp_mem_buffer *buffer;
+	struct tspp_channel *channel;
+	struct tspp_device *pdev;
 
-	TSPP_DEBUG("tspp channel %i buffer size %i",
-		channel->id, channel->bufsize);
+	if (channel_id >= TSPP_NUM_CHANNELS) {
+		pr_err("tspp: channel id out of range");
+		return NULL;
+	}
+	pdev = tspp_find_by_id(dev);
+	if (!pdev) {
+		pr_err("tspp_get: can't find device %i", dev);
+		return NULL;
+	}
+	channel = &pdev->channels[channel_id];
 
+	if (!channel->read) {
+		pr_warn("tspp: no buffer to get on channel %i!",
+			channel->id);
+		return NULL;
+	}
+
+	buffer = channel->read;
+	/* see if we have any buffers ready to read */
+	if (buffer->state != TSPP_BUF_STATE_DATA)
+		return 0;
+
+	if (buffer->state == TSPP_BUF_STATE_DATA) {
+		/* mark the buffer as busy */
+		buffer->state = TSPP_BUF_STATE_LOCKED;
+
+		/* increment the pointer along the list */
+		channel->read = channel->read->next;
+	}
+
+	return &buffer->desc;
+}
+EXPORT_SYMBOL(tspp_get_buffer);
+
+int tspp_release_buffer(u32 dev, u32 channel_id, u32 descriptor_id)
+{
+	int i, found = 0;
+	struct tspp_mem_buffer *buffer;
+	struct tspp_channel *channel;
+	struct tspp_device *pdev;
+
+	if (channel_id >= TSPP_NUM_CHANNELS) {
+		pr_err("tspp: channel id out of range");
+		return -ECHRNG;
+	}
+	pdev = tspp_find_by_id(dev);
+	if (!pdev) {
+		pr_err("tspp: can't find device %i", dev);
+		return -ENODEV;
+	}
+	channel = &pdev->channels[channel_id];
+
+	if (descriptor_id > channel->buffer_count)
+		pr_warn("tspp: desc id looks weird 0x%08x", descriptor_id);
+
+	/* find the correct descriptor */
+	buffer = channel->locked;
+	for (i = 0; i < channel->buffer_count; i++) {
+		if (buffer->desc.id == descriptor_id) {
+			found = 1;
+			break;
+		}
+		buffer = buffer->next;
+	}
+	channel->locked = channel->locked->next;
+
+	if (!found) {
+		pr_err("tspp: cant find desc %i", descriptor_id);
+		return -EINVAL;
+	}
+
+	/* make sure the buffer is in the expected state */
+	if (buffer->state != TSPP_BUF_STATE_LOCKED) {
+		pr_err("tspp: buffer %i not locked", descriptor_id);
+		return -EINVAL;
+	}
+	/* unlock the buffer and requeue it */
+	buffer->state = TSPP_BUF_STATE_WAITING;
+
+	if (tspp_queue_buffer(channel, buffer))
+		pr_warn("tspp: can't requeue buffer");
 	return 0;
 }
+EXPORT_SYMBOL(tspp_release_buffer);
+
+int tspp_allocate_buffers(u32 dev, u32 channel_id,	u32 count,
+	u32 size, u32 int_freq, tspp_allocator *alloc, void *user)
+{
+	struct tspp_channel *channel;
+	struct tspp_device *pdev;
+	struct tspp_mem_buffer *last = NULL;
+
+	TSPP_DEBUG("tspp_allocate_buffers");
+
+	if (channel_id >= TSPP_NUM_CHANNELS) {
+		pr_err("tspp: channel id out of range");
+		return -ECHRNG;
+	}
+	pdev = tspp_find_by_id(dev);
+	if (!pdev) {
+		pr_err("tspp_alloc: can't find device %i", dev);
+		return -ENODEV;
+	}
+	channel = &pdev->channels[channel_id];
+
+	channel->max_buffers = count;
+
+	/* set up interrupt frequency */
+	if (int_freq > channel->max_buffers)
+		int_freq = channel->max_buffers;
+	channel->int_freq = int_freq;
+
+	switch (channel->mode) {
+	case TSPP_MODE_DISABLED:
+	case TSPP_MODE_PES:
+		/* give the user what he asks for */
+		channel->buffer_size = size;
+		break;
+
+	case TSPP_MODE_RAW:
+		/* must be a multiple of 192 */
+		if (size < (TSPP_PACKET_LENGTH+4))
+			channel->buffer_size = (TSPP_PACKET_LENGTH+4);
+		else
+			channel->buffer_size = (size /
+				(TSPP_PACKET_LENGTH+4)) *
+				(TSPP_PACKET_LENGTH+4);
+		break;
+
+	case TSPP_MODE_RAW_NO_SUFFIX:
+		/* must be a multiple of 188 */
+		channel->buffer_size = (size / TSPP_PACKET_LENGTH) *
+			TSPP_PACKET_LENGTH;
+		break;
+	}
+
+	for (; channel->buffer_count < channel->max_buffers;
+		channel->buffer_count++) {
+
+		/* allocate the descriptor */
+		struct tspp_mem_buffer *desc = (struct tspp_mem_buffer *)
+			kmalloc(sizeof(struct tspp_mem_buffer), GFP_KERNEL);
+		if (!desc) {
+			pr_warn("tspp: Can't allocate desc %i",
+			channel->buffer_count);
+			break;
+		}
+
+		desc->desc.id = channel->buffer_count;
+		/* allocate the buffer */
+		if (tspp_alloc_buffer(channel_id, &desc->desc,
+			channel->buffer_size, alloc, user) != 0) {
+			kfree(desc);
+			pr_warn("tspp: Can't allocate buffer %i",
+				channel->buffer_count);
+			break;
+		}
+
+		/* add the descriptor to the list */
+		desc->filled = 0;
+		desc->read_index = 0;
+		if (!channel->data) {
+			channel->data = desc;
+			desc->next = channel->data;
+		} else {
+			last->next = desc;
+		}
+		last = desc;
+		desc->next = channel->data;
+
+		/* prepare the sps descriptor */
+		desc->sps.phys_base = desc->desc.phys_base;
+		desc->sps.base = desc->desc.virt_base;
+		desc->sps.size = desc->desc.size;
+
+		/* start the transfer */
+		if (tspp_queue_buffer(channel, desc))
+			pr_err("tspp: can't queue buffer %i", desc->desc.id);
+	}
+
+	channel->waiting = channel->data;
+	channel->read = channel->data;
+	channel->locked = channel->data;
+	return 0;
+}
+EXPORT_SYMBOL(tspp_allocate_buffers);
 
 /*** File Operations ***/
 static ssize_t tspp_open(struct inode *inode, struct file *filp)
 {
+	u32 dev;
 	struct tspp_channel *channel;
+
+	TSPP_DEBUG("tspp_open");
 	channel = container_of(inode->i_cdev, struct tspp_channel, cdev);
 	filp->private_data = channel;
+	dev = channel->pdev->pdev->id;
 
 	/* if this channel is already in use, quit */
 	if (channel->used) {
@@ -1341,7 +1798,7 @@
 		return -EACCES;
 	}
 
-	if (tspp_open_channel(channel) != 0) {
+	if (tspp_open_channel(dev, channel->id) != 0) {
 		pr_err("tspp: error opening channel");
 		return -EACCES;
 	}
@@ -1360,7 +1817,8 @@
 	poll_wait(filp, &channel->in_queue, p);
 
 	spin_lock_irqsave(&channel->pdev->spinlock, flags);
-	if (channel->buffer[channel->read].state == TSPP_BUF_STATE_DATA)
+	if (channel->read &&
+		channel->read->state == TSPP_BUF_STATE_DATA)
 		mask = POLLIN | POLLRDNORM;
 
 	spin_unlock_irqrestore(&channel->pdev->spinlock, flags);
@@ -1370,11 +1828,11 @@
 
 static ssize_t tspp_release(struct inode *inode, struct file *filp)
 {
-	struct tspp_channel *channel;
-	channel = filp->private_data;
+	struct tspp_channel *channel = filp->private_data;
+	u32 dev = channel->pdev->pdev->id;
+	TSPP_DEBUG("tspp_release");
 
-	pr_info("tspp_release");
-	tspp_close_channel(channel);
+	tspp_close_channel(dev, channel->id);
 
 	return 0;
 }
@@ -1389,7 +1847,23 @@
 	channel = filp->private_data;
 
 	TSPP_DEBUG("tspp_read");
-	buffer = &channel->buffer[channel->read];
+
+	while (!channel->read) {
+		if (filp->f_flags & O_NONBLOCK) {
+			pr_warn("tspp: no buffer on channel %i!",
+				channel->id);
+			return -EAGAIN;
+		}
+		/* go to sleep if there is nothing to read */
+		if (wait_event_interruptible(channel->in_queue,
+			(channel->read != NULL))) {
+			pr_err("tspp: rude awakening\n");
+			return -ERESTARTSYS;
+		}
+	}
+
+	buffer = channel->read;
+
 	/* see if we have any buffers ready to read */
 	while (buffer->state != TSPP_BUF_STATE_DATA) {
 		if (filp->f_flags & O_NONBLOCK) {
@@ -1398,7 +1872,6 @@
 			return -EAGAIN;
 		}
 		/* go to sleep if there is nothing to read */
-	   TSPP_DEBUG("tspp: sleeping");
 		if (wait_event_interruptible(channel->in_queue,
 			(buffer->state == TSPP_BUF_STATE_DATA))) {
 			pr_err("tspp: rude awakening\n");
@@ -1408,26 +1881,13 @@
 
 	while (buffer->state == TSPP_BUF_STATE_DATA) {
 		size = min(count, buffer->filled);
-		TSPP_DEBUG("tspp: reading channel %i buffer %i size %i",
-			channel->id, channel->read, size);
 		if (size == 0)
 			break;
 
-#ifndef TSPP_USE_DMA_ALLOC_COHERENT
-		/* unmap buffer (invalidates processor cache) */
-		if (buffer->mem.phys_base) {
-			dma_unmap_single(NULL,
-				buffer->mem.phys_base,
-				buffer->mem.size,
-				DMA_FROM_DEVICE);
-			buffer->mem.phys_base = 0;
-		}
-#endif
-
-		if (copy_to_user(buf, buffer->mem.base +
+		if (copy_to_user(buf, buffer->desc.virt_base +
 			buffer->read_index, size)) {
 			pr_err("tspp: error copying to user buffer");
-			return -EFAULT;
+			return -EBUSY;
 		}
 		buf += size;
 		count -= size;
@@ -1436,32 +1896,12 @@
 
 		/* after reading the end of the buffer, requeue it,
 			and set up for reading the next one */
-		if (buffer->read_index ==
-			channel->buffer[channel->read].filled) {
+		if (buffer->read_index == buffer->filled) {
 			buffer->state = TSPP_BUF_STATE_WAITING;
-#ifndef TSPP_USE_DMA_ALLOC_COHERENT
-			buffer->mem.phys_base = dma_map_single(NULL,
-				buffer->mem.base,
-				buffer->mem.size,
-				DMA_FROM_DEVICE);
-			if (!dma_mapping_error(NULL,
-			buffer->mem.phys_base)) {
-#endif
-				if (sps_transfer_one(channel->pipe,
-					buffer->mem.phys_base,
-					buffer->mem.size,
-					channel,
-					SPS_IOVEC_FLAG_INT |
-					SPS_IOVEC_FLAG_EOT))
-					pr_err("tspp: can't submit transfer");
-				else {
-					channel->read++;
-					if (channel->read == TSPP_NUM_BUFFERS)
-						channel->read = 0;
-				}
-#ifndef TSPP_USE_DMA_ALLOC_COHERENT
-			}
-#endif
+			if (tspp_queue_buffer(channel, buffer))
+				pr_err("tspp: can't submit transfer");
+			channel->locked = channel->read;
+			channel->read = channel->read->next;
 		}
 	}
 
@@ -1471,45 +1911,84 @@
 static long tspp_ioctl(struct file *filp,
 			unsigned int param0, unsigned long param1)
 {
+	u32 dev;
 	int rc = -1;
 	struct tspp_channel *channel;
+	struct tspp_select_source ss;
+	struct tspp_filter f;
+	struct tspp_key k;
+	struct tspp_iv iv;
+	struct tspp_system_keys sk;
+	struct tspp_buffer b;
 	channel = filp->private_data;
+	dev = channel->pdev->pdev->id;
 
 	if (!param1)
 		return -EINVAL;
 
 	switch (param0) {
 	case TSPP_IOCTL_SELECT_SOURCE:
-		rc = tspp_select_source(channel,
-			(struct tspp_select_source *)param1);
+		if (!access_ok(VERIFY_READ, param1,
+			sizeof(struct tspp_select_source))) {
+			return -EBUSY;
+		}
+		if (__copy_from_user(&ss, (void *)param1,
+			sizeof(struct tspp_select_source)) == 0)
+			rc = tspp_select_source(dev, channel->id, &ss);
 		break;
 	case TSPP_IOCTL_ADD_FILTER:
-		rc = tspp_add_filter(channel,
-			(struct tspp_filter *)param1);
+		if (!access_ok(VERIFY_READ, param1,
+			sizeof(struct tspp_filter))) {
+			return -ENOSR;
+		}
+		if (__copy_from_user(&f, (void *)param1,
+			sizeof(struct tspp_filter)) == 0)
+			rc = tspp_add_filter(dev, channel->id, &f);
 		break;
 	case TSPP_IOCTL_REMOVE_FILTER:
-		rc = tspp_remove_filter(channel,
-			(struct tspp_filter *)param1);
+		if (!access_ok(VERIFY_READ, param1,
+			sizeof(struct tspp_filter))) {
+			return -EBUSY;
+		}
+		if (__copy_from_user(&f, (void *)param1,
+			sizeof(struct tspp_filter)) == 0)
+			rc = tspp_remove_filter(dev, channel->id, &f);
 		break;
 	case TSPP_IOCTL_SET_KEY:
-		rc = tspp_set_key(channel,
-			(struct tspp_key *)param1);
+		if (!access_ok(VERIFY_READ, param1,
+			sizeof(struct tspp_key))) {
+			return -EBUSY;
+		}
+		if (__copy_from_user(&k, (void *)param1,
+			sizeof(struct tspp_key)) == 0)
+			rc = tspp_set_key(dev, channel->id, &k);
 		break;
 	case TSPP_IOCTL_SET_IV:
-		rc = tspp_set_iv(channel,
-			(struct tspp_iv *)param1);
+		if (!access_ok(VERIFY_READ, param1,
+			sizeof(struct tspp_iv))) {
+			return -EBUSY;
+		}
+		if (__copy_from_user(&iv, (void *)param1,
+			sizeof(struct tspp_iv)) == 0)
+			rc = tspp_set_iv(channel, &iv);
 		break;
 	case TSPP_IOCTL_SET_SYSTEM_KEYS:
-		rc = tspp_set_system_keys(channel,
-			(struct tspp_system_keys *)param1);
+		if (!access_ok(VERIFY_READ, param1,
+			sizeof(struct tspp_system_keys))) {
+			return -EINVAL;
+		}
+		if (__copy_from_user(&sk, (void *)param1,
+			sizeof(struct tspp_system_keys)) == 0)
+			rc = tspp_set_system_keys(channel, &sk);
 		break;
 	case TSPP_IOCTL_BUFFER_SIZE:
-		rc = tspp_set_buffer_size(channel,
-			(struct tspp_buffer *)param1);
-		break;
-	case TSPP_IOCTL_LOOPBACK:
-		loopback_mode = param1;
-		rc = 0;
+		if (!access_ok(VERIFY_READ, param1,
+			sizeof(struct tspp_buffer))) {
+			rc = -EINVAL;
+		}
+		if (__copy_from_user(&b, (void *)param1,
+			sizeof(struct tspp_buffer)) == 0)
+			rc = tspp_set_buffer_size(channel, &b);
 		break;
 	default:
 		pr_err("tspp: Unknown ioctl %i", param0);
@@ -1518,13 +1997,12 @@
 	/* normalize the return code in case one of the subfunctions does
 		something weird */
 	if (rc != 0)
-		rc = 1;
+		rc = -ENOIOCTLCMD;
 
 	return rc;
 }
 
 /*** debugfs ***/
-#ifdef TSPP_USE_DEBUGFS
 static int debugfs_iomem_x32_set(void *data, u64 val)
 {
 	writel_relaxed(val, data);
@@ -1605,45 +2083,6 @@
 			device->debugfs_regs[i] = NULL;
 	}
 }
-#endif /* TSPP_USE_DEBUGFS */
-
-static const struct file_operations tspp_fops = {
-	.owner   = THIS_MODULE,
-	.read    = tspp_read,
-	.open    = tspp_open,
-	.poll    = tspp_poll,
-	.release = tspp_release,
-	.unlocked_ioctl   = tspp_ioctl,
-};
-
-static int tspp_channel_init(struct tspp_channel *channel)
-{
-	channel->bufsize = TSPP_MIN_BUFFER_SIZE;
-	channel->read = 0;
-	channel->waiting = 0;
-	cdev_init(&channel->cdev, &tspp_fops);
-	channel->cdev.owner = THIS_MODULE;
-	channel->id = MINOR(tspp_minor);
-	init_waitqueue_head(&channel->in_queue);
-	channel->buffer_count = 0;
-	channel->filter_count = 0;
-
-	if (cdev_add(&channel->cdev, tspp_minor++, 1) != 0) {
-		pr_err("tspp: cdev_add failed");
-		return 1;
-	}
-
-	channel->dd = device_create(tspp_class, NULL, channel->cdev.dev,
-		channel, "tspp%02d", channel->id);
-	if (IS_ERR(channel->dd)) {
-		pr_err("tspp: device_create failed: %i",
-			(int)PTR_ERR(channel->dd));
-		cdev_del(&channel->cdev);
-		return 1;
-	}
-
-	return 0;
-}
 
 static int __devinit msm_tspp_probe(struct platform_device *pdev)
 {
@@ -1656,7 +2095,6 @@
 	struct resource *mem_tsif1;
 	struct resource *mem_tspp;
 	struct resource *mem_bam;
-	struct tspp_channel *channel;
 
 	/* must have platform data */
 	data = pdev->dev.platform_data;
@@ -1667,7 +2105,7 @@
 	}
 
 	/* check for valid device id */
-	if ((pdev->id < 0) || (pdev->id >= 1)) {
+	if ((pdev->id < 0) || (pdev->id >= TSPP_MAX_DEVICES)) {
 		pr_err("tspp: Invalid device ID %d", pdev->id);
 		rc = -EINVAL;
 		goto out;
@@ -1789,24 +2227,25 @@
 	pm_runtime_set_active(&pdev->dev);
 	pm_runtime_enable(&pdev->dev);
 
-#ifdef TSPP_USE_DEBUGFS
 	tspp_debugfs_init(device, 0);
 
 	for (i = 0; i < TSPP_TSIF_INSTANCES; i++)
 		tsif_debugfs_init(&device->tsif[i], i);
-#endif /* TSPP_USE_DEBUGFS */
 
 	wake_lock_init(&device->wake_lock, WAKE_LOCK_SUSPEND,
 		dev_name(&pdev->dev));
 
 	/* set up pointers to ram-based 'registers' */
-	tspp_filter_table[0] = TSPP_PID_FILTER_TABLE0 + device->base;
-	tspp_filter_table[1] = TSPP_PID_FILTER_TABLE1 + device->base;
-	tspp_filter_table[2] = TSPP_PID_FILTER_TABLE2 + device->base;
-	tspp_key_table = TSPP_DATA_KEY + device->base;
-	tspp_global_performance = TSPP_GLOBAL_PERFORMANCE + device->base;
-	tspp_pipe_context = TSPP_PIPE_CONTEXT + device->base;
-	tspp_pipe_performance = TSPP_PIPE_PERFORMANCE + device->base;
+	device->filters[0] = device->base + TSPP_PID_FILTER_TABLE0;
+	device->filters[1] = device->base + TSPP_PID_FILTER_TABLE1;
+	device->filters[2] = device->base + TSPP_PID_FILTER_TABLE2;
+	device->tspp_key_table = device->base + TSPP_DATA_KEY;
+	device->tspp_global_performance =
+		device->base + TSPP_GLOBAL_PERFORMANCE;
+	device->tspp_pipe_context =
+		device->base + TSPP_PIPE_CONTEXT;
+	device->tspp_pipe_performance =
+		device->base + TSPP_PIPE_PERFORMANCE;
 
 	device->bam_props.summing_threshold = 0x10;
 	device->bam_props.irq = device->bam_irq;
@@ -1818,14 +2257,9 @@
 		goto err_bam;
 	}
 
-	if (device->tsif_pclk && clk_prepare_enable(device->tsif_pclk) != 0) {
-		dev_err(&pdev->dev, "Can't start pclk");
-		goto err_pclk;
-	}
-	if (device->tsif_ref_clk &&
-		clk_prepare_enable(device->tsif_ref_clk) != 0) {
-		dev_err(&pdev->dev, "Can't start ref clk");
-		goto err_refclk;
+	if (tspp_clock_start(device) != 0) {
+		dev_err(&pdev->dev, "Can't start clocks");
+		goto err_clock;
 	}
 
 	spin_lock_init(&device->spinlock);
@@ -1839,26 +2273,29 @@
 	if (version != 1)
 		pr_warn("tspp: unrecognized hw version=%i", version);
 
-	/* update the channels with the device */
+	/* initialize the channels */
 	for (i = 0; i < TSPP_NUM_CHANNELS; i++) {
-		channel = &channel_list[i];
-		channel->pdev = device;
+		if (tspp_channel_init(&(device->channels[i]), device) != 0) {
+			pr_err("tspp_channel_init failed");
+			goto err_channel;
+		}
 	}
 
-	/* everything is ok */
+	/* stop the clocks for power savings */
+	tspp_clock_stop(device);
+
+	/* everything is ok, so add the device to the list */
+	list_add_tail(&(device->devlist), &tspp_devices);
+
 	return 0;
 
-err_refclk:
-	if (device->tsif_pclk)
-		clk_disable_unprepare(device->tsif_pclk);
-err_pclk:
+err_channel:
+err_clock:
 	sps_deregister_bam_device(device->bam_handle);
 err_bam:
-#ifdef TSPP_USE_DEBUGFS
 	tspp_debugfs_exit(device);
 	for (i = 0; i < TSPP_TSIF_INSTANCES; i++)
 		tsif_debugfs_exit(&device->tsif[i]);
-#endif /* TSPP_USE_DEBUGFS */
 err_gpio:
 err_irq:
 	tspp_stop_gpios(device);
@@ -1888,18 +2325,23 @@
 
 static int __devexit msm_tspp_remove(struct platform_device *pdev)
 {
-#ifdef TSPP_USE_DEBUGFS
+	struct tspp_channel *channel;
 	u32 i;
-#endif /* TSPP_USE_DEBUGFS */
 
 	struct tspp_device *device = platform_get_drvdata(pdev);
 
+	/* free the buffers, and delete the channels */
+	for (i = 0; i < TSPP_NUM_CHANNELS; i++) {
+		channel = &device->channels[i];
+		tspp_close_channel(device->pdev->id, i);
+		device_destroy(tspp_class, channel->cdev.dev);
+		cdev_del(&channel->cdev);
+	}
+
 	sps_deregister_bam_device(device->bam_handle);
 
-#ifdef TSPP_USE_DEBUGFS
 	for (i = 0; i < TSPP_TSIF_INSTANCES; i++)
 		tsif_debugfs_exit(&device->tsif[i]);
-#endif /* TSPP_USE_DEBUGFS */
 
 	wake_lock_destroy(&device->wake_lock);
 	free_irq(device->tspp_irq, device);
@@ -1954,17 +2396,9 @@
 
 static int __init mod_init(void)
 {
-	u32 i;
 	int rc;
 
-	/* first register the driver, and check hardware */
-	rc = platform_driver_register(&msm_tspp_driver);
-	if (rc) {
-		pr_err("tspp: platform_driver_register failed: %d", rc);
-		goto err_register;
-	}
-
-	/* now make the char devs (channels) */
+	/* make the char devs (channels) */
 	rc = alloc_chrdev_region(&tspp_minor, 0, TSPP_NUM_CHANNELS, "tspp");
 	if (rc) {
 		pr_err("tspp: alloc_chrdev_region failed: %d", rc);
@@ -1978,43 +2412,35 @@
 		goto err_class;
 	}
 
-	for (i = 0; i < TSPP_NUM_CHANNELS; i++) {
-		if (tspp_channel_init(&channel_list[i]) != 0) {
-			pr_err("tspp_channel_init failed");
-			break;
-		}
+	/* register the driver, and check hardware */
+	rc = platform_driver_register(&msm_tspp_driver);
+	if (rc) {
+		pr_err("tspp: platform_driver_register failed: %d", rc);
+		goto err_register;
 	}
 
 	return 0;
 
+err_register:
+	class_destroy(tspp_class);
 err_class:
 	unregister_chrdev_region(0, TSPP_NUM_CHANNELS);
 err_devrgn:
-	platform_driver_unregister(&msm_tspp_driver);
-err_register:
 	return rc;
 }
 
 static void __exit mod_exit(void)
 {
-	u32 i;
-	struct tspp_channel *channel;
+	/* delete low level driver */
+	platform_driver_unregister(&msm_tspp_driver);
 
-	/* first delete upper layer interface */
-	for (i = 0; i < TSPP_NUM_CHANNELS; i++) {
-		channel = &channel_list[i];
-		device_destroy(tspp_class, channel->cdev.dev);
-		cdev_del(&channel->cdev);
-	}
+	/* delete upper layer interface */
 	class_destroy(tspp_class);
 	unregister_chrdev_region(0, TSPP_NUM_CHANNELS);
-
-	/* now delete low level driver */
-	platform_driver_unregister(&msm_tspp_driver);
 }
 
 module_init(mod_init);
 module_exit(mod_exit);
 
-MODULE_DESCRIPTION("TSPP character device interface");
+MODULE_DESCRIPTION("TSPP platform device and char dev");
 MODULE_LICENSE("GPL v2");
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/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 590aa58..d82c353 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -409,7 +409,6 @@
 	if (index == EXT_CSD_BKOPS_START)
 		return 0;
 
-	mmc_delay(1);
 	/* Must check status to be sure of no errors */
 	do {
 		err = mmc_send_status(card, &status);
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index b22e2f0..52fd5e8 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -725,12 +725,6 @@
 		mmc_hostname(host->mmc), __func__,
 		notify->event_id);
 
-	if (msmsdcc_is_dml_busy(host)) {
-		/* oops !!! this should never happen. */
-		pr_err("%s: %s: Received SPS EOT event"
-			" but DML HW is still busy !!!\n",
-			mmc_hostname(host->mmc), __func__);
-	}
 	/*
 	 * Got End of transfer event!!! Check if all of the data
 	 * has been transferred?
@@ -1165,15 +1159,16 @@
 	if (mmc_cmd_type(cmd) == MMC_CMD_ADTC)
 		*c |= MCI_CSPM_DATCMD;
 
-	/* Check if AUTO CMD19 is required or not? */
+	/* Check if AUTO CMD19/CMD21 is required or not? */
 	if (host->tuning_needed &&
-		!(host->mmc->ios.timing == MMC_TIMING_MMC_HS200)) {
-
+		(host->en_auto_cmd19 || host->en_auto_cmd21)) {
 		/*
 		 * For open ended block read operation (without CMD23),
-		 * AUTO_CMD19 bit should be set while sending the READ command.
+		 * AUTO_CMD19/AUTO_CMD21 bit should be set while sending
+		 * the READ command.
 		 * For close ended block read operation (with CMD23),
-		 * AUTO_CMD19 bit should be set while sending CMD23.
+		 * AUTO_CMD19/AUTO_CMD21 bit should be set while sending
+		 * CMD23.
 		 */
 		if ((cmd->opcode == MMC_SET_BLOCK_COUNT &&
 			host->curr.mrq->cmd->opcode ==
@@ -1182,7 +1177,12 @@
 			(cmd->opcode == MMC_READ_SINGLE_BLOCK ||
 			cmd->opcode == MMC_READ_MULTIPLE_BLOCK))) {
 			msmsdcc_enable_cdr_cm_sdc4_dll(host);
-			*c |= MCI_CSPM_AUTO_CMD19;
+			if (host->en_auto_cmd19 &&
+			    host->mmc->ios.timing == MMC_TIMING_UHS_SDR104)
+				*c |= MCI_CSPM_AUTO_CMD19;
+			else if (host->en_auto_cmd21 &&
+			    host->mmc->ios.timing == MMC_TIMING_MMC_HS200)
+				*c |= MCI_CSPM_AUTO_CMD21;
 		}
 	}
 
@@ -1241,25 +1241,12 @@
 		if (is_dma_mode(host) && !msmsdcc_config_dma(host, data)) {
 			datactrl |= MCI_DPSM_DMAENABLE;
 		} else if (is_sps_mode(host)) {
-			if (!msmsdcc_is_dml_busy(host)) {
-				if (!msmsdcc_sps_start_xfer(host, data)) {
-					/* Now kick start DML transfer */
-					mb();
-					msmsdcc_dml_start_xfer(host, data);
-					datactrl |= MCI_DPSM_DMAENABLE;
-					host->sps.busy = 1;
-				}
-			} else {
-				/*
-				 * Can't proceed with new transfer as
-				 * previous trasnfer is already in progress.
-				 * There is no point of going into PIO mode
-				 * as well. Is this a time to do kernel panic?
-				 */
-				pr_err("%s: %s: DML HW is busy!!!"
-					" Can't perform new SPS transfers"
-					" now\n", mmc_hostname(host->mmc),
-					__func__);
+			if (!msmsdcc_sps_start_xfer(host, data)) {
+				/* Now kick start DML transfer */
+				mb();
+				msmsdcc_dml_start_xfer(host, data);
+				datactrl |= MCI_DPSM_DMAENABLE;
+				host->sps.busy = 1;
 			}
 		}
 	}
@@ -1370,9 +1357,11 @@
 		 */
 		if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
 			|| data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
-			pr_err("%s: CMD%d: Data timeout\n",
+			pr_err("%s: CMD%d: Data timeout. DAT0 => %d\n",
 				 mmc_hostname(host->mmc),
-				 data->mrq->cmd->opcode);
+				 data->mrq->cmd->opcode,
+				 (readl_relaxed(host->base
+				 + MCI_TEST_INPUT) & 0x2) ? 1 : 0);
 			data->error = -ETIMEDOUT;
 			msmsdcc_dump_sdcc_state(host);
 		}
@@ -2191,6 +2180,18 @@
 	return rc;
 }
 
+static inline int msmsdcc_vreg_get_voltage(struct msm_mmc_reg_data *vreg)
+{
+	int rc = 0;
+
+	rc = regulator_get_voltage(vreg->reg);
+	if (rc < 0)
+		pr_err("%s: regulator_get_voltage(%s) failed. rc=%d\n",
+			__func__, vreg->name, rc);
+
+	return rc;
+}
+
 static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
 						int uA_load)
 {
@@ -2435,6 +2436,82 @@
 	VDD_IO_SET_LEVEL,
 };
 
+/*
+ * This function returns the current VDD IO voltage level.
+ * Returns negative value if it fails to read the voltage level
+ * Returns 0 if regulator was disabled or if VDD_IO (and VDD)
+ * regulator were not defined for host.
+ */
+static int msmsdcc_get_vdd_io_vol(struct msmsdcc_host *host)
+{
+	int rc = 0;
+
+	if (host->plat->vreg_data) {
+		struct msm_mmc_reg_data *io_reg =
+			host->plat->vreg_data->vdd_io_data;
+
+		/*
+		 * If vdd_io is not defined, then we can consider that
+		 * IO voltage is same as VDD.
+		 */
+		if (!io_reg)
+			io_reg = host->plat->vreg_data->vdd_data;
+
+		if (io_reg && io_reg->is_enabled)
+			rc = msmsdcc_vreg_get_voltage(io_reg);
+	}
+
+	return rc;
+}
+
+/*
+ * This function updates the IO pad power switch bit in MCI_CLK register
+ * based on currrent IO pad voltage level.
+ * NOTE: This function assumes that host lock was not taken by caller.
+ */
+static void msmsdcc_update_io_pad_pwr_switch(struct msmsdcc_host *host)
+{
+	int rc = 0;
+	unsigned long flags;
+
+	if (!is_io_pad_pwr_switch(host))
+		return;
+
+	rc = msmsdcc_get_vdd_io_vol(host);
+
+	spin_lock_irqsave(&host->lock, flags);
+	/*
+	 * Dual voltage pad is the SDCC's (chipset) functionality and not all
+	 * the SDCC instances support the dual voltage pads.
+	 * For dual-voltage pad (1.8v/3.3v), SW should set IO_PAD_PWR_SWITCH
+	 * bit before using the pads in 1.8V mode.
+	 * For regular, not dual-voltage pads (including eMMC 1.2v/1.8v pads),
+	 * IO_PAD_PWR_SWITCH bit is a don't care.
+	 * But we don't have an option to know (by reading some SDCC register)
+	 * that a particular SDCC instance supports dual voltage pads or not,
+	 * so we simply set the IO_PAD_PWR_SWITCH bit for low voltage IO
+	 * (1.8v/1.2v). For regular (not dual-voltage pads), this bit value
+	 * is anyway ignored.
+	 */
+	if (rc > 0 && rc < 2700000)
+		host->io_pad_pwr_switch = 1;
+	else
+		host->io_pad_pwr_switch = 0;
+
+	if (atomic_read(&host->clks_on)) {
+		if (host->io_pad_pwr_switch)
+			writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
+					IO_PAD_PWR_SWITCH),
+					host->base + MMCICLOCK);
+		else
+			writel_relaxed((readl_relaxed(host->base + MMCICLOCK) &
+					~IO_PAD_PWR_SWITCH),
+					host->base + MMCICLOCK);
+		msmsdcc_sync_reg_wr(host);
+	}
+	spin_unlock_irqrestore(&host->lock, flags);
+}
+
 static int msmsdcc_set_vdd_io_vol(struct msmsdcc_host *host,
 				  enum vdd_io_level level,
 				  unsigned int voltage_level)
@@ -2736,6 +2813,7 @@
 		 * present or during system suspend).
 		 */
 		msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
+		msmsdcc_update_io_pad_pwr_switch(host);
 		msmsdcc_setup_pins(host, false);
 		break;
 	case MMC_POWER_UP:
@@ -2744,6 +2822,7 @@
 		msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENABLE);
 
 		msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
+		msmsdcc_update_io_pad_pwr_switch(host);
 		msmsdcc_setup_pins(host, true);
 		break;
 	case MMC_POWER_ON:
@@ -3156,10 +3235,6 @@
 	/* Select free running MCLK as input clock of cm_dll_sdc4 */
 	clk |= (2 << 23);
 
-	/* Clear IO_PAD_PWR_SWITCH while powering off the card */
-	if (!ios->vdd)
-		host->io_pad_pwr_switch = 0;
-
 	if (host->io_pad_pwr_switch)
 		clk |= IO_PAD_PWR_SWITCH;
 
@@ -3291,7 +3366,10 @@
 {
 	struct device *dev = mmc_dev(host->mmc);
 
-	pr_info("%s: RPM: runtime_status=%d, usage_count=%d,"
+	pr_err("%s: PM: sdcc_suspended=%d, pending_resume=%d, sdcc_suspending=%d\n",
+		mmc_hostname(host->mmc), host->sdcc_suspended,
+		host->pending_resume, host->sdcc_suspending);
+	pr_err("%s: RPM: runtime_status=%d, usage_count=%d,"
 		" is_suspended=%d, disable_depth=%d, runtime_error=%d,"
 		" request_pending=%d, request=%d\n",
 		mmc_hostname(host->mmc), dev->power.runtime_status,
@@ -3312,8 +3390,7 @@
 	if (mmc->card && mmc_card_sdio(mmc->card))
 		goto out;
 
-	if (host->sdcc_suspended && host->pending_resume &&
-			!pm_runtime_suspended(dev)) {
+	if (host->sdcc_suspended && host->pending_resume) {
 		host->pending_resume = false;
 		pm_runtime_get_noresume(dev);
 		rc = msmsdcc_runtime_resume(dev);
@@ -3334,8 +3411,8 @@
 
 skip_get_sync:
 	if (rc < 0) {
-		pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
-				__func__, rc);
+		WARN(1, "%s: %s: failed with error %d\n", mmc_hostname(mmc),
+		     __func__, rc);
 		msmsdcc_print_rpm_info(host);
 		return rc;
 	}
@@ -3361,15 +3438,9 @@
 
 	rc = pm_runtime_put_sync(mmc->parent);
 
-	/*
-	 * Ignore -EAGAIN as that is not fatal, it means that
-	 * either runtime usage count is non-zero or the runtime
-	 * pm itself is disabled or not in proper state to process
-	 * idle notification.
-	 */
-	if (rc < 0 && (rc != -EAGAIN)) {
-		pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
-				__func__, rc);
+	if (rc < 0) {
+		WARN(1, "%s: %s: failed with error %d\n", mmc_hostname(mmc),
+		     __func__, rc);
 		msmsdcc_print_rpm_info(host);
 		return rc;
 	}
@@ -3448,14 +3519,12 @@
 	unsigned long flags;
 	int rc = 0;
 
-	spin_lock_irqsave(&host->lock, flags);
-	host->io_pad_pwr_switch = 0;
-	spin_unlock_irqrestore(&host->lock, flags);
-
 	switch (ios->signal_voltage) {
 	case MMC_SIGNAL_VOLTAGE_330:
 		/* Set VDD IO to high voltage range (2.7v - 3.6v) */
 		rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
+		if (!rc)
+			msmsdcc_update_io_pad_pwr_switch(host);
 		goto out;
 	case MMC_SIGNAL_VOLTAGE_180:
 		break;
@@ -3466,6 +3535,8 @@
 		 * DDR 1.2V mode.
 		 */
 		rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_SET_LEVEL, 1200000);
+		if (!rc)
+			msmsdcc_update_io_pad_pwr_switch(host);
 		goto out;
 	default:
 		/* invalid selection. don't do anything */
@@ -3504,12 +3575,7 @@
 	if (rc)
 		goto out;
 
-	spin_lock_irqsave(&host->lock, flags);
-	writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
-			IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
-	msmsdcc_sync_reg_wr(host);
-	host->io_pad_pwr_switch = 1;
-	spin_unlock_irqrestore(&host->lock, flags);
+	msmsdcc_update_io_pad_pwr_switch(host);
 
 	/* Wait 5 ms for the voltage regulater in the card to become stable. */
 	usleep_range(5000, 5500);
@@ -4754,6 +4820,63 @@
 	return count;
 }
 
+static inline void set_auto_cmd_setting(struct device *dev,
+					 const char *buf,
+					 bool is_cmd19)
+{
+	struct mmc_host *mmc = dev_get_drvdata(dev);
+	struct msmsdcc_host *host = mmc_priv(mmc);
+	unsigned int long flags;
+	int temp;
+
+	if (!kstrtou32(buf, 0, &temp)) {
+		spin_lock_irqsave(&host->lock, flags);
+		if (is_cmd19)
+			host->en_auto_cmd19 = !!temp;
+		else
+			host->en_auto_cmd21 = !!temp;
+		spin_unlock_irqrestore(&host->lock, flags);
+	}
+}
+
+static ssize_t
+show_enable_auto_cmd19(struct device *dev, struct device_attribute *attr,
+		       char *buf)
+{
+	struct mmc_host *mmc = dev_get_drvdata(dev);
+	struct msmsdcc_host *host = mmc_priv(mmc);
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", host->en_auto_cmd19);
+}
+
+static ssize_t
+store_enable_auto_cmd19(struct device *dev, struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	set_auto_cmd_setting(dev, buf, true);
+
+	return count;
+}
+
+static ssize_t
+show_enable_auto_cmd21(struct device *dev, struct device_attribute *attr,
+		       char *buf)
+{
+	struct mmc_host *mmc = dev_get_drvdata(dev);
+	struct msmsdcc_host *host = mmc_priv(mmc);
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", host->en_auto_cmd21);
+}
+
+static ssize_t
+store_enable_auto_cmd21(struct device *dev, struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	set_auto_cmd_setting(dev, buf, false);
+
+	return count;
+}
+
 #ifdef CONFIG_HAS_EARLYSUSPEND
 static void msmsdcc_early_suspend(struct early_suspend *h)
 {
@@ -4789,10 +4912,10 @@
 	if (!base)
 		return;
 
-	pr_info("===== %s: Register Dumps @phys_base=0x%x, @virt_base=0x%x"
+	pr_err("===== %s: Register Dumps @phys_base=0x%x, @virt_base=0x%x"
 		" =====\n", name, phys_base, (u32)base);
 	for (i = 0; i < no_of_regs; i = i + 4) {
-		pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x\n", i*4,
+		pr_err("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x\n", i*4,
 			(u32)readl_relaxed(base + i*4),
 			(u32)readl_relaxed(base + ((i+1)*4)),
 			(u32)readl_relaxed(base + ((i+2)*4)),
@@ -4803,25 +4926,29 @@
 static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
 {
 	/* Dump current state of SDCC clocks, power and irq */
-	pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
+	pr_err("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
 		(host->pwr ? "ON" : "OFF"));
-	pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
+	pr_err("%s: SDCC clks are %s, MCLK rate=%d\n",
 		mmc_hostname(host->mmc),
 		(atomic_read(&host->clks_on) ? "ON" : "OFF"),
 		(u32)clk_get_rate(host->clk));
-	pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
+	pr_err("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
 		(host->sdcc_irq_disabled ? "disabled" : "enabled"));
 
 	/* Now dump SDCC registers. Don't print FIFO registers */
-	if (atomic_read(&host->clks_on))
+	if (atomic_read(&host->clks_on)) {
 		msmsdcc_print_regs("SDCC-CORE", host->base,
 				   host->core_memres->start, 28);
+		pr_err("%s: MCI_TEST_INPUT = 0x%.8x\n",
+			mmc_hostname(host->mmc),
+			readl_relaxed(host->base + MCI_TEST_INPUT));
+	}
 
 	if (host->curr.data) {
 		if (!msmsdcc_is_dma_possible(host, host->curr.data))
-			pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
+			pr_err("%s: PIO mode\n", mmc_hostname(host->mmc));
 		else if (is_dma_mode(host))
-			pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
+			pr_err("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
 				mmc_hostname(host->mmc), host->dma.busy,
 				host->dma.channel, host->dma.crci);
 		else if (is_sps_mode(host)) {
@@ -4829,16 +4956,16 @@
 				msmsdcc_print_regs("SDCC-DML", host->dml_base,
 						   host->dml_memres->start,
 						   16);
-			pr_info("%s: SPS mode: busy=%d\n",
+			pr_err("%s: SPS mode: busy=%d\n",
 				mmc_hostname(host->mmc), host->sps.busy);
 		}
 
-		pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
+		pr_err("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
 			mmc_hostname(host->mmc), host->curr.xfer_size,
 			host->curr.data_xfered, host->curr.xfer_remain);
 	}
 
-	pr_info("%s: got_dataend=%d, prog_enable=%d,"
+	pr_err("%s: got_dataend=%d, prog_enable=%d,"
 		" wait_for_auto_prog_done=%d, got_auto_prog_done=%d,"
 		" req_tout_ms=%d\n", mmc_hostname(host->mmc),
 		host->curr.got_dataend, host->prog_enable,
@@ -5123,7 +5250,9 @@
 	pdata->status_gpio = of_get_named_gpio_flags(np,
 			"cd-gpios", 0, &flags);
 	if (gpio_is_valid(pdata->status_gpio)) {
-		pdata->status_irq = gpio_to_irq(pdata->status_gpio);
+		struct platform_device *pdev = container_of(dev,
+						struct platform_device, dev);
+		pdata->status_irq = platform_get_irq_byname(pdev, "status_irq");
 		pdata->is_status_gpio_active_low = flags & OF_GPIO_ACTIVE_LOW;
 	}
 
@@ -5892,8 +6021,42 @@
 	ret = device_create_file(&pdev->dev, &host->idle_timeout);
 	if (ret)
 		goto remove_polling_file;
+
+	if (!is_auto_cmd19(host))
+		goto add_auto_cmd21_atrr;
+
+	/* Sysfs entry for AUTO CMD19 control */
+	host->auto_cmd19_attr.show = show_enable_auto_cmd19;
+	host->auto_cmd19_attr.store = store_enable_auto_cmd19;
+	sysfs_attr_init(&host->auto_cmd19_attr.attr);
+	host->auto_cmd19_attr.attr.name = "enable_auto_cmd19";
+	host->auto_cmd19_attr.attr.mode = S_IRUGO | S_IWUSR;
+	ret = device_create_file(&pdev->dev, &host->auto_cmd19_attr);
+	if (ret)
+		goto remove_idle_timeout_file;
+
+ add_auto_cmd21_atrr:
+	if (!is_auto_cmd21(host))
+		goto exit;
+
+	/* Sysfs entry for AUTO CMD21 control */
+	host->auto_cmd21_attr.show = show_enable_auto_cmd21;
+	host->auto_cmd21_attr.store = store_enable_auto_cmd21;
+	sysfs_attr_init(&host->auto_cmd21_attr.attr);
+	host->auto_cmd21_attr.attr.name = "enable_auto_cmd21";
+	host->auto_cmd21_attr.attr.mode = S_IRUGO | S_IWUSR;
+	ret = device_create_file(&pdev->dev, &host->auto_cmd21_attr);
+	if (ret)
+		goto remove_auto_cmd19_attr_file;
+
+ exit:
 	return 0;
 
+ remove_auto_cmd19_attr_file:
+	if (is_auto_cmd19(host))
+		device_remove_file(&pdev->dev, &host->auto_cmd19_attr);
+ remove_idle_timeout_file:
+	device_remove_file(&pdev->dev, &host->idle_timeout);
  remove_polling_file:
 	if (!plat->status_irq)
 		device_remove_file(&pdev->dev, &host->polling);
@@ -5974,6 +6137,10 @@
 	DBG(host, "Removing SDCC device = %d\n", pdev->id);
 	plat = host->plat;
 
+	if (is_auto_cmd19(host))
+		device_remove_file(&pdev->dev, &host->auto_cmd19_attr);
+	if (is_auto_cmd21(host))
+		device_remove_file(&pdev->dev, &host->auto_cmd21_attr);
 	device_remove_file(&pdev->dev, &host->max_bus_bw);
 	if (!plat->status_irq)
 		device_remove_file(&pdev->dev, &host->polling);
@@ -6262,6 +6429,7 @@
 
 		wake_unlock(&host->sdio_suspend_wlock);
 	}
+	host->pending_resume = false;
 	pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
 	return 0;
 }
@@ -6334,7 +6502,13 @@
 
 	if (mmc->card && mmc_card_sdio(mmc->card))
 		rc = msmsdcc_runtime_resume(dev);
-	else
+	/*
+	 * As runtime PM is enabled before calling the device's platform resume
+	 * callback, we use the pm_runtime_suspended API to know if SDCC is
+	 * really runtime suspended or not and set the pending_resume flag only
+	 * if its not runtime suspended.
+	 */
+	else if (!pm_runtime_suspended(dev))
 		host->pending_resume = true;
 
 	if (host->plat->status_irq) {
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index 3b1dbc7..5779491 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -65,6 +65,7 @@
 #define MCI_CSPM_CCSENABLE	(1 << 14)
 #define MCI_CSPM_CCSDISABLE	(1 << 15)
 #define MCI_CSPM_AUTO_CMD19	(1 << 16)
+#define MCI_CSPM_AUTO_CMD21	(1 << 21)
 
 
 #define MMCIRESPCMD		0x010
@@ -401,6 +402,8 @@
 	bool io_pad_pwr_switch;
 	bool tuning_in_progress;
 	bool tuning_needed;
+	bool en_auto_cmd19;
+	bool en_auto_cmd21;
 	bool sdio_gpio_lpm;
 	bool irq_wake_enabled;
 	struct pm_qos_request pm_qos_req_dma;
@@ -417,9 +420,15 @@
 	struct device_attribute	max_bus_bw;
 	struct device_attribute	polling;
 	struct device_attribute idle_timeout;
+	struct device_attribute auto_cmd19_attr;
+	struct device_attribute auto_cmd21_attr;
 };
 
-#define MSMSDCC_VERSION_MASK	0xFFFF
+#define MSMSDCC_VERSION_STEP_MASK	0x0000FFFF
+#define MSMSDCC_VERSION_MINOR_MASK	0x0FFF0000
+#define MSMSDCC_VERSION_MINOR_SHIFT	16
+#define MSMSDCC_VERSION_MAJOR_MASK	0xF0000000
+#define MSMSDCC_VERSION_MAJOR_SHIFT	28
 #define MSMSDCC_DMA_SUP	(1 << 0)
 #define MSMSDCC_SPS_BAM_SUP	(1 << 1)
 #define MSMSDCC_SOFT_RESET	(1 << 2)
@@ -428,6 +437,9 @@
 #define MSMSDCC_SW_RST		(1 << 5)
 #define MSMSDCC_SW_RST_CFG	(1 << 6)
 #define MSMSDCC_WAIT_FOR_TX_RX	(1 << 7)
+#define MSMSDCC_IO_PAD_PWR_SWITCH	(1 << 8)
+#define MSMSDCC_AUTO_CMD19	(1 << 9)
+#define MSMSDCC_AUTO_CMD21	(1 << 10)
 
 #define set_hw_caps(h, val)		((h)->hw_caps |= val)
 #define is_sps_mode(h)			((h)->hw_caps & MSMSDCC_SPS_BAM_SUP)
@@ -438,11 +450,16 @@
 #define is_sw_hard_reset(h)		((h)->hw_caps & MSMSDCC_SW_RST)
 #define is_sw_reset_save_config(h)	((h)->hw_caps & MSMSDCC_SW_RST_CFG)
 #define is_wait_for_tx_rx_active(h)	((h)->hw_caps & MSMSDCC_WAIT_FOR_TX_RX)
+#define is_io_pad_pwr_switch(h)	((h)->hw_caps & MSMSDCC_IO_PAD_PWR_SWITCH)
+#define is_auto_cmd19(h)		((h)->hw_caps & MSMSDCC_AUTO_CMD19)
+#define is_auto_cmd21(h)		((h)->hw_caps & MSMSDCC_AUTO_CMD21)
 
 /* Set controller capabilities based on version */
 static inline void set_default_hw_caps(struct msmsdcc_host *host)
 {
 	u32 version;
+	u16 step, minor;
+
 	/*
 	 * Lookup the Controller Version, to identify the supported features
 	 * Version number read as 0 would indicate SDCC3 or earlier versions.
@@ -453,14 +470,21 @@
 	if (!version)
 		return;
 
-	version &= MSMSDCC_VERSION_MASK;
+	step = version & MSMSDCC_VERSION_STEP_MASK;
+	minor = (version & MSMSDCC_VERSION_MINOR_MASK) >>
+			MSMSDCC_VERSION_MINOR_SHIFT;
+
 	if (version) /* SDCC v4 and greater */
 		host->hw_caps |= MSMSDCC_AUTO_PROG_DONE |
 			MSMSDCC_SOFT_RESET | MSMSDCC_REG_WR_ACTIVE
-			| MSMSDCC_WAIT_FOR_TX_RX;
+			| MSMSDCC_WAIT_FOR_TX_RX | MSMSDCC_IO_PAD_PWR_SWITCH
+			| MSMSDCC_AUTO_CMD19;
 
-	if (version >= 0x2D) /* SDCC v4 2.1.0 and greater */
-		host->hw_caps |= MSMSDCC_SW_RST | MSMSDCC_SW_RST_CFG;
+	if ((step == 0x18) && (minor >= 3))
+		host->hw_caps |= MSMSDCC_AUTO_CMD21;
+
+	if (version >= 0x2b) /* SDCC v4 2.1.0 and greater */
+		host->hw_caps |= MSMSDCC_SW_RST | MSMSDCC_AUTO_CMD21;
 }
 
 int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave);
diff --git a/drivers/net/ethernet/micrel/ks8851.c b/drivers/net/ethernet/micrel/ks8851.c
index 5e313e9..a807354 100644
--- a/drivers/net/ethernet/micrel/ks8851.c
+++ b/drivers/net/ethernet/micrel/ks8851.c
@@ -23,8 +23,13 @@
 #include <linux/crc32.h>
 #include <linux/mii.h>
 #include <linux/eeprom_93cx6.h>
+#include <linux/ks8851.h>
 
 #include <linux/spi/spi.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
 
 #include "ks8851.h"
 
@@ -131,6 +136,10 @@
 	struct spi_transfer	spi_xfer1;
 	struct spi_transfer	spi_xfer2[2];
 
+	struct regulator	*vdd_io;
+	struct regulator	*vdd_phy;
+	int			rst_gpio;
+
 	struct eeprom_93cx6	eeprom;
 };
 
@@ -1415,6 +1424,66 @@
 #define ks8851_resume NULL
 #endif
 
+static int __devinit ks8851_init_hw(struct spi_device *spi,
+				    struct ks8851_net *ks)
+{
+	struct ks8851_pdata *pdata = spi->dev.platform_data;
+	struct device_node *dnode = spi->dev.of_node;
+	enum of_gpio_flags flags;
+	int ret;
+
+	ks->rst_gpio = -ENODEV;
+
+	if (dnode)
+		ks->rst_gpio = of_get_named_gpio_flags(dnode, "rst-gpio",
+						       0, &flags);
+	else if (pdata)
+		ks->rst_gpio = pdata->rst_gpio;
+
+	if (gpio_is_valid(ks->rst_gpio)) {
+		ret = gpio_request(ks->rst_gpio, "ks8851_rst");
+		if (ret) {
+			pr_err("ks8851 gpio_request failed: %d\n", ret);
+			return ret;
+		}
+
+		/* Make sure the chip is in reset state */
+		gpio_direction_output(ks->rst_gpio, 0);
+	}
+
+	ks->vdd_io = regulator_get(&spi->dev, "vdd-io");
+
+	if (IS_ERR(ks->vdd_io)) {
+		ret = PTR_ERR(ks->vdd_io);
+		goto fail_gpio;
+	}
+
+	ks->vdd_phy = regulator_get(&spi->dev, "vdd-phy");
+
+	if (IS_ERR(ks->vdd_phy)) {
+		regulator_put(ks->vdd_io);
+		ret = PTR_ERR(ks->vdd_phy);
+		goto fail_gpio;
+	}
+
+	regulator_enable(ks->vdd_io);
+	regulator_enable(ks->vdd_phy);
+
+	/* Wait for atleast 10ms after turning on regulator */
+	usleep_range(10000, 11000);
+
+	if (gpio_is_valid(ks->rst_gpio))
+		gpio_direction_output(ks->rst_gpio, 1);
+
+	return 0;
+
+fail_gpio:
+	if (gpio_is_valid(ks->rst_gpio))
+		gpio_free(ks->rst_gpio);
+
+	return ret;
+}
+
 static int __devinit ks8851_probe(struct spi_device *spi)
 {
 	struct net_device *ndev;
@@ -1430,6 +1499,10 @@
 
 	ks = netdev_priv(ndev);
 
+	ret = ks8851_init_hw(spi, ks);
+	if (ret)
+		goto err_init;
+
 	ks->netdev = ndev;
 	ks->spidev = spi;
 	ks->tx_space = 6144;
@@ -1530,6 +1603,20 @@
 
 err_id:
 err_irq:
+	if (gpio_is_valid(ks->rst_gpio))
+		gpio_free(ks->rst_gpio);
+
+	if (!IS_ERR(ks->vdd_io)) {
+		regulator_disable(ks->vdd_io);
+		regulator_put(ks->vdd_io);
+	}
+
+	if (!IS_ERR(ks->vdd_phy)) {
+		regulator_disable(ks->vdd_phy);
+		regulator_put(ks->vdd_phy);
+	}
+
+err_init:
 	free_netdev(ndev);
 	return ret;
 }
@@ -1541,6 +1628,19 @@
 	if (netif_msg_drv(priv))
 		dev_info(&spi->dev, "remove\n");
 
+	if (gpio_is_valid(priv->rst_gpio))
+		gpio_free(priv->rst_gpio);
+
+	if (!IS_ERR(priv->vdd_io)) {
+		regulator_disable(priv->vdd_io);
+		regulator_put(priv->vdd_io);
+	}
+
+	if (!IS_ERR(priv->vdd_phy)) {
+		regulator_disable(priv->vdd_phy);
+		regulator_put(priv->vdd_phy);
+	}
+
 	unregister_netdev(priv->netdev);
 	free_irq(spi->irq, priv);
 	free_netdev(priv->netdev);
@@ -1548,9 +1648,17 @@
 	return 0;
 }
 
+static struct of_device_id ks8851_match_table[] = {
+	{
+		.compatible = "micrel,ks8851",
+	},
+	{}
+};
+
 static struct spi_driver ks8851_driver = {
 	.driver = {
 		.name = "ks8851",
+		.of_match_table = ks8851_match_table,
 		.owner = THIS_MODULE,
 	},
 	.probe = ks8851_probe,
diff --git a/drivers/net/ethernet/msm/Kconfig b/drivers/net/ethernet/msm/Kconfig
index 095cb4d..3fced2d 100644
--- a/drivers/net/ethernet/msm/Kconfig
+++ b/drivers/net/ethernet/msm/Kconfig
@@ -18,7 +18,7 @@
 
 config MSM_RMNET_BAM
 	bool "RMNET BAM Driver"
-	depends on MSM_BAM_DMUX
+	depends on (MSM_BAM_DMUX && NET_SCHED && NET_SCH_HTB && NET_SCH_PRIO && NET_CLS_FW)
 	default n
 	help
 	  Implements RMNET over BAM interface.
diff --git a/drivers/net/ethernet/msm/msm_rmnet_bam.c b/drivers/net/ethernet/msm/msm_rmnet_bam.c
index fbe8d3c..295c55c 100644
--- a/drivers/net/ethernet/msm/msm_rmnet_bam.c
+++ b/drivers/net/ethernet/msm/msm_rmnet_bam.c
@@ -29,6 +29,7 @@
 #include <linux/if_arp.h>
 #include <linux/msm_rmnet.h>
 #include <linux/platform_device.h>
+#include <net/pkt_sched.h>
 
 #ifdef CONFIG_HAS_EARLYSUSPEND
 #include <linux/earlysuspend.h>
@@ -638,6 +639,16 @@
 			dev->name);
 		break;
 
+	case RMNET_IOCTL_FLOW_ENABLE:
+		tc_qdisc_flow_control(dev, (u32)ifr->ifr_data, 1);
+		DBG0("[%s] rmnet_ioctl(): enabled flow", dev->name);
+		break;
+
+	case RMNET_IOCTL_FLOW_DISABLE:
+		tc_qdisc_flow_control(dev, (u32)ifr->ifr_data, 0);
+		DBG0("[%s] rmnet_ioctl(): disabled flow", dev->name);
+		break;
+
 	case RMNET_IOCTL_GET_QOS:           /* Get QoS header state    */
 		ifr->ifr_ifru.ifru_data =
 			(void *)(p->operation_mode & RMNET_MODE_QOS);
diff --git a/drivers/net/ppp/pppolac.c b/drivers/net/ppp/pppolac.c
index c94b850..a5d3d63 100644
--- a/drivers/net/ppp/pppolac.c
+++ b/drivers/net/ppp/pppolac.c
@@ -310,7 +310,7 @@
 	po->chan.hdrlen = 12;
 	po->chan.private = sk_udp;
 	po->chan.ops = &pppolac_channel_ops;
-	po->chan.mtu = PPP_MTU - 80;
+	po->chan.mtu = PPP_MRU - 80;
 	po->proto.lac.local = unaligned(&addr->local)->u32;
 	po->proto.lac.remote = unaligned(&addr->remote)->u32;
 	atomic_set(&po->proto.lac.sequencing, 1);
diff --git a/drivers/net/ppp/pppopns.c b/drivers/net/ppp/pppopns.c
index fb81984..6016d29 100644
--- a/drivers/net/ppp/pppopns.c
+++ b/drivers/net/ppp/pppopns.c
@@ -290,7 +290,7 @@
 	po->chan.hdrlen = 14;
 	po->chan.private = sk_raw;
 	po->chan.ops = &pppopns_channel_ops;
-	po->chan.mtu = PPP_MTU - 80;
+	po->chan.mtu = PPP_MRU - 80;
 	po->proto.pns.local = addr->local;
 	po->proto.pns.remote = addr->remote;
 	po->proto.pns.data_ready = sk_raw->sk_data_ready;
diff --git a/drivers/net/pppolac.c b/drivers/net/pppolac.c
index c94b850..a5d3d63 100644
--- a/drivers/net/pppolac.c
+++ b/drivers/net/pppolac.c
@@ -310,7 +310,7 @@
 	po->chan.hdrlen = 12;
 	po->chan.private = sk_udp;
 	po->chan.ops = &pppolac_channel_ops;
-	po->chan.mtu = PPP_MTU - 80;
+	po->chan.mtu = PPP_MRU - 80;
 	po->proto.lac.local = unaligned(&addr->local)->u32;
 	po->proto.lac.remote = unaligned(&addr->remote)->u32;
 	atomic_set(&po->proto.lac.sequencing, 1);
diff --git a/drivers/net/pppopns.c b/drivers/net/pppopns.c
index fb81984..6016d29 100644
--- a/drivers/net/pppopns.c
+++ b/drivers/net/pppopns.c
@@ -290,7 +290,7 @@
 	po->chan.hdrlen = 14;
 	po->chan.private = sk_raw;
 	po->chan.ops = &pppopns_channel_ops;
-	po->chan.mtu = PPP_MTU - 80;
+	po->chan.mtu = PPP_MRU - 80;
 	po->proto.pns.local = addr->local;
 	po->proto.pns.remote = addr->remote;
 	po->proto.pns.data_ready = sk_raw->sk_data_ready;
diff --git a/drivers/net/usb/rmnet_usb_ctrl.c b/drivers/net/usb/rmnet_usb_ctrl.c
index 186d07d..ba16ed9 100644
--- a/drivers/net/usb/rmnet_usb_ctrl.c
+++ b/drivers/net/usb/rmnet_usb_ctrl.c
@@ -271,7 +271,7 @@
 			__func__, status);
 }
 
-static int rmnet_usb_ctrl_start_rx(struct rmnet_ctrl_dev *dev)
+int rmnet_usb_ctrl_start_rx(struct rmnet_ctrl_dev *dev)
 {
 	int	retval = 0;
 
@@ -298,18 +298,6 @@
 	return 0;
 }
 
-int rmnet_usb_ctrl_start(struct rmnet_ctrl_dev *dev)
-{
-	int	status = 0;
-
-	mutex_lock(&dev->dev_lock);
-	if (dev->is_opened)
-		status = rmnet_usb_ctrl_start_rx(dev);
-	mutex_unlock(&dev->dev_lock);
-
-	return status;
-}
-
 static int rmnet_usb_ctrl_alloc_rx(struct rmnet_ctrl_dev *dev)
 {
 	int	retval = -ENOMEM;
@@ -416,7 +404,7 @@
 
 	result = usb_autopm_get_interface(dev->intf);
 	if (result < 0) {
-		dev_err(dev->devicep, "%s: Unable to resume interface: %d\n",
+		dev_dbg(dev->devicep, "%s: Unable to resume interface: %d\n",
 			__func__, result);
 
 		/*
@@ -681,7 +669,7 @@
 
 	retval = usb_autopm_get_interface(dev->intf);
 	if (retval < 0) {
-		dev_err(dev->devicep, "%s: Unable to resume interface: %d\n",
+		dev_dbg(dev->devicep, "%s: Unable to resume interface: %d\n",
 			__func__, retval);
 		return retval;
 	}
diff --git a/drivers/net/usb/rmnet_usb_ctrl.h b/drivers/net/usb/rmnet_usb_ctrl.h
index 3259940..7a84817 100644
--- a/drivers/net/usb/rmnet_usb_ctrl.h
+++ b/drivers/net/usb/rmnet_usb_ctrl.h
@@ -73,7 +73,7 @@
 
 extern struct rmnet_ctrl_dev *ctrl_dev[];
 
-extern int rmnet_usb_ctrl_start(struct rmnet_ctrl_dev *);
+extern int rmnet_usb_ctrl_start_rx(struct rmnet_ctrl_dev *);
 extern int rmnet_usb_ctrl_stop_rx(struct rmnet_ctrl_dev *);
 extern int rmnet_usb_ctrl_init(void);
 extern void rmnet_usb_ctrl_exit(void);
diff --git a/drivers/net/usb/rmnet_usb_data.c b/drivers/net/usb/rmnet_usb_data.c
index 4f8039e..b8c6140 100644
--- a/drivers/net/usb/rmnet_usb_data.c
+++ b/drivers/net/usb/rmnet_usb_data.c
@@ -151,7 +151,7 @@
 	retval = usbnet_resume(iface);
 	if (!retval) {
 		if (oldstate & PM_EVENT_SUSPEND)
-			retval = rmnet_usb_ctrl_start(dev);
+			retval = rmnet_usb_ctrl_start_rx(dev);
 	}
 fail:
 	return retval;
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index d26c845..1867fe2 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -89,6 +89,8 @@
 
 static struct workqueue_struct	*usbnet_wq;
 
+static DECLARE_WAIT_QUEUE_HEAD(unlink_wakeup);
+
 /* use ethtool to change the level for any given device */
 static int msg_level = -1;
 module_param (msg_level, int, 0);
@@ -664,7 +666,6 @@
 // precondition: never called in_interrupt
 static void usbnet_terminate_urbs(struct usbnet *dev)
 {
-	DECLARE_WAIT_QUEUE_HEAD_ONSTACK(unlink_wakeup);
 	DECLARE_WAITQUEUE(wait, current);
 	int temp;
 
@@ -1240,7 +1241,7 @@
 	// waiting for all pending urbs to complete?
 	if (dev->wait) {
 		if ((dev->txq.qlen + dev->rxq.qlen + dev->done.qlen) == 0) {
-			wake_up (dev->wait);
+			wake_up(&unlink_wakeup);
 		}
 
 	// or are we maybe short a few urbs?
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 914f4fb..5278324 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -295,7 +295,7 @@
 
 config WCNSS_CORE
 	tristate "Qualcomm WCNSS CORE driver"
-	depends on ARCH_MSM8960
+	depends on (ARCH_MSM8960 || ARCH_MSM8974)
 	select WIRELESS_EXT
 	select WEXT_PRIV
 	select WEXT_CORE
@@ -303,6 +303,18 @@
 	---help---
 	  Core driver for the Qualcomm WCNSS triple play connectivity subsystem
 
+config WCNSS_CORE_PRONTO
+	tristate "Qualcomm WCNSS Pronto Support"
+	depends on WCNSS_CORE
+	---help---
+	  Pronto Support for the Qualcomm WCNSS triple play connectivity subsystem
+
+config WCNSS_MEM_PRE_ALLOC
+	tristate "WCNSS pre-alloc memory support"
+	depends on WCNSS_CORE
+	---help---
+	  Pre-allocate memory for the WLAN driver module
+
 source "drivers/net/wireless/ath/Kconfig"
 source "drivers/net/wireless/b43/Kconfig"
 source "drivers/net/wireless/b43legacy/Kconfig"
diff --git a/drivers/net/wireless/libra/libra_sdioif.c b/drivers/net/wireless/libra/libra_sdioif.c
index aa7970a..1d72a16 100644
--- a/drivers/net/wireless/libra/libra_sdioif.c
+++ b/drivers/net/wireless/libra/libra_sdioif.c
@@ -27,6 +27,12 @@
 /* SDIO Card ID / Device ID */
 static unsigned short  libra_sdio_card_id;
 
+/* completion variables */
+struct completion gCard_rem_event_var;
+EXPORT_SYMBOL(gCard_rem_event_var);
+struct completion gShutdown_event_var;
+EXPORT_SYMBOL(gShutdown_event_var);
+
 static suspend_handler_t *libra_suspend_hldr;
 static resume_handler_t *libra_resume_hldr;
 static notify_card_removal_t *libra_notify_card_removal_hdlr;
diff --git a/drivers/net/wireless/wcnss/Makefile b/drivers/net/wireless/wcnss/Makefile
index c077848..613d477 100644
--- a/drivers/net/wireless/wcnss/Makefile
+++ b/drivers/net/wireless/wcnss/Makefile
@@ -1,6 +1,7 @@
 
 # Makefile for WCNSS triple-play driver
 
-wcnsscore-objs += wcnss_wlan.o wcnss_riva.o qcomwlan_secif.o
+wcnsscore-objs += wcnss_wlan.o qcomwlan_secif.o wcnss_vreg.o
 
 obj-$(CONFIG_WCNSS_CORE) += wcnsscore.o
+obj-$(CONFIG_WCNSS_MEM_PRE_ALLOC) += wcnss_prealloc.o
diff --git a/drivers/net/wireless/wcnss/wcnss_prealloc.c b/drivers/net/wireless/wcnss/wcnss_prealloc.c
new file mode 100644
index 0000000..7d10657
--- /dev/null
+++ b/drivers/net/wireless/wcnss/wcnss_prealloc.c
@@ -0,0 +1,103 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/slab.h>
+#include <linux/err.h>
+#include <linux/wcnss_wlan.h>
+
+static DEFINE_MUTEX(alloc_lock);
+
+struct wcnss_prealloc {
+	int occupied;
+	unsigned int size;
+	void *ptr;
+};
+
+/* pre-alloced mem for WLAN driver */
+static struct wcnss_prealloc wcnss_allocs[] = {
+	{0, 8  * 1024, NULL},
+	{0, 8  * 1024, NULL},
+	{0, 8  * 1024, NULL},
+	{0, 8  * 1024, NULL},
+	{0, 32 * 1024, NULL},
+	{0, 32 * 1024, NULL},
+	{0, 32 * 1024, NULL},
+	{0, 32 * 1024, NULL},
+	{0, 32 * 1024, NULL},
+	{0, 32 * 1024, NULL},
+	{0, 32 * 1024, NULL},
+	{0, 64 * 1024, NULL},
+	{0, 64 * 1024, NULL},
+};
+
+int wcnss_prealloc_init(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(wcnss_allocs); i++) {
+		wcnss_allocs[i].occupied = 0;
+		wcnss_allocs[i].ptr = kmalloc(wcnss_allocs[i].size, GFP_KERNEL);
+		if (wcnss_allocs[i].ptr == NULL)
+			return -ENOMEM;
+	}
+
+	return 0;
+}
+
+void wcnss_prealloc_deinit(void)
+{
+	int i = 0;
+
+	for (i = 0; i < ARRAY_SIZE(wcnss_allocs); i++)
+		kfree(wcnss_allocs[i].ptr);
+}
+
+void *wcnss_prealloc_get(unsigned int size)
+{
+	int i = 0;
+
+	mutex_lock(&alloc_lock);
+	for (i = 0; i < ARRAY_SIZE(wcnss_allocs); i++) {
+		if (wcnss_allocs[i].occupied)
+			continue;
+
+		if (wcnss_allocs[i].size > size) {
+			/* we found the slot */
+			wcnss_allocs[i].occupied = 1;
+			mutex_unlock(&alloc_lock);
+			return wcnss_allocs[i].ptr;
+		}
+	}
+	pr_err("wcnss: %s: prealloc not available\n", __func__);
+	mutex_unlock(&alloc_lock);
+
+	return NULL;
+}
+EXPORT_SYMBOL(wcnss_prealloc_get);
+
+int wcnss_prealloc_put(void *ptr)
+{
+	int i = 0;
+
+	mutex_lock(&alloc_lock);
+	for (i = 0; i < ARRAY_SIZE(wcnss_allocs); i++) {
+		if (wcnss_allocs[i].ptr == ptr) {
+			wcnss_allocs[i].occupied = 0;
+			mutex_unlock(&alloc_lock);
+			return 1;
+		}
+	}
+	mutex_unlock(&alloc_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(wcnss_prealloc_put);
diff --git a/drivers/net/wireless/wcnss/wcnss_prealloc.h b/drivers/net/wireless/wcnss/wcnss_prealloc.h
new file mode 100644
index 0000000..73ae6c6
--- /dev/null
+++ b/drivers/net/wireless/wcnss/wcnss_prealloc.h
@@ -0,0 +1,19 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 _WCNSS_PRE_ALLOC_H_
+#define _WCNSS_PRE_ALLOC_H_
+
+int wcnss_prealloc_init(void);
+void wcnss_prealloc_deinit(void);
+
+#endif/* _WCNSS_PRE_ALLOC_H_ */
diff --git a/drivers/net/wireless/wcnss/wcnss_riva.c b/drivers/net/wireless/wcnss/wcnss_riva.c
deleted file mode 100644
index 23365ff..0000000
--- a/drivers/net/wireless/wcnss/wcnss_riva.c
+++ /dev/null
@@ -1,399 +0,0 @@
-/* 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/module.h>
-#include <linux/slab.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/gpio.h>
-#include <linux/delay.h>
-#include <linux/regulator/consumer.h>
-#include <linux/mfd/pm8xxx/pm8921.h>
-#include <linux/mfd/pm8xxx/gpio.h>
-#include <linux/wcnss_wlan.h>
-#include <linux/semaphore.h>
-#include <linux/list.h>
-#include <linux/slab.h>
-#include <linux/clk.h>
-#include <mach/msm_xo.h>
-#include <mach/msm_iomap.h>
-
-
-static void __iomem *msm_riva_base;
-static struct msm_xo_voter *wlan_clock;
-static const char *id = "WLAN";
-static LIST_HEAD(power_on_lock_list);
-static DEFINE_MUTEX(list_lock);
-static DEFINE_SEMAPHORE(riva_power_on_lock);
-
-#define MSM_RIVA_PHYS                     0x03204000
-#define RIVA_PMU_CFG                      (msm_riva_base + 0x28)
-#define RIVA_PMU_CFG_IRIS_XO_CFG          BIT(3)
-#define RIVA_PMU_CFG_IRIS_XO_EN           BIT(4)
-#define RIVA_PMU_CFG_GC_BUS_MUX_SEL_TOP   BIT(5)
-#define RIVA_PMU_CFG_IRIS_XO_CFG_STS      BIT(6) /* 1: in progress, 0: done */
-
-#define RIVA_PMU_CFG_IRIS_XO_MODE         0x6
-#define RIVA_PMU_CFG_IRIS_XO_MODE_48      (3 << 1)
-
-#define VREG_NULL_CONFIG            0x0000
-#define VREG_GET_REGULATOR_MASK     0x0001
-#define VREG_SET_VOLTAGE_MASK       0x0002
-#define VREG_OPTIMUM_MODE_MASK      0x0004
-#define VREG_ENABLE_MASK            0x0008
-
-struct vregs_info {
-	const char * const name;
-	int state;
-	const int nominal_min;
-	const int low_power_min;
-	const int max_voltage;
-	const int uA_load;
-	struct regulator *regulator;
-};
-
-static struct vregs_info iris_vregs[] = {
-	{"iris_vddxo",  VREG_NULL_CONFIG, 1800000, 0, 1800000, 10000,  NULL},
-	{"iris_vddrfa", VREG_NULL_CONFIG, 1300000, 0, 1300000, 100000, NULL},
-	{"iris_vddpa",  VREG_NULL_CONFIG, 2900000, 0, 3000000, 515000, NULL},
-	{"iris_vdddig", VREG_NULL_CONFIG, 1200000, 0, 1200000, 10000,  NULL},
-};
-
-static struct vregs_info riva_vregs[] = {
-	{"riva_vddmx",  VREG_NULL_CONFIG, 1050000, 0, 1150000, 0,      NULL},
-	{"riva_vddcx",  VREG_NULL_CONFIG, 1050000, 0, 1150000, 0,      NULL},
-	{"riva_vddpx",  VREG_NULL_CONFIG, 1800000, 0, 1800000, 0,      NULL},
-};
-
-struct host_driver {
-	char name[20];
-	struct list_head list;
-};
-
-
-static int configure_iris_xo(struct device *dev, bool use_48mhz_xo, int on)
-{
-	u32 reg = 0;
-	int rc = 0;
-	struct clk *cxo = clk_get(dev, "cxo");
-	if (IS_ERR(cxo)) {
-		pr_err("Couldn't get cxo clock\n");
-		return PTR_ERR(cxo);
-	}
-
-	if (on) {
-		msm_riva_base = ioremap(MSM_RIVA_PHYS, SZ_256);
-		if (!msm_riva_base) {
-			pr_err("ioremap MSM_RIVA_PHYS failed\n");
-			goto fail;
-		}
-
-		/* Enable IRIS XO */
-		rc = clk_prepare_enable(cxo);
-		if (rc) {
-			pr_err("cxo enable failed\n");
-			goto fail;
-		}
-		writel_relaxed(0, RIVA_PMU_CFG);
-		reg = readl_relaxed(RIVA_PMU_CFG);
-		reg |= RIVA_PMU_CFG_GC_BUS_MUX_SEL_TOP |
-				RIVA_PMU_CFG_IRIS_XO_EN;
-		writel_relaxed(reg, RIVA_PMU_CFG);
-
-		/* Clear XO_MODE[b2:b1] bits. Clear implies 19.2 MHz TCXO */
-		reg &= ~(RIVA_PMU_CFG_IRIS_XO_MODE);
-
-		if (use_48mhz_xo)
-			reg |= RIVA_PMU_CFG_IRIS_XO_MODE_48;
-
-		writel_relaxed(reg, RIVA_PMU_CFG);
-
-		/* Start IRIS XO configuration */
-		reg |= RIVA_PMU_CFG_IRIS_XO_CFG;
-		writel_relaxed(reg, RIVA_PMU_CFG);
-
-		/* Wait for XO configuration to finish */
-		while (readl_relaxed(RIVA_PMU_CFG) &
-						RIVA_PMU_CFG_IRIS_XO_CFG_STS)
-			cpu_relax();
-
-		/* Stop IRIS XO configuration */
-		reg &= ~(RIVA_PMU_CFG_GC_BUS_MUX_SEL_TOP |
-				RIVA_PMU_CFG_IRIS_XO_CFG);
-		writel_relaxed(reg, RIVA_PMU_CFG);
-		clk_disable_unprepare(cxo);
-
-		if (!use_48mhz_xo) {
-			wlan_clock = msm_xo_get(MSM_XO_TCXO_A2, id);
-			if (IS_ERR(wlan_clock)) {
-				rc = PTR_ERR(wlan_clock);
-				pr_err("Failed to get MSM_XO_TCXO_A2 voter"
-							" (%d)\n", rc);
-				goto fail;
-			}
-
-			rc = msm_xo_mode_vote(wlan_clock, MSM_XO_MODE_ON);
-			if (rc < 0) {
-				pr_err("Configuring MSM_XO_MODE_ON failed"
-							" (%d)\n", rc);
-				goto msm_xo_vote_fail;
-			}
-		}
-	}  else {
-		if (wlan_clock != NULL && !use_48mhz_xo) {
-			rc = msm_xo_mode_vote(wlan_clock, MSM_XO_MODE_OFF);
-			if (rc < 0)
-				pr_err("Configuring MSM_XO_MODE_OFF failed"
-							" (%d)\n", rc);
-		}
-	}
-
-	/* Add some delay for XO to settle */
-	msleep(20);
-
-	clk_put(cxo);
-	return rc;
-
-msm_xo_vote_fail:
-	msm_xo_put(wlan_clock);
-
-fail:
-	clk_put(cxo);
-	return rc;
-}
-
-/* Helper routine to turn off all WCNSS vregs e.g. IRIS, Riva */
-static void wcnss_vregs_off(struct vregs_info regulators[], uint size)
-{
-	int i, rc = 0;
-
-	/* Regulators need to be turned off in the reverse order */
-	for (i = (size-1); i >= 0; i--) {
-		if (regulators[i].state == VREG_NULL_CONFIG)
-			continue;
-
-		/* Remove PWM mode */
-		if (regulators[i].state & VREG_OPTIMUM_MODE_MASK) {
-			rc = regulator_set_optimum_mode(
-					regulators[i].regulator, 0);
-			if (rc < 0)
-				pr_err("regulator_set_optimum_mode(%s) failed (%d)\n",
-						regulators[i].name, rc);
-		}
-
-		/* Set voltage to lowest level */
-		if (regulators[i].state & VREG_SET_VOLTAGE_MASK) {
-			rc = regulator_set_voltage(regulators[i].regulator,
-					regulators[i].low_power_min,
-					regulators[i].max_voltage);
-			if (rc)
-				pr_err("regulator_set_voltage(%s) failed (%d)\n",
-						regulators[i].name, rc);
-		}
-
-		/* Disable regulator */
-		if (regulators[i].state & VREG_ENABLE_MASK) {
-			rc = regulator_disable(regulators[i].regulator);
-			if (rc < 0)
-				pr_err("vreg %s disable failed (%d)\n",
-						regulators[i].name, rc);
-		}
-
-		/* Free the regulator source */
-		if (regulators[i].state & VREG_GET_REGULATOR_MASK)
-			regulator_put(regulators[i].regulator);
-
-		regulators[i].state = VREG_NULL_CONFIG;
-	}
-}
-
-/* Common helper routine to turn on all WCNSS vregs e.g. IRIS, Riva */
-static int wcnss_vregs_on(struct device *dev,
-		struct vregs_info regulators[], uint size)
-{
-	int i, rc = 0, reg_cnt;
-
-	for (i = 0; i < size; i++) {
-			/* Get regulator source */
-		regulators[i].regulator =
-			regulator_get(dev, regulators[i].name);
-		if (IS_ERR(regulators[i].regulator)) {
-			rc = PTR_ERR(regulators[i].regulator);
-				pr_err("regulator get of %s failed (%d)\n",
-					regulators[i].name, rc);
-				goto fail;
-		}
-		regulators[i].state |= VREG_GET_REGULATOR_MASK;
-		reg_cnt = regulator_count_voltages(regulators[i].regulator);
-		/* Set voltage to nominal. Exclude swtiches e.g. LVS */
-		if ((regulators[i].nominal_min || regulators[i].max_voltage)
-				&& (reg_cnt > 0)) {
-			rc = regulator_set_voltage(regulators[i].regulator,
-					regulators[i].nominal_min,
-					regulators[i].max_voltage);
-			if (rc) {
-				pr_err("regulator_set_voltage(%s) failed (%d)\n",
-						regulators[i].name, rc);
-				goto fail;
-			}
-			regulators[i].state |= VREG_SET_VOLTAGE_MASK;
-		}
-
-		/* Vote for PWM/PFM mode if needed */
-		if (regulators[i].uA_load && (reg_cnt > 0)) {
-			rc = regulator_set_optimum_mode(regulators[i].regulator,
-					regulators[i].uA_load);
-			if (rc < 0) {
-				pr_err("regulator_set_optimum_mode(%s) failed (%d)\n",
-						regulators[i].name, rc);
-				goto fail;
-			}
-			regulators[i].state |= VREG_OPTIMUM_MODE_MASK;
-		}
-
-		/* Enable the regulator */
-		rc = regulator_enable(regulators[i].regulator);
-		if (rc) {
-			pr_err("vreg %s enable failed (%d)\n",
-				regulators[i].name, rc);
-			goto fail;
-		}
-		regulators[i].state |= VREG_ENABLE_MASK;
-	}
-
-	return rc;
-
-fail:
-	wcnss_vregs_off(regulators, size);
-	return rc;
-
-}
-
-static void wcnss_iris_vregs_off(void)
-{
-	wcnss_vregs_off(iris_vregs, ARRAY_SIZE(iris_vregs));
-}
-
-static int wcnss_iris_vregs_on(struct device *dev)
-{
-	return wcnss_vregs_on(dev, iris_vregs, ARRAY_SIZE(iris_vregs));
-}
-
-static void wcnss_riva_vregs_off(void)
-{
-	wcnss_vregs_off(riva_vregs, ARRAY_SIZE(riva_vregs));
-}
-
-static int wcnss_riva_vregs_on(struct device *dev)
-{
-	return wcnss_vregs_on(dev, riva_vregs, ARRAY_SIZE(riva_vregs));
-}
-
-int wcnss_wlan_power(struct device *dev,
-		struct wcnss_wlan_config *cfg,
-		enum wcnss_opcode on)
-{
-	int rc = 0;
-
-	if (on) {
-		down(&riva_power_on_lock);
-		/* RIVA regulator settings */
-		rc = wcnss_riva_vregs_on(dev);
-		if (rc)
-			goto fail_riva_on;
-
-		/* IRIS regulator settings */
-		rc = wcnss_iris_vregs_on(dev);
-		if (rc)
-			goto fail_iris_on;
-
-		/* Configure IRIS XO */
-		rc = configure_iris_xo(dev, cfg->use_48mhz_xo,
-				WCNSS_WLAN_SWITCH_ON);
-		if (rc)
-			goto fail_iris_xo;
-		up(&riva_power_on_lock);
-
-	} else {
-		configure_iris_xo(dev, cfg->use_48mhz_xo,
-				WCNSS_WLAN_SWITCH_OFF);
-		wcnss_iris_vregs_off();
-		wcnss_riva_vregs_off();
-	}
-
-	return rc;
-
-fail_iris_xo:
-	wcnss_iris_vregs_off();
-
-fail_iris_on:
-	wcnss_riva_vregs_off();
-
-fail_riva_on:
-	up(&riva_power_on_lock);
-	return rc;
-}
-EXPORT_SYMBOL(wcnss_wlan_power);
-
-/*
- * During SSR Riva should not be 'powered on' until all the host drivers
- * finish their shutdown routines.  Host drivers use below APIs to
- * synchronize power-on. Riva will not be 'powered on' until all the
- * requests(to lock power-on) are freed.
- */
-int req_riva_power_on_lock(char *driver_name)
-{
-	struct host_driver *node;
-
-	if (!driver_name)
-		goto err;
-
-	node = kmalloc(sizeof(struct host_driver), GFP_KERNEL);
-	if (!node)
-		goto err;
-	strncpy(node->name, driver_name, sizeof(node->name));
-
-	mutex_lock(&list_lock);
-	/* Lock when the first request is added */
-	if (list_empty(&power_on_lock_list))
-		down(&riva_power_on_lock);
-	list_add(&node->list, &power_on_lock_list);
-	mutex_unlock(&list_lock);
-
-	return 0;
-
-err:
-	return -EINVAL;
-}
-EXPORT_SYMBOL(req_riva_power_on_lock);
-
-int free_riva_power_on_lock(char *driver_name)
-{
-	int ret = -1;
-	struct host_driver *node;
-
-	mutex_lock(&list_lock);
-	list_for_each_entry(node, &power_on_lock_list, list) {
-		if (!strncmp(node->name, driver_name, sizeof(node->name))) {
-			list_del(&node->list);
-			kfree(node);
-			ret = 0;
-			break;
-		}
-	}
-	/* unlock when the last host driver frees the lock */
-	if (list_empty(&power_on_lock_list))
-		up(&riva_power_on_lock);
-	mutex_unlock(&list_lock);
-
-	return ret;
-}
-EXPORT_SYMBOL(free_riva_power_on_lock);
diff --git a/drivers/net/wireless/wcnss/wcnss_vreg.c b/drivers/net/wireless/wcnss/wcnss_vreg.c
new file mode 100644
index 0000000..75c75a8
--- /dev/null
+++ b/drivers/net/wireless/wcnss/wcnss_vreg.c
@@ -0,0 +1,503 @@
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/slab.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
+#include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/mfd/pm8xxx/gpio.h>
+#include <linux/wcnss_wlan.h>
+#include <linux/semaphore.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <mach/msm_xo.h>
+#include <mach/msm_iomap.h>
+
+
+static void __iomem *msm_wcnss_base;
+static struct msm_xo_voter *wlan_clock;
+static const char *id = "WLAN";
+static LIST_HEAD(power_on_lock_list);
+static DEFINE_MUTEX(list_lock);
+static DEFINE_SEMAPHORE(wcnss_power_on_lock);
+
+#define MSM_RIVA_PHYS           0x03204000
+#define MSM_PRONTO_PHYS         0xfb21b000
+
+#define RIVA_PMU_OFFSET         0x28
+#define PRONTO_PMU_OFFSET       0x1004
+
+#define WCNSS_PMU_CFG_IRIS_XO_CFG          BIT(3)
+#define WCNSS_PMU_CFG_IRIS_XO_EN           BIT(4)
+#define WCNSS_PMU_CFG_GC_BUS_MUX_SEL_TOP   BIT(5)
+#define WCNSS_PMU_CFG_IRIS_XO_CFG_STS      BIT(6) /* 1: in progress, 0: done */
+
+#define WCNSS_PMU_CFG_IRIS_XO_MODE         0x6
+#define WCNSS_PMU_CFG_IRIS_XO_MODE_48      (3 << 1)
+
+#define VREG_NULL_CONFIG            0x0000
+#define VREG_GET_REGULATOR_MASK     0x0001
+#define VREG_SET_VOLTAGE_MASK       0x0002
+#define VREG_OPTIMUM_MODE_MASK      0x0004
+#define VREG_ENABLE_MASK            0x0008
+
+struct vregs_info {
+	const char * const name;
+	int state;
+	const int nominal_min;
+	const int low_power_min;
+	const int max_voltage;
+	const int uA_load;
+	struct regulator *regulator;
+};
+
+/* IRIS regulators for Riva hardware */
+static struct vregs_info iris_vregs_riva[] = {
+	{"iris_vddxo",  VREG_NULL_CONFIG, 1800000, 0, 1800000, 10000,  NULL},
+	{"iris_vddrfa", VREG_NULL_CONFIG, 1300000, 0, 1300000, 100000, NULL},
+	{"iris_vddpa",  VREG_NULL_CONFIG, 2900000, 0, 3000000, 515000, NULL},
+	{"iris_vdddig", VREG_NULL_CONFIG, 1200000, 0, 1225000, 10000,  NULL},
+};
+
+/* WCNSS regulators for Riva hardware */
+static struct vregs_info riva_vregs[] = {
+	/* Riva */
+	{"riva_vddmx",  VREG_NULL_CONFIG, 1050000, 0, 1150000, 0,      NULL},
+	{"riva_vddcx",  VREG_NULL_CONFIG, 1050000, 0, 1150000, 0,      NULL},
+	{"riva_vddpx",  VREG_NULL_CONFIG, 1800000, 0, 1800000, 0,      NULL},
+};
+
+/* IRIS regulators for Pronto hardware */
+static struct vregs_info iris_vregs_pronto[] = {
+	{"qcom,iris-vddxo",  VREG_NULL_CONFIG, 1800000, 0,
+		1800000, 10000,  NULL},
+	{"qcom,iris-vddrfa", VREG_NULL_CONFIG, 1300000, 0,
+		1300000, 100000, NULL},
+	{"qcom,iris-vddpa",  VREG_NULL_CONFIG, 2900000, 0,
+		3000000, 515000, NULL},
+	{"qcom,iris-vdddig", VREG_NULL_CONFIG, 1225000, 0,
+		1225000, 10000,  NULL},
+};
+
+/* WCNSS regulators for Pronto hardware */
+static struct vregs_info pronto_vregs[] = {
+	{"qcom,pronto-vddmx",  VREG_NULL_CONFIG, 950000,  0,
+		1150000, 0,    NULL},
+	{"qcom,pronto-vddcx",  VREG_NULL_CONFIG, 900000,  0,
+		1150000, 0,    NULL},
+	{"qcom,pronto-vddpx",  VREG_NULL_CONFIG, 1800000, 0,
+		1800000, 0,    NULL},
+};
+
+
+struct host_driver {
+	char name[20];
+	struct list_head list;
+};
+
+
+static int configure_iris_xo(struct device *dev, bool use_48mhz_xo, int on)
+{
+	u32 reg = 0;
+	int rc = 0;
+	int size = 0;
+	int pmu_offset = 0;
+	unsigned long wcnss_phys_addr;
+	void __iomem *pmu_conf_reg;
+	struct clk *clk;
+
+	if (wcnss_hardware_type() == WCNSS_PRONTO_HW) {
+		wcnss_phys_addr = MSM_PRONTO_PHYS;
+		pmu_offset = PRONTO_PMU_OFFSET;
+		size = 0x3000;
+
+		clk = clk_get(dev, "xo");
+		if (IS_ERR(clk)) {
+			pr_err("Couldn't get xo clock\n");
+			return PTR_ERR(clk);
+		}
+	} else {
+		wcnss_phys_addr = MSM_RIVA_PHYS;
+		pmu_offset = RIVA_PMU_OFFSET;
+		size = SZ_256;
+
+		clk = clk_get(dev, "cxo");
+		if (IS_ERR(clk)) {
+			pr_err("Couldn't get cxo clock\n");
+			return PTR_ERR(clk);
+		}
+	}
+
+	if (on) {
+		msm_wcnss_base = ioremap(wcnss_phys_addr, size);
+		if (!msm_wcnss_base) {
+			pr_err("ioremap wcnss physical failed\n");
+			goto fail;
+		}
+		pmu_conf_reg = msm_wcnss_base + pmu_offset;
+
+		/* Enable IRIS XO */
+		rc = clk_prepare_enable(clk);
+		if (rc) {
+			pr_err("clk enable failed\n");
+			goto fail;
+		}
+		writel_relaxed(0, pmu_conf_reg);
+		reg = readl_relaxed(pmu_conf_reg);
+		reg |= WCNSS_PMU_CFG_GC_BUS_MUX_SEL_TOP |
+				WCNSS_PMU_CFG_IRIS_XO_EN;
+		writel_relaxed(reg, pmu_conf_reg);
+
+		/* Clear XO_MODE[b2:b1] bits. Clear implies 19.2 MHz TCXO */
+		reg &= ~(WCNSS_PMU_CFG_IRIS_XO_MODE);
+
+		if (use_48mhz_xo)
+			reg |= WCNSS_PMU_CFG_IRIS_XO_MODE_48;
+
+		writel_relaxed(reg, pmu_conf_reg);
+
+		/* Start IRIS XO configuration */
+		reg |= WCNSS_PMU_CFG_IRIS_XO_CFG;
+		writel_relaxed(reg, pmu_conf_reg);
+
+		/* Wait for XO configuration to finish */
+		while (readl_relaxed(pmu_conf_reg) &
+						WCNSS_PMU_CFG_IRIS_XO_CFG_STS)
+			cpu_relax();
+
+		/* Stop IRIS XO configuration */
+		reg &= ~(WCNSS_PMU_CFG_GC_BUS_MUX_SEL_TOP |
+				WCNSS_PMU_CFG_IRIS_XO_CFG);
+		writel_relaxed(reg, pmu_conf_reg);
+		clk_disable_unprepare(clk);
+
+		if (!use_48mhz_xo) {
+			wlan_clock = msm_xo_get(MSM_XO_TCXO_A2, id);
+			if (IS_ERR(wlan_clock)) {
+				rc = PTR_ERR(wlan_clock);
+				pr_err("Failed to get MSM_XO_TCXO_A2 voter (%d)\n",
+						rc);
+				goto fail;
+			}
+
+			rc = msm_xo_mode_vote(wlan_clock, MSM_XO_MODE_ON);
+			if (rc < 0) {
+				pr_err("Configuring MSM_XO_MODE_ON failed (%d)\n",
+						rc);
+				goto msm_xo_vote_fail;
+			}
+		}
+	}  else {
+		if (wlan_clock != NULL && !use_48mhz_xo) {
+			rc = msm_xo_mode_vote(wlan_clock, MSM_XO_MODE_OFF);
+			if (rc < 0)
+				pr_err("Configuring MSM_XO_MODE_OFF failed (%d)\n",
+						rc);
+		}
+	}
+
+	/* Add some delay for XO to settle */
+	msleep(20);
+
+	clk_put(clk);
+	return rc;
+
+msm_xo_vote_fail:
+	msm_xo_put(wlan_clock);
+
+fail:
+	clk_put(clk);
+	return rc;
+}
+
+/* Helper routine to turn off all WCNSS & IRIS vregs */
+static void wcnss_vregs_off(struct vregs_info regulators[], uint size)
+{
+	int i, rc = 0;
+
+	/* Regulators need to be turned off in the reverse order */
+	for (i = (size-1); i >= 0; i--) {
+		if (regulators[i].state == VREG_NULL_CONFIG)
+			continue;
+
+		/* Remove PWM mode */
+		if (regulators[i].state & VREG_OPTIMUM_MODE_MASK) {
+			rc = regulator_set_optimum_mode(
+					regulators[i].regulator, 0);
+			if (rc < 0)
+				pr_err("regulator_set_optimum_mode(%s) failed (%d)\n",
+						regulators[i].name, rc);
+		}
+
+		/* Set voltage to lowest level */
+		if (regulators[i].state & VREG_SET_VOLTAGE_MASK) {
+			rc = regulator_set_voltage(regulators[i].regulator,
+					regulators[i].low_power_min,
+					regulators[i].max_voltage);
+			if (rc)
+				pr_err("regulator_set_voltage(%s) failed (%d)\n",
+						regulators[i].name, rc);
+		}
+
+		/* Disable regulator */
+		if (regulators[i].state & VREG_ENABLE_MASK) {
+			rc = regulator_disable(regulators[i].regulator);
+			if (rc < 0)
+				pr_err("vreg %s disable failed (%d)\n",
+						regulators[i].name, rc);
+		}
+
+		/* Free the regulator source */
+		if (regulators[i].state & VREG_GET_REGULATOR_MASK)
+			regulator_put(regulators[i].regulator);
+
+		regulators[i].state = VREG_NULL_CONFIG;
+	}
+}
+
+/* Common helper routine to turn on all WCNSS & IRIS vregs */
+static int wcnss_vregs_on(struct device *dev,
+		struct vregs_info regulators[], uint size)
+{
+	int i, rc = 0, reg_cnt;
+
+	for (i = 0; i < size; i++) {
+			/* Get regulator source */
+		regulators[i].regulator =
+			regulator_get(dev, regulators[i].name);
+		if (IS_ERR(regulators[i].regulator)) {
+			rc = PTR_ERR(regulators[i].regulator);
+				pr_err("regulator get of %s failed (%d)\n",
+					regulators[i].name, rc);
+				goto fail;
+		}
+		regulators[i].state |= VREG_GET_REGULATOR_MASK;
+		reg_cnt = regulator_count_voltages(regulators[i].regulator);
+		/* Set voltage to nominal. Exclude swtiches e.g. LVS */
+		if ((regulators[i].nominal_min || regulators[i].max_voltage)
+				&& (reg_cnt > 0)) {
+			rc = regulator_set_voltage(regulators[i].regulator,
+					regulators[i].nominal_min,
+					regulators[i].max_voltage);
+			if (rc) {
+				pr_err("regulator_set_voltage(%s) failed (%d)\n",
+						regulators[i].name, rc);
+				goto fail;
+			}
+			regulators[i].state |= VREG_SET_VOLTAGE_MASK;
+		}
+
+		/* Vote for PWM/PFM mode if needed */
+		if (regulators[i].uA_load && (reg_cnt > 0)) {
+			rc = regulator_set_optimum_mode(regulators[i].regulator,
+					regulators[i].uA_load);
+			if (rc < 0) {
+				pr_err("regulator_set_optimum_mode(%s) failed (%d)\n",
+						regulators[i].name, rc);
+				goto fail;
+			}
+			regulators[i].state |= VREG_OPTIMUM_MODE_MASK;
+		}
+
+		/* Enable the regulator */
+		rc = regulator_enable(regulators[i].regulator);
+		if (rc) {
+			pr_err("vreg %s enable failed (%d)\n",
+				regulators[i].name, rc);
+			goto fail;
+		}
+		regulators[i].state |= VREG_ENABLE_MASK;
+	}
+
+	return rc;
+
+fail:
+	wcnss_vregs_off(regulators, size);
+	return rc;
+
+}
+
+static void wcnss_iris_vregs_off(enum wcnss_hw_type hw_type)
+{
+	switch (hw_type) {
+	case WCNSS_RIVA_HW:
+		wcnss_vregs_off(iris_vregs_riva, ARRAY_SIZE(iris_vregs_riva));
+		break;
+	case WCNSS_PRONTO_HW:
+		wcnss_vregs_off(iris_vregs_pronto,
+				ARRAY_SIZE(iris_vregs_pronto));
+		break;
+	default:
+		pr_err("%s invalid hardware %d\n", __func__, hw_type);
+
+	}
+}
+
+static int wcnss_iris_vregs_on(struct device *dev, enum wcnss_hw_type hw_type)
+{
+	int ret = -1;
+
+	switch (hw_type) {
+	case WCNSS_RIVA_HW:
+		ret = wcnss_vregs_on(dev, iris_vregs_riva,
+				ARRAY_SIZE(iris_vregs_riva));
+		break;
+	case WCNSS_PRONTO_HW:
+		ret = wcnss_vregs_on(dev, iris_vregs_pronto,
+				ARRAY_SIZE(iris_vregs_pronto));
+		break;
+	default:
+		pr_err("%s invalid hardware %d\n", __func__, hw_type);
+	}
+	return ret;
+}
+
+static void wcnss_core_vregs_off(enum wcnss_hw_type hw_type)
+{
+	switch (hw_type) {
+	case WCNSS_RIVA_HW:
+		wcnss_vregs_off(riva_vregs, ARRAY_SIZE(riva_vregs));
+		break;
+	case WCNSS_PRONTO_HW:
+		wcnss_vregs_off(pronto_vregs, ARRAY_SIZE(pronto_vregs));
+		break;
+	default:
+		pr_err("%s invalid hardware %d\n", __func__, hw_type);
+	}
+
+}
+
+static int wcnss_core_vregs_on(struct device *dev, enum wcnss_hw_type hw_type)
+{
+	int ret = -1;
+
+	switch (hw_type) {
+	case WCNSS_RIVA_HW:
+		ret = wcnss_vregs_on(dev, riva_vregs, ARRAY_SIZE(riva_vregs));
+		break;
+	case WCNSS_PRONTO_HW:
+		ret = wcnss_vregs_on(dev, pronto_vregs,
+				ARRAY_SIZE(pronto_vregs));
+		break;
+	default:
+		pr_err("%s invalid hardware %d\n", __func__, hw_type);
+	}
+
+	return ret;
+
+}
+
+int wcnss_wlan_power(struct device *dev,
+		struct wcnss_wlan_config *cfg,
+		enum wcnss_opcode on)
+{
+	int rc = 0;
+	enum wcnss_hw_type hw_type = wcnss_hardware_type();
+
+	if (on) {
+		down(&wcnss_power_on_lock);
+		/* RIVA regulator settings */
+		rc = wcnss_core_vregs_on(dev, hw_type);
+		if (rc)
+			goto fail_wcnss_on;
+
+		/* IRIS regulator settings */
+		rc = wcnss_iris_vregs_on(dev, hw_type);
+		if (rc)
+			goto fail_iris_on;
+
+		/* Configure IRIS XO */
+		rc = configure_iris_xo(dev, cfg->use_48mhz_xo,
+				WCNSS_WLAN_SWITCH_ON);
+		if (rc)
+			goto fail_iris_xo;
+		up(&wcnss_power_on_lock);
+
+	} else {
+		configure_iris_xo(dev, cfg->use_48mhz_xo,
+				WCNSS_WLAN_SWITCH_OFF);
+		wcnss_iris_vregs_off(hw_type);
+		wcnss_core_vregs_off(hw_type);
+	}
+
+	return rc;
+
+fail_iris_xo:
+	wcnss_iris_vregs_off(hw_type);
+
+fail_iris_on:
+	wcnss_core_vregs_off(hw_type);
+
+fail_wcnss_on:
+	up(&wcnss_power_on_lock);
+	return rc;
+}
+EXPORT_SYMBOL(wcnss_wlan_power);
+
+/*
+ * During SSR WCNSS should not be 'powered on' until all the host drivers
+ * finish their shutdown routines.  Host drivers use below APIs to
+ * synchronize power-on. WCNSS will not be 'powered on' until all the
+ * requests(to lock power-on) are freed.
+ */
+int wcnss_req_power_on_lock(char *driver_name)
+{
+	struct host_driver *node;
+
+	if (!driver_name)
+		goto err;
+
+	node = kmalloc(sizeof(struct host_driver), GFP_KERNEL);
+	if (!node)
+		goto err;
+	strlcpy(node->name, driver_name, sizeof(node->name));
+
+	mutex_lock(&list_lock);
+	/* Lock when the first request is added */
+	if (list_empty(&power_on_lock_list))
+		down(&wcnss_power_on_lock);
+	list_add(&node->list, &power_on_lock_list);
+	mutex_unlock(&list_lock);
+
+	return 0;
+
+err:
+	return -EINVAL;
+}
+EXPORT_SYMBOL(wcnss_req_power_on_lock);
+
+int wcnss_free_power_on_lock(char *driver_name)
+{
+	int ret = -1;
+	struct host_driver *node;
+
+	mutex_lock(&list_lock);
+	list_for_each_entry(node, &power_on_lock_list, list) {
+		if (!strncmp(node->name, driver_name, sizeof(node->name))) {
+			list_del(&node->list);
+			kfree(node);
+			ret = 0;
+			break;
+		}
+	}
+	/* unlock when the last host driver frees the lock */
+	if (list_empty(&power_on_lock_list))
+		up(&wcnss_power_on_lock);
+	mutex_unlock(&list_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL(wcnss_free_power_on_lock);
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index c0a4e0e..ac0a2fd 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -22,7 +22,14 @@
 #include <linux/jiffies.h>
 #include <linux/gpio.h>
 #include <linux/wakelock.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
 #include <mach/peripheral-loader.h>
+#include <mach/msm_smd.h>
+#ifdef CONFIG_WCNSS_MEM_PRE_ALLOC
+#include "wcnss_prealloc.h"
+#endif
 
 #define DEVICE "wcnss_wlan"
 #define VERSION "1.01"
@@ -30,10 +37,36 @@
 
 /* module params */
 #define WCNSS_CONFIG_UNSPECIFIED (-1)
+
 static int has_48mhz_xo = WCNSS_CONFIG_UNSPECIFIED;
 module_param(has_48mhz_xo, int, S_IWUSR | S_IRUGO);
 MODULE_PARM_DESC(has_48mhz_xo, "Is an external 48 MHz XO present");
 
+#define WCNSS_CTRL_CHANNEL			"WCNSS_CTRL"
+#define WCNSS_MAX_FRAME_SIZE		500
+#define WCNSS_VERSION_LEN			30
+
+/* message types */
+#define WCNSS_CTRL_MSG_START	0x01000000
+#define	WCNSS_VERSION_REQ		(WCNSS_CTRL_MSG_START + 0)
+#define	WCNSS_VERSION_RSP		(WCNSS_CTRL_MSG_START + 1)
+
+#define VALID_VERSION(version) \
+	((strncmp(version, "INVALID", WCNSS_VERSION_LEN)) ? 1 : 0)
+
+struct smd_msg_hdr {
+	unsigned int type;
+	unsigned int len;
+};
+
+struct wcnss_version {
+	struct smd_msg_hdr hdr;
+	unsigned char  major;
+	unsigned char  minor;
+	unsigned char  version;
+	unsigned char  revision;
+};
+
 static struct {
 	struct platform_device *pdev;
 	void		*pil;
@@ -44,11 +77,16 @@
 	const struct dev_pm_ops *pm_ops;
 	int		triggered;
 	int		smd_channel_ready;
+	smd_channel_t	*smd_ch;
+	unsigned char	wcnss_version[WCNSS_VERSION_LEN];
 	unsigned int	serial_number;
 	int		thermal_mitigation;
+	enum wcnss_hw_type	wcnss_hw_type;
 	void		(*tm_notify)(struct device *, int);
 	struct wcnss_wlan_config wlan_config;
 	struct delayed_work wcnss_work;
+	struct work_struct wcnssctrl_version_work;
+	struct work_struct wcnssctrl_rx_work;
 	struct wake_lock wcnss_wake_lock;
 } *penv = NULL;
 
@@ -108,6 +146,19 @@
 static DEVICE_ATTR(thermal_mitigation, S_IRUSR | S_IWUSR,
 	wcnss_thermal_mitigation_show, wcnss_thermal_mitigation_store);
 
+
+static ssize_t wcnss_version_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	if (!penv)
+		return -ENODEV;
+
+	return scnprintf(buf, PAGE_SIZE, "%s", penv->wcnss_version);
+}
+
+static DEVICE_ATTR(wcnss_version, S_IRUSR,
+		wcnss_version_show, NULL);
+
 static int wcnss_create_sysfs(struct device *dev)
 {
 	int ret;
@@ -120,11 +171,21 @@
 		return ret;
 
 	ret = device_create_file(dev, &dev_attr_thermal_mitigation);
-	if (ret) {
-		device_remove_file(dev, &dev_attr_serial_number);
-		return ret;
-	}
+	if (ret)
+		goto remove_serial;
+
+	ret = device_create_file(dev, &dev_attr_wcnss_version);
+	if (ret)
+		goto remove_thermal;
+
 	return 0;
+
+remove_thermal:
+	device_remove_file(dev, &dev_attr_thermal_mitigation);
+remove_serial:
+	device_remove_file(dev, &dev_attr_serial_number);
+
+	return ret;
 }
 
 static void wcnss_remove_sysfs(struct device *dev)
@@ -132,16 +193,80 @@
 	if (dev) {
 		device_remove_file(dev, &dev_attr_serial_number);
 		device_remove_file(dev, &dev_attr_thermal_mitigation);
+		device_remove_file(dev, &dev_attr_wcnss_version);
+	}
+}
+static void wcnss_smd_notify_event(void *data, unsigned int event)
+{
+	int len = 0;
+
+	if (penv != data) {
+		pr_err("wcnss: invalid env pointer in smd callback\n");
+		return;
+	}
+	switch (event) {
+	case SMD_EVENT_DATA:
+		len = smd_read_avail(penv->smd_ch);
+		if (len < 0)
+			pr_err("wcnss: failed to read from smd %d\n", len);
+		schedule_work(&penv->wcnssctrl_rx_work);
+		break;
+
+	case SMD_EVENT_OPEN:
+		pr_debug("wcnss: opening WCNSS SMD channel :%s",
+				WCNSS_CTRL_CHANNEL);
+		if (!VALID_VERSION(penv->wcnss_version))
+			schedule_work(&penv->wcnssctrl_version_work);
+		break;
+
+	case SMD_EVENT_CLOSE:
+		pr_debug("wcnss: closing WCNSS SMD channel :%s",
+				WCNSS_CTRL_CHANNEL);
+		break;
+
+	default:
+		break;
 	}
 }
 
 static void wcnss_post_bootup(struct work_struct *work)
 {
-	pr_info("%s: Cancel APPS vote for Iris & Riva\n", __func__);
+	pr_info("%s: Cancel APPS vote for Iris & WCNSS\n", __func__);
 
-	/* Since Riva is up, cancel any APPS vote for Iris & Riva VREGs  */
+	/* Since WCNSS is up, cancel any APPS vote for Iris & WCNSS VREGs  */
 	wcnss_wlan_power(&penv->pdev->dev, &penv->wlan_config,
 		WCNSS_WLAN_SWITCH_OFF);
+
+}
+
+static int
+wcnss_pronto_gpios_config(struct device *dev, bool enable)
+{
+	int rc = 0;
+	int i, j;
+	int WCNSS_WLAN_NUM_GPIOS = 5;
+
+	for (i = 0; i < WCNSS_WLAN_NUM_GPIOS; i++) {
+		int gpio = of_get_gpio(dev->of_node, i);
+		if (enable) {
+			rc = gpio_request(gpio, "wcnss_wlan");
+			if (rc) {
+				pr_err("WCNSS gpio_request %d err %d\n",
+					gpio, rc);
+				goto fail;
+			}
+		} else
+			gpio_free(gpio);
+	}
+
+	return rc;
+
+fail:
+	for (j = WCNSS_WLAN_NUM_GPIOS-1; j >= 0; j--) {
+		int gpio = of_get_gpio(dev->of_node, i);
+		gpio_free(gpio);
+	}
+	return rc;
 }
 
 static int
@@ -213,6 +338,45 @@
 	.remove	= __devexit_p(wcnss_wlan_ctrl_remove),
 };
 
+static int __devexit
+wcnss_ctrl_remove(struct platform_device *pdev)
+{
+	if (penv && penv->smd_ch)
+		smd_close(penv->smd_ch);
+
+	return 0;
+}
+
+static int __devinit
+wcnss_ctrl_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+
+	if (!penv)
+		return -ENODEV;
+
+	ret = smd_named_open_on_edge(WCNSS_CTRL_CHANNEL, SMD_APPS_WCNSS,
+			&penv->smd_ch, penv, wcnss_smd_notify_event);
+	if (ret < 0) {
+		pr_err("wcnss: cannot open the smd command channel %s: %d\n",
+				WCNSS_CTRL_CHANNEL, ret);
+		return -ENODEV;
+	}
+	smd_disable_read_intr(penv->smd_ch);
+
+	return 0;
+}
+
+/* platform device for WCNSS_CTRL SMD channel */
+static struct platform_driver wcnss_ctrl_driver = {
+	.driver = {
+		.name	= "WCNSS_CTRL",
+		.owner	= THIS_MODULE,
+	},
+	.probe	= wcnss_ctrl_probe,
+	.remove	= __devexit_p(wcnss_ctrl_remove),
+};
+
 struct device *wcnss_wlan_get_device(void)
 {
 	if (penv && penv->pdev && penv->smd_channel_ready)
@@ -342,11 +506,99 @@
 }
 EXPORT_SYMBOL(wcnss_allow_suspend);
 
+int wcnss_hardware_type(void)
+{
+	if (penv)
+		return penv->wcnss_hw_type;
+	else
+		return -ENODEV;
+}
+EXPORT_SYMBOL(wcnss_hardware_type);
+
+static int wcnss_smd_tx(void *data, int len)
+{
+	int ret = 0;
+
+	ret = smd_write_avail(penv->smd_ch);
+	if (ret < len) {
+		pr_err("wcnss: no space available for smd frame\n");
+		ret =  -ENOSPC;
+	}
+	ret = smd_write(penv->smd_ch, data, len);
+	if (ret < len) {
+		pr_err("wcnss: failed to write Command %d", len);
+		ret = -ENODEV;
+	}
+	return ret;
+}
+
+static void wcnssctrl_rx_handler(struct work_struct *worker)
+{
+	int len = 0;
+	int rc = 0;
+	unsigned char buf[WCNSS_MAX_FRAME_SIZE];
+	struct smd_msg_hdr *phdr;
+	struct wcnss_version *pversion;
+
+	len = smd_read_avail(penv->smd_ch);
+	if (len > WCNSS_MAX_FRAME_SIZE) {
+		pr_err("wcnss: frame larger than the allowed size\n");
+		smd_read(penv->smd_ch, NULL, len);
+		return;
+	}
+	if (len <= 0)
+		return;
+
+	rc = smd_read(penv->smd_ch, buf, len);
+	if (rc < len) {
+		pr_err("wcnss: incomplete data read from smd\n");
+		return;
+	}
+
+	phdr = (struct smd_msg_hdr *)buf;
+
+	switch (phdr->type) {
+
+	case WCNSS_VERSION_RSP:
+		pversion = (struct wcnss_version *)buf;
+		if (len != sizeof(struct wcnss_version)) {
+			pr_err("wcnss: invalid version data from wcnss %d\n",
+				len);
+			return;
+		}
+		snprintf(penv->wcnss_version, WCNSS_VERSION_LEN,
+			"%02x%02x%02x%02x", pversion->major, pversion->minor,
+					pversion->version, pversion->revision);
+		pr_info("wcnss: version %s\n", penv->wcnss_version);
+		break;
+
+	default:
+		pr_err("wcnss: invalid message type %d\n", phdr->type);
+	}
+	return;
+}
+
+static void wcnss_send_version_req(struct work_struct *worker)
+{
+	struct smd_msg_hdr smd_msg;
+	int ret = 0;
+
+	smd_msg.type = WCNSS_VERSION_REQ;
+	smd_msg.len = sizeof(smd_msg);
+	ret = wcnss_smd_tx(&smd_msg, smd_msg.len);
+	if (ret < 0)
+		pr_err("wcnss: smd tx failed\n");
+
+	return;
+}
+
 static int
 wcnss_trigger_config(struct platform_device *pdev)
 {
 	int ret;
 	struct qcom_wcnss_opts *pdata;
+	int has_pronto_hw = of_property_read_bool(pdev->dev.of_node,
+									"qcom,has_pronto_hw");
 
 	/* make sure we are only triggered once */
 	if (penv->triggered)
@@ -355,24 +607,36 @@
 
 	/* initialize the WCNSS device configuration */
 	pdata = pdev->dev.platform_data;
-	if (WCNSS_CONFIG_UNSPECIFIED == has_48mhz_xo)
-		has_48mhz_xo = pdata->has_48mhz_xo;
+	if (WCNSS_CONFIG_UNSPECIFIED == has_48mhz_xo) {
+		if (has_pronto_hw) {
+			has_48mhz_xo = of_property_read_bool(pdev->dev.of_node,
+										"qcom,has_48mhz_xo");
+			penv->wcnss_hw_type = WCNSS_PRONTO_HW;
+		} else {
+			penv->wcnss_hw_type = WCNSS_RIVA_HW;
+			has_48mhz_xo = pdata->has_48mhz_xo;
+		}
+	}
 	penv->wlan_config.use_48mhz_xo = has_48mhz_xo;
 
 	penv->thermal_mitigation = 0;
-
-	penv->gpios_5wire = platform_get_resource_byname(pdev, IORESOURCE_IO,
-							"wcnss_gpios_5wire");
-
-	/* allocate 5-wire GPIO resources */
-	if (!penv->gpios_5wire) {
-		dev_err(&pdev->dev, "insufficient IO resources\n");
-		ret = -ENOENT;
-		goto fail_gpio_res;
-	}
+	strlcpy(penv->wcnss_version, "INVALID", WCNSS_VERSION_LEN);
 
 	/* Configure 5 wire GPIOs */
-	ret = wcnss_gpios_config(penv->gpios_5wire, true);
+	if (!has_pronto_hw) {
+		penv->gpios_5wire = platform_get_resource_byname(pdev,
+					IORESOURCE_IO, "wcnss_gpios_5wire");
+
+		/* allocate 5-wire GPIO resources */
+		if (!penv->gpios_5wire) {
+			dev_err(&pdev->dev, "insufficient IO resources\n");
+			ret = -ENOENT;
+			goto fail_gpio_res;
+		}
+		ret = wcnss_gpios_config(penv->gpios_5wire, true);
+	} else
+		ret = wcnss_pronto_gpios_config(&pdev->dev, true);
+
 	if (ret) {
 		dev_err(&pdev->dev, "WCNSS gpios config failed.\n");
 		goto fail_gpio_res;
@@ -408,17 +672,13 @@
 		ret = -ENOENT;
 		goto fail_res;
 	}
-
-	/* register sysfs entries */
-	ret = wcnss_create_sysfs(&pdev->dev);
-	if (ret)
-		goto fail_sysfs;
+	INIT_WORK(&penv->wcnssctrl_rx_work, wcnssctrl_rx_handler);
+	INIT_WORK(&penv->wcnssctrl_version_work, wcnss_send_version_req);
 
 	wake_lock_init(&penv->wcnss_wake_lock, WAKE_LOCK_SUSPEND, "wcnss");
 
 	return 0;
 
-fail_sysfs:
 fail_res:
 	if (penv->pil)
 		pil_put(penv->pil);
@@ -426,7 +686,10 @@
 	wcnss_wlan_power(&pdev->dev, &penv->wlan_config,
 				WCNSS_WLAN_SWITCH_OFF);
 fail_power:
-	wcnss_gpios_config(penv->gpios_5wire, false);
+	if (has_pronto_hw)
+		ret = wcnss_pronto_gpios_config(&pdev->dev, false);
+	else
+		wcnss_gpios_config(penv->gpios_5wire, false);
 fail_gpio_res:
 	kfree(penv);
 	penv = NULL;
@@ -460,6 +723,8 @@
 static int __devinit
 wcnss_wlan_probe(struct platform_device *pdev)
 {
+	int ret = 0;
+
 	/* verify we haven't been called more than once */
 	if (penv) {
 		dev_err(&pdev->dev, "cannot handle multiple devices.\n");
@@ -474,6 +739,12 @@
 	}
 	penv->pdev = pdev;
 
+	/* register sysfs entries */
+	ret = wcnss_create_sysfs(&pdev->dev);
+	if (ret)
+		return -ENOENT;
+
+
 #ifdef MODULE
 
 	/*
@@ -515,11 +786,21 @@
 	.resume		= wcnss_wlan_resume,
 };
 
+#ifdef CONFIG_WCNSS_CORE_PRONTO
+static struct of_device_id msm_wcnss_pronto_match[] = {
+	{.compatible = "qcom,wcnss_wlan"},
+	{}
+};
+#endif
+
 static struct platform_driver wcnss_wlan_driver = {
 	.driver = {
 		.name	= DEVICE,
 		.owner	= THIS_MODULE,
 		.pm	= &wcnss_wlan_pm_ops,
+#ifdef CONFIG_WCNSS_CORE_PRONTO
+		.of_match_table = msm_wcnss_pronto_match,
+#endif
 	},
 	.probe	= wcnss_wlan_probe,
 	.remove	= __devexit_p(wcnss_wlan_remove),
@@ -527,10 +808,19 @@
 
 static int __init wcnss_wlan_init(void)
 {
+	int ret = 0;
+
 	platform_driver_register(&wcnss_wlan_driver);
 	platform_driver_register(&wcnss_wlan_ctrl_driver);
+	platform_driver_register(&wcnss_ctrl_driver);
 
-	return 0;
+#ifdef CONFIG_WCNSS_MEM_PRE_ALLOC
+	ret = wcnss_prealloc_init();
+	if (ret < 0)
+		pr_err("wcnss: pre-allocation failed\n");
+#endif
+
+	return ret;
 }
 
 static void __exit wcnss_wlan_exit(void)
@@ -544,8 +834,12 @@
 		penv = NULL;
 	}
 
+	platform_driver_unregister(&wcnss_ctrl_driver);
 	platform_driver_unregister(&wcnss_wlan_ctrl_driver);
 	platform_driver_unregister(&wcnss_wlan_driver);
+#ifdef CONFIG_WCNSS_MEM_PRE_ALLOC
+	wcnss_prealloc_deinit();
+#endif
 }
 
 module_init(wcnss_wlan_init);
diff --git a/drivers/of/gpio.c b/drivers/of/gpio.c
index bf984b6..94e76d8 100644
--- a/drivers/of/gpio.c
+++ b/drivers/of/gpio.c
@@ -49,7 +49,7 @@
 	if (!gc) {
 		pr_debug("%s: gpio controller %s isn't registered\n",
 			 np->full_name, gpiospec.np->full_name);
-		ret = -ENODEV;
+		ret = -EPROBE_DEFER;
 		goto err1;
 	}
 
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/sps/bam.c b/drivers/platform/msm/sps/bam.c
index 31b405a..eb9e8ee 100644
--- a/drivers/platform/msm/sps/bam.c
+++ b/drivers/platform/msm/sps/bam.c
@@ -643,10 +643,10 @@
  */
 int bam_init(void *base, u32 ee,
 		u16 summing_threshold,
-		u32 irq_mask, u32 *version, u32 *num_pipes)
+		u32 irq_mask, u32 *version,
+		u32 *num_pipes, u32 p_rst)
 {
-	/* disable bit#11 because of HW bug */
-	u32 cfg_bits = 0xffffffff & ~(1 << 11);
+	u32 cfg_bits;
 	u32 ver = 0;
 
 	SPS_DBG2("sps:%s:bam=0x%x(va).ee=%d.", __func__, (u32) base, ee);
@@ -658,7 +658,7 @@
 				(u32) base, ver);
 		return -ENODEV;
 	} else
-		SPS_INFO("sps:REVISION of BAM 0x%x is 0x%x.\n",
+		SPS_DBG2("sps:REVISION of BAM 0x%x is 0x%x.\n",
 				(u32) base, ver);
 
 	if (summing_threshold == 0) {
@@ -667,6 +667,11 @@
 				"use default 4.\n", (u32) base);
 	}
 
+	if (p_rst)
+		cfg_bits = 0xffffffff & ~(3 << 11);
+	else
+		cfg_bits = 0xffffffff & ~(1 << 11);
+
 	bam_write_reg_field(base, CTRL, BAM_SW_RST, 1);
 	/* No delay needed */
 	bam_write_reg_field(base, CTRL, BAM_SW_RST, 0);
@@ -1398,3 +1403,32 @@
 
 	SPS_INFO("--------------------  end of FIFO  --------------------\n");
 }
+
+/* output BAM_TEST_BUS_REG with specified TEST_BUS_SEL */
+void print_bam_test_bus_reg(void *base, u32 tb_sel)
+{
+	u32 i;
+	u32 test_bus_selection[] = {0x1, 0x2, 0x3, 0x4, 0xD, 0x10,
+			0x41, 0x42, 0x43, 0x44, 0x45, 0x46};
+	u32 size = sizeof(test_bus_selection) / sizeof(u32);
+
+	if ((base == NULL) || (tb_sel == 0))
+		return;
+
+	SPS_INFO("\nsps:Specified TEST_BUS_SEL value: 0x%x\n", tb_sel);
+	bam_write_reg_field(base, TEST_BUS_SEL, BAM_TESTBUS_SEL, tb_sel);
+	SPS_INFO("sps:BAM_TEST_BUS_REG: 0x%x when TEST_BUS_SEL: 0x%x\n\n",
+		bam_read_reg(base, TEST_BUS_REG),
+		bam_read_reg_field(base, TEST_BUS_SEL, BAM_TESTBUS_SEL));
+
+	/* output other selections */
+	for (i = 0; i < size; i++) {
+		bam_write_reg_field(base, TEST_BUS_SEL, BAM_TESTBUS_SEL,
+					test_bus_selection[i]);
+
+		SPS_INFO("sps:bam 0x%x(va);TEST_BUS_REG:0x%x;TEST_BUS_SEL:0x%x",
+			(u32) base, bam_read_reg(base, TEST_BUS_REG),
+			bam_read_reg_field(base, TEST_BUS_SEL,
+					BAM_TESTBUS_SEL));
+	}
+}
diff --git a/drivers/platform/msm/sps/bam.h b/drivers/platform/msm/sps/bam.h
index 3521ffa..c183fcd 100644
--- a/drivers/platform/msm/sps/bam.h
+++ b/drivers/platform/msm/sps/bam.h
@@ -102,13 +102,16 @@
  *
  * @num_pipes - return number of pipes
  *
+ * @p_rst - ignore external block pipe reset
+ *
  * @return 0 on success, negative value on error
  *
  */
 int bam_init(void *base,
 		u32 ee,
 		u16 summing_threshold,
-		u32 irq_mask, u32 *version, u32 *num_pipes);
+		u32 irq_mask, u32 *version,
+		u32 *num_pipes, u32 p_rst);
 
 /**
  * Initialize BAM device security execution environment
diff --git a/drivers/platform/msm/sps/sps.c b/drivers/platform/msm/sps/sps.c
index 656d1fb..5bbcc84 100644
--- a/drivers/platform/msm/sps/sps.c
+++ b/drivers/platform/msm/sps/sps.c
@@ -89,6 +89,9 @@
 u8 debug_level_option;
 u8 print_limit_option;
 u8 reg_dump_option;
+u32 testbus_sel;
+u32 bam_pipe_sel;
+
 
 static char *debugfs_buf;
 static u32 debugfs_buf_size;
@@ -101,6 +104,8 @@
 struct dentry *dfile_debug_level_option;
 struct dentry *dfile_print_limit_option;
 struct dentry *dfile_reg_dump_option;
+struct dentry *dfile_testbus_sel;
+struct dentry *dfile_bam_pipe_sel;
 struct dentry *dfile_bam_addr;
 
 static struct sps_bam *phy2bam(u32 phys_addr);
@@ -325,30 +330,53 @@
 		for (i = 0; i < num_pipes; i++)
 			print_bam_pipe_selected_reg(vir_addr, i);
 		break;
-	case 5: /* output selected registers of some pipes */
+	case 5: /* output selected registers of selected pipes */
+		for (i = 0; i < num_pipes; i++)
+			if (bam_pipe_sel & (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 6: /* output desc FIFO of all active pipes */
+	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 7: /* output desc FIFO of some pipes */
+	case 8: /* output desc FIFO of selected pipes */
+		for (i = 0; i < num_pipes; i++)
+			if (bam_pipe_sel & (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 8: /* output selected registers and valid desc FIFO of all pipes */
+	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 9: /* output selected registers and desc FIFO of some pipes */
+	case 11: /* output selected registers and desc FIFO of selected pipes */
+		for (i = 0; i < num_pipes; i++)
+			if (bam_pipe_sel & (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;
+	case 13: /* output BAM_TEST_BUS_REG */
+		if (testbus_sel)
+			print_bam_test_bus_reg(vir_addr, testbus_sel);
+		else
+			pr_info("sps:TEST_BUS_SEL should NOT be zero.");
+		break;
 	default:
 		pr_info("sps:no dump option is chosen yet.");
 	}
@@ -367,6 +395,8 @@
 	debug_level_option = 0;
 	print_limit_option = 0;
 	reg_dump_option = 0;
+	testbus_sel = 0;
+	bam_pipe_sel = 0;
 	debugfs_buf_size = 0;
 	debugfs_buf_used = 0;
 	wraparound = false;
@@ -416,6 +446,20 @@
 		goto reg_dump_option_err;
 	}
 
+	dfile_testbus_sel = debugfs_create_u32("testbus_sel", 0666,
+						dent, &testbus_sel);
+	if (!dfile_testbus_sel || IS_ERR(dfile_testbus_sel)) {
+		pr_err("sps:fail to create debug_fs file for testbus_sel.\n");
+		goto testbus_sel_err;
+	}
+
+	dfile_bam_pipe_sel = debugfs_create_u32("bam_pipe_sel", 0666,
+						dent, &bam_pipe_sel);
+	if (!dfile_bam_pipe_sel || IS_ERR(dfile_bam_pipe_sel)) {
+		pr_err("sps:fail to create debug_fs file for bam_pipe_sel.\n");
+		goto bam_pipe_sel_err;
+	}
+
 	dfile_bam_addr = debugfs_create_file("bam_addr", 0666,
 			dent, 0, &sps_bam_addr_ops);
 	if (!dfile_bam_addr || IS_ERR(dfile_bam_addr)) {
@@ -427,6 +471,10 @@
 	return;
 
 bam_addr_err:
+	debugfs_remove(dfile_bam_pipe_sel);
+bam_pipe_sel_err:
+	debugfs_remove(dfile_testbus_sel);
+testbus_sel_err:
 	debugfs_remove(dfile_reg_dump_option);
 reg_dump_option_err:
 	debugfs_remove(dfile_print_limit_option);
@@ -452,6 +500,10 @@
 		debugfs_remove(dfile_print_limit_option);
 	if (dfile_reg_dump_option)
 		debugfs_remove(dfile_reg_dump_option);
+	if (dfile_testbus_sel)
+		debugfs_remove(dfile_testbus_sel);
+	if (dfile_bam_pipe_sel)
+		debugfs_remove(dfile_bam_pipe_sel);
 	if (dfile_bam_addr)
 		debugfs_remove(dfile_bam_addr);
 	if (dent)
@@ -462,7 +514,8 @@
 #endif
 
 /* Get the debug info of BAM registers and descriptor FIFOs */
-int sps_get_bam_debug_info(u32 dev, u32 option, u32 para)
+int sps_get_bam_debug_info(u32 dev, u32 option, u32 para,
+		u32 tb_sel, u8 pre_level)
 {
 	int res = 0;
 	struct sps_bam *bam;
@@ -545,6 +598,12 @@
 		print_bam_pipe_selected_reg(vir_addr, 5);
 		print_bam_pipe_desc_fifo(vir_addr, 5);
 		break;
+	case 13: /* output BAM_TEST_BUS_REG */
+		if (tb_sel)
+			print_bam_test_bus_reg(vir_addr, tb_sel);
+		else
+			pr_info("sps:TEST_BUS_SEL should NOT be zero.");
+		break;
 	default:
 		pr_info("sps:no option is chosen yet.");
 	}
diff --git a/drivers/platform/msm/sps/sps_bam.c b/drivers/platform/msm/sps/sps_bam.c
index 245ccd2..f671ece 100644
--- a/drivers/platform/msm/sps/sps_bam.c
+++ b/drivers/platform/msm/sps/sps_bam.c
@@ -254,7 +254,8 @@
 				  dev->props.ee,
 				  (u16) dev->props.summing_threshold,
 				  irq_mask,
-				  &dev->version, &num_pipes);
+				  &dev->version, &num_pipes,
+				  dev->props.options & SPS_BAM_NO_EXT_P_RST);
 	else
 		/* No, so just verify that it is enabled */
 		rc = bam_check(dev->base, &dev->version, &num_pipes);
@@ -401,7 +402,7 @@
 	}
 
 	dev->state |= BAM_STATE_ENABLED;
-	SPS_DBG2("sps:BAM 0x%x enabled: ver: %d, number of pipes: %d",
+	SPS_INFO("sps:BAM 0x%x enabled: ver:0x%x, number of pipes:%d",
 		BAM_ID(dev), dev->version, dev->props.num_pipes);
 	return 0;
 }
@@ -1368,8 +1369,8 @@
 	}
 
 	if (event_reg->callback) {
-		event_reg->callback(&sps_event->notify);
 		SPS_DBG("sps:trigger_event.using callback.");
+		event_reg->callback(&sps_event->notify);
 	}
 
 }
diff --git a/drivers/platform/msm/sps/spsi.h b/drivers/platform/msm/sps/spsi.h
index 43a50bd..8a5deff 100644
--- a/drivers/platform/msm/sps/spsi.h
+++ b/drivers/platform/msm/sps/spsi.h
@@ -200,6 +200,9 @@
 /* output descriptor FIFO of a pipe */
 void print_bam_pipe_desc_fifo(void *, u32);
 
+/* output BAM_TEST_BUS_REG */
+void print_bam_test_bus_reg(void *, u32);
+
 /**
  * Translate physical to virtual address
  *
diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index b7c73de..551c0a7 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -15,6 +15,7 @@
 #include <linux/list.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
+#include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/stat.h>
 #include <linux/module.h>
@@ -23,6 +24,7 @@
 #include <mach/usb_bam.h>
 #include <mach/sps.h>
 #include <linux/workqueue.h>
+#include <linux/dma-mapping.h>
 
 #define USB_SUMMING_THRESHOLD 512
 #define CONNECTIONS_NUM	4
@@ -53,26 +55,22 @@
 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;
-}
+void __iomem *qscratch_ram1_reg;
+struct clk *mem_clk;
+struct clk *mem_iface_clk;
 
 static int connect_pipe(u8 conn_idx, enum usb_bam_pipe_dir pipe_dir,
 						u32 *usb_pipe_idx)
 {
-	int ret;
+	int ret, ram1_value;
 	struct sps_pipe **pipe = &sps_pipes[conn_idx][pipe_dir];
 	struct sps_connect *connection =
 		&sps_connections[conn_idx][pipe_dir];
 	struct msm_usb_bam_platform_data *pdata =
 		usb_bam_pdev->dev.platform_data;
 	struct usb_bam_pipe_connect *pipe_connection =
-		(struct usb_bam_pipe_connect *)(pdata->connections +
-			 bam_offset(pdata) + (2*conn_idx+pipe_dir));
+				&msm_usb_bam_connections_info
+				[pdata->usb_active_bam][conn_idx][pipe_dir];
 
 	*pipe = sps_alloc_endpoint();
 	if (*pipe == NULL) {
@@ -83,13 +81,13 @@
 	ret = sps_get_config(*pipe, connection);
 	if (ret) {
 		pr_err("%s: tx get config failed %d\n", __func__, ret);
-		goto get_config_failed;
+		goto free_sps_endpoint;
 	}
 
 	ret = sps_phy2h(pipe_connection->src_phy_addr, &(connection->source));
 	if (ret) {
 		pr_err("%s: sps_phy2h failed (src BAM) %d\n", __func__, ret);
-		goto get_config_failed;
+		goto free_sps_endpoint;
 	}
 
 	connection->src_pipe_index = pipe_connection->src_pipe_index;
@@ -97,7 +95,7 @@
 					&(connection->destination));
 	if (ret) {
 		pr_err("%s: sps_phy2h failed (dst BAM) %d\n", __func__, ret);
-		goto get_config_failed;
+		goto free_sps_endpoint;
 	}
 	connection->dest_pipe_index = pipe_connection->dst_pipe_index;
 
@@ -109,7 +107,9 @@
 		*usb_pipe_idx = connection->dest_pipe_index;
 	}
 
-	if (!device_tree_enabled) {
+	/* If BAM is using dedicated SPS pipe memory, get it */
+	if (pipe_connection->mem_type == SPS_PIPE_MEM) {
+		pr_debug("%s: USB BAM using SPS pipe memory\n", __func__);
 		ret = sps_setup_bam2bam_fifo(
 				&data_mem_buf[conn_idx][pipe_dir],
 				pipe_connection->data_fifo_base_offset,
@@ -117,7 +117,7 @@
 		if (ret) {
 			pr_err("%s: data fifo setup failure %d\n", __func__,
 				ret);
-			goto fifo_setup_error;
+			goto free_sps_endpoint;
 		}
 
 		ret = sps_setup_bam2bam_fifo(
@@ -127,9 +127,33 @@
 		if (ret) {
 			pr_err("%s: desc. fifo setup failure %d\n", __func__,
 				ret);
-			goto fifo_setup_error;
+			goto free_sps_endpoint;
 		}
-	} else {
+	} else if (pipe_connection->mem_type == USB_PRIVATE_MEM) {
+		pr_debug("%s: USB BAM using private memory\n", __func__);
+
+		if (IS_ERR(mem_clk) || IS_ERR(mem_iface_clk)) {
+			pr_err("%s: Failed to enable USB mem_clk\n", __func__);
+			ret = IS_ERR(mem_clk);
+			goto free_sps_endpoint;
+		}
+
+		clk_prepare_enable(mem_clk);
+		clk_prepare_enable(mem_iface_clk);
+
+		/*
+		 * Enable USB PRIVATE RAM to be used for BAM FIFOs
+		 * HSUSB: Only RAM13 is used for BAM FIFOs
+		 * SSUSB: RAM11, 12, 13 are used for BAM FIFOs
+		 */
+		if (pdata->usb_active_bam == HSUSB_BAM)
+			ram1_value = 0x4;
+		else
+			ram1_value = 0x7;
+
+		pr_debug("Writing 0x%x to QSCRATCH_RAM1\n", ram1_value);
+		writel_relaxed(ram1_value, qscratch_ram1_reg);
+
 		data_mem_buf[conn_idx][pipe_dir].phys_base =
 			pipe_connection->data_fifo_base_offset +
 				pdata->usb_base_address;
@@ -151,6 +175,28 @@
 				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);
+	} else {
+		pr_debug("%s: USB BAM using system memory\n", __func__);
+		/* BAM would use system memory, allocate FIFOs */
+		data_mem_buf[conn_idx][pipe_dir].size =
+					pipe_connection->data_fifo_size;
+		data_mem_buf[conn_idx][pipe_dir].base =
+			dma_alloc_coherent(&usb_bam_pdev->dev,
+				    pipe_connection->data_fifo_size,
+				    &data_mem_buf[conn_idx][pipe_dir].phys_base,
+				    0);
+		memset(data_mem_buf[conn_idx][pipe_dir].base, 0,
+					pipe_connection->data_fifo_size);
+
+		desc_mem_buf[conn_idx][pipe_dir].size =
+					pipe_connection->desc_fifo_size;
+		desc_mem_buf[conn_idx][pipe_dir].base =
+			dma_alloc_coherent(&usb_bam_pdev->dev,
+				    pipe_connection->desc_fifo_size,
+				    &desc_mem_buf[conn_idx][pipe_dir].phys_base,
+				    0);
+		memset(desc_mem_buf[conn_idx][pipe_dir].base, 0,
+					pipe_connection->desc_fifo_size);
 	}
 
 	connection->data = data_mem_buf[conn_idx][pipe_dir];
@@ -167,8 +213,7 @@
 
 error:
 	sps_disconnect(*pipe);
-fifo_setup_error:
-get_config_failed:
+free_sps_endpoint:
 	sps_free_endpoint(*pipe);
 	return ret;
 }
@@ -177,6 +222,11 @@
 static int disconnect_pipe(u8 connection_idx, enum usb_bam_pipe_dir pipe_dir,
 						u32 *usb_pipe_idx)
 {
+	struct msm_usb_bam_platform_data *pdata =
+				usb_bam_pdev->dev.platform_data;
+	struct usb_bam_pipe_connect *pipe_connection =
+			&msm_usb_bam_connections_info
+			[pdata->usb_active_bam][connection_idx][pipe_dir];
 	struct sps_pipe *pipe = sps_pipes[connection_idx][pipe_dir];
 	struct sps_connect *connection =
 		&sps_connections[connection_idx][pipe_dir];
@@ -184,6 +234,21 @@
 	sps_disconnect(pipe);
 	sps_free_endpoint(pipe);
 
+	if (pipe_connection->mem_type == SYSTEM_MEM) {
+		pr_debug("%s: Freeing system memory used by PIPE\n", __func__);
+		dma_free_coherent(&usb_bam_pdev->dev, connection->data.size,
+			  connection->data.base, connection->data.phys_base);
+		dma_free_coherent(&usb_bam_pdev->dev, connection->desc.size,
+			  connection->desc.base, connection->desc.phys_base);
+	} else if (pipe_connection->mem_type == USB_PRIVATE_MEM) {
+		pr_debug("Freeing USB private memory used by BAM PIPE\n");
+		writel_relaxed(0x0, qscratch_ram1_reg);
+		iounmap(connection->data.base);
+		iounmap(connection->desc.base);
+		clk_disable_unprepare(mem_clk);
+		clk_disable_unprepare(mem_iface_clk);
+	}
+
 	connection->options &= ~SPS_O_AUTO_ENABLE;
 	return 0;
 }
@@ -328,7 +393,7 @@
 }
 
 static int update_connections_info(struct device_node *node, int bam,
-	int conn_num, int dir)
+	int conn_num, int dir, enum usb_pipe_mem_type mem_type)
 {
 	u32 rc;
 	char *key = NULL;
@@ -338,6 +403,8 @@
 
 	pipe_connection = &msm_usb_bam_connections_info[bam][conn_num][dir];
 
+	pipe_connection->mem_type = mem_type;
+
 	key = "qcom,src-bam-physical-address";
 	rc = of_property_read_u32(node, key, &val);
 	if (rc)
@@ -394,18 +461,49 @@
 	return -EFAULT;
 }
 
+static int usb_bam_update_conn_array_index(struct platform_device *pdev,
+		void *buff, int bam_max, int conn_max, int pipe_dirs)
+{
+	int bam_num, conn_num;
+	struct usb_bam_pipe_connect *bam_connection_arr = buff;
+
+	msm_usb_bam_connections_info = devm_kzalloc(&pdev->dev,
+		bam_max * sizeof(struct usb_bam_pipe_connect **),
+		GFP_KERNEL);
+
+	if (!msm_usb_bam_connections_info)
+		return -ENOMEM;
+
+	for (bam_num = 0; bam_num < bam_max; bam_num++) {
+		msm_usb_bam_connections_info[bam_num] =
+			devm_kzalloc(&pdev->dev, conn_max *
+			sizeof(struct usb_bam_pipe_connect *),
+			GFP_KERNEL);
+		if (!msm_usb_bam_connections_info[bam_num])
+			return -ENOMEM;
+
+		for (conn_num = 0; conn_num < conn_max; conn_num++)
+			msm_usb_bam_connections_info[bam_num][conn_num] =
+				bam_connection_arr +
+				(bam_num * conn_max * pipe_dirs) +
+				(conn_num * pipe_dirs);
+	}
+
+	return 0;
+}
+
 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;
+	enum usb_pipe_mem_type mem_type;
 
 	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
 	if (!pdata) {
@@ -441,6 +539,9 @@
 		return NULL;
 	}
 
+	pdata->ignore_core_reset_ack = of_property_read_bool(node,
+					"qcom,ignore-core-reset-ack");
+
 	for_each_child_of_node(pdev->dev.of_node, node)
 		pipe_entry++;
 
@@ -451,79 +552,79 @@
 	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 {
+	if (conn_num <= 0 || conn_num >= pdata->usb_bam_num_pipes)
 		goto err;
+
+
+	/* 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;
+
+	rc = usb_bam_update_conn_array_index(pdev, bam_connection_arr,
+					bam_amount, conn_num, ncolumns);
+	if (rc)
+		goto err;
+
+	/* 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;
+
+		key = "qcom,usb-bam-mem-type";
+		rc = of_property_read_u32(node, key, &mem_type);
+		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;
+
+		/* Check if connection type is suported */
+		if (!strcmp(str, "usb-to-peri-qdss-dwc3") ||
+			!strcmp(str, "peri-to-usb-qdss-dwc3") ||
+			!strcmp(str, "usb-to-peri-qdss-hsusb") ||
+			!strcmp(str, "peri-to-usb-qdss-hsusb"))
+				conn_num = 0;
+		else
+			goto err;
+
+		rc = update_connections_info(node, bam, conn_num,
+						dir, mem_type);
+		if (rc)
+			goto err;
 	}
 
+	pdata->connections = &msm_usb_bam_connections_info[0][0][0];
+
 	return pdata;
 err:
 	pr_err("%s: failed\n", __func__);
 	return NULL;
 }
 
+static char *bam_enable_strings[3] = {
+	[SSUSB_BAM] = "ssusb",
+	[HSUSB_BAM] = "hsusb",
+	[HSIC_BAM]  = "hsic",
+};
+
 static int usb_bam_init(void)
 {
 	u32 h_usb;
@@ -531,27 +632,54 @@
 	void *usb_virt_addr;
 	struct msm_usb_bam_platform_data *pdata =
 		usb_bam_pdev->dev.platform_data;
-	struct resource *res;
+	struct usb_bam_pipe_connect *pipe_connection =
+		&msm_usb_bam_connections_info[pdata->usb_active_bam][0][0];
+	struct resource *res, *ram_resource;
 	int irq;
 
-	res = platform_get_resource(usb_bam_pdev, IORESOURCE_MEM,
-		pdata->usb_active_bam);
+	res = platform_get_resource_byname(usb_bam_pdev, IORESOURCE_MEM,
+				bam_enable_strings[pdata->usb_active_bam]);
 	if (!res) {
 		dev_err(&usb_bam_pdev->dev, "Unable to get memory resource\n");
 		return -ENODEV;
 	}
 
-	irq = platform_get_irq(usb_bam_pdev, pdata->usb_active_bam);
+	irq = platform_get_irq_byname(usb_bam_pdev,
+				bam_enable_strings[pdata->usb_active_bam]);
 	if (irq < 0) {
 		dev_err(&usb_bam_pdev->dev, "Unable to get IRQ resource\n");
 		return irq;
 	}
 
-	usb_virt_addr = ioremap(res->start, resource_size(res));
+	usb_virt_addr = devm_ioremap(&usb_bam_pdev->dev, res->start,
+							 resource_size(res));
 	if (!usb_virt_addr) {
 		pr_err("%s: ioremap failed\n", __func__);
 		return -ENOMEM;
 	}
+
+	/* Check if USB3 pipe memory needs to be enabled */
+	if (pipe_connection->mem_type == USB_PRIVATE_MEM) {
+		pr_debug("%s: Enabling USB private memory for: %s\n", __func__,
+				bam_enable_strings[pdata->usb_active_bam]);
+
+		ram_resource = platform_get_resource_byname(usb_bam_pdev,
+					 IORESOURCE_MEM, "qscratch_ram1_reg");
+		if (!res) {
+			dev_err(&usb_bam_pdev->dev, "Unable to get qscratch\n");
+			ret = -ENODEV;
+			goto free_bam_regs;
+		}
+
+		qscratch_ram1_reg = devm_ioremap(&usb_bam_pdev->dev,
+						ram_resource->start,
+						resource_size(ram_resource));
+		if (!qscratch_ram1_reg) {
+			pr_err("%s: ioremap failed for qscratch\n", __func__);
+			ret = -ENOMEM;
+			goto free_bam_regs;
+		}
+	}
 	usb_props.phys_addr = res->start;
 	usb_props.virt_addr = usb_virt_addr;
 	usb_props.virt_size = resource_size(res);
@@ -559,20 +687,29 @@
 	usb_props.summing_threshold = USB_SUMMING_THRESHOLD;
 	usb_props.event_threshold = 512;
 	usb_props.num_pipes = pdata->usb_bam_num_pipes;
+	/*
+	 * HSUSB and HSIC Cores don't support RESET ACK signal to BAMs
+	 * Hence, let BAM to ignore acknowledge from USB while resetting PIPE
+	 */
+	if (pdata->ignore_core_reset_ack && pdata->usb_active_bam != SSUSB_BAM)
+		usb_props.options = SPS_BAM_NO_EXT_P_RST;
 
 	ret = sps_register_bam_device(&usb_props, &h_usb);
 	if (ret < 0) {
 		pr_err("%s: register bam error %d\n", __func__, ret);
-		return -EFAULT;
+		ret = -EFAULT;
+		goto free_qscratch_reg;
 	}
 
 	return 0;
-}
 
-static char *bam_enable_strings[2] = {
-	[HSUSB_BAM] = "hsusb",
-	[HSIC_BAM]  = "hsic",
-};
+free_qscratch_reg:
+	iounmap(qscratch_ram1_reg);
+free_bam_regs:
+	iounmap(usb_virt_addr);
+
+	return ret;
+}
 
 static ssize_t
 usb_bam_show_enable(struct device *dev, struct device_attribute *attr,
@@ -636,9 +773,16 @@
 			usb_bam_wake_work);
 	}
 
+	mem_clk = devm_clk_get(&pdev->dev, "mem_clk");
+	if (IS_ERR(mem_clk))
+		dev_dbg(&pdev->dev, "failed to get mem_clock\n");
+
+	mem_iface_clk = devm_clk_get(&pdev->dev, "mem_iface_clk");
+	if (IS_ERR(mem_iface_clk))
+		dev_dbg(&pdev->dev, "failed to get mem_iface_clock\n");
+
 	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;
@@ -648,7 +792,12 @@
 		return -ENODEV;
 	} else {
 		pdata = pdev->dev.platform_data;
-		device_tree_enabled = 0;
+		ret = usb_bam_update_conn_array_index(pdev, pdata->connections,
+				MAX_BAMS, CONNECTIONS_NUM, 2);
+		if (ret) {
+			pr_err("usb_bam_update_conn_array_index failed\n");
+			return ret;
+		}
 	}
 	usb_bam_pdev = pdev;
 
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index a263750..d8baa29 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -415,6 +415,14 @@
 	help
 	  Say Y here to enable support for pm8921 chip bms subdevice
 
+config BATTERY_BCL
+	tristate "Battery Current Limit driver"
+	help
+	  Say Y here to enable support for battery current limit
+	  device. The BCL driver will poll BMS if
+	  thermal daemon enables BCL.
+	  It will notify thermal daemon if IBat crosses Imax threshold.
+
 config CHARGER_SMB347
 	tristate "Summit Microelectronics SMB347 Battery Charger"
 	depends on I2C
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index 007d75b..f84b527 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -58,3 +58,4 @@
 obj-$(CONFIG_PM8921_CHARGER)	+= pm8921-charger.o
 obj-$(CONFIG_LTC4088_CHARGER)	+= ltc4088-charger.o
 obj-$(CONFIG_CHARGER_SMB347)	+= smb347-charger.o
+obj-$(CONFIG_BATTERY_BCL)	+= battery_current_limit.o
diff --git a/drivers/power/battery_current_limit.c b/drivers/power/battery_current_limit.c
new file mode 100644
index 0000000..d1750ec
--- /dev/null
+++ b/drivers/power/battery_current_limit.c
@@ -0,0 +1,534 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/power_supply.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+
+#define BCL_DEV_NAME "battery_current_limit"
+#define BCL_NAME_LENGTH 20
+/*
+ * Default BCL poll interval 1000 msec
+ */
+#define BCL_POLL_INTERVAL 1000
+/*
+ * Mininum BCL poll interval 10 msec
+ */
+#define MIN_BCL_POLL_INTERVAL 10
+
+static const char bcl_type[] = "bcl";
+
+/*
+ * Battery Current Limit Enable or Not
+ */
+enum bcl_device_mode {
+	BCL_DEVICE_DISABLED = 0,
+	BCL_DEVICE_ENABLED,
+};
+
+/*
+ * Battery Current Limit IBat Imax Threshold Mode
+ */
+enum bcl_ibat_imax_threshold_mode {
+	BCL_IBAT_IMAX_THRESHOLD_DISABLED = 0,
+	BCL_IBAT_IMAX_THRESHOLD_ENABLED,
+};
+
+/*
+ * Battery Current Limit Ibat Imax Trip Type (High and Low Threshold)
+ */
+enum bcl_ibat_imax_threshold_type {
+	BCL_IBAT_IMAX_THRESHOLD_TYPE_LOW = 0,
+	BCL_IBAT_IMAX_THRESHOLD_TYPE_HIGH,
+	BCL_IBAT_IMAX_THRESHOLD_TYPE_MAX,
+};
+
+/**
+ * BCL control block
+ *
+ */
+struct bcl_context {
+	/* BCL device */
+	struct device *dev;
+
+	/* BCL related config parameter */
+	/* BCL mode enable or not */
+	enum bcl_device_mode bcl_mode;
+	/* BCL Ibat/IMax Threshold Activate or Not */
+	enum bcl_ibat_imax_threshold_mode
+		bcl_threshold_mode[BCL_IBAT_IMAX_THRESHOLD_TYPE_MAX];
+	/* BCL Ibat/IMax Threshold value in milli Amp */
+	int bcl_threshold_value_ma[BCL_IBAT_IMAX_THRESHOLD_TYPE_MAX];
+	/* BCL Type */
+	char bcl_type[BCL_NAME_LENGTH];
+	/* BCL poll in usec */
+	int bcl_poll_interval_msec;
+
+	/* BCL realtime value based on poll */
+	/* BCL realtime ibat in milli Amp*/
+	int bcl_ibat_ma;
+	/* BCL realtime calculated imax in milli Amp*/
+	int bcl_imax_ma;
+	/* BCL realtime calculated ocv in uV*/
+	int bcl_ocv_uv;
+	/* BCL realtime vbat in mV*/
+	int bcl_vbat_mv;
+	/* BCL realtime rbat in mOhms*/
+	int bcl_rbat;
+	/* BCL period poll delay work structure  */
+	struct delayed_work     bcl_imax_work;
+
+};
+
+static struct bcl_context *gbcl;
+
+/*
+ * BCL imax calculation and trigger notification to user space
+ * if imax cross threshold
+ */
+static void bcl_calculate_imax_trigger(void)
+{
+	int ibatt_ua, vbatt_uv;
+	int imax_ma;
+	int ibatt_ma, vbatt_mv;
+	int imax_low_threshold;
+	int imax_high_threshold;
+	bool threshold_cross = false;
+	union power_supply_propval ret = {0,};
+	static struct power_supply *psy;
+
+	if (!gbcl) {
+		pr_err("called before initialization\n");
+		return;
+	}
+
+	if (psy == NULL) {
+		psy = power_supply_get_by_name("battery");
+		if (psy == NULL)
+			return;
+	}
+
+	if (psy->get_property(psy, POWER_SUPPLY_PROP_CURRENT_NOW, &ret))
+		return;
+	ibatt_ua = ret.intval;
+
+	if (psy->get_property(psy, POWER_SUPPLY_PROP_VOLTAGE_NOW, &ret))
+		return;
+	vbatt_uv = ret.intval;
+
+	if (psy->get_property(psy, POWER_SUPPLY_PROP_CURRENT_MAX, &ret))
+		return;
+	imax_ma = ret.intval/1000;
+
+	ibatt_ma = ibatt_ua/1000;
+	vbatt_mv = vbatt_uv/1000;
+
+	gbcl->bcl_ibat_ma = ibatt_ma;
+	gbcl->bcl_imax_ma = imax_ma;
+	gbcl->bcl_vbat_mv = vbatt_mv;
+
+	if (gbcl->bcl_threshold_mode[BCL_IBAT_IMAX_THRESHOLD_TYPE_HIGH]
+		== BCL_IBAT_IMAX_THRESHOLD_ENABLED) {
+		imax_high_threshold =
+		imax_ma - gbcl->bcl_threshold_value_ma
+			[BCL_IBAT_IMAX_THRESHOLD_TYPE_HIGH];
+		if (ibatt_ma >= imax_high_threshold)
+			threshold_cross = true;
+	}
+
+	if (gbcl->bcl_threshold_mode[BCL_IBAT_IMAX_THRESHOLD_TYPE_LOW]
+		== BCL_IBAT_IMAX_THRESHOLD_ENABLED) {
+		imax_low_threshold =
+		imax_ma - gbcl->bcl_threshold_value_ma
+			[BCL_IBAT_IMAX_THRESHOLD_TYPE_LOW];
+		if (ibatt_ma <= imax_low_threshold)
+			threshold_cross = true;
+	}
+
+	if (threshold_cross) {
+		sysfs_notify(&gbcl->dev->kobj,
+				NULL, "type");
+	}
+}
+
+/*
+ * BCL imax work
+ */
+static void bcl_imax_work(struct work_struct *work)
+{
+	struct bcl_context *bcl = container_of(work,
+			struct bcl_context, bcl_imax_work.work);
+
+	if (gbcl->bcl_mode == BCL_DEVICE_ENABLED) {
+		bcl_calculate_imax_trigger();
+		/* restart the delay work for caculating imax */
+		schedule_delayed_work(&bcl->bcl_imax_work,
+			round_jiffies_relative(msecs_to_jiffies
+				(bcl->bcl_poll_interval_msec)));
+	}
+}
+
+/*
+ * Set BCL mode
+ */
+static void bcl_mode_set(enum bcl_device_mode mode)
+{
+	if (!gbcl)
+		return;
+
+	if (gbcl->bcl_mode == mode)
+		return;
+
+	if (gbcl->bcl_mode == BCL_DEVICE_DISABLED
+		&& mode == BCL_DEVICE_ENABLED) {
+		gbcl->bcl_mode = mode;
+		bcl_imax_work(&(gbcl->bcl_imax_work.work));
+		return;
+	} else if (gbcl->bcl_mode == BCL_DEVICE_ENABLED
+		&& mode == BCL_DEVICE_DISABLED) {
+		gbcl->bcl_mode = mode;
+		cancel_delayed_work_sync(&(gbcl->bcl_imax_work));
+		return;
+	}
+
+	return;
+}
+
+#define show_bcl(name, variable, format) \
+static ssize_t \
+name##_show(struct device *dev, struct device_attribute *attr, char *buf) \
+{ \
+	if (gbcl) \
+		return snprintf(buf, PAGE_SIZE, format, gbcl->variable); \
+	else \
+		return  -EPERM; \
+}
+
+show_bcl(type, bcl_type, "%s\n")
+show_bcl(ibat, bcl_ibat_ma, "%d\n")
+show_bcl(imax, bcl_imax_ma, "%d\n")
+show_bcl(vbat, bcl_vbat_mv, "%d\n")
+show_bcl(rbat, bcl_rbat, "%d\n")
+show_bcl(ocv, bcl_ocv_uv, "%d\n")
+show_bcl(poll_interval, bcl_poll_interval_msec, "%d\n")
+
+static ssize_t
+mode_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	if (!gbcl)
+		return -EPERM;
+
+	return snprintf(buf, PAGE_SIZE, "%s\n",
+		gbcl->bcl_mode == BCL_DEVICE_ENABLED ? "enabled"
+			: "disabled");
+}
+
+static ssize_t
+mode_store(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	if (!gbcl)
+		return -EPERM;
+
+	if (!strncmp(buf, "enabled", 7))
+		bcl_mode_set(BCL_DEVICE_ENABLED);
+	else if (!strncmp(buf, "disabled", 8))
+		bcl_mode_set(BCL_DEVICE_DISABLED);
+	else
+		return -EINVAL;
+
+	return count;
+}
+
+static ssize_t
+ibat_imax_low_threshold_mode_show(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	if (!gbcl)
+		return -EPERM;
+
+	return snprintf(buf, PAGE_SIZE, "%s\n",
+		gbcl->bcl_threshold_mode[BCL_IBAT_IMAX_THRESHOLD_TYPE_LOW]
+		== BCL_IBAT_IMAX_THRESHOLD_ENABLED ? "enabled" : "disabled");
+}
+
+static ssize_t
+ibat_imax_low_threshold_mode_store(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	if (!gbcl)
+		return -EPERM;
+
+	if (!strncmp(buf, "enabled", 7))
+		gbcl->bcl_threshold_mode[BCL_IBAT_IMAX_THRESHOLD_TYPE_LOW]
+			= BCL_IBAT_IMAX_THRESHOLD_ENABLED;
+	else if (!strncmp(buf, "disabled", 8))
+		gbcl->bcl_threshold_mode[BCL_IBAT_IMAX_THRESHOLD_TYPE_LOW]
+			= BCL_IBAT_IMAX_THRESHOLD_DISABLED;
+	else
+		return -EINVAL;
+
+	return count;
+}
+
+static ssize_t
+ibat_imax_low_threshold_value_show(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	if (!gbcl)
+		return -EPERM;
+
+	return snprintf(buf, PAGE_SIZE, "%d\n",
+	gbcl->bcl_threshold_value_ma[BCL_IBAT_IMAX_THRESHOLD_TYPE_LOW]);
+}
+
+static ssize_t
+ibat_imax_low_threshold_value_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	int value;
+
+	if (!gbcl)
+		return -EPERM;
+
+	if (!sscanf(buf, "%d", &value))
+		return -EINVAL;
+
+	if (value < 0)
+		return -EINVAL;
+
+	gbcl->bcl_threshold_value_ma[BCL_IBAT_IMAX_THRESHOLD_TYPE_LOW]
+			= value;
+
+	return count;
+}
+
+static ssize_t
+ibat_imax_high_threshold_mode_show(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	if (!gbcl)
+		return -EPERM;
+
+	return snprintf(buf, PAGE_SIZE, "%s\n",
+		gbcl->bcl_threshold_mode[BCL_IBAT_IMAX_THRESHOLD_TYPE_HIGH]
+		== BCL_IBAT_IMAX_THRESHOLD_ENABLED ? "enabled" : "disabled");
+}
+
+static ssize_t
+ibat_imax_high_threshold_mode_store(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	if (!gbcl)
+		return -EPERM;
+
+	if (!strncmp(buf, "enabled", 7))
+		gbcl->bcl_threshold_mode[BCL_IBAT_IMAX_THRESHOLD_TYPE_HIGH]
+		= BCL_IBAT_IMAX_THRESHOLD_ENABLED;
+	else if (!strncmp(buf, "disabled", 8))
+		gbcl->bcl_threshold_mode[BCL_IBAT_IMAX_THRESHOLD_TYPE_HIGH]
+		= BCL_IBAT_IMAX_THRESHOLD_DISABLED;
+	else
+		return -EINVAL;
+
+	return count;
+}
+
+static ssize_t
+ibat_imax_high_threshold_value_show(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	if (!gbcl)
+		return -EPERM;
+
+	return snprintf(buf, PAGE_SIZE, "%d\n",
+	gbcl->bcl_threshold_value_ma[BCL_IBAT_IMAX_THRESHOLD_TYPE_HIGH]);
+}
+
+static ssize_t
+ibat_imax_high_threshold_value_store(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	int value;
+
+	if (!gbcl)
+		return -EPERM;
+
+	if (!sscanf(buf, "%d", &value))
+		return -EINVAL;
+
+	if (value < 0)
+		return -EINVAL;
+
+	gbcl->bcl_threshold_value_ma[BCL_IBAT_IMAX_THRESHOLD_TYPE_HIGH]
+		= value;
+
+	return count;
+}
+
+static ssize_t
+poll_interval_store(struct device *dev,
+			struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	int value;
+
+	if (!gbcl)
+		return -EPERM;
+
+	if (!sscanf(buf, "%d", &value))
+		return -EINVAL;
+
+	if (value < MIN_BCL_POLL_INTERVAL)
+		return -EINVAL;
+
+	gbcl->bcl_poll_interval_msec = value;
+
+	return count;
+}
+
+/*
+ * BCL device attributes
+ */
+static struct device_attribute bcl_dev_attr[] = {
+	__ATTR(type, 0444, type_show, NULL),
+	__ATTR(ibat, 0444, ibat_show, NULL),
+	__ATTR(vbat, 0444, vbat_show, NULL),
+	__ATTR(rbat, 0444, rbat_show, NULL),
+	__ATTR(ocv, 0444, ocv_show, NULL),
+	__ATTR(imax, 0444, imax_show, NULL),
+	__ATTR(mode, 0644, mode_show, mode_store),
+	__ATTR(poll_interval, 0644,
+		poll_interval_show, poll_interval_store),
+	__ATTR(ibat_imax_low_threshold_mode, 0644,
+		ibat_imax_low_threshold_mode_show,
+		ibat_imax_low_threshold_mode_store),
+	__ATTR(ibat_imax_high_threshold_mode, 0644,
+		ibat_imax_high_threshold_mode_show,
+		ibat_imax_high_threshold_mode_store),
+	__ATTR(ibat_imax_low_threshold_value, 0644,
+		ibat_imax_low_threshold_value_show,
+		ibat_imax_low_threshold_value_store),
+	__ATTR(ibat_imax_high_threshold_value, 0644,
+		ibat_imax_high_threshold_value_show,
+		ibat_imax_high_threshold_value_store)
+};
+
+static int create_bcl_sysfs(struct bcl_context *bcl)
+{
+	int result = 0;
+	int num_attr = sizeof(bcl_dev_attr)/sizeof(struct device_attribute);
+	int i;
+
+	for (i = 0; i < num_attr; i++) {
+		result = device_create_file(bcl->dev, &bcl_dev_attr[i]);
+		if (result < 0)
+			return result;
+	}
+
+	return 0;
+}
+
+static void remove_bcl_sysfs(struct bcl_context *bcl)
+{
+	int num_attr = sizeof(bcl_dev_attr)/sizeof(struct device_attribute);
+	int i;
+
+	for (i = 0; i < num_attr; i++)
+		device_remove_file(bcl->dev, &bcl_dev_attr[i]);
+
+	return;
+}
+
+static int __devinit bcl_probe(struct platform_device *pdev)
+{
+	struct bcl_context *bcl;
+	int ret = 0;
+
+	bcl = kzalloc(sizeof(struct bcl_context), GFP_KERNEL);
+
+	if (!bcl) {
+		pr_err("Cannot allocate bcl_context\n");
+		return -ENOMEM;
+	}
+
+	gbcl = bcl;
+
+	/* For BCL */
+	/* Init default BCL params */
+	bcl->dev = &pdev->dev;
+	bcl->bcl_mode = BCL_DEVICE_DISABLED;
+	bcl->bcl_threshold_mode[BCL_IBAT_IMAX_THRESHOLD_TYPE_LOW]
+		= BCL_IBAT_IMAX_THRESHOLD_DISABLED;
+	bcl->bcl_threshold_mode[BCL_IBAT_IMAX_THRESHOLD_TYPE_HIGH]
+		= BCL_IBAT_IMAX_THRESHOLD_DISABLED;
+	bcl->bcl_threshold_value_ma[BCL_IBAT_IMAX_THRESHOLD_TYPE_LOW] = 0;
+	bcl->bcl_threshold_value_ma[BCL_IBAT_IMAX_THRESHOLD_TYPE_HIGH] = 0;
+	snprintf(bcl->bcl_type, BCL_NAME_LENGTH, "%s", bcl_type);
+	bcl->bcl_poll_interval_msec = BCL_POLL_INTERVAL;
+	ret = create_bcl_sysfs(bcl);
+	if (ret < 0) {
+		pr_err("Cannot create bcl sysfs\n");
+		kfree(bcl);
+		return ret;
+	}
+	platform_set_drvdata(pdev, bcl);
+	INIT_DELAYED_WORK(&bcl->bcl_imax_work, bcl_imax_work);
+
+	return 0;
+}
+
+static int __devexit bcl_remove(struct platform_device *pdev)
+{
+	remove_bcl_sysfs(gbcl);
+	kfree(gbcl);
+	gbcl = NULL;
+	platform_set_drvdata(pdev, NULL);
+	return 0;
+}
+
+static struct platform_driver bcl_driver = {
+	.probe	= bcl_probe,
+	.remove	= __devexit_p(bcl_remove),
+	.driver	= {
+		.name	= BCL_DEV_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init bcl_init(void)
+{
+	return platform_driver_register(&bcl_driver);
+}
+
+static void __exit bcl_exit(void)
+{
+	platform_driver_unregister(&bcl_driver);
+}
+
+late_initcall(bcl_init);
+module_exit(bcl_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("battery current limit driver");
+MODULE_ALIAS("platform:" BCL_DEV_NAME);
diff --git a/drivers/power/ltc4088-charger.c b/drivers/power/ltc4088-charger.c
index dbc75cd..58503cf 100644
--- a/drivers/power/ltc4088-charger.c
+++ b/drivers/power/ltc4088-charger.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
@@ -206,9 +206,11 @@
 	struct ltc4088_chg_chip *chip;
 
 	if (psy->type == POWER_SUPPLY_TYPE_USB) {
-		chip = container_of(psy, struct ltc4088_chg_chip,
-						usb_psy);
+		chip = container_of(psy, struct ltc4088_chg_chip, usb_psy);
 		switch (psp) {
+		case POWER_SUPPLY_PROP_TYPE:
+			psy.type = val->intval;
+			break;
 		case POWER_SUPPLY_PROP_ONLINE:
 			ltc4088_set_charging(chip, val->intval);
 			break;
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index 304dc6b..b3d31d5 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/interrupt.h>
 #include <linux/bitops.h>
@@ -27,6 +28,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
@@ -49,6 +51,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,
@@ -67,16 +72,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
@@ -92,8 +87,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;
@@ -102,6 +96,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;
@@ -119,29 +115,47 @@
 	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;
+
+	struct power_supply	*batt_psy;
 };
 
+/*
+ * 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;
 
@@ -157,7 +171,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;
@@ -175,7 +189,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);
 
 /*
@@ -335,21 +348,20 @@
 	return 0;
 }
 
-static int usb_chg_plugged_in(void)
+static int usb_chg_plugged_in(struct pm8921_bms_chip *chip)
 {
-	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;
+	/* if the charger driver was not initialized, use the restart reason */
+	if (val == -EINVAL) {
+		if (pm8xxx_restart_reason(chip->dev->parent)
+				== PM8XXX_RESTART_CHG)
+			val = 1;
+		else
+			val = 0;
 	}
 
-	if (psy->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &ret))
-		return 0;
-
-	return ret.intval;
+	return val;
 }
 
 #define HOLD_OREG_DATA		BIT(1)
@@ -483,8 +495,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 -
@@ -732,29 +744,103 @@
 	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)
+				int batt_temp_degc, int ocv)
 {
 	int i, j, pcj, pcj_minus_one, pc;
 	int rows = chip->pc_temp_ocv_lut->rows;
 	int cols = chip->pc_temp_ocv_lut->cols;
 
-	/* batt_temp is in tenths of degC - convert it to degC for lookups */
-	batt_temp = batt_temp/10;
 
-	if (batt_temp < chip->pc_temp_ocv_lut->temp[0]) {
-		pr_debug("batt_temp %d < known temp range for pc\n", batt_temp);
-		batt_temp = chip->pc_temp_ocv_lut->temp[0];
+	if (batt_temp_degc < chip->pc_temp_ocv_lut->temp[0]) {
+		pr_debug("batt_temp %d < known temp range\n", batt_temp_degc);
+		batt_temp_degc = chip->pc_temp_ocv_lut->temp[0];
 	}
-	if (batt_temp > chip->pc_temp_ocv_lut->temp[cols - 1]) {
-		pr_debug("batt_temp %d > known temp range for pc\n", batt_temp);
-		batt_temp = chip->pc_temp_ocv_lut->temp[cols - 1];
+	if (batt_temp_degc > chip->pc_temp_ocv_lut->temp[cols - 1]) {
+		pr_debug("batt_temp %d > known temp range\n", batt_temp_degc);
+		batt_temp_degc = chip->pc_temp_ocv_lut->temp[cols - 1];
 	}
 
 	for (j = 0; j < cols; j++)
-		if (batt_temp <= chip->pc_temp_ocv_lut->temp[j])
+		if (batt_temp_degc <= chip->pc_temp_ocv_lut->temp[j])
 			break;
-	if (batt_temp == chip->pc_temp_ocv_lut->temp[j]) {
+	if (batt_temp_degc == chip->pc_temp_ocv_lut->temp[j]) {
 		/* found an exact match for temp in the table */
 		if (ocv >= chip->pc_temp_ocv_lut->ocv[0][j])
 			return chip->pc_temp_ocv_lut->percent[0];
@@ -777,7 +863,7 @@
 	}
 
 	/*
-	 * batt_temp is within temperature for
+	 * batt_temp_degc is within temperature for
 	 * column j-1 and j
 	 */
 	if (ocv >= chip->pc_temp_ocv_lut->ocv[0][j])
@@ -817,7 +903,7 @@
 				chip->pc_temp_ocv_lut->temp[j-1],
 				pcj,
 				chip->pc_temp_ocv_lut->temp[j],
-				batt_temp);
+				batt_temp_degc);
 			return pc;
 		}
 	}
@@ -829,14 +915,14 @@
 		return pcj_minus_one;
 
 	pr_debug("%d ocv wasn't found for temp %d in the LUT returning 100%%",
-							ocv, batt_temp);
+							ocv, batt_temp_degc);
 	return 100;
 }
 
 #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;
@@ -844,11 +930,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);
@@ -868,7 +949,7 @@
 
 	mutex_unlock(&the_chip->bms_output_lock);
 
-	usb_chg = usb_chg_plugged_in();
+	usb_chg = usb_chg_plugged_in(the_chip);
 
 	convert_vbatt_raw_to_uv(the_chip, usb_chg, vbat_raw, vbat_uv);
 	convert_vsense_to_uv(the_chip, vsense_raw, &vsense_uv);
@@ -880,42 +961,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();
-	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,
@@ -945,7 +990,7 @@
 	pm_bms_unlock_output_data(chip);
 	mutex_unlock(&chip->bms_output_lock);
 
-	usb_chg =  usb_chg_plugged_in();
+	usb_chg =  usb_chg_plugged_in(chip);
 
 	if (chip->prev_last_good_ocv_raw == 0) {
 		chip->prev_last_good_ocv_raw = raw->last_good_ocv_raw;
@@ -953,6 +998,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,
@@ -988,7 +1034,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);
@@ -1017,27 +1063,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)
 {
@@ -1090,7 +1115,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;
 }
@@ -1100,7 +1125,7 @@
 {
 	int pc, scalefactor;
 
-	pc = interpolate_pc(chip, batt_temp, ocv_uv / 1000);
+	pc = interpolate_pc(chip, batt_temp / 10, ocv_uv / 1000);
 	pr_debug("pc = %u for ocv = %dmicroVolts batt_temp = %d\n",
 					pc, ocv_uv, batt_temp);
 
@@ -1141,185 +1166,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 */
@@ -1345,7 +1415,7 @@
 						int *cc_uah,
 						int *rbatt,
 						int *iavg_ua,
-						int *delta_time_us)
+						int *delta_time_s)
 {
 	int soc_rbatt;
 
@@ -1371,11 +1441,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);
 }
 
@@ -1390,7 +1461,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,
@@ -1399,7 +1470,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;
@@ -1408,6 +1479,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);
@@ -1415,9 +1587,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;
@@ -1427,23 +1663,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)
@@ -1477,6 +1737,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)
@@ -1501,78 +1773,161 @@
 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;
+	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;
+
+	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;
 }
-EXPORT_SYMBOL(pm8921_bms_invalidate_shutdown_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;
+}
+
+static void update_power_supply(struct pm8921_bms_chip *chip)
+{
+	if (chip->batt_psy == NULL || chip->batt_psy < 0)
+		chip->batt_psy = power_supply_get_by_name("battery");
+
+	if (chip->batt_psy > 0)
+		power_supply_changed(chip->batt_psy);
+}
 
 /*
  * Remaining Usable Charge = remaining_charge (charge at ocv instance)
@@ -1588,9 +1943,15 @@
 	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;
+	int new_calculated_soc;
+	static int firsttime = 1;
 
 	calculate_soc_params(chip, raw, batt_temp, chargecycles,
 						&fcc_uah,
@@ -1599,7 +1960,7 @@
 						&cc_uah,
 						&rbatt,
 						&iavg_ua,
-						&delta_time_us);
+						&delta_time_s);
 
 	/* calculate remaining usable charge */
 	remaining_usable_charge_uah = remaining_charge_uah
@@ -1612,18 +1973,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);
-		return bms_fake_battery;
-	}
 
 	if (soc < 0) {
 		pr_err("bad rem_usb_chg = %d rem_chg %d,"
@@ -1640,30 +2026,219 @@
 		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);
+	new_calculated_soc = adjust_soc(chip, soc, batt_temp, chargecycles,
+			rbatt, fcc_uah, unusable_charge_uah, cc_uah);
+
+	pr_debug("calculated SOC = %d\n", new_calculated_soc);
+	if (new_calculated_soc != calculated_soc)
+		update_power_supply(chip);
+
+	calculated_soc = new_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;
+
+	if (bms_fake_battery != -EINVAL) {
+		pr_debug("Returning Fake SOC = %d%%\n", bms_fake_battery);
+		return bms_fake_battery;
 	}
 
-	shutdown_adjusted_soc = adjust_for_shutdown_soc(chip, last_soc);
-	backup_soc(chip, shutdown_adjusted_soc);
+	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;
 
-	return shutdown_adjusted_soc;
+	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;
+	}
+
+	/*
+	 * 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;
+
+			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)
 {
@@ -1672,10 +2247,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);
 
@@ -1687,11 +2263,11 @@
 	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);
 
-	usb_chg = usb_chg_plugged_in();
+	usb_chg = usb_chg_plugged_in(chip);
 	pr_debug("result 0.625V = 0x%x, voltage = %duV adc_meas = %lld "
 				"usb_chg = %d\n",
 				result.adc_code, voltage, result.measurement,
@@ -1714,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)
@@ -1729,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;
@@ -1774,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);
 
@@ -1815,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");
@@ -1843,7 +2413,7 @@
 						&cc_uah,
 						&rbatt,
 						&iavg_ua,
-						&delta_time_us);
+						&delta_time_s);
 	mutex_unlock(&the_chip->last_ocv_uv_mutex);
 
 	return rbatt;
@@ -1881,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);
@@ -1971,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) {
@@ -1985,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);
 	}
@@ -2011,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);
 }
@@ -2157,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)
@@ -2277,7 +2754,7 @@
 	 */
 	ocv_uv = 0;
 	pm_bms_read_output_data(chip, LAST_GOOD_OCV_VALUE, &ocv_raw);
-	usb_chg = usb_chg_plugged_in();
+	usb_chg = usb_chg_plugged_in(chip);
 	rc = convert_vbatt_raw_to_uv(chip, usb_chg, ocv_raw, &ocv_uv);
 	if (rc || ocv_uv == 0) {
 		rc = adc_based_ocv(chip, &ocv_uv);
@@ -2359,7 +2836,6 @@
 }
 
 enum bms_request_operation {
-	CALC_RBATT,
 	CALC_FCC,
 	CALC_PC,
 	CALC_SOC,
@@ -2420,18 +2896,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);
@@ -2490,10 +2961,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;
 
@@ -2505,15 +2974,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;
@@ -2609,8 +3069,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,
@@ -2716,13 +3174,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);
@@ -2746,7 +3213,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) {
@@ -2760,7 +3234,7 @@
 		goto free_irqs;
 	}
 
-	read_shutdown_soc(chip);
+	read_shutdown_soc_and_iavg(chip);
 
 	platform_set_drvdata(pdev, chip);
 	the_chip = chip;
@@ -2773,20 +3247,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:
@@ -2814,7 +3288,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 85b653d..813e40a 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -270,7 +270,9 @@
 	int				rconn_mohm;
 	enum pm8921_chg_led_src_config	led_src_config;
 	bool				host_mode;
+	bool				has_dc_supply;
 	u8				active_path;
+	int				recent_reported_soc;
 };
 
 /* user space parameter to limit usb current */
@@ -327,6 +329,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
@@ -814,7 +820,7 @@
 					 temp);
 }
 
-#define PM8921_CHG_TTRKL_MASK	0x1F
+#define PM8921_CHG_TTRKL_MASK	0x3F
 #define PM8921_CHG_TTRKL_MIN	1
 #define PM8921_CHG_TTRKL_MAX	64
 static int pm_chg_ttrkl_max_set(struct pm8921_chg_chip *chip, int minutes)
@@ -1190,6 +1196,12 @@
 	case POWER_SUPPLY_PROP_PRESENT:
 	case POWER_SUPPLY_PROP_ONLINE:
 		val->intval = 0;
+
+		if (the_chip->has_dc_supply) {
+			val->intval = 1;
+			return 0;
+		}
+
 		if (charging_disabled)
 			return 0;
 
@@ -1276,6 +1288,8 @@
 		else
 			return -EINVAL;
 		break;
+	case POWER_SUPPLY_PROP_TYPE:
+		return pm8921_set_usb_power_supply_type(val->intval);
 	default:
 		return -EINVAL;
 	}
@@ -1343,6 +1357,7 @@
 	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
 	POWER_SUPPLY_PROP_VOLTAGE_NOW,
 	POWER_SUPPLY_PROP_CAPACITY,
+	POWER_SUPPLY_PROP_CURRENT_MAX,
 	POWER_SUPPLY_PROP_CURRENT_NOW,
 	POWER_SUPPLY_PROP_TEMP,
 	POWER_SUPPLY_PROP_ENERGY_FULL,
@@ -1400,9 +1415,40 @@
 	if (percent_soc <= 10)
 		pr_warn("low battery charge = %d%%\n", percent_soc);
 
+	chip->recent_reported_soc = percent_soc;
 	return percent_soc;
 }
 
+static int get_prop_batt_current_max(struct pm8921_chg_chip *chip)
+{
+	int rbatt, ibatt_ua, vbatt_uv, ocv_uv;
+	int imax_ma;
+	int rc;
+
+	rbatt = pm8921_bms_get_rbatt();
+
+	if (rbatt < 0) {
+		rc = -ENXIO;
+		return rc;
+	}
+
+	rc =  pm8921_bms_get_simultaneous_battery_voltage_and_current
+			(&ibatt_ua, &vbatt_uv);
+
+	if (rc)
+		return rc;
+
+	ocv_uv = vbatt_uv + ibatt_ua*rbatt/1000;
+
+	imax_ma = (ocv_uv - chip->min_voltage_mv*1000)/rbatt;
+
+	if (imax_ma < 0)
+		imax_ma = 0;
+
+	return imax_ma*1000;
+
+}
+
 static int get_prop_batt_current(struct pm8921_chg_chip *chip)
 {
 	int result_ua, rc;
@@ -1556,6 +1602,9 @@
 	case POWER_SUPPLY_PROP_CURRENT_NOW:
 		val->intval = get_prop_batt_current(chip);
 		break;
+	case POWER_SUPPLY_PROP_CURRENT_MAX:
+		val->intval = get_prop_batt_current_max(chip);
+		break;
 	case POWER_SUPPLY_PROP_TEMP:
 		val->intval = get_prop_batt_temp(chip);
 		break;
@@ -1663,8 +1712,10 @@
 	 */
 	if (!get_prop_batt_present(the_chip)
 		&& !is_dc_chg_plugged_in(the_chip)) {
-		pr_err("rejected: no other power source connected\n");
-		return;
+		if (!the_chip->has_dc_supply) {
+			pr_err("rejected: no other power source connected\n");
+			return;
+		}
 	}
 
 	if (usb_max_current && mA > usb_max_current) {
@@ -1741,6 +1792,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
@@ -2462,15 +2522,18 @@
 				pm_chg_get_fsm_state(chip),
 				get_prop_batt_current(chip)
 				);
+			return;
+		} else {
+			goto check_again_later;
 		}
-		return;
 	}
 
 	if (active_path & USB_ACTIVE_BIT) {
 		reg_loop = pm_chg_get_regulation_loop(chip);
 		pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
 		if ((reg_loop & VIN_ACTIVE_BIT) &&
-			(usb_ma > USB_WALL_THRESHOLD_MA)) {
+			(usb_ma > USB_WALL_THRESHOLD_MA)
+			&& !charging_disabled) {
 			decrease_usb_ma_value(&usb_ma);
 			usb_target_ma = usb_ma;
 			/* end AICL here */
@@ -2485,7 +2548,6 @@
 
 	ibat = get_prop_batt_current(chip);
 	if (reg_loop & VIN_ACTIVE_BIT) {
-
 		pr_debug("ibat = %d fsm = %d reg_loop = 0x%x\n",
 				ibat, pm_chg_get_fsm_state(chip), reg_loop);
 		if (ibat > 0) {
@@ -2521,7 +2583,8 @@
 		unplug_ovp_fet_open(chip);
 	}
 
-	if (!(reg_loop & VIN_ACTIVE_BIT) && (active_path & USB_ACTIVE_BIT)) {
+	if (!(reg_loop & VIN_ACTIVE_BIT) && (active_path & USB_ACTIVE_BIT)
+		&& !charging_disabled) {
 		/* only increase iusb_max if vin loop not active */
 		if (usb_ma < usb_target_ma) {
 			increase_usb_ma_value(&usb_ma);
@@ -2768,6 +2831,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);
@@ -2776,7 +2840,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)));
 }
@@ -2787,6 +2856,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;
@@ -2821,11 +2892,7 @@
 		pr_debug("Exiting ichg_meas_ua = %d > 0\n", ichg_meas_ua);
 		return;
 	}
-	if (ichg_meas_ua <= ichg_threshold_ua) {
-		pr_debug("Exiting ichg_meas_ua = %d < ichg_threshold_ua = %d\n",
-					ichg_meas_ua, ichg_threshold_ua);
-		return;
-	}
+
 	ichg_meas_ma = ichg_meas_ua / 1000;
 
 	/* rconn_mohm is in milliOhms */
@@ -2846,9 +2913,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);
@@ -3669,24 +3738,9 @@
 						chip->led_src_config, rc);
 	}
 
-	/* Workarounds for die 1.1 and 1.0 */
-	if (pm8xxx_get_revision(chip->dev->parent) < PM8XXX_REVISION_8921_2p0) {
-		pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST2, 0xF1);
-		pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xCE);
-		pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xD8);
-
-		/* software workaround for correct battery_id detection */
-		pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_0, 0xFF);
-		pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_1, 0xFF);
-		pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_2, 0xFF);
-		pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_3, 0xFF);
-		pm8xxx_writeb(chip->dev->parent, PSI_CONFIG_STATUS, 0x0D);
-		udelay(100);
-		pm8xxx_writeb(chip->dev->parent, PSI_CONFIG_STATUS, 0x0C);
-	}
-
 	/* Workarounds for die 3.0 */
-	if (pm8xxx_get_revision(chip->dev->parent) == PM8XXX_REVISION_8921_3p0)
+	if (pm8xxx_get_revision(chip->dev->parent) == PM8XXX_REVISION_8921_3p0
+	&& pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8921)
 		pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xAC);
 
 	/* Enable isub_fine resolution AICL for PM8917 */
@@ -4024,6 +4078,7 @@
 	chip->hot_thr = pdata->hot_thr;
 	chip->rconn_mohm = pdata->rconn_mohm;
 	chip->led_src_config = pdata->led_src_config;
+	chip->has_dc_supply = pdata->has_dc_supply;
 
 	rc = pm8921_chg_hw_init(chip);
 	if (rc) {
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/regulator/fixed.c b/drivers/regulator/fixed.c
index 40f3803..7e74eca 100644
--- a/drivers/regulator/fixed.c
+++ b/drivers/regulator/fixed.c
@@ -62,11 +62,11 @@
 	config = devm_kzalloc(dev, sizeof(struct fixed_voltage_config),
 								 GFP_KERNEL);
 	if (!config)
-		return NULL;
+		return ERR_PTR(-ENOMEM);
 
 	config->init_data = of_get_regulator_init_data(dev, dev->of_node);
 	if (!config->init_data)
-		return NULL;
+		return ERR_PTR(-EINVAL);
 
 	init_data = config->init_data;
 	init_data->constraints.apply_uV = 0;
@@ -77,13 +77,26 @@
 	} else {
 		dev_err(dev,
 			 "Fixed regulator specified with variable voltages\n");
-		return NULL;
+		return ERR_PTR(-EINVAL);
 	}
 
 	if (init_data->constraints.boot_on)
 		config->enabled_at_boot = true;
 
 	config->gpio = of_get_named_gpio(np, "gpio", 0);
+	/*
+	 * of_get_named_gpio() currently returns ENODEV rather than
+	 * EPROBE_DEFER. This code attempts to be compatible with both
+	 * for now; the ENODEV check can be removed once the API is fixed.
+	 * of_get_named_gpio() doesn't differentiate between a missing
+	 * property (which would be fine here, since the GPIO is optional)
+	 * and some other error. Patches have been posted for both issues.
+	 * Once they are check in, we should replace this with:
+	 * if (config->gpio < 0 && config->gpio != -ENOENT)
+	 */
+	if ((config->gpio == -ENODEV) || (config->gpio == -EPROBE_DEFER))
+		return ERR_PTR(-EPROBE_DEFER);
+
 	delay = of_get_property(np, "startup-delay-us", NULL);
 	if (delay)
 		config->startup_delay = be32_to_cpu(*delay);
@@ -168,10 +181,13 @@
 	struct fixed_voltage_data *drvdata;
 	int ret;
 
-	if (pdev->dev.of_node)
+	if (pdev->dev.of_node) {
 		config = of_get_fixed_voltage_config(&pdev->dev);
-	else
+		if (IS_ERR(config))
+			return PTR_ERR(config);
+	} else {
 		config = pdev->dev.platform_data;
+	}
 
 	if (!config)
 		return -ENOMEM;
diff --git a/drivers/regulator/qpnp-regulator.c b/drivers/regulator/qpnp-regulator.c
index f8176b9..44fdbc1 100644
--- a/drivers/regulator/qpnp-regulator.c
+++ b/drivers/regulator/qpnp-regulator.c
@@ -56,7 +56,7 @@
 };
 
 enum qpnp_regulator_type {
-	QPNP_REGULATOR_TYPE_HF_BUCK		= 0x03,
+	QPNP_REGULATOR_TYPE_BUCK		= 0x03,
 	QPNP_REGULATOR_TYPE_LDO			= 0x04,
 	QPNP_REGULATOR_TYPE_VS			= 0x05,
 	QPNP_REGULATOR_TYPE_BOOST		= 0x1B,
@@ -87,6 +87,7 @@
 };
 
 enum qpnp_common_regulator_registers {
+	QPNP_COMMON_REG_DIG_MAJOR_REV		= 0x01,
 	QPNP_COMMON_REG_TYPE			= 0x04,
 	QPNP_COMMON_REG_SUBTYPE			= 0x05,
 	QPNP_COMMON_REG_VOLTAGE_RANGE		= 0x40,
@@ -106,7 +107,7 @@
 };
 
 enum qpnp_boost_registers {
-	QPNP_BOOST_REG_CURRENT_LIMIT		= 0x40,
+	QPNP_BOOST_REG_CURRENT_LIMIT		= 0x4A,
 };
 
 /* Used for indexing into ctrl_reg.  These are offets from 0x40 */
@@ -117,10 +118,6 @@
 	QPNP_COMMON_IDX_ENABLE			= 6,
 };
 
-enum qpnp_boost_control_register_index {
-	QPNP_BOOST_IDX_CURRENT_LIMIT		= 0,
-};
-
 /* Common regulator control register layout */
 #define QPNP_COMMON_ENABLE_MASK			0x80
 #define QPNP_COMMON_ENABLE			0x80
@@ -190,6 +187,8 @@
 	enum qpnp_regulator_type		type;
 	enum qpnp_regulator_subtype		subtype;
 	enum qpnp_regulator_logical_type	logical_type;
+	u32					revision_min;
+	u32					revision_max;
 	struct regulator_ops			*ops;
 	struct qpnp_voltage_set_points		*set_points;
 	int					hpm_min_load;
@@ -213,11 +212,13 @@
 	u8					ctrl_reg[8];
 };
 
-#define QPNP_VREG_MAP(_type, _subtype, _logical_type, _ops_val, \
-		      _set_points_val, _hpm_min_load) \
+#define QPNP_VREG_MAP(_type, _subtype, _dig_major_min, _dig_major_max, \
+		      _logical_type, _ops_val, _set_points_val, _hpm_min_load) \
 	{ \
 		.type		= QPNP_REGULATOR_TYPE_##_type, \
 		.subtype	= QPNP_REGULATOR_SUBTYPE_##_subtype, \
+		.revision_min	= _dig_major_min, \
+		.revision_max	= _dig_major_max, \
 		.logical_type	= QPNP_REGULATOR_LOGICAL_TYPE_##_logical_type, \
 		.ops		= &qpnp_##_ops_val##_ops, \
 		.set_points	= &_set_points_val##_set_points, \
@@ -262,6 +263,10 @@
 	VOLTAGE_RANGE(2,  750000,  775000, 1537500, 12500),
 };
 
+static struct qpnp_voltage_range nldo3_ranges[] = {
+	VOLTAGE_RANGE(0,  375000,  375000, 1537500, 12500),
+};
+
 static struct qpnp_voltage_range smps_ranges[] = {
 	VOLTAGE_RANGE(0,  375000,  375000, 1562500, 12500),
 	VOLTAGE_RANGE(1, 1550000, 1575000, 3125000, 25000),
@@ -281,6 +286,8 @@
 					= SET_POINTS(nldo1_ranges);
 static struct qpnp_voltage_set_points nldo2_set_points
 					= SET_POINTS(nldo2_ranges);
+static struct qpnp_voltage_set_points nldo3_set_points
+					= SET_POINTS(nldo3_ranges);
 static struct qpnp_voltage_set_points smps_set_points = SET_POINTS(smps_ranges);
 static struct qpnp_voltage_set_points ftsmps_set_points
 					= SET_POINTS(ftsmps_ranges);
@@ -292,6 +299,7 @@
 	&pldo_set_points,
 	&nldo1_set_points,
 	&nldo2_set_points,
+	&nldo3_set_points,
 	&smps_set_points,
 	&ftsmps_set_points,
 	&boost_set_points,
@@ -959,44 +967,70 @@
 	.enable_time		= qpnp_regulator_common_enable_time,
 };
 
+/* Maximum possible digital major revision value */
+#define INF 0xFF
+
 static const struct qpnp_regulator_mapping supported_regulators[] = {
-	QPNP_VREG_MAP(HF_BUCK,  GP_CTL,    SMPS,   smps,   smps,   100000),
-	QPNP_VREG_MAP(LDO,      N300,      LDO,    ldo,    nldo1,   10000),
-	QPNP_VREG_MAP(LDO,      N600,      LDO,    ldo,    nldo2,   10000),
-	QPNP_VREG_MAP(LDO,      N1200,     LDO,    ldo,    nldo2,   10000),
-	QPNP_VREG_MAP(LDO,      P50,       LDO,    ldo,    pldo,     5000),
-	QPNP_VREG_MAP(LDO,      P150,      LDO,    ldo,    pldo,    10000),
-	QPNP_VREG_MAP(LDO,      P300,      LDO,    ldo,    pldo,    10000),
-	QPNP_VREG_MAP(LDO,      P600,      LDO,    ldo,    pldo,    10000),
-	QPNP_VREG_MAP(LDO,      P1200,     LDO,    ldo,    pldo,    10000),
-	QPNP_VREG_MAP(VS,       LV100,     VS,     vs,     none,        0),
-	QPNP_VREG_MAP(VS,       LV300,     VS,     vs,     none,        0),
-	QPNP_VREG_MAP(VS,       MV300,     VS,     vs,     none,        0),
-	QPNP_VREG_MAP(VS,       MV500,     VS,     vs,     none,        0),
-	QPNP_VREG_MAP(VS,       HDMI,      VS,     vs,     none,        0),
-	QPNP_VREG_MAP(VS,       OTG,       VS,     vs,     none,        0),
-	QPNP_VREG_MAP(BOOST,    5V_BOOST,  BOOST,  boost,  boost,       0),
-	QPNP_VREG_MAP(FTS,      FTS_CTL,   FTSMPS, ftsmps, ftsmps, 100000),
+	/*           type subtype dig_min dig_max ltype ops setpoints hpm_min */
+	QPNP_VREG_MAP(BUCK,  GP_CTL,   0, INF, SMPS,   smps,   smps,   100000),
+	QPNP_VREG_MAP(LDO,   N300,     0, INF, LDO,    ldo,    nldo1,   10000),
+	QPNP_VREG_MAP(LDO,   N600,     0,   0, LDO,    ldo,    nldo2,   10000),
+	QPNP_VREG_MAP(LDO,   N1200,    0,   0, LDO,    ldo,    nldo2,   10000),
+	QPNP_VREG_MAP(LDO,   N600,     1, INF, LDO,    ldo,    nldo3,   10000),
+	QPNP_VREG_MAP(LDO,   N1200,    1, INF, LDO,    ldo,    nldo3,   10000),
+	QPNP_VREG_MAP(LDO,   P50,      0, INF, LDO,    ldo,    pldo,     5000),
+	QPNP_VREG_MAP(LDO,   P150,     0, INF, LDO,    ldo,    pldo,    10000),
+	QPNP_VREG_MAP(LDO,   P300,     0, INF, LDO,    ldo,    pldo,    10000),
+	QPNP_VREG_MAP(LDO,   P600,     0, INF, LDO,    ldo,    pldo,    10000),
+	QPNP_VREG_MAP(LDO,   P1200,    0, INF, LDO,    ldo,    pldo,    10000),
+	QPNP_VREG_MAP(VS,    LV100,    0, INF, VS,     vs,     none,        0),
+	QPNP_VREG_MAP(VS,    LV300,    0, INF, VS,     vs,     none,        0),
+	QPNP_VREG_MAP(VS,    MV300,    0, INF, VS,     vs,     none,        0),
+	QPNP_VREG_MAP(VS,    MV500,    0, INF, VS,     vs,     none,        0),
+	QPNP_VREG_MAP(VS,    HDMI,     0, INF, VS,     vs,     none,        0),
+	QPNP_VREG_MAP(VS,    OTG,      0, INF, VS,     vs,     none,        0),
+	QPNP_VREG_MAP(BOOST, 5V_BOOST, 0, INF, BOOST,  boost,  boost,       0),
+	QPNP_VREG_MAP(FTS,   FTS_CTL,  0, INF, FTSMPS, ftsmps, ftsmps, 100000),
 };
 
 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], dig_major_rev;
+	u8 version[QPNP_COMMON_REG_SUBTYPE - QPNP_COMMON_REG_DIG_MAJOR_REV + 1];
+	u8 type, subtype;
 
-	rc = qpnp_vreg_read(vreg, QPNP_COMMON_REG_TYPE, raw_type, 2);
+	rc = qpnp_vreg_read(vreg, QPNP_COMMON_REG_DIG_MAJOR_REV, version,
+		ARRAY_SIZE(version));
 	if (rc) {
-		vreg_err(vreg, "could not read type register, rc=%d\n", rc);
+		vreg_err(vreg, "could not read version registers, rc=%d\n", rc);
 		return rc;
 	}
-	type = raw_type[0];
-	subtype = raw_type[1];
+	dig_major_rev	= version[QPNP_COMMON_REG_DIG_MAJOR_REV
+					- QPNP_COMMON_REG_DIG_MAJOR_REV];
+	type		= version[QPNP_COMMON_REG_TYPE
+					- QPNP_COMMON_REG_DIG_MAJOR_REV];
+	subtype		= version[QPNP_COMMON_REG_SUBTYPE
+					- QPNP_COMMON_REG_DIG_MAJOR_REV];
+
+	/*
+	 * Override type and subtype register values if qcom,force-type is
+	 * present in the device tree node.
+	 */
+	rc = of_property_read_u32_array(node, "qcom,force-type", type_reg, 2);
+	if (!rc) {
+		type = type_reg[0];
+		subtype = type_reg[1];
+	}
 
 	rc = -ENODEV;
 	for (i = 0; i < ARRAY_SIZE(supported_regulators); i++) {
 		mapping = &supported_regulators[i];
-		if (mapping->type == type && mapping->subtype == subtype) {
+		if (mapping->type == type && mapping->subtype == subtype
+		    && mapping->revision_min <= dig_major_rev
+		    && mapping->revision_max >= dig_major_rev) {
 			vreg->logical_type	= mapping->logical_type;
 			vreg->set_points	= mapping->set_points;
 			vreg->hpm_min_load	= mapping->hpm_min_load;
@@ -1086,10 +1120,14 @@
 	if (type == QPNP_REGULATOR_LOGICAL_TYPE_BOOST
 		&& pdata->boost_current_limit
 			!= QPNP_BOOST_CURRENT_LIMIT_HW_DEFAULT) {
-		ctrl_reg[QPNP_BOOST_IDX_CURRENT_LIMIT] &=
-			~QPNP_BOOST_CURRENT_LIMIT_MASK;
-		ctrl_reg[QPNP_BOOST_IDX_CURRENT_LIMIT] |=
-		     pdata->boost_current_limit & QPNP_BOOST_CURRENT_LIMIT_MASK;
+		reg = pdata->boost_current_limit;
+		mask = QPNP_BOOST_CURRENT_LIMIT_MASK;
+		rc = qpnp_vreg_masked_read_write(vreg,
+			QPNP_BOOST_REG_CURRENT_LIMIT, reg, mask);
+		if (rc) {
+			vreg_err(vreg, "spmi write failed, rc=%d\n", rc);
+			return rc;
+		}
 	}
 
 	/* Write back any control register values that were modified. */
diff --git a/drivers/slimbus/slim-msm-ctrl.c b/drivers/slimbus/slim-msm-ctrl.c
index 6eb5d60..556e3ea 100644
--- a/drivers/slimbus/slim-msm-ctrl.c
+++ b/drivers/slimbus/slim-msm-ctrl.c
@@ -25,6 +25,7 @@
 #include <linux/of.h>
 #include <linux/of_slimbus.h>
 #include <mach/sps.h>
+#include <mach/qdsp6v2/apr.h>
 
 /* Per spec.max 40 bytes per received message */
 #define SLIM_RX_MSGQ_BUF_LEN	40
@@ -87,6 +88,8 @@
 #define QC_DEVID_SAT2	0x4
 #define QC_DEVID_PGD	0x5
 #define QC_MSM_DEVS	5
+#define INIT_MX_RETRIES 10
+#define DEF_RETRY_MS	10
 
 #define PGD_THIS_EE(r, v) ((v) ? PGD_THIS_EE_V2(r) : PGD_THIS_EE_V1(r))
 #define PGD_PORT(r, p, v) ((v) ? PGD_PORT_V2(r, p) : PGD_PORT_V1(r, p))
@@ -174,6 +177,7 @@
 	MGR_INT_CLR	= 0x218,
 	MGR_TX_MSG	= 0x230,
 	MGR_RX_MSG	= 0x270,
+	MGR_IE_STAT	= 0x2F0,
 	MGR_VE_STAT	= 0x300,
 };
 
@@ -232,6 +236,7 @@
 	CLK_GEAR	= 7,
 	ROOT_FREQ	= 11,
 	REF_CLK_GEAR	= 15,
+	INTR_WAKE	= 19,
 };
 
 enum msm_ctrl_state {
@@ -279,6 +284,7 @@
 	struct completion	rx_msgq_notify;
 	struct task_struct	*rx_msgq_thread;
 	struct clk		*rclk;
+	struct clk		*hclk;
 	struct mutex		tx_lock;
 	u8			pgdla;
 	bool			use_rx_msgqs;
@@ -296,6 +302,7 @@
 	u16 chanh;
 	int req_rem;
 	int req_def;
+	bool reconf;
 };
 
 struct msm_slim_sat {
@@ -445,8 +452,34 @@
 			writel_relaxed(MGR_INT_TX_MSG_SENT,
 					dev->base + MGR_INT_CLR);
 		else {
+			u32 mgr_stat = readl_relaxed(dev->base + MGR_STATUS);
+			u32 mgr_ie_stat = readl_relaxed(dev->base +
+						MGR_IE_STAT);
+			u32 frm_stat = readl_relaxed(dev->base + FRM_STAT);
+			u32 frm_cfg = readl_relaxed(dev->base + FRM_CFG);
+			u32 frm_intr_stat = readl_relaxed(dev->base +
+						FRM_INT_STAT);
+			u32 frm_ie_stat = readl_relaxed(dev->base +
+						FRM_IE_STAT);
+			u32 intf_stat = readl_relaxed(dev->base + INTF_STAT);
+			u32 intf_intr_stat = readl_relaxed(dev->base +
+						INTF_INT_STAT);
+			u32 intf_ie_stat = readl_relaxed(dev->base +
+						INTF_IE_STAT);
+
 			writel_relaxed(MGR_INT_TX_NACKED_2,
 					dev->base + MGR_INT_CLR);
+			pr_err("TX Nack MGR dump:int_stat:0x%x, mgr_stat:0x%x",
+					stat, mgr_stat);
+			pr_err("TX Nack MGR dump:ie_stat:0x%x", mgr_ie_stat);
+			pr_err("TX Nack FRM dump:int_stat:0x%x, frm_stat:0x%x",
+					frm_intr_stat, frm_stat);
+			pr_err("TX Nack FRM dump:frm_cfg:0x%x, ie_stat:0x%x",
+					frm_cfg, frm_ie_stat);
+			pr_err("TX Nack INTF dump:intr_st:0x%x, intf_stat:0x%x",
+					intf_intr_stat, intf_stat);
+			pr_err("TX Nack INTF dump:ie_stat:0x%x", intf_ie_stat);
+
 			dev->err = -EIO;
 		}
 		/*
@@ -859,7 +892,8 @@
 	dev->wr_comp = &done;
 	msm_send_msg_buf(ctrl, pbuf, txn->rl);
 	timeout = wait_for_completion_timeout(&done, HZ);
-
+	if (!timeout)
+		dev->wr_comp = NULL;
 	if (mc == SLIM_MSG_MC_RECONFIGURE_NOW) {
 		if ((txn->mc == (SLIM_MSG_MC_RECONFIGURE_NOW |
 					SLIM_MSG_CLK_PAUSE_SEQ_FLG)) &&
@@ -899,13 +933,28 @@
 	return timeout ? dev->err : -ETIMEDOUT;
 }
 
+static void msm_slim_wait_retry(struct msm_slim_ctrl *dev)
+{
+	int msec_per_frm = 0;
+	int sfr_per_sec;
+	/* Wait for 1 superframe, or default time and then retry */
+	sfr_per_sec = dev->framer.superfreq /
+			(1 << (SLIM_MAX_CLK_GEAR - dev->ctrl.clkgear));
+	if (sfr_per_sec)
+		msec_per_frm = MSEC_PER_SEC / sfr_per_sec;
+	if (msec_per_frm < DEF_RETRY_MS)
+		msec_per_frm = DEF_RETRY_MS;
+	msleep(msec_per_frm);
+}
 static int msm_set_laddr(struct slim_controller *ctrl, const u8 *ea,
 				u8 elen, u8 laddr)
 {
 	struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
-	DECLARE_COMPLETION_ONSTACK(done);
-	int timeout;
+	struct completion done;
+	int timeout, ret, retries = 0;
 	u32 *buf;
+retry_laddr:
+	init_completion(&done);
 	mutex_lock(&dev->tx_lock);
 	buf = msm_get_msg_buf(ctrl, 9);
 	buf[0] = SLIM_MSG_ASM_FIRST_WORD(9, SLIM_MSG_MT_CORE,
@@ -916,10 +965,27 @@
 	buf[2] = laddr;
 
 	dev->wr_comp = &done;
-	msm_send_msg_buf(ctrl, buf, 9);
+	ret = msm_send_msg_buf(ctrl, buf, 9);
 	timeout = wait_for_completion_timeout(&done, HZ);
+	if (!timeout)
+		dev->err = -ETIMEDOUT;
+	if (dev->err) {
+		ret = dev->err;
+		dev->err = 0;
+		dev->wr_comp = NULL;
+	}
 	mutex_unlock(&dev->tx_lock);
-	return timeout ? dev->err : -ETIMEDOUT;
+	if (ret) {
+		pr_err("set LADDR:0x%x failed:ret:%d, retrying", laddr, ret);
+		if (retries < INIT_MX_RETRIES) {
+			msm_slim_wait_retry(dev);
+			retries++;
+			goto retry_laddr;
+		} else {
+			pr_err("set LADDR failed after retrying:ret:%d", ret);
+		}
+	}
+	return ret;
 }
 
 static int msm_clk_pause_wakeup(struct slim_controller *ctrl)
@@ -1150,6 +1216,8 @@
 				msm_sat_enqueue(sat, (u32 *)buf, len);
 				queue_work(sat->wq, &sat->wd);
 			}
+			if (ret)
+				pr_err("assign laddr failed, error:%d", ret);
 		} else if (mc == SLIM_MSG_MC_REPLY_INFORMATION ||
 				mc == SLIM_MSG_MC_REPLY_VALUE) {
 			u8 tid = buf[3];
@@ -1192,7 +1260,7 @@
 		bool gen_ack = false;
 		u8 tid;
 		u8 wbuf[8];
-		int i;
+		int i, retries = 0;
 		txn.mt = SLIM_MSG_MT_SRC_REFERRED_USER;
 		txn.dt = SLIM_MSG_DEST_LOGICALADDR;
 		txn.ec = 0;
@@ -1205,7 +1273,6 @@
 
 		if (mt == SLIM_MSG_MT_CORE &&
 			mc == SLIM_MSG_MC_REPORT_PRESENT) {
-			u8 laddr;
 			u8 e_addr[6];
 			for (i = 0; i < 6; i++)
 				e_addr[i] = buf[7-i];
@@ -1215,8 +1282,6 @@
 				if (satv >= 0)
 					sat->pending_capability = true;
 			}
-			slim_assign_laddr(&dev->ctrl, e_addr, 6, &laddr);
-			sat->satcl.laddr = laddr;
 			/*
 			 * Since capability message is already sent, present
 			 * message will indicate subsystem hosting this
@@ -1226,16 +1291,15 @@
 			 */
 			if (sat->sent_capability) {
 				for (i = 0; i < sat->nsatch; i++) {
-					enum slim_ch_state chs =
-						slim_get_ch_state(&sat->satcl,
-							sat->satch[i].chanh);
-					pr_err("Slim-SSR, sat:%d, rm chan:%d",
-							laddr,
+					if (sat->satch[i].reconf) {
+						pr_err("SSR, sat:%d, rm ch:%d",
+							sat->satcl.laddr,
 							sat->satch[i].chan);
-					if (chs == SLIM_CH_ACTIVE)
 						slim_control_ch(&sat->satcl,
 							sat->satch[i].chanh,
 							SLIM_CH_REMOVE, true);
+						sat->satch[i].reconf = false;
+					}
 				}
 			}
 		} else if (mt != SLIM_MSG_MT_CORE &&
@@ -1281,8 +1345,21 @@
 			wbuf[3] = SAT_MSG_PROT;
 			txn.wbuf = wbuf;
 			txn.len = 4;
-			sat->sent_capability = true;
-			msm_xfer_msg(&dev->ctrl, &txn);
+			ret = msm_xfer_msg(&dev->ctrl, &txn);
+			if (ret) {
+				pr_err("capability for:0x%x fail:%d, retry:%d",
+						sat->satcl.laddr, ret, retries);
+				if (retries < INIT_MX_RETRIES) {
+					msm_slim_wait_retry(dev);
+					retries++;
+					goto send_capability;
+				} else {
+					pr_err("failed after all retries:%d",
+							ret);
+				}
+			} else {
+				sat->sent_capability = true;
+			}
 			break;
 		case SLIM_USR_MC_ADDR_QUERY:
 			memcpy(&wbuf[1], &buf[4], 6);
@@ -1323,15 +1400,19 @@
 			ret = slim_reconfigure_now(&sat->satcl);
 			for (i = 0; i < sat->nsatch; i++) {
 				struct msm_sat_chan *sch = &sat->satch[i];
-				if (sch->req_rem) {
-					if (!ret)
+				if (sch->req_rem && sch->reconf) {
+					if (!ret) {
 						slim_dealloc_ch(&sat->satcl,
 								sch->chanh);
+						sch->reconf = false;
+					}
 					sch->req_rem--;
 				} else if (sch->req_def) {
 					if (ret)
 						slim_dealloc_ch(&sat->satcl,
 								sch->chanh);
+					else
+						sch->reconf = true;
 					sch->req_def--;
 				}
 			}
@@ -1844,10 +1925,20 @@
 {
 	struct msm_slim_ctrl *dev;
 	int ret;
+	enum apr_subsys_state q6_state;
 	struct resource		*bam_mem, *bam_io;
 	struct resource		*slim_mem, *slim_io;
 	struct resource		*irq, *bam_irq;
 	bool			rxreg_access = false;
+
+	q6_state = apr_get_q6_state();
+	if (q6_state == APR_SUBSYS_DOWN) {
+		dev_dbg(&pdev->dev, "defering %s, adsp_state %d\n", __func__,
+			q6_state);
+		return -EPROBE_DEFER;
+	} else
+		dev_dbg(&pdev->dev, "adsp is ready\n");
+
 	slim_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
 						"slimbus_physical");
 	if (!slim_mem) {
@@ -1955,6 +2046,12 @@
 	dev->irq = irq->start;
 	dev->bam.irq = bam_irq->start;
 
+	dev->hclk = clk_get(dev->dev, "iface_clk");
+	if (IS_ERR(dev->hclk))
+		dev->hclk = NULL;
+	else
+		clk_prepare_enable(dev->hclk);
+
 	ret = msm_slim_sps_init(dev, bam_mem);
 	if (ret != 0) {
 		dev_err(dev->dev, "error SPS init\n");
@@ -2024,8 +2121,8 @@
 	wmb();
 
 	/* Framer register initialization */
-	writel_relaxed((0xA << REF_CLK_GEAR) | (0xA << CLK_GEAR) |
-		(1 << ROOT_FREQ) | (1 << FRM_ACTIVE) | 1,
+	writel_relaxed((1 << INTR_WAKE) | (0xA << REF_CLK_GEAR) |
+		(0xA << CLK_GEAR) | (1 << ROOT_FREQ) | (1 << FRM_ACTIVE) | 1,
 		dev->base + FRM_CFG);
 	/*
 	 * Make sure that framer wake-up and enabling writes go through
@@ -2067,6 +2164,10 @@
 	 * function
 	 */
 	mb();
+
+	/* Add devices registered with board-info now that controller is up */
+	slim_ctrl_add_boarddevs(&dev->ctrl);
+
 	if (pdev->dev.of_node)
 		of_register_slim_devices(&dev->ctrl);
 
@@ -2084,6 +2185,10 @@
 err_request_irq_failed:
 	msm_slim_sps_exit(dev);
 err_sps_init_failed:
+	if (dev->hclk) {
+		clk_disable_unprepare(dev->hclk);
+		clk_put(dev->hclk);
+	}
 err_of_init_failed:
 	iounmap(dev->bam.base);
 err_ioremap_bam_failed:
@@ -2120,6 +2225,8 @@
 	free_irq(dev->irq, dev);
 	slim_del_controller(&dev->ctrl);
 	clk_put(dev->rclk);
+	if (dev->hclk)
+		clk_put(dev->hclk);
 	msm_slim_sps_exit(dev);
 	kthread_stop(dev->rx_msgq_thread);
 	iounmap(dev->bam.base);
@@ -2191,8 +2298,14 @@
 {
 	int ret = 0;
 	if (!pm_runtime_enabled(dev) || !pm_runtime_suspended(dev)) {
+		struct platform_device *pdev = to_platform_device(dev);
+		struct msm_slim_ctrl *cdev = platform_get_drvdata(pdev);
 		dev_dbg(dev, "system suspend");
 		ret = msm_slim_runtime_suspend(dev);
+		if (!ret) {
+			if (cdev->hclk)
+				clk_disable_unprepare(cdev->hclk);
+		}
 	}
 	if (ret == -EBUSY) {
 		/*
@@ -2212,8 +2325,12 @@
 {
 	/* If runtime_pm is enabled, this resume shouldn't do anything */
 	if (!pm_runtime_enabled(dev) || !pm_runtime_suspended(dev)) {
+		struct platform_device *pdev = to_platform_device(dev);
+		struct msm_slim_ctrl *cdev = platform_get_drvdata(pdev);
 		int ret;
 		dev_dbg(dev, "system resume");
+		if (cdev->hclk)
+			clk_prepare_enable(cdev->hclk);
 		ret = msm_slim_runtime_resume(dev);
 		if (!ret) {
 			pm_runtime_mark_last_busy(dev);
diff --git a/drivers/slimbus/slimbus.c b/drivers/slimbus/slimbus.c
index 2198954..da2a30d 100644
--- a/drivers/slimbus/slimbus.c
+++ b/drivers/slimbus/slimbus.c
@@ -176,16 +176,27 @@
 static int slim_drv_probe(struct device *dev)
 {
 	const struct slim_driver *sdrv = to_slim_driver(dev->driver);
+	struct slim_device *sbdev = to_slim_device(dev);
+	struct slim_controller *ctrl = sbdev->ctrl;
 
-	if (sdrv->probe)
-		return sdrv->probe(to_slim_device(dev));
+	if (sdrv->probe) {
+		int ret;
+		ret = sdrv->probe(sbdev);
+		if (ret)
+			return ret;
+		if (sdrv->device_up)
+			queue_work(ctrl->wq, &sbdev->wd);
+		return 0;
+	}
 	return -ENODEV;
 }
 
 static int slim_drv_remove(struct device *dev)
 {
 	const struct slim_driver *sdrv = to_slim_driver(dev->driver);
+	struct slim_device *sbdev = to_slim_device(dev);
 
+	sbdev->notified = false;
 	if (sdrv->remove)
 		return sdrv->remove(to_slim_device(dev));
 	return -ENODEV;
@@ -263,6 +274,23 @@
 	.release	= slim_dev_release,
 };
 
+static void slim_report_present(struct work_struct *work)
+{
+	u8 laddr;
+	int ret;
+	struct slim_driver *sbdrv;
+	struct slim_device *sbdev =
+			container_of(work, struct slim_device, wd);
+	if (sbdev->notified || !sbdev->dev.driver)
+		return;
+	ret = slim_get_logical_addr(sbdev, sbdev->e_addr, 6, &laddr);
+	sbdrv = to_slim_driver(sbdev->dev.driver);
+	if (!ret && sbdrv->device_up) {
+		sbdev->notified = true;
+		sbdrv->device_up(sbdev);
+	}
+}
+
 /*
  * slim_add_device: Add a new device without register board info.
  * @ctrl: Controller to which this device is to be added to.
@@ -271,25 +299,23 @@
  */
 int slim_add_device(struct slim_controller *ctrl, struct slim_device *sbdev)
 {
-	int ret = 0;
-
 	sbdev->dev.bus = &slimbus_type;
 	sbdev->dev.parent = ctrl->dev.parent;
 	sbdev->dev.type = &slim_dev_type;
+	sbdev->dev.driver = NULL;
 	sbdev->ctrl = ctrl;
 	slim_ctrl_get(ctrl);
 	dev_set_name(&sbdev->dev, "%s", sbdev->name);
-	/* probe slave on this controller */
-	ret = device_register(&sbdev->dev);
-
-	if (ret)
-		return ret;
-
 	mutex_init(&sbdev->sldev_reconf);
 	INIT_LIST_HEAD(&sbdev->mark_define);
 	INIT_LIST_HEAD(&sbdev->mark_suspend);
 	INIT_LIST_HEAD(&sbdev->mark_removal);
-	return 0;
+	INIT_WORK(&sbdev->wd, slim_report_present);
+	mutex_lock(&ctrl->m_ctrl);
+	list_add_tail(&sbdev->dev_list, &ctrl->devs);
+	mutex_unlock(&ctrl->m_ctrl);
+	/* probe slave on this controller */
+	return device_register(&sbdev->dev);
 }
 EXPORT_SYMBOL_GPL(slim_add_device);
 
@@ -347,6 +373,24 @@
 EXPORT_SYMBOL_GPL(slim_register_board_info);
 
 /*
+ * slim_ctrl_add_boarddevs: Add devices registered by board-info
+ * @ctrl: Controller to which these devices are to be added to.
+ * This API is called by controller when it is up and running.
+ * If devices on a controller were registered before controller,
+ * this will make sure that they get probed when controller is up.
+ */
+void slim_ctrl_add_boarddevs(struct slim_controller *ctrl)
+{
+	struct sbi_boardinfo *bi;
+	mutex_lock(&board_lock);
+	list_add_tail(&ctrl->list, &slim_ctrl_list);
+	list_for_each_entry(bi, &board_list, list)
+		slim_match_ctrl_to_boardinfo(ctrl, &bi->board_info);
+	mutex_unlock(&board_lock);
+}
+EXPORT_SYMBOL_GPL(slim_ctrl_add_boarddevs);
+
+/*
  * slim_busnum_to_ctrl: Map bus number to controller
  * @busnum: Bus number
  * Returns controller representing this bus number
@@ -368,7 +412,6 @@
 static int slim_register_controller(struct slim_controller *ctrl)
 {
 	int ret = 0;
-	struct sbi_boardinfo *bi;
 
 	/* Can't register until after driver model init */
 	if (WARN_ON(!slimbus_type.p)) {
@@ -431,18 +474,18 @@
 	ctrl->sched.slots = kzalloc(SLIM_SL_PER_SUPERFRAME, GFP_KERNEL);
 #endif
 	init_completion(&ctrl->pause_comp);
-	/*
-	 * If devices on a controller were registered before controller,
-	 * this will make sure that they get probed now that controller is up
-	 */
-	mutex_lock(&board_lock);
-	list_add_tail(&ctrl->list, &slim_ctrl_list);
-	list_for_each_entry(bi, &board_list, list)
-		slim_match_ctrl_to_boardinfo(ctrl, &bi->board_info);
-	mutex_unlock(&board_lock);
+
+	INIT_LIST_HEAD(&ctrl->devs);
+	ctrl->wq = create_singlethread_workqueue(dev_name(&ctrl->dev));
+	if (!ctrl->wq)
+		goto err_workq_failed;
 
 	return 0;
 
+err_workq_failed:
+	kfree(ctrl->sched.chc3);
+	kfree(ctrl->sched.chc1);
+	kfree(ctrl->chans);
 err_chan_failed:
 	kfree(ctrl->ports);
 err_port_failed:
@@ -495,6 +538,7 @@
 
 	wait_for_completion(&ctrl->dev_released);
 	list_del(&ctrl->list);
+	destroy_workqueue(ctrl->wq);
 	/* free bus id */
 	mutex_lock(&slim_lock);
 	idr_remove(&ctrl_idr, ctrl->nr);
@@ -665,7 +709,8 @@
 				u8 e_len, u8 *laddr)
 {
 	int ret;
-	u8 i;
+	u8 i = 0;
+	struct slim_device *sbdev;
 	mutex_lock(&ctrl->m_ctrl);
 	/* already assigned */
 	if (ctrl_getlogical_addr(ctrl, e_addr, e_len, laddr) == 0)
@@ -704,7 +749,25 @@
 	dev_dbg(&ctrl->dev, "setting slimbus l-addr:%x\n", i);
 ret_assigned_laddr:
 	mutex_unlock(&ctrl->m_ctrl);
-	return ret;
+	if (ret)
+		return ret;
+
+	pr_info("slimbus laddr:0x%x, EAPC:0x%x:0x%x", i,
+				e_addr[1], e_addr[2]);
+	mutex_lock(&ctrl->m_ctrl);
+	list_for_each_entry(sbdev, &ctrl->devs, dev_list) {
+		if (memcmp(sbdev->e_addr, e_addr, 6) == 0) {
+			struct slim_driver *sbdrv;
+			if (sbdev->dev.driver) {
+				sbdrv = to_slim_driver(sbdev->dev.driver);
+				if (sbdrv->device_up)
+					queue_work(ctrl->wq, &sbdev->wd);
+			}
+			break;
+		}
+	}
+	mutex_unlock(&ctrl->m_ctrl);
+	return 0;
 }
 EXPORT_SYMBOL_GPL(slim_assign_laddr);
 
@@ -920,6 +983,15 @@
 				ret = -ETIMEDOUT;
 			} else
 				ret = 0;
+		} else if (ret < 0 && !msg->comp) {
+			struct slim_msg_txn *txn;
+			dev_err(&ctrl->dev, "slimbus Read error");
+			mutex_lock(&ctrl->m_ctrl);
+			txn = ctrl->txnt[tid];
+			/* Invalidate the transaction */
+			ctrl->txnt[tid] = NULL;
+			mutex_unlock(&ctrl->m_ctrl);
+			kfree(txn);
 		}
 
 	} else
@@ -2516,20 +2588,38 @@
 	u32 segdist;
 	struct slim_pending_ch *pch;
 
+	mutex_lock(&ctrl->sched.m_reconf);
+	mutex_lock(&ctrl->m_ctrl);
 	/*
 	 * 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;
+		struct list_head *pos, *next;
+		list_for_each_safe(pos, next, &sb->mark_removal) {
+			struct slim_ich *slc;
+			pch = list_entry(pos, struct slim_pending_ch, pending);
+			slc = &ctrl->chans[pch->chan];
+			if (slc->def > 0)
+				slc->def--;
+			/* Disconnect source port to free it up */
+			if (SLIM_HDL_TO_LA(slc->srch) == sb->laddr)
+				slc->srch = 0;
+			if (slc->def != 0) {
+				list_del(&pch->pending);
+				kfree(pch);
+			}
+		}
+		if (list_empty(&sb->mark_removal)) {
+			mutex_unlock(&ctrl->m_ctrl);
+			mutex_unlock(&ctrl->sched.m_reconf);
+			pr_info("SLIM_CL: skip reconfig sequence");
+			return 0;
+		}
 	}
 
-	mutex_lock(&ctrl->sched.m_reconf);
-	mutex_lock(&ctrl->m_ctrl);
 	ctrl->sched.pending_msgsl += sb->pending_msgsl - sb->cur_msgsl;
 	list_for_each_entry(pch, &sb->mark_define, pending) {
 		struct slim_ich *slc = &ctrl->chans[pch->chan];
@@ -2785,13 +2875,7 @@
 				ret = -ENOTCONN;
 				break;
 			}
-			if (slc->def > 0)
-				slc->def--;
-			/* Disconnect source port to free it up */
-			if (SLIM_HDL_TO_LA(slc->srch) == sb->laddr)
-				slc->srch = 0;
-			if (slc->def == 0)
-				ret = add_pending_ch(&sb->mark_removal, chan);
+			ret = add_pending_ch(&sb->mark_removal, chan);
 			if (ret)
 				break;
 		}
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index f2c881d..c26da60 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -404,17 +404,21 @@
 		if (bytes_sent < 0)
 			bytes_sent = 0;
 	}
-
 	/* We'll send in chunks of SPI_MAX_LEN if larger than
-	 * 4K bytes for targets that doesn't support infinite
-	 * mode. Make sure this doesn't happen on targets that
-	 * support infinite mode.
+	 * 4K bytes for targets that have only 12 bits in
+	 * QUP_MAX_OUTPUT_CNT register. If the target supports
+	 * more than 12bits then we send the data in chunks of
+	 * the infinite_mode value that is defined in the
+	 * corresponding board file.
 	 */
 	if (!dd->pdata->infinite_mode)
-		bytes_to_send = dd->tx_bytes_remaining / SPI_MAX_LEN ?
-				SPI_MAX_LEN : dd->tx_bytes_remaining;
+		dd->max_trfr_len = SPI_MAX_LEN;
 	else
-		bytes_to_send = dd->tx_bytes_remaining;
+		dd->max_trfr_len = (dd->pdata->infinite_mode) *
+			   (dd->bytes_per_word);
+
+	bytes_to_send = min_t(u32, dd->tx_bytes_remaining,
+			      dd->max_trfr_len);
 
 	num_transfers = DIV_ROUND_UP(bytes_to_send, dd->bytes_per_word);
 	dd->unaligned_len = bytes_to_send % dd->burst_size;
@@ -520,10 +524,11 @@
 		msm_dmov_enqueue_cmd(dd->rx_dma_chan, &dd->rx_hdr);
 }
 
-/* SPI core on targets that does not support infinite mode can send maximum of
-   4K transfers, Therefore, we are sending several chunks of 3K or less
-   (depending on how much is left). Upon completion we send the next chunk,
-   or complete the transfer if everything is finished. On targets that support
+/* SPI core on targets that does not support infinite mode can send
+   maximum of 4K transfers or 64K transfers depending up on size of
+   MAX_OUTPUT_COUNT register, Therefore, we are sending in several
+   chunks. Upon completion we send the next chunk, or complete the
+   transfer if everything is finished. On targets that support
    infinite mode, we send all the bytes in as single chunk.
 */
 static int msm_spi_dm_send_next(struct msm_spi *dd)
@@ -536,9 +541,8 @@
 
 	/* On targets which does not support infinite mode,
 	   We need to send more chunks, if we sent max last time  */
-	if ((!dd->pdata->infinite_mode) &&
-	    (dd->tx_bytes_remaining > SPI_MAX_LEN)) {
-		dd->tx_bytes_remaining -= SPI_MAX_LEN;
+	if (dd->tx_bytes_remaining > dd->max_trfr_len) {
+		dd->tx_bytes_remaining -= dd->max_trfr_len;
 		if (msm_spi_set_state(dd, SPI_OP_STATE_RESET))
 			return 0;
 		dd->read_len = dd->write_len = 0;
@@ -1294,6 +1298,7 @@
 		container_of(work, struct msm_spi, work_data);
 	unsigned long        flags;
 	u32                  status_error = 0;
+	int                  rc = 0;
 
 	mutex_lock(&dd->core_lock);
 
@@ -1304,6 +1309,21 @@
 	if (dd->use_rlock)
 		remote_mutex_lock(&dd->r_lock);
 
+	/* Configure the spi clk, miso, mosi and cs gpio */
+	if (dd->pdata->gpio_config) {
+		rc = dd->pdata->gpio_config();
+		if (rc) {
+			dev_err(dd->dev,
+					"%s: error configuring GPIOs\n",
+					__func__);
+			status_error = 1;
+		}
+	}
+
+	rc = msm_spi_request_gpios(dd);
+	if (rc)
+		status_error = 1;
+
 	clk_prepare_enable(dd->clk);
 	clk_prepare_enable(dd->pclk);
 	msm_spi_enable_irqs(dd);
@@ -1335,6 +1355,12 @@
 	clk_disable_unprepare(dd->clk);
 	clk_disable_unprepare(dd->pclk);
 
+	/* Free  the spi clk, miso, mosi, cs gpio */
+	if (!rc && dd->pdata && dd->pdata->gpio_release)
+		dd->pdata->gpio_release();
+	if (!rc)
+		msm_spi_free_gpios(dd);
+
 	if (dd->use_rlock)
 		remote_mutex_unlock(&dd->r_lock);
 
@@ -1421,6 +1447,24 @@
 	if (dd->use_rlock)
 		remote_mutex_lock(&dd->r_lock);
 
+	/* Configure the spi clk, miso, mosi, cs gpio */
+	if (dd->pdata->gpio_config) {
+		rc = dd->pdata->gpio_config();
+		if (rc) {
+			dev_err(&spi->dev,
+					"%s: error configuring GPIOs\n",
+					__func__);
+			rc = -ENXIO;
+			goto err_setup_gpio;
+		}
+	}
+
+	rc = msm_spi_request_gpios(dd);
+	if (rc) {
+		rc = -ENXIO;
+		goto err_setup_gpio;
+	}
+
 	clk_prepare_enable(dd->clk);
 	clk_prepare_enable(dd->pclk);
 
@@ -1453,10 +1497,15 @@
 	clk_disable_unprepare(dd->clk);
 	clk_disable_unprepare(dd->pclk);
 
+	/* Free  the spi clk, miso, mosi, cs gpio */
+	if (dd->pdata && dd->pdata->gpio_release)
+		dd->pdata->gpio_release();
+	msm_spi_free_gpios(dd);
+
+err_setup_gpio:
 	if (dd->use_rlock)
 		remote_mutex_unlock(&dd->r_lock);
 	mutex_unlock(&dd->core_lock);
-
 err_setup_exit:
 	return rc;
 }
@@ -1818,6 +1867,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);
@@ -1885,22 +1942,9 @@
 			dd->use_dma = 1;
 			master->dma_alignment =	dma_get_cache_alignment();
 		}
-
-skip_dma_resources:
-		if (pdata->gpio_config) {
-			rc = pdata->gpio_config();
-			if (rc) {
-				dev_err(&pdev->dev,
-					"%s: error configuring GPIOs\n",
-					__func__);
-				goto err_probe_gpio;
-			}
-		}
 	}
 
-	rc = msm_spi_request_gpios(dd);
-	if (rc)
-		goto err_probe_gpio;
+skip_dma_resources:
 
 	spin_lock_init(&dd->queue_lock);
 	mutex_init(&dd->core_lock);
@@ -1939,8 +1983,8 @@
 
 		dd->use_rlock = 1;
 		dd->pm_lat = pdata->pm_lat;
-		pm_qos_add_request(&qos_req_list, PM_QOS_CPU_DMA_LATENCY, 
-					    	 PM_QOS_DEFAULT_VALUE);
+		pm_qos_add_request(&qos_req_list, PM_QOS_CPU_DMA_LATENCY,
+					PM_QOS_DEFAULT_VALUE);
 	}
 
 	mutex_lock(&dd->core_lock);
@@ -2039,6 +2083,7 @@
 	}
 
 	spi_debugfs_init(dd);
+
 	return 0;
 
 err_attrs:
@@ -2069,10 +2114,6 @@
 err_probe_reqmem:
 	destroy_workqueue(dd->workqueue);
 err_probe_workq:
-	msm_spi_free_gpios(dd);
-err_probe_gpio:
-	if (pdata && pdata->gpio_release)
-		pdata->gpio_release();
 err_probe_res:
 	spi_master_put(master);
 err_probe_exit:
@@ -2099,7 +2140,6 @@
 
 	/* Wait for transactions to end, or time out */
 	wait_event_interruptible(dd->continue_suspend, !dd->transfer_pending);
-	msm_spi_free_gpios(dd);
 
 suspend_exit:
 	return 0;
@@ -2116,7 +2156,6 @@
 	if (!dd)
 		goto resume_exit;
 
-	BUG_ON(msm_spi_request_gpios(dd) != 0);
 	dd->suspended = 0;
 resume_exit:
 	return 0;
@@ -2130,17 +2169,13 @@
 {
 	struct spi_master *master = platform_get_drvdata(pdev);
 	struct msm_spi    *dd = spi_master_get_devdata(master);
-	struct msm_spi_platform_data *pdata = pdev->dev.platform_data;
 
 	pm_qos_remove_request(&qos_req_list);
 	spi_debugfs_exit(dd);
 	sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
 
 	msm_spi_teardown_dma(dd);
-	if (pdata && pdata->gpio_release)
-		pdata->gpio_release();
 
-	msm_spi_free_gpios(dd);
 	clk_put(dd->clk);
 	clk_put(dd->pclk);
 	destroy_workqueue(dd->workqueue);
diff --git a/drivers/spi/spi_qsd.h b/drivers/spi/spi_qsd.h
index b0d72b7..a0dee34 100644
--- a/drivers/spi/spi_qsd.h
+++ b/drivers/spi/spi_qsd.h
@@ -322,6 +322,7 @@
 	/* SPI CS GPIOs for each slave */
 	struct spi_cs_gpio       cs_gpios[ARRAY_SIZE(spi_cs_rsrcs)];
 	int                      qup_ver;
+	int			 max_trfr_len;
 };
 
 /* Forward declaration */
diff --git a/drivers/spmi/qpnp-int.c b/drivers/spmi/qpnp-int.c
index b6dfd51..24e35e4 100644
--- a/drivers/spmi/qpnp-int.c
+++ b/drivers/spmi/qpnp-int.c
@@ -253,12 +253,19 @@
 	return rc;
 }
 
+static int qpnpint_irq_set_wake(struct irq_data *d, unsigned int on)
+{
+	return 0;
+}
+
 static struct irq_chip qpnpint_chip = {
 	.name		= "qpnp-int",
 	.irq_mask	= qpnpint_irq_mask,
 	.irq_mask_ack	= qpnpint_irq_mask_ack,
 	.irq_unmask	= qpnpint_irq_unmask,
 	.irq_set_type	= qpnpint_irq_set_type,
+	.irq_set_wake	= qpnpint_irq_set_wake,
+	.flags		= IRQCHIP_MASK_ON_SUSPEND,
 };
 
 static int qpnpint_init_irq_data(struct q_chip_data *chip_d,
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/msm8960_tsens.c b/drivers/thermal/msm8960_tsens.c
index 78a1292..0c49a89 100644
--- a/drivers/thermal/msm8960_tsens.c
+++ b/drivers/thermal/msm8960_tsens.c
@@ -159,6 +159,7 @@
 	enum platform_type		hw_type;
 	int				pm_tsens_thr_data;
 	int				pm_tsens_cntl;
+	struct work_struct		tsens_work;
 	struct tsens_tm_device_sensor	sensor[0];
 };
 
@@ -610,9 +611,10 @@
 					NULL, "type");
 }
 
-static irqreturn_t tsens_isr(int irq, void *data)
+static void tsens_scheduler_fn(struct work_struct *work)
 {
-	struct tsens_tm_device *tm = data;
+	struct tsens_tm_device *tm = container_of(work, struct tsens_tm_device,
+					tsens_work);
 	unsigned int threshold, threshold_low, i, code, reg, sensor, mask;
 	unsigned int sensor_addr;
 	bool upper_th_x, lower_th_x;
@@ -627,6 +629,7 @@
 		writel_relaxed(reg | TSENS_LOWER_STATUS_CLR |
 			TSENS_UPPER_STATUS_CLR, TSENS_CNTL_ADDR);
 	}
+
 	mask = ~(TSENS_LOWER_STATUS_CLR | TSENS_UPPER_STATUS_CLR);
 	threshold = readl_relaxed(TSENS_THRESHOLD_ADDR);
 	threshold_low = (threshold & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
@@ -658,9 +661,7 @@
 				/* Notify user space */
 				schedule_work(&tm->sensor[i].work);
 				adc_code = readl_relaxed(sensor_addr);
-				pr_info("\nTrip point triggered by "
-					"current temperature (%d degrees) "
-					"measured by Temperature-Sensor %d\n",
+				pr_debug("Trigger (%d degrees) for sensor %d\n",
 					tsens_tz_code_to_degC(adc_code, i), i);
 			}
 		}
@@ -672,21 +673,13 @@
 	else
 	writel_relaxed(reg & mask, TSENS_CNTL_ADDR);
 	mb();
-	return IRQ_HANDLED;
 }
 
-static void tsens8960_sensor_mode_init(void)
+static irqreturn_t tsens_isr(int irq, void *data)
 {
-	unsigned int reg_cntl = 0;
+	schedule_work(&tmdev->tsens_work);
 
-	reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
-	if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MDM_9615 ||
-			tmdev->hw_type == APQ_8064) {
-		writel_relaxed(reg_cntl &
-				~((((1 << tmdev->tsens_num_sensor) - 1) >> 1)
-				<< (TSENS_SENSOR0_SHIFT + 1)), TSENS_CNTL_ADDR);
-		tmdev->sensor[TSENS_MAIN_SENSOR].mode = THERMAL_DEVICE_ENABLED;
-	}
+	return IRQ_HANDLED;
 }
 
 #ifdef CONFIG_PM
@@ -869,8 +862,7 @@
 			tmdev->sensor[TSENS_MAIN_SENSOR].calib_data =
 			tmdev->sensor[TSENS_MAIN_SENSOR].calib_data_backup;
 	if (!tmdev->sensor[TSENS_MAIN_SENSOR].calib_data) {
-		pr_err("%s: No temperature sensor data for calibration"
-				" in QFPROM!\n", __func__);
+		pr_err("QFPROM TSENS calibration data not present\n");
 		return -ENODEV;
 	}
 
@@ -901,8 +893,7 @@
 			tmdev->sensor[i].calib_data =
 				tmdev->sensor[i].calib_data_backup;
 		if (!tmdev->sensor[i].calib_data) {
-			WARN(1, "%s: No temperature sensor:%d data for"
-			" calibration in QFPROM!\n", __func__, i);
+			pr_err("QFPROM TSENS calibration data not present\n");
 			return -ENODEV;
 		}
 		tmdev->sensor[i].offset = (TSENS_CAL_DEGC *
@@ -1013,11 +1004,8 @@
 			rc = -ENODEV;
 			goto fail;
 		}
-		tmdev->sensor[i].mode = THERMAL_DEVICE_DISABLED;
 	}
 
-	tsens8960_sensor_mode_init();
-
 	rc = request_irq(TSENS_UPPER_LOWER_INT, tsens_isr,
 		IRQF_TRIGGER_RISING, "tsens_interrupt", tmdev);
 	if (rc < 0) {
@@ -1026,6 +1014,7 @@
 			thermal_zone_device_unregister(tmdev->sensor[i].tz_dev);
 		goto fail;
 	}
+	INIT_WORK(&tmdev->tsens_work, tsens_scheduler_fn);
 
 	pr_debug("%s: OK\n", __func__);
 	mb();
diff --git a/drivers/thermal/msm8974-tsens.c b/drivers/thermal/msm8974-tsens.c
index 2dd698a..7169dc0 100644
--- a/drivers/thermal/msm8974-tsens.c
+++ b/drivers/thermal/msm8974-tsens.c
@@ -60,18 +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_TWO_POINT_CALIB		0x2
+#define TSENS_ONE_POINT_CALIB		0x1
+#define TSENS_ONE_POINT_CALIB_OPTION_2	0x2
+#define TSENS_TWO_POINT_CALIB		0x3
+
+#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
@@ -97,7 +119,7 @@
 #define TSENS_THRESHOLD_MAX_CODE	0x3ff
 #define TSENS_THRESHOLD_MIN_CODE	0x0
 
-#define TSENS_CTRL_INIT_DATA1		0x3fffff9
+#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
@@ -133,6 +155,7 @@
 	int				calib_len;
 	struct resource			*res_tsens_mem;
 	struct resource			*res_calib_mem;
+	struct work_struct		tsens_work;
 	struct tsens_tm_device_sensor	sensor[0];
 };
 
@@ -141,27 +164,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;
@@ -407,9 +429,10 @@
 					NULL, "type");
 }
 
-static irqreturn_t tsens_isr(int irq, void *data)
+static void tsens_scheduler_fn(struct work_struct *work)
 {
-	struct tsens_tm_device *tm = data;
+	struct tsens_tm_device *tm = container_of(work, struct tsens_tm_device,
+						tsens_work);
 	unsigned int i, status, threshold;
 	unsigned int sensor_status_addr, sensor_status_ctrl_addr;
 
@@ -443,6 +466,12 @@
 		sensor_status_ctrl_addr += TSENS_SN_ADDR_OFFSET;
 	}
 	mb();
+}
+
+static irqreturn_t tsens_isr(int irq, void *data)
+{
+	schedule_work(&tmdev->tsens_work);
+
 	return IRQ_HANDLED;
 }
 
@@ -482,53 +511,72 @@
 	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;
+	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;
 
-	if (!tsens_calibration_mode) {
+	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 = 78000;
-			tmdev->sensor[i].calib_data_point1 = 49200;
-			goto compute_intercept_slope;
+			tmdev->sensor[i].calib_data_point2 = 780;
+			tmdev->sensor[i].calib_data_point1 = 492;
 		}
-	} 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;
+		goto compute_intercept_slope;
+	} else if ((tsens_calibration_mode == TSENS_ONE_POINT_CALIB) ||
+			(tsens_calibration_mode == TSENS_TWO_POINT_CALIB)) {
+		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;
+		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);
@@ -537,27 +585,64 @@
 
 	if (tsens_calibration_mode == TSENS_ONE_POINT_CALIB) {
 		tmdev->sensor[0].calib_data_point1 =
-		(((tsens_base1_data + tsens0_point1) << 2) | TSENS_BIT_APPEND);
+		(((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + tsens0_point1;
 		tmdev->sensor[1].calib_data_point1 =
-		(((tsens_base1_data + tsens1_point1) << 2) | TSENS_BIT_APPEND);
+		(((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + tsens1_point1;
 		tmdev->sensor[2].calib_data_point1 =
-		(((tsens_base1_data + tsens2_point1) << 2) | TSENS_BIT_APPEND);
+		(((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + tsens2_point1;
 		tmdev->sensor[3].calib_data_point1 =
-		(((tsens_base1_data + tsens3_point1) << 2) | TSENS_BIT_APPEND);
+		(((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + tsens3_point1;
 		tmdev->sensor[4].calib_data_point1 =
-		(((tsens_base1_data + tsens4_point1) << 2) | TSENS_BIT_APPEND);
+		(((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + tsens4_point1;
 		tmdev->sensor[5].calib_data_point1 =
-		(((tsens_base1_data + tsens5_point1) << 2) | TSENS_BIT_APPEND);
+		(((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + tsens5_point1;
 		tmdev->sensor[6].calib_data_point1 =
-		(((tsens_base1_data + tsens6_point1) << 2) | TSENS_BIT_APPEND);
+		(((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + tsens6_point1;
 		tmdev->sensor[7].calib_data_point1 =
-		(((tsens_base1_data + tsens7_point1) << 2) | TSENS_BIT_APPEND);
+		(((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + tsens7_point1;
 		tmdev->sensor[8].calib_data_point1 =
-		(((tsens_base1_data + tsens8_point1) << 2) | TSENS_BIT_APPEND);
+		(((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + tsens8_point1;
 		tmdev->sensor[9].calib_data_point1 =
-		(((tsens_base1_data + tsens9_point1) << 2) | TSENS_BIT_APPEND);
+		(((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + tsens9_point1;
 		tmdev->sensor[10].calib_data_point1 =
-		(((tsens_base1_data + tsens10_point1) << 2) | TSENS_BIT_APPEND);
+		(((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + tsens10_point1;
+	}
+
+	if ((tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2) ||
+			(tsens_calibration_mode == TSENS_TWO_POINT_CALIB)) {
+		tmdev->sensor[0].calib_data_point1 =
+		((((tsens_base1_data) + tsens0_point1) << 2) |
+						TSENS_BIT_APPEND);
+		tmdev->sensor[1].calib_data_point1 =
+		((((tsens_base1_data) + tsens1_point1) << 2) |
+						TSENS_BIT_APPEND);
+		tmdev->sensor[2].calib_data_point1 =
+		((((tsens_base1_data) + tsens2_point1) << 2) |
+						TSENS_BIT_APPEND);
+		tmdev->sensor[3].calib_data_point1 =
+		((((tsens_base1_data) + tsens3_point1) << 2) |
+						TSENS_BIT_APPEND);
+		tmdev->sensor[4].calib_data_point1 =
+		((((tsens_base1_data) + tsens4_point1) << 2) |
+						TSENS_BIT_APPEND);
+		tmdev->sensor[5].calib_data_point1 =
+		((((tsens_base1_data) + tsens5_point1) << 2) |
+						TSENS_BIT_APPEND);
+		tmdev->sensor[6].calib_data_point1 =
+		((((tsens_base1_data) + tsens6_point1) << 2) |
+						TSENS_BIT_APPEND);
+		tmdev->sensor[7].calib_data_point1 =
+		((((tsens_base1_data) + tsens7_point1) << 2) |
+						TSENS_BIT_APPEND);
+		tmdev->sensor[8].calib_data_point1 =
+		((((tsens_base1_data) + tsens8_point1) << 2) |
+						TSENS_BIT_APPEND);
+		tmdev->sensor[9].calib_data_point1 =
+		((((tsens_base1_data) + tsens9_point1) << 2) |
+						TSENS_BIT_APPEND);
+		tmdev->sensor[10].calib_data_point1 =
+		((((tsens_base1_data) + tsens10_point1) << 2) |
+						TSENS_BIT_APPEND);
 	}
 
 	if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
@@ -580,7 +665,7 @@
 		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);
+		(((tsens_base2_data + tsens9_point2) << 2) | TSENS_BIT_APPEND);
 		tmdev->sensor[10].calib_data_point2 =
 		(((tsens_base2_data + tsens10_point2) << 2) | TSENS_BIT_APPEND);
 	}
@@ -595,10 +680,9 @@
 			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;
 	}
@@ -747,6 +831,7 @@
 		goto fail;
 
 	tsens_hw_init();
+
 	tmdev->prev_reading_avail = true;
 
 	platform_set_drvdata(pdev, tmdev);
@@ -796,6 +881,7 @@
 			goto fail;
 		}
 	}
+
 	rc = request_irq(tmdev->tsens_irq, tsens_isr,
 		IRQF_TRIGGER_RISING, "tsens_interrupt", tmdev);
 	if (rc < 0) {
@@ -806,6 +892,8 @@
 	}
 	platform_set_drvdata(pdev, tmdev);
 
+	INIT_WORK(&tmdev->tsens_work, tsens_scheduler_fn);
+
 	return 0;
 fail:
 	if (tmdev->tsens_calib_addr)
diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile
index 9ebb54a..71f6a99 100644
--- a/drivers/tty/Makefile
+++ b/drivers/tty/Makefile
@@ -6,7 +6,7 @@
 obj-$(CONFIG_MAGIC_SYSRQ)	+= sysrq.o
 obj-$(CONFIG_N_HDLC)		+= n_hdlc.o
 obj-$(CONFIG_N_GSM)		+= n_gsm.o
-obj-$(CONFIG_N_SMUX)		+= n_smux.o
+obj-$(CONFIG_N_SMUX)		+= n_smux.o smux_debug.o
 obj-$(CONFIG_N_SMUX_LOOPBACK)	+= smux_test.o smux_loopback.o
 obj-$(CONFIG_SMUX_CTL)		+= smux_ctl.o
 obj-$(CONFIG_TRACE_ROUTER)	+= n_tracerouter.o
diff --git a/drivers/tty/n_smux.c b/drivers/tty/n_smux.c
index 1385e08..14b8ca2 100644
--- a/drivers/tty/n_smux.c
+++ b/drivers/tty/n_smux.c
@@ -28,12 +28,13 @@
 #include <mach/subsystem_notif.h>
 #include <mach/subsystem_restart.h>
 #include <mach/msm_serial_hs.h>
+#include <mach/msm_ipc_logging.h>
 #include "smux_private.h"
 #include "smux_loopback.h"
 
 #define SMUX_NOTIFY_FIFO_SIZE	128
 #define SMUX_TX_QUEUE_SIZE	256
-#define SMUX_PKT_LOG_SIZE 80
+#define SMUX_PKT_LOG_SIZE 128
 
 /* Maximum size we can accept in a single RX buffer */
 #define TTY_RECEIVE_ROOM 65536
@@ -59,10 +60,12 @@
 	MSM_SMUX_PKT = 1U << 3,
 };
 
-static int smux_debug_mask;
+static int smux_debug_mask = MSM_SMUX_DEBUG | MSM_SMUX_POWER_INFO;
 module_param_named(debug_mask, smux_debug_mask,
 		   int, S_IRUGO | S_IWUSR | S_IWGRP);
 
+static int disable_ipc_logging;
+
 /* Simulated wakeup used for testing */
 int smux_byte_loopback;
 module_param_named(byte_loopback, smux_byte_loopback,
@@ -71,14 +74,24 @@
 module_param_named(simulate_wakeup_delay, smux_simulate_wakeup_delay,
 		   int, S_IRUGO | S_IWUSR | S_IWGRP);
 
+#define IPC_LOG_STR(x...) do { \
+	if (!disable_ipc_logging && log_ctx) \
+		ipc_log_string(log_ctx, x); \
+} while (0)
+
 #define SMUX_DBG(x...) do {                              \
 	if (smux_debug_mask & MSM_SMUX_DEBUG) \
-			pr_info(x);  \
+			IPC_LOG_STR(x);  \
+} while (0)
+
+#define SMUX_ERR(x...) do {                              \
+	pr_err(x); \
+	IPC_LOG_STR(x);  \
 } while (0)
 
 #define SMUX_PWR(x...) do {                              \
 	if (smux_debug_mask & MSM_SMUX_POWER_INFO) \
-			pr_info(x);  \
+			IPC_LOG_STR(x);  \
 } while (0)
 
 #define SMUX_PWR_PKT_RX(pkt) do { \
@@ -90,10 +103,10 @@
 	if (smux_debug_mask & MSM_SMUX_POWER_INFO) { \
 			if (pkt->hdr.cmd == SMUX_CMD_BYTE && \
 					pkt->hdr.flags == SMUX_WAKEUP_ACK) \
-				pr_info("smux: TX Wakeup ACK\n"); \
+				IPC_LOG_STR("smux: TX Wakeup ACK\n"); \
 			else if (pkt->hdr.cmd == SMUX_CMD_BYTE && \
 					pkt->hdr.flags == SMUX_WAKEUP_REQ) \
-				pr_info("smux: TX Wakeup REQ\n"); \
+				IPC_LOG_STR("smux: TX Wakeup REQ\n"); \
 			else \
 				smux_log_pkt(pkt, 0); \
 	} \
@@ -170,59 +183,6 @@
 	SMUX_PWR_OFF_FLUSH,
 };
 
-/**
- * Logical Channel Structure.  One instance per channel.
- *
- * Locking Hierarchy
- * Each lock has a postfix that describes the locking level.  If multiple locks
- * are required, only increasing lock hierarchy numbers may be locked which
- * ensures avoiding a deadlock.
- *
- * Locking Example
- * If state_lock_lhb1 is currently held and the TX list needs to be
- * manipulated, then tx_lock_lhb2 may be locked since it's locking hierarchy
- * is greater.  However, if tx_lock_lhb2 is held, then state_lock_lhb1 may
- * not be acquired since it would result in a deadlock.
- *
- * Note that the Line Discipline locks (*_lha) should always be acquired
- * before the logical channel locks.
- */
-struct smux_lch_t {
-	/* channel state */
-	spinlock_t state_lock_lhb1;
-	uint8_t lcid;
-	unsigned local_state;
-	unsigned local_mode;
-	uint8_t local_tiocm;
-	unsigned options;
-
-	unsigned remote_state;
-	unsigned remote_mode;
-	uint8_t remote_tiocm;
-
-	int tx_flow_control;
-	int rx_flow_control_auto;
-	int rx_flow_control_client;
-
-	/* client callbacks and private data */
-	void *priv;
-	void (*notify)(void *priv, int event_type, const void *metadata);
-	int (*get_rx_buffer)(void *priv, void **pkt_priv, void **buffer,
-								int size);
-
-	/* RX Info */
-	struct list_head rx_retry_queue;
-	unsigned rx_retry_queue_cnt;
-	struct delayed_work rx_retry_work;
-
-	/* TX Info */
-	spinlock_t tx_lock_lhb2;
-	struct list_head tx_queue;
-	struct list_head tx_ready_list;
-	unsigned tx_pending_data_cnt;
-	unsigned notify_lwm;
-};
-
 union notifier_metadata {
 	struct smux_meta_disconnected disconnected;
 	struct smux_meta_read read;
@@ -276,6 +236,7 @@
 	int is_initialized;
 	int platform_devs_registered;
 	int in_reset;
+	int remote_is_alive;
 	int ld_open_count;
 	struct tty_struct *tty;
 
@@ -302,7 +263,7 @@
 
 
 /* data structures */
-static struct smux_lch_t smux_lch[SMUX_NUM_LOGICAL_CHANNELS];
+struct smux_lch_t smux_lch[SMUX_NUM_LOGICAL_CHANNELS];
 static struct smux_ldisc_t smux;
 static const char *tty_error_type[] = {
 	[TTY_NORMAL] = "normal",
@@ -312,7 +273,7 @@
 	[TTY_FRAME] = "framing",
 };
 
-static const char *smux_cmds[] = {
+static const char * const smux_cmds[] = {
 	[SMUX_CMD_DATA] = "DATA",
 	[SMUX_CMD_OPEN_LCH] = "OPEN",
 	[SMUX_CMD_CLOSE_LCH] = "CLOSE",
@@ -321,6 +282,44 @@
 	[SMUX_CMD_BYTE] = "Raw Byte",
 };
 
+static const char * const smux_events[] = {
+	[SMUX_CONNECTED] = "CONNECTED" ,
+	[SMUX_DISCONNECTED] = "DISCONNECTED",
+	[SMUX_READ_DONE] = "READ_DONE",
+	[SMUX_READ_FAIL] = "READ_FAIL",
+	[SMUX_WRITE_DONE] = "WRITE_DONE",
+	[SMUX_WRITE_FAIL] = "WRITE_FAIL",
+	[SMUX_TIOCM_UPDATE] = "TIOCM_UPDATE",
+	[SMUX_LOW_WM_HIT] = "LOW_WM_HIT",
+	[SMUX_HIGH_WM_HIT] = "HIGH_WM_HIT",
+	[SMUX_RX_RETRY_HIGH_WM_HIT] = "RX_RETRY_HIGH_WM_HIT",
+	[SMUX_RX_RETRY_LOW_WM_HIT] = "RX_RETRY_LOW_WM_HIT",
+};
+
+static const char * const smux_local_state[] = {
+	[SMUX_LCH_LOCAL_CLOSED] = "CLOSED",
+	[SMUX_LCH_LOCAL_OPENING] = "OPENING",
+	[SMUX_LCH_LOCAL_OPENED] = "OPENED",
+	[SMUX_LCH_LOCAL_CLOSING] = "CLOSING",
+};
+
+static const char * const smux_remote_state[] = {
+	[SMUX_LCH_REMOTE_CLOSED] = "CLOSED",
+	[SMUX_LCH_REMOTE_OPENED] = "OPENED",
+};
+
+static const char * const smux_mode[] = {
+	[SMUX_LCH_MODE_NORMAL] = "N",
+	[SMUX_LCH_MODE_LOCAL_LOOPBACK] = "L",
+	[SMUX_LCH_MODE_REMOTE_LOOPBACK] = "R",
+};
+
+static const char * const smux_undef[] = {
+	[SMUX_UNDEF_LONG] = "UNDEF",
+	[SMUX_UNDEF_SHORT] = "U",
+};
+
+static void *log_ctx;
 static void smux_notify_local_fn(struct work_struct *work);
 static DECLARE_WORK(smux_notify_local, smux_notify_local_fn);
 
@@ -346,12 +345,11 @@
 static DECLARE_DELAYED_WORK(smux_delayed_inactivity_work,
 		smux_inactivity_worker);
 
-static long msm_smux_tiocm_get_atomic(struct smux_lch_t *ch);
 static void list_channel(struct smux_lch_t *ch);
 static int smux_send_status_cmd(struct smux_lch_t *ch);
 static int smux_dispatch_rx_pkt(struct smux_pkt_t *pkt);
 static void smux_flush_tty(void);
-static void smux_purge_ch_tx_queue(struct smux_lch_t *ch);
+static void smux_purge_ch_tx_queue(struct smux_lch_t *ch, int is_ssr);
 static int schedule_notify(uint8_t lcid, int event,
 			const union notifier_metadata *metadata);
 static int ssr_notifier_cb(struct notifier_block *this,
@@ -363,6 +361,45 @@
 static void smux_pdev_release(struct device *dev);
 
 /**
+ * local_lch_state() - Return human readable form of local logical state.
+ * @state:  Local logical channel state enum.
+ *
+ */
+const char *local_lch_state(unsigned state)
+{
+	if (state < ARRAY_SIZE(smux_local_state))
+		return smux_local_state[state];
+	else
+		return smux_undef[SMUX_UNDEF_LONG];
+}
+
+/**
+ * remote_lch_state() - Return human readable for of remote logical state.
+ * @state:  Remote logical channel state enum.
+ *
+ */
+const char *remote_lch_state(unsigned state)
+{
+	if (state < ARRAY_SIZE(smux_remote_state))
+		return smux_remote_state[state];
+	else
+		return smux_undef[SMUX_UNDEF_LONG];
+}
+
+/**
+ * lch_mode() - Return human readable form of mode.
+ * @mode:  Mode of the logical channel.
+ *
+ */
+const char *lch_mode(unsigned mode)
+{
+	if (mode < ARRAY_SIZE(smux_mode))
+		return smux_mode[mode];
+	else
+		return smux_undef[SMUX_UNDEF_SHORT];
+}
+
+/**
  * Convert TTY Error Flags to string for logging purposes.
  *
  * @flag    TTY_* flag
@@ -389,14 +426,31 @@
 }
 
 /**
+ * Convert SMUX event to string for logging purposes.
+ *
+ * @event    SMUX event
+ * @returns String description or NULL if unknown
+ */
+static const char *event_to_str(unsigned cmd)
+{
+	if (cmd < ARRAY_SIZE(smux_events))
+		return smux_events[cmd];
+	return NULL;
+}
+
+/**
  * Set the reset state due to an unrecoverable failure.
  */
 static void smux_enter_reset(void)
 {
-	pr_err("%s: unrecoverable failure, waiting for ssr\n", __func__);
+	SMUX_ERR("%s: unrecoverable failure, waiting for ssr\n", __func__);
 	smux.in_reset = 1;
+	smux.remote_is_alive = 0;
 }
 
+/**
+ * Initialize the lch_structs.
+ */
 static int lch_init(void)
 {
 	unsigned int id;
@@ -410,7 +464,7 @@
 	smux_rx_wq = create_singlethread_workqueue("smux_rx_wq");
 
 	if (IS_ERR(smux_notify_wq) || IS_ERR(smux_tx_wq)) {
-		SMUX_DBG("%s: create_singlethread_workqueue ENOMEM\n",
+		SMUX_DBG("smux: %s: create_singlethread_workqueue ENOMEM\n",
 							__func__);
 		return -ENOMEM;
 	}
@@ -421,7 +475,7 @@
 	i |= smux_loopback_init();
 
 	if (i) {
-		pr_err("%s: out of memory error\n", __func__);
+		SMUX_ERR("%s: out of memory error\n", __func__);
 		return -ENOMEM;
 	}
 
@@ -471,7 +525,7 @@
 	/* Empty TX ready list */
 	spin_lock_irqsave(&smux.tx_lock_lha2, flags);
 	while (!list_empty(&smux.lch_tx_ready_list)) {
-		SMUX_DBG("%s: emptying ready list %p\n",
+		SMUX_DBG("smux: %s: emptying ready list %p\n",
 				__func__, smux.lch_tx_ready_list.next);
 		ch = list_first_entry(&smux.lch_tx_ready_list,
 						struct smux_lch_t,
@@ -488,7 +542,7 @@
 						struct smux_pkt_t,
 						list);
 		list_del(&pkt->list);
-		SMUX_DBG("%s: emptying power queue pkt=%p\n",
+		SMUX_DBG("smux: %s: emptying power queue pkt=%p\n",
 				__func__, pkt);
 		smux_free_pkt(pkt);
 	}
@@ -497,13 +551,13 @@
 	/* Close all ports */
 	for (i = 0 ; i < SMUX_NUM_LOGICAL_CHANNELS; i++) {
 		ch = &smux_lch[i];
-		SMUX_DBG("%s: cleaning up lcid %d\n", __func__, i);
+		SMUX_DBG("smux: %s: cleaning up lcid %d\n", __func__, i);
 
 		spin_lock_irqsave(&ch->state_lock_lhb1, flags);
 
 		/* Purge TX queue */
 		spin_lock(&ch->tx_lock_lhb2);
-		smux_purge_ch_tx_queue(ch);
+		smux_purge_ch_tx_queue(ch, 1);
 		spin_unlock(&ch->tx_lock_lhb2);
 
 		/* Notify user of disconnect and reset channel state */
@@ -670,7 +724,7 @@
 		i += snprintf(logbuf + i, SMUX_PKT_LOG_SIZE - i,
 				"%02x ", (unsigned)data[count]);
 
-	pr_info("%s\n", logbuf);
+	IPC_LOG_STR(logbuf);
 }
 
 static void smux_notify_local_fn(struct work_struct *work)
@@ -688,8 +742,9 @@
 				&notify_handle,
 				handle_size);
 		if (i != handle_size) {
-			pr_err("%s: unable to retrieve handle %d expected %d\n",
-					__func__, i, handle_size);
+			SMUX_ERR(
+				"%s: unable to retrieve handle %d expected %d\n",
+				__func__, i, handle_size);
 			spin_unlock_irqrestore(&notify_lock_lhc1, flags);
 			break;
 			}
@@ -735,7 +790,7 @@
 	/* Consider a free list implementation instead of kmalloc */
 	pkt = kmalloc(sizeof(struct smux_pkt_t), GFP_ATOMIC);
 	if (!pkt) {
-		pr_err("%s: out of memory\n", __func__);
+		SMUX_ERR("%s: out of memory\n", __func__);
 		return NULL;
 	}
 	smux_init_pkt(pkt);
@@ -779,7 +834,7 @@
 	pkt->payload = kmalloc(pkt->hdr.payload_len, GFP_ATOMIC);
 	pkt->free_payload = 1;
 	if (!pkt->payload) {
-		pr_err("%s: unable to malloc %d bytes for payload\n",
+		SMUX_ERR("%s: unable to malloc %d bytes for payload\n",
 				__func__, pkt->hdr.payload_len);
 		return -ENOMEM;
 	}
@@ -797,11 +852,12 @@
 	unsigned long flags;
 	int ret = 0;
 
+	IPC_LOG_STR("smux: %s ch:%d\n", event_to_str(event), lcid);
 	ch = &smux_lch[lcid];
 	notify_handle = kzalloc(sizeof(struct smux_notify_handle),
 						GFP_ATOMIC);
 	if (!notify_handle) {
-		pr_err("%s: out of memory\n", __func__);
+		SMUX_ERR("%s: out of memory\n", __func__);
 		ret = -ENOMEM;
 		goto free_out;
 	}
@@ -813,7 +869,7 @@
 		meta_copy = kzalloc(sizeof(union notifier_metadata),
 							GFP_ATOMIC);
 		if (!meta_copy) {
-			pr_err("%s: out of memory\n", __func__);
+			SMUX_ERR("%s: out of memory\n", __func__);
 			ret = -ENOMEM;
 			goto free_out;
 		}
@@ -826,7 +882,7 @@
 	spin_lock_irqsave(&notify_lock_lhc1, flags);
 	i = kfifo_avail(&smux_notify_fifo);
 	if (i < handle_size) {
-		pr_err("%s: fifo full error %d expected %d\n",
+		SMUX_ERR("%s: fifo full error %d expected %d\n",
 					__func__, i, handle_size);
 		ret = -ENOMEM;
 		goto unlock_out;
@@ -834,7 +890,7 @@
 
 	i = kfifo_in(&smux_notify_fifo, &notify_handle, handle_size);
 	if (i < 0 || i != handle_size) {
-		pr_err("%s: fifo not available error %d (expected %d)\n",
+		SMUX_ERR("%s: fifo not available error %d (expected %d)\n",
 				__func__, i, handle_size);
 		ret = -ENOSPC;
 		goto unlock_out;
@@ -886,7 +942,7 @@
 	char *data_start = out;
 
 	if (smux_serialize_size(pkt) > SMUX_MAX_PKT_SIZE) {
-		pr_err("%s: packet size %d too big\n",
+		SMUX_ERR("%s: packet size %d too big\n",
 				__func__, smux_serialize_size(pkt));
 		return -E2BIG;
 	}
@@ -971,7 +1027,7 @@
 			len -= data_written;
 			data += data_written;
 		} else {
-			pr_err("%s: TTY write returned error %d\n",
+			SMUX_ERR("%s: TTY write returned error %d\n",
 					__func__, data_written);
 			return data_written;
 		}
@@ -997,12 +1053,12 @@
 	int ret;
 
 	if (!smux.tty) {
-		pr_err("%s: TTY not initialized", __func__);
+		SMUX_ERR("%s: TTY not initialized", __func__);
 		return -ENOTTY;
 	}
 
 	if (pkt->hdr.cmd == SMUX_CMD_BYTE) {
-		SMUX_DBG("%s: tty send single byte\n", __func__);
+		SMUX_DBG("smux: %s: tty send single byte\n", __func__);
 		ret = write_to_tty(&pkt->hdr.flags, 1);
 		return ret;
 	}
@@ -1010,7 +1066,7 @@
 	smux_serialize_hdr(pkt, &data, &len);
 	ret = write_to_tty(data, len);
 	if (ret) {
-		pr_err("%s: failed %d to write header %d\n",
+		SMUX_ERR("%s: failed %d to write header %d\n",
 				__func__, ret, len);
 		return ret;
 	}
@@ -1018,7 +1074,7 @@
 	smux_serialize_payload(pkt, &data, &len);
 	ret = write_to_tty(data, len);
 	if (ret) {
-		pr_err("%s: failed %d to write payload %d\n",
+		SMUX_ERR("%s: failed %d to write payload %d\n",
 				__func__, ret, len);
 		return ret;
 	}
@@ -1028,7 +1084,7 @@
 		char zero = 0x0;
 		ret = write_to_tty(&zero, 1);
 		if (ret) {
-			pr_err("%s: failed %d to write padding %d\n",
+			SMUX_ERR("%s: failed %d to write padding %d\n",
 					__func__, ret, len);
 			return ret;
 		}
@@ -1048,7 +1104,7 @@
 
 	pkt = smux_alloc_pkt();
 	if (!pkt) {
-		pr_err("%s: alloc failure for byte %x\n", __func__, ch);
+		SMUX_ERR("%s: alloc failure for byte %x\n", __func__, ch);
 		return;
 	}
 	pkt->hdr.cmd = SMUX_CMD_BYTE;
@@ -1091,7 +1147,7 @@
 {
 	unsigned long flags;
 
-	SMUX_DBG("%s: queuing pkt %p\n", __func__, pkt_ptr);
+	SMUX_DBG("smux: %s: queuing pkt %p\n", __func__, pkt_ptr);
 
 	spin_lock_irqsave(&ch->tx_lock_lhb2, flags);
 	list_add_tail(&pkt_ptr->list, &ch->tx_queue);
@@ -1120,7 +1176,7 @@
 
 	spin_lock(&ch->state_lock_lhb1);
 	if (ch->local_state == SMUX_LCH_LOCAL_OPENING) {
-		SMUX_DBG("lcid %d local state 0x%x -> 0x%x\n", lcid,
+		SMUX_DBG("smux: lcid %d local state 0x%x -> 0x%x\n", lcid,
 				ch->local_state,
 				SMUX_LCH_LOCAL_OPENED);
 
@@ -1132,10 +1188,10 @@
 			schedule_notify(lcid, SMUX_CONNECTED, NULL);
 		ret = 0;
 	} else if (ch->remote_mode == SMUX_LCH_MODE_REMOTE_LOOPBACK) {
-		SMUX_DBG("Remote loopback OPEN ACK received\n");
+		SMUX_DBG("smux: Remote loopback OPEN ACK received\n");
 		ret = 0;
 	} else {
-		pr_err("%s: lcid %d state 0x%x open ack invalid\n",
+		SMUX_ERR("%s: lcid %d state 0x%x open ack invalid\n",
 				__func__, lcid, ch->local_state);
 		ret = -EINVAL;
 	}
@@ -1145,7 +1201,7 @@
 		spin_lock(&smux.tx_lock_lha2);
 		if (!smux.powerdown_enabled) {
 			smux.powerdown_enabled = 1;
-			SMUX_DBG("%s: enabling power-collapse support\n",
+			SMUX_DBG("smux: %s: enabling power-collapse support\n",
 					__func__);
 		}
 		spin_unlock(&smux.tx_lock_lha2);
@@ -1169,7 +1225,7 @@
 	spin_lock_irqsave(&ch->state_lock_lhb1, flags);
 
 	if (ch->local_state == SMUX_LCH_LOCAL_CLOSING) {
-		SMUX_DBG("lcid %d local state 0x%x -> 0x%x\n", lcid,
+		SMUX_DBG("smux: lcid %d local state 0x%x -> 0x%x\n", lcid,
 				SMUX_LCH_LOCAL_CLOSING,
 				SMUX_LCH_LOCAL_CLOSED);
 		ch->local_state = SMUX_LCH_LOCAL_CLOSED;
@@ -1178,10 +1234,10 @@
 				&meta_disconnected);
 		ret = 0;
 	} else if (ch->remote_mode == SMUX_LCH_MODE_REMOTE_LOOPBACK) {
-		SMUX_DBG("Remote loopback CLOSE ACK received\n");
+		SMUX_DBG("smux: Remote loopback CLOSE ACK received\n");
 		ret = 0;
 	} else {
-		pr_err("%s: lcid %d state 0x%x close ack invalid\n",
+		SMUX_ERR("%s: lcid %d state 0x%x close ack invalid\n",
 				__func__, lcid,	ch->local_state);
 		ret = -EINVAL;
 	}
@@ -1215,7 +1271,7 @@
 	spin_lock_irqsave(&ch->state_lock_lhb1, flags);
 
 	if (ch->remote_state == SMUX_LCH_REMOTE_CLOSED) {
-		SMUX_DBG("lcid %d remote state 0x%x -> 0x%x\n", lcid,
+		SMUX_DBG("smux: lcid %d remote state 0x%x -> 0x%x\n", lcid,
 				SMUX_LCH_REMOTE_CLOSED,
 				SMUX_LCH_REMOTE_OPENED);
 
@@ -1259,15 +1315,16 @@
 				smux_tx_queue(ack_pkt, ch, 0);
 				tx_ready = 1;
 			} else {
-				pr_err("%s: Remote loopack allocation failure\n",
-						__func__);
+				SMUX_ERR(
+					"%s: Remote loopack allocation failure\n",
+					__func__);
 			}
 		} else if (ch->local_state == SMUX_LCH_LOCAL_OPENED) {
 			schedule_notify(lcid, SMUX_CONNECTED, NULL);
 		}
 		ret = 0;
 	} else {
-		pr_err("%s: lcid %d remote state 0x%x open invalid\n",
+		SMUX_ERR("%s: lcid %d remote state 0x%x open invalid\n",
 			   __func__, lcid, ch->remote_state);
 		ret = -EINVAL;
 	}
@@ -1279,7 +1336,7 @@
 		spin_lock_irqsave(&smux.tx_lock_lha2, flags);
 		if (!smux.powerdown_enabled) {
 			smux.powerdown_enabled = 1;
-			SMUX_DBG("%s: enabling power-collapse support\n",
+			SMUX_DBG("smux: %s: enabling power-collapse support\n",
 					__func__);
 		}
 		spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
@@ -1317,7 +1374,7 @@
 
 	spin_lock_irqsave(&ch->state_lock_lhb1, flags);
 	if (ch->remote_state == SMUX_LCH_REMOTE_OPENED) {
-		SMUX_DBG("lcid %d remote state 0x%x -> 0x%x\n", lcid,
+		SMUX_DBG("smux: lcid %d remote state 0x%x -> 0x%x\n", lcid,
 				SMUX_LCH_REMOTE_OPENED,
 				SMUX_LCH_REMOTE_CLOSED);
 
@@ -1351,8 +1408,9 @@
 				smux_tx_queue(ack_pkt, ch, 0);
 				tx_ready = 1;
 			} else {
-				pr_err("%s: Remote loopack allocation failure\n",
-						__func__);
+				SMUX_ERR(
+					"%s: Remote loopack allocation failure\n",
+					__func__);
 			}
 		}
 
@@ -1361,7 +1419,7 @@
 				&meta_disconnected);
 		ret = 0;
 	} else {
-		pr_err("%s: lcid %d remote state 0x%x close invalid\n",
+		SMUX_ERR("%s: lcid %d remote state 0x%x close invalid\n",
 				__func__, lcid, ch->remote_state);
 		ret = -EINVAL;
 	}
@@ -1412,7 +1470,7 @@
 
 	if (ch->local_state != SMUX_LCH_LOCAL_OPENED
 		&& !remote_loopback) {
-		pr_err("smux: ch %d error data on local state 0x%x",
+		SMUX_ERR("smux: ch %d error data on local state 0x%x",
 					lcid, ch->local_state);
 		ret = -EIO;
 		spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
@@ -1420,7 +1478,7 @@
 	}
 
 	if (ch->remote_state != SMUX_LCH_REMOTE_OPENED) {
-		pr_err("smux: ch %d error data on remote state 0x%x",
+		SMUX_ERR("smux: ch %d error data on remote state 0x%x",
 					lcid, ch->remote_state);
 		ret = -EIO;
 		spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
@@ -1441,8 +1499,9 @@
 		}
 		if ((ch->rx_retry_queue_cnt + 1) > SMUX_RX_RETRY_MAX_PKTS) {
 			/* retry queue full */
-			pr_err("%s: ch %d RX retry queue full\n",
-					__func__, lcid);
+			SMUX_ERR(
+				"%s: ch %d RX retry queue full; rx flow=%d\n",
+				__func__, lcid, ch->rx_flow_control_auto);
 			schedule_notify(lcid, SMUX_READ_FAIL, NULL);
 			ret = -ENOMEM;
 			spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
@@ -1468,7 +1527,7 @@
 			smux_tx_queue(ack_pkt, ch, 0);
 			tx_ready = 1;
 		} else {
-			pr_err("%s: Remote loopack allocation failure\n",
+			SMUX_ERR("%s: Remote loopack allocation failure\n",
 					__func__);
 		}
 	} else if (!do_retry) {
@@ -1492,7 +1551,7 @@
 			/* buffer allocation failed - add to retry queue */
 			do_retry = 1;
 		} else if (tmp < 0) {
-			pr_err("%s: ch %d Client RX buffer alloc failed %d\n",
+			SMUX_ERR("%s: ch %d Client RX buffer alloc failed %d\n",
 					__func__, lcid, tmp);
 			schedule_notify(lcid, SMUX_READ_FAIL, NULL);
 			ret = -ENOMEM;
@@ -1504,7 +1563,7 @@
 
 		retry = kmalloc(sizeof(struct smux_rx_pkt_retry), GFP_KERNEL);
 		if (!retry) {
-			pr_err("%s: retry alloc failure\n", __func__);
+			SMUX_ERR("%s: retry alloc failure\n", __func__);
 			ret = -ENOMEM;
 			schedule_notify(lcid, SMUX_READ_FAIL, NULL);
 			goto out;
@@ -1516,7 +1575,7 @@
 		retry->pkt = smux_alloc_pkt();
 		if (!retry->pkt) {
 			kfree(retry);
-			pr_err("%s: pkt alloc failure\n", __func__);
+			SMUX_ERR("%s: pkt alloc failure\n", __func__);
 			ret = -ENOMEM;
 			schedule_notify(lcid, SMUX_READ_FAIL, NULL);
 			goto out;
@@ -1562,7 +1621,7 @@
 	unsigned long flags;
 
 	if (!pkt || smux_assert_lch_id(pkt->hdr.lcid)) {
-		pr_err("%s: invalid packet or channel id\n", __func__);
+		SMUX_ERR("%s: invalid packet or channel id\n", __func__);
 		return -ENXIO;
 	}
 
@@ -1571,14 +1630,14 @@
 	spin_lock_irqsave(&ch->state_lock_lhb1, flags);
 
 	if (ch->local_state != SMUX_LCH_LOCAL_OPENED) {
-		pr_err("smux: ch %d error data on local state 0x%x",
+		SMUX_ERR("smux: ch %d error data on local state 0x%x",
 					lcid, ch->local_state);
 		ret = -EIO;
 		goto out;
 	}
 
 	if (ch->remote_state != SMUX_LCH_REMOTE_OPENED) {
-		pr_err("smux: ch %d error data on remote state 0x%x",
+		SMUX_ERR("smux: ch %d error data on remote state 0x%x",
 					lcid, ch->remote_state);
 		ret = -EIO;
 		goto out;
@@ -1623,11 +1682,11 @@
 		/* logical channel flow control changed */
 		if (pkt->hdr.flags & SMUX_CMD_STATUS_FLOW_CNTL) {
 			/* disabled TX */
-			SMUX_DBG("TX Flow control enabled\n");
+			SMUX_DBG("smux: TX Flow control enabled\n");
 			ch->tx_flow_control = 1;
 		} else {
 			/* re-enable channel */
-			SMUX_DBG("TX Flow control disabled\n");
+			SMUX_DBG("smux: TX Flow control disabled\n");
 			ch->tx_flow_control = 0;
 			tx_ready = 1;
 		}
@@ -1671,7 +1730,7 @@
 			/* Power-down complete, turn off UART */
 			power_down = 1;
 		else
-			pr_err("%s: sleep request ack invalid in state %d\n",
+			SMUX_ERR("%s: sleep request ack invalid in state %d\n",
 					__func__, smux.power_state);
 	} else {
 		/*
@@ -1690,7 +1749,7 @@
 		if (smux.power_state == SMUX_PWR_ON) {
 			ack_pkt = smux_alloc_pkt();
 			if (ack_pkt) {
-				SMUX_PWR("%s: Power %d->%d\n", __func__,
+				SMUX_PWR("smux: %s: Power %d->%d\n", __func__,
 						smux.power_state,
 						SMUX_PWR_TURNING_OFF_FLUSH);
 
@@ -1706,7 +1765,7 @@
 			}
 		} else if (smux.power_state == SMUX_PWR_TURNING_OFF_FLUSH) {
 			/* Local power-down request still in TX queue */
-			SMUX_PWR("%s: Power-down shortcut - no ack\n",
+			SMUX_PWR("smux: %s: Power-down shortcut - no ack\n",
 					__func__);
 			smux.power_ctl_remote_req_received = 1;
 		} else if (smux.power_state == SMUX_PWR_TURNING_OFF) {
@@ -1714,17 +1773,17 @@
 			 * Local power-down request already sent to remote
 			 * side, so this request gets treated as an ACK.
 			 */
-			SMUX_PWR("%s: Power-down shortcut - no ack\n",
+			SMUX_PWR("smux: %s: Power-down shortcut - no ack\n",
 					__func__);
 			power_down = 1;
 		} else {
-			pr_err("%s: sleep request invalid in state %d\n",
+			SMUX_ERR("%s: sleep request invalid in state %d\n",
 					__func__, smux.power_state);
 		}
 	}
 
 	if (power_down) {
-		SMUX_PWR("%s: Power %d->%d\n", __func__,
+		SMUX_PWR("smux: %s: Power %d->%d\n", __func__,
 				smux.power_state, SMUX_PWR_OFF_FLUSH);
 		smux.power_state = SMUX_PWR_OFF_FLUSH;
 		queue_work(smux_tx_wq, &smux_inactivity_work);
@@ -1749,7 +1808,7 @@
 	case SMUX_CMD_OPEN_LCH:
 		SMUX_LOG_PKT_RX(pkt);
 		if (smux_assert_lch_id(pkt->hdr.lcid)) {
-			pr_err("%s: invalid channel id %d\n",
+			SMUX_ERR("%s: invalid channel id %d\n",
 					__func__, pkt->hdr.lcid);
 			break;
 		}
@@ -1759,7 +1818,7 @@
 	case SMUX_CMD_DATA:
 		SMUX_LOG_PKT_RX(pkt);
 		if (smux_assert_lch_id(pkt->hdr.lcid)) {
-			pr_err("%s: invalid channel id %d\n",
+			SMUX_ERR("%s: invalid channel id %d\n",
 					__func__, pkt->hdr.lcid);
 			break;
 		}
@@ -1769,7 +1828,7 @@
 	case SMUX_CMD_CLOSE_LCH:
 		SMUX_LOG_PKT_RX(pkt);
 		if (smux_assert_lch_id(pkt->hdr.lcid)) {
-			pr_err("%s: invalid channel id %d\n",
+			SMUX_ERR("%s: invalid channel id %d\n",
 					__func__, pkt->hdr.lcid);
 			break;
 		}
@@ -1779,7 +1838,7 @@
 	case SMUX_CMD_STATUS:
 		SMUX_LOG_PKT_RX(pkt);
 		if (smux_assert_lch_id(pkt->hdr.lcid)) {
-			pr_err("%s: invalid channel id %d\n",
+			SMUX_ERR("%s: invalid channel id %d\n",
 					__func__, pkt->hdr.lcid);
 			break;
 		}
@@ -1797,7 +1856,7 @@
 
 	default:
 		SMUX_LOG_PKT_RX(pkt);
-		pr_err("%s: command %d unknown\n", __func__, pkt->hdr.cmd);
+		SMUX_ERR("%s: command %d unknown\n", __func__, pkt->hdr.cmd);
 		ret = -EINVAL;
 	}
 	return ret;
@@ -1824,7 +1883,7 @@
 	memcpy(&recv.hdr, data, sizeof(struct smux_hdr_t));
 
 	if (recv.hdr.magic != SMUX_MAGIC) {
-		pr_err("%s: invalid header magic\n", __func__);
+		SMUX_ERR("%s: invalid header magic\n", __func__);
 		return -EINVAL;
 	}
 
@@ -1845,7 +1904,7 @@
 	if (smux.power_state == SMUX_PWR_OFF
 		|| smux.power_state == SMUX_PWR_TURNING_ON) {
 		/* wakeup system */
-		SMUX_PWR("%s: Power %d->%d\n", __func__,
+		SMUX_PWR("smux: %s: Power %d->%d\n", __func__,
 				smux.power_state, SMUX_PWR_ON);
 		smux.power_state = SMUX_PWR_ON;
 		queue_work(smux_tx_wq, &smux_wakeup_work);
@@ -1857,7 +1916,7 @@
 		smux_send_byte(SMUX_WAKEUP_ACK);
 	} else {
 		/* stale wakeup request from previous wakeup */
-		SMUX_PWR("%s: stale Wakeup REQ in state %d\n",
+		SMUX_PWR("smux: %s: stale Wakeup REQ in state %d\n",
 				__func__, smux.power_state);
 	}
 	spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
@@ -1873,7 +1932,7 @@
 	spin_lock_irqsave(&smux.tx_lock_lha2, flags);
 	if (smux.power_state == SMUX_PWR_TURNING_ON) {
 		/* received response to wakeup request */
-		SMUX_PWR("%s: Power %d->%d\n", __func__,
+		SMUX_PWR("smux: %s: Power %d->%d\n", __func__,
 				smux.power_state, SMUX_PWR_ON);
 		smux.power_state = SMUX_PWR_ON;
 		queue_work(smux_tx_wq, &smux_tx_work);
@@ -1882,7 +1941,7 @@
 
 	} else if (smux.power_state != SMUX_PWR_ON) {
 		/* invalid message */
-		SMUX_PWR("%s: stale Wakeup REQ ACK in state %d\n",
+		SMUX_PWR("smux: %s: stale Wakeup REQ ACK in state %d\n",
 				__func__, smux.power_state);
 	}
 	spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
@@ -1905,7 +1964,7 @@
 		if (smux_byte_loopback)
 			smux_receive_byte(SMUX_UT_ECHO_ACK_FAIL,
 					smux_byte_loopback);
-		pr_err("%s: TTY error 0x%x - ignoring\n", __func__, flag);
+		SMUX_ERR("%s: TTY error 0x%x - ignoring\n", __func__, flag);
 		++*used;
 		return;
 	}
@@ -1916,11 +1975,21 @@
 			smux.rx_state = SMUX_RX_MAGIC;
 			break;
 		case SMUX_WAKEUP_REQ:
-			SMUX_PWR("smux: RX Wakeup REQ\n");
+			SMUX_PWR("smux: smux: RX Wakeup REQ\n");
+			if (unlikely(!smux.remote_is_alive)) {
+				mutex_lock(&smux.mutex_lha0);
+				smux.remote_is_alive = 1;
+				mutex_unlock(&smux.mutex_lha0);
+			}
 			smux_handle_wakeup_req();
 			break;
 		case SMUX_WAKEUP_ACK:
-			SMUX_PWR("smux: RX Wakeup ACK\n");
+			SMUX_PWR("smux: smux: RX Wakeup ACK\n");
+			if (unlikely(!smux.remote_is_alive)) {
+				mutex_lock(&smux.mutex_lha0);
+				smux.remote_is_alive = 1;
+				mutex_unlock(&smux.mutex_lha0);
+			}
 			smux_handle_wakeup_ack();
 			break;
 		default:
@@ -1928,8 +1997,8 @@
 			if (smux_byte_loopback && data[i] == SMUX_UT_ECHO_REQ)
 				smux_receive_byte(SMUX_UT_ECHO_ACK_OK,
 						smux_byte_loopback);
-			pr_err("%s: parse error 0x%02x - ignoring\n", __func__,
-					(unsigned)data[i]);
+			SMUX_ERR("%s: parse error 0x%02x - ignoring\n",
+				__func__, (unsigned)data[i]);
 			break;
 		}
 	}
@@ -1951,7 +2020,7 @@
 	int i;
 
 	if (flag) {
-		pr_err("%s: TTY RX error %d\n", __func__, flag);
+		SMUX_ERR("%s: TTY RX error %d\n", __func__, flag);
 		smux_enter_reset();
 		smux.rx_state = SMUX_RX_FAILURE;
 		++*used;
@@ -1967,8 +2036,9 @@
 			smux.rx_state = SMUX_RX_HDR;
 		} else {
 			/* unexpected / trash character */
-			pr_err("%s: rx parse error for char %c; *used=%d, len=%d\n",
-					__func__, data[i], *used, len);
+			SMUX_ERR(
+				"%s: rx parse error for char %c; *used=%d, len=%d\n",
+				__func__, data[i], *used, len);
 			smux.rx_state = SMUX_RX_IDLE;
 		}
 	}
@@ -1991,7 +2061,7 @@
 	struct smux_hdr_t *hdr;
 
 	if (flag) {
-		pr_err("%s: TTY RX error %d\n", __func__, flag);
+		SMUX_ERR("%s: TTY RX error %d\n", __func__, flag);
 		smux_enter_reset();
 		smux.rx_state = SMUX_RX_FAILURE;
 		++*used;
@@ -2025,7 +2095,7 @@
 	int remaining;
 
 	if (flag) {
-		pr_err("%s: TTY RX error %d\n", __func__, flag);
+		SMUX_ERR("%s: TTY RX error %d\n", __func__, flag);
 		smux_enter_reset();
 		smux.rx_state = SMUX_RX_FAILURE;
 		++*used;
@@ -2073,6 +2143,24 @@
 }
 
 /**
+ * Returns true if the remote side has acknowledged a wakeup
+ * request previously, so we know that the link is alive and active.
+ *
+ * @returns true for is alive, false for not alive
+ */
+bool smux_remote_is_active(void)
+{
+	bool is_active = false;
+
+	mutex_lock(&smux.mutex_lha0);
+	if (smux.remote_is_alive)
+		is_active = true;
+	mutex_unlock(&smux.mutex_lha0);
+
+	return is_active;
+}
+
+/**
  * Add channel to transmit-ready list and trigger transmit worker.
  *
  * @ch Channel to add
@@ -2081,7 +2169,7 @@
 {
 	unsigned long flags;
 
-	SMUX_DBG("%s: listing channel %d\n",
+	SMUX_DBG("smux: %s: listing channel %d\n",
 			__func__, ch->lcid);
 
 	spin_lock_irqsave(&smux.tx_lock_lha2, flags);
@@ -2120,11 +2208,11 @@
 			meta_write.write.buffer = pkt->payload;
 			meta_write.write.len = pkt->hdr.payload_len;
 			if (ret >= 0) {
-				SMUX_DBG("%s: PKT write done", __func__);
+				SMUX_DBG("smux: %s: PKT write done", __func__);
 				schedule_notify(ch->lcid, SMUX_WRITE_DONE,
 						&meta_write);
 			} else {
-				pr_err("%s: failed to write pkt %d\n",
+				SMUX_ERR("%s: failed to write pkt %d\n",
 						__func__, ret);
 				schedule_notify(ch->lcid, SMUX_WRITE_FAIL,
 						&meta_write);
@@ -2140,7 +2228,7 @@
 {
 	mutex_lock(&smux.mutex_lha0);
 	if (!smux.tty) {
-		pr_err("%s: ldisc not loaded\n", __func__);
+		SMUX_ERR("%s: ldisc not loaded\n", __func__);
 		mutex_unlock(&smux.mutex_lha0);
 		return;
 	}
@@ -2149,7 +2237,7 @@
 			msecs_to_jiffies(TTY_BUFFER_FULL_WAIT_MS));
 
 	if (tty_chars_in_buffer(smux.tty) > 0)
-		pr_err("%s: unable to flush UART queue\n", __func__);
+		SMUX_ERR("%s: unable to flush UART queue\n", __func__);
 
 	mutex_unlock(&smux.mutex_lha0);
 }
@@ -2158,25 +2246,35 @@
  * Purge TX queue for logical channel.
  *
  * @ch     Logical channel pointer
+ * @is_ssr 1 = this is a subsystem restart purge
  *
  * Must be called with the following spinlocks locked:
  *  state_lock_lhb1
  *  tx_lock_lhb2
  */
-static void smux_purge_ch_tx_queue(struct smux_lch_t *ch)
+static void smux_purge_ch_tx_queue(struct smux_lch_t *ch, int is_ssr)
 {
 	struct smux_pkt_t *pkt;
 	int send_disconnect = 0;
+	struct smux_pkt_t *pkt_tmp;
+	int is_state_pkt;
 
-	while (!list_empty(&ch->tx_queue)) {
-		pkt = list_first_entry(&ch->tx_queue, struct smux_pkt_t,
-							list);
-		list_del(&pkt->list);
-
+	list_for_each_entry_safe(pkt, pkt_tmp, &ch->tx_queue, list) {
+		is_state_pkt = 0;
 		if (pkt->hdr.cmd == SMUX_CMD_OPEN_LCH) {
-			/* Open was never sent, just force to closed state */
-			ch->local_state = SMUX_LCH_LOCAL_CLOSED;
-			send_disconnect = 1;
+			if (pkt->hdr.flags & SMUX_CMD_OPEN_ACK) {
+				/* Open ACK must still be sent */
+				is_state_pkt = 1;
+			} else {
+				/* Open never sent -- force to closed state */
+				ch->local_state = SMUX_LCH_LOCAL_CLOSED;
+				send_disconnect = 1;
+			}
+		} else if (pkt->hdr.cmd == SMUX_CMD_CLOSE_LCH) {
+			if (pkt->hdr.flags & SMUX_CMD_CLOSE_ACK)
+				is_state_pkt = 1;
+			if (!send_disconnect)
+				is_state_pkt = 1;
 		} else if (pkt->hdr.cmd == SMUX_CMD_DATA) {
 			/* Notify client of failed write */
 			union notifier_metadata meta_write;
@@ -2186,7 +2284,11 @@
 			meta_write.write.len = pkt->hdr.payload_len;
 			schedule_notify(ch->lcid, SMUX_WRITE_FAIL, &meta_write);
 		}
-		smux_free_pkt(pkt);
+
+		if (!is_state_pkt || is_ssr) {
+			list_del(&pkt->list);
+			smux_free_pkt(pkt);
+		}
 	}
 
 	if (send_disconnect) {
@@ -2208,7 +2310,7 @@
 	struct uart_state *state;
 
 	if (!smux.tty || !smux.tty->driver_data) {
-		pr_err("%s: unable to find UART port for tty %p\n",
+		SMUX_ERR("%s: unable to find UART port for tty %p\n",
 				__func__, smux.tty);
 		return;
 	}
@@ -2236,7 +2338,7 @@
 	struct uart_state *state;
 
 	if (!smux.tty || !smux.tty->driver_data) {
-		pr_err("%s: unable to find UART port for tty %p\n",
+		SMUX_ERR("%s: unable to find UART port for tty %p\n",
 				__func__, smux.tty);
 		mutex_unlock(&smux.mutex_lha0);
 		return;
@@ -2276,7 +2378,7 @@
 		/* wakeup complete */
 		smux.pwr_wakeup_delay_us = 1;
 		spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
-		SMUX_DBG("%s: wakeup complete\n", __func__);
+		SMUX_DBG("smux: %s: wakeup complete\n", __func__);
 
 		/*
 		 * Cancel any pending retry.  This avoids a race condition with
@@ -2296,17 +2398,18 @@
 				SMUX_WAKEUP_DELAY_MAX;
 
 		spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
-		SMUX_PWR("%s: triggering wakeup\n", __func__);
+		SMUX_PWR("smux: %s: triggering wakeup\n", __func__);
 		smux_send_byte(SMUX_WAKEUP_REQ);
 
 		if (wakeup_delay < SMUX_WAKEUP_DELAY_MIN) {
-			SMUX_DBG("%s: sleeping for %u us\n", __func__,
+			SMUX_DBG("smux: %s: sleeping for %u us\n", __func__,
 					wakeup_delay);
 			usleep_range(wakeup_delay, 2*wakeup_delay);
 			queue_work(smux_tx_wq, &smux_wakeup_work);
 		} else {
 			/* schedule delayed work */
-			SMUX_DBG("%s: scheduling delayed wakeup in %u ms\n",
+			SMUX_DBG(
+			"smux: %s: scheduling delayed wakeup in %u ms\n",
 					__func__, wakeup_delay / 1000);
 			queue_delayed_work(smux_tx_wq,
 					&smux_wakeup_delayed_work,
@@ -2316,7 +2419,7 @@
 		/* wakeup aborted */
 		smux.pwr_wakeup_delay_us = 1;
 		spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
-		SMUX_PWR("%s: wakeup aborted\n", __func__);
+		SMUX_PWR("smux: %s: wakeup aborted\n", __func__);
 		cancel_delayed_work(&smux_wakeup_delayed_work);
 	}
 }
@@ -2346,7 +2449,8 @@
 				/* start power-down sequence */
 				pkt = smux_alloc_pkt();
 				if (pkt) {
-					SMUX_PWR("%s: Power %d->%d\n", __func__,
+					SMUX_PWR(
+					"smux: %s: Power %d->%d\n", __func__,
 						smux.power_state,
 						SMUX_PWR_TURNING_OFF_FLUSH);
 					smux.power_state =
@@ -2360,7 +2464,7 @@
 							&smux.power_queue);
 					queue_work(smux_tx_wq, &smux_tx_work);
 				} else {
-					pr_err("%s: packet alloc failed\n",
+					SMUX_ERR("%s: packet alloc failed\n",
 							__func__);
 				}
 			}
@@ -2371,7 +2475,7 @@
 
 	if (smux.power_state == SMUX_PWR_OFF_FLUSH) {
 		/* ready to power-down the UART */
-		SMUX_PWR("%s: Power %d->%d\n", __func__,
+		SMUX_PWR("smux: %s: Power %d->%d\n", __func__,
 				smux.power_state, SMUX_PWR_OFF);
 		smux.power_state = SMUX_PWR_OFF;
 
@@ -2452,16 +2556,16 @@
 	smux.rx_activity_flag = 1;
 	spin_unlock_irqrestore(&smux.rx_lock_lha1, flags);
 
-	SMUX_DBG("%s: %p, len=%d, flag=%d\n", __func__, data, len, flag);
+	SMUX_DBG("smux: %s: %p, len=%d, flag=%d\n", __func__, data, len, flag);
 	used = 0;
 	do {
 		if (smux.in_reset) {
-			SMUX_DBG("%s: abort RX due to reset\n", __func__);
+			SMUX_DBG("smux: %s: abort RX due to reset\n", __func__);
 			smux.rx_state = SMUX_RX_IDLE;
 			break;
 		}
 
-		SMUX_DBG("%s: state %d; %d of %d\n",
+		SMUX_DBG("smux: %s: state %d; %d of %d\n",
 				__func__, smux.rx_state, used, len);
 		initial_rx_state = smux.rx_state;
 
@@ -2479,7 +2583,7 @@
 			smux_rx_handle_pkt_payload(data, len, &used, flag);
 			break;
 		default:
-			SMUX_DBG("%s: invalid state %d\n",
+			SMUX_DBG("smux: %s: invalid state %d\n",
 					__func__, smux.rx_state);
 			smux.rx_state = SMUX_RX_IDLE;
 			break;
@@ -2520,7 +2624,7 @@
 	}
 
 	if (list_empty(&ch->rx_retry_queue)) {
-		SMUX_DBG("%s: retry list empty for channel %d\n",
+		SMUX_DBG("smux: %s: retry list empty for channel %d\n",
 				__func__, ch->lcid);
 		spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
 		return;
@@ -2530,7 +2634,7 @@
 					rx_retry_list);
 	spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
 
-	SMUX_DBG("%s: ch %d retrying rx pkt %p\n",
+	SMUX_DBG("smux: %s: ch %d retrying rx pkt %p\n",
 			__func__, ch->lcid, retry);
 	metadata.read.pkt_priv = 0;
 	metadata.read.buffer = 0;
@@ -2559,7 +2663,7 @@
 		retry->timeout_in_ms <<= 1;
 		if (retry->timeout_in_ms > SMUX_RX_RETRY_MAX_MS) {
 			/* timed out */
-			pr_err("%s: ch %d RX retry client timeout\n",
+			SMUX_ERR("%s: ch %d RX retry client timeout\n",
 					__func__, ch->lcid);
 			spin_lock_irqsave(&ch->state_lock_lhb1, flags);
 			tx_ready = smux_remove_rx_retry(ch, retry);
@@ -2570,7 +2674,7 @@
 		}
 	} else {
 		/* client error - drop packet */
-		pr_err("%s: ch %d RX retry client failed (%d)\n",
+		SMUX_ERR("%s: ch %d RX retry client failed (%d)\n",
 				__func__, ch->lcid, tmp);
 		spin_lock_irqsave(&ch->state_lock_lhb1, flags);
 		tx_ready = smux_remove_rx_retry(ch, retry);
@@ -2635,7 +2739,7 @@
 			if (!list_empty(&smux.lch_tx_ready_list) ||
 			   !list_empty(&smux.power_queue)) {
 				/* data to transmit, do wakeup */
-				SMUX_PWR("%s: Power %d->%d\n", __func__,
+				SMUX_PWR("smux: %s: Power %d->%d\n", __func__,
 						smux.power_state,
 						SMUX_PWR_TURNING_ON);
 				smux.power_state = SMUX_PWR_TURNING_ON;
@@ -2669,7 +2773,8 @@
 					 * and we already received a remote
 					 * power-down request.
 					 */
-					SMUX_PWR("%s: Power %d->%d\n", __func__,
+					SMUX_PWR(
+					"smux: %s: Power %d->%d\n", __func__,
 							smux.power_state,
 							SMUX_PWR_OFF_FLUSH);
 					smux.power_state = SMUX_PWR_OFF_FLUSH;
@@ -2678,7 +2783,8 @@
 							&smux_inactivity_work);
 				} else {
 					/* sending local power-down request */
-					SMUX_PWR("%s: Power %d->%d\n", __func__,
+					SMUX_PWR(
+					"smux: %s: Power %d->%d\n", __func__,
 							smux.power_state,
 							SMUX_PWR_TURNING_OFF);
 					smux.power_state = SMUX_PWR_TURNING_OFF;
@@ -2704,7 +2810,7 @@
 		/* get the next ready channel */
 		if (list_empty(&smux.lch_tx_ready_list)) {
 			/* no ready channels */
-			SMUX_DBG("%s: no more ready channels, exiting\n",
+			SMUX_DBG("smux: %s: no more ready channels, exiting\n",
 					__func__);
 			spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
 			break;
@@ -2713,7 +2819,7 @@
 
 		if (smux.power_state != SMUX_PWR_ON) {
 			/* channel not ready to transmit */
-			SMUX_DBG("%s: waiting for link up (state %d)\n",
+			SMUX_DBG("smux: %s: waiting for link up (state %d)\n",
 					__func__,
 					smux.power_state);
 			spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
@@ -2824,11 +2930,11 @@
 {
 	smux.in_reset = 1;
 
-	SMUX_DBG("%s: flushing tx wq\n", __func__);
+	SMUX_DBG("smux: %s: flushing tx wq\n", __func__);
 	flush_workqueue(smux_tx_wq);
-	SMUX_DBG("%s: flushing rx wq\n", __func__);
+	SMUX_DBG("smux: %s: flushing rx wq\n", __func__);
 	flush_workqueue(smux_rx_wq);
-	SMUX_DBG("%s: flushing notify wq\n", __func__);
+	SMUX_DBG("smux: %s: flushing notify wq\n", __func__);
 	flush_workqueue(smux_notify_wq);
 }
 
@@ -2886,13 +2992,13 @@
 
 	/* Auto RX Flow Control */
 	if (set & SMUX_CH_OPTION_AUTO_REMOTE_TX_STOP) {
-		SMUX_DBG("%s: auto rx flow control option enabled\n",
+		SMUX_DBG("smux: %s: auto rx flow control option enabled\n",
 			__func__);
 		ch->options |= SMUX_CH_OPTION_AUTO_REMOTE_TX_STOP;
 	}
 
 	if (clear & SMUX_CH_OPTION_AUTO_REMOTE_TX_STOP) {
-		SMUX_DBG("%s: auto rx flow control option disabled\n",
+		SMUX_DBG("smux: %s: auto rx flow control option disabled\n",
 			__func__);
 		ch->options &= ~SMUX_CH_OPTION_AUTO_REMOTE_TX_STOP;
 		ch->rx_flow_control_auto = 0;
@@ -2947,13 +3053,13 @@
 	}
 
 	if (ch->local_state != SMUX_LCH_LOCAL_CLOSED) {
-		pr_err("%s: open lcid %d local state %x invalid\n",
+		SMUX_ERR("%s: open lcid %d local state %x invalid\n",
 				__func__, lcid, ch->local_state);
 		ret = -EINVAL;
 		goto out;
 	}
 
-	SMUX_DBG("lcid %d local state 0x%x -> 0x%x\n", lcid,
+	SMUX_DBG("smux: lcid %d local state 0x%x -> 0x%x\n", lcid,
 			ch->local_state,
 			SMUX_LCH_LOCAL_OPENING);
 
@@ -3017,16 +3123,17 @@
 	ch->remote_tiocm = 0x0;
 	ch->tx_pending_data_cnt = 0;
 	ch->notify_lwm = 0;
+	ch->tx_flow_control = 0;
 
 	/* Purge TX queue */
 	spin_lock(&ch->tx_lock_lhb2);
-	smux_purge_ch_tx_queue(ch);
+	smux_purge_ch_tx_queue(ch, 0);
 	spin_unlock(&ch->tx_lock_lhb2);
 
 	/* Send Close Command */
 	if (ch->local_state == SMUX_LCH_LOCAL_OPENED ||
 		ch->local_state == SMUX_LCH_LOCAL_OPENING) {
-		SMUX_DBG("lcid %d local state 0x%x -> 0x%x\n", lcid,
+		SMUX_DBG("smux: lcid %d local state 0x%x -> 0x%x\n", lcid,
 				ch->local_state,
 				SMUX_LCH_LOCAL_CLOSING);
 
@@ -3041,7 +3148,7 @@
 			smux_tx_queue(pkt, ch, 0);
 			tx_ready = 1;
 		} else {
-			pr_err("%s: pkt allocation failed\n", __func__);
+			SMUX_ERR("%s: pkt allocation failed\n", __func__);
 			ret = -ENOMEM;
 		}
 
@@ -3091,14 +3198,14 @@
 
 	if (ch->local_state != SMUX_LCH_LOCAL_OPENED &&
 		ch->local_state != SMUX_LCH_LOCAL_OPENING) {
-		pr_err("%s: hdr.invalid local state %d channel %d\n",
+		SMUX_ERR("%s: hdr.invalid local state %d channel %d\n",
 					__func__, ch->local_state, lcid);
 		ret = -EINVAL;
 		goto out;
 	}
 
 	if (len > SMUX_MAX_PKT_SIZE - sizeof(struct smux_hdr_t)) {
-		pr_err("%s: payload %d too large\n",
+		SMUX_ERR("%s: payload %d too large\n",
 				__func__, len);
 		ret = -E2BIG;
 		goto out;
@@ -3120,10 +3227,10 @@
 
 	spin_lock(&ch->tx_lock_lhb2);
 	/* verify high watermark */
-	SMUX_DBG("%s: pending %d", __func__, ch->tx_pending_data_cnt);
+	SMUX_DBG("smux: %s: pending %d", __func__, ch->tx_pending_data_cnt);
 
 	if (ch->tx_pending_data_cnt >= SMUX_TX_WM_HIGH) {
-		pr_err("%s: ch %d high watermark %d exceeded %d\n",
+		SMUX_ERR("%s: ch %d high watermark %d exceeded %d\n",
 				__func__, lcid, SMUX_TX_WM_HIGH,
 				ch->tx_pending_data_cnt);
 		ret = -EAGAIN;
@@ -3133,7 +3240,7 @@
 	/* queue packet for transmit */
 	if (++ch->tx_pending_data_cnt == SMUX_TX_WM_HIGH) {
 		ch->notify_lwm = 1;
-		pr_err("%s: high watermark hit\n", __func__);
+		SMUX_ERR("%s: high watermark hit\n", __func__);
 		schedule_notify(lcid, SMUX_HIGH_WM_HIT, NULL);
 	}
 	list_add_tail(&pkt->list, &ch->tx_queue);
@@ -3251,7 +3358,7 @@
  *
  * @returns TIOCM status
  */
-static long msm_smux_tiocm_get_atomic(struct smux_lch_t *ch)
+long msm_smux_tiocm_get_atomic(struct smux_lch_t *ch)
 {
 	long status = 0x0;
 
@@ -3369,24 +3476,26 @@
 	int power_off_uart = 0;
 
 	if (code == SUBSYS_BEFORE_SHUTDOWN) {
-		SMUX_DBG("%s: ssr - before shutdown\n", __func__);
+		SMUX_DBG("smux: %s: ssr - before shutdown\n", __func__);
 		mutex_lock(&smux.mutex_lha0);
 		smux.in_reset = 1;
+		smux.remote_is_alive = 0;
 		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__);
+		SMUX_DBG("smux: %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",
+				SMUX_DBG("smux: %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",
+					SMUX_ERR(
+						"%s: error %d registering device %s\n",
 					   __func__, tmp, smux_devs[i].name);
 			}
 			smux.platform_devs_registered = 1;
@@ -3396,7 +3505,7 @@
 	} else if (code != SUBSYS_AFTER_SHUTDOWN) {
 		return NOTIFY_DONE;
 	}
-	SMUX_DBG("%s: ssr - after shutdown\n", __func__);
+	SMUX_DBG("smux: %s: ssr - after shutdown\n", __func__);
 
 	/* Cleanup channels */
 	smux_flush_workqueues();
@@ -3409,7 +3518,7 @@
 		/* Unregister platform devices */
 		if (smux.platform_devs_registered) {
 			for (i = 0; i < ARRAY_SIZE(smux_devs); ++i) {
-				SMUX_DBG("%s: unregister pdev '%s'\n",
+				SMUX_DBG("smux: %s: unregister pdev '%s'\n",
 						__func__, smux_devs[i].name);
 				platform_device_unregister(&smux_devs[i]);
 			}
@@ -3419,7 +3528,8 @@
 		/* 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_PWR("smux: %s: SSR - turning off UART\n",
+							__func__);
 			smux.power_state = SMUX_PWR_OFF;
 			power_off_uart = 1;
 		}
@@ -3433,6 +3543,7 @@
 	smux.rx_activity_flag = 0;
 	smux.rx_state = SMUX_RX_IDLE;
 	smux.in_reset = 0;
+	smux.remote_is_alive = 0;
 	mutex_unlock(&smux.mutex_lha0);
 
 	return NOTIFY_DONE;
@@ -3446,7 +3557,8 @@
 	struct platform_device *pdev;
 
 	pdev = container_of(dev, struct platform_device, dev);
-	SMUX_DBG("%s: releasing pdev %p '%s'\n", __func__, pdev, pdev->name);
+	SMUX_DBG("smux: %s: releasing pdev %p '%s'\n",
+			__func__, pdev, pdev->name);
 	memset(&pdev->dev, 0x0, sizeof(pdev->dev));
 }
 
@@ -3461,14 +3573,14 @@
 
 	mutex_lock(&smux.mutex_lha0);
 	if (smux.ld_open_count) {
-		pr_err("%s: %p multiple instances not supported\n",
+		SMUX_ERR("%s: %p multiple instances not supported\n",
 			__func__, tty);
 		mutex_unlock(&smux.mutex_lha0);
 		return -EEXIST;
 	}
 
 	if (tty->ops->write == NULL) {
-		pr_err("%s: tty->ops->write already NULL\n", __func__);
+		SMUX_ERR("%s: tty->ops->write already NULL\n", __func__);
 		mutex_unlock(&smux.mutex_lha0);
 		return -EINVAL;
 	}
@@ -3484,7 +3596,7 @@
 	/* power-down the UART if we are idle */
 	spin_lock_irqsave(&smux.tx_lock_lha2, flags);
 	if (smux.power_state == SMUX_PWR_OFF) {
-		SMUX_PWR("%s: powering off uart\n", __func__);
+		SMUX_PWR("smux: %s: powering off uart\n", __func__);
 		smux.power_state = SMUX_PWR_OFF_FLUSH;
 		spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
 		queue_work(smux_tx_wq, &smux_inactivity_work);
@@ -3494,12 +3606,12 @@
 
 	/* register platform devices */
 	for (i = 0; i < ARRAY_SIZE(smux_devs); ++i) {
-		SMUX_DBG("%s: register pdev '%s'\n",
+		SMUX_DBG("smux: %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",
+			SMUX_ERR("%s: error %d registering device %s\n",
 				   __func__, tmp, smux_devs[i].name);
 	}
 	smux.platform_devs_registered = 1;
@@ -3513,12 +3625,12 @@
 	int power_up_uart = 0;
 	int i;
 
-	SMUX_DBG("%s: ldisc unload\n", __func__);
+	SMUX_DBG("smux: %s: ldisc unload\n", __func__);
 	smux_flush_workqueues();
 
 	mutex_lock(&smux.mutex_lha0);
 	if (smux.ld_open_count <= 0) {
-		pr_err("%s: invalid ld count %d\n", __func__,
+		SMUX_ERR("%s: invalid ld count %d\n", __func__,
 			smux.ld_open_count);
 		mutex_unlock(&smux.mutex_lha0);
 		return;
@@ -3531,7 +3643,7 @@
 	/* Unregister platform devices */
 	if (smux.platform_devs_registered) {
 		for (i = 0; i < ARRAY_SIZE(smux_devs); ++i) {
-			SMUX_DBG("%s: unregister pdev '%s'\n",
+			SMUX_DBG("smux: %s: unregister pdev '%s'\n",
 					__func__, smux_devs[i].name);
 			platform_device_unregister(&smux_devs[i]);
 		}
@@ -3555,8 +3667,9 @@
 
 	/* Disconnect from TTY */
 	smux.tty = NULL;
+	smux.remote_is_alive = 0;
 	mutex_unlock(&smux.mutex_lha0);
-	SMUX_DBG("%s: ldisc complete\n", __func__);
+	SMUX_DBG("smux: %s: ldisc complete\n", __func__);
 }
 
 /**
@@ -3575,16 +3688,12 @@
 	const char *tty_name = NULL;
 	char *f;
 
-	if (smux_debug_mask & MSM_SMUX_DEBUG)
-		print_hex_dump(KERN_INFO, "smux tty rx: ", DUMP_PREFIX_OFFSET,
-				     16, 1, cp, count, true);
-
 	/* verify error flags */
 	for (i = 0, f = fp; i < count; ++i, ++f) {
 		if (*f != TTY_NORMAL) {
 			if (tty)
 				tty_name = tty->name;
-			pr_err("%s: TTY %s Error %d (%s)\n", __func__,
+			SMUX_ERR("%s: TTY %s Error %d (%s)\n", __func__,
 				   tty_name, *f, tty_flag_to_str(*f));
 
 			/* feed all previous valid data to the parser */
@@ -3603,46 +3712,46 @@
 
 static void smuxld_flush_buffer(struct tty_struct *tty)
 {
-	pr_err("%s: not supported\n", __func__);
+	SMUX_ERR("%s: not supported\n", __func__);
 }
 
 static ssize_t	smuxld_chars_in_buffer(struct tty_struct *tty)
 {
-	pr_err("%s: not supported\n", __func__);
+	SMUX_ERR("%s: not supported\n", __func__);
 	return -ENODEV;
 }
 
 static ssize_t	smuxld_read(struct tty_struct *tty, struct file *file,
 		unsigned char __user *buf, size_t nr)
 {
-	pr_err("%s: not supported\n", __func__);
+	SMUX_ERR("%s: not supported\n", __func__);
 	return -ENODEV;
 }
 
 static ssize_t	smuxld_write(struct tty_struct *tty, struct file *file,
 		 const unsigned char *buf, size_t nr)
 {
-	pr_err("%s: not supported\n", __func__);
+	SMUX_ERR("%s: not supported\n", __func__);
 	return -ENODEV;
 }
 
 static int	smuxld_ioctl(struct tty_struct *tty, struct file *file,
 		 unsigned int cmd, unsigned long arg)
 {
-	pr_err("%s: not supported\n", __func__);
+	SMUX_ERR("%s: not supported\n", __func__);
 	return -ENODEV;
 }
 
 static unsigned int smuxld_poll(struct tty_struct *tty, struct file *file,
 			 struct poll_table_struct *tbl)
 {
-	pr_err("%s: not supported\n", __func__);
+	SMUX_ERR("%s: not supported\n", __func__);
 	return -ENODEV;
 }
 
 static void smuxld_write_wakeup(struct tty_struct *tty)
 {
-	pr_err("%s: not supported\n", __func__);
+	SMUX_ERR("%s: not supported\n", __func__);
 }
 
 static struct tty_ldisc_ops smux_ldisc_ops = {
@@ -3680,6 +3789,7 @@
 	smux.tty = NULL;
 	smux.ld_open_count = 0;
 	smux.in_reset = 0;
+	smux.remote_is_alive = 0;
 	smux.is_initialized = 1;
 	smux.platform_devs_registered = 0;
 	smux_byte_loopback = 0;
@@ -3689,7 +3799,7 @@
 
 	ret	= tty_register_ldisc(N_SMUX, &smux_ldisc_ops);
 	if (ret != 0) {
-		pr_err("%s: error %d registering line discipline\n",
+		SMUX_ERR("%s: error %d registering line discipline\n",
 				__func__, ret);
 		return ret;
 	}
@@ -3698,10 +3808,16 @@
 
 	ret = lch_init();
 	if (ret != 0) {
-		pr_err("%s: lch_init failed\n", __func__);
+		SMUX_ERR("%s: lch_init failed\n", __func__);
 		return ret;
 	}
 
+	log_ctx = ipc_log_context_create(1, "smux");
+	if (!log_ctx) {
+		SMUX_ERR("%s: unable to create log context\n", __func__);
+		disable_ipc_logging = 1;
+	}
+
 	return 0;
 }
 
@@ -3711,7 +3827,7 @@
 
 	ret	= tty_unregister_ldisc(N_SMUX);
 	if (ret != 0) {
-		pr_err("%s error %d unregistering line discipline\n",
+		SMUX_ERR("%s error %d unregistering line discipline\n",
 				__func__, ret);
 		return;
 	}
diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c
index a5235ba..e6f5bf5 100644
--- a/drivers/tty/serial/msm_serial.c
+++ b/drivers/tty/serial/msm_serial.c
@@ -503,7 +503,7 @@
 
 	if (msm_port->uim) {
 		msm_write(port,
-			UART_SIM_CFG_STOP_BIT_LEN_N(1) |
+			UART_SIM_CFG_STOP_BIT_LEN_N(2) |
 			UART_SIM_CFG_SIM_CLK_ON |
 			UART_SIM_CFG_SIM_CLK_STOP_HIGH |
 			UART_SIM_CFG_MASK_RX |
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index 1904706..4a9c9a3 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -174,7 +174,7 @@
 #define UARTDM_TX_BUF_SIZE UART_XMIT_SIZE
 #define UARTDM_RX_BUF_SIZE 512
 #define RETRY_TIMEOUT 5
-#define UARTDM_NR 5
+#define UARTDM_NR 256
 
 static struct dentry *debug_base;
 static struct msm_hs_port q_uart_port[UARTDM_NR];
@@ -484,8 +484,9 @@
  * Goal is to have around 8 ms before indicate stale.
  * roundup (((Bit Rate * .008) / 10) + 1
  */
-static void msm_hs_set_bps_locked(struct uart_port *uport,
-			       unsigned int bps)
+static unsigned long msm_hs_set_bps_locked(struct uart_port *uport,
+			       unsigned int bps,
+				unsigned long flags)
 {
 	unsigned long rxstale;
 	unsigned long data;
@@ -584,11 +585,16 @@
 	} else {
 		uport->uartclk = 7372800;
 	}
+
+	spin_unlock_irqrestore(&uport->lock, flags);
 	if (clk_set_rate(msm_uport->clk, uport->uartclk)) {
 		printk(KERN_WARNING "Error setting clock rate on UART\n");
-		return;
+		WARN_ON(1);
+		spin_lock_irqsave(&uport->lock, flags);
+		return flags;
 	}
 
+	spin_lock_irqsave(&uport->lock, flags);
 	data = rxstale & UARTDM_IPR_STALE_LSB_BMSK;
 	data |= UARTDM_IPR_STALE_TIMEOUT_MSB_BMSK & (rxstale << 2);
 
@@ -600,6 +606,7 @@
 	 */
 	msm_hs_write(uport, UARTDM_CR_ADDR, RESET_TX);
 	msm_hs_write(uport, UARTDM_CR_ADDR, RESET_RX);
+	return flags;
 }
 
 
@@ -668,6 +675,7 @@
 	unsigned int c_cflag = termios->c_cflag;
 	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
 
+	mutex_lock(&msm_uport->clk_mutex);
 	spin_lock_irqsave(&uport->lock, flags);
 
 	/*
@@ -694,7 +702,7 @@
 	if (!uport->uartclk)
 		msm_hs_set_std_bps_locked(uport, bps);
 	else
-		msm_hs_set_bps_locked(uport, bps);
+		flags = msm_hs_set_bps_locked(uport, bps, flags);
 
 	data = msm_hs_read(uport, UARTDM_MR2_ADDR);
 	data &= ~UARTDM_MR2_PARITY_MODE_BMSK;
@@ -777,6 +785,7 @@
 	msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg);
 	mb();
 	spin_unlock_irqrestore(&uport->lock, flags);
+	mutex_unlock(&msm_uport->clk_mutex);
 }
 
 /*
@@ -2016,6 +2025,8 @@
 	msm_serial_debugfs_init(msm_uport, pdev->id);
 
 	uport->line = pdev->id;
+	if (pdata != NULL && pdata->userid && pdata->userid <= UARTDM_NR)
+		uport->line = pdata->userid;
 	return uart_add_one_port(&msm_hs_driver, uport);
 }
 
@@ -2122,7 +2133,6 @@
 	free_irq(uport->irq, msm_uport);
 	if (use_low_power_wakeup(msm_uport))
 		free_irq(msm_uport->wakeup.irq, msm_uport);
-	mutex_destroy(&msm_uport->clk_mutex);
 }
 
 static void __exit msm_serial_hs_exit(void)
diff --git a/drivers/tty/smux_debug.c b/drivers/tty/smux_debug.c
new file mode 100644
index 0000000..86377d6
--- /dev/null
+++ b/drivers/tty/smux_debug.c
@@ -0,0 +1,170 @@
+/* drivers/tty/smux_debug.c
+ *
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/debugfs.h>
+#include <linux/list.h>
+#include <linux/ctype.h>
+#include <linux/jiffies.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/completion.h>
+#include <linux/termios.h>
+#include <linux/smux.h>
+#include "smux_private.h"
+
+#define DEBUG_BUFMAX 4096
+
+
+
+/**
+ * smux_dump_ch() - Dumps the information of a channel to the screen.
+ * @buf:  Buffer for status message.
+ * @max: Size of status queue.
+ * @lch_number:  Number of the logical channel.
+ * @lch:  Pointer to the lch_number'th instance of struct smux_lch_t.
+ *
+ */
+static int smux_dump_ch(char *buf, int max, struct smux_lch_t *lch)
+{
+	int bytes_written;
+	long tiocm_bits;
+	unsigned long flags;
+
+	spin_lock_irqsave(&lch->state_lock_lhb1, flags);
+	spin_lock(&lch->tx_lock_lhb2);
+
+	tiocm_bits = msm_smux_tiocm_get_atomic(lch);
+
+	bytes_written = scnprintf(
+		buf, max,
+		"ch%02d: "
+		"%s(%s) "
+		"%c%c%c%c%c  "
+		"%d  "
+		"%s(%s) "
+		"%c%c\n",
+		lch->lcid,
+		local_lch_state(lch->local_state), lch_mode(lch->local_mode),
+		(tiocm_bits & TIOCM_DSR) ? 'D' : 'd',
+		(tiocm_bits & TIOCM_CTS) ? 'T' : 't',
+		(tiocm_bits & TIOCM_RI) ? 'I' : 'i',
+		(tiocm_bits & TIOCM_CD) ? 'C' : 'c',
+		lch->tx_flow_control ? 'F' : 'f',
+		lch->tx_pending_data_cnt,
+		remote_lch_state(lch->remote_state), lch_mode(lch->remote_mode),
+		(tiocm_bits & TIOCM_DTR) ? 'R' : 'r',
+		(tiocm_bits & TIOCM_RTS) ? 'S' : 's'
+		);
+
+	spin_unlock(&lch->tx_lock_lhb2);
+	spin_unlock_irqrestore(&lch->state_lock_lhb1, flags);
+
+	return bytes_written;
+}
+
+/**
+ * smux_dump_format_ch() - Informs user of format for channel dump
+ * @buf:  Buffer for status message.
+ * @max:  Size of status queue.
+ *
+ */
+static int smux_dump_format_ch(char *buf, int max)
+{
+	return scnprintf(
+		buf, max,
+		"ch_id "
+		"local state(mode) tiocm  "
+		"tx_queue  "
+		"remote state(mode) tiocm\n"
+		"local tiocm: DSR(D) CTS(T) RI(I) DCD(C) FLOW_CONTROL(F)\n"
+		"remote tiocm: DTR(R) RTS(S)\n"
+		"A capital letter indicates set, otherwise, it is not set.\n\n"
+		);
+}
+
+/**
+ * smux_debug_ch() - Log following information about each channel
+ * local open, local mode, remote open, remote mode,
+ * tiocm bits, flow control state and transmit queue size.
+ * Returns the number of bytes written to buf.
+ * @buf Buffer for status message
+ * @max Size of status queue
+ *
+ */
+static int smux_debug_ch(char *buf, int max)
+{
+	int ch_id;
+
+	int bytes_written = smux_dump_format_ch(buf, max);
+
+	for (ch_id = 0; ch_id < SMUX_NUM_LOGICAL_CHANNELS; ch_id++) {
+		bytes_written += smux_dump_ch(buf + bytes_written,
+					max - bytes_written,
+					&smux_lch[ch_id]);
+	}
+
+	return bytes_written;
+
+}
+
+static char debug_buffer[DEBUG_BUFMAX];
+
+static ssize_t debug_read(struct file *file, char __user *buf,
+			  size_t count, loff_t *ppos)
+{
+	int (*fill)(char *buf, int max) = file->private_data;
+	int bsize;
+
+	if (*ppos != 0)
+		return 0;
+
+	bsize = fill(debug_buffer, DEBUG_BUFMAX);
+	return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize);
+}
+
+static int debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static const struct file_operations debug_ops = {
+	.read = debug_read,
+	.open = debug_open,
+};
+
+
+static void debug_create(const char *name, mode_t mode,
+			struct dentry *dent,
+			int (*fill)(char *buf, int max))
+{
+	debugfs_create_file(name, mode, dent, fill, &debug_ops);
+}
+
+
+static int __init smux_debugfs_init(void)
+{
+	struct dentry *dent;
+
+	dent = debugfs_create_dir("n_smux", 0);
+	if (IS_ERR(dent))
+		return PTR_ERR(dent);
+
+	debug_create("ch", 0444, dent, smux_debug_ch);
+
+
+	return 0;
+}
+
+late_initcall(smux_debugfs_init);
diff --git a/drivers/tty/smux_private.h b/drivers/tty/smux_private.h
index 353c762..195ee0f 100644
--- a/drivers/tty/smux_private.h
+++ b/drivers/tty/smux_private.h
@@ -31,14 +31,70 @@
 #define SMUX_UT_ECHO_ACK_FAIL 0xF2
 
 /* Maximum number of packets in retry queue */
-#define SMUX_RX_RETRY_MAX_PKTS 32
-#define SMUX_RX_WM_HIGH        16
-#define SMUX_RX_WM_LOW          4
-#define SMUX_TX_WM_LOW          2
-#define SMUX_TX_WM_HIGH         4
+#define SMUX_RX_RETRY_MAX_PKTS 128
+#define SMUX_RX_WM_HIGH          4
+#define SMUX_RX_WM_LOW           0
+#define SMUX_TX_WM_LOW           2
+#define SMUX_TX_WM_HIGH          4
 
 struct tty_struct;
 
+/**
+ * Logical Channel Structure.  One instance per channel.
+ *
+ * Locking Hierarchy
+ * Each lock has a postfix that describes the locking level.  If multiple locks
+ * are required, only increasing lock hierarchy numbers may be locked which
+ * ensures avoiding a deadlock.
+ *
+ * Locking Example
+ * If state_lock_lhb1 is currently held and the TX list needs to be
+ * manipulated, then tx_lock_lhb2 may be locked since it's locking hierarchy
+ * is greater.  However, if tx_lock_lhb2 is held, then state_lock_lhb1 may
+ * not be acquired since it would result in a deadlock.
+ *
+ * Note that the Line Discipline locks (*_lha) should always be acquired
+ * before the logical channel locks.
+ */
+struct smux_lch_t {
+	/* channel state */
+	spinlock_t state_lock_lhb1;
+	uint8_t lcid;
+	unsigned local_state;
+	unsigned local_mode;
+	uint8_t local_tiocm;
+	unsigned options;
+
+	unsigned remote_state;
+	unsigned remote_mode;
+	uint8_t remote_tiocm;
+
+	int tx_flow_control;
+	int rx_flow_control_auto;
+	int rx_flow_control_client;
+
+	/* client callbacks and private data */
+	void *priv;
+	void (*notify)(void *priv, int event_type, const void *metadata);
+	int (*get_rx_buffer)(void *priv, void **pkt_priv, void **buffer,
+								int size);
+
+	/* RX Info */
+	struct list_head rx_retry_queue;
+	unsigned rx_retry_queue_cnt;
+	struct delayed_work rx_retry_work;
+
+	/* TX Info */
+	spinlock_t tx_lock_lhb2;
+	struct list_head tx_queue;
+	struct list_head tx_ready_list;
+	unsigned tx_pending_data_cnt;
+	unsigned notify_lwm;
+};
+
+/* Each instance of smux_lch_t */
+extern struct smux_lch_t smux_lch[SMUX_NUM_LOGICAL_CHANNELS];
+
 /* Packet header. */
 struct smux_hdr_t {
 	uint16_t magic;
@@ -102,6 +158,16 @@
 	SMUX_LCH_REMOTE_OPENED,
 };
 
+/* Enum used to report various undefined actions */
+enum {
+	SMUX_UNDEF_LONG,
+	SMUX_UNDEF_SHORT,
+};
+
+long msm_smux_tiocm_get_atomic(struct smux_lch_t *ch);
+const char *local_lch_state(unsigned state);
+const char *remote_lch_state(unsigned state);
+const char *lch_mode(unsigned mode);
 
 int smux_assert_lch_id(uint32_t lcid);
 void smux_init_pkt(struct smux_pkt_t *pkt);
@@ -114,6 +180,7 @@
 void smux_rx_state_machine(const unsigned char *data, int len, int flag);
 void smuxld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
 			   char *fp, int count);
+bool smux_remote_is_active(void);
 
 /* testing parameters */
 extern int smux_byte_loopback;
diff --git a/drivers/tty/smux_test.c b/drivers/tty/smux_test.c
index 4c255a4..81ac04b 100644
--- a/drivers/tty/smux_test.c
+++ b/drivers/tty/smux_test.c
@@ -690,6 +690,7 @@
 	};
 	int i = 0;
 	int failed = 0;
+	int retry_count = 0;
 	int ret;
 
 	i += scnprintf(buf + i, max - i, "Running %s\n", __func__);
@@ -701,7 +702,13 @@
 
 		i += smux_ut_basic_core(buf + i, max - i, test_data, __func__);
 		subsystem_restart("external_modem");
-		msleep(5000);
+
+		do {
+			msleep(500);
+			++retry_count;
+			UT_ASSERT_INT(retry_count, <, 20);
+		} while (!smux_remote_is_active() && !failed);
+
 		i += smux_ut_basic_core(buf + i, max - i, test_data, __func__);
 		break;
 	}
@@ -721,6 +728,7 @@
 	static struct smux_mock_callback cb_data;
 	static int cb_initialized;
 	int ret;
+	int retry_count;
 	int i = 0;
 	int failed = 0;
 
@@ -763,6 +771,14 @@
 		/* close port */
 		ret = msm_smux_close(SMUX_TEST_LCID);
 		UT_ASSERT_INT(ret, ==, 0);
+
+		/* wait for remote side to finish booting */
+		retry_count = 0;
+		do {
+			msleep(500);
+			++retry_count;
+			UT_ASSERT_INT(retry_count, <, 20);
+		} while (!smux_remote_is_active() && !failed);
 		break;
 	}
 
@@ -795,6 +811,7 @@
 	static int cb_initialized;
 	int i = 0;
 	int failed = 0;
+	int retry_count;
 	int ret;
 
 	i += scnprintf(buf + i, max - i, "Running %s\n", __func__);
@@ -841,12 +858,16 @@
 		subsystem_restart("external_modem");
 
 		/* verify SSR completed */
-		UT_ASSERT_INT(ret, ==, 0);
-		UT_ASSERT_INT(
-			(int)wait_for_completion_timeout(
-				&cb_data.cb_completion, 5*HZ),
-			>, 0);
-		UT_ASSERT_INT(cb_data.cb_count, ==, 1);
+		retry_count = 0;
+		while (cb_data.event_disconnected_ssr == 0) {
+			(void)wait_for_completion_timeout(
+				&cb_data.cb_completion, HZ);
+			INIT_COMPLETION(cb_data.cb_completion);
+			++retry_count;
+			UT_ASSERT_INT(retry_count, <, 10);
+		}
+		if (failed)
+			break;
 		UT_ASSERT_INT(cb_data.event_disconnected, ==, 1);
 		UT_ASSERT_INT(cb_data.event_disconnected_ssr, ==, 1);
 		mock_cb_data_reset(&cb_data);
@@ -854,6 +875,14 @@
 		/* close port */
 		ret = msm_smux_close(SMUX_TEST_LCID);
 		UT_ASSERT_INT(ret, ==, 0);
+
+		/* wait for remote side to finish booting */
+		retry_count = 0;
+		do {
+			msleep(500);
+			++retry_count;
+			UT_ASSERT_INT(retry_count, <, 20);
+		} while (!smux_remote_is_active() && !failed);
 		break;
 	}
 
@@ -1924,6 +1953,136 @@
 	return i;
 }
 
+/**
+ * Verify remote flow control (remote TX stop).
+ *
+ * @buf  Buffer for status message
+ * @max  Size of buffer
+ *
+ * @returns Number of bytes written to @buf
+ */
+static int smux_ut_remote_tx_stop(char *buf, int max)
+{
+	static struct smux_mock_callback cb_data;
+	static int cb_initialized;
+	int i = 0;
+	int failed = 0;
+	int ret;
+
+	i += scnprintf(buf + i, max - i, "Running %s\n", __func__);
+	pr_err("%s", buf);
+
+	if (!cb_initialized)
+		mock_cb_data_init(&cb_data);
+
+	mock_cb_data_reset(&cb_data);
+	while (!failed) {
+		/* open port for remote loopback */
+		ret = msm_smux_set_ch_option(SMUX_TEST_LCID,
+				SMUX_CH_OPTION_REMOTE_LOOPBACK, 0);
+		UT_ASSERT_INT(ret, ==, 0);
+
+		ret = msm_smux_open(SMUX_TEST_LCID, &cb_data, smux_mock_cb,
+								get_rx_buffer);
+		UT_ASSERT_INT(ret, ==, 0);
+		UT_ASSERT_INT(
+				(int)wait_for_completion_timeout(
+					&cb_data.cb_completion, HZ), >, 0);
+		UT_ASSERT_INT(cb_data.cb_count, ==, 1);
+		UT_ASSERT_INT(cb_data.event_connected, ==, 1);
+		mock_cb_data_reset(&cb_data);
+
+		/* send 1 packet and verify response */
+		ret = msm_smux_write(SMUX_TEST_LCID, (void *)1,
+					test_array, sizeof(test_array));
+		UT_ASSERT_INT(ret, ==, 0);
+		UT_ASSERT_INT(
+			(int)wait_for_completion_timeout(
+				&cb_data.cb_completion, HZ),
+			>, 0);
+		UT_ASSERT_INT(cb_data.event_write_done, ==, 1);
+
+		INIT_COMPLETION(cb_data.cb_completion);
+		if (!cb_data.event_read_done) {
+			UT_ASSERT_INT(
+				(int)wait_for_completion_timeout(
+					&cb_data.cb_completion, HZ),
+				>, 0);
+		}
+		UT_ASSERT_INT(cb_data.event_read_done, ==, 1);
+		mock_cb_data_reset(&cb_data);
+
+		/* enable flow control */
+		UT_ASSERT_INT(smux_lch[SMUX_TEST_LCID].tx_flow_control, ==, 0);
+		ret = msm_smux_set_ch_option(SMUX_TEST_LCID,
+				SMUX_CH_OPTION_REMOTE_TX_STOP, 0);
+		UT_ASSERT_INT(ret, ==, 0);
+
+		/* wait for remote echo and clear our tx_flow control */
+		msleep(500);
+		UT_ASSERT_INT(smux_lch[SMUX_TEST_LCID].tx_flow_control, ==, 1);
+		smux_lch[SMUX_TEST_LCID].tx_flow_control = 0;
+
+		/* Send 1 packet and verify no response */
+		ret = msm_smux_write(SMUX_TEST_LCID, (void *)2,
+					test_array, sizeof(test_array));
+		UT_ASSERT_INT(ret, ==, 0);
+		UT_ASSERT_INT(
+			(int)wait_for_completion_timeout(
+				&cb_data.cb_completion, HZ),
+				>, 0);
+		INIT_COMPLETION(cb_data.cb_completion);
+		UT_ASSERT_INT(cb_data.event_write_done, ==, 1);
+		UT_ASSERT_INT(cb_data.event_read_done, ==, 0);
+		UT_ASSERT_INT(cb_data.cb_count, ==, 1);
+
+		UT_ASSERT_INT(
+			(int)wait_for_completion_timeout(
+				&cb_data.cb_completion, 1*HZ),
+			==, 0);
+		UT_ASSERT_INT(cb_data.event_read_done, ==, 0);
+		mock_cb_data_reset(&cb_data);
+
+		/* disable flow control and verify response is received */
+		UT_ASSERT_INT(cb_data.event_read_done, ==, 0);
+		ret = msm_smux_set_ch_option(SMUX_TEST_LCID,
+				0, SMUX_CH_OPTION_REMOTE_TX_STOP);
+		UT_ASSERT_INT(ret, ==, 0);
+
+		UT_ASSERT_INT(
+			(int)wait_for_completion_timeout(
+				&cb_data.cb_completion, HZ),
+			>, 0);
+		UT_ASSERT_INT(cb_data.event_read_done, ==, 1);
+		mock_cb_data_reset(&cb_data);
+
+		/* close port */
+		ret = msm_smux_close(SMUX_TEST_LCID);
+		UT_ASSERT_INT(ret, ==, 0);
+		UT_ASSERT_INT(
+			(int)wait_for_completion_timeout(
+				&cb_data.cb_completion, HZ),
+			>, 0);
+		UT_ASSERT_INT(cb_data.cb_count, ==, 1);
+		UT_ASSERT_INT(cb_data.event_disconnected, ==, 1);
+		UT_ASSERT_INT(cb_data.event_disconnected_ssr, ==, 0);
+		break;
+	}
+
+	if (!failed) {
+		i += scnprintf(buf + i, max - i, "\tOK\n");
+	} else {
+		pr_err("%s: Failed\n", __func__);
+		i += scnprintf(buf + i, max - i, "\tFailed\n");
+		i += mock_cb_data_print(&cb_data, buf + i, max - i);
+		msm_smux_set_ch_option(SMUX_TEST_LCID,
+			0, SMUX_CH_OPTION_REMOTE_TX_STOP);
+		msm_smux_close(SMUX_TEST_LCID);
+	}
+	mock_cb_data_reset(&cb_data);
+	return i;
+}
+
 static char debug_buffer[DEBUG_BUFMAX];
 
 static ssize_t debug_read(struct file *file, char __user *buf,
@@ -1961,7 +2120,7 @@
 {
 	struct dentry *dent;
 
-	dent = debugfs_create_dir("n_smux", 0);
+	dent = debugfs_create_dir("n_smux_test", 0);
 	if (IS_ERR(dent))
 		return PTR_ERR(dent);
 
@@ -1995,6 +2154,8 @@
 			smux_ut_remote_ssr_open);
 	debug_create("ut_remote_ssr_rx_buff_retry", 0444, dent,
 			smux_ut_remote_ssr_rx_buff_retry);
+	debug_create("ut_remote_tx_stop", 0444, dent,
+			smux_ut_remote_tx_stop);
 
 	return 0;
 }
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
index 6c9b7cd..3d29607 100644
--- a/drivers/tty/tty_buffer.c
+++ b/drivers/tty/tty_buffer.c
@@ -185,25 +185,19 @@
 	/* Should possibly check if this fails for the largest buffer we
 	   have queued and recycle that ? */
 }
-
 /**
- *	tty_buffer_request_room		-	grow tty buffer if needed
+ *	__tty_buffer_request_room		-	grow tty buffer if needed
  *	@tty: tty structure
  *	@size: size desired
  *
  *	Make at least size bytes of linear space available for the tty
  *	buffer. If we fail return the size we managed to find.
- *
- *	Locking: Takes tty->buf.lock
+ *      Locking: Caller must hold tty->buf.lock
  */
-int tty_buffer_request_room(struct tty_struct *tty, size_t size)
+static int __tty_buffer_request_room(struct tty_struct *tty, size_t size)
 {
 	struct tty_buffer *b, *n;
 	int left;
-	unsigned long flags;
-
-	spin_lock_irqsave(&tty->buf.lock, flags);
-
 	/* OPTIMISATION: We could keep a per tty "zero" sized buffer to
 	   remove this conditional if its worth it. This would be invisible
 	   to the callers */
@@ -225,9 +219,30 @@
 			size = left;
 	}
 
-	spin_unlock_irqrestore(&tty->buf.lock, flags);
 	return size;
 }
+
+
+/**
+ *	tty_buffer_request_room		-	grow tty buffer if needed
+ *	@tty: tty structure
+ *	@size: size desired
+ *
+ *	Make at least size bytes of linear space available for the tty
+ *	buffer. If we fail return the size we managed to find.
+ *
+ *	Locking: Takes tty->buf.lock
+ */
+int tty_buffer_request_room(struct tty_struct *tty, size_t size)
+{
+	unsigned long flags;
+	int length;
+
+	spin_lock_irqsave(&tty->buf.lock, flags);
+	length = __tty_buffer_request_room(tty, size);
+	spin_unlock_irqrestore(&tty->buf.lock, flags);
+	return length;
+}
 EXPORT_SYMBOL_GPL(tty_buffer_request_room);
 
 /**
@@ -249,14 +264,22 @@
 	int copied = 0;
 	do {
 		int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
-		int space = tty_buffer_request_room(tty, goal);
-		struct tty_buffer *tb = tty->buf.tail;
+		int space;
+		unsigned long flags;
+		struct tty_buffer *tb;
+
+		spin_lock_irqsave(&tty->buf.lock, flags);
+		space = __tty_buffer_request_room(tty, goal);
+		tb = tty->buf.tail;
 		/* If there is no space then tb may be NULL */
-		if (unlikely(space == 0))
+		if (unlikely(space == 0)) {
+			spin_unlock_irqrestore(&tty->buf.lock, flags);
 			break;
+		}
 		memcpy(tb->char_buf_ptr + tb->used, chars, space);
 		memset(tb->flag_buf_ptr + tb->used, flag, space);
 		tb->used += space;
+		spin_unlock_irqrestore(&tty->buf.lock, flags);
 		copied += space;
 		chars += space;
 		/* There is a small chance that we need to split the data over
@@ -286,14 +309,22 @@
 	int copied = 0;
 	do {
 		int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
-		int space = tty_buffer_request_room(tty, goal);
-		struct tty_buffer *tb = tty->buf.tail;
+		int space;
+		unsigned long __flags;
+		struct tty_buffer *tb;
+
+		spin_lock_irqsave(&tty->buf.lock, __flags);
+		space = __tty_buffer_request_room(tty, goal);
+		tb = tty->buf.tail;
 		/* If there is no space then tb may be NULL */
-		if (unlikely(space == 0))
+		if (unlikely(space == 0)) {
+			spin_unlock_irqrestore(&tty->buf.lock, __flags);
 			break;
+		}
 		memcpy(tb->char_buf_ptr + tb->used, chars, space);
 		memcpy(tb->flag_buf_ptr + tb->used, flags, space);
 		tb->used += space;
+		spin_unlock_irqrestore(&tty->buf.lock, __flags);
 		copied += space;
 		chars += space;
 		flags += space;
@@ -344,13 +375,20 @@
 int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars,
 								size_t size)
 {
-	int space = tty_buffer_request_room(tty, size);
+	int space;
+	unsigned long flags;
+	struct tty_buffer *tb;
+
+	spin_lock_irqsave(&tty->buf.lock, flags);
+	space = __tty_buffer_request_room(tty, size);
+
+	tb = tty->buf.tail;
 	if (likely(space)) {
-		struct tty_buffer *tb = tty->buf.tail;
 		*chars = tb->char_buf_ptr + tb->used;
 		memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
 		tb->used += space;
 	}
+	spin_unlock_irqrestore(&tty->buf.lock, flags);
 	return space;
 }
 EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
@@ -374,13 +412,20 @@
 int tty_prepare_flip_string_flags(struct tty_struct *tty,
 			unsigned char **chars, char **flags, size_t size)
 {
-	int space = tty_buffer_request_room(tty, size);
+	int space;
+	unsigned long __flags;
+	struct tty_buffer *tb;
+
+	spin_lock_irqsave(&tty->buf.lock, __flags);
+	space = __tty_buffer_request_room(tty, size);
+
+	tb = tty->buf.tail;
 	if (likely(space)) {
-		struct tty_buffer *tb = tty->buf.tail;
 		*chars = tb->char_buf_ptr + tb->used;
 		*flags = tb->flag_buf_ptr + tb->used;
 		tb->used += space;
 	}
+	spin_unlock_irqrestore(&tty->buf.lock, __flags);
 	return space;
 }
 EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);
@@ -418,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) {
@@ -432,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/core/hcd.c b/drivers/usb/core/hcd.c
index 66ba02b..b8f9563 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -1473,6 +1473,8 @@
 	atomic_inc(&urb->use_count);
 	atomic_inc(&urb->dev->urbnum);
 	usbmon_urb_submit(&hcd->self, urb);
+	if (hcd->driver->log_urb)
+		hcd->driver->log_urb(urb, "S", urb->status);
 
 	/* NOTE requirements on root-hub callers (usbfs and the hub
 	 * driver, for now):  URBs' urb->transfer_buffer must be
@@ -1495,6 +1497,8 @@
 
 	if (unlikely(status)) {
 		usbmon_urb_submit_error(&hcd->self, urb, status);
+		if (hcd->driver->log_urb)
+			hcd->driver->log_urb(urb, "E", status);
 		urb->hcpriv = NULL;
 		INIT_LIST_HEAD(&urb->urb_list);
 		atomic_dec(&urb->use_count);
@@ -1597,11 +1601,10 @@
 
 	unmap_urb_for_dma(hcd, urb);
 	usbmon_urb_complete(&hcd->self, urb, status);
+	if (hcd->driver->log_urb)
+		hcd->driver->log_urb(urb, "C", status);
 	usb_unanchor_urb(urb);
 
-	if (hcd->driver->log_urb_complete)
-		hcd->driver->log_urb_complete(urb, "C", status);
-
 	/* pass ownership to the completion handler */
 	urb->status = status;
 	urb->complete (urb);
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 54ea85d..f517340 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -559,13 +559,6 @@
 			goto err1;
 		}
 
-		ret = dwc3_host_init(dwc);
-		if (ret) {
-			dev_err(dev, "failed to initialize host\n");
-			dwc3_otg_exit(dwc);
-			goto err1;
-		}
-
 		ret = dwc3_gadget_init(dwc);
 		if (ret) {
 			dev_err(dev, "failed to initialize gadget\n");
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 522e3a4..b71bd3e 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -34,6 +34,7 @@
 #include <linux/regulator/consumer.h>
 
 #include <mach/rpm-regulator.h>
+#include <mach/msm_bus.h>
 
 #include "dwc3_otg.h"
 #include "core.h"
@@ -103,10 +104,12 @@
  */
 #define QSCRATCH_REG_OFFSET	(0x000F8800)
 #define QSCRATCH_GENERAL_CFG	(QSCRATCH_REG_OFFSET + 0x08)
+#define HS_PHY_CTRL_REG		(QSCRATCH_REG_OFFSET + 0x10)
 #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)
+#define SS_PHY_CTRL_REG		(QSCRATCH_REG_OFFSET + 0x30)
 
 struct dwc3_msm_req_complete {
 	struct list_head list_item;
@@ -124,7 +127,11 @@
 	u8 ep_num_mapping[DBM_MAX_EPS];
 	const struct usb_ep_ops *original_ep_ops[DWC3_ENDPOINTS_NUM];
 	struct list_head req_complete_list;
+	struct clk		*ref_clk;
 	struct clk		*core_clk;
+	struct clk		*iface_clk;
+	struct clk		*sleep_clk;
+	struct clk		*hsphy_sleep_clk;
 	struct regulator	*hsusb_3p3;
 	struct regulator	*hsusb_1p8;
 	struct regulator	*hsusb_vddcx;
@@ -143,6 +150,8 @@
 	struct delayed_work	chg_work;
 	enum usb_chg_state	chg_state;
 	u8			dcd_retries;
+	u32			bus_perf_client;
+	struct msm_bus_scale_pdata	*bus_scale_table;
 };
 
 #define USB_HSPHY_3P3_VOL_MIN		3050000 /* uV */
@@ -1220,6 +1229,8 @@
 
 static int dwc3_msm_suspend(struct dwc3_msm *mdwc)
 {
+	int ret;
+
 	dev_dbg(mdwc->dev, "%s: entering lpm\n", __func__);
 
 	if (atomic_read(&mdwc->in_lpm)) {
@@ -1227,11 +1238,20 @@
 		return 0;
 	}
 
+	clk_disable_unprepare(mdwc->iface_clk);
 	clk_disable_unprepare(mdwc->core_clk);
+	clk_disable_unprepare(mdwc->ref_clk);
 	dwc3_hsusb_ldo_enable(0);
 	dwc3_ssusb_ldo_enable(0);
 	wake_unlock(&mdwc->wlock);
 
+	if (mdwc->bus_perf_client) {
+		ret = msm_bus_scale_client_update_request(
+						mdwc->bus_perf_client, 0);
+		if (ret)
+			dev_err(mdwc->dev, "Failed to reset bus bw vote\n");
+	}
+
 	atomic_set(&mdwc->in_lpm, 1);
 	dev_info(mdwc->dev, "DWC3 in low power mode\n");
 
@@ -1240,6 +1260,8 @@
 
 static int dwc3_msm_resume(struct dwc3_msm *mdwc)
 {
+	int ret;
+
 	dev_dbg(mdwc->dev, "%s: exiting lpm\n", __func__);
 
 	if (!atomic_read(&mdwc->in_lpm)) {
@@ -1247,8 +1269,17 @@
 		return 0;
 	}
 
+	if (mdwc->bus_perf_client) {
+		ret = msm_bus_scale_client_update_request(
+						mdwc->bus_perf_client, 1);
+		if (ret)
+			dev_err(mdwc->dev, "Failed to vote for bus scaling\n");
+	}
+
 	wake_lock(&mdwc->wlock);
+	clk_prepare_enable(mdwc->ref_clk);
 	clk_prepare_enable(mdwc->core_clk);
+	clk_prepare_enable(mdwc->iface_clk);
 	dwc3_hsusb_ldo_enable(1);
 	dwc3_ssusb_ldo_enable(1);
 
@@ -1378,6 +1409,7 @@
 	struct platform_device *dwc3;
 	struct dwc3_msm *msm;
 	struct resource *res;
+	void __iomem *tcsr;
 	int ret = 0;
 
 	msm = devm_kzalloc(&pdev->dev, sizeof(*msm), GFP_KERNEL);
@@ -1406,6 +1438,38 @@
 	clk_set_rate(msm->core_clk, 125000000);
 	clk_prepare_enable(msm->core_clk);
 
+	msm->iface_clk = devm_clk_get(&pdev->dev, "iface_clk");
+	if (IS_ERR(msm->iface_clk)) {
+		dev_err(&pdev->dev, "failed to get iface_clk\n");
+		ret = PTR_ERR(msm->iface_clk);
+		goto disable_core_clk;
+	}
+	clk_prepare_enable(msm->iface_clk);
+
+	msm->sleep_clk = devm_clk_get(&pdev->dev, "sleep_clk");
+	if (IS_ERR(msm->sleep_clk)) {
+		dev_err(&pdev->dev, "failed to get sleep_clk\n");
+		ret = PTR_ERR(msm->sleep_clk);
+		goto disable_iface_clk;
+	}
+	clk_prepare_enable(msm->sleep_clk);
+
+	msm->hsphy_sleep_clk = devm_clk_get(&pdev->dev, "sleep_a_clk");
+	if (IS_ERR(msm->hsphy_sleep_clk)) {
+		dev_err(&pdev->dev, "failed to get sleep_a_clk\n");
+		ret = PTR_ERR(msm->hsphy_sleep_clk);
+		goto disable_sleep_clk;
+	}
+	clk_prepare_enable(msm->hsphy_sleep_clk);
+
+	msm->ref_clk = devm_clk_get(&pdev->dev, "ref_clk");
+	if (IS_ERR(msm->ref_clk)) {
+		dev_err(&pdev->dev, "failed to get ref_clk\n");
+		ret = PTR_ERR(msm->ref_clk);
+		goto disable_sleep_a_clk;
+	}
+	clk_prepare_enable(msm->ref_clk);
+
 	/* SS PHY */
 	msm->ss_vdd_type = VDDCX_CORNER;
 	msm->ssusb_vddcx = devm_regulator_get(&pdev->dev, "ssusb_vdd_dig");
@@ -1415,7 +1479,7 @@
 		if (IS_ERR(msm->ssusb_vddcx)) {
 			dev_err(&pdev->dev, "unable to get ssusb vddcx\n");
 			ret = PTR_ERR(msm->ssusb_vddcx);
-			goto disable_core_clk;
+			goto disable_ref_clk;
 		}
 		msm->ss_vdd_type = VDDCX;
 		dev_dbg(&pdev->dev, "ss_vdd_type: VDDCX\n");
@@ -1424,7 +1488,7 @@
 	ret = dwc3_ssusb_config_vddcx(1);
 	if (ret) {
 		dev_err(&pdev->dev, "ssusb vddcx configuration failed\n");
-		goto disable_core_clk;
+		goto disable_ref_clk;
 	}
 
 	ret = regulator_enable(context->ssusb_vddcx);
@@ -1484,6 +1548,25 @@
 		goto free_hs_ldo_init;
 	}
 
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!res) {
+		dev_dbg(&pdev->dev, "missing TCSR memory resource\n");
+	} else {
+		tcsr = devm_ioremap_nocache(&pdev->dev, res->start,
+			resource_size(res));
+		if (!tcsr) {
+			dev_dbg(&pdev->dev, "tcsr ioremap failed\n");
+		} else {
+			/* Enable USB3 on the primary USB port. */
+			writel_relaxed(0x1, tcsr);
+			/*
+			 * Ensure that TCSR write is completed before
+			 * USB registers initialization.
+			 */
+			mb();
+		}
+	}
+
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res) {
 		dev_err(&pdev->dev, "missing memory base resource\n");
@@ -1513,8 +1596,28 @@
 	msm->resource_size = resource_size(res);
 	msm->dwc3 = dwc3;
 
+	/* SSPHY Initialization: Use ref_clk from pads and set its parameters */
+	dwc3_msm_write_reg(msm->base, SS_PHY_CTRL_REG, 0x10210002);
+	msleep(30);
+	/* Assert SSPHY reset */
+	dwc3_msm_write_reg(msm->base, SS_PHY_CTRL_REG, 0x10210082);
+	usleep_range(2000, 2200);
+	/* De-assert SSPHY reset - power and ref_clock must be ON */
+	dwc3_msm_write_reg(msm->base, SS_PHY_CTRL_REG, 0x10210002);
+	usleep_range(2000, 2200);
+	/* Ref clock must be stable now, enable ref clock for HS mode */
+	dwc3_msm_write_reg(msm->base, SS_PHY_CTRL_REG, 0x10210102);
+	usleep_range(2000, 2200);
+	/*
+	 * HSPHY Initialization: Enable UTMI clock and clamp enable HVINTs,
+	 * and disable RETENTION (power-on default is ENABLED)
+	 */
+	dwc3_msm_write_reg(msm->base, HS_PHY_CTRL_REG, 0x5220bb2);
+	usleep_range(2000, 2200);
+	/* Disable (bypass) VBUS filter */
+	dwc3_msm_write_reg(msm->base, QSCRATCH_GENERAL_CFG, 0x38);
+
 	pm_runtime_set_active(msm->dev);
-	pm_runtime_enable(msm->dev);
 
 	if (of_property_read_u32(node, "qcom,dwc-usb3-msm-dbm-eps",
 				 &msm->dbm_num_eps)) {
@@ -1545,6 +1648,18 @@
 		goto put_pdev;
 	}
 
+	msm->bus_scale_table = msm_bus_cl_get_pdata(pdev);
+	if (!msm->bus_scale_table) {
+		dev_err(&pdev->dev, "bus scaling is disabled\n");
+	} else {
+		msm->bus_perf_client =
+			msm_bus_scale_register_client(msm->bus_scale_table);
+		ret = msm_bus_scale_client_update_request(
+						msm->bus_perf_client, 1);
+		if (ret)
+			dev_err(&pdev->dev, "Failed to vote for bus scaling\n");
+	}
+
 	/* Reset the DBM */
 	dwc3_msm_dbm_soft_reset(1);
 	usleep_range(1000, 1200);
@@ -1600,6 +1715,14 @@
 	regulator_disable(context->ssusb_vddcx);
 unconfig_ss_vddcx:
 	dwc3_ssusb_config_vddcx(0);
+disable_ref_clk:
+	clk_disable_unprepare(msm->ref_clk);
+disable_sleep_a_clk:
+	clk_disable_unprepare(msm->hsphy_sleep_clk);
+disable_sleep_clk:
+	clk_disable_unprepare(msm->sleep_clk);
+disable_iface_clk:
+	clk_disable_unprepare(msm->iface_clk);
 disable_core_clk:
 	clk_disable_unprepare(msm->core_clk);
 
@@ -1629,6 +1752,10 @@
 	regulator_disable(msm->ssusb_vddcx);
 	dwc3_ssusb_config_vddcx(0);
 	clk_disable_unprepare(msm->core_clk);
+	clk_disable_unprepare(msm->iface_clk);
+	clk_disable_unprepare(msm->sleep_clk);
+	clk_disable_unprepare(msm->hsphy_sleep_clk);
+	clk_disable_unprepare(msm->ref_clk);
 
 	return 0;
 }
diff --git a/drivers/usb/dwc3/io.h b/drivers/usb/dwc3/io.h
index 90de7a4..a50f76b 100644
--- a/drivers/usb/dwc3/io.h
+++ b/drivers/usb/dwc3/io.h
@@ -50,7 +50,7 @@
 	 * space, see dwc3_probe in core.c.
 	 * However, the offsets are given starting from xHCI address space.
 	 */
-	return readl_relaxed(base + (offset - DWC3_GLOBALS_REGS_START));
+	return readl(base + (offset - DWC3_GLOBALS_REGS_START));
 }
 
 static inline void dwc3_writel(void __iomem *base, u32 offset, u32 value)
@@ -60,7 +60,7 @@
 	 * space, see dwc3_probe in core.c.
 	 * However, the offsets are given starting from xHCI address space.
 	 */
-	writel_relaxed(value, base + (offset - DWC3_GLOBALS_REGS_START));
+	writel(value, base + (offset - DWC3_GLOBALS_REGS_START));
 }
 
 #endif /* __DRIVERS_USB_DWC3_IO_H */
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index c95f82d..de9a7aa 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -1121,15 +1121,4 @@
        help
 	  Data SMD channel for transferring network data
 
-config USB_ANDROID_RMNET_CTRL_SMD
-       boolean "RmNet(BAM) control over SMD driver"
-       depends on MSM_SMD
-       help
-         Enabling this option adds rmnet control over SMD
-	 support to the android gadget. Rmnet is an
-	 alternative to CDC-ECM and Windows RNDIS.
-	 It uses QUALCOMM MSM Interface for control
-	 transfers. This option enables only control interface.
-	 Data interface used is BAM.
-
 endif # USB_GADGET
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index 7b34e60..a6eb335 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -30,6 +30,8 @@
 #include <linux/usb/gadget.h>
 #include <linux/usb/android.h>
 
+#include <mach/diag_dload.h>
+
 #include "gadget_chips.h"
 
 /*
@@ -163,6 +165,7 @@
 	struct list_head list_item;
 };
 
+struct dload_struct __iomem *diag_dload;
 static struct class *android_class;
 static struct list_head android_dev_list;
 static int android_dev_count;
@@ -173,6 +176,7 @@
 						(struct android_dev *dev);
 static void free_android_config(struct android_dev *dev,
 				struct android_configuration *conf);
+static int usb_diag_update_pid_and_serial_num(uint32_t pid, const char *snum);
 
 /* string IDs are assigned dynamically */
 #define STRING_MANUFACTURER_IDX		0
@@ -741,8 +745,12 @@
 		notify = NULL;
 		name = strsep(&b, ",");
 		/* Allow only first diag channel to update pid and serial no */
-		if (dev->pdata && !once++)
-			notify = dev->pdata->update_pid_and_serial_num;
+		if (!once++) {
+			if (dev->pdata && dev->pdata->update_pid_and_serial_num)
+				notify = dev->pdata->update_pid_and_serial_num;
+			else
+				notify = usb_diag_update_pid_and_serial_num;
+		}
 
 		if (name) {
 			err = diag_function_add(c, name, notify);
@@ -1334,7 +1342,7 @@
 		config->fsg.nluns = 2;
 		config->fsg.luns[1].cdrom = 1;
 		config->fsg.luns[1].ro = 1;
-		config->fsg.luns[1].removable = 1;
+		config->fsg.luns[1].removable = 0;
 		name[1] = "lun0";
 	}
 
@@ -2239,10 +2247,49 @@
 	kfree(conf);
 }
 
+static int usb_diag_update_pid_and_serial_num(u32 pid, const char *snum)
+{
+	struct dload_struct local_diag_dload = { 0 };
+	int *src, *dst, i;
+
+	if (!diag_dload) {
+		pr_debug("%s: unable to update PID and serial_no\n", __func__);
+		return -ENODEV;
+	}
+
+	pr_debug("%s: dload:%p pid:%x serial_num:%s\n",
+				__func__, diag_dload, pid, snum);
+
+	/* update pid */
+	local_diag_dload.magic_struct.pid = PID_MAGIC_ID;
+	local_diag_dload.pid = pid;
+
+	/* update serial number */
+	if (!snum) {
+		local_diag_dload.magic_struct.serial_num = 0;
+		memset(&local_diag_dload.serial_number, 0,
+				SERIAL_NUMBER_LENGTH);
+	} else {
+		local_diag_dload.magic_struct.serial_num = SERIAL_NUM_MAGIC_ID;
+		strlcpy((char *)&local_diag_dload.serial_number, snum,
+				SERIAL_NUMBER_LENGTH);
+	}
+
+	/* Copy to shared struct (accesses need to be 32 bit aligned) */
+	src = (int *)&local_diag_dload;
+	dst = (int *)diag_dload;
+
+	for (i = 0; i < sizeof(*diag_dload) / 4; i++)
+		*dst++ = *src++;
+
+	return 0;
+}
+
 static int __devinit android_probe(struct platform_device *pdev)
 {
 	struct android_usb_platform_data *pdata = pdev->dev.platform_data;
 	struct android_dev *android_dev;
+	struct resource *res;
 	int ret = 0;
 
 	if (!android_class) {
@@ -2277,6 +2324,19 @@
 	else
 		composite_driver.usb_core_id = 0; /*To backward compatibility*/
 
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res) {
+		diag_dload = devm_ioremap(&pdev->dev, res->start,
+							resource_size(res));
+		if (!diag_dload) {
+			dev_err(&pdev->dev, "ioremap failed\n");
+			ret = -ENOMEM;
+			goto err_dev;
+		}
+	} else {
+		dev_dbg(&pdev->dev, "failed to get mem resource\n");
+	}
+
 	ret = android_create_device(android_dev, composite_driver.usb_core_id);
 	if (ret) {
 		pr_err("%s(): android_create_device failed\n", __func__);
@@ -2355,8 +2415,17 @@
 	},
 };
 
+static struct of_device_id usb_android_dt_match[] = {
+	{	.compatible = "qcom,android-usb",
+	},
+	{}
+};
+
 static struct platform_driver android_platform_driver = {
-	.driver = { .name = "android_usb"},
+	.driver = {
+		.name = "android_usb",
+		.of_match_table = usb_android_dt_match,
+	},
 	.probe = android_probe,
 	.remove = android_remove,
 	.id_table = android_id_table,
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 4d15c55..831e970 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -2056,6 +2056,16 @@
 
 	spin_unlock(udc->lock);
 
+	if (udc->suspended) {
+		if (udc->udc_driver->notify_event)
+			udc->udc_driver->notify_event(udc,
+			CI13XXX_CONTROLLER_RESUME_EVENT);
+		if (udc->transceiver)
+			usb_phy_set_suspend(udc->transceiver, 0);
+		udc->driver->resume(&udc->gadget);
+		udc->suspended = 0;
+	}
+
 	/*stop charging upon reset */
 	if (udc->transceiver)
 		usb_phy_set_power(udc->transceiver, 0);
diff --git a/drivers/usb/gadget/f_adb.c b/drivers/usb/gadget/f_adb.c
index b997a3f..9778673 100644
--- a/drivers/usb/gadget/f_adb.c
+++ b/drivers/usb/gadget/f_adb.c
@@ -48,7 +48,6 @@
 	atomic_t read_excl;
 	atomic_t write_excl;
 	atomic_t open_excl;
-	struct delayed_work adb_release_w;
 
 	struct list_head tx_idle;
 
@@ -410,11 +409,6 @@
 	return r;
 }
 
-static void adb_release_work(struct work_struct *w)
-{
-	adb_closed_callback();
-}
-
 static int adb_open(struct inode *ip, struct file *fp)
 {
 	pr_info("adb_open\n");
@@ -429,8 +423,7 @@
 	/* clear the error latch */
 	atomic_set(&_adb_dev->error, 0);
 
-	if (!cancel_delayed_work_sync(&_adb_dev->adb_release_w))
-		adb_ready_callback();
+	adb_ready_callback();
 
 	return 0;
 }
@@ -439,16 +432,7 @@
 {
 	pr_info("adb_release\n");
 
-	/*
-	 * When USB cable is plugged out, adb reader is unblocked and
-	 * -EIO is returned to user space. adb daemon reopen the port
-	 * which would disable and enable USB configuration unnecessarily.
-	 *
-	 * Delay notifying the adb close event to android by 1 sec. If
-	 * ADB daemon opens the port with in 1 sec, USB configuration
-	 * re-enable does not happen.
-	 */
-	schedule_delayed_work(&_adb_dev->adb_release_w, msecs_to_jiffies(1000));
+	adb_closed_callback();
 
 	adb_unlock(&_adb_dev->open_excl);
 	return 0;
@@ -624,7 +608,6 @@
 	atomic_set(&dev->read_excl, 0);
 	atomic_set(&dev->write_excl, 0);
 
-	INIT_DELAYED_WORK(&dev->adb_release_w, adb_release_work);
 	INIT_LIST_HEAD(&dev->tx_idle);
 
 	_adb_dev = dev;
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index 1ea3982..0514aa8 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -2921,7 +2921,7 @@
 			rc = fsg_lun_open(curlun, lcfg->filename);
 			if (rc)
 				goto error_luns;
-		} else if (!curlun->removable) {
+		} else if (!curlun->removable && !curlun->cdrom) {
 			ERROR(common, "no file given for LUN%d\n", i);
 			rc = -EINVAL;
 			goto error_luns;
diff --git a/drivers/usb/gadget/f_qc_rndis.c b/drivers/usb/gadget/f_qc_rndis.c
index dcf307d..a740d95 100644
--- a/drivers/usb/gadget/f_qc_rndis.c
+++ b/drivers/usb/gadget/f_qc_rndis.c
@@ -882,6 +882,11 @@
 
 	rndis_set_max_pkt_xfer(rndis->config, rndis->max_pkt_per_xfer);
 
+	/* In case of aggregated packets QC device will request
+	 * aliment to 4 (2^2).
+	 */
+	rndis_set_pkt_alignment_factor(rndis->config, 2);
+
 	/* 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().
diff --git a/drivers/usb/gadget/f_rmnet.c b/drivers/usb/gadget/f_rmnet.c
index 414a7b9..aa9daf3 100644
--- a/drivers/usb/gadget/f_rmnet.c
+++ b/drivers/usb/gadget/f_rmnet.c
@@ -488,6 +488,8 @@
 		break;
 	case USB_GADGET_XPORT_HSIC:
 		break;
+	case USB_GADGET_XPORT_HSUART:
+		break;
 	case USB_GADGET_XPORT_NONE:
 		break;
 	default:
@@ -515,6 +517,8 @@
 		break;
 	case USB_GADGET_XPORT_HSIC:
 		break;
+	case USB_GADGET_XPORT_HSUART:
+		break;
 	case USB_GADGET_XPORT_NONE:
 		break;
 	default:
@@ -607,6 +611,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 +638,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 +781,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 +805,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_rndis.c b/drivers/usb/gadget/f_rndis.c
index 59ff8d7..02f044e 100644
--- a/drivers/usb/gadget/f_rndis.c
+++ b/drivers/usb/gadget/f_rndis.c
@@ -25,6 +25,10 @@
 #include "u_ether.h"
 #include "rndis.h"
 
+static bool rndis_multipacket_dl_disable;
+module_param(rndis_multipacket_dl_disable, bool, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(rndis_multipacket_dl_disable,
+	"Disable RNDIS Multi-packet support in DownLink");
 
 /*
  * This function is an RNDIS Ethernet port -- a Microsoft protocol that's
@@ -469,6 +473,8 @@
 				__func__, buf->MaxTransferSize,
 				rndis->port.multi_pkt_xfer ? "enabled" :
 							    "disabled");
+		if (rndis_multipacket_dl_disable)
+			rndis->port.multi_pkt_xfer = 0;
 	}
 //	spin_unlock(&dev->lock);
 }
diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c
index e0520c7..801d24d 100644
--- a/drivers/usb/gadget/rndis.c
+++ b/drivers/usb/gadget/rndis.c
@@ -590,8 +590,9 @@
 		(params->dev->mtu
 		+ sizeof(struct ethhdr)
 		+ sizeof(struct rndis_packet_msg_type)
+
 		+ 22));
-	resp->PacketAlignmentFactor = cpu_to_le32(0);
+	resp->PacketAlignmentFactor = cpu_to_le32(params->pkt_alignment_factor);
 	resp->AFListOffset = cpu_to_le32(0);
 	resp->AFListSize = cpu_to_le32(0);
 
@@ -902,8 +903,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;
+			rndis_per_dev_params[i].max_pkt_per_xfer = 1;
+			rndis_per_dev_params[i].pkt_alignment_factor = 0;
 			pr_debug("%s: configNr = %d\n", __func__, i);
 			return i;
 		}
@@ -964,6 +965,14 @@
 	rndis_per_dev_params[configNr].max_pkt_per_xfer = max_pkt_per_xfer;
 }
 
+void rndis_set_pkt_alignment_factor(u8 configNr, u8 pkt_alignment_factor)
+{
+	pr_debug("%s:\n", __func__);
+
+	rndis_per_dev_params[configNr].pkt_alignment_factor =
+					pkt_alignment_factor;
+}
+
 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 1f06c42..8a6a630 100644
--- a/drivers/usb/gadget/rndis.h
+++ b/drivers/usb/gadget/rndis.h
@@ -236,6 +236,7 @@
 
 	u32			vendorID;
 	u8			max_pkt_per_xfer;
+	u8			pkt_alignment_factor;
 	const char		*vendorDescr;
 	void			(*resp_avail)(void *v);
 	void			*v;
diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index fd10394..b84c74d 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -292,6 +292,10 @@
 				status = dev->unwrap(dev->port_usb,
 							skb,
 							&dev->rx_frames);
+				if (status == -EINVAL)
+					dev->net->stats.rx_errors++;
+				else if (status == -EOVERFLOW)
+					dev->net->stats.rx_over_errors++;
 			} else {
 				dev_kfree_skb_any(skb);
 				status = -ENOTCONN;
diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c
index de93049..909744f 100644
--- a/drivers/usb/gadget/u_serial.c
+++ b/drivers/usb/gadget/u_serial.c
@@ -849,13 +849,6 @@
 	port->open_count = 1;
 	port->openclose = false;
 
-	/* low_latency means ldiscs work is carried in the same context
-	 * of tty_flip_buffer_push. The same can be called from IRQ with
-	 * low_latency = 0. But better to use a dedicated worker thread
-	 * to push the data.
-	 */
-	tty->low_latency = 1;
-
 	/* if connected, start the I/O stream */
 	if (port->port_usb) {
 		struct gserial	*gser = port->port_usb;
diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c
index c16ff97..40b79a2 100644
--- a/drivers/usb/gadget/udc-core.c
+++ b/drivers/usb/gadget/udc-core.c
@@ -348,7 +348,6 @@
 			driver->unbind(udc->gadget);
 			goto err1;
 		}
-		usb_gadget_connect(udc->gadget);
 	} else {
 
 		ret = usb_gadget_start(udc->gadget, driver, bind);
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 7309438..8d967cd 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -691,8 +691,7 @@
 	hw->hw_alt_next = QTD_NEXT(ehci, ehci->async->dummy->qtd_dma);
 
 	/* clear interrupt enables, set irq latency */
-	if (ehci->max_log2_irq_thresh)
-		log2_irq_thresh = ehci->max_log2_irq_thresh;
+	log2_irq_thresh = ehci->log2_irq_thresh;
 
 	if (log2_irq_thresh < 0 || log2_irq_thresh > 6)
 		log2_irq_thresh = 0;
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index 4dd6d68..fee7a09 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -27,6 +27,7 @@
 #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>
 
@@ -34,6 +35,10 @@
 #include <linux/usb/msm_hsusb.h>
 #include <linux/gpio.h>
 #include <linux/spinlock.h>
+#include <linux/irq.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/pm_qos.h>
 
 #include <mach/msm_bus.h>
 #include <mach/clk.h>
@@ -47,8 +52,23 @@
 #define USB_REG_START_OFFSET 0x90
 #define USB_REG_END_OFFSET 0x250
 
+static struct workqueue_struct  *ehci_wq;
+struct ehci_timer {
+#define GPT_LD(p)	((p) & 0x00FFFFFF)
+	u32	gptimer0_ld;
+#define GPT_RUN		BIT(31)
+#define GPT_RESET	BIT(30)
+#define GPT_MODE	BIT(24)
+#define GPT_CNT(p)	((p) & 0x00FFFFFF)
+	u32	gptimer0_ctrl;
+
+	u32	gptimer1_ld;
+	u32	gptimer1_ctrl;
+};
+
 struct msm_hsic_hcd {
 	struct ehci_hcd		ehci;
+	spinlock_t		wakeup_lock;
 	struct device		*dev;
 	struct clk		*ahb_clk;
 	struct clk		*core_clk;
@@ -56,22 +76,37 @@
 	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;
-	bool			irq_enabled;
-	bool			async_int;
+	atomic_t		pm_usage_cnt;
 	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;
+
+	/* gp timer */
+	struct ehci_timer __iomem *timer;
+	struct completion	gpt0_completion;
+	struct completion	rt_completion;
+	int			resume_status;
+	int			resume_again;
+
+	struct pm_qos_request pm_qos_req_dma;
 };
 
 struct msm_hsic_hcd *__mehci;
 
 static bool debug_bus_voting_enabled = true;
 
+static unsigned int enable_payload_log = 1;
+module_param(enable_payload_log, uint, S_IRUGO | S_IWUSR);
 static unsigned int enable_dbg_log = 1;
 module_param(enable_dbg_log, uint, S_IRUGO | S_IWUSR);
 /*by default log ep0 and efs sync ep*/
@@ -81,12 +116,13 @@
 module_param(ep_addr_txdbg_mask, uint, S_IRUGO | S_IWUSR);
 
 /* Maximum debug message length */
-#define DBG_MSG_LEN   100UL
+#define DBG_MSG_LEN   128UL
 
 /* Maximum number of messages */
 #define DBG_MAX_MSG   256UL
 
 #define TIME_BUF_LEN  20
+#define HEX_DUMP_LEN  72
 
 enum event_type {
 	EVENT_UNDEF = -1,
@@ -97,20 +133,6 @@
 
 #define EVENT_STR_LEN	5
 
-static char *event_to_str(enum event_type e)
-{
-	switch (e) {
-	case URB_SUBMIT:
-		return "S";
-	case URB_COMPLETE:
-		return "C";
-	case EVENT_NONE:
-		return "NONE";
-	default:
-		return "UNDEF";
-	}
-}
-
 static enum event_type str_to_event(const char *name)
 {
 	if (!strncasecmp("S", name, EVENT_STR_LEN))
@@ -180,11 +202,36 @@
 	return 0;
 }
 
+static char *get_hex_data(char *dbuf, struct urb *urb, int event, int status)
+{
+	int ep_addr = urb->ep->desc.bEndpointAddress;
+	char *ubuf = urb->transfer_buffer;
+	size_t len = event ? \
+		urb->actual_length : urb->transfer_buffer_length;
+
+	if (status == -EINPROGRESS)
+		status = 0;
+
+	/*Only dump ep in completions and epout submissions*/
+	if (len && !status &&
+		(((ep_addr & USB_DIR_IN) && event) ||
+		(!(ep_addr & USB_DIR_IN) && !event))) {
+		if (len >= 32)
+			len = 32;
+		hex_dump_to_buffer(ubuf, len, 32, 4, dbuf, HEX_DUMP_LEN, 0);
+	} else {
+		dbuf = "";
+	}
+
+	return dbuf;
+}
+
 static void dbg_log_event(struct urb *urb, char * event, unsigned extra)
 {
 	unsigned long flags;
 	int ep_addr;
 	char tbuf[TIME_BUF_LEN];
+	char dbuf[HEX_DUMP_LEN];
 
 	if (!enable_dbg_log)
 		return;
@@ -192,7 +239,7 @@
 	if (!urb) {
 		write_lock_irqsave(&dbg_hsic_ctrl.lck, flags);
 		scnprintf(dbg_hsic_ctrl.buf[dbg_hsic_ctrl.idx], DBG_MSG_LEN,
-			"%s: %s : %u\n", get_timestamp(tbuf), event, extra);
+			"%s: %s : %u", get_timestamp(tbuf), event, extra);
 		dbg_inc(&dbg_hsic_ctrl.idx);
 		write_unlock_irqrestore(&dbg_hsic_ctrl.lck, flags);
 		return;
@@ -208,7 +255,7 @@
 			write_lock_irqsave(&dbg_hsic_ctrl.lck, flags);
 			scnprintf(dbg_hsic_ctrl.buf[dbg_hsic_ctrl.idx],
 				DBG_MSG_LEN, "%s: [%s : %p]:[%s] "
-				  "%02x %02x %04x %04x %04x  %u %d\n",
+				  "%02x %02x %04x %04x %04x  %u %d",
 				  get_timestamp(tbuf), event, urb,
 				  (ep_addr & USB_DIR_IN) ? "in" : "out",
 				  urb->setup_packet[0], urb->setup_packet[1],
@@ -218,14 +265,14 @@
 				  urb->setup_packet[4],
 				  (urb->setup_packet[7] << 8) |
 				  urb->setup_packet[6],
-				  urb->transfer_buffer_length, urb->status);
+				  urb->transfer_buffer_length, extra);
 
 			dbg_inc(&dbg_hsic_ctrl.idx);
 			write_unlock_irqrestore(&dbg_hsic_ctrl.lck, flags);
 		} else {
 			write_lock_irqsave(&dbg_hsic_ctrl.lck, flags);
 			scnprintf(dbg_hsic_ctrl.buf[dbg_hsic_ctrl.idx],
-				DBG_MSG_LEN, "%s: [%s : %p]:[%s] %u %d\n",
+				DBG_MSG_LEN, "%s: [%s : %p]:[%s] %u %d",
 				  get_timestamp(tbuf), event, urb,
 				  (ep_addr & USB_DIR_IN) ? "in" : "out",
 				  urb->actual_length, extra);
@@ -236,12 +283,13 @@
 	} else {
 		write_lock_irqsave(&dbg_hsic_data.lck, flags);
 		scnprintf(dbg_hsic_data.buf[dbg_hsic_data.idx], DBG_MSG_LEN,
-			  "%s: [%s : %p]:ep%d[%s]  %u %d\n",
+			  "%s: [%s : %p]:ep%d[%s]  %u %d %s",
 			  get_timestamp(tbuf), event, urb, ep_addr & 0x0f,
 			  (ep_addr & USB_DIR_IN) ? "in" : "out",
 			  str_to_event(event) ? urb->actual_length :
-			  urb->transfer_buffer_length,
-			  str_to_event(event) ?  extra : urb->status);
+			  urb->transfer_buffer_length, extra,
+			  enable_payload_log ? get_hex_data(dbuf, urb,
+				  str_to_event(event), extra) : "");
 
 		dbg_inc(&dbg_hsic_data.idx);
 		write_unlock_irqrestore(&dbg_hsic_data.lck, flags);
@@ -349,21 +397,33 @@
 static int ulpi_read(struct msm_hsic_hcd *mehci, u32 reg)
 {
 	struct usb_hcd *hcd = hsic_to_hcd(mehci);
-	unsigned long timeout;
+	int cnt = 0;
 
 	/* initiate read operation */
 	writel_relaxed(ULPI_RUN | ULPI_READ | ULPI_ADDR(reg),
 	       USB_ULPI_VIEWPORT);
 
 	/* wait for completion */
-	timeout = jiffies + usecs_to_jiffies(ULPI_IO_TIMEOUT_USEC);
-	while (readl_relaxed(USB_ULPI_VIEWPORT) & ULPI_RUN) {
-		if (time_after(jiffies, timeout)) {
-			dev_err(mehci->dev, "ulpi_read: timeout %08x\n",
-				readl_relaxed(USB_ULPI_VIEWPORT));
-			return -ETIMEDOUT;
-		}
+	while (cnt < ULPI_IO_TIMEOUT_USEC) {
+		if (!(readl_relaxed(USB_ULPI_VIEWPORT) & ULPI_RUN))
+			break;
 		udelay(1);
+		cnt++;
+	}
+
+	if (cnt >= ULPI_IO_TIMEOUT_USEC) {
+		dev_err(mehci->dev, "ulpi_read: timeout ULPI_VIEWPORT: %08x\n",
+				readl_relaxed(USB_ULPI_VIEWPORT));
+		dev_err(mehci->dev, "PORTSC: %08x USBCMD: %08x FRINDEX: %08x\n",
+				readl_relaxed(USB_PORTSC),
+				readl_relaxed(USB_USBCMD),
+				readl_relaxed(USB_FRINDEX));
+
+		/*frame counter increments afte 125us*/
+		udelay(130);
+		dev_err(mehci->dev, "ulpi_read: FRINDEX: %08x\n",
+				readl_relaxed(USB_FRINDEX));
+		return -ETIMEDOUT;
 	}
 
 	return ULPI_DATA_READ(readl_relaxed(USB_ULPI_VIEWPORT));
@@ -388,7 +448,17 @@
 	}
 
 	if (cnt >= ULPI_IO_TIMEOUT_USEC) {
-		dev_err(mehci->dev, "ulpi_write: timeout\n");
+		dev_err(mehci->dev, "ulpi_write: timeout ULPI_VIEWPORT: %08x\n",
+				readl_relaxed(USB_ULPI_VIEWPORT));
+		dev_err(mehci->dev, "PORTSC: %08x USBCMD: %08x FRINDEX: %08x\n",
+				readl_relaxed(USB_PORTSC),
+				readl_relaxed(USB_USBCMD),
+				readl_relaxed(USB_FRINDEX));
+
+		/*frame counter increments afte 125us*/
+		udelay(130);
+		dev_err(mehci->dev, "ulpi_write: FRINDEX: %08x\n",
+				readl_relaxed(USB_FRINDEX));
 		return -ETIMEDOUT;
 	}
 
@@ -597,15 +667,13 @@
 
 	disable_irq(hcd->irq);
 
-	/* make sure we don't race against the root hub being resumed */
-	if (HCD_RH_RUNNING(hcd) || HCD_WAKEUP_PENDING(hcd) ||
+	/* make sure we don't race against a remote wakeup */
+	if (test_bit(HCD_FLAG_WAKEUP_PENDING, &hcd->flags) ||
 	    readl_relaxed(USB_PORTSC) & PORT_RESUME) {
-		dev_warn(mehci->dev, "%s: Root hub is not suspended\n",
-				__func__);
+		dev_dbg(mehci->dev, "wakeup pending, aborting suspend\n");
 		enable_irq(hcd->irq);
 		return -EBUSY;
 	}
-	mehci->irq_enabled = false;
 
 	/*
 	 * PHY may take some time or even fail to enter into low power
@@ -658,21 +726,19 @@
 		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_info(mehci->dev, "HSIC-USB in low power mode\n");
 
 	return 0;
@@ -684,24 +750,26 @@
 	int cnt = 0, ret;
 	unsigned temp;
 	int min_vol, max_vol;
+	unsigned long flags;
 
 	if (!atomic_read(&mehci->in_lpm)) {
 		dev_dbg(mehci->dev, "%s called in !in_lpm\n", __func__);
 		return 0;
 	}
 
+	spin_lock_irqsave(&mehci->wakeup_lock, flags);
 	if (mehci->wakeup_irq_enabled) {
 		disable_irq_wake(mehci->wakeup_irq);
 		disable_irq_nosync(mehci->wakeup_irq);
 		mehci->wakeup_irq_enabled = 0;
 	}
+	spin_unlock_irqrestore(&mehci->wakeup_lock, flags);
+
+	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];
@@ -754,14 +822,13 @@
 	if (mehci->async_int) {
 		mehci->async_int = false;
 		pm_runtime_put_noidle(mehci->dev);
-	}
-
-	if (!mehci->irq_enabled) {
 		enable_irq(hcd->irq);
-		mehci->irq_enabled = true;
 	}
 
-	pm_relax(mehci->dev);
+	if (atomic_read(&mehci->pm_usage_cnt)) {
+		atomic_set(&mehci->pm_usage_cnt, 0);
+		pm_runtime_put_noidle(mehci->dev);
+	}
 
 	dev_info(mehci->dev, "HSIC-USB exited from low power mode\n");
 
@@ -769,28 +836,66 @@
 }
 #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);
+}
+
+#define STS_GPTIMER0_INTERRUPT	BIT(24)
 static irqreturn_t msm_hsic_irq(struct usb_hcd *hcd)
 {
+	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
 	struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
+	u32			status;
 
 	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;
 	}
 
+	status = ehci_readl(ehci, &ehci->regs->status);
+
+	if (status & STS_GPTIMER0_INTERRUPT) {
+		int timeleft;
+
+		dbg_log_event(NULL, "FPR: gpt0_isr", 0);
+
+		timeleft = GPT_CNT(ehci_readl(ehci,
+						 &mehci->timer->gptimer1_ctrl));
+		if (timeleft) {
+			ehci_writel(ehci, ehci_readl(ehci,
+				&ehci->regs->command) | CMD_RUN,
+				&ehci->regs->command);
+		} else
+			mehci->resume_again = 1;
+
+		dbg_log_event(NULL, "FPR: timeleft", timeleft);
+
+		complete(&mehci->gpt0_completion);
+		ehci_writel(ehci, STS_GPTIMER0_INTERRUPT, &ehci->regs->status);
+	}
+
 	return ehci_irq(hcd);
 }
 
 static int ehci_hsic_reset(struct usb_hcd *hcd)
 {
 	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+	struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
 	int retval;
 
+	mehci->timer = USB_HS_GPTIMER_BASE;
 	ehci->caps = USB_CAPLENGTH;
 	ehci->regs = USB_CAPLENGTH +
 		HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
@@ -827,23 +932,204 @@
 	return 0;
 }
 
-static int ehci_hsic_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
-		gfp_t mem_flags)
-{
-	dbg_log_event(urb, event_to_str(URB_SUBMIT), 0);
-	return ehci_urb_enqueue(hcd, urb, mem_flags);
-}
-
 static int ehci_hsic_bus_suspend(struct usb_hcd *hcd)
 {
 	dbg_log_event(NULL, "Suspend RH", 0);
 	return ehci_bus_suspend(hcd);
 }
 
+#define RESUME_RETRY_LIMIT		3
+#define RESUME_SIGNAL_TIME_MS		(21 * 999)
+#define RESUME_SIGNAL_TIME_SOF_MS	(23 * 999)
+static int msm_hsic_resume_thread(void *data)
+{
+	struct msm_hsic_hcd *mehci = data;
+	struct usb_hcd *hcd = hsic_to_hcd(mehci);
+	struct ehci_hcd		*ehci = hcd_to_ehci(hcd);
+	u32			temp;
+	unsigned long		resume_needed = 0;
+	int			retry_cnt = 0;
+	int			tight_resume = 0;
+	struct msm_hsic_host_platform_data *pdata = mehci->dev->platform_data;
+
+	dbg_log_event(NULL, "Resume RH", 0);
+
+	/* keep delay between bus states */
+	if (time_before(jiffies, ehci->next_statechange))
+		usleep_range(5000, 5000);
+
+	spin_lock_irq(&ehci->lock);
+	if (!HCD_HW_ACCESSIBLE(hcd)) {
+		spin_unlock_irq(&ehci->lock);
+		mehci->resume_status = -ESHUTDOWN;
+		complete(&mehci->rt_completion);
+		return 0;
+	}
+
+	if (unlikely(ehci->debug)) {
+		if (!dbgp_reset_prep())
+			ehci->debug = NULL;
+		else
+			dbgp_external_startup();
+	}
+
+	/* at least some APM implementations will try to deliver
+	 * IRQs right away, so delay them until we're ready.
+	 */
+	ehci_writel(ehci, 0, &ehci->regs->intr_enable);
+
+	/* re-init operational registers */
+	ehci_writel(ehci, 0, &ehci->regs->segment);
+	ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list);
+	ehci_writel(ehci, (u32) ehci->async->qh_dma, &ehci->regs->async_next);
+
+	/*CMD_RUN will be set after, PORT_RESUME gets cleared*/
+	if (ehci->resume_sof_bug)
+		ehci->command &= ~CMD_RUN;
+
+	/* restore CMD_RUN, framelist size, and irq threshold */
+	ehci_writel(ehci, ehci->command, &ehci->regs->command);
+
+	/* manually resume the ports we suspended during bus_suspend() */
+resume_again:
+	if (retry_cnt >= RESUME_RETRY_LIMIT) {
+		pr_info("retry count(%d) reached max, resume in tight loop\n",
+					retry_cnt);
+		tight_resume = 1;
+	}
+
+
+	temp = ehci_readl(ehci, &ehci->regs->port_status[0]);
+	temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
+	if (test_bit(0, &ehci->bus_suspended) && (temp & PORT_SUSPEND)) {
+		temp |= PORT_RESUME;
+		set_bit(0, &resume_needed);
+	}
+	dbg_log_event(NULL, "FPR: Set", temp);
+	ehci_writel(ehci, temp, &ehci->regs->port_status[0]);
+
+	/* HSIC controller has a h/w bug due to which it can try to send SOFs
+	 * (start of frames) during port resume resulting in phy lockup. HSIC hw
+	 * controller in MSM clears FPR bit after driving the resume signal for
+	 * 20ms. Workaround is to stop SOFs before driving resume and then start
+	 * sending SOFs immediately. Need to send SOFs within 3ms of resume
+	 * completion otherwise peripheral may enter undefined state. As
+	 * usleep_range does not gurantee exact sleep time, GPTimer is used to
+	 * to time the resume sequence. If driver exceeds allowable time SOFs,
+	 * repeat the resume process.
+	 */
+	if (ehci->resume_sof_bug && resume_needed) {
+		if (!tight_resume) {
+			mehci->resume_again = 0;
+			ehci_writel(ehci, GPT_LD(RESUME_SIGNAL_TIME_MS),
+					&mehci->timer->gptimer0_ld);
+			ehci_writel(ehci, GPT_RESET | GPT_RUN,
+					&mehci->timer->gptimer0_ctrl);
+			ehci_writel(ehci, INTR_MASK | STS_GPTIMER0_INTERRUPT,
+					&ehci->regs->intr_enable);
+
+			ehci_writel(ehci, GPT_LD(RESUME_SIGNAL_TIME_SOF_MS),
+					&mehci->timer->gptimer1_ld);
+			ehci_writel(ehci, GPT_RESET | GPT_RUN,
+				&mehci->timer->gptimer1_ctrl);
+
+			spin_unlock_irq(&ehci->lock);
+			if (pdata && pdata->swfi_latency)
+				pm_qos_update_request(&mehci->pm_qos_req_dma,
+					pdata->swfi_latency + 1);
+			wait_for_completion(&mehci->gpt0_completion);
+			if (pdata && pdata->swfi_latency)
+				pm_qos_update_request(&mehci->pm_qos_req_dma,
+					PM_QOS_DEFAULT_VALUE);
+			spin_lock_irq(&ehci->lock);
+		} else {
+			dbg_log_event(NULL, "FPR: Tightloop", 0);
+			/* do the resume in a tight loop */
+			handshake(ehci, &ehci->regs->port_status[0],
+				PORT_RESUME, 0, 22 * 1000);
+			ehci_writel(ehci, ehci_readl(ehci,
+				&ehci->regs->command) | CMD_RUN,
+				&ehci->regs->command);
+		}
+
+		if (mehci->resume_again) {
+			int temp;
+
+			dbg_log_event(NULL, "FPR: Re-Resume", retry_cnt);
+			pr_info("FPR: retry count: %d\n", retry_cnt);
+			spin_unlock_irq(&ehci->lock);
+			temp = ehci_readl(ehci, &ehci->regs->port_status[0]);
+			temp &= ~PORT_RWC_BITS;
+			temp |= PORT_SUSPEND;
+			ehci_writel(ehci, temp, &ehci->regs->port_status[0]);
+			/* Keep the bus idle for 5ms so that peripheral
+			 * can detect and initiate suspend
+			 */
+			usleep_range(5000, 5000);
+			dbg_log_event(NULL,
+				"FPR: RResume",
+				ehci_readl(ehci, &ehci->regs->port_status[0]));
+			spin_lock_irq(&ehci->lock);
+			mehci->resume_again = 0;
+			retry_cnt++;
+			goto resume_again;
+		}
+	}
+
+	dbg_log_event(NULL, "FPR: RT-Done", 0);
+	mehci->resume_status = 1;
+	spin_unlock_irq(&ehci->lock);
+
+	complete(&mehci->rt_completion);
+
+	return 0;
+}
+
 static int ehci_hsic_bus_resume(struct usb_hcd *hcd)
 {
-	dbg_log_event(NULL, "Resume RH", 0);
-	return ehci_bus_resume(hcd);
+	struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
+	struct ehci_hcd		*ehci = hcd_to_ehci(hcd);
+	u32			temp;
+	struct task_struct	*resume_thread = NULL;
+
+	mehci->resume_status = 0;
+	resume_thread = kthread_run(msm_hsic_resume_thread,
+			mehci, "hsic_resume_thread");
+	if (IS_ERR(resume_thread)) {
+		pr_err("Error creating resume thread:%lu\n",
+				PTR_ERR(resume_thread));
+		return PTR_ERR(resume_thread);
+	}
+
+	wait_for_completion(&mehci->rt_completion);
+
+	if (mehci->resume_status < 0)
+		return mehci->resume_status;
+
+	dbg_log_event(NULL, "FPR: Wokeup", 0);
+	spin_lock_irq(&ehci->lock);
+	(void) ehci_readl(ehci, &ehci->regs->command);
+
+	temp = 0;
+	if (ehci->async->qh_next.qh)
+		temp |= CMD_ASE;
+	if (ehci->periodic_sched)
+		temp |= CMD_PSE;
+	if (temp) {
+		ehci->command |= temp;
+		ehci_writel(ehci, ehci->command, &ehci->regs->command);
+	}
+
+	ehci->next_statechange = jiffies + msecs_to_jiffies(5);
+	hcd->state = HC_STATE_RUNNING;
+	ehci->rh_state = EHCI_RH_RUNNING;
+
+	/* Now we can safely re-enable irqs */
+	ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable);
+
+	spin_unlock_irq(&ehci->lock);
+
+	return 0;
 }
 
 static struct hc_driver msm_hsic_driver = {
@@ -866,7 +1152,7 @@
 	/*
 	 * managing i/o requests and associated device resources
 	 */
-	.urb_enqueue		= ehci_hsic_urb_enqueue,
+	.urb_enqueue		= ehci_urb_enqueue,
 	.urb_dequeue		= ehci_urb_dequeue,
 	.endpoint_disable	= ehci_endpoint_disable,
 	.endpoint_reset		= ehci_endpoint_reset,
@@ -891,7 +1177,7 @@
 	.bus_suspend		= ehci_hsic_bus_suspend,
 	.bus_resume		= ehci_hsic_bus_resume,
 
-	.log_urb_complete	= dbg_log_event,
+	.log_urb		= dbg_log_event,
 	.dump_regs		= dump_hsic_regs,
 
 	.enable_ulpi_control	= ehci_msm_enable_ulpi_control,
@@ -996,15 +1282,20 @@
 	dev_dbg(mehci->dev, "%s: hsic remote wakeup interrupt cnt: %u\n",
 			__func__, mehci->wakeup_int_cnt);
 
-	mehci->async_int = true;
-	pm_runtime_get(mehci->dev);
-	pm_stay_awake(mehci->dev);
+	wake_lock(&mehci->wlock);
 
+	spin_lock(&mehci->wakeup_lock);
 	if (mehci->wakeup_irq_enabled) {
 		mehci->wakeup_irq_enabled = 0;
 		disable_irq_wake(irq);
 		disable_irq_nosync(irq);
 	}
+	spin_unlock(&mehci->wakeup_lock);
+
+	if (!atomic_read(&mehci->pm_usage_cnt)) {
+		atomic_set(&mehci->pm_usage_cnt, 1);
+		pm_runtime_get(mehci->dev);
+	}
 
 	return IRQ_HANDLED;
 }
@@ -1253,13 +1544,17 @@
 
 	mehci = hcd_to_hsic(hcd);
 	mehci->dev = &pdev->dev;
+	pdata = mehci->dev->platform_data;
+
+	spin_lock_init(&mehci->wakeup_lock);
 
 	mehci->ehci.susp_sof_bug = 1;
 	mehci->ehci.reset_sof_bug = 1;
 
 	mehci->ehci.resume_sof_bug = 1;
 
-	mehci->ehci.max_log2_irq_thresh = 6;
+	if (pdata)
+		mehci->ehci.log2_irq_thresh = pdata->log2_irq_thresh;
 
 	res = platform_get_resource_byname(pdev,
 			IORESOURCE_IRQ,
@@ -1288,20 +1583,32 @@
 		goto deinit_clocks;
 	}
 
+	init_completion(&mehci->rt_completion);
+	init_completion(&mehci->gpt0_completion);
 	ret = msm_hsic_reset(mehci);
 	if (ret) {
 		dev_err(&pdev->dev, "unable to initialize PHY\n");
 		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,
@@ -1316,12 +1623,16 @@
 
 	/* configure wakeup irq */
 	if (mehci->wakeup_irq) {
+		/* In case if wakeup gpio is pulled high at this point
+		 * remote wakeup interrupt fires right after request_irq.
+		 * Remote wake up interrupt only needs to be enabled when
+		 * HSIC bus goes to suspend.
+		 */
+		irq_set_status_flags(mehci->wakeup_irq, IRQ_NOAUTOEN);
 		ret = request_irq(mehci->wakeup_irq, msm_hsic_wakeup_irq,
 				IRQF_TRIGGER_HIGH,
 				"msm_hsic_wakeup", mehci);
-		if (!ret) {
-			disable_irq_nosync(mehci->wakeup_irq);
-		} else {
+		if (ret) {
 			dev_err(&pdev->dev, "request_irq(%d) failed: %d\n",
 					mehci->wakeup_irq, ret);
 			mehci->wakeup_irq = 0;
@@ -1333,17 +1644,13 @@
 		dev_dbg(&pdev->dev, "mode debugfs file is"
 			"not available\n");
 
-	pdata = mehci->dev->platform_data;
 	if (pdata && pdata->bus_scale_table) {
 		mehci->bus_perf_client =
 		    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__);
@@ -1352,6 +1659,10 @@
 
 	__mehci = mehci;
 
+	if (pdata && pdata->swfi_latency)
+		pm_qos_add_request(&mehci->pm_qos_req_dma,
+			PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
+
 	/*
 	 * This pdev->dev is assigned parent of root-hub by USB core,
 	 * hence, runtime framework automatically calls this driver's
@@ -1369,6 +1680,7 @@
 	return 0;
 
 unconfig_gpio:
+	destroy_workqueue(ehci_wq);
 	msm_hsic_config_gpios(mehci, 0);
 deinit_vddcx:
 	msm_hsic_init_vddcx(mehci, 0);
@@ -1386,6 +1698,10 @@
 {
 	struct usb_hcd *hcd = platform_get_drvdata(pdev);
 	struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
+	struct msm_hsic_host_platform_data *pdata = mehci->dev->platform_data;
+
+	if (pdata && pdata->swfi_latency)
+		pm_qos_remove_request(&mehci->pm_qos_req_dma);
 
 	if (mehci->peripheral_status_irq)
 		free_irq(mehci->peripheral_status_irq, mehci);
@@ -1396,6 +1712,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);
 
@@ -1403,11 +1727,14 @@
 	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);
 
@@ -1436,12 +1763,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))
@@ -1495,6 +1836,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 c612cb9..34d90fb 100644
--- a/drivers/usb/host/ehci-msm2.c
+++ b/drivers/usb/host/ehci-msm2.c
@@ -59,6 +59,7 @@
 	uint32_t				pmic_gpio_int_cnt;
 	atomic_t				pm_usage_cnt;
 	struct wake_lock			wlock;
+	struct work_struct			phy_susp_fail_work;
 };
 
 static inline struct msm_hcd *hcd_to_mhcd(struct usb_hcd *hcd)
@@ -539,6 +540,19 @@
 	return 0;
 }
 
+static void msm_ehci_phy_susp_fail_work(struct work_struct *w)
+{
+	struct msm_hcd *mhcd = container_of(w, struct msm_hcd,
+					phy_susp_fail_work);
+	struct usb_hcd *hcd = mhcd_to_hcd(mhcd);
+
+	msm_ehci_vbus_power(mhcd, 0);
+	usb_remove_hcd(hcd);
+	msm_hsusb_reset(mhcd);
+	usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
+	msm_ehci_vbus_power(mhcd, 1);
+}
+
 #define PHY_SUSPEND_TIMEOUT_USEC	(500 * 1000)
 #define PHY_RESUME_TIMEOUT_USEC		(100 * 1000)
 
@@ -571,8 +585,8 @@
 		while (!(readl_relaxed(USB_PORTSC) & PORTSC_PHCD)) {
 			if (time_after(jiffies, timeout)) {
 				dev_err(mhcd->dev, "Unable to suspend PHY\n");
-				msm_hsusb_reset(mhcd);
-				break;
+				schedule_work(&mhcd->phy_susp_fail_work);
+				return -ETIMEDOUT;
 			}
 			udelay(1);
 		}
@@ -992,6 +1006,7 @@
 	device_init_wakeup(&pdev->dev, 1);
 	wake_lock_init(&mhcd->wlock, WAKE_LOCK_SUSPEND, dev_name(&pdev->dev));
 	wake_lock(&mhcd->wlock);
+	INIT_WORK(&mhcd->phy_susp_fail_work, msm_ehci_phy_susp_fail_work);
 	/*
 	 * This pdev->dev is assigned parent of root-hub by USB core,
 	 * hence, runtime framework automatically calls this driver's
diff --git a/drivers/usb/host/ehci-msm72k.c b/drivers/usb/host/ehci-msm72k.c
index 816e408..3e53c14 100644
--- a/drivers/usb/host/ehci-msm72k.c
+++ b/drivers/usb/host/ehci-msm72k.c
@@ -399,7 +399,7 @@
 	ehci_writel(ehci, ehci->command, &ehci->regs->command);
 	ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
 
-	hcd->state = HC_STATE_RUNNING;
+	ehci->rh_state = EHCI_RH_RUNNING;
 
 	/*Enable appropriate Interrupts*/
 	ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable);
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index 4c59eab..db49c07 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -128,9 +128,17 @@
 	else {
 		qtd = list_entry (qh->qtd_list.next,
 				struct ehci_qtd, qtd_list);
-		/* first qtd may already be partially processed */
-		if (cpu_to_hc32(ehci, qtd->qtd_dma) == qh->hw->hw_current)
+		/*
+		 * first qtd may already be partially processed.
+		 * If we come here during unlink, the QH overlay region
+		 * might have reference to the just unlinked qtd. The
+		 * qtd is updated in qh_completions(). Update the QH
+		 * overlay here.
+		 */
+		if (cpu_to_hc32(ehci, qtd->qtd_dma) == qh->hw->hw_current) {
+			qh->hw->hw_qtd_next = qtd->hw_next;
 			qtd = NULL;
+		}
 	}
 
 	if (qtd)
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index a0f995c..f8b884a 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -135,7 +135,7 @@
 	ktime_t			last_periodic_enable;
 	u32			command;
 
-	unsigned		max_log2_irq_thresh;
+	unsigned		log2_irq_thresh;
 
 	/* SILICON QUIRKS */
 	unsigned		no_selective_suspend:1;
diff --git a/drivers/usb/misc/diag_bridge.c b/drivers/usb/misc/diag_bridge.c
index 6d5544a..cad411d 100644
--- a/drivers/usb/misc/diag_bridge.c
+++ b/drivers/usb/misc/diag_bridge.c
@@ -20,6 +20,7 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/kref.h>
+#include <linux/mutex.h>
 #include <linux/platform_device.h>
 #include <linux/ratelimit.h>
 #include <linux/uaccess.h>
@@ -38,6 +39,7 @@
 	__u8			out_epAddr;
 	int			err;
 	struct kref		kref;
+	struct mutex		ifc_mutex;
 	struct diag_bridge_ops	*ops;
 	struct platform_device	*pdev;
 
@@ -96,13 +98,9 @@
 	dev_dbg(&dev->ifc->dev, "%s: status:%d actual:%d\n", __func__,
 			urb->status, urb->actual_length);
 
-	if (urb->status == -EPROTO) {
-		dev_err(&dev->ifc->dev, "%s: proto error\n", __func__);
-		/* save error so that subsequent read/write returns ENODEV */
+	/* save error so that subsequent read/write returns ENODEV */
+	if (urb->status == -EPROTO)
 		dev->err = urb->status;
-		kref_put(&dev->kref, diag_bridge_delete);
-		return;
-	}
 
 	if (cbs && cbs->read_complete_cb)
 		cbs->read_complete_cb(cbs->ctxt,
@@ -124,24 +122,34 @@
 
 	pr_debug("reading %d bytes", size);
 
-	if (!dev || !dev->ifc) {
+	if (!dev) {
 		pr_err("device is disconnected");
 		return -ENODEV;
 	}
 
+	mutex_lock(&dev->ifc_mutex);
+	if (!dev->ifc) {
+		ret = -ENODEV;
+		goto error;
+	}
+
 	if (!dev->ops) {
 		pr_err("bridge is not open");
-		return -ENODEV;
+		ret = -ENODEV;
+		goto error;
 	}
 
 	if (!size) {
 		dev_err(&dev->ifc->dev, "invalid size:%d\n", size);
-		return -EINVAL;
+		ret = -EINVAL;
+		goto error;
 	}
 
 	/* if there was a previous unrecoverable error, just quit */
-	if (dev->err)
-		return -ENODEV;
+	if (dev->err) {
+		ret = -ENODEV;
+		goto error;
+	}
 
 	kref_get(&dev->kref);
 
@@ -149,7 +157,7 @@
 	if (!urb) {
 		dev_err(&dev->ifc->dev, "unable to allocate urb\n");
 		ret = -ENOMEM;
-		goto error;
+		goto put_error;
 	}
 
 	ret = usb_autopm_get_interface(dev->ifc);
@@ -174,9 +182,11 @@
 
 free_error:
 	usb_free_urb(urb);
-error:
+put_error:
 	if (ret) /* otherwise this is done in the completion handler */
 		kref_put(&dev->kref, diag_bridge_delete);
+error:
+	mutex_unlock(&dev->ifc_mutex);
 	return ret;
 }
 EXPORT_SYMBOL(diag_bridge_read);
@@ -190,13 +200,9 @@
 
 	usb_autopm_put_interface_async(dev->ifc);
 
-	if (urb->status == -EPROTO) {
-		dev_err(&dev->ifc->dev, "%s: proto error\n", __func__);
-		/* save error so that subsequent read/write returns ENODEV */
+	/* save error so that subsequent read/write returns ENODEV */
+	if (urb->status == -EPROTO)
 		dev->err = urb->status;
-		kref_put(&dev->kref, diag_bridge_delete);
-		return;
-	}
 
 	if (cbs && cbs->write_complete_cb)
 		cbs->write_complete_cb(cbs->ctxt,
@@ -218,24 +224,34 @@
 
 	pr_debug("writing %d bytes", size);
 
-	if (!dev || !dev->ifc) {
+	if (!dev) {
 		pr_err("device is disconnected");
 		return -ENODEV;
 	}
 
+	mutex_lock(&dev->ifc_mutex);
+	if (!dev->ifc) {
+		ret = -ENODEV;
+		goto error;
+	}
+
 	if (!dev->ops) {
 		pr_err("bridge is not open");
-		return -ENODEV;
+		ret = -ENODEV;
+		goto error;
 	}
 
 	if (!size) {
 		dev_err(&dev->ifc->dev, "invalid size:%d\n", size);
-		return -EINVAL;
+		ret = -EINVAL;
+		goto error;
 	}
 
 	/* if there was a previous unrecoverable error, just quit */
-	if (dev->err)
-		return -ENODEV;
+	if (dev->err) {
+		ret = -ENODEV;
+		goto error;
+	}
 
 	kref_get(&dev->kref);
 
@@ -243,7 +259,7 @@
 	if (!urb) {
 		dev_err(&dev->ifc->dev, "unable to allocate urb\n");
 		ret = -ENOMEM;
-		goto error;
+		goto put_error;
 	}
 
 	ret = usb_autopm_get_interface(dev->ifc);
@@ -270,9 +286,11 @@
 
 free_error:
 	usb_free_urb(urb);
-error:
+put_error:
 	if (ret) /* otherwise this is done in the completion handler */
 		kref_put(&dev->kref, diag_bridge_delete);
+error:
+	mutex_unlock(&dev->ifc_mutex);
 	return ret;
 }
 EXPORT_SYMBOL(diag_bridge_write);
@@ -389,6 +407,7 @@
 	dev->udev = usb_get_dev(interface_to_usbdev(ifc));
 	dev->ifc = ifc;
 	kref_init(&dev->kref);
+	mutex_init(&dev->ifc_mutex);
 	init_usb_anchor(&dev->submitted);
 
 	ifc_desc = ifc->cur_altsetting;
@@ -430,7 +449,9 @@
 	dev_dbg(&dev->ifc->dev, "%s:\n", __func__);
 
 	platform_device_unregister(dev->pdev);
+	mutex_lock(&dev->ifc_mutex);
 	dev->ifc = NULL;
+	mutex_unlock(&dev->ifc_mutex);
 	diag_bridge_debugfs_cleanup();
 	kref_put(&dev->kref, diag_bridge_delete);
 	usb_set_intfdata(ifc, NULL);
diff --git a/drivers/usb/misc/ks_bridge.c b/drivers/usb/misc/ks_bridge.c
index 10cbe59..8753c0d 100644
--- a/drivers/usb/misc/ks_bridge.c
+++ b/drivers/usb/misc/ks_bridge.c
@@ -58,6 +58,7 @@
 	struct list_head	to_mdm_list;
 	struct list_head	to_ks_list;
 	wait_queue_head_t	ks_wait_q;
+	struct miscdevice	*fs_dev;
 
 	/* usb specific */
 	struct usb_device	*udev;
@@ -440,8 +441,13 @@
 
 	pr_debug("status:%d actual:%d", urb->status, urb->actual_length);
 
+	/*non zero len of data received while unlinking urb*/
+	if (urb->status == -ENOENT && urb->actual_length > 0)
+		goto add_to_list;
+
 	if (urb->status < 0) {
-		if (urb->status != -ESHUTDOWN && urb->status != -ENOENT)
+		if (urb->status != -ESHUTDOWN && urb->status != -ENOENT
+				&& urb->status != -EPROTO)
 			pr_err_ratelimited("urb failed with err:%d",
 					urb->status);
 		ksb_free_data_pkt(pkt);
@@ -455,6 +461,7 @@
 		goto resubmit_urb;
 	}
 
+add_to_list:
 	spin_lock(&ksb->lock);
 	pkt->len = urb->actual_length;
 	list_add_tail(&pkt->list, &ksb->to_ks_list);
@@ -531,7 +538,6 @@
 	struct usb_endpoint_descriptor	*ep_desc;
 	int				i;
 	struct ks_bridge		*ksb;
-	struct miscdevice		*fs_dev;
 
 	ifc_num = ifc->cur_altsetting->desc.bInterfaceNumber;
 
@@ -585,9 +591,10 @@
 
 	dbg_log_event(ksb, "PID-ATT", id->idProduct, 0);
 
-	fs_dev = (struct miscdevice *)id->driver_info;
-	misc_register(fs_dev);
+	ksb->fs_dev = (struct miscdevice *)id->driver_info;
+	misc_register(ksb->fs_dev);
 
+	ifc->needs_remote_wakeup = 1;
 	usb_enable_autosuspend(ksb->udev);
 
 	pr_debug("usb dev connected");
@@ -601,7 +608,7 @@
 
 	dbg_log_event(ksb, "SUSPEND", 0, 0);
 
-	pr_info("read cnt: %d", ksb->alloced_read_pkts);
+	pr_debug("read cnt: %d", ksb->alloced_read_pkts);
 
 	usb_kill_anchored_urbs(&ksb->submitted);
 
@@ -649,6 +656,8 @@
 	}
 	spin_unlock_irqrestore(&ksb->lock, flags);
 
+	misc_deregister(ksb->fs_dev);
+	ifc->needs_remote_wakeup = 0;
 	usb_put_dev(ksb->udev);
 	ksb->ifc = NULL;
 	usb_set_intfdata(ifc, NULL);
@@ -713,7 +722,8 @@
 		ksb = kzalloc(sizeof(struct ks_bridge), GFP_KERNEL);
 		if (!ksb) {
 			pr_err("unable to allocat mem for ks_bridge");
-			return -ENOMEM;
+			ret =  -ENOMEM;
+			goto dev_free;
 		}
 		__ksb[i] = ksb;
 
diff --git a/drivers/usb/misc/mdm_ctrl_bridge.c b/drivers/usb/misc/mdm_ctrl_bridge.c
index e685233..2f7e2c3 100644
--- a/drivers/usb/misc/mdm_ctrl_bridge.c
+++ b/drivers/usb/misc/mdm_ctrl_bridge.c
@@ -404,7 +404,7 @@
 
 	result = usb_autopm_get_interface_async(dev->intf);
 	if (result < 0) {
-		dev_err(&dev->intf->dev, "%s: unable to resume interface: %d\n",
+		dev_dbg(&dev->intf->dev, "%s: unable to resume interface: %d\n",
 			__func__, result);
 
 		/*
diff --git a/drivers/usb/misc/mdm_data_bridge.c b/drivers/usb/misc/mdm_data_bridge.c
index 1c9de07..c78fd0c 100644
--- a/drivers/usb/misc/mdm_data_bridge.c
+++ b/drivers/usb/misc/mdm_data_bridge.c
@@ -370,7 +370,7 @@
 
 		status = usb_autopm_get_interface(dev->intf);
 		if (status < 0) {
-			dev_err(&dev->intf->dev,
+			dev_dbg(&dev->intf->dev,
 				"can't acquire interface, status %d\n", status);
 			return;
 		}
@@ -389,7 +389,7 @@
 
 		status = usb_autopm_get_interface(dev->intf);
 		if (status < 0) {
-			dev_err(&dev->intf->dev,
+			dev_dbg(&dev->intf->dev,
 				"can't acquire interface, status %d\n", status);
 			return;
 		}
@@ -478,7 +478,7 @@
 
 	result = usb_autopm_get_interface(dev->intf);
 	if (result < 0) {
-		dev_err(&dev->intf->dev, "%s: resume failure\n", __func__);
+		dev_dbg(&dev->intf->dev, "%s: resume failure\n", __func__);
 		goto pm_error;
 	}
 
@@ -990,10 +990,10 @@
 	}
 
 	ch_id--;
-	ctrl_bridge_disconnect(ch_id);
+	ctrl_bridge_disconnect(dev->id);
 	platform_device_unregister(dev->pdev);
 	usb_set_intfdata(intf, NULL);
-	__dev[ch_id] = NULL;
+	__dev[dev->id] = NULL;
 
 	cancel_work_sync(&dev->process_rx_w);
 	cancel_work_sync(&dev->kevent);
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 7a1760f..a6d8c17 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -760,6 +760,14 @@
 		test_bit(A_BUS_SUSPEND, &motg->inputs) &&
 		motg->caps & ALLOW_LPM_ON_DEV_SUSPEND;
 	dcp = motg->chg_type == USB_DCP_CHARGER;
+
+	/* charging detection in progress due to cable plug-in */
+	if (test_bit(B_SESS_VLD, &motg->inputs) && !device_bus_suspend &&
+		!dcp) {
+		enable_irq(motg->irq);
+		return -EBUSY;
+	}
+
 	/*
 	 * Chipidea 45-nm PHY suspend sequence:
 	 *
@@ -879,6 +887,8 @@
 
 	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 &&
@@ -889,6 +899,9 @@
 		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);
 
@@ -979,6 +992,8 @@
 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 &&
@@ -991,10 +1006,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;
@@ -1019,6 +1039,7 @@
 static int msm_otg_notify_chg_type(struct msm_otg *motg)
 {
 	static int charger_type;
+
 	/*
 	 * TODO
 	 * Unify OTG driver charger types and power supply charger types
@@ -1041,7 +1062,14 @@
 	else
 		charger_type = POWER_SUPPLY_TYPE_BATTERY;
 
-	return pm8921_set_usb_power_supply_type(charger_type);
+	if (!psy) {
+		pr_err("No USB power supply registered!\n");
+		return -EINVAL;
+	}
+
+	pr_debug("setting usb power supply type %d\n", charger_type);
+	power_supply_set_supply_type(psy, charger_type);
+	return 0;
 }
 
 static int msm_otg_notify_power_supply(struct msm_otg *motg, unsigned mA)
@@ -1437,6 +1465,11 @@
 	struct usb_phy *phy = &motg->phy;
 	int ret;
 
+	if (!motg->pdata->mhl_enable) {
+		dev_dbg(phy->dev, "MHL feature not enabled\n");
+		return -ENODEV;
+	}
+
 	if (motg->pdata->otg_control != OTG_PMIC_CONTROL ||
 			!motg->pdata->pmic_id_irq) {
 		dev_dbg(phy->dev, "MHL can not be supported without PMIC Id\n");
@@ -2728,17 +2761,11 @@
 	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->sm_work_pending = true;
-			if ((otg->phy->state == OTG_STATE_A_SUSPEND) ||
-				(otg->phy->state == OTG_STATE_A_WAIT_BCON))
-				set_bit(A_BUS_REQ, &motg->inputs);
-		} else {
+		motg->async_int = irq;
+		if (!atomic_read(&motg->pm_suspended))
 			pm_request_resume(otg->phy->dev);
-		}
 		return IRQ_HANDLED;
 	}
 
@@ -3410,6 +3437,11 @@
 		pdata = msm_otg_dt_to_pdata(pdev);
 		if (!pdata)
 			return -ENOMEM;
+
+		pdata->bus_scale_table = msm_bus_cl_get_pdata(pdev);
+		if (!pdata->bus_scale_table)
+			dev_dbg(&pdev->dev, "bus scaling is disabled\n");
+
 		ret = msm_otg_setup_devices(pdev, pdata->mode, true);
 		if (ret) {
 			dev_err(&pdev->dev, "devices setup failed\n");
@@ -3514,6 +3546,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 "
@@ -3600,6 +3638,16 @@
 		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);
 
@@ -3618,7 +3666,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 &&
@@ -3686,6 +3734,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:
@@ -3858,9 +3909,7 @@
 	dev_dbg(dev, "OTG PM resume\n");
 
 	atomic_set(&motg->pm_suspended, 0);
-	if (motg->sm_work_pending) {
-		motg->sm_work_pending = false;
-
+	if (motg->async_int || motg->sm_work_pending) {
 		pm_runtime_get_noresume(dev);
 		ret = msm_otg_resume(motg);
 
@@ -3869,7 +3918,10 @@
 		pm_runtime_set_active(dev);
 		pm_runtime_enable(dev);
 
-		queue_work(system_nrt_wq, &motg->sm_work);
+		if (motg->sm_work_pending) {
+			motg->sm_work_pending = false;
+			queue_work(system_nrt_wq, &motg->sm_work);
+		}
 	}
 
 	return ret;
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c
index 366df67..bde7340 100644
--- a/drivers/usb/serial/usb_wwan.c
+++ b/drivers/usb/serial/usb_wwan.c
@@ -283,6 +283,7 @@
 {
 	struct usb_wwan_port_private *portdata =
 		container_of(w, struct usb_wwan_port_private, in_work);
+	struct usb_wwan_intf_private *intfdata;
 	struct list_head *q = &portdata->in_urb_list;
 	struct urb *urb;
 	unsigned char *data;
@@ -304,7 +305,9 @@
 		if (!tty)
 			break;
 
-		list_del_init(&urb->urb_list);
+		/* list_empty() will still be false after this; it means
+		 * URB is still being processed */
+		list_del(&urb->urb_list);
 
 		spin_unlock_irqrestore(&portdata->in_lock, flags);
 
@@ -326,18 +329,27 @@
 			spin_unlock_irqrestore(&portdata->in_lock, flags);
 			return;
 		}
+
+		/* re-init list pointer to indicate we are done with it */
+		INIT_LIST_HEAD(&urb->urb_list);
+
 		portdata->n_read = 0;
+		intfdata = port->serial->private;
 
-		usb_anchor_urb(urb, &portdata->submitted);
-		err = usb_submit_urb(urb, GFP_ATOMIC);
-		if (err) {
-			usb_unanchor_urb(urb);
-			if (err != -EPERM)
-				pr_err("%s: submit read urb failed:%d",
-						__func__, err);
+		spin_lock_irqsave(&intfdata->susp_lock, flags);
+		if (!intfdata->suspended && !urb->anchor) {
+			usb_anchor_urb(urb, &portdata->submitted);
+			err = usb_submit_urb(urb, GFP_ATOMIC);
+			if (err) {
+				usb_unanchor_urb(urb);
+				if (err != -EPERM)
+					pr_err("%s: submit read urb failed:%d",
+							__func__, err);
+			}
+
+			usb_mark_last_busy(port->serial->dev);
 		}
-
-		usb_mark_last_busy(port->serial->dev);
+		spin_unlock_irqrestore(&intfdata->susp_lock, flags);
 		spin_lock_irqsave(&portdata->in_lock, flags);
 	}
 	spin_unlock_irqrestore(&portdata->in_lock, flags);
@@ -348,6 +360,7 @@
 	int err;
 	int endpoint;
 	struct usb_wwan_port_private *portdata;
+	struct usb_wwan_intf_private *intfdata;
 	struct usb_serial_port *port;
 	int status = urb->status;
 	unsigned long flags;
@@ -357,6 +370,7 @@
 	endpoint = usb_pipeendpoint(urb->pipe);
 	port = urb->context;
 	portdata = usb_get_serial_port_data(port);
+	intfdata = port->serial->private;
 
 	usb_mark_last_busy(port->serial->dev);
 
@@ -373,6 +387,13 @@
 	dbg("%s: nonzero status: %d on endpoint %02x.",
 		__func__, status, endpoint);
 
+	spin_lock(&intfdata->susp_lock);
+	if (intfdata->suspended || !portdata->opened) {
+		spin_unlock(&intfdata->susp_lock);
+		return;
+	}
+	spin_unlock(&intfdata->susp_lock);
+
 	if (status != -ESHUTDOWN) {
 		usb_anchor_urb(urb, &portdata->submitted);
 		err = usb_submit_urb(urb, GFP_ATOMIC);
@@ -495,6 +516,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__);
@@ -849,11 +871,17 @@
 
 		for (j = 0; j < N_IN_URB; j++) {
 			urb = portdata->in_urbs[j];
+
+			/* don't re-submit if it already was submitted or if
+			 * it is being processed by in_work */
+			if (urb->anchor || !list_empty(&urb->urb_list))
+				continue;
+
 			usb_anchor_urb(urb, &portdata->submitted);
 			err = usb_submit_urb(urb, GFP_ATOMIC);
 			if (err < 0) {
-				err("%s: Error %d for bulk URB %d",
-				    __func__, err, i);
+				err("%s: Error %d for bulk URB[%d]:%p %d",
+				    __func__, err, j, urb, i);
 				usb_unanchor_urb(urb);
 				intfdata->suspended = 1;
 				spin_unlock_irq(&intfdata->susp_lock);
diff --git a/drivers/video/msm/external_common.c b/drivers/video/msm/external_common.c
index 0976fc6..c6ffaf2 100644
--- a/drivers/video/msm/external_common.c
+++ b/drivers/video/msm/external_common.c
@@ -1418,7 +1418,7 @@
 		video_format, video_format_2string(video_format),
 		supported ? "Supported" : "Not-Supported");
 	if (supported) {
-		if (mhl_is_connected()) {
+		if (mhl_is_enabled()) {
 			const struct hdmi_disp_mode_timing_type *mhl_timing =
 				hdmi_mhl_get_supported_mode(video_format);
 			boolean mhl_supported = mhl_timing != NULL;
diff --git a/drivers/video/msm/hdmi_msm.c b/drivers/video/msm/hdmi_msm.c
index 26e5687..902e92c 100644
--- a/drivers/video/msm/hdmi_msm.c
+++ b/drivers/video/msm/hdmi_msm.c
@@ -761,60 +761,61 @@
 static int hdmi_msm_read_edid(void);
 static void hdmi_msm_hpd_off(void);
 
-static void hdmi_msm_hpd_state_work(struct work_struct *work)
+static void hdmi_msm_send_event(boolean on)
 {
-	boolean hpd_state = false;
 	char *envp[2];
 
-	if (hdmi_msm_state->is_mhl_enabled) {
-		/*
-		 * HPD will be controlled from MHL
-		 */
-		envp[0] = "";
-		DEV_DBG("%s %u\n", envp[0], hpd_state);
-		return;
+	/* QDSP OFF preceding the HPD event notification */
+	envp[0] = "HDCP_STATE=FAIL";
+	envp[1] = NULL;
+	DEV_ERR("hdmi: HDMI HPD: QDSP OFF\n");
+	kobject_uevent_env(external_common_state->uevent_kobj,
+			   KOBJ_CHANGE, envp);
+
+	if (on) {
+		/* Build EDID table */
+		hdmi_msm_read_edid();
+		switch_set_state(&external_common_state->sdev, 1);
+		DEV_INFO("Hdmi state switched to %d: %s\n",
+			external_common_state->sdev.state,  __func__);
+
+		DEV_INFO("HDMI HPD: CONNECTED: send ONLINE\n");
+		kobject_uevent(external_common_state->uevent_kobj, KOBJ_ONLINE);
+		if (!external_common_state->present_hdcp) {
+			/* Send Audio for HDMI Compliance Cases*/
+			envp[0] = "HDCP_STATE=PASS";
+			envp[1] = NULL;
+			DEV_INFO("HDMI HPD: sense : send HDCP_PASS\n");
+			kobject_uevent_env(external_common_state->uevent_kobj,
+				KOBJ_CHANGE, envp);
+		}
+	} else {
+		switch_set_state(&external_common_state->sdev, 0);
+		DEV_INFO("hdmi: Hdmi state switch to %d: %s\n",
+			external_common_state->sdev.state,  __func__);
+		DEV_INFO("hdmi: HDMI HPD: sense DISCONNECTED: send OFFLINE\n");
+		kobject_uevent(external_common_state->uevent_kobj,
+			KOBJ_OFFLINE);
 	}
+}
+
+static void hdmi_msm_hpd_state_work(struct work_struct *work)
+{
+	boolean hpd_state;
 
 	if (!hdmi_msm_state || !hdmi_msm_state->hpd_initialized ||
 		!MSM_HDMI_BASE) {
-		DEV_DBG("%s: ignored, probe failed\n", __func__);
+		DEV_ERR("hdmi: %s: ignored, probe failed\n", __func__);
 		return;
 	}
 
-	DEV_DBG("%s:Got interrupt\n", __func__);
-	/* HPD_INT_STATUS[0x0250] */
-	hpd_state = (HDMI_INP(0x0250) & 0x2) >> 1;
-	mutex_lock(&external_common_state_hpd_mutex);
 	mutex_lock(&hdmi_msm_state_mutex);
-	if ((external_common_state->hpd_state != hpd_state) || (hdmi_msm_state->
-			hpd_prev_state != external_common_state->hpd_state)) {
-		external_common_state->hpd_state = hpd_state;
-		hdmi_msm_state->hpd_prev_state =
-				external_common_state->hpd_state;
-		DEV_DBG("%s: state not stable yet, wait again (%d|%d|%d)\n",
-			__func__, hdmi_msm_state->hpd_prev_state,
-			external_common_state->hpd_state, hpd_state);
-		mutex_unlock(&external_common_state_hpd_mutex);
-		hdmi_msm_state->hpd_stable = 0;
-		mutex_unlock(&hdmi_msm_state_mutex);
-		mod_timer(&hdmi_msm_state->hpd_state_timer, jiffies + HZ/2);
-		return;
-	}
-	mutex_unlock(&external_common_state_hpd_mutex);
-
-	if (hdmi_msm_state->hpd_stable++) {
-		mutex_unlock(&hdmi_msm_state_mutex);
-		DEV_DBG("%s: no more timer, depending for IRQ now\n",
-			__func__);
-		return;
-	}
-
-	hdmi_msm_state->hpd_stable = 1;
-	DEV_INFO("HDMI HPD: event detected\n");
+	DEV_DBG("%s: Handling HPD event in the workqueue\n", __func__);
 
 	if (!hdmi_msm_state->hpd_cable_chg_detected) {
+		/* The work item got called from outside the ISR */
 		mutex_unlock(&hdmi_msm_state_mutex);
-		if (hpd_state) {
+		if (external_common_state->hpd_state) {
 			if (!external_common_state->
 					disp_mode_list.num_of_elements)
 				hdmi_msm_read_edid();
@@ -822,69 +823,44 @@
 	} else {
 		hdmi_msm_state->hpd_cable_chg_detected = FALSE;
 		mutex_unlock(&hdmi_msm_state_mutex);
-		/* QDSP OFF preceding the HPD event notification */
-		envp[0] = "HDCP_STATE=FAIL";
-		envp[1] = NULL;
-		DEV_INFO("HDMI HPD: QDSP OFF\n");
-		kobject_uevent_env(external_common_state->uevent_kobj,
-				   KOBJ_CHANGE, envp);
-		if (hpd_state) {
-			/* Build EDID table */
-			hdmi_msm_read_edid();
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
-			hdmi_msm_state->reauth = FALSE ;
-#endif
-			switch_set_state(&external_common_state->sdev, 1);
-			DEV_INFO("Hdmi state switched to %d: %s\n",
-				external_common_state->sdev.state,  __func__);
-
-			DEV_INFO("HDMI HPD: CONNECTED: send ONLINE\n");
-			kobject_uevent(external_common_state->uevent_kobj,
-				KOBJ_ONLINE);
-			switch_set_state(&external_common_state->sdev, 1);
-				DEV_INFO("Hdmi state switch to %d: %s\n",
-			external_common_state->sdev.state,  __func__);
-#ifndef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
-			/* Send Audio for HDMI Compliance Cases*/
-			envp[0] = "HDCP_STATE=PASS";
-			envp[1] = NULL;
-			DEV_INFO("HDMI HPD: sense : send HDCP_PASS\n");
-			kobject_uevent_env(external_common_state->uevent_kobj,
-				KOBJ_CHANGE, envp);
-#endif
-		} else {
-			switch_set_state(&external_common_state->sdev, 0);
-			DEV_INFO("Hdmi state switched to %d: %s\n",
-				external_common_state->sdev.state,  __func__);
-
-			DEV_INFO("HDMI HPD: DISCONNECTED: send OFFLINE\n");
-			kobject_uevent(external_common_state->uevent_kobj,
-				KOBJ_OFFLINE);
+		mutex_lock(&external_common_state_hpd_mutex);
+		/*
+		 * Handle the connect event only if the cable is
+		 * still connected. This check is needed for the case
+		 * where we get a connect event followed by a disconnect
+		 * event in quick succession. In this case, there is no need
+		 * to process the connect event.
+		 */
+		if ((external_common_state->hpd_state) &&
+				!((HDMI_INP(0x0250) & 0x2) >> 1)) {
+			external_common_state->hpd_state = 0;
+			hdmi_msm_state->hpd_state_in_isr = 0;
+			mutex_unlock(&external_common_state_hpd_mutex);
+			DEV_DBG("%s: Ignoring HPD connect event\n", __func__);
+			return;
 		}
+		mutex_unlock(&external_common_state_hpd_mutex);
+		hdmi_msm_send_event(external_common_state->hpd_state);
 	}
 
-	/* HPD_INT_CTRL[0x0254]
-	 *   31:10 Reserved
-	 *   9     RCV_PLUGIN_DET_MASK	receiver plug in interrupt mask.
-	 *                              When programmed to 1,
-	 *                              RCV_PLUGIN_DET_INT will toggle
-	 *                              the interrupt line
-	 *   8:6   Reserved
-	 *   5     RX_INT_EN		Panel RX interrupt enable
-	 *         0: Disable
-	 *         1: Enable
-	 *   4     RX_INT_ACK		WRITE ONLY. Panel RX interrupt
-	 *                              ack
-	 *   3     Reserved
-	 *   2     INT_EN		Panel interrupt control
-	 *         0: Disable
-	 *         1: Enable
-	 *   1     INT_POLARITY		Panel interrupt polarity
-	 *         0: generate interrupt on disconnect
-	 *         1: generate interrupt on connect
-	 *   0     INT_ACK		WRITE ONLY. Panel interrupt ack */
-	/* Set IRQ for HPD */
-	HDMI_OUTP(0x0254, 4 | (hpd_state ? 0 : 2));
+	/*
+	 * Wait for a short time before checking for
+	 * any changes in the connection status
+	 */
+	udelay(100);
+
+	mutex_lock(&external_common_state_hpd_mutex);
+	/* HPD_INT_STATUS[0x0250] */
+	hpd_state = (HDMI_INP(0x0250) & 0x2) >> 1;
+
+	if (external_common_state->hpd_state != hpd_state) {
+		external_common_state->hpd_state = hpd_state;
+		hdmi_msm_state->hpd_state_in_isr = hpd_state;
+		mutex_unlock(&external_common_state_hpd_mutex);
+		hdmi_msm_send_event(hpd_state);
+	} else {
+		mutex_unlock(&external_common_state_hpd_mutex);
+	}
 }
 
 #ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT
@@ -917,22 +893,34 @@
 	 */
 	if (external_common_state->present_hdcp) {
 		hdcp_deauthenticate();
+		mutex_lock(&hdcp_auth_state_mutex);
+		hdmi_msm_state->reauth = TRUE;
+		mutex_unlock(&hdcp_auth_state_mutex);
 		mod_timer(&hdmi_msm_state->hdcp_timer, jiffies + HZ/2);
 	}
 }
 
 static void hdmi_msm_hdcp_work(struct work_struct *work)
 {
-
 	/* Only re-enable if cable still connected */
 	mutex_lock(&external_common_state_hpd_mutex);
 	if (external_common_state->hpd_state &&
 	    !(hdmi_msm_state->full_auth_done)) {
 		mutex_unlock(&external_common_state_hpd_mutex);
-		hdmi_msm_state->reauth = TRUE;
-		hdmi_msm_turn_on();
-	} else
+		if (hdmi_msm_state->reauth == TRUE) {
+			DEV_DBG("%s: Starting HDCP re-authentication\n",
+					__func__);
+			hdmi_msm_turn_on();
+		} else {
+			DEV_DBG("%s: Starting HDCP authentication\n", __func__);
+			hdmi_msm_hdcp_enable();
+		}
+	} else {
 		mutex_unlock(&external_common_state_hpd_mutex);
+		DEV_DBG("%s: HDMI not connected or HDCP already active\n",
+				__func__);
+		hdmi_msm_state->reauth = FALSE;
+	}
 }
 #endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */
 
@@ -966,41 +954,54 @@
 	hpd_int_ctrl = HDMI_INP_ND(0x0254);
 	if ((hpd_int_ctrl & (1 << 2)) && (hpd_int_status & (1 << 0))) {
 		boolean cable_detected = (hpd_int_status & 2) >> 1;
-
-		/* HDMI_HPD_INT_CTRL[0x0254] */
-		/* Clear all interrupts, timer will turn IRQ back on
-		 * Leaving the bit[2] on, else core goes off
-		 * on getting HPD during power off
-		 */
-		HDMI_OUTP(0x0254, (1 << 2) | (1 << 0));
-
 		DEV_DBG("%s: HPD IRQ, Ctrl=%04x, State=%04x\n", __func__,
-			hpd_int_ctrl, hpd_int_status);
-		mutex_lock(&hdmi_msm_state_mutex);
-		hdmi_msm_state->hpd_cable_chg_detected = TRUE;
+				hpd_int_ctrl, hpd_int_status);
 
-		/* ensure 2 readouts */
-		hdmi_msm_state->hpd_prev_state = cable_detected ? 0 : 1;
-		external_common_state->hpd_state = cable_detected ? 1 : 0;
-		hdmi_msm_state->hpd_stable = 0;
-		mod_timer(&hdmi_msm_state->hpd_state_timer, jiffies + HZ/2);
-		mutex_unlock(&hdmi_msm_state_mutex);
-		/*
-		 * HDCP Compliance 1A-01:
-		 * The Quantum Data Box 882 triggers two consecutive
-		 * HPD events very close to each other as a part of this
-		 * test which can trigger two parallel HDCP auth threads
-		 * if HDCP authentication is going on and we get ISR
-		 * then stop the authentication , rather than
-		 * reauthenticating it again
-		 */
-		if (!(hdmi_msm_state->full_auth_done)) {
-			DEV_DBG("%s getting hpd while authenticating\n",\
-			    __func__);
-			mutex_lock(&hdcp_auth_state_mutex);
-			hdmi_msm_state->hpd_during_auth = TRUE;
-			mutex_unlock(&hdcp_auth_state_mutex);
+		/* Ack the interrupt */
+		HDMI_OUTP(0x0254, (hpd_int_ctrl | (1 << 0)));
+
+		mutex_lock(&external_common_state_hpd_mutex);
+		if (hdmi_msm_state->hpd_state_in_isr == cable_detected) {
+			DEV_INFO("%s: HPD has the same state. Ignoring\n",
+					__func__);
+			mutex_unlock(&external_common_state_hpd_mutex);
+		} else {
+			if (!mod_timer(&hdmi_msm_state->hpd_state_timer,
+						jiffies + HZ/2)) {
+				hdmi_msm_state->hpd_state_in_isr =
+					cable_detected;
+				hdmi_msm_state->hpd_cable_chg_detected = TRUE;
+				DEV_DBG("%s: Scheduled work to handle HPD %s\n",
+						__func__,
+						cable_detected ? "connect"
+						: "disconnect");
+			}
+
+			mutex_unlock(&external_common_state_hpd_mutex);
+			/*
+			 * HDCP Compliance 1A-01:
+			 * The Quantum Data Box 882 triggers two consecutive
+			 * HPD events very close to each other as a part of this
+			 * test which can trigger two parallel HDCP auth threads
+			 * if HDCP authentication is going on and we get ISR
+			 * then stop the authentication , rather than
+			 * reauthenticating it again
+			 */
+			if (hdmi_msm_state->hdcp_activating &&
+					!(hdmi_msm_state->full_auth_done)) {
+				DEV_DBG("%s getting hpd while authenticating\n",
+					    __func__);
+				mutex_lock(&hdcp_auth_state_mutex);
+				hdmi_msm_state->hpd_during_auth = TRUE;
+				mutex_unlock(&hdcp_auth_state_mutex);
+			}
 		}
+
+		/* Set up HPD_CTRL to sense HPD event */
+		HDMI_OUTP(0x0254, 4 | (cable_detected ? 0 : 2));
+		DEV_DBG("%s: Setting HPD_CTRL=%d\n", __func__,
+				HDMI_INP(0x0254));
+
 		return IRQ_HANDLED;
 	}
 
@@ -1080,10 +1081,11 @@
 	if ((hdcp_int_val & (1 << 6)) && (hdcp_int_val & (1 << 4))) {
 		/* AUTH_FAIL_INT */
 		/* Clear and Disable */
+		uint32 link_status = HDMI_INP_ND(0x011C);
 		HDMI_OUTP(0x0118, (hdcp_int_val | (1 << 5))
 			& ~((1 << 6) | (1 << 4)));
 		DEV_INFO("HDCP: AUTH_FAIL_INT received, LINK0_STATUS=0x%08x\n",
-			HDMI_INP_ND(0x011C));
+			link_status);
 		if (hdmi_msm_state->full_auth_done) {
 			switch_set_state(&external_common_state->sdev, 0);
 			DEV_INFO("Hdmi state switched to %d: %s\n",
@@ -1100,20 +1102,18 @@
 			mutex_unlock(&hdcp_auth_state_mutex);
 			/* Calling reauth only when authentication
 			 * is sucessful or else we always go into
-			 * the reauth loop
+			 * the reauth loop. Also, No need to reauthenticate
+			 * if authentication failed because of cable disconnect
 			 */
-			queue_work(hdmi_work_queue,
-			    &hdmi_msm_state->hdcp_reauth_work);
+			if (((link_status & 0xF0) >> 4) != 0x7) {
+				DEV_DBG("Reauthenticate From %s HDCP FAIL INT ",
+					__func__);
+				queue_work(hdmi_work_queue,
+				    &hdmi_msm_state->hdcp_reauth_work);
+			} else {
+				DEV_INFO("HDCP: HDMI cable disconnected\n");
+			}
 		}
-		mutex_lock(&hdcp_auth_state_mutex);
-		/* This flag prevents other threads from re-authenticating
-		 * after we've just authenticated (i.e., finished part3)
-		 */
-		hdmi_msm_state->full_auth_done = FALSE;
-
-		mutex_unlock(&hdcp_auth_state_mutex);
-		DEV_DBG("calling reauthenticate from %s HDCP FAIL INT ",
-		    __func__);
 
 		/* Clear AUTH_FAIL_INFO as well */
 		HDMI_OUTP(0x0118, (hdcp_int_val | (1 << 7)));
@@ -2230,7 +2230,9 @@
 	/* Disable HDCP interrupts */
 	HDMI_OUTP(0x0118, 0x0);
 
+	mutex_lock(&hdcp_auth_state_mutex);
 	external_common_state->hdcp_active = FALSE;
+	mutex_unlock(&hdcp_auth_state_mutex);
 	/* 0x0130 HDCP_RESET
 	  [0] LINK0_DEAUTHENTICATE */
 	HDMI_OUTP(0x0130, 0x1);
@@ -3017,7 +3019,6 @@
 
 	unfill_black_screen();
 
-	external_common_state->hdcp_active = TRUE;
 	mutex_lock(&hdmi_msm_state_mutex);
 	hdmi_msm_state->hdcp_activating = FALSE;
 	mutex_unlock(&hdmi_msm_state_mutex);
@@ -3028,6 +3029,7 @@
 	 * after we've just authenticated (i.e., finished part3)
 	 */
 	hdmi_msm_state->full_auth_done = TRUE;
+	external_common_state->hdcp_active = TRUE;
 	mutex_unlock(&hdcp_auth_state_mutex);
 
 	if (!hdmi_msm_is_dvi_mode()) {
@@ -3974,19 +3976,6 @@
 	HDMI_OUTP(0x00A4, packet_header);
 	check_sum += IFRAME_CHECKSUM_32(packet_header);
 
-	/* Vendor Name (7bit ASCII code) */
-	/* 0x00A8 GENERIC1_0
-	 *   BYTE0           7:0  CheckSum
-	 *   BYTE1          15:8  VENDOR_NAME[0]
-	 *   BYTE2         23:16  VENDOR_NAME[1]
-	 *   BYTE3         31:24  VENDOR_NAME[2] */
-	packet_payload = ((vendor_name[0] & 0x7f) << 8)
-		| ((vendor_name[1] & 0x7f) << 16)
-		| ((vendor_name[2] & 0x7f) << 24);
-	check_sum += IFRAME_CHECKSUM_32(packet_payload);
-	packet_payload |= ((0x100 - (0xff & check_sum)) & 0xff);
-	HDMI_OUTP(0x00A8, packet_payload);
-
 	/* 0x00AC GENERIC1_1
 	 *   BYTE4           7:0  VENDOR_NAME[3]
 	 *   BYTE5          15:8  VENDOR_NAME[4]
@@ -4068,6 +4057,19 @@
 	HDMI_OUTP(0x00C0, packet_payload);
 	check_sum += IFRAME_CHECKSUM_32(packet_payload);
 
+	/* Vendor Name (7bit ASCII code) */
+	/* 0x00A8 GENERIC1_0
+	 *   BYTE0           7:0  CheckSum
+	 *   BYTE1          15:8  VENDOR_NAME[0]
+	 *   BYTE2         23:16  VENDOR_NAME[1]
+	 *   BYTE3         31:24  VENDOR_NAME[2] */
+	packet_payload = ((vendor_name[0] & 0x7f) << 8)
+		| ((vendor_name[1] & 0x7f) << 16)
+		| ((vendor_name[2] & 0x7f) << 24);
+	check_sum += IFRAME_CHECKSUM_32(packet_payload);
+	packet_payload |= ((0x100 - (0xff & check_sum)) & 0xff);
+	HDMI_OUTP(0x00A8, packet_payload);
+
 	/* GENERIC1_LINE | GENERIC1_CONT | GENERIC1_SEND
 	 * Setup HDMI TX generic packet control
 	 * Enable this packet to transmit every frame
@@ -4156,9 +4158,6 @@
 #endif
 	hdmi_msm_spd_infoframe_packetsetup();
 
-	/* Set IRQ for HPD */
-	HDMI_OUTP(0x0254, 4 | (external_common_state->hpd_state ? 0 : 2));
-
 #ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
 	if (hdmi_msm_state->reauth) {
 		hdmi_msm_hdcp_enable();
@@ -4181,7 +4180,32 @@
 
 static void hdmi_msm_hpd_state_timer(unsigned long data)
 {
-	queue_work(hdmi_work_queue, &hdmi_msm_state->hpd_state_work);
+	if (!work_busy(&hdmi_msm_state->hpd_state_work)) {
+		/*
+		 * There is no event currently queued.
+		 * Only queue the work if this event has not already
+		 * been processed.
+		 */
+		if (external_common_state->hpd_state !=
+				hdmi_msm_state->hpd_state_in_isr) {
+			/*
+			 * There is no need to use any synchronization
+			 * construct for safeguarding these state vairables
+			 * here since the only other place these are modified
+			 * is in the HPD work thread, which is known to be not
+			 * pending/running.
+			 */
+			external_common_state->hpd_state =
+				hdmi_msm_state->hpd_state_in_isr;
+			DEV_DBG("%s: Queuing work to handle HPD %s event\n",
+					__func__,
+					external_common_state->hpd_state ?
+					"connect" : "disconnect");
+			queue_work(hdmi_work_queue,
+					&hdmi_msm_state->hpd_state_work);
+			return;
+		}
+	}
 }
 
 #ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
@@ -4211,6 +4235,10 @@
 	del_timer(&hdmi_msm_state->hpd_state_timer);
 	disable_irq(hdmi_msm_state->irq);
 
+	/* Disable HPD interrupt */
+	HDMI_OUTP(0x0254, 0);
+	DEV_DBG("%s: Disabling HPD_CTRLd\n", __func__);
+
 	hdmi_msm_set_mode(FALSE);
 	hdmi_msm_state->pd->enable_5v(0);
 	hdmi_msm_clk(0);
@@ -4229,7 +4257,7 @@
 #endif
 }
 
-static int hdmi_msm_hpd_on(bool trigger_handler)
+static int hdmi_msm_hpd_on(void)
 {
 	static int phy_reset_done;
 	uint32 hpd_ctrl;
@@ -4270,35 +4298,33 @@
 		/* HDMI_USEC_REFTIMER[0x0208] */
 		HDMI_OUTP(0x0208, 0x0001001B);
 
+		/* Set up HPD state variables */
+		mutex_lock(&external_common_state_hpd_mutex);
+		external_common_state->hpd_state = 0;
+		hdmi_msm_state->hpd_state_in_isr = 0;
+		mutex_unlock(&external_common_state_hpd_mutex);
+		mutex_lock(&hdmi_msm_state_mutex);
+		hdmi_msm_state->hpd_cable_chg_detected = TRUE;
+		mutex_unlock(&hdmi_msm_state_mutex);
+
+		/* Set up HPD_CTRL to sense HPD event */
+		HDMI_OUTP(0x0254, 0x6);
+		DEV_DBG("%s: Setting HPD_CTRL=%d\n", __func__,
+				HDMI_INP(0x0254));
+
+		hdmi_msm_state->hpd_initialized = TRUE;
+
+		enable_irq(hdmi_msm_state->irq);
+
 		/* set timeout to 4.1ms (max) for hardware debounce */
 		hpd_ctrl = HDMI_INP(0x0258) | 0x1FFF;
 
 		/* Toggle HPD circuit to trigger HPD sense */
 		HDMI_OUTP(0x0258, ~(1 << 28) & hpd_ctrl);
 		HDMI_OUTP(0x0258, (1 << 28) | hpd_ctrl);
-
-		hdmi_msm_state->hpd_initialized = TRUE;
-
-		/* Check HPD State */
-		enable_irq(hdmi_msm_state->irq);
 	}
 
-	if (trigger_handler) {
-		/* Set HPD state machine: ensure at least 2 readouts */
-		mutex_lock(&external_common_state_hpd_mutex);
-		mutex_lock(&hdmi_msm_state_mutex);
-		hdmi_msm_state->hpd_stable = 0;
-		hdmi_msm_state->hpd_prev_state = TRUE;
-		external_common_state->hpd_state = FALSE;
-		hdmi_msm_state->hpd_cable_chg_detected = TRUE;
-		mutex_unlock(&hdmi_msm_state_mutex);
-		mutex_unlock(&external_common_state_hpd_mutex);
-		mod_timer(&hdmi_msm_state->hpd_state_timer,
-			jiffies + HZ/2);
-	}
-
-	DEV_DBG("%s: (IRQ, 5V on) <trigger:%s>\n", __func__,
-		trigger_handler ? "true" : "false");
+	DEV_DBG("%s: (IRQ, 5V on)\n", __func__);
 	return 0;
 
 error3:
@@ -4321,7 +4347,7 @@
 		if (hdmi_prim_display ||
 			external_common_state->hpd_feature_on) {
 			DEV_DBG("%s: Turning HPD ciruitry on\n", __func__);
-			rc = hdmi_msm_hpd_on(true);
+			rc = hdmi_msm_hpd_on();
 		}
 	} else {
 		DEV_DBG("%s: Turning HPD ciruitry off\n", __func__);
@@ -4342,15 +4368,6 @@
 	DEV_INFO("power: ON (%dx%d %d)\n", mfd->var_xres, mfd->var_yres,
 		mfd->var_pixclock);
 
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
-	mutex_lock(&hdmi_msm_state_mutex);
-	if (hdmi_msm_state->hdcp_activating) {
-		hdmi_msm_state->panel_power_on = TRUE;
-		DEV_INFO("HDCP: activating, returning\n");
-	}
-	mutex_unlock(&hdmi_msm_state_mutex);
-#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */
-
 	changed = hdmi_common_get_video_format_from_drv_data(mfd);
 	hdmi_msm_audio_info_setup(TRUE, 0, 0, 0, FALSE);
 
@@ -4360,7 +4377,13 @@
 		DEV_DBG("%s: Turning HDMI on\n", __func__);
 		mutex_unlock(&external_common_state_hpd_mutex);
 		hdmi_msm_turn_on();
-		hdmi_msm_hdcp_enable();
+
+		/* Kick off HDCP Authentication */
+		mutex_lock(&hdcp_auth_state_mutex);
+		hdmi_msm_state->reauth = FALSE;
+		hdmi_msm_state->full_auth_done = FALSE;
+		mutex_unlock(&hdcp_auth_state_mutex);
+		mod_timer(&hdmi_msm_state->hdcp_timer, jiffies + HZ/2);
 	} else
 		mutex_unlock(&external_common_state_hpd_mutex);
 
@@ -4448,6 +4471,11 @@
 	return 0;
 }
 
+bool mhl_is_enabled(void)
+{
+	return hdmi_msm_state->is_mhl_enabled;
+}
+
 static int __devinit hdmi_msm_probe(struct platform_device *pdev)
 {
 	int rc;
@@ -4590,7 +4618,7 @@
 		DEV_ERR("Init FAILED: failed to add fb device\n");
 
 	if (hdmi_prim_display) {
-		rc = hdmi_msm_hpd_on(true);
+		rc = hdmi_msm_hpd_on();
 		if (rc)
 			goto error;
 	}
@@ -4620,6 +4648,12 @@
 	if (switch_dev_register(&external_common_state->sdev) < 0)
 		DEV_ERR("Hdmi switch registration failed\n");
 
+	/* Set the default video resolution for MHL-enabled display */
+	if (hdmi_msm_state->is_mhl_enabled) {
+		DEV_DBG("MHL Enabled. Restricting default video resolution\n");
+		external_common_state->video_resolution =
+			HDMI_VFRMT_1920x1080p30_16_9;
+	}
 	return 0;
 
 error:
@@ -4692,7 +4726,7 @@
 
 	DEV_INFO("%s: %d\n", __func__, on);
 	if (on) {
-		rc = hdmi_msm_hpd_on(true);
+		rc = hdmi_msm_hpd_on();
 	} else {
 		hdmi_msm_hpd_off();
 		/* Set HDMI switch node to 0 on HPD feature disable */
diff --git a/drivers/video/msm/hdmi_msm.h b/drivers/video/msm/hdmi_msm.h
index 243a27b..5d27412 100644
--- a/drivers/video/msm/hdmi_msm.h
+++ b/drivers/video/msm/hdmi_msm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, 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
@@ -53,11 +53,10 @@
 struct hdmi_msm_state_type {
 	boolean panel_power_on;
 	boolean hpd_initialized;
+	boolean hpd_state_in_isr;
 #ifdef CONFIG_SUSPEND
 	boolean pm_suspended;
 #endif
-	int hpd_stable;
-	boolean hpd_prev_state;
 	boolean hpd_cable_chg_detected;
 	boolean full_auth_done;
 	boolean hpd_during_auth;
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 c2a110c..54fb0cb 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;
@@ -547,7 +548,7 @@
 	}
 
 	/*mask off non LUT select bits*/
-	out = inpdw(MDP_BASE + 0x90070) & ~((0x1 << 10) | 0x7);
+	out = inpdw(MDP_BASE + 0x90070);
 	MDP_OUTP(MDP_BASE + 0x90070, (mdp_lut_i << 10) | 0x7 | out);
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 	mdp_lut_i = (mdp_lut_i + 1)%2;
@@ -1284,34 +1285,6 @@
 	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)
@@ -1564,6 +1537,7 @@
 				mdp_clk_disable_unprepare();
 		}
 	}
+	pr_debug("%s: on=%d cnt=%d\n", __func__, on, mdp_clk_cnt);
 	mutex_unlock(&mdp_suspend_mutex);
 }
 
@@ -1769,6 +1743,7 @@
 	struct mdp_hist_mgmt *mgmt = NULL;
 	char *base_addr;
 	int i, ret;
+	int vsync_isr;
 	/* Ensure all the register write are complete */
 	mb();
 
@@ -1788,8 +1763,23 @@
 		goto out;
 
 	/*Primary Vsync interrupt*/
-	if (mdp_interrupt & MDP_PRIM_RDPTR)
-		vsync_isr_handler();
+	if (mdp_interrupt & MDP_PRIM_RDPTR) {
+		spin_lock_irqsave(&mdp_spin_lock, flag);
+		vsync_isr = vsync_cntrl.vsync_irq_enabled;
+		if (!vsync_isr) {
+			mdp_intr_mask &= ~MDP_PRIM_RDPTR;
+			outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+		}
+		spin_unlock_irqrestore(&mdp_spin_lock, flag);
+
+		if (vsync_isr) {
+			vsync_isr_handler();
+		} else {
+			mdp_pipe_ctrl(MDP_CMD_BLOCK,
+				MDP_BLOCK_POWER_OFF, TRUE);
+			complete(&vsync_cntrl.vsync_wait);
+		}
+	}
 
 	/* DMA3 TV-Out Start */
 	if (mdp_interrupt & TV_OUT_DMA3_START) {
@@ -1837,21 +1827,26 @@
 		if (mdp_interrupt & LCDC_FRAME_START) {
 			dma = &dma2_data;
 			spin_lock_irqsave(&mdp_spin_lock, flag);
+			vsync_isr = vsync_cntrl.vsync_irq_enabled;
 			/* let's disable LCDC interrupt */
 			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)) {
+			if (!vsync_isr) {
 				mdp_intr_mask &= ~LCDC_FRAME_START;
 				outp32(MDP_INTR_ENABLE, mdp_intr_mask);
 			}
-
 			spin_unlock_irqrestore(&mdp_spin_lock, flag);
+
+			if (vsync_isr) {
+				vsync_isr_handler();
+			} else {
+				mdp_pipe_ctrl(MDP_CMD_BLOCK,
+					MDP_BLOCK_POWER_OFF, TRUE);
+				complete(&vsync_cntrl.vsync_wait);
+			}
 		}
 
 		/* DMA2 LCD-Out Complete */
@@ -1982,6 +1977,7 @@
 		atomic_set(&mdp_block_power_cnt[i], 0);
 	}
 	INIT_WORK(&(vsync_cntrl.vsync_work), send_vsync_work);
+	init_completion(&vsync_cntrl.vsync_wait);
 #ifdef MSM_FB_ENABLE_DBGFS
 	{
 		struct dentry *root;
@@ -2065,8 +2061,10 @@
 	int ret = 0;
 	struct msm_fb_data_type *mfd = platform_get_drvdata(pdev);
 
+	pr_debug("%s:+\n", __func__);
 	mdp_histogram_ctrl_all(FALSE);
 
+	mdp_clk_ctrl(1);
 	if (mfd->panel.type == MIPI_CMD_PANEL)
 		mdp4_dsi_cmd_off(pdev);
 	else if (mfd->panel.type == MIPI_VIDEO_PANEL)
@@ -2079,9 +2077,11 @@
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 	ret = panel_next_off(pdev);
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+	mdp_clk_ctrl(0);
 
 	if (mdp_rev >= MDP_REV_41 && mfd->panel.type == MIPI_CMD_PANEL)
 		mdp_dsi_cmd_overlay_suspend(mfd);
+	pr_debug("%s:-\n", __func__);
 	return ret;
 }
 
@@ -2102,6 +2102,8 @@
 	struct msm_fb_data_type *mfd;
 	mfd = platform_get_drvdata(pdev);
 
+	pr_debug("%s:+\n", __func__);
+
 	if (mdp_rev >= MDP_REV_40) {
 		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 		mdp_clk_ctrl(1);
@@ -2131,8 +2133,8 @@
 	ret = panel_next_on(pdev);
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 
-
 	mdp_histogram_ctrl_all(TRUE);
+	pr_debug("%s:-\n", __func__);
 
 	return ret;
 }
@@ -2178,33 +2180,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)
@@ -2223,29 +2198,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;
@@ -2258,25 +2228,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)
 {
@@ -2333,21 +2284,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
@@ -2369,6 +2324,7 @@
 	struct mipi_panel_info *mipi;
 #endif
 	static int contSplash_update_done;
+	char *cp;
 
 	if ((pdev->id == 0) && (pdev->num_resources > 0)) {
 		mdp_init_pdev = pdev;
@@ -2406,7 +2362,7 @@
 		if (!(mdp_pdata->cont_splash_enabled))
 			mdp4_hw_init();
 #else
-		mdp_hw_init();
+		mdp_hw_init(mdp_pdata->cont_splash_enabled);
 #endif
 
 #ifdef CONFIG_FB_MSM_OVERLAY
@@ -2443,7 +2399,44 @@
 	if (mdp_pdata) {
 		if (mdp_pdata->cont_splash_enabled) {
 			mfd->cont_splash_done = 0;
+
 			if (!contSplash_update_done) {
+				uint32 bpp = 3;
+				/*read panel wxh and calculate splash screen
+				size*/
+				mdp_pdata->splash_screen_size =
+						inpdw(MDP_BASE + 0x90004);
+				mdp_pdata->splash_screen_size =
+				(((mdp_pdata->splash_screen_size >> 16) &
+					0x00000FFF) * (
+					mdp_pdata->splash_screen_size &
+					0x00000FFF)) * bpp;
+
+				mdp_pdata->splash_screen_addr =
+						inpdw(MDP_BASE + 0x90008);
+
+				mfd->copy_splash_buf = dma_alloc_coherent(NULL,
+					mdp_pdata->splash_screen_size,
+					(dma_addr_t *) &(mfd->copy_splash_phys),
+					GFP_KERNEL);
+
+				if (!mfd->copy_splash_buf) {
+					pr_err("DMA ALLOC FAILED for SPLASH\n");
+					return -ENOMEM;
+				}
+				cp = (char *)ioremap(
+						mdp_pdata->splash_screen_addr,
+						mdp_pdata->splash_screen_size);
+				if (!cp) {
+					pr_err("IOREMAP FAILED for SPLASH\n");
+					return -ENOMEM;
+				}
+				memcpy(mfd->copy_splash_buf, cp,
+					mdp_pdata->splash_screen_size);
+
+				MDP_OUTP(MDP_BASE + 0x90008,
+						mfd->copy_splash_phys);
+
 				if (mfd->panel.type == MIPI_VIDEO_PANEL ||
 				    mfd->panel.type == LCDC_PANEL)
 					mdp_pipe_ctrl(MDP_CMD_BLOCK,
@@ -2468,8 +2461,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();
@@ -2568,7 +2559,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;
@@ -2598,6 +2588,7 @@
 		else {
 			printk(KERN_ERR "Invalid Selection of destination panel\n");
 			rc = -ENODEV;
+			mdp_clk_ctrl(0);
 			goto mdp_probe_err;
 		}
 
@@ -2612,7 +2603,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;
@@ -2645,6 +2635,7 @@
 		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,
@@ -2696,8 +2687,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);
@@ -2744,6 +2733,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;
@@ -2835,6 +2825,17 @@
 	mutex_unlock(&mdp_suspend_mutex);
 }
 
+void mdp_free_splash_buffer(struct msm_fb_data_type *mfd)
+{
+	if (mfd->copy_splash_buf) {
+		dma_free_coherent(NULL,	mdp_pdata->splash_screen_size,
+			mfd->copy_splash_buf,
+			(dma_addr_t) mfd->copy_splash_phys);
+
+		mfd->copy_splash_buf = NULL;
+	}
+}
+
 #ifdef CONFIG_PM
 static void mdp_suspend_sub(void)
 {
diff --git a/drivers/video/msm/mdp.h b/drivers/video/msm/mdp.h
index 76d06a0..2825f87 100644
--- a/drivers/video/msm/mdp.h
+++ b/drivers/video/msm/mdp.h
@@ -44,6 +44,7 @@
 extern int mdp_rev;
 extern int mdp_iommu_split_domain;
 extern struct mdp_csc_cfg mdp_csc_convert[4];
+extern struct mdp_csc_cfg_data csc_cfg_matrix[];
 extern struct workqueue_struct *mdp_hist_wq;
 
 extern uint32 mdp_intr_mask;
@@ -96,6 +97,7 @@
 	struct device *dev;
 	struct work_struct vsync_work;
 	int vsync_irq_enabled;
+	struct completion vsync_wait;
 };
 
 extern struct vsync vsync_cntrl;
@@ -717,7 +719,7 @@
 #define MDP_DMA_P_LUT_C2_EN   BIT(2)
 #define MDP_DMA_P_LUT_POST    BIT(4)
 
-void mdp_hw_init(void);
+void mdp_hw_init(int splash);
 int mdp_ppp_pipe_wait(void);
 void mdp_pipe_kickoff(uint32 term, struct msm_fb_data_type *mfd);
 void mdp_clk_ctrl(int on);
@@ -762,7 +764,7 @@
 int mdp_lcdc_on(struct platform_device *pdev);
 int mdp_lcdc_off(struct platform_device *pdev);
 void mdp_lcdc_update(struct msm_fb_data_type *mfd);
-
+void mdp_free_splash_buffer(struct msm_fb_data_type *mfd);
 #ifdef CONFIG_FB_MSM_MDP303
 int mdp_dsi_video_on(struct platform_device *pdev);
 int mdp_dsi_video_off(struct platform_device *pdev);
@@ -812,7 +814,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);
 
@@ -827,8 +831,6 @@
 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_prepare_enable(void);
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index 767332a..6fc83df 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
@@ -192,6 +193,8 @@
 	MDP4_CHROMA_420
 };
 
+#define CSC_MAX_BLOCKS 6
+
 #define MDP4_BLEND_BG_TRANSP_EN		BIT(9)
 #define MDP4_BLEND_FG_TRANSP_EN		BIT(8)
 #define MDP4_BLEND_BG_MOD_ALPHA		BIT(7)
@@ -361,6 +364,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;
@@ -453,9 +458,6 @@
 void mdp4_clear_lcdc(void);
 void mdp4_mixer_blend_init(int mixer_num);
 void mdp4_vg_qseed_init(int vg_num);
-void mdp4_vg_csc_setup(int vp_num);
-void mdp4_mixer_csc_setup(uint32 mixer);
-void mdp4_dmap_csc_setup(void);
 void mdp4_vg_csc_update(struct mdp_csc *p);
 irqreturn_t mdp4_isr(int irq, void *ptr);
 void mdp4_overlay_format_to_pipe(uint32 format, struct mdp4_overlay_pipe *pipe);
@@ -478,7 +480,7 @@
 			struct mdp4_overlay_pipe *pipe);
 void mdp4_dmae_done_dtv(void);
 void mdp4_dtv_wait4vsync(int cndx, long long *vtime);
-void mdp4_dtv_vsync_ctrl(int cndx, int enable);
+void mdp4_dtv_vsync_ctrl(struct fb_info *info, int enable);
 void mdp4_dtv_base_swap(int cndx, struct mdp4_overlay_pipe *pipe);
 #else
 static inline void mdp4_overlay_dtv_start(void)
@@ -514,7 +516,7 @@
 {
     /* empty */
 }
-static inline void mdp4_dtv_vsync_ctrl(int cndx, long long *vtime)
+static inline void mdp4_dtv_vsync_ctrl(struct fb_info *info, int enable)
 {
     /* empty */
 }
@@ -546,7 +548,7 @@
 int mdp4_atv_off(struct platform_device *pdev);
 void mdp4_dsi_video_fxn_register(cmd_fxn_t fxn);
 void mdp4_dsi_video_overlay(struct msm_fb_data_type *mfd);
-void mdp4_lcdc_vsync_ctrl(int cndx, int enable);
+void mdp4_lcdc_vsync_ctrl(struct fb_info *info, int enable);
 void mdp4_overlay0_done_dsi_video(int cndx);
 void mdp4_overlay0_done_dsi_cmd(int cndx);
 void mdp4_primary_rdptr(void);
@@ -554,6 +556,7 @@
 int mdp4_overlay_commit(struct fb_info *info, int mixer);
 int mdp4_dsi_video_pipe_commit(void);
 int mdp4_dsi_cmd_pipe_commit(void);
+int mdp4_dsi_cmd_update_cnt(int cndx);
 int mdp4_lcdc_pipe_commit(void);
 int mdp4_dtv_pipe_commit(void);
 void mdp4_dsi_rdptr_init(int cndx);
@@ -565,9 +568,10 @@
 void mdp4_overlay_rgb_setup(struct mdp4_overlay_pipe *pipe);
 void mdp4_overlay_reg_flush(struct mdp4_overlay_pipe *pipe, int all);
 void mdp4_mixer_blend_setup(int mixer);
+void mdp4_mixer_blend_cfg(int);
 struct mdp4_overlay_pipe *mdp4_overlay_stage_pipe(int mixer, int stage);
-void mdp4_mixer_stage_up(struct mdp4_overlay_pipe *pipe);
-void mdp4_mixer_stage_down(struct mdp4_overlay_pipe *pipe);
+void mdp4_mixer_stage_up(struct mdp4_overlay_pipe *pipe, int commit);
+void mdp4_mixer_stage_down(struct mdp4_overlay_pipe *pipe, int commit);
 void mdp4_mixer_pipe_cleanup(int mixer);
 int mdp4_mixer_stage_can_run(struct mdp4_overlay_pipe *pipe);
 void mdp4_overlayproc_cfg(struct mdp4_overlay_pipe *pipe);
@@ -610,9 +614,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
@@ -728,6 +729,12 @@
 {
 	/* 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,
@@ -766,8 +773,8 @@
 void mdp4_dsi_video_wait4vsync(int cndx, long long *vtime);
 void mdp4_dsi_cmd_pipe_queue(int cndx, struct mdp4_overlay_pipe *pipe);
 void mdp4_dsi_video_pipe_queue(int cndx, struct mdp4_overlay_pipe *pipe);
-void mdp4_dsi_cmd_vsync_ctrl(int cndx, int enable);
-void mdp4_dsi_video_vsync_ctrl(int cndx, int enable);
+void mdp4_dsi_cmd_vsync_ctrl(struct fb_info *info, int enable);
+void mdp4_dsi_video_vsync_ctrl(struct fb_info *info, int enable);
 #ifdef CONFIG_FB_MSM_MDP303
 static inline void mdp4_dsi_cmd_del_timer(void)
 {
@@ -815,10 +822,12 @@
 			struct mdp4_overlay_pipe *pipe)
 {
 }
-static inline void mdp4_dsi_cmd_vsync_ctrl(int cndx, int enable)
+static inline void mdp4_dsi_cmd_vsync_ctrl(struct fb_info *info,
+				int enable)
 {
 }
-static inline void mdp4_dsi_video_vsync_ctrl(int cndx, int enable)
+static inline void mdp4_dsi_video_vsync_ctrl(struct fb_info *info,
+				int enable)
 {
 }
 
@@ -847,9 +856,6 @@
 void mdp4_dsi_video_3d_sbys(struct msm_fb_data_type *mfd,
 			 struct msmfb_overlay_3d *r3d);
 
-void mdp4_backlight_init(int cndx);
-void mdp4_backlight_put_level(int cndx, int level);
-
 int mdp4_mixer_info(int mixer_num, struct mdp_mixer_info *info);
 
 void mdp_dmap_vsync_set(int enable);
@@ -874,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);
@@ -917,5 +920,29 @@
 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);
+int mdp4_update_base_blend(struct msm_fb_data_type *mfd,
+				struct mdp_blend_cfg *mdp_blend_cfg);
+u32 mdp4_get_mixer_num(u32 panel_type);
+
+#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 9454dfe..63f0aa1 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;
 
 
@@ -136,6 +150,9 @@
 		ion_unmap_iommu(display_iclient, ihdl, DISPLAY_READ_DOMAIN,
 							GEN_POOL);
 		mdp4_stat.iommu_unmap++;
+		pr_debug("%s: map=%d unmap=%d drop=%d\n", __func__,
+			(int)mdp4_stat.iommu_map, (int)mdp4_stat.iommu_unmap,
+				(int)mdp4_stat.iommu_drop);
 		ion_free(display_iclient, ihdl);
 		flist->ihdl[i] = NULL;
 	}
@@ -475,14 +492,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;
 	}
 
@@ -736,6 +757,7 @@
 		case MDP_Y_CBCR_H1V1:
 		case MDP_Y_CRCB_H2V1:
 		case MDP_Y_CBCR_H2V1:
+		case MDP_Y_CRCB_H1V2:
 			*luma_off = pipe->src_x;
 			*chroma_off = pipe->src_x;
 			break;
@@ -773,7 +795,8 @@
 	uint32 frame_size, src_size, src_xy, dst_size, dst_xy;
 	uint32 format, pattern, luma_offset, chroma_offset;
 	uint32 mask;
-	int pnum, ptype;
+	int pnum, ptype, i;
+	uint32_t block;
 
 	pnum = pipe->pipe_num - OVERLAY_PIPE_VG1; /* start from 0 */
 	vg_base = MDP_BASE + MDP4_VIDEO_BASE;
@@ -801,6 +824,20 @@
 
 			mdp4_csc_write(&pipe->pp_cfg.csc_cfg,
 				(uint32_t) (vg_base + MDP4_VIDEO_CSC_OFF));
+
+			if (pipe->pipe_num == OVERLAY_PIPE_VG1)
+				block = MDP_BLOCK_VG_1;
+			else
+				block = MDP_BLOCK_VG_2;
+
+			for (i = 0; i < CSC_MAX_BLOCKS; i++) {
+				if (block == csc_cfg_matrix[i].block) {
+					memcpy(&csc_cfg_matrix[i].csc_data,
+					&(pipe->pp_cfg.csc_cfg),
+					sizeof(struct mdp_csc_cfg));
+					break;
+				}
+			}
 		}
 		if (pipe->pp_cfg.config_ops & MDP_OVERLAY_PP_QSEED_CFG) {
 			mdp4_qseed_access_cfg(&pipe->pp_cfg.qseed_cfg[0],
@@ -925,6 +962,7 @@
 	case MDP_YCRYCB_H2V1:
 	case MDP_Y_CRCB_H2V1:
 	case MDP_Y_CBCR_H2V1:
+	case MDP_Y_CRCB_H1V2:
 	case MDP_Y_CRCB_H2V2:
 	case MDP_Y_CBCR_H2V2:
 	case MDP_Y_CBCR_H2V2_TILE:
@@ -1108,6 +1146,7 @@
 		break;
 	case MDP_Y_CRCB_H2V1:
 	case MDP_Y_CBCR_H2V1:
+	case MDP_Y_CRCB_H1V2:
 	case MDP_Y_CRCB_H2V2:
 	case MDP_Y_CBCR_H2V2:
 	case MDP_Y_CRCB_H1V1:
@@ -1144,6 +1183,10 @@
 				pipe->chroma_sample = MDP4_CHROMA_H1V2;
 			else
 				pipe->chroma_sample = MDP4_CHROMA_RGB;
+		} else if (pipe->src_format == MDP_Y_CRCB_H1V2) {
+			pipe->element1 = C1_B_Cb;
+			pipe->element0 = C2_R_Cr;
+			pipe->chroma_sample = MDP4_CHROMA_H1V2;
 		} else if (pipe->src_format == MDP_Y_CRCB_H2V2) {
 			pipe->element1 = C1_B_Cb;
 			pipe->element0 = C2_R_Cr;
@@ -1304,6 +1347,7 @@
 	case MDP_Y_CR_CB_GH2V2:
 	case MDP_Y_CRCB_H2V2:
 	case MDP_Y_CRCB_H2V1:
+	case MDP_Y_CRCB_H1V2:
 	case MDP_Y_CRCB_H1V1:
 	case MDP_Y_CBCR_H1V1:
 	case MDP_YCRCB_H1V1:
@@ -1590,8 +1634,8 @@
 			data |= ctrl->mixer_cfg[num];
 			off = 0x10100;
 		}
-		pr_debug("%s: mixer=%d data=%x flush=%x\n", __func__,
-				mixer, data, ctrl->flush[mixer]);
+		pr_debug("%s: mixer=%d data=%x flush=%x pid=%d\n", __func__,
+				mixer, data, ctrl->flush[mixer], current->pid);
 	}
 
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
@@ -1608,7 +1652,7 @@
 }
 
 
-void mdp4_mixer_stage_up(struct mdp4_overlay_pipe *pipe)
+void mdp4_mixer_stage_up(struct mdp4_overlay_pipe *pipe, int commit)
 {
 	struct mdp4_overlay_pipe *pp;
 	int i, mixer;
@@ -1624,9 +1668,12 @@
 	}
 
 	ctrl->stage[mixer][pipe->mixer_stage] = pipe;	/* keep it */
+
+	if (commit)
+		mdp4_mixer_stage_commit(mixer);
 }
 
-void mdp4_mixer_stage_down(struct mdp4_overlay_pipe *pipe)
+void mdp4_mixer_stage_down(struct mdp4_overlay_pipe *pipe, int commit)
 {
 	struct mdp4_overlay_pipe *pp;
 	int i, mixer;
@@ -1639,7 +1686,8 @@
 			ctrl->stage[mixer][i] = NULL;  /* clear it */
 	}
 
-	mdp4_mixer_stage_commit(mixer);
+	if (commit || (mixer > 0 && !hdmi_prim_display))
+		mdp4_mixer_stage_commit(mixer);
 }
 /*
  * mixer0: rgb3: border color at register 0x15004, 0x15008
@@ -1700,7 +1748,7 @@
 
 	mdp4_overlay_reg_flush(bspipe, 1);
 	/* borderfill pipe as base layer */
-	mdp4_mixer_stage_up(pipe);
+	mdp4_mixer_stage_up(pipe, 0);
 }
 
 void mdp4_overlay_borderfill_stage_down(struct mdp4_overlay_pipe *pipe)
@@ -1754,13 +1802,13 @@
 
 	/* free borderfill pipe */
 	mdp4_overlay_reg_flush(pipe, 1);
-	mdp4_mixer_stage_down(pipe);
+	mdp4_mixer_stage_down(pipe, 0); /* commit will happen for bspipe up */
 	mdp4_overlay_pipe_free(pipe);
 
 	/* stage up base layer */
 	mdp4_overlay_reg_flush(bspipe, 1);
 	/* restore original base layer */
-	mdp4_mixer_stage_up(bspipe);
+	mdp4_mixer_stage_up(bspipe, 1);
 }
 
 
@@ -1845,6 +1893,32 @@
 	mdp4_overlay_reg_flush(pipe, 0);
 }
 
+void mdp4_mixer_blend_cfg(int mixer)
+{
+	int i, off;
+	unsigned char *overlay_base;
+	struct blend_cfg *blend;
+
+	if (mixer == MDP4_MIXER2)
+		overlay_base = MDP_BASE + MDP4_OVERLAYPROC2_BASE;
+	else if (mixer == MDP4_MIXER1)
+		overlay_base = MDP_BASE + MDP4_OVERLAYPROC1_BASE;
+	else
+		overlay_base = MDP_BASE + MDP4_OVERLAYPROC0_BASE;
+
+	blend = &ctrl->blend[mixer][MDP4_MIXER_STAGE_BASE];
+	blend++; /* stage0 */
+
+	for (i = MDP4_MIXER_STAGE0; i < MDP4_MIXER_STAGE_MAX; i++) {
+		off = 20 * i;
+		off = 0x20 * (i - MDP4_MIXER_STAGE0);
+		if (i == MDP4_MIXER_STAGE3)
+			off -= 4;
+		outpdw(overlay_base + off + 0x104, blend->op);
+		blend++;
+	}
+}
+
 /*
  * D(i+1) = Ks * S + Kd * D(i)
  */
@@ -1856,7 +1930,7 @@
 	int i, off, ptype, alpha_drop = 0;
 	int d_alpha, s_alpha;
 	unsigned char *overlay_base;
-	uint32 c0, c1, c2;
+	uint32 c0, c1, c2, base_premulti;
 
 
 	d_pipe = ctrl->stage[mixer][MDP4_MIXER_STAGE_BASE];
@@ -1866,6 +1940,8 @@
 	}
 
 	blend = &ctrl->blend[mixer][MDP4_MIXER_STAGE0];
+	base_premulti = ctrl->blend[mixer][MDP4_MIXER_STAGE_BASE].op &
+		MDP4_BLEND_FG_ALPHA_BG_CONST;
 	for (i = MDP4_MIXER_STAGE0; i < MDP4_MIXER_STAGE_MAX; i++) {
 		blend->solidfill = 0;
 		blend->op = (MDP4_BLEND_FG_ALPHA_FG_CONST |
@@ -1906,9 +1982,13 @@
 		} else if (s_alpha) {
 			if (!alpha_drop) {
 				blend->op = MDP4_BLEND_BG_ALPHA_FG_PIXEL;
-				if (!(s_pipe->flags & MDP_BLEND_FG_PREMULT))
+				if ((!(s_pipe->flags & MDP_BLEND_FG_PREMULT)) &&
+						((i != MDP4_MIXER_STAGE0) ||
+							(!base_premulti)))
 					blend->op |=
 						MDP4_BLEND_FG_ALPHA_FG_PIXEL;
+				else
+					blend->fg_alpha = 0xff;
 			} else
 				blend->op = MDP4_BLEND_BG_ALPHA_FG_CONST;
 
@@ -1918,9 +1998,14 @@
 			if (ptype == OVERLAY_TYPE_VIDEO) {
 				blend->op = (MDP4_BLEND_FG_ALPHA_BG_PIXEL |
 					MDP4_BLEND_FG_INV_ALPHA);
-				if (!(s_pipe->flags & MDP_BLEND_FG_PREMULT))
+				if ((!(s_pipe->flags & MDP_BLEND_FG_PREMULT)) &&
+						((i != MDP4_MIXER_STAGE0) ||
+							(!base_premulti)))
 					blend->op |=
 						MDP4_BLEND_BG_ALPHA_BG_PIXEL;
+				else
+					blend->fg_alpha = 0xff;
+
 				blend->co3_sel = 0; /* use bg alpha */
 			} else {
 				/* s_pipe is rgb without alpha */
@@ -1988,7 +2073,10 @@
 
 		outpdw(overlay_base + off + 0x108, blend->fg_alpha);
 		outpdw(overlay_base + off + 0x10c, blend->bg_alpha);
-		outpdw(overlay_base + off + 0x104, blend->op);
+
+		if (mdp_rev >= MDP_REV_42)
+			outpdw(overlay_base + off + 0x104, blend->op);
+
 		outpdw(overlay_base + (off << 5) + 0x1004, blend->co3_sel);
 		outpdw(overlay_base + off + 0x110, blend->transp_low0);/* low */
 		outpdw(overlay_base + off + 0x114, blend->transp_low1);/* low */
@@ -2110,79 +2198,6 @@
 
 }
 
-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,
 			struct mdp4_overlay_pipe **ppipe,
 			struct msm_fb_data_type *mfd)
@@ -2424,11 +2439,468 @@
 
 	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;
+	}
+
+	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 (mfd->panel_info.type == LVDS_PANEL &&
+		mfd->panel_info.lvds.channel_mode == LVDS_DUAL_CHANNEL_MODE)
+		pclk = pclk << 1;
+
+	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;
+
+	/*
+	 * There is one special case for the panels that have low
+	 * v_back_porch (<=4), mdp clk should be fast enough to buffer
+	 * 4 lines input during back porch time if scaling is
+	 * required(FIR).
+	 */
+	if ((mfd->panel_info.lcdc.v_back_porch <= 4) &&
+	    (pipe->src_h != pipe->dst_h) &&
+	    (mfd->panel_info.lcdc.v_back_porch)) {
+		u32 clk = 0;
+		clk = 4 * (pclk >> shift) / mfd->panel_info.lcdc.v_back_porch;
+		clk <<= shift;
+		pr_debug("%s: mdp clk rate %d based on low vbp %d\n",
+			 __func__, clk, mfd->panel_info.lcdc.v_back_porch);
+		rst = (rst > clk) ? rst : clk;
+	}
+
+	/*
+	 * 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__);
+	}
+
+	/*
+	 * Interlaced videos require the max mdp clk but cannot
+	 * be explained by mdp clk equation.
+	 */
+	if (pipe->flags & MDP_DEINTERLACE) {
+		rst = (rst > mdp_max_clk) ? rst : mdp_max_clk;
+		pr_info("%s deinterlace requires max mdp clk.\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) {
+			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_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);
+			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);
+			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,
@@ -2551,154 +3023,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 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) {
@@ -2728,20 +3056,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) {
@@ -2764,47 +3082,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;
@@ -2815,13 +3094,14 @@
 	struct mdp4_overlay_pipe *pipe;
 	int i, cnt = 0;
 
-	for (i = MDP4_MIXER_STAGE3; i >= MDP4_MIXER_STAGE_BASE; i--) {
+	/* free pipe besides base layer pipe */
+	for (i = MDP4_MIXER_STAGE3; i > MDP4_MIXER_STAGE_BASE; i--) {
 		pipe = ctrl->stage[mixer][i];
 		if (pipe == NULL)
 			continue;
 		pipe->flags &= ~MDP_OV_PLAY_NOWAIT;
 		mdp4_overlay_reg_flush(pipe, 1);
-		mdp4_mixer_stage_down(pipe);
+		mdp4_mixer_stage_down(pipe, 1);
 		mdp4_overlay_pipe_free(pipe);
 		cnt++;
 	}
@@ -2860,7 +3140,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);
@@ -2868,20 +3147,16 @@
 	}
 
 	mdp4_overlay_reg_flush(pipe, 1);
-	mdp4_mixer_stage_down(pipe);
+	mdp4_mixer_stage_down(pipe, 0);
 
 	if (pipe->mixer_num == MDP4_MIXER0) {
 		if (ctrl->panel_mode & MDP4_PANEL_MDDI) {
 			if (mfd->panel_power_on)
 				mdp4_mddi_overlay_restore();
 		}
-
-		mfd->use_ov0_blt &= ~(1 << (pipe->pipe_ndx-1));
 	} 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_stat.overlay_unset[pipe->mixer_num]++;
@@ -2920,13 +3195,13 @@
 
 	if (!hdmi_prim_display && info->node == 0) {
 		if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO)
-			mdp4_dsi_video_vsync_ctrl(0, cmd);
+			mdp4_dsi_video_vsync_ctrl(info, cmd);
 		else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD)
-			mdp4_dsi_cmd_vsync_ctrl(0, cmd);
+			mdp4_dsi_cmd_vsync_ctrl(info, cmd);
 		else if (ctrl->panel_mode & MDP4_PANEL_LCDC)
-			mdp4_lcdc_vsync_ctrl(0, cmd);
+			mdp4_lcdc_vsync_ctrl(info, cmd);
 	} else if (hdmi_prim_display || info->node == 1)
-		mdp4_dtv_vsync_ctrl(0, cmd);
+		mdp4_dtv_vsync_ctrl(info, cmd);
 
 	return 0;
 }
@@ -2998,9 +3273,8 @@
 
 	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);
+	mdp4_mixer_stage_up(pipe, 0);
 }
 
 int mdp4_overlay_play(struct fb_info *info, struct msmfb_overlay_data *req)
@@ -3032,11 +3306,11 @@
 
 	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)
-		mutex_lock(&mfd->dma->ov_mutex);
+	mutex_lock(&mfd->dma->ov_mutex);
 
 	img = &req->data;
 	get_img(img, info, pipe, 0, &start, &len, &srcp0_file,
@@ -3082,7 +3356,8 @@
 		}
 		pipe->srcp0_ystride = pipe->src_width;
 		if ((pipe->src_format == MDP_Y_CRCB_H1V1) ||
-			(pipe->src_format == MDP_Y_CBCR_H1V1)) {
+			(pipe->src_format == MDP_Y_CBCR_H1V1) ||
+			(pipe->src_format == MDP_Y_CRCB_H1V2)) {
 			if (pipe->src_width > YUV_444_MAX_WIDTH)
 				pipe->srcp1_ystride = pipe->src_width << 2;
 			else
@@ -3143,7 +3418,10 @@
 		}
 	}
 
-	if (ctrl->panel_mode & MDP4_PANEL_MDDI)
+	mdp4_overlay_mdp_perf_req(mfd, ctrl->plist);
+
+	if (pipe->mixer_num == MDP4_MIXER2 ||
+				ctrl->panel_mode & MDP4_PANEL_MDDI)
 		goto mddi;
 
 	if (pipe->mixer_num == MDP4_MIXER0) {
@@ -3163,35 +3441,31 @@
 			mdp4_dtv_pipe_queue(0, pipe);/* cndx = 0 */
 	}
 
+	mutex_unlock(&mfd->dma->ov_mutex);
 	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, 0);
 
-	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);
 	}
@@ -3199,8 +3473,10 @@
 	if (!(pipe->flags & MDP_OV_PLAY_NOWAIT))
 		mdp4_iommu_unmap(pipe);
 	mdp4_stat.overlay_play[pipe->mixer_num]++;
-	mutex_unlock(&mfd->dma->ov_mutex);
+
 end:
+	mutex_unlock(&mfd->dma->ov_mutex);
+
 #ifdef CONFIG_ANDROID_PMEM
 	if (srcp0_file)
 		put_pmem_file(srcp0_file);
@@ -3334,7 +3610,7 @@
 void mdp4_v4l2_overlay_clear(struct mdp4_overlay_pipe *pipe)
 {
 	mdp4_overlay_reg_flush(pipe, 1);
-	mdp4_mixer_stage_down(pipe);
+	mdp4_mixer_stage_down(pipe, 1);
 	mdp4_overlay_pipe_free(pipe);
 }
 
@@ -3397,7 +3673,8 @@
 	if (ctrl->panel_mode & MDP4_PANEL_LCDC)
 		mdp4_overlay_reg_flush(pipe, 1);
 
-	mdp4_mixer_stage_up(pipe);
+	mdp4_mixer_stage_up(pipe, 0); /* mixer stage commit commits this */
+	mdp4_mixer_stage_commit(pipe->mixer_num);
 
 #ifdef V4L2_VSYNC
 	/*
@@ -3424,4 +3701,22 @@
 	mutex_unlock(&mfd->dma->ov_mutex);
 	return err;
 }
-
+int mdp4_update_base_blend(struct msm_fb_data_type *mfd,
+			struct mdp_blend_cfg *mdp_blend_cfg)
+{
+	int ret = 0;
+	u32 mixer_num;
+	struct blend_cfg *blend;
+	mixer_num = mdp4_get_mixer_num(mfd->panel_info.type);
+	if (!ctrl)
+		return -EPERM;
+	blend = &ctrl->blend[mixer_num][MDP4_MIXER_STAGE_BASE];
+	if (mdp_blend_cfg->is_premultiplied) {
+		blend->bg_alpha = 0xFF;
+		blend->op = MDP4_BLEND_FG_ALPHA_BG_CONST;
+	} else {
+		blend->op = MDP4_BLEND_FG_ALPHA_FG_PIXEL;
+		blend->bg_alpha = 0;
+	}
+	return ret;
+}
diff --git a/drivers/video/msm/mdp4_overlay_atv.c b/drivers/video/msm/mdp4_overlay_atv.c
index 753ff23..e67b244 100644
--- a/drivers/video/msm/mdp4_overlay_atv.c
+++ b/drivers/video/msm/mdp4_overlay_atv.c
@@ -110,13 +110,14 @@
 
 	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_up(pipe, 0);
+	mdp4_mixer_stage_commit(pipe->mixer_num);
 
 	if (ret == 0)
 		mdp_pipe_ctrl(MDP_OVERLAY1_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
@@ -140,7 +141,7 @@
 
 	/* dis-engage rgb2 from mixer1 */
 	if (atv_pipe) {
-		mdp4_mixer_stage_down(atv_pipe);
+		mdp4_mixer_stage_down(atv_pipe, 1);
 		mdp4_iommu_unmap(atv_pipe);
 	}
 
@@ -183,10 +184,13 @@
 	} 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_overlay_reg_flush(pipe, 0);
+	mdp4_mixer_stage_up(pipe, 0);
+	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 +205,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 e1fa02e..3320d11 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_cmd.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
@@ -28,8 +28,8 @@
 
 #include "mdp.h"
 #include "msm_fb.h"
-#include "mdp4.h"
 #include "mipi_dsi.h"
+#include "mdp4.h"
 
 static int dsi_state;
 
@@ -39,15 +39,7 @@
 static int vsync_start_y_adjust = 4;
 
 #define MAX_CONTROLLER	1
-#define VSYNC_EXPIRE_TICK 4
-#define BACKLIGHT_MAX 4
-
-struct backlight {
-	int put;
-	int get;
-	int tot;
-	int blist[BACKLIGHT_MAX];
-};
+#define VSYNC_EXPIRE_TICK 8
 
 static struct vsycn_ctrl {
 	struct device *dev;
@@ -66,7 +58,7 @@
 	int blt_change;
 	int blt_free;
 	int blt_end;
-	int fake_vsync;
+	int uevent;
 	struct mutex update_lock;
 	struct completion ov_comp;
 	struct completion dmap_comp;
@@ -75,10 +67,10 @@
 	struct msm_fb_data_type *mfd;
 	struct mdp4_overlay_pipe *base_pipe;
 	struct vsync_update vlist[2];
-	struct backlight blight;
 	int vsync_enabled;
 	int clk_enabled;
 	int clk_control;
+	int new_update;
 	ktime_t vsync_time;
 	struct work_struct vsync_work;
 	struct work_struct clk_work;
@@ -108,68 +100,6 @@
 	spin_unlock_irqrestore(&mdp_spin_lock, flag);
 }
 
-static int mdp4_backlight_get_level(struct vsycn_ctrl *vctrl)
-{
-	int level = -1;
-
-	mutex_lock(&vctrl->update_lock);
-	if (vctrl->blight.tot) {
-		level = vctrl->blight.blist[vctrl->blight.get];
-		vctrl->blight.get++;
-		vctrl->blight.get %= BACKLIGHT_MAX;
-		vctrl->blight.tot--;
-		pr_debug("%s: tot=%d put=%d get=%d level=%d\n", __func__,
-		vctrl->blight.tot, vctrl->blight.put, vctrl->blight.get, level);
-	}
-	mutex_unlock(&vctrl->update_lock);
-	return level;
-}
-
-void mdp4_backlight_put_level(int cndx, int level)
-{
-	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];
-	mutex_lock(&vctrl->update_lock);
-	vctrl->blight.blist[vctrl->blight.put] = level;
-	vctrl->blight.put++;
-	vctrl->blight.put %= BACKLIGHT_MAX;
-	if (vctrl->blight.tot == BACKLIGHT_MAX) {
-		/* drop the oldest one */
-		vctrl->blight.get++;
-		vctrl->blight.get %= BACKLIGHT_MAX;
-	} else {
-		vctrl->blight.tot++;
-	}
-	mutex_unlock(&vctrl->update_lock);
-	pr_debug("%s: tot=%d put=%d get=%d level=%d\n", __func__,
-		vctrl->blight.tot, vctrl->blight.put, vctrl->blight.get, level);
-
-	if (mdp4_overlay_dsi_state_get() <= ST_DSI_SUSPEND)
-		return;
-}
-
-static int mdp4_backlight_commit_level(struct vsycn_ctrl *vctrl)
-{
-	int level;
-	int cnt = 0;
-
-	if (vctrl->blight.tot) { /* has new backlight */
-		if (mipi_dsi_ctrl_lock(0)) {
-			level = mdp4_backlight_get_level(vctrl);
-			mipi_dsi_cmd_backlight_tx(level);
-			cnt++;
-		}
-	}
-
-	return cnt;
-}
-
 static void mdp4_dsi_cmd_blt_ov_update(struct mdp4_overlay_pipe *pipe)
 {
 	uint32 off, addr;
@@ -327,6 +257,7 @@
 	struct vsycn_ctrl *vctrl;
 	struct vsync_update *vp;
 	struct mdp4_overlay_pipe *pipe;
+	struct mdp4_overlay_pipe *real_pipe;
 	unsigned long flags;
 	int need_dmap_wait = 0;
 	int need_ov_wait = 0;
@@ -355,9 +286,6 @@
 	}
 	mutex_unlock(&vctrl->update_lock);
 
-
-	mdp4_backlight_commit_level(vctrl);
-
 	/* free previous committed iommu back to pool */
 	mdp4_overlay_iommu_unmap_freelist(mixer);
 
@@ -366,7 +294,7 @@
 		/* Blt */
 		if (vctrl->blt_wait)
 			need_dmap_wait = 1;
-		else if (vctrl->ov_koff != vctrl->ov_done) {
+		if (vctrl->ov_koff != vctrl->ov_done) {
 			INIT_COMPLETION(vctrl->ov_comp);
 			need_ov_wait = 1;
 		}
@@ -410,7 +338,11 @@
 	for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) {
 		if (pipe->pipe_used) {
 			cnt++;
-			mdp4_overlay_vsync_commit(pipe);
+			real_pipe = mdp4_overlay_ndx2pipe(pipe->pipe_ndx);
+			if (real_pipe && real_pipe->pipe_used) {
+				/* pipe not unset */
+				mdp4_overlay_vsync_commit(pipe);
+			}
 			/* free previous iommu to freelist
 			* which will be freed at next
 			* pipe_commit
@@ -420,6 +352,9 @@
 		}
 	}
 
+	/* tx dcs command if had any */
+	mipi_dsi_cmdlist_commit(1);
+
 	mdp4_mixer_stage_commit(mixer);
 
 	pipe = vctrl->base_pipe;
@@ -445,26 +380,59 @@
 	return cnt;
 }
 
-void mdp4_dsi_cmd_vsync_ctrl(int cndx, int enable)
-{
-	struct vsycn_ctrl *vctrl;
+static void mdp4_overlay_update_dsi_cmd(struct msm_fb_data_type *mfd);
 
-	if (cndx >= MAX_CONTROLLER) {
-		pr_err("%s: out or range: cndx=%d\n", __func__, cndx);
-		return;
-	}
+void mdp4_dsi_cmd_vsync_ctrl(struct fb_info *info, int enable)
+{
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+	struct vsycn_ctrl *vctrl;
+	unsigned long flags;
+	int clk_set_on = 0;
+	int cndx = 0;
 
 	vctrl = &vsync_ctrl_db[cndx];
 
-	if (enable && vctrl->fake_vsync) {
-		vctrl->fake_vsync = 0;
-		schedule_work(&vctrl->vsync_work);
+	pr_debug("%s: clk_enabled=%d vsycn_enabeld=%d req=%d\n", __func__,
+		vctrl->clk_enabled, vctrl->vsync_enabled, enable);
+
+	mutex_lock(&vctrl->update_lock);
+
+	if (vctrl->vsync_enabled == enable) {
+		mutex_unlock(&vctrl->update_lock);
+		return;
 	}
 
-	if (vctrl->vsync_enabled == enable)
-		return;
-
 	vctrl->vsync_enabled = enable;
+
+	if (enable) {
+		if (vctrl->clk_enabled == 0) {
+			pr_debug("%s: SET_CLK_ON\n", __func__);
+			mipi_dsi_clk_cfg(1);
+			mdp_clk_ctrl(1);
+			vctrl->clk_enabled = 1;
+			clk_set_on = 1;
+		}
+		spin_lock_irqsave(&vctrl->spin_lock, flags);
+		vctrl->clk_control = 0;
+		vctrl->expire_tick = 0;
+		vctrl->uevent = 1;
+		vctrl->new_update = 1;
+		if (clk_set_on) {
+			vsync_irq_enable(INTR_PRIMARY_RDPTR,
+						MDP_PRIM_RDPTR_TERM);
+		}
+		spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+
+		mdp4_overlay_update_dsi_cmd(mfd);
+	} else {
+		spin_lock_irqsave(&vctrl->spin_lock, flags);
+		vctrl->clk_control = 1;
+		vctrl->uevent = 0;
+		if (vctrl->clk_enabled)
+			vctrl->expire_tick = VSYNC_EXPIRE_TICK;
+		spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+	}
+	mutex_unlock(&vctrl->update_lock);
 }
 
 void mdp4_dsi_cmd_wait4vsync(int cndx, long long *vtime)
@@ -545,13 +513,21 @@
 	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->uevent)
+		schedule_work(&vctrl->vsync_work);
+
 	if (vctrl->wait_vsync_cnt) {
 		complete(&vctrl->vsync_comp);
 		vctrl->wait_vsync_cnt = 0;
 	}
+
+	if (vctrl->expire_tick) {
+		vctrl->expire_tick--;
+		if (vctrl->expire_tick == 0)
+			schedule_work(&vctrl->clk_work);
+	}
 	spin_unlock(&vctrl->spin_lock);
 }
 
@@ -644,16 +620,19 @@
 {
 	struct vsycn_ctrl *vctrl =
 		container_of(work, typeof(*vctrl), clk_work);
+	unsigned long flags;
 
 	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;
-		}
+	if (vctrl->clk_control && vctrl->clk_enabled) {
+		pr_debug("%s: SET_CLK_OFF\n", __func__);
+		mdp_clk_ctrl(0);
+		mipi_dsi_clk_cfg(0);
+		spin_lock_irqsave(&vctrl->spin_lock, flags);
+		vsync_irq_disable(INTR_PRIMARY_RDPTR, MDP_PRIM_RDPTR_TERM);
+		vctrl->clk_enabled = 0;
+		vctrl->clk_control = 0;
+		spin_unlock_irqrestore(&vctrl->spin_lock, flags);
 	}
-
 	mutex_unlock(&vctrl->update_lock);
 }
 
@@ -687,9 +666,6 @@
 
 	vctrl->inited = 1;
 	vctrl->update_ndx = 0;
-	vctrl->blight.put = 0;
-	vctrl->blight.get = 0;
-	vctrl->blight.tot = 0;
 	mutex_init(&vctrl->update_lock);
 	init_completion(&vctrl->ov_comp);
 	init_completion(&vctrl->dmap_comp);
@@ -815,7 +791,7 @@
 	pipe->srcp0_addr = (uint32)src;
 }
 
-void mdp4_overlay_update_dsi_cmd(struct msm_fb_data_type *mfd)
+static void mdp4_overlay_update_dsi_cmd(struct msm_fb_data_type *mfd)
 {
 	int ptype;
 	struct mdp4_overlay_pipe *pipe;
@@ -829,30 +805,31 @@
 
 	vctrl = &vsync_ctrl_db[cndx];
 
-	/* MDP cmd block enable */
-	mdp_clk_ctrl(1);
+	if (vctrl->base_pipe == NULL) {
+		ptype = mdp4_overlay_format2type(mfd->fb_imgType);
+		if (ptype < 0)
+			printk(KERN_INFO "%s: format2type failed\n", __func__);
+		pipe = mdp4_overlay_pipe_alloc(ptype, MDP4_MIXER0);
+		if (pipe == NULL) {
+			printk(KERN_INFO "%s: pipe_alloc failed\n", __func__);
+			return;
+		}
+		pipe->pipe_used++;
+		pipe->mixer_stage  = MDP4_MIXER_STAGE_BASE;
+		pipe->mixer_num  = MDP4_MIXER0;
+		pipe->src_format = mfd->fb_imgType;
+		mdp4_overlay_panel_mode(pipe->mixer_num, MDP4_PANEL_DSI_CMD);
+		ret = mdp4_overlay_format2pipe(pipe);
+		if (ret < 0)
+			printk(KERN_INFO "%s: format2type failed\n", __func__);
 
-	ptype = mdp4_overlay_format2type(mfd->fb_imgType);
-	if (ptype < 0)
-		printk(KERN_INFO "%s: format2type failed\n", __func__);
-	pipe = mdp4_overlay_pipe_alloc(ptype, MDP4_MIXER0);
-	if (pipe == NULL) {
-		printk(KERN_INFO "%s: pipe_alloc failed\n", __func__);
-		return;
+		vctrl->base_pipe = pipe; /* keep it */
+		mdp4_init_writeback_buf(mfd, MDP4_MIXER0);
+		pipe->ov_blt_addr = 0;
+		pipe->dma_blt_addr = 0;
+	} else {
+		pipe = vctrl->base_pipe;
 	}
-	pipe->pipe_used++;
-	pipe->mixer_stage  = MDP4_MIXER_STAGE_BASE;
-	pipe->mixer_num  = MDP4_MIXER0;
-	pipe->src_format = mfd->fb_imgType;
-	mdp4_overlay_panel_mode(pipe->mixer_num, MDP4_PANEL_DSI_CMD);
-	ret = mdp4_overlay_format2pipe(pipe);
-	if (ret < 0)
-		printk(KERN_INFO "%s: format2type failed\n", __func__);
-
-	vctrl->base_pipe = pipe; /* keep it */
-	mdp4_init_writeback_buf(mfd, MDP4_MIXER0);
-	pipe->ov_blt_addr = 0;
-	pipe->dma_blt_addr = 0;
 
 	MDP_OUTP(MDP_BASE + 0x021c, 10); /* read pointer */
 
@@ -870,7 +847,7 @@
 
 	mdp4_overlay_reg_flush(pipe, 1);
 
-	mdp4_mixer_stage_up(pipe);
+	mdp4_mixer_stage_up(pipe, 0);
 
 	mdp4_overlayproc_cfg(pipe);
 
@@ -878,8 +855,7 @@
 
 	mdp4_overlay_dmap_cfg(mfd, 0);
 
-	/* MDP cmd block disable */
-	mdp_clk_ctrl(0);
+	wmb();
 }
 
 /* 3D side by side */
@@ -947,7 +923,7 @@
 
 	mdp4_overlay_reg_flush(pipe, 1);
 
-	mdp4_mixer_stage_up(pipe);
+	mdp4_mixer_stage_up(pipe, 0);
 
 	mdp4_overlayproc_cfg(pipe);
 
@@ -955,6 +931,7 @@
 
 	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);
 }
@@ -982,7 +959,7 @@
 	struct msm_fb_data_type *mfd;
 	struct vsycn_ctrl *vctrl;
 
-	pr_info("%s+:\n", __func__);
+	pr_debug("%s+:\n", __func__);
 
 	mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
 
@@ -991,15 +968,13 @@
 	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);
+	mdp4_overlay_update_dsi_cmd(mfd);
+	mdp_clk_ctrl(0);
 
 	mdp4_iommu_attach();
 
 	atomic_set(&vctrl->suspend, 0);
-	pr_info("%s-:\n", __func__);
+	pr_debug("%s-:\n", __func__);
 
 
 	return ret;
@@ -1013,7 +988,7 @@
 	struct vsycn_ctrl *vctrl;
 	struct mdp4_overlay_pipe *pipe;
 
-	pr_info("%s+:\n", __func__);
+	pr_debug("%s+:\n", __func__);
 
 	mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
 
@@ -1026,17 +1001,31 @@
 
 	atomic_set(&vctrl->suspend, 1);
 
-	mipi_dsi_cmd_backlight_tx(150);
-
-	mdp4_mixer_stage_down(pipe);
+	/* sanity check, free pipes besides base layer */
+	mdp4_overlay_unset_mixer(pipe->mixer_num);
+	mdp4_mixer_stage_down(pipe, 1);
 	mdp4_overlay_pipe_free(pipe);
 	vctrl->base_pipe = NULL;
 
-	vctrl->fake_vsync = 1;
+	if (vctrl->clk_enabled) {
+		/*
+		 * in case of suspend, vsycn_ctrl off is not
+		 * received from frame work which left clock on
+		 * then, clock need to be turned off here
+		 */
+		mdp_clk_ctrl(0);
+	}
+
+	vctrl->clk_enabled = 0;
+	vctrl->vsync_enabled = 0;
+	vctrl->clk_control = 0;
+	vctrl->expire_tick = 0;
+	vctrl->uevent = 0;
 
 	vsync_irq_disable(INTR_PRIMARY_RDPTR, MDP_PRIM_RDPTR_TERM);
 
-	pr_info("%s-:\n", __func__);
+
+	pr_debug("%s-:\n", __func__);
 
 	/*
 	 * footswitch off
@@ -1067,7 +1056,7 @@
 			mdp4_overlay_unset_mixer(pipe->mixer_num);
 			vctrl->base_pipe = NULL;
 		} else {
-			mdp4_mixer_stage_down(pipe);
+			mdp4_mixer_stage_down(pipe, 1);
 			mdp4_overlay_iommu_pipe_free(pipe->pipe_ndx, 1);
 		}
 	}
@@ -1078,6 +1067,7 @@
 	int cndx = 0;
 	struct vsycn_ctrl *vctrl;
 	struct mdp4_overlay_pipe *pipe;
+	unsigned long flags;
 	long long xx;
 
 	vctrl = &vsync_ctrl_db[cndx];
@@ -1085,31 +1075,44 @@
 	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__);
 		return;
 	}
 
+	mutex_lock(&vctrl->update_lock);
+	if (!vctrl->clk_enabled) {
+		pr_err("%s: mdp clocks disabled\n", __func__);
+		mutex_unlock(&vctrl->update_lock);
+		return;
+
+	}
+	mutex_unlock(&vctrl->update_lock);
+
+	spin_lock_irqsave(&vctrl->spin_lock, flags);
+	if (vctrl->expire_tick) {
+		/*
+		 * in the middle of shutting clocks down
+		 * delay to allow pan display to go through
+		 */
+		vctrl->expire_tick = VSYNC_EXPIRE_TICK;
+	}
+	spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+
 	if (pipe->mixer_stage == MDP4_MIXER_STAGE_BASE) {
 		mdp4_mipi_vsync_enable(mfd, pipe, 0);
 		mdp4_overlay_setup_pipe_addr(mfd, pipe);
 		mdp4_dsi_cmd_pipe_queue(0, pipe);
 	}
 
-	if (mfd->use_ov0_blt != mfd->ov0_blt_state) {
+	mdp4_overlay_mdp_perf_upd(mfd, 1);
 
-		if (mfd->use_ov0_blt)
-			mdp4_dsi_cmd_do_blt(mfd, 1);
-		else
-			mdp4_dsi_cmd_do_blt(mfd, 0);
-
-		mfd->ov0_blt_state = mfd->use_ov0_blt;
-	}
-
+	mutex_lock(&mfd->dma->ov_mutex);
 	mdp4_dsi_cmd_pipe_commit();
+	mutex_unlock(&mfd->dma->ov_mutex);
+
 	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 340faa2..fcdccca 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_video.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_video.c
@@ -122,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)
@@ -140,7 +137,7 @@
 		 __func__, undx, (int)pipe, pipe->pipe_ndx, pipe->pipe_num,
 		current->pid);
 
-	*pp = *pipe;	/* keep it */
+	*pp = *pipe;	/* clone it */
 	vp->update_cnt++;
 	mutex_unlock(&vctrl->update_lock);
 	mdp4_stat.overlay_play[pipe->mixer_num]++;
@@ -158,6 +155,7 @@
 	struct vsycn_ctrl *vctrl;
 	struct vsync_update *vp;
 	struct mdp4_overlay_pipe *pipe;
+	struct mdp4_overlay_pipe *real_pipe;
 	unsigned long flags;
 	int cnt = 0;
 
@@ -196,6 +194,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);
@@ -209,10 +209,15 @@
 	}
 
 	pipe = vp->plist;
+
 	for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) {
 		if (pipe->pipe_used) {
 			cnt++;
-			mdp4_overlay_vsync_commit(pipe);
+			real_pipe = mdp4_overlay_ndx2pipe(pipe->pipe_ndx);
+			if (real_pipe && real_pipe->pipe_used) {
+				/* pipe not unset */
+				mdp4_overlay_vsync_commit(pipe);
+			}
 			/* free previous iommu to freelist
 			* which will be freed at next
 			* pipe_commit
@@ -224,6 +229,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) {
@@ -248,14 +256,10 @@
 	return cnt;
 }
 
-void mdp4_dsi_video_vsync_ctrl(int cndx, int enable)
+void mdp4_dsi_video_vsync_ctrl(struct fb_info *info, int enable)
 {
 	struct vsycn_ctrl *vctrl;
-
-	if (cndx >= MAX_CONTROLLER) {
-		pr_err("%s: out or range: cndx=%d\n", __func__, cndx);
-		return;
-	}
+	int cndx = 0;
 
 	vctrl = &vsync_ctrl_db[cndx];
 
@@ -329,6 +333,27 @@
 	wait_for_completion(&vctrl->dmap_comp);
 }
 
+
+static void mdp4_dsi_video_wait4dmap_done(int cndx)
+{
+	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];
+
+	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;
@@ -492,20 +517,13 @@
 		pipe = vctrl->base_pipe;
 	}
 
-#ifdef CONTINUOUS_SPLASH
-	/* MDP cmd block enable */
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-
 	if (!(mfd->cont_splash_done)) {
 		mfd->cont_splash_done = 1;
-		mdp_pipe_ctrl(MDP_CMD_BLOCK,
-			      MDP_BLOCK_POWER_OFF, FALSE);
-		mdp4_overlay_dsi_video_wait4event(mfd, INTR_DMA_P_DONE);
-		/* disable timing generator */
+		mdp4_dsi_video_wait4dmap_done(0);
 		MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE, 0);
 		mipi_dsi_controller_cfg(0);
 	}
-#endif
+
 	pipe->src_height = fbi->var.yres;
 	pipe->src_width = fbi->var.xres;
 	pipe->src_h = fbi->var.yres;
@@ -525,6 +543,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 */
@@ -533,8 +553,9 @@
 	mdp4_overlayproc_cfg(pipe);
 
 	mdp4_overlay_reg_flush(pipe, 1);
-	mdp4_mixer_stage_up(pipe);
 
+	mdp4_mixer_stage_up(pipe, 0);
+	mdp4_mixer_stage_commit(pipe->mixer_num);
 
 	/*
 	 * DSI timing setting
@@ -623,6 +644,8 @@
 	struct msm_fb_data_type *mfd;
 	struct vsycn_ctrl *vctrl;
 	struct mdp4_overlay_pipe *pipe;
+	unsigned long flags;
+	int need_wait = 0;
 
 	mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
 	vctrl = &vsync_ctrl_db[cndx];
@@ -630,26 +653,34 @@
 
 	atomic_set(&vctrl->suspend, 1);
 
-	while (vctrl->wait_vsync_cnt)
-		msleep(20);	/* >= 17 ms */
+	msleep(20);	/* >= 17 ms */
+
+	if (pipe->ov_blt_addr) {
+		spin_lock_irqsave(&vctrl->spin_lock, flags);
+		if (vctrl->ov_koff != vctrl->ov_done)
+			need_wait = 1;
+		spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+		if (need_wait)
+			mdp4_dsi_video_wait4ov(0);
+	}
+
+	mdp_histogram_ctrl_all(FALSE);
 
 	MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE, 0);
 
 	dsi_video_enabled = 0;
 
-	mdp_histogram_ctrl_all(FALSE);
-
 	if (pipe) {
+		/* sanity check, free pipes besides base layer */
+		mdp4_overlay_unset_mixer(pipe->mixer_num);
 		if (mfd->ref_cnt == 0) {
 			/* adb stop */
 			if (pipe->pipe_type == OVERLAY_TYPE_BF)
 				mdp4_overlay_borderfill_stage_down(pipe);
-
-			mdp4_overlay_unset_mixer(pipe->mixer_num);
 			vctrl->base_pipe = NULL;
 		} else {
 			/* system suspending */
-			mdp4_mixer_stage_down(vctrl->base_pipe);
+			mdp4_mixer_stage_down(vctrl->base_pipe, 1);
 			mdp4_overlay_iommu_pipe_free(
 				vctrl->base_pipe->pipe_ndx, 1);
 		}
@@ -753,7 +784,9 @@
 
 	mdp4_overlay_reg_flush(pipe, 1);
 
-	mdp4_mixer_stage_up(pipe);
+	mdp4_mixer_stage_up(pipe, 0);
+
+	mdp4_mixer_stage_commit(pipe->mixer_num);
 
 	mb();
 }
@@ -806,13 +839,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
  */
@@ -997,21 +1023,17 @@
 		mdp4_dsi_video_pipe_queue(0, pipe);
 	}
 
-	if (mfd->use_ov0_blt != mfd->ov0_blt_state) {
+	mdp4_overlay_mdp_perf_upd(mfd, 1);
 
-		if (mfd->use_ov0_blt)
-			mdp4_dsi_video_do_blt(mfd, 1);
-		else
-			mdp4_dsi_video_do_blt(mfd, 0);
-
-		mfd->ov0_blt_state = mfd->use_ov0_blt;
-	}
-
+	mutex_lock(&mfd->dma->ov_mutex);
 	mdp4_dsi_video_pipe_commit();
+	mutex_unlock(&mfd->dma->ov_mutex);
 
 	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 d0d4f40..f3bd775 100644
--- a/drivers/video/msm/mdp4_overlay_dtv.c
+++ b/drivers/video/msm/mdp4_overlay_dtv.c
@@ -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)
@@ -158,13 +155,14 @@
 	pr_debug("%s: vndx=%d pipe_ndx=%d flags=%x pid=%d\n",
 		 __func__, undx, pipe->pipe_ndx, pipe->flags, current->pid);
 
-	*pp = *pipe;	/* keep it */
+	*pp = *pipe;	/* clone 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);
+static void mdp4_dtv_wait4dmae(int cndx);
 
 int mdp4_dtv_pipe_commit(void)
 {
@@ -174,6 +172,7 @@
 	struct vsycn_ctrl *vctrl;
 	struct vsync_update *vp;
 	struct mdp4_overlay_pipe *pipe;
+	struct mdp4_overlay_pipe *real_pipe;
 	unsigned long flags;
 	int cnt = 0;
 
@@ -199,7 +198,11 @@
 	for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) {
 		if (pipe->pipe_used) {
 			cnt++;
-			mdp4_overlay_vsync_commit(pipe);
+			real_pipe = mdp4_overlay_ndx2pipe(pipe->pipe_ndx);
+			if (real_pipe && real_pipe->pipe_used) {
+				/* pipe not unset */
+				mdp4_overlay_vsync_commit(pipe);
+			}
 			/* free previous iommu to freelist
 			* which will be freed at next
 			* pipe_commit
@@ -210,6 +213,9 @@
 	}
 	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) {
@@ -221,7 +227,7 @@
 		/* kickoff overlay1 engine */
 		mdp4_stat.kickoff_ov1++;
 		outpdw(MDP_BASE + 0x0008, 0);
-	} else if (vctrl->dmae_intr_cnt == 0) {
+	} else {
 		/* schedule second phase update  at dmap */
 		INIT_COMPLETION(vctrl->dmae_comp);
 		vsync_irq_enable(INTR_DMA_E_DONE, MDP_DMA_E_TERM);
@@ -232,14 +238,10 @@
 	return cnt;
 }
 
-void mdp4_dtv_vsync_ctrl(int cndx, int enable)
+void mdp4_dtv_vsync_ctrl(struct fb_info *info, int enable)
 {
 	struct vsycn_ctrl *vctrl;
-
-	if (cndx >= MAX_CONTROLLER) {
-		pr_err("%s: out or range: cndx=%d\n", __func__, cndx);
-		return;
-	}
+	int cndx = 0;
 
 	vctrl = &vsync_ctrl_db[cndx];
 
@@ -570,16 +572,17 @@
 	pipe = vctrl->base_pipe;
 	if (pipe != NULL) {
 		mdp4_dtv_stop(mfd);
+		/* sanity check, free pipes besides base layer */
+		mdp4_overlay_unset_mixer(pipe->mixer_num);
 		if (hdmi_prim_display && mfd->ref_cnt == 0) {
 			/* adb stop */
 			if (pipe->pipe_type == OVERLAY_TYPE_BF)
 				mdp4_overlay_borderfill_stage_down(pipe);
 
 			/* pipe == rgb2 */
-			mdp4_overlay_unset_mixer(pipe->mixer_num);
 			vctrl->base_pipe = NULL;
 		} else {
-			mdp4_mixer_stage_down(pipe);
+			mdp4_mixer_stage_down(pipe, 1);
 			mdp4_overlay_pipe_free(pipe);
 			vctrl->base_pipe = NULL;
 		}
@@ -647,8 +650,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,
@@ -701,12 +703,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__);
@@ -720,7 +726,8 @@
 	}
 
 	mdp4_overlay_reg_flush(pipe, 1);
-	mdp4_mixer_stage_up(pipe);
+	mdp4_mixer_stage_up(pipe, 0);
+	mdp4_mixer_stage_commit(pipe->mixer_num);
 
 	vctrl->base_pipe = pipe; /* keep it */
 }
@@ -786,8 +793,6 @@
 	vctrl->vsync_time = ktime_get();
 	schedule_work(&vctrl->vsync_work);
 
-	pr_debug("%s: cpu=%d\n", __func__, smp_processor_id());
-
 	spin_lock(&vctrl->spin_lock);
 	if (vctrl->wait_vsync_cnt) {
 		complete_all(&vctrl->vsync_comp);
@@ -813,6 +818,7 @@
 
 	vctrl = &vsync_ctrl_db[cndx];
 	pipe = vctrl->base_pipe;
+	pr_debug("%s: cpu=%d\n", __func__, smp_processor_id());
 
 	spin_lock(&vctrl->spin_lock);
 	if (vctrl->blt_change) {
@@ -831,13 +837,12 @@
 		vctrl->blt_change = 0;
 	}
 
-	vctrl->dmae_intr_cnt--;
-	if (vctrl->dmae_wait_cnt) {
-		complete_all(&vctrl->dmae_comp);
-		vctrl->dmae_wait_cnt = 0; /* reset */
-	} else  {
-		mdp4_overlay_dma_commit(MDP4_MIXER1);
-	}
+	if (mdp_rev <= MDP_REV_41)
+		mdp4_mixer_blend_cfg(MDP4_MIXER1);
+
+	complete_all(&vctrl->dmae_comp);
+	mdp4_overlay_dma_commit(MDP4_MIXER1);
+
 	vsync_irq_disable(INTR_DMA_E_DONE, MDP_DMA_E_TERM);
 	spin_unlock(&vctrl->spin_lock);
 }
@@ -893,7 +898,9 @@
 	temp_src_format = inpdw(rgb_base + 0x0050);
 	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_up(vctrl->base_pipe, 0);
+	mdp4_mixer_stage_commit(vctrl->base_pipe->mixer_num);
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 }
 
@@ -1000,5 +1007,8 @@
 		pipe->srcp0_addr = (uint32)mfd->ibuf.buf;
 		mdp4_dtv_pipe_queue(0, pipe);
 	}
+
+	mutex_lock(&mfd->dma->ov_mutex);
 	mdp4_dtv_pipe_commit();
+	mutex_unlock(&mfd->dma->ov_mutex);
 }
diff --git a/drivers/video/msm/mdp4_overlay_lcdc.c b/drivers/video/msm/mdp4_overlay_lcdc.c
index feba8b8..323a8fe 100644
--- a/drivers/video/msm/mdp4_overlay_lcdc.c
+++ b/drivers/video/msm/mdp4_overlay_lcdc.c
@@ -128,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)
@@ -145,7 +142,7 @@
 	pr_debug("%s: vndx=%d pipe_ndx=%d pid=%d\n", __func__,
 			undx, pipe->pipe_ndx, current->pid);
 
-	*pp = *pipe;	/* keep it */
+	*pp = *pipe;	/* clone it */
 	vp->update_cnt++;
 	mutex_unlock(&vctrl->update_lock);
 	mdp4_stat.overlay_play[pipe->mixer_num]++;
@@ -163,6 +160,7 @@
 	struct vsycn_ctrl *vctrl;
 	struct vsync_update *vp;
 	struct mdp4_overlay_pipe *pipe;
+	struct mdp4_overlay_pipe *real_pipe;
 	unsigned long flags;
 	int cnt = 0;
 
@@ -201,6 +199,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);
@@ -217,7 +217,11 @@
 	for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) {
 		if (pipe->pipe_used) {
 			cnt++;
-			mdp4_overlay_vsync_commit(pipe);
+			real_pipe = mdp4_overlay_ndx2pipe(pipe->pipe_ndx);
+			if (real_pipe && real_pipe->pipe_used) {
+				/* pipe not unset */
+				mdp4_overlay_vsync_commit(pipe);
+			}
 			/* free previous iommu to freelist
 			 * which will be freed at next
 			 * pipe_commit
@@ -229,6 +233,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) {
@@ -253,14 +260,10 @@
 	return cnt;
 }
 
-void mdp4_lcdc_vsync_ctrl(int cndx, int enable)
+void mdp4_lcdc_vsync_ctrl(struct fb_info *info, int enable)
 {
 	struct vsycn_ctrl *vctrl;
-
-	if (cndx >= MAX_CONTROLLER) {
-		pr_err("%s: out or range: cndx=%d\n", __func__, cndx);
-		return;
-	}
+	int cndx = 0;
 
 	vctrl = &vsync_ctrl_db[cndx];
 
@@ -513,6 +516,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);
@@ -521,7 +526,7 @@
 	mdp4_overlayproc_cfg(pipe);
 
 	mdp4_overlay_reg_flush(pipe, 1);
-	mdp4_mixer_stage_up(pipe);
+	mdp4_mixer_stage_up(pipe, 0);
 
 
 	/*
@@ -626,6 +631,8 @@
 	struct msm_fb_data_type *mfd;
 	struct vsycn_ctrl *vctrl;
 	struct mdp4_overlay_pipe *pipe;
+	unsigned long flags;
+	int need_wait = 0;
 
 	mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
 	vctrl = &vsync_ctrl_db[cndx];
@@ -633,26 +640,34 @@
 
 	atomic_set(&vctrl->suspend, 1);
 
-	while (vctrl->wait_vsync_cnt)
-		msleep(20);	/* >= 17 ms */
+	msleep(20);	/* >= 17 ms */
+
+	if (pipe->ov_blt_addr) {
+		spin_lock_irqsave(&vctrl->spin_lock, flags);
+		if (vctrl->ov_koff != vctrl->ov_done)
+			need_wait = 1;
+		spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+		if (need_wait)
+			mdp4_lcdc_wait4ov(0);
+	}
+
+	mdp_histogram_ctrl_all(FALSE);
 
 	MDP_OUTP(MDP_BASE + LCDC_BASE, 0);
 
 	lcdc_enabled = 0;
 
-	mdp_histogram_ctrl_all(FALSE);
-
 	if (pipe) {
+		/* sanity check, free pipes besides base layer */
+		mdp4_overlay_unset_mixer(pipe->mixer_num);
 		if (mfd->ref_cnt == 0) {
 			/* adb stop */
 			if (pipe->pipe_type == OVERLAY_TYPE_BF)
 				mdp4_overlay_borderfill_stage_down(pipe);
-
-			mdp4_overlay_unset_mixer(pipe->mixer_num);
 			vctrl->base_pipe = NULL;
 		} else {
 			/* system suspending */
-			mdp4_mixer_stage_down(vctrl->base_pipe);
+			mdp4_mixer_stage_down(vctrl->base_pipe, 1);
 			mdp4_overlay_iommu_pipe_free(
 				vctrl->base_pipe->pipe_ndx, 1);
 		}
@@ -714,12 +729,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
  */
@@ -777,6 +786,10 @@
 	}
 
 	complete_all(&vctrl->dmap_comp);
+
+	if (mdp_rev <= MDP_REV_41)
+		mdp4_mixer_blend_cfg(MDP4_MIXER0);
+
 	mdp4_overlay_dma_commit(cndx);
 	spin_unlock(&vctrl->spin_lock);
 }
@@ -900,20 +913,16 @@
 		mdp4_lcdc_pipe_queue(0, pipe);
 	}
 
-	if (mfd->use_ov0_blt != mfd->ov0_blt_state) {
+	mdp4_overlay_mdp_perf_upd(mfd, 1);
 
-		if (mfd->use_ov0_blt)
-			mdp4_lcdc_do_blt(mfd, 1);
-		else
-			mdp4_lcdc_do_blt(mfd, 0);
-
-		mfd->ov0_blt_state = mfd->use_ov0_blt;
-	}
-
+	mutex_lock(&mfd->dma->ov_mutex);
 	mdp4_lcdc_pipe_commit();
+	mutex_unlock(&mfd->dma->ov_mutex);
 
 	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..be4a89a 100644
--- a/drivers/video/msm/mdp4_overlay_mddi.c
+++ b/drivers/video/msm/mdp4_overlay_mddi.c
@@ -236,14 +236,14 @@
 
 	mdp4_overlay_rgb_setup(pipe);
 
-	mdp4_mixer_stage_up(pipe);
+	mdp4_mixer_stage_up(pipe, 1);
 
 	mdp4_overlayproc_cfg(pipe);
 
 	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..487e5d5 100644
--- a/drivers/video/msm/mdp4_overlay_writeback.c
+++ b/drivers/video/msm/mdp4_overlay_writeback.c
@@ -174,15 +174,17 @@
 	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
 		pipe->srcp0_addr = (uint32)(buf + buf_offset);
 
-	mdp4_mixer_stage_up(pipe);
+	mdp4_mixer_stage_up(pipe, 0);
 
 	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);
 
@@ -274,6 +276,9 @@
 
 	writeback_pipe->ov_blt_addr = (ulong) (node ? node->addr : NULL);
 
+	/* free previous iommu at freelist back to pool */
+	mdp4_overlay_iommu_unmap_freelist(writeback_pipe->mixer_num);
+
 	if (!writeback_pipe->ov_blt_addr) {
 		pr_err("%s: no writeback buffer 0x%x, %p\n", __func__,
 			(unsigned int)writeback_pipe->ov_blt_addr, node);
@@ -286,8 +291,13 @@
 
 	pr_debug("%s: pid=%d\n", __func__, current->pid);
 
+	mdp4_mixer_stage_commit(pipe->mixer_num);
+
 	mdp4_writeback_overlay_kickoff(mfd, pipe);
 
+	/* move current committed iommu to freelist */
+	mdp4_overlay_iommu_pipe_free(pipe->pipe_ndx, 0);
+
 	mutex_lock(&mfd->writeback_mutex);
 	list_add_tail(&node->active_entry, &mfd->writeback_busy_queue);
 	mutex_unlock(&mfd->writeback_mutex);
@@ -299,6 +309,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..359f37e 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -35,6 +35,148 @@
 
 struct mdp4_statistic mdp4_stat;
 
+struct mdp_csc_cfg_data csc_cfg_matrix[CSC_MAX_BLOCKS] = {
+	{
+	.block = MDP_BLOCK_VG_1,
+	.csc_data = {
+			(MDP_CSC_FLAG_YUV_OUT),
+			{
+				0x0254, 0x0000, 0x0331,
+				0x0254, 0xff37, 0xfe60,
+				0x0254, 0x0409, 0x0000,
+			},
+			{
+				0xfff0, 0xff80, 0xff80,
+			},
+			{
+				0, 0, 0,
+			},
+			{
+				0, 0xff, 0, 0xff, 0, 0xff,
+			},
+			{
+				0, 0xff, 0, 0xff, 0, 0xff,
+			},
+		},
+	},
+	{
+	.block = MDP_BLOCK_VG_2,
+	.csc_data = {
+			(MDP_CSC_FLAG_YUV_OUT),
+			{
+				0x0254, 0x0000, 0x0331,
+				0x0254, 0xff37, 0xfe60,
+				0x0254, 0x0409, 0x0000,
+			},
+			{
+				0xfff0, 0xff80, 0xff80,
+			},
+			{
+				0, 0, 0,
+			},
+			{
+				0, 0xff, 0, 0xff, 0, 0xff,
+			},
+			{
+				0, 0xff, 0, 0xff, 0, 0xff,
+			},
+		},
+	},
+	{
+	.block = MDP_BLOCK_DMA_P,
+	.csc_data = {
+			(0),
+			{
+				0x0200, 0x0000, 0x0000,
+				0x0000, 0x0200, 0x0000,
+				0x0000, 0x0000, 0x0200,
+			},
+			{
+				0x0, 0x0, 0x0,
+			},
+			{
+				0, 0, 0,
+			},
+			{
+				0, 0xff, 0, 0xff, 0, 0xff,
+			},
+			{
+				0, 0xff, 0, 0xff, 0, 0xff,
+			},
+		},
+	},
+	{
+	.block = MDP_BLOCK_OVERLAY_1,
+	.csc_data = {
+			(0),
+			{
+				0x0200, 0x0000, 0x0000,
+				0x0000, 0x0200, 0x0000,
+				0x0000, 0x0000, 0x0200,
+			},
+			{
+				0x0, 0x0, 0x0,
+			},
+			{
+				0, 0, 0,
+			},
+			{
+				0, 0xff, 0, 0xff, 0, 0xff,
+			},
+			{
+				0, 0xff, 0, 0xff, 0, 0xff,
+			},
+		},
+	},
+	{
+	.block = MDP_BLOCK_OVERLAY_2,
+	.csc_data = {
+			(0),
+			{
+				0x0200, 0x0000, 0x0000,
+				0x0000, 0x0200, 0x0000,
+				0x0000, 0x0000, 0x0200,
+			},
+			{
+				0x0, 0x0, 0x0,
+			},
+			{
+				0, 0, 0,
+			},
+			{
+				0, 0xff, 0, 0xff, 0, 0xff,
+			},
+			{
+				0, 0xff, 0, 0xff, 0, 0xff,
+			},
+		},
+	},
+	{
+	.block = MDP_BLOCK_DMA_S,
+	.csc_data = {
+			(0),
+			{
+				0x0200, 0x0000, 0x0000,
+				0x0000, 0x0200, 0x0000,
+				0x0000, 0x0000, 0x0200,
+			},
+			{
+				0x0, 0x0, 0x0,
+			},
+			{
+				0, 0, 0,
+			},
+			{
+				0, 0xff, 0, 0xff, 0, 0xff,
+			},
+			{
+				0, 0xff, 0, 0xff, 0, 0xff,
+			},
+		},
+	},
+};
+
+
 unsigned is_mdp4_hw_reset(void)
 {
 	unsigned hw_reset = 0;
@@ -245,11 +387,11 @@
 {
 	ulong bits;
 	uint32 clk_rate;
-
+	int i;
 	/* 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
 	/*
@@ -273,11 +415,8 @@
 	mdp4_vg_qseed_init(0);
 	mdp4_vg_qseed_init(1);
 
-	mdp4_vg_csc_setup(0);
-	mdp4_vg_csc_setup(1);
-	mdp4_mixer_csc_setup(1);
-	mdp4_mixer_csc_setup(2);
-	mdp4_dmap_csc_setup();
+	for (i = 0; i < CSC_MAX_BLOCKS; i++)
+		mdp4_csc_config(&csc_cfg_matrix[i]);
 
 	if (mdp_rev <= MDP_REV_41) {
 		mdp4_mixer_gc_lut_setup(0);
@@ -1258,422 +1397,46 @@
 	},
 };
 
-struct mdp_csc_cfg csc_matrix[3] = {
-	{
-		(MDP_CSC_FLAG_YUV_OUT),
-		{
-			0x0254, 0x0000, 0x0331,
-			0x0254, 0xff37, 0xfe60,
-			0x0254, 0x0409, 0x0000,
-		},
-		{
-			0xfff0, 0xff80, 0xff80,
-		},
-		{
-			0, 0, 0,
-		},
-		{
-			0, 0xff, 0, 0xff, 0, 0xff,
-		},
-		{
-			0, 0xff, 0, 0xff, 0, 0xff,
-		},
-	},
-	{
-		(MDP_CSC_FLAG_YUV_OUT),
-		{
-			0x0254, 0x0000, 0x0331,
-			0x0254, 0xff37, 0xfe60,
-			0x0254, 0x0409, 0x0000,
-		},
-		{
-			0xfff0, 0xff80, 0xff80,
-		},
-		{
-			0, 0, 0,
-		},
-		{
-			0, 0xff, 0, 0xff, 0, 0xff,
-		},
-		{
-			0, 0xff, 0, 0xff, 0, 0xff,
-		},
-	},
-	{
-		(0),
-		{
-			0x0200, 0x0000, 0x0000,
-			0x0000, 0x0200, 0x0000,
-			0x0000, 0x0000, 0x0200,
-		},
-		{
-			0x0, 0x0, 0x0,
-		},
-		{
-			0, 0, 0,
-		},
-		{
-			0, 0xff, 0, 0xff, 0, 0xff,
-		},
-		{
-			0, 0xff, 0, 0xff, 0, 0xff,
-		},
-	},
-};
 
-
-
-#define MDP4_CSC_MV_OFF 	0x4400
-#define MDP4_CSC_PRE_BV_OFF 	0x4500
-#define MDP4_CSC_POST_BV_OFF 	0x4580
-#define MDP4_CSC_PRE_LV_OFF 	0x4600
-#define MDP4_CSC_POST_LV_OFF 	0x4680
-
-void mdp4_vg_csc_mv_setup(int vp_num)
-{
-	uint32 *off;
-	int i, voff;
-
-	voff = MDP4_VIDEO_OFF * vp_num;
-	off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff +
-					MDP4_CSC_MV_OFF);
-
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	for (i = 0; i < 9; i++) {
-		outpdw(off, csc_matrix[vp_num].csc_mv[i]);
-		off++;
-	}
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-}
-
-void mdp4_vg_csc_pre_bv_setup(int vp_num)
-{
-	uint32 *off;
-	int i, voff;
-
-	voff = MDP4_VIDEO_OFF * vp_num;
-	off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff +
-					MDP4_CSC_PRE_BV_OFF);
-
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	for (i = 0; i < 3; i++) {
-		outpdw(off, csc_matrix[vp_num].csc_pre_bv[i]);
-		off++;
-	}
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-}
-
-void mdp4_vg_csc_post_bv_setup(int vp_num)
-{
-	uint32 *off;
-	int i, voff;
-
-	voff = MDP4_VIDEO_OFF * vp_num;
-	off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff +
-					MDP4_CSC_POST_BV_OFF);
-
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	for (i = 0; i < 3; i++) {
-		outpdw(off, csc_matrix[vp_num].csc_post_bv[i]);
-		off++;
-	}
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-}
-
-void mdp4_vg_csc_pre_lv_setup(int vp_num)
-{
-	uint32 *off;
-	int i, voff;
-
-	voff = MDP4_VIDEO_OFF * vp_num;
-	off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff +
-					MDP4_CSC_PRE_LV_OFF);
-
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	for (i = 0; i < 6; i++) {
-		outpdw(off, csc_matrix[vp_num].csc_pre_lv[i]);
-		off++;
-	}
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-}
-
-void mdp4_vg_csc_post_lv_setup(int vp_num)
-{
-	uint32 *off;
-	int i, voff;
-
-	voff = MDP4_VIDEO_OFF * vp_num;
-	off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff +
-					MDP4_CSC_POST_LV_OFF);
-
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	for (i = 0; i < 6; i++) {
-		outpdw(off, csc_matrix[vp_num].csc_post_lv[i]);
-		off++;
-	}
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-}
-
-void mdp4_vg_csc_convert_setup(int vp_num)
-{
-	struct mdp_csc_cfg_data cfg;
-
-	switch (vp_num) {
-	case 0:
-		cfg.block = MDP_BLOCK_VG_1;
-		break;
-	case 1:
-		cfg.block = MDP_BLOCK_VG_2;
-		break;
-	default:
-		pr_err("%s - invalid vp_num = %d", __func__, vp_num);
-		return;
-	}
-	cfg.csc_data = csc_matrix[vp_num];
-	mdp4_csc_enable(&cfg);
-}
-
-void mdp4_vg_csc_setup(int vp_num)
-{
-		/* yuv2rgb */
-		mdp4_vg_csc_mv_setup(vp_num);
-		mdp4_vg_csc_pre_bv_setup(vp_num);
-		mdp4_vg_csc_post_bv_setup(vp_num);
-		mdp4_vg_csc_pre_lv_setup(vp_num);
-		mdp4_vg_csc_post_lv_setup(vp_num);
-		mdp4_vg_csc_convert_setup(vp_num);
-}
 void mdp4_vg_csc_update(struct mdp_csc *p)
 {
 	struct mdp4_overlay_pipe *pipe;
-	int vp_num;
+	uint32_t block = 0;
+	int i = 0;
 
 	pipe = mdp4_overlay_ndx2pipe(p->id);
 	if (pipe == NULL) {
 		pr_err("%s: p->id = %d Error\n", __func__, p->id);
 		return;
 	}
-
-	vp_num = pipe->pipe_num - OVERLAY_PIPE_VG1;
-
-	if (vp_num == 0 || vp_num == 1) {
-		memcpy(csc_matrix[vp_num].csc_mv, p->csc_mv, sizeof(p->csc_mv));
-		memcpy(csc_matrix[vp_num].csc_pre_bv, p->csc_pre_bv,
-			sizeof(p->csc_pre_bv));
-		memcpy(csc_matrix[vp_num].csc_post_bv, p->csc_post_bv,
-			sizeof(p->csc_post_bv));
-		memcpy(csc_matrix[vp_num].csc_pre_lv, p->csc_pre_lv,
-			sizeof(p->csc_pre_lv));
-		memcpy(csc_matrix[vp_num].csc_post_lv, p->csc_post_lv,
-			sizeof(p->csc_post_lv));
-		mdp4_vg_csc_setup(vp_num);
-	}
-}
-static uint32 csc_rgb2yuv_matrix_tab[9] = {
-	0x0083, 0x0102, 0x0032,
-	0x1fb5, 0x1f6c, 0x00e1,
-	0x00e1, 0x1f45, 0x1fdc
-};
-
-static uint32 csc_rgb2yuv_pre_bv_tab[3] = {0, 0, 0};
-
-static uint32 csc_rgb2yuv_post_bv_tab[3] = {0x0010, 0x0080, 0x0080};
-
-static  uint32 csc_rgb2yuv_pre_lv_tab[6] = {
-	0x00, 0xff, 0x00,
-	0xff, 0x00, 0xff
-};
-
-static  uint32 csc_rgb2yuv_post_lv_tab[6] = {
-	0x0010, 0x00eb, 0x0010,
-	0x00f0, 0x0010, 0x00f0
-};
-
-void mdp4_mixer_csc_mv_setup(uint32 mixer)
-{
-	uint32 *off;
-	int i;
-
-	if (mixer == MDP4_MIXER1)
-		off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x2400);
+	if (pipe->pipe_num == OVERLAY_PIPE_VG1)
+		block = MDP_BLOCK_VG_1;
+	else if (pipe->pipe_num == OVERLAY_PIPE_VG2)
+		block = MDP_BLOCK_VG_2;
 	else
-		off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC2_BASE + 0x2400);
+		return;
 
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	for (i = 0; i < 9; i++) {
-		outpdw(off, csc_rgb2yuv_matrix_tab[i]);
-		off++;
+	for (i = 0; i < CSC_MAX_BLOCKS; i++) {
+		if (csc_cfg_matrix[i].block == block)
+			break;
 	}
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-}
+	if (i == CSC_MAX_BLOCKS)
+		return;
 
-void mdp4_mixer_csc_pre_bv_setup(uint32 mixer)
-{
-	uint32 *off;
-	int i;
+	memcpy(&csc_cfg_matrix[i].csc_data.csc_mv, p->csc_mv,
+			sizeof(p->csc_mv));
+	memcpy(&csc_cfg_matrix[i].csc_data.csc_pre_bv, p->csc_pre_bv,
+		sizeof(p->csc_pre_bv));
+	memcpy(&csc_cfg_matrix[i].csc_data.csc_post_bv, p->csc_post_bv,
+		sizeof(p->csc_post_bv));
+	memcpy(&csc_cfg_matrix[i].csc_data.csc_pre_lv, p->csc_pre_lv,
+		sizeof(p->csc_pre_lv));
+	memcpy(&csc_cfg_matrix[i].csc_data.csc_post_lv, p->csc_post_lv,
+		sizeof(p->csc_post_lv));
+	csc_cfg_matrix[i].csc_data.flags = MDP_CSC_FLAG_YUV_OUT;
 
-	if (mixer == MDP4_MIXER1)
-		off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x2500);
-	else
-		off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC2_BASE + 0x2500);
+	mdp4_csc_config(&csc_cfg_matrix[i]);
 
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	for (i = 0; i < 3; i++) {
-		outpdw(off, csc_rgb2yuv_pre_bv_tab[i]);
-		off++;
-	}
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-}
-
-void mdp4_mixer_csc_post_bv_setup(uint32 mixer)
-{
-	uint32 *off;
-	int i;
-
-	if (mixer == MDP4_MIXER1)
-		off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x2580);
-	else
-		off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC2_BASE + 0x2580);
-
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	for (i = 0; i < 3; i++) {
-		outpdw(off, csc_rgb2yuv_post_bv_tab[i]);
-		off++;
-	}
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-}
-
-void mdp4_mixer_csc_pre_lv_setup(uint32 mixer)
-{
-	uint32 *off;
-	int i;
-
-	if (mixer == MDP4_MIXER1)
-		off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x2600);
-	else
-		off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC2_BASE + 0x2600);
-
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	for (i = 0; i < 6; i++) {
-		outpdw(off, csc_rgb2yuv_pre_lv_tab[i]);
-		off++;
-	}
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-}
-
-void mdp4_mixer_csc_post_lv_setup(uint32 mixer)
-{
-	uint32 *off;
-	int i;
-
-	if (mixer == MDP4_MIXER1)
-		off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x2680);
-	else
-		off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC2_BASE + 0x2680);
-
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	for (i = 0; i < 6; i++) {
-		outpdw(off, csc_rgb2yuv_post_lv_tab[i]);
-		off++;
-	}
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-}
-
-void mdp4_mixer_csc_setup(uint32 mixer)
-{
-	if (mixer >= MDP4_MIXER1) {
-		/* rgb2yuv */
-		mdp4_mixer_csc_mv_setup(mixer);
-		mdp4_mixer_csc_pre_bv_setup(mixer);
-		mdp4_mixer_csc_post_bv_setup(mixer);
-		mdp4_mixer_csc_pre_lv_setup(mixer);
-		mdp4_mixer_csc_post_lv_setup(mixer);
-	}
-}
-
-#define DMA_P_BASE 0x90000
-void mdp4_dmap_csc_mv_setup(void)
-{
-	uint32 *off;
-	int i;
-
-	off = (uint32 *)(MDP_BASE + DMA_P_BASE + 0x3400);
-
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	for (i = 0; i < 9; i++) {
-		outpdw(off, csc_matrix[2].csc_mv[i]);
-		off++;
-	}
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-}
-
-void mdp4_dmap_csc_pre_bv_setup(void)
-{
-	uint32 *off;
-	int i;
-
-	off = (uint32 *)(MDP_BASE + DMA_P_BASE + 0x3500);
-
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	for (i = 0; i < 3; i++) {
-		outpdw(off, csc_matrix[2].csc_pre_bv[i]);
-		off++;
-	}
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-}
-
-void mdp4_dmap_csc_post_bv_setup(void)
-{
-	uint32 *off;
-	int i;
-
-	off = (uint32 *)(MDP_BASE + DMA_P_BASE + 0x3580);
-
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	for (i = 0; i < 3; i++) {
-		outpdw(off, csc_matrix[2].csc_post_bv[i]);
-		off++;
-	}
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-}
-
-void mdp4_dmap_csc_pre_lv_setup(void)
-{
-	uint32 *off;
-	int i;
-
-	off = (uint32 *)(MDP_BASE + DMA_P_BASE + 0x3600);
-
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	for (i = 0; i < 6; i++) {
-		outpdw(off, csc_matrix[2].csc_pre_lv[i]);
-		off++;
-	}
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-}
-
-void mdp4_dmap_csc_post_lv_setup(void)
-{
-	uint32 *off;
-	int i;
-
-	off = (uint32 *)(MDP_BASE + DMA_P_BASE + 0x3680);
-
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	for (i = 0; i < 6; i++) {
-		outpdw(off, csc_matrix[2].csc_post_lv[i]);
-		off++;
-	}
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-}
-
-void mdp4_dmap_csc_setup(void)
-{
-	mdp4_dmap_csc_mv_setup();
-	mdp4_dmap_csc_pre_bv_setup();
-	mdp4_dmap_csc_post_bv_setup();
-	mdp4_dmap_csc_pre_lv_setup();
-	mdp4_dmap_csc_post_lv_setup();
 }
 
 char gc_lut[] = {
@@ -3328,3 +3091,16 @@
 error:
 	return ret;
 }
+u32 mdp4_get_mixer_num(u32 panel_type)
+{
+	u32 mixer_num;
+	if ((panel_type == TV_PANEL) ||
+			(panel_type == DTV_PANEL))
+		mixer_num = MDP4_MIXER1;
+	else if (panel_type == WRITEBACK_PANEL) {
+		mixer_num = MDP4_MIXER2;
+	} else {
+		mixer_num = MDP4_MIXER0;
+	}
+	return mixer_num;
+}
diff --git a/drivers/video/msm/mdp_dma.c b/drivers/video/msm/mdp_dma.c
index a506648..4b76e72 100644
--- a/drivers/video/msm/mdp_dma.c
+++ b/drivers/video/msm/mdp_dma.c
@@ -514,18 +514,28 @@
 
 void mdp_dma_vsync_ctrl(int enable)
 {
+	unsigned long flag;
 	if (vsync_cntrl.vsync_irq_enabled == enable)
 		return;
 
+	spin_lock_irqsave(&mdp_spin_lock, flag);
+	if (!enable)
+		INIT_COMPLETION(vsync_cntrl.vsync_wait);
 	vsync_cntrl.vsync_irq_enabled = enable;
+	spin_unlock_irqrestore(&mdp_spin_lock, flag);
 
 	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);
+		spin_lock_irqsave(&mdp_spin_lock, flag);
+		outp32(MDP_INTR_CLEAR, MDP_PRIM_RDPTR);
+		mdp_intr_mask |= MDP_PRIM_RDPTR;
+		outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+		mdp_enable_irq(MDP_VSYNC_TERM);
+		spin_unlock_irqrestore(&mdp_spin_lock, flag);
 	} else {
-		mdp3_vsync_irq_disable(MDP_PRIM_RDPTR, MDP_VSYNC_TERM);
-		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+		wait_for_completion(&vsync_cntrl.vsync_wait);
+		mdp_disable_irq(MDP_VSYNC_TERM);
 	}
 }
 
diff --git a/drivers/video/msm/mdp_dma_dsi_video.c b/drivers/video/msm/mdp_dma_dsi_video.c
index d94896f..a1f2b65 100644
--- a/drivers/video/msm/mdp_dma_dsi_video.c
+++ b/drivers/video/msm/mdp_dma_dsi_video.c
@@ -249,17 +249,27 @@
 
 void mdp_dma_video_vsync_ctrl(int enable)
 {
+	unsigned long flag;
 	if (vsync_cntrl.vsync_irq_enabled == enable)
 		return;
 
+	spin_lock_irqsave(&mdp_spin_lock, flag);
+	if (!enable)
+		INIT_COMPLETION(vsync_cntrl.vsync_wait);
 	vsync_cntrl.vsync_irq_enabled = enable;
+	spin_unlock_irqrestore(&mdp_spin_lock, flag);
 
 	if (enable) {
 		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-		mdp3_vsync_irq_enable(LCDC_FRAME_START, MDP_VSYNC_TERM);
+		spin_lock_irqsave(&mdp_spin_lock, flag);
+		outp32(MDP_INTR_CLEAR, LCDC_FRAME_START);
+		mdp_intr_mask |= LCDC_FRAME_START;
+		outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+		mdp_enable_irq(MDP_VSYNC_TERM);
+		spin_unlock_irqrestore(&mdp_spin_lock, flag);
 	} else {
-		mdp3_vsync_irq_disable(LCDC_FRAME_START, MDP_VSYNC_TERM);
-		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+		wait_for_completion(&vsync_cntrl.vsync_wait);
+		mdp_disable_irq(MDP_VSYNC_TERM);
 	}
 }
 
diff --git a/drivers/video/msm/mdp_dma_lcdc.c b/drivers/video/msm/mdp_dma_lcdc.c
index e030c99..10d60ab 100644
--- a/drivers/video/msm/mdp_dma_lcdc.c
+++ b/drivers/video/msm/mdp_dma_lcdc.c
@@ -330,17 +330,27 @@
 
 void mdp_dma_lcdc_vsync_ctrl(int enable)
 {
+	unsigned long flag;
 	if (vsync_cntrl.vsync_irq_enabled == enable)
 		return;
 
+	spin_lock_irqsave(&mdp_spin_lock, flag);
+	if (!enable)
+		INIT_COMPLETION(vsync_cntrl.vsync_wait);
 	vsync_cntrl.vsync_irq_enabled = enable;
+	spin_unlock_irqrestore(&mdp_spin_lock, flag);
 
 	if (enable) {
 		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-		mdp3_vsync_irq_enable(LCDC_FRAME_START, MDP_VSYNC_TERM);
+		spin_lock_irqsave(&mdp_spin_lock, flag);
+		outp32(MDP_INTR_CLEAR, LCDC_FRAME_START);
+		mdp_intr_mask |= LCDC_FRAME_START;
+		outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+		mdp_enable_irq(MDP_VSYNC_TERM);
+		spin_unlock_irqrestore(&mdp_spin_lock, flag);
 	} else {
-		mdp3_vsync_irq_disable(LCDC_FRAME_START, MDP_VSYNC_TERM);
-		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+		wait_for_completion(&vsync_cntrl.vsync_wait);
+		mdp_disable_irq(MDP_VSYNC_TERM);
 	}
 }
 
diff --git a/drivers/video/msm/mdp_hw_init.c b/drivers/video/msm/mdp_hw_init.c
index ff3ad41..fc8435c 100644
--- a/drivers/video/msm/mdp_hw_init.c
+++ b/drivers/video/msm/mdp_hw_init.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-2009, 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
@@ -584,7 +584,7 @@
 
 #define   IRQ_EN_1__MDP_IRQ___M    0x00000800
 
-void mdp_hw_init(void)
+void mdp_hw_init(int splash)
 {
 	int i;
 
@@ -632,7 +632,8 @@
 	MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01e4, 0);
 
 #ifndef CONFIG_FB_MSM_MDP22
-	MDP_OUTP(MDP_BASE + 0xE0000, 0);
+	if (!splash)
+		MDP_OUTP(MDP_BASE + 0xE0000, 0);
 	MDP_OUTP(MDP_BASE + 0x100, 0xffffffff);
 	MDP_OUTP(MDP_BASE + 0x90070, 0);
 #endif
diff --git a/drivers/video/msm/mdss/Kconfig b/drivers/video/msm/mdss/Kconfig
index 30351a3..424455f 100644
--- a/drivers/video/msm/mdss/Kconfig
+++ b/drivers/video/msm/mdss/Kconfig
@@ -3,3 +3,11 @@
 	---help---
 	The MDSS Writeback Panel provides support for routing the output of
 	MDSS frame buffer driver and MDP processing to memory.
+
+config FB_MSM_MDSS_HDMI_PANEL
+	depends on FB_MSM_MDSS
+	bool "MDSS HDMI Tx Panel"
+	default n
+	---help---
+	The MDSS HDMI Panel provides support for transmitting TMDS signals of
+	MDSS frame buffer data to connected hdmi compliant TVs, monitors etc.
diff --git a/drivers/video/msm/mdss/Makefile b/drivers/video/msm/mdss/Makefile
index b6294f4..ddb6dd9 100644
--- a/drivers/video/msm/mdss/Makefile
+++ b/drivers/video/msm/mdss/Makefile
@@ -7,10 +7,14 @@
 mdss-mdp-objs += mdss_mdp_wb.o
 obj-$(CONFIG_FB_MSM_MDSS) += mdss-mdp.o
 obj-$(CONFIG_FB_MSM_MDSS) += mdss_fb.o
+obj-$(CONFIG_FB_MSM_MDSS) += mdss_io_util.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_HDMI_PANEL) += mdss_hdmi_tx.o
+obj-$(CONFIG_FB_MSM_MDSS_HDMI_PANEL) += mdss_hdmi_util.o
+obj-$(CONFIG_FB_MSM_MDSS_HDMI_PANEL) += mdss_hdmi_edid.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 6145d67..5613398 100644
--- a/drivers/video/msm/mdss/mdss.h
+++ b/drivers/video/msm/mdss/mdss.h
@@ -14,14 +14,15 @@
 #ifndef MDSS_H
 #define MDSS_H
 
+#include <linux/ion.h>
+#include <linux/msm_mdp.h>
 #include <linux/spinlock.h>
 #include <linux/types.h>
 #include <linux/workqueue.h>
 
-#define MDSS_REG_WRITE(addr, val) writel_relaxed(val, mdss_reg_base + addr)
-#define MDSS_REG_READ(addr) readl_relaxed(mdss_reg_base + addr)
+#define MDSS_REG_WRITE(addr, val) writel_relaxed(val, mdss_res->mdp_base + addr)
+#define MDSS_REG_READ(addr) readl_relaxed(mdss_res->mdp_base + addr)
 
-extern unsigned char *mdss_reg_base;
 extern spinlock_t dsi_clk_lock;
 
 enum mdss_mdp_clk_type {
@@ -34,7 +35,7 @@
 	MDSS_MAX_CLK
 };
 
-struct mdss_res_type {
+struct mdss_data_type {
 	u32 rev;
 	u32 mdp_rev;
 	struct clk *mdp_clk[MDSS_MAX_CLK];
@@ -42,6 +43,9 @@
 
 	struct workqueue_struct *clk_ctrl_wq;
 	struct delayed_work clk_ctrl_worker;
+	struct platform_device *pdev;
+	char __iomem *mdp_base;
+	char __iomem *vbif_base;
 
 	u32 irq;
 	u32 irq_mask;
@@ -50,26 +54,28 @@
 
 	u32 mdp_irq_mask;
 
-	u32 clk_ena;
 	u32 suspend;
 	u32 timeout;
 
-	u32 fs_ena;
-	u32 vsync_ena;
+	u8 clk_ena;
+	u8 fs_ena;
+	u8 vsync_ena;
+	u8 eintf_ena;
 
-	u32 intf;
-	u32 eintf_ena;
 	u32 prim_ptype;
 	u32 res_init;
-	u32 pdev_lcnt;
 	u32 bus_hdl;
 
 	u32 smp_mb_cnt;
 	u32 smp_mb_size;
 	u32 *pipe_type_map;
 	u32 *mixer_type_map;
+
+	struct ion_client *iclient;
+	int iommu_domain;
+	int iommu_attached;
 };
-extern struct mdss_res_type *mdss_res;
+extern struct mdss_data_type *mdss_res;
 
 enum mdss_hw_index {
 	MDSS_HW_MDP,
@@ -82,10 +88,36 @@
 
 struct mdss_hw {
 	u32 hw_ndx;
+	void *ptr;
 	irqreturn_t (*irq_handler)(int irq, void *ptr);
 };
 
 void mdss_enable_irq(struct mdss_hw *hw);
 void mdss_disable_irq(struct mdss_hw *hw);
 void mdss_disable_irq_nosync(struct mdss_hw *hw);
+
+static inline struct ion_client *mdss_get_ionclient(void)
+{
+	if (!mdss_res)
+		return NULL;
+	return mdss_res->iclient;
+}
+
+static inline int is_mdss_iommu_attached(void)
+{
+	if (!mdss_res)
+		return false;
+	return mdss_res->iommu_attached;
+}
+
+static inline int mdss_get_iommu_domain(void)
+{
+	if (!mdss_res)
+		return -ENODEV;
+
+	return mdss_res->iommu_domain;
+}
+
+int mdss_iommu_attach(void);
+int mdss_iommu_dettach(void);
 #endif /* MDSS_H */
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index d051828..e685785 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -17,19 +17,166 @@
 #include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/of_device.h>
+#include <linux/err.h>
+#include <linux/regulator/consumer.h>
 
 #include "mdss.h"
 #include "mdss_panel.h"
 #include "mdss_dsi.h"
 
-static struct mdss_panel_common_pdata *panel_pdata;
+static struct mdss_dsi_drv_pdata dsi_drv;
 
 static unsigned char *mdss_dsi_base;
 
+static int mdss_dsi_regulator_init(struct platform_device *pdev)
+{
+	int ret;
+	dsi_drv.vdd_vreg = devm_regulator_get(&pdev->dev, "vdd");
+	if (IS_ERR(dsi_drv.vdd_vreg)) {
+		pr_err("could not get 8941_l22, rc = %ld\n",
+				PTR_ERR(dsi_drv.vdd_vreg));
+		return -ENODEV;
+	}
+
+	ret = regulator_set_voltage(dsi_drv.vdd_vreg, 3000000, 3000000);
+	if (ret) {
+		pr_err("vdd_vreg->set_voltage failed, rc=%d\n", ret);
+		return -EINVAL;
+	}
+
+	dsi_drv.vdd_io_vreg = devm_regulator_get(&pdev->dev, "vdd_io");
+	if (IS_ERR(dsi_drv.vdd_io_vreg)) {
+		pr_err("could not get 8941_l12, rc = %ld\n",
+				PTR_ERR(dsi_drv.vdd_io_vreg));
+		return -ENODEV;
+	}
+
+	ret = regulator_set_voltage(dsi_drv.vdd_io_vreg, 1800000, 1800000);
+	if (ret) {
+		pr_err("vdd_io_vreg->set_voltage failed, rc=%d\n", ret);
+		return -EINVAL;
+	}
+
+	dsi_drv.dsi_vreg = devm_regulator_get(&pdev->dev, "vreg");
+	if (IS_ERR(dsi_drv.dsi_vreg)) {
+		pr_err("could not get 8941_l2, rc = %ld\n",
+				PTR_ERR(dsi_drv.dsi_vreg));
+		return -ENODEV;
+	}
+
+	ret = regulator_set_voltage(dsi_drv.dsi_vreg, 1200000, 1200000);
+	if (ret) {
+		pr_err("dsi_vreg->set_voltage failed, rc=%d\n", ret);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int mdss_dsi_panel_power_on(int enable)
+{
+	int ret;
+	pr_debug("%s: enable=%d\n", __func__, enable);
+
+	if (enable) {
+		ret = regulator_set_optimum_mode(dsi_drv.vdd_vreg, 100000);
+		if (ret < 0) {
+			pr_err("%s: vdd_vreg set regulator mode failed.\n",
+						       __func__);
+			return ret;
+		}
+
+		ret = regulator_set_optimum_mode(dsi_drv.vdd_io_vreg, 100000);
+		if (ret < 0) {
+			pr_err("%s: vdd_io_vreg set regulator mode failed.\n",
+						       __func__);
+			return ret;
+		}
+
+		ret = regulator_set_optimum_mode(dsi_drv.dsi_vreg, 100000);
+		if (ret < 0) {
+			pr_err("%s: dsi_vreg set regulator mode failed.\n",
+						       __func__);
+			return ret;
+		}
+
+		ret = regulator_enable(dsi_drv.vdd_vreg);
+		if (ret) {
+			pr_err("%s: Failed to enable regulator.\n", __func__);
+			return ret;
+		}
+
+		ret = regulator_enable(dsi_drv.vdd_io_vreg);
+		if (ret) {
+			pr_err("%s: Failed to enable regulator.\n", __func__);
+			return ret;
+		}
+
+		ret = regulator_enable(dsi_drv.dsi_vreg);
+		if (ret) {
+			pr_err("%s: Failed to enable regulator.\n", __func__);
+			return ret;
+		}
+
+		mdss_dsi_panel_reset(1);
+
+	} else {
+
+		mdss_dsi_panel_reset(0);
+
+		ret = regulator_disable(dsi_drv.vdd_vreg);
+		if (ret) {
+			pr_err("%s: Failed to disable regulator.\n", __func__);
+			return ret;
+		}
+
+		ret = regulator_disable(dsi_drv.vdd_io_vreg);
+		if (ret) {
+			pr_err("%s: Failed to disable regulator.\n", __func__);
+			return ret;
+		}
+
+		ret = regulator_disable(dsi_drv.dsi_vreg);
+		if (ret) {
+			pr_err("%s: Failed to disable regulator.\n", __func__);
+			return ret;
+		}
+
+		ret = regulator_set_optimum_mode(dsi_drv.vdd_vreg, 100);
+		if (ret < 0) {
+			pr_err("%s: vdd_vreg set regulator mode failed.\n",
+						       __func__);
+			return ret;
+		}
+
+		ret = regulator_set_optimum_mode(dsi_drv.vdd_io_vreg, 100);
+		if (ret < 0) {
+			pr_err("%s: vdd_io_vreg set regulator mode failed.\n",
+						       __func__);
+			return ret;
+		}
+		ret = regulator_set_optimum_mode(dsi_drv.dsi_vreg, 100);
+		if (ret < 0) {
+			pr_err("%s: dsi_vreg set regulator mode failed.\n",
+						       __func__);
+			return ret;
+		}
+	}
+	return 0;
+}
+
 static int mdss_dsi_off(struct mdss_panel_data *pdata)
 {
 	int ret = 0;
 	struct mdss_panel_info *pinfo;
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+
+	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+				panel_data);
+	if (!ctrl_pdata) {
+		pr_err("%s: Invalid input data\n", __func__);
+		return -EINVAL;
+	}
 
 	pinfo = &pdata->panel_info;
 
@@ -38,22 +185,28 @@
 
 	mdss_dsi_op_mode_config(DSI_CMD_MODE, pdata);
 
-	ret = panel_pdata->off(pdata);
+	ret = ctrl_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();
+	mdss_dsi_clk_disable(pdata);
 
 	/* disable dsi engine */
-	MIPI_OUTP(mdss_dsi_base + 0x0004, 0);
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004, 0);
 
 	spin_unlock_bh(&dsi_clk_lock);
 
 	mdss_dsi_unprepare_clocks();
 
+	ret = mdss_dsi_panel_power_on(0);
+	if (ret) {
+		pr_err("%s: Panel power off failed\n", __func__);
+		return ret;
+	}
+
 	pr_debug("%s-:\n", __func__);
 
 	return ret;
@@ -68,18 +221,29 @@
 	u32 hbp, hfp, vbp, vfp, hspw, vspw, width, height;
 	u32 ystride, bpp, data;
 	u32 dummy_xres, dummy_yres;
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+
+	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+				panel_data);
+	if (!ctrl_pdata) {
+		pr_err("%s: Invalid input data\n", __func__);
+		return -EINVAL;
+	}
 
 	pinfo = &pdata->panel_info;
 
-	cont_splash_clk_ctrl(0);
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x118, 1);
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x118, 0);
+
+	mdss_dsi_phy_sw_reset((ctrl_pdata->ctrl_base));
+	mdss_dsi_phy_enable((ctrl_pdata->ctrl_base), 1);
+	mdss_dsi_phy_init(pdata);
+
 	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();
+	mdss_dsi_clk_enable(pdata);
 	spin_unlock_bh(&dsi_clk_lock);
 
 	clk_rate = pdata->panel_info.clk_rate;
@@ -99,20 +263,20 @@
 		dummy_xres = pdata->panel_info.lcdc.xres_pad;
 		dummy_yres = pdata->panel_info.lcdc.yres_pad;
 
-		MIPI_OUTP(mdss_dsi_base + 0x24,
+		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x24,
 			((hspw + hbp + width + dummy_xres) << 16 |
 			(hspw + hbp)));
-		MIPI_OUTP(mdss_dsi_base + 0x28,
+		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x28,
 			((vspw + vbp + height + dummy_yres) << 16 |
 			(vspw + vbp)));
-		MIPI_OUTP(mdss_dsi_base + 0x2C,
+		MIPI_OUTP((ctrl_pdata->ctrl_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));
+		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x30, (hspw << 16));
+		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x34, 0);
+		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x38, (vspw << 16));
 
 	} else {		/* command mode */
 		if (mipi->dst_format == DSI_CMD_DST_FORMAT_RGB888)
@@ -128,13 +292,13 @@
 
 		/* 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);
+		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x60, data);
+		MIPI_OUTP((ctrl_pdata->ctrl_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);
+		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x64, data);
+		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x5C, data);
 	}
 
 	mdss_dsi_host_init(mipi, pdata);
@@ -142,13 +306,19 @@
 	if (mipi->force_clk_lane_hs) {
 		u32 tmp;
 
-		tmp = MIPI_INP(mdss_dsi_base + 0xac);
+		tmp = MIPI_INP((ctrl_pdata->ctrl_base) + 0xac);
 		tmp |= (1<<28);
-		MIPI_OUTP(mdss_dsi_base + 0xac, tmp);
+		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0xac, tmp);
 		wmb();
 	}
 
-	ret = panel_pdata->on(pdata);
+	ret = mdss_dsi_panel_power_on(1);
+	if (ret) {
+		pr_err("%s: Panel power on failed\n", __func__);
+		return ret;
+	}
+
+	ret = ctrl_pdata->on(pdata);
 	if (ret) {
 		pr_err("%s: unable to initialize the panel\n", __func__);
 		return ret;
@@ -160,16 +330,6 @@
 	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)
@@ -196,6 +356,15 @@
 			}
 		}
 
+		rc = mdss_dsi_regulator_init(pdev);
+		if (rc) {
+			dev_err(&pdev->dev,
+				"%s: failed to init regulator, rc=%d\n",
+							__func__, rc);
+			iounmap(mdss_dsi_base);
+			return rc;
+		}
+
 		if (mdss_dsi_clk_init(pdev)) {
 			iounmap(mdss_dsi_base);
 			return -EPERM;
@@ -232,29 +401,28 @@
 struct device dsi_dev;
 
 int dsi_panel_device_register(struct platform_device *pdev,
-			      struct mdss_panel_common_pdata *panel_data)
+			      struct mdss_panel_common_pdata *panel_data,
+			      char backlight_ctrl)
 {
 	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;
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
 
-	panel_pdata = panel_data;
+	h_period = ((panel_data->panel_info.lcdc.h_pulse_width)
+			+ (panel_data->panel_info.lcdc.h_back_porch)
+			+ (panel_data->panel_info.xres)
+			+ (panel_data->panel_info.lcdc.h_front_porch));
 
-	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_data->panel_info.lcdc.v_pulse_width)
+			+ (panel_data->panel_info.lcdc.v_back_porch)
+			+ (panel_data->panel_info.yres)
+			+ (panel_data->panel_info.lcdc.v_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_data->panel_info.mipi;
 
-	mipi  = &panel_pdata->panel_info.mipi;
-
-	panel_pdata->panel_info.type =
+	panel_data->panel_info.type =
 		((mipi->mode == DSI_VIDEO_MODE)
 			? MIPI_VIDEO_PANEL : MIPI_CMD_PANEL);
 
@@ -278,23 +446,23 @@
 	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 (panel_data->panel_info.type == MIPI_VIDEO_PANEL &&
+		!panel_data->panel_info.clk_rate) {
+		h_period += panel_data->panel_info.lcdc.xres_pad;
+		v_period += panel_data->panel_info.lcdc.yres_pad;
 
 		if (lanes > 0) {
-			panel_pdata->panel_info.clk_rate =
+			panel_data->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 =
+			panel_data->panel_info.clk_rate =
 				(h_period * v_period
 					 * (mipi->frame_rate) * bpp * 8);
 		}
 	}
-	pll_divider_config.clk_rate = panel_pdata->panel_info.clk_rate;
+	pll_divider_config.clk_rate = panel_data->panel_info.clk_rate;
 
 	rc = mdss_dsi_clk_div_config(bpp, lanes, &dsi_pclk_rate);
 	if (rc) {
@@ -306,30 +474,34 @@
 		dsi_pclk_rate = 35000000;
 	mipi->dsi_pclk_rate = dsi_pclk_rate;
 
-	/*
-	 * data chain
-	 */
-	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
-	if (!pdata)
+	ctrl_pdata = devm_kzalloc(&pdev->dev,
+		sizeof(struct mdss_dsi_ctrl_pdata), GFP_KERNEL);
+	if (!ctrl_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));
+	(ctrl_pdata->panel_data).on = mdss_dsi_on;
+	(ctrl_pdata->panel_data).off = mdss_dsi_off;
+	memcpy(&((ctrl_pdata->panel_data).panel_info),
+				&(panel_data->panel_info),
+				       sizeof(struct mdss_panel_info));
 
-	pdata->dsi_base = mdss_dsi_base;
-
+	mdss_dsi_irq_handler_config(ctrl_pdata);
+	(ctrl_pdata->panel_data).set_backlight = panel_data->bl_fnc;
+	(ctrl_pdata->ctrl_base) = mdss_dsi_base;
+	(ctrl_pdata->bl_ctrl) = backlight_ctrl;
 	/*
 	 * register in mdp driver
 	 */
-	rc = mdss_register_panel(pdata);
+	rc = mdss_register_panel(&(ctrl_pdata->panel_data));
 	if (rc) {
 		dev_err(&pdev->dev, "unable to register MIPI DSI panel\n");
-		devm_kfree(&pdev->dev, pdata);
+		devm_kfree(&pdev->dev, ctrl_pdata);
 		return rc;
 	}
 
+	ctrl_pdata->on = panel_data->on;
+	ctrl_pdata->off = panel_data->off;
+
 	pr_debug("%s: Panal data initialized\n", __func__);
 	return 0;
 }
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
index 57fce1a..e6fd910 100644
--- a/drivers/video/msm/mdss/mdss_dsi.h
+++ b/drivers/video/msm/mdss/mdss_dsi.h
@@ -19,7 +19,6 @@
 
 #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))
@@ -77,6 +76,13 @@
 	DSI_CMD_MODE_MDP,
 };
 
+enum dsi_panel_bl_ctrl {
+	BL_PWM,
+	BL_WLED,
+	BL_DCS_CMD,
+	UNKNOWN_CTRL,
+};
+
 #define DSI_NON_BURST_SYNCH_PULSE	0
 #define DSI_NON_BURST_SYNCH_EVENT	1
 #define DSI_BURST_MODE			2
@@ -242,10 +248,26 @@
 	struct mdss_panel_info panel_info;
 	int (*on) (struct mdss_panel_data *pdata);
 	int (*off) (struct mdss_panel_data *pdata);
+	void (*bl_fnc) (struct mdss_panel_data *pdata, u32 bl_level);
+};
+
+struct mdss_dsi_drv_pdata {
+	struct regulator *vdd_vreg;
+	struct regulator *vdd_io_vreg;
+	struct regulator *dsi_vreg;
+};
+
+struct mdss_dsi_ctrl_pdata {
+	int (*on) (struct mdss_panel_data *pdata);
+	int (*off) (struct mdss_panel_data *pdata);
+	struct mdss_panel_data panel_data;
+	unsigned char *ctrl_base;
+	char bl_ctrl;
 };
 
 int dsi_panel_device_register(struct platform_device *pdev,
-			      struct mdss_panel_common_pdata *panel_data);
+			      struct mdss_panel_common_pdata *panel_data,
+			      char bl_ctrl);
 
 char *mdss_dsi_buf_reserve_hdr(struct dsi_buf *dp, int hlen);
 char *mdss_dsi_buf_init(struct dsi_buf *dp);
@@ -258,7 +280,7 @@
 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);
+				unsigned char *ctrl_base);
 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);
@@ -273,13 +295,14 @@
 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_clk_enable(struct mdss_panel_data *pdata);
+void mdss_dsi_clk_disable(struct mdss_panel_data *pdata);
 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 mdss_dsi_irq_handler_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata);
 
 void mipi_set_tx_power_mode(int mode, struct mdss_panel_data *pdata);
 int mdss_dsi_clk_div_config(u8 bpp, u8 lanes,
@@ -288,7 +311,9 @@
 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);
+void mdss_dsi_panel_reset(int enable);
+void mdss_dsi_phy_enable(unsigned char *ctrl_base, int on);
+void mdss_dsi_phy_init(struct mdss_panel_data *pdata);
+void mdss_dsi_phy_sw_reset(unsigned char *ctrl_base);
 
 #endif /* MDSS_DSI_H */
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index 7bc0105..e47891e 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -21,6 +21,8 @@
 #include <linux/slab.h>
 #include <linux/iopoll.h>
 
+#include <mach/iommu_domains.h>
+
 #include "mdss.h"
 #include "mdss_dsi.h"
 
@@ -34,6 +36,7 @@
 
 struct mdss_hw mdss_dsi_hw = {
 	.hw_ndx = MDSS_HW_DSI0,
+	.ptr = NULL,
 	.irq_handler = mdss_dsi_isr,
 };
 
@@ -45,6 +48,11 @@
 	spin_lock_init(&dsi_clk_lock);
 }
 
+void mdss_dsi_irq_handler_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+{
+	mdss_dsi_hw.ptr = (void *)(ctrl_pdata);
+}
+
 void mdss_dsi_enable_irq(void)
 {
 	unsigned long flags;
@@ -55,6 +63,7 @@
 		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 */
@@ -653,6 +662,14 @@
 {
 	u32 dsi_ctrl, intr_ctrl;
 	u32 data;
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+
+	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+				panel_data);
+	if (!ctrl_pdata) {
+		pr_err("%s: Invalid input data\n", __func__);
+		return;
+	}
 
 	pinfo->rgb_swap = DSI_RGB_SWAP_RGB;
 
@@ -673,7 +690,7 @@
 		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);
+		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0010, data);
 
 		data = 0;
 		data |= ((pinfo->rgb_swap & 0x07) << 12);
@@ -683,7 +700,7 @@
 			data |= BIT(4);
 		if (pinfo->r_sel)
 			data |= BIT(0);
-		MIPI_OUTP((pdata->dsi_base) + 0x0020, data);
+		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0020, data);
 	} else if (pinfo->mode == DSI_CMD_MODE) {
 		data = 0;
 		data |= ((pinfo->interleave_max & 0x0f) << 20);
@@ -695,7 +712,7 @@
 		if (pinfo->r_sel)
 			data |= BIT(4);
 		data |= (pinfo->dst_format & 0x0f);	/* 4 bits */
-		MIPI_OUTP((pdata->dsi_base) + 0x003c, data);
+		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x003c, data);
 
 		/* DSI_COMMAND_MODE_MDP_DCS_CMD_CTRL */
 		data = pinfo->wr_mem_continue & 0x0ff;
@@ -703,7 +720,7 @@
 		data |= (pinfo->wr_mem_start & 0x0ff);
 		if (pinfo->insert_dcs_cmd)
 			data |= BIT(16);
-		MIPI_OUTP((pdata->dsi_base) + 0x0044, data);
+		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0044, data);
 	} else
 		pr_err("%s: Unknown DSI mode=%d\n", __func__, pinfo->mode);
 
@@ -726,7 +743,7 @@
 
 	/* from frame buffer, low power mode */
 	/* DSI_COMMAND_MODE_DMA_CTRL */
-	MIPI_OUTP((pdata->dsi_base) + 0x3C, 0x14000000);
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x3C, 0x14000000);
 
 	data = 0;
 	if (pinfo->te_sel)
@@ -734,59 +751,82 @@
 	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 */
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0084,
+				data); /* DSI_TRIG_CTRL */
 
 	/* DSI_LAN_SWAP_CTRL */
-	MIPI_OUTP((pdata->dsi_base) + 0x00b0, pinfo->dlane_swap);
+	MIPI_OUTP((ctrl_pdata->ctrl_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);
+	MIPI_OUTP((ctrl_pdata->ctrl_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 */
+	MIPI_OUTP((ctrl_pdata->ctrl_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);
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x010c, 0x13ff3fe0);
 
 	intr_ctrl |= DSI_INTR_ERROR_MASK;
-	MIPI_OUTP((pdata->dsi_base) + 0x0110, intr_ctrl); /* DSI_INTL_CTRL */
+	MIPI_OUTP((ctrl_pdata->ctrl_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 */
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x11c,
+					0x23f); /* DSI_CLK_CTRL */
 
 	dsi_ctrl |= BIT(0);	/* enable dsi */
-	MIPI_OUTP((pdata->dsi_base) + 0x0004, dsi_ctrl);
+	MIPI_OUTP((ctrl_pdata->ctrl_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);
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+	u32 data;
+
+	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+				panel_data);
+	if (!ctrl_pdata) {
+		pr_err("%s: Invalid input data\n", __func__);
+		return;
+	}
+
+	data = MIPI_INP((ctrl_pdata->ctrl_base) + 0x3c);
 
 	if (mode == 0)
 		data &= ~BIT(26);
 	else
 		data |= BIT(26);
 
-	MIPI_OUTP((pdata->dsi_base) + 0x3c, data);
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x3c, data);
 }
 
 void mdss_dsi_sw_reset(struct mdss_panel_data *pdata)
 {
-	MIPI_OUTP((pdata->dsi_base) + 0x118, 0x01);
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+
+	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+				panel_data);
+	if (!ctrl_pdata) {
+		pr_err("%s: Invalid input data\n", __func__);
+		return;
+	}
+
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x118, 0x01);
 	wmb();
-	MIPI_OUTP((pdata->dsi_base) + 0x118, 0x00);
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x118, 0x00);
 	wmb();
 }
 
@@ -798,38 +838,54 @@
 	u32 status;
 	u32 sleep_us = 1000;
 	u32 timeout_us = 16000;
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+
+	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+				panel_data);
+	if (!ctrl_pdata) {
+		pr_err("%s: Invalid input data\n", __func__);
+		return;
+	}
 
 	/* Check for CMD_MODE_DMA_BUSY */
-	if (readl_poll_timeout(((pdata->dsi_base) + 0x0008),
+	if (readl_poll_timeout(((ctrl_pdata->ctrl_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),
+	if (readl_poll_timeout(((ctrl_pdata->ctrl_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);
+	dsi_ctrl = MIPI_INP((ctrl_pdata->ctrl_base) + 0x0004);
 	if (enable)
 		dsi_ctrl |= 0x01;
 	else
 		dsi_ctrl &= ~0x01;
 
-	MIPI_OUTP((pdata->dsi_base) + 0x0004, dsi_ctrl);
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004, dsi_ctrl);
 	wmb();
 }
 
 void mdss_dsi_op_mode_config(int mode,
 			     struct mdss_panel_data *pdata)
 {
-
 	u32 dsi_ctrl, intr_ctrl;
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
 
-	dsi_ctrl = MIPI_INP((pdata->dsi_base) + 0x0004);
+	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+				panel_data);
+	if (!ctrl_pdata) {
+		pr_err("%s: Invalid input data\n", __func__);
+		return;
+	}
+
+
+	dsi_ctrl = MIPI_INP((ctrl_pdata->ctrl_base) + 0x0004);
 	dsi_ctrl &= ~0x07;
 	if (mode == DSI_VIDEO_MODE) {
 		dsi_ctrl |= 0x03;
@@ -842,8 +898,9 @@
 
 	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);
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0110,
+				intr_ctrl); /* DSI_INTL_CTRL */
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004, dsi_ctrl);
 	wmb();
 }
 
@@ -862,23 +919,31 @@
 {
 	u32 status;
 	int timeout_us = 10000;
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
 
-	MIPI_OUTP((pdata->dsi_base) + 0x098, 0x01);	/* trigger */
+	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+				panel_data);
+	if (!ctrl_pdata) {
+		pr_err("%s: Invalid input data\n", __func__);
+		return;
+	}
+
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x098, 0x01);	/* trigger */
 	wmb();
 
 	/* Check for CMD_MODE_DMA_BUSY */
-	if (readl_poll_timeout(((pdata->dsi_base) + 0x0008),
+	if (readl_poll_timeout(((ctrl_pdata->ctrl_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));
+	mdss_dsi_ack_err_status((ctrl_pdata->ctrl_base));
 
 	pr_debug("%s: BTA done, status = %d\n", __func__, status);
 }
 
 int mdss_dsi_cmd_reg_tx(u32 data,
-			struct mdss_panel_data *pdata)
+			unsigned char *ctrl_base)
 {
 	int i;
 	char *bp;
@@ -890,14 +955,14 @@
 
 	pr_debug("\n");
 
-	MIPI_OUTP((pdata->dsi_base) + 0x0084, 0x04);/* sw trigger */
-	MIPI_OUTP((pdata->dsi_base) + 0x0004, 0x135);
+	MIPI_OUTP(ctrl_base + 0x0084, 0x04);/* sw trigger */
+	MIPI_OUTP(ctrl_base + 0x0004, 0x135);
 
 	wmb();
 
-	MIPI_OUTP((pdata->dsi_base) + 0x03c, data);
+	MIPI_OUTP(ctrl_base + 0x03c, data);
 	wmb();
-	MIPI_OUTP((pdata->dsi_base) + 0x090, 0x01);	/* trigger */
+	MIPI_OUTP(ctrl_base + 0x090, 0x01);	/* trigger */
 	wmb();
 
 	udelay(300);
@@ -916,17 +981,25 @@
 	u32 dsi_ctrl, ctrl;
 	int i, video_mode;
 	unsigned long flag;
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+
+	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+				panel_data);
+	if (!ctrl_pdata) {
+		pr_err("%s: Invalid input data\n", __func__);
+		return -EINVAL;
+	}
 
 	/* 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);
+	dsi_ctrl = MIPI_INP((ctrl_pdata->ctrl_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);
+		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004, ctrl);
 	}
 
 	spin_lock_irqsave(&dsi_mdp_lock, flag);
@@ -951,8 +1024,8 @@
 	spin_unlock_irqrestore(&dsi_mdp_lock, flag);
 
 	if (video_mode)
-		MIPI_OUTP((pdata->dsi_base) + 0x0004, dsi_ctrl); /* restore */
-
+		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004,
+					dsi_ctrl); /* restore */
 	return cnt;
 }
 
@@ -983,6 +1056,14 @@
 	int cnt, len, diff, pkt_size;
 	unsigned long flag;
 	char cmd;
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+
+	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+				panel_data);
+	if (!ctrl_pdata) {
+		pr_err("%s: Invalid input data\n", __func__);
+		return -EINVAL;
+	}
 
 	if (pdata->panel_info.mipi.no_max_pkt_size)
 		rlen = ALIGN(rlen, 4); /* Only support rlen = 4*n */
@@ -1092,6 +1173,15 @@
 	int len;
 	int i;
 	char *bp;
+	unsigned long size, addr;
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+
+	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+				panel_data);
+	if (!ctrl_pdata) {
+		pr_err("%s: Invalid input data\n", __func__);
+		return -EINVAL;
+	}
 
 	bp = tp->data;
 
@@ -1101,26 +1191,43 @@
 
 	pr_debug("\n");
 
-	len = tp->len;
-	len += 3;
-	len &= ~0x03;	/* multipled by 4 */
+	len = ALIGN(tp->len, 4);
+	size = ALIGN(tp->len, SZ_4K);
 
-	tp->dmap = dma_map_single(&dsi_dev, tp->data, len, DMA_TO_DEVICE);
-	if (dma_mapping_error(&dsi_dev, tp->dmap))
+	tp->dmap = dma_map_single(&dsi_dev, tp->data, size, DMA_TO_DEVICE);
+	if (dma_mapping_error(&dsi_dev, tp->dmap)) {
 		pr_err("%s: dmap mapp failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	if (is_mdss_iommu_attached()) {
+		int ret = msm_iommu_map_contig_buffer(tp->dmap,
+					mdss_get_iommu_domain(), 0,
+					size, SZ_4K, 0, &(addr));
+		if (IS_ERR_VALUE(ret)) {
+			pr_err("unable to map dma memory to iommu(%d)\n", ret);
+			return -ENOMEM;
+		}
+	} else {
+		addr = tp->dmap;
+	}
 
 	INIT_COMPLETION(dsi_dma_comp);
 
-	MIPI_OUTP((pdata->dsi_base) + 0x048, tp->dmap);
-	MIPI_OUTP((pdata->dsi_base) + 0x04c, len);
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x048, addr);
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x04c, len);
 	wmb();
 
-	MIPI_OUTP((pdata->dsi_base) + 0x090, 0x01);	/* trigger */
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x090, 0x01);	/* trigger */
 	wmb();
 
 	wait_for_completion(&dsi_dma_comp);
 
-	dma_unmap_single(&dsi_dev, tp->dmap, len, DMA_TO_DEVICE);
+	if (is_mdss_iommu_attached())
+		msm_iommu_unmap_contig_buffer(addr, mdss_get_iommu_domain(),
+					      0, size);
+
+	dma_unmap_single(&dsi_dev, tp->dmap, size, DMA_TO_DEVICE);
 	tp->dmap = 0;
 	return tp->len;
 }
@@ -1130,6 +1237,14 @@
 {
 	u32 *lp, data;
 	int i, off, cnt;
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+
+	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+				panel_data);
+	if (!ctrl_pdata) {
+		pr_err("%s: Invalid input data\n", __func__);
+		return -EINVAL;
+	}
 
 	lp = (u32 *)rp->data;
 	cnt = rlen;
@@ -1144,7 +1259,7 @@
 
 
 	for (i = 0; i < cnt; i++) {
-		data = (u32)MIPI_INP((pdata->dsi_base) + off);
+		data = (u32)MIPI_INP((ctrl_pdata->ctrl_base) + off);
 		*lp++ = ntohl(data);	/* to network byte order */
 		off -= 4;
 		rp->len += sizeof(*lp);
@@ -1227,8 +1342,10 @@
 {
 	u32 isr;
 	unsigned char *dsi_base;
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata =
+			(struct mdss_dsi_ctrl_pdata *)ptr;
 
-	dsi_base = mdss_dsi_get_base_adr();
+	dsi_base = ctrl_pdata->ctrl_base;
 	if (!dsi_base)
 		pr_err("%s:%d DSI base adr no Initialized",
 				       __func__, __LINE__);
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
index bfb7fae..63ad5cc 100644
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -13,7 +13,12 @@
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/gpio.h>
+#include <linux/qpnp/pin.h>
+#include <linux/delay.h>
 #include <linux/slab.h>
+#include <linux/leds.h>
 
 #include "mdss_dsi.h"
 
@@ -28,6 +33,77 @@
 static int num_of_off_cmds;
 static char *on_cmds, *off_cmds;
 
+DEFINE_LED_TRIGGER(bl_led_trigger);
+
+static struct mdss_dsi_phy_ctrl phy_params;
+
+static int rst_gpio;
+static int disp_en;
+
+struct qpnp_pin_cfg param = {
+	.mode = QPNP_PIN_MODE_DIG_OUT,
+	.output_type = QPNP_PIN_OUT_BUF_OPEN_DRAIN_NMOS,
+	.invert = QPNP_PIN_INVERT_ENABLE,
+	.pull = QPNP_PIN_MPP_PULL_UP_30KOHM,
+	.vin_sel = QPNP_PIN_VIN3,
+	.out_strength = QPNP_PIN_OUT_STRENGTH_HIGH,
+	.select = QPNP_PIN_SEL_DTEST3,
+	.master_en = QPNP_PIN_MASTER_ENABLE,
+	.aout_ref = QPNP_PIN_AOUT_0V625,
+	.ain_route = QPNP_PIN_AIN_AMUX_CH7,
+	.cs_out = QPNP_PIN_CS_OUT_20MA,
+};
+
+void mdss_dsi_panel_reset(int enable)
+{
+	if (!disp_en)
+		pr_debug("%s:%d, reset line not configured\n",
+			   __func__, __LINE__);
+
+	if (!rst_gpio)
+		pr_debug("%s:%d, reset line not configured\n",
+			   __func__, __LINE__);
+
+	if (enable) {
+		gpio_set_value(disp_en, 1);
+		gpio_set_value(rst_gpio, 1);
+		usleep(10);
+		gpio_set_value(rst_gpio, 0);
+		usleep(200);
+		gpio_set_value(rst_gpio, 1);
+	} else {
+		gpio_set_value(rst_gpio, 0);
+		gpio_set_value(disp_en, 0);
+	}
+}
+
+static void mdss_dsi_panel_bl_ctrl(struct mdss_panel_data *pdata,
+							u32 bl_level)
+{
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+
+	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+				panel_data);
+	if (!ctrl_pdata) {
+		pr_err("%s: Invalid input data\n", __func__);
+		return;
+	}
+
+	if (ctrl_pdata->bl_ctrl) {
+		switch (ctrl_pdata->bl_ctrl) {
+		case BL_WLED:
+			led_trigger_event(bl_led_trigger, bl_level);
+			break;
+
+		default:
+			pr_err("%s: Unknown bl_ctrl configuration\n",
+				__func__);
+			break;
+		}
+	} else
+		pr_err("%s:%d, bl_ctrl not configured", __func__, __LINE__);
+}
+
 static int mdss_dsi_panel_on(struct mdss_panel_data *pdata)
 {
 	struct mipi_panel_info *mipi;
@@ -37,6 +113,8 @@
 	pr_debug("%s:%d, debug info (mode) : %d\n", __func__, __LINE__,
 		 mipi->mode);
 
+	mdss_dsi_panel_reset(1);
+
 	if (mipi->mode == DSI_VIDEO_MODE) {
 		mdss_dsi_cmds_tx(pdata, &dsi_panel_tx_buf, dsi_panel_on_cmds,
 			num_of_on_cmds);
@@ -64,17 +142,21 @@
 		return -EINVAL;
 	}
 
+	mdss_dsi_panel_reset(0);
+
 	return 0;
 }
 
 static int mdss_panel_parse_dt(struct platform_device *pdev,
-			    struct mdss_panel_common_pdata *panel_data)
+			       struct mdss_panel_common_pdata *panel_data,
+			       char *bl_ctrl)
 {
 	struct device_node *np = pdev->dev.of_node;
 	u32 res[6], tmp;
 	int rc, i, len;
 	int cmd_plen, data_offset;
 	const char *data;
+	static const char *bl_ctrl_type;
 
 	rc = of_property_read_u32_array(np, "qcom,mdss-pan-res", res, 2);
 	if (rc) {
@@ -85,6 +167,59 @@
 	panel_data->panel_info.xres = (!rc ? res[0] : 640);
 	panel_data->panel_info.yres = (!rc ? res[1] : 480);
 
+	rc = of_property_read_u32_array(np, "qcom,mdss-pan-active-res", res, 2);
+	if (rc == 0) {
+		panel_data->panel_info.lcdc.xres_pad =
+			panel_data->panel_info.xres - res[0];
+		panel_data->panel_info.lcdc.yres_pad =
+			panel_data->panel_info.yres - res[1];
+	}
+
+	disp_en = of_get_named_gpio(np, "qcom,enable-gpio", 0);
+	if (!gpio_is_valid(disp_en)) {
+		pr_err("%s:%d, Disp_en gpio not specified\n",
+						__func__, __LINE__);
+		return -ENODEV;
+	}
+
+	rc = gpio_request(disp_en, "disp_enable");
+	if (rc) {
+		pr_err("request reset gpio failed, rc=%d\n",
+			rc);
+		gpio_free(disp_en);
+		return -ENODEV;
+	}
+	rc = gpio_direction_output(disp_en, 1);
+	if (rc) {
+		pr_err("set_direction for disp_en gpio failed, rc=%d\n",
+			rc);
+		gpio_free(disp_en);
+		return -ENODEV;
+	}
+
+	rst_gpio = of_get_named_gpio(np, "qcom,rst-gpio", 0);
+	if (!gpio_is_valid(rst_gpio)) {
+		pr_err("%s:%d, reset gpio not specified\n",
+						__func__, __LINE__);
+	} else {
+	  rc = qpnp_pin_config(rst_gpio, &param);
+		if (rc) {
+			pr_err("request reset gpio failed, rc=%d\n",
+				rc);
+			gpio_free(disp_en);
+			return rc;
+		}
+
+		rc = gpio_request(rst_gpio, "disp_rst_n");
+		if (rc) {
+			pr_err("request reset gpio failed, rc=%d\n",
+				rc);
+			gpio_free(rst_gpio);
+			gpio_free(disp_en);
+			return -ENODEV;
+		}
+	}
+
 	rc = of_property_read_u32(np, "qcom,mdss-pan-bpp", &tmp);
 	if (rc) {
 		pr_err("%s:%d, panel bpp not specified\n",
@@ -106,6 +241,14 @@
 		"qcom,mdss-pan-underflow-clr", &tmp);
 	panel_data->panel_info.lcdc.underflow_clr = (!rc ? tmp : 0xff);
 
+	bl_ctrl_type = of_get_property(pdev->dev.of_node,
+				  "qcom,mdss-pan-bl-ctrl", NULL);
+	if (!strncmp(bl_ctrl_type, "bl_ctrl_wled", 12)) {
+		led_trigger_register_simple("bkl-trigger", &bl_led_trigger);
+		pr_debug("%s: SUCCESS-> WLED TRIGGER register\n", __func__);
+		*bl_ctrl = BL_WLED;
+	}
+
 	rc = of_property_read_u32_array(np,
 		"qcom,mdss-pan-bl-levels", res, 2);
 	panel_data->panel_info.bl_min = (!rc ? res[0] : 0);
@@ -184,6 +327,53 @@
 	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-phy-regulatorSettings", &len);
+	if ((!data) || (len != 8)) {
+		pr_err("%s:%d, Unable to read Phy regulator settings",
+		       __func__, __LINE__);
+		goto error;
+	}
+	for (i = 0; i < len; i++)
+		phy_params.regulator[i] = data[i];
+
+	data = of_get_property(np, "qcom,panel-phy-timingSettings", &len);
+	if ((!data) || (len != 12)) {
+		pr_err("%s:%d, Unable to read Phy timing settings",
+		       __func__, __LINE__);
+		goto error;
+	}
+	for (i = 0; i < len; i++)
+		phy_params.timing[i] = data[i];
+
+	data = of_get_property(np, "qcom,panel-phy-strengthCtrl", &len);
+	if ((!data) || (len != 2)) {
+		pr_err("%s:%d, Unable to read Phy Strength ctrl settings",
+		       __func__, __LINE__);
+		goto error;
+	}
+	phy_params.strength[0] = data[0];
+	phy_params.strength[1] = data[1];
+
+	data = of_get_property(np, "qcom,panel-phy-bistCtrl", &len);
+	if ((!data) || (len != 6)) {
+		pr_err("%s:%d, Unable to read Phy Bist Ctrl settings",
+		       __func__, __LINE__);
+		goto error;
+	}
+	for (i = 0; i < len; i++)
+		phy_params.bistCtrl[i] = data[i];
+
+	data = of_get_property(np, "qcom,panel-phy-laneConfig", &len);
+	if ((!data) || (len != 45)) {
+		pr_err("%s:%d, Unable to read Phy lane configure settings",
+		       __func__, __LINE__);
+		goto error;
+	}
+	for (i = 0; i < len; i++)
+		phy_params.laneCfg[i] = data[i];
+
+	panel_data->panel_info.mipi.dsi_phy_db = &phy_params;
+
 	data = of_get_property(np, "qcom,panel-on-cmds", &len);
 	if (!data) {
 		pr_err("%s:%d, Unable to read ON cmds", __func__, __LINE__);
@@ -288,6 +478,10 @@
 	kfree(dsi_panel_off_cmds);
 	kfree(on_cmds);
 	kfree(off_cmds);
+	if (rst_gpio)
+		gpio_free(rst_gpio);
+	if (disp_en)
+		gpio_free(disp_en);
 
 	return -EINVAL;
 }
@@ -295,8 +489,9 @@
 static int __devinit mdss_dsi_panel_probe(struct platform_device *pdev)
 {
 	int rc = 0;
-	struct mdss_panel_common_pdata *vendor_pdata = NULL;
+	static struct mdss_panel_common_pdata vendor_pdata;
 	static const char *panel_name;
+	char bl_ctrl = UNKNOWN_CTRL;
 
 	if (pdev->dev.parent == NULL) {
 		pr_err("%s: parent device missing\n", __func__);
@@ -314,21 +509,15 @@
 	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;
+	rc = mdss_panel_parse_dt(pdev, &vendor_pdata, &bl_ctrl);
+	if (rc)
 		return rc;
-	}
-	vendor_pdata->on = mdss_dsi_panel_on;
-	vendor_pdata->off = mdss_dsi_panel_off;
 
-	rc = dsi_panel_device_register(pdev, vendor_pdata);
+	vendor_pdata.on = mdss_dsi_panel_on;
+	vendor_pdata.off = mdss_dsi_panel_off;
+	vendor_pdata.bl_fnc = mdss_dsi_panel_bl_ctrl;
+
+	rc = dsi_panel_device_register(pdev, &vendor_pdata, bl_ctrl);
 	if (rc)
 		return rc;
 
@@ -350,8 +539,8 @@
 
 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);
+	mdss_dsi_buf_alloc(&dsi_panel_tx_buf, ALIGN(DSI_BUF_SIZE, SZ_4K));
+	mdss_dsi_buf_alloc(&dsi_panel_rx_buf, ALIGN(DSI_BUF_SIZE, SZ_4K));
 
 	return platform_driver_register(&this_driver);
 }
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index ee086ad..5432df0 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -144,9 +144,9 @@
 	return ret;
 }
 
-static DEVICE_ATTR(mdss_fb_type, S_IRUGO, mdss_fb_get_type, NULL);
+static DEVICE_ATTR(msm_fb_type, S_IRUGO, mdss_fb_get_type, NULL);
 static struct attribute *mdss_fb_attrs[] = {
-	&dev_attr_mdss_fb_type.attr,
+	&dev_attr_msm_fb_type.attr,
 	NULL,
 };
 
@@ -186,7 +186,7 @@
 	/*
 	 * alloc framebuffer info + par data
 	 */
-	fbi = framebuffer_alloc(sizeof(struct msm_fb_data_type), &pdev->dev);
+	fbi = framebuffer_alloc(sizeof(struct msm_fb_data_type), NULL);
 	if (fbi == NULL) {
 		pr_err("can't allocate framebuffer info data!\n");
 		return -ENOMEM;
@@ -204,9 +204,6 @@
 	mfd->panel_info.frame_count = 0;
 	mfd->bl_level = 0;
 	mfd->fb_imgType = MDP_RGBA_8888;
-	mfd->iclient = msm_ion_client_create(-1, pdev->name);
-	if (IS_ERR(mfd->iclient))
-		mfd->iclient = NULL;
 
 	mfd->pdev = pdev;
 
@@ -220,6 +217,14 @@
 	if (rc)
 		return rc;
 
+	/*
+	 * todo: Currently mfd keeps a full copy of panel data rather than
+	 *       pointer to it.
+	 *       Following line shares the fbi with panel drivers for their
+	 *       sysfs or any external communications with the panel driver.
+	 */
+	pdata->panel_info.fbi = fbi;
+
 	rc = pm_runtime_set_active(mfd->fbi->dev);
 	if (rc < 0)
 		pr_err("pm_runtime: fail to set active.\n");
@@ -276,9 +281,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 +299,6 @@
 	return 0;
 }
 
-#if defined(CONFIG_PM)
 static int mdss_fb_resume_sub(struct msm_fb_data_type *mfd)
 {
 	int ret = 0;
@@ -303,6 +306,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 +321,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 +402,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,
@@ -445,7 +431,7 @@
 			return;
 		}
 		mfd->bl_level = bkl_lvl;
-		pdata->set_backlight(mfd->bl_level);
+		pdata->set_backlight(pdata, mfd->bl_level);
 		bl_level_old = mfd->bl_level;
 		mutex_unlock(&mfd->lock);
 	}
@@ -460,7 +446,7 @@
 		if ((pdata) && (pdata->set_backlight)) {
 			mutex_lock(&mfd->lock);
 			mfd->bl_level = unset_bl_level;
-			pdata->set_backlight(mfd->bl_level);
+			pdata->set_backlight(pdata, mfd->bl_level);
 			bl_level_old = unset_bl_level;
 			mutex_unlock(&mfd->lock);
 			bl_updated = 1;
@@ -611,11 +597,35 @@
 	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 = mdss_get_ionclient();
+
+		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);
+
+			if (is_mdss_iommu_attached()) {
+				ion_map_iommu(iclient, mfd->ihdl,
+					      mdss_get_iommu_domain(),
+					      0, SZ_4K, 0, &mfd->iova,
+					      (unsigned long *) &size,
+					      0, 0);
+			}
+		} 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",
@@ -792,6 +802,20 @@
 	mfd->var_yres = var->yres;
 	mfd->var_pixclock = var->pixclock;
 
+	if (panel_info->type == MIPI_VIDEO_PANEL) {
+		var->reserved[4] = panel_info->mipi.frame_rate;
+	} else {
+		var->reserved[4] = panel_info->clk_rate /
+			((panel_info->lcdc.h_back_porch +
+			  panel_info->lcdc.h_front_porch +
+			  panel_info->lcdc.h_pulse_width +
+			  panel_info->xres) *
+			 (panel_info->lcdc.v_back_porch +
+			  panel_info->lcdc.v_front_porch +
+			  panel_info->lcdc.v_pulse_width +
+			  panel_info->yres));
+	}
+
 	/* id field for fb app  */
 
 	id = (int *)&mfd->panel;
@@ -813,15 +837,6 @@
 
 	mfd->op_enable = true;
 
-	/* cursor memory allocation */
-	if (mfd->cursor_update) {
-		mfd->cursor_buf = dma_alloc_coherent(NULL, MDSS_MDP_CURSOR_SIZE,
-					(dma_addr_t *) &mfd->cursor_buf_phys,
-					GFP_KERNEL);
-		if (!mfd->cursor_buf)
-			mfd->cursor_update = 0;
-	}
-
 	if (mfd->lut_update) {
 		ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
 		if (ret)
@@ -832,11 +847,6 @@
 		if (mfd->lut_update)
 			fb_dealloc_cmap(&fbi->cmap);
 
-		if (mfd->cursor_buf)
-			dma_free_coherent(NULL, MDSS_MDP_CURSOR_SIZE,
-					  mfd->cursor_buf,
-					  (dma_addr_t) mfd->cursor_buf_phys);
-
 		mfd->op_enable = false;
 		return -EPERM;
 	}
@@ -1107,7 +1117,7 @@
 	if (ret)
 		return ret;
 
-	return mfd->cursor_update(info, &cursor);
+	return mfd->cursor_update(mfd, &cursor);
 }
 
 static int mdss_fb_set_lut(struct fb_info *info, void __user *p)
@@ -1123,7 +1133,7 @@
 	if (ret)
 		return ret;
 
-	mfd->lut_update(info, &cmap);
+	mfd->lut_update(mfd, &cmap);
 	return 0;
 }
 
@@ -1225,6 +1235,7 @@
 int mdss_fb_get_phys_info(unsigned long *start, unsigned long *len, int fb_num)
 {
 	struct fb_info *info;
+	struct msm_fb_data_type *mfd;
 
 	if (fb_num > MAX_FBI_LIST)
 		return -EINVAL;
@@ -1233,8 +1244,16 @@
 	if (!info)
 		return -ENOENT;
 
-	*start = info->fix.smem_start;
+	mfd = (struct msm_fb_data_type *)info->par;
+	if (!mfd)
+		return -ENODEV;
+
+	if (mfd->iova)
+		*start = mfd->iova;
+	else
+		*start = info->fix.smem_start;
 	*len = info->fix.smem_len;
+
 	return 0;
 }
 EXPORT_SYMBOL(mdss_fb_get_phys_info);
diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
index ac6c213..342ebb8 100644
--- a/drivers/video/msm/mdss/mdss_fb.h
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -69,14 +69,17 @@
 	int (*kickoff_fnc) (struct mdss_mdp_ctl *ctl);
 	int (*ioctl_handler) (struct msm_fb_data_type *mfd, u32 cmd, void *arg);
 	void (*dma_fnc) (struct msm_fb_data_type *mfd);
-	int (*cursor_update) (struct fb_info *info,
+	int (*cursor_update) (struct msm_fb_data_type *mfd,
 			      struct fb_cursor *cursor);
-	int (*lut_update) (struct fb_info *info,
-			   struct fb_cmap *cmap);
-	int (*do_histogram) (struct fb_info *info,
+	int (*lut_update) (struct msm_fb_data_type *mfd, struct fb_cmap *cmap);
+	int (*do_histogram) (struct msm_fb_data_type *mfd,
 			     struct mdp_histogram *hist);
+
+	struct ion_handle *ihdl;
+	unsigned long iova;
 	void *cursor_buf;
-	void *cursor_buf_phys;
+	unsigned long cursor_buf_phys;
+	unsigned long cursor_buf_iova;
 
 	u32 bl_level;
 	struct mutex lock;
@@ -88,13 +91,15 @@
 	u32 var_pixclock;
 
 	u32 mdp_fb_page_protection;
-	struct ion_client *iclient;
 
 	struct mdss_mdp_ctl *ctl;
 	struct mdss_mdp_wb *wb;
+	struct list_head overlay_list;
 };
 
 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_hdmi_edid.c b/drivers/video/msm/mdss/mdss_hdmi_edid.c
new file mode 100644
index 0000000..f720a2f
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_hdmi_edid.c
@@ -0,0 +1,1420 @@
+/* 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
+ * 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/io.h>
+#include <linux/types.h>
+#include <mach/board.h>
+#include "mdss_hdmi_edid.h"
+
+#define DBC_START_OFFSET 4
+#define HDMI_VSDB_3D_DATA_OFFSET(vsd) \
+	(!((vsd)[8] & BIT(7)) ? 9 : (!((vsd)[8] & BIT(6)) ? 11 : 13))
+
+struct hdmi_edid_sink_data {
+	u32 disp_mode_list[HDMI_VFRMT_MAX];
+	u32 disp_3d_mode_list[HDMI_VFRMT_MAX];
+	u32 disp_multi_3d_mode_list[16];
+	u32 disp_multi_3d_mode_list_cnt;
+	u32 num_of_elements;
+	u32 preferred_video_format;
+};
+
+struct hdmi_edid_ctrl {
+	u8 pt_scan_info;
+	u8 it_scan_info;
+	u8 ce_scan_info;
+	u16 physical_address;
+	u32 video_resolution; /* selected by user */
+	u32 sink_mode; /* HDMI or DVI */
+	u8 speaker_allocation_block;
+	u8 audio_data_block_cnt;
+	u16 audio_latency;
+	u16 video_latency;
+	u32 present_3d;
+
+	struct hdmi_edid_sink_data sink_data;
+	struct hdmi_edid_init_data init_data;
+};
+
+/* The Logic ID for HDMI TX Core. Currently only support 1 HDMI TX Core. */
+struct hdmi_edid_video_mode_property_type {
+	u32	video_code;
+	u32	active_h;
+	u32	active_v;
+	u32	interlaced;
+	u32	total_h;
+	u32	total_blank_h;
+	u32	total_v;
+	u32	total_blank_v;
+	/* Must divide by 1000 to get the frequency */
+	u32	freq_h;
+	/* Must divide by 1000 to get the frequency */
+	u32	freq_v;
+	/* Must divide by 1000 to get the frequency */
+	u32	pixel_freq;
+	/* Must divide by 1000 to get the frequency */
+	u32	refresh_rate;
+	u32	aspect_ratio_4_3;
+};
+
+/* LUT is sorted from lowest Active H to highest Active H - ease searching */
+static struct hdmi_edid_video_mode_property_type
+	hdmi_edid_disp_mode_lut[] = {
+
+	/* All 640 H Active */
+	{HDMI_VFRMT_640x480p60_4_3, 640, 480, false, 800, 160, 525, 45,
+	 31465, 59940, 25175, 59940, true},
+	{HDMI_VFRMT_640x480p60_4_3, 640, 480, false, 800, 160, 525, 45,
+	 31500, 60000, 25200, 60000, true},
+
+	/* All 720 H Active */
+	{HDMI_VFRMT_720x576p50_4_3,  720, 576, false, 864, 144, 625, 49,
+	 31250, 50000, 27000, 50000, true},
+	{HDMI_VFRMT_720x480p60_4_3,  720, 480, false, 858, 138, 525, 45,
+	 31465, 59940, 27000, 59940, true},
+	{HDMI_VFRMT_720x480p60_4_3,  720, 480, false, 858, 138, 525, 45,
+	 31500, 60000, 27030, 60000, true},
+	{HDMI_VFRMT_720x576p100_4_3, 720, 576, false, 864, 144, 625, 49,
+	 62500, 100000, 54000, 100000, true},
+	{HDMI_VFRMT_720x480p120_4_3, 720, 480, false, 858, 138, 525, 45,
+	 62937, 119880, 54000, 119880, true},
+	{HDMI_VFRMT_720x480p120_4_3, 720, 480, false, 858, 138, 525, 45,
+	 63000, 120000, 54054, 120000, true},
+	{HDMI_VFRMT_720x576p200_4_3, 720, 576, false, 864, 144, 625, 49,
+	 125000, 200000, 108000, 200000, true},
+	{HDMI_VFRMT_720x480p240_4_3, 720, 480, false, 858, 138, 525, 45,
+	 125874, 239760, 108000, 239000, true},
+	{HDMI_VFRMT_720x480p240_4_3, 720, 480, false, 858, 138, 525, 45,
+	 126000, 240000, 108108, 240000, true},
+
+	/* All 1280 H Active */
+	{HDMI_VFRMT_1280x720p50_16_9,  1280, 720, false, 1980, 700, 750, 30,
+	 37500, 50000, 74250, 50000, false},
+	{HDMI_VFRMT_1280x720p60_16_9,  1280, 720, false, 1650, 370, 750, 30,
+	 44955, 59940, 74176, 59940, false},
+	{HDMI_VFRMT_1280x720p60_16_9,  1280, 720, false, 1650, 370, 750, 30,
+	 45000, 60000, 74250, 60000, false},
+	{HDMI_VFRMT_1280x720p100_16_9, 1280, 720, false, 1980, 700, 750, 30,
+	 75000, 100000, 148500, 100000, false},
+	{HDMI_VFRMT_1280x720p120_16_9, 1280, 720, false, 1650, 370, 750, 30,
+	 89909, 119880, 148352, 119880, false},
+	{HDMI_VFRMT_1280x720p120_16_9, 1280, 720, false, 1650, 370, 750, 30,
+	 90000, 120000, 148500, 120000, false},
+
+	/* All 1440 H Active */
+	{HDMI_VFRMT_1440x576i50_4_3, 1440, 576, true,  1728, 288, 625, 24,
+	 15625, 50000, 27000, 50000, true},
+	{HDMI_VFRMT_720x288p50_4_3,  1440, 288, false, 1728, 288, 312, 24,
+	 15625, 50080, 27000, 50000, true},
+	{HDMI_VFRMT_720x288p50_4_3,  1440, 288, false, 1728, 288, 313, 25,
+	 15625, 49920, 27000, 50000, true},
+	{HDMI_VFRMT_720x288p50_4_3,  1440, 288, false, 1728, 288, 314, 26,
+	 15625, 49761, 27000, 50000, true},
+	{HDMI_VFRMT_1440x576p50_4_3, 1440, 576, false, 1728, 288, 625, 49,
+	 31250, 50000, 54000, 50000, true},
+	{HDMI_VFRMT_1440x480i60_4_3, 1440, 480, true,  1716, 276, 525, 22,
+	 15734, 59940, 27000, 59940, true},
+	{HDMI_VFRMT_1440x240p60_4_3, 1440, 240, false, 1716, 276, 262, 22,
+	 15734, 60054, 27000, 59940, true},
+	{HDMI_VFRMT_1440x240p60_4_3, 1440, 240, false, 1716, 276, 263, 23,
+	 15734, 59826, 27000, 59940, true},
+	{HDMI_VFRMT_1440x480p60_4_3, 1440, 480, false, 1716, 276, 525, 45,
+	 31469, 59940, 54000, 59940, true},
+	{HDMI_VFRMT_1440x480i60_4_3, 1440, 480, true,  1716, 276, 525, 22,
+	 15750, 60000, 27027, 60000, true},
+	{HDMI_VFRMT_1440x240p60_4_3, 1440, 240, false, 1716, 276, 262, 22,
+	 15750, 60115, 27027, 60000, true},
+	{HDMI_VFRMT_1440x240p60_4_3, 1440, 240, false, 1716, 276, 263, 23,
+	 15750, 59886, 27027, 60000, true},
+	{HDMI_VFRMT_1440x480p60_4_3, 1440, 480, false, 1716, 276, 525, 45,
+	 31500, 60000, 54054, 60000, true},
+	{HDMI_VFRMT_1440x576i100_4_3, 1440, 576, true,  1728, 288, 625, 24,
+	 31250, 100000, 54000, 100000, true},
+	{HDMI_VFRMT_1440x480i120_4_3, 1440, 480, true,  1716, 276, 525, 22,
+	 31469, 119880, 54000, 119880, true},
+	{HDMI_VFRMT_1440x480i120_4_3, 1440, 480, true,  1716, 276, 525, 22,
+	 31500, 120000, 54054, 120000, true},
+	{HDMI_VFRMT_1440x576i200_4_3, 1440, 576, true,  1728, 288, 625, 24,
+	 62500, 200000, 108000, 200000, true},
+	{HDMI_VFRMT_1440x480i240_4_3, 1440, 480, true,  1716, 276, 525, 22,
+	 62937, 239760, 108000, 239000, true},
+	{HDMI_VFRMT_1440x480i240_4_3, 1440, 480, true,  1716, 276, 525, 22,
+	 63000, 240000, 108108, 240000, true},
+
+	/* All 1920 H Active */
+	{HDMI_VFRMT_1920x1080p60_16_9, 1920, 1080, false, 2200, 280, 1125,
+	 45, 67433, 59940, 148352, 59940, false},
+	{HDMI_VFRMT_1920x1080p60_16_9, 1920, 1080, true,  2200, 280, 1125,
+	 45, 67500, 60000, 148500, 60000, false},
+	{HDMI_VFRMT_1920x1080p50_16_9, 1920, 1080, false, 2640, 720, 1125,
+	 45, 56250, 50000, 148500, 50000, false},
+	{HDMI_VFRMT_1920x1080p24_16_9, 1920, 1080, false, 2750, 830, 1125,
+	 45, 26973, 23976, 74176, 24000, false},
+	{HDMI_VFRMT_1920x1080p24_16_9, 1920, 1080, false, 2750, 830, 1125,
+	 45, 27000, 24000, 74250, 24000, false},
+	{HDMI_VFRMT_1920x1080p25_16_9, 1920, 1080, false, 2640, 720, 1125,
+	 45, 28125, 25000, 74250, 25000, false},
+	{HDMI_VFRMT_1920x1080p30_16_9, 1920, 1080, false, 2200, 280, 1125,
+	 45, 33716, 29970, 74176, 30000, false},
+	{HDMI_VFRMT_1920x1080p30_16_9, 1920, 1080, false, 2200, 280, 1125,
+	 45, 33750, 30000, 74250, 30000, false},
+	{HDMI_VFRMT_1920x1080i50_16_9, 1920, 1080, true,  2304, 384, 1250,
+	 85, 31250, 50000, 72000, 50000, false},
+	{HDMI_VFRMT_1920x1080i60_16_9, 1920, 1080, true,  2200, 280, 1125,
+	 22, 33716, 59940, 74176, 59940, false},
+	{HDMI_VFRMT_1920x1080i60_16_9, 1920, 1080, true,  2200, 280, 1125,
+	 22, 33750, 60000, 74250, 60000, false},
+	{HDMI_VFRMT_1920x1080i100_16_9, 1920, 1080, true,  2640, 720, 1125,
+	 22, 56250, 100000, 148500, 100000, false},
+	{HDMI_VFRMT_1920x1080i120_16_9, 1920, 1080, true,  2200, 280, 1125,
+	 22, 67432, 119880, 148352, 119980, false},
+	{HDMI_VFRMT_1920x1080i120_16_9, 1920, 1080, true,  2200, 280, 1125,
+	 22, 67500, 120000, 148500, 120000, false},
+
+	/* All 2880 H Active */
+	{HDMI_VFRMT_2880x576i50_4_3, 2880, 576, true,  3456, 576, 625, 24,
+	 15625, 50000, 54000, 50000, true},
+	{HDMI_VFRMT_2880x288p50_4_3, 2880, 576, false, 3456, 576, 312, 24,
+	 15625, 50080, 54000, 50000, true},
+	{HDMI_VFRMT_2880x288p50_4_3, 2880, 576, false, 3456, 576, 313, 25,
+	 15625, 49920, 54000, 50000, true},
+	{HDMI_VFRMT_2880x288p50_4_3, 2880, 576, false, 3456, 576, 314, 26,
+	 15625, 49761, 54000, 50000, true},
+	{HDMI_VFRMT_2880x576p50_4_3, 2880, 576, false, 3456, 576, 625, 49,
+	 31250, 50000, 108000, 50000, true},
+	{HDMI_VFRMT_2880x480i60_4_3, 2880, 480, true,  3432, 552, 525, 22,
+	 15734, 59940, 54000, 59940, true},
+	{HDMI_VFRMT_2880x240p60_4_3, 2880, 480, false, 3432, 552, 262, 22,
+	 15734, 60054, 54000, 59940, true},
+	{HDMI_VFRMT_2880x240p60_4_3, 2880, 480, false, 3432, 552, 263, 23,
+	 15734, 59940, 54000, 59940, true},
+	{HDMI_VFRMT_2880x480p60_4_3, 2880, 480, false, 3432, 552, 525, 45,
+	 31469, 59940, 108000, 59940, true},
+	{HDMI_VFRMT_2880x480i60_4_3, 2880, 480, true,  3432, 552, 525, 22,
+	 15750, 60000, 54054, 60000, true},
+	{HDMI_VFRMT_2880x240p60_4_3, 2880, 240, false, 3432, 552, 262, 22,
+	 15750, 60115, 54054, 60000, true},
+	{HDMI_VFRMT_2880x240p60_4_3, 2880, 240, false, 3432, 552, 262, 23,
+	 15750, 59886, 54054, 60000, true},
+	{HDMI_VFRMT_2880x480p60_4_3, 2880, 480, false, 3432, 552, 525, 45,
+	 31500, 60000, 108108, 60000, true},
+};
+
+static ssize_t hdmi_edid_sysfs_rda_modes(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	ssize_t ret = 0;
+	int i;
+	struct hdmi_edid_ctrl *edid_ctrl =
+		hdmi_get_featuredata_from_sysfs_dev(dev, HDMI_TX_FEAT_EDID);
+
+	if (!edid_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	buf[0] = 0;
+	if (edid_ctrl->sink_data.num_of_elements) {
+		u32 *video_mode = edid_ctrl->sink_data.disp_mode_list;
+		for (i = 0; i < edid_ctrl->sink_data.num_of_elements; ++i) {
+			if (ret > 0)
+				ret += snprintf(buf+ret, PAGE_SIZE-ret, ",%d",
+					*video_mode++ + 1);
+			else
+				ret += snprintf(buf+ret, PAGE_SIZE-ret, "%d",
+					*video_mode++ + 1);
+		}
+	} else {
+		ret += snprintf(buf+ret, PAGE_SIZE-ret, "%d",
+			edid_ctrl->video_resolution+1);
+	}
+
+	DEV_DBG("%s: '%s'\n", __func__, buf);
+	ret += snprintf(buf+ret, PAGE_SIZE-ret, "\n");
+
+	return ret;
+} /* hdmi_edid_sysfs_rda_modes */
+static DEVICE_ATTR(edid_modes, S_IRUGO, hdmi_edid_sysfs_rda_modes, NULL);
+
+static ssize_t hdmi_edid_sysfs_rda_physical_address(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	ssize_t ret;
+	struct hdmi_edid_ctrl *edid_ctrl =
+		hdmi_get_featuredata_from_sysfs_dev(dev, HDMI_TX_FEAT_EDID);
+
+	if (!edid_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	ret = snprintf(buf, PAGE_SIZE, "%d\n", edid_ctrl->physical_address);
+	DEV_DBG("%s: '%d'\n", __func__, edid_ctrl->physical_address);
+
+	return ret;
+} /* hdmi_edid_sysfs_rda_physical_address */
+static DEVICE_ATTR(pa, S_IRUGO, hdmi_edid_sysfs_rda_physical_address, NULL);
+
+static ssize_t hdmi_edid_sysfs_rda_scan_info(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	ssize_t ret;
+	struct hdmi_edid_ctrl *edid_ctrl =
+		hdmi_get_featuredata_from_sysfs_dev(dev, HDMI_TX_FEAT_EDID);
+
+	if (!edid_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	ret = snprintf(buf, PAGE_SIZE, "%d, %d, %d\n", edid_ctrl->pt_scan_info,
+		edid_ctrl->it_scan_info, edid_ctrl->ce_scan_info);
+	DEV_DBG("%s: '%s'\n", __func__, buf);
+
+	return ret;
+} /* hdmi_edid_sysfs_rda_scan_info */
+static DEVICE_ATTR(scan_info, S_IRUGO, hdmi_edid_sysfs_rda_scan_info, NULL);
+
+static ssize_t hdmi_edid_sysfs_rda_3d_modes(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	ssize_t ret = 0;
+	int i;
+	char buff_3d[128];
+	struct hdmi_edid_ctrl *edid_ctrl =
+		hdmi_get_featuredata_from_sysfs_dev(dev, HDMI_TX_FEAT_EDID);
+
+	if (!edid_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	buf[0] = 0;
+	if (edid_ctrl->sink_data.num_of_elements) {
+		u32 *video_mode = edid_ctrl->sink_data.disp_mode_list;
+		u32 *video_3d_mode = edid_ctrl->sink_data.disp_3d_mode_list;
+
+		for (i = 0; i < edid_ctrl->sink_data.num_of_elements; ++i) {
+			ret = hdmi_get_video_3d_fmt_2string(*video_3d_mode++,
+				buff_3d);
+			if (ret > 0)
+				ret += snprintf(buf+ret, PAGE_SIZE-ret,
+					",%d=%s", *video_mode++ + 1,
+					buff_3d);
+			else
+				ret += snprintf(buf+ret, PAGE_SIZE-ret,
+					"%d=%s", *video_mode++ + 1,
+					buff_3d);
+		}
+	} else {
+		ret += snprintf(buf+ret, PAGE_SIZE-ret, "%d",
+			edid_ctrl->video_resolution+1);
+	}
+
+	DEV_DBG("%s: '%s'\n", __func__, buf);
+	ret += snprintf(buf+ret, PAGE_SIZE-ret, "\n");
+
+	return ret;
+} /* hdmi_edid_sysfs_rda_3d_modes */
+static DEVICE_ATTR(edid_3d_modes, S_IRUGO, hdmi_edid_sysfs_rda_3d_modes, NULL);
+
+static struct attribute *hdmi_edid_fs_attrs[] = {
+	&dev_attr_edid_modes.attr,
+	&dev_attr_pa.attr,
+	&dev_attr_scan_info.attr,
+	&dev_attr_edid_3d_modes.attr,
+	NULL,
+};
+
+static struct attribute_group hdmi_edid_fs_attrs_group = {
+	.attrs = hdmi_edid_fs_attrs,
+};
+
+static int hdmi_edid_read_block(struct hdmi_edid_ctrl *edid_ctrl, int block,
+	u8 *edid_buf)
+{
+	const u8 *b = NULL;
+	u32 ndx, check_sum, print_len;
+	int block_size = 0x80;
+	int i, status;
+	struct hdmi_tx_ddc_data ddc_data;
+	b = edid_buf;
+
+	if (!edid_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	do {
+		DEV_DBG("EDID: reading block(%d) with block-size=%d\n",
+			block, block_size);
+		for (i = 0; i < 0x80; i += block_size) {
+			/*Read EDID twice with 32bit alighnment too */
+			if (block < 2) {
+				memset(&ddc_data, 0, sizeof(ddc_data));
+				ddc_data.dev_addr = 0xA0;
+				ddc_data.offset   = block*0x80 + i;
+				ddc_data.data_buf = edid_buf+i;
+				ddc_data.data_len = block_size;
+				ddc_data.retry    = 1;
+				ddc_data.what     = "EDID";
+				ddc_data.no_align = false;
+
+				status = hdmi_ddc_read(
+					edid_ctrl->init_data.ddc_ctrl,
+					&ddc_data);
+			} else {
+				memset(&ddc_data, 0, sizeof(ddc_data));
+				ddc_data.dev_addr    = 0xA0;
+				ddc_data.offset      = block*0x80 + i;
+				ddc_data.data_buf    = edid_buf+i;
+				ddc_data.data_len    = block_size;
+				ddc_data.request_len = block_size;
+				ddc_data.retry       = 1;
+				ddc_data.what        = "EDID";
+
+				status = hdmi_ddc_read_seg(
+					edid_ctrl->init_data.ddc_ctrl,
+					&ddc_data);
+			}
+			if (status)
+				break;
+		}
+
+		block_size /= 2;
+	} while (status && (block_size >= 16));
+
+	if (status)
+		goto error;
+
+	/* Calculate checksum */
+	check_sum = 0;
+	for (ndx = 0; ndx < 0x80; ++ndx)
+		check_sum += edid_buf[ndx];
+
+	if (check_sum & 0xFF) {
+		DEV_ERR("%s: failed CHECKSUM (read:%x, expected:%x)\n",
+			__func__, (u8)edid_buf[0x7F], (u8)check_sum);
+		for (ndx = 0; ndx < 0x100; ndx += 4)
+			DEV_DBG("EDID[%02x-%02x] %02x %02x %02x %02x\n",
+				ndx, ndx+3,
+				b[ndx+0], b[ndx+1], b[ndx+2], b[ndx+3]);
+		status = -EPROTO;
+		goto error;
+	}
+
+	print_len = 0x80;
+	for (ndx = 0; ndx < print_len; ndx += 16)
+		DEV_DBG("EDID[%02x-%02x] %02x %02x %02x %02x\n",
+			ndx, ndx+3,
+			b[ndx+0], b[ndx+1], b[ndx+2], b[ndx+3]);
+
+error:
+	return status;
+} /* hdmi_edid_read_block */
+
+static const u8 *hdmi_edid_find_block(const u8 *in_buf, u32 start_offset,
+	u8 type, u8 *len)
+{
+	/* the start of data block collection, start of Video Data Block */
+	u32 offset = start_offset;
+	u32 end_dbc_offset = in_buf[2];
+
+	*len = 0;
+
+	/*
+	 * * edid buffer 1, byte 2 being 4 means no non-DTD/Data block
+	 *   collection present.
+	 * * edid buffer 1, byte 2 being 0 menas no non-DTD/DATA block
+	 *   collection present and no DTD data present.
+	 */
+	if ((end_dbc_offset == 0) || (end_dbc_offset == 4)) {
+		DEV_WARN("EDID: no DTD or non-DTD data present\n");
+		return NULL;
+	}
+
+	while (offset < end_dbc_offset) {
+		u8 block_len = in_buf[offset] & 0x1F;
+		if ((in_buf[offset] >> 5) == type) {
+			*len = block_len;
+			DEV_DBG("%s: EDID: block=%d found @ %d w/ length=%d\n",
+				__func__, type, offset, block_len);
+
+			return in_buf + offset;
+		}
+		offset += 1 + block_len;
+	}
+	DEV_WARN("%s: EDID: type=%d block not found in EDID block\n",
+		__func__, type);
+
+	return NULL;
+} /* hdmi_edid_find_block */
+
+static void hdmi_edid_extract_extended_data_blocks(
+	struct hdmi_edid_ctrl *edid_ctrl, const u8 *in_buf)
+{
+	u8 len = 0;
+	u32 start_offset = DBC_START_OFFSET;
+	u8 const *etag = NULL;
+
+	if (!edid_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+
+	/* A Tage code of 7 identifies extended data blocks */
+	etag = hdmi_edid_find_block(in_buf, start_offset, 7, &len);
+
+	while (etag != NULL) {
+		/* The extended data block should at least be 2 bytes long */
+		if (len < 2) {
+			DEV_DBG("%s: data block of len < 2 bytes. Ignor...\n",
+				__func__);
+		} else {
+			/*
+			 * The second byte of the extended data block has the
+			 * extended tag code
+			 */
+			switch (etag[1]) {
+			case 0:
+				/* Video Capability Data Block */
+				DEV_DBG("%s: EDID: VCDB=%02X %02X\n", __func__,
+					etag[1], etag[2]);
+
+				/*
+				 * Check if the sink specifies underscan
+				 * support for:
+				 * BIT 5: preferred video format
+				 * BIT 3: IT video format
+				 * BIT 1: CE video format
+				 */
+				edid_ctrl->pt_scan_info =
+					(etag[2] & (BIT(4) | BIT(5))) >> 4;
+				edid_ctrl->it_scan_info =
+					(etag[2] & (BIT(3) | BIT(2))) >> 2;
+				edid_ctrl->ce_scan_info =
+					etag[2] & (BIT(1) | BIT(0));
+				DEV_DBG("%s: Scan Info (pt|it|ce): (%d|%d|%d)",
+					__func__,
+					edid_ctrl->pt_scan_info,
+					edid_ctrl->it_scan_info,
+					edid_ctrl->ce_scan_info);
+				break;
+			default:
+				DEV_DBG("%s: Tag Code %d not supported\n",
+					__func__, etag[1]);
+				break;
+			}
+		}
+
+		/* There could be more that one extended data block */
+		start_offset = etag - in_buf + len + 1;
+		etag = hdmi_edid_find_block(in_buf, start_offset, 7, &len);
+	}
+} /* hdmi_edid_extract_extended_data_blocks */
+
+static void hdmi_edid_extract_3d_present(struct hdmi_edid_ctrl *edid_ctrl,
+	const u8 *in_buf)
+{
+	u8 len, offset;
+	const u8 *vsd = NULL;
+
+	if (!edid_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+
+	vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 3, &len);
+
+	edid_ctrl->present_3d = 0;
+	if (vsd == NULL || len < 9) {
+		DEV_DBG("%s: blk-id 3 not found or not long enough\n",
+			__func__);
+		return;
+	}
+
+	offset = HDMI_VSDB_3D_DATA_OFFSET(vsd);
+	DEV_DBG("%s: EDID: 3D present @ %d = %02x\n", __func__,
+		offset, vsd[offset]);
+
+	if (vsd[offset] >> 7) { /* 3D format indication present */
+		DEV_INFO("%s: EDID: 3D present, 3D-len=%d\n", __func__,
+			vsd[offset+1] & 0x1F);
+		edid_ctrl->present_3d = 1;
+	}
+} /* hdmi_edid_extract_3d_present */
+
+static void hdmi_edid_extract_audio_data_blocks(
+	struct hdmi_edid_ctrl *edid_ctrl, const u8 *in_buf)
+{
+	u8 len;
+	const u8 *sad = NULL;
+
+	if (!edid_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+
+	sad = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 1, &len);
+	if (sad == NULL)
+		return;
+
+	edid_ctrl->audio_data_block_cnt = 0;
+	while (len >= 3 && edid_ctrl->audio_data_block_cnt < 16) {
+		DEV_DBG("%s: ch=%d fmt=%d sampling=0x%02x bitdepth=0x%02x\n",
+			__func__, (sad[1]&0x7)+1, sad[1]>>3, sad[2], sad[3]);
+
+		++edid_ctrl->audio_data_block_cnt;
+		len -= 3;
+		sad += 3;
+	}
+} /* hdmi_edid_extract_audio_data_blocks */
+
+static void hdmi_edid_extract_speaker_allocation_data(
+	struct hdmi_edid_ctrl *edid_ctrl, const u8 *in_buf)
+{
+	u8 len;
+	const u8 *sad = NULL;
+
+	if (!edid_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+
+	sad = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 4, &len);
+	if (sad == NULL)
+		return;
+
+	edid_ctrl->speaker_allocation_block = sad[1];
+	DEV_DBG("%s: EDID: speaker alloc data SP byte = %08x %s%s%s%s%s%s%s\n",
+		__func__, sad[1],
+		(sad[1] & BIT(0)) ? "FL/FR," : "",
+		(sad[1] & BIT(1)) ? "LFE," : "",
+		(sad[1] & BIT(2)) ? "FC," : "",
+		(sad[1] & BIT(3)) ? "RL/RR," : "",
+		(sad[1] & BIT(4)) ? "RC," : "",
+		(sad[1] & BIT(5)) ? "FLC/FRC," : "",
+		(sad[1] & BIT(6)) ? "RLC/RRC," : "");
+} /* hdmi_edid_extract_speaker_allocation_data */
+
+static void hdmi_edid_extract_latency_fields(struct hdmi_edid_ctrl *edid_ctrl,
+	const u8 *in_buf)
+{
+	u8 len;
+	const u8 *vsd = NULL;
+
+	if (!edid_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+
+	vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 3, &len);
+
+	if (vsd == NULL || len < 12 || !(vsd[8] & BIT(7))) {
+		edid_ctrl->video_latency = (u16)-1;
+		edid_ctrl->audio_latency = (u16)-1;
+		DEV_DBG("%s: EDID: No audio/video latency present\n", __func__);
+	} else {
+		edid_ctrl->video_latency = vsd[9];
+		edid_ctrl->audio_latency = vsd[10];
+		DEV_DBG("%s: EDID: video-latency=%04x, audio-latency=%04x\n",
+			__func__, edid_ctrl->video_latency,
+			edid_ctrl->audio_latency);
+	}
+} /* hdmi_edid_extract_latency_fields */
+
+static u32 hdmi_edid_extract_ieee_reg_id(struct hdmi_edid_ctrl *edid_ctrl,
+	const u8 *in_buf)
+{
+	u8 len;
+	const u8 *vsd = NULL;
+
+	if (!edid_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return 0;
+	}
+
+	vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 3, &len);
+	if (vsd == NULL)
+		return 0;
+
+	DEV_DBG("%s: EDID: VSD PhyAddr=%04x, MaxTMDS=%dMHz\n", __func__,
+		((u32)vsd[4] << 8) + (u32)vsd[5], (u32)vsd[7] * 5);
+
+	edid_ctrl->physical_address = ((u16)vsd[4] << 8) + (u16)vsd[5];
+
+	return ((u32)vsd[3] << 16) + ((u32)vsd[2] << 8) + (u32)vsd[1];
+} /* hdmi_edid_extract_ieee_reg_id */
+
+static void hdmi_edid_extract_vendor_id(const u8 *in_buf,
+	char *vendor_id)
+{
+	u32 id_codes = ((u32)in_buf[8] << 8) + in_buf[9];
+
+	vendor_id[0] = 'A' - 1 + ((id_codes >> 10) & 0x1F);
+	vendor_id[1] = 'A' - 1 + ((id_codes >> 5) & 0x1F);
+	vendor_id[2] = 'A' - 1 + (id_codes & 0x1F);
+	vendor_id[3] = 0;
+} /* hdmi_edid_extract_vendor_id */
+
+static u32 hdmi_edid_check_header(const u8 *edid_buf)
+{
+	return (edid_buf[0] == 0x00) && (edid_buf[1] == 0xff)
+		&& (edid_buf[2] == 0xff) && (edid_buf[3] == 0xff)
+		&& (edid_buf[4] == 0xff) && (edid_buf[5] == 0xff)
+		&& (edid_buf[6] == 0xff) && (edid_buf[7] == 0x00);
+} /* hdmi_edid_check_header */
+
+static void hdmi_edid_detail_desc(const u8 *data_buf, u32 *disp_mode)
+{
+	u32	aspect_ratio_4_3    = false;
+	u32	interlaced          = false;
+	u32	active_h            = 0;
+	u32	active_v            = 0;
+	u32	blank_h             = 0;
+	u32	blank_v             = 0;
+	u32	ndx                 = 0;
+	u32	max_num_of_elements = 0;
+	u32	img_size_h          = 0;
+	u32	img_size_v          = 0;
+
+	/*
+	 * * See VESA Spec
+	 * * EDID_TIMING_DESC_UPPER_H_NIBBLE[0x4]: Relative Offset to the
+	 *   EDID detailed timing descriptors - Upper 4 bit for each H
+	 *   active/blank field
+	 * * EDID_TIMING_DESC_H_ACTIVE[0x2]: Relative Offset to the EDID
+	 *   detailed timing descriptors - H active
+	 */
+	active_h = ((((u32)data_buf[0x4] >> 0x4) & 0xF) << 8)
+		| data_buf[0x2];
+
+	/*
+	 * EDID_TIMING_DESC_H_BLANK[0x3]: Relative Offset to the EDID detailed
+	 *   timing descriptors - H blank
+	 */
+	blank_h = (((u32)data_buf[0x4] & 0xF) << 8)
+		| data_buf[0x3];
+
+	/*
+	 * * EDID_TIMING_DESC_UPPER_V_NIBBLE[0x7]: Relative Offset to the
+	 *   EDID detailed timing descriptors - Upper 4 bit for each V
+	 *   active/blank field
+	 * * EDID_TIMING_DESC_V_ACTIVE[0x5]: Relative Offset to the EDID
+	 *   detailed timing descriptors - V active
+	 */
+	active_v = ((((u32)data_buf[0x7] >> 0x4) & 0xF) << 8)
+		| data_buf[0x5];
+
+	/*
+	 * EDID_TIMING_DESC_V_BLANK[0x6]: Relative Offset to the EDID
+	 * detailed timing descriptors - V blank
+	 */
+	blank_v = (((u32)data_buf[0x7] & 0xF) << 8)
+		| data_buf[0x6];
+
+	/*
+	 * * EDID_TIMING_DESC_IMAGE_SIZE_UPPER_NIBBLE[0xE]: Relative Offset
+	 *   to the EDID detailed timing descriptors - Image Size upper
+	 *   nibble V and H
+	 * * EDID_TIMING_DESC_H_IMAGE_SIZE[0xC]: Relative Offset to the EDID
+	 *   detailed timing descriptors - H image size
+	 * * EDID_TIMING_DESC_V_IMAGE_SIZE[0xD]: Relative Offset to the EDID
+	 *   detailed timing descriptors - V image size
+	 */
+	img_size_h = ((((u32)data_buf[0xE] >> 0x4) & 0xF) << 8)
+		| data_buf[0xC];
+	img_size_v = (((u32)data_buf[0xE] & 0xF) << 8)
+		| data_buf[0xD];
+
+	/*
+	 * aspect ratio as 4:3 if within specificed range , rathaer than being
+	 * absolute value
+	 */
+	aspect_ratio_4_3 = (abs(img_size_h * 3 - img_size_v * 4) < 5) ? 1 : 0;
+
+	max_num_of_elements = sizeof(hdmi_edid_disp_mode_lut)
+		/ sizeof(*hdmi_edid_disp_mode_lut);
+
+	/*
+	 * EDID_TIMING_DESC_INTERLACE[0x11:7]: Relative Offset to the EDID
+	 * detailed timing descriptors - Interlace flag
+	 */
+	DEV_DBG("%s: Interlaced mode byte data_buf[0x11]=[%x]\n", __func__,
+		data_buf[0x11]);
+
+	/*
+	 * CEA 861-D: interlaced bit is bit[7] of byte[0x11]
+	 */
+	interlaced = (data_buf[0x11] & 0x80) >> 7;
+
+	DEV_DBG("%s: A[%ux%u] B[%ux%u] V[%ux%u] %s\n", __func__,
+		active_h, active_v, blank_h, blank_v, img_size_h, img_size_v,
+		interlaced ? "i" : "p");
+
+	*disp_mode = HDMI_VFRMT_FORCE_32BIT;
+	while (ndx < max_num_of_elements) {
+		const struct hdmi_edid_video_mode_property_type *edid =
+			hdmi_edid_disp_mode_lut + ndx;
+
+		if ((interlaced    == edid->interlaced)    &&
+			(active_h  == edid->active_h)      &&
+			(blank_h   == edid->total_blank_h) &&
+			(blank_v   == edid->total_blank_v) &&
+			((active_v == edid->active_v) ||
+			(active_v  == (edid->active_v + 1)))) {
+			if (edid->aspect_ratio_4_3 && !aspect_ratio_4_3)
+				/* Aspect ratio 16:9 */
+				*disp_mode = edid->video_code + 1;
+			else
+				/* Aspect ratio 4:3 */
+				*disp_mode = edid->video_code;
+
+			DEV_DBG("%s: mode found:%d\n", __func__, *disp_mode);
+			break;
+		}
+		++ndx;
+	}
+	if (ndx == max_num_of_elements)
+		DEV_INFO("%s: *no mode* found\n", __func__);
+} /* hdmi_edid_detail_desc */
+
+static void hdmi_edid_add_sink_3d_format(struct hdmi_edid_sink_data *sink_data,
+	u32 video_format, u32 video_3d_format)
+{
+	char string[128];
+	u32 added = false;
+	int i;
+
+	for (i = 0; i < sink_data->num_of_elements; ++i) {
+		if (sink_data->disp_mode_list[i] == video_format) {
+			sink_data->disp_3d_mode_list[i] |= video_3d_format;
+			added = true;
+			break;
+		}
+	}
+
+	hdmi_get_video_3d_fmt_2string(video_3d_format, string);
+
+	DEV_DBG("%s: EDID[3D]: format: %d [%s], %s %s\n", __func__,
+		video_format, hdmi_get_video_fmt_2string(video_format),
+		string, added ? "added" : "NOT added");
+} /* hdmi_edid_add_sink_3d_format */
+
+static void hdmi_edid_add_sink_video_format(
+	struct hdmi_edid_sink_data *sink_data, u32 video_format)
+{
+	const struct hdmi_disp_mode_timing_type *timing =
+		hdmi_get_supported_mode(video_format);
+	u32 supported = timing != NULL;
+
+	if (video_format >= HDMI_VFRMT_MAX) {
+		DEV_ERR("%s: video format: %s is not supported\n", __func__,
+			hdmi_get_video_fmt_2string(video_format));
+		return;
+	}
+
+	DEV_DBG("%s: EDID: format: %d [%s], %s\n", __func__,
+		video_format, hdmi_get_video_fmt_2string(video_format),
+		supported ? "Supported" : "Not-Supported");
+
+	if (supported) {
+		/* todo: MHL */
+		sink_data->disp_mode_list[sink_data->num_of_elements++] =
+			video_format;
+	}
+} /* hdmi_edid_add_sink_video_format */
+
+static void hdmi_edid_get_display_vsd_3d_mode(const u8 *data_buf,
+	struct hdmi_edid_sink_data *sink_data, u32 num_of_cea_blocks)
+{
+	u8 len, offset, present_multi_3d, hdmi_vic_len, hdmi_3d_len;
+	u16 structure_all, structure_mask;
+	const u8 *vsd = num_of_cea_blocks ?
+		hdmi_edid_find_block(data_buf+0x80, DBC_START_OFFSET,
+				3, &len) : NULL;
+	int i;
+
+	offset = HDMI_VSDB_3D_DATA_OFFSET(vsd);
+	present_multi_3d = (vsd[offset] & 0x60) >> 5;
+
+	offset += 1;
+	hdmi_vic_len = (vsd[offset] >> 5) & 0x7;
+	hdmi_3d_len = vsd[offset] & 0x1F;
+	DEV_DBG("%s: EDID[3D]: HDMI_VIC_LEN = %d, HDMI_3D_LEN = %d\n", __func__,
+		hdmi_vic_len, hdmi_3d_len);
+
+	offset += (hdmi_vic_len + 1);
+	if (present_multi_3d == 1 || present_multi_3d == 2) {
+		DEV_DBG("%s: EDID[3D]: multi 3D present (%d)\n", __func__,
+			present_multi_3d);
+		/* 3d_structure_all */
+		structure_all = (vsd[offset] << 8) | vsd[offset + 1];
+		offset += 2;
+		hdmi_3d_len -= 2;
+		if (present_multi_3d == 2) {
+			/* 3d_structure_mask */
+			structure_mask = (vsd[offset] << 8) | vsd[offset + 1];
+			offset += 2;
+			hdmi_3d_len -= 2;
+		} else
+			structure_mask = 0xffff;
+
+		i = 0;
+		while (i < 16) {
+			if (i >= sink_data->disp_multi_3d_mode_list_cnt)
+				break;
+
+			if (!(structure_mask & BIT(i))) {
+				++i;
+				continue;
+			}
+
+			/* BIT0: FRAME PACKING */
+			if (structure_all & BIT(0))
+				hdmi_edid_add_sink_3d_format(sink_data,
+					sink_data->
+					disp_multi_3d_mode_list[i],
+					FRAME_PACKING);
+
+			/* BIT6: TOP AND BOTTOM */
+			if (structure_all & BIT(6))
+				hdmi_edid_add_sink_3d_format(sink_data,
+					sink_data->
+					disp_multi_3d_mode_list[i],
+					TOP_AND_BOTTOM);
+
+			/* BIT8: SIDE BY SIDE HALF */
+			if (structure_all & BIT(8))
+				hdmi_edid_add_sink_3d_format(sink_data,
+					sink_data->
+					disp_multi_3d_mode_list[i],
+					SIDE_BY_SIDE_HALF);
+
+			++i;
+		}
+	}
+
+	i = 0;
+	while (hdmi_3d_len > 0) {
+		DEV_DBG("%s: EDID[3D]: 3D_Structure_%d @ %d: %02x\n", __func__,
+			i + 1, offset, vsd[offset]);
+
+		if ((vsd[offset] >> 4) >=
+			sink_data->disp_multi_3d_mode_list_cnt) {
+			if ((vsd[offset] & 0x0F) >= 8) {
+				offset += 1;
+				hdmi_3d_len -= 1;
+				DEV_DBG("%s:EDID[3D]:3D_Detail_%d @ %d: %02x\n",
+					__func__, i + 1, offset,
+					vsd[offset]);
+			}
+			i += 1;
+			offset += 1;
+			hdmi_3d_len -= 1;
+			continue;
+		}
+
+		switch (vsd[offset] & 0x0F) {
+		case 0:
+			/* 0000b: FRAME PACKING */
+			hdmi_edid_add_sink_3d_format(sink_data,
+				sink_data->
+				disp_multi_3d_mode_list[vsd[offset] >> 4],
+				FRAME_PACKING);
+			break;
+		case 6:
+			/* 0110b: TOP AND BOTTOM */
+			hdmi_edid_add_sink_3d_format(sink_data,
+				sink_data->
+				disp_multi_3d_mode_list[vsd[offset] >> 4],
+				TOP_AND_BOTTOM);
+			break;
+		case 8:
+			/* 1000b: SIDE BY SIDE HALF */
+			hdmi_edid_add_sink_3d_format(sink_data,
+				sink_data->
+				disp_multi_3d_mode_list[vsd[offset] >> 4],
+				SIDE_BY_SIDE_HALF);
+			break;
+		}
+		if ((vsd[offset] & 0x0F) >= 8) {
+			offset += 1;
+			hdmi_3d_len -= 1;
+			DEV_DBG("%s: EDID[3D]: 3D_Detail_%d @ %d: %02x\n",
+				__func__, i + 1, offset,
+				vsd[offset]);
+		}
+		i += 1;
+		offset += 1;
+		hdmi_3d_len -= 1;
+	}
+} /* hdmi_edid_get_display_vsd_3d_mode */
+
+static void hdmi_edid_get_display_mode(struct hdmi_edid_ctrl *edid_ctrl,
+	const u8 *data_buf, u32 num_of_cea_blocks)
+{
+	u8 i = 0;
+	u32 video_format = HDMI_VFRMT_640x480p60_4_3;
+	u32 has480p = false;
+	u8 len;
+	const u8 *edid_blk0 = NULL;
+	const u8 *edid_blk1 = NULL;
+	const u8 *svd = NULL;
+	u32 has60hz_mode = false;
+	u32 has50hz_mode = false;
+	struct hdmi_edid_sink_data *sink_data = NULL;
+
+	if (!edid_ctrl || !data_buf) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+
+	edid_blk0 = &data_buf[0x0];
+	edid_blk1 = &data_buf[0x80];
+	svd = num_of_cea_blocks ?
+		hdmi_edid_find_block(data_buf+0x80, DBC_START_OFFSET, 2,
+			&len) : NULL;
+
+	sink_data = &edid_ctrl->sink_data;
+
+	sink_data->num_of_elements = 0;
+	sink_data->disp_multi_3d_mode_list_cnt = 0;
+	if (svd != NULL) {
+		++svd;
+		for (i = 0; i < len; ++i, ++svd) {
+			/*
+			 * Subtract 1 because it is zero based in the driver,
+			 * while the Video identification code is 1 based in the
+			 * CEA_861D spec
+			 */
+			video_format = (*svd & 0x7F) - 1;
+			hdmi_edid_add_sink_video_format(sink_data,
+				video_format);
+			/* Make a note of the preferred video format */
+			if (i == 0)
+				sink_data->preferred_video_format =
+					video_format;
+
+			if (i < 16) {
+				sink_data->disp_multi_3d_mode_list[i]
+					= video_format;
+				sink_data->disp_multi_3d_mode_list_cnt++;
+			}
+
+			if (video_format <= HDMI_VFRMT_1920x1080p60_16_9 ||
+				video_format == HDMI_VFRMT_2880x480p60_4_3 ||
+				video_format == HDMI_VFRMT_2880x480p60_16_9)
+				has60hz_mode = true;
+
+			if ((video_format >= HDMI_VFRMT_720x576p50_4_3 &&
+				video_format <= HDMI_VFRMT_1920x1080p50_16_9) ||
+				video_format == HDMI_VFRMT_2880x576p50_4_3 ||
+				video_format == HDMI_VFRMT_2880x576p50_16_9 ||
+				video_format == HDMI_VFRMT_1920x1250i50_16_9)
+				has50hz_mode = true;
+
+			if (video_format == HDMI_VFRMT_640x480p60_4_3)
+				has480p = true;
+		}
+	} else if (!num_of_cea_blocks) {
+		/* Detailed timing descriptors */
+		u32 desc_offset = 0;
+		/*
+		 * * Maximum 4 timing descriptor in block 0 - No CEA
+		 *   extension in this case
+		 * * EDID_FIRST_TIMING_DESC[0x36] - 1st detailed timing
+		 *   descriptor
+		 * * EDID_DETAIL_TIMING_DESC_BLCK_SZ[0x12] - Each detailed
+		 *   timing descriptor has block size of 18
+		 */
+		while (4 > i && 0 != edid_blk0[0x36+desc_offset]) {
+			hdmi_edid_detail_desc(edid_blk0+0x36+desc_offset,
+				&video_format);
+
+			DEV_DBG("[%s:%d] Block-0 Adding vid fmt = [%s]\n",
+				__func__, __LINE__,
+				hdmi_get_video_fmt_2string(video_format));
+
+			hdmi_edid_add_sink_video_format(sink_data,
+				video_format);
+
+			if (video_format == HDMI_VFRMT_640x480p60_4_3)
+				has480p = true;
+
+			/* Make a note of the preferred video format */
+			if (i == 0) {
+				sink_data->preferred_video_format =
+					video_format;
+			}
+			desc_offset += 0x12;
+			++i;
+		}
+	} else if (1 == num_of_cea_blocks) {
+		u32 desc_offset = 0;
+
+		/*
+		 * Read from both block 0 and block 1
+		 * Read EDID block[0] as above
+		 */
+		while (4 > i && 0 != edid_blk0[0x36+desc_offset]) {
+			hdmi_edid_detail_desc(edid_blk0+0x36+desc_offset,
+				&video_format);
+
+			DEV_DBG("[%s:%d] Block-0 Adding vid fmt = [%s]\n",
+				__func__, __LINE__,
+				hdmi_get_video_fmt_2string(video_format));
+
+			hdmi_edid_add_sink_video_format(sink_data,
+				video_format);
+
+			if (video_format == HDMI_VFRMT_640x480p60_4_3)
+				has480p = true;
+
+			/* Make a note of the preferred video format */
+			if (i == 0) {
+				sink_data->preferred_video_format =
+					video_format;
+			}
+			desc_offset += 0x12;
+			++i;
+		}
+
+		/*
+		 * * Parse block 1 - CEA extension byte offset of first
+		 *   detailed timing generation - offset is relevant to
+		 *   the offset of block 1
+		 * * EDID_CEA_EXTENSION_FIRST_DESC[0x82]: Offset to CEA
+		 *   extension first timing desc - indicate the offset of
+		 *   the first detailed timing descriptor
+		 * * EDID_BLOCK_SIZE = 0x80  Each page size in the EDID ROM
+		 */
+		desc_offset = edid_blk1[0x02];
+		while (0 != edid_blk1[desc_offset]) {
+			hdmi_edid_detail_desc(edid_blk1+desc_offset,
+				&video_format);
+
+			DEV_DBG("[%s:%d] Block-1 Adding vid fmt = [%s]\n",
+				__func__, __LINE__,
+				hdmi_get_video_fmt_2string(video_format));
+
+			hdmi_edid_add_sink_video_format(sink_data,
+				video_format);
+			if (video_format == HDMI_VFRMT_640x480p60_4_3)
+				has480p = true;
+
+			/* Make a note of the preferred video format */
+			if (i == 0) {
+				sink_data->preferred_video_format =
+					video_format;
+			}
+			desc_offset += 0x12;
+			++i;
+		}
+	}
+
+	/* mandaroty 3d format */
+	if (edid_ctrl->present_3d) {
+		if (has60hz_mode) {
+			hdmi_edid_add_sink_3d_format(sink_data,
+				HDMI_VFRMT_1920x1080p24_16_9,
+				FRAME_PACKING | TOP_AND_BOTTOM);
+			hdmi_edid_add_sink_3d_format(sink_data,
+				HDMI_VFRMT_1280x720p60_16_9,
+				FRAME_PACKING | TOP_AND_BOTTOM);
+			hdmi_edid_add_sink_3d_format(sink_data,
+				HDMI_VFRMT_1920x1080i60_16_9,
+				SIDE_BY_SIDE_HALF);
+		}
+
+		if (has50hz_mode) {
+			hdmi_edid_add_sink_3d_format(sink_data,
+				HDMI_VFRMT_1920x1080p24_16_9,
+				FRAME_PACKING | TOP_AND_BOTTOM);
+			hdmi_edid_add_sink_3d_format(sink_data,
+				HDMI_VFRMT_1280x720p50_16_9,
+				FRAME_PACKING | TOP_AND_BOTTOM);
+			hdmi_edid_add_sink_3d_format(sink_data,
+				HDMI_VFRMT_1920x1080i50_16_9,
+				SIDE_BY_SIDE_HALF);
+		}
+
+		/* 3d format described in Vendor Specific Data */
+		hdmi_edid_get_display_vsd_3d_mode(data_buf, sink_data,
+			num_of_cea_blocks);
+	}
+
+	/*
+	 * Need to add default 640 by 480 timings, in case not described
+	 * in the EDID structure.
+	 * All DTV sink devices should support this mode
+	 */
+	if (!has480p)
+		hdmi_edid_add_sink_video_format(sink_data,
+			HDMI_VFRMT_640x480p60_4_3);
+} /* hdmi_edid_get_display_mode */
+
+int hdmi_edid_read(void *input)
+{
+	/* EDID_BLOCK_SIZE[0x80] Each page size in the EDID ROM */
+	u8 edid_buf[0x80 * 4];
+	u32 cea_extension_ver = 0;
+	u32 num_of_cea_blocks = 0;
+	u32 ieee_reg_id = 0;
+	u32 i = 1;
+	int status = 0;
+	char vendor_id[5];
+	struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input;
+
+	if (!edid_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	edid_ctrl->pt_scan_info = 0;
+	edid_ctrl->it_scan_info = 0;
+	edid_ctrl->ce_scan_info = 0;
+	edid_ctrl->present_3d = 0;
+	memset(&edid_ctrl->sink_data, 0, sizeof(edid_ctrl->sink_data));
+	memset(edid_buf, 0, sizeof(edid_buf));
+
+	status = hdmi_edid_read_block(edid_ctrl, 0, edid_buf);
+	if (status || !hdmi_edid_check_header(edid_buf)) {
+		if (!status)
+			status = -EPROTO;
+		DEV_ERR("%s: blk0 fail:%d[%02x%02x%02x%02x%02x%02x%02x%02x]\n",
+			__func__, status,
+			edid_buf[0], edid_buf[1], edid_buf[2], edid_buf[3],
+			edid_buf[4], edid_buf[5], edid_buf[6], edid_buf[7]);
+		goto error;
+	}
+	hdmi_edid_extract_vendor_id(edid_buf, vendor_id);
+
+	/* EDID_CEA_EXTENSION_FLAG[0x7E] - CEC extension byte */
+	num_of_cea_blocks = edid_buf[0x7E];
+	DEV_DBG("%s: No. of CEA blocks is  [%u]\n", __func__,
+		num_of_cea_blocks);
+	/* Find out any CEA extension blocks following block 0 */
+	switch (num_of_cea_blocks) {
+	case 0: /* No CEA extension */
+		edid_ctrl->sink_mode = false;
+		DEV_DBG("HDMI DVI mode: %s\n",
+			edid_ctrl->sink_mode ? "no" : "yes");
+		break;
+	case 1: /* Read block 1 */
+		status = hdmi_edid_read_block(edid_ctrl, 1, &edid_buf[0x80]);
+		if (status) {
+			DEV_ERR("%s: ddc read block(1) failed: %d\n", __func__,
+				status);
+			goto error;
+		}
+		if (edid_buf[0x80] != 2)
+			num_of_cea_blocks = 0;
+		if (num_of_cea_blocks) {
+			ieee_reg_id =
+				hdmi_edid_extract_ieee_reg_id(edid_ctrl,
+					edid_buf+0x80);
+			if (ieee_reg_id == 0x0c03)
+				edid_ctrl->sink_mode = true;
+			else
+				edid_ctrl->sink_mode = false;
+
+			hdmi_edid_extract_latency_fields(edid_ctrl,
+				edid_buf+0x80);
+			hdmi_edid_extract_speaker_allocation_data(
+				edid_ctrl, edid_buf+0x80);
+			hdmi_edid_extract_audio_data_blocks(edid_ctrl,
+				edid_buf+0x80);
+			hdmi_edid_extract_3d_present(edid_ctrl,
+				edid_buf+0x80);
+			hdmi_edid_extract_extended_data_blocks(edid_ctrl,
+				edid_buf+0x80);
+		}
+		break;
+	case 2:
+	case 3:
+	case 4:
+		for (i = 1; i <= num_of_cea_blocks; i++) {
+			if (!(i % 2)) {
+				status = hdmi_edid_read_block(
+					edid_ctrl, i, edid_buf+0x00);
+				if (status) {
+					DEV_ERR("%s: read blk(%d) failed:%d\n",
+						__func__, i, status);
+					goto error;
+				}
+			} else {
+				status = hdmi_edid_read_block(
+					edid_ctrl, i, edid_buf+0x80);
+				if (status) {
+					DEV_ERR("%s: read blk(%d) failed:%d\n",
+						__func__, i, status);
+					goto error;
+				}
+			}
+		}
+		break;
+	default:
+		DEV_ERR("%s: ddc read failed, not supported multi-blocks: %d\n",
+			__func__, num_of_cea_blocks);
+		status = -EPROTO;
+		goto error;
+	}
+
+	if (num_of_cea_blocks) {
+		/* EDID_CEA_EXTENSION_VERSION[0x81]: Offset to CEA extension
+		 * version number - v1,v2,v3 (v1 is seldom, v2 is obsolete,
+		 * v3 most common) */
+		cea_extension_ver = edid_buf[0x81];
+	}
+
+	/* EDID_VERSION[0x12] - EDID Version */
+	/* EDID_REVISION[0x13] - EDID Revision */
+	DEV_INFO("%s: V=%d.%d #CEABlks=%d[V%d] ID=%s IEEE=%04x Ext=0x%02x\n",
+		__func__, edid_buf[0x12], edid_buf[0x13],
+		num_of_cea_blocks, cea_extension_ver, vendor_id, ieee_reg_id,
+		edid_buf[0x80]);
+
+	hdmi_edid_get_display_mode(edid_ctrl, edid_buf, num_of_cea_blocks);
+
+	return 0;
+
+error:
+	edid_ctrl->sink_data.num_of_elements = 1;
+	edid_ctrl->sink_data.disp_mode_list[0] = edid_ctrl->video_resolution;
+
+	return status;
+} /* hdmi_edid_read */
+
+/*
+ * If the sink specified support for both underscan/overscan then, by default,
+ * set the underscan bit. Only checking underscan support for preferred
+ * format and cea formats.
+ */
+u8 hdmi_edid_get_sink_scaninfo(void *input, u32 resolution)
+{
+	u8 scaninfo = 0;
+	int use_ce_scan_info = true;
+	struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input;
+
+	if (!edid_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		goto end;
+	}
+
+	if (resolution == edid_ctrl->sink_data.preferred_video_format) {
+		use_ce_scan_info = false;
+		switch (edid_ctrl->pt_scan_info) {
+		case 0:
+			/*
+			 * Need to use the info specified for the corresponding
+			 * IT or CE format
+			 */
+			DEV_DBG("%s: No underscan info for preferred V fmt\n",
+				__func__);
+			use_ce_scan_info = true;
+			break;
+		case 3:
+			DEV_DBG("%s: Set underscan bit for preferred V fmt\n",
+				__func__);
+			scaninfo = BIT(1);
+			break;
+		default:
+			DEV_DBG("%s: Underscan not set for preferred V fmt\n",
+				__func__);
+			break;
+		}
+	}
+
+	if (use_ce_scan_info) {
+		if (3 == edid_ctrl->ce_scan_info) {
+			DEV_DBG("%s: Setting underscan bit for CE video fmt\n",
+				__func__);
+			scaninfo |= BIT(1);
+		} else {
+			DEV_DBG("%s: Not setting underscan bit for CE V fmt\n",
+				__func__);
+		}
+	}
+
+end:
+	return scaninfo;
+} /* hdmi_edid_get_sink_scaninfo */
+
+u32 hdmi_edid_get_sink_mode(void *input)
+{
+	struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input;
+
+	if (!edid_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return 0;
+	}
+
+	return edid_ctrl->sink_mode;
+} /* hdmi_edid_get_sink_mode */
+
+void hdmi_edid_set_video_resolution(void *input, u32 resolution)
+{
+	struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input;
+
+	if (!edid_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+
+	edid_ctrl->video_resolution = resolution;
+
+	if (1 == edid_ctrl->sink_data.num_of_elements)
+		edid_ctrl->sink_data.disp_mode_list[0] = resolution;
+} /* hdmi_edid_set_video_resolution */
+
+void hdmi_edid_deinit(void *input)
+{
+	struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input;
+
+	if (edid_ctrl) {
+		sysfs_remove_group(edid_ctrl->init_data.sysfs_kobj,
+			&hdmi_edid_fs_attrs_group);
+		kfree(edid_ctrl);
+	}
+} /* hdmi_edid_deinit */
+
+void *hdmi_edid_init(struct hdmi_edid_init_data *init_data)
+{
+	struct hdmi_edid_ctrl *edid_ctrl = NULL;
+
+	if (!init_data || !init_data->base ||
+		!init_data->mutex || !init_data->sysfs_kobj ||
+		!init_data->ddc_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		goto error;
+	}
+
+	edid_ctrl = kzalloc(sizeof(*edid_ctrl), GFP_KERNEL);
+	if (!edid_ctrl) {
+		DEV_ERR("%s: Out of memory\n", __func__);
+		goto error;
+	}
+
+	edid_ctrl->init_data = *init_data;
+	edid_ctrl->sink_mode = false;
+
+	if (sysfs_create_group(init_data->sysfs_kobj,
+		&hdmi_edid_fs_attrs_group)) {
+		DEV_ERR("%s: EDID sysfs create failed\n", __func__);
+		kfree(edid_ctrl);
+		edid_ctrl = NULL;
+	}
+
+error:
+	return (void *)edid_ctrl;
+} /* hdmi_edid_deinit */
diff --git a/drivers/video/msm/mdss/mdss_hdmi_edid.h b/drivers/video/msm/mdss/mdss_hdmi_edid.h
new file mode 100644
index 0000000..d10ae49
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_hdmi_edid.h
@@ -0,0 +1,33 @@
+/* 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
+ * 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 __HDMI_EDID_H__
+#define __HDMI_EDID_H__
+
+#include "mdss_hdmi_util.h"
+
+struct hdmi_edid_init_data {
+	void __iomem *base;
+	struct mutex *mutex;
+	struct kobject *sysfs_kobj;
+
+	struct hdmi_tx_ddc_ctrl *ddc_ctrl;
+};
+
+int hdmi_edid_read(void *edid_ctrl);
+u8 hdmi_edid_get_sink_scaninfo(void *edid_ctrl, u32 resolution);
+u32 hdmi_edid_get_sink_mode(void *edid_ctrl);
+void hdmi_edid_set_video_resolution(void *edid_ctrl, u32 resolution);
+void hdmi_edid_deinit(void *edid_ctrl);
+void *hdmi_edid_init(struct hdmi_edid_init_data *init_data);
+
+#endif /* __HDMI_EDID_H__ */
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
new file mode 100644
index 0000000..b88ff72
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -0,0 +1,2388 @@
+/* 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
+ * 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/bitops.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of_address.h>
+#include <linux/of_gpio.h>
+#include <linux/types.h>
+
+/* #define DEBUG */
+
+#include "mdss_fb.h"
+#include "mdss_hdmi_tx.h"
+#include "mdss_hdmi_edid.h"
+#include "mdss.h"
+#include "mdss_panel.h"
+
+#define DRV_NAME "hdmi-tx"
+#define COMPATIBLE_NAME "qcom,hdmi-tx"
+
+#define DEFAULT_VIDEO_RESOLUTION HDMI_VFRMT_1920x1080p60_16_9;
+
+/* HDMI PHY/PLL bit field macros */
+#define SW_RESET BIT(2)
+#define SW_RESET_PLL BIT(0)
+
+#define IFRAME_CHECKSUM_32(d)			\
+	((d & 0xff) + ((d >> 8) & 0xff) +	\
+	((d >> 16) & 0xff) + ((d >> 24) & 0xff))
+
+static int hdmi_tx_sysfs_enable_hpd(struct hdmi_tx_ctrl *hdmi_ctrl, int on);
+static irqreturn_t hdmi_tx_isr(int irq, void *data);
+
+struct mdss_hw hdmi_tx_hw = {
+	.hw_ndx = MDSS_HW_HDMI,
+	.ptr = NULL,
+	.irq_handler = hdmi_tx_isr,
+};
+
+const char *hdmi_pm_name(enum hdmi_tx_power_module_type module)
+{
+	switch (module) {
+	case HDMI_TX_HPD_PM:	return "HDMI_TX_HPD_PM";
+	case HDMI_TX_CORE_PM:	return "HDMI_TX_CORE_PM";
+	case HDMI_TX_CEC_PM:	return "HDMI_TX_CEC_PM";
+	default: return "???";
+	}
+} /* hdmi_pm_name */
+
+static u8 hdmi_tx_avi_iframe_lut[][16] = {
+/*	480p60	480i60	576p50	576i50	720p60	 720p50	1080p60	1080i60	1080p50
+	1080i50	1080p24	1080p30	1080p25	640x480p 480p60_16_9 576p50_4_3 */
+	{0x10,	0x10,	0x10,	0x10,	0x10,	 0x10,	0x10,	0x10,	0x10,
+	 0x10,	0x10,	0x10,	0x10,	0x10, 0x10, 0x10}, /*00*/
+	{0x18,	0x18,	0x28,	0x28,	0x28,	 0x28,	0x28,	0x28,	0x28,
+	 0x28,	0x28,	0x28,	0x28,	0x18, 0x28, 0x18}, /*01*/
+	{0x00,	0x04,	0x04,	0x04,	0x04,	 0x04,	0x04,	0x04,	0x04,
+	 0x04,	0x04,	0x04,	0x04,	0x88, 0x00, 0x04}, /*02*/
+	{0x02,	0x06,	0x11,	0x15,	0x04,	 0x13,	0x10,	0x05,	0x1F,
+	 0x14,	0x20,	0x22,	0x21,	0x01, 0x03, 0x11}, /*03*/
+	{0x00,	0x01,	0x00,	0x01,	0x00,	 0x00,	0x00,	0x00,	0x00,
+	 0x00,	0x00,	0x00,	0x00,	0x00, 0x00, 0x00}, /*04*/
+	{0x00,	0x00,	0x00,	0x00,	0x00,	 0x00,	0x00,	0x00,	0x00,
+	 0x00,	0x00,	0x00,	0x00,	0x00, 0x00, 0x00}, /*05*/
+	{0x00,	0x00,	0x00,	0x00,	0x00,	 0x00,	0x00,	0x00,	0x00,
+	 0x00,	0x00,	0x00,	0x00,	0x00, 0x00, 0x00}, /*06*/
+	{0xE1,	0xE1,	0x41,	0x41,	0xD1,	 0xd1,	0x39,	0x39,	0x39,
+	 0x39,	0x39,	0x39,	0x39,	0xe1, 0xE1, 0x41}, /*07*/
+	{0x01,	0x01,	0x02,	0x02,	0x02,	 0x02,	0x04,	0x04,	0x04,
+	 0x04,	0x04,	0x04,	0x04,	0x01, 0x01, 0x02}, /*08*/
+	{0x00,	0x00,	0x00,	0x00,	0x00,	 0x00,	0x00,	0x00,	0x00,
+	 0x00,	0x00,	0x00,	0x00,	0x00, 0x00, 0x00}, /*09*/
+	{0x00,	0x00,	0x00,	0x00,	0x00,	 0x00,	0x00,	0x00,	0x00,
+	 0x00,	0x00,	0x00,	0x00,	0x00, 0x00, 0x00}, /*10*/
+	{0xD1,	0xD1,	0xD1,	0xD1,	0x01,	 0x01,	0x81,	0x81,	0x81,
+	 0x81,	0x81,	0x81,	0x81,	0x81, 0xD1, 0xD1}, /*11*/
+	{0x02,	0x02,	0x02,	0x02,	0x05,	 0x05,	0x07,	0x07,	0x07,
+	 0x07,	0x07,	0x07,	0x07,	0x02, 0x02, 0x02}  /*12*/
+};
+
+static const char *hdmi_tx_clk_name(u32 clk)
+{
+	switch (clk) {
+	case HDMI_TX_AHB_CLK:	return "hdmi_ahb_clk";
+	case HDMI_TX_APP_CLK:	return "hdmi_app_clk";
+	case HDMI_TX_EXTP_CLK:	return "hdmi_extp_clk";
+	default:		return "???";
+	}
+} /* hdmi_tx_clk_name */
+
+static const char *hdmi_tx_io_name(u32 io)
+{
+	switch (io) {
+	case HDMI_TX_CORE_IO:	return "core_physical";
+	case HDMI_TX_PHY_IO:	return "phy_physical";
+	case HDMI_TX_QFPROM_IO:	return "qfprom_physical";
+	default:		return NULL;
+	}
+} /* hdmi_tx_io_name */
+
+static struct hdmi_tx_ctrl *hdmi_tx_get_drvdata_from_panel_data(
+	struct mdss_panel_data *mpd)
+{
+	struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
+
+	if (mpd) {
+		hdmi_ctrl = container_of(mpd, struct hdmi_tx_ctrl, panel_data);
+		if (hdmi_ctrl) {
+			hdmi_ctrl->pixel_clk =
+				mpd->panel_info.fbi->var.pixclock;
+			hdmi_ctrl->xres = mpd->panel_info.fbi->var.xres;
+			hdmi_ctrl->yres = mpd->panel_info.fbi->var.yres;
+		} else {
+			DEV_ERR("%s: hdmi_ctrl = NULL\n", __func__);
+		}
+	} else {
+		DEV_ERR("%s: mdss_panel_data = NULL\n", __func__);
+	}
+	return hdmi_ctrl;
+} /* hdmi_tx_get_drvdata_from_panel_data */
+
+static struct hdmi_tx_ctrl *hdmi_tx_get_drvdata_from_sysfs_dev(
+	struct device *device)
+{
+	struct msm_fb_data_type *mfd = NULL;
+	struct mdss_panel_data *panel_data = NULL;
+	struct fb_info *fbi = dev_get_drvdata(device);
+
+	if (fbi) {
+		mfd = (struct msm_fb_data_type *)fbi->par;
+		panel_data = dev_get_platdata(&mfd->pdev->dev);
+
+		return hdmi_tx_get_drvdata_from_panel_data(panel_data);
+	} else {
+		DEV_ERR("%s: fbi = NULL\n", __func__);
+		return NULL;
+	}
+} /* hdmi_tx_get_drvdata_from_sysfs_dev */
+
+/* todo: Fix this. Right now this is declared in hdmi_util.h */
+void *hdmi_get_featuredata_from_sysfs_dev(struct device *device,
+	u32 feature_type)
+{
+	struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
+
+	if (!device || feature_type > HDMI_TX_FEAT_MAX) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return NULL;
+	}
+
+	hdmi_ctrl = hdmi_tx_get_drvdata_from_sysfs_dev(device);
+	if (hdmi_ctrl)
+		return hdmi_ctrl->feature_data[feature_type];
+	else
+		return NULL;
+
+} /* hdmi_tx_get_featuredata_from_sysfs_dev */
+EXPORT_SYMBOL(hdmi_get_featuredata_from_sysfs_dev);
+
+static ssize_t hdmi_tx_sysfs_rda_connected(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	ssize_t ret;
+	struct hdmi_tx_ctrl *hdmi_ctrl =
+		hdmi_tx_get_drvdata_from_sysfs_dev(dev);
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	mutex_lock(&hdmi_ctrl->mutex);
+	ret = snprintf(buf, PAGE_SIZE, "%d\n", hdmi_ctrl->hpd_state);
+	DEV_DBG("%s: '%d'\n", __func__, hdmi_ctrl->hpd_state);
+	mutex_unlock(&hdmi_ctrl->mutex);
+
+	return ret;
+} /* hdmi_tx_sysfs_rda_connected */
+
+static ssize_t hdmi_tx_sysfs_rda_fake_hpd(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	ssize_t ret;
+	struct hdmi_tx_ctrl *hdmi_ctrl =
+		hdmi_tx_get_drvdata_from_sysfs_dev(dev);
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	mutex_lock(&hdmi_ctrl->mutex);
+	ret = snprintf(buf, PAGE_SIZE, "%d\n", hdmi_ctrl->hpd_state);
+	DEV_DBG("%s: '%d'\n", __func__, hdmi_ctrl->hpd_state);
+	mutex_unlock(&hdmi_ctrl->mutex);
+
+	return ret;
+} /* hdmi_tx_sysfs_rda_fake_hpd */
+
+static ssize_t hdmi_tx_sysfs_wta_fake_hpd(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	int fake_hpd, rc = 0;
+	ssize_t ret = strnlen(buf, PAGE_SIZE);
+	struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
+
+	DEV_DBG("%s:\n", __func__);
+	hdmi_ctrl = hdmi_tx_get_drvdata_from_sysfs_dev(dev);
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	rc = kstrtoint(buf, 10, &fake_hpd);
+	if (rc) {
+		DEV_ERR("%s: kstrtoint failed. rc=%d\n", __func__, rc);
+		return rc;
+	}
+
+	mutex_lock(&hdmi_ctrl->mutex);
+	DEV_INFO("%s: fake_hpd=%d\n", __func__, fake_hpd);
+	if (fake_hpd) {
+		hdmi_ctrl->hpd_state = true;
+
+		/* todo: Remove this once HPD line is available in HW */
+		DEV_INFO("HDMI HPD: sense CONNECTED: send ONLINE\n");
+		if (kobject_uevent(hdmi_ctrl->kobj, KOBJ_ONLINE))
+			DEV_ERR("%s: failed sending online event\n", __func__);
+		switch_set_state(&hdmi_ctrl->sdev, 1);
+		DEV_INFO("%s: Hdmi state switch to %d\n", __func__,
+			hdmi_ctrl->sdev.state);
+	} else {
+		hdmi_ctrl->hpd_state = false;
+
+		/* todo: Remove this once HPD line is available in HW */
+		DEV_INFO("HDMI HPD: sense CONNECTED: send ONLINE\n");
+		if (kobject_uevent(hdmi_ctrl->kobj, KOBJ_OFFLINE))
+			DEV_ERR("%s: failed sending online event\n", __func__);
+		switch_set_state(&hdmi_ctrl->sdev, 0);
+		DEV_INFO("%s: Hdmi state switch to %d\n", __func__,
+			hdmi_ctrl->sdev.state);
+	}
+	mutex_unlock(&hdmi_ctrl->mutex);
+
+	return ret;
+} /* hdmi_tx_sysfs_wta_fake_hpd */
+
+static ssize_t hdmi_tx_sysfs_rda_hpd(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	ssize_t ret;
+	struct hdmi_tx_ctrl *hdmi_ctrl =
+		hdmi_tx_get_drvdata_from_sysfs_dev(dev);
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	ret = snprintf(buf, PAGE_SIZE, "%d\n", hdmi_ctrl->hpd_feature_on);
+	DEV_DBG("%s: '%d'\n", __func__, hdmi_ctrl->hpd_feature_on);
+
+	return ret;
+} /* hdmi_tx_sysfs_rda_hpd */
+
+static ssize_t hdmi_tx_sysfs_wta_hpd(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	int hpd, rc = 0;
+	ssize_t ret = strnlen(buf, PAGE_SIZE);
+	struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
+
+	DEV_DBG("%s:\n", __func__);
+	hdmi_ctrl = hdmi_tx_get_drvdata_from_sysfs_dev(dev);
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	rc = kstrtoint(buf, 10, &hpd);
+	if (rc) {
+		DEV_ERR("%s: kstrtoint failed. rc=%d\n", __func__, rc);
+		return rc;
+	}
+
+	/* todo: Remove this once HPD line is available in HW */
+	if (0) {
+		if (0 == hpd && hdmi_ctrl->hpd_feature_on) {
+			rc = hdmi_tx_sysfs_enable_hpd(hdmi_ctrl, false);
+		} else if (1 == hpd && !hdmi_ctrl->hpd_feature_on) {
+			rc = hdmi_tx_sysfs_enable_hpd(hdmi_ctrl, true);
+		} else {
+			rc = -EPERM;
+			ret = rc;
+		}
+	}
+
+	if (!rc) {
+		hdmi_ctrl->hpd_feature_on =
+			(~hdmi_ctrl->hpd_feature_on) & BIT(0);
+		DEV_DBG("%s: '%d'\n", __func__, hdmi_ctrl->hpd_feature_on);
+	} else {
+		DEV_DBG("%s: '%d' (unchanged)\n", __func__,
+			hdmi_ctrl->hpd_feature_on);
+	}
+
+	return ret;
+} /* hdmi_tx_sysfs_wta_hpd */
+
+static DEVICE_ATTR(connected, S_IRUGO, hdmi_tx_sysfs_rda_connected, NULL);
+static DEVICE_ATTR(hpd, S_IRUGO | S_IWUSR, hdmi_tx_sysfs_rda_hpd,
+	hdmi_tx_sysfs_wta_hpd);
+static DEVICE_ATTR(fake_hpd, S_IRUGO | S_IWUSR, hdmi_tx_sysfs_rda_fake_hpd,
+	hdmi_tx_sysfs_wta_fake_hpd);
+
+static struct attribute *hdmi_tx_fs_attrs[] = {
+	&dev_attr_connected.attr,
+	&dev_attr_hpd.attr,
+	&dev_attr_fake_hpd.attr,
+	NULL,
+};
+static struct attribute_group hdmi_tx_fs_attrs_group = {
+	.attrs = hdmi_tx_fs_attrs,
+};
+
+static int hdmi_tx_sysfs_create(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+	int rc;
+	struct mdss_panel_info *pinfo = NULL;
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -ENODEV;
+	}
+	pinfo = &hdmi_ctrl->panel_data.panel_info;
+
+	rc = sysfs_create_group(&pinfo->fbi->dev->kobj,
+		&hdmi_tx_fs_attrs_group);
+	if (rc) {
+		DEV_ERR("%s: failed, rc=%d\n", __func__, rc);
+		return rc;
+	}
+	hdmi_ctrl->kobj = &pinfo->fbi->dev->kobj;
+	DEV_DBG("%s: sysfs group %p\n", __func__, hdmi_ctrl->kobj);
+
+	kobject_uevent(hdmi_ctrl->kobj, KOBJ_ADD);
+	DEV_DBG("%s: kobject_uevent(KOBJ_ADD)\n", __func__);
+
+	return 0;
+} /* hdmi_tx_sysfs_create */
+
+static void hdmi_tx_sysfs_remove(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+	if (hdmi_ctrl->kobj)
+		sysfs_remove_group(hdmi_ctrl->kobj, &hdmi_tx_fs_attrs_group);
+	hdmi_ctrl->kobj = NULL;
+} /* hdmi_tx_sysfs_remove */
+
+/* Enable HDMI features */
+static int hdmi_tx_init_features(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+	struct hdmi_edid_init_data edid_init_data;
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	edid_init_data.base = hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO].base;
+	edid_init_data.mutex = &hdmi_ctrl->mutex;
+	edid_init_data.sysfs_kobj = hdmi_ctrl->kobj;
+	edid_init_data.ddc_ctrl = &hdmi_ctrl->ddc_ctrl;
+
+	hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID] =
+		hdmi_edid_init(&edid_init_data);
+	if (!hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID]) {
+		DEV_ERR("%s: hdmi_edid_init failed\n", __func__);
+		return -EPERM;
+	}
+	hdmi_edid_set_video_resolution(
+		hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID],
+		hdmi_ctrl->video_resolution);
+
+	return 0;
+} /* hdmi_tx_init_features */
+
+static inline u32 hdmi_tx_is_controller_on(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+	return HDMI_REG_R_ND(hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO].base,
+		HDMI_CTRL) & BIT(0);
+} /* hdmi_tx_is_controller_on */
+
+static inline u32 hdmi_tx_is_dvi_mode(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+	return !(HDMI_REG_R_ND(hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO].base,
+		HDMI_CTRL) & BIT(1));
+} /* hdmi_tx_is_dvi_mode */
+
+static int hdmi_tx_init_panel_info(uint32_t resolution,
+	struct mdss_panel_info *pinfo)
+{
+	const struct hdmi_disp_mode_timing_type *timing =
+		hdmi_get_supported_mode(resolution);
+
+	if (!timing || !pinfo) {
+		DEV_ERR("%s: invalid input.\n", __func__);
+		return -EINVAL;
+	}
+
+	pinfo->xres = timing->active_h;
+	pinfo->yres = timing->active_v;
+	pinfo->clk_rate = timing->pixel_freq*1000;
+
+	pinfo->lcdc.h_back_porch = timing->back_porch_h;
+	pinfo->lcdc.h_front_porch = timing->front_porch_h;
+	pinfo->lcdc.h_pulse_width = timing->pulse_width_h;
+	pinfo->lcdc.v_back_porch = timing->back_porch_v;
+	pinfo->lcdc.v_front_porch = timing->front_porch_v;
+	pinfo->lcdc.v_pulse_width = timing->pulse_width_v;
+
+	pinfo->type = DTV_PANEL;
+	pinfo->pdest = DISPLAY_2;
+	pinfo->wait_cycle = 0;
+	pinfo->bpp = 24;
+	pinfo->fb_num = 1;
+
+	pinfo->lcdc.border_clr = 0; /* blk */
+	pinfo->lcdc.underflow_clr = 0xff; /* blue */
+	pinfo->lcdc.hsync_skew = 0;
+
+	return 0;
+} /* hdmi_tx_init_panel_info */
+
+/* Table indicating the video format supported by the HDMI TX Core */
+/* Valid Pixel-Clock rates: 25.2MHz, 27MHz, 27.03MHz, 74.25MHz, 148.5MHz */
+static void hdmi_tx_setup_video_mode_lut(void)
+{
+	hdmi_set_supported_mode(HDMI_VFRMT_640x480p60_4_3);
+	hdmi_set_supported_mode(HDMI_VFRMT_720x480p60_4_3);
+	hdmi_set_supported_mode(HDMI_VFRMT_720x480p60_16_9);
+	hdmi_set_supported_mode(HDMI_VFRMT_720x576p50_4_3);
+	hdmi_set_supported_mode(HDMI_VFRMT_720x576p50_16_9);
+	hdmi_set_supported_mode(HDMI_VFRMT_1440x480i60_4_3);
+	hdmi_set_supported_mode(HDMI_VFRMT_1440x480i60_16_9);
+	hdmi_set_supported_mode(HDMI_VFRMT_1440x576i50_4_3);
+	hdmi_set_supported_mode(HDMI_VFRMT_1440x576i50_16_9);
+	hdmi_set_supported_mode(HDMI_VFRMT_1280x720p50_16_9);
+	hdmi_set_supported_mode(HDMI_VFRMT_1280x720p60_16_9);
+	hdmi_set_supported_mode(HDMI_VFRMT_1920x1080p24_16_9);
+	hdmi_set_supported_mode(HDMI_VFRMT_1920x1080p25_16_9);
+	hdmi_set_supported_mode(HDMI_VFRMT_1920x1080p30_16_9);
+	hdmi_set_supported_mode(HDMI_VFRMT_1920x1080p50_16_9);
+	hdmi_set_supported_mode(HDMI_VFRMT_1920x1080i60_16_9);
+	hdmi_set_supported_mode(HDMI_VFRMT_1920x1080p60_16_9);
+} /* hdmi_tx_setup_video_mode_lut */
+
+static inline struct clk *hdmi_tx_get_clk(struct hdmi_tx_platform_data *pdata,
+	u32 clk_idx)
+{
+	if (!pdata || clk_idx > HDMI_TX_MAX_CLK) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return NULL;
+	}
+
+	return pdata->clk[clk_idx];
+} /* hdmi_tx_get_clk */
+
+static int hdmi_tx_clk_set_rate(struct hdmi_tx_platform_data *pdata,
+	u32 clk_idx, unsigned long clk_rate)
+{
+	int rc = 0;
+	struct clk *clk = NULL;
+
+	if (!pdata) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	clk = hdmi_tx_get_clk(pdata, clk_idx);
+	if (clk) {
+		rc = clk_set_rate(clk, clk_rate);
+		if (IS_ERR_VALUE(rc))
+			DEV_ERR("%s: failed rc=%d\n", __func__, rc);
+		else
+			DEV_DBG("%s: name='%s' rate=%lu\n", __func__,
+				hdmi_tx_clk_name(clk_idx), clk_rate);
+	} else {
+		DEV_ERR("%s: FAILED: invalid clk_idx=%d\n", __func__, clk_idx);
+		rc = -EINVAL;
+	}
+
+	return rc;
+} /* hdmi_tx_clk_set_rate */
+
+static int hdmi_tx_read_sink_info(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+	int status;
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!hdmi_tx_is_controller_on(hdmi_ctrl)) {
+		DEV_ERR("%s: failed: HDMI controller is off", __func__);
+		status = -ENXIO;
+		goto error;
+	}
+
+	hdmi_ddc_config(&hdmi_ctrl->ddc_ctrl);
+
+	status = hdmi_edid_read(hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID]);
+	if (!status)
+		DEV_DBG("%s: hdmi_edid_read success\n", __func__);
+	else
+		DEV_ERR("%s: hdmi_edid_read failed\n", __func__);
+
+error:
+	return status;
+} /* hdmi_tx_read_sink_info */
+
+static void hdmi_tx_hpd_state_work(struct work_struct *work)
+{
+	u32 hpd_state = false;
+	struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
+	struct dss_io_data *io = NULL;
+
+	hdmi_ctrl = container_of(work, struct hdmi_tx_ctrl, hpd_state_work);
+	if (!hdmi_ctrl || !hdmi_ctrl->hpd_initialized) {
+		DEV_DBG("%s: invalid input\n", __func__);
+		return;
+	}
+
+	io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
+	DEV_DBG("%s: Got HPD interrupt\n", __func__);
+
+	hpd_state = (HDMI_REG_R(io->base, HDMI_HPD_INT_STATUS) & BIT(1)) >> 1;
+	mutex_lock(&hdmi_ctrl->mutex);
+	if ((hdmi_ctrl->hpd_prev_state != hdmi_ctrl->hpd_state) ||
+		(hdmi_ctrl->hpd_state != hpd_state)) {
+
+		hdmi_ctrl->hpd_state = hpd_state;
+		hdmi_ctrl->hpd_prev_state = hdmi_ctrl->hpd_state;
+		hdmi_ctrl->hpd_stable = 0;
+
+		DEV_DBG("%s: state not stable yet, wait again (%d|%d|%d)\n",
+			__func__, hdmi_ctrl->hpd_prev_state,
+			hdmi_ctrl->hpd_state, hpd_state);
+
+		mutex_unlock(&hdmi_ctrl->mutex);
+
+		mod_timer(&hdmi_ctrl->hpd_state_timer, jiffies + HZ/2);
+
+		return;
+	}
+
+	if (hdmi_ctrl->hpd_stable) {
+		mutex_unlock(&hdmi_ctrl->mutex);
+		DEV_DBG("%s: no more timer, depending on IRQ now\n",
+			__func__);
+		return;
+	}
+
+	hdmi_ctrl->hpd_stable = 1;
+
+	/*
+	 *todo: Revisit cable chg detected condition when HPD support is ready
+	 */
+	hdmi_ctrl->hpd_cable_chg_detected = false;
+	mutex_unlock(&hdmi_ctrl->mutex);
+
+	if (hpd_state) {
+		/* todo: what if EDID read fails? */
+		hdmi_tx_read_sink_info(hdmi_ctrl);
+		DEV_INFO("HDMI HPD: sense CONNECTED: send ONLINE\n");
+		kobject_uevent(hdmi_ctrl->kobj, KOBJ_ONLINE);
+		switch_set_state(&hdmi_ctrl->sdev, 1);
+		DEV_INFO("%s: Hdmi state switch to %d\n", __func__,
+			hdmi_ctrl->sdev.state);
+	} else {
+		DEV_INFO("HDMI HPD: sense DISCONNECTED: send OFFLINE\n");
+		kobject_uevent(hdmi_ctrl->kobj, KOBJ_OFFLINE);
+		switch_set_state(&hdmi_ctrl->sdev, 0);
+		DEV_INFO("%s: Hdmi state switch to %d\n", __func__,
+			hdmi_ctrl->sdev.state);
+	}
+
+	/* Set IRQ for HPD */
+	HDMI_REG_W(io->base, HDMI_HPD_INT_CTRL, 4 | (hpd_state ? 0 : 2));
+} /* hdmi_tx_hpd_state_work */
+
+static int hdmi_tx_check_capability(void __iomem *base)
+{
+	u32 hdmi_disabled, hdcp_disabled;
+
+	if (!base) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	/* QFPROM_RAW_FEAT_CONFIG_ROW0_LSB */
+	hdcp_disabled = HDMI_REG_R_ND(base, 0x000000F8) & BIT(31);
+	/* QFPROM_RAW_FEAT_CONFIG_ROW0_MSB */
+	hdmi_disabled = HDMI_REG_R_ND(base, 0x000000FC) & BIT(0);
+
+	DEV_DBG("%s: Features <HDMI:%s, HDCP:%s>\n", __func__,
+		hdmi_disabled ? "OFF" : "ON", hdcp_disabled ? "OFF" : "ON");
+
+	if (hdmi_disabled) {
+		DEV_ERR("%s: HDMI disabled\n", __func__);
+		return -ENODEV;
+	}
+
+	if (hdcp_disabled)
+		DEV_WARN("%s: HDCP disabled\n", __func__);
+
+	return 0;
+} /* hdmi_tx_check_capability */
+
+static int hdmi_tx_set_video_fmt(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+	int rc = 0;
+	const struct hdmi_disp_mode_timing_type *timing = NULL;
+	struct hdmi_tx_platform_data *pdata = NULL;
+	u32 format = DEFAULT_VIDEO_RESOLUTION;
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		rc = -EINVAL;
+		goto end;
+	}
+
+	pdata = &hdmi_ctrl->pdata;
+
+	DEV_DBG("%s: Resolution wanted=%dx%d\n", __func__, hdmi_ctrl->xres,
+		hdmi_ctrl->yres);
+	switch (hdmi_ctrl->xres) {
+	default:
+	case 640:
+		format = HDMI_VFRMT_640x480p60_4_3;
+		break;
+	case 720:
+		format = (hdmi_ctrl->yres == 480)
+			? HDMI_VFRMT_720x480p60_16_9
+			: HDMI_VFRMT_720x576p50_16_9;
+		break;
+	case 1280:
+		if (hdmi_ctrl->frame_rate == 50000)
+			format = HDMI_VFRMT_1280x720p50_16_9;
+		else
+			format = HDMI_VFRMT_1280x720p60_16_9;
+		break;
+	case 1440:
+		/* interlaced has half of y res. */
+		format = (hdmi_ctrl->yres == 240)
+			? HDMI_VFRMT_1440x480i60_16_9
+			: HDMI_VFRMT_1440x576i50_16_9;
+		break;
+	case 1920:
+		if (hdmi_ctrl->yres == 540) {/* interlaced */
+			format = HDMI_VFRMT_1920x1080i60_16_9;
+		} else if (hdmi_ctrl->yres == 1080) {
+			if (hdmi_ctrl->frame_rate == 50000)
+				format = HDMI_VFRMT_1920x1080p50_16_9;
+			else if (hdmi_ctrl->frame_rate == 24000)
+				format = HDMI_VFRMT_1920x1080p24_16_9;
+			else if (hdmi_ctrl->frame_rate == 25000)
+				format = HDMI_VFRMT_1920x1080p25_16_9;
+			else if (hdmi_ctrl->frame_rate == 30000)
+				format = HDMI_VFRMT_1920x1080p30_16_9;
+			else
+				format = HDMI_VFRMT_1920x1080p60_16_9;
+		}
+		break;
+	}
+
+	if (hdmi_ctrl->video_resolution != format)
+		DEV_DBG("%s: switching %s => %s", __func__,
+			hdmi_get_video_fmt_2string(
+			hdmi_ctrl->video_resolution),
+			hdmi_get_video_fmt_2string(format));
+	else
+		DEV_DBG("resolution %s", hdmi_get_video_fmt_2string(
+			hdmi_ctrl->video_resolution));
+
+	timing = hdmi_get_supported_mode(format);
+	if (!timing) {
+		DEV_ERR("%s: invalid video fmt=%d\n", __func__,
+			hdmi_ctrl->video_resolution);
+		rc = -EPERM;
+		goto end;
+	}
+
+	/*
+	 * extpclk is driven by hdmi phy pll. This phy pll programming requires
+	 * hdmi_ahb_clk. So enable it and then disable.
+	 */
+	rc = clk_prepare_enable(pdata->clk[HDMI_TX_AHB_CLK]);
+	if (rc) {
+		DEV_ERR("%s: failed to enable '%s' clk\n", __func__,
+			hdmi_tx_clk_name(HDMI_TX_AHB_CLK));
+		goto end;
+	}
+	rc = hdmi_tx_clk_set_rate(pdata, HDMI_TX_EXTP_CLK,
+		timing->pixel_freq * 1000);
+	if (rc) {
+		DEV_ERR("%s: FAILED: '%s' clk set rate\n", __func__,
+			hdmi_tx_clk_name(HDMI_TX_EXTP_CLK));
+		clk_disable_unprepare(pdata->clk[HDMI_TX_AHB_CLK]);
+		goto end;
+	}
+	clk_disable_unprepare(pdata->clk[HDMI_TX_AHB_CLK]);
+
+	hdmi_ctrl->video_resolution = format;
+	hdmi_edid_set_video_resolution(
+		hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID], format);
+
+end:
+	return rc;
+} /* hdmi_tx_set_video_fmt */
+
+static void hdmi_tx_video_setup(struct hdmi_tx_ctrl *hdmi_ctrl,
+	int video_format)
+{
+	u32 total_v   = 0;
+	u32 total_h   = 0;
+	u32 start_h   = 0;
+	u32 end_h     = 0;
+	u32 start_v   = 0;
+	u32 end_v     = 0;
+	struct dss_io_data *io = NULL;
+
+	const struct hdmi_disp_mode_timing_type *timing =
+		hdmi_get_supported_mode(video_format);
+	if (timing == NULL) {
+		DEV_ERR("%s: video format not supported: %d\n", __func__,
+			video_format);
+		return;
+	}
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+
+	io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
+	if (!io->base) {
+		DEV_ERR("%s: Core io is not initialized\n", __func__);
+		return;
+	}
+
+	total_h = timing->active_h + timing->front_porch_h +
+		timing->back_porch_h + timing->pulse_width_h - 1;
+	total_v = timing->active_v + timing->front_porch_v +
+		timing->back_porch_v + timing->pulse_width_v - 1;
+	HDMI_REG_W(io->base, HDMI_TOTAL,
+		((total_v << 16) & 0x0FFF0000) |
+		((total_h << 0) & 0x00000FFF));
+
+	start_h = timing->back_porch_h + timing->pulse_width_h;
+	end_h   = (total_h + 1) - timing->front_porch_h;
+	HDMI_REG_W(io->base, HDMI_ACTIVE_H,
+		((end_h << 16) & 0x0FFF0000) |
+		((start_h << 0) & 0x00000FFF));
+
+	start_v = timing->back_porch_v + timing->pulse_width_v - 1;
+	end_v   = total_v - timing->front_porch_v;
+	HDMI_REG_W(io->base, HDMI_ACTIVE_V,
+		((end_v << 16) & 0x0FFF0000) |
+		((start_v << 0) & 0x00000FFF));
+
+	if (timing->interlaced) {
+		HDMI_REG_W(io->base, HDMI_V_TOTAL_F2,
+			((total_v + 1) << 0) & 0x00000FFF);
+
+		HDMI_REG_W(io->base, HDMI_ACTIVE_V_F2,
+			(((start_v + 1) << 0) & 0x00000FFF) |
+			(((end_v + 1) << 16) & 0x0FFF0000));
+	} else {
+		HDMI_REG_W(io->base, HDMI_V_TOTAL_F2, 0);
+		HDMI_REG_W(io->base, HDMI_ACTIVE_V_F2, 0);
+	}
+
+	HDMI_REG_W(io->base, HDMI_FRAME_CTRL,
+		((timing->interlaced << 31) & 0x80000000) |
+		((timing->active_low_h << 29) & 0x20000000) |
+		((timing->active_low_v << 28) & 0x10000000));
+} /* hdmi_tx_video_setup */
+
+static void hdmi_tx_set_avi_infoframe(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+	int i, mode = 0;
+	u8 avi_iframe[16]; /* two header + length + 13 data */
+	u8 checksum;
+	u32 sum, regVal;
+	struct dss_io_data *io = NULL;
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+
+	io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
+	if (!io->base) {
+		DEV_ERR("%s: Core io is not initialized\n", __func__);
+		return;
+	}
+
+	switch (hdmi_ctrl->video_resolution) {
+	case HDMI_VFRMT_720x480p60_4_3:
+		mode = 0;
+		break;
+	case HDMI_VFRMT_720x480i60_16_9:
+		mode = 1;
+		break;
+	case HDMI_VFRMT_720x576p50_16_9:
+		mode = 2;
+		break;
+	case HDMI_VFRMT_720x576i50_16_9:
+		mode = 3;
+		break;
+	case HDMI_VFRMT_1280x720p60_16_9:
+		mode = 4;
+		break;
+	case HDMI_VFRMT_1280x720p50_16_9:
+		mode = 5;
+		break;
+	case HDMI_VFRMT_1920x1080p60_16_9:
+		mode = 6;
+		break;
+	case HDMI_VFRMT_1920x1080i60_16_9:
+		mode = 7;
+		break;
+	case HDMI_VFRMT_1920x1080p50_16_9:
+		mode = 8;
+		break;
+	case HDMI_VFRMT_1920x1080i50_16_9:
+		mode = 9;
+		break;
+	case HDMI_VFRMT_1920x1080p24_16_9:
+		mode = 10;
+		break;
+	case HDMI_VFRMT_1920x1080p30_16_9:
+		mode = 11;
+		break;
+	case HDMI_VFRMT_1920x1080p25_16_9:
+		mode = 12;
+		break;
+	case HDMI_VFRMT_640x480p60_4_3:
+		mode = 13;
+		break;
+	case HDMI_VFRMT_720x480p60_16_9:
+		mode = 14;
+		break;
+	case HDMI_VFRMT_720x576p50_4_3:
+		mode = 15;
+		break;
+	default:
+		DEV_INFO("%s: mode %d not supported\n", __func__,
+			hdmi_ctrl->video_resolution);
+		return;
+	}
+
+	/* InfoFrame Type = 82 */
+	avi_iframe[0]  = 0x82;
+	/* Version = 2 */
+	avi_iframe[1]  = 2;
+	/* Length of AVI InfoFrame = 13 */
+	avi_iframe[2]  = 13;
+
+	/* Data Byte 01: 0 Y1 Y0 A0 B1 B0 S1 S0 */
+	avi_iframe[3]  = hdmi_tx_avi_iframe_lut[0][mode];
+	avi_iframe[3] |= hdmi_edid_get_sink_scaninfo(
+		hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID],
+		hdmi_ctrl->video_resolution);
+
+	/* Data Byte 02: C1 C0 M1 M0 R3 R2 R1 R0 */
+	avi_iframe[4]  = hdmi_tx_avi_iframe_lut[1][mode];
+	/* Data Byte 03: ITC EC2 EC1 EC0 Q1 Q0 SC1 SC0 */
+	avi_iframe[5]  = hdmi_tx_avi_iframe_lut[2][mode];
+	/* Data Byte 04: 0 VIC6 VIC5 VIC4 VIC3 VIC2 VIC1 VIC0 */
+	avi_iframe[6]  = hdmi_tx_avi_iframe_lut[3][mode];
+	/* Data Byte 05: 0 0 0 0 PR3 PR2 PR1 PR0 */
+	avi_iframe[7]  = hdmi_tx_avi_iframe_lut[4][mode];
+	/* Data Byte 06: LSB Line No of End of Top Bar */
+	avi_iframe[8]  = hdmi_tx_avi_iframe_lut[5][mode];
+	/* Data Byte 07: MSB Line No of End of Top Bar */
+	avi_iframe[9]  = hdmi_tx_avi_iframe_lut[6][mode];
+	/* Data Byte 08: LSB Line No of Start of Bottom Bar */
+	avi_iframe[10] = hdmi_tx_avi_iframe_lut[7][mode];
+	/* Data Byte 09: MSB Line No of Start of Bottom Bar */
+	avi_iframe[11] = hdmi_tx_avi_iframe_lut[8][mode];
+	/* Data Byte 10: LSB Pixel Number of End of Left Bar */
+	avi_iframe[12] = hdmi_tx_avi_iframe_lut[9][mode];
+	/* Data Byte 11: MSB Pixel Number of End of Left Bar */
+	avi_iframe[13] = hdmi_tx_avi_iframe_lut[10][mode];
+	/* Data Byte 12: LSB Pixel Number of Start of Right Bar */
+	avi_iframe[14] = hdmi_tx_avi_iframe_lut[11][mode];
+	/* Data Byte 13: MSB Pixel Number of Start of Right Bar */
+	avi_iframe[15] = hdmi_tx_avi_iframe_lut[12][mode];
+
+	sum = 0;
+	for (i = 0; i < 16; i++)
+		sum += avi_iframe[i];
+	sum &= 0xFF;
+	sum = 256 - sum;
+	checksum = (u8) sum;
+
+	regVal = avi_iframe[5];
+	regVal = regVal << 8 | avi_iframe[4];
+	regVal = regVal << 8 | avi_iframe[3];
+	regVal = regVal << 8 | checksum;
+	HDMI_REG_W(io->base, HDMI_AVI_INFO0, regVal);
+
+	regVal = avi_iframe[9];
+	regVal = regVal << 8 | avi_iframe[8];
+	regVal = regVal << 8 | avi_iframe[7];
+	regVal = regVal << 8 | avi_iframe[6];
+	HDMI_REG_W(io->base, HDMI_AVI_INFO1, regVal);
+
+	regVal = avi_iframe[13];
+	regVal = regVal << 8 | avi_iframe[12];
+	regVal = regVal << 8 | avi_iframe[11];
+	regVal = regVal << 8 | avi_iframe[10];
+	HDMI_REG_W(io->base, HDMI_AVI_INFO2, regVal);
+
+	regVal = avi_iframe[1];
+	regVal = regVal << 16 | avi_iframe[15];
+	regVal = regVal << 8 | avi_iframe[14];
+	HDMI_REG_W(io->base, HDMI_AVI_INFO3, regVal);
+
+	/* 0x3 for AVI InfFrame enable (every frame) */
+	HDMI_REG_W(io->base, HDMI_INFOFRAME_CTRL0,
+		HDMI_REG_R(io->base, HDMI_INFOFRAME_CTRL0) |
+		0x00000003L);
+} /* hdmi_tx_set_avi_infoframe */
+
+static void hdmi_tx_set_spd_infoframe(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+	u32 packet_header  = 0;
+	u32 check_sum      = 0;
+	u32 packet_payload = 0;
+	u32 packet_control = 0;
+
+	u8 *vendor_name = NULL;
+	u8 *product_description = NULL;
+	struct dss_io_data *io = NULL;
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+
+	io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
+	if (!io->base) {
+		DEV_ERR("%s: Core io is not initialized\n", __func__);
+		return;
+	}
+
+	vendor_name = hdmi_ctrl->spd_vendor_name;
+	product_description = hdmi_ctrl->spd_product_description;
+
+	/* Setup Packet header and payload */
+	/*
+	 * 0x83 InfoFrame Type Code
+	 * 0x01 InfoFrame Version Number
+	 * 0x19 Length of Source Product Description InfoFrame
+	 */
+	packet_header  = 0x83 | (0x01 << 8) | (0x19 << 16);
+	HDMI_REG_W(io->base, HDMI_GENERIC1_HDR, packet_header);
+	check_sum += IFRAME_CHECKSUM_32(packet_header);
+
+	packet_payload = (vendor_name[3] & 0x7f)
+		| ((vendor_name[4] & 0x7f) << 8)
+		| ((vendor_name[5] & 0x7f) << 16)
+		| ((vendor_name[6] & 0x7f) << 24);
+	HDMI_REG_W(io->base, HDMI_GENERIC1_1, packet_payload);
+	check_sum += IFRAME_CHECKSUM_32(packet_payload);
+
+	/* Product Description (7-bit ASCII code) */
+	packet_payload = (vendor_name[7] & 0x7f)
+		| ((product_description[0] & 0x7f) << 8)
+		| ((product_description[1] & 0x7f) << 16)
+		| ((product_description[2] & 0x7f) << 24);
+	HDMI_REG_W(io->base, HDMI_GENERIC1_2, packet_payload);
+	check_sum += IFRAME_CHECKSUM_32(packet_payload);
+
+	packet_payload = (product_description[3] & 0x7f)
+		| ((product_description[4] & 0x7f) << 8)
+		| ((product_description[5] & 0x7f) << 16)
+		| ((product_description[6] & 0x7f) << 24);
+	HDMI_REG_W(io->base, HDMI_GENERIC1_3, packet_payload);
+	check_sum += IFRAME_CHECKSUM_32(packet_payload);
+
+	packet_payload = (product_description[7] & 0x7f)
+		| ((product_description[8] & 0x7f) << 8)
+		| ((product_description[9] & 0x7f) << 16)
+		| ((product_description[10] & 0x7f) << 24);
+	HDMI_REG_W(io->base, HDMI_GENERIC1_4, packet_payload);
+	check_sum += IFRAME_CHECKSUM_32(packet_payload);
+
+	packet_payload = (product_description[11] & 0x7f)
+		| ((product_description[12] & 0x7f) << 8)
+		| ((product_description[13] & 0x7f) << 16)
+		| ((product_description[14] & 0x7f) << 24);
+	HDMI_REG_W(io->base, HDMI_GENERIC1_5, packet_payload);
+	check_sum += IFRAME_CHECKSUM_32(packet_payload);
+
+	/*
+	 * Source Device Information
+	 * 00h unknown
+	 * 01h Digital STB
+	 * 02h DVD
+	 * 03h D-VHS
+	 * 04h HDD Video
+	 * 05h DVC
+	 * 06h DSC
+	 * 07h Video CD
+	 * 08h Game
+	 * 09h PC general
+	 */
+	packet_payload = (product_description[15] & 0x7f) | 0x00 << 8;
+	HDMI_REG_W(io->base, HDMI_GENERIC1_6, packet_payload);
+	check_sum += IFRAME_CHECKSUM_32(packet_payload);
+
+	/* Vendor Name (7bit ASCII code) */
+	packet_payload = ((vendor_name[0] & 0x7f) << 8)
+		| ((vendor_name[1] & 0x7f) << 16)
+		| ((vendor_name[2] & 0x7f) << 24);
+	check_sum += IFRAME_CHECKSUM_32(packet_payload);
+	packet_payload |= ((0x100 - (0xff & check_sum)) & 0xff);
+	HDMI_REG_W(io->base, HDMI_GENERIC1_0, packet_payload);
+
+	/*
+	 * GENERIC1_LINE | GENERIC1_CONT | GENERIC1_SEND
+	 * Setup HDMI TX generic packet control
+	 * Enable this packet to transmit every frame
+	 * Enable HDMI TX engine to transmit Generic packet 1
+	 */
+	packet_control = HDMI_REG_R_ND(io->base, HDMI_GEN_PKT_CTRL);
+	packet_control |= ((0x1 << 24) | (1 << 5) | (1 << 4));
+	HDMI_REG_W(io->base, HDMI_GEN_PKT_CTRL, packet_control);
+} /* hdmi_tx_set_spd_infoframe */
+
+/* todo: revisit when new HPD debouncing logic is avialble */
+static void hdmi_tx_hpd_state_timer(unsigned long data)
+{
+	struct hdmi_tx_ctrl *hdmi_ctrl = (struct hdmi_tx_ctrl *)data;
+
+	if (hdmi_ctrl)
+		queue_work(hdmi_ctrl->workq, &hdmi_ctrl->hpd_state_work);
+	else
+		DEV_ERR("%s: invalid input\n", __func__);
+} /* hdmi_tx_hpd_state_timer */
+
+static void hdmi_tx_set_mode(struct hdmi_tx_ctrl *hdmi_ctrl, u32 power_on)
+{
+	u32 reg_val = 0;
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+
+	if (power_on) {
+		/* ENABLE */
+		reg_val |= BIT(0); /* Enable the block */
+		if (hdmi_edid_get_sink_mode(
+			hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID]) == 0) {
+			if (hdmi_ctrl->present_hdcp)
+				/* HDMI Encryption */
+				reg_val |= BIT(2);
+			reg_val |= BIT(1);
+		} else {
+			if (hdmi_ctrl->present_hdcp)
+				/* HDMI_Encryption_ON */
+				reg_val |= BIT(1) | BIT(2);
+			else
+				reg_val |= BIT(1);
+		}
+	} else {
+		reg_val = BIT(1);
+	}
+
+	HDMI_REG_W(hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO].base, HDMI_CTRL,
+		reg_val);
+
+	DEV_DBG("HDMI Core: %s, HDMI_CTRL=0x%08x\n",
+		power_on ? "Enable" : "Disable", reg_val);
+} /* hdmi_tx_set_mode */
+
+static int hdmi_tx_clk_update(struct hdmi_tx_platform_data *pdata, u32 clk_idx,
+	u32 enable)
+{
+	int rc = 0;
+	struct clk *clk = hdmi_tx_get_clk(pdata, clk_idx);
+
+	if (clk) {
+		DEV_DBG("%s: clk=%d en=%d\n", __func__, clk_idx, enable);
+		if (enable) {
+			rc = clk_prepare_enable(clk);
+			if (rc)
+				DEV_ERR("%s: clk=%d enable failed\n",
+				__func__, clk_idx);
+		} else {
+			clk_disable_unprepare(clk);
+		}
+	} else {
+		DEV_ERR("%s: FAILED: invalid input for clk='%s'\n", __func__,
+			hdmi_tx_clk_name(clk_idx));
+		rc = -EINVAL;
+	}
+
+	return rc;
+} /* hdmi_tx_clk_update */
+
+/* Note: Before accessing extpclk, always make sure that hdmi_ahb_clk is on */
+static int hdmi_tx_clk_ctrl_update(struct hdmi_tx_platform_data *pdata, int on)
+{
+	int  rc = 0;
+	DEV_DBG("%s: HDMI Clk: %s\n", __func__, on ? "Enable" : "Disable");
+
+	rc = hdmi_tx_clk_update(pdata, HDMI_TX_APP_CLK, on);
+	if (on && rc) {
+		DEV_ERR("%s: '%s' on failed\n", __func__,
+			hdmi_tx_clk_name(HDMI_TX_APP_CLK));
+		goto fail_hdmi_app_clk;
+	}
+	if (on) {
+		rc = hdmi_tx_clk_update(pdata, HDMI_TX_AHB_CLK, on);
+		if (rc) {
+			DEV_ERR("%s: '%s' on failed\n", __func__,
+				hdmi_tx_clk_name(HDMI_TX_AHB_CLK));
+			goto fail_hdmi_ahb_clk;
+		}
+		rc = hdmi_tx_clk_update(pdata, HDMI_TX_EXTP_CLK, on);
+		if (rc) {
+			DEV_ERR("%s: '%s' on failed\n", __func__,
+				hdmi_tx_clk_name(HDMI_TX_EXTP_CLK));
+			goto fail_hdmi_extp_clk;
+		}
+	} else {
+		hdmi_tx_clk_update(pdata, HDMI_TX_EXTP_CLK, on);
+		hdmi_tx_clk_update(pdata, HDMI_TX_AHB_CLK, on);
+	}
+	return rc;
+
+fail_hdmi_extp_clk:
+	hdmi_tx_clk_update(pdata, HDMI_TX_AHB_CLK, 0);
+fail_hdmi_ahb_clk:
+	hdmi_tx_clk_update(pdata, HDMI_TX_APP_CLK, 0);
+fail_hdmi_app_clk:
+	return rc;
+} /* hdmi_tx_clk_ctrl_update */
+
+static int hdmi_tx_enable_power(struct hdmi_tx_ctrl *hdmi_ctrl,
+	enum hdmi_tx_power_module_type module, int enable)
+{
+	int rc = 0;
+	struct dss_module_power *power_data = NULL;
+
+	if (!hdmi_ctrl || module >= HDMI_TX_MAX_PM) {
+		DEV_ERR("%s: Error: invalid input\n", __func__);
+		rc = -EINVAL;
+		goto error;
+	}
+
+	power_data = &hdmi_ctrl->pdata.power_data[module];
+	if (!power_data) {
+		DEV_ERR("%s: Error: invalid power data\n", __func__);
+		rc = -EINVAL;
+		goto error;
+	}
+
+	if (enable) {
+		rc = msm_dss_config_vreg(&hdmi_ctrl->pdev->dev,
+			power_data->vreg_config, power_data->num_vreg, 1);
+		if (rc) {
+			DEV_ERR("%s: Failed to config %s vreg. Error=%d\n",
+				__func__, hdmi_pm_name(module), rc);
+			return rc;
+		}
+
+		rc = msm_dss_enable_vreg(power_data->vreg_config,
+			power_data->num_vreg, 1);
+		if (rc) {
+			DEV_ERR("%s: Failed to enable %s vreg. Error=%d\n",
+				__func__, hdmi_pm_name(module), rc);
+			goto deconfig_vreg;
+		}
+
+		rc = msm_dss_enable_gpio(power_data->gpio_config,
+			power_data->num_gpio, enable);
+		if (rc) {
+			DEV_ERR("%s: Failed to enable %s gpio. Error=%d\n",
+				__func__, hdmi_pm_name(module), rc);
+			goto disable_vreg;
+		}
+	} else {
+		msm_dss_enable_gpio(power_data->gpio_config,
+			power_data->num_gpio, 0);
+	}
+
+	return rc;
+
+disable_vreg:
+	msm_dss_enable_vreg(power_data->vreg_config, power_data->num_vreg, 0);
+deconfig_vreg:
+	msm_dss_config_vreg(&hdmi_ctrl->pdev->dev, power_data->vreg_config,
+		power_data->num_vreg, 0);
+error:
+	return rc;
+} /* hdmi_tx_enable_power */
+
+static void hdmi_tx_core_off(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+
+	hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_CEC_PM, 0);
+	hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_CORE_PM, 0);
+} /* hdmi_tx_core_off */
+
+static int hdmi_tx_core_on(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+	int rc = 0;
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	rc = hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_CORE_PM, 1);
+	if (rc) {
+		DEV_ERR("%s: core hdmi_msm_enable_power failed rc = %d\n",
+			__func__, rc);
+		goto error;
+	}
+	rc = hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_CEC_PM, 1);
+	if (rc) {
+		DEV_ERR("%s: cec hdmi_msm_enable_power failed rc = %d\n",
+			__func__, rc);
+		goto disable_core_power;
+	}
+
+	return rc;
+disable_core_power:
+	hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_CORE_PM, 0);
+error:
+	return rc;
+} /* hdmi_tx_core_on */
+
+static void hdmi_tx_phy_reset(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+	unsigned int phy_reset_polarity = 0x0;
+	unsigned int pll_reset_polarity = 0x0;
+	unsigned int val;
+	struct dss_io_data *io = NULL;
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+
+	io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
+	if (!io->base) {
+		DEV_ERR("%s: io not inititalized\n", __func__);
+		return;
+	}
+
+	val = HDMI_REG_R_ND(io->base, HDMI_PHY_CTRL);
+
+	phy_reset_polarity = val >> 3 & 0x1;
+	pll_reset_polarity = val >> 1 & 0x1;
+
+	if (phy_reset_polarity == 0)
+		HDMI_REG_W_ND(io->base, HDMI_PHY_CTRL, val | SW_RESET);
+	else
+		HDMI_REG_W_ND(io->base, HDMI_PHY_CTRL, val & (~SW_RESET));
+
+	if (pll_reset_polarity == 0)
+		HDMI_REG_W_ND(io->base, HDMI_PHY_CTRL, val | SW_RESET_PLL);
+	else
+		HDMI_REG_W_ND(io->base,
+			HDMI_PHY_CTRL, val & (~SW_RESET_PLL));
+
+	if (phy_reset_polarity == 0)
+		HDMI_REG_W_ND(io->base, HDMI_PHY_CTRL, val & (~SW_RESET));
+	else
+		HDMI_REG_W_ND(io->base, HDMI_PHY_CTRL, val | SW_RESET);
+
+	if (pll_reset_polarity == 0)
+		HDMI_REG_W_ND(io->base,
+			HDMI_PHY_CTRL, val & (~SW_RESET_PLL));
+	else
+		HDMI_REG_W_ND(io->base, HDMI_PHY_CTRL, val | SW_RESET_PLL);
+} /* hdmi_tx_phy_reset */
+
+static void hdmi_tx_init_phy(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+	struct dss_io_data *io = NULL;
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+
+	io = &hdmi_ctrl->pdata.io[HDMI_TX_PHY_IO];
+	if (!io->base) {
+		DEV_ERR("%s: Core io is not initialized\n", __func__);
+		return;
+	}
+
+	HDMI_REG_W_ND(io->base, HDMI_PHY_ANA_CFG0, 0x1B);
+	HDMI_REG_W_ND(io->base, HDMI_PHY_ANA_CFG1, 0xF2);
+	HDMI_REG_W_ND(io->base, HDMI_PHY_BIST_CFG0, 0x0);
+	HDMI_REG_W_ND(io->base, HDMI_PHY_BIST_PATN0, 0x0);
+	HDMI_REG_W_ND(io->base, HDMI_PHY_BIST_PATN1, 0x0);
+	HDMI_REG_W_ND(io->base, HDMI_PHY_BIST_PATN2, 0x0);
+	HDMI_REG_W_ND(io->base, HDMI_PHY_BIST_PATN3, 0x0);
+
+	HDMI_REG_W_ND(io->base, HDMI_PHY_PD_CTRL1, 0x20);
+} /* hdmi_tx_init_phy */
+
+static void hdmi_tx_powerdown_phy(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+
+	HDMI_REG_W_ND(hdmi_ctrl->pdata.io[HDMI_TX_PHY_IO].base,
+		HDMI_PHY_PD_CTRL0, 0x7F);
+} /* hdmi_tx_powerdown_phy */
+
+static int hdmi_tx_start(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+	int rc = 0;
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+	/* todo: Audio */
+
+	hdmi_tx_set_mode(hdmi_ctrl, false);
+	mutex_lock(&hdmi_ctrl->mutex);
+	rc = hdmi_tx_clk_ctrl_update(&hdmi_ctrl->pdata, 1);
+	if (rc) {
+		DEV_ERR("%s: hdmi_tx_clk_enable failed.\n", __func__);
+		mutex_unlock(&hdmi_ctrl->mutex);
+		return rc;
+	}
+	mutex_unlock(&hdmi_ctrl->mutex);
+
+	hdmi_tx_init_phy(hdmi_ctrl);
+	HDMI_REG_W(hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO].base,
+		HDMI_USEC_REFTIMER, 0x0001001B);
+
+	hdmi_tx_set_mode(hdmi_ctrl, true);
+
+	hdmi_tx_video_setup(hdmi_ctrl, hdmi_ctrl->video_resolution);
+	/* todo: Audio */
+	hdmi_tx_set_avi_infoframe(hdmi_ctrl);
+	/* todo: CONFIG_FB_MSM_HDMI_3D */
+	hdmi_tx_set_spd_infoframe(hdmi_ctrl);
+
+	/* Set IRQ for HPD */
+	HDMI_REG_W(hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO].base,
+		HDMI_HPD_INT_CTRL, 4 | (hdmi_ctrl->hpd_state ? 0 : 2));
+
+	/* todo: HDCP/CEC */
+
+	DEV_INFO("%s: HDMI Core: Initialized\n", __func__);
+
+	return rc;
+} /* hdmi_tx_start */
+
+static int hdmi_tx_power_off(struct mdss_panel_data *panel_data)
+{
+	struct hdmi_tx_ctrl *hdmi_ctrl =
+		hdmi_tx_get_drvdata_from_panel_data(panel_data);
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	DEV_INFO("%s: power: OFF (audio off, Reset Core)\n", __func__);
+	/* todo: Audio */
+	hdmi_tx_powerdown_phy(hdmi_ctrl);
+	hdmi_ctrl->panel_power_on = false;
+
+	mutex_lock(&hdmi_ctrl->mutex);
+	if (hdmi_tx_clk_ctrl_update(&hdmi_ctrl->pdata, 0))
+		DEV_ERR("%s: hdmi_tx_clk_disable failed.\n", __func__);
+	mutex_unlock(&hdmi_ctrl->mutex);
+
+	hdmi_tx_core_off(hdmi_ctrl);
+
+	return 0;
+} /* hdmi_tx_power_off */
+
+static int hdmi_tx_power_on(struct mdss_panel_data *panel_data)
+{
+	int rc = 0;
+	struct hdmi_tx_ctrl *hdmi_ctrl =
+		hdmi_tx_get_drvdata_from_panel_data(panel_data);
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	rc = hdmi_tx_core_on(hdmi_ctrl);
+	if (rc) {
+		DEV_ERR("%s: hdmi_msm_core_on failed\n", __func__);
+		return rc;
+	}
+
+	DEV_INFO("power: ON (%dx%d %ld)\n", hdmi_ctrl->xres, hdmi_ctrl->yres,
+		hdmi_ctrl->pixel_clk);
+
+	rc = hdmi_tx_set_video_fmt(hdmi_ctrl);
+	if (rc) {
+		DEV_ERR("%s: cannot set video_fmt.rc=%d\n", __func__, rc);
+		hdmi_tx_core_off(hdmi_ctrl);
+		return rc;
+	}
+
+	mutex_lock(&hdmi_ctrl->mutex);
+	hdmi_ctrl->panel_power_on = true;
+
+	/* todo: check hdmi_tx_is_controller_on when hpd is on */
+	if (hdmi_ctrl->hpd_state) {
+		DEV_DBG("%s: Turning HDMI on\n", __func__);
+		mutex_unlock(&hdmi_ctrl->mutex);
+		rc = hdmi_tx_start(hdmi_ctrl);
+		if (rc) {
+			DEV_ERR("%s: hdmi_tx_start failed. rc=%d\n",
+				__func__, rc);
+			hdmi_tx_power_off(panel_data);
+			return rc;
+		}
+		/* todo: HDCP */
+	} else {
+		mutex_unlock(&hdmi_ctrl->mutex);
+	}
+
+	hdmi_reg_dump(hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO].base,
+		hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO].len, "HDMI-ON: ");
+
+	DEV_INFO("%s: HDMI=%s DVI= %s\n", __func__,
+		hdmi_tx_is_controller_on(hdmi_ctrl) ? "ON" : "OFF" ,
+		hdmi_tx_is_dvi_mode(hdmi_ctrl) ? "ON" : "OFF");
+
+	return 0;
+} /* hdmi_tx_power_on */
+
+static void hdmi_tx_hpd_off(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+	int rc = 0;
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+
+	if (!hdmi_ctrl->hpd_initialized) {
+		DEV_DBG("%s: HPD is already OFF, returning\n", __func__);
+		return;
+	}
+
+	DEV_DBG("%s: (timer, 5V, IRQ off)\n", __func__);
+	del_timer_sync(&hdmi_ctrl->hpd_state_timer);
+	mdss_disable_irq(&hdmi_tx_hw);
+
+	hdmi_tx_set_mode(hdmi_ctrl, false);
+
+	mutex_lock(&hdmi_ctrl->mutex);
+	rc = hdmi_tx_clk_ctrl_update(&hdmi_ctrl->pdata, 0);
+	if (rc)
+		DEV_INFO("%s: Failed to disable clock. Error=%d\n",
+			__func__, rc);
+	mutex_unlock(&hdmi_ctrl->mutex);
+
+	rc = hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_HPD_PM, 0);
+	if (rc)
+		DEV_INFO("%s: Failed to disable hpd power. Error=%d\n",
+			__func__, rc);
+
+	hdmi_ctrl->hpd_initialized = false;
+} /* hdmi_tx_hpd_off */
+
+static int hdmi_tx_hpd_on(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+	u32 reg_val;
+	int rc = 0;
+	struct dss_io_data *io = NULL;
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
+	if (!io->base) {
+		DEV_ERR("%s: io not inititalized\n", __func__);
+		return -EINVAL;
+	}
+
+	if (hdmi_ctrl->hpd_initialized) {
+		DEV_DBG("%s: HPD is already ON\n", __func__);
+	} else {
+		rc = hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_HPD_PM, true);
+		if (rc) {
+			DEV_ERR("%s: Failed to enable hpd power. rc=%d\n",
+				__func__, rc);
+			return rc;
+		}
+
+		mutex_lock(&hdmi_ctrl->mutex);
+		rc = hdmi_tx_clk_ctrl_update(&hdmi_ctrl->pdata, true);
+		if (rc) {
+			DEV_ERR("%s: Failed to enable clocks. rc=%d\n",
+				__func__, rc);
+			mutex_unlock(&hdmi_ctrl->mutex);
+			goto disable_hpd_power;
+		}
+		mutex_unlock(&hdmi_ctrl->mutex);
+
+		hdmi_reg_dump(io->base, io->len, "HDMI-INIT: ");
+
+		hdmi_tx_set_mode(hdmi_ctrl, false);
+		hdmi_tx_phy_reset(hdmi_ctrl);
+		hdmi_tx_set_mode(hdmi_ctrl, true);
+
+		HDMI_REG_W(io->base, HDMI_USEC_REFTIMER, 0x0001001B);
+
+		/* set timeout to 4.1ms (max) for hardware debounce */
+		reg_val = HDMI_REG_R(io->base, HDMI_HPD_CTRL) | 0x1FFF;
+
+		/* Toggle HPD circuit to trigger HPD sense */
+		HDMI_REG_W(io->base, HDMI_HPD_CTRL,
+			~(1 << 28) & reg_val);
+		HDMI_REG_W(io->base, HDMI_HPD_CTRL, (1 << 28) | reg_val);
+
+		hdmi_ctrl->hpd_initialized = true;
+
+		/* Check HPD State */
+		mdss_enable_irq(&hdmi_tx_hw);
+	}
+
+	/* Set HPD state machine: ensure at least 2 readouts */
+	mutex_lock(&hdmi_ctrl->mutex);
+	hdmi_ctrl->hpd_stable = 0;
+	hdmi_ctrl->hpd_prev_state = true;
+	hdmi_ctrl->hpd_state = false;
+	hdmi_ctrl->hpd_cable_chg_detected = true;
+	mutex_unlock(&hdmi_ctrl->mutex);
+	mod_timer(&hdmi_ctrl->hpd_state_timer, jiffies + HZ/2);
+
+	return 0;
+
+disable_hpd_power:
+	hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_HPD_PM, false);
+
+	return rc;
+} /* hdmi_tx_hpd_on */
+
+static int hdmi_tx_sysfs_enable_hpd(struct hdmi_tx_ctrl *hdmi_ctrl, int on)
+{
+	int rc = 0;
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	DEV_INFO("%s: %d\n", __func__, on);
+	if (on) {
+		rc = hdmi_tx_hpd_on(hdmi_ctrl);
+	} else {
+		hdmi_tx_hpd_off(hdmi_ctrl);
+		/* Set HDMI switch node to 0 on HPD feature disable */
+		switch_set_state(&hdmi_ctrl->sdev, 0);
+		DEV_INFO("%s: Hdmi state switch to %d\n", __func__,
+			hdmi_ctrl->sdev.state);
+	}
+
+	return rc;
+} /* hdmi_tx_sysfs_enable_hpd */
+
+static irqreturn_t hdmi_tx_isr(int irq, void *data)
+{
+	u32 hpd_int_status;
+	u32 hpd_int_ctrl;
+	struct dss_io_data *io = NULL;
+	struct hdmi_tx_ctrl *hdmi_ctrl = (struct hdmi_tx_ctrl *)data;
+
+	if (!hdmi_ctrl || !hdmi_ctrl->hpd_initialized) {
+		DEV_WARN("%s: invalid input data, ISR ignored\n", __func__);
+		return IRQ_HANDLED;
+	}
+
+	io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
+	if (!io->base) {
+		DEV_WARN("%s: io not initialized, ISR ignored\n", __func__);
+		return IRQ_HANDLED;
+	}
+
+	/* Process HPD Interrupt */
+	hpd_int_status = HDMI_REG_R(io->base, HDMI_HPD_INT_STATUS);
+	hpd_int_ctrl = HDMI_REG_R(io->base, HDMI_HPD_INT_CTRL);
+	if ((hpd_int_ctrl & BIT(2)) && (hpd_int_status & BIT(0))) {
+		u32 cable_detected = hpd_int_status & BIT(1);
+
+		/*
+		 * Clear all interrupts, timer will turn IRQ back on
+		 * Leaving the bit[2] on, else core goes off
+		 * on getting HPD during power off.
+		 */
+		HDMI_REG_W(io->base, HDMI_HPD_INT_CTRL, BIT(2) | BIT(0));
+
+		DEV_DBG("%s: HPD IRQ, Ctrl=%04x, State=%04x\n", __func__,
+			hpd_int_ctrl, hpd_int_status);
+
+		mutex_lock(&hdmi_ctrl->mutex);
+		hdmi_ctrl->hpd_cable_chg_detected = true;
+		hdmi_ctrl->hpd_prev_state = cable_detected ? 0 : 1;
+		hdmi_ctrl->hpd_stable = 0;
+		mutex_unlock(&hdmi_ctrl->mutex);
+
+		mod_timer(&hdmi_ctrl->hpd_state_timer, jiffies + HZ/2);
+
+		return IRQ_HANDLED;
+	}
+
+	if (!hdmi_ddc_isr(&hdmi_ctrl->ddc_ctrl))
+		return IRQ_HANDLED;
+
+	DEV_DBG("%s: HPD<Ctrl=%04x, State=%04x>\n", __func__, hpd_int_ctrl,
+		hpd_int_status);
+
+	return IRQ_HANDLED;
+} /* hdmi_tx_isr */
+
+static void hdmi_tx_clk_deinit(struct hdmi_tx_platform_data *pdata)
+{
+	int i;
+	if (!pdata) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+
+	for (i = HDMI_TX_MAX_CLK - 1; i >= 0; i--) {
+		if (pdata->clk[i])
+			clk_put(pdata->clk[i]);
+		pdata->clk[i] = NULL;
+	}
+} /* hdmi_tx_clk_deinit */
+
+static int hdmi_tx_clk_init(struct platform_device *pdev,
+	struct hdmi_tx_platform_data *pdata)
+{
+	int rc = 0;
+	struct device *dev = NULL;
+	struct clk *clk = NULL;
+
+	if (!pdev || !pdata) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+	dev = &pdev->dev;
+
+	clk = clk_get(dev, "iface_clk");
+	rc = IS_ERR(clk);
+	if (rc) {
+		DEV_ERR("%s: ERROR: '%s' clk not found\n", __func__,
+			hdmi_tx_clk_name(HDMI_TX_AHB_CLK));
+		goto error;
+	}
+	pdata->clk[HDMI_TX_AHB_CLK] = clk;
+
+	clk = clk_get(dev, "core_clk");
+	rc = IS_ERR(clk);
+	if (rc) {
+		DEV_ERR("%s: ERROR: '%s' clk not found\n", __func__,
+			hdmi_tx_clk_name(HDMI_TX_APP_CLK));
+		goto error;
+	}
+	pdata->clk[HDMI_TX_APP_CLK] = clk;
+
+	clk = clk_get(dev, "extp_clk");
+	rc = IS_ERR(clk);
+	if (rc) {
+		DEV_ERR("%s: ERROR: '%s' clk not found\n", __func__,
+			hdmi_tx_clk_name(HDMI_TX_EXTP_CLK));
+		goto error;
+	}
+	pdata->clk[HDMI_TX_EXTP_CLK] = clk;
+
+	return rc;
+
+error:
+	hdmi_tx_clk_deinit(pdata);
+	return rc;
+} /* hdmi_tx_clk_init */
+
+static void hdmi_tx_dev_deinit(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+
+	if (hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID])
+		hdmi_edid_deinit(hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID]);
+
+	switch_dev_unregister(&hdmi_ctrl->sdev);
+	del_timer_sync(&hdmi_ctrl->hpd_state_timer);
+	if (hdmi_ctrl->workq)
+		destroy_workqueue(hdmi_ctrl->workq);
+	mutex_destroy(&hdmi_ctrl->mutex);
+
+	hdmi_tx_hw.ptr = NULL;
+} /* hdmi_tx_dev_deinit */
+
+static int hdmi_tx_dev_init(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+	int rc = 0;
+	struct hdmi_tx_platform_data *pdata = NULL;
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	pdata = &hdmi_ctrl->pdata;
+
+	rc = hdmi_tx_check_capability(pdata->io[HDMI_TX_QFPROM_IO].base);
+	if (rc) {
+		DEV_ERR("%s: no HDMI device\n", __func__);
+		goto fail_no_hdmi;
+	}
+
+	/* irq enable/disable will be handled in hpd on/off */
+	hdmi_tx_hw.ptr = (void *)hdmi_ctrl;
+
+	hdmi_tx_setup_video_mode_lut();
+	mutex_init(&hdmi_ctrl->mutex);
+	hdmi_ctrl->workq = create_workqueue("hdmi_tx_workq");
+	if (!hdmi_ctrl->workq) {
+		DEV_ERR("%s: hdmi_tx_workq creation failed.\n", __func__);
+		goto fail_create_workq;
+	}
+
+	/* todo: May be move this ? */
+	hdmi_ctrl->ddc_ctrl.base = pdata->io[HDMI_TX_CORE_IO].base;
+	init_completion(&hdmi_ctrl->ddc_ctrl.ddc_sw_done);
+
+	INIT_WORK(&hdmi_ctrl->hpd_state_work, hdmi_tx_hpd_state_work);
+	init_timer(&hdmi_ctrl->hpd_state_timer);
+	hdmi_ctrl->hpd_state_timer.function = hdmi_tx_hpd_state_timer;
+	hdmi_ctrl->hpd_state_timer.data = (u32)hdmi_ctrl;
+	hdmi_ctrl->hpd_state_timer.expires = 0xffffffffL;
+
+	hdmi_ctrl->sdev.name = "hdmi";
+	if (switch_dev_register(&hdmi_ctrl->sdev) < 0) {
+		DEV_ERR("%s: Hdmi switch registration failed\n", __func__);
+		goto fail_switch_dev;
+	}
+
+	return 0;
+
+fail_switch_dev:
+	del_timer_sync(&hdmi_ctrl->hpd_state_timer);
+fail_create_workq:
+	if (hdmi_ctrl->workq)
+		destroy_workqueue(hdmi_ctrl->workq);
+	mutex_destroy(&hdmi_ctrl->mutex);
+fail_no_hdmi:
+	return rc;
+} /* hdmi_tx_dev_init */
+
+static int hdmi_tx_register_panel(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+	int rc = 0;
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	hdmi_ctrl->panel_data.on = hdmi_tx_power_on;
+	hdmi_ctrl->panel_data.off = hdmi_tx_power_off;
+
+	hdmi_ctrl->video_resolution = DEFAULT_VIDEO_RESOLUTION;
+	rc = hdmi_tx_init_panel_info(hdmi_ctrl->video_resolution,
+		&hdmi_ctrl->panel_data.panel_info);
+	if (rc) {
+		DEV_ERR("%s: hdmi_init_panel_info failed\n", __func__);
+		return rc;
+	}
+
+	rc = mdss_register_panel(&hdmi_ctrl->panel_data);
+	if (rc) {
+		DEV_ERR("%s: FAILED: to register HDMI panel\n", __func__);
+		return rc;
+	}
+
+	return rc;
+} /* hdmi_tx_register_panel */
+
+static void hdmi_tx_put_dt_vreg_data(struct device *dev,
+	struct dss_module_power *module_power)
+{
+	if (!module_power) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+
+	if (module_power->vreg_config) {
+		devm_kfree(dev, module_power->vreg_config);
+		module_power->vreg_config = NULL;
+	}
+	module_power->num_vreg = 0;
+} /* hdmi_tx_put_dt_vreg_data */
+
+static int hdmi_tx_get_dt_vreg_data(struct device *dev,
+	struct dss_module_power *mp, u32 module_type)
+{
+	int i, j, rc = 0;
+	int dt_vreg_total = 0, mod_vreg_total = 0;
+	u32 ndx_mask = 0;
+	u32 *val_array = NULL;
+	const char *mod_name = NULL;
+	struct device_node *of_node = NULL;
+	char prop_name[32];
+
+	if (!dev || !mp) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		rc = -EINVAL;
+		goto error;
+	}
+
+	switch (module_type) {
+	case HDMI_TX_HPD_PM:
+		mod_name = "hpd";
+		break;
+	case HDMI_TX_CORE_PM:
+		mod_name = "core";
+		break;
+	case HDMI_TX_CEC_PM:
+		mod_name = "cec";
+		break;
+	default:
+		DEV_ERR("%s: invalid module type=%d\n", __func__,
+			module_type);
+		return -EINVAL;
+	}
+
+	DEV_DBG("%s: module: '%s'\n", __func__, hdmi_pm_name(module_type));
+
+	of_node = dev->of_node;
+
+	memset(prop_name, 0, sizeof(prop_name));
+	snprintf(prop_name, 32, "%s-%s", COMPATIBLE_NAME, "supply-names");
+	dt_vreg_total = of_property_count_strings(of_node, prop_name);
+	if (dt_vreg_total < 0) {
+		DEV_ERR("%s: vreg not found. rc=%d\n", __func__,
+			dt_vreg_total);
+		rc = dt_vreg_total;
+		goto error;
+	}
+
+	/* count how many vreg for particular hdmi module */
+	for (i = 0; i < dt_vreg_total; i++) {
+		const char *st = NULL;
+		memset(prop_name, 0, sizeof(prop_name));
+		snprintf(prop_name, 32, "%s-%s", COMPATIBLE_NAME,
+			"supply-names");
+		rc = of_property_read_string_index(of_node,
+			prop_name, i, &st);
+		if (rc) {
+			DEV_ERR("%s: error reading name. i=%d, rc=%d\n",
+				__func__, i, rc);
+			goto error;
+		}
+
+		if (strnstr(st, mod_name, strlen(st))) {
+			ndx_mask |= BIT(i);
+			mod_vreg_total++;
+		}
+	}
+
+	if (mod_vreg_total > 0) {
+		mp->num_vreg = mod_vreg_total;
+		mp->vreg_config = devm_kzalloc(dev, sizeof(struct dss_vreg) *
+			mod_vreg_total, GFP_KERNEL);
+		if (!mp->vreg_config) {
+			DEV_ERR("%s: can't alloc '%s' vreg mem\n", __func__,
+				hdmi_pm_name(module_type));
+			goto error;
+		}
+	} else {
+		DEV_DBG("%s: no vreg\n", __func__);
+		return 0;
+	}
+
+	val_array = devm_kzalloc(dev, sizeof(u32) * dt_vreg_total, GFP_KERNEL);
+	if (!val_array) {
+		DEV_ERR("%s: can't allocate vreg scratch mem\n", __func__);
+		rc = -ENOMEM;
+		goto error;
+	}
+
+	for (i = 0, j = 0; (i < dt_vreg_total) && (j < mod_vreg_total); i++) {
+		const char *st = NULL;
+
+		if (!(ndx_mask & BIT(0))) {
+			ndx_mask >>= 1;
+			continue;
+		}
+
+		/* vreg-name */
+		memset(prop_name, 0, sizeof(prop_name));
+		snprintf(prop_name, 32, "%s-%s", COMPATIBLE_NAME,
+			"supply-names");
+		rc = of_property_read_string_index(of_node,
+			prop_name, i, &st);
+		if (rc) {
+			DEV_ERR("%s: error reading name. i=%d, rc=%d\n",
+				__func__, i, rc);
+			goto error;
+		}
+		snprintf(mp->vreg_config[j].vreg_name, 32, "%s", st);
+
+		/* vreg-type */
+		memset(prop_name, 0, sizeof(prop_name));
+		snprintf(prop_name, 32, "%s-%s", COMPATIBLE_NAME,
+			"supply-type");
+		memset(val_array, 0, sizeof(u32) * dt_vreg_total);
+		rc = of_property_read_u32_array(of_node,
+			prop_name, val_array, dt_vreg_total);
+		if (rc) {
+			DEV_ERR("%s: error read '%s' vreg type. rc=%d\n",
+				__func__, hdmi_pm_name(module_type), rc);
+			goto error;
+		}
+		mp->vreg_config[j].type = val_array[i];
+
+		/* vreg-min-voltage */
+		memset(prop_name, 0, sizeof(prop_name));
+		snprintf(prop_name, 32, "%s-%s", COMPATIBLE_NAME,
+			"min-voltage-level");
+		memset(val_array, 0, sizeof(u32) * dt_vreg_total);
+		rc = of_property_read_u32_array(of_node,
+			prop_name, val_array,
+			dt_vreg_total);
+		if (rc) {
+			DEV_ERR("%s: error read '%s' min volt. rc=%d\n",
+				__func__, hdmi_pm_name(module_type), rc);
+			goto error;
+		}
+		mp->vreg_config[j].min_voltage = val_array[i];
+
+		/* vreg-max-voltage */
+		memset(prop_name, 0, sizeof(prop_name));
+		snprintf(prop_name, 32, "%s-%s", COMPATIBLE_NAME,
+			"max-voltage-level");
+		memset(val_array, 0, sizeof(u32) * dt_vreg_total);
+		rc = of_property_read_u32_array(of_node,
+			prop_name, val_array,
+			dt_vreg_total);
+		if (rc) {
+			DEV_ERR("%s: error read '%s' max volt. rc=%d\n",
+				__func__, hdmi_pm_name(module_type), rc);
+			goto error;
+		}
+		mp->vreg_config[j].max_voltage = val_array[i];
+
+		/* vreg-op-mode */
+		memset(prop_name, 0, sizeof(prop_name));
+		snprintf(prop_name, 32, "%s-%s", COMPATIBLE_NAME,
+			"op-mode");
+		memset(val_array, 0, sizeof(u32) * dt_vreg_total);
+		rc = of_property_read_u32_array(of_node,
+			prop_name, val_array,
+			dt_vreg_total);
+		if (rc) {
+			DEV_ERR("%s: error read '%s' min volt. rc=%d\n",
+				__func__, hdmi_pm_name(module_type), rc);
+			goto error;
+		}
+		mp->vreg_config[j].optimum_voltage = val_array[i];
+
+		DEV_DBG("%s: %s type=%d, min=%d, max=%d, op=%d\n",
+			__func__, mp->vreg_config[j].vreg_name,
+			mp->vreg_config[j].type,
+			mp->vreg_config[j].min_voltage,
+			mp->vreg_config[j].max_voltage,
+			mp->vreg_config[j].optimum_voltage);
+
+		ndx_mask >>= 1;
+		j++;
+	}
+
+	devm_kfree(dev, val_array);
+
+	return rc;
+
+error:
+	for (i = HDMI_TX_MAX_PM - 1; i >= 0; i--)
+		hdmi_tx_put_dt_vreg_data(dev, mp);
+	if (val_array)
+		devm_kfree(dev, val_array);
+	return rc;
+} /* hdmi_tx_get_dt_vreg_data */
+
+static void hdmi_tx_put_dt_gpio_data(struct device *dev,
+	struct dss_module_power *module_power)
+{
+	if (!module_power) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+
+	if (module_power->gpio_config) {
+		devm_kfree(dev, module_power->gpio_config);
+		module_power->gpio_config = NULL;
+	}
+	module_power->num_gpio = 0;
+} /* hdmi_tx_put_dt_gpio_data */
+
+static int hdmi_tx_get_dt_gpio_data(struct device *dev,
+	struct dss_module_power *mp, u32 module_type)
+{
+	int i, j, rc = 0;
+	int dt_gpio_total = 0, mod_gpio_total = 0;
+	u32 ndx_mask = 0;
+	const char *mod_name = NULL;
+	struct device_node *of_node = NULL;
+	char prop_name[32];
+	snprintf(prop_name, 32, "%s-%s", COMPATIBLE_NAME, "gpio-names");
+
+	if (!dev || !mp) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		rc = -EINVAL;
+		goto error;
+	}
+
+	switch (module_type) {
+	case HDMI_TX_HPD_PM:
+		mod_name = "hpd";
+		break;
+	case HDMI_TX_CORE_PM:
+		mod_name = "core";
+		break;
+	case HDMI_TX_CEC_PM:
+		mod_name = "cec";
+		break;
+	default:
+		DEV_ERR("%s: invalid module type=%d\n", __func__,
+			module_type);
+		return -EINVAL;
+	}
+
+	DEV_DBG("%s: module: '%s'\n", __func__, hdmi_pm_name(module_type));
+
+	of_node = dev->of_node;
+
+	dt_gpio_total = of_gpio_count(of_node);
+	if (dt_gpio_total < 0) {
+		DEV_ERR("%s: gpio not found. rc=%d\n", __func__,
+			dt_gpio_total);
+		rc = dt_gpio_total;
+		goto error;
+	}
+
+	/* count how many gpio for particular hdmi module */
+	for (i = 0; i < dt_gpio_total; i++) {
+		const char *st = NULL;
+
+		rc = of_property_read_string_index(of_node,
+			prop_name, i, &st);
+		if (rc) {
+			DEV_ERR("%s: error reading name. i=%d, rc=%d\n",
+				__func__, i, rc);
+			goto error;
+		}
+
+		if (strnstr(st, mod_name, strlen(st))) {
+			ndx_mask |= BIT(i);
+			mod_gpio_total++;
+		}
+	}
+
+	if (mod_gpio_total > 0) {
+		mp->num_gpio = mod_gpio_total;
+		mp->gpio_config = devm_kzalloc(dev, sizeof(struct dss_gpio) *
+			mod_gpio_total, GFP_KERNEL);
+		if (!mp->gpio_config) {
+			DEV_ERR("%s: can't alloc '%s' gpio mem\n", __func__,
+				hdmi_pm_name(module_type));
+			goto error;
+		}
+	} else {
+		DEV_DBG("%s: no gpio\n", __func__);
+		return 0;
+	}
+
+
+	for (i = 0, j = 0; (i < dt_gpio_total) && (j < mod_gpio_total); i++) {
+		const char *st = NULL;
+
+		if (!(ndx_mask & BIT(0))) {
+			ndx_mask >>= 1;
+			continue;
+		}
+
+		/* gpio-name */
+		rc = of_property_read_string_index(of_node,
+			prop_name, i, &st);
+		if (rc) {
+			DEV_ERR("%s: error reading name. i=%d, rc=%d\n",
+				__func__, i, rc);
+			goto error;
+		}
+		snprintf(mp->gpio_config[j].gpio_name, 32, "%s", st);
+
+		/* gpio-number */
+		mp->gpio_config[j].gpio = of_get_gpio(of_node, i);
+
+		DEV_DBG("%s: gpio num=%d, name=%s\n", __func__,
+			mp->gpio_config[j].gpio,
+			mp->gpio_config[j].gpio_name);
+
+		ndx_mask >>= 1;
+		j++;
+	}
+
+	return rc;
+
+error:
+	for (i = HDMI_TX_MAX_PM - 1; i >= 0; i--)
+		hdmi_tx_put_dt_gpio_data(dev, mp);
+
+	return rc;
+} /* hdmi_tx_get_dt_gpio_data */
+
+static void hdmi_tx_put_dt_data(struct device *dev,
+	struct hdmi_tx_platform_data *pdata)
+{
+	int i;
+	if (!dev || !pdata) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+
+	hdmi_tx_clk_deinit(pdata);
+
+	for (i = HDMI_TX_MAX_PM - 1; i >= 0; i--)
+		hdmi_tx_put_dt_vreg_data(dev, &pdata->power_data[i]);
+
+	for (i = HDMI_TX_MAX_PM - 1; i >= 0; i--)
+		hdmi_tx_put_dt_gpio_data(dev, &pdata->power_data[i]);
+
+	for (i = HDMI_TX_MAX_IO - 1; i >= 0; i--) {
+		if (pdata->io[i].base)
+			iounmap(pdata->io[i].base);
+		pdata->io[i].base = NULL;
+		pdata->io[i].len = 0;
+	}
+} /* hdmi_tx_put_dt_data */
+
+static int hdmi_tx_get_dt_data(struct platform_device *pdev,
+	struct hdmi_tx_platform_data *pdata)
+{
+	int i, rc = 0;
+	struct device_node *of_node = NULL;
+
+	if (!pdev || !pdata) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	of_node = pdev->dev.of_node;
+
+	rc = of_property_read_u32(of_node, "cell-index", &pdev->id);
+	if (rc) {
+		DEV_ERR("%s: dev id from dt not found.rc=%d\n",
+			__func__, rc);
+		goto error;
+	}
+	DEV_DBG("%s: id=%d\n", __func__, pdev->id);
+
+	/* IO */
+	for (i = 0; i < HDMI_TX_MAX_IO; i++) {
+		rc = msm_dss_ioremap_byname(pdev, &pdata->io[i],
+			hdmi_tx_io_name(i));
+		if (rc) {
+			DEV_ERR("%s: '%s' remap failed\n", __func__,
+				hdmi_tx_io_name(i));
+			goto error;
+		}
+		DEV_INFO("%s: '%s': start = 0x%x, len=0x%x\n", __func__,
+			hdmi_tx_io_name(i), (u32)pdata->io[i].base,
+			pdata->io[i].len);
+	}
+
+	/* GPIO */
+	for (i = 0; i < HDMI_TX_MAX_PM; i++) {
+		rc = hdmi_tx_get_dt_gpio_data(&pdev->dev,
+			&pdata->power_data[i], i);
+		if (rc) {
+			DEV_ERR("%s: '%s' get_dt_gpio_data failed.rc=%d\n",
+				__func__, hdmi_pm_name(i), rc);
+			goto error;
+		}
+	}
+
+	/* VREG */
+	for (i = 0; i < HDMI_TX_MAX_PM; i++) {
+		rc = hdmi_tx_get_dt_vreg_data(&pdev->dev,
+			&pdata->power_data[i], i);
+		if (rc) {
+			DEV_ERR("%s: '%s' get_dt_vreg_data failed.rc=%d\n",
+				__func__, hdmi_pm_name(i), rc);
+			goto error;
+		}
+	}
+
+	/* CLK */
+	rc = hdmi_tx_clk_init(pdev, pdata);
+	if (rc) {
+		DEV_ERR("%s: FAILED: clk init. rc=%d\n", __func__, rc);
+		goto error;
+	}
+
+	return rc;
+
+error:
+	hdmi_tx_put_dt_data(&pdev->dev, pdata);
+	return rc;
+} /* hdmi_tx_get_dt_data */
+
+static int __devinit hdmi_tx_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct device_node *of_node = pdev->dev.of_node;
+	struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
+
+	if (!of_node) {
+		DEV_ERR("%s: FAILED: of_node not found\n", __func__);
+		rc = -ENODEV;
+		return rc;
+	}
+
+	hdmi_ctrl = devm_kzalloc(&pdev->dev, sizeof(*hdmi_ctrl), GFP_KERNEL);
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: FAILED: cannot alloc hdmi tx ctrl\n", __func__);
+		rc = -ENOMEM;
+		goto failed_no_mem;
+	}
+
+	platform_set_drvdata(pdev, hdmi_ctrl);
+	hdmi_ctrl->pdev = pdev;
+
+	rc = hdmi_tx_get_dt_data(pdev, &hdmi_ctrl->pdata);
+	if (rc) {
+		DEV_ERR("%s: FAILED: parsing device tree data. rc=%d\n",
+			__func__, rc);
+		goto failed_dt_data;
+	}
+
+	rc = hdmi_tx_dev_init(hdmi_ctrl);
+	if (rc) {
+		DEV_ERR("%s: FAILED: hdmi_tx_dev_init. rc=%d\n", __func__, rc);
+		goto failed_dev_init;
+	}
+
+	rc = hdmi_tx_register_panel(hdmi_ctrl);
+	if (rc) {
+		DEV_ERR("%s: FAILED: register_panel. rc=%d\n", __func__, rc);
+		goto failed_reg_panel;
+	}
+
+	rc = hdmi_tx_sysfs_create(hdmi_ctrl);
+	if (rc) {
+		DEV_ERR("%s: hdmi_tx_sysfs_create failed.rc=%d\n",
+			__func__, rc);
+		goto failed_reg_panel;
+	}
+
+	rc = hdmi_tx_init_features(hdmi_ctrl);
+	if (rc) {
+		DEV_ERR("%s: init_features failed.rc=%d\n", __func__, rc);
+		goto failed_init_features;
+	}
+
+	return rc;
+
+failed_init_features:
+	hdmi_tx_sysfs_remove(hdmi_ctrl);
+failed_reg_panel:
+	hdmi_tx_dev_deinit(hdmi_ctrl);
+failed_dev_init:
+	hdmi_tx_put_dt_data(&pdev->dev, &hdmi_ctrl->pdata);
+failed_dt_data:
+	devm_kfree(&pdev->dev, hdmi_ctrl);
+failed_no_mem:
+	return rc;
+} /* hdmi_tx_probe */
+
+static int __devexit hdmi_tx_remove(struct platform_device *pdev)
+{
+	struct hdmi_tx_ctrl *hdmi_ctrl = platform_get_drvdata(pdev);
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: no driver data\n", __func__);
+		return -ENODEV;
+	}
+
+	hdmi_tx_sysfs_remove(hdmi_ctrl);
+	hdmi_tx_dev_deinit(hdmi_ctrl);
+	hdmi_tx_put_dt_data(&pdev->dev, &hdmi_ctrl->pdata);
+	devm_kfree(&hdmi_ctrl->pdev->dev, hdmi_ctrl);
+
+	return 0;
+} /* hdmi_tx_remove */
+
+static const struct of_device_id hdmi_tx_dt_match[] = {
+	{.compatible = COMPATIBLE_NAME,},
+};
+MODULE_DEVICE_TABLE(of, hdmi_tx_dt_match);
+
+static struct platform_driver this_driver = {
+	.probe = hdmi_tx_probe,
+	.remove = hdmi_tx_remove,
+	.driver = {
+		.name = DRV_NAME,
+		.of_match_table = hdmi_tx_dt_match,
+	},
+};
+
+static int __init hdmi_tx_drv_init(void)
+{
+	int rc;
+
+	rc = platform_driver_register(&this_driver);
+	if (rc)
+		DEV_ERR("%s: FAILED: rc=%d\n", __func__, rc);
+
+	return rc;
+} /* hdmi_tx_drv_init */
+
+static void __exit hdmi_tx_drv_exit(void)
+{
+	platform_driver_unregister(&this_driver);
+} /* hdmi_tx_drv_exit */
+
+module_init(hdmi_tx_drv_init);
+module_exit(hdmi_tx_drv_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION("0.3");
+MODULE_DESCRIPTION("HDMI MSM TX driver");
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.h b/drivers/video/msm/mdss/mdss_hdmi_tx.h
new file mode 100644
index 0000000..7e37d28
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.h
@@ -0,0 +1,87 @@
+/* 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
+ * 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_HDMI_TX_H__
+#define __MDSS_HDMI_TX_H__
+
+#include <linux/switch.h>
+#include "mdss_hdmi_util.h"
+#include "mdss_io_util.h"
+
+enum hdmi_tx_clk_type {
+	HDMI_TX_AHB_CLK,
+	HDMI_TX_APP_CLK,
+	HDMI_TX_EXTP_CLK,
+	HDMI_TX_MAX_CLK
+};
+
+enum hdmi_tx_io_type {
+	HDMI_TX_CORE_IO,
+	HDMI_TX_PHY_IO,
+	HDMI_TX_QFPROM_IO,
+	HDMI_TX_MAX_IO
+};
+
+enum hdmi_tx_power_module_type {
+	HDMI_TX_HPD_PM,
+	HDMI_TX_CORE_PM,
+	HDMI_TX_CEC_PM,
+	HDMI_TX_MAX_PM
+};
+
+struct hdmi_tx_platform_data {
+	/* Data filled from device tree nodes */
+	struct dss_io_data io[HDMI_TX_MAX_IO];
+	struct dss_module_power power_data[HDMI_TX_MAX_PM];
+
+	/* clk and regulator handles */
+	struct clk *clk[HDMI_TX_MAX_CLK];
+};
+
+struct hdmi_tx_ctrl {
+	struct platform_device *pdev;
+	struct hdmi_tx_platform_data pdata;
+	struct mdss_panel_data panel_data;
+
+	struct mutex mutex;
+	struct kobject *kobj;
+	struct switch_dev sdev;
+	struct workqueue_struct *workq;
+
+	uint32_t video_resolution;
+	u32 panel_power_on;
+
+	u32 hpd_initialized;
+	int hpd_stable;
+	u32 hpd_prev_state;
+	u32 hpd_cable_chg_detected;
+	u32 hpd_state;
+	u32 hpd_feature_on;
+	struct work_struct hpd_state_work;
+	struct timer_list hpd_state_timer;
+
+	unsigned long pixel_clk;
+	u32 xres;
+	u32 yres;
+	u32 frame_rate;
+
+	u32 present_hdcp;
+
+	u8 spd_vendor_name[8];
+	u8 spd_product_description[16];
+
+	struct hdmi_tx_ddc_ctrl ddc_ctrl;
+
+	void *feature_data[HDMI_TX_FEAT_MAX];
+};
+
+#endif /* __MDSS_HDMI_TX_H__ */
diff --git a/drivers/video/msm/mdss/mdss_hdmi_util.c b/drivers/video/msm/mdss/mdss_hdmi_util.c
new file mode 100644
index 0000000..3ba9f89
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_hdmi_util.c
@@ -0,0 +1,1107 @@
+/* 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
+ * 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/io.h>
+#include <mach/board.h>
+#include "mdss_hdmi_util.h"
+
+const char *hdmi_reg_name(u32 offset)
+{
+	switch (offset) {
+	case 0x00000000: return "HDMI_CTRL";
+	case 0x00000010: return "HDMI_TEST_PATTERN";
+	case 0x00000014: return "HDMI_RANDOM_PATTERN";
+	case 0x00000018: return "HDMI_PKT_BLK_CTRL";
+	case 0x0000001C: return "HDMI_STATUS";
+	case 0x00000020: return "HDMI_AUDIO_PKT_CTRL";
+	case 0x00000024: return "HDMI_ACR_PKT_CTRL";
+	case 0x00000028: return "HDMI_VBI_PKT_CTRL";
+	case 0x0000002C: return "HDMI_INFOFRAME_CTRL0";
+	case 0x00000030: return "HDMI_INFOFRAME_CTRL1";
+	case 0x00000034: return "HDMI_GEN_PKT_CTRL";
+	case 0x0000003C: return "HDMI_ACP";
+	case 0x00000040: return "HDMI_GC";
+	case 0x00000044: return "HDMI_AUDIO_PKT_CTRL2";
+	case 0x00000048: return "HDMI_ISRC1_0";
+	case 0x0000004C: return "HDMI_ISRC1_1";
+	case 0x00000050: return "HDMI_ISRC1_2";
+	case 0x00000054: return "HDMI_ISRC1_3";
+	case 0x00000058: return "HDMI_ISRC1_4";
+	case 0x0000005C: return "HDMI_ISRC2_0";
+	case 0x00000060: return "HDMI_ISRC2_1";
+	case 0x00000064: return "HDMI_ISRC2_2";
+	case 0x00000068: return "HDMI_ISRC2_3";
+	case 0x0000006C: return "HDMI_AVI_INFO0";
+	case 0x00000070: return "HDMI_AVI_INFO1";
+	case 0x00000074: return "HDMI_AVI_INFO2";
+	case 0x00000078: return "HDMI_AVI_INFO3";
+	case 0x0000007C: return "HDMI_MPEG_INFO0";
+	case 0x00000080: return "HDMI_MPEG_INFO1";
+	case 0x00000084: return "HDMI_GENERIC0_HDR";
+	case 0x00000088: return "HDMI_GENERIC0_0";
+	case 0x0000008C: return "HDMI_GENERIC0_1";
+	case 0x00000090: return "HDMI_GENERIC0_2";
+	case 0x00000094: return "HDMI_GENERIC0_3";
+	case 0x00000098: return "HDMI_GENERIC0_4";
+	case 0x0000009C: return "HDMI_GENERIC0_5";
+	case 0x000000A0: return "HDMI_GENERIC0_6";
+	case 0x000000A4: return "HDMI_GENERIC1_HDR";
+	case 0x000000A8: return "HDMI_GENERIC1_0";
+	case 0x000000AC: return "HDMI_GENERIC1_1";
+	case 0x000000B0: return "HDMI_GENERIC1_2";
+	case 0x000000B4: return "HDMI_GENERIC1_3";
+	case 0x000000B8: return "HDMI_GENERIC1_4";
+	case 0x000000BC: return "HDMI_GENERIC1_5";
+	case 0x000000C0: return "HDMI_GENERIC1_6";
+	case 0x000000C4: return "HDMI_ACR_32_0";
+	case 0x000000C8: return "HDMI_ACR_32_1";
+	case 0x000000CC: return "HDMI_ACR_44_0";
+	case 0x000000D0: return "HDMI_ACR_44_1";
+	case 0x000000D4: return "HDMI_ACR_48_0";
+	case 0x000000D8: return "HDMI_ACR_48_1";
+	case 0x000000DC: return "HDMI_ACR_STATUS_0";
+	case 0x000000E0: return "HDMI_ACR_STATUS_1";
+	case 0x000000E4: return "HDMI_AUDIO_INFO0";
+	case 0x000000E8: return "HDMI_AUDIO_INFO1";
+	case 0x000000EC: return "HDMI_CS_60958_0";
+	case 0x000000F0: return "HDMI_CS_60958_1";
+	case 0x000000F8: return "HDMI_RAMP_CTRL0";
+	case 0x000000FC: return "HDMI_RAMP_CTRL1";
+	case 0x00000100: return "HDMI_RAMP_CTRL2";
+	case 0x00000104: return "HDMI_RAMP_CTRL3";
+	case 0x00000108: return "HDMI_CS_60958_2";
+	case 0x00000110: return "HDMI_HDCP_CTRL";
+	case 0x00000114: return "HDMI_HDCP_DEBUG_CTRL";
+	case 0x00000118: return "HDMI_HDCP_INT_CTRL";
+	case 0x0000011C: return "HDMI_HDCP_LINK0_STATUS";
+	case 0x00000120: return "HDMI_HDCP_DDC_CTRL_0";
+	case 0x00000124: return "HDMI_HDCP_DDC_CTRL_1";
+	case 0x00000128: return "HDMI_HDCP_DDC_STATUS";
+	case 0x0000012C: return "HDMI_HDCP_ENTROPY_CTRL0";
+	case 0x00000130: return "HDMI_HDCP_RESET";
+	case 0x00000134: return "HDMI_HDCP_RCVPORT_DATA0";
+	case 0x00000138: return "HDMI_HDCP_RCVPORT_DATA1";
+	case 0x0000013C: return "HDMI_HDCP_RCVPORT_DATA2_0";
+	case 0x00000140: return "HDMI_HDCP_RCVPORT_DATA2_1";
+	case 0x00000144: return "HDMI_HDCP_RCVPORT_DATA3";
+	case 0x00000148: return "HDMI_HDCP_RCVPORT_DATA4";
+	case 0x0000014C: return "HDMI_HDCP_RCVPORT_DATA5";
+	case 0x00000150: return "HDMI_HDCP_RCVPORT_DATA6";
+	case 0x00000154: return "HDMI_HDCP_RCVPORT_DATA7";
+	case 0x00000158: return "HDMI_HDCP_RCVPORT_DATA8";
+	case 0x0000015C: return "HDMI_HDCP_RCVPORT_DATA9";
+	case 0x00000160: return "HDMI_HDCP_RCVPORT_DATA10";
+	case 0x00000164: return "HDMI_HDCP_RCVPORT_DATA11";
+	case 0x00000168: return "HDMI_HDCP_RCVPORT_DATA12";
+	case 0x0000016C: return "HDMI_VENSPEC_INFO0";
+	case 0x00000170: return "HDMI_VENSPEC_INFO1";
+	case 0x00000174: return "HDMI_VENSPEC_INFO2";
+	case 0x00000178: return "HDMI_VENSPEC_INFO3";
+	case 0x0000017C: return "HDMI_VENSPEC_INFO4";
+	case 0x00000180: return "HDMI_VENSPEC_INFO5";
+	case 0x00000184: return "HDMI_VENSPEC_INFO6";
+	case 0x00000194: return "HDMI_HDCP_DEBUG";
+	case 0x0000019C: return "HDMI_TMDS_CTRL_CHAR";
+	case 0x000001A4: return "HDMI_TMDS_CTRL_SEL";
+	case 0x000001A8: return "HDMI_TMDS_SYNCCHAR01";
+	case 0x000001AC: return "HDMI_TMDS_SYNCCHAR23";
+	case 0x000001B4: return "HDMI_TMDS_DEBUG";
+	case 0x000001B8: return "HDMI_TMDS_CTL_BITS";
+	case 0x000001BC: return "HDMI_TMDS_DCBAL_CTRL";
+	case 0x000001C0: return "HDMI_TMDS_DCBAL_CHAR";
+	case 0x000001C8: return "HDMI_TMDS_CTL01_GEN";
+	case 0x000001CC: return "HDMI_TMDS_CTL23_GEN";
+	case 0x000001D0: return "HDMI_AUDIO_CFG";
+	case 0x00000204: return "HDMI_DEBUG";
+	case 0x00000208: return "HDMI_USEC_REFTIMER";
+	case 0x0000020C: return "HDMI_DDC_CTRL";
+	case 0x00000210: return "HDMI_DDC_ARBITRATION";
+	case 0x00000214: return "HDMI_DDC_INT_CTRL";
+	case 0x00000218: return "HDMI_DDC_SW_STATUS";
+	case 0x0000021C: return "HDMI_DDC_HW_STATUS";
+	case 0x00000220: return "HDMI_DDC_SPEED";
+	case 0x00000224: return "HDMI_DDC_SETUP";
+	case 0x00000228: return "HDMI_DDC_TRANS0";
+	case 0x0000022C: return "HDMI_DDC_TRANS1";
+	case 0x00000230: return "HDMI_DDC_TRANS2";
+	case 0x00000234: return "HDMI_DDC_TRANS3";
+	case 0x00000238: return "HDMI_DDC_DATA";
+	case 0x0000023C: return "HDMI_HDCP_SHA_CTRL";
+	case 0x00000240: return "HDMI_HDCP_SHA_STATUS";
+	case 0x00000244: return "HDMI_HDCP_SHA_DATA";
+	case 0x00000248: return "HDMI_HDCP_SHA_DBG_M0_0";
+	case 0x0000024C: return "HDMI_HDCP_SHA_DBG_M0_1";
+	case 0x00000250: return "HDMI_HPD_INT_STATUS";
+	case 0x00000254: return "HDMI_HPD_INT_CTRL";
+	case 0x00000258: return "HDMI_HPD_CTRL";
+	case 0x0000025C: return "HDMI_HDCP_ENTROPY_CTRL1";
+	case 0x00000260: return "HDMI_HDCP_SW_UPPER_AN";
+	case 0x00000264: return "HDMI_HDCP_SW_LOWER_AN";
+	case 0x00000268: return "HDMI_CRC_CTRL";
+	case 0x0000026C: return "HDMI_VID_CRC";
+	case 0x00000270: return "HDMI_AUD_CRC";
+	case 0x00000274: return "HDMI_VBI_CRC";
+	case 0x0000027C: return "HDMI_DDC_REF";
+	case 0x00000284: return "HDMI_HDCP_SW_UPPER_AKSV";
+	case 0x00000288: return "HDMI_HDCP_SW_LOWER_AKSV";
+	case 0x0000028C: return "HDMI_CEC_CTRL";
+	case 0x00000290: return "HDMI_CEC_WR_DATA";
+	case 0x00000294: return "HDMI_CEC_RETRANSMIT";
+	case 0x00000298: return "HDMI_CEC_STATUS";
+	case 0x0000029C: return "HDMI_CEC_INT";
+	case 0x000002A0: return "HDMI_CEC_ADDR";
+	case 0x000002A4: return "HDMI_CEC_TIME";
+	case 0x000002A8: return "HDMI_CEC_REFTIMER";
+	case 0x000002AC: return "HDMI_CEC_RD_DATA";
+	case 0x000002B0: return "HDMI_CEC_RD_FILTER";
+	case 0x000002B4: return "HDMI_ACTIVE_H";
+	case 0x000002B8: return "HDMI_ACTIVE_V";
+	case 0x000002BC: return "HDMI_ACTIVE_V_F2";
+	case 0x000002C0: return "HDMI_TOTAL";
+	case 0x000002C4: return "HDMI_V_TOTAL_F2";
+	case 0x000002C8: return "HDMI_FRAME_CTRL";
+	case 0x000002CC: return "HDMI_AUD_INT";
+	case 0x000002D0: return "HDMI_DEBUG_BUS_CTRL";
+	case 0x000002D4: return "HDMI_PHY_CTRL";
+	case 0x000002DC: return "HDMI_CEC_WR_RANGE";
+	case 0x000002E0: return "HDMI_CEC_RD_RANGE";
+	case 0x000002E4: return "HDMI_VERSION";
+	case 0x000002F4: return "HDMI_BIST_ENABLE";
+	case 0x000002F8: return "HDMI_TIMING_ENGINE_EN";
+	case 0x000002FC: return "HDMI_INTF_CONFIG";
+	case 0x00000300: return "HDMI_HSYNC_CTL";
+	case 0x00000304: return "HDMI_VSYNC_PERIOD_F0";
+	case 0x00000308: return "HDMI_VSYNC_PERIOD_F1";
+	case 0x0000030C: return "HDMI_VSYNC_PULSE_WIDTH_F0";
+	case 0x00000310: return "HDMI_VSYNC_PULSE_WIDTH_F1";
+	case 0x00000314: return "HDMI_DISPLAY_V_START_F0";
+	case 0x00000318: return "HDMI_DISPLAY_V_START_F1";
+	case 0x0000031C: return "HDMI_DISPLAY_V_END_F0";
+	case 0x00000320: return "HDMI_DISPLAY_V_END_F1";
+	case 0x00000324: return "HDMI_ACTIVE_V_START_F0";
+	case 0x00000328: return "HDMI_ACTIVE_V_START_F1";
+	case 0x0000032C: return "HDMI_ACTIVE_V_END_F0";
+	case 0x00000330: return "HDMI_ACTIVE_V_END_F1";
+	case 0x00000334: return "HDMI_DISPLAY_HCTL";
+	case 0x00000338: return "HDMI_ACTIVE_HCTL";
+	case 0x0000033C: return "HDMI_HSYNC_SKEW";
+	case 0x00000340: return "HDMI_POLARITY_CTL";
+	case 0x00000344: return "HDMI_TPG_MAIN_CONTROL";
+	case 0x00000348: return "HDMI_TPG_VIDEO_CONFIG";
+	case 0x0000034C: return "HDMI_TPG_COMPONENT_LIMITS";
+	case 0x00000350: return "HDMI_TPG_RECTANGLE";
+	case 0x00000354: return "HDMI_TPG_INITIAL_VALUE";
+	case 0x00000358: return "HDMI_TPG_BLK_WHT_PATTERN_FRAMES";
+	case 0x0000035C: return "HDMI_TPG_RGB_MAPPING";
+	default: return "???";
+	}
+} /* hdmi_reg_name */
+
+void hdmi_reg_w(void __iomem *addr, u32 offset, u32 value, u32 debug)
+{
+	u32 in_val;
+
+	writel_relaxed(value, addr+offset);
+	if (debug && PORT_DEBUG) {
+		in_val = readl_relaxed(addr+offset);
+		DEV_DBG("HDMI[%04x] => %08x [%08x] %s\n", offset, value,
+			in_val, hdmi_reg_name(offset));
+	}
+} /* hdmi_reg_w */
+
+u32 hdmi_reg_r(void __iomem *addr, u32 offset, u32 debug)
+{
+	u32 value = readl_relaxed(addr+offset);
+	if (debug && PORT_DEBUG)
+		DEV_DBG("HDMI[%04x] <= %08x %s\n", offset, value,
+			hdmi_reg_name(offset));
+	return value;
+} /* hdmi_reg_r */
+
+void hdmi_reg_dump(void __iomem *base, u32 length, const char *prefix)
+{
+	if (REG_DUMP)
+		print_hex_dump(KERN_INFO, prefix, DUMP_PREFIX_OFFSET, 32, 4,
+			(void *)base, length, false);
+} /* hdmi_reg_dump */
+
+static struct hdmi_disp_mode_timing_type
+	hdmi_supported_video_mode_lut[HDMI_VFRMT_MAX] = {
+	HDMI_SETTINGS_640x480p60_4_3,
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p60_4_3),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p60_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1280x720p60_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080i60_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i60_4_3),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i60_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x240p60_4_3),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x240p60_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x480i60_4_3),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x480i60_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x240p60_4_3),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x240p60_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480p60_4_3),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480p60_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080p60_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p50_4_3),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p50_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1280x720p50_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080i50_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i50_4_3),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i50_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x288p50_4_3),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x288p50_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x576i50_4_3),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x576i50_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x288p50_4_3),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x288p50_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576p50_4_3),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576p50_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080p50_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080p24_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080p25_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080p30_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x480p60_4_3),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x480p60_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x576p50_4_3),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x576p50_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1250i50_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080i100_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1280x720p100_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p100_4_3),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p100_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i100_4_3),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i100_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080i120_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1280x720p120_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p120_4_3),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p120_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i120_4_3),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i120_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p200_4_3),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p200_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i200_4_3),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i200_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p240_4_3),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p240_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i240_4_3),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i240_16_9),
+}; /* hdmi_supported_video_mode_lut */
+
+#define HDMI_SETUP_LUT(MODE) do {					\
+	struct hdmi_disp_mode_timing_type mode = HDMI_SETTINGS_##MODE;	\
+	hdmi_supported_video_mode_lut[mode.video_format] = mode;	\
+	} while (0)
+
+const struct hdmi_disp_mode_timing_type *hdmi_get_supported_mode(u32 mode)
+{
+	const struct hdmi_disp_mode_timing_type *ret = NULL;
+
+	if (mode >= HDMI_VFRMT_MAX)
+		return NULL;
+
+	ret = &hdmi_supported_video_mode_lut[mode];
+
+	if (ret == NULL || !ret->supported)
+		return NULL;
+
+	return ret;
+} /* hdmi_get_supported_mode */
+
+void hdmi_set_supported_mode(u32 mode)
+{
+	switch (mode) {
+	case HDMI_VFRMT_640x480p60_4_3:
+		HDMI_SETUP_LUT(640x480p60_4_3);
+		break;
+	case HDMI_VFRMT_720x480p60_4_3:
+		HDMI_SETUP_LUT(720x480p60_4_3);
+		break;
+	case HDMI_VFRMT_720x480p60_16_9:
+		HDMI_SETUP_LUT(720x480p60_16_9);
+		break;
+	case HDMI_VFRMT_720x576p50_4_3:
+		HDMI_SETUP_LUT(720x576p50_4_3);
+		break;
+	case HDMI_VFRMT_720x576p50_16_9:
+		HDMI_SETUP_LUT(720x576p50_16_9);
+		break;
+	case HDMI_VFRMT_1440x480i60_4_3:
+		HDMI_SETUP_LUT(1440x480i60_4_3);
+		break;
+	case HDMI_VFRMT_1440x480i60_16_9:
+		HDMI_SETUP_LUT(1440x480i60_16_9);
+		break;
+	case HDMI_VFRMT_1440x576i50_4_3:
+		HDMI_SETUP_LUT(1440x576i50_4_3);
+		break;
+	case HDMI_VFRMT_1440x576i50_16_9:
+		HDMI_SETUP_LUT(1440x576i50_16_9);
+		break;
+	case HDMI_VFRMT_1280x720p50_16_9:
+		HDMI_SETUP_LUT(1280x720p50_16_9);
+		break;
+	case HDMI_VFRMT_1280x720p60_16_9:
+		HDMI_SETUP_LUT(1280x720p60_16_9);
+		break;
+	case HDMI_VFRMT_1920x1080p24_16_9:
+		HDMI_SETUP_LUT(1920x1080p24_16_9);
+		break;
+	case HDMI_VFRMT_1920x1080p25_16_9:
+		HDMI_SETUP_LUT(1920x1080p25_16_9);
+		break;
+	case HDMI_VFRMT_1920x1080p30_16_9:
+		HDMI_SETUP_LUT(1920x1080p30_16_9);
+		break;
+	case HDMI_VFRMT_1920x1080p50_16_9:
+		HDMI_SETUP_LUT(1920x1080p50_16_9);
+		break;
+	case HDMI_VFRMT_1920x1080i60_16_9:
+		HDMI_SETUP_LUT(1920x1080i60_16_9);
+		break;
+	case HDMI_VFRMT_1920x1080p60_16_9:
+		HDMI_SETUP_LUT(1920x1080p60_16_9);
+		break;
+	default:
+		DEV_ERR("%s: unsupported mode=%d\n", __func__, mode);
+	}
+} /* hdmi_set_supported_mode */
+
+const char *hdmi_get_video_fmt_2string(u32 format)
+{
+	switch (format) {
+	case HDMI_VFRMT_640x480p60_4_3:    return " 640x 480 p60  4/3";
+	case HDMI_VFRMT_720x480p60_4_3:    return " 720x 480 p60  4/3";
+	case HDMI_VFRMT_720x480p60_16_9:   return " 720x 480 p60 16/9";
+	case HDMI_VFRMT_1280x720p60_16_9:  return "1280x 720 p60 16/9";
+	case HDMI_VFRMT_1920x1080i60_16_9: return "1920x1080 i60 16/9";
+	case HDMI_VFRMT_1440x480i60_4_3:   return "1440x 480 i60  4/3";
+	case HDMI_VFRMT_1440x480i60_16_9:  return "1440x 480 i60 16/9";
+	case HDMI_VFRMT_1440x240p60_4_3:   return "1440x 240 p60  4/3";
+	case HDMI_VFRMT_1440x240p60_16_9:  return "1440x 240 p60 16/9";
+	case HDMI_VFRMT_2880x480i60_4_3:   return "2880x 480 i60  4/3";
+	case HDMI_VFRMT_2880x480i60_16_9:  return "2880x 480 i60 16/9";
+	case HDMI_VFRMT_2880x240p60_4_3:   return "2880x 240 p60  4/3";
+	case HDMI_VFRMT_2880x240p60_16_9:  return "2880x 240 p60 16/9";
+	case HDMI_VFRMT_1440x480p60_4_3:   return "1440x 480 p60  4/3";
+	case HDMI_VFRMT_1440x480p60_16_9:  return "1440x 480 p60 16/9";
+	case HDMI_VFRMT_1920x1080p60_16_9: return "1920x1080 p60 16/9";
+	case HDMI_VFRMT_720x576p50_4_3:    return " 720x 576 p50  4/3";
+	case HDMI_VFRMT_720x576p50_16_9:   return " 720x 576 p50 16/9";
+	case HDMI_VFRMT_1280x720p50_16_9:  return "1280x 720 p50 16/9";
+	case HDMI_VFRMT_1920x1080i50_16_9: return "1920x1080 i50 16/9";
+	case HDMI_VFRMT_1440x576i50_4_3:   return "1440x 576 i50  4/3";
+	case HDMI_VFRMT_1440x576i50_16_9:  return "1440x 576 i50 16/9";
+	case HDMI_VFRMT_1440x288p50_4_3:   return "1440x 288 p50  4/3";
+	case HDMI_VFRMT_1440x288p50_16_9:  return "1440x 288 p50 16/9";
+	case HDMI_VFRMT_2880x576i50_4_3:   return "2880x 576 i50  4/3";
+	case HDMI_VFRMT_2880x576i50_16_9:  return "2880x 576 i50 16/9";
+	case HDMI_VFRMT_2880x288p50_4_3:   return "2880x 288 p50  4/3";
+	case HDMI_VFRMT_2880x288p50_16_9:  return "2880x 288 p50 16/9";
+	case HDMI_VFRMT_1440x576p50_4_3:   return "1440x 576 p50  4/3";
+	case HDMI_VFRMT_1440x576p50_16_9:  return "1440x 576 p50 16/9";
+	case HDMI_VFRMT_1920x1080p50_16_9: return "1920x1080 p50 16/9";
+	case HDMI_VFRMT_1920x1080p24_16_9: return "1920x1080 p24 16/9";
+	case HDMI_VFRMT_1920x1080p25_16_9: return "1920x1080 p25 16/9";
+	case HDMI_VFRMT_1920x1080p30_16_9: return "1920x1080 p30 16/9";
+	case HDMI_VFRMT_2880x480p60_4_3:   return "2880x 480 p60  4/3";
+	case HDMI_VFRMT_2880x480p60_16_9:  return "2880x 480 p60 16/9";
+	case HDMI_VFRMT_2880x576p50_4_3:   return "2880x 576 p50  4/3";
+	case HDMI_VFRMT_2880x576p50_16_9:  return "2880x 576 p50 16/9";
+	case HDMI_VFRMT_1920x1250i50_16_9: return "1920x1250 i50 16/9";
+	case HDMI_VFRMT_1920x1080i100_16_9:return "1920x1080 i100 16/9";
+	case HDMI_VFRMT_1280x720p100_16_9: return "1280x 720 p100 16/9";
+	case HDMI_VFRMT_720x576p100_4_3:   return " 720x 576 p100  4/3";
+	case HDMI_VFRMT_720x576p100_16_9:  return " 720x 576 p100 16/9";
+	case HDMI_VFRMT_1440x576i100_4_3:  return "1440x 576 i100  4/3";
+	case HDMI_VFRMT_1440x576i100_16_9: return "1440x 576 i100 16/9";
+	case HDMI_VFRMT_1920x1080i120_16_9:return "1920x1080 i120 16/9";
+	case HDMI_VFRMT_1280x720p120_16_9: return "1280x 720 p120 16/9";
+	case HDMI_VFRMT_720x480p120_4_3:   return " 720x 480 p120  4/3";
+	case HDMI_VFRMT_720x480p120_16_9:  return " 720x 480 p120 16/9";
+	case HDMI_VFRMT_1440x480i120_4_3:  return "1440x 480 i120  4/3";
+	case HDMI_VFRMT_1440x480i120_16_9: return "1440x 480 i120 16/9";
+	case HDMI_VFRMT_720x576p200_4_3:   return " 720x 576 p200  4/3";
+	case HDMI_VFRMT_720x576p200_16_9:  return " 720x 576 p200 16/9";
+	case HDMI_VFRMT_1440x576i200_4_3:  return "1440x 576 i200  4/3";
+	case HDMI_VFRMT_1440x576i200_16_9: return "1440x 576 i200 16/9";
+	case HDMI_VFRMT_720x480p240_4_3:   return " 720x 480 p240  4/3";
+	case HDMI_VFRMT_720x480p240_16_9:  return " 720x 480 p240 16/9";
+	case HDMI_VFRMT_1440x480i240_4_3:  return "1440x 480 i240  4/3";
+	case HDMI_VFRMT_1440x480i240_16_9: return "1440x 480 i240 16/9";
+	default:                           return "???";
+	}
+} /* hdmi_get_video_fmt_2string */
+
+const char *hdmi_get_single_video_3d_fmt_2string(u32 format)
+{
+	switch (format) {
+	case TOP_AND_BOTTOM:	return "TAB";
+	case FRAME_PACKING:	return "FP";
+	case SIDE_BY_SIDE_HALF: return "SSH";
+	}
+	return "";
+} /* hdmi_get_single_video_3d_fmt_2string */
+
+ssize_t hdmi_get_video_3d_fmt_2string(u32 format, char *buf)
+{
+	ssize_t ret, len = 0;
+	ret = snprintf(buf, PAGE_SIZE, "%s",
+		hdmi_get_single_video_3d_fmt_2string(
+			format & FRAME_PACKING));
+	len += ret;
+
+	if (len && (format & TOP_AND_BOTTOM))
+		ret = snprintf(buf + len, PAGE_SIZE, ":%s",
+			hdmi_get_single_video_3d_fmt_2string(
+				format & TOP_AND_BOTTOM));
+	else
+		ret = snprintf(buf + len, PAGE_SIZE, "%s",
+			hdmi_get_single_video_3d_fmt_2string(
+				format & TOP_AND_BOTTOM));
+	len += ret;
+
+	if (len && (format & SIDE_BY_SIDE_HALF))
+		ret = snprintf(buf + len, PAGE_SIZE, ":%s",
+			hdmi_get_single_video_3d_fmt_2string(
+				format & SIDE_BY_SIDE_HALF));
+	else
+		ret = snprintf(buf + len, PAGE_SIZE, "%s",
+			hdmi_get_single_video_3d_fmt_2string(
+				format & SIDE_BY_SIDE_HALF));
+	len += ret;
+
+	return len;
+} /* hdmi_get_video_3d_fmt_2string */
+
+static void hdmi_ddc_print_data(struct hdmi_tx_ddc_data *ddc_data,
+	const char *caller)
+{
+	if (!ddc_data) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+
+	DEV_DBG("%s: buf=%p, d_len=0x%x, d_addr=0x%x, no_align=%d\n",
+		caller, ddc_data->data_buf, ddc_data->data_len,
+		ddc_data->dev_addr, ddc_data->no_align);
+	DEV_DBG("%s: offset=0x%x, req_len=0x%x, retry=%d, what=%s\n",
+		caller, ddc_data->offset, ddc_data->request_len,
+		ddc_data->retry, ddc_data->what);
+} /* hdmi_ddc_print_data */
+
+static int hdmi_ddc_clear_irq(struct hdmi_tx_ddc_ctrl *ddc_ctrl,
+	char *what)
+{
+	u32 reg_val, time_out_count;
+
+	if (!ddc_ctrl || !ddc_ctrl->base) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	/* clear pending and enable interrupt */
+	time_out_count = 0xFFFF;
+	do {
+		--time_out_count;
+		/* Clear and Enable DDC interrupt */
+		HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_INT_CTRL,
+			BIT(2) | BIT(1));
+		reg_val = HDMI_REG_R_ND(ddc_ctrl->base, HDMI_DDC_INT_CTRL);
+	} while ((reg_val & BIT(0)) && time_out_count);
+
+	if (!time_out_count) {
+		DEV_ERR("%s[%s]: timedout\n", __func__, what);
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+} /*hdmi_ddc_clear_irq */
+
+static int hdmi_ddc_read_retry(struct hdmi_tx_ddc_ctrl *ddc_ctrl,
+	struct hdmi_tx_ddc_data *ddc_data)
+{
+	u32 reg_val, ndx, time_out_count;
+	int status = 0;
+	int log_retry_fail;
+
+	if (!ddc_ctrl || !ddc_ctrl->base || !ddc_data) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!ddc_data->data_buf) {
+		status = -EINVAL;
+		DEV_ERR("%s[%s]: invalid buf\n", __func__, ddc_data->what);
+		goto error;
+	}
+
+	hdmi_ddc_print_data(ddc_data, __func__);
+
+	log_retry_fail = ddc_data->retry != 1;
+again:
+	status = hdmi_ddc_clear_irq(ddc_ctrl, ddc_data->what);
+	if (status)
+		goto error;
+
+	/* Ensure Device Address has LSB set to 0 to indicate Slave addr read */
+	ddc_data->dev_addr &= 0xFE;
+
+	/*
+	 * 1. Write to HDMI_I2C_DATA with the following fields set in order to
+	 *    handle portion #1
+	 *    DATA_RW = 0x0 (write)
+	 *    DATA = linkAddress (primary link address and writing)
+	 *    INDEX = 0x0 (initial offset into buffer)
+	 *    INDEX_WRITE = 0x1 (setting initial offset)
+	 */
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA,
+		BIT(31) | (ddc_data->dev_addr << 8));
+
+	/*
+	 * 2. Write to HDMI_I2C_DATA with the following fields set in order to
+	 *    handle portion #2
+	 *    DATA_RW = 0x0 (write)
+	 *    DATA = offsetAddress
+	 *    INDEX = 0x0
+	 *    INDEX_WRITE = 0x0 (auto-increment by hardware)
+	 */
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA, ddc_data->offset << 8);
+
+	/*
+	 * 3. Write to HDMI_I2C_DATA with the following fields set in order to
+	 *    handle portion #3
+	 *    DATA_RW = 0x0 (write)
+	 *    DATA = linkAddress + 1 (primary link address 0x74 and reading)
+	 *    INDEX = 0x0
+	 *    INDEX_WRITE = 0x0 (auto-increment by hardware)
+	 */
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA,
+		(ddc_data->dev_addr | BIT(0)) << 8);
+
+	/* Data setup is complete, now setup the transaction characteristics */
+
+	/*
+	 * 4. Write to HDMI_I2C_TRANSACTION0 with the following fields set in
+	 *    order to handle characteristics of portion #1 and portion #2
+	 *    RW0 = 0x0 (write)
+	 *    START0 = 0x1 (insert START bit)
+	 *    STOP0 = 0x0 (do NOT insert STOP bit)
+	 *    CNT0 = 0x1 (single byte transaction excluding address)
+	 */
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_TRANS0, BIT(12) | BIT(16));
+
+	/*
+	 * 5. Write to HDMI_I2C_TRANSACTION1 with the following fields set in
+	 *    order to handle characteristics of portion #3
+	 *    RW1 = 0x1 (read)
+	 *    START1 = 0x1 (insert START bit)
+	 *    STOP1 = 0x1 (insert STOP bit)
+	 *    CNT1 = data_len   (it's 128 (0x80) for a blk read)
+	 */
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_TRANS1,
+		BIT(0) | BIT(12) | BIT(13) | (ddc_data->request_len << 16));
+
+	/* Trigger the I2C transfer */
+
+	/*
+	 * 6. Write to HDMI_I2C_CONTROL to kick off the hardware.
+	 *    Note that NOTHING has been transmitted on the DDC lines up to this
+	 *    point.
+	 *    TRANSACTION_CNT = 0x1 (execute transaction0 followed by
+	 *    transaction1)
+	 *    SEND_RESET = Set to 1 to send reset sequence
+	 *    GO = 0x1 (kicks off hardware)
+	 */
+	INIT_COMPLETION(ddc_ctrl->ddc_sw_done);
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_CTRL, BIT(0) | BIT(20));
+
+	time_out_count = wait_for_completion_interruptible_timeout(
+		&ddc_ctrl->ddc_sw_done, HZ/2);
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_INT_CTRL, BIT(1));
+	if (!time_out_count) {
+		if (ddc_data->retry-- > 0) {
+			DEV_INFO("%s: failed timout, retry=%d\n", __func__,
+				ddc_data->retry);
+			goto again;
+		}
+		status = -ETIMEDOUT;
+		DEV_ERR("%s: timedout(7), Int Ctrl=%08x\n", __func__,
+			HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_INT_CTRL));
+		DEV_ERR("%s: DDC SW Status=%08x, HW Status=%08x\n",
+			__func__,
+			HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_SW_STATUS),
+			HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_HW_STATUS));
+		goto error;
+	}
+
+	/* Read DDC status */
+	reg_val = HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_SW_STATUS);
+	reg_val &= BIT(12) | BIT(13) | BIT(14) | BIT(15);
+
+	/* Check if any NACK occurred */
+	if (reg_val) {
+		/* SW_STATUS_RESET */
+		HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_CTRL, BIT(3));
+
+		if (ddc_data->retry == 1)
+			/* SOFT_RESET */
+			HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_CTRL, BIT(1));
+
+		if (ddc_data->retry-- > 0) {
+			DEV_DBG("%s(%s): failed NACK=0x%08x, retry=%d\n",
+				__func__, ddc_data->what, reg_val,
+				ddc_data->retry);
+			DEV_DBG("%s: daddr=0x%02x,off=0x%02x,len=%d\n",
+				__func__, ddc_data->dev_addr,
+				ddc_data->offset, ddc_data->data_len);
+			goto again;
+		}
+		status = -EIO;
+		if (log_retry_fail) {
+			DEV_ERR("%s(%s): failed NACK=0x%08x\n",
+				__func__, ddc_data->what, reg_val);
+			DEV_ERR("%s: daddr=0x%02x,off=0x%02x,len=%d\n",
+				__func__, ddc_data->dev_addr,
+				ddc_data->offset, ddc_data->data_len);
+		}
+		goto error;
+	}
+
+	/*
+	 * 8. ALL data is now available and waiting in the DDC buffer.
+	 *    Read HDMI_I2C_DATA with the following fields set
+	 *    RW = 0x1 (read)
+	 *    DATA = BCAPS (this is field where data is pulled from)
+	 *    INDEX = 0x3 (where the data has been placed in buffer by hardware)
+	 *    INDEX_WRITE = 0x1 (explicitly define offset)
+	 */
+	/* Write this data to DDC buffer */
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA,
+		BIT(0) | (3 << 16) | BIT(31));
+
+	/* Discard first byte */
+	HDMI_REG_R_ND(ddc_ctrl->base, HDMI_DDC_DATA);
+	for (ndx = 0; ndx < ddc_data->data_len; ++ndx) {
+		reg_val = HDMI_REG_R_ND(ddc_ctrl->base, HDMI_DDC_DATA);
+		ddc_data->data_buf[ndx] = (u8)((reg_val & 0x0000FF00) >> 8);
+	}
+
+	DEV_DBG("%s[%s] success\n", __func__, ddc_data->what);
+
+error:
+	return status;
+} /* hdmi_ddc_read_retry */
+
+void hdmi_ddc_config(struct hdmi_tx_ddc_ctrl *ddc_ctrl)
+{
+	if (!ddc_ctrl || !ddc_ctrl->base) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+
+	/* Configure Pre-Scale multiplier & Threshold */
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_SPEED, (10 << 16) | (2 << 0));
+
+	/*
+	 * Setting 31:24 bits : Time units to wait before timeout
+	 * when clock is being stalled by external sink device
+	 */
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_SETUP, 0xFF000000);
+
+	/* Enable reference timer to 27 micro-seconds */
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_REF, (1 << 16) | (27 << 0));
+} /* hdmi_ddc_config */
+
+int hdmi_ddc_isr(struct hdmi_tx_ddc_ctrl *ddc_ctrl)
+{
+	int rc = -1;
+	u32 ddc_int_ctrl;
+
+	if (!ddc_ctrl || !ddc_ctrl->base) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	ddc_int_ctrl = HDMI_REG_R_ND(ddc_ctrl->base, HDMI_DDC_INT_CTRL);
+	if ((ddc_int_ctrl & BIT(2)) && (ddc_int_ctrl & BIT(0))) {
+		/* SW_DONE INT occured, clr it */
+		HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_INT_CTRL,
+			ddc_int_ctrl | BIT(1));
+		complete(&ddc_ctrl->ddc_sw_done);
+		return 0;
+	}
+
+	DEV_DBG("%s: ddc_int_ctrl=%04x\n", __func__, ddc_int_ctrl);
+
+	return rc;
+} /* hdmi_ddc_isr */
+
+int hdmi_ddc_read(struct hdmi_tx_ddc_ctrl *ddc_ctrl,
+	struct hdmi_tx_ddc_data *ddc_data)
+{
+	int rc = 0;
+
+	if (!ddc_ctrl || !ddc_data) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	rc = hdmi_ddc_read_retry(ddc_ctrl, ddc_data);
+	if (!rc)
+		return rc;
+
+	if (ddc_data->no_align) {
+		rc = hdmi_ddc_read_retry(ddc_ctrl, ddc_data);
+	} else {
+		ddc_data->request_len = 32 * ((ddc_data->data_len + 31) / 32);
+		rc = hdmi_ddc_read_retry(ddc_ctrl, ddc_data);
+	}
+
+	return rc;
+} /* hdmi_ddc_read */
+
+int hdmi_ddc_read_seg(struct hdmi_tx_ddc_ctrl *ddc_ctrl,
+	struct hdmi_tx_ddc_data *ddc_data)
+{
+	int status = 0;
+	u32 reg_val, ndx, time_out_count;
+	int log_retry_fail;
+	int seg_addr = 0x60, seg_num = 0x01;
+
+	if (!ddc_ctrl || !ddc_ctrl->base || !ddc_data) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!ddc_data->data_buf) {
+		status = -EINVAL;
+		DEV_ERR("%s[%s]: invalid buf\n", __func__, ddc_data->what);
+		goto error;
+	}
+
+	log_retry_fail = ddc_data->retry != 1;
+
+again:
+	status = hdmi_ddc_clear_irq(ddc_ctrl, ddc_data->what);
+	if (status)
+		goto error;
+
+	/* Ensure Device Address has LSB set to 0 to indicate Slave addr read */
+	ddc_data->dev_addr &= 0xFE;
+
+	/*
+	 * 1. Write to HDMI_I2C_DATA with the following fields set in order to
+	 *    handle portion #1
+	 *    DATA_RW = 0x0 (write)
+	 *    DATA = linkAddress (primary link address and writing)
+	 *    INDEX = 0x0 (initial offset into buffer)
+	 *    INDEX_WRITE = 0x1 (setting initial offset)
+	 */
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA, BIT(31) | (seg_addr << 8));
+
+	/*
+	 * 2. Write to HDMI_I2C_DATA with the following fields set in order to
+	 *    handle portion #2
+	 *    DATA_RW = 0x0 (write)
+	 *    DATA = offsetAddress
+	 *    INDEX = 0x0
+	 *    INDEX_WRITE = 0x0 (auto-increment by hardware)
+	 */
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA, seg_num << 8);
+
+	/*
+	 * 3. Write to HDMI_I2C_DATA with the following fields set in order to
+	 *    handle portion #3
+	 *    DATA_RW = 0x0 (write)
+	 *    DATA = linkAddress + 1 (primary link address 0x74 and reading)
+	 *    INDEX = 0x0
+	 *    INDEX_WRITE = 0x0 (auto-increment by hardware)
+	 */
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA, ddc_data->dev_addr << 8);
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA, ddc_data->offset << 8);
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA,
+		(ddc_data->dev_addr | BIT(0)) << 8);
+
+	/* Data setup is complete, now setup the transaction characteristics */
+
+	/*
+	 * 4. Write to HDMI_I2C_TRANSACTION0 with the following fields set in
+	 *    order to handle characteristics of portion #1 and portion #2
+	 *    RW0 = 0x0 (write)
+	 *    START0 = 0x1 (insert START bit)
+	 *    STOP0 = 0x0 (do NOT insert STOP bit)
+	 *    CNT0 = 0x1 (single byte transaction excluding address)
+	 */
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_TRANS0, BIT(12) | BIT(16));
+
+	/*
+	 * 5. Write to HDMI_I2C_TRANSACTION1 with the following fields set in
+	 *    order to handle characteristics of portion #3
+	 *    RW1 = 0x1 (read)
+	 *    START1 = 0x1 (insert START bit)
+	 *    STOP1 = 0x1 (insert STOP bit)
+	 *    CNT1 = data_len   (it's 128 (0x80) for a blk read)
+	 */
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_TRANS1, BIT(12) | BIT(16));
+
+	/*
+	 * 5. Write to HDMI_I2C_TRANSACTION1 with the following fields set in
+	 *    order to handle characteristics of portion #3
+	 *    RW1 = 0x1 (read)
+	 *    START1 = 0x1 (insert START bit)
+	 *    STOP1 = 0x1 (insert STOP bit)
+	 *    CNT1 = data_len   (it's 128 (0x80) for a blk read)
+	 */
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_TRANS2,
+		BIT(0) | BIT(12) | BIT(13) | (ddc_data->request_len << 16));
+
+	/* Trigger the I2C transfer */
+
+	/*
+	 * 6. Write to HDMI_I2C_CONTROL to kick off the hardware.
+	 *    Note that NOTHING has been transmitted on the DDC lines up to this
+	 *    point.
+	 *    TRANSACTION_CNT = 0x2 (execute transaction0 followed by
+	 *    transaction1)
+	 *    GO = 0x1 (kicks off hardware)
+	 */
+	INIT_COMPLETION(ddc_ctrl->ddc_sw_done);
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_CTRL, BIT(0) | BIT(21));
+
+	time_out_count = wait_for_completion_interruptible_timeout(
+		&ddc_ctrl->ddc_sw_done, HZ/2);
+
+	reg_val = HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_INT_CTRL);
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_INT_CTRL, reg_val & (~BIT(2)));
+	if (!time_out_count) {
+		if (ddc_data->retry-- > 0) {
+			DEV_INFO("%s: failed timout, retry=%d\n", __func__,
+				ddc_data->retry);
+			goto again;
+		}
+		status = -ETIMEDOUT;
+		DEV_ERR("%s: timedout(7), Int Ctrl=%08x\n", __func__,
+			HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_INT_CTRL));
+		DEV_ERR("%s: DDC SW Status=%08x, HW Status=%08x\n",
+			__func__,
+			HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_SW_STATUS),
+			HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_HW_STATUS));
+		goto error;
+	}
+
+	/* Read DDC status */
+	reg_val = HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_SW_STATUS);
+	reg_val &= BIT(12) | BIT(13) | BIT(14) | BIT(15);
+
+	/* Check if any NACK occurred */
+	if (reg_val) {
+		/* SW_STATUS_RESET */
+		HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_CTRL, BIT(3));
+		if (ddc_data->retry == 1)
+			/* SOFT_RESET */
+			HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_CTRL, BIT(1));
+		if (ddc_data->retry-- > 0) {
+			DEV_DBG("%s(%s): failed NACK=0x%08x, retry=%d\n",
+				__func__, ddc_data->what, reg_val,
+				ddc_data->retry);
+			DEV_DBG("%s: daddr=0x%02x,off=0x%02x,len=%d\n",
+				__func__, ddc_data->dev_addr,
+				ddc_data->offset, ddc_data->data_len);
+			goto again;
+		}
+		status = -EIO;
+		if (log_retry_fail) {
+			DEV_ERR("%s(%s): failed NACK=0x%08x\n",
+				__func__, ddc_data->what, reg_val);
+			DEV_ERR("%s: daddr=0x%02x,off=0x%02x,len=%d\n",
+				__func__, ddc_data->dev_addr,
+				ddc_data->offset, ddc_data->data_len);
+		}
+		goto error;
+	}
+
+	/*
+	 * 8. ALL data is now available and waiting in the DDC buffer.
+	 *    Read HDMI_I2C_DATA with the following fields set
+	 *    RW = 0x1 (read)
+	 *    DATA = BCAPS (this is field where data is pulled from)
+	 *    INDEX = 0x5 (where the data has been placed in buffer by hardware)
+	 *    INDEX_WRITE = 0x1 (explicitly define offset)
+	 */
+	/* Write this data to DDC buffer */
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA,
+		BIT(0) | (5 << 16) | BIT(31));
+
+	/* Discard first byte */
+	HDMI_REG_R_ND(ddc_ctrl->base, HDMI_DDC_DATA);
+
+	for (ndx = 0; ndx < ddc_data->data_len; ++ndx) {
+		reg_val = HDMI_REG_R_ND(ddc_ctrl->base, HDMI_DDC_DATA);
+		ddc_data->data_buf[ndx] = (u8) ((reg_val & 0x0000FF00) >> 8);
+	}
+
+	DEV_DBG("%s[%s] success\n", __func__, ddc_data->what);
+
+error:
+	return status;
+} /* hdmi_ddc_read_seg */
+
+int hdmi_ddc_write(struct hdmi_tx_ddc_ctrl *ddc_ctrl,
+	struct hdmi_tx_ddc_data *ddc_data)
+{
+	u32 reg_val, ndx;
+	int status = 0, retry = 10;
+	u32 time_out_count;
+
+	if (!ddc_ctrl || !ddc_ctrl->base || !ddc_data) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!ddc_data->data_buf) {
+		status = -EINVAL;
+		DEV_ERR("%s[%s]: invalid buf\n", __func__, ddc_data->what);
+		goto error;
+	}
+
+again:
+	status = hdmi_ddc_clear_irq(ddc_ctrl, ddc_data->what);
+	if (status)
+		goto error;
+
+	/* Ensure Device Address has LSB set to 0 to indicate Slave addr read */
+	ddc_data->dev_addr &= 0xFE;
+
+	/*
+	 * 1. Write to HDMI_I2C_DATA with the following fields set in order to
+	 *    handle portion #1
+	 *    DATA_RW = 0x1 (write)
+	 *    DATA = linkAddress (primary link address and writing)
+	 *    INDEX = 0x0 (initial offset into buffer)
+	 *    INDEX_WRITE = 0x1 (setting initial offset)
+	 */
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA,
+		BIT(31) | (ddc_data->dev_addr << 8));
+
+	/*
+	 * 2. Write to HDMI_I2C_DATA with the following fields set in order to
+	 *    handle portion #2
+	 *    DATA_RW = 0x0 (write)
+	 *    DATA = offsetAddress
+	 *    INDEX = 0x0
+	 *    INDEX_WRITE = 0x0 (auto-increment by hardware)
+	 */
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA, ddc_data->offset << 8);
+
+	/*
+	 * 3. Write to HDMI_I2C_DATA with the following fields set in order to
+	 *    handle portion #3
+	 *    DATA_RW = 0x0 (write)
+	 *    DATA = data_buf[ndx]
+	 *    INDEX = 0x0
+	 *    INDEX_WRITE = 0x0 (auto-increment by hardware)
+	 */
+	for (ndx = 0; ndx < ddc_data->data_len; ++ndx)
+		HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA,
+			((u32)ddc_data->data_buf[ndx]) << 8);
+
+	/* Data setup is complete, now setup the transaction characteristics */
+
+	/*
+	 * 4. Write to HDMI_I2C_TRANSACTION0 with the following fields set in
+	 *    order to handle characteristics of portion #1 and portion #2
+	 *    RW0 = 0x0 (write)
+	 *    START0 = 0x1 (insert START bit)
+	 *    STOP0 = 0x0 (do NOT insert STOP bit)
+	 *    CNT0 = 0x1 (single byte transaction excluding address)
+	 */
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_TRANS0, BIT(12) | BIT(16));
+
+	/*
+	 * 5. Write to HDMI_I2C_TRANSACTION1 with the following fields set in
+	 *    order to handle characteristics of portion #3
+	 *    RW1 = 0x1 (read)
+	 *    START1 = 0x1 (insert START bit)
+	 *    STOP1 = 0x1 (insert STOP bit)
+	 *    CNT1 = data_len   (0xN (write N bytes of data))
+	 *    Byte count for second transition (excluding the first
+	 *    Byte which is usually the address)
+	 */
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_TRANS1,
+		BIT(13) | ((ddc_data->data_len-1) << 16));
+
+	/* Trigger the I2C transfer */
+	/*
+	 * 6. Write to HDMI_I2C_CONTROL to kick off the hardware.
+	 *    Note that NOTHING has been transmitted on the DDC lines up to this
+	 *    point.
+	 *    TRANSACTION_CNT = 0x1 (execute transaction0 followed by
+	 *    transaction1)
+	 *    GO = 0x1 (kicks off hardware)
+	 */
+	INIT_COMPLETION(ddc_ctrl->ddc_sw_done);
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_CTRL, BIT(0) | BIT(20));
+
+	time_out_count = wait_for_completion_interruptible_timeout(
+		&ddc_ctrl->ddc_sw_done, HZ/2);
+
+	reg_val = HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_INT_CTRL);
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_INT_CTRL, reg_val & (~BIT(2)));
+	if (!time_out_count) {
+		if (retry-- > 0) {
+			DEV_INFO("%s[%s]: failed timout, retry=%d\n", __func__,
+				ddc_data->what, retry);
+			goto again;
+		}
+		status = -ETIMEDOUT;
+		DEV_ERR("%s[%s]: timedout, Int Ctrl=%08x\n",
+			__func__, ddc_data->what,
+			HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_INT_CTRL));
+		DEV_ERR("%s: DDC SW Status=%08x, HW Status=%08x\n",
+			__func__,
+			HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_SW_STATUS),
+			HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_HW_STATUS));
+		goto error;
+	}
+
+	/* Read DDC status */
+	reg_val = HDMI_REG_R_ND(ddc_ctrl->base, HDMI_DDC_SW_STATUS);
+	reg_val &= 0x00001000 | 0x00002000 | 0x00004000 | 0x00008000;
+
+	/* Check if any NACK occurred */
+	if (reg_val) {
+		if (retry > 1)
+			/* SW_STATUS_RESET */
+			HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_CTRL, BIT(3));
+		else
+			/* SOFT_RESET */
+			HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_CTRL, BIT(1));
+
+		if (retry-- > 0) {
+			DEV_DBG("%s[%s]: failed NACK=%08x, retry=%d\n",
+				__func__, ddc_data->what, reg_val, retry);
+			msleep(100);
+			goto again;
+		}
+		status = -EIO;
+		DEV_ERR("%s[%s]: failed NACK: %08x\n", __func__,
+			ddc_data->what, reg_val);
+		goto error;
+	}
+
+	DEV_DBG("%s[%s] success\n", __func__, ddc_data->what);
+
+error:
+	return status;
+} /* hdmi_ddc_write */
diff --git a/drivers/video/msm/mdss/mdss_hdmi_util.h b/drivers/video/msm/mdss/mdss_hdmi_util.h
new file mode 100644
index 0000000..47515ba
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_hdmi_util.h
@@ -0,0 +1,433 @@
+/* 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
+ * 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 __HDMI_UTIL_H__
+#define __HDMI_UTIL_H__
+
+#define DEV_INFO(fmt, args...)	pr_info(fmt, ##args)
+#define DEV_WARN(fmt, args...)	pr_warn(fmt, ##args)
+#define DEV_ERR(fmt, args...)	pr_err(fmt, ##args)
+
+#ifdef DEBUG
+#define DEV_DBG(fmt, args...)	pr_err(fmt, ##args)
+#else
+#define DEV_DBG(args...)	(void)0
+#endif
+
+#define PORT_DEBUG 0
+#define REG_DUMP 0
+void hdmi_reg_w(void __iomem *addr, u32 offset, u32 value, u32 debug);
+u32 hdmi_reg_r(void __iomem *addr, u32 offset, u32 debug);
+
+#define HDMI_REG_W_ND(addr, offset, val)  hdmi_reg_w(addr, offset, val, false)
+#define HDMI_REG_W(addr, offset, val)     hdmi_reg_w(addr, offset, val, true)
+#define HDMI_REG_R_ND(addr, offset)       hdmi_reg_r(addr, offset, false)
+#define HDMI_REG_R(addr, offset)          hdmi_reg_r(addr, offset, true)
+
+/* HDMI_TX Registers */
+#define HDMI_CTRL                        (0x00000000)
+#define HDMI_TEST_PATTERN                (0x00000010)
+#define HDMI_RANDOM_PATTERN              (0x00000014)
+#define HDMI_PKT_BLK_CTRL                (0x00000018)
+#define HDMI_STATUS                      (0x0000001C)
+#define HDMI_AUDIO_PKT_CTRL              (0x00000020)
+#define HDMI_ACR_PKT_CTRL                (0x00000024)
+#define HDMI_VBI_PKT_CTRL                (0x00000028)
+#define HDMI_INFOFRAME_CTRL0             (0x0000002C)
+#define HDMI_INFOFRAME_CTRL1             (0x00000030)
+#define HDMI_GEN_PKT_CTRL                (0x00000034)
+#define HDMI_ACP                         (0x0000003C)
+#define HDMI_GC                          (0x00000040)
+#define HDMI_AUDIO_PKT_CTRL2             (0x00000044)
+#define HDMI_ISRC1_0                     (0x00000048)
+#define HDMI_ISRC1_1                     (0x0000004C)
+#define HDMI_ISRC1_2                     (0x00000050)
+#define HDMI_ISRC1_3                     (0x00000054)
+#define HDMI_ISRC1_4                     (0x00000058)
+#define HDMI_ISRC2_0                     (0x0000005C)
+#define HDMI_ISRC2_1                     (0x00000060)
+#define HDMI_ISRC2_2                     (0x00000064)
+#define HDMI_ISRC2_3                     (0x00000068)
+#define HDMI_AVI_INFO0                   (0x0000006C)
+#define HDMI_AVI_INFO1                   (0x00000070)
+#define HDMI_AVI_INFO2                   (0x00000074)
+#define HDMI_AVI_INFO3                   (0x00000078)
+#define HDMI_MPEG_INFO0                  (0x0000007C)
+#define HDMI_MPEG_INFO1                  (0x00000080)
+#define HDMI_GENERIC0_HDR                (0x00000084)
+#define HDMI_GENERIC0_0                  (0x00000088)
+#define HDMI_GENERIC0_1                  (0x0000008C)
+#define HDMI_GENERIC0_2                  (0x00000090)
+#define HDMI_GENERIC0_3                  (0x00000094)
+#define HDMI_GENERIC0_4                  (0x00000098)
+#define HDMI_GENERIC0_5                  (0x0000009C)
+#define HDMI_GENERIC0_6                  (0x000000A0)
+#define HDMI_GENERIC1_HDR                (0x000000A4)
+#define HDMI_GENERIC1_0                  (0x000000A8)
+#define HDMI_GENERIC1_1                  (0x000000AC)
+#define HDMI_GENERIC1_2                  (0x000000B0)
+#define HDMI_GENERIC1_3                  (0x000000B4)
+#define HDMI_GENERIC1_4                  (0x000000B8)
+#define HDMI_GENERIC1_5                  (0x000000BC)
+#define HDMI_GENERIC1_6                  (0x000000C0)
+#define HDMI_ACR_32_0                    (0x000000C4)
+#define HDMI_ACR_32_1                    (0x000000C8)
+#define HDMI_ACR_44_0                    (0x000000CC)
+#define HDMI_ACR_44_1                    (0x000000D0)
+#define HDMI_ACR_48_0                    (0x000000D4)
+#define HDMI_ACR_48_1                    (0x000000D8)
+#define HDMI_ACR_STATUS_0                (0x000000DC)
+#define HDMI_ACR_STATUS_1                (0x000000E0)
+#define HDMI_AUDIO_INFO0                 (0x000000E4)
+#define HDMI_AUDIO_INFO1                 (0x000000E8)
+#define HDMI_CS_60958_0                  (0x000000EC)
+#define HDMI_CS_60958_1                  (0x000000F0)
+#define HDMI_RAMP_CTRL0                  (0x000000F8)
+#define HDMI_RAMP_CTRL1                  (0x000000FC)
+#define HDMI_RAMP_CTRL2                  (0x00000100)
+#define HDMI_RAMP_CTRL3                  (0x00000104)
+#define HDMI_CS_60958_2                  (0x00000108)
+#define HDMI_HDCP_CTRL                   (0x00000110)
+#define HDMI_HDCP_DEBUG_CTRL             (0x00000114)
+#define HDMI_HDCP_INT_CTRL               (0x00000118)
+#define HDMI_HDCP_LINK0_STATUS           (0x0000011C)
+#define HDMI_HDCP_DDC_CTRL_0             (0x00000120)
+#define HDMI_HDCP_DDC_CTRL_1             (0x00000124)
+#define HDMI_HDCP_DDC_STATUS             (0x00000128)
+#define HDMI_HDCP_ENTROPY_CTRL0          (0x0000012C)
+#define HDMI_HDCP_RESET                  (0x00000130)
+#define HDMI_HDCP_RCVPORT_DATA0          (0x00000134)
+#define HDMI_HDCP_RCVPORT_DATA1          (0x00000138)
+#define HDMI_HDCP_RCVPORT_DATA2_0        (0x0000013C)
+#define HDMI_HDCP_RCVPORT_DATA2_1        (0x00000140)
+#define HDMI_HDCP_RCVPORT_DATA3          (0x00000144)
+#define HDMI_HDCP_RCVPORT_DATA4          (0x00000148)
+#define HDMI_HDCP_RCVPORT_DATA5          (0x0000014C)
+#define HDMI_HDCP_RCVPORT_DATA6          (0x00000150)
+#define HDMI_HDCP_RCVPORT_DATA7          (0x00000154)
+#define HDMI_HDCP_RCVPORT_DATA8          (0x00000158)
+#define HDMI_HDCP_RCVPORT_DATA9          (0x0000015C)
+#define HDMI_HDCP_RCVPORT_DATA10         (0x00000160)
+#define HDMI_HDCP_RCVPORT_DATA11         (0x00000164)
+#define HDMI_HDCP_RCVPORT_DATA12         (0x00000168)
+#define HDMI_VENSPEC_INFO0               (0x0000016C)
+#define HDMI_VENSPEC_INFO1               (0x00000170)
+#define HDMI_VENSPEC_INFO2               (0x00000174)
+#define HDMI_VENSPEC_INFO3               (0x00000178)
+#define HDMI_VENSPEC_INFO4               (0x0000017C)
+#define HDMI_VENSPEC_INFO5               (0x00000180)
+#define HDMI_VENSPEC_INFO6               (0x00000184)
+#define HDMI_HDCP_DEBUG                  (0x00000194)
+#define HDMI_TMDS_CTRL_CHAR              (0x0000019C)
+#define HDMI_TMDS_CTRL_SEL               (0x000001A4)
+#define HDMI_TMDS_SYNCCHAR01             (0x000001A8)
+#define HDMI_TMDS_SYNCCHAR23             (0x000001AC)
+#define HDMI_TMDS_DEBUG                  (0x000001B4)
+#define HDMI_TMDS_CTL_BITS               (0x000001B8)
+#define HDMI_TMDS_DCBAL_CTRL             (0x000001BC)
+#define HDMI_TMDS_DCBAL_CHAR             (0x000001C0)
+#define HDMI_TMDS_CTL01_GEN              (0x000001C8)
+#define HDMI_TMDS_CTL23_GEN              (0x000001CC)
+#define HDMI_AUDIO_CFG                   (0x000001D0)
+#define HDMI_DEBUG                       (0x00000204)
+#define HDMI_USEC_REFTIMER               (0x00000208)
+#define HDMI_DDC_CTRL                    (0x0000020C)
+#define HDMI_DDC_ARBITRATION             (0x00000210)
+#define HDMI_DDC_INT_CTRL                (0x00000214)
+#define HDMI_DDC_SW_STATUS               (0x00000218)
+#define HDMI_DDC_HW_STATUS               (0x0000021C)
+#define HDMI_DDC_SPEED                   (0x00000220)
+#define HDMI_DDC_SETUP                   (0x00000224)
+#define HDMI_DDC_TRANS0                  (0x00000228)
+#define HDMI_DDC_TRANS1                  (0x0000022C)
+#define HDMI_DDC_TRANS2                  (0x00000230)
+#define HDMI_DDC_TRANS3                  (0x00000234)
+#define HDMI_DDC_DATA                    (0x00000238)
+#define HDMI_HDCP_SHA_CTRL               (0x0000023C)
+#define HDMI_HDCP_SHA_STATUS             (0x00000240)
+#define HDMI_HDCP_SHA_DATA               (0x00000244)
+#define HDMI_HDCP_SHA_DBG_M0_0           (0x00000248)
+#define HDMI_HDCP_SHA_DBG_M0_1           (0x0000024C)
+#define HDMI_HPD_INT_STATUS              (0x00000250)
+#define HDMI_HPD_INT_CTRL                (0x00000254)
+#define HDMI_HPD_CTRL                    (0x00000258)
+#define HDMI_HDCP_ENTROPY_CTRL1          (0x0000025C)
+#define HDMI_HDCP_SW_UPPER_AN            (0x00000260)
+#define HDMI_HDCP_SW_LOWER_AN            (0x00000264)
+#define HDMI_CRC_CTRL                    (0x00000268)
+#define HDMI_VID_CRC                     (0x0000026C)
+#define HDMI_AUD_CRC                     (0x00000270)
+#define HDMI_VBI_CRC                     (0x00000274)
+#define HDMI_DDC_REF                     (0x0000027C)
+#define HDMI_HDCP_SW_UPPER_AKSV          (0x00000284)
+#define HDMI_HDCP_SW_LOWER_AKSV          (0x00000288)
+#define HDMI_CEC_CTRL                    (0x0000028C)
+#define HDMI_CEC_WR_DATA                 (0x00000290)
+#define HDMI_CEC_RETRANSMIT              (0x00000294)
+#define HDMI_CEC_STATUS                  (0x00000298)
+#define HDMI_CEC_INT                     (0x0000029C)
+#define HDMI_CEC_ADDR                    (0x000002A0)
+#define HDMI_CEC_TIME                    (0x000002A4)
+#define HDMI_CEC_REFTIMER                (0x000002A8)
+#define HDMI_CEC_RD_DATA                 (0x000002AC)
+#define HDMI_CEC_RD_FILTER               (0x000002B0)
+#define HDMI_ACTIVE_H                    (0x000002B4)
+#define HDMI_ACTIVE_V                    (0x000002B8)
+#define HDMI_ACTIVE_V_F2                 (0x000002BC)
+#define HDMI_TOTAL                       (0x000002C0)
+#define HDMI_V_TOTAL_F2                  (0x000002C4)
+#define HDMI_FRAME_CTRL                  (0x000002C8)
+#define HDMI_AUD_INT                     (0x000002CC)
+#define HDMI_DEBUG_BUS_CTRL              (0x000002D0)
+#define HDMI_PHY_CTRL                    (0x000002D4)
+#define HDMI_CEC_WR_RANGE                (0x000002DC)
+#define HDMI_CEC_RD_RANGE                (0x000002E0)
+#define HDMI_VERSION                     (0x000002E4)
+#define HDMI_BIST_ENABLE                 (0x000002F4)
+#define HDMI_TIMING_ENGINE_EN            (0x000002F8)
+#define HDMI_INTF_CONFIG                 (0x000002FC)
+#define HDMI_HSYNC_CTL                   (0x00000300)
+#define HDMI_VSYNC_PERIOD_F0             (0x00000304)
+#define HDMI_VSYNC_PERIOD_F1             (0x00000308)
+#define HDMI_VSYNC_PULSE_WIDTH_F0        (0x0000030C)
+#define HDMI_VSYNC_PULSE_WIDTH_F1        (0x00000310)
+#define HDMI_DISPLAY_V_START_F0          (0x00000314)
+#define HDMI_DISPLAY_V_START_F1          (0x00000318)
+#define HDMI_DISPLAY_V_END_F0            (0x0000031C)
+#define HDMI_DISPLAY_V_END_F1            (0x00000320)
+#define HDMI_ACTIVE_V_START_F0           (0x00000324)
+#define HDMI_ACTIVE_V_START_F1           (0x00000328)
+#define HDMI_ACTIVE_V_END_F0             (0x0000032C)
+#define HDMI_ACTIVE_V_END_F1             (0x00000330)
+#define HDMI_DISPLAY_HCTL                (0x00000334)
+#define HDMI_ACTIVE_HCTL                 (0x00000338)
+#define HDMI_HSYNC_SKEW                  (0x0000033C)
+#define HDMI_POLARITY_CTL                (0x00000340)
+#define HDMI_TPG_MAIN_CONTROL            (0x00000344)
+#define HDMI_TPG_VIDEO_CONFIG            (0x00000348)
+#define HDMI_TPG_COMPONENT_LIMITS        (0x0000034C)
+#define HDMI_TPG_RECTANGLE               (0x00000350)
+#define HDMI_TPG_INITIAL_VALUE           (0x00000354)
+#define HDMI_TPG_BLK_WHT_PATTERN_FRAMES  (0x00000358)
+#define HDMI_TPG_RGB_MAPPING             (0x0000035C)
+
+/* HDMI PHY Registers, use them with PHY base and _ND macro */
+#define HDMI_PHY_ANA_CFG0                (0x00000000)
+#define HDMI_PHY_ANA_CFG1                (0x00000004)
+#define HDMI_PHY_PD_CTRL0                (0x00000010)
+#define HDMI_PHY_PD_CTRL1                (0x00000014)
+#define HDMI_PHY_BIST_CFG0               (0x00000034)
+#define HDMI_PHY_BIST_PATN0              (0x0000003C)
+#define HDMI_PHY_BIST_PATN1              (0x00000040)
+#define HDMI_PHY_BIST_PATN2              (0x00000044)
+#define HDMI_PHY_BIST_PATN3              (0x00000048)
+
+/* all video formats defined by EIA CEA 861D */
+#define HDMI_VFRMT_640x480p60_4_3	0
+#define HDMI_VFRMT_720x480p60_4_3	1
+#define HDMI_VFRMT_720x480p60_16_9	2
+#define HDMI_VFRMT_1280x720p60_16_9	3
+#define HDMI_VFRMT_1920x1080i60_16_9	4
+#define HDMI_VFRMT_720x480i60_4_3	5
+#define HDMI_VFRMT_1440x480i60_4_3	HDMI_VFRMT_720x480i60_4_3
+#define HDMI_VFRMT_720x480i60_16_9	6
+#define HDMI_VFRMT_1440x480i60_16_9	HDMI_VFRMT_720x480i60_16_9
+#define HDMI_VFRMT_720x240p60_4_3	7
+#define HDMI_VFRMT_1440x240p60_4_3	HDMI_VFRMT_720x240p60_4_3
+#define HDMI_VFRMT_720x240p60_16_9	8
+#define HDMI_VFRMT_1440x240p60_16_9	HDMI_VFRMT_720x240p60_16_9
+#define HDMI_VFRMT_2880x480i60_4_3	9
+#define HDMI_VFRMT_2880x480i60_16_9	10
+#define HDMI_VFRMT_2880x240p60_4_3	11
+#define HDMI_VFRMT_2880x240p60_16_9	12
+#define HDMI_VFRMT_1440x480p60_4_3	13
+#define HDMI_VFRMT_1440x480p60_16_9	14
+#define HDMI_VFRMT_1920x1080p60_16_9	15
+#define HDMI_VFRMT_720x576p50_4_3	16
+#define HDMI_VFRMT_720x576p50_16_9	17
+#define HDMI_VFRMT_1280x720p50_16_9	18
+#define HDMI_VFRMT_1920x1080i50_16_9	19
+#define HDMI_VFRMT_720x576i50_4_3	20
+#define HDMI_VFRMT_1440x576i50_4_3	HDMI_VFRMT_720x576i50_4_3
+#define HDMI_VFRMT_720x576i50_16_9	21
+#define HDMI_VFRMT_1440x576i50_16_9	HDMI_VFRMT_720x576i50_16_9
+#define HDMI_VFRMT_720x288p50_4_3	22
+#define HDMI_VFRMT_1440x288p50_4_3	HDMI_VFRMT_720x288p50_4_3
+#define HDMI_VFRMT_720x288p50_16_9	23
+#define HDMI_VFRMT_1440x288p50_16_9	HDMI_VFRMT_720x288p50_16_9
+#define HDMI_VFRMT_2880x576i50_4_3	24
+#define HDMI_VFRMT_2880x576i50_16_9	25
+#define HDMI_VFRMT_2880x288p50_4_3	26
+#define HDMI_VFRMT_2880x288p50_16_9	27
+#define HDMI_VFRMT_1440x576p50_4_3	28
+#define HDMI_VFRMT_1440x576p50_16_9	29
+#define HDMI_VFRMT_1920x1080p50_16_9	30
+#define HDMI_VFRMT_1920x1080p24_16_9	31
+#define HDMI_VFRMT_1920x1080p25_16_9	32
+#define HDMI_VFRMT_1920x1080p30_16_9	33
+#define HDMI_VFRMT_2880x480p60_4_3	34
+#define HDMI_VFRMT_2880x480p60_16_9	35
+#define HDMI_VFRMT_2880x576p50_4_3	36
+#define HDMI_VFRMT_2880x576p50_16_9	37
+#define HDMI_VFRMT_1920x1250i50_16_9	38
+#define HDMI_VFRMT_1920x1080i100_16_9	39
+#define HDMI_VFRMT_1280x720p100_16_9	40
+#define HDMI_VFRMT_720x576p100_4_3	41
+#define HDMI_VFRMT_720x576p100_16_9	42
+#define HDMI_VFRMT_720x576i100_4_3	43
+#define HDMI_VFRMT_1440x576i100_4_3	HDMI_VFRMT_720x576i100_4_3
+#define HDMI_VFRMT_720x576i100_16_9	44
+#define HDMI_VFRMT_1440x576i100_16_9	HDMI_VFRMT_720x576i100_16_9
+#define HDMI_VFRMT_1920x1080i120_16_9	45
+#define HDMI_VFRMT_1280x720p120_16_9	46
+#define HDMI_VFRMT_720x480p120_4_3	47
+#define HDMI_VFRMT_720x480p120_16_9	48
+#define HDMI_VFRMT_720x480i120_4_3	49
+#define HDMI_VFRMT_1440x480i120_4_3	HDMI_VFRMT_720x480i120_4_3
+#define HDMI_VFRMT_720x480i120_16_9	50
+#define HDMI_VFRMT_1440x480i120_16_9	HDMI_VFRMT_720x480i120_16_9
+#define HDMI_VFRMT_720x576p200_4_3	51
+#define HDMI_VFRMT_720x576p200_16_9	52
+#define HDMI_VFRMT_720x576i200_4_3	53
+#define HDMI_VFRMT_1440x576i200_4_3	HDMI_VFRMT_720x576i200_4_3
+#define HDMI_VFRMT_720x576i200_16_9	54
+#define HDMI_VFRMT_1440x576i200_16_9	HDMI_VFRMT_720x576i200_16_9
+#define HDMI_VFRMT_720x480p240_4_3	55
+#define HDMI_VFRMT_720x480p240_16_9	56
+#define HDMI_VFRMT_720x480i240_4_3	57
+#define HDMI_VFRMT_1440x480i240_4_3	HDMI_VFRMT_720x480i240_4_3
+#define HDMI_VFRMT_720x480i240_16_9	58
+#define HDMI_VFRMT_1440x480i240_16_9	HDMI_VFRMT_720x480i240_16_9
+#define HDMI_VFRMT_MAX			59
+#define HDMI_VFRMT_FORCE_32BIT		0x7FFFFFFF
+
+#define VFRMT_NOT_SUPPORTED(VFRMT) \
+	{VFRMT, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, false}
+
+#define HDMI_SETTINGS_640x480p60_4_3					\
+	{HDMI_VFRMT_640x480p60_4_3,      640,  16,  96,  48,  true,	\
+	 480, 10, 2, 33, true, 25200, 60000, false, true}
+#define HDMI_SETTINGS_720x480p60_4_3					\
+	{HDMI_VFRMT_720x480p60_4_3,      720,  16,  62,  60,  true,	\
+	 480, 9, 6, 30,  true, 27030, 60000, false, true}
+#define HDMI_SETTINGS_720x480p60_16_9					\
+	{HDMI_VFRMT_720x480p60_16_9,     720,  16,  62,  60,  true,	\
+	 480, 9, 6, 30,  true, 27030, 60000, false, true}
+#define HDMI_SETTINGS_1280x720p60_16_9					\
+	{HDMI_VFRMT_1280x720p60_16_9,    1280, 110, 40,  220, false,	\
+	 720, 5, 5, 20, false, 74250, 60000, false, true}
+#define HDMI_SETTINGS_1920x1080i60_16_9					\
+	{HDMI_VFRMT_1920x1080i60_16_9,   1920, 88,  44,  148, false,	\
+	 540, 2, 5, 5, false, 74250, 60000, false, true}
+#define HDMI_SETTINGS_1440x480i60_4_3					\
+	{HDMI_VFRMT_1440x480i60_4_3,     1440, 38,  124, 114, true,	\
+	 240, 4, 3, 15, true, 27000, 60000, true, true}
+#define HDMI_SETTINGS_1440x480i60_16_9					\
+	{HDMI_VFRMT_1440x480i60_16_9,    1440, 38,  124, 114, true,	\
+	 240, 4, 3, 15, true, 27000, 60000, true, true}
+#define HDMI_SETTINGS_1920x1080p60_16_9					\
+	{HDMI_VFRMT_1920x1080p60_16_9,   1920, 88,  44,  148,  false,	\
+	 1080, 4, 5, 36, false, 148500, 60000, false, true}
+#define HDMI_SETTINGS_720x576p50_4_3					\
+	{HDMI_VFRMT_720x576p50_4_3,      720,  12,  64,  68,   true,	\
+	 576,  5, 5, 39, true, 27000, 50000, false, true}
+#define HDMI_SETTINGS_720x576p50_16_9					\
+	{HDMI_VFRMT_720x576p50_16_9,     720,  12,  64,  68,   true,	\
+	 576,  5, 5, 39, true, 27000, 50000, false, true}
+#define HDMI_SETTINGS_1280x720p50_16_9					\
+	{HDMI_VFRMT_1280x720p50_16_9,    1280, 440, 40,  220,  false,	\
+	 720,  5, 5, 20, false, 74250, 50000, false, true}
+#define HDMI_SETTINGS_1440x576i50_4_3					\
+	{HDMI_VFRMT_1440x576i50_4_3,     1440, 24,  126, 138,  true,	\
+	 288,  2, 3, 19, true, 27000, 50000, true, true}
+#define HDMI_SETTINGS_1440x576i50_16_9					\
+	{HDMI_VFRMT_1440x576i50_16_9,    1440, 24,  126, 138,  true,	\
+	 288,  2, 3, 19, true, 27000, 50000, true, true}
+#define HDMI_SETTINGS_1920x1080p50_16_9					\
+	{HDMI_VFRMT_1920x1080p50_16_9,   1920,  528,  44,  148,  false,	\
+	 1080, 4, 5, 36, false, 148500, 50000, false, true}
+#define HDMI_SETTINGS_1920x1080p24_16_9					\
+	{HDMI_VFRMT_1920x1080p24_16_9,   1920,  638,  44,  148,  false,	\
+	 1080, 4, 5, 36, false, 74250, 24000, false, true}
+#define HDMI_SETTINGS_1920x1080p25_16_9					\
+	{HDMI_VFRMT_1920x1080p25_16_9,   1920,  528,  44,  148,  false,	\
+	 1080, 4, 5, 36, false, 74250, 25000, false, true}
+#define HDMI_SETTINGS_1920x1080p30_16_9					\
+	{HDMI_VFRMT_1920x1080p30_16_9,   1920,  88,   44,  148,  false,	\
+	 1080, 4, 5, 36, false, 74250, 30000, false, true}
+
+#define TOP_AND_BOTTOM		0x10
+#define FRAME_PACKING		0x20
+#define SIDE_BY_SIDE_HALF	0x40
+
+enum hdmi_tx_feature_type {
+	HDMI_TX_FEAT_EDID,
+	HDMI_TX_FEAT_HDCP,
+	HDMI_TX_FEAT_CEC,
+	HDMI_TX_FEAT_MAX,
+};
+
+struct hdmi_disp_mode_timing_type {
+	u32	video_format;
+	u32	active_h;
+	u32	front_porch_h;
+	u32	pulse_width_h;
+	u32	back_porch_h;
+	u32	active_low_h;
+	u32	active_v;
+	u32	front_porch_v;
+	u32	pulse_width_v;
+	u32	back_porch_v;
+	u32	active_low_v;
+	/* Must divide by 1000 to get the actual frequency in MHZ */
+	u32	pixel_freq;
+	/* Must divide by 1000 to get the actual frequency in HZ */
+	u32	refresh_rate;
+	u32	interlaced;
+	u32	supported;
+};
+
+struct hdmi_tx_ddc_ctrl {
+	void __iomem *base;
+	struct completion ddc_sw_done;
+};
+
+struct hdmi_tx_ddc_data {
+	char *what;
+	u8 *data_buf;
+	u32 data_len;
+	u32 dev_addr;
+	u32 offset;
+	u32 request_len;
+	u32 no_align;
+	int retry;
+};
+
+void hdmi_reg_dump(void __iomem *base, u32 length, const char *prefix);
+const char *hdmi_reg_name(u32 offset);
+
+const struct hdmi_disp_mode_timing_type *hdmi_get_supported_mode(u32 mode);
+void hdmi_set_supported_mode(u32 mode);
+const char *hdmi_get_video_fmt_2string(u32 format);
+ssize_t hdmi_get_video_3d_fmt_2string(u32 format, char *buf);
+
+/* todo: Fix this. Right now this is defined in mdss_hdmi_tx.c */
+void *hdmi_get_featuredata_from_sysfs_dev(struct device *device, u32 type);
+
+/* DDC */
+void hdmi_ddc_config(struct hdmi_tx_ddc_ctrl *);
+int hdmi_ddc_isr(struct hdmi_tx_ddc_ctrl *);
+int hdmi_ddc_write(struct hdmi_tx_ddc_ctrl *, struct hdmi_tx_ddc_data *);
+int hdmi_ddc_read_seg(struct hdmi_tx_ddc_ctrl *, struct hdmi_tx_ddc_data *);
+int hdmi_ddc_read(struct hdmi_tx_ddc_ctrl *, struct hdmi_tx_ddc_data *);
+
+#endif /* __HDMI_UTIL_H__ */
diff --git a/drivers/video/msm/mdss/mdss_io_util.c b/drivers/video/msm/mdss/mdss_io_util.c
new file mode 100644
index 0000000..c121772
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_io_util.c
@@ -0,0 +1,192 @@
+/* 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/err.h>
+#include <linux/io.h>
+#include "mdss_io_util.h"
+
+static struct resource *msm_dss_get_res_byname(struct platform_device *pdev,
+	unsigned int type, const char *name)
+{
+	struct resource *res = NULL;
+
+	res = platform_get_resource_byname(pdev, type, name);
+	if (!res)
+		pr_err("%s: '%s' resource not found\n", __func__, name);
+
+	return res;
+}
+
+
+int msm_dss_ioremap_byname(struct platform_device *pdev,
+	struct dss_io_data *io_data, const char *name)
+{
+	struct resource *res = NULL;
+
+	if (!pdev) {
+		pr_err("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	res = msm_dss_get_res_byname(pdev, IORESOURCE_MEM, name);
+	if (!res) {
+		pr_err("%s: '%s' msm_dss_get_res_byname failed\n",
+			__func__, name);
+		return -ENODEV;
+	}
+
+	io_data->len = resource_size(res);
+	io_data->base = ioremap(res->start, io_data->len);
+	if (!io_data->base) {
+		pr_err("%s: '%s' ioremap failed\n", __func__, name);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+int msm_dss_config_vreg(struct device *dev, struct dss_vreg *in_vreg,
+	int num_vreg, int config)
+{
+	int i = 0, rc = 0;
+	struct dss_vreg *curr_vreg;
+
+	if (config) {
+		for (i = 0; i < num_vreg; i++) {
+			curr_vreg = &in_vreg[i];
+			curr_vreg->vreg = regulator_get(dev,
+				curr_vreg->vreg_name);
+			if (IS_ERR(curr_vreg->vreg)) {
+				pr_err("%s: %s get failed\n",
+					 __func__,
+					 curr_vreg->vreg_name);
+				curr_vreg->vreg = NULL;
+				goto vreg_get_fail;
+			}
+			if (curr_vreg->type == DSS_REG_LDO) {
+				rc = regulator_set_voltage(
+					curr_vreg->vreg,
+					curr_vreg->min_voltage,
+					curr_vreg->max_voltage);
+				if (rc < 0) {
+					pr_err("%s: %s set voltage failed\n",
+						__func__,
+						curr_vreg->vreg_name);
+					goto vreg_set_voltage_fail;
+				}
+				if (curr_vreg->optimum_voltage >= 0) {
+					rc = regulator_set_optimum_mode(
+						curr_vreg->vreg,
+						curr_vreg->optimum_voltage);
+					if (rc < 0) {
+						pr_err(
+						"%s: %s set opt mode failed\n",
+						__func__,
+						curr_vreg->vreg_name);
+						goto vreg_set_opt_mode_fail;
+					}
+				}
+			}
+		}
+	} else {
+		for (i = num_vreg-1; i >= 0; i--) {
+			curr_vreg = &in_vreg[i];
+			if (curr_vreg->vreg &&
+				regulator_is_enabled(curr_vreg->vreg)) {
+				if (curr_vreg->type == DSS_REG_LDO) {
+					if (curr_vreg->optimum_voltage >= 0) {
+						regulator_set_optimum_mode(
+							curr_vreg->vreg, 0);
+					}
+					regulator_set_voltage(curr_vreg->vreg,
+						0, curr_vreg->max_voltage);
+				}
+				regulator_put(curr_vreg->vreg);
+				curr_vreg->vreg = NULL;
+			}
+		}
+	}
+	return 0;
+
+vreg_unconfig:
+if (curr_vreg->type == DSS_REG_LDO)
+	regulator_set_optimum_mode(curr_vreg->vreg, 0);
+
+vreg_set_opt_mode_fail:
+if (curr_vreg->type == DSS_REG_LDO)
+	regulator_set_voltage(curr_vreg->vreg, 0, curr_vreg->max_voltage);
+
+vreg_set_voltage_fail:
+	regulator_put(curr_vreg->vreg);
+	curr_vreg->vreg = NULL;
+
+vreg_get_fail:
+	for (i--; i >= 0; i--) {
+		curr_vreg = &in_vreg[i];
+		goto vreg_unconfig;
+	}
+	return -EPERM;
+} /* msm_dss_config_vreg */
+
+int msm_dss_enable_vreg(struct dss_vreg *in_vreg, int num_vreg, int enable)
+{
+	int i = 0, rc = 0;
+	if (enable) {
+		for (i = 0; i < num_vreg; i++) {
+			if (IS_ERR(in_vreg[i].vreg)) {
+				pr_err("%s: %s null regulator\n",
+					__func__, in_vreg[i].vreg_name);
+				goto disable_vreg;
+			}
+			rc = regulator_enable(in_vreg[i].vreg);
+			if (rc < 0) {
+				pr_err("%s: %s enable failed\n",
+					__func__, in_vreg[i].vreg_name);
+				goto disable_vreg;
+			}
+		}
+	} else {
+		for (i = num_vreg-1; i >= 0; i--)
+			regulator_disable(in_vreg[i].vreg);
+	}
+	return rc;
+
+disable_vreg:
+	for (i--; i >= 0; i--)
+		regulator_disable(in_vreg[i].vreg);
+	return rc;
+} /* msm_dss_enable_vreg */
+
+int msm_dss_enable_gpio(struct dss_gpio *in_gpio, int num_gpio, int enable)
+{
+	int i = 0, rc = 0;
+	if (enable) {
+		for (i = 0; i < num_gpio; i++) {
+			rc = gpio_request(in_gpio[i].gpio,
+				in_gpio[i].gpio_name);
+			if (rc < 0) {
+				pr_err("%s: %s enable failed\n",
+					__func__, in_gpio[i].gpio_name);
+				goto disable_gpio;
+			}
+		}
+	} else {
+		for (i = num_gpio-1; i >= 0; i--)
+			gpio_free(in_gpio[i].gpio);
+	}
+	return rc;
+
+disable_gpio:
+	for (i--; i >= 0; i--)
+		gpio_free(in_gpio[i].gpio);
+	return rc;
+} /* msm_dss_enable_gpio */
diff --git a/drivers/video/msm/mdss/mdss_io_util.h b/drivers/video/msm/mdss/mdss_io_util.h
new file mode 100644
index 0000000..9671414
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_io_util.h
@@ -0,0 +1,59 @@
+/* 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_IO_UTIL_H__
+#define __MDSS_IO_UTIL_H__
+
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+
+struct dss_io_data {
+	u32 len;
+	void __iomem *base;
+};
+
+enum dss_vreg_type {
+	DSS_REG_LDO,
+	DSS_REG_VS,
+};
+
+struct dss_vreg {
+	struct regulator *vreg; /* vreg handle */
+	char vreg_name[32];
+	enum dss_vreg_type type;
+	int min_voltage;
+	int max_voltage;
+	int optimum_voltage;
+};
+
+struct dss_gpio {
+	unsigned gpio;
+	char gpio_name[32];
+};
+
+struct dss_module_power {
+	unsigned num_vreg;
+	struct dss_vreg *vreg_config;
+	unsigned num_gpio;
+	struct dss_gpio *gpio_config;
+};
+
+int msm_dss_ioremap_byname(struct platform_device *pdev,
+	struct dss_io_data *io_data, const char *name);
+int msm_dss_enable_gpio(struct dss_gpio *in_gpio, int num_gpio, int enable);
+int msm_dss_gpio_enable(struct dss_gpio *in_gpio, int num_gpio, int enable);
+int msm_dss_config_vreg(struct device *dev, struct dss_vreg *in_vreg,
+	int num_vreg, int config);
+int msm_dss_enable_vreg(struct dss_vreg *in_vreg, int num_vreg,	int enable);
+
+#endif /* __MDSS_IO_UTIL_H__ */
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 46e49da..80e056f 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -24,7 +24,9 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
+#include <linux/iommu.h>
 #include <linux/of.h>
+#include <linux/of_address.h>
 #include <linux/pm_runtime.h>
 #include <linux/regulator/consumer.h>
 #include <linux/memory_alloc.h>
@@ -41,15 +43,14 @@
 #include <mach/hardware.h>
 #include <mach/msm_bus.h>
 #include <mach/msm_bus_board.h>
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
 
 #include "mdss.h"
 #include "mdss_fb.h"
 #include "mdss_mdp.h"
 
-unsigned char *mdss_reg_base;
-
-struct mdss_res_type *mdss_res;
-static struct msm_panel_common_pdata *mdp_pdata;
+struct mdss_data_type *mdss_res;
 
 static DEFINE_SPINLOCK(mdp_lock);
 static DEFINE_MUTEX(mdp_clk_lock);
@@ -74,30 +75,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 = {
@@ -106,8 +95,33 @@
 	.name = "mdss_mdp",
 };
 
+struct msm_iova_partition mdp_iommu_partitions[] = {
+	{
+		.start = SZ_128K,
+		.size = SZ_2G - SZ_128K,
+	},
+};
+struct msm_iova_layout mdp_iommu_layout = {
+	.client_name = "mdss_mdp",
+	.partitions = mdp_iommu_partitions,
+	.npartitions = ARRAY_SIZE(mdp_iommu_partitions),
+};
+
+struct {
+	char *name;
+	struct device *ctx;
+} mdp_iommu_ctx[] = {
+	{
+		.name = "mdp_0",
+	},
+	{
+		.name = "mdp_1",
+	}
+};
+
 struct mdss_hw mdss_mdp_hw = {
 	.hw_ndx = MDSS_HW_MDP,
+	.ptr = NULL,
 	.irq_handler = mdss_mdp_isr,
 };
 
@@ -122,16 +136,20 @@
 	hw = mdss_irq_handlers[hw_ndx];
 	spin_unlock(&mdss_lock);
 	if (hw)
-		return hw->irq_handler(irq, ptr);
+		return hw->irq_handler(irq, hw->ptr);
 
 	return -ENODEV;
 }
 
 static irqreturn_t mdss_irq_handler(int irq, void *ptr)
 {
+	struct mdss_data_type *mdata = ptr;
 	u32 intr = MDSS_MDP_REG_READ(MDSS_REG_HW_INTR_STATUS);
 
-	mdss_res->irq_buzy = true;
+	if (!mdata)
+		return IRQ_NONE;
+
+	mdata->irq_buzy = true;
 
 	if (intr & MDSS_INTR_MDP)
 		mdss_irq_dispatch(MDSS_HW_MDP, irq, ptr);
@@ -148,7 +166,7 @@
 	if (intr & MDSS_INTR_HDMI)
 		mdss_irq_dispatch(MDSS_HW_HDMI, irq, ptr);
 
-	mdss_res->irq_buzy = false;
+	mdata->irq_buzy = false;
 
 	return IRQ_HANDLED;
 }
@@ -240,9 +258,9 @@
 }
 EXPORT_SYMBOL(mdss_disable_irq_nosync);
 
-static int mdss_mdp_bus_scale_register(void)
+static int mdss_mdp_bus_scale_register(struct mdss_data_type *mdata)
 {
-	if (!mdss_res->bus_hdl) {
+	if (!mdata->bus_hdl) {
 		struct msm_bus_scale_pdata *bus_pdata = &mdp_bus_scale_table;
 		int i;
 
@@ -251,53 +269,58 @@
 			mdp_bus_usecases[i].vectors = &mdp_bus_vectors[i];
 		}
 
-		mdss_res->bus_hdl = msm_bus_scale_register_client(bus_pdata);
-		if (!mdss_res->bus_hdl) {
+		mdata->bus_hdl = msm_bus_scale_register_client(bus_pdata);
+		if (!mdata->bus_hdl) {
 			pr_err("not able to get bus scale\n");
 			return -ENOMEM;
 		}
 
-		pr_debug("register bus_hdl=%x\n", mdss_res->bus_hdl);
+		pr_debug("register bus_hdl=%x\n", mdata->bus_hdl);
 	}
 	return 0;
 }
 
-static void mdss_mdp_bus_scale_unregister(void)
+static void mdss_mdp_bus_scale_unregister(struct mdss_data_type *mdata)
 {
-	pr_debug("unregister bus_hdl=%x\n", mdss_res->bus_hdl);
+	pr_debug("unregister bus_hdl=%x\n", mdata->bus_hdl);
 
-	if (mdss_res->bus_hdl)
-		msm_bus_scale_unregister_client(mdss_res->bus_hdl);
+	if (mdata->bus_hdl)
+		msm_bus_scale_unregister_client(mdata->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)
@@ -348,9 +371,11 @@
 				irq, mdss_res->mdp_irq_mask);
 	} else {
 		mdss_res->mdp_irq_mask &= ~irq;
+
 		MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_EN,
 				mdss_res->mdp_irq_mask);
-		mdss_disable_irq(&mdss_mdp_hw);
+		if (mdss_res->mdp_irq_mask == 0)
+			mdss_disable_irq(&mdss_mdp_hw);
 	}
 	spin_unlock_irqrestore(&mdp_lock, irq_flags);
 }
@@ -369,7 +394,8 @@
 		mdss_res->mdp_irq_mask &= ~irq;
 		MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_EN,
 				mdss_res->mdp_irq_mask);
-		mdss_disable_irq_nosync(&mdss_mdp_hw);
+		if (mdss_res->mdp_irq_mask == 0)
+			mdss_disable_irq_nosync(&mdss_mdp_hw);
 	}
 	spin_unlock(&mdp_lock);
 }
@@ -427,6 +453,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 +494,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 +513,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))
@@ -521,7 +555,7 @@
 	}
 }
 
-static inline int mdss_mdp_irq_clk_register(struct platform_device *pdev,
+static inline int mdss_mdp_irq_clk_register(struct mdss_data_type *mdata,
 					    char *clk_name, int clk_idx)
 {
 	struct clk *tmp;
@@ -530,181 +564,292 @@
 		return -EINVAL;
 	}
 
-
-	tmp = clk_get(&pdev->dev, clk_name);
+	tmp = devm_clk_get(&mdata->pdev->dev, clk_name);
 	if (IS_ERR(tmp)) {
 		pr_err("unable to get clk: %s\n", clk_name);
 		return PTR_ERR(tmp);
 	}
 
-	mdss_res->mdp_clk[clk_idx] = tmp;
+	mdata->mdp_clk[clk_idx] = tmp;
 	return 0;
 }
 
-static int mdss_mdp_irq_clk_setup(struct platform_device *pdev)
+static int mdss_mdp_irq_clk_setup(struct mdss_data_type *mdata)
 {
 	int ret;
-	int i;
 
-	ret = request_irq(mdss_res->irq, mdss_irq_handler, IRQF_DISABLED,
-			  "MDSS", 0);
+	ret = devm_request_irq(&mdata->pdev->dev, mdata->irq, mdss_irq_handler,
+			 IRQF_DISABLED,	"MDSS", mdata);
 	if (ret) {
 		pr_err("mdp request_irq() failed!\n");
 		return ret;
 	}
-	disable_irq(mdss_res->irq);
+	disable_irq(mdata->irq);
 
-	mdss_res->fs = regulator_get(&pdev->dev, "vdd");
-	if (IS_ERR_OR_NULL(mdss_res->fs)) {
-		mdss_res->fs = NULL;
+	mdata->fs = devm_regulator_get(&mdata->pdev->dev, "vdd");
+	if (IS_ERR_OR_NULL(mdata->fs)) {
+		mdata->fs = NULL;
 		pr_err("unable to get gdsc regulator\n");
-		goto error;
+		return -EINVAL;
 	}
-	regulator_enable(mdss_res->fs);
+	regulator_enable(mdata->fs);
+	mdata->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) ||
-	    mdss_mdp_irq_clk_register(pdev, "core_clk_src", MDSS_CLK_MDP_SRC) ||
-	    mdss_mdp_irq_clk_register(pdev, "core_clk", MDSS_CLK_MDP_CORE) ||
-	    mdss_mdp_irq_clk_register(pdev, "lut_clk", MDSS_CLK_MDP_LUT) ||
-	    mdss_mdp_irq_clk_register(pdev, "vsync_clk", MDSS_CLK_MDP_VSYNC))
-		goto error;
+	if (mdss_mdp_irq_clk_register(mdata, "bus_clk", MDSS_CLK_AXI) ||
+	    mdss_mdp_irq_clk_register(mdata, "iface_clk", MDSS_CLK_AHB) ||
+	    mdss_mdp_irq_clk_register(mdata, "core_clk_src",
+				      MDSS_CLK_MDP_SRC) ||
+	    mdss_mdp_irq_clk_register(mdata, "core_clk",
+				      MDSS_CLK_MDP_CORE) ||
+	    mdss_mdp_irq_clk_register(mdata, "lut_clk", MDSS_CLK_MDP_LUT) ||
+	    mdss_mdp_irq_clk_register(mdata, "vsync_clk", MDSS_CLK_MDP_VSYNC))
+		return -EINVAL;
 
 	mdss_mdp_set_clk_rate(MDP_CLK_DEFAULT_RATE);
 	pr_debug("mdp clk rate=%ld\n", mdss_mdp_get_clk_rate(MDSS_CLK_MDP_SRC));
 
 	return 0;
-error:
-	for (i = 0; i < MDSS_MAX_CLK; i++) {
-		if (mdss_res->mdp_clk[i])
-			clk_put(mdss_res->mdp_clk[i]);
+}
+
+static int mdss_iommu_fault_handler(struct iommu_domain *domain,
+		struct device *dev, unsigned long iova, int flags)
+{
+	pr_err("MDP IOMMU page fault: iova 0x%lx\n", iova);
+	return 0;
+}
+
+int mdss_iommu_attach(void)
+{
+	struct iommu_domain *domain;
+	int i, domain_idx;
+
+	if (mdss_res->iommu_attached) {
+		pr_warn("mdp iommu already attached\n");
+		return 0;
 	}
-	if (mdss_res->fs)
-		regulator_put(mdss_res->fs);
-	if (mdss_res->irq)
-		free_irq(mdss_res->irq, 0);
 
-	return -EINVAL;
+	domain_idx = mdss_get_iommu_domain();
+	domain = msm_get_iommu_domain(domain_idx);
+	if (!domain) {
+		pr_err("unable to get iommu domain(%d)\n", domain_idx);
+		return -EINVAL;
+	}
 
-}
-
-static struct msm_panel_common_pdata *mdss_mdp_populate_pdata(
-	struct device *dev)
-{
-	struct msm_panel_common_pdata *pdata;
-
-	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
-	if (!pdata)
-		dev_err(dev, "could not allocate memory for pdata\n");
-	return pdata;
-}
-
-static u32 mdss_mdp_res_init(struct platform_device *pdev)
-{
-	u32 rc;
-
-	rc = mdss_mdp_irq_clk_setup(pdev);
-	if (rc)
-		return rc;
-
-	mdss_res->clk_ctrl_wq = create_singlethread_workqueue("mdp_clk_wq");
-	INIT_DELAYED_WORK(&mdss_res->clk_ctrl_worker,
-			  mdss_mdp_clk_ctrl_workqueue_handler);
-
-	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
-	mdss_res->rev = MDSS_MDP_REG_READ(MDSS_REG_HW_VERSION);
-	mdss_res->mdp_rev = MDSS_MDP_REG_READ(MDSS_MDP_REG_HW_VERSION);
-	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
-
-	mdss_res->smp_mb_cnt = MDSS_MDP_SMP_MMB_BLOCKS;
-	mdss_res->smp_mb_size = MDSS_MDP_SMP_MMB_SIZE;
-	mdss_res->pipe_type_map = mdss_mdp_pipe_type_map;
-	mdss_res->mixer_type_map = mdss_mdp_mixer_type_map;
-
-	pr_info("mdss_revision=%x\n", mdss_res->rev);
-	pr_info("mdp_hw_revision=%x\n", mdss_res->mdp_rev);
-
-	mdss_res->res_init = true;
-	mdss_res->timeout = HZ/20;
-	mdss_res->clk_ena = false;
-	mdss_res->irq_mask = MDSS_MDP_DEFAULT_INTR_MASK;
-	mdss_res->suspend = false;
-	mdss_res->prim_ptype = NO_PANEL;
-	mdss_res->irq_ena = false;
+	for (i = 0; i < ARRAY_SIZE(mdp_iommu_ctx); i++) {
+		if (iommu_attach_device(domain, mdp_iommu_ctx[i].ctx)) {
+			WARN(1, "could not attach iommu domain %d to ctx %s\n",
+				domain_idx, mdp_iommu_ctx[i].name);
+			return -EINVAL;
+		}
+	}
+	mdss_res->iommu_attached = true;
 
 	return 0;
 }
 
+int mdss_iommu_dettach(void)
+{
+	struct iommu_domain *domain;
+	int i, domain_idx;
+
+	if (!mdss_res->iommu_attached) {
+		pr_warn("mdp iommu already dettached\n");
+		return 0;
+	}
+
+	domain_idx = mdss_get_iommu_domain();
+	domain = msm_get_iommu_domain(domain_idx);
+	if (!domain) {
+		pr_err("unable to get iommu domain(%d)\n", domain_idx);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(mdp_iommu_ctx); i++)
+		iommu_detach_device(domain, mdp_iommu_ctx[i].ctx);
+	mdss_res->iommu_attached = false;
+
+	return 0;
+}
+
+int mdss_iommu_init(void)
+{
+	struct iommu_domain *domain;
+	int domain_idx, i;
+
+	domain_idx = msm_register_domain(&mdp_iommu_layout);
+	if (IS_ERR_VALUE(domain_idx))
+		return -EINVAL;
+
+	domain = msm_get_iommu_domain(domain_idx);
+	if (!domain) {
+		pr_err("unable to get iommu domain(%d)\n", domain_idx);
+		return -EINVAL;
+	}
+
+	iommu_set_fault_handler(domain, mdss_iommu_fault_handler);
+
+	for (i = 0; i < ARRAY_SIZE(mdp_iommu_ctx); i++) {
+		mdp_iommu_ctx[i].ctx = msm_iommu_get_ctx(mdp_iommu_ctx[i].name);
+		if (!mdp_iommu_ctx[i].ctx) {
+			pr_warn("unable to get iommu ctx(%s)\n",
+					mdp_iommu_ctx[i].name);
+			return -EINVAL;
+		}
+	}
+	mdss_res->iommu_domain = domain_idx;
+
+	return 0;
+}
+
+static int mdss_hw_init(struct mdss_data_type *mdata)
+{
+	char *base = mdata->vbif_base;
+
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+	/* Setup VBIF QoS settings*/
+	MDSS_MDP_REG_WRITE(0x2E0, 0x000000AA);
+	MDSS_MDP_REG_WRITE(0x2E4, 0x00000055);
+	writel_relaxed(0x00000001, base + 0x004);
+	writel_relaxed(0x00000707, base + 0x0D8);
+	writel_relaxed(0x00000030, base + 0x0F0);
+	writel_relaxed(0x00000001, base + 0x124);
+	writel_relaxed(0x00000FFF, base + 0x178);
+	writel_relaxed(0x0FFF0FFF, base + 0x17C);
+	writel_relaxed(0x22222222, base + 0x160);
+	writel_relaxed(0x00002222, base + 0x164);
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+	pr_debug("MDP hw init done\n");
+
+	return 0;
+}
+
+static u32 mdss_mdp_res_init(struct mdss_data_type *mdata)
+{
+	u32 rc = 0;
+
+	rc = mdss_mdp_irq_clk_setup(mdata);
+	if (rc)
+		return rc;
+
+	mdata->clk_ctrl_wq = create_singlethread_workqueue("mdp_clk_wq");
+	INIT_DELAYED_WORK(&mdata->clk_ctrl_worker,
+			  mdss_mdp_clk_ctrl_workqueue_handler);
+
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+	mdata->rev = MDSS_MDP_REG_READ(MDSS_REG_HW_VERSION);
+	mdata->mdp_rev = MDSS_MDP_REG_READ(MDSS_MDP_REG_HW_VERSION);
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+	mdata->smp_mb_cnt = MDSS_MDP_SMP_MMB_BLOCKS;
+	mdata->smp_mb_size = MDSS_MDP_SMP_MMB_SIZE;
+	mdata->pipe_type_map = mdss_mdp_pipe_type_map;
+	mdata->mixer_type_map = mdss_mdp_mixer_type_map;
+
+	pr_info("mdss_revision=%x\n", mdata->rev);
+	pr_info("mdp_hw_revision=%x\n", mdata->mdp_rev);
+
+	mdata->res_init = true;
+	mdata->timeout = HZ/20;
+	mdata->clk_ena = false;
+	mdata->irq_mask = MDSS_MDP_DEFAULT_INTR_MASK;
+	mdata->suspend = false;
+	mdata->prim_ptype = NO_PANEL;
+	mdata->irq_ena = false;
+
+	mdata->iclient = msm_ion_client_create(-1, mdata->pdev->name);
+	if (IS_ERR_OR_NULL(mdata->iclient)) {
+		pr_err("msm_ion_client_create() return error (%p)\n",
+				mdata->iclient);
+		mdata->iclient = NULL;
+	}
+
+	rc = mdss_iommu_init();
+	if (!IS_ERR_VALUE(rc))
+		mdss_iommu_attach();
+
+	rc = mdss_hw_init(mdata);
+
+	return rc;
+}
+
 static int mdss_mdp_probe(struct platform_device *pdev)
 {
-	struct resource *mdss_mdp_mres;
-	struct resource *mdss_mdp_ires;
-	resource_size_t size;
+	struct resource *res;
 	int rc;
+	struct mdss_data_type *mdata;
 
-	if (!mdss_res) {
-		mdss_res = devm_kzalloc(&pdev->dev, sizeof(*mdss_res),
-				GFP_KERNEL);
-		if (mdss_res == NULL)
-			return -ENOMEM;
+	if (!pdev->dev.of_node) {
+		pr_err("MDP driver only supports device tree probe\n");
+		return -ENOTSUPP;
 	}
 
-	if (pdev->dev.of_node) {
-		pdev->id = 0;
-		mdp_pdata = mdss_mdp_populate_pdata(&pdev->dev);
-		mdss_mdp_mres = platform_get_resource(pdev,
-						IORESOURCE_MEM, 0);
-		mdss_mdp_ires = platform_get_resource(pdev,
-						IORESOURCE_IRQ, 0);
-		if (!mdss_mdp_mres || !mdss_mdp_ires) {
-			pr_err("unable to get the MDSS resources");
-			rc = -ENOMEM;
-			goto probe_done;
-		}
-		mdss_reg_base = ioremap(mdss_mdp_mres->start,
-					resource_size(mdss_mdp_mres));
-
-		pr_info("MDP HW Base phy_Address=0x%x virt=0x%x\n",
-			(int) mdss_mdp_mres->start,
-			(int) mdss_reg_base);
-
-		mdss_res->irq = mdss_mdp_ires->start;
-	} else if ((pdev->id == 0) && (pdev->num_resources > 0)) {
-		mdp_pdata = pdev->dev.platform_data;
-
-		size =  resource_size(&pdev->resource[0]);
-		mdss_reg_base = ioremap(pdev->resource[0].start, size);
-
-		pr_info("MDP HW Base phy_Address=0x%x virt=0x%x\n",
-			(int) pdev->resource[0].start,
-			(int) mdss_reg_base);
-
-		mdss_res->irq = platform_get_irq(pdev, 0);
-		if (mdss_res->irq < 0) {
-			pr_err("can not get mdp irq\n");
-			rc = -ENOMEM;
-			goto probe_done;
-		}
+	if (mdss_res) {
+		pr_err("MDP already initialized\n");
+		return -EINVAL;
 	}
 
-	if (unlikely(!mdss_reg_base)) {
+	mdata = devm_kzalloc(&pdev->dev, sizeof(*mdata), GFP_KERNEL);
+	if (mdata == NULL)
+		return -ENOMEM;
+
+	pdev->id = 0;
+	mdata->pdev = pdev;
+	platform_set_drvdata(pdev, mdata);
+	mdss_res = mdata;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mdp_phys");
+	if (!res) {
+		pr_err("unable to get MDP base address\n");
 		rc = -ENOMEM;
 		goto probe_done;
 	}
 
-	rc = mdss_mdp_res_init(pdev);
+	mdata->mdp_base = devm_ioremap(&pdev->dev, res->start,
+				       resource_size(res));
+	if (unlikely(!mdata->mdp_base)) {
+		pr_err("unable to map MDP base\n");
+		rc = -ENOMEM;
+		goto probe_done;
+	}
+	pr_info("MDP HW Base phy_Address=0x%x virt=0x%x\n",
+		(int) res->start,
+		(int) mdata->mdp_base);
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vbif_phys");
+	if (!res) {
+		pr_err("unable to get MDSS VBIF base address\n");
+		rc = -ENOMEM;
+		goto probe_done;
+	}
+
+	mdata->vbif_base = devm_ioremap(&pdev->dev, res->start,
+					resource_size(res));
+	if (unlikely(!mdata->vbif_base)) {
+		pr_err("unable to map MDSS VBIF base\n");
+		rc = -ENOMEM;
+		goto probe_done;
+	}
+	pr_info("MDSS VBIF HW Base phy_Address=0x%x virt=0x%x\n",
+		(int) res->start,
+		(int) mdata->vbif_base);
+
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!res) {
+		pr_err("unable to get MDSS irq\n");
+		rc = -ENOMEM;
+		goto probe_done;
+	}
+	mdata->irq = res->start;
+
+	rc = mdss_mdp_res_init(mdata);
 	if (rc) {
 		pr_err("unable to initialize mdss mdp resources\n");
 		goto probe_done;
 	}
-	rc = mdss_mdp_bus_scale_register();
+	rc = mdss_mdp_bus_scale_register(mdata);
 probe_done:
-	if (IS_ERR_VALUE(rc)) {
-		if (mdss_res) {
-			devm_kfree(&pdev->dev, mdss_res);
-			mdss_res = NULL;
-		}
-	}
+	if (IS_ERR_VALUE(rc))
+		mdss_res = NULL;
 
 	return rc;
 }
@@ -720,9 +865,11 @@
 	if (on && !mdss_res->fs_ena) {
 		pr_debug("Enable MDP FS\n");
 		regulator_enable(mdss_res->fs);
+		mdss_iommu_attach();
 		mdss_res->fs_ena = true;
 	} else if (!on && mdss_res->fs_ena) {
 		pr_debug("Disable MDP FS\n");
+		mdss_iommu_dettach();
 		regulator_disable(mdss_res->fs);
 		mdss_res->fs_ena = false;
 	}
@@ -736,7 +883,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 +892,44 @@
 
 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)
 {
+	struct mdss_data_type *mdata = platform_get_drvdata(pdev);
+	int ret = 0;
+
+	if (!mdata)
+		return -ENODEV;
+
+	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);
+
+	mdss_hw_init(mdata);
+	return ret;
 }
 #else
 #define mdss_mdp_suspend NULL
@@ -771,11 +938,11 @@
 
 static int mdss_mdp_remove(struct platform_device *pdev)
 {
-	if (mdss_res->fs != NULL)
-		regulator_put(mdss_res->fs);
-	iounmap(mdss_reg_base);
+	struct mdss_data_type *mdata = platform_get_drvdata(pdev);
+	if (!mdata)
+		return -ENODEV;
 	pm_runtime_disable(&pdev->dev);
-	mdss_mdp_bus_scale_unregister();
+	mdss_mdp_bus_scale_unregister(mdata);
 	return 0;
 }
 
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 4489fbb..a77c18e 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -40,6 +40,11 @@
 #define MAX_DOWNSCALE_RATIO	4
 #define MAX_UPSCALE_RATIO	20
 
+#define C3_ALPHA	3	/* alpha */
+#define C2_R_Cr		2	/* R/Cr */
+#define C1_B_Cb		1	/* B/Cb */
+#define C0_G_Y		0	/* G/luma */
+
 #ifdef MDSS_MDP_DEBUG_REG
 static inline void mdss_mdp_reg_write(u32 addr, u32 val)
 {
@@ -61,8 +66,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 {
@@ -101,6 +107,9 @@
 	MDSS_MDP_MAX_CSC
 };
 
+struct mdss_mdp_ctl;
+typedef void (*mdp_vsync_handler_t)(struct mdss_mdp_ctl *, ktime_t);
+
 struct mdss_mdp_ctl {
 	u32 num;
 	u32 ref_cnt;
@@ -118,7 +127,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;
@@ -129,6 +141,7 @@
 	int (*stop_fnc) (struct mdss_mdp_ctl *ctl);
 	int (*prepare_fnc) (struct mdss_mdp_ctl *ctl, void *arg);
 	int (*display_fnc) (struct mdss_mdp_ctl *ctl, void *arg);
+	int (*set_vsync_handler) (struct mdss_mdp_ctl *, mdp_vsync_handler_t);
 
 	void *priv_data;
 };
@@ -144,8 +157,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];
 };
@@ -171,23 +182,8 @@
 	u8 bpp;
 	u8 alpha_enable;	/*  source has alpha */
 
-	/*
-	 * number of bits for source component,
-	 * 0 = 1 bit, 1 = 2 bits, 2 = 6 bits, 3 = 8 bits
-	 */
-	u8 a_bit;	/* component 3, alpha */
-	u8 r_bit;	/* component 2, R_Cr */
-	u8 b_bit;	/* component 1, B_Cb */
-	u8 g_bit;	/* component 0, G_lumz */
-
-	/*
-	 * unpack pattern
-	 * A = C3, R = C2, B = C1, G = C0
-	 */
-	u8 element3;
-	u8 element2;
-	u8 element1;
-	u8 element0;
+	u8 bits[MAX_PLANES];
+	u8 element[MAX_PLANES];
 };
 
 struct mdss_mdp_plane_sizes {
@@ -204,7 +200,6 @@
 	int p_need;
 	struct file *srcp_file;
 	struct ion_handle *srcp_ihdl;
-	struct ion_client *iclient;
 };
 
 struct mdss_mdp_data {
@@ -231,7 +226,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;
@@ -245,6 +239,9 @@
 	u32 params_changed;
 
 	unsigned long smp[MAX_PLANES];
+
+	struct mdss_mdp_data buffers[2];
+	struct list_head list;
 };
 
 struct mdss_mdp_writeback_arg {
@@ -273,7 +270,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);
@@ -281,6 +278,7 @@
 void mdss_mdp_footswitch_ctrl(int on);
 
 int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd);
+int mdss_mdp_overlay_release_all(struct msm_fb_data_type *mfd);
 int mdss_mdp_video_start(struct mdss_mdp_ctl *ctl);
 int mdss_mdp_writeback_start(struct mdss_mdp_ctl *ctl);
 
@@ -306,7 +304,6 @@
 void mdss_mdp_pipe_unlock(struct mdss_mdp_pipe *pipe);
 
 int mdss_mdp_pipe_destroy(struct mdss_mdp_pipe *pipe);
-int mdss_mdp_pipe_release_all(struct msm_fb_data_type *mfd);
 int mdss_mdp_pipe_queue_data(struct mdss_mdp_pipe *pipe,
 			     struct mdss_mdp_data *src_data);
 
@@ -316,8 +313,7 @@
 			     struct mdss_mdp_plane_sizes *ps);
 struct mdss_mdp_format_params *mdss_mdp_get_format_params(u32 format);
 int mdss_mdp_put_img(struct mdss_mdp_img_data *data);
-int mdss_mdp_get_img(struct ion_client *iclient, struct msmfb_data *img,
-		     struct mdss_mdp_img_data *data);
+int mdss_mdp_get_img(struct msmfb_data *img, struct mdss_mdp_img_data *data);
 
 int mdss_mdp_wb_kickoff(struct mdss_mdp_ctl *ctl);
 int mdss_mdp_wb_ioctl_handler(struct msm_fb_data_type *mfd, u32 cmd, void *arg);
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index c80527d..1486779 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)
@@ -478,6 +533,11 @@
 		mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_PACK_3D, 0);
 	}
 
+	/* request bus bandwidth for panel commands */
+	ctl->clk_rate = MDP_CLK_DEFAULT_RATE;
+	ctl->bus_ib_quota = SZ_1M;
+	mdss_mdp_ctl_perf_commit(MDSS_MDP_PERF_UPDATE_ALL);
+
 	ret = pdata->on(pdata);
 
 start_fail:
@@ -531,12 +591,11 @@
 
 	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);
 
-	mdss_mdp_pipe_release_all(mfd);
+	mdss_mdp_overlay_release_all(mfd);
 
 	if (!mfd->ref_cnt)
 		mdss_mdp_ctl_destroy(mfd);
@@ -705,7 +764,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 +822,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 +843,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 +852,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 +875,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_formats.h b/drivers/video/msm/mdss/mdss_mdp_formats.h
index 07eefc1..ee3b8e6 100644
--- a/drivers/video/msm/mdss/mdss_mdp_formats.h
+++ b/drivers/video/msm/mdss/mdss_mdp_formats.h
@@ -18,311 +18,149 @@
 
 #include "mdss_mdp.h"
 
-#define C3_ALPHA	3	/* alpha */
-#define C2_R_Cr		2	/* R/Cr */
-#define C1_B_Cb		1	/* B/Cb */
-#define C0_G_Y		0	/* G/luma */
+	/*
+	 * number of bits for source component,
+	 * 0 = 1 bit, 1 = 2 bits, 2 = 6 bits, 3 = 8 bits
+	 */
+enum {
+	COLOR_4BIT,
+	COLOR_5BIT,
+	COLOR_6BIT,
+	COLOR_8BIT,
+};
 
-static struct mdss_mdp_format_params mdss_mdp_format_map[MDP_IMGTYPE_LIMIT] = {
-	[MDP_RGB_565] = {
-		.format = MDP_RGB_565,
+#define FMT_RGB_565(fmt, e0, e1, e2)				\
+	{							\
+		.format = (fmt),				\
+		.fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,	\
+		.unpack_tight = 1,				\
+		.unpack_align_msb = 0,				\
+		.alpha_enable = 0,				\
+		.unpack_count = 3,				\
+		.bpp = 2,					\
+		.element = { (e0), (e1), (e2) },		\
+		.bits = {					\
+			[C2_R_Cr] = COLOR_5BIT,			\
+			[C0_G_Y] = COLOR_6BIT,			\
+			[C1_B_Cb] = COLOR_5BIT,			\
+		},						\
+	}
+
+#define FMT_RGB_888(fmt, e0, e1, e2)				\
+	{							\
+		.format = (fmt),				\
+		.fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,	\
+		.unpack_tight = 1,				\
+		.unpack_align_msb = 0,				\
+		.alpha_enable = 0,				\
+		.unpack_count = 3,				\
+		.bpp = 3,					\
+		.element = { (e0), (e1), (e2) },		\
+		.bits = {					\
+			[C2_R_Cr] = COLOR_8BIT,			\
+			[C0_G_Y] = COLOR_8BIT,			\
+			[C1_B_Cb] = COLOR_8BIT,			\
+		},						\
+	}
+
+#define FMT_RGB_8888(fmt, alpha_en, e0, e1, e2, e3)		\
+	{							\
+		.format = (fmt),				\
+		.fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,	\
+		.unpack_tight = 1,				\
+		.unpack_align_msb = 0,				\
+		.alpha_enable = (alpha_en),			\
+		.unpack_count = 4,				\
+		.bpp = 4,					\
+		.element = { (e0), (e1), (e2), (e3) },		\
+		.bits = {					\
+			[C3_ALPHA] = COLOR_8BIT,		\
+			[C2_R_Cr] = COLOR_8BIT,			\
+			[C0_G_Y] = COLOR_8BIT,			\
+			[C1_B_Cb] = COLOR_8BIT,			\
+		},						\
+	}
+
+#define FMT_YUV_COMMON(fmt)					\
+		.format = (fmt),				\
+		.is_yuv = 1,					\
+		.bits = {					\
+			[C2_R_Cr] = COLOR_8BIT,			\
+			[C0_G_Y] = COLOR_8BIT,			\
+			[C1_B_Cb] = COLOR_8BIT,			\
+		},						\
+		.alpha_enable = 0,				\
+		.unpack_tight = 1,				\
+		.unpack_align_msb = 0
+
+#define FMT_YUV_PSEUDO(fmt, samp, e0, e1)			\
+	{							\
+		FMT_YUV_COMMON(fmt),				\
+		.fetch_planes = MDSS_MDP_PLANE_PSEUDO_PLANAR,	\
+		.chroma_sample = samp,				\
+		.unpack_count = 2,				\
+		.bpp = 2,					\
+		.element = { (e0), (e1) },			\
+	}
+
+#define FMT_YUV_PLANR(fmt, samp, e0, e1)			\
+	{							\
+		FMT_YUV_COMMON(fmt),				\
+		.fetch_planes = MDSS_MDP_PLANE_PLANAR,		\
+		.chroma_sample = samp,				\
+		.element = { (e0), (e1) }			\
+	}
+
+static struct mdss_mdp_format_params mdss_mdp_format_map[] = {
+	FMT_RGB_565(MDP_RGB_565, C1_B_Cb, C0_G_Y, C2_R_Cr),
+	FMT_RGB_565(MDP_BGR_565, C2_R_Cr, C0_G_Y, C1_B_Cb),
+	FMT_RGB_888(MDP_RGB_888, C2_R_Cr, C0_G_Y, C1_B_Cb),
+	FMT_RGB_888(MDP_BGR_888, C1_B_Cb, C0_G_Y, C2_R_Cr),
+
+	FMT_RGB_8888(MDP_XRGB_8888, 0, C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb),
+	FMT_RGB_8888(MDP_ARGB_8888, 1, C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb),
+	FMT_RGB_8888(MDP_RGBA_8888, 1, C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA),
+	FMT_RGB_8888(MDP_RGBX_8888, 0, C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA),
+	FMT_RGB_8888(MDP_BGRA_8888, 1, C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA),
+
+	FMT_YUV_PSEUDO(MDP_Y_CRCB_H1V1, MDSS_MDP_CHROMA_RGB, C2_R_Cr, C1_B_Cb),
+	FMT_YUV_PSEUDO(MDP_Y_CBCR_H1V1, MDSS_MDP_CHROMA_RGB, C1_B_Cb, C2_R_Cr),
+	FMT_YUV_PSEUDO(MDP_Y_CRCB_H2V1, MDSS_MDP_CHROMA_H2V1, C2_R_Cr, C1_B_Cb),
+	FMT_YUV_PSEUDO(MDP_Y_CBCR_H2V1, MDSS_MDP_CHROMA_H2V1, C1_B_Cb, C2_R_Cr),
+	FMT_YUV_PSEUDO(MDP_Y_CRCB_H1V2, MDSS_MDP_CHROMA_H1V2, C2_R_Cr, C1_B_Cb),
+	FMT_YUV_PSEUDO(MDP_Y_CBCR_H1V2, MDSS_MDP_CHROMA_H1V2, C1_B_Cb, C2_R_Cr),
+	FMT_YUV_PSEUDO(MDP_Y_CRCB_H2V2, MDSS_MDP_CHROMA_420, C2_R_Cr, C1_B_Cb),
+	FMT_YUV_PSEUDO(MDP_Y_CBCR_H2V2, MDSS_MDP_CHROMA_420, C1_B_Cb, C2_R_Cr),
+	FMT_YUV_PSEUDO(MDP_Y_CBCR_H2V2_VENUS, MDSS_MDP_CHROMA_420,
+		       C1_B_Cb, C2_R_Cr),
+
+	FMT_YUV_PLANR(MDP_Y_CR_CB_H2V2, MDSS_MDP_CHROMA_420, C2_R_Cr, C1_B_Cb),
+	FMT_YUV_PLANR(MDP_Y_CB_CR_H2V2, MDSS_MDP_CHROMA_420, C1_B_Cb, C2_R_Cr),
+	FMT_YUV_PLANR(MDP_Y_CR_CB_GH2V2, MDSS_MDP_CHROMA_420, C2_R_Cr, C1_B_Cb),
+
+	{
+		FMT_YUV_COMMON(MDP_YCBCR_H1V1),
 		.fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
-		.a_bit = 0,
-		.r_bit = 1,	/* R, 5 bits */
-		.b_bit = 1,	/* B, 5 bits */
-		.g_bit = 2,	/* G, 6 bits */
-		.alpha_enable = 0,
-		.unpack_tight = 1,
-		.unpack_align_msb = 0,
-		.unpack_count = 2,
-		.element2 = C2_R_Cr,
-		.element1 = C0_G_Y,
-		.element0 = C1_B_Cb,
-		.bpp = 1,	/* 2 bpp */
-	},
-	[MDP_BGR_565] = {
-		.format = MDP_BGR_565,
-		.fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
-		.a_bit = 0,
-		.r_bit = 1,	/* R, 5 bits */
-		.b_bit = 1,	/* B, 5 bits */
-		.g_bit = 2,	/* G, 6 bits */
-		.alpha_enable = 0,
-		.unpack_tight = 1,
-		.unpack_align_msb = 0,
-		.unpack_count = 2,
-		.element2 = C1_B_Cb,
-		.element1 = C0_G_Y,
-		.element0 = C2_R_Cr,
-		.bpp = 1,	/* 2 bpp */
-	},
-	[MDP_RGB_888] = {
-		.format = MDP_RGB_888,
-		.fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
-		.a_bit = 0,
-		.r_bit = 3,	/* R, 8 bits */
-		.b_bit = 3,	/* B, 8 bits */
-		.g_bit = 3,	/* G, 8 bits */
-		.alpha_enable = 0,
-		.unpack_tight = 1,
-		.unpack_align_msb = 0,
-		.unpack_count = 2,
-		.element2 = C1_B_Cb,
-		.element1 = C0_G_Y,
-		.element0 = C2_R_Cr,
-		.bpp = 2,	/* 3 bpp */
-	},
-	[MDP_XRGB_8888] = {
-		.format = MDP_XRGB_8888,
-		.fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
-		.a_bit = 3,	/* alpha, 4 bits */
-		.r_bit = 3,	/* R, 8 bits */
-		.b_bit = 3,	/* B, 8 bits */
-		.g_bit = 3,	/* G, 8 bits */
-		.alpha_enable = 0,
-		.unpack_tight = 1,
-		.unpack_align_msb = 0,
+		.chroma_sample = MDSS_MDP_CHROMA_RGB,
 		.unpack_count = 3,
-		.element3 = C1_B_Cb,
-		.element2 = C0_G_Y,
-		.element1 = C2_R_Cr,
-		.element0 = C3_ALPHA,
-		.bpp = 3,	/* 4 bpp */
+		.bpp = 3,
+		.element = { C2_R_Cr, C1_B_Cb, C0_G_Y },
 	},
-	[MDP_ARGB_8888] = {
-		.format = MDP_ARGB_8888,
+	{
+		FMT_YUV_COMMON(MDP_YCRCB_H1V1),
 		.fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
-		.a_bit = 3,	/* alpha, 4 bits */
-		.r_bit = 3,	/* R, 8 bits */
-		.b_bit = 3,	/* B, 8 bits */
-		.g_bit = 3,	/* G, 8 bits */
-		.alpha_enable = 1,
-		.unpack_tight = 1,
-		.unpack_align_msb = 0,
+		.chroma_sample = MDSS_MDP_CHROMA_RGB,
 		.unpack_count = 3,
-		.element3 = C1_B_Cb,
-		.element2 = C0_G_Y,
-		.element1 = C2_R_Cr,
-		.element0 = C3_ALPHA,
-		.bpp = 3,	/* 4 bpp */
+		.bpp = 3,
+		.element = { C1_B_Cb, C2_R_Cr, C0_G_Y },
 	},
-	[MDP_RGBA_8888] = {
-		.format = MDP_RGBA_8888,
-		.fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
-		.a_bit = 3,	/* alpha, 4 bits */
-		.r_bit = 3,	/* R, 8 bits */
-		.b_bit = 3,	/* B, 8 bits */
-		.g_bit = 3,	/* G, 8 bits */
-		.alpha_enable = 1,
-		.unpack_tight = 1,
-		.unpack_align_msb = 0,
-		.unpack_count = 3,
-		.element3 = C3_ALPHA,
-		.element2 = C1_B_Cb,
-		.element1 = C0_G_Y,
-		.element0 = C2_R_Cr,
-		.bpp = 3,	/* 4 bpp */
-	},
-	[MDP_RGBX_8888] = {
-		.format = MDP_RGBX_8888,
-		.fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
-		.a_bit = 3,
-		.r_bit = 3,	/* R, 8 bits */
-		.b_bit = 3,	/* B, 8 bits */
-		.g_bit = 3,	/* G, 8 bits */
-		.alpha_enable = 0,
-		.unpack_tight = 1,
-		.unpack_align_msb = 0,
-		.unpack_count = 3,
-		.element3 = C3_ALPHA,
-		.element2 = C1_B_Cb,
-		.element1 = C0_G_Y,
-		.element0 = C2_R_Cr,
-		.bpp = 3,	/* 4 bpp */
-	},
-	[MDP_BGRA_8888] = {
-		.format = MDP_BGRA_8888,
-		.fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
-		.a_bit = 3,	/* alpha, 4 bits */
-		.r_bit = 3,	/* R, 8 bits */
-		.b_bit = 3,	/* B, 8 bits */
-		.g_bit = 3,	/* G, 8 bits */
-		.alpha_enable = 1,
-		.unpack_tight = 1,
-		.unpack_align_msb = 0,
-		.unpack_count = 3,
-		.element3 = C3_ALPHA,
-		.element2 = C2_R_Cr,
-		.element1 = C0_G_Y,
-		.element0 = C1_B_Cb,
-		.bpp = 3,	/* 4 bpp */
-	},
-	[MDP_YCRYCB_H2V1] = {
-		.format = MDP_YCRYCB_H2V1,
-		.is_yuv = 1,
-		.a_bit = 0,
-		.r_bit = 3,	/* R, 8 bits */
-		.b_bit = 3,	/* B, 8 bits */
-		.g_bit = 3,	/* G, 8 bits */
-		.alpha_enable = 0,
-		.unpack_tight = 1,
-		.unpack_align_msb = 0,
-		.unpack_count = 1,	/* 2 */
-		.bpp = 1,	/* 2 bpp */
+	{
+		FMT_YUV_COMMON(MDP_YCRYCB_H2V1),
 		.fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
 		.chroma_sample = MDSS_MDP_CHROMA_H2V1,
-		.unpack_count = 3,
-		.element3 = C0_G_Y,
-		.element2 = C2_R_Cr,
-		.element1 = C0_G_Y,
-		.element0 = C1_B_Cb,
-	},
-	[MDP_Y_CRCB_H2V1] = {
-		.format = MDP_Y_CRCB_H2V1,
-		.is_yuv = 1,
-		.a_bit = 0,
-		.r_bit = 3,	/* R, 8 bits */
-		.b_bit = 3,	/* B, 8 bits */
-		.g_bit = 3,	/* G, 8 bits */
-		.alpha_enable = 0,
-		.unpack_tight = 1,
-		.unpack_align_msb = 0,
-		.unpack_count = 1,	/* 2 */
-		.bpp = 1,	/* 2 bpp */
-		.fetch_planes = MDSS_MDP_PLANE_PSEUDO_PLANAR,
-		.chroma_sample = MDSS_MDP_CHROMA_H2V1,
-		.element1 = C1_B_Cb,
-		.element0 = C2_R_Cr,
-	},
-	[MDP_Y_CBCR_H2V1] = {
-		.format = MDP_Y_CBCR_H2V1,
-		.is_yuv = 1,
-		.a_bit = 0,
-		.r_bit = 3,	/* R, 8 bits */
-		.b_bit = 3,	/* B, 8 bits */
-		.g_bit = 3,	/* G, 8 bits */
-		.alpha_enable = 0,
-		.unpack_tight = 1,
-		.unpack_align_msb = 0,
-		.unpack_count = 1,	/* 2 */
-		.bpp = 1,	/* 2 bpp */
-		.fetch_planes = MDSS_MDP_PLANE_PSEUDO_PLANAR,
-		.chroma_sample = MDSS_MDP_CHROMA_H2V1,
-		.element1 = C2_R_Cr,
-		.element0 = C1_B_Cb,
-	},
-	[MDP_Y_CRCB_H1V2] = {
-		.format = MDP_Y_CRCB_H1V2,
-		.is_yuv = 1,
-		.a_bit = 0,
-		.r_bit = 3,	/* R, 8 bits */
-		.b_bit = 3,	/* B, 8 bits */
-		.g_bit = 3,	/* G, 8 bits */
-		.alpha_enable = 0,
-		.unpack_tight = 1,
-		.unpack_align_msb = 0,
-		.unpack_count = 1,	/* 2 */
-		.bpp = 1,	/* 2 bpp */
-		.fetch_planes = MDSS_MDP_PLANE_PSEUDO_PLANAR,
-		.chroma_sample = MDSS_MDP_CHROMA_H1V2,
-		.element1 = C1_B_Cb,
-		.element0 = C2_R_Cr,
-	},
-	[MDP_Y_CBCR_H1V2] = {
-		.format = MDP_Y_CBCR_H1V2,
-		.is_yuv = 1,
-		.a_bit = 0,
-		.r_bit = 3,	/* R, 8 bits */
-		.b_bit = 3,	/* B, 8 bits */
-		.g_bit = 3,	/* G, 8 bits */
-		.alpha_enable = 0,
-		.unpack_tight = 1,
-		.unpack_align_msb = 0,
-		.unpack_count = 1,	/* 2 */
-		.bpp = 1,	/* 2 bpp */
-		.fetch_planes = MDSS_MDP_PLANE_PSEUDO_PLANAR,
-		.chroma_sample = MDSS_MDP_CHROMA_H1V2,
-		.element1 = C2_R_Cr,
-		.element0 = C1_B_Cb,
-	},
-	[MDP_Y_CRCB_H2V2] = {
-		.format = MDP_Y_CRCB_H2V2,
-		.is_yuv = 1,
-		.a_bit = 0,
-		.r_bit = 3,	/* R, 8 bits */
-		.b_bit = 3,	/* B, 8 bits */
-		.g_bit = 3,	/* G, 8 bits */
-		.alpha_enable = 0,
-		.unpack_tight = 1,
-		.unpack_align_msb = 0,
-		.unpack_count = 1,	/* 2 */
-		.bpp = 1,	/* 2 bpp */
-		.fetch_planes = MDSS_MDP_PLANE_PSEUDO_PLANAR,
-		.chroma_sample = MDSS_MDP_CHROMA_420,
-		.element1 = C1_B_Cb,
-		.element0 = C2_R_Cr,
-	},
-	[MDP_Y_CBCR_H2V2] = {
-		.format = MDP_Y_CBCR_H2V2,
-		.is_yuv = 1,
-		.a_bit = 0,
-		.r_bit = 3,	/* R, 8 bits */
-		.b_bit = 3,	/* B, 8 bits */
-		.g_bit = 3,	/* G, 8 bits */
-		.alpha_enable = 0,
-		.unpack_tight = 1,
-		.unpack_align_msb = 0,
-		.unpack_count = 1,	/* 2 */
-		.bpp = 1,	/* 2 bpp */
-		.fetch_planes = MDSS_MDP_PLANE_PSEUDO_PLANAR,
-		.chroma_sample = MDSS_MDP_CHROMA_420,
-		.element1 = C2_R_Cr,
-		.element0 = C1_B_Cb,
-	},
-	[MDP_Y_CR_CB_H2V2] = {
-		.format = MDP_Y_CR_CB_H2V2,
-		.is_yuv = 1,
-		.a_bit = 0,
-		.r_bit = 3,	/* R, 8 bits */
-		.b_bit = 3,	/* B, 8 bits */
-		.g_bit = 3,	/* G, 8 bits */
-		.alpha_enable = 0,
-		.unpack_tight = 1,
-		.unpack_align_msb = 0,
-		.unpack_count = 1,	/* 2 */
-		.bpp = 1,	/* 2 bpp */
-		.fetch_planes = MDSS_MDP_PLANE_PLANAR,
-		.chroma_sample = MDSS_MDP_CHROMA_420,
-	},
-	[MDP_Y_CB_CR_H2V2] = {
-		.format = MDP_Y_CB_CR_H2V2,
-		.is_yuv = 1,
-		.a_bit = 0,
-		.r_bit = 3,	/* R, 8 bits */
-		.b_bit = 3,	/* B, 8 bits */
-		.g_bit = 3,	/* G, 8 bits */
-		.alpha_enable = 0,
-		.unpack_tight = 1,
-		.unpack_align_msb = 0,
-		.unpack_count = 1,	/* 2 */
-		.bpp = 1,	/* 2 bpp */
-		.fetch_planes = MDSS_MDP_PLANE_PLANAR,
-		.chroma_sample = MDSS_MDP_CHROMA_420,
-	},
-	[MDP_Y_CR_CB_GH2V2] = {
-		.format = MDP_Y_CR_CB_GH2V2,
-		.is_yuv = 1,
-		.a_bit = 0,
-		.r_bit = 3,	/* R, 8 bits */
-		.b_bit = 3,	/* B, 8 bits */
-		.g_bit = 3,	/* G, 8 bits */
-		.alpha_enable = 0,
-		.unpack_tight = 1,
-		.unpack_align_msb = 0,
-		.unpack_count = 1,	/* 2 */
-		.bpp = 1,	/* 2 bpp */
-		.fetch_planes = MDSS_MDP_PLANE_PLANAR,
-		.chroma_sample = MDSS_MDP_CHROMA_420,
+		.unpack_count = 4,
+		.bpp = 2,
+		.element = { C1_B_Cb, C0_G_Y, C2_R_Cr, C0_G_Y },
 	},
 };
 #endif
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index 2f0a1f5..5d8dd86 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -13,6 +13,8 @@
 
 #define pr_fmt(fmt)	"%s: " fmt, __func__
 
+#include <linux/workqueue.h>
+
 #include "mdss_fb.h"
 #include "mdss_mdp.h"
 
@@ -44,6 +46,12 @@
 	u8 timegen_en;
 	struct completion pp_comp;
 	struct completion vsync_comp;
+
+	struct mutex vsync_lock;
+	struct work_struct vsync_work;
+	mdp_vsync_handler_t vsync_handler;
+	void *vsync_ptr;
+	ktime_t vsync_time;
 };
 
 struct mdss_mdp_video_ctx mdss_mdp_video_ctx_list[MAX_SESSIONS];
@@ -54,6 +62,7 @@
 	u32 hsync_period, vsync_period;
 	u32 hsync_start_x, hsync_end_x, display_v_start, display_v_end;
 	u32 active_h_start, active_h_end, active_v_start, active_v_end;
+	u32 den_polarity, hsync_polarity, vsync_polarity;
 	u32 display_hctl, active_hctl, hsync_ctl, polarity_ctl;
 	int off;
 
@@ -106,9 +115,18 @@
 
 	hsync_ctl = (hsync_period << 16) | p->hsync_pulse_width;
 	display_hctl = (hsync_end_x << 16) | hsync_start_x;
-	polarity_ctl = (0 << 2) |	/* DEN Polarity */
-		       (0 << 1) |      /* VSYNC Polarity */
-		       (0);	       /* HSYNC Polarity */
+
+	den_polarity = 0;
+	if (MDSS_INTF_HDMI ==  ctl->intf_type) {
+		hsync_polarity = p->yres >= 720 ? 0 : 1;
+		vsync_polarity = p->yres >= 720 ? 0 : 1;
+	} else {
+		hsync_polarity = 0;
+		vsync_polarity = 0;
+	}
+	polarity_ctl = (den_polarity << 2)   | /*  DEN Polarity  */
+		       (vsync_polarity << 1) | /* VSYNC Polarity */
+		       (hsync_polarity << 0);  /* HSYNC Polarity */
 
 	MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_HSYNC_CTL, hsync_ctl);
 	MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_VSYNC_PERIOD_F0,
@@ -141,6 +159,47 @@
 	return 0;
 }
 
+static void send_vsync_work(struct work_struct *work)
+{
+	struct mdss_mdp_video_ctx *ctx;
+
+	ctx = container_of(work, typeof(*ctx), vsync_work);
+	mutex_lock(&ctx->vsync_lock);
+	if (ctx->vsync_handler)
+		ctx->vsync_handler(ctx->vsync_ptr, ctx->vsync_time);
+	mutex_unlock(&ctx->vsync_lock);
+}
+
+static int mdss_mdp_video_set_vsync_handler(struct mdss_mdp_ctl *ctl,
+		mdp_vsync_handler_t vsync_handler)
+{
+	struct mdss_mdp_video_ctx *ctx;
+
+	ctx = (struct mdss_mdp_video_ctx *) ctl->priv_data;
+	if (!ctx) {
+		pr_err("invalid ctx for ctl=%d\n", ctl->num);
+		return -ENODEV;
+	}
+	if (mutex_lock_interruptible(&ctx->vsync_lock))
+		return -EINTR;
+
+	if (!ctx->timegen_en) {
+		ctx->vsync_time = ktime_get();
+		schedule_work(&ctx->vsync_work);
+	}
+
+	if (!ctx->vsync_handler && vsync_handler)
+		mdss_mdp_irq_enable(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num);
+	else if (ctx->vsync_handler && !vsync_handler)
+		mdss_mdp_irq_disable(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num);
+
+	ctx->vsync_handler = vsync_handler;
+	ctx->vsync_ptr = ctl;
+	mutex_unlock(&ctx->vsync_lock);
+
+	return 0;
+}
+
 static int mdss_mdp_video_stop(struct mdss_mdp_ctl *ctl)
 {
 	struct mdss_mdp_video_ctx *ctx;
@@ -161,6 +220,11 @@
 		ctx->timegen_en = false;
 	}
 
+	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num,
+				   NULL, NULL);
+	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num,
+				   NULL, NULL);
+
 	memset(ctx, 0, sizeof(*ctx));
 
 	return 0;
@@ -190,10 +254,13 @@
 		pr_err("invalid ctx\n");
 		return;
 	}
+	ctx->vsync_time = ktime_get();
 
 	pr_debug("intr ctl=%d\n", ctx->ctl_num);
 
 	complete(&ctx->vsync_comp);
+	if (ctx->vsync_handler)
+		schedule_work(&ctx->vsync_work);
 }
 
 static int mdss_mdp_video_prepare(struct mdss_mdp_ctl *ctl, void *arg)
@@ -207,15 +274,10 @@
 	}
 
 	if (ctx->timegen_en) {
-		u32 intr_type = MDSS_MDP_IRQ_PING_PONG_COMP;
-
 		pr_debug("waiting for ping pong %d done\n", ctx->pp_num);
-		mdss_mdp_set_intr_callback(intr_type, ctx->pp_num,
-					   mdss_mdp_video_pp_intr_done, ctx);
-		mdss_mdp_irq_enable(intr_type, ctx->pp_num);
-
+		mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num);
 		wait_for_completion_interruptible(&ctx->pp_comp);
-		mdss_mdp_irq_disable(intr_type, ctx->pp_num);
+		mdss_mdp_irq_disable(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num);
 	}
 
 	return 0;
@@ -224,7 +286,6 @@
 static int mdss_mdp_video_display(struct mdss_mdp_ctl *ctl, void *arg)
 {
 	struct mdss_mdp_video_ctx *ctx;
-	u32 intr_type = MDSS_MDP_IRQ_INTF_VSYNC;
 
 	pr_debug("kickoff ctl=%d\n", ctl->num);
 
@@ -233,9 +294,12 @@
 		pr_err("invalid ctx\n");
 		return -ENODEV;
 	}
-	mdss_mdp_set_intr_callback(intr_type, ctl->intf_num,
-				   mdss_mdp_video_vsync_intr_done, ctx);
-	mdss_mdp_irq_enable(intr_type, ctl->intf_num);
+	INIT_COMPLETION(ctx->vsync_comp);
+
+	if (mutex_lock_interruptible(&ctx->vsync_lock))
+		return -EINTR;
+	if (!ctx->vsync_handler)
+		mdss_mdp_irq_enable(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num);
 
 	if (!ctx->timegen_en) {
 		int off = MDSS_MDP_REG_INTF_OFFSET(ctl->intf_num);
@@ -249,7 +313,9 @@
 	}
 
 	wait_for_completion_interruptible(&ctx->vsync_comp);
-	mdss_mdp_irq_disable(intr_type, ctl->intf_num);
+	if (!ctx->vsync_handler)
+		mdss_mdp_irq_disable(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num);
+	mutex_unlock(&ctx->vsync_lock);
 
 	return 0;
 }
@@ -293,6 +359,13 @@
 	init_completion(&ctx->pp_comp);
 	init_completion(&ctx->vsync_comp);
 
+	INIT_WORK(&ctx->vsync_work, send_vsync_work);
+	mutex_init(&ctx->vsync_lock);
+	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num,
+				   mdss_mdp_video_vsync_intr_done, ctx);
+	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num,
+				   mdss_mdp_video_pp_intr_done, ctx);
+
 	itp.width = pinfo->xres + pinfo->lcdc.xres_pad;
 	itp.height = pinfo->yres + pinfo->lcdc.yres_pad;
 	itp.border_clr = pinfo->lcdc.border_clr;
@@ -304,7 +377,7 @@
 	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.h_front_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;
 
@@ -316,6 +389,7 @@
 	ctl->stop_fnc = mdss_mdp_video_stop;
 	ctl->prepare_fnc = mdss_mdp_video_prepare;
 	ctl->display_fnc = mdss_mdp_video_display;
+	ctl->set_vsync_handler = mdss_mdp_video_set_vsync_handler;
 
 	return 0;
 }
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
index af422b7..8b4434e 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
@@ -145,20 +145,24 @@
 
 	dst_format = (chroma_samp << 23) |
 		     (fmt->fetch_planes << 19) |
-		     (fmt->unpack_align_msb << 18) |
-		     (fmt->unpack_tight << 17) |
-		     (fmt->unpack_count << 12) |
-		     (fmt->bpp << 9) |
-		     (fmt->alpha_enable << 8) |
-		     (fmt->a_bit << 6) |
-		     (fmt->r_bit << 4) |
-		     (fmt->b_bit << 2) |
-		     (fmt->g_bit << 0);
+		     (fmt->bits[C3_ALPHA] << 6) |
+		     (fmt->bits[C2_R_Cr] << 4) |
+		     (fmt->bits[C1_B_Cb] << 2) |
+		     (fmt->bits[C0_G_Y] << 0);
 
-	pattern = (fmt->element3 << 24) |
-		  (fmt->element2 << 15) |
-		  (fmt->element1 << 8) |
-		  (fmt->element0 << 0);
+	if (fmt->alpha_enable)
+		dst_format |= BIT(8); /* DSTC3_EN */
+
+	if (fmt->fetch_planes != MDSS_MDP_PLANE_PLANAR) {
+		pattern = (fmt->element[3] << 24) | (fmt->element[2] << 15) |
+			(fmt->element[1] << 8) | (fmt->element[0] << 0);
+		dst_format |= (fmt->unpack_align_msb << 18) |
+			      (fmt->unpack_tight << 17) |
+			      ((fmt->unpack_count - 1) << 12) |
+			      ((fmt->bpp - 1) << 9);
+	} else {
+		pattern = 0;
+	}
 
 	ystride0 = (ctx->dst_planes.ystride[0]) |
 		   (ctx->dst_planes.ystride[1] << 16);
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 2e9a2dc..e8e8163 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -13,12 +13,15 @@
 
 #define pr_fmt(fmt)	"%s: " fmt, __func__
 
+#include <linux/dma-mapping.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/major.h>
 #include <linux/module.h>
 #include <linux/uaccess.h>
 
+#include <mach/iommu_domains.h>
+
 #include "mdss_fb.h"
 #include "mdss_mdp.h"
 #include "mdss_mdp_rotator.h"
@@ -48,7 +51,6 @@
 				      struct mdss_mdp_format_params *fmt)
 {
 	u32 xres, yres;
-	u32 dst_w, dst_h;
 
 	xres = mfd->fbi->var.xres;
 	yres = mfd->fbi->var.yres;
@@ -61,32 +63,45 @@
 	if (req->src.width > MAX_IMG_WIDTH ||
 	    req->src.height > MAX_IMG_HEIGHT ||
 	    req->src_rect.w == 0 || req->src_rect.h == 0 ||
-	    req->dst_rect.w < MIN_DST_W || req->dst_rect.h < MIN_DST_H ||
-	    req->dst_rect.w > MAX_DST_W || req->dst_rect.h > MAX_DST_H ||
 	    CHECK_BOUNDS(req->src_rect.x, req->src_rect.w, req->src.width) ||
-	    CHECK_BOUNDS(req->src_rect.y, req->src_rect.h, req->src.height) ||
-	    CHECK_BOUNDS(req->dst_rect.x, req->dst_rect.w, xres) ||
-	    CHECK_BOUNDS(req->dst_rect.y, req->dst_rect.h, yres)) {
-		pr_err("invalid image img_w=%d img_h=%d\n",
-				req->src.width, req->src.height);
-
-		pr_err("\tsrc_rect=%d,%d,%d,%d dst_rect=%d,%d,%d,%d\n",
+	    CHECK_BOUNDS(req->src_rect.y, req->src_rect.h, req->src.height)) {
+		pr_err("invalid source image img wh=%dx%d rect=%d,%d,%d,%d\n",
+		       req->src.width, req->src.height,
 		       req->src_rect.x, req->src_rect.y,
-		       req->src_rect.w, req->src_rect.h,
-		       req->dst_rect.x, req->dst_rect.y,
+		       req->src_rect.w, req->src_rect.h);
+		return -EOVERFLOW;
+	}
+
+	if (req->dst_rect.w < MIN_DST_W || req->dst_rect.h < MIN_DST_H ||
+	    req->dst_rect.w > MAX_DST_W || req->dst_rect.h > MAX_DST_H) {
+		pr_err("invalid destination resolution (%dx%d)",
 		       req->dst_rect.w, req->dst_rect.h);
-		return -EINVAL;
+		return -EOVERFLOW;
 	}
 
-	if (req->flags & MDP_ROT_90) {
-		dst_h = req->dst_rect.w;
-		dst_w = req->dst_rect.h;
+	if (req->flags & MDSS_MDP_ROT_ONLY) {
+		/* dst res should match src res in rotation only mode*/
+		req->dst_rect.w = req->src_rect.w;
+		req->dst_rect.h = req->src_rect.h;
 	} else {
-		dst_w = req->dst_rect.w;
-		dst_h = req->dst_rect.h;
-	}
+		u32 dst_w, dst_h;
 
-	if (!(req->flags & MDSS_MDP_ROT_ONLY)) {
+		if ((CHECK_BOUNDS(req->dst_rect.x, req->dst_rect.w, xres) ||
+		     CHECK_BOUNDS(req->dst_rect.y, req->dst_rect.h, yres))) {
+			pr_err("invalid destination rect=%d,%d,%d,%d\n",
+			       req->dst_rect.x, req->dst_rect.y,
+			       req->dst_rect.w, req->dst_rect.h);
+			return -EOVERFLOW;
+		}
+
+		if (req->flags & MDP_ROT_90) {
+			dst_h = req->dst_rect.w;
+			dst_w = req->dst_rect.h;
+		} else {
+			dst_w = req->dst_rect.w;
+			dst_h = req->dst_rect.h;
+		}
+
 		if ((req->src_rect.w * MAX_UPSCALE_RATIO) < dst_w) {
 			pr_err("too much upscaling Width %d->%d\n",
 			       req->src_rect.w, req->dst_rect.w);
@@ -110,6 +125,22 @@
 			       req->src_rect.h, req->dst_rect.h);
 			return -EINVAL;
 		}
+
+		if ((fmt->chroma_sample == MDSS_MDP_CHROMA_420 ||
+		     fmt->chroma_sample == MDSS_MDP_CHROMA_H2V1) &&
+		    ((req->src_rect.w * (MAX_UPSCALE_RATIO / 2)) < dst_w)) {
+			pr_err("too much YUV upscaling Width %d->%d\n",
+			       req->src_rect.w, req->dst_rect.w);
+			return -EINVAL;
+		}
+
+		if ((fmt->chroma_sample == MDSS_MDP_CHROMA_420 ||
+		     fmt->chroma_sample == MDSS_MDP_CHROMA_H1V2) &&
+		    (req->src_rect.h * (MAX_UPSCALE_RATIO / 2)) < dst_h) {
+			pr_err("too much YUV upscaling Height %d->%d\n",
+			       req->src_rect.h, req->dst_rect.h);
+			return -EINVAL;
+		}
 	}
 
 	if (fmt->is_yuv) {
@@ -122,22 +153,6 @@
 			pr_err("invalid odd dst resolution\n");
 			return -EINVAL;
 		}
-
-		if (((req->src_rect.w * (MAX_UPSCALE_RATIO / 2)) < dst_w) &&
-		    (fmt->chroma_sample == MDSS_MDP_CHROMA_420 ||
-		     fmt->chroma_sample == MDSS_MDP_CHROMA_H2V1)) {
-			pr_err("too much YUV upscaling Width %d->%d\n",
-			       req->src_rect.w, req->dst_rect.w);
-			return -EINVAL;
-		}
-
-		if (((req->src_rect.h * (MAX_UPSCALE_RATIO / 2)) < dst_h) &&
-		    (fmt->chroma_sample == MDSS_MDP_CHROMA_420 ||
-		     fmt->chroma_sample == MDSS_MDP_CHROMA_H1V2)) {
-			pr_err("too much YUV upscaling Height %d->%d\n",
-			       req->src_rect.h, req->dst_rect.h);
-			return -EINVAL;
-		}
 	}
 
 	return 0;
@@ -266,6 +281,9 @@
 			return -ENOMEM;
 		}
 
+		mutex_lock(&mfd->lock);
+		list_add(&pipe->list, &mfd->overlay_list);
+		mutex_unlock(&mfd->lock);
 		pipe->mixer = mixer;
 		pipe->mfd = mfd;
 	} else {
@@ -330,6 +348,79 @@
 	return ret;
 }
 
+static inline int mdss_mdp_overlay_get_buf(struct msm_fb_data_type *mfd,
+					   struct mdss_mdp_data *data,
+					   struct msmfb_data *planes,
+					   int num_planes)
+{
+	int i;
+
+	memset(data, 0, sizeof(*data));
+	for (i = 0; i < num_planes; i++) {
+		mdss_mdp_get_img(&planes[i], &data->p[i]);
+		if (data->p[0].len == 0)
+			break;
+	}
+
+	if (i != num_planes) {
+		for (; i >= 0; i--)
+			mdss_mdp_put_img(&data->p[i]);
+		return -ENOMEM;
+	}
+
+	data->num_planes = num_planes;
+
+	return 0;
+}
+
+static inline int mdss_mdp_overlay_free_buf(struct mdss_mdp_data *data)
+{
+	int i;
+	for (i = 0; i < data->num_planes && data->p[i].len; i++)
+		mdss_mdp_put_img(&data->p[i]);
+
+	data->num_planes = 0;
+
+	return 0;
+}
+
+static int mdss_mdp_overlay_kickoff(struct mdss_mdp_ctl *ctl)
+{
+	int ret;
+
+	if (ctl->mfd->kickoff_fnc)
+		ret = ctl->mfd->kickoff_fnc(ctl);
+	else
+		ret = mdss_mdp_display_commit(ctl, NULL);
+	if (IS_ERR_VALUE(ret))
+		return ret;
+
+	pr_debug("freeing previous buffers\n");
+
+	mutex_lock(&ctl->mfd->lock);
+	if (!list_empty(&ctl->mfd->overlay_list)) {
+		struct mdss_mdp_pipe *pipe;
+		struct mdss_mdp_data *data;
+		int buf_ndx;
+
+		list_for_each_entry(pipe, &ctl->mfd->overlay_list, list) {
+			buf_ndx = (pipe->play_cnt - 1) & 1; /* prev buffer */
+			data = &pipe->buffers[buf_ndx];
+
+			if (data->num_planes) {
+				pr_debug("free buffer ndx=%d pnum=%d\n",
+						buf_ndx, pipe->num);
+				mdss_mdp_overlay_free_buf(data);
+			}
+		}
+	}
+	mutex_unlock(&ctl->mfd->lock);
+
+	pr_debug("done freeing previous buffers\n");
+
+	return ret;
+}
+
 static int mdss_mdp_overlay_unset(struct msm_fb_data_type *mfd, int ndx)
 {
 	struct mdss_mdp_pipe *pipe;
@@ -361,6 +452,9 @@
 			unset_ndx |= pipe_ndx;
 			pipe = mdss_mdp_pipe_get_locked(pipe_ndx);
 			if (pipe) {
+				mutex_lock(&mfd->lock);
+				list_del(&pipe->list);
+				mutex_unlock(&mfd->lock);
 				mdss_mdp_mixer_pipe_unstage(pipe);
 				cleanup_pipes[clean_cnt++] = pipe;
 			} else {
@@ -370,15 +464,51 @@
 	}
 
 	if (clean_cnt) {
-		ret = mfd->kickoff_fnc(mfd->ctl);
+		int j;
+		ret = mdss_mdp_overlay_kickoff(mfd->ctl);
 
-		for (i = 0; i < clean_cnt; i++)
-			mdss_mdp_pipe_destroy(cleanup_pipes[i]);
+		for (i = 0; i < clean_cnt; i++) {
+			pipe = cleanup_pipes[i];
+			for (j = 0; j < ARRAY_SIZE(pipe->buffers); j++)
+				mdss_mdp_overlay_free_buf(&pipe->buffers[i]);
+
+			mdss_mdp_pipe_destroy(pipe);
+		}
 	}
 
 	return ret;
 }
 
+int mdss_mdp_overlay_release_all(struct msm_fb_data_type *mfd)
+{
+	struct mdss_mdp_pipe *pipe;
+	u32 unset_ndx = 0;
+	int cnt = 0;
+
+	mutex_lock(&mfd->lock);
+	if (!list_empty(&mfd->overlay_list)) {
+		list_for_each_entry(pipe, &mfd->overlay_list, list) {
+			if (pipe->ndx & MDSS_MDP_ROT_SESSION_MASK) {
+				struct mdss_mdp_rotator_session *rot;
+				rot = mdss_mdp_rotator_session_get(pipe->ndx);
+				if (rot)
+					mdss_mdp_rotator_finish(rot);
+			} else {
+				unset_ndx |= pipe->ndx;
+				cnt++;
+			}
+		}
+	}
+	mutex_unlock(&mfd->lock);
+
+	if (unset_ndx) {
+		pr_debug("%d pipes need cleanup (%x)\n", cnt, unset_ndx);
+		mdss_mdp_overlay_unset(mfd, unset_ndx);
+	}
+
+	return 0;
+}
+
 static int mdss_mdp_overlay_play_wait(struct msm_fb_data_type *mfd,
 				      struct msmfb_overlay_data *req)
 {
@@ -387,41 +517,59 @@
 	if (!mfd || !mfd->ctl)
 		return -ENODEV;
 
-	ret = mfd->kickoff_fnc(mfd->ctl);
+	ret = mdss_mdp_overlay_kickoff(mfd->ctl);
 	if (!ret)
 		pr_err("error displaying\n");
 
 	return ret;
 }
 
-static int mdss_mdp_overlay_rotate(struct msmfb_overlay_data *req,
-				   struct mdss_mdp_data *src_data,
-				   struct mdss_mdp_data *dst_data)
+static int mdss_mdp_overlay_rotate(struct msm_fb_data_type *mfd,
+				   struct msmfb_overlay_data *req)
 {
 	struct mdss_mdp_rotator_session *rot;
+	struct mdss_mdp_data src_data, dst_data;
 	int ret;
 
+	ret = mdss_mdp_overlay_get_buf(mfd, &src_data, &req->data, 1);
+	if (ret) {
+		pr_err("src_data pmem error\n");
+		goto rotate_done;
+	}
+
+	ret = mdss_mdp_overlay_get_buf(mfd, &dst_data, &req->dst_data, 1);
+	if (ret) {
+		pr_err("dst_data pmem error\n");
+		goto rotate_done;
+	}
+
 	rot = mdss_mdp_rotator_session_get(req->id);
 	if (!rot) {
 		pr_err("invalid session id=%x\n", req->id);
-		return -ENODEV;
+		ret = -ENODEV;
+		goto rotate_done;
 	}
 
-	ret = mdss_mdp_rotator_queue(rot, src_data, dst_data);
+	ret = mdss_mdp_rotator_queue(rot, &src_data, &dst_data);
 	if (ret) {
 		pr_err("rotator queue error session id=%x\n", req->id);
-		return ret;
+		goto rotate_done;
 	}
 
+rotate_done:
+	mdss_mdp_overlay_free_buf(&dst_data);
+	mdss_mdp_overlay_free_buf(&src_data);
+
 	return 0;
 }
 
-static int mdss_mdp_overlay_queue(struct msmfb_overlay_data *req,
-				  struct mdss_mdp_data *src_data)
+static int mdss_mdp_overlay_queue(struct msm_fb_data_type *mfd,
+				  struct msmfb_overlay_data *req)
 {
-	struct mdss_mdp_pipe *pipe;
 	struct mdss_mdp_ctl *ctl;
-	int ret;
+	struct mdss_mdp_pipe *pipe;
+	struct mdss_mdp_data *src_data;
+	int ret, buf_ndx;
 
 	pipe = mdss_mdp_pipe_get_locked(req->id);
 	if (pipe == NULL) {
@@ -431,13 +579,23 @@
 
 	pr_debug("ov queue pnum=%d\n", pipe->num);
 
-	ret = mdss_mdp_pipe_queue_data(pipe, src_data);
+	buf_ndx = (pipe->play_cnt + 1) & 1; /* next buffer */
+	src_data = &pipe->buffers[buf_ndx];
+	mdss_mdp_overlay_free_buf(src_data);
+
+	ret = mdss_mdp_overlay_get_buf(mfd, src_data, &req->data, 1);
+	if (IS_ERR_VALUE(ret)) {
+		pr_err("src_data pmem error\n");
+	} else {
+		ret = mdss_mdp_pipe_queue_data(pipe, src_data);
+		if (IS_ERR_VALUE(ret))
+			mdss_mdp_overlay_free_buf(src_data);
+	}
 	ctl = pipe->mixer->ctl;
 	mdss_mdp_pipe_unlock(pipe);
 
 	if (ret == 0 && !(pipe->flags & MDP_OV_PLAY_NOWAIT))
-		ret = ctl->mfd->kickoff_fnc(ctl);
-
+		ret = mdss_mdp_overlay_kickoff(ctl);
 
 	return ret;
 }
@@ -445,41 +603,14 @@
 static int mdss_mdp_overlay_play(struct msm_fb_data_type *mfd,
 				 struct msmfb_overlay_data *req)
 {
-	struct mdss_mdp_data src_data;
 	int ret = 0;
 
-	if (mfd == NULL)
-		return -ENODEV;
-
 	pr_debug("play req id=%x\n", req->id);
 
-	memset(&src_data, 0, sizeof(src_data));
-	mdss_mdp_get_img(mfd->iclient, &req->data, &src_data.p[0]);
-	if (src_data.p[0].len == 0) {
-		pr_err("src data pmem error\n");
-		return -ENOMEM;
-	}
-	src_data.num_planes = 1;
-
-	if (req->id & MDSS_MDP_ROT_SESSION_MASK) {
-		struct mdss_mdp_data dst_data;
-		memset(&dst_data, 0, sizeof(dst_data));
-
-		mdss_mdp_get_img(mfd->iclient, &req->dst_data, &dst_data.p[0]);
-		if (dst_data.p[0].len == 0) {
-			pr_err("dst data pmem error\n");
-			return -ENOMEM;
-		}
-		dst_data.num_planes = 1;
-
-		ret = mdss_mdp_overlay_rotate(req, &src_data, &dst_data);
-
-		mdss_mdp_put_img(&dst_data.p[0]);
-	} else {
-		ret = mdss_mdp_overlay_queue(req, &src_data);
-	}
-
-	mdss_mdp_put_img(&src_data.p[0]);
+	if (req->id & MDSS_MDP_ROT_SESSION_MASK)
+		ret = mdss_mdp_overlay_rotate(mfd, req);
+	else
+		ret = mdss_mdp_overlay_queue(mfd, req);
 
 	return ret;
 }
@@ -494,24 +625,26 @@
 					 MDSS_MDP_STAGE_BASE);
 	if (pipe == NULL) {
 		struct mdp_overlay req;
-		int ret;
+		struct fb_info *fbi = mfd->fbi;
+		int ret, bpp;
 
 		memset(&req, 0, sizeof(req));
 
+		bpp = fbi->var.bits_per_pixel / 8;
 		req.id = MSMFB_NEW_REQUEST;
 		req.src.format = mfd->fb_imgType;
-		req.src.height = mfd->fbi->var.yres;
-		req.src.width = mfd->fbi->var.xres;
+		req.src.height = fbi->var.yres;
+		req.src.width = fbi->fix.line_length / bpp;
 		if (mixer_mux == MDSS_MDP_MIXER_MUX_RIGHT) {
 			if (req.src.width <= MAX_MIXER_WIDTH)
 				return -ENODEV;
 
 			req.flags |= MDSS_MDP_RIGHT_MIXER;
 			req.src_rect.x = MAX_MIXER_WIDTH;
-			req.src_rect.w = req.src.width - MAX_MIXER_WIDTH;
+			req.src_rect.w = fbi->var.xres - MAX_MIXER_WIDTH;
 		} else {
 			req.src_rect.x = 0;
-			req.src_rect.w = MIN(req.src.width, MAX_MIXER_WIDTH);
+			req.src_rect.w = MIN(fbi->var.xres, MAX_MIXER_WIDTH);
 		}
 
 		req.src_rect.y = 0;
@@ -562,7 +695,18 @@
 	offset = fbi->var.xoffset * bpp +
 		 fbi->var.yoffset * fbi->fix.line_length;
 
-	data.p[0].addr = fbi->fix.smem_start + offset;
+	if (offset > fbi->fix.smem_len) {
+		pr_err("invalid fb offset=%u total length=%u\n",
+		       offset, fbi->fix.smem_len);
+		return;
+	}
+
+	if (is_mdss_iommu_attached())
+		data.p[0].addr = mfd->iova;
+	else
+		data.p[0].addr = fbi->fix.smem_start;
+
+	data.p[0].addr += offset;
 	data.p[0].len = fbi->fix.smem_len - offset;
 	data.num_planes = 1;
 
@@ -597,18 +741,83 @@
 	}
 
 	if (fbi->var.activate & FB_ACTIVATE_VBL)
-		mfd->kickoff_fnc(mfd->ctl);
+		mdss_mdp_overlay_kickoff(mfd->ctl);
 }
 
-static int mdss_mdp_hw_cursor_update(struct fb_info *info,
+static void mdss_mdp_overlay_handle_vsync(struct mdss_mdp_ctl *ctl, ktime_t t)
+{
+	struct device *dev;
+	char buf[64];
+	char *envp[2];
+
+	if (!ctl || !ctl->mfd || !ctl->mfd->fbi) {
+		pr_warn("Invalid handle for vsync\n");
+		return;
+	}
+
+	dev = ctl->mfd->fbi->dev;
+
+	snprintf(buf, sizeof(buf), "VSYNC=%llu", ktime_to_ns(t));
+	envp[0] = buf;
+	envp[1] = NULL;
+	kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
+
+	pr_debug("sent vsync on ctl=%d ts=%llu\n", ctl->num, ktime_to_ns(t));
+}
+
+static int mdss_mdp_overlay_vsync_ctrl(struct msm_fb_data_type *mfd, int en)
+{
+	struct mdss_mdp_ctl *ctl = mfd->ctl;
+	int rc;
+
+	if (!ctl)
+		return -ENODEV;
+	if (!ctl->set_vsync_handler)
+		return -ENOTSUPP;
+
+	pr_debug("vsync en=%d\n", en);
+
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+	if (en)
+		rc = ctl->set_vsync_handler(ctl, mdss_mdp_overlay_handle_vsync);
+	else
+		rc = ctl->set_vsync_handler(ctl, NULL);
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+	return rc;
+}
+
+static int mdss_mdp_hw_cursor_update(struct msm_fb_data_type *mfd,
 				     struct fb_cursor *cursor)
 {
-	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
 	struct mdss_mdp_mixer *mixer;
 	struct fb_image *img = &cursor->image;
-	int calpha_en, transp_en, blendcfg, alpha;
+	u32 blendcfg;
 	int off, ret = 0;
 
+	if (!mfd->cursor_buf && (cursor->set & FB_CUR_SETIMAGE)) {
+		mfd->cursor_buf = dma_alloc_coherent(NULL, MDSS_MDP_CURSOR_SIZE,
+					(dma_addr_t *) &mfd->cursor_buf_phys,
+					GFP_KERNEL);
+		if (!mfd->cursor_buf) {
+			pr_err("can't allocate cursor buffer\n");
+			return -ENOMEM;
+		}
+
+		ret = msm_iommu_map_contig_buffer(mfd->cursor_buf_phys,
+						mdss_get_iommu_domain(), 0,
+						MDSS_MDP_CURSOR_SIZE, SZ_4K,
+						0, &(mfd->cursor_buf_iova));
+		if (IS_ERR_VALUE(ret)) {
+			dma_free_coherent(NULL, MDSS_MDP_CURSOR_SIZE,
+					  mfd->cursor_buf,
+					  (dma_addr_t) mfd->cursor_buf_phys);
+			pr_err("unable to map cursor buffer to iommu(%d)\n",
+			       ret);
+			return -ENOMEM;
+		}
+	}
+
 	mixer = mdss_mdp_mixer_get(mfd->ctl, MDSS_MDP_MIXER_MUX_DEFAULT);
 	off = MDSS_MDP_REG_LM_OFFSET(mixer->num);
 
@@ -628,11 +837,17 @@
 				   (img->dy << 16) | img->dx);
 
 	if (cursor->set & FB_CUR_SETIMAGE) {
+		int calpha_en, transp_en, alpha, size, cursor_addr;
 		ret = copy_from_user(mfd->cursor_buf, img->data,
 				     img->width * img->height * 4);
 		if (ret)
 			return ret;
 
+		if (is_mdss_iommu_attached())
+			cursor_addr = mfd->cursor_buf_iova;
+		else
+			cursor_addr = mfd->cursor_buf_phys;
+
 		if (img->bg_color == 0xffffffff)
 			transp_en = 0;
 		else
@@ -645,12 +860,13 @@
 		else
 			calpha_en = 0x2; /* argb */
 
-		MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_CURSOR_SIZE,
-				   (img->height << 16) | img->width);
+		size = (img->height << 16) | img->width;
+		MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_CURSOR_IMG_SIZE, size);
+		MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_CURSOR_SIZE, size);
 		MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_CURSOR_STRIDE,
 				   img->width * 4);
 		MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_CURSOR_BASE_ADDR,
-				   mfd->cursor_buf_phys);
+				   cursor_addr);
 
 		wmb();
 
@@ -682,10 +898,13 @@
 	}
 
 	if (!cursor->enable != !(blendcfg & 0x1)) {
-		if (cursor->enable)
+		if (cursor->enable) {
+			pr_debug("enable hw cursor on mixer=%d\n", mixer->num);
 			blendcfg |= 0x1;
-		else
+		} else {
+			pr_debug("disable hw cursor on mixer=%d\n", mixer->num);
 			blendcfg &= ~0x1;
+		}
 
 		MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_CURSOR_BLEND_CONFIG,
 				   blendcfg);
@@ -700,11 +919,6 @@
 	return 0;
 }
 
-static int mdss_mdp_overlay_kickoff(struct mdss_mdp_ctl *ctl)
-{
-	return mdss_mdp_display_commit(ctl, NULL);
-}
-
 static int mdss_mdp_overlay_ioctl_handler(struct msm_fb_data_type *mfd,
 					  u32 cmd, void __user *argp)
 {
@@ -793,6 +1007,16 @@
 		}
 		break;
 
+	case MSMFB_VSYNC_CTRL:
+	case MSMFB_OVERLAY_VSYNC_CTRL:
+		if (!copy_from_user(&val, argp, sizeof(val))) {
+			ret = mdss_mdp_overlay_vsync_ctrl(mfd, val);
+		} else {
+			pr_err("MSMFB_OVERLAY_VSYNC_CTRL failed (%d)\n", ret);
+			ret = -EFAULT;
+		}
+		break;
+
 	default:
 		if (mfd->panel_info.type == WRITEBACK_PANEL)
 			ret = mdss_mdp_wb_ioctl_handler(mfd, cmd, argp);
@@ -807,7 +1031,6 @@
 	mfd->on_fnc = mdss_mdp_ctl_on;
 	mfd->off_fnc = mdss_mdp_ctl_off;
 	mfd->hw_refresh = true;
-	mfd->lut_update = NULL;
 	mfd->do_histogram = NULL;
 	mfd->overlay_play_enable = true;
 	mfd->cursor_update = mdss_mdp_hw_cursor_update;
@@ -816,8 +1039,8 @@
 
 	if (mfd->panel_info.type == WRITEBACK_PANEL)
 		mfd->kickoff_fnc = mdss_mdp_wb_kickoff;
-	else
-		mfd->kickoff_fnc = mdss_mdp_overlay_kickoff;
+
+	INIT_LIST_HEAD(&mfd->overlay_list);
 
 	return 0;
 }
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index d9a148e..c936b7d 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -272,35 +272,6 @@
 	return 0;
 }
 
-int mdss_mdp_pipe_release_all(struct msm_fb_data_type *mfd)
-{
-	struct mdss_mdp_pipe *pipe;
-	int i;
-
-	if (!mfd)
-		return -ENODEV;
-
-	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
-	mutex_lock(&mdss_mdp_sspp_lock);
-	for (i = 0; i < MDSS_MDP_MAX_SSPP; i++) {
-		pipe = &mdss_mdp_pipe_list[i];
-		if (atomic_read(&pipe->ref_cnt) && pipe->mfd == mfd) {
-			pr_debug("release pnum=%d\n", pipe->num);
-			if (mdss_mdp_pipe_lock(pipe) == 0) {
-				mdss_mdp_mixer_pipe_unstage(pipe);
-				mdss_mdp_pipe_free(pipe);
-			} else {
-				pr_err("unable to lock pipe=%d for release",
-				       pipe->num);
-			}
-		}
-	}
-	mutex_unlock(&mdss_mdp_sspp_lock);
-	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
-
-	return 0;
-}
-
 static inline void mdss_mdp_pipe_write(struct mdss_mdp_pipe *pipe,
 				       u32 reg, u32 val)
 {
@@ -363,6 +334,12 @@
 	}
 
 	chroma_sample = pipe->src_fmt->chroma_sample;
+	if (pipe->flags & MDP_SOURCE_ROTATED_90) {
+		if (chroma_sample == MDSS_MDP_CHROMA_H1V2)
+			chroma_sample = MDSS_MDP_CHROMA_H2V1;
+		else if (chroma_sample == MDSS_MDP_CHROMA_H2V1)
+			chroma_sample = MDSS_MDP_CHROMA_H1V2;
+	}
 
 	if ((pipe->src.h != pipe->dst.h) ||
 	    (chroma_sample == MDSS_MDP_CHROMA_420) ||
@@ -391,7 +368,7 @@
 			else
 				scale_config |= /* G/Y, A */
 					(MDSS_MDP_SCALE_FILTER_PCMN << 10) |
-					(MDSS_MDP_SCALE_FILTER_NEAREST << 18);
+					(MDSS_MDP_SCALE_FILTER_PCMN << 18);
 
 			if (pipe->src.h <= chr_dst_h)
 				scale_config |= /* CrCb */
@@ -449,7 +426,7 @@
 			else
 				scale_config |= /* G/Y, A */
 					(MDSS_MDP_SCALE_FILTER_PCMN << 8) |
-					(MDSS_MDP_SCALE_FILTER_NEAREST << 16);
+					(MDSS_MDP_SCALE_FILTER_PCMN << 16);
 
 			if (pipe->src.w <= chr_dst_w)
 				scale_config |= /* CrCb */
@@ -523,7 +500,7 @@
 static int mdss_mdp_format_setup(struct mdss_mdp_pipe *pipe)
 {
 	struct mdss_mdp_format_params *fmt;
-	u32 rot90, opmode, chroma_samp;
+	u32 opmode, chroma_samp, unpack, src_format;
 
 	fmt = pipe->src_fmt;
 
@@ -536,8 +513,6 @@
 	pr_debug("pnum=%d format=%d opmode=%x\n", pipe->num, fmt->format,
 			opmode);
 
-	rot90 = !!(pipe->flags & MDP_ROT_90);
-
 	chroma_samp = fmt->chroma_sample;
 	if (pipe->flags & MDP_SOURCE_ROTATED_90) {
 		if (chroma_samp == MDSS_MDP_CHROMA_H2V1)
@@ -546,26 +521,34 @@
 			chroma_samp = MDSS_MDP_CHROMA_H2V1;
 	}
 
-	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_FORMAT,
-			    (chroma_samp << 23) |
-			    (fmt->fetch_planes << 19) |
-			    (fmt->unpack_align_msb << 18) |
-			    (fmt->unpack_tight << 17) |
-			    (fmt->unpack_count << 12) |
-			    (rot90 << 11) |
-			    (fmt->bpp << 9) |
-			    (fmt->alpha_enable << 8) |
-			    (fmt->a_bit << 6) |
-			    (fmt->r_bit << 4) |
-			    (fmt->b_bit << 2) |
-			    (fmt->g_bit << 0));
+	src_format = (chroma_samp << 23) |
+		     (fmt->fetch_planes << 19) |
+		     (fmt->bits[C3_ALPHA] << 6) |
+		     (fmt->bits[C2_R_Cr] << 4) |
+		     (fmt->bits[C1_B_Cb] << 2) |
+		     (fmt->bits[C0_G_Y] << 0);
 
-	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_UNPACK_PATTERN,
-			    (fmt->element3 << 24) |
-			    (fmt->element2 << 16) |
-			    (fmt->element1 << 8) |
-			    (fmt->element0 << 0));
+	if (pipe->flags & MDP_ROT_90)
+		src_format |= BIT(11); /* ROT90 */
 
+	if (fmt->alpha_enable &&
+			fmt->fetch_planes != MDSS_MDP_PLANE_INTERLEAVED)
+		src_format |= BIT(8); /* SRCC3_EN */
+
+	if (fmt->fetch_planes != MDSS_MDP_PLANE_PLANAR) {
+		unpack = (fmt->element[3] << 24) | (fmt->element[2] << 16) |
+			(fmt->element[1] << 8) | (fmt->element[0] << 0);
+
+		src_format |= ((fmt->unpack_count - 1) << 12) |
+			  (fmt->unpack_tight << 17) |
+			  (fmt->unpack_align_msb << 18) |
+			  ((fmt->bpp - 1) << 9);
+	} else {
+		unpack = 0;
+	}
+
+	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_FORMAT, src_format);
+	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_UNPACK_PATTERN, unpack);
 	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_OP_MODE, opmode);
 
 	return 0;
@@ -595,17 +578,23 @@
 static int mdss_mdp_src_addr_setup(struct mdss_mdp_pipe *pipe,
 				   struct mdss_mdp_data *data)
 {
-	int ret;
+	int is_rot = pipe->mixer->rotator_mode;
+	int ret = 0;
 
 	pr_debug("pnum=%d\n", pipe->num);
 
-	if (pipe->type != MDSS_MDP_PIPE_TYPE_DMA)
+	if (!is_rot)
 		data->bwc_enabled = pipe->bwc_mode;
 
 	ret = mdss_mdp_data_check(data, &pipe->src_planes);
 	if (ret)
 		return ret;
 
+	/* planar format expects YCbCr, swap chroma planes if YCrCb */
+	if (!is_rot && (pipe->src_fmt->fetch_planes == MDSS_MDP_PLANE_PLANAR) &&
+	    (pipe->src_fmt->element[0] == C2_R_Cr))
+		swap(data->p[1].addr, data->p[2].addr);
+
 	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC0_ADDR, data->p[0].addr);
 	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC1_ADDR, data->p[1].addr);
 	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC2_ADDR, data->p[2].addr);
@@ -630,7 +619,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_mdp_util.c b/drivers/video/msm/mdss/mdss_mdp_util.c
index f6b4fce..50cc025 100644
--- a/drivers/video/msm/mdss/mdss_mdp_util.c
+++ b/drivers/video/msm/mdss/mdss_mdp_util.c
@@ -17,10 +17,13 @@
 #include <linux/errno.h>
 #include <linux/file.h>
 #include <linux/ion.h>
+#include <linux/iommu.h>
 #include <linux/msm_kgsl.h>
 #include <linux/spinlock.h>
 #include <linux/types.h>
 
+#include <mach/iommu_domains.h>
+
 #include "mdss_fb.h"
 #include "mdss_mdp.h"
 #include "mdss_mdp_formats.h"
@@ -102,8 +105,6 @@
 	spin_lock(&mdss_mdp_intr_lock);
 	fnc = mdp_intr_cb[index].func;
 	arg = mdp_intr_cb[index].arg;
-	if (fnc != NULL)
-		mdp_intr_cb[index].func = NULL;
 	spin_unlock(&mdss_mdp_intr_lock);
 	if (fnc)
 		fnc(arg);
@@ -164,14 +165,16 @@
 
 struct mdss_mdp_format_params *mdss_mdp_get_format_params(u32 format)
 {
-	struct mdss_mdp_format_params *fmt = NULL;
 	if (format < MDP_IMGTYPE_LIMIT) {
-		fmt = &mdss_mdp_format_map[format];
-		if (fmt->format != format)
-			fmt = NULL;
+		struct mdss_mdp_format_params *fmt = NULL;
+		int i;
+		for (i = 0; i < ARRAY_SIZE(mdss_mdp_format_map); i++) {
+			fmt = &mdss_mdp_format_map[i];
+			if (format == fmt->format)
+				return fmt;
+		}
 	}
-
-	return fmt;
+	return NULL;
 }
 
 int mdss_mdp_get_plane_sizes(u32 format, u32 w, u32 h,
@@ -193,30 +196,35 @@
 	memset(ps, 0, sizeof(struct mdss_mdp_plane_sizes));
 
 	if (fmt->fetch_planes == MDSS_MDP_PLANE_INTERLEAVED) {
-		u32 bpp = fmt->bpp + 1;
+		u32 bpp = fmt->bpp;
 		ps->num_planes = 1;
 		ps->plane_size[0] = w * h * bpp;
 		ps->ystride[0] = w * bpp;
 	} else {
 		u8 hmap[] = { 1, 2, 1, 2 };
 		u8 vmap[] = { 1, 1, 2, 2 };
-		u8 horiz, vert;
+		u8 horiz, vert, stride_align;
 
 		horiz = hmap[fmt->chroma_sample];
 		vert = vmap[fmt->chroma_sample];
 
-		if (format == MDP_Y_CR_CB_GH2V2) {
-			ps->plane_size[0] = ALIGN(w, 16) * h;
-			ps->plane_size[1] = ALIGN(w / horiz, 16) * (h / vert);
-			ps->ystride[0] = ALIGN(w, 16);
-			ps->ystride[1] = ALIGN(w / horiz, 16);
-		} else {
-			ps->plane_size[0] = w * h;
-			ps->plane_size[1] = (w / horiz) * (h / vert);
-			ps->ystride[0] = w;
-			ps->ystride[1] = (w / horiz);
+		switch (format) {
+		case MDP_Y_CR_CB_GH2V2:
+			stride_align = 16;
+			break;
+		case MDP_Y_CBCR_H2V2_VENUS:
+			stride_align = 32;
+			break;
+		default:
+			stride_align = 1;
+			break;
 		}
 
+		ps->ystride[0] = ALIGN(w, stride_align);
+		ps->ystride[1] = ALIGN(w / horiz, stride_align);
+		ps->plane_size[0] = ps->ystride[0] * h;
+		ps->plane_size[1] = ps->ystride[1] * (h / vert);
+
 		if (fmt->fetch_planes == MDSS_MDP_PLANE_PSEUDO_PLANAR) {
 			ps->num_planes = 2;
 			ps->plane_size[1] *= 2;
@@ -279,33 +287,38 @@
 
 int mdss_mdp_put_img(struct mdss_mdp_img_data *data)
 {
-	/* only source may use frame buffer */
+	struct ion_client *iclient = mdss_get_ionclient();
 	if (data->flags & MDP_MEMORY_ID_TYPE_FB) {
+		pr_debug("fb mem buf=0x%x\n", data->addr);
 		fput_light(data->srcp_file, data->p_need);
-		return 0;
-	}
-	if (data->srcp_file) {
+		data->srcp_file = NULL;
+	} else if (data->srcp_file) {
+		pr_debug("pmem buf=0x%x\n", data->addr);
 		put_pmem_file(data->srcp_file);
 		data->srcp_file = NULL;
-		return 0;
-	}
-	if (!IS_ERR_OR_NULL(data->srcp_ihdl)) {
-		ion_free(data->iclient, data->srcp_ihdl);
-		data->iclient = NULL;
+	} else if (!IS_ERR_OR_NULL(data->srcp_ihdl)) {
+		pr_debug("ion hdl=%p buf=0x%x\n", data->srcp_ihdl, data->addr);
+
+		if (is_mdss_iommu_attached())
+			ion_unmap_iommu(iclient, data->srcp_ihdl,
+					mdss_get_iommu_domain(), 0);
+
+		ion_free(iclient, data->srcp_ihdl);
 		data->srcp_ihdl = NULL;
-		return 0;
+	} else {
+		return -ENOMEM;
 	}
 
-	return -ENOMEM;
+	return 0;
 }
 
-int mdss_mdp_get_img(struct ion_client *iclient, struct msmfb_data *img,
-		     struct mdss_mdp_img_data *data)
+int mdss_mdp_get_img(struct msmfb_data *img, struct mdss_mdp_img_data *data)
 {
 	struct file *file;
 	int ret = -EINVAL;
 	int fb_num;
 	unsigned long *start, *len;
+	struct ion_client *iclient = mdss_get_ionclient();
 
 	start = (unsigned long *) &data->addr;
 	len = (unsigned long *) &data->len;
@@ -318,19 +331,46 @@
 					start, len);
 	} else if (img->flags & MDP_MEMORY_ID_TYPE_FB) {
 		file = fget_light(img->memory_id, &data->p_need);
-		if (file && FB_MAJOR ==
-				MAJOR(file->f_dentry->d_inode->i_rdev)) {
-			data->srcp_file = file;
+		if (file == NULL) {
+			pr_err("invalid framebuffer file (%d)\n",
+					img->memory_id);
+			return -EINVAL;
+		}
+		data->srcp_file = file;
+
+		if (MAJOR(file->f_dentry->d_inode->i_rdev) == FB_MAJOR) {
 			fb_num = MINOR(file->f_dentry->d_inode->i_rdev);
 			ret = mdss_fb_get_phys_info(start, len, fb_num);
+			if (ret)
+				pr_err("mdss_fb_get_phys_info() failed\n");
+		} else {
+			pr_err("invalid FB_MAJOR\n");
+			ret = -1;
 		}
 	} else if (iclient) {
-		data->iclient = iclient;
 		data->srcp_ihdl = ion_import_dma_buf(iclient, img->memory_id);
-		if (IS_ERR_OR_NULL(data->srcp_ihdl))
-			return PTR_ERR(data->srcp_ihdl);
-		ret = ion_phys(iclient, data->srcp_ihdl,
-			       start, (size_t *) len);
+		if (IS_ERR_OR_NULL(data->srcp_ihdl)) {
+			pr_err("error on ion_import_fd\n");
+			ret = PTR_ERR(data->srcp_ihdl);
+			data->srcp_ihdl = NULL;
+			return ret;
+		}
+
+		if (is_mdss_iommu_attached()) {
+			ret = ion_map_iommu(iclient, data->srcp_ihdl,
+					    mdss_get_iommu_domain(),
+					    0, SZ_4K, 0, start, len, 0,
+					    ION_IOMMU_UNMAP_DELAYED);
+		} else {
+			ret = ion_phys(iclient, data->srcp_ihdl, start,
+				       (size_t *) len);
+		}
+
+		if (IS_ERR_VALUE(ret)) {
+			ion_free(iclient, data->srcp_ihdl);
+			pr_err("failed to map ion handle (%d)\n", ret);
+			return ret;
+		}
 	} else {
 		unsigned long vstart;
 		ret = get_pmem_file(img->memory_id, start, &vstart, len,
@@ -340,9 +380,11 @@
 	if (!ret && (img->offset < data->len)) {
 		data->addr += img->offset;
 		data->len -= img->offset;
+
+		pr_debug("mem=%d ihdl=%p buf=0x%x len=0x%x\n", img->memory_id,
+			 data->srcp_ihdl, data->addr, data->len);
 	} else {
-		mdss_mdp_put_img(data);
-		ret = -EINVAL;
+		return -EINVAL;
 	}
 
 	return ret;
diff --git a/drivers/video/msm/mdss/mdss_mdp_wb.c b/drivers/video/msm/mdss/mdss_mdp_wb.c
index 26e459f..bd5f464 100644
--- a/drivers/video/msm/mdss/mdss_mdp_wb.c
+++ b/drivers/video/msm/mdss/mdss_mdp_wb.c
@@ -18,6 +18,10 @@
 #include <linux/major.h>
 #include <linux/module.h>
 #include <linux/uaccess.h>
+#include <linux/iommu.h>
+
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
 
 #include "mdss_mdp.h"
 #include "mdss_fb.h"
@@ -67,33 +71,46 @@
 	static struct ion_handle *ihdl;
 	static void *videomemory;
 	static ion_phys_addr_t mdss_wb_mem;
-	static struct mdss_mdp_data buffer = { .num_planes = 1,	};
-	struct fb_info *fbi;
-	size_t img_size;
+	static struct mdss_mdp_data mdss_wb_buffer = { .num_planes = 1, };
+	int rc;
 
-	fbi = mfd->fbi;
-	img_size = fbi->var.xres * fbi->var.yres * fbi->var.bits_per_pixel / 8;
+	if (IS_ERR_OR_NULL(ihdl)) {
+		struct fb_info *fbi;
+		size_t img_size;
+		struct ion_client *iclient = mdss_get_ionclient();
+		struct mdss_mdp_img_data *img = mdss_wb_buffer.p;
 
-	if (ihdl == NULL) {
-		ihdl = ion_alloc(mfd->iclient, img_size, SZ_4K,
+		fbi = mfd->fbi;
+		img_size = fbi->var.xres * fbi->var.yres *
+			fbi->var.bits_per_pixel / 8;
+
+
+		ihdl = ion_alloc(iclient, img_size, SZ_4K,
 				 ION_HEAP(ION_SF_HEAP_ID));
-		if (!IS_ERR_OR_NULL(ihdl)) {
-			videomemory = ion_map_kernel(mfd->iclient, ihdl, 0);
-			ion_phys(mfd->iclient, ihdl, &mdss_wb_mem, &img_size);
-		} else {
+		if (IS_ERR_OR_NULL(ihdl)) {
 			pr_err("unable to alloc fbmem from ion (%p)\n", ihdl);
-			ihdl = NULL;
+			return NULL;
 		}
+
+		videomemory = ion_map_kernel(iclient, ihdl, 0);
+		ion_phys(iclient, ihdl, &mdss_wb_mem, &img_size);
+
+		if (is_mdss_iommu_attached()) {
+			rc = ion_map_iommu(iclient, ihdl,
+					   mdss_get_iommu_domain(),
+					   0, SZ_4K, 0,
+					   (unsigned long *) &img->addr,
+					   (unsigned long *) &img->len,
+					   0, 0);
+		} else {
+			img->addr = mdss_wb_mem;
+			img->len = img_size;
+		}
+
+		pr_debug("ihdl=%p virt=%p phys=0x%lx iova=0x%x size=%u\n",
+			 ihdl, videomemory, mdss_wb_mem, img->addr, img_size);
 	}
-
-	if (mdss_wb_mem) {
-		buffer.p[0].addr = (u32) mdss_wb_mem;
-		buffer.p[0].len = img_size;
-
-		return &buffer;
-	}
-
-	return NULL;
+	return &mdss_wb_buffer;
 }
 #else
 static inline
@@ -266,7 +283,7 @@
 
 	node->buf_data.num_planes = 1;
 	buf = &node->buf_data.p[0];
-	ret = mdss_mdp_get_img(mfd->iclient, data, buf);
+	ret = mdss_mdp_get_img(data, buf);
 	if (IS_ERR_VALUE(ret)) {
 		pr_err("error getting buffer info\n");
 		goto register_fail;
@@ -394,6 +411,9 @@
 	if (!ctl || !ctl->mfd)
 		return -ENODEV;
 
+	if (!ctl->power_on)
+		return 0;
+
 	mutex_lock(&mdss_mdp_wb_buf_lock);
 	wb = ctl->mfd->wb;
 	if (wb) {
@@ -546,3 +566,9 @@
 	return mdss_mdp_wb_terminate(mfd);
 }
 EXPORT_SYMBOL(msm_fb_writeback_terminate);
+
+int msm_fb_get_iommu_domain(void)
+{
+	return mdss_get_iommu_domain();
+}
+EXPORT_SYMBOL(msm_fb_get_iommu_domain);
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
index 3ec3a5d..f1a4e50 100644
--- a/drivers/video/msm/mdss/mdss_panel.h
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -83,6 +83,18 @@
 	u32 yres_pad;
 };
 
+
+/* DSI PHY configuration */
+struct mdss_dsi_phy_ctrl {
+	uint32_t regulator[8];
+	uint32_t timing[12];
+	uint32_t ctrl[4];
+	uint32_t strength[2];
+	char bistCtrl[6];
+	uint32_t pll[21];
+	char laneCfg[45];
+};
+
 struct mipi_panel_info {
 	char mode;		/* video/cmd */
 	char interleave_mode;
@@ -103,7 +115,7 @@
 	char t_clk_post; /* 0xc0, DSI_CLKOUT_TIMING_CTRL */
 	char t_clk_pre;  /* 0xc0, DSI_CLKOUT_TIMING_CTRL */
 	char vc;	/* virtual channel */
-	struct mipi_dsi_phy_ctrl *dsi_phy_db;
+	struct mdss_dsi_phy_ctrl *dsi_phy_db;
 	/* video mode */
 	char pulse_mode_hsa_he;
 	char hfp_power_stop;
@@ -166,8 +178,9 @@
 
 struct mdss_panel_data {
 	struct mdss_panel_info panel_info;
-	void (*set_backlight) (u32 bl_level);
-	unsigned char *dsi_base;
+	void (*set_backlight) (struct mdss_panel_data *pdata,
+							u32 bl_level);
+	unsigned char *mmss_cc_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
index c766ec7..545d53c 100644
--- a/drivers/video/msm/mdss/msm_mdss_io_8974.c
+++ b/drivers/video/msm/mdss/msm_mdss_io_8974.c
@@ -12,6 +12,7 @@
  */
 #include <linux/clk.h>
 #include <linux/interrupt.h>
+#include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/io.h>
 
@@ -26,8 +27,9 @@
 
 static struct dsi_clk_desc dsi_pclk;
 
-static struct clk *dsi_byte_div_clk;
+static struct clk *dsi_byte_clk;
 static struct clk *dsi_esc_clk;
+static struct clk *dsi_pixel_clk;
 
 int mdss_dsi_clk_on;
 
@@ -35,16 +37,23 @@
 {
 	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;
+	dsi_byte_clk = clk_get(dev, "byte_clk");
+	if (IS_ERR(dsi_byte_clk)) {
+		pr_err("can't find dsi_byte_clk\n");
+		dsi_byte_clk = NULL;
+		goto mdss_dsi_clk_err;
+	}
+
+	dsi_pixel_clk = clk_get(dev, "pixel_clk");
+	if (IS_ERR(dsi_pixel_clk)) {
+		pr_err("can't find dsi_pixel_clk\n");
+		dsi_pixel_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");
+		pr_err("can't find dsi_esc_clk\n");
 		dsi_esc_clk = NULL;
 		goto mdss_dsi_clk_err;
 	}
@@ -58,10 +67,12 @@
 
 void mdss_dsi_clk_deinit(struct device *dev)
 {
-	if (dsi_byte_div_clk)
-		clk_put(dsi_byte_div_clk);
+	if (dsi_byte_clk)
+		clk_put(dsi_byte_clk);
 	if (dsi_esc_clk)
 		clk_put(dsi_esc_clk);
+	if (dsi_pixel_clk)
+		clk_put(dsi_pixel_clk);
 }
 
 #define PREF_DIV_RATIO 27
@@ -143,57 +154,154 @@
 	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_byte_clk);
 	clk_prepare(dsi_esc_clk);
+	clk_prepare(dsi_pixel_clk);
 }
 
 void mdss_dsi_unprepare_clocks(void)
 {
 	clk_unprepare(dsi_esc_clk);
-	clk_unprepare(dsi_byte_div_clk);
+	clk_unprepare(dsi_pixel_clk);
+	clk_unprepare(dsi_byte_clk);
 }
 
-void mdss_dsi_clk_enable(void)
+void mdss_dsi_clk_enable(struct mdss_panel_data *pdata)
 {
 	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 */
+	if (clk_set_rate(dsi_esc_clk, 19200000) < 0)
 		pr_err("%s: dsi_esc_clk - clk_set_rate failed\n",
 					__func__);
-	clk_enable(dsi_byte_div_clk);
+
+	if (clk_set_rate(dsi_byte_clk, 53000000) < 0)
+		pr_err("%s: dsi_byte_clk - clk_set_rate failed\n",
+					__func__);
+
+	if (clk_set_rate(dsi_pixel_clk, 70000000) < 0)
+		pr_err("%s: dsi_pixel_clk - clk_set_rate failed\n",
+					__func__);
+
 	clk_enable(dsi_esc_clk);
+	clk_enable(dsi_byte_clk);
+	clk_enable(dsi_pixel_clk);
+
 	mdss_dsi_clk_on = 1;
 }
 
-void mdss_dsi_clk_disable(void)
+void mdss_dsi_clk_disable(struct mdss_panel_data *pdata)
 {
 	if (mdss_dsi_clk_on == 0) {
 		pr_info("%s: mdss_dsi_clks already OFF\n", __func__);
 		return;
 	}
+
+	clk_disable(dsi_pixel_clk);
+	clk_disable(dsi_byte_clk);
 	clk_disable(dsi_esc_clk);
-	clk_disable(dsi_byte_div_clk);
+
 	mdss_dsi_clk_on = 0;
 }
+
+void mdss_dsi_phy_sw_reset(unsigned char *ctrl_base)
+{
+	/* start phy sw reset */
+	MIPI_OUTP(ctrl_base + 0x12c, 0x0001);
+	wmb();
+	usleep(1);
+	/* end phy sw reset */
+	MIPI_OUTP(ctrl_base + 0x12c, 0x0000);
+	wmb();
+	usleep(1);
+}
+
+void mdss_dsi_phy_enable(unsigned char *ctrl_base, int on)
+{
+	if (on) {
+		MIPI_OUTP(ctrl_base + 0x0220, 0x006);
+		usleep(10);
+		MIPI_OUTP(ctrl_base + 0x0268, 0x001);
+		usleep(10);
+		MIPI_OUTP(ctrl_base + 0x0268, 0x000);
+		usleep(10);
+		MIPI_OUTP(ctrl_base + 0x0220, 0x007);
+		wmb();
+
+		/* MMSS_DSI_0_PHY_DSIPHY_CTRL_0 */
+		MIPI_OUTP(ctrl_base + 0x0470, 0x07e);
+		MIPI_OUTP(ctrl_base + 0x0470, 0x06e);
+		MIPI_OUTP(ctrl_base + 0x0470, 0x06c);
+		MIPI_OUTP(ctrl_base + 0x0470, 0x064);
+		MIPI_OUTP(ctrl_base + 0x0470, 0x065);
+		MIPI_OUTP(ctrl_base + 0x0470, 0x075);
+		MIPI_OUTP(ctrl_base + 0x0470, 0x077);
+		MIPI_OUTP(ctrl_base + 0x0470, 0x07f);
+		wmb();
+
+	} else {
+		MIPI_OUTP(ctrl_base + 0x0220, 0x006);
+		usleep(10);
+		MIPI_OUTP(ctrl_base + 0x0470, 0x000);
+		wmb();
+	}
+}
+
+void mdss_dsi_phy_init(struct mdss_panel_data *pdata)
+{
+	struct mdss_dsi_phy_ctrl *pd;
+	int i, off, ln, offset;
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+
+	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+				panel_data);
+	if (!ctrl_pdata) {
+		pr_err("%s: Invalid input data\n", __func__);
+		return;
+	}
+
+	pd = ((ctrl_pdata->panel_data).panel_info.mipi).dsi_phy_db;
+
+	off = 0x0580;	/* phy regulator ctrl settings */
+	for (i = 0; i < 8; i++) {
+		MIPI_OUTP((ctrl_pdata->ctrl_base) + off, pd->regulator[i]);
+		wmb();
+		off += 4;
+	}
+
+	off = 0x0440;	/* phy timing ctrl 0 - 11 */
+	for (i = 0; i < 12; i++) {
+		MIPI_OUTP((ctrl_pdata->ctrl_base) + off, pd->timing[i]);
+		wmb();
+		off += 4;
+	}
+
+	/* Strength ctrl 0 - 1 */
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0484, pd->strength[0]);
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0488, pd->strength[1]);
+	wmb();
+
+	off = 0x04b4;	/* phy BIST ctrl 0 - 5 */
+	for (i = 0; i < 6; i++) {
+		MIPI_OUTP((ctrl_pdata->ctrl_base) + off, pd->bistCtrl[i]);
+		wmb();
+		off += 4;
+	}
+
+	/* 4 lanes + clk lane configuration */
+	/* lane config n * (0 - 4) & DataPath setup */
+	for (ln = 0; ln < 5; ln++) {
+		off = 0x0300 + (ln * 0x40);
+		for (i = 0; i < 9; i++) {
+			offset = i + (ln * 9);
+			MIPI_OUTP((ctrl_pdata->ctrl_base) + off,
+							pd->laneCfg[offset]);
+			wmb();
+			off += 4;
+		}
+	}
+}
diff --git a/drivers/video/msm/mhl/mhl_8334.c b/drivers/video/msm/mhl/mhl_8334.c
index 646dd29..f3b8cd1 100644
--- a/drivers/video/msm/mhl/mhl_8334.c
+++ b/drivers/video/msm/mhl/mhl_8334.c
@@ -37,6 +37,11 @@
 #include "hdmi_msm.h"
 #include "mhl_i2c_utils.h"
 
+#define MSC_START_BIT_MSC_CMD		        (0x01 << 0)
+#define MSC_START_BIT_VS_CMD		        (0x01 << 1)
+#define MSC_START_BIT_READ_REG		        (0x01 << 2)
+#define MSC_START_BIT_WRITE_REG		        (0x01 << 3)
+#define MSC_START_BIT_WRITE_BURST	        (0x01 << 4)
 
 static struct i2c_device_id mhl_sii_i2c_id[] = {
 	{ MHL_DRIVER_NAME, 0 },
@@ -45,6 +50,7 @@
 
 struct mhl_msm_state_t *mhl_msm_state;
 spinlock_t mhl_state_lock;
+struct workqueue_struct *msc_send_workqueue;
 
 static int mhl_i2c_probe(struct i2c_client *client,\
 	const struct i2c_device_id *id);
@@ -55,6 +61,7 @@
 static irqreturn_t mhl_tx_isr(int irq, void *dev_id);
 void (*notify_usb_online)(int online);
 static void mhl_drive_hpd(uint8_t to_state);
+static int mhl_send_msc_command(struct msc_command_struct *req);
 
 static struct i2c_driver mhl_sii_i2c_driver = {
 	.driver = {
@@ -224,12 +231,6 @@
 	return 0;
 }
 
-bool mhl_is_connected(void)
-{
-	return true;
-}
-
-
 /*  USB_HANDSHAKING FUNCTIONS */
 
 int mhl_device_discovery(const char *name, int *result)
@@ -530,34 +531,62 @@
 static int mhl_i2c_probe(struct i2c_client *client,
 	const struct i2c_device_id *id)
 {
-	int ret = -ENODEV;
+	int ret;
+	struct msm_mhl_platform_data *tmp = client->dev.platform_data;
+	if (!tmp->mhl_enabled) {
+		ret = -ENODEV;
+		pr_warn("MHL feautre left disabled\n");
+		goto probe_early_exit;
+	}
 	mhl_msm_state->mhl_data = kzalloc(sizeof(struct msm_mhl_platform_data),
 		GFP_KERNEL);
 	if (!(mhl_msm_state->mhl_data)) {
 		ret = -ENOMEM;
 		pr_err("MHL I2C Probe failed - no mem\n");
-		goto probe_exit;
+		goto probe_early_exit;
 	}
 	mhl_msm_state->i2c_client = client;
-
 	spin_lock_init(&mhl_state_lock);
-
 	i2c_set_clientdata(client, mhl_msm_state);
 	mhl_msm_state->mhl_data = client->dev.platform_data;
 	pr_debug("MHL: mhl_msm_state->mhl_data->irq=[%d]\n",
 		mhl_msm_state->mhl_data->irq);
+	msc_send_workqueue = create_workqueue("mhl_msc_cmd_queue");
 
+	mhl_msm_state->cur_state = POWER_STATE_D0_MHL;
 	/* Init GPIO stuff here */
 	ret = mhl_sii_gpio_setup(1);
-	if (ret == -1) {
+	if (ret) {
 		pr_err("MHL: mhl_gpio_init has failed\n");
 		ret = -ENODEV;
+		goto probe_early_exit;
+	}
+	mhl_sii_power_on();
+	/* MHL SII 8334 chip specific init */
+	mhl_chip_init();
+	init_completion(&mhl_msm_state->rgnd_done);
+	/* Request IRQ stuff here */
+	pr_debug("MHL: mhl_msm_state->mhl_data->irq=[%d]\n",
+		mhl_msm_state->mhl_data->irq);
+	ret = request_threaded_irq(mhl_msm_state->mhl_data->irq, NULL,
+				   &mhl_tx_isr,
+				 IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+				 "mhl_tx_isr", mhl_msm_state);
+	if (ret) {
+		pr_err("request_threaded_irq failed, status: %d\n",
+			ret);
 		goto probe_exit;
+	} else {
+		pr_debug("request_threaded_irq succeeded\n");
 	}
 
-	mhl_sii_power_on();
+	INIT_WORK(&mhl_msm_state->mhl_msc_send_work, mhl_msc_send_work);
+	INIT_LIST_HEAD(&mhl_msm_state->list_cmd);
+	mhl_msm_state->msc_command_put_work = list_cmd_put;
+	mhl_msm_state->msc_command_get_work = list_cmd_get;
+	init_completion(&mhl_msm_state->msc_cmd_done);
 
-	pr_debug("I2C PROBE successful\n");
+	pr_debug("i2c probe successful\n");
 	return 0;
 
 probe_exit:
@@ -567,6 +596,7 @@
 		kfree(mhl_msm_state->mhl_data);
 		mhl_msm_state->mhl_data = NULL;
 	}
+probe_early_exit:
 	return ret;
 }
 
@@ -578,6 +608,46 @@
 	return 0;
 }
 
+static void list_cmd_put(struct msc_command_struct *cmd)
+{
+	struct msc_cmd_envelope *new_cmd;
+	new_cmd = vmalloc(sizeof(struct msc_cmd_envelope));
+	memcpy(&new_cmd->msc_cmd_msg, cmd,
+		sizeof(struct msc_command_struct));
+	/* Need to check for queue getting filled up */
+	list_add_tail(&new_cmd->msc_queue_envelope, &mhl_msm_state->list_cmd);
+}
+
+struct msc_command_struct *list_cmd_get(void)
+{
+	struct msc_cmd_envelope *cmd_env =
+		list_first_entry(&mhl_msm_state->list_cmd,
+			struct msc_cmd_envelope, msc_queue_envelope);
+	list_del(&cmd_env->msc_queue_envelope);
+	return &cmd_env->msc_cmd_msg;
+}
+
+static void mhl_msc_send_work(struct work_struct *work)
+{
+	int ret;
+	/*
+	 * Remove item from the queue
+	 * and schedule it
+	 */
+	struct msc_command_struct *req;
+	while (!list_empty(&mhl_msm_state->list_cmd)) {
+		req = mhl_msm_state->msc_command_get_work();
+		ret = mhl_send_msc_command(req);
+		if (ret == -EAGAIN)
+			pr_err("MHL: Queue still busy!!\n");
+		else {
+			vfree(req);
+			pr_debug("MESSAGE SENT!!!!\n");
+		}
+	}
+}
+
+
 static int __init mhl_msm_init(void)
 {
 	int32_t     ret;
@@ -589,7 +659,6 @@
 		ret = -ENOMEM;
 		goto init_exit;
 	}
-
 	mhl_msm_state->i2c_client = NULL;
 	ret = i2c_add_driver(&mhl_sii_i2c_driver);
 	if (ret) {
@@ -598,6 +667,7 @@
 		goto init_exit;
 	} else {
 		if (mhl_msm_state->i2c_client == NULL) {
+			i2c_del_driver(&mhl_sii_i2c_driver);
 			pr_err("MHL: I2C driver add failed\n");
 			ret = -ENODEV;
 			goto init_exit;
@@ -605,31 +675,9 @@
 		pr_info("MHL: I2C driver added\n");
 	}
 
-	/* Request IRQ stuff here */
-	pr_debug("MHL: mhl_msm_state->mhl_data->irq=[%d]\n",
-		mhl_msm_state->mhl_data->irq);
-	ret = request_threaded_irq(mhl_msm_state->mhl_data->irq, NULL,
-				   &mhl_tx_isr,
-				 IRQF_TRIGGER_LOW | IRQF_ONESHOT,
-				 "mhl_tx_isr", mhl_msm_state);
-	if (ret != 0) {
-		pr_err("request_threaded_irq failed, status: %d\n",
-			ret);
-		ret = -EACCES; /* Error code???? */
-		goto init_exit;
-	} else
-		pr_debug("request_threaded_irq succeeded\n");
-
-	mhl_msm_state->cur_state = POWER_STATE_D0_MHL;
-
-	/* MHL SII 8334 chip specific init */
-	mhl_chip_init();
-	init_completion(&mhl_msm_state->rgnd_done);
 	return 0;
-
 init_exit:
 	pr_err("Exiting from the init with err\n");
-	i2c_del_driver(&mhl_sii_i2c_driver);
 	if (!mhl_msm_state) {
 		kfree(mhl_msm_state);
 		mhl_msm_state = NULL;
@@ -637,6 +685,16 @@
 	 return ret;
 }
 
+static void mhl_msc_sched_work(struct msc_command_struct *req)
+{
+	/*
+	 * Put an item to the queue
+	 * and schedule work
+	 */
+	mhl_msm_state->msc_command_put_work(req);
+	queue_work(msc_send_workqueue, &mhl_msm_state->mhl_msc_send_work);
+}
+
 static void switch_mode(enum mhl_st_type to_mode)
 {
 	unsigned long flags;
@@ -666,7 +724,8 @@
 			mhl_i2c_reg_write(TX_PAGE_3, 0x0030, 0xD0);
 			msleep(50);
 			mhl_i2c_reg_modify(TX_PAGE_3, 0x0010,
-				BIT1 | BIT0, BIT1);
+				BIT1 | BIT0, 0x00);
+			mhl_i2c_reg_modify(TX_PAGE_3, 0x003D, BIT0, 0x00);
 			spin_lock_irqsave(&mhl_state_lock, flags);
 			mhl_msm_state->cur_state = POWER_STATE_D3;
 			spin_unlock_irqrestore(&mhl_state_lock, flags);
@@ -741,7 +800,7 @@
 	 * Need to re-enable here
 	 */
 	val = mhl_i2c_reg_read(TX_PAGE_3, 0x10);
-	mhl_i2c_reg_write(TX_PAGE_3, 0x10, val | BIT(0));
+	mhl_i2c_reg_write(TX_PAGE_3, 0x10, val | BIT0);
 
 	return;
 }
@@ -783,9 +842,6 @@
 	if (0x02 == rgnd_imp) {
 		pr_debug("MHL: MHL DEVICE!!!\n");
 		mhl_i2c_reg_modify(TX_PAGE_3, 0x0018, BIT0, BIT0);
-		/*
-		 * Handling the MHL event in driver
-		 */
 		mhl_msm_state->mhl_mode = TRUE;
 		if (notify_usb_online)
 			notify_usb_online(1);
@@ -922,8 +978,7 @@
 	uint8_t intr_5_stat;
 
 	/*
-	 * Clear INT 5 ??
-	 * Probably need to revisit this later
+	 * Clear INT 5
 	 * INTR5 is related to FIFO underflow/overflow reset
 	 * which is handled in 8334 by auto FIFO reset
 	 */
@@ -959,16 +1014,455 @@
 	return;
 }
 
-/*
- * RCP, RAP messages - mandatory for compliance
- *
- */
+static void mhl_cbus_process_errors(u8 int_status)
+{
+	u8 abort_reason = 0;
+	if (int_status & BIT2) {
+		abort_reason = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x0B);
+		pr_debug("%s: CBUS DDC Abort Reason(0x%02x)\n",
+			__func__, abort_reason);
+	}
+	if (int_status & BIT5) {
+		abort_reason = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x0D);
+		pr_debug("%s: CBUS MSC Requestor Abort Reason(0x%02x)\n",
+			__func__, abort_reason);
+		mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0D, 0xFF);
+	}
+	if (int_status & BIT6) {
+		abort_reason = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x0E);
+		pr_debug("%s: CBUS MSC Responder Abort Reason(0x%02x)\n",
+			__func__, abort_reason);
+		mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0E, 0xFF);
+	}
+}
+
+static int mhl_msc_command_done(struct msc_command_struct *req)
+{
+	switch (req->command) {
+	case MHL_WRITE_STAT:
+		if (req->offset == MHL_STATUS_REG_LINK_MODE) {
+			if (req->payload.data[0]
+				& MHL_STATUS_PATH_ENABLED) {
+				/* Enable TMDS output */
+				mhl_i2c_reg_modify(TX_PAGE_L0, 0x0080,
+								BIT4, BIT4);
+			} else
+				/* Disable TMDS output */
+				mhl_i2c_reg_modify(TX_PAGE_L0, 0x0080,
+								BIT4, BIT4);
+		}
+		break;
+	case MHL_READ_DEVCAP:
+		mhl_msm_state->devcap_state |= BIT(req->offset);
+		switch (req->offset) {
+		case MHL_DEV_CATEGORY_OFFSET:
+			if (req->retval & MHL_DEV_CATEGORY_POW_BIT) {
+				/*
+				 * Enable charging
+				 */
+			} else {
+				/*
+				 * Disable charging
+				 */
+			}
+			break;
+		case DEVCAP_OFFSET_MHL_VERSION:
+		case DEVCAP_OFFSET_INT_STAT_SIZE:
+			break;
+		}
+
+		break;
+	}
+	return 0;
+}
+
+static int mhl_send_msc_command(struct msc_command_struct *req)
+{
+	int timeout;
+	u8 start_bit = 0x00;
+	u8 *burst_data;
+	int i;
+
+	if (mhl_msm_state->cur_state != POWER_STATE_D0_MHL) {
+		pr_debug("%s: power_state:%02x CBUS(0x0A):%02x\n",
+		__func__,
+		mhl_msm_state->cur_state, mhl_i2c_reg_read(TX_PAGE_CBUS, 0x0A));
+		return -EFAULT;
+	}
+
+	if (!req)
+		return -EFAULT;
+
+	pr_debug("%s: command=0x%02x offset=0x%02x %02x %02x",
+		__func__,
+		req->command,
+		req->offset,
+		req->payload.data[0],
+		req->payload.data[1]);
+
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x13, req->offset);
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x14, req->payload.data[0]);
+
+	switch (req->command) {
+	case MHL_SET_INT:
+	case MHL_WRITE_STAT:
+		start_bit = MSC_START_BIT_WRITE_REG;
+		break;
+	case MHL_READ_DEVCAP:
+		start_bit = MSC_START_BIT_READ_REG;
+		break;
+	case MHL_GET_STATE:
+	case MHL_GET_VENDOR_ID:
+	case MHL_SET_HPD:
+	case MHL_CLR_HPD:
+	case MHL_GET_SC1_ERRORCODE:
+	case MHL_GET_DDC_ERRORCODE:
+	case MHL_GET_MSC_ERRORCODE:
+	case MHL_GET_SC3_ERRORCODE:
+		start_bit = MSC_START_BIT_MSC_CMD;
+		mhl_i2c_reg_write(TX_PAGE_CBUS, 0x13, req->command);
+		break;
+	case MHL_MSC_MSG:
+		start_bit = MSC_START_BIT_VS_CMD;
+		mhl_i2c_reg_write(TX_PAGE_CBUS, 0x15, req->payload.data[1]);
+		mhl_i2c_reg_write(TX_PAGE_CBUS, 0x13, req->command);
+		break;
+	case MHL_WRITE_BURST:
+		start_bit = MSC_START_BIT_WRITE_BURST;
+		mhl_i2c_reg_write(TX_PAGE_CBUS, 0x20, req->length - 1);
+		if (!(req->payload.burst_data)) {
+			pr_err("%s: burst data is null!\n", __func__);
+			goto cbus_send_fail;
+		}
+		burst_data = req->payload.burst_data;
+		for (i = 0; i < req->length; i++, burst_data++)
+			mhl_i2c_reg_write(TX_PAGE_CBUS, 0xC0 + i, *burst_data);
+		break;
+	default:
+		pr_err("%s: unknown command! (%02x)\n",
+			__func__, req->command);
+		goto cbus_send_fail;
+	}
+
+	INIT_COMPLETION(mhl_msm_state->msc_cmd_done);
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x12, start_bit);
+	timeout = wait_for_completion_interruptible_timeout
+		(&mhl_msm_state->msc_cmd_done, HZ);
+	if (!timeout) {
+		pr_err("%s: cbus_command_send timed out!\n", __func__);
+		goto cbus_send_fail;
+	}
+
+	switch (req->command) {
+	case MHL_READ_DEVCAP:
+		/* devcap */
+		req->retval = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x16);
+		pr_debug("Read CBUS[0x16]=[%02x]\n", req->retval);
+		break;
+	case MHL_MSC_MSG:
+		/* check if MSC_MSG NACKed */
+		if (mhl_i2c_reg_read(TX_PAGE_CBUS, 0x20) & BIT6)
+			return -EAGAIN;
+	default:
+		req->retval = 0;
+		break;
+	}
+	mhl_msc_command_done(req);
+	pr_debug("%s: msc cmd done\n", __func__);
+	return 0;
+
+cbus_send_fail:
+	return -EFAULT;
+}
+
+static int mhl_msc_send_set_int(u8 offset, u8 mask)
+{
+	struct msc_command_struct req;
+	req.command = MHL_SET_INT;
+	req.offset = offset;
+	req.payload.data[0] = mask;
+	mhl_msc_sched_work(&req);
+	return 0;
+}
+
+static int mhl_msc_send_write_stat(u8 offset, u8 value)
+{
+	struct msc_command_struct req;
+	req.command = MHL_WRITE_STAT;
+	req.offset = offset;
+	req.payload.data[0] = value;
+	mhl_msc_sched_work(&req);
+	return 0;
+}
+
+static int mhl_msc_send_msc_msg(u8 sub_cmd, u8 cmd_data)
+{
+	struct msc_command_struct req;
+	req.command = MHL_MSC_MSG;
+	req.payload.data[0] = sub_cmd;
+	req.payload.data[1] = cmd_data;
+	mhl_msc_sched_work(&req);
+	return 0;
+}
+
+static int mhl_msc_read_devcap(u8 offset)
+{
+	struct msc_command_struct req;
+	if (offset < 0 || offset > 15)
+		return -EFAULT;
+	req.command = MHL_READ_DEVCAP;
+	req.offset = offset;
+	req.payload.data[0] = 0;
+	mhl_msc_sched_work(&req);
+	return 0;
+}
+
+static int mhl_msc_read_devcap_all(void)
+{
+	int offset;
+	int ret;
+
+	for (offset = 0; offset < DEVCAP_SIZE; offset++) {
+		ret = mhl_msc_read_devcap(offset);
+		msleep(200);
+		if (ret == -EFAULT) {
+			pr_err("%s: queue busy!\n", __func__);
+			return -EBUSY;
+		}
+	}
+
+	return 0;
+}
+
+/* supported RCP key code */
+static const u8 rcp_key_code_tbl[] = {
+	0, 0, 0, 0, 0, 0, 0, 0,		/* 0x00~0x07 */
+	0, 0, 0, 0, 0, 0, 0, 0,		/* 0x08~0x0f */
+	0, 0, 0, 0, 0, 0, 0, 0,		/* 0x10~0x17 */
+	0, 0, 0, 0, 0, 0, 0, 0,		/* 0x18~0x1f */
+	0, 0, 0, 0, 0, 0, 0, 0,		/* 0x20~0x27 */
+	0, 0, 0, 0, 0, 0, 0, 0,		/* 0x28~0x2f */
+	0, 0, 0, 0, 0, 0, 0, 0,		/* 0x30~0x37 */
+	0, 0, 0, 0, 0, 0, 0, 0,		/* 0x38~0x3f */
+	0, 0, 0, 0, 0, 0, 0, 0,		/* 0x40~0x47 */
+	0, 0, 0, 0, 0, 0, 0, 0,		/* 0x48~0x4f */
+	0, 0, 0, 0, 0, 0, 0, 0,		/* 0x50~0x57 */
+	0, 0, 0, 0, 0, 0, 0, 0,		/* 0x58~0x5f */
+	0, 0, 0, 0, 0, 0, 0, 0,		/* 0x60~0x67 */
+	0, 0, 0, 0, 0, 0, 0, 0,		/* 0x68~0x6f */
+	0, 0, 0, 0, 0, 0, 0, 0,		/* 0x70~0x77 */
+	0, 0, 0, 0, 0, 0, 0, 0		/* 0x78~0x7f */
+};
+
+static int mhl_rcp_recv(u8 key_code)
+{
+	int rc;
+	if (rcp_key_code_tbl[(key_code & 0x7f)]) {
+		/*
+		 * TODO: Take action for the RCP cmd
+		 */
+
+		/* send ack to rcp cmd*/
+		rc = mhl_msc_send_msc_msg(
+			MHL_MSC_MSG_RCPK,
+			key_code);
+	} else {
+		/* send rcp error */
+		rc = mhl_msc_send_msc_msg(
+			MHL_MSC_MSG_RCPE,
+			MHL_RCPE_UNSUPPORTED_KEY_CODE);
+		if (rc)
+			return rc;
+		/* send rcpk after rcpe send */
+		rc = mhl_msc_send_msc_msg(
+			MHL_MSC_MSG_RCPK,
+			key_code);
+	}
+	return rc;
+}
+
+static int mhl_rap_action(u8 action_code)
+{
+	switch (action_code) {
+	case MHL_RAP_CONTENT_ON:
+		/*
+		 * Enable TMDS on TMDS_CCTRL
+		 */
+		mhl_i2c_reg_modify(TX_PAGE_L0, 0x0080, BIT4, BIT4);
+		break;
+	case MHL_RAP_CONTENT_OFF:
+		/*
+		 * Disable TMDS on TMDS_CCTRL
+		 */
+		mhl_i2c_reg_modify(TX_PAGE_L0, 0x0080, BIT4, 0x00);
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+static int mhl_rap_recv(u8 action_code)
+{
+	u8 error_code;
+
+	switch (action_code) {
+	/*case MHL_RAP_POLL:*/
+	case MHL_RAP_CONTENT_ON:
+	case MHL_RAP_CONTENT_OFF:
+		mhl_rap_action(action_code);
+		error_code = MHL_RAPK_NO_ERROR;
+		/* notify userspace */
+		break;
+	default:
+		error_code = MHL_RAPK_UNRECOGNIZED_ACTION_CODE;
+		break;
+	}
+	/* prior send rapk */
+	return mhl_msc_send_msc_msg(
+		MHL_MSC_MSG_RAPK,
+		error_code);
+}
+
+static int mhl_msc_recv_msc_msg(u8 sub_cmd, u8 cmd_data)
+{
+	int rc = 0;
+	switch (sub_cmd) {
+	case MHL_MSC_MSG_RCP:
+		pr_debug("MHL: receive RCP(0x%02x)\n", cmd_data);
+		rc = mhl_rcp_recv(cmd_data);
+		break;
+	case MHL_MSC_MSG_RCPK:
+		pr_debug("MHL: receive RCPK(0x%02x)\n", cmd_data);
+		break;
+	case MHL_MSC_MSG_RCPE:
+		pr_debug("MHL: receive RCPE(0x%02x)\n", cmd_data);
+		break;
+	case MHL_MSC_MSG_RAP:
+		pr_debug("MHL: receive RAP(0x%02x)\n", cmd_data);
+		rc = mhl_rap_recv(cmd_data);
+		break;
+	case MHL_MSC_MSG_RAPK:
+		pr_debug("MHL: receive RAPK(0x%02x)\n", cmd_data);
+		break;
+	default:
+		break;
+	}
+	return rc;
+}
+
+static int mhl_msc_recv_set_int(u8 offset, u8 set_int)
+{
+	if (offset >= 2)
+		return -EFAULT;
+
+	switch (offset) {
+	case 0:
+		/* DCAP_CHG */
+		if (set_int & MHL_INT_DCAP_CHG) {
+			/* peer dcap has changed */
+			if (mhl_msc_read_devcap_all() == -EBUSY) {
+				pr_err("READ DEVCAP FAILED to send successfully\n");
+				break;
+			}
+		}
+		/* DSCR_CHG */
+		if (set_int & MHL_INT_DSCR_CHG)
+			;
+		/* REQ_WRT */
+		if (set_int & MHL_INT_REQ_WRT) {
+			/* SET_INT: GRT_WRT */
+			mhl_msc_send_set_int(
+				MHL_RCHANGE_INT,
+				MHL_INT_GRT_WRT);
+		}
+		/* GRT_WRT */
+		if (set_int & MHL_INT_GRT_WRT)
+			;
+		break;
+	case 1:
+		/* EDID_CHG */
+		if (set_int & MHL_INT_EDID_CHG) {
+			/* peer EDID has changed.
+			 * toggle HPD to read EDID again
+			 * In 8x30 FLUID  HDMI HPD line
+			 * is not connected
+			 * with MHL 8334 transmitter
+			 */
+		}
+	}
+	return 0;
+}
+
+static int mhl_msc_recv_write_stat(u8 offset, u8 value)
+{
+	if (offset >= 2)
+		return -EFAULT;
+
+	switch (offset) {
+	case 0:
+		/* DCAP_RDY */
+		/*
+		 * Connected Device bits changed and DEVCAP READY
+		 */
+		pr_debug("MHL: value [0x%02x]\n", value);
+		pr_debug("MHL: offset [0x%02x]\n", offset);
+		pr_debug("MHL: devcap state [0x%02x]\n",
+			mhl_msm_state->devcap_state);
+		pr_debug("MHL: MHL_STATUS_DCAP_RDY [0x%02x]\n",
+			MHL_STATUS_DCAP_RDY);
+		if (((value ^ mhl_msm_state->devcap_state) &
+			MHL_STATUS_DCAP_RDY)) {
+			if (value & MHL_STATUS_DCAP_RDY) {
+				if (mhl_msc_read_devcap_all() == -EBUSY) {
+					pr_err("READ DEVCAP FAILED to send successfully\n");
+					break;
+				}
+			} else {
+				/* peer dcap turned not ready */
+				/*
+				 * Clear DEVCAP READY state
+				 */
+			}
+		}
+		break;
+	case 1:
+		/* PATH_EN */
+		/*
+		 * Connected Device bits changed and PATH ENABLED
+		 */
+		if ((value ^ mhl_msm_state->path_en_state)
+			& MHL_STATUS_PATH_ENABLED) {
+			if (value & MHL_STATUS_PATH_ENABLED) {
+				mhl_msm_state->path_en_state
+					|= (MHL_STATUS_PATH_ENABLED |
+					MHL_STATUS_CLK_MODE_NORMAL);
+				mhl_msc_send_write_stat(
+					MHL_STATUS_REG_LINK_MODE,
+					mhl_msm_state->path_en_state);
+			} else {
+				mhl_msm_state->path_en_state
+					&= ~(MHL_STATUS_PATH_ENABLED |
+					MHL_STATUS_CLK_MODE_NORMAL);
+				mhl_msc_send_write_stat(
+					MHL_STATUS_REG_LINK_MODE,
+					mhl_msm_state->path_en_state);
+			}
+		}
+		break;
+	}
+	mhl_msm_state->path_en_state = value;
+	return 0;
+}
+
+
+/* MSC, RCP, RAP messages - mandatory for compliance */
 static void mhl_cbus_isr(void)
 {
 	uint8_t regval;
 	int req_done = FALSE;
-	uint8_t sub_cmd;
-	uint8_t cmd_data;
+	uint8_t sub_cmd = 0x0;
+	uint8_t cmd_data = 0x0;
 	int msc_msg_recved = FALSE;
 	int rc = -1;
 
@@ -976,21 +1470,27 @@
 	if (regval == 0xff)
 		return;
 
-	/* clear all interrupts that were raised even if we did not process */
+	/*
+	 * clear all interrupts that were raised
+	 * even if we did not process
+	 */
 	if (regval)
 		mhl_i2c_reg_write(TX_PAGE_CBUS, 0x08, regval);
 
 	pr_debug("%s: CBUS_INT = %02x\n", __func__, regval);
 
 	/* MSC_MSG (RCP/RAP) */
-	if (regval & BIT(3)) {
+	if (regval & BIT3) {
 		sub_cmd = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x18);
 		cmd_data = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x19);
 		msc_msg_recved = TRUE;
 	}
+	/* MSC_MT_ABRT/MSC_MR_ABRT/DDC_ABORT */
+	if (regval & (BIT6 | BIT5 | BIT2))
+		mhl_cbus_process_errors(regval);
 
 	/* MSC_REQ_DONE */
-	if (regval & BIT(4))
+	if (regval & BIT4)
 		req_done = TRUE;
 
 	/* Now look for interrupts on CBUS_MSC_INT2 */
@@ -1004,11 +1504,15 @@
 	pr_debug("%s: CBUS_MSC_INT2 = %02x\n", __func__, regval);
 
 	/* received SET_INT */
-	if (regval & BIT(2)) {
+	if (regval & BIT2) {
 		uint8_t intr;
 		intr = mhl_i2c_reg_read(TX_PAGE_CBUS, 0xA0);
+		mhl_msc_recv_set_int(0, intr);
+
 		pr_debug("%s: MHL_INT_0 = %02x\n", __func__, intr);
 		intr = mhl_i2c_reg_read(TX_PAGE_CBUS, 0xA1);
+		mhl_msc_recv_set_int(1, intr);
+
 		pr_debug("%s: MHL_INT_1 = %02x\n", __func__, intr);
 		mhl_i2c_reg_write(TX_PAGE_CBUS, 0xA0, 0xFF);
 		mhl_i2c_reg_write(TX_PAGE_CBUS, 0xA1, 0xFF);
@@ -1017,11 +1521,14 @@
 	}
 
 	/* received WRITE_STAT */
-	if (regval & BIT(3)) {
+	if (regval & BIT3) {
 		uint8_t stat;
 		stat = mhl_i2c_reg_read(TX_PAGE_CBUS, 0xB0);
+		mhl_msc_recv_write_stat(0, stat);
+
 		pr_debug("%s: MHL_STATUS_0 = %02x\n", __func__, stat);
 		stat = mhl_i2c_reg_read(TX_PAGE_CBUS, 0xB1);
+		mhl_msc_recv_write_stat(1, stat);
 		pr_debug("%s: MHL_STATUS_1 = %02x\n", __func__, stat);
 
 		mhl_i2c_reg_write(TX_PAGE_CBUS, 0xB0, 0xFF);
@@ -1033,9 +1540,13 @@
 	/* received MSC_MSG */
 	if (msc_msg_recved) {
 		/*mhl msc recv msc msg*/
+		rc = mhl_msc_recv_msc_msg(sub_cmd, cmd_data);
 		if (rc)
 			pr_err("MHL: mhl msc recv msc msg failed(%d)!\n", rc);
 	}
+	/* complete last command */
+	if (req_done)
+		complete_all(&mhl_msm_state->msc_cmd_done);
 
 	return;
 }
diff --git a/drivers/video/msm/mhl_api.h b/drivers/video/msm/mhl_api.h
index a4364ea..7fdbaa9 100644
--- a/drivers/video/msm/mhl_api.h
+++ b/drivers/video/msm/mhl_api.h
@@ -15,9 +15,9 @@
 #define __MHL_API_H__
 
 #ifdef CONFIG_FB_MSM_HDMI_MHL_8334
-bool mhl_is_connected(void);
+bool mhl_is_enabled(void);
 #else
-static bool mhl_is_connected(void)
+static bool mhl_is_enabled(void)
 {
 	return false;
 }
diff --git a/drivers/video/msm/mipi_NT35510.c b/drivers/video/msm/mipi_NT35510.c
index 94c24ee..0c6ff79 100644
--- a/drivers/video/msm/mipi_NT35510.c
+++ b/drivers/video/msm/mipi_NT35510.c
@@ -592,6 +592,7 @@
 static int __devinit mipi_nt35510_lcd_probe(struct platform_device *pdev)
 {
 	struct platform_device *pthisdev = NULL;
+	struct msm_fb_panel_data *pdata;
 	pr_debug("%s\n", __func__);
 
 	if (pdev->id == 0) {
@@ -601,6 +602,11 @@
 		return 0;
 	}
 
+	pdata = pdev->dev.platform_data;
+	if (mipi_nt35510_pdata && mipi_nt35510_pdata->rotate_panel()
+			&& pdata->panel_info.type == MIPI_CMD_PANEL)
+		pdata->panel_info.lcd.refx100 = 6200;
+
 	pthisdev = msm_fb_add_device(pdev);
 	mipi_nt35510_create_sysfs(pthisdev);
 
diff --git a/drivers/video/msm/mipi_dsi.c b/drivers/video/msm/mipi_dsi.c
index b4fb930..7d534ed 100644
--- a/drivers/video/msm/mipi_dsi.c
+++ b/drivers/video/msm/mipi_dsi.c
@@ -79,6 +79,14 @@
 
 	mdp4_overlay_dsi_state_set(ST_DSI_SUSPEND);
 
+	/* make sure dsi clk is on so that
+	 * dcs commands can be sent
+	 */
+	mipi_dsi_clk_cfg(1);
+
+	/* make sure dsi_cmd_mdp is idle */
+	mipi_dsi_cmd_mdp_busy();
+
 	/*
 	 * Desctiption: change to DSI_CMD_MODE since it needed to
 	 * tx DCS dsiplay off comamnd to panel
@@ -101,7 +109,6 @@
 	mdp_bus_scale_update_request(0);
 #endif
 
-	spin_lock_bh(&dsi_clk_lock);
 	mipi_dsi_clk_disable();
 
 	/* disbale dsi engine */
@@ -110,7 +117,6 @@
 	mipi_dsi_phy_ctrl(0);
 
 	mipi_dsi_ahb_ctrl(0);
-	spin_unlock_bh(&dsi_clk_lock);
 
 	mipi_dsi_unprepare_clocks();
 	if (mipi_dsi_pdata && mipi_dsi_pdata->dsi_power_save)
@@ -554,8 +560,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.h b/drivers/video/msm/mipi_dsi.h
index ebbf362..a7832ed 100644
--- a/drivers/video/msm/mipi_dsi.h
+++ b/drivers/video/msm/mipi_dsi.h
@@ -117,6 +117,9 @@
 #define DSI_INTR_CMD_DMA_DONE_MASK	BIT(1)
 #define DSI_INTR_CMD_DMA_DONE		BIT(0)
 
+#define DSI_MDP_TERM	BIT(8)
+#define DSI_CMD_TERM	BIT(0)
+
 #define DSI_CMD_TRIGGER_NONE		0x0	/* mdp trigger */
 #define DSI_CMD_TRIGGER_TE		0x02
 #define DSI_CMD_TRIGGER_SW		0x04
@@ -185,8 +188,8 @@
 #define DSI_HDR_DATA1(data)	((data) & 0x0ff)
 #define DSI_HDR_WC(wc)		((wc) & 0x0ffff)
 
-#define DSI_BUF_SIZE	1024
-#define MIPI_DSI_MRPS	0x04  /* Maximum Return Packet Size */
+#define DSI_BUF_SIZE	64
+#define MIPI_DSI_MRPS	0x04	/* Maximum Return Packet Size */
 
 #define MIPI_DSI_LEN 8 /* 4 x 4 - 6 - 2, bytes dcs header+crc-align  */
 
@@ -247,7 +250,6 @@
 	char *payload;
 };
 
-
 typedef void (*kickoff_act)(void *);
 
 struct dsi_kickoff_action {
@@ -257,6 +259,30 @@
 };
 
 
+#define CMD_REQ_MAX	4
+
+typedef void (*fxn)(u32 data);
+
+#define CMD_REQ_RX	0x0001
+#define CMD_REQ_COMMIT 0x0002
+#define CMD_REQ_NO_MAX_PKT_SIZE 0x0008
+
+struct dcs_cmd_req {
+	struct dsi_cmd_desc *cmds;
+	int cmds_cnt;
+	u32 flags;
+	int rlen;	/* rx length */
+	fxn cb;
+};
+
+struct dcs_cmd_list {
+	int put;
+	int get;
+	int tot;
+	struct dcs_cmd_req list[CMD_REQ_MAX];
+};
+
+
 char *mipi_dsi_buf_reserve_hdr(struct dsi_buf *dp, int hlen);
 char *mipi_dsi_buf_init(struct dsi_buf *dp);
 void mipi_dsi_init(void);
@@ -284,7 +310,7 @@
 void mipi_dsi_set_tear_on(struct msm_fb_data_type *mfd);
 void mipi_dsi_set_tear_off(struct msm_fb_data_type *mfd);
 void mipi_dsi_set_backlight(struct msm_fb_data_type *mfd, int level);
-void mipi_dsi_cmd_backlight_tx(int level);
+void mipi_dsi_cmd_backlight_tx(struct dsi_buf *dp);
 void mipi_dsi_clk_enable(void);
 void mipi_dsi_clk_disable(void);
 void mipi_dsi_pre_kickoff_action(void);
@@ -315,6 +341,11 @@
 void mipi_dsi_turn_off_clks(void);
 void mipi_dsi_clk_cfg(int on);
 
+int mipi_dsi_cmdlist_put(struct dcs_cmd_req *cmdreq);
+struct dcs_cmd_req *mipi_dsi_cmdlist_get(void);
+void mipi_dsi_cmdlist_commit(int from_mdp);
+void mipi_dsi_cmd_mdp_busy(void);
+
 #ifdef CONFIG_FB_MSM_MDP303
 void update_lane_config(struct msm_panel_info *pinfo);
 #endif
diff --git a/drivers/video/msm/mipi_dsi_host.c b/drivers/video/msm/mipi_dsi_host.c
index 39e2d6d..2b75193 100644
--- a/drivers/video/msm/mipi_dsi_host.c
+++ b/drivers/video/msm/mipi_dsi_host.c
@@ -42,12 +42,13 @@
 static struct completion dsi_dma_comp;
 static struct completion dsi_mdp_comp;
 static struct dsi_buf dsi_tx_buf;
-static int dsi_irq_enabled;
+static struct dsi_buf dsi_rx_buf;
 static spinlock_t dsi_irq_lock;
 static spinlock_t dsi_mdp_lock;
 spinlock_t dsi_clk_lock;
 static int dsi_ctrl_lock;
 static int dsi_mdp_busy;
+static struct mutex cmd_mutex;
 
 static struct list_head pre_kickoff_list;
 static struct list_head post_kickoff_list;
@@ -59,6 +60,8 @@
 	STAT_DSI_MDP
 };
 
+struct dcs_cmd_list	cmdlist;
+
 #ifdef CONFIG_FB_MSM_MDP40
 void mipi_dsi_mdp_stat_inc(int which)
 {
@@ -90,42 +93,52 @@
 	init_completion(&dsi_dma_comp);
 	init_completion(&dsi_mdp_comp);
 	mipi_dsi_buf_alloc(&dsi_tx_buf, DSI_BUF_SIZE);
+	mipi_dsi_buf_alloc(&dsi_rx_buf, DSI_BUF_SIZE);
 	spin_lock_init(&dsi_irq_lock);
 	spin_lock_init(&dsi_mdp_lock);
 	spin_lock_init(&dsi_clk_lock);
+	mutex_init(&cmd_mutex);
 
 	INIT_LIST_HEAD(&pre_kickoff_list);
 	INIT_LIST_HEAD(&post_kickoff_list);
 }
 
-void mipi_dsi_enable_irq(void)
+
+static u32 dsi_irq_mask;
+
+void mipi_dsi_enable_irq(u32 term)
 {
 	unsigned long flags;
 
 	spin_lock_irqsave(&dsi_irq_lock, flags);
-	if (dsi_irq_enabled) {
-		pr_debug("%s: IRQ aleady enabled\n", __func__);
+	if (dsi_irq_mask & term) {
 		spin_unlock_irqrestore(&dsi_irq_lock, flags);
 		return;
 	}
-	dsi_irq_enabled = 1;
-	enable_irq(dsi_irq);
+	if (dsi_irq_mask == 0) {
+		enable_irq(dsi_irq);
+		pr_debug("%s: IRQ Enable, mask=%x term=%x\n",
+				__func__, (int)dsi_irq_mask, (int)term);
+	}
+	dsi_irq_mask |= term;
 	spin_unlock_irqrestore(&dsi_irq_lock, flags);
 }
 
-void mipi_dsi_disable_irq(void)
+void mipi_dsi_disable_irq(u32 term)
 {
 	unsigned long flags;
 
 	spin_lock_irqsave(&dsi_irq_lock, flags);
-	if (dsi_irq_enabled == 0) {
-		pr_debug("%s: IRQ already disabled\n", __func__);
+	if (!(dsi_irq_mask & term)) {
 		spin_unlock_irqrestore(&dsi_irq_lock, flags);
 		return;
 	}
-
-	dsi_irq_enabled = 0;
-	disable_irq(dsi_irq);
+	dsi_irq_mask &= ~term;
+	if (dsi_irq_mask == 0) {
+		disable_irq(dsi_irq);
+		pr_debug("%s: IRQ Disable, mask=%x term=%x\n",
+				__func__, (int)dsi_irq_mask, (int)term);
+	}
 	spin_unlock_irqrestore(&dsi_irq_lock, flags);
 }
 
@@ -133,17 +146,19 @@
  * mipi_dsi_disale_irq_nosync() should be called
  * from interrupt context
  */
- void mipi_dsi_disable_irq_nosync(void)
+void mipi_dsi_disable_irq_nosync(u32 term)
 {
 	spin_lock(&dsi_irq_lock);
-	if (dsi_irq_enabled == 0) {
-		pr_debug("%s: IRQ cannot be disabled\n", __func__);
+	if (!(dsi_irq_mask & term)) {
 		spin_unlock(&dsi_irq_lock);
 		return;
 	}
-
-	dsi_irq_enabled = 0;
-	disable_irq_nosync(dsi_irq);
+	dsi_irq_mask &= ~term;
+	if (dsi_irq_mask == 0) {
+		disable_irq_nosync(dsi_irq);
+		pr_debug("%s: IRQ Disable, mask=%x term=%x\n",
+				__func__, (int)dsi_irq_mask, (int)term);
+	}
 	spin_unlock(&dsi_irq_lock);
 }
 
@@ -1007,27 +1022,6 @@
 	wmb();
 }
 
-int mipi_dsi_ctrl_lock(int mdp)
-{
-	unsigned long flag;
-	int lock = 0;
-
-	spin_lock_irqsave(&dsi_mdp_lock, flag);
-	if (dsi_ctrl_lock == FALSE) {
-		dsi_ctrl_lock = TRUE;
-		lock = 1;
-		if (lock && mdp)	/* mdp pixel */
-			mipi_dsi_enable_irq();
-	}
-	spin_unlock_irqrestore(&dsi_mdp_lock, flag);
-	return lock;
-}
-
-int mipi_dsi_ctrl_lock_query()
-{
-	return dsi_ctrl_lock;
-}
-
 void mipi_dsi_mdp_busy_wait(struct msm_fb_data_type *mfd)
 {
 	unsigned long flag;
@@ -1060,7 +1054,7 @@
 	mipi_dsi_mdp_stat_inc(STAT_DSI_START);
 
 	spin_lock_irqsave(&dsi_mdp_lock, flag);
-	 mipi_dsi_enable_irq();
+	 mipi_dsi_enable_irq(DSI_MDP_TERM);
 	 dsi_mdp_busy = TRUE;
 	spin_unlock_irqrestore(&dsi_mdp_lock, flag);
 }
@@ -1134,51 +1128,6 @@
 	return 4;
 }
 
-static char led_pwm1[2] = {0x51, 0x0};	/* DTYPE_DCS_WRITE1 */
-
-static struct dsi_cmd_desc backlight_cmd = {
-	DTYPE_DCS_LWRITE, 1, 0, 0, 1, sizeof(led_pwm1), led_pwm1};
-
-/*
- * mipi_dsi_cmd_backlight_tx:
- * thread context only
- */
-void mipi_dsi_cmd_backlight_tx(int level)
-{
-	struct dsi_buf *tp;
-	struct dsi_cmd_desc *cmd;
-	unsigned long flag;
-
-	spin_lock_irqsave(&dsi_mdp_lock, flag);
-	dsi_mdp_busy = TRUE;
-	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;
-	}
-
-	mipi_dsi_enable_irq();
-	mipi_dsi_cmd_dma_add(tp, cmd);
-
-	tp->len += 3;
-	tp->len &= ~0x03;	/* multipled by 4 */
-
-	tp->dmap = dma_map_single(&dsi_dev, tp->data, tp->len, DMA_TO_DEVICE);
-	if (dma_mapping_error(&dsi_dev, tp->dmap))
-		pr_err("%s: dmap mapp failed\n", __func__);
-
-	MIPI_OUTP(MIPI_DSI_BASE + 0x044, tp->dmap);
-	MIPI_OUTP(MIPI_DSI_BASE + 0x048, tp->len);
-	wmb();
-	MIPI_OUTP(MIPI_DSI_BASE + 0x08c, 0x01);	/* trigger */
-	wmb();
-	spin_unlock_irqrestore(&dsi_mdp_lock, flag);
-}
-
 /*
  * mipi_dsi_cmds_tx:
  * thread context only
@@ -1209,7 +1158,7 @@
 	cm = cmds;
 	mipi_dsi_buf_init(tp);
 	for (i = 0; i < cnt; i++) {
-		mipi_dsi_enable_irq();
+		mipi_dsi_enable_irq(DSI_CMD_TERM);
 		mipi_dsi_buf_init(tp);
 		mipi_dsi_cmd_dma_add(tp, cm);
 		mipi_dsi_cmd_dma_tx(tp);
@@ -1300,20 +1249,20 @@
 		/* packet size need to be set at every read */
 		pkt_size = len;
 		max_pktsize[0] = pkt_size;
-		mipi_dsi_enable_irq();
+		mipi_dsi_enable_irq(DSI_CMD_TERM);
 		mipi_dsi_buf_init(tp);
 		mipi_dsi_cmd_dma_add(tp, pkt_size_cmd);
 		mipi_dsi_cmd_dma_tx(tp);
 	}
 
-	mipi_dsi_enable_irq();
+	mipi_dsi_enable_irq(DSI_CMD_TERM);
 	mipi_dsi_buf_init(tp);
 	mipi_dsi_cmd_dma_add(tp, cmds);
 
 	/* transmit read comamnd to client */
 	mipi_dsi_cmd_dma_tx(tp);
 
-	mipi_dsi_disable_irq();
+	mipi_dsi_disable_irq(DSI_CMD_TERM);
 	/*
 	 * once cmd_dma_done interrupt received,
 	 * return data from client is ready and stored
@@ -1372,6 +1321,126 @@
 	return rp->len;
 }
 
+int mipi_dsi_cmds_rx_new(struct dsi_buf *tp, struct dsi_buf *rp,
+			struct dcs_cmd_req *req, int rlen)
+{
+	struct dsi_cmd_desc *cmds;
+	int cnt, len, diff, pkt_size;
+	char cmd;
+	unsigned long flag;
+
+	if (req->flags & CMD_REQ_NO_MAX_PKT_SIZE) {
+		/* Only support rlen = 4*n */
+		rlen += 3;
+		rlen &= ~0x03;
+	}
+
+	cmds = req->cmds;
+
+	len = rlen;
+	diff = 0;
+
+	if (len <= 2)
+		cnt = 4;	/* short read */
+	else {
+		if (len > MIPI_DSI_LEN)
+			len = MIPI_DSI_LEN;	/* 8 bytes at most */
+
+		len = (len + 3) & ~0x03; /* 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);
+	dsi_mdp_busy = TRUE;
+	spin_unlock_irqrestore(&dsi_mdp_lock, flag);
+
+	if (!(req->flags & CMD_REQ_NO_MAX_PKT_SIZE)) {
+
+
+		/* packet size need to be set at every read */
+		pkt_size = len;
+		max_pktsize[0] = pkt_size;
+		mipi_dsi_enable_irq(DSI_CMD_TERM);
+		mipi_dsi_buf_init(tp);
+		mipi_dsi_cmd_dma_add(tp, pkt_size_cmd);
+		mipi_dsi_cmd_dma_tx(tp);
+	}
+
+	mipi_dsi_enable_irq(DSI_CMD_TERM);
+	mipi_dsi_buf_init(tp);
+	mipi_dsi_cmd_dma_add(tp, cmds);
+
+	/* transmit read comamnd to client */
+	mipi_dsi_cmd_dma_tx(tp);
+
+	mipi_dsi_disable_irq(DSI_CMD_TERM);
+	/*
+	 * once cmd_dma_done interrupt received,
+	 * return data from client is ready and stored
+	 * at RDBK_DATA register already
+	 */
+	mipi_dsi_buf_init(rp);
+	if (req->flags & CMD_REQ_NO_MAX_PKT_SIZE) {
+		/*
+		 * expect rlen = n * 4
+		 * short alignement for start addr
+		 */
+		rp->data += 2;
+	}
+
+	mipi_dsi_cmd_dma_rx(rp, cnt);
+
+	spin_lock_irqsave(&dsi_mdp_lock, flag);
+	dsi_mdp_busy = FALSE;
+	complete(&dsi_mdp_comp);
+	spin_unlock_irqrestore(&dsi_mdp_lock, flag);
+
+	if (req->flags & CMD_REQ_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:
+		mipi_dsi_short_read1_resp(rp);
+		break;
+	case DTYPE_GEN_READ2_RESP:
+	case DTYPE_DCS_READ2_RESP:
+		mipi_dsi_short_read2_resp(rp);
+		break;
+	case DTYPE_GEN_LREAD_RESP:
+	case DTYPE_DCS_LREAD_RESP:
+		mipi_dsi_long_read_resp(rp);
+		rp->len -= 2; /* extra 2 bytes added */
+		rp->len -= diff; /* align bytes */
+		break;
+	default:
+		break;
+	}
+
+	return rp->len;
+}
+
 int mipi_dsi_cmd_dma_tx(struct dsi_buf *tp)
 {
 
@@ -1390,6 +1459,11 @@
 	pr_debug("\n");
 #endif
 
+	if (tp->len == 0) {
+		pr_err("%s: Error, len=0\n", __func__);
+		return 0;
+	}
+
 	spin_lock_irqsave(&dsi_mdp_lock, flags);
 	tp->len += 3;
 	tp->len &= ~0x03;	/* multipled by 4 */
@@ -1441,6 +1515,136 @@
 	return rlen;
 }
 
+void mipi_dsi_cmd_mdp_busy(void)
+{
+	u32 status;
+	unsigned long flags;
+	int need_wait = 0;
+
+	spin_lock_irqsave(&dsi_mdp_lock, flags);
+	status = MIPI_INP(MIPI_DSI_BASE + 0x0004);/* DSI_STATUS */
+	if (status & 0x04) {	/* MDP BUSY */
+		INIT_COMPLETION(dsi_mdp_comp);
+		need_wait = 1;
+		pr_debug("%s: status=%x need_wait\n", __func__, (int)status);
+		mipi_dsi_enable_irq(DSI_MDP_TERM);
+	}
+	spin_unlock_irqrestore(&dsi_mdp_lock, flags);
+
+	if (need_wait)
+		wait_for_completion(&dsi_mdp_comp);
+}
+
+/*
+ * mipi_dsi_cmd_get: cmd_mutex acquired by caller
+ */
+struct dcs_cmd_req *mipi_dsi_cmdlist_get(void)
+{
+	struct dcs_cmd_req *req = NULL;
+
+	if (cmdlist.get != cmdlist.put) {
+		req = &cmdlist.list[cmdlist.get];
+		cmdlist.get++;
+		cmdlist.get %= CMD_REQ_MAX;
+		cmdlist.tot--;
+		pr_debug("%s: tot=%d put=%d get=%d\n", __func__,
+		cmdlist.tot, cmdlist.put, cmdlist.get);
+	}
+	return req;
+}
+void mipi_dsi_cmdlist_tx(struct dcs_cmd_req *req)
+{
+	struct dsi_buf *tp;
+	int ret;
+
+	mipi_dsi_buf_init(&dsi_tx_buf);
+	tp = &dsi_tx_buf;
+	ret = mipi_dsi_cmds_tx(tp, req->cmds, req->cmds_cnt);
+
+	if (req->cb)
+		req->cb(ret);
+
+}
+
+void mipi_dsi_cmdlist_rx(struct dcs_cmd_req *req)
+{
+	int len;
+	u32 *dp;
+	struct dsi_buf *tp;
+	struct dsi_buf *rp;
+
+	mipi_dsi_buf_init(&dsi_tx_buf);
+	mipi_dsi_buf_init(&dsi_rx_buf);
+
+	tp = &dsi_tx_buf;
+	rp = &dsi_rx_buf;
+
+	len = mipi_dsi_cmds_rx_new(tp, rp, req, req->rlen);
+	dp = (u32 *)rp->data;
+
+	if (req->cb)
+		req->cb(*dp);
+}
+
+void mipi_dsi_cmdlist_commit(int from_mdp)
+{
+	struct dcs_cmd_req *req;
+
+	mutex_lock(&cmd_mutex);
+	req = mipi_dsi_cmdlist_get();
+	if (req == NULL) {
+		mutex_unlock(&cmd_mutex);
+		return;
+	}
+
+	pr_debug("%s:  from_mdp=%d pid=%d\n", __func__, from_mdp, current->pid);
+
+	if (!from_mdp) { /* from put */
+		/* make sure dsi_cmd_mdp is idle */
+		mipi_dsi_cmd_mdp_busy();
+	}
+
+	mipi_dsi_clk_cfg(1);
+	if (req->flags & CMD_REQ_RX)
+		mipi_dsi_cmdlist_rx(req);
+	else
+		mipi_dsi_cmdlist_tx(req);
+	mipi_dsi_clk_cfg(0);
+
+	mutex_unlock(&cmd_mutex);
+}
+
+int mipi_dsi_cmdlist_put(struct dcs_cmd_req *cmdreq)
+{
+	struct dcs_cmd_req *req;
+	int ret = 0;
+
+	mutex_lock(&cmd_mutex);
+	req = &cmdlist.list[cmdlist.put];
+	*req = *cmdreq;
+	cmdlist.put++;
+	cmdlist.put %= CMD_REQ_MAX;
+	cmdlist.tot++;
+	if (cmdlist.put == cmdlist.get) {
+		/* drop the oldest one */
+		pr_debug("%s: DROP, tot=%d put=%d get=%d\n", __func__,
+			cmdlist.tot, cmdlist.put, cmdlist.get);
+		cmdlist.get++;
+		cmdlist.get %= CMD_REQ_MAX;
+		cmdlist.tot--;
+	}
+	mutex_unlock(&cmd_mutex);
+
+	ret++;
+	pr_debug("%s: tot=%d put=%d get=%d\n", __func__,
+		cmdlist.tot, cmdlist.put, cmdlist.get);
+
+	if (req->flags & CMD_REQ_COMMIT)
+		mipi_dsi_cmdlist_commit(0);
+
+	return ret;
+}
+
 void mipi_dsi_irq_set(uint32 mask, uint32 irq)
 {
 	uint32 data;
@@ -1529,6 +1733,8 @@
 	isr = MIPI_INP(MIPI_DSI_BASE + 0x010c);/* DSI_INTR_CTRL */
 	MIPI_OUTP(MIPI_DSI_BASE + 0x010c, isr);
 
+	pr_debug("%s: isr=%x\n", __func__, (int)isr);
+
 #ifdef CONFIG_FB_MSM_MDP40
 	mdp4_stat.intr_dsi++;
 #endif
@@ -1548,7 +1754,7 @@
 		spin_lock(&dsi_mdp_lock);
 		complete(&dsi_dma_comp);
 		dsi_ctrl_lock = FALSE;
-		mipi_dsi_disable_irq_nosync();
+		mipi_dsi_disable_irq_nosync(DSI_CMD_TERM);
 		spin_unlock(&dsi_mdp_lock);
 	}
 
@@ -1556,7 +1762,7 @@
 		mipi_dsi_mdp_stat_inc(STAT_DSI_MDP);
 		spin_lock(&dsi_mdp_lock);
 		dsi_ctrl_lock = FALSE;
-		mipi_dsi_disable_irq_nosync();
+		mipi_dsi_disable_irq_nosync(DSI_MDP_TERM);
 		dsi_mdp_busy = FALSE;
 		complete(&dsi_mdp_comp);
 		spin_unlock(&dsi_mdp_lock);
diff --git a/drivers/video/msm/mipi_novatek.c b/drivers/video/msm/mipi_novatek.c
index 7dd41d2..b893cc7 100644
--- a/drivers/video/msm/mipi_novatek.c
+++ b/drivers/video/msm/mipi_novatek.c
@@ -393,18 +393,16 @@
 
 	mipi  = &mfd->panel_info.mipi;
 
-	if (mipi_dsi_ctrl_lock(0)) {
-		if (mipi->mode == DSI_VIDEO_MODE) {
-			mipi_dsi_cmds_tx(&novatek_tx_buf, novatek_video_on_cmds,
+	if (mipi->mode == DSI_VIDEO_MODE) {
+		mipi_dsi_cmds_tx(&novatek_tx_buf, novatek_video_on_cmds,
 				ARRAY_SIZE(novatek_video_on_cmds));
-		} else {
-			mipi_dsi_cmds_tx(&novatek_tx_buf, novatek_cmd_on_cmds,
+	} else {
+		mipi_dsi_cmds_tx(&novatek_tx_buf, novatek_cmd_on_cmds,
 				ARRAY_SIZE(novatek_cmd_on_cmds));
 
-			/* clean up ack_err_status */
-			mipi_dsi_cmd_bta_sw_trigger();
-			mipi_novatek_manufacture_id(mfd);
-		}
+		/* clean up ack_err_status */
+		mipi_dsi_cmd_bta_sw_trigger();
+		mipi_novatek_manufacture_id(mfd);
 	}
 
 	return 0;
@@ -421,35 +419,38 @@
 	if (mfd->key != MFD_KEY)
 		return -EINVAL;
 
-	if (mipi_dsi_ctrl_lock(0)) {
-		mipi_dsi_cmds_tx(&novatek_tx_buf, novatek_display_off_cmds,
+	mipi_dsi_cmds_tx(&novatek_tx_buf, novatek_display_off_cmds,
 			ARRAY_SIZE(novatek_display_off_cmds));
-	}
 
 	return 0;
 }
 
 DEFINE_LED_TRIGGER(bkl_led_trigger);
 
-#ifdef CONFIG_FB_MSM_MDP303
-void mdp4_backlight_put_level(int cndx, int level)
-{
-	/* do nothing */
-}
-#endif
+static char led_pwm1[2] = {0x51, 0x0};	/* DTYPE_DCS_WRITE1 */
+static struct dsi_cmd_desc backlight_cmd = {
+	DTYPE_DCS_LWRITE, 1, 0, 0, 1, sizeof(led_pwm1), led_pwm1};
+
+struct dcs_cmd_req cmdreq;
 
 static void mipi_novatek_set_backlight(struct msm_fb_data_type *mfd)
 {
-	struct mipi_panel_info *mipi;
 
 	if ((mipi_novatek_pdata->enable_wled_bl_ctrl)
 	    && (wled_trigger_initialized)) {
 		led_trigger_event(bkl_led_trigger, mfd->bl_level);
 		return;
 	}
-	mipi  = &mfd->panel_info.mipi;
 
-	mdp4_backlight_put_level(0, mfd->bl_level);
+	led_pwm1[1] = (unsigned char)mfd->bl_level;
+
+	cmdreq.cmds = &backlight_cmd;
+	cmdreq.cmds_cnt = 1;
+	cmdreq.flags = 0;
+	cmdreq.rlen = 0;
+	cmdreq.cb = NULL;
+
+	mipi_dsi_cmdlist_put(&cmdreq);
 }
 
 static int mipi_dsi_3d_barrier_sysfs_register(struct device *dev);
diff --git a/drivers/video/msm/msm_dss_io_8x60.c b/drivers/video/msm/msm_dss_io_8x60.c
index bb6f710..c79c4c7 100644
--- a/drivers/video/msm/msm_dss_io_8x60.c
+++ b/drivers/video/msm/msm_dss_io_8x60.c
@@ -553,12 +553,8 @@
 	hdmi_msm_clk(1);
 
 	clk_reset(hdmi_msm_state->hdmi_app_clk, CLK_RESET_ASSERT);
-	clk_reset(hdmi_msm_state->hdmi_m_pclk, CLK_RESET_ASSERT);
-	clk_reset(hdmi_msm_state->hdmi_s_pclk, CLK_RESET_ASSERT);
 	udelay(20);
 	clk_reset(hdmi_msm_state->hdmi_app_clk, CLK_RESET_DEASSERT);
-	clk_reset(hdmi_msm_state->hdmi_m_pclk, CLK_RESET_DEASSERT);
-	clk_reset(hdmi_msm_state->hdmi_s_pclk, CLK_RESET_DEASSERT);
 }
 
 void hdmi_msm_init_phy(int video_format)
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index 2c1f5b7..9c55fe8 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -57,6 +57,11 @@
 static unsigned char *fbram_phys;
 static int fbram_size;
 static boolean bf_supported;
+/* Set backlight on resume after 50 ms after first
+ * pan display on the panel. This is to avoid panel specific
+ * transients during resume.
+ */
+unsigned long backlight_duration = (HZ/20);
 
 static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST];
 static int pdev_list_cnt;
@@ -330,6 +335,8 @@
 	sysfs_remove_group(&mfd->fbi->dev->kobj, &msm_fb_attr_group);
 }
 
+static void bl_workqueue_handler(struct work_struct *work);
+
 static int msm_fb_probe(struct platform_device *pdev)
 {
 	struct msm_fb_data_type *mfd;
@@ -368,6 +375,8 @@
 
 	mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
 
+	INIT_DELAYED_WORK(&mfd->backlight_worker, bl_workqueue_handler);
+
 	if (!mfd)
 		return -ENODEV;
 
@@ -904,6 +913,7 @@
 			mfd->op_enable = FALSE;
 			curr_pwr_state = mfd->panel_power_on;
 			mfd->panel_power_on = FALSE;
+			cancel_delayed_work_sync(&mfd->backlight_worker);
 			bl_updated = 0;
 
 			msleep(16);
@@ -1699,13 +1709,28 @@
 
 DEFINE_SEMAPHORE(msm_fb_pan_sem);
 
+static void bl_workqueue_handler(struct work_struct *work)
+{
+	struct msm_fb_data_type *mfd = container_of(to_delayed_work(work),
+				struct msm_fb_data_type, backlight_worker);
+	struct msm_fb_panel_data *pdata = mfd->pdev->dev.platform_data;
+
+	if ((pdata) && (pdata->set_backlight) && (!bl_updated)) {
+		down(&mfd->sem);
+		mfd->bl_level = unset_bl_level;
+		pdata->set_backlight(mfd);
+		bl_level_old = unset_bl_level;
+		bl_updated = 1;
+		up(&mfd->sem);
+	}
+}
+
 static int msm_fb_pan_display(struct fb_var_screeninfo *var,
 			      struct fb_info *info)
 {
 	struct mdp_dirty_region dirty;
 	struct mdp_dirty_region *dirtyPtr = NULL;
 	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
-	struct msm_fb_panel_data *pdata;
 
 	/*
 	 * If framebuffer is 2, io pen display is not allowed.
@@ -1791,18 +1816,12 @@
 	mdp_dma_pan_update(info);
 	up(&msm_fb_pan_sem);
 
-	if (unset_bl_level && !bl_updated) {
-		pdata = (struct msm_fb_panel_data *)mfd->pdev->
-			dev.platform_data;
-		if ((pdata) && (pdata->set_backlight)) {
-			down(&mfd->sem);
-			mfd->bl_level = unset_bl_level;
-			pdata->set_backlight(mfd);
-			bl_level_old = unset_bl_level;
-			up(&mfd->sem);
-			bl_updated = 1;
-		}
-	}
+	if (unset_bl_level && !bl_updated)
+		schedule_delayed_work(&mfd->backlight_worker,
+				backlight_duration);
+
+	if (info->node == 0 && (mfd->cont_splash_done)) /* primary */
+		mdp_free_splash_buffer(mfd);
 
 	++mfd->panel_info.frame_count;
 	return 0;
@@ -2943,7 +2962,6 @@
 	int	ret;
 	struct msmfb_overlay_data req;
 	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
-	struct msm_fb_panel_data *pdata;
 
 	if (mfd->overlay_play_enable == 0)	/* nothing to do */
 		return 0;
@@ -2974,18 +2992,12 @@
 
 	ret = mdp4_overlay_play(info, &req);
 
-	if (unset_bl_level && !bl_updated) {
-		pdata = (struct msm_fb_panel_data *)mfd->pdev->
-			dev.platform_data;
-		if ((pdata) && (pdata->set_backlight)) {
-			down(&mfd->sem);
-			mfd->bl_level = unset_bl_level;
-			pdata->set_backlight(mfd);
-			bl_level_old = unset_bl_level;
-			up(&mfd->sem);
-			bl_updated = 1;
-		}
-	}
+	if (unset_bl_level && !bl_updated)
+		schedule_delayed_work(&mfd->backlight_worker,
+				backlight_duration);
+
+	if (info->node == 0 && (mfd->cont_splash_done)) /* primary */
+		mdp_free_splash_buffer(mfd);
 
 	return ret;
 }
@@ -3243,19 +3255,23 @@
 
 	if (notify == NOTIFY_UPDATE_START) {
 		INIT_COMPLETION(mfd->msmfb_update_notify);
-		wait_for_completion_interruptible(&mfd->msmfb_update_notify);
+		ret = wait_for_completion_interruptible_timeout(
+		&mfd->msmfb_update_notify, 4*HZ);
 	} else {
 		INIT_COMPLETION(mfd->msmfb_no_update_notify);
-		wait_for_completion_interruptible(&mfd->msmfb_no_update_notify);
+		ret = wait_for_completion_interruptible_timeout(
+		&mfd->msmfb_no_update_notify, 4*HZ);
 	}
-	return 0;
+	return (ret > 0) ? 0 : -1;
 }
 
 static int msmfb_handle_pp_ioctl(struct msm_fb_data_type *mfd,
 						struct msmfb_mdp_pp *pp_ptr)
 {
 	int ret = -1;
-
+#ifdef CONFIG_FB_MSM_MDP40
+	int i = 0;
+#endif
 	if (!pp_ptr)
 		return ret;
 
@@ -3263,6 +3279,15 @@
 #ifdef CONFIG_FB_MSM_MDP40
 	case mdp_op_csc_cfg:
 		ret = mdp4_csc_config(&(pp_ptr->data.csc_cfg_data));
+		for (i = 0; i < CSC_MAX_BLOCKS; i++) {
+			if (pp_ptr->data.csc_cfg_data.block ==
+					csc_cfg_matrix[i].block) {
+				memcpy(&csc_cfg_matrix[i].csc_data,
+				&(pp_ptr->data.csc_cfg_data.csc_data),
+				sizeof(struct mdp_csc_cfg));
+				break;
+			}
+		}
 		break;
 
 	case mdp_op_pcc_cfg:
@@ -3310,7 +3335,24 @@
 
 	return ret;
 }
-
+static int msmfb_handle_metadata_ioctl(struct msm_fb_data_type *mfd,
+				struct msmfb_metadata *metadata_ptr)
+{
+	int ret;
+	switch (metadata_ptr->op) {
+#ifdef CONFIG_FB_MSM_MDP40
+	case metadata_op_base_blend:
+		ret = mdp4_update_base_blend(mfd,
+						&metadata_ptr->data.blend_cfg);
+		break;
+#endif
+	default:
+		pr_warn("Unsupported request to MDP META IOCTL.\n");
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
 static int msm_fb_ioctl(struct fb_info *info, unsigned int cmd,
 			unsigned long arg)
 {
@@ -3328,6 +3370,7 @@
 #endif
 	struct mdp_page_protection fb_page_protection;
 	struct msmfb_mdp_pp mdp_pp;
+	struct msmfb_metadata mdp_metadata;
 	int ret = 0;
 
 	switch (cmd) {
@@ -3627,6 +3670,13 @@
 		ret = msmfb_handle_pp_ioctl(mfd, &mdp_pp);
 		break;
 
+	case MSMFB_METADATA_SET:
+		ret = copy_from_user(&mdp_metadata, argp, sizeof(mdp_metadata));
+		if (ret)
+			return ret;
+		ret = msmfb_handle_metadata_ioctl(mfd, &mdp_metadata);
+		break;
+
 	default:
 		MSM_FB_INFO("MDP: unknown ioctl (cmd=%x) received!\n", cmd);
 		ret = -EINVAL;
diff --git a/drivers/video/msm/msm_fb.h b/drivers/video/msm/msm_fb.h
index efe6160..2896349 100644
--- a/drivers/video/msm/msm_fb.h
+++ b/drivers/video/msm/msm_fb.h
@@ -80,7 +80,7 @@
 	DISP_TARGET dest;
 	struct fb_info *fbi;
 
-	struct device *dev;
+	struct delayed_work backlight_worker;
 	boolean op_enable;
 	uint32 fb_imgType;
 	boolean sw_currently_refreshing;
@@ -184,11 +184,11 @@
 	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;
+	void *copy_splash_buf;
+	unsigned char *copy_splash_phys;
 };
 
 struct dentry *msm_fb_get_debugfs_root(void);
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
index 0c6aa86..400a3a7 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
@@ -171,6 +171,7 @@
 	u32  sz_desc;
 	u32  sz_cpb;
 	u32  sz_context;
+	u32  sz_extnuserdata;
 };
 struct ddl_dec_buffers{
 	struct ddl_buf_addr desc;
@@ -186,6 +187,7 @@
 	struct ddl_buf_addr h264_vert_nb_mv;
 	struct ddl_buf_addr h264_nb_ip;
 	struct ddl_buf_addr context;
+	struct ddl_buf_addr extnuserdata;
 };
 struct ddl_enc_buffer_size{
 	u32  sz_cur_y;
@@ -228,7 +230,17 @@
 			[DDL_MAX_NUM_BFRS_FOR_SLICE_BATCH];
 	u32 num_output_frames;
 	u32 out_frm_next_frmindex;
-	u32  first_output_frame_tag;
+};
+struct ddl_mp2_datadumpenabletype {
+	u32 userdatadump_enable;
+	u32 pictempscalable_extdump_enable;
+	u32 picspat_extdump_enable;
+	u32 picdisp_extdump_enable;
+	u32 copyright_extdump_enable;
+	u32 quantmatrix_extdump_enable;
+	u32 seqscalable_extdump_enable;
+	u32 seqdisp_extdump_enable;
+	u32 seq_extdump_enable;
 };
 struct ddl_encoder_data{
 	struct ddl_codec_data_hdr   hdr;
@@ -277,6 +289,7 @@
 	u32  ext_enc_control_val;
 	u32  num_references_for_p_frame;
 	u32  closed_gop;
+	u32  num_slices_comp;
 	struct vcd_property_slice_delivery_info slice_delivery_info;
 	struct ddl_batch_frame_data batch_frame;
 };
@@ -323,6 +336,9 @@
 	u32  dmx_disable;
 	int avg_dec_time;
 	int dec_time_sum;
+	struct ddl_mp2_datadumpenabletype mp2_datadump_enable;
+	u32 mp2_datadump_status;
+	u32 extn_user_data_enable;
 };
 union ddl_codec_data{
 	struct ddl_codec_data_hdr  hdr;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_errors.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_errors.c
index a2327d5..3620f1a 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_errors.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_errors.c
@@ -766,6 +766,6 @@
 	break;
 	}
 	if (string)
-		DDL_MSG_ERROR("Recoverable Error code = 0x%x : %s",
+		DDL_MSG_LOW("Recoverable Error code = 0x%x : %s",
 					  error_code, string);
 }
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
index 949e5c0..d4601f2 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
@@ -10,7 +10,7 @@
  * GNU General Public License for more details.
  *
  */
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
 #include <mach/msm_memtypes.h>
 #include "vcd_ddl.h"
 #include "vcd_ddl_shared_mem.h"
@@ -471,7 +471,7 @@
 		ddl = ddl_context->current_ddl[1];
 	else {
 		DDL_MSG_LOW("STATE-CRITICAL-FRMRUN");
-		DDL_MSG_ERROR("Unexpected channel ID = %d", channel_id);
+		DDL_MSG_LOW("Unexpected channel ID = %d", channel_id);
 		ddl = NULL;
 	}
 	return ddl;
@@ -533,6 +533,7 @@
 	ddl_pmem_free(&dec_bufs->stx_parser);
 	ddl_pmem_free(&dec_bufs->desc);
 	ddl_pmem_free(&dec_bufs->context);
+	ddl_pmem_free(&dec_bufs->extnuserdata);
 	memset(dec_bufs, 0, sizeof(struct ddl_dec_buffers));
 }
 
@@ -601,6 +602,7 @@
 	u32 sz_sub_anchor_mv = 0, sz_overlap_xform = 0, sz_bit_plane3 = 0;
 	u32 sz_bit_plane2 = 0, sz_bit_plane1 = 0, sz_stx_parser = 0;
 	u32 sz_desc, sz_cpb, sz_context, sz_vert_nb_mv = 0, sz_nb_ip = 0;
+	u32 sz_extnuserdata = 0;
 
 	if (codec == VCD_CODEC_H264) {
 		sz_mv = ddl_get_yuv_buf_size(width,
@@ -630,7 +632,8 @@
 			sz_bit_plane3 = DDL_KILO_BYTE(2);
 			sz_bit_plane2 = DDL_KILO_BYTE(2);
 			sz_bit_plane1 = DDL_KILO_BYTE(2);
-		}
+		} else if (codec == VCD_CODEC_MPEG2)
+			sz_extnuserdata = DDL_KILO_BYTE(2);
 	}
 	sz_desc = DDL_KILO_BYTE(128);
 	sz_cpb = VCD_DEC_CPB_SIZE;
@@ -657,6 +660,7 @@
 		buf_size->sz_desc           = sz_desc;
 		buf_size->sz_cpb            = sz_cpb;
 		buf_size->sz_context        = sz_context;
+		buf_size->sz_extnuserdata   = sz_extnuserdata;
 	}
 }
 
@@ -774,6 +778,16 @@
 			}
 		}
 	}
+	if (buf_size.sz_extnuserdata > 0) {
+		dec_bufs->extnuserdata.mem_type = DDL_FW_MEM;
+		ptr = ddl_pmem_alloc(&dec_bufs->extnuserdata,
+				buf_size.sz_extnuserdata, DDL_KILO_BYTE(2));
+		if (!ptr)
+			goto fail_free_exit;
+		else
+			memset(dec_bufs->extnuserdata.align_virtual_addr,
+				0, buf_size.sz_extnuserdata);
+	}
 	return status;
 fail_free_exit:
 	status = VCD_ERR_ALLOC_FAIL;
@@ -922,7 +936,9 @@
 				goto fail_enc_free_exit;
 		}
 		if (buf_size.sz_pred > 0) {
-			enc_bufs->pred.mem_type = DDL_FW_MEM;
+			enc_bufs->pred.mem_type =
+				res_trk_check_for_sec_session() ?
+				DDL_MM_MEM : DDL_FW_MEM;
 			ptr = ddl_pmem_alloc(&enc_bufs->pred,
 				buf_size.sz_pred, DDL_KILO_BYTE(2));
 			if (!ptr)
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 8ec444f..bfc27dc 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
@@ -32,7 +32,7 @@
 static void ddl_handle_enc_frame_done(struct ddl_client_context *ddl,
 	u32 eos_present);
 static void ddl_handle_slice_done_slice_batch(struct ddl_client_context *ddl);
-static void ddl_handle_enc_frame_done_slice_mode(
+static u32 ddl_handle_enc_frame_done_slice_mode(
 		struct ddl_client_context *ddl, u32 eos_present);
 static void ddl_handle_enc_skipframe_slice_mode(
 		struct ddl_client_context *ddl, u32 eos_present);
@@ -256,6 +256,10 @@
 		DDL_MSG_LOW("HEADER_DONE");
 		vidc_1080p_get_decode_seq_start_result(&seq_hdr_info);
 		parse_hdr_size_data(ddl, &seq_hdr_info);
+		decoder->mp2_datadump_status = 0;
+		vidc_sm_get_mp2datadump_status(&ddl->shared_mem
+			[ddl->command_channel],
+			&decoder->mp2_datadump_status);
 		if (res_trk_get_disable_fullhd() &&
 			(seq_hdr_info.img_size_x * seq_hdr_info.img_size_y >
 				1280 * 720)) {
@@ -487,7 +491,7 @@
 	return ret_status;
 }
 
-static void ddl_encoder_frame_run_callback(
+static u32 ddl_encoder_frame_run_callback(
 	struct ddl_client_context *ddl)
 {
 	struct ddl_context *ddl_context = ddl->ddl_context;
@@ -496,6 +500,7 @@
 	struct vcd_frame_data *output_frame =
 		&(ddl->output_frame.vcd_frm);
 	u32 eos_present = false;
+	u32 status = true;
 
 	DDL_MSG_MED("ddl_encoder_frame_run_callback\n");
 	if (!DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_WAIT_FOR_FRAME_DONE) &&
@@ -528,6 +533,7 @@
 					ddl_handle_enc_skipframe_slice_mode(
 							ddl, eos_present);
 				else
+					status =
 					ddl_handle_enc_frame_done_slice_mode(
 							ddl, eos_present);
 			} else {
@@ -601,6 +607,8 @@
 			ddl->command_channel);
 		}
 	}
+
+	return status;
 }
 
 static void get_dec_status(struct ddl_client_context *ddl,
@@ -817,7 +825,7 @@
 		if (ddl->cmd_state == DDL_CMD_DECODE_FRAME)
 			return_status = ddl_decoder_frame_run_callback(ddl);
 		else if (ddl->cmd_state == DDL_CMD_ENCODE_FRAME)
-			ddl_encoder_frame_run_callback(ddl);
+			return_status = ddl_encoder_frame_run_callback(ddl);
 		else if (ddl->cmd_state == DDL_CMD_EOS)
 			return_status = ddl_eos_frame_done_callback(ddl);
 		else {
@@ -1024,6 +1032,9 @@
 				VIDC_1080P_RISC2HOST_CMD_SLICE_DONE_RET)
 			|| (ddl_hw_response->cmd ==
 				VIDC_1080P_RISC2HOST_CMD_FRAME_DONE_RET))) {
+				vidc_sm_get_num_slices_comp(
+				&ddl->shared_mem[ddl->command_channel],
+				&encoder->num_slices_comp);
 				vidc_sm_set_encoder_slice_batch_int_ctrl(
 				&ddl->shared_mem[ddl->command_channel],
 				1);
@@ -1164,20 +1175,28 @@
 		&(decoder->dec_disp_info);
 	struct ddl_frame_data_tag *output_frame = &(ddl->output_frame);
 	struct vcd_frame_data *output_vcd_frm = &(output_frame->vcd_frm);
+	enum vidc_1080p_decode_frame frame_type = 0;
 	u32 vcd_status, free_luma_dpb = 0, disp_pict = 0, is_interlaced;
+	u32 idr_frame = 0, coded_frame = 0;
 	get_dec_op_done_data(dec_disp_info, decoder->output_order,
 		&output_vcd_frm->physical, &is_interlaced);
 	decoder->progressive_only = !(is_interlaced);
 	output_vcd_frm->frame = VCD_FRAME_YUV;
+	vidc_sm_get_displayed_picture_frame(&ddl->shared_mem
+		[ddl->command_channel], &disp_pict);
+	coded_frame = (disp_pict & 0x03);
+	idr_frame = (disp_pict & 0x20) >> 5;
+	if (idr_frame)
+		frame_type = VIDC_1080P_DECODE_FRAMETYPE_IDR;
+	else
+		frame_type = (disp_pict & 0x1c) >> 2;
 	if (decoder->codec.codec == VCD_CODEC_MPEG4 ||
 		decoder->codec.codec == VCD_CODEC_VC1 ||
 		decoder->codec.codec == VCD_CODEC_VC1_RCV ||
 		(decoder->codec.codec >= VCD_CODEC_DIVX_3 &&
 		decoder->codec.codec <= VCD_CODEC_XVID)) {
-		vidc_sm_get_displayed_picture_frame(&ddl->shared_mem
-		[ddl->command_channel], &disp_pict);
 		if (decoder->output_order == VCD_DEC_ORDER_DISPLAY) {
-			if (!disp_pict) {
+			if (!coded_frame) {
 				output_vcd_frm->frame = VCD_FRAME_NOTCODED;
 				vidc_sm_get_available_luma_dpb_address(
 					&ddl->shared_mem[ddl->command_channel],
@@ -1202,9 +1221,14 @@
 		DDL_MSG_ERROR("CORRUPTED_OUTPUT_BUFFER_ADDRESS");
 		ddl_hw_fatal_cb(ddl);
 	} else {
+		ddl_get_decoded_frame(output_vcd_frm, frame_type);
 		vidc_sm_get_metadata_status(&ddl->shared_mem
 			[ddl->command_channel],
 			&decoder->meta_data_exists);
+		decoder->mp2_datadump_status = 0;
+		vidc_sm_get_mp2datadump_status(&ddl->shared_mem
+			[ddl->command_channel],
+			&decoder->mp2_datadump_status);
 		if (decoder->output_order == VCD_DEC_ORDER_DISPLAY) {
 			vidc_sm_get_frame_tags(&ddl->shared_mem
 				[ddl->command_channel],
@@ -1332,6 +1356,10 @@
 	case VIDC_1080P_DECODE_FRAMETYPE_OTHERS:
 		frame->frame = VCD_FRAME_YUV;
 	break;
+	case VIDC_1080P_DECODE_FRAMETYPE_IDR:
+		frame->flags |= VCD_FRAME_FLAG_SYNCFRAME;
+		frame->frame = VCD_FRAME_IDR;
+	break;
 	case VIDC_1080P_DECODE_FRAMETYPE_32BIT:
 	default:
 		DDL_MSG_ERROR("UNKNOWN-FRAMETYPE");
@@ -1793,27 +1821,11 @@
 		vidc_sm_get_frame_tags(&ddl->shared_mem
 			[ddl->command_channel],
 			&output_frame->ip_frm_tag, &bottom_frame_tag);
-
-		if (start_bfr_idx == 0) {
-			encoder->batch_frame.first_output_frame_tag =
-				output_frame->ip_frm_tag;
-			DDL_MSG_LOW("%s: first_output_frame_tag[0x%x]",
-				__func__, output_frame->ip_frm_tag);
-			if (!output_frame->ip_frm_tag) {
-				DDL_MSG_ERROR("%s: first_output_frame_tag "\
-					"is zero", __func__);
-			}
+		if (!output_frame->ip_frm_tag) {
+			DDL_MSG_ERROR("%s: zero frame tag rcvd, index = %d",
+				__func__, index);
+			output_frame->ip_frm_tag = (u32)ddl->client_data;
 		}
-		if (output_frame->ip_frm_tag !=
-			encoder->batch_frame.first_output_frame_tag) {
-			DDL_MSG_ERROR("%s: output_frame->ip_frm_tag[0x%x] is "\
-				"not equal to the first_output_frame_tag[0x%x]\n",
-				__func__, output_frame->ip_frm_tag,
-				encoder->batch_frame.first_output_frame_tag);
-			output_frame->ip_frm_tag =
-				encoder->batch_frame.first_output_frame_tag;
-		}
-
 		ddl_get_encoded_frame(output_frame,
 				encoder->codec.codec,
 				encoder->enc_frame_info.enc_frame);
@@ -1836,7 +1848,7 @@
 			0);
 }
 
-static void ddl_handle_enc_frame_done_slice_mode(
+static u32 ddl_handle_enc_frame_done_slice_mode(
 		struct ddl_client_context *ddl, u32 eos_present)
 {
 	struct ddl_context       *ddl_context = ddl->ddl_context;
@@ -1850,6 +1862,7 @@
 	u32 start_bfr_idx = 0;
 	u32 actual_idx = 0;
 	struct vcd_transc *transc;
+	u32 status = true;
 
 	DDL_MSG_LOW("%s\n", __func__);
 	vidc_sm_get_num_slices_comp(
@@ -1875,6 +1888,7 @@
 		DDL_MSG_ERROR("ERROR : %d %d\n",
 		encoder->slice_delivery_info.num_slices_enc,
 		encoder->batch_frame.num_output_frames);
+		status = false;
 	}
 	for (index = 0; index < num_slices_comp; index++) {
 		actual_idx =
@@ -1896,27 +1910,11 @@
 		vidc_sm_get_frame_tags(&ddl->shared_mem
 			[ddl->command_channel],
 			&output_frame->ip_frm_tag, &bottom_frame_tag);
-
-		if (start_bfr_idx == 0) {
-			encoder->batch_frame.first_output_frame_tag =
-				output_frame->ip_frm_tag;
-			DDL_MSG_LOW("%s: first_output_frame_tag[0x%x]",
-				__func__, output_frame->ip_frm_tag);
-			if (!output_frame->ip_frm_tag) {
-				DDL_MSG_ERROR("%s: first_output_frame_tag "\
-					"is zero", __func__);
-			}
+		if (!output_frame->ip_frm_tag) {
+			DDL_MSG_ERROR("%s: zero frame tag rcvd, index = %d",
+				__func__, index);
+			output_frame->ip_frm_tag = (u32)ddl->client_data;
 		}
-		if (output_frame->ip_frm_tag !=
-			encoder->batch_frame.first_output_frame_tag) {
-			DDL_MSG_ERROR("%s: output_frame->ip_frm_tag[0x%x] is "\
-				"not equal to the first_output_frame_tag[0x%x]\n",
-				__func__, output_frame->ip_frm_tag,
-				encoder->batch_frame.first_output_frame_tag);
-			output_frame->ip_frm_tag =
-				encoder->batch_frame.first_output_frame_tag;
-		}
-
 		ddl_get_encoded_frame(output_frame,
 				encoder->codec.codec,
 				encoder->enc_frame_info.enc_frame);
@@ -1958,6 +1956,8 @@
 				sizeof(struct ddl_frame_data_tag),
 				(u32 *) ddl, ddl->client_data);
 	}
+
+	return status;
 }
 
 static void ddl_handle_enc_skipframe_slice_mode(
@@ -1987,8 +1987,9 @@
 				&output_frame->ip_frm_tag,
 				&bottom_frame_tag);
 		if (!output_frame->ip_frm_tag) {
-			DDL_MSG_ERROR("%s: output frame tag is zero",
-				__func__);
+			DDL_MSG_ERROR("%s: zero frame tag rcvd, index = %d",
+				__func__, index);
+			output_frame->ip_frm_tag = (u32)ddl->client_data;
 		}
 		ddl_get_encoded_frame(
 				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 fade821..f70c47c 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.c
@@ -52,6 +52,12 @@
 		case VCD_METADATA_QCOMFILLER:
 			skip_words = 21;
 		break;
+		case VCD_METADATA_USER_DATA:
+			skip_words = 27;
+		break;
+		case VCD_METADATA_EXT_DATA:
+			skip_words = 30;
+		break;
 		}
 	} else {
 		buffer = (u32 *) ddl->codec_data.encoder.meta_data_input.
@@ -123,6 +129,18 @@
 		hdr_entry[DDL_METADATA_HDR_PORT_INDEX] = 1;
 		hdr_entry[DDL_METADATA_HDR_TYPE_INDEX] =
 			VCD_METADATA_PASSTHROUGH;
+		hdr_entry = ddl_metadata_hdr_entry(ddl,
+			VCD_METADATA_USER_DATA);
+		hdr_entry[DDL_METADATA_HDR_VERSION_INDEX] = 0x00000101;
+		hdr_entry[DDL_METADATA_HDR_PORT_INDEX] = 1;
+		hdr_entry[DDL_METADATA_HDR_TYPE_INDEX] =
+			VCD_METADATA_USER_DATA;
+		hdr_entry = ddl_metadata_hdr_entry(ddl,
+			VCD_METADATA_EXT_DATA);
+		hdr_entry[DDL_METADATA_HDR_VERSION_INDEX] = 0x00000101;
+		hdr_entry[DDL_METADATA_HDR_PORT_INDEX] = 1;
+		hdr_entry[DDL_METADATA_HDR_TYPE_INDEX] =
+			VCD_METADATA_EXT_DATA;
 	} else {
 		hdr_entry = ddl_metadata_hdr_entry(ddl, VCD_METADATA_ENC_SLICE);
 		hdr_entry[DDL_METADATA_HDR_VERSION_INDEX] = 0x00000101;
@@ -146,6 +164,9 @@
 		else if (codec == VCD_CODEC_VC1 ||
 			codec == VCD_CODEC_VC1_RCV)
 			flag |= VCD_METADATA_VC1;
+		else if (codec == VCD_CODEC_MPEG2)
+			flag |= (VCD_METADATA_USER_DATA |
+				VCD_METADATA_EXT_DATA);
 	} else
 		flag |= VCD_METADATA_ENC_SLICE;
 	return flag;
@@ -165,7 +186,6 @@
 {
 	u32 flag = decoder->meta_data_enable_flag;
 	u32 suffix = 0, size = 0;
-
 	if (!flag) {
 		decoder->suffix = 0;
 		return;
@@ -210,6 +230,18 @@
 		DDL_METADATA_ALIGNSIZE(size);
 		suffix += (size);
 	}
+	if (flag & VCD_METADATA_USER_DATA) {
+		size = DDL_METADATA_HDR_SIZE;
+		size += DDL_METADATA_USER_PAYLOAD_SIZE;
+		DDL_METADATA_ALIGNSIZE(size);
+		suffix += (size);
+	}
+	if (flag & VCD_METADATA_EXT_DATA) {
+		size = DDL_METADATA_HDR_SIZE;
+		size += DDL_METADATA_EXT_PAYLOAD_SIZE;
+		DDL_METADATA_ALIGNSIZE(size);
+		suffix += (size);
+	}
 	size = DDL_METADATA_EXTRADATANONE_SIZE;
 	DDL_METADATA_ALIGNSIZE(size);
 	suffix += (size);
@@ -278,6 +310,10 @@
 			if (flag)
 				flag |= DDL_METADATA_MANDATORY;
 			if (*meta_data_enable_flag != flag) {
+				if (VCD_CODEC_MPEG2 == codec)
+					ddl_set_mp2_dump_default(
+						&ddl->codec_data.decoder,
+						flag);
 				*meta_data_enable_flag = flag;
 				if (ddl->decoding)
 					ddl_set_default_decoder_buffer_req(
@@ -357,6 +393,7 @@
 	u32 qp_enable = false, concealed_mb_enable = false;
 	u32 vc1_param_enable = false, sei_nal_enable = false;
 	u32 vui_enable = false, enc_slice_size_enable = false;
+	u32 mp2_data_dump_enable = false;
 
 	if (ddl->decoding)
 		flag = ddl->codec_data.decoder.meta_data_enable_flag;
@@ -380,10 +417,22 @@
 	}
 
 	DDL_MSG_LOW("metadata enable flag : %d", sei_nal_enable);
+	if (flag & VCD_METADATA_EXT_DATA || flag & VCD_METADATA_USER_DATA) {
+		mp2_data_dump_enable = true;
+		ddl->codec_data.decoder.extn_user_data_enable =
+				mp2_data_dump_enable;
+		vidc_sm_set_mp2datadump_enable(&ddl->shared_mem
+		[ddl->command_channel],
+		&ddl->codec_data.decoder.mp2_datadump_enable);
+	} else {
+		mp2_data_dump_enable = false;
+		ddl->codec_data.decoder.extn_user_data_enable =
+				mp2_data_dump_enable;
+	}
 	vidc_sm_set_metadata_enable(&ddl->shared_mem
 		[ddl->command_channel], extradata_enable, qp_enable,
 		concealed_mb_enable, vc1_param_enable, sei_nal_enable,
-		vui_enable, enc_slice_size_enable);
+		vui_enable, enc_slice_size_enable, mp2_data_dump_enable);
 }
 
 u32 ddl_vidc_encode_set_metadata_output_buf(struct ddl_client_context *ddl)
@@ -487,6 +536,11 @@
 		output_frame->flags &= ~(VCD_FRAME_FLAG_EXTRADATA);
 		return;
 	}
+	if (!decoder->mp2_datadump_status && decoder->codec.codec ==
+		VCD_CODEC_MPEG2 && !decoder->extn_user_data_enable) {
+		output_frame->flags &= ~(VCD_FRAME_FLAG_EXTRADATA);
+		return;
+	}
 	DDL_MSG_LOW("processing metadata for decoder");
 	DDL_MSG_LOW("data_len/metadata_offset : %d/%d",
 		output_frame->data_len, decoder->meta_data_offset);
@@ -507,3 +561,27 @@
 		*qfiller = (u32)(qfiller_size - DDL_METADATA_HDR_SIZE);
 	}
 }
+
+void ddl_set_mp2_dump_default(struct ddl_decoder_data *decoder, u32 flag)
+{
+
+	if (flag & VCD_METADATA_EXT_DATA) {
+		decoder->mp2_datadump_enable.pictempscalable_extdump_enable =
+			true;
+		decoder->mp2_datadump_enable.picspat_extdump_enable = true;
+		decoder->mp2_datadump_enable.picdisp_extdump_enable = true;
+		decoder->mp2_datadump_enable.copyright_extdump_enable = true;
+		decoder->mp2_datadump_enable.quantmatrix_extdump_enable =
+			true;
+		decoder->mp2_datadump_enable.seqscalable_extdump_enable =
+			true;
+		decoder->mp2_datadump_enable.seqdisp_extdump_enable = true;
+		decoder->mp2_datadump_enable.seq_extdump_enable = true;
+	}
+	if (flag & VCD_METADATA_USER_DATA)
+		decoder->mp2_datadump_enable.userdatadump_enable =
+				DDL_METADATA_USER_DUMP_FULL_MODE;
+	else
+		decoder->mp2_datadump_enable.userdatadump_enable =
+				DDL_METADATA_USER_DUMP_DISABLE_MODE;
+}
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.h
index c63b6a9..e03a9b7 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.h
@@ -14,7 +14,7 @@
 #ifndef _VCD_DDL_METADATA_H_
 #define _VCD_DDL_METADATA_H_
 
-#define DDL_MAX_DEC_METADATATYPE          8
+#define DDL_MAX_DEC_METADATATYPE          10
 #define DDL_MAX_ENC_METADATATYPE          3
 #define DDL_METADATA_EXTRAPAD_SIZE      256
 #define DDL_METADATA_HDR_SIZE            20
@@ -27,6 +27,8 @@
 #define DDL_METADATA_SEI_MAX                     5
 #define DDL_METADATA_VUI_PAYLOAD_SIZE          256
 #define DDL_METADATA_PASSTHROUGH_PAYLOAD_SIZE   68
+#define DDL_METADATA_EXT_PAYLOAD_SIZE         (640)
+#define DDL_METADATA_USER_PAYLOAD_SIZE        (2048)
 #define DDL_METADATA_CLIENT_INPUTBUFSIZE       256
 #define DDL_METADATA_TOTAL_INPUTBUFSIZE \
 	(DDL_METADATA_CLIENT_INPUTBUFSIZE * VCD_MAX_NO_CLIENT)
@@ -46,6 +48,10 @@
 #define DDL_METADATA_HDR_PORT_INDEX    1
 #define DDL_METADATA_HDR_TYPE_INDEX    2
 
+#define DDL_METADATA_USER_DUMP_DISABLE_MODE 0
+#define DDL_METADATA_USER_DUMP_OFFSET_MODE  1
+#define DDL_METADATA_USER_DUMP_FULL_MODE    2
+
 void ddl_set_default_meta_data_hdr(struct ddl_client_context *ddl);
 u32 ddl_get_metadata_params(struct ddl_client_context *ddl,
 	struct vcd_property_hdr *property_hdr, void *property_value);
@@ -62,5 +68,6 @@
 void ddl_vidc_decode_set_metadata_output(struct ddl_decoder_data *decoder);
 void ddl_process_encoder_metadata(struct ddl_client_context *ddl);
 void ddl_process_decoder_metadata(struct ddl_client_context *ddl);
+void ddl_set_mp2_dump_default(struct ddl_decoder_data *decoder, u32 flag);
 
 #endif
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 033457d..596c86f 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
@@ -1879,7 +1879,6 @@
 		output_buf_req = &decoder->actual_output_buf_req;
 		input_buf_req = &decoder->actual_input_buf_req;
 		min_dpb = decoder->min_dpb_num;
-		y_cb_cr_size = decoder->y_cb_cr_size;
 		if ((decoder->buf_format.buffer_format ==
 			VCD_BUFFER_FORMAT_TILE_4x2) &&
 			(frame_size->height < MDP_MIN_TILE_HEIGHT)) {
@@ -1891,6 +1890,7 @@
 				&decoder->buf_format,
 				(!decoder->progressive_only),
 				decoder->hdr.decoding, NULL);
+			decoder->y_cb_cr_size = y_cb_cr_size;
 		} else
 			y_cb_cr_size = decoder->y_cb_cr_size;
 	}
@@ -1953,7 +1953,11 @@
 					DDL_TILE_MULTIPLY_FACTOR);
 		total_memory_size += component_mem_size;
 	} else {
-		total_memory_size = frame_sz.scan_lines * frame_sz.stride;
+		if (decoding)
+			total_memory_size = frame_sz.scan_lines *
+						frame_sz.stride;
+		else
+			total_memory_size = frame_sz.height * 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 d45de2d..8099234 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
@@ -45,7 +45,7 @@
 #define VIDC_SM_DISP_PIC_PROFILE_DISP_PIC_PROFILE_SHFT      0
 
 #define VIDC_SM_DISP_PIC_FRAME_TYPE_ADDR                    0x00c0
-#define VIDC_SM_DISP_PIC_FRAME_TYPE_BMSK                    0x00000003
+#define VIDC_SM_DISP_PIC_FRAME_TYPE_BMSK                    0x0000003f
 #define VIDC_SM_DISP_PIC_FRAME_TYPE_SHFT                    0
 
 #define VIDC_SM_FREE_LUMA_DPB_ADDR                          0x00c4
@@ -187,6 +187,8 @@
 
 
 #define VIDC_SM_METADATA_ENABLE_ADDR                 0x0038
+#define VIDC_SM_METADATA_ENABLE_MP2_DATADUMP_BMSK    0x00000200
+#define VIDC_SM_METADATA_ENABLE_MP2_DATADUMP_SHFT    9
 #define VIDC_SM_METADATA_ENABLE_EXTRADATA_BMSK       0x40
 #define VIDC_SM_METADATA_ENABLE_EXTRADATA_SHFT       6
 #define VIDC_SM_METADATA_ENABLE_ENC_SLICE_SIZE_BMSK  0x20
@@ -251,6 +253,51 @@
 #define VIDC_SM_TIMEOUT_VALUE_BMSK        0xffffffff
 #define VIDC_SM_TIMEOUT_VALUE_SHFT        0
 
+#define VIDC_SM_MP2_DATA_DUMP_CONTROL_ADDR                        0x0194
+#define VIDC_SM_MP2_USERDATA_DUMP_ENABLE_BMSK                     0x00000300
+#define VIDC_SM_MP2_USERDATA_DUMP_ENABLE_SHFT                     8
+#define VIDC_SM_MP2_PICT_TEMP_DUMP_ENABLE_BMSK                    0x00000080
+#define VIDC_SM_MP2_PICT_TEMP_DUMP_ENABLE_SHFT                    7
+#define VIDC_SM_MP2_PICT_SPAT_EXT_DUMP_ENABLE_BMSK                0x00000040
+#define VIDC_SM_MP2_PICT_SPAT_EXT_DUMP_ENABLE_SHFT                6
+#define VIDC_SM_MP2_PICT_DISP_EXT_DUMP_ENABLE_BMSK                0x00000020
+#define VIDC_SM_MP2_PICT_DISP_EXT_DUMP_ENABLE_SHFT                5
+#define VIDC_SM_MP2_COPYRIGHT_EXT_DUMP_ENABLE_BMSK                0x00000010
+#define VIDC_SM_MP2_COPYRIGHT_EXT_DUMP_ENABLE_SHFT                4
+#define VIDC_SM_MP2_QMATRIX_EXT_DUMP_ENABLE_BMSK                  0x00000008
+#define VIDC_SM_MP2_QMATRIX_EXT_DUMP_ENABLE_SHFT                  3
+#define VIDC_SM_MP2_SCAL_EXT_DUMP_ENABLE_BMSK                     0x00000004
+#define VIDC_SM_MP2_SCAL_EXT_DUMP_ENABLE_SHFT                     2
+#define VIDC_SM_MP2_SEQ_DISP_EXT_DUMP_ENABLE_BMSK                 0x00000002
+#define VIDC_SM_MP2_SEQ_DISP_EXT_DUMP_ENABLE_SHFT                 1
+#define VIDC_SM_MP2_SEQ_EXT_DUMP_ENABLE_BMSK                      0x00000001
+#define VIDC_SM_MP2_SEQ_EXT_DUMP_ENABLE_SHFT                      0
+
+#define VIDC_SM_MP2_DATA_DUMP_STATUS_ADDR                         0x0198
+#define VIDC_SM_MP2_USERDATA_DUMP_STATUS_BMSK                     0x00000300
+#define VIDC_SM_MP2_USERDATA_DUMP_STATUS_SHFT                     8
+#define VIDC_SM_MP2_PICT_TEMP_DUMP_STATUS_BMSK                    0x00000080
+#define VIDC_SM_MP2_PICT_TEMP_DUMP_STATUS_SHFT                    7
+#define VIDC_SM_MP2_PICT_SPAT_EXT_DUMP_STATUS_BMSK                0x00000040
+#define VIDC_SM_MP2_PICT_SPAT_EXT_DUMP_STATUS_SHFT                6
+#define VIDC_SM_MP2_PICT_DISP_EXT_DUMP_STATUS_BMSK                0x00000020
+#define VIDC_SM_MP2_PICT_DISP_EXT_DUMP_STATUS_SHFT                5
+#define VIDC_SM_MP2_COPYRIGHT_EXT_DUMP_STATUS_BMSK                0x00000010
+#define VIDC_SM_MP2_COPYRIGHT_EXT_DUMP_STATUS_SHFT                4
+#define VIDC_SM_MP2_QMATRIX_EXT_DUMP_STATUS_BMSK                  0x00000008
+#define VIDC_SM_MP2_QMATRIX_EXT_DUMP_STATUS_SHFT                  3
+#define VIDC_SM_MP2_SCAL_EXT_DUMP_STATUS_BMSK                     0x00000004
+#define VIDC_SM_MP2_SCAL_EXT_DUMP_STATUS_SHFT                     2
+#define VIDC_SM_MP2_SEQ_DISP_EXT_DUMP_STATUS_BMSK                 0x00000002
+#define VIDC_SM_MP2_SEQ_DISP_EXT_DUMP_STATUS_SHFT                 1
+#define VIDC_SM_MP2_SEQ_EXT_DUMP_STATUS_BMSK                      0x00000001
+#define VIDC_SM_MP2_SEQ_EXT_DUMP_STATUS_SHFT                      0
+
+#define VIDC_SM_MP2_DATA_DUMP_BUFFER_ADDR                         0x01a4
+#define VIDC_SM_MP2_DATA_DUMP_BUFFER_SIZE_ADDR                    0x01a8
+
+
+
 #define VIDC_SM_ENC_EXT_CTRL_CLOSED_GOP_ENABLE_BMSK	0x40
 #define VIDC_SM_ENC_EXT_CTRL_CLOSED_GOP_ENABLE_SHFT	6
 
@@ -579,11 +626,14 @@
 void vidc_sm_set_metadata_enable(struct ddl_buf_addr *shared_mem,
 	u32 extradata_enable, u32 qp_enable, u32 concealed_mb_enable,
 	u32 vc1Param_enable, u32 sei_nal_enable, u32 vui_enable,
-	u32 enc_slice_size_enable)
+	u32 enc_slice_size_enable, u32 mp2_data_dump_enable)
 {
 	u32 metadata_enable;
 
-	metadata_enable = VIDC_SETFIELD((extradata_enable) ? 1 : 0,
+	metadata_enable = VIDC_SETFIELD((mp2_data_dump_enable) ? 1 : 0,
+				VIDC_SM_METADATA_ENABLE_MP2_DATADUMP_SHFT,
+				VIDC_SM_METADATA_ENABLE_MP2_DATADUMP_BMSK) |
+				VIDC_SETFIELD((extradata_enable) ? 1 : 0,
 				VIDC_SM_METADATA_ENABLE_EXTRADATA_SHFT,
 				VIDC_SM_METADATA_ENABLE_EXTRADATA_BMSK) |
 				VIDC_SETFIELD((enc_slice_size_enable) ? 1 : 0,
@@ -897,7 +947,7 @@
 				VIDC_SM_EXTENDED_PAR_HEIGHT_SHFT);
 			break;
 		default:
-			DDL_MSG_ERROR("Incorrect Aspect Ratio.");
+			DDL_MSG_LOW("Incorrect Aspect Ratio.");
 			aspect_ratio_info->par_width    = 1;
 			aspect_ratio_info->par_height   = 1;
 			break;
@@ -955,7 +1005,7 @@
 				VIDC_SM_EXTENDED_PAR_HEIGHT_SHFT);
 			break;
 		default:
-			DDL_MSG_ERROR("Incorrect Aspect Ratio.");
+			DDL_MSG_LOW("Incorrect Aspect Ratio.");
 			aspect_ratio_info->par_width    = 1;
 			aspect_ratio_info->par_height   = 1;
 			break;
@@ -1015,3 +1065,71 @@
 			timeout);
 }
 
+void vidc_sm_set_mp2datadump_enable(struct ddl_buf_addr *shared_mem,
+	struct ddl_mp2_datadumpenabletype *ddl_mp2_datadump_enable)
+{
+	u32 mp2_datadump_enable = 0;
+
+	mp2_datadump_enable = VIDC_SETFIELD(
+				ddl_mp2_datadump_enable->userdatadump_enable,
+				VIDC_SM_MP2_USERDATA_DUMP_ENABLE_SHFT,
+				VIDC_SM_MP2_USERDATA_DUMP_ENABLE_BMSK) |
+				VIDC_SETFIELD(ddl_mp2_datadump_enable->
+				pictempscalable_extdump_enable ? 1 : 0,
+				VIDC_SM_MP2_PICT_TEMP_DUMP_ENABLE_SHFT,
+				VIDC_SM_MP2_PICT_TEMP_DUMP_ENABLE_BMSK) |
+				VIDC_SETFIELD(ddl_mp2_datadump_enable->
+				picspat_extdump_enable ? 1 : 0,
+				VIDC_SM_MP2_PICT_SPAT_EXT_DUMP_ENABLE_SHFT,
+				VIDC_SM_MP2_PICT_SPAT_EXT_DUMP_ENABLE_BMSK) |
+				VIDC_SETFIELD(ddl_mp2_datadump_enable->
+				picdisp_extdump_enable ? 1 : 0,
+				VIDC_SM_MP2_PICT_DISP_EXT_DUMP_ENABLE_SHFT,
+				VIDC_SM_MP2_PICT_DISP_EXT_DUMP_ENABLE_BMSK) |
+				VIDC_SETFIELD(ddl_mp2_datadump_enable->
+				copyright_extdump_enable ? 1 : 0,
+				VIDC_SM_MP2_COPYRIGHT_EXT_DUMP_ENABLE_SHFT,
+				VIDC_SM_MP2_COPYRIGHT_EXT_DUMP_ENABLE_BMSK) |
+				VIDC_SETFIELD(ddl_mp2_datadump_enable->
+				quantmatrix_extdump_enable ? 1 : 0,
+				VIDC_SM_MP2_QMATRIX_EXT_DUMP_ENABLE_SHFT,
+				VIDC_SM_MP2_QMATRIX_EXT_DUMP_ENABLE_BMSK) |
+				VIDC_SETFIELD(ddl_mp2_datadump_enable->
+				seqscalable_extdump_enable ? 1 : 0,
+				VIDC_SM_MP2_SCAL_EXT_DUMP_ENABLE_SHFT,
+				VIDC_SM_MP2_SCAL_EXT_DUMP_ENABLE_BMSK) |
+				VIDC_SETFIELD(ddl_mp2_datadump_enable->
+				seqdisp_extdump_enable ? 1 : 0,
+				VIDC_SM_MP2_SEQ_DISP_EXT_DUMP_ENABLE_SHFT,
+				VIDC_SM_MP2_SEQ_DISP_EXT_DUMP_ENABLE_BMSK) |
+				VIDC_SETFIELD(ddl_mp2_datadump_enable->
+				seq_extdump_enable ? 1 : 0,
+				VIDC_SM_MP2_SEQ_EXT_DUMP_ENABLE_SHFT,
+				VIDC_SM_MP2_SEQ_EXT_DUMP_ENABLE_BMSK);
+	DDL_MEM_WRITE_32(shared_mem, VIDC_SM_MP2_DATA_DUMP_CONTROL_ADDR,
+			mp2_datadump_enable);
+
+}
+
+void vidc_sm_get_mp2datadump_status(struct ddl_buf_addr
+		*shared_mem, u32 *ext_userdata_present)
+{
+	u32 status;
+
+	status = DDL_MEM_READ_32(shared_mem,
+			VIDC_SM_MP2_DATA_DUMP_STATUS_ADDR);
+	*ext_userdata_present = (u32) VIDC_GETFIELD(status,
+				VIDC_SM_MP2_USERDATA_DUMP_STATUS_BMSK,
+				VIDC_SM_MP2_USERDATA_DUMP_STATUS_SHFT);
+}
+
+void vidc_sm_set_mp2datadumpbuffer(struct ddl_buf_addr *shared_mem,
+		u32 mp2datadumpaddr, u32 mp2datadumpsize)
+{
+	DDL_MEM_WRITE_32(shared_mem,
+			VIDC_SM_MP2_DATA_DUMP_BUFFER_ADDR,
+			mp2datadumpaddr);
+	DDL_MEM_WRITE_32(shared_mem,
+			VIDC_SM_MP2_DATA_DUMP_BUFFER_SIZE_ADDR,
+			mp2datadumpsize);
+}
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 1a46c36..9cb1933 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
@@ -139,7 +139,7 @@
 void vidc_sm_set_metadata_enable(struct ddl_buf_addr *shared_mem,
 	u32 extradata_enable, u32 qp_enable, u32 concealed_mb_enable,
 	u32 vc1Param_enable, u32 sei_nal_enable, u32 vui_enable,
-	u32 enc_slice_size_enable);
+	u32 enc_slice_size_enable, u32 mp2_data_dump_enable);
 void vidc_sm_get_metadata_status(struct ddl_buf_addr *shared_mem,
 	u32 *pb_metadata_present);
 void vidc_sm_get_metadata_display_index(struct ddl_buf_addr *shared_mem,
@@ -193,4 +193,11 @@
 	u32 *output_buffer_size);
 void vidc_sm_set_video_core_timeout_value(struct ddl_buf_addr *shared_mem,
 	u32 timeout);
+void vidc_sm_get_mp2datadump_status(struct ddl_buf_addr
+		*shared_mem, u32 *ext_userdata_present);
+void vidc_sm_set_mp2datadump_enable(struct ddl_buf_addr *shared_mem,
+	struct ddl_mp2_datadumpenabletype *ddl_mp2_datadump_enable);
+void vidc_sm_set_mp2datadumpbuffer(struct ddl_buf_addr *shared_mem,
+		u32 mp2datadumpaddr, u32 mp2datadumpsize);
+
 #endif
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c
index 260cd72..5897a33 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c
@@ -112,10 +112,10 @@
 					&iova,
 					&buffer_size,
 					UNCACHED, 0);
-			if (ret) {
+			if (ret || !iova) {
 				DDL_MSG_ERROR(
-				"%s():DDL ION ion map iommu failed\n",
-				 __func__);
+				"%s():DDL ION ion map iommu failed, ret = %d iova = 0x%lx\n",
+					__func__, ret, iova);
 				goto unmap_ion_alloc;
 			}
 			addr->alloced_phys_addr = (phys_addr_t) iova;
@@ -427,7 +427,7 @@
 		time_data->ddl_t1 = act_time;
 		DDL_MSG_LOW("\n%s(): Start Time (%u)", func_name, act_time);
 	} else if (vidc_msg_timing) {
-		DDL_MSG_TIME("\n%s(): Timer already started! St(%u) Act(%u)",
+		DDL_MSG_LOW("\n%s(): Timer already started! St(%u) Act(%u)",
 			func_name, time_data->ddl_t1, act_time);
 	}
 }
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
index d1f6e07..978d1de 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
@@ -260,6 +260,12 @@
 		vidc_sm_set_mpeg4_profile_override(
 			&ddl->shared_mem[ddl->command_channel],
 			VIDC_SM_PROFILE_INFO_ASP);
+	if (VCD_CODEC_MPEG2 == decoder->codec.codec)
+		vidc_sm_set_mp2datadumpbuffer(
+			&ddl->shared_mem[ddl->command_channel],
+			DDL_ADDR_OFFSET(ddl_context->dram_base_a,
+			ddl->codec_data.decoder.hw_bufs.extnuserdata),
+			DDL_KILO_BYTE(2));
 	if (VCD_CODEC_H264 == decoder->codec.codec)
 		vidc_sm_set_decoder_sei_enable(
 			&ddl->shared_mem[ddl->command_channel],
@@ -867,7 +873,6 @@
 	DDL_MEMSET(encoder->batch_frame.slice_batch_in.align_virtual_addr, 0,
 		sizeof(struct vidc_1080p_enc_slice_batch_in_param));
 	encoder->batch_frame.out_frm_next_frmindex = 0;
-	encoder->batch_frame.first_output_frame_tag = 0;
 	bitstream_size = encoder->batch_frame.output_frame[0].vcd_frm.alloc_len;
 	encoder->output_buf_req.sz = bitstream_size;
 	y_addr = DDL_OFFSET(ddl_context->dram_base_b.align_physical_addr,
@@ -960,6 +965,7 @@
 		ddl_update_core_start_time(__func__, ENC_SLICE_OP_TIME);
 		ddl_set_core_start_time(__func__, ENC_OP_TIME);
 	}
+	encoder->num_slices_comp = 0;
 	ddl_vidc_encode_set_batch_slice_info(ddl);
 	ddl_context->vidc_encode_slice_batch_start[ddl->command_channel] (
 			&enc_param);
diff --git a/drivers/video/msm/vidc/1080p/ddl/vidc.c b/drivers/video/msm/vidc/1080p/ddl/vidc.c
index d399847..3c445bc 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vidc.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vidc.c
@@ -520,8 +520,12 @@
 	u32 frame = 0;
 
 	VIDC_HWIO_IN(REG_760102, &frame);
-	*pe_frame = (enum vidc_1080p_decode_frame)
-		(frame & VIDC_1080P_SI_RG8_DECODE_FRAMETYPE_MASK);
+	if (frame & 0x10)
+		*pe_frame = (enum vidc_1080p_decode_frame)
+			VIDC_1080P_DECODE_FRAMETYPE_IDR;
+	else
+		*pe_frame = (enum vidc_1080p_decode_frame)
+			(frame & VIDC_1080P_SI_RG8_DECODE_FRAMETYPE_MASK);
 }
 
 void vidc_1080p_get_decode_frame_result(
diff --git a/drivers/video/msm/vidc/1080p/ddl/vidc.h b/drivers/video/msm/vidc/1080p/ddl/vidc.h
index 7b8dc6f..22fcd1c 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vidc.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vidc.h
@@ -277,6 +277,7 @@
 	VIDC_1080P_DECODE_FRAMETYPE_P          = 2,
 	VIDC_1080P_DECODE_FRAMETYPE_B          = 3,
 	VIDC_1080P_DECODE_FRAMETYPE_OTHERS     = 4,
+	VIDC_1080P_DECODE_FRAMETYPE_IDR        = 5,
 	VIDC_1080P_DECODE_FRAMETYPE_32BIT      = 0x7FFFFFFF
 };
 enum vidc_1080P_decode_frame_correct_type {
diff --git a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
index 291de5f..3ac396c 100644
--- a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
+++ b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
@@ -85,9 +85,10 @@
 				&iova,
 				&buffer_size,
 				UNCACHED, 0);
-		if (ret) {
-			DDL_MSG_ERROR("%s():DDL ION client iommu map failed\n",
-						 __func__);
+		if (ret || !iova) {
+			DDL_MSG_ERROR(
+			"%s():DDL ION client iommu map failed, ret = %d iova = 0x%lx\n",
+			__func__, ret, iova);
 			goto ion_unmap_bail_out;
 		}
 		addr->mapped_buffer = NULL;
@@ -536,9 +537,9 @@
 	u32 enc_perf_level = 0, dec_perf_level = 0;
 	u32 bus_clk_index, client_type = 0;
 	int rc = 0;
-
-	if (dev_ctxt->turbo_mode_set)
-		return rc;
+	bool turbo_enabled = false;
+	bool turbo_supported =
+		!resource_context.vidc_platform_data->disable_turbo;
 
 	cctxt_itr = dev_ctxt->cctxt_list_head;
 	while (cctxt_itr) {
@@ -546,6 +547,9 @@
 			dec_perf_level += cctxt_itr->reqd_perf_lvl;
 		else
 			enc_perf_level += cctxt_itr->reqd_perf_lvl;
+
+		if (cctxt_itr->is_turbo_enabled)
+			turbo_enabled = true;
 		cctxt_itr = cctxt_itr->next;
 	}
 
@@ -562,15 +566,17 @@
 
 	if (dev_ctxt->reqd_perf_lvl + dev_ctxt->curr_perf_lvl == 0)
 		bus_clk_index = 2;
-	else if (resource_context.vidc_platform_data->disable_turbo
-						&& bus_clk_index == 3) {
-		VCDRES_MSG_ERROR("Warning: Turbo mode not supported "
-				" falling back to 1080p bus\n");
+	else if ((!turbo_supported || !turbo_enabled) && bus_clk_index == 3) {
+		if (!turbo_supported)
+			VCDRES_MSG_MED("Warning: Turbo mode not supported "\
+					" falling back to 1080p bus\n");
 		bus_clk_index = 2;
 	}
 
 	if (bus_clk_index == 3)
-		dev_ctxt->turbo_mode_set = 1;
+		dev_ctxt->turbo_mode_set = true;
+	else
+		dev_ctxt->turbo_mode_set = false;
 
 	bus_clk_index = (bus_clk_index << 1) + (client_type + 1);
 	VCDRES_MSG_LOW("%s(), bus_clk_index = %d", __func__, bus_clk_index);
@@ -586,21 +592,18 @@
 	struct vcd_dev_ctxt *dev_ctxt)
 {
 	u32 vidc_freq = 0;
+	bool turbo_supported =
+		!resource_context.vidc_platform_data->disable_turbo;
+
 	if (!pn_set_perf_lvl || !dev_ctxt) {
 		VCDRES_MSG_ERROR("%s(): NULL pointer! dev_ctxt(%p)\n",
 			__func__, dev_ctxt);
 		return false;
 	}
-	if (dev_ctxt->turbo_mode_set &&
-			(req_perf_lvl < RESTRK_1080P_TURBO_PERF_LEVEL)) {
-		VCDRES_MSG_MED("%s(): TURBO MODE!!\n", __func__);
-		return true;
-	}
 
 	VCDRES_MSG_LOW("%s(), req_perf_lvl = %d", __func__, req_perf_lvl);
 
-	if (resource_context.vidc_platform_data->disable_turbo
-			&& req_perf_lvl > RESTRK_1080P_MAX_PERF_LEVEL) {
+	if (!turbo_supported && req_perf_lvl > RESTRK_1080P_MAX_PERF_LEVEL) {
 		VCDRES_MSG_ERROR("%s(): Turbo not supported! dev_ctxt(%p)\n",
 			__func__, dev_ctxt);
 	}
@@ -630,10 +633,11 @@
 		*pn_set_perf_lvl = RESTRK_1080P_TURBO_PERF_LEVEL;
 	}
 
-	if (resource_context.vidc_platform_data->disable_turbo &&
-		*pn_set_perf_lvl == RESTRK_1080P_TURBO_PERF_LEVEL) {
-		VCDRES_MSG_ERROR("Warning: Turbo mode not supported "
-				" falling back to 1080p clocks\n");
+	if ((!turbo_supported || !dev_ctxt->turbo_mode_set) &&
+		 *pn_set_perf_lvl == RESTRK_1080P_TURBO_PERF_LEVEL) {
+		if (!turbo_supported)
+			VCDRES_MSG_ERROR("Warning: Turbo mode not supported "\
+					" falling back to 1080p clocks\n");
 		vidc_freq = vidc_clk_table[2];
 		*pn_set_perf_lvl = RESTRK_1080P_MAX_PERF_LEVEL;
 	}
@@ -955,27 +959,54 @@
 
 int res_trk_open_secure_session()
 {
-	int rc;
-
-	if (res_trk_check_for_sec_session() == 1) {
-		mutex_lock(&resource_context.secure_lock);
+	int rc, memtype;
+	if (!res_trk_check_for_sec_session()) {
+		pr_err("Secure sessions are not active\n");
+		return -EINVAL;
+	}
+	mutex_lock(&resource_context.secure_lock);
+	if (!resource_context.sec_clk_heap) {
 		pr_err("Securing...\n");
 		rc = res_trk_enable_iommu_clocks();
 		if (rc) {
 			pr_err("IOMMU clock enabled failed while open");
 			goto error_open;
 		}
-		msm_ion_secure_heap(ION_HEAP(resource_context.memtype));
-		msm_ion_secure_heap(ION_HEAP(resource_context.cmd_mem_type));
-
-		if (resource_context.vidc_platform_data->secure_wb_heap)
-			msm_ion_secure_heap(ION_HEAP(ION_CP_WB_HEAP_ID));
-
+		memtype = ION_HEAP(resource_context.memtype);
+		rc = msm_ion_secure_heap(memtype);
+		if (rc) {
+			pr_err("ION heap secure failed heap id %d rc %d\n",
+				   resource_context.memtype, rc);
+			goto disable_iommu_clks;
+		}
+		memtype = ION_HEAP(resource_context.cmd_mem_type);
+		rc = msm_ion_secure_heap(memtype);
+		if (rc) {
+			pr_err("ION heap secure failed heap id %d rc %d\n",
+				   resource_context.cmd_mem_type, rc);
+			goto unsecure_memtype_heap;
+		}
+		if (resource_context.vidc_platform_data->secure_wb_heap) {
+			memtype = ION_HEAP(ION_CP_WB_HEAP_ID);
+			rc = msm_ion_secure_heap(memtype);
+			if (rc) {
+				pr_err("WB_HEAP_ID secure failed rc %d\n", rc);
+				goto unsecure_cmd_heap;
+			}
+		}
+		resource_context.sec_clk_heap = 1;
 		res_trk_disable_iommu_clocks();
-		mutex_unlock(&resource_context.secure_lock);
 	}
+	mutex_unlock(&resource_context.secure_lock);
 	return 0;
+unsecure_cmd_heap:
+	msm_ion_unsecure_heap(ION_HEAP(resource_context.memtype));
+unsecure_memtype_heap:
+	msm_ion_unsecure_heap(ION_HEAP(resource_context.cmd_mem_type));
+disable_iommu_clks:
+	res_trk_disable_iommu_clocks();
 error_open:
+	resource_context.sec_clk_heap = 0;
 	mutex_unlock(&resource_context.secure_lock);
 	return rc;
 }
@@ -983,12 +1014,13 @@
 int res_trk_close_secure_session()
 {
 	int rc;
-	if (res_trk_check_for_sec_session() == 1) {
+	if (res_trk_check_for_sec_session() == 1 &&
+		resource_context.sec_clk_heap) {
 		pr_err("Unsecuring....\n");
 		mutex_lock(&resource_context.secure_lock);
 		rc = res_trk_enable_iommu_clocks();
 		if (rc) {
-			pr_err("IOMMU clock enabled failed while close");
+			pr_err("IOMMU clock enabled failed while close\n");
 			goto error_close;
 		}
 		msm_ion_unsecure_heap(ION_HEAP(resource_context.cmd_mem_type));
@@ -998,6 +1030,7 @@
 			msm_ion_unsecure_heap(ION_HEAP(ION_CP_WB_HEAP_ID));
 
 		res_trk_disable_iommu_clocks();
+		resource_context.sec_clk_heap = 0;
 		mutex_unlock(&resource_context.secure_lock);
 	}
 	return 0;
diff --git a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.h b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.h
index 01999a4..a980230 100644
--- a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.h
+++ b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.h
@@ -14,7 +14,7 @@
 #define _VIDEO_720P_RESOURCE_TRACKER_H_
 
 #include <linux/regulator/consumer.h>
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
 #include "vcd_res_tracker_api.h"
 #ifdef CONFIG_MSM_BUS_SCALING
 #include <mach/msm_bus.h>
@@ -57,6 +57,7 @@
 	u32 mmu_clks_on;
 	u32 secure_session;
 	struct mutex secure_lock;
+	u32 sec_clk_heap;
 };
 
 #if DEBUG
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 f8d9053..5f126fd 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,7 +13,7 @@
 #ifndef _VIDEO_720P_RESOURCE_TRACKER_H_
 #define _VIDEO_720P_RESOURCE_TRACKER_H_
 #include <mach/board.h>
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
 #include "vcd_res_tracker_api.h"
 
 #define VCD_RESTRK_MIN_PERF_LEVEL 37900
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 927f19b..68bcd5c 100644
--- a/drivers/video/msm/vidc/common/dec/vdec.c
+++ b/drivers/video/msm/vidc/common/dec/vdec.c
@@ -936,9 +936,10 @@
 					SZ_4K, 0, (unsigned long *)&iova,
 					(unsigned long *)&buffer_size,
 					UNCACHED, 0);
-			if (rc) {
-				ERR("%s():get_ION_kernel physical addr fail\n",
-						 __func__);
+			if (rc || !iova) {
+				ERR(
+				"%s():get_ION_kernel physical addr fail, rc = %d iova = 0x%lx\n",
+					__func__, rc, iova);
 				goto ion_map_error;
 			}
 			vcd_h264_mv_buffer->physical_addr = (u8 *) iova;
@@ -2078,10 +2079,6 @@
 	mutex_unlock(&client_ctx->msg_queue_lock);
 	vcd_status = vcd_close(client_ctx->vcd_handle);
 
-	if (vcd_status) {
-		mutex_unlock(&vid_dec_device_p->lock);
-		return false;
-	}
 	client_ctx->user_ion_client = NULL;
 	memset((void *)client_ctx, 0, sizeof(struct video_client_ctx));
 	vid_dec_device_p->num_clients--;
diff --git a/drivers/video/msm/vidc/common/enc/venc_internal.c b/drivers/video/msm/vidc/common/enc/venc_internal.c
index 50cccbb..5ee0a3d 100644
--- a/drivers/video/msm/vidc/common/enc/venc_internal.c
+++ b/drivers/video/msm/vidc/common/enc/venc_internal.c
@@ -1868,9 +1868,10 @@
 					(unsigned long *)&iova,
 					(unsigned long *)&buffer_size,
 					UNCACHED, 0);
-			if (rc) {
-				ERR("%s():ION map iommu addr fail\n",
-					 __func__);
+			if (rc || !iova) {
+				ERR(
+				"%s():ION map iommu addr fail, rc = %d, iova = 0x%lx\n",
+					__func__, rc, iova);
 				goto map_ion_error;
 			}
 			control->physical_addr =  (u8 *) iova;
diff --git a/drivers/video/msm/vidc/common/init/vidc_init.c b/drivers/video/msm/vidc/common/init/vidc_init.c
index c884cf5..221c154 100644
--- a/drivers/video/msm/vidc/common/init/vidc_init.c
+++ b/drivers/video/msm/vidc/common/init/vidc_init.c
@@ -680,9 +680,10 @@
 						(unsigned long *) &buffer_size,
 						UNCACHED,
 						ION_IOMMU_UNMAP_DELAYED);
-				if (ret) {
-					ERR("%s():ION iommu map fail\n",
-					 __func__);
+				if (ret || !iova) {
+					ERR(
+					"%s():ION iommu map fail, ret = %d, iova = 0x%lx\n",
+						__func__, ret, iova);
 					goto ion_map_error;
 				}
 				phys_addr = iova;
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c b/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c
index 7c0d9fe..8f52f83 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c
@@ -213,11 +213,11 @@
 	return vcd_handle_input_frame(cctxt, input_frame);
 }
 
-static u32 vcd_pause_in_run(struct vcd_clnt_ctxt *cctxt)
+static u32 vcd_pause_cmn(struct vcd_clnt_ctxt *cctxt)
 {
 	u32 rc = VCD_S_SUCCESS;
 
-	VCD_MSG_LOW("vcd_pause_in_run:");
+	VCD_MSG_LOW("vcd_pause_cmn:");
 
 	if (cctxt->sched_clnt_hdl) {
 		rc = vcd_sched_suspend_resume_clnt(cctxt, false);
@@ -1709,7 +1709,7 @@
 	 vcd_encode_frame_cmn,
 	 vcd_decode_start_in_run,
 	 vcd_decode_frame_cmn,
-	 vcd_pause_in_run,
+	 vcd_pause_cmn,
 	 NULL,
 	 vcd_flush_cmn,
 	 vcd_stop_in_run,
@@ -1784,7 +1784,7 @@
 	 vcd_encode_frame_cmn,
 	 NULL,
 	 vcd_decode_frame_cmn,
-	 NULL,
+	 vcd_pause_cmn,
 	 NULL,
 	 vcd_flush_in_eos,
 	 vcd_stop_in_eos,
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_core.h b/drivers/video/msm/vidc/common/vcd/vcd_core.h
index 8126a0e..ae97561 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_core.h
+++ b/drivers/video/msm/vidc/common/vcd/vcd_core.h
@@ -13,7 +13,7 @@
 #ifndef _VCD_CORE_H_
 #define _VCD_CORE_H_
 
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
 #include <media/msm/vcd_api.h>
 #include "vcd_ddl_api.h"
 
@@ -147,7 +147,7 @@
 	u32 reqd_perf_lvl;
 	u32 curr_perf_lvl;
 	u32 set_perf_lvl_pending;
-	u32 turbo_mode_set;
+	bool turbo_mode_set;
 };
 
 struct vcd_clnt_status {
@@ -214,6 +214,7 @@
 	u32 meta_mode;
 	int perf_set_by_client;
 	int secure;
+	bool is_turbo_enabled;
 };
 
 #define VCD_BUFFERPOOL_INUSE_DECREMENT(val) \
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_device_sm.c b/drivers/video/msm/vidc/common/vcd/vcd_device_sm.c
index 53495e0..0d13028 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_device_sm.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_device_sm.c
@@ -759,7 +759,6 @@
 	client = dev_ctxt->cctxt_list_head;
 	dev_ctxt->cctxt_list_head = cctxt;
 	cctxt->next = client;
-	dev_ctxt->turbo_mode_set = 0;
 
 	*clnt_cctxt = cctxt;
 
@@ -858,7 +857,7 @@
 	} else {
 		VCD_MSG_ERROR("Unsupported API in client state %d",
 				  cctxt->clnt_state.state);
-
+		vcd_destroy_client_context(cctxt);
 		rc = VCD_ERR_BAD_STATE;
 	}
 
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_sub.c b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
index 28ea453..71e8df8 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_sub.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
@@ -121,8 +121,10 @@
 				(unsigned long *)&iova,
 				(unsigned long *)&buffer_size,
 				UNCACHED, 0);
-			if (ret) {
-				pr_err("%s() ION iommu map failed", __func__);
+			if (ret || !iova) {
+				pr_err(
+				"%s() ION iommu map failed, ret = %d, iova = 0x%lx",
+					__func__, ret, iova);
 				goto ion_map_bailout;
 			}
 			map_buffer->phy_addr = iova;
@@ -3049,6 +3051,7 @@
 {
 	u32 rc;
 	u32 res_trk_perf_level;
+	u32 turbo_perf_level;
 	if (!perf_level) {
 		VCD_MSG_ERROR("Invalid parameters\n");
 		return -EINVAL;
@@ -3058,10 +3061,13 @@
 		rc = -ENOTSUPP;
 		goto perf_level_not_supp;
 	}
+	turbo_perf_level = get_res_trk_perf_level(VCD_PERF_LEVEL_TURBO);
 	rc = vcd_set_perf_level(cctxt->dev_ctxt, res_trk_perf_level);
 	if (!rc) {
 		cctxt->reqd_perf_lvl = res_trk_perf_level;
 		cctxt->perf_set_by_client = 1;
+		if (res_trk_perf_level == turbo_perf_level)
+			cctxt->is_turbo_enabled = true;
 	}
 perf_level_not_supp:
 	return rc;
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/blkdev.h b/include/linux/blkdev.h
index a19d374..e76b0ae 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -1167,6 +1167,8 @@
 
 struct work_struct;
 int kblockd_schedule_work(struct request_queue *q, struct work_struct *work);
+int kblockd_schedule_delayed_work(struct request_queue *q,
+			struct delayed_work *dwork, unsigned long delay);
 
 #ifdef CONFIG_BLK_CGROUP
 /*
diff --git a/include/linux/coresight-stm.h b/include/linux/coresight-stm.h
index 20c4963..754f2f3 100644
--- a/include/linux/coresight-stm.h
+++ b/include/linux/coresight-stm.h
@@ -14,12 +14,12 @@
 #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_ALL			= 0x1F,
 };
 
 enum {
diff --git a/include/linux/coresight.h b/include/linux/coresight.h
index ac35780..3bba69c 100644
--- a/include/linux/coresight.h
+++ b/include/linux/coresight.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -15,7 +15,6 @@
 
 #include <linux/device.h>
 
-
 /* Peripheral id registers (0xFD0-0xFEC) */
 #define CORESIGHT_PERIPHIDR4	(0xFD0)
 #define CORESIGHT_PERIPHIDR5	(0xFD4)
@@ -31,7 +30,6 @@
 #define CORESIGHT_COMPIDR2	(0xFF8)
 #define CORESIGHT_COMPIDR3	(0xFFC)
 
-
 /* DBGv7 with baseline CP14 registers implemented */
 #define ARM_DEBUG_ARCH_V7B	(0x3)
 /* DBGv7 with all CP14 registers implemented */
@@ -47,6 +45,7 @@
 };
 
 enum coresight_dev_type {
+	CORESIGHT_DEV_TYPE_NONE,
 	CORESIGHT_DEV_TYPE_SINK,
 	CORESIGHT_DEV_TYPE_LINK,
 	CORESIGHT_DEV_TYPE_LINKSINK,
@@ -134,6 +133,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 {
@@ -158,6 +158,7 @@
 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 coresight_device *
 coresight_register(struct coresight_desc *desc) { return NULL; }
@@ -165,6 +166,7 @@
 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 7769950..45d51ce 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -112,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
@@ -689,7 +689,7 @@
 /* LOG CODES */
 
 #define LOG_0	0x0
-#define LOG_1	0x15A7
+#define LOG_1	0x1636
 #define LOG_2	0x0
 #define LOG_3	0x0
 #define LOG_4	0x4910
diff --git a/include/linux/dvb/video.h b/include/linux/dvb/video.h
index 1d750c0..81475c2 100644
--- a/include/linux/dvb/video.h
+++ b/include/linux/dvb/video.h
@@ -57,6 +57,19 @@
 	VIDEO_CENTER_CUT_OUT  /* use center cut out format */
 } video_displayformat_t;
 
+enum video_codec_t {
+	VIDEO_CODECTYPE_NONE,
+	VIDEO_CODECTYPE_MPEG2,
+	VIDEO_CODECTYPE_MPEG4,
+	VIDEO_CODECTYPE_H264,
+	VIDEO_CODECTYPE_VC1
+};
+
+enum video_out_format_t {
+	VIDEO_YUV_FORMAT_NV12,
+	VIDEO_YUV_FORMAT_TILE_4x2
+};
+
 typedef struct {
 	int w;
 	int h;
@@ -84,12 +97,29 @@
 #define VIDEO_CMD_FREEZE      (2)
 #define VIDEO_CMD_CONTINUE    (3)
 
+#define VIDEO_CMD_SET_CODEC           (4)
+#define VIDEO_CMD_GET_CODEC           (5)
+#define VIDEO_CMD_SET_OUTPUT_FORMAT   (6)
+#define VIDEO_CMD_GET_OUTPUT_FORMAT   (7)
+#define VIDEO_CMD_GET_BUFFER_REQ      (8)
+#define VIDEO_CMD_SET_INPUT_BUFFERS   (9)
+#define VIDEO_CMD_SET_OUTPUT_BUFFERS  (10)
+#define VIDEO_CMD_READ_RAW_OUTPUT     (11)
+#define VIDEO_CMD_GET_PIC_RES         (12)
+#define VIDEO_CMD_FREE_INPUT_BUFFERS  (13)
+#define VIDEO_CMD_FREE_OUTPUT_BUFFERS (14)
+#define VIDEO_CMD_GET_H264_MV_BUFFER  (15)
+#define VIDEO_CMD_SET_H264_MV_BUFFER  (16)
+#define VIDEO_CMD_FREE_H264_MV_BUFFER (17)
+#define VIDEO_CMD_CLEAR_INPUT_BUFFER  (18)
+#define VIDEO_CMD_CLEAR_OUTPUT_BUFFER (19)
+
 /* Flags for VIDEO_CMD_FREEZE */
-#define VIDEO_CMD_FREEZE_TO_BLACK     	(1 << 0)
+#define VIDEO_CMD_FREEZE_TO_BLACK	(1 << 0)
 
 /* Flags for VIDEO_CMD_STOP */
-#define VIDEO_CMD_STOP_TO_BLACK      	(1 << 0)
-#define VIDEO_CMD_STOP_IMMEDIATELY     	(1 << 1)
+#define VIDEO_CMD_STOP_TO_BLACK		(1 << 0)
+#define VIDEO_CMD_STOP_IMMEDIATELY	(1 << 1)
 
 /* Play input formats: */
 /* The decoder has no special format requirements */
@@ -97,6 +127,56 @@
 /* The decoder requires full GOPs */
 #define VIDEO_PLAY_FMT_GOP          (1)
 
+/* Picture Resolution for Video Data */
+struct video_pic_res {
+	unsigned int width;
+	unsigned int height;
+	unsigned int stride;
+	unsigned int scan_lines;
+};
+
+/* Video Buffer Properties */
+struct video_buffer_prop {
+	unsigned int alignment;
+	unsigned int buf_poolid;
+	size_t buf_size;
+};
+
+/* Buffer Requirements from Video Decoder */
+struct video_buffer_req {
+	unsigned int num_input_buffers;  /* Number of Input Buffers */
+	unsigned int num_output_buffers; /* Number of Output Buffers */
+	struct video_buffer_prop input_buf_prop; /* Input Buffer Properties */
+	struct video_buffer_prop output_buf_prop; /* Output Buffer Prop */
+};
+
+/* Video Data Buffer Structure for Input and Output */
+struct video_data_buffer {
+	void __user *bufferaddr; /* Pointer to Buffer */
+	size_t buffer_len;       /* Length of Buffer */
+	int ion_fd;             /* file Descriptor */
+	size_t offset;
+	size_t mmaped_size;
+	void *client_data;
+	void *ip_buffer_tag;
+	__u64 pts;
+};
+
+struct video_h264_mv {
+	size_t size;
+	int count;
+	int ion_fd;
+	int offset;
+};
+
+struct video_mv_buff_size {
+	int width;
+	int height;
+	int size;
+	int alignment;
+};
+
+
 /* The structure must be zeroed before use by the application
    This ensures it can be extended safely in the future. */
 struct video_command {
@@ -112,11 +192,23 @@
 			   1 specifies forward single stepping,
 			   -1 specifies backward single stepping,
 			   >1: playback at speed/1000 of the normal speed,
-			   <-1: reverse playback at (-speed/1000) of the normal speed. */
+			   <-1: reverse playback at (-speed/1000) of
+				the normal speed. */
 			__s32 speed;
 			__u32 format;
 		} play;
 
+		union {
+			enum video_codec_t codec; /* Video Codec Type */
+			enum video_out_format_t format; /* YUV Format */
+			struct video_pic_res frame_res; /* Frame Resolution */
+			/* Buffer Requirements for Video Decoder */
+			struct video_buffer_req buf_req;
+			struct video_data_buffer buffer; /* Buffer Details */
+			struct video_mv_buff_size mv_buffer_req;
+			struct video_h264_mv mv_buffer_prop;
+		};
+
 		struct {
 			__u32 data[16];
 		} raw;
@@ -126,22 +218,47 @@
 /* FIELD_UNKNOWN can be used if the hardware does not know whether
    the Vsync is for an odd, even or progressive (i.e. non-interlaced)
    field. */
-#define VIDEO_VSYNC_FIELD_UNKNOWN  	(0)
-#define VIDEO_VSYNC_FIELD_ODD 		(1)
+#define VIDEO_VSYNC_FIELD_UNKNOWN	(0)
+#define VIDEO_VSYNC_FIELD_ODD		(1)
 #define VIDEO_VSYNC_FIELD_EVEN		(2)
 #define VIDEO_VSYNC_FIELD_PROGRESSIVE	(3)
 
 struct video_event {
 	__s32 type;
-#define VIDEO_EVENT_SIZE_CHANGED	1
-#define VIDEO_EVENT_FRAME_RATE_CHANGED	2
-#define VIDEO_EVENT_DECODER_STOPPED 	3
-#define VIDEO_EVENT_VSYNC 		4
+#define VIDEO_EVENT_SIZE_CHANGED	(1)
+#define VIDEO_EVENT_FRAME_RATE_CHANGED	(2)
+#define VIDEO_EVENT_DECODER_STOPPED	(3)
+#define VIDEO_EVENT_VSYNC		(4)
+#define VIDEO_EVENT_DECODER_PLAYING     (5)
+#define VIDEO_EVENT_DECODER_FREEZED     (6)
+#define VIDEO_EVENT_DECODER_RESUMED     (7)
+#define VIDEO_EVENT_INPUT_BUFFER_DONE   (8)
+#define VIDEO_EVENT_SEQ_HDR_FOUND       (9)
+#define VIDEO_EVENT_OUTPUT_BUFFER_DONE  (10)
+#define VIDEO_EVENT_OUTPUT_FLUSH_DONE   (11)
+#define VIDEO_EVENT_INPUT_FLUSH_DONE    (12)
+#define VIDEO_EVENT_INPUT_FLUSHED       (13)
+#define VIDEO_EVENT_OUTPUT_FLUSHED      (14)
+
+
+	unsigned int    status;
+#define VIDEO_STATUS_SUCESS             0
+#define VIDEO_STATUS_BITSTREAM_ERROR    1
+#define VIDEO_STATUS_FAILED             2
+#define VIDEO_STATUS_NORESOURCE         3
+#define VIDEO_STATUS_INVALID_CMD        4
+#define VIDEO_STATUS_INVALID_PARAM      5
+#define VIDEO_STATUS_INVALID_STATE      6
+#define VIDEO_STATUS_BUSY               7
+#define VIDEO_STATUS_INVALID_HANDLE     8
+#define VIDEO_STATUS_NO_SUPPORT         9
 	__kernel_time_t timestamp;
+
 	union {
 		video_size_t size;
 		unsigned int frame_rate;	/* in frames per 1000sec */
-		unsigned char vsync_field;	/* unknown/odd/even/progressive */
+		unsigned char vsync_field; /* unknown/odd/even/progressive */
+		struct video_data_buffer buffer; /* Output Buffer Details */
 	} u;
 };
 
@@ -149,8 +266,8 @@
 struct video_status {
 	int                   video_blank;   /* blank video on freeze? */
 	video_play_state_t    play_state;    /* current state of playback */
-	video_stream_source_t stream_source; /* current source (demux/memory) */
-	video_format_t        video_format;  /* current aspect ratio of stream*/
+	video_stream_source_t stream_source;/* current source (demux/memory) */
+	video_format_t        video_format; /* current aspect ratio of stream*/
 	video_displayformat_t display_format;/* selected cropping mode */
 };
 
@@ -160,7 +277,6 @@
 	__s32 size;
 };
 
-
 typedef
 struct video_highlight {
 	int     active;      /*    1=show highlight, 0=hide highlight */
@@ -268,9 +384,9 @@
 #define VIDEO_GET_PTS              _IOR('o', 57, __u64)
 
 /* Read the number of displayed frames since the decoder was started */
-#define VIDEO_GET_FRAME_COUNT  	   _IOR('o', 58, __u64)
+#define VIDEO_GET_FRAME_COUNT	   _IOR('o', 58, __u64)
 
-#define VIDEO_COMMAND     	   _IOWR('o', 59, struct video_command)
-#define VIDEO_TRY_COMMAND 	   _IOWR('o', 60, struct video_command)
+#define VIDEO_COMMAND		   _IOWR('o', 59, struct video_command)
+#define VIDEO_TRY_COMMAND	   _IOWR('o', 60, struct video_command)
 
 #endif /*_DVBVIDEO_H_*/
diff --git a/include/linux/epm_adc.h b/include/linux/epm_adc.h
index 9cf2acf..076302b 100644
--- a/include/linux/epm_adc.h
+++ b/include/linux/epm_adc.h
@@ -13,9 +13,80 @@
 	int32_t physical;
 };
 
+struct epm_psoc_init_resp {
+	u8	cmd;
+	u8	version;
+	u8	compatible_ver;
+	u8	firm_ver[3];
+	u8	num_dev;
+	u8	num_channel;
+};
+
+struct epm_psoc_channel_configure {
+	u8		cmd;
+	u8		device_num;
+	uint32_t	channel_num;
+};
+
+struct epm_psoc_set_avg {
+	u8	cmd;
+	u8	avg_period;
+	u8	return_code;
+};
+
+struct epm_psoc_get_data {
+	u8		cmd;
+	u8		dev_num;
+	u8		chan_num;
+	uint32_t	timestamp_resp_value;
+	uint32_t	reading_value;
+};
+
+struct epm_psoc_get_buffered_data {
+	u8		cmd;
+	u8		dev_num;
+	u8		status_mask;
+	u8		chan_idx;
+	uint32_t	chan_mask;
+	uint32_t	timestamp_start;
+	uint32_t	timestamp_end;
+	u8		buff_data[48];
+};
+
+struct epm_psoc_system_time_stamp {
+	u8		cmd;
+	uint32_t	timestamp;
+};
+
+struct epm_psoc_set_channel {
+	u8		cmd;
+	u8		dev_num;
+	uint32_t	channel_mask;
+};
+
+struct epm_psoc_get_avg_buffered_switch_data {
+	u8		cmd;
+	u8		status;
+	uint32_t	timestamp_start;
+	uint32_t	channel_mask;
+	u8		avg_data[54];
+};
+
+struct epm_psoc_set_channel_switch {
+	u8		cmd;
+	u8		dev;
+	uint32_t	delay;
+};
+
+struct epm_psoc_set_vadc {
+	u8		cmd;
+	u8		vadc_dev;
+	uint32_t	vadc_voltage;
+};
+
 #ifdef __KERNEL__
 struct epm_chan_properties {
-	uint32_t resistorValue;
+	uint32_t resistorvalue;
 	uint32_t gain;
 };
 
@@ -41,4 +112,41 @@
 
 #define EPM_ADC_DEINIT		_IOR(EPM_ADC_IOCTL_CODE, 3,	\
 					     uint32_t)
+
+#define EPM_PSOC_ADC_INIT		_IOR(EPM_ADC_IOCTL_CODE, 4, \
+					struct epm_psoc_init_resp)
+
+#define EPM_PSOC_ADC_CHANNEL_ENABLE	_IOWR(EPM_ADC_IOCTL_CODE, 5, \
+					struct epm_psoc_channel_configure)
+
+#define EPM_PSOC_ADC_CHANNEL_DISABLE	_IOWR(EPM_ADC_IOCTL_CODE, 6, \
+					struct epm_psoc_channel_configure)
+
+#define EPM_PSOC_ADC_SET_AVERAGING	_IOWR(EPM_ADC_IOCTL_CODE, 7, \
+					struct epm_psoc_set_avg)
+
+#define EPM_PSOC_ADC_GET_LAST_MEASUREMENT	_IOWR(EPM_ADC_IOCTL_CODE, 8, \
+						struct epm_psoc_get_data)
+
+#define EPM_PSOC_ADC_GET_BUFFERED_DATA		_IOWR(EPM_ADC_IOCTL_CODE, 9, \
+					struct epm_psoc_get_buffered_data)
+
+#define EPM_PSOC_ADC_GET_SYSTEM_TIMESTAMP	_IOWR(EPM_ADC_IOCTL_CODE, 10, \
+					struct epm_psoc_system_time_stamp)
+
+#define EPM_PSOC_ADC_SET_SYSTEM_TIMESTAMP	_IOWR(EPM_ADC_IOCTL_CODE, 11, \
+					struct epm_psoc_system_time_stamp)
+
+#define EPM_PSOC_ADC_GET_AVERAGE_DATA		_IOWR(EPM_ADC_IOCTL_CODE, 12, \
+				struct epm_psoc_get_avg_buffered_switch_data)
+
+#define EPM_PSOC_SET_CHANNEL_SWITCH		_IOWR(EPM_ADC_IOCTL_CODE, 13, \
+					struct epm_psoc_set_channel_switch)
+
+#define EPM_PSOC_CLEAR_BUFFER			_IOWR(EPM_ADC_IOCTL_CODE, 14, \
+						uint32_t)
+
+#define EPM_PSOC_ADC_SET_VADC_REFERENCE		_IOWR(EPM_ADC_IOCTL_CODE, 15, \
+						struct epm_psoc_set_vadc)
+
 #endif /* __EPM_ADC_H */
diff --git a/include/linux/i2c/atmel_mxt_ts.h b/include/linux/i2c/atmel_mxt_ts.h
index b54fcb4..5c3c728 100644
--- a/include/linux/i2c/atmel_mxt_ts.h
+++ b/include/linux/i2c/atmel_mxt_ts.h
@@ -69,7 +69,9 @@
 	bool	i2c_pull_up;
 	bool	digital_pwr_regulator;
 	int reset_gpio;
+	u32 reset_gpio_flags;
 	int irq_gpio;
+	u32 irq_gpio_flags;
 	int *key_codes;
 
 	u8(*read_chg) (void);
diff --git a/include/linux/iopoll.h b/include/linux/iopoll.h
index 7169870..f28053c 100644
--- a/include/linux/iopoll.h
+++ b/include/linux/iopoll.h
@@ -49,6 +49,28 @@
 })
 
 /**
+ * readl_poll_timeout_noirq - Periodically poll an address until a condition is met or a timeout occurs
+ * @addr: Address to poll
+ * @val: Variable to read the value into
+ * @cond: Break condition (usually involving @val)
+ * @max_reads: Maximum number of reads before giving up
+ * @time_between_us: Time to udelay() between successive reads
+ *
+ * Returns 0 on success and -ETIMEDOUT upon a timeout.
+ */
+#define readl_poll_timeout_noirq(addr, val, cond, max_reads, time_between_us) \
+({ \
+	int count; \
+	for (count = (max_reads); count > 0; count--) { \
+		(val) = readl(addr); \
+		if (cond) \
+			break; \
+		udelay(time_between_us); \
+	} \
+	(cond) ? 0 : -ETIMEDOUT; \
+})
+
+/**
  * readl_poll - Periodically poll an address until a condition is met
  * @addr: Address to poll
  * @val: Variable to read the value into
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/leds-pm8xxx.h b/include/linux/leds-pm8xxx.h
index 60755de..ff1a93b 100644
--- a/include/linux/leds-pm8xxx.h
+++ b/include/linux/leds-pm8xxx.h
@@ -85,6 +85,7 @@
  *  @dig_mod_gen_en - digital module generator
  *  @cs_out_en - current sink output enable
  *  @op_fdbck - selection of output as feedback for the boost
+ *  @cabc_en - enable cabc for backlight pwm control
  */
 struct wled_config_data {
 	u8	num_strings;
@@ -95,6 +96,7 @@
 	bool	dig_mod_gen_en;
 	bool	cs_out_en;
 	bool	op_fdbck;
+	bool	cabc_en;
 };
 
 /**
diff --git a/include/linux/mfd/pm8xxx/core.h b/include/linux/mfd/pm8xxx/core.h
index 08e9014..38c589d 100644
--- a/include/linux/mfd/pm8xxx/core.h
+++ b/include/linux/mfd/pm8xxx/core.h
@@ -75,6 +75,27 @@
 #define PM8XXX_REVISION_8917_TEST	0
 #define PM8XXX_REVISION_8917_1p0	1
 
+#define PM8XXX_RESTART_UNKNOWN		0
+#define PM8XXX_RESTART_CBL		1
+#define PM8XXX_RESTART_KPD		2
+#define PM8XXX_RESTART_CHG		3
+#define PM8XXX_RESTART_SMPL		4
+#define PM8XXX_RESTART_RTC		5
+#define PM8XXX_RESTART_HARD_RESET	6
+#define PM8XXX_RESTART_GEN_PURPOSE	7
+#define PM8XXX_RESTART_REASON_MASK	0x07
+
+static const char * const pm8xxx_restart_reason_str[] = {
+	[0] = "Unknown",
+	[1] = "Triggered from CBL (external charger)",
+	[2] = "Triggered from KPD (power key press)",
+	[3] = "Triggered from CHG (usb charger insertion)",
+	[4] = "Triggered from SMPL (sudden momentary power loss)",
+	[5] = "Triggered from RTC (real time clock)",
+	[6] = "Triggered by Hard Reset",
+	[7] = "Triggered by General Purpose Trigger",
+};
+
 struct pm8xxx_drvdata {
 	int			(*pmic_readb) (const struct device *dev,
 						u16 addr, u8 *val);
@@ -88,6 +109,8 @@
 						int irq);
 	enum pm8xxx_version	(*pmic_get_version) (const struct device *dev);
 	int			(*pmic_get_revision) (const struct device *dev);
+	u8			(*pmic_restart_reason)
+						(const struct device *dev);
 	void			*pm_chip_data;
 };
 
@@ -156,4 +179,12 @@
 	return dd->pmic_get_revision(dev);
 }
 
+static inline u8 pm8xxx_restart_reason(const struct device *dev)
+{
+	struct pm8xxx_drvdata *dd = dev_get_drvdata(dev);
+
+	if (!dd)
+		return -EINVAL;
+	return dd->pmic_restart_reason(dev);
+}
 #endif
diff --git a/include/linux/mfd/pm8xxx/pm8821.h b/include/linux/mfd/pm8xxx/pm8821.h
index 7ed7617..f41a632 100644
--- a/include/linux/mfd/pm8xxx/pm8821.h
+++ b/include/linux/mfd/pm8xxx/pm8821.h
@@ -21,6 +21,7 @@
 #include <linux/device.h>
 #include <linux/mfd/pm8xxx/pm8821-irq.h>
 #include <linux/mfd/pm8xxx/mpp.h>
+#include <linux/mfd/pm8xxx/tm.h>
 
 #define PM8821_NR_IRQS		(112)
 #define PM8821_NR_MPPS		(4)
@@ -38,6 +39,8 @@
 		PM8821_IRQ_BLOCK_BIT(PM8821_MPP_BLOCK_START, (mpp)-1))
 
 /* PMIC Interrupts */
+#define PM8821_OVERTEMP_IRQ		PM8821_IRQ_BLOCK_BIT(5, 2)
+#define PM8821_TEMPSTAT_IRQ		PM8821_IRQ_BLOCK_BIT(5, 7)
 
 struct pm8821_platform_data {
 	int					irq_base;
diff --git a/include/linux/mfd/pm8xxx/pm8921-bms.h b/include/linux/mfd/pm8xxx/pm8921-bms.h
index bbd032d..a73a284 100644
--- a/include/linux/mfd/pm8xxx/pm8921-bms.h
+++ b/include/linux/mfd/pm8xxx/pm8921-bms.h
@@ -116,7 +116,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
  */
@@ -125,10 +126,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 b00e050..7b389c5 100644
--- a/include/linux/mfd/pm8xxx/pm8921-charger.h
+++ b/include/linux/mfd/pm8xxx/pm8921-charger.h
@@ -93,6 +93,7 @@
  *			however, this should only be enabled for devices which
  *			control the DC OVP FETs otherwise this option should
  *			remain disabled
+ * @has_dc_supply:	report DC online if this bit is set in board file
  * @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
@@ -142,6 +143,7 @@
 	int64_t				batt_id_max;
 	bool				keep_btm_on_suspend;
 	bool				dc_unplug_check;
+	bool				has_dc_supply;
 	int				trkl_voltage;
 	int				weak_voltage;
 	int				trkl_current;
@@ -281,6 +283,13 @@
  *
  */
 int pm8921_usb_ovp_disable(int disable);
+/**
+ * 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)
 {
@@ -353,6 +362,10 @@
 {
 	return -ENXIO;
 }
+static inline int pm8921_is_batfet_closed(void)
+{
+	return 1;
+}
 #endif
 
 #endif
diff --git a/include/linux/mfd/pm8xxx/spk.h b/include/linux/mfd/pm8xxx/spk.h
index 1155d2f..2905a1d 100644
--- a/include/linux/mfd/pm8xxx/spk.h
+++ b/include/linux/mfd/pm8xxx/spk.h
@@ -21,6 +21,14 @@
  */
 struct pm8xxx_spk_platform_data {
 	bool spk_add_enable;
+	int cd_ng_threshold;
+	int cd_nf_preamp_bias;
+	int cd_ng_hold;
+	int cd_ng_max_atten;
+	int noise_mute;
+	int cd_ng_decay_rate;
+	int cd_ng_attack_rate;
+	int cd_delay;
 };
 
 /*
diff --git a/include/linux/mfd/wcd9xxx/core.h b/include/linux/mfd/wcd9xxx/core.h
index 105c2cb..f6d164d 100644
--- a/include/linux/mfd/wcd9xxx/core.h
+++ b/include/linux/mfd/wcd9xxx/core.h
@@ -157,10 +157,7 @@
 	int num_rx_port;
 	int num_tx_port;
 
-	u8 idbyte_0;
-	u8 idbyte_1;
-	u8 idbyte_2;
-	u8 idbyte_3;
+	u8 idbyte[4];
 };
 
 int wcd9xxx_reg_read(struct wcd9xxx *wcd9xxx, unsigned short reg);
diff --git a/include/linux/mfd/wcd9xxx/wcd9xxx-slimslave.h b/include/linux/mfd/wcd9xxx/wcd9xxx-slimslave.h
index 9619527..0d5d058 100644
--- a/include/linux/mfd/wcd9xxx/wcd9xxx-slimslave.h
+++ b/include/linux/mfd/wcd9xxx/wcd9xxx-slimslave.h
@@ -116,4 +116,6 @@
 			unsigned int *rx_ch,
 			unsigned int *tx_ch);
 int wcd9xxx_get_slave_port(unsigned int ch_num);
+int wcd9xxx_disconnect_port(struct wcd9xxx *wcd9xxx, unsigned int *ch_num,
+				unsigned int tot_ch, unsigned int rx_tx);
 #endif /* __WCD9310_SLIMSLAVE_H_ */
diff --git a/include/linux/mhl_8334.h b/include/linux/mhl_8334.h
index 1b19103..cb9d7fa 100644
--- a/include/linux/mhl_8334.h
+++ b/include/linux/mhl_8334.h
@@ -31,6 +31,17 @@
 	MHL_DISCOVERY_RESULT_MHL,
 };
 
+struct msc_command_struct {
+	u8 command;
+	u8 offset;
+	u8 length;
+	union {
+		u8 data[16];
+		u8 *burst_data;
+	} payload;
+	u8 retval;
+};
+
 /* USB driver interface  */
 
 #ifdef CONFIG_FB_MSM_HDMI_MHL_8334
@@ -59,6 +70,15 @@
 }
 #endif
 
+
+struct msc_cmd_envelope {
+	/*
+	 * this list head is for list APIs
+	 */
+	struct list_head msc_queue_envelope;
+	struct msc_command_struct msc_cmd_msg;
+};
+
 struct mhl_msm_state_t {
 	struct i2c_client *i2c_client;
 	struct i2c_driver *i2c_driver;
@@ -68,6 +88,13 @@
 	/* Device Discovery stuff */
 	int mhl_mode;
 	struct completion rgnd_done;
+	struct completion msc_cmd_done;
+	uint8_t devcap_state;
+	uint8_t path_en_state;
+	struct work_struct mhl_msc_send_work;
+	struct list_head list_cmd;
+	void (*msc_command_put_work) (struct msc_command_struct *);
+	struct msc_command_struct* (*msc_command_get_work) (void);
 };
 
 enum {
diff --git a/include/linux/mhl_defs.h b/include/linux/mhl_defs.h
index 094874e..062bdf9 100644
--- a/include/linux/mhl_defs.h
+++ b/include/linux/mhl_defs.h
@@ -147,9 +147,15 @@
 	MHL_MSC_MSG_RAPK            = 0x21,
 };
 
-#define	RCPE_NO_ERROR				0x00
-#define	RCPE_INEEFECTIVE_KEY_CODE	0x01
-#define	RCPE_BUSY					0x02
+#define MHL_RCPE_NO_ERROR			0x00
+#define MHL_RCPE_UNSUPPORTED_KEY_CODE		0x01
+#define MHL_RCPE_BUSY				0x02
+
+#define MHL_RAPK_NO_ERROR			0x00
+#define MHL_RAPK_UNRECOGNIZED_ACTION_CODE	0x01
+#define MHL_RAPK_UNSUPPORTED_ACTION_CODE	0x02
+#define MHL_RAPK_BUSY				0x03
+
 /* MHL spec related defines*/
 enum {
 	/* Command or Data byte acknowledge */
diff --git a/include/linux/msm_audio.h b/include/linux/msm_audio.h
index f2a39e4..4eb8a65 100644
--- a/include/linux/msm_audio.h
+++ b/include/linux/msm_audio.h
@@ -222,6 +222,28 @@
 
 #define SND_SET_DEVICE _IOW(SND_IOCTL_MAGIC, 2, struct msm_device_config *)
 
+enum cad_device_path_type {
+	CAD_DEVICE_PATH_RX,	/*For Decoding session*/
+	CAD_DEVICE_PATH_TX,	/* For Encoding session*/
+	CAD_DEVICE_PATH_RX_TX, /* For Voice call */
+	CAD_DEVICE_PATH_LB,	/* For loopback (FM Analog)*/
+	CAD_DEVICE_PATH_MAX
+};
+
+struct cad_devices_type {
+	uint32_t rx_device;
+	uint32_t tx_device;
+	enum cad_device_path_type pathtype;
+};
+
+struct msm_cad_device_config {
+	struct cad_devices_type device;
+	uint32_t ear_mute;
+	uint32_t mic_mute;
+};
+
+#define CAD_SET_DEVICE _IOW(SND_IOCTL_MAGIC, 2, struct msm_cad_device_config *)
+
 #define SND_METHOD_VOICE 0
 
 struct msm_snd_volume_config {
@@ -232,6 +254,14 @@
 
 #define SND_SET_VOLUME _IOW(SND_IOCTL_MAGIC, 3, struct msm_snd_volume_config *)
 
+struct msm_cad_volume_config {
+	struct cad_devices_type device;
+	uint32_t method;
+	uint32_t volume;
+};
+
+#define CAD_SET_VOLUME _IOW(SND_IOCTL_MAGIC, 3, struct msm_cad_volume_config *)
+
 /* Returns the number of SND endpoints supported. */
 
 #define SND_GET_NUM_ENDPOINTS _IOR(SND_IOCTL_MAGIC, 4, unsigned *)
@@ -254,6 +284,24 @@
 #define SND_AVC_CTL _IOW(SND_IOCTL_MAGIC, 6, unsigned *)
 #define SND_AGC_CTL _IOW(SND_IOCTL_MAGIC, 7, unsigned *)
 
+/*return the number of CAD endpoints supported. */
+
+#define CAD_GET_NUM_ENDPOINTS _IOR(SND_IOCTL_MAGIC, 4, unsigned *)
+
+struct msm_cad_endpoint {
+	int id; /* input and output */
+	char name[64]; /* output only */
+};
+
+/* Takes an index between 0 and one less than the number returned by
+ * SND_GET_NUM_ENDPOINTS, and returns the CAD index and name of a
+ * CAD endpoint.  On input, the .id field contains the number of the
+ * endpoint, and on exit it contains the SND index, while .name contains
+ * the description of the endpoint.
+ */
+
+#define CAD_GET_ENDPOINT _IOWR(SND_IOCTL_MAGIC, 5, struct msm_cad_endpoint *)
+
 struct msm_audio_pcm_config {
 	uint32_t pcm_feedback;	/* 0 - disable > 0 - enable */
 	uint32_t buffer_count;	/* Number of buffers to allocate */
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 2519a6e..c9f9d74 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -70,6 +70,7 @@
 #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_VSYNC_CTRL  _IOW(MSMFB_IOCTL_MAGIC, 161, unsigned int)
+#define MSMFB_METADATA_SET  _IOW(MSMFB_IOCTL_MAGIC, 162, struct msmfb_metadata)
 #define FB_TYPE_3D_PANEL 0x10101010
 #define MDP_IMGTYPE2_START 0x10000
 #define MSMFB_DRIVER_VERSION	0xF9E8D701
@@ -105,6 +106,8 @@
 	MDP_YCRCB_H1V1,   /* YCrCb interleave */
 	MDP_YCBCR_H1V1,   /* YCbCr interleave */
 	MDP_BGR_565,      /* BGR 565 planer */
+	MDP_BGR_888,      /* BGR 888 */
+	MDP_Y_CBCR_H2V2_VENUS,
 	MDP_IMGTYPE_LIMIT,
 	MDP_RGB_BORDERFILL,	/* border fill pipe */
 	MDP_FB_FORMAT = MDP_IMGTYPE2_START,    /* framebuffer format */
@@ -352,12 +355,15 @@
 
 /*
 
-	mdp_block_type defines the identifiers for each of pipes in MDP 4.3
+	mdp_block_type defines the identifiers for pipes in MDP 4.3 and up
 
 	MDP_BLOCK_RESERVED is provided for backward compatibility and is
 	deprecated. It corresponds to DMA_P. So MDP_BLOCK_DMA_P should be used
 	instead.
 
+	MDP_LOGICAL_BLOCK_DISP_0 identifies the display pipe which fb0 uses,
+	same for others.
+
 */
 
 enum {
@@ -372,6 +378,9 @@
 	MDP_BLOCK_DMA_S,
 	MDP_BLOCK_DMA_E,
 	MDP_BLOCK_OVERLAY_2,
+	MDP_LOGICAL_BLOCK_DISP_0 = 0x1000,
+	MDP_LOGICAL_BLOCK_DISP_1,
+	MDP_LOGICAL_BLOCK_DISP_2,
 	MDP_BLOCK_MAX,
 };
 
@@ -484,7 +493,23 @@
 	} data;
 };
 
+enum {
+	metadata_op_none,
+	metadata_op_base_blend,
+	metadata_op_max
+};
 
+struct mdp_blend_cfg {
+	uint32_t is_premultiplied;
+};
+
+struct msmfb_metadata {
+	uint32_t op;
+	uint32_t flags;
+	union {
+		struct mdp_blend_cfg blend_cfg;
+	} data;
+};
 struct mdp_page_protection {
 	uint32_t page_protection;
 };
@@ -512,7 +537,7 @@
 };
 
 #ifdef __KERNEL__
-
+int msm_fb_get_iommu_domain(void);
 /* get the framebuffer physical address information */
 int get_fb_phys_info(unsigned long *start, unsigned long *len, int fb_num,
 	int subsys_id);
diff --git a/include/linux/msm_rmnet.h b/include/linux/msm_rmnet.h
index 9f52464..063a8f1 100644
--- a/include/linux/msm_rmnet.h
+++ b/include/linux/msm_rmnet.h
@@ -40,6 +40,8 @@
 	RMNET_IOCTL_GET_OPMODE       = 0x000089F7, /* Get operation mode     */
 	RMNET_IOCTL_OPEN             = 0x000089F8, /* Open transport port    */
 	RMNET_IOCTL_CLOSE            = 0x000089F9, /* Close transport port   */
+	RMNET_IOCTL_FLOW_ENABLE	     = 0x000089FA, /* Flow enable	     */
+	RMNET_IOCTL_FLOW_DISABLE     = 0x000089FB, /* Flow disable	     */
 	RMNET_IOCTL_MAX
 };
 
diff --git a/include/linux/msm_vidc_dec.h b/include/linux/msm_vidc_dec.h
index 3d8907a..3c99562 100644
--- a/include/linux/msm_vidc_dec.h
+++ b/include/linux/msm_vidc_dec.h
@@ -76,6 +76,9 @@
 #define VDEC_EXTRADATA_VUI 0x020
 #define VDEC_EXTRADATA_VC1 0x040
 
+#define VDEC_EXTRADATA_EXT_DATA          0x0800
+#define VDEC_EXTRADATA_USER_DATA         0x1000
+
 #define VDEC_CMDBASE	0x800
 #define VDEC_CMD_SET_INTF_VERSION	(VDEC_CMDBASE)
 
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 cb56293..647a7ef 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -140,6 +140,7 @@
 	POWER_SUPPLY_TYPE_USB_DCP,	/* Dedicated Charging Port */
 	POWER_SUPPLY_TYPE_USB_CDP,	/* Charging Downstream Port */
 	POWER_SUPPLY_TYPE_USB_ACA,	/* Accessory Charger Adapters */
+	POWER_SUPPLY_TYPE_BMS,		/* Battery Monitor System */
 };
 
 union power_supply_propval {
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/qpnp-adc.h b/include/linux/qpnp/qpnp-adc.h
index 8468aa5..19a1d97 100644
--- a/include/linux/qpnp/qpnp-adc.h
+++ b/include/linux/qpnp/qpnp-adc.h
@@ -175,17 +175,19 @@
 
 /**
  * enum qpnp_adc_channel_scaling_param - pre-scaling AMUX ratio.
- * %CHAN_PATH_SCALING1: ratio of {1, 1}
- * %CHAN_PATH_SCALING2: ratio of {1, 3}
- * %CHAN_PATH_SCALING3: ratio of {1, 4}
- * %CHAN_PATH_SCALING4: ratio of {1, 6}
+ * %CHAN_PATH_SCALING0: ratio of {1, 1}
+ * %CHAN_PATH_SCALING1: ratio of {1, 3}
+ * %CHAN_PATH_SCALING2: ratio of {1, 4}
+ * %CHAN_PATH_SCALING3: ratio of {1, 6}
+ * %CHAN_PATH_SCALING4: ratio of {1, 20}
  * %CHAN_PATH_NONE: Do not use this pre-scaling ratio type.
  *
  * The pre-scaling is applied for signals to be within the voltage range
  * of the ADC.
  */
 enum qpnp_adc_channel_scaling_param {
-	PATH_SCALING1 = 0,
+	PATH_SCALING0 = 0,
+	PATH_SCALING1,
 	PATH_SCALING2,
 	PATH_SCALING3,
 	PATH_SCALING4,
@@ -197,8 +199,8 @@
  *				   digital data relative to ADC reference.
  * %ADC_SCALE_DEFAULT: Default scaling to convert raw adc code to voltage.
  * %ADC_SCALE_BATT_THERM: Conversion to temperature based on btm parameters.
+ * %ADC_SCALE_PA_THERM: Returns temperature in degC.
  * %ADC_SCALE_PMIC_THERM: Returns result in milli degree's Centigrade.
- * %ADC_SCALE_XTERN_CHGR_CUR: Returns current across 0.1 ohm resistor.
  * %ADC_SCALE_XOTHERM: Returns XO thermistor voltage in degree's Centigrade.
  * %ADC_SCALE_NONE: Do not use this scaling type.
  */
@@ -701,6 +703,75 @@
 			const struct qpnp_adc_properties *adc_prop,
 			const struct qpnp_vadc_chan_properties *chan_prop,
 			struct qpnp_vadc_result *chan_rslt);
+/**
+ * qpnp_adc_scale_pmic_therm() - Scales the pre-calibrated digital output
+ *		of an ADC to the ADC reference and compensates for the
+ *		gain and offset. Performs the AMUX out as 2mV/K and returns
+ *		the temperature in milli degC.
+ * @adc_code:	pre-calibrated digital ouput of the ADC.
+ * @adc_prop:	adc properties of the qpnp adc such as bit resolution,
+ *		reference voltage.
+ * @chan_prop:	Individual channel properties to compensate the i/p scaling,
+ *		slope and offset.
+ * @chan_rslt:	Physical result to be stored.
+ */
+int32_t qpnp_adc_scale_pmic_therm(int32_t adc_code,
+			const struct qpnp_adc_properties *adc_prop,
+			const struct qpnp_vadc_chan_properties *chan_prop,
+			struct qpnp_vadc_result *chan_rslt);
+/**
+ * qpnp_adc_scale_batt_therm() - Scales the pre-calibrated digital output
+ *		of an ADC to the ADC reference and compensates for the
+ *		gain and offset. Returns the temperature in degC.
+ * @adc_code:	pre-calibrated digital ouput of the ADC.
+ * @adc_prop:	adc properties of the pm8xxx adc such as bit resolution,
+ *		reference voltage.
+ * @chan_prop:	individual channel properties to compensate the i/p scaling,
+ *		slope and offset.
+ * @chan_rslt:	physical result to be stored.
+ */
+int32_t qpnp_adc_scale_batt_therm(int32_t adc_code,
+			const struct qpnp_adc_properties *adc_prop,
+			const struct qpnp_vadc_chan_properties *chan_prop,
+			struct qpnp_vadc_result *chan_rslt);
+/**
+ * qpnp_adc_scale_batt_id() - Scales the pre-calibrated digital output
+ *		of an ADC to the ADC reference and compensates for the
+ *		gain and offset.
+ * @adc_code:	pre-calibrated digital ouput of the ADC.
+ * @adc_prop:	adc properties of the pm8xxx adc such as bit resolution,
+ *		reference voltage.
+ * @chan_prop:	individual channel properties to compensate the i/p scaling,
+ *		slope and offset.
+ * @chan_rslt:	physical result to be stored.
+ */
+int32_t qpnp_adc_scale_batt_id(int32_t adc_code,
+			const struct qpnp_adc_properties *adc_prop,
+			const struct qpnp_vadc_chan_properties *chan_prop,
+			struct qpnp_vadc_result *chan_rslt);
+/**
+ * qpnp_adc_scale_tdkntcg_therm() - Scales the pre-calibrated digital output
+ *		of an ADC to the ADC reference and compensates for the
+ *		gain and offset. Returns the temperature of the xo therm in mili
+		degC.
+ * @adc_code:	pre-calibrated digital ouput of the ADC.
+ * @adc_prop:	adc properties of the pm8xxx adc such as bit resolution,
+ *		reference voltage.
+ * @chan_prop:	individual channel properties to compensate the i/p scaling,
+ *		slope and offset.
+ * @chan_rslt:	physical result to be stored.
+ */
+int32_t qpnp_adc_tdkntcg_therm(int32_t adc_code,
+			const struct qpnp_adc_properties *adc_prop,
+			const struct qpnp_vadc_chan_properties *chan_prop,
+			struct qpnp_vadc_result *chan_rslt);
+/**
+ * qpnp_vadc_is_ready() - Clients can use this API to check if the
+ *			  device is ready to use.
+ * @result:	0 on success and -EPROBE_DEFER when probe for the device
+ *		has not occured.
+ */
+int32_t qpnp_vadc_is_ready(void);
 #else
 static inline int32_t qpnp_vadc_read(uint32_t channel,
 				struct qpnp_vadc_result *result)
@@ -712,8 +783,30 @@
 { return -ENXIO; }
 static inline int32_t qpnp_adc_scale_default(int32_t adc_code,
 			const struct qpnp_adc_properties *adc_prop,
-			const struct qpnp_adc_chan_properties *chan_prop,
-			struct qpnp_adc_chan_result *chan_rslt)
+			const struct qpnp_vadc_chan_properties *chan_prop,
+			struct qpnp_vadc_result *chan_rslt)
+{ return -ENXIO; }
+static inline int32_t qpnp_adc_scale_pmic_therm(int32_t adc_code,
+			const struct qpnp_adc_properties *adc_prop,
+			const struct qpnp_vadc_chan_properties *chan_prop,
+			struct qpnp_vadc_result *chan_rslt)
+{ return -ENXIO; }
+static inline int32_t qpnp_adc_scale_batt_therm(int32_t adc_code,
+			const struct qpnp_adc_properties *adc_prop,
+			const struct qpnp_vadc_chan_properties *chan_prop,
+			struct qpnp_vadc_result *chan_rslt)
+{ return -ENXIO; }
+static inline int32_t qpnp_adc_scale_batt_id(int32_t adc_code,
+			const struct qpnp_adc_properties *adc_prop,
+			const struct qpnp_vadc_chan_properties *chan_prop,
+			struct qpnp_vadc_result *chan_rslt)
+{ return -ENXIO; }
+static inline int32_t qpnp_adc_tdkntcg_therm(int32_t adc_code,
+			const struct qpnp_adc_properties *adc_prop,
+			const struct qpnp_vadc_chan_properties *chan_prop,
+			struct qpnp_vadc_result *chan_rslt)
+{ return -ENXIO; }
+static inline int32_t qpnp_vadc_is_read(void)
 { return -ENXIO; }
 #endif
 
@@ -742,6 +835,13 @@
  */
 int32_t qpnp_iadc_get_offset(enum qpnp_iadc_channels channel,
 						int32_t *result);
+/**
+ * qpnp_iadc_is_ready() - Clients can use this API to check if the
+ *			  device is ready to use.
+ * @result:	0 on success and -EPROBE_DEFER when probe for the device
+ *		has not occured.
+ */
+int32_t qpnp_iadc_is_ready(void);
 #else
 static inline int32_t qpnp_iadc_read(enum qpnp_iadc_channels channel,
 							int *result)
@@ -751,6 +851,8 @@
 static inline int32_t qpnp_iadc_get_offset(enum qpnp_iadc_channels channel,
 						int32_t *result)
 { return -ENXIO; }
+static inline int32_t qpnp_iadc_is_read(void)
+{ return -ENXIO; }
 #endif
 
 #endif
diff --git a/include/linux/regulator/krait-regulator.h b/include/linux/regulator/krait-regulator.h
index 1f85952..eb1c3fd 100644
--- a/include/linux/regulator/krait-regulator.h
+++ b/include/linux/regulator/krait-regulator.h
@@ -23,5 +23,6 @@
  * 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/slimbus/slimbus.h b/include/linux/slimbus/slimbus.h
index 75b132b..d365b15 100644
--- a/include/linux/slimbus/slimbus.h
+++ b/include/linux/slimbus/slimbus.h
@@ -479,6 +479,8 @@
  * @m_ctrl: Mutex protecting controller data structures (ports, channels etc)
  * @addrt: Logical address table
  * @num_dev: Number of active slimbus slaves on this bus
+ * @devs: List of devices on this controller
+ * @wq: Workqueue per controller used to notify devices when they report present
  * @txnt: Table of transactions having transaction ID
  * @last_tid: size of the table txnt (can't grow beyond 256 since TID is 8-bits)
  * @ports: Ports associated with this controller
@@ -525,6 +527,8 @@
 	struct mutex		m_ctrl;
 	struct slim_addrt	*addrt;
 	u8			num_dev;
+	struct list_head	devs;
+	struct workqueue_struct *wq;
 	struct slim_msg_txn	**txnt;
 	u8			last_tid;
 	struct slim_port	*ports;
@@ -569,6 +573,7 @@
 	int				(*suspend)(struct slim_device *sldev,
 					pm_message_t pmesg);
 	int				(*resume)(struct slim_device *sldev);
+	int				(*device_up)(struct slim_device *sldev);
 
 	struct device_driver		driver;
 	const struct slim_device_id	*id_table;
@@ -601,6 +606,11 @@
  *  @mark_define: List of channels pending definition/activation.
  *  @mark_suspend: List of channels pending suspend.
  *  @mark_removal: List of channels pending removal.
+ *  @notified: Flag to indicate whether this device has been notified. The
+ *	device may report present multiple times, but should be notified only
+ *	first time it has reported present.
+ *  @dev_list: List of devices on a controller
+ *  @wd: Work structure associated with workqueue for presence notification
  *  @sldev_reconf: Mutex to protect the pending data-channel lists.
  *  @pending_msgsl: Message bandwidth reservation request by this client in
  *	slots that's pending reconfiguration.
@@ -619,6 +629,9 @@
 	struct list_head	mark_define;
 	struct list_head	mark_suspend;
 	struct list_head	mark_removal;
+	bool			notified;
+	struct list_head	dev_list;
+	struct work_struct	wd;
 	struct mutex		sldev_reconf;
 	u32			pending_msgsl;
 	u32			cur_msgsl;
@@ -998,6 +1011,15 @@
 extern struct slim_controller *slim_busnum_to_ctrl(u32 busnum);
 
 /*
+ * slim_ctrl_add_boarddevs: Add devices registered by board-info
+ * @ctrl: Controller to which these devices are to be added to.
+ * This API is called by controller when it is up and running.
+ * If devices on a controller were registered before controller,
+ * this will make sure that they get probed when controller is up
+ */
+extern void slim_ctrl_add_boarddevs(struct slim_controller *ctrl);
+
+/*
  * slim_register_board_info: Board-initialization routine.
  * @info: List of all devices on all controllers present on the board.
  * @n: number of entries.
diff --git a/include/linux/tspp.h b/include/linux/tspp.h
index d5a5ffc..3f0cc81 100644
--- a/include/linux/tspp.h
+++ b/include/linux/tspp.h
@@ -24,6 +24,12 @@
 	TSPP_MODE_RAW_NO_SUFFIX
 };
 
+enum tspp_tsif_mode {
+	TSPP_TSIF_MODE_LOOPBACK, /* loopback mode */
+	TSPP_TSIF_MODE_1,        /* without sync */
+	TSPP_TSIF_MODE_2         /* with sync signal */
+};
+
 struct tspp_filter {
 	int pid;
 	int mask;
@@ -35,6 +41,7 @@
 
 struct tspp_select_source {
 	enum tspp_source source;
+	enum tspp_tsif_mode mode;
 };
 
 struct tspp_pid {
@@ -77,8 +84,5 @@
 	_IOW(TSPP_IOCTL_BASE, 5, struct tspp_system_keys)
 #define TSPP_IOCTL_BUFFER_SIZE		\
 	_IOW(TSPP_IOCTL_BASE, 6, struct tspp_buffer)
-#define TSPP_IOCTL_LOOPBACK			\
-	_IOW(TSPP_IOCTL_BASE, 0xFF, int)
-
 
 #endif /* _TSPP_H_ */
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/hcd.h b/include/linux/usb/hcd.h
index dc13bd9..dd091cd 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -346,9 +346,8 @@
 	int	(*update_device)(struct usb_hcd *, struct usb_device *);
 	int	(*set_usb2_hw_lpm)(struct usb_hcd *, struct usb_device *, int);
 
-	/* to log completion events*/
-	void	(*log_urb_complete)(struct urb *urb, char * event,
-			unsigned extra);
+	/* to log submission/completion events*/
+	void	(*log_urb)(struct urb *urb, char *event, unsigned extra);
 	void	(*dump_regs)(struct usb_hcd *);
 	void	(*enable_ulpi_control)(struct usb_hcd *hcd, u32 linestate);
 	void	(*disable_ulpi_control)(struct usb_hcd *hcd);
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index e731f97..82f9107 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -268,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.
@@ -276,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.
@@ -298,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;
@@ -376,6 +378,8 @@
 	unsigned strobe;
 	unsigned data;
 	struct msm_bus_scale_pdata *bus_scale_table;
+	unsigned log2_irq_thresh;
+	u32 swfi_latency;
 };
 
 struct msm_usb_host_platform_data {
@@ -394,6 +398,12 @@
 	bool core_clk_always_on_workaround;
 };
 
+enum usb_pipe_mem_type {
+	SPS_PIPE_MEM = 0,	/* Default, SPS dedicated pipe memory */
+	USB_PRIVATE_MEM,	/* USB's private memory */
+	SYSTEM_MEM,		/* System RAM, requires allocation */
+};
+
 /**
  * struct usb_bam_pipe_connect: pipe connection information
  * between USB/HSIC BAM and another BAM. USB/HSIC BAM can be
@@ -402,6 +412,7 @@
  * @src_pipe_index: src bam pipe index.
  * @dst_phy_addr: dst bam physical address.
  * @dst_pipe_index: dst bam pipe index.
+ * @mem_type: type of memory used for BAM FIFOs
  * @data_fifo_base_offset: data fifo offset.
  * @data_fifo_size: data fifo size.
  * @desc_fifo_base_offset: descriptor fifo offset.
@@ -412,6 +423,7 @@
 	u32 src_pipe_index;
 	u32 dst_phy_addr;
 	u32 dst_pipe_index;
+	enum usb_pipe_mem_type mem_type;
 	u32 data_fifo_base_offset;
 	u32 data_fifo_size;
 	u32 desc_fifo_base_offset;
@@ -427,6 +439,7 @@
  * @usb_bam_num_pipes: max number of pipes to use.
  * @active_conn_num: number of active pipe connections.
  * @usb_base_address: BAM physical address.
+ * @ignore_core_reset_ack: BAM can ignore ACK from USB core during PIPE RESET
  */
 struct msm_usb_bam_platform_data {
 	struct usb_bam_pipe_connect *connections;
@@ -434,11 +447,14 @@
 	int usb_bam_num_pipes;
 	u32 total_bam_num;
 	u32 usb_base_address;
+	bool ignore_core_reset_ack;
 };
 
 enum usb_bam {
-	HSUSB_BAM = 0,
+	SSUSB_BAM = 0,
+	HSUSB_BAM,
 	HSIC_BAM,
+	MAX_BAMS,
 };
 
 #ifdef CONFIG_USB_DWC3_MSM
diff --git a/include/linux/usb/msm_hsusb_hw.h b/include/linux/usb/msm_hsusb_hw.h
index 516f764..c8c2ed1 100644
--- a/include/linux/usb/msm_hsusb_hw.h
+++ b/include/linux/usb/msm_hsusb_hw.h
@@ -19,6 +19,7 @@
 #define USB_AHBBURST         (MSM_USB_BASE + 0x0090)
 #define USB_AHBMODE          (MSM_USB_BASE + 0x0098)
 #define USB_CAPLENGTH        (MSM_USB_BASE + 0x0100) /* 8 bit */
+#define USB_HS_GPTIMER_BASE  (MSM_USB_BASE + 0x80)
 
 #define USB_USBCMD           (MSM_USB_BASE + 0x0140)
 #define USB_USBSTS           (MSM_USB_BASE + 0x0144)
@@ -29,6 +30,7 @@
 
 #define USBCMD_RESET   2
 #define USB_USBINTR          (MSM_USB_BASE + 0x0148)
+#define USB_FRINDEX          (MSM_USB_BASE + 0x014C)
 
 #define PORTSC_PHCD            (1 << 23) /* phy suspend mode */
 #define PORTSC_PTS_MASK         (3 << 30)
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 66b68d0..7b5aa0b 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -2074,6 +2074,7 @@
 #define V4L2_ENC_CMD_STOP       (1)
 #define V4L2_ENC_CMD_PAUSE      (2)
 #define V4L2_ENC_CMD_RESUME     (3)
+#define V4L2_ENC_QCOM_CMD_FLUSH  (4)
 
 /* Flags for V4L2_ENC_CMD_STOP */
 #define V4L2_ENC_CMD_STOP_AT_GOP_END    (1 << 0)
@@ -2088,6 +2089,8 @@
 	};
 };
 
+#define V4L2_QCOM_BUF_FLAG_CODECCONFIG	0x4000
+
 /* Decoder commands */
 #define V4L2_DEC_CMD_START       (0)
 #define V4L2_DEC_CMD_STOP        (1)
@@ -2109,6 +2112,9 @@
 #define V4L2_DEC_QCOM_CMD_FLUSH_OUTPUT  (1 << 0)
 #define V4L2_DEC_QCOM_CMD_FLUSH_CAPTURE (1 << 1)
 
+#define V4L2_QCOM_CMD_FLUSH_OUTPUT  (1 << 0)
+#define V4L2_QCOM_CMD_FLUSH_CAPTURE (1 << 1)
+
 /* Play format requirements (returned by the driver): */
 
 /* The decoder has no special format requirements */
diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h
index 295be8f..d32bc57 100644
--- a/include/linux/wcnss_wlan.h
+++ b/include/linux/wcnss_wlan.h
@@ -21,6 +21,11 @@
 	WCNSS_WLAN_SWITCH_ON,
 };
 
+enum wcnss_hw_type {
+	WCNSS_RIVA_HW = 0,
+	WCNSS_PRONTO_HW,
+};
+
 struct wcnss_wlan_config {
 	int		use_48mhz_xo;
 };
@@ -44,13 +49,20 @@
 int wcnss_wlan_power(struct device *dev,
 				struct wcnss_wlan_config *cfg,
 				enum wcnss_opcode opcode);
-int req_riva_power_on_lock(char *driver_name);
-int free_riva_power_on_lock(char *driver_name);
+int wcnss_req_power_on_lock(char *driver_name);
+int wcnss_free_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);
+int wcnss_hardware_type(void);
+void *wcnss_prealloc_get(unsigned int size);
+int wcnss_prealloc_put(void *ptr);
+
 #define wcnss_wlan_get_drvdata(dev) dev_get_drvdata(dev)
 #define wcnss_wlan_set_drvdata(dev, data) dev_set_drvdata((dev), (data))
+/* WLAN driver uses these names */
+#define req_riva_power_on_lock(name) wcnss_req_power_on_lock(name)
+#define free_riva_power_on_lock(name) wcnss_free_power_on_lock(name)
 
 #endif /* _WCNSS_WLAN_H_ */
diff --git a/include/media/Kbuild b/include/media/Kbuild
index 2a21336..4b6e6a9 100644
--- a/include/media/Kbuild
+++ b/include/media/Kbuild
@@ -6,3 +6,4 @@
 header-y += msm_gemini.h
 header-y += msm_gestures.h
 header-y += msm_mercury.h
+header-y += msm_jpeg.h
diff --git a/include/media/msm/vcd_property.h b/include/media/msm/vcd_property.h
index acd0fa3..484d08f 100644
--- a/include/media/msm/vcd_property.h
+++ b/include/media/msm/vcd_property.h
@@ -113,6 +113,9 @@
 #define VCD_METADATA_PASSTHROUGH    0x080
 #define VCD_METADATA_ENC_SLICE      0x100
 
+#define VCD_METADATA_EXT_DATA       0x0800
+#define VCD_METADATA_USER_DATA      0x1000
+
 struct vcd_property_meta_data_enable {
 	u32 meta_data_enable_flag;
 };
diff --git a/include/media/msm/vidc_init.h b/include/media/msm/vidc_init.h
index c681213..f7d4e58 100644
--- a/include/media/msm/vidc_init.h
+++ b/include/media/msm/vidc_init.h
@@ -13,7 +13,7 @@
 
 #ifndef VIDC_INIT_H
 #define VIDC_INIT_H
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
 #include <media/msm/vidc_type.h>
 #include <media/msm/vcd_property.h>
 
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index b27debc..0ace67a 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -16,6 +16,7 @@
 #ifdef MSM_CAMERA_BIONIC
 #include <sys/types.h>
 #endif
+#include <linux/videodev2.h>
 #include <linux/types.h>
 #include <linux/ioctl.h>
 #ifdef __KERNEL__
@@ -151,7 +152,7 @@
 	_IOW(MSM_CAM_IOCTL_MAGIC, 39, struct msm_camera_st_frame *)
 
 #define MSM_CAM_IOCTL_V4L2_EVT_NOTIFY \
-	_IOR(MSM_CAM_IOCTL_MAGIC, 40, struct v4l2_event *)
+	_IOW(MSM_CAM_IOCTL_MAGIC, 40, struct v4l2_event_and_payload)
 
 #define MSM_CAM_IOCTL_SET_MEM_MAP_INFO \
 	_IOR(MSM_CAM_IOCTL_MAGIC, 41, struct msm_mem_map_info *)
@@ -216,6 +217,30 @@
 #define MSM_CAM_IOCTL_STATS_UNREG_BUF \
 	_IOR(MSM_CAM_IOCTL_MAGIC, 61, struct msm_stats_flush_bufq *)
 
+#define MSM_CAM_IOCTL_CSIC_IO_CFG \
+	_IOWR(MSM_CAM_IOCTL_MAGIC, 62, struct csic_cfg_data *)
+
+#define MSM_CAM_IOCTL_CSID_IO_CFG \
+	_IOWR(MSM_CAM_IOCTL_MAGIC, 63, struct csid_cfg_data *)
+
+#define MSM_CAM_IOCTL_CSIPHY_IO_CFG \
+	_IOR(MSM_CAM_IOCTL_MAGIC, 64, struct csiphy_cfg_data *)
+
+#define MSM_CAM_IOCTL_OEM \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 65, struct sensor_cfg_data *)
+
+#define MSM_CAM_IOCTL_AXI_INIT \
+	_IOWR(MSM_CAM_IOCTL_MAGIC, 66, uint8_t *)
+
+#define MSM_CAM_IOCTL_AXI_RELEASE \
+	_IO(MSM_CAM_IOCTL_MAGIC, 67)
+
+struct v4l2_event_and_payload {
+	struct v4l2_event evt;
+	uint32_t payload_length;
+	uint32_t transaction_id;
+	void *payload;
+};
 
 struct msm_stats_reqbuf {
 	int num_buf;		/* how many buffers requested */
@@ -350,6 +375,27 @@
 	uint32_t inst_handle;
 };
 
+struct msm_pp_crop {
+	uint32_t  src_x;
+	uint32_t  src_y;
+	uint32_t  src_w;
+	uint32_t  src_h;
+	uint32_t  dst_x;
+	uint32_t  dst_y;
+	uint32_t  dst_w;
+	uint32_t  dst_h;
+	uint8_t update_flag;
+};
+
+struct msm_mctl_pp_frame_cmd {
+	uint32_t cookie;
+	uint8_t  vpe_output_action;
+	struct msm_pp_frame src_frame;
+	struct msm_pp_frame dest_frame;
+	struct msm_pp_crop crop;
+	int path;
+};
+
 struct msm_cam_evt_divert_frame {
 	unsigned short image_mode;
 	unsigned short op_mode;
@@ -486,8 +532,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_VFE_PIX_SOF_COUNT_UPDATE 59
+#define CMD_VFE_COUNT_PIX_SOF_ENABLE 60
 
 #define CMD_AXI_CFG_PRIM               BIT(8)
 #define CMD_AXI_CFG_PRIM_ALL_CHNLS     BIT(9)
@@ -499,6 +545,8 @@
 #define CMD_AXI_START  0xE1
 #define CMD_AXI_STOP   0xE2
 #define CMD_AXI_RESET  0xE3
+#define CMD_AXI_ABORT  0xE4
+
 
 
 #define AXI_CMD_PREVIEW      BIT(0)
@@ -583,6 +631,7 @@
 	MSM_STATS_TYPE_BF,  /* Bayer Focus */
 	MSM_STATS_TYPE_BHIST,   /* Bayer Hist */
 	MSM_STATS_TYPE_AE_AW,   /* legacy stats for vfe 2.x*/
+	MSM_STATS_TYPE_COMP, /* Composite stats */
 	MSM_STATS_TYPE_MAX  /* MAX */
 };
 
@@ -662,8 +711,11 @@
 #define OUTPUT_TYPE_ST_D BIT(7)
 #define OUTPUT_TYPE_R    BIT(8)
 #define OUTPUT_TYPE_R1   BIT(9)
-
-
+#define OUTPUT_TYPE_SAEC   BIT(10)
+#define OUTPUT_TYPE_SAFC   BIT(11)
+#define OUTPUT_TYPE_SAWB   BIT(12)
+#define OUTPUT_TYPE_IHST   BIT(13)
+#define OUTPUT_TYPE_CSTA   BIT(14)
 
 struct fd_roi_info {
 	void *info;
@@ -778,27 +830,39 @@
 /* extendedmode for the thumb nail image in VIDIOC_S_PARM */
 #define MSM_V4L2_EXT_CAPTURE_MODE_THUMBNAIL \
 	(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+4)
-#define MSM_V4L2_EXT_CAPTURE_MODE_RAW \
+/* ISP_PIX_OUTPUT1: no pp, directly send output1 buf to user */
+#define MSM_V4L2_EXT_CAPTURE_MODE_ISP_PIX_OUTPUT1 \
 	(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+5)
-#define MSM_V4L2_EXT_CAPTURE_MODE_RDI \
+/* ISP_PIX_OUTPUT2: no pp, directly send output2 buf to user */
+#define MSM_V4L2_EXT_CAPTURE_MODE_ISP_PIX_OUTPUT2 \
 	(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+6)
-#define MSM_V4L2_EXT_CAPTURE_MODE_RDI1 \
+/* raw image type */
+#define MSM_V4L2_EXT_CAPTURE_MODE_RAW \
 	(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+7)
-#define MSM_V4L2_EXT_CAPTURE_MODE_RDI2 \
+/* RDI dump */
+#define MSM_V4L2_EXT_CAPTURE_MODE_RDI \
 	(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+8)
-#define MSM_V4L2_EXT_CAPTURE_MODE_AEC \
+/* RDI dump 1 */
+#define MSM_V4L2_EXT_CAPTURE_MODE_RDI1 \
 	(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+9)
-#define MSM_V4L2_EXT_CAPTURE_MODE_AWB \
+/* RDI dump 2 */
+#define MSM_V4L2_EXT_CAPTURE_MODE_RDI2 \
 	(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+10)
-#define MSM_V4L2_EXT_CAPTURE_MODE_AF \
+#define MSM_V4L2_EXT_CAPTURE_MODE_AEC \
 	(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+11)
-#define MSM_V4L2_EXT_CAPTURE_MODE_IHIST \
+#define MSM_V4L2_EXT_CAPTURE_MODE_AWB \
 	(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+12)
-#define MSM_V4L2_EXT_CAPTURE_MODE_CS \
+#define MSM_V4L2_EXT_CAPTURE_MODE_AF \
 	(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+13)
-#define MSM_V4L2_EXT_CAPTURE_MODE_RS \
+#define MSM_V4L2_EXT_CAPTURE_MODE_IHIST \
 	(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+14)
-#define MSM_V4L2_EXT_CAPTURE_MODE_MAX (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+15)
+#define MSM_V4L2_EXT_CAPTURE_MODE_CS \
+	(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+15)
+#define MSM_V4L2_EXT_CAPTURE_MODE_RS \
+	(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+16)
+#define MSM_V4L2_EXT_CAPTURE_MODE_CSTA \
+	(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+17)
+#define MSM_V4L2_EXT_CAPTURE_MODE_MAX (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+18)
 
 #define MSM_V4L2_PID_MOTION_ISO              V4L2_CID_PRIVATE_BASE
 #define MSM_V4L2_PID_EFFECT                 (V4L2_CID_PRIVATE_BASE+1)
@@ -851,7 +915,8 @@
 #define MSM_V4L2_CLOSE			11
 #define MSM_V4L2_SET_CTRL_CMD	12
 #define MSM_V4L2_EVT_SUB_MASK	13
-#define MSM_V4L2_MAX			14
+#define MSM_V4L2_PRIVATE_CMD    14
+#define MSM_V4L2_MAX			15
 #define V4L2_CAMERA_EXIT		43
 
 struct crop_info {
@@ -918,7 +983,15 @@
 #define CFG_START_STREAM              44
 #define CFG_STOP_STREAM               45
 #define CFG_GET_CSI_PARAMS            46
-#define CFG_MAX			47
+#define CFG_POWER_UP                  47
+#define CFG_POWER_DOWN                48
+#define CFG_WRITE_I2C_ARRAY           49
+#define CFG_READ_I2C_ARRAY            50
+#define CFG_PCLK_CHANGE               51
+#define CFG_CONFIG_VREG_ARRAY         52
+#define CFG_CONFIG_CLK_ARRAY          53
+#define CFG_GPIO_OP                   54
+#define CFG_MAX                       55
 
 
 #define MOVE_NEAR	0
@@ -1233,6 +1306,33 @@
 	uint16_t num_info;
 };
 
+struct msm_sensor_exp_gain_info_t {
+	uint16_t coarse_int_time_addr;
+	uint16_t global_gain_addr;
+	uint16_t vert_offset;
+};
+
+struct msm_sensor_output_reg_addr_t {
+	uint16_t x_output;
+	uint16_t y_output;
+	uint16_t line_length_pclk;
+	uint16_t frame_length_lines;
+};
+
+struct sensor_driver_params_type {
+	struct msm_camera_i2c_reg_setting *init_settings;
+	uint16_t init_settings_size;
+	struct msm_camera_i2c_reg_setting *mode_settings;
+	uint16_t mode_settings_size;
+	struct msm_sensor_output_reg_addr_t *sensor_output_reg_addr;
+	struct msm_camera_i2c_reg_setting *start_settings;
+	struct msm_camera_i2c_reg_setting *stop_settings;
+	struct msm_camera_i2c_reg_setting *groupon_settings;
+	struct msm_camera_i2c_reg_setting *groupoff_settings;
+	struct msm_sensor_exp_gain_info_t *sensor_exp_gain_info;
+	struct msm_sensor_output_info_t *output_info;
+};
+
 struct mirror_flip {
 	int32_t x_mirror;
 	int32_t y_flip;
@@ -1255,11 +1355,82 @@
 };
 
 struct csi_lane_params_t {
-	uint8_t csi_lane_assign;
+	uint16_t csi_lane_assign;
 	uint8_t csi_lane_mask;
 	uint8_t csi_if;
-	uint8_t csid_core;
-	uint32_t csid_version;
+	uint8_t csid_core[2];
+	uint8_t csi_phy_sel;
+};
+
+struct msm_camera_csid_lut_params {
+	uint8_t num_cid;
+	struct msm_camera_csid_vc_cfg *vc_cfg;
+};
+
+struct msm_camera_csid_params {
+	uint8_t lane_cnt;
+	uint16_t lane_assign;
+	uint8_t phy_sel;
+	struct msm_camera_csid_lut_params lut_params;
+};
+
+struct msm_camera_csiphy_params {
+	uint8_t lane_cnt;
+	uint8_t settle_cnt;
+	uint16_t lane_mask;
+	uint8_t combo_mode;
+};
+
+struct msm_camera_csi2_params {
+	struct msm_camera_csid_params csid_params;
+	struct msm_camera_csiphy_params csiphy_params;
+};
+
+enum msm_camera_csi_data_format {
+	CSI_8BIT,
+	CSI_10BIT,
+	CSI_12BIT,
+};
+
+struct msm_camera_csi_params {
+	enum msm_camera_csi_data_format data_format;
+	uint8_t lane_cnt;
+	uint8_t lane_assign;
+	uint8_t settle_cnt;
+	uint8_t dpcm_scheme;
+};
+
+enum csic_cfg_type_t {
+	CSIC_INIT,
+	CSIC_CFG,
+};
+
+struct csic_cfg_data {
+	enum csic_cfg_type_t cfgtype;
+	struct msm_camera_csi_params *csic_params;
+};
+
+enum csid_cfg_type_t {
+	CSID_INIT,
+	CSID_CFG,
+};
+
+struct csid_cfg_data {
+	enum csid_cfg_type_t cfgtype;
+	union {
+		uint32_t csid_version;
+		struct msm_camera_csid_params *csid_params;
+	} cfg;
+};
+
+enum csiphy_cfg_type_t {
+	CSIPHY_INIT,
+	CSIPHY_CFG,
+};
+
+struct csiphy_cfg_data {
+	enum csiphy_cfg_type_t cfgtype;
+	struct msm_camera_csiphy_params *csiphy_params;
 };
 
 #define CSI_EMBED_DATA 0x12
@@ -1359,6 +1530,81 @@
 	} cfg;
 };
 
+enum msm_camera_i2c_reg_addr_type {
+	MSM_CAMERA_I2C_BYTE_ADDR = 1,
+	MSM_CAMERA_I2C_WORD_ADDR,
+};
+
+struct msm_camera_i2c_reg_array {
+	uint16_t reg_addr;
+	uint16_t reg_data;
+};
+
+enum msm_camera_i2c_data_type {
+	MSM_CAMERA_I2C_BYTE_DATA = 1,
+	MSM_CAMERA_I2C_WORD_DATA,
+	MSM_CAMERA_I2C_SET_BYTE_MASK,
+	MSM_CAMERA_I2C_UNSET_BYTE_MASK,
+	MSM_CAMERA_I2C_SET_WORD_MASK,
+	MSM_CAMERA_I2C_UNSET_WORD_MASK,
+	MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA,
+};
+
+struct msm_camera_i2c_reg_setting {
+	struct msm_camera_i2c_reg_array *reg_setting;
+	uint16_t size;
+	enum msm_camera_i2c_reg_addr_type addr_type;
+	enum msm_camera_i2c_data_type data_type;
+	uint16_t delay;
+};
+
+enum oem_setting_type {
+	I2C_READ = 1,
+	I2C_WRITE,
+	GPIO_OP,
+	EEPROM_READ,
+	VREG_SET,
+	CLK_SET,
+};
+
+struct sensor_oem_setting {
+	enum oem_setting_type type;
+	void *data;
+};
+
+enum camera_vreg_type {
+	REG_LDO,
+	REG_VS,
+	REG_GPIO,
+};
+
+struct camera_vreg_t {
+	const char *reg_name;
+	enum camera_vreg_type type;
+	int min_voltage;
+	int max_voltage;
+	int op_mode;
+	uint32_t delay;
+};
+
+struct msm_camera_vreg_setting {
+	struct camera_vreg_t *cam_vreg;
+	uint16_t num_vreg;
+	uint8_t enable;
+};
+
+struct msm_cam_clk_info {
+	const char *clk_name;
+	long clk_rate;
+	uint32_t delay;
+};
+
+struct msm_cam_clk_setting {
+	struct msm_cam_clk_info *clk_info;
+	uint16_t num_clk_info;
+	uint8_t enable;
+};
+
 struct sensor_cfg_data {
 	int cfgtype;
 	int mode;
@@ -1395,12 +1641,30 @@
 		int ae_mode;
 		uint8_t wb_val;
 		int8_t exp_compensation;
+		uint32_t pclk;
 		struct cord aec_cord;
 		int is_autoflash;
 		struct mirror_flip mirror_flip;
+		void *setting;
 	} cfg;
 };
 
+enum gpio_operation_type {
+	GPIO_REQUEST,
+	GPIO_FREE,
+	GPIO_SET_DIRECTION_OUTPUT,
+	GPIO_SET_DIRECTION_INPUT,
+	GPIO_GET_VALUE,
+	GPIO_SET_VALUE,
+};
+
+struct msm_cam_gpio_operation {
+	enum gpio_operation_type op_type;
+	unsigned address;
+	int value;
+	const char *tag;
+};
+
 struct damping_params_t {
 	uint32_t damping_step;
 	uint32_t damping_delay;
@@ -1557,11 +1821,17 @@
 	struct pixel_t video_coord[128];
 };
 
+struct msm_calib_raw {
+	uint8_t *data;
+	uint32_t size;
+};
+
 struct msm_camera_eeprom_info_t {
 	struct msm_eeprom_support af;
 	struct msm_eeprom_support wb;
 	struct msm_eeprom_support lsc;
 	struct msm_eeprom_support dpc;
+	struct msm_eeprom_support raw;
 };
 
 struct msm_eeprom_cfg_data {
@@ -1734,6 +2004,9 @@
 #define MSM_CAM_V4L2_IOCTL_PRIVATE_G_CTRL \
 	_IOWR('V', BASE_VIDIOC_PRIVATE + 9, struct msm_camera_v4l2_ioctl_t)
 
+#define MSM_CAM_V4L2_IOCTL_PRIVATE_GENERAL \
+	_IOW('V', BASE_VIDIOC_PRIVATE + 10, struct msm_camera_v4l2_ioctl_t)
+
 #define VIDIOC_MSM_VPE_INIT \
 	_IO('V', BASE_VIDIOC_PRIVATE + 15)
 
@@ -1744,7 +2017,7 @@
 	_IOWR('V', BASE_VIDIOC_PRIVATE + 17, struct msm_mctl_pp_params *)
 
 #define VIDIOC_MSM_AXI_INIT \
-	_IO('V', BASE_VIDIOC_PRIVATE + 18)
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 18, uint8_t *)
 
 #define VIDIOC_MSM_AXI_RELEASE \
 	_IO('V', BASE_VIDIOC_PRIVATE + 19)
@@ -1758,22 +2031,27 @@
 #define VIDIOC_MSM_AXI_BUF_CFG \
 	_IOWR('V', BASE_VIDIOC_PRIVATE + 22, void *)
 
+#define VIDIOC_MSM_AXI_RDI_COUNT_UPDATE \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 23, struct rdi_count_msg)
+
 #define VIDIOC_MSM_VFE_INIT \
-	_IO('V', BASE_VIDIOC_PRIVATE + 22)
+	_IO('V', BASE_VIDIOC_PRIVATE + 24)
 
 #define VIDIOC_MSM_VFE_RELEASE \
-	_IO('V', BASE_VIDIOC_PRIVATE + 23)
+	_IO('V', BASE_VIDIOC_PRIVATE + 25)
 
 struct msm_camera_v4l2_ioctl_t {
 	uint32_t id;
-	void __user *ioctl_ptr;
 	uint32_t len;
+	uint32_t trans_code;
+	void __user *ioctl_ptr;
 };
 
 struct msm_camera_vfe_params_t {
 	uint32_t operation_mode;
 	uint32_t capture_count;
-	uint32_t skip_abort;
+	uint8_t  skip_reset;
+	uint8_t  stop_immediately;
 	uint16_t port_info;
 	uint32_t inst_handle;
 	uint16_t cmd_type;
@@ -1937,7 +2215,8 @@
  *      ------------------------------------
  *      Bits    :  Purpose
  *      ------------------------------------
- *      31 - 24 :  Reserved.
+ *      31      :  is Dev ID valid?
+ *      30 - 24 :  Dev ID.
  *      23      :  is Image mode valid?
  *      22 - 16 :  Image mode.
  *      15      :  is MCTL PP inst idx valid?
@@ -1945,6 +2224,12 @@
  *      7       :  is Video inst idx valid?
  *      6 - 0   :  Video inst idx.
  */
+#define CLR_DEVID_MODE(handle)	(handle &= 0x00FFFFFF)
+#define SET_DEVID_MODE(handle, data)	\
+	(handle |= ((0x1 << 31) | ((data & 0x7F) << 24)))
+#define GET_DEVID_MODE(handle)	\
+	((handle & 0x80000000) ? ((handle & 0x7F000000) >> 24) : 0xFF)
+
 #define CLR_IMG_MODE(handle)	(handle &= 0xFF00FFFF)
 #define SET_IMG_MODE(handle, data)	\
 	(handle |= ((0x1 << 23) | ((data & 0x7F) << 16)))
diff --git a/include/media/msm_isp.h b/include/media/msm_isp.h
index 9fa5932..faaa522 100644
--- a/include/media/msm_isp.h
+++ b/include/media/msm_isp.h
@@ -68,6 +68,9 @@
 #define MSG_ID_RDI0_UPDATE_ACK          49
 #define MSG_ID_RDI1_UPDATE_ACK          50
 #define MSG_ID_RDI2_UPDATE_ACK          51
+#define MSG_ID_PIX0_UPDATE_ACK          52
+#define MSG_ID_PREV_STOP_ACK            53
+
 
 /* ISP command IDs */
 #define VFE_CMD_DUMMY_0                                 0
@@ -324,30 +327,10 @@
 struct msm_vpe_clock_rate {
 	uint32_t rate;
 };
-struct msm_pp_crop {
-	uint32_t  src_x;
-	uint32_t  src_y;
-	uint32_t  src_w;
-	uint32_t  src_h;
-	uint32_t  dst_x;
-	uint32_t  dst_y;
-	uint32_t  dst_w;
-	uint32_t  dst_h;
-	uint8_t update_flag;
-};
+
 #define MSM_MCTL_PP_VPE_FRAME_ACK    (1<<0)
 #define MSM_MCTL_PP_VPE_FRAME_TO_APP (1<<1)
 
-struct msm_mctl_pp_frame_cmd {
-	uint32_t cookie;
-	uint8_t  vpe_output_action;
-	uint32_t src_buf_handle;
-	uint32_t dest_buf_handle;
-	struct msm_pp_crop crop;
-	int path;
-	/* TBD: 3D related */
-};
-
 #define VFE_OUTPUTS_MAIN_AND_PREVIEW    BIT(0)
 #define VFE_OUTPUTS_MAIN_AND_VIDEO      BIT(1)
 #define VFE_OUTPUTS_MAIN_AND_THUMB      BIT(2)
diff --git a/include/media/msm_jpeg.h b/include/media/msm_jpeg.h
new file mode 100644
index 0000000..11c3247
--- /dev/null
+++ b/include/media/msm_jpeg.h
@@ -0,0 +1,119 @@
+#ifndef __LINUX_MSM_JPEG_H
+#define __LINUX_MSM_JPEG_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+#define OUTPUT_H2V1  0
+#define OUTPUT_H2V2  1
+#define OUTPUT_BYTE  6
+
+#define MSM_JPEG_IOCTL_MAGIC 'g'
+
+#define MSM_JPEG_IOCTL_GET_HW_VERSION \
+	_IOW(MSM_JPEG_IOCTL_MAGIC, 1, struct msm_jpeg_hw_cmd *)
+
+#define MSM_JPEG_IOCTL_RESET \
+	_IOW(MSM_JPEG_IOCTL_MAGIC, 2, struct msm_jpeg_ctrl_cmd *)
+
+#define MSM_JPEG_IOCTL_STOP \
+	_IOW(MSM_JPEG_IOCTL_MAGIC, 3, struct msm_jpeg_hw_cmds *)
+
+#define MSM_JPEG_IOCTL_START \
+	_IOW(MSM_JPEG_IOCTL_MAGIC, 4, struct msm_jpeg_hw_cmds *)
+
+#define MSM_JPEG_IOCTL_INPUT_BUF_ENQUEUE \
+	_IOW(MSM_JPEG_IOCTL_MAGIC, 5, struct msm_jpeg_buf *)
+
+#define MSM_JPEG_IOCTL_INPUT_GET \
+	_IOW(MSM_JPEG_IOCTL_MAGIC, 6, struct msm_jpeg_buf *)
+
+#define MSM_JPEG_IOCTL_INPUT_GET_UNBLOCK \
+	_IOW(MSM_JPEG_IOCTL_MAGIC, 7, int)
+
+#define MSM_JPEG_IOCTL_OUTPUT_BUF_ENQUEUE \
+	_IOW(MSM_JPEG_IOCTL_MAGIC, 8, struct msm_jpeg_buf *)
+
+#define MSM_JPEG_IOCTL_OUTPUT_GET \
+	_IOW(MSM_JPEG_IOCTL_MAGIC, 9, struct msm_jpeg_buf *)
+
+#define MSM_JPEG_IOCTL_OUTPUT_GET_UNBLOCK \
+	_IOW(MSM_JPEG_IOCTL_MAGIC, 10, int)
+
+#define MSM_JPEG_IOCTL_EVT_GET \
+	_IOW(MSM_JPEG_IOCTL_MAGIC, 11, struct msm_jpeg_ctrl_cmd *)
+
+#define MSM_JPEG_IOCTL_EVT_GET_UNBLOCK \
+	_IOW(MSM_JPEG_IOCTL_MAGIC, 12, int)
+
+#define MSM_JPEG_IOCTL_HW_CMD \
+	_IOW(MSM_JPEG_IOCTL_MAGIC, 13, struct msm_jpeg_hw_cmd *)
+
+#define MSM_JPEG_IOCTL_HW_CMDS \
+	_IOW(MSM_JPEG_IOCTL_MAGIC, 14, struct msm_jpeg_hw_cmds *)
+
+#define MSM_JPEG_IOCTL_TEST_DUMP_REGION \
+	_IOW(MSM_JPEG_IOCTL_MAGIC, 15, unsigned long)
+
+#define MSM_JPEG_MODE_REALTIME_ENCODE 0
+#define MSM_JPEG_MODE_OFFLINE_ENCODE 1
+#define MSM_JPEG_MODE_REALTIME_ROTATION 2
+#define MSM_JPEG_MODE_OFFLINE_ROTATION 3
+
+struct msm_jpeg_ctrl_cmd {
+	uint32_t type;
+	uint32_t len;
+	void     *value;
+};
+
+#define MSM_JPEG_EVT_RESET 0
+#define MSM_JPEG_EVT_SESSION_DONE	1
+#define MSM_JPEG_EVT_ERR 2
+
+struct msm_jpeg_buf {
+	uint32_t type;
+	int      fd;
+
+	void     *vaddr;
+
+	uint32_t y_off;
+	uint32_t y_len;
+	uint32_t framedone_len;
+
+	uint32_t cbcr_off;
+	uint32_t cbcr_len;
+
+	uint32_t num_of_mcu_rows;
+	uint32_t offset;
+};
+
+#define MSM_JPEG_HW_CMD_TYPE_READ      0
+#define MSM_JPEG_HW_CMD_TYPE_WRITE     1
+#define MSM_JPEG_HW_CMD_TYPE_WRITE_OR  2
+#define MSM_JPEG_HW_CMD_TYPE_UWAIT     3
+#define MSM_JPEG_HW_CMD_TYPE_MWAIT     4
+#define MSM_JPEG_HW_CMD_TYPE_MDELAY    5
+#define MSM_JPEG_HW_CMD_TYPE_UDELAY    6
+struct msm_jpeg_hw_cmd {
+
+	uint32_t type:4;
+
+	/* n microseconds of timeout for WAIT */
+	/* n microseconds of time for DELAY */
+	/* repeat n times for READ/WRITE */
+	/* max is 0xFFF, 4095 */
+	uint32_t n:12;
+	uint32_t offset:16;
+	uint32_t mask;
+	union {
+		uint32_t data;   /* for single READ/WRITE/WAIT, n = 1 */
+		uint32_t *pdata;   /* for multiple READ/WRITE/WAIT, n > 1 */
+	};
+};
+
+struct msm_jpeg_hw_cmds {
+	uint32_t m; /* number of elements in the hw_cmd array */
+	struct msm_jpeg_hw_cmd hw_cmd[1];
+};
+
+#endif /* __LINUX_MSM_JPEG_H */
diff --git a/include/media/msm_vidc.h b/include/media/msm_vidc.h
index baa6a28..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/radio-iris.h b/include/media/radio-iris.h
index 988de6a..db69518 100644
--- a/include/media/radio-iris.h
+++ b/include/media/radio-iris.h
@@ -210,8 +210,9 @@
 #define HCI_FM_GET_DET_CH_TH_CMD 16
 
 /* Defines for FM TX*/
-#define TX_PS_DATA_LENGTH 96
+#define TX_PS_DATA_LENGTH 108
 #define TX_RT_DATA_LENGTH 64
+#define PS_STRING_LEN     9
 
 /* ----- HCI Command request ----- */
 struct hci_fm_recv_conf_req {
@@ -238,7 +239,7 @@
 	__u16	pi;
 	__u8	pty;
 	__u8	ps_repeatcount;
-	__u8	ps_len;
+	__u8	ps_num;
 	__u8    ps_data[TX_PS_DATA_LENGTH];
 } __packed;
 
@@ -246,7 +247,7 @@
 	__u8    rt_control;
 	__u16	pi;
 	__u8	pty;
-	__u8	ps_len;
+	__u8	rt_len;
 	__u8    rt_data[TX_RT_DATA_LENGTH];
 } __packed;
 
@@ -659,7 +660,7 @@
 	IRIS_REGION_OTHER
 };
 
-#define STD_BUF_SIZE        (64)
+#define STD_BUF_SIZE        (128)
 
 enum iris_buf_t {
 	IRIS_BUF_SRCH_LIST,
@@ -745,7 +746,7 @@
 /* constants */
 #define  RDS_BLOCKS_NUM	(4)
 #define BYTES_PER_BLOCK	(3)
-#define MAX_PS_LENGTH	(96)
+#define MAX_PS_LENGTH	(108)
 #define MAX_RT_LENGTH	(64)
 #define RDS_GRP_CNTR_LEN (36)
 #define RX_RT_DATA_LENGTH (63)
diff --git a/include/media/vcap_fmt.h b/include/media/vcap_fmt.h
index 00e0375..2641720 100644
--- a/include/media/vcap_fmt.h
+++ b/include/media/vcap_fmt.h
@@ -27,7 +27,8 @@
 #define VCAP_VP_REG_W_ERR_EVENT 8
 #define VCAP_VP_IN_HEIGHT_ERR_EVENT 9
 #define VCAP_VP_IN_WIDTH_ERR_EVENT 10
-#define VCAP_MAX_NOTIFY_EVENT 11
+#define VCAP_VC_UNEXPECT_BUF_DONE 11
+#define VCAP_MAX_NOTIFY_EVENT 12
 
 enum hal_vcap_mode {
 	HAL_VCAP_MODE_PRO = 0,
@@ -80,6 +81,7 @@
 #define VCAPIOC_NR_S_PARAMS _IOWR('V', (BASE_VIDIOC_PRIVATE+0), struct nr_param)
 
 #define VCAPIOC_NR_G_PARAMS _IOWR('V', (BASE_VIDIOC_PRIVATE+1), struct nr_param)
+#define VCAPIOC_S_NUM_VC_BUF _IOWR('V', (BASE_VIDIOC_PRIVATE+2), int)
 
 struct v4l2_format_vc_ext {
 	enum hal_vcap_mode     mode;
diff --git a/include/media/vcap_v4l2.h b/include/media/vcap_v4l2.h
index cf99435..1e18c9e 100644
--- a/include/media/vcap_v4l2.h
+++ b/include/media/vcap_v4l2.h
@@ -38,14 +38,16 @@
 		writel_relaxed(val, addr);	\
 	} while (0)
 
-struct vcap_client_data;
+#define VCAP_BASE (dev->vcapbase)
+#define VCAP_OFFSET(off) (VCAP_BASE + off)
 
-enum rdy_buf {
-	VC_NO_BUF = 0,
-	VC_BUF1 = 1 << 1,
-	VC_BUF2 = 1 << 2,
-	VC_BUF1N2 = 0x11 << 1,
-};
+#define VCAP_SW_RESET_REQ (VCAP_BASE + 0x024)
+#define VCAP_SW_RESET_STATUS (VCAP_BASE + 0x028)
+
+#define VCAP_VP_MIN_BUF 4
+#define VCAP_VC_MAX_BUF 6
+#define VCAP_VC_MIN_BUF 2
+struct vcap_client_data;
 
 enum vp_state {
 	VP_UNKNOWN = 0,
@@ -75,23 +77,18 @@
 	VC_AND_VP_VCAP_OP,
 };
 
-struct vcap_action {
+struct vc_action {
 	struct list_head		active;
 
 	/* thread for generating video stream*/
-	struct task_struct		*kthread;
 	wait_queue_head_t		wq;
 
 	/* Buffer index */
-	enum rdy_buf            buf_ind;
+	uint8_t					tot_buf;
+	uint8_t					buf_num;
 
 	/* Buffers inside vc */
-	struct vcap_buffer      *buf1;
-	struct vcap_buffer      *buf2;
-
-	/* Counters to control fps rate */
-	int						frame;
-	int						ini_jiffies;
+	struct vcap_buffer      *buf[6];
 };
 
 struct nr_buffer {
@@ -122,8 +119,6 @@
 	struct ion_handle		*motionHandle;
 	void					*bufMotion;
 	struct nr_buffer		bufNR;
-	struct nr_param			nr_param;
-	bool					nr_update;
 };
 
 struct vp_work_t {
@@ -167,12 +162,18 @@
 	bool					vp_resource;
 	bool					vp_dummy_event;
 	bool					vp_dummy_complete;
+	bool					vp_shutdown;
 	wait_queue_head_t		vp_dummy_waitq;
 
+	uint8_t					vc_tot_buf;
+
 	struct workqueue_struct	*vcap_wq;
 	struct vp_work_t		vp_work;
 	struct vp_work_t		vc_to_vp_work;
 	struct vp_work_t		vp_to_vc_work;
+
+	struct nr_param			nr_param;
+	bool					nr_update;
 };
 
 struct vp_format_data {
@@ -204,8 +205,8 @@
 	struct vp_format_data	vp_in_fmt;
 	struct vp_format_data	vp_out_fmt;
 
-	struct vcap_action		vid_vc_action;
-	struct vp_action		vid_vp_action;
+	struct vc_action		vc_action;
+	struct vp_action		vp_action;
 	struct workqueue_struct *vcap_work_q;
 	struct ion_handle			*vc_ion_handle;
 
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/media/videobuf2-msm-mem.h b/include/media/videobuf2-msm-mem.h
index 84e2bea..5285997 100644
--- a/include/media/videobuf2-msm-mem.h
+++ b/include/media/videobuf2-msm-mem.h
@@ -72,9 +72,10 @@
 					struct videobuf2_msm_offset *offset,
 					enum videobuf2_buffer_type,
 					uint32_t addr_offset, int path,
-					struct ion_client *client);
+					struct ion_client *client,
+					int domain_num);
 void videobuf2_pmem_contig_user_put(struct videobuf2_contig_pmem *mem,
-					struct ion_client *client);
+				struct ion_client *client, int domain_num);
 unsigned long videobuf2_to_pmem_contig(struct vb2_buffer *buf,
 					unsigned int plane_no);
 
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 3526e29..80f36e0 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -967,6 +967,26 @@
 
 #define HCI_OP_LE_CREATE_CONN_CANCEL	0x200e
 
+#define HCI_OP_LE_READ_WHITE_LIST_SIZE	0x200F
+struct hci_rp_le_read_white_list_size {
+	__u8     status;
+	__u8     size;
+} __packed;
+
+#define HCI_OP_LE_CLEAR_WHITE_LIST	0x2010
+
+#define HCI_OP_LE_ADD_DEV_WHITE_LIST	0x2011
+struct hci_cp_le_add_dev_white_list {
+	__u8     addr_type;
+	bdaddr_t addr;
+} __packed;
+
+#define HCI_OP_LE_REMOVE_DEV_WHITE_LIST 0x2012
+struct hci_cp_le_remove_dev_white_list {
+	__u8     addr_type;
+	bdaddr_t addr;
+} __packed;
+
 #define HCI_OP_LE_CONN_UPDATE		0x2013
 struct hci_cp_le_conn_update {
 	__le16   handle;
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 22428c1..544f3bf 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -191,6 +191,7 @@
 	unsigned int	acl_pkts;
 	unsigned int	sco_pkts;
 	unsigned int	le_pkts;
+	unsigned int	le_white_list_size;
 
 	unsigned int	data_block_len;
 
@@ -354,6 +355,7 @@
 	__u8		auth;
 	void		*smp_conn;
 	struct timer_list smp_timer;
+	__u8		conn_valid;
 
 
 	void (*connect_cfm_cb)	(struct hci_conn *conn, u8 status);
@@ -602,6 +604,9 @@
 					bdaddr_t *dst, __u8 sec_level,
 					__u8 auth_type,
 					struct bt_le_params *le_params);
+void hci_le_add_dev_white_list(struct hci_dev *hdev, bdaddr_t *dst);
+void hci_le_remove_dev_white_list(struct hci_dev *hdev, bdaddr_t *dst);
+void hci_le_cancel_create_connect(struct hci_dev *hdev, bdaddr_t *dst);
 int hci_conn_check_link_mode(struct hci_conn *conn);
 int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type);
 int hci_conn_change_link_key(struct hci_conn *conn);
@@ -1035,7 +1040,7 @@
 int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 le);
 int mgmt_le_conn_params(u16 index, bdaddr_t *bdaddr, u16 interval,
 						u16 latency, u16 timeout);
-int mgmt_disconnected(u16 index, bdaddr_t *bdaddr);
+int mgmt_disconnected(u16 index, bdaddr_t *bdaddr, u8 reason);
 int mgmt_disconnect_failed(u16 index);
 int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status);
 int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr);
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index 3048339..602fe59 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -60,6 +60,7 @@
 	__u8 hci_ver;
 	__u16 hci_rev;
 	__u8 name[MGMT_MAX_NAME_LENGTH];
+	__u8 le_white_list_size;
 } __packed;
 
 struct mgmt_mode {
@@ -246,6 +247,26 @@
 	bdaddr_t	bdaddr;
 } __packed;
 
+#define MGMT_OP_LE_READ_WHITE_LIST_SIZE	0xE000
+
+#define MGMT_OP_LE_CLEAR_WHITE_LIST	0xE001
+
+#define MGMT_OP_LE_ADD_DEV_WHITE_LIST	0xE002
+struct mgmt_cp_le_add_dev_white_list {
+	__u8 addr_type;
+	bdaddr_t bdaddr;
+} __packed;
+
+#define MGMT_OP_LE_REMOVE_DEV_WHITE_LIST	0xE003
+struct mgmt_cp_le_remove_dev_white_list {
+	__u8 addr_type;
+	bdaddr_t bdaddr;
+} __packed;
+
+#define MGMT_OP_LE_CREATE_CONN_WHITE_LIST	0xE004
+
+#define MGMT_OP_LE_CANCEL_CREATE_CONN_WHITE_LIST	0xE005
+
 #define MGMT_EV_CMD_COMPLETE		0x0001
 struct mgmt_ev_cmd_complete {
 	__le16 opcode;
@@ -290,6 +311,7 @@
 #define MGMT_EV_DISCONNECTED		0x000C
 struct mgmt_ev_disconnected {
 	bdaddr_t bdaddr;
+	__u8     reason;
 } __packed;
 
 #define MGMT_EV_CONNECT_FAILED		0x000D
diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h
index fffdc60..95ec28b 100644
--- a/include/net/pkt_sched.h
+++ b/include/net/pkt_sched.h
@@ -103,7 +103,8 @@
 			      struct tcf_result *res);
 extern int tc_classify(struct sk_buff *skb, const struct tcf_proto *tp,
 		       struct tcf_result *res);
-
+extern void tc_qdisc_flow_control(struct net_device *dev, u32 tcm_handle,
+				  int flow_enable);
 /* Calculate maximal size of packet seen by hard_start_xmit
    routine of this device.
  */
diff --git a/include/sound/apr_audio.h b/include/sound/apr_audio.h
index 979db58..90872c9 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
@@ -969,6 +978,16 @@
 	u32 sample_rate;
 };
 
+struct asm_amrwbplus_cfg {
+	u32  size_bytes;
+	u32  version;
+	u32  num_channels;
+	u32  amr_band_mode;
+	u32  amr_dtx_mode;
+	u32  amr_frame_fmt;
+	u32  amr_lsf_idx;
+};
+
 struct asm_flac_cfg {
 	u16 stream_info_present;
 	u16 min_blk_size;
@@ -1102,6 +1121,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 +1130,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 +1188,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;
@@ -1352,7 +1383,7 @@
 	u32	uid;
 } __attribute__((packed));
 
-#define ASM_DATA_CMD_READ_COMPRESSED                     0x00010DBC
+#define ASM_DATA_CMD_READ_COMPRESSED                     0x00010DBF
 struct asm_stream_cmd_read_compressed {
 	struct apr_hdr     hdr;
 	u32	buf_add;
@@ -1377,6 +1408,7 @@
 		struct asm_flac_cfg        flac_cfg;
 		struct asm_vorbis_cfg      vorbis_cfg;
 		struct asm_multi_channel_pcm_fmt_blk multi_ch_pcm_cfg;
+		struct asm_amrwbplus_cfg   amrwbplus_cfg;
 	} __attribute__((packed)) write_cfg;
 } __attribute__((packed));
 
@@ -1423,7 +1455,7 @@
 	u32            id;
 } __attribute__((packed));
 
-#define ASM_DATA_EVENT_READ_COMPRESSED_DONE              0x00010DBD
+#define ASM_DATA_EVENT_READ_COMPRESSED_DONE              0x00010DC0
 struct asm_data_event_read_compressed_done {
 	u32            status;
 	u32            buffer_add;
diff --git a/include/sound/jack.h b/include/sound/jack.h
index 1089ba4..8e8c133 100644
--- a/include/sound/jack.h
+++ b/include/sound/jack.h
@@ -64,7 +64,7 @@
 	int type;
 	const char *id;
 	char name[100];
-	unsigned int key[6];   /* Keep in sync with definitions above */
+	unsigned int key[8];   /* Keep in sync with definitions above */
 	void *private_data;
 	void (*private_free)(struct snd_jack *);
 };
diff --git a/include/sound/q6adm.h b/include/sound/q6adm.h
index 8e15955..676c4cb 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/q6afe-v2.h b/include/sound/q6afe-v2.h
index b1ed9a4..8ccc9f4 100644
--- a/include/sound/q6afe-v2.h
+++ b/include/sound/q6afe-v2.h
@@ -92,7 +92,7 @@
 int afe_unregister_get_events(u16 port_id);
 int afe_rt_proxy_port_write(u32 buf_addr_p, u32 mem_map_handle, int bytes);
 int afe_rt_proxy_port_read(u32 buf_addr_p, u32 mem_map_handle, int bytes);
-int afe_port_start_nowait(u16 port_id, union afe_port_config *afe_config,
+int afe_port_start(u16 port_id, union afe_port_config *afe_config,
 	u32 rate);
 int afe_port_stop_nowait(int port_id);
 int afe_apply_gain(u16 port_id, u16 gain);
diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h
index 2a555b2..2ee5ff7 100644
--- a/include/sound/q6asm-v2.h
+++ b/include/sound/q6asm-v2.h
@@ -16,7 +16,7 @@
 #include <mach/msm_subsystem_map.h>
 #include <sound/apr_audio-v2.h>
 #include <linux/list.h>
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
 
 #define IN                      0x000
 #define OUT                     0x001
diff --git a/include/sound/q6asm.h b/include/sound/q6asm.h
index ea77974..4021d48 100644
--- a/include/sound/q6asm.h
+++ b/include/sound/q6asm.h
@@ -15,7 +15,7 @@
 #include <mach/qdsp6v2/apr.h>
 #include <sound/apr_audio.h>
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
 #endif
 
 #define IN                      0x000
@@ -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);
@@ -286,6 +288,9 @@
 int q6asm_media_format_block_aac(struct audio_client *ac,
 			struct asm_aac_cfg *cfg);
 
+int q6asm_media_format_block_amrwbplus(struct audio_client *ac,
+					struct asm_amrwbplus_cfg *cfg);
+
 int q6asm_media_format_block_multi_aac(struct audio_client *ac,
 			struct asm_aac_cfg *cfg);
 
diff --git a/include/trace/events/power.h b/include/trace/events/power.h
index 9271f5d..5fa311a 100644
--- a/include/trace/events/power.h
+++ b/include/trace/events/power.h
@@ -48,6 +48,48 @@
 	TP_ARGS(frequency, cpu_id)
 );
 
+TRACE_EVENT(cpu_frequency_switch_start,
+
+	TP_PROTO(unsigned int start_freq, unsigned int end_freq,
+		 unsigned int cpu_id),
+
+	TP_ARGS(start_freq, end_freq, cpu_id),
+
+	TP_STRUCT__entry(
+		__field(	u32,		start_freq	)
+		__field(	u32,		end_freq	)
+		__field(	u32,		cpu_id		)
+	),
+
+	TP_fast_assign(
+		__entry->start_freq = start_freq;
+		__entry->end_freq = end_freq;
+		__entry->cpu_id = cpu_id;
+	),
+
+	TP_printk("start=%lu end=%lu cpu_id=%lu",
+		  (unsigned long)__entry->start_freq,
+		  (unsigned long)__entry->end_freq,
+		  (unsigned long)__entry->cpu_id)
+);
+
+TRACE_EVENT(cpu_frequency_switch_end,
+
+	TP_PROTO(unsigned int cpu_id),
+
+	TP_ARGS(cpu_id),
+
+	TP_STRUCT__entry(
+		__field(	u32,		cpu_id		)
+	),
+
+	TP_fast_assign(
+		__entry->cpu_id = cpu_id;
+	),
+
+	TP_printk("cpu_id=%lu", (unsigned long)__entry->cpu_id)
+);
+
 TRACE_EVENT(machine_suspend,
 
 	TP_PROTO(unsigned int state),
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/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/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c
index 431dba8..006d5c9 100644
--- a/kernel/trace/trace_events_filter.c
+++ b/kernel/trace/trace_events_filter.c
@@ -2002,7 +2002,7 @@
 static int __ftrace_function_set_filter(int filter, char *buf, int len,
 					struct function_filter_data *data)
 {
-	int i, re_cnt, ret;
+	int i, re_cnt, ret = 0;
 	int *reset;
 	char **re;
 
diff --git a/lib/genalloc.c b/lib/genalloc.c
index ef15640..9cf1b8b 100644
--- a/lib/genalloc.c
+++ b/lib/genalloc.c
@@ -34,6 +34,7 @@
 #include <linux/rculist.h>
 #include <linux/interrupt.h>
 #include <linux/genalloc.h>
+#include <linux/vmalloc.h>
 
 static int set_bits_ll(unsigned long *addr, unsigned long mask_to_set)
 {
@@ -178,9 +179,14 @@
 	int nbytes = sizeof(struct gen_pool_chunk) +
 				(nbits + BITS_PER_BYTE - 1) / BITS_PER_BYTE;
 
-	chunk = kmalloc_node(nbytes, GFP_KERNEL | __GFP_ZERO, nid);
+	if (nbytes <= PAGE_SIZE)
+		chunk = kmalloc_node(nbytes, __GFP_ZERO, nid);
+	else
+		chunk = vmalloc(nbytes);
 	if (unlikely(chunk == NULL))
 		return -ENOMEM;
+	if (nbytes > PAGE_SIZE)
+		memset(chunk, 0, nbytes);
 
 	chunk->phys_addr = phys;
 	chunk->start_addr = virt;
@@ -235,14 +241,20 @@
 	int bit, end_bit;
 
 	list_for_each_safe(_chunk, _next_chunk, &pool->chunks) {
+		int nbytes;
 		chunk = list_entry(_chunk, struct gen_pool_chunk, next_chunk);
 		list_del(&chunk->next_chunk);
 
 		end_bit = (chunk->end_addr - chunk->start_addr) >> order;
+		nbytes = sizeof(struct gen_pool_chunk) +
+				(end_bit + BITS_PER_BYTE - 1) / BITS_PER_BYTE;
 		bit = find_next_bit(chunk->bits, end_bit, 0);
 		BUG_ON(bit < end_bit);
 
-		kfree(chunk);
+		if (nbytes <= PAGE_SIZE)
+			kfree(chunk);
+		else
+			vfree(chunk);
 	}
 	kfree(pool);
 	return;
@@ -290,8 +302,8 @@
 
 retry:
 		start_bit = bitmap_find_next_zero_area_off(chunk->bits, chunk_size,
-						       0, nbits, align_mask,
-						       chunk->start_addr);
+						   0, nbits, align_mask,
+						   chunk->start_addr >> order);
 		if (start_bit >= chunk_size)
 			continue;
 		remain = bitmap_set_ll(chunk->bits, start_bit, nbits);
diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c
index f504921..5ac5c52 100644
--- a/net/bluetooth/bnep/core.c
+++ b/net/bluetooth/bnep/core.c
@@ -56,6 +56,9 @@
 #include "bnep.h"
 
 #define VERSION "1.3"
+/* As this feature is dummy for BNEP net device
+** disabling support */
+#undef CONFIG_BT_BNEP_MC_FILTER
 
 static bool compress_src = 1;
 static bool compress_dst = 1;
diff --git a/net/bluetooth/bnep/netdev.c b/net/bluetooth/bnep/netdev.c
index 155ff74..a8e5449 100644
--- a/net/bluetooth/bnep/netdev.c
+++ b/net/bluetooth/bnep/netdev.c
@@ -44,6 +44,9 @@
 #include "bnep.h"
 
 #define BNEP_TX_QUEUE_LEN 20
+/* As this feature is dummy for BNEP net device
+** disabling support */
+#undef CONFIG_BT_BNEP_MC_FILTER
 
 static int bnep_net_open(struct net_device *dev)
 {
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 08bf42d..0704394 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -50,7 +50,7 @@
 				bdaddr_t *dst, __u8 sec_level, __u8 auth_type,
 				struct bt_le_params *le_params)
 {
-	struct hci_conn *le;
+	struct hci_conn *le, *le_wlist_conn;
 	struct hci_cp_le_create_conn cp;
 	struct adv_entry *entry;
 	struct link_key *key;
@@ -59,8 +59,21 @@
 
 	le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst);
 	if (le) {
-		hci_conn_hold(le);
-		return le;
+		le_wlist_conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
+								BDADDR_ANY);
+		if (!le_wlist_conn) {
+			hci_conn_hold(le);
+			return le;
+		} else {
+			BT_DBG("remove wlist conn");
+			le->out = 1;
+			le->link_mode |= HCI_LM_MASTER;
+			le->sec_level = BT_SECURITY_LOW;
+			le->type = LE_LINK;
+			hci_proto_connect_cfm(le, 0);
+			hci_conn_del(le_wlist_conn);
+			return le;
+		}
 	}
 
 	key = hci_find_link_key_type(hdev, dst, KEY_TYPE_LTK);
@@ -107,8 +120,13 @@
 		cp.conn_latency = cpu_to_le16(BT_LE_LATENCY_DEF);
 		le->conn_timeout = 5;
 	}
-	bacpy(&cp.peer_addr, &le->dst);
-	cp.peer_addr_type = le->dst_type;
+	if (!bacmp(&le->dst, BDADDR_ANY)) {
+		cp.filter_policy = 0x01;
+		le->conn_timeout = 0;
+	} else {
+		bacpy(&cp.peer_addr, &le->dst);
+		cp.peer_addr_type = le->dst_type;
+	}
 
 	hci_send_cmd(hdev, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp);
 
@@ -121,6 +139,80 @@
 	hci_send_cmd(conn->hdev, HCI_OP_LE_CREATE_CONN_CANCEL, 0, NULL);
 }
 
+void hci_le_cancel_create_connect(struct hci_dev *hdev, bdaddr_t *dst)
+{
+	struct hci_conn *le;
+
+	BT_DBG("%p", hdev);
+
+	le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst);
+	if (le) {
+		BT_DBG("send hci connect cancel");
+		hci_le_connect_cancel(le);
+		hci_conn_del(le);
+	}
+}
+EXPORT_SYMBOL(hci_le_cancel_create_connect);
+
+void hci_le_add_dev_white_list(struct hci_dev *hdev, bdaddr_t *dst)
+{
+	struct hci_cp_le_add_dev_white_list cp;
+	struct adv_entry *entry;
+	struct link_key *key;
+
+	BT_DBG("%p", hdev);
+
+	memset(&cp, 0, sizeof(cp));
+	bacpy(&cp.addr, dst);
+
+	key = hci_find_link_key_type(hdev, dst, KEY_TYPE_LTK);
+	if (!key) {
+		entry = hci_find_adv_entry(hdev, dst);
+		if (entry)
+			cp.addr_type = entry->bdaddr_type;
+		else
+			cp.addr_type = 0x00;
+	} else {
+		cp.addr_type = key->addr_type;
+	}
+
+	hci_send_cmd(hdev, HCI_OP_LE_ADD_DEV_WHITE_LIST, sizeof(cp), &cp);
+}
+EXPORT_SYMBOL(hci_le_add_dev_white_list);
+
+void hci_le_remove_dev_white_list(struct hci_dev *hdev, bdaddr_t *dst)
+{
+	struct hci_cp_le_remove_dev_white_list cp;
+	struct adv_entry *entry;
+	struct link_key *key;
+
+	BT_DBG("%p", hdev);
+
+	memset(&cp, 0, sizeof(cp));
+	bacpy(&cp.addr, dst);
+
+	key = hci_find_link_key_type(hdev, dst, KEY_TYPE_LTK);
+	if (!key) {
+		entry = hci_find_adv_entry(hdev, dst);
+		if (entry)
+			cp.addr_type = entry->bdaddr_type;
+		else
+			cp.addr_type = 0x00;
+	} else {
+		cp.addr_type = key->addr_type;
+	}
+
+	hci_send_cmd(hdev, HCI_OP_LE_REMOVE_DEV_WHITE_LIST, sizeof(cp), &cp);
+}
+EXPORT_SYMBOL(hci_le_remove_dev_white_list);
+
+static inline bool is_role_switch_possible(struct hci_dev *hdev)
+{
+	if (hci_conn_hash_lookup_state(hdev, ACL_LINK, BT_CONNECTED))
+		return false;
+	return true;
+}
+
 void hci_acl_connect(struct hci_conn *conn)
 {
 	struct hci_dev *hdev = conn->hdev;
@@ -156,7 +248,8 @@
 	}
 
 	cp.pkt_type = cpu_to_le16(conn->pkt_type);
-	if (lmp_rswitch_capable(hdev) && !(hdev->link_mode & HCI_LM_MASTER))
+	if (lmp_rswitch_capable(hdev) && !(hdev->link_mode & HCI_LM_MASTER)
+		&& is_role_switch_possible(hdev))
 		cp.role_switch = 0x01;
 	else
 		cp.role_switch = 0x00;
@@ -393,9 +486,7 @@
 
 	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)
@@ -450,6 +541,8 @@
 
 	conn->power_save = 1;
 	conn->disc_timeout = HCI_DISCONN_TIMEOUT;
+	conn->conn_valid = true;
+	spin_lock_init(&conn->lock);
 	wake_lock_init(&conn->idle_lock, WAKE_LOCK_SUSPEND, "bt_idle");
 
 	switch (type) {
@@ -522,6 +615,10 @@
 
 	BT_DBG("%s conn %p handle %d", hdev->name, conn, conn->handle);
 
+	spin_lock_bh(&conn->lock);
+	conn->conn_valid = false; /* conn data is being released */
+	spin_unlock_bh(&conn->lock);
+
 	/* Make sure no timers are running */
 	del_timer(&conn->idle_timer);
 	wake_lock_destroy(&conn->idle_lock);
@@ -759,7 +856,18 @@
 	if (type == ACL_LINK)
 		return acl;
 
+	/* type of connection already existing can be ESCO or SCO
+	 * so check for both types before creating new */
+
 	sco = hci_conn_hash_lookup_ba(hdev, type, dst);
+
+	if (!sco && type == ESCO_LINK) {
+		sco = hci_conn_hash_lookup_ba(hdev, SCO_LINK, dst);
+	} else if (!sco && type == SCO_LINK) {
+		/* this case can be practically not possible */
+		sco = hci_conn_hash_lookup_ba(hdev, ESCO_LINK, dst);
+	}
+
 	if (!sco) {
 		sco = hci_conn_add(hdev, type, pkt_type, dst);
 		if (!sco) {
@@ -970,9 +1078,13 @@
 
 timer:
 	if (hdev->idle_timeout > 0) {
-		mod_timer(&conn->idle_timer,
-			jiffies + msecs_to_jiffies(hdev->idle_timeout));
-		wake_lock(&conn->idle_lock);
+		spin_lock_bh(&conn->lock);
+		if (conn->conn_valid) {
+			mod_timer(&conn->idle_timer,
+				jiffies + msecs_to_jiffies(hdev->idle_timeout));
+			wake_lock(&conn->idle_lock);
+		}
+		spin_unlock_bh(&conn->lock);
 	}
 }
 
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index bf854c3..345b70f 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -305,6 +305,12 @@
 
 	/* Read LE buffer size */
 	hci_send_cmd(hdev, HCI_OP_LE_READ_BUFFER_SIZE, 0, NULL);
+
+	/* Read LE clear white list */
+	hci_send_cmd(hdev, HCI_OP_LE_CLEAR_WHITE_LIST, 0, NULL);
+
+	/* Read LE white list size */
+	hci_send_cmd(hdev, HCI_OP_LE_READ_WHITE_LIST_SIZE, 0, NULL);
 }
 
 static void hci_scan_req(struct hci_dev *hdev, unsigned long opt)
@@ -2285,7 +2291,6 @@
 			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);
@@ -2295,7 +2300,6 @@
 			quote -= count;
 
 			conn->sent += count;
-			hci_dev_unlock(hdev);
 		}
 	}
 }
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 6e8500b..e5f43ec 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -426,6 +426,16 @@
 	hci_req_complete(hdev, HCI_OP_HOST_BUFFER_SIZE, status);
 }
 
+static void hci_cc_le_clear_white_list(struct hci_dev *hdev,
+							struct sk_buff *skb)
+{
+	__u8 status = *((__u8 *) skb->data);
+
+	BT_DBG("%s status 0x%x", hdev->name, status);
+
+	hci_req_complete(hdev, HCI_OP_LE_CLEAR_WHITE_LIST, status);
+}
+
 static void hci_cc_read_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct hci_rp_read_ssp_mode *rp = (void *) skb->data;
@@ -913,6 +923,23 @@
 	hci_req_complete(hdev, HCI_OP_LE_READ_BUFFER_SIZE, rp->status);
 }
 
+static void hci_cc_le_read_white_list_size(struct hci_dev *hdev,
+				       struct sk_buff *skb)
+{
+	struct hci_rp_le_read_white_list_size *rp = (void *) skb->data;
+
+	BT_DBG("%s status 0x%x", hdev->name, rp->status);
+
+	if (rp->status)
+		return;
+
+	hdev->le_white_list_size = rp->size;
+
+	BT_DBG("%s le white list %d", hdev->name, hdev->le_white_list_size);
+
+	hci_req_complete(hdev, HCI_OP_LE_READ_WHITE_LIST_SIZE, rp->status);
+}
+
 static void hci_cc_user_confirm_reply(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct hci_rp_user_confirm_reply *rp = (void *) skb->data;
@@ -1767,7 +1794,7 @@
 	struct hci_ev_disconn_complete *ev = (void *) skb->data;
 	struct hci_conn *conn;
 
-	BT_DBG("%s status %d", hdev->name, ev->status);
+	BT_DBG("%s status %d reason %d", hdev->name, ev->status, ev->reason);
 
 	if (ev->status) {
 		hci_dev_lock(hdev);
@@ -1785,7 +1812,7 @@
 	conn->state = BT_CLOSED;
 
 	if (conn->type == ACL_LINK || conn->type == LE_LINK)
-		mgmt_disconnected(hdev->id, &conn->dst);
+		mgmt_disconnected(hdev->id, &conn->dst, ev->reason);
 
 	if (conn->type == LE_LINK)
 		del_timer(&conn->smp_timer);
@@ -2253,6 +2280,14 @@
 		hci_cc_le_read_buffer_size(hdev, skb);
 		break;
 
+	case HCI_OP_LE_READ_WHITE_LIST_SIZE:
+		hci_cc_le_read_white_list_size(hdev, skb);
+		break;
+
+	case HCI_OP_LE_CLEAR_WHITE_LIST:
+		hci_cc_le_clear_white_list(hdev, skb);
+		break;
+
 	case HCI_OP_READ_RSSI:
 		hci_cc_read_rssi(hdev, skb);
 		break;
@@ -3172,11 +3207,23 @@
 {
 	struct hci_ev_le_conn_complete *ev = (void *) skb->data;
 	struct hci_conn *conn;
+	u8 white_list;
 
 	BT_DBG("%s status %d", hdev->name, ev->status);
 
 	hci_dev_lock(hdev);
 
+	/* Ignore event for LE cancel create conn whitelist */
+	if (ev->status && !bacmp(&ev->bdaddr, BDADDR_ANY))
+		goto unlock;
+
+	if (hci_conn_hash_lookup_ba(hdev, LE_LINK, BDADDR_ANY))
+		white_list = 1;
+	else
+		white_list = 0;
+
+	BT_DBG("w_list %d", white_list);
+
 	conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &ev->bdaddr);
 	if (!conn) {
 		conn = hci_le_conn_add(hdev, &ev->bdaddr, ev->bdaddr_type);
@@ -3208,7 +3255,8 @@
 	hci_conn_hold_device(conn);
 	hci_conn_add_sysfs(conn);
 
-	hci_proto_connect_cfm(conn, ev->status);
+	if (!white_list)
+		hci_proto_connect_cfm(conn, ev->status);
 
 unlock:
 	hci_dev_unlock(hdev);
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index d80c0e3..2c4ab78 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -93,40 +93,15 @@
 	return NULL;
 }
 
-static struct device *hidp_get_device(struct hidp_session *session)
-{
-	bdaddr_t *dst = &session->bdaddr;
-
-	struct device *device = NULL;
-	struct hci_dev *hdev;
-
-	hdev = hci_get_route(dst, BDADDR_ANY);
-	if (!hdev)
-		return NULL;
-
-	session->conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
-	if (session->conn)
-		device = &session->conn->dev;
-
-	hci_dev_put(hdev);
-
-	return device;
-}
-
 static void __hidp_link_session(struct hidp_session *session)
 {
 	__module_get(THIS_MODULE);
 	list_add(&session->list, &hidp_session_list);
-
-	hci_conn_hold_device(session->conn);
 }
 
 static void __hidp_unlink_session(struct hidp_session *session)
 {
-	struct device *dev;
-
-	dev = hidp_get_device(session);
-	if (dev)
+	if (session->conn)
 		hci_conn_put_device(session->conn);
 
 	list_del(&session->list);
@@ -660,6 +635,28 @@
 	return 0;
 }
 
+static struct hci_conn *hidp_get_connection(struct hidp_session *session)
+{
+	bdaddr_t *src = &bt_sk(session->ctrl_sock->sk)->src;
+	bdaddr_t *dst = &bt_sk(session->ctrl_sock->sk)->dst;
+	struct hci_conn *conn;
+	struct hci_dev *hdev;
+
+	hdev = hci_get_route(dst, src);
+	if (!hdev)
+		return NULL;
+
+	hci_dev_lock_bh(hdev);
+	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
+	if (conn)
+		hci_conn_hold_device(conn);
+	hci_dev_unlock_bh(hdev);
+
+	hci_dev_put(hdev);
+
+	return conn;
+}
+
 static int hidp_setup_input(struct hidp_session *session,
 				struct hidp_connadd_req *req)
 {
@@ -707,7 +704,7 @@
 		input->relbit[0] |= BIT_MASK(REL_WHEEL);
 	}
 
-	input->dev.parent = hidp_get_device(session);
+	input->dev.parent = &session->conn->dev;
 
 	input->event = hidp_input_event;
 
@@ -808,7 +805,7 @@
 	strncpy(hid->phys, batostr(&bt_sk(session->ctrl_sock->sk)->src), 64);
 	strncpy(hid->uniq, batostr(&bt_sk(session->ctrl_sock->sk)->dst), 64);
 
-	hid->dev.parent = hidp_get_device(session);
+	hid->dev.parent = &session->conn->dev;
 	hid->ll_driver = &hidp_hid_driver;
 
 	hid->hid_output_raw_report = hidp_output_raw_report;
@@ -866,6 +863,12 @@
 	session->intr_sock = intr_sock;
 	session->state     = BT_CONNECTED;
 
+	session->conn = hidp_get_connection(session);
+	if (!session->conn) {
+		err = -ENOTCONN;
+		goto failed;
+	}
+
 	setup_timer(&session->timer, hidp_idle_timeout, (unsigned long)session);
 
 	skb_queue_head_init(&session->ctrl_transmit);
@@ -874,6 +877,8 @@
 	session->flags   = req->flags & (1 << HIDP_BLUETOOTH_VENDOR_ID);
 	session->idle_to = req->idle_to;
 
+	__hidp_link_session(session);
+
 	if (req->rd_size > 0) {
 		err = hidp_setup_hid(session, req);
 		if (err && err != -ENODEV)
@@ -886,8 +891,6 @@
 			goto purge;
 	}
 
-	__hidp_link_session(session);
-
 	hidp_set_timer(session);
 
 	err = kernel_thread(hidp_session, session, CLONE_KERNEL);
@@ -909,8 +912,6 @@
 unlink:
 	hidp_del_timer(session);
 
-	__hidp_unlink_session(session);
-
 	if (session->input) {
 		input_unregister_device(session->input);
 		session->input = NULL;
@@ -925,6 +926,8 @@
 	session->rd_data = NULL;
 
 purge:
+	__hidp_unlink_session(session);
+
 	skb_queue_purge(&session->ctrl_transmit);
 	skb_queue_purge(&session->intr_transmit);
 
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 3fa4a02..761f868 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -98,6 +98,20 @@
 	return 1;
 }
 
+int l2cap_sock_le_conn_update_params_valid(struct bt_le_params *le_params)
+{
+	if (!le_params || le_params->latency > BT_LE_LATENCY_MAX ||
+			le_params->interval_min < BT_LE_CONN_INTERVAL_MIN ||
+			le_params->interval_max > BT_LE_CONN_INTERVAL_MAX ||
+			le_params->interval_min > le_params->interval_max ||
+			le_params->supervision_timeout < BT_LE_SUP_TO_MIN ||
+			le_params->supervision_timeout > BT_LE_SUP_TO_MAX) {
+		return 0;
+	}
+
+	return 1;
+}
+
 static struct sock *__l2cap_get_sock_by_addr(__le16 psm, bdaddr_t *src)
 {
 	struct sock *sk;
@@ -839,7 +853,8 @@
 		}
 
 		if (!conn->hcon->out ||
-				!l2cap_sock_le_params_valid(&le_params)) {
+				!l2cap_sock_le_conn_update_params_valid(
+					&le_params)) {
 			err = -EINVAL;
 			break;
 		}
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 72234c1..d7deaaf 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -229,6 +229,8 @@
 
 	memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
 
+	rp.le_white_list_size = hdev->le_white_list_size;
+
 	hci_dev_unlock_bh(hdev);
 	hci_dev_put(hdev);
 
@@ -1450,6 +1452,185 @@
 	return err;
 }
 
+static int le_add_dev_white_list(struct sock *sk, u16 index,
+					unsigned char *data, u16 len)
+{
+	struct hci_dev *hdev;
+	struct mgmt_cp_le_add_dev_white_list *cp;
+	int err = 0;
+
+	BT_DBG("");
+
+	cp = (void *) data;
+
+	if (len != sizeof(*cp))
+		return cmd_status(sk, index, MGMT_OP_LE_ADD_DEV_WHITE_LIST,
+									EINVAL);
+
+	hdev = hci_dev_get(index);
+	if (!hdev)
+		return cmd_status(sk, index, MGMT_OP_LE_ADD_DEV_WHITE_LIST,
+									ENODEV);
+
+	hci_dev_lock_bh(hdev);
+
+	if (!test_bit(HCI_UP, &hdev->flags)) {
+		err = cmd_status(sk, index, MGMT_OP_LE_ADD_DEV_WHITE_LIST,
+								ENETDOWN);
+		goto failed;
+	}
+
+	hci_le_add_dev_white_list(hdev, &cp->bdaddr);
+
+failed:
+	hci_dev_unlock_bh(hdev);
+	hci_dev_put(hdev);
+
+	return err;
+}
+
+static int le_remove_dev_white_list(struct sock *sk, u16 index,
+					unsigned char *data, u16 len)
+{
+	struct hci_dev *hdev;
+	struct mgmt_cp_le_remove_dev_white_list *cp;
+	int err = 0;
+
+	BT_DBG("");
+
+	cp = (void *) data;
+
+	if (len != sizeof(*cp))
+		return cmd_status(sk, index, MGMT_OP_LE_REMOVE_DEV_WHITE_LIST,
+									EINVAL);
+
+	hdev = hci_dev_get(index);
+	if (!hdev)
+		return cmd_status(sk, index, MGMT_OP_LE_REMOVE_DEV_WHITE_LIST,
+									ENODEV);
+
+	hci_dev_lock_bh(hdev);
+
+	if (!test_bit(HCI_UP, &hdev->flags)) {
+		err = cmd_status(sk, index, MGMT_OP_LE_REMOVE_DEV_WHITE_LIST,
+								ENETDOWN);
+		goto failed;
+	}
+
+	hci_le_remove_dev_white_list(hdev, &cp->bdaddr);
+
+failed:
+	hci_dev_unlock_bh(hdev);
+	hci_dev_put(hdev);
+
+	return err;
+}
+
+static int le_create_conn_white_list(struct sock *sk, u16 index)
+{
+	struct hci_dev *hdev;
+	struct hci_conn *conn;
+	u8 sec_level, auth_type;
+	struct pending_cmd *cmd;
+	bdaddr_t bdaddr;
+	int err = 0;
+
+	BT_DBG("");
+
+	hdev = hci_dev_get(index);
+	if (!hdev)
+		return cmd_status(sk, index, MGMT_OP_LE_CREATE_CONN_WHITE_LIST,
+									ENODEV);
+
+	hci_dev_lock_bh(hdev);
+
+	if (!test_bit(HCI_UP, &hdev->flags)) {
+		err = cmd_status(sk, index, MGMT_OP_LE_CREATE_CONN_WHITE_LIST,
+								ENETDOWN);
+		goto failed;
+	}
+
+	cmd = mgmt_pending_add(sk, MGMT_OP_LE_CREATE_CONN_WHITE_LIST, index,
+								NULL, 0);
+	if (!cmd) {
+		err = -ENOMEM;
+		goto failed;
+	}
+
+	sec_level = BT_SECURITY_MEDIUM;
+	auth_type = HCI_AT_GENERAL_BONDING;
+	memset(&bdaddr, 0, sizeof(bdaddr));
+	conn = hci_le_connect(hdev, 0, BDADDR_ANY, sec_level, auth_type, NULL);
+	if (IS_ERR(conn)) {
+		err = PTR_ERR(conn);
+		mgmt_pending_remove(cmd);
+	}
+
+failed:
+	hci_dev_unlock_bh(hdev);
+	hci_dev_put(hdev);
+
+	return err;
+}
+
+static int le_cancel_create_conn_white_list(struct sock *sk, u16 index)
+{
+	struct hci_dev *hdev;
+	int err = 0;
+
+	BT_DBG("");
+
+	hdev = hci_dev_get(index);
+	if (!hdev)
+		return cmd_status(sk, index,
+			MGMT_OP_LE_CANCEL_CREATE_CONN_WHITE_LIST, ENODEV);
+
+	hci_dev_lock_bh(hdev);
+
+	if (!test_bit(HCI_UP, &hdev->flags)) {
+		err = cmd_status(sk, index,
+			MGMT_OP_LE_CANCEL_CREATE_CONN_WHITE_LIST, ENETDOWN);
+		goto failed;
+	}
+
+	hci_le_cancel_create_connect(hdev, BDADDR_ANY);
+
+failed:
+	hci_dev_unlock_bh(hdev);
+	hci_dev_put(hdev);
+
+	return err;
+}
+
+static int le_clear_white_list(struct sock *sk, u16 index)
+{
+	struct hci_dev *hdev;
+	int err;
+
+	BT_DBG("");
+
+	hdev = hci_dev_get(index);
+	if (!hdev)
+		return cmd_status(sk, index,
+			MGMT_OP_LE_CLEAR_WHITE_LIST, ENODEV);
+
+	hci_dev_lock_bh(hdev);
+
+	if (!test_bit(HCI_UP, &hdev->flags)) {
+		err = cmd_status(sk, index,
+			MGMT_OP_LE_CLEAR_WHITE_LIST, ENETDOWN);
+		goto failed;
+	}
+
+	err = hci_send_cmd(hdev, HCI_OP_LE_CLEAR_WHITE_LIST, 0, NULL);
+
+failed:
+	hci_dev_unlock_bh(hdev);
+	hci_dev_put(hdev);
+
+	return err;
+}
+
 static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
 									u16 len)
 {
@@ -2466,7 +2647,23 @@
 	case MGMT_OP_ENCRYPT_LINK:
 		err = encrypt_link(sk, index, buf + sizeof(*hdr), len);
 		break;
-
+	case MGMT_OP_LE_ADD_DEV_WHITE_LIST:
+		err = le_add_dev_white_list(sk, index, buf + sizeof(*hdr),
+									len);
+		break;
+	case MGMT_OP_LE_REMOVE_DEV_WHITE_LIST:
+		err = le_remove_dev_white_list(sk, index, buf + sizeof(*hdr),
+									len);
+		break;
+	case MGMT_OP_LE_CLEAR_WHITE_LIST:
+		err = le_clear_white_list(sk, index);
+		break;
+	case MGMT_OP_LE_CREATE_CONN_WHITE_LIST:
+		err = le_create_conn_white_list(sk, index);
+		break;
+	case MGMT_OP_LE_CANCEL_CREATE_CONN_WHITE_LIST:
+		err = le_cancel_create_conn_white_list(sk, index);
+		break;
 	default:
 		BT_DBG("Unknown op %u", opcode);
 		err = cmd_status(sk, index, opcode, 0x01);
@@ -2626,10 +2823,25 @@
 int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 le)
 {
 	struct mgmt_ev_connected ev;
+	struct pending_cmd *cmd;
+	struct hci_dev *hdev;
+
+	BT_DBG("hci%u", index);
+
+	hdev = hci_dev_get(index);
+
+	if (!hdev)
+		return -ENODEV;
 
 	bacpy(&ev.bdaddr, bdaddr);
 	ev.le = le;
 
+	cmd = mgmt_pending_find(MGMT_OP_LE_CREATE_CONN_WHITE_LIST, index);
+	if (cmd) {
+		BT_ERR("mgmt_connected remove mgmt pending white_list");
+		mgmt_pending_remove(cmd);
+	}
+
 	return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
 }
 
@@ -2663,21 +2875,22 @@
 	mgmt_pending_remove(cmd);
 }
 
-int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
+int mgmt_disconnected(u16 index, bdaddr_t *bdaddr, u8 reason)
 {
 	struct mgmt_ev_disconnected ev;
 	struct sock *sk = NULL;
 	int err;
 
-	mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
-
 	bacpy(&ev.bdaddr, bdaddr);
+	ev.reason = reason;
 
 	err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
 
 	if (sk)
 		sock_put(sk);
 
+	mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
+
 	return err;
 }
 
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index 3d8981f..60e2fa9 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -1030,6 +1030,35 @@
 }
 
 /*
+ * enable/disable flow on qdisc.
+ */
+void
+tc_qdisc_flow_control(struct net_device *dev, u32 tcm_handle, int enable_flow)
+{
+	struct Qdisc *q;
+	struct __qdisc_change_req {
+		struct nlattr attr;
+		struct tc_prio_qopt data;
+	} req =	{
+		.attr = {sizeof(struct __qdisc_change_req), TCA_OPTIONS},
+		.data = {3, {1, 2, 2, 2, 1, 2, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1}, 1}
+		};
+
+	/* override flow bit */
+	req.data.enable_flow = enable_flow;
+
+	/* look up using tcm handle */
+	q = qdisc_lookup(dev, tcm_handle);
+
+	/* call registered change function */
+	if (q) {
+		if (q->ops->change(q, &(req.attr)) != 0)
+			pr_err("tc_qdisc_flow_control: qdisc change failed");
+	}
+}
+EXPORT_SYMBOL(tc_qdisc_flow_control);
+
+/*
  * Create/change qdisc.
  */
 
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 776e193..4c655c2 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -1726,7 +1726,7 @@
 				$subjectline = $line;
 				$sublinenr = "#$linenr & ";
 # Check for Subject line less than line limit
-				if (length($1) > SHORTTEXT_LIMIT) {
+				if (length($1) > SHORTTEXT_LIMIT && !($1 =~ m/Revert\ \"/)) {
 					WARN("LONG_SUMMARY_LINE",
 					     "summary line over " .
 					     SHORTTEXT_LIMIT .
@@ -1738,7 +1738,7 @@
 				# headers so we are now in the shorttext.
 				$shorttext = IN_SHORTTEXT_BLANKLINE;
 				$shorttext_exspc = 4;
-				if (length($1) > SHORTTEXT_LIMIT) {
+				if (length($1) > SHORTTEXT_LIMIT && !($1 =~ m/Revert\ \"/)) {
 					WARN("LONG_SUMMARY_LINE",
 					     "summary line over " .
 					     SHORTTEXT_LIMIT .
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 947bd85..b11118f 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -2523,7 +2523,7 @@
 		runtime->tstamp_type = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC;
 	return 0;
 }
-		
+
 static int snd_pcm_common_ioctl1(struct file *file,
 				 struct snd_pcm_substream *substream,
 				 unsigned int cmd, void __user *arg)
@@ -2592,6 +2592,7 @@
 	case SNDRV_COMPRESS_SET_PARAMS:
 	case SNDRV_COMPRESS_GET_PARAMS:
 	case SNDRV_COMPRESS_TSTAMP:
+	case SNDRV_COMPRESS_DRAIN:
 		return snd_compressed_ioctl(substream, cmd, arg);
 	}
 	snd_printd("unknown ioctl = 0x%x\n", cmd);
diff --git a/sound/soc/codecs/cs8427.c b/sound/soc/codecs/cs8427.c
index e406a32..23870a4 100644
--- a/sound/soc/codecs/cs8427.c
+++ b/sound/soc/codecs/cs8427.c
@@ -103,8 +103,37 @@
 static int cs8427_i2c_write(struct cs8427 *chip, unsigned short reg,
 			 int bytes, void *src)
 {
-	return cs8427_i2c_write_device(chip, reg, src, bytes);
+	int ret = 0, err = 0;
+	struct cs8427_platform_data *pdata = chip->client->dev.platform_data;
+	/*
+	 * enable the 100KHz level shifter to communicate
+	 * with CS8427 chip
+	 */
+	if (pdata->enable) {
+		err = pdata->enable(1);
+		if (err < 0) {
+			dev_err(&chip->client->dev,
+				"failed to enable the level shifter\n");
+			return err;
+		}
+	}
+	ret = cs8427_i2c_write_device(chip, reg, src, bytes);
+
+	/*
+	 * Disable the 100KHz level shifter to communicate
+	 * with CS8427 chip
+	 */
+	if (pdata->enable) {
+		err = pdata->enable(0);
+		if (err < 0) {
+			dev_err(&chip->client->dev,
+				"failed to disable the level shifter\n");
+			return err;
+		}
+	}
+	return ret;
 }
+
 static int cs8427_i2c_read_device(struct cs8427 *cs8427_i2c,
 				unsigned short reg,
 				  int bytes, unsigned char *dest)
@@ -156,16 +185,45 @@
 				unsigned short reg,
 				int bytes, void *dest)
 {
-	return cs8427_i2c_read_device(chip, reg,
+	u32 err = 0, ret = 0;
+	struct cs8427_platform_data *pdata = chip->client->dev.platform_data;
+	/*
+	 * enable the 100KHz level shifter to communicate
+	 * with CS8427 chip
+	 */
+	if (pdata->enable) {
+		err = pdata->enable(1);
+		if (err < 0) {
+			dev_err(&chip->client->dev,
+				"failed to enable the level shifter\n");
+			return err;
+		}
+	}
+	ret = cs8427_i2c_read_device(chip, reg,
 					bytes, dest);
+
+	/*
+	 * Disable the 100KHz level shifter to communicate
+	 * with CS8427 chip
+	 */
+	if (pdata->enable) {
+		err = pdata->enable(0);
+		if (err < 0) {
+			dev_err(&chip->client->dev,
+				"failed to disable the level shifter\n");
+			return err;
+		}
+	}
+	return ret;
 }
 
 static int cs8427_i2c_sendbytes(struct cs8427 *chip,
 			char *reg_addr, char *data,
 			int bytes)
 {
-	u32 ret = 0;
+	u32 ret = 0, err = 0;
 	u8 i = 0;
+	struct cs8427_platform_data *pdata = chip->client->dev.platform_data;
 
 	if (!chip) {
 		pr_err("%s, invalid device info\n", __func__);
@@ -176,6 +234,18 @@
 			"invalid data pointer\n", __func__);
 		return -EINVAL;
 	}
+	/*
+	 * enable the 100KHz level shifter to communicate
+	 * with CS8427 chip
+	 */
+	if (pdata->enable) {
+		err = pdata->enable(1);
+		if (err < 0) {
+			dev_err(&chip->client->dev,
+				"failed to enable the level shifter\n");
+			return err;
+		}
+	}
 	for (i = 0; i < bytes; i++) {
 		ret = cs8427_i2c_write_device(chip, (*reg_addr + i),
 						&data[i], 1);
@@ -186,6 +256,19 @@
 			break;
 		}
 	}
+
+	/*
+	 * Disable the 100KHz level shifter to communicate
+	 * with CS8427 chip
+	 */
+	if (pdata->enable) {
+		err = pdata->enable(0);
+		if (err < 0) {
+			dev_err(&chip->client->dev,
+				"failed to disable the level shifter\n");
+			return err;
+		}
+	}
 	return i;
 }
 
@@ -651,16 +734,6 @@
 	struct cs8427_platform_data *pdata = chip->client->dev.platform_data;
 	int ret = 0;
 
-	/*enable the 100KHz level shifter*/
-	if (pdata->enable) {
-		ret = pdata->enable(1);
-		if (ret < 0) {
-			dev_err(&chip->client->dev,
-				"failed to enable the level shifter\n");
-			return ret;
-		}
-	}
-
 	ret = gpio_request(pdata->reset_gpio, "cs8427 reset");
 	if (ret < 0) {
 		dev_err(&chip->client->dev,
@@ -740,7 +813,7 @@
 	unsigned char buf[CHANNEL_STATUS_SIZE];
 	unsigned char val = 0;
 	char addr = 0;
-	unsigned int reset_timeout = 100;
+	unsigned int reset_timeout = 1;
 	int ret = 0;
 	struct cs8427 *chip;
 
diff --git a/sound/soc/codecs/wcd9304.c b/sound/soc/codecs/wcd9304.c
index f4f55fa..9432a06 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"},
@@ -2313,7 +2414,7 @@
 		snd_soc_write(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x50);
 		if (SITAR_IS_1P0(sitar_core->version))
 			snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1,
-								0xFF, 0x65);
+								0xF3, 0x61);
 		usleep_range(1000, 1000);
 	} else {
 		pr_err("%s: Error, Invalid bandgap settings\n", __func__);
@@ -2459,17 +2560,38 @@
 	return 0;
 }
 
-static void sitar_shutdown(struct snd_pcm_substream *substream,
-		struct snd_soc_dai *dai)
+static void sitar_codec_pm_runtime_put(struct wcd9xxx *sitar)
 {
-	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);
+	if (sitar->dev != NULL &&
+			sitar->dev->parent != NULL) {
+		pm_runtime_mark_last_busy(sitar->dev->parent);
+		pm_runtime_put(sitar->dev->parent);
 	}
+}
+
+static void sitar_shutdown(struct snd_pcm_substream *substream,
+	struct snd_soc_dai *dai)
+{
+	struct wcd9xxx *sitar_core = dev_get_drvdata(dai->codec->dev->parent);
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(dai->codec);
+	u32 active = 0;
+
 	pr_debug("%s(): substream = %s  stream = %d\n" , __func__,
 		substream->name, substream->stream);
+	if (sitar->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+		return;
+
+	if (dai->id <= NUM_CODEC_DAIS) {
+		if (sitar->dai[dai->id-1].ch_mask) {
+			active = 1;
+			pr_debug("%s(): Codec DAI: chmask[%d] = 0x%x\n",
+				__func__, dai->id-1,
+				sitar->dai[dai->id-1].ch_mask);
+		}
+	}
+
+	if (sitar_core != NULL && active == 0)
+		sitar_codec_pm_runtime_put(sitar_core);
 }
 
 int sitar_mclk_enable(struct snd_soc_codec *codec, int mclk_enable, bool dapm)
@@ -2592,11 +2714,23 @@
 			sitar->dai[dai->id - 1].ch_tot = rx_num;
 		}
 	} else if (dai->id == AIF1_CAP) {
-		for (i = 0; i < tx_num; i++) {
-			sitar->dai[dai->id - 1].ch_num[i]  = tx_slot[i];
-			sitar->dai[dai->id - 1].ch_act = 0;
-			sitar->dai[dai->id - 1].ch_tot = tx_num;
+		sitar->dai[dai->id - 1].ch_tot = tx_num;
+		/* If all channels are already active,
+		 * Do not reset ch_act flag
+		 */
+		if ((sitar->dai[dai->id - 1].ch_tot != 0)
+			&& (sitar->dai[dai->id - 1].ch_act ==
+				sitar->dai[dai->id - 1].ch_tot)) {
+			pr_info("%s: ch_act = %d, ch_tot = %d\n", __func__,
+				sitar->dai[dai->id - 1].ch_act,
+				sitar->dai[dai->id - 1].ch_tot);
+
+			return 0;
 		}
+		sitar->dai[dai->id - 1].ch_act = 0;
+
+		for (i = 0; i < tx_num; i++)
+			sitar->dai[dai->id - 1].ch_num[i]  = tx_slot[i];
 	}
 	return 0;
 }
@@ -2865,8 +2999,9 @@
 			pr_err("%s: slim close tx/rx timeout\n",
 				   __func__);
 			ret = -EINVAL;
+		} else {
+			ret = 0;
 		}
-		ret = 0;
 		break;
 	}
 	return ret;
@@ -2878,12 +3013,18 @@
 	struct wcd9xxx *sitar;
 	struct snd_soc_codec *codec = w->codec;
 	struct sitar_priv *sitar_p = snd_soc_codec_get_drvdata(codec);
-	u32  j = 0, ret = 0;
+	u32  j = 0;
+	int 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++) {
@@ -2917,11 +3058,21 @@
 			wcd9xxx_close_slim_sch_rx(sitar,
 					sitar_p->dai[j].ch_num,
 					sitar_p->dai[j].ch_tot);
+			ret = sitar_codec_enable_chmask(sitar_p, event, j);
+			if (ret < 0) {
+				ret = wcd9xxx_disconnect_port(sitar,
+						sitar_p->dai[j].ch_num,
+						sitar_p->dai[j].ch_tot,
+						1);
+				pr_info("%s: Disconnect RX port ret = %d\n",
+						__func__, ret);
+			}
 			sitar_p->dai[j].rate = 0;
 			memset(sitar_p->dai[j].ch_num, 0, (sizeof(u32)*
 					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;
@@ -2934,14 +3085,19 @@
 	struct snd_soc_codec *codec = w->codec;
 	struct sitar_priv *sitar_p = snd_soc_codec_get_drvdata(codec);
 	/* index to the DAI ID, for now hardcoding */
-	u32  j = 0, ret = 0;
+	u32  j = 0;
+	int 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++) {
@@ -2975,11 +3131,21 @@
 			wcd9xxx_close_slim_sch_tx(sitar,
 					sitar_p->dai[j].ch_num,
 					sitar_p->dai[j].ch_tot);
+			ret = sitar_codec_enable_chmask(sitar_p, event, j);
+			if (ret < 0) {
+				ret = wcd9xxx_disconnect_port(sitar,
+						sitar_p->dai[j].ch_num,
+						sitar_p->dai[j].ch_tot,
+						0);
+				pr_info("%s: Disconnect TX port, ret = %d\n",
+						__func__, ret);
+			}
 			sitar_p->dai[j].rate = 0;
 			memset(sitar_p->dai[j].ch_num, 0, (sizeof(u32)*
 					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;
@@ -4635,12 +4801,12 @@
 }
 
 
-static unsigned long slimbus_value;
 
 static irqreturn_t sitar_slimbus_irq(int irq, void *data)
 {
 	struct sitar_priv *priv = data;
 	struct snd_soc_codec *codec = priv->codec;
+	unsigned long slimbus_value;
 	int i, j, k, port_id, ch_mask_temp;
 	u8 val;
 
@@ -4675,7 +4841,8 @@
 			}
 		}
 		wcd9xxx_interface_reg_write(codec->control_data,
-			SITAR_SLIM_PGD_PORT_INT_CLR0 + i, 0xFF);
+			SITAR_SLIM_PGD_PORT_INT_CLR0 + i, slimbus_value);
+		val = 0x0;
 	}
 
 	return IRQ_HANDLED;
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index 59cb45b..ac11f1a 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)
@@ -60,7 +64,8 @@
 #define NUM_ATTEMPTS_TO_REPORT 5
 
 #define TABLA_JACK_MASK (SND_JACK_HEADSET | SND_JACK_OC_HPHL | \
-			 SND_JACK_OC_HPHR | SND_JACK_UNSUPPORTED)
+			 SND_JACK_OC_HPHR | SND_JACK_LINEOUT | \
+			 SND_JACK_UNSUPPORTED)
 
 #define TABLA_I2S_MASTER_MODE_MASK 0x08
 
@@ -99,7 +104,7 @@
 
 #define TABLA_MBHC_STATUS_REL_DETECTION 0x0C
 
-#define TABLA_MBHC_GPIO_REL_DEBOUNCE_TIME_MS 200
+#define TABLA_MBHC_GPIO_REL_DEBOUNCE_TIME_MS 50
 
 #define TABLA_MBHC_FAKE_INS_DELTA_MV 200
 #define TABLA_MBHC_FAKE_INS_DELTA_SCALED_MV 300
@@ -1788,11 +1793,11 @@
 			0x00);
 	} else if ((tabla->bandgap_type == TABLA_BANDGAP_MBHC_MODE) &&
 		(choice == TABLA_BANDGAP_AUDIO_MODE)) {
-		snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
+		snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x50);
 		usleep_range(100, 100);
 		tabla_codec_enable_audio_mode_bandgap(codec);
 	} else if (choice == TABLA_BANDGAP_OFF) {
-		snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
+		snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x50);
 	} else {
 		pr_err("%s: Error, Invalid bandgap settings\n", __func__);
 	}
@@ -2240,26 +2245,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 +2484,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 +2522,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,
@@ -3058,6 +3064,26 @@
 	return 0;
 }
 
+static int tabla_ear_pa_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+
+	pr_debug("%s %d\n", __func__, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec, TABLA_A_RX_EAR_EN, 0x50, 0x50);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_update_bits(codec, TABLA_A_RX_EAR_EN, 0x10, 0x00);
+		snd_soc_update_bits(codec, TABLA_A_RX_EAR_EN, 0x40, 0x00);
+		break;
+	}
+	return 0;
+}
+
 static const struct snd_soc_dapm_widget tabla_1_x_dapm_widgets[] = {
 	SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", TABLA_1_A_MICB_4_CTL, 7,
 				0, tabla_codec_enable_micbias,
@@ -3754,6 +3780,35 @@
 	return 0;
 }
 
+static void tabla_shutdown(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+	struct wcd9xxx *tabla_core = dev_get_drvdata(dai->codec->dev->parent);
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
+	u32 active = 0;
+
+	pr_debug("%s(): substream = %s  stream = %d\n" , __func__,
+		 substream->name, substream->stream);
+	if (tabla->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+		return;
+
+	if (dai->id <= NUM_CODEC_DAIS) {
+		if (tabla->dai[dai->id-1].ch_mask) {
+			active = 1;
+			pr_debug("%s(): Codec DAI: chmask[%d] = 0x%x\n",
+			__func__, dai->id-1, tabla->dai[dai->id-1].ch_mask);
+		}
+	}
+
+	if ((tabla_core != NULL) &&
+	    (tabla_core->dev != NULL) &&
+	    (tabla_core->dev->parent != NULL) &&
+	    (active == 0)) {
+		pm_runtime_mark_last_busy(tabla_core->dev->parent);
+		pm_runtime_put(tabla_core->dev->parent);
+	}
+}
+
 int tabla_mclk_enable(struct snd_soc_codec *codec, int mclk_enable, bool dapm)
 {
 	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
@@ -4314,6 +4369,7 @@
 
 static struct snd_soc_dai_ops tabla_dai_ops = {
 	.startup = tabla_startup,
+	.shutdown = tabla_shutdown,
 	.hw_params = tabla_hw_params,
 	.set_sysclk = tabla_set_dai_sysclk,
 	.set_fmt = tabla_set_dai_fmt,
@@ -4467,8 +4523,8 @@
 			pr_err("%s: Slim close tx/rx wait timeout\n",
 				__func__);
 			ret = -EINVAL;
-		}
-		ret = 0;
+		} else
+			ret = 0;
 		break;
 	}
 	return ret;
@@ -4481,7 +4537,7 @@
 	struct snd_soc_codec *codec = w->codec;
 	struct tabla_priv *tabla_p = snd_soc_codec_get_drvdata(codec);
 	u32  j = 0;
-	u32  ret = 0;
+	int  ret = 0;
 	codec->control_data = dev_get_drvdata(codec->dev->parent);
 	tabla = codec->control_data;
 
@@ -4538,13 +4594,22 @@
 			ret = wcd9xxx_close_slim_sch_rx(tabla,
 						tabla_p->dai[j].ch_num,
 						tabla_p->dai[j].ch_tot);
-			tabla_p->dai[j].rate = 0;
-			memset(tabla_p->dai[j].ch_num, 0, (sizeof(u32)*
-					tabla_p->dai[j].ch_tot));
-			tabla_p->dai[j].ch_tot = 0;
 			ret = tabla_codec_enable_chmask(tabla_p,
 							SND_SOC_DAPM_POST_PMD,
 							j);
+			if (ret < 0) {
+				ret = wcd9xxx_disconnect_port(tabla,
+							tabla_p->dai[j].ch_num,
+							tabla_p->dai[j].ch_tot,
+							1);
+				pr_info("%s: Disconnect RX port ret = %d\n",
+					__func__, ret);
+			}
+			tabla_p->dai[j].rate = 0;
+			memset(tabla_p->dai[j].ch_num, 0, (sizeof(u32)*
+				tabla_p->dai[j].ch_tot));
+			tabla_p->dai[j].ch_tot = 0;
+
 			if ((tabla != NULL) &&
 			    (tabla->dev != NULL) &&
 			    (tabla->dev->parent != NULL)) {
@@ -4564,7 +4629,7 @@
 	struct tabla_priv *tabla_p = snd_soc_codec_get_drvdata(codec);
 	/* index to the DAI ID, for now hardcoding */
 	u32  j = 0;
-	u32  ret = 0;
+	int  ret = 0;
 
 	codec->control_data = dev_get_drvdata(codec->dev->parent);
 	tabla = codec->control_data;
@@ -4621,13 +4686,21 @@
 			ret = wcd9xxx_close_slim_sch_tx(tabla,
 						tabla_p->dai[j].ch_num,
 						tabla_p->dai[j].ch_tot);
+			ret = tabla_codec_enable_chmask(tabla_p,
+						SND_SOC_DAPM_POST_PMD,
+						j);
+			if (ret < 0) {
+				ret = wcd9xxx_disconnect_port(tabla,
+						tabla_p->dai[j].ch_num,
+						tabla_p->dai[j].ch_tot, 0);
+				pr_info("%s: Disconnect TX port, ret = %d\n",
+					__func__, ret);
+			}
+
 			tabla_p->dai[j].rate = 0;
 			memset(tabla_p->dai[j].ch_num, 0, (sizeof(u32)*
 					tabla_p->dai[j].ch_tot));
 			tabla_p->dai[j].ch_tot = 0;
-			ret = tabla_codec_enable_chmask(tabla_p,
-							SND_SOC_DAPM_POST_PMD,
-							j);
 			if ((tabla != NULL) &&
 			    (tabla->dev != NULL) &&
 			    (tabla->dev->parent != NULL)) {
@@ -4646,9 +4719,11 @@
 	/*RX stuff */
 	SND_SOC_DAPM_OUTPUT("EAR"),
 
-	SND_SOC_DAPM_PGA("EAR PA", TABLA_A_RX_EAR_EN, 4, 0, NULL, 0),
+	SND_SOC_DAPM_PGA_E("EAR PA", SND_SOC_NOPM, 0, 0, NULL,
+			0, tabla_ear_pa_event, SND_SOC_DAPM_PRE_PMU |
+			SND_SOC_DAPM_PRE_PMD),
 
-	SND_SOC_DAPM_MIXER("DAC1", TABLA_A_RX_EAR_EN, 6, 0, dac1_switch,
+	SND_SOC_DAPM_MIXER("DAC1", SND_SOC_NOPM, 0, 0, dac1_switch,
 		ARRAY_SIZE(dac1_switch)),
 
 	/* Headphone */
@@ -5234,7 +5309,8 @@
 				    enum snd_jack_types jack_type)
 {
 	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
-
+	pr_debug("%s: enter insertion %d hph_status %x\n",
+		 __func__, insertion, tabla->hph_status);
 	if (!insertion) {
 		/* Report removal */
 		tabla->hph_status &= ~jack_type;
@@ -5269,6 +5345,18 @@
 		tabla->current_plug = PLUG_TYPE_NONE;
 		tabla->mbhc_polling_active = false;
 	} else {
+		if (tabla->mbhc_cfg.detect_extn_cable) {
+			/* Report removal of current jack type */
+			if (tabla->hph_status != jack_type &&
+			    tabla->mbhc_cfg.headset_jack) {
+				pr_debug("%s: Reporting removal (%x)\n",
+					 __func__, tabla->hph_status);
+				tabla_snd_soc_jack_report(tabla,
+						tabla->mbhc_cfg.headset_jack,
+						0, TABLA_JACK_MASK);
+				tabla->hph_status = 0;
+			}
+		}
 		/* Report insertion */
 		tabla->hph_status |= jack_type;
 
@@ -5279,7 +5367,8 @@
 		else if (jack_type == SND_JACK_HEADSET) {
 			tabla->mbhc_polling_active = true;
 			tabla->current_plug = PLUG_TYPE_HEADSET;
-		}
+		} else if (jack_type == SND_JACK_LINEOUT)
+			tabla->current_plug = PLUG_TYPE_HIGH_HPH;
 		if (tabla->mbhc_cfg.headset_jack) {
 			pr_debug("%s: Reporting insertion %d(%x)\n", __func__,
 				 jack_type, tabla->hph_status);
@@ -5290,6 +5379,7 @@
 		}
 		tabla_clr_and_turnon_hph_padac(tabla);
 	}
+	pr_debug("%s: leave hph_status %x\n", __func__, tabla->hph_status);
 }
 
 static int tabla_codec_enable_hs_detect(struct snd_soc_codec *codec,
@@ -5303,6 +5393,9 @@
 	const struct tabla_mbhc_plug_detect_cfg *plug_det =
 	    TABLA_MBHC_CAL_PLUG_DET_PTR(tabla->mbhc_cfg.calibration);
 
+	pr_debug("%s: enter insertion(%d) trigger(0x%x)\n",
+		 __func__, insertion, trigger);
+
 	if (!tabla->mbhc_cfg.calibration) {
 		pr_err("Error, no tabla calibration\n");
 		return -EINVAL;
@@ -5317,6 +5410,7 @@
 	snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
 
 	if (insertion) {
+		pr_debug("%s: setup for insertion\n", __func__);
 		tabla_codec_switch_micbias(codec, 0);
 
 		/* DAPM can manipulate PA/DAC bits concurrently */
@@ -5412,6 +5506,7 @@
 
 	wcd9xxx_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
 	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
+	pr_debug("%s: leave\n", __func__);
 	return 0;
 }
 
@@ -6223,8 +6318,10 @@
 
 	if (tabla) {
 		codec = tabla->codec;
-		if (tabla->hphlocp_cnt++ < TABLA_OCP_ATTEMPT) {
+		if ((tabla->hphlocp_cnt < TABLA_OCP_ATTEMPT) &&
+		    (!tabla->hphrocp_cnt)) {
 			pr_info("%s: retry\n", __func__);
+			tabla->hphlocp_cnt++;
 			snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
 					    0x00);
 			snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
@@ -6232,7 +6329,6 @@
 		} else {
 			wcd9xxx_disable_irq(codec->control_data,
 					  TABLA_IRQ_HPH_PA_OCPL_FAULT);
-			tabla->hphlocp_cnt = 0;
 			tabla->hph_status |= SND_JACK_OC_HPHL;
 			if (tabla->mbhc_cfg.headset_jack)
 				tabla_snd_soc_jack_report(tabla,
@@ -6256,8 +6352,10 @@
 
 	if (tabla) {
 		codec = tabla->codec;
-		if (tabla->hphrocp_cnt++ < TABLA_OCP_ATTEMPT) {
+		if ((tabla->hphrocp_cnt < TABLA_OCP_ATTEMPT) &&
+		    (!tabla->hphlocp_cnt)) {
 			pr_info("%s: retry\n", __func__);
+			tabla->hphrocp_cnt++;
 			snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
 					    0x00);
 			snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
@@ -6265,7 +6363,6 @@
 		} else {
 			wcd9xxx_disable_irq(codec->control_data,
 					  TABLA_IRQ_HPH_PA_OCPR_FAULT);
-			tabla->hphrocp_cnt = 0;
 			tabla->hph_status |= SND_JACK_OC_HPHR;
 			if (tabla->mbhc_cfg.headset_jack)
 				tabla_snd_soc_jack_report(tabla,
@@ -6314,6 +6411,9 @@
 {
 	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
 
+	pr_debug("%s: enter current_plug(%d) new_plug(%d)\n",
+		 __func__, tabla->current_plug, plug_type);
+
 	if (plug_type == PLUG_TYPE_HEADPHONE &&
 	    tabla->current_plug == PLUG_TYPE_NONE) {
 		/* Nothing was reported previously
@@ -6322,11 +6422,14 @@
 		tabla_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
 		tabla_codec_cleanup_hs_polling(codec);
 	} else if (plug_type == PLUG_TYPE_GND_MIC_SWAP) {
-		if (tabla->current_plug == PLUG_TYPE_HEADSET)
-			tabla_codec_report_plug(codec, 0, SND_JACK_HEADSET);
-		else if (tabla->current_plug == PLUG_TYPE_HEADPHONE)
-			tabla_codec_report_plug(codec, 0, SND_JACK_HEADPHONE);
-
+		if (!tabla->mbhc_cfg.detect_extn_cable) {
+			if (tabla->current_plug == PLUG_TYPE_HEADSET)
+				tabla_codec_report_plug(codec, 0,
+							SND_JACK_HEADSET);
+			else if (tabla->current_plug == PLUG_TYPE_HEADPHONE)
+				tabla_codec_report_plug(codec, 0,
+							SND_JACK_HEADPHONE);
+		}
 		tabla_codec_report_plug(codec, 1, SND_JACK_UNSUPPORTED);
 		tabla_codec_cleanup_hs_polling(codec);
 	} else if (plug_type == PLUG_TYPE_HEADSET) {
@@ -6337,19 +6440,37 @@
 		msleep(100);
 		tabla_codec_start_hs_polling(codec);
 	} else if (plug_type == PLUG_TYPE_HIGH_HPH) {
-		if (tabla->current_plug == PLUG_TYPE_NONE)
-			tabla_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
-		tabla_codec_cleanup_hs_polling(codec);
-		pr_debug("setup mic trigger for further detection\n");
-		tabla->lpi_enabled = true;
-		tabla_codec_enable_hs_detect(codec, 1,
-					     MBHC_USE_MB_TRIGGER |
-					     MBHC_USE_HPHL_TRIGGER,
-					     false);
+		if (tabla->mbhc_cfg.detect_extn_cable) {
+			/* High impedance device found. Report as LINEOUT*/
+			tabla_codec_report_plug(codec, 1, SND_JACK_LINEOUT);
+			tabla_codec_cleanup_hs_polling(codec);
+			pr_debug("%s: setup mic trigger for further detection\n",
+				 __func__);
+			tabla->lpi_enabled = true;
+			/*
+			 * Do not enable HPHL trigger. If playback is active,
+			 * it might lead to continuous false HPHL triggers
+			 */
+			tabla_codec_enable_hs_detect(codec, 1,
+						     MBHC_USE_MB_TRIGGER,
+						     false);
+		} else {
+			if (tabla->current_plug == PLUG_TYPE_NONE)
+				tabla_codec_report_plug(codec, 1,
+							SND_JACK_HEADPHONE);
+			tabla_codec_cleanup_hs_polling(codec);
+			pr_debug("setup mic trigger for further detection\n");
+			tabla->lpi_enabled = true;
+			tabla_codec_enable_hs_detect(codec, 1,
+						     MBHC_USE_MB_TRIGGER |
+						     MBHC_USE_HPHL_TRIGGER,
+						     false);
+		}
 	} else {
 		WARN(1, "Unexpected current plug_type %d, plug_type %d\n",
 		     tabla->current_plug, plug_type);
 	}
+	pr_debug("%s: leave\n", __func__);
 }
 
 /* should be called under interrupt context that hold suspend */
@@ -6409,6 +6530,8 @@
 	bool ahighv = false, highv;
 	bool gndmicswapped = false;
 
+	pr_debug("%s: enter\n", __func__);
+
 	/* make sure override is on */
 	WARN_ON(!(snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_CTL) & 0x04));
 
@@ -6518,6 +6641,7 @@
 	}
 
 	pr_debug("%s: Detected plug type %d\n", __func__, plug_type[0]);
+	pr_debug("%s: leave\n", __func__);
 	return plug_type[0];
 }
 
@@ -6527,7 +6651,7 @@
 	struct snd_soc_codec *codec;
 	int retry = 0, pt_gnd_mic_swap_cnt = 0;
 	bool correction = false;
-	enum tabla_mbhc_plug_type plug_type;
+	enum tabla_mbhc_plug_type plug_type = PLUG_TYPE_INVALID;
 	unsigned long timeout;
 
 	tabla = container_of(work, struct tabla_priv, hs_correct_plug_work);
@@ -6567,16 +6691,23 @@
 		plug_type = tabla_codec_get_plug_type(codec, true);
 		TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
 
+		pr_debug("%s: attempt(%d) current_plug(%d) new_plug(%d)\n",
+			 __func__, retry, tabla->current_plug, plug_type);
 		if (plug_type == PLUG_TYPE_INVALID) {
 			pr_debug("Invalid plug in attempt # %d\n", retry);
-			if (retry == NUM_ATTEMPTS_TO_REPORT &&
+			if (!tabla->mbhc_cfg.detect_extn_cable &&
+			    retry == NUM_ATTEMPTS_TO_REPORT &&
 			    tabla->current_plug == PLUG_TYPE_NONE) {
 				tabla_codec_report_plug(codec, 1,
 							SND_JACK_HEADPHONE);
 			}
 		} else if (plug_type == PLUG_TYPE_HEADPHONE) {
 			pr_debug("Good headphone detected, continue polling mic\n");
-			if (tabla->current_plug == PLUG_TYPE_NONE)
+			if (tabla->mbhc_cfg.detect_extn_cable) {
+				if (tabla->current_plug != plug_type)
+					tabla_codec_report_plug(codec, 1,
+							SND_JACK_HEADPHONE);
+			} else if (tabla->current_plug == PLUG_TYPE_NONE)
 				tabla_codec_report_plug(codec, 1,
 							SND_JACK_HEADPHONE);
 		} else {
@@ -6617,7 +6748,21 @@
 		tabla_turn_onoff_override(codec, false);
 
 	tabla->mbhc_cfg.mclk_cb_fn(codec, 0, false);
-	pr_debug("%s: leave\n", __func__);
+
+	if (tabla->mbhc_cfg.detect_extn_cable) {
+		TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
+		if (tabla->current_plug == PLUG_TYPE_HEADPHONE ||
+		    tabla->current_plug == PLUG_TYPE_GND_MIC_SWAP ||
+		    tabla->current_plug == PLUG_TYPE_INVALID ||
+		    plug_type == PLUG_TYPE_INVALID) {
+			/* Enable removal detection */
+			tabla_codec_cleanup_hs_polling(codec);
+			tabla_codec_enable_hs_detect(codec, 0, 0, false);
+		}
+		TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
+	}
+	pr_debug("%s: leave current_plug(%d)\n",
+		 __func__, tabla->current_plug);
 	/* unlock sleep */
 	wcd9xxx_unlock_sleep(tabla->codec->control_data);
 }
@@ -6654,6 +6799,7 @@
 			 __func__, plug_type);
 		tabla_find_plug_and_report(codec, plug_type);
 	}
+	pr_debug("%s: leave\n", __func__);
 }
 
 /* called under codec_resource_lock acquisition */
@@ -6663,7 +6809,7 @@
 	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
 	const struct tabla_mbhc_plug_detect_cfg *plug_det =
 	    TABLA_MBHC_CAL_PLUG_DET_PTR(tabla->mbhc_cfg.calibration);
-
+	pr_debug("%s: enter\n", __func__);
 	/* Turn on the override,
 	 * tabla_codec_setup_hs_polling requires override on */
 	tabla_turn_onoff_override(codec, true);
@@ -6682,6 +6828,7 @@
 				 "plug\n", __func__);
 		else
 			tabla_codec_decide_gpio_plug(codec);
+		pr_debug("%s: leave\n", __func__);
 		return;
 	}
 
@@ -6704,7 +6851,6 @@
 		pr_debug("%s: Headphone Detected\n", __func__);
 		tabla_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
 		tabla_codec_cleanup_hs_polling(codec);
-		tabla_codec_enable_hs_detect(codec, 0, 0, false);
 		tabla_schedule_hs_detect_plug(tabla,
 					&tabla->hs_correct_plug_work_nogpio);
 	} else if (plug_type == PLUG_TYPE_HEADSET) {
@@ -6714,13 +6860,23 @@
 		/* avoid false button press detect */
 		msleep(50);
 		tabla_codec_start_hs_polling(codec);
+	} else if (tabla->mbhc_cfg.detect_extn_cable &&
+		   plug_type == PLUG_TYPE_HIGH_HPH) {
+		pr_debug("%s: High impedance plug type detected\n", __func__);
+		tabla_codec_report_plug(codec, 1, SND_JACK_LINEOUT);
+		/* Enable insertion detection on the other end of cable */
+		tabla_codec_cleanup_hs_polling(codec);
+		tabla_codec_enable_hs_detect(codec, 1,
+					     MBHC_USE_MB_TRIGGER, false);
 	}
+	pr_debug("%s: leave\n", __func__);
 }
 
 /* called only from interrupt which is under codec_resource_lock acquisition */
 static void tabla_hs_insert_irq_gpio(struct tabla_priv *priv, bool is_removal)
 {
 	struct snd_soc_codec *codec = priv->codec;
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
 
 	if (!is_removal) {
 		pr_debug("%s: MIC trigger insertion interrupt\n", __func__);
@@ -6741,6 +6897,19 @@
 			pr_debug("%s: Invalid insertion, "
 				 "stop plug detection\n", __func__);
 		}
+	} else if (tabla->mbhc_cfg.detect_extn_cable) {
+		pr_debug("%s: Removal\n", __func__);
+		if (!tabla_hs_gpio_level_remove(tabla)) {
+			/*
+			 * gpio says, something is still inserted, could be
+			 * extension cable i.e. headset is removed from
+			 * extension cable
+			 */
+			/* cancel detect plug */
+			tabla_cancel_hs_detect_plug(tabla,
+						&tabla->hs_correct_plug_work);
+			tabla_codec_decide_gpio_plug(codec);
+		}
 	} else {
 		pr_err("%s: GPIO used, invalid MBHC Removal\n", __func__);
 	}
@@ -6806,6 +6975,29 @@
 	}
 }
 
+/* called only from interrupt which is under codec_resource_lock acquisition */
+static void tabla_hs_insert_irq_extn(struct tabla_priv *priv,
+				     bool is_mb_trigger)
+{
+	struct snd_soc_codec *codec = priv->codec;
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+
+	/* Cancel possibly running hs_detect_work */
+	tabla_cancel_hs_detect_plug(tabla,
+			&tabla->hs_correct_plug_work);
+
+	if (is_mb_trigger) {
+		pr_debug("%s: Waiting for Headphone left trigger\n",
+			__func__);
+		tabla_codec_enable_hs_detect(codec, 1, MBHC_USE_HPHL_TRIGGER,
+					     false);
+	} else  {
+		pr_debug("%s: HPHL trigger received, detecting plug type\n",
+			__func__);
+		tabla_codec_detect_plug_type(codec);
+	}
+}
+
 static irqreturn_t tabla_hs_insert_irq(int irq, void *data)
 {
 	bool is_mb_trigger, is_removal;
@@ -6826,7 +7018,10 @@
 	snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
 	snd_soc_update_bits(codec, priv->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
 
-	if (priv->mbhc_cfg.gpio)
+	if (priv->mbhc_cfg.detect_extn_cable &&
+	    priv->current_plug == PLUG_TYPE_HIGH_HPH)
+		tabla_hs_insert_irq_extn(priv, is_mb_trigger);
+	else if (priv->mbhc_cfg.gpio)
 		tabla_hs_insert_irq_gpio(priv, is_removal);
 	else
 		tabla_hs_insert_irq_nogpio(priv, is_removal, is_mb_trigger);
@@ -6930,10 +7125,10 @@
 static void tabla_hs_remove_irq_gpio(struct tabla_priv *priv)
 {
 	struct snd_soc_codec *codec = priv->codec;
-
+	pr_debug("%s: enter\n", __func__);
 	if (tabla_hs_remove_settle(codec))
 		tabla_codec_start_hs_polling(codec);
-	pr_debug("%s: remove settle done\n", __func__);
+	pr_debug("%s: leave\n", __func__);
 }
 
 /* called only from interrupt which is under codec_resource_lock acquisition */
@@ -6946,6 +7141,7 @@
 	    TABLA_MBHC_CAL_GENERAL_PTR(priv->mbhc_cfg.calibration);
 	int min_us = TABLA_FAKE_REMOVAL_MIN_PERIOD_MS * 1000;
 
+	pr_debug("%s: enter\n", __func__);
 	if (priv->current_plug != PLUG_TYPE_HEADSET) {
 		pr_debug("%s(): Headset is not inserted, ignore removal\n",
 			 __func__);
@@ -6973,25 +7169,41 @@
 	} while (min_us > 0);
 
 	if (removed) {
-		/* Cancel possibly running hs_detect_work */
-		tabla_cancel_hs_detect_plug(priv,
+		if (priv->mbhc_cfg.detect_extn_cable) {
+			if (!tabla_hs_gpio_level_remove(priv)) {
+				/*
+				 * extension cable is still plugged in
+				 * report it as LINEOUT device
+				 */
+				tabla_codec_report_plug(codec, 1,
+							SND_JACK_LINEOUT);
+				tabla_codec_cleanup_hs_polling(codec);
+				tabla_codec_enable_hs_detect(codec, 1,
+							MBHC_USE_MB_TRIGGER,
+							false);
+			}
+		} else {
+			/* Cancel possibly running hs_detect_work */
+			tabla_cancel_hs_detect_plug(priv,
 					&priv->hs_correct_plug_work_nogpio);
-		/*
-		 * If this removal is not false, first check the micbias
-		 * switch status and switch it to LDOH if it is already
-		 * switched to VDDIO.
-		 */
-		tabla_codec_switch_micbias(codec, 0);
+			/*
+			 * If this removal is not false, first check the micbias
+			 * switch status and switch it to LDOH if it is already
+			 * switched to VDDIO.
+			 */
+			tabla_codec_switch_micbias(codec, 0);
 
-		tabla_codec_report_plug(codec, 0, SND_JACK_HEADSET);
-		tabla_codec_cleanup_hs_polling(codec);
-		tabla_codec_enable_hs_detect(codec, 1,
-					     MBHC_USE_MB_TRIGGER |
-					     MBHC_USE_HPHL_TRIGGER,
-					     true);
+			tabla_codec_report_plug(codec, 0, SND_JACK_HEADSET);
+			tabla_codec_cleanup_hs_polling(codec);
+			tabla_codec_enable_hs_detect(codec, 1,
+						     MBHC_USE_MB_TRIGGER |
+						     MBHC_USE_HPHL_TRIGGER,
+						     true);
+		}
 	} else {
 		tabla_codec_start_hs_polling(codec);
 	}
+	pr_debug("%s: leave\n", __func__);
 }
 
 static irqreturn_t tabla_hs_remove_irq(int irq, void *data)
@@ -7006,10 +7218,12 @@
 	if (vddio)
 		__tabla_codec_switch_micbias(priv->codec, 0, false, true);
 
-	if (priv->mbhc_cfg.gpio)
-		tabla_hs_remove_irq_gpio(priv);
-	else
+	if ((priv->mbhc_cfg.detect_extn_cable &&
+	     !tabla_hs_gpio_level_remove(priv)) ||
+	    !priv->mbhc_cfg.gpio) {
 		tabla_hs_remove_irq_nogpio(priv);
+	} else
+		tabla_hs_remove_irq_gpio(priv);
 
 	/* if driver turned off vddio switch and headset is not removed,
 	 * turn on the vddio switch back, if headset is removed then vddio
@@ -7097,6 +7311,9 @@
 			tabla_codec_cleanup_hs_polling(codec);
 			tabla_codec_report_plug(codec, 0, SND_JACK_HEADSET);
 			is_removed = true;
+		} else if (tabla->current_plug == PLUG_TYPE_HIGH_HPH) {
+			tabla_codec_report_plug(codec, 0, SND_JACK_LINEOUT);
+			is_removed = true;
 		}
 
 		if (is_removed) {
@@ -7207,6 +7424,8 @@
 	 */
 	tabla->mbhc_cfg.mclk_cb_fn(codec, 0, false);
 	if (!is_headset) {
+		pr_debug("%s: Inserted headphone is not a headset\n",
+			__func__);
 		tabla_turn_onoff_override(codec, false);
 		tabla_codec_cleanup_hs_polling(codec);
 		tabla_codec_enable_hs_detect(codec, 0, 0, false);
@@ -7777,9 +7996,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/wcd9310.h b/sound/soc/codecs/wcd9310.h
index 1cca360..4c9f8b4 100644
--- a/sound/soc/codecs/wcd9310.h
+++ b/sound/soc/codecs/wcd9310.h
@@ -176,6 +176,7 @@
 	unsigned int gpio;
 	unsigned int gpio_irq;
 	int gpio_level_insert;
+	bool detect_extn_cable;
 	/* swap_gnd_mic returns true if extern GND/MIC swap switch toggled */
 	bool (*swap_gnd_mic) (struct snd_soc_codec *);
 };
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 01820eb..136024c 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -390,35 +390,60 @@
 	TAIKO_A_CDC_TX10_VOL_CTL_GAIN,
 };
 
-static int taiko_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
+static int taiko_codec_enable_class_h_clk(struct snd_soc_dapm_widget *w,
 		struct snd_kcontrol *kcontrol, int event)
 {
 	struct snd_soc_codec *codec = w->codec;
 
-	pr_debug("%s %d\n", __func__, event);
+	pr_debug("%s %s  %d\n", __func__, w->name, event);
 
-	 /* FIX . need to use CLASS-H controller */
 	switch (event) {
-	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_OTHR_CTL, 0x01,
-			0x01);
-		usleep_range(200, 200);
-		snd_soc_update_bits(codec, TAIKO_A_NCP_STATIC, 0x10, 0x00);
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec, TAIKO_A_CDC_CLSH_B1_CTL, 0x01, 0x01);
 		break;
 	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_OTHR_RESET_B1_CTL,
-				0x01, 0x01);
-		usleep_range(20, 20);
-		snd_soc_update_bits(codec, TAIKO_A_NCP_STATIC, 0x08, 0x08);
-		snd_soc_update_bits(codec, TAIKO_A_NCP_STATIC, 0x10, 0x10);
-		snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_OTHR_CTL, 0x01,
-			0x00);
-		snd_soc_update_bits(codec, TAIKO_A_NCP_STATIC, 0x08, 0x00);
+		snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_1, 0x80, 0x00);
+		snd_soc_update_bits(codec, TAIKO_A_CDC_CLSH_B1_CTL, 0x01, 0x00);
 		break;
 	}
 	return 0;
 }
 
+static int taiko_codec_enable_class_h(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+
+	pr_debug("%s %s  %d\n", __func__, w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_5, 0x02, 0x02);
+		snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_4, 0xFF, 0xFF);
+		snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_1, 0x04, 0x04);
+		snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_3, 0x04, 0x00);
+		snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_3, 0x08, 0x00);
+		snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_1, 0x80, 0x80);
+		usleep_range(1000, 1000);
+		break;
+	}
+	return 0;
+}
+
+static int taiko_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	pr_debug("%s %s %d\n", __func__, w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		usleep_range(1000, 1000);
+		break;
+	}
+	return 0;
+}
+
+
 static int taiko_get_anc_slot(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
@@ -2766,7 +2791,7 @@
 	struct snd_soc_codec *codec = w->codec;
 	struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
 	u8 mbhc_micb_ctl_val;
-	pr_debug("%s: event = %d\n", __func__, event);
+	pr_debug("%s: %s event = %d\n", __func__, w->name, event);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
@@ -2780,6 +2805,19 @@
 		}
 		break;
 
+	case SND_SOC_DAPM_POST_PMU:
+
+		usleep_range(10000, 10000);
+
+		snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_5, 0x02, 0x00);
+		snd_soc_update_bits(codec, TAIKO_A_NCP_STATIC, 0x20, 0x00);
+		snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_3, 0x04, 0x04);
+		snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_3, 0x08, 0x00);
+
+		usleep_range(10, 10);
+
+		break;
+
 	case SND_SOC_DAPM_POST_PMD:
 		/* schedule work is required because at the time HPH PA DAPM
 		 * event callback is called by DAPM framework, CODEC dapm mutex
@@ -3012,6 +3050,8 @@
 	{"EAR PA", NULL, "EAR_PA_MIXER"},
 	{"EAR_PA_MIXER", NULL, "DAC1"},
 	{"DAC1", NULL, "CP"},
+	{"CP", NULL, "CLASS_H_EAR"},
+	{"CLASS_H_EAR", NULL, "CLASS_H_CLK"},
 
 	{"ANC1 FB MUX", "EAR_HPH_L", "RX1 MIX2"},
 	{"ANC1 FB MUX", "EAR_LINE_1", "RX2 MIX2"},
@@ -3028,7 +3068,12 @@
 	{"HPHR_PA_MIXER", NULL, "HPHR DAC"},
 
 	{"HPHL DAC", NULL, "CP"},
+	{"CP", NULL, "CLASS_H_HPH_L"},
+	{"CLASS_H_HPH_L", NULL, "CLASS_H_CLK"},
+
 	{"HPHR DAC", NULL, "CP"},
+	{"CP", NULL, "CLASS_H_HPH_R"},
+	{"CLASS_H_HPH_R", NULL, "CLASS_H_CLK"},
 
 	{"ANC", NULL, "ANC1 MUX"},
 	{"ANC", NULL, "ANC2 MUX"},
@@ -3082,7 +3127,7 @@
 	{"RX1 CHAIN", NULL, "ANC"},
 	{"RX2 CHAIN", NULL, "ANC"},
 
-	{"CP", NULL, "RX_BIAS"},
+	{"CLASS_H_CLK", NULL, "RX_BIAS"},
 	{"LINEOUT1 DAC", NULL, "RX_BIAS"},
 	{"LINEOUT2 DAC", NULL, "RX_BIAS"},
 	{"LINEOUT3 DAC", NULL, "RX_BIAS"},
@@ -3094,7 +3139,6 @@
 	{"RX3 MIX1", NULL, "COMP2_CLK"},
 	{"RX5 MIX1", NULL, "COMP2_CLK"},
 
-
 	{"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
 	{"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
 	{"RX1 MIX1", NULL, "RX1 MIX1 INP3"},
@@ -3295,38 +3339,16 @@
 	{"ADC6", NULL, "AMIC6"},
 
 	/* AUX PGA Connections */
-	{"HPHL_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
-	{"HPHL_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
-	{"HPHL_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
-	{"HPHL_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
-	{"HPHR_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
-	{"HPHR_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
-	{"HPHR_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
-	{"HPHR_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
-	{"LINEOUT1_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
-	{"LINEOUT1_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
-	{"LINEOUT1_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
-	{"LINEOUT1_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
-	{"LINEOUT2_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
-	{"LINEOUT2_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
-	{"LINEOUT2_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
-	{"LINEOUT2_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
-	{"LINEOUT3_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
-	{"LINEOUT3_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
-	{"LINEOUT3_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
-	{"LINEOUT3_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
-	{"LINEOUT4_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
-	{"LINEOUT4_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
-	{"LINEOUT4_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
-	{"LINEOUT4_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
 	{"EAR_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
-	{"EAR_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
-	{"EAR_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
-	{"EAR_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
+	{"HPHL_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
+	{"HPHR_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
+	{"LINEOUT1_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
+	{"LINEOUT2_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
+	{"LINEOUT3_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
+	{"LINEOUT4_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
 	{"AUX_PGA_Left", NULL, "AMIC5"},
 	{"AUX_PGA_Right", NULL, "AMIC6"},
 
-
 	{"IIR1", NULL, "IIR1 INP1 MUX"},
 	{"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
 	{"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
@@ -4153,6 +4175,28 @@
 	return ret;
 }
 
+static int taiko_codec_enable_ear_pa(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+
+	pr_debug("%s %s %d\n", __func__, w->name, event);
+
+	switch (event) {
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+
+		snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_5, 0x02, 0x00);
+		snd_soc_update_bits(codec, TAIKO_A_NCP_STATIC, 0x20, 0x00);
+		snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_3, 0x04, 0x04);
+		snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_3, 0x08, 0x00);
+
+		usleep_range(5000, 5000);
+		break;
+	}
+	return 0;
+}
+
 /* Todo: Have seperate dapm widgets for I2S and Slimbus.
  * Might Need to have callbacks registered only for slimbus
  */
@@ -4160,7 +4204,8 @@
 	/*RX stuff */
 	SND_SOC_DAPM_OUTPUT("EAR"),
 
-	SND_SOC_DAPM_PGA("EAR PA", TAIKO_A_RX_EAR_EN, 4, 0, NULL, 0),
+	SND_SOC_DAPM_PGA_E("EAR PA", TAIKO_A_RX_EAR_EN, 4, 0, NULL, 0,
+			taiko_codec_enable_ear_pa, SND_SOC_DAPM_POST_PMU),
 
 	SND_SOC_DAPM_MIXER("DAC1", TAIKO_A_RX_EAR_EN, 6, 0, dac1_switch,
 		ARRAY_SIZE(dac1_switch)),
@@ -4193,13 +4238,13 @@
 	SND_SOC_DAPM_OUTPUT("HEADPHONE"),
 	SND_SOC_DAPM_PGA_E("HPHL", TAIKO_A_RX_HPH_CNP_EN, 5, 0, NULL, 0,
 		taiko_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
-			SND_SOC_DAPM_POST_PMD),
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
 	SND_SOC_DAPM_MIXER("HPHL DAC", TAIKO_A_RX_HPH_L_DAC_CTL, 7, 0,
 		hphl_switch, ARRAY_SIZE(hphl_switch)),
 
 	SND_SOC_DAPM_PGA_E("HPHR", TAIKO_A_RX_HPH_CNP_EN, 4, 0, NULL, 0,
 		taiko_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
-			SND_SOC_DAPM_POST_PMD),
+		SND_SOC_DAPM_POST_PMU |	SND_SOC_DAPM_POST_PMD),
 
 	SND_SOC_DAPM_DAC_E("HPHR DAC", NULL, TAIKO_A_RX_HPH_R_DAC_CTL, 7, 0,
 		taiko_hphr_dac_event,
@@ -4329,10 +4374,23 @@
 	SND_SOC_DAPM_MUX("RX7 MIX2 INP2", SND_SOC_NOPM, 0, 0,
 		&rx7_mix2_inp2_mux),
 
-	SND_SOC_DAPM_SUPPLY("CP", TAIKO_A_NCP_EN, 0, 0,
-		taiko_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
+	SND_SOC_DAPM_SUPPLY("CLASS_H_CLK", TAIKO_A_CDC_CLK_OTHR_CTL, 0, 0,
+		taiko_codec_enable_class_h_clk, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_PRE_PMD),
 
+	SND_SOC_DAPM_SUPPLY("CLASS_H_EAR", TAIKO_A_CDC_CLSH_B1_CTL, 4, 0,
+		taiko_codec_enable_class_h, SND_SOC_DAPM_POST_PMU),
+
+	SND_SOC_DAPM_SUPPLY("CLASS_H_HPH_R", TAIKO_A_CDC_CLSH_B1_CTL, 3, 0,
+		taiko_codec_enable_class_h, SND_SOC_DAPM_POST_PMU),
+
+	SND_SOC_DAPM_SUPPLY("CLASS_H_HPH_L", TAIKO_A_CDC_CLSH_B1_CTL, 2, 0,
+		taiko_codec_enable_class_h, SND_SOC_DAPM_POST_PMU),
+
+	SND_SOC_DAPM_SUPPLY("CP", TAIKO_A_NCP_EN, 0, 0,
+		taiko_codec_enable_charge_pump, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
 	SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
 		taiko_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMD),
@@ -6812,6 +6870,85 @@
 	return IRQ_HANDLED;
 }
 
+static const struct taiko_reg_mask_val taiko_1_0_class_h_ear[] = {
+
+	/* CLASS-H EAR  IDLE_THRESHOLD Table */
+	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_IDLE_EAR_THSD, 0x26),
+	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_FCLKONLY_EAR_THSD, 0x2C),
+
+	/* CLASS-H EAR I_PA_FACT Table. */
+	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_I_PA_FACT_EAR_L,	0xA9),
+	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_I_PA_FACT_EAR_U, 0x07),
+
+	/* CLASS-H EAR Voltage Headroom , Voltage Min. */
+	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_V_PA_HD_EAR, 0x0D),
+	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_V_PA_MIN_EAR, 0x3A),
+
+	/* CLASS-H EAR K values --chnages from load. */
+	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_ADDR, 0x08),
+	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x1B),
+	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x00),
+	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x2D),
+	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x00),
+	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x36),
+	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x00),
+	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x37),
+	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x00),
+	/** end of Ear PA load 32 */
+};
+
+
+static const struct taiko_reg_mask_val taiko_1_0_class_h_hph[] = {
+
+	/* CLASS-H HPH  IDLE_THRESHOLD Table */
+	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_IDLE_HPH_THSD, 0x13),
+	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0x19),
+
+	/* CLASS-H HPH I_PA_FACT Table */
+	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_I_PA_FACT_HPH_L,	0x9A),
+	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_I_PA_FACT_HPH_U, 0x06),
+
+	/* CLASS-H HPH Voltage Headroom , Voltage Min */
+	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_V_PA_HD_HPH, 0x0D),
+	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_V_PA_MIN_HPH, 0x1D),
+
+	/* CLASS-H HPH K values --chnages from load .*/
+	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_ADDR, 0x00),
+	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0xAE),
+	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x01),
+	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x1C),
+	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x00),
+	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x25),
+	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x00),
+	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x27),
+	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x00),
+};
+
+static int taiko_config_ear_class_h(struct snd_soc_codec *codec, u32 ear_load)
+{
+	u32 i;
+
+	if (ear_load  != 32)
+		return -EINVAL;
+
+	for (i = 0; i < ARRAY_SIZE(taiko_1_0_class_h_ear); i++)
+		snd_soc_write(codec, taiko_1_0_class_h_ear[i].reg,
+				taiko_1_0_class_h_ear[i].val);
+	return 0;
+}
+
+static int taiko_config_hph_class_h(struct snd_soc_codec *codec, u32 hph_load)
+{
+	u32 i;
+	if (hph_load  != 16)
+		return -EINVAL;
+
+	for (i = 0; i < ARRAY_SIZE(taiko_1_0_class_h_hph); i++)
+		snd_soc_write(codec, taiko_1_0_class_h_hph[i].reg,
+				taiko_1_0_class_h_hph[i].val);
+	return 0;
+}
+
 static int taiko_handle_pdata(struct taiko_priv *taiko)
 {
 	struct snd_soc_codec *codec = taiko->codec;
@@ -6943,28 +7080,48 @@
 			break;
 		}
 	}
+
+	taiko_config_ear_class_h(codec, 32);
+	taiko_config_hph_class_h(codec, 16);
+
 done:
 	return rc;
 }
 
 static const struct taiko_reg_mask_val taiko_1_0_reg_defaults[] = {
 
-	/* Taiko 1.1 MICBIAS changes */
-	TAIKO_REG_VAL(TAIKO_A_MICB_1_INT_RBIAS, 0x24),
-	TAIKO_REG_VAL(TAIKO_A_MICB_2_INT_RBIAS, 0x24),
-	TAIKO_REG_VAL(TAIKO_A_MICB_3_INT_RBIAS, 0x24),
+	/* set MCLk to 9.6 */
+	TAIKO_REG_VAL(TAIKO_A_CHIP_CTL, 0x0A),
+	TAIKO_REG_VAL(TAIKO_A_CDC_CLK_POWER_CTL, 0x03),
 
-	/* Taiko 1.1 HPH changes */
-	TAIKO_REG_VAL(TAIKO_A_RX_HPH_BIAS_PA, 0x57),
-	TAIKO_REG_VAL(TAIKO_A_RX_HPH_BIAS_LDO, 0x56),
+	/* EAR PA deafults  */
+	TAIKO_REG_VAL(TAIKO_A_RX_EAR_CMBUFF, 0x05),
+	/* HPH PA */
+	TAIKO_REG_VAL(TAIKO_A_RX_HPH_BIAS_PA, 0x7A),
 
-	/* Taiko 1.1 EAR PA changes */
-	TAIKO_REG_VAL(TAIKO_A_RX_EAR_BIAS_PA, 0xA6),
-	TAIKO_REG_VAL(TAIKO_A_RX_EAR_GAIN, 0x02),
-	TAIKO_REG_VAL(TAIKO_A_RX_EAR_VCM, 0x03),
+	/** BUCK and NCP defaults for EAR and HS */
+	TAIKO_REG_VAL(TAIKO_A_BUCK_CTRL_CCL_4, 0x50),
+	TAIKO_REG_VAL(TAIKO_A_BUCK_CTRL_VCL_1, 0x08),
+	TAIKO_REG_VAL(TAIKO_A_BUCK_CTRL_CCL_1, 0x5B),
+	TAIKO_REG_VAL(TAIKO_A_NCP_CLK, 0xFC),
+
+	/* CLASS-H defaults for EAR and HS */
+	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_BUCK_NCP_VARS, 0x00),
+	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_BUCK_NCP_VARS, 0x04),
+	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_B2_CTL, 0x01),
+	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_B2_CTL, 0x05),
+	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_B2_CTL, 0x35),
+	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_B3_CTL, 0x30),
+	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_B3_CTL, 0x3B),
+
+	/*
+	 * For CLASS-H, Enable ANC delay buffer,
+	 * set HPHL and EAR PA ref gain to 0 DB.
+	 */
+	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_B1_CTL, 0x26),
 
 
-	/* Taiko 1.1 RX Changes */
+	/* RX deafults */
 	TAIKO_REG_VAL(TAIKO_A_CDC_RX1_B5_CTL, 0x78),
 	TAIKO_REG_VAL(TAIKO_A_CDC_RX2_B5_CTL, 0x78),
 	TAIKO_REG_VAL(TAIKO_A_CDC_RX3_B5_CTL, 0x78),
@@ -6973,17 +7130,16 @@
 	TAIKO_REG_VAL(TAIKO_A_CDC_RX6_B5_CTL, 0x78),
 	TAIKO_REG_VAL(TAIKO_A_CDC_RX7_B5_CTL, 0x78),
 
-	/* Taiko 1.1 RX1 and RX2 Changes */
+	/* RX1 and RX2 defaults */
 	TAIKO_REG_VAL(TAIKO_A_CDC_RX1_B6_CTL, 0xA0),
 	TAIKO_REG_VAL(TAIKO_A_CDC_RX2_B6_CTL, 0xA0),
 
-	/* Taiko 1.1 RX3 to RX7 Changes */
+	/* RX3 to RX7 defaults */
 	TAIKO_REG_VAL(TAIKO_A_CDC_RX3_B6_CTL, 0x80),
 	TAIKO_REG_VAL(TAIKO_A_CDC_RX4_B6_CTL, 0x80),
 	TAIKO_REG_VAL(TAIKO_A_CDC_RX5_B6_CTL, 0x80),
 	TAIKO_REG_VAL(TAIKO_A_CDC_RX6_B6_CTL, 0x80),
 	TAIKO_REG_VAL(TAIKO_A_CDC_RX7_B6_CTL, 0x80),
-
 };
 
 static void taiko_update_reg_defaults(struct snd_soc_codec *codec)
@@ -7002,21 +7158,16 @@
 	{TAIKO_A_RX_HPH_OCP_CTL, 0xE0, 0x60},
 	{TAIKO_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
 
-	{TAIKO_A_QFUSE_CTL, 0xFF, 0x03},
-
 	/* Initialize gain registers to use register gain */
-	{TAIKO_A_RX_HPH_L_GAIN, 0x10, 0x10},
-	{TAIKO_A_RX_HPH_R_GAIN, 0x10, 0x10},
-	{TAIKO_A_RX_LINE_1_GAIN, 0x10, 0x10},
-	{TAIKO_A_RX_LINE_2_GAIN, 0x10, 0x10},
-	{TAIKO_A_RX_LINE_3_GAIN, 0x10, 0x10},
-	{TAIKO_A_RX_LINE_4_GAIN, 0x10, 0x10},
+	{TAIKO_A_RX_HPH_L_GAIN, 0x20, 0x20},
+	{TAIKO_A_RX_HPH_R_GAIN, 0x20, 0x20},
+	{TAIKO_A_RX_LINE_1_GAIN, 0x20, 0x20},
+	{TAIKO_A_RX_LINE_2_GAIN, 0x20, 0x20},
+	{TAIKO_A_RX_LINE_3_GAIN, 0x20, 0x20},
+	{TAIKO_A_RX_LINE_4_GAIN, 0x20, 0x20},
 
-	/* Initialize mic biases to differential mode */
-	{TAIKO_A_MICB_1_INT_RBIAS, 0x24, 0x24},
-	{TAIKO_A_MICB_2_INT_RBIAS, 0x24, 0x24},
-	{TAIKO_A_MICB_3_INT_RBIAS, 0x24, 0x24},
-
+	/* CLASS H config */
+	{TAIKO_A_CDC_CONN_CLSH_CTL, 0x3C, 0x14},
 
 	/* Use 16 bit sample size for TX1 to TX6 */
 	{TAIKO_A_CDC_CONN_TX_SB_B1_CTL, 0x30, 0x20},
@@ -7048,21 +7199,22 @@
 	{TAIKO_A_CDC_TX9_MUX_CTL, 0x8, 0x0},
 	{TAIKO_A_CDC_TX10_MUX_CTL, 0x8, 0x0},
 
-	/* config Decimator for DMIC CLK_MODE_1(4.8Mhz@9.6Mhz mclk) */
-	{TAIKO_A_CDC_TX1_DMIC_CTL, 0x7, 0x0},
-	{TAIKO_A_CDC_TX2_DMIC_CTL, 0x7, 0x0},
-	{TAIKO_A_CDC_TX3_DMIC_CTL, 0x7, 0x0},
-	{TAIKO_A_CDC_TX4_DMIC_CTL, 0x7, 0x0},
-	{TAIKO_A_CDC_TX5_DMIC_CTL, 0x7, 0x0},
-	{TAIKO_A_CDC_TX6_DMIC_CTL, 0x7, 0x0},
-	{TAIKO_A_CDC_TX7_DMIC_CTL, 0x7, 0x0},
-	{TAIKO_A_CDC_TX8_DMIC_CTL, 0x7, 0x0},
-	{TAIKO_A_CDC_TX9_DMIC_CTL, 0x7, 0x0},
-	{TAIKO_A_CDC_TX10_DMIC_CTL, 0x7, 0x0},
+	/* config Decimator for DMIC CLK_MODE_1(3.2Mhz@9.6Mhz mclk) */
+	{TAIKO_A_CDC_TX1_DMIC_CTL, 0x7, 0x1},
+	{TAIKO_A_CDC_TX2_DMIC_CTL, 0x7, 0x1},
+	{TAIKO_A_CDC_TX3_DMIC_CTL, 0x7, 0x1},
+	{TAIKO_A_CDC_TX4_DMIC_CTL, 0x7, 0x1},
+	{TAIKO_A_CDC_TX5_DMIC_CTL, 0x7, 0x1},
+	{TAIKO_A_CDC_TX6_DMIC_CTL, 0x7, 0x1},
+	{TAIKO_A_CDC_TX7_DMIC_CTL, 0x7, 0x1},
+	{TAIKO_A_CDC_TX8_DMIC_CTL, 0x7, 0x1},
+	{TAIKO_A_CDC_TX9_DMIC_CTL, 0x7, 0x1},
+	{TAIKO_A_CDC_TX10_DMIC_CTL, 0x7, 0x1},
 
-	/* config DMIC clk to CLK_MODE_1 (4.8Mhz@9.6Mhz mclk) */
-	{TAIKO_A_CDC_CLK_DMIC_B1_CTL, 0xEE, 0x0},
-	{TAIKO_A_CDC_CLK_DMIC_B2_CTL, 0xEE, 0x0},
+	/* config DMIC clk to CLK_MODE_1 (3.2Mhz@9.6Mhz mclk) */
+	{TAIKO_A_CDC_CLK_DMIC_B1_CTL, 0xEE, 0x22},
+	{TAIKO_A_CDC_CLK_DMIC_B2_CTL, 0x0E, 0x02},
+
 };
 
 static void taiko_codec_init_reg(struct snd_soc_codec *codec)
@@ -7297,10 +7449,11 @@
 	int i;
 	int ch_cnt;
 
-
 	codec->control_data = dev_get_drvdata(codec->dev->parent);
 	control = codec->control_data;
 
+	dev_info(codec->dev, "%s()\n", __func__);
+
 	taiko = kzalloc(sizeof(struct taiko_priv), GFP_KERNEL);
 	if (!taiko) {
 		dev_err(codec->dev, "Failed to allocate private data\n");
diff --git a/sound/soc/msm/Makefile b/sound/soc/msm/Makefile
index 43c678d..99302eb 100644
--- a/sound/soc/msm/Makefile
+++ b/sound/soc/msm/Makefile
@@ -56,13 +56,13 @@
 
 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
 obj-$(CONFIG_SND_SOC_QDSP6) += snd-soc-qdsp6.o
 
-snd-soc-msm8960-objs := msm8960.o apq8064.o msm8930.o mpq8064.o
+snd-soc-msm8960-objs := msm8960.o apq8064.o msm8930.o mpq8064.o apq8064-i2s.o
 obj-$(CONFIG_SND_SOC_MSM8960) += snd-soc-msm8960.o
 
 # Generic MSM drivers
diff --git a/sound/soc/msm/apq8064-i2s.c b/sound/soc/msm/apq8064-i2s.c
new file mode 100644
index 0000000..162f39d
--- /dev/null
+++ b/sound/soc/msm/apq8064-i2s.c
@@ -0,0 +1,2808 @@
+/* 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/delay.h>
+#include <linux/gpio.h>
+#include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+#include <linux/slimbus/slimbus.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/jack.h>
+#include <asm/mach-types.h>
+#include <mach/socinfo.h>
+#include "msm-pcm-routing.h"
+#include "../codecs/wcd9310.h"
+
+/* 8064 machine driver */
+
+#define PM8921_GPIO_BASE		NR_GPIO_IRQS
+#define PM8921_GPIO_PM_TO_SYS(pm_gpio)  (pm_gpio - 1 + PM8921_GPIO_BASE)
+
+#define MSM8064_SPK_ON 1
+#define MSM8064_SPK_OFF 0
+
+#define MSM_SLIM_0_RX_MAX_CHANNELS		2
+#define MSM_SLIM_0_TX_MAX_CHANNELS		4
+
+#define BTSCO_RATE_8KHZ 8000
+#define BTSCO_RATE_16KHZ 16000
+
+#define BOTTOM_SPK_AMP_POS	0x1
+#define BOTTOM_SPK_AMP_NEG	0x2
+#define TOP_SPK_AMP_POS		0x4
+#define TOP_SPK_AMP_NEG		0x8
+#define TOP_SPK_AMP		0x10
+
+
+#define GPIO_AUX_PCM_DOUT 43
+#define GPIO_AUX_PCM_DIN 44
+#define GPIO_AUX_PCM_SYNC 45
+#define GPIO_AUX_PCM_CLK 46
+
+#define TABLA_EXT_CLK_RATE 12288000
+
+#define TABLA_MBHC_DEF_BUTTONS 8
+#define TABLA_MBHC_DEF_RLOADS 5
+
+#define JACK_DETECT_GPIO 38
+
+#define APQ_I2S_SLAVE_CONFIG	0
+/* MCLK selection GPIOs from PMIC */
+#define PM_GPIO_MCLK_MDM	10
+#define PM_GPIO_MCLK_APQ	41
+
+/* SPKR I2S Configuration */
+#define GPIO_SPKR_I2S_MCLK  39
+#define GPIO_SPKR_I2S_SCK   40
+#define GPIO_SPKR_I2S_DOUT  41
+#define GPIO_SPKR_I2S_WS    42
+
+/* MIC I2S Configuration */
+#define GPIO_MIC_I2S_MCLK	34
+#define GPIO_MIC_I2S_SCK	35
+#define GPIO_MIC_I2S_WS		36
+#define GPIO_MIC_I2S_DIN0	37
+#define GPIO_MIC_I2S_DIN1   38
+
+/* MI2S Configuration */
+#define GPIO_MI2S_WS    27
+#define GPIO_MI2S_SCK   28
+#define GPIO_MI2S_SD3   29
+#define GPIO_MI2S_SD2   30
+#define GPIO_MI2S_SD1   31
+#define GPIO_MI2S_SD0   32
+#define GPIO_MI2S_MCLK  33
+
+struct request_gpio {
+	unsigned gpio_no;
+	char *gpio_name;
+};
+/* SD0 as RX and SD3 as TX. SD1 and SD2 are unused */
+static struct request_gpio mi2s_gpio[] = {
+	{
+		.gpio_no = GPIO_MI2S_WS,
+		.gpio_name = "MI2S_WS",
+	},
+	{
+		.gpio_no = GPIO_MI2S_SCK,
+		.gpio_name = "MI2S_SCK",
+	},
+	{
+		.gpio_no = GPIO_MI2S_SD3,
+		.gpio_name = "MI2S_SD3",
+	},
+	{
+		.gpio_no = GPIO_MI2S_SD0,
+		.gpio_name = "MI2S_SD0",
+	},
+	{
+		.gpio_no = GPIO_MI2S_MCLK,
+		.gpio_name = "MI2S_MCLK",
+	},
+};
+
+/* I2S RX is slave so MCLK is not needed */
+static struct request_gpio spkr_i2s_gpio[] = {
+	{
+		.gpio_no = GPIO_SPKR_I2S_WS,
+		.gpio_name = "SPKR_I2S_WS",
+	},
+	{
+		.gpio_no = GPIO_SPKR_I2S_SCK,
+		.gpio_name = "SPKR_I2S_SCK",
+	},
+	{
+		.gpio_no = GPIO_SPKR_I2S_DOUT,
+		.gpio_name = "SPKR_I2S_DOUT",
+	},
+};
+
+
+/* I2S TX is slave so MCLK is not needed. DIN1 is not used */
+static struct request_gpio mic_i2s_gpio[] = {
+	{
+		.gpio_no = GPIO_MIC_I2S_WS,
+		.gpio_name = "MIC_I2S_WS",
+	},
+	{
+		.gpio_no = GPIO_MIC_I2S_SCK,
+		.gpio_name = "MIC_I2S_SCK",
+	},
+	{
+		.gpio_no = GPIO_MIC_I2S_DIN0,
+		.gpio_name = "MIC_I2S_DIN",
+	},
+};
+
+/* Shared channel numbers for Slimbus ports that connect APQ to MDM. */
+enum {
+	SLIM_1_RX_1 = 145, /* BT-SCO and USB TX */
+	SLIM_1_TX_1 = 146, /* BT-SCO and USB RX */
+	SLIM_3_RX_1 = 151, /* External echo-cancellation ref */
+	SLIM_3_RX_2 = 152, /* External echo-cancellation ref */
+	SLIM_3_TX_1 = 153, /* HDMI RX */
+	SLIM_3_TX_2 = 154, /* HDMI RX */
+	SLIM_4_TX_1 = 148, /* In-call recording RX */
+	SLIM_4_TX_2 = 149, /* In-call recording RX */
+	SLIM_4_RX_1 = 150, /* In-call music delivery TX */
+};
+
+enum {
+	INCALL_REC_MONO,
+	INCALL_REC_STEREO,
+};
+
+
+#if APQ_I2S_SLAVE_CONFIG
+static u32 mdm_mclk_gpio = PM8921_GPIO_PM_TO_SYS(PM_GPIO_MCLK_MDM);
+static u32 apq_mclk_gpio = PM8921_GPIO_PM_TO_SYS(PM_GPIO_MCLK_APQ);
+#endif
+static u32 top_spk_pamp_gpio  = PM8921_GPIO_PM_TO_SYS(18);
+static u32 bottom_spk_pamp_gpio = PM8921_GPIO_PM_TO_SYS(19);
+static int msm_spk_control;
+static int msm_ext_bottom_spk_pamp;
+static int msm_ext_top_spk_pamp;
+static int msm_slim_0_rx_ch = 1;
+static int msm_slim_0_tx_ch = 1;
+static int msm_slim_3_rx_ch = 1;
+
+static struct clk *i2s_rx_bit_clk;
+static struct clk *i2s_tx_bit_clk;
+
+#if (!APQ_I2S_SLAVE_CONFIG)
+static struct clk *mi2s_osr_clk;
+#endif
+static struct clk *mi2s_bit_clk;
+
+static int msm_i2s_rx_ch = 1;
+static int msm_i2s_tx_ch = 1;
+static int msm_mi2s_rx_ch = 1;
+static int msm_mi2s_tx_ch = 1;
+/* MI2S TX and RX share the same control block*/
+static atomic_t mi2s_rsc_ref;
+
+static int msm_btsco_rate = BTSCO_RATE_8KHZ;
+static int msm_btsco_ch = 1;
+
+static int rec_mode = INCALL_REC_MONO;
+
+static struct clk *codec_clk;
+static int clk_users;
+
+static struct snd_soc_jack hs_jack;
+static struct snd_soc_jack button_jack;
+
+static int apq8064_i2s_hs_detect_use_gpio = -1;
+module_param(apq8064_i2s_hs_detect_use_gpio, int, 0444);
+MODULE_PARM_DESC(apq8064_i2s_hs_detect_use_gpio, "Use GPIO for headset detection");
+
+static bool apq8064_i2s_hs_detect_use_firmware;
+module_param(apq8064_i2s_hs_detect_use_firmware, bool, 0444);
+MODULE_PARM_DESC(apq8064_i2s_hs_detect_use_firmware,
+			"Use firmware for headset detection");
+
+static int msm_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
+				    bool dapm);
+
+static struct tabla_mbhc_config mbhc_cfg = {
+	.headset_jack = &hs_jack,
+	.button_jack = &button_jack,
+	.read_fw_bin = false,
+	.calibration = NULL,
+	.micbias = TABLA_MICBIAS2,
+	.mclk_cb_fn = msm_enable_codec_ext_clk,
+	.mclk_rate = TABLA_EXT_CLK_RATE,
+	.gpio = 0,
+	.gpio_irq = 0,
+	.gpio_level_insert = 1,
+};
+
+static struct mutex cdc_mclk_mutex;
+
+static void msm_enable_ext_spk_amp_gpio(u32 spk_amp_gpio)
+{
+	int ret = 0;
+
+	struct pm_gpio param = {
+		.direction      = PM_GPIO_DIR_OUT,
+		.output_buffer  = PM_GPIO_OUT_BUF_CMOS,
+		.output_value   = 1,
+		.pull      = PM_GPIO_PULL_NO,
+		.vin_sel	= PM_GPIO_VIN_S4,
+		.out_strength   = PM_GPIO_STRENGTH_MED,
+		.
+			function       = PM_GPIO_FUNC_NORMAL,
+	};
+
+	if (spk_amp_gpio == bottom_spk_pamp_gpio) {
+
+		ret = gpio_request(bottom_spk_pamp_gpio, "BOTTOM_SPK_AMP");
+		if (ret) {
+			pr_err("%s: Error requesting BOTTOM SPK AMP GPIO %u\n",
+				__func__, bottom_spk_pamp_gpio);
+			return;
+		}
+		ret = pm8xxx_gpio_config(bottom_spk_pamp_gpio, &param);
+		if (ret)
+			pr_err("%s: Failed to configure Bottom Spk Ampl gpio %u\n",
+			__func__, bottom_spk_pamp_gpio);
+		else {
+			pr_debug("%s: enable Bottom spkr amp gpio\n", __func__);
+			gpio_direction_output(bottom_spk_pamp_gpio, 1);
+		}
+
+	} else if (spk_amp_gpio == top_spk_pamp_gpio) {
+
+		ret = gpio_request(top_spk_pamp_gpio, "TOP_SPK_AMP");
+		if (ret) {
+			pr_err("%s: Error requesting GPIO %d\n", __func__,
+				top_spk_pamp_gpio);
+			return;
+		}
+		ret = pm8xxx_gpio_config(top_spk_pamp_gpio, &param);
+		if (ret)
+			pr_err("%s: Failed to configure Top Spk Ampl gpio %u\n",
+			__func__, top_spk_pamp_gpio);
+		else {
+			pr_debug("%s: enable Top spkr amp gpio\n", __func__);
+			gpio_direction_output(top_spk_pamp_gpio, 1);
+		}
+	} else {
+		pr_err("%s: ERROR : Invalid External Speaker Ampl GPIO gpio = %u\n",
+		__func__, spk_amp_gpio);
+		return;
+	}
+}
+
+static void msm_ext_spk_power_amp_on(u32 spk)
+{
+	if (spk & (BOTTOM_SPK_AMP_POS | BOTTOM_SPK_AMP_NEG)) {
+
+		if ((msm_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_POS) &&
+			(msm_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_NEG)) {
+
+			pr_debug("%s() External Bottom Speaker Ampl already	turned on\n"
+			"spk = 0x%08x\n", __func__, spk);
+			return;
+		}
+
+		msm_ext_bottom_spk_pamp |= spk;
+
+		if ((msm_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_POS) &&
+			(msm_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_NEG)) {
+
+			msm_enable_ext_spk_amp_gpio(bottom_spk_pamp_gpio);
+			pr_debug("%s: slepping 4 ms after turning on external\n"
+			"Bottom Speaker Ampl\n", __func__);
+			usleep_range(4000, 4000);
+		}
+
+	} else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG | TOP_SPK_AMP)) {
+
+		pr_debug("%s():top_spk_amp_state = 0x%x spk_event = 0x%x\n",
+		__func__, msm_ext_top_spk_pamp, spk);
+
+		if (((msm_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
+			(msm_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) ||
+				(msm_ext_top_spk_pamp & TOP_SPK_AMP)) {
+
+			pr_debug("%s() External Top Speaker Ampl already turned on\n"
+			"spk = 0x%08x\n", __func__, spk);
+			return;
+		}
+
+		msm_ext_top_spk_pamp |= spk;
+
+		if (((msm_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
+			(msm_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) ||
+				(msm_ext_top_spk_pamp & TOP_SPK_AMP)) {
+
+			msm_enable_ext_spk_amp_gpio(top_spk_pamp_gpio);
+			pr_debug("%s: sleeping 4 ms after turning on\n"
+			"external Top Speaker Ampl\n", __func__);
+			usleep_range(4000, 4000);
+		}
+	} else  {
+
+		pr_err("%s: ERROR : Invalid External Speaker Ampl. spk = 0x%08x\n",
+			__func__, spk);
+		return;
+	}
+}
+
+static void msm_ext_spk_power_amp_off(u32 spk)
+{
+	if (spk & (BOTTOM_SPK_AMP_POS | BOTTOM_SPK_AMP_NEG)) {
+
+		if (!msm_ext_bottom_spk_pamp)
+			return;
+
+		gpio_direction_output(bottom_spk_pamp_gpio, 0);
+		gpio_free(bottom_spk_pamp_gpio);
+		msm_ext_bottom_spk_pamp = 0;
+
+		pr_debug("%s: sleeping 4 ms after turning off external Bottom\n"
+		"Speaker Ampl\n", __func__);
+
+		usleep_range(4000, 4000);
+
+	} else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG | TOP_SPK_AMP)) {
+
+		pr_debug("%s: top_spk_amp_state = 0x%x spk_event = 0x%x\n",
+				__func__, msm_ext_top_spk_pamp, spk);
+
+		if (!msm_ext_top_spk_pamp)
+			return;
+
+		if ((spk & TOP_SPK_AMP_POS) || (spk & TOP_SPK_AMP_NEG)) {
+
+			msm_ext_top_spk_pamp &= (~(TOP_SPK_AMP_POS |
+							TOP_SPK_AMP_NEG));
+		} else if (spk & TOP_SPK_AMP) {
+			msm_ext_top_spk_pamp &=  ~TOP_SPK_AMP;
+		}
+
+		if (msm_ext_top_spk_pamp)
+			return;
+
+		gpio_direction_output(top_spk_pamp_gpio, 0);
+		gpio_free(top_spk_pamp_gpio);
+		msm_ext_top_spk_pamp = 0;
+
+		pr_debug("%s: sleeping 4 ms after ext Top Spek Ampl is off\n",
+				__func__);
+
+		usleep_range(4000, 4000);
+	} else  {
+
+		pr_err("%s: ERROR : Invalid Ext Spk Ampl. spk = 0x%08x\n",
+			__func__, spk);
+		return;
+	}
+}
+
+static void msm_ext_control(struct snd_soc_codec *codec)
+{
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+	pr_debug("%s: msm_spk_control = %d", __func__, msm_spk_control);
+	if (msm_spk_control == MSM8064_SPK_ON) {
+		snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
+		snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
+		snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
+		snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
+	} else {
+		snd_soc_dapm_disable_pin(dapm, "Ext Spk Bottom Pos");
+		snd_soc_dapm_disable_pin(dapm, "Ext Spk Bottom Neg");
+		snd_soc_dapm_disable_pin(dapm, "Ext Spk Top Pos");
+		snd_soc_dapm_disable_pin(dapm, "Ext Spk Top Neg");
+	}
+
+	snd_soc_dapm_sync(dapm);
+}
+
+static int msm_get_spk(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm_spk_control = %d", __func__, msm_spk_control);
+	ucontrol->value.integer.value[0] = msm_spk_control;
+	return 0;
+}
+static int msm_set_spk(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+	pr_debug("%s()\n", __func__);
+	if (msm_spk_control == ucontrol->value.integer.value[0])
+		return 0;
+
+	msm_spk_control = ucontrol->value.integer.value[0];
+	msm_ext_control(codec);
+	return 1;
+}
+static int msm_spkramp_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *k, int event)
+{
+	pr_debug("%s() %x\n", __func__, SND_SOC_DAPM_EVENT_ON(event));
+
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		if (!strncmp(w->name, "Ext Spk Bottom Pos", 18))
+			msm_ext_spk_power_amp_on(BOTTOM_SPK_AMP_POS);
+		else if (!strncmp(w->name, "Ext Spk Bottom Neg", 18))
+			msm_ext_spk_power_amp_on(BOTTOM_SPK_AMP_NEG);
+		else if (!strncmp(w->name, "Ext Spk Top Pos", 15))
+			msm_ext_spk_power_amp_on(TOP_SPK_AMP_POS);
+		else if  (!strncmp(w->name, "Ext Spk Top Neg", 15))
+			msm_ext_spk_power_amp_on(TOP_SPK_AMP_NEG);
+		else if  (!strncmp(w->name, "Ext Spk Top", 12))
+			msm_ext_spk_power_amp_on(TOP_SPK_AMP);
+		else {
+			pr_err("%s() Invalid Speaker Widget = %s\n",
+					__func__, w->name);
+			return -EINVAL;
+		}
+
+	} else {
+		if (!strncmp(w->name, "Ext Spk Bottom Pos", 18))
+			msm_ext_spk_power_amp_off(BOTTOM_SPK_AMP_POS);
+		else if (!strncmp(w->name, "Ext Spk Bottom Neg", 18))
+			msm_ext_spk_power_amp_off(BOTTOM_SPK_AMP_NEG);
+		else if (!strncmp(w->name, "Ext Spk Top Pos", 15))
+			msm_ext_spk_power_amp_off(TOP_SPK_AMP_POS);
+		else if  (!strncmp(w->name, "Ext Spk Top Neg", 15))
+			msm_ext_spk_power_amp_off(TOP_SPK_AMP_NEG);
+		else if  (!strncmp(w->name, "Ext Spk Top", 12))
+			msm_ext_spk_power_amp_off(TOP_SPK_AMP);
+		else {
+			pr_err("%s() Invalid Speaker Widget = %s\n",
+					__func__, w->name);
+			return -EINVAL;
+		}
+	}
+	return 0;
+}
+
+static int msm_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
+				    bool dapm)
+{
+	int r = 0;
+	pr_debug("%s: enable = %d\n", __func__, enable);
+
+	mutex_lock(&cdc_mclk_mutex);
+	if (enable) {
+		clk_users++;
+		pr_debug("%s: clk_users = %d\n", __func__, clk_users);
+		if (clk_users == 1) {
+			if (codec_clk) {
+				/*
+				* For MBHC calc, the MCLK is from APQ side
+				* so APQ has control of the MCLK at this point
+				*/
+				clk_set_rate(codec_clk, TABLA_EXT_CLK_RATE);
+				clk_prepare_enable(codec_clk);
+				tabla_mclk_enable(codec, 1, dapm);
+			} else {
+				pr_err("%s: Error setting Tabla MCLK\n",
+				       __func__);
+				clk_users--;
+				r = -EINVAL;
+			}
+		}
+	} else {
+		if (clk_users > 0) {
+			clk_users--;
+			pr_debug("%s: clk_users = %d\n", __func__, clk_users);
+			if (clk_users == 0) {
+				pr_debug("%s: disabling MCLK. clk_users = %d\n",
+					 __func__, clk_users);
+				tabla_mclk_enable(codec, 0, dapm);
+				/*
+				* For MBHC calc, the MCLK is from APQ side
+				* so APQ has control of the MCLK at this point
+				*/
+				clk_disable_unprepare(codec_clk);
+			}
+		} else {
+			pr_err("%s: Error releasing Tabla MCLK\n", __func__);
+			r = -EINVAL;
+		}
+	}
+	mutex_unlock(&cdc_mclk_mutex);
+	return r;
+}
+
+static int msm_mclk_event(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	pr_debug("%s: event = %d\n", __func__, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+
+		clk_users++;
+		pr_debug("%s: clk_users = %d\n", __func__, clk_users);
+
+		if (clk_users != 1)
+			return 0;
+
+		if (codec_clk) {
+			/*
+			* Since the MCLK is from MDM side so APQ side
+			* has no control of the MCLK at this point
+			*/
+			/*clk_set_rate(codec_clk, TABLA_EXT_CLK_RATE);
+			clk_prepare_enable(codec_clk); */
+			tabla_mclk_enable(w->codec, 1, true);
+
+		} else {
+			pr_err("%s: Error setting Tabla MCLK\n", __func__);
+			clk_users--;
+			return -EINVAL;
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+
+		pr_debug("%s: clk_users = %d\n", __func__, clk_users);
+
+		if (clk_users == 0)
+			return 0;
+
+		clk_users--;
+
+		if (!clk_users) {
+			pr_debug("%s: disabling MCLK. clk_users = %d\n",
+					__func__, clk_users);
+
+			tabla_mclk_enable(w->codec, 0, true);
+			/*
+			* Since the MCLK is from MDM side so APQ side
+			* has no control of the MCLK at this point
+			*/
+			/* clk_disable_unprepare(codec_clk); */
+		}
+		break;
+	}
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget apq8064_dapm_widgets[] = {
+
+	SND_SOC_DAPM_SUPPLY("MCLK",  SND_SOC_NOPM, 0, 0,
+	msm_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_SPK("Ext Spk Bottom Pos", msm_spkramp_event),
+	SND_SOC_DAPM_SPK("Ext Spk Bottom Neg", msm_spkramp_event),
+
+	SND_SOC_DAPM_SPK("Ext Spk Top Pos", msm_spkramp_event),
+	SND_SOC_DAPM_SPK("Ext Spk Top Neg", msm_spkramp_event),
+	SND_SOC_DAPM_SPK("Ext Spk Top", msm_spkramp_event),
+
+	/************ Analog MICs ************/
+	/**
+	 * Analog mic7 (Front Top) on Liquid.
+	 * Used as Handset mic on CDP.
+	 */
+	SND_SOC_DAPM_MIC("Analog mic7", NULL),
+
+	SND_SOC_DAPM_MIC("Headset Mic", NULL),
+	SND_SOC_DAPM_MIC("ANCRight Headset Mic", NULL),
+	SND_SOC_DAPM_MIC("ANCLeft Headset Mic", NULL),
+
+	/*********** Digital Mics ***************/
+	SND_SOC_DAPM_MIC("Digital Mic1", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic2", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic3", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic4", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic5", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic6", NULL),
+};
+
+static const struct snd_soc_dapm_route apq8064_common_audio_map[] = {
+
+	{"RX_BIAS", NULL, "MCLK"},
+	{"LDO_H", NULL, "MCLK"},
+
+	{"HEADPHONE", NULL, "LDO_H"},
+
+	/* Speaker path */
+	{"Ext Spk Bottom Pos", NULL, "LINEOUT1"},
+	{"Ext Spk Bottom Neg", NULL, "LINEOUT3"},
+
+	{"Ext Spk Top Pos", NULL, "LINEOUT2"},
+	{"Ext Spk Top Neg", NULL, "LINEOUT4"},
+	{"Ext Spk Top", NULL, "LINEOUT5"},
+
+	/************   Analog MIC Paths  ************/
+
+	/* Headset Mic */
+	{"AMIC2", NULL, "MIC BIAS2 External"},
+	{"MIC BIAS2 External", NULL, "Headset Mic"},
+
+	/* Headset ANC microphones */
+	{"AMIC3", NULL, "MIC BIAS3 Internal1"},
+	{"MIC BIAS3 Internal1", NULL, "ANCRight Headset Mic"},
+
+	{"AMIC4", NULL, "MIC BIAS1 Internal2"},
+	{"MIC BIAS1 Internal2", NULL, "ANCLeft Headset Mic"},
+};
+
+static const struct snd_soc_dapm_route apq8064_mtp_audio_map[] = {
+
+	/************   Digital MIC Paths  ************/
+
+	/*
+	 * Digital Mic1 (Front bottom Left) on MTP.
+	 * Conncted to DMIC1 Input on Tabla codec.
+	 */
+	{"DMIC1", NULL, "MIC BIAS1 External"},
+	{"MIC BIAS1 External", NULL, "Digital Mic1"},
+
+	/**
+	 * Digital Mic2 (Front bottom right) on MTP.
+	 * Conncted to DMIC2 Input on Tabla codec.
+	 */
+	{"DMIC2", NULL, "MIC BIAS1 External"},
+	{"MIC BIAS1 External", NULL, "Digital Mic2"},
+
+	/**
+	 * Digital Mic3 (Back bottom) on MTP.
+	 * Conncted to DMIC3 Input on Tabla codec.
+	 */
+	{"DMIC3", NULL, "MIC BIAS3 External"},
+	{"MIC BIAS3 External", NULL, "Digital Mic3"},
+
+	/**
+	 * Digital Mic4 (Back top) on MTP.
+	 * Conncted to DMIC4 Input on Tabla codec.
+	 */
+	{"DMIC4", NULL, "MIC BIAS3 External"},
+	{"MIC BIAS3 External", NULL, "Digital Mic4"},
+
+	/**
+	 * Digital Mic5 (Top front Mic) on MTP.
+	 * Conncted to DMIC6 Input on Tabla codec.
+	 */
+	{"DMIC6", NULL, "MIC BIAS4 External"},
+	{"MIC BIAS4 External", NULL, "Digital Mic5"},
+
+};
+
+static const struct snd_soc_dapm_route apq8064_liquid_cdp_audio_map[] = {
+
+	/************   Analog MIC Paths  ************/
+	/**
+	 * Analog mic7 (Front Top Mic) on Liquid.
+	 * Used as Handset mic on CDP.
+	 * Not there on MTP.
+	 */
+	{"AMIC1", NULL, "MIC BIAS1 External"},
+	{"MIC BIAS1 External", NULL, "Analog mic7"},
+
+
+	/************   Digital MIC Paths  ************/
+	/**
+	 * The digital Mic routes are setup considering
+	 * Liquid as default device.
+	 */
+
+	/**
+	 * Digital Mic1 (Front bottom left corner) on Liquid.
+	 * Digital Mic2 (Front bottom right) on MTP.
+	 * Digital Mic GM1 on CDP mainboard.
+	 * Conncted to DMIC2 Input on Tabla codec.
+	 */
+	{"DMIC2", NULL, "MIC BIAS1 External"},
+	{"MIC BIAS1 External", NULL, "Digital Mic1"},
+
+	/**
+	 * Digital Mic2 (Front left side) on Liquid.
+	 * Digital Mic GM2 on CDP mainboard.
+	 * Not there on MTP.
+	 * Conncted to DMIC3 Input on Tabla codec.
+	 */
+	{"DMIC3", NULL, "MIC BIAS3 External"},
+	{"MIC BIAS3 External", NULL, "Digital Mic2"},
+
+	/**
+	 * Digital Mic3. Front bottom left of middle on Liquid.
+	 * Digital Mic5 (Top front Mic) on MTP.
+	 * Digital Mic GM5 on CDP mainboard.
+	 * Conncted to DMIC6 Input on Tabla codec.
+	 */
+	{"DMIC6", NULL, "MIC BIAS4 External"},
+	{"MIC BIAS4 External", NULL, "Digital Mic3"},
+
+	/**
+	 * Digital Mic4. Back bottom on Liquid.
+	 * Digital Mic GM3 on CDP mainboard.
+	 * Top Front Mic on MTP.
+	 * Conncted to DMIC5 Input on Tabla codec.
+	 */
+	{"DMIC5", NULL, "MIC BIAS4 External"},
+	{"MIC BIAS4 External", NULL, "Digital Mic4"},
+
+	/**
+	 * Digital Mic5. Front bottom right of middle on Liquid.
+	 * Digital Mic GM6 on CDP mainboard.
+	 * Not there on MTP.
+	 * Conncted to DMIC4 Input on Tabla codec.
+	 */
+	{"DMIC4", NULL, "MIC BIAS3 External"},
+	{"MIC BIAS3 External", NULL, "Digital Mic5"},
+
+	/* Digital Mic6 (Front bottom right corner) on Liquid.
+	 * Digital Mic1 (Front bottom Left) on MTP.
+	 * Digital Mic GM4 on CDP.
+	 * Conncted to DMIC1 Input on Tabla codec.
+	 */
+	{"DMIC1", NULL, "MIC BIAS1 External"},
+	{"MIC BIAS1 External", NULL, "Digital Mic6"},
+};
+
+static const char * const spk_function[] = {"Off", "On"};
+static const char * const rx_ch_text[] = {"One", "Two"};
+static const char * const tx_ch_text[] = {"One", "Two", "Three", "Four"};
+
+static const struct soc_enum msm_enum[] = {
+	SOC_ENUM_SINGLE_EXT(2, spk_function),
+	SOC_ENUM_SINGLE_EXT(2, rx_ch_text),
+	SOC_ENUM_SINGLE_EXT(4, tx_ch_text),
+};
+
+static const char * const btsco_rate_text[] = {"8000", "16000"};
+static const struct soc_enum msm_btsco_enum[] = {
+		SOC_ENUM_SINGLE_EXT(2, btsco_rate_text),
+};
+
+static int msm_slim_0_rx_ch_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm_slim_0_rx_ch  = %d\n", __func__,
+			msm_slim_0_rx_ch);
+	ucontrol->value.integer.value[0] = msm_slim_0_rx_ch - 1;
+	return 0;
+}
+
+static int msm_slim_0_rx_ch_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	msm_slim_0_rx_ch = ucontrol->value.integer.value[0] + 1;
+
+	pr_debug("%s: msm_slim_0_rx_ch = %d\n", __func__,
+			msm_slim_0_rx_ch);
+	return 1;
+}
+
+static int msm_slim_0_tx_ch_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm_slim_0_tx_ch  = %d\n", __func__,
+			msm_slim_0_tx_ch);
+	ucontrol->value.integer.value[0] = msm_slim_0_tx_ch - 1;
+	return 0;
+}
+
+static int msm_slim_0_tx_ch_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	msm_slim_0_tx_ch = ucontrol->value.integer.value[0] + 1;
+
+	pr_debug("%s: msm_slim_0_tx_ch = %d\n", __func__,
+			msm_slim_0_tx_ch);
+	return 1;
+}
+
+static int msm_slim_3_rx_ch_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm_slim_3_rx_ch  = %d\n", __func__,
+			msm_slim_3_rx_ch);
+	ucontrol->value.integer.value[0] = msm_slim_3_rx_ch - 1;
+	return 0;
+}
+
+static int msm_slim_3_rx_ch_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	msm_slim_3_rx_ch = ucontrol->value.integer.value[0] + 1;
+
+	pr_debug("%s: msm_slim_3_rx_ch = %d\n", __func__,
+			msm_slim_3_rx_ch);
+	return 1;
+}
+
+static int msm_btsco_rate_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm_btsco_rate  = %d", __func__,
+					msm_btsco_rate);
+	ucontrol->value.integer.value[0] = msm_btsco_rate;
+	return 0;
+}
+
+static int msm_btsco_rate_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	switch (ucontrol->value.integer.value[0]) {
+	case 8000:
+		msm_btsco_rate = BTSCO_RATE_8KHZ;
+		break;
+	case 16000:
+		msm_btsco_rate = BTSCO_RATE_16KHZ;
+		break;
+	default:
+		msm_btsco_rate = BTSCO_RATE_8KHZ;
+		break;
+	}
+	pr_debug("%s: msm_btsco_rate = %d\n", __func__,
+					msm_btsco_rate);
+	return 0;
+}
+
+static int msm_incall_rec_mode_get(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = rec_mode;
+	return 0;
+}
+
+static int msm_incall_rec_mode_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+
+	rec_mode = ucontrol->value.integer.value[0];
+	pr_debug("%s: rec_mode:%d\n", __func__, rec_mode);
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new tabla_msm_controls[] = {
+	SOC_ENUM_EXT("Speaker Function", msm_enum[0], msm_get_spk,
+		msm_set_spk),
+	SOC_ENUM_EXT("SLIM_0_RX Channels", msm_enum[1],
+		msm_slim_0_rx_ch_get, msm_slim_0_rx_ch_put),
+	SOC_ENUM_EXT("SLIM_0_TX Channels", msm_enum[2],
+		msm_slim_0_tx_ch_get, msm_slim_0_tx_ch_put),
+	SOC_ENUM_EXT("Internal BTSCO SampleRate", msm_btsco_enum[0],
+		msm_btsco_rate_get, msm_btsco_rate_put),
+	SOC_SINGLE_EXT("Incall Rec Mode", SND_SOC_NOPM, 0, 1, 0,
+			msm_incall_rec_mode_get, msm_incall_rec_mode_put),
+	SOC_ENUM_EXT("SLIM_3_RX Channels", msm_enum[1],
+		msm_slim_3_rx_ch_get, msm_slim_3_rx_ch_put),
+};
+
+
+static int msm_mi2s_rx_ch_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm_mi2s_rx_ch  = %d\n", __func__,
+			msm_mi2s_rx_ch);
+	ucontrol->value.integer.value[0] = msm_mi2s_rx_ch - 1;
+	return 0;
+}
+
+static int msm_mi2s_rx_ch_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	msm_mi2s_rx_ch = ucontrol->value.integer.value[0] + 1;
+
+	pr_debug("%s: msm_mi2s_rx_ch = %d\n", __func__,
+			msm_mi2s_rx_ch);
+	return 1;
+}
+
+static int msm_mi2s_tx_ch_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm_mi2s_tx_ch  = %d\n", __func__,
+			msm_mi2s_tx_ch);
+	ucontrol->value.integer.value[0] = msm_mi2s_tx_ch - 1;
+	return 0;
+}
+
+static int msm_mi2s_tx_ch_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	msm_mi2s_tx_ch = ucontrol->value.integer.value[0] + 1;
+
+	pr_debug("%s: msm_mi2s_tx_ch = %d\n", __func__,
+			msm_mi2s_tx_ch);
+	return 1;
+}
+
+static int msm_mi2s_get_spk(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm_spk_control = %d", __func__, msm_spk_control);
+	ucontrol->value.integer.value[0] = msm_spk_control;
+	return 0;
+}
+static int msm_mi2s_set_spk(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+	pr_debug("%s()\n", __func__);
+	if (msm_spk_control == ucontrol->value.integer.value[0])
+		return 0;
+
+	msm_spk_control = ucontrol->value.integer.value[0];
+	msm_ext_control(codec);
+	return 1;
+}
+
+static int msm_mi2s_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+			struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+	SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+			SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	pr_debug("%s()\n", __func__);
+	rate->min = rate->max = 48000;
+	channels->min = channels->max = msm_mi2s_rx_ch;
+
+	return 0;
+}
+
+static int msm_mi2s_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+			struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+	SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+			SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	pr_debug("%s()\n", __func__);
+	rate->min = rate->max = 48000;
+
+	channels->min = channels->max = msm_mi2s_tx_ch;
+
+	return 0;
+}
+
+
+static int msm_i2s_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+			struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+	SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+			SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	pr_debug("%s()\n", __func__);
+	rate->min = rate->max = 48000;
+	channels->min = channels->max = msm_i2s_rx_ch;
+
+	return 0;
+}
+
+static int msm_i2s_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+			struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+	SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+			SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	pr_debug("%s()\n", __func__);
+	rate->min = rate->max = 48000;
+
+	channels->min = channels->max = msm_i2s_tx_ch;
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new tabla_msm_mi2s_controls[] = {
+	SOC_ENUM_EXT("Speaker Function", msm_enum[0], msm_mi2s_get_spk,
+		msm_mi2s_set_spk),
+	SOC_ENUM_EXT("MI2S_RX Channels", msm_enum[1],
+		msm_mi2s_rx_ch_get, msm_mi2s_rx_ch_put),
+	SOC_ENUM_EXT("MI2S_TX Channels", msm_enum[2],
+		msm_mi2s_tx_ch_get, msm_mi2s_tx_ch_put),
+	SOC_ENUM_EXT("Internal BTSCO SampleRate", msm_btsco_enum[0],
+		msm_btsco_rate_get, msm_btsco_rate_put),
+	SOC_SINGLE_EXT("Incall Rec Mode", SND_SOC_NOPM, 0, 1, 0,
+		msm_incall_rec_mode_get, msm_incall_rec_mode_put),
+};
+
+static int msm_mi2s_audrx_init(struct snd_soc_pcm_runtime *rtd)
+{
+	int ret;
+	uint32_t revision;
+	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+
+#if APQ_I2S_SLAVE_CONFIG
+	struct pm_gpio param = {
+		.direction      = PM_GPIO_DIR_OUT,
+		.output_buffer  = PM_GPIO_OUT_BUF_CMOS,
+		.output_value   = 1,
+		.pull      = PM_GPIO_PULL_NO,
+		.vin_sel	= PM_GPIO_VIN_S4,
+		.out_strength   = PM_GPIO_STRENGTH_MED,
+		.function       = PM_GPIO_FUNC_NORMAL,
+	};
+#endif
+	pr_debug("%s(), dev_name(%s)\n", __func__, dev_name(cpu_dai->dev));
+	ret = gpio_request(GPIO_MI2S_MCLK, "MI2S_MCLK");
+	if (ret)
+		pr_err("%s: Failed to request gpio %d\n", __func__,
+			   GPIO_MI2S_MCLK);
+
+#if APQ_I2S_SLAVE_CONFIG
+	/* APQ provides the mclk to codec */
+	ret = gpio_request(mdm_mclk_gpio, "MDM_MCLK_SWITCH");
+	if (ret) {
+		pr_err("%s: Failed to request gpio %d\n", __func__,
+			mdm_mclk_gpio);
+		return ret;
+	}
+	ret = pm8xxx_gpio_config(mdm_mclk_gpio, &param);
+	if (ret)
+		pr_err("%s: Failed to configure gpio %d\n", __func__,
+			mdm_mclk_gpio);
+	else
+		gpio_direction_output(mdm_mclk_gpio, 0);
+
+	ret = gpio_request(apq_mclk_gpio, "APQ_MCLK_SWITCH");
+	if (ret) {
+		pr_err("%s: Failed to request gpio %d\n", __func__,
+			apq_mclk_gpio);
+		return ret;
+	}
+	ret = pm8xxx_gpio_config(apq_mclk_gpio, &param);
+	if (ret)
+		pr_err("%s: Failed to configure gpio %d\n", __func__,
+			apq_mclk_gpio);
+	else
+		gpio_direction_output(apq_mclk_gpio, 1);
+	pr_debug("%s: Config mdm_mclk_gpio and apq_mclk_gpio\n",
+	__func__);
+#else
+	pr_debug("%s: Not config mdm_mclk_gpio and apq_mclk_gpio\n",
+	__func__);
+#endif
+	snd_soc_dapm_new_controls(dapm, apq8064_dapm_widgets,
+				ARRAY_SIZE(apq8064_dapm_widgets));
+
+	snd_soc_dapm_add_routes(dapm, apq8064_common_audio_map,
+		ARRAY_SIZE(apq8064_common_audio_map));
+
+	if (machine_is_apq8064_mtp()) {
+		snd_soc_dapm_add_routes(dapm, apq8064_mtp_audio_map,
+			ARRAY_SIZE(apq8064_mtp_audio_map));
+	} else  {
+		snd_soc_dapm_add_routes(dapm, apq8064_liquid_cdp_audio_map,
+			ARRAY_SIZE(apq8064_liquid_cdp_audio_map));
+	}
+
+	snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
+	snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
+	snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
+	snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
+
+	snd_soc_dapm_sync(dapm);
+
+	ret = snd_soc_jack_new(codec, "Headset Jack",
+			       (SND_JACK_HEADSET | SND_JACK_OC_HPHL |
+				SND_JACK_OC_HPHR | SND_JACK_UNSUPPORTED),
+		&hs_jack);
+	if (ret) {
+		pr_err("failed to create new jack\n");
+		return ret;
+	}
+
+	ret = snd_soc_jack_new(codec, "Button Jack",
+			       TABLA_JACK_BUTTON_MASK, &button_jack);
+	if (ret) {
+		pr_err("failed to create new jack\n");
+		return ret;
+	}
+	/* Get the MCLK from MI2S block for MBHC calibration */
+	codec_clk = clk_get(cpu_dai->dev, "osr_clk");
+	pr_debug("%s: Device name is %s\n", __func__, dev_name(cpu_dai->dev));
+
+	/* APQ8064 Rev 1.1 CDP and Liquid have mechanical switch */
+	revision = socinfo_get_version();
+	if (apq8064_i2s_hs_detect_use_gpio != -1) {
+		if (apq8064_i2s_hs_detect_use_gpio == 1)
+			pr_debug("%s: MBHC mechanical is enabled by request\n",
+				 __func__);
+		else if (apq8064_i2s_hs_detect_use_gpio == 0)
+			pr_debug("%s: MBHC mechanical is disabled by request\n",
+				 __func__);
+		else
+			pr_warn("%s: Invalid hs_detect_use_gpio %d\n", __func__,
+				apq8064_i2s_hs_detect_use_gpio);
+	} else if (SOCINFO_VERSION_MAJOR(revision) == 0) {
+		pr_warn("%s: Unknown HW revision detected %d.%d\n", __func__,
+			SOCINFO_VERSION_MAJOR(revision),
+			SOCINFO_VERSION_MINOR(revision));
+	} else if ((SOCINFO_VERSION_MAJOR(revision) == 1 &&
+		    SOCINFO_VERSION_MINOR(revision) >= 1 &&
+		    (machine_is_apq8064_cdp() ||
+		     machine_is_apq8064_liquid())) ||
+		   SOCINFO_VERSION_MAJOR(revision) > 1) {
+		pr_debug("%s: MBHC mechanical switch available APQ8064 detected\n",
+		__func__);
+		apq8064_i2s_hs_detect_use_gpio = 1;
+	}
+
+	if (apq8064_i2s_hs_detect_use_gpio == 1) {
+		pr_debug("%s: Using MBHC mechanical switch\n", __func__);
+		mbhc_cfg.gpio = JACK_DETECT_GPIO;
+		mbhc_cfg.gpio_irq = gpio_to_irq(JACK_DETECT_GPIO);
+		ret = gpio_request(mbhc_cfg.gpio, "MBHC_HS_DETECT");
+		if (ret < 0) {
+			pr_err("%s: gpio_request %d failed %d\n", __func__,
+			       mbhc_cfg.gpio, ret);
+			return ret;
+		}
+		gpio_direction_input(JACK_DETECT_GPIO);
+	} else
+		pr_debug("%s: Not using MBHC mechanical switch\n", __func__);
+
+	mbhc_cfg.read_fw_bin = apq8064_i2s_hs_detect_use_firmware;
+
+	ret = tabla_hs_detect(codec, &mbhc_cfg);
+
+#if APQ_I2S_SLAVE_CONFIG
+	/* MDM provides the mclk to codec */
+	gpio_direction_output(apq_mclk_gpio, 0);
+	gpio_direction_output(mdm_mclk_gpio, 1);
+	pr_debug("%s: Should not running here if no clock switch\n", __func__);
+#endif
+	/* Should we add code to put back codec clock?*/
+	gpio_free(GPIO_MI2S_MCLK);
+	pr_debug("%s: Free MCLK GPIO\n", __func__);
+	return ret;
+}
+
+static int msm_mi2s_free_gpios(void)
+{
+	int	i;
+	for (i = 0; i < ARRAY_SIZE(mi2s_gpio); i++)
+		gpio_free(mi2s_gpio[i].gpio_no);
+	return 0;
+}
+
+static void msm_mi2s_shutdown(struct snd_pcm_substream *substream)
+{
+
+	if (atomic_dec_return(&mi2s_rsc_ref) == 0) {
+		pr_debug("%s: free mi2s resources\n", __func__);
+		if (mi2s_bit_clk) {
+			clk_disable_unprepare(mi2s_bit_clk);
+			clk_put(mi2s_bit_clk);
+			mi2s_bit_clk = NULL;
+		}
+#if (!APQ_I2S_SLAVE_CONFIG)
+		if (mi2s_osr_clk) {
+			clk_disable_unprepare(mi2s_osr_clk);
+			clk_put(mi2s_osr_clk);
+			mi2s_osr_clk = NULL;
+		}
+#endif
+		msm_mi2s_free_gpios();
+	}
+}
+
+static int msm_configure_mi2s_gpio(void)
+{
+	int	rtn;
+	int	i;
+	int	j;
+	for (i = 0; i < ARRAY_SIZE(mi2s_gpio); i++) {
+		rtn = gpio_request(mi2s_gpio[i].gpio_no,
+						   mi2s_gpio[i].gpio_name);
+		pr_debug("%s: gpio = %d, gpio name = %s, rtn = %d\n",
+				 __func__,
+				 mi2s_gpio[i].gpio_no,
+				 mi2s_gpio[i].gpio_name,
+				 rtn);
+		if (rtn) {
+			pr_err("%s: Failed to request gpio %d\n",
+				   __func__,
+				   mi2s_gpio[i].gpio_no);
+			for (j = i; j >= 0; j--)
+				gpio_free(mi2s_gpio[j].gpio_no);
+			goto err;
+		}
+	}
+err:
+	return rtn;
+}
+
+static int msm_mi2s_startup(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+
+	pr_debug("%s: dai name %s %p\n", __func__, cpu_dai->name, cpu_dai->dev);
+
+	if (atomic_inc_return(&mi2s_rsc_ref) == 1) {
+		pr_debug("%s: acquire mi2s resources\n", __func__);
+		msm_configure_mi2s_gpio();
+
+#if APQ_I2S_SLAVE_CONFIG
+		pr_debug("%s: APQ is MI2S slave\n", __func__);
+		mi2s_bit_clk = clk_get(cpu_dai->dev, "bit_clk");
+		if (IS_ERR(mi2s_bit_clk))
+			return PTR_ERR(mi2s_bit_clk);
+		clk_set_rate(mi2s_bit_clk, 0);
+		ret = clk_prepare_enable(mi2s_bit_clk);
+		if (IS_ERR_VALUE(ret)) {
+			pr_err("Unable to enable mi2s_bit_clk\n");
+			clk_put(mi2s_bit_clk);
+			return ret;
+		}
+		ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBM_CFM);
+		if (IS_ERR_VALUE(ret))
+			pr_err("set format for CPU dai failed\n");
+#else
+		pr_debug("%s: APQ is MI2S master\n", __func__);
+		mi2s_osr_clk = clk_get(cpu_dai->dev, "osr_clk");
+		if (IS_ERR(mi2s_osr_clk))
+			return PTR_ERR(mi2s_osr_clk);
+		clk_set_rate(mi2s_osr_clk, TABLA_EXT_CLK_RATE);
+		ret = clk_prepare_enable(mi2s_osr_clk);
+		if (IS_ERR_VALUE(ret)) {
+			pr_err("Unable to enable mi2s_osr_clk\n");
+			clk_put(mi2s_osr_clk);
+			return ret;
+		}
+		mi2s_bit_clk = clk_get(cpu_dai->dev, "bit_clk");
+		if (IS_ERR(mi2s_bit_clk)) {
+			pr_err("Unable to get mi2s_bit_clk\n");
+			clk_disable_unprepare(mi2s_osr_clk);
+			clk_put(mi2s_osr_clk);
+			return PTR_ERR(mi2s_bit_clk);
+		}
+		clk_set_rate(mi2s_bit_clk, 8);
+		ret = clk_prepare_enable(mi2s_bit_clk);
+		if (IS_ERR_VALUE(ret)) {
+			pr_err("Unable to enable mi2s_bit_clk\n");
+			clk_disable_unprepare(mi2s_osr_clk);
+			clk_put(mi2s_osr_clk);
+			clk_put(mi2s_bit_clk);
+			return ret;
+		}
+		ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS);
+		if (IS_ERR_VALUE(ret))
+			pr_err("set format for CPU dai failed\n");
+#endif
+	}
+
+	return ret;
+}
+
+
+static int msm_i2s_rx_free_gpios(void)
+{
+	int	i;
+	for (i = 0; i < ARRAY_SIZE(spkr_i2s_gpio); i++)
+		gpio_free(spkr_i2s_gpio[i].gpio_no);
+	return 0;
+}
+
+
+static int msm_i2s_tx_free_gpios(void)
+{
+	int	i;
+	for (i = 0; i < ARRAY_SIZE(mic_i2s_gpio); i++)
+		gpio_free(mic_i2s_gpio[i].gpio_no);
+	return 0;
+}
+
+static void msm_i2s_shutdown(struct snd_pcm_substream *substream)
+{
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		pr_debug("%s: free i2s rx resources\n", __func__);
+		if (i2s_rx_bit_clk) {
+			clk_disable_unprepare(i2s_rx_bit_clk);
+			clk_put(i2s_rx_bit_clk);
+			i2s_rx_bit_clk = NULL;
+		}
+		msm_i2s_rx_free_gpios();
+	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		pr_debug("%s: free i2s tx resources\n", __func__);
+		if (i2s_tx_bit_clk) {
+			clk_disable_unprepare(i2s_tx_bit_clk);
+			clk_put(i2s_tx_bit_clk);
+			i2s_tx_bit_clk = NULL;
+		}
+		msm_i2s_tx_free_gpios();
+	}
+}
+
+static int msm_configure_i2s_rx_gpio(void)
+{
+	int	rtn;
+	int	i;
+	int	j;
+	for (i = 0; i < ARRAY_SIZE(spkr_i2s_gpio); i++) {
+		rtn = gpio_request(spkr_i2s_gpio[i].gpio_no,
+						   spkr_i2s_gpio[i].gpio_name);
+		pr_debug("%s: gpio = %d, gpio name = %s, rtn = %d\n",
+				 __func__,
+				 spkr_i2s_gpio[i].gpio_no,
+				 spkr_i2s_gpio[i].gpio_name,
+				 rtn);
+		if (rtn) {
+			pr_err("%s: Failed to request gpio %d\n",
+				   __func__,
+				   spkr_i2s_gpio[i].gpio_no);
+			for (j = i; j >= 0; j--)
+				gpio_free(spkr_i2s_gpio[j].gpio_no);
+			goto err;
+		}
+	}
+err:
+	return rtn;
+}
+
+static int msm_configure_i2s_tx_gpio(void)
+{
+	int	rtn;
+	int	i;
+	int	j;
+	for (i = 0; i < ARRAY_SIZE(mic_i2s_gpio); i++) {
+		rtn = gpio_request(mic_i2s_gpio[i].gpio_no,
+						   mic_i2s_gpio[i].gpio_name);
+		pr_debug("%s: gpio = %d, gpio name = %s, rtn = %d\n",
+				 __func__,
+				 mic_i2s_gpio[i].gpio_no,
+				 mic_i2s_gpio[i].gpio_name,
+				 rtn);
+		if (rtn) {
+			pr_err("%s: Failed to request gpio %d\n",
+				   __func__,
+				   mic_i2s_gpio[i].gpio_no);
+			for (j = i; j >= 0; j--)
+				gpio_free(mic_i2s_gpio[j].gpio_no);
+			goto err;
+		}
+	}
+err:
+	return rtn;
+}
+
+static int msm_i2s_startup(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		msm_configure_i2s_rx_gpio();
+		i2s_rx_bit_clk = clk_get(cpu_dai->dev, "bit_clk");
+		if (IS_ERR(i2s_rx_bit_clk)) {
+			pr_err("Failed to get i2s bit_clk\n");
+			return PTR_ERR(i2s_rx_bit_clk);
+		}
+		clk_set_rate(i2s_rx_bit_clk, 0);
+		ret = clk_prepare_enable(i2s_rx_bit_clk);
+		if (IS_ERR_VALUE(ret)) {
+			pr_err("Unable to enable i2s_rx_bit_clk\n");
+			clk_put(i2s_rx_bit_clk);
+			return ret;
+		}
+		ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBM_CFM);
+		if (IS_ERR_VALUE(ret))
+			pr_err("set format for CPU dai failed\n");
+	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		msm_configure_i2s_tx_gpio();
+		i2s_tx_bit_clk = clk_get(cpu_dai->dev, "bit_clk");
+		if (IS_ERR(i2s_tx_bit_clk)) {
+			pr_err("Failed to get i2s_tx_bit_clk\n");
+			return PTR_ERR(i2s_tx_bit_clk);
+		}
+		clk_set_rate(i2s_tx_bit_clk, 0);
+		ret = clk_prepare_enable(i2s_tx_bit_clk);
+		if (ret != 0) {
+			pr_err("Unable to enable i2s_tx_bit_clk\n");
+			clk_put(i2s_tx_bit_clk);
+			return ret;
+		}
+		ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBM_CFM);
+		if (IS_ERR_VALUE(ret))
+			pr_err("set format for CPU dai failed\n");
+	}
+
+	pr_debug("%s: ret = %d\n", __func__, ret);
+	pr_debug("%s(): substream = %s  stream = %d\n", __func__,
+			substream->name, substream->stream);
+	return ret;
+}
+
+static void *def_tabla_mbhc_cal(void)
+{
+	void *tabla_cal;
+	struct tabla_mbhc_btn_detect_cfg *btn_cfg;
+	u16 *btn_low, *btn_high;
+	u8 *n_ready, *n_cic, *gain;
+
+	tabla_cal = kzalloc(TABLA_MBHC_CAL_SIZE(TABLA_MBHC_DEF_BUTTONS,
+						TABLA_MBHC_DEF_RLOADS),
+			    GFP_KERNEL);
+	if (!tabla_cal) {
+		pr_err("%s: out of memory\n", __func__);
+		return NULL;
+	}
+
+#define S(X, Y) ((TABLA_MBHC_CAL_GENERAL_PTR(tabla_cal)->X) = (Y))
+	S(t_ldoh, 100);
+	S(t_bg_fast_settle, 100);
+	S(t_shutdown_plug_rem, 255);
+	S(mbhc_nsa, 4);
+	S(mbhc_navg, 4);
+#undef S
+#define S(X, Y) ((TABLA_MBHC_CAL_PLUG_DET_PTR(tabla_cal)->X) = (Y))
+	S(mic_current, TABLA_PID_MIC_5_UA);
+	S(hph_current, TABLA_PID_MIC_5_UA);
+	S(t_mic_pid, 100);
+	S(t_ins_complete, 250);
+	S(t_ins_retry, 200);
+#undef S
+#define S(X, Y) ((TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla_cal)->X) = (Y))
+	S(v_no_mic, 30);
+	S(v_hs_max, 1550);
+#undef S
+#define S(X, Y) ((TABLA_MBHC_CAL_BTN_DET_PTR(tabla_cal)->X) = (Y))
+	S(c[0], 62);
+	S(c[1], 124);
+	S(nc, 1);
+	S(n_meas, 3);
+	S(mbhc_nsc, 11);
+	S(n_btn_meas, 1);
+	S(n_btn_con, 2);
+	S(num_btn, TABLA_MBHC_DEF_BUTTONS);
+	S(v_btn_press_delta_sta, 100);
+	S(v_btn_press_delta_cic, 50);
+#undef S
+	btn_cfg = TABLA_MBHC_CAL_BTN_DET_PTR(tabla_cal);
+	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;
+	n_ready = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_N_READY);
+	n_ready[0] = 48;
+	n_ready[1] = 38;
+	n_cic = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_N_CIC);
+	n_cic[0] = 60;
+	n_cic[1] = 47;
+	gain = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_GAIN);
+	gain[0] = 11;
+	gain[1] = 9;
+
+	return tabla_cal;
+}
+
+static int msm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	int ret = 0;
+	unsigned int rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
+	unsigned int rx_ch_cnt = 0, tx_ch_cnt = 0;
+	unsigned int num_tx_ch = 0;
+
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+
+		pr_debug("%s: rx_0_ch=%d\n", __func__, msm_slim_0_rx_ch);
+
+		ret = snd_soc_dai_get_channel_map(codec_dai,
+				&tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
+		if (ret < 0) {
+			pr_err("%s: failed to get codec chan map\n", __func__);
+			goto end;
+		}
+
+		ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
+				msm_slim_0_rx_ch, rx_ch);
+		if (ret < 0) {
+			pr_err("%s: failed to set cpu chan map\n", __func__);
+			goto end;
+		}
+		ret = snd_soc_dai_set_channel_map(codec_dai, 0, 0,
+				msm_slim_0_rx_ch, rx_ch);
+		if (ret < 0) {
+			pr_err("%s: failed to set codec channel map\n",
+								__func__);
+			goto end;
+		}
+	} else {
+
+		if (codec_dai->id  == 2)
+			num_tx_ch =  msm_slim_0_tx_ch;
+		else if (codec_dai->id == 5) {
+			/* DAI 5 is used for external EC reference from codec.
+			 * Since Rx is fed as reference for EC, the config of
+			 * this DAI is based on that of the Rx path.
+			 */
+			num_tx_ch =  msm_slim_0_rx_ch;
+		}
+
+		pr_debug("%s: %s_tx_dai_id_%d_ch=%d\n", __func__,
+			codec_dai->name, codec_dai->id, num_tx_ch);
+
+		ret = snd_soc_dai_get_channel_map(codec_dai,
+				&tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
+		if (ret < 0) {
+			pr_err("%s: failed to get codec chan map\n", __func__);
+			goto end;
+		}
+
+		ret = snd_soc_dai_set_channel_map(cpu_dai,
+				num_tx_ch, tx_ch, 0 , 0);
+		if (ret < 0) {
+			pr_err("%s: failed to set cpu chan map\n", __func__);
+			goto end;
+		}
+		ret = snd_soc_dai_set_channel_map(codec_dai,
+				num_tx_ch, tx_ch, 0, 0);
+		if (ret < 0) {
+			pr_err("%s: failed to set codec channel map\n",
+								__func__);
+			goto end;
+		}
+
+
+	}
+end:
+	return ret;
+}
+
+static int msm_stubrx_init(struct snd_soc_pcm_runtime *rtd)
+{
+	rtd->pmdown_time = 0;
+
+	return 0;
+}
+
+static int msm_slimbus_2_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	int ret = 0;
+	unsigned int rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
+	unsigned int rx_ch_cnt = 0, tx_ch_cnt = 0;
+	unsigned int num_tx_ch = 0;
+	unsigned int num_rx_ch = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+
+		num_rx_ch =  params_channels(params);
+
+		pr_debug("%s: %s rx_dai_id = %d  num_ch = %d\n", __func__,
+			codec_dai->name, codec_dai->id, num_rx_ch);
+
+		ret = snd_soc_dai_get_channel_map(codec_dai,
+				&tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
+		if (ret < 0) {
+			pr_err("%s: failed to get codec chan map\n", __func__);
+			goto end;
+		}
+
+		ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
+				num_rx_ch, rx_ch);
+		if (ret < 0) {
+			pr_err("%s: failed to set cpu chan map\n", __func__);
+			goto end;
+		}
+		ret = snd_soc_dai_set_channel_map(codec_dai, 0, 0,
+				num_rx_ch, rx_ch);
+		if (ret < 0) {
+			pr_err("%s: failed to set codec channel map\n",
+								__func__);
+			goto end;
+		}
+	} else {
+
+		num_tx_ch =  params_channels(params);
+
+		pr_debug("%s: %s  tx_dai_id = %d  num_ch = %d\n", __func__,
+			codec_dai->name, codec_dai->id, num_tx_ch);
+
+		ret = snd_soc_dai_get_channel_map(codec_dai,
+				&tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
+		if (ret < 0) {
+			pr_err("%s: failed to get codec chan map\n", __func__);
+			goto end;
+		}
+
+		ret = snd_soc_dai_set_channel_map(cpu_dai,
+				num_tx_ch, tx_ch, 0 , 0);
+		if (ret < 0) {
+			pr_err("%s: failed to set cpu chan map\n", __func__);
+			goto end;
+		}
+		ret = snd_soc_dai_set_channel_map(codec_dai,
+				num_tx_ch, tx_ch, 0, 0);
+		if (ret < 0) {
+			pr_err("%s: failed to set codec channel map\n",
+								__func__);
+			goto end;
+		}
+	}
+end:
+	return ret;
+}
+
+static int msm_slimbus_1_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	int ret = 0;
+	unsigned int rx_ch = SLIM_1_RX_1, tx_ch = SLIM_1_TX_1;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		pr_debug("%s: APQ BT/USB TX -> SLIMBUS_1_RX -> MDM TX shared ch %d\n",
+			__func__, rx_ch);
+
+		ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0, 1, &rx_ch);
+		if (ret < 0) {
+			pr_err("%s: Erorr %d setting SLIM_1 RX channel map\n",
+				__func__, ret);
+
+			goto end;
+		}
+	} else {
+		pr_debug("%s: MDM RX -> SLIMBUS_1_TX -> APQ BT/USB Rx shared ch %d\n",
+			__func__, tx_ch);
+
+		ret = snd_soc_dai_set_channel_map(cpu_dai, 1, &tx_ch, 0, 0);
+		if (ret < 0) {
+			pr_err("%s: Erorr %d setting SLIM_1 TX channel map\n",
+				__func__, ret);
+
+			goto end;
+		}
+	}
+
+end:
+	return ret;
+}
+
+static int msm_slimbus_3_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	int ret = 0;
+	unsigned int rx_ch[2] = {SLIM_3_RX_1, SLIM_3_RX_2};
+	unsigned int tx_ch[2] = {SLIM_3_TX_1, SLIM_3_TX_2};
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		pr_debug("%s: slim_3_rx_ch %d, sch %d %d\n",
+			 __func__, msm_slim_3_rx_ch,
+				 rx_ch[0], rx_ch[1]);
+
+		ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
+				msm_slim_3_rx_ch, rx_ch);
+		if (ret < 0) {
+			pr_err("%s: Erorr %d setting SLIM_3 RX channel map\n",
+				__func__, ret);
+
+			goto end;
+		}
+	} else {
+		pr_debug("%s: MDM RX -> SLIMBUS_3_TX -> APQ HDMI ch: %d, %d\n",
+			__func__, tx_ch[0], tx_ch[1]);
+
+		ret = snd_soc_dai_set_channel_map(cpu_dai, 2, tx_ch, 0, 0);
+		if (ret < 0) {
+			pr_err("%s: Erorr %d setting SLIM_3 TX channel map\n",
+				__func__, ret);
+
+			goto end;
+		}
+	}
+
+end:
+	return ret;
+}
+
+static int msm_slimbus_4_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	int ret = 0;
+	unsigned int rx_ch = SLIM_4_RX_1, tx_ch[2];
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		pr_debug("%s: APQ Incall Playback SLIMBUS_4_RX -> MDM TX shared ch %d\n",
+			__func__, rx_ch);
+
+		ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0, 1, &rx_ch);
+		if (ret < 0) {
+			pr_err("%s: Erorr %d setting SLIM_4 RX channel map\n",
+				__func__, ret);
+
+		}
+	} else {
+		if (rec_mode == INCALL_REC_STEREO) {
+			tx_ch[0] = SLIM_4_TX_1;
+			tx_ch[1] = SLIM_4_TX_2;
+			ret = snd_soc_dai_set_channel_map(cpu_dai, 2,
+							tx_ch, 0, 0);
+		} else {
+			tx_ch[0] = SLIM_4_TX_1;
+			ret = snd_soc_dai_set_channel_map(cpu_dai, 1,
+							tx_ch, 0, 0);
+		}
+		pr_debug("%s: Incall Record shared tx_ch[0]:%d, tx_ch[1]:%d\n",
+			__func__, tx_ch[0], tx_ch[1]);
+
+		if (ret < 0) {
+			pr_err("%s: Erorr %d setting SLIM_4 TX channel map\n",
+				__func__, ret);
+
+		}
+	}
+
+	return ret;
+}
+
+static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
+{
+	int err;
+	uint32_t revision;
+	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+
+	pr_debug("%s(), dev_name(%s)\n", __func__, dev_name(cpu_dai->dev));
+
+	/*if (machine_is_msm_liquid()) {
+		top_spk_pamp_gpio = (PM8921_GPIO_PM_TO_SYS(19));
+		bottom_spk_pamp_gpio = (PM8921_GPIO_PM_TO_SYS(18));
+	}*/
+
+	snd_soc_dapm_new_controls(dapm, apq8064_dapm_widgets,
+				ARRAY_SIZE(apq8064_dapm_widgets));
+
+	snd_soc_dapm_add_routes(dapm, apq8064_common_audio_map,
+		ARRAY_SIZE(apq8064_common_audio_map));
+
+	if (machine_is_apq8064_mtp()) {
+		snd_soc_dapm_add_routes(dapm, apq8064_mtp_audio_map,
+			ARRAY_SIZE(apq8064_mtp_audio_map));
+	} else  {
+		snd_soc_dapm_add_routes(dapm, apq8064_liquid_cdp_audio_map,
+			ARRAY_SIZE(apq8064_liquid_cdp_audio_map));
+	}
+
+	snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
+	snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
+	snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
+	snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
+
+	snd_soc_dapm_sync(dapm);
+
+	err = snd_soc_jack_new(codec, "Headset Jack",
+			       (SND_JACK_HEADSET | SND_JACK_OC_HPHL |
+				SND_JACK_OC_HPHR | SND_JACK_UNSUPPORTED),
+			       &hs_jack);
+	if (err) {
+		pr_err("failed to create new jack\n");
+		return err;
+	}
+
+	err = snd_soc_jack_new(codec, "Button Jack",
+			       TABLA_JACK_BUTTON_MASK, &button_jack);
+	if (err) {
+		pr_err("failed to create new jack\n");
+		return err;
+	}
+
+	codec_clk = clk_get(cpu_dai->dev, "osr_clk");
+
+	/* APQ8064 Rev 1.1 CDP and Liquid have mechanical switch */
+	revision = socinfo_get_version();
+	if (apq8064_i2s_hs_detect_use_gpio != -1) {
+		if (apq8064_i2s_hs_detect_use_gpio == 1)
+			pr_debug("%s: MBHC mechanical is enabled by request\n",
+				 __func__);
+		else if (apq8064_i2s_hs_detect_use_gpio == 0)
+			pr_debug("%s: MBHC mechanical is disabled by request\n",
+				 __func__);
+		else
+			pr_warn("%s: Invalid hs_detect_use_gpio %d\n", __func__,
+				apq8064_i2s_hs_detect_use_gpio);
+	} else if (SOCINFO_VERSION_MAJOR(revision) == 0) {
+		pr_warn("%s: Unknown HW revision detected %d.%d\n", __func__,
+			SOCINFO_VERSION_MAJOR(revision),
+			SOCINFO_VERSION_MINOR(revision));
+	} else if ((SOCINFO_VERSION_MAJOR(revision) == 1 &&
+		    SOCINFO_VERSION_MINOR(revision) >= 1 &&
+		    (machine_is_apq8064_cdp() ||
+		     machine_is_apq8064_liquid())) ||
+		   SOCINFO_VERSION_MAJOR(revision) > 1) {
+		pr_debug("%s: MBHC mechanical switch available APQ8064 detected\n",
+		__func__);
+		apq8064_i2s_hs_detect_use_gpio = 1;
+	}
+
+	if (apq8064_i2s_hs_detect_use_gpio == 1) {
+		pr_debug("%s: Using MBHC mechanical switch\n", __func__);
+		mbhc_cfg.gpio = JACK_DETECT_GPIO;
+		mbhc_cfg.gpio_irq = gpio_to_irq(JACK_DETECT_GPIO);
+		err = gpio_request(mbhc_cfg.gpio, "MBHC_HS_DETECT");
+		if (err < 0) {
+			pr_err("%s: gpio_request %d failed %d\n", __func__,
+			       mbhc_cfg.gpio, err);
+			return err;
+		}
+		gpio_direction_input(JACK_DETECT_GPIO);
+	} else
+		pr_debug("%s: Not using MBHC mechanical switch\n", __func__);
+
+	mbhc_cfg.read_fw_bin = apq8064_i2s_hs_detect_use_firmware;
+
+	err = tabla_hs_detect(codec, &mbhc_cfg);
+
+	return err;
+}
+
+static int msm_slim_0_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+			struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+	SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+			SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	pr_debug("%s()\n", __func__);
+	rate->min = rate->max = 48000;
+	channels->min = channels->max = msm_slim_0_rx_ch;
+
+	return 0;
+}
+
+static int msm_slim_0_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+			struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+	SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+			SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	pr_debug("%s()\n", __func__);
+	rate->min = rate->max = 48000;
+	channels->min = channels->max = msm_slim_0_tx_ch;
+
+	return 0;
+}
+
+static int msm_slim_3_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+			struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+	SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+			SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	pr_debug("%s()\n", __func__);
+	rate->min = rate->max = 48000;
+	channels->min = channels->max = msm_slim_3_rx_ch;
+
+	return 0;
+}
+
+static int msm_slim_3_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+			struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+			SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+			SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	pr_debug("%s()\n", __func__);
+	rate->min = rate->max = 48000;
+	channels->min = channels->max = 2;
+
+	return 0;
+}
+
+static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+			struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+	SNDRV_PCM_HW_PARAM_RATE);
+
+	pr_debug("%s()\n", __func__);
+	rate->min = rate->max = 48000;
+
+	return 0;
+}
+
+static int msm_hdmi_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+					struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	pr_debug("%s channels->min %u channels->max %u ()\n", __func__,
+			channels->min, channels->max);
+
+	rate->min = rate->max = 48000;
+
+	return 0;
+}
+
+static int msm_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+					struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	rate->min = rate->max = msm_btsco_rate;
+	channels->min = channels->max = msm_btsco_ch;
+
+	return 0;
+}
+static int msm_auxpcm_be_params_fixup(struct snd_soc_pcm_runtime *rtd,
+					struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	/* PCM only supports mono output with 8khz sample rate */
+	rate->min = rate->max = 8000;
+	channels->min = channels->max = 1;
+
+	return 0;
+}
+static int msm_proxy_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+			struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+	SNDRV_PCM_HW_PARAM_RATE);
+
+	pr_debug("%s()\n", __func__);
+	rate->min = rate->max = 48000;
+
+	return 0;
+}
+
+static int msm_aux_pcm_get_gpios(void)
+{
+	int ret = 0;
+
+	pr_debug("%s\n", __func__);
+
+	ret = gpio_request(GPIO_AUX_PCM_DOUT, "AUX PCM DOUT");
+	if (ret < 0) {
+		pr_err("%s: Failed to request gpio(%d): AUX PCM DOUT",
+				__func__, GPIO_AUX_PCM_DOUT);
+		goto fail_dout;
+	}
+
+	ret = gpio_request(GPIO_AUX_PCM_DIN, "AUX PCM DIN");
+	if (ret < 0) {
+		pr_err("%s: Failed to request gpio(%d): AUX PCM DIN",
+				__func__, GPIO_AUX_PCM_DIN);
+		goto fail_din;
+	}
+
+	ret = gpio_request(GPIO_AUX_PCM_SYNC, "AUX PCM SYNC");
+	if (ret < 0) {
+		pr_err("%s: Failed to request gpio(%d): AUX PCM SYNC",
+				__func__, GPIO_AUX_PCM_SYNC);
+		goto fail_sync;
+	}
+	ret = gpio_request(GPIO_AUX_PCM_CLK, "AUX PCM CLK");
+	if (ret < 0) {
+		pr_err("%s: Failed to request gpio(%d): AUX PCM CLK",
+				__func__, GPIO_AUX_PCM_CLK);
+		goto fail_clk;
+	}
+
+	return 0;
+
+fail_clk:
+	gpio_free(GPIO_AUX_PCM_SYNC);
+fail_sync:
+	gpio_free(GPIO_AUX_PCM_DIN);
+fail_din:
+	gpio_free(GPIO_AUX_PCM_DOUT);
+fail_dout:
+
+	return ret;
+}
+
+static int msm_aux_pcm_free_gpios(void)
+{
+	gpio_free(GPIO_AUX_PCM_DIN);
+	gpio_free(GPIO_AUX_PCM_DOUT);
+	gpio_free(GPIO_AUX_PCM_SYNC);
+	gpio_free(GPIO_AUX_PCM_CLK);
+
+	return 0;
+}
+static int msm_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+	pr_debug("%s(): dai_link_str_name = %s cpu_dai = %s codec_dai = %s\n",
+		__func__, rtd->dai_link->stream_name,
+		rtd->dai_link->cpu_dai_name,
+		 rtd->dai_link->codec_dai_name);
+	return 0;
+}
+
+static int msm_auxpcm_startup(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+
+	pr_debug("%s(): substream = %s\n", __func__, substream->name);
+	ret = msm_aux_pcm_get_gpios();
+	if (ret < 0) {
+		pr_err("%s: Aux PCM GPIO request failed\n", __func__);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int msm_slimbus_1_startup(struct snd_pcm_substream *substream)
+{
+	struct slim_controller *slim = slim_busnum_to_ctrl(1);
+
+	pr_debug("%s(): substream = %s  stream = %d\n", __func__,
+		 substream->name, substream->stream);
+
+	if (slim != NULL)
+		pm_runtime_get_sync(slim->dev.parent);
+
+	return 0;
+}
+
+static void msm_auxpcm_shutdown(struct snd_pcm_substream *substream)
+{
+
+	pr_debug("%s(): substream = %s\n", __func__, substream->name);
+	msm_aux_pcm_free_gpios();
+}
+
+static void msm_shutdown(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+	pr_debug("%s(): dai_link_str_name = %s cpu_dai = %s codec_dai = %s\n",
+		__func__, rtd->dai_link->stream_name,
+		rtd->dai_link->cpu_dai_name, rtd->dai_link->codec_dai_name);
+}
+
+static void msm_slimbus_1_shutdown(struct snd_pcm_substream *substream)
+{
+	struct slim_controller *slim = slim_busnum_to_ctrl(1);
+
+	pr_debug("%s(): substream = %s  stream = %d\n", __func__,
+		 substream->name, substream->stream);
+
+	if (slim != NULL) {
+		pm_runtime_mark_last_busy(slim->dev.parent);
+		pm_runtime_put(slim->dev.parent);
+	}
+}
+
+static struct snd_soc_ops msm_be_ops = {
+	.startup = msm_startup,
+	.hw_params = msm_hw_params,
+	.shutdown = msm_shutdown,
+};
+
+static struct snd_soc_ops msm_auxpcm_be_ops = {
+	.startup = msm_auxpcm_startup,
+	.shutdown = msm_auxpcm_shutdown,
+};
+
+static struct snd_soc_ops msm_slimbus_1_be_ops = {
+	.startup = msm_slimbus_1_startup,
+	.hw_params = msm_slimbus_1_hw_params,
+	.shutdown = msm_slimbus_1_shutdown,
+};
+
+static struct snd_soc_ops msm_slimbus_3_be_ops = {
+	.startup = msm_startup,
+	.hw_params = msm_slimbus_3_hw_params,
+	.shutdown = msm_shutdown,
+};
+
+static struct snd_soc_ops msm_slimbus_4_be_ops = {
+	.startup = msm_startup,
+	.hw_params = msm_slimbus_4_hw_params,
+	.shutdown = msm_shutdown,
+};
+
+static struct snd_soc_ops msm_slimbus_2_be_ops = {
+	.startup = msm_startup,
+	.hw_params = msm_slimbus_2_hw_params,
+	.shutdown = msm_shutdown,
+};
+
+static struct snd_soc_ops msm_mi2s_be_ops = {
+	.startup = msm_mi2s_startup,
+	.shutdown = msm_mi2s_shutdown,
+};
+
+
+static struct snd_soc_ops msm_i2s_be_ops = {
+	.startup = msm_i2s_startup,
+	.shutdown = msm_i2s_shutdown,
+};
+
+static struct snd_soc_dai_link msm_dai_delta_mi2s[] = {
+	/* Backend DAI Links */
+	{
+		.name = LPASS_BE_MI2S_RX,
+		.stream_name = "MI2S Playback",
+		.cpu_dai_name = "msm-dai-q6-mi2s",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "tabla_codec",
+		.codec_dai_name	= "tabla_i2s_rx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_MI2S_RX,
+		.init = &msm_mi2s_audrx_init,
+		.be_hw_params_fixup = msm_mi2s_rx_be_hw_params_fixup,
+		.ops = &msm_mi2s_be_ops,
+		.ignore_pmdown_time = 1, /* Playback support */
+	},
+	{
+		.name = LPASS_BE_MI2S_TX,
+		.stream_name = "MI2S Capture",
+		.cpu_dai_name = "msm-dai-q6-mi2s",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "tabla_codec",
+		.codec_dai_name	= "tabla_i2s_tx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_MI2S_TX,
+		.be_hw_params_fixup = msm_mi2s_tx_be_hw_params_fixup,
+		.ops = &msm_mi2s_be_ops,
+	},
+	{
+		.name = LPASS_BE_PRI_I2S_RX,
+		.stream_name = "Primary I2S Playback",
+		.cpu_dai_name = "msm-dai-q6.0",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_PRI_I2S_RX,
+		.be_hw_params_fixup = msm_i2s_rx_be_hw_params_fixup,
+		.ops = &msm_i2s_be_ops,
+	},
+	{
+		.name = LPASS_BE_PRI_I2S_TX,
+		.stream_name = "Primary I2S Capture",
+		.cpu_dai_name = "msm-dai-q6.1",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_PRI_I2S_TX,
+		.be_hw_params_fixup = msm_i2s_tx_be_hw_params_fixup,
+		.ops = &msm_i2s_be_ops,
+	},
+};
+
+
+static struct snd_soc_dai_link msm_dai_delta_slim[] = {
+	/* Hostless PMC 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, /* Playback support */
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		/* .be_id = do not care */
+	},
+	/* Backend DAI Links */
+	{
+		.name = LPASS_BE_SLIMBUS_0_RX,
+		.stream_name = "Slimbus Playback",
+		.cpu_dai_name = "msm-dai-q6.16384",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "tabla_codec",
+		.codec_dai_name	= "tabla_rx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_0_RX,
+		.init = &msm_audrx_init,
+		.be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
+		.ops = &msm_be_ops,
+		.ignore_pmdown_time = 1, /* Playback support */
+	},
+	{
+		.name = LPASS_BE_SLIMBUS_0_TX,
+		.stream_name = "Slimbus Capture",
+		.cpu_dai_name = "msm-dai-q6.16385",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "tabla_codec",
+		.codec_dai_name	= "tabla_tx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_0_TX,
+		.be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
+		.ops = &msm_be_ops,
+	},
+	{
+		.name = LPASS_BE_STUB_RX,
+		.stream_name = "Stub Playback",
+		.cpu_dai_name = "msm-dai-stub",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "tabla_codec",
+		.codec_dai_name = "tabla_rx2",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_EXTPROC_RX,
+		.be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
+		.init = &msm_stubrx_init,
+		.ops = &msm_be_ops,
+		.ignore_pmdown_time = 1, /* Playback support */
+	},
+	{
+		.name = LPASS_BE_STUB_TX,
+		.stream_name = "Stub Capture",
+		.cpu_dai_name = "msm-dai-stub",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "tabla_codec",
+		.codec_dai_name = "tabla_tx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_EXTPROC_TX,
+		.be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
+		.ops = &msm_be_ops,
+	},
+	{
+		.name = LPASS_BE_SLIMBUS_1_RX,
+		.stream_name = "Slimbus1 Playback",
+		.cpu_dai_name = "msm-dai-q6.16386",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_1_RX,
+		.be_hw_params_fixup = msm_btsco_be_hw_params_fixup,
+		.ops = &msm_slimbus_1_be_ops,
+		.ignore_pmdown_time = 1, /* Playback support */
+
+	},
+	{
+		.name = LPASS_BE_SLIMBUS_1_TX,
+		.stream_name = "Slimbus1 Capture",
+		.cpu_dai_name = "msm-dai-q6.16387",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_1_TX,
+		.be_hw_params_fixup =  msm_btsco_be_hw_params_fixup,
+		.ops = &msm_slimbus_1_be_ops,
+	},
+	/* Ultrasound TX Back End DAI Link */
+	{
+		.name = "SLIMBUS_2 Hostless Capture",
+		.stream_name = "SLIMBUS_2 Hostless Capture",
+		.cpu_dai_name = "msm-dai-q6.16389",
+		.platform_name = "msm-pcm-hostless",
+		.codec_name = "tabla_codec",
+		.codec_dai_name = "tabla_tx2",
+		.ignore_suspend = 1,
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ops = &msm_slimbus_2_be_ops,
+	},
+	/* Ultrasound RX Back End DAI Link */
+	{
+		.name = "SLIMBUS_2 Hostless Playback",
+		.stream_name = "SLIMBUS_2 Hostless Playback",
+		.cpu_dai_name = "msm-dai-q6.16388",
+		.platform_name = "msm-pcm-hostless",
+		.codec_name = "tabla_codec",
+		.codec_dai_name = "tabla_rx3",
+		.ignore_suspend = 1,
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ops = &msm_slimbus_2_be_ops,
+	},
+	/* Incall Music Back End DAI Link */
+	{
+		.name = LPASS_BE_SLIMBUS_4_RX,
+		.stream_name = "Slimbus4 Playback",
+		.cpu_dai_name = "msm-dai-q6.16392",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_4_RX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ops = &msm_slimbus_4_be_ops,
+		.ignore_pmdown_time = 1, /* Playback support */
+	},
+	/* Incall Record Back End DAI Link */
+	{
+		.name = LPASS_BE_SLIMBUS_4_TX,
+		.stream_name = "Slimbus4 Capture",
+		.cpu_dai_name = "msm-dai-q6.16393",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_4_TX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ops = &msm_slimbus_4_be_ops,
+	},
+	{
+		.name = LPASS_BE_STUB_1_TX,
+		.stream_name = "Stub1 Capture",
+		.cpu_dai_name = "msm-dai-stub",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "tabla_codec",
+		.codec_dai_name	= "tabla_tx3",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_EXTPROC_EC_TX,
+		/* This BE is used for external EC reference from codec. Since
+		 * Rx is fed as reference for EC, the config of this DAI is
+		 * based on that of the Rx path.
+		 */
+		.be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
+		.ops = &msm_be_ops,
+	},
+	{
+		.name = LPASS_BE_SLIMBUS_3_RX,
+		.stream_name = "Slimbus3 Playback",
+		.cpu_dai_name = "msm-dai-q6.16390",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_3_RX,
+		.be_hw_params_fixup = msm_slim_3_rx_be_hw_params_fixup,
+		.ops = &msm_slimbus_3_be_ops,
+		.ignore_pmdown_time = 1, /* Playback support */
+	},
+	{
+		.name = LPASS_BE_SLIMBUS_3_TX,
+		.stream_name = "Slimbus3 Capture",
+		.cpu_dai_name = "msm-dai-q6.16391",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_3_TX,
+		.be_hw_params_fixup = msm_slim_3_tx_be_hw_params_fixup,
+		.ops = &msm_slimbus_3_be_ops,
+	},
+};
+
+/* Digital audio interface glue - connects codec <---> CPU */
+static struct snd_soc_dai_link msm_dai[] = {
+	/* FrontEnd DAI Links */
+	{
+		.name = "MSM8960 Media1",
+		.stream_name = "MultiMedia1",
+		.cpu_dai_name	= "MultiMedia1",
+		.platform_name  = "msm-pcm-dsp",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+		SND_SOC_DPCM_TRIGGER_POST},
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1, /* Playback support */
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA1
+	},
+	{
+		.name = "MSM8960 Media2",
+		.stream_name = "MultiMedia2",
+		.cpu_dai_name	= "MultiMedia2",
+		.platform_name  = "msm-multi-ch-pcm-dsp",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+		SND_SOC_DPCM_TRIGGER_POST},
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1, /* Playback support */
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
+	},
+	{
+		.name = "Circuit-Switch Voice",
+		.stream_name = "CS-Voice",
+		.cpu_dai_name   = "CS-VOICE",
+		.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,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1, /* Playback support */
+		.be_id = MSM_FRONTEND_DAI_CS_VOICE,
+	},
+	{
+		.name = "MSM VoIP",
+		.stream_name = "VoIP",
+		.cpu_dai_name	= "VoIP",
+		.platform_name  = "msm-voip-dsp",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+		SND_SOC_DPCM_TRIGGER_POST},
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1, /* Playback support */
+		.be_id = MSM_FRONTEND_DAI_VOIP,
+	},
+	{
+		.name = "MSM8960 LPA",
+		.stream_name = "LPA",
+		.cpu_dai_name	= "MultiMedia3",
+		.platform_name  = "msm-pcm-lpa",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+		SND_SOC_DPCM_TRIGGER_POST},
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1, /* Playback support */
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA3,
+	},
+	{
+		.name = "INT_FM Hostless",
+		.stream_name = "INT_FM Hostless",
+		.cpu_dai_name	= "INT_FM_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, /* Playback support */
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		/* .be_id = do not care */
+	},
+	{
+		.name = "MSM AFE-PCM RX",
+		.stream_name = "AFE-PROXY RX",
+		.cpu_dai_name = "msm-dai-q6.241",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.platform_name  = "msm-pcm-afe",
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1, /* Playback support */
+	},
+	{
+		.name = "MSM AFE-PCM TX",
+		.stream_name = "AFE-PROXY TX",
+		.cpu_dai_name = "msm-dai-q6.240",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.platform_name  = "msm-pcm-afe",
+		.ignore_suspend = 1,
+	},
+	{
+		.name = "MSM8960 Compr",
+		.stream_name = "COMPR",
+		.cpu_dai_name	= "MultiMedia4",
+		.platform_name  = "msm-compr-dsp",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+		SND_SOC_DPCM_TRIGGER_POST},
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1, /* Playback support */
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA4,
+	},
+	{
+		.name = "AUXPCM Hostless",
+		.stream_name = "AUXPCM Hostless",
+		.cpu_dai_name	= "AUXPCM_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, /* Playback support */
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+	},
+	/* HDMI Hostless */
+	{
+		.name = "HDMI_RX_HOSTLESS",
+		.stream_name = "HDMI_RX_HOSTLESS",
+		.cpu_dai_name = "HDMI_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,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1, /* Playback support */
+	},
+	{
+		.name = "Voice Stub",
+		.stream_name = "Voice Stub",
+		.cpu_dai_name = "VOICE_STUB",
+		.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, /* Playback support */
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+	},
+	/* Backend BT/FM DAI Links */
+	{
+		.name = LPASS_BE_INT_BT_SCO_RX,
+		.stream_name = "Internal BT-SCO Playback",
+		.cpu_dai_name = "msm-dai-q6.12288",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name	= "msm-stub-rx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_INT_BT_SCO_RX,
+		.be_hw_params_fixup = msm_btsco_be_hw_params_fixup,
+		.ignore_pmdown_time = 1, /* Playback support */
+	},
+	{
+		.name = LPASS_BE_INT_BT_SCO_TX,
+		.stream_name = "Internal BT-SCO Capture",
+		.cpu_dai_name = "msm-dai-q6.12289",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name	= "msm-stub-tx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_INT_BT_SCO_TX,
+		.be_hw_params_fixup = msm_btsco_be_hw_params_fixup,
+	},
+	{
+		.name = LPASS_BE_INT_FM_RX,
+		.stream_name = "Internal FM Playback",
+		.cpu_dai_name = "msm-dai-q6.12292",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_INT_FM_RX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ignore_pmdown_time = 1, /* Playback support */
+	},
+	{
+		.name = LPASS_BE_INT_FM_TX,
+		.stream_name = "Internal FM Capture",
+		.cpu_dai_name = "msm-dai-q6.12293",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_INT_FM_TX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+	},
+	/* HDMI BACK END DAI Link */
+	{
+		.name = LPASS_BE_HDMI,
+		.stream_name = "HDMI Playback",
+		.cpu_dai_name = "msm-dai-q6-hdmi.8",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_HDMI_RX,
+		.be_hw_params_fixup = msm_hdmi_be_hw_params_fixup,
+	},
+	/* Backend AFE DAI Links */
+	{
+		.name = LPASS_BE_AFE_PCM_RX,
+		.stream_name = "AFE Playback",
+		.cpu_dai_name = "msm-dai-q6.224",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_AFE_PCM_RX,
+		.be_hw_params_fixup = msm_proxy_be_hw_params_fixup,
+		.ignore_pmdown_time = 1, /* Playback support */
+	},
+	{
+		.name = LPASS_BE_AFE_PCM_TX,
+		.stream_name = "AFE Capture",
+		.cpu_dai_name = "msm-dai-q6.225",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
+		.be_hw_params_fixup = msm_proxy_be_hw_params_fixup,
+	},
+	/* AUX PCM Backend DAI Links */
+	{
+		.name = LPASS_BE_AUXPCM_RX,
+		.stream_name = "AUX PCM Playback",
+		.cpu_dai_name = "msm-dai-q6.2",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_AUXPCM_RX,
+		.be_hw_params_fixup = msm_auxpcm_be_params_fixup,
+		.ops = &msm_auxpcm_be_ops,
+		.ignore_pmdown_time = 1, /* Playback support */
+	},
+	{
+		.name = LPASS_BE_AUXPCM_TX,
+		.stream_name = "AUX PCM Capture",
+		.cpu_dai_name = "msm-dai-q6.3",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_AUXPCM_TX,
+		.be_hw_params_fixup = msm_auxpcm_be_params_fixup,
+	},
+};
+
+
+/* Digital audio interface glue - connects codec <---> CPU */
+static struct snd_soc_dai_link msm_mi2s_dai[
+					 ARRAY_SIZE(msm_dai) +
+					 ARRAY_SIZE(msm_dai_delta_mi2s)];
+
+static struct snd_soc_dai_link msm_slim_dai[
+					 ARRAY_SIZE(msm_dai) +
+					 ARRAY_SIZE(msm_dai_delta_slim)];
+
+static struct snd_soc_card snd_soc_card_msm = {
+	.name		= "apq8064-tabla-snd-card",
+};
+
+static struct platform_device *msm_snd_device;
+
+static int __init msm_audio_init(void)
+{
+
+	int ret;
+	u32	version = socinfo_get_platform_version();
+	if (!machine_is_apq8064_mtp() ||
+	(SOCINFO_VERSION_MINOR(version) != 1)) {
+		pr_info("%s: Not APQ8064 in I2S mode\n", __func__);
+		return -ENODEV;
+	}
+	pr_debug("%s: APQ8064 is in I2S mode\n", __func__);
+	mbhc_cfg.calibration = def_tabla_mbhc_cal();
+	if (!mbhc_cfg.calibration) {
+		pr_err("Calibration data allocation failed\n");
+		return -ENOMEM;
+	}
+
+	msm_snd_device = platform_device_alloc("soc-audio", 0);
+	if (!msm_snd_device) {
+		pr_err("Platform device allocation failed\n");
+		kfree(mbhc_cfg.calibration);
+		return -ENOMEM;
+	}
+
+	if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
+		memcpy(msm_slim_dai, msm_dai, sizeof(msm_dai));
+		memcpy(msm_slim_dai + ARRAY_SIZE(msm_dai),
+			   msm_dai_delta_slim, sizeof(msm_dai_delta_slim));
+		snd_soc_card_msm.dai_link = msm_slim_dai;
+		snd_soc_card_msm.num_links = ARRAY_SIZE(msm_slim_dai);
+		snd_soc_card_msm.controls = tabla_msm_controls;
+		snd_soc_card_msm.num_controls =
+			ARRAY_SIZE(tabla_msm_controls);
+		pr_info("%s: Load Slimbus Dai\n", __func__);
+	} else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C) {
+			memcpy(msm_mi2s_dai, msm_dai, sizeof(msm_dai));
+			memcpy(msm_mi2s_dai + ARRAY_SIZE(msm_dai),
+			msm_dai_delta_mi2s, sizeof(msm_dai_delta_mi2s));
+			snd_soc_card_msm.dai_link = msm_mi2s_dai;
+			snd_soc_card_msm.num_links = ARRAY_SIZE(msm_mi2s_dai);
+			snd_soc_card_msm.controls = tabla_msm_mi2s_controls;
+			snd_soc_card_msm.num_controls =
+				ARRAY_SIZE(tabla_msm_mi2s_controls);
+			pr_info("%s: Load MI2S\n", __func__);
+	}
+
+	platform_set_drvdata(msm_snd_device, &snd_soc_card_msm);
+	ret = platform_device_add(msm_snd_device);
+	if (ret) {
+		platform_device_put(msm_snd_device);
+		kfree(mbhc_cfg.calibration);
+		return ret;
+	}
+
+	mutex_init(&cdc_mclk_mutex);
+	atomic_set(&mi2s_rsc_ref, 0);
+	return ret;
+
+}
+module_init(msm_audio_init);
+
+static void __exit msm_audio_exit(void)
+{
+	if (!cpu_is_apq8064() || (socinfo_get_id() == 130)) {
+		pr_err("%s: Not the right machine type\n", __func__);
+		return ;
+	}
+	platform_device_unregister(msm_snd_device);
+	if (mbhc_cfg.gpio)
+		gpio_free(mbhc_cfg.gpio);
+	kfree(mbhc_cfg.calibration);
+	mutex_destroy(&cdc_mclk_mutex);
+}
+module_exit(msm_audio_exit);
+
+MODULE_DESCRIPTION("ALSA SoC msm");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/apq8064.c b/sound/soc/msm/apq8064.c
index a596f03..e46064b 100644
--- a/sound/soc/msm/apq8064.c
+++ b/sound/soc/msm/apq8064.c
@@ -105,6 +105,10 @@
 module_param(apq8064_hs_detect_use_gpio, int, 0444);
 MODULE_PARM_DESC(apq8064_hs_detect_use_gpio, "Use GPIO for headset detection");
 
+static bool apq8064_hs_detect_extn_cable;
+module_param(apq8064_hs_detect_extn_cable, bool, 0444);
+MODULE_PARM_DESC(apq8064_hs_detect_extn_cable, "Enable extension cable feature");
+
 static bool apq8064_hs_detect_use_firmware;
 module_param(apq8064_hs_detect_use_firmware, bool, 0444);
 MODULE_PARM_DESC(apq8064_hs_detect_use_firmware, "Use firmware for headset "
@@ -124,6 +128,7 @@
 	.gpio = 0,
 	.gpio_irq = 0,
 	.gpio_level_insert = 1,
+	.detect_extn_cable = false,
 };
 
 static struct mutex cdc_mclk_mutex;
@@ -796,7 +801,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);
@@ -814,24 +819,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;
@@ -1152,8 +1157,9 @@
 	snd_soc_dapm_sync(dapm);
 
 	err = snd_soc_jack_new(codec, "Headset Jack",
-			       (SND_JACK_HEADSET | SND_JACK_OC_HPHL |
-				SND_JACK_OC_HPHR | SND_JACK_UNSUPPORTED),
+			       (SND_JACK_HEADSET |  SND_JACK_LINEOUT |
+				SND_JACK_OC_HPHL |  SND_JACK_OC_HPHR |
+				SND_JACK_UNSUPPORTED),
 			       &hs_jack);
 	if (err) {
 		pr_err("failed to create new jack\n");
@@ -1206,6 +1212,8 @@
 			return err;
 		}
 		gpio_direction_input(JACK_DETECT_GPIO);
+		if (apq8064_hs_detect_extn_cable)
+			mbhc_cfg.detect_extn_cable = true;
 	} else
 		pr_debug("%s: Not using MBHC mechanical switch\n", __func__);
 
@@ -1280,6 +1288,28 @@
 	return 0;
 }
 
+static int msm_slim_4_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+			struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+			SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+			SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	pr_debug("%s()\n", __func__);
+
+	rate->min = rate->max = 48000;
+	if (rec_mode == INCALL_REC_STEREO)
+		channels->min = channels->max = 2;
+	else
+		channels->min = channels->max = 1;
+
+	pr_debug("%s channels->min %u channels->max %u ()\n", __func__,
+			channels->min, channels->max);
+	return 0;
+}
+
 static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 			struct snd_pcm_hw_params *params)
 {
@@ -1678,6 +1708,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,
@@ -1913,7 +1974,7 @@
 		.codec_dai_name = "msm-stub-tx",
 		.no_pcm = 1,
 		.be_id = MSM_BACKEND_DAI_SLIMBUS_4_TX,
-		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.be_hw_params_fixup = msm_slim_4_tx_be_hw_params_fixup,
 		.ops = &msm_slimbus_4_be_ops,
 	},
 	{
@@ -1960,7 +2021,7 @@
 	},
 };
 
-struct snd_soc_card snd_soc_card_msm = {
+static struct snd_soc_card snd_soc_card_msm = {
 	.name		= "apq8064-tabla-snd-card",
 	.dai_link	= msm_dai,
 	.num_links	= ARRAY_SIZE(msm_dai),
@@ -1973,12 +2034,16 @@
 static int __init msm_audio_init(void)
 {
 	int ret;
-
-	if (!cpu_is_apq8064() || (socinfo_get_id() == 130)) {
-		pr_err("%s: Not the right machine type\n", __func__);
+	u32	version = socinfo_get_platform_version();
+	if (!cpu_is_apq8064() || (socinfo_get_id() == 130) ||
+		SOCINFO_VERSION_MINOR(version) == 1) {
+		pr_info("%s: Not APQ8064 in SLIMBUS mode\n", __func__);
 		return -ENODEV;
 	}
 
+	if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917)
+		bottom_spk_pamp_gpio = PM8921_GPIO_PM_TO_SYS(16);
+
 	mbhc_cfg.calibration = def_tabla_mbhc_cal();
 	if (!mbhc_cfg.calibration) {
 		pr_err("Calibration data allocation failed\n");
diff --git a/sound/soc/msm/mdm9615.c b/sound/soc/msm/mdm9615.c
index b80a0a9..05786a7 100644
--- a/sound/soc/msm/mdm9615.c
+++ b/sound/soc/msm/mdm9615.c
@@ -17,6 +17,7 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/io.h>
+#include <linux/mfd/wcd9xxx/core.h>
 #include <sound/core.h>
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
@@ -42,10 +43,8 @@
 #define SAMPLE_RATE_8KHZ 8000
 #define SAMPLE_RATE_16KHZ 16000
 
-#define BOTTOM_SPK_AMP_POS	0x1
-#define BOTTOM_SPK_AMP_NEG	0x2
-#define TOP_SPK_AMP_POS		0x4
-#define TOP_SPK_AMP_NEG		0x8
+#define TOP_AND_BOTTOM_SPK_AMP_POS	0x1
+#define TOP_AND_BOTTOM_SPK_AMP_NEG	0x2
 
 #define GPIO_AUX_PCM_DOUT 23
 #define GPIO_AUX_PCM_DIN 22
@@ -62,6 +61,10 @@
 #define TABLA_MBHC_DEF_BUTTONS 8
 #define TABLA_MBHC_DEF_RLOADS 5
 
+#define PM8018_IRQ_BASE			(NR_MSM_IRQS + NR_GPIO_IRQS)
+#define JACK_DETECT_GPIO 3
+#define JACK_DETECT_INT PM8018_GPIO_IRQ(PM8018_IRQ_BASE, JACK_DETECT_GPIO)
+
 /*
  * Added for I2S
  */
@@ -245,16 +248,13 @@
 /*
  * Added for I2S
  */
-
-static u32 top_spk_pamp_gpio  = PM8018_GPIO_PM_TO_SYS(3);
-static u32 bottom_spk_pamp_gpio = PM8018_GPIO_PM_TO_SYS(5);
+static u32 top_and_bottom_spk_pamp_gpio = PM8018_GPIO_PM_TO_SYS(5);
 
 void *sif_virt_addr;
 void *secpcm_portslc_virt_addr;
 
 static int mdm9615_spk_control;
-static int mdm9615_ext_bottom_spk_pamp;
-static int mdm9615_ext_top_spk_pamp;
+static int mdm9615_ext_top_and_bottom_spk_pamp;
 static int mdm9615_slim_0_rx_ch = 1;
 static int mdm9615_slim_0_tx_ch = 1;
 
@@ -271,6 +271,14 @@
 static struct snd_soc_jack hs_jack;
 static struct snd_soc_jack button_jack;
 
+static bool hs_detect_use_gpio;
+module_param(hs_detect_use_gpio, bool, 0444);
+MODULE_PARM_DESC(hs_detect_use_gpio, "Use GPIO for headset detection");
+
+static bool hs_detect_use_firmware;
+module_param(hs_detect_use_firmware, bool, 0444);
+MODULE_PARM_DESC(hs_detect_use_firmware, "Use firmware for headset detection");
+
 static int mdm9615_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
 					bool dapm);
 static struct tabla_mbhc_config mbhc_cfg = {
@@ -300,39 +308,26 @@
 		.function       = PM_GPIO_FUNC_NORMAL,
 	};
 
-	if (spk_amp_gpio == bottom_spk_pamp_gpio) {
+	if (spk_amp_gpio == top_and_bottom_spk_pamp_gpio) {
 
-		ret = gpio_request(bottom_spk_pamp_gpio, "BOTTOM_SPK_AMP");
+		ret = gpio_request(top_and_bottom_spk_pamp_gpio,
+				   "TOP_AND_BOTTOM_SPK_AMP");
 		if (ret) {
-			pr_err("%s: Error requesting BOTTOM SPK AMP GPIO %u\n",
-				__func__, bottom_spk_pamp_gpio);
+			pr_err("%s: Error requesting TOP AND BOTTOM SPK AMP GPIO %u\n",
+				__func__, top_and_bottom_spk_pamp_gpio);
 			return;
 		}
-		ret = pm8xxx_gpio_config(bottom_spk_pamp_gpio, &param);
+		ret = pm8xxx_gpio_config(top_and_bottom_spk_pamp_gpio, &param);
 		if (ret)
-			pr_err("%s: Failed to configure Bottom Spk Ampl"
-				" gpio %u\n", __func__, bottom_spk_pamp_gpio);
+			pr_err("%s: Failed to configure Top & Bottom Spk Ampl\n"
+				"gpio %u\n", __func__,
+				top_and_bottom_spk_pamp_gpio);
 		else {
-			pr_debug("%s: enable Bottom spkr amp gpio\n", __func__);
-			gpio_direction_output(bottom_spk_pamp_gpio, 1);
+			pr_debug("%s: enable Top & Bottom spkr amp gpio\n",
+				 __func__);
+			gpio_direction_output(top_and_bottom_spk_pamp_gpio, 1);
 		}
 
-	} else if (spk_amp_gpio == top_spk_pamp_gpio) {
-
-		ret = gpio_request(top_spk_pamp_gpio, "TOP_SPK_AMP");
-		if (ret) {
-			pr_err("%s: Error requesting GPIO %d\n", __func__,
-				top_spk_pamp_gpio);
-			return;
-		}
-		ret = pm8xxx_gpio_config(top_spk_pamp_gpio, &param);
-		if (ret)
-			pr_err("%s: Failed to configure Top Spk Ampl"
-				" gpio %u\n", __func__, top_spk_pamp_gpio);
-		else {
-			pr_debug("%s: enable Top spkr amp gpio\n", __func__);
-			gpio_direction_output(top_spk_pamp_gpio, 1);
-		}
 	} else {
 		pr_err("%s: ERROR : Invalid External Speaker Ampl GPIO."
 			" gpio = %u\n", __func__, spk_amp_gpio);
@@ -342,49 +337,30 @@
 
 static void mdm9615_ext_spk_power_amp_on(u32 spk)
 {
-	if (spk & (BOTTOM_SPK_AMP_POS | BOTTOM_SPK_AMP_NEG)) {
-
-		if ((mdm9615_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_POS) &&
-			(mdm9615_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_NEG)) {
-
-			pr_debug("%s() External Bottom Speaker Ampl already "
+	if (spk & (TOP_AND_BOTTOM_SPK_AMP_POS | TOP_AND_BOTTOM_SPK_AMP_NEG)) {
+		if ((mdm9615_ext_top_and_bottom_spk_pamp &
+		     TOP_AND_BOTTOM_SPK_AMP_POS) &&
+		    (mdm9615_ext_top_and_bottom_spk_pamp &
+		     TOP_AND_BOTTOM_SPK_AMP_NEG)) {
+			pr_debug("%s() External Speaker Ampl already "
 				"turned on. spk = 0x%08x\n", __func__, spk);
 			return;
 		}
 
-		mdm9615_ext_bottom_spk_pamp |= spk;
+		mdm9615_ext_top_and_bottom_spk_pamp |= spk;
 
-		if ((mdm9615_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_POS) &&
-			(mdm9615_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_NEG)) {
-
-			mdm9615_enable_ext_spk_amp_gpio(bottom_spk_pamp_gpio);
-			pr_debug("%s: slepping 4 ms after turning on external "
-				" Bottom Speaker Ampl\n", __func__);
+		if ((mdm9615_ext_top_and_bottom_spk_pamp &
+		     TOP_AND_BOTTOM_SPK_AMP_POS) &&
+		    (mdm9615_ext_top_and_bottom_spk_pamp &
+		     TOP_AND_BOTTOM_SPK_AMP_NEG)) {
+			mdm9615_enable_ext_spk_amp_gpio(
+					top_and_bottom_spk_pamp_gpio);
+			pr_debug("%s: slepping 4 ms after turning on external\n"
+				"Speaker Ampl\n", __func__);
 			usleep_range(4000, 4000);
 		}
 
-	} else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG)) {
-
-		if ((mdm9615_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
-			(mdm9615_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) {
-
-			pr_debug("%s() External Top Speaker Ampl already"
-				"turned on. spk = 0x%08x\n", __func__, spk);
-			return;
-		}
-
-		mdm9615_ext_top_spk_pamp |= spk;
-
-		if ((mdm9615_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
-			(mdm9615_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) {
-
-			mdm9615_enable_ext_spk_amp_gpio(top_spk_pamp_gpio);
-			pr_debug("%s: sleeping 4 ms after turning on "
-				" external Top Speaker Ampl\n", __func__);
-			usleep_range(4000, 4000);
-		}
-	} else  {
-
+	} else {
 		pr_err("%s: ERROR : Invalid External Speaker Ampl. spk = 0x%08x\n",
 			__func__, spk);
 		return;
@@ -393,33 +369,20 @@
 
 static void mdm9615_ext_spk_power_amp_off(u32 spk)
 {
-	if (spk & (BOTTOM_SPK_AMP_POS | BOTTOM_SPK_AMP_NEG)) {
+	if (spk & (TOP_AND_BOTTOM_SPK_AMP_POS | TOP_AND_BOTTOM_SPK_AMP_NEG)) {
 
-		if (!mdm9615_ext_bottom_spk_pamp)
+		if (!mdm9615_ext_top_and_bottom_spk_pamp)
 			return;
 
-		gpio_direction_output(bottom_spk_pamp_gpio, 0);
-		gpio_free(bottom_spk_pamp_gpio);
-		mdm9615_ext_bottom_spk_pamp = 0;
+		gpio_direction_output(top_and_bottom_spk_pamp_gpio, 0);
+		gpio_free(top_and_bottom_spk_pamp_gpio);
+		mdm9615_ext_top_and_bottom_spk_pamp = 0;
 
 		pr_debug("%s: sleeping 4 ms after turning off external Bottom"
 			" Speaker Ampl\n", __func__);
 
 		usleep_range(4000, 4000);
 
-	} else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG)) {
-
-		if (!mdm9615_ext_top_spk_pamp)
-			return;
-
-		gpio_direction_output(top_spk_pamp_gpio, 0);
-		gpio_free(top_spk_pamp_gpio);
-		mdm9615_ext_top_spk_pamp = 0;
-
-		pr_debug("%s: sleeping 4 ms after turning off external Top"
-			" Spkaker Ampl\n", __func__);
-
-		usleep_range(4000, 4000);
 	} else  {
 
 		pr_err("%s: ERROR : Invalid Ext Spk Ampl. spk = 0x%08x\n",
@@ -434,15 +397,11 @@
 
 	pr_debug("%s: mdm9615_spk_control = %d", __func__, mdm9615_spk_control);
 	if (mdm9615_spk_control == MDM9615_SPK_ON) {
-		snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
-		snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
-		snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
-		snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
+		snd_soc_dapm_enable_pin(dapm, "Ext Spk Pos");
+		snd_soc_dapm_enable_pin(dapm, "Ext Spk Neg");
 	} else {
-		snd_soc_dapm_disable_pin(dapm, "Ext Spk Bottom Pos");
-		snd_soc_dapm_disable_pin(dapm, "Ext Spk Bottom Neg");
-		snd_soc_dapm_disable_pin(dapm, "Ext Spk Top Pos");
-		snd_soc_dapm_disable_pin(dapm, "Ext Spk Top Neg");
+		snd_soc_dapm_disable_pin(dapm, "Ext Spk Pos");
+		snd_soc_dapm_disable_pin(dapm, "Ext Spk Neg");
 	}
 
 	snd_soc_dapm_sync(dapm);
@@ -474,14 +433,12 @@
 	pr_debug("%s() %x\n", __func__, SND_SOC_DAPM_EVENT_ON(event));
 
 	if (SND_SOC_DAPM_EVENT_ON(event)) {
-		if (!strncmp(w->name, "Ext Spk Bottom Pos", 18))
-			mdm9615_ext_spk_power_amp_on(BOTTOM_SPK_AMP_POS);
-		else if (!strncmp(w->name, "Ext Spk Bottom Neg", 18))
-			mdm9615_ext_spk_power_amp_on(BOTTOM_SPK_AMP_NEG);
-		else if (!strncmp(w->name, "Ext Spk Top Pos", 15))
-			mdm9615_ext_spk_power_amp_on(TOP_SPK_AMP_POS);
-		else if  (!strncmp(w->name, "Ext Spk Top Neg", 15))
-			mdm9615_ext_spk_power_amp_on(TOP_SPK_AMP_NEG);
+		if (!strncmp(w->name, "Ext Spk Pos", 11))
+			mdm9615_ext_spk_power_amp_on(
+					TOP_AND_BOTTOM_SPK_AMP_POS);
+		else if (!strncmp(w->name, "Ext Spk Neg", 11))
+			mdm9615_ext_spk_power_amp_on(
+					TOP_AND_BOTTOM_SPK_AMP_NEG);
 		else {
 			pr_err("%s() Invalid Speaker Widget = %s\n",
 					__func__, w->name);
@@ -489,14 +446,12 @@
 		}
 
 	} else {
-		if (!strncmp(w->name, "Ext Spk Bottom Pos", 18))
-			mdm9615_ext_spk_power_amp_off(BOTTOM_SPK_AMP_POS);
-		else if (!strncmp(w->name, "Ext Spk Bottom Neg", 18))
-			mdm9615_ext_spk_power_amp_off(BOTTOM_SPK_AMP_NEG);
-		else if (!strncmp(w->name, "Ext Spk Top Pos", 15))
-			mdm9615_ext_spk_power_amp_off(TOP_SPK_AMP_POS);
-		else if  (!strncmp(w->name, "Ext Spk Top Neg", 15))
-			mdm9615_ext_spk_power_amp_off(TOP_SPK_AMP_NEG);
+		if (!strncmp(w->name, "Ext Spk Pos", 11))
+			mdm9615_ext_spk_power_amp_off(
+					TOP_AND_BOTTOM_SPK_AMP_POS);
+		else if (!strncmp(w->name, "Ext Spk Neg", 11))
+			mdm9615_ext_spk_power_amp_off(
+					TOP_AND_BOTTOM_SPK_AMP_NEG);
 		else {
 			pr_err("%s() Invalid Speaker Widget = %s\n",
 					__func__, w->name);
@@ -557,11 +512,8 @@
 	SND_SOC_DAPM_SUPPLY("MCLK",  SND_SOC_NOPM, 0, 0,
 	mdm9615_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 
-	SND_SOC_DAPM_SPK("Ext Spk Bottom Pos", mdm9615_spkramp_event),
-	SND_SOC_DAPM_SPK("Ext Spk Bottom Neg", mdm9615_spkramp_event),
-
-	SND_SOC_DAPM_SPK("Ext Spk Top Pos", mdm9615_spkramp_event),
-	SND_SOC_DAPM_SPK("Ext Spk Top Neg", mdm9615_spkramp_event),
+	SND_SOC_DAPM_SPK("Ext Spk Pos", mdm9615_spkramp_event),
+	SND_SOC_DAPM_SPK("Ext Spk Neg", mdm9615_spkramp_event),
 
 	SND_SOC_DAPM_MIC("Handset Mic", NULL),
 	SND_SOC_DAPM_MIC("Headset Mic", NULL),
@@ -584,11 +536,11 @@
 	{"LDO_H", NULL, "MCLK"},
 
 	/* Speaker path */
-	{"Ext Spk Bottom Pos", NULL, "LINEOUT1"},
-	{"Ext Spk Bottom Neg", NULL, "LINEOUT3"},
+	{"Ext Spk Pos", NULL, "LINEOUT1"},
+	{"Ext Spk Neg", NULL, "LINEOUT3"},
 
-	{"Ext Spk Top Pos", NULL, "LINEOUT2"},
-	{"Ext Spk Top Neg", NULL, "LINEOUT4"},
+	{"Ext Spk Pos", NULL, "LINEOUT2"},
+	{"Ext Spk Neg", NULL, "LINEOUT4"},
 
 	/* Microphone path */
 	{"AMIC1", NULL, "MIC BIAS1 External"},
@@ -1006,10 +958,8 @@
 
 	snd_soc_dapm_add_routes(dapm, common_audio_map,
 		ARRAY_SIZE(common_audio_map));
-	snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
-	snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
-	snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
-	snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
+	snd_soc_dapm_enable_pin(dapm, "Ext Spk Pos");
+	snd_soc_dapm_enable_pin(dapm, "Ext Spk Neg");
 
 	snd_soc_dapm_sync(dapm);
 
@@ -1510,6 +1460,13 @@
 	struct snd_soc_codec *codec = rtd->codec;
 	struct snd_soc_dapm_context *dapm = &codec->dapm;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct pm_gpio jack_gpio_cfg = {
+		.direction = PM_GPIO_DIR_IN,
+		.pull = PM_GPIO_PULL_NO,
+		.function = PM_GPIO_FUNC_NORMAL,
+		.vin_sel = 2,
+		.inv_int_pol = 0,
+	};
 
 	pr_debug("%s(), dev_name%s\n", __func__, dev_name(cpu_dai->dev));
 
@@ -1521,10 +1478,8 @@
 	snd_soc_dapm_add_routes(dapm, common_audio_map,
 		ARRAY_SIZE(common_audio_map));
 
-	snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
-	snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
-	snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
-	snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
+	snd_soc_dapm_enable_pin(dapm, "Ext Spk Pos");
+	snd_soc_dapm_enable_pin(dapm, "Ext Spk Neg");
 
 	snd_soc_dapm_sync(dapm);
 
@@ -1545,6 +1500,22 @@
 	}
 	codec_clk = clk_get(cpu_dai->dev, "osr_clk");
 
+	if (hs_detect_use_gpio) {
+		mbhc_cfg.gpio = PM8018_GPIO_PM_TO_SYS(JACK_DETECT_GPIO);
+		mbhc_cfg.gpio_irq = JACK_DETECT_INT;
+	}
+
+	if (mbhc_cfg.gpio) {
+		err = pm8xxx_gpio_config(mbhc_cfg.gpio, &jack_gpio_cfg);
+		if (err) {
+			pr_err("%s: pm8xxx_gpio_config JACK_DETECT failed %d\n",
+			       __func__, err);
+			return err;
+		}
+	}
+
+	mbhc_cfg.read_fw_bin = hs_detect_use_firmware;
+
 	err = tabla_hs_detect(codec, &mbhc_cfg);
 
 	return err;
diff --git a/sound/soc/msm/mpq8064.c b/sound/soc/msm/mpq8064.c
index f5bbf56..333f73e 100644
--- a/sound/soc/msm/mpq8064.c
+++ b/sound/soc/msm/mpq8064.c
@@ -133,7 +133,7 @@
 static int msm_ext_top_spk_pamp;
 static int msm_slim_0_rx_ch = 1;
 static int msm_slim_0_tx_ch = 1;
-static int msm_hdmi_rx_ch = 2;
+static int msm_hdmi_rx_ch = 8;
 
 static struct clk *codec_clk;
 static int clk_users;
@@ -515,14 +515,15 @@
 static const char *spk_function[] = {"Off", "On"};
 static const char *slim0_rx_ch_text[] = {"One", "Two"};
 static const char *slim0_tx_ch_text[] = {"One", "Two", "Three", "Four"};
-static const char *hdmi_rx_ch_text[] = {"Two", "Three", "Four", "Five", "Six"};
+static const char * const hdmi_rx_ch_text[] = {"Two", "Three", "Four",
+					"Five", "Six", "Seven", "Eight"};
 
 
 static const struct soc_enum msm_enum[] = {
 	SOC_ENUM_SINGLE_EXT(2, spk_function),
 	SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
 	SOC_ENUM_SINGLE_EXT(4, slim0_tx_ch_text),
-	SOC_ENUM_SINGLE_EXT(5, hdmi_rx_ch_text),
+	SOC_ENUM_SINGLE_EXT(7, hdmi_rx_ch_text),
 
 };
 
@@ -627,7 +628,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);
@@ -645,24 +646,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;
@@ -809,6 +810,22 @@
 	return 0;
 }
 
+static int msm_be_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+			struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	pr_debug("%s()\n", __func__);
+	rate->min = rate->max = 48000;
+	channels->min =  channels->max = 2;
+
+	return 0;
+}
+
 static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 			struct snd_pcm_hw_params *params)
 {
@@ -1339,7 +1356,7 @@
 		.codec_dai_name = "spdif_rx",
 		.no_pcm = 1,
 		.be_id = MSM_BACKEND_DAI_SEC_I2S_RX,
-		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.be_hw_params_fixup = msm_be_i2s_hw_params_fixup,
 		.ops = &mpq8064_sec_i2s_rx_be_ops,
 		.ignore_pmdown_time = 1, /* this dainlink has playback support */
 	},
@@ -1486,6 +1503,9 @@
 		return -ENODEV;
 	}
 
+	if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917)
+		bottom_spk_pamp_gpio = PM8921_GPIO_PM_TO_SYS(16);
+
 	mbhc_cfg.calibration = def_tabla_mbhc_cal();
 	if (!mbhc_cfg.calibration) {
 		pr_err("Calibration data allocation failed\n");
diff --git a/sound/soc/msm/msm-compr-q6.c b/sound/soc/msm/msm-compr-q6.c
index 35cbb5b..b76160e 100644
--- a/sound/soc/msm/msm-compr-q6.c
+++ b/sound/soc/msm/msm-compr-q6.c
@@ -26,6 +26,7 @@
 #include <sound/initval.h>
 #include <sound/control.h>
 #include <sound/q6asm.h>
+#include <sound/pcm_params.h>
 #include <asm/dma.h>
 #include <linux/dma-mapping.h>
 #include <linux/android_pmem.h>
@@ -41,6 +42,7 @@
 #define COMPRE_CAPTURE_PERIOD_SIZE	((COMPRE_CAPTURE_MAX_FRAME_SIZE + \
 					  COMPRE_CAPTURE_HEADER_SIZE) * \
 					  MAX_NUM_FRAMES_PER_BUFFER)
+#define COMPRE_OUTPUT_METADATA_SIZE	(sizeof(struct output_meta_data_st))
 
 struct snd_msm {
 	struct msm_audio *prtd;
@@ -82,12 +84,12 @@
 	.rate_min =	     8000,
 	.rate_max =	     48000,
 	.channels_min =	 1,
-	.channels_max =	 2,
+	.channels_max =	 8,
 	.buffer_bytes_max =     1200 * 1024 * 2,
-	.period_bytes_min =	4800,
+	.period_bytes_min =	2400,
 	.period_bytes_max =     1200 * 1024,
 	.periods_min =	  2,
-	.periods_max =	  512,
+	.periods_max =	  1024,
 	.fifo_size =	    0,
 };
 
@@ -112,8 +114,11 @@
 	struct audio_aio_write_param param;
 	struct audio_aio_read_param read_param;
 	struct audio_buffer *buf = NULL;
+	struct output_meta_data_st output_meta_data;
 	uint32_t *ptrmem = (uint32_t *)payload;
 	int i = 0;
+	int time_stamp_flag = 0;
+	int buffer_length = 0;
 
 	pr_debug("%s opcode =%08x\n", __func__, opcode);
 	switch (opcode) {
@@ -134,8 +139,6 @@
 			break;
 		} else
 			atomic_set(&prtd->pending_buffer, 0);
-		if (runtime->status->hw_ptr >= runtime->control->appl_ptr)
-			break;
 		buf = prtd->audio_client->port[IN].buf;
 		pr_debug("%s:writing %d bytes of buffer[%d] to dsp 2\n",
 				__func__, prtd->pcm_count, prtd->out_head);
@@ -144,14 +147,35 @@
 				((unsigned int)buf[0].phys
 				+ (prtd->out_head * prtd->pcm_count)));
 
+		if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
+			time_stamp_flag = SET_TIMESTAMP;
+		else
+			time_stamp_flag = NO_TIMESTAMP;
+		memcpy(&output_meta_data, (char *)(buf->data +
+			prtd->out_head * prtd->pcm_count),
+			COMPRE_OUTPUT_METADATA_SIZE);
+
+		buffer_length = output_meta_data.frame_size;
+		pr_debug("meta_data_length: %d, frame_length: %d\n",
+			 output_meta_data.meta_data_length,
+			 output_meta_data.frame_size);
+		pr_debug("timestamp_msw: %d, timestamp_lsw: %d\n",
+			 output_meta_data.timestamp_msw,
+			 output_meta_data.timestamp_lsw);
+		if (buffer_length == 0) {
+			pr_debug("Recieved a zero length buffer-break out");
+			break;
+		}
 		param.paddr = (unsigned long)buf[0].phys
-				+ (prtd->out_head * prtd->pcm_count);
-		param.len = prtd->pcm_count;
-		param.msw_ts = 0;
-		param.lsw_ts = 0;
-		param.flags = NO_TIMESTAMP;
+				+ (prtd->out_head * prtd->pcm_count)
+				+ output_meta_data.meta_data_length;
+		param.len = buffer_length;
+		param.msw_ts = output_meta_data.timestamp_msw;
+		param.lsw_ts = output_meta_data.timestamp_lsw;
+		param.flags = time_stamp_flag;
 		param.uid =  (unsigned long)buf[0].phys
-				+ (prtd->out_head * prtd->pcm_count);
+				+ (prtd->out_head * prtd->pcm_count
+				+ output_meta_data.meta_data_length);
 		for (i = 0; i < sizeof(struct audio_aio_write_param)/4;
 					i++, ++ptrmem)
 			pr_debug("cmd[%d]=0x%08x\n", i, *ptrmem);
@@ -166,8 +190,12 @@
 	}
 	case ASM_DATA_CMDRSP_EOS:
 		pr_debug("ASM_DATA_CMDRSP_EOS\n");
-		prtd->cmd_ack = 1;
-		wake_up(&the_locks.eos_wait);
+		if (atomic_read(&prtd->eos)) {
+			pr_debug("ASM_DATA_CMDRSP_EOS wake up\n");
+			prtd->cmd_ack = 1;
+			wake_up(&the_locks.eos_wait);
+			atomic_set(&prtd->eos, 0);
+		}
 		break;
 	case ASM_DATA_EVENT_READ_DONE: {
 		pr_debug("ASM_DATA_EVENT_READ_DONE\n");
@@ -197,7 +225,7 @@
 		buf = prtd->audio_client->port[OUT].buf;
 		pr_debug("pcm_irq_pos=%d, buf[0].phys = 0x%X\n",
 				prtd->pcm_irq_pos, (uint32_t)buf[0].phys);
-		read_param.len = prtd->pcm_count - COMPRE_CAPTURE_HEADER_SIZE ;
+		read_param.len = prtd->pcm_count - COMPRE_CAPTURE_HEADER_SIZE;
 		read_param.paddr = (unsigned long)(buf[0].phys) +
 			prtd->pcm_irq_pos + COMPRE_CAPTURE_HEADER_SIZE;
 		prtd->pcm_irq_pos += prtd->pcm_count;
@@ -251,12 +279,28 @@
 				__func__, prtd->out_head,
 				((unsigned int)buf[0].phys
 				+ (prtd->out_head * prtd->pcm_count)));
-			param.paddr = (unsigned long)buf[prtd->out_head].phys;
-			param.len = prtd->pcm_count;
-			param.msw_ts = 0;
-			param.lsw_ts = 0;
-			param.flags = NO_TIMESTAMP;
-			param.uid =  (unsigned long)buf[prtd->out_head].phys;
+			if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
+				time_stamp_flag = SET_TIMESTAMP;
+			else
+				time_stamp_flag = NO_TIMESTAMP;
+			memcpy(&output_meta_data, (char *)(buf->data +
+				prtd->out_head * prtd->pcm_count),
+				COMPRE_OUTPUT_METADATA_SIZE);
+			buffer_length = output_meta_data.frame_size;
+			pr_debug("meta_data_length: %d, frame_length: %d\n",
+				 output_meta_data.meta_data_length,
+				 output_meta_data.frame_size);
+			pr_debug("timestamp_msw: %d, timestamp_lsw: %d\n",
+				 output_meta_data.timestamp_msw,
+				 output_meta_data.timestamp_lsw);
+			param.paddr = (unsigned long)buf[prtd->out_head].phys
+					+ output_meta_data.meta_data_length;
+			param.len = buffer_length;
+			param.msw_ts = output_meta_data.timestamp_msw;
+			param.lsw_ts = output_meta_data.timestamp_lsw;
+			param.flags = time_stamp_flag;
+			param.uid =  (unsigned long)buf[prtd->out_head].phys
+					+ output_meta_data.meta_data_length;
 			if (q6asm_async_write(prtd->audio_client,
 						&param) < 0)
 				pr_err("%s:q6asm_async_write failed\n",
@@ -271,7 +315,7 @@
 		case ASM_STREAM_CMD_FLUSH:
 			pr_debug("ASM_STREAM_CMD_FLUSH\n");
 			prtd->cmd_ack = 1;
-			wake_up(&the_locks.eos_wait);
+			wake_up(&the_locks.flush_wait);
 			break;
 		default:
 			break;
@@ -292,6 +336,7 @@
 	struct asm_aac_cfg aac_cfg;
 	struct asm_wma_cfg wma_cfg;
 	struct asm_wmapro_cfg wma_pro_cfg;
+	struct asm_amrwbplus_cfg amrwb_cfg;
 	int ret;
 
 	pr_debug("compressed stream prepare\n");
@@ -337,7 +382,7 @@
 		pr_debug("SND_AUDIOCODEC_WMA\n");
 		memset(&wma_cfg, 0x0, sizeof(struct asm_wma_cfg));
 		wma_cfg.format_tag = compr->info.codec_param.codec.format;
-		wma_cfg.ch_cfg = runtime->channels;
+		wma_cfg.ch_cfg = compr->info.codec_param.codec.ch_in;
 		wma_cfg.sample_rate = compr->info.codec_param.codec.sample_rate;
 		wma_cfg.avg_bytes_per_sec =
 			compr->info.codec_param.codec.bit_rate/8;
@@ -389,6 +434,27 @@
 			return ret;
 		}
 		break;
+	case SND_AUDIOCODEC_AMRWB:
+		pr_debug("SND_AUDIOCODEC_AMRWB\n");
+		ret = q6asm_media_format_block(prtd->audio_client,
+					compr->codec);
+		if (ret < 0) {
+			pr_err("%s: CMD Format block failed\n", __func__);
+			return ret;
+		}
+		break;
+	case SND_AUDIOCODEC_AMRWBPLUS:
+		pr_debug("SND_AUDIOCODEC_AMRWBPLUS\n");
+		memset(&amrwb_cfg, 0x0, sizeof(struct asm_amrwbplus_cfg));
+		amrwb_cfg.size_bytes = sizeof(struct asm_amrwbplus_cfg);
+		pr_debug("calling q6asm_media_format_block_amrwbplus");
+		ret = q6asm_media_format_block_amrwbplus(prtd->audio_client,
+						&amrwb_cfg);
+		if (ret < 0) {
+			pr_err("%s: CMD Format block failed\n", __func__);
+			return ret;
+		}
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -405,6 +471,7 @@
 	struct compr_audio *compr = runtime->private_data;
 	struct msm_audio *prtd = &compr->prtd;
 	struct audio_buffer *buf = prtd->audio_client->port[OUT].buf;
+	struct snd_codec *codec = &compr->info.codec_param.codec;
 	struct audio_aio_read_param read_param;
 	int ret = 0;
 	int i;
@@ -419,6 +486,21 @@
 	if (prtd->enabled)
 		return ret;
 	read_param.len = prtd->pcm_count;
+
+	switch (codec->id) {
+	case SND_AUDIOCODEC_AMRWB:
+		pr_debug("SND_AUDIOCODEC_AMRWB\n");
+		ret = q6asm_enc_cfg_blk_amrwb(prtd->audio_client,
+			MAX_NUM_FRAMES_PER_BUFFER,
+			codec->options.generic.reserved[0] /*bitrate 0-8*/,
+			codec->options.generic.reserved[1] /*dtx mode 0/1*/);
+		if (ret < 0)
+			pr_err("%s: CMD Format block" \
+				"failed: %d\n", __func__, ret);
+		break;
+	default:
+		pr_debug("No config for codec %d\n", codec->id);
+	}
 	pr_debug("%s: Samp_rate = %d, Channel = %d, pcm_size = %d,\n"
 			 "pcm_count = %d, periods = %d\n",
 			 __func__, prtd->samp_rate, prtd->channel_mode,
@@ -426,8 +508,24 @@
 
 	for (i = 0; i < runtime->periods; i++) {
 		read_param.uid = i;
-		read_param.paddr = (unsigned long)(buf[i].phys);
-		q6asm_async_read_compressed(prtd->audio_client, &read_param);
+		switch (codec->id) {
+		case SND_AUDIOCODEC_AMRWB:
+			read_param.len = prtd->pcm_count
+					- COMPRE_CAPTURE_HEADER_SIZE;
+			read_param.paddr = (unsigned long)(buf[i].phys)
+					+ COMPRE_CAPTURE_HEADER_SIZE;
+			pr_debug("Push buffer [%d] to DSP, "\
+					"paddr: %p, vaddr: %p\n",
+					i, (void *) read_param.paddr,
+					buf[i].data);
+			q6asm_async_read(prtd->audio_client, &read_param);
+			break;
+		default:
+			read_param.paddr = (unsigned long)(buf[i].phys);
+			q6asm_async_read_compressed(prtd->audio_client,
+				&read_param);
+			break;
+		}
 	}
 	prtd->periods = runtime->periods;
 
@@ -459,9 +557,16 @@
 					1);
 			}
 		} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
-			msm_pcm_routing_reg_psthr_stream(
-				soc_prtd->dai_link->be_id,
-				prtd->session_id, substream->stream, 1);
+			switch (compr->info.codec_param.codec.id) {
+			case SND_AUDIOCODEC_AMRWB:
+				break;
+			default:
+				msm_pcm_routing_reg_psthr_stream(
+					soc_prtd->dai_link->be_id,
+					prtd->session_id, substream->stream,
+					1);
+				break;
+			}
 		}
 	case SNDRV_PCM_TRIGGER_RESUME:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
@@ -480,10 +585,16 @@
 					0);
 			}
 		} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
-			msm_pcm_routing_reg_psthr_stream(
-				soc_prtd->dai_link->be_id,
-				prtd->session_id, substream->stream,
-				0);
+			switch (compr->info.codec_param.codec.id) {
+			case SND_AUDIOCODEC_AMRWB:
+				break;
+			default:
+				msm_pcm_routing_reg_psthr_stream(
+					soc_prtd->dai_link->be_id,
+					prtd->session_id, substream->stream,
+					0);
+				break;
+			}
 		}
 		atomic_set(&prtd->start, 0);
 		break;
@@ -506,7 +617,7 @@
 {
 	pr_debug("%s\n", __func__);
 	/* MP3 Block */
-	compr->info.compr_cap.num_codecs = 1;
+	compr->info.compr_cap.num_codecs = 10;
 	compr->info.compr_cap.min_fragment_size = runtime->hw.period_bytes_min;
 	compr->info.compr_cap.max_fragment_size = runtime->hw.period_bytes_max;
 	compr->info.compr_cap.min_fragments = runtime->hw.periods_min;
@@ -519,7 +630,9 @@
 	compr->info.compr_cap.codecs[5] = SND_AUDIOCODEC_DTS;
 	compr->info.compr_cap.codecs[6] = SND_AUDIOCODEC_DTS_LBR;
 	compr->info.compr_cap.codecs[7] = SND_AUDIOCODEC_DTS_PASS_THROUGH;
-	/* Add new codecs here */
+	compr->info.compr_cap.codecs[8] = SND_AUDIOCODEC_AMRWB;
+	compr->info.compr_cap.codecs[9] = SND_AUDIOCODEC_AMRWBPLUS;
+	/* Add new codecs here and update num_codecs*/
 }
 
 static int msm_compr_open(struct snd_pcm_substream *substream)
@@ -555,7 +668,7 @@
 		kfree(prtd);
 		return -ENOMEM;
 	}
-
+	prtd->audio_client->perf_mode = false;
 	pr_info("%s: session ID %d\n", __func__, prtd->audio_client->session);
 
 	prtd->session_id = prtd->audio_client->session;
@@ -585,6 +698,7 @@
 		compr->codec = FORMAT_MP3;
 	populate_codec_list(compr, runtime);
 	runtime->private_data = compr;
+	atomic_set(&prtd->eos, 0);
 	compressed_audio.prtd =  &compr->prtd;
 	ret = compressed_set_volume(compressed_audio.volume);
 	if (ret < 0)
@@ -631,6 +745,7 @@
 
 	dir = IN;
 	atomic_set(&prtd->pending_buffer, 0);
+	prtd->pcm_irq_pos = 0;
 	q6asm_cmd(prtd->audio_client, CMD_CLOSE);
 	compressed_audio.prtd = NULL;
 	q6asm_audio_client_buf_free_contiguous(dir,
@@ -768,14 +883,36 @@
 			}
 			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;
 		}
 	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
-		ret = q6asm_open_read_compressed(prtd->audio_client,
-					MAX_NUM_FRAMES_PER_BUFFER,
-					COMPRESSED_META_DATA_MODE);
+		switch (compr->info.codec_param.codec.id) {
+		case SND_AUDIOCODEC_AMRWB:
+			pr_debug("q6asm_open_read(FORMAT_AMRWB)\n");
+			ret = q6asm_open_read(prtd->audio_client,
+				FORMAT_AMRWB);
+			if (ret < 0) {
+				pr_err("%s: compressed Session out open failed\n",
+					__func__);
+				return -ENOMEM;
+			}
+			pr_debug("msm_pcm_routing_reg_phy_stream\n");
+			msm_pcm_routing_reg_phy_stream(
+					soc_prtd->dai_link->be_id,
+					prtd->audio_client->perf_mode,
+					prtd->session_id, substream->stream);
+			break;
+		default:
+			pr_debug("q6asm_open_read_compressed(COMPRESSED_META_DATA_MODE)\n");
+			ret = q6asm_open_read_compressed(prtd->audio_client,
+				MAX_NUM_FRAMES_PER_BUFFER,
+				COMPRESSED_META_DATA_MODE);
+			break;
+		}
 
 		if (ret < 0) {
 			pr_err("%s: compressed Session out open failed\n",
@@ -783,12 +920,23 @@
 			return -ENOMEM;
 		}
 	}
+
 	ret = q6asm_set_io_mode(prtd->audio_client, ASYNC_IO_MODE);
 	if (ret < 0) {
 		pr_err("%s: Set IO mode failed\n", __func__);
 		return -ENOMEM;
 	}
-
+	/* Modifying kernel hardware params based on userspace config */
+	if (params_periods(params) > 0 &&
+		(params_periods(params) != runtime->hw.periods_max)) {
+		runtime->hw.periods_max = params_periods(params);
+	}
+	if (params_period_bytes(params) > 0 &&
+		(params_period_bytes(params) != runtime->hw.period_bytes_min)) {
+		runtime->hw.period_bytes_min = params_period_bytes(params);
+	}
+	runtime->hw.buffer_bytes_max =
+			runtime->hw.period_bytes_min * runtime->hw.periods_max;
 	ret = q6asm_audio_client_buf_alloc_contiguous(dir,
 			prtd->audio_client,
 			runtime->hw.period_bytes_min,
@@ -904,23 +1052,63 @@
 			pr_debug("SND_AUDIOCODEC_DTS\n");
 			compr->codec = FORMAT_DTS_LBR;
 			break;
+		case SND_AUDIOCODEC_AMRWB:
+			pr_debug("msm_compr_ioctl SND_AUDIOCODEC_AMRWB\n");
+			compr->codec = FORMAT_AMRWB;
+			break;
+		case SND_AUDIOCODEC_AMRWBPLUS:
+			pr_debug("msm_compr_ioctl SND_AUDIOCODEC_AMRWBPLUS\n");
+			compr->codec = FORMAT_AMR_WB_PLUS;
+			break;
 		default:
+			/*Needed for the HDMI IN compressed use case*/
 			pr_debug("FORMAT_LINEAR_PCM\n");
 			compr->codec = FORMAT_LINEAR_PCM;
 			break;
 		}
 		return 0;
 	case SNDRV_PCM_IOCTL1_RESET:
-		prtd->cmd_ack = 0;
-		rc = q6asm_cmd(prtd->audio_client, CMD_FLUSH);
-		if (rc < 0)
-			pr_err("%s: flush cmd failed rc=%d\n", __func__, rc);
-		rc = wait_event_timeout(the_locks.eos_wait,
-			prtd->cmd_ack, 5 * HZ);
-		if (rc < 0)
-			pr_err("Flush cmd timeout\n");
-		prtd->pcm_irq_pos = 0;
+		pr_debug("SNDRV_PCM_IOCTL1_RESET\n");
+		/* Flush only when session is started during CAPTURE,
+		   while PLAYBACK has no such restriction. */
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
+			  (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
+						atomic_read(&prtd->start))) {
+			if (atomic_read(&prtd->eos)) {
+				prtd->cmd_ack = 1;
+				wake_up(&the_locks.eos_wait);
+				atomic_set(&prtd->eos, 0);
+			}
+
+			/* A unlikely race condition possible with FLUSH
+			   DRAIN if ack is set by flush and reset by drain */
+			prtd->cmd_ack = 0;
+			rc = q6asm_cmd(prtd->audio_client, CMD_FLUSH);
+			if (rc < 0) {
+				pr_err("%s: flush cmd failed rc=%d\n",
+					__func__, rc);
+				return rc;
+			}
+			rc = wait_event_timeout(the_locks.flush_wait,
+				prtd->cmd_ack, 5 * HZ);
+			if (rc < 0)
+				pr_err("Flush cmd timeout\n");
+			prtd->pcm_irq_pos = 0;
+		}
 		break;
+	case SNDRV_COMPRESS_DRAIN:
+		pr_debug("%s: SNDRV_COMPRESS_DRAIN\n", __func__);
+		atomic_set(&prtd->eos, 1);
+		atomic_set(&prtd->pending_buffer, 0);
+		prtd->cmd_ack = 0;
+		q6asm_cmd_nowait(prtd->audio_client, CMD_EOS);
+		/* Wait indefinitely for  DRAIN. Flush can also signal this*/
+		rc = wait_event_interruptible(the_locks.eos_wait,
+			prtd->cmd_ack);
+		if (rc < 0)
+			pr_err("EOS cmd interrupted\n");
+		pr_debug("%s: SNDRV_COMPRESS_DRAIN  out of wait\n", __func__);
+		return 0;
 	default:
 		break;
 	}
@@ -981,6 +1169,7 @@
 	init_waitqueue_head(&the_locks.eos_wait);
 	init_waitqueue_head(&the_locks.write_wait);
 	init_waitqueue_head(&the_locks.read_wait);
+	init_waitqueue_head(&the_locks.flush_wait);
 
 	return platform_driver_register(&msm_compr_driver);
 }
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 4cd4a2c..16a4aaa 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -82,7 +82,7 @@
 					SNDRV_PCM_RATE_KNOT),
 			.formats = SNDRV_PCM_FMTBIT_S16_LE,
 			.channels_min = 1,
-			.channels_max = 6,
+			.channels_max = 8,
 			.rate_min =     8000,
 			.rate_max =	48000,
 		},
@@ -173,7 +173,7 @@
 					SNDRV_PCM_RATE_KNOT),
 			.formats = SNDRV_PCM_FMTBIT_S16_LE,
 			.channels_min = 1,
-			.channels_max = 6,
+			.channels_max = 8,
 			.rate_min =	8000,
 			.rate_max = 48000,
 		},
@@ -199,10 +199,21 @@
 					SNDRV_PCM_RATE_KNOT),
 			.formats = SNDRV_PCM_FMTBIT_S16_LE,
 			.channels_min = 1,
-			.channels_max = 6,
+			.channels_max = 8,
 			.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",
 	},
@@ -214,7 +225,7 @@
 					SNDRV_PCM_RATE_KNOT),
 			.formats = SNDRV_PCM_FMTBIT_S16_LE,
 			.channels_min = 1,
-			.channels_max = 6,
+			.channels_max = 8,
 			.rate_min =	8000,
 			.rate_max = 48000,
 		},
@@ -229,7 +240,7 @@
 					SNDRV_PCM_RATE_KNOT),
 			.formats = SNDRV_PCM_FMTBIT_S16_LE,
 			.channels_min = 1,
-			.channels_max = 6,
+			.channels_max = 8,
 			.rate_min =	8000,
 			.rate_max = 48000,
 		},
@@ -244,7 +255,7 @@
 					SNDRV_PCM_RATE_KNOT),
 			.formats = SNDRV_PCM_FMTBIT_S16_LE,
 			.channels_min = 1,
-			.channels_max = 6,
+			.channels_max = 8,
 			.rate_min =	8000,
 			.rate_max = 48000,
 		},
diff --git a/sound/soc/msm/msm-dai-q6-hdmi.c b/sound/soc/msm/msm-dai-q6-hdmi.c
index c082ed7..2b3dd5f 100644
--- a/sound/soc/msm/msm-dai-q6-hdmi.c
+++ b/sound/soc/msm/msm-dai-q6-hdmi.c
@@ -111,6 +111,13 @@
 		dai_data->port_config.hdmi_multi_ch.channel_allocation =
 				channel_allocation;
 		break;
+	case 8:
+		channel_allocation  = 0x1F;
+		hdmi_msm_audio_info_setup(1, MSM_HDMI_AUDIO_CHANNEL_8,
+				channel_allocation, level_shift, down_mix);
+		dai_data->port_config.hdmi_multi_ch.channel_allocation =
+				channel_allocation;
+		break;
 	default:
 		dev_err(dai->dev, "invalid Channels = %u\n",
 				dai_data->channels);
diff --git a/sound/soc/msm/msm-dai-q6.c b/sound/soc/msm/msm-dai-q6.c
index 89b709f..ee1ab79 100644
--- a/sound/soc/msm/msm-dai-q6.c
+++ b/sound/soc/msm/msm-dai-q6.c
@@ -465,6 +465,9 @@
 	dai_data->channels = params_channels(params);
 	switch (dai_data->channels) {
 	case 2:
+	case 4:
+	case 6:
+	case 8:
 		dai_data->port_config.mi2s.channel = MSM_AFE_STEREO;
 		break;
 	case 1:
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..5b0759c 100644
--- a/sound/soc/msm/msm-multi-ch-pcm-q6.c
+++ b/sound/soc/msm/msm-multi-ch-pcm-q6.c
@@ -28,6 +28,7 @@
 #include <sound/pcm.h>
 #include <sound/initval.h>
 #include <sound/control.h>
+#include <sound/timer.h>
 
 #include "msm-pcm-q6.h"
 #include "msm-pcm-routing.h"
@@ -46,11 +47,11 @@
 static struct snd_msm_volume multi_ch_pcm_audio = {NULL, 0x2000};
 
 #define PLAYBACK_NUM_PERIODS		8
-#define PLAYBACK_MAX_PERIOD_SIZE	4032
+#define PLAYBACK_MAX_PERIOD_SIZE	12288
 #define PLAYBACK_MIN_PERIOD_SIZE        256
 #define CAPTURE_NUM_PERIODS		16
 #define CAPTURE_MIN_PERIOD_SIZE		320
-#define CAPTURE_MAX_PERIOD_SIZE		5376
+#define CAPTURE_MAX_PERIOD_SIZE		12288
 
 static struct snd_pcm_hardware msm_pcm_hardware_capture = {
 	.info =                 (SNDRV_PCM_INFO_MMAP |
@@ -83,7 +84,7 @@
 	.rate_min =             8000,
 	.rate_max =             48000,
 	.channels_min =         1,
-	.channels_max =         6,
+	.channels_max =         8,
 	.buffer_bytes_max =     PLAYBACK_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE,
 	.period_bytes_min =     PLAYBACK_MIN_PERIOD_SIZE,
 	.period_bytes_max =     PLAYBACK_MAX_PERIOD_SIZE,
@@ -110,6 +111,9 @@
 {
 	struct msm_audio *prtd = priv;
 	struct snd_pcm_substream *substream = prtd->substream;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct audio_aio_write_param param;
+	struct audio_buffer *buf = NULL;
 	uint32_t *ptrmem = (uint32_t *)payload;
 	int i = 0;
 	uint32_t idx = 0;
@@ -118,6 +122,7 @@
 	pr_debug("%s\n", __func__);
 	switch (opcode) {
 	case ASM_DATA_EVENT_WRITE_DONE: {
+		uint32_t *ptrmem = (uint32_t *)&param;
 		pr_debug("ASM_DATA_EVENT_WRITE_DONE\n");
 		pr_debug("Buffer Consumed = 0x%08x\n", *ptrmem);
 		prtd->pcm_irq_pos += prtd->pcm_count;
@@ -129,14 +134,31 @@
 			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);
-		}
+		buf = prtd->audio_client->port[IN].buf;
+		pr_debug("%s:writing %d bytes of buffer[%d] to dsp 2\n",
+				__func__, prtd->pcm_count, prtd->out_head);
+		pr_debug("%s:writing buffer[%d] from 0x%08x\n",
+				__func__, prtd->out_head,
+				((unsigned int)buf[0].phys
+				+ (prtd->out_head * prtd->pcm_count)));
+		param.paddr = (unsigned long)buf[0].phys
+				+ (prtd->out_head * prtd->pcm_count);
+		param.len = prtd->pcm_count;
+		param.msw_ts = 0;
+		param.lsw_ts = 0;
+		param.flags = NO_TIMESTAMP;
+		param.uid =  (unsigned long)buf[0].phys
+				+ (prtd->out_head * prtd->pcm_count);
+		for (i = 0; i < sizeof(struct audio_aio_write_param)/4;
+					i++, ++ptrmem)
+			pr_debug("cmd[%d]=0x%08x\n", i, *ptrmem);
+		if (q6asm_async_write(prtd->audio_client,
+					&param) < 0)
+			pr_err("%s:q6asm_async_write failed\n",
+				__func__);
+		else
+			prtd->out_head =
+			(prtd->out_head + 1) & (runtime->periods - 1);
 		break;
 	}
 	case ASM_DATA_CMDRSP_EOS:
@@ -174,18 +196,36 @@
 				break;
 			}
 			if (prtd->mmap_flag) {
-				pr_debug("%s:writing %d bytes"
-					" of buffer to dsp\n",
-					__func__,
-					prtd->pcm_count);
-				q6asm_write_nolock(prtd->audio_client,
-					prtd->pcm_count,
-					0, 0, NO_TIMESTAMP);
+				pr_debug("%s:writing %d bytes"\
+					" of buffer[%d] to dsp\n",
+					__func__, prtd->pcm_count,
+					prtd->out_head);
+				buf = prtd->audio_client->port[IN].buf;
+				pr_debug("%s:writing buffer[%d] from 0x%08x\n",
+					__func__, prtd->out_head,
+					((unsigned int)buf[0].phys
+					+ (prtd->out_head * prtd->pcm_count)));
+				param.paddr = (unsigned long)
+						buf[prtd->out_head].phys;
+				param.len = prtd->pcm_count;
+				param.msw_ts = 0;
+				param.lsw_ts = 0;
+				param.flags = NO_TIMESTAMP;
+				param.uid =  (unsigned long)
+						buf[prtd->out_head].phys;
+				if (q6asm_async_write(prtd->audio_client,
+							&param) < 0)
+					pr_err("%s:q6asm_async_write failed\n",
+						__func__);
+				else
+					prtd->out_head =
+						(prtd->out_head + 1)
+						& (runtime->periods - 1);
 			} else {
 				while (atomic_read(&prtd->out_needed)) {
-					pr_debug("%s:writing %d bytes"
-						 " of buffer to dsp\n",
-						__func__,
+					pr_debug("%s:writing %d bytesi" \
+						  " of buffer to dsp\n", \
+						__func__, \
 						prtd->pcm_count);
 					q6asm_write_nolock(prtd->audio_client,
 						prtd->pcm_count,
@@ -214,6 +254,13 @@
 	int ret;
 
 	pr_debug("%s\n", __func__);
+	if (prtd->mmap_flag) {
+		ret = q6asm_set_io_mode(prtd->audio_client, ASYNC_IO_MODE);
+		if (ret < 0) {
+			pr_err("%s: Set IO mode failed\n", __func__);
+			return -ENOMEM;
+		}
+	}
 	prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
 	prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
 	prtd->pcm_irq_pos = 0;
@@ -256,8 +303,8 @@
 
 	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);
+	ret = q6asm_enc_cfg_blk_multi_ch_pcm(prtd->audio_client,
+		 prtd->samp_rate, prtd->channel_mode);
 	if (ret < 0)
 		pr_debug("%s: cmd cfg pcm was block failed", __func__);
 
@@ -337,6 +384,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,
@@ -351,7 +399,8 @@
 	/* Capture path */
 	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
 		runtime->hw = msm_pcm_hardware_capture;
-		ret = q6asm_open_read(prtd->audio_client, FORMAT_LINEAR_PCM);
+		ret = q6asm_open_read(prtd->audio_client,
+				FORMAT_MULTI_CHANNEL_LINEAR_PCM);
 		if (ret < 0) {
 			pr_err("%s: pcm in open failed\n", __func__);
 			q6asm_audio_client_free(prtd->audio_client);
@@ -364,8 +413,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;
 
@@ -707,10 +756,6 @@
 	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)),
diff --git a/sound/soc/msm/msm-pcm-lpa.c b/sound/soc/msm/msm-pcm-lpa.c
index 269b49b..ff0fb3b 100644
--- a/sound/soc/msm/msm-pcm-lpa.c
+++ b/sound/soc/msm/msm-pcm-lpa.c
@@ -289,6 +289,7 @@
 		kfree(prtd);
 		return -ENOMEM;
 	}
+	prtd->audio_client->perf_mode = false;
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		ret = q6asm_open_write(prtd->audio_client, FORMAT_LINEAR_PCM);
 		if (ret < 0) {
@@ -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-q6.h b/sound/soc/msm/msm-pcm-q6.h
index 9e743a7..f1af99a 100644
--- a/sound/soc/msm/msm-pcm-q6.h
+++ b/sound/soc/msm/msm-pcm-q6.h
@@ -48,6 +48,7 @@
 	wait_queue_head_t write_wait;
 	wait_queue_head_t eos_wait;
 	wait_queue_head_t enable_wait;
+	wait_queue_head_t flush_wait;
 };
 
 struct msm_audio {
@@ -75,10 +76,19 @@
 	atomic_t out_count;
 	atomic_t in_count;
 	atomic_t out_needed;
+	atomic_t eos;
 	int out_head;
 	int periods;
 	int mmap_flag;
 	atomic_t pending_buffer;
 };
 
+struct output_meta_data_st {
+	uint32_t meta_data_length;
+	uint32_t frame_size;
+	uint32_t timestamp_lsw;
+	uint32_t timestamp_msw;
+	uint32_t reserved[12];
+};
+
 #endif /*_MSM_PCM_H*/
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index 26dbb21..6456b2a 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;
@@ -1274,6 +1302,9 @@
 	SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_INT_BT_SCO_RX,
 	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new int_fm_rx_mixer_controls[] = {
@@ -1289,6 +1320,9 @@
 	SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_INT_FM_RX,
 	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_INT_FM_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new afe_pcm_rx_mixer_controls[] = {
@@ -1304,6 +1338,9 @@
 	SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_AFE_PCM_RX,
 	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_AFE_PCM_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new auxpcm_rx_mixer_controls[] = {
@@ -1319,6 +1356,9 @@
 	SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_AUXPCM_RX,
 	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_AUXPCM_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new sec_auxpcm_rx_mixer_controls[] = {
@@ -1375,11 +1415,32 @@
 	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),
+	SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_MI2S_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_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,
 	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer)
 };
 
 static const struct snd_kcontrol_new pri_rx_voice_mixer_controls[] = {
@@ -2023,6 +2084,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),
@@ -2122,6 +2184,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,
@@ -2280,16 +2344,19 @@
 	{"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"},
 	{"MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+	{"MI2S_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
 	{"MI2S_RX", NULL, "MI2S_RX Audio Mixer"},
 
 	{"MultiMedia1 Mixer", "PRI_TX", "PRI_I2S_TX"},
 	{"MultiMedia1 Mixer", "MI2S_TX", "MI2S_TX"},
 	{"MultiMedia2 Mixer", "MI2S_TX", "MI2S_TX"},
 	{"MultiMedia4 Mixer", "MI2S_TX", "MI2S_TX"},
+	{"MultiMedia4 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
 	{"MultiMedia1 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
 	{"MultiMedia1 Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
 	{"MultiMedia1 Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
@@ -2298,33 +2365,41 @@
 	{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
 	{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
 	{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+	{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
 	{"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX Audio Mixer"},
 
 	{"INTERNAL_FM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
 	{"INTERNAL_FM_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
 	{"INTERNAL_FM_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
 	{"INTERNAL_FM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+	{"INTERNAL_FM_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
 	{"INT_FM_RX", NULL, "INTERNAL_FM_RX Audio Mixer"},
 
 	{"AFE_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
 	{"AFE_PCM_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
 	{"AFE_PCM_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
 	{"AFE_PCM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+	{"AFE_PCM_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
 	{"PCM_RX", NULL, "AFE_PCM_RX Audio Mixer"},
 
 	{"MultiMedia1 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+	{"MultiMedia5 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
 	{"MultiMedia1 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+	{"MultiMedia5 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
 
 	{"MultiMedia1 Mixer", "AFE_PCM_TX", "PCM_TX"},
+	{"MultiMedia5 Mixer", "AFE_PCM_TX", "PCM_TX"},
 	{"MM_UL1", NULL, "MultiMedia1 Mixer"},
 	{"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"},
 	{"AUX_PCM_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
 	{"AUX_PCM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+	{"AUX_PCM_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
 	{"AUX_PCM_RX", NULL, "AUX_PCM_RX Audio Mixer"},
 
 	{"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -2553,6 +2628,7 @@
 	bedai->active = 0;
 	bedai->sample_rate = 0;
 	bedai->channel = 0;
+	bedai->perf_mode = false;
 	mutex_unlock(&routing_lock);
 
 	return 0;
@@ -2565,6 +2641,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);
@@ -2592,18 +2669,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 45dbf40..6b87475 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-voice.c b/sound/soc/msm/msm-pcm-voice.c
index 633973e..c5e2f09 100644
--- a/sound/soc/msm/msm-pcm-voice.c
+++ b/sound/soc/msm/msm-pcm-voice.c
@@ -464,6 +464,7 @@
 
 	voc_set_tty_mode(voc_get_session_id(VOICE_SESSION_NAME), tty_mode);
 
+	voc_set_tty_mode(voc_get_session_id(SGLTE_SESSION_NAME), tty_mode);
 	return 0;
 }
 static int msm_voice_widevoice_put(struct snd_kcontrol *kcontrol,
@@ -475,7 +476,8 @@
 
 	voc_set_widevoice_enable(voc_get_session_id(VOICE_SESSION_NAME),
 				 wv_enable);
-
+	voc_set_widevoice_enable(voc_get_session_id(SGLTE_SESSION_NAME),
+				 wv_enable);
 	return 0;
 }
 
@@ -497,6 +499,8 @@
 
 	voc_set_pp_enable(voc_get_session_id(VOICE_SESSION_NAME),
 			MODULE_ID_VOICE_MODULE_ST, st_enable);
+	voc_set_pp_enable(voc_get_session_id(SGLTE_SESSION_NAME),
+			MODULE_ID_VOICE_MODULE_ST, st_enable);
 
 	return 0;
 }
@@ -519,6 +523,8 @@
 
 	voc_set_pp_enable(voc_get_session_id(VOICE_SESSION_NAME),
 			MODULE_ID_VOICE_MODULE_FENS, fens_enable);
+	voc_set_pp_enable(voc_get_session_id(SGLTE_SESSION_NAME),
+			MODULE_ID_VOICE_MODULE_FENS, fens_enable);
 
 	return 0;
 }
diff --git a/sound/soc/msm/msm-pcm.h b/sound/soc/msm/msm-pcm.h
index 6e1325b..867116a 100644
--- a/sound/soc/msm/msm-pcm.h
+++ b/sound/soc/msm/msm-pcm.h
@@ -27,7 +27,7 @@
 #include <mach/qdsp5/qdsp5audrecmsg.h>
 #include <mach/qdsp5/qdsp5audpreproccmdi.h>
 #include <mach/qdsp5/qdsp5audpreprocmsg.h>
-
+#include <mach/qdsp5/qdsp5audpp.h>
 #include <../arch/arm/mach-msm/qdsp5/adsp.h>
 #include <../arch/arm/mach-msm/qdsp5/audmgr.h>
 
diff --git a/sound/soc/msm/msm8930.c b/sound/soc/msm/msm8930.c
index e86db10..c8d4b02 100644
--- a/sound/soc/msm/msm8930.c
+++ b/sound/soc/msm/msm8930.c
@@ -38,6 +38,7 @@
 #define SPK_AMP_POS	0x1
 #define SPK_AMP_NEG	0x2
 #define SPKR_BOOST_GPIO 15
+#define LEFT_SPKR_AMPL_GPIO 15
 #define DEFAULT_PMIC_SPK_GAIN 0x0D
 #define SITAR_EXT_CLK_RATE 12288000
 
@@ -121,6 +122,24 @@
 	return 1;
 }
 
+static int msm8930_cfg_spkr_gpio(int gpio,
+		int enable, const char *gpio_label)
+{
+	int ret = 0;
+
+	pr_debug("%s: Configure %s GPIO %u",
+		__func__, gpio_label, gpio);
+	ret = gpio_request(gpio, gpio_label);
+	if (ret)
+		return ret;
+
+	pr_debug("%s: Enable %s gpio %u\n",
+		__func__, gpio_label, gpio);
+	gpio_direction_output(gpio, enable);
+
+	return ret;
+}
+
 static void msm8960_ext_spk_power_amp_on(u32 spk)
 {
 	int ret = 0;
@@ -139,24 +158,30 @@
 		if ((msm8930_ext_spk_pamp & SPK_AMP_POS) &&
 			(msm8930_ext_spk_pamp & SPK_AMP_NEG)) {
 
-			if (machine_is_msm8930_mtp()
-				|| machine_is_msm8930_fluid()) {
-				pr_debug("%s: Configure Speaker Boost GPIO %u",
-						__func__, SPKR_BOOST_GPIO);
-				ret = gpio_request(SPKR_BOOST_GPIO,
-								   "SPKR_BOOST_EN");
+			if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917) {
+				ret = msm8930_cfg_spkr_gpio(
+						LEFT_SPKR_AMPL_GPIO,
+						1, "LEFT_SPKR_AMPL");
 				if (ret) {
-					pr_err("%s: Failed to configure speaker boost "
-					"gpio %u\n", __func__, SPKR_BOOST_GPIO);
+					pr_err("%s: Failed to config ampl gpio %u\n",
+						__func__, LEFT_SPKR_AMPL_GPIO);
 					return;
 				}
+			} else {
 
-				pr_debug("%s: Enable Speaker boost gpio %u\n",
-					__func__, SPKR_BOOST_GPIO);
-				gpio_direction_output(SPKR_BOOST_GPIO, 1);
+				if (machine_is_msm8930_mtp()
+					|| machine_is_msm8930_fluid()) {
+					ret = msm8930_cfg_spkr_gpio(
+					  SPKR_BOOST_GPIO, 1, "SPKR_BOOST");
+					if (ret) {
+						pr_err("%s: Failure: spkr boost gpio %u\n",
+						  __func__, SPKR_BOOST_GPIO);
+						return;
+					}
+				}
+				pm8xxx_spk_enable(MSM8930_SPK_ON);
 			}
 
-			pm8xxx_spk_enable(MSM8930_SPK_ON);
 			pr_debug("%s: slepping 4 ms after turning on external "
 				" Left Speaker Ampl\n", __func__);
 			usleep_range(4000, 4000);
@@ -175,6 +200,13 @@
 	if (spk & (SPK_AMP_POS | SPK_AMP_NEG)) {
 		if (!msm8930_ext_spk_pamp)
 			return;
+
+		if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917) {
+			gpio_free(LEFT_SPKR_AMPL_GPIO);
+			msm8930_ext_spk_pamp = 0;
+			return;
+		}
+
 		if (machine_is_msm8930_mtp()
 			|| machine_is_msm8930_fluid()) {
 			pr_debug("%s: Free speaker boost gpio %u\n",
@@ -463,7 +495,8 @@
 {
 	int ret = 0;
 	msm8930_pmic_spk_gain = ucontrol->value.integer.value[0];
-	ret = pm8xxx_spk_gain(msm8930_pmic_spk_gain);
+	if (socinfo_get_pmic_model() != PMIC_MODEL_PM8917)
+		ret = pm8xxx_spk_gain(msm8930_pmic_spk_gain);
 	pr_debug("%s: msm8930_pmic_spk_gain = %d"
 			 " ucontrol->value.integer.value[0] = %d\n", __func__,
 			 msm8930_pmic_spk_gain,
@@ -660,8 +693,10 @@
 	mbhc_cfg.gpio_irq = gpio_to_irq(mbhc_cfg.gpio);
 	sitar_hs_detect(codec, &mbhc_cfg);
 
-	/* Initialize default PMIC speaker gain */
-	pm8xxx_spk_gain(DEFAULT_PMIC_SPK_GAIN);
+	if (socinfo_get_pmic_model() != PMIC_MODEL_PM8917) {
+		/* Initialize default PMIC speaker gain */
+		pm8xxx_spk_gain(DEFAULT_PMIC_SPK_GAIN);
+	}
 
 	return 0;
 }
@@ -1015,6 +1050,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..6bd6adc 100644
--- a/sound/soc/msm/msm8960.c
+++ b/sound/soc/msm/msm8960.c
@@ -88,6 +88,11 @@
 module_param(hs_detect_use_gpio, bool, 0444);
 MODULE_PARM_DESC(hs_detect_use_gpio, "Use GPIO for headset detection");
 
+static bool hs_detect_extn_cable;
+module_param(hs_detect_extn_cable, bool, 0444);
+MODULE_PARM_DESC(hs_detect_extn_cable, "Enable extension cable feature");
+
+
 static bool hs_detect_use_firmware;
 module_param(hs_detect_use_firmware, bool, 0444);
 MODULE_PARM_DESC(hs_detect_use_firmware, "Use firmware for headset detection");
@@ -108,6 +113,7 @@
 	.gpio_irq = 0,
 	.gpio_level_insert = 1,
 	.swap_gnd_mic = NULL,
+	.detect_extn_cable = false,
 };
 
 static u32 us_euro_sel_gpio = PM8921_GPIO_PM_TO_SYS(JACK_US_EURO_SEL_GPIO);
@@ -715,20 +721,20 @@
 	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] = 20;
-	btn_low[1] = 21;
-	btn_high[1] = 62;
-	btn_low[2] = 63;
-	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[0] = 10;
+	btn_low[1] = 11;
+	btn_high[1] = 52;
+	btn_low[2] = 53;
+	btn_high[2] = 94;
+	btn_low[3] = 95;
+	btn_high[3] = 133;
+	btn_low[4] = 134;
+	btn_high[4] = 171;
+	btn_low[5] = 172;
+	btn_high[5] = 208;
+	btn_low[6] = 209;
+	btn_high[6] = 244;
+	btn_low[7] = 245;
 	btn_high[7] = 330;
 	n_ready = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_N_READY);
 	n_ready[0] = 80;
@@ -911,9 +917,10 @@
 	snd_soc_dapm_sync(dapm);
 
 	err = snd_soc_jack_new(codec, "Headset Jack",
-			       (SND_JACK_HEADSET | SND_JACK_OC_HPHL |
-				SND_JACK_OC_HPHR | SND_JACK_UNSUPPORTED),
-			       &hs_jack);
+			       (SND_JACK_HEADSET | SND_JACK_LINEOUT |
+				SND_JACK_OC_HPHL | SND_JACK_OC_HPHR |
+				SND_JACK_UNSUPPORTED),
+				&hs_jack);
 	if (err) {
 		pr_err("failed to create new jack\n");
 		return err;
@@ -934,6 +941,8 @@
 	if (hs_detect_use_gpio) {
 		mbhc_cfg.gpio = PM8921_GPIO_PM_TO_SYS(JACK_DETECT_GPIO);
 		mbhc_cfg.gpio_irq = JACK_DETECT_INT;
+		if (hs_detect_extn_cable)
+			mbhc_cfg.detect_extn_cable = true;
 	}
 
 	if (mbhc_cfg.gpio) {
@@ -1348,6 +1357,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,
@@ -1739,13 +1763,21 @@
 		return ret;
 	}
 
-	if (msm8960_configure_headset_mic_gpios()) {
-		pr_err("%s Fail to configure headset mic gpios\n", __func__);
+	if (cpu_is_msm8960()) {
+		if (msm8960_configure_headset_mic_gpios()) {
+			pr_err("%s Fail to configure headset mic gpios\n",
+								__func__);
+			msm8960_headset_gpios_configured = 0;
+		} else
+			msm8960_headset_gpios_configured = 1;
+	} else {
 		msm8960_headset_gpios_configured = 0;
-	} else
-		msm8960_headset_gpios_configured = 1;
+		pr_debug("%s headset GPIO 23 and 35 not configured msm960ab",
+								__func__);
+	}
 
 	mutex_init(&cdc_mclk_mutex);
+
 	return ret;
 
 }
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 3516022..c7820dd 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -13,11 +13,11 @@
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/gpio.h>
-#include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/of_gpio.h>
 #include <linux/platform_device.h>
-#include <linux/gpio.h>
-#include <linux/mfd/pm8xxx/pm8921.h>
 #include <linux/slab.h>
+#include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/qpnp/clkdiv.h>
 #include <sound/core.h>
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
@@ -28,7 +28,7 @@
 #include <qdsp6v2/msm-pcm-routing-v2.h>
 #include "../codecs/wcd9320.h"
 
-/* 8974 machine driver */
+#define DRV_NAME "msm8974-asoc-taiko"
 
 #define PM8921_GPIO_BASE		NR_GPIO_IRQS
 #define PM8921_GPIO_PM_TO_SYS(pm_gpio)  (pm_gpio - 1 + PM8921_GPIO_BASE)
@@ -57,6 +57,11 @@
 #define TABLA_MBHC_DEF_BUTTONS 8
 #define TABLA_MBHC_DEF_RLOADS 5
 
+struct msm8974_asoc_mach_data {
+	int mclk_gpio;
+	u32 mclk_freq;
+};
+
 /* Shared channel numbers for Slimbus ports that connect APQ to MDM. */
 enum {
 	SLIM_1_RX_1 = 145, /* BT-SCO and USB TX */
@@ -76,12 +81,13 @@
 static int msm_slim_0_tx_ch = 1;
 
 static int msm_btsco_rate = BTSCO_RATE_8KHZ;
-static int msm_headset_gpios_configured;
 
 static struct snd_soc_jack hs_jack;
 static struct snd_soc_jack button_jack;
 
 static struct mutex cdc_mclk_mutex;
+static struct q_clkdiv *codec_clk;
+static int clk_users;
 
 static void msm_enable_ext_spk_amp_gpio(u32 spk_amp_gpio)
 {
@@ -309,16 +315,67 @@
 	return 0;
 }
 
-static int msm_mclk_event(struct snd_soc_dapm_widget *w,
+static int msm8974_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
+					bool dapm)
+{
+	int ret = 0;
+	pr_debug("%s: enable = %d clk_users = %d\n",
+		__func__, enable, clk_users);
+
+	mutex_lock(&cdc_mclk_mutex);
+	if (enable) {
+		if (!codec_clk) {
+			dev_err(codec->dev, "%s: did not get Taiko MCLK\n",
+				__func__);
+			return -EINVAL;
+		}
+
+		clk_users++;
+		if (clk_users != 1)
+			return ret;
+
+		ret = qpnp_clkdiv_enable(codec_clk);
+		if (ret) {
+			dev_err(codec->dev, "%s: Error enabling taiko MCLK\n",
+			       __func__);
+			return -ENODEV;
+		}
+		taiko_mclk_enable(codec, 1, dapm);
+	} else {
+		if (clk_users > 0) {
+			clk_users--;
+			if (clk_users == 0) {
+				taiko_mclk_enable(codec, 0, dapm);
+				qpnp_clkdiv_disable(codec_clk);
+			}
+		} else {
+			pr_err("%s: Error releasing Tabla MCLK\n", __func__);
+			ret = -EINVAL;
+		}
+	}
+	mutex_unlock(&cdc_mclk_mutex);
+	return ret;
+}
+
+static int msm8974_mclk_event(struct snd_soc_dapm_widget *w,
 		struct snd_kcontrol *kcontrol, int event)
 {
+	pr_debug("%s: event = %d\n", __func__, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		return msm8974_enable_codec_ext_clk(w->codec, 1, true);
+	case SND_SOC_DAPM_POST_PMD:
+		return msm8974_enable_codec_ext_clk(w->codec, 0, true);
+	}
+
 	return 0;
 }
 
-static const struct snd_soc_dapm_widget msm_dapm_widgets[] = {
+static const struct snd_soc_dapm_widget msm8974_dapm_widgets[] = {
 
 	SND_SOC_DAPM_SUPPLY("MCLK",  SND_SOC_NOPM, 0, 0,
-	msm_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	msm8974_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 
 	SND_SOC_DAPM_SPK("Ext Spk Bottom Pos", msm_spkramp_event),
 	SND_SOC_DAPM_SPK("Ext Spk Bottom Neg", msm_spkramp_event),
@@ -328,7 +385,6 @@
 
 	SND_SOC_DAPM_MIC("Handset Mic", NULL),
 	SND_SOC_DAPM_MIC("Headset Mic", NULL),
-	SND_SOC_DAPM_MIC("Digital Mic1", NULL),
 	SND_SOC_DAPM_MIC("ANCRight Headset Mic", NULL),
 	SND_SOC_DAPM_MIC("ANCLeft Headset Mic", NULL),
 
@@ -338,92 +394,6 @@
 	SND_SOC_DAPM_MIC("Digital Mic4", NULL),
 	SND_SOC_DAPM_MIC("Digital Mic5", NULL),
 	SND_SOC_DAPM_MIC("Digital Mic6", NULL),
-
-};
-
-static const struct snd_soc_dapm_route common_audio_map[] = {
-
-	{"RX_BIAS", NULL, "MCLK"},
-	{"LDO_H", NULL, "MCLK"},
-
-	/* Speaker path */
-	{"Ext Spk Bottom Pos", NULL, "LINEOUT1"},
-	{"Ext Spk Bottom Neg", NULL, "LINEOUT3"},
-
-	{"Ext Spk Top Pos", NULL, "LINEOUT2"},
-	{"Ext Spk Top Neg", NULL, "LINEOUT4"},
-
-	/* Microphone path */
-	{"AMIC1", NULL, "MIC BIAS1 Internal1"},
-	{"MIC BIAS1 Internal1", NULL, "Handset Mic"},
-
-	{"AMIC2", NULL, "MIC BIAS2 External"},
-	{"MIC BIAS2 External", NULL, "Headset Mic"},
-
-	/**
-	 * AMIC3 and AMIC4 inputs are connected to ANC microphones
-	 * These mics are biased differently on CDP and FLUID
-	 * routing entries below are based on bias arrangement
-	 * on FLUID.
-	 */
-	{"AMIC3", NULL, "MIC BIAS3 Internal1"},
-	{"MIC BIAS3 Internal1", NULL, "ANCRight Headset Mic"},
-
-	{"AMIC4", NULL, "MIC BIAS1 Internal2"},
-	{"MIC BIAS1 Internal2", NULL, "ANCLeft Headset Mic"},
-
-	{"HEADPHONE", NULL, "LDO_H"},
-
-	/**
-	 * The digital Mic routes are setup considering
-	 * fluid as default device.
-	 */
-
-	/**
-	 * Digital Mic1. Front Bottom left Digital Mic on Fluid and MTP.
-	 * Digital Mic GM5 on CDP mainboard.
-	 * Conncted to DMIC2 Input on Tabla codec.
-	 */
-	{"DMIC2", NULL, "MIC BIAS1 External"},
-	{"MIC BIAS1 External", NULL, "Digital Mic1"},
-
-	/**
-	 * Digital Mic2. Front Bottom right Digital Mic on Fluid and MTP.
-	 * Digital Mic GM6 on CDP mainboard.
-	 * Conncted to DMIC1 Input on Tabla codec.
-	 */
-	{"DMIC1", NULL, "MIC BIAS1 External"},
-	{"MIC BIAS1 External", NULL, "Digital Mic2"},
-
-	/**
-	 * Digital Mic3. Back Bottom Digital Mic on Fluid.
-	 * Digital Mic GM1 on CDP mainboard.
-	 * Conncted to DMIC4 Input on Tabla codec.
-	 */
-	{"DMIC4", NULL, "MIC BIAS3 External"},
-	{"MIC BIAS3 External", NULL, "Digital Mic3"},
-
-	/**
-	 * Digital Mic4. Back top Digital Mic on Fluid.
-	 * Digital Mic GM2 on CDP mainboard.
-	 * Conncted to DMIC3 Input on Tabla codec.
-	 */
-	{"DMIC3", NULL, "MIC BIAS3 External"},
-	{"MIC BIAS3 External", NULL, "Digital Mic4"},
-
-	/**
-	 * Digital Mic5. Front top Digital Mic on Fluid.
-	 * Digital Mic GM3 on CDP mainboard.
-	 * Conncted to DMIC5 Input on Tabla codec.
-	 */
-	{"DMIC5", NULL, "MIC BIAS4 External"},
-	{"MIC BIAS4 External", NULL, "Digital Mic5"},
-
-	/* Tabla digital Mic6 - back bottom digital Mic on Liquid and
-	 * bottom mic on CDP. FLUID/MTP do not have dmic6 installed.
-	 */
-	{"DMIC6", NULL, "MIC BIAS4 External"},
-	{"MIC BIAS4 External", NULL, "Digital Mic6"},
 };
 
 static const char *const spk_function[] = {"Off", "On"};
@@ -671,11 +641,8 @@
 	if (err < 0)
 		return err;
 
-	snd_soc_dapm_new_controls(dapm, msm_dapm_widgets,
-				ARRAY_SIZE(msm_dapm_widgets));
-
-	snd_soc_dapm_add_routes(dapm, common_audio_map,
-		ARRAY_SIZE(common_audio_map));
+	snd_soc_dapm_new_controls(dapm, msm8974_dapm_widgets,
+				ARRAY_SIZE(msm8974_dapm_widgets));
 
 	snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
 	snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
@@ -790,7 +757,7 @@
 };
 
 /* Digital audio interface glue - connects codec <---> CPU */
-static struct snd_soc_dai_link msm_dai[] = {
+static struct snd_soc_dai_link msm8974_dai[] = {
 	/* FrontEnd DAI Links */
 	{
 		.name = "MSM8974 Media1",
@@ -823,6 +790,22 @@
 		.be_id = MSM_FRONTEND_DAI_VOIP,
 	},
 	{
+		.name = "Circuit-Switch Voice",
+		.stream_name = "CS-Voice",
+		.cpu_dai_name   = "CS-VOICE",
+		.platform_name  = "msm-pcm-voice",
+		.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},
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.be_id = MSM_FRONTEND_DAI_CS_VOICE,
+	},
+	{
 		.name = "MSM8974 LPA",
 		.stream_name = "LPA",
 		.cpu_dai_name	= "MultiMedia3",
@@ -837,6 +820,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",
@@ -923,58 +921,148 @@
 	},
 };
 
-struct snd_soc_card snd_soc_card_msm = {
+struct snd_soc_card snd_soc_card_msm8974 = {
 	.name		= "msm8974-taiko-snd-card",
-	.dai_link	= msm_dai,
-	.num_links	= ARRAY_SIZE(msm_dai),
+	.dai_link	= msm8974_dai,
+	.num_links	= ARRAY_SIZE(msm8974_dai),
 };
 
-static struct platform_device *msm_snd_device;
-
-static void msm_free_headset_mic_gpios(void)
+static int msm8974_prepare_codec_mclk(struct snd_soc_card *card)
 {
-	if (msm_headset_gpios_configured) {
-		gpio_free(PM8921_GPIO_PM_TO_SYS(23));
-		gpio_free(PM8921_GPIO_PM_TO_SYS(35));
-	}
-}
-
-static int __init msm_audio_init(void)
-{
-	int ret = 0;
-
-	mutex_init(&cdc_mclk_mutex);
-	if (!machine_is_msm8974_sim()) {
-		pr_err("%s: Not the right machine type\n", __func__);
-		return -ENODEV;
-	}
-	msm_snd_device = platform_device_alloc("soc-audio", 0);
-	if (!msm_snd_device) {
-		pr_err("Platform device allocation failed\n");
-		return -ENOMEM;
+	struct msm8974_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+	int ret;
+	if (pdata->mclk_gpio) {
+		ret = gpio_request(pdata->mclk_gpio, "TAIKO_CODEC_PMIC_MCLK");
+		if (ret) {
+			dev_err(card->dev,
+				"%s: Failed to request taiko mclk gpio %d\n",
+				__func__, pdata->mclk_gpio);
+			return ret;
+		}
 	}
 
-	platform_set_drvdata(msm_snd_device, &snd_soc_card_msm);
-	ret = platform_device_add(msm_snd_device);
+	codec_clk = qpnp_clkdiv_get(card->dev, "taiko-mclk");
+	if (IS_ERR(codec_clk)) {
+		dev_err(card->dev,
+			"%s: Failed to request taiko mclk from pmic %ld\n",
+			__func__, PTR_ERR(codec_clk));
+		return -ENODEV ;
+	}
+
+	ret = qpnp_clkdiv_config(codec_clk, Q_CLKDIV_XO_DIV_2);
 	if (ret) {
-		platform_device_put(msm_snd_device);
-		return ret;
+		dev_err(card->dev, "%s: Failed to set taiko mclk to %u\n",
+			__func__, pdata->mclk_gpio);
+			return ret;
 	}
-	return ret;
-
+	return 0;
 }
-module_init(msm_audio_init);
 
-static void __exit msm_audio_exit(void)
+static __devinit int msm8974_asoc_machine_probe(struct platform_device *pdev)
 {
-	if (!machine_is_msm8974_sim()) {
-		pr_err("%s: Not the right machine type\n", __func__);
-		return ;
+	struct snd_soc_card *card = &snd_soc_card_msm8974;
+	struct msm8974_asoc_mach_data *pdata;
+	int ret;
+
+	if (!pdev->dev.of_node) {
+		dev_err(&pdev->dev, "No platform supplied from device tree\n");
+		return -EINVAL;
 	}
-	msm_free_headset_mic_gpios();
-	platform_device_unregister(msm_snd_device);
+
+	pdata = devm_kzalloc(&pdev->dev,
+			sizeof(struct msm8974_asoc_mach_data), GFP_KERNEL);
+	if (!pdata) {
+		dev_err(&pdev->dev, "Can't allocate msm8974_asoc_mach_data\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	card->dev = &pdev->dev;
+	platform_set_drvdata(pdev, card);
+	snd_soc_card_set_drvdata(card, pdata);
+
+	ret = snd_soc_of_parse_card_name(card, "qcom,model");
+	if (ret)
+		goto err;
+
+	ret = snd_soc_of_parse_audio_routing(card,
+			"qcom,audio-routing");
+	if (ret)
+		goto err;
+
+	ret = of_property_read_u32(pdev->dev.of_node,
+			"qcom,taiko-mclk-clk-freq", &pdata->mclk_freq);
+	if (ret) {
+		dev_err(&pdev->dev, "Looking up %s property in node %s failed",
+			"qcom,taiko-mclk-clk-freq",
+			pdev->dev.of_node->full_name);
+		goto err;
+	}
+
+	if (pdata->mclk_freq != 9600000) {
+		dev_err(&pdev->dev, "unsupported taiko mclk freq %u\n",
+			pdata->mclk_freq);
+		ret = -EINVAL;
+		goto err;
+	}
+
+	pdata->mclk_gpio = of_get_named_gpio(pdev->dev.of_node,
+				"qcom,cdc-mclk-gpios", 0);
+	if (pdata->mclk_gpio < 0) {
+		dev_err(&pdev->dev,
+			"Looking up %s property in node %s failed %d\n",
+			"qcom, cdc-mclk-gpios", pdev->dev.of_node->full_name,
+			pdata->mclk_gpio);
+		ret = -ENODEV;
+		goto err;
+	}
+
+	ret = msm8974_prepare_codec_mclk(card);
+	if (ret)
+		goto err;
+
+	ret = snd_soc_register_card(card);
+	if (ret) {
+		dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+			ret);
+		goto err;
+	}
+	mutex_init(&cdc_mclk_mutex);
+	return 0;
+err:
+	devm_kfree(&pdev->dev, pdata);
+	return ret;
 }
-module_exit(msm_audio_exit);
+
+static int __devexit msm8974_asoc_machine_remove(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = platform_get_drvdata(pdev);
+	struct msm8974_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+
+	gpio_free(pdata->mclk_gpio);
+	snd_soc_unregister_card(card);
+
+	return 0;
+}
+
+static const struct of_device_id msm8974_asoc_machine_of_match[]  = {
+	{ .compatible = "qcom,msm8974-audio-taiko", },
+	{},
+};
+
+static struct platform_driver msm8974_asoc_machine_driver = {
+	.driver = {
+		.name = DRV_NAME,
+		.owner = THIS_MODULE,
+		.pm = &snd_soc_pm_ops,
+		.of_match_table = msm8974_asoc_machine_of_match,
+	},
+	.probe = msm8974_asoc_machine_probe,
+	.remove = __devexit_p(msm8974_asoc_machine_remove),
+};
+module_platform_driver(msm8974_asoc_machine_driver);
 
 MODULE_DESCRIPTION("ALSA SoC msm");
 MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, msm8974_asoc_machine_of_match);
diff --git a/sound/soc/msm/qdsp6/q6adm.c b/sound/soc/msm/qdsp6/q6adm.c
index 0327e4a..c6970f1 100644
--- a/sound/soc/msm/qdsp6/q6adm.c
+++ b/sound/soc/msm/qdsp6/q6adm.c
@@ -250,6 +250,18 @@
 			}
 			this_adm.apr = NULL;
 		}
+		pr_debug("Resetting calibration blocks");
+		for (i = 0; i < MAX_AUDPROC_TYPES; i++) {
+			/* Device calibration */
+			mem_addr_audproc[i].cal_size = 0;
+			mem_addr_audproc[i].cal_kvaddr = 0;
+			mem_addr_audproc[i].cal_paddr = 0;
+
+			/* Volume calibration */
+			mem_addr_audvol[i].cal_size = 0;
+			mem_addr_audvol[i].cal_kvaddr = 0;
+			mem_addr_audvol[i].cal_paddr = 0;
+		}
 		return 0;
 	}
 
@@ -294,7 +306,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 +720,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 +758,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 +802,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/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index 06be186..3a226b4 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;
@@ -1434,6 +1526,14 @@
 	case FORMAT_DTS_LBR:
 		open.format = DTS_LBR;
 		break;
+	case FORMAT_AMRWB:
+		open.format = AMRWB_FS;
+		pr_debug("q6asm_open_write FORMAT_AMRWB");
+		break;
+	case FORMAT_AMR_WB_PLUS:
+		open.format = AMR_WB_PLUS;
+		pr_debug("q6asm_open_write FORMAT_AMR_WB_PLUS");
+		break;
 	default:
 		pr_err("%s: Invalid format[%d]\n", __func__, format);
 		goto fail_cmd;
@@ -1785,7 +1885,16 @@
 	enc_cfg.enc_blk.cfg.mpcm.sample_rate = rate;
 	enc_cfg.enc_blk.cfg.mpcm.is_signed = 1;
 	enc_cfg.enc_blk.cfg.mpcm.is_interleaved = 1;
-	if (channels == 2) {
+	if (channels == 1) {
+		enc_cfg.enc_blk.cfg.mpcm.channel_mapping[0] = PCM_CHANNEL_FL;
+		enc_cfg.enc_blk.cfg.mpcm.channel_mapping[1] = 0;
+		enc_cfg.enc_blk.cfg.mpcm.channel_mapping[2] = 0;
+		enc_cfg.enc_blk.cfg.mpcm.channel_mapping[3] = 0;
+		enc_cfg.enc_blk.cfg.mpcm.channel_mapping[4] = 0;
+		enc_cfg.enc_blk.cfg.mpcm.channel_mapping[5] = 0;
+		enc_cfg.enc_blk.cfg.mpcm.channel_mapping[6] = 0;
+		enc_cfg.enc_blk.cfg.mpcm.channel_mapping[7] = 0;
+	} else if (channels == 2) {
 		enc_cfg.enc_blk.cfg.mpcm.channel_mapping[0] = PCM_CHANNEL_FL;
 		enc_cfg.enc_blk.cfg.mpcm.channel_mapping[1] = PCM_CHANNEL_FR;
 		enc_cfg.enc_blk.cfg.mpcm.channel_mapping[2] = 0;
@@ -1940,6 +2049,11 @@
 	} else if (num_channels == 2) {
 		channel_mapping[0] = PCM_CHANNEL_FL;
 		channel_mapping[1] = PCM_CHANNEL_FR;
+	} else if (num_channels == 4) {
+		channel_mapping[0] = PCM_CHANNEL_FL;
+		channel_mapping[1] = PCM_CHANNEL_FR;
+		channel_mapping[1] = PCM_CHANNEL_LB;
+		channel_mapping[1] = PCM_CHANNEL_RB;
 	} else if (num_channels == 6) {
 		channel_mapping[0] = PCM_CHANNEL_FC;
 		channel_mapping[1] = PCM_CHANNEL_FL;
@@ -1947,6 +2061,15 @@
 		channel_mapping[3] = PCM_CHANNEL_LB;
 		channel_mapping[4] = PCM_CHANNEL_RB;
 		channel_mapping[5] = PCM_CHANNEL_LFE;
+	} else if (num_channels == 8) {
+		channel_mapping[0] = PCM_CHANNEL_FC;
+		channel_mapping[1] = PCM_CHANNEL_FL;
+		channel_mapping[2] = PCM_CHANNEL_FR;
+		channel_mapping[3] = PCM_CHANNEL_LB;
+		channel_mapping[4] = PCM_CHANNEL_RB;
+		channel_mapping[5] = PCM_CHANNEL_LFE;
+		channel_mapping[6] = PCM_CHANNEL_FLC;
+		channel_mapping[7] = PCM_CHANNEL_FRC;
 	} else {
 		pr_err("%s: ERROR.unsupported num_ch = %u\n", __func__,
 				num_channels);
@@ -2203,6 +2326,11 @@
 	} else if (channels == 2) {
 		channel_mapping[0] = PCM_CHANNEL_FL;
 		channel_mapping[1] = PCM_CHANNEL_FR;
+	} else if (channels == 4) {
+		channel_mapping[0] = PCM_CHANNEL_FL;
+		channel_mapping[1] = PCM_CHANNEL_FR;
+		channel_mapping[1] = PCM_CHANNEL_LB;
+		channel_mapping[1] = PCM_CHANNEL_RB;
 	} else if (channels == 6) {
 		channel_mapping[0] = PCM_CHANNEL_FC;
 		channel_mapping[1] = PCM_CHANNEL_FL;
@@ -2210,6 +2338,15 @@
 		channel_mapping[3] = PCM_CHANNEL_LB;
 		channel_mapping[4] = PCM_CHANNEL_RB;
 		channel_mapping[5] = PCM_CHANNEL_LFE;
+	} else if (channels == 8) {
+		channel_mapping[0] = PCM_CHANNEL_FC;
+		channel_mapping[1] = PCM_CHANNEL_FL;
+		channel_mapping[2] = PCM_CHANNEL_FR;
+		channel_mapping[3] = PCM_CHANNEL_LB;
+		channel_mapping[4] = PCM_CHANNEL_RB;
+		channel_mapping[5] = PCM_CHANNEL_LFE;
+		channel_mapping[6] = PCM_CHANNEL_FLC;
+		channel_mapping[7] = PCM_CHANNEL_FRC;
 	} else {
 		pr_err("%s: ERROR.unsupported num_ch = %u\n", __func__,
 				channels);
@@ -2280,7 +2417,56 @@
 	return -EINVAL;
 }
 
+int q6asm_media_format_block_amrwbplus(struct audio_client *ac,
+					struct asm_amrwbplus_cfg *cfg)
+{
+	struct asm_stream_media_format_update fmt;
+	int rc = 0;
+	pr_debug("q6asm_media_format_block_amrwbplus");
 
+	pr_debug("%s:session[%d]band-mode[%d]frame-fmt[%d]ch[%d]\n",
+		__func__,
+		ac->session,
+		cfg->amr_band_mode,
+		cfg->amr_frame_fmt,
+		cfg->num_channels);
+
+	q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
+
+	fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FORMAT_UPDATE;
+
+	fmt.format = AMR_WB_PLUS;
+	fmt.cfg_size = cfg->size_bytes;
+
+	fmt.write_cfg.amrwbplus_cfg.size_bytes    = cfg->size_bytes;
+	fmt.write_cfg.amrwbplus_cfg.version       = cfg->version;
+	fmt.write_cfg.amrwbplus_cfg.num_channels  = cfg->num_channels;
+	fmt.write_cfg.amrwbplus_cfg.amr_band_mode = cfg->amr_band_mode;
+	fmt.write_cfg.amrwbplus_cfg.amr_dtx_mode  = cfg->amr_dtx_mode;
+	fmt.write_cfg.amrwbplus_cfg.amr_frame_fmt = cfg->amr_frame_fmt;
+	fmt.write_cfg.amrwbplus_cfg.amr_lsf_idx   = cfg->amr_lsf_idx;
+
+	pr_debug("%s: num_channels=%x amr_band_mode=%d amr_frame_fmt=%d\n",
+			__func__,
+			cfg->num_channels,
+			cfg->amr_band_mode,
+			cfg->amr_frame_fmt);
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
+	if (rc < 0) {
+		pr_err("%s:Comamnd media format update failed..\n", __func__);
+		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 FORMAT_UPDATE\n", __func__);
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
 int q6asm_media_format_block_multi_aac(struct audio_client *ac,
 				struct asm_aac_cfg *cfg)
 {
@@ -2352,6 +2538,9 @@
 	case FORMAT_AMRWB:
 		fmt.format = AMRWB_FS;
 		break;
+	case FORMAT_AMR_WB_PLUS:
+		fmt.format = AMR_WB_PLUS;
+		break;
 	case FORMAT_AMRNB:
 		fmt.format = AMRNB_FS;
 		break;
diff --git a/sound/soc/msm/qdsp6/q6voice.h b/sound/soc/msm/qdsp6/q6voice.h
index 1cb2878..34b1b52 100644
--- a/sound/soc/msm/qdsp6/q6voice.h
+++ b/sound/soc/msm/qdsp6/q6voice.h
@@ -13,7 +13,7 @@
 #define __QDSP6VOICE_H__
 
 #include <mach/qdsp6v2/apr.h>
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
 
 #define MAX_VOC_PKT_SIZE 642
 #define SESSION_NAME_LEN 21
diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
index 360744a..6f3249a 100644
--- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
@@ -279,7 +279,6 @@
 static int msm_compr_open(struct snd_pcm_substream *substream)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
 	struct compr_audio *compr;
 	struct msm_audio *prtd;
 	int ret = 0;
@@ -319,9 +318,6 @@
 	pr_info("%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->session_id, substream->stream);
-
 	prtd->cmd_ack = 1;
 
 	ret = snd_pcm_hw_constraint_list(runtime, 0,
@@ -460,6 +456,7 @@
 				struct snd_pcm_hw_params *params)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
 	struct compr_audio *compr = runtime->private_data;
 	struct msm_audio *prtd = &compr->prtd;
 	struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
@@ -477,6 +474,9 @@
 		pr_err("%s: Session out open failed\n", __func__);
 		return -ENOMEM;
 	}
+	msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
+			prtd->session_id, substream->stream);
+
 	ret = q6asm_set_io_mode(prtd->audio_client, ASYNC_IO_MODE);
 	if (ret < 0) {
 		pr_err("%s: Set IO mode failed\n", __func__);
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index 485569b..3eab972 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -400,70 +400,23 @@
 	int rc = 0;
 
 	if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
-		/* PORT START should be set if prepare called in active state */
-		rc = afe_q6_interface_prepare();
+		switch (dai->id) {
+		case VOICE_PLAYBACK_TX:
+		case VOICE_RECORD_TX:
+		case VOICE_RECORD_RX:
+			rc = afe_start_pseudo_port(dai->id);
+		default:
+			rc = afe_port_start(dai->id, &dai_data->port_config,
+					    dai_data->rate);
+		}
+
 		if (IS_ERR_VALUE(rc))
-			dev_err(dai->dev, "fail to open AFE APR\n");
-	}
-	return rc;
-}
-
-static int msm_dai_q6_trigger(struct snd_pcm_substream *substream, int cmd,
-		struct snd_soc_dai *dai)
-{
-	struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
-	int rc = 0;
-
-	/*
-	 * Start/stop port without waiting for Q6 AFE response. Need to have
-	 * native q6 AFE driver propagates AFE response in order to handle
-	 * port start/stop command error properly if error does arise.
-	 */
-	pr_debug("%s:port:%d  cmd:%d dai_data->status_mask = %ld",
-		__func__, dai->id, cmd, *dai_data->status_mask);
-	switch (cmd) {
-	case SNDRV_PCM_TRIGGER_START:
-	case SNDRV_PCM_TRIGGER_RESUME:
-	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
-			switch (dai->id) {
-			case VOICE_PLAYBACK_TX:
-			case VOICE_RECORD_TX:
-			case VOICE_RECORD_RX:
-				afe_pseudo_port_start_nowait(dai->id);
-				break;
-			default:
-				afe_port_start_nowait(dai->id,
-					&dai_data->port_config, dai_data->rate);
-				break;
-			}
+			dev_err(dai->dev, "fail to open AFE port %x\n",
+				dai->id);
+		else
 			set_bit(STATUS_PORT_STARTED,
 				dai_data->status_mask);
-		}
-		break;
-	case SNDRV_PCM_TRIGGER_STOP:
-	case SNDRV_PCM_TRIGGER_SUSPEND:
-	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
-			switch (dai->id) {
-			case VOICE_PLAYBACK_TX:
-			case VOICE_RECORD_TX:
-			case VOICE_RECORD_RX:
-				afe_pseudo_port_stop_nowait(dai->id);
-				break;
-			default:
-				afe_port_stop_nowait(dai->id);
-				break;
-			}
-			clear_bit(STATUS_PORT_STARTED,
-				dai_data->status_mask);
-		}
-		break;
-
-	default:
-		rc = -EINVAL;
 	}
-
 	return rc;
 }
 
@@ -799,7 +752,6 @@
 
 static struct snd_soc_dai_ops msm_dai_q6_ops = {
 	.prepare	= msm_dai_q6_prepare,
-	.trigger	= msm_dai_q6_trigger,
 	.hw_params	= msm_dai_q6_hw_params,
 	.shutdown	= msm_dai_q6_shutdown,
 	.set_fmt	= msm_dai_q6_set_fmt,
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
index 047e0f0..19e0464 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
@@ -57,11 +57,11 @@
 	.rate_max =             48000,
 	.channels_min =         1,
 	.channels_max =         2,
-	.buffer_bytes_max =     2 * 1024 * 1024,
+	.buffer_bytes_max =     1024 * 1024,
 	.period_bytes_min =	128 * 1024,
-	.period_bytes_max =     512 * 1024,
+	.period_bytes_max =     256 * 1024,
 	.periods_min =          4,
-	.periods_max =          16,
+	.periods_max =          8,
 	.fifo_size =            0,
 };
 
@@ -87,7 +87,6 @@
 	unsigned long flag = 0;
 	int i = 0;
 
-	pr_debug("%s\n", __func__);
 	spin_lock_irqsave(&the_locks.event_lock, flag);
 	switch (opcode) {
 	case ASM_DATA_EVENT_WRITE_DONE_V2: {
@@ -110,12 +109,16 @@
 			break;
 		} else
 			atomic_set(&prtd->pending_buffer, 0);
-		if (runtime->status->hw_ptr >= runtime->control->appl_ptr)
-			break;
+
+		buf = prtd->audio_client->port[IN].buf;
+		if (runtime->status->hw_ptr >= runtime->control->appl_ptr) {
+			memset((void *)buf[0].data +
+				(prtd->out_head * prtd->pcm_count),
+				0, prtd->pcm_count);
+		}
 		pr_debug("%s:writing %d bytes of buffer to dsp 2\n",
 				__func__, prtd->pcm_count);
 
-		buf = prtd->audio_client->port[IN].buf;
 		param.paddr = (unsigned long)buf[0].phys
 				+ (prtd->out_head * prtd->pcm_count);
 		param.len = prtd->pcm_count;
@@ -230,11 +233,13 @@
 		pr_debug("SNDRV_PCM_TRIGGER_START\n");
 		q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
 		atomic_set(&prtd->start, 1);
+		atomic_set(&prtd->stop, 0);
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
 		pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
 		audio_ocmem_process_req(AUDIO, false);
 		atomic_set(&prtd->start, 0);
+		atomic_set(&prtd->stop, 1);
 		if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
 			break;
 		break;
@@ -322,6 +327,7 @@
 
 	prtd->dsp_cnt = 0;
 	atomic_set(&prtd->pending_buffer, 1);
+	atomic_set(&prtd->stop, 1);
 	runtime->private_data = prtd;
 	lpa_audio.prtd = prtd;
 	lpa_set_volume(lpa_audio.volume);
@@ -365,7 +371,8 @@
 	To issue EOS to dsp, we need to be run state otherwise
 	EOS is not honored.
 	*/
-	if (msm_routing_check_backend_enabled(soc_prtd->dai_link->be_id)) {
+	if (msm_routing_check_backend_enabled(soc_prtd->dai_link->be_id) &&
+		(!atomic_read(&prtd->stop))) {
 		rc = q6asm_run(prtd->audio_client, 0, 0, 0);
 		atomic_set(&prtd->pending_buffer, 0);
 		prtd->cmd_ack = 0;
@@ -385,6 +392,7 @@
 	q6asm_audio_client_buf_free_contiguous(dir,
 				prtd->audio_client);
 
+	atomic_set(&prtd->stop, 1);
 	pr_debug("%s\n", __func__);
 	msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
 		SNDRV_PCM_STREAM_PLAYBACK);
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
index c9f9593..7483bb6 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -107,7 +107,6 @@
 	uint32_t idx = 0;
 	uint32_t size = 0;
 
-	pr_err("%s\n", __func__);
 	switch (opcode) {
 	case ASM_DATA_EVENT_WRITE_DONE_V2: {
 		pr_debug("ASM_DATA_EVENT_WRITE_DONE_V2\n");
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h
index 44395b7..22bf0cc 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h
@@ -72,6 +72,7 @@
 	int close_ack;
 	int cmd_ack;
 	atomic_t start;
+	atomic_t stop;
 	atomic_t out_count;
 	atomic_t in_count;
 	atomic_t out_needed;
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
index 206e881..f1e0f3a 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
@@ -466,6 +466,9 @@
 
 static __devinit int msm_pcm_probe(struct platform_device *pdev)
 {
+	if (pdev->dev.of_node)
+		dev_set_name(&pdev->dev, "%s", "msm-pcm-voice");
+
 	pr_debug("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
 	return snd_soc_register_platform(&pdev->dev,
 				   &msm_soc_platform);
@@ -477,10 +480,17 @@
 	return 0;
 }
 
+static const struct of_device_id msm_voice_dt_match[] = {
+	{.compatible = "qcom,msm-pcm-voice"},
+	{}
+};
+MODULE_DEVICE_TABLE(of, msm_voice_dt_match);
+
 static struct platform_driver msm_pcm_driver = {
 	.driver = {
 		.name = "msm-pcm-voice",
 		.owner = THIS_MODULE,
+		.of_match_table = msm_voice_dt_match,
 	},
 	.probe = msm_pcm_probe,
 	.remove = __devexit_p(msm_pcm_remove),
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 756cb18..0b25545 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -30,6 +30,7 @@
 	atomic_t state;
 	atomic_t status;
 	wait_queue_head_t wait[AFE_MAX_PORTS];
+	struct task_struct *task;
 	void (*tx_cb) (uint32_t opcode,
 		uint32_t token, uint32_t *payload, void *priv);
 	void (*rx_cb) (uint32_t opcode,
@@ -58,6 +59,9 @@
 			atomic_set(&this_afe.state, 0);
 			this_afe.apr = NULL;
 		}
+		/* send info to user */
+		pr_debug("task_name = %s pid = %d\n",
+			this_afe.task->comm, this_afe.task->pid);
 		return 0;
 	}
 	pr_debug("%s:opcode = 0x%x cmd = 0x%x status = 0x%x\n",
@@ -248,7 +252,7 @@
 		afe_send_cal_block(RX_CAL, port_id);
 }
 
-int afe_port_start_nowait(u16 port_id, union afe_port_config *afe_config,
+int afe_port_start(u16 port_id, union afe_port_config *afe_config,
 	u32 rate) /* This function is no blocking */
 {
 	struct afe_port_cmd_device_start start;
@@ -274,8 +278,9 @@
 		port_id = VIRTUAL_ID_TO_PORTID(port_id);
 
 	ret = afe_q6_interface_prepare();
-	if (ret != 0)
+	if (IS_ERR_VALUE(ret))
 		return ret;
+
 	if (q6audio_validate_port(port_id) < 0) {
 		pr_err("%s: Failed : Invalid Port id = %d\n", __func__,
 				port_id);
@@ -338,6 +343,8 @@
 
 	config.port = *afe_config;
 
+	atomic_set(&this_afe.state, 1);
+	atomic_set(&this_afe.status, 0);
 	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &config);
 	if (ret < 0) {
 		pr_err("%s: AFE enable for port %d failed\n", __func__,
@@ -345,7 +352,20 @@
 		ret = -EINVAL;
 		goto fail_cmd;
 	}
+	ret = wait_event_timeout(this_afe.wait[index],
+				(atomic_read(&this_afe.state) == 0),
+					msecs_to_jiffies(TIMEOUT_MS));
 
+	if (!ret) {
+		pr_err("%s: wait_event timeout IF CONFIG\n", __func__);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+	if (atomic_read(&this_afe.status) != 0) {
+		pr_err("%s: config cmd failed\n", __func__);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
 	/* send AFE cal */
 	afe_send_cal(port_id);
 
@@ -360,6 +380,7 @@
 	pr_debug("%s: cmd device start opcode[0x%x] port id[0x%x]\n",
 		 __func__, start.hdr.opcode, start.port_id);
 
+	atomic_set(&this_afe.state, 1);
 	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
 
 	if (IS_ERR_VALUE(ret)) {
@@ -369,6 +390,21 @@
 		goto fail_cmd;
 	}
 
+	ret = wait_event_timeout(this_afe.wait[index],
+				(atomic_read(&this_afe.state) == 0),
+					msecs_to_jiffies(TIMEOUT_MS));
+
+	if (!ret) {
+		pr_err("%s: wait_event timeout PORT START\n", __func__);
+		 ret = -EINVAL;
+		goto fail_cmd;
+	}
+	if (this_afe.task != current)
+		this_afe.task = current;
+
+	pr_debug("task_name = %s pid = %d\n",
+		this_afe.task->comm, this_afe.task->pid);
+
 	return 0;
 
 fail_cmd:
@@ -506,8 +542,7 @@
 	config.pdata.param_size =  sizeof(config.port);
 
 	config.port = *afe_config;
-	pr_debug("%s: param PL size=%d iparam_size[%d][%d %d %d %d]"
-		" param_id[%x]\n",
+	pr_debug("%s: param PL size=%d iparam_size[%d][%d %d %d %d] param_id[%x]\n",
 		__func__, config.param.payload_size, config.pdata.param_size,
 		sizeof(config), sizeof(config.param), sizeof(config.port),
 		sizeof(struct apr_hdr), config.pdata.param_id);
@@ -586,25 +621,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 +646,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;
@@ -654,8 +688,8 @@
 
 	/* RX ports numbers are even .TX ports numbers are odd. */
 	if (port_id % 2 == 0) {
-		pr_err("%s: Failed : afe loopback gain only for TX ports."
-			" port_id %d\n", __func__, port_id);
+		pr_err("%s: Failed : afe loopback gain only for TX ports. port_id %d\n",
+				__func__, port_id);
 		ret = -EINVAL;
 		goto fail_cmd;
 	}
@@ -667,26 +701,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 +730,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;
@@ -1322,7 +1354,7 @@
 			else
 				base = 10;
 
-			if (strict_strtoul(token, base, &param1[cnt]) != 0)
+			if (kstrtoul(token, base, &param1[cnt]) != 0)
 				return -EINVAL;
 
 			token = strsep(&buf, " ");
@@ -1392,8 +1424,7 @@
 			}
 
 			if (param[1] < 0 || param[1] > 100) {
-				pr_err("%s: Error, volume shoud be 0 to 100"
-					" percentage param = %lu\n",
+				pr_err("%s: Error, volume shoud be 0 to 100 percentage param = %lu\n",
 					__func__, param[1]);
 				rc = -EINVAL;
 				goto afe_error;
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index a3af263..714b2ce 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -136,7 +136,7 @@
 			kfree(temp);
 			return -EFAULT;
 		}
-		if (!strict_strtol(temp, 10, &out_enable_flag)) {
+		if (!kstrtol(temp, 10, &out_enable_flag)) {
 			kfree(temp);
 			return count;
 		}
@@ -177,7 +177,7 @@
 			kfree(temp);
 			return -EFAULT;
 		}
-		if (!strict_strtol(temp, 10, &in_enable_flag)) {
+		if (!kstrtol(temp, 10, &in_enable_flag)) {
 			kfree(temp);
 			return count;
 		}
@@ -347,7 +347,7 @@
 	int rc = 0;
 	pr_debug("%s: Session id %d\n", __func__, ac->session);
 	mutex_lock(&ac->cmd_lock);
-	if (ac->io_mode == SYNC_IO_MODE) {
+	if (ac->io_mode & SYNC_IO_MODE) {
 		port = &ac->port[dir];
 		if (!port->buf) {
 			mutex_unlock(&ac->cmd_lock);
@@ -454,7 +454,7 @@
 	if (!ac || !ac->session)
 		return;
 	pr_debug("%s: Session id %d\n", __func__, ac->session);
-	if (ac->io_mode == SYNC_IO_MODE) {
+	if (ac->io_mode & SYNC_IO_MODE) {
 		for (loopcnt = 0; loopcnt <= OUT; loopcnt++) {
 			port = &ac->port[loopcnt];
 			if (!port->buf)
@@ -603,7 +603,7 @@
 	if (ac->session <= 0 || ac->session > 8)
 		goto fail;
 
-	if (ac->io_mode == SYNC_IO_MODE) {
+	if (ac->io_mode & SYNC_IO_MODE) {
 		if (ac->port[dir].buf) {
 			pr_debug("%s: buffer already allocated\n", __func__);
 			return 0;
@@ -973,7 +973,7 @@
 		pr_debug("%s: Rxed opcode[0x%x] status[0x%x] token[%d]",
 				__func__, payload[0], payload[1],
 				data->token);
-		if (ac->io_mode == SYNC_IO_MODE) {
+		if (ac->io_mode & SYNC_IO_MODE) {
 			if (port->buf == NULL) {
 				pr_err("%s: Unexpected Write Done\n",
 								__func__);
@@ -1025,7 +1025,7 @@
 				payload[READDONE_IDX_SEQ_ID],
 				payload[READDONE_IDX_NUMFRAMES]);
 
-		if (ac->io_mode == SYNC_IO_MODE) {
+		if (ac->io_mode & SYNC_IO_MODE) {
 			if (port->buf == NULL) {
 				pr_err("%s: Unexpected Write Done\n", __func__);
 				return -EINVAL;
@@ -1060,8 +1060,8 @@
 		pr_debug("%s: ASM_SESSION_CMDRSP_GET_SESSIONTIME_V3, payload[0] = %d, payload[1] = %d, payload[2] = %d\n",
 				 __func__,
 				 payload[0], payload[1], payload[2]);
-		ac->time_stamp = (uint64_t)(((uint64_t)payload[1] << 32) |
-				payload[2]);
+		ac->time_stamp = (uint64_t)(((uint64_t)payload[2] << 32) |
+				payload[1]);
 		if (atomic_read(&ac->cmd_state)) {
 			atomic_set(&ac->cmd_state, 0);
 			wake_up(&ac->cmd_wait);
@@ -1092,7 +1092,7 @@
 	if (!ac || ((dir != IN) && (dir != OUT)))
 		return NULL;
 
-	if (ac->io_mode == SYNC_IO_MODE) {
+	if (ac->io_mode & SYNC_IO_MODE) {
 		port = &ac->port[dir];
 
 		mutex_lock(&port->lock);
@@ -1186,7 +1186,7 @@
 	if (!ac || (dir != OUT))
 		return ret;
 
-	if (ac->io_mode == SYNC_IO_MODE) {
+	if (ac->io_mode & SYNC_IO_MODE) {
 		port = &ac->port[dir];
 
 		mutex_lock(&port->lock);
@@ -2825,7 +2825,7 @@
 		pr_err("APR handle NULL\n");
 		return -EINVAL;
 	}
-	if (ac->io_mode == SYNC_IO_MODE) {
+	if (ac->io_mode & SYNC_IO_MODE) {
 		port = &ac->port[OUT];
 
 		q6asm_add_hdr(ac, &read.hdr, sizeof(read), FALSE);
@@ -2888,7 +2888,7 @@
 		pr_err("APR handle NULL\n");
 		return -EINVAL;
 	}
-	if (ac->io_mode == SYNC_IO_MODE) {
+	if (ac->io_mode & SYNC_IO_MODE) {
 		port = &ac->port[OUT];
 
 		q6asm_add_hdr_async(ac, &read.hdr, sizeof(read), FALSE);
@@ -2969,12 +2969,10 @@
 	write.timestamp_lsw = param->lsw_ts;
 	liomode = (ASYNC_IO_MODE | NT_MODE);
 
-	if (ac->io_mode == liomode) {
-		pr_info("%s: subtracting 32 for header\n", __func__);
+	if (ac->io_mode == liomode)
 		lbuf_addr_lsw = (write.buf_addr_lsw - 32);
-	} else{
+	else
 		lbuf_addr_lsw = write.buf_addr_lsw;
-	}
 
 	pr_debug("%s: token[0x%x], buf_addr_lsw[0x%x], buf_size[0x%x], ts_msw[0x%x], ts_lsw[0x%x], lbuf_addr_lsw: 0x[%x]\n",
 		__func__,
@@ -3034,12 +3032,10 @@
 	read.buf_size = param->len;
 	read.seq_id = param->uid;
 	liomode = (NT_MODE | ASYNC_IO_MODE);
-	if (ac->io_mode == liomode) {
-		pr_info("%s: subtracting 32 for header\n", __func__);
+	if (ac->io_mode == liomode)
 		lbuf_addr_lsw = (read.buf_addr_lsw - 32);
-	} else{
+	else
 		lbuf_addr_lsw = read.buf_addr_lsw;
-	}
 
 	list_for_each_safe(ptr, next, &ac->port[IN].mem_map_handle) {
 		buf_node = list_entry(ptr, struct asm_buffer_node, list);
@@ -3075,7 +3071,7 @@
 		return -EINVAL;
 	}
 	pr_debug("%s: session[%d] len=%d", __func__, ac->session, len);
-	if (ac->io_mode == SYNC_IO_MODE) {
+	if (ac->io_mode & SYNC_IO_MODE) {
 		port = &ac->port[IN];
 
 		q6asm_add_hdr(ac, &write.hdr, sizeof(write),
@@ -3143,7 +3139,7 @@
 		return -EINVAL;
 	}
 	pr_debug("%s: session[%d] len=%d", __func__, ac->session, len);
-	if (ac->io_mode == SYNC_IO_MODE) {
+	if (ac->io_mode & SYNC_IO_MODE) {
 		port = &ac->port[IN];
 
 		q6asm_add_hdr_async(ac, &write.hdr, sizeof(write),
@@ -3352,7 +3348,7 @@
 	int loopcnt = 0;
 	struct audio_port_data *port = NULL;
 
-	if (ac->io_mode == SYNC_IO_MODE) {
+	if (ac->io_mode & SYNC_IO_MODE) {
 		mutex_lock(&ac->cmd_lock);
 		for (loopcnt = 0; loopcnt <= OUT; loopcnt++) {
 			port = &ac->port[loopcnt];
diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c
index 4e11dfe..f84b456 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.c
+++ b/sound/soc/msm/qdsp6v2/q6voice.c
@@ -50,19 +50,6 @@
 static int voice_send_set_device_cmd(struct voice_data *v);
 static int voice_send_disable_vocproc_cmd(struct voice_data *v);
 static int voice_send_vol_index_cmd(struct voice_data *v);
-static int voice_send_cvp_map_memory_cmd(struct voice_data *v);
-static int voice_send_cvp_unmap_memory_cmd(struct voice_data *v);
-static int voice_send_cvs_map_memory_cmd(struct voice_data *v);
-static int voice_send_cvs_unmap_memory_cmd(struct voice_data *v);
-static int voice_send_cvs_register_cal_cmd(struct voice_data *v);
-static int voice_send_cvs_deregister_cal_cmd(struct voice_data *v);
-static int voice_send_cvp_register_cal_cmd(struct voice_data *v);
-static int voice_send_cvp_deregister_cal_cmd(struct voice_data *v);
-static int voice_send_cvp_register_vol_cal_table_cmd(struct voice_data *v);
-static int voice_send_cvp_deregister_vol_cal_table_cmd(struct voice_data *v);
-static int voice_send_set_widevoice_enable_cmd(struct voice_data *v);
-static int voice_send_set_pp_enable_cmd(struct voice_data *v,
-					uint32_t module_id, int enable);
 static int voice_cvs_stop_playback(struct voice_data *v);
 static int voice_cvs_start_playback(struct voice_data *v);
 static int voice_cvs_start_record(struct voice_data *v, uint32_t rec_mode);
@@ -223,7 +210,6 @@
 			goto err;
 		}
 
-		rtac_set_voice_handle(RTAC_CVS, common.apr_q6_cvs);
 	}
 
 	if (common.apr_q6_cvp == NULL) {
@@ -238,7 +224,6 @@
 			goto err;
 		}
 
-		rtac_set_voice_handle(RTAC_CVP, common.apr_q6_cvp);
 	}
 
 	mutex_unlock(&common.common_lock);
@@ -249,7 +234,6 @@
 	if (common.apr_q6_cvs != NULL) {
 		apr_deregister(common.apr_q6_cvs);
 		common.apr_q6_cvs = NULL;
-		rtac_set_voice_handle(RTAC_CVS, NULL);
 	}
 	if (common.apr_q6_mvm != NULL) {
 		apr_deregister(common.apr_q6_mvm);
@@ -278,7 +262,8 @@
 		return -EINVAL;
 	}
 	pr_debug("%s: VoLTE command to MVM\n", __func__);
-	if (is_volte_session(v->session_id)) {
+	if (is_volte_session(v->session_id) ||
+		is_voice_session(v->session_id)) {
 		mvm_handle = voice_get_mvm_handle(v);
 		mvm_voice_ctl_cmd.hdr.hdr_field = APR_HDR_FIELD(
 						APR_MSG_TYPE_SEQ_CMD,
@@ -1211,765 +1196,6 @@
 	return -EINVAL;
 }
 
-static int voice_send_cvs_register_cal_cmd(struct voice_data *v)
-{
-	struct cvs_register_cal_data_cmd cvs_reg_cal_cmd;
-	struct acdb_cal_block cal_block;
-	int ret = 0;
-	void *apr_cvs;
-	u16 cvs_handle;
-	uint32_t cal_paddr;
-
-	/* get the cvs cal data */
-	get_all_vocstrm_cal(&cal_block);
-	if (cal_block.cal_size == 0)
-		goto fail;
-
-	if (v == NULL) {
-		pr_err("%s: v is NULL\n", __func__);
-		return -EINVAL;
-	}
-	apr_cvs = common.apr_q6_cvs;
-
-	if (!apr_cvs) {
-		pr_err("%s: apr_cvs is NULL.\n", __func__);
-		return -EINVAL;
-	}
-
-	if (is_voip_session(v->session_id)) {
-		if (common.cvs_cal.buf) {
-			cal_paddr = common.cvs_cal.phy;
-
-			memcpy(common.cvs_cal.buf,
-				(void *) cal_block.cal_kvaddr,
-				cal_block.cal_size);
-		} else {
-			return -EINVAL;
-		}
-	} else {
-		cal_paddr = cal_block.cal_paddr;
-	}
-
-	cvs_handle = voice_get_cvs_handle(v);
-
-	/* fill in the header */
-	cvs_reg_cal_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
-				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
-	cvs_reg_cal_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
-				sizeof(cvs_reg_cal_cmd) - APR_HDR_SIZE);
-	cvs_reg_cal_cmd.hdr.src_port = v->session_id;
-	cvs_reg_cal_cmd.hdr.dest_port = cvs_handle;
-	cvs_reg_cal_cmd.hdr.token = 0;
-	cvs_reg_cal_cmd.hdr.opcode = VSS_ISTREAM_CMD_REGISTER_CALIBRATION_DATA;
-
-	cvs_reg_cal_cmd.cvs_cal_data.phys_addr = cal_paddr;
-	cvs_reg_cal_cmd.cvs_cal_data.mem_size = cal_block.cal_size;
-
-	v->cvs_state = CMD_STATUS_FAIL;
-	ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_reg_cal_cmd);
-	if (ret < 0) {
-		pr_err("Fail: sending cvs cal,\n");
-		goto fail;
-	}
-	ret = wait_event_timeout(v->cvs_wait,
-			(v->cvs_state == CMD_STATUS_SUCCESS),
-			msecs_to_jiffies(TIMEOUT_MS));
-	if (!ret) {
-		pr_err("%s: wait_event timeout\n", __func__);
-		goto fail;
-	}
-	return 0;
-fail:
-	return -EINVAL;
-
-}
-
-static int voice_send_cvs_deregister_cal_cmd(struct voice_data *v)
-{
-	struct cvs_deregister_cal_data_cmd cvs_dereg_cal_cmd;
-	struct acdb_cal_block cal_block;
-	int ret = 0;
-	void *apr_cvs;
-	u16 cvs_handle;
-
-	get_all_vocstrm_cal(&cal_block);
-	if (cal_block.cal_size == 0)
-		return 0;
-
-	if (v == NULL) {
-		pr_err("%s: v is NULL\n", __func__);
-		return -EINVAL;
-	}
-	apr_cvs = common.apr_q6_cvs;
-
-	if (!apr_cvs) {
-		pr_err("%s: apr_cvs is NULL.\n", __func__);
-		return -EINVAL;
-	}
-	cvs_handle = voice_get_cvs_handle(v);
-
-	/* fill in the header */
-	cvs_dereg_cal_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
-				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
-	cvs_dereg_cal_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
-				sizeof(cvs_dereg_cal_cmd) - APR_HDR_SIZE);
-	cvs_dereg_cal_cmd.hdr.src_port = v->session_id;
-	cvs_dereg_cal_cmd.hdr.dest_port = cvs_handle;
-	cvs_dereg_cal_cmd.hdr.token = 0;
-	cvs_dereg_cal_cmd.hdr.opcode =
-			VSS_ISTREAM_CMD_DEREGISTER_CALIBRATION_DATA;
-
-	v->cvs_state = CMD_STATUS_FAIL;
-	ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_dereg_cal_cmd);
-	if (ret < 0) {
-		pr_err("Fail: sending cvs cal,\n");
-		goto fail;
-	}
-	ret = wait_event_timeout(v->cvs_wait,
-			(v->cvs_state == CMD_STATUS_SUCCESS),
-			msecs_to_jiffies(TIMEOUT_MS));
-	if (!ret) {
-		pr_err("%s: wait_event timeout\n", __func__);
-		goto fail;
-	}
-	return 0;
-fail:
-	return -EINVAL;
-
-}
-
-static int voice_send_cvp_map_memory_cmd(struct voice_data *v)
-{
-	struct vss_map_memory_cmd cvp_map_mem_cmd;
-	struct acdb_cal_block cal_block;
-	int ret = 0;
-	void *apr_cvp;
-	u16 cvp_handle;
-	uint32_t cal_paddr;
-
-	/* get all cvp cal data */
-	get_all_cvp_cal(&cal_block);
-	if (cal_block.cal_size == 0)
-		goto fail;
-
-	if (v == NULL) {
-		pr_err("%s: v is NULL\n", __func__);
-		return -EINVAL;
-	}
-	apr_cvp = common.apr_q6_cvp;
-
-	if (!apr_cvp) {
-		pr_err("%s: apr_cvp is NULL.\n", __func__);
-		return -EINVAL;
-	}
-
-	if (is_voip_session(v->session_id)) {
-		if (common.cvp_cal.buf)
-			cal_paddr = common.cvp_cal.phy;
-		else
-			return -EINVAL;
-	} else {
-		cal_paddr = cal_block.cal_paddr;
-	}
-	cvp_handle = voice_get_cvp_handle(v);
-
-	/* fill in the header */
-	cvp_map_mem_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
-				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
-	cvp_map_mem_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
-				sizeof(cvp_map_mem_cmd) - APR_HDR_SIZE);
-	cvp_map_mem_cmd.hdr.src_port = v->session_id;
-	cvp_map_mem_cmd.hdr.dest_port = cvp_handle;
-	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__,
-		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;
-	cvp_map_mem_cmd.vss_map_mem.mem_pool_id =
-				VSS_ICOMMON_MAP_MEMORY_SHMEM8_4K_POOL;
-
-	v->cvp_state = CMD_STATUS_FAIL;
-	ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_map_mem_cmd);
-	if (ret < 0) {
-		pr_err("Fail: sending cvp cal,\n");
-		goto fail;
-	}
-	ret = wait_event_timeout(v->cvp_wait,
-			(v->cvp_state == CMD_STATUS_SUCCESS),
-			msecs_to_jiffies(TIMEOUT_MS));
-	if (!ret) {
-		pr_err("%s: wait_event timeout\n", __func__);
-		goto fail;
-	}
-	return 0;
-fail:
-	return -EINVAL;
-
-}
-
-static int voice_send_cvp_unmap_memory_cmd(struct voice_data *v)
-{
-	struct vss_unmap_memory_cmd cvp_unmap_mem_cmd;
-	struct acdb_cal_block cal_block;
-	int ret = 0;
-	void *apr_cvp;
-	u16 cvp_handle;
-	uint32_t cal_paddr;
-
-	get_all_cvp_cal(&cal_block);
-	if (cal_block.cal_size == 0)
-		return 0;
-
-	if (v == NULL) {
-		pr_err("%s: v is NULL\n", __func__);
-		return -EINVAL;
-	}
-	apr_cvp = common.apr_q6_cvp;
-
-	if (!apr_cvp) {
-		pr_err("%s: apr_cvp is NULL.\n", __func__);
-		return -EINVAL;
-	}
-
-	if (is_voip_session(v->session_id))
-		cal_paddr = common.cvp_cal.phy;
-	else
-		cal_paddr = cal_block.cal_paddr;
-
-	cvp_handle = voice_get_cvp_handle(v);
-
-	/* fill in the header */
-	cvp_unmap_mem_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
-				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
-	cvp_unmap_mem_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
-				sizeof(cvp_unmap_mem_cmd) - APR_HDR_SIZE);
-	cvp_unmap_mem_cmd.hdr.src_port = v->session_id;
-	cvp_unmap_mem_cmd.hdr.dest_port = cvp_handle;
-	cvp_unmap_mem_cmd.hdr.token = 0;
-	cvp_unmap_mem_cmd.hdr.opcode = VSS_ICOMMON_CMD_UNMAP_MEMORY;
-
-	cvp_unmap_mem_cmd.vss_unmap_mem.phys_addr = cal_paddr;
-
-	v->cvp_state = CMD_STATUS_FAIL;
-	ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_unmap_mem_cmd);
-	if (ret < 0) {
-		pr_err("Fail: sending cvp cal,\n");
-		goto fail;
-	}
-	ret = wait_event_timeout(v->cvp_wait,
-			(v->cvp_state == CMD_STATUS_SUCCESS),
-			msecs_to_jiffies(TIMEOUT_MS));
-	if (!ret) {
-		pr_err("%s: wait_event timeout\n", __func__);
-		goto fail;
-	}
-	return 0;
-fail:
-	return -EINVAL;
-
-}
-
-static int voice_send_cvs_map_memory_cmd(struct voice_data *v)
-{
-	struct vss_map_memory_cmd cvs_map_mem_cmd;
-	struct acdb_cal_block cal_block;
-	int ret = 0;
-	void *apr_cvs;
-	u16 cvs_handle;
-	uint32_t cal_paddr;
-
-	/* get all cvs cal data */
-	get_all_vocstrm_cal(&cal_block);
-	if (cal_block.cal_size == 0)
-		goto fail;
-
-	if (v == NULL) {
-		pr_err("%s: v is NULL\n", __func__);
-		return -EINVAL;
-	}
-	apr_cvs = common.apr_q6_cvs;
-
-	if (!apr_cvs) {
-		pr_err("%s: apr_cvs is NULL.\n", __func__);
-		return -EINVAL;
-	}
-
-	if (is_voip_session(v->session_id)) {
-		if (common.cvs_cal.buf)
-			cal_paddr = common.cvs_cal.phy;
-		else
-			return -EINVAL;
-	} else {
-		cal_paddr = cal_block.cal_paddr;
-	}
-
-	cvs_handle = voice_get_cvs_handle(v);
-
-	/* fill in the header */
-	cvs_map_mem_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
-				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
-	cvs_map_mem_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
-				sizeof(cvs_map_mem_cmd) - APR_HDR_SIZE);
-	cvs_map_mem_cmd.hdr.src_port = v->session_id;
-	cvs_map_mem_cmd.hdr.dest_port = cvs_handle;
-	cvs_map_mem_cmd.hdr.token = 0;
-	cvs_map_mem_cmd.hdr.opcode = VSS_ICOMMON_CMD_MAP_MEMORY;
-
-	pr_debug("%s, phys_addr: 0x%x, mem_size: %d\n", __func__,
-		cal_paddr, cal_block.cal_size);
-	cvs_map_mem_cmd.vss_map_mem.phys_addr = cal_paddr;
-	cvs_map_mem_cmd.vss_map_mem.mem_size = cal_block.cal_size;
-	cvs_map_mem_cmd.vss_map_mem.mem_pool_id =
-				VSS_ICOMMON_MAP_MEMORY_SHMEM8_4K_POOL;
-
-	v->cvs_state = CMD_STATUS_FAIL;
-	ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_map_mem_cmd);
-	if (ret < 0) {
-		pr_err("Fail: sending cvs cal,\n");
-		goto fail;
-	}
-	ret = wait_event_timeout(v->cvs_wait,
-			(v->cvs_state == CMD_STATUS_SUCCESS),
-			msecs_to_jiffies(TIMEOUT_MS));
-	if (!ret) {
-		pr_err("%s: wait_event timeout\n", __func__);
-		goto fail;
-	}
-	return 0;
-fail:
-	return -EINVAL;
-
-}
-
-static int voice_send_cvs_unmap_memory_cmd(struct voice_data *v)
-{
-	struct vss_unmap_memory_cmd cvs_unmap_mem_cmd;
-	struct acdb_cal_block cal_block;
-	int ret = 0;
-	void *apr_cvs;
-	u16 cvs_handle;
-	uint32_t cal_paddr;
-
-	get_all_vocstrm_cal(&cal_block);
-	if (cal_block.cal_size == 0)
-		return 0;
-
-	if (v == NULL) {
-		pr_err("%s: v is NULL\n", __func__);
-		return -EINVAL;
-	}
-	apr_cvs = common.apr_q6_cvs;
-
-	if (!apr_cvs) {
-		pr_err("%s: apr_cvs is NULL.\n", __func__);
-		return -EINVAL;
-	}
-
-	if (is_voip_session(v->session_id))
-		cal_paddr = common.cvs_cal.phy;
-	else
-		cal_paddr = cal_block.cal_paddr;
-
-	cvs_handle = voice_get_cvs_handle(v);
-
-	/* fill in the header */
-	cvs_unmap_mem_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
-				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
-	cvs_unmap_mem_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
-				sizeof(cvs_unmap_mem_cmd) - APR_HDR_SIZE);
-	cvs_unmap_mem_cmd.hdr.src_port = v->session_id;
-	cvs_unmap_mem_cmd.hdr.dest_port = cvs_handle;
-	cvs_unmap_mem_cmd.hdr.token = 0;
-	cvs_unmap_mem_cmd.hdr.opcode = VSS_ICOMMON_CMD_UNMAP_MEMORY;
-
-	cvs_unmap_mem_cmd.vss_unmap_mem.phys_addr = cal_paddr;
-
-	v->cvs_state = CMD_STATUS_FAIL;
-	ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_unmap_mem_cmd);
-	if (ret < 0) {
-		pr_err("Fail: sending cvs cal,\n");
-		goto fail;
-	}
-	ret = wait_event_timeout(v->cvs_wait,
-			(v->cvs_state == CMD_STATUS_SUCCESS),
-			msecs_to_jiffies(TIMEOUT_MS));
-	if (!ret) {
-		pr_err("%s: wait_event timeout\n", __func__);
-		goto fail;
-	}
-	return 0;
-fail:
-	return -EINVAL;
-
-}
-
-static int voice_send_cvp_register_cal_cmd(struct voice_data *v)
-{
-	struct cvp_register_cal_data_cmd cvp_reg_cal_cmd;
-	struct acdb_cal_block cal_block;
-	int ret = 0;
-	void *apr_cvp;
-	u16 cvp_handle;
-	uint32_t cal_paddr;
-
-      /* get the cvp cal data */
-	get_all_vocproc_cal(&cal_block);
-	if (cal_block.cal_size == 0)
-		goto fail;
-
-	if (v == NULL) {
-		pr_err("%s: v is NULL\n", __func__);
-		return -EINVAL;
-	}
-	apr_cvp = common.apr_q6_cvp;
-
-	if (!apr_cvp) {
-		pr_err("%s: apr_cvp is NULL.\n", __func__);
-		return -EINVAL;
-	}
-
-	if (is_voip_session(v->session_id)) {
-		if (common.cvp_cal.buf) {
-			cal_paddr = common.cvp_cal.phy;
-
-			memcpy(common.cvp_cal.buf,
-				(void *)cal_block.cal_kvaddr,
-				cal_block.cal_size);
-		} else {
-			return -EINVAL;
-		}
-	} else {
-		cal_paddr = cal_block.cal_paddr;
-	}
-
-	cvp_handle = voice_get_cvp_handle(v);
-
-	/* fill in the header */
-	cvp_reg_cal_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
-				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
-	cvp_reg_cal_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
-				sizeof(cvp_reg_cal_cmd) - APR_HDR_SIZE);
-	cvp_reg_cal_cmd.hdr.src_port = v->session_id;
-	cvp_reg_cal_cmd.hdr.dest_port = cvp_handle;
-	cvp_reg_cal_cmd.hdr.token = 0;
-	cvp_reg_cal_cmd.hdr.opcode = VSS_IVOCPROC_CMD_REGISTER_CALIBRATION_DATA;
-
-	cvp_reg_cal_cmd.cvp_cal_data.phys_addr = cal_paddr;
-	cvp_reg_cal_cmd.cvp_cal_data.mem_size = cal_block.cal_size;
-
-	v->cvp_state = CMD_STATUS_FAIL;
-	ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_reg_cal_cmd);
-	if (ret < 0) {
-		pr_err("Fail: sending cvp cal,\n");
-		goto fail;
-	}
-	ret = wait_event_timeout(v->cvp_wait,
-			(v->cvp_state == CMD_STATUS_SUCCESS),
-			msecs_to_jiffies(TIMEOUT_MS));
-	if (!ret) {
-		pr_err("%s: wait_event timeout\n", __func__);
-		goto fail;
-	}
-	return 0;
-fail:
-	return -EINVAL;
-
-}
-
-static int voice_send_cvp_deregister_cal_cmd(struct voice_data *v)
-{
-	struct cvp_deregister_cal_data_cmd cvp_dereg_cal_cmd;
-	struct acdb_cal_block cal_block;
-	int ret = 0;
-	void *apr_cvp;
-	u16 cvp_handle;
-
-	get_all_vocproc_cal(&cal_block);
-	if (cal_block.cal_size == 0)
-		return 0;
-
-	if (v == NULL) {
-		pr_err("%s: v is NULL\n", __func__);
-		return -EINVAL;
-	}
-	apr_cvp = common.apr_q6_cvp;
-
-	if (!apr_cvp) {
-		pr_err("%s: apr_cvp is NULL.\n", __func__);
-		return -EINVAL;
-	}
-	cvp_handle = voice_get_cvp_handle(v);
-
-	/* fill in the header */
-	cvp_dereg_cal_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
-				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
-	cvp_dereg_cal_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
-				sizeof(cvp_dereg_cal_cmd) - APR_HDR_SIZE);
-	cvp_dereg_cal_cmd.hdr.src_port = v->session_id;
-	cvp_dereg_cal_cmd.hdr.dest_port = cvp_handle;
-	cvp_dereg_cal_cmd.hdr.token = 0;
-	cvp_dereg_cal_cmd.hdr.opcode =
-			VSS_IVOCPROC_CMD_DEREGISTER_CALIBRATION_DATA;
-
-	v->cvp_state = CMD_STATUS_FAIL;
-	ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_dereg_cal_cmd);
-	if (ret < 0) {
-		pr_err("Fail: sending cvp cal,\n");
-		goto fail;
-	}
-	ret = wait_event_timeout(v->cvp_wait,
-			(v->cvp_state == CMD_STATUS_SUCCESS),
-			msecs_to_jiffies(TIMEOUT_MS));
-	if (!ret) {
-		pr_err("%s: wait_event timeout\n", __func__);
-		goto fail;
-	}
-	return 0;
-fail:
-	return -EINVAL;
-
-}
-
-static int voice_send_cvp_register_vol_cal_table_cmd(struct voice_data *v)
-{
-	struct cvp_register_vol_cal_table_cmd cvp_reg_cal_tbl_cmd;
-	struct acdb_cal_block vol_block;
-	struct acdb_cal_block voc_block;
-	int ret = 0;
-	void *apr_cvp;
-	u16 cvp_handle;
-	uint32_t cal_paddr;
-
-	/* get the cvp vol cal data */
-	get_all_vocvol_cal(&vol_block);
-	get_all_vocproc_cal(&voc_block);
-
-	if (vol_block.cal_size == 0)
-		goto fail;
-
-	if (v == NULL) {
-		pr_err("%s: v is NULL\n", __func__);
-		return -EINVAL;
-	}
-	apr_cvp = common.apr_q6_cvp;
-
-	if (!apr_cvp) {
-		pr_err("%s: apr_cvp is NULL.\n", __func__);
-		return -EINVAL;
-	}
-
-	if (is_voip_session(v->session_id)) {
-		if (common.cvp_cal.buf) {
-			cal_paddr = common.cvp_cal.phy + voc_block.cal_size;
-
-			memcpy(common.cvp_cal.buf + voc_block.cal_size,
-				(void *) vol_block.cal_kvaddr,
-				vol_block.cal_size);
-		} else {
-			return -EINVAL;
-		}
-	} else {
-		cal_paddr = vol_block.cal_paddr;
-	}
-
-	cvp_handle = voice_get_cvp_handle(v);
-
-	/* fill in the header */
-	cvp_reg_cal_tbl_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
-				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
-	cvp_reg_cal_tbl_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
-				sizeof(cvp_reg_cal_tbl_cmd) - APR_HDR_SIZE);
-	cvp_reg_cal_tbl_cmd.hdr.src_port = v->session_id;
-	cvp_reg_cal_tbl_cmd.hdr.dest_port = cvp_handle;
-	cvp_reg_cal_tbl_cmd.hdr.token = 0;
-	cvp_reg_cal_tbl_cmd.hdr.opcode =
-				VSS_IVOCPROC_CMD_REGISTER_VOLUME_CAL_TABLE;
-
-	cvp_reg_cal_tbl_cmd.cvp_vol_cal_tbl.phys_addr = cal_paddr;
-	cvp_reg_cal_tbl_cmd.cvp_vol_cal_tbl.mem_size = vol_block.cal_size;
-
-	v->cvp_state = CMD_STATUS_FAIL;
-	ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_reg_cal_tbl_cmd);
-	if (ret < 0) {
-		pr_err("Fail: sending cvp cal table,\n");
-		goto fail;
-	}
-	ret = wait_event_timeout(v->cvp_wait,
-			(v->cvp_state == CMD_STATUS_SUCCESS),
-			msecs_to_jiffies(TIMEOUT_MS));
-	if (!ret) {
-		pr_err("%s: wait_event timeout\n", __func__);
-		goto fail;
-	}
-	return 0;
-fail:
-	return -EINVAL;
-
-}
-
-static int voice_send_cvp_deregister_vol_cal_table_cmd(struct voice_data *v)
-{
-	struct cvp_deregister_vol_cal_table_cmd cvp_dereg_cal_tbl_cmd;
-	struct acdb_cal_block cal_block;
-	int ret = 0;
-	void *apr_cvp;
-	u16 cvp_handle;
-
-	get_all_vocvol_cal(&cal_block);
-	if (cal_block.cal_size == 0)
-		return 0;
-
-	if (v == NULL) {
-		pr_err("%s: v is NULL\n", __func__);
-		return -EINVAL;
-	}
-	apr_cvp = common.apr_q6_cvp;
-
-	if (!apr_cvp) {
-		pr_err("%s: apr_cvp is NULL.\n", __func__);
-		return -EINVAL;
-	}
-	cvp_handle = voice_get_cvp_handle(v);
-
-	/* fill in the header */
-	cvp_dereg_cal_tbl_cmd.hdr.hdr_field = APR_HDR_FIELD(
-						APR_MSG_TYPE_SEQ_CMD,
-						APR_HDR_LEN(APR_HDR_SIZE),
-						APR_PKT_VER);
-	cvp_dereg_cal_tbl_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
-				sizeof(cvp_dereg_cal_tbl_cmd) - APR_HDR_SIZE);
-	cvp_dereg_cal_tbl_cmd.hdr.src_port = v->session_id;
-	cvp_dereg_cal_tbl_cmd.hdr.dest_port = cvp_handle;
-	cvp_dereg_cal_tbl_cmd.hdr.token = 0;
-	cvp_dereg_cal_tbl_cmd.hdr.opcode =
-				VSS_IVOCPROC_CMD_DEREGISTER_VOLUME_CAL_TABLE;
-
-	v->cvp_state = CMD_STATUS_FAIL;
-	ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_dereg_cal_tbl_cmd);
-	if (ret < 0) {
-		pr_err("Fail: sending cvp cal table,\n");
-		goto fail;
-	}
-	ret = wait_event_timeout(v->cvp_wait,
-			(v->cvp_state == CMD_STATUS_SUCCESS),
-			msecs_to_jiffies(TIMEOUT_MS));
-	if (!ret) {
-		pr_err("%s: wait_event timeout\n", __func__);
-		goto fail;
-	}
-	return 0;
-fail:
-	return -EINVAL;
-
-}
-
-static int voice_send_set_widevoice_enable_cmd(struct voice_data *v)
-{
-	struct mvm_set_widevoice_enable_cmd mvm_set_wv_cmd;
-	int ret = 0;
-	void *apr_mvm;
-	u16 mvm_handle;
-
-	if (v == NULL) {
-		pr_err("%s: v is NULL\n", __func__);
-		return -EINVAL;
-	}
-	apr_mvm = common.apr_q6_mvm;
-
-	if (!apr_mvm) {
-		pr_err("%s: apr_mvm is NULL.\n", __func__);
-		return -EINVAL;
-	}
-	mvm_handle = voice_get_mvm_handle(v);
-
-	/* fill in the header */
-	mvm_set_wv_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
-				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
-	mvm_set_wv_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
-				sizeof(mvm_set_wv_cmd) - APR_HDR_SIZE);
-	mvm_set_wv_cmd.hdr.src_port = v->session_id;
-	mvm_set_wv_cmd.hdr.dest_port = mvm_handle;
-	mvm_set_wv_cmd.hdr.token = 0;
-	mvm_set_wv_cmd.hdr.opcode = VSS_IWIDEVOICE_CMD_SET_WIDEVOICE;
-
-	mvm_set_wv_cmd.vss_set_wv.enable = v->wv_enable;
-
-	v->mvm_state = CMD_STATUS_FAIL;
-	ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_set_wv_cmd);
-	if (ret < 0) {
-		pr_err("Fail: sending mvm set widevoice enable,\n");
-		goto fail;
-	}
-	ret = wait_event_timeout(v->mvm_wait,
-			(v->mvm_state == CMD_STATUS_SUCCESS),
-			msecs_to_jiffies(TIMEOUT_MS));
-	if (!ret) {
-		pr_err("%s: wait_event timeout\n", __func__);
-		goto fail;
-	}
-	return 0;
-fail:
-	return -EINVAL;
-}
-
-static int voice_send_set_pp_enable_cmd(struct voice_data *v,
-					uint32_t module_id, int enable)
-{
-	struct cvs_set_pp_enable_cmd cvs_set_pp_cmd;
-	int ret = 0;
-	void *apr_cvs;
-	u16 cvs_handle;
-
-	if (v == NULL) {
-		pr_err("%s: v is NULL\n", __func__);
-		return -EINVAL;
-	}
-	apr_cvs = common.apr_q6_cvs;
-
-	if (!apr_cvs) {
-		pr_err("%s: apr_cvs is NULL.\n", __func__);
-		return -EINVAL;
-	}
-	cvs_handle = voice_get_cvs_handle(v);
-
-	/* fill in the header */
-	cvs_set_pp_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
-				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
-	cvs_set_pp_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
-				sizeof(cvs_set_pp_cmd) - APR_HDR_SIZE);
-	cvs_set_pp_cmd.hdr.src_port = v->session_id;
-	cvs_set_pp_cmd.hdr.dest_port = cvs_handle;
-	cvs_set_pp_cmd.hdr.token = 0;
-	cvs_set_pp_cmd.hdr.opcode = VSS_ICOMMON_CMD_SET_UI_PROPERTY;
-
-	cvs_set_pp_cmd.vss_set_pp.module_id = module_id;
-	cvs_set_pp_cmd.vss_set_pp.param_id = VOICE_PARAM_MOD_ENABLE;
-	cvs_set_pp_cmd.vss_set_pp.param_size = MOD_ENABLE_PARAM_LEN;
-	cvs_set_pp_cmd.vss_set_pp.reserved = 0;
-	cvs_set_pp_cmd.vss_set_pp.enable = enable;
-	cvs_set_pp_cmd.vss_set_pp.reserved_field = 0;
-	pr_debug("voice_send_set_pp_enable_cmd, module_id=%d, enable=%d\n",
-		module_id, enable);
-
-	v->cvs_state = CMD_STATUS_FAIL;
-	ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_pp_cmd);
-	if (ret < 0) {
-		pr_err("Fail: sending cvs set slowtalk enable,\n");
-		goto fail;
-	}
-	ret = wait_event_timeout(v->cvs_wait,
-		(v->cvs_state == CMD_STATUS_SUCCESS),
-			msecs_to_jiffies(TIMEOUT_MS));
-	if (!ret) {
-		pr_err("%s: wait_event timeout\n", __func__);
-		goto fail;
-	}
-	return 0;
-fail:
-	return -EINVAL;
-}
 
 static int voice_setup_vocproc(struct voice_data *v)
 {
@@ -2040,17 +1266,6 @@
 		goto fail;
 	}
 
-	/* send cvs cal */
-	ret = voice_send_cvs_map_memory_cmd(v);
-	if (!ret)
-		voice_send_cvs_register_cal_cmd(v);
-
-	/* send cvp and vol cal */
-	ret = voice_send_cvp_map_memory_cmd(v);
-	if (!ret) {
-		voice_send_cvp_register_cal_cmd(v);
-		voice_send_cvp_register_vol_cal_table_cmd(v);
-	}
 
 	/* enable vocproc */
 	ret = voice_send_enable_vocproc_cmd(v);
@@ -2065,16 +1280,6 @@
 	/* send tty mode if tty device is used */
 	voice_send_tty_mode_cmd(v);
 
-	/* enable widevoice if wv_enable is set */
-	if (v->wv_enable)
-		voice_send_set_widevoice_enable_cmd(v);
-
-	/* enable slowtalk if st_enable is set */
-	if (v->st_enable)
-		voice_send_set_pp_enable_cmd(v, MODULE_ID_VOICE_MODULE_ST,
-					v->st_enable);
-	voice_send_set_pp_enable_cmd(v, MODULE_ID_VOICE_MODULE_FENS,
-					v->fens_enable);
 
 	if (is_voip_session(v->session_id))
 		voice_send_netid_timing_cmd(v);
@@ -2087,10 +1292,6 @@
 	if (v->rec_info.rec_enable)
 		voice_cvs_start_record(v, v->rec_info.rec_mode);
 
-	rtac_add_voice(voice_get_cvs_handle(v),
-		voice_get_cvp_handle(v),
-		v->dev_rx.port_id, v->dev_tx.port_id,
-		v->session_id);
 
 	return 0;
 
@@ -2359,14 +1560,6 @@
 		goto fail;
 	}
 
-	/* deregister cvp and vol cal */
-	voice_send_cvp_deregister_vol_cal_table_cmd(v);
-	voice_send_cvp_deregister_cal_cmd(v);
-	voice_send_cvp_unmap_memory_cmd(v);
-
-	/* deregister cvs cal */
-	voice_send_cvs_deregister_cal_cmd(v);
-	voice_send_cvs_unmap_memory_cmd(v);
 
 	/* destrop cvp session */
 	cvp_destroy_session_cmd.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
@@ -2395,7 +1588,6 @@
 		goto fail;
 	}
 
-	rtac_remove_voice(voice_get_cvs_handle(v));
 	cvp_handle = 0;
 	voice_set_cvp_handle(v, cvp_handle);
 
@@ -2975,12 +2167,6 @@
 	mutex_lock(&v->lock);
 
 	if (v->voc_state == VOC_RUN) {
-		if (v->dev_tx.port_id != RT_PROXY_PORT_001_TX &&
-			v->dev_rx.port_id != RT_PROXY_PORT_001_RX)
-			afe_sidetone(v->dev_tx.port_id, v->dev_rx.port_id,
-					0, 0);
-
-		rtac_remove_voice(voice_get_cvs_handle(v));
 		/* send cmd to dsp to disable vocproc */
 		ret = voice_send_disable_vocproc_cmd(v);
 		if (ret < 0) {
@@ -2988,10 +2174,6 @@
 			goto fail;
 		}
 
-		/* deregister cvp and vol cal */
-		voice_send_cvp_deregister_vol_cal_table_cmd(v);
-		voice_send_cvp_deregister_cal_cmd(v);
-		voice_send_cvp_unmap_memory_cmd(v);
 
 		v->voc_state = VOC_CHANGE;
 	}
@@ -3004,7 +2186,6 @@
 int voc_enable_cvp(uint16_t session_id)
 {
 	struct voice_data *v = voice_get_session(session_id);
-	struct sidetone_cal sidetone_cal_data;
 	int ret = 0;
 
 	if (v == NULL) {
@@ -3021,53 +2202,9 @@
 			pr_err("%s:  set device failed\n", __func__);
 			goto fail;
 		}
-		/* send cvp and vol cal */
-		ret = voice_send_cvp_map_memory_cmd(v);
-		if (!ret) {
-			voice_send_cvp_register_cal_cmd(v);
-			voice_send_cvp_register_vol_cal_table_cmd(v);
-		}
-		ret = voice_send_enable_vocproc_cmd(v);
-		if (ret < 0) {
-			pr_err("%s: enable vocproc failed\n", __func__);
-			goto fail;
-
-		}
 		/* send tty mode if tty device is used */
 		voice_send_tty_mode_cmd(v);
 
-		/* enable widevoice if wv_enable is set */
-		if (v->wv_enable)
-			voice_send_set_widevoice_enable_cmd(v);
-
-		/* enable slowtalk */
-		if (v->st_enable)
-			voice_send_set_pp_enable_cmd(v,
-						MODULE_ID_VOICE_MODULE_ST,
-						v->st_enable);
-		/* enable FENS */
-		if (v->fens_enable)
-			voice_send_set_pp_enable_cmd(v,
-						MODULE_ID_VOICE_MODULE_FENS,
-						v->fens_enable);
-
-		get_sidetone_cal(&sidetone_cal_data);
-		if (v->dev_tx.port_id != RT_PROXY_PORT_001_TX &&
-			v->dev_rx.port_id != RT_PROXY_PORT_001_RX) {
-			ret = afe_sidetone(v->dev_tx.port_id,
-					v->dev_rx.port_id,
-					sidetone_cal_data.enable,
-					sidetone_cal_data.gain);
-
-			if (ret < 0)
-				pr_err("%s: AFE command sidetone failed\n",
-					__func__);
-		}
-
-		rtac_add_voice(voice_get_cvs_handle(v),
-			voice_get_cvp_handle(v),
-			v->dev_rx.port_id, v->dev_tx.port_id,
-			v->session_id);
 		v->voc_state = VOC_RUN;
 	}
 
@@ -3201,8 +2338,6 @@
 
 	mvm_handle = voice_get_mvm_handle(v);
 
-	if (mvm_handle != 0)
-		voice_send_set_widevoice_enable_cmd(v);
 
 	mutex_unlock(&v->lock);
 
@@ -3246,16 +2381,6 @@
 	else if (module_id == MODULE_ID_VOICE_MODULE_FENS)
 		v->fens_enable = enable;
 
-	if (v->voc_state == VOC_RUN) {
-		if (module_id == MODULE_ID_VOICE_MODULE_ST)
-			ret = voice_send_set_pp_enable_cmd(v,
-						MODULE_ID_VOICE_MODULE_ST,
-						enable);
-		else if (module_id == MODULE_ID_VOICE_MODULE_FENS)
-			ret = voice_send_set_pp_enable_cmd(v,
-						MODULE_ID_VOICE_MODULE_FENS,
-						enable);
-	}
 	mutex_unlock(&v->lock);
 
 	return ret;
@@ -3391,10 +2516,6 @@
 	mutex_lock(&v->lock);
 
 	if (v->voc_state == VOC_RUN) {
-		if (v->dev_tx.port_id != RT_PROXY_PORT_001_TX &&
-			v->dev_rx.port_id != RT_PROXY_PORT_001_RX)
-			afe_sidetone(v->dev_tx.port_id, v->dev_rx.port_id,
-					0, 0);
 		ret = voice_destroy_vocproc(v);
 		if (ret < 0)
 			pr_err("%s:  destroy voice failed\n", __func__);
@@ -3409,7 +2530,6 @@
 int voc_start_voice_call(uint16_t session_id)
 {
 	struct voice_data *v = voice_get_session(session_id);
-	struct sidetone_cal sidetone_cal_data;
 	int ret = 0;
 
 	if (v == NULL) {
@@ -3447,16 +2567,6 @@
 			pr_err("start voice failed\n");
 			goto fail;
 		}
-		get_sidetone_cal(&sidetone_cal_data);
-		if (v->dev_tx.port_id != RT_PROXY_PORT_001_TX &&
-			v->dev_rx.port_id != RT_PROXY_PORT_001_RX) {
-			ret = afe_sidetone(v->dev_tx.port_id,
-					v->dev_rx.port_id,
-					sidetone_cal_data.enable,
-					sidetone_cal_data.gain);
-			if (ret < 0)
-				pr_err("AFE command sidetone failed\n");
-		}
 
 		v->voc_state = VOC_RUN;
 	}
@@ -3649,8 +2759,6 @@
 				wake_up(&v->cvs_wait);
 				break;
 			case VOICE_CMD_SET_PARAM:
-				rtac_make_voice_callback(RTAC_CVS, ptr,
-							data->payload_size);
 				break;
 			default:
 				pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
@@ -3712,9 +2820,6 @@
 			pr_debug("%s: dl_cb is NULL\n", __func__);
 	} else if (data->opcode == VSS_ISTREAM_EVT_SEND_DEC_BUFFER) {
 		pr_debug("Send dec buf resp\n");
-	} else if (data->opcode ==  VOICE_EVT_GET_PARAM_ACK) {
-		rtac_make_voice_callback(RTAC_CVS, data->payload,
-					data->payload_size);
 	} else
 		pr_debug("Unknown opcode 0x%x\n", data->opcode);
 
@@ -3792,8 +2897,6 @@
 				wake_up(&v->cvp_wait);
 				break;
 			case VOICE_CMD_SET_PARAM:
-				rtac_make_voice_callback(RTAC_CVP, ptr,
-							data->payload_size);
 				break;
 			default:
 				pr_debug("%s: not match cmd = 0x%x\n",
@@ -3801,9 +2904,6 @@
 				break;
 			}
 		}
-	} else if (data->opcode ==  VOICE_EVT_GET_PARAM_ACK) {
-		rtac_make_voice_callback(RTAC_CVP, data->payload,
-			data->payload_size);
 	}
 	return 0;
 }
@@ -3812,73 +2912,9 @@
 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;
-	}
-
-	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 = 1;  /* default is mute */
 	common.default_vol_val = 0;
diff --git a/sound/soc/msm/qdsp6v2/q6voice.h b/sound/soc/msm/qdsp6v2/q6voice.h
index 1bedb15..8bafe04 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.h
+++ b/sound/soc/msm/qdsp6v2/q6voice.h
@@ -13,7 +13,7 @@
 #define __QDSP6VOICE_H__
 
 #include <mach/qdsp6v2/apr.h>
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
 
 #define MAX_VOC_PKT_SIZE 642
 #define SESSION_NAME_LEN 20
@@ -119,6 +119,8 @@
 #define VSS_IMVM_CMD_CREATE_FULL_CONTROL_SESSION	0x000110FE
 /* Create a new full control MVM session. */
 
+#define VSS_IVOCPROC_CMD_CREATE_FULL_CONTROL_SESSION_V2	0x000112BF
+
 #define APRV2_IBASIC_CMD_DESTROY_SESSION		0x0001003C
 /**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
 
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 4522d15..79016b5 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -3231,6 +3231,7 @@
 	card->instantiated = 0;
 	mutex_init(&card->mutex);
 	mutex_init(&card->dpcm_mutex);
+	mutex_init(&card->dapm_power_mutex);
 
 	mutex_lock(&client_mutex);
 	list_add(&card->list, &card_list);
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 729142f..5ac6434 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -1290,7 +1290,7 @@
 		/* Do we need to apply any queued changes? */
 		if (sort[w->id] != cur_sort || w->reg != cur_reg ||
 		    w->dapm != cur_dapm || w->subseq != cur_subseq) {
-			if (!list_empty(&pending))
+			if (cur_dapm && !list_empty(&pending))
 				dapm_seq_run_coalesced(cur_dapm, &pending);
 
 			if (cur_dapm && cur_dapm->seq_notifier) {
@@ -1350,7 +1350,7 @@
 				"Failed to apply widget power: %d\n", ret);
 	}
 
-	if (!list_empty(&pending))
+	if (cur_dapm && !list_empty(&pending))
 		dapm_seq_run_coalesced(cur_dapm, &pending);
 
 	if (cur_dapm && cur_dapm->seq_notifier) {
@@ -1567,6 +1567,8 @@
 
 	trace_snd_soc_dapm_start(card);
 
+	mutex_lock(&card->dapm_power_mutex);
+
 	list_for_each_entry(d, &card->dapm_list, list) {
 		if (d->n_widgets || d->codec == NULL) {
 			if (d->idle_bias_off)
@@ -1682,6 +1684,8 @@
 		"DAPM sequencing finished, waiting %dms\n", card->pop_time);
 	pop_wait(card->pop_time);
 
+	mutex_unlock(&card->dapm_power_mutex);
+
 	trace_snd_soc_dapm_done(card);
 
 	return 0;
@@ -3092,9 +3096,9 @@
 	if (stream == NULL)
 		return 0;
 
-	//mutex_lock(&codec->mutex);
+	mutex_lock(&codec->mutex);
 	soc_dapm_stream_event(&codec->dapm, stream, event);
-	//mutex_unlock(&codec->mutex);
+	mutex_unlock(&codec->mutex);
 
 	return 0;
 }
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 65cee5d..f989b17 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -2046,6 +2046,8 @@
 			be_disconnect(fe, SNDRV_PCM_STREAM_PLAYBACK);
 		}
 
+		fe_path_put(&list);
+
 capture:
 		/* skip if FE doesn't have capture capability */
 		if (!fe->cpu_dai->driver->capture.channels_min)
diff --git a/tools/perf/Documentation/perf-script-json-export.txt b/tools/perf/Documentation/perf-script-json-export.txt
new file mode 100644
index 0000000..dd47c7c
--- /dev/null
+++ b/tools/perf/Documentation/perf-script-json-export.txt
@@ -0,0 +1,29 @@
+perf-script-json-export(1)
+====================
+
+NAME
+----
+perf-script-json-export - Export trace data to JSON
+
+SYNOPSIS
+--------
+[verse]
+'perf script' -g JSON:<script>
+'perf script' -g <script.json>
+'perf script' -s JSON:<script> [option]*
+'perf script' -s <script.json> [option]*
+
+DESCRIPTION
+-----------
+
+This perf script option is used to export perf script data using JSON
+format.  JSON export extesion is identified either by the 'JSON:'
+prefix or the '.json' file extension.
+
+Both command forms export JSON fomatted data.  The '-g'/'--gen-script'
+option does not include actual event data.  Only Definitions.  '-s'
+version includes events and definition data (by default).
+
+SEE ALSO
+--------
+linkperf:perf-script[1]
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 80f23c0..0cff0ca 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -633,6 +633,12 @@
   endif
 endif
 
+ifdef NO_JSON_EXPORT
+	BASIC_CFLAGS += -DNO_JSON_EXPORT
+else
+	LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-json-export.o
+endif
+
 ifdef NO_DEMANGLE
 	BASIC_CFLAGS += -DNO_DEMANGLE
 else
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 704d63a..f7f18c7 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -469,6 +469,7 @@
 {
 	setup_perl_scripting();
 	setup_python_scripting();
+	setup_json_export();
 
 	scripting_ops = &default_scripting_ops;
 }
diff --git a/tools/perf/util/scripting-engines/trace-event-json-export.c b/tools/perf/util/scripting-engines/trace-event-json-export.c
new file mode 100644
index 0000000..2aec459
--- /dev/null
+++ b/tools/perf/util/scripting-engines/trace-event-json-export.c
@@ -0,0 +1,322 @@
+/*
+ * trace-event-json-export.  Export events to JSON format.
+ *
+ * derived from: trace-event-python.c
+ *
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (C) 2010 Tom Zanussi <tzanussi@gmail.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  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
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "../../perf.h"
+#include "../util.h"
+#include "../trace-event.h"
+#include "../event.h"
+#include "../thread.h"
+
+#define FTRACE_MAX_EVENT				\
+	((1 << (sizeof(unsigned short) * 8)) - 1)
+
+FILE *ofp;
+struct event *events[FTRACE_MAX_EVENT];
+static char *cur_field_name;
+
+static void define_value(enum print_arg_type field_type,
+			 int id,
+			 const char *field_name,
+			 const char *field_value,
+			 const char *field_str)
+{
+	const char *handler_name = (field_type == PRINT_SYMBOL) ?
+		"define_symbol" : "define_flag";
+	unsigned long long value;
+
+	value = eval_flag(field_value);
+
+	fprintf(ofp,
+		",\n[\"%s\",%d,{\"field\":\"%s\",\"value\":%llu,\"name\":\"%s\"}]",
+		handler_name, id, field_name, value, field_str);
+}
+
+static void define_values(enum print_arg_type field_type,
+			  struct print_flag_sym *field,
+			  int id,
+			  const char *field_name)
+{
+	define_value(field_type, id, field_name, field->value,
+			 field->str);
+
+	if (field->next)
+		define_values(field_type, field->next, id, field_name);
+}
+
+static void define_field(enum print_arg_type field_type,
+			 int id,
+			 const char *field_name,
+			 const char *delim)
+{
+	if (field_type == PRINT_FLAGS) {
+		const char *handler_name = "define_flag_field";
+		fprintf(ofp,
+			",\n[\"%s\",%d,{\"field\":\"%s\",\"delim\":\"%s\"}]",
+			handler_name, id, field_name, delim);
+	} else {
+		const char *handler_name = "define_symbol_field";
+		fprintf(ofp, ",\n[\"%s\",%d,{\"field\":\"%s\"}]",
+				handler_name, id, field_name);
+	}
+}
+
+static void define_event_symbols(struct event *event,
+				struct print_arg *args)
+{
+	switch (args->type) {
+	case PRINT_NULL:
+		break;
+	case PRINT_ATOM:
+		define_value(PRINT_FLAGS, event->id, cur_field_name, "0",
+				 args->atom.atom);
+		break;
+	case PRINT_FIELD:
+		cur_field_name = args->field.name;
+		break;
+	case PRINT_FLAGS:
+		define_event_symbols(event, args->flags.field);
+		define_field(PRINT_FLAGS, event->id, cur_field_name,
+				 args->flags.delim);
+		define_values(PRINT_FLAGS, args->flags.flags, event->id,
+				  cur_field_name);
+		break;
+	case PRINT_SYMBOL:
+		define_event_symbols(event, args->symbol.field);
+		define_field(PRINT_SYMBOL, event->id, cur_field_name, NULL);
+		define_values(PRINT_SYMBOL, args->symbol.symbols, event->id,
+				  cur_field_name);
+		break;
+	case PRINT_STRING:
+		break;
+	case PRINT_TYPE:
+		define_event_symbols(event, args->typecast.item);
+		break;
+	case PRINT_OP:
+		define_event_symbols(event, args->op.left);
+		define_event_symbols(event, args->op.right);
+		break;
+	default:
+		/* we should warn... */
+		return;
+	}
+
+	if (args->next)
+		define_event_symbols(event, args->next);
+}
+
+#define prefix(indx) (indx ? "," : "")
+static void define_event(struct event *event)
+{
+	const char *ev_system = event->system;
+	const char *ev_name = event->name;
+	int indx = 0;
+	const char *handler_name = "define_event";
+	struct format_field *field = 0;
+
+	fprintf(ofp,
+		",\n[\"%s\",%d,{\"system\":\"%s\",\"name\":\"%s\",\"args\":{",
+			handler_name, event->id, ev_system, ev_name);
+
+	fprintf(ofp, "%s\"%s\":%d", prefix(indx), "common_s", indx);
+	indx++;
+	fprintf(ofp, "%s\"%s\":%d", prefix(indx), "common_ns", indx);
+	indx++;
+	fprintf(ofp, "%s\"%s\":%d", prefix(indx), "common_cpu", indx);
+	indx++;
+	fprintf(ofp, "%s\"%s\":%d", prefix(indx), "common_comm", indx);
+	indx++;
+	for (field = event->format.common_fields; field; field = field->next) {
+		fprintf(ofp, "%s\"%s\":%d", prefix(indx), field->name, indx);
+		indx++;
+	}
+	for (field = event->format.fields; field; field = field->next) {
+		fprintf(ofp, "%s\"%s\":%d", prefix(indx), field->name, indx);
+		indx++;
+	}
+	fprintf(ofp, "}}]");
+}
+
+static inline struct event *find_cache_event(int type)
+{
+	struct event *event;
+
+	if (events[type])
+		return events[type];
+
+	events[type] = event = trace_find_event(type);
+	if (!event)
+		return NULL;
+
+	define_event(event);
+	define_event_symbols(event, event->print_fmt.args);
+
+	return event;
+}
+
+static void json_process_field(int indx, void *data, struct format_field *field)
+{
+	unsigned long long val;
+
+	if (field->flags & FIELD_IS_STRING) {
+		int offset;
+		if (field->flags & FIELD_IS_DYNAMIC) {
+			offset = *(int *)(data + field->offset);
+			offset &= 0xffff;
+		} else
+			offset = field->offset;
+		fprintf(ofp, "%s\"%s\"", prefix(indx), (char *)data + offset);
+	} else { /* FIELD_IS_NUMERIC */
+		val = read_size(data + field->offset, field->size);
+		if (field->flags & FIELD_IS_SIGNED)
+			fprintf(ofp, "%s%lld", prefix(indx),
+					(long long int) val);
+		else
+			fprintf(ofp, "%s%llu", prefix(indx), val);
+	}
+}
+
+static void json_process_event(union perf_event *pevent __unused,
+			       struct perf_sample *sample,
+			       struct perf_evsel *evsel __unused,
+			       struct machine *machine __unused,
+			       struct thread *thread)
+{
+	struct format_field *field;
+	unsigned long s, ns;
+	struct event *event;
+	int type;
+	int indx = 0;
+	int cpu = sample->cpu;
+	void *data = sample->raw_data;
+	unsigned long long nsecs = sample->time;
+	char *comm = thread->comm;
+
+	type = trace_parse_common_type(data);
+
+	event = find_cache_event(type);
+	if (!event)
+		die("ug! no event found for type %d", type);
+
+	s = nsecs / NSECS_PER_SEC;
+	ns = nsecs - s * NSECS_PER_SEC;
+
+	fprintf(ofp, ",\n[\"event\",%d,[%lu,%lu,%d,\"%s\"",
+			type, s, ns, cpu, comm);
+
+	indx += 4;
+
+	for (field = event->format.common_fields; field; field = field->next)
+		json_process_field(indx++, data, field);
+
+	for (field = event->format.fields; field; field = field->next)
+		json_process_field(indx++, data, field);
+
+	fprintf(ofp , "]]");
+}
+
+/*
+ * Start trace script
+ */
+static int json_start_script(const char *script, int argc __unused,
+		const char **argv __unused)
+{
+	int err = 0;
+
+	if (script[0]) {
+		ofp = fopen(script, "w");
+		if (ofp == NULL) {
+			fprintf(stderr, "couldn't open %s\n", script);
+			return -EBADF;
+		}
+	} else
+		ofp = stdout;
+
+	fprintf(ofp, "[[\"trace_start\"]");
+
+	return err;
+}
+
+/*
+ * Stop trace script
+ */
+static int json_stop_script(void)
+{
+	int err = 0;
+
+	fprintf(ofp, ",\n[\"trace_end\"]]");
+
+	return err;
+}
+
+static int json_generate_script(const char *outfile)
+{
+	struct event *event = NULL;
+	char fname[PATH_MAX];
+
+	snprintf(fname, sizeof(fname), "%s.json", outfile);
+
+	ofp = fopen(fname, "w");
+
+	if (ofp == NULL) {
+		fprintf(stderr, "couldn't open %s\n", fname);
+		return -EBADF;
+	}
+	fprintf(ofp, "[[\"generate_start\"]");
+
+	while ((event = trace_find_next_event(event))) {
+		define_event(event);
+		define_event_symbols(event, event->print_fmt.args);
+	}
+
+	fprintf(ofp, ",\n[\"generate_end\"]]");
+
+	fclose(ofp);
+
+	fprintf(stderr, "generated json script: %s\n", fname);
+
+	return 0;
+}
+
+struct scripting_ops json_scripting_ops = {
+	.name = "JSON",
+	.start_script = json_start_script,
+	.stop_script = json_stop_script,
+	.process_event = json_process_event,
+	.generate_script = json_generate_script,
+};
+
+void setup_json_export(void)
+{
+	int err;
+	err = script_spec_register("JSON", &json_scripting_ops);
+	if (err)
+		die("error registering JSON export extension");
+}
+
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index 58ae14c..0a6009d 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -305,6 +305,7 @@
 
 void setup_perl_scripting(void);
 void setup_python_scripting(void);
+void setup_json_export(void);
 
 struct scripting_context {
 	void *event_data;