Merge "ASOC: msm: Add support for Multimedia2 front end."
diff --git a/Documentation/arm/msm/adsprpc-drv.txt b/Documentation/arm/msm/adsprpc-drv.txt
new file mode 100644
index 0000000..f468ddb
--- /dev/null
+++ b/Documentation/arm/msm/adsprpc-drv.txt
@@ -0,0 +1,198 @@
+Introduction
+============
+
+The MSM ADSPRPC driver implements an IPC (Inter-Processor Communication)
+mechanism that allows for clients to transparently make remote method
+invocations across processor boundaries.
+
+The below diagram depicts invocation of a single method where the client
+and objects reside on different processors. An object could expose
+multiple methods which can be grouped together and referred to as an
+interface.
+
+: ,--------,        ,------,  ,-----------,  ,------,        ,--------,
+: |        | method |      |  |           |  |      | method |        |
+: | Client |------->| Stub |->| Transport |->| Skel |------->| Object |
+: |        |        |      |  |           |  |      |        |        |
+: `--------`        `------`  `-----------`  `------`        `--------`
+
+Client:    Linux user mode process that initiates the remote invocation
+Stub:      Auto generated code linked in with the user mode process that
+           takes care of marshaling parameters
+Transport: Involved in carrying an invocation from a client to an
+           object. This involves two portions: 1) MSM ADSPRPC Linux
+           kernel driver that receives the remote invocation, queues
+           them up and then waits for the response after signaling the
+           remote side. 2) Service running on the remote side that
+           dequeues the messages from the queue and dispatches them for
+           processing.
+Skel:      Auto generated code that takes care of un-marshaling
+           parameters
+Object:    Method implementation
+
+Hardware description
+====================
+
+The driver interfaces with the components in the DSP subsystem and does
+not drive or manage any hardware resources.
+
+Software description
+====================
+
+The MSM ADSPRPC driver uses SMD (Shared Memory Driver) to send and
+receive messages with the remote processor. The SMD channel used for
+communication is opened during initialization of the driver and is
+closed when the driver module is unloaded. The driver does not expose
+HLOS memory to the remote processor but rather communication of
+invocation parameters happen over ION allocated buffers.
+
+The driver receives remote call invocations via an ioctl call. When a
+remote call invocation is received, the driver does the following:
+- Retrieves the invocation parameters
+- Copies input buffers in HLOS memory to ION allocated buffers
+- Allocates ION buffers for output buffers in HLOS memory as required
+- Scatter-gathers list of pages for ION allocated input and output
+  buffers
+- Coalesces information about the contiguous page buffers
+- Builds up a message with the received information
+- Sends the message to a remote processor through an SMD channel
+- Waits for a response from the remote processor through the SMD channel
+- Reads the message available from the shared memory SMD channel
+- Copies back from ION buffers to HLOS memory for output buffers
+- Returns the response of the remote invocation
+
+Design
+======
+
+The design goals of this transport mechanism are:
+- Fast and efficient ways to transfer huge buffers across
+  inter-processor boundaries
+- Zero copy of ION allocated buffers passed during invocations
+
+To achieve the zero copy approach of ION allocated user space buffers,
+the driver scatter-gathers the list of pages of the buffers being passed
+in. This information is then sent over to the remote processor for it
+to map into its address space.
+
+The invocation requests sent over the SMD channel carry context
+information as to whom the request is originating from. The responses
+received over the SMD channel have context information in the message
+which is then used to wake the thread waiting for a response.
+
+If the remote processor goes down and gets restarted, the SMD channel
+is re-initialized when the remote processor comes back up. An
+error code would be returned to the client for all invocations that
+happen before the SMD channel could get completely re-initialized.
+
+Power Management
+================
+
+None
+
+SMP/multi-core
+==============
+
+The driver uses semaphores to wake up clients waiting for a remote
+invocation response.
+
+Security
+========
+
+Use of the zero copy approach results in a page-size granularity of
+all buffers being passed to the remote processor. The objects that will
+be manipulating these buffers on the remote processor will be signed
+and trusted entities, thereby alleviating any fear of intentional
+scribbling of these buffers.
+
+Performance
+===========
+
+In order to minimize latencies across remote invocations:
+- messages exchanged between the remote processors are kept short
+- zero copy approach for ION allocated user space buffers
+
+Interface
+=========
+
+The driver exposes a user space interface through /dev/adsprpc-smd and
+the user space clients send commands to the driver by using the
+following ioctl command:
+
+- FASTRPC_IOCTL_INVOKE: Parameters passed in includes the buffers and
+  data related to remote invocation.
+
+  /*
+   * Information about the input/output buffer or an handle to the
+   * object being passed in the remote invocation
+   *
+   * @pv:     Pointer to input/output buffer
+   * @len:    Length of the input/output buffer
+   * @handle: Handle to the remote object
+   */
+  typedef union {
+	struct remote_buf {
+		void *pv;
+		int len;
+	} buf;
+	unsigned int handle;
+  } remote_arg;
+
+  /*
+   * Invocation parameters passed via ioctl call by the client
+   *
+   * @handle: Handle to the object on which the method is to be
+   *          invoked
+   * @sc:     Scalars detailing the parameters being passed in
+   *          bits 0-3: Number of output handles
+   *          bits 4-7: Number of input handles
+   *          bits 8-15: Number of output buffers
+   *          bits 16-23: Number of input buffers
+   *          bits 24-28: Method to be invoked
+   *          bits 29-31: Method attributes
+   * @pra:    Remote arguments to be passed for method invocation
+   */
+  struct fastrpc_ioctl_invoke {
+	unsigned int handle;
+	unsigned int sc;
+	remote_arg *pra;
+  };
+
+Driver parameters
+=================
+
+None
+
+Config options
+==============
+
+None
+
+Dependencies
+============
+
+The ADSPRPC driver requires that the ADSP RPC SMD channel be created and
+the SMD subsystem be initialized. During initialization, the driver
+opens an existing SMD edge channel between ADSP and Apps processor. On
+success, the driver waits for the "channel opened" event from SMD,
+acknowledging the channel availability from the remote SMD driver for
+communication to begin.
+
+User space utilities
+====================
+
+None
+
+Other
+=====
+
+None
+
+Known issues
+============
+
+None
+
+To do
+=====
+
+None
diff --git a/Documentation/block/row-iosched.txt b/Documentation/block/row-iosched.txt
new file mode 100644
index 0000000..987bd88
--- /dev/null
+++ b/Documentation/block/row-iosched.txt
@@ -0,0 +1,117 @@
+Introduction
+============
+
+The ROW scheduling algorithm will be used in mobile devices as default
+block layer IO scheduling algorithm. ROW stands for "READ Over WRITE"
+which is the main requests dispatch policy of this algorithm.
+
+The ROW IO scheduler was developed with the mobile devices needs in
+mind. In mobile devices we favor user experience upon everything else,
+thus we want to give READ IO requests as much priority as possible.
+The main idea of the ROW scheduling policy is:
+If there are READ requests in pipe - dispatch them but don't starve
+the WRITE requests too much.
+
+Software description
+====================
+The requests are kept in queues according to their priority. The
+dispatching of requests is done in a Round Robin manner with a
+different slice for each queue. The dispatch quantum for a specific
+queue is defined according to the queues priority. READ queues are
+given bigger dispatch quantum than the WRITE queues, within a dispatch
+cycle.
+
+At the moment there are 6 types of queues the requests are
+distributed to:
+-	High priority READ queue
+-	High priority Synchronous WRITE queue
+-	Regular priority READ queue
+-	Regular priority Synchronous WRITE queue
+-	Regular priority WRITE queue
+-	Low priority READ queue
+
+If in a certain dispatch cycle one of the queues was empty and didn't
+use its quantum that queue will be marked as "un-served". If we're in a
+middle of a dispatch cycle dispatching from queue Y and a request
+arrives for queue X that was un-served in the previous cycle, if X's
+priority is higher than Y's, queue X will be preempted in the favor of
+queue Y. This won't mean that cycle is restarted. The "dispatched"
+counter of queue X will remain unchanged. Once queue Y uses up it's quantum
+(or there will be no more requests left on it) we'll switch back to queue X
+and allow it to finish it's quantum.
+
+For READ requests queues we allow idling in within a dispatch quantum in
+order to give the application a chance to insert more requests. Idling
+means adding some extra time for serving a certain queue even if the
+queue is empty. The idling is enabled if we identify the application is
+inserting requests in a high frequency.
+
+For idling on READ queues we use timer mechanism. When the timer expires,
+if there are requests in the scheduler we will signal the underlying driver
+(for example the MMC driver) to fetch another request for dispatch.
+
+The ROW algorithm takes the scheduling policy one step further, making
+it a bit more "user-needs oriented", by allowing the application to
+hint on the urgency of its requests. For example: even among the READ
+requests several requests may be more urgent for completion then others.
+The former will go to the High priority READ queue, that is given the
+bigger dispatch quantum than any other queue.
+
+ROW scheduler will support special services for block devices that
+supports High Priority Requests. That is, the scheduler may inform the
+device upon urgent requests using new callback make_urgent_request.
+In addition it will support rescheduling of requests that were
+interrupted. For example, if the device issues a long write request and
+a sudden high priority read interrupt pops in, the scheduler will
+inform the device about the urgent request, so the device can stop the
+current write request and serve the high priority read request. In such
+a case the device may also send back to the scheduler the reminder of
+the interrupted write request, such that the scheduler may continue
+sending high priority requests without the need to interrupt the
+ongoing write again and again. The write remainder will be sent later on
+according to the scheduler policy.
+
+Design
+======
+Existing algorithms (cfq, deadline) sort the io requests according LBA.
+When deciding on the next request to dispatch they choose the closest
+request to the current disk head position (from handling last
+dispatched request). This is done in order to reduce the disk head
+movement to a minimum.
+We feel that this functionality isn't really needed in mobile devices.
+Usually applications that write/read large chunks of data insert the
+requests in already sorted LBA order. Thus dealing with sort trees adds
+unnecessary complexity.
+
+We're planing to try this enhancement in the future to check if the
+performance is influenced by it.
+
+SMP/multi-core
+==============
+At the moment the code is acceded from 2 contexts:
+- Application context (from block/elevator layer): adding the requests.
+- Underlying driver context (for example the mmc driver thread): dispatching
+  the requests and notifying on completion.
+
+One lock is used to synchronize between the two. This lock is provided
+by the underlying driver along with the dispatch queue.
+
+Config options
+==============
+1. hp_read_quantum: dispatch quantum for the high priority READ queue
+2. rp_read_quantum: dispatch quantum for the regular priority READ queue
+3. hp_swrite_quantum: dispatch quantum for the high priority Synchronous
+   WRITE queue
+4. rp_swrite_quantum: dispatch quantum for the regular priority
+   Synchronous WRITE queue
+5. rp_write_quantum: dispatch quantum for the regular priority WRITE
+   queue
+6. lp_read_quantum: dispatch quantum for the low priority READ queue
+7. lp_swrite_quantum: dispatch quantum for the low priority Synchronous
+   WRITE queue
+8. read_idle: how long to idle on read queue in Msec (in case idling
+   is enabled on that queue).
+9. read_idle_freq: frequency of inserting READ requests that will
+   trigger idling. This is the time in Msec between inserting two READ
+   requests
+
diff --git a/Documentation/devicetree/bindings/cache/msm_cache_dump.txt b/Documentation/devicetree/bindings/cache/msm_cache_dump.txt
new file mode 100644
index 0000000..b7a68b5
--- /dev/null
+++ b/Documentation/devicetree/bindings/cache/msm_cache_dump.txt
@@ -0,0 +1,24 @@
+* Qualcomm Krait L1 / L2 cache dumping device
+This is a virtual device that dumps the contents of L1 and L2 caches in the
+event of a kernel panic or a watchdog trigger.
+
+Required properties:
+- compatible:			Should be "qcom,cache_dump"
+- qcom,l1-dump-size:		Amount of memory needed for L1 dump(s), in bytes
+- qcom,l2-dump-size:		Amount of memory needed for L2 dump, in bytes
+- qcom,memory-reservation-size: Combined reserved memory for the dump buffers
+- qcom,memory-reservation-type: Type of memory to be reserved
+
+Optional properties:
+- qcom,use-imem-dump-offset: If specified, store cache dump buffer addresses
+  in IMEM rather than using the memory dump reservation table.
+
+Example:
+	qcom,cache_dump {
+		compatible = "qcom,cache_dump";
+		qcom,l1-dump-size = <0x100000>;
+		qcom,l2-dump-size = <0x400000>;
+		qcom,memory-reservation-type = "EBI1";
+		qcom,memory-reservation-size = <0x500000>;
+	};
+
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
index 82e76fc..26bddd9 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
@@ -14,7 +14,7 @@
 - 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
+- qcom,panel-phy-regulatorSettings:	An array of length 7 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.
diff --git a/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt b/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt
index 46b39ec..21d376a 100644
--- a/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt
+++ b/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt
@@ -13,7 +13,7 @@
 - interrupts:	Specifies the interrupt associated with PON.
 
 Optional properties:
-- qcom,pon-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
@@ -24,11 +24,15 @@
 				reset source. All the child nodes are optional,
 				if none of them are specified the driver fails
 				to register.
+- qcom,system-reset		Specifies that this PON peripheral can be used
+				to reset the system. This property can only be
+				used by one device on the system. It is an error
+				to include it more than once.
 
 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
+- qcom,pull-up			The initial state of the reset pin under
 				consideration.
 				0 = No pull-up
 				1 = pull-up enabled
diff --git a/Documentation/devicetree/bindings/power/qpnp-bms.txt b/Documentation/devicetree/bindings/power/qpnp-bms.txt
new file mode 100644
index 0000000..1d3c2db
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/qpnp-bms.txt
@@ -0,0 +1,80 @@
+Qualcomm's QPNP PMIC Battery Management System driver
+
+QPNP PMIC BMS provides interface to clients to read properties related
+to the battery. It's main function is to calculate the State of Charge (SOC),
+a 0-100 percentage representing the amount of charge left in the battery.
+
+BMS node
+
+Required properties:
+- compatible : should be "qcom,qpnp-bms" for the BM driver.
+- reg : offset and length of the PMIC BMS register map.
+- interrupts : the interrupt mappings for bms.
+		The format should be
+		<slave-id peripheral-id interrupt-number>.
+- interrupt-names : names for the mapped bms interrupt
+		The following interrupts are required:
+		0 : vsense_for_r
+		1 : vsense_avg
+		2 : sw_cc_thr
+		3 : ocv_thr
+		4 : charge_begin
+		5 : good_ocv
+		6 : ocv_for_r
+		7 : cc_thr
+- qcom,bms-r-sense-mohm : sensor resistance in in milli-ohms.
+- qcom,bms-v-cutoff-uv : cutoff voltage where the battery is considered dead in
+			micro-volts.
+- qcom,bms-max-voltage-uv : maximum voltage for the battery in micro-volts.
+- qcom,bms-r-conn-mohm : connector resistance in milli-ohms.
+- qcom,bms-shutdown-soc-valid-limit : If the ocv upon restart is within this
+			distance of the shutdown ocv, the BMS will try to force
+			the new SoC to the old one to provide charge continuity.
+			That is to say,
+				if (abs(shutdown-soc - current-soc) < limit)
+				then use old SoC.
+- qcom,bms-adjust-soc-low-threshold : The low threshold for the "flat portion"
+			of the charging curve. The BMS will not adjust SoC
+			based on voltage during this time.
+- qcom,bms-adjust-soc-high-threshold :  The high threshold for the "flat
+			portion" of the charging curve. The BMS will not
+			adjust SoC based on voltage during this time.
+- qcom,bms-chg-term-ua : current in micro-amps when charging is considered done.
+			As soon as current passes this point, charging is
+			stopped.
+
+Example:
+	bms@4000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		compatible = "qcom,qpnp-bms";
+		reg = <0x4000 0x100>;
+
+		interrupts =	<0x0 0x40 0x0>,
+				<0x0 0x40 0x1>,
+				<0x0 0x40 0x2>,
+				<0x0 0x40 0x3>,
+				<0x0 0x40 0x4>,
+				<0x0 0x40 0x5>,
+				<0x0 0x40 0x6>,
+				<0x0 0x40 0x7>;
+
+		interrupt-names = "vsense_for_r",
+				  "vsense_avg",
+				  "sw_cc_thr",
+				  "ocv_thr",
+				  "charge_begin",
+				  "good_ocv",
+				  "ocv_for_r",
+				  "cc_thr";
+
+		qcom,bms-r-sense-mohm = <10>;
+		qcom,bms-v-cutoff-uv = <3400000>;
+		qcom,bms-max-voltage-uv = <4200000>;
+		qcom,bms-r-conn-mohm = <18>;
+		qcom,bms-shutdown-soc-valid-limit = <20>;
+		qcom,bms-adjust-soc-low-threshold = <25>;
+		qcom,bms-adjust-soc-high-threshold = <45>;
+		qcom,bms-chg-term-ua = <100000>;
+	};
diff --git a/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
index 1f7e488..7731b33 100644
--- a/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
@@ -39,17 +39,17 @@
 		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];
+						    20 00 01];
 		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 */
+		qcom,panel-phy-bistCtrl = [00 00 b1 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-phy-laneConfig = [00 c2 45 00 00 00 00 01 75 /* lane0 config */
+					     00 c2 45 00 00 00 00 01 75 /* lane1 config */
+					     00 c2 45 00 00 00 00 01 75 /* lane2 config */
+					     00 c2 45 00 00 00 00 01 75 /* lane3 config */
+					     00 02 45 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
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index 0f5fd1c..869a357 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -30,6 +30,7 @@
 				     <0x0 0x8 0x4>;
 			interrupt-names = "kpdpwr", "resin", "resin-bark";
 			qcom,pon-dbc-delay = <15625>;
+			qcom,system-reset;
 
 			qcom,pon_1 {
 				qcom,pon-type = <0>;
@@ -66,6 +67,107 @@
 			qcom,cxo-freq = <19200000>;
 		};
 
+		pm8941-chg {
+			spmi-dev-container;
+			compatible = "qcom,qpnp-charger";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			qcom,chg-vddmax-mv = <4200>;
+			qcom,chg-vddsafe-mv = <4200>;
+			qcom,chg-vinmin-mv = <4200>;
+			qcom,chg-ibatmax-ma = <1500>;
+			qcom,chg-ibatterm-ma = <200>;
+
+			qcom,chg-chgr@1000 {
+				reg = <0x1000 0x100>;
+				interrupts =	<0x0 0x10 0x0>,
+						<0x0 0x10 0x1>,
+						<0x0 0x10 0x2>,
+						<0x0 0x10 0x3>,
+						<0x0 0x10 0x4>,
+						<0x0 0x10 0x5>,
+						<0x0 0x10 0x6>,
+						<0x0 0x10 0x7>;
+
+				interrupt-names =	"chg-done",
+							"chg-failed",
+							"fast-chg-on",
+							"trkl-chg-on",
+							"state-change",
+							"chgwdog",
+							"vbat-det-hi",
+							"vbat-det-lo";
+			};
+
+			qcom,chg-buck@1100 {
+				reg = <0x1100 0x100>;
+				interrupts =	<0x0 0x11 0x0>,
+						<0x0 0x11 0x1>,
+						<0x0 0x11 0x2>,
+						<0x0 0x11 0x3>,
+						<0x0 0x11 0x4>,
+						<0x0 0x11 0x5>,
+						<0x0 0x11 0x6>;
+
+				interrupt-names =	"vdd-loop",
+							"ibat-loop",
+							"ichg-loop",
+							"vchg-loop",
+							"overtemp",
+							"vref-ov",
+							"vbat-ov";
+			};
+
+			qcom,chg-bat-if@1200 {
+				reg = <0x1200 0x100>;
+				interrupts =	<0x0 0x12 0x0>,
+						<0x0 0x12 0x1>,
+						<0x0 0x12 0x2>,
+						<0x0 0x12 0x3>,
+						<0x0 0x12 0x4>;
+
+				interrupt-names =	"psi",
+							"vcp-on",
+							"bat-fet-on",
+							"bat-temp-ok",
+							"batt-pres";
+			};
+
+			qcom,chg-usb-chgpth@1300 {
+				reg = <0x1300 0x100>;
+				interrupts =	<0 0x13 0x0>,
+						<0 0x13 0x1>,
+						<0x0 0x13 0x2>;
+
+				interrupt-names =	"usbin-valid",
+							"coarse-det-usb",
+							"chg-gone";
+			};
+
+			qcom,chg-dc-chgpth@1400 {
+				reg = <0x1400 0x100>;
+				interrupts =	<0x0 0x14 0x0>,
+						<0x0 0x14 0x1>;
+
+				interrupt-names =	"dcin-valid",
+							"coarse-det-dc";
+			};
+
+			qcom,chg-boost@1500 {
+				reg = <0x1500 0x100>;
+				interrupts =	<0x0 0x15 0x0>,
+						<0x0 0x15 0x1>;
+
+				interrupt-names =	"limit-error",
+							"boost-pwr-ok";
+			};
+
+			qcom,chg-misc@1600 {
+				reg = <0x1600 0x100>;
+			};
+		};
+
 		pm8941_gpios {
 			spmi-dev-container;
 			compatible = "qcom,qpnp-pin";
diff --git a/arch/arm/boot/dts/msm8974-gpio.dtsi b/arch/arm/boot/dts/msm8974-gpio.dtsi
index e7c742c..dac87a3 100644
--- a/arch/arm/boot/dts/msm8974-gpio.dtsi
+++ b/arch/arm/boot/dts/msm8974-gpio.dtsi
@@ -109,6 +109,13 @@
 
 			gpio@d200 {
 				status = "ok";
+				qcom,mode = <1>;		/* QPNP_PIN_MODE_DIG_OUT */
+				qcom,output-type = <0>;		/* QPNP_PIN_OUT_BUF_CMOS */
+				qcom,pull = <5>;		/* QPNP_PIN_PULL_NO */
+				qcom,vin-sel = <2>;		/* QPNP_PIN_VIN2 */
+				qcom,out-strength = <2>;	/* QPNP_PIN_OUT_STRENGTH_MED */
+				qcom,src-select = <0>;		/* QPNP_PIN_SEL_FUNC_CONSTANT */
+				qcom,master-en = <1>;
 			};
 
 			gpio@d300 {
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index fe60c83..da0e1e5 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -60,6 +60,10 @@
 			<244800 133330000>;
 	};
 
+	qcom,wfd {
+		compatible = "qcom,msm-wfd";
+	};
+
 	serial@f991f000 {
 		compatible = "qcom,msm-lsuart-v14";
 		reg = <0xf991f000 0x1000>;
@@ -860,6 +864,14 @@
 		interrupt-names = "l1_irq", "l2_irq";
 	};
 
+	qcom,cache_dump {
+		compatible = "qcom,cache_dump";
+		qcom,l1-dump-size = <0x100000>;
+		qcom,l2-dump-size = <0x500000>;
+		qcom,memory-reservation-type = "EBI1";
+		qcom,memory-reservation-size = <0x600000>; /* 6M EBI1 buffer */
+	};
+
 	tsens@fc4a8000 {
 		compatible = "qcom,msm-tsens";
 		reg = <0xfc4a8000 0x2000>,
diff --git a/arch/arm/boot/dts/msm8974_pm.dtsi b/arch/arm/boot/dts/msm8974_pm.dtsi
index f3efbb8..8e3f4b8 100644
--- a/arch/arm/boot/dts/msm8974_pm.dtsi
+++ b/arch/arm/boot/dts/msm8974_pm.dtsi
@@ -309,8 +309,9 @@
 		qcom,ipc-bit-offset = <1>;
 
 		qcom,gic-parent = <&intc>;
-		qcom,gic-map = <47 180>, /* usb2_hsic_async_wakeup_irq */
+		qcom,gic-map = <47 172>, /* usb2_hsic_async_wakeup_irq */
 			<53 104>, /* mdss_irq */
+			<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
 			<0xff 57>,  /* mss_to_apps_irq(0) */
 			<0xff 58>,  /* mss_to_apps_irq(1) */
 			<0xff 59>,  /* mss_to_apps_irq(2) */
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index 7b7adca..8ad3b66 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -55,7 +55,7 @@
 		compatible = "qcom,msm_sps";
 		reg = <0xf9984000 0x15000>,
 		      <0xf9999000 0xb000>,
-		      <0xfe800000 0x4800>;
+		      <0xfe803000 0x4800>;
 		interrupts = <0 94 0>;
 		qcom,device-type = <2>;
 	};
diff --git a/arch/arm/configs/msm7627a-perf_defconfig b/arch/arm/configs/msm7627a-perf_defconfig
index 1b792d9..7f10641 100644
--- a/arch/arm/configs/msm7627a-perf_defconfig
+++ b/arch/arm/configs/msm7627a-perf_defconfig
@@ -283,6 +283,7 @@
 CONFIG_ION=y
 CONFIG_ION_MSM=y
 CONFIG_MSM_KGSL=y
+CONFIG_MSM_KGSL_DISABLE_SHADOW_WRITES=y
 CONFIG_FB=y
 CONFIG_FB_MSM=y
 # CONFIG_FB_MSM_BACKLIGHT is not set
diff --git a/arch/arm/configs/msm7627a_defconfig b/arch/arm/configs/msm7627a_defconfig
index aeb59af..0e0653f 100644
--- a/arch/arm/configs/msm7627a_defconfig
+++ b/arch/arm/configs/msm7627a_defconfig
@@ -285,6 +285,7 @@
 CONFIG_ION=y
 CONFIG_ION_MSM=y
 CONFIG_MSM_KGSL=y
+CONFIG_MSM_KGSL_DISABLE_SHADOW_WRITES=y
 CONFIG_FB=y
 CONFIG_FB_MSM=y
 # CONFIG_FB_MSM_BACKLIGHT is not set
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index 2c8f71e..afe528d 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -69,6 +69,7 @@
 CONFIG_MSM_DSPS=y
 CONFIG_MSM_IPC_ROUTER=y
 CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
+CONFIG_MSM_AVS_HW=y
 # CONFIG_MSM_HW3D is not set
 CONFIG_MSM_PIL_QDSP6V4=y
 CONFIG_MSM_PIL_RIVA=y
@@ -96,6 +97,7 @@
 CONFIG_MSM_L1_ERR_PANIC=y
 CONFIG_MSM_L1_ERR_LOG=y
 CONFIG_MSM_L2_ERP_2BIT_PANIC=y
+CONFIG_MSM_EVENT_TIMER=y
 CONFIG_MSM_DCVS=y
 CONFIG_MSM_HSIC_SYSMON=y
 CONFIG_STRICT_MEMORY_RWX=y
@@ -389,6 +391,7 @@
 CONFIG_FB_MSM_WRITEBACK_MSM_PANEL=y
 CONFIG_FB_MSM_LVDS_MIPI_PANEL_DETECT=y
 CONFIG_FB_MSM_HDMI_MSM_PANEL=y
+CONFIG_FB_MSM_HDMI_MHL_8334=y
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
 CONFIG_SOUND=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index a2deab2..4c9383d 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -68,6 +68,7 @@
 CONFIG_MSM_DSPS=y
 CONFIG_MSM_IPC_ROUTER=y
 CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
+CONFIG_MSM_AVS_HW=y
 # CONFIG_MSM_HW3D is not set
 CONFIG_MSM_PIL_QDSP6V4=y
 CONFIG_MSM_PIL_RIVA=y
@@ -87,6 +88,7 @@
 CONFIG_MSM_RPM_RBCPR_STATS_LOG=y
 CONFIG_MSM_BUS_SCALING=y
 CONFIG_MSM_BUS_RPM_MULTI_TIER_ENABLED=y
+CONFIG_MSM_EVENT_TIMER=y
 CONFIG_MSM_WATCHDOG=y
 CONFIG_MSM_DLOAD_MODE=y
 CONFIG_MSM_RTB=y
@@ -392,6 +394,7 @@
 CONFIG_FB_MSM_WRITEBACK_MSM_PANEL=y
 CONFIG_FB_MSM_LVDS_MIPI_PANEL_DETECT=y
 CONFIG_FB_MSM_HDMI_MSM_PANEL=y
+CONFIG_FB_MSM_HDMI_MHL_8334=y
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
 CONFIG_SOUND=y
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
new file mode 100644
index 0000000..392e062
--- /dev/null
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -0,0 +1,401 @@
+# CONFIG_ARM_PATCH_PHYS_VIRT is not set
+CONFIG_EXPERIMENTAL=y
+CONFIG_LOCALVERSION="-perf"
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_KALLSYMS_ALL=y
+CONFIG_ASHMEM=y
+CONFIG_EMBEDDED=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+CONFIG_KPROBES=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_EFI_PARTITION=y
+CONFIG_ARCH_MSM=y
+CONFIG_ARCH_MSM8974=y
+CONFIG_ARCH_MSM8226=y
+CONFIG_MSM_KRAIT_TBB_ABORT_HANDLER=y
+# CONFIG_MSM_STACKED_MEMORY is not set
+CONFIG_CPU_HAS_L2_PMU=y
+# CONFIG_MSM_FIQ_SUPPORT is not set
+# CONFIG_MSM_PROC_COMM is not set
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SMD_PKG4=y
+CONFIG_MSM_BAM_DMUX=y
+CONFIG_MSM_IPC_ROUTER=y
+CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
+# CONFIG_MSM_HW3D is not set
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_PIL_LPASS_QDSP6V5=y
+CONFIG_MSM_PIL_MSS_QDSP6V5=y
+CONFIG_MSM_PIL_MBA=y
+CONFIG_MSM_PIL_VENUS=y
+CONFIG_MSM_PIL_PRONTO=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_BUS_SCALING=y
+CONFIG_MSM_WATCHDOG_V2=y
+CONFIG_MSM_MEMORY_DUMP=y
+CONFIG_MSM_DLOAD_MODE=y
+CONFIG_MSM_ADSP_LOADER=m
+CONFIG_MSM_OCMEM=y
+CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
+CONFIG_MSM_OCMEM_DEBUG=y
+CONFIG_MSM_OCMEM_NONSECURE=y
+CONFIG_MSM_CACHE_ERP=y
+CONFIG_MSM_L1_ERR_PANIC=y
+CONFIG_MSM_L1_ERR_LOG=y
+CONFIG_MSM_L2_ERP_2BIT_PANIC=y
+CONFIG_STRICT_MEMORY_RWX=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SMP=y
+# CONFIG_SMP_ON_UP is not set
+CONFIG_ARM_ARCH_TIMER=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_HIGHMEM=y
+CONFIG_VMALLOC_RESERVE=0x19000000
+CONFIG_CC_STACKPROTECTOR=y
+CONFIG_CP_ACCESS=y
+CONFIG_USE_OF=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_IDLE=y
+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
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_NETLINK_LOG=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_SIP=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_LOG=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_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
+CONFIG_NET_CLS_FW=y
+CONFIG_NET_CLS_U32=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_FLOW=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_CMP=y
+CONFIG_NET_EMATCH_NBYTE=y
+CONFIG_NET_EMATCH_U32=y
+CONFIG_NET_EMATCH_META=y
+CONFIG_NET_EMATCH_TEXT=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_BT=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_CFG80211=m
+CONFIG_RFKILL=y
+CONFIG_GENLOCK=y
+CONFIG_GENLOCK_MISCDEVICE=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_QSEECOM=y
+CONFIG_SCSI=y
+CONFIG_SCSI_TGT=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+CONFIG_TUN=y
+CONFIG_KS8851=m
+# CONFIG_MSM_RMNET is not set
+CONFIG_MSM_RMNET_BAM=y
+CONFIG_SLIP=y
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_MODE_SLIP6=y
+CONFIG_WCNSS_CORE=y
+CONFIG_WCNSS_CORE_PRONTO=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=m
+CONFIG_KEYBOARD_GPIO=y
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ATMEL_MXT=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_SERIAL_MSM_HSL=y
+CONFIG_SERIAL_MSM_HSL_CONSOLE=y
+CONFIG_DIAG_CHAR=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM=y
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_QUP=y
+CONFIG_SPI=y
+CONFIG_SPI_QUP=y
+CONFIG_SPI_SPIDEV=m
+CONFIG_SPMI=y
+CONFIG_SPMI_MSM_PMIC_ARB=y
+CONFIG_MSM_QPNP_INT=y
+CONFIG_SLIMBUS_MSM_CTRL=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_QPNP_PIN=y
+CONFIG_GPIO_QPNP_PIN_DEBUG=y
+CONFIG_POWER_SUPPLY=y
+# CONFIG_BATTERY_MSM is not set
+CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
+CONFIG_SENSORS_QPNP_ADC_CURRENT=y
+CONFIG_THERMAL=y
+CONFIG_THERMAL_TSENS8974=y
+CONFIG_WCD9320_CODEC=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_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_VIDEOBUF2_MSM_MEM=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_MSM_CAMERA_V4L2=y
+CONFIG_OV2720=y
+CONFIG_MSM_CAMERA_SENSOR=y
+CONFIG_MSM_ACTUATOR=y
+CONFIG_MSM_JPEG=y
+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_RADIO_IRIS=y
+CONFIG_RADIO_IRIS_TRANSPORT=m
+CONFIG_ION=y
+CONFIG_ION_MSM=y
+CONFIG_MSM_KGSL=y
+CONFIG_FB=y
+CONFIG_FB_MSM=y
+# CONFIG_FB_MSM_BACKLIGHT is not set
+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
+# CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_MSM8974=y
+CONFIG_USB=y
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_ISD200=y
+CONFIG_USB_STORAGE_USBAT=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+CONFIG_USB_STORAGE_ALAUDA=y
+CONFIG_USB_STORAGE_ONETOUCH=y
+CONFIG_USB_STORAGE_KARMA=y
+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
+CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_BLOCK_MINORS=32
+# CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_TEST=m
+CONFIG_MMC_MSM=y
+CONFIG_MMC_MSM_SPS_SUPPORT=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
+CONFIG_RTC_DRV_QPNP=y
+CONFIG_STAGING=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_ANDROID_LOGGER=y
+CONFIG_ANDROID_RAM_CONSOLE=y
+CONFIG_ANDROID_TIMED_GPIO=y
+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_MSM_QDSS=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT4_FS=y
+CONFIG_FUSE_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_TIMER_STATS=y
+# 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_PID_IN_CONTEXTIDR=y
+CONFIG_KEYS=y
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_DEV_QCRYPTO=m
+CONFIG_CRYPTO_DEV_QCE=m
+CONFIG_CRYPTO_DEV_QCEDEV=m
+CONFIG_CRC_CCITT=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 471ecd9..7e3aad7 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -20,14 +20,18 @@
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_RD_BZIP2=y
 CONFIG_RD_LZMA=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_PANIC_TIMEOUT=5
 CONFIG_KALLSYMS_ALL=y
 CONFIG_ASHMEM=y
 CONFIG_EMBEDDED=y
 CONFIG_PROFILING=y
-CONFIG_OPROFILE=m
+CONFIG_OPROFILE=y
+CONFIG_KPROBES=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
 CONFIG_PARTITION_ADVANCED=y
 CONFIG_EFI_PARTITION=y
 CONFIG_ARCH_MSM=y
@@ -35,39 +39,41 @@
 CONFIG_ARCH_MSM8226=y
 CONFIG_MSM_KRAIT_TBB_ABORT_HANDLER=y
 # CONFIG_MSM_STACKED_MEMORY is not set
-CONFIG_KERNEL_PMEM_EBI_REGION=y
 CONFIG_CPU_HAS_L2_PMU=y
 # CONFIG_MSM_FIQ_SUPPORT is not set
 # CONFIG_MSM_PROC_COMM is not set
 CONFIG_MSM_SMD=y
 CONFIG_MSM_SMD_PKG4=y
+CONFIG_MSM_BAM_DMUX=y
 CONFIG_MSM_IPC_ROUTER=y
 CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
 # CONFIG_MSM_HW3D is not set
+CONFIG_MSM_SUBSYSTEM_RESTART=y
 CONFIG_MSM_PIL_LPASS_QDSP6V5=y
 CONFIG_MSM_PIL_MSS_QDSP6V5=y
 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_BUS_SCALING=y
+CONFIG_MSM_WATCHDOG_V2=y
+CONFIG_MSM_MEMORY_DUMP=y
+CONFIG_MSM_DLOAD_MODE=y
+CONFIG_MSM_ADSP_LOADER=m
 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_L1_ERR_LOG=y
 CONFIG_MSM_L2_ERP_PRINT_ACCESS_ERRORS=y
+CONFIG_MSM_L2_ERP_1BIT_PANIC=y
 CONFIG_MSM_L2_ERP_2BIT_PANIC=y
-CONFIG_MSM_ADSP_LOADER=m
+CONFIG_STRICT_MEMORY_RWX=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_SMP=y
@@ -77,6 +83,8 @@
 CONFIG_AEABI=y
 CONFIG_HIGHMEM=y
 CONFIG_VMALLOC_RESERVE=0x19000000
+CONFIG_CC_STACKPROTECTOR=y
+CONFIG_CP_ACCESS=y
 CONFIG_USE_OF=y
 CONFIG_CPU_FREQ=y
 CONFIG_CPU_FREQ_GOV_POWERSAVE=y
@@ -113,10 +121,100 @@
 CONFIG_IPV6_MIP6=y
 CONFIG_IPV6_MULTIPLE_TABLES=y
 CONFIG_IPV6_SUBTREES=y
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_NETLINK_LOG=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_SIP=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_LOG=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_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
 CONFIG_NET_CLS_FW=y
+CONFIG_NET_CLS_U32=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_FLOW=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_CMP=y
+CONFIG_NET_EMATCH_NBYTE=y
+CONFIG_NET_EMATCH_U32=y
+CONFIG_NET_EMATCH_META=y
+CONFIG_NET_EMATCH_TEXT=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_BT=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_CFG80211=m
+CONFIG_RFKILL=y
 CONFIG_GENLOCK=y
 CONFIG_GENLOCK_MISCDEVICE=y
 CONFIG_BLK_DEV_LOOP=y
@@ -136,15 +234,20 @@
 CONFIG_DM_CRYPT=y
 CONFIG_NETDEVICES=y
 CONFIG_DUMMY=y
+CONFIG_TUN=y
 CONFIG_KS8851=m
 # CONFIG_MSM_RMNET is not set
 CONFIG_MSM_RMNET_BAM=y
+CONFIG_SLIP=y
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_MODE_SLIP6=y
+CONFIG_WCNSS_CORE=y
+CONFIG_WCNSS_CORE_PRONTO=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
@@ -156,14 +259,12 @@
 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
 CONFIG_SPMI=y
 CONFIG_SPMI_MSM_PMIC_ARB=y
 CONFIG_MSM_QPNP_INT=y
-CONFIG_SLIMBUS=y
 CONFIG_SLIMBUS_MSM_CTRL=y
 CONFIG_DEBUG_GPIO=y
 CONFIG_GPIO_SYSFS=y
@@ -171,11 +272,11 @@
 CONFIG_GPIO_QPNP_PIN_DEBUG=y
 CONFIG_POWER_SUPPLY=y
 # CONFIG_BATTERY_MSM 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_WCD9320_CODEC=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
 CONFIG_REGULATOR_STUB=y
 CONFIG_REGULATOR_QPNP=y
@@ -186,9 +287,11 @@
 CONFIG_VIDEOBUF2_MSM_MEM=y
 CONFIG_V4L_PLATFORM_DRIVERS=y
 CONFIG_MSM_CAMERA_V4L2=y
+CONFIG_MSM_WFD=y
+CONFIG_OV2720=y
 CONFIG_MSM_CAMERA_SENSOR=y
 CONFIG_MSM_ACTUATOR=y
-CONFIG_MSM_CAM_IRQ_ROUTER=n
+CONFIG_MSM_JPEG=y
 CONFIG_MSM_CCI=y
 CONFIG_MSM_CSI30_HEADER=y
 CONFIG_MSM_CSIPHY=y
@@ -196,11 +299,8 @@
 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
@@ -218,7 +318,6 @@
 CONFIG_SND=y
 CONFIG_SND_SOC=y
 CONFIG_SND_SOC_MSM8974=y
-CONFIG_WCD9320_CODEC=y
 CONFIG_USB=y
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_STORAGE=y
@@ -248,8 +347,6 @@
 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
@@ -273,6 +370,7 @@
 CONFIG_QPNP_POWER_ON=y
 CONFIG_QPNP_CLKDIV=y
 CONFIG_MSM_IOMMU=y
+CONFIG_MSM_QDSS=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT3_FS=y
@@ -286,48 +384,34 @@
 CONFIG_NLS_ISO8859_1=y
 CONFIG_PRINTK_TIME=y
 CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_FS=y
+CONFIG_LOCKUP_DETECTOR=y
+# CONFIG_DETECT_HUNG_TASK is not set
 # CONFIG_SCHED_DEBUG is not set
 CONFIG_TIMER_STATS=y
+CONFIG_DEBUG_KMEMLEAK=y
+CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
 # CONFIG_DEBUG_PREEMPT is not set
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+CONFIG_DEBUG_STACK_USAGE=y
 CONFIG_DEBUG_INFO=y
 CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DEBUG_LIST=y
+CONFIG_FAULT_INJECTION=y
+CONFIG_FAIL_PAGE_ALLOC=y
+CONFIG_FAULT_INJECTION_DEBUG_FS=y
+CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
+CONFIG_DEBUG_PAGEALLOC=y
 CONFIG_ENABLE_DEFAULT_TRACERS=y
 CONFIG_DYNAMIC_DEBUG=y
 CONFIG_DEBUG_USER=y
+CONFIG_PID_IN_CONTEXTIDR=y
 CONFIG_KEYS=y
 CONFIG_CRYPTO_MD4=y
-CONFIG_CRYPTO_SHA256=y
-CONFIG_CRYPTO_AES=y
 CONFIG_CRYPTO_ARC4=y
 CONFIG_CRYPTO_TWOFISH=y
 CONFIG_CRYPTO_DEV_QCRYPTO=m
 CONFIG_CRYPTO_DEV_QCE=m
 CONFIG_CRYPTO_DEV_QCEDEV=m
 CONFIG_CRC_CCITT=y
-CONFIG_LIBCRC32C=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/kernel/traps.c b/arch/arm/kernel/traps.c
index 63d402f..1e9504b 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -37,6 +37,8 @@
 
 #include "signal.h"
 
+#include <trace/events/exception.h>
+
 static const char *handler[]= { "prefetch abort", "data abort", "address exception", "interrupt" };
 
 void *vectors_page;
@@ -410,6 +412,8 @@
 	if (call_undef_hook(regs, instr) == 0)
 		return;
 
+	trace_undef_instr(regs, (void *)pc);
+
 #ifdef CONFIG_DEBUG_USER
 	if (user_debug & UDBG_UNDEFINED) {
 		printk(KERN_INFO "%s (%d): undefined instruction: pc=%p\n",
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index badee85..c9b786c 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -2142,6 +2142,14 @@
 	depends on PM
 	bool
 
+config MSM_EVENT_TIMER
+	bool "Event timer"
+	help
+		This option enables a modules that manages a list of event timers that
+		need to be monitored by the PM. The enables the PM code to monitor
+		events that require the core to be awake and ready to handle the
+		event.
+
 config MSM_NOPM
 	default y if !PM
 	bool
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 70234bf..d8e625a 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -343,6 +343,7 @@
 obj-$(CONFIG_MSM_BUSPM_DEV) += msm-buspm-dev.o
 
 obj-$(CONFIG_MSM_IOMMU)		+= devices-iommu.o iommu_domains.o
+obj-$(CONFIG_MSM_EVENT_TIMER)		+= event_timer.o
 
 ifdef CONFIG_VCM
 obj-$(CONFIG_ARCH_MSM8X60) += board-msm8x60-vcm.o
diff --git a/arch/arm/mach-msm/acpuclock-7627.c b/arch/arm/mach-msm/acpuclock-7627.c
index 7be3667..1a2ae48 100644
--- a/arch/arm/mach-msm/acpuclock-7627.c
+++ b/arch/arm/mach-msm/acpuclock-7627.c
@@ -739,7 +739,8 @@
 			}
 		}
 
-		if (!(plls_enabled & (1 << tgt_s->pll))) {
+		if ((tgt_s->pll != ACPU_PLL_TCXO) &&
+				!(plls_enabled & (1 << tgt_s->pll))) {
 			rc = clk_enable(pll_clk[tgt_s->pll].clk);
 			if (rc < 0) {
 				pr_err("PLL%d enable failed (%d)\n",
@@ -827,7 +828,8 @@
 		goto out;
 
 	/* Change the AXI bus frequency if we can. */
-	if (strt_s->axiclk_khz != tgt_s->axiclk_khz) {
+	if (reason != SETRATE_PC &&
+		strt_s->axiclk_khz != tgt_s->axiclk_khz) {
 		res = clk_set_rate(drv_state.ebi1_clk,
 				tgt_s->axiclk_khz * 1000);
 		if (res < 0)
diff --git a/arch/arm/mach-msm/acpuclock-8064.c b/arch/arm/mach-msm/acpuclock-8064.c
index 3c80875..06c2579 100644
--- a/arch/arm/mach-msm/acpuclock-8064.c
+++ b/arch/arm/mach-msm/acpuclock-8064.c
@@ -219,7 +219,7 @@
 	.l2_freq_tbl = l2_freq_tbl,
 	.l2_freq_tbl_size = sizeof(l2_freq_tbl),
 	.bus_scale = &bus_scale_data,
-	.qfprom_phys_base = 0x00700000,
+	.pte_efuse_phys = 0x007000C0,
 	.stby_khz = 384000,
 };
 
diff --git a/arch/arm/mach-msm/acpuclock-8627.c b/arch/arm/mach-msm/acpuclock-8627.c
index 07a7f8f..9e6662d 100644
--- a/arch/arm/mach-msm/acpuclock-8627.c
+++ b/arch/arm/mach-msm/acpuclock-8627.c
@@ -138,7 +138,7 @@
 	.l2_freq_tbl = l2_freq_tbl,
 	.l2_freq_tbl_size = sizeof(l2_freq_tbl),
 	.bus_scale = &bus_scale_data,
-	.qfprom_phys_base = 0x00700000,
+	.pte_efuse_phys = 0x007000C0,
 	.stby_khz = 384000,
 };
 
diff --git a/arch/arm/mach-msm/acpuclock-8930.c b/arch/arm/mach-msm/acpuclock-8930.c
index 77876ee..b8ca865 100644
--- a/arch/arm/mach-msm/acpuclock-8930.c
+++ b/arch/arm/mach-msm/acpuclock-8930.c
@@ -221,7 +221,7 @@
 	.l2_freq_tbl = l2_freq_tbl,
 	.l2_freq_tbl_size = sizeof(l2_freq_tbl),
 	.bus_scale = &bus_scale_data,
-	.qfprom_phys_base = 0x00700000,
+	.pte_efuse_phys = 0x007000C0,
 	.stby_khz = 384000,
 };
 
diff --git a/arch/arm/mach-msm/acpuclock-8930aa.c b/arch/arm/mach-msm/acpuclock-8930aa.c
index dbc3e32..d589f1a 100644
--- a/arch/arm/mach-msm/acpuclock-8930aa.c
+++ b/arch/arm/mach-msm/acpuclock-8930aa.c
@@ -200,7 +200,7 @@
 	.l2_freq_tbl = l2_freq_tbl,
 	.l2_freq_tbl_size = sizeof(l2_freq_tbl),
 	.bus_scale = &bus_scale_data,
-	.qfprom_phys_base = 0x00700000,
+	.pte_efuse_phys = 0x007000C0,
 	.stby_khz = 384000,
 };
 
diff --git a/arch/arm/mach-msm/acpuclock-8960.c b/arch/arm/mach-msm/acpuclock-8960.c
index 631bd7e..e16c6b6 100644
--- a/arch/arm/mach-msm/acpuclock-8960.c
+++ b/arch/arm/mach-msm/acpuclock-8960.c
@@ -112,8 +112,10 @@
 	{ }
 };
 
+#define AVS(x) .avsdscr_setting = (x)
+
 static struct acpu_level acpu_freq_tbl_slow[] __initdata = {
-	{ 1, {   384000, PLL_8, 0, 2, 0x00 }, L2(0),   950000 },
+	{ 1, {   384000, PLL_8, 0, 2, 0x00 }, L2(0),   950000, AVS(0x40001F) },
 	{ 0, {   432000, HFPLL, 2, 0, 0x20 }, L2(6),   975000 },
 	{ 1, {   486000, HFPLL, 2, 0, 0x24 }, L2(6),   975000 },
 	{ 0, {   540000, HFPLL, 2, 0, 0x28 }, L2(6),  1000000 },
@@ -126,20 +128,20 @@
 	{ 1, {   918000, HFPLL, 1, 0, 0x22 }, L2(6),  1100000 },
 	{ 0, {   972000, HFPLL, 1, 0, 0x24 }, L2(6),  1125000 },
 	{ 1, {  1026000, HFPLL, 1, 0, 0x26 }, L2(6),  1125000 },
-	{ 0, {  1080000, HFPLL, 1, 0, 0x28 }, L2(18), 1175000 },
-	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(18), 1175000 },
-	{ 0, {  1188000, HFPLL, 1, 0, 0x2C }, L2(18), 1200000 },
-	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(18), 1200000 },
-	{ 0, {  1296000, HFPLL, 1, 0, 0x30 }, L2(18), 1225000 },
-	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(18), 1225000 },
-	{ 0, {  1404000, HFPLL, 1, 0, 0x34 }, L2(18), 1237500 },
-	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(18), 1237500 },
-	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(18), 1250000 },
+	{ 0, {  1080000, HFPLL, 1, 0, 0x28 }, L2(18), 1175000, AVS(0x400015) },
+	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(18), 1175000, AVS(0x400015) },
+	{ 0, {  1188000, HFPLL, 1, 0, 0x2C }, L2(18), 1200000, AVS(0x400015) },
+	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(18), 1200000, AVS(0x400015) },
+	{ 0, {  1296000, HFPLL, 1, 0, 0x30 }, L2(18), 1225000, AVS(0x400015) },
+	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(18), 1225000, AVS(0x400015) },
+	{ 0, {  1404000, HFPLL, 1, 0, 0x34 }, L2(18), 1237500, AVS(0x400015) },
+	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(18), 1237500, AVS(0x100018) },
+	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(18), 1250000, AVS(0x400012) },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_nom[] __initdata = {
-	{ 1, {   384000, PLL_8, 0, 2, 0x00 }, L2(0),   900000 },
+	{ 1, {   384000, PLL_8, 0, 2, 0x00 }, L2(0),   900000, AVS(0x40007F) },
 	{ 0, {   432000, HFPLL, 2, 0, 0x20 }, L2(6),   925000 },
 	{ 1, {   486000, HFPLL, 2, 0, 0x24 }, L2(6),   925000 },
 	{ 0, {   540000, HFPLL, 2, 0, 0x28 }, L2(6),   950000 },
@@ -152,20 +154,20 @@
 	{ 1, {   918000, HFPLL, 1, 0, 0x22 }, L2(6),  1050000 },
 	{ 0, {   972000, HFPLL, 1, 0, 0x24 }, L2(6),  1075000 },
 	{ 1, {  1026000, HFPLL, 1, 0, 0x26 }, L2(6),  1075000 },
-	{ 0, {  1080000, HFPLL, 1, 0, 0x28 }, L2(18), 1125000 },
-	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(18), 1125000 },
-	{ 0, {  1188000, HFPLL, 1, 0, 0x2C }, L2(18), 1150000 },
-	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(18), 1150000 },
-	{ 0, {  1296000, HFPLL, 1, 0, 0x30 }, L2(18), 1175000 },
-	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(18), 1175000 },
-	{ 0, {  1404000, HFPLL, 1, 0, 0x34 }, L2(18), 1187500 },
-	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(18), 1187500 },
-	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(18), 1200000 },
+	{ 0, {  1080000, HFPLL, 1, 0, 0x28 }, L2(18), 1125000, AVS(0x400015) },
+	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(18), 1125000, AVS(0x400015) },
+	{ 0, {  1188000, HFPLL, 1, 0, 0x2C }, L2(18), 1150000, AVS(0x400015) },
+	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(18), 1150000, AVS(0x400015) },
+	{ 0, {  1296000, HFPLL, 1, 0, 0x30 }, L2(18), 1175000, AVS(0x400015) },
+	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(18), 1175000, AVS(0x400015) },
+	{ 0, {  1404000, HFPLL, 1, 0, 0x34 }, L2(18), 1187500, AVS(0x400015) },
+	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(18), 1187500, AVS(0x100018) },
+	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(18), 1200000, AVS(0x400012) },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_fast[] __initdata = {
-	{ 1, {   384000, PLL_8, 0, 2, 0x00 }, L2(0),   850000 },
+	{ 1, {   384000, PLL_8, 0, 2, 0x00 }, L2(0),   850000, AVS(0x4000FF) },
 	{ 0, {   432000, HFPLL, 2, 0, 0x20 }, L2(6),   875000 },
 	{ 1, {   486000, HFPLL, 2, 0, 0x24 }, L2(6),   875000 },
 	{ 0, {   540000, HFPLL, 2, 0, 0x28 }, L2(6),   900000 },
@@ -178,15 +180,15 @@
 	{ 1, {   918000, HFPLL, 1, 0, 0x22 }, L2(6),  1000000 },
 	{ 0, {   972000, HFPLL, 1, 0, 0x24 }, L2(6),  1025000 },
 	{ 1, {  1026000, HFPLL, 1, 0, 0x26 }, L2(6),  1025000 },
-	{ 0, {  1080000, HFPLL, 1, 0, 0x28 }, L2(18), 1075000 },
-	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(18), 1075000 },
-	{ 0, {  1188000, HFPLL, 1, 0, 0x2C }, L2(18), 1100000 },
-	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(18), 1100000 },
-	{ 0, {  1296000, HFPLL, 1, 0, 0x30 }, L2(18), 1125000 },
-	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(18), 1125000 },
-	{ 0, {  1404000, HFPLL, 1, 0, 0x34 }, L2(18), 1137500 },
-	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(18), 1137500 },
-	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(18), 1150000 },
+	{ 0, {  1080000, HFPLL, 1, 0, 0x28 }, L2(18), 1075000, AVS(0x10001B) },
+	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(18), 1075000, AVS(0x10001B) },
+	{ 0, {  1188000, HFPLL, 1, 0, 0x2C }, L2(18), 1100000, AVS(0x10001B) },
+	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(18), 1100000, AVS(0x10001B) },
+	{ 0, {  1296000, HFPLL, 1, 0, 0x30 }, L2(18), 1125000, AVS(0x10001B) },
+	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(18), 1125000, AVS(0x400012) },
+	{ 0, {  1404000, HFPLL, 1, 0, 0x34 }, L2(18), 1137500, AVS(0x400012) },
+	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(18), 1137500, AVS(0x400012) },
+	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(18), 1150000, AVS(0x400012) },
 	{ 0, { 0 } }
 };
 
@@ -204,7 +206,7 @@
 	.l2_freq_tbl = l2_freq_tbl,
 	.l2_freq_tbl_size = sizeof(l2_freq_tbl),
 	.bus_scale = &bus_scale_data,
-	.qfprom_phys_base = 0x00700000,
+	.pte_efuse_phys = 0x007000C0,
 	.stby_khz = 384000,
 };
 
diff --git a/arch/arm/mach-msm/acpuclock-8960ab.c b/arch/arm/mach-msm/acpuclock-8960ab.c
index 63bff55..628e1ba 100644
--- a/arch/arm/mach-msm/acpuclock-8960ab.c
+++ b/arch/arm/mach-msm/acpuclock-8960ab.c
@@ -146,7 +146,7 @@
 	.l2_freq_tbl = l2_freq_tbl,
 	.l2_freq_tbl_size = sizeof(l2_freq_tbl),
 	.bus_scale = &bus_scale_data,
-	.qfprom_phys_base = 0x00700000,
+	.pte_efuse_phys = 0x007000C0,
 	.stby_khz = 384000,
 };
 
diff --git a/arch/arm/mach-msm/acpuclock-8974.c b/arch/arm/mach-msm/acpuclock-8974.c
index 16f77ba..ee2ca45 100644
--- a/arch/arm/mach-msm/acpuclock-8974.c
+++ b/arch/arm/mach-msm/acpuclock-8974.c
@@ -179,7 +179,7 @@
 	.l2_freq_tbl = l2_freq_tbl,
 	.l2_freq_tbl_size = sizeof(l2_freq_tbl),
 	.bus_scale = &bus_scale_data,
-	.qfprom_phys_base = 0xFC4A8000,
+	.pte_efuse_phys = 0xFC4B80B0,
 	.stby_khz = 300000,
 };
 
diff --git a/arch/arm/mach-msm/acpuclock-krait.c b/arch/arm/mach-msm/acpuclock-krait.c
index 9afa7c0..2951c1a 100644
--- a/arch/arm/mach-msm/acpuclock-krait.c
+++ b/arch/arm/mach-msm/acpuclock-krait.c
@@ -36,6 +36,7 @@
 
 #include "acpuclock.h"
 #include "acpuclock-krait.h"
+#include "avs.h"
 
 /* MUX source selects. */
 #define PRI_SRC_SEL_SEC_SRC	0
@@ -44,9 +45,6 @@
 #define SEC_SRC_SEL_L2PLL	1
 #define SEC_SRC_SEL_AUX		2
 
-/* PTE EFUSE register offset. */
-#define PTE_EFUSE		0xC0
-
 static DEFINE_MUTEX(driver_lock);
 static DEFINE_SPINLOCK(l2_lock);
 
@@ -472,6 +470,12 @@
 	vdd_data.vdd_core = calculate_vdd_core(tgt);
 	vdd_data.ua_core = tgt->ua_core;
 
+	/* Disable AVS before voltage switch */
+	if (reason == SETRATE_CPUFREQ && drv.scalable[cpu].avs_enabled) {
+		AVS_DISABLE(cpu);
+		drv.scalable[cpu].avs_enabled = false;
+	}
+
 	/* Increase VDD levels if needed. */
 	if (reason == SETRATE_CPUFREQ || reason == SETRATE_HOTPLUG) {
 		rc = increase_vdd(cpu, &vdd_data, reason);
@@ -507,6 +511,12 @@
 	/* Drop VDD levels if we can. */
 	decrease_vdd(cpu, &vdd_data, reason);
 
+	/* Re-enable AVS */
+	if (reason == SETRATE_CPUFREQ && tgt->avsdscr_setting) {
+		AVS_ENABLE(cpu, tgt->avsdscr_setting);
+		drv.scalable[cpu].avs_enabled = true;
+	}
+
 	dev_dbg(drv.dev, "ACPU%d speed change complete\n", cpu);
 
 out:
@@ -926,25 +936,27 @@
 
 static void krait_apply_vmin(struct acpu_level *tbl)
 {
-	for (; tbl->speed.khz != 0; tbl++)
+	for (; tbl->speed.khz != 0; tbl++) {
 		if (tbl->vdd_core < 1150000)
 			tbl->vdd_core = 1150000;
+		tbl->avsdscr_setting = 0;
+	}
 }
 
-static int __init select_freq_plan(u32 qfprom_phys)
+static int __init select_freq_plan(u32 pte_efuse_phys)
 {
-	void __iomem *qfprom_base;
-	u32 pte_efuse, pvs, tbl_idx;
+	void __iomem *pte_efuse;
+	u32 pte_efuse_val, pvs, tbl_idx;
 	char *pvs_names[] = { "Slow", "Nominal", "Fast", "Faster", "Unknown" };
 
-	qfprom_base = ioremap(qfprom_phys, SZ_256);
+	pte_efuse = ioremap(pte_efuse_phys, 4);
 	/* Select frequency tables. */
-	if (qfprom_base) {
-		pte_efuse = readl_relaxed(qfprom_base + PTE_EFUSE);
-		pvs = (pte_efuse >> 10) & 0x7;
-		iounmap(qfprom_base);
+	if (pte_efuse) {
+		pte_efuse_val = readl_relaxed(pte_efuse);
+		pvs = (pte_efuse_val >> 10) & 0x7;
+		iounmap(pte_efuse);
 		if (pvs == 0x7)
-			pvs = (pte_efuse >> 13) & 0x7;
+			pvs = (pte_efuse_val >> 13) & 0x7;
 
 		switch (pvs) {
 		case 0x0:
@@ -1005,7 +1017,7 @@
 		GFP_KERNEL);
 	BUG_ON(!drv.bus_scale->usecase);
 
-	tbl_idx = select_freq_plan(params->qfprom_phys_base);
+	tbl_idx = select_freq_plan(params->pte_efuse_phys);
 	drv.acpu_freq_tbl = kmemdup(params->pvs_tables[tbl_idx].table,
 				    params->pvs_tables[tbl_idx].size,
 				    GFP_KERNEL);
diff --git a/arch/arm/mach-msm/acpuclock-krait.h b/arch/arm/mach-msm/acpuclock-krait.h
index 1b891b1..d615b85 100644
--- a/arch/arm/mach-msm/acpuclock-krait.h
+++ b/arch/arm/mach-msm/acpuclock-krait.h
@@ -143,6 +143,7 @@
  * @l2_level: L2 configuration to use.
  * @vdd_core: CPU core voltage in uV.
  * @ua_core: CPU core current consumption in uA.
+ * @avsdscr_setting: AVS DSCR configuration.
  */
 struct acpu_level {
 	const int use_for_scaling;
@@ -150,6 +151,7 @@
 	const unsigned int l2_level;
 	int vdd_core;
 	int ua_core;
+	unsigned int avsdscr_setting;
 };
 
 /**
@@ -203,6 +205,7 @@
  * @l2_vote: L2 performance level vote associate with the current CPU speed.
  * @vreg: Array of voltage regulators needed by the scalable.
  * @initialized: Flag set to true when per_cpu_init() has been called.
+ * @avs_enabled: True if avs is enabled for the scalabale. False otherwise.
  */
 struct scalable {
 	const phys_addr_t hfpll_phys_base;
@@ -214,6 +217,7 @@
 	unsigned int l2_vote;
 	struct vreg vreg[NUM_VREG];
 	bool initialized;
+	bool avs_enabled;
 };
 
 /**
@@ -236,7 +240,7 @@
  * @pvs_tables: CPU frequency tables.
  * @l2_freq_tbl: L2 frequency table.
  * @l2_freq_tbl_size: Size of @l2_freq_tbl.
- * @qfprom_phys_base: Physical base address of QFPROM.
+ * @pte_efuse_phys: Physical address of PTE EFUSE.
  * @bus_scale: MSM bus driver parameters.
  * @stby_khz: KHz value corresponding to an always-on clock source.
  */
@@ -247,7 +251,7 @@
 	struct pvs_table *pvs_tables;
 	struct l2_level *l2_freq_tbl;
 	size_t l2_freq_tbl_size;
-	phys_addr_t qfprom_phys_base;
+	phys_addr_t pte_efuse_phys;
 	struct msm_bus_scale_pdata *bus_scale;
 	unsigned long stby_khz;
 };
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index 1a02fce..d5e4638 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -1809,6 +1809,10 @@
 	in_global_reset = 0;
 	vote_dfab();
 	if (!power_management_only_mode) {
+		sps_disconnect(bam_tx_pipe);
+		sps_disconnect(bam_rx_pipe);
+		__memzero(rx_desc_mem_buf.base, rx_desc_mem_buf.size);
+		__memzero(tx_desc_mem_buf.base, tx_desc_mem_buf.size);
 		i = sps_device_reset(a2_device_handle);
 		if (i)
 			pr_err("%s: device reset failed rc = %d\n", __func__,
@@ -1861,12 +1865,6 @@
 
 	/* tear down BAM connection */
 	INIT_COMPLETION(bam_connection_completion);
-	if (!power_management_only_mode) {
-		sps_disconnect(bam_tx_pipe);
-		sps_disconnect(bam_rx_pipe);
-		__memzero(rx_desc_mem_buf.base, rx_desc_mem_buf.size);
-		__memzero(tx_desc_mem_buf.base, tx_desc_mem_buf.size);
-	}
 	unvote_dfab();
 
 	mutex_lock(&bam_rx_pool_mutexlock);
diff --git a/arch/arm/mach-msm/board-8064-camera.c b/arch/arm/mach-msm/board-8064-camera.c
index bc1eded..c79f82f 100644
--- a/arch/arm/mach-msm/board-8064-camera.c
+++ b/arch/arm/mach-msm/board-8064-camera.c
@@ -396,11 +396,13 @@
 
 static struct msm_camera_device_platform_data msm_camera_csi_device_data[] = {
 	{
+		.csiphy_core = 0,
 		.csid_core = 0,
 		.is_vpe    = 1,
 		.cam_bus_scale_table = &cam_bus_client_pdata,
 	},
 	{
+		.csiphy_core = 1,
 		.csid_core = 1,
 		.is_vpe    = 1,
 		.cam_bus_scale_table = &cam_bus_client_pdata,
diff --git a/arch/arm/mach-msm/board-8064-regulator.c b/arch/arm/mach-msm/board-8064-regulator.c
index bbb9a81..6cdafbc 100644
--- a/arch/arm/mach-msm/board-8064-regulator.c
+++ b/arch/arm/mach-msm/board-8064-regulator.c
@@ -189,6 +189,7 @@
 	REGULATOR_SUPPLY("vcc_i2c",		"3-0024"),
 	REGULATOR_SUPPLY("vddp",		"0-0048"),
 	REGULATOR_SUPPLY("hdmi_lvl_tsl",	"hdmi_msm.0"),
+	REGULATOR_SUPPLY("vdd-io",		"spi0.2"),
 };
 VREG_CONSUMERS(S5) = {
 	REGULATOR_SUPPLY("8921_s5",		NULL),
@@ -252,7 +253,7 @@
 };
 VREG_CONSUMERS(EXT_3P3V) = {
 	REGULATOR_SUPPLY("ext_3p3v",		NULL),
-	REGULATOR_SUPPLY("vdd_io",		"spi0.2"),
+	REGULATOR_SUPPLY("vdd-phy",		"spi0.2"),
 	REGULATOR_SUPPLY("mhl_usb_hs_switch",	"msm_otg"),
 	REGULATOR_SUPPLY("lvds_vccs_3p3v",      "lvds.0"),
 	REGULATOR_SUPPLY("dsi1_vccs_3p3v",      "mipi_dsi.1"),
diff --git a/arch/arm/mach-msm/board-8930-camera.c b/arch/arm/mach-msm/board-8930-camera.c
index 883e04d..eb00f34 100644
--- a/arch/arm/mach-msm/board-8930-camera.c
+++ b/arch/arm/mach-msm/board-8930-camera.c
@@ -392,11 +392,13 @@
 
 static struct msm_camera_device_platform_data msm_camera_csi_device_data[] = {
 	{
+		.csiphy_core = 0,
 		.csid_core = 0,
 		.is_vpe    = 1,
 		.cam_bus_scale_table = &cam_bus_client_pdata,
 	},
 	{
+		.csiphy_core = 1,
 		.csid_core = 1,
 		.is_vpe    = 1,
 		.cam_bus_scale_table = &cam_bus_client_pdata,
diff --git a/arch/arm/mach-msm/board-8960-camera.c b/arch/arm/mach-msm/board-8960-camera.c
index 792eea4..9bb6e09 100644
--- a/arch/arm/mach-msm/board-8960-camera.c
+++ b/arch/arm/mach-msm/board-8960-camera.c
@@ -474,16 +474,19 @@
 
 static struct msm_camera_device_platform_data msm_camera_csi_device_data[] = {
 	{
+		.csiphy_core = 0,
 		.csid_core = 0,
 		.is_vpe    = 1,
 		.cam_bus_scale_table = &cam_bus_client_pdata,
 	},
 	{
+		.csiphy_core = 1,
 		.csid_core = 1,
 		.is_vpe    = 1,
 		.cam_bus_scale_table = &cam_bus_client_pdata,
 	},
 	{
+		.csiphy_core = 2,
 		.csid_core = 2,
 		.is_vpe    = 1,
 		.cam_bus_scale_table = &cam_bus_client_pdata,
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 3a82b07..06efc03 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -1688,8 +1688,8 @@
 		.reg_base_addr = MSM_SAW0_BASE,
 		.reg_init_values[MSM_SPM_REG_SAW2_CFG] = 0x1F,
 #if defined(CONFIG_MSM_AVS_HW)
-		.reg_init_values[MSM_SPM_REG_SAW2_AVS_CTL] = 0x00,
-		.reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x00,
+		.reg_init_values[MSM_SPM_REG_SAW2_AVS_CTL] = 0x50589464,
+		.reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x00020000,
 #endif
 		.reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01,
 		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x03020004,
@@ -1703,8 +1703,8 @@
 		.reg_base_addr = MSM_SAW1_BASE,
 		.reg_init_values[MSM_SPM_REG_SAW2_CFG] = 0x1F,
 #if defined(CONFIG_MSM_AVS_HW)
-		.reg_init_values[MSM_SPM_REG_SAW2_AVS_CTL] = 0x00,
-		.reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x00,
+		.reg_init_values[MSM_SPM_REG_SAW2_AVS_CTL] = 0x50589464,
+		.reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x00020000,
 #endif
 		.reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01,
 		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020204,
@@ -2822,19 +2822,24 @@
 		msm_kgsl_3d0.dev.platform_data;
 	uint32_t soc_platform_version = socinfo_get_version();
 
+	/* Fixup data that needs to change based on GPU ID */
 	if (cpu_is_msm8960ab()) {
 		kgsl_3d0_pdata->chipid = ADRENO_CHIPID(3, 2, 1, 0);
 		/* 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);
+	} else {
+		kgsl_3d0_pdata->iommu_count = 1;
+		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 (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);
+		}
 	}
 
 	/* Register the 3D core */
diff --git a/arch/arm/mach-msm/board-msm7627a-camera.c b/arch/arm/mach-msm/board-msm7627a-camera.c
index 7a1e2ff..b5f214b 100644
--- a/arch/arm/mach-msm/board-msm7627a-camera.c
+++ b/arch/arm/mach-msm/board-msm7627a-camera.c
@@ -139,12 +139,14 @@
 
 struct msm_camera_device_platform_data msm_camera_device_data_csi1[] = {
 	{
+		.csiphy_core = 1,
 		.csid_core = 1,
 		.ioclk = {
 			.vfe_clk_rate = 192000000,
 		},
 	},
 	{
+		.csiphy_core = 1,
 		.csid_core = 1,
 		.ioclk = {
 			.vfe_clk_rate = 266667000,
@@ -154,12 +156,14 @@
 
 struct msm_camera_device_platform_data msm_camera_device_data_csi0[] = {
 	{
+		.csiphy_core = 0,
 		.csid_core = 0,
 		.ioclk = {
 			.vfe_clk_rate = 192000000,
 		},
 	},
 	{
+		.csiphy_core = 0,
 		.csid_core = 0,
 		.ioclk = {
 			.vfe_clk_rate = 266667000,
diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c
index f16751d..b3ce01c 100644
--- a/arch/arm/mach-msm/board-msm7x30.c
+++ b/arch/arm/mach-msm/board-msm7x30.c
@@ -884,6 +884,7 @@
 #ifdef CONFIG_MSM_CAMERA_V4L2
 static struct msm_camera_device_platform_data msm_camera_csi_device_data[] = {
 	{
+		.csiphy_core = 0,
 		.csid_core = 0,
 		.is_vpe    = 1,
 		.ioclk = {
@@ -891,6 +892,7 @@
 		},
 	},
 	{
+		.csiphy_core = 0,
 		.csid_core = 0,
 		.is_vpe    = 1,
 		.ioclk = {
diff --git a/arch/arm/mach-msm/board-msm8x60-camera.c b/arch/arm/mach-msm/board-msm8x60-camera.c
index acd7f74..7e5f022 100644
--- a/arch/arm/mach-msm/board-msm8x60-camera.c
+++ b/arch/arm/mach-msm/board-msm8x60-camera.c
@@ -360,6 +360,7 @@
 
 static struct msm_camera_device_platform_data msm_camera_csi_device_data[] = {
 	{
+		.csiphy_core = 0,
 		.csid_core = 0,
 		.is_vpe    = 1,
 		.cam_bus_scale_table = &cam_bus_client_pdata,
@@ -368,6 +369,7 @@
 		},
 	},
 	{
+		.csiphy_core = 1,
 		.csid_core = 1,
 		.is_vpe    = 1,
 		.cam_bus_scale_table = &cam_bus_client_pdata,
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 01bc9dd..f6b1332 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -5330,6 +5330,7 @@
 	CLK_LOOKUP("cam_clk",		cam0_clk.c,	"4-0020"),
 	CLK_LOOKUP("cam_clk",		cam1_clk.c,	"4-0048"),
 	CLK_LOOKUP("cam_clk",		cam1_clk.c,	"4-006c"),
+	CLK_LOOKUP("cam_clk",		cam2_clk.c,		""),
 	CLK_LOOKUP("csi_src_clk",	csi0_src_clk.c,		"msm_csid.0"),
 	CLK_LOOKUP("csi_src_clk",	csi1_src_clk.c,		"msm_csid.1"),
 	CLK_LOOKUP("csi_src_clk",	csi2_src_clk.c,		"msm_csid.2"),
@@ -6430,16 +6431,16 @@
 		is_pll_enabled = readl_relaxed(BB_PLL14_STATUS_REG) & BIT(16);
 		if (!is_pll_enabled)
 			/* Ref clk = 27MHz and program pll14 to 480MHz */
-			configure_pll(&pll14_config, &pll14_regs, 1);
+			configure_sr_pll(&pll14_config, &pll14_regs, 1);
 
 		/* Program PLL15 to 975MHz with ref clk = 27MHz */
-		configure_pll(&pll15_config, &pll15_regs, 0);
+		configure_sr_pll(&pll15_config, &pll15_regs, 0);
 
 		/* Check if PLL4 is active */
 		is_pll_enabled = readl_relaxed(LCC_PLL0_STATUS_REG) & BIT(16);
 		if (!is_pll_enabled)
 			/* Ref clk = 27MHz and program pll4 to 393.2160MHz */
-			configure_pll(&pll4_config_393, &pll4_regs, 1);
+			configure_sr_pll(&pll4_config_393, &pll4_regs, 1);
 
 		/* Enable PLL4 source on the LPASS Primary PLL Mux */
 		writel_relaxed(0x1, LCC_PRI_PLL_CLK_CTL_REG);
@@ -6457,7 +6458,7 @@
 		pll15_config.l = 0x21 | BVAL(31, 7, 0x600);
 		pll15_config.m = 0x1;
 		pll15_config.n = 0x3;
-		configure_pll(&pll15_config, &pll15_regs, 0);
+		configure_sr_pll(&pll15_config, &pll15_regs, 0);
 		/* Disable AUX and BIST outputs */
 		writel_relaxed(0, MM_PLL3_TEST_CTL_REG);
 	}
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index b054e08..62e8f0f 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -5594,16 +5594,16 @@
 
 	if (!(readl_relaxed(GCC_REG_BASE(GPLL0_STATUS_REG))
 			& gpll0_clk_src.status_mask))
-		configure_pll(&gpll0_config, &gpll0_regs, 1);
+		configure_sr_hpm_lp_pll(&gpll0_config, &gpll0_regs, 1);
 
 	if (!(readl_relaxed(GCC_REG_BASE(GPLL1_STATUS_REG))
 			& gpll1_clk_src.status_mask))
-		configure_pll(&gpll1_config, &gpll1_regs, 1);
+		configure_sr_hpm_lp_pll(&gpll1_config, &gpll1_regs, 1);
 
-	configure_pll(&mmpll0_config, &mmpll0_regs, 1);
-	configure_pll(&mmpll1_config, &mmpll1_regs, 1);
-	configure_pll(&mmpll3_config, &mmpll3_regs, 0);
-	configure_pll(&lpapll0_config, &lpapll0_regs, 1);
+	configure_sr_hpm_lp_pll(&mmpll0_config, &mmpll0_regs, 1);
+	configure_sr_hpm_lp_pll(&mmpll1_config, &mmpll1_regs, 1);
+	configure_sr_hpm_lp_pll(&mmpll3_config, &mmpll3_regs, 0);
+	configure_sr_hpm_lp_pll(&lpapll0_config, &lpapll0_regs, 1);
 
 	/* Enable GPLL0's aux outputs. */
 	regval = readl_relaxed(GCC_REG_BASE(GPLL0_USER_CTL_REG));
@@ -5769,7 +5769,7 @@
 	if (!virt_bases[APCS_BASE])
 		panic("clock-8974: Unable to ioremap APCS_GCC_CC memory!");
 
-	clk_ops_local_pll.enable = msm8974_pll_clk_enable;
+	clk_ops_local_pll.enable = sr_hpm_lp_pll_clk_enable;
 
 	vdd_dig_reg = rpm_regulator_get(NULL, "vdd_dig");
 	if (IS_ERR(vdd_dig_reg))
diff --git a/arch/arm/mach-msm/clock-9615.c b/arch/arm/mach-msm/clock-9615.c
index 648a8d4..15eaa4b 100644
--- a/arch/arm/mach-msm/clock-9615.c
+++ b/arch/arm/mach-msm/clock-9615.c
@@ -1807,14 +1807,14 @@
 		regval |= BIT(12);
 		writel_relaxed(regval, BB_PLL0_TEST_CTL_REG);
 
-		configure_pll(&pll0_config, &pll0_regs, 1);
+		configure_sr_pll(&pll0_config, &pll0_regs, 1);
 	}
 
 	/* Check if PLL14 is enabled in FSM mode */
 	is_pll_enabled  = readl_relaxed(BB_PLL14_STATUS_REG) & BIT(16);
 
 	if (!is_pll_enabled)
-		configure_pll(&pll14_config, &pll14_regs, 1);
+		configure_sr_pll(&pll14_config, &pll14_regs, 1);
 	else if (!(readl_relaxed(BB_PLL14_MODE_REG) & BIT(20)))
 		WARN(1, "PLL14 enabled in non-FSM mode!\n");
 
diff --git a/arch/arm/mach-msm/clock-local2.c b/arch/arm/mach-msm/clock-local2.c
index 3f19b2a..2beb990 100644
--- a/arch/arm/mach-msm/clock-local2.c
+++ b/arch/arm/mach-msm/clock-local2.c
@@ -474,10 +474,10 @@
 	if (branch->has_sibling == 1)
 		return -ENXIO;
 
-	if (branch->parent)
-		return rcg_clk_list_rate(branch->parent, n);
+	if (branch->parent && branch->parent->ops->list_rate)
+		return branch->parent->ops->list_rate(branch->parent, n);
 	else
-		return 0;
+		return -ENXIO;
 }
 
 static enum handoff branch_clk_handoff(struct clk *c)
diff --git a/arch/arm/mach-msm/clock-mdss-8974.c b/arch/arm/mach-msm/clock-mdss-8974.c
index 4d147c3..14e1185 100644
--- a/arch/arm/mach-msm/clock-mdss-8974.c
+++ b/arch/arm/mach-msm/clock-mdss-8974.c
@@ -67,7 +67,9 @@
 static int pll_byte_clk_rate;
 static int pll_pclk_rate;
 static int pll_initialized;
+static int pll_enabled;
 static struct clk *mdss_dsi_ahb_clk;
+static unsigned long dsi_pll_rate;
 
 static void __iomem *hdmi_phy_base;
 static void __iomem *hdmi_phy_pll_base;
@@ -135,6 +137,7 @@
 	int pll_divcfg1, pll_divcfg2;
 	int half_bitclk_rate;
 
+	pr_debug("%s:\n", __func__);
 	if (pll_initialized)
 		return 0;
 
@@ -193,10 +196,13 @@
 	REG_W(0x00, mdss_dsi_base + 0x0290); /* CAL CFG9 */
 	REG_W(0x20, mdss_dsi_base + 0x029c); /* EFUSE CFG */
 
+	dsi_pll_rate = rate;
+
 	pll_byte_clk_rate = 53000000;
 	pll_pclk_rate = 105000000;
 
 	clk_disable(mdss_dsi_ahb_clk);
+	pr_debug("%s: **** PLL initialized success\n", __func__);
 	pll_initialized = 1;
 
 	return 0;
@@ -206,11 +212,19 @@
 {
 	u32 status;
 	u32 max_reads, timeout_us;
-	static int pll_enabled;
+	int i;
 
 	if (pll_enabled)
 		return 0;
 
+	if (!pll_initialized) {
+		if (dsi_pll_rate)
+			mdss_dsi_pll_byte_set_rate(c, dsi_pll_rate);
+		else
+			pr_err("%s: Calling clk_en before set_rate\n",
+						__func__);
+	}
+
 	if (!mdss_dsi_ahb_clk) {
 		pr_err("%s: mdss_dsi_ahb_clk not initialized\n",
 				__func__);
@@ -218,26 +232,39 @@
 	}
 
 	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)) {
+	/* PLL power up */
+	for (i = 0; i < 3; i++) {
+		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_debug("%s: DSI PLL status=%x failed to Lock\n",
+			       __func__, status);
+			pr_debug("%s:Trying to power UP PLL again\n",
+			       __func__);
+		} else
+			break;
+	}
+
+	if ((status & 0x01) != 1) {
 		pr_err("%s: DSI PLL status=%x failed to Lock\n",
 		       __func__, status);
 		clk_disable(mdss_dsi_ahb_clk);
 		return -EINVAL;
 	}
+
+	pr_debug("%s: **** PLL Lock success\n", __func__);
 	clk_disable(mdss_dsi_ahb_clk);
 	pll_enabled = 1;
 
@@ -253,6 +280,9 @@
 	clk_enable(mdss_dsi_ahb_clk);
 	writel_relaxed(0x00, mdss_dsi_base + 0x0220); /* GLB CFG */
 	clk_disable(mdss_dsi_ahb_clk);
+	pr_debug("%s: **** disable pll Initialize\n", __func__);
+	pll_initialized = 0;
+	pll_enabled = 0;
 }
 
 void hdmi_pll_disable(void)
diff --git a/arch/arm/mach-msm/clock-pll.c b/arch/arm/mach-msm/clock-pll.c
index d5831e2..23941d7 100644
--- a/arch/arm/mach-msm/clock-pll.c
+++ b/arch/arm/mach-msm/clock-pll.c
@@ -247,7 +247,7 @@
 
 #define PLL_LOCKED_BIT BIT(16)
 
-int msm8974_pll_clk_enable(struct clk *c)
+int sr_hpm_lp_pll_clk_enable(struct clk *c)
 {
 	unsigned long flags;
 	struct pll_clk *pll = to_pll_clk(c);
@@ -255,23 +255,12 @@
 	int ret = 0;
 
 	spin_lock_irqsave(&pll_reg_lock, flags);
-	mode = readl_relaxed(PLL_MODE_REG(pll));
-	/* Disable PLL bypass mode. */
-	mode |= PLL_BYPASSNL;
+
+	/* Disable PLL bypass mode and de-assert reset. */
+	mode = PLL_BYPASSNL | PLL_RESET_N;
 	writel_relaxed(mode, PLL_MODE_REG(pll));
 
-	/*
-	 * H/W requires a 5us delay between disabling the bypass and
-	 * de-asserting the reset. Delay 10us just to be safe.
-	 */
-	mb();
-	udelay(10);
-
-	/* De-assert active-low PLL reset. */
-	mode |= PLL_RESET_N;
-	writel_relaxed(mode, PLL_MODE_REG(pll));
-
-	/* Wait for pll to enable. */
+	/* Wait for pll to lock. */
 	for (count = ENABLE_WAIT_MAX_LOOPS; count > 0; count--) {
 		if (readl_relaxed(PLL_STATUS_REG(pll)) & PLL_LOCKED_BIT)
 			break;
@@ -453,7 +442,8 @@
 	.is_enabled = pll_clk_is_enabled,
 };
 
-static void __init __set_fsm_mode(void __iomem *mode_reg)
+static void __init __set_fsm_mode(void __iomem *mode_reg,
+					u32 bias_count, u32 lock_count)
 {
 	u32 regval = readl_relaxed(mode_reg);
 
@@ -463,12 +453,12 @@
 
 	/* Program bias count */
 	regval &= ~BM(19, 14);
-	regval |= BVAL(19, 14, 0x1);
+	regval |= BVAL(19, 14, bias_count);
 	writel_relaxed(regval, mode_reg);
 
 	/* Program lock count */
 	regval &= ~BM(13, 8);
-	regval |= BVAL(13, 8, 0x8);
+	regval |= BVAL(13, 8, lock_count);
 	writel_relaxed(regval, mode_reg);
 
 	/* Enable PLL FSM voting */
@@ -476,7 +466,7 @@
 	writel_relaxed(regval, mode_reg);
 }
 
-void __init configure_pll(struct pll_config *config,
+void __init __configure_pll(struct pll_config *config,
 		struct pll_config_regs *regs, u32 ena_fsm_mode)
 {
 	u32 regval;
@@ -509,8 +499,21 @@
 	regval &= ~config->vco_mask;
 	regval |= config->vco_val;
 	writel_relaxed(regval, PLL_CONFIG_REG(regs));
-
-	/* Configure in FSM mode if necessary */
-	if (ena_fsm_mode)
-		__set_fsm_mode(PLL_MODE_REG(regs));
 }
+
+void __init configure_sr_pll(struct pll_config *config,
+		struct pll_config_regs *regs, u32 ena_fsm_mode)
+{
+	__configure_pll(config, regs, ena_fsm_mode);
+	if (ena_fsm_mode)
+		__set_fsm_mode(PLL_MODE_REG(regs), 0x1, 0x8);
+}
+
+void __init configure_sr_hpm_lp_pll(struct pll_config *config,
+		struct pll_config_regs *regs, u32 ena_fsm_mode)
+{
+	__configure_pll(config, regs, ena_fsm_mode);
+	if (ena_fsm_mode)
+		__set_fsm_mode(PLL_MODE_REG(regs), 0x1, 0x0);
+}
+
diff --git a/arch/arm/mach-msm/clock-pll.h b/arch/arm/mach-msm/clock-pll.h
index 90f8a95..30f595b 100644
--- a/arch/arm/mach-msm/clock-pll.h
+++ b/arch/arm/mach-msm/clock-pll.h
@@ -111,7 +111,7 @@
 }
 
 int sr_pll_clk_enable(struct clk *c);
-int msm8974_pll_clk_enable(struct clk *c);
+int sr_hpm_lp_pll_clk_enable(struct clk *c);
 
 /*
  * PLL vote clock APIs
@@ -146,6 +146,8 @@
 	void *const __iomem *base;
 };
 
-void __init configure_pll(struct pll_config *, struct pll_config_regs *, u32);
-
+void configure_sr_pll(struct pll_config *config, struct pll_config_regs *regs,
+				u32 ena_fsm_mode);
+void configure_sr_hpm_lp_pll(struct pll_config *config,
+				struct pll_config_regs *, u32 ena_fsm_mode);
 #endif
diff --git a/arch/arm/mach-msm/cpufreq.c b/arch/arm/mach-msm/cpufreq.c
index 05bd56ef..6c9b413 100644
--- a/arch/arm/mach-msm/cpufreq.c
+++ b/arch/arm/mach-msm/cpufreq.c
@@ -32,19 +32,6 @@
 
 #include "acpuclock.h"
 
-#ifdef CONFIG_SMP
-struct cpufreq_work_struct {
-	struct work_struct work;
-	struct cpufreq_policy *policy;
-	struct completion complete;
-	int frequency;
-	int status;
-};
-
-static DEFINE_PER_CPU(struct cpufreq_work_struct, cpufreq_work);
-static struct workqueue_struct *msm_cpufreq_wq;
-#endif
-
 struct cpufreq_suspend_t {
 	struct mutex suspend_mutex;
 	int device_suspended;
@@ -91,45 +78,6 @@
 	return ret;
 }
 
-#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 =
-		container_of(work, struct cpufreq_work_struct, work);
-
-	cpu_work->status = set_cpu_freq(cpu_work->policy, cpu_work->frequency);
-	complete(&cpu_work->complete);
-}
-#endif
-
 static int msm_cpufreq_target(struct cpufreq_policy *policy,
 				unsigned int target_freq,
 				unsigned int relation)
@@ -137,19 +85,12 @@
 	int ret = -EFAULT;
 	int index;
 	struct cpufreq_frequency_table *table;
-#ifdef CONFIG_SMP
-	struct cpufreq_work_struct *cpu_work = NULL;
-	cpumask_var_t mask;
 
 	if (!cpu_active(policy->cpu)) {
 		pr_info("cpufreq: cpu %d is not active.\n", policy->cpu);
 		return -ENODEV;
 	}
 
-	if (!alloc_cpumask_var(&mask, GFP_KERNEL))
-		return -ENOMEM;
-#endif
-
 	mutex_lock(&per_cpu(cpufreq_suspend, policy->cpu).suspend_mutex);
 
 	if (per_cpu(cpufreq_suspend, policy->cpu).device_suspended) {
@@ -167,39 +108,13 @@
 		goto done;
 	}
 
-#ifdef CONFIG_CPU_FREQ_DEBUG
 	pr_debug("CPU[%d] target %d relation %d (%d-%d) selected %d\n",
 		policy->cpu, target_freq, relation,
 		policy->min, policy->max, table[index].frequency);
-#endif
 
-#ifdef CONFIG_SMP
-	cpu_work = &per_cpu(cpufreq_work, policy->cpu);
-	cpu_work->policy = policy;
-	cpu_work->frequency = table[index].frequency;
-	cpu_work->status = -ENODEV;
-
-	cpumask_clear(mask);
-	cpumask_set_cpu(policy->cpu, mask);
-	if (cpumask_equal(mask, &current->cpus_allowed)) {
-		ret = set_cpu_freq(cpu_work->policy, cpu_work->frequency);
-		goto done;
-	} else {
-		cancel_work_sync(&cpu_work->work);
-		INIT_COMPLETION(cpu_work->complete);
-		queue_work_on(policy->cpu, msm_cpufreq_wq, &cpu_work->work);
-		wait_for_completion(&cpu_work->complete);
-	}
-
-	ret = cpu_work->status;
-#else
 	ret = set_cpu_freq(policy, table[index].frequency);
-#endif
 
 done:
-#ifdef CONFIG_SMP
-	free_cpumask_var(mask);
-#endif
 	mutex_unlock(&per_cpu(cpufreq_suspend, policy->cpu).suspend_mutex);
 	return ret;
 }
@@ -282,10 +197,6 @@
 	int cur_freq;
 	int index;
 	struct cpufreq_frequency_table *table;
-#ifdef CONFIG_SMP
-	struct cpufreq_work_struct *cpu_work = NULL;
-#endif
-
 
 	table = cpufreq_frequency_get_table(policy->cpu);
 	if (table == NULL)
@@ -314,7 +225,7 @@
 	    CPUFREQ_RELATION_H, &index) &&
 	    cpufreq_frequency_table_target(policy, table, cur_freq,
 	    CPUFREQ_RELATION_L, &index)) {
-		pr_info("cpufreq: cpu%d at invalid freq: %d\n",
+		pr_info("%s: cpu%d at invalid freq: %d\n", __func__,
 				policy->cpu, cur_freq);
 		return -EINVAL;
 	}
@@ -334,15 +245,39 @@
 
 	policy->cpuinfo.transition_latency =
 		acpuclk_get_switch_time() * NSEC_PER_USEC;
-#ifdef CONFIG_SMP
-	cpu_work = &per_cpu(cpufreq_work, policy->cpu);
-	INIT_WORK(&cpu_work->work, set_cpu_work);
-	init_completion(&cpu_work->complete);
-#endif
 
 	return 0;
 }
 
+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 int msm_cpufreq_suspend(void)
 {
 	int cpu;
@@ -382,6 +317,10 @@
 	}
 }
 
+static struct notifier_block msm_cpufreq_pm_notifier = {
+	.notifier_call = msm_cpufreq_pm_event,
+};
+
 static struct freq_attr *msm_freq_attr[] = {
 	&cpufreq_freq_attr_scaling_available_freqs,
 	NULL,
@@ -398,10 +337,6 @@
 	.attr		= msm_freq_attr,
 };
 
-static struct notifier_block msm_cpufreq_pm_notifier = {
-	.notifier_call = msm_cpufreq_pm_event,
-};
-
 static int __init msm_cpufreq_register(void)
 {
 	int cpu;
@@ -411,10 +346,7 @@
 		per_cpu(cpufreq_suspend, cpu).device_suspended = 0;
 	}
 
-#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);
 	return cpufreq_register_driver(&msm_cpufreq_driver);
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index 4ad5580..0f106f5 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -2316,8 +2316,8 @@
 };
 
 static struct msm_rpmstats_platform_data msm_rpm_stat_pdata = {
-	.phys_addr_base = 0x0010D204,
-	.phys_size = SZ_8K,
+	.phys_addr_base = 0x0010DD04,
+	.phys_size = SZ_256,
 };
 
 struct platform_device apq8064_rpm_stat_device = {
diff --git a/arch/arm/mach-msm/devices-8930.c b/arch/arm/mach-msm/devices-8930.c
index 292f58d..ad89a86 100644
--- a/arch/arm/mach-msm/devices-8930.c
+++ b/arch/arm/mach-msm/devices-8930.c
@@ -530,8 +530,8 @@
 };
 
 static struct msm_rpmstats_platform_data msm_rpm_stat_pdata = {
-	.phys_addr_base = 0x0010D204,
-	.phys_size = SZ_8K,
+	.phys_addr_base = 0x0010DD04,
+	.phys_size = SZ_256,
 };
 
 struct platform_device msm8930_rpm_stat_device = {
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index d22690c..b6926a2 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -3145,18 +3145,29 @@
 	},
 };
 
-static const struct kgsl_iommu_ctx kgsl_3d0_iommu_ctxs[] = {
+static const struct kgsl_iommu_ctx kgsl_3d0_iommu0_ctxs[] = {
 	{ "gfx3d_user", 0 },
 	{ "gfx3d_priv", 1 },
 };
 
+static const struct kgsl_iommu_ctx kgsl_3d0_iommu1_ctxs[] = {
+	{ "gfx3d1_user", 0 },
+	{ "gfx3d1_priv", 1 },
+};
+
 static struct kgsl_device_iommu_data kgsl_3d0_iommu_data[] = {
 	{
-		.iommu_ctxs = kgsl_3d0_iommu_ctxs,
-		.iommu_ctx_count = ARRAY_SIZE(kgsl_3d0_iommu_ctxs),
+		.iommu_ctxs = kgsl_3d0_iommu0_ctxs,
+		.iommu_ctx_count = ARRAY_SIZE(kgsl_3d0_iommu0_ctxs),
 		.physstart = 0x07C00000,
 		.physend = 0x07C00000 + SZ_1M - 1,
 	},
+	{
+		.iommu_ctxs = kgsl_3d0_iommu1_ctxs,
+		.iommu_ctx_count = ARRAY_SIZE(kgsl_3d0_iommu1_ctxs),
+		.physstart = 0x07D00000,
+		.physend = 0x07D00000 + SZ_1M - 1,
+	},
 };
 
 static struct kgsl_device_platform_data kgsl_3d0_pdata = {
@@ -3657,8 +3668,8 @@
 };
 
 static struct msm_rpmstats_platform_data msm_rpm_stat_pdata = {
-	.phys_addr_base = 0x0010D204,
-	.phys_size = SZ_8K,
+	.phys_addr_base = 0x0010DD04,
+	.phys_size = SZ_256,
 };
 
 struct platform_device msm8960_rpm_stat_device = {
diff --git a/arch/arm/mach-msm/devices-iommu.c b/arch/arm/mach-msm/devices-iommu.c
index b65bd1f..acf577e 100644
--- a/arch/arm/mach-msm/devices-iommu.c
+++ b/arch/arm/mach-msm/devices-iommu.c
@@ -365,25 +365,25 @@
 static struct msm_iommu_dev gfx3d_iommu = {
 	.name = "gfx3d",
 	.ncb = 3,
-	.ttbr_split = 2,
+	.ttbr_split = 1,
 };
 
 static struct msm_iommu_dev gfx3d1_iommu = {
 	.name = "gfx3d1",
 	.ncb = 3,
-	.ttbr_split = 2,
+	.ttbr_split = 1,
 };
 
 static struct msm_iommu_dev gfx2d0_iommu = {
 	.name = "gfx2d0",
 	.ncb = 2,
-	.ttbr_split = 2,
+	.ttbr_split = 1,
 };
 
 static struct msm_iommu_dev gfx2d1_iommu = {
 	.name = "gfx2d1",
 	.ncb = 2,
-	.ttbr_split = 2,
+	.ttbr_split = 1,
 };
 
 static struct msm_iommu_dev vcap_iommu = {
diff --git a/arch/arm/mach-msm/devices-msm7x27a.c b/arch/arm/mach-msm/devices-msm7x27a.c
index cd5b2e5..c877ba9 100644
--- a/arch/arm/mach-msm/devices-msm7x27a.c
+++ b/arch/arm/mach-msm/devices-msm7x27a.c
@@ -1728,7 +1728,7 @@
 	uint32_t quot;
 
 	/* This formula is as per chip characterization data */
-	quot = max_quot - ((max_freq / 10 - new_freq / 10) * 5);
+	quot = max_quot - (((max_freq - new_freq) * 5) / 10);
 
 	return quot;
 }
diff --git a/arch/arm/mach-msm/event_timer.c b/arch/arm/mach-msm/event_timer.c
new file mode 100644
index 0000000..e06dad4
--- /dev/null
+++ b/arch/arm/mach-msm/event_timer.c
@@ -0,0 +1,318 @@
+/* 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/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <mach/event_timer.h>
+
+#define __INIT_HEAD(x)	{ .head = RB_ROOT,\
+			.next = NULL, }
+
+#define DEFINE_TIME_HEAD(x) struct timerqueue_head x = __INIT_HEAD(x)
+
+/**
+ * struct event_timer_info - basic event timer structure
+ * @node: timerqueue node to track time ordered data structure
+ *        of event timers
+ * @timer: hrtimer created for this event.
+ * @function : callback function for event timer.
+ * @data : callback data for event timer.
+ */
+struct event_timer_info {
+	struct timerqueue_node node;
+	void (*function)(void *);
+	void *data;
+};
+
+
+static DEFINE_TIME_HEAD(timer_head);
+static DEFINE_SPINLOCK(event_timer_lock);
+static struct hrtimer event_hrtimer;
+static enum hrtimer_restart event_hrtimer_cb(struct hrtimer *hrtimer);
+
+static int msm_event_debug_mask;
+module_param_named(
+	debug_mask, msm_event_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP
+);
+
+enum {
+	MSM_EVENT_TIMER_DEBUG = 1U << 0,
+};
+
+
+/**
+ * add_event_timer() : Add a wakeup event. Intended to be called
+ *                     by clients once. Returns a handle to be used
+ *                     for future transactions.
+ * @function : The callback function will be called when event
+ *             timer expires.
+ * @data: callback data provided by client.
+ */
+struct event_timer_info *add_event_timer(void (*function)(void *), void *data)
+{
+	struct event_timer_info *event_info =
+			kzalloc(sizeof(struct event_timer_info), GFP_KERNEL);
+
+	if (!event_info)
+		return NULL;
+
+	event_info->function = function;
+	event_info->data = data;
+	/* Init rb node and hr timer */
+	timerqueue_init(&event_info->node);
+
+	return event_info;
+}
+
+/**
+ * is_event_next(): Helper function to check if the event is the next
+ *                   next expiring event
+ * @event : handle to the event to be checked.
+ */
+static bool is_event_next(struct event_timer_info *event)
+{
+	struct event_timer_info *next_event;
+	struct timerqueue_node *next;
+	bool ret = false;
+
+	next = timerqueue_getnext(&timer_head);
+	if (!next)
+		goto exit_is_next_event;
+
+	next_event = container_of(next, struct event_timer_info, node);
+	if (!next_event)
+		goto exit_is_next_event;
+
+	if (next_event == event)
+		ret = true;
+
+exit_is_next_event:
+	return ret;
+}
+
+/**
+ * is_event_active(): Helper function to check if the timer for a given event
+ *                    has been started.
+ * @event : handle to the event to be checked.
+ */
+static bool is_event_active(struct event_timer_info *event)
+{
+	struct timerqueue_node *next;
+	struct event_timer_info *next_event;
+	bool ret = false;
+
+	for (next = timerqueue_getnext(&timer_head); next;
+			next = timerqueue_iterate_next(next)) {
+		next_event = container_of(next, struct event_timer_info, node);
+
+		if (event == next_event) {
+			ret = true;
+			break;
+		}
+	}
+	return ret;
+}
+
+/**
+ * create_httimer(): Helper function to setup hrtimer.
+ */
+static void create_hrtimer(ktime_t expires)
+{
+	static bool timer_initialized;
+
+	if (!timer_initialized) {
+		hrtimer_init(&event_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+		timer_initialized = true;
+	}
+
+	event_hrtimer.function = event_hrtimer_cb;
+	hrtimer_start(&event_hrtimer, expires, HRTIMER_MODE_ABS);
+
+	if (msm_event_debug_mask && MSM_EVENT_TIMER_DEBUG)
+		pr_info("%s: Setting timer for %lu", __func__,
+			(unsigned long)ktime_to_ns(expires));
+}
+
+/**
+ * event_hrtimer_cb() : Callback function for hr timer.
+ *                      Make the client CB from here and remove the event
+ *                      from the time ordered queue.
+ */
+static enum hrtimer_restart event_hrtimer_cb(struct hrtimer *hrtimer)
+{
+	struct event_timer_info *event;
+	struct timerqueue_node *next;
+
+	next = timerqueue_getnext(&timer_head);
+
+	while (next && (ktime_to_ns(next->expires)
+		<= ktime_to_ns(hrtimer->node.expires))) {
+		if (!next)
+			goto hrtimer_cb_exit;
+
+		event = container_of(next, struct event_timer_info, node);
+		if (!event)
+			goto hrtimer_cb_exit;
+
+		if (msm_event_debug_mask && MSM_EVENT_TIMER_DEBUG)
+			pr_info("%s: Deleting event @ %lu", __func__,
+			(unsigned long)ktime_to_ns(next->expires));
+
+		timerqueue_del(&timer_head, &event->node);
+
+		if (event->function)
+			event->function(event->data);
+		next = timerqueue_getnext(&timer_head);
+	}
+
+	if (next)
+		create_hrtimer(next->expires);
+
+hrtimer_cb_exit:
+	return HRTIMER_NORESTART;
+}
+
+/**
+ * create_timer_smp(): Helper function used setting up timer on core 0.
+ */
+static void create_timer_smp(void *data)
+{
+	unsigned long flags;
+	struct event_timer_info *event =
+		(struct event_timer_info *)data;
+
+	local_irq_save(flags);
+	create_hrtimer(event->node.expires);
+	local_irq_restore(flags);
+}
+
+/**
+ *  setup_timer() : Helper function to setup timer on primary
+ *                  core during hrtimer callback.
+ *  @event: event handle causing the wakeup.
+ */
+static void setup_event_hrtimer(struct event_timer_info *event)
+{
+	struct timerqueue_node *next;
+	unsigned long flags;
+
+	spin_lock_irqsave(&event_timer_lock, flags);
+	if (is_event_active(event))
+		timerqueue_del(&timer_head, &event->node);
+
+	next = timerqueue_getnext(&timer_head);
+	timerqueue_add(&timer_head, &event->node);
+	spin_unlock_irqrestore(&event_timer_lock, flags);
+
+	if (!next ||
+		(next && (ktime_to_ns(event->node.expires) <
+				ktime_to_ns(next->expires)))) {
+		if (msm_event_debug_mask && MSM_EVENT_TIMER_DEBUG)
+			pr_info("%s: Setting timer for %lu", __func__,
+			(unsigned long)ktime_to_ns(event->node.expires));
+
+		smp_call_function_single(0, create_timer_smp, event, 1);
+		}
+}
+
+/**
+ * activate_event_timer() : Set the expiration time for an event in absolute
+ *                           ktime. This is a oneshot event timer, clients
+ *                           should call this again to set another expiration.
+ *  @event : event handle.
+ *  @event_time : event time in absolute ktime.
+ */
+void activate_event_timer(struct event_timer_info *event, ktime_t event_time)
+{
+	if (!event)
+		return;
+
+	if (msm_event_debug_mask && MSM_EVENT_TIMER_DEBUG)
+		pr_info("%s: Adding event timer @ %lu", __func__,
+				(unsigned long)ktime_to_us(event_time));
+
+	event->node.expires = event_time;
+	/* Start hr timer and add event to rb tree */
+	setup_event_hrtimer(event);
+}
+
+
+/**
+ * deactivate_event_timer() : Deactivate an event timer, this removes the event from
+ *                            the time ordered queue of event timers.
+ * @event: event handle.
+ */
+void deactivate_event_timer(struct event_timer_info *event)
+{
+	unsigned long flags;
+
+	if (msm_event_debug_mask && MSM_EVENT_TIMER_DEBUG)
+		pr_info("%s: Deactivate timer", __func__);
+
+	spin_lock_irqsave(&event_timer_lock, flags);
+	if (is_event_active(event)) {
+		if (is_event_next(event))
+			hrtimer_try_to_cancel(&event_hrtimer);
+
+		timerqueue_del(&timer_head, &event->node);
+	}
+	spin_unlock_irqrestore(&event_timer_lock, flags);
+}
+
+/**
+ * destroy_event_timer() : Free the event info data structure allocated during
+ *                         add_event_timer().
+ * @event: event handle.
+ */
+void destroy_event_timer(struct event_timer_info *event)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&event_timer_lock, flags);
+	if (is_event_active(event)) {
+		if (is_event_next(event))
+			hrtimer_try_to_cancel(&event_hrtimer);
+
+		timerqueue_del(&timer_head, &event->node);
+	}
+	spin_unlock_irqrestore(&event_timer_lock, flags);
+	kfree(event);
+}
+
+/**
+ * get_next_event_timer() - Get the next wakeup event. Returns
+ *                          a ktime value of the next expiring event.
+ */
+ktime_t get_next_event_time(void)
+{
+	unsigned long flags;
+	struct timerqueue_node *next;
+	ktime_t next_event = ns_to_ktime(0);
+
+	spin_lock_irqsave(&event_timer_lock, flags);
+	next = timerqueue_getnext(&timer_head);
+	spin_unlock_irqrestore(&event_timer_lock, flags);
+
+	if (!next)
+		return next_event;
+
+	next_event = hrtimer_get_remaining(&event_hrtimer);
+	if (msm_event_debug_mask && MSM_EVENT_TIMER_DEBUG)
+		pr_info("%s: Next Event %lu", __func__,
+			(unsigned long)ktime_to_us(next_event));
+
+	return next_event;
+}
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index 5b8729a..433fee3 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -63,6 +63,7 @@
 	uint8_t csid_core;
 	uint8_t is_vpe;
 	struct msm_bus_scale_pdata *cam_bus_scale_table;
+	uint8_t csiphy_core;
 };
 
 #ifdef CONFIG_SENSORS_MT9T013
@@ -177,7 +178,6 @@
 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 {
diff --git a/arch/arm/mach-msm/include/mach/event_timer.h b/arch/arm/mach-msm/include/mach/event_timer.h
new file mode 100644
index 0000000..7a00b23
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/event_timer.h
@@ -0,0 +1,77 @@
+/* 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 __ARCH_ARM_MACH_MSM_EVENT_TIMER_H
+#define __ARCH_ARM_MACH_MSM_EVENT_TIMER_H
+
+#include <linux/hrtimer.h>
+
+struct event_timer_info;
+
+#ifdef CONFIG_MSM_EVENT_TIMER
+/**
+ * add_event_timer() : Add a wakeup event. Intended to be called
+ *                     by clients once. Returns a handle to be used
+ *                     for future transactions.
+ * @function : The callback function will be called when event
+ *             timer expires.
+ * @data : Callback data provided by client.
+ */
+struct event_timer_info *add_event_timer(void (*function)(void *), void *data);
+
+/** activate_event_timer() : Set the expiration time for an event in absolute
+ *                           ktime. This is a oneshot event timer, clients
+ *                           should call this again to set another expiration.
+ *  @event : Event handle.
+ *  @event_time : Event time in absolute ktime.
+ */
+void activate_event_timer(struct event_timer_info *event, ktime_t event_time);
+
+/**
+ * deactivate_event_timer() : Deactivate an event timer.
+ * @event: event handle.
+ */
+void deactivate_event_timer(struct event_timer_info *event);
+
+/**
+ * destroy_event_timer() : Free the event info data structure allocated during
+ * add_event_timer().
+ * @event: event handle.
+ */
+void destroy_event_timer(struct event_timer_info *event);
+
+/**
+ * get_next_event_timer() : Get the next wakeup event.
+ *                          returns a ktime value of the next
+ *                          expiring event.
+ */
+ktime_t get_next_event_time(void);
+#else
+static inline void *add_event_timer(void (*function)(void *), void *data)
+{
+	return NULL;
+}
+
+static inline void activate_event_timer(void *event, ktime_t event_time) {}
+
+static inline void deactivate_event_timer(void *event) {}
+
+static inline void destroy_event_timer(void *event) {}
+
+static inline ktime_t get_next_event_time(void)
+{
+	return ns_to_ktime(0);
+}
+
+#endif /* CONFIG_MSM_EVENT_TIMER_MANAGER */
+#endif /* __ARCH_ARM_MACH_MSM_EVENT_TIMER_H */
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-9625.h b/arch/arm/mach-msm/include/mach/msm_iomap-9625.h
index 493cf36..eecdd67 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-9625.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-9625.h
@@ -23,7 +23,7 @@
  *
  */
 
-#define MSM9625_SHARED_RAM_PHYS	0x18D00000
+#define MSM9625_SHARED_RAM_PHYS	0x00000000
 
 #define MSM9625_APCS_GCC_PHYS	0xF9011000
 #define MSM9625_APCS_GCC_SIZE	SZ_4K
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap.h b/arch/arm/mach-msm/include/mach/msm_iomap.h
index 21bea4f..6f925d4 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap.h
@@ -105,7 +105,7 @@
 
 
 #if defined(CONFIG_ARCH_MSM9615) || defined(CONFIG_ARCH_MSM7X27) \
-	|| defined(CONFIG_ARCH_MSM7X30)
+	|| defined(CONFIG_ARCH_MSM7X30) || defined(CONFIG_ARCH_MSM9625)
 #define MSM_SHARED_RAM_SIZE	SZ_1M
 #else
 #define MSM_SHARED_RAM_SIZE	SZ_2M
diff --git a/arch/arm/mach-msm/include/mach/msm_memory_dump.h b/arch/arm/mach-msm/include/mach/msm_memory_dump.h
index 5e686bf..729a077 100644
--- a/arch/arm/mach-msm/include/mach/msm_memory_dump.h
+++ b/arch/arm/mach-msm/include/mach/msm_memory_dump.h
@@ -17,7 +17,8 @@
 
 enum dump_client_type {
 	MSM_CPU_CTXT = 0,
-	MSM_CACHE,
+	MSM_L1_CACHE,
+	MSM_L2_CACHE,
 	MSM_OCMEM,
 	MSM_TMC_ETFETB,
 	MSM_ETM0_REG,
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index 5430f99..e0fec65 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -497,7 +497,7 @@
 
 void __init msm_map_mpq8092_io(void)
 {
-	msm_shared_ram_phys = MSM8974_MSM_SHARED_RAM_PHYS;
+	msm_shared_ram_phys = MSM8092_MSM_SHARED_RAM_PHYS;
 	msm_map_io(mpq8092_io_desc, ARRAY_SIZE(mpq8092_io_desc));
 }
 #endif /* CONFIG_ARCH_MPQ8092 */
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index 7dc8d0f..c82eac1 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -2096,7 +2096,7 @@
 			mutex_lock(&rt_entry->lock);
 			i += scnprintf(buf + i, max - i,
 				       "Node Id: 0x%08x\n", rt_entry->node_id);
-			if (j == IPC_ROUTER_NID_LOCAL) {
+			if (rt_entry->node_id == IPC_ROUTER_NID_LOCAL) {
 				i += scnprintf(buf + i, max - i,
 				       "XPRT Name: Loopback\n");
 				i += scnprintf(buf + i, max - i,
diff --git a/arch/arm/mach-msm/lpm_levels.c b/arch/arm/mach-msm/lpm_levels.c
index f7456ef..8218a42 100644
--- a/arch/arm/mach-msm/lpm_levels.c
+++ b/arch/arm/mach-msm/lpm_levels.c
@@ -92,8 +92,8 @@
 }
 
 static void *msm_lpm_lowest_limits(bool from_idle,
-		enum msm_pm_sleep_mode sleep_mode, uint32_t latency_us,
-		uint32_t sleep_us, uint32_t *power)
+		enum msm_pm_sleep_mode sleep_mode,
+		struct msm_pm_time_params *time_param, uint32_t *power)
 {
 	unsigned int cpu = smp_processor_id();
 	struct msm_rpmrs_level *best_level = NULL;
@@ -114,20 +114,22 @@
 		if (sleep_mode != level->sleep_mode)
 			continue;
 
-		if (latency_us < level->latency_us)
+		if (time_param->latency_us < level->latency_us)
 			continue;
 
-		if (sleep_us <= 1) {
+		if (time_param->sleep_us <= 1) {
 			pwr = level->energy_overhead;
-		} else if (sleep_us <= level->time_overhead_us) {
-			pwr = level->energy_overhead / sleep_us;
-		} else if ((sleep_us >> 10) > level->time_overhead_us) {
+		} else if (time_param->sleep_us <= level->time_overhead_us) {
+			pwr = level->energy_overhead / time_param->sleep_us;
+		} else if ((time_param->sleep_us >> 10)
+				> level->time_overhead_us) {
 			pwr = level->steady_state_power;
 		} else {
 			pwr = level->steady_state_power;
 			pwr -= (level->time_overhead_us *
-					level->steady_state_power)/sleep_us;
-			pwr += level->energy_overhead / sleep_us;
+				level->steady_state_power) /
+						time_param->sleep_us;
+			pwr += level->energy_overhead / time_param->sleep_us;
 		}
 
 		if (!best_level || best_level->rs_limits.power[cpu] >= pwr) {
diff --git a/arch/arm/mach-msm/msm_cache_dump.c b/arch/arm/mach-msm/msm_cache_dump.c
index 9759d5a..8b4978f 100644
--- a/arch/arm/mach-msm/msm_cache_dump.c
+++ b/arch/arm/mach-msm/msm_cache_dump.c
@@ -21,10 +21,13 @@
 #include <linux/pm.h>
 #include <linux/memory_alloc.h>
 #include <linux/notifier.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <mach/scm.h>
 #include <mach/msm_cache_dump.h>
 #include <mach/memory.h>
 #include <mach/msm_iomap.h>
+#include <mach/msm_memory_dump.h>
 
 #define L2_DUMP_OFFSET 0x14
 
@@ -37,6 +40,7 @@
  */
 static struct l1_cache_dump *l1_dump;
 static struct l2_cache_dump *l2_dump;
+static int use_imem_dump_offset;
 
 static int msm_cache_dump_panic(struct notifier_block *this,
 				unsigned long event, void *ptr)
@@ -45,7 +49,8 @@
 	/*
 	 * Clear the bootloader magic so the dumps aren't overwritten
 	 */
-	__raw_writel(0, MSM_IMEM_BASE + L2_DUMP_OFFSET);
+	if (use_imem_dump_offset)
+		__raw_writel(0, MSM_IMEM_BASE + L2_DUMP_OFFSET);
 
 	scm_call_atomic1(L1C_SERVICE_ID, CACHE_BUFFER_DUMP_COMMAND_ID, 2);
 	scm_call_atomic1(L1C_SERVICE_ID, CACHE_BUFFER_DUMP_COMMAND_ID, 1);
@@ -65,14 +70,38 @@
 static int msm_cache_dump_probe(struct platform_device *pdev)
 {
 	struct msm_cache_dump_platform_data *d = pdev->dev.platform_data;
+	struct msm_client_dump l1_dump_entry, l2_dump_entry;
 	int ret;
 	struct {
 		unsigned long buf;
 		unsigned long size;
 	} l1_cache_data;
 	void *temp;
-	unsigned long total_size = d->l1_size + d->l2_size;
+	u32 l1_size, l2_size;
+	unsigned long total_size;
 
+	if (pdev->dev.of_node) {
+		ret = of_property_read_u32(pdev->dev.of_node,
+					   "qcom,l1-dump-size", &l1_size);
+		if (ret)
+			return ret;
+
+		ret = of_property_read_u32(pdev->dev.of_node,
+					   "qcom,l2-dump-size", &l2_size);
+		if (ret)
+			return ret;
+
+		use_imem_dump_offset = of_property_read_bool(pdev->dev.of_node,
+						   "qcom,use-imem-dump-offset");
+	} else {
+		l1_size = d->l1_size;
+		l2_size = d->l2_size;
+
+		/* Non-DT targets assume the IMEM dump offset shall be used */
+		use_imem_dump_offset = 1;
+	};
+
+	total_size = l1_size + l2_size;
 	msm_cache_dump_addr = allocate_contiguous_ebi_nomap(total_size, SZ_4K);
 
 	if (!msm_cache_dump_addr) {
@@ -86,7 +115,7 @@
 	iounmap(temp);
 
 	l1_cache_data.buf = msm_cache_dump_addr;
-	l1_cache_data.size = d->l1_size;
+	l1_cache_data.size = l1_size;
 
 	ret = scm_call(L1C_SERVICE_ID, L1C_BUFFER_SET_COMMAND_ID,
 			&l1_cache_data, sizeof(l1_cache_data), NULL, 0);
@@ -96,10 +125,11 @@
 			__func__, ret);
 
 	l1_dump = (struct l1_cache_dump *)msm_cache_dump_addr;
+	l2_dump = (struct l2_cache_dump *)(msm_cache_dump_addr + l1_size);
 
 #if defined(CONFIG_MSM_CACHE_DUMP_ON_PANIC)
-	l1_cache_data.buf = msm_cache_dump_addr + d->l1_size;
-	l1_cache_data.size = d->l2_size;
+	l1_cache_data.buf = msm_cache_dump_addr + l1_size;
+	l1_cache_data.size = l2_size;
 
 	ret = scm_call(L1C_SERVICE_ID, L2C_BUFFER_SET_COMMAND_ID,
 			&l1_cache_data, sizeof(l1_cache_data), NULL, 0);
@@ -108,11 +138,27 @@
 		pr_err("%s: could not register L2 buffer ret = %d.\n",
 			__func__, ret);
 #endif
-	__raw_writel(msm_cache_dump_addr + d->l1_size,
+
+	if (use_imem_dump_offset)
+		__raw_writel(msm_cache_dump_addr + l1_size,
 			MSM_IMEM_BASE + L2_DUMP_OFFSET);
+	else {
+		l1_dump_entry.id = MSM_L1_CACHE;
+		l1_dump_entry.start_addr = msm_cache_dump_addr;
+		l1_dump_entry.end_addr = l1_dump_entry.start_addr + l1_size - 1;
 
+		l2_dump_entry.id = MSM_L2_CACHE;
+		l2_dump_entry.start_addr = msm_cache_dump_addr + l1_size;
+		l2_dump_entry.end_addr = l2_dump_entry.start_addr + l2_size - 1;
 
-	l2_dump = (struct l2_cache_dump *)(msm_cache_dump_addr + d->l1_size);
+		ret = msm_dump_table_register(&l1_dump_entry);
+		if (ret)
+			pr_err("Could not register L1 dump area: %d\n", ret);
+
+		ret = msm_dump_table_register(&l2_dump_entry);
+		if (ret)
+			pr_err("Could not register L2 dump area: %d\n", ret);
+	}
 
 	atomic_notifier_chain_register(&panic_notifier_list,
 						&msm_cache_dump_blk);
@@ -126,11 +172,18 @@
 	return 0;
 }
 
+static struct of_device_id cache_dump_match_table[] = {
+	{	.compatible = "qcom,cache_dump",	},
+	{}
+};
+EXPORT_COMPAT("qcom,cache_dump");
+
 static struct platform_driver msm_cache_dump_driver = {
 	.remove		= __devexit_p(msm_cache_dump_remove),
 	.driver         = {
 		.name = "msm_cache_dump",
-		.owner = THIS_MODULE
+		.owner = THIS_MODULE,
+		.of_match_table = cache_dump_match_table,
 	},
 };
 
diff --git a/arch/arm/mach-msm/msm_cpr.c b/arch/arm/mach-msm/msm_cpr.c
index e2640a2..12f7d96 100644
--- a/arch/arm/mach-msm/msm_cpr.c
+++ b/arch/arm/mach-msm/msm_cpr.c
@@ -44,6 +44,8 @@
  */
 #define TIMER_COUNT(freq, delay) ((freq * delay) / 1000)
 #define ALL_CPR_IRQ 0x3F
+#define STEP_QUOT_MAX 25
+#define STEP_QUOT_MIN 12
 
 /* Need platform device handle for suspend and resume APIs */
 static struct platform_device *cpr_pdev;
@@ -269,8 +271,19 @@
 		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",
+	/*
+	 * Based on chip characterization data, it is good to add some
+	 * margin on top of calculated step quot to help reduce the
+	 * number of CPR interrupts. The present value suggested is 3.
+	 * Further, if the step quot is outside range, clamp it to the
+	 * maximum permitted value.
+	 */
+	chip_data->step_quot = ((quot1 - quot2) / 4) + 3;
+	if (chip_data->step_quot < STEP_QUOT_MIN ||
+			chip_data->step_quot > STEP_QUOT_MAX)
+		chip_data->step_quot = STEP_QUOT_MAX;
+
+	pr_info("%s: Step Quot is %d\n",
 			__func__, chip_data->step_quot);
 	/* Disable the cpr */
 	cpr_modify_reg(cpr, RBCPR_CTL, LOOP_EN_M, DISABLE_CPR);
@@ -626,6 +639,8 @@
 					RBCPR_GCNT_TARGET(cpr->curr_osc)));
 		pr_debug("%s: new_freq: %d, set_freq: %d, quot: %d\n", __func__,
 			freqs->new, new_freq, quot);
+		pr_info("%s: PVS Voltage setting is: %d\n", __func__,
+			regulator_get_voltage(cpr->vreg_cx));
 
 		enable_irq(cpr->irq);
 		/**
diff --git a/arch/arm/mach-msm/ocmem_rdm.c b/arch/arm/mach-msm/ocmem_rdm.c
index 85dc85d..4aba69c 100644
--- a/arch/arm/mach-msm/ocmem_rdm.c
+++ b/arch/arm/mach-msm/ocmem_rdm.c
@@ -93,8 +93,8 @@
 static void *br_base;
 static void *dm_base;
 
-static atomic_t dm_pending;
-static wait_queue_head_t dm_wq;
+struct completion dm_clear_event;
+struct completion dm_transfer_event;
 /* Shadow tables for debug purposes */
 struct ocmem_br_table {
 	unsigned int offset;
@@ -136,22 +136,22 @@
 		pr_debug("Data mover completed\n");
 		irq_status &= ~BIT(0);
 		ocmem_write(irq_status, dm_base + DM_INTR_CLR);
+		complete(&dm_transfer_event);
 	} 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);
+		complete(&dm_clear_event);
 	} else {
 		BUG_ON(1);
 	}
-	atomic_set(&dm_pending, 0);
-	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);
+	INIT_COMPLETION(dm_clear_event);
 	/* Clear DM Mask */
 	ocmem_write(DM_MASK_RESET, dm_base + DM_INTR_MASK);
 	/* Clear DM Interrupts */
@@ -169,8 +169,8 @@
 	/* Trigger Data Clear */
 	ocmem_write(DM_CLR_ENABLE, dm_base + DM_CLR_TRIGGER);
 
-	wait_event_interruptible(dm_wq,
-		atomic_read(&dm_pending) == 0);
+	wait_for_completion(&dm_clear_event);
+
 	return 0;
 }
 #else
@@ -249,7 +249,7 @@
 
 	status = ocmem_read(dm_base + DM_GEN_STATUS);
 	pr_debug("Transfer status before %x\n", status);
-	atomic_set(&dm_pending, 1);
+	INIT_COMPLETION(dm_transfer_event);
 	/* The DM and BR tables must be programmed before triggering the
 	 * Data Mover else the coherent transfer would be corrupted
 	 */
@@ -258,9 +258,7 @@
 	ocmem_write(dm_ctrl, dm_base + DM_CTRL);
 	pr_debug("ocmem: rdm: dm_ctrl %x br_ctrl %x\n", dm_ctrl, br_ctrl);
 
-	wait_event_interruptible(dm_wq,
-		atomic_read(&dm_pending) == 0);
-
+	wait_for_completion(&dm_transfer_event);
 	ocmem_disable_core_clock();
 	return 0;
 }
@@ -291,7 +289,8 @@
 		return rc;
 	}
 
-	init_waitqueue_head(&dm_wq);
+	init_completion(&dm_clear_event);
+	init_completion(&dm_transfer_event);
 	/* Clear DM Mask */
 	ocmem_write(DM_MASK_RESET, dm_base + DM_INTR_MASK);
 	/* enable dm interrupts */
diff --git a/arch/arm/mach-msm/pil-riva.c b/arch/arm/mach-msm/pil-riva.c
index ba0e242..3040a31 100644
--- a/arch/arm/mach-msm/pil-riva.c
+++ b/arch/arm/mach-msm/pil-riva.c
@@ -21,7 +21,6 @@
 #include <linux/regulator/consumer.h>
 #include <linux/clk.h>
 
-#include <asm/mach-types.h>
 #include <mach/msm_iomap.h>
 
 #include "peripheral-loader.h"
@@ -359,18 +358,12 @@
 
 static int __init pil_riva_init(void)
 {
-	if (machine_is_mpq8064_hrd()) {
-		pr_err("pil_riva not supported on this target\n");
-		return 0;
-	}
 	return platform_driver_register(&pil_riva_driver);
 }
 module_init(pil_riva_init);
 
 static void __exit pil_riva_exit(void)
 {
-	if (machine_is_mpq8064_hrd())
-		return;
 	platform_driver_unregister(&pil_riva_driver);
 }
 module_exit(pil_riva_exit);
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index dbb23d5..60ee8f0 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -49,6 +49,7 @@
 #include "spm.h"
 #include "timer.h"
 #include "pm-boot.h"
+#include <mach/event_timer.h>
 
 /******************************************************************************
  * Debug Definitions
@@ -112,6 +113,7 @@
 		"standalone_power_collapse",
 };
 
+static struct hrtimer pm_hrtimer;
 static struct msm_pm_sleep_ops pm_sleep_ops;
 /*
  * Write out the attribute.
@@ -645,6 +647,28 @@
 	return time;
 }
 
+/**
+ * pm_hrtimer_cb() : Callback function for hrtimer created if the
+ *                   core needs to be awake to handle an event.
+ * @hrtimer : Pointer to hrtimer
+ */
+static enum hrtimer_restart pm_hrtimer_cb(struct hrtimer *hrtimer)
+{
+	return HRTIMER_NORESTART;
+}
+
+/**
+ * msm_pm_set_timer() : Set an hrtimer to wakeup the core in time
+ *                      to handle an event.
+ */
+static void msm_pm_set_timer(uint32_t modified_time_us)
+{
+	u64 modified_time_ns = modified_time_us * NSEC_PER_USEC;
+	ktime_t modified_ktime = ns_to_ktime(modified_time_ns);
+	pm_hrtimer.function = pm_hrtimer_cb;
+	hrtimer_start(&pm_hrtimer, modified_ktime, HRTIMER_MODE_ABS);
+}
+
 /******************************************************************************
  * External Idle/Suspend Functions
  *****************************************************************************/
@@ -657,15 +681,25 @@
 int msm_pm_idle_prepare(struct cpuidle_device *dev,
 		struct cpuidle_driver *drv, int index)
 {
-	uint32_t latency_us;
-	uint32_t sleep_us;
 	int i;
 	unsigned int power_usage = -1;
 	int ret = 0;
+	uint32_t modified_time_us = 0;
+	struct msm_pm_time_params time_param;
 
-	latency_us = (uint32_t) pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
-	sleep_us = (uint32_t) ktime_to_ns(tick_nohz_get_sleep_length());
-	sleep_us = DIV_ROUND_UP(sleep_us, 1000);
+	time_param.latency_us =
+		(uint32_t) pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
+	time_param.sleep_us =
+		(uint32_t) (ktime_to_us(tick_nohz_get_sleep_length())
+								& UINT_MAX);
+	time_param.modified_time_us = 0;
+
+	if (!dev->cpu)
+		time_param.next_event_us =
+			(uint32_t) (ktime_to_us(get_next_event_time())
+								& UINT_MAX);
+	else
+		time_param.next_event_us = 0;
 
 	for (i = 0; i < dev->state_count; i++) {
 		struct cpuidle_state *state = &drv->states[i];
@@ -702,17 +736,18 @@
 		case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
 			if (!allow)
 				break;
+			/* fall through */
 
 			if (pm_sleep_ops.lowest_limits)
 				rs_limits = pm_sleep_ops.lowest_limits(true,
-						mode, latency_us, sleep_us,
-						&power);
+						mode, &time_param, &power);
 
 			if (MSM_PM_DEBUG_IDLE & msm_pm_debug_mask)
 				pr_info("CPU%u: %s: %s, latency %uus, "
 					"sleep %uus, limit %p\n",
 					dev->cpu, __func__, state->desc,
-					latency_us, sleep_us, rs_limits);
+					time_param.latency_us,
+					time_param.sleep_us, rs_limits);
 
 			if (!rs_limits)
 				allow = false;
@@ -730,6 +765,7 @@
 		if (allow) {
 			if (power < power_usage) {
 				power_usage = power;
+				modified_time_us = time_param.modified_time_us;
 				ret = mode;
 			}
 
@@ -738,6 +774,8 @@
 		}
 	}
 
+	if (modified_time_us && !dev->cpu)
+		msm_pm_set_timer(modified_time_us);
 	return ret;
 }
 
@@ -850,6 +888,11 @@
 	int i;
 	int64_t period = 0;
 	int64_t time = msm_pm_timer_enter_suspend(&period);
+	struct msm_pm_time_params time_param;
+
+	time_param.latency_us = -1;
+	time_param.sleep_us = -1;
+	time_param.next_event_us = 0;
 
 	if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
 		pr_info("%s\n", __func__);
@@ -887,8 +930,7 @@
 #endif /* CONFIG_MSM_SLEEP_TIME_OVERRIDE */
 		if (pm_sleep_ops.lowest_limits)
 			rs_limits = pm_sleep_ops.lowest_limits(false,
-					MSM_PM_SLEEP_MODE_POWER_COLLAPSE, -1,
-					-1, &power);
+			MSM_PM_SLEEP_MODE_POWER_COLLAPSE, &time_param, &power);
 
 		if (rs_limits) {
 			if (pm_sleep_ops.enter_sleep)
@@ -1046,6 +1088,7 @@
 
 	suspend_set_ops(&msm_pm_ops);
 	msm_pm_qtimer_available();
+	hrtimer_init(&pm_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
 	msm_cpuidle_init();
 	platform_driver_register(&msm_pc_counter_driver);
 
diff --git a/arch/arm/mach-msm/pm.h b/arch/arm/mach-msm/pm.h
index e2553e2..51256ca 100644
--- a/arch/arm/mach-msm/pm.h
+++ b/arch/arm/mach-msm/pm.h
@@ -57,6 +57,13 @@
 
 #define MSM_PM_MODE(cpu, mode_nr)  ((cpu) * MSM_PM_SLEEP_MODE_NR + (mode_nr))
 
+struct msm_pm_time_params {
+	uint32_t latency_us;
+	uint32_t sleep_us;
+	uint32_t next_event_us;
+	uint32_t modified_time_us;
+};
+
 struct msm_pm_platform_data {
 	u8 idle_supported;   /* Allow device to enter mode during idle */
 	u8 suspend_supported; /* Allow device to enter mode during suspend */
@@ -72,8 +79,8 @@
 
 struct msm_pm_sleep_ops {
 	void *(*lowest_limits)(bool from_idle,
-			enum msm_pm_sleep_mode sleep_mode, uint32_t latency_us,
-			uint32_t sleep_us, uint32_t *power);
+			enum msm_pm_sleep_mode sleep_mode,
+			struct msm_pm_time_params *time_param, uint32_t *power);
 	int (*enter_sleep)(uint32_t sclk_count, void *limits,
 			bool from_idle, bool notify_rpm);
 	void (*exit_sleep)(void *limits, bool from_idle,
diff --git a/arch/arm/mach-msm/qdsp6v2/Makefile b/arch/arm/mach-msm/qdsp6v2/Makefile
index 0c75f66..ed8cb345 100644
--- a/arch/arm/mach-msm/qdsp6v2/Makefile
+++ b/arch/arm/mach-msm/qdsp6v2/Makefile
@@ -26,3 +26,4 @@
 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/
+obj-m += adsprpc.o
diff --git a/arch/arm/mach-msm/qdsp6v2/adsprpc.c b/arch/arm/mach-msm/qdsp6v2/adsprpc.c
new file mode 100644
index 0000000..6e6f8e8
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/adsprpc.c
@@ -0,0 +1,706 @@
+/*
+ * 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 "adsprpc.h"
+
+struct smq_invoke_ctx {
+	struct completion work;
+	int retval;
+	atomic_t free;
+};
+
+struct smq_context_list {
+	struct smq_invoke_ctx *ls;
+	int size;
+	int last;
+};
+
+struct fastrpc_apps {
+	smd_channel_t *chan;
+	struct smq_context_list clst;
+	struct completion work;
+	struct ion_client *iclient;
+	struct cdev cdev;
+	dev_t dev_no;
+	spinlock_t wrlock;
+	spinlock_t hlock;
+	struct hlist_head htbl[RPC_HASH_SZ];
+};
+
+struct fastrpc_buf {
+	struct ion_handle *handle;
+	void *virt;
+	ion_phys_addr_t phys;
+	int size;
+	int used;
+};
+
+struct fastrpc_device {
+	uint32_t tgid;
+	struct hlist_node hn;
+	struct fastrpc_buf buf;
+};
+
+static struct fastrpc_apps gfa;
+
+static void free_mem(struct fastrpc_buf *buf)
+{
+	struct fastrpc_apps *me = &gfa;
+
+	if (buf->handle) {
+		if (buf->virt) {
+			ion_unmap_kernel(me->iclient, buf->handle);
+			buf->virt = 0;
+		}
+		ion_free(me->iclient, buf->handle);
+		buf->handle = 0;
+	}
+}
+
+static int alloc_mem(struct fastrpc_buf *buf)
+{
+	struct ion_client *clnt = gfa.iclient;
+	int err = 0;
+
+	buf->handle = ion_alloc(clnt, buf->size, SZ_4K,
+				ION_HEAP(ION_AUDIO_HEAP_ID));
+	VERIFY(0 == IS_ERR_OR_NULL(buf->handle));
+	buf->virt = 0;
+	VERIFY(0 != (buf->virt = ion_map_kernel(clnt, buf->handle,
+						ION_SET_CACHE(CACHED))));
+	VERIFY(0 == ion_phys(clnt, buf->handle, &buf->phys, &buf->size));
+ bail:
+	if (err && !IS_ERR_OR_NULL(buf->handle))
+		free_mem(buf);
+	return err;
+}
+
+static int context_list_ctor(struct smq_context_list *me, int size)
+{
+	int err = 0;
+	VERIFY(0 != (me->ls = kzalloc(size, GFP_KERNEL)));
+	me->size = size / sizeof(*me->ls);
+	me->last = 0;
+ bail:
+	return err;
+}
+
+static void context_list_dtor(struct smq_context_list *me)
+{
+	kfree(me->ls);
+	me->ls = 0;
+}
+
+static void context_list_alloc_ctx(struct smq_context_list *me,
+					struct smq_invoke_ctx **po)
+{
+	int ii = me->last;
+	struct smq_invoke_ctx *ctx;
+
+	for (;;) {
+		ii = ii % me->size;
+		ctx = &me->ls[ii];
+		if (atomic_read(&ctx->free) == 0)
+			if (0 == atomic_cmpxchg(&ctx->free, 0, 1))
+				break;
+		ii++;
+	}
+	me->last = ii;
+	ctx->retval = -1;
+	init_completion(&ctx->work);
+	*po = ctx;
+}
+
+static void context_free(struct smq_invoke_ctx *me)
+{
+	if (me)
+		atomic_set(&me->free, 0);
+}
+
+static void context_notify_user(struct smq_invoke_ctx *me, int retval)
+{
+	me->retval = retval;
+	complete(&me->work);
+}
+
+static void context_notify_all_users(struct smq_context_list *me)
+{
+	int ii;
+
+	if (!me->ls)
+		return;
+	for (ii = 0; ii < me->size; ++ii) {
+		if (atomic_read(&me->ls[ii].free) != 0)
+			complete(&me->ls[ii].work);
+	}
+}
+
+static int get_page_list(uint32_t kernel, uint32_t sc, remote_arg_t *pra,
+			struct fastrpc_buf *ibuf, struct fastrpc_buf *obuf)
+{
+	struct smq_phy_page *pgstart, *pages;
+	struct smq_invoke_buf *list;
+	int ii, rlen, err = 0;
+	int inbufs = REMOTE_SCALARS_INBUFS(sc);
+	int outbufs = REMOTE_SCALARS_OUTBUFS(sc);
+
+	VERIFY(0 != try_module_get(THIS_MODULE));
+	LOCK_MMAP(kernel);
+	*obuf = *ibuf;
+ retry:
+	list = smq_invoke_buf_start((remote_arg_t *)obuf->virt, sc);
+	pgstart = smq_phy_page_start(sc, list);
+	pages = pgstart + 1;
+	rlen = obuf->size - ((uint32_t)pages - (uint32_t)obuf->virt);
+	if (rlen < 0) {
+		rlen = ((uint32_t)pages - (uint32_t)obuf->virt) - obuf->size;
+		obuf->size += buf_page_size(rlen);
+		obuf->handle = 0;
+		VERIFY(0 == alloc_mem(obuf));
+		goto retry;
+	}
+	pgstart->addr = obuf->phys;
+	pgstart->size = obuf->size;
+	for (ii = 0; ii < inbufs + outbufs; ++ii) {
+		void *buf;
+		int len, num;
+
+		len = pra[ii].buf.len;
+		if (!len)
+			continue;
+		buf = pra[ii].buf.pv;
+		num = buf_num_pages(buf, len);
+		if (!kernel)
+			list[ii].num = buf_get_pages(buf, len, num,
+				ii >= inbufs, pages, rlen / sizeof(*pages));
+		else
+			list[ii].num = 0;
+		VERIFY(list[ii].num >= 0);
+		if (list[ii].num) {
+			list[ii].pgidx = pages - pgstart;
+			pages = pages + list[ii].num;
+		} else if (rlen > sizeof(*pages)) {
+			list[ii].pgidx = pages - pgstart;
+			pages = pages + 1;
+		} else {
+			if (obuf->handle != ibuf->handle)
+				free_mem(obuf);
+			obuf->size += buf_page_size(sizeof(*pages));
+			obuf->handle = 0;
+			VERIFY(0 == alloc_mem(obuf));
+			goto retry;
+		}
+		rlen = obuf->size - ((uint32_t) pages - (uint32_t) obuf->virt);
+	}
+	obuf->used = obuf->size - rlen;
+ bail:
+	if (err && (obuf->handle != ibuf->handle))
+		free_mem(obuf);
+	UNLOCK_MMAP(kernel);
+	module_put(THIS_MODULE);
+	return err;
+}
+
+static int get_args(uint32_t kernel, uint32_t sc, remote_arg_t *pra,
+			remote_arg_t *rpra, remote_arg_t *upra,
+			struct fastrpc_buf *ibuf, struct fastrpc_buf **abufs,
+			int *nbufs)
+{
+	struct smq_invoke_buf *list;
+	struct fastrpc_buf *pbuf = ibuf, *obufs = 0;
+	struct smq_phy_page *pages;
+	void *args;
+	int ii, rlen, size, used, inh, bufs = 0, err = 0;
+	int inbufs = REMOTE_SCALARS_INBUFS(sc);
+	int outbufs = REMOTE_SCALARS_OUTBUFS(sc);
+
+	list = smq_invoke_buf_start(rpra, sc);
+	pages = smq_phy_page_start(sc, list);
+	used = ALIGN_8(pbuf->used);
+	args = (void *)((char *)pbuf->virt + used);
+	rlen = pbuf->size - used;
+	for (ii = 0; ii < inbufs + outbufs; ++ii) {
+		int num;
+
+		rpra[ii].buf.len = pra[ii].buf.len;
+		if (list[ii].num) {
+			rpra[ii].buf.pv = pra[ii].buf.pv;
+			continue;
+		}
+		if (rlen < pra[ii].buf.len) {
+			struct fastrpc_buf *b;
+			pbuf->used = pbuf->size - rlen;
+			VERIFY(0 != (b = krealloc(obufs,
+				 (bufs + 1) * sizeof(*obufs), GFP_KERNEL)));
+			obufs = b;
+			pbuf = obufs + bufs;
+			pbuf->size = buf_num_pages(0, pra[ii].buf.len) *
+								PAGE_SIZE;
+			VERIFY(0 == alloc_mem(pbuf));
+			bufs++;
+			args = pbuf->virt;
+			rlen = pbuf->size;
+		}
+		num = buf_num_pages(args, pra[ii].buf.len);
+		if (pbuf == ibuf) {
+			list[ii].num = num;
+			list[ii].pgidx = 0;
+		} else {
+			list[ii].num = 1;
+			pages[list[ii].pgidx].addr =
+				buf_page_start((void *)(pbuf->phys +
+							 (pbuf->size - rlen)));
+			pages[list[ii].pgidx].size =
+				buf_page_size(pra[ii].buf.len);
+		}
+		if (ii < inbufs) {
+			if (!kernel)
+				VERIFY(0 == copy_from_user(args, pra[ii].buf.pv,
+							pra[ii].buf.len));
+			else
+				memmove(args, pra[ii].buf.pv, pra[ii].buf.len);
+		}
+		rpra[ii].buf.pv = args;
+		args = (void *)((char *)args + ALIGN_8(pra[ii].buf.len));
+		rlen -= ALIGN_8(pra[ii].buf.len);
+	}
+	for (ii = 0; ii < inbufs; ++ii) {
+		if (rpra[ii].buf.len)
+			dmac_flush_range(rpra[ii].buf.pv,
+				  (char *)rpra[ii].buf.pv + rpra[ii].buf.len);
+	}
+	pbuf->used = pbuf->size - rlen;
+	size = sizeof(*rpra) * REMOTE_SCALARS_INHANDLES(sc);
+	if (size) {
+		inh = inbufs + outbufs;
+		if (!kernel)
+			VERIFY(0 == copy_from_user(&rpra[inh], &upra[inh],
+							size));
+		else
+			memmove(&rpra[inh], &upra[inh], size);
+	}
+	dmac_flush_range(rpra, (char *)rpra + used);
+ bail:
+	*abufs = obufs;
+	*nbufs = bufs;
+	return err;
+}
+
+static int put_args(uint32_t kernel, uint32_t sc, remote_arg_t *pra,
+			remote_arg_t *rpra, remote_arg_t *upra)
+{
+	int ii, inbufs, outbufs, outh, size;
+	int err = 0;
+
+	inbufs = REMOTE_SCALARS_INBUFS(sc);
+	outbufs = REMOTE_SCALARS_OUTBUFS(sc);
+	for (ii = inbufs; ii < inbufs + outbufs; ++ii) {
+		if (rpra[ii].buf.pv != pra[ii].buf.pv)
+			VERIFY(0 == copy_to_user(pra[ii].buf.pv,
+					rpra[ii].buf.pv, rpra[ii].buf.len));
+	}
+	size = sizeof(*rpra) * REMOTE_SCALARS_OUTHANDLES(sc);
+	if (size) {
+		outh = inbufs + outbufs + REMOTE_SCALARS_INHANDLES(sc);
+		if (!kernel)
+			VERIFY(0 == copy_to_user(&upra[outh], &rpra[outh],
+						size));
+		else
+			memmove(&upra[outh], &rpra[outh], size);
+	}
+ bail:
+	return err;
+}
+
+static void inv_args(uint32_t sc, remote_arg_t *rpra, int used)
+{
+	int ii, inbufs, outbufs;
+	int inv = 0;
+
+	inbufs = REMOTE_SCALARS_INBUFS(sc);
+	outbufs = REMOTE_SCALARS_OUTBUFS(sc);
+	for (ii = inbufs; ii < inbufs + outbufs; ++ii) {
+		if (buf_page_start(rpra) == buf_page_start(rpra[ii].buf.pv))
+			inv = 1;
+		else
+			dmac_inv_range(rpra[ii].buf.pv,
+				(char *)rpra[ii].buf.pv + rpra[ii].buf.len);
+	}
+
+	if (inv || REMOTE_SCALARS_OUTHANDLES(sc))
+		dmac_inv_range(rpra, (char *)rpra + used);
+}
+
+static int fastrpc_invoke_send(struct fastrpc_apps *me, remote_handle_t handle,
+				 uint32_t sc, struct smq_invoke_ctx *ctx,
+				 struct fastrpc_buf *buf)
+{
+	struct smq_msg msg;
+	int err = 0, len;
+
+	msg.pid = current->tgid;
+	msg.tid = current->pid;
+	msg.invoke.header.ctx = ctx;
+	msg.invoke.header.handle = handle;
+	msg.invoke.header.sc = sc;
+	msg.invoke.page.addr = buf->phys;
+	msg.invoke.page.size = buf_page_size(buf->used);
+	spin_lock(&me->wrlock);
+	len = smd_write(me->chan, &msg, sizeof(msg));
+	spin_unlock(&me->wrlock);
+	VERIFY(len == sizeof(msg));
+ bail:
+	return err;
+}
+
+static void fastrpc_deinit(void)
+{
+	struct fastrpc_apps *me = &gfa;
+
+	if (me->chan)
+		(void)smd_close(me->chan);
+	context_list_dtor(&me->clst);
+	ion_client_destroy(me->iclient);
+	me->iclient = 0;
+	me->chan = 0;
+}
+
+static void fastrpc_read_handler(void)
+{
+	struct fastrpc_apps *me = &gfa;
+	struct smq_invoke_rsp rsp;
+	int err = 0;
+
+	do {
+		VERIFY(sizeof(rsp) ==
+				 smd_read_from_cb(me->chan, &rsp, sizeof(rsp)));
+		context_notify_user(rsp.ctx, rsp.retval);
+	} while (!err);
+ bail:
+	return;
+}
+
+static void smd_event_handler(void *priv, unsigned event)
+{
+	struct fastrpc_apps *me = (struct fastrpc_apps *)priv;
+
+	switch (event) {
+	case SMD_EVENT_OPEN:
+		complete(&(me->work));
+		break;
+	case SMD_EVENT_CLOSE:
+		context_notify_all_users(&me->clst);
+		break;
+	case SMD_EVENT_DATA:
+		fastrpc_read_handler();
+		break;
+	}
+}
+
+static int fastrpc_init(void)
+{
+	int err = 0;
+	struct fastrpc_apps *me = &gfa;
+
+	if (me->chan == 0) {
+		int ii;
+		spin_lock_init(&me->hlock);
+		spin_lock_init(&me->wrlock);
+		init_completion(&me->work);
+		for (ii = 0; ii < RPC_HASH_SZ; ++ii)
+			INIT_HLIST_HEAD(&me->htbl[ii]);
+		VERIFY(0 == context_list_ctor(&me->clst, SZ_4K));
+		me->iclient = msm_ion_client_create(ION_HEAP_CARVEOUT_MASK,
+							DEVICE_NAME);
+		VERIFY(0 == IS_ERR_OR_NULL(me->iclient));
+		VERIFY(0 == smd_named_open_on_edge(FASTRPC_SMD_GUID,
+						SMD_APPS_QDSP, &me->chan,
+						me, smd_event_handler));
+		VERIFY(0 != wait_for_completion_timeout(&me->work,
+							RPC_TIMEOUT));
+	}
+ bail:
+	if (err)
+		fastrpc_deinit();
+	return err;
+}
+
+static void free_dev(struct fastrpc_device *dev)
+{
+	if (dev) {
+		module_put(THIS_MODULE);
+		free_mem(&dev->buf);
+		kfree(dev);
+	}
+}
+
+static int alloc_dev(struct fastrpc_device **dev)
+{
+	int err = 0;
+	struct fastrpc_device *fd = 0;
+
+	VERIFY(0 != try_module_get(THIS_MODULE));
+	VERIFY(0 != (fd = kzalloc(sizeof(*fd), GFP_KERNEL)));
+	fd->buf.size = PAGE_SIZE;
+	VERIFY(0 == alloc_mem(&fd->buf));
+	fd->tgid = current->tgid;
+	INIT_HLIST_NODE(&fd->hn);
+	*dev = fd;
+ bail:
+	if (err)
+		free_dev(fd);
+	return err;
+}
+
+static int get_dev(struct fastrpc_apps *me, struct fastrpc_device **rdev)
+{
+	struct hlist_head *head;
+	struct fastrpc_device *dev = 0;
+	struct hlist_node *n;
+	uint32_t h = hash_32(current->tgid, RPC_HASH_BITS);
+	int err = 0;
+
+	spin_lock(&me->hlock);
+	head = &me->htbl[h];
+	hlist_for_each_entry(dev, n, head, hn) {
+		if (dev->tgid == current->tgid) {
+			hlist_del(&dev->hn);
+			break;
+		}
+	}
+	spin_unlock(&me->hlock);
+	VERIFY(dev != 0);
+	*rdev = dev;
+ bail:
+	if (err) {
+		free_dev(dev);
+		err = alloc_dev(rdev);
+	}
+	return err;
+}
+
+static void add_dev(struct fastrpc_apps *me, struct fastrpc_device *dev)
+{
+	struct hlist_head *head;
+	uint32_t h = hash_32(current->tgid, RPC_HASH_BITS);
+
+	spin_lock(&me->hlock);
+	head = &me->htbl[h];
+	hlist_add_head(&dev->hn, head);
+	spin_unlock(&me->hlock);
+	return;
+}
+
+static int fastrpc_release_current_dsp_process(void);
+
+static int fastrpc_internal_invoke(struct fastrpc_apps *me, uint32_t kernel,
+			struct fastrpc_ioctl_invoke *invoke, remote_arg_t *pra)
+{
+	remote_arg_t *rpra = 0;
+	struct fastrpc_device *dev = 0;
+	struct smq_invoke_ctx *ctx = 0;
+	struct fastrpc_buf obuf, *abufs = 0, *b;
+	int interrupted = 0;
+	uint32_t sc;
+	int ii, nbufs = 0, err = 0;
+
+	sc = invoke->sc;
+	obuf.handle = 0;
+	if (REMOTE_SCALARS_LENGTH(sc)) {
+		VERIFY(0 == get_dev(me, &dev));
+		VERIFY(0 == get_page_list(kernel, sc, pra, &dev->buf, &obuf));
+		rpra = (remote_arg_t *)obuf.virt;
+		VERIFY(0 == get_args(kernel, sc, pra, rpra, invoke->pra, &obuf,
+					&abufs, &nbufs));
+	}
+
+	context_list_alloc_ctx(&me->clst, &ctx);
+	VERIFY(0 == fastrpc_invoke_send(me, invoke->handle, sc, ctx, &obuf));
+	inv_args(sc, rpra, obuf.used);
+	VERIFY(0 == (interrupted =
+			wait_for_completion_interruptible(&ctx->work)));
+	VERIFY(0 == (err = ctx->retval));
+	VERIFY(0 == put_args(kernel, sc, pra, rpra, invoke->pra));
+ bail:
+	if (interrupted) {
+		init_completion(&ctx->work);
+		if (!kernel)
+			(void)fastrpc_release_current_dsp_process();
+		wait_for_completion(&ctx->work);
+	}
+	context_free(ctx);
+	for (ii = 0, b = abufs; ii < nbufs; ++ii, ++b)
+		free_mem(b);
+	kfree(abufs);
+	if (dev) {
+		add_dev(me, dev);
+		if (obuf.handle != dev->buf.handle)
+			free_mem(&obuf);
+	}
+	return err;
+}
+
+static int fastrpc_create_current_dsp_process(void)
+{
+	int err = 0;
+	struct fastrpc_ioctl_invoke ioctl;
+	struct fastrpc_apps *me = &gfa;
+	remote_arg_t ra[1];
+	int tgid = 0;
+
+	tgid = current->tgid;
+	ra[0].buf.pv = &tgid;
+	ra[0].buf.len = sizeof(tgid);
+	ioctl.handle = 1;
+	ioctl.sc = REMOTE_SCALARS_MAKE(0, 1, 0);
+	ioctl.pra = ra;
+	VERIFY(0 == fastrpc_internal_invoke(me, 1, &ioctl, ra));
+ bail:
+	return err;
+}
+
+static int fastrpc_release_current_dsp_process(void)
+{
+	int err = 0;
+	struct fastrpc_apps *me = &gfa;
+	struct fastrpc_ioctl_invoke ioctl;
+	remote_arg_t ra[1];
+	int tgid = 0;
+
+	tgid = current->tgid;
+	ra[0].buf.pv = &tgid;
+	ra[0].buf.len = sizeof(tgid);
+	ioctl.handle = 1;
+	ioctl.sc = REMOTE_SCALARS_MAKE(1, 1, 0);
+	ioctl.pra = ra;
+	VERIFY(0 == fastrpc_internal_invoke(me, 1, &ioctl, ra));
+ bail:
+	return err;
+}
+
+static void cleanup_current_dev(void)
+{
+	struct fastrpc_apps *me = &gfa;
+	uint32_t h = hash_32(current->tgid, RPC_HASH_BITS);
+	struct hlist_head *head;
+	struct hlist_node *pos;
+	struct fastrpc_device *dev;
+
+ rnext:
+	dev = 0;
+	spin_lock(&me->hlock);
+	head = &me->htbl[h];
+	hlist_for_each_entry(dev, pos, head, hn) {
+		if (dev->tgid == current->tgid) {
+			hlist_del(&dev->hn);
+			break;
+		}
+	}
+	spin_unlock(&me->hlock);
+	if (dev) {
+		free_dev(dev);
+		goto rnext;
+	}
+	return;
+}
+
+static int fastrpc_device_release(struct inode *inode, struct file *file)
+{
+	(void)fastrpc_release_current_dsp_process();
+	cleanup_current_dev();
+	return 0;
+}
+
+static int fastrpc_device_open(struct inode *inode, struct file *filp)
+{
+	int err = 0;
+
+	if (0 != try_module_get(THIS_MODULE)) {
+		/* This call will cause a dev to be created
+		 * which will addref this module
+		 */
+		VERIFY(0 == fastrpc_create_current_dsp_process());
+ bail:
+		if (err)
+			cleanup_current_dev();
+		module_put(THIS_MODULE);
+	}
+	return err;
+}
+
+
+static long fastrpc_device_ioctl(struct file *file, unsigned int ioctl_num,
+				 unsigned long ioctl_param)
+{
+	struct fastrpc_apps *me = &gfa;
+	struct fastrpc_ioctl_invoke invoke;
+	remote_arg_t *pra = 0;
+	void *param = (char *)ioctl_param;
+	int bufs, err = 0;
+
+	switch (ioctl_num) {
+	case FASTRPC_IOCTL_INVOKE:
+		VERIFY(0 == copy_from_user(&invoke, param, sizeof(invoke)));
+		bufs = REMOTE_SCALARS_INBUFS(invoke.sc) +
+			REMOTE_SCALARS_OUTBUFS(invoke.sc);
+		if (bufs) {
+			bufs = bufs * sizeof(*pra);
+			VERIFY(0 != (pra = kmalloc(bufs, GFP_KERNEL)));
+		}
+		VERIFY(0 == copy_from_user(pra, invoke.pra, bufs));
+		VERIFY(0 == (err = fastrpc_internal_invoke(me, 0, &invoke,
+								pra)));
+		break;
+	default:
+		err = -EINVAL;
+		break;
+	}
+ bail:
+	kfree(pra);
+	return err;
+}
+
+static const struct file_operations fops = {
+	.open = fastrpc_device_open,
+	.release = fastrpc_device_release,
+	.unlocked_ioctl = fastrpc_device_ioctl,
+};
+
+static int __init fastrpc_device_init(void)
+{
+	struct fastrpc_apps *me = &gfa;
+	int err = 0;
+
+	VERIFY(0 == fastrpc_init());
+	VERIFY(0 == alloc_chrdev_region(&me->dev_no, 0, 1, DEVICE_NAME));
+	cdev_init(&me->cdev, &fops);
+	me->cdev.owner = THIS_MODULE;
+	VERIFY(0 == cdev_add(&me->cdev, MKDEV(MAJOR(me->dev_no), 0), 1));
+	pr_info("'mknod /dev/%s c %d 0'\n", DEVICE_NAME, MAJOR(me->dev_no));
+ bail:
+	return err;
+}
+
+static void __exit fastrpc_device_exit(void)
+{
+	struct fastrpc_apps *me = &gfa;
+
+	fastrpc_deinit();
+	cdev_del(&me->cdev);
+	unregister_chrdev_region(me->dev_no, 1);
+}
+
+module_init(fastrpc_device_init);
+module_exit(fastrpc_device_exit);
+
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp6v2/adsprpc.h b/arch/arm/mach-msm/qdsp6v2/adsprpc.h
new file mode 100644
index 0000000..368b8e6
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/adsprpc.h
@@ -0,0 +1,106 @@
+/*
+ * 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 ADSPRPC_H
+#define ADSPRPC_H
+
+#include <linux/slab.h>
+#include <linux/completion.h>
+#include <linux/pagemap.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/cdev.h>
+#include <linux/list.h>
+#include <linux/hash.h>
+#include <linux/ion.h>
+#include <mach/msm_smd.h>
+#include <mach/ion.h>
+#include "adsprpc_shared.h"
+
+#ifndef ION_ADSPRPC_HEAP_ID
+#define ION_ADSPRPC_HEAP_ID ION_AUDIO_HEAP_ID
+#endif
+
+#define RPC_TIMEOUT	(5 * HZ)
+#define RPC_HASH_BITS	5
+#define RPC_HASH_SZ	(1 << RPC_HASH_BITS)
+
+#define ALIGN_8(a)	ALIGN(a, 8)
+
+#define LOCK_MMAP(kernel)\
+		do {\
+			if (!kernel)\
+				down_read(&current->mm->mmap_sem);\
+		} while (0)
+
+#define UNLOCK_MMAP(kernel)\
+		do {\
+			if (!kernel)\
+				up_read(&current->mm->mmap_sem);\
+		} while (0)
+
+
+static inline uint32_t buf_page_start(void *buf)
+{
+	uint32_t start = (uint32_t) buf & PAGE_MASK;
+	return start;
+}
+
+static inline uint32_t buf_page_offset(void *buf)
+{
+	uint32_t offset = (uint32_t) buf & (PAGE_SIZE - 1);
+	return offset;
+}
+
+static inline int buf_num_pages(void *buf, int len)
+{
+	uint32_t start = buf_page_start(buf) >> PAGE_SHIFT;
+	uint32_t end = (((uint32_t) buf + len - 1) & PAGE_MASK) >> PAGE_SHIFT;
+	int nPages = end - start + 1;
+	return nPages;
+}
+
+static inline uint32_t buf_page_size(uint32_t size)
+{
+	uint32_t sz = (size + (PAGE_SIZE - 1)) & PAGE_MASK;
+	return sz > PAGE_SIZE ? sz : PAGE_SIZE;
+}
+
+static inline int buf_get_pages(void *addr, int sz, int nr_pages, int access,
+				  struct smq_phy_page *pages, int nr_elems)
+{
+	struct vm_area_struct *vma;
+	uint32_t start = buf_page_start(addr);
+	uint32_t len = nr_pages << PAGE_SHIFT;
+	uint32_t pfn;
+	int n = -1, err = 0;
+
+	VERIFY(0 != access_ok(access ? VERIFY_WRITE : VERIFY_READ,
+			      (void __user *)start, len));
+	VERIFY(0 != (vma = find_vma(current->mm, start)));
+	VERIFY(((uint32_t)addr + sz) <= vma->vm_end);
+	n = 0;
+	VERIFY(0 != (vma->vm_flags & VM_PFNMAP));
+	VERIFY(0 != (vma->vm_flags & VM_PFN_AT_MMAP));
+	VERIFY(nr_elems > 0);
+	pfn = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT);
+	pages->addr = __pfn_to_phys(pfn);
+	pages->size = len;
+	n++;
+ bail:
+	return n;
+}
+
+#endif
diff --git a/arch/arm/mach-msm/qdsp6v2/adsprpc_shared.h b/arch/arm/mach-msm/qdsp6v2/adsprpc_shared.h
new file mode 100644
index 0000000..04b1d4a
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/adsprpc_shared.h
@@ -0,0 +1,147 @@
+/*
+ * 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 ADSPRPC_SHARED_H
+#define ADSPRPC_SHARED_H
+
+#define FASTRPC_IOCTL_INVOKE _IOWR('R', 1, struct fastrpc_ioctl_invoke)
+#define FASTRPC_SMD_GUID "fastrpcsmd-apps-dsp"
+#define DEVICE_NAME      "adsprpc-smd"
+
+/* Retrives number of input buffers from the scalars parameter */
+#define REMOTE_SCALARS_INBUFS(sc)        (((sc) >> 16) & 0x0ff)
+
+/* Retrives number of output buffers from the scalars parameter */
+#define REMOTE_SCALARS_OUTBUFS(sc)       (((sc) >> 8) & 0x0ff)
+
+/* Retrives number of input handles from the scalars parameter */
+#define REMOTE_SCALARS_INHANDLES(sc)     (((sc) >> 4) & 0x0f)
+
+/* Retrives number of output handles from the scalars parameter */
+#define REMOTE_SCALARS_OUTHANDLES(sc)    ((sc) & 0x0f)
+
+#define REMOTE_SCALARS_LENGTH(sc)	(REMOTE_SCALARS_INBUFS(sc) +\
+					REMOTE_SCALARS_OUTBUFS(sc) +\
+					REMOTE_SCALARS_INHANDLES(sc) +\
+					REMOTE_SCALARS_OUTHANDLES(sc))
+
+#define REMOTE_SCALARS_MAKEX(attr, method, in, out, oin, oout) \
+		((((uint32_t)   (attr) & 0x7) << 29) | \
+		(((uint32_t) (method) & 0x1f) << 24) | \
+		(((uint32_t)     (in) & 0xff) << 16) | \
+		(((uint32_t)    (out) & 0xff) <<  8) | \
+		(((uint32_t)    (oin) & 0x0f) <<  4) | \
+		((uint32_t)   (oout) & 0x0f))
+
+#define REMOTE_SCALARS_MAKE(method, in, out) \
+		REMOTE_SCALARS_MAKEX(0, method, in, out, 0, 0)
+
+
+#ifndef VERIFY_PRINT_ERROR
+#define VERIFY_EPRINTF(format, args) (void)0
+#endif
+
+#ifndef VERIFY_PRINT_INFO
+#define VERIFY_IPRINTF(args) (void)0
+#endif
+
+#ifndef VERIFY
+#define __STR__(x) #x ":"
+#define __TOSTR__(x) __STR__(x)
+#define __FILE_LINE__ __FILE__ ":" __TOSTR__(__LINE__)
+
+#define VERIFY(val) \
+do {\
+	VERIFY_IPRINTF(__FILE_LINE__"info: calling: " #val "\n");\
+	if (0 == (val)) {\
+		err = err == 0 ? -1 : err;\
+		VERIFY_EPRINTF(__FILE_LINE__"error: %d: " #val "\n", err);\
+		goto bail;\
+	} else {\
+		VERIFY_IPRINTF(__FILE_LINE__"info: passed: " #val "\n");\
+	} \
+} while (0)
+#endif
+
+#define remote_handle_t uint32_t
+#define remote_arg_t    union remote_arg
+
+struct remote_buf {
+	void *pv;		/* buffer pointer */
+	int len;		/* length of buffer */
+};
+
+union remote_arg {
+	struct remote_buf buf;	/* buffer info */
+	remote_handle_t h;	/* remote handle */
+};
+
+struct fastrpc_ioctl_invoke {
+	remote_handle_t handle;	/* remote handle */
+	uint32_t sc;		/* scalars describing the data */
+	remote_arg_t *pra;	/* remote arguments list */
+};
+
+struct smq_null_invoke {
+	struct smq_invoke_ctx *ctx; /* invoke caller context */
+	remote_handle_t handle;	    /* handle to invoke */
+	uint32_t sc;		    /* scalars structure describing the data */
+};
+
+struct smq_phy_page {
+	uint32_t addr;		/* physical address */
+	uint32_t size;		/* size of contiguous region */
+};
+
+struct smq_invoke_buf {
+	int num;		/* number of contiguous regions */
+	int pgidx;		/* index to start of contiguous region */
+};
+
+struct smq_invoke {
+	struct smq_null_invoke header;
+	struct smq_phy_page page;   /* remote arg and list of pages address */
+};
+
+struct smq_msg {
+	uint32_t pid;           /* process group id */
+	uint32_t tid;           /* thread id */
+	struct smq_invoke invoke;
+};
+
+struct smq_invoke_rsp {
+	struct smq_invoke_ctx *ctx;  /* invoke caller context */
+	int retval;	             /* invoke return value */
+};
+
+static inline struct smq_invoke_buf *smq_invoke_buf_start(remote_arg_t *pra,
+							uint32_t sc)
+{
+	int len = REMOTE_SCALARS_LENGTH(sc);
+	return (struct smq_invoke_buf *)(&pra[len]);
+}
+
+static inline struct smq_phy_page *smq_phy_page_start(uint32_t sc,
+						struct smq_invoke_buf *buf)
+{
+	int nTotal = REMOTE_SCALARS_INBUFS(sc) + REMOTE_SCALARS_OUTBUFS(sc);
+	return (struct smq_phy_page *)(&buf[nTotal]);
+}
+
+static inline int smq_invoke_buf_size(uint32_t sc, int nPages)
+{
+	struct smq_phy_page *start = smq_phy_page_start(sc, 0);
+	return (int)(&(start[nPages]));
+}
+
+#endif
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
index a7e34d9..2e4b756 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
@@ -471,13 +471,20 @@
 
 	pr_debug("%s[%p]:\n", __func__, audio);
 
-	mutex_lock(&audio->write_lock);
 	audio->eos_rsp = 0;
 
+	pr_debug("%s[%p]Wait for write done from DSP\n", __func__, audio);
 	rc = wait_event_interruptible(audio->write_wait,
 					(list_empty(&audio->out_queue)) ||
 					audio->wflush || audio->stopped);
 
+	if (audio->stopped || audio->wflush) {
+		pr_debug("%s[%p]: Audio Flushed or Stopped,this is not EOS\n"
+			, __func__, audio);
+		audio->wflush = 0;
+		rc = -EBUSY;
+	}
+
 	if (rc < 0) {
 		pr_err("%s[%p]: wait event for list_empty failed, rc = %d\n",
 			__func__, audio, rc);
@@ -485,11 +492,14 @@
 	}
 
 	rc = q6asm_cmd(audio->ac, CMD_EOS);
+	pr_debug("%s[%p]: EOS cmd sent to DSP\n", __func__, audio);
 
 	if (rc < 0)
 		pr_err("%s[%p]: q6asm_cmd failed, rc = %d",
 			__func__, audio, rc);
 
+	pr_debug("%s[%p]: wait for RENDERED_EOS from DSP\n"
+		, __func__, audio);
 	rc = wait_event_interruptible(audio->write_wait,
 					(audio->eos_rsp || audio->wflush ||
 					audio->stopped));
@@ -500,22 +510,18 @@
 		goto done;
 	}
 
-	if (audio->eos_rsp == 1) {
-		rc = audio_aio_enable(audio);
-		if (rc)
-			pr_err("%s[%p]: audio enable failed\n",
-				__func__, audio);
-		else {
-			audio->drv_status &= ~ADRV_STATUS_PAUSE;
-			audio->enabled = 1;
-		}
+	if (audio->stopped || audio->wflush) {
+		audio->wflush = 0;
+		pr_debug("%s[%p]: Audio Flushed or Stopped,this is not EOS\n"
+			, __func__, audio);
+		rc = -EBUSY;
 	}
 
-	if (audio->stopped || audio->wflush)
-		rc = -EBUSY;
+	if (audio->eos_rsp == 1)
+		pr_debug("%s[%p]: EOS\n", __func__, audio);
+
 
 done:
-	mutex_unlock(&audio->write_lock);
 	mutex_lock(&audio->lock);
 	audio->drv_status &= ~ADRV_STATUS_FSYNC;
 	mutex_unlock(&audio->lock);
@@ -963,7 +969,8 @@
 			audio->drv_ops.out_flush(audio);
 		} else
 			audio->drv_ops.out_flush(audio);
-		audio->drv_ops.in_flush(audio);
+		if (audio->feedback == NON_TUNNEL_MODE)
+			audio->drv_ops.in_flush(audio);
 	}
 }
 
@@ -1167,7 +1174,11 @@
 			rc = -EINTR;
 		} else {
 			audio->rflush = 0;
-			audio->wflush = 0;
+			if (audio->drv_status & ADRV_STATUS_FSYNC)
+				wake_up(&audio->write_wait);
+			else
+				audio->wflush = 0;
+
 		}
 		audio->eos_flag = 0;
 		audio->eos_rsp = 0;
diff --git a/arch/arm/mach-msm/restart.c b/arch/arm/mach-msm/restart.c
index 53736ac..5883b0c 100644
--- a/arch/arm/mach-msm/restart.c
+++ b/arch/arm/mach-msm/restart.c
@@ -24,6 +24,7 @@
 #include <linux/mfd/pmic8058.h>
 #include <linux/mfd/pmic8901.h>
 #include <linux/mfd/pm8xxx/misc.h>
+#include <linux/qpnp/power-on.h>
 
 #include <asm/mach-types.h>
 #include <asm/cacheflush.h>
@@ -128,6 +129,7 @@
 	set_dload_mode(0);
 #endif
 	pm8xxx_reset_pwr_off(0);
+	qpnp_pon_system_pwr_off(0);
 
 	if (lower_pshold) {
 		if (!use_restart_v2())
@@ -208,6 +210,7 @@
 #endif
 
 	pm8xxx_reset_pwr_off(1);
+	qpnp_pon_system_pwr_off(1);
 
 	if (cmd != NULL) {
 		if (!strncmp(cmd, "bootloader", 10)) {
diff --git a/arch/arm/mach-msm/rpm-smd.c b/arch/arm/mach-msm/rpm-smd.c
index a190342..a9d1ed8 100644
--- a/arch/arm/mach-msm/rpm-smd.c
+++ b/arch/arm/mach-msm/rpm-smd.c
@@ -289,9 +289,10 @@
 
 	if (!handle)
 		return;
-	for (i = 0; i < handle->write_idx; i++)
+	for (i = 0; i < handle->num_elements; i++)
 		kfree(handle->kvp[i].value);
 	kfree(handle->kvp);
+	kfree(handle->buf);
 	kfree(handle);
 }
 EXPORT_SYMBOL(msm_rpm_free_request);
diff --git a/arch/arm/mach-msm/rpm_resources.c b/arch/arm/mach-msm/rpm_resources.c
index 9d794e7..2a835f7 100644
--- a/arch/arm/mach-msm/rpm_resources.c
+++ b/arch/arm/mach-msm/rpm_resources.c
@@ -20,6 +20,7 @@
 #include <linux/proc_fs.h>
 #include <linux/spinlock.h>
 #include <linux/cpu.h>
+#include <linux/hrtimer.h>
 #include <mach/rpm.h>
 #include <mach/msm_iomap.h>
 #include <asm/mach-types.h>
@@ -37,6 +38,7 @@
 enum {
 	MSM_RPMRS_DEBUG_OUTPUT = BIT(0),
 	MSM_RPMRS_DEBUG_BUFFER = BIT(1),
+	MSM_RPMRS_DEBUG_EVENT_TIMER = BIT(2),
 };
 
 static int msm_rpmrs_debug_mask;
@@ -891,8 +893,8 @@
 }
 
 static void *msm_rpmrs_lowest_limits(bool from_idle,
-		enum msm_pm_sleep_mode sleep_mode, uint32_t latency_us,
-		uint32_t sleep_us, uint32_t *power)
+		enum msm_pm_sleep_mode sleep_mode,
+		struct msm_pm_time_params *time_param, uint32_t *power)
 {
 	unsigned int cpu = smp_processor_id();
 	struct msm_rpmrs_level *best_level = NULL;
@@ -900,6 +902,8 @@
 	bool gpio_detectable = false;
 	int i;
 	uint32_t pwr;
+	uint32_t next_wakeup_us = time_param->sleep_us;
+	bool modify_event_timer;
 
 	if (sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE) {
 		irqs_detectable = msm_mpm_irqs_detectable(from_idle);
@@ -909,16 +913,32 @@
 	for (i = 0; i < msm_rpmrs_level_count; i++) {
 		struct msm_rpmrs_level *level = &msm_rpmrs_levels[i];
 
+		modify_event_timer = false;
+
 		if (!level->available)
 			continue;
 
 		if (sleep_mode != level->sleep_mode)
 			continue;
 
-		if (latency_us < level->latency_us)
+		if (time_param->latency_us < level->latency_us)
 			continue;
 
-		if (sleep_us <= level->time_overhead_us)
+		if (time_param->next_event_us &&
+				time_param->next_event_us < level->latency_us)
+			continue;
+
+		if (time_param->next_event_us) {
+			if ((time_param->next_event_us < time_param->sleep_us)
+			|| ((time_param->next_event_us - level->latency_us) <
+				time_param->sleep_us)) {
+				modify_event_timer = true;
+				next_wakeup_us = time_param->next_event_us -
+						level->latency_us;
+			}
+		}
+
+		if (next_wakeup_us <= level->time_overhead_us)
 			continue;
 
 		if (!msm_rpmrs_irqs_detectable(&level->rs_limits,
@@ -929,18 +949,17 @@
 			if (!cpu && msm_rpm_local_request_is_outstanding())
 					break;
 
-
-		if (sleep_us <= 1) {
+		if (next_wakeup_us <= 1) {
 			pwr = level->energy_overhead;
-		} else if (sleep_us <= level->time_overhead_us) {
-			pwr = level->energy_overhead / sleep_us;
-		} else if ((sleep_us >> 10) > level->time_overhead_us) {
+		} else if (next_wakeup_us <= level->time_overhead_us) {
+			pwr = level->energy_overhead / next_wakeup_us;
+		} else if ((next_wakeup_us >> 10) > level->time_overhead_us) {
 			pwr = level->steady_state_power;
 		} else {
 			pwr = level->steady_state_power;
 			pwr -= (level->time_overhead_us *
-					level->steady_state_power)/sleep_us;
-			pwr += level->energy_overhead / sleep_us;
+				level->steady_state_power)/next_wakeup_us;
+			pwr += level->energy_overhead / next_wakeup_us;
 		}
 
 		if (!best_level ||
@@ -950,6 +969,12 @@
 			best_level = level;
 			if (power)
 				*power = pwr;
+			if (modify_event_timer && best_level->latency_us > 1)
+				time_param->modified_time_us =
+					time_param->next_event_us -
+							best_level->latency_us;
+			else
+				time_param->modified_time_us = 0;
 		}
 	}
 
diff --git a/arch/arm/mach-msm/smd_pkt.c b/arch/arm/mach-msm/smd_pkt.c
index 5962d71..928e59b 100644
--- a/arch/arm/mach-msm/smd_pkt.c
+++ b/arch/arm/mach-msm/smd_pkt.c
@@ -35,6 +35,7 @@
 
 #include <mach/msm_smd.h>
 #include <mach/peripheral-loader.h>
+#include <mach/msm_ipc_logging.h>
 
 #include "smd_private.h"
 #ifdef CONFIG_ARCH_FSM9XXX
@@ -65,6 +66,7 @@
 	wait_queue_head_t ch_opened_wait_queue;
 
 	int i;
+	int ref_cnt;
 
 	int blocking_write;
 	int is_open;
@@ -88,6 +90,9 @@
 static void check_and_wakeup_writer(struct smd_pkt_dev *smd_pkt_devp);
 static uint32_t is_modem_smsm_inited(void);
 
+#define SMD_PKT_IPC_LOG_PAGE_CNT 2
+static void *smd_pkt_ilctxt;
+
 static int msm_smd_pkt_debug_mask;
 module_param_named(debug_mask, msm_smd_pkt_debug_mask,
 		int, S_IRUGO | S_IWUSR | S_IWGRP);
@@ -104,22 +109,44 @@
 #define DEBUG
 
 #ifdef DEBUG
+
+#define SMD_PKT_LOG_STRING(x...) \
+do { \
+	if (smd_pkt_ilctxt) \
+		ipc_log_string(smd_pkt_ilctxt, "<SMD_PKT>: "x); \
+} while (0)
+
+#define SMD_PKT_LOG_BUF(buf, cnt) \
+do { \
+	char log_buf[128]; \
+	int i; \
+	if (smd_pkt_ilctxt) { \
+		i = cnt < 16 ? cnt : 16; \
+		hex_dump_to_buffer(buf, i, 16, 1, log_buf, \
+				   sizeof(log_buf), false); \
+		ipc_log_string(smd_pkt_ilctxt, "<SMD_PKT>: %s", log_buf); \
+	} \
+} while (0)
+
 #define D_STATUS(x...) \
 do { \
 	if (msm_smd_pkt_debug_mask & SMD_PKT_STATUS) \
 		pr_info("Status: "x); \
+	SMD_PKT_LOG_STRING(x); \
 } while (0)
 
 #define D_READ(x...) \
 do { \
 	if (msm_smd_pkt_debug_mask & SMD_PKT_READ) \
 		pr_info("Read: "x); \
+	SMD_PKT_LOG_STRING(x); \
 } while (0)
 
 #define D_WRITE(x...) \
 do { \
 	if (msm_smd_pkt_debug_mask & SMD_PKT_WRITE) \
 		pr_info("Write: "x); \
+	SMD_PKT_LOG_STRING(x); \
 } while (0)
 
 #define D_READ_DUMP_BUFFER(prestr, cnt, buf) \
@@ -128,6 +155,7 @@
 		print_hex_dump(KERN_INFO, prestr, \
 			       DUMP_PREFIX_NONE, 16, 1, \
 			       buf, cnt, 1); \
+	SMD_PKT_LOG_BUF(buf, cnt); \
 } while (0)
 
 #define D_WRITE_DUMP_BUFFER(prestr, cnt, buf) \
@@ -136,12 +164,14 @@
 		print_hex_dump(KERN_INFO, prestr, \
 			       DUMP_PREFIX_NONE, 16, 1, \
 			       buf, cnt, 1); \
+	SMD_PKT_LOG_BUF(buf, cnt); \
 } while (0)
 
 #define D_POLL(x...) \
 do { \
 	if (msm_smd_pkt_debug_mask & SMD_PKT_POLL) \
 		pr_info("Poll: "x); \
+	SMD_PKT_LOG_STRING(x); \
 } while (0)
 
 #define E_SMD_PKT_SSR(x) \
@@ -270,6 +300,7 @@
 	if (!smd_pkt_devp)
 		return -EINVAL;
 
+	mutex_lock(&smd_pkt_devp->ch_lock);
 	switch (cmd) {
 	case TIOCMGET:
 		D_STATUS("%s TIOCMGET command on smd_pkt_dev id:%d\n",
@@ -288,6 +319,7 @@
 		pr_err("%s: Unrecognized ioctl command %d\n", __func__, cmd);
 		ret = -1;
 	}
+	mutex_unlock(&smd_pkt_devp->ch_lock);
 
 	return ret;
 }
@@ -867,9 +899,12 @@
 			smd_pkt_devp->ch_size =
 				smd_write_avail(smd_pkt_devp->ch);
 			r = 0;
+			smd_pkt_devp->ref_cnt++;
 			D_STATUS("Finished %s on smd_pkt_dev id:%d\n",
 				 __func__, smd_pkt_devp->i);
 		}
+	} else {
+		smd_pkt_devp->ref_cnt++;
 	}
 release_pil:
 	if (peripheral && (r < 0))
@@ -902,12 +937,14 @@
 	D_STATUS("Begin %s on smd_pkt_dev id:%d\n",
 		 __func__, smd_pkt_devp->i);
 
-	clean_and_signal(smd_pkt_devp);
-
 	mutex_lock(&smd_pkt_devp->ch_lock);
 	mutex_lock(&smd_pkt_devp->rx_lock);
 	mutex_lock(&smd_pkt_devp->tx_lock);
-	if (smd_pkt_devp->ch != 0) {
+	if (smd_pkt_devp->ref_cnt > 0)
+		smd_pkt_devp->ref_cnt--;
+
+	if (smd_pkt_devp->ch != 0 && smd_pkt_devp->ref_cnt == 0) {
+		clean_and_signal(smd_pkt_devp);
 		r = smd_close(smd_pkt_devp->ch);
 		smd_pkt_devp->ch = 0;
 		smd_pkt_devp->blocking_write = 0;
@@ -916,15 +953,15 @@
 		smd_pkt_devp->driver.probe = NULL;
 		if (smd_pkt_devp->pil)
 			pil_put(smd_pkt_devp->pil);
+		smd_pkt_devp->has_reset = 0;
+		smd_pkt_devp->do_reset_notification = 0;
+		smd_pkt_devp->wakelock_locked = 0;
+		wake_lock_destroy(&smd_pkt_devp->pa_wake_lock);
 	}
 	mutex_unlock(&smd_pkt_devp->tx_lock);
 	mutex_unlock(&smd_pkt_devp->rx_lock);
 	mutex_unlock(&smd_pkt_devp->ch_lock);
 
-	smd_pkt_devp->has_reset = 0;
-	smd_pkt_devp->do_reset_notification = 0;
-	smd_pkt_devp->wakelock_locked = 0;
-	wake_lock_destroy(&smd_pkt_devp->pa_wake_lock);
 	D_STATUS("Finished %s on smd_pkt_dev id:%d\n",
 		 __func__, smd_pkt_devp->i);
 
@@ -1024,6 +1061,9 @@
 
 	INIT_DELAYED_WORK(&loopback_work, loopback_probe_worker);
 
+	smd_pkt_ilctxt = ipc_log_context_create(SMD_PKT_IPC_LOG_PAGE_CNT,
+						"smd_pkt");
+
 	D_STATUS("SMD Packet Port Driver Initialized.\n");
 	return 0;
 
diff --git a/arch/arm/mach-msm/spm-v2.c b/arch/arm/mach-msm/spm-v2.c
index 26dfdff..1eab9bf 100644
--- a/arch/arm/mach-msm/spm-v2.c
+++ b/arch/arm/mach-msm/spm-v2.c
@@ -310,9 +310,43 @@
 	return 0;
 }
 
+#ifdef CONFIG_MSM_AVS_HW
+static void msm_spm_drv_disable_avs(struct msm_spm_driver_data *dev)
+{
+	msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_AVS_CTL);
+	dev->reg_shadow[MSM_SPM_REG_SAW2_AVS_CTL] &= ~BIT(27);
+	msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_AVS_CTL);
+}
+
+static void msm_spm_drv_enable_avs(struct msm_spm_driver_data *dev)
+{
+	dev->reg_shadow[MSM_SPM_REG_SAW2_AVS_CTL] |= BIT(27);
+	msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_AVS_CTL);
+}
+
+static void msm_spm_drv_set_avs_vlevel(struct msm_spm_driver_data *dev,
+		unsigned int vlevel)
+{
+	vlevel &= 0x3f;
+	dev->reg_shadow[MSM_SPM_REG_SAW2_AVS_CTL] &= ~0x7efc00;
+	dev->reg_shadow[MSM_SPM_REG_SAW2_AVS_CTL] |= ((vlevel - 4) << 10);
+	dev->reg_shadow[MSM_SPM_REG_SAW2_AVS_CTL] |= (vlevel << 17);
+	msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_AVS_CTL);
+}
+
+#else
+
+static void msm_spm_drv_disable_avs(struct msm_spm_driver_data *dev) { }
+
+static void msm_spm_drv_enable_avs(struct msm_spm_driver_data *dev) { }
+
+static void msm_spm_drv_set_avs_vlevel(struct msm_spm_driver_data *dev,
+		unsigned int vlevel) { }
+#endif
+
 int msm_spm_drv_set_vdd(struct msm_spm_driver_data *dev, unsigned int vlevel)
 {
-	uint32_t timeout_us;
+	uint32_t timeout_us, new_level;
 
 	if (!dev)
 		return -EINVAL;
@@ -321,42 +355,46 @@
 		return -ENOSYS;
 
 	if (msm_spm_debug_mask & MSM_SPM_DEBUG_VCTL)
-		pr_info("%s: requesting vlevel 0x%x\n",
-			__func__, vlevel);
+		pr_info("%s: requesting vlevel %#x\n", __func__, vlevel);
+
+	msm_spm_drv_disable_avs(dev);
+
+	/* Kick the state machine back to idle */
+	dev->reg_shadow[MSM_SPM_REG_SAW2_RST] = 1;
+	msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_RST);
 
 	msm_spm_drv_apcs_set_vctl(dev, vlevel);
 	msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_VCTL);
 	msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_PMIC_DATA_0);
 	msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_PMIC_DATA_1);
-	mb();
 
-	/* Wait for PMIC state to return to idle or until timeout */
 	timeout_us = dev->vctl_timeout_us;
-	while (msm_spm_drv_get_sts_pmic_state(dev) != MSM_SPM_PMIC_STATE_IDLE) {
-		if (!timeout_us)
-			goto set_vdd_bail;
-
-		if (timeout_us > 10) {
-			udelay(10);
-			timeout_us -= 10;
-		} else {
-			udelay(timeout_us);
-			timeout_us = 0;
-		}
+	/* Confirm the voltage we set was what hardware sent */
+	do {
+		new_level = msm_spm_drv_get_sts_curr_pmic_data(dev);
+		if (new_level == vlevel)
+			break;
+		udelay(1);
+	} while (--timeout_us);
+	if (!timeout_us) {
+		pr_info("Wrong level %#x\n", new_level);
+		goto set_vdd_bail;
 	}
 
-	if (msm_spm_drv_get_sts_curr_pmic_data(dev) != vlevel)
-		goto set_vdd_bail;
+	/* Set AVS min/max */
+	msm_spm_drv_set_avs_vlevel(dev, vlevel);
 
 	if (msm_spm_debug_mask & MSM_SPM_DEBUG_VCTL)
 		pr_info("%s: done, remaining timeout %uus\n",
 			__func__, timeout_us);
 
+	msm_spm_drv_enable_avs(dev);
 	return 0;
 
 set_vdd_bail:
-	pr_err("%s: failed, remaining timeout %uus, vlevel 0x%x\n",
-	       __func__, timeout_us, msm_spm_drv_get_sts_curr_pmic_data(dev));
+	msm_spm_drv_enable_avs(dev);
+	pr_err("%s: failed %#x, remaining timeout %uus, vlevel %#x\n",
+		__func__, vlevel, timeout_us, new_level);
 	return -EIO;
 }
 
diff --git a/arch/arm/mach-msm/spm_devices.c b/arch/arm/mach-msm/spm_devices.c
index 05d11d2..b87b0f1 100644
--- a/arch/arm/mach-msm/spm_devices.c
+++ b/arch/arm/mach-msm/spm_devices.c
@@ -38,16 +38,38 @@
 	uint32_t num_modes;
 };
 
+struct msm_spm_vdd_info {
+	uint32_t cpu;
+	uint32_t vlevel;
+	int err;
+};
+
 static struct msm_spm_device msm_spm_l2_device;
 static DEFINE_PER_CPU_SHARED_ALIGNED(struct msm_spm_device, msm_cpu_spm_device);
 
-int msm_spm_set_vdd(unsigned int cpu, unsigned int vlevel)
+
+/* Must be called on the same cpu as the one being set to */
+static void msm_spm_smp_set_vdd(void *data)
 {
 	struct msm_spm_device *dev;
-	int ret = -EIO;
+	struct msm_spm_vdd_info *info = (struct msm_spm_vdd_info *)data;
 
-	dev = &per_cpu(msm_cpu_spm_device, cpu);
-	ret = msm_spm_drv_set_vdd(&dev->reg_data, vlevel);
+	dev = &per_cpu(msm_cpu_spm_device, info->cpu);
+	info->err = msm_spm_drv_set_vdd(&dev->reg_data, info->vlevel);
+}
+
+int msm_spm_set_vdd(unsigned int cpu, unsigned int vlevel)
+{
+	struct msm_spm_vdd_info info;
+	int ret;
+
+	info.cpu = cpu;
+	info.vlevel = vlevel;
+
+	/* Set to true to block on vdd change */
+	ret = smp_call_function_single(cpu, msm_spm_smp_set_vdd, &info, true);
+	if (!ret)
+		ret = info.err;
 
 	return ret;
 }
diff --git a/arch/arm/mach-msm/subsystem_restart.c b/arch/arm/mach-msm/subsystem_restart.c
index 0318a70..bae1ab0 100644
--- a/arch/arm/mach-msm/subsystem_restart.c
+++ b/arch/arm/mach-msm/subsystem_restart.c
@@ -58,11 +58,13 @@
 enum subsys_state {
 	SUBSYS_OFFLINE,
 	SUBSYS_ONLINE,
+	SUBSYS_CRASHED,
 };
 
 static const char * const subsys_states[] = {
 	[SUBSYS_OFFLINE] = "OFFLINE",
 	[SUBSYS_ONLINE] = "ONLINE",
+	[SUBSYS_CRASHED] = "CRASHED",
 };
 
 struct subsys_device {
@@ -71,7 +73,7 @@
 	char wlname[64];
 	struct work_struct work;
 	spinlock_t restart_lock;
-	int restart_count;
+	bool restarting;
 
 	void *notify;
 	struct device dev;
@@ -107,6 +109,21 @@
 	return snprintf(buf, PAGE_SIZE, "%s\n", subsys_states[state]);
 }
 
+static void subsys_set_state(struct subsys_device *subsys,
+			     enum subsys_state state)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&subsys->restart_lock, flags);
+	if (subsys->state != state) {
+		subsys->state = state;
+		spin_unlock_irqrestore(&subsys->restart_lock, flags);
+		sysfs_notify(&subsys->dev.kobj, NULL, "state");
+		return;
+	}
+	spin_unlock_irqrestore(&subsys->restart_lock, flags);
+}
+
 static struct device_attribute subsys_attrs[] = {
 	__ATTR_RO(name),
 	__ATTR_RO(state),
@@ -333,6 +350,7 @@
 	if (dev->desc->shutdown(dev->desc) < 0)
 		panic("subsys-restart: [%p]: Failed to shutdown %s!",
 			current, name);
+	subsys_set_state(dev, SUBSYS_OFFLINE);
 }
 
 static void subsystem_ramdump(struct subsys_device *dev, void *data)
@@ -351,6 +369,7 @@
 	pr_info("[%p]: Powering up %s\n", current, name);
 	if (dev->desc->powerup(dev->desc) < 0)
 		panic("[%p]: Failed to powerup %s!", current, name);
+	subsys_set_state(dev, SUBSYS_ONLINE);
 }
 
 static int __find_subsys(struct device *dev, void *data)
@@ -418,7 +437,10 @@
 	 * Now that we've acquired the shutdown lock, either we're the first to
 	 * restart these subsystems or some other thread is doing the powerup
 	 * sequence for these subsystems. In the latter case, panic and bail
-	 * out, since a subsystem died in its powerup sequence.
+	 * out, since a subsystem died in its powerup sequence. This catches
+	 * the case where a subsystem in a restart order isn't the one
+	 * who initiated the original restart but has crashed while the restart
+	 * order is being rebooted.
 	 */
 	if (!mutex_trylock(powerup_lock))
 		panic("%s[%p]: Subsystem died during powerup!",
@@ -465,32 +487,36 @@
 
 out:
 	spin_lock_irqsave(&dev->restart_lock, flags);
-	dev->restart_count--;
-	if (!dev->restart_count)
-		wake_unlock(&dev->wake_lock);
+	dev->restarting = false;
+	wake_unlock(&dev->wake_lock);
 	spin_unlock_irqrestore(&dev->restart_lock, flags);
 }
 
 static void __subsystem_restart_dev(struct subsys_device *dev)
 {
 	struct subsys_desc *desc = dev->desc;
+	const char *name = dev->desc->name;
 	unsigned long flags;
 
 	pr_debug("Restarting %s [level=%d]!\n", desc->name, restart_level);
 
+	/*
+	 * We want to allow drivers to call subsystem_restart{_dev}() as many
+	 * times as they want up until the point where the subsystem is
+	 * shutdown.
+	 */
 	spin_lock_irqsave(&dev->restart_lock, flags);
-	if (!dev->restart_count)
-		wake_lock(&dev->wake_lock);
-	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);
+	if (dev->state != SUBSYS_CRASHED) {
+		if (dev->state == SUBSYS_ONLINE && !dev->restarting) {
+			dev->restarting = true;
+			dev->state = SUBSYS_CRASHED;
+			wake_lock(&dev->wake_lock);
+			queue_work(ssr_wq, &dev->work);
+		} else {
+			panic("Subsystem %s crashed during SSR!", name);
+		}
 	}
+	spin_unlock_irqrestore(&dev->restart_lock, flags);
 }
 
 int subsystem_restart_dev(struct subsys_device *dev)
@@ -644,6 +670,7 @@
 	subsys->dev.parent = desc->dev;
 	subsys->dev.bus = &subsys_bus_type;
 	subsys->dev.release = subsys_device_release;
+	subsys->state = SUBSYS_ONLINE; /* Until proper refcounting appears */
 
 	subsys->notify = subsys_notif_add_subsys(desc->name);
 	subsys->restart_order = update_restart_order(subsys);
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index ed03b33..19ef5a6 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -37,6 +37,9 @@
 
 #include "fault.h"
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/exception.h>
+
 #ifdef CONFIG_MMU
 
 #ifdef CONFIG_KPROBES
@@ -173,6 +176,8 @@
 {
 	struct siginfo si;
 
+	trace_user_fault(tsk, addr, fsr);
+
 #ifdef CONFIG_DEBUG_USER
 	if (((user_debug & UDBG_SEGV) && (sig == SIGSEGV)) ||
 	    ((user_debug & UDBG_BUS)  && (sig == SIGBUS))) {
diff --git a/block/Kconfig.iosched b/block/Kconfig.iosched
index 4142d91..5fd98ea 100644
--- a/block/Kconfig.iosched
+++ b/block/Kconfig.iosched
@@ -32,6 +32,17 @@
 	  a new point in the service tree and doing a batch of IO from there
 	  in case of expiry.
 
+config IOSCHED_ROW
+	tristate "ROW I/O scheduler"
+	default y
+	---help---
+	  The ROW I/O scheduler gives priority to READ requests over the
+	  WRITE requests when dispatching, without starving WRITE requests.
+	  Requests are kept in priority queues. Dispatching is done in a RR
+	  manner when the dispatch quantum for each queue is calculated
+	  according to queue priority.
+	  Most suitable for mobile devices.
+
 config IOSCHED_CFQ
 	tristate "CFQ I/O scheduler"
 	# If BLK_CGROUP is a module, CFQ has to be built as module.
@@ -64,6 +75,16 @@
 	config DEFAULT_DEADLINE
 		bool "Deadline" if IOSCHED_DEADLINE=y
 
+	config DEFAULT_ROW
+		bool "ROW" if IOSCHED_ROW=y
+		help
+		  The ROW I/O scheduler gives priority to READ requests
+		  over the WRITE requests when dispatching, without starving
+		  WRITE requests. Requests are kept in priority queues.
+		  Dispatching is done in a RR manner when the dispatch quantum
+		  for each queue is defined according to queue priority.
+		  Most suitable for mobile devices.
+
 	config DEFAULT_CFQ
 		bool "CFQ" if IOSCHED_CFQ=y
 
@@ -75,6 +96,7 @@
 config DEFAULT_IOSCHED
 	string
 	default "deadline" if DEFAULT_DEADLINE
+	default "row" if DEFAULT_ROW
 	default "cfq" if DEFAULT_CFQ
 	default "noop" if DEFAULT_NOOP
 
diff --git a/block/Makefile b/block/Makefile
index 436b220..b5e6637 100644
--- a/block/Makefile
+++ b/block/Makefile
@@ -14,6 +14,7 @@
 obj-$(CONFIG_BLK_DEV_THROTTLING)	+= blk-throttle.o
 obj-$(CONFIG_IOSCHED_NOOP)	+= noop-iosched.o
 obj-$(CONFIG_IOSCHED_DEADLINE)	+= deadline-iosched.o
+obj-$(CONFIG_IOSCHED_ROW)	+= row-iosched.o
 obj-$(CONFIG_IOSCHED_CFQ)	+= cfq-iosched.o
 obj-$(CONFIG_IOSCHED_TEST)	+= test-iosched.o
 
diff --git a/block/row-iosched.c b/block/row-iosched.c
new file mode 100644
index 0000000..f24437c
--- /dev/null
+++ b/block/row-iosched.c
@@ -0,0 +1,681 @@
+/*
+ * ROW (Read Over Write) I/O scheduler.
+ *
+ * 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.
+ */
+
+/* See Documentation/block/row-iosched.txt */
+
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/blkdev.h>
+#include <linux/elevator.h>
+#include <linux/bio.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/compiler.h>
+#include <linux/blktrace_api.h>
+#include <linux/jiffies.h>
+
+/*
+ * enum row_queue_prio - Priorities of the ROW queues
+ *
+ * This enum defines the priorities (and the number of queues)
+ * the requests will be disptributed to. The higher priority -
+ * the bigger is the dispatch quantum given to that queue.
+ * ROWQ_PRIO_HIGH_READ - is the higher priority queue.
+ *
+ */
+enum row_queue_prio {
+	ROWQ_PRIO_HIGH_READ = 0,
+	ROWQ_PRIO_REG_READ,
+	ROWQ_PRIO_HIGH_SWRITE,
+	ROWQ_PRIO_REG_SWRITE,
+	ROWQ_PRIO_REG_WRITE,
+	ROWQ_PRIO_LOW_READ,
+	ROWQ_PRIO_LOW_SWRITE,
+	ROWQ_MAX_PRIO,
+};
+
+/* Flags indicating whether idling is enabled on the queue */
+static const bool queue_idling_enabled[] = {
+	true,	/* ROWQ_PRIO_HIGH_READ */
+	true,	/* ROWQ_PRIO_REG_READ */
+	false,	/* ROWQ_PRIO_HIGH_SWRITE */
+	false,	/* ROWQ_PRIO_REG_SWRITE */
+	false,	/* ROWQ_PRIO_REG_WRITE */
+	false,	/* ROWQ_PRIO_LOW_READ */
+	false,	/* ROWQ_PRIO_LOW_SWRITE */
+};
+
+/* Default values for row queues quantums in each dispatch cycle */
+static const int queue_quantum[] = {
+	100,	/* ROWQ_PRIO_HIGH_READ */
+	100,	/* ROWQ_PRIO_REG_READ */
+	2,	/* ROWQ_PRIO_HIGH_SWRITE */
+	1,	/* ROWQ_PRIO_REG_SWRITE */
+	1,	/* ROWQ_PRIO_REG_WRITE */
+	1,	/* ROWQ_PRIO_LOW_READ */
+	1	/* ROWQ_PRIO_LOW_SWRITE */
+};
+
+/* Default values for idling on read queues */
+#define ROW_IDLE_TIME 50	/* 5 msec */
+#define ROW_READ_FREQ 70	/* 7 msec */
+
+/**
+ * struct rowq_idling_data -  parameters for idling on the queue
+ * @idle_trigger_time:	time (in jiffies). If a new request was
+ *			inserted before this time value, idling
+ *			will be enabled.
+ * @begin_idling:	flag indicating wether we should idle
+ *
+ */
+struct rowq_idling_data {
+	unsigned long		idle_trigger_time;
+	bool			begin_idling;
+};
+
+/**
+ * struct row_queue - requests grouping structure
+ * @rdata:		parent row_data structure
+ * @fifo:		fifo of requests
+ * @prio:		queue priority (enum row_queue_prio)
+ * @nr_dispatched:	number of requests already dispatched in
+ *			the current dispatch cycle
+ * @slice:		number of requests to dispatch in a cycle
+ * @idle_data:		data for idling on queues
+ *
+ */
+struct row_queue {
+	struct row_data		*rdata;
+	struct list_head	fifo;
+	enum row_queue_prio	prio;
+
+	unsigned int		nr_dispatched;
+	unsigned int		slice;
+
+	/* used only for READ queues */
+	struct rowq_idling_data	idle_data;
+};
+
+/**
+ * struct idling_data - data for idling on empty rqueue
+ * @idle_time:		idling duration (msec)
+ * @freq:		min time between two requests that
+ *			triger idling (msec)
+ * @idle_work:		pointer to struct delayed_work
+ *
+ */
+struct idling_data {
+	unsigned long			idle_time;
+	unsigned long			freq;
+
+	struct workqueue_struct	*idle_workqueue;
+	struct delayed_work		idle_work;
+};
+
+/**
+ * struct row_queue - Per block device rqueue structure
+ * @dispatch_queue:	dispatch rqueue
+ * @row_queues:		array of priority request queues with
+ *			dispatch quantum per rqueue
+ * @curr_queue:		index in the row_queues array of the
+ *			currently serviced rqueue
+ * @read_idle:		data for idling after READ request
+ * @nr_reqs: nr_reqs[0] holds the number of all READ requests in
+ *			scheduler, nr_reqs[1] holds the number of all WRITE
+ *			requests in scheduler
+ * @cycle_flags:	used for marking unserved queueus
+ *
+ */
+struct row_data {
+	struct request_queue		*dispatch_queue;
+
+	struct {
+		struct row_queue	rqueue;
+		int			disp_quantum;
+	} row_queues[ROWQ_MAX_PRIO];
+
+	enum row_queue_prio		curr_queue;
+
+	struct idling_data		read_idle;
+	unsigned int			nr_reqs[2];
+
+	unsigned int			cycle_flags;
+};
+
+#define RQ_ROWQ(rq) ((struct row_queue *) ((rq)->elv.priv[0]))
+
+#define row_log(q, fmt, args...)   \
+	blk_add_trace_msg(q, "%s():" fmt , __func__, ##args)
+#define row_log_rowq(rdata, rowq_id, fmt, args...)		\
+	blk_add_trace_msg(rdata->dispatch_queue, "rowq%d " fmt, \
+		rowq_id, ##args)
+
+static inline void row_mark_rowq_unserved(struct row_data *rd,
+					 enum row_queue_prio qnum)
+{
+	rd->cycle_flags |= (1 << qnum);
+}
+
+static inline void row_clear_rowq_unserved(struct row_data *rd,
+					  enum row_queue_prio qnum)
+{
+	rd->cycle_flags &= ~(1 << qnum);
+}
+
+static inline int row_rowq_unserved(struct row_data *rd,
+				   enum row_queue_prio qnum)
+{
+	return rd->cycle_flags & (1 << qnum);
+}
+
+/******************** Static helper functions ***********************/
+/*
+ * kick_queue() - Wake up device driver queue thread
+ * @work:	pointer to struct work_struct
+ *
+ * This is a idling delayed work function. It's purpose is to wake up the
+ * device driver in order for it to start fetching requests.
+ *
+ */
+static void kick_queue(struct work_struct *work)
+{
+	struct delayed_work *idle_work = to_delayed_work(work);
+	struct idling_data *read_data =
+		container_of(idle_work, struct idling_data, idle_work);
+	struct row_data *rd =
+		container_of(read_data, struct row_data, read_idle);
+
+	row_log_rowq(rd, rd->curr_queue, "Performing delayed work");
+	/* Mark idling process as done */
+	rd->row_queues[rd->curr_queue].rqueue.idle_data.begin_idling = false;
+
+	if (!(rd->nr_reqs[0] + rd->nr_reqs[1]))
+		row_log(rd->dispatch_queue, "No requests in scheduler");
+	else {
+		spin_lock_irq(rd->dispatch_queue->queue_lock);
+		__blk_run_queue(rd->dispatch_queue);
+		spin_unlock_irq(rd->dispatch_queue->queue_lock);
+	}
+}
+
+/*
+ * row_restart_disp_cycle() - Restart the dispatch cycle
+ * @rd:	pointer to struct row_data
+ *
+ * This function restarts the dispatch cycle by:
+ * - Setting current queue to ROWQ_PRIO_HIGH_READ
+ * - For each queue: reset the number of requests dispatched in
+ *   the cycle
+ */
+static inline void row_restart_disp_cycle(struct row_data *rd)
+{
+	int i;
+
+	for (i = 0; i < ROWQ_MAX_PRIO; i++)
+		rd->row_queues[i].rqueue.nr_dispatched = 0;
+
+	rd->curr_queue = ROWQ_PRIO_HIGH_READ;
+	row_log(rd->dispatch_queue, "Restarting cycle");
+}
+
+static inline void row_get_next_queue(struct row_data *rd)
+{
+	rd->curr_queue++;
+	if (rd->curr_queue == ROWQ_MAX_PRIO)
+		row_restart_disp_cycle(rd);
+}
+
+/******************* Elevator callback functions *********************/
+
+/*
+ * row_add_request() - Add request to the scheduler
+ * @q:	requests queue
+ * @rq:	request to add
+ *
+ */
+static void row_add_request(struct request_queue *q,
+			    struct request *rq)
+{
+	struct row_data *rd = (struct row_data *)q->elevator->elevator_data;
+	struct row_queue *rqueue = RQ_ROWQ(rq);
+
+	list_add_tail(&rq->queuelist, &rqueue->fifo);
+	rd->nr_reqs[rq_data_dir(rq)]++;
+	rq_set_fifo_time(rq, jiffies); /* for statistics*/
+
+	if (queue_idling_enabled[rqueue->prio]) {
+		if (delayed_work_pending(&rd->read_idle.idle_work))
+			(void)cancel_delayed_work(
+				&rd->read_idle.idle_work);
+		if (time_before(jiffies, rqueue->idle_data.idle_trigger_time)) {
+			rqueue->idle_data.begin_idling = true;
+			row_log_rowq(rd, rqueue->prio, "Enable idling");
+		} else
+			rqueue->idle_data.begin_idling = false;
+
+		rqueue->idle_data.idle_trigger_time =
+			jiffies + msecs_to_jiffies(rd->read_idle.freq);
+	}
+	row_log_rowq(rd, rqueue->prio, "added request");
+}
+
+/*
+ * row_remove_request() -  Remove given request from scheduler
+ * @q:	requests queue
+ * @rq:	request to remove
+ *
+ */
+static void row_remove_request(struct request_queue *q,
+			       struct request *rq)
+{
+	struct row_data *rd = (struct row_data *)q->elevator->elevator_data;
+
+	rq_fifo_clear(rq);
+	rd->nr_reqs[rq_data_dir(rq)]--;
+}
+
+/*
+ * row_dispatch_insert() - move request to dispatch queue
+ * @rd:	pointer to struct row_data
+ *
+ * This function moves the next request to dispatch from
+ * rd->curr_queue to the dispatch queue
+ *
+ */
+static void row_dispatch_insert(struct row_data *rd)
+{
+	struct request *rq;
+
+	rq = rq_entry_fifo(rd->row_queues[rd->curr_queue].rqueue.fifo.next);
+	row_remove_request(rd->dispatch_queue, rq);
+	elv_dispatch_add_tail(rd->dispatch_queue, rq);
+	rd->row_queues[rd->curr_queue].rqueue.nr_dispatched++;
+	row_clear_rowq_unserved(rd, rd->curr_queue);
+	row_log_rowq(rd, rd->curr_queue, " Dispatched request nr_disp = %d",
+		     rd->row_queues[rd->curr_queue].rqueue.nr_dispatched);
+}
+
+/*
+ * row_choose_queue() -  choose the next queue to dispatch from
+ * @rd:	pointer to struct row_data
+ *
+ * Updates rd->curr_queue. Returns 1 if there are requests to
+ * dispatch, 0 if there are no requests in scheduler
+ *
+ */
+static int row_choose_queue(struct row_data *rd)
+{
+	int prev_curr_queue = rd->curr_queue;
+
+	if (!(rd->nr_reqs[0] + rd->nr_reqs[1])) {
+		row_log(rd->dispatch_queue, "No more requests in scheduler");
+		return 0;
+	}
+
+	row_get_next_queue(rd);
+
+	/*
+	 * Loop over all queues to find the next queue that is not empty.
+	 * Stop when you get back to curr_queue
+	 */
+	while (list_empty(&rd->row_queues[rd->curr_queue].rqueue.fifo)
+	       && rd->curr_queue != prev_curr_queue) {
+		/* Mark rqueue as unserved */
+		row_mark_rowq_unserved(rd, rd->curr_queue);
+		row_get_next_queue(rd);
+	}
+
+	return 1;
+}
+
+/*
+ * row_dispatch_requests() - selects the next request to dispatch
+ * @q:		requests queue
+ * @force:	ignored
+ *
+ * Return 0 if no requests were moved to the dispatch queue.
+ *	  1 otherwise
+ *
+ */
+static int row_dispatch_requests(struct request_queue *q, int force)
+{
+	struct row_data *rd = (struct row_data *)q->elevator->elevator_data;
+	int ret = 0, currq, i;
+
+	currq = rd->curr_queue;
+
+	/*
+	 * Find the first unserved queue (with higher priority then currq)
+	 * that is not empty
+	 */
+	for (i = 0; i < currq; i++) {
+		if (row_rowq_unserved(rd, i) &&
+		    !list_empty(&rd->row_queues[i].rqueue.fifo)) {
+			row_log_rowq(rd, currq,
+				" Preemting for unserved rowq%d", i);
+			rd->curr_queue = i;
+			row_dispatch_insert(rd);
+			ret = 1;
+			goto done;
+		}
+	}
+
+	if (rd->row_queues[currq].rqueue.nr_dispatched >=
+	    rd->row_queues[currq].disp_quantum) {
+		rd->row_queues[currq].rqueue.nr_dispatched = 0;
+		row_log_rowq(rd, currq, "Expiring rqueue");
+		ret = row_choose_queue(rd);
+		if (ret)
+			row_dispatch_insert(rd);
+		goto done;
+	}
+
+	/* Dispatch from curr_queue */
+	if (list_empty(&rd->row_queues[currq].rqueue.fifo)) {
+		/* check idling */
+		if (delayed_work_pending(&rd->read_idle.idle_work)) {
+			row_log_rowq(rd, currq,
+				     "Delayed work pending. Exiting");
+			goto done;
+		}
+
+		if (queue_idling_enabled[currq] &&
+		    rd->row_queues[currq].rqueue.idle_data.begin_idling) {
+			if (!queue_delayed_work(rd->read_idle.idle_workqueue,
+			    &rd->read_idle.idle_work,
+			    jiffies +
+			    msecs_to_jiffies(rd->read_idle.idle_time))) {
+				row_log_rowq(rd, currq,
+					     "Work already on queue!");
+				pr_err("ROW_BUG: Work already on queue!");
+			} else
+				row_log_rowq(rd, currq,
+				     "Scheduled delayed work. exiting");
+			goto done;
+		} else {
+			row_log_rowq(rd, currq,
+				     "Currq empty. Choose next queue");
+			ret = row_choose_queue(rd);
+			if (!ret)
+				goto done;
+		}
+	}
+
+	ret = 1;
+	row_dispatch_insert(rd);
+
+done:
+	return ret;
+}
+
+/*
+ * row_init_queue() - Init scheduler data structures
+ * @q:	requests queue
+ *
+ * Return pointer to struct row_data to be saved in elevator for
+ * this dispatch queue
+ *
+ */
+static void *row_init_queue(struct request_queue *q)
+{
+
+	struct row_data *rdata;
+	int i;
+
+	rdata = kmalloc_node(sizeof(*rdata),
+			     GFP_KERNEL | __GFP_ZERO, q->node);
+	if (!rdata)
+		return NULL;
+
+	for (i = 0; i < ROWQ_MAX_PRIO; i++) {
+		INIT_LIST_HEAD(&rdata->row_queues[i].rqueue.fifo);
+		rdata->row_queues[i].disp_quantum = queue_quantum[i];
+		rdata->row_queues[i].rqueue.rdata = rdata;
+		rdata->row_queues[i].rqueue.prio = i;
+		rdata->row_queues[i].rqueue.idle_data.begin_idling = false;
+	}
+
+	/*
+	 * Currently idling is enabled only for READ queues. If we want to
+	 * enable it for write queues also, note that idling frequency will
+	 * be the same in both cases
+	 */
+	rdata->read_idle.idle_time = ROW_IDLE_TIME;
+	rdata->read_idle.freq = ROW_READ_FREQ;
+	rdata->read_idle.idle_workqueue = alloc_workqueue("row_idle_work",
+					    WQ_MEM_RECLAIM | WQ_HIGHPRI, 0);
+	if (!rdata->read_idle.idle_workqueue)
+		panic("Failed to create idle workqueue\n");
+	INIT_DELAYED_WORK(&rdata->read_idle.idle_work, kick_queue);
+
+	rdata->curr_queue = ROWQ_PRIO_HIGH_READ;
+	rdata->dispatch_queue = q;
+
+	rdata->nr_reqs[READ] = rdata->nr_reqs[WRITE] = 0;
+
+	return rdata;
+}
+
+/*
+ * row_exit_queue() - called on unloading the RAW scheduler
+ * @e:	poiner to struct elevator_queue
+ *
+ */
+static void row_exit_queue(struct elevator_queue *e)
+{
+	struct row_data *rd = (struct row_data *)e->elevator_data;
+	int i;
+
+	for (i = 0; i < ROWQ_MAX_PRIO; i++)
+		BUG_ON(!list_empty(&rd->row_queues[i].rqueue.fifo));
+	(void)cancel_delayed_work_sync(&rd->read_idle.idle_work);
+	kfree(rd);
+}
+
+/*
+ * row_merged_requests() - Called when 2 requests are merged
+ * @q:		requests queue
+ * @rq:		request the two requests were merged into
+ * @next:	request that was merged
+ */
+static void row_merged_requests(struct request_queue *q, struct request *rq,
+				 struct request *next)
+{
+	struct row_queue   *rqueue = RQ_ROWQ(next);
+
+	list_del_init(&next->queuelist);
+
+	rqueue->rdata->nr_reqs[rq_data_dir(rq)]--;
+}
+
+/*
+ * get_queue_type() - Get queue type for a given request
+ *
+ * This is a helping function which purpose is to determine what
+ * ROW queue the given request should be added to (and
+ * dispatched from leter on)
+ *
+ * TODO: Right now only 3 queues are used REG_READ, REG_WRITE
+ * and REG_SWRITE
+ */
+static enum row_queue_prio get_queue_type(struct request *rq)
+{
+	const int data_dir = rq_data_dir(rq);
+	const bool is_sync = rq_is_sync(rq);
+
+	if (data_dir == READ)
+		return ROWQ_PRIO_REG_READ;
+	else if (is_sync)
+		return ROWQ_PRIO_REG_SWRITE;
+	else
+		return ROWQ_PRIO_REG_WRITE;
+}
+
+/*
+ * row_set_request() - Set ROW data structures associated with this request.
+ * @q:		requests queue
+ * @rq:		pointer to the request
+ * @gfp_mask:	ignored
+ *
+ */
+static int
+row_set_request(struct request_queue *q, struct request *rq, gfp_t gfp_mask)
+{
+	struct row_data *rd = (struct row_data *)q->elevator->elevator_data;
+	unsigned long flags;
+
+	spin_lock_irqsave(q->queue_lock, flags);
+	rq->elv.priv[0] =
+		(void *)(&rd->row_queues[get_queue_type(rq)]);
+	spin_unlock_irqrestore(q->queue_lock, flags);
+
+	return 0;
+}
+
+/********** Helping sysfs functions/defenitions for ROW attributes ******/
+static ssize_t row_var_show(int var, char *page)
+{
+	return snprintf(page, 100, "%d\n", var);
+}
+
+static ssize_t row_var_store(int *var, const char *page, size_t count)
+{
+	int err;
+	err = kstrtoul(page, 10, (unsigned long *)var);
+
+	return count;
+}
+
+#define SHOW_FUNCTION(__FUNC, __VAR, __CONV)				\
+static ssize_t __FUNC(struct elevator_queue *e, char *page)		\
+{									\
+	struct row_data *rowd = e->elevator_data;			\
+	int __data = __VAR;						\
+	if (__CONV)							\
+		__data = jiffies_to_msecs(__data);			\
+	return row_var_show(__data, (page));			\
+}
+SHOW_FUNCTION(row_hp_read_quantum_show,
+	rowd->row_queues[ROWQ_PRIO_HIGH_READ].disp_quantum, 0);
+SHOW_FUNCTION(row_rp_read_quantum_show,
+	rowd->row_queues[ROWQ_PRIO_REG_READ].disp_quantum, 0);
+SHOW_FUNCTION(row_hp_swrite_quantum_show,
+	rowd->row_queues[ROWQ_PRIO_HIGH_SWRITE].disp_quantum, 0);
+SHOW_FUNCTION(row_rp_swrite_quantum_show,
+	rowd->row_queues[ROWQ_PRIO_REG_SWRITE].disp_quantum, 0);
+SHOW_FUNCTION(row_rp_write_quantum_show,
+	rowd->row_queues[ROWQ_PRIO_REG_WRITE].disp_quantum, 0);
+SHOW_FUNCTION(row_lp_read_quantum_show,
+	rowd->row_queues[ROWQ_PRIO_LOW_READ].disp_quantum, 0);
+SHOW_FUNCTION(row_lp_swrite_quantum_show,
+	rowd->row_queues[ROWQ_PRIO_LOW_SWRITE].disp_quantum, 0);
+SHOW_FUNCTION(row_read_idle_show, rowd->read_idle.idle_time, 1);
+SHOW_FUNCTION(row_read_idle_freq_show, rowd->read_idle.freq, 1);
+#undef SHOW_FUNCTION
+
+#define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX, __CONV)			\
+static ssize_t __FUNC(struct elevator_queue *e,				\
+		const char *page, size_t count)				\
+{									\
+	struct row_data *rowd = e->elevator_data;			\
+	int __data;						\
+	int ret = row_var_store(&__data, (page), count);		\
+	if (__CONV)							\
+		__data = (int)msecs_to_jiffies(__data);			\
+	if (__data < (MIN))						\
+		__data = (MIN);						\
+	else if (__data > (MAX))					\
+		__data = (MAX);						\
+	*(__PTR) = __data;						\
+	return ret;							\
+}
+STORE_FUNCTION(row_hp_read_quantum_store,
+		&rowd->row_queues[ROWQ_PRIO_HIGH_READ].disp_quantum, 0,
+		INT_MAX, 0);
+STORE_FUNCTION(row_rp_read_quantum_store,
+		&rowd->row_queues[ROWQ_PRIO_REG_READ].disp_quantum, 0,
+		INT_MAX, 0);
+STORE_FUNCTION(row_hp_swrite_quantum_store,
+		&rowd->row_queues[ROWQ_PRIO_HIGH_SWRITE].disp_quantum, 0,
+		INT_MAX, 0);
+STORE_FUNCTION(row_rp_swrite_quantum_store,
+		&rowd->row_queues[ROWQ_PRIO_REG_SWRITE].disp_quantum, 0,
+		INT_MAX, 0);
+STORE_FUNCTION(row_rp_write_quantum_store,
+		&rowd->row_queues[ROWQ_PRIO_REG_WRITE].disp_quantum, 0,
+		INT_MAX, 0);
+STORE_FUNCTION(row_lp_read_quantum_store,
+		&rowd->row_queues[ROWQ_PRIO_LOW_READ].disp_quantum, 0,
+		INT_MAX, 0);
+STORE_FUNCTION(row_lp_swrite_quantum_store,
+		&rowd->row_queues[ROWQ_PRIO_LOW_SWRITE].disp_quantum, 0,
+		INT_MAX, 1);
+STORE_FUNCTION(row_read_idle_store, &rowd->read_idle.idle_time, 1, INT_MAX, 1);
+STORE_FUNCTION(row_read_idle_freq_store, &rowd->read_idle.freq,
+				1, INT_MAX, 1);
+
+#undef STORE_FUNCTION
+
+#define ROW_ATTR(name) \
+	__ATTR(name, S_IRUGO|S_IWUSR, row_##name##_show, \
+				      row_##name##_store)
+
+static struct elv_fs_entry row_attrs[] = {
+	ROW_ATTR(hp_read_quantum),
+	ROW_ATTR(rp_read_quantum),
+	ROW_ATTR(hp_swrite_quantum),
+	ROW_ATTR(rp_swrite_quantum),
+	ROW_ATTR(rp_write_quantum),
+	ROW_ATTR(lp_read_quantum),
+	ROW_ATTR(lp_swrite_quantum),
+	ROW_ATTR(read_idle),
+	ROW_ATTR(read_idle_freq),
+	__ATTR_NULL
+};
+
+static struct elevator_type iosched_row = {
+	.ops = {
+		.elevator_merge_req_fn		= row_merged_requests,
+		.elevator_dispatch_fn		= row_dispatch_requests,
+		.elevator_add_req_fn		= row_add_request,
+		.elevator_former_req_fn		= elv_rb_former_request,
+		.elevator_latter_req_fn		= elv_rb_latter_request,
+		.elevator_set_req_fn		= row_set_request,
+		.elevator_init_fn		= row_init_queue,
+		.elevator_exit_fn		= row_exit_queue,
+	},
+
+	.elevator_attrs = row_attrs,
+	.elevator_name = "row",
+	.elevator_owner = THIS_MODULE,
+};
+
+static int __init row_init(void)
+{
+	elv_register(&iosched_row);
+	return 0;
+}
+
+static void __exit row_exit(void)
+{
+	elv_unregister(&iosched_row);
+}
+
+module_init(row_init);
+module_exit(row_exit);
+
+MODULE_LICENSE("GPLv2");
+MODULE_DESCRIPTION("Read Over Write IO scheduler");
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 1c14859..b18d709 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -279,12 +279,14 @@
 	struct diag_request *write_ptr_mdm;
 	/* HSIC variables */
 	int hsic_ch;
+	int hsic_inited;
 	int hsic_device_enabled;
 	int hsic_device_opened;
 	int hsic_suspend;
 	int in_busy_hsic_read_on_device;
 	int in_busy_hsic_write;
 	struct work_struct diag_read_hsic_work;
+	struct mutex bridge_mutex;
 	/* USB MDM channel variables */
 	int usb_mdm_connected;
 	int read_len_mdm;
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index c827ec7..a669b45 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -1124,6 +1124,7 @@
 			driver->apps_rsp_buf[2] = 0x0;
 			driver->apps_rsp_buf[3] = 0x0;
 			*(int *)(driver->apps_rsp_buf + 4) = 0x0;
+			*(int *)(driver->apps_rsp_buf + 8) = 0x0; /* status */
 			if (driver->ch_cntl)
 				diag_send_log_mask_update(driver->ch_cntl,
 								 ALL_EQUIP_ID);
@@ -1133,7 +1134,7 @@
 			if (driver->ch_wcnss_cntl)
 				diag_send_log_mask_update(driver->ch_wcnss_cntl,
 								 ALL_EQUIP_ID);
-			ENCODE_RSP_AND_SEND(7);
+			ENCODE_RSP_AND_SEND(11);
 			return 0;
 		}
 #endif
diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c
index 52fd673..e417d5a 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.c
@@ -558,6 +558,7 @@
 
 	ret = scnprintf(buf, DEBUG_BUF_SIZE,
 		"hsic ch: %d\n"
+		"hsic_inited: %d\n"
 		"hsic enabled: %d\n"
 		"hsic_opened: %d\n"
 		"hsic_suspend: %d\n"
@@ -575,6 +576,7 @@
 		"diag_disconnect_work: %d\n"
 		"diag_usb_read_complete_work: %d\n",
 		driver->hsic_ch,
+		driver->hsic_inited,
 		driver->hsic_device_enabled,
 		driver->hsic_device_opened,
 		driver->hsic_suspend,
diff --git a/drivers/char/diag/diagfwd_hsic.c b/drivers/char/diag/diagfwd_hsic.c
index 3878a82..56f2fae 100644
--- a/drivers/char/diag/diagfwd_hsic.c
+++ b/drivers/char/diag/diagfwd_hsic.c
@@ -236,20 +236,20 @@
 	.resume = diag_hsic_resume,
 };
 
-static int diag_hsic_close(void)
+static void diag_hsic_close(void)
 {
 	if (driver->hsic_device_enabled) {
 		driver->hsic_ch = 0;
 		if (driver->hsic_device_opened) {
 			driver->hsic_device_opened = 0;
 			diag_bridge_close();
+			pr_debug("diag: %s: closed successfully\n", __func__);
+		} else {
+			pr_debug("diag: %s: already closed\n", __func__);
 		}
-		pr_debug("diag: in %s: closed successfully\n", __func__);
 	} else {
-		pr_debug("diag: in %s: already closed\n", __func__);
+		pr_debug("diag: %s: HSIC device already removed\n", __func__);
 	}
-
-	return 0;
 }
 
 /* diagfwd_cancel_hsic is called to cancel outstanding read/writes */
@@ -257,6 +257,7 @@
 {
 	int err;
 
+	mutex_lock(&driver->bridge_mutex);
 	if (driver->hsic_device_enabled) {
 		if (driver->hsic_device_opened) {
 			driver->hsic_ch = 0;
@@ -274,6 +275,7 @@
 		}
 	}
 
+	mutex_unlock(&driver->bridge_mutex);
 	return 0;
 }
 
@@ -284,6 +286,7 @@
 
 	pr_debug("diag: in %s\n", __func__);
 
+	mutex_lock(&driver->bridge_mutex);
 	/* If the usb cable is being connected */
 	if (process_cable) {
 		err = usb_diag_alloc_req(driver->mdm_ch, N_MDM_WRITE,
@@ -301,6 +304,7 @@
 	} else if (driver->diag_smux_enabled) {
 		driver->in_busy_smux = 0;
 		diagfwd_connect_smux();
+		mutex_unlock(&driver->bridge_mutex);
 		return 0;
 	}
 
@@ -323,22 +327,24 @@
 		 * Turn on communication over usb mdm and hsic, if the hsic
 		 * device driver is enabled and opened
 		 */
-		if (driver->hsic_device_opened)
+		if (driver->hsic_device_opened) {
 			driver->hsic_ch = 1;
 
-		/* Poll USB mdm channel to check for data */
-		if (driver->logging_mode == USB_MODE)
-			queue_work(driver->diag_bridge_wq,
-					&driver->diag_read_mdm_work);
+			/* Poll USB mdm channel to check for data */
+			if (driver->logging_mode == USB_MODE)
+				queue_work(driver->diag_bridge_wq,
+						&driver->diag_read_mdm_work);
 
-		/* Poll HSIC channel to check for data */
-		queue_work(driver->diag_bridge_wq,
-				 &driver->diag_read_hsic_work);
+			/* Poll HSIC channel to check for data */
+			queue_work(driver->diag_bridge_wq,
+					 &driver->diag_read_hsic_work);
+		}
 	} else {
 		/* The hsic device driver has not yet been enabled */
 		pr_info("diag: HSIC channel not yet enabled\n");
 	}
 
+	mutex_unlock(&driver->bridge_mutex);
 	return 0;
 }
 
@@ -350,6 +356,8 @@
 {
 	pr_debug("diag: In %s, process_cable: %d\n", __func__, process_cable);
 
+	mutex_lock(&driver->bridge_mutex);
+
 	/* If the usb cable is being disconnected */
 	if (process_cable) {
 		driver->usb_mdm_connected = 0;
@@ -361,7 +369,7 @@
 		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();
+		diag_hsic_close();
 	} else if (driver->diag_smux_enabled &&
 		driver->logging_mode == USB_MODE) {
 		driver->in_busy_smux = 1;
@@ -370,6 +378,8 @@
 		/* Turn off communication over usb mdm and smux */
 		msm_smux_close(LCID_VALID);
 	}
+
+	mutex_unlock(&driver->bridge_mutex);
 	return 0;
 }
 
@@ -551,13 +561,15 @@
 {
 	int err = 0;
 	pr_debug("diag: in %s\n", __func__);
-	if (!driver->hsic_device_enabled) {
+	if (!driver->hsic_inited) {
 		diagmem_hsic_init(driver);
 		INIT_WORK(&(driver->diag_read_hsic_work),
 					 diag_read_hsic_work_fn);
-		driver->hsic_device_enabled = 1;
+		driver->hsic_inited = 1;
 	}
 
+	mutex_lock(&driver->bridge_mutex);
+
 	/*
 	 * The probe function was called after the usb was connected
 	 * on the legacy channel OR ODL is turned on. Communication over usb
@@ -565,11 +577,17 @@
 	 */
 	if (driver->usb_mdm_connected || (driver->logging_mode ==
 							 MEMORY_DEVICE_MODE)) {
-		/* The hsic (diag_bridge) platform device driver is enabled */
+		if (driver->hsic_device_opened) {
+			/* should not happen. close it before re-opening */
+			pr_warn("diag: HSIC channel already opened in probe\n");
+			diag_bridge_close();
+		}
+
 		err = diag_bridge_open(&hsic_diag_bridge_ops);
 		if (err) {
 			pr_err("diag: could not open HSIC, err: %d\n", err);
 			driver->hsic_device_opened = 0;
+			mutex_unlock(&driver->bridge_mutex);
 			return err;
 		}
 
@@ -591,13 +609,19 @@
 				 &driver->diag_read_hsic_work);
 	}
 
+	/* The hsic (diag_bridge) platform device driver is enabled */
+	driver->hsic_device_enabled = 1;
+	mutex_unlock(&driver->bridge_mutex);
 	return err;
 }
 
 static int diag_hsic_remove(struct platform_device *pdev)
 {
 	pr_debug("diag: %s called\n", __func__);
+	mutex_lock(&driver->bridge_mutex);
 	diag_hsic_close();
+	driver->hsic_device_enabled = 0;
+	mutex_unlock(&driver->bridge_mutex);
 	return 0;
 }
 
@@ -670,6 +694,7 @@
 	driver->itemsize_hsic_write = sizeof(struct diag_request);
 	driver->poolsize_hsic_write = N_MDM_WRITE;
 
+	mutex_init(&driver->bridge_mutex);
 #ifdef CONFIG_DIAG_OVER_USB
 	INIT_WORK(&(driver->diag_read_mdm_work), diag_read_mdm_work_fn);
 #endif
@@ -713,8 +738,9 @@
 	if (driver->hsic_device_enabled) {
 		diag_hsic_close();
 		driver->hsic_device_enabled = 0;
-		diagmem_exit(driver, POOL_TYPE_ALL);
 	}
+	driver->hsic_inited = 0;
+	diagmem_exit(driver, POOL_TYPE_ALL);
 	if (driver->diag_smux_enabled) {
 		driver->lcid = LCID_INVALID;
 		kfree(driver->buf_in_smux);
diff --git a/drivers/char/diag/diagmem.c b/drivers/char/diag/diagmem.c
index 82c47af..1a522d5 100644
--- a/drivers/char/diag/diagmem.c
+++ b/drivers/char/diag/diagmem.c
@@ -106,7 +106,7 @@
 			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->diag_hsic_pool && (driver->hsic_inited == 0)) {
 		if (driver->count_hsic_pool == 0) {
 			mempool_destroy(driver->diag_hdlc_pool);
 			driver->diag_hdlc_pool = NULL;
@@ -114,8 +114,7 @@
 			pr_err("Unable to destroy HDLC mempool");
 	}
 
-	if (driver->diag_hsic_write_pool &&
-		(driver->hsic_device_enabled == 0)) {
+	if (driver->diag_hsic_write_pool && (driver->hsic_inited == 0)) {
 		/*
 		 * Free up struct pool ONLY if there are no outstanding
 		 * transactions(aggregation buffer) with USB
diff --git a/drivers/coresight/Kconfig b/drivers/coresight/Kconfig
index 1219af1..a23fff0 100644
--- a/drivers/coresight/Kconfig
+++ b/drivers/coresight/Kconfig
@@ -30,3 +30,12 @@
 
 	  For production builds, you should probably say 'N' here to avoid
 	  potential power, performance and memory penalty.
+
+config CONTROL_TRACE
+	tristate "Turn on to control tracing"
+	help
+	  Builds module to abort tracing on a user space data, instruction
+	  or prefetch abort.
+
+	  For production builds, you should probably say 'N' here to avoid
+	  potential power, performance and memory penalty.
diff --git a/drivers/coresight/Makefile b/drivers/coresight/Makefile
index 4ee93cf..a2815de 100644
--- a/drivers/coresight/Makefile
+++ b/drivers/coresight/Makefile
@@ -1,3 +1,3 @@
-
+obj-$(CONFIG_CONTROL_TRACE) += control_trace.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/control_trace.c b/drivers/coresight/control_trace.c
new file mode 100644
index 0000000..aa8bfc5
--- /dev/null
+++ b/drivers/coresight/control_trace.c
@@ -0,0 +1,71 @@
+/* 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.
+ */
+
+/*
+ * DLKM to register a callback with a ftrace event
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/tracepoint.h>
+#include <linux/coresight.h>
+
+#include <trace/events/exception.h>
+
+static void abort_coresight_tracing(void *ignore, struct task_struct *task,\
+					unsigned long addr, unsigned int fsr)
+{
+	coresight_abort();
+	pr_debug("control_trace: task_name: %s, addr: %lu, fsr:%u",\
+		(char *)task->comm, addr, fsr);
+}
+
+static void abort_tracing_undef_instr(void *ignore, struct pt_regs *regs,\
+					void *pc)
+{
+	if (user_mode(regs)) {
+		coresight_abort();
+		pr_debug("control_trace: pc: %p", pc);
+	}
+}
+
+static int __init control_trace_init(void)
+{
+	int ret_user_fault, ret_undef_instr;
+	ret_user_fault = register_trace_user_fault(abort_coresight_tracing,\
+							NULL);
+	ret_undef_instr = register_trace_undef_instr(abort_tracing_undef_instr,\
+							NULL);
+	if (ret_user_fault != 0 || ret_undef_instr != 0) {
+		pr_info("control_trace: Module Not Registered\n");
+		return (ret_user_fault < 0 ?\
+			ret_user_fault : ret_undef_instr);
+	}
+	pr_info("control_trace: Module Registered\n");
+	return 0;
+}
+
+module_init(control_trace_init);
+
+static void __exit control_trace_exit(void)
+{
+	unregister_trace_user_fault(abort_coresight_tracing, NULL);
+	unregister_trace_undef_instr(abort_tracing_undef_instr, NULL);
+	pr_info("control_trace: Module Removed\n");
+}
+
+module_exit(control_trace_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Kernel Module to abort tracing");
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 03fdc5a..c799c1f 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -556,7 +556,6 @@
 	  PMICs through RPC.
 
 config GPIO_QPNP_PIN
-	depends on ARCH_MSM8974
 	depends on SPMI
 	depends on OF_SPMI
 	depends on MSM_QPNP_INT
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index 98254b5..7f760ed 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -1391,8 +1391,10 @@
 				   sizeof(struct ion_fd_data)))
 			return -EFAULT;
 		data.handle = ion_import_dma_buf(client, data.fd);
-		if (IS_ERR(data.handle))
+		if (IS_ERR(data.handle)) {
+			ret = PTR_ERR(data.handle);
 			data.handle = NULL;
+		}
 		if (copy_to_user((void __user *)arg, &data,
 				 sizeof(struct ion_fd_data)))
 			return -EFAULT;
diff --git a/drivers/gpu/msm/Makefile b/drivers/gpu/msm/Makefile
index c7ed329..aacd355 100644
--- a/drivers/gpu/msm/Makefile
+++ b/drivers/gpu/msm/Makefile
@@ -17,6 +17,7 @@
 msm_kgsl_core-$(CONFIG_MSM_SCM) += kgsl_pwrscale_trustzone.o
 msm_kgsl_core-$(CONFIG_MSM_SLEEP_STATS_DEVICE) += kgsl_pwrscale_idlestats.o
 msm_kgsl_core-$(CONFIG_MSM_DCVS) += kgsl_pwrscale_msm.o
+msm_kgsl_core-$(CONFIG_SYNC) += kgsl_sync.o
 
 msm_adreno-y += \
 	adreno_ringbuffer.o \
diff --git a/drivers/gpu/msm/adreno_a2xx.c b/drivers/gpu/msm/adreno_a2xx.c
index 1f32e54..2388fff 100644
--- a/drivers/gpu/msm/adreno_a2xx.c
+++ b/drivers/gpu/msm/adreno_a2xx.c
@@ -1574,8 +1574,6 @@
 		return;
 	}
 
-	KGSL_CTXT_INFO(device, "context flags %08x\n", context->flags);
-
 	cmds[0] = cp_nop_packet(1);
 	cmds[1] = KGSL_CONTEXT_TO_MEM_IDENTIFIER;
 	cmds[2] = cp_type3_packet(CP_MEM_WRITE, 2);
@@ -1710,18 +1708,24 @@
 
 	if (status & CP_INT_CNTL__RB_INT_MASK) {
 		/* signal intr completion event */
-		unsigned int context_id;
-		kgsl_sharedmem_readl(&device->memstore,
-				&context_id,
+		unsigned int context_id, timestamp;
+		kgsl_sharedmem_readl(&device->memstore, &context_id,
 				KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
 					current_context));
+
+		kgsl_sharedmem_readl(&device->memstore, &timestamp,
+				KGSL_MEMSTORE_OFFSET(context_id,
+					eoptimestamp));
+
 		if (context_id < KGSL_MEMSTORE_MAX) {
 			kgsl_sharedmem_writel(&rb->device->memstore,
 					KGSL_MEMSTORE_OFFSET(context_id,
 						ts_cmp_enable), 0);
 			wmb();
 		}
-		KGSL_CMD_WARN(rb->device, "ringbuffer rb interrupt\n");
+
+		KGSL_CMD_WARN(device, "<%d:0x%x> ringbuffer interrupt\n",
+				context_id, timestamp);
 	}
 
 	for (i = 0; i < ARRAY_SIZE(kgsl_cp_error_irqs); i++) {
@@ -1743,7 +1747,6 @@
 	adreno_regwrite(device, REG_CP_INT_ACK, status);
 
 	if (status & (CP_INT_CNTL__IB1_INT_MASK | CP_INT_CNTL__RB_INT_MASK)) {
-		KGSL_CMD_WARN(rb->device, "ringbuffer ib1/rb interrupt\n");
 		queue_work(device->work_queue, &device->ts_expired_ws);
 		wake_up_interruptible_all(&device->wait_queue);
 		atomic_notifier_call_chain(&(device->ts_notifier_list),
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index d89e882..7bf928f 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -2409,8 +2409,6 @@
 		return;
 	}
 
-	KGSL_CTXT_INFO(device, "context flags %08x\n", context->flags);
-
 	cmds[0] = cp_nop_packet(1);
 	cmds[1] = KGSL_CONTEXT_TO_MEM_IDENTIFIER;
 	cmds[2] = cp_type3_packet(CP_MEM_WRITE, 2);
@@ -2565,17 +2563,24 @@
 	struct kgsl_device *device = &adreno_dev->dev;
 
 	if (irq == A3XX_INT_CP_RB_INT) {
-		unsigned int context_id;
+		unsigned int context_id, timestamp;
 		kgsl_sharedmem_readl(&device->memstore, &context_id,
 				KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
 					current_context));
+
+		kgsl_sharedmem_readl(&device->memstore, &timestamp,
+				KGSL_MEMSTORE_OFFSET(context_id,
+					eoptimestamp));
+
 		if (context_id < KGSL_MEMSTORE_MAX) {
 			kgsl_sharedmem_writel(&device->memstore,
 					KGSL_MEMSTORE_OFFSET(context_id,
 						ts_cmp_enable), 0);
 			wmb();
 		}
-		KGSL_CMD_WARN(device, "ringbuffer rb interrupt\n");
+
+		KGSL_CMD_WARN(device, "<%d:0x%x> ringbuffer interrupt\n",
+				context_id, timestamp);
 	}
 
 	wake_up_interruptible_all(&device->wait_queue);
@@ -2701,62 +2706,100 @@
 	return val;
 }
 
+struct a3xx_vbif_data {
+	unsigned int reg;
+	unsigned int val;
+};
+
+/* VBIF registers start after 0x3000 so use 0x0 as end of list marker */
+static struct a3xx_vbif_data a305_vbif[] = {
+	/* Set up 16 deep read/write request queues */
+	{ A3XX_VBIF_IN_RD_LIM_CONF0, 0x10101010 },
+	{ A3XX_VBIF_IN_RD_LIM_CONF1, 0x10101010 },
+	{ A3XX_VBIF_OUT_RD_LIM_CONF0, 0x10101010 },
+	{ A3XX_VBIF_OUT_WR_LIM_CONF0, 0x10101010 },
+	{ A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303 },
+	{ A3XX_VBIF_IN_WR_LIM_CONF0, 0x10101010 },
+	{ A3XX_VBIF_IN_WR_LIM_CONF1, 0x10101010 },
+	/* Enable WR-REQ */
+	{ A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x0000FF },
+	/* Set up round robin arbitration between both AXI ports */
+	{ A3XX_VBIF_ARB_CTL, 0x00000030 },
+	/* Set up AOOO */
+	{ A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000003C },
+	{ A3XX_VBIF_OUT_AXI_AOOO, 0x003C003C },
+	{0, 0},
+};
+
+static struct a3xx_vbif_data a320_vbif[] = {
+	/* Set up 16 deep read/write request queues */
+	{ A3XX_VBIF_IN_RD_LIM_CONF0, 0x10101010 },
+	{ A3XX_VBIF_IN_RD_LIM_CONF1, 0x10101010 },
+	{ A3XX_VBIF_OUT_RD_LIM_CONF0, 0x10101010 },
+	{ A3XX_VBIF_OUT_WR_LIM_CONF0, 0x10101010 },
+	{ A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303 },
+	{ A3XX_VBIF_IN_WR_LIM_CONF0, 0x10101010 },
+	{ A3XX_VBIF_IN_WR_LIM_CONF1, 0x10101010 },
+	/* Enable WR-REQ */
+	{ A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x0000FF },
+	/* Set up round robin arbitration between both AXI ports */
+	{ A3XX_VBIF_ARB_CTL, 0x00000030 },
+	/* Set up AOOO */
+	{ A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000003C },
+	{ A3XX_VBIF_OUT_AXI_AOOO, 0x003C003C },
+	/* Enable 1K sort */
+	{ A3XX_VBIF_ABIT_SORT, 0x000000FF },
+	{ A3XX_VBIF_ABIT_SORT_CONF, 0x000000A4 },
+	{0, 0},
+};
+
+static struct a3xx_vbif_data a330_vbif[] = {
+	/* Set up 16 deep read/write request queues */
+	{ A3XX_VBIF_IN_RD_LIM_CONF0, 0x18181818 },
+	{ A3XX_VBIF_IN_RD_LIM_CONF1, 0x18181818 },
+	{ A3XX_VBIF_OUT_RD_LIM_CONF0, 0x18181818 },
+	{ A3XX_VBIF_OUT_WR_LIM_CONF0, 0x18181818 },
+	{ A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303 },
+	{ A3XX_VBIF_IN_WR_LIM_CONF0, 0x18181818 },
+	{ A3XX_VBIF_IN_WR_LIM_CONF1, 0x18181818 },
+	/* Enable WR-REQ */
+	{ A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x00003F },
+	/* Set up round robin arbitration between both AXI ports */
+	{ A3XX_VBIF_ARB_CTL, 0x00000030 },
+	/* Set up VBIF_ROUND_ROBIN_QOS_ARB */
+	{ A3XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x0001 },
+	/* Set up AOOO */
+	{ A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000FFFF },
+	{ A3XX_VBIF_OUT_AXI_AOOO, 0xFFFFFFFF },
+	/* Enable 1K sort */
+	{ A3XX_VBIF_ABIT_SORT, 0x1FFFF },
+	{ A3XX_VBIF_ABIT_SORT_CONF, 0x000000A4 },
+	/* Disable VBIF clock gating. This is to enable AXI running
+	 * higher frequency than GPU.
+	 */
+	{ A3XX_VBIF_CLKON, 1 },
+	{0, 0},
+};
+
 static void a3xx_start(struct adreno_device *adreno_dev)
 {
 	struct kgsl_device *device = &adreno_dev->dev;
+	struct a3xx_vbif_data *vbif = NULL;
 
-	/* Set up 16 deep read/write request queues */
-	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, 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, 0x18181818);
-		/* Enable WR-REQ */
-		adreno_regwrite(device, A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x00003F);
+	if (adreno_is_a305(adreno_dev))
+		vbif = a305_vbif;
+	else if (adreno_is_a320(adreno_dev))
+		vbif = a320_vbif;
+	else if (adreno_is_a330(adreno_dev))
+		vbif = a330_vbif;
 
-		/* Set up round robin arbitration between both AXI ports */
-		adreno_regwrite(device, A3XX_VBIF_ARB_CTL, 0x00000030);
-		/* Set up VBIF_ROUND_ROBIN_QOS_ARB */
-		adreno_regwrite(device, A3XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x0001);
+	BUG_ON(vbif == NULL);
 
-		/* Set up AOOO */
-		adreno_regwrite(device, A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000FFFF);
-		adreno_regwrite(device, A3XX_VBIF_OUT_AXI_AOOO, 0xFFFFFFFF);
-
-		/* 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);
-		adreno_regwrite(device, A3XX_VBIF_OUT_RD_LIM_CONF0, 0x10101010);
-		adreno_regwrite(device, A3XX_VBIF_OUT_WR_LIM_CONF0, 0x10101010);
-		adreno_regwrite(device, A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303);
-		adreno_regwrite(device, A3XX_VBIF_IN_WR_LIM_CONF0, 0x10101010);
-		adreno_regwrite(device, A3XX_VBIF_IN_WR_LIM_CONF1, 0x10101010);
-		/* Enable WR-REQ */
-		adreno_regwrite(device, A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x0000FF);
-
-		/* Set up round robin arbitration between both AXI ports */
-		adreno_regwrite(device, A3XX_VBIF_ARB_CTL, 0x00000030);
-		/* Set up AOOO */
-		adreno_regwrite(device, A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000003C);
-		adreno_regwrite(device, A3XX_VBIF_OUT_AXI_AOOO, 0x003C003C);
+	while (vbif->reg != 0) {
+		adreno_regwrite(device, vbif->reg, vbif->val);
+		vbif++;
 	}
 
-	if (cpu_is_apq8064()) {
-		/* Enable 1K sort */
-		adreno_regwrite(device, A3XX_VBIF_ABIT_SORT, 0x000000FF);
-		adreno_regwrite(device, A3XX_VBIF_ABIT_SORT_CONF, 0x000000A4);
-	}
 	/* Make all blocks contribute to the GPU BUSY perf counter */
 	adreno_regwrite(device, A3XX_RBBM_GPU_BUSY_MASKED, 0xFFFFFFFF);
 
diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c
index b51342f..70ad81c 100644
--- a/drivers/gpu/msm/adreno_drawctxt.c
+++ b/drivers/gpu/msm/adreno_drawctxt.c
@@ -288,8 +288,10 @@
 		return;
 	}
 
-	KGSL_CTXT_INFO(device, "from %p to %p flags %d\n",
-			adreno_dev->drawctxt_active, drawctxt, flags);
+	KGSL_CTXT_INFO(device, "from %d to %d flags %d\n",
+		adreno_dev->drawctxt_active ?
+		adreno_dev->drawctxt_active->id : 0,
+		drawctxt ? drawctxt->id : 0, flags);
 
 	/* Save the old context */
 	adreno_dev->gpudev->ctxt_save(adreno_dev, adreno_dev->drawctxt_active);
diff --git a/drivers/gpu/msm/adreno_postmortem.c b/drivers/gpu/msm/adreno_postmortem.c
index 620b82c..daa78ed 100644
--- a/drivers/gpu/msm/adreno_postmortem.c
+++ b/drivers/gpu/msm/adreno_postmortem.c
@@ -50,6 +50,7 @@
 	{CP_DRAW_INDX,			"DRW_NDX_"},
 	{CP_DRAW_INDX_BIN,		"DRW_NDXB"},
 	{CP_EVENT_WRITE,		"EVENT_WT"},
+	{CP_MEM_WRITE,			"MEM_WRIT"},
 	{CP_IM_LOAD,			"IN__LOAD"},
 	{CP_IM_LOAD_IMMEDIATE,		"IM_LOADI"},
 	{CP_IM_STORE,			"IM_STORE"},
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index db913a5..1ff219b 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -969,8 +969,8 @@
 					drawctxt, 0,
 					&link[0], (cmds - link));
 
-	KGSL_CMD_INFO(device, "ctxt %d g %08x numibs %d ts %d\n",
-		context->id, (unsigned int)ibdesc, numibs, *timestamp);
+	KGSL_CMD_INFO(device, "<%d:0x%x> g %08x numibs %d\n",
+		context->id, *timestamp, (unsigned int)ibdesc, numibs);
 
 	kfree(link);
 
diff --git a/drivers/gpu/msm/adreno_snapshot.c b/drivers/gpu/msm/adreno_snapshot.c
index 08a01b0..93be980 100644
--- a/drivers/gpu/msm/adreno_snapshot.c
+++ b/drivers/gpu/msm/adreno_snapshot.c
@@ -328,8 +328,8 @@
 		ret = kgsl_snapshot_get_object(device, ptbase,
 				sp_vs_pvt_mem_addr, 8192,
 				SNAPSHOT_GPU_OBJECT_GENERIC);
-
 		snapshot_frozen_objsize += ret;
+		sp_vs_pvt_mem_addr = 0;
 	}
 
 	if (sp_fs_pvt_mem_addr) {
@@ -337,6 +337,7 @@
 				sp_fs_pvt_mem_addr, 8192,
 				SNAPSHOT_GPU_OBJECT_GENERIC);
 		snapshot_frozen_objsize += ret;
+		sp_fs_pvt_mem_addr = 0;
 	}
 
 	/* Finally: VBOs */
@@ -359,7 +360,13 @@
 				0, SNAPSHOT_GPU_OBJECT_GENERIC);
 			snapshot_frozen_objsize += ret;
 		}
+
+		vbo[i].base = 0;
+		vbo[i].stride = 0;
 	}
+
+	vfd_control_0 = 0;
+	vfd_index_max = 0;
 }
 
 /*
@@ -473,21 +480,33 @@
 		unsigned int gpuaddr, unsigned int dwords)
 {
 	int i, ret, rem = dwords;
-	unsigned int *src = (unsigned int *) adreno_convertaddr(device, ptbase,
-		gpuaddr, dwords << 2);
+	unsigned int *src;
+
+	/*
+	 * If the object is already in the list, we don't need to parse it again
+	 */
+
+	if (kgsl_snapshot_have_object(device, ptbase, gpuaddr, dwords << 2))
+		return;
+
+	src = (unsigned int *) adreno_convertaddr(device, ptbase, gpuaddr,
+		dwords << 2);
 
 	if (src == NULL)
 		return;
 
-	for (i = 0; rem != 0; rem--, i++) {
+	for (i = 0; rem > 0; rem--, i++) {
 		int pktsize;
 
+		/* If the packet isn't a type 1 or a type 3, then don't bother
+		 * parsing it - it is likely corrupted */
+
 		if (!pkt_is_type0(src[i]) && !pkt_is_type3(src[i]))
-			continue;
+			break;
 
 		pktsize = type3_pkt_size(src[i]);
 
-		if ((pktsize + 1) > rem)
+		if (!pktsize || (pktsize + 1) > rem)
 			break;
 
 		if (pkt_is_type3(src[i])) {
@@ -650,27 +669,11 @@
 		*data = rbptr[index];
 
 		/*
-		 * Sometimes the rptr is located in the middle of a packet.
-		 * try to adust for that by modifying the rptr to match a
-		 * packet boundary. Unfortunately for us, it is hard to tell
-		 * which dwords are legitimate type0 header and which are just
-		 * random data so only do the adjustments for type3 packets
-		 */
-
-		if (pkt_is_type3(rbptr[index])) {
-			unsigned int pktsize =
-				type3_pkt_size(rbptr[index]);
-			if (index +  pktsize > rptr)
-				rptr = (index + pktsize) %
-					rb->sizedwords;
-		}
-
-		/*
 		 * Only parse IBs between the start and the rptr or the next
 		 * context switch, whichever comes first
 		 */
 
-		if (index == ib_parse_start)
+		if (parse_ibs == 0 && index == ib_parse_start)
 			parse_ibs = 1;
 		else if (index == rptr || adreno_rb_ctxtswitch(&rbptr[index]))
 			parse_ibs = 0;
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index f630f2a..5904abb 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -36,6 +36,7 @@
 #include "kgsl_sharedmem.h"
 #include "kgsl_device.h"
 #include "kgsl_trace.h"
+#include "kgsl_sync.h"
 
 #undef MODULE_PARAM_PREFIX
 #define MODULE_PARAM_PREFIX "kgsl."
@@ -368,6 +369,12 @@
 	context->id = id;
 	context->dev_priv = dev_priv;
 
+	if (kgsl_sync_timeline_create(context)) {
+		idr_remove(&dev_priv->device->context_idr, id);
+		kfree(context);
+		return NULL;
+	}
+
 	return context;
 }
 
@@ -412,6 +419,7 @@
 {
 	struct kgsl_context *context = container_of(kref, struct kgsl_context,
 						    refcount);
+	kgsl_sync_timeline_destroy(context);
 	kfree(context);
 }
 
@@ -1107,9 +1115,6 @@
 	}
 
 	if (param->flags & KGSL_CONTEXT_SUBMIT_IB_LIST) {
-		KGSL_DRV_INFO(dev_priv->device,
-			"Using IB list mode for ib submission, numibs: %d\n",
-			param->numibs);
 		if (!param->numibs) {
 			KGSL_DRV_ERR(dev_priv->device,
 				"Invalid numibs as parameter: %d\n",
@@ -1438,42 +1443,43 @@
 	if (ret)
 		return ret;
 
-	if (phys == 0) {
-		ret = -EINVAL;
+	ret = -ERANGE;
+
+	if (phys == 0)
+		goto err;
+
+	/* Make sure the length of the region, the offset and the desired
+	 * size are all page aligned or bail
+	 */
+	if ((len & ~PAGE_MASK) ||
+		(offset & ~PAGE_MASK) ||
+		(size & ~PAGE_MASK)) {
+		KGSL_CORE_ERR("length offset or size is not page aligned\n");
 		goto err;
 	}
 
-	if (offset >= len) {
-		ret = -EINVAL;
+	/* The size or offset can never be greater than the PMEM length */
+	if (offset >= len || size > len)
 		goto err;
-	}
 
+	/* If size is 0, then adjust it to default to the size of the region
+	 * minus the offset.  If size isn't zero, then make sure that it will
+	 * fit inside of the region.
+	 */
 	if (size == 0)
-		size = len;
+		size = len - offset;
 
-	/* Adjust the size of the region to account for the offset */
-	size += offset & ~PAGE_MASK;
-
-	size = ALIGN(size, PAGE_SIZE);
-
-	if (_check_region(offset & PAGE_MASK, size, len)) {
-		KGSL_CORE_ERR("Offset (%ld) + size (%d) is larger"
-			      "than pmem region length %ld\n",
-			      offset & PAGE_MASK, size, len);
-		ret = -EINVAL;
+	else if (_check_region(offset, size, len))
 		goto err;
 
-	}
-
 	entry->priv_data = filep;
 
 	entry->memdesc.pagetable = pagetable;
 	entry->memdesc.size = size;
-	entry->memdesc.physaddr = phys + (offset & PAGE_MASK);
-	entry->memdesc.hostptr = (void *) (virt + (offset & PAGE_MASK));
+	entry->memdesc.physaddr = phys + offset;
+	entry->memdesc.hostptr = (void *) (virt + offset);
 
-	ret = memdesc_sg_phys(&entry->memdesc,
-		phys + (offset & PAGE_MASK), size);
+	ret = memdesc_sg_phys(&entry->memdesc, phys + offset, size);
 	if (ret)
 		goto err;
 
@@ -2019,6 +2025,11 @@
 			param->context_id, param->timestamp, param->priv,
 			param->len, dev_priv);
 		break;
+	case KGSL_TIMESTAMP_EVENT_FENCE:
+		ret = kgsl_add_fence_event(dev_priv->device,
+			param->context_id, param->timestamp, param->priv,
+			param->len, dev_priv);
+		break;
 	default:
 		ret = -EINVAL;
 	}
@@ -2095,6 +2106,8 @@
 		cmd = IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP;
 	else if (cmd == IOCTL_KGSL_CMDSTREAM_READTIMESTAMP_OLD)
 		cmd = IOCTL_KGSL_CMDSTREAM_READTIMESTAMP;
+	else if (cmd == IOCTL_KGSL_TIMESTAMP_EVENT_OLD)
+		cmd = IOCTL_KGSL_TIMESTAMP_EVENT;
 
 	nr = _IOC_NR(cmd);
 
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 2a2e916..2ca3a4f 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -22,6 +22,7 @@
 #include "kgsl_pwrctrl.h"
 #include "kgsl_log.h"
 #include "kgsl_pwrscale.h"
+#include <linux/sync.h>
 
 #define KGSL_TIMEOUT_NONE       0
 #define KGSL_TIMEOUT_DEFAULT    0xFFFFFFFF
@@ -236,6 +237,12 @@
 	 * context was responsible for causing it
 	 */
 	unsigned int reset_status;
+
+	/*
+	 * Timeline used to create fences that can be signaled when a
+	 * sync_pt timestamp expires.
+	 */
+	struct sync_timeline *timeline;
 };
 
 struct kgsl_process_private {
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index dee889d..0e1e100 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -320,7 +320,7 @@
 	if (KGSL_MMU_TYPE_GPU == kgsl_mmu_type)
 		return CONFIG_MSM_KGSL_PAGE_TABLE_SIZE;
 	else if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_type)
-		return SZ_2G;
+		return SZ_2G - KGSL_PAGETABLE_BASE;
 	else
 		return 0;
 }
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index a2ab5b1..0bfcfd8 100644
--- a/drivers/gpu/msm/kgsl_snapshot.c
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -289,6 +289,32 @@
 	kfree(obj);
 }
 
+/* ksgl_snapshot_have_object - Return 1 if the object has been processed
+ *@device - the device that is being snapshotted
+ * @ptbase - the pagetable base of the object to freeze
+ * @gpuaddr - The gpu address of the object to freeze
+ * @size - the size of the object (may not always be the size of the region)
+ *
+ * Return 1 if the object is already in the list - this can save us from
+ * having to parse the sme thing over again.
+*/
+int kgsl_snapshot_have_object(struct kgsl_device *device, unsigned int ptbase,
+	unsigned int gpuaddr, unsigned int size)
+{
+	struct kgsl_snapshot_object *obj;
+
+	list_for_each_entry(obj, &device->snapshot_obj_list, node) {
+		if (obj->ptbase != ptbase)
+			continue;
+
+		if ((gpuaddr >= obj->gpuaddr) &&
+			((gpuaddr + size) <= (obj->gpuaddr + obj->size)))
+			return 1;
+	}
+
+	return 0;
+}
+
 /* kgsl_snapshot_get_object - Mark a GPU buffer to be frozen
  * @device - the device that is being snapshotted
  * @ptbase - the pagetable base of the object to freeze
diff --git a/drivers/gpu/msm/kgsl_snapshot.h b/drivers/gpu/msm/kgsl_snapshot.h
index 6d81bcf..bc29863 100644
--- a/drivers/gpu/msm/kgsl_snapshot.h
+++ b/drivers/gpu/msm/kgsl_snapshot.h
@@ -311,5 +311,8 @@
 int kgsl_snapshot_get_object(struct kgsl_device *device, unsigned int ptbase,
 	unsigned int gpuaddr, unsigned int size, unsigned int type);
 
+int kgsl_snapshot_have_object(struct kgsl_device *device, unsigned int ptbase,
+	unsigned int gpuaddr, unsigned int size);
+
 #endif
 #endif
diff --git a/drivers/gpu/msm/kgsl_sync.c b/drivers/gpu/msm/kgsl_sync.c
new file mode 100644
index 0000000..a2dfe3b
--- /dev/null
+++ b/drivers/gpu/msm/kgsl_sync.c
@@ -0,0 +1,214 @@
+/* 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/file.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+#include "kgsl_sync.h"
+
+struct sync_pt *kgsl_sync_pt_create(struct sync_timeline *timeline,
+	unsigned int timestamp)
+{
+	struct sync_pt *pt;
+	pt = sync_pt_create(timeline, (int) sizeof(struct kgsl_sync_pt));
+	if (pt) {
+		struct kgsl_sync_pt *kpt = (struct kgsl_sync_pt *) pt;
+		kpt->timestamp = timestamp;
+	}
+	return pt;
+}
+
+/*
+ * This should only be called on sync_pts which have been created but
+ * not added to a fence.
+ */
+void kgsl_sync_pt_destroy(struct sync_pt *pt)
+{
+	sync_pt_free(pt);
+}
+
+static struct sync_pt *kgsl_sync_pt_dup(struct sync_pt *pt)
+{
+	struct kgsl_sync_pt *kpt = (struct kgsl_sync_pt *) pt;
+	return kgsl_sync_pt_create(pt->parent, kpt->timestamp);
+}
+
+static int kgsl_sync_pt_has_signaled(struct sync_pt *pt)
+{
+	struct kgsl_sync_pt *kpt = (struct kgsl_sync_pt *) pt;
+	struct kgsl_sync_timeline *ktimeline =
+		 (struct kgsl_sync_timeline *) pt->parent;
+	unsigned int ts = kpt->timestamp;
+	unsigned int last_ts = ktimeline->last_timestamp;
+	if (timestamp_cmp(last_ts, ts) >= 0) {
+		/* signaled */
+		return 1;
+	}
+	return 0;
+}
+
+static int kgsl_sync_pt_compare(struct sync_pt *a, struct sync_pt *b)
+{
+	struct kgsl_sync_pt *kpt_a = (struct kgsl_sync_pt *) a;
+	struct kgsl_sync_pt *kpt_b = (struct kgsl_sync_pt *) b;
+	unsigned int ts_a = kpt_a->timestamp;
+	unsigned int ts_b = kpt_b->timestamp;
+	return timestamp_cmp(ts_a, ts_b);
+}
+
+struct kgsl_fence_event_priv {
+	struct kgsl_context *context;
+};
+
+/**
+ * kgsl_fence_event_cb - Event callback for a fence timestamp event
+ * @device - The KGSL device that expired the timestamp
+ * @priv - private data for the event
+ * @context_id - the context id that goes with the timestamp
+ * @timestamp - the timestamp that triggered the event
+ *
+ * Signal a fence following the expiration of a timestamp
+ */
+
+static inline void kgsl_fence_event_cb(struct kgsl_device *device,
+	void *priv, u32 context_id, u32 timestamp)
+{
+	struct kgsl_fence_event_priv *ev = priv;
+	kgsl_sync_timeline_signal(ev->context->timeline, timestamp);
+	kgsl_context_put(ev->context);
+	kfree(ev);
+}
+
+/**
+ * kgsl_add_fence_event - Create a new fence event
+ * @device - KGSL device to create the event on
+ * @timestamp - Timestamp to trigger the event
+ * @data - Return fence fd stored in struct kgsl_timestamp_event_fence
+ * @len - length of the fence event
+ * @owner - driver instance that owns this event
+ * @returns 0 on success or error code on error
+ *
+ * Create a fence and register an event to signal the fence when
+ * the timestamp expires
+ */
+
+int kgsl_add_fence_event(struct kgsl_device *device,
+	u32 context_id, u32 timestamp, void __user *data, int len,
+	struct kgsl_device_private *owner)
+{
+	struct kgsl_fence_event_priv *event;
+	struct kgsl_timestamp_event_fence priv;
+	struct kgsl_context *context;
+	struct sync_pt *pt;
+	struct sync_fence *fence = NULL;
+	int ret = -EINVAL;
+
+	if (len != sizeof(priv))
+		return -EINVAL;
+
+	context = kgsl_find_context(owner, context_id);
+	if (context == NULL)
+		return -EINVAL;
+
+	event = kzalloc(sizeof(*event), GFP_KERNEL);
+	if (event == NULL)
+		return -ENOMEM;
+	event->context = context;
+	kgsl_context_get(context);
+
+	pt = kgsl_sync_pt_create(context->timeline, timestamp);
+	if (pt == NULL) {
+		KGSL_DRV_ERR(device, "kgsl_sync_pt_create failed\n");
+		ret = -ENOMEM;
+		goto fail_pt;
+	}
+
+	fence = sync_fence_create("kgsl-fence", pt);
+	if (fence == NULL) {
+		/* only destroy pt when not added to fence */
+		kgsl_sync_pt_destroy(pt);
+		KGSL_DRV_ERR(device, "sync_fence_create failed\n");
+		ret = -ENOMEM;
+		goto fail_fence;
+	}
+
+	priv.fence_fd = get_unused_fd_flags(0);
+	if (priv.fence_fd < 0) {
+		KGSL_DRV_ERR(device, "invalid fence fd\n");
+		ret = -EINVAL;
+		goto fail_fd;
+	}
+	sync_fence_install(fence, priv.fence_fd);
+
+	if (copy_to_user(data, &priv, sizeof(priv))) {
+		ret = -EFAULT;
+		goto fail_copy_fd;
+	}
+
+	ret = kgsl_add_event(device, context_id, timestamp,
+			kgsl_fence_event_cb, event, owner);
+	if (ret)
+		goto fail_event;
+
+	return 0;
+
+fail_event:
+fail_copy_fd:
+	/* clean up sync_fence_install */
+	sync_fence_put(fence);
+	put_unused_fd(priv.fence_fd);
+fail_fd:
+	/* clean up sync_fence_create */
+	sync_fence_put(fence);
+fail_fence:
+fail_pt:
+	kgsl_context_put(context);
+	kfree(event);
+	return ret;
+}
+
+static const struct sync_timeline_ops kgsl_sync_timeline_ops = {
+	.dup = kgsl_sync_pt_dup,
+	.has_signaled = kgsl_sync_pt_has_signaled,
+	.compare = kgsl_sync_pt_compare,
+};
+
+int kgsl_sync_timeline_create(struct kgsl_context *context)
+{
+	struct kgsl_sync_timeline *ktimeline;
+
+	context->timeline = sync_timeline_create(&kgsl_sync_timeline_ops,
+		(int) sizeof(struct kgsl_sync_timeline), "kgsl-timeline");
+	if (context->timeline == NULL)
+		return -EINVAL;
+
+	ktimeline = (struct kgsl_sync_timeline *) context->timeline;
+	ktimeline->last_timestamp = 0;
+
+	return 0;
+}
+
+void kgsl_sync_timeline_signal(struct sync_timeline *timeline,
+	unsigned int timestamp)
+{
+	struct kgsl_sync_timeline *ktimeline =
+		(struct kgsl_sync_timeline *) timeline;
+	ktimeline->last_timestamp = timestamp;
+	sync_timeline_signal(timeline);
+}
+
+void kgsl_sync_timeline_destroy(struct kgsl_context *context)
+{
+	sync_timeline_destroy(context->timeline);
+}
diff --git a/drivers/gpu/msm/kgsl_sync.h b/drivers/gpu/msm/kgsl_sync.h
new file mode 100644
index 0000000..06b3ad0
--- /dev/null
+++ b/drivers/gpu/msm/kgsl_sync.h
@@ -0,0 +1,75 @@
+/* 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 __KGSL_SYNC_H
+#define __KGSL_SYNC_H
+
+#include <linux/sync.h>
+#include "kgsl_device.h"
+
+struct kgsl_sync_timeline {
+	struct sync_timeline timeline;
+	unsigned int last_timestamp;
+};
+
+struct kgsl_sync_pt {
+	struct sync_pt pt;
+	unsigned int timestamp;
+};
+
+#if defined(CONFIG_SYNC)
+struct sync_pt *kgsl_sync_pt_create(struct sync_timeline *timeline,
+	unsigned int timestamp);
+void kgsl_sync_pt_destroy(struct sync_pt *pt);
+int kgsl_add_fence_event(struct kgsl_device *device,
+	u32 context_id, u32 timestamp, void __user *data, int len,
+	struct kgsl_device_private *owner);
+int kgsl_sync_timeline_create(struct kgsl_context *context);
+void kgsl_sync_timeline_signal(struct sync_timeline *timeline,
+	unsigned int timestamp);
+void kgsl_sync_timeline_destroy(struct kgsl_context *context);
+#else
+static inline struct sync_pt
+*kgsl_sync_pt_create(struct sync_timeline *timeline, unsigned int timestamp)
+{
+	return NULL;
+}
+
+static inline void kgsl_sync_pt_destroy(struct sync_pt *pt)
+{
+}
+
+static inline int kgsl_add_fence_event(struct kgsl_device *device,
+	u32 context_id, u32 timestamp, void __user *data, int len,
+	struct kgsl_device_private *owner)
+{
+	return -EINVAL;
+}
+
+static int kgsl_sync_timeline_create(struct kgsl_context *context)
+{
+	context->timeline = NULL;
+	return 0;
+}
+
+static inline void
+kgsl_sync_timeline_signal(struct sync_timeline *timeline,
+	unsigned int timestamp)
+{
+}
+
+static inline void kgsl_sync_timeline_destroy(struct kgsl_context *context)
+{
+}
+#endif
+
+#endif /* __KGSL_SYNC_H */
diff --git a/drivers/hwmon/epm_adc.c b/drivers/hwmon/epm_adc.c
index 3969319..56b8841 100644
--- a/drivers/hwmon/epm_adc.c
+++ b/drivers/hwmon/epm_adc.c
@@ -102,8 +102,6 @@
 #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;
 	struct device			*hwmon;
@@ -172,14 +170,6 @@
 {
 	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) {
@@ -521,27 +511,27 @@
 	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;
-	int64_t *adc_scaled_data = 0;
+	int64_t adc_scaled_data = 0;
 
 	/* Get the channel number */
 	channel_num = (adc_raw_data[0] & EPM_ADC_ADS_CHANNEL_DATA_CHID);
 	sign_bit    = 1;
 	/* This is the 16-bit raw data */
-	*adc_scaled_data = ((adc_raw_data[1] << 8) | adc_raw_data[2]);
+	adc_scaled_data = ((adc_raw_data[1] << 8) | adc_raw_data[2]);
 	/* Obtain the internal system reading */
 	if (channel_num == EPM_ADC_ADS_CHANNEL_VCC) {
-		*adc_scaled_data *= EPM_ADC_SCALE_MILLI;
-		do_div(*adc_scaled_data, EPM_ADC_SCALE_CODE_VOLTS);
+		adc_scaled_data *= EPM_ADC_SCALE_MILLI;
+		do_div(adc_scaled_data, EPM_ADC_SCALE_CODE_VOLTS);
 	} else if (channel_num == EPM_ADC_ADS_CHANNEL_GAIN) {
-		do_div(*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;
-		do_div(*adc_scaled_data, EPM_ADC_SCALE_CODE_VOLTS);
+		adc_scaled_data *= EPM_ADC_SCALE_MILLI;
+		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;
-		do_div(*adc_scaled_data, EPM_ADC_TEMP_SENSOR_COEFF);
+		adc_scaled_data -= EPM_ADC_TEMP_TO_DEGC_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__);
@@ -553,31 +543,31 @@
 		 * 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) {
+		if (adc_scaled_data & EPM_ADC_MAX_NEGATIVE_SCALE_CODE) {
 			sign_bit = -1;
-			*adc_scaled_data = (~*adc_scaled_data
+			adc_scaled_data = (~adc_scaled_data
 				& EPM_ADC_NEG_LSB_CODE);
 		}
-		if (*adc_scaled_data != 0) {
-			*adc_scaled_data *= EPM_ADC_SCALE_FACTOR;
+		if (adc_scaled_data != 0) {
+			adc_scaled_data *= EPM_ADC_SCALE_FACTOR;
 			 /* Device is calibrated for 1LSB = VREF/7800h.*/
-			*adc_scaled_data *= EPM_ADC_MILLI_VOLTS_SOURCE;
-			do_div(*adc_scaled_data, EPM_ADC_VREF_CODE);
+			adc_scaled_data *= EPM_ADC_MILLI_VOLTS_SOURCE;
+			do_div(adc_scaled_data, EPM_ADC_VREF_CODE);
 			 /* Data will now be in micro-volts.*/
-			*adc_scaled_data *= EPM_ADC_SCALE_MILLI;
+			adc_scaled_data *= EPM_ADC_SCALE_MILLI;
 			 /* Divide by amplifier gain value.*/
-			do_div(*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.*/
-			do_div(*adc_scaled_data, EPM_ADC_SCALE_FACTOR);
-			*adc_scaled_data *= EPM_ADC_SCALE_MILLI;
+			do_div(adc_scaled_data, EPM_ADC_SCALE_FACTOR);
+			adc_scaled_data *= EPM_ADC_SCALE_MILLI;
 			 /* Data is now in micro-amps.*/
-			do_div(*adc_scaled_data,
+			do_div(adc_scaled_data,
 				pdata->channel[chan_idx].resistorvalue);
 			 /* Set the sign bit for lekage current. */
-			*adc_scaled_data *= sign_bit;
+			adc_scaled_data *= sign_bit;
 		}
 	}
-	conv->physical = (int32_t) *adc_scaled_data;
+	conv->physical = (int32_t) adc_scaled_data;
 
 	return 0;
 }
@@ -1600,16 +1590,15 @@
 	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;
+	else {
+		epm_adc = epm_adc_drv;
+		epm_adc_drv->epm_spi_client = spi;
+		epm_adc_drv->epm_spi_client->bits_per_word =
+				EPM_ADC_ADS_SPI_BITS_PER_WORD;
+		return rc;
+	}
 
 	epm_adc = epm_adc_drv;
 	epm_adc->misc.name = EPM_ADC_DRIVER_NAME;
diff --git a/drivers/hwmon/pm8xxx-adc.c b/drivers/hwmon/pm8xxx-adc.c
index 8e35252..181a97e 100644
--- a/drivers/hwmon/pm8xxx-adc.c
+++ b/drivers/hwmon/pm8xxx-adc.c
@@ -31,6 +31,7 @@
 #include <linux/mfd/pm8xxx/core.h>
 #include <linux/regulator/consumer.h>
 #include <linux/mfd/pm8xxx/pm8xxx-adc.h>
+#include <mach/msm_xo.h>
 
 /* User Bank register set */
 #define PM8XXX_ADC_ARB_USRP_CNTRL1			0x197
@@ -141,6 +142,7 @@
 	struct work_struct			cool_work;
 	uint32_t				mpp_base;
 	struct device				*hwmon;
+	struct msm_xo_voter			*adc_voter;
 	int					msm_suspend_check;
 	struct pm8xxx_adc_amux_properties	*conv;
 	struct pm8xxx_adc_arb_btm_param		batt;
@@ -290,14 +292,34 @@
 	return rc;
 }
 
+static int32_t pm8xxx_adc_xo_vote(bool on)
+{
+	struct pm8xxx_adc *adc_pmic = pmic_adc;
+
+	if (on)
+		msm_xo_mode_vote(adc_pmic->adc_voter, MSM_XO_MODE_ON);
+	else
+		msm_xo_mode_vote(adc_pmic->adc_voter, MSM_XO_MODE_OFF);
+
+	return 0;
+}
+
 static int32_t pm8xxx_adc_channel_power_enable(uint32_t channel,
 							bool power_cntrl)
 {
 	int rc = 0;
 
-	switch (channel)
+	switch (channel) {
 	case ADC_MPP_1_AMUX8:
 		rc = pm8xxx_adc_patherm_power(power_cntrl);
+		break;
+	case CHANNEL_DIE_TEMP:
+	case CHANNEL_MUXOFF:
+		rc = pm8xxx_adc_xo_vote(power_cntrl);
+		break;
+	default:
+		break;
+	}
 
 	return rc;
 }
@@ -1147,6 +1169,7 @@
 	struct pm8xxx_adc *adc_pmic = pmic_adc;
 	int i;
 
+	msm_xo_put(adc_pmic->adc_voter);
 	platform_set_drvdata(pdev, NULL);
 	pmic_adc = NULL;
 	if (!pa_therm) {
@@ -1265,6 +1288,14 @@
 	}
 	adc_pmic->hwmon = hwmon_device_register(adc_pmic->dev);
 
+	if (adc_pmic->adc_voter == NULL) {
+		adc_pmic->adc_voter = msm_xo_get(MSM_XO_TCXO_D0, "pmic_xoadc");
+		if (IS_ERR(adc_pmic->adc_voter)) {
+			dev_err(&pdev->dev, "Failed to get XO vote\n");
+			return PTR_ERR(adc_pmic->adc_voter);
+		}
+	}
+
 	pa_therm = regulator_get(adc_pmic->dev, "pa_therm");
 	if (IS_ERR(pa_therm)) {
 		rc = PTR_ERR(pa_therm);
diff --git a/drivers/media/dvb/dvb-core/demux.h b/drivers/media/dvb/dvb-core/demux.h
index 071d209..7190af8 100644
--- a/drivers/media/dvb/dvb-core/demux.h
+++ b/drivers/media/dvb/dvb-core/demux.h
@@ -109,6 +109,24 @@
 	};
 };
 
+/*
+ * struct data_buffer: Parameters of buffer allocated by
+ * demux device for input/output. Can be used to directly map the
+ * demux-device buffer to HW output if HW supports it.
+ */
+struct data_buffer {
+	/* dvb_ringbuffer managed by demux-device */
+	const struct dvb_ringbuffer *ringbuff;
+
+
+	/*
+	 * Private handle returned by kernel demux when
+	 * map_buffer is called in case external buffer
+	 * is used. NULL if buffer is allocated internally.
+	 */
+	void *priv_handle;
+};
+
 /*--------------------------------------------------------------------------*/
 /* TS packet reception */
 /*--------------------------------------------------------------------------*/
@@ -168,7 +186,7 @@
 struct dmx_ts_feed {
 	int is_filtering; /* Set to non-zero when filtering in progress */
 	struct dmx_demux *parent; /* Back-pointer */
-	const struct dvb_ringbuffer *buffer;
+	struct data_buffer buffer;
 	void *priv; /* Pointer to private data of the API client */
 	int (*set) (struct dmx_ts_feed *feed,
 		    u16 pid,
@@ -198,7 +216,7 @@
 	u8 filter_mask [DMX_MAX_FILTER_SIZE];
 	u8 filter_mode [DMX_MAX_FILTER_SIZE];
 	struct dmx_section_feed* parent; /* Back-pointer */
-	const struct dvb_ringbuffer *buffer;
+	struct data_buffer buffer;
 	void* priv; /* Pointer to private data of the API client */
 };
 
@@ -316,6 +334,8 @@
 	u32 capabilities;            /* Bitfield of capability flags */
 	struct dmx_frontend* frontend;    /* Front-end connected to the demux */
 	void* priv;                  /* Pointer to private data of the API client */
+	struct data_buffer dvr_input; /* DVR input buffer */
+
 	int (*open) (struct dmx_demux* demux);
 	int (*close) (struct dmx_demux* demux);
 	int (*write) (struct dmx_demux *demux, const char *buf, size_t count);
@@ -359,6 +379,13 @@
 
 	int (*get_stc) (struct dmx_demux* demux, unsigned int num,
 			u64 *stc, unsigned int *base);
+
+	int (*map_buffer) (struct dmx_demux *demux,
+			struct dmx_buffer *dmx_buffer,
+			void **priv_handle, void **mem);
+
+	int (*unmap_buffer) (struct dmx_demux *demux,
+			void *priv_handle);
 };
 
 #endif /* #ifndef __DEMUX_H */
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index 8353f6f..d9f62ad 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -490,6 +490,8 @@
 		dvb_ringbuffer_init(&dmxdev->dvr_buffer, mem, DVR_BUFFER_SIZE);
 		dvb_dmxdev_flush_events(&dmxdev->dvr_output_events);
 		dmxdev->dvr_feeds_count = 0;
+		dmxdev->dvr_buffer_mode = DMX_BUFFER_MODE_INTERNAL;
+		dmxdev->dvr_priv_buff_handle = NULL;
 
 		dvbdev->readers--;
 	} else if (!dvbdev->writers) {
@@ -517,10 +519,14 @@
 
 		dmxdev->demux->disconnect_frontend(dmxdev->demux);
 		dmxdev->demux->connect_frontend(dmxdev->demux, front);
+		dmxdev->dvr_input_buffer_mode = DMX_BUFFER_MODE_INTERNAL;
 
 		dvb_ringbuffer_init(&dmxdev->dvr_input_buffer,
 							mem,
 							DVR_BUFFER_SIZE);
+
+		dmxdev->demux->dvr_input.priv_handle = NULL;
+		dmxdev->demux->dvr_input.ringbuff = &dmxdev->dvr_input_buffer;
 		dvbdev->writers--;
 	}
 
@@ -545,7 +551,16 @@
 			dmxdev->dvr_buffer.data = NULL;
 			spin_unlock_irq(&dmxdev->lock);
 			wake_up_all(&dmxdev->dvr_buffer.queue);
-			vfree(mem);
+
+			if (dmxdev->dvr_buffer_mode == DMX_BUFFER_MODE_INTERNAL)
+				vfree(mem);
+		}
+
+		if ((dmxdev->dvr_buffer_mode == DMX_BUFFER_MODE_EXTERNAL) &&
+			dmxdev->dvr_priv_buff_handle) {
+			dmxdev->demux->unmap_buffer(dmxdev->demux,
+					dmxdev->dvr_priv_buff_handle);
+			dmxdev->dvr_priv_buff_handle = NULL;
 		}
 	} else {
 		int i;
@@ -589,7 +604,17 @@
 			spin_lock_irq(&dmxdev->dvr_in_lock);
 			dmxdev->dvr_input_buffer.data = NULL;
 			spin_unlock_irq(&dmxdev->dvr_in_lock);
-			vfree(mem);
+
+			if (dmxdev->dvr_buffer_mode == DMX_BUFFER_MODE_INTERNAL)
+				vfree(mem);
+		}
+
+		if ((dmxdev->dvr_input_buffer_mode ==
+			DMX_BUFFER_MODE_EXTERNAL) &&
+			(dmxdev->demux->dvr_input.priv_handle)) {
+			dmxdev->demux->unmap_buffer(dmxdev->demux,
+					dmxdev->demux->dvr_input.priv_handle);
+			dmxdev->demux->dvr_input.priv_handle = NULL;
 		}
 	}
 	/* TODO */
@@ -611,6 +636,7 @@
 	struct dvb_device *dvbdev = filp->private_data;
 	struct dmxdev *dmxdev = dvbdev->priv;
 	struct dvb_ringbuffer *buffer;
+	enum dmx_buffer_mode buffer_mode;
 	int vma_size;
 	int buffer_size;
 	int ret;
@@ -627,10 +653,18 @@
 		return -ENODEV;
 	}
 
-	if ((filp->f_flags & O_ACCMODE) == O_RDONLY)
+	if ((filp->f_flags & O_ACCMODE) == O_RDONLY) {
 		buffer = &dmxdev->dvr_buffer;
-	else
+		buffer_mode = dmxdev->dvr_buffer_mode;
+	} else {
 		buffer = &dmxdev->dvr_input_buffer;
+		buffer_mode = dmxdev->dvr_input_buffer_mode;
+	}
+
+	if (buffer_mode == DMX_BUFFER_MODE_EXTERNAL) {
+		mutex_unlock(&dmxdev->mutex);
+		return -EINVAL;
+	}
 
 	vma_size = vma->vm_end - vma->vm_start;
 
@@ -669,7 +703,8 @@
 	if (!dmxdev->demux->write)
 		return -EOPNOTSUPP;
 
-	if ((file->f_flags & O_ACCMODE) == O_RDONLY)
+	if (((file->f_flags & O_ACCMODE) == O_RDONLY) ||
+		(!src->data))
 		return -EINVAL;
 
 	if ((file->f_flags & O_NONBLOCK) &&
@@ -859,20 +894,23 @@
 	void *newmem;
 	void *oldmem;
 	spinlock_t *lock;
+	enum dmx_buffer_mode buffer_mode;
 
 	dprintk("function : %s\n", __func__);
 
 	if ((f_flags & O_ACCMODE) == O_RDONLY) {
 		buf = &dmxdev->dvr_buffer;
 		lock = &dmxdev->lock;
+		buffer_mode = dmxdev->dvr_buffer_mode;
 	} else {
 		buf = &dmxdev->dvr_input_buffer;
 		lock = &dmxdev->dvr_in_lock;
+		buffer_mode = dmxdev->dvr_input_buffer_mode;
 	}
 
 	if (buf->size == size)
 		return 0;
-	if (!size)
+	if ((!size) || (buffer_mode == DMX_BUFFER_MODE_EXTERNAL))
 		return -EINVAL;
 
 	newmem = vmalloc_user(size);
@@ -903,6 +941,72 @@
 	return 0;
 }
 
+static int dvb_dvr_set_buffer_mode(struct dmxdev *dmxdev,
+			unsigned int f_flags, enum dmx_buffer_mode mode)
+{
+	if ((mode != DMX_BUFFER_MODE_INTERNAL) &&
+		(mode != DMX_BUFFER_MODE_EXTERNAL))
+		return -EINVAL;
+
+	if ((mode == DMX_BUFFER_MODE_INTERNAL) &&
+		(dmxdev->capabilities & DMXDEV_CAP_EXTERNAL_BUFFS_ONLY))
+		return -EINVAL;
+
+	if ((mode == DMX_BUFFER_MODE_EXTERNAL) &&
+		(!dmxdev->demux->map_buffer || !dmxdev->demux->unmap_buffer))
+		return -EINVAL;
+
+	if ((f_flags & O_ACCMODE) == O_RDONLY)
+		dmxdev->dvr_buffer_mode = mode;
+	else
+		dmxdev->dvr_input_buffer_mode = mode;
+
+	return 0;
+}
+
+static int dvb_dvr_set_buffer(struct dmxdev *dmxdev,
+			unsigned int f_flags, struct dmx_buffer *dmx_buffer)
+{
+	struct dvb_ringbuffer *buf;
+	spinlock_t *lock;
+	enum dmx_buffer_mode buffer_mode;
+	void **buff_handle;
+	void *newmem;
+	void *oldmem;
+
+	if ((f_flags & O_ACCMODE) == O_RDONLY) {
+		buf = &dmxdev->dvr_buffer;
+		lock = &dmxdev->lock;
+		buffer_mode = dmxdev->dvr_buffer_mode;
+		buff_handle = &dmxdev->dvr_priv_buff_handle;
+	} else {
+		buf = &dmxdev->dvr_input_buffer;
+		lock = &dmxdev->dvr_in_lock;
+		buffer_mode = dmxdev->dvr_input_buffer_mode;
+		buff_handle = &dmxdev->demux->dvr_input.priv_handle;
+	}
+
+	if ((!dmx_buffer->size) ||
+		(buffer_mode == DMX_BUFFER_MODE_INTERNAL))
+		return -EINVAL;
+
+	oldmem = *buff_handle;
+	if (dmxdev->demux->map_buffer(dmxdev->demux, dmx_buffer,
+				buff_handle, &newmem))
+		return -ENOMEM;
+
+	spin_lock_irq(lock);
+	buf->data = newmem;
+	buf->size = dmx_buffer->size;
+	dvb_ringbuffer_reset(buf);
+	spin_unlock_irq(lock);
+
+	if (oldmem)
+		dmxdev->demux->unmap_buffer(dmxdev->demux, oldmem);
+
+	return 0;
+}
+
 static int dvb_dvr_get_event(struct dmxdev *dmxdev,
 				unsigned int f_flags,
 				struct dmx_filter_event *event)
@@ -1058,7 +1162,7 @@
 
 	if (buf->size == size)
 		return 0;
-	if (!size)
+	if ((!size) || (dmxdevfilter->buffer_mode == DMX_BUFFER_MODE_EXTERNAL))
 		return -EINVAL;
 	if (dmxdevfilter->state >= DMXDEV_STATE_GO)
 		return -EBUSY;
@@ -1081,6 +1185,85 @@
 	return 0;
 }
 
+static int dvb_dmxdev_set_buffer_mode(struct dmxdev_filter *dmxdevfilter,
+					enum dmx_buffer_mode mode)
+{
+	struct dvb_ringbuffer *buf = &dmxdevfilter->buffer;
+	struct dmxdev *dmxdev = dmxdevfilter->dev;
+	void *oldmem;
+
+	if (dmxdevfilter->state >= DMXDEV_STATE_GO)
+		return -EBUSY;
+
+	if ((mode != DMX_BUFFER_MODE_INTERNAL) &&
+		(mode != DMX_BUFFER_MODE_EXTERNAL))
+		return -EINVAL;
+
+	if ((mode == DMX_BUFFER_MODE_INTERNAL) &&
+		(dmxdev->capabilities & DMXDEV_CAP_EXTERNAL_BUFFS_ONLY))
+		return -EINVAL;
+
+	if ((mode == DMX_BUFFER_MODE_EXTERNAL) &&
+		(!dmxdev->demux->map_buffer || !dmxdev->demux->unmap_buffer))
+		return -EINVAL;
+
+	if (mode == dmxdevfilter->buffer_mode)
+		return 0;
+
+	oldmem = buf->data;
+	spin_lock_irq(&dmxdevfilter->dev->lock);
+	buf->data = NULL;
+	spin_unlock_irq(&dmxdevfilter->dev->lock);
+
+	dmxdevfilter->buffer_mode = mode;
+
+	if (mode == DMX_BUFFER_MODE_INTERNAL) {
+		/* switched from external to internal */
+		if (dmxdevfilter->priv_buff_handle) {
+			dmxdev->demux->unmap_buffer(dmxdev->demux,
+				dmxdevfilter->priv_buff_handle);
+			dmxdevfilter->priv_buff_handle = NULL;
+		}
+	} else if (oldmem) {
+		/* switched from internal to external */
+		vfree(oldmem);
+	}
+
+	return 0;
+}
+
+static int dvb_dmxdev_set_buffer(struct dmxdev_filter *dmxdevfilter,
+					struct dmx_buffer *buffer)
+{
+	struct dvb_ringbuffer *buf = &dmxdevfilter->buffer;
+	struct dmxdev *dmxdev = dmxdevfilter->dev;
+	void *newmem;
+	void *oldmem;
+
+	if (dmxdevfilter->state >= DMXDEV_STATE_GO)
+		return -EBUSY;
+
+	if ((!buffer->size) ||
+		(dmxdevfilter->buffer_mode == DMX_BUFFER_MODE_INTERNAL))
+		return -EINVAL;
+
+	oldmem = dmxdevfilter->priv_buff_handle;
+	if (dmxdev->demux->map_buffer(dmxdev->demux, buffer,
+			&dmxdevfilter->priv_buff_handle, &newmem))
+		return -ENOMEM;
+
+	spin_lock_irq(&dmxdevfilter->dev->lock);
+	buf->data = newmem;
+	buf->size = buffer->size;
+	dvb_ringbuffer_reset(buf);
+	spin_unlock_irq(&dmxdevfilter->dev->lock);
+
+	if (oldmem)
+		dmxdev->demux->unmap_buffer(dmxdev->demux, oldmem);
+
+	return 0;
+}
+
 static int dvb_dmxdev_set_pes_buffer_size(struct dmxdev_filter *dmxdevfilter,
 					unsigned long size)
 {
@@ -1962,12 +2145,14 @@
 	tsfeed->priv = filter;
 
 	if (filter->params.pes.output == DMX_OUT_TS_TAP) {
-		tsfeed->buffer = &dmxdev->dvr_buffer;
+		tsfeed->buffer.ringbuff = &dmxdev->dvr_buffer;
+		tsfeed->buffer.priv_handle = dmxdev->dvr_priv_buff_handle;
 		if (!dmxdev->dvr_feeds_count)
 			dmxdev->dvr_feed = filter;
 		dmxdev->dvr_feeds_count++;
 	} else {
-		tsfeed->buffer = &filter->buffer;
+		tsfeed->buffer.ringbuff = &filter->buffer;
+		tsfeed->buffer.priv_handle = filter->priv_buff_handle;
 	}
 
 	if (tsfeed->data_ready_cb) {
@@ -2028,6 +2213,9 @@
 		dvb_dmxdev_filter_stop(filter);
 
 	if (!filter->buffer.data) {
+		if ((filter->buffer_mode == DMX_BUFFER_MODE_EXTERNAL) ||
+			(dmxdev->capabilities & DMXDEV_CAP_EXTERNAL_BUFFS_ONLY))
+			return -ENOMEM;
 		mem = vmalloc_user(filter->buffer.size);
 		if (!mem)
 			return -ENOMEM;
@@ -2105,7 +2293,8 @@
 		}
 
 		(*secfilter)->priv = filter;
-		(*secfilter)->buffer = &filter->buffer;
+		(*secfilter)->buffer.ringbuff = &filter->buffer;
+		(*secfilter)->buffer.priv_handle = filter->priv_buff_handle;
 
 		memcpy(&((*secfilter)->filter_value[3]),
 		       &(para->filter.filter[1]), DMX_FILTER_SIZE - 1);
@@ -2182,6 +2371,8 @@
 	mutex_init(&dmxdevfilter->mutex);
 	file->private_data = dmxdevfilter;
 
+	dmxdevfilter->buffer_mode = DMX_BUFFER_MODE_INTERNAL;
+	dmxdevfilter->priv_buff_handle = NULL;
 	dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192);
 	dvb_dmxdev_flush_events(&dmxdevfilter->events);
 
@@ -2212,7 +2403,15 @@
 		spin_lock_irq(&dmxdev->lock);
 		dmxdevfilter->buffer.data = NULL;
 		spin_unlock_irq(&dmxdev->lock);
-		vfree(mem);
+		if (dmxdevfilter->buffer_mode == DMX_BUFFER_MODE_INTERNAL)
+			vfree(mem);
+	}
+
+	if ((dmxdevfilter->buffer_mode == DMX_BUFFER_MODE_EXTERNAL) &&
+		(dmxdevfilter->priv_buff_handle)) {
+		dmxdev->demux->unmap_buffer(dmxdev->demux,
+			dmxdevfilter->priv_buff_handle);
+		dmxdevfilter->priv_buff_handle = NULL;
 	}
 
 	dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_FREE);
@@ -2487,6 +2686,25 @@
 		mutex_unlock(&dmxdevfilter->mutex);
 		break;
 
+	case DMX_SET_BUFFER_MODE:
+		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+			mutex_unlock(&dmxdev->mutex);
+			return -ERESTARTSYS;
+		}
+		ret = dvb_dmxdev_set_buffer_mode(dmxdevfilter,
+				*(enum dmx_buffer_mode *)parg);
+		mutex_unlock(&dmxdevfilter->mutex);
+		break;
+
+	case DMX_SET_BUFFER:
+		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+			mutex_unlock(&dmxdev->mutex);
+			return -ERESTARTSYS;
+		}
+		ret = dvb_dmxdev_set_buffer(dmxdevfilter, parg);
+		mutex_unlock(&dmxdevfilter->mutex);
+		break;
+
 	case DMX_GET_BUFFER_STATUS:
 		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
 			mutex_unlock(&dmxdev->mutex);
@@ -2679,7 +2897,8 @@
 		return -ERESTARTSYS;
 	}
 
-	if (!dmxdevfilter->buffer.data) {
+	if ((!dmxdevfilter->buffer.data) ||
+		(dmxdevfilter->buffer_mode == DMX_BUFFER_MODE_EXTERNAL)) {
 		mutex_unlock(&dmxdevfilter->mutex);
 		mutex_unlock(&dmxdev->mutex);
 		return -EINVAL;
@@ -2767,6 +2986,15 @@
 		ret = dvb_dvr_set_buffer_size(dmxdev, file->f_flags, arg);
 		break;
 
+	case DMX_SET_BUFFER_MODE:
+		ret = dvb_dvr_set_buffer_mode(dmxdev, file->f_flags,
+			*(enum dmx_buffer_mode *)parg);
+		break;
+
+	case DMX_SET_BUFFER:
+		ret = dvb_dvr_set_buffer(dmxdev, file->f_flags, parg);
+		break;
+
 	case DMX_GET_BUFFER_STATUS:
 		ret = dvb_dvr_get_buffer_status(dmxdev, file->f_flags, parg);
 		break;
diff --git a/drivers/media/dvb/dvb-core/dmxdev.h b/drivers/media/dvb/dvb-core/dmxdev.h
index 9fd900e..e30c2c3 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.h
+++ b/drivers/media/dvb/dvb-core/dmxdev.h
@@ -113,6 +113,8 @@
 	enum dmxdev_state state;
 	struct dmxdev *dev;
 	struct dvb_ringbuffer buffer;
+	void *priv_buff_handle;
+	enum dmx_buffer_mode buffer_mode;
 	u32 flush_data_len;
 
 	struct mutex mutex;
@@ -139,9 +141,10 @@
 
 	int filternum;
 	int capabilities;
-#define DMXDEV_CAP_DUPLEX	0x1
-#define DMXDEV_CAP_PULL_MODE	0x2
-#define DMXDEV_CAP_INDEXING	0x4
+#define DMXDEV_CAP_DUPLEX	0x01
+#define DMXDEV_CAP_PULL_MODE	0x02
+#define DMXDEV_CAP_INDEXING	0x04
+#define DMXDEV_CAP_EXTERNAL_BUFFS_ONLY	0x08
 
 	enum dmx_playback_mode_t playback_mode;
 	dmx_source_t source;
@@ -153,12 +156,15 @@
 	struct dmx_frontend *dvr_orig_fe;
 
 	struct dvb_ringbuffer dvr_buffer;
+	void *dvr_priv_buff_handle;
+	enum dmx_buffer_mode dvr_buffer_mode;
 	struct dmxdev_events_queue dvr_output_events;
 	struct dmxdev_filter *dvr_feed;
 	u32 dvr_flush_data_len;
 	int dvr_feeds_count;
 
 	struct dvb_ringbuffer dvr_input_buffer;
+	enum dmx_buffer_mode dvr_input_buffer_mode;
 	struct workqueue_struct *dvr_input_workqueue;
 
 #define DVR_BUFFER_SIZE (10*188*1024)
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index df71f76..de7b28d 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -1794,6 +1794,8 @@
 	dmx->release_ts_feed = dvbdmx_release_ts_feed;
 	dmx->allocate_section_feed = dvbdmx_allocate_section_feed;
 	dmx->release_section_feed = dvbdmx_release_section_feed;
+	dmx->map_buffer = NULL;
+	dmx->unmap_buffer = NULL;
 
 	dmx->add_frontend = dvbdmx_add_frontend;
 	dmx->remove_frontend = dvbdmx_remove_frontend;
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c
index a01cf5b..836ca65 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c
@@ -595,7 +595,7 @@
 	 * for decoder's buffers.
 	 */
 	mpq_dmx_info.ion_client =
-		msm_ion_client_create(UINT_MAX, "demux client");
+		msm_ion_client_create(UINT_MAX, "demux_client");
 
 	if (IS_ERR_OR_NULL(mpq_dmx_info.ion_client)) {
 		MPQ_DVB_ERR_PRINT(
@@ -603,6 +603,8 @@
 				__func__);
 
 		result = PTR_ERR(mpq_dmx_info.ion_client);
+		if (!result)
+			result = -ENOMEM;
 		mpq_dmx_info.ion_client = NULL;
 		goto init_failed_free_demux_devices;
 	}
@@ -683,7 +685,7 @@
 
 	if (mpq_dmx_info.devices != NULL) {
 		for (i = 0; i < mpq_demux_device_num; i++) {
-			mpq_demux = mpq_dmx_info.devices+i;
+			mpq_demux = mpq_dmx_info.devices + i;
 
 			if (mpq_demux->is_initialized) {
 				mpq_demux->demux.dmx.remove_frontend(
@@ -764,6 +766,107 @@
 }
 EXPORT_SYMBOL(mpq_dmx_set_source);
 
+int mpq_dmx_map_buffer(struct dmx_demux *demux, struct dmx_buffer *dmx_buffer,
+		void **priv_handle, void **kernel_mem)
+{
+	struct dvb_demux *dvb_demux = demux->priv;
+	struct mpq_demux *mpq_demux;
+	struct ion_handle *ion_handle;
+	unsigned long ionflag = 0;
+	int ret;
+
+	if ((mpq_dmx_info.devices == NULL) || (dvb_demux == NULL) ||
+		(priv_handle == NULL) || (kernel_mem == NULL)) {
+		MPQ_DVB_ERR_PRINT("%s: invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	mpq_demux = dvb_demux->priv;
+	if (mpq_demux == NULL) {
+		MPQ_DVB_ERR_PRINT("%s: invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	ion_handle = ion_import_dma_buf(mpq_demux->ion_client,
+					dmx_buffer->handle);
+	if (IS_ERR_OR_NULL(ion_handle)) {
+		ret = PTR_ERR(ion_handle);
+		if (!ret)
+			ret = -ENOMEM;
+
+		MPQ_DVB_ERR_PRINT("%s: ion_import_dma_buf failed %d\n",
+			__func__, ret);
+		goto map_buffer_failed;
+	}
+
+	ret = ion_handle_get_flags(mpq_demux->ion_client, ion_handle, &ionflag);
+	if (ret) {
+		MPQ_DVB_ERR_PRINT("%s: ion_handle_get_flags failed %d\n",
+			__func__, ret);
+		goto map_buffer_failed_free_buff;
+	}
+
+	if (ionflag & ION_SECURE) {
+		MPQ_DVB_DBG_PRINT("%s: secured buffer\n", __func__);
+		/* TBD: Set buffer as secured */
+		*kernel_mem = NULL;
+	} else {
+		*kernel_mem = ion_map_kernel(mpq_demux->ion_client,
+						ion_handle, ionflag);
+		if (*kernel_mem == NULL) {
+			MPQ_DVB_ERR_PRINT("%s: ion_map_kernel failed\n",
+				__func__);
+			ret = -ENOMEM;
+			goto map_buffer_failed_free_buff;
+		}
+	}
+
+	*priv_handle = (void *)ion_handle;
+	return 0;
+
+map_buffer_failed_free_buff:
+	ion_free(mpq_demux->ion_client, ion_handle);
+map_buffer_failed:
+	return ret;
+}
+EXPORT_SYMBOL(mpq_dmx_map_buffer);
+
+int mpq_dmx_unmap_buffer(struct dmx_demux *demux,
+		void *priv_handle)
+{
+	struct dvb_demux *dvb_demux = demux->priv;
+	struct ion_handle *ion_handle = priv_handle;
+	struct mpq_demux *mpq_demux;
+	unsigned long ionflag = 0;
+	int ret;
+
+	if ((mpq_dmx_info.devices == NULL) || (dvb_demux == NULL) ||
+		(priv_handle == NULL)) {
+		MPQ_DVB_ERR_PRINT("%s: invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	mpq_demux = dvb_demux->priv;
+	if (mpq_demux == NULL) {
+		MPQ_DVB_ERR_PRINT("%s: invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	ret = ion_handle_get_flags(mpq_demux->ion_client, ion_handle, &ionflag);
+	if (ret) {
+		MPQ_DVB_ERR_PRINT("%s: ion_handle_get_flags failed %d\n",
+			__func__, ret);
+		return -EINVAL;
+	}
+
+	if (!(ionflag & ION_SECURE))
+		ion_unmap_kernel(mpq_demux->ion_client, ion_handle);
+
+	ion_free(mpq_demux->ion_client, ion_handle);
+
+	return 0;
+}
+EXPORT_SYMBOL(mpq_dmx_unmap_buffer);
 
 int mpq_dmx_init_video_feed(struct dvb_demux_feed *feed)
 {
@@ -836,9 +939,10 @@
 
 		MPQ_DVB_ERR_PRINT(
 			"%s: FAILED to allocate payload buffer %d\n",
-			__func__,
-			ret);
+			__func__, ret);
 
+		if (!ret)
+			ret = -ENOMEM;
 		goto init_failed_free_packet_buffer;
 	}
 
@@ -852,9 +956,10 @@
 
 		MPQ_DVB_ERR_PRINT(
 			"%s: FAILED to map payload buffer %d\n",
-			__func__,
-			ret);
+			__func__, ret);
 
+		if (!ret)
+			ret = -ENOMEM;
 		goto init_failed_free_payload_buffer;
 	}
 
@@ -922,8 +1027,7 @@
 		MPQ_DVB_ERR_PRINT(
 			"%s: mpq_adapter_register_stream_if failed, "
 			"err = %d\n",
-			__func__,
-			ret);
+			__func__, ret);
 		goto init_failed_unmap_payload_buffer;
 	}
 
@@ -991,8 +1095,7 @@
 
 	wake_up_all(&feed_data->video_buffer->raw_data.queue);
 
-	mpq_adapter_unregister_stream_if(
-		feed_data->stream_interface);
+	mpq_adapter_unregister_stream_if(feed_data->stream_interface);
 
 	vfree(feed_data->video_buffer->packet_data.data);
 
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 893273d..3500eda 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.h
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.h
@@ -332,7 +332,7 @@
  * them to the dvb adapter.
  *
  * @dmx_init_func: Pointer to the function to be used
- *  to initialize demux of the udnerlying HW plugin.
+ *  to initialize demux of the underlying HW plugin.
  *
  * Return     error code
  *
@@ -361,6 +361,38 @@
 int mpq_dmx_set_source(struct dmx_demux *demux, const dmx_source_t *src);
 
 /**
+ * mpq_dmx_map_buffer - map user-space buffer into kernel space.
+ *
+ * @demux: The demux device.
+ * @dmx_buffer: The demux buffer from user-space, assumes that
+ * buffer handle is ION file-handle.
+ * @priv_handle: Saves ION-handle of the buffer imported by this function.
+ * @kernel_mem: Saves kernel mapped address of the buffer.
+ *
+ * Return     error code
+ *
+ * The function maps the buffer into kernel memory only if the buffer
+ * was not allocated with secure flag, otherwise the returned kernel
+ * memory address is set to NULL.
+ */
+int mpq_dmx_map_buffer(struct dmx_demux *demux, struct dmx_buffer *dmx_buffer,
+		void **priv_handle, void **kernel_mem);
+
+/**
+ * mpq_dmx_unmap_buffer - unmap user-space buffer from kernel space memory.
+ *
+ * @demux: The demux device.
+ * @priv_handle: ION-handle of the buffer returned from mpq_dmx_map_buffer.
+ *
+ * Return     error code
+ *
+ * The function unmaps the buffer from kernel memory only if the buffer
+ * was not allocated with secure flag.
+ */
+int mpq_dmx_unmap_buffer(struct dmx_demux *demux,
+		void *priv_handle);
+
+/**
  * mpq_dmx_init_video_feed - Initializes video feed
  * used to pass data to decoder directly.
  *
@@ -396,8 +428,7 @@
  *
  * Return     error code.
  */
-int mpq_dmx_decoder_fullness_init(
-		struct dvb_demux_feed *feed);
+int mpq_dmx_decoder_fullness_init(struct dvb_demux_feed *feed);
 
 /**
  * mpq_dmx_decoder_fullness_wait - Checks whether decoder buffer
@@ -408,8 +439,7 @@
  *
  * Return     error code.
  */
-int mpq_dmx_decoder_fullness_wait(
-		struct dvb_demux_feed *feed,
+int mpq_dmx_decoder_fullness_wait(struct dvb_demux_feed *feed,
 		size_t required_space);
 
 /**
@@ -422,8 +452,7 @@
  *
  * Return     error code.
  */
-int mpq_dmx_decoder_fullness_abort(
-		struct dvb_demux_feed *feed);
+int mpq_dmx_decoder_fullness_abort(struct dvb_demux_feed *feed);
 
 /**
  * mpq_dmx_decoder_buffer_status - Returns the
@@ -452,9 +481,7 @@
  * the packet and does not write them to the output buffer.
  * Scrambled packets are bypassed.
  */
-int mpq_dmx_process_video_packet(
-		struct dvb_demux_feed *feed,
-		const u8 *buf);
+int mpq_dmx_process_video_packet(struct dvb_demux_feed *feed, const u8 *buf);
 
 /**
  * mpq_dmx_process_pcr_packet - Extract PCR/STC pairs from
@@ -475,9 +502,7 @@
  * The function callbacks dmxdev after extraction of the pcr/stc
  * pair.
  */
-int mpq_dmx_process_pcr_packet(
-			struct dvb_demux_feed *feed,
-			const u8 *buf);
+int mpq_dmx_process_pcr_packet(struct dvb_demux_feed *feed, const u8 *buf);
 
 /**
  * mpq_dmx_is_video_feed - Returns whether the PES feed
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 74a0dbe..627c5a2 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c
@@ -579,6 +579,24 @@
 	caps->max_bitrate = 144;
 	caps->demod_input_max_bitrate = 72;
 	caps->memory_input_max_bitrate = 72;
+	caps->section.flags = 0;
+	caps->section.max_size = 0xFFFFFFFF;
+	caps->section.size_alignment = 0;
+	caps->pes.flags = 0;
+	caps->pes.max_size = 0xFFFFFFFF;
+	caps->pes.size_alignment = 0;
+	caps->recording_188_tsp.flags = 0;
+	caps->recording_188_tsp.max_size = 0xFFFFFFFF;
+	caps->recording_188_tsp.size_alignment = 0;
+	caps->recording_192_tsp.flags = 0;
+	caps->recording_192_tsp.max_size = 0xFFFFFFFF;
+	caps->recording_192_tsp.size_alignment = 0;
+	caps->playback_188_tsp.flags = 0;
+	caps->playback_188_tsp.max_size = 0xFFFFFFFF;
+	caps->playback_188_tsp.size_alignment = 0;
+	caps->playback_192_tsp.flags = 0;
+	caps->playback_192_tsp.max_size = 0xFFFFFFFF;
+	caps->playback_192_tsp.size_alignment = 0;
 
 	return 0;
 }
@@ -645,6 +663,8 @@
 
 	mpq_demux->dmxdev.demux->set_source = mpq_dmx_set_source;
 	mpq_demux->dmxdev.demux->get_caps = mpq_tsif_dmx_get_caps;
+	mpq_demux->dmxdev.demux->map_buffer = mpq_dmx_map_buffer;
+	mpq_demux->dmxdev.demux->unmap_buffer = mpq_dmx_unmap_buffer;
 
 	result = dvb_dmxdev_init(&mpq_demux->dmxdev, mpq_adapter);
 	if (result < 0) {
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 c1d1462..e4f00c0 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
@@ -708,6 +708,24 @@
 	caps->max_bitrate = 144;
 	caps->demod_input_max_bitrate = 72;
 	caps->memory_input_max_bitrate = 72;
+	caps->section.flags = 0;
+	caps->section.max_size = 0xFFFFFFFF;
+	caps->section.size_alignment = 0;
+	caps->pes.flags = 0;
+	caps->pes.max_size = 0xFFFFFFFF;
+	caps->pes.size_alignment = 0;
+	caps->recording_188_tsp.flags = 0;
+	caps->recording_188_tsp.max_size = 0xFFFFFFFF;
+	caps->recording_188_tsp.size_alignment = 0;
+	caps->recording_192_tsp.flags = 0;
+	caps->recording_192_tsp.max_size = 0xFFFFFFFF;
+	caps->recording_192_tsp.size_alignment = 0;
+	caps->playback_188_tsp.flags = 0;
+	caps->playback_188_tsp.max_size = 0xFFFFFFFF;
+	caps->playback_188_tsp.size_alignment = 0;
+	caps->playback_192_tsp.flags = 0;
+	caps->playback_192_tsp.max_size = 0xFFFFFFFF;
+	caps->playback_192_tsp.size_alignment = 0;
 
 	return 0;
 }
@@ -766,6 +784,8 @@
 
 	mpq_demux->dmxdev.demux->set_source = mpq_dmx_set_source;
 	mpq_demux->dmxdev.demux->get_caps = mpq_tspp_dmx_get_caps;
+	mpq_demux->dmxdev.demux->map_buffer = mpq_dmx_map_buffer;
+	mpq_demux->dmxdev.demux->unmap_buffer = mpq_dmx_unmap_buffer;
 
 	result = dvb_dmxdev_init(&mpq_demux->dmxdev, mpq_adapter);
 	if (result < 0) {
diff --git a/drivers/media/dvb/mpq/video/mpq_dvb_video.c b/drivers/media/dvb/mpq/video/mpq_dvb_video.c
index 3dc31bb..4b3fb0c 100644
--- a/drivers/media/dvb/mpq/video/mpq_dvb_video.c
+++ b/drivers/media/dvb/mpq/video/mpq_dvb_video.c
@@ -868,7 +868,7 @@
 	if (rc)
 		DBG("Failed in mpq_int_vid_dec_get_buffer_req : %d\n", rc);
 
-	vdec_buf_req.num_output_buffers = 15;
+	vdec_buf_req.num_output_buffers = 12;
 	rc = mpq_int_set_out_buffer_req(client_ctx, &vdec_buf_req);
 	if (rc)
 		DBG("Failed in mpq_int_set_out_buffer_req (15) : %d\n", rc);
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index ae020e8..0d2d91c 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -1262,3 +1262,4 @@
 endif # V4L_MEM2MEM_DRIVERS
 
 source "drivers/media/video/msm_vidc/Kconfig"
+source "drivers/media/video/msm_wfd/Kconfig"
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 082ee3d..fd736c3 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -215,7 +215,7 @@
 obj-$(CONFIG_MSM_CAMERA) += msm/
 obj-$(CONFIG_ARCH_OMAP)	+= omap/
 obj-$(CONFIG_MSM_VIDC_V4L2) += msm_vidc/
-obj-$(CONFIG_FB_MSM_WRITEBACK_MSM_PANEL) += msm_wfd/
+obj-$(CONFIG_MSM_WFD) += msm_wfd/
 
 ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core
 ccflags-y += -I$(srctree)/drivers/media/dvb/frontends
diff --git a/drivers/media/video/msm/csi/msm_csi2_register.c b/drivers/media/video/msm/csi/msm_csi2_register.c
index aa539ff..5f2183b 100644
--- a/drivers/media/video/msm/csi/msm_csi2_register.c
+++ b/drivers/media/video/msm/csi/msm_csi2_register.c
@@ -16,18 +16,21 @@
 #include "msm_csi_register.h"
 
 int msm_csi_register_subdevs(struct msm_cam_media_controller *p_mctl,
-	int core_index, struct msm_cam_server_dev *server_dev)
+	uint8_t csiphy_code_index, uint8_t csid_core_index,
+	struct msm_cam_server_dev *server_dev)
 {
 	int rc = -ENODEV;
 
+	CDBG("%s csiphy sel %d csid sel %d\n", __func__, csiphy_code_index,
+		csid_core_index);
 	/* register csiphy subdev */
-	p_mctl->csiphy_sdev = server_dev->csiphy_device[core_index];
+	p_mctl->csiphy_sdev = server_dev->csiphy_device[csiphy_code_index];
 	if (!p_mctl->csiphy_sdev)
 		goto out;
 	v4l2_set_subdev_hostdata(p_mctl->csiphy_sdev, p_mctl);
 
 	/* register csid subdev */
-	p_mctl->csid_sdev = server_dev->csid_device[core_index];
+	p_mctl->csid_sdev = server_dev->csid_device[csid_core_index];
 	if (!p_mctl->csid_sdev)
 		goto out;
 	v4l2_set_subdev_hostdata(p_mctl->csid_sdev, p_mctl);
diff --git a/drivers/media/video/msm/csi/msm_csi_register.h b/drivers/media/video/msm/csi/msm_csi_register.h
index ebb001c..4214feb 100644
--- a/drivers/media/video/msm/csi/msm_csi_register.h
+++ b/drivers/media/video/msm/csi/msm_csi_register.h
@@ -12,5 +12,5 @@
  */
 
 int msm_csi_register_subdevs(struct msm_cam_media_controller *p_mctl,
-	int core_index,
+	uint8_t csiphy_code_index, uint8_t csid_core_index,
 	struct msm_cam_server_dev *server_dev);
diff --git a/drivers/media/video/msm/csi/msm_csic_register.c b/drivers/media/video/msm/csi/msm_csic_register.c
index dc3641a..af50101 100644
--- a/drivers/media/video/msm/csi/msm_csic_register.c
+++ b/drivers/media/video/msm/csi/msm_csic_register.c
@@ -16,11 +16,12 @@
 #include "msm_csi_register.h"
 
 int msm_csi_register_subdevs(struct msm_cam_media_controller *p_mctl,
-	int core_index, struct msm_cam_server_dev *server_dev)
+	uint8_t csiphy_code_index, uint8_t csid_core_index,
+	struct msm_cam_server_dev *server_dev)
 {
 	int rc = -ENODEV;
 
-	p_mctl->csic_sdev = server_dev->csic_device[core_index];
+	p_mctl->csic_sdev = server_dev->csic_device[csid_core_index];
 	if (!p_mctl->csic_sdev)
 		goto out;
 	v4l2_set_subdev_hostdata(p_mctl->csic_sdev, p_mctl);
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 9549dcc..d508c1d 100644
--- a/drivers/media/video/msm/io/msm_io_7x27a_v4l2.c
+++ b/drivers/media/video/msm/io/msm_io_7x27a_v4l2.c
@@ -139,11 +139,11 @@
 	switch (perf_setting) {
 	case S_INIT:
 		add_axi_qos();
-		break;
-	case S_PREVIEW:
 		update_axi_qos(MSM_AXI_QOS_PREVIEW);
 		axi_allocate(AXI_FLOW_VIEWFINDER_HI);
 		break;
+	case S_PREVIEW:
+		break;
 	case S_VIDEO:
 		update_axi_qos(MSM_AXI_QOS_RECORDING);
 		break;
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_common.h b/drivers/media/video/msm/jpeg_10/msm_jpeg_common.h
index 88ec1ad..04af6b6 100644
--- a/drivers/media/video/msm/jpeg_10/msm_jpeg_common.h
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_common.h
@@ -14,12 +14,13 @@
 #define MSM_JPEG_COMMON_H
 
 #ifdef MSM_JPEG_DEBUG
-#define JPEG_DBG(fmt, args...) printk(fmt, ##args)
+#define JPEG_DBG(fmt, args...) pr_info(fmt, ##args)
 #else
 #define JPEG_DBG(fmt, args...) do { } while (0)
 #endif
 
 #define JPEG_PR_ERR   pr_err
+#define JPEG_DBG_HIGH   pr_err
 
 enum JPEG_MODE {
 	JPEG_MODE_DISABLE,
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_core.c b/drivers/media/video/msm/jpeg_10/msm_jpeg_core.c
index 7905ff3..b67245c 100644
--- a/drivers/media/video/msm/jpeg_10/msm_jpeg_core.c
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_core.c
@@ -17,122 +17,130 @@
 #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)
-{
+int msm_jpeg_core_reset(struct msm_jpeg_device *pgmn_dev, 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;
+	JPEG_DBG("%s:%d] reset", __func__, __LINE__);
+	memset(&pgmn_dev->fe_pingpong_buf, 0,
+		sizeof(pgmn_dev->fe_pingpong_buf));
+	pgmn_dev->fe_pingpong_buf.is_fe = 1;
+	memset(&pgmn_dev->we_pingpong_buf, 0,
+		sizeof(pgmn_dev->we_pingpong_buf));
+	spin_lock_irqsave(&pgmn_dev->reset_lock, flags);
+	pgmn_dev->reset_done_ack = 0;
 	msm_jpeg_hw_reset(base, size);
-	spin_unlock_irqrestore(&reset_lock, flags);
+	spin_unlock_irqrestore(&pgmn_dev->reset_lock, flags);
 	rc = wait_event_interruptible_timeout(
-			reset_wait,
-			reset_done_ack,
+			pgmn_dev->reset_wait,
+			pgmn_dev->reset_done_ack,
 			msecs_to_jiffies(tm));
 
-	if (!reset_done_ack) {
+	if (!pgmn_dev->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);
+	spin_lock_irqsave(&pgmn_dev->reset_lock, flags);
+	pgmn_dev->reset_done_ack = 0;
+	spin_unlock_irqrestore(&pgmn_dev->reset_lock, flags);
 
 	return 0;
 }
 
-void msm_jpeg_core_release(int release_buf, int domain_num)
-{
+void msm_jpeg_core_release(struct msm_jpeg_device *pgmn_dev,
+	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;
+		if (pgmn_dev->we_pingpong_buf.buf_status[i] &&
+			pgmn_dev->release_buf)
+			msm_jpeg_platform_p2v(pgmn_dev,
+				pgmn_dev->we_pingpong_buf.buf[i].file,
+				&pgmn_dev->we_pingpong_buf.buf[i].handle,
+					domain_num);
+		pgmn_dev->we_pingpong_buf.buf_status[i] = 0;
 	}
 }
 
-void msm_jpeg_core_init(void)
+void msm_jpeg_core_init(struct msm_jpeg_device *pgmn_dev)
 {
-	init_waitqueue_head(&reset_wait);
-	spin_lock_init(&reset_lock);
+	init_waitqueue_head(&pgmn_dev->reset_wait);
+	spin_lock_init(&pgmn_dev->reset_lock);
 }
 
-int msm_jpeg_core_fe_start(void)
+int msm_jpeg_core_fe_start(struct msm_jpeg_device *pgmn_dev)
 {
-	msm_jpeg_hw_fe_start();
+	msm_jpeg_hw_fe_start(pgmn_dev->base);
 	return 0;
 }
 
 /* fetch engine */
-int msm_jpeg_core_fe_buf_update(struct msm_jpeg_core_buf *buf)
+int msm_jpeg_core_fe_buf_update(struct msm_jpeg_device *pgmn_dev,
+	struct msm_jpeg_core_buf *buf)
 {
+	if (0 == buf->cbcr_len)
+		buf->cbcr_buffer_addr = 0x0;
 	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);
+	return msm_jpeg_hw_pingpong_update(&pgmn_dev->fe_pingpong_buf, buf,
+		pgmn_dev->base);
 }
 
-void *msm_jpeg_core_fe_pingpong_irq(int jpeg_irq_status, void *context)
+void *msm_jpeg_core_fe_pingpong_irq(int jpeg_irq_status,
+	struct msm_jpeg_device *pgmn_dev)
 {
-	return msm_jpeg_hw_pingpong_irq(&fe_pingpong_buf);
+	return msm_jpeg_hw_pingpong_irq(&pgmn_dev->fe_pingpong_buf);
 }
 
 /* write engine */
-int msm_jpeg_core_we_buf_update(struct msm_jpeg_core_buf *buf)
-{
+int msm_jpeg_core_we_buf_update(struct msm_jpeg_device *pgmn_dev,
+	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;
+	pgmn_dev->we_pingpong_buf.buf[0] = *buf;
+	pgmn_dev->we_pingpong_buf.buf_status[0] = 1;
 	msm_jpeg_hw_we_buffer_update(
-			&we_pingpong_buf.buf[0], 0);
+		&pgmn_dev->we_pingpong_buf.buf[0], 0, pgmn_dev->base);
 
 	return 0;
 }
 
-int msm_jpeg_core_we_buf_reset(struct msm_jpeg_hw_buf *buf)
+int msm_jpeg_core_we_buf_reset(struct msm_jpeg_device *pgmn_dev,
+	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;
+		if (pgmn_dev->we_pingpong_buf.buf[i].y_buffer_addr
+			== buf->y_buffer_addr)
+			pgmn_dev->we_pingpong_buf.buf_status[i] = 0;
 	}
 	return 0;
 }
 
-void *msm_jpeg_core_we_pingpong_irq(int jpeg_irq_status, void *context)
+void *msm_jpeg_core_we_pingpong_irq(int jpeg_irq_status,
+	struct msm_jpeg_device *pgmn_dev)
 {
 	JPEG_DBG("%s:%d]\n", __func__, __LINE__);
 
-	return msm_jpeg_hw_pingpong_irq(&we_pingpong_buf);
+	return msm_jpeg_hw_pingpong_irq(&pgmn_dev->we_pingpong_buf);
 }
 
-void *msm_jpeg_core_framedone_irq(int jpeg_irq_status, void *context)
+void *msm_jpeg_core_framedone_irq(int jpeg_irq_status,
+	struct msm_jpeg_device *pgmn_dev)
 {
 	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();
+	buf_p = msm_jpeg_hw_pingpong_active_buffer(
+		&pgmn_dev->we_pingpong_buf);
+	if (buf_p && !pgmn_dev->decode_flag) {
+		buf_p->framedone_len =
+			msm_jpeg_hw_encode_output_size(pgmn_dev->base);
 		JPEG_DBG("%s:%d] framedone_len %d\n", __func__, __LINE__,
 			buf_p->framedone_len);
 	}
@@ -140,14 +148,16 @@
 	return buf_p;
 }
 
-void *msm_jpeg_core_reset_ack_irq(int jpeg_irq_status, void *context)
+void *msm_jpeg_core_reset_ack_irq(int jpeg_irq_status,
+	struct msm_jpeg_device *pgmn_dev)
 {
 	/* @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)
+void *msm_jpeg_core_err_irq(int jpeg_irq_status,
+	struct msm_jpeg_device *pgmn_dev)
 {
 	JPEG_PR_ERR("%s:%d]\n", __func__, jpeg_irq_status);
 	return NULL;
@@ -155,15 +165,32 @@
 
 static int (*msm_jpeg_irq_handler) (int, void *, void *);
 
+void msm_jpeg_core_return_buffers(struct msm_jpeg_device *pgmn_dev,
+	 int jpeg_irq_status)
+{
+	void *data = NULL;
+	data = msm_jpeg_core_fe_pingpong_irq(jpeg_irq_status,
+		pgmn_dev);
+	if (msm_jpeg_irq_handler)
+		msm_jpeg_irq_handler(MSM_JPEG_HW_MASK_COMP_FE,
+			pgmn_dev, data);
+	data = msm_jpeg_core_we_pingpong_irq(jpeg_irq_status,
+		pgmn_dev);
+	if (msm_jpeg_irq_handler)
+		msm_jpeg_irq_handler(MSM_JPEG_HW_MASK_COMP_WE,
+			pgmn_dev, data);
+}
+
 irqreturn_t msm_jpeg_core_irq(int irq_num, void *context)
 {
 	void *data = NULL;
 	unsigned long flags;
 	int jpeg_irq_status;
+	struct msm_jpeg_device *pgmn_dev = (struct msm_jpeg_device *)context;
 
 	JPEG_DBG("%s:%d] irq_num = %d\n", __func__, __LINE__, irq_num);
 
-	jpeg_irq_status = msm_jpeg_hw_irq_get_status();
+	jpeg_irq_status = msm_jpeg_hw_irq_get_status(pgmn_dev->base);
 
 	JPEG_DBG("%s:%d] jpeg_irq_status = %0x\n", __func__, __LINE__,
 		jpeg_irq_status);
@@ -171,18 +198,26 @@
 	/*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);
+			JPEG_IRQ_CLEAR_ALL, pgmn_dev->base);
 	} else if (jpeg_irq_status & 0x1) {
 		msm_jpeg_hw_irq_clear(JPEG_IRQ_CLEAR_BMSK,
-			JPEG_IRQ_CLEAR_ALL);
+			JPEG_IRQ_CLEAR_ALL, pgmn_dev->base);
+		if (pgmn_dev->decode_flag)
+			msm_jpeg_decode_status(pgmn_dev->base);
 	} else {
 		msm_jpeg_hw_irq_clear(JPEG_IRQ_CLEAR_BMSK,
-			jpeg_irq_status);
+			jpeg_irq_status, pgmn_dev->base);
 	}
 
 	if (msm_jpeg_hw_irq_is_frame_done(jpeg_irq_status)) {
+		/* send fe ping pong irq */
+		data = msm_jpeg_core_fe_pingpong_irq(jpeg_irq_status,
+			pgmn_dev);
+		if (msm_jpeg_irq_handler)
+			msm_jpeg_irq_handler(MSM_JPEG_HW_MASK_COMP_FE,
+				context, data);
 		data = msm_jpeg_core_framedone_irq(jpeg_irq_status,
-			context);
+			pgmn_dev);
 		if (msm_jpeg_irq_handler)
 			msm_jpeg_irq_handler(
 				MSM_JPEG_HW_MASK_COMP_FRAMEDONE,
@@ -190,11 +225,11 @@
 	}
 	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);
+			pgmn_dev);
+		spin_lock_irqsave(&pgmn_dev->reset_lock, flags);
+		pgmn_dev->reset_done_ack = 1;
+		spin_unlock_irqrestore(&pgmn_dev->reset_lock, flags);
+		wake_up(&pgmn_dev->reset_wait);
 		if (msm_jpeg_irq_handler)
 			msm_jpeg_irq_handler(
 				MSM_JPEG_HW_MASK_COMP_RESET_ACK,
@@ -203,7 +238,10 @@
 
 	/* 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 (pgmn_dev->decode_flag)
+			msm_jpeg_decode_status(pgmn_dev->base);
+		msm_jpeg_core_return_buffers(pgmn_dev, jpeg_irq_status);
+		data = msm_jpeg_core_err_irq(jpeg_irq_status, pgmn_dev);
 		if (msm_jpeg_irq_handler)
 			msm_jpeg_irq_handler(MSM_JPEG_HW_MASK_COMP_ERR,
 				context, data);
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_core.h b/drivers/media/video/msm/jpeg_10/msm_jpeg_core.h
index b5c725c..212eaff 100644
--- a/drivers/media/video/msm/jpeg_10/msm_jpeg_core.h
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_core.h
@@ -15,6 +15,7 @@
 
 #include <linux/interrupt.h>
 #include "msm_jpeg_hw.h"
+#include "msm_jpeg_sync.h"
 
 #define msm_jpeg_core_buf msm_jpeg_hw_buf
 
@@ -23,13 +24,17 @@
 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_fe_buf_update(struct msm_jpeg_device *pgmn_dev,
+	struct msm_jpeg_core_buf *buf);
+int msm_jpeg_core_we_buf_update(struct msm_jpeg_device *pgmn_dev,
+	struct msm_jpeg_core_buf *buf);
+int msm_jpeg_core_we_buf_reset(struct msm_jpeg_device *pgmn_dev,
+	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);
+int msm_jpeg_core_reset(struct msm_jpeg_device *pgmn_dev, uint8_t op_mode,
+	void *base, int size);
+int msm_jpeg_core_fe_start(struct msm_jpeg_device *);
 
-void msm_jpeg_core_release(int, int);
-void msm_jpeg_core_init(void);
+void msm_jpeg_core_release(struct msm_jpeg_device *, int);
+void msm_jpeg_core_init(struct msm_jpeg_device *);
 #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
index 45a9a38..0662f54 100644
--- a/drivers/media/video/msm/jpeg_10/msm_jpeg_dev.c
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_dev.c
@@ -31,9 +31,7 @@
 #include "msm_jpeg_common.h"
 
 #define MSM_JPEG_NAME "jpeg"
-#define MSM_JPEGE1_NAME "jpege1"
-#define MSM_JPEGD_NAME "jpegd"
-
+#define DEV_NAME_LEN 10
 
 static int msm_jpeg_open(struct inode *inode, struct file *filp)
 {
@@ -146,7 +144,7 @@
 	int rc = -1;
 	struct device *dev;
 	struct msm_jpeg_device *msm_jpeg_device_p;
-	char devname[10];
+	char devname[DEV_NAME_LEN];
 
 	msm_jpeg_device_p = kzalloc(sizeof(struct msm_jpeg_device), GFP_ATOMIC);
 	if (!msm_jpeg_device_p) {
@@ -158,7 +156,7 @@
 
 	if (pdev->dev.of_node)
 		of_property_read_u32((&pdev->dev)->of_node, "cell-index",
-								&pdev->id);
+			&pdev->id);
 
 	snprintf(devname, sizeof(devname), "%s%d", MSM_JPEG_NAME, pdev->id);
 
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_hw.c b/drivers/media/video/msm/jpeg_10/msm_jpeg_hw.c
index 0bfb6a8..e311e4c 100644
--- a/drivers/media/video/msm/jpeg_10/msm_jpeg_hw.c
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_hw.c
@@ -17,11 +17,8 @@
 
 #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)
+	struct msm_jpeg_hw_buf *buf, void *base)
 {
 	int buf_free_index = -1;
 
@@ -41,11 +38,13 @@
 	if (pingpong_hw->is_fe) {
 		/* it is fe */
 		msm_jpeg_hw_fe_buffer_update(
-			&pingpong_hw->buf[buf_free_index], buf_free_index);
+			&pingpong_hw->buf[buf_free_index], buf_free_index,
+			base);
 	} else {
 		/* it is we */
 		msm_jpeg_hw_we_buffer_update(
-			&pingpong_hw->buf[buf_free_index], buf_free_index);
+			&pingpong_hw->buf[buf_free_index], buf_free_index,
+			base);
 	}
 	return 0;
 }
@@ -81,12 +80,10 @@
 		JPEG_IRQ_STATUS_BMSK, {0} },
 };
 
-int msm_jpeg_hw_irq_get_status(void)
+int msm_jpeg_hw_irq_get_status(void *base)
 {
 	uint32_t n_irq_status = 0;
-	rmb();
-	n_irq_status = msm_jpeg_hw_read(&hw_cmd_irq_get_status[0]);
-	rmb();
+	n_irq_status = msm_jpeg_hw_read(&hw_cmd_irq_get_status[0], base);
 	return n_irq_status;
 }
 
@@ -97,11 +94,12 @@
 	JPEG_ENCODE_OUTPUT_SIZE_STATUS_BMSK, {0} } ,
 };
 
-long msm_jpeg_hw_encode_output_size(void)
+long msm_jpeg_hw_encode_output_size(void *base)
 {
 	uint32_t encode_output_size = 0;
 
-	encode_output_size = msm_jpeg_hw_read(&hw_cmd_encode_output_size[0]);
+	encode_output_size = msm_jpeg_hw_read(&hw_cmd_encode_output_size[0],
+		base);
 
 	return encode_output_size;
 }
@@ -112,12 +110,12 @@
 		JPEG_IRQ_CLEAR_BMSK, {JPEG_IRQ_CLEAR_ALL} },
 };
 
-void msm_jpeg_hw_irq_clear(uint32_t mask, uint32_t data)
+void msm_jpeg_hw_irq_clear(uint32_t mask, uint32_t data, void *base)
 {
 	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]);
+	msm_jpeg_hw_write(&hw_cmd_irq_clear[0], base);
 }
 
 struct msm_jpeg_hw_cmd hw_cmd_fe_ping_update[] = {
@@ -137,26 +135,26 @@
 };
 
 void msm_jpeg_hw_fe_buffer_update(struct msm_jpeg_hw_buf *p_input,
-	uint8_t pingpong_index)
+	uint8_t pingpong_index, void *base)
 {
 	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++);
+		msm_jpeg_hw_write(hw_cmd_p++, base);
 		wmb();
-		msm_jpeg_hw_write(hw_cmd_p++);
+		msm_jpeg_hw_write(hw_cmd_p++, base);
 		wmb();
-		msm_jpeg_hw_write(hw_cmd_p++);
+		msm_jpeg_hw_write(hw_cmd_p++, base);
 		wmb();
 		hw_cmd_p->data = p_input->y_buffer_addr;
-		msm_jpeg_hw_write(hw_cmd_p++);
+		msm_jpeg_hw_write(hw_cmd_p++, base);
 		wmb();
-		msm_jpeg_hw_write(hw_cmd_p++);
+		msm_jpeg_hw_write(hw_cmd_p++, base);
 		wmb();
 		hw_cmd_p->data = p_input->cbcr_buffer_addr;
-		msm_jpeg_hw_write(hw_cmd_p++);
+		msm_jpeg_hw_write(hw_cmd_p++, base);
 		wmb();
 
 	}
@@ -169,9 +167,9 @@
 		JPEG_CMD_BMSK, {JPEG_OFFLINE_CMD_START} },
 };
 
-void msm_jpeg_hw_fe_start(void)
+void msm_jpeg_hw_fe_start(void *base)
 {
-	msm_jpeg_hw_write(&hw_cmd_fe_start[0]);
+	msm_jpeg_hw_write(&hw_cmd_fe_start[0], base);
 
 	return;
 }
@@ -180,20 +178,46 @@
 	/* 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} },
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN1_WR_PNTR_ADDR,
+		JPEG_PLN0_WR_PNTR_BMSK, {0} },
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN2_WR_PNTR_ADDR,
+		JPEG_PLN0_WR_PNTR_BMSK, {0} },
 };
 
+void msm_jpeg_decode_status(void *base)
+{
+	uint32_t data;
+	data = readl_relaxed(base + JPEG_DECODE_MCUS_DECODED_STATUS);
+	JPEG_DBG_HIGH("Decode MCUs decode status %u", data);
+	data = readl_relaxed(base + JPEG_DECODE_BITS_CONSUMED_STATUS);
+	JPEG_DBG_HIGH("Decode bits consumed status %u", data);
+	data = readl_relaxed(base + JPEG_DECODE_PRED_Y_STATE);
+	JPEG_DBG_HIGH("Decode prediction Y state %u", data);
+	data = readl_relaxed(base + JPEG_DECODE_PRED_C_STATE);
+	JPEG_DBG_HIGH("Decode prediction C state %u", data);
+	data = readl_relaxed(base + JPEG_DECODE_RSM_STATE);
+	JPEG_DBG_HIGH("Decode prediction RSM state %u", data);
+}
+
+
 void msm_jpeg_hw_we_buffer_update(struct msm_jpeg_hw_buf *p_input,
-	uint8_t pingpong_index)
+	uint8_t pingpong_index, void *base)
 {
 	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++);
-
+		JPEG_PR_ERR("%s Output pln0 buffer address is %x\n", __func__,
+			p_input->y_buffer_addr);
+		msm_jpeg_hw_write(hw_cmd_p++, base);
+		hw_cmd_p->data = p_input->cbcr_buffer_addr;
+		JPEG_PR_ERR("%s Output pln1 buffer address is %x\n", __func__,
+			p_input->cbcr_buffer_addr);
+		msm_jpeg_hw_write(hw_cmd_p++, base);
+		JPEG_PR_ERR("%s Output pln2 buffer address is %x\n", __func__,
+			p_input->pln2_addr);
+		msm_jpeg_hw_write(hw_cmd_p++, base);
 	}
 	return;
 }
@@ -210,31 +234,26 @@
 		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++);
+	msm_jpeg_hw_write(hw_cmd_p++, base);
 	wmb();
-	msm_jpeg_hw_write(hw_cmd_p++);
+	msm_jpeg_hw_write(hw_cmd_p++, base);
 	wmb();
-	msm_jpeg_hw_write(hw_cmd_p++);
+	msm_jpeg_hw_write(hw_cmd_p++, base);
 	wmb();
-	msm_jpeg_hw_write(hw_cmd_p);
+	msm_jpeg_hw_write(hw_cmd_p, base);
 	wmb();
 
 	return;
 }
 
-uint32_t msm_jpeg_hw_read(struct msm_jpeg_hw_cmd *hw_cmd_p)
+uint32_t msm_jpeg_hw_read(struct msm_jpeg_hw_cmd *hw_cmd_p,
+	 void *jpeg_region_base)
 {
 	uint32_t *paddr;
 	uint32_t data;
@@ -247,7 +266,8 @@
 	return data;
 }
 
-void msm_jpeg_hw_write(struct msm_jpeg_hw_cmd *hw_cmd_p)
+void msm_jpeg_hw_write(struct msm_jpeg_hw_cmd *hw_cmd_p,
+	void *jpeg_region_base)
 {
 	uint32_t *paddr;
 	uint32_t old_data, new_data;
@@ -266,17 +286,18 @@
 	writel_relaxed(new_data, paddr);
 }
 
-int msm_jpeg_hw_wait(struct msm_jpeg_hw_cmd *hw_cmd_p, int m_us)
+int msm_jpeg_hw_wait(struct msm_jpeg_hw_cmd *hw_cmd_p, int m_us,
+	void *base)
 {
 	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);
+	data = msm_jpeg_hw_read(hw_cmd_p, base);
 	if (data != wait_data) {
 		while (tm) {
 			udelay(m_us);
-			data = msm_jpeg_hw_read(hw_cmd_p);
+			data = msm_jpeg_hw_read(hw_cmd_p, base);
 			if (data == wait_data)
 				break;
 			tm--;
@@ -295,41 +316,42 @@
 	}
 }
 
-int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *hw_cmd_p, int m_cmds)
+int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *hw_cmd_p, int m_cmds,
+	uint32_t max_size, void *base)
 {
 	int is_copy_to_user = -1;
 	uint32_t data;
 
 	while (m_cmds--) {
-		if (hw_cmd_p->offset > jpeg_region_size) {
+		if (hw_cmd_p->offset > max_size) {
 			JPEG_PR_ERR("%s:%d] %d exceed hw region %d\n", __func__,
-				__LINE__, hw_cmd_p->offset, jpeg_region_size);
+				__LINE__, hw_cmd_p->offset, max_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);
+			hw_cmd_p->data = msm_jpeg_hw_read(hw_cmd_p, base);
 			is_copy_to_user = 1;
 			break;
 
 		case MSM_JPEG_HW_CMD_TYPE_WRITE:
-			msm_jpeg_hw_write(hw_cmd_p);
+			msm_jpeg_hw_write(hw_cmd_p, base);
 			break;
 
 		case MSM_JPEG_HW_CMD_TYPE_WRITE_OR:
-			data = msm_jpeg_hw_read(hw_cmd_p);
+			data = msm_jpeg_hw_read(hw_cmd_p, base);
 			hw_cmd_p->data = (hw_cmd_p->data & hw_cmd_p->mask) |
 				data;
-			msm_jpeg_hw_write(hw_cmd_p);
+			msm_jpeg_hw_write(hw_cmd_p, base);
 			break;
 
 		case MSM_JPEG_HW_CMD_TYPE_UWAIT:
-			msm_jpeg_hw_wait(hw_cmd_p, 1);
+			msm_jpeg_hw_wait(hw_cmd_p, 1, base);
 			break;
 
 		case MSM_JPEG_HW_CMD_TYPE_MWAIT:
-			msm_jpeg_hw_wait(hw_cmd_p, 1000);
+			msm_jpeg_hw_wait(hw_cmd_p, 1000, base);
 			break;
 
 		case MSM_JPEG_HW_CMD_TYPE_UDELAY:
@@ -350,15 +372,14 @@
 	return is_copy_to_user;
 }
 
-void msm_jpeg_io_dump(int size)
+void msm_jpeg_io_dump(void *base, int size)
 {
 	char line_str[128], *p_str;
-	void __iomem *addr = jpeg_region_base;
+	void __iomem *addr = (void __iomem *)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);
+	JPEG_DBG_HIGH("%s:%d] %p %d", __func__, __LINE__, addr, size);
 	line_str[0] = '\0';
 	p_str = line_str;
 	for (i = 0; i < size/4; i++) {
@@ -370,11 +391,12 @@
 		snprintf(p_str, 12, "%08x ", data);
 		p_str += 9;
 		if ((i + 1) % 4 == 0) {
-			JPEG_PR_ERR("%s\n", line_str);
+			JPEG_DBG_HIGH("%s\n", line_str);
 			line_str[0] = '\0';
 			p_str = line_str;
 		}
 	}
 	if (line_str[0] != '\0')
-		JPEG_PR_ERR("%s\n", line_str);
+		JPEG_DBG_HIGH("%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
index 73a0e27..e90b941 100644
--- a/drivers/media/video/msm/jpeg_10/msm_jpeg_hw.h
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_hw.h
@@ -28,6 +28,8 @@
 	uint32_t cbcr_len;
 	uint32_t num_of_mcu_rows;
 	struct ion_handle *handle;
+	uint32_t pln2_addr;
+	uint32_t pln2_offset;
 };
 
 struct msm_jpeg_hw_pingpong {
@@ -38,14 +40,14 @@
 };
 
 int msm_jpeg_hw_pingpong_update(struct msm_jpeg_hw_pingpong *pingpong_hw,
-	struct msm_jpeg_hw_buf *buf);
+	struct msm_jpeg_hw_buf *buf, void *);
 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);
+void msm_jpeg_hw_irq_clear(uint32_t, uint32_t, void *);
+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 \
@@ -56,13 +58,14 @@
 #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_DCD_UNESCAPED_FF | \
+		MSM_JPEG_HW_IRQ_STATUS_DCD_HUFFMAN_ERROR | \
+		MSM_JPEG_HW_IRQ_STATUS_DCD_COEFFICIENT_ERR | \
+		MSM_JPEG_HW_IRQ_STATUS_DCD_MISSING_BIT_STUFF | \
+		MSM_JPEG_HW_IRQ_STATUS_DCD_SCAN_UNDERFLOW | \
+		MSM_JPEG_HW_IRQ_STATUS_DCD_INVALID_RSM | \
+		MSM_JPEG_HW_IRQ_STATUS_DCD_INVALID_RSM_SEQ | \
+		MSM_JPEG_HW_IRQ_STATUS_DCD_MISSING_RSM | \
 		MSM_JPEG_HW_IRQ_STATUS_VIOLATION_MASK)
 
 #define msm_jpeg_hw_irq_is_frame_done(jpeg_irq_status) \
@@ -77,25 +80,26 @@
 	(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);
+	uint8_t pingpong_index, void *);
 void msm_jpeg_hw_we_buffer_update(struct msm_jpeg_hw_buf *p_input,
-	uint8_t pingpong_index);
+	uint8_t pingpong_index, void *);
 
 void msm_jpeg_hw_we_buffer_cfg(uint8_t is_realtime);
 
-void msm_jpeg_hw_fe_start(void);
+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);
+uint32_t msm_jpeg_hw_read(struct msm_jpeg_hw_cmd *, void *);
+void msm_jpeg_hw_write(struct msm_jpeg_hw_cmd *, void *);
+int msm_jpeg_hw_wait(struct msm_jpeg_hw_cmd *, int, void *);
+void msm_jpeg_hw_delay(struct msm_jpeg_hw_cmd *, int);
+int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *, int ,
+	uint32_t , void *);
 void msm_jpeg_hw_region_dump(int size);
-void msm_jpeg_io_dump(int size);
+void msm_jpeg_io_dump(void *base, int size);
+void msm_jpeg_decode_status(void *base);
 
 #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
index ae64c32..928d59e 100644
--- a/drivers/media/video/msm/jpeg_10/msm_jpeg_hw_reg.h
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_hw_reg.h
@@ -37,30 +37,25 @@
 #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 MSM_JPEG_HW_IRQ_STATUS_DCD_UNESCAPED_FF      (0x1<<19)
+#define MSM_JPEG_HW_IRQ_STATUS_DCD_HUFFMAN_ERROR     (0x1<<20)
+#define MSM_JPEG_HW_IRQ_STATUS_DCD_COEFFICIENT_ERR   (0x1<<21)
+#define MSM_JPEG_HW_IRQ_STATUS_DCD_MISSING_BIT_STUFF (0x1<<22)
+#define MSM_JPEG_HW_IRQ_STATUS_DCD_SCAN_UNDERFLOW    (0x1<<23)
+#define MSM_JPEG_HW_IRQ_STATUS_DCD_INVALID_RSM       (0x1<<24)
+#define MSM_JPEG_HW_IRQ_STATUS_DCD_INVALID_RSM_SEQ   (0x1<<25)
+#define MSM_JPEG_HW_IRQ_STATUS_DCD_MISSING_RSM       (0x1<<26)
+#define MSM_JPEG_HW_IRQ_STATUS_VIOLATION_MASK        (0x1<<29)
 
 #define JPEG_OFFLINE_CMD_START 0x00000001
 
-#define JPEG_RESET_DEFAULT 0x00000003 /* cfff? */
+#define JPEG_RESET_DEFAULT 0x00020000
 
 #define JPEG_IRQ_DISABLE_ALL 0x00000000
 #define JPEG_IRQ_CLEAR_ALL 0xFFFFFFFF
@@ -87,6 +82,9 @@
 #define JPEG_PLN1_WR_PNTR_ADDR (JPEG_REG_BASE + 0x000000D0)
 #define JPEG_PLN1_WR_PNTR_BMSK 0xFFFFFFFF
 
+#define JPEG_PLN2_WR_PNTR_ADDR (JPEG_REG_BASE + 0x000000D4)
+#define JPEG_PLN2_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
@@ -103,6 +101,11 @@
 #define JPEG_ENCODE_OUTPUT_SIZE_STATUS_ADDR (JPEG_REG_BASE + 0x00000180)
 #define JPEG_ENCODE_OUTPUT_SIZE_STATUS_BMSK 0x1FFFFFFF
 
+#define JPEG_DECODE_MCUS_DECODED_STATUS   (JPEG_REG_BASE + 0x00000258)
+#define JPEG_DECODE_BITS_CONSUMED_STATUS  (JPEG_REG_BASE + 0x0000025C)
+#define JPEG_DECODE_PRED_Y_STATE          (JPEG_REG_BASE + 0x00000260)
+#define JPEG_DECODE_PRED_C_STATE          (JPEG_REG_BASE + 0x00000264)
+#define JPEG_DECODE_RSM_STATE             (JPEG_REG_BASE + 0x00000268)
 
 #define VBIF_BASE_ADDRESS                      0xFDA60000
 #define VBIF_REGION_SIZE                       0xC30
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_platform.c b/drivers/media/video/msm/jpeg_10/msm_jpeg_platform.c
index 981c56c..0370f63 100644
--- a/drivers/media/video/msm/jpeg_10/msm_jpeg_platform.c
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_platform.c
@@ -26,36 +26,32 @@
 #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)
+void msm_jpeg_platform_p2v(struct msm_jpeg_device *pgmn_dev, 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);
+	ion_unmap_iommu(pgmn_dev->jpeg_client, *ionhandle, domain_num, 0);
+	ion_free(pgmn_dev->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)
-{
+uint32_t msm_jpeg_platform_v2p(struct msm_jpeg_device *pgmn_dev, 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);
+	*ionhandle = ion_import_dma_buf(pgmn_dev->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__,
+	rc = ion_map_iommu(pgmn_dev->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
@@ -81,7 +77,7 @@
 	return paddr;
 error1:
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
-	ion_free(jpeg_client, *ionhandle);
+	ion_free(pgmn_dev->jpeg_client, *ionhandle);
 #endif
 	return 0;
 }
@@ -149,10 +145,10 @@
 	}
 	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_mem->start, jpeg_irq);
 
 	jpeg_io = request_mem_region(jpeg_mem->start,
-					resource_size(jpeg_mem), pdev->name);
+		resource_size(jpeg_mem), pdev->name);
 	if (!jpeg_io) {
 		JPEG_PR_ERR("%s: region already claimed\n", __func__);
 		return -EBUSY;
@@ -165,14 +161,14 @@
 		goto fail1;
 	}
 
-	jpeg_vbif = ioremap(VBIF_BASE_ADDRESS, VBIF_REGION_SIZE);
-	if (!jpeg_vbif) {
+	pgmn_dev->jpeg_vbif = ioremap(VBIF_BASE_ADDRESS, VBIF_REGION_SIZE);
+	if (!pgmn_dev->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);
+		(uint32_t)pgmn_dev->jpeg_vbif);
 
 	pgmn_dev->jpeg_fs = regulator_get(&pgmn_dev->pdev->dev, "vdd");
 	rc = regulator_enable(pgmn_dev->jpeg_fs);
@@ -202,9 +198,8 @@
 					(uint32_t)pgmn_dev->iommu_ctx_arr[i]);
 	}
 #endif
-	set_vbif_params(jpeg_vbif);
+	set_vbif_params(pgmn_dev->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) {
@@ -218,7 +213,7 @@
 	*irq  = jpeg_irq;
 
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
-	jpeg_client = msm_ion_client_create(-1, "camera/jpeg");
+	pgmn_dev->jpeg_client = msm_ion_client_create(-1, "camera/jpeg");
 #endif
 	JPEG_DBG("%s:%d] success\n", __func__, __LINE__);
 
@@ -276,11 +271,11 @@
 		regulator_disable(pgmn_dev->jpeg_fs);
 		pgmn_dev->jpeg_fs = NULL;
 	}
-	iounmap(jpeg_vbif);
+	iounmap(pgmn_dev->jpeg_vbif);
 	iounmap(base);
 	release_mem_region(mem->start, resource_size(mem));
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
-	ion_client_destroy(jpeg_client);
+	ion_client_destroy(pgmn_dev->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
index 8a37cef..cd80d2e 100644
--- a/drivers/media/video/msm/jpeg_10/msm_jpeg_platform.h
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_platform.h
@@ -18,12 +18,13 @@
 #include <linux/ion.h>
 #include <linux/iommu.h>
 #include <mach/iommu.h>
+#include "msm_jpeg_sync.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);
+void msm_jpeg_platform_p2v(struct msm_jpeg_device *pgmn_dev, struct file *file,
+	struct ion_handle **ionhandle, int domain_num);
+uint32_t msm_jpeg_platform_v2p(struct msm_jpeg_device *pgmn_dev, 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);
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_sync.c b/drivers/media/video/msm/jpeg_10/msm_jpeg_sync.c
index 6ac4a5e..a0aaf03 100644
--- a/drivers/media/video/msm/jpeg_10/msm_jpeg_sync.c
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_sync.c
@@ -22,7 +22,9 @@
 #include "msm_jpeg_platform.h"
 #include "msm_jpeg_common.h"
 
-static int release_buf;
+#define JPEG_REG_SIZE 0x308
+#define JPEG_DEV_CNT 3
+#define JPEG_DEC_ID 2
 
 inline void msm_jpeg_q_init(char const *name, struct msm_jpeg_q *q_p)
 {
@@ -143,15 +145,15 @@
 	return 0;
 }
 
-inline void msm_jpeg_outbuf_q_cleanup(struct msm_jpeg_q *q_p,
-				int domain_num)
+inline void msm_jpeg_outbuf_q_cleanup(struct msm_jpeg_device *pgmn_dev,
+	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,
+			msm_jpeg_platform_p2v(pgmn_dev, buf_p->file,
 				&buf_p->handle, domain_num);
 			JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
 			kfree(buf_p);
@@ -289,10 +291,10 @@
 	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);
+		rc = msm_jpeg_core_we_buf_update(pgmn_dev, buf_out);
 		kfree(buf_out);
 	} else {
-		msm_jpeg_core_we_buf_reset(buf_in);
+		msm_jpeg_core_we_buf_reset(pgmn_dev, buf_in);
 		JPEG_DBG("%s:%d] no output buffer\n", __func__, __LINE__);
 		rc = -2;
 	}
@@ -320,7 +322,7 @@
 	}
 
 	buf_cmd = buf_p->vbuf;
-	msm_jpeg_platform_p2v(buf_p->file, &buf_p->handle,
+	msm_jpeg_platform_p2v(pgmn_dev, buf_p->file, &buf_p->handle,
 		pgmn_dev->domain_num);
 	kfree(buf_p);
 
@@ -347,6 +349,7 @@
 {
 	struct msm_jpeg_buf buf_cmd;
 	struct msm_jpeg_core_buf *buf_p;
+	memset(&buf_cmd, 0x0, sizeof(struct msm_jpeg_buf));
 
 	JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
 	if (copy_from_user(&buf_cmd, arg, sizeof(struct msm_jpeg_buf))) {
@@ -364,7 +367,7 @@
 		__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_p->y_buffer_addr = msm_jpeg_platform_v2p(pgmn_dev, buf_cmd.fd,
 		buf_cmd.y_len, &buf_p->file, &buf_p->handle,
 		pgmn_dev->domain_num);
 	if (!buf_p->y_buffer_addr) {
@@ -372,9 +375,18 @@
 		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);
+
+	if (buf_cmd.cbcr_len)
+		buf_p->cbcr_buffer_addr = buf_p->y_buffer_addr +
+			buf_cmd.y_len;
+	else
+		buf_p->cbcr_buffer_addr = 0x0;
+
+	JPEG_DBG("%s:%d] After v2p pln0_addr =0x%x,pln0_len %d pl1_len %d",
+		__func__, __LINE__, buf_p->y_buffer_addr,
+		buf_cmd.y_len, buf_cmd.cbcr_len);
 	buf_p->y_len = buf_cmd.y_len;
+	buf_p->cbcr_len = buf_cmd.cbcr_len;
 	buf_p->vbuf = buf_cmd;
 
 	msm_jpeg_q_in(&pgmn_dev->output_buf_q, buf_p);
@@ -403,9 +415,9 @@
 	buf_out = msm_jpeg_q_out(&pgmn_dev->input_buf_q);
 
 	if (buf_out) {
-		rc = msm_jpeg_core_fe_buf_update(buf_out);
+		rc = msm_jpeg_core_fe_buf_update(pgmn_dev, buf_out);
 		kfree(buf_out);
-		msm_jpeg_core_fe_start();
+		msm_jpeg_core_fe_start(pgmn_dev);
 	} else {
 		JPEG_DBG("%s:%d] no input buffer\n", __func__, __LINE__);
 		rc = -EFAULT;
@@ -433,8 +445,8 @@
 	}
 
 	buf_cmd = buf_p->vbuf;
-	msm_jpeg_platform_p2v(buf_p->file, &buf_p->handle,
-					pgmn_dev->domain_num);
+	msm_jpeg_platform_p2v(pgmn_dev, buf_p->file, &buf_p->handle,
+		pgmn_dev->domain_num);
 	kfree(buf_p);
 
 	JPEG_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
@@ -460,6 +472,7 @@
 {
 	struct msm_jpeg_core_buf *buf_p;
 	struct msm_jpeg_buf buf_cmd;
+	memset(&buf_cmd, 0x0, sizeof(struct msm_jpeg_buf));
 
 	if (copy_from_user(&buf_cmd, arg, sizeof(struct msm_jpeg_buf))) {
 		JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
@@ -475,20 +488,26 @@
 	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_p->y_buffer_addr    = msm_jpeg_platform_v2p(pgmn_dev, 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;
+	buf_p->y_len = buf_cmd.y_len;
+	buf_p->cbcr_len = buf_cmd.cbcr_len;
+	if (buf_cmd.cbcr_len)
+		buf_p->cbcr_buffer_addr = buf_p->y_buffer_addr + buf_cmd.y_len
+			+ buf_cmd.cbcr_off;
+	else
+		buf_p->cbcr_buffer_addr = 0x0;
+
 	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) {
+	if (!buf_p->y_buffer_addr) {
 		JPEG_PR_ERR("%s:%d] v2p wrong\n", __func__, __LINE__);
 		kfree(buf_p);
 		return -EFAULT;
@@ -559,13 +578,15 @@
 	JPEG_DBG("%s:%d] platform resources - mem %p, base %p, irq %d\n",
 		__func__, __LINE__,
 		pgmn_dev->mem, pgmn_dev->base, pgmn_dev->irq);
+	pgmn_dev->res_size = resource_size(pgmn_dev->mem);
 
 	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, &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();
+	msm_jpeg_core_init(pgmn_dev);
 
 	JPEG_DBG("%s:%d] success\n", __func__, __LINE__);
 	return rc;
@@ -583,13 +604,14 @@
 	pgmn_dev->open_count--;
 	mutex_unlock(&pgmn_dev->lock);
 
-	msm_jpeg_core_release(release_buf, pgmn_dev->domain_num);
+	msm_jpeg_core_release(pgmn_dev, 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_outbuf_q_cleanup(pgmn_dev, &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);
+	msm_jpeg_outbuf_q_cleanup(pgmn_dev, &pgmn_dev->input_buf_q,
+		pgmn_dev->domain_num);
 
 	JPEG_DBG("%s:%d]\n", __func__, __LINE__);
 	if (pgmn_dev->open_count)
@@ -598,6 +620,7 @@
 	msm_jpeg_platform_release(pgmn_dev->mem, pgmn_dev->base,
 		pgmn_dev->irq, pgmn_dev);
 
+	JPEG_DBG("%s:%d]\n", __func__, __LINE__);
 	return 0;
 }
 
@@ -612,7 +635,8 @@
 		return -EFAULT;
 	}
 
-	is_copy_to_user = msm_jpeg_hw_exec_cmds(&hw_cmd, 1);
+	is_copy_to_user = msm_jpeg_hw_exec_cmds(&hw_cmd, 1,
+		pgmn_dev->res_size, pgmn_dev->base);
 	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);
@@ -657,7 +681,8 @@
 
 	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);
+	is_copy_to_user = msm_jpeg_hw_exec_cmds(hw_cmd_p, m,
+		 pgmn_dev->res_size, pgmn_dev->base);
 
 	if (is_copy_to_user >= 0) {
 		if (copy_to_user(arg, hw_cmds_p, len)) {
@@ -678,12 +703,12 @@
 
 	JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
 
-	release_buf = 1;
+	pgmn_dev->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);
+			msm_jpeg_core_fe_buf_update(pgmn_dev, buf_out);
 			kfree(buf_out);
 		} else {
 			JPEG_DBG("%s:%d] no input buffer\n", __func__,
@@ -696,8 +721,8 @@
 		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;
+			msm_jpeg_core_we_buf_update(pgmn_dev, buf_out_free[i]);
+			pgmn_dev->release_buf = 0;
 		} else {
 			JPEG_DBG("%s:%d] no output buffer\n",
 			__func__, __LINE__);
@@ -708,6 +733,7 @@
 	for (i = 0; i < 2; i++)
 		kfree(buf_out_free[i]);
 
+	msm_jpeg_io_dump(pgmn_dev->base, JPEG_REG_SIZE);
 	rc = msm_jpeg_ioctl_hw_cmds(pgmn_dev, arg);
 	JPEG_DBG("%s:%d]\n", __func__, __LINE__);
 	return rc;
@@ -727,7 +753,7 @@
 
 	pgmn_dev->op_mode = ctrl_cmd.type;
 
-	rc = msm_jpeg_core_reset(pgmn_dev->op_mode, pgmn_dev->base,
+	rc = msm_jpeg_core_reset(pgmn_dev, pgmn_dev->op_mode, pgmn_dev->base,
 		resource_size(pgmn_dev->mem));
 	return rc;
 }
@@ -736,7 +762,7 @@
 	unsigned long arg)
 {
 	JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
-	msm_jpeg_io_dump(arg);
+	msm_jpeg_io_dump(pgmn_dev->base, JPEG_REG_SIZE);
 	return 0;
 }
 
@@ -836,9 +862,10 @@
 
 int __msm_jpeg_init(struct msm_jpeg_device *pgmn_dev)
 {
-	int rc = 0, i = 0;
+	int rc = 0, i = 0, j = 0;
 	int idx = 0;
-	char *iommu_name[3] = {"jpeg_enc0", "jpeg_enc1", "jpeg_dec"};
+	char *iommu_name[JPEG_DEV_CNT] = {"jpeg_enc0", "jpeg_enc1",
+		"jpeg_dec"};
 
 	mutex_init(&pgmn_dev->lock);
 
@@ -847,6 +874,7 @@
 	idx = pgmn_dev->pdev->id;
 	pgmn_dev->idx = idx;
 	pgmn_dev->iommu_cnt = 1;
+	pgmn_dev->decode_flag = (idx == JPEG_DEC_ID);
 
 	msm_jpeg_q_init("evt_q", &pgmn_dev->evt_q);
 	msm_jpeg_q_init("output_rtn_q", &pgmn_dev->output_rtn_q);
@@ -855,21 +883,23 @@
 	msm_jpeg_q_init("input_buf_q", &pgmn_dev->input_buf_q);
 
 #ifdef CONFIG_MSM_IOMMU
-/*get device context for IOMMU*/
+	j = (pgmn_dev->iommu_cnt <= 1) ? idx : 0;
+	/*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]);
+		pgmn_dev->iommu_ctx_arr[i] = msm_iommu_get_ctx(iommu_name[j]);
+		JPEG_DBG("%s:%d] name %s", __func__, __LINE__, iommu_name[j]);
 		JPEG_DBG("%s:%d] ctx 0x%x", __func__, __LINE__,
-					(uint32_t)pgmn_dev->iommu_ctx_arr[i]);
+			(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;
 		}
+		j++;
 	}
 	pgmn_dev->domain_num = camera_register_domain();
 	JPEG_DBG("%s:%d] dom_num 0x%x", __func__, __LINE__,
-				pgmn_dev->domain_num);
+		pgmn_dev->domain_num);
 	if (pgmn_dev->domain_num < 0) {
 		JPEG_PR_ERR("%s: could not register domain\n", __func__);
 		goto error;
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_sync.h b/drivers/media/video/msm/jpeg_10/msm_jpeg_sync.h
index 1d82060..1ac4838 100644
--- a/drivers/media/video/msm/jpeg_10/msm_jpeg_sync.h
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_sync.h
@@ -21,7 +21,7 @@
 #include <linux/platform_device.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-subdev.h>
-#include "msm_jpeg_core.h"
+#include "msm_jpeg_hw.h"
 
 #define JPEG_7X 0x1
 #define JPEG_8X60 (0x1 << 1)
@@ -88,6 +88,17 @@
 	struct iommu_domain *domain;
 	struct device *iommu_ctx_arr[3];
 	int iommu_cnt;
+	int decode_flag;
+	struct ion_client *jpeg_client;
+	void *jpeg_vbif;
+	int release_buf;
+	struct msm_jpeg_hw_pingpong fe_pingpong_buf;
+	struct msm_jpeg_hw_pingpong we_pingpong_buf;
+	int we_pingpong_index;
+	int reset_done_ack;
+	spinlock_t reset_lock;
+	wait_queue_head_t reset_wait;
+	uint32_t res_size;
 };
 
 int __msm_jpeg_open(struct msm_jpeg_device *pgmn_dev);
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index cb59d68..2d9296c 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -720,7 +720,7 @@
 int msm_cam_register_subdev_node(struct v4l2_subdev *sd,
 	struct msm_cam_subdev_info *sd_info);
 int msm_mctl_find_sensor_subdevs(struct msm_cam_media_controller *p_mctl,
-	int core_index);
+	uint8_t csiphy_core_index, uint8_t csid_core_index);
 int msm_server_open_client(int *p_qidx);
 int msm_server_send_ctrl(struct msm_ctrl_cmd *out, int ctrl_id);
 int msm_server_close_client(int idx);
diff --git a/drivers/media/video/msm/msm_isp.c b/drivers/media/video/msm/msm_isp.c
index 2613986..1e17c5c 100644
--- a/drivers/media/video/msm/msm_isp.c
+++ b/drivers/media/video/msm/msm_isp.c
@@ -555,6 +555,7 @@
 	case CMD_AXI_CFG_PRIM_ALL_CHNLS|CMD_AXI_CFG_SEC:
 	case CMD_AXI_START:
 	case CMD_AXI_STOP:
+	case CMD_AXI_RESET:
 	case CMD_AXI_CFG_TERT1:
 	case CMD_AXI_CFG_TERT2:
 		/* Dont need to pass buffer information.
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index c94da2a..482e569 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -529,7 +529,8 @@
 		wake_lock(&p_mctl->wake_lock);
 
 		csid_core = camdev->csid_core;
-		rc = msm_mctl_find_sensor_subdevs(p_mctl, csid_core);
+		rc = msm_mctl_find_sensor_subdevs(p_mctl, camdev->csiphy_core,
+			csid_core);
 		if (rc < 0) {
 			pr_err("%s: msm_mctl_find_sensor_subdevs failed:%d\n",
 				__func__, rc);
diff --git a/drivers/media/video/msm/sensors/msm_sensor.c b/drivers/media/video/msm/sensors/msm_sensor.c
index 999783e..f5c9a73 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.c
+++ b/drivers/media/video/msm/sensors/msm_sensor.c
@@ -402,7 +402,8 @@
 			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_phy_sel =
+			s_ctrl->sensordata->pdata->csiphy_core;
 	}
 	sensor_output_info->csi_if = s_ctrl->sensordata->csi_if;
 	for (index = 0; index < sensor_output_info->csi_if; index++)
@@ -1184,8 +1185,7 @@
 		pr_err("%s failed %d\n", __func__, __LINE__);
 		goto ERROR3;
 	}
-	pinfo->csi_lane_params->csi_phy_sel = val;
-
+	sensordata->pdata->csiphy_core = val;
 	kfree(val_array);
 	return rc;
 ERROR3:
@@ -1762,6 +1762,8 @@
 		s_ctrl->sensor_i2c_addr >> 1;
 	s_ctrl->sensor_i2c_client->cci_client->retries = 3;
 	s_ctrl->sensor_i2c_client->cci_client->id_map = 0;
+	if (!s_ctrl->wait_num_frames)
+		s_ctrl->wait_num_frames = 1 * Q10;
 
 	rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl);
 	if (rc < 0) {
@@ -1777,6 +1779,8 @@
 	if (rc < 0)
 		goto probe_fail;
 
+	pr_err("%s %s probe succeeded\n", __func__,
+		s_ctrl->sensordata->sensor_name);
 	v4l2_subdev_init(&s_ctrl->sensor_v4l2_subdev,
 		s_ctrl->sensor_v4l2_subdev_ops);
 	snprintf(s_ctrl->sensor_v4l2_subdev.name,
diff --git a/drivers/media/video/msm/sensors/ov5647_v4l2.c b/drivers/media/video/msm/sensors/ov5647_v4l2.c
index eb6a8b0..f6cf427 100644
--- a/drivers/media/video/msm/sensors/ov5647_v4l2.c
+++ b/drivers/media/video/msm/sensors/ov5647_v4l2.c
@@ -23,6 +23,8 @@
 
 static struct msm_camera_i2c_reg_conf ov5647_start_settings[] = {
 	{0x4202, 0x00},  /* streaming on */
+	{0x0100, 0x01},
+	{0x4800, 0x04},
 };
 
 static struct msm_camera_i2c_reg_conf ov5647_stop_settings[] = {
diff --git a/drivers/media/video/msm/server/msm_cam_server.c b/drivers/media/video/msm/server/msm_cam_server.c
index bb9a9b7..74dd3f2 100644
--- a/drivers/media/video/msm/server/msm_cam_server.c
+++ b/drivers/media/video/msm/server/msm_cam_server.c
@@ -1643,6 +1643,10 @@
 
 		rp = (struct msm_vfe_resp *)arg;
 		frame_info = rp->evt_msg.data;
+		if (!frame_info) {
+			interface = PIX_0;
+			break;
+		}
 		if (frame_info->inst_handle) {
 			vnode_id = GET_DEVID_MODE(frame_info->inst_handle);
 			if (vnode_id < MAX_NUM_ACTIVE_CAMERA &&
@@ -1797,13 +1801,14 @@
 }
 
 int msm_mctl_find_sensor_subdevs(struct msm_cam_media_controller *p_mctl,
-	int core_index)
+	uint8_t csiphy_core_index, uint8_t csid_core_index)
 {
 	int rc = -ENODEV;
 
 	v4l2_set_subdev_hostdata(p_mctl->sensor_sdev, p_mctl);
 
-	rc = msm_csi_register_subdevs(p_mctl, core_index, &g_server_dev);
+	rc = msm_csi_register_subdevs(p_mctl, csiphy_core_index,
+		csid_core_index, &g_server_dev);
 	if (rc < 0)
 		pr_err("%s: Could not find sensor subdevs\n", __func__);
 
diff --git a/drivers/media/video/msm/vfe/msm_vfe7x27a_v4l2.c b/drivers/media/video/msm/vfe/msm_vfe7x27a_v4l2.c
index 15c38af..9deae65 100644
--- a/drivers/media/video/msm/vfe/msm_vfe7x27a_v4l2.c
+++ b/drivers/media/video/msm/vfe/msm_vfe7x27a_v4l2.c
@@ -1561,6 +1561,11 @@
 	}
 		return 0;
 
+	case CMD_AXI_START:
+	case CMD_AXI_STOP:
+	case CMD_AXI_RESET:
+		return 0;
+
 	case CMD_CONFIG_FREE_BUF_ADDR: {
 		int path = *((int *)cmd->value);
 		struct buf_info *outch = vfe2x_get_ch(path);
@@ -1853,9 +1858,6 @@
 						flags);
 				if (op_mode & SNAPSHOT_MASK_MODE) {
 					vfe2x_ctrl->stop_pending = 0;
-					vfe2x_send_isp_msg(vfe2x_ctrl,
-						msgs_map[MSG_STOP_ACK].
-						isp_id);
 					spin_unlock_irqrestore(
 							&vfe2x_ctrl->table_lock,
 							flags);
diff --git a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
index 170322c..7fa4f26 100644
--- a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
@@ -31,7 +31,6 @@
 #include "msm_smem.h"
 
 #define BASE_DEVICE_NUMBER 32
-#define MAX_EVENTS 30
 #define SHARED_QSIZE 0x1000000
 
 static struct msm_bus_vectors enc_ocmem_init_vectors[]  = {
@@ -451,7 +450,7 @@
 };
 
 struct msm_v4l2_vid_inst {
-	struct msm_vidc_inst vidc_inst;
+	struct msm_vidc_inst *vidc_inst;
 	void *mem_client;
 	struct list_head registered_bufs;
 };
@@ -468,22 +467,7 @@
 	struct msm_vidc_inst *vidc_inst;
 	vidc_inst = container_of(filp->private_data,
 			struct msm_vidc_inst, event_handler);
-	return container_of((void *)vidc_inst,
-			struct msm_v4l2_vid_inst, vidc_inst);
-}
-
-static int msm_vidc_v4l2_setup_event_queue(void *inst,
-				struct video_device *pvdev)
-{
-	int rc = 0;
-	struct msm_vidc_inst *vidc_inst = (struct msm_vidc_inst *)inst;
-	spin_lock_init(&pvdev->fh_lock);
-	INIT_LIST_HEAD(&pvdev->fh_list);
-
-	v4l2_fh_init(&vidc_inst->event_handler, pvdev);
-	v4l2_fh_add(&vidc_inst->event_handler);
-
-	return rc;
+	return (struct msm_v4l2_vid_inst *)vidc_inst->priv;
 }
 
 struct buffer_info *get_registered_buf(struct list_head *list,
@@ -556,7 +540,8 @@
 		rc = -ENOMEM;
 		goto fail_mem_client;
 	}
-	rc = msm_vidc_open(&v4l2_inst->vidc_inst, core->id, vid_dev->type);
+
+	v4l2_inst->vidc_inst = msm_vidc_open(core->id, vid_dev->type);
 	if (rc) {
 		dprintk(VIDC_ERR,
 		"Failed to create video instance, core: %d, type = %d\n",
@@ -565,9 +550,9 @@
 		goto fail_open;
 	}
 	INIT_LIST_HEAD(&v4l2_inst->registered_bufs);
-	rc = msm_vidc_v4l2_setup_event_queue(&v4l2_inst->vidc_inst, vdev);
+	v4l2_inst->vidc_inst->priv = v4l2_inst;
 	clear_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags);
-	filp->private_data = &(v4l2_inst->vidc_inst.event_handler);
+	filp->private_data = &(v4l2_inst->vidc_inst->event_handler);
 	return rc;
 fail_open:
 	msm_smem_delete_client(v4l2_inst->mem_client);
@@ -576,22 +561,69 @@
 fail_nomem:
 	return rc;
 }
+static int msm_v4l2_release_output_buffers(struct msm_v4l2_vid_inst *v4l2_inst)
+{
+	struct list_head *ptr, *next;
+	struct buffer_info *bi;
+	struct v4l2_buffer buffer_info;
+	struct v4l2_plane plane;
+	int rc = 0;
+	list_for_each_safe(ptr, next, &v4l2_inst->registered_bufs) {
+		bi = list_entry(ptr, struct buffer_info, list);
+		if (bi->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+			buffer_info.type = bi->type;
+			plane.reserved[0] = bi->fd;
+			plane.reserved[1] = bi->buff_off;
+			plane.length = bi->size;
+			plane.m.userptr = bi->device_addr;
+			buffer_info.m.planes = &plane;
+			buffer_info.length = 1;
+			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);
+			if (rc)
+				dprintk(VIDC_ERR,
+					"Failed Release 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);
+			list_del(&bi->list);
+			if (bi->handle)
+				msm_smem_free(v4l2_inst->mem_client,
+					bi->handle);
+			kfree(bi);
+			}
+	}
+	return rc;
+}
 
 static int msm_v4l2_close(struct file *filp)
 {
-	int rc;
+	int rc = 0;
 	struct list_head *ptr, *next;
-	struct buffer_info *binfo;
+	struct buffer_info *bi;
 	struct msm_vidc_inst *vidc_inst;
 	struct msm_v4l2_vid_inst *v4l2_inst;
 	vidc_inst = get_vidc_inst(filp, NULL);
 	v4l2_inst = get_v4l2_inst(filp, NULL);
+	rc = msm_v4l2_release_output_buffers(v4l2_inst);
+	if (rc)
+		dprintk(VIDC_WARN,
+			"Failed in %s for release output buffers\n", __func__);
 	rc = msm_vidc_close(vidc_inst);
 	list_for_each_safe(ptr, next, &v4l2_inst->registered_bufs) {
-		binfo = list_entry(ptr, struct buffer_info, list);
-		list_del(&binfo->list);
-		msm_smem_free(v4l2_inst->mem_client, binfo->handle);
-		kfree(binfo);
+		bi = list_entry(ptr, struct buffer_info, list);
+		if (bi->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+			list_del(&bi->list);
+			if (bi->handle)
+				msm_smem_free(v4l2_inst->mem_client,
+					bi->handle);
+			kfree(bi);
+		}
 	}
 	msm_smem_delete_client(v4l2_inst->mem_client);
 	kfree(v4l2_inst);
@@ -645,38 +677,13 @@
 {
 	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
 	struct msm_v4l2_vid_inst *v4l2_inst;
-	struct list_head *ptr, *next;
-	int rc;
-	struct buffer_info *bi;
-	struct v4l2_buffer buffer_info;
-	struct v4l2_plane plane;
+	int rc = 0;
 	v4l2_inst = get_v4l2_inst(file, NULL);
-	if (b->count == 0) {
-		list_for_each_safe(ptr, next, &v4l2_inst->registered_bufs) {
-			bi = list_entry(ptr, struct buffer_info, list);
-			if (bi->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
-				buffer_info.type = bi->type;
-				plane.reserved[0] = bi->fd;
-				plane.reserved[1] = bi->buff_off;
-				plane.length = bi->size;
-				plane.m.userptr = bi->device_addr;
-				buffer_info.m.planes = &plane;
-				buffer_info.length = 1;
-				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);
-				if (bi->handle)
-					msm_smem_free(v4l2_inst->mem_client,
-							bi->handle);
-				kfree(bi);
-			}
-		}
-	}
+	if (b->count == 0)
+		rc = msm_v4l2_release_output_buffers(v4l2_inst);
+	if (rc)
+		dprintk(VIDC_WARN,
+			"Failed in %s for release output buffers\n", __func__);
 	return msm_vidc_reqbufs((void *)vidc_inst, b);
 }
 
@@ -752,7 +759,7 @@
 		list_add_tail(&binfo->list, &v4l2_inst->registered_bufs);
 		b->m.planes[i].m.userptr = binfo->device_addr;
 	}
-	rc = msm_vidc_prepare_buf(&v4l2_inst->vidc_inst, b);
+	rc = msm_vidc_prepare_buf(v4l2_inst->vidc_inst, b);
 exit:
 	return rc;
 }
@@ -794,7 +801,7 @@
 			}
 		}
 	}
-	rc = msm_vidc_qbuf(&v4l2_inst->vidc_inst, b);
+	rc = msm_vidc_qbuf(v4l2_inst->vidc_inst, b);
 err_invalid_buff:
 	return rc;
 }
@@ -823,23 +830,31 @@
 static int msm_v4l2_subscribe_event(struct v4l2_fh *fh,
 				struct v4l2_event_subscription *sub)
 {
-	int rc = 0;
-	rc = v4l2_event_subscribe(fh, sub, MAX_EVENTS);
-	return rc;
+	struct msm_vidc_inst *vidc_inst = container_of(fh,
+			struct msm_vidc_inst, event_handler);
+	return msm_vidc_subscribe_event((void *)vidc_inst, sub);
 }
 
 static int msm_v4l2_unsubscribe_event(struct v4l2_fh *fh,
 				struct v4l2_event_subscription *sub)
 {
-	int rc = 0;
-	rc = v4l2_event_unsubscribe(fh, sub);
-	return rc;
+	struct msm_vidc_inst *vidc_inst = container_of(fh,
+			struct msm_vidc_inst, event_handler);
+	return msm_vidc_unsubscribe_event((void *)vidc_inst, sub);
 }
 
 static int msm_v4l2_decoder_cmd(struct file *file, void *fh,
 				struct v4l2_decoder_cmd *dec)
 {
+	struct msm_v4l2_vid_inst *v4l2_inst;
 	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+	int rc = 0;
+	v4l2_inst = get_v4l2_inst(file, NULL);
+	if (dec->cmd == V4L2_DEC_CMD_STOP)
+		rc = msm_v4l2_release_output_buffers(v4l2_inst);
+	if (rc)
+		dprintk(VIDC_WARN,
+			"Failed in %s for release output buffers\n", __func__);
 	return msm_vidc_decoder_cmd((void *)vidc_inst, dec);
 }
 
@@ -936,7 +951,7 @@
 	struct msm_iova_layout layout;
 	int rc = 0;
 	int i;
-	struct iommu_info *io_map = core->resources.io_map;
+	struct msm_vidc_iommu_info *io_map = core->resources.io_map;
 	strlcpy(io_map[CP_MAP].name, "vidc-cp-map",
 			sizeof(io_map[CP_MAP].name));
 	strlcpy(io_map[CP_MAP].ctx, "venus_cp",
diff --git a/drivers/media/video/msm_vidc/msm_vdec.c b/drivers/media/video/msm_vidc/msm_vdec.c
index 8240890..ead118d 100644
--- a/drivers/media/video/msm_vidc/msm_vdec.c
+++ b/drivers/media/video/msm_vidc/msm_vdec.c
@@ -229,6 +229,14 @@
 		.type = OUTPUT_PORT,
 	},
 	{
+		.name = "VC1 SP",
+		.description = "VC-1 compressed format G",
+		.fourcc = V4L2_PIX_FMT_VC1_ANNEX_L,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = OUTPUT_PORT,
+	},
+	{
 		.name = "H264",
 		.description = "H264 compressed format",
 		.fourcc = V4L2_PIX_FMT_H264,
@@ -524,6 +532,8 @@
 			goto err_invalid_fmt;
 		}
 	} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		inst->prop.width = f->fmt.pix_mp.width;
+		inst->prop.height = f->fmt.pix_mp.height;
 		fmt = msm_comm_get_pixel_fmt_fourcc(vdec_formats,
 			ARRAY_SIZE(vdec_formats), f->fmt.pix_mp.pixelformat,
 			OUTPUT_PORT);
@@ -737,6 +747,16 @@
 	return rc;
 }
 
+static inline int stop_streaming(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	rc = msm_comm_try_state(inst, MSM_VIDC_RELEASE_RESOURCES_DONE);
+	if (rc)
+		dprintk(VIDC_ERR,
+			"Failed to move inst: %p to start done state\n", inst);
+	return rc;
+}
+
 static int msm_vdec_start_streaming(struct vb2_queue *q, unsigned int count)
 {
 	struct msm_vidc_inst *inst;
@@ -778,13 +798,11 @@
 	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_RELEASE_RESOURCES_DONE);
+			rc = stop_streaming(inst);
 		break;
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
 		if (!inst->vb2_bufq[OUTPUT_PORT].streaming)
-			rc = msm_comm_try_state(inst,
-				MSM_VIDC_RELEASE_RESOURCES_DONE);
+			rc = stop_streaming(inst);
 		break;
 	default:
 		dprintk(VIDC_ERR,
@@ -820,6 +838,12 @@
 		rc = msm_comm_flush(inst, dec->flags);
 		break;
 	case V4L2_DEC_CMD_STOP:
+		rc = msm_comm_release_scratch_buffers(inst);
+		if (rc)
+			pr_err("Failed to release scratch buffers: %d\n", rc);
+		rc = msm_comm_release_persist_buffers(inst);
+		if (rc)
+			pr_err("Failed to release persist buffers: %d\n", rc);
 		rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
 		break;
 	default:
diff --git a/drivers/media/video/msm_vidc/msm_venc.c b/drivers/media/video/msm_vidc/msm_venc.c
index 6c0f224..c137c08 100644
--- a/drivers/media/video/msm_vidc/msm_venc.c
+++ b/drivers/media/video/msm_vidc/msm_venc.c
@@ -95,7 +95,7 @@
 		.type = V4L2_CTRL_TYPE_INTEGER,
 		.minimum = MIN_FRAME_RATE,
 		.maximum = MAX_FRAME_RATE,
-		.default_value = DEFAULT_FRAME_RATE,
+		.default_value = MIN_FRAME_RATE,
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
diff --git a/drivers/media/video/msm_vidc/msm_vidc.c b/drivers/media/video/msm_vidc/msm_vidc.c
index 449dab2..ec9dac8 100644
--- a/drivers/media/video/msm_vidc/msm_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_vidc.c
@@ -11,6 +11,7 @@
  *
  */
 
+#include <linux/sched.h>
 #include <linux/slab.h>
 #include <media/msm_vidc.h>
 #include "msm_vidc_internal.h"
@@ -21,21 +22,21 @@
 #include "msm_smem.h"
 #include <linux/delay.h>
 
-int msm_vidc_poll(void *instance, struct file *filp,
-		struct poll_table_struct *wait)
+#define MAX_EVENTS 30
+
+static int get_poll_flags(void *instance)
 {
-	int rc = 0;
 	struct msm_vidc_inst *inst = instance;
 	struct vb2_queue *outq = &inst->vb2_bufq[OUTPUT_PORT];
 	struct vb2_queue *capq = &inst->vb2_bufq[CAPTURE_PORT];
 	struct vb2_buffer *out_vb = NULL;
 	struct vb2_buffer *cap_vb = NULL;
 	unsigned long flags;
-	poll_wait(filp, &inst->event_handler.wait, wait);
-	poll_wait(filp, &capq->done_wq, wait);
-	poll_wait(filp, &outq->done_wq, wait);
+	int rc = 0;
+
 	if (v4l2_event_pending(&inst->event_handler))
 		rc |= POLLPRI;
+
 	spin_lock_irqsave(&capq->done_lock, flags);
 	if (!list_empty(&capq->done_list))
 		cap_vb = list_first_entry(&capq->done_list, struct vb2_buffer,
@@ -44,6 +45,7 @@
 				|| cap_vb->state == VB2_BUF_STATE_ERROR))
 		rc |= POLLIN | POLLRDNORM;
 	spin_unlock_irqrestore(&capq->done_lock, flags);
+
 	spin_lock_irqsave(&outq->done_lock, flags);
 	if (!list_empty(&outq->done_list))
 		out_vb = list_first_entry(&outq->done_list, struct vb2_buffer,
@@ -52,12 +54,55 @@
 				|| out_vb->state == VB2_BUF_STATE_ERROR))
 		rc |= POLLOUT | POLLWRNORM;
 	spin_unlock_irqrestore(&outq->done_lock, flags);
+
 	return rc;
 }
 
+int msm_vidc_poll(void *instance, struct file *filp,
+		struct poll_table_struct *wait)
+{
+	struct msm_vidc_inst *inst = instance;
+	struct vb2_queue *outq = &inst->vb2_bufq[OUTPUT_PORT];
+	struct vb2_queue *capq = &inst->vb2_bufq[CAPTURE_PORT];
+
+	poll_wait(filp, &inst->event_handler.wait, wait);
+	poll_wait(filp, &capq->done_wq, wait);
+	poll_wait(filp, &outq->done_wq, wait);
+	return get_poll_flags(inst);
+}
+
+/* Kernel client alternative for msm_vidc_poll */
+int msm_vidc_wait(void *instance)
+{
+	struct msm_vidc_inst *inst = instance;
+	int rc = 0;
+
+	wait_event(inst->kernel_event_queue, (rc = get_poll_flags(inst)));
+	return rc;
+}
+
+int msm_vidc_get_iommu_maps(void *instance,
+		struct msm_vidc_iommu_info maps[MAX_MAP])
+{
+	struct msm_vidc_inst *inst = instance;
+	int c = 0;
+
+	if (!inst || !maps)
+		return -EINVAL;
+
+	for (c = 0; c < MAX_MAP; ++c)
+		maps[c] = inst->core->resources.io_map[c];
+
+	return 0;
+}
+
 int msm_vidc_querycap(void *instance, struct v4l2_capability *cap)
 {
 	struct msm_vidc_inst *inst = instance;
+
+	if (!inst || !cap)
+		return -EINVAL;
+
 	if (inst->session_type == MSM_VIDC_DECODER)
 		return msm_vdec_querycap(instance, cap);
 	else if (inst->session_type == MSM_VIDC_ENCODER)
@@ -67,6 +112,10 @@
 int msm_vidc_enum_fmt(void *instance, struct v4l2_fmtdesc *f)
 {
 	struct msm_vidc_inst *inst = instance;
+
+	if (!inst || !f)
+		return -EINVAL;
+
 	if (inst->session_type == MSM_VIDC_DECODER)
 		return msm_vdec_enum_fmt(instance, f);
 	else if (inst->session_type == MSM_VIDC_ENCODER)
@@ -76,6 +125,10 @@
 int msm_vidc_s_fmt(void *instance, struct v4l2_format *f)
 {
 	struct msm_vidc_inst *inst = instance;
+
+	if (!inst || !f)
+		return -EINVAL;
+
 	if (inst->session_type == MSM_VIDC_DECODER)
 		return msm_vdec_s_fmt(instance, f);
 	if (inst->session_type == MSM_VIDC_ENCODER)
@@ -85,6 +138,10 @@
 int msm_vidc_g_fmt(void *instance, struct v4l2_format *f)
 {
 	struct msm_vidc_inst *inst = instance;
+
+	if (!inst || !f)
+		return -EINVAL;
+
 	if (inst->session_type == MSM_VIDC_DECODER)
 		return msm_vdec_g_fmt(instance, f);
 	else if (inst->session_type == MSM_VIDC_ENCODER)
@@ -94,6 +151,10 @@
 int msm_vidc_s_ctrl(void *instance, struct v4l2_control *control)
 {
 	struct msm_vidc_inst *inst = instance;
+
+	if (!inst || !control)
+		return -EINVAL;
+
 	if (inst->session_type == MSM_VIDC_DECODER)
 		return msm_vdec_s_ctrl(instance, control);
 	if (inst->session_type == MSM_VIDC_ENCODER)
@@ -103,6 +164,10 @@
 int msm_vidc_g_ctrl(void *instance, struct v4l2_control *control)
 {
 	struct msm_vidc_inst *inst = instance;
+
+	if (!inst || !control)
+		return -EINVAL;
+
 	if (inst->session_type == MSM_VIDC_DECODER)
 		return msm_vdec_g_ctrl(instance, control);
 	if (inst->session_type == MSM_VIDC_ENCODER)
@@ -112,6 +177,10 @@
 int msm_vidc_reqbufs(void *instance, struct v4l2_requestbuffers *b)
 {
 	struct msm_vidc_inst *inst = instance;
+
+	if (!inst || !b)
+		return -EINVAL;
+
 	if (inst->session_type == MSM_VIDC_DECODER)
 		return msm_vdec_reqbufs(instance, b);
 	if (inst->session_type == MSM_VIDC_ENCODER)
@@ -122,6 +191,10 @@
 int msm_vidc_prepare_buf(void *instance, struct v4l2_buffer *b)
 {
 	struct msm_vidc_inst *inst = instance;
+
+	if (!inst || !b)
+		return -EINVAL;
+
 	if (inst->session_type == MSM_VIDC_DECODER)
 		return msm_vdec_prepare_buf(instance, b);
 	if (inst->session_type == MSM_VIDC_ENCODER)
@@ -132,6 +205,10 @@
 int msm_vidc_release_buf(void *instance, struct v4l2_buffer *b)
 {
 	struct msm_vidc_inst *inst = instance;
+
+	if (!inst || !b)
+		return -EINVAL;
+
 	if (inst->session_type == MSM_VIDC_DECODER)
 		return msm_vdec_release_buf(instance, b);
 	return -EINVAL;
@@ -156,6 +233,10 @@
 int msm_vidc_qbuf(void *instance, struct v4l2_buffer *b)
 {
 	struct msm_vidc_inst *inst = instance;
+
+	if (!inst || !b)
+		return -EINVAL;
+
 	if (inst->session_type == MSM_VIDC_DECODER)
 		return msm_vdec_qbuf(instance, b);
 	if (inst->session_type == MSM_VIDC_ENCODER)
@@ -166,6 +247,10 @@
 int msm_vidc_dqbuf(void *instance, struct v4l2_buffer *b)
 {
 	struct msm_vidc_inst *inst = instance;
+
+	if (!inst || !b)
+		return -EINVAL;
+
 	if (inst->session_type == MSM_VIDC_DECODER)
 		return msm_vdec_dqbuf(instance, b);
 	if (inst->session_type == MSM_VIDC_ENCODER)
@@ -176,6 +261,10 @@
 int msm_vidc_streamon(void *instance, enum v4l2_buf_type i)
 {
 	struct msm_vidc_inst *inst = instance;
+
+	if (!inst)
+		return -EINVAL;
+
 	if (inst->session_type == MSM_VIDC_DECODER)
 		return msm_vdec_streamon(instance, i);
 	if (inst->session_type == MSM_VIDC_ENCODER)
@@ -186,6 +275,10 @@
 int msm_vidc_streamoff(void *instance, enum v4l2_buf_type i)
 {
 	struct msm_vidc_inst *inst = instance;
+
+	if (!inst)
+		return -EINVAL;
+
 	if (inst->session_type == MSM_VIDC_DECODER)
 		return msm_vdec_streamoff(instance, i);
 	if (inst->session_type == MSM_VIDC_ENCODER)
@@ -193,13 +286,13 @@
 	return -EINVAL;
 }
 
-void *vidc_get_userptr(void *alloc_ctx, unsigned long vaddr,
+static void *vidc_get_userptr(void *alloc_ctx, unsigned long vaddr,
 				unsigned long size, int write)
 {
 	return (void *)0xdeadbeef;
 }
 
-void vidc_put_userptr(void *buf_priv)
+static void vidc_put_userptr(void *buf_priv)
 {
 }
 
@@ -232,9 +325,60 @@
 	return vb2_queue_init(q);
 }
 
-int msm_vidc_open(void *vidc_inst, int core_id, int session_type)
+static int setup_event_queue(void *inst,
+				struct video_device *pvdev)
 {
-	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)vidc_inst;
+	int rc = 0;
+	struct msm_vidc_inst *vidc_inst = (struct msm_vidc_inst *)inst;
+	spin_lock_init(&pvdev->fh_lock);
+	INIT_LIST_HEAD(&pvdev->fh_list);
+
+	v4l2_fh_init(&vidc_inst->event_handler, pvdev);
+	v4l2_fh_add(&vidc_inst->event_handler);
+
+	return rc;
+}
+
+int msm_vidc_subscribe_event(void *inst, struct v4l2_event_subscription *sub)
+{
+	int rc = 0;
+	struct msm_vidc_inst *vidc_inst = (struct msm_vidc_inst *)inst;
+
+	if (!inst || !sub)
+		return -EINVAL;
+
+	rc = v4l2_event_subscribe(&vidc_inst->event_handler, sub, MAX_EVENTS);
+	return rc;
+}
+
+
+int msm_vidc_unsubscribe_event(void *inst, struct v4l2_event_subscription *sub)
+{
+	int rc = 0;
+	struct msm_vidc_inst *vidc_inst = (struct msm_vidc_inst *)inst;
+
+	if (!inst || !sub)
+		return -EINVAL;
+
+	rc = v4l2_event_unsubscribe(&vidc_inst->event_handler, sub);
+	return rc;
+}
+
+int msm_vidc_dqevent(void *inst, struct v4l2_event *event)
+{
+	int rc = 0;
+	struct msm_vidc_inst *vidc_inst = (struct msm_vidc_inst *)inst;
+
+	if (!inst || !event)
+		return -EINVAL;
+
+	rc = v4l2_event_dequeue(&vidc_inst->event_handler, event, false);
+	return rc;
+}
+
+void *msm_vidc_open(int core_id, int session_type)
+{
+	struct msm_vidc_inst *inst = NULL;
 	struct msm_vidc_core *core = NULL;
 	unsigned long flags;
 	int rc = 0;
@@ -252,14 +396,23 @@
 		goto err_invalid_core;
 	}
 
+	inst = kzalloc(sizeof(*inst), GFP_KERNEL);
+	if (!inst) {
+		pr_err("Failed to allocate memory\n")	;
+		rc = -ENOMEM;
+		goto err_invalid_core;
+	}
+
 	mutex_init(&inst->sync_lock);
 	spin_lock_init(&inst->lock);
 	inst->session_type = session_type;
 	INIT_LIST_HEAD(&inst->pendingq);
 	INIT_LIST_HEAD(&inst->internalbufs);
 	INIT_LIST_HEAD(&inst->persistbufs);
+	init_waitqueue_head(&inst->kernel_event_queue);
 	inst->state = MSM_VIDC_CORE_UNINIT_DONE;
 	inst->core = core;
+
 	for (i = SESSION_MSG_INDEX(SESSION_MSG_START);
 		i <= SESSION_MSG_INDEX(SESSION_MSG_END); i++) {
 		init_completion(&inst->completions[i]);
@@ -276,6 +429,7 @@
 		msm_venc_inst_init(inst);
 		msm_venc_ctrl_init(inst);
 	}
+
 	rc = vb2_bufq_init(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
 			session_type);
 	if (rc) {
@@ -298,17 +452,20 @@
 	}
 	inst->debugfs_root =
 		msm_vidc_debugfs_init_inst(inst, core->debugfs_root);
+
+	setup_event_queue(inst, &core->vdev[core_id].vdev);
+
 	spin_lock_irqsave(&core->lock, flags);
 	list_add_tail(&inst->list, &core->instances);
 	spin_unlock_irqrestore(&core->lock, flags);
-	return rc;
+	return inst;
 fail_init:
 	msm_smem_delete_client(inst->mem_client);
 fail_mem_client:
 	kfree(inst);
 	inst = NULL;
 err_invalid_core:
-	return rc;
+	return inst;
 }
 
 static void cleanup_instance(struct msm_vidc_inst *inst)
@@ -360,6 +517,10 @@
 	struct msm_vidc_core *core;
 	struct list_head *ptr, *next;
 	int rc = 0;
+
+	if (!inst)
+		return -EINVAL;
+
 	core = inst->core;
 	mutex_lock(&core->sync_lock);
 	list_for_each_safe(ptr, next, &core->instances) {
@@ -373,6 +534,7 @@
 		dprintk(VIDC_ERR,
 			"Failed to move video instance to uninit state\n");
 	cleanup_instance(inst);
+	kfree(inst);
 	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 5b83cfb..2aed0b7 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.c
@@ -166,7 +166,7 @@
 	int rc;
 	struct iommu_domain *domain;
 	int i;
-	struct iommu_info *io_map;
+	struct msm_vidc_iommu_info *io_map;
 	struct device *dev;
 	for (i = 0; i < MAX_MAP; i++) {
 		io_map = &core->resources.io_map[i];
@@ -202,7 +202,7 @@
 {
 	struct device *dev;
 	struct iommu_domain *domain;
-	struct iommu_info *io_map;
+	struct msm_vidc_iommu_info *io_map;
 	int i;
 	if (!core) {
 		dprintk(VIDC_ERR, "Invalid paramter: %p\n", core);
@@ -408,6 +408,7 @@
 		inst->reconfig_width = event_notify->width;
 		inst->in_reconfig = true;
 		v4l2_event_queue_fh(&inst->event_handler, &dqevent);
+		wake_up(&inst->kernel_event_queue);
 		return;
 	} else {
 		dprintk(VIDC_ERR,
@@ -501,6 +502,7 @@
 		dqevent.type = V4L2_EVENT_MSM_VIDC_FLUSH_DONE;
 		dqevent.id = 0;
 		v4l2_event_queue_fh(&inst->event_handler, &dqevent);
+		wake_up(&inst->kernel_event_queue);
 	} else {
 		dprintk(VIDC_ERR, "Failed to get valid response for flush\n");
 	}
@@ -518,6 +520,7 @@
 		dqevent.type = V4L2_EVENT_MSM_VIDC_CLOSE_DONE;
 		dqevent.id = 0;
 		v4l2_event_queue_fh(&inst->event_handler, &dqevent);
+		wake_up(&inst->kernel_event_queue);
 	} else {
 		dprintk(VIDC_ERR,
 			"Failed to get valid response for session close\n");
@@ -552,13 +555,17 @@
 {
 	struct msm_vidc_cb_data_done *response = data;
 	struct vb2_buffer *vb;
+	struct msm_vidc_inst *inst;
 	if (!response) {
 		dprintk(VIDC_ERR, "Invalid response from vidc_hal\n");
 		return;
 	}
 	vb = response->clnt_data;
-	if (vb)
+	inst = (struct msm_vidc_inst *)response->session_id;
+	if (vb) {
 		vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+		wake_up(&inst->kernel_event_queue);
+	}
 }
 
 static void handle_fbd(enum command_response cmd, void *data)
@@ -622,6 +629,7 @@
 				vb->v4l2_planes[0].bytesused,
 				vb->v4l2_buf.flags);
 		vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+		wake_up(&inst->kernel_event_queue);
 	} else {
 		/*
 		 * FIXME:
@@ -737,7 +745,7 @@
 		dprintk(VIDC_ERR, "Invalid args: %p\n", core);
 		return -EINVAL;
 	}
-	num_mbs_per_sec = 2 * msm_comm_get_load(core, MSM_VIDC_ENCODER);
+	num_mbs_per_sec = 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,
@@ -1558,6 +1566,68 @@
 	return rc;
 }
 
+int msm_comm_release_scratch_buffers(struct msm_vidc_inst *inst)
+{
+	struct msm_smem *handle;
+	struct list_head *ptr, *next;
+	struct internal_buf *buf;
+	struct vidc_buffer_addr_info buffer_info;
+	int rc = 0;
+	unsigned long flags;
+	spin_lock_irqsave(&inst->lock, flags);
+	if (!list_empty(&inst->internalbufs)) {
+		list_for_each_safe(ptr, next, &inst->internalbufs) {
+			buf = list_entry(ptr, struct internal_buf,
+					list);
+			handle = buf->handle;
+			buffer_info.buffer_size = handle->size;
+			buffer_info.buffer_type = HAL_BUFFER_INTERNAL_SCRATCH;
+			buffer_info.num_buffers = 1;
+			buffer_info.align_device_addr = handle->device_addr;
+			rc = vidc_hal_session_release_buffers(
+				(void *) inst->session,	&buffer_info);
+			list_del(&buf->list);
+			msm_smem_free(inst->mem_client, buf->handle);
+			kfree(buf);
+		}
+	}
+	spin_unlock_irqrestore(&inst->lock, flags);
+	return rc;
+}
+
+int msm_comm_release_persist_buffers(struct msm_vidc_inst *inst)
+{
+	struct msm_smem *handle;
+	struct list_head *ptr, *next;
+	struct internal_buf *buf;
+	struct vidc_buffer_addr_info buffer_info;
+	int rc = 0;
+	unsigned long flags;
+	spin_lock_irqsave(&inst->lock, flags);
+	if (!list_empty(&inst->persistbufs)) {
+		list_for_each_safe(ptr, next, &inst->persistbufs) {
+			buf = list_entry(ptr, struct internal_buf,
+				list);
+			handle = buf->handle;
+			buffer_info.buffer_size = handle->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_release_buffers(
+				(void *) inst->session,	&buffer_info);
+			if (rc)
+				dprintk(VIDC_WARN,
+					"Failed in %s for buffer %ld\n",
+					__func__, handle->device_addr);
+			list_del(&buf->list);
+			msm_smem_free(inst->mem_client, buf->handle);
+			kfree(buf);
+		}
+	}
+	spin_unlock_irqrestore(&inst->lock, flags);
+	return rc;
+}
+
 int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst)
 {
 	int rc = 0;
@@ -1578,6 +1648,17 @@
 		list_for_each_safe(ptr, next, &inst->internalbufs) {
 			binfo = list_entry(ptr, struct internal_buf,
 					list);
+			handle = binfo->handle;
+			buffer_info.buffer_size = handle->size;
+			buffer_info.buffer_type = HAL_BUFFER_INTERNAL_SCRATCH;
+			buffer_info.num_buffers = 1;
+			buffer_info.align_device_addr = handle->device_addr;
+			rc = vidc_hal_session_release_buffers(
+				(void *) inst->session, &buffer_info);
+			if (rc)
+				dprintk(VIDC_WARN,
+					"Failed in release %s for buffer %ld\n",
+					__func__, handle->device_addr);
 			list_del(&binfo->list);
 			msm_smem_free(inst->mem_client, binfo->handle);
 			kfree(binfo);
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.h b/drivers/media/video/msm_vidc/msm_vidc_common.h
index 69aa53a..1301e5c 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.h
@@ -32,6 +32,8 @@
 int msm_comm_qbuf(struct vb2_buffer *vb);
 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);
+int msm_comm_release_scratch_buffers(struct msm_vidc_inst *inst);
+int msm_comm_release_persist_buffers(struct msm_vidc_inst *inst);
 #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_internal.h b/drivers/media/video/msm_vidc/msm_vidc_internal.h
index 55aec74..1f2eff8 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_internal.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_internal.h
@@ -19,6 +19,7 @@
 #include <linux/types.h>
 #include <linux/completion.h>
 #include <linux/clk.h>
+#include <linux/wait.h>
 #include <mach/msm_bus.h>
 #include <mach/msm_bus_board.h>
 #include <mach/ocmem.h>
@@ -141,20 +142,6 @@
 	void *cookie;
 };
 
-struct iommu_info {
-	u32 addr_range[2];
-	char name[MAX_NAME_LENGTH];
-	char ctx[MAX_NAME_LENGTH];
-	int domain;
-	int partition;
-};
-
-enum io_maps {
-	CP_MAP,
-	NS_MAP,
-	MAX_MAP
-};
-
 enum vidc_clocks {
 	VCODEC_CLK,
 	VCODEC_AHB_CLK,
@@ -188,7 +175,7 @@
 
 struct msm_vidc_resources {
 	struct msm_vidc_fw fw;
-	struct iommu_info io_map[MAX_MAP];
+	struct msm_vidc_iommu_info io_map[MAX_MAP];
 	struct core_clock clock[VCODEC_MAX_CLKS];
 	struct vidc_bus_info bus_info;
 	struct on_chip_mem ocmem;
@@ -240,6 +227,7 @@
 	struct completion completions[SESSION_MSG_END - SESSION_MSG_START + 1];
 	struct v4l2_fh event_handler;
 	struct msm_smem *extradata_handle;
+	wait_queue_head_t kernel_event_queue;
 	bool in_reconfig;
 	u32 reconfig_width;
 	u32 reconfig_height;
@@ -247,6 +235,7 @@
 	u32 ftb_count;
 	u32 fbd_count;
 	struct vb2_buffer *vb2_seq_hdr;
+	void *priv;
 };
 
 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 12ba874..0639dea 100644
--- a/drivers/media/video/msm_vidc/vidc_hal.c
+++ b/drivers/media/video/msm_vidc/vidc_hal.c
@@ -608,6 +608,9 @@
 
 static void set_vbif_registers(struct hal_device *device)
 {
+	/*Disable Dynamic clock gating for Venus VBIF*/
+	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_OUT_AXI_AOOO_EN, 0x00000FFF, 0);
 	write_register(device->hal_data->register_base_addr,
@@ -636,6 +639,8 @@
 			VIDC_VBIF_OUT_WR_LIM_CONF0, 0x00001010, 0);
 	write_register(device->hal_data->register_base_addr,
 			VIDC_VBIF_ARB_CTL, 0x00000030, 0);
+	write_register(device->hal_data->register_base_addr,
+			VIDC_VENUS0_WRAPPER_VBIF_REQ_PRIORITY, 0x5555556, 0);
 }
 
 int vidc_hal_core_init(void *device, int domain)
@@ -654,10 +659,6 @@
 	INIT_LIST_HEAD(&dev->sess_head);
 	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);
diff --git a/drivers/media/video/msm_vidc/vidc_hal_io.h b/drivers/media/video/msm_vidc/vidc_hal_io.h
index c4b1e0c..b85e015 100644
--- a/drivers/media/video/msm_vidc/vidc_hal_io.h
+++ b/drivers/media/video/msm_vidc/vidc_hal_io.h
@@ -124,9 +124,9 @@
 #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 \
+#define VIDC_VENUS0_WRAPPER_VBIF_REQ_PRIORITY \
 	(VIDC_WRAPPER_BASE_OFFS + 0x20)
-#define VIDC_VENUS0_VENUS_WRAPPER_VBIF_PRIORITY_LEVEL \
+#define VIDC_VENUS0_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)
diff --git a/drivers/media/video/msm_wfd/Kconfig b/drivers/media/video/msm_wfd/Kconfig
new file mode 100644
index 0000000..6050d73
--- /dev/null
+++ b/drivers/media/video/msm_wfd/Kconfig
@@ -0,0 +1,6 @@
+menuconfig MSM_WFD
+	bool "Qualcomm MSM Wifi Display Driver"
+		depends on (MSM_VIDC_1080P || MSM_VIDC_V4L2)
+		---help---
+		Enables the Wifi Display driver.
+
diff --git a/drivers/media/video/msm_wfd/Makefile b/drivers/media/video/msm_wfd/Makefile
index 5decaca..813bc64 100644
--- a/drivers/media/video/msm_wfd/Makefile
+++ b/drivers/media/video/msm_wfd/Makefile
@@ -1,5 +1,14 @@
-obj-y += mdp-subdev.o
-obj-y += enc-subdev.o
-obj-y += vsg-subdev.o
-obj-y += wfd-ioctl.o
-obj-y += wfd-util.o
+ifeq ($(CONFIG_MSM_WFD),y)
+  obj-y += wfd-ioctl.o
+  obj-y += wfd-util.o
+  obj-y += vsg-subdev.o
+  ifeq ($(CONFIG_FB_MSM_WRITEBACK_MSM_PANEL),y)
+    obj-y += mdp-4-subdev.o
+  else ifeq ($(CONFIG_FB_MSM_MDSS_WRITEBACK),y)
+    obj-y += mdp-5-subdev.o
+  else
+    obj-y += mdp-dummy-subdev.o
+  endif
+  obj-$(CONFIG_MSM_VIDC_1080P) += enc-mfc-subdev.o
+  obj-$(CONFIG_MSM_VIDC_V4L2) += enc-venus-subdev.o
+endif
diff --git a/drivers/media/video/msm_wfd/enc-subdev.c b/drivers/media/video/msm_wfd/enc-mfc-subdev.c
similarity index 96%
rename from drivers/media/video/msm_wfd/enc-subdev.c
rename to drivers/media/video/msm_wfd/enc-mfc-subdev.c
index e1cabf9..5997345 100644
--- a/drivers/media/video/msm_wfd/enc-subdev.c
+++ b/drivers/media/video/msm_wfd/enc-mfc-subdev.c
@@ -227,7 +227,7 @@
 					BUFFER_TYPE_OUTPUT, pmem_fd,
 					kvaddr, buffer_index, &ion_handle);
 			else
-				WFD_MSG_ERR("Got an output buffer that we "
+				WFD_MSG_ERR("Got an output buffer that we " \
 						"couldn't recognize!\n");
 
 			if (msm_ion_do_cache_op(client_ctx->user_ion_client,
@@ -547,8 +547,8 @@
 
 		if (vcd_property_level.level < VCD_LEVEL_MPEG4_0
 			|| vcd_property_level.level > VCD_LEVEL_MPEG4_X) {
-			WFD_MSG_ERR("Level (%d) out of range"
-					"for codec (%d)\n", level, codec);
+			WFD_MSG_ERR("Level (%d) out of range for codec (%d)\n",
+					level, codec);
 
 			rc = -EINVAL;
 			goto err;
@@ -558,8 +558,8 @@
 
 		if (vcd_property_level.level < VCD_LEVEL_H264_1
 			|| vcd_property_level.level > VCD_LEVEL_H264_5p1) {
-			WFD_MSG_ERR("Level (%d) out of range"
-					"for codec (%d)\n", level, codec);
+			WFD_MSG_ERR("Level (%d) out of range for codec (%d)\n",
+					level, codec);
 
 			rc = -EINVAL;
 			goto err;
@@ -678,9 +678,9 @@
 			vcd_property_profile.profile = VCD_PROFILE_MPEG4_ASP;
 			break;
 		default:
-			WFD_MSG_ERR("Profile %d not supported,"
-					"defaulting to simple (%d)",
-					profile, VCD_PROFILE_MPEG4_SP);
+			WFD_MSG_ERR("Profile %d not supported, defaulting " \
+					"to simple (%d)", profile,
+					VCD_PROFILE_MPEG4_SP);
 			vcd_property_profile.profile = VCD_PROFILE_MPEG4_SP;
 			break;
 		}
@@ -697,17 +697,16 @@
 			vcd_property_profile.profile = VCD_PROFILE_H264_HIGH;
 			break;
 		default:
-			WFD_MSG_ERR("Profile %d not supported,"
-					"defaulting to baseline (%d)",
-					profile, VCD_PROFILE_H264_BASELINE);
+			WFD_MSG_ERR("Profile %d not supported, defaulting " \
+					"to baseline (%d)", profile,
+					VCD_PROFILE_H264_BASELINE);
 			vcd_property_profile.profile =
 				VCD_PROFILE_H264_BASELINE;
 			break;
 		}
 	} else {
-		WFD_MSG_ERR("Codec (%d) not supported,"
-				"not setting profile (%d)",
-				codec, profile);
+		WFD_MSG_ERR("Codec (%d) not supported, not "\
+				"setting profile (%d)",	codec, profile);
 		rc = -ENOTSUPP;
 		goto err_set_profile;
 	}
@@ -2312,6 +2311,73 @@
 	return rc;
 }
 
+long venc_mmap(struct v4l2_subdev *sd, void *arg)
+{
+	struct venc_inst *inst = sd->dev_priv;
+	struct mem_region_map *mmap = arg;
+	struct mem_region *mregion = NULL;
+	unsigned long rc = 0, size = 0;
+	void *paddr = NULL;
+
+	if (!sd) {
+		WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+		return -EINVAL;
+	} else if (!mmap || !mmap->mregion) {
+		WFD_MSG_ERR("Memregion required for %s\n", __func__);
+		return -EINVAL;
+	}
+
+	mregion = mmap->mregion;
+	if (mregion->size % SZ_4K != 0) {
+		WFD_MSG_ERR("Memregion not aligned to %d\n", SZ_4K);
+		return -EINVAL;
+	}
+
+	if (inst->secure) {
+		rc = ion_phys(mmap->ion_client, mregion->ion_handle,
+				(unsigned long *)&paddr,
+				(size_t *)&size);
+	} else {
+		rc = ion_map_iommu(mmap->ion_client, mregion->ion_handle,
+				VIDEO_DOMAIN, VIDEO_MAIN_POOL, SZ_4K,
+				0, (unsigned long *)&paddr,
+				&size, 0, 0);
+	}
+
+	if (rc) {
+		WFD_MSG_ERR("Failed to get physical addr\n");
+		paddr = NULL;
+	} else if (size < mregion->size) {
+		WFD_MSG_ERR("Failed to map enough memory\n");
+		rc = -ENOMEM;
+	}
+
+	mregion->paddr = paddr;
+	return rc;
+}
+
+long venc_munmap(struct v4l2_subdev *sd, void *arg)
+{
+	struct venc_inst *inst = sd->dev_priv;
+	struct mem_region_map *mmap = arg;
+	struct mem_region *mregion = NULL;
+	if (!sd) {
+		WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+		return -EINVAL;
+	} else if (!mregion) {
+		WFD_MSG_ERR("Memregion required for %s\n", __func__);
+		return -EINVAL;
+	}
+
+	mregion = mmap->mregion;
+	if (!inst->secure) {
+		ion_unmap_iommu(mmap->ion_client, mregion->ion_handle,
+				VIDEO_DOMAIN, VIDEO_MAIN_POOL);
+	}
+
+	return 0;
+}
+
 long venc_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
 {
 	long rc = 0;
@@ -2375,6 +2441,12 @@
 	case ENCODE_FLUSH:
 		rc = venc_flush_buffers(sd, arg);
 		break;
+	case ENC_MMAP:
+		rc = venc_mmap(sd, arg);
+		break;
+	case ENC_MUNMAP:
+		rc = venc_munmap(sd, arg);
+		break;
 	default:
 		rc = -1;
 		break;
diff --git a/drivers/media/video/msm_wfd/enc-subdev.h b/drivers/media/video/msm_wfd/enc-subdev.h
index 00eb6da..c6c854e 100644
--- a/drivers/media/video/msm_wfd/enc-subdev.h
+++ b/drivers/media/video/msm_wfd/enc-subdev.h
@@ -14,6 +14,7 @@
 #ifndef _WFD_ENC_SUBDEV_
 #define _WFD_ENC_SUBDEV_
 
+#include <linux/list.h>
 #include <linux/msm_ion.h>
 #include <media/v4l2-subdev.h>
 #include <media/videobuf2-core.h>
@@ -29,6 +30,15 @@
 	u32 cookie;
 	struct ion_handle *ion_handle;
 };
+
+/* FIXME: need to come with a less stupid name */
+struct mem_region_map {
+	struct mem_region *mregion;
+	struct ion_client *ion_client;
+	uint32_t flags;
+	void *cookie;
+};
+
 struct bufreq {
 	u32 count;
 	u32 height;
@@ -44,13 +54,27 @@
 struct venc_msg_ops {
 	void *cookie;
 	void *cbdata;
-	int secure;
+	bool secure;
 	void (*op_buffer_done)(void *cookie, u32 status,
 			struct vb2_buffer *buf);
 	void (*ip_buffer_done)(void *cookie, u32 status,
 			struct mem_region *mregion);
 };
 
+static inline bool mem_region_equals(struct mem_region *a,
+		struct mem_region *b)
+{
+	if (a == b)
+		return true;
+	else if (a->fd || b->fd)
+		return (a->fd == b->fd) &&
+			(a->offset == b->offset);
+	else if (a->kvaddr || b->kvaddr)
+		return a->kvaddr == b->kvaddr;
+	else
+		return false;
+}
+
 #define OPEN  _IOR('V', 1, void *)
 #define CLOSE  _IO('V', 2)
 #define ENCODE_START  _IO('V', 3)
@@ -75,6 +99,8 @@
 #define FREE_INPUT_BUFFER _IOWR('V', 22, struct mem_region *)
 #define FREE_RECON_BUFFERS _IO('V', 23)
 #define ENCODE_FLUSH _IO('V', 24)
+#define ENC_MMAP _IOWR('V', 25, struct mem_region_map *)
+#define ENC_MUNMAP _IOWR('V', 26, struct mem_region_map *)
 
 extern int venc_init(struct v4l2_subdev *sd, u32 val);
 extern int venc_load_fw(struct v4l2_subdev *sd);
diff --git a/drivers/media/video/msm_wfd/enc-venus-subdev.c b/drivers/media/video/msm_wfd/enc-venus-subdev.c
new file mode 100644
index 0000000..04e42f5
--- /dev/null
+++ b/drivers/media/video/msm_wfd/enc-venus-subdev.c
@@ -0,0 +1,1218 @@
+/* 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/bitmap.h>
+#include <linux/completion.h>
+#include <linux/ion.h>
+#include <linux/kthread.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <mach/iommu_domains.h>
+#include <media/msm_vidc.h>
+#include <media/v4l2-subdev.h>
+#include "enc-subdev.h"
+#include "wfd-util.h"
+
+#define BUF_TYPE_OUTPUT V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
+#define BUF_TYPE_INPUT V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
+
+static struct ion_client *venc_ion_client;
+
+struct index_bitmap {
+	unsigned long *bitmap;
+	int size;
+	int size_bits; /*Size in bits, not necessarily size/8 */
+};
+
+struct venc_inst {
+	void *vidc_context;
+	struct mutex lock;
+	struct venc_msg_ops vmops;
+	struct mem_region registered_input_bufs, registered_output_bufs;
+	struct index_bitmap free_input_indices, free_output_indices;
+	int num_output_planes, num_input_planes;
+	struct task_struct *callback_thread;
+	bool callback_thread_running;
+	struct completion dq_complete, cmd_complete;
+	bool secure;
+	int domain;
+};
+
+int venc_load_fw(struct v4l2_subdev *sd)
+{
+	/*No need to explicitly load the fw */
+	return 0;
+}
+
+int venc_init(struct v4l2_subdev *sd, u32 val)
+{
+	if (!venc_ion_client)
+		venc_ion_client = msm_ion_client_create(-1, "wfd_enc_subdev");
+
+	return venc_ion_client ? 0 : -ENOMEM;
+}
+
+static int next_free_index(struct index_bitmap *index_bitmap)
+{
+	int index = find_first_zero_bit(index_bitmap->bitmap,
+			index_bitmap->size_bits);
+
+	return (index >= index_bitmap->size_bits) ?
+		-1 : index;
+}
+
+static int mark_index_busy(struct index_bitmap *index_bitmap, int index)
+{
+	if (index > index_bitmap->size_bits) {
+		WFD_MSG_WARN("Marking unknown index as busy\n");
+		return -EINVAL;
+	}
+	set_bit(index, index_bitmap->bitmap);
+	return 0;
+}
+
+static int mark_index_free(struct index_bitmap *index_bitmap, int index)
+{
+	if (index > index_bitmap->size_bits) {
+		WFD_MSG_WARN("Marking unknown index as free\n");
+		return -EINVAL;
+	}
+	clear_bit(index, index_bitmap->bitmap);
+	return 0;
+}
+
+static int get_list_len(struct mem_region *list)
+{
+	struct mem_region *curr = NULL;
+	int index = 0;
+	list_for_each_entry(curr, &list->list, list) {
+		++index;
+	}
+
+	return index;
+}
+
+static struct mem_region *get_registered_mregion(struct mem_region *list,
+		struct mem_region *mregion)
+{
+	struct mem_region *curr = NULL;
+	list_for_each_entry(curr, &list->list, list) {
+		if (unlikely(mem_region_equals(curr, mregion)))
+			return curr;
+	}
+
+	return NULL;
+}
+
+static int venc_vidc_callback_thread(void *data)
+{
+	struct venc_inst *inst = data;
+	WFD_MSG_DBG("Starting callback thread\n");
+	while (!kthread_should_stop()) {
+		bool dequeue_buf = false;
+		struct v4l2_buffer buffer = {0};
+		struct v4l2_event event = {0};
+		int num_planes = 0;
+		int flags = msm_vidc_wait(inst->vidc_context);
+
+		if (flags & POLLERR) {
+			WFD_MSG_ERR("Encoder reported error\n");
+			break;
+		}
+
+		if (flags & POLLPRI) {
+			bool bail_out = false;
+
+			msm_vidc_dqevent(inst->vidc_context, &event);
+			if (event.type == V4L2_EVENT_MSM_VIDC_CLOSE_DONE) {
+				WFD_MSG_ERR("enc callback thread shutting " \
+						"down normally\n");
+				bail_out = true;
+			} else {
+				WFD_MSG_ERR("Got unknown event %d, ignoring\n",
+						event.id);
+			}
+
+			complete_all(&inst->cmd_complete);
+			if (bail_out)
+				break;
+		}
+
+		if (flags & POLLIN || flags & POLLRDNORM) {
+			buffer.type = BUF_TYPE_OUTPUT;
+			dequeue_buf = true;
+			num_planes = inst->num_output_planes;
+			WFD_MSG_DBG("Output buffer ready!\n");
+		}
+
+		if (flags & POLLOUT || flags & POLLWRNORM) {
+			buffer.type = BUF_TYPE_INPUT;
+			dequeue_buf = true;
+			num_planes = inst->num_input_planes;
+			WFD_MSG_DBG("Input buffer ready!\n");
+		}
+
+		if (dequeue_buf) {
+			int rc = 0;
+			struct v4l2_plane *planes = NULL;
+			struct mem_region *curr = NULL, *mregion = NULL;
+			struct list_head *reg_bufs = NULL;
+			struct index_bitmap *bitmap = NULL;
+
+			planes = kzalloc(sizeof(*planes) * num_planes,
+					GFP_KERNEL);
+			buffer.m.planes = planes;
+			buffer.length = 1;
+			buffer.memory = V4L2_MEMORY_USERPTR;
+			rc = msm_vidc_dqbuf(inst->vidc_context, &buffer);
+
+			if (rc) {
+				WFD_MSG_ERR("Error dequeuing buffer" \
+						"from vidc: %d", rc);
+				goto abort_dequeue;
+			}
+
+			reg_bufs = buffer.type == BUF_TYPE_OUTPUT ?
+				&inst->registered_output_bufs.list :
+				&inst->registered_input_bufs.list;
+
+			bitmap = buffer.type == BUF_TYPE_OUTPUT ?
+				&inst->free_output_indices :
+				&inst->free_input_indices;
+
+			list_for_each_entry(curr, reg_bufs, list) {
+				if ((u32)curr->paddr ==
+						buffer.m.planes[0].m.userptr) {
+					mregion = curr;
+					break;
+				}
+			}
+
+			if (!mregion) {
+				WFD_MSG_ERR("Got done msg for unknown buf\n");
+				goto abort_dequeue;
+			}
+
+			if (buffer.type == BUF_TYPE_OUTPUT &&
+				inst->vmops.op_buffer_done) {
+				struct vb2_buffer *vb =
+					(struct vb2_buffer *)mregion->cookie;
+
+				vb->v4l2_buf.flags = buffer.flags;
+				vb->v4l2_buf.timestamp = buffer.timestamp;
+				vb->v4l2_planes[0].bytesused =
+					buffer.m.planes[0].bytesused;
+
+				inst->vmops.op_buffer_done(
+					inst->vmops.cbdata, 0, vb);
+			} else if (buffer.type == BUF_TYPE_INPUT &&
+					inst->vmops.ip_buffer_done) {
+				inst->vmops.ip_buffer_done(
+						inst->vmops.cbdata,
+						0, mregion);
+			}
+
+			complete_all(&inst->dq_complete);
+			mutex_lock(&inst->lock);
+			mark_index_free(bitmap, buffer.index);
+			mutex_unlock(&inst->lock);
+abort_dequeue:
+			kfree(planes);
+		}
+	}
+
+
+	WFD_MSG_DBG("Exiting callback thread\n");
+	mutex_lock(&inst->lock);
+	inst->callback_thread_running = false;
+	mutex_unlock(&inst->lock);
+	return 0;
+}
+
+static long venc_open(struct v4l2_subdev *sd, void *arg)
+{
+	struct venc_inst *inst = NULL;
+	struct venc_msg_ops *vmops = arg;
+	struct v4l2_event_subscription event = {0};
+	struct msm_vidc_iommu_info maps[MAX_MAP];
+	int rc = 0;
+
+	if (!vmops) {
+		WFD_MSG_ERR("Callbacks required for %s\n", __func__);
+		rc = -EINVAL;
+		goto venc_open_fail;
+	} else if (!sd) {
+		WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+		rc = -EINVAL;
+		goto venc_open_fail;
+	}
+
+	inst = kzalloc(sizeof(*inst), GFP_KERNEL);
+	if (!inst) {
+		WFD_MSG_ERR("Failed to allocate memory\n");
+		rc = -EINVAL;
+		goto venc_open_fail;
+	}
+
+	inst->secure = false;
+	inst->vmops = *vmops;
+	INIT_LIST_HEAD(&inst->registered_output_bufs.list);
+	INIT_LIST_HEAD(&inst->registered_input_bufs.list);
+	init_completion(&inst->dq_complete);
+	init_completion(&inst->cmd_complete);
+	mutex_init(&inst->lock);
+	inst->vidc_context = msm_vidc_open(MSM_VIDC_CORE_0, MSM_VIDC_ENCODER);
+	if (!inst->vidc_context) {
+		WFD_MSG_ERR("Failed to create vidc context\n");
+		rc = -ENXIO;
+		goto vidc_open_fail;
+	}
+
+	event.type = V4L2_EVENT_MSM_VIDC_CLOSE_DONE;
+	rc = msm_vidc_subscribe_event(inst->vidc_context, &event);
+	if (rc) {
+		WFD_MSG_ERR("Failed to subscribe to CLOSE_DONE event\n");
+		goto vidc_subscribe_fail;
+	}
+
+	event.type = V4L2_EVENT_MSM_VIDC_FLUSH_DONE;
+	rc = msm_vidc_subscribe_event(inst->vidc_context, &event);
+	if (rc) {
+		WFD_MSG_ERR("Failed to subscribe to FLUSH_DONE event\n");
+		goto vidc_subscribe_fail;
+	}
+
+	rc = msm_vidc_get_iommu_maps(inst->vidc_context, maps);
+	if (rc) {
+		WFD_MSG_ERR("Failed to retreive domain mappings\n");
+		rc = -ENODATA;
+		goto vidc_subscribe_fail;
+	}
+
+	inst->domain = maps[inst->secure ? CP_MAP : NS_MAP].domain;
+
+	inst->callback_thread = kthread_run(venc_vidc_callback_thread, inst,
+					"venc_vidc_callback_thread");
+	if (IS_ERR(inst->callback_thread)) {
+		WFD_MSG_ERR("Failed to create callback thread\n");
+		rc = PTR_ERR(inst->callback_thread);
+		inst->callback_thread = NULL;
+		goto vidc_kthread_create_fail;
+	}
+	inst->callback_thread_running = true;
+
+	sd->dev_priv = inst;
+	vmops->cookie = inst;
+	return 0;
+vidc_kthread_create_fail:
+	event.type = V4L2_EVENT_MSM_VIDC_CLOSE_DONE;
+	msm_vidc_unsubscribe_event(inst->vidc_context, &event);
+
+	event.type = V4L2_EVENT_MSM_VIDC_FLUSH_DONE;
+	msm_vidc_unsubscribe_event(inst->vidc_context, &event);
+vidc_subscribe_fail:
+	msm_vidc_close(inst->vidc_context);
+vidc_open_fail:
+	kfree(inst);
+venc_open_fail:
+	return rc;
+}
+
+static long venc_close(struct v4l2_subdev *sd, void *arg)
+{
+	struct venc_inst *inst = NULL;
+	struct v4l2_event_subscription event = {0};
+	struct v4l2_encoder_cmd enc_cmd = {0};
+	int rc = 0;
+
+	if (!sd) {
+		WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+		rc = -EINVAL;
+		goto venc_close_fail;
+	}
+
+	inst = (struct venc_inst *)sd->dev_priv;
+	enc_cmd.cmd = V4L2_ENC_CMD_STOP;
+	msm_vidc_encoder_cmd(inst->vidc_context, &enc_cmd);
+
+	wait_for_completion(&inst->cmd_complete);
+
+	if (inst->callback_thread && inst->callback_thread_running)
+		kthread_stop(inst->callback_thread);
+
+	event.type = V4L2_EVENT_MSM_VIDC_CLOSE_DONE;
+	rc = msm_vidc_unsubscribe_event(inst->vidc_context, &event);
+	if (rc)
+		WFD_MSG_WARN("Failed to unsubscribe close event\n");
+
+	event.type = V4L2_EVENT_MSM_VIDC_FLUSH_DONE;
+	rc = msm_vidc_unsubscribe_event(inst->vidc_context, &event);
+	if (rc)
+		WFD_MSG_WARN("Failed to unsubscribe flush event\n");
+
+	rc = msm_vidc_close(inst->vidc_context);
+	if (rc)
+		WFD_MSG_WARN("Failed to close vidc context\n");
+
+	kfree(inst);
+	sd->dev_priv = inst = NULL;
+venc_close_fail:
+	return rc;
+}
+
+static long venc_get_buffer_req(struct v4l2_subdev *sd, void *arg)
+{
+	int rc = 0;
+	struct venc_inst *inst = NULL;
+	struct bufreq *bufreq = arg;
+	struct v4l2_requestbuffers v4l2_bufreq = {0};
+	struct v4l2_format v4l2_format = {0};
+
+	if (!sd) {
+		WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+		rc = -EINVAL;
+		goto venc_buf_req_fail;
+	} else if (!arg) {
+		WFD_MSG_ERR("Invalid buffer requirements\n");
+		rc = -EINVAL;
+		goto venc_buf_req_fail;
+	}
+
+	inst = (struct venc_inst *)sd->dev_priv;
+	/* Get buffer count */
+	v4l2_bufreq = (struct v4l2_requestbuffers) {
+		.count = bufreq->count,
+		.type = BUF_TYPE_OUTPUT,
+		.memory = V4L2_MEMORY_USERPTR,
+	};
+
+	rc = msm_vidc_reqbufs(inst->vidc_context, &v4l2_bufreq);
+	if (rc) {
+		WFD_MSG_ERR("Failed getting buffer requirements\n");
+		goto venc_buf_req_fail;
+	}
+
+	/* Get buffer size */
+	v4l2_format.type = BUF_TYPE_OUTPUT;
+	rc = msm_vidc_g_fmt(inst->vidc_context, &v4l2_format);
+	if (rc) {
+		WFD_MSG_ERR("Failed getting OP buffer size\n");
+		goto venc_buf_req_fail;
+	}
+
+	bufreq->count = v4l2_bufreq.count;
+	bufreq->size = v4l2_format.fmt.pix_mp.plane_fmt[0].sizeimage;
+
+	inst->free_output_indices.size_bits = bufreq->count;
+	inst->free_output_indices.size = roundup(bufreq->count,
+				sizeof(unsigned long)) / sizeof(unsigned long);
+	inst->free_output_indices.bitmap = kzalloc(inst->free_output_indices.
+						size, GFP_KERNEL);
+venc_buf_req_fail:
+	return rc;
+}
+
+static long venc_set_buffer_req(struct v4l2_subdev *sd, void *arg)
+{
+	int rc = 0;
+	struct venc_inst *inst = NULL;
+	struct bufreq *bufreq = arg;
+	struct v4l2_requestbuffers v4l2_bufreq = {0};
+	struct v4l2_format v4l2_format = {0};
+
+	if (!sd) {
+		WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+		rc = -EINVAL;
+		goto venc_buf_req_fail;
+	} else if (!arg) {
+		WFD_MSG_ERR("Invalid buffer requirements\n");
+		rc = -EINVAL;
+		goto venc_buf_req_fail;
+	}
+
+	inst = (struct venc_inst *)sd->dev_priv;
+
+	/* Attempt to set buffer count */
+	v4l2_bufreq = (struct v4l2_requestbuffers) {
+		.count = bufreq->count,
+		.type = BUF_TYPE_INPUT,
+		.memory = V4L2_MEMORY_USERPTR,
+	};
+
+	rc = msm_vidc_reqbufs(inst->vidc_context, &v4l2_bufreq);
+	if (rc) {
+		WFD_MSG_ERR("Failed getting buffer requirements");
+		goto venc_buf_req_fail;
+	}
+
+	/* Get buffer size */
+	v4l2_format.type = BUF_TYPE_INPUT;
+	rc = msm_vidc_g_fmt(inst->vidc_context, &v4l2_format);
+	if (rc) {
+		WFD_MSG_ERR("Failed getting OP buffer size\n");
+		goto venc_buf_req_fail;
+	}
+
+	bufreq->count = v4l2_bufreq.count;
+	bufreq->size = v4l2_format.fmt.pix_mp.plane_fmt[0].sizeimage;
+
+	inst->free_input_indices.size_bits = bufreq->count;
+	inst->free_input_indices.size = roundup(bufreq->count,
+				sizeof(unsigned long)) / sizeof(unsigned long);
+	inst->free_input_indices.bitmap = kzalloc(inst->free_input_indices.
+						size, GFP_KERNEL);
+venc_buf_req_fail:
+	return rc;
+}
+
+static long venc_start(struct v4l2_subdev *sd)
+{
+	struct venc_inst *inst = NULL;
+	int rc = 0;
+
+	if (!sd) {
+		WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+		rc = -EINVAL;
+		goto venc_start_fail;
+	}
+
+	inst = (struct venc_inst *)sd->dev_priv;
+
+	rc = msm_vidc_streamon(inst->vidc_context, BUF_TYPE_OUTPUT);
+	if (rc) {
+		WFD_MSG_ERR("Failed to streamon vidc's output port");
+		goto venc_start_fail;
+	}
+
+	rc = msm_vidc_streamon(inst->vidc_context, BUF_TYPE_INPUT);
+	if (rc) {
+		WFD_MSG_ERR("Failed to streamon vidc's input port");
+		goto venc_start_fail;
+	}
+
+venc_start_fail:
+	return rc;
+}
+
+static long venc_stop(struct v4l2_subdev *sd)
+{
+	struct venc_inst *inst = NULL;
+	int rc = 0;
+
+	if (!sd) {
+		WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+		rc = -EINVAL;
+		goto venc_stop_fail;
+	}
+
+	inst = (struct venc_inst *)sd->dev_priv;
+
+	rc = msm_vidc_streamoff(inst->vidc_context, BUF_TYPE_INPUT);
+	if (rc) {
+		WFD_MSG_ERR("Failed to streamoff vidc's input port");
+		goto venc_stop_fail;
+	}
+
+	rc = msm_vidc_streamoff(inst->vidc_context, BUF_TYPE_OUTPUT);
+	if (rc) {
+		WFD_MSG_ERR("Failed to streamoff vidc's output port");
+		goto venc_stop_fail;
+	}
+
+venc_stop_fail:
+	return rc;
+}
+
+static long venc_set_input_buffer(struct v4l2_subdev *sd, void *arg)
+{
+	int rc = 0;
+	struct venc_inst *inst = NULL;
+	struct v4l2_buffer buf = {0};
+	struct v4l2_plane plane = {0};
+	struct mem_region *mregion = arg;
+
+	if (!sd) {
+		WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+		rc =  -EINVAL;
+		goto set_input_buffer_fail;
+	} else if (!arg) {
+		WFD_MSG_ERR("Invalid input buffer\n");
+		rc =  -EINVAL;
+		goto set_input_buffer_fail;
+	}
+
+	inst = (struct venc_inst *)sd->dev_priv;
+	if (get_registered_mregion(&inst->registered_input_bufs, mregion)) {
+		WFD_MSG_ERR("Duplicate input buffer\n");
+		rc = -EEXIST;
+		goto set_input_buffer_fail;
+	}
+
+	mregion = kzalloc(sizeof(*mregion), GFP_KERNEL);
+	*mregion = *(struct mem_region *)arg;
+
+	plane = (struct v4l2_plane) {
+		.length = mregion->size,
+		.m.userptr = (u32)mregion->paddr,
+	};
+
+	buf = (struct v4l2_buffer) {
+		.index = get_list_len(&inst->registered_input_bufs),
+		.type = BUF_TYPE_INPUT,
+		.bytesused = 0,
+		.memory = V4L2_MEMORY_USERPTR,
+		.m.planes = &plane,
+		.length = 1,
+	};
+
+	WFD_MSG_DBG("Prepare %p with index, %d",
+		(void *)buf.m.planes[0].m.userptr, buf.index);
+	rc = msm_vidc_prepare_buf(inst->vidc_context, &buf);
+	if (rc) {
+		WFD_MSG_ERR("Failed to prepare input buffer\n");
+		goto set_input_buffer_fail;
+	}
+
+	list_add_tail(&mregion->list, &inst->registered_input_bufs.list);
+	return 0;
+set_input_buffer_fail:
+	kfree(mregion);
+	return rc;
+}
+
+static int venc_map_user_to_kernel(struct venc_inst *inst,
+		struct mem_region *mregion)
+{
+	int rc = 0;
+	unsigned long flags = 0, size = 0;
+	if (!mregion) {
+		rc = -EINVAL;
+		goto venc_map_fail;
+	}
+
+	mregion->ion_handle = ion_import_dma_buf(venc_ion_client, mregion->fd);
+	if (IS_ERR_OR_NULL(mregion->ion_handle)) {
+		rc = PTR_ERR(mregion->ion_handle);
+		WFD_MSG_ERR("Failed to get handle: %p, %d, %d, %d\n",
+			venc_ion_client, mregion->fd, mregion->offset, rc);
+		mregion->ion_handle = NULL;
+		goto venc_map_fail;
+	}
+
+	rc = ion_handle_get_flags(venc_ion_client, mregion->ion_handle, &flags);
+	if (rc) {
+		WFD_MSG_ERR("Failed to get ion flags %d\n", rc);
+		goto venc_map_fail;
+	}
+
+	mregion->kvaddr = ion_map_kernel(venc_ion_client,
+				mregion->ion_handle, flags);
+
+	if (IS_ERR_OR_NULL(mregion->kvaddr)) {
+		WFD_MSG_ERR("Failed to map buffer into kernel\n");
+		rc = PTR_ERR(mregion->kvaddr);
+		mregion->kvaddr = NULL;
+		goto venc_map_fail;
+	}
+
+	rc = ion_map_iommu(venc_ion_client, mregion->ion_handle,
+			inst->domain, 0, SZ_4K, 0,
+			(unsigned long *)&mregion->paddr, &size, flags, 0);
+
+	if (rc) {
+		WFD_MSG_ERR("Failed to map into iommu\n");
+		goto venc_map_iommu_map_fail;
+	} else if (size < mregion->size) {
+		WFD_MSG_ERR("Failed to iommu map the correct size\n");
+		goto venc_map_iommu_size_fail;
+	}
+
+	return 0;
+venc_map_iommu_size_fail:
+	ion_unmap_iommu(venc_ion_client, mregion->ion_handle,
+			inst->domain, 0);
+venc_map_iommu_map_fail:
+	ion_unmap_kernel(venc_ion_client, mregion->ion_handle);
+venc_map_fail:
+	return rc;
+}
+
+static int venc_unmap_user_to_kernel(struct venc_inst *inst,
+		struct mem_region *mregion)
+{
+	if (!mregion || !mregion->ion_handle)
+		return 0;
+
+	if (mregion->paddr) {
+		ion_unmap_iommu(venc_ion_client, mregion->ion_handle,
+				inst->domain, 0);
+		mregion->paddr = NULL;
+	}
+
+	if (mregion->kvaddr) {
+		ion_unmap_kernel(venc_ion_client, mregion->ion_handle);
+		mregion->kvaddr = NULL;
+	}
+
+
+	return 0;
+}
+
+static long venc_set_output_buffer(struct v4l2_subdev *sd, void *arg)
+{
+	int rc = 0;
+	struct venc_inst *inst = NULL;
+	struct v4l2_buffer buf = {0};
+	struct v4l2_plane plane = {0};
+	struct mem_region *mregion = arg;
+
+	if (!sd) {
+		WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+		rc = -EINVAL;
+		goto venc_set_output_buffer_fail;
+	} else if (!mregion) {
+		WFD_MSG_ERR("Invalid output buffer\n");
+		rc = -EINVAL;
+		goto venc_set_output_buffer_fail;
+	}
+
+	inst = (struct venc_inst *)sd->dev_priv;
+
+	/* Check if buf already registered */
+	if (get_registered_mregion(&inst->registered_output_bufs, mregion)) {
+		WFD_MSG_ERR("Duplicate output buffer\n");
+		rc = -EEXIST;
+		goto venc_set_output_buffer_fail;
+	}
+
+	mregion = kzalloc(sizeof(*mregion), GFP_KERNEL);
+
+	if (!mregion) {
+		WFD_MSG_ERR("Failed to allocate memory\n");
+		goto venc_set_output_buffer_fail;
+	}
+
+	*mregion = *(struct mem_region *)arg;
+	INIT_LIST_HEAD(&mregion->list);
+
+	rc = venc_map_user_to_kernel(inst, mregion);
+	if (rc) {
+		WFD_MSG_ERR("Failed to map output buffer\n");
+		goto venc_set_output_buffer_map_fail;
+	}
+
+	plane = (struct v4l2_plane) {
+		.length = mregion->size,
+		.m.userptr = (u32)mregion->paddr,
+	};
+
+	buf = (struct v4l2_buffer) {
+		.index = get_list_len(&inst->registered_output_bufs),
+		.type = BUF_TYPE_OUTPUT,
+		.bytesused = 0,
+		.memory = V4L2_MEMORY_USERPTR,
+		.m.planes = &plane,
+		.length = 1,
+	};
+
+	WFD_MSG_DBG("Prepare %p with index, %d",
+		(void *)buf.m.planes[0].m.userptr, buf.index);
+	rc = msm_vidc_prepare_buf(inst->vidc_context, &buf);
+	if (rc) {
+		WFD_MSG_ERR("Failed to prepare output buffer\n");
+		goto venc_set_output_buffer_prepare_fail;
+	}
+
+	list_add_tail(&mregion->list, &inst->registered_output_bufs.list);
+	return rc;
+venc_set_output_buffer_prepare_fail:
+	venc_unmap_user_to_kernel(inst, mregion);
+venc_set_output_buffer_map_fail:
+	kfree(mregion);
+venc_set_output_buffer_fail:
+	return rc;
+}
+
+static long venc_set_format(struct v4l2_subdev *sd, void *arg)
+{
+	struct venc_inst *inst = NULL;
+	struct v4l2_format *fmt = arg, temp;
+	int rc = 0;
+
+	if (!sd) {
+		WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+		rc = -EINVAL;
+		goto venc_set_format_fail;
+	} else if (!fmt) {
+		WFD_MSG_ERR("Invalid format\n");
+		rc = -EINVAL;
+		goto venc_set_format_fail;
+	} else if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+		WFD_MSG_ERR("Invalid buffer type %d\n", fmt->type);
+		rc = -ENOTSUPP;
+		goto venc_set_format_fail;
+	}
+
+	inst = (struct venc_inst *)sd->dev_priv;
+	temp = (struct v4l2_format) {
+		.type = BUF_TYPE_OUTPUT,
+		.fmt.pix_mp = (struct v4l2_pix_format_mplane) {
+			.width = fmt->fmt.pix.width,
+			.height = fmt->fmt.pix.height,
+			.pixelformat = fmt->fmt.pix.pixelformat,
+		},
+	};
+
+	rc = msm_vidc_s_fmt(inst->vidc_context, &temp);
+
+	if (rc) {
+		WFD_MSG_ERR("Failed to format for output port\n");
+		goto venc_set_format_fail;
+	} else if (!temp.fmt.pix_mp.num_planes) {
+		WFD_MSG_ERR("No. of planes for output buffers make no sense\n");
+		rc = -EINVAL;
+		goto venc_set_format_fail;
+	}
+	fmt->fmt.pix.sizeimage = temp.fmt.pix_mp.plane_fmt[0].sizeimage;
+	inst->num_output_planes = temp.fmt.pix_mp.num_planes;
+
+	temp.type = BUF_TYPE_INPUT;
+	temp.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12;
+	rc = msm_vidc_s_fmt(inst->vidc_context, &temp);
+	inst->num_input_planes = temp.fmt.pix_mp.num_planes;
+
+	if (rc) {
+		WFD_MSG_ERR("Failed to format for input port\n");
+		goto venc_set_format_fail;
+	}
+venc_set_format_fail:
+	return rc;
+}
+
+static long venc_set_framerate(struct v4l2_subdev *sd, void *arg)
+{
+	struct venc_inst *inst = NULL;
+	struct v4l2_control ctrl = {0};
+
+	if (!sd) {
+		WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+		return -EINVAL;
+	} else if (!arg) {
+		WFD_MSG_ERR("Invalid framerate\n");
+		return -EINVAL;
+	}
+
+	inst = (struct venc_inst *)sd->dev_priv;
+	ctrl.id = V4L2_CID_MPEG_VIDC_VIDEO_FRAME_RATE;
+	ctrl.value = 30;
+	return msm_vidc_s_ctrl(inst->vidc_context, &ctrl);
+}
+
+static long venc_fill_outbuf(struct v4l2_subdev *sd, void *arg)
+{
+	struct venc_inst *inst = NULL;
+	struct mem_region *mregion = NULL;
+	struct v4l2_buffer buffer = {0};
+	struct v4l2_plane plane = {0};
+	int index = 0, rc = 0;
+
+	if (!sd) {
+		WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+		return -EINVAL;
+	} else if (!arg) {
+		WFD_MSG_ERR("Invalid output buffer ot fill\n");
+		return -EINVAL;
+	}
+
+	inst = (struct venc_inst *)sd->dev_priv;
+	mregion = get_registered_mregion(&inst->registered_output_bufs, arg);
+
+	if (!mregion) {
+		WFD_MSG_ERR("Output buffer not registered\n");
+		return -ENOENT;
+	}
+
+	plane = (struct v4l2_plane) {
+		.length = mregion->size,
+		.m.userptr = (u32)mregion->paddr,
+	};
+
+	while (true) {
+		mutex_lock(&inst->lock);
+		index = next_free_index(&inst->free_output_indices);
+		mutex_unlock(&inst->lock);
+
+		if (index < 0)
+			wait_for_completion(&inst->dq_complete);
+		else
+			break;
+	}
+
+	buffer = (struct v4l2_buffer) {
+		.index = index,
+		.type = BUF_TYPE_OUTPUT,
+		.memory = V4L2_MEMORY_USERPTR,
+		.m.planes = &plane,
+		.length = 1,
+	};
+
+	WFD_MSG_DBG("Fill buffer %p with index, %d",
+		(void *)buffer.m.planes[0].m.userptr, buffer.index);
+	rc = msm_vidc_qbuf(inst->vidc_context, &buffer);
+	if (!rc) {
+		mutex_lock(&inst->lock);
+		mark_index_busy(&inst->free_output_indices, index);
+		mutex_unlock(&inst->lock);
+	}
+	return rc;
+
+}
+
+static long venc_encode_frame(struct v4l2_subdev *sd, void *arg)
+{
+	struct venc_inst *inst = NULL;
+	struct venc_buf_info *venc_buf = arg;
+	struct mem_region *mregion = NULL;
+	struct v4l2_buffer buffer = {0};
+	struct v4l2_plane plane = {0};
+	int index = 0, rc = 0;
+
+	if (!sd) {
+		WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+		return -EINVAL;
+	} else if (!venc_buf) {
+		WFD_MSG_ERR("Invalid output buffer ot fill\n");
+		return -EINVAL;
+	}
+
+	inst = (struct venc_inst *)sd->dev_priv;
+	mregion = venc_buf->mregion;
+
+	plane = (struct v4l2_plane) {
+		.length = mregion->size,
+		.m.userptr = (u32)mregion->paddr,
+		.bytesused = mregion->size,
+	};
+
+	while (true) {
+		mutex_lock(&inst->lock);
+		index = next_free_index(&inst->free_input_indices);
+		mutex_unlock(&inst->lock);
+
+		if (index < 0)
+			wait_for_completion(&inst->dq_complete);
+		else
+			break;
+	}
+
+	buffer = (struct v4l2_buffer) {
+		.index = index,
+		.type = BUF_TYPE_INPUT,
+		.timestamp = ns_to_timeval(venc_buf->timestamp),
+		.memory = V4L2_MEMORY_USERPTR,
+		.m.planes = &plane,
+		.length = 1,
+	};
+
+	WFD_MSG_DBG("Encode buffer %p with index, %d",
+		(void *)buffer.m.planes[0].m.userptr, buffer.index);
+	rc = msm_vidc_qbuf(inst->vidc_context, &buffer);
+	if (!rc) {
+		mutex_lock(&inst->lock);
+		mark_index_busy(&inst->free_input_indices, index);
+		mutex_unlock(&inst->lock);
+	}
+	return rc;
+}
+
+static long venc_alloc_recon_buffers(struct v4l2_subdev *sd, void *arg)
+{
+	/* vidc driver allocates internally on streamon */
+	return 0;
+}
+
+static long venc_free_buffer(struct venc_inst *inst, int type,
+		struct mem_region *to_free, bool unmap_user_buffer)
+{
+	struct mem_region *mregion = NULL;
+	struct mem_region *buf_list = NULL;
+
+	if (type == BUF_TYPE_OUTPUT) {
+		buf_list = &inst->registered_output_bufs;
+	} else if (type == BUF_TYPE_INPUT) {
+		buf_list = &inst->registered_input_bufs;
+	} else {
+		WFD_MSG_ERR("Trying to free a buffer of unknown type\n");
+		return -EINVAL;
+	}
+
+	mregion = get_registered_mregion(buf_list, to_free);
+
+	if (!mregion) {
+		WFD_MSG_ERR("Buffer not registered, cannot free\n");
+		return -ENOENT;
+	}
+
+	if (unmap_user_buffer) {
+		int rc = venc_unmap_user_to_kernel(inst, mregion);
+		if (rc)
+			WFD_MSG_WARN("Unable to unmap user buffer\n");
+	}
+
+	list_del(&mregion->list);
+	kfree(mregion);
+	return 0;
+}
+static long venc_free_output_buffer(struct v4l2_subdev *sd, void *arg)
+{
+	int rc = 0;
+	struct venc_inst *inst = NULL;
+
+	if (!sd) {
+		WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+		rc = -EINVAL;
+		goto venc_free_output_buffer_fail;
+	} else if (!arg) {
+		WFD_MSG_ERR("Invalid output buffer\n");
+		rc = -EINVAL;
+		goto venc_free_output_buffer_fail;
+	}
+
+	inst = (struct venc_inst *)sd->dev_priv;
+	return venc_free_buffer(inst, BUF_TYPE_OUTPUT, arg, true);
+venc_free_output_buffer_fail:
+	return rc;
+}
+
+static long venc_flush_buffers(struct v4l2_subdev *sd, void *arg)
+{
+	struct venc_inst *inst = NULL;
+	struct v4l2_encoder_cmd enc_cmd = {0};
+	int rc = 0;
+
+	if (!sd) {
+		WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+		rc = -EINVAL;
+		goto venc_flush_buffers_fail;
+	}
+
+	inst = (struct venc_inst *)sd->dev_priv;
+
+	enc_cmd.cmd = V4L2_ENC_QCOM_CMD_FLUSH;
+	enc_cmd.flags = BUF_TYPE_INPUT | BUF_TYPE_OUTPUT;
+	msm_vidc_encoder_cmd(inst->vidc_context, &enc_cmd);
+
+	wait_for_completion(&inst->cmd_complete);
+venc_flush_buffers_fail:
+	return rc;
+}
+
+static long venc_free_input_buffer(struct v4l2_subdev *sd, void *arg)
+{
+	int rc = 0;
+	struct venc_inst *inst = NULL;
+
+	if (!sd) {
+		WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+		rc = -EINVAL;
+		goto venc_free_input_buffer_fail;
+	} else if (!arg) {
+		WFD_MSG_ERR("Invalid output buffer\n");
+		rc = -EINVAL;
+		goto venc_free_input_buffer_fail;
+	}
+
+	inst = (struct venc_inst *)sd->dev_priv;
+	return venc_free_buffer(inst, BUF_TYPE_INPUT, arg, false);
+venc_free_input_buffer_fail:
+	return rc;
+}
+
+static long venc_free_recon_buffers(struct v4l2_subdev *sd, void *arg)
+{
+	/* vidc driver takes care of this */
+	return 0;
+}
+
+static long venc_set_property(struct v4l2_subdev *sd, void *arg)
+{
+	struct venc_inst *inst = NULL;
+	struct v4l2_control *ctrl = arg;
+
+	if (!sd) {
+		WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+		return -EINVAL;
+	}
+
+	inst = (struct venc_inst *)sd->dev_priv;
+	if (ctrl->id == V4L2_CID_MPEG_VIDEO_HEADER_MODE) {
+		/* XXX: We don't support this yet, but to prevent unncessary
+		 * target specific code for the client, we'll not error out.
+		 * The client ideally shouldn't notice this */
+		return 0;
+	}
+
+	return msm_vidc_s_ctrl(inst->vidc_context, (struct v4l2_control *)arg);
+}
+
+static long venc_get_property(struct v4l2_subdev *sd, void *arg)
+{
+	struct venc_inst *inst = NULL;
+
+	if (!sd) {
+		WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+		return -EINVAL;
+	}
+
+	inst = (struct venc_inst *)sd->dev_priv;
+	return msm_vidc_g_ctrl(inst->vidc_context, (struct v4l2_control *)arg);
+}
+
+long venc_mmap(struct v4l2_subdev *sd, void *arg)
+{
+	struct mem_region_map *mmap = arg;
+	struct mem_region *mregion = NULL;
+	unsigned long rc = 0, size = 0;
+	void *paddr = NULL;
+	struct venc_inst *inst = NULL;
+
+	if (!sd) {
+		WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+		return -EINVAL;
+	} else if (!mmap || !mmap->mregion) {
+		WFD_MSG_ERR("Memregion required for %s\n", __func__);
+		return -EINVAL;
+	}
+
+	inst = (struct venc_inst *)sd->dev_priv;
+	mregion = mmap->mregion;
+	if (mregion->size % SZ_4K != 0) {
+		WFD_MSG_ERR("Memregion not aligned to %d\n", SZ_4K);
+		return -EINVAL;
+	}
+
+	rc = ion_map_iommu(mmap->ion_client, mregion->ion_handle,
+			inst->domain, 0, SZ_4K, 0, (unsigned long *)&paddr,
+			&size, 0, 0);
+
+	if (rc) {
+		WFD_MSG_ERR("Failed to get physical addr\n");
+		paddr = NULL;
+	} else if (size < mregion->size) {
+		WFD_MSG_ERR("Failed to map enough memory\n");
+		rc = -ENOMEM;
+	}
+
+	mregion->paddr = paddr;
+	return rc;
+}
+
+long venc_munmap(struct v4l2_subdev *sd, void *arg)
+{
+	struct mem_region_map *mmap = arg;
+	struct mem_region *mregion = NULL;
+	struct venc_inst *inst = NULL;
+
+	if (!sd) {
+		WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+		return -EINVAL;
+	} else if (!mmap || !mmap->mregion) {
+		WFD_MSG_ERR("Memregion required for %s\n", __func__);
+		return -EINVAL;
+	}
+
+	inst = (struct venc_inst *)sd->dev_priv;
+	mregion = mmap->mregion;
+
+	ion_unmap_iommu(mmap->ion_client, mregion->ion_handle,
+			inst->domain, 0);
+	return 0;
+}
+
+long venc_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+	long rc = 0;
+	switch (cmd) {
+	case OPEN:
+		rc = venc_open(sd, arg);
+		break;
+	case CLOSE:
+		rc = venc_close(sd, arg);
+		break;
+	case ENCODE_START:
+		rc = venc_start(sd);
+		break;
+	case ENCODE_FRAME:
+		venc_encode_frame(sd, arg);
+		break;
+	case ENCODE_STOP:
+		rc = venc_stop(sd);
+		break;
+	case SET_PROP:
+		rc = venc_set_property(sd, arg);
+		break;
+	case GET_PROP:
+		rc = venc_get_property(sd, arg);
+		break;
+	case GET_BUFFER_REQ:
+		rc = venc_get_buffer_req(sd, arg);
+		break;
+	case SET_BUFFER_REQ:
+		rc = venc_set_buffer_req(sd, arg);
+		break;
+	case FREE_BUFFER:
+		break;
+	case FILL_OUTPUT_BUFFER:
+		rc = venc_fill_outbuf(sd, arg);
+		break;
+	case SET_FORMAT:
+		rc = venc_set_format(sd, arg);
+		break;
+	case SET_FRAMERATE:
+		rc = venc_set_framerate(sd, arg);
+		break;
+	case SET_INPUT_BUFFER:
+		rc = venc_set_input_buffer(sd, arg);
+		break;
+	case SET_OUTPUT_BUFFER:
+		rc = venc_set_output_buffer(sd, arg);
+		break;
+	case ALLOC_RECON_BUFFERS:
+		rc = venc_alloc_recon_buffers(sd, arg);
+		break;
+	case FREE_OUTPUT_BUFFER:
+		rc = venc_free_output_buffer(sd, arg);
+		break;
+	case FREE_INPUT_BUFFER:
+		rc = venc_free_input_buffer(sd, arg);
+		break;
+	case FREE_RECON_BUFFERS:
+		rc = venc_free_recon_buffers(sd, arg);
+		break;
+	case ENCODE_FLUSH:
+		rc = venc_flush_buffers(sd, arg);
+		break;
+	case ENC_MMAP:
+		rc = venc_mmap(sd, arg);
+		break;
+	case ENC_MUNMAP:
+		rc = venc_munmap(sd, arg);
+		break;
+	default:
+		WFD_MSG_ERR("Unknown ioctl %d to enc-subdev\n", cmd);
+		rc = -ENOTSUPP;
+		break;
+	}
+	return rc;
+}
diff --git a/drivers/media/video/msm_wfd/mdp-subdev.c b/drivers/media/video/msm_wfd/mdp-4-subdev.c
similarity index 67%
copy from drivers/media/video/msm_wfd/mdp-subdev.c
copy to drivers/media/video/msm_wfd/mdp-4-subdev.c
index 886b0ba..c68d5d4 100644
--- a/drivers/media/video/msm_wfd/mdp-subdev.c
+++ b/drivers/media/video/msm_wfd/mdp-4-subdev.c
@@ -10,53 +10,66 @@
 * GNU General Public License for more details.
 *
 */
+#include <linux/msm_mdp.h>
+#include <mach/iommu_domains.h>
+#include <media/videobuf2-core.h>
+#include "enc-subdev.h"
 #include "mdp-subdev.h"
 #include "wfd-util.h"
-#include <media/videobuf2-core.h>
-#include <linux/msm_mdp.h>
 
 struct mdp_instance {
 	struct fb_info *mdp;
 	u32 height;
 	u32 width;
+	bool secure;
+	bool uses_iommu_split_domain;
 };
 
 int mdp_init(struct v4l2_subdev *sd, u32 val)
 {
 	return 0;
 }
+
 int mdp_open(struct v4l2_subdev *sd, void *arg)
 {
 	struct mdp_instance *inst = kzalloc(sizeof(struct mdp_instance),
 					GFP_KERNEL);
-	void **cookie = (void **)arg;
+	struct mdp_msg_ops *mops = arg;
 	int rc = 0;
 	struct fb_info *fbi = NULL;
 
 	if (!inst) {
 		WFD_MSG_ERR("Out of memory\n");
-		return -ENOMEM;
+		rc = -ENOMEM;
+		goto mdp_open_fail;
+	} else if (!mops) {
+		WFD_MSG_ERR("Invalid arguments\n");
+		rc = -EINVAL;
+		goto mdp_open_fail;
 	}
 
 	fbi = msm_fb_get_writeback_fb();
 	if (!fbi) {
 		WFD_MSG_ERR("Failed to acquire mdp instance\n");
 		rc = -ENODEV;
-		goto exit;
+		goto mdp_open_fail;
 	}
 
 	/*Tell HDMI daemon to open fb2*/
 	rc = kobject_uevent(&fbi->dev->kobj, KOBJ_ADD);
 	if (rc) {
 		WFD_MSG_ERR("Failed add to kobj");
-		goto exit;
+		goto mdp_open_fail;
 	}
 
 	msm_fb_writeback_init(fbi);
 	inst->mdp = fbi;
-	*cookie = inst;
+	inst->secure = mops->secure;
+	inst->uses_iommu_split_domain = mops->iommu_split_domain;
+
+	mops->cookie = inst;
 	return rc;
-exit:
+mdp_open_fail:
 	kfree(inst);
 	return rc;
 }
@@ -134,8 +147,8 @@
 	fbdata.flags = 0;
 	fbdata.priv = (uint32_t)binfo->cookie;
 
-	WFD_MSG_INFO("queue buffer to mdp with offset = %u,"
-			"fd = %u, priv = %p, iova = %p\n",
+	WFD_MSG_INFO("queue buffer to mdp with offset = %u, fd = %u, "\
+			"priv = %p, iova = %p\n",
 			fbdata.offset, fbdata.memory_id,
 			(void *)fbdata.priv, (void *)fbdata.iova);
 	rc = msm_fb_writeback_queue_buffer(inst->mdp, &fbdata);
@@ -179,6 +192,84 @@
 	inst->width = prop->width;
 	return 0;
 }
+
+int mdp_mmap(struct v4l2_subdev *sd, void *arg)
+{
+	int rc = 0, domain = -1;
+	struct mem_region_map *mmap = arg;
+	struct mem_region *mregion;
+	bool use_iommu = true;
+	struct mdp_instance *inst = NULL;
+
+	if (!mmap || !mmap->mregion || !mmap->cookie) {
+		WFD_MSG_ERR("Invalid argument\n");
+		return -EINVAL;
+	}
+
+	inst = mmap->cookie;
+	mregion = mmap->mregion;
+	if (mregion->size % SZ_4K != 0) {
+		WFD_MSG_ERR("Memregion not aligned to %d\n", SZ_4K);
+		return -EINVAL;
+	}
+
+	if (inst->uses_iommu_split_domain) {
+		if (inst->secure)
+			use_iommu = false;
+		else
+			domain = DISPLAY_WRITE_DOMAIN;
+	} else {
+		domain = DISPLAY_READ_DOMAIN;
+	}
+
+	if (use_iommu) {
+		rc = ion_map_iommu(mmap->ion_client, mregion->ion_handle,
+				domain, GEN_POOL, SZ_4K, 0,
+				(unsigned long *)&mregion->paddr,
+				(unsigned long *)&mregion->size,
+				0, 0);
+	} else {
+		rc = ion_phys(mmap->ion_client,	mregion->ion_handle,
+				(unsigned long *)&mregion->paddr,
+				(size_t *)&mregion->size);
+	}
+
+	return rc;
+}
+
+int mdp_munmap(struct v4l2_subdev *sd, void *arg)
+{
+	struct mem_region_map *mmap = arg;
+	struct mem_region *mregion;
+	bool use_iommu = false;
+	int domain = -1;
+	struct mdp_instance *inst = NULL;
+
+	if (!mmap || !mmap->mregion || !mmap->cookie) {
+		WFD_MSG_ERR("Invalid argument\n");
+		return -EINVAL;
+	}
+
+	inst = mmap->cookie;
+	mregion = mmap->mregion;
+
+	if (inst->uses_iommu_split_domain) {
+		if (inst->secure)
+			use_iommu = false;
+		else
+			domain = DISPLAY_WRITE_DOMAIN;
+	} else {
+		domain = DISPLAY_READ_DOMAIN;
+	}
+
+	if (use_iommu)
+		ion_unmap_iommu(mmap->ion_client,
+				mregion->ion_handle,
+				domain, GEN_POOL);
+
+	return 0;
+}
+
 long mdp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
 {
 	int rc = 0;
@@ -208,6 +299,12 @@
 	case MDP_CLOSE:
 		rc = mdp_close(sd, arg);
 		break;
+	case MDP_MMAP:
+		rc = mdp_mmap(sd, arg);
+		break;
+	case MDP_MUNMAP:
+		rc = mdp_munmap(sd, arg);
+		break;
 	default:
 		WFD_MSG_ERR("IOCTL: %u not supported\n", cmd);
 		rc = -EINVAL;
diff --git a/drivers/media/video/msm_wfd/mdp-subdev.c b/drivers/media/video/msm_wfd/mdp-5-subdev.c
similarity index 72%
rename from drivers/media/video/msm_wfd/mdp-subdev.c
rename to drivers/media/video/msm_wfd/mdp-5-subdev.c
index 886b0ba..4f29389 100644
--- a/drivers/media/video/msm_wfd/mdp-subdev.c
+++ b/drivers/media/video/msm_wfd/mdp-5-subdev.c
@@ -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
@@ -10,53 +10,63 @@
 * GNU General Public License for more details.
 *
 */
+#include <linux/msm_mdp.h>
+#include <mach/iommu_domains.h>
+#include <media/videobuf2-core.h>
+#include "enc-subdev.h"
 #include "mdp-subdev.h"
 #include "wfd-util.h"
-#include <media/videobuf2-core.h>
-#include <linux/msm_mdp.h>
+
 
 struct mdp_instance {
 	struct fb_info *mdp;
 	u32 height;
 	u32 width;
+	bool secure;
 };
 
 int mdp_init(struct v4l2_subdev *sd, u32 val)
 {
 	return 0;
 }
+
 int mdp_open(struct v4l2_subdev *sd, void *arg)
 {
 	struct mdp_instance *inst = kzalloc(sizeof(struct mdp_instance),
 					GFP_KERNEL);
-	void **cookie = (void **)arg;
+	struct mdp_msg_ops *mops = arg;
 	int rc = 0;
 	struct fb_info *fbi = NULL;
 
 	if (!inst) {
 		WFD_MSG_ERR("Out of memory\n");
-		return -ENOMEM;
+		rc = -ENOMEM;
+		goto mdp_open_fail;
+	} else if (!mops) {
+		WFD_MSG_ERR("Invalid arguments\n");
+		rc = -EINVAL;
+		goto mdp_open_fail;
 	}
 
 	fbi = msm_fb_get_writeback_fb();
 	if (!fbi) {
 		WFD_MSG_ERR("Failed to acquire mdp instance\n");
 		rc = -ENODEV;
-		goto exit;
+		goto mdp_open_fail;
 	}
 
 	/*Tell HDMI daemon to open fb2*/
 	rc = kobject_uevent(&fbi->dev->kobj, KOBJ_ADD);
-	if (rc) {
+	if (rc)
 		WFD_MSG_ERR("Failed add to kobj");
-		goto exit;
-	}
 
 	msm_fb_writeback_init(fbi);
 	inst->mdp = fbi;
-	*cookie = inst;
+	inst->secure = mops->secure;
+
+	mops->cookie = inst;
 	return rc;
-exit:
+mdp_open_fail:
 	kfree(inst);
 	return rc;
 }
@@ -85,6 +95,7 @@
 exit:
 	return rc;
 }
+
 int mdp_stop(struct v4l2_subdev *sd, void *arg)
 {
 	struct mdp_instance *inst = arg;
@@ -134,8 +145,8 @@
 	fbdata.flags = 0;
 	fbdata.priv = (uint32_t)binfo->cookie;
 
-	WFD_MSG_INFO("queue buffer to mdp with offset = %u,"
-			"fd = %u, priv = %p, iova = %p\n",
+	WFD_MSG_DBG("queue buffer to mdp with offset = %u, fd = %u, "\
+			"priv = %p, iova = %p\n",
 			fbdata.offset, fbdata.memory_id,
 			(void *)fbdata.priv, (void *)fbdata.iova);
 	rc = msm_fb_writeback_queue_buffer(inst->mdp, &fbdata);
@@ -179,6 +190,58 @@
 	inst->width = prop->width;
 	return 0;
 }
+
+int mdp_mmap(struct v4l2_subdev *sd, void *arg)
+{
+	int rc = 0;
+	struct mem_region_map *mmap = arg;
+	struct mem_region *mregion;
+	bool domain = -1;
+	struct mdp_instance *inst = NULL;
+
+	if (!mmap || !mmap->mregion || !mmap->cookie) {
+		WFD_MSG_ERR("Invalid argument\n");
+		return -EINVAL;
+	}
+
+	inst = mmap->cookie;
+	mregion = mmap->mregion;
+	if (mregion->size % SZ_4K != 0) {
+		WFD_MSG_ERR("Memregion not aligned to %d\n", SZ_4K);
+		return -EINVAL;
+	}
+
+	domain = msm_fb_get_iommu_domain();
+	rc = ion_map_iommu(mmap->ion_client, mregion->ion_handle,
+			domain, 0, SZ_4K, 0,
+			(unsigned long *)&mregion->paddr,
+			(unsigned long *)&mregion->size,
+			0, 0);
+	return rc;
+}
+
+int mdp_munmap(struct v4l2_subdev *sd, void *arg)
+{
+	struct mem_region_map *mmap = arg;
+	struct mem_region *mregion;
+	bool domain = -1;
+	struct mdp_instance *inst = NULL;
+
+	if (!mmap || !mmap->mregion || !mmap->cookie) {
+		WFD_MSG_ERR("Invalid argument\n");
+		return -EINVAL;
+	}
+
+	inst = mmap->cookie;
+	mregion = mmap->mregion;
+
+	domain = msm_fb_get_iommu_domain();
+	ion_unmap_iommu(mmap->ion_client,
+			mregion->ion_handle,
+			domain, 0);
+	return 0;
+}
+
 long mdp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
 {
 	int rc = 0;
@@ -208,6 +271,12 @@
 	case MDP_CLOSE:
 		rc = mdp_close(sd, arg);
 		break;
+	case MDP_MMAP:
+		rc = mdp_mmap(sd, arg);
+		break;
+	case MDP_MUNMAP:
+		rc = mdp_munmap(sd, arg);
+		break;
 	default:
 		WFD_MSG_ERR("IOCTL: %u not supported\n", cmd);
 		rc = -EINVAL;
diff --git a/drivers/media/video/msm_wfd/mdp-dummy-subdev.c b/drivers/media/video/msm_wfd/mdp-dummy-subdev.c
new file mode 100644
index 0000000..b2db208
--- /dev/null
+++ b/drivers/media/video/msm_wfd/mdp-dummy-subdev.c
@@ -0,0 +1,187 @@
+/* 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/list.h>
+#include <linux/msm_mdp.h>
+#include <media/videobuf2-core.h>
+
+#include "enc-subdev.h"
+#include "mdp-subdev.h"
+#include "wfd-util.h"
+
+struct mdp_buf_queue {
+	struct mdp_buf_info mdp_buf_info;
+	struct list_head node;
+};
+
+struct mdp_instance {
+	struct mdp_buf_queue mdp_bufs;
+	struct mutex mutex;
+};
+
+int mdp_init(struct v4l2_subdev *sd, u32 val)
+{
+	return 0;
+}
+int mdp_open(struct v4l2_subdev *sd, void *arg)
+{
+	struct mdp_instance *inst = kzalloc(sizeof(struct mdp_instance),
+					GFP_KERNEL);
+	void **cookie = (void **)arg;
+	int rc = 0;
+
+	if (!inst) {
+		WFD_MSG_ERR("Out of memory\n");
+		return -ENOMEM;
+	}
+
+	INIT_LIST_HEAD(&inst->mdp_bufs.node);
+	mutex_init(&inst->mutex);
+	*cookie = inst;
+	return rc;
+}
+
+int mdp_start(struct v4l2_subdev *sd, void *arg)
+{
+	return 0;
+}
+int mdp_stop(struct v4l2_subdev *sd, void *arg)
+{
+	return 0;
+}
+int mdp_close(struct v4l2_subdev *sd, void *arg)
+{
+	return 0;
+}
+int mdp_q_buffer(struct v4l2_subdev *sd, void *arg)
+{
+	static int foo;
+	int rc = 0;
+	struct mdp_buf_info *binfo = arg;
+	struct mdp_instance *inst = NULL;
+
+	if (!binfo || !binfo->inst || !binfo->cookie) {
+		WFD_MSG_ERR("Invalid argument\n");
+		return -EINVAL;
+	}
+
+
+	inst = binfo->inst;
+	if (binfo->kvaddr) {
+		struct mdp_buf_queue *new_entry = kzalloc(sizeof(*new_entry),
+				GFP_KERNEL);
+		memset((void *)binfo->kvaddr, foo++, 1024);
+		new_entry->mdp_buf_info = *binfo;
+		mutex_lock(&inst->mutex);
+		list_add_tail(&new_entry->node, &inst->mdp_bufs.node);
+		mutex_unlock(&inst->mutex);
+		WFD_MSG_DBG("Queue %p with cookie %p\n",
+			(void *)binfo->paddr, (void *)binfo->cookie);
+	} else {
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
+int mdp_dq_buffer(struct v4l2_subdev *sd, void *arg)
+{
+	struct mdp_buf_info *binfo = arg;
+	struct mdp_buf_queue *head = NULL;
+	struct mdp_instance *inst = NULL;
+
+	inst = binfo->inst;
+
+	while (head == NULL) {
+		mutex_lock(&inst->mutex);
+		if (!list_empty(&inst->mdp_bufs.node))
+			head = list_first_entry(&inst->mdp_bufs.node,
+					struct mdp_buf_queue, node);
+		mutex_unlock(&inst->mutex);
+	}
+
+	if (head == NULL)
+		return -ENOBUFS;
+
+	mutex_lock(&inst->mutex);
+	list_del(&head->node);
+	mutex_unlock(&inst->mutex);
+
+	*binfo = head->mdp_buf_info;
+	WFD_MSG_DBG("Dequeue %p with cookie %p\n",
+		(void *)binfo->paddr, (void *)binfo->cookie);
+	return 0;
+
+}
+int mdp_set_prop(struct v4l2_subdev *sd, void *arg)
+{
+	return 0;
+}
+
+int mdp_mmap(struct v4l2_subdev *sd, void *arg)
+{
+	int rc = 0;
+	struct mem_region_map *mmap = arg;
+	struct mem_region *mregion;
+
+	mregion = mmap->mregion;
+	mregion->paddr = mregion->kvaddr;
+	return rc;
+}
+
+int mdp_munmap(struct v4l2_subdev *sd, void *arg)
+{
+	/* Whatever */
+	return 0;
+}
+
+long mdp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+	int rc = 0;
+	if (!sd) {
+		WFD_MSG_ERR("Invalid arguments\n");
+		return -EINVAL;
+	}
+	switch (cmd) {
+	case MDP_Q_BUFFER:
+		rc = mdp_q_buffer(sd, arg);
+		break;
+	case MDP_DQ_BUFFER:
+		rc = mdp_dq_buffer(sd, arg);
+		break;
+	case MDP_OPEN:
+		rc = mdp_open(sd, arg);
+		break;
+	case MDP_START:
+		rc = mdp_start(sd, arg);
+		break;
+	case MDP_STOP:
+		rc = mdp_stop(sd, arg);
+		break;
+	case MDP_SET_PROP:
+		rc = mdp_set_prop(sd, arg);
+		break;
+	case MDP_CLOSE:
+		rc = mdp_close(sd, arg);
+		break;
+	case MDP_MMAP:
+		rc = mdp_mmap(sd, arg);
+		break;
+	case MDP_MUNMAP:
+		rc = mdp_munmap(sd, arg);
+		break;
+	default:
+		WFD_MSG_ERR("IOCTL: %u not supported\n", cmd);
+		rc = -EINVAL;
+		break;
+	}
+	return rc;
+}
diff --git a/drivers/media/video/msm_wfd/mdp-subdev.h b/drivers/media/video/msm_wfd/mdp-subdev.h
index 081fead..5e81e3c 100644
--- a/drivers/media/video/msm_wfd/mdp-subdev.h
+++ b/drivers/media/video/msm_wfd/mdp-subdev.h
@@ -34,6 +34,12 @@
 	u32 width;
 };
 
+struct mdp_msg_ops {
+	void *cookie;
+	bool secure;
+	bool iommu_split_domain;
+};
+
 static inline bool mdp_buf_info_equals(struct mdp_buf_info *a,
 		struct mdp_buf_info *b)
 {
@@ -51,6 +57,10 @@
 #define MDP_CLOSE  _IOR(MDP_MAGIC_IOCTL, 5, void *)
 #define MDP_START  _IOR(MDP_MAGIC_IOCTL, 6, void *)
 #define MDP_STOP  _IOR(MDP_MAGIC_IOCTL, 7, void *)
+#define MDP_MMAP  _IOR(MDP_MAGIC_IOCTL, 8, struct mem_region_map *)
+#define MDP_MUNMAP  _IOR(MDP_MAGIC_IOCTL, 9, struct mem_region_map *)
+
+
 extern int mdp_init(struct v4l2_subdev *sd, u32 val);
 extern long mdp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg);
 
diff --git a/drivers/media/video/msm_wfd/wfd-ioctl.c b/drivers/media/video/msm_wfd/wfd-ioctl.c
index 8981c1a..23af7e9 100644
--- a/drivers/media/video/msm_wfd/wfd-ioctl.c
+++ b/drivers/media/video/msm_wfd/wfd-ioctl.c
@@ -10,7 +10,6 @@
  * GNU General Public License for more details.
  *
  */
-
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/list.h>
@@ -40,8 +39,8 @@
 #define WFD_NUM_DEVICES 2
 #define WFD_DEVICE_NUMBER_BASE 38
 #define WFD_DEVICE_SECURE (WFD_DEVICE_NUMBER_BASE + 1)
-#define DEFAULT_WFD_WIDTH 640
-#define DEFAULT_WFD_HEIGHT 480
+#define DEFAULT_WFD_WIDTH 1280
+#define DEFAULT_WFD_HEIGHT 720
 #define VENC_INPUT_BUFFERS 4
 
 struct wfd_device {
@@ -152,11 +151,10 @@
 static int wfd_allocate_ion_buffer(struct ion_client *client,
 		bool secure, struct mem_region *mregion)
 {
-	struct ion_handle *handle;
-	void *kvaddr = NULL, *phys_addr = NULL;
-	unsigned long size;
+	struct ion_handle *handle = NULL;
+	void *kvaddr = NULL;
 	unsigned int alloc_regions = 0;
-	int rc;
+	int rc = 0;
 
 	alloc_regions = ION_HEAP(ION_CP_MM_HEAP_ID);
 	alloc_regions |= secure ? ION_SECURE :
@@ -178,32 +176,7 @@
 		goto alloc_fail;
 	}
 
-	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 || !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");
-		rc = -ENOMEM;
-		goto alloc_fail;
-	}
-
 	mregion->kvaddr = kvaddr;
-	mregion->paddr = phys_addr;
 	mregion->ion_handle = handle;
 
 	return rc;
@@ -273,6 +246,7 @@
 	spin_unlock_irqrestore(&inst->inst_lock, flags);
 
 	for (i = 0; i < VENC_INPUT_BUFFERS; ++i) {
+		struct mem_region_map mmap_context = {0};
 		mpair = kzalloc(sizeof(*mpair), GFP_KERNEL);
 		enc_mregion = kzalloc(sizeof(*enc_mregion), GFP_KERNEL);
 		mdp_mregion = kzalloc(sizeof(*enc_mregion), GFP_KERNEL);
@@ -281,12 +255,20 @@
 		rc = wfd_allocate_ion_buffer(wfd_dev->ion_client,
 				wfd_dev->secure_device, enc_mregion);
 		if (rc) {
-			WFD_MSG_ERR("Failed to allocate input memory."
-				" This error causes memory leak!!!\n");
+			WFD_MSG_ERR("Failed to allocate input memory\n");
 			goto alloc_fail;
 		}
 
-		WFD_MSG_DBG("NOTE: enc paddr = %p, kvaddr = %p\n",
+		mmap_context.mregion = enc_mregion;
+		mmap_context.ion_client = wfd_dev->ion_client;
+		rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
+				ENC_MMAP, &mmap_context);
+		if (rc || !enc_mregion->paddr) {
+			WFD_MSG_ERR("Failed to map input memory\n");
+			goto alloc_fail;
+		}
+
+		WFD_MSG_ERR("NOTE: enc paddr = %p, kvaddr = %p\n",
 				enc_mregion->paddr,
 				enc_mregion->kvaddr);
 
@@ -301,27 +283,12 @@
 		mdp_mregion->cookie = 0;
 		mdp_mregion->ion_handle = enc_mregion->ion_handle;
 
-		if (wfd_dev->mdp_iommu_split_domain) {
-			if (wfd_dev->secure_device) {
-				rc = ion_phys(wfd_dev->ion_client,
-					mdp_mregion->ion_handle,
-					(unsigned long *)&mdp_mregion->paddr,
-					(size_t *)&mdp_mregion->size);
-			} else {
-				rc = ion_map_iommu(wfd_dev->ion_client,
-					mdp_mregion->ion_handle,
-					DISPLAY_WRITE_DOMAIN, GEN_POOL, SZ_4K,
-					0, (unsigned long *)&mdp_mregion->paddr,
-					(unsigned long *)&mdp_mregion->size,
-					0, 0);
-			}
-		} else {
-			rc = ion_map_iommu(wfd_dev->ion_client,
-				mdp_mregion->ion_handle,
-				DISPLAY_READ_DOMAIN, GEN_POOL, SZ_4K,
-				0, (unsigned long *)&mdp_mregion->paddr,
-				(unsigned long *)&mdp_mregion->size, 0, 0);
-		}
+		memset(&mmap_context, 0, sizeof(mmap_context));
+		mmap_context.mregion = mdp_mregion;
+		mmap_context.ion_client = wfd_dev->ion_client;
+		mmap_context.cookie = inst->mdp_inst;
+		rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl,
+				MDP_MMAP, (void *)&mmap_context);
 
 		if (rc || !mdp_mregion->paddr) {
 			WFD_MSG_ERR(
@@ -401,24 +368,24 @@
 						"from encoder\n");
 
 			if (mpair->mdp->paddr) {
-				if (wfd_dev->mdp_iommu_split_domain) {
-					if (!wfd_dev->secure_device)
-						ion_unmap_iommu(wfd_dev->
-							ion_client,
-							mpair->mdp->ion_handle,
-							DISPLAY_WRITE_DOMAIN,
-							GEN_POOL);
-				} else {
-					ion_unmap_iommu(wfd_dev->ion_client,
-						mpair->mdp->ion_handle,
-						DISPLAY_READ_DOMAIN, GEN_POOL);
-				}
+				struct mem_region_map temp = {0};
+
+				temp.ion_client = wfd_dev->ion_client;
+				temp.mregion = mpair->mdp;
+				temp.cookie = inst->mdp_inst;
+
+				v4l2_subdev_call(&wfd_dev->mdp_sdev, core,
+						ioctl, MDP_MUNMAP,
+						(void *)&temp);
 			}
 
-			if (mpair->enc->paddr && !wfd_dev->secure_device)
-				ion_unmap_iommu(wfd_dev->ion_client,
-						mpair->enc->ion_handle,
-						VIDEO_DOMAIN, VIDEO_MAIN_POOL);
+			if (mpair->enc->paddr) {
+				struct mem_region_map temp = {0};
+				temp.ion_client = wfd_dev->ion_client;
+				temp.mregion = mpair->enc;
+				v4l2_subdev_call(&wfd_dev->enc_sdev,
+					core, ioctl, ENC_MUNMAP, &temp);
+			}
 
 			wfd_free_ion_buffer(wfd_dev->ion_client, mpair->enc);
 			list_del(&mpair->list);
@@ -884,7 +851,7 @@
 		list_add_tail(&minfo_entry->list, &inst->minfo_list);
 		spin_unlock_irqrestore(&inst->inst_lock, flags);
 	} else
-		WFD_MSG_INFO("Buffer already registered\n");
+		WFD_MSG_DBG("Buffer already registered\n");
 
 	return 0;
 }
@@ -970,7 +937,7 @@
 	struct wfd_inst *inst = filp->private_data;
 	int rc;
 
-	WFD_MSG_INFO("Waiting to dequeue buffer\n");
+	WFD_MSG_DBG("Waiting to dequeue buffer\n");
 	rc = vb2_dqbuf(&inst->vid_bufq, b, 0);
 
 	if (rc)
@@ -1306,6 +1273,7 @@
 	struct wfd_inst *inst = NULL;
 	struct wfd_device *wfd_dev = NULL;
 	struct venc_msg_ops enc_mops;
+	struct mdp_msg_ops mdp_mops;
 	struct vsg_msg_ops vsg_mops;
 
 	WFD_MSG_DBG("wfd_open: E\n");
@@ -1339,12 +1307,15 @@
 
 	wfd_stats_init(&inst->stats, MINOR(filp->f_dentry->d_inode->i_rdev));
 
+	mdp_mops.secure = wfd_dev->secure_device;
+	mdp_mops.iommu_split_domain = wfd_dev->mdp_iommu_split_domain;
 	rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl, MDP_OPEN,
-				(void *)&inst->mdp_inst);
+				(void *)&mdp_mops);
 	if (rc) {
 		WFD_MSG_ERR("Failed to open mdp subdevice: %d\n", rc);
 		goto err_mdp_open;
 	}
+	inst->mdp_inst = mdp_mops.cookie;
 
 	rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, load_fw);
 	if (rc) {
diff --git a/drivers/media/video/msm_wfd/wfd-util.h b/drivers/media/video/msm_wfd/wfd-util.h
index b6bb245..2fe7360 100644
--- a/drivers/media/video/msm_wfd/wfd-util.h
+++ b/drivers/media/video/msm_wfd/wfd-util.h
@@ -21,16 +21,11 @@
 /*#define DEBUG_WFD*/
 
 #define WFD_TAG "wfd: "
-#ifdef DEBUG_WFD
-	#define WFD_MSG_INFO(fmt...) pr_info(WFD_TAG fmt)
-	#define WFD_MSG_WARN(fmt...) pr_warning(WFD_TAG fmt)
-#else
-	#define WFD_MSG_INFO(fmt...)
-	#define WFD_MSG_WARN(fmt...)
-#endif
-	#define WFD_MSG_ERR(fmt...) pr_err(KERN_ERR WFD_TAG fmt)
-	#define WFD_MSG_CRIT(fmt...) pr_crit(KERN_CRIT WFD_TAG fmt)
-	#define WFD_MSG_DBG(fmt...) pr_debug(WFD_TAG fmt)
+#define WFD_MSG_INFO(fmt...) pr_info(WFD_TAG fmt)
+#define WFD_MSG_WARN(fmt...) pr_warning(WFD_TAG fmt)
+#define WFD_MSG_ERR(fmt...) pr_err(KERN_ERR WFD_TAG fmt)
+#define WFD_MSG_CRIT(fmt...) pr_crit(KERN_CRIT WFD_TAG fmt)
+#define WFD_MSG_DBG(fmt...) pr_debug(WFD_TAG fmt)
 
 
 struct wfd_stats_encode_sample {
diff --git a/drivers/media/video/vcap_v4l2.c b/drivers/media/video/vcap_v4l2.c
index 28abb36..e6cbae3 100644
--- a/drivers/media/video/vcap_v4l2.c
+++ b/drivers/media/video/vcap_v4l2.c
@@ -257,6 +257,8 @@
 	rc = config_gpios(1, dev->vcap_pdata);
 	if (rc < 0)
 		goto gpio_failed;
+	writel_relaxed(0x00030003, VCAP_OFFSET(0xD78));
+	writel_relaxed(0x00030003, VCAP_OFFSET(0xD7C));
 	return 0;
 
 gpio_failed:
@@ -340,6 +342,8 @@
 		return -EINVAL;
 	}
 
+	vb->v4l2_buf.timestamp = b->timestamp;
+	vb->v4l2_buf.field = b->field;
 	list_add_tail(&vb->queued_entry, &q->queued_list);
 	vb->state = VB2_BUF_STATE_QUEUED;
 
diff --git a/drivers/media/video/vcap_vc.c b/drivers/media/video/vcap_vc.c
index 78e108f..572c272 100644
--- a/drivers/media/video/vcap_vc.c
+++ b/drivers/media/video/vcap_vc.c
@@ -122,6 +122,17 @@
 	return 0;
 }
 
+static struct timeval interpolate_ts(struct timeval tv, uint32_t delta)
+{
+	if (tv.tv_usec < delta) {
+		tv.tv_sec--;
+		tv.tv_usec += VCAP_USEC - delta;
+	} else {
+		tv.tv_usec -= delta;
+	}
+	return tv;
+}
+
 irqreturn_t vc_handler(struct vcap_dev *dev)
 {
 	uint32_t irq, timestamp;
@@ -194,6 +205,10 @@
 			done_count++;
 	}
 
+	/* Assign field value in case somehow got out of sync */
+	if (c_data->vc_format.mode == HAL_VCAP_MODE_INT && done_count == 1)
+		c_data->vc_action.top_field = !(irq & 0x1);
+
 	/* Double check expected buffers are done */
 	buf_num = c_data->vc_action.buf_num;
 	tot = c_data->vc_action.tot_buf;
@@ -212,6 +227,20 @@
 
 	/* If here we know which buffers are done */
 	timestamp = readl_relaxed(VCAP_VC_TIMESTAMP);
+	if (timestamp < c_data->vc_action.last_ts) {
+		c_data->vc_action.vc_ts.tv_usec +=
+			(0xFFFFFFFF - c_data->vc_action.last_ts) +
+			timestamp + 1;
+	} else {
+		c_data->vc_action.vc_ts.tv_usec +=
+			timestamp - c_data->vc_action.last_ts;
+	}
+
+	c_data->vc_action.vc_ts.tv_sec +=
+		c_data->vc_action.vc_ts.tv_usec / VCAP_USEC;
+	c_data->vc_action.vc_ts.tv_usec =
+		c_data->vc_action.vc_ts.tv_usec % VCAP_USEC;
+	c_data->vc_action.last_ts = timestamp;
 
 	c_data->vc_action.buf_num = (buf_num + done_count) % tot;
 	for (i = 0; i < done_count; i++) {
@@ -223,6 +252,8 @@
 			v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
 				VCAP_VC_BUF_OVERWRITE_EVENT;
 			v4l2_event_queue(dev->vfd, &v4l2_evt);
+			c_data->vc_action.top_field =
+				!c_data->vc_action.top_field;
 			continue;
 		}
 		buf = list_entry(c_data->vc_action.active.next,
@@ -232,9 +263,18 @@
 		/* Config vc with this new buffer */
 		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 -
+		vb->v4l2_buf.timestamp = interpolate_ts(
+			c_data->vc_action.vc_ts,
 			1000000 / c_data->vc_format.frame_rate *
-			(done_count - 1 - i);
+			(done_count - 1 - i));
+		if (c_data->vc_format.mode == HAL_VCAP_MODE_INT) {
+			if (c_data->vc_action.top_field)
+				vb->v4l2_buf.field = V4L2_FIELD_TOP;
+			else
+				vb->v4l2_buf.field = V4L2_FIELD_BOTTOM;
+			c_data->vc_action.top_field =
+				!c_data->vc_action.top_field;
+		}
 		vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
 		work_todo = true;
 		c_data->vc_action.buf[idx] = buf;
@@ -298,6 +338,12 @@
 			VCAP_VC_C_ADDR_1 + i * 8);
 	}
 
+	c_data->vc_action.last_ts = readl_relaxed(VCAP_VC_TIMESTAMP);
+	c_data->vc_action.vc_ts.tv_sec =
+		c_data->vc_action.last_ts / VCAP_USEC;
+	c_data->vc_action.vc_ts.tv_usec =
+		c_data->vc_action.last_ts % VCAP_USEC;
+
 	rc = 0;
 	for (i = 0; i < c_data->vc_action.tot_buf; i++)
 		rc = rc << 1 | 0x2;
diff --git a/drivers/media/video/vcap_vp.c b/drivers/media/video/vcap_vp.c
index 139de28..4c3ff16 100644
--- a/drivers/media/video/vcap_vp.c
+++ b/drivers/media/video/vcap_vp.c
@@ -200,9 +200,7 @@
 	unsigned long flags = 0;
 	uint32_t irq;
 	int rc;
-#ifndef TOP_FIELD_FIX
-	bool top_field;
-#endif
+	bool top_field = 0;
 
 	if (vp_work && vp_work->cd && vp_work->cd->dev)
 		dev = vp_work->cd->dev;
@@ -233,14 +231,15 @@
 			queue_work(dev->vcap_wq, &dev->vp_to_vc_work.work);
 	}
 
+	if (vp_act->bufT0 != NULL && vp_act->vp_state == VP_NORMAL) {
+		vp_act->bufOut->vb.v4l2_buf.timestamp =
+			vp_act->bufT0->vb.v4l2_buf.timestamp;
+	}
 	vb2_buffer_done(&vp_act->bufOut->vb, VB2_BUF_STATE_DONE);
 
 	/* Cycle to next state */
 	if (vp_act->vp_state != VP_NORMAL)
 		vp_act->vp_state++;
-#ifdef TOP_FIELD_FIX
-	vp_act->top_field = !vp_act->top_field;
-#endif
 
 	/* Cycle Buffers*/
 	if (dev->nr_param.mode) {
@@ -273,18 +272,11 @@
 	}
 
 	/* Config VP */
-#ifndef TOP_FIELD_FIX
 	if (vp_act->bufT2->vb.v4l2_buf.field == V4L2_FIELD_TOP)
 		top_field = 1;
-#endif
 
-#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);
-#else
 	writel_iowmb(0x00000000 | top_field, VCAP_VP_CTRL);
 	writel_iowmb(0x00010000 | top_field, VCAP_VP_CTRL);
-#endif
 	enable_irq(dev->vpirq->start);
 	writel_iowmb(irq, VCAP_VP_INT_CLEAR);
 }
@@ -742,9 +734,7 @@
 	unsigned long flags = 0;
 	unsigned int chroma_fmt = 0;
 	int size;
-#ifndef TOP_FIELD_FIX
-	bool top_field;
-#endif
+	bool top_field = 0;
 
 	if (!c_data->streaming)
 		return -ENOEXEC;
@@ -817,21 +807,12 @@
 			chroma_fmt << 11 | 0x1 << 4, VCAP_VP_OUT_CONFIG);
 
 	/* Enable Interrupt */
-#ifdef TOP_FIELD_FIX
-	vp_act->top_field = 1;
-#else
 	if (vp_act->bufT2->vb.v4l2_buf.field == V4L2_FIELD_TOP)
 		top_field = 1;
-#endif
 	vp_act->vp_state = VP_FRAME2;
 	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);
-#else
 	writel_iowmb(0x00000000 | top_field, VCAP_VP_CTRL);
 	writel_iowmb(0x00010000 | top_field, VCAP_VP_CTRL);
-#endif
 	atomic_set(&c_data->dev->vp_enabled, 1);
 	enable_irq(dev->vpirq->start);
 	return 0;
@@ -842,9 +823,7 @@
 	struct vcap_dev *dev;
 	struct vp_action *vp_act;
 	int rc;
-#ifndef TOP_FIELD_FIX
-	bool top_field;
-#endif
+	bool top_field = 0;
 
 	dprintk(2, "Start Continue\n");
 	dev = c_data->dev;
@@ -865,20 +844,13 @@
 	if (rc < 0)
 		return rc;
 
-#ifndef TOP_FIELD_FIX
 	if (vp_act->bufT2->vb.v4l2_buf.field == V4L2_FIELD_TOP)
 		top_field = 1;
-#endif
 
 	/* Config VP & Enable Interrupt */
 	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);
-#else
 	writel_iowmb(0x00000000 | top_field, VCAP_VP_CTRL);
 	writel_iowmb(0x00010000 | top_field, VCAP_VP_CTRL);
-#endif
 
 	atomic_set(&c_data->dev->vp_enabled, 1);
 	enable_irq(dev->vpirq->start);
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index c785a7e..8b9d08b 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -1793,13 +1793,6 @@
 		type = rq_data_dir(req) == READ ? MMC_BLK_READ : MMC_BLK_WRITE;
 		mmc_queue_bounce_post(mq_rq);
 
-		/*
-		 * Check BKOPS urgency from each R1 response
-		 */
-		if (mmc_card_mmc(card) &&
-			(brq->cmd.resp[0] & R1_EXCEPTION_EVENT))
-			mmc_card_set_check_bkops(card);
-
 		switch (status) {
 		case MMC_BLK_SUCCESS:
 		case MMC_BLK_PARTIAL:
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index ebcf7ed..e1e4408 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -74,9 +74,6 @@
 		spin_unlock_irq(q->queue_lock);
 
 		if (req || mq->mqrq_prev->req) {
-			if (mmc_card_doing_bkops(mq->card))
-				mmc_interrupt_bkops(mq->card);
-
 			set_current_state(TASK_RUNNING);
 			mq->issue_fn(mq, req);
 		} else {
@@ -84,8 +81,6 @@
 				set_current_state(TASK_RUNNING);
 				break;
 			}
-
-			mmc_start_bkops(mq->card);
 			up(&mq->thread_sem);
 			schedule();
 			down(&mq->thread_sem);
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index e4d0fc1..478cfac 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -43,12 +43,6 @@
 #include "sd_ops.h"
 #include "sdio_ops.h"
 
-/*
- * The Background operations can take a long time, depends on the house keeping
- * operations the card has to perform
- */
-#define MMC_BKOPS_MAX_TIMEOUT    (4 * 60 * 1000) /* max time to wait in ms */
-
 static struct workqueue_struct *workqueue;
 
 /*
@@ -278,74 +272,6 @@
 	host->ops->request(host, mrq);
 }
 
-/**
- *	mmc_start_bkops - start BKOPS for supported cards
- *	@card: MMC card to start BKOPS
- *
- *	Start background operations whenever requested.
- *	when the urgent BKOPS bit is set in a R1 command response
- *	then background operations should be started immediately.
-*/
-void mmc_start_bkops(struct mmc_card *card)
-{
-	int err;
-	unsigned long flags;
-	int timeout;
-
-	BUG_ON(!card);
-	if (!card->ext_csd.bkops_en || !(card->host->caps2 & MMC_CAP2_BKOPS))
-		return;
-
-	if (mmc_card_check_bkops(card)) {
-		spin_lock_irqsave(&card->host->lock, flags);
-		mmc_card_clr_check_bkops(card);
-		spin_unlock_irqrestore(&card->host->lock, flags);
-		if (mmc_is_exception_event(card, EXT_CSD_URGENT_BKOPS))
-			if (card->ext_csd.raw_bkops_status)
-				mmc_card_set_need_bkops(card);
-	}
-
-	/*
-	 * If card is already doing bkops or need for
-	 * bkops flag is not set, then do nothing just
-	 * return
-	 */
-	if (mmc_card_doing_bkops(card) || !mmc_card_need_bkops(card))
-		return;
-
-	mmc_claim_host(card->host);
-
-	timeout = (card->ext_csd.raw_bkops_status >= EXT_CSD_BKOPS_LEVEL_2) ?
-		MMC_BKOPS_MAX_TIMEOUT : 0;
-
-	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-			EXT_CSD_BKOPS_START, 1, timeout);
-	if (err) {
-		pr_warning("%s: error %d starting bkops\n",
-			   mmc_hostname(card->host), err);
-		mmc_card_clr_need_bkops(card);
-		goto out;
-	}
-
-	spin_lock_irqsave(&card->host->lock, flags);
-	mmc_card_clr_need_bkops(card);
-
-	/*
-	 * For urgent bkops status (LEVEL_2 and more)
-	 * bkops executed synchronously, otherwise
-	 * the operation is in progress
-	 */
-	if (card->ext_csd.raw_bkops_status >= EXT_CSD_BKOPS_LEVEL_2)
-		mmc_card_set_check_bkops(card);
-	else
-		mmc_card_set_doing_bkops(card);
-
-	spin_unlock_irqrestore(&card->host->lock, flags);
-out:
-	mmc_release_host(card->host);
-}
-EXPORT_SYMBOL(mmc_start_bkops);
-
 static void mmc_wait_done(struct mmc_request *mrq)
 {
 	complete(&mrq->completion);
@@ -581,69 +507,6 @@
 EXPORT_SYMBOL(mmc_wait_for_cmd);
 
 /**
- *	mmc_interrupt_bkops - interrupt ongoing BKOPS
- *	@card: MMC card to check BKOPS
- *
- *	Send HPI command to interrupt ongoing background operations,
- *	to allow rapid servicing of foreground operations,e.g. read/
- *	writes. Wait until the card comes out of the programming state
- *	to avoid errors in servicing read/write requests.
- */
-int mmc_interrupt_bkops(struct mmc_card *card)
-{
-	int err = 0;
-	unsigned long flags;
-
-	BUG_ON(!card);
-
-	err = mmc_interrupt_hpi(card);
-
-	spin_lock_irqsave(&card->host->lock, flags);
-	mmc_card_clr_doing_bkops(card);
-	spin_unlock_irqrestore(&card->host->lock, flags);
-
-	return err;
-}
-EXPORT_SYMBOL(mmc_interrupt_bkops);
-
-int mmc_read_bkops_status(struct mmc_card *card)
-{
-	int err;
-	u8 ext_csd[512];
-
-	mmc_claim_host(card->host);
-	err = mmc_send_ext_csd(card, ext_csd);
-	mmc_release_host(card->host);
-	if (err)
-		return err;
-
-	card->ext_csd.raw_bkops_status = ext_csd[EXT_CSD_BKOPS_STATUS];
-	card->ext_csd.raw_exception_status = ext_csd[EXT_CSD_EXP_EVENTS_STATUS];
-
-	return 0;
-}
-EXPORT_SYMBOL(mmc_read_bkops_status);
-
-int mmc_is_exception_event(struct mmc_card *card, unsigned int value)
-{
-	int err;
-
-	err = mmc_read_bkops_status(card);
-	if (err) {
-		pr_err("%s: Didn't read bkops status : %d\n",
-		       mmc_hostname(card->host), err);
-		return 0;
-	}
-
-	/* In eMMC 4.41, R1_EXCEPTION_EVENT is URGENT_BKOPS */
-	if (card->ext_csd.rev == 5)
-		return 1;
-
-	return (card->ext_csd.raw_exception_status & value) ? 1 : 0;
-}
-EXPORT_SYMBOL(mmc_is_exception_event);
-
-/**
  *	mmc_set_data_timeout - set the timeout for a data command
  *	@data: data phase for command
  *	@card: the MMC card associated with the data transfer
@@ -1297,7 +1160,7 @@
 		bit = fls(host->ocr_avail) - 1;
 
 	host->ios.vdd = bit;
-	if (mmc_host_is_spi(host)) 
+	if (mmc_host_is_spi(host))
 		host->ios.chip_select = MMC_CS_HIGH;
 	else {
 		host->ios.chip_select = MMC_CS_DONTCARE;
@@ -1334,7 +1197,7 @@
 
 	host->ios.clock = 0;
 	host->ios.vdd = 0;
-	
+
 
 	/*
 	 * Reset ocr mask to be the highest possible voltage supported for
@@ -2507,12 +2370,8 @@
 				err = -EBUSY;
 
 		if (!err) {
-			if (host->bus_ops->suspend) {
-				if (mmc_card_doing_bkops(host->card))
-					mmc_interrupt_bkops(host->card);
-
+			if (host->bus_ops->suspend)
 				err = host->bus_ops->suspend(host);
-			}
 			if (!(host->card && mmc_card_sdio(host->card)))
 				mmc_release_host(host);
 
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index b1b8892..f87b8cc 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -463,24 +463,6 @@
 	}
 
 	if (card->ext_csd.rev >= 5) {
-		/* check whether the eMMC card support BKOPS */
-		if (ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1) {
-			card->ext_csd.bkops = 1;
-			card->ext_csd.bkops_en = ext_csd[EXT_CSD_BKOPS_EN];
-			card->ext_csd.raw_bkops_status =
-				ext_csd[EXT_CSD_BKOPS_STATUS];
-			if (!card->ext_csd.bkops_en &&
-				card->host->caps2 & MMC_CAP2_INIT_BKOPS) {
-				err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-					EXT_CSD_BKOPS_EN, 1, 0);
-				if (err)
-					pr_warning("%s: Enabling BKOPS failed\n",
-						mmc_hostname(card->host));
-				else
-					card->ext_csd.bkops_en = 1;
-			}
-		}
-
 		/* check whether the eMMC card supports HPI */
 		if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x1) {
 			card->ext_csd.hpi = 1;
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index d82c353..e18d922 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -393,22 +393,13 @@
 		  (index << 16) |
 		  (value << 8) |
 		  set;
-		cmd.flags = MMC_CMD_AC;
-	if (index == EXT_CSD_BKOPS_START &&
-	    card->ext_csd.raw_bkops_status < EXT_CSD_BKOPS_LEVEL_2)
-		cmd.flags |= MMC_RSP_SPI_R1 | MMC_RSP_R1;
-	else
-		cmd.flags |= MMC_RSP_SPI_R1B | MMC_RSP_R1B;
+	cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
 	cmd.cmd_timeout_ms = timeout_ms;
 
 	err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
 	if (err)
 		return err;
 
-	/* No need to check card status in case of BKOPS switch*/
-	if (index == EXT_CSD_BKOPS_START)
-		return 0;
-
 	/* 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 52fd5e8..c4b41e1 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -1336,34 +1336,41 @@
 msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
 		 unsigned int status)
 {
-	if (status & MCI_DATACRCFAIL) {
-		if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
-			|| data->mrq->cmd->opcode == MMC_BUS_TEST_R
-			|| data->mrq->cmd->opcode ==
-				MMC_SEND_TUNING_BLOCK_HS200)) {
-			pr_err("%s: Data CRC error\n",
-			       mmc_hostname(host->mmc));
-			pr_err("%s: opcode 0x%.8x\n", __func__,
-			       data->mrq->cmd->opcode);
-			pr_err("%s: blksz %d, blocks %d\n", __func__,
-			       data->blksz, data->blocks);
-			data->error = -EILSEQ;
+	if ((status & MCI_DATACRCFAIL) || (status & MCI_DATATIMEOUT)) {
+		u32 opcode = data->mrq->cmd->opcode;
+
+		if (!((!host->tuning_in_progress && opcode == MMC_BUS_TEST_W)
+		    || (opcode == MMC_BUS_TEST_R) ||
+		    (host->tuning_in_progress &&
+		    (opcode == MMC_SEND_TUNING_BLOCK_HS200 ||
+		     opcode == MMC_SEND_TUNING_BLOCK)))) {
+			if (status & MCI_DATACRCFAIL) {
+				pr_err("%s: Data CRC error\n",
+				       mmc_hostname(host->mmc));
+				pr_err("%s: opcode 0x%.8x\n", __func__, opcode);
+				pr_err("%s: blksz %d, blocks %d\n", __func__,
+				       data->blksz, data->blocks);
+			} else {
+				pr_err("%s: CMD%d: Data timeout. DAT0 => %d\n",
+					 mmc_hostname(host->mmc), opcode,
+					 (readl_relaxed(host->base
+					 + MCI_TEST_INPUT) & 0x2) ? 1 : 0);
+				msmsdcc_dump_sdcc_state(host);
+			}
 		}
-	} else if (status & MCI_DATATIMEOUT) {
-		/* CRC is optional for the bus test commands, not all
+
+		/*
+		 * CRC is optional for the bus test commands, not all
 		 * cards respond back with CRC. However controller
 		 * waits for the CRC and times out. Hence ignore the
 		 * data timeouts during the Bustest.
 		 */
-		if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
-			|| data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
-			pr_err("%s: CMD%d: Data timeout. DAT0 => %d\n",
-				 mmc_hostname(host->mmc),
-				 data->mrq->cmd->opcode,
-				 (readl_relaxed(host->base
-				 + MCI_TEST_INPUT) & 0x2) ? 1 : 0);
-			data->error = -ETIMEDOUT;
-			msmsdcc_dump_sdcc_state(host);
+		if (!((!host->tuning_in_progress && opcode == MMC_BUS_TEST_W)
+		    || (opcode == MMC_BUS_TEST_R))) {
+			if (status & MCI_DATACRCFAIL)
+				data->error = -EILSEQ;
+			else
+				data->error = -ETIMEDOUT;
 		}
 	} else if (status & MCI_RXOVERRUN) {
 		pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
@@ -5798,13 +5805,12 @@
 	mmc->caps2 |= MMC_CAP2_PACKED_WR_CONTROL;
 	mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_DETECT_ON_ERR);
 	mmc->caps2 |= MMC_CAP2_SANITIZE;
+	mmc->caps2 |= MMC_CAP2_CACHE_CTRL;
 
 	if (plat->nonremovable)
 		mmc->caps |= MMC_CAP_NONREMOVABLE;
 	mmc->caps |= MMC_CAP_SDIO_IRQ;
 
-	mmc->caps2 |= MMC_CAP2_INIT_BKOPS | MMC_CAP2_BKOPS;
-
 	if (plat->is_sdio_al_client)
 		mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
 
diff --git a/drivers/net/usb/rmnet_usb_ctrl.c b/drivers/net/usb/rmnet_usb_ctrl.c
index ba16ed9..7ed8ffa 100644
--- a/drivers/net/usb/rmnet_usb_ctrl.c
+++ b/drivers/net/usb/rmnet_usb_ctrl.c
@@ -122,6 +122,55 @@
 	return 0;
 }
 
+static void get_encap_work(struct work_struct *w)
+{
+	struct usb_device	*udev;
+	struct rmnet_ctrl_dev	*dev =
+			container_of(w, struct rmnet_ctrl_dev, get_encap_work);
+	int			status;
+
+	udev = interface_to_usbdev(dev->intf);
+
+	status = usb_autopm_get_interface(dev->intf);
+	if (status < 0 && status != -EAGAIN && status != -EACCES) {
+		dev->get_encap_failure_cnt++;
+		return;
+	}
+
+	usb_fill_control_urb(dev->rcvurb, udev,
+				usb_rcvctrlpipe(udev, 0),
+				(unsigned char *)dev->in_ctlreq,
+				dev->rcvbuf,
+				DEFAULT_READ_URB_LENGTH,
+				resp_avail_cb, dev);
+
+
+	usb_anchor_urb(dev->rcvurb, &dev->rx_submitted);
+	status = usb_submit_urb(dev->rcvurb, GFP_KERNEL);
+	if (status) {
+		dev->get_encap_failure_cnt++;
+		usb_unanchor_urb(dev->rcvurb);
+		usb_autopm_put_interface(dev->intf);
+		dev_err(dev->devicep,
+		"%s: Error submitting Read URB %d\n", __func__, status);
+		goto resubmit_int_urb;
+	}
+
+	return;
+
+resubmit_int_urb:
+	/*check if it is already submitted in resume*/
+	if (!dev->inturb->anchor) {
+		usb_anchor_urb(dev->inturb, &dev->rx_submitted);
+		status = usb_submit_urb(dev->inturb, GFP_KERNEL);
+		if (status) {
+			usb_unanchor_urb(dev->inturb);
+			dev_err(dev->devicep, "%s: Error re-submitting Int URB %d\n",
+				__func__, status);
+		}
+	}
+}
+
 static void notification_available_cb(struct urb *urb)
 {
 	int				status;
@@ -133,12 +182,13 @@
 
 	switch (urb->status) {
 	case 0:
+	/*if non zero lenght of data received while unlink*/
+	case -ENOENT:
 		/*success*/
 		break;
 
 	/*do not resubmit*/
 	case -ESHUTDOWN:
-	case -ENOENT:
 	case -ECONNRESET:
 	case -EPROTO:
 		return;
@@ -156,26 +206,17 @@
 		goto resubmit_int_urb;
 	}
 
+	if (!urb->actual_length)
+		return;
+
 	ctrl = urb->transfer_buffer;
 
 	switch (ctrl->bNotificationType) {
 	case USB_CDC_NOTIFY_RESPONSE_AVAILABLE:
 		dev->resp_avail_cnt++;
-		usb_fill_control_urb(dev->rcvurb, udev,
-					usb_rcvctrlpipe(udev, 0),
-					(unsigned char *)dev->in_ctlreq,
-					dev->rcvbuf,
-					DEFAULT_READ_URB_LENGTH,
-					resp_avail_cb, dev);
-
-		status = usb_submit_urb(dev->rcvurb, GFP_ATOMIC);
-		if (status) {
-			dev_err(dev->devicep,
-			"%s: Error submitting Read URB %d\n", __func__, status);
-			goto resubmit_int_urb;
-		}
 
 		usb_mark_last_busy(udev);
+		queue_work(dev->wq, &dev->get_encap_work);
 
 		if (!dev->resp_available) {
 			dev->resp_available = true;
@@ -189,10 +230,13 @@
 	}
 
 resubmit_int_urb:
+	usb_anchor_urb(urb, &dev->rx_submitted);
 	status = usb_submit_urb(urb, GFP_ATOMIC);
-	if (status)
+	if (status) {
+		usb_unanchor_urb(urb);
 		dev_err(dev->devicep, "%s: Error re-submitting Int URB %d\n",
 		__func__, status);
+	}
 
 	return;
 }
@@ -208,6 +252,8 @@
 
 	udev = interface_to_usbdev(dev->intf);
 
+	usb_autopm_put_interface_async(dev->intf);
+
 	switch (urb->status) {
 	case 0:
 		/*success*/
@@ -263,41 +309,41 @@
 	wake_up(&dev->read_wait_queue);
 
 resubmit_int_urb:
-	/*re-submit int urb to check response available*/
-	usb_mark_last_busy(udev);
-	status = usb_submit_urb(dev->inturb, GFP_ATOMIC);
-	if (status)
-		dev_err(dev->devicep, "%s: Error re-submitting Int URB %d\n",
-			__func__, status);
+	/*check if it is already submitted in resume*/
+	if (!dev->inturb->anchor) {
+		usb_mark_last_busy(udev);
+		usb_anchor_urb(dev->inturb, &dev->rx_submitted);
+		status = usb_submit_urb(dev->inturb, GFP_ATOMIC);
+		if (status) {
+			usb_unanchor_urb(dev->inturb);
+			dev_err(dev->devicep, "%s: Error re-submitting Int URB %d\n",
+				__func__, status);
+		}
+	}
 }
 
 int rmnet_usb_ctrl_start_rx(struct rmnet_ctrl_dev *dev)
 {
 	int	retval = 0;
 
+	usb_anchor_urb(dev->inturb, &dev->rx_submitted);
 	retval = usb_submit_urb(dev->inturb, GFP_KERNEL);
-	if (retval < 0)
-		dev_err(dev->devicep, "%s Intr submit %d\n", __func__, retval);
+	if (retval < 0) {
+		usb_unanchor_urb(dev->inturb);
+		dev_err(dev->devicep, "%s Intr submit %d\n", __func__,
+				retval);
+	}
 
 	return retval;
 }
 
-int rmnet_usb_ctrl_stop_rx(struct rmnet_ctrl_dev *dev)
+int rmnet_usb_ctrl_suspend(struct rmnet_ctrl_dev *dev)
 {
-	if (!is_dev_connected(dev)) {
-		dev_dbg(dev->devicep, "%s: Ctrl device disconnected\n",
-			__func__);
-		return -ENODEV;
-	}
-
-	dev_dbg(dev->devicep, "%s\n", __func__);
-
-	usb_kill_urb(dev->rcvurb);
-	usb_kill_urb(dev->inturb);
+	if (!flush_work_sync(&dev->get_encap_work))
+		usb_kill_anchored_urbs(&dev->rx_submitted);
 
 	return 0;
 }
-
 static int rmnet_usb_ctrl_alloc_rx(struct rmnet_ctrl_dev *dev)
 {
 	int	retval = -ENOMEM;
@@ -826,7 +872,6 @@
 
 void rmnet_usb_ctrl_disconnect(struct rmnet_ctrl_dev *dev)
 {
-	rmnet_usb_ctrl_stop_rx(dev);
 
 	mutex_lock(&dev->dev_lock);
 
@@ -839,13 +884,16 @@
 
 	wake_up(&dev->read_wait_queue);
 
+	cancel_work_sync(&dev->get_encap_work);
+
+	usb_kill_anchored_urbs(&dev->tx_submitted);
+	usb_kill_anchored_urbs(&dev->rx_submitted);
+
 	usb_free_urb(dev->inturb);
 	dev->inturb = NULL;
 
 	kfree(dev->intbuf);
 	dev->intbuf = NULL;
-
-	usb_kill_anchored_urbs(&dev->tx_submitted);
 }
 
 #if defined(CONFIG_DEBUG_FS)
@@ -879,6 +927,7 @@
 				"cbits_tomdm:              %d\n"
 				"mdm_wait_timeout:         %u\n"
 				"zlp_cnt:                  %u\n"
+				"get_encap_failure_cnt     %u\n"
 				"dev opened:               %s\n",
 				dev, dev->name,
 				dev->snd_encap_cmd_cnt,
@@ -890,6 +939,7 @@
 				dev->cbits_tomdm,
 				dev->mdm_wait_timeout,
 				dev->zlp_cnt,
+				dev->get_encap_failure_cnt,
 				dev->is_opened ? "OPEN" : "CLOSE");
 
 	}
@@ -968,12 +1018,21 @@
 		/*for debug purpose*/
 		snprintf(dev->name, CTRL_DEV_MAX_LEN, "hsicctl%d", n);
 
+		dev->wq = create_singlethread_workqueue(dev->name);
+		if (!dev->wq) {
+			pr_err("unable to allocate workqueue");
+			kfree(dev);
+			goto error0;
+		}
+
 		mutex_init(&dev->dev_lock);
 		spin_lock_init(&dev->rx_lock);
 		init_waitqueue_head(&dev->read_wait_queue);
 		init_waitqueue_head(&dev->open_wait_queue);
 		INIT_LIST_HEAD(&dev->rx_list);
 		init_usb_anchor(&dev->tx_submitted);
+		init_usb_anchor(&dev->rx_submitted);
+		INIT_WORK(&dev->get_encap_work, get_encap_work);
 
 		status = rmnet_usb_ctrl_alloc_rx(dev);
 		if (status < 0) {
@@ -1074,6 +1133,7 @@
 		device_remove_file(ctrl_dev[i]->devicep, &dev_attr_modem_wait);
 #endif
 		cdev_del(&ctrl_dev[i]->cdev);
+		destroy_workqueue(ctrl_dev[i]->wq);
 		kfree(ctrl_dev[i]);
 		ctrl_dev[i] = NULL;
 		device_destroy(ctrldev_classp, MKDEV(MAJOR(ctrldev_num), i));
diff --git a/drivers/net/usb/rmnet_usb_ctrl.h b/drivers/net/usb/rmnet_usb_ctrl.h
index 7a84817..a8f8079 100644
--- a/drivers/net/usb/rmnet_usb_ctrl.h
+++ b/drivers/net/usb/rmnet_usb_ctrl.h
@@ -34,6 +34,7 @@
 	struct urb		*rcvurb;
 	struct urb		*inturb;
 	struct usb_anchor	tx_submitted;
+	struct usb_anchor	rx_submitted;
 	void			*rcvbuf;
 	void			*intbuf;
 	struct usb_ctrlrequest	*in_ctlreq;
@@ -44,6 +45,9 @@
 	wait_queue_head_t	read_wait_queue;
 	wait_queue_head_t	open_wait_queue;
 
+	struct workqueue_struct	*wq;
+	struct work_struct	get_encap_work;
+
 	unsigned		is_opened;
 
 	bool			is_connected;
@@ -66,6 +70,7 @@
 	unsigned int		snd_encap_cmd_cnt;
 	unsigned int		get_encap_resp_cnt;
 	unsigned int		resp_avail_cnt;
+	unsigned int		get_encap_failure_cnt;
 	unsigned int		set_ctrl_line_state_cnt;
 	unsigned int		tx_ctrl_err_cnt;
 	unsigned int		zlp_cnt;
@@ -74,7 +79,7 @@
 extern struct rmnet_ctrl_dev *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_suspend(struct rmnet_ctrl_dev *dev);
 extern int rmnet_usb_ctrl_init(void);
 extern void rmnet_usb_ctrl_exit(void);
 extern int rmnet_usb_ctrl_probe(struct usb_interface *intf,
diff --git a/drivers/net/usb/rmnet_usb_data.c b/drivers/net/usb/rmnet_usb_data.c
index b8c6140..17ff067 100644
--- a/drivers/net/usb/rmnet_usb_data.c
+++ b/drivers/net/usb/rmnet_usb_data.c
@@ -87,7 +87,6 @@
 {
 	struct usbnet		*unet;
 	struct rmnet_ctrl_dev	*dev;
-	int			time = 0;
 	int			retval = 0;
 
 	unet = usb_get_intfdata(iface);
@@ -107,19 +106,12 @@
 
 	retval = usbnet_suspend(iface, message);
 	if (!retval) {
-		if (message.event & PM_EVENT_SUSPEND) {
-			time = usb_wait_anchor_empty_timeout(&dev->tx_submitted,
-								1000);
-			if (!time)
-				usb_kill_anchored_urbs(&dev->tx_submitted);
-
-			retval = rmnet_usb_ctrl_stop_rx(dev);
-			iface->dev.power.power_state.event = message.event;
-		}
-		/*  TBD : do we need to set/clear usbnet->udev->reset_resume*/
-		} else
+		retval = rmnet_usb_ctrl_suspend(dev);
+		iface->dev.power.power_state.event = message.event;
+	} else {
 		dev_dbg(&iface->dev,
 			"%s: device is busy can not suspend\n", __func__);
+	}
 
 fail:
 	return retval;
diff --git a/drivers/platform/msm/qpnp-power-on.c b/drivers/platform/msm/qpnp-power-on.c
index 996456f..33b12ae 100644
--- a/drivers/platform/msm/qpnp-power-on.c
+++ b/drivers/platform/msm/qpnp-power-on.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
@@ -35,6 +35,7 @@
 #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_PS_HOLD_RST_CTL(base)	(base + 0x5A)
 
 #define QPNP_PON_RESIN_PULL_UP		BIT(0)
 #define QPNP_PON_KPDPWR_PULL_UP		BIT(1)
@@ -50,6 +51,10 @@
 #define QPNP_PON_RESIN_N_SET		BIT(1)
 #define QPNP_PON_RESIN_BARK_N_SET	BIT(4)
 
+#define QPNP_PON_RESET_EN		BIT(7)
+#define QPNP_PON_WARM_RESET		BIT(0)
+#define QPNP_PON_SHUTDOWN		BIT(2)
+
 /* Ranges */
 #define QPNP_PON_S1_TIMER_MAX		10256
 #define QPNP_PON_S2_TIMER_MAX		2000
@@ -84,6 +89,8 @@
 	struct delayed_work bark_work;
 };
 
+static struct qpnp_pon *sys_reset_dev;
+
 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
@@ -113,6 +120,57 @@
 	return rc;
 }
 
+/**
+ * qpnp_pon_system_pwr_off - Configure system-reset PMIC for shutdown or reset
+ * @reset: Configures for shutdown if 0, or reset if 1.
+ *
+ * This function will only configure a single PMIC. The other PMICs in the
+ * system are slaved off of it and require no explicit configuration. Once
+ * the system-reset PMIC is configured properly, the MSM can drop PS_HOLD to
+ * activate the specified configuration.
+ */
+int qpnp_pon_system_pwr_off(bool reset)
+{
+	int rc;
+	struct qpnp_pon *pon = sys_reset_dev;
+
+	if (!pon)
+		return -ENODEV;
+
+	rc = qpnp_pon_masked_write(pon, QPNP_PON_PS_HOLD_RST_CTL(pon->base),
+							QPNP_PON_RESET_EN, 0);
+	if (rc)
+		dev_err(&pon->spmi->dev,
+			"Unable to write to addr=%x, rc(%d)\n",
+				QPNP_PON_PS_HOLD_RST_CTL(pon->base), rc);
+
+	/*
+	 * We need 10 sleep clock cycles here. But since the clock is
+	 * internally generated, we need to add 50% tolerance to be
+	 * conservative.
+	 */
+	udelay(500);
+
+	rc = qpnp_pon_masked_write(pon, QPNP_PON_PS_HOLD_RST_CTL(pon->base),
+			   QPNP_PON_WARM_RESET | QPNP_PON_SHUTDOWN,
+			   reset ? QPNP_PON_WARM_RESET : QPNP_PON_SHUTDOWN);
+	if (rc)
+		dev_err(&pon->spmi->dev,
+			"Unable to write to addr=%x, rc(%d)\n",
+				QPNP_PON_PS_HOLD_RST_CTL(pon->base), rc);
+
+	rc = qpnp_pon_masked_write(pon, QPNP_PON_PS_HOLD_RST_CTL(pon->base),
+							QPNP_PON_RESET_EN,
+							QPNP_PON_RESET_EN);
+	if (rc)
+		dev_err(&pon->spmi->dev,
+			"Unable to write to addr=%x, rc(%d)\n",
+				QPNP_PON_PS_HOLD_RST_CTL(pon->base), rc);
+
+	return rc;
+}
+EXPORT_SYMBOL(qpnp_pon_system_pwr_off);
+
 static struct qpnp_pon_config *
 qpnp_get_cfg(struct qpnp_pon *pon, u32 pon_type)
 {
@@ -662,7 +720,7 @@
 	struct resource *pon_resource;
 	struct device_node *itr = NULL;
 	u32 delay = 0;
-	int rc = 0;
+	int rc, sys_reset;
 
 	pon = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_pon),
 							GFP_KERNEL);
@@ -671,6 +729,15 @@
 		return -ENOMEM;
 	}
 
+	sys_reset = of_property_read_bool(spmi->dev.of_node,
+						"qcom,system-reset");
+	if (sys_reset && sys_reset_dev) {
+		dev_err(&spmi->dev, "qcom,system-reset property can only be specified for one device on the system\n");
+		return -EINVAL;
+	} else if (sys_reset) {
+		sys_reset_dev = pon;
+	}
+
 	pon->spmi = spmi;
 
 	/* get the total number of pon configurations */
diff --git a/drivers/platform/msm/sps/bam.c b/drivers/platform/msm/sps/bam.c
index eb9e8ee..bcb4cdb 100644
--- a/drivers/platform/msm/sps/bam.c
+++ b/drivers/platform/msm/sps/bam.c
@@ -679,7 +679,7 @@
 	bam_write_reg_field(base, CTRL, BAM_EN, 1);
 
 #ifdef CONFIG_SPS_SUPPORT_NDP_BAM
-	bam_write_reg_field(base, CTRL, CACHE_MISS_ERR_RESP_EN, 1);
+	bam_write_reg_field(base, CTRL, CACHE_MISS_ERR_RESP_EN, 0);
 
 	bam_write_reg_field(base, CTRL, LOCAL_CLK_GATING, 1);
 #endif
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index d8baa29..2542845 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -442,4 +442,13 @@
 	help
 	  Say Y to enable battery temperature measurements using
 	  thermistor connected on BATCTRL ADC.
+
+config QPNP_BMS
+	tristate "QPNP Battery Monitoring System driver"
+	depends on SPMI
+	depends on MSM_QPNP_INT
+	help
+	  Say Y here to enable support for QPNP chip bms device.
+	  It registers a fuelgauge bms power supply to report
+	  State of Charge.
 endif # POWER_SUPPLY
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index f84b527..9dc1960 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -55,6 +55,7 @@
 obj-$(CONFIG_SMB137B_CHARGER)   += smb137b.o
 obj-$(CONFIG_PM8XXX_CCADC)	+= pm8xxx-ccadc.o
 obj-$(CONFIG_PM8921_BMS)	+= pm8921-bms.o
+obj-$(CONFIG_QPNP_BMS)		+= qpnp-bms.o
 obj-$(CONFIG_PM8921_CHARGER)	+= pm8921-charger.o
 obj-$(CONFIG_LTC4088_CHARGER)	+= ltc4088-charger.o
 obj-$(CONFIG_CHARGER_SMB347)	+= smb347-charger.o
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index 28b641d..e4e0004 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -1852,6 +1852,9 @@
 	}
 	if (disable)
 		pr_warn("current drawn from chg=0, battery provides current\n");
+
+	pm_chg_usb_suspend_enable(the_chip, disable);
+
 	return pm_chg_charge_dis(the_chip, disable);
 }
 EXPORT_SYMBOL(pm8921_disable_source_current);
@@ -2495,11 +2498,6 @@
 		pr_debug("USB charger active\n");
 
 		pm_chg_iusbmax_get(chip, &usb_ma);
-		if (usb_ma == 500 && !usb_target_ma) {
-			pr_debug("Stopping Unplug Check Worker USB == 500mA\n");
-			disable_input_voltage_regulation(chip);
-			return;
-		}
 
 		if (usb_ma <= 100) {
 			pr_debug(
@@ -3316,7 +3314,7 @@
 	chip->usb_present = !!is_usb_chg_plugged_in(chip);
 
 	notify_usb_of_the_plugin_event(chip->usb_present);
-	if (chip->usb_present) {
+	if (chip->usb_present || chip->dc_present) {
 		schedule_delayed_work(&chip->unplug_check_work,
 			round_jiffies_relative(msecs_to_jiffies
 				(UNPLUG_CHECK_WAIT_PERIOD_MS)));
@@ -4150,6 +4148,7 @@
 	}
 
 	enable_irq_wake(chip->pmic_chg_irq[USBIN_VALID_IRQ]);
+	enable_irq_wake(chip->pmic_chg_irq[DCIN_VALID_IRQ]);
 	enable_irq_wake(chip->pmic_chg_irq[USBIN_OV_IRQ]);
 	enable_irq_wake(chip->pmic_chg_irq[USBIN_UV_IRQ]);
 	enable_irq_wake(chip->pmic_chg_irq[BAT_TEMP_OK_IRQ]);
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
new file mode 100644
index 0000000..7b4d97e
--- /dev/null
+++ b/drivers/power/qpnp-bms.c
@@ -0,0 +1,353 @@
+/* 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/types.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/power_supply.h>
+#include <linux/spmi.h>
+
+/* Interrupt offsets */
+#define INT_RT_STS(base)		(base + 0x10)
+#define INT_SET_TYPE(base)		(base + 0x11)
+#define INT_POLARITY_HIGH(base)		(base + 0x12)
+#define INT_POLARITY_LOW(base)		(base + 0x13)
+#define INT_LATCHED_CLR(base)		(base + 0x14)
+#define INT_EN_SET(base)		(base + 0x15)
+#define INT_EN_CLR(base)		(base + 0x16)
+#define INT_LATCHED_STS(base)		(base + 0x18)
+#define INT_PENDING_STS(base)		(base + 0x19)
+#define INT_MID_SEL(base)		(base + 0x1A)
+#define INT_PRIORITY(base)		(base + 0x1B)
+
+/* BMS Register Offsets */
+#define BMS1_REVISION1			0x0
+#define BMS1_REVISION2			0x1
+#define BMS1_STATUS1			0x8
+#define BMS1_MODE_CTL			0X40
+/* Columb counter clear registers */
+#define BMS1_CC_DATA_CTL		0x42
+#define BMS1_CC_CLEAR_CTRL		0x43
+/* OCV limit registers */
+#define BMS1_OCV_USE_LOW_LIMIT_THR0	0x48
+#define BMS1_OCV_USE_LOW_LIMIT_THR1	0x49
+#define BMS1_OCV_USE_HIGH_LIMIT_THR0	0x4A
+#define BMS1_OCV_USE_HIGH_LIMIT_THR1	0x4B
+#define BMS1_OCV_USE_LIMIT_CTL		0x4C
+/* CC interrupt threshold */
+#define BMS1_CC_THR0			0x7A
+#define BMS1_CC_THR1			0x7B
+#define BMS1_CC_THR2			0x7C
+#define BMS1_CC_THR3			0x7D
+#define BMS1_CC_THR4			0x7E
+/* OCV for r registers */
+#define BMS1_OCV_FOR_R_DATA0		0x80
+#define BMS1_OCV_FOR_R_DATA1		0x81
+#define BMS1_VSENSE_FOR_R_DATA0		0x82
+#define BMS1_VSENSE_FOR_R_DATA1		0x83
+/* Columb counter data */
+#define BMS1_CC_DATA0			0x8A
+#define BMS1_CC_DATA1			0x8B
+#define BMS1_CC_DATA2			0x8C
+#define BMS1_CC_DATA3			0x8D
+#define BMS1_CC_DATA4			0x8E
+/* OCV for soc data */
+#define BMS1_OCV_FOR_SOC_DATA0		0x90
+#define BMS1_OCV_FOR_SOC_DATA1		0x91
+#define BMS1_VSENSE_PON_DATA0		0x94
+#define BMS1_VSENSE_PON_DATA1		0x95
+#define BMS1_VBAT_AVG_DATA0		0x9E
+#define BMS1_VBAT_AVG_DATA1		0x9F
+/* Extra bms registers */
+#define BMS1_BMS_DATA_REG_0		0xB0
+#define BMS1_BMS_DATA_REG_1		0xB1
+#define BMS1_BMS_DATA_REG_2		0xB2
+#define BMS1_BMS_DATA_REG_3		0xB3
+
+#define QPNP_BMS_DEV_NAME "qcom,qpnp-bms"
+
+struct qpnp_bms_chip {
+	struct device			*dev;
+	struct power_supply		bms_psy;
+	struct spmi_device		*spmi;
+	u16				base;
+
+	u8				revision1;
+	u8				revision2;
+	int				charger_status;
+	bool				online;
+	/* platform data */
+	unsigned int			r_sense_mohm;
+	unsigned int			v_cutoff;
+	unsigned int			max_voltage;
+	unsigned int			r_conn_mohm;
+	int				shutdown_soc_valid_limit;
+	int				adjust_soc_low_threshold;
+	int				adjust_soc_high_threshold;
+	int				chg_term;
+};
+
+static struct of_device_id qpnp_bms_match_table[] = {
+	{ .compatible = QPNP_BMS_DEV_NAME },
+	{}
+};
+
+static char *qpnp_bms_supplicants[] = {
+	"battery"
+};
+
+static enum power_supply_property msm_bms_power_props[] = {
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_ONLINE,
+	POWER_SUPPLY_PROP_CAPACITY,
+	POWER_SUPPLY_PROP_CURRENT_NOW,
+	POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
+};
+
+static int qpnp_read_wrapper(struct qpnp_bms_chip *chip, u8 *val,
+			u16 base, int count)
+{
+	int rc;
+	struct spmi_device *spmi = chip->spmi;
+
+	rc = spmi_ext_register_readl(spmi->ctrl, spmi->sid, base, val, count);
+	if (rc)
+		pr_err("SPMI read failed rc=%d\n", rc);
+
+	return 0;
+}
+
+/* Returns capacity as a SoC percentage between 0 and 100 */
+static int get_prop_bms_capacity(struct qpnp_bms_chip *chip)
+{
+	/* return 50 until a real algorithm is implemented */
+	return 50;
+}
+
+/* Returns instantaneous current in uA */
+static int get_prop_bms_current_now(struct qpnp_bms_chip *chip)
+{
+	/* temporarily return 0 until a real algorithm is put in */
+	return 0;
+}
+
+/* Returns full charge design in uAh */
+static int get_prop_bms_charge_full_design(struct qpnp_bms_chip *chip)
+{
+	/* temporarily return 0 until a real algorithm is put in */
+	return 0;
+}
+
+static void set_prop_bms_online(struct qpnp_bms_chip *chip, bool online)
+{
+	chip->online = online;
+}
+
+static void set_prop_bms_status(struct qpnp_bms_chip *chip, int status)
+{
+	chip->charger_status = status;
+}
+
+static void qpnp_bms_external_power_changed(struct power_supply *psy)
+{
+}
+
+static int qpnp_bms_power_get_property(struct power_supply *psy,
+					enum power_supply_property psp,
+					union power_supply_propval *val)
+{
+	struct qpnp_bms_chip *chip = container_of(psy, struct qpnp_bms_chip,
+								bms_psy);
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_CAPACITY:
+		val->intval = get_prop_bms_capacity(chip);
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_NOW:
+		val->intval = get_prop_bms_current_now(chip);
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
+		val->intval = get_prop_bms_charge_full_design(chip);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int qpnp_bms_power_set_property(struct power_supply *psy,
+					enum power_supply_property psp,
+					const union power_supply_propval *val)
+{
+	struct qpnp_bms_chip *chip = container_of(psy, struct qpnp_bms_chip,
+								bms_psy);
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_ONLINE:
+		set_prop_bms_online(chip, val->intval);
+		break;
+	case POWER_SUPPLY_PROP_STATUS:
+		set_prop_bms_status(chip, (bool)val->intval);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+#define SPMI_PROPERTY_READ(chip_prop, qpnp_spmi_property, retval, errlabel)\
+do {									\
+	retval = of_property_read_u32(spmi->dev.of_node,		\
+				"qcom,bms-" qpnp_spmi_property,		\
+					&chip->chip_prop);		\
+	if (retval) {							\
+		pr_err("Error reading " #qpnp_spmi_property		\
+						" property %d\n", rc);	\
+		goto errlabel;						\
+	}								\
+} while (0)
+
+static int __devinit
+qpnp_bms_probe(struct spmi_device *spmi)
+{
+	struct qpnp_bms_chip *chip;
+	struct resource *bms_resource;
+	int rc;
+
+	chip = kzalloc(sizeof *chip, GFP_KERNEL);
+
+	if (chip == NULL) {
+		pr_err("kzalloc() failed.\n");
+		return -ENOMEM;
+	}
+
+	chip->dev = &(spmi->dev);
+	chip->spmi = spmi;
+
+	bms_resource = spmi_get_resource(spmi, NULL, IORESOURCE_MEM, 0);
+	if (!bms_resource) {
+		dev_err(&spmi->dev, "Unable to get BMS base address\n");
+		return -ENXIO;
+	}
+	chip->base = bms_resource->start;
+
+	rc = qpnp_read_wrapper(chip, &chip->revision1,
+			chip->base + BMS1_REVISION1, 1);
+	if (rc) {
+		pr_err("error reading version register %d\n", rc);
+		goto error_read;
+	}
+
+	rc = qpnp_read_wrapper(chip, &chip->revision2,
+			chip->base + BMS1_REVISION2, 1);
+	if (rc) {
+		pr_err("Error reading version register %d\n", rc);
+		goto error_read;
+	}
+
+	SPMI_PROPERTY_READ(r_sense_mohm, "r-sense-mohm", rc, error_read);
+	SPMI_PROPERTY_READ(v_cutoff, "v-cutoff-uv", rc, error_read);
+	SPMI_PROPERTY_READ(max_voltage, "max-voltage-uv", rc, error_read);
+	SPMI_PROPERTY_READ(r_conn_mohm, "r-conn-mohm", rc, error_read);
+	SPMI_PROPERTY_READ(shutdown_soc_valid_limit,
+			"shutdown-soc-valid-limit", rc, error_read);
+	SPMI_PROPERTY_READ(adjust_soc_low_threshold,
+			"adjust-soc-low-threshold", rc, error_read);
+	SPMI_PROPERTY_READ(adjust_soc_high_threshold,
+			"adjust-soc-high-threshold", rc, error_read);
+	SPMI_PROPERTY_READ(chg_term, "chg-term-ua", rc, error_read);
+
+	pr_debug("dts data: r_sense_mohm:%d, v_cutoff:%d, max_v:%d, r_conn:%d, shutdown_soc: %d, adjust_soc_low:%d, adjust_soc_high:%d, chg_term:%d\n",
+			chip->r_sense_mohm, chip->v_cutoff,
+			chip->max_voltage, chip->r_conn_mohm,
+			chip->shutdown_soc_valid_limit,
+			chip->adjust_soc_low_threshold,
+			chip->adjust_soc_high_threshold,
+			chip->chg_term);
+
+	dev_set_drvdata(&spmi->dev, chip);
+	device_init_wakeup(&spmi->dev, 1);
+
+	/* setup & register the battery power supply */
+	chip->bms_psy.name = "bms";
+	chip->bms_psy.type = POWER_SUPPLY_TYPE_BMS;
+	chip->bms_psy.properties = msm_bms_power_props;
+	chip->bms_psy.num_properties = ARRAY_SIZE(msm_bms_power_props);
+	chip->bms_psy.get_property = qpnp_bms_power_get_property;
+	chip->bms_psy.set_property = qpnp_bms_power_set_property;
+	chip->bms_psy.external_power_changed =
+		qpnp_bms_external_power_changed;
+	chip->bms_psy.supplied_to = qpnp_bms_supplicants;
+	chip->bms_psy.num_supplicants = ARRAY_SIZE(qpnp_bms_supplicants);
+
+	rc = power_supply_register(chip->dev, &chip->bms_psy);
+
+	if (rc < 0) {
+		pr_err("power_supply_register bms failed rc = %d\n", rc);
+		goto unregister_dc;
+	}
+
+	pr_info("probe success\n");
+	return 0;
+
+unregister_dc:
+	power_supply_unregister(&chip->bms_psy);
+	dev_set_drvdata(&spmi->dev, NULL);
+error_read:
+	kfree(chip);
+	return rc;
+}
+
+static int __devexit
+qpnp_bms_remove(struct spmi_device *spmi)
+{
+	struct qpnp_bms_chip *chip = dev_get_drvdata(&spmi->dev);
+
+	dev_set_drvdata(&spmi->dev, NULL);
+	kfree(chip);
+	return 0;
+}
+
+static struct spmi_driver qpnp_bms_driver = {
+	.probe		= qpnp_bms_probe,
+	.remove		= __devexit_p(qpnp_bms_remove),
+	.driver		= {
+		.name		= QPNP_BMS_DEV_NAME,
+		.owner		= THIS_MODULE,
+		.of_match_table	= qpnp_bms_match_table,
+	},
+};
+
+static int __init qpnp_bms_init(void)
+{
+	pr_info("QPNP BMS INIT\n");
+	return spmi_driver_register(&qpnp_bms_driver);
+}
+
+static void __exit qpnp_bms_exit(void)
+{
+	pr_info("QPNP BMS EXIT\n");
+	return spmi_driver_unregister(&qpnp_bms_driver);
+}
+
+module_init(qpnp_bms_init);
+module_exit(qpnp_bms_exit);
+
+MODULE_DESCRIPTION("QPNP BMS Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" QPNP_BMS_DEV_NAME);
diff --git a/drivers/slimbus/slim-msm-ctrl.c b/drivers/slimbus/slim-msm-ctrl.c
index 6cddf2d..e2f37cc 100644
--- a/drivers/slimbus/slim-msm-ctrl.c
+++ b/drivers/slimbus/slim-msm-ctrl.c
@@ -699,7 +699,8 @@
 			for (i = 0; i < 6; i++)
 				e_addr[i] = buf[7-i];
 
-			ret = slim_assign_laddr(&dev->ctrl, e_addr, 6, &laddr);
+			ret = slim_assign_laddr(&dev->ctrl, e_addr, 6, &laddr,
+						false);
 			/* Is this Qualcomm ported generic device? */
 			if (!ret && e_addr[5] == QC_MFGID_LSB &&
 				e_addr[4] == QC_MFGID_MSB &&
diff --git a/drivers/slimbus/slimbus.c b/drivers/slimbus/slimbus.c
index da2a30d..bd25875 100644
--- a/drivers/slimbus/slimbus.c
+++ b/drivers/slimbus/slimbus.c
@@ -681,13 +681,13 @@
 }
 
 static int ctrl_getlogical_addr(struct slim_controller *ctrl, const u8 *eaddr,
-				u8 e_len, u8 *laddr)
+				u8 e_len, u8 *entry)
 {
 	u8 i;
 	for (i = 0; i < ctrl->num_dev; i++) {
 		if (ctrl->addrt[i].valid &&
 			memcmp(ctrl->addrt[i].eaddr, eaddr, e_len) == 0) {
-			*laddr = i;
+			*entry = i;
 			return 0;
 		}
 	}
@@ -699,23 +699,28 @@
  * @ctrl: Controller with which device is enumerated.
  * @e_addr: 6-byte elemental address of the device.
  * @e_len: buffer length for e_addr
- * @laddr: Return logical address.
+  * @laddr: Return logical address (if valid flag is false)
+  * @valid: true if laddr holds a valid address that controller wants to
+  *	set for this enumeration address. Otherwise framework sets index into
+  *	address table as logical address.
  * Called by controller in response to REPORT_PRESENT. Framework will assign
  * a logical address to this enumeration address.
  * Function returns -EXFULL to indicate that all logical addresses are already
  * taken.
  */
 int slim_assign_laddr(struct slim_controller *ctrl, const u8 *e_addr,
-				u8 e_len, u8 *laddr)
+				u8 e_len, u8 *laddr, bool valid)
 {
 	int ret;
 	u8 i = 0;
+	bool exists = false;
 	struct slim_device *sbdev;
 	mutex_lock(&ctrl->m_ctrl);
 	/* already assigned */
-	if (ctrl_getlogical_addr(ctrl, e_addr, e_len, laddr) == 0)
-		i = *laddr;
-	else {
+	if (ctrl_getlogical_addr(ctrl, e_addr, e_len, &i) == 0) {
+		*laddr = ctrl->addrt[i].laddr;
+		exists = true;
+	} else {
 		if (ctrl->num_dev >= 254) {
 			ret = -EXFULL;
 			goto ret_assigned_laddr;
@@ -737,22 +742,26 @@
 		}
 		memcpy(ctrl->addrt[i].eaddr, e_addr, e_len);
 		ctrl->addrt[i].valid = true;
+		/* Preferred address is index into table */
+		if (!valid)
+			*laddr = i;
 	}
 
-	ret = ctrl->set_laddr(ctrl, ctrl->addrt[i].eaddr, 6, i);
+	ret = ctrl->set_laddr(ctrl, (const u8 *)&ctrl->addrt[i].eaddr, 6,
+				*laddr);
 	if (ret) {
 		ctrl->addrt[i].valid = false;
 		goto ret_assigned_laddr;
 	}
-	*laddr = i;
+	ctrl->addrt[i].laddr = *laddr;
 
-	dev_dbg(&ctrl->dev, "setting slimbus l-addr:%x\n", i);
+	dev_dbg(&ctrl->dev, "setting slimbus l-addr:%x\n", *laddr);
 ret_assigned_laddr:
 	mutex_unlock(&ctrl->m_ctrl);
-	if (ret)
+	if (exists || ret)
 		return ret;
 
-	pr_info("slimbus laddr:0x%x, EAPC:0x%x:0x%x", i,
+	pr_info("slimbus:%d laddr:0x%x, EAPC:0x%x:0x%x", ctrl->nr, *laddr,
 				e_addr[1], e_addr[2]);
 	mutex_lock(&ctrl->m_ctrl);
 	list_for_each_entry(sbdev, &ctrl->devs, dev_list) {
@@ -785,12 +794,21 @@
 				u8 e_len, u8 *laddr)
 {
 	int ret = 0;
+	u8 entry;
 	struct slim_controller *ctrl = sb->ctrl;
 	if (!ctrl || !laddr || !e_addr || e_len != 6)
 		return -EINVAL;
 	mutex_lock(&ctrl->m_ctrl);
-	ret = ctrl_getlogical_addr(ctrl, e_addr, e_len, laddr);
+	ret = ctrl_getlogical_addr(ctrl, e_addr, e_len, &entry);
+	if (!ret)
+		*laddr = ctrl->addrt[entry].laddr;
 	mutex_unlock(&ctrl->m_ctrl);
+	if (ret == -ENXIO && ctrl->get_laddr) {
+		ret = ctrl->get_laddr(ctrl, e_addr, e_len, laddr);
+		if (!ret)
+			ret = slim_assign_laddr(ctrl, e_addr, e_len, laddr,
+						true);
+	}
 	return ret;
 }
 EXPORT_SYMBOL_GPL(slim_get_logical_addr);
@@ -943,8 +961,6 @@
 	u16 ec;
 	u8 tid, mlen = 6;
 
-	if (sbdev->laddr != SLIM_LA_MANAGER && sbdev->laddr >= ctrl->num_dev)
-		return -ENXIO;
 	ret = slim_ele_access_sanity(msg, mc, rbuf, wbuf, len);
 	if (ret)
 		goto xfer_err;
@@ -2641,7 +2657,15 @@
 		slc->state = SLIM_CH_SUSPENDED;
 	}
 
-	ret = slim_allocbw(sb, &subframe, &clkgear);
+	/*
+	 * Controller can override default channel scheduling algorithm.
+	 * (e.g. if controller needs to use fixed channel scheduling based
+	 * on number of channels)
+	 */
+	if (ctrl->allocbw)
+		ret = ctrl->allocbw(sb, &subframe, &clkgear);
+	else
+		ret = slim_allocbw(sb, &subframe, &clkgear);
 
 	if (!ret) {
 		ret = slim_processtxn(ctrl, SLIM_MSG_DEST_BROADCAST,
diff --git a/drivers/spmi/Kconfig b/drivers/spmi/Kconfig
index 8724138..c32978e 100644
--- a/drivers/spmi/Kconfig
+++ b/drivers/spmi/Kconfig
@@ -21,7 +21,6 @@
 
 config MSM_QPNP_INT
 	depends on SPARSE_IRQ
-	depends on ARCH_MSM8974
 	depends on SPMI
 	depends on OF_SPMI
 	bool "MSM QPNP INT"
diff --git a/drivers/tty/smux_ctl.c b/drivers/tty/smux_ctl.c
index 7e0e6f8..c17495b 100644
--- a/drivers/tty/smux_ctl.c
+++ b/drivers/tty/smux_ctl.c
@@ -770,12 +770,13 @@
 	poll_wait(file, &devp->read_wait_queue, wait);
 
 	readable = smux_ctl_readable(devp->id);
-	if (readable < 0) {
+	if (readable > 0) {
+		mask = POLLIN | POLLRDNORM;
+	} else if ((readable < 0) && (readable != -ERESTARTSYS)) {
+		/* error case (non-signal) received */
 		pr_err(SMUX_CTL_MODULE_NAME ": %s err%d during poll for smuxctl%d\n",
 			__func__, readable, devp->id);
 		mask = POLLERR;
-	} else if (readable) {
-		mask = POLLIN | POLLRDNORM;
 	}
 
 	return mask;
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index a6eb335..46f21a7 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -80,6 +80,8 @@
 #ifdef CONFIG_TARGET_CORE
 #include "f_tcm.c"
 #endif
+#include "u_uac1.c"
+#include "f_uac1.c"
 
 MODULE_AUTHOR("Mike Lockwood");
 MODULE_DESCRIPTION("Android Composite USB Driver");
@@ -702,6 +704,18 @@
 	.init		= mbim_function_init,
 };
 
+/* PERIPHERAL AUDIO */
+static int audio_function_bind_config(struct android_usb_function *f,
+					  struct usb_configuration *c)
+{
+	return audio_bind_config(c);
+}
+
+static struct android_usb_function audio_function = {
+	.name		= "audio",
+	.bind_config	= audio_function_bind_config,
+};
+
 
 /* DIAG */
 static char diag_clients[32];	    /*enabled DIAG clients- "diag[,diag_mdm]" */
@@ -1506,6 +1520,7 @@
 static struct android_usb_function *supported_functions[] = {
 	&mbim_function,
 	&ecm_qc_function,
+	&audio_function,
 	&rmnet_smd_function,
 	&rmnet_sdio_function,
 	&rmnet_smd_sdio_function,
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 5b39336..b8b7f68 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -2575,7 +2575,7 @@
 	int retval = 0;
 	unsigned long flags;
 
-	trace("%p, %p", ep, desc);
+	trace("ep = %p, desc = %p", ep, desc);
 
 	if (ep == NULL || desc == NULL)
 		return -EINVAL;
@@ -2601,9 +2601,10 @@
 
 	if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
 		mEp->qh.ptr->cap |=  QH_IOS;
-	else if (mEp->type == USB_ENDPOINT_XFER_ISOC)
+	else if (mEp->type == USB_ENDPOINT_XFER_ISOC) {
 		mEp->qh.ptr->cap &= ~QH_MULT;
-	else
+		mEp->qh.ptr->cap |= BIT(30);
+	} else
 		mEp->qh.ptr->cap |= QH_ZLT;
 
 	mEp->qh.ptr->cap |=
diff --git a/drivers/usb/gadget/f_mbim.c b/drivers/usb/gadget/f_mbim.c
index 6883b78..7a84ca3 100644
--- a/drivers/usb/gadget/f_mbim.c
+++ b/drivers/usb/gadget/f_mbim.c
@@ -67,8 +67,8 @@
 };
 
 struct f_mbim {
-	struct usb_function function;
-	struct usb_composite_dev *cdev;
+	struct usb_function		function;
+	struct usb_composite_dev	*cdev;
 
 	atomic_t	online;
 	bool		is_open;
@@ -1255,6 +1255,20 @@
 	pr_info("mbim deactivated\n");
 }
 
+#define MBIM_ACTIVE_PORT	0
+
+static void mbim_suspend(struct usb_function *f)
+{
+	pr_info("mbim suspended\n");
+	bam_data_suspend(MBIM_ACTIVE_PORT);
+}
+
+static void mbim_resume(struct usb_function *f)
+{
+	pr_info("mbim resumed\n");
+	bam_data_resume(MBIM_ACTIVE_PORT);
+}
+
 /*---------------------- function driver setup/binding ---------------------*/
 
 static int
@@ -1288,6 +1302,8 @@
 	mbim_data_intf.bInterfaceNumber = status;
 	mbim_union_desc.bSlaveInterface0 = status;
 
+	mbim->bam_port.cdev = cdev;
+
 	status = -ENODEV;
 
 	/* allocate instance-specific endpoints */
@@ -1461,6 +1477,8 @@
 	mbim->function.get_alt = mbim_get_alt;
 	mbim->function.setup = mbim_setup;
 	mbim->function.disable = mbim_disable;
+	mbim->function.suspend = mbim_suspend;
+	mbim->function.resume = mbim_resume;
 
 	INIT_LIST_HEAD(&mbim->cpkt_req_q);
 	INIT_LIST_HEAD(&mbim->cpkt_resp_q);
diff --git a/drivers/usb/gadget/f_qc_ecm.c b/drivers/usb/gadget/f_qc_ecm.c
index 98a29ae..7fedaf6 100644
--- a/drivers/usb/gadget/f_qc_ecm.c
+++ b/drivers/usb/gadget/f_qc_ecm.c
@@ -305,7 +305,7 @@
 {
 	int ret;
 
-	ecm_qc_bam_port.func = dev->port.func;
+	ecm_qc_bam_port.cdev = dev->port.func.config->cdev;
 	ecm_qc_bam_port.in = dev->port.in_ep;
 	ecm_qc_bam_port.out = dev->port.out_ep;
 
diff --git a/drivers/usb/gadget/f_qc_rndis.c b/drivers/usb/gadget/f_qc_rndis.c
index a740d95..60b96fe 100644
--- a/drivers/usb/gadget/f_qc_rndis.c
+++ b/drivers/usb/gadget/f_qc_rndis.c
@@ -417,7 +417,7 @@
 {
 	int ret;
 
-	rndis_qc_bam_port.func = dev->port.func;
+	rndis_qc_bam_port.cdev = dev->port.func.config->cdev;
 	rndis_qc_bam_port.in = dev->port.in_ep;
 	rndis_qc_bam_port.out = dev->port.out_ep;
 
diff --git a/drivers/usb/gadget/f_uac1.c b/drivers/usb/gadget/f_uac1.c
index 1a5dcd5..b385592 100644
--- a/drivers/usb/gadget/f_uac1.c
+++ b/drivers/usb/gadget/f_uac1.c
@@ -1,6 +1,7 @@
 /*
  * f_audio.c -- USB Audio class function driver
-  *
+ *
+ * Copyright (c) 2012, The Linux Foundation. All rights reserved.
  * Copyright (C) 2008 Bryan Wu <cooloney@kernel.org>
  * Copyright (C) 2008 Analog Devices, Inc
  *
@@ -9,29 +10,21 @@
  * Licensed under the GPL-2 or later.
  */
 
+#ifdef pr_fmt
+#undef pr_fmt
+#endif
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
 #include <linux/slab.h>
 #include <linux/kernel.h>
 #include <linux/device.h>
 #include <linux/atomic.h>
 
+#include <sound/core.h>
+#include <sound/initval.h>
+
 #include "u_uac1.h"
 
-#define OUT_EP_MAX_PACKET_SIZE	200
-static int req_buf_size = OUT_EP_MAX_PACKET_SIZE;
-module_param(req_buf_size, int, S_IRUGO);
-MODULE_PARM_DESC(req_buf_size, "ISO OUT endpoint request buffer size");
-
-static int req_count = 256;
-module_param(req_count, int, S_IRUGO);
-MODULE_PARM_DESC(req_count, "ISO OUT endpoint request count");
-
-static int audio_buf_size = 48000;
-module_param(audio_buf_size, int, S_IRUGO);
-MODULE_PARM_DESC(audio_buf_size, "Audio buffer size");
-
-static int generic_set_cmd(struct usb_audio_control *con, u8 cmd, int value);
-static int generic_get_cmd(struct usb_audio_control *con, u8 cmd);
-
 /*
  * DESCRIPTORS ... most are static, but strings and full
  * configuration descriptors are built on demand.
@@ -39,180 +32,376 @@
 
 /*
  * We have two interfaces- AudioControl and AudioStreaming
- * TODO: only supcard playback currently
  */
-#define F_AUDIO_AC_INTERFACE	0
-#define F_AUDIO_AS_INTERFACE	1
-#define F_AUDIO_NUM_INTERFACES	2
+#define PLAYBACK_EP_MAX_PACKET_SIZE	32
+static int req_playback_buf_size = PLAYBACK_EP_MAX_PACKET_SIZE;
+module_param(req_playback_buf_size, int, S_IRUGO);
+MODULE_PARM_DESC(req_playback_buf_size, "ISO OUT endpoint (playback) request buffer size");
 
-/* B.3.1  Standard AC Interface Descriptor */
-static struct usb_interface_descriptor ac_interface_desc __initdata = {
-	.bLength =		USB_DT_INTERFACE_SIZE,
-	.bDescriptorType =	USB_DT_INTERFACE,
-	.bNumEndpoints =	0,
-	.bInterfaceClass =	USB_CLASS_AUDIO,
-	.bInterfaceSubClass =	USB_SUBCLASS_AUDIOCONTROL,
-};
+static int req_playback_count = 48;
+module_param(req_playback_count, int, S_IRUGO);
+MODULE_PARM_DESC(req_playback_count, "ISO OUT endpoint (playback) request count");
+
+static int audio_playback_buf_size = 256*32;
+module_param(audio_playback_buf_size, int, S_IRUGO);
+MODULE_PARM_DESC(audio_playback_buf_size, "Audio buffer size");
+
+#define CAPTURE_EP_MAX_PACKET_SIZE	32
+static int req_capture_buf_size = CAPTURE_EP_MAX_PACKET_SIZE;
+module_param(req_capture_buf_size, int, S_IRUGO);
+MODULE_PARM_DESC(req_capture_buf_size, "ISO IN endpoint (capture) request buffer size");
+
+static int req_capture_count = 48;
+module_param(req_capture_count, int, S_IRUGO);
+MODULE_PARM_DESC(req_capture_count, "ISO IN endpoint (capture) request count");
+
+static int audio_capture_buf_size = 256*32;
+module_param(audio_capture_buf_size, int, S_IRUGO);
+MODULE_PARM_DESC(audio_capture_buf_size, "Microphone Audio buffer size");
+
+static int generic_set_cmd(struct usb_audio_control *con, u8 cmd, int value);
+static int generic_get_cmd(struct usb_audio_control *con, u8 cmd);
 
 DECLARE_UAC_AC_HEADER_DESCRIPTOR(2);
+DECLARE_UAC_FORMAT_TYPE_I_DISCRETE_DESC(1);
 
-#define UAC_DT_AC_HEADER_LENGTH	UAC_DT_AC_HEADER_SIZE(F_AUDIO_NUM_INTERFACES)
-/* 1 input terminal, 1 output terminal and 1 feature unit */
-#define UAC_DT_TOTAL_LENGTH (UAC_DT_AC_HEADER_LENGTH + UAC_DT_INPUT_TERMINAL_SIZE \
-	+ UAC_DT_OUTPUT_TERMINAL_SIZE + UAC_DT_FEATURE_UNIT_SIZE(0))
-/* B.3.2  Class-Specific AC Interface Descriptor */
-static struct uac1_ac_header_descriptor_2 ac_header_desc = {
-	.bLength =		UAC_DT_AC_HEADER_LENGTH,
-	.bDescriptorType =	USB_DT_CS_INTERFACE,
-	.bDescriptorSubtype =	UAC_HEADER,
-	.bcdADC =		__constant_cpu_to_le16(0x0100),
-	.wTotalLength =		__constant_cpu_to_le16(UAC_DT_TOTAL_LENGTH),
-	.bInCollection =	F_AUDIO_NUM_INTERFACES,
-	.baInterfaceNr = {
-		[0] =		F_AUDIO_AC_INTERFACE,
-		[1] =		F_AUDIO_AS_INTERFACE,
-	}
+#define SPEAKER_INPUT_TERMINAL_ID	3
+#define SPEAKER_OUTPUT_TERMINAL_ID	4
+
+#define MICROPHONE_INPUT_TERMINAL_ID	1
+#define MICROPHONE_OUTPUT_TERMINAL_ID	2
+
+
+ /*
+  * We have two interfaces- AudioControl and AudioStreaming
+  */
+
+#define F_AUDIO_INTERFACE_MICROPHONE	2
+#define F_AUDIO_INTERFACE_SPEAKER	3
+#define F_AUDIO_NUM_INTERFACES		2
+
+ /* B.3.1  Standard AC Interface Descriptor */
+struct usb_interface_descriptor ac_interface_desc = {
+	.bLength		= USB_DT_INTERFACE_SIZE,
+	.bDescriptorType	= USB_DT_INTERFACE,
+	.bNumEndpoints		= 0,
+	.bInterfaceClass	= USB_CLASS_AUDIO,
+	.bInterfaceSubClass	= USB_SUBCLASS_AUDIOCONTROL,
 };
 
-#define INPUT_TERMINAL_ID	1
-static struct uac_input_terminal_descriptor input_terminal_desc = {
-	.bLength =		UAC_DT_INPUT_TERMINAL_SIZE,
-	.bDescriptorType =	USB_DT_CS_INTERFACE,
-	.bDescriptorSubtype =	UAC_INPUT_TERMINAL,
-	.bTerminalID =		INPUT_TERMINAL_ID,
-	.wTerminalType =	UAC_TERMINAL_STREAMING,
-	.bAssocTerminal =	0,
-	.wChannelConfig =	0x3,
-};
+#define TOTAL_LENGTH (                  \
+	UAC_DT_AC_HEADER_SIZE(2)      + \
+	UAC_DT_INPUT_TERMINAL_SIZE    + \
+	UAC_DT_OUTPUT_TERMINAL_SIZE   + \
+	UAC_DT_INPUT_TERMINAL_SIZE    + \
+	UAC_DT_OUTPUT_TERMINAL_SIZE     \
+	)
 
-DECLARE_UAC_FEATURE_UNIT_DESCRIPTOR(0);
-
-#define FEATURE_UNIT_ID		2
-static struct uac_feature_unit_descriptor_0 feature_unit_desc = {
-	.bLength		= UAC_DT_FEATURE_UNIT_SIZE(0),
+ /* B.3.2  Class-Specific AC Interface Descriptor */
+struct uac1_ac_header_descriptor_2 ac_header_desc = {
+	.bLength		= UAC_DT_AC_HEADER_SIZE(2),
 	.bDescriptorType	= USB_DT_CS_INTERFACE,
-	.bDescriptorSubtype	= UAC_FEATURE_UNIT,
-	.bUnitID		= FEATURE_UNIT_ID,
-	.bSourceID		= INPUT_TERMINAL_ID,
-	.bControlSize		= 2,
-	.bmaControls[0]		= (UAC_FU_MUTE | UAC_FU_VOLUME),
+	.bDescriptorSubtype	= UAC_HEADER,
+	.bcdADC			= __constant_cpu_to_le16(0x0100),
+	.wTotalLength		= __constant_cpu_to_le16(TOTAL_LENGTH),
+	.bInCollection		= F_AUDIO_NUM_INTERFACES,
+	/*.baInterfaceNr	= {
+					[0] = F_AUDIO_INTERFACE_MICROPHONE,
+					[1] = F_AUDIO_INTERFACE_SPEAKER,
+				  }
+	*/
 };
 
-static struct usb_audio_control mute_control = {
-	.list = LIST_HEAD_INIT(mute_control.list),
-	.name = "Mute Control",
+/*---------------------------------*/
+
+struct uac_input_terminal_descriptor speaker_input_terminal_desc = {
+	.bLength		= UAC_DT_INPUT_TERMINAL_SIZE,
+	.bDescriptorType	= USB_DT_CS_INTERFACE,
+	.bDescriptorSubtype	= UAC_INPUT_TERMINAL,
+	.bTerminalID		= SPEAKER_INPUT_TERMINAL_ID,
+	.wTerminalType		= UAC_TERMINAL_STREAMING,
+	.bAssocTerminal		= SPEAKER_OUTPUT_TERMINAL_ID,
+	.wChannelConfig		= 0x3,
+};
+
+struct uac1_output_terminal_descriptor speaker_output_terminal_desc = {
+	.bLength		= UAC_DT_OUTPUT_TERMINAL_SIZE,
+	.bDescriptorType	= USB_DT_CS_INTERFACE,
+	.bDescriptorSubtype	= UAC_OUTPUT_TERMINAL,
+	.bTerminalID		= SPEAKER_OUTPUT_TERMINAL_ID,
+	.wTerminalType		= UAC_OUTPUT_TERMINAL_SPEAKER,
+	.bAssocTerminal		= SPEAKER_INPUT_TERMINAL_ID,
+	.bSourceID		= SPEAKER_INPUT_TERMINAL_ID,
+};
+
+static struct usb_audio_control speaker_mute_control = {
+	.list = LIST_HEAD_INIT(speaker_mute_control.list),
+	.name = "Speaker Mute Control",
 	.type = UAC_FU_MUTE,
 	/* Todo: add real Mute control code */
 	.set = generic_set_cmd,
 	.get = generic_get_cmd,
 };
 
-static struct usb_audio_control volume_control = {
-	.list = LIST_HEAD_INIT(volume_control.list),
-	.name = "Volume Control",
+static struct usb_audio_control speaker_volume_control = {
+	.list = LIST_HEAD_INIT(speaker_volume_control.list),
+	.name = "Speaker Volume Control",
 	.type = UAC_FU_VOLUME,
 	/* Todo: add real Volume control code */
 	.set = generic_set_cmd,
 	.get = generic_get_cmd,
 };
 
-static struct usb_audio_control_selector feature_unit = {
-	.list = LIST_HEAD_INIT(feature_unit.list),
-	.id = FEATURE_UNIT_ID,
-	.name = "Mute & Volume Control",
-	.type = UAC_FEATURE_UNIT,
-	.desc = (struct usb_descriptor_header *)&feature_unit_desc,
+static struct usb_audio_control_selector speaker_fu_controls = {
+	.list = LIST_HEAD_INIT(speaker_fu_controls.list),
+	.name = "Speaker Function Unit Controls",
 };
 
-#define OUTPUT_TERMINAL_ID	3
-static struct uac1_output_terminal_descriptor output_terminal_desc = {
+static struct uac_input_terminal_descriptor microphone_input_terminal_desc = {
+	.bLength		= UAC_DT_INPUT_TERMINAL_SIZE,
+	.bDescriptorType	= USB_DT_CS_INTERFACE,
+	.bDescriptorSubtype	= UAC_INPUT_TERMINAL,
+	.bTerminalID		= MICROPHONE_INPUT_TERMINAL_ID,
+	.wTerminalType		= UAC_INPUT_TERMINAL_MICROPHONE,
+	.bAssocTerminal		= MICROPHONE_OUTPUT_TERMINAL_ID,
+	.bNrChannels		= 1,
+	.wChannelConfig		= 0x3,
+};
+
+static struct
+uac1_output_terminal_descriptor microphone_output_terminal_desc = {
 	.bLength		= UAC_DT_OUTPUT_TERMINAL_SIZE,
 	.bDescriptorType	= USB_DT_CS_INTERFACE,
 	.bDescriptorSubtype	= UAC_OUTPUT_TERMINAL,
-	.bTerminalID		= OUTPUT_TERMINAL_ID,
-	.wTerminalType		= UAC_OUTPUT_TERMINAL_SPEAKER,
-	.bAssocTerminal		= FEATURE_UNIT_ID,
-	.bSourceID		= FEATURE_UNIT_ID,
+	.bTerminalID		= MICROPHONE_OUTPUT_TERMINAL_ID,
+	.wTerminalType		= UAC_TERMINAL_STREAMING,
+	.bAssocTerminal		= MICROPHONE_INPUT_TERMINAL_ID,
+	.bSourceID		= MICROPHONE_INPUT_TERMINAL_ID,
 };
 
-/* B.4.1  Standard AS Interface Descriptor */
-static struct usb_interface_descriptor as_interface_alt_0_desc = {
-	.bLength =		USB_DT_INTERFACE_SIZE,
-	.bDescriptorType =	USB_DT_INTERFACE,
-	.bAlternateSetting =	0,
-	.bNumEndpoints =	0,
-	.bInterfaceClass =	USB_CLASS_AUDIO,
-	.bInterfaceSubClass =	USB_SUBCLASS_AUDIOSTREAMING,
+static struct usb_audio_control microphone_mute_control = {
+	.list = LIST_HEAD_INIT(microphone_mute_control.list),
+	.name = "Microphone Mute Control",
+	.type = UAC_FU_MUTE,
+	/* Todo: add real Mute control code */
+	.set = generic_set_cmd,
+	.get = generic_get_cmd,
 };
 
-static struct usb_interface_descriptor as_interface_alt_1_desc = {
-	.bLength =		USB_DT_INTERFACE_SIZE,
-	.bDescriptorType =	USB_DT_INTERFACE,
-	.bAlternateSetting =	1,
-	.bNumEndpoints =	1,
-	.bInterfaceClass =	USB_CLASS_AUDIO,
-	.bInterfaceSubClass =	USB_SUBCLASS_AUDIOSTREAMING,
+static struct usb_audio_control microphone_volume_control = {
+	.list = LIST_HEAD_INIT(microphone_volume_control.list),
+	.name = "Microphone Volume Control",
+	.type = UAC_FU_VOLUME,
+	/* Todo: add real Volume control code */
+	.set = generic_set_cmd,
+	.get = generic_get_cmd,
 };
 
-/* B.4.2  Class-Specific AS Interface Descriptor */
-static struct uac1_as_header_descriptor as_header_desc = {
-	.bLength =		UAC_DT_AS_HEADER_SIZE,
-	.bDescriptorType =	USB_DT_CS_INTERFACE,
-	.bDescriptorSubtype =	UAC_AS_GENERAL,
-	.bTerminalLink =	INPUT_TERMINAL_ID,
-	.bDelay =		1,
-	.wFormatTag =		UAC_FORMAT_TYPE_I_PCM,
+static struct usb_audio_control_selector microphone_fu_controls = {
+	.list = LIST_HEAD_INIT(microphone_fu_controls.list),
+	.name = "Microphone Feature Unit Controls",
 };
 
-DECLARE_UAC_FORMAT_TYPE_I_DISCRETE_DESC(1);
+/*---------------------------------*/
 
-static struct uac_format_type_i_discrete_descriptor_1 as_type_i_desc = {
-	.bLength =		UAC_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(1),
-	.bDescriptorType =	USB_DT_CS_INTERFACE,
-	.bDescriptorSubtype =	UAC_FORMAT_TYPE,
-	.bFormatType =		UAC_FORMAT_TYPE_I,
-	.bSubframeSize =	2,
-	.bBitResolution =	16,
-	.bSamFreqType =		1,
+ /* B.4.1  Standard AS Interface Descriptor */
+static struct usb_interface_descriptor speaker_as_interface_alt_0_desc = {
+	.bLength		= USB_DT_INTERFACE_SIZE,
+	.bDescriptorType	= USB_DT_INTERFACE,
+	.bAlternateSetting	= 0,
+	.bNumEndpoints		= 0,
+	.bInterfaceClass	= USB_CLASS_AUDIO,
+	.bInterfaceSubClass	= USB_SUBCLASS_AUDIOSTREAMING,
 };
 
-/* Standard ISO OUT Endpoint Descriptor */
-static struct usb_endpoint_descriptor as_out_ep_desc  = {
-	.bLength =		USB_DT_ENDPOINT_AUDIO_SIZE,
-	.bDescriptorType =	USB_DT_ENDPOINT,
-	.bEndpointAddress =	USB_DIR_OUT,
-	.bmAttributes =		USB_ENDPOINT_SYNC_ADAPTIVE
-				| USB_ENDPOINT_XFER_ISOC,
-	.wMaxPacketSize =	__constant_cpu_to_le16(OUT_EP_MAX_PACKET_SIZE),
-	.bInterval =		4,
+static struct usb_interface_descriptor speaker_as_interface_alt_1_desc = {
+	.bLength		= USB_DT_INTERFACE_SIZE,
+	.bDescriptorType	= USB_DT_INTERFACE,
+	.bAlternateSetting	= 1,
+	.bNumEndpoints		= 1,
+	.bInterfaceClass	= USB_CLASS_AUDIO,
+	.bInterfaceSubClass	= USB_SUBCLASS_AUDIOSTREAMING,
+};
+
+ /* B.4.2  Class-Specific AS Interface Descriptor */
+static struct uac1_as_header_descriptor speaker_as_header_desc = {
+	.bLength		= UAC_DT_AS_HEADER_SIZE,
+	.bDescriptorType	= USB_DT_CS_INTERFACE,
+	.bDescriptorSubtype	= UAC_AS_GENERAL,
+	.bTerminalLink		= SPEAKER_INPUT_TERMINAL_ID,
+	.bDelay			= 1,
+	.wFormatTag		= UAC_FORMAT_TYPE_I_PCM,
+};
+
+static struct uac_format_type_i_discrete_descriptor_1 speaker_as_type_i_desc = {
+	.bLength		= UAC_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(1),
+	.bDescriptorType	= USB_DT_CS_INTERFACE,
+	.bDescriptorSubtype	= UAC_FORMAT_TYPE,
+	.bFormatType		= UAC_FORMAT_TYPE_I,
+	.bSubframeSize		= 2,
+	.bBitResolution		= 16,
+	.bSamFreqType		= 1,
+};
+
+ /* Standard ISO OUT Endpoint Descriptor */
+static struct usb_endpoint_descriptor speaker_as_ep_out_desc = {
+	.bLength		= USB_DT_ENDPOINT_AUDIO_SIZE,
+	.bDescriptorType	= USB_DT_ENDPOINT,
+	.bEndpointAddress	= USB_DIR_OUT,
+	.bmAttributes		= USB_ENDPOINT_SYNC_ADAPTIVE |
+				  USB_ENDPOINT_XFER_ISOC,
+	.wMaxPacketSize		=
+		__constant_cpu_to_le16(PLAYBACK_EP_MAX_PACKET_SIZE),
+	.bInterval		= 4,
 };
 
 /* Class-specific AS ISO OUT Endpoint Descriptor */
-static struct uac_iso_endpoint_descriptor as_iso_out_desc __initdata = {
-	.bLength =		UAC_ISO_ENDPOINT_DESC_SIZE,
-	.bDescriptorType =	USB_DT_CS_ENDPOINT,
-	.bDescriptorSubtype =	UAC_EP_GENERAL,
-	.bmAttributes = 	1,
-	.bLockDelayUnits =	1,
-	.wLockDelay =		__constant_cpu_to_le16(1),
+static struct uac_iso_endpoint_descriptor speaker_as_iso_out_desc  = {
+	.bLength		= UAC_ISO_ENDPOINT_DESC_SIZE,
+	.bDescriptorType	= USB_DT_CS_ENDPOINT,
+	.bDescriptorSubtype	= UAC_EP_GENERAL,
+	.bmAttributes		= 1,
+	.bLockDelayUnits	= 1,
+	.wLockDelay		= __constant_cpu_to_le16(1),
 };
 
-static struct usb_descriptor_header *f_audio_desc[] __initdata = {
+static struct usb_audio_control speaker_sample_freq_control = {
+	.list = LIST_HEAD_INIT(speaker_sample_freq_control.list),
+	.name = "Speaker Sampling Frequency Control",
+	.type = UAC_EP_CS_ATTR_SAMPLE_RATE,
+	.set  = generic_set_cmd,
+	.get  = generic_get_cmd,
+};
+
+static struct usb_audio_control_selector speaker_as_iso_out = {
+	.list = LIST_HEAD_INIT(speaker_as_iso_out.list),
+	.name = "Speaker Iso-out Endpoint Control",
+	.type = UAC_EP_GENERAL,
+	.desc = (struct usb_descriptor_header *)&speaker_as_iso_out_desc,
+};
+
+/*---------------------------------*/
+
+/* B.4.1  Standard AS Interface Descriptor */
+static struct usb_interface_descriptor microphone_as_interface_alt_0_desc = {
+	.bLength		= USB_DT_INTERFACE_SIZE,
+	.bDescriptorType	= USB_DT_INTERFACE,
+	.bAlternateSetting	= 0,
+	.bNumEndpoints		= 0,
+	.bInterfaceClass	= USB_CLASS_AUDIO,
+	.bInterfaceSubClass	= USB_SUBCLASS_AUDIOSTREAMING,
+};
+
+static struct usb_interface_descriptor microphone_as_interface_alt_1_desc = {
+	.bLength		= USB_DT_INTERFACE_SIZE,
+	.bDescriptorType	= USB_DT_INTERFACE,
+	.bAlternateSetting	= 1,
+	.bNumEndpoints		= 1,
+	.bInterfaceClass	= USB_CLASS_AUDIO,
+	.bInterfaceSubClass	= USB_SUBCLASS_AUDIOSTREAMING,
+};
+
+/* B.4.2  Class-Specific AS Interface Descriptor */
+static struct uac1_as_header_descriptor microphone_as_header_desc = {
+	.bLength		= UAC_DT_AS_HEADER_SIZE,
+	.bDescriptorType	= USB_DT_CS_INTERFACE,
+	.bDescriptorSubtype	= UAC_AS_GENERAL,
+	.bTerminalLink		= MICROPHONE_OUTPUT_TERMINAL_ID,
+	.bDelay			= 1,
+	.wFormatTag		= UAC_FORMAT_TYPE_I_PCM,
+};
+
+static struct
+uac_format_type_i_discrete_descriptor_1 microphone_as_type_i_desc = {
+	.bLength		= UAC_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(1),
+	.bDescriptorType	= USB_DT_CS_INTERFACE,
+	.bDescriptorSubtype	= UAC_FORMAT_TYPE,
+	.bFormatType		= UAC_FORMAT_TYPE_I,
+	.bNrChannels		= 1,
+	.bSubframeSize		= 2,
+	.bBitResolution		= 16,
+	.bSamFreqType		= 1,
+};
+
+/* Standard ISO IN Endpoint Descriptor */
+static struct usb_endpoint_descriptor microphone_as_ep_in_desc = {
+	.bLength		= USB_DT_ENDPOINT_AUDIO_SIZE,
+	.bDescriptorType	= USB_DT_ENDPOINT,
+	.bEndpointAddress	= USB_DIR_IN,
+	.bmAttributes		=
+		USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
+	.wMaxPacketSize		=
+		__constant_cpu_to_le16(CAPTURE_EP_MAX_PACKET_SIZE),
+	.bInterval		= 4,
+};
+
+ /* Class-specific AS ISO OUT Endpoint Descriptor */
+static struct uac_iso_endpoint_descriptor microphone_as_iso_in_desc  = {
+	.bLength		= UAC_ISO_ENDPOINT_DESC_SIZE,
+	.bDescriptorType	= USB_DT_CS_ENDPOINT,
+	.bDescriptorSubtype	= UAC_EP_GENERAL,
+	.bmAttributes		= 1,
+	.bLockDelayUnits	= 1,
+	.wLockDelay		= __constant_cpu_to_le16(1),
+};
+
+static struct usb_audio_control microphone_sample_freq_control = {
+	.list = LIST_HEAD_INIT(microphone_sample_freq_control.list),
+	.name = "Microphone Sampling Frequency Control",
+	.type = UAC_EP_CS_ATTR_SAMPLE_RATE,
+	.set  = generic_set_cmd,
+	.get  = generic_get_cmd,
+};
+
+static struct usb_audio_control_selector microphone_as_iso_in = {
+	.list = LIST_HEAD_INIT(microphone_as_iso_in.list),
+	.name = "Microphone Iso-IN Endpoint Control",
+	.type = UAC_EP_GENERAL,
+	.desc = (struct usb_descriptor_header *)&microphone_as_iso_in_desc,
+};
+
+/*--------------------------------- */
+
+static struct usb_descriptor_header *f_audio_desc[]  = {
 	(struct usb_descriptor_header *)&ac_interface_desc,
 	(struct usb_descriptor_header *)&ac_header_desc,
 
-	(struct usb_descriptor_header *)&input_terminal_desc,
-	(struct usb_descriptor_header *)&output_terminal_desc,
-	(struct usb_descriptor_header *)&feature_unit_desc,
+	(struct usb_descriptor_header *)&microphone_input_terminal_desc,
+	(struct usb_descriptor_header *)&microphone_output_terminal_desc,
 
-	(struct usb_descriptor_header *)&as_interface_alt_0_desc,
-	(struct usb_descriptor_header *)&as_interface_alt_1_desc,
-	(struct usb_descriptor_header *)&as_header_desc,
+	(struct usb_descriptor_header *)&speaker_input_terminal_desc,
+	(struct usb_descriptor_header *)&speaker_output_terminal_desc,
 
-	(struct usb_descriptor_header *)&as_type_i_desc,
+	(struct usb_descriptor_header *)&microphone_as_interface_alt_0_desc,
+	(struct usb_descriptor_header *)&microphone_as_interface_alt_1_desc,
+	(struct usb_descriptor_header *)&microphone_as_header_desc,
+	(struct usb_descriptor_header *)&microphone_as_type_i_desc,
+	(struct usb_descriptor_header *)&microphone_as_ep_in_desc,
+	(struct usb_descriptor_header *)&microphone_as_iso_in_desc,
 
-	(struct usb_descriptor_header *)&as_out_ep_desc,
-	(struct usb_descriptor_header *)&as_iso_out_desc,
+	(struct usb_descriptor_header *)&speaker_as_interface_alt_0_desc,
+	(struct usb_descriptor_header *)&speaker_as_interface_alt_1_desc,
+	(struct usb_descriptor_header *)&speaker_as_header_desc,
+	(struct usb_descriptor_header *)&speaker_as_type_i_desc,
+	(struct usb_descriptor_header *)&speaker_as_ep_out_desc,
+	(struct usb_descriptor_header *)&speaker_as_iso_out_desc,
+
+	NULL,
+};
+
+/* string IDs are assigned dynamically */
+
+static struct usb_string audio_string_defs[] = {
+	{  } /* end of list */
+};
+
+static struct usb_gadget_strings audio_stringtab_dev = {
+	.language	= 0x0409,	/* en-us */
+	.strings	= audio_string_defs,
+};
+
+static struct usb_gadget_strings *audio_strings[] = {
+	&audio_stringtab_dev,
 	NULL,
 };
 
@@ -229,25 +418,32 @@
 
 static struct f_audio_buf *f_audio_buffer_alloc(int buf_size)
 {
-	struct f_audio_buf *copy_buf;
+	struct f_audio_buf *playback_copy_buf;
 
-	copy_buf = kzalloc(sizeof *copy_buf, GFP_ATOMIC);
-	if (!copy_buf)
-		return ERR_PTR(-ENOMEM);
-
-	copy_buf->buf = kzalloc(buf_size, GFP_ATOMIC);
-	if (!copy_buf->buf) {
-		kfree(copy_buf);
+	playback_copy_buf = kzalloc(sizeof *playback_copy_buf, GFP_ATOMIC);
+	if (!playback_copy_buf) {
+		pr_err("Failed to allocate playback_copy_buf");
 		return ERR_PTR(-ENOMEM);
 	}
 
-	return copy_buf;
+	playback_copy_buf->buf = kzalloc(buf_size, GFP_ATOMIC);
+	if (!playback_copy_buf->buf) {
+		pr_err("Failed to allocate playback_copy_buf buffer");
+		kfree(playback_copy_buf);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	return playback_copy_buf;
 }
 
 static void f_audio_buffer_free(struct f_audio_buf *audio_buf)
 {
-	kfree(audio_buf->buf);
-	kfree(audio_buf);
+	if (audio_buf) {
+		kfree(audio_buf->buf);
+		kfree(audio_buf);
+		audio_buf->buf = NULL;
+		audio_buf = NULL;
+	}
 }
 /*-------------------------------------------------------------------------*/
 
@@ -256,16 +452,24 @@
 
 	/* endpoints handle full and/or high speeds */
 	struct usb_ep			*out_ep;
+	struct usb_ep			*in_ep;
 
-	spinlock_t			lock;
-	struct f_audio_buf *copy_buf;
-	struct work_struct playback_work;
-	struct list_head play_queue;
+	spinlock_t			playback_lock;
+	struct f_audio_buf		*playback_copy_buf;
+	struct work_struct		playback_work;
+	struct list_head		play_queue;
+
+	spinlock_t			capture_lock;
+	struct f_audio_buf		*capture_copy_buf;
+	struct work_struct		capture_work;
+	struct list_head		capture_queue;
+	struct usb_request		*capture_req;
 
 	/* Control Set command */
-	struct list_head cs;
-	u8 set_cmd;
-	struct usb_audio_control *set_con;
+	struct list_head		fu_cs;
+	struct list_head		ep_cs;
+	u8				set_cmd;
+	struct usb_audio_control	*set_con;
 };
 
 static inline struct f_audio *func_to_audio(struct usb_function *f)
@@ -280,50 +484,126 @@
 	struct f_audio *audio = container_of(data, struct f_audio,
 					playback_work);
 	struct f_audio_buf *play_buf;
+	unsigned long flags;
+	int res = 0;
 
-	spin_lock_irq(&audio->lock);
+	spin_lock_irqsave(&audio->playback_lock, flags);
 	if (list_empty(&audio->play_queue)) {
-		spin_unlock_irq(&audio->lock);
+		pr_err("playback_buf is empty");
+		spin_unlock_irqrestore(&audio->playback_lock, flags);
 		return;
 	}
 	play_buf = list_first_entry(&audio->play_queue,
 			struct f_audio_buf, list);
 	list_del(&play_buf->list);
-	spin_unlock_irq(&audio->lock);
+	spin_unlock_irqrestore(&audio->playback_lock, flags);
 
-	u_audio_playback(&audio->card, play_buf->buf, play_buf->actual);
+	pr_debug("play_buf->actual = %d", play_buf->actual);
+
+	res = u_audio_playback(&audio->card, play_buf->buf, play_buf->actual);
+	if (res)
+		pr_err("copying failed");
+
 	f_audio_buffer_free(play_buf);
 }
 
-static int f_audio_out_ep_complete(struct usb_ep *ep, struct usb_request *req)
+static int
+f_audio_playback_ep_complete(struct usb_ep *ep, struct usb_request *req)
 {
 	struct f_audio *audio = req->context;
-	struct usb_composite_dev *cdev = audio->card.func.config->cdev;
-	struct f_audio_buf *copy_buf = audio->copy_buf;
+	struct f_audio_buf *copy_buf = audio->playback_copy_buf;
 	int err;
 
 	if (!copy_buf)
 		return -EINVAL;
 
 	/* Copy buffer is full, add it to the play_queue */
-	if (audio_buf_size - copy_buf->actual < req->actual) {
+	if (audio_playback_buf_size - copy_buf->actual < req->actual) {
+		pr_debug("audio_playback_buf_size %d - copy_buf->actual %d, req->actual %d",
+			audio_playback_buf_size, copy_buf->actual, req->actual);
 		list_add_tail(&copy_buf->list, &audio->play_queue);
 		schedule_work(&audio->playback_work);
-		copy_buf = f_audio_buffer_alloc(audio_buf_size);
-		if (IS_ERR(copy_buf))
+		copy_buf = f_audio_buffer_alloc(audio_playback_buf_size);
+		if (IS_ERR(copy_buf)) {
+			pr_err("Failed to allocate playback_copy_buf");
 			return -ENOMEM;
+		}
 	}
 
 	memcpy(copy_buf->buf + copy_buf->actual, req->buf, req->actual);
 	copy_buf->actual += req->actual;
-	audio->copy_buf = copy_buf;
+	audio->playback_copy_buf = copy_buf;
 
 	err = usb_ep_queue(ep, req, GFP_ATOMIC);
 	if (err)
-		ERROR(cdev, "%s queue req: %d\n", ep->name, err);
+		pr_err("Failed to queue %s req: err - %d\n", ep->name, err);
 
-	return 0;
+	return err;
+}
 
+static void f_audio_capture_work(struct work_struct *data)
+{
+	struct f_audio *audio =
+			container_of(data, struct f_audio, capture_work);
+	struct f_audio_buf *capture_buf;
+	unsigned long flags;
+	int res = 0;
+
+	capture_buf = f_audio_buffer_alloc(audio_capture_buf_size);
+	if (capture_buf <= 0) {
+		pr_err("%s: buffer alloc failed\n", __func__);
+		return;
+	}
+
+	res = u_audio_capture(&audio->card, capture_buf->buf,
+			audio_capture_buf_size);
+	if (res)
+		pr_err("copying failed");
+
+	pr_debug("Queue capture packet: size %d", audio_capture_buf_size);
+	spin_lock_irqsave(&audio->capture_lock, flags);
+	list_add_tail(&capture_buf->list, &audio->capture_queue);
+	spin_unlock_irqrestore(&audio->capture_lock, flags);
+}
+
+static int
+f_audio_capture_ep_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct f_audio *audio = req->context;
+	struct f_audio_buf *copy_buf = audio->capture_copy_buf;
+	unsigned long flags;
+	int err = 0;
+
+	if (copy_buf == 0) {
+		pr_debug("copy_buf == 0");
+		spin_lock_irqsave(&audio->capture_lock, flags);
+		if (list_empty(&audio->capture_queue)) {
+			spin_unlock_irqrestore(&audio->capture_lock, flags);
+			schedule_work(&audio->capture_work);
+			goto done;
+		}
+		copy_buf = list_first_entry(&audio->capture_queue,
+						struct f_audio_buf, list);
+		list_del(&copy_buf->list);
+		audio->capture_copy_buf = copy_buf;
+		spin_unlock_irqrestore(&audio->capture_lock, flags);
+	}
+
+	pr_debug("Copy %d bytes", req->actual);
+	memcpy(req->buf, copy_buf->buf + copy_buf->actual, req->actual);
+	copy_buf->actual += req->actual;
+
+	if (audio_capture_buf_size - copy_buf->actual < req->actual) {
+		f_audio_buffer_free(copy_buf);
+		audio->capture_copy_buf = 0;
+		schedule_work(&audio->capture_work);
+	}
+done:
+	err = usb_ep_queue(ep, req, GFP_ATOMIC);
+	if (err)
+		pr_err("Failed to queue %s req: err - %d\n", ep->name, err);
+
+	return err;
 }
 
 static void f_audio_complete(struct usb_ep *ep, struct usb_request *req)
@@ -331,14 +611,14 @@
 	struct f_audio *audio = req->context;
 	int status = req->status;
 	u32 data = 0;
-	struct usb_ep *out_ep = audio->out_ep;
 
 	switch (status) {
-
-	case 0:				/* normal completion? */
-		if (ep == out_ep)
-			f_audio_out_ep_complete(ep, req);
-		else if (audio->set_con) {
+	case 0:	/* normal completion? */
+		if (ep == audio->out_ep) {
+			f_audio_playback_ep_complete(ep, req);
+		} else if (ep == audio->in_ep) {
+			f_audio_capture_ep_complete(ep, req);
+		} else if (audio->set_con) {
 			memcpy(&data, req->buf, req->length);
 			audio->set_con->set(audio->set_con, audio->set_cmd,
 					le16_to_cpu(data));
@@ -346,6 +626,7 @@
 		}
 		break;
 	default:
+		pr_err("Failed completion: status %d", status);
 		break;
 	}
 }
@@ -364,10 +645,10 @@
 	struct usb_audio_control_selector *cs;
 	struct usb_audio_control *con;
 
-	DBG(cdev, "bRequest 0x%x, w_value 0x%04x, len %d, entity %d\n",
+	pr_debug("bRequest 0x%x, w_value 0x%04x, len %d, entity %d\n",
 			ctrl->bRequest, w_value, len, id);
 
-	list_for_each_entry(cs, &audio->cs, list) {
+	list_for_each_entry(cs, &audio->fu_cs, list) {
 		if (cs->id == id) {
 			list_for_each_entry(con, &cs->control, list) {
 				if (con->type == con_sel) {
@@ -401,10 +682,10 @@
 	struct usb_audio_control_selector *cs;
 	struct usb_audio_control *con;
 
-	DBG(cdev, "bRequest 0x%x, w_value 0x%04x, len %d, entity %d\n",
+	pr_debug("bRequest 0x%x, w_value 0x%04x, len %d, entity %d\n",
 			ctrl->bRequest, w_value, len, id);
 
-	list_for_each_entry(cs, &audio->cs, list) {
+	list_for_each_entry(cs, &audio->fu_cs, list) {
 		if (cs->id == id) {
 			list_for_each_entry(con, &cs->control, list) {
 				if (con->type == con_sel && con->get) {
@@ -423,36 +704,68 @@
 	return len;
 }
 
+static void audio_set_endpoint_complete(struct usb_ep *ep,
+					struct usb_request *req)
+{
+	struct f_audio *audio = req->context;
+	u32 data = 0;
+
+	if (req->status == 0 && audio->set_con) {
+		memcpy(&data, req->buf, req->length);
+		audio->set_con->set(audio->set_con, audio->set_cmd,
+					le32_to_cpu(data));
+		audio->set_con = NULL;
+	}
+}
+
 static int audio_set_endpoint_req(struct usb_function *f,
 		const struct usb_ctrlrequest *ctrl)
 {
+	int	value = -EOPNOTSUPP;
+	u16	ep = le16_to_cpu(ctrl->wIndex);
+	u16	len = le16_to_cpu(ctrl->wLength);
+	u16	w_value = le16_to_cpu(ctrl->wValue);
+
+	struct f_audio *audio = func_to_audio(f);
 	struct usb_composite_dev *cdev = f->config->cdev;
-	int			value = -EOPNOTSUPP;
-	u16			ep = le16_to_cpu(ctrl->wIndex);
-	u16			len = le16_to_cpu(ctrl->wLength);
-	u16			w_value = le16_to_cpu(ctrl->wValue);
+	struct usb_request *req = cdev->req;
+	struct usb_audio_control_selector *cs;
+	struct usb_audio_control *con;
 
-	DBG(cdev, "bRequest 0x%x, w_value 0x%04x, len %d, endpoint %d\n",
-			ctrl->bRequest, w_value, len, ep);
+	u8	epnum   = ep & ~0x80;
+	u8	con_sel = (w_value >> 8) & 0xFF;
+	u8	cmd     = (ctrl->bRequest & 0x0F);
 
-	switch (ctrl->bRequest) {
-	case UAC_SET_CUR:
-		value = len;
-		break;
+	pr_debug("bRequest 0x%x, w_value 0x%04x, len %d, endp %d, epnum %d\n",
+			ctrl->bRequest, w_value, len, ep, epnum);
 
-	case UAC_SET_MIN:
-		break;
+	list_for_each_entry(cs, &audio->ep_cs, list) {
+		if (cs->id != epnum)
+			continue;
 
-	case UAC_SET_MAX:
-		break;
+		list_for_each_entry(con, &cs->control, list) {
+			if (con->type != con_sel)
+				continue;
 
-	case UAC_SET_RES:
-		break;
-
-	case UAC_SET_MEM:
-		break;
-
-	default:
+			switch (cmd) {
+			case UAC__CUR:
+			case UAC__MIN:
+			case UAC__MAX:
+			case UAC__RES:
+				audio->set_con = con;
+				audio->set_cmd = cmd;
+				req->context   = audio;
+				req->complete  = audio_set_endpoint_complete;
+				value = len;
+				break;
+			case UAC__MEM:
+				break;
+			default:
+				pr_err("Unknown command");
+				break;
+			}
+			break;
+		}
 		break;
 	}
 
@@ -462,25 +775,48 @@
 static int audio_get_endpoint_req(struct usb_function *f,
 		const struct usb_ctrlrequest *ctrl)
 {
+	struct f_audio *audio = func_to_audio(f);
 	struct usb_composite_dev *cdev = f->config->cdev;
-	int value = -EOPNOTSUPP;
-	u8 ep = ((le16_to_cpu(ctrl->wIndex) >> 8) & 0xFF);
-	u16 len = le16_to_cpu(ctrl->wLength);
-	u16 w_value = le16_to_cpu(ctrl->wValue);
+	struct usb_request *req = cdev->req;
+	struct usb_audio_control_selector *cs;
+	struct usb_audio_control *con;
+	int data;
 
-	DBG(cdev, "bRequest 0x%x, w_value 0x%04x, len %d, endpoint %d\n",
+	int value   = -EOPNOTSUPP;
+	u8  ep      = (le16_to_cpu(ctrl->wIndex) & 0x7F);
+	u8  epnum   = ep & ~0x80;
+	u16 len     = le16_to_cpu(ctrl->wLength);
+	u16 w_value = le16_to_cpu(ctrl->wValue);
+	u8  con_sel = (w_value >> 8) & 0xFF;
+	u8  cmd     = (ctrl->bRequest & 0x0F);
+
+	pr_debug("bRequest 0x%x, w_value 0x%04x, len %d, ep %d\n",
 			ctrl->bRequest, w_value, len, ep);
 
-	switch (ctrl->bRequest) {
-	case UAC_GET_CUR:
-	case UAC_GET_MIN:
-	case UAC_GET_MAX:
-	case UAC_GET_RES:
-		value = len;
-		break;
-	case UAC_GET_MEM:
-		break;
-	default:
+	list_for_each_entry(cs, &audio->ep_cs, list) {
+		if (cs->id != epnum)
+			continue;
+
+		list_for_each_entry(con, &cs->control, list) {
+			if (con->type != con_sel)
+				continue;
+
+			switch (cmd) {
+			case UAC__CUR:
+			case UAC__MIN:
+			case UAC__MAX:
+			case UAC__RES:
+				data = cpu_to_le32(generic_get_cmd(con, cmd));
+				memcpy(req->buf, &data, len);
+				value = len;
+				break;
+			case UAC__MEM:
+				break;
+			default:
+				break;
+			}
+			break;
+		}
 		break;
 	}
 
@@ -500,39 +836,47 @@
 	/* composite driver infrastructure handles everything; interface
 	 * activation uses set_alt().
 	 */
+
 	switch (ctrl->bRequestType) {
 	case USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE:
+		pr_debug("USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE");
 		value = audio_set_intf_req(f, ctrl);
 		break;
 
 	case USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE:
+		pr_debug("USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE");
 		value = audio_get_intf_req(f, ctrl);
 		break;
 
 	case USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT:
+		pr_debug("USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT");
 		value = audio_set_endpoint_req(f, ctrl);
 		break;
 
 	case USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT:
+		pr_debug("USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT");
 		value = audio_get_endpoint_req(f, ctrl);
 		break;
 
 	default:
-		ERROR(cdev, "invalid control req%02x.%02x v%04x i%04x l%d\n",
+		pr_err("Unknown control request %02x.%02x v%04x i%04x l%d\n",
 			ctrl->bRequestType, ctrl->bRequest,
 			w_value, w_index, w_length);
+
 	}
 
 	/* respond with data transfer or status phase? */
 	if (value >= 0) {
-		DBG(cdev, "audio req%02x.%02x v%04x i%04x l%d\n",
+		pr_debug("audio req %02x.%02x v%04x i%04x l%d\n",
 			ctrl->bRequestType, ctrl->bRequest,
 			w_value, w_index, w_length);
-		req->zero = 0;
+		req->zero = 1;
 		req->length = value;
 		value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
 		if (value < 0)
-			ERROR(cdev, "audio response on err %d\n", value);
+			pr_err("audio response failed on err %d\n", value);
+	} else {
+		pr_err("STALL\n");
 	}
 
 	/* device either stalls (value < 0) or reports success */
@@ -542,55 +886,114 @@
 static int f_audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 {
 	struct f_audio		*audio = func_to_audio(f);
-	struct usb_composite_dev *cdev = f->config->cdev;
-	struct usb_ep *out_ep = audio->out_ep;
-	struct usb_request *req;
+	struct usb_ep		*out_ep = audio->out_ep;
+	struct usb_ep		*in_ep = audio->in_ep;
+	struct usb_request	*req;
+	unsigned long flags;
 	int i = 0, err = 0;
 
-	DBG(cdev, "intf %d, alt %d\n", intf, alt);
+	pr_debug("intf %d, alt %d\n", intf, alt);
 
-	if (intf == 1) {
+	if (intf == ac_header_desc.baInterfaceNr[0]) {
 		if (alt == 1) {
-			usb_ep_enable(out_ep);
-			out_ep->driver_data = audio;
-			audio->copy_buf = f_audio_buffer_alloc(audio_buf_size);
-			if (IS_ERR(audio->copy_buf))
+			err = usb_ep_enable(in_ep);
+			if (err) {
+				pr_err("Failed to enable capture ep");
+				return err;
+			}
+			in_ep->driver_data = audio;
+			audio->capture_copy_buf = 0;
+
+			/* Allocate a write buffer */
+			req = usb_ep_alloc_request(in_ep, GFP_ATOMIC);
+			if (!req) {
+				pr_err("request allocation failed\n");
 				return -ENOMEM;
+			}
+			req->buf = kzalloc(req_capture_buf_size,
+						GFP_ATOMIC);
+			if (!req->buf) {
+				pr_err("request buffer allocation failed\n");
+				return -ENOMEM;
+			}
+
+			req->length = req_capture_buf_size;
+			req->context = audio;
+			req->complete =	f_audio_complete;
+			audio->capture_req = req;
+			err = usb_ep_queue(in_ep, req, GFP_ATOMIC);
+			if (err)
+				pr_err("Failed to queue %s req: err %d\n",
+				 in_ep->name, err);
+			schedule_work(&audio->capture_work);
+		} else {
+			struct f_audio_buf *capture_buf;
+			spin_lock_irqsave(&audio->capture_lock, flags);
+			while (!list_empty(&audio->capture_queue)) {
+				capture_buf =
+					list_first_entry(
+						&audio->capture_queue,
+						 struct f_audio_buf,
+						 list);
+				list_del(&capture_buf->list);
+				f_audio_buffer_free(capture_buf);
+			}
+			spin_unlock_irqrestore(&audio->capture_lock, flags);
+		}
+	} else if (intf == ac_header_desc.baInterfaceNr[1]) {
+		if (alt == 1) {
+			err = usb_ep_enable(out_ep);
+			if (err) {
+				pr_err("Failed to enable playback ep");
+				return err;
+			}
+			out_ep->driver_data = audio;
+			audio->playback_copy_buf =
+				f_audio_buffer_alloc(audio_playback_buf_size);
+			if (IS_ERR(audio->playback_copy_buf)) {
+				pr_err("Failed to allocate playback_copy_buf");
+				return -ENOMEM;
+			}
 
 			/*
 			 * allocate a bunch of read buffers
 			 * and queue them all at once.
 			 */
-			for (i = 0; i < req_count && err == 0; i++) {
+			for (i = 0; i < req_playback_count && err == 0; i++) {
 				req = usb_ep_alloc_request(out_ep, GFP_ATOMIC);
-				if (req) {
-					req->buf = kzalloc(req_buf_size,
-							GFP_ATOMIC);
-					if (req->buf) {
-						req->length = req_buf_size;
-						req->context = audio;
-						req->complete =
-							f_audio_complete;
-						err = usb_ep_queue(out_ep,
-							req, GFP_ATOMIC);
-						if (err)
-							ERROR(cdev,
-							"%s queue req: %d\n",
-							out_ep->name, err);
-					} else
-						err = -ENOMEM;
-				} else
-					err = -ENOMEM;
+				if (!req) {
+					pr_err("request allocation failed\n");
+					return -ENOMEM;
+				}
+				req->buf = kzalloc(req_playback_buf_size,
+						GFP_ATOMIC);
+				if (!req->buf) {
+					pr_err("request buffer allocation failed\n");
+					return -ENOMEM;
+				}
+				req->length = req_playback_buf_size;
+				req->context = audio;
+				req->complete =	f_audio_complete;
+				err = usb_ep_queue(out_ep, req, GFP_ATOMIC);
+				if (err)
+					pr_err("Failed to queue %s queue req: err %d\n",
+						out_ep->name, err);
 			}
-
+			pr_debug("Allocated %d requests\n", req_playback_count);
 		} else {
-			struct f_audio_buf *copy_buf = audio->copy_buf;
-			if (copy_buf) {
-				list_add_tail(&copy_buf->list,
+			struct f_audio_buf *playback_copy_buf =
+				audio->playback_copy_buf;
+			if (playback_copy_buf) {
+				pr_err("Schedule playback_work");
+				list_add_tail(&playback_copy_buf->list,
 						&audio->play_queue);
 				schedule_work(&audio->playback_work);
+			} else {
+				pr_err("playback_buf is empty. Stop.");
 			}
 		}
+	} else {
+		pr_err("Interface %d. Do nothing. Return %d\n", intf, err);
 	}
 
 	return err;
@@ -598,7 +1001,7 @@
 
 static void f_audio_disable(struct usb_function *f)
 {
-	return;
+	u_audio_clear();
 }
 
 /*-------------------------------------------------------------------------*/
@@ -610,12 +1013,23 @@
 	int rate;
 
 	/* Set channel numbers */
-	input_terminal_desc.bNrChannels = u_audio_get_playback_channels(card);
-	as_type_i_desc.bNrChannels = u_audio_get_playback_channels(card);
+	speaker_input_terminal_desc.bNrChannels =
+			u_audio_get_playback_channels(card);
+	speaker_as_type_i_desc.bNrChannels =
+			u_audio_get_playback_channels(card);
+
+	microphone_input_terminal_desc.bNrChannels =
+			u_audio_get_capture_channels(card);
+	microphone_as_type_i_desc.bNrChannels =
+			u_audio_get_capture_channels(card);
 
 	/* Set sample rates */
 	rate = u_audio_get_playback_rate(card);
-	sam_freq = as_type_i_desc.tSamFreq[0];
+	sam_freq = speaker_as_type_i_desc.tSamFreq[0];
+	memcpy(sam_freq, &rate, 3);
+
+	rate = u_audio_get_capture_rate(card);
+	sam_freq = microphone_as_type_i_desc.tSamFreq[0];
 	memcpy(sam_freq, &rate, 3);
 
 	/* Todo: Set Sample bits and other parameters */
@@ -624,64 +1038,101 @@
 }
 
 /* audio function driver setup/binding */
-static int __init
+static int
 f_audio_bind(struct usb_configuration *c, struct usb_function *f)
 {
 	struct usb_composite_dev *cdev = c->cdev;
 	struct f_audio		*audio = func_to_audio(f);
 	int			status;
 	struct usb_ep		*ep;
+	u8			epaddr;
+
 
 	f_audio_build_desc(audio);
 
 	/* allocate instance-specific interface IDs, and patch descriptors */
 	status = usb_interface_id(c, f);
-	if (status < 0)
+	if (status < 0) {
+		pr_err("%s: failed to allocate desc interface", __func__);
 		goto fail;
+	}
 	ac_interface_desc.bInterfaceNumber = status;
 
+	status = -ENOMEM;
+
 	status = usb_interface_id(c, f);
-	if (status < 0)
+	if (status < 0) {
+		pr_err("%s: failed to allocate alt interface", __func__);
 		goto fail;
-	as_interface_alt_0_desc.bInterfaceNumber = status;
-	as_interface_alt_1_desc.bInterfaceNumber = status;
+	}
+	microphone_as_interface_alt_0_desc.bInterfaceNumber = status;
+	microphone_as_interface_alt_1_desc.bInterfaceNumber = status;
+	ac_header_desc.baInterfaceNr[0] = status;
+
+	status = -ENODEV;
+
+	status = usb_interface_id(c, f);
+	if (status < 0) {
+		pr_err("%s: failed to allocate alt interface", __func__);
+		goto fail;
+	}
+	speaker_as_interface_alt_0_desc.bInterfaceNumber = status;
+	speaker_as_interface_alt_1_desc.bInterfaceNumber = status;
+	ac_header_desc.baInterfaceNr[1] = status;
 
 	status = -ENODEV;
 
 	/* allocate instance-specific endpoints */
-	ep = usb_ep_autoconfig(cdev->gadget, &as_out_ep_desc);
-	if (!ep)
+	ep = usb_ep_autoconfig(cdev->gadget, &microphone_as_ep_in_desc);
+	if (!ep) {
+		pr_err("%s: failed to autoconfig in endpoint", __func__);
 		goto fail;
-	audio->out_ep = ep;
-	audio->out_ep->desc = &as_out_ep_desc;
-	ep->driver_data = cdev;	/* claim */
+	}
+	audio->in_ep = ep;
+	ep->desc = &microphone_as_ep_in_desc;
+	ep->driver_data = cdev;
 
 	status = -ENOMEM;
 
-	/* copy descriptors, and track endpoint copies */
-	f->descriptors = usb_copy_descriptors(f_audio_desc);
+	ep = usb_ep_autoconfig(cdev->gadget, &speaker_as_ep_out_desc);
+	if (!ep) {
+		pr_err("%s: failed to autoconfig out endpoint", __func__);
+		goto fail;
+	}
+	audio->out_ep = ep;
+	ep->desc = &speaker_as_ep_out_desc;
+	ep->driver_data = cdev;
 
-	/*
-	 * support all relevant hardware speeds... we expect that when
+	/* associate bEndpointAddress with usb_function */
+	epaddr = microphone_as_ep_in_desc.bEndpointAddress & ~USB_DIR_IN;
+	microphone_as_iso_in.id = epaddr;
+
+	epaddr = speaker_as_ep_out_desc.bEndpointAddress & ~USB_DIR_IN;
+	speaker_as_iso_out.id = epaddr;
+
+	/* support all relevant hardware speeds. we expect that when
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * both speeds
 	 */
+
+	/* copy descriptors, and track endpoint copies */
 	if (gadget_is_dualspeed(c->cdev->gadget)) {
 		c->highspeed = true;
 		f->hs_descriptors = usb_copy_descriptors(f_audio_desc);
+	} else {
+		f->descriptors = usb_copy_descriptors(f_audio_desc);
 	}
 
 	return 0;
 
 fail:
-
 	return status;
 }
 
 static void
 f_audio_unbind(struct usb_configuration *c, struct usb_function *f)
 {
-	struct f_audio		*audio = func_to_audio(f);
+	struct f_audio *audio = func_to_audio(f);
 
 	usb_free_descriptors(f->descriptors);
 	usb_free_descriptors(f->hs_descriptors);
@@ -703,31 +1154,58 @@
 }
 
 /* Todo: add more control selecotor dynamically */
-int __init control_selector_init(struct f_audio *audio)
+int  control_selector_init(struct f_audio *audio)
 {
-	INIT_LIST_HEAD(&audio->cs);
-	list_add(&feature_unit.list, &audio->cs);
+	INIT_LIST_HEAD(&audio->fu_cs);
+	list_add(&microphone_fu_controls.list, &audio->fu_cs);
+	list_add(&speaker_fu_controls.list, &audio->fu_cs);
 
-	INIT_LIST_HEAD(&feature_unit.control);
-	list_add(&mute_control.list, &feature_unit.control);
-	list_add(&volume_control.list, &feature_unit.control);
+	INIT_LIST_HEAD(&microphone_fu_controls.control);
+	list_add(&microphone_mute_control.list,
+		 &microphone_fu_controls.control);
+	list_add(&microphone_volume_control.list,
+		 &microphone_fu_controls.control);
 
-	volume_control.data[UAC__CUR] = 0xffc0;
-	volume_control.data[UAC__MIN] = 0xe3a0;
-	volume_control.data[UAC__MAX] = 0xfff0;
-	volume_control.data[UAC__RES] = 0x0030;
+	INIT_LIST_HEAD(&speaker_fu_controls.control);
+	list_add(&speaker_mute_control.list,
+		 &speaker_fu_controls.control);
+	list_add(&speaker_volume_control.list,
+		 &speaker_fu_controls.control);
+
+	microphone_volume_control.data[UAC__CUR] = 0xffc0;
+	microphone_volume_control.data[UAC__MIN] = 0xe3a0;
+	microphone_volume_control.data[UAC__MAX] = 0xfff0;
+	microphone_volume_control.data[UAC__RES] = 0x0030;
+
+	speaker_volume_control.data[UAC__CUR] = 0xffc0;
+	speaker_volume_control.data[UAC__MIN] = 0xe3a0;
+	speaker_volume_control.data[UAC__MAX] = 0xfff0;
+	speaker_volume_control.data[UAC__RES] = 0x0030;
+
+	INIT_LIST_HEAD(&audio->ep_cs);
+	list_add(&speaker_as_iso_out.list, &audio->ep_cs);
+	list_add(&microphone_as_iso_in.list, &audio->ep_cs);
+
+	INIT_LIST_HEAD(&microphone_as_iso_in.control);
+	list_add(&microphone_sample_freq_control.list,
+		 &microphone_as_iso_in.control);
+
+	INIT_LIST_HEAD(&speaker_as_iso_out.control);
+	list_add(&speaker_sample_freq_control.list,
+		 &speaker_as_iso_out.control);
 
 	return 0;
+
 }
 
 /**
  * audio_bind_config - add USB audio function to a configuration
- * @c: the configuration to supcard the USB audio function
+ * @c: the configuration to support the USB audio function
  * Context: single threaded during gadget setup
  *
  * Returns zero on success, else negative errno.
  */
-int __init audio_bind_config(struct usb_configuration *c)
+int audio_bind_config(struct usb_configuration *c)
 {
 	struct f_audio *audio;
 	int status;
@@ -737,17 +1215,15 @@
 	if (!audio)
 		return -ENOMEM;
 
-	audio->card.func.name = "g_audio";
 	audio->card.gadget = c->cdev->gadget;
 
 	INIT_LIST_HEAD(&audio->play_queue);
-	spin_lock_init(&audio->lock);
+	spin_lock_init(&audio->playback_lock);
 
-	/* set up ASLA audio devices */
-	status = gaudio_setup(&audio->card);
-	if (status < 0)
-		goto setup_fail;
+	INIT_LIST_HEAD(&audio->capture_queue);
+	spin_lock_init(&audio->capture_lock);
 
+	audio->card.func.name = "audio";
 	audio->card.func.strings = audio_strings;
 	audio->card.func.bind = f_audio_bind;
 	audio->card.func.unbind = f_audio_unbind;
@@ -756,15 +1232,20 @@
 	audio->card.func.disable = f_audio_disable;
 
 	control_selector_init(audio);
-
 	INIT_WORK(&audio->playback_work, f_audio_playback_work);
+	INIT_WORK(&audio->capture_work, f_audio_capture_work);
 
-	status = usb_add_function(c, &audio->card.func);
-	if (status)
+	/* set up ASLA audio devices */
+	status = gaudio_setup(&audio->card);
+	if (status < 0)
 		goto add_fail;
 
-	INFO(c->cdev, "audio_buf_size %d, req_buf_size %d, req_count %d\n",
-		audio_buf_size, req_buf_size, req_count);
+	status = usb_add_function(c, &audio->card.func);
+	if (status) {
+		pr_err("%s: Failed to add usb audio function, err = %d",
+			__func__, status);
+		goto setup_fail;
+	}
 
 	return status;
 
diff --git a/drivers/usb/gadget/u_bam_data.c b/drivers/usb/gadget/u_bam_data.c
index a105f5d..32f683e 100644
--- a/drivers/usb/gadget/u_bam_data.c
+++ b/drivers/usb/gadget/u_bam_data.c
@@ -35,7 +35,7 @@
 #define MSM_VENDOR_ID			BIT(16)
 
 struct data_port {
-	struct usb_function		func;
+	struct usb_composite_dev	*cdev;
 	struct usb_ep			*in;
 	struct usb_ep			*out;
 };
@@ -326,3 +326,54 @@
 	return ret;
 }
 
+static int bam_data_wake_cb(void *param)
+{
+	struct bam_data_port *port = (struct bam_data_port *)param;
+	struct data_port *d_port = port->port_usb;
+
+	pr_info("%s: woken up by peer\n", __func__);
+
+	if (!d_port) {
+		pr_err("FAILED: d_port == NULL");
+		return -ENODEV;
+	}
+
+	if (!d_port->cdev) {
+		pr_err("FAILED: d_port->cdev == NULL");
+		return -ENODEV;
+	}
+
+	if (!d_port->cdev->gadget) {
+		pr_err("FAILED: d_port->cdev->gadget == NULL");
+		return -ENODEV;
+	}
+
+	return usb_gadget_wakeup(d_port->cdev->gadget);
+}
+
+void bam_data_suspend(u8 port_num)
+{
+
+	struct bam_data_port	*port;
+	struct bam_data_ch_info *d;
+
+	port = bam2bam_data_ports[port_num];
+	d = &port->data_ch;
+
+	pr_info("%s: suspended port %d\n", __func__, port_num);
+	usb_bam_register_wake_cb(d->connection_idx, bam_data_wake_cb, port);
+}
+
+void bam_data_resume(u8 port_num)
+{
+
+	struct bam_data_port	*port;
+	struct bam_data_ch_info *d;
+
+	port = bam2bam_data_ports[port_num];
+	d = &port->data_ch;
+
+	pr_info("%s: resumed port %d\n", __func__, port_num);
+	usb_bam_register_wake_cb(d->connection_idx, NULL, NULL);
+}
+
diff --git a/drivers/usb/gadget/u_data_hsic.c b/drivers/usb/gadget/u_data_hsic.c
index 89d2887..746c041 100644
--- a/drivers/usb/gadget/u_data_hsic.c
+++ b/drivers/usb/gadget/u_data_hsic.c
@@ -220,6 +220,7 @@
 		req->context = skb;
 		req->buf = skb->data;
 		req->length = skb->len;
+		req->zero = 1;
 
 		port->n_tx_req_queued++;
 		if (port->n_tx_req_queued == ghsic_data_tx_intr_thld) {
diff --git a/drivers/usb/gadget/u_uac1.c b/drivers/usb/gadget/u_uac1.c
index af98989..fc4fb7a 100644
--- a/drivers/usb/gadget/u_uac1.c
+++ b/drivers/usb/gadget/u_uac1.c
@@ -1,6 +1,7 @@
 /*
- * u_uac1.c -- ALSA audio utilities for Gadget stack
+ * u_audio.c -- ALSA audio utilities for Gadget stack
  *
+ * Copyright (c) 2012, The Linux Foundation. All rights reserved.
  * Copyright (C) 2008 Bryan Wu <cooloney@kernel.org>
  * Copyright (C) 2008 Analog Devices, Inc
  *
@@ -19,12 +20,17 @@
 
 #include "u_uac1.h"
 
+#ifdef pr_fmt
+#undef pr_fmt
+#endif
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
 /*
  * This component encapsulates the ALSA devices for USB audio gadget
  */
 
-#define FILE_PCM_PLAYBACK	"/dev/snd/pcmC0D0p"
-#define FILE_PCM_CAPTURE	"/dev/snd/pcmC0D0c"
+#define FILE_PCM_PLAYBACK	"/dev/snd/pcmC0D5p"
+#define FILE_PCM_CAPTURE	"/dev/snd/pcmC0D6c"
 #define FILE_CONTROL		"/dev/snd/controlC0"
 
 static char *fn_play = FILE_PCM_PLAYBACK;
@@ -39,6 +45,10 @@
 module_param(fn_cntl, charp, S_IRUGO);
 MODULE_PARM_DESC(fn_cntl, "Control device file name");
 
+static struct gaudio *the_card;
+
+static bool audio_reinit;
+
 /*-------------------------------------------------------------------------*/
 
 /**
@@ -94,8 +104,9 @@
 			}
 			changed = snd_interval_refine(i, &t);
 		}
-	} else
+	} else {
 		return -EINVAL;
+	}
 	if (changed) {
 		params->cmask |= 1 << var;
 		params->rmask |= 1 << var;
@@ -104,10 +115,32 @@
 }
 /*-------------------------------------------------------------------------*/
 
+static inline
+struct snd_interval *param_to_interval(struct snd_pcm_hw_params *p, int n)
+{
+	return &(p->intervals[n - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL]);
+}
+
+int pcm_buffer_size(struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *i =
+		param_to_interval(params, SNDRV_PCM_HW_PARAM_BUFFER_BYTES);
+	pr_debug("buffer_bytes = (%d,%d) omin=%d omax=%d int=%d empty=%d\n",
+		i->min, i->max, i->openmin, i->openmax, i->integer, i->empty);
+	return i->min;
+}
+
+int pcm_period_size(struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *i =
+		param_to_interval(params, SNDRV_PCM_HW_PARAM_PERIOD_BYTES);
+	return i->min;
+}
+
 /**
  * Set default hardware params
  */
-static int playback_default_hw_params(struct gaudio_snd_dev *snd)
+static int playback_prepare_params(struct gaudio_snd_dev *snd)
 {
 	struct snd_pcm_substream *substream = snd->substream;
 	struct snd_pcm_hw_params *params;
@@ -117,12 +150,12 @@
 	* SNDRV_PCM_ACCESS_RW_INTERLEAVED,
 	* SNDRV_PCM_FORMAT_S16_LE
 	* CHANNELS: 2
-	* RATE: 48000
+	* RATE: 8000
 	*/
 	snd->access = SNDRV_PCM_ACCESS_RW_INTERLEAVED;
 	snd->format = SNDRV_PCM_FORMAT_S16_LE;
 	snd->channels = 2;
-	snd->rate = 48000;
+	snd->rate = 8000;
 
 	params = kzalloc(sizeof(*params), GFP_KERNEL);
 	if (!params)
@@ -138,17 +171,23 @@
 	_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_RATE,
 			snd->rate, 0);
 
-	snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
-	snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_HW_PARAMS, params);
+	result = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
+	if (result < 0)
+		pr_err("SNDRV_PCM_IOCTL_DROP failed: %d\n", (int)result);
 
-	result = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_PREPARE, NULL);
+	result = snd_pcm_kernel_ioctl(substream,
+			SNDRV_PCM_IOCTL_HW_PARAMS, params);
 	if (result < 0) {
-		ERROR(snd->card,
-			"Preparing sound card failed: %d\n", (int)result);
+		pr_err("SNDRV_PCM_IOCTL_HW_PARAMS failed: %d\n", (int)result);
 		kfree(params);
 		return result;
 	}
 
+	result = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_PREPARE, NULL);
+	if (result < 0)
+		pr_err("Preparing playback failed: %d\n", (int)result);
+
+
 	/* Store the hardware parameters */
 	snd->access = params_access(params);
 	snd->format = params_format(params);
@@ -157,13 +196,236 @@
 
 	kfree(params);
 
-	INFO(snd->card,
-		"Hardware params: access %x, format %x, channels %d, rate %d\n",
+	pr_debug("playback params: access %x, format %x, channels %d, rate %d\n",
 		snd->access, snd->format, snd->channels, snd->rate);
 
 	return 0;
 }
 
+static int capture_prepare_params(struct gaudio_snd_dev *snd)
+{
+	struct snd_pcm_substream *substream = snd->substream;
+	struct snd_pcm_runtime   *runtime = substream->runtime;
+	struct snd_pcm_hw_params *params;
+	struct snd_pcm_sw_params *swparams;
+	unsigned long period_size;
+	unsigned long buffer_size;
+	snd_pcm_sframes_t result = 0;
+
+	/*
+	 * SNDRV_PCM_ACCESS_RW_INTERLEAVED,
+	 * SNDRV_PCM_FORMAT_S16_LE
+	 * CHANNELS: 1
+	 * RATE: 8000
+	 */
+	snd->access = SNDRV_PCM_ACCESS_RW_INTERLEAVED;
+	snd->format = SNDRV_PCM_FORMAT_S16_LE;
+	snd->channels = 1;
+	snd->rate = 8000;
+
+	params = kzalloc(sizeof(*params), GFP_KERNEL);
+	if (!params) {
+		pr_err("Failed to allocate hw params");
+		return -ENOMEM;
+	}
+
+	_snd_pcm_hw_params_any(params);
+	_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_ACCESS,
+			snd->access, 0);
+	_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_FORMAT,
+			snd->format, 0);
+	_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_CHANNELS,
+			snd->channels, 0);
+	_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_RATE,
+			snd->rate, 0);
+
+	result = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
+	if (result < 0)
+		pr_err("SNDRV_PCM_IOCTL_DROP failed: %d\n", (int)result);
+
+	result = snd_pcm_kernel_ioctl(substream,
+			SNDRV_PCM_IOCTL_HW_PARAMS, params);
+	if (result < 0) {
+		pr_err("SNDRV_PCM_IOCTL_HW_PARAMS failed: %d\n", (int)result);
+		kfree(params);
+		return result;
+	}
+
+	result = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_PREPARE,
+					NULL);
+	if (result < 0)
+		pr_err("Preparing capture failed: %d\n", (int)result);
+
+	/* Store the hardware parameters */
+	snd->access = params_access(params);
+	snd->format = params_format(params);
+	snd->channels = params_channels(params);
+	snd->rate = params_rate(params);
+
+	runtime->frame_bits = snd_pcm_format_physical_width(runtime->format);
+
+	kfree(params);
+
+	swparams = kzalloc(sizeof(*swparams), GFP_KERNEL);
+	if (!swparams) {
+		pr_err("Failed to allocate sw params");
+		return -ENOMEM;
+	}
+
+	buffer_size = pcm_buffer_size(params);
+	period_size = pcm_period_size(params);
+	swparams->avail_min = period_size/2;
+	swparams->xfer_align = period_size/2;
+
+	swparams->tstamp_mode = SNDRV_PCM_TSTAMP_NONE;
+	swparams->period_step = 1;
+	swparams->start_threshold = 1;
+	swparams->stop_threshold = INT_MAX;
+	swparams->silence_size = 0;
+	swparams->silence_threshold = 0;
+
+	result = snd_pcm_kernel_ioctl(substream,
+			SNDRV_PCM_IOCTL_SW_PARAMS, swparams);
+	if (result < 0)
+		pr_err("SNDRV_PCM_IOCTL_SW_PARAMS failed: %d\n", (int)result);
+
+	kfree(swparams);
+
+	pr_debug("capture params: access %x, format %x, channels %d, rate %d\n",
+		snd->access, snd->format, snd->channels, snd->rate);
+
+	return result;
+}
+
+/**
+ * Set default hardware params
+ */
+static int playback_default_hw_params(struct gaudio_snd_dev *snd)
+{
+	struct snd_pcm_hw_params *params;
+
+       /*
+	* SNDRV_PCM_ACCESS_RW_INTERLEAVED,
+	* SNDRV_PCM_FORMAT_S16_LE
+	* CHANNELS: 2
+	* RATE: 8000
+	*/
+	snd->access = SNDRV_PCM_ACCESS_RW_INTERLEAVED;
+	snd->format = SNDRV_PCM_FORMAT_S16_LE;
+	snd->channels = 2;
+	snd->rate = 8000;
+
+	params = kzalloc(sizeof(*params), GFP_KERNEL);
+	if (!params)
+		return -ENOMEM;
+
+	_snd_pcm_hw_params_any(params);
+	_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_ACCESS,
+			snd->access, 0);
+	_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_FORMAT,
+			snd->format, 0);
+	_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_CHANNELS,
+			snd->channels, 0);
+	_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_RATE,
+			snd->rate, 0);
+
+	/* Store the hardware parameters */
+	snd->access = params_access(params);
+	snd->format = params_format(params);
+	snd->channels = params_channels(params);
+	snd->rate = params_rate(params);
+
+	kfree(params);
+
+	pr_debug("playback params: access %x, format %x, channels %d, rate %d\n",
+		snd->access, snd->format, snd->channels, snd->rate);
+
+	return 0;
+}
+
+static int capture_default_hw_params(struct gaudio_snd_dev *snd)
+{
+	struct snd_pcm_hw_params *params;
+
+	/*
+	 * SNDRV_PCM_ACCESS_RW_INTERLEAVED,
+	 * SNDRV_PCM_FORMAT_S16_LE
+	 * CHANNELS: 1
+	 * RATE: 8000
+	 */
+	snd->access = SNDRV_PCM_ACCESS_RW_INTERLEAVED;
+	snd->format = SNDRV_PCM_FORMAT_S16_LE;
+	snd->channels = 1;
+	snd->rate = 8000;
+
+	params = kzalloc(sizeof(*params), GFP_KERNEL);
+	if (!params)
+		return -ENOMEM;
+
+	_snd_pcm_hw_params_any(params);
+	_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_ACCESS,
+			snd->access, 0);
+	_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_FORMAT,
+			snd->format, 0);
+	_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_CHANNELS,
+			snd->channels, 0);
+	_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_RATE,
+			snd->rate, 0);
+
+	/* Store the hardware parameters */
+	snd->access = params_access(params);
+	snd->format = params_format(params);
+	snd->channels = params_channels(params);
+	snd->rate = params_rate(params);
+
+	kfree(params);
+
+	pr_debug("capture params: access %x, format %x, channels %d, rate %d\n",
+		snd->access, snd->format, snd->channels, snd->rate);
+
+	return 0;
+}
+
+static int gaudio_open_streams(void)
+{
+	struct gaudio_snd_dev *snd;
+	int res = 0;
+
+	if (!the_card) {
+		pr_err("%s: Card is NULL", __func__);
+		return -ENODEV;
+	}
+
+	pr_debug("Initialize hw params");
+
+	/* Open PCM playback device and setup substream */
+	snd = &the_card->playback;
+	res = playback_prepare_params(snd);
+	if (res) {
+		pr_err("Setting playback params failed: err %d", res);
+		return res;
+	}
+
+	pr_debug("Initialized playback params");
+
+	/* Open PCM capture device and setup substream */
+	snd = &the_card->capture;
+	res = capture_prepare_params(snd);
+	if (res) {
+		pr_err("Setting capture params failed: err %d", res);
+		return res;
+	}
+
+	pr_info("Initialized capture params");
+
+	return 0;
+}
+
+void u_audio_clear(void)
+{
+	audio_reinit = false;
+}
+
 /**
  * Playback audio buffer data by ALSA PCM device
  */
@@ -175,28 +437,106 @@
 	mm_segment_t old_fs;
 	ssize_t result;
 	snd_pcm_sframes_t frames;
+	int err = 0;
+
+	if (!count) {
+		pr_err("Buffer is empty, no data to play");
+		return 0;
+	}
+
+	if (!audio_reinit) {
+		err = gaudio_open_streams();
+		if (err) {
+			pr_err("Failed to init audio streams");
+			return 0;
+		}
+		audio_reinit = 1;
+	}
 
 try_again:
 	if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
-		runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
+		runtime->status->state == SNDRV_PCM_STATE_SUSPENDED ||
+		runtime->status->state == SNDRV_PCM_STATE_SETUP) {
 		result = snd_pcm_kernel_ioctl(substream,
 				SNDRV_PCM_IOCTL_PREPARE, NULL);
 		if (result < 0) {
-			ERROR(card, "Preparing sound card failed: %d\n",
+			pr_err("Preparing playback failed: %d\n",
+					(int)result);
+			return result;
+		}
+	}
+
+	if (!runtime->frame_bits) {
+		pr_err("SND failure - runtime->frame_bits == 0");
+		return 0;
+	}
+
+	frames = bytes_to_frames(runtime, count);
+	pr_debug("runtime->frame_bits = %d, count = %d, frames = %d",
+		runtime->frame_bits, (int)count, (int)frames);
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	result = snd_pcm_lib_write(snd->substream, buf, frames);
+	if (result != frames) {
+		pr_err("snd_pcm_lib_write failed with err %d\n", (int)result);
+		set_fs(old_fs);
+		goto try_again;
+	}
+	set_fs(old_fs);
+
+	pr_debug("Done. Sent %d frames", (int)frames);
+
+	return 0;
+}
+
+static size_t u_audio_capture(struct gaudio *card, void *buf, size_t count)
+{
+	ssize_t result;
+	mm_segment_t old_fs;
+	snd_pcm_sframes_t frames;
+	int err = 0;
+
+	struct gaudio_snd_dev	 *snd = &card->capture;
+	struct snd_pcm_substream *substream = snd->substream;
+	struct snd_pcm_runtime   *runtime = substream->runtime;
+
+	if (!audio_reinit) {
+		err = gaudio_open_streams();
+		if (err) {
+			pr_err("Failed to init audio streams: err %d", err);
+			return 0;
+		}
+		audio_reinit = 1;
+	}
+
+try_again:
+	if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
+		runtime->status->state == SNDRV_PCM_STATE_SUSPENDED ||
+		runtime->status->state == SNDRV_PCM_STATE_SETUP) {
+		result = snd_pcm_kernel_ioctl(substream,
+				SNDRV_PCM_IOCTL_PREPARE, NULL);
+		if (result < 0) {
+			pr_err("Preparing capture failed: %d\n",
 					(int)result);
 			return result;
 		}
 	}
 
 	frames = bytes_to_frames(runtime, count);
+
 	old_fs = get_fs();
 	set_fs(KERNEL_DS);
-	result = snd_pcm_lib_write(snd->substream, buf, frames);
+
+	pr_debug("frames = %d, count = %d", (int)frames, count);
+
+	result = snd_pcm_lib_read(substream, buf, frames);
 	if (result != frames) {
-		ERROR(card, "Playback error: %d\n", (int)result);
+		pr_err("Capture error: %d\n", (int)result);
 		set_fs(old_fs);
 		goto try_again;
 	}
+
 	set_fs(old_fs);
 
 	return 0;
@@ -204,14 +544,29 @@
 
 static int u_audio_get_playback_channels(struct gaudio *card)
 {
+	pr_debug("Return %d", card->playback.channels);
 	return card->playback.channels;
 }
 
 static int u_audio_get_playback_rate(struct gaudio *card)
 {
+	pr_debug("Return %d", card->playback.rate);
 	return card->playback.rate;
 }
 
+static int u_audio_get_capture_channels(struct gaudio *card)
+{
+	pr_debug("Return %d", card->capture.channels);
+	return card->capture.channels;
+}
+
+static int u_audio_get_capture_rate(struct gaudio *card)
+{
+	pr_debug("Return %d", card->capture.rate);
+	return card->capture.rate;
+}
+
+
 /**
  * Open ALSA PCM and control device files
  * Initial the PCM or control device
@@ -220,16 +575,18 @@
 {
 	struct snd_pcm_file *pcm_file;
 	struct gaudio_snd_dev *snd;
+	int res = 0;
 
-	if (!card)
+	if (!card) {
+		pr_err("%s: Card is NULL", __func__);
 		return -ENODEV;
-
+	}
 	/* Open control device */
 	snd = &card->control;
 	snd->filp = filp_open(fn_cntl, O_RDWR, 0);
 	if (IS_ERR(snd->filp)) {
 		int ret = PTR_ERR(snd->filp);
-		ERROR(card, "unable to open sound control device file: %s\n",
+		pr_err("unable to open sound control device file: %s\n",
 				fn_cntl);
 		snd->filp = NULL;
 		return ret;
@@ -240,29 +597,41 @@
 	snd = &card->playback;
 	snd->filp = filp_open(fn_play, O_WRONLY, 0);
 	if (IS_ERR(snd->filp)) {
-		ERROR(card, "No such PCM playback device: %s\n", fn_play);
+		pr_err("No such PCM playback device: %s\n", fn_play);
 		snd->filp = NULL;
+		return -EINVAL;
 	}
+	pr_debug("Initialized PCM playback device: %s\n", fn_play);
+
 	pcm_file = snd->filp->private_data;
 	snd->substream = pcm_file->substream;
 	snd->card = card;
-	playback_default_hw_params(snd);
+	res = playback_default_hw_params(snd);
+	if (res) {
+		pr_err("Setting playback HW params failed: err %d", res);
+		return res;
+	}
 
 	/* Open PCM capture device and setup substream */
 	snd = &card->capture;
 	snd->filp = filp_open(fn_cap, O_RDONLY, 0);
 	if (IS_ERR(snd->filp)) {
-		ERROR(card, "No such PCM capture device: %s\n", fn_cap);
+		pr_err("No such PCM capture device: %s\n", fn_cap);
 		snd->substream = NULL;
 		snd->card = NULL;
 		snd->filp = NULL;
-	} else {
-		pcm_file = snd->filp->private_data;
-		snd->substream = pcm_file->substream;
-		snd->card = card;
+		return -EINVAL;
 	}
 
-	return 0;
+	pcm_file = snd->filp->private_data;
+	snd->substream = pcm_file->substream;
+	snd->card = card;
+	res = capture_default_hw_params(snd);
+
+	if (res)
+		pr_err("Setting capture HW params failed: err %d", res);
+
+	return res;
 }
 
 /**
@@ -272,6 +641,7 @@
 {
 	struct gaudio_snd_dev	*snd;
 
+	pr_debug("Enter");
 	/* Close control device */
 	snd = &gau->control;
 	if (snd->filp)
@@ -290,7 +660,7 @@
 	return 0;
 }
 
-static struct gaudio *the_card;
+
 /**
  * gaudio_setup - setup ALSA interface and preparing for USB transfer
  *
@@ -298,18 +668,17 @@
  *
  * Returns negative errno, or zero on success
  */
-int __init gaudio_setup(struct gaudio *card)
+int gaudio_setup(struct gaudio *card)
 {
 	int	ret;
 
 	ret = gaudio_open_snd_dev(card);
 	if (ret)
-		ERROR(card, "we need at least one control device\n");
+		pr_err("Failed to open snd devices\n");
 	else if (!the_card)
 		the_card = card;
 
 	return ret;
-
 }
 
 /**
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index fee7a09..b7f1878 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -659,12 +659,6 @@
 		return 0;
 	}
 
-	if (!(readl_relaxed(USB_PORTSC) & PORT_PE)) {
-		dev_dbg(mehci->dev, "%s:port is not enabled skip suspend\n",
-				__func__);
-		return -EAGAIN;
-	}
-
 	disable_irq(hcd->irq);
 
 	/* make sure we don't race against a remote wakeup */
@@ -934,6 +928,15 @@
 
 static int ehci_hsic_bus_suspend(struct usb_hcd *hcd)
 {
+	struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
+
+	if (!(readl_relaxed(USB_PORTSC) & PORT_PE)) {
+		dbg_log_event(NULL, "RH suspend attempt failed", 0);
+		dev_dbg(mehci->dev, "%s:port is not enabled skip suspend\n",
+				__func__);
+		return -EAGAIN;
+	}
+
 	dbg_log_event(NULL, "Suspend RH", 0);
 	return ehci_bus_suspend(hcd);
 }
diff --git a/drivers/usb/misc/diag_bridge.c b/drivers/usb/misc/diag_bridge.c
index cad411d..b1b7763 100644
--- a/drivers/usb/misc/diag_bridge.c
+++ b/drivers/usb/misc/diag_bridge.c
@@ -60,6 +60,11 @@
 		return -ENODEV;
 	}
 
+	if (dev->ops) {
+		pr_err("bridge already opened");
+		return -EALREADY;
+	}
+
 	dev->ops = ops;
 	dev->err = 0;
 
@@ -82,6 +87,16 @@
 {
 	struct diag_bridge	*dev = __dev;
 
+	if (!dev) {
+		pr_err("dev is null");
+		return;
+	}
+
+	if (!dev->ops) {
+		pr_err("can't close bridge that was not open");
+		return;
+	}
+
 	dev_dbg(&dev->ifc->dev, "%s:\n", __func__);
 
 	usb_kill_anchored_urbs(&dev->submitted);
diff --git a/drivers/usb/misc/ks_bridge.c b/drivers/usb/misc/ks_bridge.c
index 8753c0d..87f43e1c 100644
--- a/drivers/usb/misc/ks_bridge.c
+++ b/drivers/usb/misc/ks_bridge.c
@@ -262,6 +262,8 @@
 			return;
 		}
 
+		usb_free_urb(urb);
+
 		spin_lock_irqsave(&ksb->lock, flags);
 	}
 	spin_unlock_irqrestore(&ksb->lock, flags);
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 5637f19..998978c 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -69,6 +69,13 @@
 
 #define USB_SUSPEND_DELAY_TIME	(500 * HZ/1000) /* 500 msec */
 
+enum msm_otg_phy_reg_mode {
+	USB_PHY_REG_OFF,
+	USB_PHY_REG_ON,
+	USB_PHY_REG_LPM_ON,
+	USB_PHY_REG_LPM_OFF,
+};
+
 static DECLARE_COMPLETION(pmic_vbus_init);
 static struct msm_otg *the_msm_otg;
 static bool debug_aca_enabled;
@@ -168,7 +175,8 @@
 	return ret;
 }
 
-static int msm_hsusb_ldo_enable(struct msm_otg *motg, int on)
+static int msm_hsusb_ldo_enable(struct msm_otg *motg,
+	enum msm_otg_phy_reg_mode mode)
 {
 	int ret = 0;
 
@@ -182,7 +190,8 @@
 		return -ENODEV;
 	}
 
-	if (on) {
+	switch (mode) {
+	case USB_PHY_REG_ON:
 		ret = regulator_set_optimum_mode(hsusb_1p8,
 				USB_PHY_1P8_HPM_LOAD);
 		if (ret < 0) {
@@ -219,7 +228,9 @@
 			return ret;
 		}
 
-	} else {
+		break;
+
+	case USB_PHY_REG_OFF:
 		ret = regulator_disable(hsusb_1p8);
 		if (ret) {
 			dev_err(motg->phy.dev, "%s: unable to disable the hsusb 1p8\n",
@@ -242,9 +253,55 @@
 		if (ret < 0)
 			pr_err("%s: Unable to set LPM of the regulator:"
 				"HSUSB_3p3\n", __func__);
+
+		break;
+
+	case USB_PHY_REG_LPM_ON:
+		ret = regulator_set_optimum_mode(hsusb_1p8,
+				USB_PHY_1P8_LPM_LOAD);
+		if (ret < 0) {
+			pr_err("%s: Unable to set LPM of the regulator: HSUSB_1p8\n",
+				__func__);
+			return ret;
+		}
+
+		ret = regulator_set_optimum_mode(hsusb_3p3,
+				USB_PHY_3P3_LPM_LOAD);
+		if (ret < 0) {
+			pr_err("%s: Unable to set LPM of the regulator: HSUSB_3p3\n",
+				__func__);
+			regulator_set_optimum_mode(hsusb_1p8, USB_PHY_REG_ON);
+			return ret;
+		}
+
+		break;
+
+	case USB_PHY_REG_LPM_OFF:
+		ret = regulator_set_optimum_mode(hsusb_1p8,
+				USB_PHY_1P8_HPM_LOAD);
+		if (ret < 0) {
+			pr_err("%s: Unable to set HPM of the regulator: HSUSB_1p8\n",
+				__func__);
+			return ret;
+		}
+
+		ret = regulator_set_optimum_mode(hsusb_3p3,
+				USB_PHY_3P3_HPM_LOAD);
+		if (ret < 0) {
+			pr_err("%s: Unable to set HPM of the regulator: HSUSB_3p3\n",
+				__func__);
+			regulator_set_optimum_mode(hsusb_1p8, USB_PHY_REG_ON);
+			return ret;
+		}
+
+		break;
+
+	default:
+		pr_err("%s: Unsupported mode (%d).", __func__, mode);
+		return -ENOTSUPP;
 	}
 
-	pr_debug("reg (%s)\n", on ? "HPM" : "LPM");
+	pr_debug("%s: USB reg mode (%d) (OFF/HPM/LPM)\n", __func__, mode);
 	return ret < 0 ? ret : 0;
 }
 
@@ -881,8 +938,12 @@
 
 	if (motg->caps & ALLOW_PHY_POWER_COLLAPSE &&
 			!host_bus_suspend && !dcp) {
-		msm_hsusb_ldo_enable(motg, 0);
+		msm_hsusb_ldo_enable(motg, USB_PHY_REG_OFF);
 		motg->lpm_flags |= PHY_PWR_COLLAPSED;
+	} else if (motg->caps & ALLOW_PHY_REGULATORS_LPM &&
+			!host_bus_suspend && !device_bus_suspend && !dcp) {
+		msm_hsusb_ldo_enable(motg, USB_PHY_REG_LPM_ON);
+		motg->lpm_flags |= PHY_REGULATORS_LPM;
 	}
 
 	if (motg->lpm_flags & PHY_RETENTIONED) {
@@ -946,8 +1007,11 @@
 	}
 
 	if (motg->lpm_flags & PHY_PWR_COLLAPSED) {
-		msm_hsusb_ldo_enable(motg, 1);
+		msm_hsusb_ldo_enable(motg, USB_PHY_REG_ON);
 		motg->lpm_flags &= ~PHY_PWR_COLLAPSED;
+	} else if (motg->lpm_flags & PHY_REGULATORS_LPM) {
+		msm_hsusb_ldo_enable(motg, USB_PHY_REG_LPM_OFF);
+		motg->lpm_flags &= ~PHY_REGULATORS_LPM;
 	}
 
 	if (motg->lpm_flags & PHY_RETENTIONED) {
@@ -3622,7 +3686,7 @@
 		}
 	}
 
-	ret = msm_hsusb_ldo_enable(motg, 1);
+	ret = msm_hsusb_ldo_enable(motg, USB_PHY_REG_ON);
 	if (ret) {
 		dev_err(&pdev->dev, "hsusb vreg enable failed\n");
 		goto free_ldo_init;
@@ -3724,7 +3788,8 @@
 				ALLOW_PHY_RETENTION;
 
 		if (motg->pdata->otg_control == OTG_PHY_CONTROL)
-			motg->caps = ALLOW_PHY_RETENTION;
+			motg->caps = ALLOW_PHY_RETENTION |
+				ALLOW_PHY_REGULATORS_LPM;
 	}
 
 	if (motg->pdata->enable_lpm_on_dev_suspend)
@@ -3756,7 +3821,7 @@
 destroy_wlock:
 	wake_lock_destroy(&motg->wlock);
 	clk_disable_unprepare(motg->core_clk);
-	msm_hsusb_ldo_enable(motg, 0);
+	msm_hsusb_ldo_enable(motg, USB_PHY_REG_OFF);
 free_ldo_init:
 	msm_hsusb_ldo_init(motg, 0);
 free_hsusb_vddcx:
@@ -3843,7 +3908,7 @@
 	clk_disable_unprepare(motg->pclk);
 	clk_disable_unprepare(motg->core_clk);
 	msm_xo_put(motg->xo_handle);
-	msm_hsusb_ldo_enable(motg, 0);
+	msm_hsusb_ldo_enable(motg, USB_PHY_REG_OFF);
 	msm_hsusb_ldo_init(motg, 0);
 	regulator_disable(hsusb_vddcx);
 	regulator_set_voltage(hsusb_vddcx,
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index 6e3567f..f6d9eb7 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -606,7 +606,7 @@
 
 static int mdp_hist_init_mgmt(struct mdp_hist_mgmt *mgmt, uint32_t block)
 {
-	uint32_t bins, extra, index, term = 0;
+	uint32_t bins, extra, index, intr = 0, term = 0;
 	init_completion(&mgmt->mdp_hist_comp);
 	mutex_init(&mgmt->mdp_hist_mutex);
 	mutex_init(&mgmt->mdp_do_hist_mutex);
@@ -622,6 +622,8 @@
 	switch (block) {
 	case MDP_BLOCK_DMA_P:
 		term = MDP_HISTOGRAM_TERM_DMA_P;
+		intr = (mdp_rev >= MDP_REV_40) ? INTR_DMA_P_HISTOGRAM :
+								MDP_HIST_DONE;
 		bins = (mdp_rev >= MDP_REV_42) ? MDP_REV42_HIST_MAX_BIN :
 			MDP_REV41_HIST_MAX_BIN;
 		extra = 2;
@@ -630,6 +632,7 @@
 		break;
 	case MDP_BLOCK_DMA_S:
 		term = MDP_HISTOGRAM_TERM_DMA_S;
+		intr = INTR_DMA_S_HISTOGRAM;
 		bins = MDP_REV42_HIST_MAX_BIN;
 		extra = 2;
 		mgmt->base += 0x5000;
@@ -637,6 +640,7 @@
 		break;
 	case MDP_BLOCK_VG_1:
 		term = MDP_HISTOGRAM_TERM_VG_1;
+		intr = INTR_VG1_HISTOGRAM;
 		bins = MDP_REV42_HIST_MAX_BIN;
 		extra = 1;
 		mgmt->base += 0x6000;
@@ -644,6 +648,7 @@
 		break;
 	case MDP_BLOCK_VG_2:
 		term = MDP_HISTOGRAM_TERM_VG_2;
+		intr = INTR_VG2_HISTOGRAM;
 		bins = MDP_REV42_HIST_MAX_BIN;
 		extra = 1;
 		mgmt->base += 0x6000;
@@ -651,6 +656,8 @@
 		break;
 	default:
 		term = MDP_HISTOGRAM_TERM_DMA_P;
+		intr = (mdp_rev >= MDP_REV_40) ? INTR_DMA_P_HISTOGRAM :
+								MDP_HIST_DONE;
 		bins = (mdp_rev >= MDP_REV_42) ? MDP_REV42_HIST_MAX_BIN :
 			MDP_REV41_HIST_MAX_BIN;
 		extra = 2;
@@ -658,6 +665,7 @@
 		index = MDP_HIST_MGMT_DMA_P;
 	}
 	mgmt->irq_term = term;
+	mgmt->intr = intr;
 
 	mgmt->c0 = kmalloc(bins * sizeof(uint32_t), GFP_KERNEL);
 	if (mgmt->c0 == NULL)
@@ -802,20 +810,45 @@
 static int mdp_histogram_enable(struct mdp_hist_mgmt *mgmt)
 {
 	uint32_t base;
+	unsigned long flag;
 	if (mgmt->mdp_is_hist_data == TRUE) {
 		pr_err("%s histogram already started\n", __func__);
 		return -EINVAL;
 	}
 
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	mdp_enable_irq(mgmt->irq_term);
+	base = (uint32_t) (MDP_BASE + mgmt->base);
+	/*First make sure that device is not collecting histogram*/
+	mgmt->mdp_is_hist_data = FALSE;
+	mgmt->mdp_is_hist_valid = FALSE;
+	mgmt->mdp_is_hist_init = FALSE;
+	spin_lock_irqsave(&mdp_spin_lock, flag);
+	outp32(MDP_INTR_CLEAR, mgmt->intr);
+	mdp_intr_mask &= ~mgmt->intr;
+	outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+	MDP_OUTP(base + 0x001C, 0);
+	MDP_OUTP(base + 0x0018, INTR_HIST_DONE | INTR_HIST_RESET_SEQ_DONE);
+	MDP_OUTP(base + 0x0024, 0);
+	spin_unlock_irqrestore(&mdp_spin_lock, flag);
+
+	mutex_unlock(&mgmt->mdp_hist_mutex);
+	cancel_work_sync(&mgmt->mdp_histogram_worker);
+	mutex_lock(&mgmt->mdp_hist_mutex);
+
+	/*Then initialize histogram*/
 	INIT_COMPLETION(mgmt->mdp_hist_comp);
 
-	base = (uint32_t) (MDP_BASE + mgmt->base);
+	spin_lock_irqsave(&mdp_spin_lock, flag);
 	MDP_OUTP(base + 0x0018, INTR_HIST_DONE | INTR_HIST_RESET_SEQ_DONE);
 	MDP_OUTP(base + 0x0010, 1);
 	MDP_OUTP(base + 0x001C, INTR_HIST_DONE | INTR_HIST_RESET_SEQ_DONE);
 
+	outp32(MDP_INTR_CLEAR, mgmt->intr);
+	mdp_intr_mask |= mgmt->intr;
+	outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+	mdp_enable_irq(mgmt->irq_term);
+	spin_unlock_irqrestore(&mdp_spin_lock, flag);
+
 	MDP_OUTP(base + 0x0004, mgmt->frame_cnt);
 	if (mgmt->block != MDP_BLOCK_VG_1 && mgmt->block != MDP_BLOCK_VG_2)
 		MDP_OUTP(base + 0x0008, mgmt->bit_mask);
@@ -830,6 +863,7 @@
 static int mdp_histogram_disable(struct mdp_hist_mgmt *mgmt)
 {
 	uint32_t base, status;
+	unsigned long flag;
 	if (mgmt->mdp_is_hist_data == FALSE) {
 		pr_err("%s histogram already stopped\n", __func__);
 		return -EINVAL;
@@ -842,6 +876,13 @@
 	base = (uint32_t) (MDP_BASE + mgmt->base);
 
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+	spin_lock_irqsave(&mdp_spin_lock, flag);
+	outp32(MDP_INTR_CLEAR, mgmt->intr);
+	mdp_intr_mask &= ~mgmt->intr;
+	outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+	mdp_disable_irq(mgmt->irq_term);
+	spin_unlock_irqrestore(&mdp_spin_lock, flag);
+
 	if (mdp_rev >= MDP_REV_42)
 		MDP_OUTP(base + 0x0020, 1);
 	status = inpdw(base + 0x001C);
@@ -856,7 +897,6 @@
 		complete(&mgmt->mdp_hist_comp);
 	}
 
-	mdp_disable_irq(mgmt->irq_term);
 	return 0;
 }
 
@@ -1102,6 +1142,7 @@
 	struct mdp_hist_mgmt *mgmt = container_of(data, struct mdp_hist_mgmt,
 							mdp_histogram_worker);
 	int ret = 0;
+	bool hist_ready;
 	mutex_lock(&mgmt->mdp_hist_mutex);
 	if (mgmt->mdp_is_hist_data == FALSE) {
 		pr_debug("%s, Histogram disabled before read.\n", __func__);
@@ -1116,8 +1157,9 @@
 			pr_err("mgmt->hist invalid NULL\n");
 		ret = -EINVAL;
 	}
+	hist_ready = (mgmt->mdp_is_hist_init && mgmt->mdp_is_hist_valid);
 
-	if (!ret) {
+	if (!ret && hist_ready) {
 		switch (mgmt->block) {
 		case MDP_BLOCK_DMA_P:
 		case MDP_BLOCK_DMA_S:
@@ -1138,7 +1180,7 @@
 	 * if read was triggered by an underrun or failed copying,
 	 * don't wake up readers
 	 */
-	if (!ret && mgmt->mdp_is_hist_valid && mgmt->mdp_is_hist_init) {
+	if (!ret && hist_ready) {
 		mgmt->hist = NULL;
 		if (waitqueue_active(&mgmt->mdp_hist_comp.wait))
 			complete(&mgmt->mdp_hist_comp);
@@ -1150,7 +1192,7 @@
 			mgmt->mdp_is_hist_init = TRUE;
 
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	if (!ret)
+	if (!ret && hist_ready)
 		__mdp_histogram_kickoff(mgmt);
 	else
 		__mdp_histogram_reset(mgmt);
@@ -1728,10 +1770,8 @@
 	isr &= mask;
 	if (isr & INTR_HIST_RESET_SEQ_DONE)
 		__mdp_histogram_kickoff(mgmt);
-
-	if (isr & INTR_HIST_DONE) {
+	else if (isr & INTR_HIST_DONE)
 		queue_work(mdp_hist_wq, &mgmt->mdp_histogram_worker);
-	}
 }
 
 #ifndef CONFIG_FB_MSM_MDP40
@@ -1741,7 +1781,6 @@
 	struct mdp_dma_data *dma;
 	unsigned long flag;
 	struct mdp_hist_mgmt *mgmt = NULL;
-	char *base_addr;
 	int i, ret;
 	int vsync_isr;
 	/* Ensure all the register write are complete */
@@ -1813,13 +1852,7 @@
 				mgmt = mdp_hist_mgmt_array[i];
 				if (!mgmt)
 					continue;
-
-				base_addr = MDP_BASE + mgmt->base;
-				outpdw(base_addr + 0x010, 1);
-				outpdw(base_addr + 0x01C, INTR_HIST_DONE |
-						INTR_HIST_RESET_SEQ_DONE);
 				mgmt->mdp_is_hist_valid = FALSE;
-				__mdp_histogram_reset(mgmt);
 			}
 		}
 
diff --git a/drivers/video/msm/mdp.h b/drivers/video/msm/mdp.h
index 1397507..371174c 100644
--- a/drivers/video/msm/mdp.h
+++ b/drivers/video/msm/mdp.h
@@ -256,6 +256,7 @@
 struct mdp_hist_mgmt {
 	uint32_t block;
 	uint32_t irq_term;
+	uint32_t intr;
 	uint32_t base;
 	struct completion mdp_hist_comp;
 	struct mutex mdp_hist_mutex;
@@ -323,6 +324,14 @@
 #define TV_OUT_DMA3_START   BIT(13)
 #define MDP_HIST_DONE       BIT(20)
 
+/*MDP4 MDP histogram interrupts*/
+/*note: these are only applicable on MDP4+ targets*/
+#define INTR_VG1_HISTOGRAM		BIT(5)
+#define INTR_VG2_HISTOGRAM		BIT(6)
+#define INTR_DMA_P_HISTOGRAM		BIT(17)
+#define INTR_DMA_S_HISTOGRAM		BIT(26)
+/*end MDP4 MDP histogram interrupts*/
+
 /* histogram interrupts */
 #define INTR_HIST_DONE			BIT(1)
 #define INTR_HIST_RESET_SEQ_DONE	BIT(0)
@@ -337,7 +346,6 @@
 			MDP_DMA_S_DONE| \
 			MDP_DMA_E_DONE| \
 			LCDC_UNDERFLOW| \
-			MDP_HIST_DONE| \
 			TV_ENC_UNDERRUN)
 #endif
 
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index 6fc83df..005e87c 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -111,33 +111,23 @@
 };
 
 /* system interrupts */
+/*note histogram interrupts defined in mdp.h*/
 #define INTR_OVERLAY0_DONE		BIT(0)
 #define INTR_OVERLAY1_DONE		BIT(1)
 #define INTR_DMA_S_DONE			BIT(2)
 #define INTR_DMA_E_DONE			BIT(3)
 #define INTR_DMA_P_DONE			BIT(4)
-#define INTR_VG1_HISTOGRAM		BIT(5)
-#define INTR_VG2_HISTOGRAM		BIT(6)
 #define INTR_PRIMARY_VSYNC		BIT(7)
 #define INTR_PRIMARY_INTF_UDERRUN	BIT(8)
 #define INTR_EXTERNAL_VSYNC		BIT(9)
 #define INTR_EXTERNAL_INTF_UDERRUN	BIT(10)
 #define INTR_PRIMARY_RDPTR		BIT(11)	/* read pointer */
-#define INTR_DMA_P_HISTOGRAM		BIT(17)
-#define INTR_DMA_S_HISTOGRAM		BIT(26)
 #define INTR_OVERLAY2_DONE		BIT(30)
 
 #ifdef CONFIG_FB_MSM_OVERLAY
-#define MDP4_ANY_INTR_MASK	(INTR_DMA_P_HISTOGRAM | \
-				INTR_DMA_S_HISTOGRAM | \
-				INTR_VG1_HISTOGRAM | \
-				INTR_VG2_HISTOGRAM)
+#define MDP4_ANY_INTR_MASK	(0)
 #else
-#define MDP4_ANY_INTR_MASK	(INTR_DMA_P_DONE| \
-				INTR_DMA_P_HISTOGRAM | \
-				INTR_DMA_S_HISTOGRAM | \
-				INTR_VG1_HISTOGRAM | \
-				INTR_VG2_HISTOGRAM)
+#define MDP4_ANY_INTR_MASK	(INTR_DMA_P_DONE)
 #endif
 
 enum {
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index 63f0aa1..18cf817 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -3092,6 +3092,7 @@
 int mdp4_overlay_unset_mixer(int mixer)
 {
 	struct mdp4_overlay_pipe *pipe;
+	struct mdp4_overlay_pipe *orgpipe;
 	int i, cnt = 0;
 
 	/* free pipe besides base layer pipe */
@@ -3103,6 +3104,10 @@
 		mdp4_overlay_reg_flush(pipe, 1);
 		mdp4_mixer_stage_down(pipe, 1);
 		mdp4_overlay_pipe_free(pipe);
+		/*Clear real pipe attributes as well */
+		orgpipe = mdp4_overlay_ndx2pipe(pipe->pipe_ndx);
+		if (orgpipe != NULL)
+			orgpipe->pipe_used = 0;
 		cnt++;
 	}
 
diff --git a/drivers/video/msm/mdp4_overlay_dsi_video.c b/drivers/video/msm/mdp4_overlay_dsi_video.c
index fcdccca..2d21929 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_video.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_video.c
@@ -677,6 +677,11 @@
 			/* adb stop */
 			if (pipe->pipe_type == OVERLAY_TYPE_BF)
 				mdp4_overlay_borderfill_stage_down(pipe);
+
+			/* base pipe may change after borderfill_stage_down */
+			pipe = vctrl->base_pipe;
+			mdp4_mixer_stage_down(pipe, 1);
+			mdp4_overlay_pipe_free(pipe);
 			vctrl->base_pipe = NULL;
 		} else {
 			/* system suspending */
diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c
index f3bd775..f01543b 100644
--- a/drivers/video/msm/mdp4_overlay_dtv.c
+++ b/drivers/video/msm/mdp4_overlay_dtv.c
@@ -579,6 +579,10 @@
 			if (pipe->pipe_type == OVERLAY_TYPE_BF)
 				mdp4_overlay_borderfill_stage_down(pipe);
 
+			/* base pipe may change after borderfill_stage_down */
+			pipe = vctrl->base_pipe;
+			mdp4_mixer_stage_down(pipe, 1);
+			mdp4_overlay_pipe_free(pipe);
 			/* pipe == rgb2 */
 			vctrl->base_pipe = NULL;
 		} else {
@@ -1009,6 +1013,8 @@
 	}
 
 	mutex_lock(&mfd->dma->ov_mutex);
+	mdp4_overlay_mdp_perf_upd(mfd, 1);
 	mdp4_dtv_pipe_commit();
+	mdp4_overlay_mdp_perf_upd(mfd, 0);
 	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 323a8fe..bc8ded5 100644
--- a/drivers/video/msm/mdp4_overlay_lcdc.c
+++ b/drivers/video/msm/mdp4_overlay_lcdc.c
@@ -664,6 +664,11 @@
 			/* adb stop */
 			if (pipe->pipe_type == OVERLAY_TYPE_BF)
 				mdp4_overlay_borderfill_stage_down(pipe);
+
+			/* base pipe may change after borderfill_stage_down */
+			pipe = vctrl->base_pipe;
+			mdp4_mixer_stage_down(pipe, 1);
+			mdp4_overlay_pipe_free(pipe);
 			vctrl->base_pipe = NULL;
 		} else {
 			/* system suspending */
diff --git a/drivers/video/msm/mdp4_overlay_writeback.c b/drivers/video/msm/mdp4_overlay_writeback.c
index 487e5d5..ee7e9ce 100644
--- a/drivers/video/msm/mdp4_overlay_writeback.c
+++ b/drivers/video/msm/mdp4_overlay_writeback.c
@@ -294,6 +294,7 @@
 	mdp4_mixer_stage_commit(pipe->mixer_num);
 
 	mdp4_writeback_overlay_kickoff(mfd, pipe);
+	mdp4_writeback_dma_busy_wait(mfd);
 
 	/* move current committed iommu to freelist */
 	mdp4_overlay_iommu_pipe_free(pipe->pipe_ndx, 0);
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index 359f37e..b35acfb 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -500,7 +500,6 @@
 	uint32 isr, mask, panel;
 	struct mdp_dma_data *dma;
 	struct mdp_hist_mgmt *mgmt = NULL;
-	char *base_addr;
 	int i, ret;
 
 	mdp_is_in_isr = TRUE;
@@ -528,12 +527,7 @@
 			mgmt = mdp_hist_mgmt_array[i];
 			if (!mgmt)
 				continue;
-			base_addr = MDP_BASE + mgmt->base;
-			MDP_OUTP(base_addr + 0x010, 1);
-			outpdw(base_addr + 0x01c, INTR_HIST_DONE |
-						INTR_HIST_RESET_SEQ_DONE);
 			mgmt->mdp_is_hist_valid = FALSE;
-			__mdp_histogram_reset(mgmt);
 		}
 	}
 
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index e685785..e409a0b 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -100,17 +100,21 @@
 			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;
 		}
+		msleep(20);
+		wmb();
+
+		ret = regulator_enable(dsi_drv.vdd_vreg);
+		if (ret) {
+			pr_err("%s: Failed to enable regulator.\n", __func__);
+			return ret;
+		}
+		msleep(20);
+		wmb();
 
 		ret = regulator_enable(dsi_drv.dsi_vreg);
 		if (ret) {
@@ -130,13 +134,13 @@
 			return ret;
 		}
 
-		ret = regulator_disable(dsi_drv.vdd_io_vreg);
+		ret = regulator_disable(dsi_drv.dsi_vreg);
 		if (ret) {
 			pr_err("%s: Failed to disable regulator.\n", __func__);
 			return ret;
 		}
 
-		ret = regulator_disable(dsi_drv.dsi_vreg);
+		ret = regulator_disable(dsi_drv.vdd_io_vreg);
 		if (ret) {
 			pr_err("%s: Failed to disable regulator.\n", __func__);
 			return ret;
@@ -165,11 +169,11 @@
 	return 0;
 }
 
-static int mdss_dsi_off(struct mdss_panel_data *pdata)
+static int mdss_dsi_ctrl_unprepare(struct mdss_panel_data *pdata)
 {
-	int ret = 0;
 	struct mdss_panel_info *pinfo;
 	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+	int ret = 0;
 
 	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
 				panel_data);
@@ -180,9 +184,6 @@
 
 	pinfo = &pdata->panel_info;
 
-	if (pdata->panel_info.type == MIPI_VIDEO_PANEL)
-		mdss_dsi_controller_cfg(0, pdata);
-
 	mdss_dsi_op_mode_config(DSI_CMD_MODE, pdata);
 
 	ret = ctrl_pdata->off(pdata);
@@ -191,16 +192,23 @@
 		return ret;
 	}
 
+	return ret;
+}
+
+static int mdss_dsi_off(struct mdss_panel_data *pdata)
+{
+	int ret = 0;
+
 	spin_lock_bh(&dsi_clk_lock);
 	mdss_dsi_clk_disable(pdata);
 
-	/* disable dsi engine */
-	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004, 0);
-
 	spin_unlock_bh(&dsi_clk_lock);
 
 	mdss_dsi_unprepare_clocks();
 
+	/* disable DSI controller */
+	mdss_dsi_controller_cfg(0, pdata);
+
 	ret = mdss_dsi_panel_power_on(0);
 	if (ret) {
 		pr_err("%s: Panel power off failed\n", __func__);
@@ -232,11 +240,13 @@
 
 	pinfo = &pdata->panel_info;
 
-	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x118, 1);
-	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x118, 0);
+	ret = mdss_dsi_panel_power_on(1);
+	if (ret) {
+		pr_err("%s: Panel power on failed\n", __func__);
+		return ret;
+	}
 
 	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();
@@ -312,12 +322,6 @@
 		wmb();
 	}
 
-	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__);
@@ -481,6 +485,7 @@
 
 	(ctrl_pdata->panel_data).on = mdss_dsi_on;
 	(ctrl_pdata->panel_data).off = mdss_dsi_off;
+	(ctrl_pdata->panel_data).intf_unprepare = mdss_dsi_ctrl_unprepare;
 	memcpy(&((ctrl_pdata->panel_data).panel_info),
 				&(panel_data->panel_info),
 				       sizeof(struct mdss_panel_info));
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index e47891e..5d0d578 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -861,6 +861,16 @@
 			       sleep_us, timeout_us))
 		pr_info("%s: FIFO status=%x failed\n", __func__, status);
 
+	/* Check for VIDEO_MODE_ENGINE_BUSY */
+	if (readl_poll_timeout(((ctrl_pdata->ctrl_base) + 0x0008),
+			   status,
+			   ((status & 0x08) == 0),
+			       sleep_us, timeout_us)) {
+		pr_debug("%s: DSI status=%x\n", __func__, status);
+		pr_debug("%s: Doing sw reset\n", __func__);
+		mdss_dsi_sw_reset(pdata);
+	}
+
 	dsi_ctrl = MIPI_INP((ctrl_pdata->ctrl_base) + 0x0004);
 	if (enable)
 		dsi_ctrl |= 0x01;
@@ -884,14 +894,21 @@
 		return;
 	}
 
-
 	dsi_ctrl = MIPI_INP((ctrl_pdata->ctrl_base) + 0x0004);
-	dsi_ctrl &= ~0x07;
+	/*If Video enabled, Keep Video and Cmd mode ON */
+	if (dsi_ctrl & 0x02)
+		dsi_ctrl &= ~0x05;
+	else
+		dsi_ctrl &= ~0x07;
+
 	if (mode == DSI_VIDEO_MODE) {
 		dsi_ctrl |= 0x03;
 		intr_ctrl = DSI_INTR_CMD_DMA_DONE_MASK;
 	} else {		/* command mode */
 		dsi_ctrl |= 0x05;
+		if (pdata->panel_info.type == MIPI_VIDEO_PANEL)
+			dsi_ctrl |= 0x02;
+
 		intr_ctrl = DSI_INTR_CMD_DMA_DONE_MASK | DSI_INTR_ERROR_MASK |
 				DSI_INTR_CMD_MDP_DONE_MASK;
 	}
@@ -1102,6 +1119,7 @@
 		mdss_dsi_buf_init(tp);
 		mdss_dsi_cmd_dma_add(tp, pkt_size_cmd);
 		mdss_dsi_cmd_dma_tx(tp, pdata);
+		pr_debug("%s: Max packet size sent\n", __func__);
 	}
 
 	mdss_dsi_buf_init(tp);
@@ -1161,6 +1179,7 @@
 		rp->len -= diff; /* align bytes */
 		break;
 	default:
+		pr_debug("%s: Unknown cmd received\n", __func__);
 		break;
 	}
 
@@ -1261,6 +1280,8 @@
 	for (i = 0; i < cnt; i++) {
 		data = (u32)MIPI_INP((ctrl_pdata->ctrl_base) + off);
 		*lp++ = ntohl(data);	/* to network byte order */
+		pr_debug("%s: data = 0x%x and ntohl(data) = 0x%x\n",
+					 __func__, data, ntohl(data));
 		off -= 4;
 		rp->len += sizeof(*lp);
 	}
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
index 63ad5cc..b247e4d 100644
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -40,20 +40,6 @@
 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)
@@ -64,13 +50,20 @@
 		pr_debug("%s:%d, reset line not configured\n",
 			   __func__, __LINE__);
 
+	pr_debug("%s: enable = %d\n", __func__, enable);
+
 	if (enable) {
-		gpio_set_value(disp_en, 1);
 		gpio_set_value(rst_gpio, 1);
-		usleep(10);
+		msleep(20);
+		wmb();
 		gpio_set_value(rst_gpio, 0);
-		usleep(200);
+		udelay(200);
+		wmb();
 		gpio_set_value(rst_gpio, 1);
+		msleep(20);
+		wmb();
+		gpio_set_value(disp_en, 1);
+		wmb();
 	} else {
 		gpio_set_value(rst_gpio, 0);
 		gpio_set_value(disp_en, 0);
@@ -113,7 +106,7 @@
 	pr_debug("%s:%d, debug info (mode) : %d\n", __func__, __LINE__,
 		 mipi->mode);
 
-	mdss_dsi_panel_reset(1);
+	mdss_dsi_sw_reset(pdata);
 
 	if (mipi->mode == DSI_VIDEO_MODE) {
 		mdss_dsi_cmds_tx(pdata, &dsi_panel_tx_buf, dsi_panel_on_cmds,
@@ -142,8 +135,6 @@
 		return -EINVAL;
 	}
 
-	mdss_dsi_panel_reset(0);
-
 	return 0;
 }
 
@@ -202,14 +193,6 @@
 		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",
@@ -328,7 +311,7 @@
 	panel_data->panel_info.mipi.frame_rate = (!rc ? tmp : 60);
 
 	data = of_get_property(np, "qcom,panel-phy-regulatorSettings", &len);
-	if ((!data) || (len != 8)) {
+	if ((!data) || (len != 7)) {
 		pr_err("%s:%d, Unable to read Phy regulator settings",
 		       __func__, __LINE__);
 		goto error;
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 06d8769..3bef9b3 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -326,7 +326,6 @@
 	struct fb_info *fbi;
 	int ret, i;
 	int result = 0;
-	console_lock();
 	for (i = 0; i < fbi_list_index; i++) {
 		fbi = fbi_list[i];
 		fb_set_suspend(fbi, FBINFO_STATE_SUSPENDED);
@@ -337,7 +336,6 @@
 			result = ret;
 		}
 	}
-	console_unlock();
 	return result;
 }
 
@@ -347,7 +345,6 @@
 	int ret, i;
 	int result = 0;
 
-	console_lock();
 	for (i = 0; i < fbi_list_index; i++) {
 		fbi = fbi_list[i];
 
@@ -355,7 +352,6 @@
 		if (ret == 0)
 			fb_set_suspend(fbi, FBINFO_STATE_RUNNING);
 	}
-	console_unlock();
 	return result;
 }
 
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 3fb70bd..63df84c 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -931,11 +931,11 @@
 	mutex_lock(&mdp_suspend_mutex);
 	mdss_res->suspend = false;
 	mutex_unlock(&mdp_suspend_mutex);
+	mdss_hw_init(mdata);
 	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
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index 26fbca1..f72ff8d 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -494,6 +494,11 @@
 	}
 	ctl = mfd->ctl;
 
+	if (ctl->power_on) {
+		WARN(1, "already on!\n");
+		return 0;
+	}
+
 	mutex_lock(&ctl->lock);
 
 	ctl->power_on = true;
@@ -571,12 +576,30 @@
 
 	ctl = mfd->ctl;
 
+	if (!ctl->power_on) {
+		WARN(1, "already off!\n");
+		return 0;
+	}
+
 	pr_debug("ctl_num=%d\n", mfd->ctl->num);
 
+	mdss_mdp_overlay_release_all(mfd);
+
+	/* request bus bandwidth for panel commands */
+	ctl->bus_ib_quota = SZ_1M;
+	mdss_mdp_ctl_perf_commit(MDSS_MDP_PERF_UPDATE_ALL);
+
 	mutex_lock(&ctl->lock);
 	ctl->power_on = false;
 
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+
+	if (pdata->intf_unprepare)
+		ret = pdata->intf_unprepare(pdata);
+
+	if (ret)
+		pr_err("%s: intf_unprepare failed\n", __func__);
+
 	if (ctl->stop_fnc)
 		ret = ctl->stop_fnc(ctl);
 	else
@@ -586,6 +609,7 @@
 		pr_warn("error powering off intf ctl=%d\n", ctl->num);
 
 	ret = pdata->off(pdata);
+
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 
 	ctl->play_cnt = 0;
@@ -594,8 +618,6 @@
 
 	mutex_unlock(&ctl->lock);
 
-	mdss_mdp_overlay_release_all(mfd);
-
 	if (!mfd->ref_cnt)
 		mdss_mdp_ctl_destroy(mfd);
 
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index 5d8dd86..fed7d21 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -274,6 +274,7 @@
 	}
 
 	if (ctx->timegen_en) {
+		INIT_COMPLETION(ctx->pp_comp);
 		pr_debug("waiting for ping pong %d done\n", ctx->pp_num);
 		mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num);
 		wait_for_completion_interruptible(&ctx->pp_comp);
@@ -312,7 +313,7 @@
 		wmb();
 	}
 
-	wait_for_completion_interruptible(&ctx->vsync_comp);
+	wait_for_completion(&ctx->vsync_comp);
 	if (!ctx->vsync_handler)
 		mdss_mdp_irq_disable(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num);
 	mutex_unlock(&ctx->vsync_lock);
diff --git a/drivers/video/msm/mdss/mdss_mdp_wb.c b/drivers/video/msm/mdss/mdss_mdp_wb.c
index bd5f464..b0a67938 100644
--- a/drivers/video/msm/mdss/mdss_mdp_wb.c
+++ b/drivers/video/msm/mdss/mdss_mdp_wb.c
@@ -388,7 +388,7 @@
 		ret = -ENOBUFS;
 	}
 	mutex_unlock(&wb->lock);
-	return 0;
+	return ret;
 }
 
 static void mdss_mdp_wb_callback(void *arg)
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
index f1a4e50..5cdfe34 100644
--- a/drivers/video/msm/mdss/mdss_panel.h
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -86,7 +86,7 @@
 
 /* DSI PHY configuration */
 struct mdss_dsi_phy_ctrl {
-	uint32_t regulator[8];
+	uint32_t regulator[7];
 	uint32_t timing[12];
 	uint32_t ctrl[4];
 	uint32_t strength[2];
@@ -180,6 +180,7 @@
 	struct mdss_panel_info panel_info;
 	void (*set_backlight) (struct mdss_panel_data *pdata,
 							u32 bl_level);
+	int (*intf_unprepare) (struct mdss_panel_data *pdata);
 	unsigned char *mmss_cc_base;
 
 	/* function entry chain */
diff --git a/drivers/video/msm/mdss/msm_mdss_io_8974.c b/drivers/video/msm/mdss/msm_mdss_io_8974.c
index 545d53c..1232ec6 100644
--- a/drivers/video/msm/mdss/msm_mdss_io_8974.c
+++ b/drivers/video/msm/mdss/msm_mdss_io_8974.c
@@ -212,25 +212,34 @@
 {
 	/* start phy sw reset */
 	MIPI_OUTP(ctrl_base + 0x12c, 0x0001);
+	udelay(1000);
 	wmb();
-	usleep(1);
 	/* end phy sw reset */
 	MIPI_OUTP(ctrl_base + 0x12c, 0x0000);
+	udelay(100);
 	wmb();
-	usleep(1);
 }
 
 void mdss_dsi_phy_enable(unsigned char *ctrl_base, int on)
 {
 	if (on) {
+		MIPI_OUTP(ctrl_base + 0x03cc, 0x03);
+		wmb();
+		usleep(100);
 		MIPI_OUTP(ctrl_base + 0x0220, 0x006);
-		usleep(10);
+		wmb();
+		usleep(100);
 		MIPI_OUTP(ctrl_base + 0x0268, 0x001);
-		usleep(10);
+		wmb();
+		usleep(100);
 		MIPI_OUTP(ctrl_base + 0x0268, 0x000);
-		usleep(10);
+		wmb();
+		usleep(100);
 		MIPI_OUTP(ctrl_base + 0x0220, 0x007);
 		wmb();
+		MIPI_OUTP(ctrl_base + 0x03cc, 0x01);
+		wmb();
+		usleep(100);
 
 		/* MMSS_DSI_0_PHY_DSIPHY_CTRL_0 */
 		MIPI_OUTP(ctrl_base + 0x0470, 0x07e);
@@ -266,12 +275,25 @@
 
 	pd = ((ctrl_pdata->panel_data).panel_info.mipi).dsi_phy_db;
 
+	/* Strength ctrl 0 */
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0484, 0x07);
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0484, pd->strength[0]);
+
 	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;
-	}
+	/* Regulator ctrl - CAL_PWD_CFG */
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 6), pd->regulator[6]);
+	/* Regulator ctrl - TEST */
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 5), pd->regulator[5]);
+	/* Regulator ctrl 3 */
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 3), pd->regulator[3]);
+	/* Regulator ctrl 2 */
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 2), pd->regulator[2]);
+	/* Regulator ctrl 1 */
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 1), pd->regulator[1]);
+	/* Regulator ctrl 0 */
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 0), pd->regulator[0]);
+	/* Regulator ctrl 4 */
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 4), pd->regulator[4]);
 
 	off = 0x0440;	/* phy timing ctrl 0 - 11 */
 	for (i = 0; i < 12; i++) {
@@ -280,17 +302,15 @@
 		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]);
+	/* MMSS_DSI_0_PHY_DSIPHY_CTRL_1 */
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0474, 0x00);
+	/* MMSS_DSI_0_PHY_DSIPHY_CTRL_0 */
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0470, 0x5f);
 	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;
-	}
+	/* Strength ctrl 1 */
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0488, pd->strength[1]);
+	wmb();
 
 	/* 4 lanes + clk lane configuration */
 	/* lane config n * (0 - 4) & DataPath setup */
@@ -304,4 +324,20 @@
 			off += 4;
 		}
 	}
+
+	/* MMSS_DSI_0_PHY_DSIPHY_CTRL_0 */
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0470, 0x7f);
+	wmb();
+
+	/* DSI_0_PHY_DSIPHY_GLBL_TEST_CTRL */
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x04d4, 0x01);
+	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;
+	}
+
 }
diff --git a/drivers/video/msm/mhl/mhl_8334.c b/drivers/video/msm/mhl/mhl_8334.c
index f3b8cd1..6c0778f 100644
--- a/drivers/video/msm/mhl/mhl_8334.c
+++ b/drivers/video/msm/mhl/mhl_8334.c
@@ -62,6 +62,9 @@
 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 void list_cmd_put(struct msc_command_struct *cmd);
+static struct msc_command_struct *list_cmd_get(void);
+static void mhl_msc_send_work(struct work_struct *work);
 
 static struct i2c_driver mhl_sii_i2c_driver = {
 	.driver = {
@@ -618,7 +621,7 @@
 	list_add_tail(&new_cmd->msc_queue_envelope, &mhl_msm_state->list_cmd);
 }
 
-struct msc_command_struct *list_cmd_get(void)
+static struct msc_command_struct *list_cmd_get(void)
 {
 	struct msc_cmd_envelope *cmd_env =
 		list_first_entry(&mhl_msm_state->list_cmd,
diff --git a/drivers/video/msm/mipi_NT35510.c b/drivers/video/msm/mipi_NT35510.c
index 0c6ff79..d75198a 100644
--- a/drivers/video/msm/mipi_NT35510.c
+++ b/drivers/video/msm/mipi_NT35510.c
@@ -32,8 +32,8 @@
 static char write_ram[2] = {0x2c, 0x00}; /* write ram */
 
 static struct dsi_cmd_desc nt35510_display_off_cmds[] = {
-	{DTYPE_DCS_WRITE, 1, 0, 0, 150, sizeof(display_off), display_off},
-	{DTYPE_DCS_WRITE, 1, 0, 0, 150, sizeof(enter_sleep), enter_sleep}
+	{DTYPE_DCS_WRITE, 1, 0, 0, 50, sizeof(display_off), display_off},
+	{DTYPE_DCS_WRITE, 1, 0, 0, 50, sizeof(enter_sleep), enter_sleep}
 };
 
 static char cmd0[6] = {
@@ -213,46 +213,46 @@
 };
 static char config_MADCTL[2] = {0x36, 0x00};
 static struct dsi_cmd_desc nt35510_cmd_display_on_cmds[] = {
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd0), cmd0},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd1), cmd1},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd2), cmd2},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd3), cmd3},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd4), cmd4},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd5), cmd5},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd6), cmd6},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd7), cmd7},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd8), cmd8},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd9), cmd9},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd10), cmd10},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd11), cmd11},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd12), cmd12},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd13), cmd13},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd14), cmd14},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd15), cmd15},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd16), cmd16},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd17), cmd17},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd18), cmd18},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd19), cmd19},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd20), cmd20},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd21), cmd21},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd22), cmd22},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd23), cmd23},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd24), cmd24},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd25), cmd25},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd26), cmd26},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd27), cmd27},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd0), cmd0},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd1), cmd1},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd2), cmd2},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd3), cmd3},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd4), cmd4},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd5), cmd5},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd6), cmd6},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd7), cmd7},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd8), cmd8},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd9), cmd9},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd10), cmd10},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd11), cmd11},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd12), cmd12},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd13), cmd13},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd14), cmd14},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd15), cmd15},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd16), cmd16},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd17), cmd17},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd18), cmd18},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd19), cmd19},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd20), cmd20},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd21), cmd21},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd22), cmd22},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd23), cmd23},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd24), cmd24},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd25), cmd25},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd26), cmd26},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd27), cmd27},
 
-	{DTYPE_DCS_WRITE, 1, 0, 0, 150,	sizeof(exit_sleep), exit_sleep},
-	{DTYPE_DCS_WRITE, 1, 0, 0, 10,	sizeof(display_on), display_on},
+	{DTYPE_DCS_WRITE, 1, 0, 0, 0,	sizeof(exit_sleep), exit_sleep},
+	{DTYPE_DCS_WRITE, 1, 0, 0, 0,	sizeof(display_on), display_on},
 
-	{DTYPE_DCS_WRITE1, 1, 0, 0, 150,
+	{DTYPE_DCS_WRITE1, 1, 0, 0, 0,
 		sizeof(config_MADCTL), config_MADCTL},
 
-	{DTYPE_DCS_WRITE, 1, 0, 0, 10,	sizeof(write_ram), write_ram},
+	{DTYPE_DCS_WRITE, 1, 0, 0, 0,	sizeof(write_ram), write_ram},
 };
 
 static struct dsi_cmd_desc nt35510_cmd_display_on_cmds_rotate[] = {
-	{DTYPE_DCS_LWRITE, 1, 0, 0, 50,
+	{DTYPE_DCS_LWRITE, 1, 0, 0, 0,
 		sizeof(cmd19_rotate), cmd19_rotate},
 };
 
@@ -430,34 +430,34 @@
 };
 static char config_video_MADCTL[2] = {0x36, 0xC0};
 static struct dsi_cmd_desc nt35510_video_display_on_cmds[] = {
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video0), video0},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video1), video1},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video2), video2},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video3), video3},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video4), video4},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video5), video5},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video6), video6},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video7), video7},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video8), video8},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video9), video9},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video10), video10},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video11), video11},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video12), video12},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video13), video13},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video14), video14},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video15), video15},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video16), video16},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video17), video17},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video18), video18},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video19), video19},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video20), video20},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video21), video21},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video22), video22},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video23), video23},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video24), video24},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video25), video25},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video26), video26},
-	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video27), video27},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video0), video0},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video1), video1},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video2), video2},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video3), video3},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video4), video4},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video5), video5},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video6), video6},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video7), video7},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video8), video8},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video9), video9},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video10), video10},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video11), video11},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video12), video12},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video13), video13},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video14), video14},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video15), video15},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video16), video16},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video17), video17},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video18), video18},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video19), video19},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video20), video20},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video21), video21},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video22), video22},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video23), video23},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video24), video24},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video25), video25},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video26), video26},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video27), video27},
 	{DTYPE_DCS_WRITE, 1, 0, 0, NT35510_SLEEP_OFF_DELAY, sizeof(exit_sleep),
 			exit_sleep},
 	{DTYPE_DCS_WRITE, 1, 0, 0, NT35510_DISPLAY_ON_DELAY, sizeof(display_on),
@@ -465,7 +465,7 @@
 };
 
 static struct dsi_cmd_desc nt35510_video_display_on_cmds_rotate[] = {
-	{DTYPE_DCS_WRITE1, 1, 0, 0, 150,
+	{DTYPE_DCS_WRITE1, 1, 0, 0, 0,
 		sizeof(config_video_MADCTL), config_video_MADCTL},
 };
 static int mipi_nt35510_lcd_on(struct platform_device *pdev)
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 3620f1a..2af76f3 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_errors.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_errors.c
@@ -70,7 +70,6 @@
 	case VIDC_1080P_ERROR_MEM_ALLOCATION_FAILED:
 	case VIDC_1080P_ERROR_INSUFFICIENT_CONTEXT_SIZE:
 	case VIDC_1080P_ERROR_DIVIDE_BY_ZERO:
-	case VIDC_1080P_ERROR_DESCRIPTOR_BUFFER_EMPTY:
 	case VIDC_1080P_ERROR_DMA_TX_NOT_COMPLETE:
 	case VIDC_1080P_ERROR_VSP_NOT_READY:
 	case VIDC_1080P_ERROR_BUFFER_FULL_STATE:
@@ -242,6 +241,7 @@
 	case VIDC_1080P_ERROR_HEADER_NOT_FOUND:
 	case VIDC_1080P_ERROR_SLICE_PARSE_ERROR:
 	case VIDC_1080P_ERROR_NON_PAIRED_FIELD_NOT_SUPPORTED:
+	case VIDC_1080P_ERROR_DESCRIPTOR_BUFFER_EMPTY:
 		vcd_status = VCD_ERR_BITSTREAM_ERR;
 		DDL_MSG_ERROR("VIDC_BIT_STREAM_ERR");
 		break;
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 4f19de9..d94bc5b 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
@@ -1258,6 +1258,8 @@
 				output_vcd_frm->flags |=
 					VCD_FRAME_FLAG_DATACORRUPT;
 		}
+		if (decoder->codec.codec != VCD_CODEC_H264)
+			output_vcd_frm->flags &= ~VCD_FRAME_FLAG_DATACORRUPT;
 		output_vcd_frm->ip_frm_tag = dec_disp_info->tag_top;
 		vidc_sm_get_picture_times(&ddl->shared_mem
 			[ddl->command_channel],
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index 45d51ce..288ed43 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -109,7 +109,7 @@
 /* This needs to be modified manually now, when we add
  a new RANGE of SSIDs to the msg_mask_tbl */
 #define MSG_MASK_TBL_CNT		24
-#define EVENT_LAST_ID			0x08AD
+#define EVENT_LAST_ID			0x08C5
 
 #define MSG_SSID_0			0
 #define MSG_SSID_0_LAST			93
diff --git a/include/linux/dvb/dmx.h b/include/linux/dvb/dmx.h
index d19dfa5..257e069 100644
--- a/include/linux/dvb/dmx.h
+++ b/include/linux/dvb/dmx.h
@@ -307,6 +307,22 @@
 	} params;
 };
 
+/* Filter's buffer requirement returned in dmx_caps */
+struct dmx_buffer_requirement {
+	/* Buffer size alignment, 0 means no special requirement */
+	__u32 size_alignment;
+
+	/* Maximum buffer size allowed */
+	__u32 max_size;
+	__u32 flags;
+
+/* Buffer allocated as physically contiguous memory */
+#define DMX_BUFFER_CONTIGEOUS_MEM			0x1
+
+/* If the filter's data is decrypted, the buffer should be secured one */
+#define DMX_BUFFER_SECURED_IF_DECRYPTED		0x2
+};
+
 typedef struct dmx_caps {
 	__u32 caps;
 
@@ -363,6 +379,23 @@
 
 	/* Max bitrate from single memory input. Mbit/sec */
 	int memory_input_max_bitrate;
+
+	struct dmx_buffer_requirement section;
+
+	/* For PES not sent to decoder */
+	struct dmx_buffer_requirement pes;
+
+	/* Recording buffer for recording of 188 bytes packets */
+	struct dmx_buffer_requirement recording_188_tsp;
+
+	/* Recording buffer for recording of 192 bytes packets */
+	struct dmx_buffer_requirement recording_192_tsp;
+
+	/* DVR input buffer for playback of 188 bytes packets */
+	struct dmx_buffer_requirement playback_188_tsp;
+
+	/* DVR input buffer for playback of 192 bytes packets */
+	struct dmx_buffer_requirement playback_192_tsp;
 } dmx_caps_t;
 
 typedef enum {
@@ -410,6 +443,28 @@
 	__u64 stc;		/* output: stc in 'base'*90 kHz units */
 };
 
+enum dmx_buffer_mode {
+	/*
+	 * demux buffers are allocated internally
+	 * by the demux driver. This is the default mode.
+	 * DMX_SET_BUFFER_SIZE can be used to set the size of
+	 * this buffer.
+	 */
+	DMX_BUFFER_MODE_INTERNAL,
+
+	/*
+	 * demux buffers are allocated externally and provided
+	 * to demux through DMX_SET_BUFFER.
+	 * When this mode is used DMX_SET_BUFFER_SIZE and
+	 * mmap are prohibited.
+	 */
+	DMX_BUFFER_MODE_EXTERNAL,
+};
+
+struct dmx_buffer {
+	unsigned int size;
+	int handle;
+};
 
 #define DMX_START                _IO('o', 41)
 #define DMX_STOP                 _IO('o', 42)
@@ -430,5 +485,7 @@
 #define DMX_FEED_DATA			 _IO('o', 58)
 #define DMX_SET_PLAYBACK_MODE	 _IOW('o', 59, enum dmx_playback_mode_t)
 #define DMX_GET_EVENT			 _IOR('o', 60, struct dmx_filter_event)
+#define DMX_SET_BUFFER_MODE		 _IOW('o', 61, enum dmx_buffer_mode)
+#define DMX_SET_BUFFER			 _IOW('o', 62, struct dmx_buffer)
 
 #endif /*_DVBDMX_H_*/
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 19ca831..a80eb59 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -83,9 +83,6 @@
 	unsigned int            data_tag_unit_size;     /* DATA TAG UNIT size */
 	unsigned int		boot_ro_lock;		/* ro lock support */
 	bool			boot_ro_lockable;
-	bool			bkops;		/* background support bit */
-	bool			bkops_en;	/* background enable bit */
-	u8			raw_exception_status;	/* 53 */
 	u8			raw_partition_support;	/* 160 */
 	u8			raw_erased_mem_count;	/* 181 */
 	u8			raw_ext_csd_structure;	/* 194 */
@@ -99,7 +96,6 @@
 	u8			raw_sec_erase_mult;	/* 230 */
 	u8			raw_sec_feature_support;/* 231 */
 	u8			raw_trim_mult;		/* 232 */
-	u8			raw_bkops_status;	/* 246 */
 	u8			raw_sectors[4];		/* 212 - 4 bytes */
 
 	unsigned int            feature_support;
@@ -251,9 +247,6 @@
 #define MMC_CARD_REMOVED	(1<<7)		/* card has been removed */
 #define MMC_STATE_HIGHSPEED_200	(1<<8)		/* card is in HS200 mode */
 #define MMC_STATE_SLEEP		(1<<9)		/* card is in sleep state */
-#define MMC_STATE_NEED_BKOPS	(1<<10)		/* card need to do BKOPS */
-#define MMC_STATE_DOING_BKOPS	(1<<11)		/* card is doing BKOPS */
-#define MMC_STATE_CHECK_BKOPS	(1<<12)		/* card need to check BKOPS */
 	unsigned int		quirks; 	/* card quirks */
 #define MMC_QUIRK_LENIENT_FN0	(1<<0)		/* allow SDIO FN0 writes outside of the VS CCCR range */
 #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)	/* use func->cur_blksize */
@@ -422,9 +415,6 @@
 #define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC)
 #define mmc_card_removed(c)	((c) && ((c)->state & MMC_CARD_REMOVED))
 #define mmc_card_is_sleep(c)	((c)->state & MMC_STATE_SLEEP)
-#define mmc_card_need_bkops(c)	((c)->state & MMC_STATE_NEED_BKOPS)
-#define mmc_card_doing_bkops(c)	((c)->state & MMC_STATE_DOING_BKOPS)
-#define mmc_card_check_bkops(c) ((c)->state & MMC_STATE_CHECK_BKOPS)
 
 #define mmc_card_set_present(c)	((c)->state |= MMC_STATE_PRESENT)
 #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
@@ -437,13 +427,7 @@
 #define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC)
 #define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED)
 #define mmc_card_set_sleep(c)	((c)->state |= MMC_STATE_SLEEP)
-#define mmc_card_set_need_bkops(c)	((c)->state |= MMC_STATE_NEED_BKOPS)
-#define mmc_card_set_doing_bkops(c)	((c)->state |= MMC_STATE_DOING_BKOPS)
-#define mmc_card_set_check_bkops(c) ((c)->state |= MMC_STATE_CHECK_BKOPS)
 
-#define mmc_card_clr_need_bkops(c)	((c)->state &= ~MMC_STATE_NEED_BKOPS)
-#define mmc_card_clr_doing_bkops(c)	((c)->state &= ~MMC_STATE_DOING_BKOPS)
-#define mmc_card_clr_check_bkops(c) ((c)->state &= ~MMC_STATE_CHECK_BKOPS)
 #define mmc_card_clr_sleep(c)	((c)->state &= ~MMC_STATE_SLEEP)
 /*
  * Quirk add/remove for MMC products.
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index 338c891..817862f 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -138,9 +138,6 @@
 struct mmc_card;
 struct mmc_async_req;
 
-extern int mmc_interrupt_bkops(struct mmc_card *);
-extern int mmc_read_bkops_status(struct mmc_card *);
-extern int mmc_is_exception_event(struct mmc_card *, unsigned int);
 extern struct mmc_async_req *mmc_start_req(struct mmc_host *,
 					   struct mmc_async_req *, int *);
 extern int mmc_interrupt_hpi(struct mmc_card *);
@@ -172,7 +169,6 @@
 extern int mmc_can_poweroff_notify(const struct mmc_card *card);
 extern int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from,
 				   unsigned int nr);
-extern void mmc_start_bkops(struct mmc_card *card);
 extern unsigned int mmc_calc_max_discard(struct mmc_card *card);
 
 extern int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen);
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 05a6b5b..dcd9a6f 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -247,8 +247,6 @@
 				 MMC_CAP2_PACKED_WR) /* Allow packed commands */
 #define MMC_CAP2_PACKED_WR_CONTROL (1 << 12) /* Allow write packing control */
 #define MMC_CAP2_SANITIZE	(1 << 13)		/* Support Sanitize */
-#define MMC_CAP2_BKOPS		    (1 << 14)	/* BKOPS supported */
-#define MMC_CAP2_INIT_BKOPS	    (1 << 15)	/* Need to set BKOPS_EN */
 #define MMC_CAP2_POWER_OFF_VCCQ_DURING_SUSPEND	(1 << 16)
 
 	mmc_pm_flag_t		pm_caps;	/* supported pm features */
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index b867c62..ce4d3c2 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -139,7 +139,6 @@
 #define R1_CURRENT_STATE(x)	((x & 0x00001E00) >> 9)	/* sx, b (4 bits) */
 #define R1_READY_FOR_DATA	(1 << 8)	/* sx, a */
 #define R1_SWITCH_ERROR		(1 << 7)	/* sx, c */
-#define R1_EXCEPTION_EVENT	(1 << 6)	/* sx, a */
 #define R1_APP_CMD		(1 << 5)	/* sr, c */
 #define R1_EXP_EVENT		(1 << 6)	/* sr, a */
 
@@ -287,8 +286,6 @@
 #define EXT_CSD_PARTITION_SUPPORT	160	/* RO */
 #define EXT_CSD_HPI_MGMT		161	/* R/W */
 #define EXT_CSD_RST_N_FUNCTION		162	/* R/W */
-#define EXT_CSD_BKOPS_EN		163	/* R/W */
-#define EXT_CSD_BKOPS_START		164	/* W */
 #define EXT_CSD_SANITIZE_START		165     /* W */
 #define EXT_CSD_WR_REL_PARAM		166	/* RO */
 #define EXT_CSD_BOOT_WP			173	/* R/W */
@@ -322,7 +319,6 @@
 #define EXT_CSD_PWR_CL_200_360		237	/* RO */
 #define EXT_CSD_PWR_CL_DDR_52_195	238	/* RO */
 #define EXT_CSD_PWR_CL_DDR_52_360	239	/* RO */
-#define EXT_CSD_BKOPS_STATUS		246	/* RO */
 #define EXT_CSD_POWER_OFF_LONG_TIME	247	/* RO */
 #define EXT_CSD_GENERIC_CMD6_TIME	248	/* RO */
 #define EXT_CSD_CACHE_SIZE		249	/* RO, 4 bytes */
@@ -330,7 +326,6 @@
 #define EXT_CSD_DATA_TAG_SUPPORT	499	/* RO */
 #define EXT_CSD_MAX_PACKED_WRITES	500	/* RO */
 #define EXT_CSD_MAX_PACKED_READS	501	/* RO */
-#define EXT_CSD_BKOPS_SUPPORT		502	/* RO */
 #define EXT_CSD_HPI_FEATURES		503	/* RO */
 
 /*
@@ -423,16 +418,4 @@
 #define MMC_PW_OFF_NOTIFY_SHORT		1
 #define MMC_PW_OFF_NOTIFY_LONG		2
 
-/*
- * BKOPS status level
- */
-#define EXT_CSD_BKOPS_LEVEL_2		0x2
-
-/*
- * EXCEPTION_EVENT_STATUS field (eMMC4.5)
- */
-#define EXT_CSD_URGENT_BKOPS		BIT(0)
-#define EXT_CSD_DYNCAP_NEEDED		BIT(1)
-#define EXT_CSD_SYSPOOL_EXHAUSTED	BIT(2)
-
 #endif /* LINUX_MMC_MMC_H */
diff --git a/include/linux/msm_kgsl.h b/include/linux/msm_kgsl.h
index 2253655..71ff639 100644
--- a/include/linux/msm_kgsl.h
+++ b/include/linux/msm_kgsl.h
@@ -2,7 +2,7 @@
 #define _MSM_KGSL_H
 
 #define KGSL_VERSION_MAJOR        3
-#define KGSL_VERSION_MINOR        11
+#define KGSL_VERSION_MINOR        12
 
 /*context flags */
 #define KGSL_CONTEXT_SAVE_GMEM		0x00000001
@@ -432,7 +432,8 @@
 
 /*
  * A timestamp event allows the user space to register an action following an
- * expired timestamp.
+ * expired timestamp. Note IOCTL_KGSL_TIMESTAMP_EVENT has been redefined to
+ * _IOWR to support fences which need to return a fd for the priv parameter.
  */
 
 struct kgsl_timestamp_event {
@@ -443,7 +444,7 @@
 	size_t len;              /* Size of the event specific blob */
 };
 
-#define IOCTL_KGSL_TIMESTAMP_EVENT \
+#define IOCTL_KGSL_TIMESTAMP_EVENT_OLD \
 	_IOW(KGSL_IOC_TYPE, 0x31, struct kgsl_timestamp_event)
 
 /* A genlock timestamp event releases an existing lock on timestamp expire */
@@ -454,6 +455,14 @@
 	int handle; /* Handle of the genlock lock to release */
 };
 
+/* A fence timestamp event releases an existing lock on timestamp expire */
+
+#define KGSL_TIMESTAMP_EVENT_FENCE 2
+
+struct kgsl_timestamp_event_fence {
+	int fence_fd; /* Fence to signal */
+};
+
 /*
  * Set a property within the kernel.  Uses the same structure as
  * IOCTL_KGSL_GETPROPERTY
@@ -462,6 +471,9 @@
 #define IOCTL_KGSL_SETPROPERTY \
 	_IOW(KGSL_IOC_TYPE, 0x32, struct kgsl_device_getproperty)
 
+#define IOCTL_KGSL_TIMESTAMP_EVENT \
+	_IOWR(KGSL_IOC_TYPE, 0x33, struct kgsl_timestamp_event)
+
 #ifdef __KERNEL__
 #ifdef CONFIG_MSM_KGSL_DRM
 int kgsl_gem_obj_addr(int drm_fd, int handle, unsigned long *start,
diff --git a/include/linux/qpnp/power-on.h b/include/linux/qpnp/power-on.h
new file mode 100644
index 0000000..85dbce9
--- /dev/null
+++ b/include/linux/qpnp/power-on.h
@@ -0,0 +1,24 @@
+/* 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 QPNP_PON_H
+#define QPNP_PON_H
+
+#include <linux/errno.h>
+
+#ifdef CONFIG_QPNP_POWER_ON
+int qpnp_pon_system_pwr_off(bool reset);
+#else
+static int qpnp_pon_system_pwr_off(bool reset) { return -ENODEV; }
+#endif
+
+#endif
diff --git a/include/linux/slimbus/slimbus.h b/include/linux/slimbus/slimbus.h
index d365b15..e333235 100644
--- a/include/linux/slimbus/slimbus.h
+++ b/include/linux/slimbus/slimbus.h
@@ -143,10 +143,15 @@
  * struct slim_addrt: slimbus address used internally by the slimbus framework.
  * @valid: If the device is still there or if the address can be reused.
  * @eaddr: 6-bytes-long elemental address
+ * @laddr: It is possible that controller will set a predefined logical address
+ *	rather than the one assigned by framework. (i.e. logical address may
+ *	not be same as index into this table). This entry will store the
+ *	logical address value for this enumeration address.
  */
 struct slim_addrt {
 	bool	valid;
 	u8	eaddr[6];
+	u8	laddr;
 };
 
 /*
@@ -498,6 +503,11 @@
  * @set_laddr: Setup logical address at laddr for the slave with elemental
  *	address e_addr. Drivers implementing controller will be expected to
  *	send unicast message to this device with its logical address.
+ * @allocbw: Controller can override default reconfiguration and channel
+ *	scheduling algorithm.
+ * @get_laddr: It is possible that controller needs to set fixed logical
+ *	address table and get_laddr can be used in that case so that controller
+ *	can do this assignment.
  * @wakeup: This function pointer implements controller-specific procedure
  *	to wake it up from clock-pause. Framework will call this to bring
  *	the controller out of clock pause.
@@ -542,6 +552,10 @@
 				struct slim_msg_txn *txn);
 	int			(*set_laddr)(struct slim_controller *ctrl,
 				const u8 *ea, u8 elen, u8 laddr);
+	int			(*allocbw)(struct slim_device *sb,
+				int *subfrmc, int *clkgear);
+	int			(*get_laddr)(struct slim_controller *ctrl,
+				const u8 *ea, u8 elen, u8 *laddr);
 	int			(*wakeup)(struct slim_controller *ctrl);
 	int			(*config_port)(struct slim_controller *ctrl,
 				u8 port);
@@ -979,14 +993,17 @@
  * @ctrl: Controller with which device is enumerated.
  * @e_addr: 6-byte elemental address of the device.
  * @e_len: buffer length for e_addr
- * @laddr: Return logical address.
+ * @laddr: Return logical address (if valid flag is false)
+ * @valid: true if laddr holds a valid address that controller wants to
+ *	set for this enumeration address. Otherwise framework sets index into
+ *	address table as logical address.
  * Called by controller in response to REPORT_PRESENT. Framework will assign
  * a logical address to this enumeration address.
  * Function returns -EXFULL to indicate that all logical addresses are already
  * taken.
  */
 extern int slim_assign_laddr(struct slim_controller *ctrl, const u8 *e_addr,
-				u8 e_len, u8 *laddr);
+				u8 e_len, u8 *laddr, bool valid);
 
 /*
  * slim_msg_response: Deliver Message response received from a device to the
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index adcc450..8e6550f 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -348,7 +348,7 @@
 	/*
 	 * Allowing PHY power collpase turns off the HSUSB 3.3v and 1.8v
 	 * analog regulators while going to low power mode.
-	 * Currently only 8960(28nm PHY) has the support to allowing PHY
+	 * Currently only 28nm PHY has the support to allowing PHY
 	 * power collapse since it doesn't have leakage currents while
 	 * turning off the power rails.
 	 */
@@ -362,12 +362,18 @@
 	   * Allow putting the core in Low Power mode, when
 	   * USB bus is suspended but cable is connected.
 	   */
-#define ALLOW_LPM_ON_DEV_SUSPEND	    BIT(2)
+#define ALLOW_LPM_ON_DEV_SUSPEND	BIT(2)
+	/*
+	 * Allowing PHY regulators LPM puts the HSUSB 3.3v and 1.8v
+	 * analog regulators into LPM while going to USB low power mode.
+	 */
+#define ALLOW_PHY_REGULATORS_LPM	BIT(3)
 	unsigned long lpm_flags;
 #define PHY_PWR_COLLAPSED		BIT(0)
 #define PHY_RETENTIONED			BIT(1)
 #define XO_SHUTDOWN			BIT(2)
 #define CLOCKS_DOWN			BIT(3)
+#define PHY_REGULATORS_LPM	BIT(4)
 	int reset_counter;
 	unsigned long b_last_se0_sess;
 	unsigned long tmouts;
diff --git a/include/media/msm_jpeg.h b/include/media/msm_jpeg.h
index 11c3247..56829f1 100644
--- a/include/media/msm_jpeg.h
+++ b/include/media/msm_jpeg.h
@@ -85,6 +85,8 @@
 
 	uint32_t num_of_mcu_rows;
 	uint32_t offset;
+	uint32_t pln2_off;
+	uint32_t pln2_len;
 };
 
 #define MSM_JPEG_HW_CMD_TYPE_READ      0
diff --git a/include/media/msm_vidc.h b/include/media/msm_vidc.h
index 2efe31c..34464c6 100644
--- a/include/media/msm_vidc.h
+++ b/include/media/msm_vidc.h
@@ -14,8 +14,8 @@
 #ifndef _MSM_VIDC_H_
 #define _MSM_VIDC_H_
 
-#include <linux/videodev2.h>
 #include <linux/poll.h>
+#include <linux/videodev2.h>
 
 enum core_id {
 	MSM_VIDC_CORE_0 = 0,
@@ -28,7 +28,21 @@
 	MSM_VIDC_MAX_DEVICES,
 };
 
-int msm_vidc_open(void *vidc_inst, int core_id, int session_type);
+struct msm_vidc_iommu_info {
+	u32 addr_range[2];
+	char name[64];
+	char ctx[64];
+	int domain;
+	int partition;
+};
+
+enum msm_vidc_io_maps {
+	CP_MAP,
+	NS_MAP,
+	MAX_MAP
+};
+
+void *msm_vidc_open(int core_id, int session_type);
 int msm_vidc_close(void *instance);
 int msm_vidc_querycap(void *instance, struct v4l2_capability *cap);
 int msm_vidc_enum_fmt(void *instance, struct v4l2_fmtdesc *f);
@@ -47,4 +61,12 @@
 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);
+int msm_vidc_get_iommu_maps(void *instance,
+		struct msm_vidc_iommu_info maps[MAX_MAP]);
+int msm_vidc_subscribe_event(void *instance,
+		struct v4l2_event_subscription *sub);
+int msm_vidc_unsubscribe_event(void *instance,
+		struct v4l2_event_subscription *sub);
+int msm_vidc_dqevent(void *instance, struct v4l2_event *event);
+int msm_vidc_wait(void *instance);
 #endif
diff --git a/include/media/vcap_v4l2.h b/include/media/vcap_v4l2.h
index 1e18c9e..b2a538c 100644
--- a/include/media/vcap_v4l2.h
+++ b/include/media/vcap_v4l2.h
@@ -14,7 +14,6 @@
 #ifndef VCAP_V4L2_H
 #define VCAP_V4L2_H
 
-#define TOP_FIELD_FIX
 #ifdef __KERNEL__
 #include <linux/types.h>
 #include <linux/videodev2.h>
@@ -38,6 +37,7 @@
 		writel_relaxed(val, addr);	\
 	} while (0)
 
+#define VCAP_USEC (1000000)
 #define VCAP_BASE (dev->vcapbase)
 #define VCAP_OFFSET(off) (VCAP_BASE + off)
 
@@ -87,6 +87,11 @@
 	uint8_t					tot_buf;
 	uint8_t					buf_num;
 
+	bool					top_field;
+
+	struct timeval			vc_ts;
+	uint32_t				last_ts;
+
 	/* Buffers inside vc */
 	struct vcap_buffer      *buf[6];
 };
@@ -103,9 +108,6 @@
 
 	/* Buffer index */
 	enum vp_state			vp_state;
-#ifdef TOP_FIELD_FIX
-	bool					top_field;
-#endif
 
 	/* Buffers inside vc */
 	struct vcap_buffer      *bufTm1;
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index ac4ec09..1da6aa2 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -242,18 +242,18 @@
  */
 struct adm_cmd_set_pp_params_v5 {
 	struct apr_hdr hdr;
-		u32                  data_payload_addr_lsw;
+	u32		payload_addr_lsw;
 	/* LSW of parameter data payload address.*/
-	u32                  data_payload_addr_msw;
+	u32		payload_addr_msw;
 	/* MSW of parameter data payload address.*/
 
-		u32                  mem_map_handle;
+	u32		mem_map_handle;
 /* Memory map handle returned by ADM_CMD_SHARED_MEM_MAP_REGIONS
  * command */
 /* If mem_map_handle is zero implies the message is in
  * the payload */
 
-	u32                  data_payload_size;
+	u32		payload_size;
 /* Size in bytes of the variable payload accompanying this
  * message or
  * in shared memory. This is used for parsing the parameter
diff --git a/include/trace/events/exception.h b/include/trace/events/exception.h
new file mode 100644
index 0000000..110e920
--- /dev/null
+++ b/include/trace/events/exception.h
@@ -0,0 +1,68 @@
+/* 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.
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM exception
+
+#if !defined(_TRACE_EXCEPTION_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_EXCEPTION_H
+
+#include <linux/tracepoint.h>
+
+struct task_struct;
+
+TRACE_EVENT(user_fault,
+
+	TP_PROTO(struct task_struct *tsk, unsigned long addr, unsigned int fsr),
+
+	TP_ARGS(tsk, addr, fsr),
+
+	TP_STRUCT__entry(
+		__string(task_name, tsk->comm)
+		__field(unsigned long, addr)
+		__field(unsigned int, fsr)
+	),
+
+	TP_fast_assign(
+	__assign_str(task_name, tsk->comm)
+		__entry->addr	= addr;
+		__entry->fsr	= fsr;
+	),
+
+	TP_printk("task_name:%s addr:%lu, fsr:%u", __get_str(task_name),\
+		__entry->addr, __entry->fsr)
+);
+
+struct pt_regs;
+
+TRACE_EVENT(undef_instr,
+
+	TP_PROTO(struct pt_regs *regs, void *prog_cnt),
+
+	TP_ARGS(regs, prog_cnt),
+
+	TP_STRUCT__entry(
+		__field(void *, prog_cnt)
+		__field(struct pt_regs *, regs)
+	),
+
+	TP_fast_assign(
+		__entry->regs		= regs;
+		__entry->prog_cnt	= prog_cnt;
+	),
+
+	TP_printk("pc:%p", __entry->prog_cnt)
+);
+
+#endif
+
+#include <trace/define_trace.h>
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index ac11f1a..a47e446 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -8379,8 +8379,9 @@
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct tabla_priv *tabla = platform_get_drvdata(pdev);
-	dev_dbg(dev, "%s: system resume\n", __func__);
-	tabla->mbhc_last_resume = jiffies;
+	dev_dbg(dev, "%s: system resume tabla %p\n", __func__, tabla);
+	if (tabla)
+		tabla->mbhc_last_resume = jiffies;
 	return 0;
 }
 
diff --git a/sound/soc/msm/apq8064.c b/sound/soc/msm/apq8064.c
index 1041818..80d6e5d 100644
--- a/sound/soc/msm/apq8064.c
+++ b/sound/soc/msm/apq8064.c
@@ -1310,6 +1310,24 @@
 	return 0;
 }
 
+static int msm_slim_4_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);
+
+	rate->min = rate->max = 48000;
+	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)
 {
@@ -1739,6 +1757,48 @@
 		.ignore_pmdown_time = 1,
 		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA5,
 	},
+	{
+		.name = "MSM8960 Media6",
+		.stream_name = "MultiMedia6",
+		.cpu_dai_name   = "MultiMedia6",
+		.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, /* this dailink has playback support */
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA6
+	},
+	{
+		.name = "MSM8960 Compr2",
+		.stream_name = "COMPR2",
+		.cpu_dai_name   = "MultiMedia7",
+		.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, /* this dailink has playback support */
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA7,
+	},
+	{
+		.name = "MSM8960 Compr3",
+		.stream_name = "COMPR3",
+		.cpu_dai_name   = "MultiMedia8",
+		.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, /* this dailink has playback support */
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA8,
+	},
 	/* Backend DAI Links */
 	{
 		.name = LPASS_BE_SLIMBUS_0_RX,
@@ -1960,7 +2020,7 @@
 		.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,
+		.be_hw_params_fixup = msm_slim_4_rx_be_hw_params_fixup,
 		.ops = &msm_slimbus_4_be_ops,
 		.ignore_pmdown_time = 1, /* this dainlink has playback support */
 	},
diff --git a/sound/soc/msm/msm-compr-q6.c b/sound/soc/msm/msm-compr-q6.c
index a911d9d..78b3abc 100644
--- a/sound/soc/msm/msm-compr-q6.c
+++ b/sound/soc/msm/msm-compr-q6.c
@@ -354,13 +354,14 @@
 
 	switch (compr->info.codec_param.codec.id) {
 	case SND_AUDIOCODEC_MP3:
+		pr_debug("%s: SND_AUDIOCODEC_MP3\n", __func__);
 		ret = q6asm_media_format_block(prtd->audio_client,
 				compr->codec);
 		if (ret < 0)
 			pr_info("%s: CMD Format block failed\n", __func__);
 		break;
 	case SND_AUDIOCODEC_AAC:
-		pr_debug("SND_AUDIOCODEC_AAC\n");
+		pr_debug("%s: SND_AUDIOCODEC_AAC\n", __func__);
 		memset(&aac_cfg, 0x0, sizeof(struct asm_aac_cfg));
 		aac_cfg.aot = AAC_ENC_MODE_EAAC_P;
 		aac_cfg.format = 0x03;
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index 5b69da4..52f4644 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -74,6 +74,9 @@
 static const DECLARE_TLV_DB_LINEAR(compressed_rx_vol_gain, 0,
 			INT_RX_VOL_MAX_STEPS);
 
+static int msm_route_compressed2_vol_control;
+static const DECLARE_TLV_DB_LINEAR(compressed2_rx_vol_gain, 0,
+			INT_RX_VOL_MAX_STEPS);
 static int msm_route_ec_ref_rx;
 
 /* Equal to Frontend after last of the MULTIMEDIA SESSIONS */
@@ -869,6 +872,22 @@
 	return 0;
 }
 
+static int msm_routing_get_compressed2_vol_mixer(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = msm_route_compressed2_vol_control;
+	return 0;
+}
+
+static int msm_routing_set_compressed2_vol_mixer(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	if (!compressed_set_volume(ucontrol->value.integer.value[0]))
+		msm_route_compressed2_vol_control =
+			ucontrol->value.integer.value[0];
+	return 0;
+}
+
 static int msm_routing_get_srs_trumedia_control(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
@@ -1461,6 +1480,9 @@
 	SOC_SINGLE_EXT("SGLTE", MSM_BACKEND_DAI_PRI_I2S_RX,
 	MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_PRI_I2S_RX,
+	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+	msm_routing_put_voice_stub_mixer),
 };
 
 static const struct snd_kcontrol_new sec_i2s_rx_voice_mixer_controls[] = {
@@ -1724,6 +1746,9 @@
 	SOC_SINGLE_EXT("SLIM_3_TX", MSM_BACKEND_DAI_SLIMBUS_3_TX,
 	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
 	msm_routing_put_voice_stub_mixer),
+	SOC_SINGLE_EXT("PRIMARY_I2S_TX", MSM_BACKEND_DAI_PRI_I2S_TX,
+	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+	msm_routing_put_voice_stub_mixer),
 };
 
 static const struct snd_kcontrol_new sbus_0_rx_port_mixer_controls[] = {
@@ -1786,6 +1811,13 @@
 	msm_routing_put_port_mixer),
 };
 
+static const struct snd_kcontrol_new pri_i2s_rx_port_mixer_controls[] = {
+	SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_PRI_I2S_RX,
+	MSM_BACKEND_DAI_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+	msm_routing_put_port_mixer),
+
+};
+
 static const struct snd_kcontrol_new sec_i2s_rx_port_mixer_controls[] = {
 	SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_SEC_I2S_RX,
 	MSM_BACKEND_DAI_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
@@ -1796,6 +1828,9 @@
 	SOC_SINGLE_EXT("SLIM_1_TX", MSM_BACKEND_DAI_MI2S_RX,
 	MSM_BACKEND_DAI_SLIMBUS_1_TX, 1, 0, msm_routing_get_port_mixer,
 	msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("PRIMARY_I2S_TX", MSM_BACKEND_DAI_MI2S_RX,
+	MSM_BACKEND_DAI_PRI_I2S_TX, 1, 0, msm_routing_get_port_mixer,
+	msm_routing_put_port_mixer),
 };
 
 static const struct snd_kcontrol_new fm_switch_mixer_controls =
@@ -1838,6 +1873,12 @@
 	msm_routing_set_compressed_vol_mixer, compressed_rx_vol_gain),
 };
 
+static const struct snd_kcontrol_new compressed2_vol_mixer_controls[] = {
+	SOC_SINGLE_EXT_TLV("COMPRESSED2 RX Volume", SND_SOC_NOPM, 0,
+	INT_RX_VOL_GAIN, 0, msm_routing_get_compressed2_vol_mixer,
+	msm_routing_set_compressed2_vol_mixer, compressed2_rx_vol_gain),
+};
+
 static const struct snd_kcontrol_new lpa_SRS_trumedia_controls[] = {
 	{.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "SRS TruMedia",
@@ -2282,6 +2323,9 @@
 	SND_SOC_DAPM_MIXER("HDMI_RX Port Mixer",
 	SND_SOC_NOPM, 0, 0, hdmi_rx_port_mixer_controls,
 	ARRAY_SIZE(hdmi_rx_port_mixer_controls)),
+	SND_SOC_DAPM_MIXER("PRI_I2S_RX Port Mixer",
+	SND_SOC_NOPM, 0, 0, pri_i2s_rx_port_mixer_controls,
+	ARRAY_SIZE(pri_i2s_rx_port_mixer_controls)),
 	SND_SOC_DAPM_MIXER("SEC_I2S_RX Port Mixer",
 	SND_SOC_NOPM, 0, 0, sec_i2s_rx_port_mixer_controls,
 	ARRAY_SIZE(sec_i2s_rx_port_mixer_controls)),
@@ -2416,6 +2460,7 @@
 	{"PRI_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
 	{"PRI_RX_Voice Mixer", "SGLTE", "SGLTE_DL"},
 	{"PRI_RX_Voice Mixer", "Voip", "VOIP_DL"},
+	{"PRI_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
 	{"PRI_I2S_RX", NULL, "PRI_RX_Voice Mixer"},
 
 	{"SEC_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
@@ -2522,6 +2567,7 @@
 	{"Voice Stub Tx Mixer", "STUB_1_TX_HL", "STUB_1_TX"},
 	{"Voice Stub Tx Mixer", "MI2S_TX", "MI2S_TX"},
 	{"Voice Stub Tx Mixer", "SLIM_3_TX", "SLIMBUS_3_TX"},
+	{"Voice Stub Tx Mixer", "PRIMARY_I2S_TX", "PRI_I2S_TX"},
 	{"VOICE_STUB_UL", NULL, "Voice Stub Tx Mixer"},
 
 	{"STUB_RX Mixer", "Voice Stub", "VOICE_STUB_DL"},
@@ -2552,7 +2598,12 @@
 	{"SEC_I2S_RX Port Mixer", "MI2S_TX", "MI2S_TX"},
 	{"SEC_I2S_RX", NULL, "SEC_I2S_RX Port Mixer"},
 
+	{"PRI_I2S_RX Port Mixer", "MI2S_TX", "MI2S_TX"},
+	{"PRI_I2S_RX", NULL, "PRI_I2S_RX Port Mixer"},
+
+
 	{"MI2S_RX Port Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
+	{"MI2S_RX Port Mixer", "PRIMARY_I2S_TX", "PRI_I2S_TX"},
 	{"MI2S_RX", NULL, "MI2S_RX Port Mixer"},
 	/* Backend Enablement */
 
@@ -2780,6 +2831,9 @@
 	snd_soc_add_platform_controls(platform,
 				compressed_vol_mixer_controls,
 			ARRAY_SIZE(compressed_vol_mixer_controls));
+	snd_soc_add_platform_controls(platform,
+				compressed2_vol_mixer_controls,
+			ARRAY_SIZE(compressed2_vol_mixer_controls));
 
 	snd_soc_add_platform_controls(platform,
 				lpa_SRS_trumedia_controls,
diff --git a/sound/soc/msm/msm8960.c b/sound/soc/msm/msm8960.c
index 6bd6adc..1338e2f 100644
--- a/sound/soc/msm/msm8960.c
+++ b/sound/soc/msm/msm8960.c
@@ -1372,6 +1372,48 @@
 		.ignore_pmdown_time = 1,
 		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA5,
 	},
+	{
+		.name = "MSM8960 Media6",
+		.stream_name = "MultiMedia6",
+		.cpu_dai_name   = "MultiMedia6",
+		.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, /* this dailink has playback support */
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA6
+	},
+	{
+		.name = "MSM8960 Compr2",
+		.stream_name = "COMPR2",
+		.cpu_dai_name   = "MultiMedia7",
+		.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, /* this dailink has playback support */
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA7,
+	},
+	{
+		.name = "MSM8960 Compr3",
+		.stream_name = "COMPR3",
+		.cpu_dai_name   = "MultiMedia8",
+		.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, /* this dailink has playback support */
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA8,
+	},
 	/* Backend BT/FM DAI Links */
 	{
 		.name = LPASS_BE_INT_BT_SCO_RX,
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index e5837b2..62257b4 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -41,6 +41,14 @@
 	wait_queue_head_t wait[Q6_AFE_MAX_PORTS];
 };
 
+static struct acdb_cal_block mem_addr_audproc[MAX_AUDPROC_TYPES];
+static struct acdb_cal_block mem_addr_audvol[MAX_AUDPROC_TYPES];
+
+/* 0 - (MAX_AUDPROC_TYPES -1):				audproc handles */
+/* (MAX_AUDPROC_TYPES -1) - (2 * MAX_AUDPROC_TYPES -1):	audvol handles */
+atomic_t mem_map_handles[(2 * MAX_AUDPROC_TYPES)];
+atomic_t mem_map_index;
+
 static struct adm_ctl			this_adm;
 
 static int32_t adm_callback(struct apr_client_data *data, void *priv)
@@ -63,6 +71,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;
 	}
 
@@ -82,18 +102,23 @@
 			switch (payload[0]) {
 			case ADM_CMD_SET_PP_PARAMS_V5:
 				if (rtac_make_adm_callback(
-					payload, data->payload_size))
+					payload, data->payload_size)) {
 					pr_debug("%s: payload[0]: 0x%x\n",
 						__func__, payload[0]);
 					break;
+				}
 			case ADM_CMD_DEVICE_CLOSE_V5:
 			case ADM_CMD_SHARED_MEM_UNMAP_REGIONS:
-			case ADM_CMD_SHARED_MEM_MAP_REGIONS:
 			case ADM_CMD_MATRIX_MAP_ROUTINGS_V5:
-				pr_debug("ADM_CMD_MATRIX_MAP_ROUTINGS\n");
+				pr_debug("%s: Basic callback received, wake up.\n",
+					__func__);
 				atomic_set(&this_adm.copp_stat[index], 1);
 				wake_up(&this_adm.wait[index]);
 				break;
+			case ADM_CMD_SHARED_MEM_MAP_REGIONS:
+				/* Block until memory handle comes back */
+				/* via ADM_CMDRSP_SHARED_MEM_MAP_REGIONS */
+				break;
 			default:
 				pr_err("%s: Unknown Cmd: 0x%x\n", __func__,
 								payload[0]);
@@ -125,6 +150,14 @@
 			rtac_make_adm_callback(payload,
 				data->payload_size);
 			break;
+		case ADM_CMDRSP_SHARED_MEM_MAP_REGIONS:
+			pr_debug("%s: ADM_CMDRSP_SHARED_MEM_MAP_REGIONS\n",
+				__func__);
+			atomic_set(&mem_map_handles[
+				atomic_read(&mem_map_index)], *payload);
+			atomic_set(&this_adm.copp_stat[0], 1);
+			wake_up(&this_adm.wait[index]);
+			break;
 		default:
 			pr_err("%s: Unknown cmd:0x%x\n", __func__,
 							data->opcode);
@@ -134,12 +167,143 @@
 	return 0;
 }
 
-/* TODO: send_adm_cal_block function to be defined
-	when calibration available for 8974 */
+static int send_adm_cal_block(int port_id, struct acdb_cal_block *aud_cal)
+{
+	s32				result = 0;
+	struct adm_cmd_set_pp_params_v5	adm_params;
+	int index = afe_get_port_index(port_id);
+	if (index < 0 || index >= AFE_MAX_PORTS) {
+		pr_err("%s: invalid port idx %d portid %d\n",
+				__func__, index, port_id);
+		return 0;
+	}
+
+	pr_debug("%s: Port id %d, index %d\n", __func__, port_id, index);
+
+	if (!aud_cal || aud_cal->cal_size == 0) {
+		pr_debug("%s: No ADM cal to send for port_id = %d!\n",
+			__func__, port_id);
+		result = -EINVAL;
+		goto done;
+	}
+
+	adm_params.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+		APR_HDR_LEN(20), APR_PKT_VER);
+	adm_params.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+		sizeof(adm_params));
+	adm_params.hdr.src_svc = APR_SVC_ADM;
+	adm_params.hdr.src_domain = APR_DOMAIN_APPS;
+	adm_params.hdr.src_port = port_id;
+	adm_params.hdr.dest_svc = APR_SVC_ADM;
+	adm_params.hdr.dest_domain = APR_DOMAIN_ADSP;
+	adm_params.hdr.dest_port = atomic_read(&this_adm.copp_id[index]);
+	adm_params.hdr.token = port_id;
+	adm_params.hdr.opcode = ADM_CMD_SET_PP_PARAMS_V5;
+	adm_params.payload_addr_lsw = aud_cal->cal_paddr;
+	adm_params.payload_addr_msw = 0;
+	adm_params.mem_map_handle = atomic_read(&mem_map_handles[
+					atomic_read(&mem_map_index)]);
+	adm_params.payload_size = aud_cal->cal_size;
+
+	atomic_set(&this_adm.copp_stat[index], 0);
+	pr_debug("%s: Sending SET_PARAMS payload = 0x%x, size = %d\n",
+		__func__, adm_params.payload_addr_lsw,
+		adm_params.payload_size);
+	result = apr_send_pkt(this_adm.apr, (uint32_t *)&adm_params);
+	if (result < 0) {
+		pr_err("%s: Set params failed port = %d payload = 0x%x\n",
+			__func__, port_id, aud_cal->cal_paddr);
+		result = -EINVAL;
+		goto done;
+	}
+	/* Wait for the callback */
+	result = wait_event_timeout(this_adm.wait[index],
+		atomic_read(&this_adm.copp_stat[index]),
+		msecs_to_jiffies(TIMEOUT_MS));
+	if (!result) {
+		pr_err("%s: Set params timed out port = %d, payload = 0x%x\n",
+			__func__, port_id, aud_cal->cal_paddr);
+		result = -EINVAL;
+		goto done;
+	}
+
+	result = 0;
+done:
+	return result;
+}
+
 static void send_adm_cal(int port_id, int path)
 {
-	/* function to be defined when calibration available for 8974 */
+	int			result = 0;
+	s32			acdb_path;
+	struct acdb_cal_block	aud_cal;
+	int			size = 4096;
 	pr_debug("%s\n", __func__);
+
+	/* Maps audio_dev_ctrl path definition to ACDB definition */
+	acdb_path = path - 1;
+
+	pr_debug("%s: Sending audproc cal\n", __func__);
+	get_audproc_cal(acdb_path, &aud_cal);
+
+	/* map & cache buffers used */
+	if (((mem_addr_audproc[acdb_path].cal_paddr != aud_cal.cal_paddr)  &&
+		(aud_cal.cal_size > 0)) ||
+		(aud_cal.cal_size > mem_addr_audproc[acdb_path].cal_size)) {
+
+		atomic_set(&mem_map_index, acdb_path);
+		if (mem_addr_audproc[acdb_path].cal_paddr != 0)
+			adm_memory_unmap_regions(port_id,
+				&mem_addr_audproc[acdb_path].cal_paddr,
+				&size, 1);
+
+		result = adm_memory_map_regions(port_id, &aud_cal.cal_paddr,
+						0, &aud_cal.cal_size, 1);
+		if (result < 0)
+			pr_err("ADM audproc mmap did not work! path = %d, addr = 0x%x, size = %d\n",
+				acdb_path, aud_cal.cal_paddr,
+				aud_cal.cal_size);
+		else
+			mem_addr_audproc[acdb_path] = aud_cal;
+	}
+
+	if (!send_adm_cal_block(port_id, &aud_cal))
+		pr_debug("%s: Audproc cal sent for port id: %d, path %d\n",
+			__func__, port_id, acdb_path);
+	else
+		pr_debug("%s: Audproc cal not sent for port id: %d, path %d\n",
+			__func__, port_id, acdb_path);
+
+	pr_debug("%s: Sending audvol cal\n", __func__);
+	get_audvol_cal(acdb_path, &aud_cal);
+
+	/* map & cache buffers used */
+	if (((mem_addr_audvol[acdb_path].cal_paddr != aud_cal.cal_paddr)  &&
+		(aud_cal.cal_size > 0))  ||
+		(aud_cal.cal_size > mem_addr_audvol[acdb_path].cal_size)) {
+
+		atomic_set(&mem_map_index, (acdb_path + MAX_AUDPROC_TYPES));
+		if (mem_addr_audvol[acdb_path].cal_paddr != 0)
+			adm_memory_unmap_regions(port_id,
+				&mem_addr_audvol[acdb_path].cal_paddr,
+				&size, 1);
+
+		result = adm_memory_map_regions(port_id, &aud_cal.cal_paddr,
+						0, &aud_cal.cal_size, 1);
+		if (result < 0)
+			pr_err("ADM audvol mmap did not work! path = %d, addr = 0x%x, size = %d\n",
+				acdb_path, aud_cal.cal_paddr,
+				aud_cal.cal_size);
+		else
+			mem_addr_audvol[acdb_path] = aud_cal;
+	}
+
+	if (!send_adm_cal_block(port_id, &aud_cal))
+		pr_debug("%s: Audvol cal sent for port id: %d, path %d\n",
+			__func__, port_id, acdb_path);
+	else
+		pr_debug("%s: Audvol cal not sent for port id: %d, path %d\n",
+			__func__, port_id, acdb_path);
 }
 
 int adm_connect_afe_port(int mode, int session_id, int port_id)
@@ -572,7 +736,8 @@
 	unmap_regions.hdr.dest_port = 0;
 	unmap_regions.hdr.token = 0;
 	unmap_regions.hdr.opcode = ADM_CMD_SHARED_MEM_UNMAP_REGIONS;
-	unmap_regions.mem_map_handle = this_adm.mem_map_handle[index];
+	unmap_regions.mem_map_handle = atomic_read(&mem_map_handles[
+						atomic_read(&mem_map_index)]);
 	atomic_set(&this_adm.copp_stat[0], 0);
 	ret = apr_send_pkt(this_adm.apr, (uint32_t *) &unmap_regions);
 	if (ret < 0) {