Merge "wcnss: add subsystem failure reason for wcnss" into msm-3.0
diff --git a/Documentation/devicetree/bindings/arm/msm/rpm-regulator-smd.txt b/Documentation/devicetree/bindings/arm/msm/rpm-regulator-smd.txt
new file mode 100644
index 0000000..786635f
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/rpm-regulator-smd.txt
@@ -0,0 +1,153 @@
+Qualcomm RPM Regulators
+
+rpm-regulator-smd is a regulator driver which supports regulators inside of
+PMICs which are controlled by the RPM processor.  Communication with the RPM
+processor takes place over SMD.
+
+Required structure:
+- RPM regulators must be described in two levels of devices nodes.  The first
+	level describes the interface with the RPM.  The second level describes
+	properties of one regulator framework interface (of potentially many) to
+	the regulator.
+
+[First Level Nodes]
+
+Required properties:
+- compatible:          Must be "qcom,rpm-regulator-smd-resource"
+- qcom,resource-name:  Resource name string for this regulator to be used in RPM
+			transactions.  Length is 4 characters max.
+- qcom,resource-id:    Resource instance ID for this regulator to be used in RPM
+			transactions.
+- qcom,regulator-type: Type of this regulator.  Supported values are:
+				0 = LDO
+				1 = SMPS
+				2 = VS
+				3 = NCP
+
+Optional properties:
+- qcom,allow-atomic:   Flag specifying if atomic access is allowed for this
+			regulator.  Supported values are:
+				0 or not present = mutex locks used
+				1 = spinlocks used
+- qcom,enable-time:    Time in us to delay after enabling the regulator
+- qcom,hpm-min-load:   Load current in uA which corresponds to the minimum load
+			which requires the regulator to be in high power mode.
+
+[Second Level Nodes]
+
+Required properties:
+- compatible:          Must be "qcom,rpm-regulator-smd"
+- regulator-name:      A string used as a descriptive name for regulator outputs
+- qcom,set:            Specifies which sets that requests made with this
+			regulator interface should be sent to.  Regulator
+			requests sent in the active set take effect immediately.
+			Requests sent in the sleep set take effect when the Apps
+			processor transitions into RPM assisted power collapse.
+			Supported values are:
+				1 = Active set only
+				2 = Sleep set only
+				3 = Both active and sleep sets
+
+
+
+Optional properties:
+- parent-supply:               phandle to the parent supply/regulator node
+- qcom,system-load:            Load in uA present on regulator that is not
+				captured by any consumer request
+The following properties specify initial values for parameters to be sent to the
+RPM in regulator requests.
+- qcom,init-enable:            0 = regulator disabled
+			       1 = regulator enabled
+- qcom,init-voltage:           Voltage in uV
+- qcom,init-current:           Current in mA
+- qcom,init-ldo-mode:          Operating mode to be used with LDO regulators
+				Supported values are:
+					0 = mode determined by current requests
+					1 = force HPM (NPM)
+- qcom,init-smps-mode:         Operating mode to be used with SMPS regulators
+				Supported values are:
+					0 = auto; hardware determines mode
+					1 = mode determined by current requests
+					2 = force HPM (PWM)
+- qcom,init-pin-ctrl-enable:   Bit mask specifying which hardware pins should be
+				used to enable the regulator, if any; supported
+				bits are:
+					0 = ignore all hardware enable signals
+					BIT(0) = follow HW0_EN signal
+					BIT(1) = follow HW1_EN signal
+					BIT(2) = follow HW2_EN signal
+					BIT(3) = follow HW3_EN signal
+- qcom,init-pin-ctrl-mode:     Bit mask specifying which hardware pins should be
+				used to force the regulator into high power
+				mode, if any.  Supported bits are:
+					0 = ignore all hardware enable signals
+					BIT(0) = follow HW0_EN signal
+					BIT(1) = follow HW1_EN signal
+					BIT(2) = follow HW2_EN signal
+					BIT(3) = follow HW3_EN signal
+					BIT(4) = follow PMIC awake state
+- qcom,init-frequency:         Switching frequency in MHz for SMPS regulators.
+				Supported values are:
+					 0 = Don't care about frequency used
+					 1 = 19.20
+					 2 = 9.60
+					 3 = 6.40
+					 4 = 4.80
+					 5 = 3.84
+					 6 = 3.20
+					 7 = 2.74
+					 8 = 2.40
+					 9 = 2.13
+					10 = 1.92
+					11 = 1.75
+					12 = 1.60
+					13 = 1.48
+					14 = 1.37
+					15 = 1.28
+					16 = 1.20
+- qcom,init-head-room:         Voltage head room in uV required for the
+				regulator
+- qcom,init-quiet-mode:        Specify that quiet mode is needed for an SMPS
+				regulator in order to have lower output noise.
+				Supported values are:
+					0 = No quiet mode
+					1 = Quiet mode
+					2 = Super quiet mode
+- qcom,init-freq-reason:       Consumer requiring specified frequency for an
+				SMPS regulator.  Supported values are:
+					0 = None
+					1 = Bluetooth
+					2 = GPS
+					4 = WLAN
+					8 = WAN
+
+All properties specified within the core regulator framework can also be used in
+second level nodes.  These bindings can be found in:
+Documentation/devicetree/bindings/regulator/regulator.txt.
+
+Example:
+
+rpm-regulator-smpb1 {
+	qcom,resource-name = "smpb";
+	qcom,resource-id = <1>;
+	qcom,regulator-type = <1>;
+	qcom,hpm-min-load = <100000>;
+	compatible = "qcom,rpm-regulator-smd-resource";
+	status = "disabled";
+
+	pm8841_s1: regulator-s1 {
+		regulator-name = "8841_s1";
+		qcom,set = <3>;
+		regulator-min-microvolt = <900000>;
+		regulator-max-microvolt = <1150000>;
+		qcom,init-voltage = <1150000>;
+		compatible = "qcom,rpm-regulator-smd";
+	};
+	pm8841_s1_ao: regulator-s1-ao {
+		regulator-name = "8841_s1_ao";
+		qcom,set = <1>;
+		regulator-min-microvolt = <900000>;
+		regulator-max-microvolt = <1150000>;
+		compatible = "qcom,rpm-regulator-smd";
+	};
+};
diff --git a/Documentation/devicetree/bindings/arm/msm/rpm-smd.txt b/Documentation/devicetree/bindings/arm/msm/rpm-smd.txt
new file mode 100644
index 0000000..8ebd3ba
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/rpm-smd.txt
@@ -0,0 +1,30 @@
+Resource Power Manager(RPM)
+
+RPM is a dedicated hardware engine for managing shared SoC resources,
+which includes buses, clocks, power rails, etc.  The goal of RPM is
+to achieve the maximum power savings while satisfying the SoC's
+operational and performance requirements.  RPM accepts resource
+requests from multiple RPM masters.  It arbitrates and aggregates the
+requests, and configures the shared resources.  The RPM masters are
+the application processor, the modem processor, as well as hardware
+accelerators. The RPM driver communicates with the hardware engine using
+SMD.
+
+The devicetree representation of the SPM block should be:
+
+Required properties
+
+- compatible: "qcom,rpm-smd"
+- rpm-channel-name: The string corresponding to the channel name of the
+			peripheral subsystem
+- rpm-channel-type: The interal SMD edge for this subsystem found in
+			<mach/msm_smd.h>
+
+Example:
+
+	qcom,rpm-smd {
+		compatible = "qcom,rpm-smd"
+		qcom,rpm-channel-name = "rpm_requests";
+		qcom,rpm-channel-type = 15; /* SMD_APPS_RPM */
+	}
+}
diff --git a/Documentation/devicetree/bindings/iommu/msm_iommu.txt b/Documentation/devicetree/bindings/iommu/msm_iommu.txt
new file mode 100644
index 0000000..67933e7
--- /dev/null
+++ b/Documentation/devicetree/bindings/iommu/msm_iommu.txt
@@ -0,0 +1,35 @@
+* Qualcomm MSM IOMMU
+
+Required properties:
+- compatible : one of:
+	- "qcom,msm-smmu-v2"
+- reg : offset and length of the register set for the device.
+
+- List of sub nodes, one for each of the translation context banks supported.
+  Each sub node has the following required properties:
+
+  - reg : offset and length of the register set for the context bank.
+  - interrupts : should contain the context bank interrupt.
+  - qcom,iommu-ctx-sids : List of stream identifiers associated with this
+    translation context.
+  - qcom,iommu-ctx-name : Name of the context bank
+
+Example:
+
+        qcom,iommu@fda64000 {
+                compatible = "qcom,msm-smmu-v2";
+                reg = <0xfda64000 0x10000>;
+
+                qcom,iommu-ctx@fda6c000 {
+                        reg = <0xfda6c000 0x1000>;
+                        interrupts = <0 70 0>;
+                        qcom,iommu-ctx-sids = <0 2>;
+			qcom,iommu-ctx-name = "ctx_0";
+                };
+                qcom,iommu-ctx@fda6d000 {
+                        reg = <0xfda6d000 0x1000>;
+                        interrupts = <0 71 0>;
+                        qcom,iommu-ctx-sids = <1>;
+			qcom,iommu-ctx-name = "ctx_1";
+                };
+        };
diff --git a/Documentation/devicetree/bindings/pil/pil-mba.txt b/Documentation/devicetree/bindings/pil/pil-mba.txt
new file mode 100644
index 0000000..7aafd219
--- /dev/null
+++ b/Documentation/devicetree/bindings/pil/pil-mba.txt
@@ -0,0 +1,27 @@
+Qualcomm Modem Boot Authenticator Peripheral Image Loader
+
+pil-mba is a peripheral image loader (PIL) driver. It is used for loading
+modem images using the self-authenticating hardware and software features
+of the Modem Boot Authenticator.
+
+Required properties:
+- compatible:	      Must be "qcom,pil-mba"
+- reg:		      Two pairs of physical base addresses and sizes. The
+		      first corresponds to the Relay Message Buffer (RMB)
+		      register base. The second specifies the address at which
+		      the primary modem image metadata should be stored.
+- qcom,firmware-name: Base name of the firmware image. Ex. "modem"
+
+Optional properties:
+- qcom,depends-on:    firmware-name of a prerequisite image that must already
+		      be running.
+
+Example:
+	qcom,mba@fc820000 {
+		compatible = "qcom,pil-mba";
+		reg = <0xfc820000 0x0020>,
+		      <0x0d1f0000 0x4000>;
+
+		qcom,firmware-name = "modem";
+		qcom,depends-on    = "mba";
+	};
diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt
index 002431a..308f992 100644
--- a/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt
@@ -7,17 +7,15 @@
 
 Required properties:
 - compatible:	      Must be "qcom,pil-q6v5-lpass"
-- reg:		      Three pairs of physical base addresses and region sizes
+- reg:		      Two pairs of physical base addresses and region sizes
 		      of memory mapped registers. The first region corresponds
-		      to QDSP6SS_PUB, the second corresponds to LPASS_CC, and
-		      the third to LPASS_HALTREQ.
+		      to QDSP6SS_PUB, and the second to LPASS_HALTREQ.
 - qcom,firmware-name: Base name of the firmware image. Ex. "lpass"
 
 Example:
 	qcom,lpass@fe200000 {
 	        compatible = "qcom,pil-q6v5-lpass";
 	        reg = <0xfe200000 0x00100>,
-	              <0xfe000000 0x40000>,
 	              <0xfd485100 0x00010>;
 
 	        qcom,firmware-name = "lpass";
diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
new file mode 100644
index 0000000..95e7f88
--- /dev/null
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
@@ -0,0 +1,32 @@
+Qualcomm MSS QDSP6v5 Peripheral Image Loader
+
+pil-qdsp6v5-mss is a peripheral image loader (PIL) driver. It is used for
+loading QDSP6v5 (Hexagon) firmware images for modem subsystems into memory and
+preparing the subsystem's processor to execute code. It's also responsible for
+shutting down the processor when it's not needed.
+
+Required properties:
+- compatible:	      Must be "qcom,pil-q6v5-mss"
+- reg:		      Four pairs of physical base addresses and region sizes of
+		      memory mapped registers. The first region corresponds to
+		      QDSP6SS_PUB, the second to the bus port halt register
+		      base, the third to the MSS_RELAY_MSG_BUFFER base, and the
+		      fourth to the MSS_RESTART register.
+- vdd_mss-supply:     Reference to the regulator that supplies the processor.
+- qcom,firmware-name: Base name of the firmware image. Ex. "mdsp"
+- qcom,pil-self-auth: <0> if the hardware does not require self-authenticating
+		      images and self-authentication is not desired;
+		      <1> if the hardware requires self-authenticating images.
+
+Example:
+	qcom,mss@fc880000 {
+		compatible = "qcom,pil-q6v5-mss";
+		reg = <0xfc880000 0x100>,
+		      <0xfd485000 0x400>,
+		      <0xfc820000 0x020>,
+		      <0xfc401680 0x004>;
+		vdd_mss-supply = <&pm8841_s3>;
+
+		qcom,firmware-name = "mba";
+		qcom,pil-self-auth = <1>;
+	};
diff --git a/Documentation/devicetree/bindings/prng/msm-rng.txt b/Documentation/devicetree/bindings/prng/msm-rng.txt
new file mode 100644
index 0000000..3d55808
--- /dev/null
+++ b/Documentation/devicetree/bindings/prng/msm-rng.txt
@@ -0,0 +1,12 @@
+* RNG (Random Number Generator)
+
+Required properties:
+- compatible : Should be "qcom,msm-rng"
+- reg        : Offset and length of the register set for the device
+
+Example:
+
+        qcom,msm-rng@f9bff000 {
+                              compatible = "qcom,msm-rng";
+                              reg = <0xf9bff000 0x200>;
+        };
diff --git a/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt b/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt
new file mode 100644
index 0000000..cd7bdce
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt
@@ -0,0 +1,21 @@
+Qualcomm Global Distributed Switch Controller (GDSC) Regulator Driver
+
+The GDSC driver, implemented under the regulator framework, is responsible for
+safely collapsing and restoring power to peripheral cores on chipsets like
+msm-copper for power savings.
+
+Required properties:
+ - compatible:      Must be "qcom,gdsc"
+ - regulator-name:  A string used as a descriptive name for regulator outputs
+ - reg:             The address of the GDSCR register
+
+Optional properties:
+ - parent-supply:   phandle to the parent supply/regulator node
+
+Example:
+	gdsc_oxili_gx: qcom,gdsc@fd8c4024 {
+		compatible = "qcom,gdsc";
+		regulator-name = "gdsc_oxili_gx";
+		parent-supply = <&pm8841_s4>;
+		reg = <0xfd8c4024 0x4>;
+	};
diff --git a/Documentation/devicetree/bindings/regulator/regulator.txt b/Documentation/devicetree/bindings/regulator/regulator.txt
index 82bef20..0d22aa1 100644
--- a/Documentation/devicetree/bindings/regulator/regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/regulator.txt
@@ -10,6 +10,11 @@
 - regulator-always-on: boolean, regulator should never be disabled
 - regulator-boot-on: bootloader/firmware enabled regulator
 - <name>-supply: phandle to the parent supply/regulator node
+- qcom,consumer-supplies: flattened list of supply and dev_name pairs
+	This property is used to support regulator consumers that have no device
+	tree node.  An empty string, "", can be used to specify a null device
+	name.  A null device name is used to allow calls such as:
+	regulator_get(NULL, "pll_vdd").
 
 Example:
 
@@ -18,6 +23,7 @@
 		regulator-max-microvolt = <2500000>;
 		regulator-always-on;
 		vin-supply = <&vin>;
+		qcom,consumer-supplies = "pll_vdd", "", "lcd_vcc", "foo.1";
 	};
 
 Regulator Consumers:
diff --git a/Documentation/dvb/qcom-mpq.txt b/Documentation/dvb/qcom-mpq.txt
new file mode 100644
index 0000000..28f5d39
--- /dev/null
+++ b/Documentation/dvb/qcom-mpq.txt
@@ -0,0 +1,409 @@
+Introduction
+============
+MPQ DVB Adapter implements Digital Video Broadcasting devices according
+to LinuxTV (linuxtv.org) defined API and infrastructure.
+
+The implemented devices are dvb/demux devices, dvb/dvr devices and
+dvb/video devices.
+
+These devices are used in Qualcomm's MPQ chipsets that support
+broadcast applications.
+
+dvb/demux is responsible to receive a digital stream broadcasted over
+the air from a hardware unit (TSPP - Transport stream packet processor,
+or TSIF - Transport Stream Interface) and separates the stream into its
+various sub-streams such as video, audio and auxiliary data.
+The separation operation is named demuxing.
+
+dvb/dvr is used in conjunction with dvb/demux to re-play a digital
+stream from memory or to record stream to memory.
+
+dvb/video is used to handle the video decoding, it receives compressed
+video from dvb/demux through a stream-buffer interface and interacts
+with the existing HW video driver to perform the decoding.
+
+For more information on the TSIF interface, please refer to TSIF
+documentation under "Documentation/arm/msm/tsif.txt".
+For more information on the TSPP interface, please refer to TSPP
+documentation under "Documentation/arm/msm/tspp.txt".
+For more information on DVB-API definition, please refer dvb
+documentation under "Documentation/dvb/readme.txt".
+
+Hardware description
+====================
+dvb/demux, dvb/dvr and dvb/video do not interact with a hardware directly;
+The implementation of these drivers is done using the kernel API of TSPP,
+TSIF and video drivers.
+
+Software description
+====================
+
+Terminology
+-----------
+Stream: A stream is a TS packet source
+  - For example, MPEG2 Transport Stream from TSIF0
+Filter: Enables TS packet filtering and routing according to PID (packet ID)
+  - The decision regarding which PIDs in the stream will be routed
+    is done via filters, each demux open request corresponds to a filter.
+  - Filters can pass TS packets as-is (for recording), assemble them into
+    "other" PES packets (for PES packets read by client), assemble and send
+    them to decoder (for decoder PES), or assemble them into sections.
+Service: A service is a set of PIDs as defined in the service PMT.
+  Each service may be carried in a different transport stream or part of the
+  same transport stream. Processing a service means either preparing the
+  data for display and/or for recording.
+
+Requirments
+-----------
+1. Demuxing from different sources:
+   - Live transport stream inputs (TSIF)
+   - Memory inputs
+2. Support different packet formats:
+   - 188-bytes transport packets
+   - 192-bytes transport packets
+3. PID filtering
+4. Output of the following data:
+   - Decoder PES: PES (video and/or audio) that can be directed to HW decoders
+     in tunneling mode (without interaction of user-space).
+   - Other PES: a non-decoder PES, such as subtitle, teletext. The consumer
+     of this data is user-space that reads the data through standard read
+     calls.
+   - Sections: Sections are used by user-space to acquire different kinds of
+     information such as channels list, program user guide, etc.
+   - Transport Stream Packets: Transport stream packets of specific PIDs as
+     they were received in the input stream. User-space can use those to
+     record specific services and/or to perform time-shift buffer.
+   - PCR/STC: Pairs of PCR/STC can be used by user-space to perform
+     clock-recovery.
+   - Frame-indexing: For recorded stream, demux provides indexing of the
+     I-frames within the stream that can be used for trick-modes operations
+     while playing a recorded file.
+5. Support decryption of scrambled transport packets.
+6. Support recording of scrambled streams.
+8. Section filtering.
+
+Control path
+------------
+1. Client opens a demux device. Open request is done on the same demux
+   device for each filter.
+2. Client may configure the demux's internal ring-buffer size used to
+   hold the data for user-space (or default is used).
+3. Client configures the opened filter either to capture sections,
+   TS packets (for recording) or PES (decoder or non-decoder PES).
+   - The demux configures the underlying HW accordingly through
+     TSPP or TSIF kernel APIs
+   - demux receives notification of new data from the underlying HW and
+     performs demuxing operation based on the configuration.
+4. Client can then read data received from the selected filter.
+
+Data path
+---------
+For each filter that is opened, demux manages a circular buffer that
+holds the captured filter data; Client read commands extract data from
+the relevant ring buffer. Data loss can occur if a client cannot keep up
+with stream bandwidth.
+
+For PES data tunneled to decoder, demux manages a stream-buffer used to
+transfer the PES data to the decoder. The stream-buffer is built from
+two ring-buffers: One holding the PES payload (elementary stream) and
+the other holding PES parameters extracted from the PES header. The
+ring-buffer with PES parameters points to the location of respective PES
+payload in the PES payload ring-buffer.
+
+To allow concurrency of multiple stream processing, multiple demux/dvr
+devices exist. Each demux devices handles a single stream input. The
+number of demux devices is configurable depending on the required number
+of concurrent stream processing.
+
+The client configures each demux device with the stream to process,
+by default, all devices are configured to process stream from memory.
+The default setting can be changed by issuing ioctl that configures
+the demux source to either TSIF0 or TSIF1. For specific TSIF input,
+only one demux device may process it at a time.
+
+Background Processing
+---------------------
+When demux receives notifications from underlying HW drivers about new
+data, it schedules work to a single-threaded workqueue to process the
+notification.
+
+The processing is the action of demuxing of the new data; it may sleep
+as it locks against the demux data-structure that may be accessed by
+user-space in the meanwhile.
+
+A single threaded workqueue exists for each live input (TSIF0 or TSIF1)
+to process the inputs in parallel.
+
+Dependencies
+------------
+The demux driver depends on the following kernel drivers and subsystems:
+1. TSIF driver: Used to receive TS packets from TSIF interface for
+   targets supporting TSIF only.
+2. TSPP driver: Used to receive TS packets and/or PES from TSPP
+   interface for targets supporting TSPP.
+3. TZ-COM: Used to communicate with TrustZone to handle scrambled
+   streams.
+4. ION: Used to allocate memory for buffers holding decoder-data in
+   case the data is tunneled between demux and decoders.
+   Also used to allocate memory for TSPP/TSIF output pipes.
+5. dvb-core: Existing Linux infrastructure used for implementation of
+   dvb devices.
+
+Design
+======
+
+Goals
+-----
+The demux driver is designed to:
+1. Fulfil the requirements listed above.
+2. Be able to work on different chipsets having different HW
+   capabilities. For example, some chipsets are equipped with TSIF only,
+   others are equipped with TSPP of different versions.
+
+Design Blocks
+-------------
+Demux implementation hooks to the existing Linux dvb-core
+infrastructure as follows:
+
+     +----------+  +------------------------------------------+
+     |          |  |             MPQ Demux Driver             |
+     |          |  | +----------+  +----------+  +----------+ |
+     |          |  | | MPQ DMX  |  | MPQ DMX  |  | MPQ DMX  | |
+     | QCOM MPQ |  | | TSIF     |  | TSPPv1   |  | TSPPv2   | |
+     |  Adapter |  | | Plugin   |  | Plugin   |  | Plugin   | |
+     |          |  | +----------+  +----------+  +----------+ |
+     |          |  | +--------------------------------------+ |
+     |          |  | |       MPQ Demux Common Services      | |
+     |          |  | +--------------------------------------+ |
+     +----------+  +------------------------------------------+
+     +--------------------------------------------------------+
+     |                    Linux DVB Core                      |
+     |     +----------+      +----------+       +----------+  |
+     |     |   DVB    |      | DVB DMX  |       |  DVB     |  |
+     |     |  Demux   |      |  Device  |       |  Device  |  |
+     |     +----------+      +----------+       +----------+  |
+     +--------------------------------------------------------+
+
+The new developed code is QCOM MPQ Adapter and the MPQ Demux driver
+with the various MPQ-DMX Plugins.
+
+QCOM MPQ Adapter registers a new DVB adapter to Linux dvb-core.
+The MPQ DVB adapter is built as a separate kernel module. Using it
+demux and video devices can register themselves to the adapter.
+
+MPQ-DMX plugins exist to hook to dvb-core demux implementation
+depending on the HW capabilities. Only one of these plugins might be
+compiled and run at a time on the target.
+As the name of each plugin implies, one plugin implements demux
+functionality for targets supporting TSIF only, and the others
+implement pluging for targets supporting TSPP in different versions.
+
+The plugin implementation is not hooked to specific chipset as
+different chipsets might have the same HW capability.
+
+The MPQ-DMX Plugin Common Services provides common services that are
+used by all plugins, such as registrations of demux devices to
+the dvb-core.
+
+The demux plugin is built as a separate kernel module. Each plugin
+hooks to the DVB-Demux by providing set of pointers to functions
+required for DVB-Demux and dvb-core operation. The actual
+implementation of these function differs between the plugins depending
+on the HW capabilities. The plugins may be viewed as "classes"
+inheriting from DVB-Demux "class".
+
+Interface to TSPP/TSIF Drivers
+------------------------------
+Each demux plugin interacts with the kernel API of the relevant driver
+(either TSIF or TSPP) to receive TS packets or other kinds of data
+depending on the HW capabilities.
+
+The demux uses the kernel API of TSIF and TSPP drivers and registers
+callback triggered when new data is received. The callback schedules
+work to a single-threaded workqueue to process the data. The actual
+processing of the data depends on the HW capabilities.
+
+Interface to TZ-COM Driver
+--------------------------
+For cases HW does not support descrambling, the descrambling is
+performed by communicating with TZ using TZ-COM kernel API.
+
+ION driver is used to allocate input and output buffers provided to TZ.
+
+Interface to Decoders
+---------------------
+The interface to the decoders is done through a stream-buffer interface.
+The design aims not to have direct calls between dvb/demux and
+dvb/video for de-coupling and generality. dvb/demux and dvb/video
+interact only with stream-buffer API.
+
+Stream buffer is built of two ring-buffers, one holding the PES payload
+(the video elementary stream) and the other holding parameters from PES
+headers required by decoders.
+
+The separation to two ring-buffers allows locking the payload buffer
+as secured buffer that only the decoder's HW may access while allowing
+the software to access the PES headers which are not required to be
+secured. Locking of the payload buffer is done when the data should be
+secured (scrambled video stream for example).
+
+The stream-buffer API make use of dvb-ring buffer implementation that
+is part of dvb-core.
+
+SMP/multi-core
+==============
+Driver is fully SMP aware.
+
+Interface
+=========
+
+User-space API
+--------------
+dvb/demux and dvb/dvr each expose a char device interface to user-space
+as defined by linuxtv.org. Extension to this interface is done to add
+new features required by MPQ use-cases. The extensions preserve backward
+compatibility of the API defined by linuxtv.org
+
+The devices appear in file-system under:
+/dev/dvb/adapter0/demuxN
+/dev/dvb/adapter0/dvrN
+
+Where "N" ranges between 0 to total number of demux devices defined.
+The default configuration is 4 devices.
+
+Extensions to this API (through new ioctl) exist to provide the
+following functionality:
+
+1. DMX_SET_TS_PACKET_FORMAT: Set the transport stream TS packet format.
+   Configures whether the stream fed to demux from memory is with TS packet
+   of 188 bytes long, 192 bytes long, etc.
+   Default is 188 bytes long to preserve backward compatibility.
+
+   Returns the following values:
+   0 in case of success.
+   -EINVAL if the parameter is invalid.
+   -EBUSY if demux is already running.
+
+2. DMX_SET_DECODER_BUFFER_SIZE: Set the decoder's buffer size.
+   For data tunneled to decoder, client can configure the size of the buffer
+   holding the PES payload.
+   Default is set to the fixed size value that exists in current dvb-core to
+   preserve backward compatibility.
+
+   Returns the following values:
+   0 in case of success.
+   -EINVAL if the parameter is invalid.
+   -EBUSY if demux is already running.
+
+3. DMX_SET_TS_OUT_FORMAT: Set the TS packet recording format.
+   Indicates whether the TS packet used for recording should be in 188 or 192
+   bytes long format. In case of 192-packets output, 4 bytes zero timestamp
+   is attached to the original 188 packet.
+   Default is set for 188 to preserve backward compatibility.
+
+   Returns the following values:
+   0 in case of success.
+   -EINVAL if the parameter is invalid.
+   -EBUSY if demux is already running.
+
+4. Added support for mmap for direct access to input/output buffers.
+   User can either use the original read/write syscalls or use mmap
+   on the specific file-handle. Several ioctls were exposed so that
+   user can find-out the status of the buffers (DMX_GET_BUFFER_STATUS),
+   to notify demux when data is consumed (DMX_RELEASE_DATA) or notify
+   dvr when data is fed (DMX_FEED_DATA).
+
+5. DMX_SET_PLAYBACK_MODE: Set playback mode in memory input.
+   In memory input, contrary to live input, playback can be in pull mode,
+   where if one of output buffers is full, demux stalls waiting for free space,
+   this would cause DVR input buffer fullness to accumulate.
+
+   Returns the following values:
+   0 in case of success.
+   -EINVAL if the parameter is invalid.
+   -EBUSY if demux is already running.
+
+debugfs
+-------
+debugfs is used for debug purposes.
+
+Directory in debugfs is created for each demux device.
+
+Each directory includes several performance counters of the specific demux:
+Total demuxing time, total CRC time, HW notification rate, HW notification
+buffer size.
+
+
+Exported Kernel API
+-------------------
+MPQ adapter exports the following kernel API:
+1. Getter API for the registered MPQ adapter handle.
+   This is used by demux plugin as well as dvb/video implementation to
+   register their devices to that adapter.
+2. Stream buffer API: Used to tunnel the data between dvb/demux and
+   decoders. The API is used by dvb/demux and by decoders to write/read
+   tunneled data.
+3. Stream buffer interface registration: Used to register stream-buffer
+   interfaces. When demux driver is asked to tunnel data to a decoder,
+   the demux allocates a stream-buffer to be shared between demux and
+   the decoder. For the decoder to retrieve the info of the
+   stream-buffer it should connect to, stream-buffer registration API
+   exist.
+   The demux registers the new allocated stream buffer handle to MPQ
+   Adapter, and the decoder may query the registered interface through
+   MPQ Adapter.
+
+Driver parameters
+=================
+There are three kernel modules required for DVB API operation:
+1. dvb-core.ko: This is an existing Linux module for dvb functionality.
+   The parameters for this module are the one defined by linuxtv.org.
+   An additional parameter was added to specify whether to collect
+   performance debug information exposed through debugfs.
+   Parameter name: dvb_demux_performancecheck
+
+2. mpq-adapter.ko: MPQ DVB adapter module. Has a parameter to
+   specify the adapter number, the number (X) is the same as the one
+   that appears in /dev/dvb/adapterX. Default is 0.
+   Parameter name: adapter_nr
+
+3. mpq-dmx-hw-plugin.ko: Module for demux HW plugin. Receives as a
+   parameter the number of required demux devices. Default is set to the
+   number specified in kernel configuration.
+   Parameter name: mpq_demux_device_num
+
+Config options
+==============
+New kernel configurations is available (through make menuconfig) to
+enable MPQ based adapter functionality. The following configurations
+exist:
+1. Control whether to enable QCOM MPQ DVB adapter (tri-state).
+   It depends on having dvb-core enabled.
+2. If MPQ adapter is enabled:
+   2.1. Control whether to enable MPQ dvb/demux (tri-state)
+   2.2. Control whether to enable MPQ dvb/video (tri-state)
+   2.3. If dvb/demux is enabled:
+        2.3.1. Configure the number of demux devices. Default is 4.
+        2.3.2. Select the desired demux plugin. Each plugin would appear
+               in the list of options depending whether the respective
+               driver (TSIF/TSPP) is enabled or not.
+
+Dependencies
+============
+1. The implementation depends on having dvb-core enabled.
+2. Each demux plugin depends on whether the relevant driver it uses
+   is enabled. TSIF plugin depends on TSIF driver and TSPP plugins
+   depend on TSPP driver.
+3. There's no communication to other processors.
+
+User space utilities
+====================
+N/A
+
+Other
+=====
+N/A
+
+Known issues
+============
+N/A
diff --git a/Documentation/mmc/mmc-dev-attrs.txt b/Documentation/mmc/mmc-dev-attrs.txt
index 8898a95..70fa101 100644
--- a/Documentation/mmc/mmc-dev-attrs.txt
+++ b/Documentation/mmc/mmc-dev-attrs.txt
@@ -8,6 +8,23 @@
 
 	force_ro		Enforce read-only access even if write protect switch is off.
 
+	num_wr_reqs_to_start_packing 	This attribute is used to determine
+	the trigger for activating the write packing, in case the write
+	packing control feature is enabled.
+
+	When the MMC manages to reach a point where num_wr_reqs_to_start_packing
+	write requests could be packed, it enables the write packing feature.
+	This allows us to start the write packing only when it is beneficial
+	and has minimum affect on the read latency.
+
+	The number of potential packed requests that will trigger the packing
+	can be configured via sysfs by writing the required value to:
+	/sys/block/<block_dev_name>/num_wr_reqs_to_start_packing.
+
+	The default value of num_wr_reqs_to_start_packing was determined by
+	running parallel lmdd write and lmdd read operations and calculating
+	the max number of packed writes requests.
+
 SD and MMC Device Attributes
 ============================
 
diff --git a/arch/arm/boot/dts/msm-gdsc.dtsi b/arch/arm/boot/dts/msm-gdsc.dtsi
new file mode 100644
index 0000000..f83fe76
--- /dev/null
+++ b/arch/arm/boot/dts/msm-gdsc.dtsi
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+	gdsc_venus: qcom,gdsc@fd8c1024 {
+		compatible = "qcom,gdsc";
+		regulator-name = "gdsc_venus";
+		reg = <0xfd8c1024 0x4>;
+	};
+
+	gdsc_mdss: qcom,gdsc@fd8c2304 {
+		compatible = "qcom,gdsc";
+		regulator-name = "gdsc_mdss";
+		reg = <0xfd8c2304 0x4>;
+	};
+
+	gdsc_jpeg: qcom,gdsc@fd8c35a4 {
+		compatible = "qcom,gdsc";
+		regulator-name = "gdsc_jpeg";
+		reg = <0xfd8c35a4 0x4>;
+	};
+
+	gdsc_vfe: qcom,gdsc@fd8c36a4 {
+		compatible = "qcom,gdsc";
+		regulator-name = "gdsc_vfe";
+		reg = <0xfd8c36a4 0x4>;
+	};
+
+	gdsc_oxili_gx: qcom,gdsc@fd8c4024 {
+		compatible = "qcom,gdsc";
+		regulator-name = "gdsc_oxili_gx";
+		reg = <0xfd8c4024 0x4>;
+	};
+
+	gdsc_oxili_cx: qcom,gdsc@fd8c4034 {
+		compatible = "qcom,gdsc";
+		regulator-name = "gdsc_oxili_cx";
+		reg = <0xfd8c4034 0x4>;
+	};
+
+	gdsc_usb_hsic: qcom,gdsc@fc400404 {
+		compatible = "qcom,gdsc";
+		regulator-name = "gdsc_usb_hsic";
+		reg = <0xfc400404 0x4>;
+	};
+};
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index 2698ea7..e62dfbd 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -315,9 +315,9 @@
 				};
 			};
 
-			regulator@1d00 {
+			regulator@a000 {
 				regulator-name = "8941_boost";
-				reg = <0x1d00 0x100>;
+				reg = <0xa000 0x100>;
 				compatible = "qcom,qpnp-regulator";
 				status = "disabled";
 			};
diff --git a/arch/arm/boot/dts/msm-pm8x41-rpm-regulator.dtsi b/arch/arm/boot/dts/msm-pm8x41-rpm-regulator.dtsi
new file mode 100644
index 0000000..019112a
--- /dev/null
+++ b/arch/arm/boot/dts/msm-pm8x41-rpm-regulator.dtsi
@@ -0,0 +1,587 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/ {
+	qcom,rpm-smd {
+		rpm-regulator-smpb1 {
+			qcom,resource-name = "smpb";
+			qcom,resource-id = <1>;
+			qcom,regulator-type = <1>;
+			qcom,hpm-min-load = <100000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-s1 {
+				regulator-name = "8841_s1";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-smpb2 {
+			qcom,resource-name = "smpb";
+			qcom,resource-id = <2>;
+			qcom,regulator-type = <1>;
+			qcom,hpm-min-load = <100000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-s2 {
+				regulator-name = "8841_s2";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-smpb3 {
+			qcom,resource-name = "smpb";
+			qcom,resource-id = <3>;
+			qcom,regulator-type = <1>;
+			qcom,hpm-min-load = <100000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-s3 {
+				regulator-name = "8841_s3";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-smpb4 {
+			qcom,resource-name = "smpb";
+			qcom,resource-id = <4>;
+			qcom,regulator-type = <1>;
+			qcom,hpm-min-load = <100000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-s4 {
+				regulator-name = "8841_s4";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-smpa1 {
+			qcom,resource-name = "smpa";
+			qcom,resource-id = <1>;
+			qcom,regulator-type = <1>;
+			qcom,hpm-min-load = <100000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-s1 {
+				regulator-name = "8941_s1";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-smpa2 {
+			qcom,resource-name = "smpa";
+			qcom,resource-id = <2>;
+			qcom,regulator-type = <1>;
+			qcom,hpm-min-load = <100000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-s2 {
+				regulator-name = "8941_s2";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-smpa3 {
+			qcom,resource-name = "smpa";
+			qcom,resource-id = <3>;
+			qcom,regulator-type = <1>;
+			qcom,hpm-min-load = <100000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-s3 {
+				regulator-name = "8941_s3";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-ldoa1 {
+			qcom,resource-name = "ldoa";
+			qcom,resource-id = <1>;
+			qcom,regulator-type = <0>;
+			qcom,hpm-min-load = <10000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-l1 {
+				regulator-name = "8941_l1";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-ldoa2 {
+			qcom,resource-name = "ldoa";
+			qcom,resource-id = <2>;
+			qcom,regulator-type = <0>;
+			qcom,hpm-min-load = <10000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-l2 {
+				regulator-name = "8941_l2";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-ldoa3 {
+			qcom,resource-name = "ldoa";
+			qcom,resource-id = <3>;
+			qcom,regulator-type = <0>;
+			qcom,hpm-min-load = <10000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-l3 {
+				regulator-name = "8941_l3";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-ldoa4 {
+			qcom,resource-name = "ldoa";
+			qcom,resource-id = <4>;
+			qcom,regulator-type = <0>;
+			qcom,hpm-min-load = <10000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-l4 {
+				regulator-name = "8941_l4";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-ldoa5 {
+			qcom,resource-name = "ldoa";
+			qcom,resource-id = <5>;
+			qcom,regulator-type = <0>;
+			qcom,hpm-min-load = <10000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-l5 {
+				regulator-name = "8941_l5";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-ldoa6 {
+			qcom,resource-name = "ldoa";
+			qcom,resource-id = <6>;
+			qcom,regulator-type = <0>;
+			qcom,hpm-min-load = <10000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-l6 {
+				regulator-name = "8941_l6";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-ldoa7 {
+			qcom,resource-name = "ldoa";
+			qcom,resource-id = <7>;
+			qcom,regulator-type = <0>;
+			qcom,hpm-min-load = <10000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-l7 {
+				regulator-name = "8941_l7";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-ldoa8 {
+			qcom,resource-name = "ldoa";
+			qcom,resource-id = <8>;
+			qcom,regulator-type = <0>;
+			qcom,hpm-min-load = <10000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-l8 {
+				regulator-name = "8941_l8";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-ldoa9 {
+			qcom,resource-name = "ldoa";
+			qcom,resource-id = <9>;
+			qcom,regulator-type = <0>;
+			qcom,hpm-min-load = <10000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-l9 {
+				regulator-name = "8941_l9";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-ldoa10 {
+			qcom,resource-name = "ldoa";
+			qcom,resource-id = <10>;
+			qcom,regulator-type = <0>;
+			qcom,hpm-min-load = <10000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-l10 {
+				regulator-name = "8941_l10";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-ldoa11 {
+			qcom,resource-name = "ldoa";
+			qcom,resource-id = <11>;
+			qcom,regulator-type = <0>;
+			qcom,hpm-min-load = <10000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-l11 {
+				regulator-name = "8941_l11";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-ldoa12 {
+			qcom,resource-name = "ldoa";
+			qcom,resource-id = <12>;
+			qcom,regulator-type = <0>;
+			qcom,hpm-min-load = <10000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-l12 {
+				regulator-name = "8941_l12";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-ldoa13 {
+			qcom,resource-name = "ldoa";
+			qcom,resource-id = <13>;
+			qcom,regulator-type = <0>;
+			qcom,hpm-min-load = <10000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-l13 {
+				regulator-name = "8941_l13";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-ldoa14 {
+			qcom,resource-name = "ldoa";
+			qcom,resource-id = <14>;
+			qcom,regulator-type = <0>;
+			qcom,hpm-min-load = <10000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-l14 {
+				regulator-name = "8941_l14";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-ldoa15 {
+			qcom,resource-name = "ldoa";
+			qcom,resource-id = <15>;
+			qcom,regulator-type = <0>;
+			qcom,hpm-min-load = <10000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-l15 {
+				regulator-name = "8941_l15";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-ldoa16 {
+			qcom,resource-name = "ldoa";
+			qcom,resource-id = <16>;
+			qcom,regulator-type = <0>;
+			qcom,hpm-min-load = <10000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-l16 {
+				regulator-name = "8941_l16";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-ldoa17 {
+			qcom,resource-name = "ldoa";
+			qcom,resource-id = <17>;
+			qcom,regulator-type = <0>;
+			qcom,hpm-min-load = <10000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-l17 {
+				regulator-name = "8941_l17";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-ldoa18 {
+			qcom,resource-name = "ldoa";
+			qcom,resource-id = <18>;
+			qcom,regulator-type = <0>;
+			qcom,hpm-min-load = <10000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-l18 {
+				regulator-name = "8941_l18";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-ldoa19 {
+			qcom,resource-name = "ldoa";
+			qcom,resource-id = <19>;
+			qcom,regulator-type = <0>;
+			qcom,hpm-min-load = <10000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-l19 {
+				regulator-name = "8941_l19";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-ldoa20 {
+			qcom,resource-name = "ldoa";
+			qcom,resource-id = <20>;
+			qcom,regulator-type = <0>;
+			qcom,hpm-min-load = <10000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-l20 {
+				regulator-name = "8941_l20";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-ldoa21 {
+			qcom,resource-name = "ldoa";
+			qcom,resource-id = <21>;
+			qcom,regulator-type = <0>;
+			qcom,hpm-min-load = <10000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-l21 {
+				regulator-name = "8941_l21";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-ldoa22 {
+			qcom,resource-name = "ldoa";
+			qcom,resource-id = <22>;
+			qcom,regulator-type = <0>;
+			qcom,hpm-min-load = <10000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-l22 {
+				regulator-name = "8941_l22";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-ldoa23 {
+			qcom,resource-name = "ldoa";
+			qcom,resource-id = <23>;
+			qcom,regulator-type = <0>;
+			qcom,hpm-min-load = <10000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-l23 {
+				regulator-name = "8941_l23";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-ldoa24 {
+			qcom,resource-name = "ldoa";
+			qcom,resource-id = <24>;
+			qcom,regulator-type = <0>;
+			qcom,hpm-min-load = <10000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-l24 {
+				regulator-name = "8941_l24";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		/* TODO: find out correct resource names for LVS vs MVS */
+		rpm-regulator-vsa1 {
+			qcom,resource-name = "vsa";
+			qcom,resource-id = <1>;
+			qcom,regulator-type = <2>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-lvs1 {
+				regulator-name = "8941_lvs1";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-vsa2 {
+			qcom,resource-name = "vsa";
+			qcom,resource-id = <2>;
+			qcom,regulator-type = <2>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-lvs2 {
+				regulator-name = "8941_lvs2";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-vsa3 {
+			qcom,resource-name = "vsa";
+			qcom,resource-id = <3>;
+			qcom,regulator-type = <2>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-lvs3 {
+				regulator-name = "8941_lvs3";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-vsa4 {
+			qcom,resource-name = "vsa";
+			qcom,resource-id = <4>;
+			qcom,regulator-type = <2>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-mvs1 {
+				regulator-name = "8941_mvs1";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-vsa5 {
+			qcom,resource-name = "vsa";
+			qcom,resource-id = <5>;
+			qcom,regulator-type = <2>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-mvs2 {
+				regulator-name = "8941_mvs2";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/msm9625.dts b/arch/arm/boot/dts/msm9625.dts
new file mode 100644
index 0000000..d5aed00
--- /dev/null
+++ b/arch/arm/boot/dts/msm9625.dts
@@ -0,0 +1,47 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/include/ "skeleton.dtsi"
+
+/ {
+	model = "Qualcomm MSM 9625";
+	compatible = "qcom,msm9625";
+	interrupt-parent = <&intc>;
+
+	intc: interrupt-controller@F9000000 {
+		compatible = "qcom,msm-qgic2";
+		interrupt-controller;
+		#interrupt-cells = <3>;
+		reg = <0xF9000000 0x1000>,
+		      <0xF9002000 0x1000>;
+	};
+
+	msmgpio: gpio@fd510000 {
+		compatible = "qcom,msm-gpio";
+		interrupt-controller;
+		#interrupt-cells = <2>;
+		reg = <0xfd510000 0x4000>;
+	};
+
+	timer {
+		compatible = "qcom,msm-qtimer", "arm,armv7-timer";
+		interrupts = <0 7 0>;
+		clock-frequency = <5000000>;
+	};
+
+	serial@f991f000 {
+		compatible = "qcom,msm-lsuart-v14";
+		reg = <0xf991f000 0x1000>;
+		interrupts = <0 109 0>;
+	};
+};
diff --git a/arch/arm/boot/dts/msmcopper-iommu.dtsi b/arch/arm/boot/dts/msmcopper-iommu.dtsi
new file mode 100644
index 0000000..e0ce8ac
--- /dev/null
+++ b/arch/arm/boot/dts/msmcopper-iommu.dtsi
@@ -0,0 +1,88 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/ {
+	jpeg: qcom,iommu@fda64000 {
+		compatible = "qcom,msm-smmu-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		reg = <0xfda64000 0x10000>;
+
+		qcom,iommu-ctx@fda6c000 {
+			reg = <0xfda6c000 0x1000>;
+			interrupts = <0 69 0>;
+			qcom,iommu-ctx-sids = <0>;
+			qcom,iommu-ctx-name = "jpeg_enc0";
+		};
+		qcom,iommu-ctx@fda6d000 {
+			reg = <0xfda6d000 0x1000>;
+			interrupts = <0 70 0>;
+			qcom,iommu-ctx-sids = <1>;
+			qcom,iommu-ctx-name = "jpeg_enc1";
+		};
+		qcom,iommu-ctx@fda6e000 {
+			reg = <0xfda6e000 0x1000>;
+			interrupts = <0 71 0>;
+			qcom,iommu-ctx-sids = <2>;
+			qcom,iommu-ctx-name = "jpeg_dec";
+		};
+	};
+
+	mdp: qcom,iommu@fd928000 {
+		compatible = "qcom,msm-smmu-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		reg = <0xfd928000 0x10000>;
+
+		qcom,iommu-ctx@fd930000 {
+			reg = <0xfd930000 0x1000>;
+			interrupts = <0 74 0>;
+			qcom,iommu-ctx-sids = <0>;
+			qcom,iommu-ctx-name = "mdp_0";
+		};
+		qcom,iommu-ctx@fd931000 {
+			reg = <0xfd931000 0x1000>;
+			interrupts = <0 75 0>;
+			qcom,iommu-ctx-sids = <1>;
+			qcom,iommu-ctx-name = "mdp_1";
+		};
+	};
+
+	venus: qcom,iommu@fdc84000 {
+		compatible = "qcom,msm-smmu-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		reg = <0xfdc84000 0x10000>;
+
+		qcom,iommu-ctx@fdc8c000 {
+			reg = <0xfdc8c000 0x1000>;
+			interrupts = <0 43 0>;
+			qcom,iommu-ctx-sids = <0 1 2 3 4 5>;
+			qcom,iommu-ctx-name = "venus_ns";
+		};
+		qcom,iommu-ctx@fdc8d000 {
+			reg = <0xfdc8d000 0x1000>;
+			interrupts = <0 42 0>;
+			qcom,iommu-ctx-sids = <0x80 0x81 0x82 0x83 0x84 0x85>;
+			qcom,iommu-ctx-name = "venus_cp";
+		};
+		qcom,iommu-ctx@fdc8e000 {
+			reg = <0xfdc8e000 0x1000>;
+			interrupts = <0 41 0>;
+			qcom,iommu-ctx-sids = <0xc0 0xc6>;
+			qcom,iommu-ctx-name = "venus_fw";
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/msmcopper-regulator.dtsi b/arch/arm/boot/dts/msmcopper-regulator.dtsi
index 48d5720..0d0c587 100644
--- a/arch/arm/boot/dts/msmcopper-regulator.dtsi
+++ b/arch/arm/boot/dts/msmcopper-regulator.dtsi
@@ -41,7 +41,7 @@
 				status = "okay";
 			};
 
-			pm8941_boost: regulator@1d00 {
+			pm8941_boost: regulator@a000 {
 				regulator-min-microvolt = <5000000>;
 				regulator-max-microvolt = <5000000>;
 				qcom,enable-time = <500>;
@@ -313,6 +313,7 @@
 				regulator-max-microvolt = <1150000>;
 				qcom,enable-time = <500>;
 				qcom,pull-down-enable = <1>;
+				regulator-always-on;
 				status = "okay";
 			};
 
diff --git a/arch/arm/boot/dts/msmcopper-rumi.dts b/arch/arm/boot/dts/msmcopper-rumi.dts
index 8c00535..dff1973 100644
--- a/arch/arm/boot/dts/msmcopper-rumi.dts
+++ b/arch/arm/boot/dts/msmcopper-rumi.dts
@@ -30,11 +30,19 @@
 		status = "disable";
 	};
 
-	qcom,sdcc@f980b000 {
+	qcom,sdcc@f9824000 {
+                qcom,sdcc-clk-rates = <400000 19200000>;
+        };
+
+        qcom,sdcc@f98a4000 {
+                qcom,sdcc-clk-rates = <400000 19200000>;
+        };
+
+	qcom,sdcc@f9864000 {
 		status = "disable";
 	};
 
-	qcom,sdcc@f984b000 {
+	qcom,sdcc@f98e4000 {
 		status = "disable";
 	};
 
@@ -67,6 +75,23 @@
 		};
 	};
 
+	i2c@f9966000 {
+		status = "disable";
+	};
+
+	i2c@f9967000 {
+		cell-index = <0>;
+		compatible = "qcom,i2c-qup";
+		reg = <0Xf9967000 0x1000>;
+		reg-names = "qup_phys_addr";
+		interrupts = <0 105 0>;
+		interrupt-names = "qup_err_intr";
+		qcom,i2c-bus-freq = <100000>;
+		qcom,i2c-src-freq = <24000000>;
+		gpios = <&msmgpio 83 0>, /* DAT  */
+			<&msmgpio 84 0>; /* CLK */
+	};
+
 	slim@fe12f000 {
 		status = "disable";
 	};
@@ -75,10 +100,6 @@
 		status = "disable";
 	};
 
-	i2c@f9966000 {
-		status = "disable";
-	};
-
 	qcom,ssusb@F9200000 {
 		status = "disable";
 	};
diff --git a/arch/arm/boot/dts/msmcopper-sim.dts b/arch/arm/boot/dts/msmcopper-sim.dts
index ab6b8ba..ae3f2dd 100644
--- a/arch/arm/boot/dts/msmcopper-sim.dts
+++ b/arch/arm/boot/dts/msmcopper-sim.dts
@@ -17,4 +17,22 @@
 / {
 	model = "Qualcomm MSM Copper Simulator";
 	compatible = "qcom,msmcopper-sim", "qcom,msmcopper";
+
+	qcom,sdcc@f9824000 {
+		qcom,sdcc-disable_cmd23;
+	};
+
+	qcom,sdcc@f98a4000 {
+		status = "disable";
+	};
+
+	qcom,sdcc@f9864000 {
+		qcom,sdcc-clk-rates = <400000 25000000 50000000 100000000 200000000>;
+		qcom,sdcc-sup-voltages = <2950 2950>;
+		qcom,sdcc-disable_cmd23;
+	};
+
+	qcom,sdcc@f98e4000 {
+		status = "disable";
+	};
 };
diff --git a/arch/arm/boot/dts/msmcopper.dtsi b/arch/arm/boot/dts/msmcopper.dtsi
index 89a726e..a902ba5 100644
--- a/arch/arm/boot/dts/msmcopper.dtsi
+++ b/arch/arm/boot/dts/msmcopper.dtsi
@@ -12,10 +12,13 @@
 
 /include/ "skeleton.dtsi"
 /include/ "msmcopper_pm.dtsi"
+/include/ "msm-pm8x41-rpm-regulator.dtsi"
 /include/ "msm-pm8841.dtsi"
 /include/ "msm-pm8941.dtsi"
 /include/ "msmcopper-regulator.dtsi"
 /include/ "msmcopper-gpio.dtsi"
+/include/ "msmcopper-iommu.dtsi"
+/include/ "msm-gdsc.dtsi"
 
 / {
 	model = "Qualcomm MSM Copper";
@@ -75,30 +78,50 @@
 		qcom,hsusb-otg-otg-control = <1>;
 	};
 
-	qcom,sdcc@f980b000 {
+	qcom,sdcc@f9824000 {
 		cell-index = <1>;
 		compatible = "qcom,msm-sdcc";
-		reg = <0xf980b000 0x1000>;
+		reg = <0xf9824000 0x1000>;
 		interrupts = <0 123 0>;
 
-		qcom,sdcc-clk-rates = <400000 25000000 50000000 96000000 192000000>;
-		qcom,sdcc-sup-voltages = <3300 3300>;
+		qcom,sdcc-clk-rates = <400000 25000000 50000000 100000000 200000000>;
+		qcom,sdcc-sup-voltages = <2950 2950>;
 		qcom,sdcc-bus-width = <8>;
 		qcom,sdcc-hs200;
 		qcom,sdcc-nonremovable;
-		qcom,sdcc-disable_cmd23;
 	};
 
-	qcom,sdcc@f984b000 {
+	qcom,sdcc@f98a4000 {
+		cell-index = <2>;
+		compatible = "qcom,msm-sdcc";
+		reg = <0xf98a4000 0x1000>;
+		interrupts = <0 125 0>;
+
+		qcom,sdcc-clk-rates = <400000 25000000 50000000 100000000 200000000>;
+		qcom,sdcc-sup-voltages = <2950 2950>;
+		qcom,sdcc-bus-width = <4>;
+	};
+
+	qcom,sdcc@f9864000 {
 		cell-index = <3>;
 		compatible = "qcom,msm-sdcc";
-		reg = <0xf984b000 0x1000>;
+		reg = <0xf9864000 0x1000>;
 		interrupts = <0 127 0>;
 
-		qcom,sdcc-clk-rates = <400000 25000000 50000000>;
-		qcom,sdcc-sup-voltages = <3300 3300>;
+		qcom,sdcc-clk-rates = <400000 25000000 50000000 100000000>;
+		qcom,sdcc-sup-voltages = <1800 1800>;
 		qcom,sdcc-bus-width = <4>;
-		qcom,sdcc-disable_cmd23;
+	};
+
+	qcom,sdcc@f98e4000 {
+		cell-index = <4>;
+		compatible = "qcom,msm-sdcc";
+		reg = <0xf98e4000 0x1000>;
+		interrupts = <0 129 0>;
+
+		qcom,sdcc-clk-rates = <400000 25000000 50000000 100000000>;
+		qcom,sdcc-sup-voltages = <1800 1800>;
+		qcom,sdcc-bus-width = <4>;
 	};
 
 	qcom,sps@f9980000 {
@@ -110,11 +133,12 @@
 		qcom,bam-dma-res-pipes = <6>;
 	};
 
+
 	spi@f9924000 {
 		compatible = "qcom,spi-qup-v2";
 		reg = <0xf9924000 0x1000>;
 		interrupts = <0 96 0>;
-		spi-max-frequency = <24000000>;
+		spi-max-frequency = <25000000>;
 	};
 
 	slim@fe12f000 {
@@ -253,13 +277,37 @@
 		qcom,dwc-usb3-msm-dbm-eps = <4>;
 	};
 
+	gdsc_oxili_gx: qcom,gdsc@fd8c4024 {
+		parent-supply = <&pm8841_s4>;
+	};
+
 	qcom,lpass@fe200000 {
 		compatible = "qcom,pil-q6v5-lpass";
 		reg = <0xfe200000 0x00100>,
-		      <0xfe000000 0x40000>,
 		      <0xfd485100 0x00010>;
 
-		qcom,firmware-name = "lpass";
+		qcom,firmware-name = "adsp";
+	};
+
+	qcom,mss@fc880000 {
+		compatible = "qcom,pil-q6v5-mss";
+		reg = <0xfc880000 0x100>,
+		      <0xfd485000 0x400>,
+		      <0xfc820000 0x020>,
+		      <0xfc401680 0x004>;
+		vdd_mss-supply = <&pm8841_s3>;
+
+		qcom,firmware-name = "mba";
+		qcom,pil-self-auth = <1>;
+	};
+
+	qcom,mba@fc820000 {
+		compatible = "qcom,pil-mba";
+		reg = <0xfc820000 0x0020>,
+		      <0x0d1fc000 0x4000>;
+
+		qcom,firmware-name = "modem";
+		qcom,depends-on    = "mba";
 	};
 
 	qcom,pronto@fb21b000 {
@@ -275,4 +323,15 @@
 	qcom,ocmem@fdd00000 {
 		compatible = "qcom,msm_ocmem";
 	};
+
+	qcom,rpm-smd {
+		compatible = "qcom,rpm-smd";
+		rpm-channel-name = "rpm_requests";
+		rpm-channel-type = <15>; /* SMD_APPS_RPM */
+	};
+
+        qcom,msm-rng@f9bff000 {
+               compatible = "qcom,msm-rng";
+               reg = <0xf9bff000 0x200>;
+        };
 };
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
index 875b479..99747ba 100644
--- a/arch/arm/common/gic.c
+++ b/arch/arm/common/gic.c
@@ -212,10 +212,13 @@
 {
 	unsigned int i;
 	void __iomem *base = gic_data_dist_base(gic);
+#ifdef CONFIG_ARCH_MSM8625
+	unsigned long flags;
+#endif
 
 	for (i = 0; i * 32 < gic->max_irq; i++) {
 #ifdef CONFIG_ARCH_MSM8625
-		raw_spin_lock(&irq_controller_lock);
+		raw_spin_lock_irqsave(&irq_controller_lock, flags);
 #endif
 		gic->enabled_irqs[i]
 			= readl_relaxed(base + GIC_DIST_ENABLE_SET + i * 4);
@@ -225,7 +228,7 @@
 		writel_relaxed(gic->wakeup_irqs[i],
 			base + GIC_DIST_ENABLE_SET + i * 4);
 #ifdef CONFIG_ARCH_MSM8625
-		raw_spin_unlock(&irq_controller_lock);
+		raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 #endif
 	}
 	mb();
@@ -248,17 +251,28 @@
 	u32 enabled;
 	unsigned long pending[32];
 	void __iomem *base = gic_data_dist_base(gic);
+#ifdef CONFIG_ARCH_MSM8625
+	unsigned long flags;
+#endif
 
 	if (!msm_show_resume_irq_mask)
 		return;
 
+#ifdef CONFIG_ARCH_MSM8625
+	raw_spin_lock_irqsave(&irq_controller_lock, flags);
+#else
 	raw_spin_lock(&irq_controller_lock);
+#endif
 	for (i = 0; i * 32 < gic->max_irq; i++) {
 		enabled = readl_relaxed(base + GIC_DIST_ENABLE_CLEAR + i * 4);
 		pending[i] = readl_relaxed(base + GIC_DIST_PENDING_SET + i * 4);
 		pending[i] &= enabled;
 	}
-	raw_spin_unlock(&irq_controller_lock);
+#ifdef CONFIG_ARCH_MSM8625
+	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
+#else
+	raw_spin_lock(&irq_controller_lock);
+#endif
 
 	for (i = find_first_bit(pending, gic->max_irq);
 	     i < gic->max_irq;
@@ -272,11 +286,13 @@
 {
 	unsigned int i;
 	void __iomem *base = gic_data_dist_base(gic);
-
+#ifdef CONFIG_ARCH_MSM8625
+	unsigned long flags;
+#endif
 	gic_show_resume_irq(gic);
 	for (i = 0; i * 32 < gic->max_irq; i++) {
 #ifdef CONFIG_ARCH_MSM8625
-		raw_spin_lock(&irq_controller_lock);
+		raw_spin_lock_irqsave(&irq_controller_lock, flags);
 #endif
 		/* disable all of them */
 		writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4);
@@ -284,7 +300,7 @@
 		writel_relaxed(gic->enabled_irqs[i],
 			base + GIC_DIST_ENABLE_SET + i * 4);
 #ifdef CONFIG_ARCH_MSM8625
-		raw_spin_unlock(&irq_controller_lock);
+		raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 #endif
 	}
 	mb();
@@ -1128,8 +1144,9 @@
 	unsigned long value = 0;
 	struct gic_chip_data *gic = &gic_data[0];
 	void __iomem *base = gic_data_dist_base(gic);
+	unsigned long flags;
 
-	raw_spin_lock(&irq_controller_lock);
+	raw_spin_lock_irqsave(&irq_controller_lock, flags);
 	/*
 	 * PPI and SGI to be included.
 	 * MSM8625_INT_A9_M2A_5 needs to be ignored, as A9_M2A_5
@@ -1146,13 +1163,14 @@
 			for (bit = 0; bit < 32; bit++) {
 				bit = find_next_bit(&value, 32, bit);
 				if ((bit + 32 * i) != MSM8625_INT_A9_M2A_5) {
-					raw_spin_unlock(&irq_controller_lock);
+					raw_spin_unlock_irqrestore(
+						&irq_controller_lock, flags);
 					return 1;
 				}
 			}
 		}
 	}
-	raw_spin_unlock(&irq_controller_lock);
+	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 
 	return 0;
 }
@@ -1165,14 +1183,13 @@
 
 	gic_cpu_save(0);
 	gic_dist_save(0);
-	 /* Disable all the Interrupts, if we enter from idle pc */
-	if (from_idle) {
-		for (i = 0; (i * 32) < gic->max_irq; i++) {
-			raw_spin_lock(&irq_controller_lock);
-			writel_relaxed(0xffffffff, base
-					+ GIC_DIST_ENABLE_CLEAR + i * 4);
-			raw_spin_unlock(&irq_controller_lock);
-		}
+
+	/* Disable all the Interrupts, before we enter pc */
+	for (i = 0; (i * 32) < gic->max_irq; i++) {
+		raw_spin_lock(&irq_controller_lock);
+		writel_relaxed(0xffffffff, base
+				+ GIC_DIST_ENABLE_CLEAR + i * 4);
+		raw_spin_unlock(&irq_controller_lock);
 	}
 }
 
@@ -1193,8 +1210,9 @@
 	struct gic_chip_data *gic = &gic_data[0];
 	void __iomem *base = gic_data_dist_base(gic);
 	unsigned int value = 0;
+	unsigned long flags;
 
-	raw_spin_lock(&irq_controller_lock);
+	raw_spin_lock_irqsave(&irq_controller_lock, flags);
 
 	value = __raw_readl(base + GIC_DIST_ACTIVE_BIT + 0x4);
 	value |= BIT(8);
@@ -1220,6 +1238,6 @@
 	value |= BIT(8);
 	__raw_writel(value, base + GIC_DIST_PENDING_SET + 0x4);
 	mb();
-	raw_spin_unlock(&irq_controller_lock);
+	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
 #endif
diff --git a/arch/arm/configs/msm-copper_defconfig b/arch/arm/configs/msm-copper_defconfig
index eb2c2c8..0b44865 100644
--- a/arch/arm/configs/msm-copper_defconfig
+++ b/arch/arm/configs/msm-copper_defconfig
@@ -43,6 +43,10 @@
 CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
 # CONFIG_MSM_HW3D is not set
 CONFIG_MSM_PIL_LPASS_QDSP6V5=y
+CONFIG_MSM_PIL_MSS_QDSP6V5=y
+CONFIG_MSM_PIL_MBA=y
+CONFIG_MSM_PIL_PRONTO=y
+CONFIG_MSM_IOMMU=y
 CONFIG_MSM_DIRECT_SCLK_ACCESS=y
 CONFIG_MSM_OCMEM=y
 CONFIG_NO_HZ=y
@@ -126,6 +130,12 @@
 CONFIG_REGULATOR=y
 CONFIG_REGULATOR_STUB=y
 CONFIG_REGULATOR_QPNP=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_VIDEO_DEV=y
+# CONFIG_RC_CORE is not set
+# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
+# CONFIG_VIDEO_CAPTURE_DRIVERS is not set
+# CONFIG_RADIO_ADAPTERS is not set
 CONFIG_ION=y
 CONFIG_ION_MSM=y
 CONFIG_FB=y
@@ -196,3 +206,6 @@
 CONFIG_CRYPTO_DEFLATE=y
 CONFIG_CRC_CCITT=y
 CONFIG_LIBCRC32C=y
+CONFIG_MSM_TZ_LOG=y
+CONFIG_HW_RANDOM_MSM=y
+
diff --git a/arch/arm/configs/msm7627a-perf_defconfig b/arch/arm/configs/msm7627a-perf_defconfig
index f195d68..9a2fa39 100644
--- a/arch/arm/configs/msm7627a-perf_defconfig
+++ b/arch/arm/configs/msm7627a-perf_defconfig
@@ -241,7 +241,7 @@
 CONFIG_MSM_CAMERA_V4L2=y
 CONFIG_OV5647=y
 CONFIG_AD5046_ACT=y
-CONFIG_WEBCAM_OV7692_QRD=y
+CONFIG_OV7692=y
 CONFIG_WEBCAM_OV9726=y
 CONFIG_MT9E013=y
 CONFIG_S5K4E1=y
diff --git a/arch/arm/configs/msm7627a_defconfig b/arch/arm/configs/msm7627a_defconfig
index bc350a7..869fb6d 100644
--- a/arch/arm/configs/msm7627a_defconfig
+++ b/arch/arm/configs/msm7627a_defconfig
@@ -242,7 +242,7 @@
 CONFIG_MSM_CAMERA_V4L2=y
 CONFIG_OV5647=y
 CONFIG_AD5046_ACT=y
-CONFIG_WEBCAM_OV7692_QRD=y
+CONFIG_OV7692=y
 CONFIG_WEBCAM_OV9726=y
 CONFIG_MT9E013=y
 CONFIG_S5K4E1=y
diff --git a/arch/arm/configs/msm7630-perf_defconfig b/arch/arm/configs/msm7630-perf_defconfig
index 736f2bb..456eb9c 100644
--- a/arch/arm/configs/msm7630-perf_defconfig
+++ b/arch/arm/configs/msm7630-perf_defconfig
@@ -279,6 +279,7 @@
 CONFIG_FB_MSM_TRIPLE_BUFFER=y
 CONFIG_FB_MSM_MDP40=y
 CONFIG_FB_MSM_OVERLAY=y
+CONFIG_FB_MSM_OVERLAY0_WRITEBACK=y
 CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM=y
 CONFIG_FB_MSM_HDMI_ADV7520_PANEL=y
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
diff --git a/arch/arm/configs/msm7630_defconfig b/arch/arm/configs/msm7630_defconfig
index bc464b4..fd11d67 100644
--- a/arch/arm/configs/msm7630_defconfig
+++ b/arch/arm/configs/msm7630_defconfig
@@ -281,6 +281,7 @@
 CONFIG_FB_MSM_TRIPLE_BUFFER=y
 CONFIG_FB_MSM_MDP40=y
 CONFIG_FB_MSM_OVERLAY=y
+CONFIG_FB_MSM_OVERLAY0_WRITEBACK=y
 CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM=y
 CONFIG_FB_MSM_HDMI_ADV7520_PANEL=y
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
diff --git a/arch/arm/configs/msm8660-perf_defconfig b/arch/arm/configs/msm8660-perf_defconfig
index 87296cc..a6bbaf4 100644
--- a/arch/arm/configs/msm8660-perf_defconfig
+++ b/arch/arm/configs/msm8660-perf_defconfig
@@ -69,7 +69,6 @@
 CONFIG_MSM_SUBSYSTEM_RESTART=y
 CONFIG_MSM_RPM_LOG=y
 CONFIG_MSM_RPM_STATS_LOG=y
-CONFIG_MSM_IOMMU=y
 CONFIG_MSM_WATCHDOG=y
 CONFIG_MSM_DLOAD_MODE=y
 CONFIG_MSM_ETM=y
diff --git a/arch/arm/configs/msm8660_defconfig b/arch/arm/configs/msm8660_defconfig
index fd06714..df49bdc 100644
--- a/arch/arm/configs/msm8660_defconfig
+++ b/arch/arm/configs/msm8660_defconfig
@@ -68,7 +68,6 @@
 CONFIG_MSM_SUBSYSTEM_RESTART=y
 CONFIG_MSM_RPM_LOG=y
 CONFIG_MSM_RPM_STATS_LOG=y
-CONFIG_MSM_IOMMU=y
 CONFIG_MSM_WATCHDOG=y
 CONFIG_MSM_DLOAD_MODE=y
 CONFIG_MSM_ETM=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index fb5cff7..14ba936 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -61,7 +61,9 @@
 # CONFIG_MSM_PROC_COMM is not set
 CONFIG_MSM_SMD=y
 CONFIG_MSM_SMD_PKG4=y
+CONFIG_MSM_PCIE=y
 CONFIG_MSM_BAM_DMUX=y
+CONFIG_MSM_RMNET_SMUX=y
 CONFIG_MSM_DSPS=y
 CONFIG_MSM_IPC_ROUTER=y
 CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
@@ -92,6 +94,8 @@
 CONFIG_MSM_DCVS=y
 CONFIG_MSM_HSIC_SYSMON=y
 CONFIG_STRICT_MEMORY_RWX=y
+CONFIG_PCI=y
+CONFIG_PCI_MSI=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_SMP=y
@@ -227,7 +231,7 @@
 CONFIG_BT_BNEP_PROTO_FILTER=y
 CONFIG_BT_HIDP=y
 CONFIG_BT_HCISMD=y
-CONFIG_CFG80211=y
+CONFIG_CFG80211=m
 # CONFIG_CFG80211_WEXT is not set
 CONFIG_RFKILL=y
 CONFIG_GENLOCK=y
@@ -279,6 +283,9 @@
 CONFIG_INPUT_UINPUT=y
 CONFIG_INPUT_PMIC8XXX_PWRKEY=y
 # CONFIG_LEGACY_PTYS is not set
+CONFIG_N_SMUX=y
+CONFIG_N_SMUX_LOOPBACK=y
+CONFIG_SMUX_CTL=y
 CONFIG_SERIAL_MSM_HS=y
 CONFIG_SERIAL_MSM_HSL=y
 CONFIG_SERIAL_MSM_HSL_CONSOLE=y
@@ -302,6 +309,7 @@
 CONFIG_SMB349_CHARGER=y
 CONFIG_PM8921_CHARGER=y
 CONFIG_PM8921_BMS=y
+CONFIG_PM8921_BCL=y
 CONFIG_SENSORS_PM8XXX_ADC=y
 CONFIG_SENSORS_EPM_ADC=y
 CONFIG_THERMAL=y
@@ -321,6 +329,7 @@
 CONFIG_MEDIA_CONTROLLER=y
 CONFIG_VIDEO_DEV=y
 CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_USER_RC_INPUT=y
 CONFIG_IR_GPIO_CIR=y
 # CONFIG_MEDIA_TUNER_CUSTOMISE is not set
 CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
@@ -330,6 +339,7 @@
 CONFIG_MT9M114=y
 CONFIG_IMX074_ACT=y
 CONFIG_MSM_CAMERA_FLASH_SC628A=y
+CONFIG_MSM_CAMERA_FLASH_TPS61310=y
 CONFIG_OV2720=y
 CONFIG_MSM_CAMERA_SENSOR=y
 CONFIG_MSM_ACTUATOR=y
@@ -436,6 +446,8 @@
 CONFIG_MSM_SSBI=y
 CONFIG_SPS=y
 CONFIG_SPS_SUPPORT_BAMDMA=y
+CONFIG_MOBICORE_SUPPORT=m
+CONFIG_MOBICORE_API=m
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT3_FS=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 5c01299..24b1c7d 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -60,7 +60,9 @@
 # CONFIG_MSM_PROC_COMM is not set
 CONFIG_MSM_SMD=y
 CONFIG_MSM_SMD_PKG4=y
+CONFIG_MSM_PCIE=y
 CONFIG_MSM_BAM_DMUX=y
+CONFIG_MSM_RMNET_SMUX=y
 CONFIG_MSM_DSPS=y
 CONFIG_MSM_IPC_ROUTER=y
 CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
@@ -99,6 +101,8 @@
 CONFIG_MSM_CACHE_DUMP_ON_PANIC=y
 CONFIG_MSM_HSIC_SYSMON=y
 CONFIG_STRICT_MEMORY_RWX=y
+CONFIG_PCI=y
+CONFIG_PCI_MSI=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_SMP=y
@@ -234,7 +238,7 @@
 CONFIG_BT_BNEP_PROTO_FILTER=y
 CONFIG_BT_HIDP=y
 CONFIG_BT_HCISMD=y
-CONFIG_CFG80211=y
+CONFIG_CFG80211=m
 # CONFIG_CFG80211_WEXT is not set
 CONFIG_RFKILL=y
 CONFIG_GENLOCK=y
@@ -288,6 +292,9 @@
 CONFIG_INPUT_UINPUT=y
 CONFIG_INPUT_PMIC8XXX_PWRKEY=y
 # CONFIG_LEGACY_PTYS is not set
+CONFIG_N_SMUX=y
+CONFIG_N_SMUX_LOOPBACK=y
+CONFIG_SMUX_CTL=y
 CONFIG_SERIAL_MSM_HS=y
 CONFIG_SERIAL_MSM_HSL=y
 CONFIG_SERIAL_MSM_HSL_CONSOLE=y
@@ -311,6 +318,7 @@
 CONFIG_SMB349_CHARGER=y
 CONFIG_PM8921_CHARGER=y
 CONFIG_PM8921_BMS=y
+CONFIG_PM8921_BCL=y
 CONFIG_SENSORS_PM8XXX_ADC=y
 CONFIG_SENSORS_EPM_ADC=y
 CONFIG_THERMAL=y
@@ -330,6 +338,7 @@
 CONFIG_MEDIA_CONTROLLER=y
 CONFIG_VIDEO_DEV=y
 CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_USER_RC_INPUT=y
 CONFIG_IR_GPIO_CIR=y
 # CONFIG_MEDIA_TUNER_CUSTOMISE is not set
 CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
@@ -339,15 +348,16 @@
 CONFIG_MT9M114=y
 CONFIG_IMX074_ACT=y
 CONFIG_MSM_CAMERA_FLASH_SC628A=y
+CONFIG_MSM_CAMERA_FLASH_TPS61310=y
 CONFIG_OV2720=y
 CONFIG_MSM_CAMERA_SENSOR=y
 CONFIG_MSM_ACTUATOR=y
-CONFIG_MSM_GEMINI=y
-CONFIG_S5K3L1YX=y
-CONFIG_IMX091=y
 CONFIG_MSM_EEPROM=y
 CONFIG_IMX074_EEPROM=y
 CONFIG_IMX091_EEPROM=y
+CONFIG_MSM_GEMINI=y
+CONFIG_S5K3L1YX=y
+CONFIG_IMX091=y
 CONFIG_RADIO_IRIS=y
 CONFIG_RADIO_IRIS_TRANSPORT=m
 CONFIG_ION=y
@@ -445,6 +455,8 @@
 CONFIG_MSM_SSBI=y
 CONFIG_SPS=y
 CONFIG_SPS_SUPPORT_BAMDMA=y
+CONFIG_MOBICORE_SUPPORT=m
+CONFIG_MOBICORE_API=m
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT3_FS=y
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
new file mode 100644
index 0000000..89fb888
--- /dev/null
+++ b/arch/arm/configs/msm9625_defconfig
@@ -0,0 +1,107 @@
+CONFIG_EXPERIMENTAL=y
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_SPARSE_IRQ=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_FAIR_GROUP_SCHED is not set
+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_KALLSYMS_ALL=y
+CONFIG_EMBEDDED=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=m
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_ARCH_MSM=y
+CONFIG_ARCH_MSM9625=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_DIRECT_SCLK_ACCESS=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_ARM_ARCH_TIMER=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_HIGHMEM=y
+CONFIG_VMALLOC_RESERVE=0x19000000
+CONFIG_USE_OF=y
+CONFIG_ARM_APPENDED_DTB=y
+CONFIG_ARM_ATAG_DTB_COMPAT=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_SUSPEND is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_MISC_DEVICES=y
+# CONFIG_ANDROID_PMEM is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=m
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_MSM_HSL=y
+CONFIG_SERIAL_MSM_HSL_CONSOLE=y
+CONFIG_HW_RANDOM=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+# CONFIG_HWMON is not set
+# CONFIG_MFD_SUPPORT is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
+CONFIG_DEBUG_KERNEL=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_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_USER=y
+CONFIG_KEYS=y
+CONFIG_CRYPTO_AUTHENC=y
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_AES=y
+CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_DES=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_DEFLATE=y
+# CONFIG_CRYPTO_HW is not set
+CONFIG_CRC_CCITT=y
+CONFIG_CRC16=y
+CONFIG_LIBCRC32C=y
diff --git a/arch/arm/include/asm/mach/flash.h b/arch/arm/include/asm/mach/flash.h
index 36938ea..7ed9630 100644
--- a/arch/arm/include/asm/mach/flash.h
+++ b/arch/arm/include/asm/mach/flash.h
@@ -13,6 +13,11 @@
 struct mtd_partition;
 struct mtd_info;
 
+enum sw_version {
+	VERSION_1 = 0,
+	VERSION_2,
+};
+
 /*
  * map_name:	the map probe function name
  * name:	flash device name (eg, as used with mtdparts=)
@@ -24,6 +29,7 @@
  * mmcontrol:	method called to enable or disable Sync. Burst Read in OneNAND
  * parts:	optional array of mtd_partitions for static partitioning
  * nr_parts:	number of mtd_partitions for static partitoning
+ * version:	software register interface version
  */
 struct flash_platform_data {
 	const char	*map_name;
@@ -36,6 +42,7 @@
 	void		(*mmcontrol)(struct mtd_info *mtd, int sync_read);
 	struct mtd_partition *parts;
 	unsigned int	nr_parts;
+	enum sw_version	version;
 };
 
 #endif
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S
index 7f7e5c0..cf2d473 100644
--- a/arch/arm/kernel/vmlinux.lds.S
+++ b/arch/arm/kernel/vmlinux.lds.S
@@ -91,8 +91,10 @@
 
 #ifndef CONFIG_XIP_KERNEL
 	. = ALIGN(PAGE_SIZE);
+#ifndef CONFIG_STRICT_MEMORY_RWX
 	__init_end = .;
 #endif
+#endif
 
 	/*
 	 * unwind exit sections must be discarded before the rest of the
@@ -115,6 +117,7 @@
 
 #ifdef CONFIG_STRICT_MEMORY_RWX
 	. = ALIGN(1<<SECTION_SHIFT);
+	__init_end = .;
 #endif
 	.text : {			/* Real text segment		*/
 		_text = .;		/* Text and read-only data	*/
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 83e6666..e603703 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -8,7 +8,6 @@
 	select MSM_VIC
 	select CPU_V6
 	select MSM_REMOTE_SPINLOCK_SWP
-	select MSM_PM if PM
 
 config ARCH_MSM7X25
 	bool "MSM7x25"
@@ -17,7 +16,6 @@
 	select CPU_V6
 	select MSM_REMOTE_SPINLOCK_SWP
 	select MULTI_IRQ_HANDLER
-	select MSM_PM if PM
 
 config ARCH_MSM7X27
 	bool "MSM7x27"
@@ -96,6 +94,7 @@
 	select MSM_SECURE_IO
 	select MSM_DALRPC
 	select MSM_QDSP6_APR
+	select MSM_QDSP6_CODECS
 	select MSM_NATIVE_RESTART
 	select ARCH_INLINE_SPIN_TRYLOCK
 	select ARCH_INLINE_SPIN_TRYLOCK_BH
@@ -146,6 +145,7 @@
 	select MSM_RPM
 	select MSM_XO
 	select MSM_QDSP6_APR
+	select MSM_QDSP6_CODECS
 	select MSM_PIL
 	select MSM_AUDIO_QDSP6 if SND_SOC
 	select CPU_HAS_L2_PMU
@@ -157,7 +157,6 @@
 	select ARCH_POPULATES_NODE_MAP
 	select ARCH_SPARSEMEM_ENABLE
 	select ARCH_HAS_HOLES_MEMORYMODEL
-	select ENABLE_DMM
 	select MEMORY_HOTPLUG if ENABLE_DMM
 	select MEMORY_HOTREMOVE if ENABLE_DMM
 	select ARCH_ENABLE_MEMORY_HOTPLUG if ENABLE_DMM
@@ -188,6 +187,7 @@
 	select MSM_RPM
 	select MSM_XO
 	select MSM_QDSP6_APR
+	select MSM_QDSP6_CODECS
 	select MSM_PIL
 	select MSM_AUDIO_QDSP6 if SND_SOC
 	select CPU_HAS_L2_PMU
@@ -199,7 +199,6 @@
 	select ARCH_POPULATES_NODE_MAP
 	select ARCH_SPARSEMEM_ENABLE
 	select ARCH_HAS_HOLES_MEMORYMODEL
-	select ENABLE_DMM
 	select MEMORY_HOTPLUG if ENABLE_DMM
 	select MEMORY_HOTREMOVE if ENABLE_DMM
 	select ARCH_ENABLE_MEMORY_HOTPLUG if ENABLE_DMM
@@ -224,6 +223,7 @@
 	select MSM_REMOTE_SPINLOCK_SFPB
 	select MSM_PIL
 	select MSM_QDSP6_APR
+	select MSM_QDSP6_CODECS
 	select MSM_AUDIO_QDSP6 if SND_SOC
 	select MULTI_IRQ_HANDLER
 	select MSM_RPM
@@ -232,7 +232,6 @@
 	select MSM_PM8X60 if PM
 	select CPU_HAS_L2_PMU
 	select HOLES_IN_ZONE if SPARSEMEM
-	select ENABLE_DMM
 	select MEMORY_HOTPLUG if ENABLE_DMM
 	select MEMORY_HOTREMOVE if ENABLE_DMM
 	select ARCH_ENABLE_MEMORY_HOTPLUG if ENABLE_DMM
@@ -259,8 +258,9 @@
 	select MSM_PIL
 	select MSM_SPM_V2
 	select MSM_L2_SPM
-	select MSM_RPM
 	select MSM_PM8X60 if PM
+	select MSM_RPM_SMD
+	select REGULATOR
 
 config ARCH_FSM9XXX
 	bool "FSM9XXX"
@@ -312,6 +312,7 @@
 	select SMP
 	select MSM_SMP
 	select CPU_V7
+	select MSM_GPIOMUX
 	select MULTI_IRQ_HANDLER
 	select MSM_V2_TLMM
 
@@ -389,6 +390,10 @@
 	bool "Resource Power Manager"
 	select MSM_MPM
 
+config MSM_RPM_SMD
+	depends on MSM_SMD
+	bool "Support for using SMD as the transport layer for communicatons with RPM"
+
 config MSM_MPM
 	bool "Modem Power Manager"
 
@@ -880,7 +885,7 @@
 	default "0x80200000" if ARCH_APQ8064
 	default "0x80200000" if ARCH_MSM8960
 	default "0x80200000" if ARCH_MSM8930
-	default "0x20200000" if ARCH_MSMCOPPER
+	default "0x00000000" if ARCH_MSMCOPPER
 	default "0x10000000" if ARCH_FSM9XXX
 	default "0x20200000" if ARCH_MSM9625
 	default "0x00200000" if !MSM_STACKED_MEMORY
@@ -942,14 +947,6 @@
 	help
 	  Say Y here if high speed MSM UART v1.4 is present.
 
-config DEBUG_MSM8930_UART
-	bool "Kernel low-level debugging messages via MSM 8930 UART"
-	depends on ARCH_MSM8930 && DEBUG_LL
-	select MSM_HAS_DEBUG_UART_HS
-	help
-	  Say Y here if you want the debug print routines to direct
-	  their output to the serial port on MSM 8930 devices.
-
 config MSM_DEBUG_UART_PHYS
 	hex
 	default 0xA9A00000 if (ARCH_MSM7X27 || ARCH_QSD8X50) && DEBUG_MSM_UART1
@@ -996,13 +993,28 @@
 
 	config DEBUG_MSM8960_UART
 		bool "Kernel low-level debugging messages via MSM 8960 UART"
-		depends on ARCH_MSM8960
-		select DEBUG_MSM8930_UART
+		depends on ARCH_MSM8960 && DEBUG_LL
 		select MSM_HAS_DEBUG_UART_HS
 		help
 		  Say Y here if you want the debug print routines to direct
 		  their output to the serial port on MSM 8960 devices.
 
+	config DEBUG_MSM8930_UART
+		bool "Kernel low-level debugging messages via MSM 8930 UART"
+		depends on ARCH_MSM8930 && DEBUG_LL
+		select MSM_HAS_DEBUG_UART_HS
+		help
+		Say Y here if you want the debug print routines to direct
+		their output to the serial port on MSM 8930 devices.
+
+	config DEBUG_APQ8064_UART
+		bool "Kernel low-level debugging messages via APQ 8064 UART"
+		depends on ARCH_APQ8064 && DEBUG_LL
+		select MSM_HAS_DEBUG_UART_HS
+		help
+		Say Y here if you want the debug print routines to direct
+		their output to the serial port on APQ 8064 devices.
+
 	config DEBUG_MSMCOPPER_UART
 		bool "Kernel low-level debugging messages via MSM Copper UART"
 		depends on ARCH_MSMCOPPER
@@ -1798,6 +1810,18 @@
 	  voltages and other parameters of the various power rails supplied
 	  by some Qualcomm PMICs.
 
+config MSM_RPM_REGULATOR_SMD
+	bool "SMD RPM regulator driver"
+	depends on REGULATOR
+	depends on OF
+	depends on MSM_RPM_SMD
+	help
+	  Compile in support for the SMD RPM regulator driver which is used for
+	  setting voltages and other parameters of the various power rails
+	  supplied by some Qualcomm PMICs.  The SMD RPM regulator driver should
+	  be used on systems which contain an RPM which communicates with the
+	  application processor over SMD.
+
 config MSM_PIL
 	bool "Peripheral image loading"
 	select FW_LOADER
@@ -1833,8 +1857,22 @@
        tristate "LPASS QDSP6v5 (Hexagon) Boot Support"
        depends on MSM_PIL
        help
-         Support for booting and shutting down QDSP6v5 processors (Hexagon)
-	 processors in low power audio subsystems.
+         Support for booting and shutting down QDSP6v5 (Hexagon) processors
+	 in low power audio subsystems.
+
+config MSM_PIL_MSS_QDSP6V5
+       tristate "MSS QDSP6v5 (Hexagon) Boot Support"
+       depends on MSM_PIL
+       help
+         Support for booting and shutting down QDSP6v5 (Hexagon) processors
+	 in modem subsystems.
+
+config MSM_PIL_MBA
+	tristate "Support for modem self-authentication"
+	depends on MSM_PIL_MSS_QDSP6V5
+	help
+	  Support for booting self-authenticating modems using the Modem Boot
+	  Authenticator.
 
 config MSM_PIL_RIVA
 	tristate "RIVA (WCNSS) Boot Support"
@@ -1992,7 +2030,7 @@
 
 config MSM_IOMMU
 	bool "MSM IOMMU Support"
-	depends on ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_APQ8064
+	depends on ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_APQ8064 || ARCH_MSMCOPPER
 	select IOMMU_API
 	default n
 	help
@@ -2037,10 +2075,6 @@
 config MSM_NATIVE_RESTART
 	bool
 
-config MSM_PM
-	depends on PM
-	bool
-
 config MSM_PM2
 	depends on PM
 	bool
@@ -2176,6 +2210,15 @@
 	  used by audio driver to configure QDSP6's
 	  ASM, ADM and AFE.
 
+config MSM_QDSP6_CODECS
+	bool "Audio Codecs on QDSP6 APR "
+	depends on MSM_SMD
+	default n
+	help
+	  Enable Audio codecs with APR IPC protocol support between
+	  application processor and QDSP6. APR is
+	  used by audio driver to configure QDSP6's
+	  ASM, ADM and AFE.
 
 config MSM_AUDIO_QDSP6
         bool "QDSP6 HW Audio support"
@@ -2282,6 +2325,16 @@
 
 	  For production builds, you should probably say 'N' here.
 
+config MSM_L1_ERR_LOG
+	bool "Log CPU ERP events to system memory"
+	depends on MSM_CACHE_ERP
+	help
+	  Enable logging CPU ERP events to an area of memory that will be
+	  preserved across a system reset. This may be useful for detecting and
+	  troubleshooting ERP-related system crashes in the field.
+
+	  For production builds, you may want to say 'Y' here.
+
 config MSM_L2_ERP_PRINT_ACCESS_ERRORS
 	bool "Report L2 master port slave/decode errors in kernel log"
 	depends on MSM_CACHE_ERP
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index d633aa7..2ad51cd 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -68,6 +68,8 @@
 obj-$(CONFIG_MSM_PIL_QDSP6V3) += pil-q6v3.o
 obj-$(CONFIG_MSM_PIL_QDSP6V4) += pil-q6v4.o
 obj-$(CONFIG_MSM_PIL_LPASS_QDSP6V5) += pil-q6v5.o pil-q6v5-lpass.o
+obj-$(CONFIG_MSM_PIL_MSS_QDSP6V5) += pil-q6v5.o pil-q6v5-mss.o
+obj-$(CONFIG_MSM_PIL_MBA) += pil-mba.o
 obj-$(CONFIG_MSM_PIL_RIVA) += pil-riva.o
 obj-$(CONFIG_MSM_PIL_TZAPPS) += pil-tzapps.o
 obj-$(CONFIG_MSM_PIL_VIDC) += pil-vidc.o
@@ -107,11 +109,13 @@
 ifndef CONFIG_ARCH_MSM8X60
 ifndef CONFIG_ARCH_APQ8064
 ifndef CONFIG_ARCH_MSMCOPPER
+ifndef CONFIG_ARCH_MSM9625
 	obj-y += nand_partitions.o
 endif
 endif
 endif
 endif
+endif
 obj-$(CONFIG_MSM_SDIO_TTY) += sdio_tty.o
 obj-$(CONFIG_MSM_SMD_TTY) += smd_tty.o
 obj-$(CONFIG_MSM_SMD_QMI) += smd_qmi.o
@@ -152,8 +156,8 @@
 obj-$(CONFIG_MSM_HW3D) += hw3d.o
 obj-$(CONFIG_PM) += pm-boot.o
 obj-$(CONFIG_MSM_PM8X60) += pm-8x60.o pm-data.o
+obj-$(CONFIG_MSM_IDLE_STATS) += pm-stats.o
 obj-$(CONFIG_MSM_PM2) += pm2.o
-obj-$(CONFIG_MSM_PM) += pm.o
 obj-$(CONFIG_MSM_NOPM) += no-pm.o
 
 obj-$(CONFIG_MSM_PCIE) += pcie.o pcie_irq.o
@@ -186,6 +190,8 @@
 obj-$(CONFIG_ARCH_APQ8064) += rpm-regulator-8960.o
 endif
 
+obj-$(CONFIG_MSM_RPM_REGULATOR_SMD) += rpm-regulator-smd.o
+
 ifdef CONFIG_MSM_SUBSYSTEM_RESTART
 	obj-y += subsystem_notif.o
 	obj-y += subsystem_restart.o
@@ -281,6 +287,8 @@
 obj-$(CONFIG_ARCH_MSMCOPPER) += board-copper.o board-dt.o board-copper-regulator.o board-copper-gpiomux.o
 obj-$(CONFIG_ARCH_MSMCOPPER) += acpuclock-krait.o acpuclock-copper.o
 obj-$(CONFIG_ARCH_MSMCOPPER) += clock-local2.o clock-pll.o clock-copper.o
+obj-$(CONFIG_ARCH_MSMCOPPER) += gdsc.o
+obj-$(CONFIG_ARCH_MSM9625) += board-9625.o board-9625-gpiomux.o
 
 obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire.o board-sapphire-gpio.o
 obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-keypad.o board-sapphire-panel.o
@@ -303,6 +311,8 @@
 	obj-$(CONFIG_ARCH_MSM8960) += rpm_resources.o
 	obj-$(CONFIG_ARCH_MSM8X60) += rpm_resources.o
 	obj-$(CONFIG_ARCH_MSM9615) += rpm_resources.o
+endif
+ifdef CONFIG_MSM_RPM_SMD
 	obj-$(CONFIG_ARCH_MSMCOPPER) += lpm_levels.o
 endif
 obj-$(CONFIG_MSM_MPM) += mpm.o
@@ -313,12 +323,15 @@
 obj-$(CONFIG_MSM_BUS_SCALING) += msm_bus/
 obj-$(CONFIG_MSM_BUSPM_DEV) += msm-buspm-dev.o
 
-obj-$(CONFIG_MSM_IOMMU)		+= iommu.o iommu_dev.o devices-iommu.o iommu_domains.o
+obj-$(CONFIG_MSM_IOMMU)	+= iommu.o iommu_dev.o devices-iommu.o iommu_domains.o
+ifdef CONFIG_OF
+obj-$(CONFIG_MSM_IOMMU)	+= iommu-v2.o iommu_dev-v2.o iommu_pagetable.o
+endif
 
 ifdef CONFIG_VCM
 obj-$(CONFIG_ARCH_MSM8X60) += board-msm8x60-vcm.o
 endif
-obj-$(CONFIG_MSM_OCMEM) += ocmem.o
+obj-$(CONFIG_MSM_OCMEM) += ocmem.o ocmem_allocator.o
 
 obj-$(CONFIG_ARCH_MSM7X27) += gpiomux-7x27.o gpiomux-v1.o gpiomux.o
 obj-$(CONFIG_ARCH_MSM7X30) += gpiomux-7x30.o gpiomux-v1.o gpiomux.o
@@ -328,6 +341,8 @@
 obj-$(CONFIG_ARCH_APQ8064) += gpiomux-v2.o gpiomux.o
 obj-$(CONFIG_ARCH_MSM9615) += gpiomux-v2.o gpiomux.o
 obj-$(CONFIG_ARCH_MSMCOPPER) += gpiomux-v2.o gpiomux.o
+obj-$(CONFIG_ARCH_MSM9625) += gpiomux-v2.o gpiomux.o
+
 
 ifdef CONFIG_FSM9XXX_TLMM
 obj-y   += gpio-fsm9xxx.o
@@ -364,3 +379,5 @@
 
 obj-$(CONFIG_MSM_HSIC_SYSMON) += hsic_sysmon.o
 obj-$(CONFIG_MSM_HSIC_SYSMON_TEST) += hsic_sysmon_test.o
+
+obj-$(CONFIG_MSM_RPM_SMD) += rpm-smd.o
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index 58c630e..bd8d153 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -46,11 +46,14 @@
    zreladdr-$(CONFIG_ARCH_APQ8064)	:= 0x80208000
 
 # MSMCOPPER
-   zreladdr-$(CONFIG_ARCH_MSMCOPPER)	:= 0x20208000
+   zreladdr-$(CONFIG_ARCH_MSMCOPPER)	:= 0x00008000
 
 # MSM9615
    zreladdr-$(CONFIG_ARCH_MSM9615)	:= 0x40808000
 
+# MSM9625
+   zreladdr-$(CONFIG_ARCH_MSM9625)	:= 0x20208000
+
 # FSM9XXX
    zreladdr-$(CONFIG_ARCH_FSM9XXX)	:= 0x10008000
 params_phys-$(CONFIG_ARCH_FSM9XXX)	:= 0x10000100
diff --git a/arch/arm/mach-msm/acpuclock-7627.c b/arch/arm/mach-msm/acpuclock-7627.c
index 99311d4..7c2c556 100644
--- a/arch/arm/mach-msm/acpuclock-7627.c
+++ b/arch/arm/mach-msm/acpuclock-7627.c
@@ -249,6 +249,35 @@
 	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
 };
 
+/* 8625 PLL4 @ 1152MHz with GSM capable modem */
+static struct clkctl_acpu_speed pll0_960_pll1_245_pll2_1200_pll4_1152[] = {
+	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 30720 },
+	{ 0, 61440, ACPU_PLL_1, 1, 3,  7680, 3, 1, 61440 },
+	{ 1, 122880, ACPU_PLL_1, 1, 1,  15360, 3, 2, 61440 },
+	{ 1, 245760, ACPU_PLL_1, 1, 0, 30720, 3, 3, 61440 },
+	{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
+	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
+	{ 0, 576000, ACPU_PLL_4, 6, 1, 72000, 3, 6, 160000 },
+	{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 160000 },
+	{ 1, 1152000, ACPU_PLL_4, 6, 0, 144000, 3, 7, 200000},
+	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+};
+
+/* 8625 PLL4 @ 1115MHz with CDMA capable modem */
+static struct clkctl_acpu_speed pll0_960_pll1_196_pll2_1200_pll4_1152[] = {
+	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 24576 },
+	{ 0, 65536, ACPU_PLL_1, 1, 3,  8192, 3, 1, 49152 },
+	{ 1, 98304, ACPU_PLL_1, 1, 1,  12288, 3, 2, 49152 },
+	{ 1, 196608, ACPU_PLL_1, 1, 0, 24576, 3, 3, 98304 },
+	{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
+	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
+	{ 0, 576000, ACPU_PLL_4, 6, 1, 72000, 3, 6, 160000 },
+	{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 160000 },
+	{ 1, 1152000, ACPU_PLL_4, 6, 0, 144000, 3, 7, 200000},
+	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+};
+
+
 /* 7625a PLL2 @ 1200MHz with GSM capable modem */
 static struct clkctl_acpu_speed pll0_960_pll1_245_pll2_1200_25a[] = {
 	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 30720 },
@@ -365,6 +394,8 @@
 	PLL_CONFIG(960, 589, 1200, 1008),
 	PLL_CONFIG(960, 245, 1200, 1209),
 	PLL_CONFIG(960, 196, 1200, 1209),
+	PLL_CONFIG(960, 245, 1200, 1152),
+	PLL_CONFIG(960, 196, 1200, 1152),
 	{ 0, 0, 0, 0, 0 }
 };
 
diff --git a/arch/arm/mach-msm/acpuclock-8960.c b/arch/arm/mach-msm/acpuclock-8960.c
index 041e755..f467aba 100644
--- a/arch/arm/mach-msm/acpuclock-8960.c
+++ b/arch/arm/mach-msm/acpuclock-8960.c
@@ -370,6 +370,7 @@
 		},
 	[L2] = {
 			.hfpll_base   = MSM_HFPLL_BASE    + 0x400,
+			.hfpll_vdd_tbl = hfpll_vdd_dig_tbl_8930,
 			.aux_clk_sel  = MSM_APCS_GCC_BASE + 0x028,
 			.l2cpmr_iaddr = L2CPMR_IADDR,
 			.vreg[VREG_HFPLL_B] = { "hfpll_l2", 1800000,
@@ -512,15 +513,15 @@
 	{ 1, {   918000, HFPLL, 1, 0, 0x22 }, L2(7),  1100000 },
 	{ 0, {   972000, HFPLL, 1, 0, 0x24 }, L2(7),  1125000 },
 	{ 1, {  1026000, HFPLL, 1, 0, 0x26 }, L2(7),  1125000 },
-	{ 0, {  1080000, HFPLL, 1, 0, 0x28 }, L2(16), 1175000 },
-	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(16), 1175000 },
-	{ 0, {  1188000, HFPLL, 1, 0, 0x2C }, L2(16), 1200000 },
-	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(16), 1200000 },
-	{ 0, {  1296000, HFPLL, 1, 0, 0x30 }, L2(16), 1225000 },
-	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(16), 1225000 },
-	{ 0, {  1404000, HFPLL, 1, 0, 0x34 }, L2(16), 1237500 },
-	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(16), 1237500 },
-	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(16), 1250000 },
+	{ 0, {  1080000, HFPLL, 1, 0, 0x28 }, L2(19), 1175000 },
+	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(19), 1175000 },
+	{ 0, {  1188000, HFPLL, 1, 0, 0x2C }, L2(19), 1200000 },
+	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(19), 1200000 },
+	{ 0, {  1296000, HFPLL, 1, 0, 0x30 }, L2(19), 1225000 },
+	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(19), 1225000 },
+	{ 0, {  1404000, HFPLL, 1, 0, 0x34 }, L2(19), 1237500 },
+	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(19), 1237500 },
+	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(19), 1250000 },
 	{ 0, { 0 } }
 };
 
@@ -539,15 +540,15 @@
 	{ 1, {   918000, HFPLL, 1, 0, 0x22 }, L2(7),  1050000 },
 	{ 0, {   972000, HFPLL, 1, 0, 0x24 }, L2(7),  1075000 },
 	{ 1, {  1026000, HFPLL, 1, 0, 0x26 }, L2(7),  1075000 },
-	{ 0, {  1080000, HFPLL, 1, 0, 0x28 }, L2(16), 1125000 },
-	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(16), 1125000 },
-	{ 0, {  1188000, HFPLL, 1, 0, 0x2C }, L2(16), 1150000 },
-	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(16), 1150000 },
-	{ 0, {  1296000, HFPLL, 1, 0, 0x30 }, L2(16), 1175000 },
-	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(16), 1175000 },
-	{ 0, {  1404000, HFPLL, 1, 0, 0x34 }, L2(16), 1187500 },
-	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(16), 1187500 },
-	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(16), 1200000 },
+	{ 0, {  1080000, HFPLL, 1, 0, 0x28 }, L2(19), 1125000 },
+	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(19), 1125000 },
+	{ 0, {  1188000, HFPLL, 1, 0, 0x2C }, L2(19), 1150000 },
+	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(19), 1150000 },
+	{ 0, {  1296000, HFPLL, 1, 0, 0x30 }, L2(19), 1175000 },
+	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(19), 1175000 },
+	{ 0, {  1404000, HFPLL, 1, 0, 0x34 }, L2(19), 1187500 },
+	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(19), 1187500 },
+	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(19), 1200000 },
 	{ 0, { 0 } }
 };
 
@@ -566,15 +567,15 @@
 	{ 1, {   918000, HFPLL, 1, 0, 0x22 }, L2(7),  1000000 },
 	{ 0, {   972000, HFPLL, 1, 0, 0x24 }, L2(7),  1025000 },
 	{ 1, {  1026000, HFPLL, 1, 0, 0x26 }, L2(7),  1025000 },
-	{ 0, {  1080000, HFPLL, 1, 0, 0x28 }, L2(16), 1075000 },
-	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(16), 1075000 },
-	{ 0, {  1188000, HFPLL, 1, 0, 0x2C }, L2(16), 1100000 },
-	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(16), 1100000 },
-	{ 0, {  1296000, HFPLL, 1, 0, 0x30 }, L2(16), 1125000 },
-	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(16), 1125000 },
-	{ 0, {  1404000, HFPLL, 1, 0, 0x34 }, L2(16), 1137500 },
-	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(16), 1137500 },
-	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(16), 1150000 },
+	{ 0, {  1080000, HFPLL, 1, 0, 0x28 }, L2(19), 1075000 },
+	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(19), 1075000 },
+	{ 0, {  1188000, HFPLL, 1, 0, 0x2C }, L2(19), 1100000 },
+	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(19), 1100000 },
+	{ 0, {  1296000, HFPLL, 1, 0, 0x30 }, L2(19), 1125000 },
+	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(19), 1125000 },
+	{ 0, {  1404000, HFPLL, 1, 0, 0x34 }, L2(19), 1137500 },
+	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(19), 1137500 },
+	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(19), 1150000 },
 	{ 0, { 0 } }
 };
 
@@ -653,23 +654,23 @@
 
 /* TODO: Update core voltages when data is available. */
 static struct acpu_level acpu_freq_tbl_8930[] = {
-	{ 0, { STBY_KHZ, QSB,   0, 0, 0x00 }, L2(0),   900000 },
-	{ 1, {   384000, PLL_8, 0, 2, 0x00 }, L2(1),   900000 },
-	{ 1, {   432000, HFPLL, 2, 0, 0x20 }, L2(6),   925000 },
-	{ 1, {   486000, HFPLL, 2, 0, 0x24 }, L2(6),   925000 },
-	{ 1, {   540000, HFPLL, 2, 0, 0x28 }, L2(6),   937500 },
-	{ 1, {   594000, HFPLL, 1, 0, 0x16 }, L2(6),   962500 },
-	{ 1, {   648000, HFPLL, 1, 0, 0x18 }, L2(6),   987500 },
-	{ 1, {   702000, HFPLL, 1, 0, 0x1A }, L2(6),  1000000 },
-	{ 1, {   756000, HFPLL, 1, 0, 0x1C }, L2(11), 1025000 },
-	{ 1, {   810000, HFPLL, 1, 0, 0x1E }, L2(11), 1062500 },
-	{ 1, {   864000, HFPLL, 1, 0, 0x20 }, L2(11), 1062500 },
-	{ 1, {   918000, HFPLL, 1, 0, 0x22 }, L2(11), 1087500 },
-	{ 1, {   972000, HFPLL, 1, 0, 0x24 }, L2(16), 1100000 },
-	{ 1, {  1026000, HFPLL, 1, 0, 0x26 }, L2(16), 1100000 },
-	{ 1, {  1080000, HFPLL, 1, 0, 0x28 }, L2(16), 1100000 },
-	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(16), 1100000 },
-	{ 1, {  1188000, HFPLL, 1, 0, 0x2C }, L2(16), 1125000 },
+	{ 0, { STBY_KHZ, QSB,   0, 0, 0x00 }, L2(0),   925000 },
+	{ 1, {   384000, PLL_8, 0, 2, 0x00 }, L2(1),   925000 },
+	{ 1, {   432000, HFPLL, 2, 0, 0x20 }, L2(6),   937500 },
+	{ 1, {   486000, HFPLL, 2, 0, 0x24 }, L2(6),   962500 },
+	{ 1, {   540000, HFPLL, 2, 0, 0x28 }, L2(6),   987500 },
+	{ 1, {   594000, HFPLL, 1, 0, 0x16 }, L2(6),  1000000 },
+	{ 1, {   648000, HFPLL, 1, 0, 0x18 }, L2(6),  1025000 },
+	{ 1, {   702000, HFPLL, 1, 0, 0x1A }, L2(6),  1037500 },
+	{ 1, {   756000, HFPLL, 1, 0, 0x1C }, L2(11), 1062500 },
+	{ 1, {   810000, HFPLL, 1, 0, 0x1E }, L2(11), 1087500 },
+	{ 1, {   864000, HFPLL, 1, 0, 0x20 }, L2(11), 1100000 },
+	{ 1, {   918000, HFPLL, 1, 0, 0x22 }, L2(11), 1125000 },
+	{ 1, {   972000, HFPLL, 1, 0, 0x24 }, L2(16), 1137500 },
+	{ 1, {  1026000, HFPLL, 1, 0, 0x26 }, L2(16), 1162500 },
+	{ 1, {  1080000, HFPLL, 1, 0, 0x28 }, L2(16), 1187500 },
+	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(16), 1200000 },
+	{ 1, {  1188000, HFPLL, 1, 0, 0x2C }, L2(16), 1225000 },
 	{ 0, { 0 } }
 };
 
diff --git a/arch/arm/mach-msm/acpuclock-8x60.c b/arch/arm/mach-msm/acpuclock-8x60.c
index 787483b..48efa18 100644
--- a/arch/arm/mach-msm/acpuclock-8x60.c
+++ b/arch/arm/mach-msm/acpuclock-8x60.c
@@ -217,40 +217,7 @@
 };
 
 /* SCPLL frequencies = 2 * 27 MHz * L_VAL */
-static struct clkctl_acpu_speed acpu_freq_tbl_slowest[] = {
-  { {1, 1},  192000,  ACPU_PLL_8, 3, 1, 0, 0,    L2(1),   800000, 0x03006000},
-  /* MAX_AXI row is used to source CPU cores and L2 from the AFAB clock. */
-  { {0, 0},  MAX_AXI, ACPU_AFAB,  1, 0, 0, 0,    L2(0),   825000, 0x03006000},
-  { {1, 1},  384000,  ACPU_PLL_8, 3, 0, 0, 0,    L2(1),   825000, 0x03006000},
-  { {1, 1},  432000,  ACPU_SCPLL, 0, 0, 1, 0x08, L2(1),   850000, 0x03006000},
-  { {1, 1},  486000,  ACPU_SCPLL, 0, 0, 1, 0x09, L2(2),   850000, 0x03006000},
-  { {1, 1},  540000,  ACPU_SCPLL, 0, 0, 1, 0x0A, L2(3),   875000, 0x03006000},
-  { {1, 1},  594000,  ACPU_SCPLL, 0, 0, 1, 0x0B, L2(4),   875000, 0x03006000},
-  { {1, 1},  648000,  ACPU_SCPLL, 0, 0, 1, 0x0C, L2(5),   900000, 0x03006000},
-  { {1, 1},  702000,  ACPU_SCPLL, 0, 0, 1, 0x0D, L2(6),   900000, 0x03006000},
-  { {1, 1},  756000,  ACPU_SCPLL, 0, 0, 1, 0x0E, L2(7),   925000, 0x03006000},
-  { {1, 1},  810000,  ACPU_SCPLL, 0, 0, 1, 0x0F, L2(8),   975000, 0x03006000},
-  { {1, 1},  864000,  ACPU_SCPLL, 0, 0, 1, 0x10, L2(9),   975000, 0x03006000},
-  { {1, 1},  918000,  ACPU_SCPLL, 0, 0, 1, 0x11, L2(10), 1000000, 0x03006000},
-  { {1, 1},  972000,  ACPU_SCPLL, 0, 0, 1, 0x12, L2(11), 1025000, 0x03006000},
-  { {1, 1}, 1026000,  ACPU_SCPLL, 0, 0, 1, 0x13, L2(12), 1025000, 0x03006000},
-  { {1, 1}, 1080000,  ACPU_SCPLL, 0, 0, 1, 0x14, L2(13), 1050000, 0x03006000},
-  { {1, 1}, 1134000,  ACPU_SCPLL, 0, 0, 1, 0x15, L2(14), 1075000, 0x03006000},
-  { {1, 1}, 1188000,  ACPU_SCPLL, 0, 0, 1, 0x16, L2(15), 1100000, 0x03006000},
-  { {1, 1}, 1242000,  ACPU_SCPLL, 0, 0, 1, 0x17, L2(16), 1125000, 0x03006000},
-  { {1, 1}, 1296000,  ACPU_SCPLL, 0, 0, 1, 0x18, L2(17), 1150000, 0x03006000},
-  { {1, 1}, 1350000,  ACPU_SCPLL, 0, 0, 1, 0x19, L2(18), 1175000, 0x03006000},
-  { {1, 1}, 1404000,  ACPU_SCPLL, 0, 0, 1, 0x1A, L2(19), 1200000, 0x03006000},
-  { {1, 1}, 1458000,  ACPU_SCPLL, 0, 0, 1, 0x1B, L2(19), 1225000, 0x03006000},
-  { {1, 1}, 1512000,  ACPU_SCPLL, 0, 0, 1, 0x1C, L2(19), 1250000, 0x03006000},
-  { {1, 1}, 1566000,  ACPU_SCPLL, 0, 0, 1, 0x1D, L2(19), 1275000, 0x03006000},
-  { {1, 1}, 1620000,  ACPU_SCPLL, 0, 0, 1, 0x1E, L2(19), 1300000, 0x03006000},
-  { {1, 1}, 1674000,  ACPU_SCPLL, 0, 0, 1, 0x1F, L2(19), 1325000, 0x03006000},
-  { {0, 0}, 0 },
-};
-
-/* SCPLL frequencies = 2 * 27 MHz * L_VAL */
-static struct clkctl_acpu_speed acpu_freq_tbl_slower[] = {
+static struct clkctl_acpu_speed acpu_freq_tbl_1512mhz_slow[] = {
   { {1, 1},  192000,  ACPU_PLL_8, 3, 1, 0, 0,    L2(1),   800000, 0x03006000},
   /* MAX_AXI row is used to source CPU cores and L2 from the AFAB clock. */
   { {0, 0},  MAX_AXI, ACPU_AFAB,  1, 0, 0, 0,    L2(0),   825000, 0x03006000},
@@ -276,47 +243,11 @@
   { {1, 1}, 1404000,  ACPU_SCPLL, 0, 0, 1, 0x1A, L2(19), 1175000, 0x03006000},
   { {1, 1}, 1458000,  ACPU_SCPLL, 0, 0, 1, 0x1B, L2(19), 1200000, 0x03006000},
   { {1, 1}, 1512000,  ACPU_SCPLL, 0, 0, 1, 0x1C, L2(19), 1225000, 0x03006000},
-  { {1, 1}, 1566000,  ACPU_SCPLL, 0, 0, 1, 0x1D, L2(19), 1250000, 0x03006000},
-  { {1, 1}, 1620000,  ACPU_SCPLL, 0, 0, 1, 0x1E, L2(19), 1275000, 0x03006000},
-  { {1, 1}, 1674000,  ACPU_SCPLL, 0, 0, 1, 0x1F, L2(19), 1300000, 0x03006000},
   { {0, 0}, 0 },
 };
 
 /* SCPLL frequencies = 2 * 27 MHz * L_VAL */
-static struct clkctl_acpu_speed acpu_freq_tbl_slow[] = {
-  { {1, 1},  192000,  ACPU_PLL_8, 3, 1, 0, 0,    L2(1),   800000, 0x03006000},
-  /* MAX_AXI row is used to source CPU cores and L2 from the AFAB clock. */
-  { {0, 0},  MAX_AXI, ACPU_AFAB,  1, 0, 0, 0,    L2(0),   825000, 0x03006000},
-  { {1, 1},  384000,  ACPU_PLL_8, 3, 0, 0, 0,    L2(1),   825000, 0x03006000},
-  { {1, 1},  432000,  ACPU_SCPLL, 0, 0, 1, 0x08, L2(1),   850000, 0x03006000},
-  { {1, 1},  486000,  ACPU_SCPLL, 0, 0, 1, 0x09, L2(2),   850000, 0x03006000},
-  { {1, 1},  540000,  ACPU_SCPLL, 0, 0, 1, 0x0A, L2(3),   875000, 0x03006000},
-  { {1, 1},  594000,  ACPU_SCPLL, 0, 0, 1, 0x0B, L2(4),   875000, 0x03006000},
-  { {1, 1},  648000,  ACPU_SCPLL, 0, 0, 1, 0x0C, L2(5),   900000, 0x03006000},
-  { {1, 1},  702000,  ACPU_SCPLL, 0, 0, 1, 0x0D, L2(6),   900000, 0x03006000},
-  { {1, 1},  756000,  ACPU_SCPLL, 0, 0, 1, 0x0E, L2(7),   925000, 0x03006000},
-  { {1, 1},  810000,  ACPU_SCPLL, 0, 0, 1, 0x0F, L2(8),   975000, 0x03006000},
-  { {1, 1},  864000,  ACPU_SCPLL, 0, 0, 1, 0x10, L2(9),   975000, 0x03006000},
-  { {1, 1},  918000,  ACPU_SCPLL, 0, 0, 1, 0x11, L2(10), 1000000, 0x03006000},
-  { {1, 1},  972000,  ACPU_SCPLL, 0, 0, 1, 0x12, L2(11), 1025000, 0x03006000},
-  { {1, 1}, 1026000,  ACPU_SCPLL, 0, 0, 1, 0x13, L2(12), 1025000, 0x03006000},
-  { {1, 1}, 1080000,  ACPU_SCPLL, 0, 0, 1, 0x14, L2(13), 1050000, 0x03006000},
-  { {1, 1}, 1134000,  ACPU_SCPLL, 0, 0, 1, 0x15, L2(14), 1075000, 0x03006000},
-  { {1, 1}, 1188000,  ACPU_SCPLL, 0, 0, 1, 0x16, L2(15), 1100000, 0x03006000},
-  { {1, 1}, 1242000,  ACPU_SCPLL, 0, 0, 1, 0x17, L2(16), 1125000, 0x03006000},
-  { {1, 1}, 1296000,  ACPU_SCPLL, 0, 0, 1, 0x18, L2(17), 1150000, 0x03006000},
-  { {1, 1}, 1350000,  ACPU_SCPLL, 0, 0, 1, 0x19, L2(18), 1150000, 0x03006000},
-  { {1, 1}, 1404000,  ACPU_SCPLL, 0, 0, 1, 0x1A, L2(19), 1175000, 0x03006000},
-  { {1, 1}, 1458000,  ACPU_SCPLL, 0, 0, 1, 0x1B, L2(19), 1200000, 0x03006000},
-  { {1, 1}, 1512000,  ACPU_SCPLL, 0, 0, 1, 0x1C, L2(19), 1225000, 0x03006000},
-  { {1, 1}, 1566000,  ACPU_SCPLL, 0, 0, 1, 0x1D, L2(19), 1225000, 0x03006000},
-  { {1, 1}, 1620000,  ACPU_SCPLL, 0, 0, 1, 0x1E, L2(19), 1225000, 0x03006000},
-  { {1, 1}, 1674000,  ACPU_SCPLL, 0, 0, 1, 0x1F, L2(19), 1250000, 0x03006000},
-  { {0, 0}, 0 },
-};
-
-/* SCPLL frequencies = 2 * 27 MHz * L_VAL */
-static struct clkctl_acpu_speed acpu_freq_tbl_nom[] = {
+static struct clkctl_acpu_speed acpu_freq_tbl_1512mhz_nom[] = {
   { {1, 1},  192000,  ACPU_PLL_8, 3, 1, 0, 0,    L2(1),   800000, 0x03006000},
   /* MAX_AXI row is used to source CPU cores and L2 from the AFAB clock. */
   { {0, 0},  MAX_AXI, ACPU_AFAB,  1, 0, 0, 0,    L2(0),   825000, 0x03006000},
@@ -342,14 +273,11 @@
   { {1, 1}, 1404000,  ACPU_SCPLL, 0, 0, 1, 0x1A, L2(19), 1150000, 0x03006000},
   { {1, 1}, 1458000,  ACPU_SCPLL, 0, 0, 1, 0x1B, L2(19), 1150000, 0x03006000},
   { {1, 1}, 1512000,  ACPU_SCPLL, 0, 0, 1, 0x1C, L2(19), 1175000, 0x03006000},
-  { {1, 1}, 1566000,  ACPU_SCPLL, 0, 0, 1, 0x1D, L2(19), 1175000, 0x03006000},
-  { {1, 1}, 1620000,  ACPU_SCPLL, 0, 0, 1, 0x1E, L2(19), 1200000, 0x03006000},
-  { {1, 1}, 1674000,  ACPU_SCPLL, 0, 0, 1, 0x1F, L2(19), 1200000, 0x03006000},
   { {0, 0}, 0 },
 };
 
 /* SCPLL frequencies = 2 * 27 MHz * L_VAL */
-static struct clkctl_acpu_speed acpu_freq_tbl_fast[] = {
+static struct clkctl_acpu_speed acpu_freq_tbl_1512mhz_fast[] = {
   { {1, 1},  192000,  ACPU_PLL_8, 3, 1, 0, 0,    L2(1),   800000, 0x03006000},
   /* MAX_AXI row is used to source CPU cores and L2 from the AFAB clock. */
   { {0, 0},  MAX_AXI, ACPU_AFAB,  1, 0, 0, 0,    L2(0),   825000, 0x03006000},
@@ -375,13 +303,141 @@
   { {1, 1}, 1404000,  ACPU_SCPLL, 0, 0, 1, 0x1A, L2(19), 1100000, 0x03006000},
   { {1, 1}, 1458000,  ACPU_SCPLL, 0, 0, 1, 0x1B, L2(19), 1100000, 0x03006000},
   { {1, 1}, 1512000,  ACPU_SCPLL, 0, 0, 1, 0x1C, L2(19), 1125000, 0x03006000},
-  { {1, 1}, 1566000,  ACPU_SCPLL, 0, 0, 1, 0x1D, L2(19), 1125000, 0x03006000},
+  { {0, 0}, 0 },
+};
+
+/* SCPLL frequencies = 2 * 27 MHz * L_VAL */
+static struct clkctl_acpu_speed acpu_freq_tbl_1674mhz_slower[] = {
+  { {1, 1},  192000,  ACPU_PLL_8, 3, 1, 0, 0,    L2(1),   775000, 0x03006000},
+  /* MAX_AXI row is used to source CPU cores and L2 from the AFAB clock. */
+  { {0, 0},  MAX_AXI, ACPU_AFAB,  1, 0, 0, 0,    L2(0),   775000, 0x03006000},
+  { {1, 1},  384000,  ACPU_PLL_8, 3, 0, 0, 0,    L2(1),   775000, 0x03006000},
+  { {1, 1},  432000,  ACPU_SCPLL, 0, 0, 1, 0x08, L2(1),   775000, 0x03006000},
+  { {1, 1},  486000,  ACPU_SCPLL, 0, 0, 1, 0x09, L2(2),   775000, 0x03006000},
+  { {1, 1},  540000,  ACPU_SCPLL, 0, 0, 1, 0x0A, L2(3),   787500, 0x03006000},
+  { {1, 1},  594000,  ACPU_SCPLL, 0, 0, 1, 0x0B, L2(4),   800000, 0x03006000},
+  { {1, 1},  648000,  ACPU_SCPLL, 0, 0, 1, 0x0C, L2(5),   825000, 0x03006000},
+  { {1, 1},  702000,  ACPU_SCPLL, 0, 0, 1, 0x0D, L2(6),   837500, 0x03006000},
+  { {1, 1},  756000,  ACPU_SCPLL, 0, 0, 1, 0x0E, L2(7),   850000, 0x03006000},
+  { {1, 1},  810000,  ACPU_SCPLL, 0, 0, 1, 0x0F, L2(8),   875000, 0x03006000},
+  { {1, 1},  864000,  ACPU_SCPLL, 0, 0, 1, 0x10, L2(9),   900000, 0x03006000},
+  { {1, 1},  918000,  ACPU_SCPLL, 0, 0, 1, 0x11, L2(10),  912500, 0x03006000},
+  { {1, 1},  972000,  ACPU_SCPLL, 0, 0, 1, 0x12, L2(11),  937500, 0x03006000},
+  { {1, 1}, 1026000,  ACPU_SCPLL, 0, 0, 1, 0x13, L2(12),  962500, 0x03006000},
+  { {1, 1}, 1080000,  ACPU_SCPLL, 0, 0, 1, 0x14, L2(13),  987500, 0x03006000},
+  { {1, 1}, 1134000,  ACPU_SCPLL, 0, 0, 1, 0x15, L2(14), 1012500, 0x03006000},
+  { {1, 1}, 1188000,  ACPU_SCPLL, 0, 0, 1, 0x16, L2(15), 1025000, 0x03006000},
+  { {1, 1}, 1242000,  ACPU_SCPLL, 0, 0, 1, 0x17, L2(16), 1062500, 0x03006000},
+  { {1, 1}, 1296000,  ACPU_SCPLL, 0, 0, 1, 0x18, L2(17), 1087500, 0x03006000},
+  { {1, 1}, 1350000,  ACPU_SCPLL, 0, 0, 1, 0x19, L2(18), 1100000, 0x03006000},
+  { {1, 1}, 1404000,  ACPU_SCPLL, 0, 0, 1, 0x1A, L2(19), 1125000, 0x03006000},
+  { {1, 1}, 1458000,  ACPU_SCPLL, 0, 0, 1, 0x1B, L2(19), 1150000, 0x03006000},
+  { {1, 1}, 1512000,  ACPU_SCPLL, 0, 0, 1, 0x1C, L2(19), 1187500, 0x03006000},
+  { {1, 1}, 1566000,  ACPU_SCPLL, 0, 0, 1, 0x1D, L2(19), 1225000, 0x03006000},
+  { {1, 1}, 1620000,  ACPU_SCPLL, 0, 0, 1, 0x1E, L2(19), 1262500, 0x03006000},
+  { {1, 1}, 1674000,  ACPU_SCPLL, 0, 0, 1, 0x1F, L2(19), 1300000, 0x03006000},
+  { {0, 0}, 0 },
+};
+
+/* SCPLL frequencies = 2 * 27 MHz * L_VAL */
+static struct clkctl_acpu_speed acpu_freq_tbl_1674mhz_slow[] = {
+  { {1, 1},  192000,  ACPU_PLL_8, 3, 1, 0, 0,    L2(1),   775000, 0x03006000},
+  /* MAX_AXI row is used to source CPU cores and L2 from the AFAB clock. */
+  { {0, 0},  MAX_AXI, ACPU_AFAB,  1, 0, 0, 0,    L2(0),   775000, 0x03006000},
+  { {1, 1},  384000,  ACPU_PLL_8, 3, 0, 0, 0,    L2(1),   775000, 0x03006000},
+  { {1, 1},  432000,  ACPU_SCPLL, 0, 0, 1, 0x08, L2(1),   775000, 0x03006000},
+  { {1, 1},  486000,  ACPU_SCPLL, 0, 0, 1, 0x09, L2(2),   775000, 0x03006000},
+  { {1, 1},  540000,  ACPU_SCPLL, 0, 0, 1, 0x0A, L2(3),   787500, 0x03006000},
+  { {1, 1},  594000,  ACPU_SCPLL, 0, 0, 1, 0x0B, L2(4),   800000, 0x03006000},
+  { {1, 1},  648000,  ACPU_SCPLL, 0, 0, 1, 0x0C, L2(5),   825000, 0x03006000},
+  { {1, 1},  702000,  ACPU_SCPLL, 0, 0, 1, 0x0D, L2(6),   837500, 0x03006000},
+  { {1, 1},  756000,  ACPU_SCPLL, 0, 0, 1, 0x0E, L2(7),   850000, 0x03006000},
+  { {1, 1},  810000,  ACPU_SCPLL, 0, 0, 1, 0x0F, L2(8),   862500, 0x03006000},
+  { {1, 1},  864000,  ACPU_SCPLL, 0, 0, 1, 0x10, L2(9),   887500, 0x03006000},
+  { {1, 1},  918000,  ACPU_SCPLL, 0, 0, 1, 0x11, L2(10),  900000, 0x03006000},
+  { {1, 1},  972000,  ACPU_SCPLL, 0, 0, 1, 0x12, L2(11),  925000, 0x03006000},
+  { {1, 1}, 1026000,  ACPU_SCPLL, 0, 0, 1, 0x13, L2(12),  937500, 0x03006000},
+  { {1, 1}, 1080000,  ACPU_SCPLL, 0, 0, 1, 0x14, L2(13),  962500, 0x03006000},
+  { {1, 1}, 1134000,  ACPU_SCPLL, 0, 0, 1, 0x15, L2(14),  987500, 0x03006000},
+  { {1, 1}, 1188000,  ACPU_SCPLL, 0, 0, 1, 0x16, L2(15), 1000000, 0x03006000},
+  { {1, 1}, 1242000,  ACPU_SCPLL, 0, 0, 1, 0x17, L2(16), 1025000, 0x03006000},
+  { {1, 1}, 1296000,  ACPU_SCPLL, 0, 0, 1, 0x18, L2(17), 1050000, 0x03006000},
+  { {1, 1}, 1350000,  ACPU_SCPLL, 0, 0, 1, 0x19, L2(18), 1062500, 0x03006000},
+  { {1, 1}, 1404000,  ACPU_SCPLL, 0, 0, 1, 0x1A, L2(19), 1087500, 0x03006000},
+  { {1, 1}, 1458000,  ACPU_SCPLL, 0, 0, 1, 0x1B, L2(19), 1112500, 0x03006000},
+  { {1, 1}, 1512000,  ACPU_SCPLL, 0, 0, 1, 0x1C, L2(19), 1150000, 0x03006000},
+  { {1, 1}, 1566000,  ACPU_SCPLL, 0, 0, 1, 0x1D, L2(19), 1175000, 0x03006000},
+  { {1, 1}, 1620000,  ACPU_SCPLL, 0, 0, 1, 0x1E, L2(19), 1212500, 0x03006000},
+  { {1, 1}, 1674000,  ACPU_SCPLL, 0, 0, 1, 0x1F, L2(19), 1250000, 0x03006000},
+  { {0, 0}, 0 },
+};
+
+/* SCPLL frequencies = 2 * 27 MHz * L_VAL */
+static struct clkctl_acpu_speed acpu_freq_tbl_1674mhz_nom[] = {
+  { {1, 1},  192000,  ACPU_PLL_8, 3, 1, 0, 0,    L2(1),   775000, 0x03006000},
+  /* MAX_AXI row is used to source CPU cores and L2 from the AFAB clock. */
+  { {0, 0},  MAX_AXI, ACPU_AFAB,  1, 0, 0, 0,    L2(0),   775000, 0x03006000},
+  { {1, 1},  384000,  ACPU_PLL_8, 3, 0, 0, 0,    L2(1),   775000, 0x03006000},
+  { {1, 1},  432000,  ACPU_SCPLL, 0, 0, 1, 0x08, L2(1),   775000, 0x03006000},
+  { {1, 1},  486000,  ACPU_SCPLL, 0, 0, 1, 0x09, L2(2),   775000, 0x03006000},
+  { {1, 1},  540000,  ACPU_SCPLL, 0, 0, 1, 0x0A, L2(3),   787500, 0x03006000},
+  { {1, 1},  594000,  ACPU_SCPLL, 0, 0, 1, 0x0B, L2(4),   800000, 0x03006000},
+  { {1, 1},  648000,  ACPU_SCPLL, 0, 0, 1, 0x0C, L2(5),   812500, 0x03006000},
+  { {1, 1},  702000,  ACPU_SCPLL, 0, 0, 1, 0x0D, L2(6),   825000, 0x03006000},
+  { {1, 1},  756000,  ACPU_SCPLL, 0, 0, 1, 0x0E, L2(7),   837500, 0x03006000},
+  { {1, 1},  810000,  ACPU_SCPLL, 0, 0, 1, 0x0F, L2(8),   850000, 0x03006000},
+  { {1, 1},  864000,  ACPU_SCPLL, 0, 0, 1, 0x10, L2(9),   875000, 0x03006000},
+  { {1, 1},  918000,  ACPU_SCPLL, 0, 0, 1, 0x11, L2(10),  887500, 0x03006000},
+  { {1, 1},  972000,  ACPU_SCPLL, 0, 0, 1, 0x12, L2(11),  900000, 0x03006000},
+  { {1, 1}, 1026000,  ACPU_SCPLL, 0, 0, 1, 0x13, L2(12),  912500, 0x03006000},
+  { {1, 1}, 1080000,  ACPU_SCPLL, 0, 0, 1, 0x14, L2(13),  937500, 0x03006000},
+  { {1, 1}, 1134000,  ACPU_SCPLL, 0, 0, 1, 0x15, L2(14),  950000, 0x03006000},
+  { {1, 1}, 1188000,  ACPU_SCPLL, 0, 0, 1, 0x16, L2(15),  975000, 0x03006000},
+  { {1, 1}, 1242000,  ACPU_SCPLL, 0, 0, 1, 0x17, L2(16),  987500, 0x03006000},
+  { {1, 1}, 1296000,  ACPU_SCPLL, 0, 0, 1, 0x18, L2(17), 1012500, 0x03006000},
+  { {1, 1}, 1350000,  ACPU_SCPLL, 0, 0, 1, 0x19, L2(18), 1025000, 0x03006000},
+  { {1, 1}, 1404000,  ACPU_SCPLL, 0, 0, 1, 0x1A, L2(19), 1050000, 0x03006000},
+  { {1, 1}, 1458000,  ACPU_SCPLL, 0, 0, 1, 0x1B, L2(19), 1075000, 0x03006000},
+  { {1, 1}, 1512000,  ACPU_SCPLL, 0, 0, 1, 0x1C, L2(19), 1112500, 0x03006000},
+  { {1, 1}, 1566000,  ACPU_SCPLL, 0, 0, 1, 0x1D, L2(19), 1137500, 0x03006000},
+  { {1, 1}, 1620000,  ACPU_SCPLL, 0, 0, 1, 0x1E, L2(19), 1175000, 0x03006000},
+  { {1, 1}, 1674000,  ACPU_SCPLL, 0, 0, 1, 0x1F, L2(19), 1200000, 0x03006000},
+  { {0, 0}, 0 },
+};
+
+/* SCPLL frequencies = 2 * 27 MHz * L_VAL */
+static struct clkctl_acpu_speed acpu_freq_tbl_1674mhz_fast[] = {
+  { {1, 1},  192000,  ACPU_PLL_8, 3, 1, 0, 0,    L2(1),   775000, 0x03006000},
+  /* MAX_AXI row is used to source CPU cores and L2 from the AFAB clock. */
+  { {0, 0},  MAX_AXI, ACPU_AFAB,  1, 0, 0, 0,    L2(0),   775000, 0x03006000},
+  { {1, 1},  384000,  ACPU_PLL_8, 3, 0, 0, 0,    L2(1),   775000, 0x03006000},
+  { {1, 1},  432000,  ACPU_SCPLL, 0, 0, 1, 0x08, L2(1),   775000, 0x03006000},
+  { {1, 1},  486000,  ACPU_SCPLL, 0, 0, 1, 0x09, L2(2),   775000, 0x03006000},
+  { {1, 1},  540000,  ACPU_SCPLL, 0, 0, 1, 0x0A, L2(3),   775000, 0x03006000},
+  { {1, 1},  594000,  ACPU_SCPLL, 0, 0, 1, 0x0B, L2(4),   787500, 0x03006000},
+  { {1, 1},  648000,  ACPU_SCPLL, 0, 0, 1, 0x0C, L2(5),   800000, 0x03006000},
+  { {1, 1},  702000,  ACPU_SCPLL, 0, 0, 1, 0x0D, L2(6),   812500, 0x03006000},
+  { {1, 1},  756000,  ACPU_SCPLL, 0, 0, 1, 0x0E, L2(7),   825000, 0x03006000},
+  { {1, 1},  810000,  ACPU_SCPLL, 0, 0, 1, 0x0F, L2(8),   837500, 0x03006000},
+  { {1, 1},  864000,  ACPU_SCPLL, 0, 0, 1, 0x10, L2(9),   862500, 0x03006000},
+  { {1, 1},  918000,  ACPU_SCPLL, 0, 0, 1, 0x11, L2(10),  875000, 0x03006000},
+  { {1, 1},  972000,  ACPU_SCPLL, 0, 0, 1, 0x12, L2(11),  887500, 0x03006000},
+  { {1, 1}, 1026000,  ACPU_SCPLL, 0, 0, 1, 0x13, L2(12),  900000, 0x03006000},
+  { {1, 1}, 1080000,  ACPU_SCPLL, 0, 0, 1, 0x14, L2(13),  925000, 0x03006000},
+  { {1, 1}, 1134000,  ACPU_SCPLL, 0, 0, 1, 0x15, L2(14),  937500, 0x03006000},
+  { {1, 1}, 1188000,  ACPU_SCPLL, 0, 0, 1, 0x16, L2(15),  950000, 0x03006000},
+  { {1, 1}, 1242000,  ACPU_SCPLL, 0, 0, 1, 0x17, L2(16),  962500, 0x03006000},
+  { {1, 1}, 1296000,  ACPU_SCPLL, 0, 0, 1, 0x18, L2(17),  975000, 0x03006000},
+  { {1, 1}, 1350000,  ACPU_SCPLL, 0, 0, 1, 0x19, L2(18), 1000000, 0x03006000},
+  { {1, 1}, 1404000,  ACPU_SCPLL, 0, 0, 1, 0x1A, L2(19), 1025000, 0x03006000},
+  { {1, 1}, 1458000,  ACPU_SCPLL, 0, 0, 1, 0x1B, L2(19), 1050000, 0x03006000},
+  { {1, 1}, 1512000,  ACPU_SCPLL, 0, 0, 1, 0x1C, L2(19), 1075000, 0x03006000},
+  { {1, 1}, 1566000,  ACPU_SCPLL, 0, 0, 1, 0x1D, L2(19), 1100000, 0x03006000},
   { {1, 1}, 1620000,  ACPU_SCPLL, 0, 0, 1, 0x1E, L2(19), 1125000, 0x03006000},
   { {1, 1}, 1674000,  ACPU_SCPLL, 0, 0, 1, 0x1F, L2(19), 1150000, 0x03006000},
   { {0, 0}, 0 },
 };
 
-
 /* acpu_freq_tbl row to use when reconfiguring SC/L2 PLLs. */
 #define CAL_IDX 1
 
@@ -930,7 +986,7 @@
 
 static __init struct clkctl_acpu_speed *select_freq_plan(void)
 {
-	uint32_t pte_efuse, speed_bin, pvs, max_khz;
+	uint32_t pte_efuse, speed_bin, pvs;
 	struct clkctl_acpu_speed *f;
 
 	pte_efuse = readl_relaxed(QFPROM_PTE_EFUSE_ADDR);
@@ -944,67 +1000,55 @@
 		pvs = (pte_efuse >> 13) & 0x7;
 
 	if (speed_bin == 0x2) {
-		max_khz = 1674000;
 		switch (pvs) {
 		case 0x7:
-		case 0x5:
-			acpu_freq_tbl = acpu_freq_tbl_slowest;
-			pr_info("ACPU PVS: Slowest\n");
-			break;
 		case 0x4:
-			acpu_freq_tbl = acpu_freq_tbl_slower;
+			acpu_freq_tbl = acpu_freq_tbl_1674mhz_slower;
 			pr_info("ACPU PVS: Slower\n");
 			break;
 		case 0x0:
-			acpu_freq_tbl = acpu_freq_tbl_slow;
+			acpu_freq_tbl = acpu_freq_tbl_1674mhz_slow;
 			pr_info("ACPU PVS: Slow\n");
 			break;
 		case 0x1:
-			acpu_freq_tbl = acpu_freq_tbl_nom;
+			acpu_freq_tbl = acpu_freq_tbl_1674mhz_nom;
 			pr_info("ACPU PVS: Nominal\n");
 			break;
 		case 0x3:
-			acpu_freq_tbl = acpu_freq_tbl_fast;
+			acpu_freq_tbl = acpu_freq_tbl_1674mhz_fast;
 			pr_info("ACPU PVS: Fast\n");
 			break;
 		default:
-			acpu_freq_tbl = acpu_freq_tbl_slowest;
-			pr_warn("ACPU PVS: Unknown. Defaulting to slowest.\n");
+			acpu_freq_tbl = acpu_freq_tbl_1674mhz_slower;
+			pr_warn("ACPU PVS: Unknown. Defaulting to slower.\n");
 			break;
 		}
 	} else if (speed_bin == 0x1) {
-		max_khz = 1512000;
 		switch (pvs) {
 		case 0x0:
 		case 0x7:
-			acpu_freq_tbl = acpu_freq_tbl_slow;
+			acpu_freq_tbl = acpu_freq_tbl_1512mhz_slow;
 			pr_info("ACPU PVS: Slow\n");
 			break;
 		case 0x1:
-			acpu_freq_tbl = acpu_freq_tbl_nom;
+			acpu_freq_tbl = acpu_freq_tbl_1512mhz_nom;
 			pr_info("ACPU PVS: Nominal\n");
 			break;
 		case 0x3:
-			acpu_freq_tbl = acpu_freq_tbl_fast;
+			acpu_freq_tbl = acpu_freq_tbl_1512mhz_fast;
 			pr_info("ACPU PVS: Fast\n");
 			break;
 		default:
-			acpu_freq_tbl = acpu_freq_tbl_slow;
+			acpu_freq_tbl = acpu_freq_tbl_1512mhz_slow;
 			pr_warn("ACPU PVS: Unknown. Defaulting to slow.\n");
 			break;
 		}
 	} else {
-		max_khz = 1188000;
 		acpu_freq_tbl = acpu_freq_tbl_1188mhz;
 	}
 
-	/* Truncate the table based to max_khz. */
-	for (f = acpu_freq_tbl; f->acpuclk_khz != 0; f++) {
-		if (f->acpuclk_khz > max_khz) {
-			f->acpuclk_khz = 0;
-			break;
-		}
-	}
+	for (f = acpu_freq_tbl; f->acpuclk_khz != 0; f++)
+		;
 	f--;
 	pr_info("Max ACPU freq: %u KHz\n", f->acpuclk_khz);
 
diff --git a/arch/arm/mach-msm/board-8064-camera.c b/arch/arm/mach-msm/board-8064-camera.c
index 36953ef..114b271 100644
--- a/arch/arm/mach-msm/board-8064-camera.c
+++ b/arch/arm/mach-msm/board-8064-camera.c
@@ -188,6 +188,7 @@
 	.flash_sr_type = MSM_CAMERA_FLASH_SRC_EXT,
 	._fsrc.ext_driver_src.led_en = VFE_CAMIF_TIMER1_GPIO,
 	._fsrc.ext_driver_src.led_flash_en = VFE_CAMIF_TIMER2_GPIO,
+	._fsrc.ext_driver_src.flash_id = MAM_CAMERA_EXT_LED_FLASH_SC628A,
 };
 
 static struct msm_gpiomux_config apq8064_cam_2d_configs[] = {
diff --git a/arch/arm/mach-msm/board-8064-display.c b/arch/arm/mach-msm/board-8064-display.c
index 60bc26c..040e573 100644
--- a/arch/arm/mach-msm/board-8064-display.c
+++ b/arch/arm/mach-msm/board-8064-display.c
@@ -227,7 +227,7 @@
 };
 
 static int mdp_core_clk_rate_table[] = {
-	85330000,
+	59080000,
 	128000000,
 	160000000,
 	200000000,
@@ -235,7 +235,7 @@
 
 static struct msm_panel_common_pdata mdp_pdata = {
 	.gpio = MDP_VSYNC_GPIO,
-	.mdp_core_clk_rate = 85330000,
+	.mdp_core_clk_rate = 59080000,
 	.mdp_core_clk_table = mdp_core_clk_rate_table,
 	.num_mdp_clk = ARRAY_SIZE(mdp_core_clk_rate_table),
 	.mdp_bus_scale_table = &mdp_bus_scale_pdata,
diff --git a/arch/arm/mach-msm/board-8064-gpiomux.c b/arch/arm/mach-msm/board-8064-gpiomux.c
index 3431cd0..6ef1335a 100644
--- a/arch/arm/mach-msm/board-8064-gpiomux.c
+++ b/arch/arm/mach-msm/board-8064-gpiomux.c
@@ -55,7 +55,7 @@
 
 /* Chip selects for EPM SPI clients */
 static struct gpiomux_setting gpio_epm_spi_cs_config = {
-	.func = GPIOMUX_FUNC_3,
+	.func = GPIOMUX_FUNC_6,
 	.drv = GPIOMUX_DRV_12MA,
 	.pull = GPIOMUX_PULL_UP,
 };
@@ -342,6 +342,12 @@
 	.pull = GPIOMUX_PULL_KEEPER,
 };
 
+static struct gpiomux_setting mbhc_hs_detect = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
 static struct gpiomux_setting cdc_mclk = {
 	.func = GPIOMUX_FUNC_1,
 	.drv = GPIOMUX_DRV_8MA,
@@ -501,6 +507,19 @@
 	.dir = GPIOMUX_OUT_LOW,
 };
 
+static struct gpiomux_setting hsic_wakeup_act_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_DOWN,
+	.dir = GPIOMUX_IN,
+};
+
+static struct gpiomux_setting hsic_wakeup_sus_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+	.dir = GPIOMUX_IN,
+};
 
 static struct msm_gpiomux_config apq8064_hsic_configs[] = {
 	{
@@ -517,6 +536,13 @@
 			[GPIOMUX_SUSPENDED] = &hsic_sus_cfg,
 		},
 	},
+	{
+		.gpio = 47,              /* wake up */
+		.settings = {
+			[GPIOMUX_ACTIVE] = &hsic_wakeup_act_cfg,
+			[GPIOMUX_SUSPENDED] = &hsic_wakeup_sus_cfg,
+		},
+	},
 };
 #endif
 
@@ -730,6 +756,12 @@
 
 static struct msm_gpiomux_config apq8064_audio_codec_configs[] __initdata = {
 	{
+		.gpio = 38,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &mbhc_hs_detect,
+		},
+	},
+	{
 		.gpio = 39,
 		.settings = {
 			[GPIOMUX_SUSPENDED] = &cdc_mclk,
@@ -765,7 +797,7 @@
 	.pull = GPIOMUX_PULL_DOWN,
 };
 
-static struct gpiomux_setting ap2mdm_pon_reset_n_cfg = {
+static struct gpiomux_setting ap2mdm_soft_reset_cfg = {
 	.func = GPIOMUX_FUNC_GPIO,
 	.drv = GPIOMUX_DRV_8MA,
 	.pull = GPIOMUX_PULL_DOWN,
@@ -806,11 +838,11 @@
 			[GPIOMUX_SUSPENDED] = &ap2mdm_cfg,
 		}
 	},
-	/* AP2MDM_PON_RESET_N */
+	/* AP2MDM_SOFT_RESET, aka AP2MDM_PON_RESET_N */
 	{
 		.gpio = 27,
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &ap2mdm_pon_reset_n_cfg,
+			[GPIOMUX_SUSPENDED] = &ap2mdm_soft_reset_cfg,
 		}
 	},
 	/* AP2MDM_WAKEUP */
@@ -991,6 +1023,151 @@
 	},
 };
 
+#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+static struct gpiomux_setting sdc2_clk_active_cfg = {
+	.func = GPIOMUX_FUNC_2,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting sdc2_cmd_data_0_3_active_cfg = {
+	.func = GPIOMUX_FUNC_2,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting sdc2_suspended_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting sdc2_data_1_suspended_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct msm_gpiomux_config apq8064_sdc2_configs[] __initdata = {
+	{
+		.gpio      = 59,
+		.settings = {
+			[GPIOMUX_ACTIVE] = &sdc2_clk_active_cfg,
+			[GPIOMUX_SUSPENDED] = &sdc2_suspended_cfg,
+		},
+	},
+	{
+		.gpio      = 57,
+		.settings = {
+			[GPIOMUX_ACTIVE] = &sdc2_cmd_data_0_3_active_cfg,
+			[GPIOMUX_SUSPENDED] = &sdc2_suspended_cfg,
+		},
+
+	},
+	{
+		.gpio      = 62,
+		.settings = {
+			[GPIOMUX_ACTIVE] = &sdc2_cmd_data_0_3_active_cfg,
+			[GPIOMUX_SUSPENDED] = &sdc2_suspended_cfg,
+		},
+	},
+	{
+		.gpio      = 61,
+		.settings = {
+			[GPIOMUX_ACTIVE] = &sdc2_cmd_data_0_3_active_cfg,
+			[GPIOMUX_SUSPENDED] = &sdc2_data_1_suspended_cfg,
+		},
+	},
+	{
+		.gpio      = 60,
+		.settings = {
+			[GPIOMUX_ACTIVE] = &sdc2_cmd_data_0_3_active_cfg,
+			[GPIOMUX_SUSPENDED] = &sdc2_suspended_cfg,
+		},
+	},
+	{
+		.gpio      = 58,
+		.settings = {
+			[GPIOMUX_ACTIVE] = &sdc2_cmd_data_0_3_active_cfg,
+			[GPIOMUX_SUSPENDED] = &sdc2_suspended_cfg,
+		},
+	},
+};
+#endif
+
+
+#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT
+static struct gpiomux_setting sdc4_clk_active_cfg = {
+	.func = GPIOMUX_FUNC_2,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting sdc4_cmd_data_0_3_active_cfg = {
+	.func = GPIOMUX_FUNC_2,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting sdc4_suspended_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting sdc4_data_1_suspended_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct msm_gpiomux_config apq8064_sdc4_configs[] __initdata = {
+	{
+		.gpio      = 68,
+		.settings = {
+			[GPIOMUX_ACTIVE] = &sdc4_clk_active_cfg,
+			[GPIOMUX_SUSPENDED] = &sdc4_suspended_cfg,
+		},
+	},
+	{
+		.gpio      = 67,
+		.settings = {
+			[GPIOMUX_ACTIVE] = &sdc4_cmd_data_0_3_active_cfg,
+			[GPIOMUX_SUSPENDED] = &sdc4_suspended_cfg,
+		},
+
+	},
+	{
+		.gpio      = 66,
+		.settings = {
+			[GPIOMUX_ACTIVE] = &sdc4_cmd_data_0_3_active_cfg,
+			[GPIOMUX_SUSPENDED] = &sdc4_suspended_cfg,
+		},
+	},
+	{
+		.gpio      = 65,
+		.settings = {
+			[GPIOMUX_ACTIVE] = &sdc4_cmd_data_0_3_active_cfg,
+			[GPIOMUX_SUSPENDED] = &sdc4_data_1_suspended_cfg,
+		},
+	},
+	{
+		.gpio      = 64,
+		.settings = {
+			[GPIOMUX_ACTIVE] = &sdc4_cmd_data_0_3_active_cfg,
+			[GPIOMUX_SUSPENDED] = &sdc4_suspended_cfg,
+		},
+	},
+	{
+		.gpio      = 63,
+		.settings = {
+			[GPIOMUX_ACTIVE] = &sdc4_cmd_data_0_3_active_cfg,
+			[GPIOMUX_SUSPENDED] = &sdc4_suspended_cfg,
+		},
+	},
+};
+#endif
+
 void __init apq8064_init_gpiomux(void)
 {
 	int rc;
@@ -1072,4 +1249,14 @@
 	 if (machine_is_mpq8064_cdp())
 		msm_gpiomux_install(mpq8064_ir_configs,
 				ARRAY_SIZE(mpq8064_ir_configs));
+
+#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+	 msm_gpiomux_install(apq8064_sdc2_configs,
+			     ARRAY_SIZE(apq8064_sdc2_configs));
+#endif
+
+#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT
+	 msm_gpiomux_install(apq8064_sdc4_configs,
+			     ARRAY_SIZE(apq8064_sdc4_configs));
+#endif
 }
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index 91fd400..7e04ca7 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -126,7 +126,7 @@
 	PM8921_GPIO_INPUT(38, PM_GPIO_PULL_UP_30),
 	/* TABLA CODEC RESET */
 	PM8921_GPIO_OUTPUT(34, 1, MED),
-	PM8921_GPIO_INPUT(31, PM_GPIO_PULL_NO),
+	PM8921_GPIO_OUTPUT(13, 0, HIGH),               /* PCIE_CLK_PWR_EN */
 };
 
 static struct pm8xxx_gpio_init pm8921_mtp_kp_gpios[] __initdata = {
@@ -146,6 +146,8 @@
 	PM8921_MPP_INIT(8, D_OUTPUT, PM8921_MPP_DIG_LEVEL_S4, DOUT_CTRL_LOW),
 	/*MPP9 is used to detect docking station connection/removal on Liquid*/
 	PM8921_MPP_INIT(9, D_INPUT, PM8921_MPP_DIG_LEVEL_S4, DIN_TO_INT),
+	/* PCIE_RESET_N */
+	PM8921_MPP_INIT(1, D_OUTPUT, PM8921_MPP_DIG_LEVEL_VPH, DOUT_CTRL_HIGH),
 };
 
 void __init apq8064_pm8xxx_gpio_mpp_init(void)
diff --git a/arch/arm/mach-msm/board-8064-regulator.c b/arch/arm/mach-msm/board-8064-regulator.c
index 58e83a0..ccd9c54 100644
--- a/arch/arm/mach-msm/board-8064-regulator.c
+++ b/arch/arm/mach-msm/board-8064-regulator.c
@@ -157,6 +157,8 @@
 	REGULATOR_SUPPLY("HSUSB_VDDCX",		"msm_ehci_host.1"),
 	REGULATOR_SUPPLY("HSIC_VDDCX",		"msm_hsic_host"),
 	REGULATOR_SUPPLY("riva_vddcx",		"wcnss_wlan.0"),
+	REGULATOR_SUPPLY("vp_pcie",             "msm_pcie"),
+	REGULATOR_SUPPLY("vptx_pcie",           "msm_pcie"),
 };
 VREG_CONSUMERS(S4) = {
 	REGULATOR_SUPPLY("8921_s4",		NULL),
@@ -213,6 +215,7 @@
 };
 VREG_CONSUMERS(LVS6) = {
 	REGULATOR_SUPPLY("8921_lvs6",		NULL),
+	REGULATOR_SUPPLY("vdd_pcie_vph",        "msm_pcie"),
 };
 VREG_CONSUMERS(LVS7) = {
 	REGULATOR_SUPPLY("8921_lvs7",		NULL),
@@ -256,6 +259,7 @@
 	REGULATOR_SUPPLY("lvds_vccs_3p3v",      "lvds.0"),
 	REGULATOR_SUPPLY("dsi1_vccs_3p3v",      "mipi_dsi.1"),
 	REGULATOR_SUPPLY("hdmi_mux_vdd",        "hdmi_msm.0"),
+	REGULATOR_SUPPLY("pcie_ext_3p3v",       "msm_pcie"),
 };
 VREG_CONSUMERS(EXT_TS_SW) = {
 	REGULATOR_SUPPLY("ext_ts_sw",		NULL),
@@ -545,7 +549,7 @@
 	 *		ID   name always_on pd min_uV   max_uV   en_t supply
 	 *	system_uA reg_ID
 	 */
-	PM8XXX_NLDO1200(L26, "8921_l26", 0, 1, 1050000, 1050000, 200, "8921_s7",
+	PM8XXX_NLDO1200(L26, "8921_l26", 0, 1, 375000, 1050000, 200, "8921_s7",
 		0, 1),
 
 	/*           ID        name     always_on pd       en_t supply reg_ID */
@@ -585,7 +589,7 @@
 	RPM_LDO(L22, 0, 1, 0, 2600000, 2600000, NULL,          0,     0),
 	RPM_LDO(L23, 0, 1, 0, 1800000, 1800000, NULL,          0,     0),
 	RPM_LDO(L24, 0, 1, 1,  750000, 1150000, "8921_s1", 10000, 10000),
-	RPM_LDO(L25, 1, 1, 0, 1225000, 1225000, "8921_s1", 10000, 10000),
+	RPM_LDO(L25, 1, 1, 0, 1250000, 1250000, "8921_s1", 10000, 10000),
 	RPM_LDO(L27, 0, 1, 0, 1100000, 1100000, "8921_s7",     0,     0),
 	RPM_LDO(L28, 0, 1, 0, 1050000, 1050000, "8921_s7",     0,     0),
 	RPM_LDO(L29, 0, 1, 0, 2000000, 2000000, NULL,          0,     0),
diff --git a/arch/arm/mach-msm/board-8064-storage.c b/arch/arm/mach-msm/board-8064-storage.c
index 72126c8..f3790dd 100644
--- a/arch/arm/mach-msm/board-8064-storage.c
+++ b/arch/arm/mach-msm/board-8064-storage.c
@@ -188,13 +188,50 @@
 	},
 };
 
+static struct msm_mmc_gpio sdc2_gpio[] = {
+	{59, "sdc2_clk"},
+	{57, "sdc2_cmd"},
+	{62, "sdc2_dat_0"},
+	{61, "sdc2_dat_1"},
+	{60, "sdc2_dat_2"},
+	{58, "sdc2_dat_3"},
+};
+
+static struct msm_mmc_gpio sdc4_gpio[] = {
+	{68, "sdc4_clk"},
+	{67, "sdc4_cmd"},
+	{66, "sdc4_dat_0"},
+	{65, "sdc4_dat_1"},
+	{64, "sdc4_dat_2"},
+	{63, "sdc4_dat_3"},
+};
+
+static struct msm_mmc_gpio_data mmc_gpio_data[MAX_SDCC_CONTROLLER] = {
+	[SDCC2] = {
+		.gpio = sdc2_gpio,
+		.size = ARRAY_SIZE(sdc2_gpio),
+	},
+	[SDCC4] = {
+		.gpio = sdc4_gpio,
+		.size = ARRAY_SIZE(sdc4_gpio),
+	}
+};
+
 static struct msm_mmc_pin_data mmc_slot_pin_data[MAX_SDCC_CONTROLLER] = {
 	[SDCC1] = {
 		.pad_data = &mmc_pad_data[SDCC1],
 	},
+	[SDCC2] = {
+		.is_gpio = 1,
+		.gpio_data = &mmc_gpio_data[SDCC2],
+	},
 	[SDCC3] = {
 		.pad_data = &mmc_pad_data[SDCC3],
 	},
+	[SDCC4] = {
+		.is_gpio = 1,
+		.gpio_data = &mmc_gpio_data[SDCC4],
+	},
 };
 
 #define MSM_MPM_PIN_SDC1_DAT1	17
@@ -227,6 +264,26 @@
 static struct mmc_platform_data *apq8064_sdc1_pdata;
 #endif
 
+#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+static unsigned int sdc2_sup_clk_rates[] = {
+	400000, 24000000, 48000000
+};
+
+static struct mmc_platform_data sdc2_data = {
+	.ocr_mask       = MMC_VDD_27_28 | MMC_VDD_28_29,
+	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
+	.sup_clk_table	= sdc2_sup_clk_rates,
+	.sup_clk_cnt	= ARRAY_SIZE(sdc2_sup_clk_rates),
+	.pclk_src_dfab	= 1,
+	.pin_data	= &mmc_slot_pin_data[SDCC2],
+	.sdiowakeup_irq = MSM_GPIO_TO_INT(61),
+	.msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
+};
+static struct mmc_platform_data *apq8064_sdc2_pdata = &sdc2_data;
+#else
+static struct mmc_platform_data *apq8064_sdc2_pdata;
+#endif
+
 #ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
 static unsigned int sdc3_sup_clk_rates[] = {
 	400000, 24000000, 48000000, 96000000, 192000000
@@ -258,6 +315,27 @@
 static struct mmc_platform_data *apq8064_sdc3_pdata;
 #endif
 
+
+#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT
+static unsigned int sdc4_sup_clk_rates[] = {
+	400000, 24000000, 48000000
+};
+
+static struct mmc_platform_data sdc4_data = {
+	.ocr_mask       = MMC_VDD_27_28 | MMC_VDD_28_29,
+	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
+	.sup_clk_table	= sdc4_sup_clk_rates,
+	.sup_clk_cnt	= ARRAY_SIZE(sdc4_sup_clk_rates),
+	.pclk_src_dfab	= 1,
+	.pin_data	= &mmc_slot_pin_data[SDCC4],
+	.sdiowakeup_irq = MSM_GPIO_TO_INT(65),
+	.msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
+};
+static struct mmc_platform_data *apq8064_sdc4_pdata = &sdc4_data;
+#else
+static struct mmc_platform_data *apq8064_sdc4_pdata;
+#endif
+
 void __init apq8064_init_mmc(void)
 {
 	if ((machine_is_apq8064_rumi3()) || machine_is_apq8064_sim()) {
@@ -278,6 +356,9 @@
 	if (apq8064_sdc1_pdata)
 		apq8064_add_sdcc(1, apq8064_sdc1_pdata);
 
+	if (apq8064_sdc2_pdata)
+		apq8064_add_sdcc(2, apq8064_sdc2_pdata);
+
 	if (apq8064_sdc3_pdata) {
 		if (!machine_is_apq8064_cdp()) {
 			apq8064_sdc3_pdata->wpswitch_gpio = 0;
@@ -285,11 +366,33 @@
 		}
 		if (machine_is_mpq8064_cdp() || machine_is_mpq8064_hrd() ||
 			machine_is_mpq8064_dtv()) {
+			int rc;
+			struct pm_gpio sd_card_det_init_cfg = {
+				.direction      = PM_GPIO_DIR_IN,
+				.output_buffer  = PM_GPIO_OUT_BUF_CMOS,
+				.pull           = PM_GPIO_PULL_UP_30,
+				.vin_sel        = PM_GPIO_VIN_S4,
+				.out_strength   = PM_GPIO_STRENGTH_NO,
+				.function       = PM_GPIO_FUNC_NORMAL,
+			};
+
 			apq8064_sdc3_pdata->status_gpio =
 				PM8921_GPIO_PM_TO_SYS(31);
 			apq8064_sdc3_pdata->status_irq =
 				PM8921_GPIO_IRQ(PM8921_IRQ_BASE, 31);
+			rc = pm8xxx_gpio_config(apq8064_sdc3_pdata->status_gpio,
+					&sd_card_det_init_cfg);
+			if (rc) {
+				pr_info("%s: SD_CARD_DET GPIO%d config "
+					"failed(%d)\n", __func__,
+					apq8064_sdc3_pdata->status_gpio, rc);
+				apq8064_sdc3_pdata->status_gpio = 0;
+				apq8064_sdc3_pdata->status_irq = 0;
+			}
 		}
 		apq8064_add_sdcc(3, apq8064_sdc3_pdata);
 	}
+
+	if (apq8064_sdc4_pdata)
+		apq8064_add_sdcc(4, apq8064_sdc4_pdata);
 }
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index ed17cc4..12d67a9 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -69,6 +69,7 @@
 #include <sound/cs8427.h>
 #include <media/gpio-ir-recv.h>
 #include <linux/fmem.h>
+#include <mach/msm_pcie.h>
 
 #include "msm_watchdog.h"
 #include "board-8064.h"
@@ -90,18 +91,20 @@
 #endif
 
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+#define HOLE_SIZE		0x20000
 #define MSM_PMEM_KERNEL_EBI1_SIZE  0x65000
 #ifdef CONFIG_MSM_IOMMU
 #define MSM_ION_MM_SIZE		0x3800000
 #define MSM_ION_SF_SIZE		0
+#define MSM_ION_QSECOM_SIZE	0x780000 /* (7.5MB) */
 #define MSM_ION_HEAP_NUM	7
 #else
 #define MSM_ION_MM_SIZE		MSM_PMEM_ADSP_SIZE
 #define MSM_ION_SF_SIZE		MSM_PMEM_SIZE
+#define MSM_ION_QSECOM_SIZE	0x600000 /* (6MB) */
 #define MSM_ION_HEAP_NUM	8
 #endif
-#define MSM_ION_MM_FW_SIZE	0x200000 /* (2MB) */
-#define MSM_ION_QSECOM_SIZE	0x300000 /* (3MB) */
+#define MSM_ION_MM_FW_SIZE	(0x200000 - HOLE_SIZE) /* (2MB - 128KB) */
 #define MSM_ION_MFC_SIZE	SZ_8K
 #define MSM_ION_AUDIO_SIZE	MSM_PMEM_AUDIO_SIZE
 #else
@@ -109,10 +112,15 @@
 #define MSM_ION_HEAP_NUM	1
 #endif
 
-#define APQ8064_FIXED_AREA_START 0xa0000000
+#define APQ8064_FIXED_AREA_START (0xa0000000 - (MSM_ION_MM_FW_SIZE + \
+							HOLE_SIZE))
 #define MAX_FIXED_AREA_SIZE	0x10000000
-#define MSM_MM_FW_SIZE		0x200000
-#define APQ8064_FW_START	(APQ8064_FIXED_AREA_START - MSM_MM_FW_SIZE)
+#define MSM_MM_FW_SIZE		(0x200000 - HOLE_SIZE)
+#define APQ8064_FW_START	APQ8064_FIXED_AREA_START
+
+/* PCIe power enable pmic gpio */
+#define PCIE_PWR_EN_PMIC_GPIO 13
+#define PCIE_RST_N_PMIC_MPP 1
 
 #ifdef CONFIG_KERNEL_PMEM_EBI_REGION
 static unsigned pmem_kernel_ebi1_size = MSM_PMEM_KERNEL_EBI1_SIZE;
@@ -499,19 +507,20 @@
 		return;
 
 	if (apq8064_fmem_pdata.size) {
-		apq8064_fmem_pdata.reserved_size_low = fixed_low_size;
+		apq8064_fmem_pdata.reserved_size_low = fixed_low_size +
+								HOLE_SIZE;
 		apq8064_fmem_pdata.reserved_size_high = fixed_high_size;
 	}
 
 	/* Since the fixed area may be carved out of lowmem,
 	 * make sure the length is a multiple of 1M.
 	 */
-	fixed_size = (fixed_size + MSM_MM_FW_SIZE + SECTION_SIZE - 1)
+	fixed_size = (fixed_size + HOLE_SIZE + SECTION_SIZE - 1)
 		& SECTION_MASK;
 	apq8064_reserve_fixed_area(fixed_size);
 
 	fixed_low_start = APQ8064_FIXED_AREA_START;
-	fixed_middle_start = fixed_low_start + fixed_low_size;
+	fixed_middle_start = fixed_low_start + fixed_low_size + HOLE_SIZE;
 	fixed_high_start = fixed_middle_start + fixed_middle_size;
 
 	for (i = 0; i < apq8064_ion_pdata.nr; ++i) {
@@ -519,11 +528,13 @@
 
 		if (heap->extra_data) {
 			int fixed_position = NOT_FIXED;
+			struct ion_cp_heap_pdata *pdata;
 
 			switch (heap->type) {
 			case ION_HEAP_TYPE_CP:
-				fixed_position = ((struct ion_cp_heap_pdata *)
-					heap->extra_data)->fixed_position;
+				pdata =
+				(struct ion_cp_heap_pdata *)heap->extra_data;
+				fixed_position = pdata->fixed_position;
 				break;
 			case ION_HEAP_TYPE_CARVEOUT:
 				fixed_position = ((struct ion_co_heap_pdata *)
@@ -539,6 +550,9 @@
 				break;
 			case FIXED_MIDDLE:
 				heap->base = fixed_middle_start;
+				pdata->secure_base = fixed_middle_start
+								- HOLE_SIZE;
+				pdata->secure_size = HOLE_SIZE + heap->size;
 				break;
 			case FIXED_HIGH:
 				heap->base = fixed_high_start;
@@ -556,6 +570,17 @@
 	apq8064_mdp_writeback(apq8064_reserve_table);
 }
 
+static void __init reserve_cache_dump_memory(void)
+{
+#ifdef CONFIG_MSM_CACHE_DUMP
+	unsigned int total;
+
+	total = apq8064_cache_dump_pdata.l1_size +
+		apq8064_cache_dump_pdata.l2_size;
+	apq8064_reserve_table[MEMTYPE_EBI1].size += total;
+#endif
+}
+
 static void __init apq8064_calculate_reserve_sizes(void)
 {
 	size_pmem_devices();
@@ -563,6 +588,7 @@
 	reserve_ion_memory();
 	reserve_mdp_memory();
 	reserve_rtb_memory();
+	reserve_cache_dump_memory();
 }
 
 static struct reserve_info apq8064_reserve_info __initdata = {
@@ -859,9 +885,11 @@
 
 static void __init apq8064_ehci_host_init(void)
 {
-	if (machine_is_apq8064_liquid()) {
-		msm_ehci_host_pdata3.dock_connect_irq =
-				PM8921_MPP_IRQ(PM8921_IRQ_BASE, 9);
+	if (machine_is_apq8064_liquid() || machine_is_mpq8064_cdp() ||
+		machine_is_mpq8064_hrd() || machine_is_mpq8064_dtv()) {
+		if (machine_is_apq8064_liquid())
+			msm_ehci_host_pdata3.dock_connect_irq =
+					PM8921_MPP_IRQ(PM8921_IRQ_BASE, 9);
 
 		apq8064_device_ehci_host3.dev.platform_data =
 				&msm_ehci_host_pdata3;
@@ -998,13 +1026,13 @@
 	{
 		.name = "VDDD_CDC_D",
 		.min_uV = 1225000,
-		.max_uV = 1225000,
+		.max_uV = 1250000,
 		.optimum_uA = WCD9XXX_VDDD_CDC_D_CUR_MAX,
 	},
 	{
 		.name = "CDC_VDDA_A_1P2V",
 		.min_uV = 1225000,
-		.max_uV = 1225000,
+		.max_uV = 1250000,
 		.optimum_uA = WCD9XXX_VDDD_CDC_A_CUR_MAX,
 	},
 	},
@@ -1065,13 +1093,13 @@
 	{
 		.name = "VDDD_CDC_D",
 		.min_uV = 1225000,
-		.max_uV = 1225000,
+		.max_uV = 1250000,
 		.optimum_uA = WCD9XXX_VDDD_CDC_D_CUR_MAX,
 	},
 	{
 		.name = "CDC_VDDA_A_1P2V",
 		.min_uV = 1225000,
-		.max_uV = 1225000,
+		.max_uV = 1250000,
 		.optimum_uA = WCD9XXX_VDDD_CDC_A_CUR_MAX,
 	},
 	},
@@ -1124,23 +1152,31 @@
 #define ISA1200_HAP_LEN_GPIO		PM8921_GPIO_PM_TO_SYS(20)
 #define ISA1200_HAP_CLK			PM8921_GPIO_PM_TO_SYS(44)
 
-static int isa1200_power(int on)
+static int isa1200_clk_enable(bool on)
 {
 	int rc = 0;
 
-	gpio_set_value_cansleep(ISA1200_HAP_CLK, !!on);
+	gpio_set_value_cansleep(ISA1200_HAP_CLK, on);
 
-	if (on)
+	if (on) {
 		rc = pm8xxx_aux_clk_control(CLK_MP3_2, XO_DIV_1, true);
-	else
+		if (rc) {
+			pr_err("%s: unable to write aux clock register(%d)\n",
+				__func__, rc);
+			goto err_gpio_dis;
+		}
+	} else {
 		rc = pm8xxx_aux_clk_control(CLK_MP3_2, XO_DIV_NONE, true);
-
-	if (rc) {
-		pr_err("%s: unable to write aux clock register(%d)\n",
-			__func__, rc);
+		if (rc)
+			pr_err("%s: unable to write aux clock register(%d)\n",
+				__func__, rc);
 	}
 
 	return rc;
+
+err_gpio_dis:
+	gpio_set_value_cansleep(ISA1200_HAP_CLK, !on);
+	return rc;
 }
 
 static int isa1200_dev_setup(bool enable)
@@ -1182,7 +1218,7 @@
 static struct isa1200_platform_data isa1200_1_pdata = {
 	.name = "vibrator",
 	.dev_setup = isa1200_dev_setup,
-	.power_on = isa1200_power,
+	.clk_enable = isa1200_clk_enable,
 	.hap_en_gpio = ISA1200_HAP_EN_GPIO,
 	.hap_len_gpio = ISA1200_HAP_LEN_GPIO,
 	.max_timeout = 15000,
@@ -1209,7 +1245,7 @@
 	/* T6 Object */
 	0, 0, 0, 0, 0, 0,
 	/* T38 Object */
-	14, 1, 0, 22, 2, 12, 0, 0, 0, 0,
+	14, 2, 0, 24, 5, 12, 0, 0, 0, 0,
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -1221,7 +1257,7 @@
 	/* T8 Object */
 	25, 0, 20, 20, 0, 0, 0, 0, 0, 0,
 	/* T9 Object */
-	131, 0, 0, 26, 42, 0, 32, 80, 2, 5,
+	139, 0, 0, 26, 42, 0, 32, 80, 2, 5,
 	0, 5, 5, 0, 10, 30, 10, 10, 255, 2,
 	85, 5, 0, 5, 9, 5, 12, 35, 70, 40,
 	20, 5, 0, 0, 0,
@@ -1231,13 +1267,13 @@
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	0, 0, 0, 0, 0, 0, 0, 0, 0,
 	/* T25 Object */
-	3, 0, 60, 115, 156, 99,
+	1, 0, 60, 115, 156, 99,
 	/* T27 Object */
 	0, 0, 0, 0, 0, 0, 0,
 	/* T40 Object */
 	0, 0, 0, 0, 0,
 	/* T42 Object */
-	2, 0, 255, 0, 255, 0, 0, 0, 0, 0,
+	0, 0, 255, 0, 255, 0, 0, 0, 0, 0,
 	/* T43 Object */
 	0, 0, 0, 0, 0, 0, 0, 64, 0, 8,
 	16,
@@ -1246,7 +1282,7 @@
 	/* T47 Object */
 	0, 0, 0, 0, 0, 0, 3, 64, 66, 0,
 	/* T48 Object */
-	31, 64, 64, 0, 0, 0, 0, 0, 0, 0,
+	1, 64, 64, 0, 0, 0, 0, 0, 0, 0,
 	32, 40, 0, 10, 10, 0, 0, 100, 10, 90,
 	0, 0, 0, 0, 0, 0, 0, 10, 1, 10,
 	52, 10, 12, 0, 33, 0, 1, 0, 0, 0,
@@ -1662,6 +1698,8 @@
 static struct mdm_platform_data mdm_platform_data = {
 	.mdm_version = "3.0",
 	.ramdump_delay_ms = 2000,
+	.early_power_on = 1,
+	.sfr_query = 1,
 	.peripheral_platform_device = &apq8064_device_hsic_host,
 };
 
@@ -1738,62 +1776,56 @@
 		MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT,
 		MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE),
 		true,
-		100, 650, 801, 200,
+		1, 784, 180000, 100,
 	},
 
 	{
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE,
 		MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE),
 		true,
-		2000, 200, 576000, 2000,
+		1300, 228, 1200000, 2000,
 	},
 
 	{
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
 		MSM_RPMRS_LIMITS(ON, GDHS, MAX, ACTIVE),
 		false,
-		8500, 51, 1122000, 8500,
+		2000, 138, 1208400, 3200,
 	},
 
 	{
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
-		MSM_RPMRS_LIMITS(ON, HSFS_OPEN, MAX, ACTIVE),
-		false,
-		9000, 51, 1130300, 9000,
-	},
-	{
-		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
 		MSM_RPMRS_LIMITS(ON, HSFS_OPEN, ACTIVE, RET_HIGH),
 		false,
-		10000, 51, 1130300, 10000,
+		6000, 119, 1850300, 9000,
 	},
 
 	{
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
 		MSM_RPMRS_LIMITS(OFF, GDHS, MAX, ACTIVE),
 		false,
-		12000, 14, 2205900, 12000,
+		9200, 68, 2839200, 16400,
 	},
 
 	{
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
 		MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, MAX, ACTIVE),
 		false,
-		18000, 12, 2364250, 18000,
+		10300, 63, 3128000, 18200,
 	},
 
 	{
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
 		MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, ACTIVE, RET_HIGH),
 		false,
-		23500, 10, 2667000, 23500,
+		18000, 10, 4602600, 27000,
 	},
 
 	{
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
 		MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, RET_HIGH, RET_LOW),
 		false,
-		29700, 5, 2867000, 30000,
+		20000, 2, 5752000, 32000,
 	},
 };
 
@@ -1998,6 +2030,22 @@
 	msm_bus_8064_cpss_fpb.dev.platform_data = &msm_bus_8064_cpss_fpb_pdata;
 }
 
+/* PCIe gpios */
+static struct msm_pcie_gpio_info_t msm_pcie_gpio_info[MSM_PCIE_MAX_GPIO] = {
+	{"rst_n", PM8921_MPP_PM_TO_SYS(PCIE_RST_N_PMIC_MPP), 0},
+	{"pwr_en", PM8921_GPIO_PM_TO_SYS(PCIE_PWR_EN_PMIC_GPIO), 1},
+};
+
+static struct msm_pcie_platform msm_pcie_platform_data = {
+	.gpio = msm_pcie_gpio_info,
+};
+
+static void __init mpq8064_pcie_init(void)
+{
+	msm_device_pcie.dev.platform_data = &msm_pcie_platform_data;
+	platform_device_register(&msm_device_pcie);
+}
+
 static struct platform_device apq8064_device_ext_5v_vreg __devinitdata = {
 	.name	= GPIO_REGULATOR_DEV_NAME,
 	.id	= PM8921_MPP_PM_TO_SYS(7),
@@ -2140,9 +2188,11 @@
 	&apq_cpudai_slimbus_1_tx,
 	&apq_cpudai_slimbus_2_tx,
 	&apq_cpudai_slimbus_3_rx,
+	&apq_cpudai_slimbus_3_tx,
 	&apq8064_rpm_device,
 	&apq8064_rpm_log_device,
 	&apq8064_rpm_stat_device,
+	&apq_device_tz_log,
 	&msm_bus_8064_apps_fabric,
 	&msm_bus_8064_sys_fabric,
 	&msm_bus_8064_mm_fabric,
@@ -2169,6 +2219,7 @@
 	&msm8960_gemini_device,
 	&apq8064_iommu_domain_device,
 	&msm_tsens_device,
+	&apq8064_cache_dump_device,
 };
 
 static struct platform_device *sim_devices[] __initdata = {
@@ -2258,6 +2309,33 @@
 	.id	= -1,
 };
 
+static int rf4ce_gpio_init(void)
+{
+	if (!machine_is_mpq8064_cdp())
+		return -EINVAL;
+
+	/* CC2533 SRDY Input */
+	if (!gpio_request(SX150X_GPIO(4, 6), "rf4ce_srdy")) {
+		gpio_direction_input(SX150X_GPIO(4, 6));
+		gpio_export(SX150X_GPIO(4, 6), true);
+	}
+
+	/* CC2533 MRDY Output */
+	if (!gpio_request(SX150X_GPIO(4, 5), "rf4ce_mrdy")) {
+		gpio_direction_output(SX150X_GPIO(4, 5), 1);
+		gpio_export(SX150X_GPIO(4, 5), true);
+	}
+
+	/* CC2533 Reset Output */
+	if (!gpio_request(SX150X_GPIO(4, 7), "rf4ce_reset")) {
+		gpio_direction_output(SX150X_GPIO(4, 7), 0);
+		gpio_export(SX150X_GPIO(4, 7), true);
+	}
+
+	return 0;
+}
+late_initcall(rf4ce_gpio_init);
+
 static struct platform_device *mpq_devices[] __initdata = {
 	&msm_device_sps_apq8064,
 	&mpq8064_device_qup_i2c_gsbi5,
@@ -2877,6 +2955,7 @@
 		machine_is_mpq8064_dtv()) {
 		enable_avc_i2c_bus();
 		platform_add_devices(mpq_devices, ARRAY_SIZE(mpq_devices));
+		mpq8064_pcie_init();
 	} else {
 		ethernet_init();
 		platform_add_devices(cdp_devices, ARRAY_SIZE(cdp_devices));
@@ -2972,6 +3051,7 @@
 	.handle_irq = gic_handle_irq,
 	.timer = &msm_timer,
 	.init_machine = apq8064_cdp_init,
+	.init_early = apq8064_allocate_memory_regions,
 	.init_very_early = apq8064_early_reserve,
 MACHINE_END
 
@@ -2982,6 +3062,7 @@
 	.handle_irq = gic_handle_irq,
 	.timer = &msm_timer,
 	.init_machine = apq8064_cdp_init,
+	.init_early = apq8064_allocate_memory_regions,
 	.init_very_early = apq8064_early_reserve,
 MACHINE_END
 
diff --git a/arch/arm/mach-msm/board-8064.h b/arch/arm/mach-msm/board-8064.h
index 67e0e6f..c992865 100644
--- a/arch/arm/mach-msm/board-8064.h
+++ b/arch/arm/mach-msm/board-8064.h
@@ -20,6 +20,7 @@
 #include <mach/irqs.h>
 #include <mach/rpm-regulator.h>
 #include <mach/msm_rtb.h>
+#include <mach/msm_cache_dump.h>
 
 /* Macros assume PMIC GPIOs and MPPs start at 1 */
 #define PM8921_GPIO_BASE		NR_GPIO_IRQS
@@ -143,4 +144,5 @@
 };
 
 extern struct msm_rtb_platform_data apq8064_rtb_pdata;
+extern struct msm_cache_dump_platform_data apq8064_cache_dump_pdata;
 #endif
diff --git a/arch/arm/mach-msm/board-8930-camera.c b/arch/arm/mach-msm/board-8930-camera.c
index cc5b13c..c9d720c 100644
--- a/arch/arm/mach-msm/board-8930-camera.c
+++ b/arch/arm/mach-msm/board-8930-camera.c
@@ -198,12 +198,9 @@
 #ifdef CONFIG_MSM_CAMERA_FLASH
 static struct msm_camera_sensor_flash_src msm_flash_src = {
 	.flash_sr_type = MSM_CAMERA_FLASH_SRC_EXT,
-	._fsrc.ext_driver_src.led_en = GPIO_CAM_GP_LED_EN1,
-	._fsrc.ext_driver_src.led_flash_en = GPIO_CAM_GP_LED_EN2,
-#if defined(CONFIG_I2C) && (defined(CONFIG_GPIO_SX150X) || \
-			defined(CONFIG_GPIO_SX150X_MODULE))
-	._fsrc.ext_driver_src.expander_info = cam_expander_info,
-#endif
+	._fsrc.ext_driver_src.led_en = VFE_CAMIF_TIMER1_GPIO,
+	._fsrc.ext_driver_src.led_flash_en = VFE_CAMIF_TIMER2_GPIO,
+	._fsrc.ext_driver_src.flash_id = MAM_CAMERA_EXT_LED_FLASH_TPS61310,
 };
 #endif
 
@@ -536,7 +533,8 @@
 };
 
 static struct msm_camera_sensor_flash_data flash_s5k3l1yx = {
-	.flash_type = MSM_CAMERA_FLASH_NONE,
+	.flash_type = MSM_CAMERA_FLASH_LED,
+	.flash_src = &msm_flash_src
 };
 
 static struct msm_camera_csi_lane_params s5k3l1yx_csi_lane_params = {
@@ -585,6 +583,15 @@
 		struct msm_camera_sensor_info *s_info;
 		s_info = &msm_camera_sensor_s5k3l1yx_data;
 		s_info->sensor_platform_info->mount_angle = 0;
+		msm_flash_src._fsrc.ext_driver_src.led_en =
+			GPIO_CAM_GP_LED_EN1;
+		msm_flash_src._fsrc.ext_driver_src.led_flash_en =
+			GPIO_CAM_GP_LED_EN2;
+#if defined(CONFIG_I2C) && (defined(CONFIG_GPIO_SX150X) || \
+	defined(CONFIG_GPIO_SX150X_MODULE))
+		msm_flash_src._fsrc.ext_driver_src.expander_info =
+			cam_expander_info;
+#endif
 	}
 
 	platform_device_register(&msm_camera_server);
@@ -615,11 +622,9 @@
 	I2C_BOARD_INFO("s5k3l1yx", 0x20),
 	.platform_data = &msm_camera_sensor_s5k3l1yx_data,
 	},
-#ifdef CONFIG_MSM_CAMERA_FLASH_SC628A
 	{
-	I2C_BOARD_INFO("sc628a", 0x6E),
+	I2C_BOARD_INFO("tps61310", 0x66),
 	},
-#endif
 };
 
 struct msm_camera_board_info msm8930_camera_board_info = {
diff --git a/arch/arm/mach-msm/board-8930-gpiomux.c b/arch/arm/mach-msm/board-8930-gpiomux.c
index 936a798..3013070 100644
--- a/arch/arm/mach-msm/board-8930-gpiomux.c
+++ b/arch/arm/mach-msm/board-8930-gpiomux.c
@@ -624,6 +624,22 @@
 	},
 };
 
+static struct gpiomux_setting sd_det_line = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct msm_gpiomux_config msm8930_sd_det_config[] __initdata = {
+	{
+		.gpio = 94,	/* SD Card Detect Line */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &sd_det_line,
+			[GPIOMUX_ACTIVE] = &sd_det_line,
+		},
+	},
+};
+
 int __init msm8930_init_gpiomux(void)
 {
 	int rc = msm_gpiomux_init(NR_GPIO_IRQS);
@@ -687,5 +703,9 @@
 
 	msm_gpiomux_install(msm8960_mdp_vsync_configs,
 			ARRAY_SIZE(msm8960_mdp_vsync_configs));
+
+	msm_gpiomux_install(msm8930_sd_det_config,
+			ARRAY_SIZE(msm8930_sd_det_config));
+
 	return 0;
 }
diff --git a/arch/arm/mach-msm/board-8930-gpu.c b/arch/arm/mach-msm/board-8930-gpu.c
index e23b76c..3c3843a 100644
--- a/arch/arm/mach-msm/board-8930-gpu.c
+++ b/arch/arm/mach-msm/board-8930-gpu.c
@@ -115,7 +115,7 @@
 static struct kgsl_device_platform_data kgsl_3d0_pdata = {
 	.pwrlevel = {
 		{
-			.gpu_freq = 400000000,
+			.gpu_freq = 450000000,
 			.bus_freq = 3,
 			.io_fraction = 0,
 		},
diff --git a/arch/arm/mach-msm/board-8930-regulator.c b/arch/arm/mach-msm/board-8930-regulator.c
index fc89a11..2f24c95 100644
--- a/arch/arm/mach-msm/board-8930-regulator.c
+++ b/arch/arm/mach-msm/board-8930-regulator.c
@@ -84,6 +84,9 @@
 	REGULATOR_SUPPLY("VDDIO_CDC",		"sitar-slim"),
 	REGULATOR_SUPPLY("CDC_VDDA_TX",		"sitar-slim"),
 	REGULATOR_SUPPLY("CDC_VDDA_RX",		"sitar-slim"),
+	REGULATOR_SUPPLY("VDDIO_CDC",		"sitar1p1-slim"),
+	REGULATOR_SUPPLY("CDC_VDDA_TX",		"sitar1p1-slim"),
+	REGULATOR_SUPPLY("CDC_VDDA_RX",		"sitar1p1-slim"),
 	REGULATOR_SUPPLY("vddp",		"0-0048"),
 };
 VREG_CONSUMERS(L12) = {
@@ -118,6 +121,8 @@
 	REGULATOR_SUPPLY("8038_l20",		NULL),
 	REGULATOR_SUPPLY("VDDD_CDC_D",		"sitar-slim"),
 	REGULATOR_SUPPLY("CDC_VDDA_A_1P2V",	"sitar-slim"),
+	REGULATOR_SUPPLY("VDDD_CDC_D",		"sitar1p1-slim"),
+	REGULATOR_SUPPLY("CDC_VDDA_A_1P2V",	"sitar1p1-slim"),
 };
 VREG_CONSUMERS(L21) = {
 	REGULATOR_SUPPLY("8038_l21",		NULL),
@@ -159,6 +164,7 @@
 VREG_CONSUMERS(S4) = {
 	REGULATOR_SUPPLY("8038_s4",		NULL),
 	REGULATOR_SUPPLY("CDC_VDD_CP",		"sitar-slim"),
+	REGULATOR_SUPPLY("CDC_VDD_CP",		"sitar1p1-slim"),
 };
 VREG_CONSUMERS(S5) = {
 	REGULATOR_SUPPLY("8038_s5",		NULL),
@@ -446,11 +452,11 @@
 	 *	    ID  name always_on pd min_uV   max_uV   en_t supply
 	 *	system_uA reg_ID
 	 */
-	PM8XXX_NLDO1200(L16, "8038_l16", 0, 1, 1050000, 1050000, 200, "8038_s3",
+	PM8XXX_NLDO1200(L16, "8038_l16", 0, 1, 375000, 1050000, 200, "8038_s3",
 		0, 0),
-	PM8XXX_NLDO1200(L19, "8038_l19", 0, 1, 1050000, 1050000, 200, "8038_s3",
+	PM8XXX_NLDO1200(L19, "8038_l19", 0, 1, 375000, 1050000, 200, "8038_s3",
 		0, 1),
-	PM8XXX_NLDO1200(L27, "8038_l27", 0, 1, 1050000, 1050000, 200, "8038_s3",
+	PM8XXX_NLDO1200(L27, "8038_l27", 0, 1, 375000, 1050000, 200, "8038_s3",
 		0, 2),
 };
 
diff --git a/arch/arm/mach-msm/board-8930-storage.c b/arch/arm/mach-msm/board-8930-storage.c
index 6dd7add..89c54fe 100644
--- a/arch/arm/mach-msm/board-8930-storage.c
+++ b/arch/arm/mach-msm/board-8930-storage.c
@@ -53,7 +53,19 @@
 		.name = "sdc_vdd",
 		.high_vol_level = 2950000,
 		.low_vol_level = 2950000,
+		/*
+		 * Normally this is not an always ON regulator. On this
+		 * platform, unfortunately the sd detect line is connected
+		 * to this via esd circuit and so turn this off/on while card
+		 * is not present causes the sd detect line to toggle
+		 * continuously. This is expected to be fixed in the newer
+		 * hardware revisions - maybe once that is done, this can be
+		 * reverted.
+		 */
+		.always_on = 1,
+		.lpm_sup = 1,
 		.hpm_uA = 800000, /* 800mA */
+		.lpm_uA = 9000,
 	}
 };
 
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index 1c4251c..19cc762 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -131,14 +131,15 @@
 #ifdef CONFIG_MSM_IOMMU
 #define MSM_ION_MM_SIZE            0x3800000 /* Need to be multiple of 64K */
 #define MSM_ION_SF_SIZE            0x0
+#define MSM_ION_QSECOM_SIZE	0x780000 /* (7.5MB) */
 #define MSM_ION_HEAP_NUM	7
 #else
 #define MSM_ION_SF_SIZE		MSM_PMEM_SIZE
 #define MSM_ION_MM_SIZE		MSM_PMEM_ADSP_SIZE
+#define MSM_ION_QSECOM_SIZE	0x600000 /* (6MB) */
 #define MSM_ION_HEAP_NUM	8
 #endif
 #define MSM_ION_MM_FW_SIZE	0x200000 /* (2MB) */
-#define MSM_ION_QSECOM_SIZE	0x300000 /* (3MB) */
 #define MSM_ION_MFC_SIZE	SZ_8K
 #define MSM_ION_AUDIO_SIZE	MSM_PMEM_AUDIO_SIZE
 
@@ -797,6 +798,70 @@
 	.platform_data = &sitar_platform_data,
 	},
 };
+
+static struct wcd9xxx_pdata sitar1p1_platform_data = {
+		.slimbus_slave_device = {
+		.name = "sitar-slave",
+		.e_addr = {0, 0, 0x70, 0, 0x17, 2},
+	},
+	.irq = MSM_GPIO_TO_INT(62),
+	.irq_base = SITAR_INTERRUPT_BASE,
+	.num_irqs = NR_WCD9XXX_IRQS,
+	.reset_gpio = 42,
+	.micbias = {
+		.ldoh_v = SITAR_LDOH_2P85_V,
+		.cfilt1_mv = 1800,
+		.cfilt2_mv = 1800,
+		.bias1_cfilt_sel = SITAR_CFILT1_SEL,
+		.bias2_cfilt_sel = SITAR_CFILT2_SEL,
+	},
+	.regulator = {
+	{
+		.name = "CDC_VDD_CP",
+		.min_uV = 1950000,
+		.max_uV = 2200000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_CP_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_RX",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_RX_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_TX",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_TX_CUR_MAX,
+	},
+	{
+		.name = "VDDIO_CDC",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_VDDIO_CDC_CUR_MAX,
+	},
+	{
+		.name = "VDDD_CDC_D",
+		.min_uV = 1200000,
+		.max_uV = 1200000,
+		.optimum_uA = WCD9XXX_VDDD_CDC_D_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_A_1P2V",
+		.min_uV = 1200000,
+		.max_uV = 1200000,
+		.optimum_uA = WCD9XXX_VDDD_CDC_A_CUR_MAX,
+	},
+	},
+};
+
+static struct slim_device msm_slim_sitar1p1 = {
+	.name = "sitar1p1-slim",
+	.e_addr = {0, 1, 0x70, 0, 0x17, 2},
+	.dev = {
+	.platform_data = &sitar1p1_platform_data,
+	},
+};
 #endif
 
 
@@ -806,6 +871,10 @@
 		.bus_num = 1,
 		.slim_slave = &msm_slim_sitar,
 	},
+	{
+		.bus_num = 1,
+		.slim_slave = &msm_slim_sitar1p1,
+	},
 #endif
 	/* add more slimbus slaves as needed */
 };
@@ -1581,16 +1650,16 @@
 	/* T6 Object */
 	 0, 0, 0, 0, 0, 0,
 	/* T38 Object */
-	 15, 2, 0, 15, 12, 11, 0, 0,
+	 15, 3, 0, 15, 12, 11, 0, 0,
 	/* T7 Object */
-	 48, 255, 25,
+	32, 16, 50,
 	/* T8 Object */
-	 27, 0, 5, 1, 0, 0, 8, 8, 0, 0,
+	 30, 0, 5, 1, 0, 0, 8, 8, 0, 0,
 	/* T9 Object */
-	 131, 0, 0, 19, 11, 0, 16, 35, 1, 3,
-	 10, 15, 1, 11, 4, 5, 40, 10, 43, 4,
-	 54, 2, 0, 0, 0, 0, 143, 40, 143, 80,
-	 18, 15, 50, 50, 2,
+	 131, 0, 0, 19, 11, 0, 16, 43, 2, 3,
+	 10, 7, 2, 0, 4, 5, 35, 10, 43, 4,
+	 54, 2, 15, 32, 38, 38, 143, 40, 143, 80,
+	 7, 9, 50, 50, 2,
 	/* T15 Object */
 	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	 0,
@@ -1610,13 +1679,13 @@
 	/* T42 Object */
 	 0, 0, 0, 0, 0, 0, 0, 0,
 	/* T46 Object */
-	 0, 3, 16, 48, 0, 0, 1, 0, 0,
+	 0, 3, 8, 16, 0, 0, 1, 0, 0,
 	/* T47 Object */
 	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	/* T48 Object */
-	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	 0, 0, 8, 0, 0, 0, 0, 0, 0, 0,
+	 0, 0, 0, 0, 0, 0, 0, 100, 4, 64,
+	 0, 0, 5, 42, 0, 0, 0, 0, 0, 0,
 	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	 0, 0, 0, 0,
@@ -1721,6 +1790,7 @@
 		.gpio = GPIO_VOLUME_UP,
 		.wakeup = 1,
 		.active_low = 1,
+		.debounce_interval = 15,
 	},
 	{
 		.code = KEY_VOLUMEDOWN,
@@ -1729,6 +1799,7 @@
 		.gpio = GPIO_VOLUME_DOWN,
 		.wakeup = 1,
 		.active_low = 1,
+		.debounce_interval = 15,
 	},
 	{
 		.code = KEY_CAMERA_FOCUS,
@@ -1737,6 +1808,7 @@
 		.gpio = GPIO_CAMERA_FOCUS,
 		.wakeup = 1,
 		.active_low = 1,
+		.debounce_interval = 15,
 	},
 	{
 		.code = KEY_CAMERA_SNAPSHOT,
@@ -1745,6 +1817,7 @@
 		.gpio = GPIO_CAMERA_SNAPSHOT,
 		.wakeup = 1,
 		.active_low = 1,
+		.debounce_interval = 15,
 	},
 };
 
@@ -2057,62 +2130,56 @@
 		MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT,
 		MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE),
 		true,
-		100, 650, 801, 200,
+		1, 784, 180000, 100,
 	},
 
 	{
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE,
 		MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE),
 		true,
-		2000, 200, 576000, 2000,
+		1300, 228, 1200000, 2000,
 	},
 
 	{
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
 		MSM_RPMRS_LIMITS(ON, GDHS, MAX, ACTIVE),
 		false,
-		8500, 51, 1122000, 8500,
+		2000, 138, 1208400, 3200,
 	},
 
 	{
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
-		MSM_RPMRS_LIMITS(ON, HSFS_OPEN, MAX, ACTIVE),
-		false,
-		9000, 51, 1130300, 9000,
-	},
-	{
-		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
 		MSM_RPMRS_LIMITS(ON, HSFS_OPEN, ACTIVE, RET_HIGH),
 		false,
-		10000, 51, 1130300, 10000,
+		6000, 119, 1850300, 9000,
 	},
 
 	{
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
 		MSM_RPMRS_LIMITS(OFF, GDHS, MAX, ACTIVE),
 		false,
-		12000, 14, 2205900, 12000,
+		9200, 68, 2839200, 16400,
 	},
 
 	{
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
 		MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, MAX, ACTIVE),
 		false,
-		18000, 12, 2364250, 18000,
+		10300, 63, 3128000, 18200,
 	},
 
 	{
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
 		MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, ACTIVE, RET_HIGH),
 		false,
-		23500, 10, 2667000, 23500,
+		18000, 10, 4602600, 27000,
 	},
 
 	{
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
 		MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, RET_HIGH, RET_LOW),
 		false,
-		29700, 5, 2867000, 30000,
+		20000, 2, 5752000, 32000,
 	},
 };
 
@@ -2126,17 +2193,17 @@
 		[MSM_RPMRS_VDD_MEM_MAX]		= 1150000,
 	},
 	.vdd_dig_levels = {
-		[MSM_RPMRS_VDD_DIG_RET_LOW]	= 500000,
-		[MSM_RPMRS_VDD_DIG_RET_HIGH]	= 750000,
-		[MSM_RPMRS_VDD_DIG_ACTIVE]	= 950000,
-		[MSM_RPMRS_VDD_DIG_MAX]		= 1150000,
+		[MSM_RPMRS_VDD_DIG_RET_LOW]	= 0,
+		[MSM_RPMRS_VDD_DIG_RET_HIGH]	= 0,
+		[MSM_RPMRS_VDD_DIG_ACTIVE]	= 1,
+		[MSM_RPMRS_VDD_DIG_MAX]		= 3,
 	},
 	.vdd_mask = 0x7FFFFF,
 	.rpmrs_target_id = {
 		[MSM_RPMRS_ID_PXO_CLK]		= MSM_RPM_ID_PXO_CLK,
 		[MSM_RPMRS_ID_L2_CACHE_CTL]	= MSM_RPM_ID_LAST,
-		[MSM_RPMRS_ID_VDD_DIG_0]	= MSM_RPM_ID_PM8038_S1_0,
-		[MSM_RPMRS_ID_VDD_DIG_1]	= MSM_RPM_ID_PM8038_S1_1,
+		[MSM_RPMRS_ID_VDD_DIG_0]	= MSM_RPM_ID_VOLTAGE_CORNER,
+		[MSM_RPMRS_ID_VDD_DIG_1]	= MSM_RPM_ID_LAST,
 		[MSM_RPMRS_ID_VDD_MEM_0]	= MSM_RPM_ID_PM8038_L24_0,
 		[MSM_RPMRS_ID_VDD_MEM_1]	= MSM_RPM_ID_PM8038_L24_1,
 		[MSM_RPMRS_ID_RPM_CTL]		= MSM_RPM_ID_RPM_CTL,
@@ -2267,6 +2334,8 @@
 	platform_device_register(&msm8930_device_rpm_regulator);
 	msm_clock_init(&msm8930_clock_init_data);
 	msm8960_device_otg.dev.platform_data = &msm_otg_pdata;
+	android_usb_pdata.swfi_latency =
+			msm_rpmrs_levels[0].latency_us;
 	msm8930_init_gpiomux();
 	msm8960_device_qup_spi_gsbi1.dev.platform_data =
 				&msm8960_qup_spi_gsbi1_pdata;
diff --git a/arch/arm/mach-msm/board-8960-camera.c b/arch/arm/mach-msm/board-8960-camera.c
index 371bb53..ad9b03d 100644
--- a/arch/arm/mach-msm/board-8960-camera.c
+++ b/arch/arm/mach-msm/board-8960-camera.c
@@ -197,6 +197,7 @@
 	.flash_sr_type = MSM_CAMERA_FLASH_SRC_EXT,
 	._fsrc.ext_driver_src.led_en = VFE_CAMIF_TIMER1_GPIO,
 	._fsrc.ext_driver_src.led_flash_en = VFE_CAMIF_TIMER2_GPIO,
+	._fsrc.ext_driver_src.flash_id = MAM_CAMERA_EXT_LED_FLASH_SC628A,
 };
 #endif
 
diff --git a/arch/arm/mach-msm/board-8960-gpiomux.c b/arch/arm/mach-msm/board-8960-gpiomux.c
index 978eb09..94cafae 100644
--- a/arch/arm/mach-msm/board-8960-gpiomux.c
+++ b/arch/arm/mach-msm/board-8960-gpiomux.c
@@ -55,6 +55,21 @@
 	.pull = GPIOMUX_PULL_NONE,
 };
 
+static struct gpiomux_setting external_vfr[] = {
+	/* Suspended state */
+	{
+		.func = GPIOMUX_FUNC_3,
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_KEEPER,
+	},
+	/* Active state */
+	{
+		.func = GPIOMUX_FUNC_3,
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_KEEPER,
+	},
+};
+
 static struct gpiomux_setting gsbi_uart = {
 	.func = GPIOMUX_FUNC_1,
 	.drv = GPIOMUX_DRV_8MA,
@@ -424,6 +439,16 @@
 	},
 };
 
+static struct msm_gpiomux_config msm8960_external_vfr_configs[] __initdata = {
+	{
+		.gpio      = 23,        /* EXTERNAL VFR */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &external_vfr[0],
+			[GPIOMUX_ACTIVE] = &external_vfr[1],
+		},
+	},
+};
+
 static struct msm_gpiomux_config msm8960_gsbi8_uart_configs[] __initdata = {
 	{
 		.gpio      = 34,        /* GSBI8 UART3 */
@@ -685,49 +710,56 @@
 	},
 };
 
-static struct msm_gpiomux_config mdm_configs[] __initdata = {
+static struct msm_gpiomux_config sglte_configs[] __initdata = {
 	/* AP2MDM_STATUS */
 	{
-		.gpio = 94,
+		.gpio = 77,
 		.settings = {
 			[GPIOMUX_SUSPENDED] = &ap2mdm_cfg,
 		}
 	},
 	/* MDM2AP_STATUS */
 	{
-		.gpio = 69,
+		.gpio = 24,
 		.settings = {
 			[GPIOMUX_SUSPENDED] = &mdm2ap_status_cfg,
 		}
 	},
 	/* MDM2AP_ERRFATAL */
 	{
-		.gpio = 70,
+		.gpio = 40,
 		.settings = {
 			[GPIOMUX_SUSPENDED] = &mdm2ap_errfatal_cfg,
 		}
 	},
 	/* AP2MDM_ERRFATAL */
 	{
-		.gpio = 95,
+		.gpio = 80,
 		.settings = {
 			[GPIOMUX_SUSPENDED] = &ap2mdm_cfg,
 		}
 	},
 	/* AP2MDM_KPDPWR_N */
 	{
-		.gpio = 81,
+		.gpio = 79,
 		.settings = {
 			[GPIOMUX_SUSPENDED] = &ap2mdm_kpdpwr_n_cfg,
 		}
 	},
-	/* AP2MDM_PMIC_RESET_N */
+	/* AP2MDM_PMIC_PWR_EN */
 	{
-		.gpio = 80,
+		.gpio = 22,
 		.settings = {
 			[GPIOMUX_SUSPENDED] = &ap2mdm_kpdpwr_n_cfg,
 		}
-	}
+	},
+	/* AP2MDM_SOFT_RESET */
+	{
+		.gpio = 78,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ap2mdm_cfg,
+		}
+	},
 };
 
 static struct msm_gpiomux_config msm8960_mdp_vsync_configs[] __initdata = {
@@ -923,13 +955,9 @@
 		msm_gpiomux_install(hap_lvl_shft_config,
 			ARRAY_SIZE(hap_lvl_shft_config));
 
-	if (PLATFORM_IS_CHARM25())
-		msm_gpiomux_install(mdm_configs,
-			ARRAY_SIZE(mdm_configs));
-
 #ifdef CONFIG_USB_EHCI_MSM_HSIC
 	if ((SOCINFO_VERSION_MAJOR(socinfo_get_version()) != 1) &&
-		(PLATFORM_IS_CHARM25() || machine_is_msm8960_liquid()))
+		machine_is_msm8960_liquid())
 		msm_gpiomux_install(msm8960_hsic_configs,
 			ARRAY_SIZE(msm8960_hsic_configs));
 
@@ -953,15 +981,24 @@
 	else
 		msm_gpiomux_install(msm8960_gsbi5_uart_configs,
 			ARRAY_SIZE(msm8960_gsbi5_uart_configs));
-	/* For 8960 Fusion 2.2 Primary IPC */
-	if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE)
+
+	if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE) {
+		/* For 8960 Fusion 2.2 Primary IPC */
 		msm_gpiomux_install(msm8960_fusion_gsbi_configs,
 			ARRAY_SIZE(msm8960_fusion_gsbi_configs));
+		/* For SGLTE 8960 Fusion External VFR */
+		msm_gpiomux_install(msm8960_external_vfr_configs,
+			ARRAY_SIZE(msm8960_external_vfr_configs));
+	}
 
 #ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
 	msm_gpiomux_install(msm8960_sdcc2_configs,
 		ARRAY_SIZE(msm8960_sdcc2_configs));
 #endif
 
+	if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE)
+		msm_gpiomux_install(sglte_configs,
+			ARRAY_SIZE(sglte_configs));
+
 	return 0;
 }
diff --git a/arch/arm/mach-msm/board-8960-regulator.c b/arch/arm/mach-msm/board-8960-regulator.c
index 3923ecf..8291cc7 100644
--- a/arch/arm/mach-msm/board-8960-regulator.c
+++ b/arch/arm/mach-msm/board-8960-regulator.c
@@ -497,11 +497,11 @@
 	 *		ID   name always_on pd min_uV   max_uV   en_t supply
 	 *	system_uA reg_ID
 	 */
-	PM8XXX_NLDO1200(L26, "8921_l26", 0, 1, 1050000, 1050000, 200, "8921_s7",
+	PM8XXX_NLDO1200(L26, "8921_l26", 0, 1, 375000, 1050000, 200, "8921_s7",
 		0, 1),
-	PM8XXX_NLDO1200(L27, "8921_l27", 0, 1, 1050000, 1050000, 200, "8921_s7",
+	PM8XXX_NLDO1200(L27, "8921_l27", 0, 1, 375000, 1050000, 200, "8921_s7",
 		0, 2),
-	PM8XXX_NLDO1200(L28, "8921_l28", 0, 1, 1050000, 1050000, 200, "8921_s7",
+	PM8XXX_NLDO1200(L28, "8921_l28", 0, 1, 375000, 1050000, 200, "8921_s7",
 		0, 3),
 	PM8XXX_LDO(L29,      "8921_l29", 0, 1, 2050000, 2100000, 200, "8921_s8",
 		0, 4),
@@ -543,7 +543,7 @@
 	RPM_LDO(L22,	 0, 1, 0, 2750000, 2750000, NULL,      0, 0),
 	RPM_LDO(L23,	 1, 1, 1, 1800000, 1800000, "8921_s8", 10000, 10000),
 	RPM_LDO(L24,	 0, 1, 1,  750000, 1150000, "8921_s1", 10000, 10000),
-	RPM_LDO(L25,	 1, 1, 0, 1225000, 1225000, "8921_s1", 10000, 10000),
+	RPM_LDO(L25,	 1, 1, 0, 1250000, 1250000, "8921_s1", 10000, 10000),
 
 	/*	ID     a_on pd ss		    supply */
 	RPM_VS(LVS1,	 0, 1, 0,		    "8921_s4"),
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index c103fa8..79af1a7 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -701,31 +701,11 @@
 static void __init reserve_cache_dump_memory(void)
 {
 #ifdef CONFIG_MSM_CACHE_DUMP
-	unsigned int spare;
-	unsigned int l1_size;
-	unsigned int l2_size;
 	unsigned int total;
-	int ret;
 
-	ret = scm_call(L1C_SERVICE_ID, L1C_BUFFER_GET_SIZE_COMMAND_ID, &spare,
-		sizeof(spare), &l1_size, sizeof(l1_size));
-
-	if (ret)
-		/* Fall back to something reasonable here */
-		l1_size = L1_BUFFER_SIZE;
-
-	ret = scm_call(L1C_SERVICE_ID, L2C_BUFFER_GET_SIZE_COMMAND_ID, &spare,
-		sizeof(spare), &l2_size, sizeof(l2_size));
-
-	if (ret)
-		/* Fall back to something reasonable here */
-		l2_size = L2_BUFFER_SIZE;
-
-	total = l1_size + l2_size;
-
+	total = msm8960_cache_dump_pdata.l1_size +
+		msm8960_cache_dump_pdata.l2_size;
 	msm8960_reserve_table[MEMTYPE_EBI1].size += total;
-	msm8960_cache_dump_pdata.l1_size = l1_size;
-	msm8960_cache_dump_pdata.l2_size = l2_size;
 #endif
 }
 
@@ -915,13 +895,13 @@
 	{
 		.name = "VDDD_CDC_D",
 		.min_uV = 1225000,
-		.max_uV = 1225000,
+		.max_uV = 1250000,
 		.optimum_uA = WCD9XXX_VDDD_CDC_D_CUR_MAX,
 	},
 	{
 		.name = "CDC_VDDA_A_1P2V",
 		.min_uV = 1225000,
-		.max_uV = 1225000,
+		.max_uV = 1250000,
 		.optimum_uA = WCD9XXX_VDDD_CDC_A_CUR_MAX,
 	},
 	},
@@ -982,13 +962,13 @@
 	{
 		.name = "VDDD_CDC_D",
 		.min_uV = 1225000,
-		.max_uV = 1225000,
+		.max_uV = 1250000,
 		.optimum_uA = WCD9XXX_VDDD_CDC_D_CUR_MAX,
 	},
 	{
 		.name = "CDC_VDDA_A_1P2V",
 		.min_uV = 1225000,
-		.max_uV = 1225000,
+		.max_uV = 1250000,
 		.optimum_uA = WCD9XXX_VDDD_CDC_A_CUR_MAX,
 	},
 	},
@@ -1298,68 +1278,11 @@
 };
 #endif
 
-#define MDM2AP_ERRFATAL			70
-#define AP2MDM_ERRFATAL			95
-#define MDM2AP_STATUS			69
-#define AP2MDM_STATUS			94
-#define AP2MDM_PMIC_RESET_N		80
-#define AP2MDM_KPDPWR_N			81
-
-static struct resource mdm_resources[] = {
-	{
-		.start	= MDM2AP_ERRFATAL,
-		.end	= MDM2AP_ERRFATAL,
-		.name	= "MDM2AP_ERRFATAL",
-		.flags	= IORESOURCE_IO,
-	},
-	{
-		.start	= AP2MDM_ERRFATAL,
-		.end	= AP2MDM_ERRFATAL,
-		.name	= "AP2MDM_ERRFATAL",
-		.flags	= IORESOURCE_IO,
-	},
-	{
-		.start	= MDM2AP_STATUS,
-		.end	= MDM2AP_STATUS,
-		.name	= "MDM2AP_STATUS",
-		.flags	= IORESOURCE_IO,
-	},
-	{
-		.start	= AP2MDM_STATUS,
-		.end	= AP2MDM_STATUS,
-		.name	= "AP2MDM_STATUS",
-		.flags	= IORESOURCE_IO,
-	},
-	{
-		.start	= AP2MDM_PMIC_RESET_N,
-		.end	= AP2MDM_PMIC_RESET_N,
-		.name	= "AP2MDM_PMIC_RESET_N",
-		.flags	= IORESOURCE_IO,
-	},
-	{
-		.start	= AP2MDM_KPDPWR_N,
-		.end	= AP2MDM_KPDPWR_N,
-		.name	= "AP2MDM_KPDPWR_N",
-		.flags	= IORESOURCE_IO,
-	},
-};
-
-static struct mdm_platform_data mdm_platform_data = {
-	.mdm_version = "2.5",
-};
-
-static struct platform_device mdm_device = {
-	.name		= "mdm2_modem",
-	.id		= -1,
-	.num_resources	= ARRAY_SIZE(mdm_resources),
-	.resource	= mdm_resources,
-	.dev		= {
-		.platform_data = &mdm_platform_data,
-	},
-};
-
-static struct platform_device *mdm_devices[] __initdata = {
-	&mdm_device,
+static struct mdm_platform_data sglte_platform_data = {
+	.mdm_version = "4.0",
+	.ramdump_delay_ms = 1000,
+	.soft_reset_inverted = 1,
+	.peripheral_platform_device = NULL,
 };
 
 #define MSM_SHARED_RAM_PHYS 0x80000000
@@ -2034,7 +1957,7 @@
 	/* T6 Object */
 	0, 0, 0, 0, 0, 0,
 	/* T38 Object */
-	12, 2, 0, 17, 1, 12, 0, 0, 0, 0,
+	12, 3, 0, 24, 5, 12, 0, 0, 0, 0,
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -2046,7 +1969,7 @@
 	/* T8 Object */
 	25, 0, 20, 20, 0, 0, 20, 50, 0, 0,
 	/* T9 Object */
-	131, 0, 0, 26, 42, 0, 32, 80, 2, 5,
+	139, 0, 0, 26, 42, 0, 32, 80, 2, 5,
 	0, 5, 5, 0, 10, 30, 10, 10, 255, 2,
 	85, 5, 10, 10, 10, 10, 135, 55, 70, 40,
 	10, 5, 0, 0, 0,
@@ -2056,13 +1979,13 @@
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	0, 0, 0, 0, 0, 0, 0, 0, 0,
 	/* T25 Object */
-	3, 0, 60, 115, 156, 99,
+	1, 0, 60, 115, 156, 99,
 	/* T27 Object */
 	0, 0, 0, 0, 0, 0, 0,
 	/* T40 Object */
 	0, 0, 0, 0, 0,
 	/* T42 Object */
-	2, 0, 255, 0, 255, 0, 0, 0, 0, 0,
+	0, 0, 255, 0, 255, 0, 0, 0, 0, 0,
 	/* T43 Object */
 	0, 0, 0, 0, 0, 0, 0, 64, 0, 8,
 	16,
@@ -2071,7 +1994,7 @@
 	/* T47 Object */
 	0, 0, 0, 0, 0, 0, 3, 64, 66, 0,
 	/* T48 Object */
-	31, 64, 64, 0, 0, 0, 0, 0, 0, 0,
+	1, 64, 64, 0, 0, 0, 0, 0, 0, 0,
 	48, 40, 0, 10, 10, 0, 0, 100, 10, 80,
 	0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
 	52, 0, 12, 0, 17, 0, 1, 0, 0, 0,
@@ -2724,62 +2647,56 @@
 		MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT,
 		MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE),
 		true,
-		100, 650, 801, 200,
+		1, 784, 180000, 100,
 	},
 
 	{
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE,
 		MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE),
 		true,
-		2000, 200, 576000, 2000,
+		1300, 228, 1200000, 2000,
 	},
 
 	{
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
 		MSM_RPMRS_LIMITS(ON, GDHS, MAX, ACTIVE),
 		false,
-		8500, 51, 1122000, 8500,
+		2000, 138, 1208400, 3200,
 	},
 
 	{
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
-		MSM_RPMRS_LIMITS(ON, HSFS_OPEN, MAX, ACTIVE),
-		false,
-		9000, 51, 1130300, 9000,
-	},
-	{
-		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
 		MSM_RPMRS_LIMITS(ON, HSFS_OPEN, ACTIVE, RET_HIGH),
 		false,
-		10000, 51, 1130300, 10000,
+		6000, 119, 1850300, 9000,
 	},
 
 	{
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
 		MSM_RPMRS_LIMITS(OFF, GDHS, MAX, ACTIVE),
 		false,
-		12000, 14, 2205900, 12000,
+		9200, 68, 2839200, 16400,
 	},
 
 	{
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
 		MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, MAX, ACTIVE),
 		false,
-		18000, 12, 2364250, 18000,
+		10300, 63, 3128000, 18200,
 	},
 
 	{
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
 		MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, ACTIVE, RET_HIGH),
 		false,
-		23500, 10, 2667000, 23500,
+		18000, 10, 4602600, 27000,
 	},
 
 	{
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
 		MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, RET_HIGH, RET_LOW),
 		false,
-		29700, 5, 2867000, 30000,
+		20000, 2, 5752000, 32000,
 	},
 };
 
@@ -2893,7 +2810,7 @@
 	if (SOCINFO_VERSION_MAJOR(version) == 1)
 		return;
 
-	if (PLATFORM_IS_CHARM25() || machine_is_msm8960_liquid())
+	if (machine_is_msm8960_liquid())
 		platform_device_register(&msm_device_hsic_host);
 #endif
 }
@@ -3167,8 +3084,10 @@
 	change_memory_power = &msm8960_change_memory_power;
 	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
 	msm_pm_init_sleep_status_data(&msm_pm_slp_sts_data);
-	if (PLATFORM_IS_CHARM25())
-		platform_add_devices(mdm_devices, ARRAY_SIZE(mdm_devices));
+	if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE) {
+		mdm_sglte_device.dev.platform_data = &sglte_platform_data;
+		platform_device_register(&mdm_sglte_device);
+	}
 }
 
 MACHINE_START(MSM8960_SIM, "QCT MSM8960 SIMULATOR")
diff --git a/arch/arm/mach-msm/board-8960.h b/arch/arm/mach-msm/board-8960.h
index 925c5b4..261055e 100644
--- a/arch/arm/mach-msm/board-8960.h
+++ b/arch/arm/mach-msm/board-8960.h
@@ -86,11 +86,6 @@
 void msm8960_set_display_params(char *prim_panel, char *ext_panel);
 void msm8960_pm8921_gpio_mpp_init(void);
 void msm8960_mdp_writeback(struct memtype_reserve *reserve_table);
-#define PLATFORM_IS_CHARM25() \
-	(machine_is_msm8960_cdp() && \
-		(socinfo_get_platform_subtype() == 1) \
-	)
-
 #define MSM_8960_GSBI4_QUP_I2C_BUS_ID 4
 #define MSM_8960_GSBI3_QUP_I2C_BUS_ID 3
 #define MSM_8960_GSBI10_QUP_I2C_BUS_ID 10
diff --git a/arch/arm/mach-msm/board-9615-gpiomux.c b/arch/arm/mach-msm/board-9615-gpiomux.c
index 0e18918..624cf5e 100644
--- a/arch/arm/mach-msm/board-9615-gpiomux.c
+++ b/arch/arm/mach-msm/board-9615-gpiomux.c
@@ -105,6 +105,20 @@
 };
 #endif
 
+static struct gpiomux_setting wlan_active_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+	.dir = GPIOMUX_OUT_LOW,
+};
+
+static struct gpiomux_setting wlan_suspend_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+	.dir = GPIOMUX_IN,
+};
+
 static struct msm_gpiomux_config msm9615_audio_codec_configs[] __initdata = {
 	{
 		.gpio = 24,
@@ -251,6 +265,7 @@
 		.gpio      = 16,	/* GSBI5 I2C QUP SCL */
 		.settings = {
 			[GPIOMUX_SUSPENDED] = &gsbi5,
+			[GPIOMUX_ACTIVE] = &gsbi5,
 		},
 	},
 	{
@@ -306,6 +321,17 @@
 };
 #endif
 
+static struct msm_gpiomux_config msm9615_wlan_configs[] __initdata = {
+	{
+		.gpio      = 21,/* WLAN_RESET_N */
+		.settings = {
+			[GPIOMUX_ACTIVE] = &wlan_active_config,
+			[GPIOMUX_SUSPENDED] = &wlan_suspend_config,
+		},
+	},
+};
+
+
 int __init msm9615_init_gpiomux(void)
 {
 	int rc;
@@ -332,6 +358,9 @@
 	msm_gpiomux_install(msm9615_audio_codec_configs,
 			ARRAY_SIZE(msm9615_audio_codec_configs));
 
+	msm_gpiomux_install(msm9615_wlan_configs,
+			ARRAY_SIZE(msm9615_wlan_configs));
+
 #ifdef CONFIG_FB_MSM_EBI2
 	msm_gpiomux_install(msm9615_ebi2_lcdc_configs,
 			ARRAY_SIZE(msm9615_ebi2_lcdc_configs));
diff --git a/arch/arm/mach-msm/board-9615-regulator.c b/arch/arm/mach-msm/board-9615-regulator.c
index 8328501..0ece37c 100644
--- a/arch/arm/mach-msm/board-9615-regulator.c
+++ b/arch/arm/mach-msm/board-9615-regulator.c
@@ -79,6 +79,10 @@
 	REGULATOR_SUPPLY("CDC_VDDA_A_1P2V",	"tabla2x-slim"),
 	REGULATOR_SUPPLY("VDDD_CDC_D",		"tabla-slim"),
 	REGULATOR_SUPPLY("VDDD_CDC_D",		"tabla2x-slim"),
+	REGULATOR_SUPPLY("VDDD_CDC_D",          "0-000d"),
+	REGULATOR_SUPPLY("CDC_VDDA_A_1P2V",     "0-000d"),
+	REGULATOR_SUPPLY("VDDD_CDC_D",		"tabla top level"),
+	REGULATOR_SUPPLY("CDC_VDDA_A_1P2V",	"tabla top level"),
 };
 VREG_CONSUMERS(S3) = {
 	REGULATOR_SUPPLY("8018_s3",		NULL),
@@ -91,6 +95,14 @@
 	REGULATOR_SUPPLY("CDC_VDDA_TX",		"tabla2x-slim"),
 	REGULATOR_SUPPLY("VDDIO_CDC",		"tabla-slim"),
 	REGULATOR_SUPPLY("VDDIO_CDC",		"tabla2x-slim"),
+	REGULATOR_SUPPLY("VDDIO_CDC",		"tabla top level"),
+	REGULATOR_SUPPLY("CDC_VDD_CP",		"tabla top level"),
+	REGULATOR_SUPPLY("CDC_VDDA_TX",		"tabla top level"),
+	REGULATOR_SUPPLY("CDC_VDDA_RX",		"tabla top level"),
+	REGULATOR_SUPPLY("VDDIO_CDC",		"0-000d"),
+	REGULATOR_SUPPLY("CDC_VDD_CP",		"0-000d"),
+	REGULATOR_SUPPLY("CDC_VDDA_TX",		"0-000d"),
+	REGULATOR_SUPPLY("CDC_VDDA_RX",		"0-000d"),
 };
 VREG_CONSUMERS(S4) = {
 	REGULATOR_SUPPLY("8018_s4",		NULL),
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index da9ce67..9ad2c5e 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -51,6 +51,7 @@
 #include "pm.h"
 #include "acpuclock.h"
 #include "pm-boot.h"
+#include <mach/gpiomux.h>
 
 #ifdef CONFIG_ION_MSM
 #define MSM_ION_AUDIO_SIZE	0xAF000
@@ -126,6 +127,103 @@
 };
 #endif
 
+struct pm8xxx_gpio_init {
+	unsigned		gpio;
+	struct pm_gpio		config;
+};
+
+struct pm8xxx_mpp_init {
+	unsigned			mpp;
+	struct pm8xxx_mpp_config_data	config;
+};
+
+#define PM8018_GPIO_INIT(_gpio, _dir, _buf, _val, _pull, _vin, _out_strength, \
+			_func, _inv, _disable) \
+{ \
+	.gpio	= PM8018_GPIO_PM_TO_SYS(_gpio), \
+	.config	= { \
+		.direction	= _dir, \
+		.output_buffer	= _buf, \
+		.output_value	= _val, \
+		.pull		= _pull, \
+		.vin_sel	= _vin, \
+		.out_strength	= _out_strength, \
+		.function	= _func, \
+		.inv_int_pol	= _inv, \
+		.disable_pin	= _disable, \
+	} \
+}
+
+#define PM8018_MPP_INIT(_mpp, _type, _level, _control) \
+{ \
+	.mpp	= PM8018_MPP_PM_TO_SYS(_mpp), \
+	.config	= { \
+		.type		= PM8XXX_MPP_TYPE_##_type, \
+		.level		= _level, \
+		.control	= PM8XXX_MPP_##_control, \
+	} \
+}
+
+#define PM8018_GPIO_DISABLE(_gpio) \
+	PM8018_GPIO_INIT(_gpio, PM_GPIO_DIR_IN, 0, 0, 0, PM8018_GPIO_VIN_S3, \
+			 0, 0, 0, 1)
+
+#define PM8018_GPIO_OUTPUT(_gpio, _val, _strength) \
+	PM8018_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+			PM_GPIO_PULL_NO, PM8018_GPIO_VIN_S3, \
+			PM_GPIO_STRENGTH_##_strength, \
+			PM_GPIO_FUNC_NORMAL, 0, 0)
+
+#define PM8018_GPIO_INPUT(_gpio, _pull) \
+	PM8018_GPIO_INIT(_gpio, PM_GPIO_DIR_IN, PM_GPIO_OUT_BUF_CMOS, 0, \
+			_pull, PM8018_GPIO_VIN_S3, \
+			PM_GPIO_STRENGTH_NO, \
+			PM_GPIO_FUNC_NORMAL, 0, 0)
+
+#define PM8018_GPIO_OUTPUT_FUNC(_gpio, _val, _func) \
+	PM8018_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+			PM_GPIO_PULL_NO, PM8018_GPIO_VIN_S3, \
+			PM_GPIO_STRENGTH_HIGH, \
+			_func, 0, 0)
+
+#define PM8018_GPIO_OUTPUT_VIN(_gpio, _val, _vin) \
+	PM8018_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+			PM_GPIO_PULL_NO, _vin, \
+			PM_GPIO_STRENGTH_HIGH, \
+			PM_GPIO_FUNC_NORMAL, 0, 0)
+
+/* Initial PM8018 GPIO configurations */
+static struct pm8xxx_gpio_init pm8018_gpios[] __initdata = {
+	PM8018_GPIO_OUTPUT(2,	0,	HIGH) /* EXT_LDO_EN_WLAN */
+};
+
+/* Initial PM8018 MPP configurations */
+static struct pm8xxx_mpp_init pm8018_mpps[] __initdata = {
+};
+
+void __init msm9615_pm8xxx_gpio_mpp_init(void)
+{
+	int i, rc;
+
+	for (i = 0; i < ARRAY_SIZE(pm8018_gpios); i++) {
+		rc = pm8xxx_gpio_config(pm8018_gpios[i].gpio,
+					&pm8018_gpios[i].config);
+		if (rc) {
+			pr_err("%s: pm8018_gpio_config: rc=%d\n", __func__, rc);
+			break;
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(pm8018_mpps); i++) {
+		rc = pm8xxx_mpp_config(pm8018_mpps[i].mpp,
+					&pm8018_mpps[i].config);
+		if (rc) {
+			pr_err("%s: pm8018_mpp_config: rc=%d\n", __func__, rc);
+			break;
+		}
+	}
+}
+
 static struct pm8xxx_adc_amux pm8018_adc_channels_data[] = {
 	{"vcoin", CHANNEL_VCOIN, CHAN_PATH_SCALING2, AMUX_RSV1,
 		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
@@ -295,6 +393,95 @@
 
 #define TABLA_INTERRUPT_BASE (NR_MSM_IRQS + NR_GPIO_IRQS)
 
+/*
+ * MDM9x15 I2S.
+ */
+static struct wcd9xxx_pdata wcd9xxx_i2c_platform_data = {
+	.irq = MSM_GPIO_TO_INT(85),
+	.irq_base = TABLA_INTERRUPT_BASE,
+	.num_irqs = NR_TABLA_IRQS,
+	.reset_gpio = 84,
+	.micbias = {
+		.ldoh_v = TABLA_LDOH_2P85_V,
+		.cfilt1_mv = 1800,
+		.cfilt2_mv = 1800,
+		.cfilt3_mv = 1800,
+		.bias1_cfilt_sel = TABLA_CFILT1_SEL,
+		.bias2_cfilt_sel = TABLA_CFILT2_SEL,
+		.bias3_cfilt_sel = TABLA_CFILT3_SEL,
+		.bias4_cfilt_sel = TABLA_CFILT3_SEL,
+	},
+	.regulator = {
+	{
+		.name = "CDC_VDD_CP",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_CP_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_RX",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_RX_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_TX",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_TX_CUR_MAX,
+	},
+	{
+		.name = "VDDIO_CDC",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_VDDIO_CDC_CUR_MAX,
+	},
+	{
+		.name = "VDDD_CDC_D",
+		.min_uV = 1225000,
+		.max_uV = 1225000,
+		.optimum_uA = WCD9XXX_VDDD_CDC_D_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_A_1P2V",
+		.min_uV = 1225000,
+		.max_uV = 1225000,
+		.optimum_uA = WCD9XXX_VDDD_CDC_A_CUR_MAX,
+	}
+	},
+};
+
+static struct i2c_board_info wcd9xxx_device_info[] __initdata = {
+	{
+		I2C_BOARD_INFO("tabla top level", TABLA_I2C_SLAVE_ADDR),
+		.platform_data = &wcd9xxx_i2c_platform_data,
+	},
+	{
+		I2C_BOARD_INFO("tabla analog", TABLA_ANALOG_I2C_SLAVE_ADDR),
+		.platform_data = &wcd9xxx_i2c_platform_data,
+	},
+	{
+		I2C_BOARD_INFO("tabla digital1", TABLA_DIGITAL1_I2C_SLAVE_ADDR),
+		.platform_data = &wcd9xxx_i2c_platform_data,
+	},
+	{
+		I2C_BOARD_INFO("tabla digital2", TABLA_DIGITAL2_I2C_SLAVE_ADDR),
+		.platform_data = &wcd9xxx_i2c_platform_data,
+	},
+};
+
+static struct i2c_registry msm9615_i2c_devices[] __initdata = {
+	{
+		I2C_SURF | I2C_FFA | I2C_FLUID,
+		MSM_9615_GSBI5_QUP_I2C_BUS_ID,
+		wcd9xxx_device_info,
+		ARRAY_SIZE(wcd9xxx_device_info),
+	},
+};
+/*
+ * MDM9x15 I2S.
+ */
+
 /* Micbias setting is based on 8660 CDP/MTP/FLUID requirement
  * 4 micbiases are used to power various analog and digital
  * microphones operating at 1800 mV. Technically, all micbiases
@@ -567,6 +754,7 @@
 	.phy_type		= SNPS_28NM_INTEGRATED_PHY,
 	.vbus_power		= msm_hsusb_vbus_power,
 	.disable_reset_on_disconnect	= true,
+	.enable_lpm_on_dev_suspend	= true,
 };
 
 static struct msm_hsic_peripheral_platform_data msm_hsic_peripheral_pdata = {
@@ -663,9 +851,7 @@
 #ifdef CONFIG_LTC4088_CHARGER
 	&msm_device_charger,
 #endif
-#ifndef CONFIG_USB_CI13XXX_MSM_HSIC
 	&msm_device_otg,
-#endif
 	&msm_device_hsic_peripheral,
 	&msm_device_gadget_peripheral,
 	&msm_device_hsusb_host,
@@ -700,6 +886,8 @@
 	&msm_stub_codec,
 	&msm_voice,
 	&msm_voip,
+	&msm_i2s_cpudai0,
+	&msm_i2s_cpudai1,
 	&msm_pcm_hostless,
 	&msm_cpudai_afe_01_rx,
 	&msm_cpudai_afe_01_tx,
@@ -728,8 +916,27 @@
 
 static void __init msm9615_i2c_init(void)
 {
+	u8 mach_mask = 0;
+	int i;
+	/* Mask is hardcoded to SURF (CDP).
+	 * works on MTP with same configuration.
+	 */
+	mach_mask = I2C_SURF;
+	if (machine_is_msm9615_cdp())
+		mach_mask = I2C_SURF;
+	else if (machine_is_msm9615_mtp())
+		mach_mask = I2C_FFA;
+	else
+		pr_err("unmatched machine ID in register_i2c_devices\n");
 	msm9615_device_qup_i2c_gsbi5.dev.platform_data =
 					&msm9615_i2c_qup_gsbi5_pdata;
+	for (i = 0; i < ARRAY_SIZE(msm9615_i2c_devices); ++i) {
+		if (msm9615_i2c_devices[i].machs & mach_mask) {
+			i2c_register_board_info(msm9615_i2c_devices[i].bus,
+						msm9615_i2c_devices[i].info,
+						msm9615_i2c_devices[i].len);
+			}
+	}
 }
 
 static void __init msm9615_reserve(void)
@@ -765,7 +972,7 @@
 		&msm_hsic_peripheral_pdata;
 	msm_device_usb_bam.dev.platform_data = &msm_usb_bam_pdata;
 	platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
-
+	msm9615_pm8xxx_gpio_mpp_init();
 	acpuclk_init(&acpuclk_9615_soc_data);
 
 	/* Ensure ar6000pm device is registered before MMC/SDC */
diff --git a/arch/arm/mach-msm/board-9615.h b/arch/arm/mach-msm/board-9615.h
index 7dd003f..80656b3 100644
--- a/arch/arm/mach-msm/board-9615.h
+++ b/arch/arm/mach-msm/board-9615.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -17,6 +17,34 @@
 #include <linux/mfd/pm8xxx/pm8018.h>
 #include <linux/regulator/gpio-regulator.h>
 
+/*
+ * MDM9x15 I2S.
+ */
+#ifdef CONFIG_I2C
+#define I2C_SURF 1
+#define I2C_FFA  (1 << 1)
+#define I2C_RUMI (1 << 2)
+#define I2C_SIM  (1 << 3)
+#define I2C_FLUID (1 << 4)
+#define I2C_LIQUID (1 << 5)
+
+struct i2c_registry {
+	u8                     machs;
+	int                    bus;
+	struct i2c_board_info *info;
+	int                    len;
+};
+#endif
+/* Tabla slave address for I2C */
+#define TABLA_I2C_SLAVE_ADDR		0x0d
+#define TABLA_ANALOG_I2C_SLAVE_ADDR	0x77
+#define TABLA_DIGITAL1_I2C_SLAVE_ADDR	0x66
+#define TABLA_DIGITAL2_I2C_SLAVE_ADDR	0x55
+#define MSM_9615_GSBI5_QUP_I2C_BUS_ID 0
+/*
+ * MDM9x15 I2S.
+ */
+
 /* Macros assume PMIC GPIOs and MPPs start at 1 */
 #define PM8018_GPIO_BASE		NR_GPIO_IRQS
 #define PM8018_GPIO_PM_TO_SYS(pm_gpio)	(pm_gpio - 1 + PM8018_GPIO_BASE)
@@ -36,7 +64,7 @@
 #define GPIO_VREG_ID_EXT_2P95V		0
 
 extern struct gpio_regulator_platform_data msm_gpio_regulator_pdata[];
-
+uint32_t msm9615_rpm_get_swfi_latency(void);
 int msm9615_init_gpiomux(void);
 void msm9615_init_mmc(void);
 void mdm9615_allocate_fb_region(void);
diff --git a/arch/arm/mach-msm/board-9625-gpiomux.c b/arch/arm/mach-msm/board-9625-gpiomux.c
new file mode 100644
index 0000000..e28c734
--- /dev/null
+++ b/arch/arm/mach-msm/board-9625-gpiomux.c
@@ -0,0 +1,53 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <mach/board.h>
+#include <mach/gpio.h>
+#include <mach/gpiomux.h>
+
+static struct gpiomux_setting gpio_uart_config = {
+	.func = GPIOMUX_FUNC_2,
+	.drv = GPIOMUX_DRV_16MA,
+	.pull = GPIOMUX_PULL_NONE,
+	.dir = GPIOMUX_OUT_HIGH,
+};
+
+static struct msm_gpiomux_config msm_blsp_configs[] __initdata = {
+	{
+		.gpio      = 45,	       /* BLSP1 UART TX */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_uart_config,
+		},
+	},
+	{
+		.gpio      = 46,	       /* BLSP1 UART RX */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_uart_config,
+		},
+	},
+};
+
+void __init msm9625_init_gpiomux(void)
+{
+	int rc;
+
+	rc = msm_gpiomux_init(NR_GPIO_IRQS);
+	if (rc) {
+		pr_err(KERN_ERR "msm9625_init_gpiomux failed %d\n", rc);
+		return;
+	}
+
+	msm_gpiomux_install(msm_blsp_configs, ARRAY_SIZE(msm_blsp_configs));
+}
diff --git a/arch/arm/mach-msm/board-9625.c b/arch/arm/mach-msm/board-9625.c
new file mode 100644
index 0000000..60dfe3c
--- /dev/null
+++ b/arch/arm/mach-msm/board-9625.c
@@ -0,0 +1,104 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/of_irq.h>
+#include <linux/memory.h>
+#include <asm/mach/map.h>
+#include <asm/hardware/gic.h>
+#include <asm/arch_timer.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <mach/socinfo.h>
+#include <mach/board.h>
+#include <mach/gpio.h>
+#include "clock.h"
+
+static struct clk_lookup msm_clocks_dummy[] = {
+	CLK_DUMMY("core_clk",   BLSP1_UART_CLK, "msm_serial_hsl.0", OFF),
+	CLK_DUMMY("iface_clk",  BLSP1_UART_CLK, "msm_serial_hsl.0", OFF),
+	CLK_DUMMY("phy_clk", NULL, "msm_otg", OFF),
+	CLK_DUMMY("core_clk", NULL, "msm_otg", OFF),
+	CLK_DUMMY("alt_core_clk", NULL, "msm_otg", OFF),
+	CLK_DUMMY("iface_clk", NULL, "msm_otg", OFF),
+	CLK_DUMMY("xo", NULL, "msm_otg", OFF),
+	CLK_DUMMY("dfab_clk",	DFAB_CLK,	NULL, 0),
+	CLK_DUMMY("dma_bam_pclk",	DMA_BAM_P_CLK,	NULL, 0),
+	CLK_DUMMY("mem_clk",	NULL,	NULL, 0),
+	CLK_DUMMY("core_clk",	NULL,	"spi_qsd.1",	OFF),
+	CLK_DUMMY("iface_clk",	NULL,	"spi_qsd.1",	OFF),
+	CLK_DUMMY("core_clk",	NULL,	"f9966000.i2c", 0),
+	CLK_DUMMY("iface_clk",	NULL,	"f9966000.i2c", 0),
+	CLK_DUMMY("core_clk",	NULL,	"fe12f000.slim",	OFF),
+};
+
+struct clock_init_data msm_dummy_clock_init_data __initdata = {
+	.table = msm_clocks_dummy,
+	.size = ARRAY_SIZE(msm_clocks_dummy),
+};
+
+static struct of_device_id irq_match[] __initdata  = {
+	{ .compatible = "qcom,msm-qgic2", .data = gic_of_init, },
+	{ .compatible = "qcom,msm-gpio", .data = msm_gpio_of_init, },
+	{}
+};
+
+static const char *msm9625_dt_match[] __initconst = {
+	"qcom,msm9625",
+	NULL
+};
+
+static struct of_dev_auxdata msm9625_auxdata_lookup[] __initdata = {
+	OF_DEV_AUXDATA("qcom,msm-lsuart-v14", 0xF991F000, \
+			"msm_serial_hsl.0", NULL),
+	{}
+};
+
+void __init msm9625_init_irq(void)
+{
+	of_irq_init(irq_match);
+}
+
+static void __init msm_dt_timer_init(void)
+{
+	arch_timer_of_register();
+}
+
+static struct sys_timer msm_dt_timer = {
+	.init = msm_dt_timer_init
+};
+
+void __init msm9625_init(void)
+{
+	if (socinfo_init() < 0)
+		pr_err("%s: socinfo_init() failed\n", __func__);
+	msm_clock_init(&msm_dummy_clock_init_data);
+	of_platform_populate(NULL, of_default_bus_match_table,
+			msm9625_auxdata_lookup, NULL);
+}
+
+DT_MACHINE_START(MSM_DT, "Qualcomm MSM (Flattened Device Tree)")
+	.map_io = msm_map_msm9625_io,
+	.init_irq = msm9625_init_irq,
+	.init_machine = msm9625_init,
+	.handle_irq = gic_handle_irq,
+	.timer = &msm_dt_timer,
+	.dt_compat = msm9625_dt_match,
+	.nr_irqs = -1,
+MACHINE_END
diff --git a/arch/arm/mach-msm/board-copper-gpiomux.c b/arch/arm/mach-msm/board-copper-gpiomux.c
index 0ea33c7..caba698 100644
--- a/arch/arm/mach-msm/board-copper-gpiomux.c
+++ b/arch/arm/mach-msm/board-copper-gpiomux.c
@@ -54,6 +54,12 @@
 	},
 };
 #endif
+static struct gpiomux_setting gpio_i2c_config = {
+	.func = GPIOMUX_FUNC_3,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
 
 static struct msm_gpiomux_config msm_blsp_configs[] __initdata = {
 #if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
@@ -83,6 +89,18 @@
 	},
 #endif
 	{
+		.gpio      = 83,		/* BLSP11 QUP I2C_DAT */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+		},
+	},
+	{
+		.gpio      = 84,		/* BLSP11 QUP I2C_CLK */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+		},
+	},
+	{
 		.gpio      = 45,	       /* BLSP8 UART TX */
 		.settings = {
 			[GPIOMUX_SUSPENDED] = &gpio_uart_config,
diff --git a/arch/arm/mach-msm/board-copper.c b/arch/arm/mach-msm/board-copper.c
index eb06b81..53de3b2 100644
--- a/arch/arm/mach-msm/board-copper.c
+++ b/arch/arm/mach-msm/board-copper.c
@@ -39,6 +39,8 @@
 #endif
 #include <mach/msm_memtypes.h>
 #include <mach/msm_smd.h>
+#include <mach/rpm-smd.h>
+#include <mach/rpm-regulator-smd.h>
 #include <mach/qpnp-int.h>
 #include <mach/socinfo.h>
 #include "clock.h"
@@ -390,6 +392,23 @@
 	.id	= -1,
 };
 
+#define SHARED_IMEM_TZ_BASE 0xFE805720
+static struct resource copper_tzlog_resources[] = {
+	{
+		.start = SHARED_IMEM_TZ_BASE,
+		.end = SHARED_IMEM_TZ_BASE + SZ_4K - 1,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+struct platform_device copper_device_tz_log = {
+	.name		= "tz_log",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(copper_tzlog_resources),
+	.resource	= copper_tzlog_resources,
+};
+
+
 void __init msm_copper_add_devices(void)
 {
 #ifdef CONFIG_ION_MSM
@@ -399,6 +418,7 @@
 	platform_device_register(&android_usb_device);
 	platform_add_devices(msm_copper_stub_regulator_devices,
 					msm_copper_stub_regulator_devices_len);
+	platform_device_register(&copper_device_tz_log);
 }
 
 /*
@@ -410,6 +430,8 @@
 void __init msm_copper_add_drivers(void)
 {
 	msm_smd_init();
+	msm_rpm_driver_init();
+	rpm_regulator_smd_driver_init();
 	msm_spm_device_init();
 	regulator_stub_init();
 }
@@ -463,14 +485,22 @@
 			"spi_qsd.1", NULL),
 	OF_DEV_AUXDATA("qcom,spmi-pmic-arb", 0xFC4C0000, \
 			"spmi-pmic-arb.0", NULL),
-	OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF980B000, \
+	OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF9824000, \
 			"msm_sdcc.1", NULL),
-	OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF984B000, \
+	OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF98A4000, \
+			"msm_sdcc.2", NULL),
+	OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF9864000, \
 			"msm_sdcc.3", NULL),
+	OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF98E4000, \
+			"msm_sdcc.4", NULL),
 	OF_DEV_AUXDATA("qcom,pil-q6v5-lpass",   0xFE200000, \
 			"pil-q6v5-lpass", NULL),
+	OF_DEV_AUXDATA("qcom,pil-q6v5-mss", 0xFC880000, "pil-q6v5-mss", NULL),
+	OF_DEV_AUXDATA("qcom,pil-mba",     0xFC820000, "pil-mba", NULL),
 	OF_DEV_AUXDATA("qcom,pil-pronto", 0xFB21B000, \
 			"pil_pronto", NULL),
+	OF_DEV_AUXDATA("qcom,msm-rng", 0xF9BFF000, \
+			"msm_rng", NULL),
 	{}
 };
 
diff --git a/arch/arm/mach-msm/board-msm7627a-bt.c b/arch/arm/mach-msm/board-msm7627a-bt.c
index 75d5f15..4567c76 100644
--- a/arch/arm/mach-msm/board-msm7627a-bt.c
+++ b/arch/arm/mach-msm/board-msm7627a-bt.c
@@ -627,13 +627,16 @@
 
 	for (i = 0; i < ARRAY_SIZE(bt_vregs); i++) {
 		if (IS_ERR_OR_NULL(bt_vregs[i].reg)) {
-			rc = bt_vregs[i].reg ?
-				PTR_ERR(bt_vregs[i].reg) :
-				-ENODEV;
-			dev_err(&msm_bt_power_device.dev,
-				"%s: invalid regulator handle for %s: %d\n",
+			bt_vregs[i].reg =
+				regulator_get(&msm_bt_power_device.dev,
+						bt_vregs[i].name);
+			if (IS_ERR(bt_vregs[i].reg)) {
+				rc = PTR_ERR(bt_vregs[i].reg);
+				dev_err(&msm_bt_power_device.dev,
+					"%s: could not get regulator %s: %d\n",
 					__func__, bt_vregs[i].name, rc);
-			goto reg_disable;
+				goto reg_disable;
+			}
 		}
 
 		rc = on ? regulator_set_voltage(bt_vregs[i].reg,
@@ -687,6 +690,7 @@
 			i--;
 			regulator_disable(bt_vregs[i].reg);
 			regulator_put(bt_vregs[i].reg);
+			bt_vregs[i].reg = NULL;
 		}
 	}
 	return rc;
diff --git a/arch/arm/mach-msm/board-msm7627a-camera.c b/arch/arm/mach-msm/board-msm7627a-camera.c
index c069aab..251c97a 100644
--- a/arch/arm/mach-msm/board-msm7627a-camera.c
+++ b/arch/arm/mach-msm/board-msm7627a-camera.c
@@ -75,7 +75,7 @@
 	.gpio_no_mux = 1,
 };
 
-#ifdef CONFIG_WEBCAM_OV7692_QRD
+#ifdef CONFIG_OV7692
 static struct gpio ov7692_cam_req_gpio[] = {
 	{GPIO_SKU1_CAM_VGA_SHDN, GPIOF_DIR_OUT, "CAM_VGA_SHDN"},
 	{GPIO_SKU1_CAM_VGA_RESET_N, GPIOF_DIR_OUT, "CAM_VGA_RESET"},
@@ -194,7 +194,7 @@
 };
 #endif
 
-#ifdef CONFIG_WEBCAM_OV7692_QRD
+#ifdef CONFIG_OV7692
 static struct msm_camera_sensor_platform_info sensor_board_info_ov7692 = {
 	.mount_angle = 90,
 	.cam_vreg = msm_cam_vreg,
diff --git a/arch/arm/mach-msm/board-msm7627a-io.c b/arch/arm/mach-msm/board-msm7627a-io.c
index bfd9379..23df1cf 100644
--- a/arch/arm/mach-msm/board-msm7627a-io.c
+++ b/arch/arm/mach-msm/board-msm7627a-io.c
@@ -125,6 +125,11 @@
 	KEY_VOLUMEDOWN,
 };
 
+static const unsigned short keymap_8625_evt[] = {
+	KEY_VOLUMEDOWN,
+	KEY_VOLUMEUP,
+};
+
 static struct gpio_event_matrix_info kp_matrix_info_8625 = {
 	.info.func      = gpio_event_matrix_func,
 	.keymap         = keymap_8625,
@@ -853,7 +858,11 @@
 #endif
 
 	/* keypad */
-	if (machine_is_msm7627a_evb() || machine_is_msm8625_evb())
+	if (machine_is_msm8625_evt())
+		kp_matrix_info_8625.keymap = keymap_8625_evt;
+
+	if (machine_is_msm7627a_evb() || machine_is_msm8625_evb() ||
+			machine_is_msm8625_evt())
 		platform_device_register(&kp_pdev_8625);
 	else if (machine_is_msm7627a_qrd3() || machine_is_msm8625_qrd7())
 		platform_device_register(&kp_pdev_sku3);
diff --git a/arch/arm/mach-msm/board-msm7x27a.c b/arch/arm/mach-msm/board-msm7x27a.c
index 803550a..951fadc 100644
--- a/arch/arm/mach-msm/board-msm7x27a.c
+++ b/arch/arm/mach-msm/board-msm7x27a.c
@@ -635,8 +635,9 @@
 static u32 msm_calculate_batt_capacity(u32 current_voltage);
 
 static struct msm_psy_batt_pdata msm_psy_batt_data = {
-	.voltage_min_design     = 2800,
-	.voltage_max_design     = 4300,
+	.voltage_min_design     = 3200,
+	.voltage_max_design     = 4200,
+	.voltage_fail_safe      = 3340,
 	.avail_chg_sources      = AC_CHG | USB_CHG ,
 	.batt_technology        = POWER_SUPPLY_TECHNOLOGY_LION,
 	.calculate_capacity     = &msm_calculate_batt_capacity,
@@ -760,9 +761,9 @@
 static void msm7x27a_cfg_uart2dm_serial(void) { }
 #endif
 
-struct fmem_platform_data fmem_pdata;
+static struct fmem_platform_data fmem_pdata;
 
-struct platform_device fmem_device = {
+static struct platform_device fmem_device = {
 	.name = "fmem",
 	.id = 1,
 	.dev = { .platform_data = &fmem_pdata },
diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c
index 7fa4968..4ec9743 100644
--- a/arch/arm/mach-msm/board-msm7x30.c
+++ b/arch/arm/mach-msm/board-msm7x30.c
@@ -95,15 +95,31 @@
 
 #define MSM_PMEM_SF_SIZE	0x1700000
 #ifdef CONFIG_FB_MSM_TRIPLE_BUFFER
-#define MSM_FB_SIZE            0x780000
+#define MSM_FB_PRIM_BUF_SIZE   (864 * 480 * 4 * 3) /* 4bpp * 3 Pages */
 #else
-#define MSM_FB_SIZE            0x500000
+#define MSM_FB_PRIM_BUF_SIZE   (864 * 480 * 4 * 2) /* 4bpp * 2 Pages */
 #endif
 /*
  * Reserve space for double buffered full screen
  * res V4L2 video overlay - i.e. 1280x720x1.5x2
  */
 #define MSM_V4L2_VIDEO_OVERLAY_BUF_SIZE 2764800
+
+#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
+#define MSM_FB_EXT_BUF_SIZE (1280 * 720 * 2 * 1) /* 2 bpp x 1 page */
+#else
+#define MSM_FB_EXT_BUF_SIZE    0
+#endif
+
+#ifdef CONFIG_FB_MSM_OVERLAY0_WRITEBACK
+/* width x height x 3 bpp x 2 frame buffer */
+#define MSM_FB_OVERLAY0_WRITEBACK_SIZE roundup((864 * 480 * 3 * 2), 4096)
+#else
+#define MSM_FB_OVERLAY0_WRITEBACK_SIZE  0
+#endif
+
+#define MSM_FB_SIZE roundup(MSM_FB_PRIM_BUF_SIZE + MSM_FB_EXT_BUF_SIZE, 4096)
+
 #define MSM_PMEM_ADSP_SIZE      0x1E00000
 #define MSM_FLUID_PMEM_ADSP_SIZE	0x2800000
 #define PMEM_KERNEL_EBI0_SIZE   0x600000
@@ -4533,6 +4549,7 @@
 	.mdp_core_clk_table = mdp_core_clk_rate_table,
 	.num_mdp_clk = ARRAY_SIZE(mdp_core_clk_rate_table),
 	.mdp_rev = MDP_REV_40,
+	.mem_hid = MEMTYPE_EBI0,
 };
 
 static int lcd_panel_spi_gpio_num[] = {
@@ -7095,7 +7112,7 @@
 }
 early_param("pmem_sf_size", pmem_sf_size_setup);
 
-static unsigned fb_size = MSM_FB_SIZE;
+static unsigned fb_size;
 static int __init fb_size_setup(char *p)
 {
 	fb_size = memparse(p, NULL);
@@ -7176,10 +7193,17 @@
 #endif
 }
 
+static void __init reserve_mdp_memory(void)
+{
+	mdp_pdata.ov0_wb_size = MSM_FB_OVERLAY0_WRITEBACK_SIZE;
+	msm7x30_reserve_table[mdp_pdata.mem_hid].size += mdp_pdata.ov0_wb_size;
+}
+
 static void __init msm7x30_calculate_reserve_sizes(void)
 {
 	size_pmem_devices();
 	reserve_pmem_memory();
+	reserve_mdp_memory();
 }
 
 static int msm7x30_paddr_to_memtype(unsigned int paddr)
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index b0799c2..c6e20ca 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -106,6 +106,7 @@
 
 #include <linux/ion.h>
 #include <mach/ion.h>
+#include <mach/msm_rtb.h>
 
 #define MSM_SHARED_RAM_PHYS 0x40000000
 #define MDM2AP_SYNC 129
@@ -2639,17 +2640,29 @@
 #define MSM_SMI_SIZE          0x4000000
 
 #define KERNEL_SMI_BASE       (MSM_SMI_BASE)
+#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
+#define KERNEL_SMI_SIZE       0x000000
+#else
 #define KERNEL_SMI_SIZE       0x600000
+#endif
 
 #define USER_SMI_BASE         (KERNEL_SMI_BASE + KERNEL_SMI_SIZE)
 #define USER_SMI_SIZE         (MSM_SMI_SIZE - KERNEL_SMI_SIZE)
 #define MSM_PMEM_SMIPOOL_SIZE USER_SMI_SIZE
 
+#define MSM_ION_HOLE_SIZE	SZ_128K /* (128KB) */
+#define MSM_MM_FW_SIZE		(0x200000 - MSM_ION_HOLE_SIZE) /*(2MB-128KB)*/
+#define MSM_ION_MM_SIZE		0x3800000  /* (56MB) */
+#define MSM_ION_MFC_SIZE	SZ_8K
+
+#define MSM_MM_FW_BASE		MSM_SMI_BASE
+#define MSM_ION_HOLE_BASE	(MSM_MM_FW_BASE + MSM_MM_FW_SIZE)
+#define MSM_ION_MM_BASE		(MSM_ION_HOLE_BASE + MSM_ION_HOLE_SIZE)
+#define MSM_ION_MFC_BASE	(MSM_ION_MM_BASE + MSM_ION_MM_SIZE)
+
 #define MSM_ION_SF_SIZE		0x4000000 /* 64MB */
 #define MSM_ION_CAMERA_SIZE     MSM_PMEM_ADSP_SIZE
-#define MSM_ION_MM_FW_SIZE	0x200000 /* (2MB) */
-#define MSM_ION_MM_SIZE		0x3600000 /* (54MB) Must be a multiple of 64K */
-#define MSM_ION_MFC_SIZE	SZ_8K
+
 #ifdef CONFIG_FB_MSM_OVERLAY1_WRITEBACK
 #define MSM_ION_WB_SIZE		0xC00000 /* 12MB */
 #else
@@ -4856,6 +4869,29 @@
 	},
 };
 
+static struct msm_rtb_platform_data msm_rtb_pdata = {
+	.size = SZ_1M,
+};
+
+static int __init msm_rtb_set_buffer_size(char *p)
+{
+	int s;
+
+	s = memparse(p, NULL);
+	msm_rtb_pdata.size = ALIGN(s, SZ_4K);
+	return 0;
+}
+early_param("msm_rtb_size", msm_rtb_set_buffer_size);
+
+
+static struct platform_device msm_rtb_device = {
+	.name           = "msm_rtb",
+	.id             = -1,
+	.dev            = {
+		.platform_data = &msm_rtb_pdata,
+	},
+};
+
 static void pmic8058_xoadc_mpp_config(void)
 {
 	int rc, i;
@@ -5257,7 +5293,7 @@
 #endif
 	&msm8660_device_watchdog,
 	&msm_device_tz_log,
-
+	&msm_rtb_device,
 };
 
 #ifdef CONFIG_ION_MSM
@@ -5268,6 +5304,8 @@
 	.request_region = request_smi_region,
 	.release_region = release_smi_region,
 	.setup_region = setup_smi_region,
+	.secure_base = MSM_ION_HOLE_BASE,
+	.secure_size = MSM_ION_HOLE_SIZE + MSM_ION_MM_SIZE,
 	.iommu_map_all = 1,
 	.iommu_2x_map_domain = VIDEO_DOMAIN,
 };
@@ -5285,9 +5323,8 @@
 	.align = PAGE_SIZE,
 };
 
-static struct ion_co_heap_pdata fw_co_ion_pdata = {
+static struct ion_co_heap_pdata hole_co_ion_pdata = {
 	.adjacent_mem_id = ION_CP_MM_HEAP_ID,
-	.align = SZ_128K,
 };
 
 static struct ion_co_heap_pdata co_ion_pdata = {
@@ -5320,6 +5357,7 @@
 			.id	= ION_CP_MM_HEAP_ID,
 			.type	= ION_HEAP_TYPE_CP,
 			.name	= ION_MM_HEAP_NAME,
+			.base   = MSM_ION_MM_BASE,
 			.size	= MSM_ION_MM_SIZE,
 			.memory_type = ION_SMI_TYPE,
 			.extra_data = (void *) &cp_mm_ion_pdata,
@@ -5328,14 +5366,16 @@
 			.id	= ION_MM_FIRMWARE_HEAP_ID,
 			.type	= ION_HEAP_TYPE_CARVEOUT,
 			.name	= ION_MM_FIRMWARE_HEAP_NAME,
-			.size	= MSM_ION_MM_FW_SIZE,
+			.base	= MSM_ION_HOLE_BASE,
+			.size	= MSM_ION_HOLE_SIZE,
 			.memory_type = ION_SMI_TYPE,
-			.extra_data = (void *) &fw_co_ion_pdata,
+			.extra_data = (void *) &hole_co_ion_pdata,
 		},
 		{
 			.id	= ION_CP_MFC_HEAP_ID,
 			.type	= ION_HEAP_TYPE_CP,
 			.name	= ION_MFC_HEAP_NAME,
+			.base	= MSM_ION_MFC_BASE,
 			.size	= MSM_ION_MFC_SIZE,
 			.memory_type = ION_SMI_TYPE,
 			.extra_data = (void *) &cp_mfc_ion_pdata,
@@ -5404,12 +5444,7 @@
 		.size	=	KERNEL_SMI_SIZE,
 		.flags	=	MEMTYPE_FLAGS_FIXED,
 	},
-	/* User space SMI memory pool for video core */
-	/* used for encoder, decoder input & output buffers  */
 	[MEMTYPE_SMI] = {
-		.start	=	USER_SMI_BASE,
-		.limit	=	USER_SMI_SIZE,
-		.flags	=	MEMTYPE_FLAGS_FIXED,
 	},
 	[MEMTYPE_EBI0] = {
 		.flags	=	MEMTYPE_FLAGS_1M_ALIGN,
@@ -5454,9 +5489,6 @@
 	}
 
 	msm8x60_reserve_table[MEMTYPE_EBI1].size += msm_ion_sf_size;
-	msm8x60_reserve_table[MEMTYPE_SMI].size += MSM_ION_MM_FW_SIZE;
-	msm8x60_reserve_table[MEMTYPE_SMI].size += MSM_ION_MM_SIZE;
-	msm8x60_reserve_table[MEMTYPE_SMI].size += MSM_ION_MFC_SIZE;
 	msm8x60_reserve_table[MEMTYPE_EBI1].size += MSM_ION_CAMERA_SIZE;
 	msm8x60_reserve_table[MEMTYPE_EBI1].size += MSM_ION_WB_SIZE;
 	msm8x60_reserve_table[MEMTYPE_EBI1].size += MSM_ION_AUDIO_SIZE;
@@ -5503,12 +5535,20 @@
 
 static void __init reserve_mdp_memory(void);
 
+static void __init reserve_rtb_memory(void)
+{
+#if defined(CONFIG_MSM_RTB)
+	msm8x60_reserve_table[MEMTYPE_EBI1].size += msm_rtb_pdata.size;
+#endif
+}
+
 static void __init msm8x60_calculate_reserve_sizes(void)
 {
 	size_pmem_devices();
 	reserve_pmem_memory();
 	reserve_ion_memory();
 	reserve_mdp_memory();
+	reserve_rtb_memory();
 }
 
 static int msm8x60_paddr_to_memtype(unsigned int paddr)
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
index f565075..b7b2bf5 100644
--- a/arch/arm/mach-msm/board-qrd7627a.c
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -31,6 +31,7 @@
 #include <linux/memblock.h>
 #include <linux/input/ft5x06_ts.h>
 #include <linux/msm_adc.h>
+#include <linux/fmem.h>
 #include <asm/mach/mmc.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -382,6 +383,9 @@
 	.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
 	.cached = 1,
 	.memory_type = MEMTYPE_EBI1,
+	.request_region = request_fmem_c_region,
+	.release_region = release_fmem_c_region,
+	.reusable = 1,
 };
 
 static struct platform_device android_pmem_adsp_device = {
@@ -578,8 +582,9 @@
 static u32 msm_calculate_batt_capacity(u32 current_voltage);
 
 static struct msm_psy_batt_pdata msm_psy_batt_data = {
-	.voltage_min_design     = 2800,
-	.voltage_max_design     = 4300,
+	.voltage_min_design     = 3200,
+	.voltage_max_design     = 4200,
+	.voltage_fail_safe      = 3340,
 	.avail_chg_sources      = AC_CHG | USB_CHG ,
 	.batt_technology        = POWER_SUPPLY_TECHNOLOGY_LION,
 	.calculate_capacity     = &msm_calculate_batt_capacity,
@@ -618,6 +623,14 @@
 	},
 };
 
+static struct fmem_platform_data fmem_pdata;
+
+static struct platform_device fmem_device = {
+	.name = "fmem",
+	.id = 1,
+	.dev = { .platform_data = &fmem_pdata },
+};
+
 static struct platform_device *common_devices[] __initdata = {
 	&android_usb_device,
 	&android_pmem_device,
@@ -630,6 +643,7 @@
 	&asoc_msm_dai0,
 	&asoc_msm_dai1,
 	&msm_adc_device,
+	&fmem_device,
 };
 
 static struct platform_device *qrd7627a_devices[] __initdata = {
@@ -687,12 +701,44 @@
 	},
 };
 
+#ifdef CONFIG_ANDROID_PMEM
+static struct android_pmem_platform_data *pmem_pdata_array[] __initdata = {
+		&android_pmem_adsp_pdata,
+		&android_pmem_audio_pdata,
+		&android_pmem_pdata,
+};
+#endif
+
 static void __init size_pmem_devices(void)
 {
 #ifdef CONFIG_ANDROID_PMEM
+	unsigned int i;
+	unsigned int reusable_count = 0;
+
 	android_pmem_adsp_pdata.size = pmem_adsp_size;
 	android_pmem_pdata.size = pmem_mdp_size;
 	android_pmem_audio_pdata.size = pmem_audio_size;
+
+	fmem_pdata.size = 0;
+	fmem_pdata.align = PAGE_SIZE;
+
+	/* Find pmem devices that should use FMEM (reusable) memory.
+	 */
+	for (i = 0; i < ARRAY_SIZE(pmem_pdata_array); ++i) {
+		struct android_pmem_platform_data *pdata = pmem_pdata_array[i];
+
+		if (!reusable_count && pdata->reusable)
+			fmem_pdata.size += pdata->size;
+
+		reusable_count += (pdata->reusable) ? 1 : 0;
+
+		if (pdata->reusable && reusable_count > 1) {
+			pr_err("%s: Too many PMEM devices specified as reusable. PMEM device %s was not configured as reusable.\n",
+				__func__, pdata->name);
+			pdata->reusable = 0;
+		}
+	}
+
 #endif
 }
 
@@ -704,9 +750,10 @@
 static void __init reserve_pmem_memory(void)
 {
 #ifdef CONFIG_ANDROID_PMEM
-	reserve_memory_for(&android_pmem_adsp_pdata);
-	reserve_memory_for(&android_pmem_pdata);
-	reserve_memory_for(&android_pmem_audio_pdata);
+	unsigned int i;
+	for (i = 0; i < ARRAY_SIZE(pmem_pdata_array); ++i)
+		reserve_memory_for(pmem_pdata_array[i]);
+
 	msm7627a_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size;
 #endif
 }
diff --git a/arch/arm/mach-msm/cache_erp.c b/arch/arm/mach-msm/cache_erp.c
index 97225ac..4d7ce12 100644
--- a/arch/arm/mach-msm/cache_erp.c
+++ b/arch/arm/mach-msm/cache_erp.c
@@ -35,6 +35,9 @@
 /* Print a message for everything but TLB MH events */
 #define CESR_PRINT_MASK		0x000000FF
 
+/* Log everything but TLB MH events */
+#define CESR_LOG_EVENT_MASK	0x000000FF
+
 #define L2ESR_IND_ADDR		0x204
 #define L2ESYNR0_IND_ADDR	0x208
 #define L2ESYNR1_IND_ADDR	0x209
@@ -87,6 +90,9 @@
 
 #define MODULE_NAME "msm_cache_erp"
 
+#define ERP_LOG_MAGIC_ADDR	0x748
+#define ERP_LOG_MAGIC		0x11C39893
+
 struct msm_l1_err_stats {
 	unsigned int dctpe;
 	unsigned int dcdpe;
@@ -114,6 +120,10 @@
 static int l1_erp_irq, l2_erp_irq;
 static struct proc_dir_entry *procfs_entry;
 
+#ifdef CONFIG_MSM_L1_ERR_LOG
+static struct proc_dir_entry *procfs_log_entry;
+#endif
+
 static inline unsigned int read_cesr(void)
 {
 	unsigned int cesr;
@@ -192,6 +202,48 @@
 	return len;
 }
 
+#ifdef CONFIG_MSM_L1_ERR_LOG
+static int proc_read_log(char *page, char **start, off_t off, int count,
+	int *eof, void *data)
+{
+	char *p = page;
+	int len, log_value;
+	log_value = __raw_readl(MSM_IMEM_BASE + ERP_LOG_MAGIC_ADDR) ==
+			ERP_LOG_MAGIC ? 1 : 0;
+
+	p += snprintf(p, PAGE_SIZE, "%d\n", log_value);
+
+	len = (p - page) - off;
+	if (len < 0)
+		len = 0;
+
+	*eof = (len <= count) ? 1 : 0;
+	*start = page + off;
+
+	return len;
+}
+
+static void log_cpu_event(void)
+{
+	__raw_writel(ERP_LOG_MAGIC, MSM_IMEM_BASE + ERP_LOG_MAGIC_ADDR);
+	mb();
+}
+
+static int procfs_event_log_init(void)
+{
+	procfs_log_entry = create_proc_entry("cpu/msm_erp_log", S_IRUGO, NULL);
+
+	if (!procfs_log_entry)
+		return -ENODEV;
+	procfs_log_entry->read_proc = proc_read_log;
+	return 0;
+}
+
+#else
+static inline void log_cpu_event(void) { }
+static inline int procfs_event_log_init(void) { return 0; }
+#endif
+
 static irqreturn_t msm_l1_erp_irq(int irq, void *dev_id)
 {
 	struct msm_l1_err_stats *l1_stats = dev_id;
@@ -199,6 +251,7 @@
 	unsigned int i_cesynr, d_cesynr;
 	unsigned int cpu = smp_processor_id();
 	int print_regs = cesr & CESR_PRINT_MASK;
+	int log_event = cesr & CESR_LOG_EVENT_MASK;
 
 	void *const saw_bases[] = {
 		MSM_SAW0_BASE,
@@ -271,6 +324,9 @@
 		pr_alert("D-side CESYNR = 0x%08x\n", d_cesynr);
 	}
 
+	if (log_event)
+		log_cpu_event();
+
 	/* Clear the interrupt bits we processed */
 	write_cesr(cesr);
 
@@ -459,6 +515,11 @@
 	put_online_cpus();
 
 	procfs_entry->read_proc = proc_read_status;
+
+	ret = procfs_event_log_init();
+	if (ret)
+		pr_err("Failed to create procfs node for ERP log access\n");
+
 	return 0;
 
 fail_l2:
diff --git a/arch/arm/mach-msm/clock-7x30.c b/arch/arm/mach-msm/clock-7x30.c
index f51eb5b..cc48fe7 100644
--- a/arch/arm/mach-msm/clock-7x30.c
+++ b/arch/arm/mach-msm/clock-7x30.c
@@ -221,9 +221,15 @@
 	pcom_xo_enable(PCOM_XO_TCXO, PCOM_XO_DISABLE);
 }
 
+static enum handoff xo_clk_handoff(struct clk *clk)
+{
+	return HANDOFF_ENABLED_CLK;
+}
+
 static struct clk_ops clk_ops_tcxo = {
 	.enable = tcxo_clk_enable,
 	.disable = tcxo_clk_disable,
+	.handoff = xo_clk_handoff,
 	.is_local = pcom_is_local,
 };
 
@@ -250,6 +256,7 @@
 static struct clk_ops clk_ops_lpxo = {
 	.enable = lpxo_clk_enable,
 	.disable = lpxo_clk_disable,
+	.handoff = xo_clk_handoff,
 	.is_local = pcom_is_local,
 };
 
@@ -2651,14 +2658,14 @@
 }
 #endif /* CONFIG_DEBUG_FS */
 
-static struct clk_ops measure_clk_ops = {
+static struct clk_ops clk_ops_measure = {
 	.set_parent = measure_clk_set_parent,
 	.get_rate = measure_clk_get_rate,
 };
 
 static struct clk measure_clk = {
 	.dbg_name = "measure_clk",
-	.ops = &measure_clk_ops,
+	.ops = &clk_ops_measure,
 	CLK_INIT(measure_clk),
 };
 
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 3a0b87e..79fb69f 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -42,6 +42,7 @@
 
 /* Peripheral clock registers. */
 #define ADM0_PBUS_CLK_CTL_REG			REG(0x2208)
+#define SFAB_SATA_S_HCLK_CTL_REG		REG(0x2480)
 #define CE1_HCLK_CTL_REG			REG(0x2720)
 #define CE1_CORE_CLK_CTL_REG			REG(0x2724)
 #define PRNG_CLK_NS_REG				REG(0x2E80)
@@ -108,10 +109,12 @@
 #define TSIF_REF_CLK_MD_REG			REG(0x270C)
 #define TSIF_REF_CLK_NS_REG			REG(0x2710)
 #define TSSC_CLK_CTL_REG			REG(0x2CA0)
+#define SATA_HCLK_CTL_REG			REG(0x2C00)
 #define SATA_CLK_SRC_NS_REG			REG(0x2C08)
 #define SATA_RXOOB_CLK_CTL_REG			REG(0x2C0C)
 #define SATA_PMALIVE_CLK_CTL_REG		REG(0x2C10)
 #define SATA_PHY_REF_CLK_CTL_REG		REG(0x2C14)
+#define SATA_ACLK_CTL_REG			REG(0x2C20)
 #define SATA_PHY_CFG_CLK_CTL_REG		REG(0x2C40)
 #define USB_FSn_HCLK_CTL_REG(n)			REG(0x2960+(0x20*((n)-1)))
 #define USB_FSn_RESET_REG(n)			REG(0x2974+(0x20*((n)-1)))
@@ -767,6 +770,8 @@
 	.b = {
 		.ctl_reg = MAXI_EN5_REG,
 		.en_mask = BIT(12),
+		.hwcg_reg = MAXI_EN5_REG,
+		.hwcg_mask = BIT(11),
 		.reset_reg = SW_RESET_AXI_REG,
 		.reset_mask = BIT(16),
 		.halt_reg = DBG_BUS_VEC_J_REG,
@@ -784,6 +789,8 @@
 	.b = {
 		.ctl_reg = MAXI_EN5_REG,
 		.en_mask = BIT(25),
+		.hwcg_reg = MAXI_EN5_REG,
+		.hwcg_mask = BIT(24),
 		.reset_reg = SW_RESET_AXI_REG,
 		.reset_mask = BIT(17),
 		.halt_reg = DBG_BUS_VEC_J_REG,
@@ -1173,6 +1180,8 @@
 	.b = {
 		.ctl_reg = AHB_EN3_REG,
 		.en_mask = BIT(1),
+		.hwcg_reg = AHB_EN3_REG,
+		.hwcg_mask = BIT(0),
 		.reset_reg = SW_RESET_AHB2_REG,
 		.reset_mask = BIT(2),
 		.halt_reg = DBG_BUS_VEC_J_REG,
@@ -1926,6 +1935,69 @@
 	}
 };
 
+#define F_SATA(f, s, d) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.ns_val = NS_DIVSRC(6, 3, d, 2, 0, s##_to_bb_mux), \
+	}
+
+static struct clk_freq_tbl clk_tbl_sata[] = {
+	F_SATA(        0,  gnd, 1),
+	F_SATA( 48000000, pll8, 8),
+	F_SATA(100000000, pll3, 12),
+	F_END
+};
+
+static struct rcg_clk sata_src_clk = {
+	.b = {
+		.ctl_reg = SATA_CLK_SRC_NS_REG,
+		.halt_check = NOCHECK,
+	},
+	.ns_reg = SATA_CLK_SRC_NS_REG,
+	.root_en_mask = BIT(7),
+	.ns_mask = BM(6, 0),
+	.set_rate = set_rate_nop,
+	.freq_tbl = clk_tbl_sata,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "sata_src_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 50000000, NOMINAL, 100000000),
+		CLK_INIT(sata_src_clk.c),
+	},
+};
+
+static struct branch_clk sata_rxoob_clk = {
+	.b = {
+		.ctl_reg = SATA_RXOOB_CLK_CTL_REG,
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_MSS_SMPSS_MISC_STATE_REG,
+		.halt_bit = 26,
+	},
+	.parent = &sata_src_clk.c,
+	.c = {
+		.dbg_name = "sata_rxoob_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(sata_rxoob_clk.c),
+	},
+};
+
+static struct branch_clk sata_pmalive_clk = {
+	.b = {
+		.ctl_reg = SATA_PMALIVE_CLK_CTL_REG,
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_MSS_SMPSS_MISC_STATE_REG,
+		.halt_bit = 25,
+	},
+	.parent = &sata_src_clk.c,
+	.c = {
+		.dbg_name = "sata_pmalive_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(sata_pmalive_clk.c),
+	},
+};
+
 static struct branch_clk sata_phy_ref_clk = {
 	.b = {
 		.ctl_reg = SATA_PHY_REF_CLK_CTL_REG,
@@ -1941,6 +2013,47 @@
 	},
 };
 
+static struct branch_clk sata_a_clk = {
+	.b = {
+		.ctl_reg = SATA_ACLK_CTL_REG,
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_AFAB_SFAB_STATEA_REG,
+		.halt_bit = 12,
+	},
+	.c = {
+		.dbg_name = "sata_a_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(sata_a_clk.c),
+	},
+};
+
+static struct branch_clk sata_p_clk = {
+	.b = {
+		.ctl_reg = SATA_HCLK_CTL_REG,
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_MSS_SMPSS_MISC_STATE_REG,
+		.halt_bit = 27,
+	},
+	.c = {
+		.dbg_name = "sata_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(sata_p_clk.c),
+	},
+};
+
+static struct branch_clk sfab_sata_s_p_clk = {
+	.b = {
+		.ctl_reg = SFAB_SATA_S_HCLK_CTL_REG,
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_AFAB_SFAB_STATEB_REG,
+		.halt_bit = 14,
+	},
+	.c = {
+		.dbg_name = "sfab_sata_s_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(sfab_sata_s_p_clk.c),
+	},
+};
 static struct branch_clk pcie_p_clk = {
 	.b = {
 		.ctl_reg = PCIE_HCLK_CTL_REG,
@@ -4492,6 +4605,11 @@
 static DEFINE_CLK_VOTER(ebi1_msmbus_clk, &ebi1_clk.c, LONG_MAX);
 static DEFINE_CLK_VOTER(ebi1_adm_clk, &ebi1_clk.c, 0);
 
+static DEFINE_CLK_VOTER(ebi1_acpu_a_clk, &ebi1_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(ebi1_msmbus_a_clk, &ebi1_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(afab_acpu_a_clk, &afab_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(afab_msmbus_a_clk, &afab_a_clk.c, LONG_MAX);
+
 #ifdef CONFIG_DEBUG_FS
 struct measure_sel {
 	u32 test_vector;
@@ -4550,7 +4668,11 @@
 	{ TEST_PER_LS(0x56), &gsbi7_uart_clk.c },
 	{ TEST_PER_LS(0x58), &gsbi7_qup_clk.c },
 	{ TEST_PER_LS(0x59), &gsbi8_p_clk.c },
+	{ TEST_PER_LS(0x59), &sfab_sata_s_p_clk.c },
 	{ TEST_PER_LS(0x5A), &gsbi8_uart_clk.c },
+	{ TEST_PER_LS(0x5A), &sata_p_clk.c },
+	{ TEST_PER_LS(0x5B), &sata_rxoob_clk.c },
+	{ TEST_PER_LS(0x5C), &sata_pmalive_clk.c },
 	{ TEST_PER_LS(0x5C), &gsbi8_qup_clk.c },
 	{ TEST_PER_LS(0x5D), &gsbi9_p_clk.c },
 	{ TEST_PER_LS(0x5E), &gsbi9_uart_clk.c },
@@ -4606,6 +4728,7 @@
 	{ TEST_PER_HS(0x26), &q6sw_clk },
 	{ TEST_PER_HS(0x27), &q6fw_clk },
 	{ TEST_PER_HS(0x2A), &adm0_clk.c },
+	{ TEST_PER_HS(0x31), &sata_a_clk.c },
 	{ TEST_PER_HS(0x2D), &pcie_phy_ref_clk.c },
 	{ TEST_PER_HS(0x32), &pcie_a_clk.c },
 	{ TEST_PER_HS(0x34), &ebi1_clk.c },
@@ -4882,7 +5005,7 @@
 }
 #endif /* CONFIG_DEBUG_FS */
 
-static struct clk_ops measure_clk_ops = {
+static struct clk_ops clk_ops_measure = {
 	.set_parent = measure_clk_set_parent,
 	.get_rate = measure_clk_get_rate,
 };
@@ -4890,7 +5013,7 @@
 static struct measure_clk measure_clk = {
 	.c = {
 		.dbg_name = "measure_clk",
-		.ops = &measure_clk_ops,
+		.ops = &clk_ops_measure,
 		CLK_INIT(measure_clk.c),
 	},
 	.multiplier = 1,
@@ -4912,8 +5035,25 @@
 	CLK_LOOKUP("pll4",		pll4_clk.c,	NULL),
 	CLK_LOOKUP("measure",		measure_clk.c,	"debug"),
 
+	CLK_LOOKUP("bus_clk",		afab_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		afab_a_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		cfpb_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		cfpb_a_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		dfab_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		dfab_a_clk.c,	""),
+	CLK_LOOKUP("mem_clk",		ebi1_clk.c,	""),
+	CLK_LOOKUP("mem_clk",		ebi1_a_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		mmfab_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		mmfab_a_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		mmfpb_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		mmfpb_a_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		sfab_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		sfab_a_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		sfpb_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		sfpb_a_clk.c,	""),
+
 	CLK_LOOKUP("bus_clk",		afab_clk.c,		"msm_apps_fab"),
-	CLK_LOOKUP("bus_a_clk",		afab_a_clk.c,		"msm_apps_fab"),
+	CLK_LOOKUP("bus_a_clk",		afab_msmbus_a_clk.c,	"msm_apps_fab"),
 	CLK_LOOKUP("bus_clk",		cfpb_clk.c,		"msm_cpss_fpb"),
 	CLK_LOOKUP("bus_a_clk",		cfpb_a_clk.c,		"msm_cpss_fpb"),
 	CLK_LOOKUP("bus_clk",		sfab_clk.c,		"msm_sys_fab"),
@@ -4923,7 +5063,7 @@
 	CLK_LOOKUP("bus_clk",		mmfab_clk.c,		"msm_mm_fab"),
 	CLK_LOOKUP("bus_a_clk",		mmfab_a_clk.c,		"msm_mm_fab"),
 	CLK_LOOKUP("mem_clk",		ebi1_msmbus_clk.c,	"msm_bus"),
-	CLK_LOOKUP("mem_a_clk",		ebi1_a_clk.c,		"msm_bus"),
+	CLK_LOOKUP("mem_a_clk",		ebi1_msmbus_a_clk.c,	"msm_bus"),
 	CLK_LOOKUP("dfab_clk",		dfab_msmbus_clk.c,	"msm_bus"),
 	CLK_LOOKUP("dfab_a_clk",	dfab_msmbus_a_clk.c,	"msm_bus"),
 
@@ -4967,6 +5107,12 @@
 	CLK_LOOKUP("sys_clk",		usb_fs1_sys_clk.c,	""),
 	CLK_LOOKUP("ref_clk",		sata_phy_ref_clk.c,	""),
 	CLK_LOOKUP("cfg_clk",		sata_phy_cfg_clk.c,	""),
+	CLK_LOOKUP("src_clk",		sata_src_clk.c,		""),
+	CLK_LOOKUP("core_rxoob_clk",	sata_rxoob_clk.c,	""),
+	CLK_LOOKUP("core_pmalive_clk",	sata_pmalive_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		sata_a_clk.c,		""),
+	CLK_LOOKUP("iface_clk",		sata_p_clk.c,		""),
+	CLK_LOOKUP("slave_iface_clk",	sfab_sata_s_p_clk.c,	""),
 	CLK_LOOKUP("iface_clk",		ce3_p_clk.c,		"qce.0"),
 	CLK_LOOKUP("iface_clk",		ce3_p_clk.c,		"qcrypto.0"),
 	CLK_LOOKUP("core_clk",		ce3_core_clk.c,		"qce.0"),
@@ -4992,9 +5138,9 @@
 	CLK_LOOKUP("iface_clk",		sdc2_p_clk.c,		"msm_sdcc.2"),
 	CLK_LOOKUP("iface_clk",		sdc3_p_clk.c,		"msm_sdcc.3"),
 	CLK_LOOKUP("iface_clk",		sdc4_p_clk.c,		"msm_sdcc.4"),
-	CLK_LOOKUP("iface_clk",		pcie_p_clk.c,		""),
-	CLK_LOOKUP("ref_clk",		pcie_phy_ref_clk.c,	""),
-	CLK_LOOKUP("bus_clk",		pcie_a_clk.c,		""),
+	CLK_LOOKUP("iface_clk",		pcie_p_clk.c,		"msm_pcie"),
+	CLK_LOOKUP("ref_clk",		pcie_phy_ref_clk.c,	"msm_pcie"),
+	CLK_LOOKUP("bus_clk",		pcie_a_clk.c,		"msm_pcie"),
 	CLK_LOOKUP("core_clk",		adm0_clk.c,		"msm_dmov"),
 	CLK_LOOKUP("iface_clk",		adm0_p_clk.c,		"msm_dmov"),
 	CLK_LOOKUP("iface_clk",		pmic_arb0_p_clk.c,	""),
@@ -5189,6 +5335,8 @@
 	CLK_LOOKUP("smmu_iface_clk",	smmu_p_clk.c,  "pil_vidc"),
 
 	CLK_LOOKUP("mem_clk",		ebi1_adm_clk.c, "msm_dmov"),
+	CLK_LOOKUP("mem_clk",		ebi1_acpu_a_clk.c, ""),
+	CLK_LOOKUP("bus_clk",		afab_acpu_a_clk.c, ""),
 
 	CLK_LOOKUP("l2_mclk",		l2_m_clk,     ""),
 	CLK_LOOKUP("krait0_mclk",	krait0_m_clk, ""),
@@ -5212,8 +5360,25 @@
 	CLK_LOOKUP("pll4",		pll4_clk.c,	NULL),
 	CLK_LOOKUP("measure",		measure_clk.c,	"debug"),
 
+	CLK_LOOKUP("bus_clk",		afab_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		afab_a_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		cfpb_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		cfpb_a_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		dfab_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		dfab_a_clk.c,	""),
+	CLK_LOOKUP("mem_clk",		ebi1_clk.c,	""),
+	CLK_LOOKUP("mem_clk",		ebi1_a_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		mmfab_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		mmfab_a_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		mmfpb_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		mmfpb_a_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		sfab_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		sfab_a_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		sfpb_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		sfpb_a_clk.c,	""),
+
 	CLK_LOOKUP("bus_clk",		afab_clk.c,		"msm_apps_fab"),
-	CLK_LOOKUP("bus_a_clk",		afab_a_clk.c,		"msm_apps_fab"),
+	CLK_LOOKUP("bus_a_clk",		afab_msmbus_a_clk.c,	"msm_apps_fab"),
 	CLK_LOOKUP("bus_clk",		cfpb_clk.c,		"msm_cpss_fpb"),
 	CLK_LOOKUP("bus_a_clk",		cfpb_a_clk.c,		"msm_cpss_fpb"),
 	CLK_LOOKUP("bus_clk",		sfab_clk.c,		"msm_sys_fab"),
@@ -5223,7 +5388,7 @@
 	CLK_LOOKUP("bus_clk",		mmfab_clk.c,		"msm_mm_fab"),
 	CLK_LOOKUP("bus_a_clk",		mmfab_a_clk.c,		"msm_mm_fab"),
 	CLK_LOOKUP("mem_clk",		ebi1_msmbus_clk.c,	"msm_bus"),
-	CLK_LOOKUP("mem_a_clk",		ebi1_a_clk.c,		"msm_bus"),
+	CLK_LOOKUP("mem_a_clk",		ebi1_msmbus_a_clk.c,	"msm_bus"),
 	CLK_LOOKUP("dfab_clk",		dfab_msmbus_clk.c,	"msm_bus"),
 	CLK_LOOKUP("dfab_a_clk",	dfab_msmbus_a_clk.c,	"msm_bus"),
 
@@ -5487,6 +5652,8 @@
 	CLK_LOOKUP("bus_clk",		dfab_tzcom_clk.c,	"tzcom"),
 
 	CLK_LOOKUP("mem_clk",		ebi1_adm_clk.c, "msm_dmov"),
+	CLK_LOOKUP("mem_clk",		ebi1_acpu_a_clk.c, ""),
+	CLK_LOOKUP("bus_clk",		afab_acpu_a_clk.c, ""),
 
 	CLK_LOOKUP("l2_mclk",		l2_m_clk,     ""),
 	CLK_LOOKUP("krait0_mclk",	krait0_m_clk, ""),
@@ -5509,8 +5676,25 @@
 	CLK_LOOKUP("pll4",		pll4_clk.c,	NULL),
 	CLK_LOOKUP("measure",		measure_clk.c,	"debug"),
 
+	CLK_LOOKUP("bus_clk",		afab_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		afab_a_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		cfpb_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		cfpb_a_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		dfab_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		dfab_a_clk.c,	""),
+	CLK_LOOKUP("mem_clk",		ebi1_clk.c,	""),
+	CLK_LOOKUP("mem_clk",		ebi1_a_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		mmfab_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		mmfab_a_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		mmfpb_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		mmfpb_a_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		sfab_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		sfab_a_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		sfpb_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		sfpb_a_clk.c,	""),
+
 	CLK_LOOKUP("bus_clk",		afab_clk.c,		"msm_apps_fab"),
-	CLK_LOOKUP("bus_a_clk",		afab_a_clk.c,		"msm_apps_fab"),
+	CLK_LOOKUP("bus_a_clk",		afab_msmbus_a_clk.c,	"msm_apps_fab"),
 	CLK_LOOKUP("bus_clk",		cfpb_clk.c,		"msm_cpss_fpb"),
 	CLK_LOOKUP("bus_a_clk",		cfpb_a_clk.c,		"msm_cpss_fpb"),
 	CLK_LOOKUP("bus_clk",		sfab_clk.c,		"msm_sys_fab"),
@@ -5520,7 +5704,7 @@
 	CLK_LOOKUP("bus_clk",		mmfab_clk.c,		"msm_mm_fab"),
 	CLK_LOOKUP("bus_a_clk",		mmfab_a_clk.c,		"msm_mm_fab"),
 	CLK_LOOKUP("mem_clk",		ebi1_msmbus_clk.c,	"msm_bus"),
-	CLK_LOOKUP("mem_a_clk",		ebi1_a_clk.c,		"msm_bus"),
+	CLK_LOOKUP("mem_a_clk",		ebi1_msmbus_a_clk.c,	"msm_bus"),
 	CLK_LOOKUP("dfab_clk",		dfab_msmbus_clk.c,	"msm_bus"),
 	CLK_LOOKUP("dfab_a_clk",	dfab_msmbus_a_clk.c,	"msm_bus"),
 
@@ -5761,6 +5945,8 @@
 	CLK_LOOKUP("bus_clk",		dfab_qseecom_clk.c,	"qseecom"),
 
 	CLK_LOOKUP("mem_clk",		ebi1_adm_clk.c, "msm_dmov"),
+	CLK_LOOKUP("mem_clk",		ebi1_acpu_a_clk.c, ""),
+	CLK_LOOKUP("bus_clk",		afab_acpu_a_clk.c, ""),
 
 	CLK_LOOKUP("l2_mclk",		l2_m_clk,     ""),
 	CLK_LOOKUP("krait0_mclk",	krait0_m_clk, ""),
@@ -5873,7 +6059,7 @@
 	 * the clock is halted. The sleep and wake-up delays are set to safe
 	 * values.
 	 */
-	if (cpu_is_msm8960()) {
+	if (cpu_is_msm8960() || cpu_is_apq8064()) {
 		rmwreg(0x44000000, AHB_EN_REG,  0x6C000103);
 		writel_relaxed(0x3C7097F9, AHB_EN2_REG);
 	} else {
@@ -5881,7 +6067,7 @@
 		writel_relaxed(0x000007F9, AHB_EN2_REG);
 	}
 	if (cpu_is_apq8064())
-		rmwreg(0x00000000, AHB_EN3_REG, 0x00000001);
+		rmwreg(0x00000001, AHB_EN3_REG, 0x00000001);
 
 	/* Deassert all locally-owned MM AHB resets. */
 	rmwreg(0, SW_RESET_AHB_REG, 0xFFF7DFFF);
@@ -5890,8 +6076,9 @@
 	/* Initialize MM AXI registers: Enable HW gating for all clocks that
 	 * support it. Also set FORCE_CORE_ON bits, and any sleep and wake-up
 	 * delays to safe values. */
-	if (cpu_is_msm8960() &&
-			SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 3) {
+	if ((cpu_is_msm8960() &&
+			SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 3) ||
+			cpu_is_apq8064()) {
 		rmwreg(0x0003AFF9, MAXI_EN_REG,  0x0803FFFF);
 		rmwreg(0x3A27FCFF, MAXI_EN2_REG, 0x3A3FFFFF);
 		rmwreg(0x0027FCFF, MAXI_EN4_REG, 0x017FFFFF);
@@ -5902,10 +6089,10 @@
 	}
 	rmwreg(0x0027FCFF, MAXI_EN3_REG, 0x003FFFFF);
 	if (cpu_is_apq8064())
-		rmwreg(0x009FE4FF, MAXI_EN5_REG, 0x01FFEFFF);
+		rmwreg(0x019FECFF, MAXI_EN5_REG, 0x01FFEFFF);
 	if (cpu_is_msm8930())
 		rmwreg(0x000004FF, MAXI_EN5_REG, 0x00000FFF);
-	if (cpu_is_msm8960())
+	if (cpu_is_msm8960() || cpu_is_apq8064())
 		rmwreg(0x00003C38, SAXI_EN_REG,  0x00003FFF);
 	else
 		rmwreg(0x000003C7, SAXI_EN_REG,  0x00003FFF);
@@ -5982,9 +6169,17 @@
 	if (cpu_is_msm8960() || cpu_is_apq8064())
 		rmwreg(0x2, DSI2_BYTE_NS_REG, 0x7);
 
-	/* Source the sata_phy_ref_clk from PXO */
-	if (cpu_is_apq8064())
+	/* Source the dsi1_esc_clk from the DSI1 PHY PLLs */
+	rmwreg(0x1, DSI1_ESC_NS_REG, 0x7);
+
+	/*
+	 * Source the sata_phy_ref_clk from PXO and set predivider of
+	 * sata_pmalive_clk to 1.
+	 */
+	if (cpu_is_apq8064()) {
 		rmwreg(0, SATA_PHY_REF_CLK_CTL_REG, 0x1);
+		rmwreg(0, SATA_PMALIVE_CLK_CTL_REG, 0x3);
+	}
 
 	/*
 	 * TODO: Programming below PLLs and prng_clk is temporary and
diff --git a/arch/arm/mach-msm/clock-8x60.c b/arch/arm/mach-msm/clock-8x60.c
index 8d2b37a..975587d 100644
--- a/arch/arm/mach-msm/clock-8x60.c
+++ b/arch/arm/mach-msm/clock-8x60.c
@@ -363,11 +363,22 @@
 	return false;
 }
 
+static enum handoff pll4_clk_handoff(struct clk *clk)
+{
+	struct msm_rpm_iv_pair iv = { MSM_RPM_ID_PLL_4 };
+	int rc = msm_rpm_get_status(&iv, 1);
+	if (rc < 0 || !iv.value)
+		return HANDOFF_DISABLED_CLK;
+
+	return HANDOFF_ENABLED_CLK;
+}
+
 static struct clk_ops clk_ops_pll4 = {
 	.enable = pll4_clk_enable,
 	.disable = pll4_clk_disable,
 	.get_parent = pll4_clk_get_parent,
 	.is_local = pll4_clk_is_local,
+	.handoff = pll4_clk_handoff,
 };
 
 static struct fixed_clk pll4_clk = {
@@ -3106,6 +3117,11 @@
 static DEFINE_CLK_VOTER(ebi1_msmbus_clk, &ebi1_clk.c, LONG_MAX);
 static DEFINE_CLK_VOTER(ebi1_adm0_clk,   &ebi1_clk.c, 0);
 static DEFINE_CLK_VOTER(ebi1_adm1_clk,   &ebi1_clk.c, 0);
+static DEFINE_CLK_VOTER(ebi1_acpu_a_clk,   &ebi1_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(ebi1_msmbus_a_clk, &ebi1_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(afab_acpu_a_clk,   &afab_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(afab_msmbus_a_clk, &afab_a_clk.c, LONG_MAX);
+
 static DEFINE_CLK_MEASURE(sc0_m_clk);
 static DEFINE_CLK_MEASURE(sc1_m_clk);
 static DEFINE_CLK_MEASURE(l2_m_clk);
@@ -3445,7 +3461,7 @@
 }
 #endif /* CONFIG_DEBUG_FS */
 
-static struct clk_ops measure_clk_ops = {
+static struct clk_ops clk_ops_measure = {
 	.set_parent = measure_clk_set_parent,
 	.get_rate = measure_clk_get_rate,
 };
@@ -3453,7 +3469,7 @@
 static struct measure_clk measure_clk = {
 	.c = {
 		.dbg_name = "measure_clk",
-		.ops = &measure_clk_ops,
+		.ops = &clk_ops_measure,
 		CLK_INIT(measure_clk.c),
 	},
 	.multiplier = 1,
@@ -3468,8 +3484,27 @@
 	CLK_LOOKUP("pll4",		pll4_clk.c,	"pil_qdsp6v3"),
 	CLK_LOOKUP("measure",		measure_clk.c,	"debug"),
 
+	CLK_LOOKUP("bus_clk",		afab_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		afab_a_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		cfpb_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		cfpb_a_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		dfab_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		dfab_a_clk.c,	""),
+	CLK_LOOKUP("mem_clk",		ebi1_clk.c,	""),
+	CLK_LOOKUP("mem_clk",		ebi1_a_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		mmfab_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		mmfab_a_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		mmfpb_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		mmfpb_a_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		sfab_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		sfab_a_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		sfpb_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		sfpb_a_clk.c,	""),
+	CLK_LOOKUP("mem_clk",		smi_clk.c,	""),
+	CLK_LOOKUP("mem_clk",		smi_a_clk.c,	""),
+
 	CLK_LOOKUP("bus_clk",		afab_clk.c,	"msm_apps_fab"),
-	CLK_LOOKUP("bus_a_clk",		afab_a_clk.c,	"msm_apps_fab"),
+	CLK_LOOKUP("bus_a_clk",		afab_msmbus_a_clk.c, "msm_apps_fab"),
 	CLK_LOOKUP("bus_clk",		sfab_clk.c,	"msm_sys_fab"),
 	CLK_LOOKUP("bus_a_clk",		sfab_a_clk.c,	"msm_sys_fab"),
 	CLK_LOOKUP("bus_clk",		sfpb_clk.c,	"msm_sys_fpb"),
@@ -3479,16 +3514,10 @@
 	CLK_LOOKUP("bus_clk",		cfpb_clk.c,	"msm_cpss_fpb"),
 	CLK_LOOKUP("bus_a_clk",		cfpb_a_clk.c,	"msm_cpss_fpb"),
 	CLK_LOOKUP("mem_clk",		ebi1_msmbus_clk.c, "msm_bus"),
-	CLK_LOOKUP("mem_a_clk",		ebi1_a_clk.c,	"msm_bus"),
+	CLK_LOOKUP("mem_a_clk",		ebi1_msmbus_a_clk.c, "msm_bus"),
 	CLK_LOOKUP("smi_clk",		smi_clk.c,	"msm_bus"),
 	CLK_LOOKUP("smi_a_clk",		smi_a_clk.c,	"msm_bus"),
 
-	CLK_LOOKUP("ebi1_clk",		ebi1_clk.c,	NULL),
-	CLK_LOOKUP("dfab_clk",		dfab_clk.c,	NULL),
-	CLK_LOOKUP("dfab_a_clk",	dfab_a_clk.c,	NULL),
-	CLK_LOOKUP("mmfpb_clk",		mmfpb_clk.c,	NULL),
-	CLK_LOOKUP("mmfpb_a_clk",	mmfpb_a_clk.c,	NULL),
-
 	CLK_LOOKUP("core_clk",		gp0_clk.c,		""),
 	CLK_LOOKUP("core_clk",		gp1_clk.c,		""),
 	CLK_LOOKUP("core_clk",		gp2_clk.c,		""),
@@ -3702,6 +3731,8 @@
 
 	CLK_LOOKUP("mem_clk",		ebi1_adm0_clk.c, "msm_dmov.0"),
 	CLK_LOOKUP("mem_clk",		ebi1_adm1_clk.c, "msm_dmov.1"),
+	CLK_LOOKUP("mem_clk",		ebi1_acpu_a_clk.c, ""),
+	CLK_LOOKUP("bus_clk",		afab_acpu_a_clk.c, ""),
 
 	CLK_LOOKUP("sc0_mclk",		sc0_m_clk, ""),
 	CLK_LOOKUP("sc1_mclk",		sc1_m_clk, ""),
diff --git a/arch/arm/mach-msm/clock-9615.c b/arch/arm/mach-msm/clock-9615.c
index 1fd9b4d..f7c5a6a 100644
--- a/arch/arm/mach-msm/clock-9615.c
+++ b/arch/arm/mach-msm/clock-9615.c
@@ -1338,7 +1338,11 @@
 static DEFINE_CLK_VOTER(dfab_msmbus_clk, &dfab_clk.c, 0);
 static DEFINE_CLK_VOTER(dfab_msmbus_a_clk, &dfab_a_clk.c, 0);
 static DEFINE_CLK_VOTER(ebi1_msmbus_clk, &ebi1_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(ebi1_msmbus_a_clk, &ebi1_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(ebi1_acpu_a_clk, &ebi1_a_clk.c, LONG_MAX);
 static DEFINE_CLK_VOTER(ebi1_adm_clk, &ebi1_clk.c, 0);
+static DEFINE_CLK_VOTER(sfab_msmbus_a_clk, &sfab_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(sfab_acpu_a_clk, &sfab_a_clk.c, LONG_MAX);
 
 #ifdef CONFIG_DEBUG_FS
 struct measure_sel {
@@ -1560,7 +1564,7 @@
 }
 #endif /* CONFIG_DEBUG_FS */
 
-static struct clk_ops measure_clk_ops = {
+static struct clk_ops clk_ops_measure = {
 	.set_parent = measure_clk_set_parent,
 	.get_rate = measure_clk_get_rate,
 };
@@ -1568,7 +1572,7 @@
 static struct measure_clk measure_clk = {
 	.c = {
 		.dbg_name = "measure_clk",
-		.ops = &measure_clk_ops,
+		.ops = &clk_ops_measure,
 		CLK_INIT(measure_clk.c),
 	},
 	.multiplier = 1,
@@ -1588,19 +1592,24 @@
 
 	CLK_LOOKUP("measure",	measure_clk.c,	"debug"),
 
+	CLK_LOOKUP("bus_clk",		cfpb_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		cfpb_a_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		dfab_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		dfab_a_clk.c,	""),
+	CLK_LOOKUP("mem_clk",		ebi1_clk.c,	""),
+	CLK_LOOKUP("mem_clk",		ebi1_a_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		sfab_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		sfab_a_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		sfpb_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		sfpb_a_clk.c,	""),
+
 	CLK_LOOKUP("bus_clk",		sfab_clk.c,		"msm_sys_fab"),
-	CLK_LOOKUP("bus_a_clk",		sfab_a_clk.c,		"msm_sys_fab"),
+	CLK_LOOKUP("bus_a_clk",		sfab_msmbus_a_clk.c,	"msm_sys_fab"),
 	CLK_LOOKUP("mem_clk",		ebi1_msmbus_clk.c,	"msm_bus"),
-	CLK_LOOKUP("mem_a_clk",		ebi1_a_clk.c,		"msm_bus"),
+	CLK_LOOKUP("mem_a_clk",		ebi1_msmbus_a_clk.c,	"msm_bus"),
 	CLK_LOOKUP("dfab_clk",		dfab_msmbus_clk.c,	"msm_bus"),
 	CLK_LOOKUP("dfab_a_clk",	dfab_msmbus_a_clk.c,	"msm_bus"),
 
-	CLK_LOOKUP("bus_clk",		sfpb_clk.c,	NULL),
-	CLK_LOOKUP("bus_a_clk",		sfpb_a_clk.c,	NULL),
-	CLK_LOOKUP("bus_clk",		cfpb_clk.c,	NULL),
-	CLK_LOOKUP("bus_a_clk",		cfpb_a_clk.c,	NULL),
-	CLK_LOOKUP("ebi1_clk",		ebi1_clk.c,	NULL),
-
 	CLK_LOOKUP("core_clk",		gp0_clk.c,	""),
 	CLK_LOOKUP("core_clk",		gp1_clk.c,	""),
 	CLK_LOOKUP("core_clk",		gp2_clk.c,	""),
@@ -1655,6 +1664,10 @@
 			   "msm-dai-q6.1"),
 	CLK_LOOKUP("osr_clk",		codec_i2s_mic_osr_clk.c,
 			   "msm-dai-q6.1"),
+	CLK_LOOKUP("bit_clk",		codec_i2s_spkr_bit_clk.c,
+			   "msm-dai-q6.0"),
+	CLK_LOOKUP("osr_clk",		codec_i2s_spkr_osr_clk.c,
+			   "msm-dai-q6.0"),
 	CLK_LOOKUP("bit_clk",		spare_i2s_mic_bit_clk.c,
 			   "msm-dai-q6.5"),
 	CLK_LOOKUP("osr_clk",		spare_i2s_mic_osr_clk.c,
@@ -1678,6 +1691,8 @@
 	CLK_LOOKUP("dfab_clk",		dfab_sps_clk.c,		"msm_sps"),
 	CLK_LOOKUP("bus_clk",		dfab_bam_dmux_clk.c,	"BAM_RMNT"),
 	CLK_LOOKUP("mem_clk",		ebi1_adm_clk.c, "msm_dmov"),
+	CLK_LOOKUP("mem_clk",		ebi1_acpu_a_clk.c, ""),
+	CLK_LOOKUP("bus_clk",		sfab_acpu_a_clk.c, ""),
 
 	CLK_LOOKUP("iface_clk",		ce1_p_clk.c,		"qce.0"),
 	CLK_LOOKUP("iface_clk",		ce1_p_clk.c,		"qcrypto.0"),
diff --git a/arch/arm/mach-msm/clock-copper.c b/arch/arm/mach-msm/clock-copper.c
index 03667d7..c33d486 100644
--- a/arch/arm/mach-msm/clock-copper.c
+++ b/arch/arm/mach-msm/clock-copper.c
@@ -598,9 +598,16 @@
 	return;
 }
 
+static enum handoff cxo_clk_handoff(struct clk *clk)
+{
+	/* TODO: Remove from here once the rpm xo clock is ready. */
+	return HANDOFF_ENABLED_CLK;
+}
+
 static struct clk_ops clk_ops_cxo = {
 	.enable = cxo_clk_enable,
 	.disable = cxo_clk_disable,
+	.handoff = cxo_clk_handoff,
 };
 
 static struct fixed_clk cxo_clk_src = {
@@ -1391,7 +1398,6 @@
 	.cbcr_reg = BAM_DMA_AHB_CBCR,
 	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
 	.en_mask = BIT(12),
-	.bcr_reg = BAM_DMA_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_bam_dma_ahb_clk",
@@ -1404,7 +1410,6 @@
 	.cbcr_reg = BLSP1_AHB_CBCR,
 	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
 	.en_mask = BIT(17),
-	.bcr_reg = BLSP1_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_blsp1_ahb_clk",
@@ -1417,7 +1422,6 @@
 	.cbcr_reg = BLSP1_QUP1_I2C_APPS_CBCR,
 	.parent = &cxo_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = BLSP1_QUP1_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_blsp1_qup1_i2c_apps_clk",
@@ -1429,7 +1433,6 @@
 static struct branch_clk gcc_blsp1_qup1_spi_apps_clk = {
 	.cbcr_reg = BLSP1_QUP1_SPI_APPS_CBCR,
 	.parent = &blsp1_qup1_spi_apps_clk_src.c,
-	.bcr_reg = BLSP1_QUP1_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_blsp1_qup1_spi_apps_clk",
@@ -1442,7 +1445,6 @@
 	.cbcr_reg = BLSP1_QUP2_I2C_APPS_CBCR,
 	.parent = &cxo_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = BLSP1_QUP2_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_blsp1_qup2_i2c_apps_clk",
@@ -1454,7 +1456,6 @@
 static struct branch_clk gcc_blsp1_qup2_spi_apps_clk = {
 	.cbcr_reg = BLSP1_QUP2_SPI_APPS_CBCR,
 	.parent = &blsp1_qup2_spi_apps_clk_src.c,
-	.bcr_reg = BLSP1_QUP2_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_blsp1_qup2_spi_apps_clk",
@@ -1467,7 +1468,6 @@
 	.cbcr_reg = BLSP1_QUP3_I2C_APPS_CBCR,
 	.parent = &cxo_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = BLSP1_QUP3_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_blsp1_qup3_i2c_apps_clk",
@@ -1479,7 +1479,6 @@
 static struct branch_clk gcc_blsp1_qup3_spi_apps_clk = {
 	.cbcr_reg = BLSP1_QUP3_SPI_APPS_CBCR,
 	.parent = &blsp1_qup3_spi_apps_clk_src.c,
-	.bcr_reg = BLSP1_QUP3_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_blsp1_qup3_spi_apps_clk",
@@ -1492,7 +1491,6 @@
 	.cbcr_reg = BLSP1_QUP4_I2C_APPS_CBCR,
 	.parent = &cxo_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = BLSP1_QUP4_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_blsp1_qup4_i2c_apps_clk",
@@ -1504,7 +1502,6 @@
 static struct branch_clk gcc_blsp1_qup4_spi_apps_clk = {
 	.cbcr_reg = BLSP1_QUP4_SPI_APPS_CBCR,
 	.parent = &blsp1_qup4_spi_apps_clk_src.c,
-	.bcr_reg = BLSP1_QUP4_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_blsp1_qup4_spi_apps_clk",
@@ -1517,7 +1514,6 @@
 	.cbcr_reg = BLSP1_QUP5_I2C_APPS_CBCR,
 	.parent = &cxo_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = BLSP1_QUP5_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_blsp1_qup5_i2c_apps_clk",
@@ -1529,7 +1525,6 @@
 static struct branch_clk gcc_blsp1_qup5_spi_apps_clk = {
 	.cbcr_reg = BLSP1_QUP5_SPI_APPS_CBCR,
 	.parent = &blsp1_qup5_spi_apps_clk_src.c,
-	.bcr_reg = BLSP1_QUP5_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_blsp1_qup5_spi_apps_clk",
@@ -1542,7 +1537,6 @@
 	.cbcr_reg = BLSP1_QUP6_I2C_APPS_CBCR,
 	.parent = &cxo_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = BLSP1_QUP6_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_blsp1_qup6_i2c_apps_clk",
@@ -1554,7 +1548,6 @@
 static struct branch_clk gcc_blsp1_qup6_spi_apps_clk = {
 	.cbcr_reg = BLSP1_QUP6_SPI_APPS_CBCR,
 	.parent = &blsp1_qup6_spi_apps_clk_src.c,
-	.bcr_reg = BLSP1_QUP6_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_blsp1_qup6_spi_apps_clk",
@@ -1566,7 +1559,6 @@
 static struct branch_clk gcc_blsp1_uart1_apps_clk = {
 	.cbcr_reg = BLSP1_UART1_APPS_CBCR,
 	.parent = &blsp1_uart1_apps_clk_src.c,
-	.bcr_reg = BLSP1_UART1_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_blsp1_uart1_apps_clk",
@@ -1578,7 +1570,6 @@
 static struct branch_clk gcc_blsp1_uart2_apps_clk = {
 	.cbcr_reg = BLSP1_UART2_APPS_CBCR,
 	.parent = &blsp1_uart2_apps_clk_src.c,
-	.bcr_reg = BLSP1_UART2_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_blsp1_uart2_apps_clk",
@@ -1590,7 +1581,6 @@
 static struct branch_clk gcc_blsp1_uart3_apps_clk = {
 	.cbcr_reg = BLSP1_UART3_APPS_CBCR,
 	.parent = &blsp1_uart3_apps_clk_src.c,
-	.bcr_reg = BLSP1_UART3_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_blsp1_uart3_apps_clk",
@@ -1602,7 +1592,6 @@
 static struct branch_clk gcc_blsp1_uart4_apps_clk = {
 	.cbcr_reg = BLSP1_UART4_APPS_CBCR,
 	.parent = &blsp1_uart4_apps_clk_src.c,
-	.bcr_reg = BLSP1_UART4_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_blsp1_uart4_apps_clk",
@@ -1614,7 +1603,6 @@
 static struct branch_clk gcc_blsp1_uart5_apps_clk = {
 	.cbcr_reg = BLSP1_UART5_APPS_CBCR,
 	.parent = &blsp1_uart5_apps_clk_src.c,
-	.bcr_reg = BLSP1_UART5_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_blsp1_uart5_apps_clk",
@@ -1626,7 +1614,6 @@
 static struct branch_clk gcc_blsp1_uart6_apps_clk = {
 	.cbcr_reg = BLSP1_UART6_APPS_CBCR,
 	.parent = &blsp1_uart6_apps_clk_src.c,
-	.bcr_reg = BLSP1_UART6_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_blsp1_uart6_apps_clk",
@@ -1639,7 +1626,6 @@
 	.cbcr_reg = BOOT_ROM_AHB_CBCR,
 	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
 	.en_mask = BIT(10),
-	.bcr_reg = BOOT_ROM_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_boot_rom_ahb_clk",
@@ -1652,7 +1638,6 @@
 	.cbcr_reg = BLSP2_AHB_CBCR,
 	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
 	.en_mask = BIT(15),
-	.bcr_reg = BLSP2_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_blsp2_ahb_clk",
@@ -1665,7 +1650,6 @@
 	.cbcr_reg = BLSP2_QUP1_I2C_APPS_CBCR,
 	.parent = &cxo_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = BLSP2_QUP1_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_blsp2_qup1_i2c_apps_clk",
@@ -1677,7 +1661,6 @@
 static struct branch_clk gcc_blsp2_qup1_spi_apps_clk = {
 	.cbcr_reg = BLSP2_QUP1_SPI_APPS_CBCR,
 	.parent = &blsp2_qup1_spi_apps_clk_src.c,
-	.bcr_reg = BLSP2_QUP1_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_blsp2_qup1_spi_apps_clk",
@@ -1690,7 +1673,6 @@
 	.cbcr_reg = BLSP2_QUP2_I2C_APPS_CBCR,
 	.parent = &cxo_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = BLSP2_QUP2_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_blsp2_qup2_i2c_apps_clk",
@@ -1702,7 +1684,6 @@
 static struct branch_clk gcc_blsp2_qup2_spi_apps_clk = {
 	.cbcr_reg = BLSP2_QUP2_SPI_APPS_CBCR,
 	.parent = &blsp2_qup2_spi_apps_clk_src.c,
-	.bcr_reg = BLSP2_QUP2_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_blsp2_qup2_spi_apps_clk",
@@ -1715,7 +1696,6 @@
 	.cbcr_reg = BLSP2_QUP3_I2C_APPS_CBCR,
 	.parent = &cxo_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = BLSP2_QUP3_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_blsp2_qup3_i2c_apps_clk",
@@ -1727,7 +1707,6 @@
 static struct branch_clk gcc_blsp2_qup3_spi_apps_clk = {
 	.cbcr_reg = BLSP2_QUP3_SPI_APPS_CBCR,
 	.parent = &blsp2_qup3_spi_apps_clk_src.c,
-	.bcr_reg = BLSP2_QUP3_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_blsp2_qup3_spi_apps_clk",
@@ -1740,7 +1719,6 @@
 	.cbcr_reg = BLSP2_QUP4_I2C_APPS_CBCR,
 	.parent = &cxo_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = BLSP2_QUP4_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_blsp2_qup4_i2c_apps_clk",
@@ -1752,7 +1730,6 @@
 static struct branch_clk gcc_blsp2_qup4_spi_apps_clk = {
 	.cbcr_reg = BLSP2_QUP4_SPI_APPS_CBCR,
 	.parent = &blsp2_qup4_spi_apps_clk_src.c,
-	.bcr_reg = BLSP2_QUP4_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_blsp2_qup4_spi_apps_clk",
@@ -1765,7 +1742,6 @@
 	.cbcr_reg = BLSP2_QUP5_I2C_APPS_CBCR,
 	.parent = &cxo_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = BLSP2_QUP5_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_blsp2_qup5_i2c_apps_clk",
@@ -1777,7 +1753,6 @@
 static struct branch_clk gcc_blsp2_qup5_spi_apps_clk = {
 	.cbcr_reg = BLSP2_QUP5_SPI_APPS_CBCR,
 	.parent = &blsp2_qup5_spi_apps_clk_src.c,
-	.bcr_reg = BLSP2_QUP5_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_blsp2_qup5_spi_apps_clk",
@@ -1790,7 +1765,6 @@
 	.cbcr_reg = BLSP2_QUP6_I2C_APPS_CBCR,
 	.parent = &cxo_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = BLSP2_QUP6_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_blsp2_qup6_i2c_apps_clk",
@@ -1802,7 +1776,6 @@
 static struct branch_clk gcc_blsp2_qup6_spi_apps_clk = {
 	.cbcr_reg = BLSP2_QUP6_SPI_APPS_CBCR,
 	.parent = &blsp2_qup6_spi_apps_clk_src.c,
-	.bcr_reg = BLSP2_QUP6_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_blsp2_qup6_spi_apps_clk",
@@ -1814,7 +1787,6 @@
 static struct branch_clk gcc_blsp2_uart1_apps_clk = {
 	.cbcr_reg = BLSP2_UART1_APPS_CBCR,
 	.parent = &blsp2_uart1_apps_clk_src.c,
-	.bcr_reg = BLSP2_UART1_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_blsp2_uart1_apps_clk",
@@ -1826,7 +1798,6 @@
 static struct branch_clk gcc_blsp2_uart2_apps_clk = {
 	.cbcr_reg = BLSP2_UART2_APPS_CBCR,
 	.parent = &blsp2_uart2_apps_clk_src.c,
-	.bcr_reg = BLSP2_UART2_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_blsp2_uart2_apps_clk",
@@ -1838,7 +1809,6 @@
 static struct branch_clk gcc_blsp2_uart3_apps_clk = {
 	.cbcr_reg = BLSP2_UART3_APPS_CBCR,
 	.parent = &blsp2_uart3_apps_clk_src.c,
-	.bcr_reg = BLSP2_UART3_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_blsp2_uart3_apps_clk",
@@ -1850,7 +1820,6 @@
 static struct branch_clk gcc_blsp2_uart4_apps_clk = {
 	.cbcr_reg = BLSP2_UART4_APPS_CBCR,
 	.parent = &blsp2_uart4_apps_clk_src.c,
-	.bcr_reg = BLSP2_UART4_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_blsp2_uart4_apps_clk",
@@ -1862,7 +1831,6 @@
 static struct branch_clk gcc_blsp2_uart5_apps_clk = {
 	.cbcr_reg = BLSP2_UART5_APPS_CBCR,
 	.parent = &blsp2_uart5_apps_clk_src.c,
-	.bcr_reg = BLSP2_UART5_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_blsp2_uart5_apps_clk",
@@ -1874,7 +1842,6 @@
 static struct branch_clk gcc_blsp2_uart6_apps_clk = {
 	.cbcr_reg = BLSP2_UART6_APPS_CBCR,
 	.parent = &blsp2_uart6_apps_clk_src.c,
-	.bcr_reg = BLSP2_UART6_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_blsp2_uart6_apps_clk",
@@ -1887,7 +1854,6 @@
 	.cbcr_reg = CE1_CBCR,
 	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
 	.en_mask = BIT(5),
-	.bcr_reg = CE1_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_ce1_clk",
@@ -1900,7 +1866,6 @@
 	.cbcr_reg = CE1_AHB_CBCR,
 	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
 	.en_mask = BIT(3),
-	.bcr_reg = CE1_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_ce1_ahb_clk",
@@ -1913,7 +1878,6 @@
 	.cbcr_reg = CE1_AXI_CBCR,
 	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
 	.en_mask = BIT(4),
-	.bcr_reg = CE1_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_ce1_axi_clk",
@@ -1926,7 +1890,6 @@
 	.cbcr_reg = CE2_CBCR,
 	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
 	.en_mask = BIT(2),
-	.bcr_reg = CE2_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_ce2_clk",
@@ -1939,7 +1902,6 @@
 	.cbcr_reg = CE2_AHB_CBCR,
 	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
 	.en_mask = BIT(0),
-	.bcr_reg = CE2_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_ce1_ahb_clk",
@@ -1952,7 +1914,6 @@
 	.cbcr_reg = CE2_AXI_CBCR,
 	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
 	.en_mask = BIT(1),
-	.bcr_reg = CE2_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_ce1_axi_clk",
@@ -1997,7 +1958,6 @@
 static struct branch_clk gcc_pdm2_clk = {
 	.cbcr_reg = PDM2_CBCR,
 	.parent = &pdm2_clk_src.c,
-	.bcr_reg = PDM_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_pdm2_clk",
@@ -2009,7 +1969,6 @@
 static struct branch_clk gcc_pdm_ahb_clk = {
 	.cbcr_reg = PDM_AHB_CBCR,
 	.has_sibling = 1,
-	.bcr_reg = PDM_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_pdm_ahb_clk",
@@ -2022,7 +1981,6 @@
 	.cbcr_reg = PRNG_AHB_CBCR,
 	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
 	.en_mask = BIT(13),
-	.bcr_reg = PRNG_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_prng_ahb_clk",
@@ -2034,7 +1992,6 @@
 static struct branch_clk gcc_sdcc1_ahb_clk = {
 	.cbcr_reg = SDCC1_AHB_CBCR,
 	.has_sibling = 1,
-	.bcr_reg = SDCC1_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_sdcc1_ahb_clk",
@@ -2046,7 +2003,6 @@
 static struct branch_clk gcc_sdcc1_apps_clk = {
 	.cbcr_reg = SDCC1_APPS_CBCR,
 	.parent = &sdcc1_apps_clk_src.c,
-	.bcr_reg = SDCC1_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_sdcc1_apps_clk",
@@ -2058,7 +2014,6 @@
 static struct branch_clk gcc_sdcc2_ahb_clk = {
 	.cbcr_reg = SDCC2_AHB_CBCR,
 	.has_sibling = 1,
-	.bcr_reg = SDCC2_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_sdcc2_ahb_clk",
@@ -2070,7 +2025,6 @@
 static struct branch_clk gcc_sdcc2_apps_clk = {
 	.cbcr_reg = SDCC2_APPS_CBCR,
 	.parent = &sdcc2_apps_clk_src.c,
-	.bcr_reg = SDCC2_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_sdcc2_apps_clk",
@@ -2082,7 +2036,6 @@
 static struct branch_clk gcc_sdcc3_ahb_clk = {
 	.cbcr_reg = SDCC3_AHB_CBCR,
 	.has_sibling = 1,
-	.bcr_reg = SDCC3_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_sdcc3_ahb_clk",
@@ -2094,7 +2047,6 @@
 static struct branch_clk gcc_sdcc3_apps_clk = {
 	.cbcr_reg = SDCC3_APPS_CBCR,
 	.parent = &sdcc3_apps_clk_src.c,
-	.bcr_reg = SDCC3_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_sdcc3_apps_clk",
@@ -2106,7 +2058,6 @@
 static struct branch_clk gcc_sdcc4_ahb_clk = {
 	.cbcr_reg = SDCC4_AHB_CBCR,
 	.has_sibling = 1,
-	.bcr_reg = SDCC4_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_sdcc4_ahb_clk",
@@ -2118,7 +2069,6 @@
 static struct branch_clk gcc_sdcc4_apps_clk = {
 	.cbcr_reg = SDCC4_APPS_CBCR,
 	.parent = &sdcc4_apps_clk_src.c,
-	.bcr_reg = SDCC4_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_sdcc4_apps_clk",
@@ -2130,7 +2080,6 @@
 static struct branch_clk gcc_tsif_ahb_clk = {
 	.cbcr_reg = TSIF_AHB_CBCR,
 	.has_sibling = 1,
-	.bcr_reg = TSIF_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_tsif_ahb_clk",
@@ -2142,7 +2091,6 @@
 static struct branch_clk gcc_tsif_ref_clk = {
 	.cbcr_reg = TSIF_REF_CBCR,
 	.parent = &tsif_ref_clk_src.c,
-	.bcr_reg = TSIF_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_tsif_ref_clk",
@@ -2155,7 +2103,6 @@
 	.cbcr_reg = USB30_MASTER_CBCR,
 	.parent = &usb30_master_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = USB_30_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_usb30_master_clk",
@@ -2167,7 +2114,6 @@
 static struct branch_clk gcc_usb30_mock_utmi_clk = {
 	.cbcr_reg = USB30_MOCK_UTMI_CBCR,
 	.parent = &usb30_mock_utmi_clk_src.c,
-	.bcr_reg = USB_30_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_usb30_mock_utmi_clk",
@@ -2179,7 +2125,6 @@
 static struct branch_clk gcc_usb_hs_ahb_clk = {
 	.cbcr_reg = USB_HS_AHB_CBCR,
 	.has_sibling = 1,
-	.bcr_reg = USB_HS_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_usb_hs_ahb_clk",
@@ -2191,7 +2136,6 @@
 static struct branch_clk gcc_usb_hs_system_clk = {
 	.cbcr_reg = USB_HS_SYSTEM_CBCR,
 	.parent = &usb_hs_system_clk_src.c,
-	.bcr_reg = USB_HS_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_usb_hs_system_clk",
@@ -2203,7 +2147,6 @@
 static struct branch_clk gcc_usb_hsic_ahb_clk = {
 	.cbcr_reg = USB_HSIC_AHB_CBCR,
 	.has_sibling = 1,
-	.bcr_reg = USB_HS_HSIC_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_usb_hsic_ahb_clk",
@@ -2215,7 +2158,6 @@
 static struct branch_clk gcc_usb_hsic_clk = {
 	.cbcr_reg = USB_HSIC_CBCR,
 	.parent = &usb_hsic_clk_src.c,
-	.bcr_reg = USB_HS_HSIC_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_usb_hsic_clk",
@@ -2227,7 +2169,6 @@
 static struct branch_clk gcc_usb_hsic_io_cal_clk = {
 	.cbcr_reg = USB_HSIC_IO_CAL_CBCR,
 	.parent = &usb_hsic_io_cal_clk_src.c,
-	.bcr_reg = USB_HS_HSIC_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_usb_hsic_io_cal_clk",
@@ -2239,7 +2180,6 @@
 static struct branch_clk gcc_usb_hsic_system_clk = {
 	.cbcr_reg = USB_HSIC_SYSTEM_CBCR,
 	.parent = &usb_hsic_system_clk_src.c,
-	.bcr_reg = USB_HS_HSIC_BCR,
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.dbg_name = "gcc_usb_hsic_system_clk",
@@ -2931,7 +2871,6 @@
 	.cbcr_reg = CAMSS_CCI_CCI_AHB_CBCR,
 	.parent = &ahb_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = CAMSS_CCI_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_cci_cci_ahb_clk",
@@ -2944,7 +2883,6 @@
 	.cbcr_reg = CAMSS_CCI_CCI_CBCR,
 	.parent = &cci_clk_src.c,
 	.has_sibling = 0,
-	.bcr_reg = CAMSS_CCI_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_cci_cci_clk",
@@ -2957,7 +2895,6 @@
 	.cbcr_reg = CAMSS_CSI0_AHB_CBCR,
 	.parent = &ahb_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = CAMSS_CSI0_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_csi0_ahb_clk",
@@ -2970,7 +2907,6 @@
 	.cbcr_reg = CAMSS_CSI0_CBCR,
 	.parent = &csi0_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = CAMSS_CSI0_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_csi0_clk",
@@ -2983,7 +2919,6 @@
 	.cbcr_reg = CAMSS_CSI0PHY_CBCR,
 	.parent = &csi0_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = CAMSS_CSI0PHY_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_csi0phy_clk",
@@ -2996,7 +2931,6 @@
 	.cbcr_reg = CAMSS_CSI0PIX_CBCR,
 	.parent = &csi0_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = CAMSS_CSI0PIX_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_csi0pix_clk",
@@ -3009,7 +2943,6 @@
 	.cbcr_reg = CAMSS_CSI0RDI_CBCR,
 	.parent = &csi0_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = CAMSS_CSI0RDI_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_csi0rdi_clk",
@@ -3022,7 +2955,6 @@
 	.cbcr_reg = CAMSS_CSI1_AHB_CBCR,
 	.parent = &ahb_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = CAMSS_CSI1_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_csi1_ahb_clk",
@@ -3035,7 +2967,6 @@
 	.cbcr_reg = CAMSS_CSI1_CBCR,
 	.parent = &csi1_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = CAMSS_CSI1_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_csi1_clk",
@@ -3048,7 +2979,6 @@
 	.cbcr_reg = CAMSS_CSI1PHY_CBCR,
 	.parent = &csi1_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = CAMSS_CSI1PHY_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_csi1phy_clk",
@@ -3061,7 +2991,6 @@
 	.cbcr_reg = CAMSS_CSI1PIX_CBCR,
 	.parent = &csi1_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = CAMSS_CSI1PIX_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_csi1pix_clk",
@@ -3074,7 +3003,6 @@
 	.cbcr_reg = CAMSS_CSI1RDI_CBCR,
 	.parent = &csi1_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = CAMSS_CSI1RDI_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_csi1rdi_clk",
@@ -3087,7 +3015,6 @@
 	.cbcr_reg = CAMSS_CSI2_AHB_CBCR,
 	.parent = &ahb_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = CAMSS_CSI2_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_csi2_ahb_clk",
@@ -3100,7 +3027,6 @@
 	.cbcr_reg = CAMSS_CSI2_CBCR,
 	.parent = &csi2_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = CAMSS_CSI2_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_csi2_clk",
@@ -3113,7 +3039,6 @@
 	.cbcr_reg = CAMSS_CSI2PHY_CBCR,
 	.parent = &csi2_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = CAMSS_CSI2PHY_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_csi2phy_clk",
@@ -3126,7 +3051,6 @@
 	.cbcr_reg = CAMSS_CSI2PIX_CBCR,
 	.parent = &csi2_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = CAMSS_CSI2PIX_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_csi2pix_clk",
@@ -3139,7 +3063,6 @@
 	.cbcr_reg = CAMSS_CSI2RDI_CBCR,
 	.parent = &csi2_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = CAMSS_CSI2RDI_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_csi2rdi_clk",
@@ -3152,7 +3075,6 @@
 	.cbcr_reg = CAMSS_CSI3_AHB_CBCR,
 	.parent = &ahb_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = CAMSS_CSI3_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_csi3_ahb_clk",
@@ -3165,7 +3087,6 @@
 	.cbcr_reg = CAMSS_CSI3_CBCR,
 	.parent = &csi3_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = CAMSS_CSI3_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_csi3_clk",
@@ -3178,7 +3099,6 @@
 	.cbcr_reg = CAMSS_CSI3PHY_CBCR,
 	.parent = &csi3_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = CAMSS_CSI3PHY_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_csi3phy_clk",
@@ -3191,7 +3111,6 @@
 	.cbcr_reg = CAMSS_CSI3PIX_CBCR,
 	.parent = &csi3_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = CAMSS_CSI3PIX_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_csi3pix_clk",
@@ -3204,7 +3123,6 @@
 	.cbcr_reg = CAMSS_CSI3RDI_CBCR,
 	.parent = &csi3_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = CAMSS_CSI3RDI_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_csi3rdi_clk",
@@ -3217,7 +3135,6 @@
 	.cbcr_reg = CAMSS_CSI_VFE0_CBCR,
 	.parent = &vfe0_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = CAMSS_CSI_VFE0_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_csi_vfe0_clk",
@@ -3230,7 +3147,6 @@
 	.cbcr_reg = CAMSS_CSI_VFE1_CBCR,
 	.parent = &vfe1_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = CAMSS_CSI_VFE1_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_csi_vfe1_clk",
@@ -3243,7 +3159,6 @@
 	.cbcr_reg = CAMSS_GP0_CBCR,
 	.parent = &mmss_gp0_clk_src.c,
 	.has_sibling = 0,
-	.bcr_reg = CAMSS_GP0_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_gp0_clk",
@@ -3256,7 +3171,6 @@
 	.cbcr_reg = CAMSS_GP1_CBCR,
 	.parent = &mmss_gp1_clk_src.c,
 	.has_sibling = 0,
-	.bcr_reg = CAMSS_GP1_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_gp1_clk",
@@ -3269,7 +3183,6 @@
 	.cbcr_reg = CAMSS_ISPIF_AHB_CBCR,
 	.parent = &ahb_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = CAMSS_ISPIF_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_ispif_ahb_clk",
@@ -3282,7 +3195,6 @@
 	.cbcr_reg = CAMSS_JPEG_JPEG0_CBCR,
 	.parent = &jpeg0_clk_src.c,
 	.has_sibling = 0,
-	.bcr_reg = CAMSS_JPEG_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_jpeg_jpeg0_clk",
@@ -3295,7 +3207,6 @@
 	.cbcr_reg = CAMSS_JPEG_JPEG1_CBCR,
 	.parent = &jpeg1_clk_src.c,
 	.has_sibling = 0,
-	.bcr_reg = CAMSS_JPEG_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_jpeg_jpeg1_clk",
@@ -3308,7 +3219,6 @@
 	.cbcr_reg = CAMSS_JPEG_JPEG2_CBCR,
 	.parent = &jpeg2_clk_src.c,
 	.has_sibling = 0,
-	.bcr_reg = CAMSS_JPEG_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_jpeg_jpeg2_clk",
@@ -3321,7 +3231,6 @@
 	.cbcr_reg = CAMSS_JPEG_JPEG_AHB_CBCR,
 	.parent = &ahb_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = CAMSS_JPEG_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_jpeg_jpeg_ahb_clk",
@@ -3334,7 +3243,6 @@
 	.cbcr_reg = CAMSS_JPEG_JPEG_AXI_CBCR,
 	.parent = &axi_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = CAMSS_JPEG_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_jpeg_jpeg_axi_clk",
@@ -3346,7 +3254,6 @@
 static struct branch_clk camss_jpeg_jpeg_ocmemnoc_clk = {
 	.cbcr_reg = CAMSS_JPEG_JPEG_OCMEMNOC_CBCR,
 	.has_sibling = 1,
-	.bcr_reg = CAMSS_JPEG_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_jpeg_jpeg_ocmemnoc_clk",
@@ -3359,7 +3266,6 @@
 	.cbcr_reg = CAMSS_MCLK0_CBCR,
 	.parent = &mclk0_clk_src.c,
 	.has_sibling = 0,
-	.bcr_reg = CAMSS_MCLK0_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_mclk0_clk",
@@ -3372,7 +3278,6 @@
 	.cbcr_reg = CAMSS_MCLK1_CBCR,
 	.parent = &mclk1_clk_src.c,
 	.has_sibling = 0,
-	.bcr_reg = CAMSS_MCLK1_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_mclk1_clk",
@@ -3385,7 +3290,6 @@
 	.cbcr_reg = CAMSS_MCLK2_CBCR,
 	.parent = &mclk2_clk_src.c,
 	.has_sibling = 0,
-	.bcr_reg = CAMSS_MCLK2_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_mclk2_clk",
@@ -3398,7 +3302,6 @@
 	.cbcr_reg = CAMSS_MCLK3_CBCR,
 	.parent = &mclk3_clk_src.c,
 	.has_sibling = 0,
-	.bcr_reg = CAMSS_MCLK3_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_mclk3_clk",
@@ -3411,7 +3314,6 @@
 	.cbcr_reg = CAMSS_MICRO_AHB_CBCR,
 	.parent = &ahb_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = CAMSS_MICRO_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_micro_ahb_clk",
@@ -3424,7 +3326,6 @@
 	.cbcr_reg = CAMSS_PHY0_CSI0PHYTIMER_CBCR,
 	.parent = &csi0phytimer_clk_src.c,
 	.has_sibling = 0,
-	.bcr_reg = CAMSS_PHY0_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_phy0_csi0phytimer_clk",
@@ -3437,7 +3338,6 @@
 	.cbcr_reg = CAMSS_PHY1_CSI1PHYTIMER_CBCR,
 	.parent = &csi1phytimer_clk_src.c,
 	.has_sibling = 0,
-	.bcr_reg = CAMSS_PHY1_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_phy1_csi1phytimer_clk",
@@ -3450,7 +3350,6 @@
 	.cbcr_reg = CAMSS_PHY2_CSI2PHYTIMER_CBCR,
 	.parent = &csi2phytimer_clk_src.c,
 	.has_sibling = 0,
-	.bcr_reg = CAMSS_PHY2_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_phy2_csi2phytimer_clk",
@@ -3463,7 +3362,6 @@
 	.cbcr_reg = CAMSS_TOP_AHB_CBCR,
 	.parent = &ahb_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = CAMSS_TOP_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_top_ahb_clk",
@@ -3476,7 +3374,6 @@
 	.cbcr_reg = CAMSS_VFE_CPP_AHB_CBCR,
 	.parent = &ahb_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = CAMSS_VFE_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_vfe_cpp_ahb_clk",
@@ -3489,7 +3386,6 @@
 	.cbcr_reg = CAMSS_VFE_CPP_CBCR,
 	.parent = &cpp_clk_src.c,
 	.has_sibling = 0,
-	.bcr_reg = CAMSS_VFE_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_vfe_cpp_clk",
@@ -3502,7 +3398,6 @@
 	.cbcr_reg = CAMSS_VFE_VFE0_CBCR,
 	.parent = &vfe0_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = CAMSS_VFE_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_vfe_vfe0_clk",
@@ -3515,7 +3410,6 @@
 	.cbcr_reg = CAMSS_VFE_VFE1_CBCR,
 	.parent = &vfe1_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = CAMSS_VFE_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_vfe_vfe1_clk",
@@ -3528,7 +3422,6 @@
 	.cbcr_reg = CAMSS_VFE_VFE_AHB_CBCR,
 	.parent = &ahb_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = CAMSS_VFE_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_vfe_vfe_ahb_clk",
@@ -3541,7 +3434,6 @@
 	.cbcr_reg = CAMSS_VFE_VFE_AXI_CBCR,
 	.parent = &axi_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = CAMSS_VFE_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_vfe_vfe_axi_clk",
@@ -3553,7 +3445,6 @@
 static struct branch_clk camss_vfe_vfe_ocmemnoc_clk = {
 	.cbcr_reg = CAMSS_VFE_VFE_OCMEMNOC_CBCR,
 	.has_sibling = 1,
-	.bcr_reg = CAMSS_VFE_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_vfe_vfe_ocmemnoc_clk",
@@ -3566,7 +3457,6 @@
 	.cbcr_reg = MDSS_AHB_CBCR,
 	.parent = &ahb_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = MDSS_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "mdss_ahb_clk",
@@ -3579,7 +3469,6 @@
 	.cbcr_reg = MDSS_AXI_CBCR,
 	.parent = &axi_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = MDSS_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "mdss_axi_clk",
@@ -3592,7 +3481,6 @@
 	.cbcr_reg = MDSS_BYTE0_CBCR,
 	.parent = &byte0_clk_src.c,
 	.has_sibling = 0,
-	.bcr_reg = MDSS_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "mdss_byte0_clk",
@@ -3605,7 +3493,6 @@
 	.cbcr_reg = MDSS_BYTE1_CBCR,
 	.parent = &byte1_clk_src.c,
 	.has_sibling = 0,
-	.bcr_reg = MDSS_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "mdss_byte1_clk",
@@ -3618,7 +3505,6 @@
 	.cbcr_reg = MDSS_EDPAUX_CBCR,
 	.parent = &edpaux_clk_src.c,
 	.has_sibling = 0,
-	.bcr_reg = MDSS_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "mdss_edpaux_clk",
@@ -3631,7 +3517,6 @@
 	.cbcr_reg = MDSS_EDPLINK_CBCR,
 	.parent = &edplink_clk_src.c,
 	.has_sibling = 0,
-	.bcr_reg = MDSS_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "mdss_edplink_clk",
@@ -3644,7 +3529,6 @@
 	.cbcr_reg = MDSS_EDPPIXEL_CBCR,
 	.parent = &edppixel_clk_src.c,
 	.has_sibling = 0,
-	.bcr_reg = MDSS_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "mdss_edppixel_clk",
@@ -3657,7 +3541,6 @@
 	.cbcr_reg = MDSS_ESC0_CBCR,
 	.parent = &esc0_clk_src.c,
 	.has_sibling = 0,
-	.bcr_reg = MDSS_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "mdss_esc0_clk",
@@ -3670,7 +3553,6 @@
 	.cbcr_reg = MDSS_ESC1_CBCR,
 	.parent = &esc1_clk_src.c,
 	.has_sibling = 0,
-	.bcr_reg = MDSS_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "mdss_esc1_clk",
@@ -3683,7 +3565,6 @@
 	.cbcr_reg = MDSS_EXTPCLK_CBCR,
 	.parent = &extpclk_clk_src.c,
 	.has_sibling = 0,
-	.bcr_reg = MDSS_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "mdss_extpclk_clk",
@@ -3696,7 +3577,6 @@
 	.cbcr_reg = MDSS_HDMI_AHB_CBCR,
 	.parent = &ahb_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = MDSS_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "mdss_hdmi_ahb_clk",
@@ -3709,7 +3589,6 @@
 	.cbcr_reg = MDSS_HDMI_CBCR,
 	.parent = &hdmi_clk_src.c,
 	.has_sibling = 0,
-	.bcr_reg = MDSS_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "mdss_hdmi_clk",
@@ -3722,7 +3601,6 @@
 	.cbcr_reg = MDSS_MDP_CBCR,
 	.parent = &mdp_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = MDSS_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "mdss_mdp_clk",
@@ -3735,7 +3613,6 @@
 	.cbcr_reg = MDSS_MDP_LUT_CBCR,
 	.parent = &mdp_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = MDSS_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "mdss_mdp_lut_clk",
@@ -3748,7 +3625,6 @@
 	.cbcr_reg = MDSS_PCLK0_CBCR,
 	.parent = &pclk0_clk_src.c,
 	.has_sibling = 0,
-	.bcr_reg = MDSS_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "mdss_pclk0_clk",
@@ -3761,7 +3637,6 @@
 	.cbcr_reg = MDSS_PCLK1_CBCR,
 	.parent = &pclk1_clk_src.c,
 	.has_sibling = 0,
-	.bcr_reg = MDSS_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "mdss_pclk1_clk",
@@ -3774,7 +3649,6 @@
 	.cbcr_reg = MDSS_VSYNC_CBCR,
 	.parent = &vsync_clk_src.c,
 	.has_sibling = 0,
-	.bcr_reg = MDSS_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "mdss_vsync_clk",
@@ -3787,7 +3661,6 @@
 	.cbcr_reg = MMSS_MISC_AHB_CBCR,
 	.parent = &ahb_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = MMSSNOCAHB_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "mmss_misc_ahb_clk",
@@ -3800,7 +3673,6 @@
 	.cbcr_reg = MMSS_MMSSNOC_AHB_CBCR,
 	.parent = &ahb_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = MMSSNOCAHB_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "mmss_mmssnoc_ahb_clk",
@@ -3813,7 +3685,6 @@
 	.cbcr_reg = MMSS_MMSSNOC_BTO_AHB_CBCR,
 	.parent = &ahb_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = MMSSNOCAHB_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "mmss_mmssnoc_bto_ahb_clk",
@@ -3826,7 +3697,6 @@
 	.cbcr_reg = MMSS_MMSSNOC_AXI_CBCR,
 	.parent = &axi_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = MMSSNOCAXI_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "mmss_mmssnoc_axi_clk",
@@ -3839,7 +3709,6 @@
 	.cbcr_reg = MMSS_S0_AXI_CBCR,
 	.parent = &axi_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = MMSSNOCAXI_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "mmss_s0_axi_clk",
@@ -3852,7 +3721,6 @@
 	.cbcr_reg = VENUS0_AHB_CBCR,
 	.parent = &ahb_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = VENUS0_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "venus0_ahb_clk",
@@ -3865,7 +3733,6 @@
 	.cbcr_reg = VENUS0_AXI_CBCR,
 	.parent = &axi_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = VENUS0_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "venus0_axi_clk",
@@ -3877,7 +3744,6 @@
 static struct branch_clk venus0_ocmemnoc_clk = {
 	.cbcr_reg = VENUS0_OCMEMNOC_CBCR,
 	.has_sibling = 1,
-	.bcr_reg = VENUS0_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "venus0_ocmemnoc_clk",
@@ -3890,7 +3756,6 @@
 	.cbcr_reg = VENUS0_VCODEC0_CBCR,
 	.parent = &vcodec0_clk_src.c,
 	.has_sibling = 0,
-	.bcr_reg = VENUS0_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "venus0_vcodec0_clk",
@@ -3902,7 +3767,6 @@
 static struct branch_clk oxili_gfx3d_clk = {
 	.cbcr_reg = OXILI_GFX3D_CBCR,
 	.has_sibling = 1,
-	.bcr_reg = OXILI_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "oxili_gfx3d_clk",
@@ -3915,7 +3779,6 @@
 	.cbcr_reg = OXILICX_AHB_CBCR,
 	.parent = &ahb_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = OXILICX_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "oxilicx_ahb_clk",
@@ -3928,7 +3791,6 @@
 	.cbcr_reg = OXILICX_AXI_CBCR,
 	.parent = &axi_clk_src.c,
 	.has_sibling = 1,
-	.bcr_reg = OXILICX_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "oxilicx_axi_clk",
@@ -4363,7 +4225,6 @@
 
 static struct branch_clk mss_bus_q6_clk = {
 	.cbcr_reg = MSS_BUS_Q6_CBCR,
-	.bcr_reg = MSS_Q6SS_BCR,
 	.has_sibling = 1,
 	.base = &virt_bases[MSS_BASE],
 	.c = {
@@ -4699,7 +4560,7 @@
 }
 #endif /* CONFIG_DEBUG_FS */
 
-static struct clk_ops measure_clk_ops = {
+static struct clk_ops clk_ops_measure = {
 	.set_parent = measure_clk_set_parent,
 	.get_rate = measure_clk_get_rate,
 };
@@ -4707,7 +4568,7 @@
 static struct measure_clk measure_clk = {
 	.c = {
 		.dbg_name = "measure_clk",
-		.ops = &measure_clk_ops,
+		.ops = &clk_ops_measure,
 		CLK_INIT(measure_clk.c),
 	},
 	.multiplier = 1,
@@ -4716,6 +4577,9 @@
 static struct clk_lookup msm_clocks_copper[] = {
 	CLK_LOOKUP("xo",	cxo_clk_src.c,	"msm_otg"),
 	CLK_LOOKUP("xo",	cxo_clk_src.c,	"pil-q6v5-lpass"),
+	CLK_LOOKUP("xo",	cxo_clk_src.c,	"pil-q6v5-mss"),
+	CLK_LOOKUP("xo",	cxo_clk_src.c,	"pil-mba"),
+	CLK_LOOKUP("xo",	cxo_clk_src.c,	"pil_pronto"),
 	CLK_LOOKUP("measure",	measure_clk.c,	"debug"),
 
 	CLK_LOOKUP("dma_bam_pclk", gcc_bam_dma_ahb_clk.c, "msm_sps"),
@@ -4846,7 +4710,10 @@
 	CLK_LOOKUP("core_clk", camss_jpeg_jpeg0_clk.c, ""),
 	CLK_LOOKUP("core_clk", camss_jpeg_jpeg1_clk.c, ""),
 	CLK_LOOKUP("core_clk", camss_jpeg_jpeg2_clk.c, ""),
-	CLK_LOOKUP("iface_clk", camss_jpeg_jpeg_ahb_clk.c, ""),
+	CLK_LOOKUP("iface_clk", camss_jpeg_jpeg_ahb_clk.c,
+						"fda64000.qcom,iommu"),
+	CLK_LOOKUP("core_clk", camss_jpeg_jpeg_axi_clk.c,
+						"fda64000.qcom,iommu"),
 	CLK_LOOKUP("bus_clk", camss_jpeg_jpeg_axi_clk.c, ""),
 	CLK_LOOKUP("bus_clk", camss_jpeg_jpeg_ocmemnoc_clk.c, ""),
 	CLK_LOOKUP("core_clk", camss_mclk0_clk.c, ""),
@@ -4867,11 +4734,15 @@
 	CLK_LOOKUP("iface_clk", camss_vfe_vfe_ahb_clk.c, ""),
 	CLK_LOOKUP("bus_clk", camss_vfe_vfe_axi_clk.c, ""),
 	CLK_LOOKUP("bus_clk", camss_vfe_vfe_ocmemnoc_clk.c, ""),
-	CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, ""),
+	CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "fd928000.qcom,iommu"),
+	CLK_LOOKUP("core_clk", mdss_axi_clk.c, "fd928000.qcom,iommu"),
 	CLK_LOOKUP("bus_clk", mdss_axi_clk.c, ""),
 	CLK_LOOKUP("core_clk", oxili_gfx3d_clk.c, ""),
 	CLK_LOOKUP("iface_clk", oxilicx_ahb_clk.c, ""),
 	CLK_LOOKUP("bus_clk", oxilicx_axi_clk.c, ""),
+	CLK_LOOKUP("iface_clk", venus0_ahb_clk.c, "fdc84000.qcom,iommu"),
+	CLK_LOOKUP("core_clk", venus0_axi_clk.c, "fdc84000.qcom,iommu"),
+	CLK_LOOKUP("bus_clk", venus0_axi_clk.c, ""),
 
 	/* LPASS clocks */
 	CLK_LOOKUP("core_clk", audio_core_slimbus_core_clk.c, "fe12f000.slim"),
@@ -4904,12 +4775,13 @@
 	CLK_LOOKUP("ebit_clk", audio_core_lpaif_pcm1_ebit_clk.c, ""),
 	CLK_LOOKUP("ibit_clk", audio_core_lpaif_pcm1_ibit_clk.c, ""),
 
-	CLK_LOOKUP("core_clk",       mss_xo_q6_clk.c, ""),
-	CLK_LOOKUP("bus_clk",       mss_bus_q6_clk.c, ""),
-	CLK_LOOKUP("core_clk",         q6ss_xo_clk.c, ""),
-	CLK_LOOKUP("bus_clk",  q6ss_ahb_lfabif_clk.c, ""),
-	CLK_LOOKUP("mem_clk", gcc_boot_rom_ahb_clk.c, ""),
+	CLK_LOOKUP("core_clk",       mss_xo_q6_clk.c, "pil-q6v5-mss"),
+	CLK_LOOKUP("bus_clk",       mss_bus_q6_clk.c, "pil-q6v5-mss"),
 	CLK_LOOKUP("bus_clk",  gcc_mss_cfg_ahb_clk.c, ""),
+	CLK_LOOKUP("mem_clk", gcc_boot_rom_ahb_clk.c, "pil-q6v5-mss"),
+	CLK_LOOKUP("core_clk",         q6ss_xo_clk.c, "pil-q6v5-lpass"),
+	CLK_LOOKUP("bus_clk",  q6ss_ahb_lfabif_clk.c, "pil-q6v5-lpass"),
+	CLK_LOOKUP("core_clk", gcc_prng_ahb_clk.c, "msm_rng"),
 
 	/* TODO: Remove dummy clocks as soon as they become unnecessary */
 	CLK_DUMMY("phy_clk",       NULL,    "msm_otg", OFF),
diff --git a/arch/arm/mach-msm/clock-local.c b/arch/arm/mach-msm/clock-local.c
index e1b3381..4f365fa 100644
--- a/arch/arm/mach-msm/clock-local.c
+++ b/arch/arm/mach-msm/clock-local.c
@@ -627,20 +627,16 @@
 	return HANDOFF_ENABLED_CLK;
 }
 
-struct clk_ops clk_ops_gnd = {
-};
+struct clk_ops clk_ops_empty;
 
 struct fixed_clk gnd_clk = {
 	.c = {
 		.dbg_name = "ground_clk",
-		.ops = &clk_ops_gnd,
+		.ops = &clk_ops_empty,
 		CLK_INIT(gnd_clk.c),
 	},
 };
 
-struct clk_ops clk_ops_measure = {
-};
-
 static int branch_clk_enable(struct clk *clk)
 {
 	unsigned long flags;
diff --git a/arch/arm/mach-msm/clock-local.h b/arch/arm/mach-msm/clock-local.h
index a419d69..ffc7057 100644
--- a/arch/arm/mach-msm/clock-local.h
+++ b/arch/arm/mach-msm/clock-local.h
@@ -77,7 +77,7 @@
  */
 #define DEFINE_CLK_MEASURE(name) \
 	struct clk name = { \
-		.ops = &clk_ops_measure, \
+		.ops = &clk_ops_empty, \
 		.dbg_name = #name, \
 		CLK_INIT(name), \
 	}; \
@@ -264,7 +264,7 @@
 	struct clk c;
 };
 
-extern struct clk_ops clk_ops_measure;
+extern struct clk_ops clk_ops_empty;
 
 static inline struct measure_clk *to_measure_clk(struct clk *clk)
 {
diff --git a/arch/arm/mach-msm/clock-local2.c b/arch/arm/mach-msm/clock-local2.c
index e8e88d7..cf45e63 100644
--- a/arch/arm/mach-msm/clock-local2.c
+++ b/arch/arm/mach-msm/clock-local2.c
@@ -462,14 +462,16 @@
 }
 
 static int __branch_clk_reset(void __iomem *bcr_reg,
-				enum clk_reset_action action)
+				enum clk_reset_action action, const char *name)
 {
 	int ret = 0;
 	unsigned long flags;
 	u32 reg_val;
 
-	if (!bcr_reg)
+	if (!bcr_reg) {
+		WARN("clk_reset called on an unsupported clock (%s)\n", name);
 		return -EPERM;
+	}
 
 	spin_lock_irqsave(&local_clock_reg_lock, flags);
 	reg_val = readl_relaxed(bcr_reg);
@@ -495,7 +497,7 @@
 static int branch_clk_reset(struct clk *c, enum clk_reset_action action)
 {
 	struct branch_clk *branch = to_branch_clk(c);
-	return __branch_clk_reset(BCR_REG(branch), action);
+	return __branch_clk_reset(BCR_REG(branch), action, c->dbg_name);
 }
 
 /*
@@ -503,8 +505,8 @@
  */
 static int local_vote_clk_reset(struct clk *c, enum clk_reset_action action)
 {
-	struct branch_clk *vclk = to_branch_clk(c);
-	return __branch_clk_reset(BCR_REG(vclk), action);
+	struct local_vote_clk *vclk = to_local_vote_clk(c);
+	return __branch_clk_reset(BCR_REG(vclk), action, c->dbg_name);
 }
 
 static int local_vote_clk_enable(struct clk *c)
diff --git a/arch/arm/mach-msm/clock-local2.h b/arch/arm/mach-msm/clock-local2.h
index c8d53cb..547e633 100644
--- a/arch/arm/mach-msm/clock-local2.h
+++ b/arch/arm/mach-msm/clock-local2.h
@@ -153,8 +153,6 @@
 	struct clk c;
 };
 
-extern struct clk_ops clk_ops_measure;
-
 static inline struct measure_clk *to_measure_clk(struct clk *clk)
 {
 	return container_of(clk, struct measure_clk, c);
diff --git a/arch/arm/mach-msm/clock-pcom-lookup.c b/arch/arm/mach-msm/clock-pcom-lookup.c
index d842d45..f71d6d5 100644
--- a/arch/arm/mach-msm/clock-pcom-lookup.c
+++ b/arch/arm/mach-msm/clock-pcom-lookup.c
@@ -39,7 +39,7 @@
 	.id = PLL_0,
 	.mode_reg = PLLn_MODE(0),
 	.c = {
-		.ops = &clk_pll_ops,
+		.ops = &clk_ops_pll,
 		.dbg_name = "pll0_clk",
 		CLK_INIT(pll0_clk.c),
 	},
@@ -49,7 +49,7 @@
 	.id = PLL_1,
 	.mode_reg = PLLn_MODE(1),
 	.c = {
-		.ops = &clk_pll_ops,
+		.ops = &clk_ops_pll,
 		.dbg_name = "pll1_clk",
 		CLK_INIT(pll1_clk.c),
 	},
@@ -59,7 +59,7 @@
 	.id = PLL_2,
 	.mode_reg = PLLn_MODE(2),
 	.c = {
-		.ops = &clk_pll_ops,
+		.ops = &clk_ops_pll,
 		.dbg_name = "pll2_clk",
 		CLK_INIT(pll2_clk.c),
 	},
@@ -69,7 +69,7 @@
 	.id = PLL_4,
 	.mode_reg = PLL4_MODE,
 	.c = {
-		.ops = &clk_pll_ops,
+		.ops = &clk_ops_pll,
 		.dbg_name = "pll4_clk",
 		CLK_INIT(pll4_clk.c),
 	},
diff --git a/arch/arm/mach-msm/clock-pcom.c b/arch/arm/mach-msm/clock-pcom.c
index 58cea99..658fa2a 100644
--- a/arch/arm/mach-msm/clock-pcom.c
+++ b/arch/arm/mach-msm/clock-pcom.c
@@ -175,6 +175,18 @@
 	return false;
 }
 
+static enum handoff pc_clk_handoff(struct clk *clk)
+{
+	/*
+	 * Handoff clock state only since querying and caching the rate here
+	 * would incur more overhead than it would ever save.
+	 */
+	if (pc_clk_is_enabled(clk))
+		return HANDOFF_ENABLED_CLK;
+
+	return HANDOFF_DISABLED_CLK;
+}
+
 struct clk_ops clk_ops_pcom = {
 	.enable = pc_clk_enable,
 	.disable = pc_clk_disable,
@@ -187,6 +199,7 @@
 	.is_enabled = pc_clk_is_enabled,
 	.round_rate = pc_clk_round_rate,
 	.is_local = pc_clk_is_local,
+	.handoff = pc_clk_handoff,
 };
 
 struct clk_ops clk_ops_pcom_ext_config = {
@@ -201,5 +214,6 @@
 	.is_enabled = pc_clk_is_enabled,
 	.round_rate = pc_clk_round_rate,
 	.is_local = pc_clk_is_local,
+	.handoff = pc_clk_handoff,
 };
 
diff --git a/arch/arm/mach-msm/clock-pll.c b/arch/arm/mach-msm/clock-pll.c
index 3a232c5..d839911 100644
--- a/arch/arm/mach-msm/clock-pll.c
+++ b/arch/arm/mach-msm/clock-pll.c
@@ -110,12 +110,22 @@
 	return !!(readl_relaxed(PLL_STATUS_REG(pll)) & pll->status_mask);
 }
 
+static enum handoff pll_vote_clk_handoff(struct clk *clk)
+{
+	struct pll_vote_clk *pll = to_pll_vote_clk(clk);
+	if (readl_relaxed(PLL_EN_REG(pll)) & pll->en_mask)
+		return HANDOFF_ENABLED_CLK;
+
+	return HANDOFF_DISABLED_CLK;
+}
+
 struct clk_ops clk_ops_pll_vote = {
 	.enable = pll_vote_clk_enable,
 	.disable = pll_vote_clk_disable,
 	.auto_off = pll_vote_clk_disable,
 	.is_enabled = pll_vote_clk_is_enabled,
 	.get_parent = pll_vote_clk_get_parent,
+	.handoff = pll_vote_clk_handoff,
 };
 
 static void __pll_clk_enable_reg(void __iomem *mode_reg)
@@ -181,6 +191,18 @@
 	spin_unlock_irqrestore(&pll_reg_lock, flags);
 }
 
+static enum handoff local_pll_clk_handoff(struct clk *clk)
+{
+	struct pll_clk *pll = to_pll_clk(clk);
+	u32 mode = readl_relaxed(PLL_MODE_REG(pll));
+	u32 mask = PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL;
+
+	if ((mode & mask) == mask)
+		return HANDOFF_ENABLED_CLK;
+
+	return HANDOFF_DISABLED_CLK;
+}
+
 static struct clk *local_pll_clk_get_parent(struct clk *clk)
 {
 	struct pll_clk *pll = to_pll_clk(clk);
@@ -281,6 +303,7 @@
 	.enable = local_pll_clk_enable,
 	.disable = local_pll_clk_disable,
 	.auto_off = local_pll_clk_disable,
+	.handoff = local_pll_clk_handoff,
 	.get_parent = local_pll_clk_get_parent,
 };
 
@@ -297,6 +320,7 @@
 	{41, 800000000},
 	{50, 960000000},
 	{52, 1008000000},
+	{60, 1152000000},
 	{62, 1200000000},
 	{63, 1209600000},
 	{0, 0},
@@ -427,7 +451,7 @@
 	return HANDOFF_ENABLED_CLK;
 }
 
-struct clk_ops clk_pll_ops = {
+struct clk_ops clk_ops_pll = {
 	.enable = pll_clk_enable,
 	.disable = pll_clk_disable,
 	.handoff = pll_clk_handoff,
diff --git a/arch/arm/mach-msm/clock-pll.h b/arch/arm/mach-msm/clock-pll.h
index 231668f..a8c642f 100644
--- a/arch/arm/mach-msm/clock-pll.h
+++ b/arch/arm/mach-msm/clock-pll.h
@@ -43,7 +43,7 @@
 	void *const __iomem *base;
 };
 
-extern struct clk_ops clk_pll_ops;
+extern struct clk_ops clk_ops_pll;
 
 static inline struct pll_shared_clk *to_pll_shared_clk(struct clk *clk)
 {
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index f6eee76..00572dd 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -42,6 +42,7 @@
 #include "rpm_log.h"
 #include <mach/mpm.h>
 #include <mach/iommu_domains.h>
+#include <mach/msm_cache_dump.h>
 
 /* Address of GSBI blocks */
 #define MSM_GSBI1_PHYS		0x12440000
@@ -82,6 +83,25 @@
 #define MSM_HSUSB4_PHYS		0x12530000
 #define MSM_HSUSB4_SIZE		SZ_4K
 
+/* Address of PCIE20 PARF */
+#define PCIE20_PARF_PHYS   0x1b600000
+#define PCIE20_PARF_SIZE   SZ_128
+
+/* Address of PCIE20 ELBI */
+#define PCIE20_ELBI_PHYS   0x1b502000
+#define PCIE20_ELBI_SIZE   SZ_256
+
+/* Address of PCIE20 */
+#define PCIE20_PHYS   0x1b500000
+#define PCIE20_SIZE   SZ_4K
+
+/* AXI address for PCIE device BAR resources */
+#define PCIE_AXI_BAR_PHYS   0x08000000
+#define PCIE_AXI_BAR_SIZE   SZ_8M
+
+/* AXI address for PCIE device config space */
+#define PCIE_AXI_CONF_PHYS   0x08c00000
+#define PCIE_AXI_CONF_SIZE   SZ_4K
 
 static struct msm_watchdog_pdata msm_watchdog_pdata = {
 	.pet_time = 10000,
@@ -458,13 +478,24 @@
  */
 struct msm_dai_auxpcm_pdata apq_auxpcm_pdata = {
 	.clk = "pcm_clk",
-	.mode = AFE_PCM_CFG_MODE_PCM,
-	.sync = AFE_PCM_CFG_SYNC_INT,
-	.frame = AFE_PCM_CFG_FRM_256BPF,
-	.quant = AFE_PCM_CFG_QUANT_LINEAR_NOPAD,
-	.slot = 0,
-	.data = AFE_PCM_CFG_CDATAOE_MASTER,
-	.pcm_clk_rate = 2048000,
+	.mode_8k = {
+		.mode = AFE_PCM_CFG_MODE_PCM,
+		.sync = AFE_PCM_CFG_SYNC_INT,
+		.frame = AFE_PCM_CFG_FRM_256BPF,
+		.quant = AFE_PCM_CFG_QUANT_LINEAR_NOPAD,
+		.slot = 0,
+		.data = AFE_PCM_CFG_CDATAOE_MASTER,
+		.pcm_clk_rate = 2048000,
+	},
+	.mode_16k = {
+		.mode = AFE_PCM_CFG_MODE_PCM,
+		.sync = AFE_PCM_CFG_SYNC_INT,
+		.frame = AFE_PCM_CFG_FRM_256BPF,
+		.quant = AFE_PCM_CFG_QUANT_LINEAR_NOPAD,
+		.slot = 0,
+		.data = AFE_PCM_CFG_CDATAOE_MASTER,
+		.pcm_clk_rate = 4096000,
+	}
 };
 
 struct platform_device apq_cpudai_auxpcm_rx = {
@@ -587,6 +618,11 @@
 	.id = 0x4006,
 };
 
+struct platform_device apq_cpudai_slimbus_3_tx = {
+	.name = "msm-dai-q6",
+	.id = 0x4007,
+};
+
 static struct resource resources_ssbi_pmic1[] = {
 	{
 		.start  = MSM_PMIC1_SSBI_CMD_PHYS,
@@ -741,10 +777,10 @@
 		.flags	= IORESOURCE_IRQ,
 	},
 	{
-		.start	= MSM_GPIO_TO_INT(88),
-		.end	= MSM_GPIO_TO_INT(88),
-		.name	= "wakeup_irq",
-		.flags	= IORESOURCE_IRQ,
+		.start	= 47,
+		.end	= 47,
+		.name	= "wakeup",
+		.flags	= IORESOURCE_IO,
 	},
 };
 
@@ -819,6 +855,22 @@
 	},
 };
 
+#define SHARED_IMEM_TZ_BASE 0x2a03f720
+static struct resource tzlog_resources[] = {
+	{
+		.start = SHARED_IMEM_TZ_BASE,
+		.end = SHARED_IMEM_TZ_BASE + SZ_4K - 1,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+struct platform_device apq_device_tz_log = {
+	.name		= "tz_log",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(tzlog_resources),
+	.resource	= tzlog_resources,
+};
+
 /* MSM Video core device */
 #ifdef CONFIG_MSM_BUS_SCALING
 static struct msm_bus_vectors vidc_init_vectors[] = {
@@ -1518,6 +1570,46 @@
 	},
 };
 
+static struct resource resources_msm_pcie[] = {
+	{
+		.name   = "parf",
+		.start  = PCIE20_PARF_PHYS,
+		.end    = PCIE20_PARF_PHYS + PCIE20_PARF_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name   = "elbi",
+		.start  = PCIE20_ELBI_PHYS,
+		.end    = PCIE20_ELBI_PHYS + PCIE20_ELBI_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name   = "pcie20",
+		.start  = PCIE20_PHYS,
+		.end    = PCIE20_PHYS + PCIE20_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name   = "axi_bar",
+		.start  = PCIE_AXI_BAR_PHYS,
+		.end    = PCIE_AXI_BAR_PHYS + PCIE_AXI_BAR_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name   = "axi_conf",
+		.start  = PCIE_AXI_CONF_PHYS,
+		.end    = PCIE_AXI_CONF_PHYS + PCIE_AXI_CONF_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm_device_pcie = {
+	.name           = "msm_pcie",
+	.id             = -1,
+	.num_resources  = ARRAY_SIZE(resources_msm_pcie),
+	.resource       = resources_msm_pcie,
+};
+
 #ifdef CONFIG_HW_RANDOM_MSM
 /* PRNG device */
 #define MSM_PRNG_PHYS           0x1A500000
@@ -1931,6 +2023,16 @@
 
 /* Sensors DSPS platform data */
 
+#define PPSS_DSPS_TCM_CODE_BASE 0x12000000
+#define PPSS_DSPS_TCM_CODE_SIZE 0x28000
+#define PPSS_DSPS_TCM_BUF_BASE  0x12040000
+#define PPSS_DSPS_TCM_BUF_SIZE  0x4000
+#define PPSS_DSPS_PIPE_BASE     0x12800000
+#define PPSS_DSPS_PIPE_SIZE     0x4000
+#define PPSS_DSPS_DDR_BASE      0x8fe00000
+#define PPSS_DSPS_DDR_SIZE      0x100000
+#define PPSS_SMEM_BASE          0x80000000
+#define PPSS_SMEM_SIZE          0x200000
 #define PPSS_REG_PHYS_BASE	0x12080000
 
 static struct dsps_clk_info dsps_clks[] = {};
@@ -1949,6 +2051,16 @@
 	.regs = dsps_regs,
 	.regs_num = ARRAY_SIZE(dsps_regs),
 	.dsps_pwr_ctl_en = 1,
+	.tcm_code_start = PPSS_DSPS_TCM_CODE_BASE,
+	.tcm_code_size = PPSS_DSPS_TCM_CODE_SIZE,
+	.tcm_buf_start = PPSS_DSPS_TCM_BUF_BASE,
+	.tcm_buf_size = PPSS_DSPS_TCM_BUF_SIZE,
+	.pipe_start = PPSS_DSPS_PIPE_BASE,
+	.pipe_size = PPSS_DSPS_PIPE_SIZE,
+	.ddr_start = PPSS_DSPS_DDR_BASE,
+	.ddr_size = PPSS_DSPS_DDR_SIZE,
+	.smem_start = PPSS_SMEM_BASE,
+	.smem_size  = PPSS_SMEM_SIZE,
 	.signature = DSPS_SIGNATURE,
 };
 
@@ -2070,11 +2182,12 @@
 };
 #endif
 
+/* AP2MDM_SOFT_RESET is implemented by the PON_RESET_N gpio */
 #define MDM2AP_ERRFATAL			19
 #define AP2MDM_ERRFATAL			18
 #define MDM2AP_STATUS			49
 #define AP2MDM_STATUS			48
-#define AP2MDM_PMIC_RESET_N		27
+#define AP2MDM_SOFT_RESET		27
 #define AP2MDM_WAKEUP			35
 
 static struct resource mdm_resources[] = {
@@ -2103,9 +2216,9 @@
 		.flags	= IORESOURCE_IO,
 	},
 	{
-		.start	= AP2MDM_PMIC_RESET_N,
-		.end	= AP2MDM_PMIC_RESET_N,
-		.name	= "AP2MDM_PMIC_RESET_N",
+		.start	= AP2MDM_SOFT_RESET,
+		.end	= AP2MDM_SOFT_RESET,
+		.name	= "AP2MDM_SOFT_RESET",
 		.flags	= IORESOURCE_IO,
 	},
 	{
@@ -2242,11 +2355,17 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	{
-		.name	= "vcap",
+		.name	= "vc_irq",
 		.start	= VCAP_VC,
 		.end	= VCAP_VC,
 		.flags	= IORESOURCE_IRQ,
 	},
+	{
+		.name	= "vp_irq",
+		.start	= VCAP_VP,
+		.end	= VCAP_VP,
+		.flags	= IORESOURCE_IRQ,
+	},
 };
 
 static unsigned vcap_gpios[] = {
@@ -2511,3 +2630,23 @@
 		.platform_data = &apq8064_rtb_pdata,
 	},
 };
+
+#define APQ8064_L1_SIZE  SZ_1M
+/*
+ * The actual L2 size is smaller but we need a larger buffer
+ * size to store other dump information
+ */
+#define APQ8064_L2_SIZE  SZ_8M
+
+struct msm_cache_dump_platform_data apq8064_cache_dump_pdata = {
+	.l2_size = APQ8064_L2_SIZE,
+	.l1_size = APQ8064_L1_SIZE,
+};
+
+struct platform_device apq8064_cache_dump_device = {
+	.name           = "msm_cache_dump",
+	.id             = -1,
+	.dev            = {
+		.platform_data = &apq8064_cache_dump_pdata,
+	},
+};
diff --git a/arch/arm/mach-msm/devices-8930.c b/arch/arm/mach-msm/devices-8930.c
index 4ad73f9..9de2213 100644
--- a/arch/arm/mach-msm/devices-8930.c
+++ b/arch/arm/mach-msm/devices-8930.c
@@ -126,6 +126,7 @@
 		MSM_RPM_MAP(8930, CXO_BUFFERS, CXO_BUFFERS, 1),
 		MSM_RPM_MAP(8930, USB_OTG_SWITCH, USB_OTG_SWITCH, 1),
 		MSM_RPM_MAP(8930, HDMI_SWITCH, HDMI_SWITCH, 1),
+		MSM_RPM_MAP(8930, DDR_DMM_0, DDR_DMM, 2),
 		MSM_RPM_MAP(8930, QDSS_CLK, QDSS_CLK, 1),
 		MSM_RPM_MAP(8930, VOLTAGE_CORNER, VOLTAGE_CORNER, 1),
 	},
@@ -230,6 +231,8 @@
 		MSM_RPM_STATUS_ID_MAP(8930, CXO_BUFFERS),
 		MSM_RPM_STATUS_ID_MAP(8930, USB_OTG_SWITCH),
 		MSM_RPM_STATUS_ID_MAP(8930, HDMI_SWITCH),
+		MSM_RPM_STATUS_ID_MAP(8930, DDR_DMM_0),
+		MSM_RPM_STATUS_ID_MAP(8930, DDR_DMM_1),
 		MSM_RPM_STATUS_ID_MAP(8930, QDSS_CLK),
 		MSM_RPM_STATUS_ID_MAP(8930, VOLTAGE_CORNER),
 	},
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index f1553b6..e7d8f42 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -1892,13 +1892,24 @@
  */
 struct msm_dai_auxpcm_pdata auxpcm_pdata = {
 	.clk = "pcm_clk",
-	.mode = AFE_PCM_CFG_MODE_PCM,
-	.sync = AFE_PCM_CFG_SYNC_INT,
-	.frame = AFE_PCM_CFG_FRM_256BPF,
-	.quant = AFE_PCM_CFG_QUANT_LINEAR_NOPAD,
-	.slot = 0,
-	.data = AFE_PCM_CFG_CDATAOE_MASTER,
-	.pcm_clk_rate = 2048000,
+	.mode_8k = {
+		.mode = AFE_PCM_CFG_MODE_PCM,
+		.sync = AFE_PCM_CFG_SYNC_INT,
+		.frame = AFE_PCM_CFG_FRM_256BPF,
+		.quant = AFE_PCM_CFG_QUANT_LINEAR_NOPAD,
+		.slot = 0,
+		.data = AFE_PCM_CFG_CDATAOE_MASTER,
+		.pcm_clk_rate = 2048000,
+	},
+	.mode_16k = {
+		.mode = AFE_PCM_CFG_MODE_PCM,
+		.sync = AFE_PCM_CFG_SYNC_INT,
+		.frame = AFE_PCM_CFG_FRM_256BPF,
+		.quant = AFE_PCM_CFG_QUANT_LINEAR_NOPAD,
+		.slot = 0,
+		.data = AFE_PCM_CFG_CDATAOE_MASTER,
+		.pcm_clk_rate = 4096000,
+	}
 };
 
 struct platform_device msm_cpudai_auxpcm_rx = {
@@ -3235,6 +3246,16 @@
 /* Sensors DSPS platform data */
 #ifdef CONFIG_MSM_DSPS
 
+#define PPSS_DSPS_TCM_CODE_BASE 0x12000000
+#define PPSS_DSPS_TCM_CODE_SIZE 0x28000
+#define PPSS_DSPS_TCM_BUF_BASE  0x12040000
+#define PPSS_DSPS_TCM_BUF_SIZE  0x4000
+#define PPSS_DSPS_PIPE_BASE     0x12800000
+#define PPSS_DSPS_PIPE_SIZE     0x4000
+#define PPSS_DSPS_DDR_BASE      0x8fe00000
+#define PPSS_DSPS_DDR_SIZE      0x100000
+#define PPSS_SMEM_BASE          0x80000000
+#define PPSS_SMEM_SIZE          0x200000
 #define PPSS_REG_PHYS_BASE	0x12080000
 
 static struct dsps_clk_info dsps_clks[] = {};
@@ -3253,6 +3274,16 @@
 	.regs = dsps_regs,
 	.regs_num = ARRAY_SIZE(dsps_regs),
 	.dsps_pwr_ctl_en = 1,
+	.tcm_code_start = PPSS_DSPS_TCM_CODE_BASE,
+	.tcm_code_size = PPSS_DSPS_TCM_CODE_SIZE,
+	.tcm_buf_start = PPSS_DSPS_TCM_BUF_BASE,
+	.tcm_buf_size = PPSS_DSPS_TCM_BUF_SIZE,
+	.pipe_start = PPSS_DSPS_PIPE_BASE,
+	.pipe_size = PPSS_DSPS_PIPE_SIZE,
+	.ddr_start = PPSS_DSPS_DDR_BASE,
+	.ddr_size = PPSS_DSPS_DDR_SIZE,
+	.smem_start = PPSS_SMEM_BASE,
+	.smem_size  = PPSS_SMEM_SIZE,
 	.signature = DSPS_SIGNATURE,
 };
 
@@ -3263,7 +3294,6 @@
 		.name  = "ppss_reg",
 		.flags = IORESOURCE_MEM,
 	},
-
 	{
 		.start = PPSS_WDOG_TIMER_IRQ,
 		.end   = PPSS_WDOG_TIMER_IRQ,
@@ -3620,9 +3650,16 @@
 	},
 };
 
+#define MSM_8960_L1_SIZE  SZ_1M
+/*
+ * The actual L2 size is smaller but we need a larger buffer
+ * size to store other dump information
+ */
+#define MSM_8960_L2_SIZE  SZ_4M
+
 struct msm_cache_dump_platform_data msm8960_cache_dump_pdata = {
-	.l2_size = L2_BUFFER_SIZE,
-	.l1_size = L1_BUFFER_SIZE,
+	.l2_size = MSM_8960_L2_SIZE,
+	.l1_size = MSM_8960_L1_SIZE,
 };
 
 struct platform_device msm8960_cache_dump_device = {
@@ -3632,3 +3669,63 @@
 		.platform_data = &msm8960_cache_dump_pdata,
 	},
 };
+
+#define MDM2AP_ERRFATAL			40
+#define AP2MDM_ERRFATAL			80
+#define MDM2AP_STATUS			24
+#define AP2MDM_STATUS			77
+#define AP2MDM_PMIC_PWR_EN		22
+#define AP2MDM_KPDPWR_N			79
+#define AP2MDM_SOFT_RESET		78
+
+static struct resource sglte_resources[] = {
+	{
+		.start	= MDM2AP_ERRFATAL,
+		.end	= MDM2AP_ERRFATAL,
+		.name	= "MDM2AP_ERRFATAL",
+		.flags	= IORESOURCE_IO,
+	},
+	{
+		.start	= AP2MDM_ERRFATAL,
+		.end	= AP2MDM_ERRFATAL,
+		.name	= "AP2MDM_ERRFATAL",
+		.flags	= IORESOURCE_IO,
+	},
+	{
+		.start	= MDM2AP_STATUS,
+		.end	= MDM2AP_STATUS,
+		.name	= "MDM2AP_STATUS",
+		.flags	= IORESOURCE_IO,
+	},
+	{
+		.start	= AP2MDM_STATUS,
+		.end	= AP2MDM_STATUS,
+		.name	= "AP2MDM_STATUS",
+		.flags	= IORESOURCE_IO,
+	},
+	{
+		.start	= AP2MDM_PMIC_PWR_EN,
+		.end	= AP2MDM_PMIC_PWR_EN,
+		.name	= "AP2MDM_PMIC_PWR_EN",
+		.flags	= IORESOURCE_IO,
+	},
+	{
+		.start	= AP2MDM_KPDPWR_N,
+		.end	= AP2MDM_KPDPWR_N,
+		.name	= "AP2MDM_KPDPWR_N",
+		.flags	= IORESOURCE_IO,
+	},
+	{
+		.start	= AP2MDM_SOFT_RESET,
+		.end	= AP2MDM_SOFT_RESET,
+		.name	= "AP2MDM_SOFT_RESET",
+		.flags	= IORESOURCE_IO,
+	},
+};
+
+struct platform_device mdm_sglte_device = {
+	.name		= "mdm2_modem",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(sglte_resources),
+	.resource	= sglte_resources,
+};
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index c084d29..85d00eb 100644
--- a/arch/arm/mach-msm/devices-9615.c
+++ b/arch/arm/mach-msm/devices-9615.c
@@ -62,6 +62,9 @@
 #define MSM_PMIC1_SSBI_CMD_PHYS	0x00500000
 #define MSM_PMIC_SSBI_SIZE	SZ_4K
 
+#define MSM_GPIO_I2C_CLK 16
+#define MSM_GPIO_I2C_SDA 17
+
 static struct msm_watchdog_pdata msm_watchdog_pdata = {
 	.pet_time = 10000,
 	.bark_time = 11000,
@@ -132,6 +135,8 @@
 	},
 };
 
+#define MSM_HSUSB_RESUME_GPIO	79
+
 static struct resource resources_hsusb[] = {
 	{
 		.start	= MSM9615_HSUSB_PHYS,
@@ -143,6 +148,12 @@
 		.end	= USB1_HS_IRQ,
 		.flags	= IORESOURCE_IRQ,
 	},
+	{
+		.start	= MSM_HSUSB_RESUME_GPIO,
+		.end	= MSM_HSUSB_RESUME_GPIO,
+		.name	= "USB_RESUME",
+		.flags	= IORESOURCE_IO,
+	},
 };
 
 static struct resource resources_usb_bam[] = {
@@ -307,6 +318,19 @@
 		.end	= GSBI5_QUP_IRQ,
 		.flags	= IORESOURCE_IRQ,
 	},
+	{
+		.name   = "i2c_clk",
+		.start     = MSM_GPIO_I2C_CLK,
+		.end       = MSM_GPIO_I2C_CLK,
+		.flags     = IORESOURCE_IO,
+	},
+	{
+		.name   = "i2c_sda",
+		.start     = MSM_GPIO_I2C_SDA,
+		.end       = MSM_GPIO_I2C_SDA,
+		.flags     = IORESOURCE_IO,
+
+	},
 };
 
 struct platform_device msm9615_device_qup_i2c_gsbi5 = {
@@ -432,13 +456,24 @@
  */
 struct msm_dai_auxpcm_pdata auxpcm_pdata = {
 	.clk = "pcm_clk",
-	.mode = AFE_PCM_CFG_MODE_PCM,
-	.sync = AFE_PCM_CFG_SYNC_INT,
-	.frame = AFE_PCM_CFG_FRM_256BPF,
-	.quant = AFE_PCM_CFG_QUANT_LINEAR_NOPAD,
-	.slot = 0,
-	.data = AFE_PCM_CFG_CDATAOE_MASTER,
-	.pcm_clk_rate = 2048000,
+	.mode_8k = {
+		.mode = AFE_PCM_CFG_MODE_PCM,
+		.sync = AFE_PCM_CFG_SYNC_INT,
+		.frame = AFE_PCM_CFG_FRM_256BPF,
+		.quant = AFE_PCM_CFG_QUANT_LINEAR_NOPAD,
+		.slot = 0,
+		.data = AFE_PCM_CFG_CDATAOE_MASTER,
+		.pcm_clk_rate = 2048000,
+	},
+	.mode_16k = {
+		.mode = AFE_PCM_CFG_MODE_PCM,
+		.sync = AFE_PCM_CFG_SYNC_INT,
+		.frame = AFE_PCM_CFG_FRM_256BPF,
+		.quant = AFE_PCM_CFG_QUANT_LINEAR_NOPAD,
+		.slot = 0,
+		.data = AFE_PCM_CFG_CDATAOE_MASTER,
+		.pcm_clk_rate = 4096000,
+	}
 };
 
 struct platform_device msm_cpudai_auxpcm_rx = {
@@ -472,6 +507,15 @@
 	.id	= -1,
 };
 
+struct platform_device msm_i2s_cpudai0 = {
+	.name   = "msm-dai-q6",
+	.id     = PRIMARY_I2S_RX,
+};
+
+struct platform_device msm_i2s_cpudai1 = {
+	.name   = "msm-dai-q6",
+	.id     = PRIMARY_I2S_TX,
+};
 struct platform_device msm_voip = {
 	.name	= "msm-voip-dsp",
 	.id	= -1,
@@ -583,8 +627,7 @@
 };
 
 struct flash_platform_data msm_nand_data = {
-	.parts		= NULL,
-	.nr_parts	= 0,
+	.version = VERSION_2,
 };
 
 struct platform_device msm_device_nand = {
diff --git a/arch/arm/mach-msm/devices-iommu.c b/arch/arm/mach-msm/devices-iommu.c
index 9a03afd..f5676d3 100644
--- a/arch/arm/mach-msm/devices-iommu.c
+++ b/arch/arm/mach-msm/devices-iommu.c
@@ -568,26 +568,26 @@
 	.mids = {1, -1}
 };
 
-static struct msm_iommu_ctx_dev mdp_vg1_ctx = {
-	.name = "mdp_vg1",
+static struct msm_iommu_ctx_dev mdp_port0_cb0_ctx = {
+	.name = "mdp_port0_cb0",
 	.num = 0,
 	.mids = {0, 2, -1}
 };
 
-static struct msm_iommu_ctx_dev mdp_rgb1_ctx = {
-	.name = "mdp_rgb1",
+static struct msm_iommu_ctx_dev mdp_port0_cb1_ctx = {
+	.name = "mdp_port0_cb1",
 	.num = 1,
 	.mids = {1, 3, 4, 5, 6, 7, 8, 9, 10, -1}
 };
 
-static struct msm_iommu_ctx_dev mdp_vg2_ctx = {
-	.name = "mdp_vg2",
+static struct msm_iommu_ctx_dev mdp_port1_cb0_ctx = {
+	.name = "mdp_port1_cb0",
 	.num = 0,
 	.mids = {0, 2, -1}
 };
 
-static struct msm_iommu_ctx_dev mdp_rgb2_ctx = {
-	.name = "mdp_rgb2",
+static struct msm_iommu_ctx_dev mdp_port1_cb1_ctx = {
+	.name = "mdp_port1_cb1",
 	.num = 1,
 	.mids = {1, 3, 4, 5, 6, 7, 8, 9, 10, -1}
 };
@@ -732,39 +732,39 @@
 	},
 };
 
-static struct platform_device msm_device_mdp_vg1_ctx = {
+static struct platform_device msm_device_mdp_port0_cb0_ctx = {
 	.name = "msm_iommu_ctx",
 	.id = 4,
 	.dev = {
 		.parent = &msm_device_iommu_mdp0.dev,
-		.platform_data = &mdp_vg1_ctx,
+		.platform_data = &mdp_port0_cb0_ctx,
 	},
 };
 
-static struct platform_device msm_device_mdp_rgb1_ctx = {
+static struct platform_device msm_device_mdp_port0_cb1_ctx = {
 	.name = "msm_iommu_ctx",
 	.id = 5,
 	.dev = {
 		.parent = &msm_device_iommu_mdp0.dev,
-		.platform_data = &mdp_rgb1_ctx,
+		.platform_data = &mdp_port0_cb1_ctx,
 	},
 };
 
-static struct platform_device msm_device_mdp_vg2_ctx = {
+static struct platform_device msm_device_mdp_port1_cb0_ctx = {
 	.name = "msm_iommu_ctx",
 	.id = 6,
 	.dev = {
 		.parent = &msm_device_iommu_mdp1.dev,
-		.platform_data = &mdp_vg2_ctx,
+		.platform_data = &mdp_port1_cb0_ctx,
 	},
 };
 
-static struct platform_device msm_device_mdp_rgb2_ctx = {
+static struct platform_device msm_device_mdp_port1_cb1_ctx = {
 	.name = "msm_iommu_ctx",
 	.id = 7,
 	.dev = {
 		.parent = &msm_device_iommu_mdp1.dev,
-		.platform_data = &mdp_rgb2_ctx,
+		.platform_data = &mdp_port1_cb1_ctx,
 	},
 };
 
@@ -950,10 +950,10 @@
 static struct platform_device *msm_iommu_common_ctx_devs[] = {
 	&msm_device_vpe_src_ctx,
 	&msm_device_vpe_dst_ctx,
-	&msm_device_mdp_vg1_ctx,
-	&msm_device_mdp_rgb1_ctx,
-	&msm_device_mdp_vg2_ctx,
-	&msm_device_mdp_rgb2_ctx,
+	&msm_device_mdp_port0_cb0_ctx,
+	&msm_device_mdp_port0_cb1_ctx,
+	&msm_device_mdp_port1_cb0_ctx,
+	&msm_device_mdp_port1_cb1_ctx,
 	&msm_device_rot_src_ctx,
 	&msm_device_rot_dst_ctx,
 	&msm_device_ijpeg_src_ctx,
@@ -987,8 +987,8 @@
 static int __init iommu_init(void)
 {
 	int ret;
-	if (!msm_soc_version_supports_iommu()) {
-		pr_err("IOMMU is not supported on this SoC version.\n");
+	if (!msm_soc_version_supports_iommu_v1()) {
+		pr_err("IOMMU v1 is not supported on this SoC version.\n");
 		return -ENODEV;
 	}
 
diff --git a/arch/arm/mach-msm/devices-msm7x27a.c b/arch/arm/mach-msm/devices-msm7x27a.c
index 2d79f62..4654606 100644
--- a/arch/arm/mach-msm/devices-msm7x27a.c
+++ b/arch/arm/mach-msm/devices-msm7x27a.c
@@ -417,7 +417,9 @@
 	},
 };
 
-struct flash_platform_data msm_nand_data;
+struct flash_platform_data msm_nand_data = {
+	.version = VERSION_2,
+};
 
 struct platform_device msm_device_nand = {
 	.name		= "msm_nand",
diff --git a/arch/arm/mach-msm/devices-msm7x30.c b/arch/arm/mach-msm/devices-msm7x30.c
index e055579..069714a 100644
--- a/arch/arm/mach-msm/devices-msm7x30.c
+++ b/arch/arm/mach-msm/devices-msm7x30.c
@@ -656,9 +656,7 @@
 };
 
 struct flash_platform_data msm_nand_data = {
-	.parts		= NULL,
-	.nr_parts	= 0,
-	.interleave     = 0,
+	.version = VERSION_2,
 };
 
 struct platform_device msm_device_nand = {
diff --git a/arch/arm/mach-msm/devices-msm8x60.c b/arch/arm/mach-msm/devices-msm8x60.c
index d622af2..005ed1f 100644
--- a/arch/arm/mach-msm/devices-msm8x60.c
+++ b/arch/arm/mach-msm/devices-msm8x60.c
@@ -1568,6 +1568,16 @@
 /* Sensors DSPS platform data */
 #ifdef CONFIG_MSM_DSPS
 
+#define PPSS_DSPS_TCM_CODE_BASE 0x12000000
+#define PPSS_DSPS_TCM_CODE_SIZE 0x28000
+#define PPSS_DSPS_TCM_BUF_BASE  0x12040000
+#define PPSS_DSPS_TCM_BUF_SIZE  0x4000
+#define PPSS_DSPS_PIPE_BASE     0x12800000
+#define PPSS_DSPS_PIPE_SIZE     0x0 /* 8660 V2 does not use PIPE memory */
+#define PPSS_DSPS_DDR_BASE      0x8fe00000
+#define PPSS_DSPS_DDR_SIZE      0x0 /* 8660 V2 does not use DDR memory */
+#define PPSS_SMEM_BASE          0x40000000
+#define PPSS_SMEM_SIZE          0x4000
 #define PPSS_REG_PHYS_BASE	0x12080000
 
 #define MHZ (1000*1000)
@@ -1631,6 +1641,16 @@
 	.regs = dsps_regs,
 	.regs_num = ARRAY_SIZE(dsps_regs),
 	.init = dsps_init1,
+	.tcm_code_start = PPSS_DSPS_TCM_CODE_BASE,
+	.tcm_code_size = PPSS_DSPS_TCM_CODE_SIZE,
+	.tcm_buf_start = PPSS_DSPS_TCM_BUF_BASE,
+	.tcm_buf_size = PPSS_DSPS_TCM_BUF_SIZE,
+	.pipe_start = PPSS_DSPS_PIPE_BASE,
+	.pipe_size = PPSS_DSPS_PIPE_SIZE,
+	.ddr_start = PPSS_DSPS_DDR_BASE,
+	.ddr_size = PPSS_DSPS_DDR_SIZE,
+	.smem_start = PPSS_SMEM_BASE,
+	.smem_size  = PPSS_SMEM_SIZE,
 	.signature = DSPS_SIGNATURE,
 };
 
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 31142c1..4fd262f 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -167,6 +167,8 @@
 extern struct platform_device msm_device_dmov_adm0;
 extern struct platform_device msm_device_dmov_adm1;
 
+extern struct platform_device msm_device_pcie;
+
 extern struct platform_device msm_device_nand;
 
 extern struct platform_device msm_device_tssc;
@@ -223,6 +225,8 @@
 extern struct platform_device msm_cpudai_incall_music_rx;
 extern struct platform_device msm_cpudai_incall_record_rx;
 extern struct platform_device msm_cpudai_incall_record_tx;
+extern struct platform_device msm_i2s_cpudai0;
+extern struct platform_device msm_i2s_cpudai1;
 
 extern struct platform_device msm_pil_q6v3;
 extern struct platform_device msm_pil_modem;
@@ -265,6 +269,7 @@
 extern struct platform_device apq_cpudai_slimbus_1_tx;
 extern struct platform_device apq_cpudai_slimbus_2_tx;
 extern struct platform_device apq_cpudai_slimbus_3_rx;
+extern struct platform_device apq_cpudai_slimbus_3_tx;
 extern struct platform_device apq_cpudai_slim_4_rx;
 extern struct platform_device apq_cpudai_slim_4_tx;
 
@@ -392,3 +397,10 @@
 extern struct platform_device apq8064_rtb_device;
 
 extern struct platform_device msm8960_cache_dump_device;
+extern struct platform_device apq8064_cache_dump_device;
+
+extern struct platform_device copper_device_tz_log;
+
+extern struct platform_device mdm_sglte_device;
+
+extern struct platform_device apq_device_tz_log;
diff --git a/arch/arm/mach-msm/dma.c b/arch/arm/mach-msm/dma.c
index d433b9e..d3b2274 100644
--- a/arch/arm/mach-msm/dma.c
+++ b/arch/arm/mach-msm/dma.c
@@ -59,20 +59,19 @@
 	int channel_active;
 	int sd;
 	size_t sd_size;
-	struct list_head staged_commands[MSM_DMOV_CHANNEL_COUNT];
 	struct list_head ready_commands[MSM_DMOV_CHANNEL_COUNT];
 	struct list_head active_commands[MSM_DMOV_CHANNEL_COUNT];
-	struct mutex lock;
-	spinlock_t list_lock;
+	spinlock_t lock;
 	unsigned int irq;
 	struct clk *clk;
 	struct clk *pclk;
 	struct clk *ebiclk;
 	unsigned int clk_ctl;
-	struct delayed_work work;
+	struct timer_list timer;
 };
 
-static void msm_dmov_clock_work(struct work_struct *);
+static void msm_dmov_clock_timer(unsigned long);
+static int msm_dmov_clk_toggle(int, int);
 
 #ifdef CONFIG_ARCH_MSM8X60
 
@@ -164,19 +163,15 @@
 	{
 		.crci_conf = adm0_crci_conf,
 		.chan_conf = adm0_chan_conf,
-		.lock = __MUTEX_INITIALIZER(dmov_conf[0].lock),
-		.list_lock = __SPIN_LOCK_UNLOCKED(dmov_list_lock),
+		.lock = __SPIN_LOCK_UNLOCKED(dmov_lock),
 		.clk_ctl = CLK_DIS,
-		.work = __DELAYED_WORK_INITIALIZER(dmov_conf[0].work,
-				msm_dmov_clock_work),
+		.timer = TIMER_INITIALIZER(msm_dmov_clock_timer, 0, 0),
 	}, {
 		.crci_conf = adm1_crci_conf,
 		.chan_conf = adm1_chan_conf,
-		.lock = __MUTEX_INITIALIZER(dmov_conf[1].lock),
-		.list_lock = __SPIN_LOCK_UNLOCKED(dmov_list_lock),
+		.lock = __SPIN_LOCK_UNLOCKED(dmov_lock),
 		.clk_ctl = CLK_DIS,
-		.work = __DELAYED_WORK_INITIALIZER(dmov_conf[1].work,
-				msm_dmov_clock_work),
+		.timer = TIMER_INITIALIZER(msm_dmov_clock_timer, 0, 1),
 	}
 };
 #else
@@ -184,11 +179,9 @@
 	{
 		.crci_conf = NULL,
 		.chan_conf = NULL,
-		.lock = __MUTEX_INITIALIZER(dmov_conf[0].lock),
-		.list_lock = __SPIN_LOCK_UNLOCKED(dmov_list_lock),
+		.lock = __SPIN_LOCK_UNLOCKED(dmov_lock),
 		.clk_ctl = CLK_DIS,
-		.work = __DELAYED_WORK_INITIALIZER(dmov_conf[0].work,
-				msm_dmov_clock_work),
+		.timer = TIMER_INITIALIZER(msm_dmov_clock_timer, 0, 0),
 	}
 };
 #endif
@@ -230,153 +223,94 @@
 #define PRINT_FLOW(format, args...) \
 	MSM_DMOV_DPRINTF(MSM_DMOV_PRINT_FLOW, format, args);
 
-static int msm_dmov_clk_on(int adm)
+static int msm_dmov_clk_toggle(int adm, int on)
 {
-	int ret;
+	int ret = 0;
 
-	ret = clk_prepare_enable(dmov_conf[adm].clk);
-	if (ret)
-		return ret;
-	if (dmov_conf[adm].pclk) {
-		ret = clk_prepare_enable(dmov_conf[adm].pclk);
-		if (ret) {
-			clk_disable_unprepare(dmov_conf[adm].clk);
-			return ret;
+	if (on) {
+		ret = clk_enable(dmov_conf[adm].clk);
+		if (ret)
+			goto err;
+		if (dmov_conf[adm].pclk) {
+			ret = clk_enable(dmov_conf[adm].pclk);
+			if (ret) {
+				clk_disable(dmov_conf[adm].clk);
+				goto err;
+			}
 		}
-	}
-	if (dmov_conf[adm].ebiclk) {
-		ret = clk_prepare_enable(dmov_conf[adm].ebiclk);
-		if (ret) {
-			if (dmov_conf[adm].pclk)
-				clk_disable_unprepare(dmov_conf[adm].pclk);
-			clk_disable_unprepare(dmov_conf[adm].clk);
+		if (dmov_conf[adm].ebiclk) {
+			ret = clk_enable(dmov_conf[adm].ebiclk);
+			if (ret) {
+				if (dmov_conf[adm].pclk)
+					clk_disable(dmov_conf[adm].pclk);
+				clk_disable(dmov_conf[adm].clk);
+			}
 		}
+	} else {
+		clk_disable(dmov_conf[adm].clk);
+		if (dmov_conf[adm].pclk)
+			clk_disable(dmov_conf[adm].pclk);
+		if (dmov_conf[adm].ebiclk)
+			clk_disable(dmov_conf[adm].ebiclk);
 	}
+err:
 	return ret;
 }
 
-static void msm_dmov_clk_off(int adm)
+static void msm_dmov_clock_timer(unsigned long adm)
 {
-	clk_disable_unprepare(dmov_conf[adm].clk);
-	if (dmov_conf[adm].pclk)
-		clk_disable_unprepare(dmov_conf[adm].pclk);
-	if (dmov_conf[adm].ebiclk)
-		clk_disable_unprepare(dmov_conf[adm].ebiclk);
-}
-
-static void msm_dmov_clock_work(struct work_struct *work)
-{
-	struct msm_dmov_conf *conf =
-		container_of(to_delayed_work(work), struct msm_dmov_conf, work);
-	int adm = DMOV_IRQ_TO_ADM(conf->irq);
-	mutex_lock(&conf->lock);
-	if (conf->clk_ctl == CLK_TO_BE_DIS) {
-		BUG_ON(conf->channel_active);
-		msm_dmov_clk_off(adm);
-		conf->clk_ctl = CLK_DIS;
+	unsigned long irq_flags;
+	spin_lock_irqsave(&dmov_conf[adm].lock, irq_flags);
+	if (dmov_conf[adm].clk_ctl == CLK_TO_BE_DIS) {
+		BUG_ON(dmov_conf[adm].channel_active);
+		msm_dmov_clk_toggle(adm, 0);
+		dmov_conf[adm].clk_ctl = CLK_DIS;
 	}
-	mutex_unlock(&conf->lock);
-}
-
-enum {
-	NOFLUSH = 0,
-	GRACEFUL,
-	NONGRACEFUL,
-};
-
-/* Caller must hold the list lock */
-static struct msm_dmov_cmd *start_ready_cmd(unsigned ch, int adm)
-{
-	struct msm_dmov_cmd *cmd;
-
-	if (list_empty(&dmov_conf[adm].ready_commands[ch]))
-		return NULL;
-
-	cmd = list_entry(dmov_conf[adm].ready_commands[ch].next, typeof(*cmd),
-			 list);
-	list_del(&cmd->list);
-	if (cmd->exec_func)
-		cmd->exec_func(cmd);
-	list_add_tail(&cmd->list, &dmov_conf[adm].active_commands[ch]);
-	if (!dmov_conf[adm].channel_active)
-		enable_irq(dmov_conf[adm].irq);
-	dmov_conf[adm].channel_active |= BIT(ch);
-	PRINT_IO("msm dmov enqueue command, %x, ch %d\n", cmd->cmdptr, ch);
-	writel_relaxed(cmd->cmdptr, DMOV_REG(DMOV_CMD_PTR(ch), adm));
-
-	return cmd;
-}
-
-static void msm_dmov_enqueue_cmd_ext_work(struct work_struct *work)
-{
-	struct msm_dmov_cmd *cmd =
-		container_of(work, struct msm_dmov_cmd, work);
-	unsigned id = cmd->id;
-	unsigned status;
-	unsigned long flags;
-	int adm = DMOV_ID_TO_ADM(id);
-	int ch = DMOV_ID_TO_CHAN(id);
-
-	mutex_lock(&dmov_conf[adm].lock);
-	if (dmov_conf[adm].clk_ctl == CLK_DIS) {
-		status = msm_dmov_clk_on(adm);
-		if (status != 0)
-			goto error;
-	} else if (dmov_conf[adm].clk_ctl == CLK_TO_BE_DIS)
-		cancel_delayed_work_sync(&dmov_conf[adm].work);
-	dmov_conf[adm].clk_ctl = CLK_EN;
-
-	spin_lock_irqsave(&dmov_conf[adm].list_lock, flags);
-
-	cmd = list_entry(dmov_conf[adm].staged_commands[ch].next, typeof(*cmd),
-			 list);
-	list_del(&cmd->list);
-	list_add_tail(&cmd->list, &dmov_conf[adm].ready_commands[ch]);
-	status = readl_relaxed(DMOV_REG(DMOV_STATUS(ch), adm));
-	if (status & DMOV_STATUS_CMD_PTR_RDY) {
-		PRINT_IO("msm_dmov_enqueue_cmd(%d), start command, status %x\n",
-			id, status);
-		cmd = start_ready_cmd(ch, adm);
-		/*
-		 * We added something to the ready list, and still hold the
-		 * list lock. Thus, no need to check for cmd == NULL
-		 */
-		if (cmd->toflush) {
-			int flush = (cmd->toflush == GRACEFUL) ? 1 << 31 : 0;
-			writel_relaxed(flush, DMOV_REG(DMOV_FLUSH0(ch), adm));
-		}
-	} else {
-		cmd->toflush = 0;
-		if (list_empty(&dmov_conf[adm].active_commands[ch]) &&
-		    !list_empty(&dmov_conf[adm].ready_commands[ch]))
-			PRINT_ERROR("msm_dmov_enqueue_cmd_ext(%d), stalled, "
-				"status %x\n", id, status);
-		PRINT_IO("msm_dmov_enqueue_cmd(%d), enqueue command, status "
-		    "%x\n", id, status);
-	}
-	if (!dmov_conf[adm].channel_active) {
-		dmov_conf[adm].clk_ctl = CLK_TO_BE_DIS;
-		schedule_delayed_work(&dmov_conf[adm].work, HZ);
-	}
-	spin_unlock_irqrestore(&dmov_conf[adm].list_lock, flags);
-error:
-	mutex_unlock(&dmov_conf[adm].lock);
+	spin_unlock_irqrestore(&dmov_conf[adm].lock, irq_flags);
 }
 
 void msm_dmov_enqueue_cmd_ext(unsigned id, struct msm_dmov_cmd *cmd)
 {
+	unsigned long irq_flags;
+	unsigned int status;
 	int adm = DMOV_ID_TO_ADM(id);
 	int ch = DMOV_ID_TO_CHAN(id);
-	unsigned long flags;
-	cmd->id = id;
-	cmd->toflush = 0;
-	INIT_WORK(&cmd->work, msm_dmov_enqueue_cmd_ext_work);
 
-	spin_lock_irqsave(&dmov_conf[adm].list_lock, flags);
-	list_add_tail(&cmd->list, &dmov_conf[adm].staged_commands[ch]);
-	spin_unlock_irqrestore(&dmov_conf[adm].list_lock, flags);
+	spin_lock_irqsave(&dmov_conf[adm].lock, irq_flags);
+	if (dmov_conf[adm].clk_ctl == CLK_DIS) {
+		status = msm_dmov_clk_toggle(adm, 1);
+		if (status != 0)
+			goto error;
+	} else if (dmov_conf[adm].clk_ctl == CLK_TO_BE_DIS)
+		del_timer(&dmov_conf[adm].timer);
+	dmov_conf[adm].clk_ctl = CLK_EN;
 
-	schedule_work(&cmd->work);
+	status = readl_relaxed(DMOV_REG(DMOV_STATUS(ch), adm));
+	if (status & DMOV_STATUS_CMD_PTR_RDY) {
+		PRINT_IO("msm_dmov_enqueue_cmd(%d), start command, status %x\n",
+			id, status);
+		if (cmd->exec_func)
+			cmd->exec_func(cmd);
+		list_add_tail(&cmd->list, &dmov_conf[adm].active_commands[ch]);
+		if (!dmov_conf[adm].channel_active)
+			enable_irq(dmov_conf[adm].irq);
+		dmov_conf[adm].channel_active |= 1U << ch;
+		PRINT_IO("Writing %x exactly to register", cmd->cmdptr);
+		writel_relaxed(cmd->cmdptr, DMOV_REG(DMOV_CMD_PTR(ch), adm));
+	} else {
+		if (!dmov_conf[adm].channel_active) {
+			dmov_conf[adm].clk_ctl = CLK_TO_BE_DIS;
+			mod_timer(&dmov_conf[adm].timer, jiffies + HZ);
+		}
+		if (list_empty(&dmov_conf[adm].active_commands[ch]))
+			PRINT_ERROR("msm_dmov_enqueue_cmd_ext(%d), stalled, "
+				"status %x\n", id, status);
+		PRINT_IO("msm_dmov_enqueue_cmd(%d), enqueue command, status "
+		    "%x\n", id, status);
+		list_add_tail(&cmd->list, &dmov_conf[adm].ready_commands[ch]);
+	}
+error:
+	spin_unlock_irqrestore(&dmov_conf[adm].lock, irq_flags);
 }
 EXPORT_SYMBOL(msm_dmov_enqueue_cmd_ext);
 
@@ -395,18 +329,14 @@
 	int ch = DMOV_ID_TO_CHAN(id);
 	int adm = DMOV_ID_TO_ADM(id);
 	int flush = graceful ? DMOV_FLUSH_TYPE : 0;
-	struct msm_dmov_cmd *cmd;
-
-	spin_lock_irqsave(&dmov_conf[adm].list_lock, irq_flags);
+	spin_lock_irqsave(&dmov_conf[adm].lock, irq_flags);
 	/* XXX not checking if flush cmd sent already */
 	if (!list_empty(&dmov_conf[adm].active_commands[ch])) {
 		PRINT_IO("msm_dmov_flush(%d), send flush cmd\n", id);
 		writel_relaxed(flush, DMOV_REG(DMOV_FLUSH0(ch), adm));
 	}
-	list_for_each_entry(cmd, &dmov_conf[adm].staged_commands[ch], list)
-		cmd->toflush = graceful ? GRACEFUL : NONGRACEFUL;
 	/* spin_unlock_irqrestore has the necessary barrier */
-	spin_unlock_irqrestore(&dmov_conf[adm].list_lock, irq_flags);
+	spin_unlock_irqrestore(&dmov_conf[adm].lock, irq_flags);
 }
 EXPORT_SYMBOL(msm_dmov_flush);
 
@@ -468,7 +398,7 @@
 	errdata->flush[5] = readl_relaxed(DMOV_REG(DMOV_FLUSH5(ch), adm));
 }
 
-static irqreturn_t msm_dmov_isr(int irq, void *dev_id)
+static irqreturn_t msm_datamover_irq_handler(int irq, void *dev_id)
 {
 	unsigned int int_status;
 	unsigned int mask;
@@ -481,12 +411,11 @@
 	struct msm_dmov_cmd *cmd;
 	int adm = DMOV_IRQ_TO_ADM(irq);
 
-	mutex_lock(&dmov_conf[adm].lock);
+	spin_lock_irqsave(&dmov_conf[adm].lock, irq_flags);
 	/* read and clear isr */
 	int_status = readl_relaxed(DMOV_REG(DMOV_ISR, adm));
 	PRINT_FLOW("msm_datamover_irq_handler: DMOV_ISR %x\n", int_status);
 
-	spin_lock_irqsave(&dmov_conf[adm].list_lock, irq_flags);
 	while (int_status) {
 		mask = int_status & -int_status;
 		ch = fls(mask) - 1;
@@ -554,38 +483,51 @@
 			ch_status = readl_relaxed(DMOV_REG(DMOV_STATUS(ch),
 						  adm));
 			PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", id, ch_status);
-			if (ch_status & DMOV_STATUS_CMD_PTR_RDY)
-				start_ready_cmd(ch, adm);
+			if ((ch_status & DMOV_STATUS_CMD_PTR_RDY) &&
+			    !list_empty(&dmov_conf[adm].ready_commands[ch])) {
+				cmd = list_entry(dmov_conf[adm].
+					ready_commands[ch].next, typeof(*cmd),
+					list);
+				list_del(&cmd->list);
+				if (cmd->exec_func)
+					cmd->exec_func(cmd);
+				list_add_tail(&cmd->list,
+					&dmov_conf[adm].active_commands[ch]);
+				PRINT_FLOW("msm_datamover_irq_handler id %d,"
+						 "start command\n", id);
+				writel_relaxed(cmd->cmdptr,
+					       DMOV_REG(DMOV_CMD_PTR(ch), adm));
+			}
 		} while (ch_status & DMOV_STATUS_RSLT_VALID);
 		if (list_empty(&dmov_conf[adm].active_commands[ch]) &&
-		    list_empty(&dmov_conf[adm].ready_commands[ch]))
+				list_empty(&dmov_conf[adm].ready_commands[ch]))
 			dmov_conf[adm].channel_active &= ~(1U << ch);
 		PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", id, ch_status);
 	}
-	spin_unlock_irqrestore(&dmov_conf[adm].list_lock, irq_flags);
 
 	if (!dmov_conf[adm].channel_active && valid) {
 		disable_irq_nosync(dmov_conf[adm].irq);
 		dmov_conf[adm].clk_ctl = CLK_TO_BE_DIS;
-		schedule_delayed_work(&dmov_conf[adm].work, HZ);
+		mod_timer(&dmov_conf[adm].timer, jiffies + HZ);
 	}
 
-	mutex_unlock(&dmov_conf[adm].lock);
+	spin_unlock_irqrestore(&dmov_conf[adm].lock, irq_flags);
 	return valid ? IRQ_HANDLED : IRQ_NONE;
 }
 
 static int msm_dmov_suspend_late(struct device *dev)
 {
+	unsigned long irq_flags;
 	struct platform_device *pdev = to_platform_device(dev);
 	int adm = (pdev->id >= 0) ? pdev->id : 0;
-	mutex_lock(&dmov_conf[adm].lock);
+	spin_lock_irqsave(&dmov_conf[adm].lock, irq_flags);
 	if (dmov_conf[adm].clk_ctl == CLK_TO_BE_DIS) {
 		BUG_ON(dmov_conf[adm].channel_active);
-		cancel_delayed_work_sync(&dmov_conf[adm].work);
-		msm_dmov_clk_off(adm);
+		del_timer(&dmov_conf[adm].timer);
+		msm_dmov_clk_toggle(adm, 0);
 		dmov_conf[adm].clk_ctl = CLK_DIS;
 	}
-	mutex_unlock(&dmov_conf[adm].lock);
+	spin_unlock_irqrestore(&dmov_conf[adm].lock, irq_flags);
 	return 0;
 }
 
@@ -700,8 +642,8 @@
 	if (!dmov_conf[adm].base)
 		return -ENOMEM;
 
-	ret = request_threaded_irq(dmov_conf[adm].irq, NULL, msm_dmov_isr,
-				   IRQF_ONESHOT, "msmdatamover", NULL);
+	ret = request_irq(dmov_conf[adm].irq, msm_datamover_irq_handler,
+		0, "msmdatamover", NULL);
 	if (ret) {
 		PRINT_ERROR("Requesting ADM%d irq %d failed\n", adm,
 			dmov_conf[adm].irq);
@@ -713,7 +655,7 @@
 		PRINT_ERROR("Requesting ADM%d clocks failed\n", adm);
 		goto out_irq;
 	}
-	ret = msm_dmov_clk_on(adm);
+	ret = msm_dmov_clk_toggle(adm, 1);
 	if (ret) {
 		PRINT_ERROR("Enabling ADM%d clocks failed\n", adm);
 		goto out_irq;
@@ -721,7 +663,6 @@
 
 	config_datamover(adm);
 	for (i = 0; i < MSM_DMOV_CHANNEL_COUNT; i++) {
-		INIT_LIST_HEAD(&dmov_conf[adm].staged_commands[i]);
 		INIT_LIST_HEAD(&dmov_conf[adm].ready_commands[i]);
 		INIT_LIST_HEAD(&dmov_conf[adm].active_commands[i]);
 
@@ -730,7 +671,7 @@
 		     DMOV_REG(DMOV_RSLT_CONF(i), adm));
 	}
 	wmb();
-	msm_dmov_clk_off(adm);
+	msm_dmov_clk_toggle(adm, 0);
 	return ret;
 out_irq:
 	free_irq(dmov_conf[adm].irq, NULL);
diff --git a/arch/arm/mach-msm/gdsc.c b/arch/arm/mach-msm/gdsc.c
new file mode 100644
index 0000000..a77ac24
--- /dev/null
+++ b/arch/arm/mach-msm/gdsc.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+
+#define PWR_ON_MASK		BIT(31)
+#define EN_REST_WAIT_MASK	(0xF << 20)
+#define EN_FEW_WAIT_MASK	(0xF << 16)
+#define CLK_DIS_WAIT_MASK	(0xF << 12)
+#define SW_OVERRIDE_MASK	BIT(2)
+#define HW_CONTROL_MASK		BIT(1)
+#define SW_COLLAPSE_MASK	BIT(0)
+
+/* Wait 2^n CXO cycles between all states. Here, n=2 (4 cycles). */
+#define EN_REST_WAIT_VAL	(0x2 << 20)
+#define EN_FEW_WAIT_VAL		(0x2 << 16)
+#define CLK_DIS_WAIT_VAL	(0x2 << 12)
+
+#define TIMEOUT_US		10
+
+struct gdsc {
+	struct regulator_dev	*rdev;
+	struct regulator_desc	rdesc;
+	void __iomem		*gdscr;
+};
+
+static int gdsc_is_enabled(struct regulator_dev *rdev)
+{
+	struct gdsc *sc = rdev_get_drvdata(rdev);
+
+	return !!(readl_relaxed(sc->gdscr) & PWR_ON_MASK);
+}
+
+static int gdsc_enable(struct regulator_dev *rdev)
+{
+	struct gdsc *sc = rdev_get_drvdata(rdev);
+	uint32_t regval;
+	int ret;
+
+	regval = readl_relaxed(sc->gdscr);
+	regval &= ~SW_COLLAPSE_MASK;
+	writel_relaxed(regval, sc->gdscr);
+
+	ret = readl_tight_poll_timeout(sc->gdscr, regval, regval & PWR_ON_MASK,
+				       TIMEOUT_US);
+	if (ret)
+		dev_err(&rdev->dev, "%s enable timed out\n", sc->rdesc.name);
+
+	return ret;
+}
+
+static int gdsc_disable(struct regulator_dev *rdev)
+{
+	struct gdsc *sc = rdev_get_drvdata(rdev);
+	uint32_t regval;
+	int ret;
+
+	regval = readl_relaxed(sc->gdscr);
+	regval |= SW_COLLAPSE_MASK;
+	writel_relaxed(regval, sc->gdscr);
+
+	ret = readl_tight_poll_timeout(sc->gdscr, regval,
+				       !(regval & PWR_ON_MASK), TIMEOUT_US);
+	if (ret)
+		dev_err(&rdev->dev, "%s disable timed out\n", sc->rdesc.name);
+
+	return ret;
+}
+
+static struct regulator_ops gdsc_ops = {
+	.is_enabled = gdsc_is_enabled,
+	.enable = gdsc_enable,
+	.disable = gdsc_disable,
+};
+
+static int __devinit gdsc_probe(struct platform_device *pdev)
+{
+	static atomic_t gdsc_count = ATOMIC_INIT(-1);
+	struct regulator_init_data *init_data;
+	struct resource *res;
+	struct gdsc *sc;
+	uint32_t regval;
+	int ret;
+
+	sc = devm_kzalloc(&pdev->dev, sizeof(struct gdsc), GFP_KERNEL);
+	if (sc == NULL)
+		return -ENOMEM;
+
+	init_data = of_get_regulator_init_data(&pdev->dev);
+	if (init_data == NULL)
+		return -ENOMEM;
+
+	if (of_get_property(pdev->dev.of_node, "parent-supply", NULL))
+		init_data->supply_regulator = "parent";
+
+	ret = of_property_read_string(pdev->dev.of_node, "regulator-name",
+				      &sc->rdesc.name);
+	if (ret)
+		return ret;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res == NULL)
+		return -EINVAL;
+	sc->gdscr = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (sc->gdscr == NULL)
+		return -ENOMEM;
+
+	sc->rdesc.id = atomic_inc_return(&gdsc_count);
+	sc->rdesc.ops = &gdsc_ops;
+	sc->rdesc.type = REGULATOR_VOLTAGE;
+	sc->rdesc.owner = THIS_MODULE;
+	platform_set_drvdata(pdev, sc);
+
+	/*
+	 * Disable HW trigger: collapse/restore occur based on registers writes.
+	 * Disable SW override: Use hardware state-machine for sequencing.
+	 */
+	regval = readl_relaxed(sc->gdscr);
+	regval &= ~(HW_CONTROL_MASK | SW_OVERRIDE_MASK);
+
+	/* Configure wait time between states. */
+	regval &= ~(EN_REST_WAIT_MASK | EN_FEW_WAIT_MASK | CLK_DIS_WAIT_MASK);
+	regval |= EN_REST_WAIT_VAL | EN_FEW_WAIT_VAL | CLK_DIS_WAIT_VAL;
+	writel_relaxed(regval, sc->gdscr);
+
+	sc->rdev = regulator_register(&sc->rdesc, &pdev->dev, init_data, sc,
+				      pdev->dev.of_node);
+	if (IS_ERR(sc->rdev)) {
+		dev_err(&pdev->dev, "regulator_register(\"%s\") failed.\n",
+			sc->rdesc.name);
+		return PTR_ERR(sc->rdev);
+	}
+
+	return 0;
+}
+
+static int __devexit gdsc_remove(struct platform_device *pdev)
+{
+	struct gdsc *sc = platform_get_drvdata(pdev);
+	regulator_unregister(sc->rdev);
+	return 0;
+}
+
+static struct of_device_id gdsc_match_table[] = {
+	{ .compatible = "qcom,gdsc" },
+	{}
+};
+
+static struct platform_driver gdsc_driver = {
+	.probe		= gdsc_probe,
+	.remove		= __devexit_p(gdsc_remove),
+	.driver		= {
+		.name		= "gdsc",
+		.of_match_table = gdsc_match_table,
+		.owner		= THIS_MODULE,
+	},
+};
+
+static int __init gdsc_init(void)
+{
+	return platform_driver_register(&gdsc_driver);
+}
+subsys_initcall(gdsc_init);
+
+static void __exit gdsc_exit(void)
+{
+	platform_driver_unregister(&gdsc_driver);
+}
+module_exit(gdsc_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Copper GDSC power rail regulator driver");
diff --git a/arch/arm/mach-msm/gss-8064.c b/arch/arm/mach-msm/gss-8064.c
index 3c475d6..126f8e0 100644
--- a/arch/arm/mach-msm/gss-8064.c
+++ b/arch/arm/mach-msm/gss-8064.c
@@ -23,6 +23,7 @@
 #include <linux/fs.h>
 
 #include <mach/irqs.h>
+#include <mach/msm_smsm.h>
 #include <mach/scm.h>
 #include <mach/peripheral-loader.h>
 #include <mach/subsystem_restart.h>
@@ -42,6 +43,32 @@
 
 static int crash_shutdown;
 
+#define MAX_SSR_REASON_LEN 81U
+
+static void log_gss_sfr(void)
+{
+	u32 size;
+	char *smem_reason, reason[MAX_SSR_REASON_LEN];
+
+	smem_reason = smem_get_entry(SMEM_SSR_REASON_MSS0, &size);
+	if (!smem_reason || !size) {
+		pr_err("GSS subsystem failure reason: (unknown, smem_get_entry failed).\n");
+		return;
+	}
+	if (!smem_reason[0]) {
+		pr_err("GSS subsystem failure reason: (unknown, init string found).\n");
+		return;
+	}
+
+	size = min(size, MAX_SSR_REASON_LEN-1);
+	memcpy(reason, smem_reason, size);
+	reason[size] = '\0';
+	pr_err("GSS subsystem failure reason: %s.\n", reason);
+
+	smem_reason[0] = '\0';
+	wmb();
+}
+
 static void gss_fatal_fn(struct work_struct *work)
 {
 	uint32_t panic_smsm_states = SMSM_RESET | SMSM_SYSTEM_DOWNLOAD;
@@ -58,6 +85,7 @@
 		pr_err("GSS SMSM state changed to SMSM_RESET.\n"
 			"Probable err_fatal on the GSS. "
 			"Calling subsystem restart...\n");
+		log_gss_sfr();
 		subsystem_restart("gss");
 
 	} else if (gss_state & reset_smsm_states) {
@@ -68,6 +96,7 @@
 		kernel_restart(NULL);
 	} else {
 		/* TODO: Bus unlock code/sequence goes _here_ */
+		log_gss_sfr();
 		subsystem_restart("gss");
 	}
 }
@@ -84,6 +113,7 @@
 		pr_err("GSS SMSM state changed to SMSM_RESET.\n"
 			"Probable err_fatal on the GSS. "
 			"Calling subsystem restart...\n");
+		log_gss_sfr();
 		subsystem_restart("gss");
 	}
 }
diff --git a/arch/arm/mach-msm/idle-macros.S b/arch/arm/mach-msm/idle-macros.S
new file mode 100644
index 0000000..1622e13
--- /dev/null
+++ b/arch/arm/mach-msm/idle-macros.S
@@ -0,0 +1,153 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <asm/hardware/cache-l2x0.h>
+
+/* Add 300 NOPs after 'wfi' for 8x25 target */
+.macro DELAY_8x25, rept
+#ifdef CONFIG_ARCH_MSM8625
+	.rept   \rept
+	nop
+	.endr
+#endif
+.endm
+
+/* Switch between smp_to_amp/amp_to_smp configuration */
+.macro SET_SMP_COHERENCY, on = 0
+	ldr     r0, =target_type
+	ldr     r0, [r0]
+	mov     r1, #TARGET_IS_8625
+	cmp     r0, r1
+	bne     skip\@
+	mrc	p15, 0, r0, c1, c0, 1	/* read ACTLR register */
+	.if     \on
+	orr	r0, r0, #(1 << 6)	/* Set the SMP bit in ACTLR */
+	.else
+	bic	r0, r0, #(1 << 6)	/* Clear the SMP bit */
+	.endif
+	mcr	p15, 0, r0, c1, c0, 1	/* write ACTLR register */
+	isb
+skip\@:
+.endm
+
+/*
+ * Enable the "L2" cache, not require to restore the controller registers
+ */
+.macro ENABLE_8x25_L2
+	ldr     r0, =target_type
+	ldr     r0, [r0]
+	mov     r1, #TARGET_IS_8625
+	cmp     r0, r1
+	bne     skip_enable\@
+	ldr     r0, =apps_power_collapse
+	ldr     r0, [r0]
+	cmp     r0, #POWER_COLLAPSED
+	bne     skip_enable\@
+	ldr     r0, =l2x0_base_addr
+	ldr	r0, [r0]
+	mov	r1, #0x1
+	str	r1, [r0, #L2X0_CTRL]
+	dmb
+skip_enable\@:
+.endm
+
+/*
+ * Perform the required operation
+ * operation: type of operation on l2 cache (e.g: clean&inv or inv)
+ * l2_enable: enable or disable
+ */
+.macro DO_CACHE_OPERATION, operation, l2_enable
+	ldr     r2, =l2x0_base_addr
+	ldr	r2, [r2]
+	ldr     r0, =0xffff
+	str     r0, [r2, #\operation]
+wait\@:
+	ldr	r0, [r2, #\operation]
+	ldr	r1, =0xffff
+	ands    r0, r0, r1
+	bne     wait\@
+l2x_sync\@:
+	mov	r0, #0x0
+	str	r0, [r2, #L2X0_CACHE_SYNC]
+sync\@:
+	ldr	r0, [r2, #L2X0_CACHE_SYNC]
+	ands	r0, r0, #0x1
+	bne	sync\@
+	mov     r1, #\l2_enable
+	str     r1, [r2, #L2X0_CTRL]
+.endm
+
+/*
+ * Clean and invalidate the L2 cache.
+ * 1. Check the target type
+ * 2. Check whether we are coming from PC are not
+ * 3. Save 'aux', 'data latency', & 'prefetch ctlr' registers
+ * 4. Start L2 clean & invalidation operation
+ * 5. Disable the L2 cache
+ */
+.macro SUSPEND_8x25_L2
+	ldr     r0, =target_type
+	ldr     r0, [r0]
+	mov     r1, #TARGET_IS_8625
+	cmp     r0, r1
+	bne     skip_suspend\@
+	ldr	r0, =apps_power_collapse
+	ldr	r0, [r0]
+	cmp	r0, #POWER_COLLAPSED
+	bne	skip_suspend\@
+	ldr	r0, =l2x0_saved_ctrl_reg_val
+	ldr	r1, =l2x0_base_addr
+	ldr	r1, [r1]
+	ldr	r2, [r1, #L2X0_AUX_CTRL]
+	str	r2, [r0, #0x0] /* store aux_ctlr reg value */
+	ldr     r2, [r1, #L2X0_DATA_LATENCY_CTRL]
+	str     r2, [r0, #0x4] /* store data latency reg value */
+	ldr     r2, [r1, #L2X0_PREFETCH_CTRL]
+	str     r2, [r0, #0x8] /* store prefetch_ctlr reg value */
+	DO_CACHE_OPERATION L2X0_CLEAN_INV_WAY OFF
+	dmb
+skip_suspend\@:
+.endm
+
+/*
+ * Coming back from a successful PC
+ * 1. Check the target type
+ * 2. Check whether we are going to PC are not
+ * 3. Disable the L2 cache
+ * 4. Restore 'aux', 'data latency', & 'prefetch ctlr' reg
+ * 5. Invalidate the cache
+ * 6. Enable the L2 cache
+ */
+.macro RESUME_8x25_L2
+	ldr     r0, =target_type
+	ldr     r0, [r0]
+	mov     r1, #TARGET_IS_8625
+	cmp     r0, r1
+	bne     skip_resume\@
+	ldr	r0, =apps_power_collapse
+	ldr	r0, [r0]
+	cmp	r0, #POWER_COLLAPSED
+	bne	skip_resume\@
+	ldr     r1, =l2x0_base_addr
+	ldr	r1, [r1]
+	mov     r0, #0x0
+	str     r0, [r1, #L2X0_CTRL]
+	ldr     r0, =l2x0_saved_ctrl_reg_val
+	ldr     r2, [r0, #0x0]
+	str	r2, [r1, #L2X0_AUX_CTRL] /* restore aux_ctlr reg value */
+	ldr	r2, [r0, #0x4]
+	str	r2, [r1, #L2X0_DATA_LATENCY_CTRL]
+	ldr	r2, [r0, #0x8]
+	str     r2, [r1, #L2X0_PREFETCH_CTRL]
+	DO_CACHE_OPERATION L2X0_INV_WAY ON
+skip_resume\@:
+.endm
diff --git a/arch/arm/mach-msm/idle-v7.S b/arch/arm/mach-msm/idle-v7.S
index b73ddc8..b75f76f 100644
--- a/arch/arm/mach-msm/idle-v7.S
+++ b/arch/arm/mach-msm/idle-v7.S
@@ -20,39 +20,13 @@
 #include <asm/assembler.h>
 
 #include "idle.h"
+#include "idle-macros.S"
 
 #ifdef CONFIG_ARCH_MSM_KRAIT
 #define SCM_SVC_BOOT 0x1
 #define SCM_CMD_TERMINATE_PC 0x2
 #endif
 
-/* Switch between smp_to_amp/amp_to_smp configuration */
-.macro SET_SMP_COHERENCY, on = 0
-ldr     r0, =target_type
-ldr     r0, [r0]
-mov     r1, #TARGET_IS_8625
-cmp     r0, r1
-bne     skip\@
-mrc	p15, 0, r0, c1, c0, 1	/* read ACTLR register */
-.if     \on
-orr	r0, r0, #(1 << 6)	/* Set the SMP bit in ACTLR */
-.else
-bic	r0, r0, #(1 << 6)	/* Clear the SMP bit */
-.endif
-mcr	p15, 0, r0, c1, c0, 1	/* write ACTLR register */
-isb
-skip\@:
-.endm
-
-/* Add NOPs for 8x25 target */
-.macro DELAY_8x25, rept
-#ifdef CONFIG_ARCH_MSM8625
-	.rept	\rept
-	nop
-	.endr
-#endif
-.endm
-
 ENTRY(msm_arch_idle)
 	wfi
 #ifdef CONFIG_ARCH_MSM8X60
@@ -135,16 +109,19 @@
 	bic     r0, r4, #(1 << 2)        /* clear dcache bit   */
 	bic     r0, r0, #(1 << 12)       /* clear icache bit   */
 	mcr     p15, 0, r0, c1, c0, 0    /* disable d/i cache  */
-	dsb
+	isb
 
+	SUSPEND_8x25_L2
 	SET_SMP_COHERENCY OFF
 	wfi
 	DELAY_8x25 300
 
 	mcr     p15, 0, r4, c1, c0, 0    /* restore d/i cache  */
 	isb
-#endif
+	ENABLE_8x25_L2 /* enable only l2, no need to restore the reg back */
 	SET_SMP_COHERENCY ON
+#endif
+
 #if defined(CONFIG_MSM_FIQ_SUPPORT)
 	cpsie   f
 #endif
@@ -237,7 +214,6 @@
 	dsb
 	isb
 
-	SET_SMP_COHERENCY ON
 #ifdef CONFIG_ARCH_MSM_KRAIT
 	mrc	p15, 0, r1, c0, c0, 0
 	ldr	r3, =0xff00fc00
@@ -247,7 +223,11 @@
 	mrceq	p15, 7, r3, c15, c0, 2
 	biceq	r3, r3, #0x400
 	mcreq	p15, 7, r3, c15, c0, 2
+#else
+	RESUME_8x25_L2
+	SET_SMP_COHERENCY ON
 #endif
+
 #ifdef CONFIG_MSM_JTAG
 	stmfd   sp!, {lr}
 	bl      msm_jtag_restore_state
@@ -302,6 +282,14 @@
 target_type:
 	.long  0x0
 
+	.globl apps_power_collapse
+apps_power_collapse:
+	.long 0x0
+
+	.globl l2x0_base_addr
+l2x0_base_addr:
+	.long 0x0
+
 /*
  * Default the l2 flush flag to 1 so that caches are flushed during power
  * collapse unless the  L2 driver decides to flush them only during L2
@@ -309,3 +297,13 @@
  */
 msm_pm_flush_l2_flag:
 	.long 0x1
+
+/*
+ * Save & restore l2x0 registers while system is entering and resuming
+ * from Power Collapse.
+ * 1. aux_ctrl_save (0x0)
+ * 2. data_latency_ctrl (0x4)
+ * 3. prefetch control (0x8)
+ */
+l2x0_saved_ctrl_reg_val:
+	.space 4 * 3
diff --git a/arch/arm/mach-msm/idle.h b/arch/arm/mach-msm/idle.h
index bfd632f..4abdd04 100644
--- a/arch/arm/mach-msm/idle.h
+++ b/arch/arm/mach-msm/idle.h
@@ -25,6 +25,7 @@
 #define ON	1
 #define OFF	0
 #define TARGET_IS_8625	1
+#define POWER_COLLAPSED 1
 
 #ifndef __ASSEMBLY__
 
@@ -40,6 +41,8 @@
 extern unsigned long msm_pm_pc_pgd;
 extern unsigned long msm_pm_boot_vector[NR_CPUS];
 extern uint32_t target_type;
+extern uint32_t apps_power_collapse;
+extern uint32_t *l2x0_base_addr;
 #else
 static inline void msm_pm_set_l2_flush_flag(unsigned int flag)
 {
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index 56210d5..5e2eaf1 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -125,9 +125,15 @@
 	const struct pmic8058_leds_platform_data *driver_channel;
 };
 
+enum msm_camera_ext_led_flash_id {
+	MAM_CAMERA_EXT_LED_FLASH_SC628A,
+	MAM_CAMERA_EXT_LED_FLASH_TPS61310,
+};
+
 struct msm_camera_sensor_flash_external {
 	uint32_t led_en;
 	uint32_t led_flash_en;
+	enum msm_camera_ext_led_flash_id flash_id;
 	struct msm_cam_expander_info *expander_info;
 };
 
@@ -550,6 +556,7 @@
 void msm_map_fsm9xxx_io(void);
 void msm_map_copper_io(void);
 void msm_map_msm8625_io(void);
+void msm_map_msm9625_io(void);
 void msm_init_irq(void);
 void msm_copper_init_irq(void);
 void vic_handle_irq(struct pt_regs *regs);
diff --git a/arch/arm/mach-msm/include/mach/camera.h b/arch/arm/mach-msm/include/mach/camera.h
index 90d236b..47d9b5f 100644
--- a/arch/arm/mach-msm/include/mach/camera.h
+++ b/arch/arm/mach-msm/include/mach/camera.h
@@ -24,8 +24,8 @@
 
 #include <mach/board.h>
 #include <media/msm_camera.h>
-#include <mach/msm_subsystem_map.h>
 #include <linux/ion.h>
+#include <mach/iommu_domains.h>
 
 #define CONFIG_MSM_CAMERA_DEBUG
 #ifdef CONFIG_MSM_CAMERA_DEBUG
@@ -653,7 +653,8 @@
 void msm_camio_camif_pad_reg_reset_2(void);
 
 void msm_camio_vfe_blk_reset(void);
-void msm_camio_vfe_blk_reset_2(int flag);
+void msm_camio_vfe_blk_reset_2(void);
+void msm_camio_vfe_blk_reset_3(void);
 
 int32_t msm_camio_3d_enable(const struct msm_camera_sensor_info *sinfo);
 void msm_camio_3d_disable(void);
diff --git a/arch/arm/mach-msm/include/mach/dma.h b/arch/arm/mach-msm/include/mach/dma.h
index ba621e6..70519ff 100644
--- a/arch/arm/mach-msm/include/mach/dma.h
+++ b/arch/arm/mach-msm/include/mach/dma.h
@@ -35,10 +35,7 @@
 			      unsigned int result,
 			      struct msm_dmov_errdata *err);
 	void (*exec_func)(struct msm_dmov_cmd *cmd);
-	struct work_struct work;
-	unsigned id;    /* For internal use */
 	void *user;	/* Pointer for caller's reference */
-	u8 toflush;
 };
 
 struct msm_dmov_pdata {
diff --git a/arch/arm/mach-msm/include/mach/iommu.h b/arch/arm/mach-msm/include/mach/iommu.h
index a6f27d7..b57ae10 100644
--- a/arch/arm/mach-msm/include/mach/iommu.h
+++ b/arch/arm/mach-msm/include/mach/iommu.h
@@ -18,6 +18,7 @@
 #include <mach/socinfo.h>
 
 extern pgprot_t     pgprot_kernel;
+extern struct platform_device *msm_iommu_root_dev;
 
 /* Domain attributes */
 #define MSM_IOMMU_DOMAIN_PT_CACHEABLE	0x1
@@ -104,6 +105,7 @@
  * message and dump useful IOMMU registers.
  */
 irqreturn_t msm_iommu_fault_handler(int irq, void *dev_id);
+irqreturn_t msm_iommu_fault_handler_v2(int irq, void *dev_id);
 
 #ifdef CONFIG_MSM_IOMMU
 /*
@@ -121,8 +123,17 @@
 
 #endif
 
-static inline int msm_soc_version_supports_iommu(void)
+static inline int msm_soc_version_supports_iommu_v1(void)
 {
+#ifdef CONFIG_OF
+	struct device_node *node;
+
+	node = of_find_compatible_node(NULL, NULL, "qcom,msm-smmu-v2");
+	if (node) {
+		of_node_put(node);
+		return 0;
+	}
+#endif
 	if (cpu_is_msm8960() &&
 	    SOCINFO_VERSION_MAJOR(socinfo_get_version()) < 2)
 		return 0;
diff --git a/arch/arm/mach-msm/include/mach/iommu_domains.h b/arch/arm/mach-msm/include/mach/iommu_domains.h
index dfb100c..1a3a022 100644
--- a/arch/arm/mach-msm/include/mach/iommu_domains.h
+++ b/arch/arm/mach-msm/include/mach/iommu_domains.h
@@ -56,14 +56,28 @@
 	unsigned int domain_alloc_flags;
 };
 
+
+struct msm_iova_partition {
+	unsigned long start;
+	unsigned long size;
+};
+
+struct msm_iova_layout {
+	struct msm_iova_partition *partitions;
+	int npartitions;
+	const char *client_name;
+	unsigned int domain_flags;
+};
+
 #if defined(CONFIG_MSM_IOMMU)
 
 extern struct iommu_domain *msm_get_iommu_domain(int domain_num);
 
-extern unsigned long msm_allocate_iova_address(unsigned int iommu_domain,
+extern int msm_allocate_iova_address(unsigned int iommu_domain,
 					unsigned int partition_no,
 					unsigned long size,
-					unsigned long align);
+					unsigned long align,
+					unsigned long *iova);
 
 extern void msm_free_iova_address(unsigned long iova,
 			unsigned int iommu_domain,
@@ -97,16 +111,19 @@
 					unsigned int partition_no,
 					unsigned long size);
 
+extern int msm_register_domain(struct msm_iova_layout *layout);
+
 #else
 static inline struct iommu_domain
 	*msm_get_iommu_domain(int subsys_id) { return NULL; }
 
 
 
-static inline unsigned long msm_allocate_iova_address(unsigned int iommu_domain,
+static inline int msm_allocate_iova_address(unsigned int iommu_domain,
 					unsigned int partition_no,
 					unsigned long size,
-					unsigned long align) { return 0; }
+					unsigned long align,
+					unsigned long *iova) { return -ENOMEM; }
 
 static inline void msm_free_iova_address(unsigned long iova,
 			unsigned int iommu_domain,
@@ -153,6 +170,11 @@
 {
 	return;
 }
+
+static inline int msm_register_domain(struct msm_iova_layout *layout)
+{
+	return -ENODEV;
+}
 #endif
 
 #endif
diff --git a/arch/arm/mach-msm/include/mach/iommu_hw-v2.h b/arch/arm/mach-msm/include/mach/iommu_hw-v2.h
new file mode 100644
index 0000000..fac13b3
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/iommu_hw-v2.h
@@ -0,0 +1,2111 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_IOMMU_HW_V2_H
+#define __ARCH_ARM_MACH_MSM_IOMMU_HW_V2_H
+
+#define CTX_SHIFT  12
+#define CTX_OFFSET 0x8000
+
+#define MAX_NUM_SMR 128
+
+#define GET_GLOBAL_REG(reg, base) (readl_relaxed((base) + (reg)))
+#define GET_CTX_REG(reg, base, ctx) \
+	(readl_relaxed((base) + CTX_OFFSET + (reg) + ((ctx) << CTX_SHIFT)))
+
+#define SET_GLOBAL_REG(reg, base, val)	writel_relaxed((val), ((base) + (reg)))
+
+#define SET_CTX_REG(reg, base, ctx, val) \
+	writel_relaxed((val), \
+		((base) + CTX_OFFSET + (reg) + ((ctx) << CTX_SHIFT)))
+
+/* Wrappers for numbered registers */
+#define SET_GLOBAL_REG_N(b, n, r, v) SET_GLOBAL_REG((b), ((r) + (n << 2)), (v))
+#define GET_GLOBAL_REG_N(b, n, r)    GET_GLOBAL_REG((b), ((r) + (n << 2)))
+
+/* Field wrappers */
+#define GET_GLOBAL_FIELD(b, r, F) \
+	GET_FIELD(((b) + (r)), r##_##F##_MASK, r##_##F##_SHIFT)
+#define GET_CONTEXT_FIELD(b, c, r, F) \
+	GET_FIELD(((b) + CTX_OFFSET + (r) + ((c) << CTX_SHIFT)), \
+			r##_##F##_MASK, r##_##F##_SHIFT)
+
+#define SET_GLOBAL_FIELD(b, r, F, v) \
+	SET_FIELD(((b) + (r)), r##_##F##_MASK, r##_##F##_SHIFT, (v))
+#define SET_CONTEXT_FIELD(b, c, r, F, v) \
+	SET_FIELD(((b) + CTX_OFFSET + (r) + ((c) << CTX_SHIFT)), \
+			r##_##F##_MASK, r##_##F##_SHIFT, (v))
+
+/* Wrappers for numbered field registers */
+#define SET_GLOBAL_FIELD_N(b, n, r, F, v) \
+	SET_FIELD(((b) + ((n) << 2) + (r)), r##_##F##_MASK, r##_##F##_SHIFT, v)
+#define GET_GLOBAL_FIELD_N(b, n, r, F) \
+	GET_FIELD(((b) + ((n) << 2) + (r)), r##_##F##_MASK, r##_##F##_SHIFT)
+
+#define GET_FIELD(addr, mask, shift) ((readl_relaxed(addr) >> (shift)) & (mask))
+
+#define SET_FIELD(addr, mask, shift, v) \
+do { \
+	int t = readl_relaxed(addr); \
+	writel_relaxed((t & ~((mask) << (shift))) + (((v) & \
+			(mask)) << (shift)), addr); \
+} while (0)
+
+
+/* Global register space 0 setters / getters */
+#define SET_CR0(b, v)            SET_GLOBAL_REG(CR0, (b), (v))
+#define SET_SCR1(b, v)           SET_GLOBAL_REG(SCR1, (b), (v))
+#define SET_CR2(b, v)            SET_GLOBAL_REG(CR2, (b), (v))
+#define SET_ACR(b, v)            SET_GLOBAL_REG(ACR, (b), (v))
+#define SET_IDR0(b, N, v)        SET_GLOBAL_REG(IDR0, (b), (v))
+#define SET_IDR1(b, N, v)        SET_GLOBAL_REG(IDR1, (b), (v))
+#define SET_IDR2(b, N, v)        SET_GLOBAL_REG(IDR2, (b), (v))
+#define SET_IDR7(b, N, v)        SET_GLOBAL_REG(IDR7, (b), (v))
+#define SET_GFAR(b, v)           SET_GLOBAL_REG(GFAR, (b), (v))
+#define SET_GFSR(b, v)           SET_GLOBAL_REG(GFSR, (b), (v))
+#define SET_GFSRRESTORE(b, v)    SET_GLOBAL_REG(GFSRRESTORE, (b), (v))
+#define SET_GFSYNR0(b, v)        SET_GLOBAL_REG(GFSYNR0, (b), (v))
+#define SET_GFSYNR1(b, v)        SET_GLOBAL_REG(GFSYNR1, (b), (v))
+#define SET_GFSYNR2(b, v)        SET_GLOBAL_REG(GFSYNR2, (b), (v))
+#define SET_TLBIVMID(b, v)       SET_GLOBAL_REG(TLBIVMID, (b), (v))
+#define SET_TLBIALLNSNH(b, v)    SET_GLOBAL_REG(TLBIALLNSNH, (b), (v))
+#define SET_TLBIALLH(b, v)       SET_GLOBAL_REG(TLBIALLH, (b), (v))
+#define SET_TLBGSYNC(b, v)       SET_GLOBAL_REG(TLBGSYNC, (b), (v))
+#define SET_TLBGSTATUS(b, v)     SET_GLOBAL_REG(TLBSTATUS, (b), (v))
+#define SET_TLBIVAH(b, v)        SET_GLOBAL_REG(TLBIVAH, (b), (v))
+#define SET_GATS1UR(b, v)        SET_GLOBAL_REG(GATS1UR, (b), (v))
+#define SET_GATS1UW(b, v)        SET_GLOBAL_REG(GATS1UW, (b), (v))
+#define SET_GATS1PR(b, v)        SET_GLOBAL_REG(GATS1PR, (b), (v))
+#define SET_GATS1PW(b, v)        SET_GLOBAL_REG(GATS1PW, (b), (v))
+#define SET_GATS12UR(b, v)       SET_GLOBAL_REG(GATS12UR, (b), (v))
+#define SET_GATS12UW(b, v)       SET_GLOBAL_REG(GATS12UW, (b), (v))
+#define SET_GATS12PR(b, v)       SET_GLOBAL_REG(GATS12PR, (b), (v))
+#define SET_GATS12PW(b, v)       SET_GLOBAL_REG(GATS12PW, (b), (v))
+#define SET_GPAR(b, v)           SET_GLOBAL_REG(GPAR, (b), (v))
+#define SET_GATSR(b, v)          SET_GLOBAL_REG(GATSR, (b), (v))
+#define SET_NSCR0(b, v)          SET_GLOBAL_REG(NSCR0, (b), (v))
+#define SET_NSCR2(b, v)          SET_GLOBAL_REG(NSCR2, (b), (v))
+#define SET_NSACR(b, v)          SET_GLOBAL_REG(NSACR, (b), (v))
+#define SET_PMCR(b, v)           SET_GLOBAL_REG(PMCR, (b), (v))
+#define SET_SMR_N(b, N, v)       SET_GLOBAL_REG_N(SMR, N, (b), (v))
+#define SET_S2CR_N(b, N, v)      SET_GLOBAL_REG_N(S2CR, N, (b), (v))
+
+#define GET_CR0(b)               GET_GLOBAL_REG(CR0, (b))
+#define GET_SCR1(b)              GET_GLOBAL_REG(SCR1, (b))
+#define GET_CR2(b)               GET_GLOBAL_REG(CR2, (b))
+#define GET_ACR(b)               GET_GLOBAL_REG(ACR, (b))
+#define GET_IDR0(b, N)           GET_GLOBAL_REG(IDR0, (b))
+#define GET_IDR1(b, N)           GET_GLOBAL_REG(IDR1, (b))
+#define GET_IDR2(b, N)           GET_GLOBAL_REG(IDR2, (b))
+#define GET_IDR7(b, N)           GET_GLOBAL_REG(IDR7, (b))
+#define GET_GFAR(b)              GET_GLOBAL_REG(GFAR, (b))
+#define GET_GFSR(b)              GET_GLOBAL_REG(GFSR, (b))
+#define GET_GFSRRESTORE(b)       GET_GLOBAL_REG(GFSRRESTORE, (b))
+#define GET_GFSYNR0(b)           GET_GLOBAL_REG(GFSYNR0, (b))
+#define GET_GFSYNR1(b)           GET_GLOBAL_REG(GFSYNR1, (b))
+#define GET_GFSYNR2(b)           GET_GLOBAL_REG(GFSYNR2, (b))
+#define GET_TLBIVMID(b)          GET_GLOBAL_REG(TLBIVMID, (b))
+#define GET_TLBIALLNSNH(b)       GET_GLOBAL_REG(TLBIALLNSNH, (b))
+#define GET_TLBIALLH(b)          GET_GLOBAL_REG(TLBIALLH, (b))
+#define GET_TLBGSYNC(b)          GET_GLOBAL_REG(TLBGSYNC, (b))
+#define GET_TLBGSTATUS(b)        GET_GLOBAL_REG(TLBSTATUS, (b))
+#define GET_TLBIVAH(b)           GET_GLOBAL_REG(TLBIVAH, (b))
+#define GET_GATS1UR(b)           GET_GLOBAL_REG(GATS1UR, (b))
+#define GET_GATS1UW(b)           GET_GLOBAL_REG(GATS1UW, (b))
+#define GET_GATS1PR(b)           GET_GLOBAL_REG(GATS1PR, (b))
+#define GET_GATS1PW(b)           GET_GLOBAL_REG(GATS1PW, (b))
+#define GET_GATS12UR(b)          GET_GLOBAL_REG(GATS12UR, (b))
+#define GET_GATS12UW(b)          GET_GLOBAL_REG(GATS12UW, (b))
+#define GET_GATS12PR(b)          GET_GLOBAL_REG(GATS12PR, (b))
+#define GET_GATS12PW(b)          GET_GLOBAL_REG(GATS12PW, (b))
+#define GET_GPAR(b)              GET_GLOBAL_REG(GPAR, (b))
+#define GET_GATSR(b)             GET_GLOBAL_REG(GATSR, (b))
+#define GET_NSCR0(b)             GET_GLOBAL_REG(NSCR0, (b))
+#define GET_NSCR2(b)             GET_GLOBAL_REG(NSCR2, (b))
+#define GET_NSACR(b)             GET_GLOBAL_REG(NSACR, (b))
+#define GET_PMCR(b, v)           GET_GLOBAL_REG(PMCR, (b))
+#define GET_SMR_N(b, N)          GET_GLOBAL_REG_N(SMR, N, (b))
+#define GET_S2CR_N(b, N)         GET_GLOBAL_REG_N(S2CR, N, (b))
+
+/* Global register space 1 setters / getters */
+#define SET_CBAR_N(b, N, v)      SET_GLOBAL_REG_N(CBAR, N, (b), (v))
+#define SET_CBFRSYNRA_N(b, N, v) SET_GLOBAL_REG_N(CBFRSYNRA, N, (b), (v))
+
+#define GET_CBAR_N(b, N)         GET_GLOBAL_REG_N(CBAR, N, (b))
+#define GET_CBFRSYNRA_N(b, N)    GET_GLOBAL_REG_N(CBFRSYNRA, N, (b))
+
+/* Implementation defined register setters/getters */
+#define SET_PREDICTIONDIS0(b, v) SET_GLOBAL_REG(PREDICTIONDIS0, (b), (v))
+#define SET_PREDICTIONDIS1(b, v) SET_GLOBAL_REG(PREDICTIONDIS1, (b), (v))
+#define SET_S1L1BFBLP0(b, v)     SET_GLOBAL_REG(S1L1BFBLP0, (b), (v))
+
+/* SSD register setters/getters */
+#define SET_SSDR_N(b, N, v)      SET_GLOBAL_REG_N(SSDR_N, N, (b), (v))
+
+#define GET_SSDR_N(b, N)         GET_GLOBAL_REG_N(SSDR_N, N, (b))
+
+/* Context bank register setters/getters */
+#define SET_SCTLR(b, c, v)       SET_CTX_REG(CB_SCTLR, (b), (c), (v))
+#define SET_ACTLR(b, c, v)       SET_CTX_REG(CB_ACTLR, (b), (c), (v))
+#define SET_RESUME(b, c, v)      SET_CTX_REG(CB_RESUME, (b), (c), (v))
+#define SET_TTBR0(b, c, v)       SET_CTX_REG(CB_TTBR0, (b), (c), (v))
+#define SET_TTBR1(b, c, v)       SET_CTX_REG(CB_TTBR1, (b), (c), (v))
+#define SET_TTBCR(b, c, v)       SET_CTX_REG(CB_TTBCR, (b), (c), (v))
+#define SET_CONTEXTIDR(b, c, v)  SET_CTX_REG(CB_CONTEXTIDR, (b), (c), (v))
+#define SET_PRRR(b, c, v)        SET_CTX_REG(CB_PRRR, (b), (c), (v))
+#define SET_NMRR(b, c, v)        SET_CTX_REG(CB_NMRR, (b), (c), (v))
+#define SET_PAR(b, c, v)         SET_CTX_REG(CB_PAR, (b), (c), (v))
+#define SET_FSR(b, c, v)         SET_CTX_REG(CB_FSR, (b), (c), (v))
+#define SET_FSRRESTORE(b, c, v)  SET_CTX_REG(CB_FSRRESTORE, (b), (c), (v))
+#define SET_FAR(b, c, v)         SET_CTX_REG(CB_FAR, (b), (c), (v))
+#define SET_FSYNR0(b, c, v)      SET_CTX_REG(CB_FSYNR0, (b), (c), (v))
+#define SET_FSYNR1(b, c, v)      SET_CTX_REG(CB_FSYNR1, (b), (c), (v))
+#define SET_TLBIVA(b, c, v)      SET_CTX_REG(CB_TLBIVA, (b), (c), (v))
+#define SET_TLBIVAA(b, c, v)     SET_CTX_REG(CB_TLBIVAA, (b), (c), (v))
+#define SET_TLBIASID(b, c, v)    SET_CTX_REG(CB_TLBIASID, (b), (c), (v))
+#define SET_TLBIALL(b, c, v)     SET_CTX_REG(CB_TLBIALL, (b), (c), (v))
+#define SET_TLBIVAL(b, c, v)     SET_CTX_REG(CB_TLBIVAL, (b), (c), (v))
+#define SET_TLBIVAAL(b, c, v)    SET_CTX_REG(CB_TLBIVAAL, (b), (c), (v))
+#define SET_TLBSYNC(b, c, v)     SET_CTX_REG(CB_TLBSYNC, (b), (c), (v))
+#define SET_TLBSTATUS(b, c, v)   SET_CTX_REG(CB_TLBSTATUS, (b), (c), (v))
+#define SET_ATS1PR(b, c, v)      SET_CTX_REG(CB_ATS1PR, (b), (c), (v))
+#define SET_ATS1PW(b, c, v)      SET_CTX_REG(CB_ATS1PW, (b), (c), (v))
+#define SET_ATS1UR(b, c, v)      SET_CTX_REG(CB_ATS1UR, (b), (c), (v))
+#define SET_ATS1UW(b, c, v)      SET_CTX_REG(CB_ATS1UW, (b), (c), (v))
+#define SET_ATSR(b, c, v)        SET_CTX_REG(CB_ATSR, (b), (c), (v))
+
+#define GET_SCTLR(b, c)          GET_CTX_REG(CB_SCTLR, (b), (c))
+#define GET_ACTLR(b, c)          GET_CTX_REG(CB_ACTLR, (b), (c))
+#define GET_RESUME(b, c)         GET_CTX_REG(CB_RESUME, (b), (c))
+#define GET_TTBR0(b, c)          GET_CTX_REG(CB_TTBR0, (b), (c))
+#define GET_TTBR1(b, c)          GET_CTX_REG(CB_TTBR1, (b), (c))
+#define GET_TTBCR(b, c)          GET_CTX_REG(CB_TTBCR, (b), (c))
+#define GET_CONTEXTIDR(b, c)     GET_CTX_REG(CB_CONTEXTIDR, (b), (c))
+#define GET_PRRR(b, c)           GET_CTX_REG(CB_PRRR, (b), (c))
+#define GET_NMRR(b, c)           GET_CTX_REG(CB_NMRR, (b), (c))
+#define GET_PAR(b, c)            GET_CTX_REG(CB_PAR, (b), (c))
+#define GET_FSR(b, c)            GET_CTX_REG(CB_FSR, (b), (c))
+#define GET_FSRRESTORE(b, c)     GET_CTX_REG(CB_FSRRESTORE, (b), (c))
+#define GET_FAR(b, c)            GET_CTX_REG(CB_FAR, (b), (c))
+#define GET_FSYNR0(b, c)         GET_CTX_REG(CB_FSYNR0, (b), (c))
+#define GET_FSYNR1(b, c)         GET_CTX_REG(CB_FSYNR1, (b), (c))
+#define GET_TLBIVA(b, c)         GET_CTX_REG(CB_TLBIVA, (b), (c))
+#define GET_TLBIVAA(b, c)        GET_CTX_REG(CB_TLBIVAA, (b), (c))
+#define GET_TLBIASID(b, c)       GET_CTX_REG(CB_TLBIASID, (b), (c))
+#define GET_TLBIALL(b, c)        GET_CTX_REG(CB_TLBIALL, (b), (c))
+#define GET_TLBIVAL(b, c)        GET_CTX_REG(CB_TLBIVAL, (b), (c))
+#define GET_TLBIVAAL(b, c)       GET_CTX_REG(CB_TLBIVAAL, (b), (c))
+#define GET_TLBSYNC(b, c)        GET_CTX_REG(CB_TLBSYNC, (b), (c))
+#define GET_TLBSTATUS(b, c)      GET_CTX_REG(CB_TLBSTATUS, (b), (c))
+#define GET_ATS1PR(b, c)         GET_CTX_REG(CB_ATS1PR, (b), (c))
+#define GET_ATS1PW(b, c)         GET_CTX_REG(CB_ATS1PW, (b), (c))
+#define GET_ATS1UR(b, c)         GET_CTX_REG(CB_ATS1UR, (b), (c))
+#define GET_ATS1UW(b, c)         GET_CTX_REG(CB_ATS1UW, (b), (c))
+#define GET_ATSR(b, c)           GET_CTX_REG(CB_ATSR, (b), (c))
+
+/* Global Register field setters / getters */
+/* Configuration Register: CR0 */
+#define SET_CR0_NSCFG(b, v)        SET_GLOBAL_FIELD(b, CR0, NSCFG, v)
+#define SET_CR0_WACFG(b, v)        SET_GLOBAL_FIELD(b, CR0, WACFG, v)
+#define SET_CR0_RACFG(b, v)        SET_GLOBAL_FIELD(b, CR0, RACFG, v)
+#define SET_CR0_SHCFG(b, v)        SET_GLOBAL_FIELD(b, CR0, SHCFG, v)
+#define SET_CR0_SMCFCFG(b, v)      SET_GLOBAL_FIELD(b, CR0, SMCFCFG, v)
+#define SET_CR0_MTCFG(b, v)        SET_GLOBAL_FIELD(b, CR0, MTCFG, v)
+#define SET_CR0_BSU(b, v)          SET_GLOBAL_FIELD(b, CR0, BSU, v)
+#define SET_CR0_FB(b, v)           SET_GLOBAL_FIELD(b, CR0, FB, v)
+#define SET_CR0_PTM(b, v)          SET_GLOBAL_FIELD(b, CR0, PTM, v)
+#define SET_CR0_VMIDPNE(b, v)      SET_GLOBAL_FIELD(b, CR0, VMIDPNE, v)
+#define SET_CR0_USFCFG(b, v)       SET_GLOBAL_FIELD(b, CR0, USFCFG, v)
+#define SET_CR0_GSE(b, v)          SET_GLOBAL_FIELD(b, CR0, GSE, v)
+#define SET_CR0_STALLD(b, v)       SET_GLOBAL_FIELD(b, CR0, STALLD, v)
+#define SET_CR0_TRANSIENTCFG(b, v) SET_GLOBAL_FIELD(b, CR0, TRANSIENTCFG, v)
+#define SET_CR0_GCFGFIE(b, v)      SET_GLOBAL_FIELD(b, CR0, GCFGFIE, v)
+#define SET_CR0_GCFGFRE(b, v)      SET_GLOBAL_FIELD(b, CR0, GCFGFRE, v)
+#define SET_CR0_GFIE(b, v)         SET_GLOBAL_FIELD(b, CR0, GFIE, v)
+#define SET_CR0_GFRE(b, v)         SET_GLOBAL_FIELD(b, CR0, GFRE, v)
+#define SET_CR0_CLIENTPD(b, v)     SET_GLOBAL_FIELD(b, CR0, CLIENTPD, v)
+
+#define GET_CR0_NSCFG(b)           GET_GLOBAL_FIELD(b, CR0, NSCFG)
+#define GET_CR0_WACFG(b)           GET_GLOBAL_FIELD(b, CR0, WACFG)
+#define GET_CR0_RACFG(b)           GET_GLOBAL_FIELD(b, CR0, RACFG)
+#define GET_CR0_SHCFG(b)           GET_GLOBAL_FIELD(b, CR0, SHCFG)
+#define GET_CR0_SMCFCFG(b)         GET_GLOBAL_FIELD(b, CR0, SMCFCFG)
+#define GET_CR0_MTCFG(b)           GET_GLOBAL_FIELD(b, CR0, MTCFG)
+#define GET_CR0_BSU(b)             GET_GLOBAL_FIELD(b, CR0, BSU)
+#define GET_CR0_FB(b)              GET_GLOBAL_FIELD(b, CR0, FB)
+#define GET_CR0_PTM(b)             GET_GLOBAL_FIELD(b, CR0, PTM)
+#define GET_CR0_VMIDPNE(b)         GET_GLOBAL_FIELD(b, CR0, VMIDPNE)
+#define GET_CR0_USFCFG(b)          GET_GLOBAL_FIELD(b, CR0, USFCFG)
+#define GET_CR0_GSE(b)             GET_GLOBAL_FIELD(b, CR0, GSE)
+#define GET_CR0_STALLD(b)          GET_GLOBAL_FIELD(b, CR0, STALLD)
+#define GET_CR0_TRANSIENTCFG(b)    GET_GLOBAL_FIELD(b, CR0, TRANSIENTCFG)
+#define GET_CR0_GCFGFIE(b)         GET_GLOBAL_FIELD(b, CR0, GCFGFIE)
+#define GET_CR0_GCFGFRE(b)         GET_GLOBAL_FIELD(b, CR0, GCFGFRE)
+#define GET_CR0_GFIE(b)            GET_GLOBAL_FIELD(b, CR0, GFIE)
+#define GET_CR0_GFRE(b)            GET_GLOBAL_FIELD(b, CR0, GFRE)
+#define GET_CR0_CLIENTPD(b)        GET_GLOBAL_FIELD(b, CR0, CLIENTPD)
+
+/* Configuration Register: CR2 */
+#define SET_CR2_BPVMID(b, v)     SET_GLOBAL_FIELD(b, CR2, BPVMID, v)
+
+#define GET_CR2_BPVMID(b)        GET_GLOBAL_FIELD(b, CR2, BPVMID)
+
+/* Global Address Translation, Stage 1, Privileged Read: GATS1PR */
+#define SET_GATS1PR_ADDR(b, v)   SET_GLOBAL_FIELD(b, GATS1PR, ADDR, v)
+#define SET_GATS1PR_NDX(b, v)    SET_GLOBAL_FIELD(b, GATS1PR, NDX, v)
+
+#define GET_GATS1PR_ADDR(b)      GET_GLOBAL_FIELD(b, GATS1PR, ADDR)
+#define GET_GATS1PR_NDX(b)       GET_GLOBAL_FIELD(b, GATS1PR, NDX)
+
+/* Global Address Translation, Stage 1, Privileged Write: GATS1PW */
+#define SET_GATS1PW_ADDR(b, v)   SET_GLOBAL_FIELD(b, GATS1PW, ADDR, v)
+#define SET_GATS1PW_NDX(b, v)    SET_GLOBAL_FIELD(b, GATS1PW, NDX, v)
+
+#define GET_GATS1PW_ADDR(b)      GET_GLOBAL_FIELD(b, GATS1PW, ADDR)
+#define GET_GATS1PW_NDX(b)       GET_GLOBAL_FIELD(b, GATS1PW, NDX)
+
+/* Global Address Translation, Stage 1, User Read: GATS1UR */
+#define SET_GATS1UR_ADDR(b, v)   SET_GLOBAL_FIELD(b, GATS1UR, ADDR, v)
+#define SET_GATS1UR_NDX(b, v)    SET_GLOBAL_FIELD(b, GATS1UR, NDX, v)
+
+#define GET_GATS1UR_ADDR(b)      GET_GLOBAL_FIELD(b, GATS1UR, ADDR)
+#define GET_GATS1UR_NDX(b)       GET_GLOBAL_FIELD(b, GATS1UR, NDX)
+
+/* Global Address Translation, Stage 1, User Read: GATS1UW */
+#define SET_GATS1UW_ADDR(b, v)   SET_GLOBAL_FIELD(b, GATS1UW, ADDR, v)
+#define SET_GATS1UW_NDX(b, v)    SET_GLOBAL_FIELD(b, GATS1UW, NDX, v)
+
+#define GET_GATS1UW_ADDR(b)      GET_GLOBAL_FIELD(b, GATS1UW, ADDR)
+#define GET_GATS1UW_NDX(b)       GET_GLOBAL_FIELD(b, GATS1UW, NDX)
+
+/* Global Address Translation, Stage 1 and 2, Privileged Read: GATS12PR */
+#define SET_GATS12PR_ADDR(b, v)  SET_GLOBAL_FIELD(b, GATS12PR, ADDR, v)
+#define SET_GATS12PR_NDX(b, v)   SET_GLOBAL_FIELD(b, GATS12PR, NDX, v)
+
+#define GET_GATS12PR_ADDR(b)     GET_GLOBAL_FIELD(b, GATS12PR, ADDR)
+#define GET_GATS12PR_NDX(b)      GET_GLOBAL_FIELD(b, GATS12PR, NDX)
+
+/* Global Address Translation, Stage 1, Privileged Write: GATS1PW */
+#define SET_GATS12PW_ADDR(b, v)  SET_GLOBAL_FIELD(b, GATS12PW, ADDR, v)
+#define SET_GATS12PW_NDX(b, v)   SET_GLOBAL_FIELD(b, GATS12PW, NDX, v)
+
+#define GET_GATS12PW_ADDR(b)     GET_GLOBAL_FIELD(b, GATS12PW, ADDR)
+#define GET_GATS12PW_NDX(b)      GET_GLOBAL_FIELD(b, GATS12PW, NDX)
+
+/* Global Address Translation, Stage 1, User Read: GATS1UR */
+#define SET_GATS12UR_ADDR(b, v)  SET_GLOBAL_FIELD(b, GATS12UR, ADDR, v)
+#define SET_GATS12UR_NDX(b, v)   SET_GLOBAL_FIELD(b, GATS12UR, NDX, v)
+
+#define GET_GATS12UR_ADDR(b)     GET_GLOBAL_FIELD(b, GATS12UR, ADDR)
+#define GET_GATS12UR_NDX(b)      GET_GLOBAL_FIELD(b, GATS12UR, NDX)
+
+/* Global Address Translation, Stage 1, User Read: GATS1UW */
+#define SET_GATS12UW_ADDR(b, v)  SET_GLOBAL_FIELD(b, GATS12UW, ADDR, v)
+#define SET_GATS12UW_NDX(b, v)   SET_GLOBAL_FIELD(b, GATS12UW, NDX, v)
+
+#define GET_GATS12UW_ADDR(b)     GET_GLOBAL_FIELD(b, GATS12UW, ADDR)
+#define GET_GATS12UW_NDX(b)      GET_GLOBAL_FIELD(b, GATS12UW, NDX)
+
+/* Global Address Translation Status Register: GATSR */
+#define SET_GATSR_ACTIVE(b, v)   SET_GLOBAL_FIELD(b, GATSR, ACTIVE, v)
+
+#define GET_GATSR_ACTIVE(b)      GET_GLOBAL_FIELD(b, GATSR, ACTIVE)
+
+/* Global Fault Address Register: GFAR */
+#define SET_GFAR_FADDR(b, v)     SET_GLOBAL_FIELD(b, GFAR, FADDR, v)
+
+#define GET_GFAR_FADDR(b)        GET_GLOBAL_FIELD(b, GFAR, FADDR)
+
+/* Global Fault Status Register: GFSR */
+#define SET_GFSR_ICF(b, v)        SET_GLOBAL_FIELD(b, GFSR, ICF, v)
+#define SET_GFSR_USF(b, v)        SET_GLOBAL_FIELD(b, GFSR, USF, v)
+#define SET_GFSR_SMCF(b, v)       SET_GLOBAL_FIELD(b, GFSR, SMCF, v)
+#define SET_GFSR_UCBF(b, v)       SET_GLOBAL_FIELD(b, GFSR, UCBF, v)
+#define SET_GFSR_UCIF(b, v)       SET_GLOBAL_FIELD(b, GFSR, UCIF, v)
+#define SET_GFSR_CAF(b, v)        SET_GLOBAL_FIELD(b, GFSR, CAF, v)
+#define SET_GFSR_EF(b, v)         SET_GLOBAL_FIELD(b, GFSR, EF, v)
+#define SET_GFSR_PF(b, v)         SET_GLOBAL_FIELD(b, GFSR, PF, v)
+#define SET_GFSR_MULTI(b, v)      SET_GLOBAL_FIELD(b, GFSR, MULTI, v)
+
+#define GET_GFSR_ICF(b)           GET_GLOBAL_FIELD(b, GFSR, ICF)
+#define GET_GFSR_USF(b)           GET_GLOBAL_FIELD(b, GFSR, USF)
+#define GET_GFSR_SMCF(b)          GET_GLOBAL_FIELD(b, GFSR, SMCF)
+#define GET_GFSR_UCBF(b)          GET_GLOBAL_FIELD(b, GFSR, UCBF)
+#define GET_GFSR_UCIF(b)          GET_GLOBAL_FIELD(b, GFSR, UCIF)
+#define GET_GFSR_CAF(b)           GET_GLOBAL_FIELD(b, GFSR, CAF)
+#define GET_GFSR_EF(b)            GET_GLOBAL_FIELD(b, GFSR, EF)
+#define GET_GFSR_PF(b)            GET_GLOBAL_FIELD(b, GFSR, PF)
+#define GET_GFSR_MULTI(b)         GET_GLOBAL_FIELD(b, GFSR, MULTI)
+
+/* Global Fault Syndrome Register 0: GFSYNR0 */
+#define SET_GFSYNR0_NESTED(b, v)  SET_GLOBAL_FIELD(b, GFSYNR0, NESTED, v)
+#define SET_GFSYNR0_WNR(b, v)     SET_GLOBAL_FIELD(b, GFSYNR0, WNR, v)
+#define SET_GFSYNR0_PNU(b, v)     SET_GLOBAL_FIELD(b, GFSYNR0, PNU, v)
+#define SET_GFSYNR0_IND(b, v)     SET_GLOBAL_FIELD(b, GFSYNR0, IND, v)
+#define SET_GFSYNR0_NSSTATE(b, v) SET_GLOBAL_FIELD(b, GFSYNR0, NSSTATE, v)
+#define SET_GFSYNR0_NSATTR(b, v)  SET_GLOBAL_FIELD(b, GFSYNR0, NSATTR, v)
+
+#define GET_GFSYNR0_NESTED(b)     GET_GLOBAL_FIELD(b, GFSYNR0, NESTED)
+#define GET_GFSYNR0_WNR(b)        GET_GLOBAL_FIELD(b, GFSYNR0, WNR)
+#define GET_GFSYNR0_PNU(b)        GET_GLOBAL_FIELD(b, GFSYNR0, PNU)
+#define GET_GFSYNR0_IND(b)        GET_GLOBAL_FIELD(b, GFSYNR0, IND)
+#define GET_GFSYNR0_NSSTATE(b)    GET_GLOBAL_FIELD(b, GFSYNR0, NSSTATE)
+#define GET_GFSYNR0_NSATTR(b)     GET_GLOBAL_FIELD(b, GFSYNR0, NSATTR)
+
+/* Global Fault Syndrome Register 1: GFSYNR1 */
+#define SET_GFSYNR1_SID(b, v)     SET_GLOBAL_FIELD(b, GFSYNR1, SID, v)
+
+#define GET_GFSYNR1_SID(b)        GET_GLOBAL_FIELD(b, GFSYNR1, SID)
+
+/* Global Physical Address Register: GPAR */
+#define SET_GPAR_F(b, v)          SET_GLOBAL_FIELD(b, GPAR, F, v)
+#define SET_GPAR_SS(b, v)         SET_GLOBAL_FIELD(b, GPAR, SS, v)
+#define SET_GPAR_OUTER(b, v)      SET_GLOBAL_FIELD(b, GPAR, OUTER, v)
+#define SET_GPAR_INNER(b, v)      SET_GLOBAL_FIELD(b, GPAR, INNER, v)
+#define SET_GPAR_SH(b, v)         SET_GLOBAL_FIELD(b, GPAR, SH, v)
+#define SET_GPAR_NS(b, v)         SET_GLOBAL_FIELD(b, GPAR, NS, v)
+#define SET_GPAR_NOS(b, v)        SET_GLOBAL_FIELD(b, GPAR, NOS, v)
+#define SET_GPAR_PA(b, v)         SET_GLOBAL_FIELD(b, GPAR, PA, v)
+#define SET_GPAR_TF(b, v)         SET_GLOBAL_FIELD(b, GPAR, TF, v)
+#define SET_GPAR_AFF(b, v)        SET_GLOBAL_FIELD(b, GPAR, AFF, v)
+#define SET_GPAR_PF(b, v)         SET_GLOBAL_FIELD(b, GPAR, PF, v)
+#define SET_GPAR_EF(b, v)         SET_GLOBAL_FIELD(b, GPAR, EF, v)
+#define SET_GPAR_TLCMCF(b, v)     SET_GLOBAL_FIELD(b, GPAR, TLCMCF, v)
+#define SET_GPAR_TLBLKF(b, v)     SET_GLOBAL_FIELD(b, GPAR, TLBLKF, v)
+#define SET_GPAR_UCBF(b, v)       SET_GLOBAL_FIELD(b, GPAR, UCBF, v)
+
+#define GET_GPAR_F(b)             GET_GLOBAL_FIELD(b, GPAR, F)
+#define GET_GPAR_SS(b)            GET_GLOBAL_FIELD(b, GPAR, SS)
+#define GET_GPAR_OUTER(b)         GET_GLOBAL_FIELD(b, GPAR, OUTER)
+#define GET_GPAR_INNER(b)         GET_GLOBAL_FIELD(b, GPAR, INNER)
+#define GET_GPAR_SH(b)            GET_GLOBAL_FIELD(b, GPAR, SH)
+#define GET_GPAR_NS(b)            GET_GLOBAL_FIELD(b, GPAR, NS)
+#define GET_GPAR_NOS(b)           GET_GLOBAL_FIELD(b, GPAR, NOS)
+#define GET_GPAR_PA(b)            GET_GLOBAL_FIELD(b, GPAR, PA)
+#define GET_GPAR_TF(b)            GET_GLOBAL_FIELD(b, GPAR, TF)
+#define GET_GPAR_AFF(b)           GET_GLOBAL_FIELD(b, GPAR, AFF)
+#define GET_GPAR_PF(b)            GET_GLOBAL_FIELD(b, GPAR, PF)
+#define GET_GPAR_EF(b)            GET_GLOBAL_FIELD(b, GPAR, EF)
+#define GET_GPAR_TLCMCF(b)        GET_GLOBAL_FIELD(b, GPAR, TLCMCF)
+#define GET_GPAR_TLBLKF(b)        GET_GLOBAL_FIELD(b, GPAR, TLBLKF)
+#define GET_GPAR_UCBF(b)          GET_GLOBAL_FIELD(b, GPAR, UCBF)
+
+/* Identification Register: IDR0 */
+#define SET_IDR0_NUMSMRG(b, v)    SET_GLOBAL_FIELD(b, IDR0, NUMSMRG, v)
+#define SET_IDR0_NUMSIDB(b, v)    SET_GLOBAL_FIELD(b, IDR0, NUMSIDB, v)
+#define SET_IDR0_BTM(b, v)        SET_GLOBAL_FIELD(b, IDR0, BTM, v)
+#define SET_IDR0_CTTW(b, v)       SET_GLOBAL_FIELD(b, IDR0, CTTW, v)
+#define SET_IDR0_NUMIRPT(b, v)    SET_GLOBAL_FIELD(b, IDR0, NUMIRPT, v)
+#define SET_IDR0_PTFS(b, v)       SET_GLOBAL_FIELD(b, IDR0, PTFS, v)
+#define SET_IDR0_SMS(b, v)        SET_GLOBAL_FIELD(b, IDR0, SMS, v)
+#define SET_IDR0_NTS(b, v)        SET_GLOBAL_FIELD(b, IDR0, NTS, v)
+#define SET_IDR0_S2TS(b, v)       SET_GLOBAL_FIELD(b, IDR0, S2TS, v)
+#define SET_IDR0_S1TS(b, v)       SET_GLOBAL_FIELD(b, IDR0, S1TS, v)
+#define SET_IDR0_SES(b, v)        SET_GLOBAL_FIELD(b, IDR0, SES, v)
+
+#define GET_IDR0_NUMSMRG(b)       GET_GLOBAL_FIELD(b, IDR0, NUMSMRG)
+#define GET_IDR0_NUMSIDB(b)       GET_GLOBAL_FIELD(b, IDR0, NUMSIDB)
+#define GET_IDR0_BTM(b)           GET_GLOBAL_FIELD(b, IDR0, BTM)
+#define GET_IDR0_CTTW(b)          GET_GLOBAL_FIELD(b, IDR0, CTTW)
+#define GET_IDR0_NUMIRPT(b)       GET_GLOBAL_FIELD(b, IDR0, NUMIRPT)
+#define GET_IDR0_PTFS(b)          GET_GLOBAL_FIELD(b, IDR0, PTFS)
+#define GET_IDR0_SMS(b)           GET_GLOBAL_FIELD(b, IDR0, SMS)
+#define GET_IDR0_NTS(b)           GET_GLOBAL_FIELD(b, IDR0, NTS)
+#define GET_IDR0_S2TS(b)          GET_GLOBAL_FIELD(b, IDR0, S2TS)
+#define GET_IDR0_S1TS(b)          GET_GLOBAL_FIELD(b, IDR0, S1TS)
+#define GET_IDR0_SES(b)           GET_GLOBAL_FIELD(b, IDR0, SES)
+
+/* Identification Register: IDR1 */
+#define SET_IDR1_NUMCB(b, v)       SET_GLOBAL_FIELD(b, IDR1, NUMCB, v)
+#define SET_IDR1_NUMSSDNDXB(b, v)  SET_GLOBAL_FIELD(b, IDR1, NUMSSDNDXB, v)
+#define SET_IDR1_SSDTP(b, v)       SET_GLOBAL_FIELD(b, IDR1, SSDTP, v)
+#define SET_IDR1_SMCD(b, v)        SET_GLOBAL_FIELD(b, IDR1, SMCD, v)
+#define SET_IDR1_NUMS2CB(b, v)     SET_GLOBAL_FIELD(b, IDR1, NUMS2CB, v)
+#define SET_IDR1_NUMPAGENDXB(b, v) SET_GLOBAL_FIELD(b, IDR1, NUMPAGENDXB, v)
+#define SET_IDR1_PAGESIZE(b, v)    SET_GLOBAL_FIELD(b, IDR1, PAGESIZE, v)
+
+#define GET_IDR1_NUMCB(b)          GET_GLOBAL_FIELD(b, IDR1, NUMCB)
+#define GET_IDR1_NUMSSDNDXB(b)     GET_GLOBAL_FIELD(b, IDR1, NUMSSDNDXB)
+#define GET_IDR1_SSDTP(b)          GET_GLOBAL_FIELD(b, IDR1, SSDTP)
+#define GET_IDR1_SMCD(b)           GET_GLOBAL_FIELD(b, IDR1, SMCD)
+#define GET_IDR1_NUMS2CB(b)        GET_GLOBAL_FIELD(b, IDR1, NUMS2CB)
+#define GET_IDR1_NUMPAGENDXB(b)    GET_GLOBAL_FIELD(b, IDR1, NUMPAGENDXB)
+#define GET_IDR1_PAGESIZE(b)       GET_GLOBAL_FIELD(b, IDR1, PAGESIZE)
+
+/* Identification Register: IDR2 */
+#define SET_IDR2_IAS(b, v)       SET_GLOBAL_FIELD(b, IDR2, IAS, v)
+#define SET_IDR2_OAS(b, v)       SET_GLOBAL_FIELD(b, IDR2, OAS, v)
+
+#define GET_IDR2_IAS(b)          GET_GLOBAL_FIELD(b, IDR2, IAS)
+#define GET_IDR2_OAS(b)          GET_GLOBAL_FIELD(b, IDR2, OAS)
+
+/* Identification Register: IDR7 */
+#define SET_IDR7_MINOR(b, v)     SET_GLOBAL_FIELD(b, IDR7, MINOR, v)
+#define SET_IDR7_MAJOR(b, v)     SET_GLOBAL_FIELD(b, IDR7, MAJOR, v)
+
+#define GET_IDR7_MINOR(b)        GET_GLOBAL_FIELD(b, IDR7, MINOR)
+#define GET_IDR7_MAJOR(b)        GET_GLOBAL_FIELD(b, IDR7, MAJOR)
+
+/* Stream to Context Register: S2CR_N */
+#define SET_S2CR_CBNDX(b, n, v)   SET_GLOBAL_FIELD_N(b, n, S2CR, CBNDX, v)
+#define SET_S2CR_SHCFG(b, n, v)   SET_GLOBAL_FIELD_N(b, n, S2CR, SHCFG, v)
+#define SET_S2CR_MTCFG(b, n, v)   SET_GLOBAL_FIELD_N(b, n, S2CR, MTCFG, v)
+#define SET_S2CR_MEMATTR(b, n, v) SET_GLOBAL_FIELD_N(b, n, S2CR, MEMATTR, v)
+#define SET_S2CR_TYPE(b, n, v)    SET_GLOBAL_FIELD_N(b, n, S2CR, TYPE, v)
+#define SET_S2CR_NSCFG(b, n, v)   SET_GLOBAL_FIELD_N(b, n, S2CR, NSCFG, v)
+#define SET_S2CR_RACFG(b, n, v)   SET_GLOBAL_FIELD_N(b, n, S2CR, RACFG, v)
+#define SET_S2CR_WACFG(b, n, v)   SET_GLOBAL_FIELD_N(b, n, S2CR, WACFG, v)
+#define SET_S2CR_PRIVCFG(b, n, v) SET_GLOBAL_FIELD_N(b, n, S2CR, PRIVCFG, v)
+#define SET_S2CR_INSTCFG(b, n, v) SET_GLOBAL_FIELD_N(b, n, S2CR, INSTCFG, v)
+#define SET_S2CR_TRANSIENTCFG(b, n, v) \
+				SET_GLOBAL_FIELD_N(b, n, S2CR, TRANSIENTCFG, v)
+#define SET_S2CR_VMID(b, n, v)    SET_GLOBAL_FIELD_N(b, n, S2CR, VMID, v)
+#define SET_S2CR_BSU(b, n, v)     SET_GLOBAL_FIELD_N(b, n, S2CR, BSU, v)
+#define SET_S2CR_FB(b, n, v)      SET_GLOBAL_FIELD_N(b, n, S2CR, FB, v)
+
+#define GET_S2CR_CBNDX(b, n)      GET_GLOBAL_FIELD_N(b, n, S2CR, CBNDX)
+#define GET_S2CR_SHCFG(b, n)      GET_GLOBAL_FIELD_N(b, n, S2CR, SHCFG)
+#define GET_S2CR_MTCFG(b, n)      GET_GLOBAL_FIELD_N(b, n, S2CR, MTCFG)
+#define GET_S2CR_MEMATTR(b, n)    GET_GLOBAL_FIELD_N(b, n, S2CR, MEMATTR)
+#define GET_S2CR_TYPE(b, n)       GET_GLOBAL_FIELD_N(b, n, S2CR, TYPE)
+#define GET_S2CR_NSCFG(b, n)      GET_GLOBAL_FIELD_N(b, n, S2CR, NSCFG)
+#define GET_S2CR_RACFG(b, n)      GET_GLOBAL_FIELD_N(b, n, S2CR, RACFG)
+#define GET_S2CR_WACFG(b, n)      GET_GLOBAL_FIELD_N(b, n, S2CR, WACFG)
+#define GET_S2CR_PRIVCFG(b, n)    GET_GLOBAL_FIELD_N(b, n, S2CR, PRIVCFG)
+#define GET_S2CR_INSTCFG(b, n)    GET_GLOBAL_FIELD_N(b, n, S2CR, INSTCFG)
+#define GET_S2CR_TRANSIENTCFG(b, n) \
+				GET_GLOBAL_FIELD_N(b, n, S2CR, TRANSIENTCFG)
+#define GET_S2CR_VMID(b, n)       GET_GLOBAL_FIELD_N(b, n, S2CR, VMID)
+#define GET_S2CR_BSU(b, n)        GET_GLOBAL_FIELD_N(b, n, S2CR, BSU)
+#define GET_S2CR_FB(b, n)         GET_GLOBAL_FIELD_N(b, n, S2CR, FB)
+
+/* Stream Match Register: SMR_N */
+#define SET_SMR_ID(b, n, v)       SET_GLOBAL_FIELD_N(b, n, SMR, ID, v)
+#define SET_SMR_MASK(b, n, v)     SET_GLOBAL_FIELD_N(b, n, SMR, MASK, v)
+#define SET_SMR_VALID(b, n, v)    SET_GLOBAL_FIELD_N(b, n, SMR, VALID, v)
+
+#define GET_SMR_ID(b, n)          GET_GLOBAL_FIELD_N(b, n, SMR, ID)
+#define GET_SMR_MASK(b, n)        GET_GLOBAL_FIELD_N(b, n, SMR, MASK)
+#define GET_SMR_VALID(b, n)       GET_GLOBAL_FIELD_N(b, n, SMR, VALID)
+
+/* Global TLB Status: TLBGSTATUS */
+#define SET_TLBGSTATUS_GSACTIVE(b, v) \
+				SET_GLOBAL_FIELD(b, TLBGSTATUS, GSACTIVE, v)
+
+#define GET_TLBGSTATUS_GSACTIVE(b)    \
+				GET_GLOBAL_FIELD(b, TLBGSTATUS, GSACTIVE)
+
+/* Invalidate Hyp TLB by VA: TLBIVAH */
+#define SET_TLBIVAH_ADDR(b, v)  SET_GLOBAL_FIELD(b, TLBIVAH, ADDR, v)
+
+#define GET_TLBIVAH_ADDR(b)     GET_GLOBAL_FIELD(b, TLBIVAH, ADDR)
+
+/* Invalidate TLB by VMID: TLBIVMID */
+#define SET_TLBIVMID_VMID(b, v) SET_GLOBAL_FIELD(b, TLBIVMID, VMID, v)
+
+#define GET_TLBIVMID_VMID(b)    GET_GLOBAL_FIELD(b, TLBIVMID, VMID)
+
+/* Global Register Space 1 Field setters/getters*/
+/* Context Bank Attribute Register: CBAR_N */
+#define SET_CBAR_VMID(b, n, v)     SET_GLOBAL_FIELD_N(b, n, CBAR, VMID, v)
+#define SET_CBAR_CBNDX(b, n, v)    SET_GLOBAL_FIELD_N(b, n, CBAR, CBNDX, v)
+#define SET_CBAR_BPSHCFG(b, n, v)  SET_GLOBAL_FIELD_N(b, n, CBAR, BPSHCFG, v)
+#define SET_CBAR_HYPC(b, n, v)     SET_GLOBAL_FIELD_N(b, n, CBAR, HYPC, v)
+#define SET_CBAR_FB(b, n, v)       SET_GLOBAL_FIELD_N(b, n, CBAR, FB, v)
+#define SET_CBAR_MEMATTR(b, n, v)  SET_GLOBAL_FIELD_N(b, n, CBAR, MEMATTR, v)
+#define SET_CBAR_TYPE(b, n, v)     SET_GLOBAL_FIELD_N(b, n, CBAR, TYPE, v)
+#define SET_CBAR_BSU(b, n, v)      SET_GLOBAL_FIELD_N(b, n, CBAR, BSU, v)
+#define SET_CBAR_RACFG(b, n, v)    SET_GLOBAL_FIELD_N(b, n, CBAR, RACFG, v)
+#define SET_CBAR_WACFG(b, n, v)    SET_GLOBAL_FIELD_N(b, n, CBAR, WACFG, v)
+#define SET_CBAR_IRPTNDX(b, n, v)  SET_GLOBAL_FIELD_N(b, n, CBAR, IRPTNDX, v)
+
+#define GET_CBAR_VMID(b, n)        GET_GLOBAL_FIELD_N(b, n, CBAR, VMID)
+#define GET_CBAR_CBNDX(b, n)       GET_GLOBAL_FIELD_N(b, n, CBAR, CBNDX)
+#define GET_CBAR_BPSHCFG(b, n)     GET_GLOBAL_FIELD_N(b, n, CBAR, BPSHCFG)
+#define GET_CBAR_HYPC(b, n)        GET_GLOBAL_FIELD_N(b, n, CBAR, HYPC)
+#define GET_CBAR_FB(b, n)          GET_GLOBAL_FIELD_N(b, n, CBAR, FB)
+#define GET_CBAR_MEMATTR(b, n)     GET_GLOBAL_FIELD_N(b, n, CBAR, MEMATTR)
+#define GET_CBAR_TYPE(b, n)        GET_GLOBAL_FIELD_N(b, n, CBAR, TYPE)
+#define GET_CBAR_BSU(b, n)         GET_GLOBAL_FIELD_N(b, n, CBAR, BSU)
+#define GET_CBAR_RACFG(b, n)       GET_GLOBAL_FIELD_N(b, n, CBAR, RACFG)
+#define GET_CBAR_WACFG(b, n)       GET_GLOBAL_FIELD_N(b, n, CBAR, WACFG)
+#define GET_CBAR_IRPTNDX(b, n)     GET_GLOBAL_FIELD_N(b, n, CBAR, IRPTNDX)
+
+/* Context Bank Fault Restricted Syndrome Register A: CBFRSYNRA_N */
+#define SET_CBFRSYNRA_SID(b, n, v) SET_GLOBAL_FIELD_N(b, n, CBFRSYNRA, SID, v)
+
+#define GET_CBFRSYNRA_SID(b, n)    GET_GLOBAL_FIELD_N(b, n, CBFRSYNRA, SID)
+
+/* Stage 1 Context Bank Format Fields */
+#define SET_CB_ACTLR_REQPRIORITY (b, c, v) \
+		SET_CONTEXT_FIELD(b, c, CB_ACTLR, REQPRIORITY, v)
+#define SET_CB_ACTLR_REQPRIORITYCFG(b, c, v) \
+		SET_CONTEXT_FIELD(b, c, CB_ACTLR, REQPRIORITYCFG, v)
+#define SET_CB_ACTLR_PRIVCFG(b, c, v) \
+		SET_CONTEXT_FIELD(b, c, CB_ACTLR, PRIVCFG, v)
+#define SET_CB_ACTLR_BPRCOSH(b, c, v) \
+		SET_CONTEXT_FIELD(b, c, CB_ACTLR, BPRCOSH, v)
+#define SET_CB_ACTLR_BPRCISH(b, c, v) \
+		SET_CONTEXT_FIELD(b, c, CB_ACTLR, BPRCISH, v)
+#define SET_CB_ACTLR_BPRCNSH(b, c, v) \
+		SET_CONTEXT_FIELD(b, c, CB_ACTLR, BPRCNSH, v)
+
+#define GET_CB_ACTLR_REQPRIORITY (b, c) \
+		GET_CONTEXT_FIELD(b, c, CB_ACTLR, REQPRIORITY)
+#define GET_CB_ACTLR_REQPRIORITYCFG(b, c) \
+		GET_CONTEXT_FIELD(b, c, CB_ACTLR, REQPRIORITYCFG)
+#define GET_CB_ACTLR_PRIVCFG(b, c)  GET_CONTEXT_FIELD(b, c, CB_ACTLR, PRIVCFG)
+#define GET_CB_ACTLR_BPRCOSH(b, c)  GET_CONTEXT_FIELD(b, c, CB_ACTLR, BPRCOSH)
+#define GET_CB_ACTLR_BPRCISH(b, c)  GET_CONTEXT_FIELD(b, c, CB_ACTLR, BPRCISH)
+#define GET_CB_ACTLR_BPRCNSH(b, c)  GET_CONTEXT_FIELD(b, c, CB_ACTLR, BPRCNSH)
+
+/* Address Translation, Stage 1, Privileged Read: CB_ATS1PR */
+#define SET_CB_ATS1PR_ADDR(b, c, v) SET_CONTEXT_FIELD(b, c, CB_ATS1PR, ADDR, v)
+
+#define GET_CB_ATS1PR_ADDR(b, c)    GET_CONTEXT_FIELD(b, c, CB_ATS1PR, ADDR)
+
+/* Address Translation, Stage 1, Privileged Write: CB_ATS1PW */
+#define SET_CB_ATS1PW_ADDR(b, c, v) SET_CONTEXT_FIELD(b, c, CB_ATS1PW, ADDR, v)
+
+#define GET_CB_ATS1PW_ADDR(b, c)    GET_CONTEXT_FIELD(b, c, CB_ATS1PW, ADDR)
+
+/* Address Translation, Stage 1, User Read: CB_ATS1UR */
+#define SET_CB_ATS1UR_ADDR(b, c, v) SET_CONTEXT_FIELD(b, c, CB_ATS1UR, ADDR, v)
+
+#define GET_CB_ATS1UR_ADDR(b, c)    GET_CONTEXT_FIELD(b, c, CB_ATS1UR, ADDR)
+
+/* Address Translation, Stage 1, User Write: CB_ATS1UW */
+#define SET_CB_ATS1UW_ADDR(b, c, v) SET_CONTEXT_FIELD(b, c, CB_ATS1UW, ADDR, v)
+
+#define GET_CB_ATS1UW_ADDR(b, c)    GET_CONTEXT_FIELD(b, c, CB_ATS1UW, ADDR)
+
+/* Address Translation Status Register: CB_ATSR */
+#define SET_CB_ATSR_ACTIVE(b, c, v) SET_CONTEXT_FIELD(b, c, CB_ATSR, ACTIVE, v)
+
+#define GET_CB_ATSR_ACTIVE(b, c)    GET_CONTEXT_FIELD(b, c, CB_ATSR, ACTIVE)
+
+/* Context ID Register: CB_CONTEXTIDR */
+#define SET_CB_CONTEXTIDR_ASID(b, c, v) \
+			SET_CONTEXT_FIELD(b, c, CB_CONTEXTIDR, ASID, v)
+#define SET_CB_CONTEXTIDR_PROCID(b, c, v) \
+			SET_CONTEXT_FIELD(b, c, CB_CONTEXTIDR, PROCID, v)
+
+#define GET_CB_CONTEXTIDR_ASID(b, c)    \
+			GET_CONTEXT_FIELD(b, c, CB_CONTEXTIDR, ASID)
+#define GET_CB_CONTEXTIDR_PROCID(b, c)    \
+			GET_CONTEXT_FIELD(b, c, CB_CONTEXTIDR, PROCID)
+
+/* Fault Address Register: CB_FAR */
+#define SET_CB_FAR_FADDR(b, c, v) SET_CONTEXT_FIELD(b, c, CB_FAR, FADDR, v)
+
+#define GET_CB_FAR_FADDR(b, c)    GET_CONTEXT_FIELD(b, c, CB_FAR, FADDR)
+
+/* Fault Status Register: CB_FSR */
+#define SET_CB_FSR_TF(b, c, v)     SET_CONTEXT_FIELD(b, c, CB_FSR, TF, v)
+#define SET_CB_FSR_AFF(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_FSR, AFF, v)
+#define SET_CB_FSR_PF(b, c, v)     SET_CONTEXT_FIELD(b, c, CB_FSR, PF, v)
+#define SET_CB_FSR_EF(b, c, v)     SET_CONTEXT_FIELD(b, c, CB_FSR, EF, v)
+#define SET_CB_FSR_TLBMCF(b, c, v) SET_CONTEXT_FIELD(b, c, CB_FSR, TLBMCF, v)
+#define SET_CB_FSR_TLBLKF(b, c, v) SET_CONTEXT_FIELD(b, c, CB_FSR, TLBLKF, v)
+#define SET_CB_FSR_SS(b, c, v)     SET_CONTEXT_FIELD(b, c, CB_FSR, SS, v)
+#define SET_CB_FSR_MULTI(b, c, v)  SET_CONTEXT_FIELD(b, c, CB_FSR, MULTI, v)
+
+#define GET_CB_FSR_TF(b, c)        GET_CONTEXT_FIELD(b, c, CB_FSR, TF)
+#define GET_CB_FSR_AFF(b, c)       GET_CONTEXT_FIELD(b, c, CB_FSR, AFF)
+#define GET_CB_FSR_PF(b, c)        GET_CONTEXT_FIELD(b, c, CB_FSR, PF)
+#define GET_CB_FSR_EF(b, c)        GET_CONTEXT_FIELD(b, c, CB_FSR, EF)
+#define GET_CB_FSR_TLBMCF(b, c)    GET_CONTEXT_FIELD(b, c, CB_FSR, TLBMCF)
+#define GET_CB_FSR_TLBLKF(b, c)    GET_CONTEXT_FIELD(b, c, CB_FSR, TLBLKF)
+#define GET_CB_FSR_SS(b, c)        GET_CONTEXT_FIELD(b, c, CB_FSR, SS)
+#define GET_CB_FSR_MULTI(b, c)     GET_CONTEXT_FIELD(b, c, CB_FSR, MULTI)
+
+/* Fault Syndrome Register 0: CB_FSYNR0 */
+#define SET_CB_FSYNR0_PLVL(b, c, v) SET_CONTEXT_FIELD(b, c, CB_FSYNR0, PLVL, v)
+#define SET_CB_FSYNR0_S1PTWF(b, c, v) \
+				SET_CONTEXT_FIELD(b, c, CB_FSYNR0, S1PTWF, v)
+#define SET_CB_FSYNR0_WNR(b, c, v)  SET_CONTEXT_FIELD(b, c, CB_FSYNR0, WNR, v)
+#define SET_CB_FSYNR0_PNU(b, c, v)  SET_CONTEXT_FIELD(b, c, CB_FSYNR0, PNU, v)
+#define SET_CB_FSYNR0_IND(b, c, v)  SET_CONTEXT_FIELD(b, c, CB_FSYNR0, IND, v)
+#define SET_CB_FSYNR0_NSSTATE(b, c, v) \
+				SET_CONTEXT_FIELD(b, c, CB_FSYNR0, NSSTATE, v)
+#define SET_CB_FSYNR0_NSATTR(b, c, v) \
+				SET_CONTEXT_FIELD(b, c, CB_FSYNR0, NSATTR, v)
+#define SET_CB_FSYNR0_ATOF(b, c, v)  SET_CONTEXT_FIELD(b, c, CB_FSYNR0, ATOF, v)
+#define SET_CB_FSYNR0_PTWF(b, c, v)  SET_CONTEXT_FIELD(b, c, CB_FSYNR0, PTWF, v)
+#define SET_CB_FSYNR0_AFR(b, c, v)   SET_CONTEXT_FIELD(b, c, CB_FSYNR0, AFR, v)
+#define SET_CB_FSYNR0_S1CBNDX(b, c, v) \
+				SET_CONTEXT_FIELD(b, c, CB_FSYNR0, S1CBNDX, v)
+
+#define GET_CB_FSYNR0_PLVL(b, c)    GET_CONTEXT_FIELD(b, c, CB_FSYNR0, PLVL)
+#define GET_CB_FSYNR0_S1PTWF(b, c)    \
+				GET_CONTEXT_FIELD(b, c, CB_FSYNR0, S1PTWF)
+#define GET_CB_FSYNR0_WNR(b, c)     GET_CONTEXT_FIELD(b, c, CB_FSYNR0, WNR)
+#define GET_CB_FSYNR0_PNU(b, c)     GET_CONTEXT_FIELD(b, c, CB_FSYNR0, PNU)
+#define GET_CB_FSYNR0_IND(b, c)     GET_CONTEXT_FIELD(b, c, CB_FSYNR0, IND)
+#define GET_CB_FSYNR0_NSSTATE(b, c)    \
+				GET_CONTEXT_FIELD(b, c, CB_FSYNR0, NSSTATE)
+#define GET_CB_FSYNR0_NSATTR(b, c)    \
+				GET_CONTEXT_FIELD(b, c, CB_FSYNR0, NSATTR)
+#define GET_CB_FSYNR0_ATOF(b, c)     GET_CONTEXT_FIELD(b, c, CB_FSYNR0, ATOF)
+#define GET_CB_FSYNR0_PTWF(b, c)     GET_CONTEXT_FIELD(b, c, CB_FSYNR0, PTWF)
+#define GET_CB_FSYNR0_AFR(b, c)      GET_CONTEXT_FIELD(b, c, CB_FSYNR0, AFR)
+#define GET_CB_FSYNR0_S1CBNDX(b, c)    \
+				GET_CONTEXT_FIELD(b, c, CB_FSYNR0, S1CBNDX)
+
+/* Normal Memory Remap Register: CB_NMRR */
+#define SET_CB_NMRR_IR0(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_NMRR, IR0, v)
+#define SET_CB_NMRR_IR1(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_NMRR, IR1, v)
+#define SET_CB_NMRR_IR2(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_NMRR, IR2, v)
+#define SET_CB_NMRR_IR3(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_NMRR, IR3, v)
+#define SET_CB_NMRR_IR4(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_NMRR, IR4, v)
+#define SET_CB_NMRR_IR5(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_NMRR, IR5, v)
+#define SET_CB_NMRR_IR6(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_NMRR, IR6, v)
+#define SET_CB_NMRR_IR7(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_NMRR, IR7, v)
+#define SET_CB_NMRR_OR0(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_NMRR, OR0, v)
+#define SET_CB_NMRR_OR1(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_NMRR, OR1, v)
+#define SET_CB_NMRR_OR2(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_NMRR, OR2, v)
+#define SET_CB_NMRR_OR3(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_NMRR, OR3, v)
+#define SET_CB_NMRR_OR4(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_NMRR, OR4, v)
+#define SET_CB_NMRR_OR5(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_NMRR, OR5, v)
+#define SET_CB_NMRR_OR6(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_NMRR, OR6, v)
+#define SET_CB_NMRR_OR7(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_NMRR, OR7, v)
+
+#define GET_CB_NMRR_IR0(b, c)       GET_CONTEXT_FIELD(b, c, CB_NMRR, IR0)
+#define GET_CB_NMRR_IR1(b, c)       GET_CONTEXT_FIELD(b, c, CB_NMRR, IR1)
+#define GET_CB_NMRR_IR2(b, c)       GET_CONTEXT_FIELD(b, c, CB_NMRR, IR2)
+#define GET_CB_NMRR_IR3(b, c)       GET_CONTEXT_FIELD(b, c, CB_NMRR, IR3)
+#define GET_CB_NMRR_IR4(b, c)       GET_CONTEXT_FIELD(b, c, CB_NMRR, IR4)
+#define GET_CB_NMRR_IR5(b, c)       GET_CONTEXT_FIELD(b, c, CB_NMRR, IR5)
+#define GET_CB_NMRR_IR6(b, c)       GET_CONTEXT_FIELD(b, c, CB_NMRR, IR6)
+#define GET_CB_NMRR_IR7(b, c)       GET_CONTEXT_FIELD(b, c, CB_NMRR, IR7)
+#define GET_CB_NMRR_OR0(b, c)       GET_CONTEXT_FIELD(b, c, CB_NMRR, OR0)
+#define GET_CB_NMRR_OR1(b, c)       GET_CONTEXT_FIELD(b, c, CB_NMRR, OR1)
+#define GET_CB_NMRR_OR2(b, c)       GET_CONTEXT_FIELD(b, c, CB_NMRR, OR2)
+#define GET_CB_NMRR_OR3(b, c)       GET_CONTEXT_FIELD(b, c, CB_NMRR, OR3)
+#define GET_CB_NMRR_OR4(b, c)       GET_CONTEXT_FIELD(b, c, CB_NMRR, OR4)
+#define GET_CB_NMRR_OR5(b, c)       GET_CONTEXT_FIELD(b, c, CB_NMRR, OR5)
+
+/* Physical Address Register: CB_PAR */
+#define SET_CB_PAR_F(b, c, v)       SET_CONTEXT_FIELD(b, c, CB_PAR, F, v)
+#define SET_CB_PAR_SS(b, c, v)      SET_CONTEXT_FIELD(b, c, CB_PAR, SS, v)
+#define SET_CB_PAR_OUTER(b, c, v)   SET_CONTEXT_FIELD(b, c, CB_PAR, OUTER, v)
+#define SET_CB_PAR_INNER(b, c, v)   SET_CONTEXT_FIELD(b, c, CB_PAR, INNER, v)
+#define SET_CB_PAR_SH(b, c, v)      SET_CONTEXT_FIELD(b, c, CB_PAR, SH, v)
+#define SET_CB_PAR_NS(b, c, v)      SET_CONTEXT_FIELD(b, c, CB_PAR, NS, v)
+#define SET_CB_PAR_NOS(b, c, v)     SET_CONTEXT_FIELD(b, c, CB_PAR, NOS, v)
+#define SET_CB_PAR_PA(b, c, v)      SET_CONTEXT_FIELD(b, c, CB_PAR, PA, v)
+#define SET_CB_PAR_TF(b, c, v)      SET_CONTEXT_FIELD(b, c, CB_PAR, TF, v)
+#define SET_CB_PAR_AFF(b, c, v)     SET_CONTEXT_FIELD(b, c, CB_PAR, AFF, v)
+#define SET_CB_PAR_PF(b, c, v)      SET_CONTEXT_FIELD(b, c, CB_PAR, PF, v)
+#define SET_CB_PAR_TLBMCF(b, c, v)  SET_CONTEXT_FIELD(b, c, CB_PAR, TLBMCF, v)
+#define SET_CB_PAR_TLBLKF(b, c, v)  SET_CONTEXT_FIELD(b, c, CB_PAR, TLBLKF, v)
+#define SET_CB_PAR_ATOT(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_PAR, ATOT, v)
+#define SET_CB_PAR_PLVL(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_PAR, PLVL, v)
+#define SET_CB_PAR_STAGE(b, c, v)   SET_CONTEXT_FIELD(b, c, CB_PAR, STAGE, v)
+
+#define GET_CB_PAR_F(b, c)          GET_CONTEXT_FIELD(b, c, CB_PAR, F)
+#define GET_CB_PAR_SS(b, c)         GET_CONTEXT_FIELD(b, c, CB_PAR, SS)
+#define GET_CB_PAR_OUTER(b, c)      GET_CONTEXT_FIELD(b, c, CB_PAR, OUTER)
+#define GET_CB_PAR_INNER(b, c)      GET_CONTEXT_FIELD(b, c, CB_PAR, INNER)
+#define GET_CB_PAR_SH(b, c)         GET_CONTEXT_FIELD(b, c, CB_PAR, SH)
+#define GET_CB_PAR_NS(b, c)         GET_CONTEXT_FIELD(b, c, CB_PAR, NS)
+#define GET_CB_PAR_NOS(b, c)        GET_CONTEXT_FIELD(b, c, CB_PAR, NOS)
+#define GET_CB_PAR_PA(b, c)         GET_CONTEXT_FIELD(b, c, CB_PAR, PA)
+#define GET_CB_PAR_TF(b, c)         GET_CONTEXT_FIELD(b, c, CB_PAR, TF)
+#define GET_CB_PAR_AFF(b, c)        GET_CONTEXT_FIELD(b, c, CB_PAR, AFF)
+#define GET_CB_PAR_PF(b, c)         GET_CONTEXT_FIELD(b, c, CB_PAR, PF)
+#define GET_CB_PAR_TLBMCF(b, c)     GET_CONTEXT_FIELD(b, c, CB_PAR, TLBMCF)
+#define GET_CB_PAR_TLBLKF(b, c)     GET_CONTEXT_FIELD(b, c, CB_PAR, TLBLKF)
+#define GET_CB_PAR_ATOT(b, c)       GET_CONTEXT_FIELD(b, c, CB_PAR, ATOT)
+#define GET_CB_PAR_PLVL(b, c)       GET_CONTEXT_FIELD(b, c, CB_PAR, PLVL)
+#define GET_CB_PAR_STAGE(b, c)      GET_CONTEXT_FIELD(b, c, CB_PAR, STAGE)
+
+/* Primary Region Remap Register: CB_PRRR */
+#define SET_CB_PRRR_TR0(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_PRRR, TR0, v)
+#define SET_CB_PRRR_TR1(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_PRRR, TR1, v)
+#define SET_CB_PRRR_TR2(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_PRRR, TR2, v)
+#define SET_CB_PRRR_TR3(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_PRRR, TR3, v)
+#define SET_CB_PRRR_TR4(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_PRRR, TR4, v)
+#define SET_CB_PRRR_TR5(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_PRRR, TR5, v)
+#define SET_CB_PRRR_TR6(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_PRRR, TR6, v)
+#define SET_CB_PRRR_TR7(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_PRRR, TR7, v)
+#define SET_CB_PRRR_DS0(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_PRRR, DS0, v)
+#define SET_CB_PRRR_DS1(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_PRRR, DS1, v)
+#define SET_CB_PRRR_NS0(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_PRRR, NS0, v)
+#define SET_CB_PRRR_NS1(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_PRRR, NS1, v)
+#define SET_CB_PRRR_NOS0(b, c, v)   SET_CONTEXT_FIELD(b, c, CB_PRRR, NOS0, v)
+#define SET_CB_PRRR_NOS1(b, c, v)   SET_CONTEXT_FIELD(b, c, CB_PRRR, NOS1, v)
+#define SET_CB_PRRR_NOS2(b, c, v)   SET_CONTEXT_FIELD(b, c, CB_PRRR, NOS2, v)
+#define SET_CB_PRRR_NOS3(b, c, v)   SET_CONTEXT_FIELD(b, c, CB_PRRR, NOS3, v)
+#define SET_CB_PRRR_NOS4(b, c, v)   SET_CONTEXT_FIELD(b, c, CB_PRRR, NOS4, v)
+#define SET_CB_PRRR_NOS5(b, c, v)   SET_CONTEXT_FIELD(b, c, CB_PRRR, NOS5, v)
+#define SET_CB_PRRR_NOS6(b, c, v)   SET_CONTEXT_FIELD(b, c, CB_PRRR, NOS6, v)
+#define SET_CB_PRRR_NOS7(b, c, v)   SET_CONTEXT_FIELD(b, c, CB_PRRR, NOS7, v)
+
+#define GET_CB_PRRR_TR0(b, c)       GET_CONTEXT_FIELD(b, c, CB_PRRR, TR0)
+#define GET_CB_PRRR_TR1(b, c)       GET_CONTEXT_FIELD(b, c, CB_PRRR, TR1)
+#define GET_CB_PRRR_TR2(b, c)       GET_CONTEXT_FIELD(b, c, CB_PRRR, TR2)
+#define GET_CB_PRRR_TR3(b, c)       GET_CONTEXT_FIELD(b, c, CB_PRRR, TR3)
+#define GET_CB_PRRR_TR4(b, c)       GET_CONTEXT_FIELD(b, c, CB_PRRR, TR4)
+#define GET_CB_PRRR_TR5(b, c)       GET_CONTEXT_FIELD(b, c, CB_PRRR, TR5)
+#define GET_CB_PRRR_TR6(b, c)       GET_CONTEXT_FIELD(b, c, CB_PRRR, TR6)
+#define GET_CB_PRRR_TR7(b, c)       GET_CONTEXT_FIELD(b, c, CB_PRRR, TR7)
+#define GET_CB_PRRR_DS0(b, c)       GET_CONTEXT_FIELD(b, c, CB_PRRR, DS0)
+#define GET_CB_PRRR_DS1(b, c)       GET_CONTEXT_FIELD(b, c, CB_PRRR, DS1)
+#define GET_CB_PRRR_NS0(b, c)       GET_CONTEXT_FIELD(b, c, CB_PRRR, NS0)
+#define GET_CB_PRRR_NS1(b, c)       GET_CONTEXT_FIELD(b, c, CB_PRRR, NS1)
+#define GET_CB_PRRR_NOS0(b, c)      GET_CONTEXT_FIELD(b, c, CB_PRRR, NOS0)
+#define GET_CB_PRRR_NOS1(b, c)      GET_CONTEXT_FIELD(b, c, CB_PRRR, NOS1)
+#define GET_CB_PRRR_NOS2(b, c)      GET_CONTEXT_FIELD(b, c, CB_PRRR, NOS2)
+#define GET_CB_PRRR_NOS3(b, c)      GET_CONTEXT_FIELD(b, c, CB_PRRR, NOS3)
+#define GET_CB_PRRR_NOS4(b, c)      GET_CONTEXT_FIELD(b, c, CB_PRRR, NOS4)
+#define GET_CB_PRRR_NOS5(b, c)      GET_CONTEXT_FIELD(b, c, CB_PRRR, NOS5)
+#define GET_CB_PRRR_NOS6(b, c)      GET_CONTEXT_FIELD(b, c, CB_PRRR, NOS6)
+#define GET_CB_PRRR_NOS7(b, c)      GET_CONTEXT_FIELD(b, c, CB_PRRR, NOS7)
+
+/* Transaction Resume: CB_RESUME */
+#define SET_CB_RESUME_TNR(b, c, v)  SET_CONTEXT_FIELD(b, c, CB_RESUME, TNR, v)
+
+#define GET_CB_RESUME_TNR(b, c)     GET_CONTEXT_FIELD(b, c, CB_RESUME, TNR)
+
+/* System Control Register: CB_SCTLR */
+#define SET_CB_SCTLR_M(b, c, v)     SET_CONTEXT_FIELD(b, c, CB_SCTLR, M, v)
+#define SET_CB_SCTLR_TRE(b, c, v)   SET_CONTEXT_FIELD(b, c, CB_SCTLR, TRE, v)
+#define SET_CB_SCTLR_AFE(b, c, v)   SET_CONTEXT_FIELD(b, c, CB_SCTLR, AFE, v)
+#define SET_CB_SCTLR_AFFD(b, c, v)  SET_CONTEXT_FIELD(b, c, CB_SCTLR, AFFD, v)
+#define SET_CB_SCTLR_E(b, c, v)     SET_CONTEXT_FIELD(b, c, CB_SCTLR, E, v)
+#define SET_CB_SCTLR_CFRE(b, c, v)  SET_CONTEXT_FIELD(b, c, CB_SCTLR, CFRE, v)
+#define SET_CB_SCTLR_CFIE(b, c, v)  SET_CONTEXT_FIELD(b, c, CB_SCTLR, CFIE, v)
+#define SET_CB_SCTLR_CFCFG(b, c, v) SET_CONTEXT_FIELD(b, c, CB_SCTLR, CFCFG, v)
+#define SET_CB_SCTLR_HUPCF(b, c, v) SET_CONTEXT_FIELD(b, c, CB_SCTLR, HUPCF, v)
+#define SET_CB_SCTLR_WXN(b, c, v)   SET_CONTEXT_FIELD(b, c, CB_SCTLR, WXN, v)
+#define SET_CB_SCTLR_UWXN(b, c, v)  SET_CONTEXT_FIELD(b, c, CB_SCTLR, UWXN, v)
+#define SET_CB_SCTLR_ASIDPNE(b, c, v) \
+			SET_CONTEXT_FIELD(b, c, CB_SCTLR, ASIDPNE, v)
+#define SET_CB_SCTLR_TRANSIENTCFG(b, c, v) \
+			SET_CONTEXT_FIELD(b, c, CB_SCTLR, TRANSIENTCFG, v)
+#define SET_CB_SCTLR_MEMATTR(b, c, v) \
+			SET_CONTEXT_FIELD(b, c, CB_SCTLR, MEMATTR, v)
+#define SET_CB_SCTLR_MTCFG(b, c, v) SET_CONTEXT_FIELD(b, c, CB_SCTLR, MTCFG, v)
+#define SET_CB_SCTLR_SHCFG(b, c, v) SET_CONTEXT_FIELD(b, c, CB_SCTLR, SHCFG, v)
+#define SET_CB_SCTLR_RACFG(b, c, v) SET_CONTEXT_FIELD(b, c, CB_SCTLR, RACFG, v)
+#define SET_CB_SCTLR_WACFG(b, c, v) SET_CONTEXT_FIELD(b, c, CB_SCTLR, WACFG, v)
+#define SET_CB_SCTLR_NSCFG(b, c, v) SET_CONTEXT_FIELD(b, c, CB_SCTLR, NSCFG, v)
+
+#define GET_CB_SCTLR_M(b, c)        GET_CONTEXT_FIELD(b, c, CB_SCTLR, M)
+#define GET_CB_SCTLR_TRE(b, c)      GET_CONTEXT_FIELD(b, c, CB_SCTLR, TRE)
+#define GET_CB_SCTLR_AFE(b, c)      GET_CONTEXT_FIELD(b, c, CB_SCTLR, AFE)
+#define GET_CB_SCTLR_AFFD(b, c)     GET_CONTEXT_FIELD(b, c, CB_SCTLR, AFFD)
+#define GET_CB_SCTLR_E(b, c)        GET_CONTEXT_FIELD(b, c, CB_SCTLR, E)
+#define GET_CB_SCTLR_CFRE(b, c)     GET_CONTEXT_FIELD(b, c, CB_SCTLR, CFRE)
+#define GET_CB_SCTLR_CFIE(b, c)     GET_CONTEXT_FIELD(b, c, CB_SCTLR, CFIE)
+#define GET_CB_SCTLR_CFCFG(b, c)    GET_CONTEXT_FIELD(b, c, CB_SCTLR, CFCFG)
+#define GET_CB_SCTLR_HUPCF(b, c)    GET_CONTEXT_FIELD(b, c, CB_SCTLR, HUPCF)
+#define GET_CB_SCTLR_WXN(b, c)      GET_CONTEXT_FIELD(b, c, CB_SCTLR, WXN)
+#define GET_CB_SCTLR_UWXN(b, c)     GET_CONTEXT_FIELD(b, c, CB_SCTLR, UWXN)
+#define GET_CB_SCTLR_ASIDPNE(b, c)    \
+			GET_CONTEXT_FIELD(b, c, CB_SCTLR, ASIDPNE)
+#define GET_CB_SCTLR_TRANSIENTCFG(b, c)    \
+			GET_CONTEXT_FIELD(b, c, CB_SCTLR, TRANSIENTCFG)
+#define GET_CB_SCTLR_MEMATTR(b, c)    \
+			GET_CONTEXT_FIELD(b, c, CB_SCTLR, MEMATTR)
+#define GET_CB_SCTLR_MTCFG(b, c)    GET_CONTEXT_FIELD(b, c, CB_SCTLR, MTCFG)
+#define GET_CB_SCTLR_SHCFG(b, c)    GET_CONTEXT_FIELD(b, c, CB_SCTLR, SHCFG)
+#define GET_CB_SCTLR_RACFG(b, c)    GET_CONTEXT_FIELD(b, c, CB_SCTLR, RACFG)
+#define GET_CB_SCTLR_WACFG(b, c)    GET_CONTEXT_FIELD(b, c, CB_SCTLR, WACFG)
+#define GET_CB_SCTLR_NSCFG(b, c)    GET_CONTEXT_FIELD(b, c, CB_SCTLR, NSCFG)
+
+/* Invalidate TLB by ASID: CB_TLBIASID */
+#define SET_CB_TLBIASID_ASID(b, c, v) \
+				SET_CONTEXT_FIELD(b, c, CB_TLBIASID, ASID, v)
+
+#define GET_CB_TLBIASID_ASID(b, c)    \
+				GET_CONTEXT_FIELD(b, c, CB_TLBIASID, ASID)
+
+/* Invalidate TLB by VA: CB_TLBIVA */
+#define SET_CB_TLBIVA_ASID(b, c, v) SET_CONTEXT_FIELD(b, c, CB_TLBIVA, ASID, v)
+#define SET_CB_TLBIVA_VA(b, c, v)   SET_CONTEXT_FIELD(b, c, CB_TLBIVA, VA, v)
+
+#define GET_CB_TLBIVA_ASID(b, c)    GET_CONTEXT_FIELD(b, c, CB_TLBIVA, ASID)
+#define GET_CB_TLBIVA_VA(b, c)      GET_CONTEXT_FIELD(b, c, CB_TLBIVA, VA)
+
+/* Invalidate TLB by VA, All ASID: CB_TLBIVAA */
+#define SET_CB_TLBIVAA_VA(b, c, v)  SET_CONTEXT_FIELD(b, c, CB_TLBIVAA, VA, v)
+
+#define GET_CB_TLBIVAA_VA(b, c)     GET_CONTEXT_FIELD(b, c, CB_TLBIVAA, VA)
+
+/* Invalidate TLB by VA, All ASID, Last Level: CB_TLBIVAAL */
+#define SET_CB_TLBIVAAL_VA(b, c, v) SET_CONTEXT_FIELD(b, c, CB_TLBIVAAL, VA, v)
+
+#define GET_CB_TLBIVAAL_VA(b, c)    GET_CONTEXT_FIELD(b, c, CB_TLBIVAAL, VA)
+
+/* Invalidate TLB by VA, Last Level: CB_TLBIVAL */
+#define SET_CB_TLBIVAL_ASID(b, c, v) \
+			SET_CONTEXT_FIELD(b, c, CB_TLBIVAL, ASID, v)
+#define SET_CB_TLBIVAL_VA(b, c, v)   SET_CONTEXT_FIELD(b, c, CB_TLBIVAL, VA, v)
+
+#define GET_CB_TLBIVAL_ASID(b, c)    \
+			GET_CONTEXT_FIELD(b, c, CB_TLBIVAL, ASID)
+#define GET_CB_TLBIVAL_VA(b, c)      GET_CONTEXT_FIELD(b, c, CB_TLBIVAL, VA)
+
+/* TLB Status: CB_TLBSTATUS */
+#define SET_CB_TLBSTATUS_SACTIVE(b, c, v) \
+			SET_CONTEXT_FIELD(b, c, CB_TLBSTATUS, SACTIVE, v)
+
+#define GET_CB_TLBSTATUS_SACTIVE(b, c)    \
+			GET_CONTEXT_FIELD(b, c, CB_TLBSTATUS, SACTIVE)
+
+/* Translation Table Base Control Register: CB_TTBCR */
+#define SET_CB_TTBCR_T0SZ(b, c, v)   SET_CONTEXT_FIELD(b, c, CB_TTBCR, T0SZ, v)
+#define SET_CB_TTBCR_PD0(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_TTBCR, PD0, v)
+#define SET_CB_TTBCR_PD1(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_TTBCR, PD1, v)
+#define SET_CB_TTBCR_NSCFG0(b, c, v) \
+			SET_CONTEXT_FIELD(b, c, CB_TTBCR, NSCFG0, v)
+#define SET_CB_TTBCR_NSCFG1(b, c, v) \
+			SET_CONTEXT_FIELD(b, c, CB_TTBCR, NSCFG1, v)
+#define SET_CB_TTBCR_EAE(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_TTBCR, EAE, v)
+
+#define GET_CB_TTBCR_T0SZ(b, c)      GET_CONTEXT_FIELD(b, c, CB_TTBCR, T0SZ)
+#define GET_CB_TTBCR_PD0(b, c)       GET_CONTEXT_FIELD(b, c, CB_TTBCR, PD0)
+#define GET_CB_TTBCR_PD1(b, c)       GET_CONTEXT_FIELD(b, c, CB_TTBCR, PD1)
+#define GET_CB_TTBCR_NSCFG0(b, c)    \
+			GET_CONTEXT_FIELD(b, c, CB_TTBCR, NSCFG0)
+#define GET_CB_TTBCR_NSCFG1(b, c)    \
+			GET_CONTEXT_FIELD(b, c, CB_TTBCR, NSCFG1)
+#define GET_CB_TTBCR_EAE(b, c)       GET_CONTEXT_FIELD(b, c, CB_TTBCR, EAE)
+
+/* Translation Table Base Register 0: CB_TTBR */
+#define SET_CB_TTBR0_IRGN1(b, c, v) SET_CONTEXT_FIELD(b, c, CB_TTBR0, IRGN1, v)
+#define SET_CB_TTBR0_S(b, c, v)     SET_CONTEXT_FIELD(b, c, CB_TTBR0, S, v)
+#define SET_CB_TTBR0_RGN(b, c, v)   SET_CONTEXT_FIELD(b, c, CB_TTBR0, RGN, v)
+#define SET_CB_TTBR0_NOS(b, c, v)   SET_CONTEXT_FIELD(b, c, CB_TTBR0, NOS, v)
+#define SET_CB_TTBR0_IRGN0(b, c, v) SET_CONTEXT_FIELD(b, c, CB_TTBR0, IRGN0, v)
+#define SET_CB_TTBR0_ADDR(b, c, v)  SET_CONTEXT_FIELD(b, c, CB_TTBR0, ADDR, v)
+
+#define GET_CB_TTBR0_IRGN1(b, c)    GET_CONTEXT_FIELD(b, c, CB_TTBR0, IRGN1)
+#define GET_CB_TTBR0_S(b, c)        GET_CONTEXT_FIELD(b, c, CB_TTBR0, S)
+#define GET_CB_TTBR0_RGN(b, c)      GET_CONTEXT_FIELD(b, c, CB_TTBR0, RGN)
+#define GET_CB_TTBR0_NOS(b, c)      GET_CONTEXT_FIELD(b, c, CB_TTBR0, NOS)
+#define GET_CB_TTBR0_IRGN0(b, c)    GET_CONTEXT_FIELD(b, c, CB_TTBR0, IRGN0)
+#define GET_CB_TTBR0_ADDR(b, c)     GET_CONTEXT_FIELD(b, c, CB_TTBR0, ADDR)
+
+/* Translation Table Base Register 1: CB_TTBR1 */
+#define SET_CB_TTBR1_IRGN1(b, c, v) SET_CONTEXT_FIELD(b, c, CB_TTBR1, IRGN1, v)
+#define SET_CB_TTBR1_0S(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_TTBR1, S, v)
+#define SET_CB_TTBR1_RGN(b, c, v)   SET_CONTEXT_FIELD(b, c, CB_TTBR1, RGN, v)
+#define SET_CB_TTBR1_NOS(b, c, v)   SET_CONTEXT_FIELD(b, c, CB_TTBR1, NOS, v)
+#define SET_CB_TTBR1_IRGN0(b, c, v) SET_CONTEXT_FIELD(b, c, CB_TTBR1, IRGN0, v)
+#define SET_CB_TTBR1_ADDR(b, c, v)  SET_CONTEXT_FIELD(b, c, CB_TTBR1, ADDR, v)
+
+#define GET_CB_TTBR1_IRGN1(b, c)    GET_CONTEXT_FIELD(b, c, CB_TTBR1, IRGN1)
+#define GET_CB_TTBR1_0S(b, c)       GET_CONTEXT_FIELD(b, c, CB_TTBR1, S)
+#define GET_CB_TTBR1_RGN(b, c)      GET_CONTEXT_FIELD(b, c, CB_TTBR1, RGN)
+#define GET_CB_TTBR1_NOS(b, c)      GET_CONTEXT_FIELD(b, c, CB_TTBR1, NOS)
+#define GET_CB_TTBR1_IRGN0(b, c)    GET_CONTEXT_FIELD(b, c, CB_TTBR1, IRGN0)
+#define GET_CB_TTBR1_ADDR(b, c)     GET_CONTEXT_FIELD(b, c, CB_TTBR1, ADDR)
+
+/* Global Register Space 0 */
+#define CR0		(0x0000)
+#define SCR1		(0x0004)
+#define CR2		(0x0008)
+#define ACR		(0x0010)
+#define IDR0		(0x0020)
+#define IDR1		(0x0024)
+#define IDR2		(0x0028)
+#define IDR7		(0x003C)
+#define GFAR		(0x0040)
+#define GFSR		(0x0044)
+#define GFSRRESTORE	(0x004C)
+#define GFSYNR0		(0x0050)
+#define GFSYNR1		(0x0054)
+#define GFSYNR2		(0x0058)
+#define TLBIVMID	(0x0064)
+#define TLBIALLNSNH	(0x0068)
+#define TLBIALLH	(0x006C)
+#define TLBGSYNC	(0x0070)
+#define TLBGSTATUS	(0x0074)
+#define TLBIVAH		(0x0078)
+#define GATS1UR		(0x0100)
+#define GATS1UW		(0x0108)
+#define GATS1PR		(0x0110)
+#define GATS1PW		(0x0118)
+#define GATS12UR	(0x0120)
+#define GATS12UW	(0x0128)
+#define GATS12PR	(0x0130)
+#define GATS12PW	(0x0138)
+#define GPAR		(0x0180)
+#define GATSR		(0x0188)
+#define NSCR0		(0x0400)
+#define NSCR2		(0x0408)
+#define NSACR		(0x0410)
+#define SMR		(0x0800)
+#define S2CR		(0x0C00)
+
+/* Global Register Space 1 */
+#define CBAR		(0x1000)
+#define CBFRSYNRA	(0x1400)
+
+/* Implementation defined Register Space */
+#define PREDICTIONDIS0	(0x204C)
+#define PREDICTIONDIS1	(0x2050)
+#define S1L1BFBLP0	(0x215C)
+
+/* Performance Monitoring Register Space */
+#define PMEVCNTR_N	(0x3000)
+#define PMEVTYPER_N	(0x3400)
+#define PMCGCR_N	(0x3800)
+#define PMCGSMR_N	(0x3A00)
+#define PMCNTENSET_N	(0x3C00)
+#define PMCNTENCLR_N	(0x3C20)
+#define PMINTENSET_N	(0x3C40)
+#define PMINTENCLR_N	(0x3C60)
+#define PMOVSCLR_N	(0x3C80)
+#define PMOVSSET_N	(0x3CC0)
+#define PMCFGR		(0x3E00)
+#define PMCR		(0x3E04)
+#define PMCEID0		(0x3E20)
+#define PMCEID1		(0x3E24)
+#define PMAUTHSTATUS	(0x3FB8)
+#define PMDEVTYPE	(0x3FCC)
+
+/* Secure Status Determination Address Space */
+#define SSDR_N		(0x4000)
+
+/* Stage 1 Context Bank Format */
+#define CB_SCTLR	(0x000)
+#define CB_ACTLR	(0x004)
+#define CB_RESUME	(0x008)
+#define CB_TTBR0	(0x020)
+#define CB_TTBR1	(0x028)
+#define CB_TTBCR	(0x030)
+#define CB_CONTEXTIDR	(0x034)
+#define CB_PRRR		(0x038)
+#define CB_NMRR		(0x03C)
+#define CB_PAR		(0x050)
+#define CB_FSR		(0x058)
+#define CB_FSRRESTORE	(0x05C)
+#define CB_FAR		(0x060)
+#define CB_FSYNR0	(0x068)
+#define CB_FSYNR1	(0x06C)
+#define CB_TLBIVA	(0x600)
+#define CB_TLBIVAA	(0x608)
+#define CB_TLBIASID	(0x610)
+#define CB_TLBIALL	(0x618)
+#define CB_TLBIVAL	(0x620)
+#define CB_TLBIVAAL	(0x628)
+#define CB_TLBSYNC	(0x7F0)
+#define CB_TLBSTATUS	(0x7F4)
+#define CB_ATS1PR	(0x800)
+#define CB_ATS1PW	(0x808)
+#define CB_ATS1UR	(0x810)
+#define CB_ATS1UW	(0x818)
+#define CB_ATSR		(0x8F0)
+#define CB_PMXEVCNTR_N	(0xE00)
+#define CB_PMXEVTYPER_N	(0xE80)
+#define CB_PMCFGR	(0xF00)
+#define CB_PMCR		(0xF04)
+#define CB_PMCEID0	(0xF20)
+#define CB_PMCEID1	(0xF24)
+#define CB_PMCNTENSET	(0xF40)
+#define CB_PMCNTENCLR	(0xF44)
+#define CB_PMINTENSET	(0xF48)
+#define CB_PMINTENCLR	(0xF4C)
+#define CB_PMOVSCLR	(0xF50)
+#define CB_PMOVSSET	(0xF58)
+#define CB_PMAUTHSTATUS	(0xFB8)
+
+/* Global Register Fields */
+/* Configuration Register: CR0 */
+#define CR0_NSCFG         (CR0_NSCFG_MASK         << CR0_NSCFG_SHIFT)
+#define CR0_WACFG         (CR0_WACFG_MASK         << CR0_WACFG_SHIFT)
+#define CR0_RACFG         (CR0_RACFG_MASK         << CR0_RACFG_SHIFT)
+#define CR0_SHCFG         (CR0_SHCFG_MASK         << CR0_SHCFG_SHIFT)
+#define CR0_SMCFCFG       (CR0_SMCFCFG_MASK       << CR0_SMCFCFG_SHIFT)
+#define CR0_MTCFG         (CR0_MTCFG_MASK         << CR0_MTCFG_SHIFT)
+#define CR0_MEMATTR       (CR0_MEMATTR_MASK       << CR0_MEMATTR_SHIFT)
+#define CR0_BSU           (CR0_BSU_MASK           << CR0_BSU_SHIFT)
+#define CR0_FB            (CR0_FB_MASK            << CR0_FB_SHIFT)
+#define CR0_PTM           (CR0_PTM_MASK           << CR0_PTM_SHIFT)
+#define CR0_VMIDPNE       (CR0_VMIDPNE_MASK       << CR0_VMIDPNE_SHIFT)
+#define CR0_USFCFG        (CR0_USFCFG_MASK        << CR0_USFCFG_SHIFT)
+#define CR0_GSE           (CR0_GSE_MASK           << CR0_GSE_SHIFT)
+#define CR0_STALLD        (CR0_STALLD_MASK        << CR0_STALLD_SHIFT)
+#define CR0_TRANSIENTCFG  (CR0_TRANSIENTCFG_MASK  << CR0_TRANSIENTCFG_SHIFT)
+#define CR0_GCFGFIE       (CR0_GCFGFIE_MASK       << CR0_GCFGFIE_SHIFT)
+#define CR0_GCFGFRE       (CR0_GCFGFRE_MASK       << CR0_GCFGFRE_SHIFT)
+#define CR0_GFIE          (CR0_GFIE_MASK          << CR0_GFIE_SHIFT)
+#define CR0_GFRE          (CR0_GFRE_MASK          << CR0_GFRE_SHIFT)
+#define CR0_CLIENTPD      (CR0_CLIENTPD_MASK      << CR0_CLIENTPD_SHIFT)
+
+/* Configuration Register: CR2 */
+#define CR2_BPVMID        (CR2_BPVMID_MASK << CR2_BPVMID_SHIFT)
+
+/* Global Address Translation, Stage 1, Privileged Read: GATS1PR */
+#define GATS1PR_ADDR  (GATS1PR_ADDR_MASK  << GATS1PR_ADDR_SHIFT)
+#define GATS1PR_NDX   (GATS1PR_NDX_MASK   << GATS1PR_NDX_SHIFT)
+
+/* Global Address Translation, Stage 1, Privileged Write: GATS1PW */
+#define GATS1PW_ADDR  (GATS1PW_ADDR_MASK  << GATS1PW_ADDR_SHIFT)
+#define GATS1PW_NDX   (GATS1PW_NDX_MASK   << GATS1PW_NDX_SHIFT)
+
+/* Global Address Translation, Stage 1, User Read: GATS1UR */
+#define GATS1UR_ADDR  (GATS1UR_ADDR_MASK  << GATS1UR_ADDR_SHIFT)
+#define GATS1UR_NDX   (GATS1UR_NDX_MASK   << GATS1UR_NDX_SHIFT)
+
+/* Global Address Translation, Stage 1, User Write: GATS1UW */
+#define GATS1UW_ADDR  (GATS1UW_ADDR_MASK  << GATS1UW_ADDR_SHIFT)
+#define GATS1UW_NDX   (GATS1UW_NDX_MASK   << GATS1UW_NDX_SHIFT)
+
+/* Global Address Translation, Stage 1 and 2, Privileged Read: GATS1PR */
+#define GATS12PR_ADDR (GATS12PR_ADDR_MASK << GATS12PR_ADDR_SHIFT)
+#define GATS12PR_NDX  (GATS12PR_NDX_MASK  << GATS12PR_NDX_SHIFT)
+
+/* Global Address Translation, Stage 1 and 2, Privileged Write: GATS1PW */
+#define GATS12PW_ADDR (GATS12PW_ADDR_MASK << GATS12PW_ADDR_SHIFT)
+#define GATS12PW_NDX  (GATS12PW_NDX_MASK  << GATS12PW_NDX_SHIFT)
+
+/* Global Address Translation, Stage 1 and 2, User Read: GATS1UR */
+#define GATS12UR_ADDR (GATS12UR_ADDR_MASK << GATS12UR_ADDR_SHIFT)
+#define GATS12UR_NDX  (GATS12UR_NDX_MASK  << GATS12UR_NDX_SHIFT)
+
+/* Global Address Translation, Stage 1 and 2, User Write: GATS1UW */
+#define GATS12UW_ADDR (GATS12UW_ADDR_MASK << GATS12UW_ADDR_SHIFT)
+#define GATS12UW_NDX  (GATS12UW_NDX_MASK  << GATS12UW_NDX_SHIFT)
+
+/* Global Address Translation Status Register: GATSR */
+#define GATSR_ACTIVE  (GATSR_ACTIVE_MASK  << GATSR_ACTIVE_SHIFT)
+
+/* Global Fault Address Register: GFAR */
+#define GFAR_FADDR    (GFAR_FADDR_MASK << GFAR_FADDR_SHIFT)
+
+/* Global Fault Status Register: GFSR */
+#define GFSR_ICF      (GFSR_ICF_MASK   << GFSR_ICF_SHIFT)
+#define GFSR_USF      (GFSR_USF_MASK   << GFSR_USF_SHIFT)
+#define GFSR_SMCF     (GFSR_SMCF_MASK  << GFSR_SMCF_SHIFT)
+#define GFSR_UCBF     (GFSR_UCBF_MASK  << GFSR_UCBF_SHIFT)
+#define GFSR_UCIF     (GFSR_UCIF_MASK  << GFSR_UCIF_SHIFT)
+#define GFSR_CAF      (GFSR_CAF_MASK   << GFSR_CAF_SHIFT)
+#define GFSR_EF       (GFSR_EF_MASK    << GFSR_EF_SHIFT)
+#define GFSR_PF       (GFSR_PF_MASK    << GFSR_PF_SHIFT)
+#define GFSR_MULTI    (GFSR_MULTI_MASK << GFSR_MULTI_SHIFT)
+
+/* Global Fault Syndrome Register 0: GFSYNR0 */
+#define GFSYNR0_NESTED  (GFSYNR0_NESTED_MASK  << GFSYNR0_NESTED_SHIFT)
+#define GFSYNR0_WNR     (GFSYNR0_WNR_MASK     << GFSYNR0_WNR_SHIFT)
+#define GFSYNR0_PNU     (GFSYNR0_PNU_MASK     << GFSYNR0_PNU_SHIFT)
+#define GFSYNR0_IND     (GFSYNR0_IND_MASK     << GFSYNR0_IND_SHIFT)
+#define GFSYNR0_NSSTATE (GFSYNR0_NSSTATE_MASK << GFSYNR0_NSSTATE_SHIFT)
+#define GFSYNR0_NSATTR  (GFSYNR0_NSATTR_MASK  << GFSYNR0_NSATTR_SHIFT)
+
+/* Global Fault Syndrome Register 1: GFSYNR1 */
+#define GFSYNR1_SID     (GFSYNR1_SID_MASK     << GFSYNR1_SID_SHIFT)
+
+/* Global Physical Address Register: GPAR */
+#define GPAR_F          (GPAR_F_MASK      << GPAR_F_SHIFT)
+#define GPAR_SS         (GPAR_SS_MASK     << GPAR_SS_SHIFT)
+#define GPAR_OUTER      (GPAR_OUTER_MASK  << GPAR_OUTER_SHIFT)
+#define GPAR_INNER      (GPAR_INNER_MASK  << GPAR_INNER_SHIFT)
+#define GPAR_SH         (GPAR_SH_MASK     << GPAR_SH_SHIFT)
+#define GPAR_NS         (GPAR_NS_MASK     << GPAR_NS_SHIFT)
+#define GPAR_NOS        (GPAR_NOS_MASK    << GPAR_NOS_SHIFT)
+#define GPAR_PA         (GPAR_PA_MASK     << GPAR_PA_SHIFT)
+#define GPAR_TF         (GPAR_TF_MASK     << GPAR_TF_SHIFT)
+#define GPAR_AFF        (GPAR_AFF_MASK    << GPAR_AFF_SHIFT)
+#define GPAR_PF         (GPAR_PF_MASK     << GPAR_PF_SHIFT)
+#define GPAR_EF         (GPAR_EF_MASK     << GPAR_EF_SHIFT)
+#define GPAR_TLCMCF     (GPAR_TLBMCF_MASK << GPAR_TLCMCF_SHIFT)
+#define GPAR_TLBLKF     (GPAR_TLBLKF_MASK << GPAR_TLBLKF_SHIFT)
+#define GPAR_UCBF       (GPAR_UCBF_MASK   << GFAR_UCBF_SHIFT)
+
+/* Identification Register: IDR0 */
+#define IDR0_NUMSMRG    (IDR0_NUMSMRG_MASK  << IDR0_NUMSMGR_SHIFT)
+#define IDR0_NUMSIDB    (IDR0_NUMSIDB_MASK  << IDR0_NUMSIDB_SHIFT)
+#define IDR0_BTM        (IDR0_BTM_MASK      << IDR0_BTM_SHIFT)
+#define IDR0_CTTW       (IDR0_CTTW_MASK     << IDR0_CTTW_SHIFT)
+#define IDR0_NUMIRPT    (IDR0_NUMIPRT_MASK  << IDR0_NUMIRPT_SHIFT)
+#define IDR0_PTFS       (IDR0_PTFS_MASK     << IDR0_PTFS_SHIFT)
+#define IDR0_SMS        (IDR0_SMS_MASK      << IDR0_SMS_SHIFT)
+#define IDR0_NTS        (IDR0_NTS_MASK      << IDR0_NTS_SHIFT)
+#define IDR0_S2TS       (IDR0_S2TS_MASK     << IDR0_S2TS_SHIFT)
+#define IDR0_S1TS       (IDR0_S1TS_MASK     << IDR0_S1TS_SHIFT)
+#define IDR0_SES        (IDR0_SES_MASK      << IDR0_SES_SHIFT)
+
+/* Identification Register: IDR1 */
+#define IDR1_NUMCB       (IDR1_NUMCB_MASK       << IDR1_NUMCB_SHIFT)
+#define IDR1_NUMSSDNDXB  (IDR1_NUMSSDNDXB_MASK  << IDR1_NUMSSDNDXB_SHIFT)
+#define IDR1_SSDTP       (IDR1_SSDTP_MASK       << IDR1_SSDTP_SHIFT)
+#define IDR1_SMCD        (IDR1_SMCD_MASK        << IDR1_SMCD_SHIFT)
+#define IDR1_NUMS2CB     (IDR1_NUMS2CB_MASK     << IDR1_NUMS2CB_SHIFT)
+#define IDR1_NUMPAGENDXB (IDR1_NUMPAGENDXB_MASK << IDR1_NUMPAGENDXB_SHIFT)
+#define IDR1_PAGESIZE    (IDR1_PAGESIZE_MASK    << IDR1_PAGESIZE_SHIFT)
+
+/* Identification Register: IDR2 */
+#define IDR2_IAS         (IDR2_IAS_MASK << IDR2_IAS_SHIFT)
+#define IDR1_OAS         (IDR2_OAS_MASK << IDR2_OAS_SHIFT)
+
+/* Identification Register: IDR7 */
+#define IDR7_MINOR       (IDR7_MINOR_MASK << IDR7_MINOR_SHIFT)
+#define IDR7_MAJOR       (IDR7_MAJOR_MASK << IDR7_MAJOR_SHIFT)
+
+/* Stream to Context Register: S2CR */
+#define S2CR_CBNDX        (S2CR_CBNDX_MASK         << S2cR_CBNDX_SHIFT)
+#define S2CR_SHCFG        (S2CR_SHCFG_MASK         << s2CR_SHCFG_SHIFT)
+#define S2CR_MTCFG        (S2CR_MTCFG_MASK         << S2CR_MTCFG_SHIFT)
+#define S2CR_MEMATTR      (S2CR_MEMATTR_MASK       << S2CR_MEMATTR_SHIFT)
+#define S2CR_TYPE         (S2CR_TYPE_MASK          << S2CR_TYPE_SHIFT)
+#define S2CR_NSCFG        (S2CR_NSCFG_MASK         << S2CR_NSCFG_SHIFT)
+#define S2CR_RACFG        (S2CR_RACFG_MASK         << S2CR_RACFG_SHIFT)
+#define S2CR_WACFG        (S2CR_WACFG_MASK         << S2CR_WACFG_SHIFT)
+#define S2CR_PRIVCFG      (S2CR_PRIVCFG_MASK       << S2CR_PRIVCFG_SHIFT)
+#define S2CR_INSTCFG      (S2CR_INSTCFG_MASK       << S2CR_INSTCFG_SHIFT)
+#define S2CR_TRANSIENTCFG (S2CR_TRANSIENTCFG_MASK  << S2CR_TRANSIENTCFG_SHIFT)
+#define S2CR_VMID         (S2CR_VMID_MASK          << S2CR_VMID_SHIFT)
+#define S2CR_BSU          (S2CR_BSU_MASK           << S2CR_BSU_SHIFT)
+#define S2CR_FB           (S2CR_FB_MASK            << S2CR_FB_SHIFT)
+
+/* Stream Match Register: SMR */
+#define SMR_ID            (SMR_ID_MASK    << SMR_ID_SHIFT)
+#define SMR_MASK          (SMR_MASK_MASK  << SMR_MASK_SHIFT)
+#define SMR_VALID         (SMR_VALID_MASK << SMR_VALID_SHIFT)
+
+/* Global TLB Status: TLBGSTATUS */
+#define TLBGSTATUS_GSACTIVE (TLBGSTATUS_GSACTIVE_MASK << \
+					TLBGSTATUS_GSACTIVE_SHIFT)
+/* Invalidate Hyp TLB by VA: TLBIVAH */
+#define TLBIVAH_ADDR  (TLBIVAH_ADDR_MASK << TLBIVAH_ADDR_SHIFT)
+
+/* Invalidate TLB by VMID: TLBIVMID */
+#define TLBIVMID_VMID (TLBIVMID_VMID_MASK << TLBIVMID_VMID_SHIFT)
+
+/* Context Bank Attribute Register: CBAR */
+#define CBAR_VMID       (CBAR_VMID_MASK    << CBAR_VMID_SHIFT)
+#define CBAR_CBNDX      (CBAR_CBNDX_MASK   << CBAR_CBNDX_SHIFT)
+#define CBAR_BPSHCFG    (CBAR_BPSHCFG_MASK << CBAR_BPSHCFG_SHIFT)
+#define CBAR_HYPC       (CBAR_HYPC_MASK    << CBAR_HYPC_SHIFT)
+#define CBAR_FB         (CBAR_FB_MASK      << CBAR_FB_SHIFT)
+#define CBAR_MEMATTR    (CBAR_MEMATTR_MASK << CBAR_MEMATTR_SHIFT)
+#define CBAR_TYPE       (CBAR_TYPE_MASK    << CBAR_TYPE_SHIFT)
+#define CBAR_BSU        (CBAR_BSU_MASK     << CBAR_BSU_SHIFT)
+#define CBAR_RACFG      (CBAR_RACFG_MASK   << CBAR_RACFG_SHIFT)
+#define CBAR_WACFG      (CBAR_WACFG_MASK   << CBAR_WACFG_SHIFT)
+#define CBAR_IRPTNDX    (CBAR_IRPTNDX_MASK << CBAR_IRPTNDX_SHIFT)
+
+/* Context Bank Fault Restricted Syndrome Register A: CBFRSYNRA */
+#define CBFRSYNRA_SID   (CBFRSYNRA_SID_MASK << CBFRSYNRA_SID_SHIFT)
+
+/* Performance Monitoring Register Fields */
+
+/* Stage 1 Context Bank Format Fields */
+/* Auxiliary Control Register: CB_ACTLR */
+#define CB_ACTLR_REQPRIORITY \
+		(CB_ACTLR_REQPRIORITY_MASK << CB_ACTLR_REQPRIORITY_SHIFT)
+#define CB_ACTLR_REQPRIORITYCFG \
+		(CB_ACTLR_REQPRIORITYCFG_MASK << CB_ACTLR_REQPRIORITYCFG_SHIFT)
+#define CB_ACTLR_PRIVCFG (CB_ACTLR_PRIVCFG_MASK << CB_ACTLR_PRIVCFG_SHIFT)
+#define CB_ACTLR_BPRCOSH (CB_ACTLR_BPRCOSH_MASK << CB_ACTLR_BPRCOSH_SHIFT)
+#define CB_ACTLR_BPRCISH (CB_ACTLR_BPRCISH_MASK << CB_ACTLR_BPRCISH_SHIFT)
+#define CB_ACTLR_BPRCNSH (CB_ACTLR_BPRCNSH_MASK << CB_ACTLR_BPRCNSH_SHIFT)
+
+/* Address Translation, Stage 1, Privileged Read: CB_ATS1PR */
+#define CB_ATS1PR_ADDR  (CB_ATS1PR_ADDR_MASK << CB_ATS1PR_ADDR_SHIFT)
+
+/* Address Translation, Stage 1, Privileged Write: CB_ATS1PW */
+#define CB_ATS1PW_ADDR  (CB_ATS1PW_ADDR_MASK << CB_ATS1PW_ADDR_SHIFT)
+
+/* Address Translation, Stage 1, User Read: CB_ATS1UR */
+#define CB_ATS1UR_ADDR  (CB_ATS1UR_ADDR_MASK << CB_ATS1UR_ADDR_SHIFT)
+
+/* Address Translation, Stage 1, User Write: CB_ATS1UW */
+#define CB_ATS1UW_ADDR  (CB_ATS1UW_ADDR_MASK << CB_ATS1UW_ADDR_SHIFT)
+
+/* Address Translation Status Register: CB_ATSR */
+#define CB_ATSR_ACTIVE  (CB_ATSR_ACTIVE_MASK << CB_ATSR_ACTIVE_SHIFT)
+
+/* Context ID Register: CB_CONTEXTIDR */
+#define CB_CONTEXTIDR_ASID    (CB_CONTEXTIDR_ASID_MASK << \
+				CB_CONTEXTIDR_ASID_SHIFT)
+#define CB_CONTEXTIDR_PROCID  (CB_CONTEXTIDR_PROCID_MASK << \
+				CB_CONTEXTIDR_PROCID_SHIFT)
+
+/* Fault Address Register: CB_FAR */
+#define CB_FAR_FADDR  (CB_FAR_FADDR_MASK << CB_FAR_FADDR_SHIFT)
+
+/* Fault Status Register: CB_FSR */
+#define CB_FSR_TF     (CB_FSR_TF_MASK     << CB_FSR_TF_SHIFT)
+#define CB_FSR_AFF    (CB_FSR_AFF_MASK    << CB_FSR_AFF_SHIFT)
+#define CB_FSR_PF     (CB_FSR_PF_MASK     << CB_FSR_PF_SHIFT)
+#define CB_FSR_EF     (CB_FSR_EF_MASK     << CB_FSR_EF_SHIFT)
+#define CB_FSR_TLBMCF (CB_FSR_TLBMCF_MASK << CB_FSR_TLBMCF_SHIFT)
+#define CB_FSR_TLBLKF (CB_FSR_TLBLKF_MASK << CB_FSR_TLBLKF_SHIFT)
+#define CB_FSR_SS     (CB_FSR_SS_MASK     << CB_FSR_SS_SHIFT)
+#define CB_FSR_MULTI  (CB_FSR_MULTI_MASK  << CB_FSR_MULTI_SHIFT)
+
+/* Fault Syndrome Register 0: CB_FSYNR0 */
+#define CB_FSYNR0_PLVL     (CB_FSYNR0_PLVL_MASK    << CB_FSYNR0_PLVL_SHIFT)
+#define CB_FSYNR0_S1PTWF   (CB_FSYNR0_S1PTWF_MASK  << CB_FSYNR0_S1PTWF_SHIFT)
+#define CB_FSYNR0_WNR      (CB_FSYNR0_WNR_MASK     << CB_FSYNR0_WNR_SHIFT)
+#define CB_FSYNR0_PNU      (CB_FSYNR0_PNU_MASK     << CB_FSYNR0_PNU_SHIFT)
+#define CB_FSYNR0_IND      (CB_FSYNR0_IND_MASK     << CB_FSYNR0_IND_SHIFT)
+#define CB_FSYNR0_NSSTATE  (CB_FSYNR0_NSSTATE_MASK << CB_FSYNR0_NSSTATE_SHIFT)
+#define CB_FSYNR0_NSATTR   (CB_FSYNR0_NSATTR_MASK  << CB_FSYNR0_NSATTR_SHIFT)
+#define CB_FSYNR0_ATOF     (CB_FSYNR0_ATOF_MASK    << CB_FSYNR0_ATOF_SHIFT)
+#define CB_FSYNR0_PTWF     (CB_FSYNR0_PTWF_MASK    << CB_FSYNR0_PTWF_SHIFT)
+#define CB_FSYNR0_AFR      (CB_FSYNR0_AFR_MASK     << CB_FSYNR0_AFR_SHIFT)
+#define CB_FSYNR0_S1CBNDX  (CB_FSYNR0_S1CBNDX_MASK << CB_FSYNR0_S1CBNDX_SHIFT)
+
+/* Normal Memory Remap Register: CB_NMRR */
+#define CB_NMRR_IR0        (CB_NMRR_IR0_MASK   << CB_NMRR_IR0_SHIFT)
+#define CB_NMRR_IR1        (CB_NMRR_IR1_MASK   << CB_NMRR_IR1_SHIFT)
+#define CB_NMRR_IR2        (CB_NMRR_IR2_MASK   << CB_NMRR_IR2_SHIFT)
+#define CB_NMRR_IR3        (CB_NMRR_IR3_MASK   << CB_NMRR_IR3_SHIFT)
+#define CB_NMRR_IR4        (CB_NMRR_IR4_MASK   << CB_NMRR_IR4_SHIFT)
+#define CB_NMRR_IR5        (CB_NMRR_IR5_MASK   << CB_NMRR_IR5_SHIFT)
+#define CB_NMRR_IR6        (CB_NMRR_IR6_MASK   << CB_NMRR_IR6_SHIFT)
+#define CB_NMRR_IR7        (CB_NMRR_IR7_MASK   << CB_NMRR_IR7_SHIFT)
+#define CB_NMRR_OR0        (CB_NMRR_OR0_MASK   << CB_NMRR_OR0_SHIFT)
+#define CB_NMRR_OR1        (CB_NMRR_OR1_MASK   << CB_NMRR_OR1_SHIFT)
+#define CB_NMRR_OR2        (CB_NMRR_OR2_MASK   << CB_NMRR_OR2_SHIFT)
+#define CB_NMRR_OR3        (CB_NMRR_OR3_MASK   << CB_NMRR_OR3_SHIFT)
+#define CB_NMRR_OR4        (CB_NMRR_OR4_MASK   << CB_NMRR_OR4_SHIFT)
+#define CB_NMRR_OR5        (CB_NMRR_OR5_MASK   << CB_NMRR_OR5_SHIFT)
+#define CB_NMRR_OR6        (CB_NMRR_OR6_MASK   << CB_NMRR_OR6_SHIFT)
+#define CB_NMRR_OR7        (CB_NMRR_OR7_MASK   << CB_NMRR_OR7_SHIFT)
+
+/* Physical Address Register: CB_PAR */
+#define CB_PAR_F           (CB_PAR_F_MASK      << CB_PAR_F_SHIFT)
+#define CB_PAR_SS          (CB_PAR_SS_MASK     << CB_PAR_SS_SHIFT)
+#define CB_PAR_OUTER       (CB_PAR_OUTER_MASK  << CB_PAR_OUTER_SHIFT)
+#define CB_PAR_INNER       (CB_PAR_INNER_MASK  << CB_PAR_INNER_SHIFT)
+#define CB_PAR_SH          (CB_PAR_SH_MASK     << CB_PAR_SH_SHIFT)
+#define CB_PAR_NS          (CB_PAR_NS_MASK     << CB_PAR_NS_SHIFT)
+#define CB_PAR_NOS         (CB_PAR_NOS_MASK    << CB_PAR_NOS_SHIFT)
+#define CB_PAR_PA          (CB_PAR_PA_MASK     << CB_PAR_PA_SHIFT)
+#define CB_PAR_TF          (CB_PAR_TF_MASK     << CB_PAR_TF_SHIFT)
+#define CB_PAR_AFF         (CB_PAR_AFF_MASK    << CB_PAR_AFF_SHIFT)
+#define CB_PAR_PF          (CB_PAR_PF_MASK     << CB_PAR_PF_SHIFT)
+#define CB_PAR_TLBMCF      (CB_PAR_TLBMCF_MASK << CB_PAR_TLBMCF_SHIFT)
+#define CB_PAR_TLBLKF      (CB_PAR_TLBLKF_MASK << CB_PAR_TLBLKF_SHIFT)
+#define CB_PAR_ATOT        (CB_PAR_ATOT_MASK   << CB_PAR_ATOT_SHIFT)
+#define CB_PAR_PLVL        (CB_PAR_PLVL_MASK   << CB_PAR_PLVL_SHIFT)
+#define CB_PAR_STAGE       (CB_PAR_STAGE_MASK  << CB_PAR_STAGE_SHIFT)
+
+/* Primary Region Remap Register: CB_PRRR */
+#define CB_PRRR_TR0        (CB_PRRR_TR0_MASK   << CB_PRRR_TR0_SHIFT)
+#define CB_PRRR_TR1        (CB_PRRR_TR1_MASK   << CB_PRRR_TR1_SHIFT)
+#define CB_PRRR_TR2        (CB_PRRR_TR2_MASK   << CB_PRRR_TR2_SHIFT)
+#define CB_PRRR_TR3        (CB_PRRR_TR3_MASK   << CB_PRRR_TR3_SHIFT)
+#define CB_PRRR_TR4        (CB_PRRR_TR4_MASK   << CB_PRRR_TR4_SHIFT)
+#define CB_PRRR_TR5        (CB_PRRR_TR5_MASK   << CB_PRRR_TR5_SHIFT)
+#define CB_PRRR_TR6        (CB_PRRR_TR6_MASK   << CB_PRRR_TR6_SHIFT)
+#define CB_PRRR_TR7        (CB_PRRR_TR7_MASK   << CB_PRRR_TR7_SHIFT)
+#define CB_PRRR_DS0        (CB_PRRR_DS0_MASK   << CB_PRRR_DS0_SHIFT)
+#define CB_PRRR_DS1        (CB_PRRR_DS1_MASK   << CB_PRRR_DS1_SHIFT)
+#define CB_PRRR_NS0        (CB_PRRR_NS0_MASK   << CB_PRRR_NS0_SHIFT)
+#define CB_PRRR_NS1        (CB_PRRR_NS1_MASK   << CB_PRRR_NS1_SHIFT)
+#define CB_PRRR_NOS0       (CB_PRRR_NOS0_MASK  << CB_PRRR_NOS0_SHIFT)
+#define CB_PRRR_NOS1       (CB_PRRR_NOS1_MASK  << CB_PRRR_NOS1_SHIFT)
+#define CB_PRRR_NOS2       (CB_PRRR_NOS2_MASK  << CB_PRRR_NOS2_SHIFT)
+#define CB_PRRR_NOS3       (CB_PRRR_NOS3_MASK  << CB_PRRR_NOS3_SHIFT)
+#define CB_PRRR_NOS4       (CB_PRRR_NOS4_MASK  << CB_PRRR_NOS4_SHIFT)
+#define CB_PRRR_NOS5       (CB_PRRR_NOS5_MASK  << CB_PRRR_NOS5_SHIFT)
+#define CB_PRRR_NOS6       (CB_PRRR_NOS6_MASK  << CB_PRRR_NOS6_SHIFT)
+#define CB_PRRR_NOS7       (CB_PRRR_NOS7_MASK  << CB_PRRR_NOS7_SHIFT)
+
+/* Transaction Resume: CB_RESUME */
+#define CB_RESUME_TNR      (CB_RESUME_TNR_MASK << CB_RESUME_TNR_SHIFT)
+
+/* System Control Register: CB_SCTLR */
+#define CB_SCTLR_M           (CB_SCTLR_M_MASK       << CB_SCTLR_M_SHIFT)
+#define CB_SCTLR_TRE         (CB_SCTLR_TRE_MASK     << CB_SCTLR_TRE_SHIFT)
+#define CB_SCTLR_AFE         (CB_SCTLR_AFE_MASK     << CB_SCTLR_AFE_SHIFT)
+#define CB_SCTLR_AFFD        (CB_SCTLR_AFFD_MASK    << CB_SCTLR_AFFD_SHIFT)
+#define CB_SCTLR_E           (CB_SCTLR_E_MASK       << CB_SCTLR_E_SHIFT)
+#define CB_SCTLR_CFRE        (CB_SCTLR_CFRE_MASK    << CB_SCTLR_CFRE_SHIFT)
+#define CB_SCTLR_CFIE        (CB_SCTLR_CFIE_MASK    << CB_SCTLR_CFIE_SHIFT)
+#define CB_SCTLR_CFCFG       (CB_SCTLR_CFCFG_MASK   << CB_SCTLR_CFCFG_SHIFT)
+#define CB_SCTLR_HUPCF       (CB_SCTLR_HUPCF_MASK   << CB_SCTLR_HUPCF_SHIFT)
+#define CB_SCTLR_WXN         (CB_SCTLR_WXN_MASK     << CB_SCTLR_WXN_SHIFT)
+#define CB_SCTLR_UWXN        (CB_SCTLR_UWXN_MASK    << CB_SCTLR_UWXN_SHIFT)
+#define CB_SCTLR_ASIDPNE     (CB_SCTLR_ASIDPNE_MASK << CB_SCTLR_ASIDPNE_SHIFT)
+#define CB_SCTLR_TRANSIENTCFG (CB_SCTLR_TRANSIENTCFG_MASK << \
+						CB_SCTLR_TRANSIENTCFG_SHIFT)
+#define CB_SCTLR_MEMATTR     (CB_SCTLR_MEMATTR_MASK << CB_SCTLR_MEMATTR_SHIFT)
+#define CB_SCTLR_MTCFG       (CB_SCTLR_MTCFG_MASK   << CB_SCTLR_MTCFG_SHIFT)
+#define CB_SCTLR_SHCFG       (CB_SCTLR_SHCFG_MASK   << CB_SCTLR_SHCFG_SHIFT)
+#define CB_SCTLR_RACFG       (CB_SCTLR_RACFG_MASK   << CB_SCTLR_RACFG_SHIFT)
+#define CB_SCTLR_WACFG       (CB_SCTLR_WACFG_MASK   << CB_SCTLR_WACFG_SHIFT)
+#define CB_SCTLR_NSCFG       (CB_SCTLR_NSCFG_MASK   << CB_SCTLR_NSCFG_SHIFT)
+
+/* Invalidate TLB by ASID: CB_TLBIASID */
+#define CB_TLBIASID_ASID     (CB_TLBIASID_ASID_MASK << CB_TLBIASID_ASID_SHIFT)
+
+/* Invalidate TLB by VA: CB_TLBIVA */
+#define CB_TLBIVA_ASID       (CB_TLBIVA_ASID_MASK   << CB_TLBIVA_ASID_SHIFT)
+#define CB_TLBIVA_VA         (CB_TLBIVA_VA_MASK     << CB_TLBIVA_VA_SHIFT)
+
+/* Invalidate TLB by VA, All ASID: CB_TLBIVAA */
+#define CB_TLBIVAA_VA        (CB_TLBIVAA_VA_MASK    << CB_TLBIVAA_VA_SHIFT)
+
+/* Invalidate TLB by VA, All ASID, Last Level: CB_TLBIVAAL */
+#define CB_TLBIVAAL_VA       (CB_TLBIVAAL_VA_MASK   << CB_TLBIVAAL_VA_SHIFT)
+
+/* Invalidate TLB by VA, Last Level: CB_TLBIVAL */
+#define CB_TLBIVAL_ASID      (CB_TLBIVAL_ASID_MASK  << CB_TLBIVAL_ASID_SHIFT)
+#define CB_TLBIVAL_VA        (CB_TLBIVAL_VA_MASK    << CB_TLBIVAL_VA_SHIFT)
+
+/* TLB Status: CB_TLBSTATUS */
+#define CB_TLBSTATUS_SACTIVE (CB_TLBSTATUS_SACTIVE_MASK << \
+						CB_TLBSTATUS_SACTIVE_SHIFT)
+
+/* Translation Table Base Control Register: CB_TTBCR */
+#define CB_TTBCR_T0SZ        (CB_TTBCR_T0SZ_MASK    << CB_TTBCR_T0SZ_SHIFT)
+#define CB_TTBCR_PD0         (CB_TTBCR_PD0_MASK     << CB_TTBCR_PD0_SHIFT)
+#define CB_TTBCR_PD1         (CB_TTBCR_PD1_MASK     << CB_TTBCR_PD1_SHIFT)
+#define CB_TTBCR_NSCFG0      (CB_TTBCR_NSCFG0_MASK  << CB_TTBCR_NSCFG0_SHIFT)
+#define CB_TTBCR_NSCFG1      (CB_TTBCR_NSCFG1_MASK  << CB_TTBCR_NSCFG1_SHIFT)
+#define CB_TTBCR_EAE         (CB_TTBCR_EAE_MASK     << CB_TTBCR_EAE_SHIFT)
+
+/* Translation Table Base Register 0: CB_TTBR0 */
+#define CB_TTBR0_IRGN1       (CB_TTBR0_IRGN1_MASK   << CB_TTBR0_IRGN1_SHIFT)
+#define CB_TTBR0_S           (CB_TTBR0_S_MASK       << CB_TTBR0_S_SHIFT)
+#define CB_TTBR0_RGN         (CB_TTBR0_RGN_MASK     << CB_TTBR0_RGN_SHIFT)
+#define CB_TTBR0_NOS         (CB_TTBR0_NOS_MASK     << CB_TTBR0_NOS_SHIFT)
+#define CB_TTBR0_IRGN0       (CB_TTBR0_IRGN0_MASK   << CB_TTBR0_IRGN0_SHIFT)
+#define CB_TTBR0_ADDR        (CB_TTBR0_ADDR_MASK    << CB_TTBR0_ADDR_SHIFT)
+
+/* Translation Table Base Register 1: CB_TTBR1 */
+#define CB_TTBR1_IRGN1       (CB_TTBR1_IRGN1_MASK   << CB_TTBR1_IRGN1_SHIFT)
+#define CB_TTBR1_S           (CB_TTBR1_S_MASK       << CB_TTBR1_S_SHIFT)
+#define CB_TTBR1_RGN         (CB_TTBR1_RGN_MASK     << CB_TTBR1_RGN_SHIFT)
+#define CB_TTBR1_NOS         (CB_TTBR1_NOS_MASK     << CB_TTBR1_NOS_SHIFT)
+#define CB_TTBR1_IRGN0       (CB_TTBR1_IRGN0_MASK   << CB_TTBR1_IRGN0_SHIFT)
+#define CB_TTBR1_ADDR        (CB_TTBR1_ADDR_MASK    << CB_TTBR1_ADDR_SHIFT)
+
+/* Global Register Masks */
+/* Configuration Register 0 */
+#define CR0_NSCFG_MASK          0x03
+#define CR0_WACFG_MASK          0x03
+#define CR0_RACFG_MASK          0x03
+#define CR0_SHCFG_MASK          0x03
+#define CR0_SMCFCFG_MASK        0x01
+#define CR0_MTCFG_MASK          0x01
+#define CR0_MEMATTR_MASK        0x0F
+#define CR0_BSU_MASK            0x03
+#define CR0_FB_MASK             0x01
+#define CR0_PTM_MASK            0x01
+#define CR0_VMIDPNE_MASK        0x01
+#define CR0_USFCFG_MASK         0x01
+#define CR0_GSE_MASK            0x01
+#define CR0_STALLD_MASK         0x01
+#define CR0_TRANSIENTCFG_MASK   0x03
+#define CR0_GCFGFIE_MASK        0x01
+#define CR0_GCFGFRE_MASK        0x01
+#define CR0_GFIE_MASK           0x01
+#define CR0_GFRE_MASK           0x01
+#define CR0_CLIENTPD_MASK       0x01
+
+/* Configuration Register 2 */
+#define CR2_BPVMID_MASK         0xFF
+
+/* Global Address Translation, Stage 1, Privileged Read: GATS1PR */
+#define GATS1PR_ADDR_MASK       0xFFFFF
+#define GATS1PR_NDX_MASK        0xFF
+
+/* Global Address Translation, Stage 1, Privileged Write: GATS1PW */
+#define GATS1PW_ADDR_MASK       0xFFFFF
+#define GATS1PW_NDX_MASK        0xFF
+
+/* Global Address Translation, Stage 1, User Read: GATS1UR */
+#define GATS1UR_ADDR_MASK       0xFFFFF
+#define GATS1UR_NDX_MASK        0xFF
+
+/* Global Address Translation, Stage 1, User Write: GATS1UW */
+#define GATS1UW_ADDR_MASK       0xFFFFF
+#define GATS1UW_NDX_MASK        0xFF
+
+/* Global Address Translation, Stage 1 and 2, Privileged Read: GATS1PR */
+#define GATS12PR_ADDR_MASK      0xFFFFF
+#define GATS12PR_NDX_MASK       0xFF
+
+/* Global Address Translation, Stage 1 and 2, Privileged Write: GATS1PW */
+#define GATS12PW_ADDR_MASK      0xFFFFF
+#define GATS12PW_NDX_MASK       0xFF
+
+/* Global Address Translation, Stage 1 and 2, User Read: GATS1UR */
+#define GATS12UR_ADDR_MASK      0xFFFFF
+#define GATS12UR_NDX_MASK       0xFF
+
+/* Global Address Translation, Stage 1 and 2, User Write: GATS1UW */
+#define GATS12UW_ADDR_MASK      0xFFFFF
+#define GATS12UW_NDX_MASK       0xFF
+
+/* Global Address Translation Status Register: GATSR */
+#define GATSR_ACTIVE_MASK       0x01
+
+/* Global Fault Address Register: GFAR */
+#define GFAR_FADDR_MASK         0xFFFFFFFF
+
+/* Global Fault Status Register: GFSR */
+#define GFSR_ICF_MASK           0x01
+#define GFSR_USF_MASK           0x01
+#define GFSR_SMCF_MASK          0x01
+#define GFSR_UCBF_MASK          0x01
+#define GFSR_UCIF_MASK          0x01
+#define GFSR_CAF_MASK           0x01
+#define GFSR_EF_MASK            0x01
+#define GFSR_PF_MASK            0x01
+#define GFSR_MULTI_MASK         0x01
+
+/* Global Fault Syndrome Register 0: GFSYNR0 */
+#define GFSYNR0_NESTED_MASK     0x01
+#define GFSYNR0_WNR_MASK        0x01
+#define GFSYNR0_PNU_MASK        0x01
+#define GFSYNR0_IND_MASK        0x01
+#define GFSYNR0_NSSTATE_MASK    0x01
+#define GFSYNR0_NSATTR_MASK     0x01
+
+/* Global Fault Syndrome Register 1: GFSYNR1 */
+#define GFSYNR1_SID_MASK        0x7FFF
+#define GFSYNr1_SSD_IDX_MASK    0x7FFF
+
+/* Global Physical Address Register: GPAR */
+#define GPAR_F_MASK             0x01
+#define GPAR_SS_MASK            0x01
+#define GPAR_OUTER_MASK         0x03
+#define GPAR_INNER_MASK         0x03
+#define GPAR_SH_MASK            0x01
+#define GPAR_NS_MASK            0x01
+#define GPAR_NOS_MASK           0x01
+#define GPAR_PA_MASK            0xFFFFF
+#define GPAR_TF_MASK            0x01
+#define GPAR_AFF_MASK           0x01
+#define GPAR_PF_MASK            0x01
+#define GPAR_EF_MASK            0x01
+#define GPAR_TLBMCF_MASK        0x01
+#define GPAR_TLBLKF_MASK        0x01
+#define GPAR_UCBF_MASK          0x01
+
+/* Identification Register: IDR0 */
+#define IDR0_NUMSMRG_MASK       0xFF
+#define IDR0_NUMSIDB_MASK       0x0F
+#define IDR0_BTM_MASK           0x01
+#define IDR0_CTTW_MASK          0x01
+#define IDR0_NUMIPRT_MASK       0xFF
+#define IDR0_PTFS_MASK          0x01
+#define IDR0_SMS_MASK           0x01
+#define IDR0_NTS_MASK           0x01
+#define IDR0_S2TS_MASK          0x01
+#define IDR0_S1TS_MASK          0x01
+#define IDR0_SES_MASK           0x01
+
+/* Identification Register: IDR1 */
+#define IDR1_NUMCB_MASK         0xFF
+#define IDR1_NUMSSDNDXB_MASK    0x0F
+#define IDR1_SSDTP_MASK         0x01
+#define IDR1_SMCD_MASK          0x01
+#define IDR1_NUMS2CB_MASK       0xFF
+#define IDR1_NUMPAGENDXB_MASK   0x07
+#define IDR1_PAGESIZE_MASK      0x01
+
+/* Identification Register: IDR2 */
+#define IDR2_IAS_MASK           0x0F
+#define IDR2_OAS_MASK           0x0F
+
+/* Identification Register: IDR7 */
+#define IDR7_MINOR_MASK         0x0F
+#define IDR7_MAJOR_MASK         0x0F
+
+/* Stream to Context Register: S2CR */
+#define S2CR_CBNDX_MASK         0xFF
+#define S2CR_SHCFG_MASK         0x03
+#define S2CR_MTCFG_MASK         0x01
+#define S2CR_MEMATTR_MASK       0x0F
+#define S2CR_TYPE_MASK          0x03
+#define S2CR_NSCFG_MASK         0x03
+#define S2CR_RACFG_MASK         0x03
+#define S2CR_WACFG_MASK         0x03
+#define S2CR_PRIVCFG_MASK       0x03
+#define S2CR_INSTCFG_MASK       0x03
+#define S2CR_TRANSIENTCFG_MASK  0x03
+#define S2CR_VMID_MASK          0xFF
+#define S2CR_BSU_MASK           0x03
+#define S2CR_FB_MASK            0x01
+
+/* Stream Match Register: SMR */
+#define SMR_ID_MASK             0x7FFF
+#define SMR_MASK_MASK           0x7FFF
+#define SMR_VALID_MASK          0x01
+
+/* Global TLB Status: TLBGSTATUS */
+#define TLBGSTATUS_GSACTIVE_MASK 0x01
+
+/* Invalidate Hyp TLB by VA: TLBIVAH */
+#define TLBIVAH_ADDR_MASK       0xFFFFF
+
+/* Invalidate TLB by VMID: TLBIVMID */
+#define TLBIVMID_VMID_MASK      0xFF
+
+/* Global Register Space 1 Mask */
+/* Context Bank Attribute Register: CBAR */
+#define CBAR_VMID_MASK          0xFF
+#define CBAR_CBNDX_MASK         0x03
+#define CBAR_BPSHCFG_MASK       0x03
+#define CBAR_HYPC_MASK          0x01
+#define CBAR_FB_MASK            0x01
+#define CBAR_MEMATTR_MASK       0x0F
+#define CBAR_TYPE_MASK          0x03
+#define CBAR_BSU_MASK           0x03
+#define CBAR_RACFG_MASK         0x03
+#define CBAR_WACFG_MASK         0x03
+#define CBAR_IRPTNDX_MASK       0xFF
+
+/* Context Bank Fault Restricted Syndrome Register A: CBFRSYNRA */
+#define CBFRSYNRA_SID_MASK      0x7FFF
+
+/* Stage 1 Context Bank Format Masks */
+/* Auxiliary Control Register: CB_ACTLR */
+#define CB_ACTLR_REQPRIORITY_MASK    0x3
+#define CB_ACTLR_REQPRIORITYCFG_MASK 0x1
+#define CB_ACTLR_PRIVCFG_MASK        0x3
+#define CB_ACTLR_BPRCOSH_MASK        0x1
+#define CB_ACTLR_BPRCISH_MASK        0x1
+#define CB_ACTLR_BPRCNSH_MASK        0x1
+
+/* Address Translation, Stage 1, Privileged Read: CB_ATS1PR */
+#define CB_ATS1PR_ADDR_MASK     0xFFFFF
+
+/* Address Translation, Stage 1, Privileged Write: CB_ATS1PW */
+#define CB_ATS1PW_ADDR_MASK     0xFFFFF
+
+/* Address Translation, Stage 1, User Read: CB_ATS1UR */
+#define CB_ATS1UR_ADDR_MASK     0xFFFFF
+
+/* Address Translation, Stage 1, User Write: CB_ATS1UW */
+#define CB_ATS1UW_ADDR_MASK     0xFFFFF
+
+/* Address Translation Status Register: CB_ATSR */
+#define CB_ATSR_ACTIVE_MASK     0x01
+
+/* Context ID Register: CB_CONTEXTIDR */
+#define CB_CONTEXTIDR_ASID_MASK   0xFF
+#define CB_CONTEXTIDR_PROCID_MASK 0xFFFFFF
+
+/* Fault Address Register: CB_FAR */
+#define CB_FAR_FADDR_MASK       0xFFFFFFFF
+
+/* Fault Status Register: CB_FSR */
+#define CB_FSR_TF_MASK          0x01
+#define CB_FSR_AFF_MASK         0x01
+#define CB_FSR_PF_MASK          0x01
+#define CB_FSR_EF_MASK          0x01
+#define CB_FSR_TLBMCF_MASK      0x01
+#define CB_FSR_TLBLKF_MASK      0x01
+#define CB_FSR_SS_MASK          0x01
+#define CB_FSR_MULTI_MASK       0x01
+
+/* Fault Syndrome Register 0: CB_FSYNR0 */
+#define CB_FSYNR0_PLVL_MASK     0x03
+#define CB_FSYNR0_S1PTWF_MASK   0x01
+#define CB_FSYNR0_WNR_MASK      0x01
+#define CB_FSYNR0_PNU_MASK      0x01
+#define CB_FSYNR0_IND_MASK      0x01
+#define CB_FSYNR0_NSSTATE_MASK  0x01
+#define CB_FSYNR0_NSATTR_MASK   0x01
+#define CB_FSYNR0_ATOF_MASK     0x01
+#define CB_FSYNR0_PTWF_MASK     0x01
+#define CB_FSYNR0_AFR_MASK      0x01
+#define CB_FSYNR0_S1CBNDX_MASK  0xFF
+
+/* Normal Memory Remap Register: CB_NMRR */
+#define CB_NMRR_IR0_MASK        0x03
+#define CB_NMRR_IR1_MASK        0x03
+#define CB_NMRR_IR2_MASK        0x03
+#define CB_NMRR_IR3_MASK        0x03
+#define CB_NMRR_IR4_MASK        0x03
+#define CB_NMRR_IR5_MASK        0x03
+#define CB_NMRR_IR6_MASK        0x03
+#define CB_NMRR_IR7_MASK        0x03
+#define CB_NMRR_OR0_MASK        0x03
+#define CB_NMRR_OR1_MASK        0x03
+#define CB_NMRR_OR2_MASK        0x03
+#define CB_NMRR_OR3_MASK        0x03
+#define CB_NMRR_OR4_MASK        0x03
+#define CB_NMRR_OR5_MASK        0x03
+#define CB_NMRR_OR6_MASK        0x03
+#define CB_NMRR_OR7_MASK        0x03
+
+/* Physical Address Register: CB_PAR */
+#define CB_PAR_F_MASK           0x01
+#define CB_PAR_SS_MASK          0x01
+#define CB_PAR_OUTER_MASK       0x03
+#define CB_PAR_INNER_MASK       0x07
+#define CB_PAR_SH_MASK          0x01
+#define CB_PAR_NS_MASK          0x01
+#define CB_PAR_NOS_MASK         0x01
+#define CB_PAR_PA_MASK          0xFFFFF
+#define CB_PAR_TF_MASK          0x01
+#define CB_PAR_AFF_MASK         0x01
+#define CB_PAR_PF_MASK          0x01
+#define CB_PAR_TLBMCF_MASK      0x01
+#define CB_PAR_TLBLKF_MASK      0x01
+#define CB_PAR_ATOT_MASK        0x01
+#define CB_PAR_PLVL_MASK        0x03
+#define CB_PAR_STAGE_MASK       0x01
+
+/* Primary Region Remap Register: CB_PRRR */
+#define CB_PRRR_TR0_MASK        0x03
+#define CB_PRRR_TR1_MASK        0x03
+#define CB_PRRR_TR2_MASK        0x03
+#define CB_PRRR_TR3_MASK        0x03
+#define CB_PRRR_TR4_MASK        0x03
+#define CB_PRRR_TR5_MASK        0x03
+#define CB_PRRR_TR6_MASK        0x03
+#define CB_PRRR_TR7_MASK        0x03
+#define CB_PRRR_DS0_MASK        0x01
+#define CB_PRRR_DS1_MASK        0x01
+#define CB_PRRR_NS0_MASK        0x01
+#define CB_PRRR_NS1_MASK        0x01
+#define CB_PRRR_NOS0_MASK       0x01
+#define CB_PRRR_NOS1_MASK       0x01
+#define CB_PRRR_NOS2_MASK       0x01
+#define CB_PRRR_NOS3_MASK       0x01
+#define CB_PRRR_NOS4_MASK       0x01
+#define CB_PRRR_NOS5_MASK       0x01
+#define CB_PRRR_NOS6_MASK       0x01
+#define CB_PRRR_NOS7_MASK       0x01
+
+/* Transaction Resume: CB_RESUME */
+#define CB_RESUME_TNR_MASK      0x01
+
+/* System Control Register: CB_SCTLR */
+#define CB_SCTLR_M_MASK            0x01
+#define CB_SCTLR_TRE_MASK          0x01
+#define CB_SCTLR_AFE_MASK          0x01
+#define CB_SCTLR_AFFD_MASK         0x01
+#define CB_SCTLR_E_MASK            0x01
+#define CB_SCTLR_CFRE_MASK         0x01
+#define CB_SCTLR_CFIE_MASK         0x01
+#define CB_SCTLR_CFCFG_MASK        0x01
+#define CB_SCTLR_HUPCF_MASK        0x01
+#define CB_SCTLR_WXN_MASK          0x01
+#define CB_SCTLR_UWXN_MASK         0x01
+#define CB_SCTLR_ASIDPNE_MASK      0x01
+#define CB_SCTLR_TRANSIENTCFG_MASK 0x03
+#define CB_SCTLR_MEMATTR_MASK      0x0F
+#define CB_SCTLR_MTCFG_MASK        0x01
+#define CB_SCTLR_SHCFG_MASK        0x03
+#define CB_SCTLR_RACFG_MASK        0x03
+#define CB_SCTLR_WACFG_MASK        0x03
+#define CB_SCTLR_NSCFG_MASK        0x03
+
+/* Invalidate TLB by ASID: CB_TLBIASID */
+#define CB_TLBIASID_ASID_MASK      0xFF
+
+/* Invalidate TLB by VA: CB_TLBIVA */
+#define CB_TLBIVA_ASID_MASK        0xFF
+#define CB_TLBIVA_VA_MASK          0xFFFFF
+
+/* Invalidate TLB by VA, All ASID: CB_TLBIVAA */
+#define CB_TLBIVAA_VA_MASK         0xFFFFF
+
+/* Invalidate TLB by VA, All ASID, Last Level: CB_TLBIVAAL */
+#define CB_TLBIVAAL_VA_MASK        0xFFFFF
+
+/* Invalidate TLB by VA, Last Level: CB_TLBIVAL */
+#define CB_TLBIVAL_ASID_MASK       0xFF
+#define CB_TLBIVAL_VA_MASK         0xFFFFF
+
+/* TLB Status: CB_TLBSTATUS */
+#define CB_TLBSTATUS_SACTIVE_MASK  0x01
+
+/* Translation Table Base Control Register: CB_TTBCR */
+#define CB_TTBCR_T0SZ_MASK         0x07
+#define CB_TTBCR_PD0_MASK          0x01
+#define CB_TTBCR_PD1_MASK          0x01
+#define CB_TTBCR_NSCFG0_MASK       0x01
+#define CB_TTBCR_NSCFG1_MASK       0x01
+#define CB_TTBCR_EAE_MASK          0x01
+
+/* Translation Table Base Register 0/1: CB_TTBR */
+#define CB_TTBR0_IRGN1_MASK        0x01
+#define CB_TTBR0_S_MASK            0x01
+#define CB_TTBR0_RGN_MASK          0x01
+#define CB_TTBR0_NOS_MASK          0x01
+#define CB_TTBR0_IRGN0_MASK        0x01
+#define CB_TTBR0_ADDR_MASK         0xFFFFFF
+
+#define CB_TTBR1_IRGN1_MASK        0x1
+#define CB_TTBR1_S_MASK            0x1
+#define CB_TTBR1_RGN_MASK          0x1
+#define CB_TTBR1_NOS_MASK          0X1
+#define CB_TTBR1_IRGN0_MASK        0X1
+#define CB_TTBR1_ADDR_MASK         0xFFFFFF
+
+/* Global Register Shifts */
+/* Configuration Register: CR0 */
+#define CR0_NSCFG_SHIFT            28
+#define CR0_WACFG_SHIFT            26
+#define CR0_RACFG_SHIFT            24
+#define CR0_SHCFG_SHIFT            22
+#define CR0_SMCFCFG_SHIFT          21
+#define CR0_MTCFG_SHIFT            20
+#define CR0_MEMATTR_SHIFT          16
+#define CR0_BSU_SHIFT              14
+#define CR0_FB_SHIFT               13
+#define CR0_PTM_SHIFT              12
+#define CR0_VMIDPNE_SHIFT          11
+#define CR0_USFCFG_SHIFT           10
+#define CR0_GSE_SHIFT              9
+#define CR0_STALLD_SHIFT           8
+#define CR0_TRANSIENTCFG_SHIFT     6
+#define CR0_GCFGFIE_SHIFT          5
+#define CR0_GCFGFRE_SHIFT          4
+#define CR0_GFIE_SHIFT             2
+#define CR0_GFRE_SHIFT             1
+#define CR0_CLIENTPD_SHIFT         0
+
+/* Configuration Register: CR2 */
+#define CR2_BPVMID_SHIFT           0
+
+/* Global Address Translation, Stage 1, Privileged Read: GATS1PR */
+#define GATS1PR_ADDR_SHIFT         12
+#define GATS1PR_NDX_SHIFT          0
+
+/* Global Address Translation, Stage 1, Privileged Write: GATS1PW */
+#define GATS1PW_ADDR_SHIFT         12
+#define GATS1PW_NDX_SHIFT          0
+
+/* Global Address Translation, Stage 1, User Read: GATS1UR */
+#define GATS1UR_ADDR_SHIFT         12
+#define GATS1UR_NDX_SHIFT          0
+
+/* Global Address Translation, Stage 1, User Write: GATS1UW */
+#define GATS1UW_ADDR_SHIFT         12
+#define GATS1UW_NDX_SHIFT          0
+
+/* Global Address Translation, Stage 1 and 2, Privileged Read: GATS12PR */
+#define GATS12PR_ADDR_SHIFT        12
+#define GATS12PR_NDX_SHIFT         0
+
+/* Global Address Translation, Stage 1 and 2, Privileged Write: GATS12PW */
+#define GATS12PW_ADDR_SHIFT        12
+#define GATS12PW_NDX_SHIFT         0
+
+/* Global Address Translation, Stage 1 and 2, User Read: GATS12UR */
+#define GATS12UR_ADDR_SHIFT        12
+#define GATS12UR_NDX_SHIFT         0
+
+/* Global Address Translation, Stage 1 and 2, User Write: GATS12UW */
+#define GATS12UW_ADDR_SHIFT        12
+#define GATS12UW_NDX_SHIFT         0
+
+/* Global Address Translation Status Register: GATSR */
+#define GATSR_ACTIVE_SHIFT         0
+
+/* Global Fault Address Register: GFAR */
+#define GFAR_FADDR_SHIFT           0
+
+/* Global Fault Status Register: GFSR */
+#define GFSR_ICF_SHIFT             0
+#define GFSR_USF_SHIFT             1
+#define GFSR_SMCF_SHIFT            2
+#define GFSR_UCBF_SHIFT            3
+#define GFSR_UCIF_SHIFT            4
+#define GFSR_CAF_SHIFT             5
+#define GFSR_EF_SHIFT              6
+#define GFSR_PF_SHIFT              7
+#define GFSR_MULTI_SHIFT           31
+
+/* Global Fault Syndrome Register 0: GFSYNR0 */
+#define GFSYNR0_NESTED_SHIFT       0
+#define GFSYNR0_WNR_SHIFT          1
+#define GFSYNR0_PNU_SHIFT          2
+#define GFSYNR0_IND_SHIFT          3
+#define GFSYNR0_NSSTATE_SHIFT      4
+#define GFSYNR0_NSATTR_SHIFT       5
+
+/* Global Fault Syndrome Register 1: GFSYNR1 */
+#define GFSYNR1_SID_SHIFT          0
+
+/* Global Physical Address Register: GPAR */
+#define GPAR_F_SHIFT               0
+#define GPAR_SS_SHIFT              1
+#define GPAR_OUTER_SHIFT           2
+#define GPAR_INNER_SHIFT           4
+#define GPAR_SH_SHIFT              7
+#define GPAR_NS_SHIFT              9
+#define GPAR_NOS_SHIFT             10
+#define GPAR_PA_SHIFT              12
+#define GPAR_TF_SHIFT              1
+#define GPAR_AFF_SHIFT             2
+#define GPAR_PF_SHIFT              3
+#define GPAR_EF_SHIFT              4
+#define GPAR_TLCMCF_SHIFT          5
+#define GPAR_TLBLKF_SHIFT          6
+#define GFAR_UCBF_SHIFT            30
+
+/* Identification Register: IDR0 */
+#define IDR0_NUMSMRG_SHIFT         0
+#define IDR0_NUMSIDB_SHIFT         9
+#define IDR0_BTM_SHIFT             13
+#define IDR0_CTTW_SHIFT            14
+#define IDR0_NUMIRPT_SHIFT         16
+#define IDR0_PTFS_SHIFT            24
+#define IDR0_SMS_SHIFT             27
+#define IDR0_NTS_SHIFT             28
+#define IDR0_S2TS_SHIFT            29
+#define IDR0_S1TS_SHIFT            30
+#define IDR0_SES_SHIFT             31
+
+/* Identification Register: IDR1 */
+#define IDR1_NUMCB_SHIFT           0
+#define IDR1_NUMSSDNDXB_SHIFT      8
+#define IDR1_SSDTP_SHIFT           12
+#define IDR1_SMCD_SHIFT            15
+#define IDR1_NUMS2CB_SHIFT         16
+#define IDR1_NUMPAGENDXB_SHIFT     28
+#define IDR1_PAGESIZE_SHIFT        31
+
+/* Identification Register: IDR2 */
+#define IDR2_IAS_SHIFT             0
+#define IDR2_OAS_SHIFT             4
+
+/* Identification Register: IDR7 */
+#define IDR7_MINOR_SHIFT           0
+#define IDR7_MAJOR_SHIFT           4
+
+/* Stream to Context Register: S2CR */
+#define S2CR_CBNDX_SHIFT           0
+#define s2CR_SHCFG_SHIFT           8
+#define S2CR_MTCFG_SHIFT           11
+#define S2CR_MEMATTR_SHIFT         12
+#define S2CR_TYPE_SHIFT            16
+#define S2CR_NSCFG_SHIFT           18
+#define S2CR_RACFG_SHIFT           20
+#define S2CR_WACFG_SHIFT           22
+#define S2CR_PRIVCFG_SHIFT         24
+#define S2CR_INSTCFG_SHIFT         26
+#define S2CR_TRANSIENTCFG_SHIFT    28
+#define S2CR_VMID_SHIFT            0
+#define S2CR_BSU_SHIFT             24
+#define S2CR_FB_SHIFT              26
+
+/* Stream Match Register: SMR */
+#define SMR_ID_SHIFT               0
+#define SMR_MASK_SHIFT             16
+#define SMR_VALID_SHIFT            31
+
+/* Global TLB Status: TLBGSTATUS */
+#define TLBGSTATUS_GSACTIVE_SHIFT  0
+
+/* Invalidate Hyp TLB by VA: TLBIVAH */
+#define TLBIVAH_ADDR_SHIFT         12
+
+/* Invalidate TLB by VMID: TLBIVMID */
+#define TLBIVMID_VMID_SHIFT        0
+
+/* Context Bank Attribute Register: CBAR */
+#define CBAR_VMID_SHIFT            0
+#define CBAR_CBNDX_SHIFT           8
+#define CBAR_BPSHCFG_SHIFT         8
+#define CBAR_HYPC_SHIFT            10
+#define CBAR_FB_SHIFT              11
+#define CBAR_MEMATTR_SHIFT         12
+#define CBAR_TYPE_SHIFT            16
+#define CBAR_BSU_SHIFT             18
+#define CBAR_RACFG_SHIFT           20
+#define CBAR_WACFG_SHIFT           22
+#define CBAR_IRPTNDX_SHIFT         24
+
+/* Context Bank Fault Restricted Syndrome Register A: CBFRSYNRA */
+#define CBFRSYNRA_SID_SHIFT        0
+
+/* Stage 1 Context Bank Format Shifts */
+/* Auxiliary Control Register: CB_ACTLR */
+#define CB_ACTLR_REQPRIORITY_SHIFT     0
+#define CB_ACTLR_REQPRIORITYCFG_SHIFT  4
+#define CB_ACTLR_PRIVCFG_SHIFT         8
+#define CB_ACTLR_BPRCOSH_SHIFT         28
+#define CB_ACTLR_BPRCISH_SHIFT         29
+#define CB_ACTLR_BPRCNSH_SHIFT         30
+
+/* Address Translation, Stage 1, Privileged Read: CB_ATS1PR */
+#define CB_ATS1PR_ADDR_SHIFT       12
+
+/* Address Translation, Stage 1, Privileged Write: CB_ATS1PW */
+#define CB_ATS1PW_ADDR_SHIFT       12
+
+/* Address Translation, Stage 1, User Read: CB_ATS1UR */
+#define CB_ATS1UR_ADDR_SHIFT       12
+
+/* Address Translation, Stage 1, User Write: CB_ATS1UW */
+#define CB_ATS1UW_ADDR_SHIFT       12
+
+/* Address Translation Status Register: CB_ATSR */
+#define CB_ATSR_ACTIVE_SHIFT       0
+
+/* Context ID Register: CB_CONTEXTIDR */
+#define CB_CONTEXTIDR_ASID_SHIFT   0
+#define CB_CONTEXTIDR_PROCID_SHIFT 8
+
+/* Fault Address Register: CB_FAR */
+#define CB_FAR_FADDR_SHIFT         0
+
+/* Fault Status Register: CB_FSR */
+#define CB_FSR_TF_SHIFT            1
+#define CB_FSR_AFF_SHIFT           2
+#define CB_FSR_PF_SHIFT            3
+#define CB_FSR_EF_SHIFT            4
+#define CB_FSR_TLBMCF_SHIFT        5
+#define CB_FSR_TLBLKF_SHIFT        6
+#define CB_FSR_SS_SHIFT            30
+#define CB_FSR_MULTI_SHIFT         31
+
+/* Fault Syndrome Register 0: CB_FSYNR0 */
+#define CB_FSYNR0_PLVL_SHIFT       0
+#define CB_FSYNR0_S1PTWF_SHIFT     3
+#define CB_FSYNR0_WNR_SHIFT        4
+#define CB_FSYNR0_PNU_SHIFT        5
+#define CB_FSYNR0_IND_SHIFT        6
+#define CB_FSYNR0_NSSTATE_SHIFT    7
+#define CB_FSYNR0_NSATTR_SHIFT     8
+#define CB_FSYNR0_ATOF_SHIFT       9
+#define CB_FSYNR0_PTWF_SHIFT       10
+#define CB_FSYNR0_AFR_SHIFT        11
+#define CB_FSYNR0_S1CBNDX_SHIFT    16
+
+/* Normal Memory Remap Register: CB_NMRR */
+#define CB_NMRR_IR0_SHIFT          0
+#define CB_NMRR_IR1_SHIFT          2
+#define CB_NMRR_IR2_SHIFT          4
+#define CB_NMRR_IR3_SHIFT          6
+#define CB_NMRR_IR4_SHIFT          8
+#define CB_NMRR_IR5_SHIFT          10
+#define CB_NMRR_IR6_SHIFT          12
+#define CB_NMRR_IR7_SHIFT          14
+#define CB_NMRR_OR0_SHIFT          16
+#define CB_NMRR_OR1_SHIFT          18
+#define CB_NMRR_OR2_SHIFT          20
+#define CB_NMRR_OR3_SHIFT          22
+#define CB_NMRR_OR4_SHIFT          24
+#define CB_NMRR_OR5_SHIFT          26
+#define CB_NMRR_OR6_SHIFT          28
+#define CB_NMRR_OR7_SHIFT          30
+
+/* Physical Address Register: CB_PAR */
+#define CB_PAR_F_SHIFT             0
+#define CB_PAR_SS_SHIFT            1
+#define CB_PAR_OUTER_SHIFT         2
+#define CB_PAR_INNER_SHIFT         4
+#define CB_PAR_SH_SHIFT            7
+#define CB_PAR_NS_SHIFT            9
+#define CB_PAR_NOS_SHIFT           10
+#define CB_PAR_PA_SHIFT            12
+#define CB_PAR_TF_SHIFT            1
+#define CB_PAR_AFF_SHIFT           2
+#define CB_PAR_PF_SHIFT            3
+#define CB_PAR_TLBMCF_SHIFT        5
+#define CB_PAR_TLBLKF_SHIFT        6
+#define CB_PAR_ATOT_SHIFT          31
+#define CB_PAR_PLVL_SHIFT          0
+#define CB_PAR_STAGE_SHIFT         3
+
+/* Primary Region Remap Register: CB_PRRR */
+#define CB_PRRR_TR0_SHIFT          0
+#define CB_PRRR_TR1_SHIFT          2
+#define CB_PRRR_TR2_SHIFT          4
+#define CB_PRRR_TR3_SHIFT          6
+#define CB_PRRR_TR4_SHIFT          8
+#define CB_PRRR_TR5_SHIFT          10
+#define CB_PRRR_TR6_SHIFT          12
+#define CB_PRRR_TR7_SHIFT          14
+#define CB_PRRR_DS0_SHIFT          16
+#define CB_PRRR_DS1_SHIFT          17
+#define CB_PRRR_NS0_SHIFT          18
+#define CB_PRRR_NS1_SHIFT          19
+#define CB_PRRR_NOS0_SHIFT         24
+#define CB_PRRR_NOS1_SHIFT         25
+#define CB_PRRR_NOS2_SHIFT         26
+#define CB_PRRR_NOS3_SHIFT         27
+#define CB_PRRR_NOS4_SHIFT         28
+#define CB_PRRR_NOS5_SHIFT         29
+#define CB_PRRR_NOS6_SHIFT         30
+#define CB_PRRR_NOS7_SHIFT         31
+
+/* Transaction Resume: CB_RESUME */
+#define CB_RESUME_TNR_SHIFT        0
+
+/* System Control Register: CB_SCTLR */
+#define CB_SCTLR_M_SHIFT            0
+#define CB_SCTLR_TRE_SHIFT          1
+#define CB_SCTLR_AFE_SHIFT          2
+#define CB_SCTLR_AFFD_SHIFT         3
+#define CB_SCTLR_E_SHIFT            4
+#define CB_SCTLR_CFRE_SHIFT         5
+#define CB_SCTLR_CFIE_SHIFT         6
+#define CB_SCTLR_CFCFG_SHIFT        7
+#define CB_SCTLR_HUPCF_SHIFT        8
+#define CB_SCTLR_WXN_SHIFT          9
+#define CB_SCTLR_UWXN_SHIFT         10
+#define CB_SCTLR_ASIDPNE_SHIFT      12
+#define CB_SCTLR_TRANSIENTCFG_SHIFT 14
+#define CB_SCTLR_MEMATTR_SHIFT      16
+#define CB_SCTLR_MTCFG_SHIFT        20
+#define CB_SCTLR_SHCFG_SHIFT        22
+#define CB_SCTLR_RACFG_SHIFT        24
+#define CB_SCTLR_WACFG_SHIFT        26
+#define CB_SCTLR_NSCFG_SHIFT        28
+
+/* Invalidate TLB by ASID: CB_TLBIASID */
+#define CB_TLBIASID_ASID_SHIFT      0
+
+/* Invalidate TLB by VA: CB_TLBIVA */
+#define CB_TLBIVA_ASID_SHIFT        0
+#define CB_TLBIVA_VA_SHIFT          12
+
+/* Invalidate TLB by VA, All ASID: CB_TLBIVAA */
+#define CB_TLBIVAA_VA_SHIFT         12
+
+/* Invalidate TLB by VA, All ASID, Last Level: CB_TLBIVAAL */
+#define CB_TLBIVAAL_VA_SHIFT        12
+
+/* Invalidate TLB by VA, Last Level: CB_TLBIVAL */
+#define CB_TLBIVAL_ASID_SHIFT       0
+#define CB_TLBIVAL_VA_SHIFT         12
+
+/* TLB Status: CB_TLBSTATUS */
+#define CB_TLBSTATUS_SACTIVE_SHIFT  0
+
+/* Translation Table Base Control Register: CB_TTBCR */
+#define CB_TTBCR_T0SZ_SHIFT         0
+#define CB_TTBCR_PD0_SHIFT          4
+#define CB_TTBCR_PD1_SHIFT          5
+#define CB_TTBCR_NSCFG0_SHIFT       14
+#define CB_TTBCR_NSCFG1_SHIFT       30
+#define CB_TTBCR_EAE_SHIFT          31
+
+/* Translation Table Base Register 0/1: CB_TTBR */
+#define CB_TTBR0_IRGN1_SHIFT        0
+#define CB_TTBR0_S_SHIFT            1
+#define CB_TTBR0_RGN_SHIFT          3
+#define CB_TTBR0_NOS_SHIFT          5
+#define CB_TTBR0_IRGN0_SHIFT        6
+#define CB_TTBR0_ADDR_SHIFT         14
+
+#define CB_TTBR1_IRGN1_SHIFT        0
+#define CB_TTBR1_S_SHIFT            1
+#define CB_TTBR1_RGN_SHIFT          3
+#define CB_TTBR1_NOS_SHIFT          5
+#define CB_TTBR1_IRGN0_SHIFT        6
+#define CB_TTBR1_ADDR_SHIFT         14
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/mdm2.h b/arch/arm/mach-msm/include/mach/mdm2.h
index 78ca88f..997b3be 100644
--- a/arch/arm/mach-msm/include/mach/mdm2.h
+++ b/arch/arm/mach-msm/include/mach/mdm2.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -16,6 +16,9 @@
 struct mdm_platform_data {
 	char *mdm_version;
 	int ramdump_delay_ms;
+	int soft_reset_inverted;
+	int early_power_on;
+	int sfr_query;
 	struct platform_device *peripheral_platform_device;
 };
 
diff --git a/arch/arm/mach-msm/include/mach/msm_battery.h b/arch/arm/mach-msm/include/mach/msm_battery.h
index c54e7d8..fe496d5 100644
--- a/arch/arm/mach-msm/include/mach/msm_battery.h
+++ b/arch/arm/mach-msm/include/mach/msm_battery.h
@@ -21,6 +21,7 @@
 struct msm_psy_batt_pdata {
 	u32 voltage_max_design;
 	u32 voltage_min_design;
+	u32 voltage_fail_safe;
 	u32 avail_chg_sources;
 	u32 batt_technology;
 	u32 (*calculate_capacity)(u32 voltage);
diff --git a/arch/arm/mach-msm/include/mach/msm_bus_board.h b/arch/arm/mach-msm/include/mach/msm_bus_board.h
index f62bc86..956d44e 100644
--- a/arch/arm/mach-msm/include/mach/msm_bus_board.h
+++ b/arch/arm/mach-msm/include/mach/msm_bus_board.h
@@ -37,6 +37,8 @@
 	const unsigned int ntieredslaves;
 	bool il_flag;
 	const struct msm_bus_board_algorithm *board_algo;
+	int hw_sel;
+	void *hw_data;
 };
 
 enum msm_bus_bw_tier_type {
@@ -154,6 +156,16 @@
 	MSM_BUS_FAB_CPSS_FPB = 4096,
 };
 
+enum msm_bus_fab_noc_bimc_type {
+	MSM_BUS_FAB_BIMC = 0,
+	MSM_BUS_FAB_SYS_NOC = 1024,
+	MSM_BUS_FAB_MMSS_NOC = 2048,
+	MSM_BUS_FAB_OCMEM_NOC = 3072,
+	MSM_BUS_FAB_PERIPH_NOC = 4096,
+	MSM_BUS_FAB_CONFIG_NOC = 5120,
+	MSM_BUS_FAB_OCMEM_VNOC = 6144,
+};
+
 enum msm_bus_fabric_master_type {
 	MSM_BUS_MASTER_FIRST = 1,
 	MSM_BUS_MASTER_AMPSS_M0 = 1,
@@ -212,7 +224,50 @@
 	MSM_BUS_MASTER_GRAPHICS_3D_PORT1,
 	MSM_BUS_MASTER_VIDEO_ENC,
 	MSM_BUS_MASTER_VIDEO_DEC,
-	MSM_BUS_MASTER_LAST = MSM_BUS_MASTER_VIDEO_DEC,
+
+	MSM_BUS_MASTER_LPASS_AHB,
+	MSM_BUS_MASTER_QDSS_BAM,
+	MSM_BUS_MASTER_SNOC_CFG,
+	MSM_BUS_MASTER_CRYPTO_CORE0,
+	MSM_BUS_MASTER_CRYPTO_CORE1,
+	MSM_BUS_MASTER_MSS_NAV,
+	MSM_BUS_MASTER_OCMEM_DMA,
+	MSM_BUS_MASTER_WCSS,
+	MSM_BUS_MASTER_QDSS_ETR,
+	MSM_BUS_MASTER_USB3,
+
+	MSM_BUS_MASTER_JPEG,
+	MSM_BUS_MASTER_VIDEO_P0,
+	MSM_BUS_MASTER_VIDEO_P1,
+
+	MSM_BUS_MASTER_MSS_PROC,
+	MSM_BUS_MASTER_JPEG_OCMEM,
+	MSM_BUS_MASTER_MDP_OCMEM,
+	MSM_BUS_MASTER_VIDEO_P0_OCMEM,
+	MSM_BUS_MASTER_VIDEO_P1_OCMEM,
+	MSM_BUS_MASTER_VFE_OCMEM,
+	MSM_BUS_MASTER_CNOC_ONOC_CFG,
+	MSM_BUS_MASTER_RPM_INST,
+	MSM_BUS_MASTER_RPM_DATA,
+	MSM_BUS_MASTER_RPM_SYS,
+	MSM_BUS_MASTER_DEHR,
+	MSM_BUS_MASTER_QDSS_DAP,
+	MSM_BUS_MASTER_TIC,
+
+	MSM_BUS_MASTER_SDCC_1,
+	MSM_BUS_MASTER_SDCC_3,
+	MSM_BUS_MASTER_SDCC_4,
+	MSM_BUS_MASTER_SDCC_2,
+	MSM_BUS_MASTER_TSIF,
+	MSM_BUS_MASTER_BAM_DMA,
+	MSM_BUS_MASTER_BLSP_2,
+	MSM_BUS_MASTER_USB_HSIC,
+	MSM_BUS_MASTER_BLSP_1,
+	MSM_BUS_MASTER_USB_HS,
+	MSM_BUS_MASTER_PNOC_CFG,
+	MSM_BUS_MASTER_V_OCMEM_GFX3D,
+
+	MSM_BUS_MASTER_LAST = MSM_BUS_MASTER_V_OCMEM_GFX3D,
 
 	MSM_BUS_SYSTEM_FPB_MASTER_SYSTEM =
 		MSM_BUS_SYSTEM_MASTER_SYSTEM_FPB,
@@ -297,7 +352,77 @@
 	MSM_BUS_SLAVE_MSM_PRNG,
 	MSM_BUS_SLAVE_GSS,
 	MSM_BUS_SLAVE_SATA,
-	MSM_BUS_SLAVE_LAST = MSM_BUS_SLAVE_MSM_PRNG,
+
+	MSM_BUS_SLAVE_USB3,
+	MSM_BUS_SLAVE_WCSS,
+	MSM_BUS_SLAVE_OCIMEM,
+	MSM_BUS_SLAVE_SNOC_OCMEM,
+	MSM_BUS_SLAVE_SERVICE_SNOC,
+	MSM_BUS_SLAVE_QDSS_STM,
+
+	MSM_BUS_SLAVE_CAMERA_CFG,
+	MSM_BUS_SLAVE_DISPLAY_CFG,
+	MSM_BUS_SLAVE_OCMEM_CFG,
+	MSM_BUS_SLAVE_CPR_CFG,
+	MSM_BUS_SLAVE_CPR_XPU_CFG,
+	MSM_BUS_SLAVE_MISC_CFG,
+	MSM_BUS_SLAVE_MISC_XPU_CFG,
+	MSM_BUS_SLAVE_VENUS_CFG,
+	MSM_BUS_SLAVE_MISC_VENUS_CFG,
+	MSM_BUS_SLAVE_GRAPHICS_3D_CFG,
+	MSM_BUS_SLAVE_MMSS_CLK_CFG,
+	MSM_BUS_SLAVE_MMSS_CLK_XPU_CFG,
+	MSM_BUS_SLAVE_MNOC_MPU_CFG,
+	MSM_BUS_SLAVE_ONOC_MPU_CFG,
+	MSM_BUS_SLAVE_SERVICE_MNOC,
+
+	MSM_BUS_SLAVE_OCMEM,
+	MSM_BUS_SLAVE_SERVICE_ONOC,
+
+	MSM_BUS_SLAVE_SDCC_1,
+	MSM_BUS_SLAVE_SDCC_3,
+	MSM_BUS_SLAVE_SDCC_2,
+	MSM_BUS_SLAVE_SDCC_4,
+	MSM_BUS_SLAVE_BAM_DMA,
+	MSM_BUS_SLAVE_BLSP_2,
+	MSM_BUS_SLAVE_USB_HSIC,
+	MSM_BUS_SLAVE_BLSP_1,
+	MSM_BUS_SLAVE_USB_HS,
+	MSM_BUS_SLAVE_PDM,
+	MSM_BUS_SLAVE_PERIPH_APU_CFG,
+	MSM_BUS_SLAVE_PNOC_MPU_CFG,
+	MSM_BUS_SLAVE_PRNG,
+	MSM_BUS_SLAVE_SERVICE_PNOC,
+
+	MSM_BUS_SLAVE_CLK_CTL,
+	MSM_BUS_SLAVE_CNOC_MSS,
+	MSM_BUS_SLAVE_SECURITY,
+	MSM_BUS_SLAVE_TCSR,
+	MSM_BUS_SLAVE_TLMM,
+	MSM_BUS_SLAVE_CRYPTO_0_CFG,
+	MSM_BUS_SLAVE_CRYPTO_1_CFG,
+	MSM_BUS_SLAVE_IMEM_CFG,
+	MSM_BUS_SLAVE_MESSAGE_RAM,
+	MSM_BUS_SLAVE_BIMC_CFG,
+	MSM_BUS_SLAVE_BOOT_ROM,
+	MSM_BUS_SLAVE_CNOC_MNOC_MMSS_CFG,
+	MSM_BUS_SLAVE_PMIC_ARB,
+	MSM_BUS_SLAVE_SPDM_WRAPPER,
+	MSM_BUS_SLAVE_DEHR_CFG,
+	MSM_BUS_SLAVE_QDSS_CFG,
+	MSM_BUS_SLAVE_RBCPR_CFG,
+	MSM_BUS_SLAVE_RBCPR_QDSS_APU_CFG,
+	MSM_BUS_SLAVE_SNOC_MPU_CFG,
+	MSM_BUS_SLAVE_CNOC_ONOC_CFG,
+	MSM_BUS_SLAVE_CNOC_MNOC_CFG,
+	MSM_BUS_SLAVE_PNOC_CFG,
+	MSM_BUS_SLAVE_SNOC_CFG,
+	MSM_BUS_SLAVE_EBI1_DLL_CFG,
+	MSM_BUS_SLAVE_PHY_APU_CFG,
+	MSM_BUS_SLAVE_EBI1_PHY_CFG,
+	MSM_BUS_SLAVE_SERVICE_CNOC,
+
+	MSM_BUS_SLAVE_LAST = MSM_BUS_SLAVE_SERVICE_CNOC,
 
 	MSM_BUS_SYSTEM_FPB_SLAVE_SYSTEM =
 		MSM_BUS_SYSTEM_SLAVE_SYSTEM_FPB,
diff --git a/arch/arm/mach-msm/include/mach/msm_cache_dump.h b/arch/arm/mach-msm/include/mach/msm_cache_dump.h
index 6e4f628..80f4159 100644
--- a/arch/arm/mach-msm/include/mach/msm_cache_dump.h
+++ b/arch/arm/mach-msm/include/mach/msm_cache_dump.h
@@ -57,9 +57,6 @@
 	unsigned int l2_size;
 };
 
-#define L1_BUFFER_SIZE	SZ_1M
-#define L2_BUFFER_SIZE	SZ_4M
-
 #define CACHE_BUFFER_DUMP_SIZE (L1_BUFFER_SIZE + L2_BUFFER_SIZE)
 
 #define L1C_SERVICE_ID 3
diff --git a/arch/arm/mach-msm/include/mach/msm_dsps.h b/arch/arm/mach-msm/include/mach/msm_dsps.h
index cfb2024..32a4f15 100644
--- a/arch/arm/mach-msm/include/mach/msm_dsps.h
+++ b/arch/arm/mach-msm/include/mach/msm_dsps.h
@@ -75,6 +75,16 @@
  * @regs_num - number of regulators.
  * @dsps_pwr_ctl_en - to enable DSPS to do power control if set 1
  *  otherwise the apps will do power control
+ * @tcm_code_start - start of the TCM code region as physical address
+ * @tcm_code_size - size of the TCM code region in bytes
+ * @tcm_buf_start - start of the TCM buf region as physical address
+ * @tcm_buf_size - size of the TCM buf region in bytes
+ * @pipe_start - start of the PIPE region as physical address
+ * @pipe_size - size of the PIPE region in bytes
+ * @ddr_start - start of the DDR region as physical address
+ * @ddr_size - size of the DDR region in bytes
+ * @smem_start - start of the smem region as physical address
+ * @smem_size - size of the smem region in bytes
  * @signature - signature for validity check.
  */
 struct msm_dsps_platform_data {
@@ -87,6 +97,16 @@
 	int regs_num;
 	int dsps_pwr_ctl_en;
 	void (*init)(struct msm_dsps_platform_data *data);
+	int tcm_code_start;
+	int tcm_code_size;
+	int tcm_buf_start;
+	int tcm_buf_size;
+	int pipe_start;
+	int pipe_size;
+	int ddr_start;
+	int ddr_size;
+	int smem_start;
+	int smem_size;
 	u32 signature;
 };
 
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8064.h b/arch/arm/mach-msm/include/mach/msm_iomap-8064.h
index 96bc35e..10e2b74 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8064.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8064.h
@@ -106,4 +106,9 @@
 #define APQ8064_HDMI_PHYS		0x04A00000
 #define APQ8064_HDMI_SIZE		SZ_4K
 
+#ifdef CONFIG_DEBUG_APQ8064_UART
+#define MSM_DEBUG_UART_BASE		IOMEM(0xFA740000)
+#define MSM_DEBUG_UART_PHYS		0x16640000
+#endif
+
 #endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-copper.h b/arch/arm/mach-msm/include/mach/msm_iomap-copper.h
index b560276..441f82a 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-copper.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-copper.h
@@ -23,7 +23,7 @@
  *
  */
 
-#define COPPER_MSM_SHARED_RAM_PHYS	0x18D00000
+#define COPPER_MSM_SHARED_RAM_PHYS	0x0FA00000
 
 #define COPPER_QGIC_DIST_PHYS	0xF9000000
 #define COPPER_QGIC_DIST_SIZE	SZ_4K
diff --git a/arch/arm/mach-msm/include/mach/msm_smsm.h b/arch/arm/mach-msm/include/mach/msm_smsm.h
index 5b15340..0fc3a2b 100644
--- a/arch/arm/mach-msm/include/mach/msm_smsm.h
+++ b/arch/arm/mach-msm/include/mach/msm_smsm.h
@@ -58,6 +58,7 @@
 #define SMSM_TIMEWAIT          0x00000400
 #define SMSM_TIMEINIT          0x00000800
 #define SMSM_PWRC_EARLY_EXIT   0x00001000
+#define SMSM_LTE_COEX_AWAKE    0x00001000
 #define SMSM_WFPI              0x00002000
 #define SMSM_SLEEP             0x00004000
 #define SMSM_SLEEPEXIT         0x00008000
diff --git a/arch/arm/mach-msm/include/mach/ocmem_priv.h b/arch/arm/mach-msm/include/mach/ocmem_priv.h
index 32d46b4..daf32a5 100644
--- a/arch/arm/mach-msm/include/mach/ocmem_priv.h
+++ b/arch/arm/mach-msm/include/mach/ocmem_priv.h
@@ -74,4 +74,8 @@
 };
 
 struct ocmem_zone *get_zone(unsigned);
+unsigned long allocate_head(struct ocmem_zone *, unsigned long);
+int free_head(struct ocmem_zone *, unsigned long, unsigned long);
+unsigned long allocate_tail(struct ocmem_zone *, unsigned long);
+int free_tail(struct ocmem_zone *, unsigned long, unsigned long);
 #endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h b/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h
index bd303b2..f747a80 100644
--- a/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h
@@ -68,12 +68,23 @@
 #define USF_POINT_EPOS_FORMAT	0
 #define USF_RAW_FORMAT		1
 
+/* Indexes of event types, produced by the calculators */
+#define USF_TSC_EVENT_IND      0
+#define USF_TSC_PTR_EVENT_IND  1
+#define USF_MOUSE_EVENT_IND    2
+#define USF_KEYBOARD_EVENT_IND 3
+#define USF_MAX_EVENT_IND      4
+
 /* Types of events, produced by the calculators */
 #define USF_NO_EVENT 0
-#define USF_TSC_EVENT 1
-#define USF_MOUSE_EVENT 2
-#define USF_KEYBOARD_EVENT 4
-#define USF_ALL_EVENTS (USF_TSC_EVENT | USF_MOUSE_EVENT | USF_KEYBOARD_EVENT)
+#define USF_TSC_EVENT      (1 << USF_TSC_EVENT_IND)
+#define USF_TSC_PTR_EVENT  (1 << USF_TSC_PTR_EVENT_IND)
+#define USF_MOUSE_EVENT    (1 << USF_MOUSE_EVENT_IND)
+#define USF_KEYBOARD_EVENT (1 << USF_KEYBOARD_EVENT_IND)
+#define USF_ALL_EVENTS         (USF_TSC_EVENT |\
+				USF_TSC_PTR_EVENT |\
+				USF_MOUSE_EVENT |\
+				USF_KEYBOARD_EVENT)
 
 /* min, max array dimension */
 #define MIN_MAX_DIM 2
@@ -152,9 +163,6 @@
 	/* Info specific for RX*/
 };
 
-
-#define	USF_PIX_COORDINATE  0 /* unit is pixel */
-#define	USF_CMM_COORDINATE  1 /* unit is 0.01 mm */
 struct point_event_type {
 /* Pen coordinates (x, y, z) in units, defined by <coordinates_type>  */
 	int coordinates[COORDINATES_DIM];
@@ -162,8 +170,6 @@
 	int inclinations[TILTS_DIM];
 /* [0-1023] (10bits); 0 - pen up */
 	uint32_t pressure;
-/* 0 - mapped in the display pixel. 1 - raw in 0.01 mm (only for log); */
-	uint8_t coordinates_type;
 };
 
 /* Mouse buttons, supported by USF */
@@ -189,8 +195,8 @@
 	uint32_t seq_num;
 /* Event generation system time */
 	uint32_t timestamp;
-/* Destination input event type (e.g. touch screen, mouse, key) */
-	uint16_t event_type;
+/* Destination input event type index (e.g. touch screen, mouse, key) */
+	uint16_t event_type_ind;
 	union {
 		struct point_event_type point_event;
 		struct mouse_event_type mouse_event;
diff --git a/arch/arm/mach-msm/include/mach/rpm-8930.h b/arch/arm/mach-msm/include/mach/rpm-8930.h
index 0211b67..5ec3a74 100644
--- a/arch/arm/mach-msm/include/mach/rpm-8930.h
+++ b/arch/arm/mach-msm/include/mach/rpm-8930.h
@@ -100,6 +100,7 @@
 	MSM_RPM_8930_SEL_CXO_BUFFERS				= 81,
 	MSM_RPM_8930_SEL_USB_OTG_SWITCH				= 82,
 	MSM_RPM_8930_SEL_HDMI_SWITCH				= 83,
+	MSM_RPM_8930_SEL_DDR_DMM				= 84,
 	MSM_RPM_8930_SEL_VOLTAGE_CORNER				= 87,
 	MSM_RPM_8930_SEL_LAST = MSM_RPM_8930_SEL_VOLTAGE_CORNER,
 };
@@ -239,8 +240,10 @@
 	MSM_RPM_8930_ID_CXO_BUFFERS	= 164,
 	MSM_RPM_8930_ID_USB_OTG_SWITCH	= 165,
 	MSM_RPM_8930_ID_HDMI_SWITCH	= 166,
-	MSM_RPM_8930_ID_QDSS_CLK	= 167,
-	MSM_RPM_8930_ID_VOLTAGE_CORNER	= 168,
+	MSM_RPM_8930_ID_DDR_DMM_0		= 167,
+	MSM_RPM_8930_ID_DDR_DMM_1		= 168,
+	MSM_RPM_8930_ID_QDSS_CLK	= 168,
+	MSM_RPM_8930_ID_VOLTAGE_CORNER	= 169,
 	MSM_RPM_8930_ID_LAST = MSM_RPM_8930_ID_VOLTAGE_CORNER,
 };
 
@@ -350,8 +353,10 @@
 	MSM_RPM_8930_STATUS_ID_CXO_BUFFERS			= 105,
 	MSM_RPM_8930_STATUS_ID_USB_OTG_SWITCH			= 106,
 	MSM_RPM_8930_STATUS_ID_HDMI_SWITCH			= 107,
-	MSM_RPM_8930_STATUS_ID_QDSS_CLK				= 108,
-	MSM_RPM_8930_STATUS_ID_VOLTAGE_CORNER			= 109,
+	MSM_RPM_8930_STATUS_ID_DDR_DMM_0			= 108,
+	MSM_RPM_8930_STATUS_ID_DDR_DMM_1			= 109,
+	MSM_RPM_8930_STATUS_ID_QDSS_CLK				= 110,
+	MSM_RPM_8930_STATUS_ID_VOLTAGE_CORNER			= 111,
 	MSM_RPM_8930_STATUS_ID_LAST = MSM_RPM_8930_STATUS_ID_VOLTAGE_CORNER,
 };
 
diff --git a/arch/arm/mach-msm/include/mach/rpm-regulator-smd.h b/arch/arm/mach-msm/include/mach/rpm-regulator-smd.h
new file mode 100644
index 0000000..2eb59f5
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/rpm-regulator-smd.h
@@ -0,0 +1,55 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_INCLUDE_MACH_RPM_REGULATOR_SMD_H
+#define __ARCH_ARM_MACH_MSM_INCLUDE_MACH_RPM_REGULATOR_SMD_H
+
+#include <linux/device.h>
+
+struct rpm_regulator;
+
+#if defined(CONFIG_MSM_RPM_REGULATOR_SMD) || defined(CONFIG_MSM_RPM_REGULATOR)
+
+struct rpm_regulator *rpm_regulator_get(struct device *dev, const char *supply);
+
+void rpm_regulator_put(struct rpm_regulator *regulator);
+
+int rpm_regulator_enable(struct rpm_regulator *regulator);
+
+int rpm_regulator_disable(struct rpm_regulator *regulator);
+
+int rpm_regulator_set_voltage(struct rpm_regulator *regulator, int min_uV,
+			      int max_uV);
+
+int __init rpm_regulator_smd_driver_init(void);
+
+#else
+
+static inline struct rpm_regulator *rpm_regulator_get(struct device *dev,
+					const char *supply) { return NULL; }
+
+static inline void rpm_regulator_put(struct rpm_regulator *regulator) { }
+
+static inline int rpm_regulator_enable(struct rpm_regulator *regulator)
+			{ return 0; }
+
+static inline int rpm_regulator_disable(struct rpm_regulator *regulator)
+			{ return 0; }
+
+static inline int rpm_regulator_set_voltage(struct rpm_regulator *regulator,
+					int min_uV, int max_uV) { return 0; }
+
+static inline int __init rpm_regulator_smd_driver_init(void) { return 0; }
+
+#endif /* CONFIG_MSM_RPM_REGULATOR_SMD */
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/rpm-regulator.h b/arch/arm/mach-msm/include/mach/rpm-regulator.h
index f9fc487..a010257 100644
--- a/arch/arm/mach-msm/include/mach/rpm-regulator.h
+++ b/arch/arm/mach-msm/include/mach/rpm-regulator.h
@@ -81,6 +81,20 @@
 };
 
 /**
+ * enum rpm_vreg_voter - RPM regulator voter IDs for private APIs
+ */
+enum rpm_vreg_voter {
+	RPM_VREG_VOTER_REG_FRAMEWORK,	/* for internal use only */
+	RPM_VREG_VOTER1,		/* for use by the acpu-clock driver */
+	RPM_VREG_VOTER2,		/* for use by the acpu-clock driver */
+	RPM_VREG_VOTER3,		/* for use by other drivers */
+	RPM_VREG_VOTER4,		/* for use by the acpu-clock driver */
+	RPM_VREG_VOTER5,		/* for use by the acpu-clock driver */
+	RPM_VREG_VOTER6,		/* for use by the acpu-clock driver */
+	RPM_VREG_VOTER_COUNT,
+};
+
+/**
  * struct rpm_regulator_init_data - RPM regulator initialization data
  * @init_data:		regulator constraints
  * @id:			regulator id; from enum rpm_vreg_id
@@ -132,28 +146,27 @@
 };
 
 /**
- * struct rpm_regulator_platform_data - RPM regulator platform data
+ * struct rpm_regulator_consumer_mapping - mapping used by private consumers
  */
-struct rpm_regulator_platform_data {
-	struct rpm_regulator_init_data	*init_data;
-	int				num_regulators;
-	enum rpm_vreg_version		version;
-	int				vreg_id_vdd_mem;
-	int				vreg_id_vdd_dig;
+struct rpm_regulator_consumer_mapping {
+	const char		*dev_name;
+	const char		*supply;
+	int			vreg_id;
+	enum rpm_vreg_voter	voter;
+	int			sleep_also;
 };
 
 /**
- * enum rpm_vreg_voter - RPM regulator voter IDs for private APIs
+ * struct rpm_regulator_platform_data - RPM regulator platform data
  */
-enum rpm_vreg_voter {
-	RPM_VREG_VOTER_REG_FRAMEWORK,	/* for internal use only */
-	RPM_VREG_VOTER1,		/* for use by the acpu-clock driver */
-	RPM_VREG_VOTER2,		/* for use by the acpu-clock driver */
-	RPM_VREG_VOTER3,		/* for use by other drivers */
-	RPM_VREG_VOTER4,		/* for use by the acpu-clock driver */
-	RPM_VREG_VOTER5,		/* for use by the acpu-clock driver */
-	RPM_VREG_VOTER6,		/* for use by the acpu-clock driver */
-	RPM_VREG_VOTER_COUNT,
+struct rpm_regulator_platform_data {
+	struct rpm_regulator_init_data		*init_data;
+	int					num_regulators;
+	enum rpm_vreg_version			version;
+	int					vreg_id_vdd_mem;
+	int					vreg_id_vdd_dig;
+	struct rpm_regulator_consumer_mapping	*consumer_map;
+	int					consumer_map_len;
 };
 
 #ifdef CONFIG_MSM_RPM_REGULATOR
diff --git a/arch/arm/mach-msm/include/mach/rpm-smd.h b/arch/arm/mach-msm/include/mach/rpm-smd.h
new file mode 100644
index 0000000..ff58fed
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/rpm-smd.h
@@ -0,0 +1,254 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_RPM_SMD_H
+#define __ARCH_ARM_MACH_MSM_RPM_SMD_H
+
+/**
+ * enum msm_rpm_set - RPM enumerations for sleep/active set
+ * %MSM_RPM_CTX_SET_0: Set resource parameters for active mode.
+ * %MSM_RPM_CTX_SET_SLEEP: Set resource parameters for sleep.
+ */
+enum msm_rpm_set {
+	MSM_RPM_CTX_ACTIVE_SET,
+	MSM_RPM_CTX_SLEEP_SET,
+};
+
+struct msm_rpm_request;
+
+struct msm_rpm_kvp {
+	uint32_t key;
+	uint32_t length;
+	uint8_t *data;
+};
+#ifdef CONFIG_MSM_RPM_SMD
+/**
+ * msm_rpm_request() - Creates a parent element to identify the
+ * resource on the RPM, that stores the KVPs for different fields modified
+ * for a hardware resource
+ *
+ * @set: if the device is setting the active/sleep set parameter
+ * for the resource
+ * @rsc_type: unsigned 32 bit integer that identifies the type of the resource
+ * @rsc_id: unsigned 32 bit that uniquely identifies a resource within a type
+ * @num_elements: number of KVPs pairs associated with the resource
+ *
+ * returns pointer to a msm_rpm_request on success, NULL on error
+ */
+struct msm_rpm_request *msm_rpm_create_request(
+		enum msm_rpm_set set, uint32_t rsc_type,
+		uint32_t rsc_id, int num_elements);
+
+/**
+ * msm_rpm_request_noirq() - Creates a parent element to identify the
+ * resource on the RPM, that stores the KVPs for different fields modified
+ * for a hardware resource. This function is similar to msm_rpm_create_request
+ * except that it has to be called with interrupts masked.
+ *
+ * @set: if the device is setting the active/sleep set parameter
+ * for the resource
+ * @rsc_type: unsigned 32 bit integer that identifies the type of the resource
+ * @rsc_id: unsigned 32 bit that uniquely identifies a resource within a type
+ * @num_elements: number of KVPs pairs associated with the resource
+ *
+ * returns pointer to a msm_rpm_request on success, NULL on error
+ */
+struct msm_rpm_request *msm_rpm_create_request_noirq(
+		enum msm_rpm_set set, uint32_t rsc_type,
+		uint32_t rsc_id, int num_elements);
+
+/**
+ * msm_rpm_add_kvp_data() - Adds a Key value pair to a existing RPM resource.
+ *
+ * @handle: RPM resource handle to which the data should be appended
+ * @key:  unsigned integer identify the parameter modified
+ * @data: byte array that contains the value corresponding to key.
+ * @size:   size of data in bytes.
+ *
+ * returns 0 on success or errno
+ */
+int msm_rpm_add_kvp_data(struct msm_rpm_request *handle,
+		uint32_t key, const uint8_t *data, int size);
+
+/**
+ * msm_rpm_add_kvp_data_noirq() - Adds a Key value pair to a existing RPM
+ * resource. This function is similar to msm_rpm_add_kvp_data except that it
+ * has to be called with interrupts masked.
+ *
+ * @handle: RPM resource handle to which the data should be appended
+ * @key:  unsigned integer identify the parameter modified
+ * @data: byte array that contains the value corresponding to key.
+ * @size:   size of data in bytes.
+ *
+ * returns 0 on success or errno
+ */
+int msm_rpm_add_kvp_data_noirq(struct msm_rpm_request *handle,
+		uint32_t key, const uint8_t *data, int size);
+
+/** msm_rpm_free_request() - clean up the RPM request handle created with
+ * msm_rpm_create_request
+ *
+ * @handle: RPM resource handle to be cleared.
+ */
+
+void msm_rpm_free_request(struct msm_rpm_request *handle);
+
+/**
+ * msm_rpm_send_request() - Send the RPM messages using SMD. The function
+ * assigns a message id before sending the data out to the RPM. RPM hardware
+ * uses the message id to acknowledge the messages.
+ *
+ * @handle: pointer to the msm_rpm_request for the resource being modified.
+ *
+ * returns non-zero message id on success and zero on a failed transaction.
+ * The drivers use message id to wait for ACK from RPM.
+ */
+int msm_rpm_send_request(struct msm_rpm_request *handle);
+
+/**
+ * msm_rpm_send_request_noirq() - Send the RPM messages using SMD. The
+ * function assigns a message id before sending the data out to the RPM.
+ * RPM hardware uses the message id to acknowledge the messages. This function
+ * is similar to msm_rpm_send_request except that it has to be called with
+ * interrupts masked.
+ *
+ * @handle: pointer to the msm_rpm_request for the resource being modified.
+ *
+ * returns non-zero message id on success and zero on a failed transaction.
+ * The drivers use message id to wait for ACK from RPM.
+ */
+int msm_rpm_send_request_noirq(struct msm_rpm_request *handle);
+
+/**
+ * msm_rpm_wait_for_ack() - A blocking call that waits for acknowledgment of
+ * a message from RPM.
+ *
+ * @msg_id: the return from msm_rpm_send_requests
+ *
+ * returns 0 on success or errno
+ */
+int msm_rpm_wait_for_ack(uint32_t msg_id);
+
+/**
+ * msm_rpm_wait_for_ack_noirq() - A blocking call that waits for acknowledgment
+ * of a message from RPM. This function is similar to msm_rpm_wait_for_ack
+ * except that it has to be called with interrupts masked.
+ *
+ * @msg_id: the return from msm_rpm_send_request
+ *
+ * returns 0 on success or errno
+ */
+int msm_rpm_wait_for_ack_noirq(uint32_t msg_id);
+
+/**
+ * msm_rpm_send_message() -Wrapper function for clients to send data given an
+ * array of key value pairs.
+ *
+ * @set: if the device is setting the active/sleep set parameter
+ * for the resource
+ * @rsc_type: unsigned 32 bit integer that identifies the type of the resource
+ * @rsc_id: unsigned 32 bit that uniquely identifies a resource within a type
+ * @kvp: array of KVP data.
+ * @nelem: number of KVPs pairs associated with the message.
+ *
+ * returns  0 on success and errno on failure.
+ */
+int msm_rpm_send_message(enum msm_rpm_set set, uint32_t rsc_type,
+		uint32_t rsc_id, struct msm_rpm_kvp *kvp, int nelems);
+
+/**
+ * msm_rpm_send_message_noirq() -Wrapper function for clients to send data
+ * given an array of key value pairs. This function is similar to the
+ * msm_rpm_send_message() except that it has to be called with interrupts
+ * disabled. Clients should choose the irq version when possible for system
+ * performance.
+ *
+ * @set: if the device is setting the active/sleep set parameter
+ * for the resource
+ * @rsc_type: unsigned 32 bit integer that identifies the type of the resource
+ * @rsc_id: unsigned 32 bit that uniquely identifies a resource within a type
+ * @kvp: array of KVP data.
+ * @nelem: number of KVPs pairs associated with the message.
+ *
+ * returns  0 on success and errno on failure.
+ */
+int msm_rpm_send_message_noirq(enum msm_rpm_set set, uint32_t rsc_type,
+		uint32_t rsc_id, struct msm_rpm_kvp *kvp, int nelems);
+
+/**
+ * msm_rpm_driver_init() - Initialization function that registers for a
+ * rpm platform driver.
+ *
+ * returns 0 on success.
+ */
+int __init msm_rpm_driver_init(void);
+
+#else
+
+static inline struct msm_rpm_request *msm_rpm_create_request(
+		enum msm_rpm_set set, uint32_t rsc_type,
+		uint32_t rsc_id, int num_elements)
+{
+	return NULL;
+}
+
+static inline struct msm_rpm_request *msm_rpm_create_request_noirq(
+		enum msm_rpm_set set, uint32_t rsc_type,
+		uint32_t rsc_id, int num_elements)
+{
+	return NULL;
+
+}
+static inline uint32_t msm_rpm_add_kvp_data(struct msm_rpm_request *handle,
+		uint32_t key, const uint8_t *data, int count)
+{
+	return 0;
+}
+static inline uint32_t msm_rpm_add_kvp_data_noirq(
+		struct msm_rpm_request *handle, uint32_t key,
+		const uint8_t *data, int count)
+{
+	return 0;
+}
+
+static inline void msm_rpm_free_request(struct msm_rpm_request *handle)
+{
+	return ;
+}
+
+static inline int msm_rpm_send_request(struct msm_rpm_request *handle)
+{
+	return 0;
+}
+
+static inline int msm_rpm_send_request_noirq(struct msm_rpm_request *handle)
+{
+	return 0;
+
+}
+static inline int msm_rpm_wait_for_ack(uint32_t msg_id)
+{
+	return 0;
+
+}
+static inline int msm_rpm_wait_for_ack_noirq(uint32_t msg_id)
+{
+	return 0;
+}
+
+static inline int __init msm_rpm_driver_init(void)
+{
+	return 0;
+}
+#endif
+#endif /*__ARCH_ARM_MACH_MSM_RPM_SMD_H*/
diff --git a/arch/arm/mach-msm/include/mach/usb_gadget_xport.h b/arch/arm/mach-msm/include/mach/usb_gadget_xport.h
index d8a3e60..be11989 100644
--- a/arch/arm/mach-msm/include/mach/usb_gadget_xport.h
+++ b/arch/arm/mach-msm/include/mach/usb_gadget_xport.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -22,6 +22,7 @@
 	USB_GADGET_XPORT_BAM,
 	USB_GADGET_XPORT_BAM2BAM,
 	USB_GADGET_XPORT_HSIC,
+	USB_GADGET_XPORT_HSUART,
 	USB_GADGET_XPORT_NONE,
 };
 
@@ -42,6 +43,8 @@
 		return "BAM2BAM";
 	case USB_GADGET_XPORT_HSIC:
 		return "HSIC";
+	case USB_GADGET_XPORT_HSUART:
+		return "HSUART";
 	case USB_GADGET_XPORT_NONE:
 		return "NONE";
 	default:
@@ -63,6 +66,8 @@
 		return USB_GADGET_XPORT_BAM2BAM;
 	if (!strncasecmp("HSIC", name, XPORT_STR_LEN))
 		return USB_GADGET_XPORT_HSIC;
+	if (!strncasecmp("HSUART", name, XPORT_STR_LEN))
+		return USB_GADGET_XPORT_HSUART;
 	if (!strncasecmp("", name, XPORT_STR_LEN))
 		return USB_GADGET_XPORT_NONE;
 
@@ -79,6 +84,11 @@
 #define NUM_PORTS (NUM_RMNET_HSIC_PORTS \
 	+ NUM_DUN_HSIC_PORTS)
 
+#define NUM_RMNET_HSUART_PORTS 1
+#define NUM_DUN_HSUART_PORTS 1
+#define NUM_HSUART_PORTS (NUM_RMNET_HSUART_PORTS \
+	+ NUM_DUN_HSUART_PORTS)
+
 int ghsic_ctrl_connect(void *, int);
 void ghsic_ctrl_disconnect(void *, int);
 int ghsic_ctrl_setup(unsigned int, enum gadget_type);
@@ -86,4 +96,10 @@
 void ghsic_data_disconnect(void *, int);
 int ghsic_data_setup(unsigned int, enum gadget_type);
 
+int ghsuart_ctrl_connect(void *, int);
+void ghsuart_ctrl_disconnect(void *, int);
+int ghsuart_ctrl_setup(unsigned int, enum gadget_type);
+int ghsuart_data_connect(void *, int);
+void ghsuart_data_disconnect(void *, int);
+int ghsuart_data_setup(unsigned int, enum gadget_type);
 #endif
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index 59d3a96..2a0d34a 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -281,6 +281,9 @@
 	},
 	MSM_CHIP_DEVICE(QFPROM, APQ8064),
 	MSM_CHIP_DEVICE(SIC_NON_SECURE, APQ8064),
+#ifdef CONFIG_DEBUG_APQ8064_UART
+	MSM_DEVICE(DEBUG_UART),
+#endif
 };
 
 void __init msm_map_apq8064_io(void)
diff --git a/arch/arm/mach-msm/iommu-v2.c b/arch/arm/mach-msm/iommu-v2.c
new file mode 100644
index 0000000..41f5043
--- /dev/null
+++ b/arch/arm/mach-msm/iommu-v2.c
@@ -0,0 +1,570 @@
+/* Copyright (c) 2012 Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/iommu.h>
+#include <linux/clk.h>
+#include <linux/scatterlist.h>
+
+#include <asm/sizes.h>
+
+#include <mach/iommu_hw-v2.h>
+#include <mach/iommu.h>
+
+#include "iommu_pagetable.h"
+
+static DEFINE_MUTEX(msm_iommu_lock);
+
+struct msm_priv {
+	struct iommu_pt pt;
+	struct list_head list_attached;
+};
+
+static int __enable_clocks(struct msm_iommu_drvdata *drvdata)
+{
+	int ret;
+
+	ret = clk_prepare_enable(drvdata->pclk);
+	if (ret)
+		goto fail;
+
+	if (drvdata->clk) {
+		ret = clk_prepare_enable(drvdata->clk);
+		if (ret)
+			clk_disable_unprepare(drvdata->pclk);
+	}
+fail:
+	return ret;
+}
+
+static void __disable_clocks(struct msm_iommu_drvdata *drvdata)
+{
+	if (drvdata->clk)
+		clk_disable_unprepare(drvdata->clk);
+	clk_disable_unprepare(drvdata->pclk);
+}
+
+static int __flush_iotlb_va(struct iommu_domain *domain, unsigned int va)
+{
+	struct msm_priv *priv = domain->priv;
+	struct msm_iommu_drvdata *iommu_drvdata;
+	struct msm_iommu_ctx_drvdata *ctx_drvdata;
+	int asid;
+
+	list_for_each_entry(ctx_drvdata, &priv->list_attached, attached_elm) {
+		BUG_ON(!ctx_drvdata->pdev || !ctx_drvdata->pdev->dev.parent);
+
+		iommu_drvdata = dev_get_drvdata(ctx_drvdata->pdev->dev.parent);
+		BUG_ON(!iommu_drvdata);
+
+		asid = GET_CB_CONTEXTIDR_ASID(iommu_drvdata->base,
+					   ctx_drvdata->num);
+
+		SET_TLBIVA(iommu_drvdata->base, ctx_drvdata->num,
+			   asid | (va & CB_TLBIVA_VA));
+		mb();
+	}
+
+	return 0;
+}
+
+static int __flush_iotlb(struct iommu_domain *domain)
+{
+	struct msm_priv *priv = domain->priv;
+	struct msm_iommu_drvdata *iommu_drvdata;
+	struct msm_iommu_ctx_drvdata *ctx_drvdata;
+	int asid;
+
+	list_for_each_entry(ctx_drvdata, &priv->list_attached, attached_elm) {
+		BUG_ON(!ctx_drvdata->pdev || !ctx_drvdata->pdev->dev.parent);
+
+		iommu_drvdata = dev_get_drvdata(ctx_drvdata->pdev->dev.parent);
+		BUG_ON(!iommu_drvdata);
+
+		asid = GET_CB_CONTEXTIDR_ASID(iommu_drvdata->base,
+					   ctx_drvdata->num);
+
+		SET_TLBIASID(iommu_drvdata->base, ctx_drvdata->num, asid);
+		mb();
+	}
+
+	return 0;
+}
+
+static void __reset_context(void __iomem *base, int ctx)
+{
+	SET_ACTLR(base, ctx, 0);
+	SET_FAR(base, ctx, 0);
+	SET_FSRRESTORE(base, ctx, 0);
+	SET_NMRR(base, ctx, 0);
+	SET_PAR(base, ctx, 0);
+	SET_PRRR(base, ctx, 0);
+	SET_SCTLR(base, ctx, 0);
+	SET_TLBIALL(base, ctx, 0);
+	SET_TTBCR(base, ctx, 0);
+	SET_TTBR0(base, ctx, 0);
+	SET_TTBR1(base, ctx, 0);
+	mb();
+}
+
+static void __program_context(void __iomem *base, int ctx, int ncb,
+				phys_addr_t pgtable, int redirect)
+{
+	unsigned int prrr, nmrr;
+	unsigned int pn;
+	int i, j, found;
+
+	__reset_context(base, ctx);
+
+	pn = pgtable >> CB_TTBR0_ADDR_SHIFT;
+	SET_TTBCR(base, ctx, 0);
+	SET_CB_TTBR0_ADDR(base, ctx, pn);
+
+	/* Enable context fault interrupt */
+	SET_CB_SCTLR_CFIE(base, ctx, 1);
+
+	/* Redirect all cacheable requests to L2 slave port. */
+	SET_CB_ACTLR_BPRCISH(base, ctx, 1);
+	SET_CB_ACTLR_BPRCOSH(base, ctx, 1);
+	SET_CB_ACTLR_BPRCNSH(base, ctx, 1);
+
+	/* Turn on TEX Remap */
+	SET_CB_SCTLR_TRE(base, ctx, 1);
+
+	/* Enable private ASID namespace */
+	SET_CB_SCTLR_ASIDPNE(base, ctx, 1);
+
+	/* Set TEX remap attributes */
+	RCP15_PRRR(prrr);
+	RCP15_NMRR(nmrr);
+	SET_PRRR(base, ctx, prrr);
+	SET_NMRR(base, ctx, nmrr);
+
+	/* Configure page tables as inner-cacheable and shareable to reduce
+	 * the TLB miss penalty.
+	 */
+	if (redirect) {
+		SET_CB_TTBR0_S(base, ctx, 1);
+		SET_CB_TTBR0_NOS(base, ctx, 1);
+		SET_CB_TTBR0_IRGN1(base, ctx, 0); /* WB, WA */
+		SET_CB_TTBR0_IRGN0(base, ctx, 1);
+		SET_CB_TTBR0_RGN(base, ctx, 1);   /* WB, WA */
+	}
+
+       /* Find if this page table is used elsewhere, and re-use ASID */
+	found = 0;
+	for (i = 0; i < ncb; i++)
+		if ((GET_CB_TTBR0_ADDR(base, i) == pn) && (i != ctx)) {
+			SET_CB_CONTEXTIDR_ASID(base, ctx, \
+					GET_CB_CONTEXTIDR_ASID(base, i));
+			found = 1;
+			break;
+		}
+
+	/* If page table is new, find an unused ASID */
+	if (!found) {
+		for (i = 0; i < ncb; i++) {
+			found = 0;
+			for (j = 0; j < ncb; j++) {
+				if (GET_CB_CONTEXTIDR_ASID(base, j) == i &&
+				    j != ctx)
+					found = 1;
+			}
+
+			if (!found) {
+				SET_CB_CONTEXTIDR_ASID(base, ctx, i);
+				break;
+			}
+		}
+		BUG_ON(found);
+	}
+
+	/* Enable the MMU */
+	SET_CB_SCTLR_M(base, ctx, 1);
+	mb();
+}
+
+static int msm_iommu_domain_init(struct iommu_domain *domain, int flags)
+{
+	struct msm_priv *priv;
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		goto fail_nomem;
+
+#ifdef CONFIG_IOMMU_PGTABLES_L2
+	priv->pt.redirect = flags & MSM_IOMMU_DOMAIN_PT_CACHEABLE;
+#endif
+
+	INIT_LIST_HEAD(&priv->list_attached);
+	if (msm_iommu_pagetable_alloc(&priv->pt))
+		goto fail_nomem;
+
+	domain->priv = priv;
+	return 0;
+
+fail_nomem:
+	kfree(priv);
+	return -ENOMEM;
+}
+
+static void msm_iommu_domain_destroy(struct iommu_domain *domain)
+{
+	struct msm_priv *priv;
+
+	mutex_lock(&msm_iommu_lock);
+	priv = domain->priv;
+	domain->priv = NULL;
+
+	if (priv)
+		msm_iommu_pagetable_free(&priv->pt);
+
+	kfree(priv);
+	mutex_unlock(&msm_iommu_lock);
+}
+
+static int msm_iommu_attach_dev(struct iommu_domain *domain, struct device *dev)
+{
+	struct msm_priv *priv;
+	struct msm_iommu_drvdata *iommu_drvdata;
+	struct msm_iommu_ctx_drvdata *ctx_drvdata;
+	struct msm_iommu_ctx_drvdata *tmp_drvdata;
+	int ret = 0;
+
+	mutex_lock(&msm_iommu_lock);
+
+	priv = domain->priv;
+	if (!priv || !dev) {
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	iommu_drvdata = dev_get_drvdata(dev->parent);
+	ctx_drvdata = dev_get_drvdata(dev);
+	if (!iommu_drvdata || !ctx_drvdata) {
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	if (!list_empty(&ctx_drvdata->attached_elm)) {
+		ret = -EBUSY;
+		goto fail;
+	}
+
+	list_for_each_entry(tmp_drvdata, &priv->list_attached, attached_elm)
+		if (tmp_drvdata == ctx_drvdata) {
+			ret = -EBUSY;
+			goto fail;
+		}
+
+	ret = __enable_clocks(iommu_drvdata);
+	if (ret)
+		goto fail;
+
+	__program_context(iommu_drvdata->base, ctx_drvdata->num,
+		iommu_drvdata->ncb, __pa(priv->pt.fl_table),
+		priv->pt.redirect);
+
+	__disable_clocks(iommu_drvdata);
+	list_add(&(ctx_drvdata->attached_elm), &priv->list_attached);
+	ctx_drvdata->attached_domain = domain;
+
+fail:
+	mutex_unlock(&msm_iommu_lock);
+	return ret;
+}
+
+static void msm_iommu_detach_dev(struct iommu_domain *domain,
+				 struct device *dev)
+{
+	struct msm_priv *priv;
+	struct msm_iommu_drvdata *iommu_drvdata;
+	struct msm_iommu_ctx_drvdata *ctx_drvdata;
+	int ret;
+
+	mutex_lock(&msm_iommu_lock);
+	priv = domain->priv;
+	if (!priv || !dev)
+		goto fail;
+
+	iommu_drvdata = dev_get_drvdata(dev->parent);
+	ctx_drvdata = dev_get_drvdata(dev);
+	if (!iommu_drvdata || !ctx_drvdata || !ctx_drvdata->attached_domain)
+		goto fail;
+
+	ret = __enable_clocks(iommu_drvdata);
+	if (ret)
+		goto fail;
+
+	SET_TLBIASID(iommu_drvdata->base, ctx_drvdata->num,
+		GET_CB_CONTEXTIDR_ASID(iommu_drvdata->base, ctx_drvdata->num));
+
+	__reset_context(iommu_drvdata->base, ctx_drvdata->num);
+	__disable_clocks(iommu_drvdata);
+	list_del_init(&ctx_drvdata->attached_elm);
+	ctx_drvdata->attached_domain = NULL;
+
+fail:
+	mutex_unlock(&msm_iommu_lock);
+}
+
+static int msm_iommu_map(struct iommu_domain *domain, unsigned long va,
+			 phys_addr_t pa, int order, int prot)
+{
+	struct msm_priv *priv;
+	int ret = 0;
+
+	mutex_lock(&msm_iommu_lock);
+
+	priv = domain->priv;
+	if (!priv) {
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	ret = msm_iommu_pagetable_map(&priv->pt, va, pa, order, prot);
+	if (ret)
+		goto fail;
+
+	ret = __flush_iotlb_va(domain, va);
+fail:
+	mutex_unlock(&msm_iommu_lock);
+	return ret;
+}
+
+static int msm_iommu_unmap(struct iommu_domain *domain, unsigned long va,
+			    int order)
+{
+	struct msm_priv *priv;
+	int ret = 0;
+
+	mutex_lock(&msm_iommu_lock);
+
+	priv = domain->priv;
+	if (!priv) {
+		ret = -ENODEV;
+		goto fail;
+	}
+
+	ret = msm_iommu_pagetable_unmap(&priv->pt, va, order);
+	if (ret < 0)
+		goto fail;
+
+	ret = __flush_iotlb_va(domain, va);
+fail:
+	mutex_unlock(&msm_iommu_lock);
+	return ret;
+}
+
+static int msm_iommu_map_range(struct iommu_domain *domain, unsigned int va,
+			       struct scatterlist *sg, unsigned int len,
+			       int prot)
+{
+	int ret;
+	struct msm_priv *priv;
+
+	mutex_lock(&msm_iommu_lock);
+
+	priv = domain->priv;
+	if (!priv) {
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	ret = msm_iommu_pagetable_map_range(&priv->pt, va, sg, len, prot);
+	if (ret)
+		goto fail;
+
+	__flush_iotlb(domain);
+fail:
+	mutex_unlock(&msm_iommu_lock);
+	return ret;
+}
+
+
+static int msm_iommu_unmap_range(struct iommu_domain *domain, unsigned int va,
+				 unsigned int len)
+{
+	struct msm_priv *priv;
+
+	mutex_lock(&msm_iommu_lock);
+
+	priv = domain->priv;
+	msm_iommu_pagetable_unmap_range(&priv->pt, va, len);
+
+	__flush_iotlb(domain);
+	mutex_unlock(&msm_iommu_lock);
+	return 0;
+}
+
+static phys_addr_t msm_iommu_iova_to_phys(struct iommu_domain *domain,
+					  unsigned long va)
+{
+	struct msm_priv *priv;
+	struct msm_iommu_drvdata *iommu_drvdata;
+	struct msm_iommu_ctx_drvdata *ctx_drvdata;
+	unsigned int par;
+	void __iomem *base;
+	phys_addr_t pa = 0;
+	int ctx;
+
+	mutex_lock(&msm_iommu_lock);
+
+	priv = domain->priv;
+	if (list_empty(&priv->list_attached))
+		goto fail;
+
+	ctx_drvdata = list_entry(priv->list_attached.next,
+				 struct msm_iommu_ctx_drvdata, attached_elm);
+	iommu_drvdata = dev_get_drvdata(ctx_drvdata->pdev->dev.parent);
+
+	base = iommu_drvdata->base;
+	ctx = ctx_drvdata->num;
+
+	SET_ATS1PR(base, ctx, va & CB_ATS1PR_ADDR);
+	mb();
+	while (GET_CB_ATSR_ACTIVE(base, ctx))
+		cpu_relax();
+
+	par = GET_PAR(base, ctx);
+	if (par & CB_PAR_F) {
+		pa = 0;
+	} else {
+		/* We are dealing with a supersection */
+		if (par & CB_PAR_SS)
+			pa = (par & 0xFF000000) | (va & 0x00FFFFFF);
+		else /* Upper 20 bits from PAR, lower 12 from VA */
+			pa = (par & 0xFFFFF000) | (va & 0x00000FFF);
+	}
+
+fail:
+	mutex_unlock(&msm_iommu_lock);
+	return pa;
+}
+
+static int msm_iommu_domain_has_cap(struct iommu_domain *domain,
+				    unsigned long cap)
+{
+	return 0;
+}
+
+static void print_ctx_regs(void __iomem *base, int ctx, unsigned int fsr)
+{
+	pr_err("FAR    = %08x    PAR    = %08x\n",
+		 GET_FAR(base, ctx), GET_PAR(base, ctx));
+	pr_err("FSR    = %08x [%s%s%s%s%s%s%s%s%s]\n", fsr,
+			(fsr & 0x02) ? "TF " : "",
+			(fsr & 0x04) ? "AFF " : "",
+			(fsr & 0x08) ? "PF " : "",
+			(fsr & 0x10) ? "EF " : "",
+			(fsr & 0x20) ? "TLBMCF " : "",
+			(fsr & 0x40) ? "TLBLKF " : "",
+			(fsr & 0x80) ? "MHF " : "",
+			(fsr & 0x40000000) ? "SS " : "",
+			(fsr & 0x80000000) ? "MULTI " : "");
+
+	pr_err("FSYNR0 = %08x    FSYNR1 = %08x\n",
+		 GET_FSYNR0(base, ctx), GET_FSYNR1(base, ctx));
+	pr_err("TTBR0  = %08x    TTBR1  = %08x\n",
+		 GET_TTBR0(base, ctx), GET_TTBR1(base, ctx));
+	pr_err("SCTLR  = %08x    ACTLR  = %08x\n",
+		 GET_SCTLR(base, ctx), GET_ACTLR(base, ctx));
+	pr_err("PRRR   = %08x    NMRR   = %08x\n",
+		 GET_PRRR(base, ctx), GET_NMRR(base, ctx));
+}
+
+irqreturn_t msm_iommu_fault_handler_v2(int irq, void *dev_id)
+{
+	struct platform_device *pdev = dev_id;
+	struct msm_iommu_drvdata *drvdata;
+	struct msm_iommu_ctx_drvdata *ctx_drvdata;
+	unsigned int fsr;
+	int ret = IRQ_NONE;
+
+	mutex_lock(&msm_iommu_lock);
+
+	BUG_ON(!pdev);
+
+	drvdata = dev_get_drvdata(pdev->dev.parent);
+	BUG_ON(!drvdata);
+
+	ctx_drvdata = dev_get_drvdata(&pdev->dev);
+	BUG_ON(!ctx_drvdata);
+
+	fsr = GET_FSR(drvdata->base, ctx_drvdata->num);
+	if (fsr) {
+		if (!ctx_drvdata->attached_domain) {
+			pr_err("Bad domain in interrupt handler\n");
+			ret = -ENOSYS;
+		} else
+			ret = report_iommu_fault(ctx_drvdata->attached_domain,
+				&ctx_drvdata->pdev->dev,
+				GET_FAR(drvdata->base, ctx_drvdata->num), 0);
+
+		if (ret == -ENOSYS) {
+			pr_err("Unexpected IOMMU page fault!\n");
+			pr_err("name = %s\n", drvdata->name);
+			pr_err("context = %s (%d)\n", ctx_drvdata->name,
+							ctx_drvdata->num);
+			pr_err("Interesting registers:\n");
+			print_ctx_regs(drvdata->base, ctx_drvdata->num, fsr);
+		}
+
+		SET_FSR(drvdata->base, ctx_drvdata->num, fsr);
+		ret = IRQ_HANDLED;
+	} else
+		ret = IRQ_NONE;
+
+	mutex_unlock(&msm_iommu_lock);
+	return ret;
+}
+
+static phys_addr_t msm_iommu_get_pt_base_addr(struct iommu_domain *domain)
+{
+	struct msm_priv *priv = domain->priv;
+	return __pa(priv->pt.fl_table);
+}
+
+static struct iommu_ops msm_iommu_ops = {
+	.domain_init = msm_iommu_domain_init,
+	.domain_destroy = msm_iommu_domain_destroy,
+	.attach_dev = msm_iommu_attach_dev,
+	.detach_dev = msm_iommu_detach_dev,
+	.map = msm_iommu_map,
+	.unmap = msm_iommu_unmap,
+	.map_range = msm_iommu_map_range,
+	.unmap_range = msm_iommu_unmap_range,
+	.iova_to_phys = msm_iommu_iova_to_phys,
+	.domain_has_cap = msm_iommu_domain_has_cap,
+	.get_pt_base_addr = msm_iommu_get_pt_base_addr
+};
+
+static int __init msm_iommu_init(void)
+{
+	msm_iommu_pagetable_init();
+	register_iommu(&msm_iommu_ops);
+	return 0;
+}
+
+subsys_initcall(msm_iommu_init);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MSM SMMU v2 Driver");
diff --git a/arch/arm/mach-msm/iommu.c b/arch/arm/mach-msm/iommu.c
index 49a3e6f..89eef57 100644
--- a/arch/arm/mach-msm/iommu.c
+++ b/arch/arm/mach-msm/iommu.c
@@ -1083,7 +1083,7 @@
 
 static int __init msm_iommu_init(void)
 {
-	if (!msm_soc_version_supports_iommu())
+	if (!msm_soc_version_supports_iommu_v1())
 		return -ENODEV;
 
 	setup_iommu_tex_classes();
diff --git a/arch/arm/mach-msm/iommu_dev-v2.c b/arch/arm/mach-msm/iommu_dev-v2.c
new file mode 100644
index 0000000..e690ada
--- /dev/null
+++ b/arch/arm/mach-msm/iommu_dev-v2.c
@@ -0,0 +1,376 @@
+/* Copyright (c) 2012 Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/iommu.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/atomic.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+
+#include <mach/iommu_hw-v2.h>
+#include <mach/iommu.h>
+
+static void msm_iommu_reset(void __iomem *base)
+{
+	int i;
+
+	SET_ACR(base, 0);
+	SET_NSACR(base, 0);
+	SET_CR2(base, 0);
+	SET_NSCR2(base, 0);
+	SET_GFAR(base, 0);
+	SET_GFSRRESTORE(base, 0);
+	SET_TLBIALLNSNH(base, 0);
+	SET_PMCR(base, 0);
+	SET_SCR1(base, 0);
+	SET_SSDR_N(base, 0, 0);
+
+	for (i = 0; i < MAX_NUM_SMR; i++)
+		SET_SMR_VALID(base, i, 0);
+
+	mb();
+}
+
+static int msm_iommu_parse_dt(struct platform_device *pdev,
+				struct msm_iommu_drvdata *drvdata)
+{
+	struct device_node *child;
+	int ret;
+
+	ret = device_move(&pdev->dev, &msm_iommu_root_dev->dev, DPM_ORDER_NONE);
+	if (ret)
+		return ret;
+
+	for_each_child_of_node(pdev->dev.of_node, child) {
+		drvdata->ncb++;
+		if (!of_platform_device_create(child, NULL, &pdev->dev))
+			pr_err("Failed to create %s device\n", child->name);
+	}
+
+	drvdata->name = dev_name(&pdev->dev);
+	return 0;
+}
+
+static atomic_t msm_iommu_next_id = ATOMIC_INIT(-1);
+
+static int __devinit msm_iommu_probe(struct platform_device *pdev)
+{
+	struct msm_iommu_drvdata *drvdata;
+	struct resource *r;
+	int ret;
+
+	if (msm_iommu_root_dev == pdev)
+		return 0;
+
+	if (pdev->id == -1)
+		pdev->id = atomic_inc_return(&msm_iommu_next_id) - 1;
+
+	drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
+	if (!drvdata)
+		return -ENOMEM;
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!r)
+		return -EINVAL;
+
+	drvdata->base = devm_ioremap(&pdev->dev, r->start, resource_size(r));
+	if (!drvdata->base)
+		return -ENOMEM;
+
+	drvdata->pclk = clk_get(&pdev->dev, "iface_clk");
+	if (IS_ERR(drvdata->pclk))
+		return PTR_ERR(drvdata->pclk);
+
+	ret = clk_prepare_enable(drvdata->pclk);
+	if (ret)
+		goto fail_enable;
+
+	drvdata->clk = clk_get(&pdev->dev, "core_clk");
+	if (!IS_ERR(drvdata->clk)) {
+		if (clk_get_rate(drvdata->clk) == 0) {
+			ret = clk_round_rate(drvdata->clk, 1);
+			clk_set_rate(drvdata->clk, ret);
+		}
+
+		ret = clk_prepare_enable(drvdata->clk);
+		if (ret) {
+			clk_put(drvdata->clk);
+			goto fail_pclk;
+		}
+	} else
+		drvdata->clk = NULL;
+
+	msm_iommu_reset(drvdata->base);
+
+	SET_CR0_SMCFCFG(drvdata->base, 1);
+	SET_CR0_USFCFG(drvdata->base, 1);
+	SET_CR0_STALLD(drvdata->base, 1);
+	SET_CR0_GCFGFIE(drvdata->base, 1);
+	SET_CR0_GCFGFRE(drvdata->base, 1);
+	SET_CR0_GFIE(drvdata->base, 1);
+	SET_CR0_GFRE(drvdata->base, 1);
+	SET_CR0_CLIENTPD(drvdata->base, 0);
+
+	ret = msm_iommu_parse_dt(pdev, drvdata);
+	if (ret)
+		goto fail_clk;
+
+	pr_info("device %s mapped at %p, with %d ctx banks\n",
+		drvdata->name, drvdata->base, drvdata->ncb);
+
+	platform_set_drvdata(pdev, drvdata);
+
+	if (drvdata->clk)
+		clk_disable_unprepare(drvdata->clk);
+
+	clk_disable_unprepare(drvdata->pclk);
+
+	return 0;
+
+fail_clk:
+	if (drvdata->clk) {
+		clk_disable_unprepare(drvdata->clk);
+		clk_put(drvdata->clk);
+	}
+fail_pclk:
+	clk_disable_unprepare(drvdata->pclk);
+fail_enable:
+	clk_put(drvdata->pclk);
+	return ret;
+}
+
+static int __devexit msm_iommu_remove(struct platform_device *pdev)
+{
+	struct msm_iommu_drvdata *drv = NULL;
+
+	drv = platform_get_drvdata(pdev);
+	if (drv) {
+		if (drv->clk)
+			clk_put(drv->clk);
+		clk_put(drv->pclk);
+		platform_set_drvdata(pdev, NULL);
+	}
+	return 0;
+}
+
+static int msm_iommu_ctx_parse_dt(struct platform_device *pdev,
+				struct msm_iommu_drvdata *drvdata,
+				struct msm_iommu_ctx_drvdata *ctx_drvdata)
+{
+	struct resource *r, rp;
+	u32 sids[MAX_NUM_SMR];
+	int num = 0;
+	int irq, i, ret, len = 0;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq > 0) {
+		ret = request_threaded_irq(irq, NULL,
+				msm_iommu_fault_handler_v2,
+				IRQF_ONESHOT | IRQF_SHARED,
+				"msm_iommu_nonsecure_irq", pdev);
+		if (ret) {
+			pr_err("Request IRQ %d failed with ret=%d\n", irq, ret);
+			return ret;
+		}
+	}
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!r)
+		return -EINVAL;
+
+	ret = of_address_to_resource(pdev->dev.parent->of_node, 0, &rp);
+	if (ret)
+		return -EINVAL;
+
+	/* Calculate the context bank number using the base addresses. The
+	 * first 8 pages belong to the global address space which is followed
+	 * by the context banks, hence subtract by 8 to get the context bank
+	 * number.
+	 */
+	ctx_drvdata->num = ((r->start - rp.start) >> CTX_SHIFT) - 8;
+
+	if (of_property_read_string(pdev->dev.of_node, "qcom,iommu-ctx-name",
+					&ctx_drvdata->name))
+		ctx_drvdata->name = dev_name(&pdev->dev);
+
+	of_get_property(pdev->dev.of_node, "qcom,iommu-ctx-sids", &len);
+	BUG_ON(len >= sizeof(sids));
+	if (of_property_read_u32_array(pdev->dev.of_node, "qcom,iommu-ctx-sids",
+					sids, len / sizeof(*sids)))
+		return -EINVAL;
+
+	/* Program the M2V tables for this context */
+	for (i = 0; i < len / sizeof(*sids); i++) {
+		for (; num < MAX_NUM_SMR; num++)
+			if (GET_SMR_VALID(drvdata->base, num) == 0)
+				break;
+		BUG_ON(num >= MAX_NUM_SMR);
+
+		SET_SMR_VALID(drvdata->base, num, 1);
+		SET_SMR_MASK(drvdata->base, num, 0);
+		SET_SMR_ID(drvdata->base, num, sids[i]);
+
+		/* Set VMID = 0 */
+		SET_S2CR_N(drvdata->base, num, 0);
+		SET_S2CR_CBNDX(drvdata->base, num, ctx_drvdata->num);
+		/* Set security bit override to be Non-secure */
+		SET_S2CR_NSCFG(drvdata->base, sids[i], 3);
+
+		SET_CBAR_N(drvdata->base, ctx_drvdata->num, 0);
+		/* Stage 1 Context with Stage 2 bypass */
+		SET_CBAR_TYPE(drvdata->base, ctx_drvdata->num, 1);
+		/* Route page faults to the non-secure interrupt */
+		SET_CBAR_IRPTNDX(drvdata->base, ctx_drvdata->num, 1);
+	}
+	mb();
+
+	return 0;
+}
+
+static int __devinit msm_iommu_ctx_probe(struct platform_device *pdev)
+{
+	struct msm_iommu_drvdata *drvdata;
+	struct msm_iommu_ctx_drvdata *ctx_drvdata = NULL;
+	int ret;
+
+	if (!pdev->dev.parent)
+		return -EINVAL;
+
+	drvdata = dev_get_drvdata(pdev->dev.parent);
+	if (!drvdata)
+		return -ENODEV;
+
+	ctx_drvdata = devm_kzalloc(&pdev->dev, sizeof(*ctx_drvdata),
+					GFP_KERNEL);
+	if (!ctx_drvdata)
+		return -ENOMEM;
+
+	ctx_drvdata->pdev = pdev;
+	INIT_LIST_HEAD(&ctx_drvdata->attached_elm);
+	platform_set_drvdata(pdev, ctx_drvdata);
+
+	ret = clk_prepare_enable(drvdata->pclk);
+	if (ret)
+		return ret;
+
+	if (drvdata->clk) {
+		ret = clk_prepare_enable(drvdata->clk);
+		if (ret) {
+			clk_disable_unprepare(drvdata->pclk);
+			return ret;
+		}
+	}
+
+	ret = msm_iommu_ctx_parse_dt(pdev, drvdata, ctx_drvdata);
+	if (!ret)
+		dev_info(&pdev->dev, "context %s using bank %d\n",
+				dev_name(&pdev->dev), ctx_drvdata->num);
+
+	if (drvdata->clk)
+		clk_disable_unprepare(drvdata->clk);
+	clk_disable_unprepare(drvdata->pclk);
+
+	return ret;
+}
+
+static int __devexit msm_iommu_ctx_remove(struct platform_device *pdev)
+{
+	platform_set_drvdata(pdev, NULL);
+	return 0;
+}
+
+static struct of_device_id msm_iommu_match_table[] = {
+	{ .compatible = "qcom,msm-smmu-v2", },
+	{}
+};
+
+static struct platform_driver msm_iommu_driver = {
+	.driver = {
+		.name	= "msm_iommu_v2",
+		.of_match_table = msm_iommu_match_table,
+	},
+	.probe		= msm_iommu_probe,
+	.remove		= __devexit_p(msm_iommu_remove),
+};
+
+static struct of_device_id msm_iommu_ctx_match_table[] = {
+	{ .name = "qcom,iommu-ctx", },
+	{}
+};
+
+static struct platform_driver msm_iommu_ctx_driver = {
+	.driver = {
+		.name	= "msm_iommu_ctx_v2",
+		.of_match_table = msm_iommu_ctx_match_table,
+	},
+	.probe		= msm_iommu_ctx_probe,
+	.remove		= __devexit_p(msm_iommu_ctx_remove),
+};
+
+static int __init msm_iommu_driver_init(void)
+{
+	struct device_node *node;
+	int ret;
+
+	node = of_find_compatible_node(NULL, NULL, "qcom,msm-smmu-v2");
+	if (!node)
+		return -ENODEV;
+
+	of_node_put(node);
+
+	msm_iommu_root_dev = platform_device_register_simple(
+						"msm_iommu", -1, 0, 0);
+	if (!msm_iommu_root_dev) {
+		pr_err("Failed to create root IOMMU device\n");
+		ret = -ENODEV;
+		goto error;
+	}
+
+	atomic_inc(&msm_iommu_next_id);
+
+	ret = platform_driver_register(&msm_iommu_driver);
+	if (ret != 0) {
+		pr_err("Failed to register IOMMU driver\n");
+		goto error;
+	}
+
+	ret = platform_driver_register(&msm_iommu_ctx_driver);
+	if (ret != 0) {
+		pr_err("Failed to register IOMMU context driver\n");
+		goto error;
+	}
+
+error:
+	return ret;
+}
+
+static void __exit msm_iommu_driver_exit(void)
+{
+	platform_driver_unregister(&msm_iommu_ctx_driver);
+	platform_driver_unregister(&msm_iommu_driver);
+	platform_device_unregister(msm_iommu_root_dev);
+}
+
+subsys_initcall(msm_iommu_driver_init);
+module_exit(msm_iommu_driver_exit);
+
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/iommu_dev.c b/arch/arm/mach-msm/iommu_dev.c
index b8b5aa3..967283d 100644
--- a/arch/arm/mach-msm/iommu_dev.c
+++ b/arch/arm/mach-msm/iommu_dev.c
@@ -33,13 +33,14 @@
 	struct device *dev;
 };
 
-static struct platform_device *msm_iommu_root_dev;
+struct platform_device *msm_iommu_root_dev;
 
 static int each_iommu_ctx(struct device *dev, void *data)
 {
 	struct iommu_ctx_iter_data *res = data;
-	struct msm_iommu_ctx_dev *c = dev->platform_data;
+	struct msm_iommu_ctx_drvdata *c;
 
+	c = dev_get_drvdata(dev);
 	if (!res || !c || !c->name || !res->name)
 		return -EINVAL;
 
@@ -68,7 +69,7 @@
 	r.name = ctx_name;
 	found = device_for_each_child(&msm_iommu_root_dev->dev, &r, each_iommu);
 
-	if (!found || !dev_get_drvdata(r.dev)) {
+	if (found <= 0 || !dev_get_drvdata(r.dev)) {
 		pr_err("Could not find context <%s>\n", ctx_name);
 		goto fail;
 	}
diff --git a/arch/arm/mach-msm/iommu_domains.c b/arch/arm/mach-msm/iommu_domains.c
index 34c16d1..9cf16b6 100644
--- a/arch/arm/mach-msm/iommu_domains.c
+++ b/arch/arm/mach-msm/iommu_domains.c
@@ -10,27 +10,34 @@
  * GNU General Public License for more details.
  */
 
-#include <mach/msm_subsystem_map.h>
-#include <linux/memory_alloc.h>
+#include <linux/init.h>
 #include <linux/iommu.h>
+#include <linux/memory_alloc.h>
 #include <linux/platform_device.h>
+#include <linux/rbtree.h>
+#include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <asm/sizes.h>
 #include <asm/page.h>
-#include <linux/init.h>
 #include <mach/iommu.h>
 #include <mach/iommu_domains.h>
 #include <mach/socinfo.h>
+#include <mach/msm_subsystem_map.h>
 
 /* dummy 64K for overmapping */
 char iommu_dummy[2*SZ_64K-4];
 
-struct msm_iommu_domain_state {
-	struct msm_iommu_domain *domains;
-	int ndomains;
+struct msm_iova_data {
+	struct rb_node node;
+	struct mem_pool *pools;
+	int npools;
+	struct iommu_domain *domain;
+	int domain_num;
 };
 
-static struct msm_iommu_domain_state domain_state;
+static struct rb_root domain_root;
+DEFINE_MUTEX(domain_mutex);
+static atomic_t domain_nums = ATOMIC_INIT(-1);
 
 int msm_iommu_map_extra(struct iommu_domain *domain,
 				unsigned long start_iova,
@@ -127,9 +134,10 @@
 	if (size & (align - 1))
 		return -EINVAL;
 
-	iova = msm_allocate_iova_address(domain_no, partition_no, size, align);
+	ret = msm_allocate_iova_address(domain_no, partition_no, size, align,
+						&iova);
 
-	if (!iova)
+	if (ret)
 		return -ENOMEM;
 
 	ret = msm_iommu_map_iova_phys(msm_get_iommu_domain(domain_no), iova,
@@ -152,73 +160,210 @@
 	msm_free_iova_address(iova, domain_no, partition_no, size);
 }
 
+static struct msm_iova_data *find_domain(int domain_num)
+{
+	struct rb_root *root = &domain_root;
+	struct rb_node *p = root->rb_node;
+
+	mutex_lock(&domain_mutex);
+
+	while (p) {
+		struct msm_iova_data *node;
+
+		node = rb_entry(p, struct msm_iova_data, node);
+		if (domain_num < node->domain_num)
+			p = p->rb_left;
+		else if (domain_num > node->domain_num)
+			p = p->rb_right;
+		else {
+			mutex_unlock(&domain_mutex);
+			return node;
+		}
+	}
+	mutex_unlock(&domain_mutex);
+	return NULL;
+}
+
+static int add_domain(struct msm_iova_data *node)
+{
+	struct rb_root *root = &domain_root;
+	struct rb_node **p = &root->rb_node;
+	struct rb_node *parent = NULL;
+
+	mutex_lock(&domain_mutex);
+	while (*p) {
+		struct msm_iova_data *tmp;
+		parent = *p;
+
+		tmp = rb_entry(parent, struct msm_iova_data, node);
+
+		if (node->domain_num < tmp->domain_num)
+			p = &(*p)->rb_left;
+		else if (node->domain_num > tmp->domain_num)
+			p = &(*p)->rb_right;
+		else
+			BUG();
+	}
+	rb_link_node(&node->node, parent, p);
+	rb_insert_color(&node->node, root);
+	mutex_unlock(&domain_mutex);
+	return 0;
+}
+
 struct iommu_domain *msm_get_iommu_domain(int domain_num)
 {
-	if (domain_num >= 0 && domain_num < domain_state.ndomains)
-		return domain_state.domains[domain_num].domain;
+	struct msm_iova_data *data;
+
+	data = find_domain(domain_num);
+
+	if (data)
+		return data->domain;
 	else
 		return NULL;
 }
 
-unsigned long msm_allocate_iova_address(unsigned int iommu_domain,
+int msm_allocate_iova_address(unsigned int iommu_domain,
 					unsigned int partition_no,
 					unsigned long size,
-					unsigned long align)
+					unsigned long align,
+					unsigned long *iova)
 {
+	struct msm_iova_data *data;
 	struct mem_pool *pool;
-	unsigned long iova;
+	unsigned long va;
 
-	if (iommu_domain >= domain_state.ndomains)
-		return 0;
+	data = find_domain(iommu_domain);
 
-	if (partition_no >= domain_state.domains[iommu_domain].npools)
-		return 0;
+	if (!data)
+		return -EINVAL;
 
-	pool = &domain_state.domains[iommu_domain].iova_pools[partition_no];
+	if (partition_no >= data->npools)
+		return -EINVAL;
+
+	pool = &data->pools[partition_no];
 
 	if (!pool->gpool)
-		return 0;
+		return -EINVAL;
 
-	iova = gen_pool_alloc_aligned(pool->gpool, size, ilog2(align));
-	if (iova)
+	va = gen_pool_alloc_aligned(pool->gpool, size, ilog2(align));
+	if (va) {
 		pool->free -= size;
+		/* Offset because genpool can't handle 0 addresses */
+		if (pool->paddr == 0)
+			va -= SZ_4K;
+		*iova = va;
+		return 0;
+	}
 
-	return iova;
+	return -ENOMEM;
 }
 
 void msm_free_iova_address(unsigned long iova,
-			   unsigned int iommu_domain,
-			   unsigned int partition_no,
-			   unsigned long size)
+				unsigned int iommu_domain,
+				unsigned int partition_no,
+				unsigned long size)
 {
+	struct msm_iova_data *data;
 	struct mem_pool *pool;
 
-	if (iommu_domain >= domain_state.ndomains) {
+	data = find_domain(iommu_domain);
+
+	if (!data) {
 		WARN(1, "Invalid domain %d\n", iommu_domain);
 		return;
 	}
 
-	if (partition_no >= domain_state.domains[iommu_domain].npools) {
+	if (partition_no >= data->npools) {
 		WARN(1, "Invalid partition %d for domain %d\n",
 			partition_no, iommu_domain);
 		return;
 	}
 
-	pool = &domain_state.domains[iommu_domain].iova_pools[partition_no];
+	pool = &data->pools[partition_no];
 
 	if (!pool)
 		return;
 
 	pool->free += size;
+
+	/* Offset because genpool can't handle 0 addresses */
+	if (pool->paddr == 0)
+		iova += SZ_4K;
+
 	gen_pool_free(pool->gpool, iova, size);
 }
 
+int msm_register_domain(struct msm_iova_layout *layout)
+{
+	int i;
+	struct msm_iova_data *data;
+	struct mem_pool *pools;
+
+	if (!layout)
+		return -EINVAL;
+
+	data = kmalloc(sizeof(*data), GFP_KERNEL);
+
+	if (!data)
+		return -ENOMEM;
+
+	pools = kmalloc(sizeof(struct mem_pool) * layout->npartitions,
+			GFP_KERNEL);
+
+	if (!pools)
+		goto out;
+
+	for (i = 0; i < layout->npartitions; i++) {
+		if (layout->partitions[i].size == 0)
+			continue;
+
+		pools[i].gpool = gen_pool_create(PAGE_SHIFT, -1);
+
+		if (!pools[i].gpool)
+			continue;
+
+		pools[i].paddr = layout->partitions[i].start;
+		pools[i].size = layout->partitions[i].size;
+
+		/*
+		 * genalloc can't handle a pool starting at address 0.
+		 * For now, solve this problem by offsetting the value
+		 * put in by 4k.
+		 * gen pool address = actual address + 4k
+		 */
+		if (pools[i].paddr == 0)
+			layout->partitions[i].start += SZ_4K;
+
+		if (gen_pool_add(pools[i].gpool,
+			layout->partitions[i].start,
+			layout->partitions[i].size, -1)) {
+			gen_pool_destroy(pools[i].gpool);
+			pools[i].gpool = NULL;
+			continue;
+		}
+	}
+
+	data->pools = pools;
+	data->npools = layout->npartitions;
+	data->domain_num = atomic_inc_return(&domain_nums);
+	data->domain = iommu_domain_alloc(layout->domain_flags);
+
+	add_domain(data);
+
+	return data->domain_num;
+
+out:
+	kfree(data);
+
+	return -EINVAL;
+}
+
 int msm_use_iommu()
 {
 	/*
 	 * If there are no domains, don't bother trying to use the iommu
 	 */
-	return domain_state.ndomains && iommu_found();
+	return iommu_found();
 }
 
 static int __init iommu_domain_probe(struct platform_device *pdev)
@@ -229,64 +374,52 @@
 	if (!p)
 		return -ENODEV;
 
-	domain_state.domains = p->domains;
-	domain_state.ndomains = p->ndomains;
+	for (i = 0; i < p->ndomains; i++) {
+		struct msm_iova_layout l;
+		struct msm_iova_partition *part;
+		struct msm_iommu_domain *domains;
 
-	for (i = 0; i < domain_state.ndomains; i++) {
-		domain_state.domains[i].domain = iommu_domain_alloc(
-							p->domain_alloc_flags);
-		if (!domain_state.domains[i].domain)
+		domains = p->domains;
+		l.npartitions = domains[i].npools;
+		part = kmalloc(
+			sizeof(struct msm_iova_partition) * l.npartitions,
+				GFP_KERNEL);
+
+		if (!part) {
+			pr_info("%s: could not allocate space for domain %d",
+				__func__, i);
 			continue;
-
-		for (j = 0; j < domain_state.domains[i].npools; j++) {
-			struct mem_pool *pool = &domain_state.domains[i].
-							iova_pools[j];
-			mutex_init(&pool->pool_mutex);
-			if (pool->size) {
-				pool->gpool = gen_pool_create(PAGE_SHIFT, -1);
-
-				if (!pool->gpool) {
-					pr_err("%s: could not allocate pool\n",
-						__func__);
-					pr_err("%s: domain %d iova space %d\n",
-						__func__, i, j);
-					continue;
-				}
-
-				if (gen_pool_add(pool->gpool, pool->paddr,
-						pool->size, -1)) {
-					pr_err("%s: could not add memory\n",
-						__func__);
-					pr_err("%s: domain %d pool %d\n",
-						__func__, i, j);
-					gen_pool_destroy(pool->gpool);
-					pool->gpool = NULL;
-					continue;
-				}
-			} else {
-				pool->gpool = NULL;
-			}
 		}
+
+		for (j = 0; j < l.npartitions; j++) {
+			part[j].start = p->domains[i].iova_pools[j].paddr;
+			part[j].size = p->domains[i].iova_pools[j].size;
+		}
+
+		l.partitions = part;
+
+		msm_register_domain(&l);
+
+		kfree(part);
 	}
 
 	for (i = 0; i < p->nnames; i++) {
-		int domain_idx;
 		struct device *ctx = msm_iommu_get_ctx(
 						p->domain_names[i].name);
+		struct iommu_domain *domain;
 
 		if (!ctx)
 			continue;
 
-		domain_idx = p->domain_names[i].domain;
+		domain = msm_get_iommu_domain(p->domain_names[i].domain);
 
-		if (!domain_state.domains[domain_idx].domain)
+		if (!domain)
 			continue;
 
-		if (iommu_attach_device(domain_state.domains[domain_idx].domain,
-					ctx)) {
-			WARN(1, "%s: could not attach domain %d to context %s."
+		if (iommu_attach_device(domain, ctx)) {
+			WARN(1, "%s: could not attach domain %p to context %s."
 				" iommu programming will not occur.\n",
-				__func__, domain_idx,
+				__func__, domain,
 				p->domain_names[i].name);
 			continue;
 		}
diff --git a/arch/arm/mach-msm/iommu_pagetable.c b/arch/arm/mach-msm/iommu_pagetable.c
new file mode 100644
index 0000000..b485605
--- /dev/null
+++ b/arch/arm/mach-msm/iommu_pagetable.c
@@ -0,0 +1,520 @@
+/* Copyright (c) 2012 Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/iommu.h>
+#include <linux/scatterlist.h>
+
+#include <asm/cacheflush.h>
+
+#include <mach/iommu.h>
+#include "iommu_pagetable.h"
+
+/* Sharability attributes of MSM IOMMU mappings */
+#define MSM_IOMMU_ATTR_NON_SH		0x0
+#define MSM_IOMMU_ATTR_SH		0x4
+
+/* Cacheability attributes of MSM IOMMU mappings */
+#define MSM_IOMMU_ATTR_NONCACHED	0x0
+#define MSM_IOMMU_ATTR_CACHED_WB_WA	0x1
+#define MSM_IOMMU_ATTR_CACHED_WB_NWA	0x2
+#define MSM_IOMMU_ATTR_CACHED_WT	0x3
+
+static int msm_iommu_tex_class[4];
+
+static inline void clean_pte(unsigned long *start, unsigned long *end,
+				int redirect)
+{
+	if (!redirect)
+		dmac_flush_range(start, end);
+}
+
+int msm_iommu_pagetable_alloc(struct iommu_pt *pt)
+{
+	pt->fl_table = (unsigned long *)__get_free_pages(GFP_KERNEL,
+							  get_order(SZ_16K));
+	if (!pt->fl_table)
+		return -ENOMEM;
+
+	memset(pt->fl_table, 0, SZ_16K);
+	clean_pte(pt->fl_table, pt->fl_table + NUM_FL_PTE, pt->redirect);
+
+	return 0;
+}
+
+void msm_iommu_pagetable_free(struct iommu_pt *pt)
+{
+	unsigned long *fl_table;
+	int i;
+
+	fl_table = pt->fl_table;
+	for (i = 0; i < NUM_FL_PTE; i++)
+		if ((fl_table[i] & 0x03) == FL_TYPE_TABLE)
+			free_page((unsigned long) __va(((fl_table[i]) &
+							FL_BASE_MASK)));
+	free_pages((unsigned long)fl_table, get_order(SZ_16K));
+	pt->fl_table = 0;
+}
+
+static int __get_pgprot(int prot, int len)
+{
+	unsigned int pgprot;
+	int tex;
+
+	if (!(prot & (IOMMU_READ | IOMMU_WRITE))) {
+		prot |= IOMMU_READ | IOMMU_WRITE;
+		WARN_ONCE(1, "No attributes in iommu mapping; assuming RW\n");
+	}
+
+	if ((prot & IOMMU_WRITE) && !(prot & IOMMU_READ)) {
+		prot |= IOMMU_READ;
+		WARN_ONCE(1, "Write-only unsupported; falling back to RW\n");
+	}
+
+	if (prot & IOMMU_CACHE)
+		tex = (pgprot_kernel >> 2) & 0x07;
+	else
+		tex = msm_iommu_tex_class[MSM_IOMMU_ATTR_NONCACHED];
+
+	if (tex < 0 || tex > NUM_TEX_CLASS - 1)
+		return 0;
+
+	if (len == SZ_16M || len == SZ_1M) {
+		pgprot = FL_SHARED;
+		pgprot |= tex & 0x01 ? FL_BUFFERABLE : 0;
+		pgprot |= tex & 0x02 ? FL_CACHEABLE : 0;
+		pgprot |= tex & 0x04 ? FL_TEX0 : 0;
+		pgprot |= FL_AP0 | FL_AP1;
+		pgprot |= prot & IOMMU_WRITE ? 0 : FL_AP2;
+	} else	{
+		pgprot = SL_SHARED;
+		pgprot |= tex & 0x01 ? SL_BUFFERABLE : 0;
+		pgprot |= tex & 0x02 ? SL_CACHEABLE : 0;
+		pgprot |= tex & 0x04 ? SL_TEX0 : 0;
+		pgprot |= SL_AP0 | SL_AP1;
+		pgprot |= prot & IOMMU_WRITE ? 0 : SL_AP2;
+	}
+
+	return pgprot;
+}
+
+int msm_iommu_pagetable_map(struct iommu_pt *pt, unsigned long va,
+			phys_addr_t pa, int order, int prot)
+{
+	unsigned long *fl_pte;
+	unsigned long fl_offset;
+	unsigned long *sl_table;
+	unsigned long *sl_pte;
+	unsigned long sl_offset;
+	unsigned int pgprot;
+	size_t len = 0x1000UL << order;
+	int ret = 0;
+
+	if (len != SZ_16M && len != SZ_1M &&
+	    len != SZ_64K && len != SZ_4K) {
+		pr_debug("Bad size: %d\n", len);
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	if (!pt->fl_table) {
+		pr_debug("Null page table\n");
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	pgprot = __get_pgprot(prot, len);
+	if (!pgprot) {
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	fl_offset = FL_OFFSET(va);		/* Upper 12 bits */
+	fl_pte = pt->fl_table + fl_offset;	/* int pointers, 4 bytes */
+
+	if (len == SZ_16M) {
+		int i = 0;
+
+		for (i = 0; i < 16; i++)
+			if (*(fl_pte+i)) {
+				ret = -EBUSY;
+				goto fail;
+			}
+
+		for (i = 0; i < 16; i++)
+			*(fl_pte+i) = (pa & 0xFF000000) | FL_SUPERSECTION |
+				  FL_TYPE_SECT | FL_SHARED | FL_NG | pgprot;
+		clean_pte(fl_pte, fl_pte + 16, pt->redirect);
+	}
+
+	if (len == SZ_1M) {
+		if (*fl_pte) {
+			ret = -EBUSY;
+			goto fail;
+		}
+
+		*fl_pte = (pa & 0xFFF00000) | FL_NG | FL_TYPE_SECT
+					| FL_SHARED | pgprot;
+		clean_pte(fl_pte, fl_pte + 1, pt->redirect);
+	}
+
+	/* Need a 2nd level table */
+	if (len == SZ_4K || len == SZ_64K) {
+
+		if (*fl_pte == 0) {
+			unsigned long *sl;
+			sl = (unsigned long *) __get_free_pages(GFP_KERNEL,
+							get_order(SZ_4K));
+
+			if (!sl) {
+				pr_debug("Could not allocate second level table\n");
+				ret = -ENOMEM;
+				goto fail;
+			}
+			memset(sl, 0, SZ_4K);
+			clean_pte(sl, sl + NUM_SL_PTE, pt->redirect);
+
+			*fl_pte = ((((int)__pa(sl)) & FL_BASE_MASK) | \
+						      FL_TYPE_TABLE);
+			clean_pte(fl_pte, fl_pte + 1, pt->redirect);
+		}
+
+		if (!(*fl_pte & FL_TYPE_TABLE)) {
+			ret = -EBUSY;
+			goto fail;
+		}
+	}
+
+	sl_table = (unsigned long *) __va(((*fl_pte) & FL_BASE_MASK));
+	sl_offset = SL_OFFSET(va);
+	sl_pte = sl_table + sl_offset;
+
+	if (len == SZ_4K) {
+		if (*sl_pte) {
+			ret = -EBUSY;
+			goto fail;
+		}
+
+		*sl_pte = (pa & SL_BASE_MASK_SMALL) | SL_NG | SL_SHARED
+						| SL_TYPE_SMALL | pgprot;
+		clean_pte(sl_pte, sl_pte + 1, pt->redirect);
+	}
+
+	if (len == SZ_64K) {
+		int i;
+
+		for (i = 0; i < 16; i++)
+			if (*(sl_pte+i)) {
+				ret = -EBUSY;
+				goto fail;
+			}
+
+		for (i = 0; i < 16; i++)
+			*(sl_pte+i) = (pa & SL_BASE_MASK_LARGE) | SL_NG
+					| SL_SHARED | SL_TYPE_LARGE | pgprot;
+
+		clean_pte(sl_pte, sl_pte + 16, pt->redirect);
+	}
+
+fail:
+	return ret;
+}
+
+int msm_iommu_pagetable_unmap(struct iommu_pt *pt, unsigned long va, int order)
+{
+	unsigned long *fl_pte;
+	unsigned long fl_offset;
+	unsigned long *sl_table;
+	unsigned long *sl_pte;
+	unsigned long sl_offset;
+	size_t len = 0x1000UL << order;
+	int i, ret = 0;
+
+	if (len != SZ_16M && len != SZ_1M &&
+	    len != SZ_64K && len != SZ_4K) {
+		pr_debug("Bad length: %d\n", len);
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	if (!pt->fl_table) {
+		pr_debug("Null page table\n");
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	fl_offset = FL_OFFSET(va);		/* Upper 12 bits */
+	fl_pte = pt->fl_table + fl_offset;	/* int pointers, 4 bytes */
+
+	if (*fl_pte == 0) {
+		pr_debug("First level PTE is 0\n");
+		ret = -ENODEV;
+		goto fail;
+	}
+
+	/* Unmap supersection */
+	if (len == SZ_16M) {
+		for (i = 0; i < 16; i++)
+			*(fl_pte+i) = 0;
+
+		clean_pte(fl_pte, fl_pte + 16, pt->redirect);
+	}
+
+	if (len == SZ_1M) {
+		*fl_pte = 0;
+		clean_pte(fl_pte, fl_pte + 1, pt->redirect);
+	}
+
+	sl_table = (unsigned long *) __va(((*fl_pte) & FL_BASE_MASK));
+	sl_offset = SL_OFFSET(va);
+	sl_pte = sl_table + sl_offset;
+
+	if (len == SZ_64K) {
+		for (i = 0; i < 16; i++)
+			*(sl_pte+i) = 0;
+
+		clean_pte(sl_pte, sl_pte + 16, pt->redirect);
+	}
+
+	if (len == SZ_4K) {
+		*sl_pte = 0;
+		clean_pte(sl_pte, sl_pte + 1, pt->redirect);
+	}
+
+	if (len == SZ_4K || len == SZ_64K) {
+		int used = 0;
+
+		for (i = 0; i < NUM_SL_PTE; i++)
+			if (sl_table[i])
+				used = 1;
+		if (!used) {
+			free_page((unsigned long)sl_table);
+			*fl_pte = 0;
+			clean_pte(fl_pte, fl_pte + 1, pt->redirect);
+		}
+	}
+
+fail:
+	return ret;
+}
+
+static unsigned int get_phys_addr(struct scatterlist *sg)
+{
+	/*
+	 * Try sg_dma_address first so that we can
+	 * map carveout regions that do not have a
+	 * struct page associated with them.
+	 */
+	unsigned int pa = sg_dma_address(sg);
+	if (pa == 0)
+		pa = sg_phys(sg);
+	return pa;
+}
+
+int msm_iommu_pagetable_map_range(struct iommu_pt *pt, unsigned int va,
+		       struct scatterlist *sg, unsigned int len, int prot)
+{
+	unsigned int pa;
+	unsigned int offset = 0;
+	unsigned int pgprot;
+	unsigned long *fl_pte;
+	unsigned long fl_offset;
+	unsigned long *sl_table;
+	unsigned long sl_offset, sl_start;
+	unsigned int chunk_offset = 0;
+	unsigned int chunk_pa;
+	int ret = 0;
+
+	BUG_ON(len & (SZ_4K - 1));
+
+	pgprot = __get_pgprot(prot, SZ_4K);
+	if (!pgprot) {
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	fl_offset = FL_OFFSET(va);		/* Upper 12 bits */
+	fl_pte = pt->fl_table + fl_offset;	/* int pointers, 4 bytes */
+
+	sl_table = (unsigned long *) __va(((*fl_pte) & FL_BASE_MASK));
+	sl_offset = SL_OFFSET(va);
+
+	chunk_pa = get_phys_addr(sg);
+	if (chunk_pa == 0) {
+		pr_debug("No dma address for sg %p\n", sg);
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	while (offset < len) {
+		/* Set up a 2nd level page table if one doesn't exist */
+		if (*fl_pte == 0) {
+			sl_table = (unsigned long *)
+				 __get_free_pages(GFP_KERNEL, get_order(SZ_4K));
+
+			if (!sl_table) {
+				pr_debug("Could not allocate second level table\n");
+				ret = -ENOMEM;
+				goto fail;
+			}
+
+			memset(sl_table, 0, SZ_4K);
+			clean_pte(sl_table, sl_table + NUM_SL_PTE,
+					pt->redirect);
+
+			*fl_pte = ((((int)__pa(sl_table)) & FL_BASE_MASK) |
+							    FL_TYPE_TABLE);
+			clean_pte(fl_pte, fl_pte + 1, pt->redirect);
+		} else
+			sl_table = (unsigned long *)
+					       __va(((*fl_pte) & FL_BASE_MASK));
+
+		/* Keep track of initial position so we
+		 * don't clean more than we have to
+		 */
+		sl_start = sl_offset;
+
+		/* Build the 2nd level page table */
+		while (offset < len && sl_offset < NUM_SL_PTE) {
+			pa = chunk_pa + chunk_offset;
+			sl_table[sl_offset] = (pa & SL_BASE_MASK_SMALL) |
+			      pgprot | SL_NG | SL_SHARED | SL_TYPE_SMALL;
+			sl_offset++;
+			offset += SZ_4K;
+
+			chunk_offset += SZ_4K;
+
+			if (chunk_offset >= sg->length && offset < len) {
+				chunk_offset = 0;
+				sg = sg_next(sg);
+				chunk_pa = get_phys_addr(sg);
+				if (chunk_pa == 0) {
+					pr_debug("No dma address for sg %p\n",
+						sg);
+					ret = -EINVAL;
+					goto fail;
+				}
+			}
+		}
+
+		clean_pte(sl_table + sl_start, sl_table + sl_offset,
+				pt->redirect);
+		fl_pte++;
+		sl_offset = 0;
+	}
+
+fail:
+	return ret;
+}
+
+void msm_iommu_pagetable_unmap_range(struct iommu_pt *pt, unsigned int va,
+				 unsigned int len)
+{
+	unsigned int offset = 0;
+	unsigned long *fl_pte;
+	unsigned long fl_offset;
+	unsigned long *sl_table;
+	unsigned long sl_start, sl_end;
+	int used, i;
+
+	BUG_ON(len & (SZ_4K - 1));
+
+	fl_offset = FL_OFFSET(va);		/* Upper 12 bits */
+	fl_pte = pt->fl_table + fl_offset;	/* int pointers, 4 bytes */
+
+	sl_start = SL_OFFSET(va);
+
+	while (offset < len) {
+		sl_table = (unsigned long *) __va(((*fl_pte) & FL_BASE_MASK));
+		sl_end = ((len - offset) / SZ_4K) + sl_start;
+
+		if (sl_end > NUM_SL_PTE)
+			sl_end = NUM_SL_PTE;
+
+		memset(sl_table + sl_start, 0, (sl_end - sl_start) * 4);
+		clean_pte(sl_table + sl_start, sl_table + sl_end,
+				pt->redirect);
+
+		offset += (sl_end - sl_start) * SZ_4K;
+
+		/* Unmap and free the 2nd level table if all mappings in it
+		 * were removed. This saves memory, but the table will need
+		 * to be re-allocated the next time someone tries to map these
+		 * VAs.
+		 */
+		used = 0;
+
+		/* If we just unmapped the whole table, don't bother
+		 * seeing if there are still used entries left.
+		 */
+		if (sl_end - sl_start != NUM_SL_PTE)
+			for (i = 0; i < NUM_SL_PTE; i++)
+				if (sl_table[i]) {
+					used = 1;
+					break;
+				}
+		if (!used) {
+			free_page((unsigned long)sl_table);
+			*fl_pte = 0;
+			clean_pte(fl_pte, fl_pte + 1, pt->redirect);
+		}
+
+		sl_start = 0;
+		fl_pte++;
+	}
+}
+
+static int __init get_tex_class(int icp, int ocp, int mt, int nos)
+{
+	int i = 0;
+	unsigned int prrr = 0;
+	unsigned int nmrr = 0;
+	int c_icp, c_ocp, c_mt, c_nos;
+
+	RCP15_PRRR(prrr);
+	RCP15_NMRR(nmrr);
+
+	for (i = 0; i < NUM_TEX_CLASS; i++) {
+		c_nos = PRRR_NOS(prrr, i);
+		c_mt = PRRR_MT(prrr, i);
+		c_icp = NMRR_ICP(nmrr, i);
+		c_ocp = NMRR_OCP(nmrr, i);
+
+		if (icp == c_icp && ocp == c_ocp && c_mt == mt && c_nos == nos)
+			return i;
+	}
+
+	return -ENODEV;
+}
+
+static void __init setup_iommu_tex_classes(void)
+{
+	msm_iommu_tex_class[MSM_IOMMU_ATTR_NONCACHED] =
+			get_tex_class(CP_NONCACHED, CP_NONCACHED, MT_NORMAL, 1);
+
+	msm_iommu_tex_class[MSM_IOMMU_ATTR_CACHED_WB_WA] =
+			get_tex_class(CP_WB_WA, CP_WB_WA, MT_NORMAL, 1);
+
+	msm_iommu_tex_class[MSM_IOMMU_ATTR_CACHED_WB_NWA] =
+			get_tex_class(CP_WB_NWA, CP_WB_NWA, MT_NORMAL, 1);
+
+	msm_iommu_tex_class[MSM_IOMMU_ATTR_CACHED_WT] =
+			get_tex_class(CP_WT, CP_WT, MT_NORMAL, 1);
+}
+
+void __init msm_iommu_pagetable_init(void)
+{
+	setup_iommu_tex_classes();
+}
diff --git a/arch/arm/mach-msm/iommu_pagetable.h b/arch/arm/mach-msm/iommu_pagetable.h
new file mode 100644
index 0000000..39f1d3d
--- /dev/null
+++ b/arch/arm/mach-msm/iommu_pagetable.h
@@ -0,0 +1,90 @@
+/* Copyright (c) 2012 Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_IOMMU_PAGETABLE_H
+#define __ARCH_ARM_MACH_MSM_IOMMU_PAGETABLE_H
+
+#define NUM_FL_PTE      4096
+#define NUM_SL_PTE      256
+#define NUM_TEX_CLASS   8
+
+/* First-level page table bits */
+#define FL_BASE_MASK            0xFFFFFC00
+#define FL_TYPE_TABLE           (1 << 0)
+#define FL_TYPE_SECT            (2 << 0)
+#define FL_SUPERSECTION         (1 << 18)
+#define FL_AP0                  (1 << 10)
+#define FL_AP1                  (1 << 11)
+#define FL_AP2                  (1 << 15)
+#define FL_SHARED               (1 << 16)
+#define FL_BUFFERABLE           (1 << 2)
+#define FL_CACHEABLE            (1 << 3)
+#define FL_TEX0                 (1 << 12)
+#define FL_OFFSET(va)           (((va) & 0xFFF00000) >> 20)
+#define FL_NG                   (1 << 17)
+
+/* Second-level page table bits */
+#define SL_BASE_MASK_LARGE      0xFFFF0000
+#define SL_BASE_MASK_SMALL      0xFFFFF000
+#define SL_TYPE_LARGE           (1 << 0)
+#define SL_TYPE_SMALL           (2 << 0)
+#define SL_AP0                  (1 << 4)
+#define SL_AP1                  (2 << 4)
+#define SL_AP2                  (1 << 9)
+#define SL_SHARED               (1 << 10)
+#define SL_BUFFERABLE           (1 << 2)
+#define SL_CACHEABLE            (1 << 3)
+#define SL_TEX0                 (1 << 6)
+#define SL_OFFSET(va)           (((va) & 0xFF000) >> 12)
+#define SL_NG                   (1 << 11)
+
+/* Memory type and cache policy attributes */
+#define MT_SO                   0
+#define MT_DEV                  1
+#define MT_NORMAL               2
+#define CP_NONCACHED            0
+#define CP_WB_WA                1
+#define CP_WT                   2
+#define CP_WB_NWA               3
+
+/* TEX Remap Registers */
+#define NMRR_ICP(nmrr, n) (((nmrr) & (3 << ((n) * 2))) >> ((n) * 2))
+#define NMRR_OCP(nmrr, n) (((nmrr) & (3 << ((n) * 2 + 16))) >> ((n) * 2 + 16))
+
+#define PRRR_NOS(prrr, n) ((prrr) & (1 << ((n) + 24)) ? 1 : 0)
+#define PRRR_MT(prrr, n)  ((((prrr) & (3 << ((n) * 2))) >> ((n) * 2)))
+
+#define MRC(reg, processor, op1, crn, crm, op2)                         \
+__asm__ __volatile__ (                                                  \
+"   mrc   "   #processor "," #op1 ", %0,"  #crn "," #crm "," #op2 "\n"  \
+: "=r" (reg))
+
+#define RCP15_PRRR(reg)   MRC(reg, p15, 0, c10, c2, 0)
+#define RCP15_NMRR(reg)   MRC(reg, p15, 0, c10, c2, 1)
+
+struct iommu_pt {
+	unsigned long *fl_table;
+	int redirect;
+};
+
+void msm_iommu_pagetable_init(void);
+int msm_iommu_pagetable_alloc(struct iommu_pt *pt);
+void msm_iommu_pagetable_free(struct iommu_pt *pt);
+int msm_iommu_pagetable_map(struct iommu_pt *pt, unsigned long va,
+			phys_addr_t pa, int order, int prot);
+int msm_iommu_pagetable_unmap(struct iommu_pt *pt, unsigned long va,
+				int order);
+int msm_iommu_pagetable_map_range(struct iommu_pt *pt, unsigned int va,
+			struct scatterlist *sg, unsigned int len, int prot);
+void msm_iommu_pagetable_unmap_range(struct iommu_pt *pt, unsigned int va,
+				unsigned int len);
+#endif
diff --git a/arch/arm/mach-msm/ipc_router_smd_xprt.c b/arch/arm/mach-msm/ipc_router_smd_xprt.c
index 307b6ae..a5721c4 100644
--- a/arch/arm/mach-msm/ipc_router_smd_xprt.c
+++ b/arch/arm/mach-msm/ipc_router_smd_xprt.c
@@ -52,6 +52,7 @@
 	struct delayed_work read_work;
 	spinlock_t ss_reset_lock;	/*Subsystem reset lock*/
 	int ss_reset;
+	void *pil;
 };
 
 struct msm_ipc_router_smd_xprt_work {
@@ -202,10 +203,16 @@
 
 static int msm_ipc_router_smd_remote_close(struct msm_ipc_router_xprt *xprt)
 {
+	int rc;
 	struct msm_ipc_router_smd_xprt *smd_xprtp =
 		container_of(xprt, struct msm_ipc_router_smd_xprt, xprt);
 
-	return smd_close(smd_xprtp->channel);
+	rc = smd_close(smd_xprtp->channel);
+	if (smd_xprtp->pil) {
+		pil_put(smd_xprtp->pil);
+		smd_xprtp->pil = NULL;
+	}
+	return rc;
 }
 
 static void smd_xprt_read_data(struct work_struct *work)
@@ -387,6 +394,23 @@
 	}
 }
 
+static void *msm_ipc_load_subsystem(uint32_t edge)
+{
+	void *pil = NULL;
+	const char *peripheral;
+
+	peripheral = smd_edge_to_subsystem(edge);
+	if (peripheral) {
+		pil = pil_get(peripheral);
+		if (IS_ERR(pil)) {
+			pr_err("%s: Failed to load %s\n",
+				__func__, peripheral);
+			pil = NULL;
+		}
+	}
+	return pil;
+}
+
 static int msm_ipc_router_smd_remote_probe(struct platform_device *pdev)
 {
 	int rc;
@@ -424,6 +448,8 @@
 	spin_lock_init(&smd_remote_xprt[id].ss_reset_lock);
 	smd_remote_xprt[id].ss_reset = 0;
 
+	smd_remote_xprt[id].pil = msm_ipc_load_subsystem(
+					smd_xprt_cfg[id].edge);
 	rc = smd_named_open_on_edge(smd_xprt_cfg[id].ch_name,
 				    smd_xprt_cfg[id].edge,
 				    &smd_remote_xprt[id].channel,
@@ -432,6 +458,10 @@
 	if (rc < 0) {
 		pr_err("%s: Channel open failed for %s\n",
 			__func__, smd_xprt_cfg[id].ch_name);
+		if (smd_remote_xprt[id].pil) {
+			pil_put(smd_remote_xprt[id].pil);
+			smd_remote_xprt[id].pil = NULL;
+		}
 		destroy_workqueue(smd_remote_xprt[id].smd_xprt_wq);
 		return rc;
 	}
diff --git a/arch/arm/mach-msm/lpm_levels.c b/arch/arm/mach-msm/lpm_levels.c
index 48cf3f7..80b82cb 100644
--- a/arch/arm/mach-msm/lpm_levels.c
+++ b/arch/arm/mach-msm/lpm_levels.c
@@ -19,18 +19,19 @@
 #include <linux/of.h>
 #include <mach/mpm.h>
 #include "rpm_resources.h"
+#include "pm.h"
 
 static struct msm_rpmrs_level *msm_lpm_levels;
 static int msm_lpm_level_count;
 
-int msm_rpmrs_enter_sleep(uint32_t sclk_count, struct msm_rpmrs_limits *limits,
+static int msm_lpm_enter_sleep(uint32_t sclk_count, void *limits,
 		bool from_idle, bool notify_rpm)
 {
 	/* TODO */
 	return 0;
 }
 
-void msm_rpmrs_exit_sleep(struct msm_rpmrs_limits *limits, bool from_idle,
+static void msm_lpm_exit_sleep(void *limits, bool from_idle,
 		bool notify_rpm, bool collapsed)
 {
 	/* TODO */
@@ -50,14 +51,15 @@
 	return;
 }
 
-struct msm_rpmrs_limits *msm_rpmrs_lowest_limits(
-	bool from_idle, enum msm_pm_sleep_mode sleep_mode, uint32_t latency_us,
-	uint32_t sleep_us)
+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)
 {
 	unsigned int cpu = smp_processor_id();
 	struct msm_rpmrs_level *best_level = NULL;
 	bool irqs_detectable = false;
 	bool gpio_detectable = false;
+	uint32_t pwr;
 	int i;
 
 	if (!msm_lpm_levels)
@@ -70,7 +72,6 @@
 
 	for (i = 0; i < msm_lpm_level_count; i++) {
 		struct msm_rpmrs_level *level = &msm_lpm_levels[i];
-		uint32_t power;
 
 		if (!level->available)
 			continue;
@@ -86,28 +87,36 @@
 			continue;
 
 		if (sleep_us <= 1) {
-			power = level->energy_overhead;
+			pwr = level->energy_overhead;
 		} else if (sleep_us <= level->time_overhead_us) {
-			power = level->energy_overhead / sleep_us;
+			pwr = level->energy_overhead / sleep_us;
 		} else if ((sleep_us >> 10) > level->time_overhead_us) {
-			power = level->steady_state_power;
+			pwr = level->steady_state_power;
 		} else {
-			power = level->steady_state_power;
-			power -= (level->time_overhead_us *
+			pwr = level->steady_state_power;
+			pwr -= (level->time_overhead_us *
 					level->steady_state_power)/sleep_us;
-			power += level->energy_overhead / sleep_us;
+			pwr += level->energy_overhead / sleep_us;
 		}
 
-		if (!best_level ||
-				best_level->rs_limits.power[cpu] >= power) {
+		if (!best_level || best_level->rs_limits.power[cpu] >= pwr) {
+
 			level->rs_limits.latency_us[cpu] = level->latency_us;
-			level->rs_limits.power[cpu] = power;
+			level->rs_limits.power[cpu] = pwr;
 			best_level = level;
+
+			if (power)
+				*power = pwr;
 		}
 	}
 
 	return best_level ? &best_level->rs_limits : NULL;
 }
+static struct msm_pm_sleep_ops msm_lpm_ops = {
+	.lowest_limits = msm_lpm_lowest_limits,
+	.enter_sleep = msm_lpm_enter_sleep,
+	.exit_sleep = msm_lpm_exit_sleep,
+};
 
 static int __devinit msm_lpm_levels_probe(struct platform_device *pdev)
 {
@@ -204,6 +213,8 @@
 	msm_lpm_levels = levels;
 	msm_lpm_level_count = idx;
 
+	msm_pm_set_sleep_ops(&msm_lpm_ops);
+
 	return 0;
 fail:
 	pr_err("%s: Error in name %s key %s\n", __func__, node->full_name, key);
diff --git a/arch/arm/mach-msm/mdm2.c b/arch/arm/mach-msm/mdm2.c
index b4b7ea3..bd7bd9e 100644
--- a/arch/arm/mach-msm/mdm2.c
+++ b/arch/arm/mach-msm/mdm2.c
@@ -53,11 +53,13 @@
 
 static void mdm_peripheral_connect(struct mdm_modem_drv *mdm_drv)
 {
+	if (!mdm_drv->pdata->peripheral_platform_device)
+		return;
+
 	mutex_lock(&hsic_status_lock);
 	if (hsic_peripheral_status)
 		goto out;
-	if (mdm_drv->pdata->peripheral_platform_device)
-		platform_device_add(mdm_drv->pdata->peripheral_platform_device);
+	platform_device_add(mdm_drv->pdata->peripheral_platform_device);
 	hsic_peripheral_status = 1;
 out:
 	mutex_unlock(&hsic_status_lock);
@@ -65,84 +67,106 @@
 
 static void mdm_peripheral_disconnect(struct mdm_modem_drv *mdm_drv)
 {
+	if (!mdm_drv->pdata->peripheral_platform_device)
+		return;
+
 	mutex_lock(&hsic_status_lock);
 	if (!hsic_peripheral_status)
 		goto out;
-	if (mdm_drv->pdata->peripheral_platform_device)
-		platform_device_del(mdm_drv->pdata->peripheral_platform_device);
+	platform_device_del(mdm_drv->pdata->peripheral_platform_device);
 	hsic_peripheral_status = 0;
 out:
 	mutex_unlock(&hsic_status_lock);
 }
 
-static void power_on_mdm(struct mdm_modem_drv *mdm_drv)
+static void mdm_power_down_common(struct mdm_modem_drv *mdm_drv)
+{
+	int soft_reset_direction =
+		mdm_drv->pdata->soft_reset_inverted ? 1 : 0;
+
+	gpio_direction_output(mdm_drv->ap2mdm_soft_reset_gpio,
+				soft_reset_direction);
+	mdm_peripheral_disconnect(mdm_drv);
+}
+
+static void mdm_do_first_power_on(struct mdm_modem_drv *mdm_drv)
+{
+	int soft_reset_direction =
+		mdm_drv->pdata->soft_reset_inverted ? 0 : 1;
+
+	if (power_on_count != 1) {
+		pr_err("%s: Calling fn when power_on_count != 1\n",
+			   __func__);
+		return;
+	}
+
+	pr_err("%s: Powering on modem for the first time\n", __func__);
+	mdm_peripheral_disconnect(mdm_drv);
+
+	/* If the device has a kpd pwr gpio then toggle it. */
+	if (mdm_drv->ap2mdm_kpdpwr_n_gpio > 0) {
+		/* Pull AP2MDM_KPDPWR gpio high and wait for PS_HOLD to settle,
+		 * then	pull it back low.
+		 */
+		pr_debug("%s: Pulling AP2MDM_KPDPWR gpio high\n", __func__);
+		gpio_direction_output(mdm_drv->ap2mdm_kpdpwr_n_gpio, 1);
+		msleep(1000);
+		gpio_direction_output(mdm_drv->ap2mdm_kpdpwr_n_gpio, 0);
+	}
+
+	/* De-assert the soft reset line. */
+	pr_debug("%s: De-asserting soft reset gpio\n", __func__);
+	gpio_direction_output(mdm_drv->ap2mdm_soft_reset_gpio,
+						  soft_reset_direction);
+
+	mdm_peripheral_connect(mdm_drv);
+	msleep(200);
+}
+
+static void mdm_do_soft_power_on(struct mdm_modem_drv *mdm_drv)
+{
+	int soft_reset_direction =
+		mdm_drv->pdata->soft_reset_inverted ? 0 : 1;
+
+	/* De-assert the soft reset line. */
+	pr_err("%s: soft resetting mdm modem\n", __func__);
+
+	mdm_peripheral_disconnect(mdm_drv);
+
+	gpio_direction_output(mdm_drv->ap2mdm_soft_reset_gpio,
+		soft_reset_direction == 1 ? 0 : 1);
+	usleep_range(5000, 10000);
+	gpio_direction_output(mdm_drv->ap2mdm_soft_reset_gpio,
+		soft_reset_direction == 1 ? 1 : 0);
+
+	mdm_peripheral_connect(mdm_drv);
+	msleep(200);
+}
+
+static void mdm_power_on_common(struct mdm_modem_drv *mdm_drv)
 {
 	power_on_count++;
 
 	/* this gpio will be used to indicate apq readiness,
-	 * de-assert it now so that it can asserted later
+	 * de-assert it now so that it can be asserted later.
+	 * May not be used.
 	 */
-	gpio_direction_output(mdm_drv->ap2mdm_wakeup_gpio, 0);
+	if (mdm_drv->ap2mdm_wakeup_gpio > 0)
+		gpio_direction_output(mdm_drv->ap2mdm_wakeup_gpio, 0);
 
-	/* The second attempt to power-on the mdm is the first attempt
-	 * from user space, but we're already powered on. Ignore this.
-	 * Subsequent attempts are from SSR or if something failed, in
-	 * which case we must always reset the modem.
+	/*
+	 * If we did an "early power on" then ignore the very next
+	 * power-on request because it would the be first request from
+	 * user space but we're already powered on. Ignore it.
 	 */
-	if (power_on_count == 2)
+	if (mdm_drv->pdata->early_power_on &&
+			(power_on_count == 2))
 		return;
 
-	mdm_peripheral_disconnect(mdm_drv);
-
-	/* Pull RESET gpio low and wait for it to settle. */
-	pr_debug("Pulling RESET gpio low\n");
-	gpio_direction_output(mdm_drv->ap2mdm_pmic_reset_n_gpio, 0);
-	usleep_range(5000, 10000);
-
-	/* Deassert RESET first and wait for it to settle. */
-	pr_debug("%s: Pulling RESET gpio high\n", __func__);
-	gpio_direction_output(mdm_drv->ap2mdm_pmic_reset_n_gpio, 1);
-	usleep(20000);
-
-	/* Pull PWR gpio high and wait for it to settle, but only
-	 * the first time the mdm is powered up.
-	 * Some targets do not use ap2mdm_kpdpwr_n_gpio.
-	 */
-	if (power_on_count == 1) {
-		if (mdm_drv->ap2mdm_kpdpwr_n_gpio > 0) {
-			pr_debug("%s: Powering on mdm modem\n", __func__);
-			gpio_direction_output(mdm_drv->ap2mdm_kpdpwr_n_gpio, 1);
-			usleep(1000);
-		}
-	}
-	mdm_peripheral_connect(mdm_drv);
-
-	msleep(200);
-}
-
-static void power_down_mdm(struct mdm_modem_drv *mdm_drv)
-{
-	int i;
-
-	for (i = MDM_MODEM_TIMEOUT; i > 0; i -= MDM_MODEM_DELTA) {
-		pet_watchdog();
-		msleep(MDM_MODEM_DELTA);
-		if (gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0)
-			break;
-	}
-	if (i <= 0) {
-		pr_err("%s: MDM2AP_STATUS never went low.\n",
-			 __func__);
-		gpio_direction_output(mdm_drv->ap2mdm_pmic_reset_n_gpio, 0);
-
-		for (i = MDM_HOLD_TIME; i > 0; i -= MDM_MODEM_DELTA) {
-			pet_watchdog();
-			msleep(MDM_MODEM_DELTA);
-		}
-	}
-	if (mdm_drv->ap2mdm_kpdpwr_n_gpio > 0)
-		gpio_direction_output(mdm_drv->ap2mdm_kpdpwr_n_gpio, 0);
-	mdm_peripheral_disconnect(mdm_drv);
+	if (power_on_count == 1)
+		mdm_do_first_power_on(mdm_drv);
+	else
+		mdm_do_soft_power_on(mdm_drv);
 }
 
 static void debug_state_changed(int value)
@@ -157,13 +181,15 @@
 	if (value) {
 		mdm_peripheral_disconnect(mdm_drv);
 		mdm_peripheral_connect(mdm_drv);
-		gpio_direction_output(mdm_drv->ap2mdm_wakeup_gpio, 1);
+		if (mdm_drv->ap2mdm_wakeup_gpio > 0)
+			gpio_direction_output(mdm_drv->ap2mdm_wakeup_gpio, 1);
 	}
 }
 
 static struct mdm_ops mdm_cb = {
-	.power_on_mdm_cb = power_on_mdm,
-	.power_down_mdm_cb = power_down_mdm,
+	.power_on_mdm_cb = mdm_power_on_common,
+	.reset_mdm_cb = mdm_power_on_common,
+	.power_down_mdm_cb = mdm_power_down_common,
 	.debug_state_changed_cb = debug_state_changed,
 	.status_cb = mdm_status_changed,
 };
diff --git a/arch/arm/mach-msm/mdm_common.c b/arch/arm/mach-msm/mdm_common.c
index 8d99c1c..ffff782 100644
--- a/arch/arm/mach-msm/mdm_common.c
+++ b/arch/arm/mach-msm/mdm_common.c
@@ -39,6 +39,7 @@
 #include <linux/msm_charm.h>
 #include "msm_watchdog.h"
 #include "mdm_private.h"
+#include "sysmon.h"
 
 #define MDM_MODEM_TIMEOUT	6000
 #define MDM_MODEM_DELTA	100
@@ -47,6 +48,7 @@
 
 static int mdm_debug_on;
 static struct workqueue_struct *mdm_queue;
+static struct workqueue_struct *mdm_sfr_queue;
 
 #define EXTERNAL_MODEM "external_modem"
 
@@ -58,6 +60,36 @@
 
 static int first_boot = 1;
 
+#define RD_BUF_SIZE			100
+#define SFR_MAX_RETRIES		10
+#define SFR_RETRY_INTERVAL	1000
+
+static void mdm_restart_reason_fn(struct work_struct *work)
+{
+	int ret, ntries = 0;
+	char sfr_buf[RD_BUF_SIZE];
+
+	do {
+		msleep(SFR_RETRY_INTERVAL);
+		ret = sysmon_get_reason(SYSMON_SS_EXT_MODEM,
+					sfr_buf, sizeof(sfr_buf));
+		if (ret) {
+			/*
+			 * The sysmon device may not have been probed as yet
+			 * after the restart.
+			 */
+			pr_err("%s: Error retrieving mdm restart reason, ret = %d, "
+					"%d/%d tries\n", __func__, ret,
+					ntries + 1,	SFR_MAX_RETRIES);
+		} else {
+			pr_err("mdm restart reason: %s\n", sfr_buf);
+			break;
+		}
+	} while (++ntries < SFR_MAX_RETRIES);
+}
+
+static DECLARE_WORK(sfr_reason_work, mdm_restart_reason_fn);
+
 long mdm_modem_ioctl(struct file *filp, unsigned int cmd,
 				unsigned long arg)
 {
@@ -120,6 +152,14 @@
 					 (unsigned long __user *) arg);
 		INIT_COMPLETION(mdm_needs_reload);
 		break;
+	case GET_DLOAD_STATUS:
+		pr_debug("getting status of mdm2ap_errfatal_gpio\n");
+		if (gpio_get_value(mdm_drv->mdm2ap_errfatal_gpio) == 1 &&
+			!mdm_drv->mdm_ready)
+			put_user(1, (unsigned long __user *) arg);
+		else
+			put_user(0, (unsigned long __user *) arg);
+		break;
 	default:
 		pr_err("%s: invalid ioctl cmd = %d\n", __func__, _IOC_NR(cmd));
 		ret = -EINVAL;
@@ -129,31 +169,13 @@
 	return ret;
 }
 
-static void mdm_fatal_fn(struct work_struct *work)
-{
-	pr_info("%s: Reseting the mdm due to an errfatal\n", __func__);
-	subsystem_restart(EXTERNAL_MODEM);
-}
-
-static DECLARE_WORK(mdm_fatal_work, mdm_fatal_fn);
-
 static void mdm_status_fn(struct work_struct *work)
 {
 	int value = gpio_get_value(mdm_drv->mdm2ap_status_gpio);
 
-	if (!mdm_drv->mdm_ready)
-		return;
-
-	mdm_drv->ops->status_cb(mdm_drv, value);
-
 	pr_debug("%s: status:%d\n", __func__, value);
-
-	if ((value == 0)) {
-		pr_info("%s: unexpected reset external modem\n", __func__);
-		subsystem_restart(EXTERNAL_MODEM);
-	} else if (value == 1) {
-		pr_info("%s: status = 1: mdm is now ready\n", __func__);
-	}
+	if (mdm_drv->mdm_ready && mdm_drv->ops->status_cb)
+		mdm_drv->ops->status_cb(mdm_drv, value);
 }
 
 static DECLARE_WORK(mdm_status_work, mdm_status_fn);
@@ -162,7 +184,6 @@
 {
 	disable_irq_nosync(mdm_drv->mdm_errfatal_irq);
 	disable_irq_nosync(mdm_drv->mdm_status_irq);
-
 }
 
 static irqreturn_t mdm_errfatal(int irq, void *dev_id)
@@ -170,8 +191,9 @@
 	pr_debug("%s: mdm got errfatal interrupt\n", __func__);
 	if (mdm_drv->mdm_ready &&
 		(gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 1)) {
-		pr_debug("%s: scheduling work now\n", __func__);
-		queue_work(mdm_queue, &mdm_fatal_work);
+		pr_info("%s: Reseting the mdm due to an errfatal\n", __func__);
+		mdm_drv->mdm_ready = 0;
+		subsystem_restart(EXTERNAL_MODEM);
 	}
 	return IRQ_HANDLED;
 }
@@ -210,8 +232,12 @@
 		if (gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0)
 			break;
 	}
-	if (i <= 0)
+	if (i <= 0) {
 		pr_err("%s: MDM2AP_STATUS never went low\n", __func__);
+		/* Reset the modem so that it will go into download mode. */
+		if (mdm_drv && mdm_drv->ops->reset_mdm_cb)
+			mdm_drv->ops->reset_mdm_cb(mdm_drv);
+	}
 	return NOTIFY_DONE;
 }
 
@@ -221,16 +247,23 @@
 
 static irqreturn_t mdm_status_change(int irq, void *dev_id)
 {
+	int value = gpio_get_value(mdm_drv->mdm2ap_status_gpio);
+
 	pr_debug("%s: mdm sent status change interrupt\n", __func__);
-
-	queue_work(mdm_queue, &mdm_status_work);
-
+	if (value == 0 && mdm_drv->mdm_ready == 1) {
+		pr_info("%s: unexpected reset external modem\n", __func__);
+		mdm_drv->mdm_unexpected_reset_occurred = 1;
+		mdm_drv->mdm_ready = 0;
+		subsystem_restart(EXTERNAL_MODEM);
+	} else if (value == 1) {
+		pr_info("%s: status = 1: mdm is now ready\n", __func__);
+		queue_work(mdm_queue, &mdm_status_work);
+	}
 	return IRQ_HANDLED;
 }
 
 static int mdm_subsys_shutdown(const struct subsys_data *crashed_subsys)
 {
-	mdm_drv->mdm_ready = 0;
 	gpio_direction_output(mdm_drv->ap2mdm_errfatal_gpio, 1);
 	if (mdm_drv->pdata->ramdump_delay_ms > 0) {
 		/* Wait for the external modem to complete
@@ -238,7 +271,11 @@
 		 */
 		msleep(mdm_drv->pdata->ramdump_delay_ms);
 	}
-	mdm_drv->ops->power_down_mdm_cb(mdm_drv);
+	if (!mdm_drv->mdm_unexpected_reset_occurred)
+		mdm_drv->ops->reset_mdm_cb(mdm_drv);
+	else
+		mdm_drv->mdm_unexpected_reset_occurred = 0;
+
 	return 0;
 }
 
@@ -253,8 +290,13 @@
 			msecs_to_jiffies(MDM_BOOT_TIMEOUT))) {
 		mdm_drv->mdm_boot_status = -ETIMEDOUT;
 		pr_info("%s: mdm modem restart timed out.\n", __func__);
-	} else
+	} else {
 		pr_info("%s: mdm modem has been restarted\n", __func__);
+
+		/* Log the reason for the restart */
+		if (mdm_drv->pdata->sfr_query)
+			queue_work(mdm_sfr_queue, &sfr_reason_work);
+	}
 	INIT_COMPLETION(mdm_boot);
 	return mdm_drv->mdm_boot_status;
 }
@@ -275,7 +317,6 @@
 			pr_info("%s: mdm modem ramdumps completed.\n",
 					__func__);
 		INIT_COMPLETION(mdm_ram_dumps);
-		gpio_direction_output(mdm_drv->ap2mdm_errfatal_gpio, 1);
 		mdm_drv->ops->power_down_mdm_cb(mdm_drv);
 	}
 	return mdm_drv->mdm_ram_dump_status;
@@ -360,11 +401,11 @@
 	if (pres)
 		mdm_drv->ap2mdm_wakeup_gpio = pres->start;
 
-	/* AP2MDM_PMIC_RESET_N */
+	/* AP2MDM_SOFT_RESET */
 	pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
-							"AP2MDM_PMIC_RESET_N");
+							"AP2MDM_SOFT_RESET");
 	if (pres)
-		mdm_drv->ap2mdm_pmic_reset_n_gpio = pres->start;
+		mdm_drv->ap2mdm_soft_reset_gpio = pres->start;
 
 	/* AP2MDM_KPDPWR_N */
 	pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
@@ -372,6 +413,12 @@
 	if (pres)
 		mdm_drv->ap2mdm_kpdpwr_n_gpio = pres->start;
 
+	/* AP2MDM_PMIC_PWR_EN */
+	pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
+							"AP2MDM_PMIC_PWR_EN");
+	if (pres)
+		mdm_drv->ap2mdm_pmic_pwr_en_gpio = pres->start;
+
 	mdm_drv->boot_type                  = CHARM_NORMAL_BOOT;
 
 	mdm_drv->ops      = mdm_ops;
@@ -395,11 +442,18 @@
 
 	gpio_request(mdm_drv->ap2mdm_status_gpio, "AP2MDM_STATUS");
 	gpio_request(mdm_drv->ap2mdm_errfatal_gpio, "AP2MDM_ERRFATAL");
-	gpio_request(mdm_drv->ap2mdm_kpdpwr_n_gpio, "AP2MDM_KPDPWR_N");
-	gpio_request(mdm_drv->ap2mdm_pmic_reset_n_gpio, "AP2MDM_PMIC_RESET_N");
+	if (mdm_drv->ap2mdm_kpdpwr_n_gpio > 0)
+		gpio_request(mdm_drv->ap2mdm_kpdpwr_n_gpio, "AP2MDM_KPDPWR_N");
 	gpio_request(mdm_drv->mdm2ap_status_gpio, "MDM2AP_STATUS");
 	gpio_request(mdm_drv->mdm2ap_errfatal_gpio, "MDM2AP_ERRFATAL");
 
+	if (mdm_drv->ap2mdm_pmic_pwr_en_gpio > 0)
+		gpio_request(mdm_drv->ap2mdm_pmic_pwr_en_gpio,
+					 "AP2MDM_PMIC_PWR_EN");
+	if (mdm_drv->ap2mdm_soft_reset_gpio > 0)
+		gpio_request(mdm_drv->ap2mdm_soft_reset_gpio,
+					 "AP2MDM_SOFT_RESET");
+
 	if (mdm_drv->ap2mdm_wakeup_gpio > 0)
 		gpio_request(mdm_drv->ap2mdm_wakeup_gpio, "AP2MDM_WAKEUP");
 
@@ -421,6 +475,16 @@
 		goto fatal_err;
 	}
 
+	mdm_sfr_queue = alloc_workqueue("mdm_sfr_queue", 0, 0);
+	if (!mdm_sfr_queue) {
+		pr_err("%s: could not create workqueue mdm_sfr_queue."
+			" All mdm functionality will be disabled\n",
+			__func__);
+		ret = -ENOMEM;
+		destroy_workqueue(mdm_queue);
+		goto fatal_err;
+	}
+
 	atomic_notifier_chain_register(&panic_notifier_list, &mdm_panic_blk);
 	mdm_debugfs_init();
 
@@ -470,10 +534,18 @@
 	mdm_drv->mdm_status_irq = irq;
 
 status_err:
+	/*
+	 * If AP2MDM_PMIC_PWR_EN gpio is used, pull it high. It remains
+	 * high until the whole phone is shut down.
+	 */
+	if (mdm_drv->ap2mdm_pmic_pwr_en_gpio > 0)
+		gpio_direction_output(mdm_drv->ap2mdm_pmic_pwr_en_gpio, 1);
+
 	/* Perform early powerup of the external modem in order to
 	 * allow tabla devices to be found.
 	 */
-	mdm_drv->ops->power_on_mdm_cb(mdm_drv);
+	if (mdm_drv->pdata->early_power_on)
+		mdm_drv->ops->power_on_mdm_cb(mdm_drv);
 
 	pr_info("%s: Registering mdm modem\n", __func__);
 	return misc_register(&mdm_modem_misc);
@@ -481,10 +553,14 @@
 fatal_err:
 	gpio_free(mdm_drv->ap2mdm_status_gpio);
 	gpio_free(mdm_drv->ap2mdm_errfatal_gpio);
-	gpio_free(mdm_drv->ap2mdm_kpdpwr_n_gpio);
-	gpio_free(mdm_drv->ap2mdm_pmic_reset_n_gpio);
+	if (mdm_drv->ap2mdm_kpdpwr_n_gpio > 0)
+		gpio_free(mdm_drv->ap2mdm_kpdpwr_n_gpio);
+	if (mdm_drv->ap2mdm_pmic_pwr_en_gpio > 0)
+		gpio_free(mdm_drv->ap2mdm_pmic_pwr_en_gpio);
 	gpio_free(mdm_drv->mdm2ap_status_gpio);
 	gpio_free(mdm_drv->mdm2ap_errfatal_gpio);
+	if (mdm_drv->ap2mdm_soft_reset_gpio > 0)
+		gpio_free(mdm_drv->ap2mdm_soft_reset_gpio);
 
 	if (mdm_drv->ap2mdm_wakeup_gpio > 0)
 		gpio_free(mdm_drv->ap2mdm_wakeup_gpio);
@@ -502,10 +578,14 @@
 
 	gpio_free(mdm_drv->ap2mdm_status_gpio);
 	gpio_free(mdm_drv->ap2mdm_errfatal_gpio);
-	gpio_free(mdm_drv->ap2mdm_kpdpwr_n_gpio);
-	gpio_free(mdm_drv->ap2mdm_pmic_reset_n_gpio);
+	if (mdm_drv->ap2mdm_kpdpwr_n_gpio > 0)
+		gpio_free(mdm_drv->ap2mdm_kpdpwr_n_gpio);
+	if (mdm_drv->ap2mdm_pmic_pwr_en_gpio > 0)
+		gpio_free(mdm_drv->ap2mdm_pmic_pwr_en_gpio);
 	gpio_free(mdm_drv->mdm2ap_status_gpio);
 	gpio_free(mdm_drv->mdm2ap_errfatal_gpio);
+	if (mdm_drv->ap2mdm_soft_reset_gpio > 0)
+		gpio_free(mdm_drv->ap2mdm_soft_reset_gpio);
 
 	if (mdm_drv->ap2mdm_wakeup_gpio > 0)
 		gpio_free(mdm_drv->ap2mdm_wakeup_gpio);
@@ -521,5 +601,7 @@
 	mdm_disable_irqs();
 
 	mdm_drv->ops->power_down_mdm_cb(mdm_drv);
+	if (mdm_drv->ap2mdm_pmic_pwr_en_gpio > 0)
+		gpio_direction_output(mdm_drv->ap2mdm_pmic_pwr_en_gpio, 0);
 }
 
diff --git a/arch/arm/mach-msm/mdm_private.h b/arch/arm/mach-msm/mdm_private.h
index 206bd8b..f157d88 100644
--- a/arch/arm/mach-msm/mdm_private.h
+++ b/arch/arm/mach-msm/mdm_private.h
@@ -17,6 +17,7 @@
 
 struct mdm_ops {
 	void (*power_on_mdm_cb)(struct mdm_modem_drv *mdm_drv);
+	void (*reset_mdm_cb)(struct mdm_modem_drv *mdm_drv);
 	void (*normal_boot_done_cb)(struct mdm_modem_drv *mdm_drv);
 	void (*power_down_mdm_cb)(struct mdm_modem_drv *mdm_drv);
 	void (*debug_state_changed_cb)(int value);
@@ -31,8 +32,9 @@
 	unsigned ap2mdm_status_gpio;
 	unsigned mdm2ap_wakeup_gpio;
 	unsigned ap2mdm_wakeup_gpio;
-	unsigned ap2mdm_pmic_reset_n_gpio;
 	unsigned ap2mdm_kpdpwr_n_gpio;
+	unsigned ap2mdm_soft_reset_gpio;
+	unsigned ap2mdm_pmic_pwr_en_gpio;
 
 	int mdm_errfatal_irq;
 	int mdm_status_irq;
@@ -41,6 +43,7 @@
 	int mdm_ram_dump_status;
 	enum charm_boot_type boot_type;
 	int mdm_debug_on;
+	int mdm_unexpected_reset_occurred;
 
 	struct mdm_ops *ops;
 	struct mdm_platform_data *pdata;
diff --git a/arch/arm/mach-msm/memory.c b/arch/arm/mach-msm/memory.c
index ccb18b3..8898585 100644
--- a/arch/arm/mach-msm/memory.c
+++ b/arch/arm/mach-msm/memory.c
@@ -83,67 +83,29 @@
 }
 EXPORT_SYMBOL(write_to_strongly_ordered_memory);
 
-void flush_axi_bus_buffer(void)
-{
-#if defined(CONFIG_ARCH_MSM7X27) && !defined(CONFIG_ARCH_MSM7X27A)
-	__asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" \
-				    : : "r" (0) : "memory");
-	write_to_strongly_ordered_memory();
-#endif
-}
-
-#define CACHE_LINE_SIZE 32
-
-/* These cache related routines make the assumption that the associated
- * physical memory is contiguous. They will operate on all (L1
- * and L2 if present) caches.
+/* These cache related routines make the assumption (if outer cache is
+ * available) that the associated physical memory is contiguous.
+ * They will operate on all (L1 and L2 if present) caches.
  */
 void clean_and_invalidate_caches(unsigned long vstart,
 	unsigned long length, unsigned long pstart)
 {
-	unsigned long vaddr;
-
-	for (vaddr = vstart; vaddr < vstart + length; vaddr += CACHE_LINE_SIZE)
-		asm ("mcr p15, 0, %0, c7, c14, 1" : : "r" (vaddr));
-#ifdef CONFIG_OUTER_CACHE
+	dmac_flush_range((void *)vstart, (void *) (vstart + length));
 	outer_flush_range(pstart, pstart + length);
-#endif
-	asm ("mcr p15, 0, %0, c7, c10, 4" : : "r" (0));
-	asm ("mcr p15, 0, %0, c7, c5, 0" : : "r" (0));
-
-	flush_axi_bus_buffer();
 }
 
 void clean_caches(unsigned long vstart,
 	unsigned long length, unsigned long pstart)
 {
-	unsigned long vaddr;
-
-	for (vaddr = vstart; vaddr < vstart + length; vaddr += CACHE_LINE_SIZE)
-		asm ("mcr p15, 0, %0, c7, c10, 1" : : "r" (vaddr));
-#ifdef CONFIG_OUTER_CACHE
+	dmac_clean_range((void *)vstart, (void *) (vstart + length));
 	outer_clean_range(pstart, pstart + length);
-#endif
-	asm ("mcr p15, 0, %0, c7, c10, 4" : : "r" (0));
-	asm ("mcr p15, 0, %0, c7, c5, 0" : : "r" (0));
-
-	flush_axi_bus_buffer();
 }
 
 void invalidate_caches(unsigned long vstart,
 	unsigned long length, unsigned long pstart)
 {
-	unsigned long vaddr;
-
-	for (vaddr = vstart; vaddr < vstart + length; vaddr += CACHE_LINE_SIZE)
-		asm ("mcr p15, 0, %0, c7, c6, 1" : : "r" (vaddr));
-#ifdef CONFIG_OUTER_CACHE
+	dmac_inv_range((void *)vstart, (void *) (vstart + length));
 	outer_inv_range(pstart, pstart + length);
-#endif
-	asm ("mcr p15, 0, %0, c7, c10, 4" : : "r" (0));
-	asm ("mcr p15, 0, %0, c7, c5, 0" : : "r" (0));
-
-	flush_axi_bus_buffer();
 }
 
 void * __init alloc_bootmem_aligned(unsigned long size, unsigned long alignment)
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_core.h b/arch/arm/mach-msm/msm_bus/msm_bus_core.h
index e35130e..341fda8 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_core.h
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_core.h
@@ -29,6 +29,17 @@
 #define MSM_FAB_ERR(msg, ...) \
 	dev_err(&fabric->fabdev.dev, msg, ## __VA_ARGS__)
 
+#define IS_MASTER_VALID(mas) \
+	(((mas >= MSM_BUS_MASTER_FIRST) && (mas <= MSM_BUS_MASTER_LAST)) \
+	 ? 1 : 0)
+#define IS_SLAVE_VALID(slv) \
+	(((slv >= MSM_BUS_SLAVE_FIRST) && (slv <= MSM_BUS_SLAVE_LAST)) ? 1 : 0)
+
+#define INTERLEAVED_BW(fab_pdata, bw, ports) \
+	((fab_pdata->il_flag) ? DIV_ROUND_UP((bw), (ports)) : (bw))
+#define INTERLEAVED_VAL(fab_pdata, n) \
+	((fab_pdata->il_flag) ? (n) : 1)
+
 enum msm_bus_dbg_op_type {
 	MSM_BUS_DBG_UNREGISTER = -2,
 	MSM_BUS_DBG_REGISTER,
@@ -48,9 +59,12 @@
 	int *tier;
 	int num_tiers;
 	int ahb;
+	int hw_sel;
 	const char *slaveclk[NUM_CTX];
 	const char *memclk;
 	unsigned int buswidth;
+	unsigned int ws;
+	unsigned int mode;
 };
 
 struct path_node {
@@ -88,6 +102,27 @@
 	int commit_index;
 	struct nodeclk nodeclk[NUM_CTX];
 	struct nodeclk memclk;
+	void *hw_data;
+};
+
+struct msm_bus_hw_algorithm {
+	int (*allocate_commit_data)(struct msm_bus_fabric_registration
+		*fab_pdata, void **cdata, int ctx);
+	void *(*allocate_hw_data)(struct platform_device *pdev,
+		struct msm_bus_fabric_registration *fab_pdata);
+	void (*node_init)(void *hw_data, struct msm_bus_inode_info *info);
+	void (*free_commit_data)(void *cdata);
+	void (*update_bw)(struct msm_bus_inode_info *hop,
+		struct msm_bus_inode_info *info,
+		struct msm_bus_fabric_registration *fab_pdata,
+		void *sel_cdata, int *master_tiers,
+		long int add_bw);
+	void (*fill_cdata_buffer)(int *curr, char *buf, const int max_size,
+		void *cdata, int nmasters, int nslaves, int ntslaves);
+	int (*commit)(struct msm_bus_fabric_registration
+		*fab_pdata, void *hw_data, void **cdata);
+	int (*port_unhalt)(uint32_t haltid, uint8_t mport);
+	int (*port_halt)(uint32_t haltid, uint8_t mport);
 };
 
 struct msm_bus_fabric_device {
@@ -96,6 +131,7 @@
 	struct device dev;
 	const struct msm_bus_fab_algorithm *algo;
 	const struct msm_bus_board_algorithm *board_algo;
+	struct msm_bus_hw_algorithm hw_algo;
 	int visited;
 };
 #define to_msm_bus_fabric_device(d) container_of(d, \
@@ -150,22 +186,17 @@
 struct msm_bus_fabric_device *msm_bus_get_fabric_device(int fabid);
 int msm_bus_get_num_fab(void);
 
-int allocate_commit_data(struct msm_bus_fabric_registration *fab_pdata,
-	void **cdata);
-struct msm_rpm_iv_pair *allocate_rpm_data(struct msm_bus_fabric_registration
-	*fab_pdata);
-int msm_bus_rpm_commit(struct msm_bus_fabric_registration
-	*fab_pdata, struct msm_rpm_iv_pair *rpm_data, void **cdata);
-void free_commit_data(void *cdata);
-void msm_bus_rpm_update_bw(struct msm_bus_inode_info *hop,
-	struct msm_bus_inode_info *info,
-	struct msm_bus_fabric_registration *fab_pdata,
-	void *sel_cdata, int *master_tiers,
-	long int add_bw);
 void msm_bus_rpm_fill_cdata_buffer(int *curr, char *buf, const int max_size,
 	void *cdata, int nmasters, int nslaves, int ntslaves);
-bool msm_bus_rpm_is_mem_interleaved(void);
 
+int msm_bus_hw_fab_init(struct msm_bus_fabric_registration *pdata,
+	struct msm_bus_hw_algorithm *hw_algo);
+int msm_bus_rpm_hw_init(struct msm_bus_fabric_registration *pdata,
+	struct msm_bus_hw_algorithm *hw_algo);
+int msm_bus_noc_hw_init(struct msm_bus_fabric_registration *pdata,
+	struct msm_bus_hw_algorithm *hw_algo);
+int msm_bus_bimc_hw_init(struct msm_bus_fabric_registration *pdata,
+	struct msm_bus_hw_algorithm *hw_algo);
 #if defined(CONFIG_DEBUG_FS) && defined(CONFIG_MSM_BUS_SCALING)
 void msm_bus_dbg_client_data(struct msm_bus_scale_pdata *pdata, int index,
 	uint32_t cl);
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
index 64fd03e..8c015d1 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
@@ -20,7 +20,7 @@
 #include <linux/clk.h>
 #include <linux/radix-tree.h>
 #include <mach/board.h>
-#include <mach/rpm.h>
+#include <mach/socinfo.h>
 #include "msm_bus_core.h"
 
 enum {
@@ -43,9 +43,8 @@
 	int num_nodes;
 	struct list_head gateways;
 	struct msm_bus_inode_info info;
-	const struct msm_bus_fab_algorithm *algo;
 	struct msm_bus_fabric_registration *pdata;
-	struct msm_rpm_iv_pair *rpm_data;
+	void *hw_data;
 };
 #define to_msm_bus_fabric(d) container_of(d, \
 	struct msm_bus_fabric, d)
@@ -117,18 +116,26 @@
 /**
  * register_fabric_info() - Create the internal fabric structure and
  * build the topology tree from platform specific data
- *
+ * @pdev: Platform device for getting base addresses
  * @fabric: Fabric to which the gateways, nodes should be added
  *
  * This function is called from probe. Iterates over the platform data,
  * and builds the topology
  */
-static int register_fabric_info(struct msm_bus_fabric *fabric)
+static int register_fabric_info(struct platform_device *pdev,
+	struct msm_bus_fabric *fabric)
 {
-	int i, ret = 0, err = 0;
+	int i = 0, ret = 0, err = 0;
 
 	MSM_BUS_DBG("id:%d pdata-id: %d len: %d\n", fabric->fabdev.id,
 		fabric->pdata->id, fabric->pdata->len);
+	fabric->hw_data = fabric->fabdev.hw_algo.allocate_hw_data(pdev,
+		fabric->pdata);
+	if (ZERO_OR_NULL_PTR(fabric->hw_data)) {
+		MSM_BUS_ERR("Couldn't allocate hw_data for fab: %d\n",
+			fabric->fabdev.id);
+		goto error;
+	}
 
 	for (i = 0; i < fabric->pdata->len; i++) {
 		struct msm_bus_inode_info *info;
@@ -177,9 +184,16 @@
 			kfree(info);
 			goto error;
 		}
-	}
 
-	fabric->rpm_data = allocate_rpm_data(fabric->pdata);
+		if (fabric->fabdev.hw_algo.node_init == NULL)
+			continue;
+
+		fabric->fabdev.hw_algo.node_init(fabric->hw_data, info);
+		if (ret) {
+			MSM_BUS_ERR("Unable to init node info, ret: %d\n", ret);
+			kfree(info);
+		}
+	}
 
 	MSM_BUS_DBG("Fabric: %d nmasters: %d nslaves: %d\n"
 		" ntieredslaves: %d, rpm_enabled: %d\n",
@@ -323,6 +337,10 @@
 	struct msm_bus_fabric *fabric = to_msm_bus_fabric(fabdev);
 	void *sel_cdata;
 
+	/* Temporarily stub out arbitration settings for copper */
+	if (machine_is_copper())
+		return;
+
 	sel_cdata = fabric->cdata[ctx];
 
 	/* If it's an ahb fabric, don't calculate arb values */
@@ -335,7 +353,7 @@
 		return;
 	}
 
-	msm_bus_rpm_update_bw(hop, info, fabric->pdata, sel_cdata,
+	fabdev->hw_algo.update_bw(hop, info, fabric->pdata, sel_cdata,
 		master_tiers, add_bw);
 	fabric->arb_dirty = true;
 }
@@ -416,10 +434,10 @@
 }
 
 /**
- * msm_bus_fabric_rpm_commit() - Commit the arbitration data to RPM
+ * msm_bus_fabric_hw_commit() - Commit the arbitration data to Hardware.
  * @fabric: Fabric for which the data should be committed
  * */
-static int msm_bus_fabric_rpm_commit(struct msm_bus_fabric_device *fabdev)
+static int msm_bus_fabric_hw_commit(struct msm_bus_fabric_device *fabdev)
 {
 	int status = 0;
 	struct msm_bus_fabric *fabric = to_msm_bus_fabric(fabdev);
@@ -439,7 +457,7 @@
 		goto skip_arb;
 	}
 
-	status = msm_bus_rpm_commit(fabric->pdata, fabric->rpm_data,
+	status = fabdev->hw_algo.commit(fabric->pdata, fabric->hw_data,
 		(void **)fabric->cdata);
 	if (status)
 		MSM_BUS_DBG("Error committing arb data for fabric: %d\n",
@@ -466,12 +484,9 @@
  */
 int msm_bus_fabric_port_halt(struct msm_bus_fabric_device *fabdev, int iid)
 {
-	struct msm_bus_halt_vector hvector = {0, 0};
-	struct msm_rpm_iv_pair rpm_data[2];
 	struct msm_bus_inode_info *info = NULL;
 	uint8_t mport;
 	uint32_t haltid = 0;
-	int status = 0;
 	struct msm_bus_fabric *fabric = to_msm_bus_fabric(fabdev);
 
 	info = fabdev->algo->find_node(fabdev, iid);
@@ -482,23 +497,8 @@
 
 	haltid = fabric->pdata->haltid;
 	mport = info->node_info->masterp[0];
-	MSM_BUS_MASTER_HALT(hvector.haltmask, hvector.haltval, mport);
-	rpm_data[0].id = haltid;
-	rpm_data[0].value = hvector.haltval;
-	rpm_data[1].id = haltid + 1;
-	rpm_data[1].value = hvector.haltmask;
 
-	MSM_BUS_DBG("ctx: %d, id: %d, value: %d\n",
-		MSM_RPM_CTX_SET_0, rpm_data[0].id, rpm_data[0].value);
-	MSM_BUS_DBG("ctx: %d, id: %d, value: %d\n",
-		MSM_RPM_CTX_SET_0, rpm_data[1].id, rpm_data[1].value);
-
-	if (fabric->pdata->rpm_enabled)
-		status = msm_rpm_set(MSM_RPM_CTX_SET_0, rpm_data, 2);
-	if (status)
-		MSM_BUS_DBG("msm_rpm_set returned: %d\n", status);
-
-	return status;
+	return fabdev->hw_algo.port_halt(haltid, mport);
 }
 
 /**
@@ -508,12 +508,9 @@
  */
 int msm_bus_fabric_port_unhalt(struct msm_bus_fabric_device *fabdev, int iid)
 {
-	struct msm_bus_halt_vector hvector = {0, 0};
-	struct msm_rpm_iv_pair rpm_data[2];
 	struct msm_bus_inode_info *info = NULL;
 	uint8_t mport;
 	uint32_t haltid = 0;
-	int status = 0;
 	struct msm_bus_fabric *fabric = to_msm_bus_fabric(fabdev);
 
 	info = fabdev->algo->find_node(fabdev, iid);
@@ -524,24 +521,7 @@
 
 	haltid = fabric->pdata->haltid;
 	mport = info->node_info->masterp[0];
-	MSM_BUS_MASTER_UNHALT(hvector.haltmask, hvector.haltval,
-		mport);
-	rpm_data[0].id = haltid;
-	rpm_data[0].value = hvector.haltval;
-	rpm_data[1].id = haltid + 1;
-	rpm_data[1].value = hvector.haltmask;
-
-	MSM_BUS_DBG("unalt: ctx: %d, id: %d, value: %d\n",
-		MSM_RPM_CTX_SET_SLEEP, rpm_data[0].id, rpm_data[0].value);
-	MSM_BUS_DBG("unhalt: ctx: %d, id: %d, value: %d\n",
-		MSM_RPM_CTX_SET_SLEEP, rpm_data[1].id, rpm_data[1].value);
-
-	if (fabric->pdata->rpm_enabled)
-		status = msm_rpm_set(MSM_RPM_CTX_SET_0, rpm_data, 2);
-	if (status)
-		MSM_BUS_DBG("msm_rpm_set returned: %d\n", status);
-
-	return status;
+	return fabdev->hw_algo.port_unhalt(haltid, mport);
 }
 
 /**
@@ -604,12 +584,25 @@
 	.update_bw = msm_bus_fabric_update_bw,
 	.port_halt = msm_bus_fabric_port_halt,
 	.port_unhalt = msm_bus_fabric_port_unhalt,
-	.commit = msm_bus_fabric_rpm_commit,
+	.commit = msm_bus_fabric_hw_commit,
 	.find_node = msm_bus_fabric_find_node,
 	.find_gw_node = msm_bus_fabric_find_gw_node,
 	.get_gw_list = msm_bus_fabric_get_gw_list,
 };
 
+static int msm_bus_fabric_hw_init(struct msm_bus_fabric_registration *pdata,
+	struct msm_bus_hw_algorithm *hw_algo)
+{
+	int ret = 0;
+	ret = msm_bus_rpm_hw_init(pdata, hw_algo);
+	if (ret) {
+		MSM_BUS_ERR("RPM initialization failed\n");
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
 static int msm_bus_fabric_probe(struct platform_device *pdev)
 {
 	int ctx, ret = 0;
@@ -647,7 +640,13 @@
 	pdata = (struct msm_bus_fabric_registration *)pdev->dev.platform_data;
 	fabric->fabdev.name = pdata->name;
 	fabric->fabdev.algo = &msm_bus_algo;
-	pdata->il_flag = msm_bus_rpm_is_mem_interleaved();
+	ret = msm_bus_fabric_hw_init(pdata, &fabric->fabdev.hw_algo);
+	if (ret) {
+		MSM_BUS_ERR("Error initializing hardware for fabric: %d\n",
+			fabric->fabdev.id);
+		goto err;
+	}
+
 	fabric->ahb = pdata->ahb;
 	fabric->pdata = pdata;
 	fabric->pdata->board_algo->assign_iids(fabric->pdata,
@@ -681,7 +680,7 @@
 	}
 
 	/* Find num. of slaves, masters, populate gateways, radix tree */
-	ret = register_fabric_info(fabric);
+	ret = register_fabric_info(pdev, fabric);
 	if (ret) {
 		MSM_BUS_ERR("Could not register fabric %d info, ret: %d\n",
 			fabric->fabdev.id, ret);
@@ -690,8 +689,8 @@
 	if (!fabric->ahb) {
 		/* Allocate memory for commit data */
 		for (ctx = 0; ctx < NUM_CTX; ctx++) {
-			ret = allocate_commit_data(fabric->pdata, &fabric->
-				cdata[ctx]);
+			ret = fabric->fabdev.hw_algo.allocate_commit_data(
+				fabric->pdata, &fabric->cdata[ctx], ctx);
 			if (ret) {
 				MSM_BUS_ERR("Failed to alloc commit data for "
 					"fab: %d, ret = %d\n",
@@ -726,12 +725,12 @@
 		fabric->pdata->nslaves; i++)
 		radix_tree_delete(&fabric->fab_tree, i);
 	if (!fabric->ahb) {
-		free_commit_data(fabric->cdata[DUAL_CTX]);
-		free_commit_data(fabric->cdata[ACTIVE_CTX]);
+		fabdev->hw_algo.free_commit_data(fabric->cdata[DUAL_CTX]);
+		fabdev->hw_algo.free_commit_data(fabric->cdata[ACTIVE_CTX]);
 	}
 
 	kfree(fabric->info.node_info);
-	kfree(fabric->rpm_data);
+	kfree(fabric->hw_data);
 	kfree(fabric);
 	return ret;
 }
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_rpm.c b/arch/arm/mach-msm/msm_bus/msm_bus_rpm.c
index b13037e..4653431 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_rpm.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_rpm.c
@@ -24,11 +24,6 @@
 #include "msm_bus_core.h"
 #include "../rpm_resources.h"
 
-#define INTERLEAVED_BW(fab_pdata, bw, ports) \
-	((fab_pdata->il_flag) ? ((bw) / (ports)) : (bw))
-#define INTERLEAVED_VAL(fab_pdata, n) \
-	((fab_pdata->il_flag) ? (n) : 1)
-
 void msm_bus_rpm_set_mt_mask()
 {
 #ifdef CONFIG_MSM_BUS_RPM_MULTI_TIER_ENABLED
@@ -115,7 +110,7 @@
 #define BW_VAL_FROM_BYTES(bw) \
 	((((bw) >> 17) & 0x8000) ? 0x7FFF : ((bw) >> 17))
 
-uint32_t msm_bus_set_bw_bytes(unsigned long bw)
+static uint32_t msm_bus_set_bw_bytes(unsigned long bw)
 {
 	return ((((bw) & 0x1FFFF) && (((bw) >> 17) == 0)) ?
 		ROUNDED_BW_VAL_FROM_BYTES(bw) : BW_VAL_FROM_BYTES(bw));
@@ -132,7 +127,8 @@
 	return (val)&0x7FFF;
 }
 
-uint16_t msm_bus_create_bw_tier_pair_bytes(uint8_t type, unsigned long bw)
+static uint16_t msm_bus_create_bw_tier_pair_bytes(uint8_t type,
+	unsigned long bw)
 {
 	return ((((type) == MSM_BUS_BW_TIER1 ? 1 : 0) << 15) |
 	 (msm_bus_set_bw_bytes(bw)));
@@ -168,8 +164,8 @@
  * format specified by RPM
  * @fabric: Fabric device for which commit data is allocated
  */
-int allocate_commit_data(struct msm_bus_fabric_registration *fab_pdata,
-	void **cdata)
+static int msm_bus_rpm_allocate_commit_data(struct msm_bus_fabric_registration
+	*fab_pdata, void **cdata, int ctx)
 {
 	struct commit_data **cd = (struct commit_data **)cdata;
 	*cd = kzalloc(sizeof(struct commit_data), GFP_KERNEL);
@@ -209,7 +205,7 @@
 	return 0;
 }
 
-void free_commit_data(void *cdata)
+static void free_commit_data(void *cdata)
 {
 	struct commit_data *cd = (struct commit_data *)cdata;
 
@@ -223,8 +219,8 @@
  * allocate_rpm_data() - Allocate the id-value pairs to be
  * sent to RPM
  */
-struct msm_rpm_iv_pair *allocate_rpm_data(struct msm_bus_fabric_registration
-	*fab_pdata)
+static void *msm_bus_rpm_allocate_rpm_data(struct platform_device *pdev,
+	struct msm_bus_fabric_registration *fab_pdata)
 {
 	struct msm_rpm_iv_pair *rpm_data;
 	uint16_t count = ((fab_pdata->nmasters * fab_pdata->ntieredslaves) +
@@ -232,14 +228,14 @@
 
 	rpm_data = kmalloc((sizeof(struct msm_rpm_iv_pair) * count),
 		GFP_KERNEL);
-	return rpm_data;
+	return (void *)rpm_data;
 }
 
 #define BWMASK 0x7FFF
 #define TIERMASK 0x8000
 #define GET_TIER(n) (((n) & TIERMASK) >> 15)
 
-void msm_bus_rpm_update_bw(struct msm_bus_inode_info *hop,
+static void msm_bus_rpm_update_bw(struct msm_bus_inode_info *hop,
 	struct msm_bus_inode_info *info,
 	struct msm_bus_fabric_registration *fab_pdata,
 	void *sel_cdata, int *master_tiers,
@@ -469,7 +465,7 @@
 #define MODE1_IMM(val)	((val) & 0x7F)
 #define __CLZ(x) ((8 * sizeof(uint32_t)) - 1 - __fls(x))
 
-uint8_t msm_bus_set_bw_bytes(unsigned long val)
+static uint8_t msm_bus_set_bw_bytes(unsigned long val)
 {
 	unsigned int shift;
 	unsigned int intVal;
@@ -524,7 +520,8 @@
 	return msm_bus_get_bw(val) << 20;
 }
 
-uint8_t msm_bus_create_bw_tier_pair_bytes(uint8_t type, unsigned long bw)
+static uint8_t msm_bus_create_bw_tier_pair_bytes(uint8_t type,
+	unsigned long bw)
 {
 	return msm_bus_set_bw_bytes(bw);
 };
@@ -534,14 +531,14 @@
 	return msm_bus_create_bw_tier_pair_bytes(type, bw);
 };
 
-int allocate_commit_data(struct msm_bus_fabric_registration *fab_pdata,
-	void **cdata)
+static int msm_bus_rpm_allocate_commit_data(struct msm_bus_fabric_registration
+	*fab_pdata, void **cdata, int ctx)
 {
 	struct commit_data **cd = (struct commit_data **)cdata;
 	int i;
 
 	*cd = kzalloc(sizeof(struct commit_data), GFP_KERNEL);
-	if (!*cdata) {
+	if (!*cd) {
 		MSM_BUS_DBG("Couldn't alloc mem for cdata\n");
 		goto cdata_err;
 	}
@@ -589,7 +586,7 @@
 	return -ENOMEM;
 }
 
-void free_commit_data(void *cdata)
+static void free_commit_data(void *cdata)
 {
 	int i;
 	struct commit_data *cd = (struct commit_data *)cdata;
@@ -601,8 +598,8 @@
 	kfree(cd);
 }
 
-struct msm_rpm_iv_pair *allocate_rpm_data(struct msm_bus_fabric_registration
-	*fab_pdata)
+static void *msm_bus_rpm_allocate_rpm_data(struct platform_device *pdev,
+	struct msm_bus_fabric_registration *fab_pdata)
 {
 	struct msm_rpm_iv_pair *rpm_data;
 	uint16_t count = (((fab_pdata->nmasters * fab_pdata->ntieredslaves *
@@ -610,7 +607,7 @@
 
 	rpm_data = kmalloc((sizeof(struct msm_rpm_iv_pair) * count),
 		GFP_KERNEL);
-	return rpm_data;
+	return (void *)rpm_data;
 }
 
 static int msm_bus_rpm_compare_cdata(
@@ -750,12 +747,12 @@
 	-(msm_bus_get_bw_bytes(msm_bus_create_bw_tier_pair_bytes(0, -(x)))) : \
 	(msm_bus_get_bw_bytes(msm_bus_create_bw_tier_pair_bytes(0, x))))
 
-uint16_t msm_bus_pack_bwsum_bytes(unsigned long bw)
+static uint16_t msm_bus_pack_bwsum_bytes(unsigned long bw)
 {
 	return (bw + ((1 << 20) - 1)) >> 20;
 };
 
-void msm_bus_rpm_update_bw(struct msm_bus_inode_info *hop,
+static void msm_bus_rpm_update_bw(struct msm_bus_inode_info *hop,
 	struct msm_bus_inode_info *info,
 	struct msm_bus_fabric_registration *fab_pdata,
 	void *sel_cdata, int *master_tiers,
@@ -862,14 +859,14 @@
 * msm_bus_rpm_commit() - Commit the arbitration data to RPM
 * @fabric: Fabric for which the data should be committed
 **/
-int msm_bus_rpm_commit(struct msm_bus_fabric_registration
-	*fab_pdata, struct msm_rpm_iv_pair *rpm_data,
-	void **cdata)
+static int msm_bus_rpm_commit(struct msm_bus_fabric_registration
+	*fab_pdata, void *hw_data, void **cdata)
 {
 
 	int ret;
 	bool valid;
 	struct commit_data *dual_cd, *act_cd;
+	struct msm_rpm_iv_pair *rpm_data = (struct msm_rpm_iv_pair *)hw_data;
 	dual_cd = (struct commit_data *)cdata[DUAL_CTX];
 	act_cd = (struct commit_data *)cdata[ACTIVE_CTX];
 
@@ -901,3 +898,67 @@
 
 	return ret;
 }
+
+static int msm_bus_rpm_port_halt(uint32_t haltid, uint8_t mport)
+{
+	int status = 0;
+	struct msm_bus_halt_vector hvector = {0, 0};
+	struct msm_rpm_iv_pair rpm_data[2];
+
+	MSM_BUS_MASTER_HALT(hvector.haltmask, hvector.haltval, mport);
+	rpm_data[0].id = haltid;
+	rpm_data[0].value = hvector.haltval;
+	rpm_data[1].id = haltid + 1;
+	rpm_data[1].value = hvector.haltmask;
+
+	MSM_BUS_DBG("ctx: %d, id: %d, value: %d\n",
+		MSM_RPM_CTX_SET_0, rpm_data[0].id, rpm_data[0].value);
+	MSM_BUS_DBG("ctx: %d, id: %d, value: %d\n",
+		MSM_RPM_CTX_SET_0, rpm_data[1].id, rpm_data[1].value);
+
+	status = msm_rpm_set(MSM_RPM_CTX_SET_0, rpm_data, 2);
+	if (status)
+		MSM_BUS_DBG("msm_rpm_set returned: %d\n", status);
+	return status;
+}
+
+static int msm_bus_rpm_port_unhalt(uint32_t haltid, uint8_t mport)
+{
+	int status = 0;
+	struct msm_bus_halt_vector hvector = {0, 0};
+	struct msm_rpm_iv_pair rpm_data[2];
+
+	MSM_BUS_MASTER_UNHALT(hvector.haltmask, hvector.haltval,
+		mport);
+	rpm_data[0].id = haltid;
+	rpm_data[0].value = hvector.haltval;
+	rpm_data[1].id = haltid + 1;
+	rpm_data[1].value = hvector.haltmask;
+
+	MSM_BUS_DBG("unalt: ctx: %d, id: %d, value: %d\n",
+		MSM_RPM_CTX_SET_SLEEP, rpm_data[0].id, rpm_data[0].value);
+	MSM_BUS_DBG("unhalt: ctx: %d, id: %d, value: %d\n",
+		MSM_RPM_CTX_SET_SLEEP, rpm_data[1].id, rpm_data[1].value);
+
+	status = msm_rpm_set(MSM_RPM_CTX_SET_0, rpm_data, 2);
+	if (status)
+		MSM_BUS_DBG("msm_rpm_set returned: %d\n", status);
+	return status;
+}
+
+int msm_bus_rpm_hw_init(struct msm_bus_fabric_registration *pdata,
+	struct msm_bus_hw_algorithm *hw_algo)
+{
+	pdata->il_flag = msm_bus_rpm_is_mem_interleaved();
+	hw_algo->allocate_commit_data = msm_bus_rpm_allocate_commit_data;
+	hw_algo->allocate_hw_data = msm_bus_rpm_allocate_rpm_data;
+	hw_algo->node_init = NULL;
+	hw_algo->free_commit_data = free_commit_data;
+	hw_algo->update_bw = msm_bus_rpm_update_bw;
+	hw_algo->commit = msm_bus_rpm_commit;
+	hw_algo->port_halt = msm_bus_rpm_port_halt;
+	hw_algo->port_unhalt = msm_bus_rpm_port_unhalt;
+	if (!pdata->ahb)
+		pdata->rpm_enabled = 1;
+	return 0;
+}
diff --git a/arch/arm/mach-msm/msm_cache_dump.c b/arch/arm/mach-msm/msm_cache_dump.c
index b21412f..9759d5a 100644
--- a/arch/arm/mach-msm/msm_cache_dump.c
+++ b/arch/arm/mach-msm/msm_cache_dump.c
@@ -31,13 +31,12 @@
 static unsigned long msm_cache_dump_addr;
 
 /*
- * These are dummy pointers so the defintion of l1_cache_dump
- * and l2_cache_dump don't get optimized away. If they aren't
- * referenced, the structure definitions don't show up in the
- * debugging information which is needed for post processing.
+ * These should not actually be dereferenced. There's no
+ * need for a virtual mapping, but the physical address is
+ * necessary.
  */
-static struct l1_cache_dump __used *l1_dump;
-static struct l2_cache_dump __used *l2_dump;
+static struct l1_cache_dump *l1_dump;
+static struct l2_cache_dump *l2_dump;
 
 static int msm_cache_dump_panic(struct notifier_block *this,
 				unsigned long event, void *ptr)
@@ -96,6 +95,8 @@
 		pr_err("%s: could not register L1 buffer ret = %d.\n",
 			__func__, ret);
 
+	l1_dump = (struct l1_cache_dump *)msm_cache_dump_addr;
+
 #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;
@@ -110,6 +111,9 @@
 	__raw_writel(msm_cache_dump_addr + d->l1_size,
 			MSM_IMEM_BASE + L2_DUMP_OFFSET);
 
+
+	l2_dump = (struct l2_cache_dump *)(msm_cache_dump_addr + d->l1_size);
+
 	atomic_notifier_chain_register(&panic_notifier_list,
 						&msm_cache_dump_blk);
 	return 0;
diff --git a/arch/arm/mach-msm/msm_dsps.c b/arch/arm/mach-msm/msm_dsps.c
index 057665b..3b52a9f 100644
--- a/arch/arm/mach-msm/msm_dsps.c
+++ b/arch/arm/mach-msm/msm_dsps.c
@@ -15,6 +15,8 @@
  *
  */
 
+#include <asm/atomic.h>
+
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/module.h>
@@ -39,10 +41,11 @@
 #include <mach/subsystem_restart.h>
 #include <mach/subsystem_notif.h>
 
+#include "ramdump.h"
 #include "timer.h"
 
 #define DRV_NAME	"msm_dsps"
-#define DRV_VERSION	"3.02"
+#define DRV_VERSION	"4.00"
 
 #define PPSS_PAUSE_REG	0x1804
 
@@ -58,8 +61,15 @@
  *  @cdev - character device for user interface.
  *  @pdata - platform data.
  *  @pil - handle to DSPS Firmware loader.
+ *  @dspsfw_ramdump_dev - handle to ramdump device for DSPS
+ *  @dspsfw_ramdump_segments - Ramdump segment information for DSPS
+ *  @smem_ramdump_dev - handle to ramdump device for smem
+ *  @smem_ramdump_segments - Ramdump segment information for smem
  *  @is_on - DSPS is on.
  *  @ref_count - open/close reference count.
+ *  @wdog_irq - DSPS Watchdog IRQ
+ *  @wd_crash - Watchdog ISR fired
+ *  @crash_in_progress - 1 if crash recovery is in progress
  *  @ppss_base - ppss registers virtual base address.
  */
 struct dsps_drv {
@@ -73,9 +83,18 @@
 
 	void *pil;
 
+	void *dspsfw_ramdump_dev;
+	struct ramdump_segment dspsfw_ramdump_segments[4];
+
+	void *smem_ramdump_dev;
+	struct ramdump_segment smem_ramdump_segments[1];
+
 	int is_on;
 	int ref_count;
+	int wdog_irq;
 
+	atomic_t wd_crash;
+	atomic_t crash_in_progress;
 	void __iomem *ppss_base;
 };
 
@@ -89,8 +108,7 @@
  */
 static int dsps_crash_shutdown_g;
 
-
-static void dsps_fatal_handler(struct work_struct *work);
+static void dsps_restart_handler(struct work_struct *work);
 
 /**
  *  Load DSPS Firmware.
@@ -360,7 +378,7 @@
 	return 0;
 }
 
-static DECLARE_WORK(dsps_fatal_work, dsps_fatal_handler);
+static DECLARE_WORK(dsps_fatal_work, dsps_restart_handler);
 
 /**
  *  Watchdog interrupt handler
@@ -369,6 +387,7 @@
 static irqreturn_t dsps_wdog_bite_irq(int irq, void *dev_id)
 {
 	pr_debug("%s\n", __func__);
+	atomic_set(&drv->wd_crash, 1);
 	(void)schedule_work(&dsps_fatal_work);
 	disable_irq_nosync(irq);
 	return IRQ_HANDLED;
@@ -406,7 +425,7 @@
 		ret = put_user(val, (u32 __user *) arg);
 		break;
 	case DSPS_IOCTL_RESET:
-		dsps_fatal_handler(NULL);
+		dsps_restart_handler(NULL);
 		ret = 0;
 		break;
 	default:
@@ -498,21 +517,52 @@
 	ppss_wdog = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
 						"ppss_wdog");
 	if (ppss_wdog) {
-		ret = request_irq(ppss_wdog->start, dsps_wdog_bite_irq,
+		drv->wdog_irq = ppss_wdog->start;
+		ret = request_irq(drv->wdog_irq, dsps_wdog_bite_irq,
 				  IRQF_TRIGGER_RISING, "dsps_wdog", NULL);
 		if (ret) {
 			pr_err("%s: request_irq fail %d\n", __func__, ret);
 			goto request_irq_err;
 		}
 	} else {
+		drv->wdog_irq = -1;
 		pr_debug("%s: ppss_wdog not supported.\n", __func__);
 	}
 
+	drv->dspsfw_ramdump_segments[0].address = drv->pdata->tcm_code_start;
+	drv->dspsfw_ramdump_segments[0].size =  drv->pdata->tcm_code_size;
+	drv->dspsfw_ramdump_segments[1].address = drv->pdata->tcm_buf_start;
+	drv->dspsfw_ramdump_segments[1].size =  drv->pdata->tcm_buf_size;
+	drv->dspsfw_ramdump_segments[2].address = drv->pdata->pipe_start;
+	drv->dspsfw_ramdump_segments[2].size =  drv->pdata->pipe_size;
+	drv->dspsfw_ramdump_segments[3].address = drv->pdata->ddr_start;
+	drv->dspsfw_ramdump_segments[3].size =  drv->pdata->ddr_size;
+
+	drv->dspsfw_ramdump_dev = create_ramdump_device("dsps");
+	if (!drv->dspsfw_ramdump_dev) {
+		pr_err("%s: create_ramdump_device(\"dsps\") fail\n",
+			      __func__);
+		goto create_ramdump_err;
+	}
+
+	drv->smem_ramdump_segments[0].address = drv->pdata->smem_start;
+	drv->smem_ramdump_segments[0].size =  drv->pdata->smem_size;
+	drv->smem_ramdump_dev = create_ramdump_device("smem");
+	if (!drv->smem_ramdump_dev) {
+		pr_err("%s: create_ramdump_device(\"smem\") fail\n",
+		       __func__);
+		goto create_ramdump_err;
+	}
+
 	if (drv->pdata->init)
 		drv->pdata->init(drv->pdata);
 
 	return 0;
 
+create_ramdump_err:
+	disable_irq_nosync(drv->wdog_irq);
+	free_irq(drv->wdog_irq, NULL);
+
 request_irq_err:
 	iounmap(drv->ppss_base);
 
@@ -600,6 +650,8 @@
 		}
 	}
 
+	free_irq(drv->wdog_irq, NULL);
+
 	iounmap(drv->ppss_base);
 }
 
@@ -646,22 +698,42 @@
  *  Fatal error handler
  *  Resets DSPS.
  */
-static void dsps_fatal_handler(struct work_struct *work)
+static void dsps_restart_handler(struct work_struct *work)
 {
 	uint32_t dsps_state;
+	int restart_level;
+	char *smem_reset_reason;
+	unsigned smem_reset_size;
+	const char dflt_reason[] = "Died too early due to unknown reason";
 
 	dsps_state = smsm_get_state(SMSM_DSPS_STATE);
+	restart_level = get_restart_level();
 
-	pr_debug("%s: DSPS state 0x%x\n", __func__, dsps_state);
+	pr_debug("%s: DSPS state 0x%x. Restart lvl %d\n",
+		__func__, dsps_state, restart_level);
 
-	if (dsps_state & SMSM_RESET) {
-		pr_err("%s: DSPS fatal error detected. Resetting\n",
+	if ((dsps_state & SMSM_RESET) ||
+	    (atomic_read(&drv->wd_crash) == 1)) {
+		smem_reset_reason = smem_get_entry(SMEM_SSR_REASON_DSPS0,
+			&smem_reset_size);
+		if (smem_reset_reason != NULL && smem_reset_reason[0] != 0) {
+			smem_reset_reason[smem_reset_size-1] = 0;
+			pr_err("%s: DSPS failure: %s\nResetting DSPS\n",
+				__func__, smem_reset_reason);
+			memset(smem_reset_reason, 0, smem_reset_size);
+			wmb();
+		} else
+			pr_err("%s: DSPS failure: %s\nResetting DSPS\n",
+				__func__, dflt_reason);
+	} else
+		pr_err("%s: User-initiated DSPS reset.\nResetting DSPS\n",
 		       __func__);
-		panic("DSPS fatal error detected.");
+
+	if (atomic_add_return(1, &drv->crash_in_progress) > 1) {
+		pr_err("%s: DSPS already resetting. Count %d\n", __func__,
+		       atomic_read(&drv->crash_in_progress));
 	} else {
-		pr_debug("%s: User-initiated DSPS reset. Resetting\n",
-			 __func__);
-		panic("User-initiated DSPS reset.");
+		subsystem_restart("dsps");
 	}
 }
 
@@ -680,13 +752,8 @@
 		dsps_crash_shutdown_g = 0;
 		return;
 	}
-
-	if (new_state & SMSM_RESET) {
-		pr_err
-		    ("%s: SMSM_RESET state detected. restarting the DSPS\n",
-		     __func__);
-		panic("SMSM_RESET state detected.");
-	}
+	if (new_state & SMSM_RESET)
+		dsps_restart_handler(NULL);
 }
 
 /**
@@ -697,7 +764,9 @@
 static int dsps_shutdown(const struct subsys_data *subsys)
 {
 	pr_debug("%s\n", __func__);
-	dsps_unload();
+	dsps_suspend();
+	pil_force_shutdown(drv->pdata->pil_name);
+	dsps_power_off_handler();
 	return 0;
 }
 
@@ -709,11 +778,14 @@
 static int dsps_powerup(const struct subsys_data *subsys)
 {
 	pr_debug("%s\n", __func__);
-	if (dsps_load(drv->pdata->pil_name) != 0) {
-		pr_err("%s: fail to restart DSPS after reboot\n",
-		       __func__);
-		return 1;
+	dsps_power_on_handler();
+	pil_force_boot(drv->pdata->pil_name);
+	atomic_set(&drv->crash_in_progress, 0);
+	if (atomic_read(&drv->wd_crash) > 0) {
+		atomic_set(&drv->wd_crash, 0);
+		enable_irq(drv->wdog_irq);
 	}
+	dsps_resume();
 	return 0;
 }
 
@@ -736,8 +808,34 @@
  */
 static int dsps_ramdump(int enable, const struct subsys_data *subsys)
 {
+	int ret = 0;
 	pr_debug("%s\n", __func__);
-	return 0;
+
+	if (enable) {
+		if (drv->dspsfw_ramdump_dev != NULL) {
+			ret = do_ramdump(drv->dspsfw_ramdump_dev,
+				drv->dspsfw_ramdump_segments,
+				ARRAY_SIZE(drv->dspsfw_ramdump_segments));
+			if (ret < 0) {
+				pr_err("%s: Unable to dump DSPS memory (rc = %d).\n",
+				       __func__, ret);
+				goto dsps_ramdump_out;
+			}
+		}
+		if (drv->smem_ramdump_dev != NULL) {
+			ret = do_ramdump(drv->smem_ramdump_dev,
+				drv->smem_ramdump_segments,
+				ARRAY_SIZE(drv->smem_ramdump_segments));
+			if (ret < 0) {
+				pr_err("%s: Unable to dump smem memory (rc = %d).\n",
+				       __func__, ret);
+				goto dsps_ramdump_out;
+			}
+		}
+	}
+
+dsps_ramdump_out:
+	return ret;
 }
 
 static struct subsys_data dsps_ssrops = {
@@ -768,6 +866,9 @@
 		pr_err("%s: kzalloc fail.\n", __func__);
 		goto alloc_err;
 	}
+	atomic_set(&drv->wd_crash, 0);
+	atomic_set(&drv->crash_in_progress, 0);
+
 	drv->pdata = pdev->dev.platform_data;
 
 	drv->dev_class = class_create(THIS_MODULE, DRV_NAME);
diff --git a/arch/arm/mach-msm/msm_watchdog.c b/arch/arm/mach-msm/msm_watchdog.c
index 9b8bc61..2cff7f0 100644
--- a/arch/arm/mach-msm/msm_watchdog.c
+++ b/arch/arm/mach-msm/msm_watchdog.c
@@ -151,13 +151,43 @@
 	.notifier_call	= panic_wdog_handler,
 };
 
+struct wdog_disable_work_data {
+	struct work_struct work;
+	struct completion complete;
+};
+
+static void wdog_disable_work(struct work_struct *work)
+{
+	struct wdog_disable_work_data *work_data =
+		container_of(work, struct wdog_disable_work_data, work);
+	__raw_writel(0, msm_tmr0_base + WDT0_EN);
+	mb();
+	if (has_vic) {
+		free_irq(WDT0_ACCSCSSNBARK_INT, 0);
+	} else {
+		disable_percpu_irq(WDT0_ACCSCSSNBARK_INT);
+		if (!appsbark_fiq) {
+			free_percpu_irq(WDT0_ACCSCSSNBARK_INT,
+					percpu_pdata);
+			free_percpu(percpu_pdata);
+		}
+	}
+	enable = 0;
+	atomic_notifier_chain_unregister(&panic_notifier_list, &panic_blk);
+	cancel_delayed_work(&dogwork_struct);
+	/* may be suspended after the first write above */
+	__raw_writel(0, msm_tmr0_base + WDT0_EN);
+	complete(&work_data->complete);
+	pr_info("MSM Watchdog deactivated.\n");
+}
+
 static int wdog_enable_set(const char *val, struct kernel_param *kp)
 {
 	int ret = 0;
 	int old_val = runtime_disable;
+	struct wdog_disable_work_data work_data;
 
 	mutex_lock(&disable_lock);
-
 	if (!enable) {
 		printk(KERN_INFO "MSM Watchdog is not active.\n");
 		ret = -EINVAL;
@@ -165,43 +195,20 @@
 	}
 
 	ret = param_set_int(val, kp);
-
 	if (ret)
 		goto done;
 
-	switch (runtime_disable) {
-
-	case 1:
-		if (!old_val) {
-			__raw_writel(0, msm_tmr0_base + WDT0_EN);
-			mb();
-			if (has_vic) {
-				free_irq(WDT0_ACCSCSSNBARK_INT, 0);
-			} else {
-				disable_percpu_irq(WDT0_ACCSCSSNBARK_INT);
-				if (!appsbark_fiq) {
-					free_percpu_irq(WDT0_ACCSCSSNBARK_INT,
-							percpu_pdata);
-					free_percpu(percpu_pdata);
-				}
-			}
-			enable = 0;
-			atomic_notifier_chain_unregister(&panic_notifier_list,
-			       &panic_blk);
-			cancel_delayed_work(&dogwork_struct);
-			/* may be suspended after the first write above */
-			__raw_writel(0, msm_tmr0_base + WDT0_EN);
-			printk(KERN_INFO "MSM Watchdog deactivated.\n");
-		}
-	break;
-
-	default:
+	if (runtime_disable == 1) {
+		if (old_val)
+			goto done;
+		init_completion(&work_data.complete);
+		INIT_WORK_ONSTACK(&work_data.work, wdog_disable_work);
+		schedule_work_on(0, &work_data.work);
+		wait_for_completion(&work_data.complete);
+	} else {
 		runtime_disable = old_val;
 		ret = -EINVAL;
-	break;
-
 	}
-
 done:
 	mutex_unlock(&disable_lock);
 	return ret;
@@ -332,9 +339,49 @@
 	}
 }
 
+struct fiq_handler wdog_fh = {
+	.name = MODULE_NAME,
+};
+
 static void init_watchdog_work(struct work_struct *work)
 {
 	u64 timeout = (bark_time * WDT_HZ)/1000;
+	void *stack;
+	int ret;
+
+	if (has_vic) {
+		ret = request_irq(WDT0_ACCSCSSNBARK_INT, wdog_bark_handler, 0,
+				  "apps_wdog_bark", NULL);
+		if (ret)
+			return;
+	} else if (appsbark_fiq) {
+		claim_fiq(&wdog_fh);
+		set_fiq_handler(&msm_wdog_fiq_start, msm_wdog_fiq_length);
+		stack = (void *)__get_free_pages(GFP_KERNEL, THREAD_SIZE_ORDER);
+		if (!stack) {
+			pr_info("No free pages available - %s fails\n",
+					__func__);
+			return;
+		}
+
+		msm_wdog_fiq_setup(stack);
+		gic_set_irq_secure(WDT0_ACCSCSSNBARK_INT);
+	} else {
+		percpu_pdata = alloc_percpu(struct msm_watchdog_pdata *);
+		if (!percpu_pdata) {
+			pr_err("%s: memory allocation failed for percpu data\n",
+					__func__);
+			return;
+		}
+
+		/* Must request irq before sending scm command */
+		ret = request_percpu_irq(WDT0_ACCSCSSNBARK_INT,
+			wdog_bark_handler, "apps_wdog_bark", percpu_pdata);
+		if (ret) {
+			free_percpu(percpu_pdata);
+			return;
+		}
+	}
 
 	configure_bark_dump();
 
@@ -358,15 +405,9 @@
 	return;
 }
 
-struct fiq_handler wdog_fh = {
-	.name = MODULE_NAME,
-};
-
 static int msm_watchdog_probe(struct platform_device *pdev)
 {
 	struct msm_watchdog_pdata *pdata = pdev->dev.platform_data;
-	int ret;
-	void *stack;
 
 	if (!enable || !pdata || !pdata->pet_time || !pdata->bark_time) {
 		printk(KERN_INFO "MSM Watchdog Not Initialized\n");
@@ -382,41 +423,6 @@
 
 	msm_tmr0_base = msm_timer_get_timer0_base();
 
-	if (has_vic) {
-		ret = request_irq(WDT0_ACCSCSSNBARK_INT, wdog_bark_handler, 0,
-				  "apps_wdog_bark", NULL);
-		if (ret)
-			return ret;
-	} else if (appsbark_fiq) {
-		claim_fiq(&wdog_fh);
-		set_fiq_handler(&msm_wdog_fiq_start, msm_wdog_fiq_length);
-		stack = (void *)__get_free_pages(GFP_KERNEL, THREAD_SIZE_ORDER);
-		if (!stack) {
-			pr_info("No free pages available - %s fails\n",
-					__func__);
-			return -ENOMEM;
-		}
-
-		msm_wdog_fiq_setup(stack);
-		gic_set_irq_secure(WDT0_ACCSCSSNBARK_INT);
-	} else {
-		percpu_pdata = alloc_percpu(struct msm_watchdog_pdata *);
-		if (!percpu_pdata) {
-			pr_err("%s: memory allocation failed for percpu data\n",
-					__func__);
-			return -ENOMEM;
-		}
-
-		*__this_cpu_ptr(percpu_pdata) = pdata;
-		/* Must request irq before sending scm command */
-		ret = request_percpu_irq(WDT0_ACCSCSSNBARK_INT,
-			wdog_bark_handler, "apps_wdog_bark", percpu_pdata);
-		if (ret) {
-			free_percpu(percpu_pdata);
-			return ret;
-		}
-	}
-
 	/*
 	 * This is only temporary till SBLs turn on the XPUs
 	 * This initialization will be done in SBLs on a later releases
diff --git a/arch/arm/mach-msm/no-pm.c b/arch/arm/mach-msm/no-pm.c
index d1c474b..a0e01b4 100644
--- a/arch/arm/mach-msm/no-pm.c
+++ b/arch/arm/mach-msm/no-pm.c
@@ -32,4 +32,16 @@
 }
 
 void msm_pm_set_max_sleep_time(int64_t max_sleep_time_ns) { }
-EXPORT_SYMBOL(msm_pm_set_max_sleep_time);
+
+void msm_pm_set_irq_extns(struct msm_pm_irq_calls *irq_calls) {}
+
+int msm_pm_idle_prepare(struct cpuidle_device *dev)
+{
+	return -ENOSYS;
+}
+
+int msm_pm_idle_enter(enum msm_pm_sleep_mode sleep_mode)
+{
+	return -ENOSYS;
+}
+
diff --git a/arch/arm/mach-msm/ocmem.c b/arch/arm/mach-msm/ocmem.c
index af39dc3..69e39df 100644
--- a/arch/arm/mach-msm/ocmem.c
+++ b/arch/arm/mach-msm/ocmem.c
@@ -29,6 +29,7 @@
 	unsigned long p_start;
 	unsigned long p_size;
 	unsigned long p_min;
+	unsigned int p_tail;
 };
 
 struct ocmem_plat_data {
@@ -36,7 +37,7 @@
 	unsigned long size;
 	unsigned long base;
 	struct ocmem_partition *parts;
-	int nr_parts;
+	unsigned nr_parts;
 };
 
 struct ocmem_zone zones[OCMEM_CLIENT_MAX];
@@ -70,19 +71,20 @@
 	unsigned long start;
 	unsigned long size;
 	unsigned long min;
+	unsigned int tail;
 };
 
 /* This static table will go away with device tree support */
 static struct ocmem_quota_table qt[OCMEM_CLIENT_MAX] = {
-	/* name,	id,	start,	size,	min */
-	{ "graphics", OCMEM_GRAPHICS, 0x0, 0x100000, 0x80000},
-	{ "video", OCMEM_VIDEO, 0x100000, 0x80000, 0x55000},
-	{ "camera", OCMEM_CAMERA, 0x0, 0x0, 0x0},
-	{ "voice", OCMEM_VOICE,  0x0, 0x0, 0x0 },
-	{ "hp_audio", OCMEM_HP_AUDIO, 0x0, 0x0, 0x0},
-	{ "lp_audio", OCMEM_LP_AUDIO, 0x80000, 0xA0000, 0xA0000},
-	{ "blast", OCMEM_BLAST, 0x120000, 0x20000, 0x20000},
-	{ "sensors", OCMEM_SENSORS, 0x140000, 0x40000, 0x40000},
+	/* name,        id,     start,  size,   min, tail */
+	{ "graphics", OCMEM_GRAPHICS, 0x0, 0x100000, 0x80000, 0},
+	{ "video", OCMEM_VIDEO, 0x100000, 0x80000, 0x55000, 1},
+	{ "camera", OCMEM_CAMERA, 0x0, 0x0, 0x0, 0},
+	{ "voice", OCMEM_VOICE,  0x0, 0x0, 0x0, 0 },
+	{ "hp_audio", OCMEM_HP_AUDIO, 0x0, 0x0, 0x0, 0},
+	{ "lp_audio", OCMEM_LP_AUDIO, 0x80000, 0xA0000, 0xA0000, 0},
+	{ "blast", OCMEM_BLAST, 0x120000, 0x20000, 0x20000, 0},
+	{ "sensors", OCMEM_SENSORS, 0x140000, 0x40000, 0x40000, 0},
 };
 
 static inline int get_id(const char *name)
@@ -100,7 +102,7 @@
 	struct ocmem_plat_data *pdata = NULL;
 	struct ocmem_partition *parts = NULL;
 	struct device   *dev = &pdev->dev;
-	int nr_parts;
+	unsigned nr_parts = 0;
 	int i;
 	int j;
 
@@ -142,6 +144,7 @@
 		parts[j].p_size = qt[i].size;
 		parts[j].p_start = qt[i].start;
 		parts[j].p_min = qt[i].min;
+		parts[j].p_tail = qt[i].tail;
 		j++;
 	}
 	BUG_ON(j != nr_parts);
@@ -225,6 +228,13 @@
 		zone->max_regions = 0;
 		INIT_LIST_HEAD(&zone->region_list);
 		zone->z_ops = z_ops;
+		if (part->p_tail) {
+			z_ops->allocate = allocate_tail;
+			z_ops->free = free_tail;
+		} else {
+			z_ops->allocate = allocate_head;
+			z_ops->free = free_head;
+		}
 		active_zones++;
 
 		if (active_zones == 1)
diff --git a/arch/arm/mach-msm/ocmem_allocator.c b/arch/arm/mach-msm/ocmem_allocator.c
new file mode 100644
index 0000000..71cacda
--- /dev/null
+++ b/arch/arm/mach-msm/ocmem_allocator.c
@@ -0,0 +1,105 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <mach/ocmem.h>
+#include <mach/ocmem_priv.h>
+#include <linux/genalloc.h>
+
+/* All allocator operations are serialized by ocmem driver */
+
+/* The allocators work as follows:
+	Constraints:
+	1) There is no IOMMU access to OCMEM hence successive allocations
+		in the zone must be physically contiguous
+	2) Allocations must be freed in reverse order within a zone.
+
+	z->z_start: Fixed pointer to the start of a zone
+	z->z_end:   Fixed pointer to the end of a zone
+
+	z->z_head:  Movable pointer to the next free area when growing at head
+			Fixed on zones that grow from tail
+
+	z->z_tail:  Movable pointer to the next free area when growing at tail
+			Fixed on zones that grow from head
+
+	z->z_free:  Free space in a zone that is updated on an allocation/free
+
+	reserve:    Enable libgenpool to simulate tail allocations
+*/
+
+unsigned long allocate_head(struct ocmem_zone *z, unsigned long size)
+{
+
+	unsigned long offset;
+
+	offset  = gen_pool_alloc(z->z_pool, size);
+
+	if (!offset)
+		return -ENOMEM;
+
+	z->z_head += size;
+	z->z_free -= size;
+	return offset;
+}
+
+unsigned long allocate_tail(struct ocmem_zone *z, unsigned long size)
+{
+	unsigned long offset;
+	unsigned long reserve;
+	unsigned long head;
+
+	if (z->z_tail < (z->z_head + size))
+		return -ENOMEM;
+
+	reserve = z->z_tail - z->z_head - size;
+	if (reserve) {
+		head = gen_pool_alloc(z->z_pool, reserve);
+		offset = gen_pool_alloc(z->z_pool, size);
+		gen_pool_free(z->z_pool, head, reserve);
+	} else
+		offset = gen_pool_alloc(z->z_pool, size);
+
+	if (!offset)
+		return -ENOMEM;
+
+	z->z_tail -= size;
+	z->z_free -= size;
+	return offset;
+}
+
+int free_head(struct ocmem_zone *z, unsigned long offset,
+			unsigned long size)
+{
+	if (offset > z->z_head) {
+		pr_err("ocmem: Detected out of order free "
+				"leading to fragmentation\n");
+		return -EINVAL;
+	}
+	gen_pool_free(z->z_pool, offset, size);
+	z->z_head -= size;
+	z->z_free += size;
+	return 0;
+}
+
+int free_tail(struct ocmem_zone *z, unsigned long offset,
+				unsigned long size)
+{
+	if (offset > z->z_tail) {
+		pr_err("ocmem: Detected out of order free "
+				"leading to fragmentation\n");
+		return -EINVAL;
+	}
+	gen_pool_free(z->z_pool, offset, size);
+	z->z_tail += size;
+	z->z_free += size;
+	return 0;
+}
diff --git a/arch/arm/mach-msm/pcie.c b/arch/arm/mach-msm/pcie.c
index 4e2b1083..dd91e66 100644
--- a/arch/arm/mach-msm/pcie.c
+++ b/arch/arm/mach-msm/pcie.c
@@ -201,7 +201,7 @@
 	.write = msm_pcie_wr_conf,
 };
 
-static int __devinit msm_pcie_gpio_init(void)
+static int __init msm_pcie_gpio_init(void)
 {
 	int rc, i;
 	struct msm_pcie_gpio_info_t *info;
@@ -239,7 +239,7 @@
 		gpio_free(msm_pcie_dev.gpio[i].num);
 }
 
-static int __devinit msm_pcie_vreg_init(struct device *dev)
+static int __init msm_pcie_vreg_init(struct device *dev)
 {
 	int i, rc = 0;
 	struct regulator *vreg;
@@ -306,7 +306,7 @@
 	}
 }
 
-static int __devinit msm_pcie_clk_init(struct device *dev)
+static int __init msm_pcie_clk_init(struct device *dev)
 {
 	int i, rc = 0;
 	struct clk *clk_hdl;
@@ -346,7 +346,7 @@
 	}
 }
 
-static void __devinit msm_pcie_config_controller(void)
+static void __init msm_pcie_config_controller(void)
 {
 	struct msm_pcie_dev_t *dev = &msm_pcie_dev;
 	struct msm_pcie_res_info_t *axi_bar = &dev->res[MSM_PCIE_RES_AXI_BAR];
@@ -393,7 +393,7 @@
 	wmb();
 }
 
-static int __devinit msm_pcie_get_resources(struct platform_device *pdev)
+static int __init msm_pcie_get_resources(struct platform_device *pdev)
 {
 	int i, rc = 0;
 	struct resource *res;
@@ -437,7 +437,7 @@
 	return rc;
 }
 
-static void __devexit msm_pcie_release_resources(void)
+static void msm_pcie_release_resources(void)
 {
 	int i;
 
@@ -452,7 +452,7 @@
 	msm_pcie_dev.axi_conf = NULL;
 }
 
-static int __devinit msm_pcie_setup(int nr, struct pci_sys_data *sys)
+static int __init msm_pcie_setup(int nr, struct pci_sys_data *sys)
 {
 	int rc;
 	struct msm_pcie_dev_t *dev = &msm_pcie_dev;
@@ -548,8 +548,8 @@
 	return (rc) ? 0 : 1;
 }
 
-static struct pci_bus __devinit *msm_pcie_scan_bus(int nr,
-						   struct pci_sys_data *sys)
+static struct pci_bus __init *msm_pcie_scan_bus(int nr,
+						struct pci_sys_data *sys)
 {
 	struct pci_bus *bus = NULL;
 
@@ -560,13 +560,13 @@
 	return bus;
 }
 
-static int __devinit msm_pcie_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init msm_pcie_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
 {
 	PCIE_DBG("slot %d pin %d\n", slot, pin);
 	return (pin <= 4) ? (PCIE20_INTA + pin - 1) : 0;
 }
 
-static struct hw_pci msm_pci __devinitdata = {
+static struct hw_pci msm_pci __initdata = {
 	.nr_controllers = 1,
 	.swizzle = pci_std_swizzle,
 	.setup = msm_pcie_setup,
@@ -574,7 +574,7 @@
 	.map_irq = msm_pcie_map_irq,
 };
 
-static int __devinit msm_pcie_probe(struct platform_device *pdev)
+static int __init msm_pcie_probe(struct platform_device *pdev)
 {
 	const struct msm_pcie_platform *pdata;
 	int rc;
@@ -603,7 +603,7 @@
 	return 0;
 }
 
-static int __devexit msm_pcie_remove(struct platform_device *pdev)
+static int __exit msm_pcie_remove(struct platform_device *pdev)
 {
 	PCIE_DBG("\n");
 
@@ -621,8 +621,7 @@
 }
 
 static struct platform_driver msm_pcie_driver = {
-	.probe = msm_pcie_probe,
-	.remove = __devexit_p(msm_pcie_remove),
+	.remove = __exit_p(msm_pcie_remove),
 	.driver = {
 		.name = "msm_pcie",
 		.owner = THIS_MODULE,
@@ -632,7 +631,7 @@
 static int __init msm_pcie_init(void)
 {
 	PCIE_DBG("\n");
-	return platform_driver_register(&msm_pcie_driver);
+	return platform_driver_probe(&msm_pcie_driver, msm_pcie_probe);
 }
 subsys_initcall(msm_pcie_init);
 
diff --git a/arch/arm/mach-msm/pcie_irq.c b/arch/arm/mach-msm/pcie_irq.c
index df100db..d915561 100644
--- a/arch/arm/mach-msm/pcie_irq.c
+++ b/arch/arm/mach-msm/pcie_irq.c
@@ -67,7 +67,7 @@
 	return IRQ_HANDLED;
 }
 
-uint32_t __devinit msm_pcie_irq_init(struct msm_pcie_dev_t *dev)
+uint32_t __init msm_pcie_irq_init(struct msm_pcie_dev_t *dev)
 {
 	int i, rc;
 
@@ -93,7 +93,7 @@
 	return rc;
 }
 
-void msm_pcie_irq_deinit(struct msm_pcie_dev_t *dev)
+void __exit msm_pcie_irq_deinit(struct msm_pcie_dev_t *dev)
 {
 	free_irq(PCIE20_INT_MSI, dev);
 }
diff --git a/arch/arm/mach-msm/peripheral-loader.c b/arch/arm/mach-msm/peripheral-loader.c
index 0ecea85..bfbf4bc 100644
--- a/arch/arm/mach-msm/peripheral-loader.c
+++ b/arch/arm/mach-msm/peripheral-loader.c
@@ -137,8 +137,11 @@
 	const struct firmware *fw = NULL;
 	const u8 *data;
 
-	if (memblock_is_region_memory(phdr->p_paddr, phdr->p_memsz)) {
-		dev_err(&pil->dev, "Kernel memory would be overwritten");
+	if (memblock_overlaps_memory(phdr->p_paddr, phdr->p_memsz)) {
+		dev_err(&pil->dev, "%s: kernel memory would be overwritten "
+			"[%#08lx, %#08lx)\n", pil->desc->name,
+			(unsigned long)phdr->p_paddr,
+			(unsigned long)(phdr->p_paddr + phdr->p_memsz));
 		return -EPERM;
 	}
 
@@ -147,14 +150,15 @@
 				pil->desc->name, num);
 		ret = request_firmware(&fw, fw_name, &pil->dev);
 		if (ret) {
-			dev_err(&pil->dev, "Failed to locate blob %s\n",
-					fw_name);
+			dev_err(&pil->dev, "%s: Failed to locate blob %s\n",
+					pil->desc->name, fw_name);
 			return ret;
 		}
 
 		if (fw->size != phdr->p_filesz) {
-			dev_err(&pil->dev, "Blob size %u doesn't match %u\n",
-					fw->size, phdr->p_filesz);
+			dev_err(&pil->dev, "%s: Blob size %u doesn't match "
+					"%u\n", pil->desc->name, fw->size,
+					phdr->p_filesz);
 			ret = -EPERM;
 			goto release_fw;
 		}
@@ -171,7 +175,8 @@
 		size = min_t(size_t, IOMAP_SIZE, count);
 		buf = ioremap(paddr, size);
 		if (!buf) {
-			dev_err(&pil->dev, "Failed to map memory\n");
+			dev_err(&pil->dev, "%s: Failed to map memory\n",
+					pil->desc->name);
 			ret = -ENOMEM;
 			goto release_fw;
 		}
@@ -192,7 +197,8 @@
 		size = min_t(size_t, IOMAP_SIZE, count);
 		buf = ioremap(paddr, size);
 		if (!buf) {
-			dev_err(&pil->dev, "Failed to map memory\n");
+			dev_err(&pil->dev, "%s: Failed to map memory\n",
+					pil->desc->name);
 			ret = -ENOMEM;
 			goto release_fw;
 		}
@@ -207,7 +213,8 @@
 		ret = pil->desc->ops->verify_blob(pil->desc, phdr->p_paddr,
 					  phdr->p_memsz);
 		if (ret)
-			dev_err(&pil->dev, "Blob%u failed verification\n", num);
+			dev_err(&pil->dev, "%s: Blob%u failed verification\n",
+				pil->desc->name, num);
 	}
 
 release_fw:
@@ -238,38 +245,43 @@
 	snprintf(fw_name, sizeof(fw_name), "%s.mdt", pil->desc->name);
 	ret = request_firmware(&fw, fw_name, &pil->dev);
 	if (ret) {
-		dev_err(&pil->dev, "Failed to locate %s\n", fw_name);
+		dev_err(&pil->dev, "%s: Failed to locate %s\n",
+				pil->desc->name, fw_name);
 		goto out;
 	}
 
 	if (fw->size < sizeof(*ehdr)) {
-		dev_err(&pil->dev, "Not big enough to be an elf header\n");
+		dev_err(&pil->dev, "%s: Not big enough to be an elf header\n",
+				pil->desc->name);
 		ret = -EIO;
 		goto release_fw;
 	}
 
 	ehdr = (struct elf32_hdr *)fw->data;
 	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
-		dev_err(&pil->dev, "Not an elf header\n");
+		dev_err(&pil->dev, "%s: Not an elf header\n", pil->desc->name);
 		ret = -EIO;
 		goto release_fw;
 	}
 
 	if (ehdr->e_phnum == 0) {
-		dev_err(&pil->dev, "No loadable segments\n");
+		dev_err(&pil->dev, "%s: No loadable segments\n",
+				pil->desc->name);
 		ret = -EIO;
 		goto release_fw;
 	}
 	if (sizeof(struct elf32_phdr) * ehdr->e_phnum +
 	    sizeof(struct elf32_hdr) > fw->size) {
-		dev_err(&pil->dev, "Program headers not within mdt\n");
+		dev_err(&pil->dev, "%s: Program headers not within mdt\n",
+				pil->desc->name);
 		ret = -EIO;
 		goto release_fw;
 	}
 
 	ret = pil->desc->ops->init_image(pil->desc, fw->data, fw->size);
 	if (ret) {
-		dev_err(&pil->dev, "Invalid firmware metadata\n");
+		dev_err(&pil->dev, "%s: Invalid firmware metadata\n",
+				pil->desc->name);
 		goto release_fw;
 	}
 
@@ -280,25 +292,27 @@
 
 		ret = load_segment(phdr, i, pil);
 		if (ret) {
-			dev_err(&pil->dev, "Failed to load segment %d\n",
-					i);
+			dev_err(&pil->dev, "%s: Failed to load segment %d\n",
+					pil->desc->name, i);
 			goto release_fw;
 		}
 	}
 
 	ret = pil_proxy_vote(pil);
 	if (ret) {
-		dev_err(&pil->dev, "Failed to proxy vote\n");
+		dev_err(&pil->dev, "%s: Failed to proxy vote\n",
+					pil->desc->name);
 		goto release_fw;
 	}
 
 	ret = pil->desc->ops->auth_and_reset(pil->desc);
 	if (ret) {
-		dev_err(&pil->dev, "Failed to bring out of reset\n");
+		dev_err(&pil->dev, "%s: Failed to bring out of reset\n",
+				pil->desc->name);
 		proxy_timeout = 0; /* Remove proxy vote immediately on error */
 		goto err_boot;
 	}
-	dev_info(&pil->dev, "brought %s out of reset\n", pil->desc->name);
+	dev_info(&pil->dev, "%s: Brought out of reset\n", pil->desc->name);
 err_boot:
 	pil_proxy_unvote(pil, proxy_timeout);
 release_fw:
@@ -394,7 +408,8 @@
 		return;
 
 	mutex_lock(&pil->lock);
-	if (WARN(!pil->count, "%s: Reference count mismatch\n", __func__))
+	if (WARN(!pil->count, "%s: %s: Reference count mismatch\n",
+			pil->desc->name, __func__))
 		goto err_out;
 	if (!--pil->count)
 		pil_shutdown(pil);
@@ -425,7 +440,8 @@
 	}
 
 	mutex_lock(&pil->lock);
-	if (!WARN(!pil->count, "%s: Reference count mismatch\n", __func__))
+	if (!WARN(!pil->count, "%s: %s: Reference count mismatch\n",
+			pil->desc->name, __func__))
 		pil_shutdown(pil);
 	mutex_unlock(&pil->lock);
 
@@ -445,7 +461,8 @@
 	}
 
 	mutex_lock(&pil->lock);
-	if (!WARN(!pil->count, "%s: Reference count mismatch\n", __func__))
+	if (!WARN(!pil->count, "%s: %s: Reference count mismatch\n",
+			pil->desc->name, __func__))
 		ret = load_image(pil);
 	if (!ret)
 		pil_set_state(pil, PIL_ONLINE);
@@ -575,6 +592,10 @@
 				"invalid proxy voting. ignoring\n"))
 		((struct pil_reset_ops *)desc->ops)->proxy_unvote = NULL;
 
+	WARN(desc->ops->proxy_unvote && !desc->proxy_timeout,
+		"A proxy timeout of 0 ms was specified for %s. Specify one in "
+		"desc->proxy_timeout.\n", desc->name);
+
 	pil = kzalloc(sizeof(*pil), GFP_KERNEL);
 	if (!pil)
 		return ERR_PTR(-ENOMEM);
diff --git a/arch/arm/mach-msm/pil-mba.c b/arch/arm/mach-msm/pil-mba.c
new file mode 100644
index 0000000..7405ab9
--- /dev/null
+++ b/arch/arm/mach-msm/pil-mba.c
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/ioport.h>
+#include <linux/elf.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/of.h>
+
+#include "peripheral-loader.h"
+
+#define RMB_MBA_COMMAND			0x08
+#define RMB_MBA_STATUS			0x0C
+#define RMB_PMI_META_DATA		0x10
+#define RMB_PMI_CODE_START		0x14
+#define RMB_PMI_CODE_LENGTH		0x18
+
+#define CMD_META_DATA_READY		0x1
+#define CMD_LOAD_READY			0x2
+
+#define STATUS_META_DATA_AUTH_SUCCESS	0x3
+#define STATUS_AUTH_COMPLETE		0x4
+#define STATUS_ERROR_MASK		BIT(31)
+
+#define AUTH_TIMEOUT_US			10000000
+#define PROXY_TIMEOUT_MS		10000
+#define POLL_INTERVAL_US		50
+
+struct mba_data {
+	void __iomem *reg_base;
+	void __iomem *metadata_base;
+	unsigned long metadata_phys;
+	struct pil_device *pil;
+	struct clk *xo;
+	u32 img_length;
+};
+
+static int pil_mba_make_proxy_votes(struct pil_desc *pil)
+{
+	int ret;
+	struct mba_data *drv = dev_get_drvdata(pil->dev);
+
+	ret = clk_prepare_enable(drv->xo);
+	if (ret) {
+		dev_err(pil->dev, "Failed to enable XO\n");
+		return ret;
+	}
+	return 0;
+}
+
+static void pil_mba_remove_proxy_votes(struct pil_desc *pil)
+{
+	struct mba_data *drv = dev_get_drvdata(pil->dev);
+	clk_disable_unprepare(drv->xo);
+}
+
+static int pil_mba_init_image(struct pil_desc *pil,
+			      const u8 *metadata, size_t size)
+{
+	struct mba_data *drv = dev_get_drvdata(pil->dev);
+	u32 status;
+	int ret;
+
+	/* Copy metadata to assigned shared buffer location */
+	memcpy(drv->metadata_base, metadata, size);
+
+	/* Initialize length counter to 0 */
+	writel_relaxed(0, drv->reg_base + RMB_PMI_CODE_LENGTH);
+	drv->img_length = 0;
+
+	/* Pass address of meta-data to the MBA and perform authentication */
+	writel_relaxed(drv->metadata_phys, drv->reg_base + RMB_PMI_META_DATA);
+	writel_relaxed(CMD_META_DATA_READY, drv->reg_base + RMB_MBA_COMMAND);
+	ret = readl_poll_timeout(drv->reg_base + RMB_MBA_STATUS, status,
+		status == STATUS_META_DATA_AUTH_SUCCESS,
+		POLL_INTERVAL_US, AUTH_TIMEOUT_US);
+	if (ret)
+		dev_err(pil->dev, "MBA authentication timed out\n");
+
+	return ret;
+}
+
+static int pil_mba_verify_blob(struct pil_desc *pil, u32 phy_addr,
+			       size_t size)
+{
+	struct mba_data *drv = dev_get_drvdata(pil->dev);
+
+	/* Begin image authentication */
+	if (drv->img_length == 0) {
+		writel_relaxed(phy_addr, drv->reg_base + RMB_PMI_CODE_START);
+		writel_relaxed(CMD_LOAD_READY, drv->reg_base + RMB_MBA_COMMAND);
+	}
+	/* Increment length counter */
+	drv->img_length += size;
+	writel_relaxed(drv->img_length, drv->reg_base + RMB_PMI_CODE_LENGTH);
+
+	return readl_relaxed(drv->reg_base + RMB_MBA_STATUS)
+			& STATUS_ERROR_MASK;
+}
+
+static int pil_mba_auth(struct pil_desc *pil)
+{
+	struct mba_data *drv = dev_get_drvdata(pil->dev);
+	int ret;
+	u32 status;
+
+	/* Wait for all segments to be authenticated or an error to occur */
+	ret = readl_poll_timeout(drv->reg_base + RMB_MBA_STATUS, status,
+			status == STATUS_AUTH_COMPLETE ||
+			status & STATUS_ERROR_MASK,
+			50, AUTH_TIMEOUT_US);
+	if (ret)
+		return ret;
+
+	if (status & STATUS_ERROR_MASK)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int pil_mba_shutdown(struct pil_desc *pil)
+{
+	return 0;
+}
+
+static struct pil_reset_ops pil_mba_ops = {
+	.init_image = pil_mba_init_image,
+	.proxy_vote = pil_mba_make_proxy_votes,
+	.proxy_unvote = pil_mba_remove_proxy_votes,
+	.verify_blob = pil_mba_verify_blob,
+	.auth_and_reset = pil_mba_auth,
+	.shutdown = pil_mba_shutdown,
+};
+
+static int __devinit pil_mba_driver_probe(struct platform_device *pdev)
+{
+	struct mba_data *drv;
+	struct resource *res;
+	struct pil_desc *desc;
+	int ret;
+
+	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
+	if (!drv)
+		return -ENOMEM;
+	platform_set_drvdata(pdev, drv);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -EINVAL;
+	drv->reg_base = devm_ioremap(&pdev->dev, res->start,
+				     resource_size(res));
+	if (!drv->reg_base)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (res) {
+		drv->metadata_base = devm_ioremap(&pdev->dev, res->start,
+						  resource_size(res));
+		if (!drv->metadata_base)
+			return -ENOMEM;
+		drv->metadata_phys = res->start;
+	}
+
+	desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
+	if (!drv)
+		return -ENOMEM;
+
+	ret = of_property_read_string(pdev->dev.of_node, "qcom,firmware-name",
+				      &desc->name);
+	if (ret)
+		return ret;
+
+	of_property_read_string(pdev->dev.of_node, "qcom,depends-on",
+				      &desc->depends_on);
+
+	drv->xo = devm_clk_get(&pdev->dev, "xo");
+	if (IS_ERR(drv->xo))
+		return PTR_ERR(drv->xo);
+
+	desc->dev = &pdev->dev;
+	desc->ops = &pil_mba_ops;
+	desc->owner = THIS_MODULE;
+	desc->proxy_timeout = PROXY_TIMEOUT_MS;
+
+	drv->pil = msm_pil_register(desc);
+	if (IS_ERR(drv->pil))
+		return PTR_ERR(drv->pil);
+
+	return 0;
+}
+
+static int __devexit pil_mba_driver_exit(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static struct of_device_id mba_match_table[] = {
+	{ .compatible = "qcom,pil-mba" },
+	{}
+};
+
+struct platform_driver pil_mba_driver = {
+	.probe = pil_mba_driver_probe,
+	.remove = __devexit_p(pil_mba_driver_exit),
+	.driver = {
+		.name = "pil-mba",
+		.of_match_table = mba_match_table,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init pil_mba_init(void)
+{
+	return platform_driver_register(&pil_mba_driver);
+}
+module_init(pil_mba_init);
+
+static void __exit pil_mba_exit(void)
+{
+	platform_driver_unregister(&pil_mba_driver);
+}
+module_exit(pil_mba_exit);
+
+MODULE_DESCRIPTION("Support for modem boot using the Modem Boot Authenticator");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/pil-q6v4.c b/arch/arm/mach-msm/pil-q6v4.c
index 8446e42..131a74b 100644
--- a/arch/arm/mach-msm/pil-q6v4.c
+++ b/arch/arm/mach-msm/pil-q6v4.c
@@ -116,14 +116,9 @@
 	int err;
 	struct q6v4_data *drv = dev_get_drvdata(dev);
 
-	err = regulator_set_voltage(drv->vreg, 1050000, 1050000);
+	err = regulator_set_voltage(drv->vreg, 375000, 375000);
 	if (err) {
-		dev_err(dev, "Failed to set regulator's voltage.\n");
-		return err;
-	}
-	err = regulator_set_optimum_mode(drv->vreg, 100000);
-	if (err < 0) {
-		dev_err(dev, "Failed to set regulator's mode.\n");
+		dev_err(dev, "Failed to set regulator's voltage step.\n");
 		return err;
 	}
 	err = regulator_enable(drv->vreg);
@@ -131,6 +126,18 @@
 		dev_err(dev, "Failed to enable regulator.\n");
 		return err;
 	}
+
+	/*
+	 * Q6 hardware requires a two step voltage ramp-up.
+	 * Delay between the steps.
+	 */
+	udelay(100);
+
+	err = regulator_set_voltage(drv->vreg, 1050000, 1050000);
+	if (err) {
+		dev_err(dev, "Failed to set regulator's voltage.\n");
+		return err;
+	}
 	drv->vreg_enabled = true;
 	return 0;
 }
@@ -411,6 +418,12 @@
 	if (IS_ERR(drv->vreg))
 		return PTR_ERR(drv->vreg);
 
+	ret = regulator_set_optimum_mode(drv->vreg, 100000);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Failed to set regulator's mode.\n");
+		return ret;
+	}
+
 	drv->xo = devm_clk_get(&pdev->dev, "xo");
 	if (IS_ERR(drv->xo))
 		return PTR_ERR(drv->xo);
diff --git a/arch/arm/mach-msm/pil-q6v5-lpass.c b/arch/arm/mach-msm/pil-q6v5-lpass.c
index 5eac539..311f8a7 100644
--- a/arch/arm/mach-msm/pil-q6v5-lpass.c
+++ b/arch/arm/mach-msm/pil-q6v5-lpass.c
@@ -15,66 +15,34 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
-#include <linux/iopoll.h>
 #include <linux/err.h>
 #include <linux/of.h>
+#include <linux/clk.h>
 
 #include "peripheral-loader.h"
 #include "pil-q6v5.h"
 
-/* Register Offsets */
 #define QDSP6SS_RST_EVB			0x010
-#define LPASS_Q6SS_BCR			0x06000
-#define LPASS_Q6SS_AHB_LFABIF_CBCR	0x22000
-#define LPASS_Q6SS_XO_CBCR		0x26000
-#define AXI_HALTREQ			0x0
-#define AXI_HALTACK			0x4
-#define AXI_IDLE			0x8
-
-#define HALT_ACK_TIMEOUT_US		100000
-
-static void clk_reg_enable(void __iomem *reg)
-{
-	u32 val;
-	val = readl_relaxed(reg);
-	val |= BIT(0);
-	writel_relaxed(val, reg);
-}
-
-static void clk_reg_disable(void __iomem *reg)
-{
-	u32 val;
-	val = readl_relaxed(reg);
-	val &= ~BIT(0);
-	writel_relaxed(val, reg);
-}
+#define PROXY_TIMEOUT_MS		10000
 
 static int pil_lpass_shutdown(struct pil_desc *pil)
 {
 	struct q6v5_data *drv = dev_get_drvdata(pil->dev);
-	int ret;
-	u32 status;
 
-	writel_relaxed(1, drv->axi_halt_base + AXI_HALTREQ);
-	ret = readl_poll_timeout(drv->axi_halt_base + AXI_HALTACK,
-		status,	status, 50, HALT_ACK_TIMEOUT_US);
-	if (ret)
-		dev_err(pil->dev, "Port halt timeout\n");
-	else if (!readl_relaxed(drv->axi_halt_base + AXI_IDLE))
-		dev_err(pil->dev, "Port halt failed\n");
-	writel_relaxed(0, drv->axi_halt_base + AXI_HALTREQ);
+	pil_q6v5_halt_axi_port(pil, drv->axi_halt_base);
 
-	/* Make sure Q6 registers are accessible */
-	writel_relaxed(0, drv->clk_base + LPASS_Q6SS_BCR);
-	clk_reg_enable(drv->clk_base + LPASS_Q6SS_AHB_LFABIF_CBCR);
-	mb();
+	/*
+	 * If the shutdown function is called before the reset function, clocks
+	 * will not be enabled yet. Enable them here so that register writes
+	 * performed during the shutdown succeed.
+	 */
+	if (drv->is_booted == false)
+		pil_q6v5_enable_clks(pil);
 
 	pil_q6v5_shutdown(pil);
+	pil_q6v5_disable_clks(pil);
 
-	/* Disable clocks and assert subsystem resets. */
-	clk_reg_disable(drv->clk_base + LPASS_Q6SS_AHB_LFABIF_CBCR);
-	clk_reg_disable(drv->clk_base + LPASS_Q6SS_XO_CBCR);
-	writel_relaxed(1, drv->clk_base + LPASS_Q6SS_BCR);
+	drv->is_booted = false;
 
 	return 0;
 }
@@ -82,21 +50,25 @@
 static int pil_lpass_reset(struct pil_desc *pil)
 {
 	struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+	int ret;
 
-	/*
-	 * Bring subsystem out of reset and enable required
-	 * regulators and clocks.
-	 */
-	writel_relaxed(0, drv->clk_base + LPASS_Q6SS_BCR);
-	clk_reg_enable(drv->clk_base + LPASS_Q6SS_XO_CBCR);
-	clk_reg_enable(drv->clk_base + LPASS_Q6SS_AHB_LFABIF_CBCR);
-	mb();
+	ret = pil_q6v5_enable_clks(pil);
+	if (ret)
+		return ret;
 
 	/* Program Image Address */
 	writel_relaxed(((drv->start_addr >> 4) & 0x0FFFFFF0),
 				drv->reg_base + QDSP6SS_RST_EVB);
 
-	return pil_q6v5_reset(pil);
+	ret = pil_q6v5_reset(pil);
+	if (ret) {
+		pil_q6v5_disable_clks(pil);
+		return ret;
+	}
+
+	drv->is_booted = true;
+
+	return 0;
 }
 
 static struct pil_reset_ops pil_lpass_ops = {
@@ -111,7 +83,6 @@
 {
 	struct q6v5_data *drv;
 	struct pil_desc *desc;
-	struct resource *res;
 
 	desc = pil_q6v5_init(pdev);
 	if (IS_ERR(desc))
@@ -123,12 +94,7 @@
 
 	desc->ops = &pil_lpass_ops;
 	desc->owner = THIS_MODULE;
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
-	drv->axi_halt_base = devm_ioremap(&pdev->dev, res->start,
-					  resource_size(res));
-	if (!drv->axi_halt_base)
-		return -ENOMEM;
+	desc->proxy_timeout = PROXY_TIMEOUT_MS;
 
 	drv->pil = msm_pil_register(desc);
 	if (IS_ERR(drv->pil))
diff --git a/arch/arm/mach-msm/pil-q6v5-mss.c b/arch/arm/mach-msm/pil-q6v5-mss.c
new file mode 100644
index 0000000..e279f99
--- /dev/null
+++ b/arch/arm/mach-msm/pil-q6v5-mss.c
@@ -0,0 +1,291 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/ioport.h>
+#include <linux/elf.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/regulator/consumer.h>
+
+#include <mach/clk.h>
+
+#include "peripheral-loader.h"
+#include "pil-q6v5.h"
+
+/* Q6 Register Offsets */
+#define QDSP6SS_RST_EVB			0x010
+
+/* AXI Halting Registers */
+#define MSS_Q6_HALT_BASE		0x180
+#define MSS_MODEM_HALT_BASE		0x200
+#define MSS_NC_HALT_BASE		0x280
+
+/* RMB Status Register Values */
+#define STATUS_PBL_SUCCESS		0x1
+#define STATUS_XPU_UNLOCKED		0x1
+#define STATUS_XPU_UNLOCKED_SCRIBBLED	0x2
+
+/* PBL/MBA interface registers */
+#define RMB_MBA_IMAGE			0x00
+#define RMB_PBL_STATUS			0x04
+#define RMB_MBA_STATUS			0x0C
+
+#define PBL_MBA_WAIT_TIMEOUT_US		100000
+#define PROXY_TIMEOUT_MS		10000
+#define POLL_INTERVAL_US		50
+
+static int pil_mss_power_up(struct device *dev)
+{
+	int ret;
+	struct q6v5_data *drv = dev_get_drvdata(dev);
+
+	ret = regulator_enable(drv->vreg);
+	if (ret)
+		dev_err(dev, "Failed to enable regulator.\n");
+
+	return ret;
+}
+
+static int pil_mss_power_down(struct device *dev)
+{
+	struct q6v5_data *drv = dev_get_drvdata(dev);
+
+	return regulator_disable(drv->vreg);
+}
+
+static int wait_for_mba_ready(struct device *dev)
+{
+	struct q6v5_data *drv = dev_get_drvdata(dev);
+	int ret;
+	u32 status;
+
+	/* Wait for PBL completion. */
+	ret = readl_poll_timeout(drv->rmb_base + RMB_PBL_STATUS, status,
+		status != 0, POLL_INTERVAL_US, PBL_MBA_WAIT_TIMEOUT_US);
+	if (ret) {
+		dev_err(dev, "PBL boot timed out\n");
+		return ret;
+	}
+	if (status != STATUS_PBL_SUCCESS) {
+		dev_err(dev, "PBL returned unexpected status %d\n", status);
+		return -EINVAL;
+	}
+
+	/* Wait for MBA completion. */
+	ret = readl_poll_timeout(drv->rmb_base + RMB_MBA_STATUS, status,
+		status != 0, POLL_INTERVAL_US, PBL_MBA_WAIT_TIMEOUT_US);
+	if (ret) {
+		dev_err(dev, "MBA boot timed out\n");
+		return ret;
+	}
+	if (status != STATUS_XPU_UNLOCKED &&
+	    status != STATUS_XPU_UNLOCKED_SCRIBBLED) {
+		dev_err(dev, "MBA returned unexpected status %d\n", status);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int pil_mss_shutdown(struct pil_desc *pil)
+{
+	struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+
+	pil_q6v5_halt_axi_port(pil, drv->axi_halt_base + MSS_Q6_HALT_BASE);
+	pil_q6v5_halt_axi_port(pil, drv->axi_halt_base + MSS_MODEM_HALT_BASE);
+	pil_q6v5_halt_axi_port(pil, drv->axi_halt_base + MSS_NC_HALT_BASE);
+
+	/*
+	 * If the shutdown function is called before the reset function, clocks
+	 * and power will not be enabled yet. Enable them here so that register
+	 * writes performed during the shutdown succeed.
+	 */
+	if (drv->is_booted == false) {
+		pil_mss_power_up(pil->dev);
+		pil_q6v5_enable_clks(pil);
+	}
+	pil_q6v5_shutdown(pil);
+
+	pil_q6v5_disable_clks(pil);
+	pil_mss_power_down(pil->dev);
+
+	writel_relaxed(1, drv->restart_reg);
+
+	drv->is_booted = false;
+
+	return 0;
+}
+
+static int pil_mss_reset(struct pil_desc *pil)
+{
+	struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+	int ret;
+
+	writel_relaxed(0, drv->restart_reg);
+	mb();
+
+	/*
+	 * Bring subsystem out of reset and enable required
+	 * regulators and clocks.
+	 */
+	ret = pil_mss_power_up(pil->dev);
+	if (ret)
+		goto err_power;
+
+	ret = pil_q6v5_enable_clks(pil);
+	if (ret)
+		goto err_clks;
+
+	/* Program Image Address */
+	if (drv->self_auth)
+		writel_relaxed(drv->start_addr, drv->rmb_base + RMB_MBA_IMAGE);
+	else
+		writel_relaxed((drv->start_addr >> 4) & 0x0FFFFFF0,
+				drv->reg_base + QDSP6SS_RST_EVB);
+
+	ret = pil_q6v5_reset(pil);
+	if (ret)
+		goto err_q6v5_reset;
+
+	/* Wait for MBA to start. Check for PBL and MBA errors while waiting. */
+	if (drv->self_auth) {
+		ret = wait_for_mba_ready(pil->dev);
+		if (ret)
+			goto err_auth;
+	}
+
+	drv->is_booted = true;
+
+	return 0;
+
+err_auth:
+	pil_q6v5_shutdown(pil);
+err_q6v5_reset:
+	pil_q6v5_disable_clks(pil);
+err_clks:
+	pil_mss_power_down(pil->dev);
+err_power:
+	return ret;
+}
+
+static struct pil_reset_ops pil_mss_ops = {
+	.init_image = pil_q6v5_init_image,
+	.proxy_vote = pil_q6v5_make_proxy_votes,
+	.proxy_unvote = pil_q6v5_remove_proxy_votes,
+	.auth_and_reset = pil_mss_reset,
+	.shutdown = pil_mss_shutdown,
+};
+
+static int __devinit pil_mss_driver_probe(struct platform_device *pdev)
+{
+	struct q6v5_data *drv;
+	struct pil_desc *desc;
+	struct resource *res;
+	int ret;
+
+	desc = pil_q6v5_init(pdev);
+	if (IS_ERR(desc))
+		return PTR_ERR(desc);
+	drv = platform_get_drvdata(pdev);
+	if (drv == NULL)
+		return -ENODEV;
+
+	desc->ops = &pil_mss_ops;
+	desc->owner = THIS_MODULE;
+	desc->proxy_timeout = PROXY_TIMEOUT_MS;
+
+	of_property_read_u32(pdev->dev.of_node, "qcom,pil-self-auth",
+			     &drv->self_auth);
+	if (drv->self_auth) {
+		res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+		drv->rmb_base = devm_ioremap(&pdev->dev, res->start,
+					     resource_size(res));
+		if (!drv->rmb_base)
+			return -ENOMEM;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
+	drv->restart_reg = devm_ioremap(&pdev->dev, res->start,
+					resource_size(res));
+	if (!drv->restart_reg)
+		return -ENOMEM;
+
+	drv->vreg = devm_regulator_get(&pdev->dev, "vdd_mss");
+	if (IS_ERR(drv->vreg))
+		return PTR_ERR(drv->vreg);
+
+	ret = regulator_set_voltage(drv->vreg, 1150000, 1150000);
+	if (ret)
+		dev_err(&pdev->dev, "Failed to set regulator's voltage.\n");
+
+	ret = regulator_set_optimum_mode(drv->vreg, 100000);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Failed to set regulator's mode.\n");
+		return ret;
+	}
+
+	drv->mem_clk = devm_clk_get(&pdev->dev, "mem_clk");
+	if (IS_ERR(drv->mem_clk))
+		return PTR_ERR(drv->mem_clk);
+
+	drv->pil = msm_pil_register(desc);
+	if (IS_ERR(drv->pil))
+		return PTR_ERR(drv->pil);
+
+	return 0;
+}
+
+static int __devexit pil_mss_driver_exit(struct platform_device *pdev)
+{
+	struct q6v5_data *drv = platform_get_drvdata(pdev);
+	msm_pil_unregister(drv->pil);
+	return 0;
+}
+
+static struct of_device_id mss_match_table[] = {
+	{ .compatible = "qcom,pil-q6v5-mss" },
+	{}
+};
+
+static struct platform_driver pil_mss_driver = {
+	.probe = pil_mss_driver_probe,
+	.remove = __devexit_p(pil_mss_driver_exit),
+	.driver = {
+		.name = "pil-q6v5-mss",
+		.of_match_table = mss_match_table,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init pil_mss_init(void)
+{
+	return platform_driver_register(&pil_mss_driver);
+}
+module_init(pil_mss_init);
+
+static void __exit pil_mss_exit(void)
+{
+	platform_driver_unregister(&pil_mss_driver);
+}
+module_exit(pil_mss_exit);
+
+MODULE_DESCRIPTION("Support for booting modem subsystems with QDSP6v5 Hexagon processors");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/pil-q6v5.c b/arch/arm/mach-msm/pil-q6v5.c
index cd58a4c..a362a7e3 100644
--- a/arch/arm/mach-msm/pil-q6v5.c
+++ b/arch/arm/mach-msm/pil-q6v5.c
@@ -15,19 +15,29 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
+#include <linux/iopoll.h>
 #include <linux/elf.h>
 #include <linux/err.h>
 #include <linux/of.h>
 #include <linux/clk.h>
 
+#include <mach/clk.h>
+
 #include "peripheral-loader.h"
 #include "pil-q6v5.h"
 
-/* Register Offsets */
+/* QDSP6SS Register Offsets */
 #define QDSP6SS_RESET			0x014
 #define QDSP6SS_GFMUX_CTL		0x020
 #define QDSP6SS_PWR_CTL			0x030
 
+/* AXI Halt Register Offsets */
+#define AXI_HALTREQ			0x0
+#define AXI_HALTACK			0x4
+#define AXI_IDLE			0x8
+
+#define HALT_ACK_TIMEOUT_US		100000
+
 /* QDSP6SS_RESET */
 #define Q6SS_CORE_ARES			BIT(1)
 #define Q6SS_ETM_ISDB_ARES		BIT(3)
@@ -66,6 +76,27 @@
 }
 EXPORT_SYMBOL(pil_q6v5_remove_proxy_votes);
 
+void pil_q6v5_halt_axi_port(struct pil_desc *pil, void __iomem *halt_base)
+{
+	int ret;
+	u32 status;
+
+	/* Assert halt request */
+	writel_relaxed(1, halt_base + AXI_HALTREQ);
+
+	/* Wait for halt */
+	ret = readl_poll_timeout(halt_base + AXI_HALTACK,
+		status, status != 0, 50, HALT_ACK_TIMEOUT_US);
+	if (ret)
+		dev_warn(pil->dev, "Port %p halt timeout\n", halt_base);
+	else if (!readl_relaxed(halt_base + AXI_IDLE))
+		dev_warn(pil->dev, "Port %p halt failed\n", halt_base);
+
+	/* Clear halt request (port will remain halted until reset) */
+	writel_relaxed(0, halt_base + AXI_HALTREQ);
+}
+EXPORT_SYMBOL(pil_q6v5_halt_axi_port);
+
 int pil_q6v5_init_image(struct pil_desc *pil, const u8 *metadata,
 			       size_t size)
 {
@@ -76,6 +107,50 @@
 }
 EXPORT_SYMBOL(pil_q6v5_init_image);
 
+int pil_q6v5_enable_clks(struct pil_desc *pil)
+{
+	struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+	int ret;
+
+	ret = clk_reset(drv->core_clk, CLK_RESET_DEASSERT);
+	if (ret)
+		goto err_reset;
+	ret = clk_prepare_enable(drv->core_clk);
+	if (ret)
+		goto err_core_clk;
+	ret = clk_prepare_enable(drv->bus_clk);
+	if (ret)
+		goto err_bus_clk;
+	if (drv->mem_clk) {
+		ret = clk_prepare_enable(drv->mem_clk);
+		if (ret)
+			goto err_mem_clk;
+	}
+
+	return 0;
+
+err_mem_clk:
+	clk_disable_unprepare(drv->bus_clk);
+err_bus_clk:
+	clk_disable_unprepare(drv->core_clk);
+err_core_clk:
+	clk_reset(drv->core_clk, CLK_RESET_ASSERT);
+err_reset:
+	return ret;
+}
+EXPORT_SYMBOL(pil_q6v5_enable_clks);
+
+void pil_q6v5_disable_clks(struct pil_desc *pil)
+{
+	struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+
+	clk_disable_unprepare(drv->bus_clk);
+	clk_disable_unprepare(drv->core_clk);
+	clk_disable_unprepare(drv->mem_clk);
+	clk_reset(drv->core_clk, CLK_RESET_ASSERT);
+}
+EXPORT_SYMBOL(pil_q6v5_disable_clks);
+
 void pil_q6v5_shutdown(struct pil_desc *pil)
 {
 	u32 val;
@@ -172,11 +247,10 @@
 				     resource_size(res));
 	if (!drv->reg_base)
 		return ERR_PTR(-ENOMEM);
-
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-	drv->clk_base = devm_ioremap(&pdev->dev, res->start,
-				     resource_size(res));
-	if (!drv->clk_base)
+	drv->axi_halt_base = devm_ioremap(&pdev->dev, res->start,
+					  resource_size(res));
+	if (!drv->axi_halt_base)
 		return ERR_PTR(-ENOMEM);
 
 	desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
@@ -192,6 +266,14 @@
 	if (IS_ERR(drv->xo))
 		return ERR_CAST(drv->xo);
 
+	drv->bus_clk = devm_clk_get(&pdev->dev, "bus_clk");
+	if (IS_ERR(drv->bus_clk))
+		return ERR_CAST(drv->bus_clk);
+
+	drv->core_clk = devm_clk_get(&pdev->dev, "core_clk");
+	if (IS_ERR(drv->core_clk))
+		return ERR_CAST(drv->core_clk);
+
 	desc->dev = &pdev->dev;
 
 	return desc;
diff --git a/arch/arm/mach-msm/pil-q6v5.h b/arch/arm/mach-msm/pil-q6v5.h
index b17d4e7..e0d7a20 100644
--- a/arch/arm/mach-msm/pil-q6v5.h
+++ b/arch/arm/mach-msm/pil-q6v5.h
@@ -21,23 +21,29 @@
 
 struct q6v5_data {
 	void __iomem *reg_base;
-	void __iomem *clk_base;
+	struct clk *xo;
+	struct clk *bus_clk;
+	struct clk *core_clk;
+	struct clk *mem_clk;
 	void __iomem *axi_halt_base;
 	void __iomem *rmb_base;
+	void __iomem *restart_reg;
 	unsigned long start_addr;
 	struct regulator *vreg;
-	bool vreg_enabled;
+	bool is_booted;
 	int self_auth;
-	struct clk *xo;
 	struct pil_device *pil;
 };
 
 int pil_q6v5_make_proxy_votes(struct pil_desc *pil);
 void pil_q6v5_remove_proxy_votes(struct pil_desc *pil);
+void pil_q6v5_halt_axi_port(struct pil_desc *pil, void __iomem *halt_base);
 int pil_q6v5_init_image(struct pil_desc *pil, const u8 *metadata,
 			size_t size);
 void pil_q6v5_shutdown(struct pil_desc *pil);
 int pil_q6v5_reset(struct pil_desc *pil);
+int pil_q6v5_enable_clks(struct pil_desc *pil);
+void pil_q6v5_disable_clks(struct pil_desc *pil);
 struct pil_desc *pil_q6v5_init(struct platform_device *pdev);
 
 #endif
diff --git a/arch/arm/mach-msm/platsmp-8625.c b/arch/arm/mach-msm/platsmp-8625.c
index 3826b12..91f1133 100644
--- a/arch/arm/mach-msm/platsmp-8625.c
+++ b/arch/arm/mach-msm/platsmp-8625.c
@@ -170,6 +170,8 @@
 {
 	unsigned long timeout;
 
+	preset_lpj = loops_per_jiffy;
+
 	if (cold_boot_done == false) {
 		if (msm8625_release_secondary()) {
 			pr_err("Failed to release secondary core\n");
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index cbe5201..6f68c8b 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -21,11 +21,9 @@
 #include <linux/ktime.h>
 #include <linux/pm.h>
 #include <linux/pm_qos_params.h>
-#include <linux/proc_fs.h>
 #include <linux/smp.h>
 #include <linux/suspend.h>
 #include <linux/tick.h>
-#include <linux/uaccess.h>
 #include <linux/wakelock.h>
 #include <linux/delay.h>
 #include <mach/msm_iomap.h>
@@ -46,7 +44,6 @@
 #include <mach/cpuidle.h>
 #include "idle.h"
 #include "pm.h"
-#include "rpm_resources.h"
 #include "scm-boot.h"
 #include "spm.h"
 #include "timer.h"
@@ -111,6 +108,7 @@
 		"standalone_power_collapse",
 };
 
+static struct msm_pm_sleep_ops pm_sleep_ops;
 /*
  * Write out the attribute.
  */
@@ -319,220 +317,6 @@
 }
 
 /******************************************************************************
- * CONFIG_MSM_IDLE_STATS
- *****************************************************************************/
-
-#ifdef CONFIG_MSM_IDLE_STATS
-enum msm_pm_time_stats_id {
-	MSM_PM_STAT_REQUESTED_IDLE,
-	MSM_PM_STAT_IDLE_WFI,
-	MSM_PM_STAT_RETENTION,
-	MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE,
-	MSM_PM_STAT_IDLE_POWER_COLLAPSE,
-	MSM_PM_STAT_SUSPEND,
-	MSM_PM_STAT_COUNT
-};
-
-struct msm_pm_time_stats {
-	const char *name;
-	int64_t first_bucket_time;
-	int bucket[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
-	int64_t min_time[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
-	int64_t max_time[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
-	int count;
-	int64_t total_time;
-};
-
-struct msm_pm_cpu_time_stats {
-	struct msm_pm_time_stats stats[MSM_PM_STAT_COUNT];
-};
-
-static DEFINE_SPINLOCK(msm_pm_stats_lock);
-static DEFINE_PER_CPU_SHARED_ALIGNED(
-	struct msm_pm_cpu_time_stats, msm_pm_stats);
-
-/*
- * Add the given time data to the statistics collection.
- */
-static void msm_pm_add_stat(enum msm_pm_time_stats_id id, int64_t t)
-{
-	unsigned long flags;
-	struct msm_pm_time_stats *stats;
-	int64_t bt;
-	int i;
-
-	spin_lock_irqsave(&msm_pm_stats_lock, flags);
-	stats = __get_cpu_var(msm_pm_stats).stats;
-
-	stats[id].total_time += t;
-	stats[id].count++;
-
-	bt = t;
-	do_div(bt, stats[id].first_bucket_time);
-
-	if (bt < 1ULL << (CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT *
-				(CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1)))
-		i = DIV_ROUND_UP(fls((uint32_t)bt),
-					CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT);
-	else
-		i = CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1;
-
-	if (i >= CONFIG_MSM_IDLE_STATS_BUCKET_COUNT)
-		i = CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1;
-
-	stats[id].bucket[i]++;
-
-	if (t < stats[id].min_time[i] || !stats[id].max_time[i])
-		stats[id].min_time[i] = t;
-	if (t > stats[id].max_time[i])
-		stats[id].max_time[i] = t;
-
-	spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
-}
-
-/*
- * Helper function of snprintf where buf is auto-incremented, size is auto-
- * decremented, and there is no return value.
- *
- * NOTE: buf and size must be l-values (e.g. variables)
- */
-#define SNPRINTF(buf, size, format, ...) \
-	do { \
-		if (size > 0) { \
-			int ret; \
-			ret = snprintf(buf, size, format, ## __VA_ARGS__); \
-			if (ret > size) { \
-				buf += size; \
-				size = 0; \
-			} else { \
-				buf += ret; \
-				size -= ret; \
-			} \
-		} \
-	} while (0)
-
-/*
- * Write out the power management statistics.
- */
-static int msm_pm_read_proc
-	(char *page, char **start, off_t off, int count, int *eof, void *data)
-{
-	unsigned int cpu = off / MSM_PM_STAT_COUNT;
-	int id = off % MSM_PM_STAT_COUNT;
-	char *p = page;
-
-	if (count < 1024) {
-		*start = (char *) 0;
-		*eof = 0;
-		return 0;
-	}
-
-	if (cpu < num_possible_cpus()) {
-		unsigned long flags;
-		struct msm_pm_time_stats *stats;
-		int i;
-		int64_t bucket_time;
-		int64_t s;
-		uint32_t ns;
-
-		spin_lock_irqsave(&msm_pm_stats_lock, flags);
-		stats = per_cpu(msm_pm_stats, cpu).stats;
-
-		s = stats[id].total_time;
-		ns = do_div(s, NSEC_PER_SEC);
-		SNPRINTF(p, count,
-			"[cpu %u] %s:\n"
-			"  count: %7d\n"
-			"  total_time: %lld.%09u\n",
-			cpu, stats[id].name,
-			stats[id].count,
-			s, ns);
-
-		bucket_time = stats[id].first_bucket_time;
-		for (i = 0; i < CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1; i++) {
-			s = bucket_time;
-			ns = do_div(s, NSEC_PER_SEC);
-			SNPRINTF(p, count,
-				"   <%6lld.%09u: %7d (%lld-%lld)\n",
-				s, ns, stats[id].bucket[i],
-				stats[id].min_time[i],
-				stats[id].max_time[i]);
-
-			bucket_time <<= CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT;
-		}
-
-		SNPRINTF(p, count, "  >=%6lld.%09u: %7d (%lld-%lld)\n",
-			s, ns, stats[id].bucket[i],
-			stats[id].min_time[i],
-			stats[id].max_time[i]);
-
-		*start = (char *) 1;
-		*eof = (off + 1 >= MSM_PM_STAT_COUNT * num_possible_cpus());
-
-		spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
-	}
-
-	return p - page;
-}
-#undef SNPRINTF
-
-#define MSM_PM_STATS_RESET "reset"
-
-/*
- * Reset the power management statistics values.
- */
-static int msm_pm_write_proc(struct file *file, const char __user *buffer,
-	unsigned long count, void *data)
-{
-	char buf[sizeof(MSM_PM_STATS_RESET)];
-	int ret;
-	unsigned long flags;
-	unsigned int cpu;
-
-	if (count < strlen(MSM_PM_STATS_RESET)) {
-		ret = -EINVAL;
-		goto write_proc_failed;
-	}
-
-	if (copy_from_user(buf, buffer, strlen(MSM_PM_STATS_RESET))) {
-		ret = -EFAULT;
-		goto write_proc_failed;
-	}
-
-	if (memcmp(buf, MSM_PM_STATS_RESET, strlen(MSM_PM_STATS_RESET))) {
-		ret = -EINVAL;
-		goto write_proc_failed;
-	}
-
-	spin_lock_irqsave(&msm_pm_stats_lock, flags);
-	for_each_possible_cpu(cpu) {
-		struct msm_pm_time_stats *stats;
-		int i;
-
-		stats = per_cpu(msm_pm_stats, cpu).stats;
-		for (i = 0; i < MSM_PM_STAT_COUNT; i++) {
-			memset(stats[i].bucket,
-				0, sizeof(stats[i].bucket));
-			memset(stats[i].min_time,
-				0, sizeof(stats[i].min_time));
-			memset(stats[i].max_time,
-				0, sizeof(stats[i].max_time));
-			stats[i].count = 0;
-			stats[i].total_time = 0;
-		}
-	}
-
-	spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
-	return count;
-
-write_proc_failed:
-	return ret;
-}
-#undef MSM_PM_STATS_RESET
-#endif /* CONFIG_MSM_IDLE_STATS */
-
-
-/******************************************************************************
  * Configure Hardware before/after Low Power Mode
  *****************************************************************************/
 
@@ -612,7 +396,7 @@
  *
  *****************************************************************************/
 
-static struct msm_rpmrs_limits *msm_pm_idle_rs_limits;
+static void *msm_pm_idle_rs_limits;
 static bool msm_pm_use_qtimer;
 
 static void msm_pm_swfi(void)
@@ -805,6 +589,38 @@
 	msm_timer_exit_idle((int) timer_halted);
 }
 
+static int64_t msm_pm_timer_enter_suspend(int64_t *period)
+{
+	int time = 0;
+
+	if (msm_pm_use_qtimer)
+		return sched_clock();
+
+	time = msm_timer_get_sclk_time(period);
+	if (!time)
+		pr_err("%s: Unable to read sclk.\n", __func__);
+
+	return time;
+}
+
+static int64_t msm_pm_timer_exit_suspend(int64_t time, int64_t period)
+{
+	if (msm_pm_use_qtimer)
+		return sched_clock() - time;
+
+	if (time != 0) {
+		int64_t end_time = msm_timer_get_sclk_time(NULL);
+		if (end_time != 0) {
+			time = end_time - time;
+			if (time < 0)
+				time += period;
+		} else
+			time = 0;
+	}
+
+	return time;
+}
+
 /******************************************************************************
  * External Idle/Suspend Functions
  *****************************************************************************/
@@ -828,7 +644,8 @@
 		struct cpuidle_state *state = &dev->states[i];
 		enum msm_pm_sleep_mode mode;
 		bool allow;
-		struct msm_rpmrs_limits *rs_limits = NULL;
+		void *rs_limits = NULL;
+		uint32_t power;
 		int idx;
 
 		mode = (enum msm_pm_sleep_mode) state->driver_data;
@@ -857,12 +674,6 @@
 		case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
 			if (!allow)
 				break;
-
-			if (!dev->cpu &&
-				msm_rpm_local_request_is_outstanding()) {
-				allow = false;
-				break;
-			}
 			/* fall through */
 
 		case MSM_PM_SLEEP_MODE_RETENTION:
@@ -874,8 +685,10 @@
 			if (!allow)
 				break;
 
-			rs_limits = msm_rpmrs_lowest_limits(true,
-						mode, latency_us, sleep_us);
+			if (pm_sleep_ops.lowest_limits)
+				rs_limits = pm_sleep_ops.lowest_limits(true,
+						mode, latency_us, sleep_us,
+						&power);
 
 			if (MSM_PM_DEBUG_IDLE & msm_pm_debug_mask)
 				pr_info("CPU%u: %s: %s, latency %uus, "
@@ -883,17 +696,6 @@
 					dev->cpu, __func__, state->desc,
 					latency_us, sleep_us, rs_limits);
 
-			if ((MSM_PM_DEBUG_IDLE_LIMITS & msm_pm_debug_mask) &&
-					rs_limits)
-				pr_info("CPU%u: %s: limit %p: "
-					"pxo %d, l2_cache %d, "
-					"vdd_mem %d, vdd_dig %d\n",
-					dev->cpu, __func__, rs_limits,
-					rs_limits->pxo,
-					rs_limits->l2_cache,
-					rs_limits->vdd_mem,
-					rs_limits->vdd_dig);
-
 			if (!rs_limits)
 				allow = false;
 			break;
@@ -911,7 +713,7 @@
 			state->flags &= ~CPUIDLE_FLAG_IGNORE;
 			state->target_residency = 0;
 			state->exit_latency = 0;
-			state->power_usage = rs_limits->power[dev->cpu];
+			state->power_usage = power;
 
 			if (MSM_PM_SLEEP_MODE_POWER_COLLAPSE == mode)
 				msm_pm_idle_rs_limits = rs_limits;
@@ -926,9 +728,7 @@
 int msm_pm_idle_enter(enum msm_pm_sleep_mode sleep_mode)
 {
 	int64_t time;
-#ifdef CONFIG_MSM_IDLE_STATS
 	int exit_stat;
-#endif
 
 	if (MSM_PM_DEBUG_IDLE & msm_pm_debug_mask)
 		pr_info("CPU%u: %s: mode %d\n",
@@ -939,30 +739,24 @@
 	switch (sleep_mode) {
 	case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
 		msm_pm_swfi();
-#ifdef CONFIG_MSM_IDLE_STATS
 		exit_stat = MSM_PM_STAT_IDLE_WFI;
-#endif
 		break;
 
 	case MSM_PM_SLEEP_MODE_RETENTION:
 		msm_pm_retention();
-#ifdef CONFIG_MSM_IDLE_STATS
 		exit_stat = MSM_PM_STAT_RETENTION;
-#endif
 		break;
 
 	case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
 		msm_pm_power_collapse_standalone(true);
-#ifdef CONFIG_MSM_IDLE_STATS
 		exit_stat = MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE;
-#endif
 		break;
 
 	case MSM_PM_SLEEP_MODE_POWER_COLLAPSE: {
 		int64_t timer_expiration = 0;
 		bool timer_halted = false;
 		uint32_t sleep_delay;
-		int ret;
+		int ret = -ENODEV;
 		int notify_rpm =
 			(sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE);
 		int collapsed;
@@ -977,20 +771,20 @@
 		if (MSM_PM_DEBUG_IDLE_CLK & msm_pm_debug_mask)
 			clock_debug_print_enabled();
 
-		ret = msm_rpmrs_enter_sleep(
-			sleep_delay, msm_pm_idle_rs_limits, true, notify_rpm);
+		if (pm_sleep_ops.enter_sleep)
+			ret = pm_sleep_ops.enter_sleep(sleep_delay,
+					msm_pm_idle_rs_limits,
+					true, notify_rpm);
 		if (!ret) {
 			collapsed = msm_pm_power_collapse(true);
 			timer_halted = true;
 
-			msm_rpmrs_exit_sleep(msm_pm_idle_rs_limits, true,
-					notify_rpm, collapsed);
+			if (pm_sleep_ops.exit_sleep)
+				pm_sleep_ops.exit_sleep(msm_pm_idle_rs_limits,
+						true, notify_rpm, collapsed);
 		}
 		msm_pm_timer_exit_idle(timer_halted);
-
-#ifdef CONFIG_MSM_IDLE_STATS
 		exit_stat = MSM_PM_STAT_IDLE_POWER_COLLAPSE;
-#endif
 		break;
 	}
 
@@ -1000,9 +794,7 @@
 	}
 
 	time = ktime_to_ns(ktime_get()) - time;
-#ifdef CONFIG_MSM_IDLE_STATS
 	msm_pm_add_stat(exit_stat, time);
-#endif
 
 	do_div(time, 1000);
 	return (int) time;
@@ -1097,11 +889,8 @@
 {
 	bool allow[MSM_PM_SLEEP_MODE_NR];
 	int i;
-
-#ifdef CONFIG_MSM_IDLE_STATS
 	int64_t period = 0;
-	int64_t time = msm_timer_get_sclk_time(&period);
-#endif
+	int64_t time = msm_pm_timer_enter_suspend(&period);
 
 	if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
 		pr_info("%s\n", __func__);
@@ -1120,8 +909,9 @@
 	}
 
 	if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE]) {
-		struct msm_rpmrs_limits *rs_limits;
-		int ret;
+		void *rs_limits = NULL;
+		int ret = -ENODEV;
+		uint32_t power;
 
 		if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
 			pr_info("%s: power collapse\n", __func__);
@@ -1136,46 +926,29 @@
 			msm_pm_sleep_time_override = 0;
 		}
 #endif /* CONFIG_MSM_SLEEP_TIME_OVERRIDE */
-
-		if (MSM_PM_DEBUG_SUSPEND_LIMITS & msm_pm_debug_mask)
-			msm_rpmrs_show_resources();
-
-		rs_limits = msm_rpmrs_lowest_limits(false,
-				MSM_PM_SLEEP_MODE_POWER_COLLAPSE, -1, -1);
-
-		if ((MSM_PM_DEBUG_SUSPEND_LIMITS & msm_pm_debug_mask) &&
-				rs_limits)
-			pr_info("%s: limit %p: pxo %d, l2_cache %d, "
-				"vdd_mem %d, vdd_dig %d\n",
-				__func__, rs_limits,
-				rs_limits->pxo, rs_limits->l2_cache,
-				rs_limits->vdd_mem, rs_limits->vdd_dig);
+		if (pm_sleep_ops.lowest_limits)
+			rs_limits = pm_sleep_ops.lowest_limits(false,
+					MSM_PM_SLEEP_MODE_POWER_COLLAPSE, -1,
+					-1, &power);
 
 		if (rs_limits) {
-			ret = msm_rpmrs_enter_sleep(
-				msm_pm_max_sleep_time, rs_limits, false, true);
+			if (pm_sleep_ops.enter_sleep)
+				ret = pm_sleep_ops.enter_sleep(
+						msm_pm_max_sleep_time,
+						rs_limits, false, true);
 			if (!ret) {
 				int collapsed = msm_pm_power_collapse(false);
-				msm_rpmrs_exit_sleep(rs_limits, false, true,
-						collapsed);
+				if (pm_sleep_ops.exit_sleep) {
+					pm_sleep_ops.exit_sleep(rs_limits,
+						false, true, collapsed);
+				}
 			}
 		} else {
 			pr_err("%s: cannot find the lowest power limit\n",
 				__func__);
 		}
-
-#ifdef CONFIG_MSM_IDLE_STATS
-		if (time != 0) {
-			int64_t end_time = msm_timer_get_sclk_time(NULL);
-			if (end_time != 0) {
-				time = end_time - time;
-				if (time < 0)
-					time += period;
-			} else
-				time = 0;
-		}
+		time = msm_pm_timer_exit_suspend(time, period);
 		msm_pm_add_stat(MSM_PM_STAT_SUSPEND, time);
-#endif /* CONFIG_MSM_IDLE_STATS */
 	} else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE]) {
 		if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
 			pr_info("%s: standalone power collapse\n", __func__);
@@ -1212,15 +985,25 @@
 	msm_pm_slp_sts = data;
 }
 
+void msm_pm_set_sleep_ops(struct msm_pm_sleep_ops *ops)
+{
+	if (ops)
+		pm_sleep_ops = *ops;
+}
+
 static int __init msm_pm_init(void)
 {
 	pgd_t *pc_pgd;
 	pmd_t *pmd;
 	unsigned long pmdval;
-#ifdef CONFIG_MSM_IDLE_STATS
-	unsigned int cpu;
-	struct proc_dir_entry *d_entry;
-#endif
+	enum msm_pm_time_stats_id enable_stats[] = {
+		MSM_PM_STAT_IDLE_WFI,
+		MSM_PM_STAT_RETENTION,
+		MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE,
+		MSM_PM_STAT_IDLE_POWER_COLLAPSE,
+		MSM_PM_STAT_SUSPEND,
+	};
+
 	/* Page table for cores to come back up safely. */
 	pc_pgd = pgd_alloc(&init_mm);
 	if (!pc_pgd)
@@ -1257,49 +1040,9 @@
 	clean_caches((unsigned long)&msm_pm_pc_pgd, sizeof(msm_pm_pc_pgd),
 		     virt_to_phys(&msm_pm_pc_pgd));
 
-#ifdef CONFIG_MSM_IDLE_STATS
-	for_each_possible_cpu(cpu) {
-		struct msm_pm_time_stats *stats =
-			per_cpu(msm_pm_stats, cpu).stats;
-
-		stats[MSM_PM_STAT_REQUESTED_IDLE].name = "idle-request";
-		stats[MSM_PM_STAT_REQUESTED_IDLE].first_bucket_time =
-			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-
-		stats[MSM_PM_STAT_IDLE_WFI].name = "idle-wfi";
-		stats[MSM_PM_STAT_IDLE_WFI].first_bucket_time =
-			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-
-		stats[MSM_PM_STAT_RETENTION].name = "retention";
-		stats[MSM_PM_STAT_RETENTION].first_bucket_time =
-			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-
-		stats[MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE].name =
-			"idle-standalone-power-collapse";
-		stats[MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE].
-			first_bucket_time = CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-
-		stats[MSM_PM_STAT_IDLE_POWER_COLLAPSE].name =
-			"idle-power-collapse";
-		stats[MSM_PM_STAT_IDLE_POWER_COLLAPSE].first_bucket_time =
-			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-
-		stats[MSM_PM_STAT_SUSPEND].name = "suspend";
-		stats[MSM_PM_STAT_SUSPEND].first_bucket_time =
-			CONFIG_MSM_SUSPEND_STATS_FIRST_BUCKET;
-	}
-
-	d_entry = create_proc_entry("msm_pm_stats",
-			S_IRUGO | S_IWUSR | S_IWGRP, NULL);
-	if (d_entry) {
-		d_entry->read_proc = msm_pm_read_proc;
-		d_entry->write_proc = msm_pm_write_proc;
-		d_entry->data = NULL;
-	}
-#endif  /* CONFIG_MSM_IDLE_STATS */
-
-
 	msm_pm_mode_sysfs_add();
+	msm_pm_add_stats(enable_stats, ARRAY_SIZE(enable_stats));
+
 	msm_spm_allow_x_cpu_set_vdd(false);
 
 	suspend_set_ops(&msm_pm_ops);
diff --git a/arch/arm/mach-msm/pm-boot.c b/arch/arm/mach-msm/pm-boot.c
index f6105af1..079ed9c 100644
--- a/arch/arm/mach-msm/pm-boot.c
+++ b/arch/arm/mach-msm/pm-boot.c
@@ -41,7 +41,7 @@
 }
 
 #ifdef CONFIG_MSM_SCM
-static int __init msm_pm_tz_boot_init(void)
+static int __devinit msm_pm_tz_boot_init(void)
 {
 	int flag = 0;
 	if (num_possible_cpus() == 1)
@@ -72,7 +72,7 @@
 		unsigned long entry) {}
 #endif
 
-static int __init msm_pm_boot_reset_vector_init(uint32_t *reset_vector)
+static int __devinit msm_pm_boot_reset_vector_init(uint32_t *reset_vector)
 {
 	if (!reset_vector)
 		return -ENODEV;
@@ -110,7 +110,7 @@
 }
 #define BOOT_REMAP_ENABLE  BIT(0)
 
-int __init msm_pm_boot_init(struct msm_pm_boot_platform_data *pdata)
+int __devinit msm_pm_boot_init(struct msm_pm_boot_platform_data *pdata)
 {
 	int ret = 0;
 	unsigned long entry;
diff --git a/arch/arm/mach-msm/pm-stats.c b/arch/arm/mach-msm/pm-stats.c
new file mode 100644
index 0000000..936820a
--- /dev/null
+++ b/arch/arm/mach-msm/pm-stats.c
@@ -0,0 +1,305 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/uaccess.h>
+#include <linux/proc_fs.h>
+
+#include "pm.h"
+
+struct msm_pm_time_stats {
+	const char *name;
+	int64_t first_bucket_time;
+	int bucket[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
+	int64_t min_time[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
+	int64_t max_time[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
+	int count;
+	int64_t total_time;
+	bool enabled;
+};
+
+struct msm_pm_cpu_time_stats {
+	struct msm_pm_time_stats stats[MSM_PM_STAT_COUNT];
+};
+
+static DEFINE_SPINLOCK(msm_pm_stats_lock);
+static DEFINE_PER_CPU_SHARED_ALIGNED(
+	struct msm_pm_cpu_time_stats, msm_pm_stats);
+
+/*
+ * Add the given time data to the statistics collection.
+ */
+void msm_pm_add_stat(enum msm_pm_time_stats_id id, int64_t t)
+{
+	unsigned long flags;
+	struct msm_pm_time_stats *stats;
+	int64_t bt;
+	int i;
+
+	spin_lock_irqsave(&msm_pm_stats_lock, flags);
+	stats = __get_cpu_var(msm_pm_stats).stats;
+
+	if (!stats[id].enabled)
+		goto add_bail;
+
+	stats[id].total_time += t;
+	stats[id].count++;
+
+	bt = t;
+	do_div(bt, stats[id].first_bucket_time);
+
+	if (bt < 1ULL << (CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT *
+				(CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1)))
+		i = DIV_ROUND_UP(fls((uint32_t)bt),
+					CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT);
+	else
+		i = CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1;
+
+	if (i >= CONFIG_MSM_IDLE_STATS_BUCKET_COUNT)
+		i = CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1;
+
+	stats[id].bucket[i]++;
+
+	if (t < stats[id].min_time[i] || !stats[id].max_time[i])
+		stats[id].min_time[i] = t;
+	if (t > stats[id].max_time[i])
+		stats[id].max_time[i] = t;
+
+add_bail:
+	spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
+}
+
+/*
+ * Helper function of snprintf where buf is auto-incremented, size is auto-
+ * decremented, and there is no return value.
+ *
+ * NOTE: buf and size must be l-values (e.g. variables)
+ */
+#define SNPRINTF(buf, size, format, ...) \
+	do { \
+		if (size > 0) { \
+			int ret; \
+			ret = snprintf(buf, size, format, ## __VA_ARGS__); \
+			if (ret > size) { \
+				buf += size; \
+				size = 0; \
+			} else { \
+				buf += ret; \
+				size -= ret; \
+			} \
+		} \
+	} while (0)
+
+/*
+ * Write out the power management statistics.
+ */
+static int msm_pm_read_proc
+	(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	unsigned int cpu = off / MSM_PM_STAT_COUNT;
+	int id = off % MSM_PM_STAT_COUNT;
+	char *p = page;
+
+	if (count < 1024) {
+		*start = (char *) 0;
+		*eof = 0;
+		return 0;
+	}
+
+	if (cpu < num_possible_cpus()) {
+		unsigned long flags;
+		struct msm_pm_time_stats *stats;
+		int i;
+		int64_t bucket_time;
+		int64_t s;
+		uint32_t ns;
+
+		spin_lock_irqsave(&msm_pm_stats_lock, flags);
+		stats = per_cpu(msm_pm_stats, cpu).stats;
+
+		/* Skip the disabled ones */
+		if (!stats[id].enabled) {
+			*p = '\0';
+			p++;
+			goto again;
+		}
+
+		s = stats[id].total_time;
+		ns = do_div(s, NSEC_PER_SEC);
+		SNPRINTF(p, count,
+			"[cpu %u] %s:\n"
+			"  count: %7d\n"
+			"  total_time: %lld.%09u\n",
+			cpu, stats[id].name,
+			stats[id].count,
+			s, ns);
+
+		bucket_time = stats[id].first_bucket_time;
+		for (i = 0; i < CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1; i++) {
+			s = bucket_time;
+			ns = do_div(s, NSEC_PER_SEC);
+			SNPRINTF(p, count,
+				"   <%6lld.%09u: %7d (%lld-%lld)\n",
+				s, ns, stats[id].bucket[i],
+				stats[id].min_time[i],
+				stats[id].max_time[i]);
+
+			bucket_time <<= CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT;
+		}
+
+		SNPRINTF(p, count, "  >=%6lld.%09u: %7d (%lld-%lld)\n",
+			s, ns, stats[id].bucket[i],
+			stats[id].min_time[i],
+			stats[id].max_time[i]);
+
+again:
+		*start = (char *) 1;
+		*eof = (off + 1 >= MSM_PM_STAT_COUNT * num_possible_cpus());
+
+		spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
+	}
+
+	return p - page;
+}
+#undef SNPRINTF
+
+#define MSM_PM_STATS_RESET "reset"
+
+/*
+ * Reset the power management statistics values.
+ */
+static int msm_pm_write_proc(struct file *file, const char __user *buffer,
+	unsigned long count, void *data)
+{
+	char buf[sizeof(MSM_PM_STATS_RESET)];
+	int ret;
+	unsigned long flags;
+	unsigned int cpu;
+
+	if (count < sizeof(MSM_PM_STATS_RESET)) {
+		ret = -EINVAL;
+		goto write_proc_failed;
+	}
+
+	if (copy_from_user(buf, buffer, sizeof(MSM_PM_STATS_RESET))) {
+		ret = -EFAULT;
+		goto write_proc_failed;
+	}
+
+	if (memcmp(buf, MSM_PM_STATS_RESET, sizeof(MSM_PM_STATS_RESET))) {
+		ret = -EINVAL;
+		goto write_proc_failed;
+	}
+
+	spin_lock_irqsave(&msm_pm_stats_lock, flags);
+	for_each_possible_cpu(cpu) {
+		struct msm_pm_time_stats *stats;
+		int i;
+
+		stats = per_cpu(msm_pm_stats, cpu).stats;
+		for (i = 0; i < MSM_PM_STAT_COUNT; i++) {
+			memset(stats[i].bucket,
+				0, sizeof(stats[i].bucket));
+			memset(stats[i].min_time,
+				0, sizeof(stats[i].min_time));
+			memset(stats[i].max_time,
+				0, sizeof(stats[i].max_time));
+			stats[i].count = 0;
+			stats[i].total_time = 0;
+		}
+	}
+
+	spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
+	return count;
+
+write_proc_failed:
+	return ret;
+}
+#undef MSM_PM_STATS_RESET
+
+void msm_pm_add_stats(enum msm_pm_time_stats_id *enable_stats, int size)
+{
+	unsigned int cpu;
+	struct proc_dir_entry *d_entry;
+	int i = 0;
+
+	for_each_possible_cpu(cpu) {
+		struct msm_pm_time_stats *stats =
+			per_cpu(msm_pm_stats, cpu).stats;
+
+		stats[MSM_PM_STAT_REQUESTED_IDLE].name = "idle-request";
+		stats[MSM_PM_STAT_REQUESTED_IDLE].first_bucket_time =
+			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
+
+		stats[MSM_PM_STAT_IDLE_SPIN].name = "idle-spin";
+		stats[MSM_PM_STAT_IDLE_SPIN].first_bucket_time =
+			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
+
+		stats[MSM_PM_STAT_IDLE_WFI].name = "idle-wfi";
+		stats[MSM_PM_STAT_IDLE_WFI].first_bucket_time =
+			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
+
+		stats[MSM_PM_STAT_RETENTION].name = "retention";
+		stats[MSM_PM_STAT_RETENTION].first_bucket_time =
+			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
+
+		stats[MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE].name =
+			"idle-standalone-power-collapse";
+		stats[MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE].
+			first_bucket_time = CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
+
+		stats[MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE].name =
+			"idle-failed-standalone-power-collapse";
+		stats[MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE].
+			first_bucket_time =
+			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
+
+		stats[MSM_PM_STAT_IDLE_POWER_COLLAPSE].name =
+			"idle-power-collapse";
+		stats[MSM_PM_STAT_IDLE_POWER_COLLAPSE].first_bucket_time =
+			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
+
+		stats[MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE].name =
+			"idle-failed-power-collapse";
+		stats[MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE].
+			first_bucket_time =
+			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
+
+		stats[MSM_PM_STAT_SUSPEND].name = "suspend";
+		stats[MSM_PM_STAT_SUSPEND].first_bucket_time =
+			CONFIG_MSM_SUSPEND_STATS_FIRST_BUCKET;
+
+		stats[MSM_PM_STAT_FAILED_SUSPEND].name = "failed-suspend";
+		stats[MSM_PM_STAT_FAILED_SUSPEND].first_bucket_time =
+			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
+
+		stats[MSM_PM_STAT_NOT_IDLE].name = "not-idle";
+		stats[MSM_PM_STAT_NOT_IDLE].first_bucket_time =
+			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
+
+		for (i = 0; i < size; i++)
+			stats[enable_stats[i]].enabled = true;
+
+	}
+
+	d_entry = create_proc_entry("msm_pm_stats",
+			S_IRUGO | S_IWUSR | S_IWGRP, NULL);
+	if (d_entry) {
+		d_entry->read_proc = msm_pm_read_proc;
+		d_entry->write_proc = msm_pm_write_proc;
+		d_entry->data = NULL;
+	}
+}
diff --git a/arch/arm/mach-msm/pm.c b/arch/arm/mach-msm/pm.c
deleted file mode 100644
index d684a5a..0000000
--- a/arch/arm/mach-msm/pm.c
+++ /dev/null
@@ -1,895 +0,0 @@
-/* arch/arm/mach-msm/pm.c
- *
- * MSM Power Management Routines
- *
- * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/pm.h>
-#include <linux/pm_qos_params.h>
-#include <linux/proc_fs.h>
-#include <linux/suspend.h>
-#include <linux/reboot.h>
-#include <linux/uaccess.h>
-#include <mach/msm_iomap.h>
-#include <mach/system.h>
-#include <asm/io.h>
-
-#ifdef CONFIG_HAS_WAKELOCK
-#include <linux/wakelock.h>
-#endif
-
-#include "smd_private.h"
-#include "smd_rpcrouter.h"
-#include "acpuclock.h"
-#include "clock.h"
-#include "proc_comm.h"
-#include "idle.h"
-#include "irq.h"
-#include "gpio.h"
-#include "timer.h"
-#include "pm.h"
-#include "pm-boot.h"
-
-enum {
-	MSM_PM_DEBUG_SUSPEND = 1U << 0,
-	MSM_PM_DEBUG_POWER_COLLAPSE = 1U << 1,
-	MSM_PM_DEBUG_STATE = 1U << 2,
-	MSM_PM_DEBUG_CLOCK = 1U << 3,
-	MSM_PM_DEBUG_RESET_VECTOR = 1U << 4,
-	MSM_PM_DEBUG_SMSM_STATE = 1U << 5,
-	MSM_PM_DEBUG_IDLE = 1U << 6,
-};
-static int msm_pm_debug_mask;
-module_param_named(debug_mask, msm_pm_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
-
-#ifdef CONFIG_MSM_SLEEP_TIME_OVERRIDE
-static int msm_pm_sleep_time_override;
-module_param_named(sleep_time_override,
-	msm_pm_sleep_time_override, int, S_IRUGO | S_IWUSR | S_IWGRP);
-#endif
-
-static int msm_pm_sleep_mode = CONFIG_MSM7X00A_SLEEP_MODE;
-module_param_named(sleep_mode, msm_pm_sleep_mode, int, S_IRUGO | S_IWUSR | S_IWGRP);
-static int msm_pm_idle_sleep_mode = CONFIG_MSM7X00A_IDLE_SLEEP_MODE;
-module_param_named(idle_sleep_mode, msm_pm_idle_sleep_mode, int, S_IRUGO | S_IWUSR | S_IWGRP);
-static int msm_pm_idle_sleep_min_time = CONFIG_MSM7X00A_IDLE_SLEEP_MIN_TIME;
-module_param_named(idle_sleep_min_time, msm_pm_idle_sleep_min_time, int, S_IRUGO | S_IWUSR | S_IWGRP);
-static int msm_pm_idle_spin_time = CONFIG_MSM7X00A_IDLE_SPIN_TIME;
-module_param_named(idle_spin_time, msm_pm_idle_spin_time, int, S_IRUGO | S_IWUSR | S_IWGRP);
-
-#define A11S_CLK_SLEEP_EN (MSM_CSR_BASE + 0x11c)
-#define A11S_PWRDOWN (MSM_CSR_BASE + 0x440)
-#define A11S_STANDBY_CTL (MSM_CSR_BASE + 0x108)
-#define A11RAMBACKBIAS (MSM_CSR_BASE + 0x508)
-
-enum {
-	SLEEP_LIMIT_NONE = 0,
-	SLEEP_LIMIT_NO_TCXO_SHUTDOWN = 2
-};
-
-static atomic_t msm_pm_init_done = ATOMIC_INIT(0);
-struct smsm_interrupt_info_ext {
-	uint32_t aArm_en_mask;
-	uint32_t aArm_interrupts_pending;
-	uint32_t aArm_wakeup_reason;
-	uint32_t aArm_rpc_prog;
-	uint32_t aArm_rpc_proc;
-	char aArm_smd_port_name[20];
-	uint32_t aArm_gpio_info;
-};
-static struct msm_pm_smem_addr_t {
-	uint32_t *sleep_delay;
-	uint32_t *limit_sleep;
-	struct smsm_interrupt_info *int_info;
-	struct smsm_interrupt_info_ext *int_info_ext;
-} msm_pm_sma;
-
-static uint32_t msm_pm_max_sleep_time;
-static struct msm_pm_platform_data *msm_pm_modes;
-
-#ifdef CONFIG_MSM_IDLE_STATS
-enum msm_pm_time_stats_id {
-	MSM_PM_STAT_REQUESTED_IDLE,
-	MSM_PM_STAT_IDLE_SPIN,
-	MSM_PM_STAT_IDLE_WFI,
-	MSM_PM_STAT_IDLE_SLEEP,
-	MSM_PM_STAT_IDLE_FAILED_SLEEP,
-	MSM_PM_STAT_IDLE_POWER_COLLAPSE,
-	MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE,
-	MSM_PM_STAT_SUSPEND,
-	MSM_PM_STAT_FAILED_SUSPEND,
-	MSM_PM_STAT_NOT_IDLE,
-	MSM_PM_STAT_COUNT
-};
-
-static struct msm_pm_time_stats {
-	const char *name;
-	int64_t first_bucket_time;
-	int bucket[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
-	int64_t min_time[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
-	int64_t max_time[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
-	int count;
-	int64_t total_time;
-} msm_pm_stats[MSM_PM_STAT_COUNT] = {
-	[MSM_PM_STAT_REQUESTED_IDLE].name = "idle-request",
-	[MSM_PM_STAT_REQUESTED_IDLE].first_bucket_time =
-		CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
-
-	[MSM_PM_STAT_IDLE_SPIN].name = "idle-spin",
-	[MSM_PM_STAT_IDLE_SPIN].first_bucket_time =
-		CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
-
-	[MSM_PM_STAT_IDLE_WFI].name = "idle-wfi",
-	[MSM_PM_STAT_IDLE_WFI].first_bucket_time =
-		CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
-
-	[MSM_PM_STAT_IDLE_SLEEP].name = "idle-sleep",
-	[MSM_PM_STAT_IDLE_SLEEP].first_bucket_time =
-		CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
-
-	[MSM_PM_STAT_IDLE_FAILED_SLEEP].name = "idle-failed-sleep",
-	[MSM_PM_STAT_IDLE_FAILED_SLEEP].first_bucket_time =
-		CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
-
-	[MSM_PM_STAT_IDLE_POWER_COLLAPSE].name = "idle-power-collapse",
-	[MSM_PM_STAT_IDLE_POWER_COLLAPSE].first_bucket_time =
-		CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
-
-	[MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE].name =
-		"idle-failed-power-collapse",
-	[MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE].first_bucket_time =
-		CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
-
-	[MSM_PM_STAT_SUSPEND].name = "suspend",
-	[MSM_PM_STAT_SUSPEND].first_bucket_time =
-		CONFIG_MSM_SUSPEND_STATS_FIRST_BUCKET,
-
-	[MSM_PM_STAT_FAILED_SUSPEND].name = "failed-suspend",
-	[MSM_PM_STAT_FAILED_SUSPEND].first_bucket_time =
-		CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
-
-	[MSM_PM_STAT_NOT_IDLE].name = "not-idle",
-	[MSM_PM_STAT_NOT_IDLE].first_bucket_time =
-		CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
-};
-
-static void msm_pm_add_stat(enum msm_pm_time_stats_id id, int64_t t)
-{
-	int i;
-	int64_t bt;
-	msm_pm_stats[id].total_time += t;
-	msm_pm_stats[id].count++;
-	bt = t;
-	do_div(bt, msm_pm_stats[id].first_bucket_time);
-	if (bt < 1ULL << (CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT *
-				(CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1)))
-		i = DIV_ROUND_UP(fls((uint32_t)bt),
-					CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT);
-	else
-		i = CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1;
-	msm_pm_stats[id].bucket[i]++;
-	if (t < msm_pm_stats[id].min_time[i] || !msm_pm_stats[id].max_time[i])
-		msm_pm_stats[id].min_time[i] = t;
-	if (t > msm_pm_stats[id].max_time[i])
-		msm_pm_stats[id].max_time[i] = t;
-}
-
-static uint32_t msm_pm_sleep_limit = SLEEP_LIMIT_NONE;
-#endif
-
-static int
-msm_pm_wait_state(uint32_t wait_state_all_set, uint32_t wait_state_all_clear,
-                  uint32_t wait_state_any_set, uint32_t wait_state_any_clear)
-{
-	int i;
-	uint32_t state;
-
-	for (i = 0; i < 2000000; i++) {
-		state = smsm_get_state(SMSM_MODEM_STATE);
-		if (((state & wait_state_all_set) == wait_state_all_set) &&
-		    ((~state & wait_state_all_clear) == wait_state_all_clear) &&
-		    (wait_state_any_set == 0 || (state & wait_state_any_set) ||
-		     wait_state_any_clear == 0 || (state & wait_state_any_clear)))
-			return 0;
-	}
-	printk(KERN_ERR "msm_pm_wait_state(%x, %x, %x, %x) failed %x\n",
-	       wait_state_all_set, wait_state_all_clear,
-	       wait_state_any_set, wait_state_any_clear, state);
-	return -ETIMEDOUT;
-}
-
-/*
- * Respond to timing out waiting for Modem
- *
- * NOTE: The function never returns.
- */
-static void msm_pm_timeout(void)
-{
-#if defined(CONFIG_MSM_PM_TIMEOUT_RESET_CHIP)
-	printk(KERN_EMERG "%s(): resetting chip\n", __func__);
-	msm_proc_comm(PCOM_RESET_CHIP_IMM, NULL, NULL);
-#elif defined(CONFIG_MSM_PM_TIMEOUT_RESET_MODEM)
-	printk(KERN_EMERG "%s(): resetting modem\n", __func__);
-	msm_proc_comm_reset_modem_now();
-#elif defined(CONFIG_MSM_PM_TIMEOUT_HALT)
-	printk(KERN_EMERG "%s(): halting\n", __func__);
-#endif
-	for (;;)
-		;
-}
-
-static int msm_sleep(int sleep_mode, uint32_t sleep_delay,
-	uint32_t sleep_limit, int from_idle)
-{
-	int collapsed;
-	uint32_t enter_state;
-	uint32_t enter_wait_set = 0;
-	uint32_t enter_wait_clear = 0;
-	uint32_t exit_state;
-	uint32_t exit_wait_clear = 0;
-	uint32_t exit_wait_set = 0;
-	unsigned long pm_saved_acpu_clk_rate = 0;
-	int ret;
-	int rv = -EINTR;
-
-	if (msm_pm_debug_mask & MSM_PM_DEBUG_SUSPEND)
-		printk(KERN_INFO "msm_sleep(): "
-			"mode %d delay %u limit %u idle %d\n",
-			sleep_mode, sleep_delay, sleep_limit, from_idle);
-
-	switch (sleep_mode) {
-	case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
-		enter_state = SMSM_PWRC;
-		enter_wait_set = SMSM_RSA;
-		exit_state = SMSM_WFPI;
-		exit_wait_clear = SMSM_RSA;
-		break;
-	case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND:
-		enter_state = SMSM_PWRC_SUSPEND;
-		enter_wait_set = SMSM_RSA;
-		exit_state = SMSM_WFPI;
-		exit_wait_clear = SMSM_RSA;
-		break;
-	case MSM_PM_SLEEP_MODE_APPS_SLEEP:
-		enter_state = SMSM_SLEEP;
-		exit_state = SMSM_SLEEPEXIT;
-		exit_wait_set = SMSM_SLEEPEXIT;
-		break;
-	default:
-		enter_state = 0;
-		exit_state = 0;
-	}
-
-	if (enter_state && !(smsm_get_state(SMSM_MODEM_STATE) & SMSM_RUN)) {
-		if ((MSM_PM_DEBUG_POWER_COLLAPSE | MSM_PM_DEBUG_SUSPEND) &
-			msm_pm_debug_mask)
-			printk(KERN_INFO "msm_sleep(): modem not ready\n");
-		rv = -EBUSY;
-		goto check_failed;
-	}
-
-	memset(msm_pm_sma.int_info, 0, sizeof(*msm_pm_sma.int_info));
-	msm_irq_enter_sleep1(!!enter_state, from_idle,
-		&msm_pm_sma.int_info->aArm_en_mask);
-	msm_gpio_enter_sleep(from_idle);
-
-	if (enter_state) {
-		if (sleep_delay == 0 && sleep_mode >= MSM_PM_SLEEP_MODE_APPS_SLEEP)
-			sleep_delay = 192000*5; /* APPS_SLEEP does not allow infinite timeout */
-
-		*msm_pm_sma.sleep_delay = sleep_delay;
-		*msm_pm_sma.limit_sleep = sleep_limit;
-		ret = smsm_change_state(SMSM_APPS_STATE, SMSM_RUN, enter_state);
-		if (ret) {
-			printk(KERN_ERR "msm_sleep(): smsm_change_state %x failed\n", enter_state);
-			enter_state = 0;
-			exit_state = 0;
-		}
-		ret = msm_pm_wait_state(enter_wait_set, enter_wait_clear, 0, 0);
-		if (ret) {
-			printk(KERN_EMERG "msm_sleep(): power collapse entry "
-				"timed out waiting for Modem's response\n");
-			msm_pm_timeout();
-		}
-	}
-	if (msm_irq_enter_sleep2(!!enter_state, from_idle))
-		goto enter_failed;
-
-	if (enter_state) {
-		__raw_writel(0x1f, A11S_CLK_SLEEP_EN);
-		__raw_writel(1, A11S_PWRDOWN);
-
-		__raw_writel(0, A11S_STANDBY_CTL);
-		__raw_writel(0, A11RAMBACKBIAS);
-
-		if (msm_pm_debug_mask & MSM_PM_DEBUG_STATE)
-			printk(KERN_INFO "msm_sleep(): enter "
-			       "A11S_CLK_SLEEP_EN %x, A11S_PWRDOWN %x, "
-			       "smsm_get_state %x\n",
-			       __raw_readl(A11S_CLK_SLEEP_EN),
-			       __raw_readl(A11S_PWRDOWN),
-			       smsm_get_state(SMSM_MODEM_STATE));
-	}
-
-	if (sleep_mode <= MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT) {
-		pm_saved_acpu_clk_rate = acpuclk_power_collapse();
-		if (msm_pm_debug_mask & MSM_PM_DEBUG_CLOCK)
-			printk(KERN_INFO "msm_sleep(): %ld enter power collapse"
-			       "\n", pm_saved_acpu_clk_rate);
-		if (pm_saved_acpu_clk_rate == 0)
-			goto ramp_down_failed;
-	}
-	if (sleep_mode < MSM_PM_SLEEP_MODE_APPS_SLEEP) {
-		if (msm_pm_debug_mask & MSM_PM_DEBUG_SMSM_STATE)
-			smsm_print_sleep_info(*msm_pm_sma.sleep_delay,
-				*msm_pm_sma.limit_sleep,
-				msm_pm_sma.int_info->aArm_en_mask,
-				msm_pm_sma.int_info->aArm_wakeup_reason,
-				msm_pm_sma.int_info->aArm_interrupts_pending);
-		msm_pm_boot_config_before_pc(smp_processor_id(),
-				virt_to_phys(msm_pm_collapse_exit));
-		collapsed = msm_pm_collapse();
-		msm_pm_boot_config_after_pc(smp_processor_id());
-		if (collapsed) {
-			cpu_init();
-			local_fiq_enable();
-			rv = 0;
-		}
-		if (msm_pm_debug_mask & MSM_PM_DEBUG_POWER_COLLAPSE)
-			printk(KERN_INFO "msm_pm_collapse(): returned %d\n",
-			       collapsed);
-		if (msm_pm_debug_mask & MSM_PM_DEBUG_SMSM_STATE)
-			smsm_print_sleep_info(*msm_pm_sma.sleep_delay,
-				*msm_pm_sma.limit_sleep,
-				msm_pm_sma.int_info->aArm_en_mask,
-				msm_pm_sma.int_info->aArm_wakeup_reason,
-				msm_pm_sma.int_info->aArm_interrupts_pending);
-	} else {
-		msm_arch_idle();
-		rv = 0;
-	}
-
-	if (sleep_mode <= MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT) {
-		if (msm_pm_debug_mask & MSM_PM_DEBUG_CLOCK)
-			printk(KERN_INFO "msm_sleep(): exit power collapse %ld"
-			       "\n", pm_saved_acpu_clk_rate);
-		if (acpuclk_set_rate(smp_processor_id(),
-				pm_saved_acpu_clk_rate, SETRATE_PC) < 0)
-			printk(KERN_ERR "msm_sleep(): clk_set_rate %ld "
-			       "failed\n", pm_saved_acpu_clk_rate);
-	}
-	if (msm_pm_debug_mask & MSM_PM_DEBUG_STATE)
-		printk(KERN_INFO "msm_sleep(): exit A11S_CLK_SLEEP_EN %x, "
-		       "A11S_PWRDOWN %x, smsm_get_state %x\n",
-		       __raw_readl(A11S_CLK_SLEEP_EN),
-		       __raw_readl(A11S_PWRDOWN),
-		       smsm_get_state(SMSM_MODEM_STATE));
-ramp_down_failed:
-	msm_irq_exit_sleep1(msm_pm_sma.int_info->aArm_en_mask,
-		msm_pm_sma.int_info->aArm_wakeup_reason,
-		msm_pm_sma.int_info->aArm_interrupts_pending);
-enter_failed:
-	if (enter_state) {
-		__raw_writel(0x00, A11S_CLK_SLEEP_EN);
-		__raw_writel(0, A11S_PWRDOWN);
-		smsm_change_state(SMSM_APPS_STATE, enter_state, exit_state);
-		if (msm_pm_wait_state(exit_wait_set, exit_wait_clear, 0, 0)) {
-			printk(KERN_EMERG "msm_sleep(): power collapse exit "
-				"timed out waiting for Modem's response\n");
-			msm_pm_timeout();
-		}
-		if (msm_pm_debug_mask & MSM_PM_DEBUG_STATE)
-			printk(KERN_INFO "msm_sleep(): sleep exit "
-			       "A11S_CLK_SLEEP_EN %x, A11S_PWRDOWN %x, "
-			       "smsm_get_state %x\n",
-			       __raw_readl(A11S_CLK_SLEEP_EN),
-			       __raw_readl(A11S_PWRDOWN),
-			       smsm_get_state(SMSM_MODEM_STATE));
-		if (msm_pm_debug_mask & MSM_PM_DEBUG_SMSM_STATE)
-			smsm_print_sleep_info(*msm_pm_sma.sleep_delay,
-				*msm_pm_sma.limit_sleep,
-				msm_pm_sma.int_info->aArm_en_mask,
-				msm_pm_sma.int_info->aArm_wakeup_reason,
-				msm_pm_sma.int_info->aArm_interrupts_pending);
-	}
-	msm_irq_exit_sleep2(msm_pm_sma.int_info->aArm_en_mask,
-		msm_pm_sma.int_info->aArm_wakeup_reason,
-		msm_pm_sma.int_info->aArm_interrupts_pending);
-	if (enter_state) {
-		smsm_change_state(SMSM_APPS_STATE, exit_state, SMSM_RUN);
-		if (msm_pm_debug_mask & MSM_PM_DEBUG_STATE)
-			printk(KERN_INFO "msm_sleep(): sleep exit "
-			       "A11S_CLK_SLEEP_EN %x, A11S_PWRDOWN %x, "
-			       "smsm_get_state %x\n",
-			       __raw_readl(A11S_CLK_SLEEP_EN),
-			       __raw_readl(A11S_PWRDOWN),
-			       smsm_get_state(SMSM_MODEM_STATE));
-	}
-	msm_irq_exit_sleep3(msm_pm_sma.int_info->aArm_en_mask,
-		msm_pm_sma.int_info->aArm_wakeup_reason,
-		msm_pm_sma.int_info->aArm_interrupts_pending);
-	msm_gpio_exit_sleep();
-	smd_sleep_exit();
-
-check_failed:
-	return rv;
-}
-
-void msm_pm_set_max_sleep_time(int64_t max_sleep_time_ns)
-{
-	int64_t max_sleep_time_bs = max_sleep_time_ns;
-
-	/* Convert from ns -> BS units */
-	do_div(max_sleep_time_bs, NSEC_PER_SEC / 32768);
-
-	if (max_sleep_time_bs > 0x6DDD000)
-		msm_pm_max_sleep_time = (uint32_t) 0x6DDD000;
-	else
-		msm_pm_max_sleep_time = (uint32_t) max_sleep_time_bs;
-
-	if (msm_pm_debug_mask & MSM_PM_DEBUG_SUSPEND)
-		printk(KERN_INFO "%s: Requested %lldns (%lldbs), Giving %ubs\n",
-			__func__, max_sleep_time_ns,
-			max_sleep_time_bs,
-			msm_pm_max_sleep_time);
-}
-EXPORT_SYMBOL(msm_pm_set_max_sleep_time);
-
-void arch_idle(void)
-{
-	int ret;
-	int spin;
-	int64_t sleep_time;
-	int low_power = 0;
-	struct msm_pm_platform_data *mode;
-#ifdef CONFIG_MSM_IDLE_STATS
-	int64_t t1;
-	static int64_t t2;
-	int exit_stat;
-#endif
-	int latency_qos = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
-	uint32_t sleep_limit = SLEEP_LIMIT_NONE;
-	int allow_sleep =
-		msm_pm_idle_sleep_mode < MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT &&
-#ifdef CONFIG_HAS_WAKELOCK
-		!has_wake_lock(WAKE_LOCK_IDLE) &&
-#endif
-		msm_irq_idle_sleep_allowed();
-
-	if (!atomic_read(&msm_pm_init_done))
-		return;
-
-	sleep_time = msm_timer_enter_idle();
-
-#ifdef CONFIG_MSM_IDLE_STATS
-	t1 = ktime_to_ns(ktime_get());
-	msm_pm_add_stat(MSM_PM_STAT_NOT_IDLE, t1 - t2);
-	msm_pm_add_stat(MSM_PM_STAT_REQUESTED_IDLE, sleep_time);
-#endif
-
-	mode = &msm_pm_modes[MSM_PM_SLEEP_MODE_POWER_COLLAPSE];
-	if (mode->latency >= latency_qos)
-		sleep_limit = SLEEP_LIMIT_NO_TCXO_SHUTDOWN;
-
-	mode = &msm_pm_modes[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN];
-	if (mode->latency >= latency_qos)
-		allow_sleep = false;
-
-	mode = &msm_pm_modes[
-		MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT];
-	if (mode->latency >= latency_qos) {
-		/* no time even for SWFI */
-		while (!msm_irq_pending())
-			udelay(1);
-#ifdef CONFIG_MSM_IDLE_STATS
-		exit_stat = MSM_PM_STAT_IDLE_SPIN;
-#endif
-		goto abort_idle;
-	}
-
-	if (msm_pm_debug_mask & MSM_PM_DEBUG_IDLE)
-		printk(KERN_INFO "arch_idle: sleep time %llu, allow_sleep %d\n",
-		       sleep_time, allow_sleep);
-	spin = msm_pm_idle_spin_time >> 10;
-	while (spin-- > 0) {
-		if (msm_irq_pending()) {
-#ifdef CONFIG_MSM_IDLE_STATS
-			exit_stat = MSM_PM_STAT_IDLE_SPIN;
-#endif
-			goto abort_idle;
-		}
-		udelay(1);
-	}
-	if (sleep_time < msm_pm_idle_sleep_min_time || !allow_sleep) {
-		unsigned long saved_rate;
-		saved_rate = acpuclk_wait_for_irq();
-		if (msm_pm_debug_mask & MSM_PM_DEBUG_CLOCK)
-			printk(KERN_DEBUG "arch_idle: clk %ld -> swfi\n",
-				saved_rate);
-		if (saved_rate) {
-			msm_arch_idle();
-#ifdef CONFIG_MSM_IDLE_STATS
-			exit_stat = MSM_PM_STAT_IDLE_WFI;
-#endif
-		} else {
-			while (!msm_irq_pending())
-				udelay(1);
-#ifdef CONFIG_MSM_IDLE_STATS
-			exit_stat = MSM_PM_STAT_IDLE_SPIN;
-#endif
-		}
-		if (msm_pm_debug_mask & MSM_PM_DEBUG_CLOCK)
-			printk(KERN_DEBUG "msm_sleep: clk swfi -> %ld\n",
-				saved_rate);
-		if (saved_rate
-		    && acpuclk_set_rate(smp_processor_id(),
-				saved_rate, SETRATE_SWFI) < 0)
-			printk(KERN_ERR "msm_sleep(): clk_set_rate %ld "
-			       "failed\n", saved_rate);
-	} else {
-		low_power = 1;
-		do_div(sleep_time, NSEC_PER_SEC / 32768);
-		if (sleep_time > 0x6DDD000) {
-			printk("sleep_time too big %lld\n", sleep_time);
-			sleep_time = 0x6DDD000;
-		}
-		ret = msm_sleep(msm_pm_idle_sleep_mode, sleep_time,
-			sleep_limit, 1);
-#ifdef CONFIG_MSM_IDLE_STATS
-		switch (msm_pm_idle_sleep_mode) {
-		case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND:
-		case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
-			if (ret)
-				exit_stat =
-					MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE;
-			else {
-				exit_stat = MSM_PM_STAT_IDLE_POWER_COLLAPSE;
-				msm_pm_sleep_limit = sleep_limit;
-			}
-			break;
-		case MSM_PM_SLEEP_MODE_APPS_SLEEP:
-			if (ret)
-				exit_stat = MSM_PM_STAT_IDLE_FAILED_SLEEP;
-			else
-				exit_stat = MSM_PM_STAT_IDLE_SLEEP;
-			break;
-		default:
-			exit_stat = MSM_PM_STAT_IDLE_WFI;
-		}
-#endif
-	}
-abort_idle:
-	msm_timer_exit_idle(low_power);
-#ifdef CONFIG_MSM_IDLE_STATS
-	t2 = ktime_to_ns(ktime_get());
-	msm_pm_add_stat(exit_stat, t2 - t1);
-#endif
-}
-
-static int msm_pm_enter(suspend_state_t state)
-{
-	uint32_t sleep_limit = SLEEP_LIMIT_NONE;
-	int ret;
-#ifdef CONFIG_MSM_IDLE_STATS
-	int64_t period = 0;
-	int64_t time = 0;
-
-	time = msm_timer_get_sclk_time(&period);
-#endif
-
-	clock_debug_print_enabled();
-
-#ifdef CONFIG_MSM_SLEEP_TIME_OVERRIDE
-	if (msm_pm_sleep_time_override > 0) {
-		int64_t ns = NSEC_PER_SEC * (int64_t)msm_pm_sleep_time_override;
-		msm_pm_set_max_sleep_time(ns);
-		msm_pm_sleep_time_override = 0;
-	}
-#endif
-
-	ret = msm_sleep(msm_pm_sleep_mode,
-		msm_pm_max_sleep_time, sleep_limit, 0);
-
-#ifdef CONFIG_MSM_IDLE_STATS
-	if (msm_pm_sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND ||
-		msm_pm_sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE) {
-		enum msm_pm_time_stats_id id;
-		int64_t end_time;
-
-		if (ret)
-			id = MSM_PM_STAT_FAILED_SUSPEND;
-		else {
-			id = MSM_PM_STAT_SUSPEND;
-			msm_pm_sleep_limit = sleep_limit;
-		}
-
-		if (time != 0) {
-			end_time = msm_timer_get_sclk_time(NULL);
-			if (end_time != 0) {
-				time = end_time - time;
-				if (time < 0)
-					time += period;
-			} else
-				time = 0;
-		}
-
-		msm_pm_add_stat(id, time);
-	}
-#endif
-
-	return 0;
-}
-
-static struct platform_suspend_ops msm_pm_ops = {
-	.enter		= msm_pm_enter,
-	.valid		= suspend_valid_only_mem,
-};
-
-static uint32_t restart_reason = 0x776655AA;
-
-static void msm_pm_power_off(void)
-{
-	msm_rpcrouter_close();
-	msm_proc_comm(PCOM_POWER_DOWN, 0, 0);
-	for (;;) ;
-}
-
-static void msm_pm_restart(char str, const char *cmd)
-{
-	msm_rpcrouter_close();
-	msm_proc_comm(PCOM_RESET_CHIP, &restart_reason, 0);
-
-	for (;;) ;
-}
-
-static int msm_reboot_call(struct notifier_block *this, unsigned long code, void *_cmd)
-{
-	if((code == SYS_RESTART) && _cmd) {
-		char *cmd = _cmd;
-		if (!strcmp(cmd, "bootloader")) {
-			restart_reason = 0x77665500;
-		} else if (!strcmp(cmd, "recovery")) {
-			restart_reason = 0x77665502;
-		} else if (!strcmp(cmd, "eraseflash")) {
-			restart_reason = 0x776655EF;
-		} else if (!strncmp(cmd, "oem-", 4)) {
-			unsigned code = simple_strtoul(cmd + 4, 0, 16) & 0xff;
-			restart_reason = 0x6f656d00 | code;
-		} else {
-			restart_reason = 0x77665501;
-		}
-	}
-	return NOTIFY_DONE;
-}
-
-static struct notifier_block msm_reboot_notifier = {
-	.notifier_call = msm_reboot_call,
-};
-
-#ifdef CONFIG_MSM_IDLE_STATS
-/*
- * Helper function of snprintf where buf is auto-incremented, size is auto-
- * decremented, and there is no return value.
- *
- * NOTE: buf and size must be l-values (e.g. variables)
- */
-#define SNPRINTF(buf, size, format, ...) \
-	do { \
-		if (size > 0) { \
-			int ret; \
-			ret = snprintf(buf, size, format, ## __VA_ARGS__); \
-			if (ret > size) { \
-				buf += size; \
-				size = 0; \
-			} else { \
-				buf += ret; \
-				size -= ret; \
-			} \
-		} \
-	} while (0)
-
-/*
- * Write out the power management statistics.
- */
-static int msm_pm_read_proc(
-	char *page, char **start, off_t off, int count, int *eof, void *data)
-{
-	int i;
-	char *p = page;
-
-	if (count < 1024) {
-		*start = (char *) 0;
-		*eof = 0;
-		return 0;
-	}
-
-	if (!off) {
-		SNPRINTF(p, count, "Last power collapse voted ");
-		if (msm_pm_sleep_limit == SLEEP_LIMIT_NONE)
-			SNPRINTF(p, count, "for TCXO shutdown\n\n");
-		else
-			SNPRINTF(p, count, "against TCXO shutdown\n\n");
-
-		*start = (char *) 1;
-		*eof = 0;
-	} else if (--off < ARRAY_SIZE(msm_pm_stats)) {
-		int64_t bucket_time;
-		int64_t s;
-		uint32_t ns;
-
-		s = msm_pm_stats[off].total_time;
-		ns = do_div(s, NSEC_PER_SEC);
-		SNPRINTF(p, count,
-			"%s:\n"
-			"  count: %7d\n"
-			"  total_time: %lld.%09u\n",
-			msm_pm_stats[off].name,
-			msm_pm_stats[off].count,
-			s, ns);
-
-		bucket_time = msm_pm_stats[off].first_bucket_time;
-		for (i = 0; i < CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1; i++) {
-			s = bucket_time;
-			ns = do_div(s, NSEC_PER_SEC);
-			SNPRINTF(p, count,
-				"   <%6lld.%09u: %7d (%lld-%lld)\n",
-				s, ns, msm_pm_stats[off].bucket[i],
-				msm_pm_stats[off].min_time[i],
-				msm_pm_stats[off].max_time[i]);
-
-			bucket_time <<= CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT;
-		}
-
-		SNPRINTF(p, count, "  >=%6lld.%09u: %7d (%lld-%lld)\n",
-			s, ns, msm_pm_stats[off].bucket[i],
-			msm_pm_stats[off].min_time[i],
-			msm_pm_stats[off].max_time[i]);
-
-		*start = (char *) 1;
-		*eof = (off + 1 >= ARRAY_SIZE(msm_pm_stats));
-	}
-
-	return p - page;
-}
-#undef SNPRINTF
-
-#define MSM_PM_STATS_RESET "reset"
-
-/*
- * Reset the power management statistics values.
- */
-static int msm_pm_write_proc(struct file *file, const char __user *buffer,
-	unsigned long count, void *data)
-{
-	char buf[sizeof(MSM_PM_STATS_RESET)];
-	int ret;
-	unsigned long flags;
-	int i;
-
-	if (count < strlen(MSM_PM_STATS_RESET)) {
-		ret = -EINVAL;
-		goto write_proc_failed;
-	}
-
-	if (copy_from_user(buf, buffer, strlen(MSM_PM_STATS_RESET))) {
-		ret = -EFAULT;
-		goto write_proc_failed;
-	}
-
-	if (memcmp(buf, MSM_PM_STATS_RESET, strlen(MSM_PM_STATS_RESET))) {
-		ret = -EINVAL;
-		goto write_proc_failed;
-	}
-
-	local_irq_save(flags);
-	for (i = 0; i < ARRAY_SIZE(msm_pm_stats); i++) {
-		memset(msm_pm_stats[i].bucket,
-			0, sizeof(msm_pm_stats[i].bucket));
-		memset(msm_pm_stats[i].min_time,
-			0, sizeof(msm_pm_stats[i].min_time));
-		memset(msm_pm_stats[i].max_time,
-			0, sizeof(msm_pm_stats[i].max_time));
-		msm_pm_stats[i].count = 0;
-		msm_pm_stats[i].total_time = 0;
-	}
-
-	msm_pm_sleep_limit = SLEEP_LIMIT_NONE;
-	local_irq_restore(flags);
-
-	return count;
-
-write_proc_failed:
-	return ret;
-}
-#undef MSM_PM_STATS_RESET
-#endif /* CONFIG_MSM_IDLE_STATS */
-
-static int __init msm_pm_init(void)
-{
-#ifdef CONFIG_MSM_IDLE_STATS
-	struct proc_dir_entry *d_entry;
-#endif
-	int ret;
-
-	pm_power_off = msm_pm_power_off;
-	arm_pm_restart = msm_pm_restart;
-	msm_pm_max_sleep_time = 0;
-
-	register_reboot_notifier(&msm_reboot_notifier);
-
-	msm_pm_sma.sleep_delay = smem_alloc(SMEM_SMSM_SLEEP_DELAY,
-		sizeof(*msm_pm_sma.sleep_delay));
-	if (msm_pm_sma.sleep_delay == NULL) {
-		printk(KERN_ERR "msm_pm_init: failed get SLEEP_DELAY\n");
-		return -ENODEV;
-	}
-
-	msm_pm_sma.limit_sleep = smem_alloc(SMEM_SMSM_LIMIT_SLEEP,
-		sizeof(*msm_pm_sma.limit_sleep));
-	if (msm_pm_sma.limit_sleep == NULL) {
-		printk(KERN_ERR "msm_pm_init: failed get LIMIT_SLEEP\n");
-		return -ENODEV;
-	}
-
-	msm_pm_sma.int_info_ext = smem_alloc(SMEM_SMSM_INT_INFO,
-		sizeof(*msm_pm_sma.int_info_ext));
-
-	if (msm_pm_sma.int_info_ext)
-		msm_pm_sma.int_info = (struct smsm_interrupt_info *)
-			msm_pm_sma.int_info_ext;
-	else
-		msm_pm_sma.int_info = smem_alloc(SMEM_SMSM_INT_INFO,
-			sizeof(*msm_pm_sma.int_info));
-
-	if (msm_pm_sma.int_info == NULL) {
-		printk(KERN_ERR "msm_pm_init: failed get INT_INFO\n");
-		return -ENODEV;
-	}
-
-	ret = msm_timer_init_time_sync(msm_pm_timeout);
-	if (ret)
-		return ret;
-
-	BUG_ON(msm_pm_modes == NULL);
-
-	atomic_set(&msm_pm_init_done, 1);
-	suspend_set_ops(&msm_pm_ops);
-
-#ifdef CONFIG_MSM_IDLE_STATS
-	d_entry = create_proc_entry("msm_pm_stats",
-			S_IRUGO | S_IWUSR | S_IWGRP, NULL);
-	if (d_entry) {
-		d_entry->read_proc = msm_pm_read_proc;
-		d_entry->write_proc = msm_pm_write_proc;
-		d_entry->data = NULL;
-	}
-#endif
-
-	return 0;
-}
-
-void __init msm_pm_set_platform_data(
-	struct msm_pm_platform_data *data, int count)
-{
-	BUG_ON(MSM_PM_SLEEP_MODE_NR != count);
-	msm_pm_modes = data;
-}
-
-late_initcall(msm_pm_init);
diff --git a/arch/arm/mach-msm/pm.h b/arch/arm/mach-msm/pm.h
index 09494a0..0d5101d 100644
--- a/arch/arm/mach-msm/pm.h
+++ b/arch/arm/mach-msm/pm.h
@@ -76,6 +76,16 @@
 	uint32_t mask;
 };
 
+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);
+	int (*enter_sleep)(uint32_t sclk_count, void *limits,
+			bool from_idle, bool notify_rpm);
+	void (*exit_sleep)(void *limits, bool from_idle,
+			bool notify_rpm, bool collapsed);
+};
+
 void msm_pm_set_platform_data(struct msm_pm_platform_data *data, int count);
 void msm_pm_set_irq_extns(struct msm_pm_irq_calls *irq_calls);
 int msm_pm_idle_prepare(struct cpuidle_device *dev);
@@ -84,19 +94,47 @@
 
 void __init msm_pm_init_sleep_status_data(
 		struct msm_pm_sleep_status_data *sleep_data);
+
+
 #ifdef CONFIG_MSM_PM8X60
 void msm_pm_set_rpm_wakeup_irq(unsigned int irq);
 int msm_pm_wait_cpu_shutdown(unsigned int cpu);
 bool msm_pm_verify_cpu_pc(unsigned int cpu);
+void msm_pm_set_sleep_ops(struct msm_pm_sleep_ops *ops);
 #else
 static inline void msm_pm_set_rpm_wakeup_irq(unsigned int irq) {}
 static inline int msm_pm_wait_cpu_shutdown(unsigned int cpu) { return 0; }
 static inline bool msm_pm_verify_cpu_pc(unsigned int cpu) { return true; }
+static inline void msm_pm_set_sleep_ops(struct msm_pm_sleep_ops *ops) {}
 #endif
-
 #ifdef CONFIG_HOTPLUG_CPU
 int msm_platform_secondary_init(unsigned int cpu);
 #else
 static inline int msm_platform_secondary_init(unsigned int cpu) { return 0; }
 #endif
+
+enum msm_pm_time_stats_id {
+	MSM_PM_STAT_REQUESTED_IDLE = 0,
+	MSM_PM_STAT_IDLE_SPIN,
+	MSM_PM_STAT_IDLE_WFI,
+	MSM_PM_STAT_RETENTION,
+	MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE,
+	MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE,
+	MSM_PM_STAT_IDLE_POWER_COLLAPSE,
+	MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE,
+	MSM_PM_STAT_SUSPEND,
+	MSM_PM_STAT_FAILED_SUSPEND,
+	MSM_PM_STAT_NOT_IDLE,
+	MSM_PM_STAT_COUNT
+};
+
+#ifdef CONFIG_MSM_IDLE_STATS
+void msm_pm_add_stats(enum msm_pm_time_stats_id *enable_stats, int size);
+void msm_pm_add_stat(enum msm_pm_time_stats_id id, int64_t t);
+#else
+static inline void msm_pm_add_stats(enum msm_pm_time_stats_id *enable_stats,
+		int size) {}
+static inline void msm_pm_add_stat(enum msm_pm_time_stats_id id, int64_t t) {}
+#endif
+
 #endif  /* __ARCH_ARM_MACH_MSM_PM_H */
diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c
index ee78a31..426d6e6 100644
--- a/arch/arm/mach-msm/pm2.c
+++ b/arch/arm/mach-msm/pm2.c
@@ -23,10 +23,8 @@
 #include <linux/init.h>
 #include <linux/pm.h>
 #include <linux/pm_qos_params.h>
-#include <linux/proc_fs.h>
 #include <linux/suspend.h>
 #include <linux/reboot.h>
-#include <linux/uaccess.h>
 #include <linux/io.h>
 #include <linux/tick.h>
 #include <linux/memory.h>
@@ -425,6 +423,7 @@
 	SLEEP_LIMIT_MASK = 0x03,
 };
 
+static uint32_t msm_pm_sleep_limit = SLEEP_LIMIT_NONE;
 #ifdef CONFIG_MSM_MEMORY_LOW_POWER_MODE
 enum {
 	SLEEP_RESOURCE_MEMORY_BIT0 = 0x0200,
@@ -455,30 +454,21 @@
 static void msm_pm_config_hw_before_power_down(void)
 {
 	if (cpu_is_msm7x30() || cpu_is_msm8x55()) {
-		__raw_writel(1, APPS_PWRDOWN);
-		mb();
 		__raw_writel(4, APPS_SECOP);
-		mb();
 	} else if (cpu_is_msm7x27()) {
 		__raw_writel(0x1f, APPS_CLK_SLEEP_EN);
-		mb();
-		__raw_writel(1, APPS_PWRDOWN);
-		mb();
 	} else if (cpu_is_msm7x27a() || cpu_is_msm7x27aa() ||
 		   cpu_is_msm7x25a() || cpu_is_msm7x25aa() ||
 		   cpu_is_msm7x25ab()) {
 		__raw_writel(0x7, APPS_CLK_SLEEP_EN);
-		mb();
-		__raw_writel(1, APPS_PWRDOWN);
-		mb();
-	} else {
+	} else if (cpu_is_qsd8x50()) {
 		__raw_writel(0x1f, APPS_CLK_SLEEP_EN);
 		mb();
-		__raw_writel(1, APPS_PWRDOWN);
-		mb();
 		__raw_writel(0, APPS_STANDBY_CTL);
-		mb();
 	}
+	mb();
+	__raw_writel(1, APPS_PWRDOWN);
+	mb();
 }
 
 /*
@@ -559,13 +549,11 @@
 		__raw_writel(0, APPS_PWRDOWN);
 		mb();
 		msm_spm_reinit();
-	} else {
+	} else if (cpu_is_msm8625()) {
 		__raw_writel(0, APPS_PWRDOWN);
 		mb();
-		__raw_writel(0, APPS_CLK_SLEEP_EN);
-		mb();
 
-		if (cpu_is_msm8625() && power_collapsed) {
+		if (power_collapsed) {
 			/*
 			 * enable the SCU while coming out of power
 			 * collapse.
@@ -576,6 +564,11 @@
 			 */
 			configure_top_csr();
 		}
+	} else {
+		__raw_writel(0, APPS_PWRDOWN);
+		mb();
+		__raw_writel(0, APPS_CLK_SLEEP_EN);
+		mb();
 	}
 }
 
@@ -771,238 +764,6 @@
 
 
 /******************************************************************************
- * CONFIG_MSM_IDLE_STATS
- *****************************************************************************/
-
-#ifdef CONFIG_MSM_IDLE_STATS
-enum msm_pm_time_stats_id {
-	MSM_PM_STAT_REQUESTED_IDLE,
-	MSM_PM_STAT_IDLE_SPIN,
-	MSM_PM_STAT_IDLE_WFI,
-	MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE,
-	MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE,
-	MSM_PM_STAT_IDLE_POWER_COLLAPSE,
-	MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE,
-	MSM_PM_STAT_SUSPEND,
-	MSM_PM_STAT_FAILED_SUSPEND,
-	MSM_PM_STAT_NOT_IDLE,
-	MSM_PM_STAT_COUNT
-};
-
-struct msm_pm_time_stats {
-	const char *name;
-	int64_t first_bucket_time;
-	int bucket[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
-	int64_t min_time[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
-	int64_t max_time[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
-	int count;
-	int64_t total_time;
-};
-
-struct msm_pm_cpu_time_stats {
-	struct msm_pm_time_stats stats[MSM_PM_STAT_COUNT];
-};
-
-static DEFINE_PER_CPU_SHARED_ALIGNED(
-		struct msm_pm_cpu_time_stats, msm_pm_stats);
-
-static uint32_t msm_pm_sleep_limit = SLEEP_LIMIT_NONE;
-
-static DEFINE_SPINLOCK(msm_pm_stats_lock);
-
-/*
- * Add the given time data to the statistics collection.
- */
-static void msm_pm_add_stat(enum msm_pm_time_stats_id id, int64_t t)
-{
-	unsigned long flags;
-	struct msm_pm_time_stats *stats;
-	int i;
-	int64_t bt;
-
-	spin_lock_irqsave(&msm_pm_stats_lock, flags);
-	stats = __get_cpu_var(msm_pm_stats).stats;
-
-	stats[id].total_time += t;
-	stats[id].count++;
-
-	bt = t;
-	do_div(bt, stats[id].first_bucket_time);
-
-	if (bt < 1ULL << (CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT *
-				(CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1)))
-		i = DIV_ROUND_UP(fls((uint32_t)bt),
-					CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT);
-	else
-		i = CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1;
-
-	if (i >= CONFIG_MSM_IDLE_STATS_BUCKET_COUNT)
-		i = CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1;
-
-	stats[id].bucket[i]++;
-
-	if (t < stats[id].min_time[i] || !stats[id].max_time[i])
-		stats[id].min_time[i] = t;
-	if (t > stats[id].max_time[i])
-		stats[id].max_time[i] = t;
-
-	spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
-}
-
-/*
- * Helper function of snprintf where buf is auto-incremented, size is auto-
- * decremented, and there is no return value.
- *
- * NOTE: buf and size must be l-values (e.g. variables)
- */
-#define SNPRINTF(buf, size, format, ...) \
-	do { \
-		if (size > 0) { \
-			int ret; \
-			ret = snprintf(buf, size, format, ## __VA_ARGS__); \
-			if (ret > size) { \
-				buf += size; \
-				size = 0; \
-			} else { \
-				buf += ret; \
-				size -= ret; \
-			} \
-		} \
-	} while (0)
-
-/*
- * Write out the power management statistics.
- */
-static int msm_pm_read_proc
-	(char *page, char **start, off_t off, int count, int *eof, void *data)
-{
-	unsigned int cpu = off / MSM_PM_STAT_COUNT;
-	int id = off % MSM_PM_STAT_COUNT;
-	char *p = page;
-
-	if (count < 1024) {
-		*start = (char *) 0;
-		*eof = 0;
-		return 0;
-	}
-
-	if (!off) {
-		SNPRINTF(p, count, "Last power collapse voted ");
-		if ((msm_pm_sleep_limit & SLEEP_LIMIT_MASK) ==
-			SLEEP_LIMIT_NONE)
-			SNPRINTF(p, count, "for TCXO shutdown\n\n");
-		else
-			SNPRINTF(p, count, "against TCXO shutdown\n\n");
-	}
-
-	if (cpu < num_possible_cpus()) {
-		unsigned long flags;
-		struct msm_pm_time_stats *stats;
-		int i;
-		int64_t bucket_time;
-		int64_t s;
-		uint32_t ns;
-
-		spin_lock_irqsave(&msm_pm_stats_lock, flags);
-		stats = per_cpu(msm_pm_stats, cpu).stats;
-
-		s = stats[id].total_time;
-		ns = do_div(s, NSEC_PER_SEC);
-		SNPRINTF(p, count,
-			"[cpu %u] %s:\n"
-			"  count: %7d\n"
-			"  total_time: %lld.%09u\n",
-			cpu, stats[id].name,
-			stats[id].count,
-			s, ns);
-
-		bucket_time = stats[id].first_bucket_time;
-		for (i = 0; i < CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1; i++) {
-			s = bucket_time;
-			ns = do_div(s, NSEC_PER_SEC);
-			SNPRINTF(p, count,
-				"   <%6lld.%09u: %7d (%lld-%lld)\n",
-				s, ns, stats[id].bucket[i],
-				stats[id].min_time[i],
-				stats[id].max_time[i]);
-
-			bucket_time <<= CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT;
-		}
-
-		SNPRINTF(p, count, "  >=%6lld.%09u: %7d (%lld-%lld)\n",
-			s, ns, stats[id].bucket[i],
-			stats[id].min_time[i],
-			stats[id].max_time[i]);
-
-		*start = (char *) 1;
-		*eof = (off + 1 >= MSM_PM_STAT_COUNT * num_possible_cpus());
-
-		spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
-	}
-
-	return p - page;
-}
-#undef SNPRINTF
-
-#define MSM_PM_STATS_RESET "reset"
-
-/*
- * Reset the power management statistics values.
- */
-static int msm_pm_write_proc(struct file *file, const char __user *buffer,
-	unsigned long count, void *data)
-{
-	char buf[sizeof(MSM_PM_STATS_RESET)];
-	int ret;
-	unsigned long flags;
-	unsigned int cpu;
-
-	if (count < strlen(MSM_PM_STATS_RESET)) {
-		ret = -EINVAL;
-		goto write_proc_failed;
-	}
-
-	if (copy_from_user(buf, buffer, strlen(MSM_PM_STATS_RESET))) {
-		ret = -EFAULT;
-		goto write_proc_failed;
-	}
-
-	if (memcmp(buf, MSM_PM_STATS_RESET, strlen(MSM_PM_STATS_RESET))) {
-		ret = -EINVAL;
-		goto write_proc_failed;
-	}
-
-	spin_lock_irqsave(&msm_pm_stats_lock, flags);
-	for_each_possible_cpu(cpu) {
-		struct msm_pm_time_stats *stats;
-		int i;
-
-		stats = per_cpu(msm_pm_stats, cpu).stats;
-		for (i = 0; i < MSM_PM_STAT_COUNT; i++) {
-			memset(stats[i].bucket,
-				0, sizeof(stats[i].bucket));
-			memset(stats[i].min_time,
-				0, sizeof(stats[i].min_time));
-			memset(stats[i].max_time,
-				0, sizeof(stats[i].max_time));
-			stats[i].count = 0;
-			stats[i].total_time = 0;
-		}
-	}
-	msm_pm_sleep_limit = SLEEP_LIMIT_NONE;
-	spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
-
-	return count;
-
-write_proc_failed:
-	return ret;
-}
-
-#undef MSM_PM_STATS_RESET
-#endif /* CONFIG_MSM_IDLE_STATS */
-
-
-/******************************************************************************
  * Shared Memory Bits
  *****************************************************************************/
 
@@ -1193,7 +954,10 @@
 #endif
 
 #ifdef CONFIG_CACHE_L2X0
-	l2cc_suspend();
+	if (!cpu_is_msm8625())
+		l2cc_suspend();
+	else
+		apps_power_collapse = 1;
 #endif
 
 	collapsed = msm_pm_collapse();
@@ -1220,7 +984,10 @@
 	}
 
 #ifdef CONFIG_CACHE_L2X0
-	l2cc_resume();
+	if (!cpu_is_msm8625())
+		l2cc_resume();
+	else
+		apps_power_collapse = 0;
 #endif
 
 	msm_pm_boot_config_after_pc(smp_processor_id());
@@ -1507,6 +1274,30 @@
 	return 0;
 }
 
+static int64_t msm_pm_timer_enter_suspend(int64_t *period)
+{
+	int time = 0;
+
+	time = msm_timer_get_sclk_time(period);
+	if (!time)
+		pr_err("%s: Unable to read sclk.\n", __func__);
+		return time;
+}
+
+static int64_t msm_pm_timer_exit_suspend(int64_t time, int64_t period)
+{
+
+	if (time != 0) {
+		int64_t end_time = msm_timer_get_sclk_time(NULL);
+		if (end_time != 0) {
+			time = end_time - time;
+			if (time < 0)
+				time += period;
+			} else
+				time = 0;
+		}
+	return time;
+}
 
 /******************************************************************************
  * External Idle/Suspend Functions
@@ -1525,28 +1316,22 @@
 	int ret;
 	int i;
 	unsigned int cpu;
-
-#ifdef CONFIG_MSM_IDLE_STATS
 	int64_t t1;
 	static DEFINE_PER_CPU(int64_t, t2);
 	int exit_stat;
- #endif
 
 	if (!atomic_read(&msm_pm_init_done))
 		return;
 
 	cpu = smp_processor_id();
-
 	latency_qos = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
 	/* get the next timer expiration */
 	timer_expiration = ktime_to_ns(tick_nohz_get_sleep_length());
 
-#ifdef CONFIG_MSM_IDLE_STATS
 	t1 = ktime_to_ns(ktime_get());
 	msm_pm_add_stat(MSM_PM_STAT_NOT_IDLE, t1 - __get_cpu_var(t2));
 	msm_pm_add_stat(MSM_PM_STAT_REQUESTED_IDLE, timer_expiration);
 	exit_stat = MSM_PM_STAT_IDLE_SPIN;
-#endif
 
 	for (i = 0; i < ARRAY_SIZE(allow); i++)
 		allow[i] = true;
@@ -1627,46 +1412,34 @@
 		low_power = (ret != -EBUSY && ret != -ETIMEDOUT);
 		msm_timer_exit_idle(low_power);
 
-#ifdef CONFIG_MSM_IDLE_STATS
 		if (ret)
 			exit_stat = MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE;
 		else {
 			exit_stat = MSM_PM_STAT_IDLE_POWER_COLLAPSE;
 			msm_pm_sleep_limit = sleep_limit;
 		}
-#endif
 	} else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE]) {
 		ret = msm_pm_power_collapse_standalone(true);
-#ifdef CONFIG_MSM_IDLE_STATS
 		exit_stat = ret ?
 			MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE :
 			MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE;
-#endif
 	} else if (allow[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT]) {
 		ret = msm_pm_swfi(true);
 		if (ret)
 			while (!msm_pm_irq_extns->irq_pending())
 				udelay(1);
-#ifdef CONFIG_MSM_IDLE_STATS
 		exit_stat = ret ? MSM_PM_STAT_IDLE_SPIN : MSM_PM_STAT_IDLE_WFI;
-#endif
 	} else if (allow[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT]) {
 		msm_pm_swfi(false);
-#ifdef CONFIG_MSM_IDLE_STATS
 		exit_stat = MSM_PM_STAT_IDLE_WFI;
-#endif
 	} else {
 		while (!msm_pm_irq_extns->irq_pending())
 			udelay(1);
-#ifdef CONFIG_MSM_IDLE_STATS
 		exit_stat = MSM_PM_STAT_IDLE_SPIN;
-#endif
 	}
 
-#ifdef CONFIG_MSM_IDLE_STATS
 	__get_cpu_var(t2) = ktime_to_ns(ktime_get());
 	msm_pm_add_stat(exit_stat, __get_cpu_var(t2) - t1);
-#endif
 }
 
 /*
@@ -1687,10 +1460,8 @@
 	uint32_t sleep_limit = SLEEP_LIMIT_NONE;
 	int ret = -EPERM;
 	int i;
-#ifdef CONFIG_MSM_IDLE_STATS
 	int64_t period = 0;
 	int64_t time = 0;
-#endif
 
 	/* Must executed by CORE0 */
 	if (smp_processor_id()) {
@@ -1698,9 +1469,7 @@
 		goto suspend_exit;
 	}
 
-#ifdef CONFIG_MSM_IDLE_STATS
-	time = msm_timer_get_sclk_time(&period);
-#endif
+	time = msm_pm_timer_enter_suspend(&period);
 
 	MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND, KERN_INFO,
 		"%s(): sleep limit %u\n", __func__, sleep_limit);
@@ -1717,10 +1486,7 @@
 
 	if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] ||
 		allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN]) {
-#ifdef CONFIG_MSM_IDLE_STATS
 		enum msm_pm_time_stats_id id;
-		int64_t end_time;
-#endif
 
 		clock_debug_print_enabled();
 
@@ -1750,7 +1516,6 @@
 		ret = msm_pm_power_collapse(
 			false, msm_pm_max_sleep_time, sleep_limit);
 
-#ifdef CONFIG_MSM_IDLE_STATS
 		if (ret)
 			id = MSM_PM_STAT_FAILED_SUSPEND;
 		else {
@@ -1758,18 +1523,8 @@
 			msm_pm_sleep_limit = sleep_limit;
 		}
 
-		if (time != 0) {
-			end_time = msm_timer_get_sclk_time(NULL);
-			if (end_time != 0) {
-				time = end_time - time;
-				if (time < 0)
-					time += period;
-			} else
-				time = 0;
-		}
-
+		time = msm_pm_timer_exit_suspend(time, period);
 		msm_pm_add_stat(id, time);
-#endif
 	} else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE]) {
 		ret = msm_pm_power_collapse_standalone(false);
 	} else if (allow[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT]) {
@@ -1879,12 +1634,21 @@
  */
 static int __init msm_pm_init(void)
 {
-#ifdef CONFIG_MSM_IDLE_STATS
-	struct proc_dir_entry *d_entry;
-	unsigned int cpu;
-#endif
 	int ret;
 	int val;
+	enum msm_pm_time_stats_id enable_stats[] = {
+		MSM_PM_STAT_REQUESTED_IDLE,
+		MSM_PM_STAT_IDLE_SPIN,
+		MSM_PM_STAT_IDLE_WFI,
+		MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE,
+		MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE,
+		MSM_PM_STAT_IDLE_POWER_COLLAPSE,
+		MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE,
+		MSM_PM_STAT_SUSPEND,
+		MSM_PM_STAT_FAILED_SUSPEND,
+		MSM_PM_STAT_NOT_IDLE,
+	};
+
 #ifdef CONFIG_CPU_V7
 	pgd_t *pc_pgd;
 	pmd_t *pmd;
@@ -1962,6 +1726,8 @@
 		 */
 		val = 0x00030002;
 		__raw_writel(val, (MSM_CFG_CTL_BASE + 0x38));
+
+		l2x0_base_addr = MSM_L2CC_BASE;
 	}
 
 #ifdef CONFIG_MSM_MEMORY_LOW_POWER_MODE
@@ -1978,70 +1744,9 @@
 	suspend_set_ops(&msm_pm_ops);
 
 	msm_pm_mode_sysfs_add();
-#ifdef CONFIG_MSM_IDLE_STATS
-	for_each_possible_cpu(cpu) {
-		struct msm_pm_time_stats *stats =
-			per_cpu(msm_pm_stats, cpu).stats;
-
-		stats[MSM_PM_STAT_REQUESTED_IDLE].name = "idle-request";
-		stats[MSM_PM_STAT_REQUESTED_IDLE].first_bucket_time =
-			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-
-		stats[MSM_PM_STAT_IDLE_SPIN].name = "idle-spin";
-		stats[MSM_PM_STAT_IDLE_SPIN].first_bucket_time =
-			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-
-		stats[MSM_PM_STAT_IDLE_WFI].name = "idle-wfi";
-		stats[MSM_PM_STAT_IDLE_WFI].first_bucket_time =
-			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-
-		stats[MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE].name =
-			"idle-standalone-power-collapse";
-		stats[MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE].
-			first_bucket_time =
-			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-
-		stats[MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE].name =
-			"idle-failed-standalone-power-collapse";
-		stats[MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE].
-			first_bucket_time =
-			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-
-		stats[MSM_PM_STAT_IDLE_POWER_COLLAPSE].name =
-			"idle-power-collapse";
-		stats[MSM_PM_STAT_IDLE_POWER_COLLAPSE].first_bucket_time =
-			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-
-		stats[MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE].name =
-			"idle-failed-power-collapse";
-		stats[MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE].
-			first_bucket_time =
-			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-
-		stats[MSM_PM_STAT_SUSPEND].name = "suspend";
-		stats[MSM_PM_STAT_SUSPEND].first_bucket_time =
-			CONFIG_MSM_SUSPEND_STATS_FIRST_BUCKET;
-
-		stats[MSM_PM_STAT_FAILED_SUSPEND].name = "failed-suspend";
-		stats[MSM_PM_STAT_FAILED_SUSPEND].first_bucket_time =
-			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-
-		stats[MSM_PM_STAT_NOT_IDLE].name = "not-idle";
-		stats[MSM_PM_STAT_NOT_IDLE].first_bucket_time =
-			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-	}
+	msm_pm_add_stats(enable_stats, ARRAY_SIZE(enable_stats));
 
 	atomic_set(&msm_pm_init_done, 1);
-
-	d_entry = create_proc_entry("msm_pm_stats",
-			S_IRUGO | S_IWUSR | S_IWGRP, NULL);
-	if (d_entry) {
-		d_entry->read_proc = msm_pm_read_proc;
-		d_entry->write_proc = msm_pm_write_proc;
-		d_entry->data = NULL;
-	}
-#endif
-
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/qdsp5/adsp.c b/arch/arm/mach-msm/qdsp5/adsp.c
index 6f5ccbf..b485058 100644
--- a/arch/arm/mach-msm/qdsp5/adsp.c
+++ b/arch/arm/mach-msm/qdsp5/adsp.c
@@ -865,7 +865,8 @@
 	unsigned msg_id;
 	unsigned msg_length;
 #ifdef CONFIG_DEBUG_FS
-	uint16_t *ptr;
+	uint16_t *ptr16;
+	uint32_t *ptr32;
 	int ii;
 #endif /* CONFIG_DEBUG_FS */
 	void (*func)(void *, size_t);
@@ -909,12 +910,20 @@
 		return 0;
 	}
 #ifdef CONFIG_DEBUG_FS
-	if (rdump > 0) {
-		ptr = read_event_addr;
+	if (rdump > 0 &&
+		(dsp_addr >= (void *)(MSM_AD5_BASE + QDSP_RAMC_OFFSET))) {
+		ptr32 = read_event_addr;
+		pr_info("D->A\n");
+		pr_info("m_id = %x id = %x\n", module->id, msg_id);
+		for (ii = 0; ii < msg_length/4; ii++)
+			pr_info("%x ", ptr32[ii]);
+		pr_info("\n");
+	} else if (rdump > 0) {
+		ptr16 = read_event_addr;
 		pr_info("D->A\n");
 		pr_info("m_id = %x id = %x\n", module->id, msg_id);
 		for (ii = 0; ii < msg_length/2; ii++)
-			pr_info("%x ", ptr[ii]);
+			pr_info("%x ", ptr16[ii]);
 		pr_info("\n");
 	}
 #endif /* CONFIG_DEBUG_FS */
diff --git a/arch/arm/mach-msm/qdsp6v2/Makefile b/arch/arm/mach-msm/qdsp6v2/Makefile
index 083a9f1..cee8f04 100644
--- a/arch/arm/mach-msm/qdsp6v2/Makefile
+++ b/arch/arm/mach-msm/qdsp6v2/Makefile
@@ -1,5 +1,4 @@
 obj-y += rtac.o
-
 ifdef CONFIG_ARCH_MSM8X60
 obj-y += audio_dev_ctl.o
 obj-y += board-msm8x60-audio.o
@@ -17,6 +16,7 @@
 ifndef CONFIG_ARCH_MSM9615
 obj-y += aac_in.o qcelp_in.o evrc_in.o amrnb_in.o audio_utils.o
 obj-y += audio_wma.o audio_wmapro.o audio_aac.o audio_multi_aac.o audio_utils_aio.o
+obj-$(CONFIG_MSM_QDSP6_CODECS) += q6audio_v1.o q6audio_v1_aio.o
 obj-$(CONFIG_MSM_ULTRASOUND) += ultrasound/
 obj-y += audio_mp3.o audio_amrnb.o audio_amrwb.o audio_evrc.o audio_qcelp.o amrwb_in.o
 endif
diff --git a/arch/arm/mach-msm/qdsp6v2/aac_in.c b/arch/arm/mach-msm/qdsp6v2/aac_in.c
index 41d3ff3..6e79a75 100644
--- a/arch/arm/mach-msm/qdsp6v2/aac_in.c
+++ b/arch/arm/mach-msm/qdsp6v2/aac_in.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -22,8 +22,6 @@
 #include <linux/msm_audio_aac.h>
 #include <asm/atomic.h>
 #include <asm/ioctls.h>
-#include <sound/q6asm.h>
-#include <sound/apr_audio.h>
 #include "audio_utils.h"
 
 
@@ -35,43 +33,6 @@
 
 #define AAC_FORMAT_ADTS 65535
 
-void q6asm_aac_in_cb(uint32_t opcode, uint32_t token,
-		uint32_t *payload, void *priv)
-{
-	struct q6audio_in * audio = (struct q6audio_in *)priv;
-	unsigned long flags;
-
-	pr_debug("%s:session id %d: opcode[0x%x]\n", __func__,
-			audio->ac->session, opcode);
-
-	spin_lock_irqsave(&audio->dsp_lock, flags);
-	switch (opcode) {
-	case ASM_DATA_EVENT_READ_DONE:
-		audio_in_get_dsp_frames(audio, token, payload);
-		break;
-	case ASM_DATA_EVENT_WRITE_DONE:
-		atomic_inc(&audio->in_count);
-		wake_up(&audio->write_wait);
-		break;
-	case ASM_DATA_CMDRSP_EOS:
-		audio->eos_rsp = 1;
-		wake_up(&audio->read_wait);
-		break;
-	case ASM_STREAM_CMDRSP_GET_ENCDEC_PARAM:
-		break;
-	case ASM_STREAM_CMDRSP_GET_PP_PARAMS:
-		break;
-	case ASM_SESSION_EVENT_TX_OVERFLOW:
-		pr_err("%s:session id %d: ASM_SESSION_EVENT_TX_OVERFLOW\n",
-			__func__, audio->ac->session);
-		break;
-	default:
-		pr_debug("%s:session id %d: Ignore opcode[0x%x]\n", __func__,
-			audio->ac->session, opcode);
-		break;
-	}
-	spin_unlock_irqrestore(&audio->dsp_lock, flags);
-}
 /* ------------------- device --------------------- */
 static long aac_in_ioctl(struct file *file,
 				unsigned int cmd, unsigned long arg)
@@ -121,8 +82,8 @@
 					aac_mode,
 					enc_cfg->stream_format);
 		if (rc < 0) {
-			pr_err("%s:session id %d: cmd media format block\
-				failed\n", __func__, audio->ac->session);
+			pr_err("%s:session id %d: cmd media format block"
+				"failed\n", __func__, audio->ac->session);
 			break;
 		}
 		if (audio->feedback == NON_TUNNEL_MODE) {
@@ -130,8 +91,8 @@
 						audio->pcm_cfg.sample_rate,
 						audio->pcm_cfg.channel_count);
 			if (rc < 0) {
-				pr_err("%s:session id %d: media format block\
-				failed\n", __func__, audio->ac->session);
+				pr_err("%s:session id %d: media format block"
+				"failed\n", __func__, audio->ac->session);
 				break;
 			}
 		}
@@ -140,8 +101,8 @@
 			audio->enabled = 1;
 		} else {
 			audio->enabled = 0;
-			pr_err("%s:session id %d: Audio Start procedure\
-			failed rc=%d\n", __func__, audio->ac->session, rc);
+			pr_err("%s:session id %d: Audio Start procedure"
+			"failed rc=%d\n", __func__, audio->ac->session, rc);
 			break;
 		}
 		while (cnt++ < audio->str_cfg.buffer_count)
@@ -155,8 +116,8 @@
 				audio->ac->session);
 		rc = audio_in_disable(audio);
 		if (rc  < 0) {
-			pr_err("%s:session id %d: Audio Stop procedure failed\
-				rc=%d\n", __func__, audio->ac->session, rc);
+			pr_err("%s:session id %d: Audio Stop procedure failed"
+				"rc=%d\n", __func__, audio->ac->session, rc);
 			break;
 		}
 		break;
@@ -174,8 +135,8 @@
 		/* ADTS(-1) to ADTS(0x00), RAW(0x00) to RAW(0x03) */
 		cfg.stream_format = ((enc_cfg->stream_format == \
 			0x00) ? AUDIO_AAC_FORMAT_ADTS : AUDIO_AAC_FORMAT_RAW);
-		pr_debug("%s:session id %d: Get-aac-cfg: format=%d sr=%d\
-			bitrate=%d\n", __func__, audio->ac->session,
+		pr_debug("%s:session id %d: Get-aac-cfg: format=%d sr=%d"
+			"bitrate=%d\n", __func__, audio->ac->session,
 			cfg.stream_format, cfg.sample_rate, cfg.bit_rate);
 		if (copy_to_user((void *)arg, &cfg, sizeof(cfg)))
 			rc = -EFAULT;
@@ -229,8 +190,8 @@
 		enc_cfg->stream_format =
 			((cfg.stream_format == AUDIO_AAC_FORMAT_RAW) ? \
 								0x03 : 0x00);
-		pr_debug("%s:session id %d: Set-aac-cfg:SR= 0x%x ch=0x%x\
-			bitrate=0x%x, format(adts/raw) = %d\n",
+		pr_debug("%s:session id %d: Set-aac-cfg:SR= 0x%x ch=0x%x"
+			"bitrate=0x%x, format(adts/raw) = %d\n",
 			__func__, audio->ac->session, enc_cfg->sample_rate,
 			enc_cfg->channels, enc_cfg->bit_rate,
 			enc_cfg->stream_format);
@@ -289,16 +250,16 @@
 	audio = kzalloc(sizeof(struct q6audio_in), GFP_KERNEL);
 
 	if (audio == NULL) {
-		pr_err("%s: Could not allocate memory for aac\
-				driver\n", __func__);
+		pr_err("%s: Could not allocate memory for aac"
+				"driver\n", __func__);
 		return -ENOMEM;
 	}
 	/* Allocate memory for encoder config param */
 	audio->enc_cfg = kzalloc(sizeof(struct msm_audio_aac_enc_config),
 				GFP_KERNEL);
 	if (audio->enc_cfg == NULL) {
-		pr_err("%s:session id %d: Could not allocate memory for aac\
-				config param\n", __func__, audio->ac->session);
+		pr_err("%s:session id %d: Could not allocate memory for aac"
+				"config param\n", __func__, audio->ac->session);
 		kfree(audio);
 		return -ENOMEM;
 	}
@@ -307,8 +268,8 @@
 	audio->codec_cfg = kzalloc(sizeof(struct msm_audio_aac_config),
 				GFP_KERNEL);
 	if (audio->codec_cfg == NULL) {
-		pr_err("%s:session id %d: Could not allocate memory for aac\
-				config\n", __func__, audio->ac->session);
+		pr_err("%s:session id %d: Could not allocate memory for aac"
+				"config\n", __func__, audio->ac->session);
 		kfree(audio->enc_cfg);
 		kfree(audio);
 		return -ENOMEM;
@@ -343,12 +304,12 @@
 	aac_config->sbr_ps_on_flag = 0;
 	aac_config->channel_configuration = 1;
 
-	audio->ac = q6asm_audio_client_alloc((app_cb)q6asm_aac_in_cb,
+	audio->ac = q6asm_audio_client_alloc((app_cb)q6asm_in_cb,
 							(void *)audio);
 
 	if (!audio->ac) {
-		pr_err("%s: Could not allocate memory for\
-				audio client\n", __func__);
+		pr_err("%s: Could not allocate memory for"
+				"audio client\n", __func__);
 		kfree(audio->enc_cfg);
 		kfree(audio->codec_cfg);
 		kfree(audio);
@@ -386,8 +347,8 @@
 		/* register for tx overflow (valid for tunnel mode only) */
 		rc = q6asm_reg_tx_overflow(audio->ac, 0x01);
 		if (rc < 0) {
-			pr_err("%s:session id %d: TX Overflow registration\
-				failed rc=%d\n", __func__,
+			pr_err("%s:session id %d: TX Overflow registration"
+				"failed rc=%d\n", __func__,
 				audio->ac->session, rc);
 			rc = -ENODEV;
 			goto fail;
diff --git a/arch/arm/mach-msm/qdsp6v2/amrnb_in.c b/arch/arm/mach-msm/qdsp6v2/amrnb_in.c
index 6a70428..63a0774 100644
--- a/arch/arm/mach-msm/qdsp6v2/amrnb_in.c
+++ b/arch/arm/mach-msm/qdsp6v2/amrnb_in.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -22,8 +22,6 @@
 #include <linux/msm_audio_amrnb.h>
 #include <asm/atomic.h>
 #include <asm/ioctls.h>
-#include <sound/q6asm.h>
-#include <sound/apr_audio.h>
 #include "audio_utils.h"
 
 /* Buffer with meta*/
@@ -32,44 +30,6 @@
 /* Maximum 10 frames in buffer with meta */
 #define FRAME_SIZE		(1 + ((32+sizeof(struct meta_out_dsp)) * 10))
 
-void q6asm_amrnb_in_cb(uint32_t opcode, uint32_t token,
-		uint32_t *payload, void *priv)
-{
-	struct q6audio_in * audio = (struct q6audio_in *)priv;
-	unsigned long flags;
-
-	pr_debug("%s:session id %d: opcode - %d\n", __func__,
-			audio->ac->session, opcode);
-
-	spin_lock_irqsave(&audio->dsp_lock, flags);
-	switch (opcode) {
-	case ASM_DATA_EVENT_READ_DONE:
-		audio_in_get_dsp_frames(audio, token, payload);
-		break;
-	case ASM_DATA_EVENT_WRITE_DONE:
-		atomic_inc(&audio->in_count);
-		wake_up(&audio->write_wait);
-		break;
-	case ASM_DATA_CMDRSP_EOS:
-		audio->eos_rsp = 1;
-		wake_up(&audio->read_wait);
-		break;
-	case ASM_STREAM_CMDRSP_GET_ENCDEC_PARAM:
-		break;
-	case ASM_STREAM_CMDRSP_GET_PP_PARAMS:
-		break;
-	case ASM_SESSION_EVENT_TX_OVERFLOW:
-		pr_err("%s:session id %d: ASM_SESSION_EVENT_TX_OVERFLOW\n",
-			__func__, audio->ac->session);
-		break;
-	default:
-		pr_err("%s:session id %d: Ignore opcode[0x%x]\n", __func__,
-				audio->ac->session, opcode);
-		break;
-	}
-	spin_unlock_irqrestore(&audio->dsp_lock, flags);
-}
-
 /* ------------------- device --------------------- */
 static long amrnb_in_ioctl(struct file *file,
 				unsigned int cmd, unsigned long arg)
@@ -102,8 +62,8 @@
 			enc_cfg->dtx_enable);
 
 		if (rc < 0) {
-			pr_err("%s:session id %d: cmd amrnb media format block\
-				failed\n", __func__, audio->ac->session);
+			pr_err("%s:session id %d: cmd amrnb media format block"
+				"failed\n", __func__, audio->ac->session);
 			break;
 		}
 		if (audio->feedback == NON_TUNNEL_MODE) {
@@ -112,8 +72,8 @@
 				audio->pcm_cfg.channel_count);
 
 			if (rc < 0) {
-				pr_err("%s:session id %d: media format block\
-				failed\n", __func__, audio->ac->session);
+				pr_err("%s:session id %d: media format block"
+				"failed\n", __func__, audio->ac->session);
 				break;
 			}
 		}
@@ -125,8 +85,8 @@
 			audio->enabled = 1;
 		} else {
 			audio->enabled = 0;
-			pr_err("%s:session id %d: Audio Start procedure failed\
-					rc=%d\n", __func__,
+			pr_err("%s:session id %d: Audio Start procedure failed"
+					"rc=%d\n", __func__,
 					audio->ac->session, rc);
 			break;
 		}
@@ -141,8 +101,8 @@
 		pr_debug("%s:AUDIO_STOP\n", __func__);
 		rc = audio_in_disable(audio);
 		if (rc  < 0) {
-			pr_err("%s:session id %d: Audio Stop procedure failed\
-				rc=%d\n", __func__,
+			pr_err("%s:session id %d: Audio Stop procedure failed"
+				"rc=%d\n", __func__,
 				audio->ac->session, rc);
 			break;
 		}
@@ -196,16 +156,16 @@
 	audio = kzalloc(sizeof(struct q6audio_in), GFP_KERNEL);
 
 	if (audio == NULL) {
-		pr_err("%s Could not allocate memory for amrnb\
-			driver\n", __func__);
+		pr_err("%s Could not allocate memory for amrnb"
+			"driver\n", __func__);
 		return -ENOMEM;
 	}
 	/* Allocate memory for encoder config param */
 	audio->enc_cfg = kzalloc(sizeof(struct msm_audio_amrnb_enc_config_v2),
 				GFP_KERNEL);
 	if (audio->enc_cfg == NULL) {
-		pr_err("%s:session id %d: Could not allocate memory for aac\
-				config param\n", __func__, audio->ac->session);
+		pr_err("%s:session id %d: Could not allocate memory for aac"
+				"config param\n", __func__, audio->ac->session);
 		kfree(audio);
 		return -ENOMEM;
 	}
@@ -234,12 +194,12 @@
 	audio->buf_cfg.meta_info_enable = 0x01;
 	audio->buf_cfg.frames_per_buf = 0x01;
 
-	audio->ac = q6asm_audio_client_alloc((app_cb)q6asm_amrnb_in_cb,
+	audio->ac = q6asm_audio_client_alloc((app_cb)q6asm_in_cb,
 				(void *)audio);
 
 	if (!audio->ac) {
-		pr_err("%s: Could not allocate memory for audio\
-				client\n", __func__);
+		pr_err("%s: Could not allocate memory for audio"
+				"client\n", __func__);
 		kfree(audio->enc_cfg);
 		kfree(audio);
 		return -ENOMEM;
@@ -272,8 +232,8 @@
 		/* register for tx overflow (valid for tunnel mode only) */
 		rc = q6asm_reg_tx_overflow(audio->ac, 0x01);
 		if (rc < 0) {
-			pr_err("%s:session id %d: TX Overflow registration\
-				failed rc=%d\n", __func__, audio->ac->session,
+			pr_err("%s:session id %d: TX Overflow registration"
+				"failed rc=%d\n", __func__, audio->ac->session,
 				rc);
 			rc = -ENODEV;
 			goto fail;
diff --git a/arch/arm/mach-msm/qdsp6v2/amrwb_in.c b/arch/arm/mach-msm/qdsp6v2/amrwb_in.c
index 5df976d..d0462e0 100644
--- a/arch/arm/mach-msm/qdsp6v2/amrwb_in.c
+++ b/arch/arm/mach-msm/qdsp6v2/amrwb_in.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -19,8 +19,6 @@
 #include <linux/slab.h>
 #include <linux/uaccess.h>
 #include <linux/wait.h>
-#include <sound/apr_audio.h>
-#include <sound/q6asm.h>
 #include <asm/atomic.h>
 #include <asm/ioctls.h>
 #include "audio_utils.h"
@@ -31,44 +29,6 @@
 /* Maximum 10 frames in buffer with meta */
 #define FRAME_SIZE		(1 + ((61+sizeof(struct meta_out_dsp)) * 10))
 
-void q6asm_amrwb_in_cb(uint32_t opcode, uint32_t token,
-		uint32_t *payload, void *priv)
-{
-	struct q6audio_in * audio = (struct q6audio_in *)priv;
-	unsigned long flags;
-
-	pr_debug("%s:session id %d: opcode - %d\n", __func__,
-			audio->ac->session, opcode);
-
-	spin_lock_irqsave(&audio->dsp_lock, flags);
-	switch (opcode) {
-	case ASM_DATA_EVENT_READ_DONE:
-		audio_in_get_dsp_frames(audio, token, payload);
-		break;
-	case ASM_DATA_EVENT_WRITE_DONE:
-		atomic_inc(&audio->in_count);
-		wake_up(&audio->write_wait);
-		break;
-	case ASM_DATA_CMDRSP_EOS:
-		audio->eos_rsp = 1;
-		wake_up(&audio->read_wait);
-		break;
-	case ASM_STREAM_CMDRSP_GET_ENCDEC_PARAM:
-		break;
-	case ASM_STREAM_CMDRSP_GET_PP_PARAMS:
-		break;
-	case ASM_SESSION_EVENT_TX_OVERFLOW:
-		pr_err("%s:session id %d: ASM_SESSION_EVENT_TX_OVERFLOW\n",
-			__func__, audio->ac->session);
-		break;
-	default:
-		pr_err("%s:session id %d: Ignore opcode[0x%x]\n", __func__,
-				audio->ac->session, opcode);
-		break;
-	}
-	spin_unlock_irqrestore(&audio->dsp_lock, flags);
-}
-
 /* ------------------- device --------------------- */
 static long amrwb_in_ioctl(struct file *file,
 				unsigned int cmd, unsigned long arg)
@@ -231,7 +191,7 @@
 	audio->buf_cfg.meta_info_enable = 0x01;
 	audio->buf_cfg.frames_per_buf = 0x01;
 
-	audio->ac = q6asm_audio_client_alloc((app_cb)q6asm_amrwb_in_cb,
+	audio->ac = q6asm_audio_client_alloc((app_cb)q6asm_in_cb,
 				(void *)audio);
 
 	if (!audio->ac) {
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_aac.c b/arch/arm/mach-msm/qdsp6v2/audio_aac.c
index 88189f6..485234f 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_aac.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_aac.c
@@ -2,7 +2,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -21,28 +21,6 @@
 #define AUDIO_AAC_DUAL_MONO_INVALID -1
 #define PCM_BUFSZ_MIN_AAC	((8*1024) + sizeof(struct dec_meta_out))
 
-static void q6_audio_aac_cb(uint32_t opcode, uint32_t token,
-		uint32_t *payload, void *priv)
-{
-	struct q6audio_aio *audio = (struct q6audio_aio *)priv;
-
-	pr_debug("%s:opcode = %x token = 0x%x\n", __func__, opcode, token);
-	switch (opcode) {
-	case ASM_DATA_EVENT_WRITE_DONE:
-	case ASM_DATA_EVENT_READ_DONE:
-	case ASM_DATA_CMDRSP_EOS:
-	case ASM_DATA_CMD_MEDIA_FORMAT_UPDATE:
-	case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
-	case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY:
-	case ASM_DATA_EVENT_ENC_SR_CM_NOTIFY:
-		audio_aio_cb(opcode, token, payload, audio);
-		break;
-	default:
-		pr_debug("%s:Unhandled event = 0x%8x\n", __func__, opcode);
-		break;
-	}
-}
-
 #ifdef CONFIG_DEBUG_FS
 static const struct file_operations audio_aac_debug_fops = {
 	.read = audio_aio_debug_read,
@@ -222,8 +200,8 @@
 	audio->codec_cfg = kzalloc(sizeof(struct msm_audio_aac_config),
 					GFP_KERNEL);
 	if (audio->codec_cfg == NULL) {
-		pr_err("%s:Could not allocate memory for aac\
-			config\n", __func__);
+		pr_err("%s:Could not allocate memory for aac"
+			"config\n", __func__);
 		kfree(audio);
 		return -ENOMEM;
 	}
@@ -235,7 +213,7 @@
 	audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN_AAC;
 	aac_config->dual_mono_mode = AUDIO_AAC_DUAL_MONO_INVALID;
 
-	audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_aac_cb,
+	audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
 					     (void *)audio);
 
 	if (!audio->ac) {
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_amrnb.c b/arch/arm/mach-msm/qdsp6v2/audio_amrnb.c
index 6768f7a..f4316d0 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_amrnb.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_amrnb.c
@@ -2,7 +2,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -16,24 +16,6 @@
  */
 #include "audio_utils_aio.h"
 
-static void q6_audio_amrnb_cb(uint32_t opcode, uint32_t token,
-		uint32_t *payload, void *priv)
-{
-	struct q6audio_aio *audio = (struct q6audio_aio *)priv;
-
-	pr_debug("%s:opcde = %d token = 0x%x\n", __func__, opcode, token);
-	switch (opcode) {
-	case ASM_DATA_EVENT_WRITE_DONE:
-	case ASM_DATA_EVENT_READ_DONE:
-	case ASM_DATA_CMDRSP_EOS:
-		audio_aio_cb(opcode, token, payload, audio);
-		break;
-	default:
-		pr_debug("%s:Unhandled event = 0x%8x\n", __func__, opcode);
-		break;
-	}
-}
-
 #ifdef CONFIG_DEBUG_FS
 static const struct file_operations audio_amrnb_debug_fops = {
 	.read = audio_aio_debug_read,
@@ -101,7 +83,7 @@
 
 	audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
 
-	audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_amrnb_cb,
+	audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
 					     (void *)audio);
 
 	if (!audio->ac) {
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_amrwb.c b/arch/arm/mach-msm/qdsp6v2/audio_amrwb.c
index f95e191..28c1732 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_amrwb.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_amrwb.c
@@ -2,7 +2,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -17,24 +17,6 @@
 
 #include "audio_utils_aio.h"
 
-static void q6_audio_amrwb_cb(uint32_t opcode, uint32_t token,
-		uint32_t *payload, void *priv)
-{
-	struct q6audio_aio *audio = (struct q6audio_aio *)priv;
-
-	pr_debug("%s:opcde = %d token = 0x%x\n", __func__, opcode, token);
-	switch (opcode) {
-	case ASM_DATA_EVENT_WRITE_DONE:
-	case ASM_DATA_EVENT_READ_DONE:
-	case ASM_DATA_CMDRSP_EOS:
-		audio_aio_cb(opcode, token, payload, audio);
-		break;
-	default:
-		pr_debug("%s:Unhandled event = 0x%8x\n", __func__, opcode);
-		break;
-	}
-}
-
 #ifdef CONFIG_DEBUG_FS
 static const struct file_operations audio_amrwb_debug_fops = {
 	.read = audio_aio_debug_read,
@@ -103,7 +85,7 @@
 	}
 	audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
 
-	audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_amrwb_cb,
+	audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
 					     (void *)audio);
 
 	if (!audio->ac) {
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_evrc.c b/arch/arm/mach-msm/qdsp6v2/audio_evrc.c
index 12c815d..ec5162d 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_evrc.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_evrc.c
@@ -2,7 +2,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -17,23 +17,7 @@
 
 #include "audio_utils_aio.h"
 
-static void q6_audio_evrc_cb(uint32_t opcode, uint32_t token,
-		uint32_t *payload, void *priv)
-{
-	struct q6audio_aio *audio = (struct q6audio_aio *)priv;
 
-	pr_debug("%s:opcde = %d token = 0x%x\n", __func__, opcode, token);
-	switch (opcode) {
-	case ASM_DATA_EVENT_WRITE_DONE:
-	case ASM_DATA_EVENT_READ_DONE:
-	case ASM_DATA_CMDRSP_EOS:
-		audio_aio_cb(opcode, token, payload, audio);
-		break;
-	default:
-		pr_debug("%s:Unhandled event = 0x%8x\n", __func__, opcode);
-		break;
-	}
-}
 
 #ifdef CONFIG_DEBUG_FS
 static const struct file_operations audio_evrc_debug_fops = {
@@ -107,7 +91,7 @@
 	 */
 	audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
 
-	audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_evrc_cb,
+	audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
 					     (void *)audio);
 
 	if (!audio->ac) {
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_mp3.c b/arch/arm/mach-msm/qdsp6v2/audio_mp3.c
index 22552c6..93a8739 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_mp3.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_mp3.c
@@ -2,7 +2,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -17,24 +17,6 @@
 
 #include "audio_utils_aio.h"
 
-static void q6_audio_mp3_cb(uint32_t opcode, uint32_t token,
-		uint32_t *payload, void *priv)
-{
-	struct q6audio_aio *audio = (struct q6audio_aio *)priv;
-
-	pr_debug("%s:opcde = %d token = 0x%x\n", __func__, opcode, token);
-	switch (opcode) {
-	case ASM_DATA_EVENT_WRITE_DONE:
-	case ASM_DATA_EVENT_READ_DONE:
-	case ASM_DATA_CMDRSP_EOS:
-		audio_aio_cb(opcode, token, payload, audio);
-		break;
-	default:
-		pr_debug("%s:Unhandled event = 0x%8x\n", __func__, opcode);
-		break;
-	}
-}
-
 #ifdef CONFIG_DEBUG_FS
 static const struct file_operations audio_mp3_debug_fops = {
 	.read = audio_aio_debug_read,
@@ -103,7 +85,7 @@
 
 	audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
 
-	audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_mp3_cb,
+	audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
 					     (void *)audio);
 
 	if (!audio->ac) {
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c b/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c
index 8a0ba3e..9253056 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c
@@ -25,28 +25,6 @@
 /* Default number of pre-allocated event packets */
 #define PCM_BUFSZ_MIN_AACM	((8*1024) + sizeof(struct dec_meta_out))
 
-static void q6_audio_aac_cb(uint32_t opcode, uint32_t token,
-		uint32_t *payload, void *priv)
-{
-	struct q6audio_aio *audio = (struct q6audio_aio *)priv;
-
-	pr_debug("%s:opcode = %x token = 0x%x\n", __func__, opcode, token);
-	switch (opcode) {
-	case ASM_DATA_EVENT_WRITE_DONE:
-	case ASM_DATA_EVENT_READ_DONE:
-	case ASM_DATA_CMDRSP_EOS:
-	case ASM_DATA_CMD_MEDIA_FORMAT_UPDATE:
-	case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
-	case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY:
-	case ASM_DATA_EVENT_ENC_SR_CM_NOTIFY:
-		audio_aio_cb(opcode, token, payload, audio);
-		break;
-	default:
-		pr_debug("%s:Unhandled event = 0x%8x\n", __func__, opcode);
-		break;
-	}
-}
-
 #ifdef CONFIG_DEBUG_FS
 static const struct file_operations audio_aac_debug_fops = {
 	.read = audio_aio_debug_read,
@@ -234,8 +212,8 @@
 	audio->codec_cfg = kzalloc(sizeof(struct msm_audio_aac_config),
 					GFP_KERNEL);
 	if (audio->codec_cfg == NULL) {
-		pr_err("%s: Could not allocate memory for aac\
-			config\n", __func__);
+		pr_err("%s: Could not allocate memory for aac"
+			"config\n", __func__);
 		kfree(audio);
 		return -ENOMEM;
 	}
@@ -245,7 +223,7 @@
 	audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN_AACM;
 	aac_config->dual_mono_mode = AUDIO_AAC_DUAL_MONO_INVALID;
 
-	audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_aac_cb,
+	audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
 					     (void *)audio);
 
 	if (!audio->ac) {
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_qcelp.c b/arch/arm/mach-msm/qdsp6v2/audio_qcelp.c
index 7b72c97..37f6e6b 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_qcelp.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_qcelp.c
@@ -2,7 +2,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -19,23 +19,6 @@
 
 #define FRAME_SIZE_DEC_QCELP  ((32) + sizeof(struct dec_meta_in))
 
-static void q6_audio_qcelp_cb(uint32_t opcode, uint32_t token,
-		uint32_t *payload, void *priv)
-{
-	struct q6audio_aio *audio = (struct q6audio_aio *)priv;
-
-	switch (opcode) {
-	case ASM_DATA_EVENT_WRITE_DONE:
-	case ASM_DATA_EVENT_READ_DONE:
-	case ASM_DATA_CMDRSP_EOS:
-		audio_aio_cb(opcode, token, payload, audio);
-		break;
-	default:
-		pr_debug("%s:Unhandled event = 0x%8x\n", __func__, opcode);
-		break;
-	}
-}
-
 #ifdef CONFIG_DEBUG_FS
 static const struct file_operations audio_qcelp_debug_fops = {
 	.read = audio_aio_debug_read,
@@ -113,7 +96,7 @@
 	audio->pcm_cfg.sample_rate = 8000;
 	audio->pcm_cfg.channel_count = 1;
 
-	audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_qcelp_cb,
+	audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
 					     (void *)audio);
 
 	if (!audio->ac) {
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils.c b/arch/arm/mach-msm/qdsp6v2/audio_utils.c
index f9445d8..6a23e37 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -21,8 +21,6 @@
 #include <linux/slab.h>
 #include <asm/atomic.h>
 #include <asm/ioctls.h>
-#include <sound/q6asm.h>
-#include <sound/apr_audio.h>
 #include "audio_utils.h"
 
 static int audio_in_pause(struct q6audio_in  *audio)
@@ -86,35 +84,6 @@
 	return 0;
 }
 
-void  audio_in_get_dsp_frames(struct q6audio_in *audio,
-	uint32_t token,	uint32_t *payload)
-{
-	uint32_t index;
-
-	index = token;
-	pr_debug("%s:session id %d: index=%d nr frames=%d offset[%d]\n",
-			__func__, audio->ac->session, token, payload[7],
-			payload[3]);
-	pr_debug("%s:session id %d: timemsw=%d lsw=%d\n", __func__,
-			audio->ac->session, payload[4], payload[5]);
-	pr_debug("%s:session id %d: uflags=0x%8x uid=0x%8x\n", __func__,
-			audio->ac->session, payload[6], payload[8]);
-	pr_debug("%s:session id %d: enc frame size=0x%8x\n", __func__,
-			audio->ac->session, payload[2]);
-
-	audio->out_frame_info[index][0] = payload[7];
-	audio->out_frame_info[index][1] = payload[3];
-
-	/* statistics of read */
-	atomic_add(payload[2], &audio->in_bytes);
-	atomic_add(payload[7], &audio->in_samples);
-
-	if (atomic_read(&audio->out_count) <= audio->str_cfg.buffer_count) {
-		atomic_inc(&audio->out_count);
-		wake_up(&audio->read_wait);
-	}
-}
-
 /* must be called with audio->lock held */
 int audio_in_enable(struct q6audio_in  *audio)
 {
@@ -140,8 +109,8 @@
 
 		rc = q6asm_cmd(audio->ac, CMD_CLOSE);
 		if (rc < 0)
-			pr_err("%s:session id %d: Failed to close the\
-				session rc=%d\n", __func__, audio->ac->session,
+			pr_err("%s:session id %d: Failed to close the"
+				"session rc=%d\n", __func__, audio->ac->session,
 				rc);
 		audio->stopped = 1;
 		memset(audio->out_frame_info, 0,
@@ -166,8 +135,8 @@
 				ALIGN_BUF_SIZE(audio->pcm_cfg.buffer_size),
 				audio->pcm_cfg.buffer_count);
 			if (rc < 0) {
-				pr_err("%s:session id %d: Buffer Alloc\
-						failed\n", __func__,
+				pr_err("%s:session id %d: Buffer Alloc"
+						"failed\n", __func__,
 						audio->ac->session);
 				rc = -ENOMEM;
 				break;
@@ -203,8 +172,8 @@
 				ALIGN_BUF_SIZE(audio->pcm_cfg.buffer_size),
 				audio->pcm_cfg.buffer_count);
 			if (rc < 0) {
-				pr_err("%s:session id %d: Buffer Alloc\
-					failed\n", __func__,
+				pr_err("%s:session id %d: Buffer Alloc"
+					"failed\n", __func__,
 					audio->ac->session);
 				rc = -ENOMEM;
 				break;
@@ -334,15 +303,15 @@
 		}
 		audio->buf_cfg.meta_info_enable = cfg.meta_info_enable;
 		audio->buf_cfg.frames_per_buf = cfg.frames_per_buf;
-		pr_debug("%s:session id %d: Set-buf-cfg: meta[%d]\
-				framesperbuf[%d]\n", __func__,
+		pr_debug("%s:session id %d: Set-buf-cfg: meta[%d]"
+				"framesperbuf[%d]\n", __func__,
 				audio->ac->session, cfg.meta_info_enable,
 				cfg.frames_per_buf);
 		break;
 	}
 	case AUDIO_GET_BUF_CFG: {
-		pr_debug("%s:session id %d: Get-buf-cfg: meta[%d]\
-			framesperbuf[%d]\n", __func__,
+		pr_debug("%s:session id %d: Get-buf-cfg: meta[%d]"
+			"framesperbuf[%d]\n", __func__,
 			audio->ac->session, audio->buf_cfg.meta_info_enable,
 			audio->buf_cfg.frames_per_buf);
 
@@ -437,8 +406,8 @@
 
 		if ((audio->stopped && !(atomic_read(&audio->out_count))) ||
 			audio->rflush) {
-			pr_debug("%s:session id %d: driver in stop state or\
-				flush,No more buf to read", __func__,
+			pr_debug("%s:session id %d: driver in stop state or"
+				"flush,No more buf to read", __func__,
 				audio->ac->session);
 			rc = 0;/* End of File */
 			break;
@@ -504,8 +473,8 @@
 			count -= bytes_to_copy;
 			buf += bytes_to_copy;
 		} else {
-			pr_err("%s:session id %d: short read data[%p]\
-				bytesavail[%d]bytesrequest[%d]\n", __func__,
+			pr_err("%s:session id %d: short read data[%p]"
+				"bytesavail[%d]bytesrequest[%d]\n", __func__,
 				audio->ac->session,
 				data, size, count);
 		}
@@ -585,8 +554,8 @@
 						&nflags);
 			buf += mfield_size;
 			/* send the EOS and return */
-			pr_debug("%s:session id %d: send EOS\
-				0x%8x\n", __func__,
+			pr_debug("%s:session id %d: send EOS"
+				"0x%8x\n", __func__,
 				audio->ac->session, nflags);
 			break;
 		}
@@ -613,8 +582,8 @@
 				buf += mfield_size;
 				count -= mfield_size;
 			} else {
-				pr_debug("%s:session id %d: continuous\
-				buffer\n", __func__, audio->ac->session);
+				pr_debug("%s:session id %d: continuous"
+				"buffer\n", __func__, audio->ac->session);
 			}
 		}
 		xfer = (count > (audio->pcm_cfg.buffer_size)) ?
@@ -634,8 +603,8 @@
 		buf += xfer;
 	}
 	mutex_unlock(&audio->write_lock);
-	pr_debug("%s:session id %d: eos_condition 0x%8x buf[0x%x]\
-			start[0x%x]\n", __func__, audio->ac->session,
+	pr_debug("%s:session id %d: eos_condition 0x%8x buf[0x%x]"
+			"start[0x%x]\n", __func__, audio->ac->session,
 				nflags,	(int) buf, (int) start);
 	if (nflags & AUD_EOS_SET) {
 		rc = q6asm_cmd(audio->ac, CMD_EOS);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils.h b/arch/arm/mach-msm/qdsp6v2/audio_utils.h
index 7a696ca..df963f9 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils.h
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -11,6 +11,7 @@
  *
 */
 #include <linux/msm_audio.h>
+#include "q6audio_common.h"
 
 #define FRAME_NUM	(8)
 
@@ -26,18 +27,18 @@
 #define BUF_ALLOC_INOUT 0x03
 #define ALIGN_BUF_SIZE(size) ((size + 4095) & (~4095))
 
-struct timestamp{
+struct timestamp {
 	unsigned long lowpart;
 	unsigned long highpart;
 } __attribute__ ((packed));
 
-struct meta_in{
+struct meta_in {
 	unsigned short offset;
 	struct timestamp ntimestamp;
 	unsigned int nflags;
 } __attribute__ ((packed));
 
-struct meta_out_dsp{
+struct meta_out_dsp {
 	u32 offset_to_frame;
 	u32 frame_size;
 	u32 encoded_pcm_samples;
@@ -46,12 +47,12 @@
 	u32 nflags;
 } __attribute__ ((packed));
 
-struct meta_out{
+struct meta_out {
 	unsigned char num_of_frames;
 	struct meta_out_dsp meta_out_dsp[];
 } __attribute__ ((packed));
 
-struct q6audio_in{
+struct q6audio_in {
 	spinlock_t			dsp_lock;
 	atomic_t			in_bytes;
 	atomic_t			in_samples;
@@ -89,8 +90,6 @@
 	long (*enc_ioctl)(struct file *, unsigned int, unsigned long);
 };
 
-void  audio_in_get_dsp_frames(struct q6audio_in *audio,
-		uint32_t token,	uint32_t *payload);
 int audio_in_enable(struct q6audio_in  *audio);
 int audio_in_disable(struct q6audio_in  *audio);
 int audio_in_buf_alloc(struct q6audio_in *audio);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
index 644df2d..cef2fae 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
@@ -23,8 +23,6 @@
 #include <linux/slab.h>
 #include <asm/atomic.h>
 #include <asm/ioctls.h>
-#include <sound/q6asm.h>
-#include <sound/apr_audio.h>
 #include <linux/debugfs.h>
 #include "audio_utils_aio.h"
 
@@ -295,8 +293,8 @@
 		kfree(used_buf);
 		if (list_empty(&audio->out_queue) &&
 			(audio->drv_status & ADRV_STATUS_FSYNC)) {
-			pr_debug("%s[%p]: list is empty, reached EOS in\
-				Tunnel\n", __func__, audio);
+			pr_debug("%s[%p]: list is empty, reached EOS in"
+				"Tunnel\n", __func__, audio);
 			wake_up(&audio->write_wait);
 		}
 	} else {
@@ -424,72 +422,6 @@
 	}
 }
 
-void audio_aio_cb(uint32_t opcode, uint32_t token,
-		uint32_t *payload,  struct q6audio_aio *audio)
-{
-	union msm_audio_event_payload e_payload;
-
-	switch (opcode) {
-	case ASM_DATA_EVENT_WRITE_DONE:
-		pr_debug("%s[%p]:ASM_DATA_EVENT_WRITE_DONE token = 0x%x\n",
-			__func__, audio, token);
-		audio_aio_async_write_ack(audio, token, payload);
-		break;
-	case ASM_DATA_EVENT_READ_DONE:
-		pr_debug("%s[%p]:ASM_DATA_EVENT_READ_DONE token = 0x%x\n",
-			__func__, audio, token);
-		audio_aio_async_read_ack(audio, token, payload);
-		break;
-	case ASM_DATA_CMDRSP_EOS:
-		/* EOS Handle */
-		pr_debug("%s[%p]:ASM_DATA_CMDRSP_EOS\n", __func__, audio);
-		if (audio->feedback) { /* Non-Tunnel mode */
-			audio->eos_rsp = 1;
-			/* propagate input EOS i/p buffer,
-			after receiving DSP acknowledgement */
-			if (audio->eos_flag &&
-				(audio->eos_write_payload.aio_buf.buf_addr)) {
-				audio_aio_post_event(audio,
-						AUDIO_EVENT_WRITE_DONE,
-						audio->eos_write_payload);
-				memset(&audio->eos_write_payload , 0,
-					sizeof(union msm_audio_event_payload));
-				audio->eos_flag = 0;
-			}
-		} else { /* Tunnel mode */
-			audio->eos_rsp = 1;
-			wake_up(&audio->write_wait);
-			wake_up(&audio->cmd_wait);
-		}
-		break;
-	case ASM_DATA_CMD_MEDIA_FORMAT_UPDATE:
-	case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
-		pr_debug("%s[%p]:payload0[%x] payloa1d[%x]opcode= 0x%x\n",
-			__func__, audio, payload[0], payload[1], opcode);
-		break;
-	case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY:
-	case ASM_DATA_EVENT_ENC_SR_CM_NOTIFY:
-		pr_debug("%s[%p]: ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY, "
-
-				"payload[0]-sr = %d, payload[1]-chl = %d, "
-				"payload[2] = %d, payload[3] = %d\n", __func__,
-				audio, payload[0], payload[1], payload[2],
-				payload[3]);
-		pr_debug("%s[%p]: ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY, "
-				"sr(prev) = %d, chl(prev) = %d,",
-				__func__, audio, audio->pcm_cfg.sample_rate,
-		audio->pcm_cfg.channel_count);
-		audio->pcm_cfg.sample_rate = payload[0];
-		audio->pcm_cfg.channel_count = payload[1] & 0xFFFF;
-		e_payload.stream_info.chan_info = audio->pcm_cfg.channel_count;
-		e_payload.stream_info.sample_rate = audio->pcm_cfg.sample_rate;
-		audio_aio_post_event(audio, AUDIO_EVENT_STREAM_INFO, e_payload);
-		break;
-	default:
-		break;
-	}
-}
-
 int audio_aio_enable(struct q6audio_aio  *audio)
 {
 	/* 2nd arg: 0 -> run immediately
@@ -1041,8 +973,8 @@
 		return -EFAULT;
 	}
 
-	pr_debug("%s[%p]:node %p dir %x buf_addr %p buf_len %d data_len \
-		%d\n", __func__, audio, buf_node, dir, buf_node->buf.buf_addr,
+	pr_debug("%s[%p]:node %p dir %x buf_addr %p buf_len %d data_len"
+		"%d\n", __func__, audio, buf_node, dir, buf_node->buf.buf_addr,
 		buf_node->buf.buf_len, buf_node->buf.data_len);
 	buf_node->paddr = audio_aio_ion_fixup(audio, buf_node->buf.buf_addr,
 						buf_node->buf.buf_len, 1,
@@ -1447,8 +1379,8 @@
 		break;
 	}
 	case AUDIO_GET_BUF_CFG: {
-		pr_debug("%s[%p]:session id %d: Get-buf-cfg: meta[%d]\
-			framesperbuf[%d]\n", __func__, audio,
+		pr_debug("%s[%p]:session id %d: Get-buf-cfg: meta[%d]"
+			"framesperbuf[%d]\n", __func__, audio,
 			audio->ac->session, audio->buf_cfg.meta_info_enable,
 			audio->buf_cfg.frames_per_buf);
 
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.h b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.h
index a25ca4d..16acb06 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.h
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.h
@@ -27,8 +27,7 @@
 #include <linux/ion.h>
 #include <asm/ioctls.h>
 #include <asm/atomic.h>
-#include <sound/q6asm.h>
-#include <sound/apr_audio.h>
+#include "q6audio_common.h"
 
 #define TUNNEL_MODE     0x0000
 #define NON_TUNNEL_MODE 0x0001
@@ -190,6 +189,12 @@
 	long (*codec_ioctl)(struct file *, unsigned int, unsigned long);
 };
 
+void audio_aio_async_write_ack(struct q6audio_aio *audio, uint32_t token,
+				uint32_t *payload);
+
+void audio_aio_async_read_ack(struct q6audio_aio *audio, uint32_t token,
+			uint32_t *payload);
+
 int audio_aio_open(struct q6audio_aio *audio, struct file *file);
 int audio_aio_enable(struct q6audio_aio  *audio);
 void audio_aio_post_event(struct q6audio_aio *audio, int type,
@@ -197,8 +202,6 @@
 int audio_aio_release(struct inode *inode, struct file *file);
 long audio_aio_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
 int audio_aio_fsync(struct file *file, int datasync);
-void audio_aio_cb(uint32_t opcode, uint32_t token,
-			uint32_t *payload,  struct q6audio_aio *audio);
 void audio_aio_async_out_flush(struct q6audio_aio *audio);
 void audio_aio_async_in_flush(struct q6audio_aio *audio);
 #ifdef CONFIG_DEBUG_FS
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_wma.c b/arch/arm/mach-msm/qdsp6v2/audio_wma.c
index bea0485..021d58b 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_wma.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_wma.c
@@ -2,7 +2,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -19,24 +19,6 @@
 #include <linux/msm_audio_wma.h>
 #include "audio_utils_aio.h"
 
-static void q6_audio_wma_cb(uint32_t opcode, uint32_t token,
-		uint32_t *payload, void *priv)
-{
-	struct q6audio_aio *audio = (struct q6audio_aio *)priv;
-
-	pr_debug("%s:opcode = %x token = 0x%x\n", __func__, opcode, token);
-	switch (opcode) {
-	case ASM_DATA_EVENT_WRITE_DONE:
-	case ASM_DATA_EVENT_READ_DONE:
-	case ASM_DATA_CMDRSP_EOS:
-		audio_aio_cb(opcode, token, payload, audio);
-		break;
-	default:
-		pr_debug("%s:Unhandled event = 0x%8x\n", __func__, opcode);
-		break;
-	}
-}
-
 #ifdef CONFIG_DEBUG_FS
 static const struct file_operations audio_wma_debug_fops = {
 	.read = audio_aio_debug_read,
@@ -139,15 +121,15 @@
 	audio->codec_cfg = kzalloc(sizeof(struct msm_audio_wma_config_v2),
 					GFP_KERNEL);
 	if (audio->codec_cfg == NULL) {
-		pr_err("%s:Could not allocate memory for wma\
-			config\n", __func__);
+		pr_err("%s:Could not allocate memory for wma"
+			"config\n", __func__);
 		kfree(audio);
 		return -ENOMEM;
 	}
 
 	audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
 
-	audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_wma_cb,
+	audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
 					     (void *)audio);
 
 	if (!audio->ac) {
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_wmapro.c b/arch/arm/mach-msm/qdsp6v2/audio_wmapro.c
index 98d1b30..4fcdcc1 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_wmapro.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_wmapro.c
@@ -2,7 +2,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -19,24 +19,6 @@
 #include <linux/msm_audio_wmapro.h>
 #include "audio_utils_aio.h"
 
-static void q6_audio_wmapro_cb(uint32_t opcode, uint32_t token,
-		uint32_t *payload, void *priv)
-{
-	struct q6audio_aio *audio = (struct q6audio_aio *)priv;
-
-	pr_debug("%s:opcode = %x token = 0x%x\n", __func__, opcode, token);
-	switch (opcode) {
-	case ASM_DATA_EVENT_WRITE_DONE:
-	case ASM_DATA_EVENT_READ_DONE:
-	case ASM_DATA_CMDRSP_EOS:
-		audio_aio_cb(opcode, token, payload, audio);
-		break;
-	default:
-		pr_debug("%s:Unhandled event = 0x%8x\n", __func__, opcode);
-		break;
-	}
-}
-
 #ifdef CONFIG_DEBUG_FS
 static const struct file_operations audio_wmapro_debug_fops = {
 	.read = audio_aio_debug_read,
@@ -197,8 +179,8 @@
 	audio->codec_cfg = kzalloc(sizeof(struct msm_audio_wmapro_config),
 					GFP_KERNEL);
 	if (audio->codec_cfg == NULL) {
-		pr_err("%s: Could not allocate memory for wmapro\
-			config\n", __func__);
+		pr_err("%s: Could not allocate memory for wmapro"
+			"config\n", __func__);
 		kfree(audio);
 		return -ENOMEM;
 	}
@@ -206,7 +188,7 @@
 
 	audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
 
-	audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_wmapro_cb,
+	audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
 					     (void *)audio);
 
 	if (!audio->ac) {
diff --git a/arch/arm/mach-msm/qdsp6v2/evrc_in.c b/arch/arm/mach-msm/qdsp6v2/evrc_in.c
index ffe10bc..b95d659 100644
--- a/arch/arm/mach-msm/qdsp6v2/evrc_in.c
+++ b/arch/arm/mach-msm/qdsp6v2/evrc_in.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -22,8 +22,6 @@
 #include <linux/msm_audio_qcp.h>
 #include <asm/atomic.h>
 #include <asm/ioctls.h>
-#include <sound/q6asm.h>
-#include <sound/apr_audio.h>
 #include "audio_utils.h"
 
 /* Buffer with meta*/
@@ -32,44 +30,6 @@
 /* Maximum 10 frames in buffer with meta */
 #define FRAME_SIZE		(1 + ((23+sizeof(struct meta_out_dsp)) * 10))
 
-void q6asm_evrc_in_cb(uint32_t opcode, uint32_t token,
-		uint32_t *payload, void *priv)
-{
-	struct q6audio_in * audio = (struct q6audio_in *)priv;
-	unsigned long flags;
-
-	pr_debug("%s:session id %d: opcode - %d\n", __func__,
-			audio->ac->session, opcode);
-
-	spin_lock_irqsave(&audio->dsp_lock, flags);
-	switch (opcode) {
-	case ASM_DATA_EVENT_READ_DONE:
-		audio_in_get_dsp_frames(audio, token, payload);
-		break;
-	case ASM_DATA_EVENT_WRITE_DONE:
-		atomic_inc(&audio->in_count);
-		wake_up(&audio->write_wait);
-		break;
-	case ASM_DATA_CMDRSP_EOS:
-		audio->eos_rsp = 1;
-		wake_up(&audio->read_wait);
-		break;
-	case ASM_STREAM_CMDRSP_GET_ENCDEC_PARAM:
-		break;
-	case ASM_STREAM_CMDRSP_GET_PP_PARAMS:
-		break;
-	case ASM_SESSION_EVENT_TX_OVERFLOW:
-		pr_err("%s:session id %d: ASM_SESSION_EVENT_TX_OVERFLOW\n",
-				__func__, audio->ac->session);
-		break;
-	default:
-		pr_err("%s:session id %d: Ignore opcode[0x%x]\n", __func__,
-				audio->ac->session, opcode);
-		break;
-	}
-	spin_unlock_irqrestore(&audio->dsp_lock, flags);
-}
-
 /* ------------------- device --------------------- */
 static long evrc_in_ioctl(struct file *file,
 				unsigned int cmd, unsigned long arg)
@@ -104,8 +64,8 @@
 			enc_cfg->max_bit_rate, 0);
 
 		if (rc < 0) {
-			pr_err("%s:session id %d: cmd evrc media format block\
-				failed\n", __func__, audio->ac->session);
+			pr_err("%s:session id %d: cmd evrc media format block"
+				"failed\n", __func__, audio->ac->session);
 			break;
 		}
 		if (audio->feedback == NON_TUNNEL_MODE) {
@@ -114,8 +74,8 @@
 				audio->pcm_cfg.channel_count);
 
 			if (rc < 0) {
-				pr_err("%s:session id %d: media format block\
-				failed\n", __func__, audio->ac->session);
+				pr_err("%s:session id %d: media format block"
+				"failed\n", __func__, audio->ac->session);
 				break;
 			}
 		}
@@ -126,8 +86,8 @@
 			audio->enabled = 1;
 		} else {
 			audio->enabled = 0;
-			pr_err("%s:session id %d: Audio Start procedure failed\
-				rc=%d\n", __func__, audio->ac->session, rc);
+			pr_err("%s:session id %d: Audio Start procedure failed"
+				"rc=%d\n", __func__, audio->ac->session, rc);
 			break;
 		}
 		while (cnt++ < audio->str_cfg.buffer_count)
@@ -142,8 +102,8 @@
 				audio->ac->session);
 		rc = audio_in_disable(audio);
 		if (rc  < 0) {
-			pr_err("%s:session id %d: Audio Stop procedure failed\
-				rc=%d\n", __func__, audio->ac->session, rc);
+			pr_err("%s:session id %d: Audio Stop procedure failed"
+				"rc=%d\n", __func__, audio->ac->session, rc);
 			break;
 		}
 		break;
@@ -183,8 +143,8 @@
 		}
 		enc_cfg->min_bit_rate = cfg.min_bit_rate;
 		enc_cfg->max_bit_rate = cfg.max_bit_rate;
-		pr_debug("%s:session id %d: min_bit_rate= 0x%x\
-			max_bit_rate=0x%x\n", __func__,
+		pr_debug("%s:session id %d: min_bit_rate= 0x%x"
+			"max_bit_rate=0x%x\n", __func__,
 			audio->ac->session, enc_cfg->min_bit_rate,
 			enc_cfg->max_bit_rate);
 		break;
@@ -204,16 +164,16 @@
 	audio = kzalloc(sizeof(struct q6audio_in), GFP_KERNEL);
 
 	if (audio == NULL) {
-		pr_err("%s: Could not allocate memory for evrc\
-				driver\n", __func__);
+		pr_err("%s: Could not allocate memory for evrc"
+				"driver\n", __func__);
 		return -ENOMEM;
 	}
 	/* Allocate memory for encoder config param */
 	audio->enc_cfg = kzalloc(sizeof(struct msm_audio_evrc_enc_config),
 				GFP_KERNEL);
 	if (audio->enc_cfg == NULL) {
-		pr_err("%s:session id %d: Could not allocate memory for aac\
-				config param\n", __func__, audio->ac->session);
+		pr_err("%s:session id %d: Could not allocate memory for aac"
+				"config param\n", __func__, audio->ac->session);
 		kfree(audio);
 		return -ENOMEM;
 	}
@@ -241,12 +201,12 @@
 	audio->buf_cfg.meta_info_enable = 0x01;
 	audio->buf_cfg.frames_per_buf = 0x01;
 
-	audio->ac = q6asm_audio_client_alloc((app_cb)q6asm_evrc_in_cb,
+	audio->ac = q6asm_audio_client_alloc((app_cb)q6asm_in_cb,
 				(void *)audio);
 
 	if (!audio->ac) {
-		pr_err("%s: Could not allocate memory for audio\
-				client\n", __func__);
+		pr_err("%s: Could not allocate memory for audio"
+				"client\n", __func__);
 		kfree(audio->enc_cfg);
 		kfree(audio);
 		return -ENOMEM;
@@ -279,8 +239,8 @@
 		/* register for tx overflow (valid for tunnel mode only) */
 		rc = q6asm_reg_tx_overflow(audio->ac, 0x01);
 		if (rc < 0) {
-			pr_err("%s:session id %d: TX Overflow registration\
-				failed rc=%d\n", __func__,
+			pr_err("%s:session id %d: TX Overflow registration"
+				"failed rc=%d\n", __func__,
 				audio->ac->session, rc);
 			rc = -ENODEV;
 			goto fail;
diff --git a/arch/arm/mach-msm/qdsp6v2/q6audio_common.h b/arch/arm/mach-msm/qdsp6v2/q6audio_common.h
new file mode 100644
index 0000000..e108de5
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/q6audio_common.h
@@ -0,0 +1,35 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+*/
+
+/* For Decoders */
+#ifndef __Q6_AUDIO_COMMON_H__
+#define __Q6_AUDIO_COMMON_H__
+
+#include <sound/apr_audio.h>
+#include <sound/q6asm.h>
+
+void q6_audio_cb(uint32_t opcode, uint32_t token,
+		uint32_t *payload, void *priv);
+
+void audio_aio_cb(uint32_t opcode, uint32_t token,
+			uint32_t *payload,  void *audio);
+
+
+/* For Encoders */
+void q6asm_in_cb(uint32_t opcode, uint32_t token,
+		uint32_t *payload, void *priv);
+
+void  audio_in_get_dsp_frames(void *audio,
+		uint32_t token,	uint32_t *payload);
+
+#endif /*__Q6_AUDIO_COMMON_H__*/
diff --git a/arch/arm/mach-msm/qdsp6v2/q6audio_v1.c b/arch/arm/mach-msm/qdsp6v2/q6audio_v1.c
new file mode 100644
index 0000000..f49d6e0
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/q6audio_v1.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include "audio_utils.h"
+
+void q6asm_in_cb(uint32_t opcode, uint32_t token,
+		uint32_t *payload, void *priv)
+{
+	struct q6audio_in * audio = (struct q6audio_in *)priv;
+	unsigned long flags;
+
+	pr_debug("%s:session id %d: opcode[0x%x]\n", __func__,
+			audio->ac->session, opcode);
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	switch (opcode) {
+	case ASM_DATA_EVENT_READ_DONE:
+		audio_in_get_dsp_frames(audio, token, payload);
+		break;
+	case ASM_DATA_EVENT_WRITE_DONE:
+		atomic_inc(&audio->in_count);
+		wake_up(&audio->write_wait);
+		break;
+	case ASM_DATA_CMDRSP_EOS:
+		audio->eos_rsp = 1;
+		wake_up(&audio->read_wait);
+		break;
+	case ASM_STREAM_CMDRSP_GET_ENCDEC_PARAM:
+		break;
+	case ASM_STREAM_CMDRSP_GET_PP_PARAMS:
+		break;
+	case ASM_SESSION_EVENT_TX_OVERFLOW:
+		pr_err("%s:session id %d: ASM_SESSION_EVENT_TX_OVERFLOW\n",
+			__func__, audio->ac->session);
+		break;
+	default:
+		pr_debug("%s:session id %d: Ignore opcode[0x%x]\n", __func__,
+			audio->ac->session, opcode);
+		break;
+	}
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+void  audio_in_get_dsp_frames(/*struct q6audio_in *audio,*/void *aud,
+	uint32_t token,	uint32_t *payload)
+{
+	struct q6audio_in *audio = (struct q6audio_in *)aud;
+	uint32_t index;
+
+	index = token;
+	pr_debug("%s:session id %d: index=%d nr frames=%d offset[%d]\n",
+			__func__, audio->ac->session, token, payload[7],
+			payload[3]);
+	pr_debug("%s:session id %d: timemsw=%d lsw=%d\n", __func__,
+			audio->ac->session, payload[4], payload[5]);
+	pr_debug("%s:session id %d: uflags=0x%8x uid=0x%8x\n", __func__,
+			audio->ac->session, payload[6], payload[8]);
+	pr_debug("%s:session id %d: enc frame size=0x%8x\n", __func__,
+			audio->ac->session, payload[2]);
+
+	audio->out_frame_info[index][0] = payload[7];
+	audio->out_frame_info[index][1] = payload[3];
+
+	/* statistics of read */
+	atomic_add(payload[2], &audio->in_bytes);
+	atomic_add(payload[7], &audio->in_samples);
+
+	if (atomic_read(&audio->out_count) <= audio->str_cfg.buffer_count) {
+		atomic_inc(&audio->out_count);
+		wake_up(&audio->read_wait);
+	}
+}
diff --git a/arch/arm/mach-msm/qdsp6v2/q6audio_v1_aio.c b/arch/arm/mach-msm/qdsp6v2/q6audio_v1_aio.c
new file mode 100644
index 0000000..112de62
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/q6audio_v1_aio.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2012 Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include "audio_utils_aio.h"
+
+void q6_audio_cb(uint32_t opcode, uint32_t token,
+		uint32_t *payload, void *priv)
+{
+	struct q6audio_aio *audio = (struct q6audio_aio *)priv;
+
+	pr_debug("%s:opcode = %x token = 0x%x\n", __func__, opcode, token);
+	switch (opcode) {
+	case ASM_DATA_EVENT_WRITE_DONE:
+	case ASM_DATA_EVENT_READ_DONE:
+	case ASM_DATA_CMDRSP_EOS:
+	case ASM_DATA_CMD_MEDIA_FORMAT_UPDATE:
+	case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
+	case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY:
+	case ASM_DATA_EVENT_ENC_SR_CM_NOTIFY:
+		audio_aio_cb(opcode, token, payload, audio);
+		break;
+	default:
+		pr_debug("%s:Unhandled event = 0x%8x\n", __func__, opcode);
+		break;
+	}
+}
+
+void audio_aio_cb(uint32_t opcode, uint32_t token,
+		uint32_t *payload,  void *priv)
+{
+	union msm_audio_event_payload e_payload;
+	struct q6audio_aio *audio = (struct q6audio_aio *)priv;
+
+	switch (opcode) {
+	case ASM_DATA_EVENT_WRITE_DONE:
+		pr_debug("%s[%p]:ASM_DATA_EVENT_WRITE_DONE token = 0x%x\n",
+			__func__, audio, token);
+		audio_aio_async_write_ack(audio, token, payload);
+		break;
+	case ASM_DATA_EVENT_READ_DONE:
+		pr_debug("%s[%p]:ASM_DATA_EVENT_READ_DONE token = 0x%x\n",
+			__func__, audio, token);
+		audio_aio_async_read_ack(audio, token, payload);
+		break;
+	case ASM_DATA_CMDRSP_EOS:
+		/* EOS Handle */
+		pr_debug("%s[%p]:ASM_DATA_CMDRSP_EOS\n", __func__, audio);
+		if (audio->feedback) { /* Non-Tunnel mode */
+			audio->eos_rsp = 1;
+			/* propagate input EOS i/p buffer,
+			after receiving DSP acknowledgement */
+			if (audio->eos_flag &&
+				(audio->eos_write_payload.aio_buf.buf_addr)) {
+				audio_aio_post_event(audio,
+						AUDIO_EVENT_WRITE_DONE,
+						audio->eos_write_payload);
+				memset(&audio->eos_write_payload , 0,
+					sizeof(union msm_audio_event_payload));
+				audio->eos_flag = 0;
+			}
+		} else { /* Tunnel mode */
+			audio->eos_rsp = 1;
+			wake_up(&audio->write_wait);
+			wake_up(&audio->cmd_wait);
+		}
+		break;
+	case ASM_DATA_CMD_MEDIA_FORMAT_UPDATE:
+	case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
+		pr_debug("%s[%p]:payload0[%x] payloa1d[%x]opcode= 0x%x\n",
+			__func__, audio, payload[0], payload[1], opcode);
+		break;
+	case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY:
+	case ASM_DATA_EVENT_ENC_SR_CM_NOTIFY:
+		pr_debug("%s[%p]: ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY, "
+
+				"payload[0]-sr = %d, payload[1]-chl = %d, "
+				"payload[2] = %d, payload[3] = %d\n", __func__,
+				audio, payload[0], payload[1], payload[2],
+				payload[3]);
+		pr_debug("%s[%p]: ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY, "
+				"sr(prev) = %d, chl(prev) = %d,",
+				__func__, audio, audio->pcm_cfg.sample_rate,
+		audio->pcm_cfg.channel_count);
+		audio->pcm_cfg.sample_rate = payload[0];
+		audio->pcm_cfg.channel_count = payload[1] & 0xFFFF;
+		e_payload.stream_info.chan_info = audio->pcm_cfg.channel_count;
+		e_payload.stream_info.sample_rate = audio->pcm_cfg.sample_rate;
+		audio_aio_post_event(audio, AUDIO_EVENT_STREAM_INFO, e_payload);
+		break;
+	default:
+		break;
+	}
+}
diff --git a/arch/arm/mach-msm/qdsp6v2/qcelp_in.c b/arch/arm/mach-msm/qdsp6v2/qcelp_in.c
index 3cf4e25..a48df39 100644
--- a/arch/arm/mach-msm/qdsp6v2/qcelp_in.c
+++ b/arch/arm/mach-msm/qdsp6v2/qcelp_in.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -22,8 +22,6 @@
 #include <linux/msm_audio_qcp.h>
 #include <asm/atomic.h>
 #include <asm/ioctls.h>
-#include <sound/q6asm.h>
-#include <sound/apr_audio.h>
 #include "audio_utils.h"
 
 /* Buffer with meta*/
@@ -32,43 +30,6 @@
 /* Maximum 10 frames in buffer with meta */
 #define FRAME_SIZE		(1 + ((35+sizeof(struct meta_out_dsp)) * 10))
 
-void q6asm_qcelp_in_cb(uint32_t opcode, uint32_t token,
-		uint32_t *payload, void *priv)
-{
-	struct q6audio_in * audio = (struct q6audio_in *)priv;
-	unsigned long flags;
-
-	pr_debug("%s:session id %d: opcode - %d\n", __func__,
-			audio->ac->session, opcode);
-
-	spin_lock_irqsave(&audio->dsp_lock, flags);
-	switch (opcode) {
-	case ASM_DATA_EVENT_READ_DONE:
-		audio_in_get_dsp_frames(audio, token, payload);
-		break;
-	case ASM_DATA_EVENT_WRITE_DONE:
-		atomic_inc(&audio->in_count);
-		wake_up(&audio->write_wait);
-		break;
-	case ASM_DATA_CMDRSP_EOS:
-		audio->eos_rsp = 1;
-		wake_up(&audio->read_wait);
-		break;
-	case ASM_STREAM_CMDRSP_GET_ENCDEC_PARAM:
-		break;
-	case ASM_STREAM_CMDRSP_GET_PP_PARAMS:
-		break;
-	case ASM_SESSION_EVENT_TX_OVERFLOW:
-		pr_err("%s:session id %d:ASM_SESSION_EVENT_TX_OVERFLOW\n",
-			__func__, audio->ac->session);
-		break;
-	default:
-		pr_err("%s:session id %d: Ignore opcode[0x%x]\n", __func__,
-			audio->ac->session, opcode);
-		break;
-	}
-	spin_unlock_irqrestore(&audio->dsp_lock, flags);
-}
 /* ------------------- device --------------------- */
 static long qcelp_in_ioctl(struct file *file,
 				unsigned int cmd, unsigned long arg)
@@ -103,8 +64,8 @@
 			enc_cfg->max_bit_rate, 0, 0);
 
 		if (rc < 0) {
-			pr_err("%s:session id %d: cmd qcelp media format block\
-				failed\n", __func__, audio->ac->session);
+			pr_err("%s:session id %d: cmd qcelp media format block"
+				"failed\n", __func__, audio->ac->session);
 			break;
 		}
 		if (audio->feedback == NON_TUNNEL_MODE) {
@@ -113,8 +74,8 @@
 				audio->pcm_cfg.channel_count);
 
 			if (rc < 0) {
-				pr_err("%s:session id %d: media format block\
-				failed\n", __func__, audio->ac->session);
+				pr_err("%s:session id %d: media format block"
+				"failed\n", __func__, audio->ac->session);
 				break;
 			}
 		}
@@ -125,8 +86,8 @@
 			audio->enabled = 1;
 		} else {
 			audio->enabled = 0;
-			pr_err("%s:session id %d: Audio Start procedure failed\
-				rc=%d\n", __func__, audio->ac->session, rc);
+			pr_err("%s:session id %d: Audio Start procedure failed"
+				"rc=%d\n", __func__, audio->ac->session, rc);
 			break;
 		}
 		while (cnt++ < audio->str_cfg.buffer_count)
@@ -141,8 +102,8 @@
 				audio->ac->session);
 		rc = audio_in_disable(audio);
 		if (rc  < 0) {
-			pr_err("%s:session id %d: Audio Stop procedure failed\
-					rc=%d\n", __func__, audio->ac->session,
+			pr_err("%s:session id %d: Audio Stop procedure failed"
+					"rc=%d\n", __func__, audio->ac->session,
 					rc);
 			break;
 		}
@@ -180,8 +141,8 @@
 		}
 		enc_cfg->min_bit_rate = cfg.min_bit_rate;
 		enc_cfg->max_bit_rate = cfg.max_bit_rate;
-		pr_debug("%s:session id %d: min_bit_rate= 0x%x\
-			max_bit_rate=0x%x\n", __func__,
+		pr_debug("%s:session id %d: min_bit_rate= 0x%x"
+			"max_bit_rate=0x%x\n", __func__,
 			audio->ac->session, enc_cfg->min_bit_rate,
 			enc_cfg->max_bit_rate);
 		break;
@@ -201,16 +162,16 @@
 	audio = kzalloc(sizeof(struct q6audio_in), GFP_KERNEL);
 
 	if (audio == NULL) {
-		pr_err("%s: Could not allocate memory for qcelp\
-				driver\n", __func__);
+		pr_err("%s: Could not allocate memory for qcelp"
+				"driver\n", __func__);
 		return -ENOMEM;
 	}
 	/* Allocate memory for encoder config param */
 	audio->enc_cfg = kzalloc(sizeof(struct msm_audio_qcelp_enc_config),
 				GFP_KERNEL);
 	if (audio->enc_cfg == NULL) {
-		pr_err("%s:session id %d: Could not allocate memory for aac\
-				config param\n", __func__, audio->ac->session);
+		pr_err("%s:session id %d: Could not allocate memory for aac"
+				"config param\n", __func__, audio->ac->session);
 		kfree(audio);
 		return -ENOMEM;
 	}
@@ -239,12 +200,12 @@
 	audio->buf_cfg.meta_info_enable = 0x01;
 	audio->buf_cfg.frames_per_buf = 0x01;
 
-	audio->ac = q6asm_audio_client_alloc((app_cb)q6asm_qcelp_in_cb,
+	audio->ac = q6asm_audio_client_alloc((app_cb)q6asm_in_cb,
 				(void *)audio);
 
 	if (!audio->ac) {
-		pr_err("%s: Could not allocate memory for audio\
-				client\n", __func__);
+		pr_err("%s: Could not allocate memory for audio"
+				"client\n", __func__);
 		kfree(audio->enc_cfg);
 		kfree(audio);
 		return -ENOMEM;
@@ -277,8 +238,8 @@
 		/* register for tx overflow (valid for tunnel mode only) */
 		rc = q6asm_reg_tx_overflow(audio->ac, 0x01);
 		if (rc < 0) {
-			pr_err("%s:session id %d: TX Overflow registration\
-			failed rc=%d\n", __func__, audio->ac->session, rc);
+			pr_err("%s:session id %d: TX Overflow registration"
+			"failed rc=%d\n", __func__, audio->ac->session, rc);
 			rc = -ENODEV;
 			goto fail;
 		}
diff --git a/arch/arm/mach-msm/qdsp6v2/snddev_ecodec.c b/arch/arm/mach-msm/qdsp6v2/snddev_ecodec.c
index f75af16..0b38ec2 100644
--- a/arch/arm/mach-msm/qdsp6v2/snddev_ecodec.c
+++ b/arch/arm/mach-msm/qdsp6v2/snddev_ecodec.c
@@ -220,7 +220,7 @@
 		goto err_clk;
 	}
 
-	clk_enable(drv->ecodec_clk);
+	clk_prepare_enable(drv->ecodec_clk);
 
 	clk_reset(drv->ecodec_clk, CLK_RESET_DEASSERT);
 
@@ -260,7 +260,7 @@
 
 		pr_info("%s: closing all devices\n", __func__);
 
-		clk_disable(drv->ecodec_clk);
+		clk_disable_unprepare(drv->ecodec_clk);
 		aux_pcm_gpios_free();
 
 		afe_close(PCM_RX);
diff --git a/arch/arm/mach-msm/qdsp6v2/snddev_icodec.c b/arch/arm/mach-msm/qdsp6v2/snddev_icodec.c
index ea935cc..8a92c85 100644
--- a/arch/arm/mach-msm/qdsp6v2/snddev_icodec.c
+++ b/arch/arm/mach-msm/qdsp6v2/snddev_icodec.c
@@ -319,7 +319,7 @@
 		goto error_invalid_freq;
 	}
 
-	clk_enable(drv->rx_osrclk);
+	clk_prepare_enable(drv->rx_osrclk);
 	drv->rx_bitclk = clk_get_sys(NULL, "i2s_spkr_bit_clk");
 	if (IS_ERR(drv->rx_bitclk))
 		pr_err("%s clock Error\n", __func__);
@@ -339,7 +339,7 @@
 		pr_err("ERROR setting m clock1\n");
 		goto error_adie;
 	}
-	clk_enable(drv->rx_bitclk);
+	clk_prepare_enable(drv->rx_bitclk);
 
 	if (icodec->data->voltage_on)
 		icodec->data->voltage_on();
@@ -406,7 +406,7 @@
 
 error_pamp:
 error_adie:
-	clk_disable(drv->rx_osrclk);
+	clk_disable_unprepare(drv->rx_osrclk);
 error_invalid_freq:
 
 	pr_err("%s: encounter error\n", __func__);
@@ -448,7 +448,7 @@
 		goto error_invalid_freq;
 	}
 
-	clk_enable(drv->tx_osrclk);
+	clk_prepare_enable(drv->tx_osrclk);
 	drv->tx_bitclk = clk_get_sys(NULL, "i2s_mic_bit_clk");
 	if (IS_ERR(drv->tx_bitclk))
 		pr_err("%s clock Error\n", __func__);
@@ -464,7 +464,7 @@
 	} else
 		trc =  clk_set_rate(drv->tx_bitclk, 8);
 
-	clk_enable(drv->tx_bitclk);
+	clk_prepare_enable(drv->tx_bitclk);
 
 	/* Enable ADIE */
 	trc = adie_codec_open(icodec->data->profile, &icodec->adie_path);
@@ -572,8 +572,8 @@
 	if (icodec->data->voltage_off)
 		icodec->data->voltage_off();
 
-	clk_disable(drv->rx_bitclk);
-	clk_disable(drv->rx_osrclk);
+	clk_disable_unprepare(drv->rx_bitclk);
+	clk_disable_unprepare(drv->rx_osrclk);
 
 	msm_snddev_rx_mclk_free();
 
@@ -602,8 +602,8 @@
 
 	afe_close(icodec->data->copp_id);
 
-	clk_disable(drv->tx_bitclk);
-	clk_disable(drv->tx_osrclk);
+	clk_disable_unprepare(drv->tx_bitclk);
+	clk_disable_unprepare(drv->tx_osrclk);
 
 	msm_snddev_tx_mclk_free();
 
diff --git a/arch/arm/mach-msm/qdsp6v2/snddev_mi2s.c b/arch/arm/mach-msm/qdsp6v2/snddev_mi2s.c
index 75a7411..4cf18b3 100644
--- a/arch/arm/mach-msm/qdsp6v2/snddev_mi2s.c
+++ b/arch/arm/mach-msm/qdsp6v2/snddev_mi2s.c
@@ -194,7 +194,7 @@
 		pr_err("ERROR setting osr clock\n");
 		return -ENODEV;
 	}
-	clk_enable(drv->tx_osrclk);
+	clk_prepare_enable(drv->tx_osrclk);
 
 	/* set up bit clk */
 	drv->tx_bitclk = clk_get_sys(NULL, "mi2s_bit_clk");
@@ -204,10 +204,10 @@
 	rc =  clk_set_rate(drv->tx_bitclk, 8);
 	if (IS_ERR_VALUE(rc)) {
 		pr_err("ERROR setting bit clock\n");
-		clk_disable(drv->tx_osrclk);
+		clk_disable_unprepare(drv->tx_osrclk);
 		return -ENODEV;
 	}
-	clk_enable(drv->tx_bitclk);
+	clk_prepare_enable(drv->tx_bitclk);
 
 	afe_config.mi2s.bitwidth = 16;
 
@@ -336,8 +336,8 @@
 
 error_invalid_data:
 
-	clk_disable(drv->tx_bitclk);
-	clk_disable(drv->tx_osrclk);
+	clk_disable_unprepare(drv->tx_bitclk);
+	clk_disable_unprepare(drv->tx_osrclk);
 	return -EINVAL;
 }
 
@@ -358,8 +358,8 @@
 		return -EIO;
 	}
 	afe_close(snddev_mi2s_data->copp_id);
-	clk_disable(mi2s_drv->tx_bitclk);
-	clk_disable(mi2s_drv->tx_osrclk);
+	clk_disable_unprepare(mi2s_drv->tx_bitclk);
+	clk_disable_unprepare(mi2s_drv->tx_osrclk);
 
 	mi2s_gpios_free();
 
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
index 614339b..a8773ea 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
@@ -27,7 +27,8 @@
 #include "usfcdev.h"
 
 /* The driver version*/
-#define DRV_VERSION "1.3.1"
+#define DRV_VERSION "1.4.0"
+#define USF_VERSION_ID 0x0140
 
 /* Standard timeout in the asynchronous ops */
 #define USF_TIMEOUT_JIFFIES (1*HZ) /* 1 sec */
@@ -108,8 +109,8 @@
 	uint16_t dev_ind;
 	/* Event types, supported by device */
 	uint16_t event_types;
-	/*  The device is "input" module registered client */
-	struct input_dev *input_if;
+	/*  The input devices are "input" module registered clients */
+	struct input_dev *input_ifs[USF_MAX_EVENT_IND];
 	/*  The event source */
 	int event_src;
 	/* Bitmap of types of events, conflicting to USF's ones */
@@ -118,6 +119,23 @@
 	uint16_t conflicting_event_filters;
 };
 
+struct usf_input_dev_type {
+	/* Input event type, supported by the input device */
+	uint16_t event_type;
+	/* Input device name */
+	const char *input_dev_name;
+	/* Input device registration function */
+	int (*prepare_dev)(uint16_t, struct usf_type *,
+			    struct us_input_info_type *,
+			   const char *);
+	/* Input event notification function */
+	void (*notify_event)(struct usf_type *,
+			     uint16_t,
+			     struct usf_event_type *
+			     );
+};
+
+
 /* The MAX number of the supported devices */
 #define MAX_DEVS_NUMBER	1
 
@@ -131,9 +149,197 @@
 /* The opened devices container */
 static int s_opened_devs[MAX_DEVS_NUMBER];
 
-#define USF_NAME_PREFIX "USF_"
+#define USF_NAME_PREFIX "usf_"
 #define USF_NAME_PREFIX_SIZE 4
 
+
+static struct input_dev *allocate_dev(uint16_t ind, const char *name)
+{
+	struct input_dev *in_dev = input_allocate_device();
+
+	if (in_dev == NULL) {
+		pr_err("%s: input_allocate_device() failed\n", __func__);
+	} else {
+		/* Common part configuration */
+		in_dev->name = name;
+		in_dev->phys = NULL;
+		in_dev->id.bustype = BUS_HOST;
+		in_dev->id.vendor  = 0x0001;
+		in_dev->id.product = 0x0001;
+		in_dev->id.version = USF_VERSION_ID;
+	}
+	return in_dev;
+}
+
+static int prepare_tsc_input_device(uint16_t ind,
+				struct usf_type *usf_info,
+				struct us_input_info_type *input_info,
+				const char *name)
+{
+	struct input_dev *in_dev = allocate_dev(ind, name);
+
+	if (in_dev == NULL)
+		return -ENOMEM;
+
+	usf_info->input_ifs[ind] = in_dev;
+	in_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+	in_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+	input_set_abs_params(in_dev, ABS_X,
+			     input_info->tsc_x_dim[MIN_IND],
+			     input_info->tsc_x_dim[MAX_IND],
+			     0, 0);
+	input_set_abs_params(in_dev, ABS_Y,
+			     input_info->tsc_y_dim[MIN_IND],
+			     input_info->tsc_y_dim[MAX_IND],
+			     0, 0);
+	input_set_abs_params(in_dev, ABS_DISTANCE,
+			     input_info->tsc_z_dim[MIN_IND],
+			     input_info->tsc_z_dim[MAX_IND],
+			     0, 0);
+
+	input_set_abs_params(in_dev, ABS_PRESSURE,
+			     input_info->tsc_pressure[MIN_IND],
+			     input_info->tsc_pressure[MAX_IND],
+			     0, 0);
+
+	input_set_abs_params(in_dev, ABS_TILT_X,
+			     input_info->tsc_x_tilt[MIN_IND],
+			     input_info->tsc_x_tilt[MAX_IND],
+			     0, 0);
+	input_set_abs_params(in_dev, ABS_TILT_Y,
+			     input_info->tsc_y_tilt[MIN_IND],
+			     input_info->tsc_y_tilt[MAX_IND],
+			     0, 0);
+
+	return 0;
+}
+
+static int prepare_mouse_input_device(uint16_t ind, struct usf_type *usf_info,
+			struct us_input_info_type *input_info,
+			const char *name)
+{
+	struct input_dev *in_dev = allocate_dev(ind, name);
+
+	if (in_dev == NULL)
+		return -ENOMEM;
+
+	usf_info->input_ifs[ind] = in_dev;
+	in_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
+
+	in_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
+						BIT_MASK(BTN_RIGHT) |
+						BIT_MASK(BTN_MIDDLE);
+	in_dev->relbit[0] =  BIT_MASK(REL_X) |
+				BIT_MASK(REL_Y) |
+				BIT_MASK(REL_Z);
+
+	return 0;
+}
+
+static int prepare_keyboard_input_device(
+					uint16_t ind,
+					struct usf_type *usf_info,
+					struct us_input_info_type *input_info,
+					const char *name)
+{
+	struct input_dev *in_dev = allocate_dev(ind, name);
+
+	if (in_dev == NULL)
+		return -ENOMEM;
+
+	usf_info->input_ifs[ind] = in_dev;
+	in_dev->evbit[0] |= BIT_MASK(EV_KEY);
+	/* All keys are permitted */
+	memset(in_dev->keybit, 0xff, sizeof(in_dev->keybit));
+
+	return 0;
+}
+
+static void notify_tsc_event(struct usf_type *usf_info,
+			     uint16_t if_ind,
+			     struct usf_event_type *event)
+
+{
+	struct input_dev *input_if = usf_info->input_ifs[if_ind];
+	struct point_event_type *pe = &(event->event_data.point_event);
+
+	input_report_abs(input_if, ABS_X, pe->coordinates[X_IND]);
+	input_report_abs(input_if, ABS_Y, pe->coordinates[Y_IND]);
+	input_report_abs(input_if, ABS_DISTANCE, pe->coordinates[Z_IND]);
+
+	input_report_abs(input_if, ABS_TILT_X, pe->inclinations[X_IND]);
+	input_report_abs(input_if, ABS_TILT_Y, pe->inclinations[Y_IND]);
+
+	input_report_abs(input_if, ABS_PRESSURE, pe->pressure);
+	input_report_key(input_if, BTN_TOUCH, !!(pe->pressure));
+
+	if (usf_info->event_src)
+		input_report_key(input_if, usf_info->event_src, 1);
+
+	input_sync(input_if);
+
+	pr_debug("%s: TSC event: xyz[%d;%d;%d], incl[%d;%d], pressure[%d]\n",
+		 __func__,
+		 pe->coordinates[X_IND],
+		 pe->coordinates[Y_IND],
+		 pe->coordinates[Z_IND],
+		 pe->inclinations[X_IND],
+		 pe->inclinations[Y_IND],
+		 pe->pressure);
+}
+
+static void notify_mouse_event(struct usf_type *usf_info,
+			       uint16_t if_ind,
+			       struct usf_event_type *event)
+{
+	struct input_dev *input_if = usf_info->input_ifs[if_ind];
+	struct mouse_event_type *me = &(event->event_data.mouse_event);
+
+	input_report_rel(input_if, REL_X, me->rels[X_IND]);
+	input_report_rel(input_if, REL_Y, me->rels[Y_IND]);
+	input_report_rel(input_if, REL_Z, me->rels[Z_IND]);
+
+	input_report_key(input_if, BTN_LEFT,
+			 me->buttons_states & USF_BUTTON_LEFT_MASK);
+	input_report_key(input_if, BTN_MIDDLE,
+			 me->buttons_states & USF_BUTTON_MIDDLE_MASK);
+	input_report_key(input_if, BTN_RIGHT,
+			 me->buttons_states & USF_BUTTON_RIGHT_MASK);
+
+	input_sync(input_if);
+
+	pr_debug("%s: mouse event: dx[%d], dy[%d], buttons_states[%d]\n",
+		 __func__, me->rels[X_IND],
+		 me->rels[Y_IND], me->buttons_states);
+}
+
+static void notify_key_event(struct usf_type *usf_info,
+			     uint16_t if_ind,
+			     struct usf_event_type *event)
+{
+	struct input_dev *input_if = usf_info->input_ifs[if_ind];
+	struct key_event_type *ke = &(event->event_data.key_event);
+
+	input_report_key(input_if, ke->key, ke->key_state);
+	input_sync(input_if);
+	pr_debug("%s: key event: key[%d], state[%d]\n",
+		 __func__,
+		 ke->key,
+		 ke->key_state);
+
+}
+
+static struct usf_input_dev_type s_usf_input_devs[] = {
+	{USF_TSC_EVENT, "usf_tsc",
+		prepare_tsc_input_device, notify_tsc_event},
+	{USF_TSC_PTR_EVENT, "usf_tsc_ptr",
+		prepare_tsc_input_device, notify_tsc_event},
+	{USF_MOUSE_EVENT, "usf_mouse",
+		prepare_mouse_input_device, notify_mouse_event},
+	{USF_KEYBOARD_EVENT, "usf_kb",
+		prepare_keyboard_input_device, notify_key_event},
+};
+
 static void usf_rx_cb(uint32_t opcode, uint32_t token,
 		      uint32_t *payload, void *priv)
 {
@@ -386,8 +592,8 @@
 				 struct us_input_info_type *input_info)
 {
 	int rc = 0;
-	struct input_dev *input_dev = NULL;
 	bool ret = true;
+	uint16_t ind = 0;
 
 	if ((usf_info == NULL) ||
 	    (input_info == NULL) ||
@@ -396,194 +602,75 @@
 		return -EINVAL;
 	}
 
-	if (usf_info->input_if != NULL) {
-		pr_err("%s: input_if is already allocated\n", __func__);
-		return -EFAULT;
-	}
-
-	input_dev = input_allocate_device();
-	if (input_dev == NULL) {
-		pr_err("%s: input_allocate_device() failed\n", __func__);
-		return -ENOMEM;
-	}
-
-	/* Common part configuration */
-	input_dev->name = (const char *)(usf_info->usf_tx.client_name);
-	input_dev->phys = NULL;
-	input_dev->id.bustype = BUS_HOST;
-	input_dev->id.vendor  = 0x0001;
-	input_dev->id.product = 0x0001;
-	input_dev->id.version = 0x0001;
-
-	if (input_info->event_types & USF_TSC_EVENT) {
-		/* TSC part configuration */
-		input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
-		input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
-		input_set_abs_params(input_dev, ABS_X,
-				     input_info->tsc_x_dim[MIN_IND],
-				     input_info->tsc_x_dim[MAX_IND],
-				     0, 0);
-		input_set_abs_params(input_dev, ABS_Y,
-				     input_info->tsc_y_dim[MIN_IND],
-				     input_info->tsc_y_dim[MAX_IND],
-				     0, 0);
-		input_set_abs_params(input_dev, ABS_DISTANCE,
-				     input_info->tsc_z_dim[MIN_IND],
-				     input_info->tsc_z_dim[MAX_IND],
-				     0, 0);
-
-		input_set_abs_params(input_dev, ABS_PRESSURE,
-				     input_info->tsc_pressure[MIN_IND],
-				     input_info->tsc_pressure[MAX_IND], 0, 0);
-
-		input_set_abs_params(input_dev, ABS_TILT_X,
-				     input_info->tsc_x_tilt[MIN_IND],
-				     input_info->tsc_x_tilt[MAX_IND],
-				     0, 0);
-		input_set_abs_params(input_dev, ABS_TILT_Y,
-				     input_info->tsc_y_tilt[MIN_IND],
-				     input_info->tsc_y_tilt[MAX_IND],
-				     0, 0);
-	}
-
-	if (input_info->event_types & USF_MOUSE_EVENT) {
-		/* Mouse part configuration */
-		input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
-
-		input_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
-							BIT_MASK(BTN_RIGHT) |
-							BIT_MASK(BTN_MIDDLE);
-		input_dev->relbit[0] =  BIT_MASK(REL_X) |
-					BIT_MASK(REL_Y) |
-					BIT_MASK(REL_Z);
-	}
-
-	if (input_info->event_types & USF_KEYBOARD_EVENT) {
-		/* Keyboard part configuration */
-		input_dev->evbit[0] |= BIT_MASK(EV_KEY);
-
-		/* All keys are permitted */
-		memset(input_dev->keybit, 0xff, sizeof(input_dev->keybit));
-	}
-
 	if (input_info->event_src < ARRAY_SIZE(s_event_src_map))
-		usf_info->event_src = s_event_src_map[input_info->event_src];
+		usf_info->event_src =
+			s_event_src_map[input_info->event_src];
 	else
 		usf_info->event_src = 0;
 
-	if (usf_info->event_src)
-		input_set_capability(input_dev, EV_KEY, usf_info->event_src);
+	for (ind = 0; ind < USF_MAX_EVENT_IND; ++ind) {
+		if (usf_info->input_ifs[ind] != NULL) {
+			pr_err("%s: input_if[%d] is already allocated\n",
+				__func__, ind);
+			return -EFAULT;
+		}
+		if ((input_info->event_types &
+			s_usf_input_devs[ind].event_type) &&
+		     s_usf_input_devs[ind].prepare_dev) {
+			rc = (*s_usf_input_devs[ind].prepare_dev)(
+				ind,
+				usf_info,
+				input_info,
+				s_usf_input_devs[ind].input_dev_name);
+			if (rc)
+				return rc;
 
-	rc = input_register_device(input_dev);
-	if (rc) {
-		pr_err("%s: input_register_device() failed; rc=%d\n",
-		       __func__, rc);
-		input_free_device(input_dev);
-	} else {
-		usf_info->input_if = input_dev;
-		usf_info->event_types = input_info->event_types;
-		pr_debug("%s: input device[%s] was registered\n",
-			__func__, input_dev->name);
-		ret = usf_register_conflicting_events(
-					input_info->conflicting_event_types);
-		if (ret)
-			usf_info->conflicting_event_types =
-				input_info->conflicting_event_types;
-	}
 
-	return rc;
+			if (usf_info->event_src)
+				input_set_capability(usf_info->input_ifs[ind],
+						     EV_KEY,
+						     usf_info->event_src);
+
+			rc = input_register_device(usf_info->input_ifs[ind]);
+			if (rc) {
+				pr_err("%s: input_reg_dev() failed; rc=%d\n",
+					__func__, rc);
+				input_free_device(usf_info->input_ifs[ind]);
+				usf_info->input_ifs[ind] = NULL;
+			} else {
+				usf_info->event_types |=
+					s_usf_input_devs[ind].event_type;
+				pr_debug("%s: input device[%s] was registered\n",
+					__func__,
+					s_usf_input_devs[ind].input_dev_name);
+			}
+		} /* supported event */
+	} /* event types loop */
+
+	ret = usf_register_conflicting_events(
+			input_info->conflicting_event_types);
+	if (ret)
+		usf_info->conflicting_event_types =
+			input_info->conflicting_event_types;
+
+	return 0;
 }
 
-static void notify_tsc_event(struct usf_type *usf_info,
-			     struct point_event_type *pe)
-{
-	struct input_dev *input_if = usf_info->input_if;
-
-	input_report_abs(input_if, ABS_X, pe->coordinates[X_IND]);
-	input_report_abs(input_if, ABS_Y, pe->coordinates[Y_IND]);
-	input_report_abs(input_if, ABS_DISTANCE, pe->coordinates[Z_IND]);
-
-	input_report_abs(input_if, ABS_TILT_X, pe->inclinations[X_IND]);
-	input_report_abs(input_if, ABS_TILT_Y, pe->inclinations[Y_IND]);
-
-	input_report_abs(input_if, ABS_PRESSURE, pe->pressure);
-	input_report_key(input_if, BTN_TOUCH, !!(pe->pressure));
-
-	if (usf_info->event_src)
-		input_report_key(input_if, usf_info->event_src, 1);
-
-	input_sync(input_if);
-
-	pr_debug("%s: TSC event: xyz[%d;%d;%d], incl[%d;%d], pressure[%d]\n",
-		 __func__,
-		 pe->coordinates[X_IND],
-		 pe->coordinates[Y_IND],
-		 pe->coordinates[Z_IND],
-		 pe->inclinations[X_IND],
-		 pe->inclinations[Y_IND],
-		 pe->pressure);
-}
-
-static void notify_mouse_event(struct input_dev *input_if,
-			       struct mouse_event_type *me)
-{
-	if (me == NULL) {
-		pr_err("%s: mouse event is NULL\n", __func__);
-		return;
-	}
-
-	input_report_rel(input_if, REL_X, me->rels[X_IND]);
-	input_report_rel(input_if, REL_Y, me->rels[Y_IND]);
-	input_report_rel(input_if, REL_Z, me->rels[Z_IND]);
-
-	input_report_key(input_if, BTN_LEFT,
-			 me->buttons_states & USF_BUTTON_LEFT_MASK);
-	input_report_key(input_if, BTN_MIDDLE,
-			 me->buttons_states & USF_BUTTON_MIDDLE_MASK);
-	input_report_key(input_if, BTN_RIGHT,
-			 me->buttons_states & USF_BUTTON_RIGHT_MASK);
-
-	input_sync(input_if);
-
-	pr_debug("%s: mouse event: dx[%d], dy[%d], buttons_states[%d]\n",
-		 __func__, me->rels[X_IND],
-		 me->rels[Y_IND], me->buttons_states);
-}
-
-static void notify_key_event(struct input_dev *input_if,
-			       struct key_event_type *ke)
-{
-	if (ke == NULL) {
-		pr_err("%s: key event is NULL\n", __func__);
-		return;
-	}
-
-	input_report_key(input_if, ke->key, ke->key_state);
-	input_sync(input_if);
-	pr_debug("%s: key event: key[%d], state[%d]\n",
-		 __func__,
-		 ke->key,
-		 ke->key_state);
-
-}
 
 static void handle_input_event(struct usf_type *usf_info,
 			       uint16_t event_counter,
 			       struct usf_event_type *event)
 {
-	struct input_dev *input_if = NULL;
 	uint16_t ind = 0;
 	uint16_t events_num = 0;
 	struct usf_event_type usf_events[USF_EVENTS_PORTION_SIZE];
 	int rc = 0;
 
-	if ((usf_info == NULL) || (usf_info->input_if == NULL) ||
+	if ((usf_info == NULL) ||
 	    (event == NULL) || (!event_counter)) {
 		return;
 	}
 
-	input_if = usf_info->input_if;
-
 	while (event_counter > 0) {
 		if (event_counter > USF_EVENTS_PORTION_SIZE) {
 			events_num = USF_EVENTS_PORTION_SIZE;
@@ -602,26 +689,17 @@
 		}
 		for (ind = 0; ind < events_num; ++ind) {
 			struct usf_event_type *p_event = &usf_events[ind];
-			if (p_event->event_type & USF_TSC_EVENT) {
-				struct point_event_type *pe =
-					&(p_event->event_data.point_event);
-				if (pe->coordinates_type ==
-					USF_PIX_COORDINATE)
-					notify_tsc_event(usf_info, pe);
-				else
-					pr_debug("%s: wrong coord type: %d",
-						__func__,
-						pe->coordinates_type);
-				continue;
-			}
-			if (p_event->event_type & USF_MOUSE_EVENT) {
-				notify_mouse_event(input_if,
-					&(p_event->event_data.mouse_event));
-				continue;
-			}
-			if (p_event->event_type & USF_KEYBOARD_EVENT)
-				notify_key_event(input_if,
-					&(p_event->event_data.key_event));
+			uint16_t if_ind = p_event->event_type_ind;
+
+			if ((if_ind >= USF_MAX_EVENT_IND) ||
+			    (usf_info->input_ifs[if_ind] == NULL))
+				continue; /* event isn't supported */
+
+			if (s_usf_input_devs[if_ind].notify_event)
+				(*s_usf_input_devs[if_ind].notify_event)(
+								usf_info,
+								if_ind,
+								p_event);
 		} /* loop in the portion */
 	} /* all events loop */
 }
@@ -1051,13 +1129,20 @@
 
 static void usf_release_input(struct usf_type *usf)
 {
-	if (usf->input_if != NULL) {
+	uint16_t ind = 0;
+
+	for (ind = 0; ind < USF_MAX_EVENT_IND; ++ind) {
+		if (usf->input_ifs[ind] == NULL)
+			continue;
+
 		usf_unregister_conflicting_events(
 						usf->conflicting_event_types);
 		usf->conflicting_event_types = 0;
-		input_unregister_device(usf->input_if);
-		usf->input_if = NULL;
-		pr_debug("%s input_unregister_device\n",  __func__);
+		input_unregister_device(usf->input_ifs[ind]);
+		usf->input_ifs[ind] = NULL;
+		pr_debug("%s input_unregister_device[%s]\n",
+			 __func__,
+			 s_usf_input_devs[ind].input_dev_name);
 	}
 } /* usf_release_input */
 
diff --git a/arch/arm/mach-msm/rpc_pmapp.c b/arch/arm/mach-msm/rpc_pmapp.c
index 811e63c..1d18553 100644
--- a/arch/arm/mach-msm/rpc_pmapp.c
+++ b/arch/arm/mach-msm/rpc_pmapp.c
@@ -548,7 +548,7 @@
 
 int pmapp_disp_backlight_set_brightness(int value)
 {
-	if (value < 0 || value > 100)
+	if (value < 0 || value > 255)
 		return -EINVAL;
 
 	return pmapp_rpc_set_only(value, 0, 0, 0, 1,
diff --git a/arch/arm/mach-msm/rpm-notifier.h b/arch/arm/mach-msm/rpm-notifier.h
new file mode 100644
index 0000000..df8d9b3
--- /dev/null
+++ b/arch/arm/mach-msm/rpm-notifier.h
@@ -0,0 +1,27 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __ARCH_ARM_MACH_MSM_RPM_NOTIF_H
+#define __ARCH_ARM_MACH_MSM_RPM_NOTIF_H
+
+struct msm_rpm_notifier_data {
+	uint32_t rsc_type;
+	uint32_t rsc_id;
+	uint32_t key;
+	uint32_t size;
+	uint8_t *value;
+};
+
+int msm_rpm_register_notifier(struct notifier_block *nb);
+int msm_rpm_unregister_notifier(struct notifier_block *nb);
+
+#endif /*__ARCH_ARM_MACH_MSM_RPM_NOTIF_H */
diff --git a/arch/arm/mach-msm/rpm-regulator-smd.c b/arch/arm/mach-msm/rpm-regulator-smd.c
new file mode 100644
index 0000000..b892d05
--- /dev/null
+++ b/arch/arm/mach-msm/rpm-regulator-smd.c
@@ -0,0 +1,1430 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <mach/rpm-smd.h>
+#include <mach/rpm-regulator-smd.h>
+#include <mach/socinfo.h>
+
+/* Debug Definitions */
+
+enum {
+	RPM_VREG_DEBUG_REQUEST		= BIT(0),
+	RPM_VREG_DEBUG_FULL_REQUEST	= BIT(1),
+	RPM_VREG_DEBUG_DUPLICATE	= BIT(2),
+};
+
+static int rpm_vreg_debug_mask;
+module_param_named(
+	debug_mask, rpm_vreg_debug_mask, int, S_IRUSR | S_IWUSR
+);
+
+#define vreg_err(req, fmt, ...) \
+	pr_err("%s: " fmt, req->rdesc.name, ##__VA_ARGS__)
+
+/* RPM regulator request types */
+enum rpm_regulator_smd_type {
+	RPM_REGULATOR_SMD_TYPE_LDO,
+	RPM_REGULATOR_SMD_TYPE_SMPS,
+	RPM_REGULATOR_SMD_TYPE_VS,
+	RPM_REGULATOR_SMD_TYPE_NCP,
+	RPM_REGULATOR_SMD_TYPE_MAX,
+};
+
+/* RPM resource parameters */
+enum rpm_regulator_param_index {
+	RPM_REGULATOR_PARAM_ENABLE,
+	RPM_REGULATOR_PARAM_VOLTAGE,
+	RPM_REGULATOR_PARAM_CURRENT,
+	RPM_REGULATOR_PARAM_MODE_LDO,
+	RPM_REGULATOR_PARAM_MODE_SMPS,
+	RPM_REGULATOR_PARAM_PIN_CTRL_ENABLE,
+	RPM_REGULATOR_PARAM_PIN_CTRL_MODE,
+	RPM_REGULATOR_PARAM_FREQUENCY,
+	RPM_REGULATOR_PARAM_HEAD_ROOM,
+	RPM_REGULATOR_PARAM_QUIET_MODE,
+	RPM_REGULATOR_PARAM_FREQ_REASON,
+	RPM_REGULATOR_PARAM_MAX,
+};
+
+#define RPM_SET_CONFIG_ACTIVE			BIT(0)
+#define RPM_SET_CONFIG_SLEEP			BIT(1)
+#define RPM_SET_CONFIG_BOTH			(RPM_SET_CONFIG_ACTIVE \
+						 | RPM_SET_CONFIG_SLEEP)
+struct rpm_regulator_param {
+	char	*name;
+	char	*property_name;
+	u32	key;
+	u32	min;
+	u32	max;
+	u32	supported_regulator_types;
+};
+
+#define PARAM(_idx, _support_ldo, _support_smps, _support_vs, _support_ncp, \
+		_name, _min, _max, _property_name)	\
+	[RPM_REGULATOR_PARAM_##_idx] = { \
+		.name = _name, \
+		.property_name = _property_name, \
+		.min = _min, \
+		.max = _max, \
+		.supported_regulator_types = \
+			_support_ldo << RPM_REGULATOR_SMD_TYPE_LDO | \
+			_support_smps << RPM_REGULATOR_SMD_TYPE_SMPS | \
+			_support_vs << RPM_REGULATOR_SMD_TYPE_VS | \
+			_support_ncp << RPM_REGULATOR_SMD_TYPE_NCP, \
+	}
+
+static struct rpm_regulator_param params[RPM_REGULATOR_PARAM_MAX] = {
+	/*    ID             LDO SMPS VS  NCP  name  min max          property-name */
+	PARAM(ENABLE,          1,  1,  1,  1, "swen", 0, 1,          "qcom,init-enable"),
+	PARAM(VOLTAGE,         1,  1,  0,  1, "uv",   0, 0x7FFFFFF,  "qcom,init-voltage"),
+	PARAM(CURRENT,         1,  1,  0,  0, "ma",   0, 0x1FFF,     "qcom,init-current"),
+	PARAM(MODE_LDO,        1,  0,  0,  0, "lsmd", 0, 1,          "qcom,init-ldo-mode"),
+	PARAM(MODE_SMPS,       0,  1,  0,  0, "ssmd", 0, 2,          "qcom,init-smps-mode"),
+	PARAM(PIN_CTRL_ENABLE, 1,  1,  1,  0, "pcen", 0, 0xF,        "qcom,init-pin-ctrl-enable"),
+	PARAM(PIN_CTRL_MODE,   1,  1,  1,  0, "pcmd", 0, 0x1F,       "qcom,init-pin-ctrl-mode"),
+	PARAM(FREQUENCY,       0,  1,  0,  1, "freq", 0, 16,         "qcom,init-frequency"),
+	PARAM(HEAD_ROOM,       1,  0,  0,  1, "hr",   0, 0x7FFFFFFF, "qcom,init-head-room"),
+	PARAM(QUIET_MODE,      0,  1,  0,  0, "qm",   0, 2,          "qcom,init-quiet-mode"),
+	PARAM(FREQ_REASON,     0,  1,  0,  1, "resn", 0, 8,          "qcom,init-freq-reason"),
+};
+
+struct rpm_vreg_request {
+	u32			param[RPM_REGULATOR_PARAM_MAX];
+	u32			valid;
+	u32			modified;
+};
+
+struct rpm_vreg {
+	struct rpm_vreg_request	aggr_req_active;
+	struct rpm_vreg_request	aggr_req_sleep;
+	struct list_head	reg_list;
+	const char		*resource_name;
+	u32			resource_id;
+	bool			allow_atomic;
+	int			regulator_type;
+	int			hpm_min_load;
+	int			enable_time;
+	struct spinlock		slock;
+	struct mutex		mlock;
+	unsigned long		flags;
+	bool			sleep_request_sent;
+	struct msm_rpm_request	*handle_active;
+	struct msm_rpm_request	*handle_sleep;
+};
+
+struct rpm_regulator {
+	struct regulator_desc	rdesc;
+	struct regulator_dev	*rdev;
+	struct rpm_vreg		*rpm_vreg;
+	struct list_head	list;
+	bool			set_active;
+	bool			set_sleep;
+	struct rpm_vreg_request	req;
+	int			system_load;
+	int			min_uV;
+	int			max_uV;
+};
+
+/*
+ * This voltage in uV is returned by get_voltage functions when there is no way
+ * to determine the current voltage level.  It is needed because the regulator
+ * framework treats a 0 uV voltage as an error.
+ */
+#define VOLTAGE_UNKNOWN 1
+
+/*
+ * Regulator requests sent in the active set take effect immediately.  Requests
+ * sent in the sleep set take effect when the Apps processor transitions into
+ * RPM assisted power collapse.  For any given regulator, if an active set
+ * request is present, but not a sleep set request, then the active set request
+ * is used at all times, even when the Apps processor is power collapsed.
+ *
+ * The rpm-regulator-smd takes advantage of this default usage of the active set
+ * request by only sending a sleep set request if it differs from the
+ * corresponding active set request.
+ */
+#define RPM_SET_ACTIVE	MSM_RPM_CTX_ACTIVE_SET
+#define RPM_SET_SLEEP	MSM_RPM_CTX_SLEEP_SET
+
+static u32 rpm_vreg_string_to_int(const u8 *str)
+{
+	int i, len;
+	u32 output = 0;
+
+	len = strnlen(str, sizeof(u32));
+	for (i = 0; i < len; i++)
+		output |= str[i] << (i * 8);
+
+	return output;
+}
+
+static inline void rpm_vreg_lock(struct rpm_vreg *rpm_vreg)
+{
+	if (rpm_vreg->allow_atomic)
+		spin_lock_irqsave(&rpm_vreg->slock, rpm_vreg->flags);
+	else
+		mutex_lock(&rpm_vreg->mlock);
+}
+
+static inline void rpm_vreg_unlock(struct rpm_vreg *rpm_vreg)
+{
+	if (rpm_vreg->allow_atomic)
+		spin_unlock_irqrestore(&rpm_vreg->slock, rpm_vreg->flags);
+	else
+		mutex_unlock(&rpm_vreg->mlock);
+}
+
+static inline bool rpm_vreg_active_or_sleep_enabled(struct rpm_vreg *rpm_vreg)
+{
+	return (rpm_vreg->aggr_req_active.param[RPM_REGULATOR_PARAM_ENABLE]
+			&& (rpm_vreg->aggr_req_active.valid
+				& BIT(RPM_REGULATOR_PARAM_ENABLE)))
+	    || ((rpm_vreg->aggr_req_sleep.param[RPM_REGULATOR_PARAM_ENABLE])
+				&& (rpm_vreg->aggr_req_sleep.valid
+					& BIT(RPM_REGULATOR_PARAM_ENABLE)));
+}
+
+/*
+ * This is used when voting for LPM or HPM by subtracting or adding to the
+ * hpm_min_load of a regulator.  It has units of uA.
+ */
+#define LOAD_THRESHOLD_STEP	1000
+
+static inline int rpm_vreg_hpm_min_uA(struct rpm_vreg *rpm_vreg)
+{
+	return rpm_vreg->hpm_min_load;
+}
+
+static inline int rpm_vreg_lpm_max_uA(struct rpm_vreg *rpm_vreg)
+{
+	return rpm_vreg->hpm_min_load - LOAD_THRESHOLD_STEP;
+}
+
+#define MICRO_TO_MILLI(uV)	((uV) / 1000)
+#define MILLI_TO_MICRO(uV)	((uV) * 1000)
+
+#define DEBUG_PRINT_BUFFER_SIZE 512
+#define REQ_SENT	0
+#define REQ_PREV	1
+#define REQ_CACHED	2
+#define REQ_TYPES	3
+
+static void rpm_regulator_req(struct rpm_regulator *regulator, int set,
+				bool sent)
+{
+	char buf[DEBUG_PRINT_BUFFER_SIZE];
+	size_t buflen = DEBUG_PRINT_BUFFER_SIZE;
+	struct rpm_vreg *rpm_vreg = regulator->rpm_vreg;
+	struct rpm_vreg_request *aggr;
+	bool first;
+	u32 mask[REQ_TYPES] = {0, 0, 0};
+	const char *req_names[REQ_TYPES] = {"sent", "prev", "cached"};
+	int pos = 0;
+	int i, j;
+
+	aggr = (set == RPM_SET_ACTIVE)
+		? &rpm_vreg->aggr_req_active : &rpm_vreg->aggr_req_sleep;
+
+	if (rpm_vreg_debug_mask & RPM_VREG_DEBUG_DUPLICATE) {
+		mask[REQ_SENT] = aggr->modified;
+		mask[REQ_PREV] = aggr->valid & ~aggr->modified;
+	} else if (sent
+		   && (rpm_vreg_debug_mask & RPM_VREG_DEBUG_FULL_REQUEST)) {
+		mask[REQ_SENT] = aggr->modified;
+		mask[REQ_PREV] = aggr->valid & ~aggr->modified;
+	} else if (sent && (rpm_vreg_debug_mask & RPM_VREG_DEBUG_REQUEST)) {
+		mask[REQ_SENT] = aggr->modified;
+	}
+
+	if (!(mask[REQ_SENT] | mask[REQ_PREV]))
+		return;
+
+	if (set == RPM_SET_SLEEP && !rpm_vreg->sleep_request_sent) {
+		mask[REQ_CACHED] = mask[REQ_SENT] | mask[REQ_PREV];
+		mask[REQ_SENT] = 0;
+		mask[REQ_PREV] = 0;
+	}
+
+	pos += scnprintf(buf + pos, buflen - pos, "%s%s: ",
+			KERN_INFO, __func__);
+
+	pos += scnprintf(buf + pos, buflen - pos, "%s %u (%s): s=%s",
+			rpm_vreg->resource_name, rpm_vreg->resource_id,
+			regulator->rdesc.name,
+			(set == RPM_SET_ACTIVE ? "act" : "slp"));
+
+	for (i = 0; i < REQ_TYPES; i++) {
+		if (mask[i])
+			pos += scnprintf(buf + pos, buflen - pos, "; %s: ",
+					req_names[i]);
+
+		first = true;
+		for (j = 0; j < RPM_REGULATOR_PARAM_MAX; j++) {
+			if (mask[i] & BIT(j)) {
+				pos += scnprintf(buf + pos, buflen - pos,
+					"%s%s=%u", (first ? "" : ", "),
+					params[j].name, aggr->param[j]);
+				first = false;
+			}
+		}
+	}
+
+	pos += scnprintf(buf + pos, buflen - pos, "\n");
+	printk(buf);
+}
+
+#define RPM_VREG_SET_PARAM(_regulator, _param, _val) \
+{ \
+	(_regulator)->req.param[RPM_REGULATOR_PARAM_##_param] = _val; \
+	(_regulator)->req.modified |= BIT(RPM_REGULATOR_PARAM_##_param); \
+} \
+
+static int rpm_vreg_add_kvp_to_request(struct rpm_vreg *rpm_vreg,
+				       const u32 *param, int idx, u32 set)
+{
+	struct msm_rpm_request *handle;
+
+	handle = (set == RPM_SET_ACTIVE	? rpm_vreg->handle_active
+					: rpm_vreg->handle_sleep);
+
+	if (rpm_vreg->allow_atomic)
+		return msm_rpm_add_kvp_data_noirq(handle, params[idx].key,
+						  (u8 *)&param[idx], 4);
+	else
+		return msm_rpm_add_kvp_data(handle, params[idx].key,
+					    (u8 *)&param[idx], 4);
+}
+
+static void rpm_vreg_check_modified_requests(const u32 *prev_param,
+		const u32 *param, u32 prev_valid, u32 *modified)
+{
+	u32 value_changed = 0;
+	int i;
+
+	for (i = 0; i < RPM_REGULATOR_PARAM_MAX; i++) {
+		if (param[i] != prev_param[i])
+			value_changed |= BIT(i);
+	}
+
+	/*
+	 * Only keep bits that are for changed parameters or previously
+	 * invalid parameters.
+	 */
+	*modified &= value_changed | ~prev_valid;
+}
+
+static int rpm_vreg_add_modified_requests(struct rpm_regulator *regulator,
+		u32 set, const u32 *param, u32 modified)
+{
+	struct rpm_vreg *rpm_vreg = regulator->rpm_vreg;
+	int rc = 0;
+	int i;
+
+	for (i = 0; i < RPM_REGULATOR_PARAM_MAX; i++) {
+		/* Only send requests for modified parameters. */
+		if (modified & BIT(i)) {
+			rc = rpm_vreg_add_kvp_to_request(rpm_vreg, param, i,
+							set);
+			if (rc) {
+				vreg_err(regulator,
+					"add KVP failed: %s %u; %s, rc=%d\n",
+					rpm_vreg->resource_name,
+					rpm_vreg->resource_id, params[i].name,
+					rc);
+				return rc;
+			}
+		}
+	}
+
+	return rc;
+}
+
+static int rpm_vreg_send_request(struct rpm_regulator *regulator, u32 set)
+{
+	struct rpm_vreg *rpm_vreg = regulator->rpm_vreg;
+	struct msm_rpm_request *handle
+		= (set == RPM_SET_ACTIVE ? rpm_vreg->handle_active
+					: rpm_vreg->handle_sleep);
+	int rc;
+
+	if (rpm_vreg->allow_atomic)
+		rc = msm_rpm_wait_for_ack_noirq(msm_rpm_send_request_noirq(
+						  handle));
+	else
+		rc = msm_rpm_wait_for_ack(msm_rpm_send_request(handle));
+
+	if (rc)
+		vreg_err(regulator, "msm rpm send failed: %s %u; set=%s, "
+			"rc=%d\n", rpm_vreg->resource_name,
+			rpm_vreg->resource_id,
+			(set == RPM_SET_ACTIVE ? "act" : "slp"), rc);
+
+	return rc;
+}
+
+#define RPM_VREG_AGGR_MAX(_idx, _param_aggr, _param_reg) \
+{ \
+	_param_aggr[RPM_REGULATOR_PARAM_##_idx] \
+	 = max(_param_aggr[RPM_REGULATOR_PARAM_##_idx], \
+		_param_reg[RPM_REGULATOR_PARAM_##_idx]); \
+}
+
+#define RPM_VREG_AGGR_SUM(_idx, _param_aggr, _param_reg) \
+{ \
+	_param_aggr[RPM_REGULATOR_PARAM_##_idx] \
+		 += _param_reg[RPM_REGULATOR_PARAM_##_idx]; \
+}
+
+#define RPM_VREG_AGGR_OR(_idx, _param_aggr, _param_reg) \
+{ \
+	_param_aggr[RPM_REGULATOR_PARAM_##_idx] \
+		|= _param_reg[RPM_REGULATOR_PARAM_##_idx]; \
+}
+
+/*
+ * The RPM treats freq=0 as a special value meaning that this consumer does not
+ * care what the SMPS switching freqency is.
+ */
+#define RPM_REGULATOR_FREQ_DONT_CARE 0
+
+static inline void rpm_vreg_freqency_aggr(u32 *freq, u32 consumer_freq)
+{
+	if (consumer_freq != RPM_REGULATOR_FREQ_DONT_CARE
+		&& (consumer_freq < *freq
+			|| *freq == RPM_REGULATOR_FREQ_DONT_CARE))
+		*freq = consumer_freq;
+}
+
+/*
+ * Aggregation is performed on each parameter based on the way that the RPM
+ * aggregates that type internally between RPM masters.
+ */
+static void rpm_vreg_aggregate_params(u32 *param_aggr, const u32 *param_reg)
+{
+	RPM_VREG_AGGR_MAX(ENABLE, param_aggr, param_reg);
+	RPM_VREG_AGGR_MAX(VOLTAGE, param_aggr, param_reg);
+	RPM_VREG_AGGR_SUM(CURRENT, param_aggr, param_reg);
+	RPM_VREG_AGGR_MAX(MODE_LDO, param_aggr, param_reg);
+	RPM_VREG_AGGR_MAX(MODE_SMPS, param_aggr, param_reg);
+	RPM_VREG_AGGR_OR(PIN_CTRL_ENABLE, param_aggr, param_reg);
+	RPM_VREG_AGGR_OR(PIN_CTRL_MODE, param_aggr, param_reg);
+	rpm_vreg_freqency_aggr(&param_aggr[RPM_REGULATOR_PARAM_FREQUENCY],
+		param_reg[RPM_REGULATOR_PARAM_FREQUENCY]);
+	RPM_VREG_AGGR_MAX(HEAD_ROOM, param_aggr, param_reg);
+	RPM_VREG_AGGR_MAX(QUIET_MODE, param_aggr, param_reg);
+	RPM_VREG_AGGR_MAX(FREQ_REASON, param_aggr, param_reg);
+}
+
+static int rpm_vreg_aggregate_requests(struct rpm_regulator *regulator)
+{
+	struct rpm_vreg *rpm_vreg = regulator->rpm_vreg;
+	u32 param_active[RPM_REGULATOR_PARAM_MAX];
+	u32 param_sleep[RPM_REGULATOR_PARAM_MAX];
+	u32 modified_active, modified_sleep;
+	struct rpm_regulator *reg;
+	bool sleep_set_differs = false;
+	bool send_active = false;
+	bool send_sleep = false;
+	int rc = 0;
+	int i;
+
+	memset(param_active, 0, sizeof(param_active));
+	memset(param_sleep, 0, sizeof(param_sleep));
+	modified_active = rpm_vreg->aggr_req_active.modified;
+	modified_sleep = rpm_vreg->aggr_req_sleep.modified;
+
+	/*
+	 * Aggregate all of the requests for this regulator in both active
+	 * and sleep sets.
+	 */
+	list_for_each_entry(reg, &rpm_vreg->reg_list, list) {
+		if (reg->set_active) {
+			rpm_vreg_aggregate_params(param_active, reg->req.param);
+			modified_active |= reg->req.modified;
+		}
+		if (reg->set_sleep) {
+			rpm_vreg_aggregate_params(param_sleep, reg->req.param);
+			modified_sleep |= reg->req.modified;
+		}
+	}
+
+	/*
+	 * Check if the aggregated sleep set parameter values differ from the
+	 * aggregated active set parameter values.
+	 */
+	if (!rpm_vreg->sleep_request_sent) {
+		for (i = 0; i < RPM_REGULATOR_PARAM_MAX; i++) {
+			if ((param_active[i] != param_sleep[i])
+			    && (modified_sleep & BIT(i))) {
+				sleep_set_differs = true;
+				break;
+			}
+		}
+	}
+
+	/* Add KVPs to the active set RPM request if they have new values. */
+	rpm_vreg_check_modified_requests(rpm_vreg->aggr_req_active.param,
+		param_active, rpm_vreg->aggr_req_active.valid,
+		&modified_active);
+	rc = rpm_vreg_add_modified_requests(regulator, RPM_SET_ACTIVE,
+		param_active, modified_active);
+	if (rc)
+		return rc;
+	send_active = modified_active;
+
+	/*
+	 * Sleep set configurations are only sent if they differ from the
+	 * active set values.  This is because the active set values will take
+	 * effect during rpm assisted power collapse in the absence of sleep set
+	 * values.
+	 *
+	 * However, once a sleep set request is sent for a given regulator,
+	 * additional sleep set requests must be sent in the future even if they
+	 * match the corresponding active set requests.
+	 */
+	if (rpm_vreg->sleep_request_sent || sleep_set_differs) {
+		/* Add KVPs to the sleep set RPM request if they are new. */
+		rpm_vreg_check_modified_requests(rpm_vreg->aggr_req_sleep.param,
+			param_sleep, rpm_vreg->aggr_req_sleep.valid,
+			&modified_sleep);
+		rc = rpm_vreg_add_modified_requests(regulator, RPM_SET_SLEEP,
+			param_sleep, modified_sleep);
+		if (rc)
+			return rc;
+		send_sleep = modified_sleep;
+	}
+
+	/* Send active set request to the RPM if it contains new KVPs. */
+	if (send_active) {
+		rc = rpm_vreg_send_request(regulator, RPM_SET_ACTIVE);
+		if (rc)
+			return rc;
+		rpm_vreg->aggr_req_active.valid |= modified_active;
+	}
+	/* Store the results of the aggregation. */
+	rpm_vreg->aggr_req_active.modified = modified_active;
+	memcpy(rpm_vreg->aggr_req_active.param, param_active,
+		sizeof(param_active));
+
+	/* Handle debug printing of the active set request. */
+	rpm_regulator_req(regulator, RPM_SET_ACTIVE, send_active);
+	if (send_active)
+		rpm_vreg->aggr_req_active.modified = 0;
+
+	/* Send sleep set request to the RPM if it contains new KVPs. */
+	if (send_sleep) {
+		rc = rpm_vreg_send_request(regulator, RPM_SET_SLEEP);
+		if (rc)
+			return rc;
+		else
+			rpm_vreg->sleep_request_sent = true;
+		rpm_vreg->aggr_req_sleep.valid |= modified_sleep;
+	}
+	/* Store the results of the aggregation. */
+	rpm_vreg->aggr_req_sleep.modified = modified_sleep;
+	memcpy(rpm_vreg->aggr_req_sleep.param, param_sleep,
+		sizeof(param_sleep));
+
+	/* Handle debug printing of the sleep set request. */
+	rpm_regulator_req(regulator, RPM_SET_SLEEP, send_sleep);
+	if (send_sleep)
+		rpm_vreg->aggr_req_sleep.modified = 0;
+
+	/*
+	 * Loop over all requests for this regulator to update the valid and
+	 * modified values for use in future aggregation.
+	 */
+	list_for_each_entry(reg, &rpm_vreg->reg_list, list) {
+		reg->req.valid |= reg->req.modified;
+		reg->req.modified = 0;
+	}
+
+	return rc;
+}
+
+static int rpm_vreg_is_enabled(struct regulator_dev *rdev)
+{
+	struct rpm_regulator *reg = rdev_get_drvdata(rdev);
+
+	return reg->req.param[RPM_REGULATOR_PARAM_ENABLE];
+}
+
+static int rpm_vreg_enable(struct regulator_dev *rdev)
+{
+	struct rpm_regulator *reg = rdev_get_drvdata(rdev);
+	int rc;
+	u32 prev_enable;
+
+	rpm_vreg_lock(reg->rpm_vreg);
+
+	prev_enable = reg->req.param[RPM_REGULATOR_PARAM_ENABLE];
+	RPM_VREG_SET_PARAM(reg, ENABLE, 1);
+	rc = rpm_vreg_aggregate_requests(reg);
+	if (rc) {
+		vreg_err(reg, "enable failed, rc=%d", rc);
+		RPM_VREG_SET_PARAM(reg, ENABLE, prev_enable);
+	}
+
+	rpm_vreg_unlock(reg->rpm_vreg);
+
+	return rc;
+}
+
+static int rpm_vreg_disable(struct regulator_dev *rdev)
+{
+	struct rpm_regulator *reg = rdev_get_drvdata(rdev);
+	int rc;
+	u32 prev_enable;
+
+	rpm_vreg_lock(reg->rpm_vreg);
+
+	prev_enable = reg->req.param[RPM_REGULATOR_PARAM_ENABLE];
+	RPM_VREG_SET_PARAM(reg, ENABLE, 0);
+	rc = rpm_vreg_aggregate_requests(reg);
+	if (rc) {
+		vreg_err(reg, "enable failed, rc=%d", rc);
+		RPM_VREG_SET_PARAM(reg, ENABLE, prev_enable);
+	}
+
+	rpm_vreg_unlock(reg->rpm_vreg);
+
+	return rc;
+}
+
+static int rpm_vreg_set_voltage(struct regulator_dev *rdev, int min_uV,
+				int max_uV, unsigned *selector)
+{
+	struct rpm_regulator *reg = rdev_get_drvdata(rdev);
+	int rc = 0;
+	u32 prev_voltage;
+
+	rpm_vreg_lock(reg->rpm_vreg);
+
+	prev_voltage = reg->req.param[RPM_REGULATOR_PARAM_VOLTAGE];
+	RPM_VREG_SET_PARAM(reg, VOLTAGE, min_uV);
+
+	/* Only send a new voltage if the regulator is currently enabled. */
+	if (rpm_vreg_active_or_sleep_enabled(reg->rpm_vreg))
+		rc = rpm_vreg_aggregate_requests(reg);
+
+	if (rc) {
+		vreg_err(reg, "set voltage failed, rc=%d", rc);
+		RPM_VREG_SET_PARAM(reg, VOLTAGE, prev_voltage);
+	}
+
+	rpm_vreg_unlock(reg->rpm_vreg);
+
+	return rc;
+}
+
+static int rpm_vreg_get_voltage(struct regulator_dev *rdev)
+{
+	struct rpm_regulator *reg = rdev_get_drvdata(rdev);
+	int uV;
+
+	uV = reg->req.param[RPM_REGULATOR_PARAM_VOLTAGE];
+	if (uV == 0)
+		uV = VOLTAGE_UNKNOWN;
+
+	return uV;
+}
+
+static int rpm_vreg_list_voltage(struct regulator_dev *rdev, unsigned selector)
+{
+	struct rpm_regulator *reg = rdev_get_drvdata(rdev);
+	int uV = 0;
+
+	if (selector == 0)
+		uV = reg->min_uV;
+	else if (selector == 1)
+		uV = reg->max_uV;
+
+	return uV;
+}
+
+static int rpm_vreg_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+	struct rpm_regulator *reg = rdev_get_drvdata(rdev);
+	int rc = 0;
+	u32 prev_current;
+	int prev_uA;
+
+	rpm_vreg_lock(reg->rpm_vreg);
+
+	prev_current = reg->req.param[RPM_REGULATOR_PARAM_CURRENT];
+	prev_uA = MILLI_TO_MICRO(prev_current);
+
+	if (mode == REGULATOR_MODE_NORMAL) {
+		/* Make sure that request current is in HPM range. */
+		if (prev_uA < rpm_vreg_hpm_min_uA(reg->rpm_vreg))
+			RPM_VREG_SET_PARAM(reg, CURRENT,
+			    MICRO_TO_MILLI(rpm_vreg_hpm_min_uA(reg->rpm_vreg)));
+	} else if (REGULATOR_MODE_IDLE) {
+		/* Make sure that request current is in LPM range. */
+		if (prev_uA > rpm_vreg_lpm_max_uA(reg->rpm_vreg))
+			RPM_VREG_SET_PARAM(reg, CURRENT,
+			    MICRO_TO_MILLI(rpm_vreg_lpm_max_uA(reg->rpm_vreg)));
+	} else {
+		vreg_err(reg, "invalid mode: %u\n", mode);
+		rpm_vreg_unlock(reg->rpm_vreg);
+		return -EINVAL;
+	}
+
+	/* Only send a new mode value if the regulator is currently enabled. */
+	if (rpm_vreg_active_or_sleep_enabled(reg->rpm_vreg))
+		rc = rpm_vreg_aggregate_requests(reg);
+
+	if (rc) {
+		vreg_err(reg, "set mode failed, rc=%d", rc);
+		RPM_VREG_SET_PARAM(reg, CURRENT, prev_current);
+	}
+
+	rpm_vreg_unlock(reg->rpm_vreg);
+
+	return rc;
+}
+
+static unsigned int rpm_vreg_get_mode(struct regulator_dev *rdev)
+{
+	struct rpm_regulator *reg = rdev_get_drvdata(rdev);
+
+	return (reg->req.param[RPM_REGULATOR_PARAM_CURRENT]
+			>= MICRO_TO_MILLI(reg->rpm_vreg->hpm_min_load))
+		? REGULATOR_MODE_NORMAL : REGULATOR_MODE_IDLE;
+}
+
+static unsigned int rpm_vreg_get_optimum_mode(struct regulator_dev *rdev,
+			int input_uV, int output_uV, int load_uA)
+{
+	struct rpm_regulator *reg = rdev_get_drvdata(rdev);
+	u32 load_mA;
+
+	load_uA += reg->system_load;
+
+	load_mA = MICRO_TO_MILLI(load_uA);
+	if (load_mA > params[RPM_REGULATOR_PARAM_CURRENT].max)
+		load_mA = params[RPM_REGULATOR_PARAM_CURRENT].max;
+
+	rpm_vreg_lock(reg->rpm_vreg);
+	RPM_VREG_SET_PARAM(reg, CURRENT, MICRO_TO_MILLI(load_uA));
+	rpm_vreg_unlock(reg->rpm_vreg);
+
+	return (load_uA >= reg->rpm_vreg->hpm_min_load)
+		? REGULATOR_MODE_NORMAL : REGULATOR_MODE_IDLE;
+}
+
+static int rpm_vreg_enable_time(struct regulator_dev *rdev)
+{
+	struct rpm_regulator *reg = rdev_get_drvdata(rdev);
+
+	return reg->rpm_vreg->enable_time;
+}
+
+/**
+ * rpm_regulator_get() - lookup and obtain a handle to an RPM regulator
+ * @dev: device for regulator consumer
+ * @supply: supply name
+ *
+ * Returns a struct rpm_regulator corresponding to the regulator producer,
+ * or ERR_PTR() containing errno.
+ *
+ * This function may only be called from nonatomic context.
+ */
+struct rpm_regulator *rpm_regulator_get(struct device *dev, const char *supply)
+{
+	struct rpm_regulator *framework_reg;
+	struct rpm_regulator *priv_reg = NULL;
+	struct regulator *regulator;
+	struct rpm_vreg *rpm_vreg;
+
+	regulator = regulator_get(dev, supply);
+	if (regulator == NULL) {
+		pr_err("could not find regulator for: dev=%s, id=%s\n",
+			(dev ? dev_name(dev) : ""), (supply ? supply : ""));
+		return ERR_PTR(-ENODEV);
+	}
+
+	framework_reg = regulator_get_drvdata(regulator);
+	if (framework_reg == NULL) {
+		pr_err("regulator structure not found.\n");
+		regulator_put(regulator);
+		return ERR_PTR(-ENODEV);
+	}
+	regulator_put(regulator);
+
+	rpm_vreg = framework_reg->rpm_vreg;
+
+	priv_reg = kzalloc(sizeof(struct rpm_regulator), GFP_KERNEL);
+	if (priv_reg == NULL) {
+		vreg_err(framework_reg, "could not allocate memory for "
+			"regulator\n");
+		rpm_vreg_unlock(rpm_vreg);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	/*
+	 * Allocate a regulator_dev struct so that framework callback functions
+	 * can be called from the private API functions.
+	 */
+	priv_reg->rdev = kzalloc(sizeof(struct regulator_dev), GFP_KERNEL);
+	if (priv_reg->rdev == NULL) {
+		vreg_err(framework_reg, "could not allocate memory for "
+			"regulator_dev\n");
+		kfree(priv_reg);
+		rpm_vreg_unlock(rpm_vreg);
+		return ERR_PTR(-ENOMEM);
+	}
+	priv_reg->rdev->reg_data	= priv_reg;
+	priv_reg->rpm_vreg		= rpm_vreg;
+	priv_reg->rdesc.name		= framework_reg->rdesc.name;
+	priv_reg->set_active		= framework_reg->set_active;
+	priv_reg->set_sleep		= framework_reg->set_sleep;
+	priv_reg->min_uV		= framework_reg->min_uV;
+	priv_reg->max_uV		= framework_reg->max_uV;
+	priv_reg->system_load		= framework_reg->system_load;
+
+	might_sleep_if(!rpm_vreg->allow_atomic);
+	rpm_vreg_lock(rpm_vreg);
+	list_add(&priv_reg->list, &rpm_vreg->reg_list);
+	rpm_vreg_unlock(rpm_vreg);
+
+	return priv_reg;
+}
+EXPORT_SYMBOL_GPL(rpm_regulator_get);
+
+static int rpm_regulator_check_input(struct rpm_regulator *regulator)
+{
+	if (regulator == NULL || regulator->rpm_vreg == NULL) {
+		pr_err("invalid rpm_regulator pointer\n");
+		return -EINVAL;
+	}
+
+	might_sleep_if(!regulator->rpm_vreg->allow_atomic);
+
+	return 0;
+}
+
+/**
+ * rpm_regulator_put() - free the RPM regulator handle
+ * @regulator: RPM regulator handle
+ *
+ * Parameter reaggregation does not take place when rpm_regulator_put is called.
+ * Therefore, regulator enable state and voltage must be configured
+ * appropriately before calling rpm_regulator_put.
+ *
+ * This function may be called from either atomic or nonatomic context.  If this
+ * function is called from atomic context, then the regulator being operated on
+ * must be configured via device tree with qcom,allow-atomic == 1.
+ */
+void rpm_regulator_put(struct rpm_regulator *regulator)
+{
+	struct rpm_vreg *rpm_vreg;
+	int rc = rpm_regulator_check_input(regulator);
+
+	if (rc)
+		return;
+
+	rpm_vreg = regulator->rpm_vreg;
+
+	might_sleep_if(!rpm_vreg->allow_atomic);
+	rpm_vreg_lock(rpm_vreg);
+	list_del(&regulator->list);
+	rpm_vreg_unlock(rpm_vreg);
+
+	kfree(regulator->rdev);
+	kfree(regulator);
+}
+EXPORT_SYMBOL_GPL(rpm_regulator_put);
+
+/**
+ * rpm_regulator_enable() - enable regulator output
+ * @regulator: RPM regulator handle
+ *
+ * Returns 0 on success or errno on failure.
+ *
+ * This function may be called from either atomic or nonatomic context.  If this
+ * function is called from atomic context, then the regulator being operated on
+ * must be configured via device tree with qcom,allow-atomic == 1.
+ */
+int rpm_regulator_enable(struct rpm_regulator *regulator)
+{
+	int rc = rpm_regulator_check_input(regulator);
+
+	if (rc)
+		return rc;
+
+	return rpm_vreg_enable(regulator->rdev);
+}
+EXPORT_SYMBOL_GPL(rpm_regulator_enable);
+
+/**
+ * rpm_regulator_disable() - disable regulator output
+ * @regulator: RPM regulator handle
+ *
+ * Returns 0 on success or errno on failure.
+ *
+ * The enable state of the regulator is determined by aggregating the requests
+ * of all consumers.  Therefore, it is possible that the regulator will remain
+ * enabled even after rpm_regulator_disable is called.
+ *
+ * This function may be called from either atomic or nonatomic context.  If this
+ * function is called from atomic context, then the regulator being operated on
+ * must be configured via device tree with qcom,allow-atomic == 1.
+ */
+int rpm_regulator_disable(struct rpm_regulator *regulator)
+{
+	int rc = rpm_regulator_check_input(regulator);
+
+	if (rc)
+		return rc;
+
+	return rpm_vreg_disable(regulator->rdev);
+}
+EXPORT_SYMBOL_GPL(rpm_regulator_disable);
+
+/**
+ * rpm_regulator_set_voltage() - set regulator output voltage
+ * @regulator: RPM regulator handle
+ * @min_uV: minimum required voltage in uV
+ * @max_uV: maximum acceptable voltage in uV
+ *
+ * Sets a voltage regulator to the desired output voltage. This can be set
+ * while the regulator is disabled or enabled.  If the regulator is enabled then
+ * the voltage will change to the new value immediately; otherwise, if the
+ * regulator is disabled, then the regulator will output at the new voltage when
+ * enabled.
+ *
+ * The min_uV to max_uV voltage range requested must intersect with the
+ * voltage constraint range configured for the regulator.
+ *
+ * Returns 0 on success or errno on failure.
+ *
+ * The final voltage value that is sent to the RPM is aggregated based upon the
+ * values requested by all consumers of the regulator.  This corresponds to the
+ * maximum min_uV value.
+ *
+ * This function may be called from either atomic or nonatomic context.  If this
+ * function is called from atomic context, then the regulator being operated on
+ * must be configured via device tree with qcom,allow-atomic == 1.
+ */
+int rpm_regulator_set_voltage(struct rpm_regulator *regulator, int min_uV,
+			      int max_uV)
+{
+	int rc = rpm_regulator_check_input(regulator);
+	int uV = min_uV;
+
+	if (rc)
+		return rc;
+
+	if (regulator->rpm_vreg->regulator_type == RPM_REGULATOR_SMD_TYPE_VS) {
+		vreg_err(regulator, "unsupported regulator type: %d\n",
+			regulator->rpm_vreg->regulator_type);
+		return -EINVAL;
+	}
+
+	if (min_uV > max_uV) {
+		vreg_err(regulator, "min_uV=%d must be less than max_uV=%d\n",
+			min_uV, max_uV);
+		return -EINVAL;
+	}
+
+	if (uV < regulator->min_uV && max_uV >= regulator->min_uV)
+		uV = regulator->min_uV;
+
+	if (uV < regulator->min_uV || uV > regulator->max_uV) {
+		vreg_err(regulator, "request v=[%d, %d] is outside allowed "
+			"v=[%d, %d]\n", min_uV, max_uV, regulator->min_uV,
+			regulator->max_uV);
+		return -EINVAL;
+	}
+
+	return rpm_vreg_set_voltage(regulator->rdev, uV, uV, NULL);
+}
+EXPORT_SYMBOL_GPL(rpm_regulator_set_voltage);
+
+static struct regulator_ops ldo_ops = {
+	.enable			= rpm_vreg_enable,
+	.disable		= rpm_vreg_disable,
+	.is_enabled		= rpm_vreg_is_enabled,
+	.set_voltage		= rpm_vreg_set_voltage,
+	.get_voltage		= rpm_vreg_get_voltage,
+	.list_voltage		= rpm_vreg_list_voltage,
+	.set_mode		= rpm_vreg_set_mode,
+	.get_mode		= rpm_vreg_get_mode,
+	.get_optimum_mode	= rpm_vreg_get_optimum_mode,
+	.enable_time		= rpm_vreg_enable_time,
+};
+
+static struct regulator_ops smps_ops = {
+	.enable			= rpm_vreg_enable,
+	.disable		= rpm_vreg_disable,
+	.is_enabled		= rpm_vreg_is_enabled,
+	.set_voltage		= rpm_vreg_set_voltage,
+	.get_voltage		= rpm_vreg_get_voltage,
+	.list_voltage		= rpm_vreg_list_voltage,
+	.set_mode		= rpm_vreg_set_mode,
+	.get_mode		= rpm_vreg_get_mode,
+	.get_optimum_mode	= rpm_vreg_get_optimum_mode,
+	.enable_time		= rpm_vreg_enable_time,
+};
+
+static struct regulator_ops switch_ops = {
+	.enable			= rpm_vreg_enable,
+	.disable		= rpm_vreg_disable,
+	.is_enabled		= rpm_vreg_is_enabled,
+	.enable_time		= rpm_vreg_enable_time,
+};
+
+static struct regulator_ops ncp_ops = {
+	.enable			= rpm_vreg_enable,
+	.disable		= rpm_vreg_disable,
+	.is_enabled		= rpm_vreg_is_enabled,
+	.set_voltage		= rpm_vreg_set_voltage,
+	.get_voltage		= rpm_vreg_get_voltage,
+	.list_voltage		= rpm_vreg_list_voltage,
+	.enable_time		= rpm_vreg_enable_time,
+};
+
+static struct regulator_ops *vreg_ops[] = {
+	[RPM_REGULATOR_SMD_TYPE_LDO]	= &ldo_ops,
+	[RPM_REGULATOR_SMD_TYPE_SMPS]	= &smps_ops,
+	[RPM_REGULATOR_SMD_TYPE_VS]	= &switch_ops,
+	[RPM_REGULATOR_SMD_TYPE_NCP]	= &ncp_ops,
+};
+
+static int __devexit rpm_vreg_device_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct rpm_regulator *reg;
+
+	reg = platform_get_drvdata(pdev);
+	if (reg) {
+		rpm_vreg_lock(reg->rpm_vreg);
+		regulator_unregister(reg->rdev);
+		list_del(&reg->list);
+		kfree(reg);
+		rpm_vreg_unlock(reg->rpm_vreg);
+	} else {
+		dev_err(dev, "%s: drvdata missing\n", __func__);
+		return -EINVAL;
+	}
+
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static int __devexit rpm_vreg_resource_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct rpm_regulator *reg, *reg_temp;
+	struct rpm_vreg *rpm_vreg;
+
+	rpm_vreg = platform_get_drvdata(pdev);
+	if (rpm_vreg) {
+		rpm_vreg_lock(rpm_vreg);
+		list_for_each_entry_safe(reg, reg_temp, &rpm_vreg->reg_list,
+				list) {
+			/* Only touch data for private consumers. */
+			if (reg->rdev->desc == NULL) {
+				list_del(&reg->list);
+				kfree(reg->rdev);
+				kfree(reg);
+			} else {
+				dev_err(dev, "%s: not all child devices have "
+					"been removed\n", __func__);
+			}
+		}
+		rpm_vreg_unlock(rpm_vreg);
+
+		msm_rpm_free_request(rpm_vreg->handle_active);
+		msm_rpm_free_request(rpm_vreg->handle_sleep);
+
+		kfree(rpm_vreg);
+	} else {
+		dev_err(dev, "%s: drvdata missing\n", __func__);
+		return -EINVAL;
+	}
+
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+/*
+ * This probe is called for child rpm-regulator devices which have
+ * properties which are required to configure individual regulator
+ * framework regulators for a given RPM regulator resource.
+ */
+static int __devinit rpm_vreg_device_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *node = dev->of_node;
+	struct regulator_init_data *init_data;
+	struct rpm_vreg *rpm_vreg;
+	struct rpm_regulator *reg;
+	int rc = 0;
+	int i, regulator_type;
+	u32 val;
+
+	if (!dev->of_node) {
+		dev_err(dev, "%s: device tree information missing\n", __func__);
+		return -ENODEV;
+	}
+
+	if (pdev->dev.parent == NULL) {
+		dev_err(dev, "%s: parent device missing\n", __func__);
+		return -ENODEV;
+	}
+
+	rpm_vreg = dev_get_drvdata(pdev->dev.parent);
+	if (rpm_vreg == NULL) {
+		dev_err(dev, "%s: rpm_vreg not found in parent device\n",
+			__func__);
+		return -ENODEV;
+	}
+
+	reg = kzalloc(sizeof(struct rpm_regulator), GFP_KERNEL);
+	if (reg == NULL) {
+		dev_err(dev, "%s: could not allocate memory for reg\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	regulator_type		= rpm_vreg->regulator_type;
+	reg->rpm_vreg		= rpm_vreg;
+	reg->rdesc.ops		= vreg_ops[regulator_type];
+	reg->rdesc.owner	= THIS_MODULE;
+	reg->rdesc.type		= REGULATOR_VOLTAGE;
+
+	if (regulator_type == RPM_REGULATOR_SMD_TYPE_VS)
+		reg->rdesc.n_voltages = 0;
+	else
+		reg->rdesc.n_voltages = 2;
+
+	rc = of_property_read_u32(node, "qcom,set", &val);
+	if (rc) {
+		dev_err(dev, "%s: sleep set and/or active set must be "
+			"configured via qcom,set property, rc=%d\n", __func__,
+			rc);
+		goto fail_free_reg;
+	} else if (!(val & RPM_SET_CONFIG_BOTH)) {
+		dev_err(dev, "%s: qcom,set=%u property is invalid\n", __func__,
+			val);
+		rc = -EINVAL;
+		goto fail_free_reg;
+	}
+
+	reg->set_active = !!(val & RPM_SET_CONFIG_ACTIVE);
+	reg->set_sleep = !!(val & RPM_SET_CONFIG_SLEEP);
+
+	init_data = of_get_regulator_init_data(dev);
+	if (init_data == NULL) {
+		dev_err(dev, "%s: unable to allocate memory\n", __func__);
+		rc = -ENOMEM;
+		goto fail_free_reg;
+	}
+	if (init_data->constraints.name == NULL) {
+		dev_err(dev, "%s: regulator name not specified\n", __func__);
+		rc = -EINVAL;
+		goto fail_free_reg;
+	}
+
+	init_data->constraints.input_uV	= init_data->constraints.max_uV;
+
+	if (of_get_property(node, "parent-supply", NULL))
+		init_data->supply_regulator = "parent";
+
+	/*
+	 * Fill in ops and mode masks based on callbacks specified for
+	 * this type of regulator.
+	 */
+	if (reg->rdesc.ops->enable)
+		init_data->constraints.valid_ops_mask
+			|= REGULATOR_CHANGE_STATUS;
+	if (reg->rdesc.ops->get_voltage)
+		init_data->constraints.valid_ops_mask
+			|= REGULATOR_CHANGE_VOLTAGE;
+	if (reg->rdesc.ops->get_mode) {
+		init_data->constraints.valid_ops_mask
+			|= REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_DRMS;
+		init_data->constraints.valid_modes_mask
+			|= REGULATOR_MODE_NORMAL | REGULATOR_MODE_IDLE;
+	}
+
+	reg->rdesc.name		= init_data->constraints.name;
+	reg->min_uV		= init_data->constraints.min_uV;
+	reg->max_uV		= init_data->constraints.max_uV;
+
+	/* Initialize the param array based on optional properties. */
+	for (i = 0; i < RPM_REGULATOR_PARAM_MAX; i++) {
+		rc = of_property_read_u32(node, params[i].property_name, &val);
+		if (rc == 0) {
+			if (params[i].supported_regulator_types
+					& BIT(regulator_type)) {
+				if (val < params[i].min
+						|| val > params[i].max) {
+					pr_warn("%s: device tree property: "
+						"%s=%u is outsided allowed "
+						"range [%u, %u]\n",
+						reg->rdesc.name,
+						params[i].property_name, val,
+						params[i].min, params[i].max);
+					continue;
+				}
+				reg->req.param[i] = val;
+				reg->req.modified |= BIT(i);
+			} else {
+				pr_warn("%s: regulator type=%d does not support"
+					" device tree property: %s\n",
+					reg->rdesc.name, regulator_type,
+					params[i].property_name);
+			}
+		}
+	}
+
+	of_property_read_u32(node, "qcom,system_load", &reg->system_load);
+
+	rpm_vreg_lock(rpm_vreg);
+	list_add(&reg->list, &rpm_vreg->reg_list);
+	rpm_vreg_unlock(rpm_vreg);
+
+	reg->rdev = regulator_register(&reg->rdesc, dev, init_data, reg, node);
+	if (IS_ERR(reg->rdev)) {
+		rc = PTR_ERR(reg->rdev);
+		reg->rdev = NULL;
+		pr_err("regulator_register failed: %s, rc=%d\n",
+			reg->rdesc.name, rc);
+		goto fail_remove_from_list;
+	}
+
+	platform_set_drvdata(pdev, reg);
+
+	pr_debug("successfully probed: %s\n", reg->rdesc.name);
+
+	return 0;
+
+fail_remove_from_list:
+	rpm_vreg_lock(rpm_vreg);
+	list_del(&reg->list);
+	rpm_vreg_unlock(rpm_vreg);
+
+fail_free_reg:
+	kfree(reg);
+	return rc;
+}
+
+/*
+ * This probe is called for parent rpm-regulator devices which have
+ * properties which are required to identify a given RPM resource.
+ */
+static int __devinit rpm_vreg_resource_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *node = dev->of_node;
+	struct rpm_vreg *rpm_vreg;
+	int val = 0;
+	u32 resource_type;
+	int rc;
+
+	if (!dev->of_node) {
+		dev_err(dev, "%s: device tree information missing\n", __func__);
+		return -ENODEV;
+	}
+
+	/* Create new rpm_vreg entry. */
+	rpm_vreg = kzalloc(sizeof(struct rpm_vreg), GFP_KERNEL);
+	if (rpm_vreg == NULL) {
+		dev_err(dev, "%s: could not allocate memory for vreg\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	/* Required device tree properties: */
+	rc = of_property_read_string(node, "qcom,resource-name",
+			&rpm_vreg->resource_name);
+	if (rc) {
+		dev_err(dev, "%s: qcom,resource-name missing in DT node\n",
+			__func__);
+		goto fail_free_vreg;
+	}
+	resource_type = rpm_vreg_string_to_int(rpm_vreg->resource_name);
+
+	rc = of_property_read_u32(node, "qcom,resource-id",
+			&rpm_vreg->resource_id);
+	if (rc) {
+		dev_err(dev, "%s: qcom,resource-id missing in DT node\n",
+			__func__);
+		goto fail_free_vreg;
+	}
+
+	rc = of_property_read_u32(node, "qcom,regulator-type",
+			&rpm_vreg->regulator_type);
+	if (rc) {
+		dev_err(dev, "%s: qcom,regulator-type missing in DT node\n",
+			__func__);
+		goto fail_free_vreg;
+	}
+
+	if ((rpm_vreg->regulator_type < 0)
+	    || (rpm_vreg->regulator_type >= RPM_REGULATOR_SMD_TYPE_MAX)) {
+		dev_err(dev, "%s: invalid regulator type: %d\n", __func__,
+			rpm_vreg->regulator_type);
+		rc = -EINVAL;
+		goto fail_free_vreg;
+	}
+
+	/* Optional device tree properties: */
+	of_property_read_u32(node, "qcom,allow-atomic", &val);
+	rpm_vreg->allow_atomic = !!val;
+	of_property_read_u32(node, "qcom,enable-time", &rpm_vreg->enable_time);
+	of_property_read_u32(node, "qcom,hpm-min-load",
+		&rpm_vreg->hpm_min_load);
+
+	rpm_vreg->handle_active = msm_rpm_create_request(RPM_SET_ACTIVE,
+		resource_type, rpm_vreg->resource_id, RPM_REGULATOR_PARAM_MAX);
+	if (rpm_vreg->handle_active == NULL
+	    || IS_ERR(rpm_vreg->handle_active)) {
+		rc = PTR_ERR(rpm_vreg->handle_active);
+		dev_err(dev, "%s: failed to create active RPM handle, rc=%d\n",
+			__func__, rc);
+		goto fail_free_vreg;
+	}
+
+	rpm_vreg->handle_sleep = msm_rpm_create_request(RPM_SET_SLEEP,
+		resource_type, rpm_vreg->resource_id, RPM_REGULATOR_PARAM_MAX);
+	if (rpm_vreg->handle_sleep == NULL || IS_ERR(rpm_vreg->handle_sleep)) {
+		rc = PTR_ERR(rpm_vreg->handle_sleep);
+		dev_err(dev, "%s: failed to create sleep RPM handle, rc=%d\n",
+			__func__, rc);
+		goto fail_free_handle_active;
+	}
+
+	INIT_LIST_HEAD(&rpm_vreg->reg_list);
+
+	if (rpm_vreg->allow_atomic)
+		spin_lock_init(&rpm_vreg->slock);
+	else
+		mutex_init(&rpm_vreg->mlock);
+
+	platform_set_drvdata(pdev, rpm_vreg);
+
+	rc = of_platform_populate(node, NULL, NULL, dev);
+	if (rc) {
+		dev_err(dev, "%s: failed to add child nodes, rc=%d\n", __func__,
+			rc);
+		goto fail_unset_drvdata;
+	}
+
+	pr_debug("successfully probed: %s (%08X) %u\n", rpm_vreg->resource_name,
+		resource_type, rpm_vreg->resource_id);
+
+	return rc;
+
+fail_unset_drvdata:
+	platform_set_drvdata(pdev, NULL);
+	msm_rpm_free_request(rpm_vreg->handle_sleep);
+
+fail_free_handle_active:
+	msm_rpm_free_request(rpm_vreg->handle_active);
+
+fail_free_vreg:
+	kfree(rpm_vreg);
+
+	return rc;
+}
+
+static struct of_device_id rpm_vreg_match_table_device[] = {
+	{ .compatible = "qcom,rpm-regulator-smd", },
+	{}
+};
+
+static struct of_device_id rpm_vreg_match_table_resource[] = {
+	{ .compatible = "qcom,rpm-regulator-smd-resource", },
+	{}
+};
+
+static struct platform_driver rpm_vreg_device_driver = {
+	.probe = rpm_vreg_device_probe,
+	.remove = __devexit_p(rpm_vreg_device_remove),
+	.driver = {
+		.name = "qcom,rpm-regulator-smd",
+		.owner = THIS_MODULE,
+		.of_match_table = rpm_vreg_match_table_device,
+	},
+};
+
+static struct platform_driver rpm_vreg_resource_driver = {
+	.probe = rpm_vreg_resource_probe,
+	.remove = __devexit_p(rpm_vreg_resource_remove),
+	.driver = {
+		.name = "qcom,rpm-regulator-smd-resource",
+		.owner = THIS_MODULE,
+		.of_match_table = rpm_vreg_match_table_resource,
+	},
+};
+
+/**
+ * rpm_regulator_smd_driver_init() - initialized SMD RPM regulator driver
+ *
+ * This function registers the SMD RPM regulator platform drivers.
+ *
+ * Returns 0 on success or errno on failure.
+ */
+int __init rpm_regulator_smd_driver_init(void)
+{
+	static bool initialized;
+	int i, rc;
+
+	if (initialized)
+		return 0;
+	else
+		initialized = true;
+
+	/* Store parameter string names as integers */
+	for (i = 0; i < RPM_REGULATOR_PARAM_MAX; i++)
+		params[i].key = rpm_vreg_string_to_int(params[i].name);
+
+	rc = platform_driver_register(&rpm_vreg_device_driver);
+	if (rc)
+		return rc;
+
+	return platform_driver_register(&rpm_vreg_resource_driver);
+}
+EXPORT_SYMBOL_GPL(rpm_regulator_smd_driver_init);
+
+static void __exit rpm_vreg_exit(void)
+{
+	platform_driver_unregister(&rpm_vreg_device_driver);
+	platform_driver_unregister(&rpm_vreg_resource_driver);
+}
+
+module_init(rpm_regulator_smd_driver_init);
+module_exit(rpm_vreg_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MSM SMD RPM regulator driver");
diff --git a/arch/arm/mach-msm/rpm-regulator.c b/arch/arm/mach-msm/rpm-regulator.c
index c708df5..f663695 100644
--- a/arch/arm/mach-msm/rpm-regulator.c
+++ b/arch/arm/mach-msm/rpm-regulator.c
@@ -19,10 +19,12 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
+#include <linux/string.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/driver.h>
 #include <mach/rpm.h>
 #include <mach/rpm-regulator.h>
+#include <mach/rpm-regulator-smd.h>
 #include <mach/socinfo.h>
 
 #include "rpm_resources.h"
@@ -42,6 +44,15 @@
 	debug_mask, msm_rpm_vreg_debug_mask, int, S_IRUSR | S_IWUSR
 );
 
+/* Used for access via the rpm_regulator_* API. */
+struct rpm_regulator {
+	int			vreg_id;
+	enum rpm_vreg_voter	voter;
+	int			sleep_also;
+	int			min_uV;
+	int			max_uV;
+};
+
 struct vreg_config *(*get_config[])(void) = {
 	[RPM_VREG_VERSION_8660] = get_config_8660,
 	[RPM_VREG_VERSION_8960] = get_config_8960,
@@ -49,6 +60,9 @@
 	[RPM_VREG_VERSION_8930] = get_config_8930,
 };
 
+static struct rpm_regulator_consumer_mapping *consumer_map;
+static int consumer_map_len;
+
 #define SET_PART(_vreg, _part, _val) \
 	_vreg->req[_vreg->part->_part.word].value \
 		= (_vreg->req[_vreg->part->_part.word].value \
@@ -615,6 +629,243 @@
 }
 EXPORT_SYMBOL_GPL(rpm_vreg_set_frequency);
 
+#define MAX_NAME_LEN 64
+/**
+ * rpm_regulator_get() - lookup and obtain a handle to an RPM regulator
+ * @dev: device for regulator consumer
+ * @supply: supply name
+ *
+ * Returns a struct rpm_regulator corresponding to the regulator producer,
+ * or ERR_PTR() containing errno.
+ *
+ * This function may only be called from nonatomic context.  The mapping between
+ * <dev, supply> tuples and rpm_regulators struct pointers is specified via
+ * rpm-regulator platform data.
+ */
+struct rpm_regulator *rpm_regulator_get(struct device *dev, const char *supply)
+{
+	struct rpm_regulator_consumer_mapping *mapping = NULL;
+	const char *devname = NULL;
+	struct rpm_regulator *regulator;
+	int i;
+
+	if (!config) {
+		pr_err("rpm-regulator driver has not probed yet.\n");
+		return ERR_PTR(-ENODEV);
+	}
+
+	if (consumer_map == NULL || consumer_map_len == 0) {
+		pr_err("No private consumer mapping has been specified.\n");
+		return ERR_PTR(-ENODEV);
+	}
+
+	if (supply == NULL) {
+		pr_err("supply name must be specified\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	if (dev)
+		devname = dev_name(dev);
+
+	for (i = 0; i < consumer_map_len; i++) {
+		/* If the mapping has a device set up it must match */
+		if (consumer_map[i].dev_name &&
+			(!devname || strncmp(consumer_map[i].dev_name, devname,
+					     MAX_NAME_LEN)))
+			continue;
+
+		if (strncmp(consumer_map[i].supply, supply, MAX_NAME_LEN)
+		    == 0) {
+			mapping = &consumer_map[i];
+			break;
+		}
+	}
+
+	if (mapping == NULL) {
+		pr_err("could not find mapping for dev=%s, supply=%s\n",
+			(devname ? devname : "(null)"), supply);
+		return ERR_PTR(-ENODEV);
+	}
+
+	regulator = kzalloc(sizeof(struct rpm_regulator), GFP_KERNEL);
+	if (regulator == NULL) {
+		pr_err("could not allocate memory for regulator\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	regulator->vreg_id	= mapping->vreg_id;
+	regulator->voter	= mapping->voter;
+	regulator->sleep_also	= mapping->sleep_also;
+
+	return regulator;
+}
+EXPORT_SYMBOL_GPL(rpm_regulator_get);
+
+static int rpm_regulator_check_input(struct rpm_regulator *regulator)
+{
+	int rc = 0;
+
+	if (regulator == NULL) {
+		rc = -EINVAL;
+		pr_err("invalid (null) rpm_regulator pointer\n");
+	} else if (IS_ERR(regulator)) {
+		rc = PTR_ERR(regulator);
+		pr_err("invalid rpm_regulator pointer, rc=%d\n", rc);
+	}
+
+	return rc;
+}
+
+/**
+ * rpm_regulator_put() - free the RPM regulator handle
+ * @regulator: RPM regulator handle
+ *
+ * Parameter reaggregation does not take place when rpm_regulator_put is called.
+ * Therefore, regulator enable state and voltage must be configured
+ * appropriately before calling rpm_regulator_put.
+ *
+ * This function may be called from either atomic or nonatomic context.
+ */
+void rpm_regulator_put(struct rpm_regulator *regulator)
+{
+	kfree(regulator);
+}
+EXPORT_SYMBOL_GPL(rpm_regulator_put);
+
+/**
+ * rpm_regulator_enable() - enable regulator output
+ * @regulator: RPM regulator handle
+ *
+ * Returns 0 on success or errno on failure.
+ *
+ * This function may be called from either atomic or nonatomic context.  This
+ * function may only be called for regulators which have the sleep_selectable
+ * flag set in their configuration data.
+ *
+ * rpm_regulator_set_voltage must be called before rpm_regulator_enable because
+ * enabling is defined by the RPM interface to be requesting the desired
+ * non-zero regulator output voltage.
+ */
+int rpm_regulator_enable(struct rpm_regulator *regulator)
+{
+	int rc = rpm_regulator_check_input(regulator);
+	struct vreg *vreg;
+
+	if (rc)
+		return rc;
+
+	if (regulator->vreg_id < config->vreg_id_min
+			|| regulator->vreg_id > config->vreg_id_max) {
+		pr_err("invalid regulator id=%d\n", regulator->vreg_id);
+		return -EINVAL;
+	}
+
+	vreg = &config->vregs[regulator->vreg_id];
+
+	/*
+	 * Handle voltage switches which can be enabled without
+	 * rpm_regulator_set_voltage ever being called.
+	 */
+	if (regulator->min_uV == 0 && regulator->max_uV == 0
+	    && vreg->part->uV.mask == 0 && vreg->part->mV.mask == 0) {
+		regulator->min_uV = 1;
+		regulator->max_uV = 1;
+	}
+
+	if (regulator->min_uV == 0 && regulator->max_uV == 0) {
+		pr_err("Voltage must be set with rpm_regulator_set_voltage "
+			"before calling rpm_regulator_enable; vreg_id=%d, "
+			"voter=%d\n", regulator->vreg_id, regulator->voter);
+		return -EINVAL;
+	}
+
+	rc = rpm_vreg_set_voltage(regulator->vreg_id, regulator->voter,
+		regulator->min_uV, regulator->max_uV, regulator->sleep_also);
+
+	if (rc)
+		pr_err("rpm_vreg_set_voltage failed, rc=%d\n", rc);
+
+	return rc;
+}
+EXPORT_SYMBOL_GPL(rpm_regulator_enable);
+
+/**
+ * rpm_regulator_disable() - disable regulator output
+ * @regulator: RPM regulator handle
+ *
+ * Returns 0 on success or errno on failure.
+ *
+ * The enable state of the regulator is determined by aggregating the requests
+ * of all consumers.  Therefore, it is possible that the regulator will remain
+ * enabled even after rpm_regulator_disable is called.
+ *
+ * This function may be called from either atomic or nonatomic context.  This
+ * function may only be called for regulators which have the sleep_selectable
+ * flag set in their configuration data.
+ */
+int rpm_regulator_disable(struct rpm_regulator *regulator)
+{
+	int rc = rpm_regulator_check_input(regulator);
+
+	if (rc)
+		return rc;
+
+	rc = rpm_vreg_set_voltage(regulator->vreg_id, regulator->voter, 0, 0,
+				  regulator->sleep_also);
+
+	if (rc)
+		pr_err("rpm_vreg_set_voltage failed, rc=%d\n", rc);
+
+	return rc;
+}
+EXPORT_SYMBOL_GPL(rpm_regulator_disable);
+
+/**
+ * rpm_regulator_set_voltage() - set regulator output voltage
+ * @regulator: RPM regulator handle
+ * @min_uV: minimum required voltage in uV
+ * @max_uV: maximum acceptable voltage in uV
+ *
+ * Sets a voltage regulator to the desired output voltage. This can be set
+ * while the regulator is disabled or enabled.  If the regulator is disabled,
+ * then rpm_regulator_set_voltage will both enable the regulator and set it to
+ * output at the requested voltage.
+ *
+ * The min_uV to max_uV voltage range requested must intersect with the
+ * voltage constraint range configured for the regulator.
+ *
+ * Returns 0 on success or errno on failure.
+ *
+ * The final voltage value that is sent to the RPM is aggregated based upon the
+ * values requested by all consumers of the regulator.  This corresponds to the
+ * maximum min_uV value.
+ *
+ * This function may be called from either atomic or nonatomic context.  This
+ * function may only be called for regulators which have the sleep_selectable
+ * flag set in their configuration data.
+ */
+int rpm_regulator_set_voltage(struct rpm_regulator *regulator, int min_uV,
+			      int max_uV)
+{
+	int rc = rpm_regulator_check_input(regulator);
+
+	if (rc)
+		return rc;
+
+	rc = rpm_vreg_set_voltage(regulator->vreg_id, regulator->voter, min_uV,
+				 max_uV, regulator->sleep_also);
+
+	if (rc) {
+		pr_err("rpm_vreg_set_voltage failed, rc=%d\n", rc);
+	} else {
+		regulator->min_uV = min_uV;
+		regulator->max_uV = max_uV;
+	}
+
+	return rc;
+}
+EXPORT_SYMBOL_GPL(rpm_regulator_set_voltage);
+
 static inline int vreg_hpm_min_uA(struct vreg *vreg)
 {
 	return vreg->hpm_min_load;
@@ -1374,6 +1625,8 @@
 static int __devinit rpm_vreg_probe(struct platform_device *pdev)
 {
 	struct rpm_regulator_platform_data *platform_data;
+	static struct rpm_regulator_consumer_mapping *prev_consumer_map;
+	static int prev_consumer_map_len;
 	int rc = 0;
 	int i, id;
 
@@ -1416,6 +1669,42 @@
 			mutex_init(&config->vregs[i].pc_lock);
 	}
 
+	/* Copy the list of private API consumers. */
+	if (platform_data->consumer_map_len > 0) {
+		if (consumer_map_len == 0) {
+			consumer_map_len = platform_data->consumer_map_len;
+			consumer_map = kmemdup(platform_data->consumer_map,
+				sizeof(struct rpm_regulator_consumer_mapping)
+				* consumer_map_len, GFP_KERNEL);
+			if (consumer_map == NULL) {
+				pr_err("memory allocation failed\n");
+				consumer_map_len = 0;
+				return -ENOMEM;
+			}
+		} else {
+			/* Concatenate new map with the existing one. */
+			prev_consumer_map = consumer_map;
+			prev_consumer_map_len = consumer_map_len;
+			consumer_map_len += platform_data->consumer_map_len;
+			consumer_map = kmalloc(
+				sizeof(struct rpm_regulator_consumer_mapping)
+				* consumer_map_len, GFP_KERNEL);
+			if (consumer_map == NULL) {
+				pr_err("memory allocation failed\n");
+				consumer_map_len = 0;
+				return -ENOMEM;
+			}
+			memcpy(consumer_map, prev_consumer_map,
+				sizeof(struct rpm_regulator_consumer_mapping)
+				* prev_consumer_map_len);
+			memcpy(&consumer_map[prev_consumer_map_len],
+				platform_data->consumer_map,
+				sizeof(struct rpm_regulator_consumer_mapping)
+				* platform_data->consumer_map_len);
+		}
+
+	}
+
 	/* Initialize all of the regulators listed in the platform data. */
 	for (i = 0; i < platform_data->num_regulators; i++) {
 		rc = rpm_vreg_init_regulator(&platform_data->init_data[i],
@@ -1492,6 +1781,8 @@
 
 	platform_driver_unregister(&rpm_vreg_driver);
 
+	kfree(consumer_map);
+
 	for (i = 0; i < config->vregs_len; i++)
 		mutex_destroy(&config->vregs[i].pc_lock);
 }
diff --git a/arch/arm/mach-msm/rpm-smd.c b/arch/arm/mach-msm/rpm-smd.c
new file mode 100644
index 0000000..75f4d92
--- /dev/null
+++ b/arch/arm/mach-msm/rpm-smd.c
@@ -0,0 +1,826 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/bug.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/notifier.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <mach/socinfo.h>
+#include <mach/msm_smd.h>
+#include <mach/rpm-smd.h>
+#include "rpm-notifier.h"
+
+struct msm_rpm_driver_data {
+	const char *ch_name;
+	uint32_t ch_type;
+	smd_channel_t *ch_info;
+	struct work_struct work;
+	spinlock_t smd_lock_write;
+	spinlock_t smd_lock_read;
+	struct completion smd_open;
+};
+
+#define DEFAULT_BUFFER_SIZE 256
+#define GFP_FLAG(noirq) (noirq ? GFP_ATOMIC : GFP_KERNEL)
+#define INV_HDR "resource does not exist"
+#define ERR "err\0"
+#define MAX_ERR_BUFFER_SIZE 60
+
+static struct atomic_notifier_head msm_rpm_sleep_notifier;
+static bool standalone;
+
+int msm_rpm_register_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_register(&msm_rpm_sleep_notifier, nb);
+}
+
+int msm_rpm_unregister_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_unregister(&msm_rpm_sleep_notifier, nb);
+}
+
+static struct workqueue_struct *msm_rpm_smd_wq;
+
+enum {
+	MSM_RPM_MSG_REQUEST_TYPE = 0,
+	MSM_RPM_MSG_TYPE_NR,
+};
+
+static const uint32_t msm_rpm_request_service[MSM_RPM_MSG_TYPE_NR] = {
+	0x716572, /* 'req\0' */
+};
+
+/*the order of fields matter and reflect the order expected by the RPM*/
+struct rpm_request_header {
+	uint32_t service_type;
+	uint32_t request_len;
+};
+
+struct rpm_message_header {
+	uint32_t msg_id;
+	enum msm_rpm_set set;
+	uint32_t resource_type;
+	uint32_t resource_id;
+	uint32_t data_len;
+};
+
+struct msm_rpm_kvp_data {
+	uint32_t key;
+	uint32_t nbytes; /* number of bytes */
+	uint8_t *value;
+	bool valid;
+};
+
+static atomic_t msm_rpm_msg_id = ATOMIC_INIT(0);
+
+static struct msm_rpm_driver_data msm_rpm_data;
+
+struct msm_rpm_request {
+	struct rpm_request_header req_hdr;
+	struct rpm_message_header msg_hdr;
+	struct msm_rpm_kvp_data *kvp;
+	uint32_t num_elements;
+	uint32_t write_idx;
+	uint8_t *buf;
+	uint32_t numbytes;
+};
+
+/*
+ * Data related to message acknowledgement
+ */
+
+LIST_HEAD(msm_rpm_wait_list);
+
+struct msm_rpm_wait_data {
+	struct list_head list;
+	uint32_t msg_id;
+	bool ack_recd;
+	int errno;
+	struct completion ack;
+};
+DEFINE_SPINLOCK(msm_rpm_list_lock);
+
+struct msm_rpm_ack_msg {
+	uint32_t req;
+	uint32_t req_len;
+	uint32_t rsc_id;
+	uint32_t msg_len;
+	uint32_t id_ack;
+};
+
+static int irq_process;
+
+LIST_HEAD(msm_rpm_ack_list);
+
+static void msm_rpm_notify_sleep_chain(struct rpm_message_header *hdr,
+		struct msm_rpm_kvp_data *kvp)
+{
+	struct msm_rpm_notifier_data notif;
+
+	notif.rsc_type = hdr->resource_type;
+	notif.rsc_id = hdr->resource_id;
+	notif.key = kvp->key;
+	notif.size = kvp->nbytes;
+	notif.value = kvp->value;
+	atomic_notifier_call_chain(&msm_rpm_sleep_notifier, 0, &notif);
+}
+
+static int msm_rpm_add_kvp_data_common(struct msm_rpm_request *handle,
+		uint32_t key, const uint8_t *data, int size, bool noirq)
+{
+	int i;
+	int data_size, msg_size;
+
+	if (!handle)
+		return -EINVAL;
+
+	data_size = ALIGN(size, SZ_4);
+	msg_size = data_size + sizeof(struct rpm_request_header);
+
+	for (i = 0; i < handle->write_idx; i++) {
+		if (handle->kvp[i].key != key)
+			continue;
+		if (handle->kvp[i].nbytes != data_size) {
+			kfree(handle->kvp[i].value);
+			handle->kvp[i].value = NULL;
+		} else {
+			if (!memcmp(handle->kvp[i].value, data, data_size))
+				return 0;
+		}
+		break;
+	}
+
+	if (i >= handle->num_elements)
+		return -ENOMEM;
+
+	if (i == handle->write_idx)
+		handle->write_idx++;
+
+	if (!handle->kvp[i].value) {
+		handle->kvp[i].value = kzalloc(data_size, GFP_FLAG(noirq));
+
+		if (!handle->kvp[i].value)
+			return -ENOMEM;
+	} else {
+		/* We enter the else case, if a key already exists but the
+		 * data doesn't match. In which case, we should zero the data
+		 * out.
+		 */
+		memset(handle->kvp[i].value, 0, data_size);
+	}
+
+	if (!handle->kvp[i].valid)
+		handle->msg_hdr.data_len += msg_size;
+	else
+		handle->msg_hdr.data_len += (data_size - handle->kvp[i].nbytes);
+
+	handle->kvp[i].nbytes = data_size;
+	handle->kvp[i].key = key;
+	memcpy(handle->kvp[i].value, data, size);
+	handle->kvp[i].valid = true;
+
+	if (handle->msg_hdr.set == MSM_RPM_CTX_SLEEP_SET)
+		msm_rpm_notify_sleep_chain(&handle->msg_hdr, &handle->kvp[i]);
+
+	return 0;
+
+}
+
+static struct msm_rpm_request *msm_rpm_create_request_common(
+		enum msm_rpm_set set, uint32_t rsc_type, uint32_t rsc_id,
+		int num_elements, bool noirq)
+{
+	struct msm_rpm_request *cdata;
+
+	cdata = kzalloc(sizeof(struct msm_rpm_request),
+			GFP_FLAG(noirq));
+
+	if (!cdata) {
+		printk(KERN_INFO"%s():Cannot allocate memory for client data\n",
+				__func__);
+		goto cdata_alloc_fail;
+	}
+
+	cdata->msg_hdr.set = set;
+	cdata->msg_hdr.resource_type = rsc_type;
+	cdata->msg_hdr.resource_id = rsc_id;
+	cdata->msg_hdr.data_len = 0;
+
+	cdata->num_elements = num_elements;
+	cdata->write_idx = 0;
+
+	cdata->kvp = kzalloc(sizeof(struct msm_rpm_kvp_data) * num_elements,
+			GFP_FLAG(noirq));
+
+	if (!cdata->kvp) {
+		pr_warn("%s(): Cannot allocate memory for key value data\n",
+				__func__);
+		goto kvp_alloc_fail;
+	}
+
+	cdata->buf = kzalloc(DEFAULT_BUFFER_SIZE, GFP_FLAG(noirq));
+
+	if (!cdata->buf)
+		goto buf_alloc_fail;
+
+	cdata->numbytes = DEFAULT_BUFFER_SIZE;
+	return cdata;
+
+buf_alloc_fail:
+	kfree(cdata->kvp);
+kvp_alloc_fail:
+	kfree(cdata);
+cdata_alloc_fail:
+	return NULL;
+
+}
+
+void msm_rpm_free_request(struct msm_rpm_request *handle)
+{
+	int i;
+
+	if (!handle)
+		return;
+	for (i = 0; i < handle->write_idx; i++)
+		kfree(handle->kvp[i].value);
+	kfree(handle->kvp);
+	kfree(handle);
+}
+EXPORT_SYMBOL(msm_rpm_free_request);
+
+struct msm_rpm_request *msm_rpm_create_request(
+		enum msm_rpm_set set, uint32_t rsc_type,
+		uint32_t rsc_id, int num_elements)
+{
+	return msm_rpm_create_request_common(set, rsc_type, rsc_id,
+			num_elements, false);
+}
+EXPORT_SYMBOL(msm_rpm_create_request);
+
+struct msm_rpm_request *msm_rpm_create_request_noirq(
+		enum msm_rpm_set set, uint32_t rsc_type,
+		uint32_t rsc_id, int num_elements)
+{
+	return msm_rpm_create_request_common(set, rsc_type, rsc_id,
+			num_elements, true);
+}
+EXPORT_SYMBOL(msm_rpm_create_request_noirq);
+
+int msm_rpm_add_kvp_data(struct msm_rpm_request *handle,
+		uint32_t key, const uint8_t *data, int size)
+{
+	return msm_rpm_add_kvp_data_common(handle, key, data, size, false);
+
+}
+EXPORT_SYMBOL(msm_rpm_add_kvp_data);
+
+int msm_rpm_add_kvp_data_noirq(struct msm_rpm_request *handle,
+		uint32_t key, const uint8_t *data, int size)
+{
+	return msm_rpm_add_kvp_data_common(handle, key, data, size, true);
+}
+EXPORT_SYMBOL(msm_rpm_add_kvp_data_noirq);
+
+/* Runs in interrupt context */
+static void msm_rpm_notify(void *data, unsigned event)
+{
+	struct msm_rpm_driver_data *pdata = (struct msm_rpm_driver_data *)data;
+	BUG_ON(!pdata);
+
+	if (!(pdata->ch_info))
+		return;
+
+	switch (event) {
+	case SMD_EVENT_DATA:
+		queue_work(msm_rpm_smd_wq, &pdata->work);
+		break;
+	case SMD_EVENT_OPEN:
+		complete(&pdata->smd_open);
+		break;
+	case SMD_EVENT_CLOSE:
+	case SMD_EVENT_STATUS:
+	case SMD_EVENT_REOPEN_READY:
+		break;
+	default:
+		pr_info("Unknown SMD event\n");
+
+	}
+}
+
+static struct msm_rpm_wait_data *msm_rpm_get_entry_from_msg_id(uint32_t msg_id)
+{
+	struct list_head *ptr;
+	struct msm_rpm_wait_data *elem;
+	unsigned long flags;
+
+	spin_lock_irqsave(&msm_rpm_list_lock, flags);
+
+	list_for_each(ptr, &msm_rpm_wait_list) {
+		elem = list_entry(ptr, struct msm_rpm_wait_data, list);
+		if (elem && (elem->msg_id == msg_id))
+			break;
+		elem = NULL;
+	}
+	spin_unlock_irqrestore(&msm_rpm_list_lock, flags);
+	return elem;
+}
+
+static int msm_rpm_get_next_msg_id(void)
+{
+	int id;
+
+	do {
+		id = atomic_inc_return(&msm_rpm_msg_id);
+	} while ((id == 0) || msm_rpm_get_entry_from_msg_id(id));
+
+	return id;
+}
+
+static int msm_rpm_add_wait_list(uint32_t msg_id)
+{
+	unsigned long flags;
+	struct msm_rpm_wait_data *data =
+		kzalloc(sizeof(struct msm_rpm_wait_data), GFP_ATOMIC);
+
+	if (!data)
+		return -ENOMEM;
+
+	init_completion(&data->ack);
+	data->ack_recd = false;
+	data->msg_id = msg_id;
+	spin_lock_irqsave(&msm_rpm_list_lock, flags);
+	list_add(&data->list, &msm_rpm_wait_list);
+	spin_unlock_irqrestore(&msm_rpm_list_lock, flags);
+
+	return 0;
+}
+
+static void msm_rpm_free_list_entry(struct msm_rpm_wait_data *elem)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&msm_rpm_list_lock, flags);
+	list_del(&elem->list);
+	spin_unlock_irqrestore(&msm_rpm_list_lock, flags);
+	kfree(elem);
+}
+
+static void msm_rpm_process_ack(uint32_t msg_id, int errno)
+{
+	struct list_head *ptr;
+	struct msm_rpm_wait_data *elem;
+	unsigned long flags;
+
+	spin_lock_irqsave(&msm_rpm_list_lock, flags);
+
+	list_for_each(ptr, &msm_rpm_wait_list) {
+		elem = list_entry(ptr, struct msm_rpm_wait_data, list);
+		if (elem && (elem->msg_id == msg_id)) {
+			elem->errno = errno;
+			elem->ack_recd = true;
+			complete(&elem->ack);
+			break;
+		}
+		elem = NULL;
+	}
+	WARN_ON(!elem);
+
+	spin_unlock_irqrestore(&msm_rpm_list_lock, flags);
+}
+
+struct msm_rpm_kvp_packet {
+	uint32_t id;
+	uint32_t len;
+	uint32_t val;
+};
+
+static inline uint32_t msm_rpm_get_msg_id_from_ack(uint8_t *buf)
+{
+	return ((struct msm_rpm_ack_msg *)buf)->id_ack;
+}
+
+static inline int msm_rpm_get_error_from_ack(uint8_t *buf)
+{
+	uint8_t *tmp;
+	uint32_t req_len = ((struct msm_rpm_ack_msg *)buf)->req_len;
+
+	int rc = -ENODEV;
+
+	req_len -= sizeof(struct msm_rpm_ack_msg);
+	req_len += 2 * sizeof(uint32_t);
+	if (!req_len)
+		return 0;
+
+	tmp = buf + sizeof(struct msm_rpm_ack_msg);
+
+	BUG_ON(memcmp(tmp, ERR, sizeof(uint32_t)));
+
+	tmp += 2 * sizeof(uint32_t);
+
+	if (!(memcmp(tmp, INV_HDR, min(req_len, sizeof(INV_HDR))-1)))
+		rc = -EINVAL;
+
+	return rc;
+}
+
+static void msm_rpm_read_smd_data(char *buf)
+{
+	int pkt_sz;
+	int bytes_read = 0;
+
+	pkt_sz = smd_cur_packet_size(msm_rpm_data.ch_info);
+
+	BUG_ON(pkt_sz > MAX_ERR_BUFFER_SIZE);
+
+	if (pkt_sz != smd_read_avail(msm_rpm_data.ch_info))
+		return;
+
+	BUG_ON(pkt_sz == 0);
+
+	do {
+		int len;
+
+		len = smd_read(msm_rpm_data.ch_info, buf + bytes_read, pkt_sz);
+		pkt_sz -= len;
+		bytes_read += len;
+
+	} while (pkt_sz > 0);
+
+	BUG_ON(pkt_sz < 0);
+}
+
+static void msm_rpm_smd_work(struct work_struct *work)
+{
+	uint32_t msg_id;
+	int errno;
+	char buf[MAX_ERR_BUFFER_SIZE] = {0};
+	unsigned long flags;
+
+	while (smd_is_pkt_avail(msm_rpm_data.ch_info) && !irq_process) {
+		spin_lock_irqsave(&msm_rpm_data.smd_lock_read, flags);
+		msm_rpm_read_smd_data(buf);
+		spin_unlock_irqrestore(&msm_rpm_data.smd_lock_read, flags);
+		msg_id = msm_rpm_get_msg_id_from_ack(buf);
+		errno = msm_rpm_get_error_from_ack(buf);
+		msm_rpm_process_ack(msg_id, errno);
+	}
+}
+
+static int msm_rpm_send_data(struct msm_rpm_request *cdata,
+		int msg_type, bool noirq)
+{
+	uint8_t *tmpbuff;
+	int i, ret, msg_size;
+	unsigned long flags;
+
+	int req_hdr_sz, msg_hdr_sz;
+
+	if (!cdata->msg_hdr.data_len)
+		return 0;
+	req_hdr_sz = sizeof(cdata->req_hdr);
+	msg_hdr_sz = sizeof(cdata->msg_hdr);
+
+	cdata->req_hdr.service_type = msm_rpm_request_service[msg_type];
+
+	cdata->msg_hdr.msg_id = msm_rpm_get_next_msg_id();
+
+	cdata->req_hdr.request_len = cdata->msg_hdr.data_len + msg_hdr_sz;
+	msg_size = cdata->req_hdr.request_len + req_hdr_sz;
+
+	/* populate data_len */
+	if (msg_size > cdata->numbytes) {
+		kfree(cdata->buf);
+		cdata->numbytes = msg_size;
+		cdata->buf = kzalloc(msg_size, GFP_FLAG(noirq));
+	}
+
+	if (!cdata->buf)
+		return 0;
+
+	tmpbuff = cdata->buf;
+
+	memcpy(tmpbuff, &cdata->req_hdr, req_hdr_sz + msg_hdr_sz);
+
+	tmpbuff += req_hdr_sz + msg_hdr_sz;
+
+	for (i = 0; (i < cdata->write_idx); i++) {
+		/* Sanity check */
+		BUG_ON((tmpbuff - cdata->buf) > cdata->numbytes);
+
+		if (!cdata->kvp[i].valid)
+			continue;
+
+		memcpy(tmpbuff, &cdata->kvp[i].key, sizeof(uint32_t));
+		tmpbuff += sizeof(uint32_t);
+
+		memcpy(tmpbuff, &cdata->kvp[i].nbytes, sizeof(uint32_t));
+		tmpbuff += sizeof(uint32_t);
+
+		memcpy(tmpbuff, cdata->kvp[i].value, cdata->kvp[i].nbytes);
+		tmpbuff += cdata->kvp[i].nbytes;
+	}
+
+	if (standalone) {
+		for (i = 0; (i < cdata->write_idx); i++)
+			cdata->kvp[i].valid = false;
+
+		cdata->msg_hdr.data_len = 0;
+		ret = cdata->msg_hdr.msg_id;
+		return ret;
+	}
+
+	msm_rpm_add_wait_list(cdata->msg_hdr.msg_id);
+
+	spin_lock_irqsave(&msm_rpm_data.smd_lock_write, flags);
+
+	ret = smd_write_avail(msm_rpm_data.ch_info);
+
+	if (ret < 0) {
+		pr_warn("%s(): SMD not initialized\n", __func__);
+		spin_unlock_irqrestore(&msm_rpm_data.smd_lock_write, flags);
+		return 0;
+	}
+
+	while ((ret < msg_size)) {
+		if (!noirq) {
+			spin_unlock_irqrestore(&msm_rpm_data.smd_lock_write,
+					flags);
+			cpu_relax();
+			spin_lock_irqsave(&msm_rpm_data.smd_lock_write, flags);
+		} else
+			udelay(5);
+		ret = smd_write_avail(msm_rpm_data.ch_info);
+	}
+
+	ret = smd_write(msm_rpm_data.ch_info, &cdata->buf[0], msg_size);
+	spin_unlock_irqrestore(&msm_rpm_data.smd_lock_write, flags);
+
+	if (ret == msg_size) {
+		for (i = 0; (i < cdata->write_idx); i++)
+			cdata->kvp[i].valid = false;
+		cdata->msg_hdr.data_len = 0;
+		ret = cdata->msg_hdr.msg_id;
+	} else if (ret < msg_size) {
+		struct msm_rpm_wait_data *rc;
+		ret = 0;
+		pr_info("Failed to write data msg_size:%d ret:%d\n",
+				msg_size, ret);
+		rc = msm_rpm_get_entry_from_msg_id(cdata->msg_hdr.msg_id);
+		if (rc)
+			msm_rpm_free_list_entry(rc);
+	}
+	return ret;
+}
+
+int msm_rpm_send_request(struct msm_rpm_request *handle)
+{
+	return msm_rpm_send_data(handle, MSM_RPM_MSG_REQUEST_TYPE, false);
+}
+EXPORT_SYMBOL(msm_rpm_send_request);
+
+int msm_rpm_send_request_noirq(struct msm_rpm_request *handle)
+{
+	return msm_rpm_send_data(handle, MSM_RPM_MSG_REQUEST_TYPE, true);
+}
+EXPORT_SYMBOL(msm_rpm_send_request_noirq);
+
+int msm_rpm_wait_for_ack(uint32_t msg_id)
+{
+	struct msm_rpm_wait_data *elem;
+	int rc = 0;
+
+	if (!msg_id)
+		return -EINVAL;
+
+	if (standalone)
+		return 0;
+
+	elem = msm_rpm_get_entry_from_msg_id(msg_id);
+	if (!elem)
+		return 0;
+
+	rc = wait_for_completion_timeout(&elem->ack, msecs_to_jiffies(1));
+	if (!rc) {
+		pr_warn("%s(): Timed out after 1 ms\n", __func__);
+		rc = -ETIMEDOUT;
+	} else {
+		rc = elem->errno;
+		msm_rpm_free_list_entry(elem);
+	}
+	return rc;
+}
+EXPORT_SYMBOL(msm_rpm_wait_for_ack);
+
+int msm_rpm_wait_for_ack_noirq(uint32_t msg_id)
+{
+	struct msm_rpm_wait_data *elem;
+	unsigned long flags;
+	int rc = 0;
+	uint32_t id = 0;
+	int count = 0;
+
+	if (!msg_id)
+		return -EINVAL;
+
+	if (standalone)
+		return 0;
+
+	spin_lock_irqsave(&msm_rpm_data.smd_lock_read, flags);
+	irq_process = true;
+
+	elem = msm_rpm_get_entry_from_msg_id(msg_id);
+
+	if (!elem)
+		/* Should this be a bug
+		 * Is it ok for another thread to read the msg?
+		 */
+		goto wait_ack_cleanup;
+
+	while ((id != msg_id) && (count++ < 10)) {
+		if (smd_is_pkt_avail(msm_rpm_data.ch_info)) {
+			int errno;
+			char buf[MAX_ERR_BUFFER_SIZE] = {};
+
+			msm_rpm_read_smd_data(buf);
+			id = msm_rpm_get_msg_id_from_ack(buf);
+			errno = msm_rpm_get_error_from_ack(buf);
+			msm_rpm_process_ack(id, errno);
+		} else
+			udelay(100);
+	}
+
+	if (count == 10) {
+		rc = -ETIMEDOUT;
+		pr_warn("%s(): Timed out after 1ms\n", __func__);
+	} else {
+		rc = elem->errno;
+		msm_rpm_free_list_entry(elem);
+	}
+wait_ack_cleanup:
+	irq_process = false;
+	spin_unlock_irqrestore(&msm_rpm_data.smd_lock_read, flags);
+	return rc;
+}
+EXPORT_SYMBOL(msm_rpm_wait_for_ack_noirq);
+
+int msm_rpm_send_message(enum msm_rpm_set set, uint32_t rsc_type,
+		uint32_t rsc_id, struct msm_rpm_kvp *kvp, int nelems)
+{
+	int i, rc;
+	struct msm_rpm_request *req =
+		msm_rpm_create_request(set, rsc_type, rsc_id, nelems);
+	if (!req)
+		return -ENOMEM;
+
+	for (i = 0; i < nelems; i++) {
+		rc = msm_rpm_add_kvp_data(req, kvp[i].key,
+				kvp[i].data, kvp[i].length);
+		if (rc)
+			goto bail;
+	}
+
+	rc = msm_rpm_wait_for_ack(msm_rpm_send_request(req));
+bail:
+	msm_rpm_free_request(req);
+	return rc;
+}
+EXPORT_SYMBOL(msm_rpm_send_message);
+
+int msm_rpm_send_message_noirq(enum msm_rpm_set set, uint32_t rsc_type,
+		uint32_t rsc_id, struct msm_rpm_kvp *kvp, int nelems)
+{
+	int i, rc;
+	struct msm_rpm_request *req =
+		msm_rpm_create_request_noirq(set, rsc_type, rsc_id, nelems);
+	if (!req)
+		return -ENOMEM;
+
+	for (i = 0; i < nelems; i++) {
+		rc = msm_rpm_add_kvp_data_noirq(req, kvp[i].key,
+					kvp[i].data, kvp[i].length);
+		if (rc)
+			goto bail;
+	}
+
+	rc = msm_rpm_wait_for_ack_noirq(msm_rpm_send_request_noirq(req));
+bail:
+	msm_rpm_free_request(req);
+	return rc;
+}
+EXPORT_SYMBOL(msm_rpm_send_message_noirq);
+static bool msm_rpm_set_standalone(void)
+{
+	if (machine_is_copper()) {
+		pr_warn("%s(): Running in standalone mode, requests "
+				"will not be sent to RPM\n", __func__);
+		standalone = true;
+	}
+	return standalone;
+}
+
+static int __devinit msm_rpm_dev_probe(struct platform_device *pdev)
+{
+	char *key = NULL;
+	int ret;
+
+	key = "rpm-channel-name";
+	ret = of_property_read_string(pdev->dev.of_node, key,
+					&msm_rpm_data.ch_name);
+	if (ret)
+		goto fail;
+
+	key = "rpm-channel-type";
+	ret = of_property_read_u32(pdev->dev.of_node, key,
+					&msm_rpm_data.ch_type);
+	if (ret)
+		goto fail;
+
+	init_completion(&msm_rpm_data.smd_open);
+	spin_lock_init(&msm_rpm_data.smd_lock_write);
+	spin_lock_init(&msm_rpm_data.smd_lock_read);
+	INIT_WORK(&msm_rpm_data.work, msm_rpm_smd_work);
+
+	if (smd_named_open_on_edge(msm_rpm_data.ch_name, msm_rpm_data.ch_type,
+				&msm_rpm_data.ch_info, &msm_rpm_data,
+				msm_rpm_notify)) {
+		pr_info("Cannot open RPM channel %s %d\n", msm_rpm_data.ch_name,
+				msm_rpm_data.ch_type);
+
+		msm_rpm_set_standalone();
+		BUG_ON(!standalone);
+		complete(&msm_rpm_data.smd_open);
+	}
+
+	ret = wait_for_completion_timeout(&msm_rpm_data.smd_open,
+			msecs_to_jiffies(5));
+
+	BUG_ON(!ret);
+
+	smd_disable_read_intr(msm_rpm_data.ch_info);
+
+	if (!standalone) {
+		msm_rpm_smd_wq = create_singlethread_workqueue("rpm-smd");
+		if (!msm_rpm_smd_wq)
+			return -EINVAL;
+	}
+
+	of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+	return 0;
+fail:
+	pr_err("%s(): Failed to read node: %s, key=%s\n", __func__,
+			pdev->dev.of_node->full_name, key);
+	return -EINVAL;
+}
+
+static struct of_device_id msm_rpm_match_table[] =  {
+	{.compatible = "qcom,rpm-smd"},
+	{},
+};
+
+static struct platform_driver msm_rpm_device_driver = {
+	.probe = msm_rpm_dev_probe,
+	.driver = {
+		.name = "rpm-smd",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_rpm_match_table,
+	},
+};
+
+int __init msm_rpm_driver_init(void)
+{
+	static bool registered;
+
+	if (registered)
+		return 0;
+	registered = true;
+
+	return platform_driver_register(&msm_rpm_device_driver);
+}
+EXPORT_SYMBOL(msm_rpm_driver_init);
+late_initcall(msm_rpm_driver_init);
diff --git a/arch/arm/mach-msm/rpm_resources.c b/arch/arm/mach-msm/rpm_resources.c
index 7daea5c..5314cee 100644
--- a/arch/arm/mach-msm/rpm_resources.c
+++ b/arch/arm/mach-msm/rpm_resources.c
@@ -867,15 +867,16 @@
 	spin_unlock_irqrestore(&msm_rpmrs_lock, flags);
 }
 
-struct msm_rpmrs_limits *msm_rpmrs_lowest_limits(
-	bool from_idle, enum msm_pm_sleep_mode sleep_mode, uint32_t latency_us,
-	uint32_t sleep_us)
+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)
 {
 	unsigned int cpu = smp_processor_id();
 	struct msm_rpmrs_level *best_level = NULL;
 	bool irqs_detectable = false;
 	bool gpio_detectable = false;
 	int i;
+	uint32_t pwr;
 
 	if (sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE) {
 		irqs_detectable = msm_mpm_irqs_detectable(from_idle);
@@ -884,7 +885,6 @@
 
 	for (i = 0; i < msm_rpmrs_level_count; i++) {
 		struct msm_rpmrs_level *level = &msm_rpmrs_levels[i];
-		uint32_t power;
 
 		if (!level->available)
 			continue;
@@ -902,31 +902,38 @@
 					irqs_detectable, gpio_detectable))
 			continue;
 
+		if (MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE == sleep_mode)
+			if (!cpu && msm_rpm_local_request_is_outstanding())
+					break;
+
+
 		if (sleep_us <= 1) {
-			power = level->energy_overhead;
+			pwr = level->energy_overhead;
 		} else if (sleep_us <= level->time_overhead_us) {
-			power = level->energy_overhead / sleep_us;
+			pwr = level->energy_overhead / sleep_us;
 		} else if ((sleep_us >> 10) > level->time_overhead_us) {
-			power = level->steady_state_power;
+			pwr = level->steady_state_power;
 		} else {
-			power = level->steady_state_power;
-			power -= (level->time_overhead_us *
+			pwr = level->steady_state_power;
+			pwr -= (level->time_overhead_us *
 					level->steady_state_power)/sleep_us;
-			power += level->energy_overhead / sleep_us;
+			pwr += level->energy_overhead / sleep_us;
 		}
 
 		if (!best_level ||
-				best_level->rs_limits.power[cpu] >= power) {
+				best_level->rs_limits.power[cpu] >= pwr) {
 			level->rs_limits.latency_us[cpu] = level->latency_us;
-			level->rs_limits.power[cpu] = power;
+			level->rs_limits.power[cpu] = pwr;
 			best_level = level;
+			if (power)
+				*power = pwr;
 		}
 	}
 
 	return best_level ? &best_level->rs_limits : NULL;
 }
 
-int msm_rpmrs_enter_sleep(uint32_t sclk_count, struct msm_rpmrs_limits *limits,
+static int msm_rpmrs_enter_sleep(uint32_t sclk_count, void *limits,
 		bool from_idle, bool notify_rpm)
 {
 	int rc = 0;
@@ -944,7 +951,7 @@
 	return rc;
 }
 
-void msm_rpmrs_exit_sleep(struct msm_rpmrs_limits *limits, bool from_idle,
+static void msm_rpmrs_exit_sleep(void *limits, bool from_idle,
 		bool notify_rpm, bool collapsed)
 {
 
@@ -1067,6 +1074,12 @@
 }
 device_initcall(msm_rpmrs_init);
 
+static struct msm_pm_sleep_ops msm_rpmrs_ops = {
+	.lowest_limits = msm_rpmrs_lowest_limits,
+	.enter_sleep = msm_rpmrs_enter_sleep,
+	.exit_sleep = msm_rpmrs_exit_sleep,
+};
+
 static int __init msm_rpmrs_l2_init(void)
 {
 	if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_apq8064()) {
@@ -1085,6 +1098,9 @@
 		msm_rpmrs_l2_cache.aggregate = NULL;
 		msm_rpmrs_l2_cache.restore = NULL;
 	}
+
+	msm_pm_set_sleep_ops(&msm_rpmrs_ops);
+
 	return 0;
 }
 early_initcall(msm_rpmrs_l2_init);
diff --git a/arch/arm/mach-msm/rpm_resources.h b/arch/arm/mach-msm/rpm_resources.h
index a5c61b2..d594405 100644
--- a/arch/arm/mach-msm/rpm_resources.h
+++ b/arch/arm/mach-msm/rpm_resources.h
@@ -137,16 +137,6 @@
 }
 
 void msm_rpmrs_show_resources(void);
-
-struct msm_rpmrs_limits *msm_rpmrs_lowest_limits(
-	bool from_idle, enum msm_pm_sleep_mode sleep_mode, uint32_t latency_us,
-	uint32_t sleep_us);
-
-int msm_rpmrs_enter_sleep(uint32_t sclk_count, struct msm_rpmrs_limits *limits,
-		bool from_idle, bool notify_rpm);
-void msm_rpmrs_exit_sleep(struct msm_rpmrs_limits *limits, bool from_idle,
-		bool notify_rpm, bool collapsed);
-
 int msm_rpmrs_levels_init(struct msm_rpmrs_platform_data *data);
 
 #endif /* __ARCH_ARM_MACH_MSM_RPM_RESOURCES_H */
diff --git a/arch/arm/mach-msm/sdio_al_dloader.c b/arch/arm/mach-msm/sdio_al_dloader.c
index 74b8478..f48c32b 100644
--- a/arch/arm/mach-msm/sdio_al_dloader.c
+++ b/arch/arm/mach-msm/sdio_al_dloader.c
@@ -1140,14 +1140,6 @@
 		return status;
 	}
 
-	status = sdio_dld_create_thread();
-	if (status) {
-		sdio_dld_dealloc_local_buffers();
-		pr_err(MODULE_NAME ": %s, failed in sdio_dld_create_thread()."
-				   "status=%d\n", __func__, status);
-		return status;
-	}
-
 	/* init waiting event of the write callback */
 	init_waitqueue_head(&sdio_dld->write_callback_event.wait_event);
 
@@ -1168,6 +1160,15 @@
 	sdio_dld->push_timer.data = (unsigned long) sdio_dld;
 	sdio_dld->push_timer.function = sdio_dld_push_timer_handler;
 
+	status = sdio_dld_create_thread();
+	if (status) {
+		del_timer_sync(&sdio_dld->timer);
+		del_timer_sync(&sdio_dld->push_timer);
+		sdio_dld_dealloc_local_buffers();
+		pr_err(MODULE_NAME ": %s, failed in sdio_dld_create_thread()."
+				   "status=%d\n", __func__, status);
+		return status;
+	}
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/smd_pkt.c b/arch/arm/mach-msm/smd_pkt.c
index abcd336..b9cba8c 100644
--- a/arch/arm/mach-msm/smd_pkt.c
+++ b/arch/arm/mach-msm/smd_pkt.c
@@ -40,7 +40,7 @@
 #ifdef CONFIG_ARCH_FSM9XXX
 #define NUM_SMD_PKT_PORTS 4
 #else
-#define NUM_SMD_PKT_PORTS 14
+#define NUM_SMD_PKT_PORTS 15
 #endif
 
 #define LOOPBACK_INX (NUM_SMD_PKT_PORTS - 1)
@@ -677,6 +677,7 @@
 	"apr_apps2",
 	"smdcntl8",
 	"smd_sns_adsp",
+	"smd_cxm_qmi",
 	"smd_pkt_loopback",
 };
 
@@ -694,6 +695,7 @@
 	"apr_apps2",
 	"DATA40_CNTL",
 	"SENSOR",
+	"CXM_QMI_PORT_8064",
 	"LOOPBACK",
 };
 
@@ -711,6 +713,7 @@
 	SMD_APPS_QDSP,
 	SMD_APPS_MODEM,
 	SMD_APPS_QDSP,
+	SMD_APPS_WCNSS,
 	SMD_APPS_MODEM,
 };
 #endif
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index d811f71..b047cf4 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -218,7 +218,6 @@
 
 	/* 8064 IDs */
 	[109] = MSM_CPU_8064,
-	[130] = MSM_CPU_8064,
 
 	/* 8930 IDs */
 	[116] = MSM_CPU_8930,
@@ -247,14 +246,17 @@
 	[128] = MSM_CPU_8625,
 	[129] = MSM_CPU_8625,
 
-	/* 9625 IDs */
-	[130] = MSM_CPU_9625,
+	/* 8064 MPQ ID */
+	[130] = MSM_CPU_8064,
 
 	/* 7x25AB IDs */
 	[131] = MSM_CPU_7X25AB,
 	[132] = MSM_CPU_7X25AB,
 	[133] = MSM_CPU_7X25AB,
 
+	/* 9625 IDs */
+	[134] = MSM_CPU_9625,
+
 	/* Uninitialized IDs are not known to run Linux.
 	   MSM_CPU_UNKNOWN is set to 0 to ensure these IDs are
 	   considered as unknown CPU. */
@@ -625,7 +627,7 @@
 		strlcpy(dummy_socinfo.build_id, "copper - ",
 			sizeof(dummy_socinfo.build_id));
 	} else if (early_machine_is_msm9625()) {
-		dummy_socinfo.id = 130;
+		dummy_socinfo.id = 134;
 		strlcpy(dummy_socinfo.build_id, "msm9625 - ",
 			sizeof(dummy_socinfo.build_id));
 	} else if (machine_is_msm8625_rumi3())
diff --git a/arch/arm/mach-msm/subsystem_map.c b/arch/arm/mach-msm/subsystem_map.c
index 4a1285b..916686f 100644
--- a/arch/arm/mach-msm/subsystem_map.c
+++ b/arch/arm/mach-msm/subsystem_map.c
@@ -375,12 +375,13 @@
 			partition_no = msm_subsystem_get_partition_no(
 								subsys_ids[i]);
 
-			iova_start = msm_allocate_iova_address(domain_no,
+			ret = msm_allocate_iova_address(domain_no,
 						partition_no,
 						map_size,
-						max(min_align, SZ_4K));
+						max(min_align, SZ_4K),
+						&iova_start);
 
-			if (!iova_start) {
+			if (ret) {
 				pr_err("%s: could not allocate iova address\n",
 					__func__);
 				continue;
diff --git a/arch/arm/mach-msm/timer.h b/arch/arm/mach-msm/timer.h
index 368dd7b..5d18bb4 100644
--- a/arch/arm/mach-msm/timer.h
+++ b/arch/arm/mach-msm/timer.h
@@ -17,12 +17,12 @@
 extern struct sys_timer msm_timer;
 
 void __iomem *msm_timer_get_timer0_base(void);
-int64_t msm_timer_get_sclk_time(int64_t *period);
 uint32_t msm_timer_get_sclk_ticks(void);
 int msm_timer_init_time_sync(void (*timeout)(void));
 #ifndef CONFIG_ARM_ARCH_TIMER
 int64_t msm_timer_enter_idle(void);
 void msm_timer_exit_idle(int low_power);
+int64_t msm_timer_get_sclk_time(int64_t *period);
 #else
 static inline int64_t msm_timer_enter_idle(void) { return 0; }
 static inline void msm_timer_exit_idle(int low_power) { return; }
diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S
index 404538a..bacba58 100644
--- a/arch/arm/vfp/vfphw.S
+++ b/arch/arm/vfp/vfphw.S
@@ -159,6 +159,22 @@
 	tst	r5, #FPSCR_IXE
 	bne	process_exception
 
+#ifdef CONFIG_ARCH_MSM_KRAIT
+	@ Krait does not set FPEXC.DEX for unsupported short vector instructions
+	mrc     p15, 0, r2, c0, c0, 0
+	ldr     r4, =0xff00fc00
+	and     r4, r2, r4
+	ldr     r2, =0x51000400
+	cmp     r2, r4
+	bne skip
+
+	tst	r5, #FPSCR_LENGTH_MASK
+	beq	skip
+	orr	r1, r1, #FPEXC_DEX
+	b process_exception
+skip:
+#endif
+
 	@ Fall into hand on to next handler - appropriate coproc instr
 	@ not recognised by VFP
 
diff --git a/block/blk-core.c b/block/blk-core.c
index 35ae52d..a6a8ccb 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -1467,7 +1467,7 @@
 			goto end_io;
 		}
 
-		if (unlikely(!(bio->bi_rw & REQ_DISCARD) &&
+		if (unlikely(!(bio->bi_rw & (REQ_DISCARD | REQ_SANITIZE)) &&
 			     nr_sectors > queue_max_hw_sectors(q))) {
 			printk(KERN_ERR "bio too big device %s (%u > %u)\n",
 			       bdevname(bio->bi_bdev, b),
@@ -1521,6 +1521,14 @@
 			goto end_io;
 		}
 
+		if ((bio->bi_rw & REQ_SANITIZE) &&
+		    (!blk_queue_sanitize(q))) {
+			pr_info("%s - got a SANITIZE request but the queue "
+			       "doesn't support sanitize requests", __func__);
+			err = -EOPNOTSUPP;
+			goto end_io;
+		}
+
 		if (blk_throtl_bio(q, &bio))
 			goto end_io;
 
@@ -1611,7 +1619,8 @@
 	 * If it's a regular read/write or a barrier with data attached,
 	 * go through the normal accounting stuff before submission.
 	 */
-	if (bio_has_data(bio) && !(rw & REQ_DISCARD)) {
+	if (bio_has_data(bio) &&
+	    (!(rw & (REQ_DISCARD | REQ_SANITIZE)))) {
 		if (rw & WRITE) {
 			count_vm_events(PGPGOUT, count);
 		} else {
@@ -1657,7 +1666,7 @@
  */
 int blk_rq_check_limits(struct request_queue *q, struct request *rq)
 {
-	if (rq->cmd_flags & REQ_DISCARD)
+	if (rq->cmd_flags & (REQ_DISCARD | REQ_SANITIZE))
 		return 0;
 
 	if (blk_rq_sectors(rq) > queue_max_sectors(q) ||
diff --git a/block/blk-lib.c b/block/blk-lib.c
index 78e627e..39a7f25 100644
--- a/block/blk-lib.c
+++ b/block/blk-lib.c
@@ -112,6 +112,57 @@
 EXPORT_SYMBOL(blkdev_issue_discard);
 
 /**
+ * blkdev_issue_sanitize - queue a sanitize request
+ * @bdev:	blockdev to issue sanitize for
+ * @gfp_mask:	memory allocation flags (for bio_alloc)
+ *
+ * Description:
+ *    Issue a sanitize request for the specified block device
+ */
+int blkdev_issue_sanitize(struct block_device *bdev, gfp_t gfp_mask)
+{
+	DECLARE_COMPLETION_ONSTACK(wait);
+	struct request_queue *q = bdev_get_queue(bdev);
+	int type = REQ_WRITE | REQ_SANITIZE;
+	struct bio_batch bb;
+	struct bio *bio;
+	int ret = 0;
+
+	if (!q)
+		return -ENXIO;
+
+	if (!blk_queue_sanitize(q)) {
+		pr_err("%s - card doesn't support sanitize", __func__);
+		return -EOPNOTSUPP;
+	}
+
+	bio = bio_alloc(gfp_mask, 1);
+	if (!bio)
+		return -ENOMEM;
+
+	atomic_set(&bb.done, 1);
+	bb.flags = 1 << BIO_UPTODATE;
+	bb.wait = &wait;
+
+	bio->bi_end_io = bio_batch_end_io;
+	bio->bi_bdev = bdev;
+	bio->bi_private = &bb;
+
+	atomic_inc(&bb.done);
+	submit_bio(type, bio);
+
+	/* Wait for bios in-flight */
+	if (!atomic_dec_and_test(&bb.done))
+		wait_for_completion(&wait);
+
+	if (!test_bit(BIO_UPTODATE, &bb.flags))
+		ret = -EIO;
+
+	return ret;
+}
+EXPORT_SYMBOL(blkdev_issue_sanitize);
+
+/**
  * blkdev_issue_zeroout - generate number of zero filed write bios
  * @bdev:	blockdev to issue
  * @sector:	start sector
diff --git a/block/blk-merge.c b/block/blk-merge.c
index cfcc37c..f3ed15b 100644
--- a/block/blk-merge.c
+++ b/block/blk-merge.c
@@ -383,6 +383,12 @@
 		return 0;
 
 	/*
+	 * Don't merge file system requests and sanitize requests
+	 */
+	if ((req->cmd_flags & REQ_SANITIZE) != (next->cmd_flags & REQ_SANITIZE))
+		return 0;
+
+	/*
 	 * not contiguous
 	 */
 	if (blk_rq_pos(req) + blk_rq_sectors(req) != blk_rq_pos(next))
diff --git a/block/elevator.c b/block/elevator.c
index b0b38ce..78a14b5 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -89,6 +89,12 @@
 		return 0;
 
 	/*
+	 * Don't merge sanitize requests
+	 */
+	if ((bio->bi_rw & REQ_SANITIZE) != (rq->bio->bi_rw & REQ_SANITIZE))
+		return 0;
+
+	/*
 	 * different data direction or already started, don't merge
 	 */
 	if (bio_data_dir(bio) != rq_data_dir(rq))
@@ -657,7 +663,7 @@
 	if (rq->cmd_flags & REQ_SOFTBARRIER) {
 		/* barriers are scheduling boundary, update end_sector */
 		if (rq->cmd_type == REQ_TYPE_FS ||
-		    (rq->cmd_flags & REQ_DISCARD)) {
+		    (rq->cmd_flags & (REQ_DISCARD | REQ_SANITIZE))) {
 			q->end_sector = rq_end_sector(rq);
 			q->boundary_rq = rq;
 		}
diff --git a/block/ioctl.c b/block/ioctl.c
index 1124cd2..dbc103b 100644
--- a/block/ioctl.c
+++ b/block/ioctl.c
@@ -131,6 +131,11 @@
 	return blkdev_issue_discard(bdev, start, len, GFP_KERNEL, flags);
 }
 
+static int blk_ioctl_sanitize(struct block_device *bdev)
+{
+	return blkdev_issue_sanitize(bdev, GFP_KERNEL);
+}
+
 static int put_ushort(unsigned long arg, unsigned short val)
 {
 	return put_user(val, (unsigned short __user *)arg);
@@ -215,6 +220,10 @@
 		set_device_ro(bdev, n);
 		return 0;
 
+	case BLKSANITIZE:
+		ret = blk_ioctl_sanitize(bdev);
+		break;
+
 	case BLKDISCARD:
 	case BLKSECDISCARD: {
 		uint64_t range[2];
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 58bf45d..aaa2086 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -132,4 +132,6 @@
 
 source "drivers/clocksource/Kconfig"
 
+source "drivers/gud/Kconfig"
+
 endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 82008ed..13dc06e 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -126,3 +126,6 @@
 obj-y				+= clk/
 
 obj-$(CONFIG_HWSPINLOCK)	+= hwspinlock/
+
+#MobiCore
+obj-$(CONFIG_MOBICORE_SUPPORT)  += gud/
diff --git a/drivers/bluetooth/hci_smd.c b/drivers/bluetooth/hci_smd.c
index 8f51e2d..18cef72 100644
--- a/drivers/bluetooth/hci_smd.c
+++ b/drivers/bluetooth/hci_smd.c
@@ -22,6 +22,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/errno.h>
+#include <linux/semaphore.h>
 #include <linux/string.h>
 #include <linux/skbuff.h>
 #include <linux/wakelock.h>
@@ -43,7 +44,9 @@
 
 
 static int hcismd_set;
-static DEFINE_MUTEX(hci_smd_enable);
+static DEFINE_SEMAPHORE(hci_smd_enable);
+
+static int restart_in_progress;
 
 static int hcismd_set_enable(const char *val, struct kernel_param *kp);
 module_param_call(hcismd_set, hcismd_set_enable, NULL, &hcismd_set, 0644);
@@ -496,18 +499,24 @@
 
 static void hci_dev_restart(struct work_struct *worker)
 {
-	mutex_lock(&hci_smd_enable);
+	down(&hci_smd_enable);
+	restart_in_progress = 1;
 	hci_smd_deregister_dev(&hs);
 	hci_smd_register_smd(&hs);
-	mutex_unlock(&hci_smd_enable);
+	up(&hci_smd_enable);
 	kfree(worker);
 }
 
 static void hci_dev_smd_open(struct work_struct *worker)
 {
-	mutex_lock(&hci_smd_enable);
+	down(&hci_smd_enable);
+	if (restart_in_progress == 1) {
+		/* Allow wcnss to initialize */
+		restart_in_progress = 0;
+		msleep(10000);
+	}
 	hci_smd_hci_register_dev(&hs);
-	mutex_unlock(&hci_smd_enable);
+	up(&hci_smd_enable);
 	kfree(worker);
 }
 
@@ -515,7 +524,9 @@
 {
 	int ret = 0;
 
-	mutex_lock(&hci_smd_enable);
+	pr_err("hcismd_set_enable %d", hcismd_set);
+
+	down(&hci_smd_enable);
 
 	ret = param_set_int(val, kp);
 
@@ -525,7 +536,8 @@
 	switch (hcismd_set) {
 
 	case 1:
-		hci_smd_register_smd(&hs);
+		if (hs.hdev == NULL)
+			hci_smd_register_smd(&hs);
 	break;
 	case 0:
 		hci_smd_deregister_dev(&hs);
@@ -535,7 +547,7 @@
 	}
 
 done:
-	mutex_unlock(&hci_smd_enable);
+	up(&hci_smd_enable);
 	return ret;
 }
 static int  __init hci_smd_init(void)
@@ -544,6 +556,8 @@
 			 "msm_smd_Rx");
 	wake_lock_init(&hs.wake_lock_tx, WAKE_LOCK_SUSPEND,
 			 "msm_smd_Tx");
+	restart_in_progress = 0;
+	hs.hdev = NULL;
 	return 0;
 }
 module_init(hci_smd_init);
diff --git a/drivers/char/diag/Kconfig b/drivers/char/diag/Kconfig
index 53df29b..8f8707f 100644
--- a/drivers/char/diag/Kconfig
+++ b/drivers/char/diag/Kconfig
@@ -32,10 +32,10 @@
 
 menu "HSIC support for DIAG"
 
-config DIAG_HSIC_PIPE
+config DIAG_BRIDGE_CODE
 	depends on USB_QCOM_DIAG_BRIDGE
 	default y
-	bool "Enable 9K DIAG traffic over HSIC"
+	bool "Enable QSC/9K DIAG traffic over SMUX/HSIC"
 	help
-	 HSIC Transport Layer for DIAG Router
+	 SMUX/HSIC Transport Layer for DIAG Router
 endmenu
diff --git a/drivers/char/diag/Makefile b/drivers/char/diag/Makefile
index 3181d29..ea75ffd 100644
--- a/drivers/char/diag/Makefile
+++ b/drivers/char/diag/Makefile
@@ -1,4 +1,5 @@
 obj-$(CONFIG_DIAG_CHAR) := diagchar.o
 obj-$(CONFIG_DIAG_SDIO_PIPE) += diagfwd_sdio.o
-obj-$(CONFIG_DIAG_HSIC_PIPE) += diagfwd_hsic.o
+obj-$(CONFIG_DIAG_BRIDGE_CODE) += diagfwd_hsic.o
+obj-$(CONFIG_DIAG_BRIDGE_CODE) += diagfwd_smux.o
 diagchar-objs := diagchar_core.o diagchar_hdlc.o diagfwd.o diagmem.o diagfwd_cntl.o diag_dci.o
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 49d687d..7e7b514 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -41,6 +41,7 @@
 #define SDIO_DATA		4
 #define WCNSS_DATA		5
 #define HSIC_DATA		6
+#define SMUX_DATA		7
 #define MODEM_PROC		0
 #define APPS_PROC		1
 #define QDSP_PROC		2
@@ -254,24 +255,30 @@
 	struct diag_request *usb_read_mdm_ptr;
 	struct diag_request *write_ptr_mdm;
 #endif
-#ifdef CONFIG_DIAG_HSIC_PIPE
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+	/* SGLTE variables */
+	int lcid;
+	unsigned char *buf_in_smux;
+	int in_busy_smux;
+	int diag_smux_enabled;
+	/* HSIC variables */
 	unsigned char *buf_in_hsic;
-	unsigned char *usb_buf_mdm_out;
-	int hsic_initialized;
 	int hsic_ch;
 	int hsic_device_enabled;
 	int hsic_device_opened;
 	int hsic_suspend;
-	int read_len_mdm;
 	int in_busy_hsic_read_on_device;
 	int in_busy_hsic_write_on_device;
 	int in_busy_hsic_write;
 	int in_busy_hsic_read;
-	int usb_mdm_connected;
-	struct usb_diag_ch *mdm_ch;
-	struct workqueue_struct *diag_hsic_wq;
-	struct work_struct diag_read_mdm_work;
 	struct work_struct diag_read_hsic_work;
+	/* USB MDM channel variables */
+	int usb_mdm_connected;
+	int read_len_mdm;
+	unsigned char *usb_buf_mdm_out;
+	struct usb_diag_ch *mdm_ch;
+	struct workqueue_struct *diag_bridge_wq;
+	struct work_struct diag_read_mdm_work;
 	struct work_struct diag_disconnect_work;
 	struct work_struct diag_usb_read_complete_work;
 	struct diag_request *usb_read_mdm_ptr;
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 34640c3..8d6a607 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -32,8 +32,9 @@
 #ifdef CONFIG_DIAG_SDIO_PIPE
 #include "diagfwd_sdio.h"
 #endif
-#ifdef CONFIG_DIAG_HSIC_PIPE
+#ifdef CONFIG_DIAG_BRIDGE_CODE
 #include "diagfwd_hsic.h"
+#include "diagfwd_smux.h"
 #endif
 #include <linux/timer.h>
 
@@ -194,6 +195,7 @@
 				return -ENOMEM;
 			}
 		}
+		driver->data_ready[i] = 0x0;
 		driver->data_ready[i] |= MSG_MASKS_TYPE;
 		driver->data_ready[i] |= EVENT_MASKS_TYPE;
 		driver->data_ready[i] |= LOG_MASKS_TYPE;
@@ -233,9 +235,9 @@
 	if (driver->logging_process_id == current->tgid) {
 		driver->logging_mode = USB_MODE;
 		diagfwd_connect();
-#ifdef CONFIG_DIAG_HSIC_PIPE
+#ifdef CONFIG_DIAG_BRIDGE_CODE
 		diagfwd_cancel_hsic();
-		diagfwd_connect_hsic(0);
+		diagfwd_connect_bridge(0);
 #endif
 	}
 #endif /* DIAG over USB */
@@ -480,8 +482,8 @@
 #ifdef CONFIG_DIAG_SDIO_PIPE
 			driver->in_busy_sdio = 1;
 #endif
-#ifdef CONFIG_DIAG_HSIC_PIPE
-			diagfwd_disconnect_hsic(0);
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+			diagfwd_disconnect_bridge(0);
 #endif
 		} else if (temp == NO_LOGGING_MODE && driver->logging_mode
 							== MEMORY_DEVICE_MODE) {
@@ -508,22 +510,22 @@
 				queue_work(driver->diag_sdio_wq,
 					&(driver->diag_read_sdio_work));
 #endif
-#ifdef CONFIG_DIAG_HSIC_PIPE
-			diagfwd_connect_hsic(0);
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+			diagfwd_connect_bridge(0);
 #endif
 		}
 #ifdef CONFIG_DIAG_OVER_USB
 		else if (temp == USB_MODE && driver->logging_mode
 							 == NO_LOGGING_MODE) {
 			diagfwd_disconnect();
-#ifdef CONFIG_DIAG_HSIC_PIPE
-			diagfwd_disconnect_hsic(0);
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+			diagfwd_disconnect_bridge(0);
 #endif
 		} else if (temp == NO_LOGGING_MODE && driver->logging_mode
 								== USB_MODE) {
 			diagfwd_connect();
-#ifdef CONFIG_DIAG_HSIC_PIPE
-			diagfwd_connect_hsic(0);
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+			diagfwd_connect_bridge(0);
 #endif
 		} else if (temp == USB_MODE && driver->logging_mode
 							== MEMORY_DEVICE_MODE) {
@@ -551,16 +553,16 @@
 				queue_work(driver->diag_sdio_wq,
 					&(driver->diag_read_sdio_work));
 #endif
-#ifdef CONFIG_DIAG_HSIC_PIPE
+#ifdef CONFIG_DIAG_BRIDGE_CODE
 			diagfwd_cancel_hsic();
-			diagfwd_connect_hsic(0);
+			diagfwd_connect_bridge(0);
 #endif
 		} else if (temp == MEMORY_DEVICE_MODE &&
 				 driver->logging_mode == USB_MODE) {
 			diagfwd_connect();
-#ifdef CONFIG_DIAG_HSIC_PIPE
+#ifdef CONFIG_DIAG_BRIDGE_CODE
 			diagfwd_cancel_hsic();
-			diagfwd_connect_hsic(0);
+			diagfwd_connect_bridge(0);
 #endif
 		}
 #endif /* DIAG over USB */
@@ -719,7 +721,7 @@
 			driver->in_busy_sdio = 0;
 		}
 #endif
-#ifdef CONFIG_DIAG_HSIC_PIPE
+#ifdef CONFIG_DIAG_BRIDGE_CODE
 		pr_debug("diag: Copy data to user space %d\n",
 			 driver->in_busy_hsic_write_on_device);
 		if (driver->in_busy_hsic_write_on_device == 1) {
@@ -897,7 +899,7 @@
 			}
 		}
 #endif
-#ifdef CONFIG_DIAG_HSIC_PIPE
+#ifdef CONFIG_DIAG_BRIDGE_CODE
 		/* send masks to 9k too */
 		if (driver->hsic_ch && (payload_size > 0)) {
 			/* wait sending mask updates if HSIC ch not ready */
@@ -1198,16 +1200,16 @@
 inline void diag_sdio_fn(int type) {}
 #endif
 
-#ifdef CONFIG_DIAG_HSIC_PIPE
-void diag_hsic_fn(int type)
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+void diag_bridge_fn(int type)
 {
 	if (type == INIT)
-		diagfwd_hsic_init();
+		diagfwd_bridge_init();
 	else if (type == EXIT)
-		diagfwd_hsic_exit();
+		diagfwd_bridge_exit();
 }
 #else
-inline void diag_hsic_fn(int type) {}
+inline void diag_bridge_fn(int type) {}
 #endif
 
 static int __init diagchar_init(void)
@@ -1254,7 +1256,7 @@
 		diagfwd_cntl_init();
 		driver->dci_state = diag_dci_init();
 		diag_sdio_fn(INIT);
-		diag_hsic_fn(INIT);
+		diag_bridge_fn(INIT);
 		pr_debug("diagchar initializing ..\n");
 		driver->num = 1;
 		driver->name = ((void *)driver) + sizeof(struct diagchar_dev);
@@ -1288,7 +1290,7 @@
 	diagfwd_exit();
 	diagfwd_cntl_exit();
 	diag_sdio_fn(EXIT);
-	diag_hsic_fn(EXIT);
+	diag_bridge_fn(EXIT);
 	return -1;
 }
 
@@ -1301,7 +1303,7 @@
 	diagfwd_exit();
 	diagfwd_cntl_exit();
 	diag_sdio_fn(EXIT);
-	diag_hsic_fn(EXIT);
+	diag_bridge_fn(EXIT);
 	diag_debugfs_cleanup();
 	diagchar_cleanup();
 	printk(KERN_INFO "done diagchar exit\n");
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index a7a4a2a..a920f56 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -300,12 +300,12 @@
 				&(driver->diag_read_sdio_work));
 		}
 #endif
-#ifdef CONFIG_DIAG_HSIC_PIPE
+#ifdef CONFIG_DIAG_BRIDGE_CODE
 		else if (proc_num == HSIC_DATA) {
 			driver->in_busy_hsic_read = 0;
 			driver->in_busy_hsic_write_on_device = 0;
 			if (driver->hsic_ch)
-				queue_work(driver->diag_hsic_wq,
+				queue_work(driver->diag_bridge_wq,
 					&(driver->diag_read_hsic_work));
 		}
 #endif
@@ -352,7 +352,7 @@
 						"while USB write\n");
 		}
 #endif
-#ifdef CONFIG_DIAG_HSIC_PIPE
+#ifdef CONFIG_DIAG_BRIDGE_CODE
 		else if (proc_num == HSIC_DATA) {
 			if (driver->hsic_device_enabled) {
 				write_ptr->buf = buf;
@@ -360,6 +360,10 @@
 			} else
 				pr_err("diag: Incorrect hsic data "
 						"while USB write\n");
+		} else if (proc_num == SMUX_DATA) {
+				write_ptr->buf = buf;
+				pr_debug("diag: writing SMUX data\n");
+				err = usb_diag_write(driver->mdm_ch, write_ptr);
 		}
 #endif
 		APPEND_DEBUG('d');
@@ -1139,8 +1143,17 @@
 		}
 	}
 #if defined(CONFIG_DIAG_OVER_USB)
+	/* Check for the command/respond msg for the maximum packet length */
+	if ((*buf == 0x4b) && (*(buf+1) == 0x12) &&
+		(*(uint16_t *)(buf+2) == 0x0055)) {
+		for (i = 0; i < 4; i++)
+			*(driver->apps_rsp_buf+i) = *(buf+i);
+		*(uint32_t *)(driver->apps_rsp_buf+4) = PKT_SIZE;
+		ENCODE_RSP_AND_SEND(7);
+		return 0;
+	}
 	/* Check for Apps Only & get event mask request */
-	if (!(driver->ch) && chk_apps_only() && *buf == 0x81) {
+	else if (!(driver->ch) && chk_apps_only() && *buf == 0x81) {
 		driver->apps_rsp_buf[0] = 0x81;
 		driver->apps_rsp_buf[1] = 0x0;
 		*(uint16_t *)(driver->apps_rsp_buf + 2) = 0x0;
diff --git a/drivers/char/diag/diagfwd_hsic.c b/drivers/char/diag/diagfwd_hsic.c
index a3c6f26..d54d3dc 100644
--- a/drivers/char/diag/diagfwd_hsic.c
+++ b/drivers/char/diag/diagfwd_hsic.c
@@ -19,6 +19,7 @@
 #include <linux/workqueue.h>
 #include <linux/pm_runtime.h>
 #include <linux/platform_device.h>
+#include <linux/smux.h>
 #include <asm/current.h>
 #ifdef CONFIG_DIAG_OVER_USB
 #include <mach/usbdiag.h>
@@ -28,6 +29,7 @@
 #include "diagchar.h"
 #include "diagfwd.h"
 #include "diagfwd_hsic.h"
+#include "diagfwd_smux.h"
 
 static void diag_read_hsic_work_fn(struct work_struct *work)
 {
@@ -71,7 +73,8 @@
 	 * the next read
 	 */
 	if (!driver->in_busy_hsic_read)
-		queue_work(driver->diag_hsic_wq, &driver->diag_read_hsic_work);
+		queue_work(driver->diag_bridge_wq,
+				 &driver->diag_read_hsic_work);
 }
 
 static void diag_hsic_read_complete_callback(void *ctxt, char *buf,
@@ -114,7 +117,8 @@
 	if (!driver->in_busy_hsic_write_on_device && ((driver->logging_mode
 			== MEMORY_DEVICE_MODE) || (driver->usb_mdm_connected &&
 						    !driver->hsic_suspend)))
-		queue_work(driver->diag_hsic_wq, &driver->diag_read_hsic_work);
+		queue_work(driver->diag_bridge_wq,
+				 &driver->diag_read_hsic_work);
 }
 
 static void diag_hsic_write_complete_callback(void *ctxt, char *buf,
@@ -132,7 +136,7 @@
 		pr_err("DIAG in %s: actual_size: %d\n", __func__, actual_size);
 
 	if (driver->usb_mdm_connected)
-		queue_work(driver->diag_hsic_wq, &driver->diag_read_mdm_work);
+		queue_work(driver->diag_bridge_wq, &driver->diag_read_mdm_work);
 }
 
 static int diag_hsic_suspend(void *ctxt)
@@ -157,7 +161,8 @@
 
 	if (!driver->in_busy_hsic_write_on_device && (driver->logging_mode
 			== MEMORY_DEVICE_MODE || driver->usb_mdm_connected))
-		queue_work(driver->diag_hsic_wq, &driver->diag_read_hsic_work);
+		queue_work(driver->diag_bridge_wq,
+			 &driver->diag_read_hsic_work);
 }
 
 static struct diag_bridge_ops hsic_diag_bridge_ops = {
@@ -209,42 +214,48 @@
 	return 0;
 }
 
-/* diagfwd_connect_hsic is called when the USB mdm channel is connected */
-int diagfwd_connect_hsic(int process_cable)
+/* diagfwd_connect_bridge is called when the USB mdm channel is connected */
+int diagfwd_connect_bridge(int process_cable)
 {
 	int err;
 
-	pr_debug("DIAG in %s\n", __func__);
+	pr_debug("diag: in %s\n", __func__);
 
 	/* If the usb cable is being connected */
 	if (process_cable) {
 		err = usb_diag_alloc_req(driver->mdm_ch, N_MDM_WRITE,
 			N_MDM_READ);
 		if (err)
-			pr_err("DIAG: unable to alloc USB req on mdm"
+			pr_err("diag: unable to alloc USB req on mdm"
 				" ch err:%d\n", err);
 
 		driver->usb_mdm_connected = 1;
 	}
 
-	driver->in_busy_hsic_write_on_device = 0;
-	driver->in_busy_hsic_read_on_device = 0;
-	driver->in_busy_hsic_write = 0;
-	driver->in_busy_hsic_read = 0;
+	if (driver->hsic_device_enabled) {
+		driver->in_busy_hsic_write_on_device = 0;
+		driver->in_busy_hsic_read_on_device = 0;
+		driver->in_busy_hsic_write = 0;
+		driver->in_busy_hsic_read = 0;
+	} else if (driver->diag_smux_enabled) {
+		driver->in_busy_smux = 0;
+		diagfwd_connect_smux();
+		return 0;
+	}
 
 	/* If the hsic (diag_bridge) platform device is not open */
 	if (driver->hsic_device_enabled) {
 		if (!driver->hsic_device_opened) {
 			err = diag_bridge_open(&hsic_diag_bridge_ops);
 			if (err) {
-				pr_err("DIAG: HSIC channel open error: %d\n",
+				pr_err("diag: HSIC channel open error: %d\n",
 					err);
 			} else {
-				pr_debug("DIAG: opened HSIC channel\n");
+				pr_debug("diag: opened HSIC channel\n");
 				driver->hsic_device_opened = 1;
 			}
 		} else {
-			pr_debug("DIAG: HSIC channel already open\n");
+			pr_debug("diag: HSIC channel already open\n");
 		}
 
 		/*
@@ -256,24 +267,25 @@
 
 		/* Poll USB mdm channel to check for data */
 		if (driver->logging_mode == USB_MODE)
-			queue_work(driver->diag_hsic_wq,
+			queue_work(driver->diag_bridge_wq,
 					&driver->diag_read_mdm_work);
 
 		/* Poll HSIC channel to check for data */
-		queue_work(driver->diag_hsic_wq, &driver->diag_read_hsic_work);
+		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");
+		pr_info("diag: HSIC channel not yet enabled\n");
 	}
 
 	return 0;
 }
 
 /*
- * diagfwd_disconnect_hsic is called when the USB mdm channel
+ * diagfwd_disconnect_bridge is called when the USB mdm channel
  * is disconnected
  */
-int diagfwd_disconnect_hsic(int process_cable)
+int diagfwd_disconnect_bridge(int process_cable)
 {
 	pr_debug("DIAG in %s\n", __func__);
 
@@ -284,12 +296,19 @@
 	}
 
 	if (driver->logging_mode != MEMORY_DEVICE_MODE) {
-		driver->in_busy_hsic_write_on_device = 1;
-		driver->in_busy_hsic_read_on_device = 1;
-		driver->in_busy_hsic_write = 1;
-		driver->in_busy_hsic_read = 1;
-		/* Turn off communication over usb mdm and hsic */
-		return diag_hsic_close();
+		if (driver->hsic_device_enabled) {
+			driver->in_busy_hsic_write_on_device = 1;
+			driver->in_busy_hsic_read_on_device = 1;
+			driver->in_busy_hsic_write = 1;
+			driver->in_busy_hsic_read = 1;
+			/* Turn off communication over usb mdm and hsic */
+			return diag_hsic_close();
+		} else if (driver->diag_smux_enabled) {
+			driver->in_busy_smux = 1;
+			driver->lcid = LCID_INVALID;
+			/* Turn off communication over usb mdm and smux */
+			msm_smux_close(LCID_VALID);
+		}
 	}
 	return 0;
 }
@@ -313,18 +332,23 @@
 	APPEND_DEBUG('q');
 
 	/* Read data from the hsic */
-	queue_work(driver->diag_hsic_wq, &driver->diag_read_hsic_work);
+	queue_work(driver->diag_bridge_wq, &driver->diag_read_hsic_work);
 
 	return 0;
 }
 
 /* Called after the asychronous usb_diag_read() on mdm channel is complete */
-static int diagfwd_read_complete_hsic(struct diag_request *diag_read_ptr)
+static int diagfwd_read_complete_bridge(struct diag_request *diag_read_ptr)
 {
 	/* The read of the usb driver on the mdm (not hsic) has completed */
 	driver->in_busy_hsic_read_on_device = 0;
 	driver->read_len_mdm = diag_read_ptr->actual;
 
+	if (driver->diag_smux_enabled) {
+		diagfwd_read_complete_smux();
+		return 0;
+	}
+	/* If SMUX not enabled, check for HSIC */
 	if (!driver->hsic_ch) {
 		pr_err("DIAG in %s: driver->hsic_ch == 0\n", __func__);
 		return 0;
@@ -366,30 +390,34 @@
 	 * hsic channel
 	 */
 	if (!driver->in_busy_hsic_write)
-		queue_work(driver->diag_hsic_wq, &driver->diag_read_mdm_work);
+		queue_work(driver->diag_bridge_wq, &driver->diag_read_mdm_work);
 
 	return 0;
 }
 
-static void diagfwd_hsic_notifier(void *priv, unsigned event,
+static void diagfwd_bridge_notifier(void *priv, unsigned event,
 					struct diag_request *d_req)
 {
 	switch (event) {
 	case USB_DIAG_CONNECT:
-		diagfwd_connect_hsic(1);
+		diagfwd_connect_bridge(1);
 		break;
 	case USB_DIAG_DISCONNECT:
-		queue_work(driver->diag_hsic_wq, &driver->diag_disconnect_work);
+		queue_work(driver->diag_bridge_wq,
+			 &driver->diag_disconnect_work);
 		break;
 	case USB_DIAG_READ_DONE:
-		queue_work(driver->diag_hsic_wq,
+		queue_work(driver->diag_bridge_wq,
 				&driver->diag_usb_read_complete_work);
 		break;
 	case USB_DIAG_WRITE_DONE:
-		diagfwd_write_complete_hsic();
+		if (driver->hsic_device_enabled)
+			diagfwd_write_complete_hsic();
+		else if (driver->diag_smux_enabled)
+			diagfwd_write_complete_smux();
 		break;
 	default:
-		pr_err("DIAG in %s: Unknown event from USB diag:%u\n",
+		pr_err("diag: in %s: Unknown event from USB diag:%u\n",
 			__func__, event);
 		break;
 	}
@@ -397,16 +425,33 @@
 
 static void diag_usb_read_complete_fn(struct work_struct *w)
 {
-	diagfwd_read_complete_hsic(driver->usb_read_mdm_ptr);
+	diagfwd_read_complete_bridge(driver->usb_read_mdm_ptr);
 }
 
 static void diag_disconnect_work_fn(struct work_struct *w)
 {
-	diagfwd_disconnect_hsic(1);
+	diagfwd_disconnect_bridge(1);
 }
 
 static void diag_read_mdm_work_fn(struct work_struct *work)
 {
+	int ret;
+	if (driver->diag_smux_enabled) {
+		if (driver->lcid && driver->usb_buf_mdm_out &&
+					 (driver->read_len_mdm > 0)) {
+			ret = msm_smux_write(driver->lcid,  NULL,
+		 driver->usb_buf_mdm_out, driver->read_len_mdm);
+			if (ret)
+				pr_err("diag: writing to SMUX ch, r = %d,"
+					"lcid = %d\n", ret, driver->lcid);
+		}
+		driver->usb_read_mdm_ptr->buf = driver->usb_buf_mdm_out;
+		driver->usb_read_mdm_ptr->length = USB_MAX_OUT_BUF;
+		usb_diag_read(driver->mdm_ch, driver->usb_read_mdm_ptr);
+		return;
+	}
+
+	/* if SMUX not enabled, check for HSIC */
 	if (!driver->hsic_ch) {
 		pr_err("DIAG in %s: driver->hsic_ch == 0\n", __func__);
 		return;
@@ -434,7 +479,8 @@
 	 * queue up the reading of data from the mdm channel
 	 */
 	if (!driver->in_busy_hsic_read_on_device)
-		queue_work(driver->diag_hsic_wq, &driver->diag_read_mdm_work);
+		queue_work(driver->diag_bridge_wq,
+			 &driver->diag_read_mdm_work);
 }
 
 static int diag_hsic_probe(struct platform_device *pdev)
@@ -442,31 +488,10 @@
 	int err = 0;
 	pr_debug("diag: in %s\n", __func__);
 	if (!driver->hsic_device_enabled) {
-		driver->read_len_mdm = 0;
 		if (driver->buf_in_hsic == NULL)
 			driver->buf_in_hsic = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
-		if (driver->buf_in_hsic == NULL)
-			goto err;
-		if (driver->usb_buf_mdm_out  == NULL)
-			driver->usb_buf_mdm_out = kzalloc(USB_MAX_OUT_BUF,
-								 GFP_KERNEL);
-		if (driver->usb_buf_mdm_out == NULL)
-			goto err;
-		if (driver->write_ptr_mdm == NULL)
-			driver->write_ptr_mdm = kzalloc(
-			sizeof(struct diag_request), GFP_KERNEL);
-		if (driver->write_ptr_mdm == NULL)
-			goto err;
-		if (driver->usb_read_mdm_ptr == NULL)
-			driver->usb_read_mdm_ptr = kzalloc(
-			sizeof(struct diag_request), GFP_KERNEL);
-		if (driver->usb_read_mdm_ptr == NULL)
-			goto err;
-#ifdef CONFIG_DIAG_OVER_USB
-		INIT_WORK(&(driver->diag_read_mdm_work), diag_read_mdm_work_fn);
-#endif
 		INIT_WORK(&(driver->diag_read_hsic_work),
-						 diag_read_hsic_work_fn);
+					 diag_read_hsic_work_fn);
 		driver->hsic_device_enabled = 1;
 	}
 
@@ -495,25 +520,16 @@
 
 		if (driver->usb_mdm_connected) {
 			/* Poll USB mdm channel to check for data */
-			queue_work(driver->diag_hsic_wq,
+			queue_work(driver->diag_bridge_wq,
 					 &driver->diag_read_mdm_work);
 		}
 
 		/* Poll HSIC channel to check for data */
-		queue_work(driver->diag_hsic_wq, &driver->diag_read_hsic_work);
+		queue_work(driver->diag_bridge_wq,
+				 &driver->diag_read_hsic_work);
 	}
 
 	return err;
-err:
-	pr_err("DIAG could not initialize buf for HSIC\n");
-	kfree(driver->buf_in_hsic);
-	kfree(driver->usb_buf_mdm_out);
-	kfree(driver->write_ptr_mdm);
-	kfree(driver->usb_read_mdm_ptr);
-	if (driver->diag_hsic_wq)
-		destroy_workqueue(driver->diag_hsic_wq);
-
-	return -ENOMEM;
 }
 
 static int diag_hsic_remove(struct platform_device *pdev)
@@ -550,55 +566,93 @@
 		   },
 };
 
-void diagfwd_hsic_init(void)
+void diagfwd_bridge_init(void)
 {
 	int ret;
 
-	pr_debug("DIAG in %s\n", __func__);
+	pr_debug("diag: in %s\n", __func__);
+	driver->diag_bridge_wq = create_singlethread_workqueue(
+							"diag_bridge_wq");
+	driver->read_len_mdm = 0;
+	if (driver->usb_buf_mdm_out  == NULL)
+		driver->usb_buf_mdm_out = kzalloc(USB_MAX_OUT_BUF,
+							 GFP_KERNEL);
+	if (driver->usb_buf_mdm_out == NULL)
+		goto err;
+	if (driver->write_ptr_mdm == NULL)
+		driver->write_ptr_mdm = kzalloc(
+		sizeof(struct diag_request), GFP_KERNEL);
+	if (driver->write_ptr_mdm == NULL)
+		goto err;
+	if (driver->usb_read_mdm_ptr == NULL)
+		driver->usb_read_mdm_ptr = kzalloc(
+		sizeof(struct diag_request), GFP_KERNEL);
+	if (driver->usb_read_mdm_ptr == NULL)
+		goto err;
 
-	driver->diag_hsic_wq = create_singlethread_workqueue("diag_hsic_wq");
+#ifdef CONFIG_DIAG_OVER_USB
+	INIT_WORK(&(driver->diag_read_mdm_work), diag_read_mdm_work_fn);
+#endif
 	INIT_WORK(&(driver->diag_disconnect_work), diag_disconnect_work_fn);
 	INIT_WORK(&(driver->diag_usb_read_complete_work),
 			diag_usb_read_complete_fn);
-
 #ifdef CONFIG_DIAG_OVER_USB
-	driver->mdm_ch = usb_diag_open(DIAG_MDM, driver, diagfwd_hsic_notifier);
+	driver->mdm_ch = usb_diag_open(DIAG_MDM, driver,
+						 diagfwd_bridge_notifier);
 	if (IS_ERR(driver->mdm_ch)) {
-		pr_err("DIAG Unable to open USB diag MDM channel\n");
+		pr_err("diag: Unable to open USB diag MDM channel\n");
 		goto err;
 	}
 #endif
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+	INIT_WORK(&(driver->diag_disconnect_work), diag_disconnect_work_fn);
+	INIT_WORK(&(driver->diag_usb_read_complete_work),
+			diag_usb_read_complete_fn);
+	/* register HSIC device */
 	ret = platform_driver_register(&msm_hsic_ch_driver);
 	if (ret)
-		pr_err("DIAG could not register HSIC device, ret: %d\n", ret);
-	else
-		driver->hsic_initialized = 1;
-
+		pr_err("diag: could not register HSIC device, ret: %d\n", ret);
+	/* register SMUX device */
+	ret = platform_driver_register(&msm_diagfwd_smux_driver);
+	if (ret)
+		pr_err("diag: could not register SMUX device, ret: %d\n", ret);
+#endif
 	return;
 err:
-	pr_err("DIAG could not initialize for HSIC execution\n");
-}
-
-void diagfwd_hsic_exit(void)
-{
-	pr_debug("DIAG in %s\n", __func__);
-
-	if (driver->hsic_initialized)
-		diag_hsic_close();
-
-#ifdef CONFIG_DIAG_OVER_USB
-	if (driver->usb_mdm_connected)
-		usb_diag_free_req(driver->mdm_ch);
-#endif
-	platform_driver_unregister(&msm_hsic_ch_driver);
-#ifdef CONFIG_DIAG_OVER_USB
-	usb_diag_close(driver->mdm_ch);
-#endif
-	kfree(driver->buf_in_hsic);
+	pr_err("diag: Could not initialize for bridge forwarding\n");
 	kfree(driver->usb_buf_mdm_out);
 	kfree(driver->write_ptr_mdm);
 	kfree(driver->usb_read_mdm_ptr);
-	destroy_workqueue(driver->diag_hsic_wq);
+	if (driver->diag_bridge_wq)
+		destroy_workqueue(driver->diag_bridge_wq);
 
-	driver->hsic_device_enabled = 0;
+	return;
+}
+
+void diagfwd_bridge_exit(void)
+{
+	pr_debug("diag: in %s\n", __func__);
+
+	if (driver->hsic_device_enabled) {
+		diag_hsic_close();
+		kfree(driver->buf_in_hsic);
+		driver->hsic_device_enabled = 0;
+	}
+	if (driver->diag_smux_enabled) {
+		driver->lcid = LCID_INVALID;
+		kfree(driver->buf_in_smux);
+		driver->diag_smux_enabled = 0;
+	}
+	platform_driver_unregister(&msm_hsic_ch_driver);
+	platform_driver_unregister(&msm_diagfwd_smux_driver);
+	/* destroy USB MDM specific variables */
+#ifdef CONFIG_DIAG_OVER_USB
+	if (driver->usb_mdm_connected)
+		usb_diag_free_req(driver->mdm_ch);
+	usb_diag_close(driver->mdm_ch);
+#endif
+	kfree(driver->usb_buf_mdm_out);
+	kfree(driver->write_ptr_mdm);
+	kfree(driver->usb_read_mdm_ptr);
+	destroy_workqueue(driver->diag_bridge_wq);
 }
diff --git a/drivers/char/diag/diagfwd_hsic.h b/drivers/char/diag/diagfwd_hsic.h
index 8785d9f..b189c94 100644
--- a/drivers/char/diag/diagfwd_hsic.h
+++ b/drivers/char/diag/diagfwd_hsic.h
@@ -17,11 +17,11 @@
 #define N_MDM_WRITE	1 /* Upgrade to 2 with ping pong buffer */
 #define N_MDM_READ	1
 
-int diagfwd_connect_hsic(int);
-int diagfwd_disconnect_hsic(int);
+int diagfwd_connect_bridge(int);
+int diagfwd_disconnect_bridge(int);
 int diagfwd_write_complete_hsic(void);
 int diagfwd_cancel_hsic(void);
-void diagfwd_hsic_init(void);
-void diagfwd_hsic_exit(void);
+void diagfwd_bridge_init(void);
+void diagfwd_bridge_exit(void);
 
 #endif
diff --git a/drivers/char/diag/diagfwd_smux.c b/drivers/char/diag/diagfwd_smux.c
new file mode 100644
index 0000000..8bbc67e
--- /dev/null
+++ b/drivers/char/diag/diagfwd_smux.c
@@ -0,0 +1,156 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/termios.h>
+#include <linux/slab.h>
+#include <linux/diagchar.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <mach/usbdiag.h>
+#include "diagchar.h"
+#include "diagfwd.h"
+#include "diagfwd_smux.h"
+
+void diag_smux_event(void *priv, int event_type, const void *metadata)
+{
+	unsigned char *rx_buf;
+	int len;
+
+	switch (event_type) {
+	case SMUX_CONNECTED:
+		pr_debug("diag: SMUX_CONNECTED received\n");
+		driver->in_busy_smux = 0;
+		/* read data from USB MDM channel & Initiate first write */
+		queue_work(driver->diag_bridge_wq,
+				 &(driver->diag_read_mdm_work));
+		break;
+	case SMUX_DISCONNECTED:
+		pr_info("diag: SMUX_DISCONNECTED received\n");
+		break;
+	case SMUX_WRITE_DONE:
+		pr_debug("diag: SMUX Write done\n");
+		break;
+	case SMUX_WRITE_FAIL:
+		pr_info("diag: SMUX Write Failed\n");
+		break;
+	case SMUX_READ_FAIL:
+		pr_info("diag: SMUX Read Failed\n");
+		break;
+	case SMUX_READ_DONE:
+		len = ((struct smux_meta_read *)metadata)->len;
+		rx_buf = ((struct smux_meta_read *)metadata)->buffer;
+		driver->write_ptr_mdm->length = len;
+		diag_device_write(driver->buf_in_smux, SMUX_DATA,
+						 driver->write_ptr_mdm);
+		break;
+	};
+}
+
+int diagfwd_write_complete_smux(void)
+{
+	pr_debug("diag: clear in_busy_smux\n");
+	driver->in_busy_smux = 0;
+	return 0;
+}
+
+int diagfwd_read_complete_smux(void)
+{
+	queue_work(driver->diag_bridge_wq, &(driver->diag_read_mdm_work));
+	return 0;
+}
+
+int diag_get_rx_buffer(void *priv, void **pkt_priv, void **buffer, int size)
+{
+	if (!driver->in_busy_smux) {
+		*pkt_priv = (void *)0x1234;
+		*buffer = driver->buf_in_smux;
+		pr_debug("diag: set in_busy_smux as 1\n");
+		driver->in_busy_smux = 1;
+	} else {
+		pr_debug("diag: read buffer for SMUX is BUSY\n");
+		return -EAGAIN;
+	}
+	return 0;
+}
+
+static int diagfwd_smux_runtime_suspend(struct device *dev)
+{
+	dev_dbg(dev, "pm_runtime: suspending...\n");
+	return 0;
+}
+
+static int diagfwd_smux_runtime_resume(struct device *dev)
+{
+	dev_dbg(dev, "pm_runtime: resuming...\n");
+	return 0;
+}
+
+static const struct dev_pm_ops diagfwd_smux_dev_pm_ops = {
+	.runtime_suspend = diagfwd_smux_runtime_suspend,
+	.runtime_resume = diagfwd_smux_runtime_resume,
+};
+
+int diagfwd_connect_smux(void)
+{
+	void *priv = NULL;
+	int ret = 0;
+
+	if (driver->lcid == LCID_INVALID) {
+		ret = msm_smux_open(LCID_VALID, priv, diag_smux_event,
+						 diag_get_rx_buffer);
+		if (!ret) {
+			driver->lcid = LCID_VALID;
+			msm_smux_tiocm_set(driver->lcid, TIOCM_DTR, 0);
+			pr_info("diag: open SMUX ch, r = %d\n", ret);
+		} else {
+			pr_err("diag: failed to open SMUX ch, r = %d\n", ret);
+		}
+	}
+	/* Poll USB channel to check for data*/
+	queue_work(driver->diag_bridge_wq, &(driver->diag_read_mdm_work));
+	return ret;
+}
+
+static int diagfwd_smux_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+
+	pr_info("diag: SMUX probe called\n");
+	driver->lcid = LCID_INVALID;
+	driver->diag_smux_enabled = 1;
+	if (driver->buf_in_smux == NULL) {
+		driver->buf_in_smux = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
+		if (driver->buf_in_smux == NULL)
+			goto err;
+	}
+	/* Only required for Local loopback test
+	 * ret = msm_smux_set_ch_option(LCID_VALID,
+				 SMUX_CH_OPTION_LOCAL_LOOPBACK, 0);
+	 * if (ret)
+	 *	pr_err("diag: error setting SMUX ch option, r = %d\n", ret);
+	 */
+	ret = diagfwd_connect_smux();
+	return ret;
+
+err:
+	pr_err("diag: Could not initialize SMUX buffer\n");
+	kfree(driver->buf_in_smux);
+	return ret;
+}
+
+struct platform_driver msm_diagfwd_smux_driver = {
+	.probe = diagfwd_smux_probe,
+	.driver = {
+		   .name = "SMUX_DIAG",
+		   .owner = THIS_MODULE,
+		   .pm   = &diagfwd_smux_dev_pm_ops,
+		   },
+};
diff --git a/drivers/char/diag/diagfwd_smux.h b/drivers/char/diag/diagfwd_smux.h
new file mode 100644
index 0000000..e78b7ed
--- /dev/null
+++ b/drivers/char/diag/diagfwd_smux.h
@@ -0,0 +1,25 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef DIAGFWD_SMUX_H
+#define DIAGFWD_SMUX_H
+
+#include <linux/smux.h>
+#define LCID_VALID	SMUX_USB_DIAG_0
+#define LCID_INVALID	0
+
+int diagfwd_read_complete_smux(void);
+int diagfwd_write_complete_smux(void);
+int diagfwd_connect_smux(void);
+extern struct platform_driver msm_diagfwd_smux_driver;
+
+#endif
diff --git a/drivers/char/hw_random/msm_rng.c b/drivers/char/hw_random/msm_rng.c
index 974b77e..7e6670d 100644
--- a/drivers/char/hw_random/msm_rng.c
+++ b/drivers/char/hw_random/msm_rng.c
@@ -231,12 +231,19 @@
 	return 0;
 }
 
+static struct of_device_id qrng_match[] = {
+	{	.compatible = "qcom,msm-rng",
+	},
+	{}
+};
+
 static struct platform_driver rng_driver = {
 	.probe      = msm_rng_probe,
 	.remove     = __devexit_p(msm_rng_remove),
 	.driver     = {
 		.name   = DRIVER_NAME,
 		.owner  = THIS_MODULE,
+		.of_match_table = qrng_match,
 	}
 };
 
diff --git a/drivers/char/msm_rotator.c b/drivers/char/msm_rotator.c
index 81a9fa7..6cd1806 100644
--- a/drivers/char/msm_rotator.c
+++ b/drivers/char/msm_rotator.c
@@ -45,6 +45,7 @@
 #define MSM_ROTATOR_START			(MSM_ROTATOR_BASE+0x0030)
 #define MSM_ROTATOR_MAX_BURST_SIZE		(MSM_ROTATOR_BASE+0x0050)
 #define MSM_ROTATOR_HW_VERSION			(MSM_ROTATOR_BASE+0x0070)
+#define MSM_ROTATOR_SW_RESET			(MSM_ROTATOR_BASE+0x0074)
 #define MSM_ROTATOR_SRC_SIZE			(MSM_ROTATOR_BASE+0x1108)
 #define MSM_ROTATOR_SRCP0_ADDR			(MSM_ROTATOR_BASE+0x110c)
 #define MSM_ROTATOR_SRCP1_ADDR			(MSM_ROTATOR_BASE+0x1110)
@@ -906,8 +907,7 @@
 			break;
 
 	if (s == MAX_SESSIONS) {
-		dev_dbg(msm_rotator_dev->device,
-			"%s() : Attempt to use invalid session_id %d\n",
+		pr_err("%s() : Attempt to use invalid session_id %d\n",
 			__func__, s);
 		rc = -EINVAL;
 		goto do_rotate_unlock_mutex;
@@ -1129,11 +1129,13 @@
 		break;
 	default:
 		rc = -EINVAL;
+		pr_err("%s(): Unsupported format %u\n", __func__, format);
 		goto do_rotate_exit;
 	}
 
 	if (rc != 0) {
 		msm_rotator_dev->last_session_idx = INVALID_SESSION;
+		pr_err("%s(): Invalid session error\n", __func__);
 		goto do_rotate_exit;
 	}
 
@@ -1145,8 +1147,11 @@
 	wait_event(msm_rotator_dev->wq,
 		   (msm_rotator_dev->processing == 0));
 	status = (unsigned char)ioread32(MSM_ROTATOR_INTR_STATUS);
-	if ((status & 0x03) != 0x01)
+	if ((status & 0x03) != 0x01) {
+		pr_err("%s(): AXI Bus Error, issuing SW_RESET\n", __func__);
+		iowrite32(0x1, MSM_ROTATOR_SW_RESET);
 		rc = -EFAULT;
+	}
 	iowrite32(0, MSM_ROTATOR_INTR_ENABLE);
 	iowrite32(3, MSM_ROTATOR_INTR_CLEAR);
 
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 36375c05..473b0ef 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -281,8 +281,23 @@
 	}
 }
 EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
+/**
+ * cpufreq_notify_utilization - notify CPU userspace about CPU utilization
+ * change
+ *
+ * This function is called everytime the CPU load is evaluated by the
+ * ondemand governor. It notifies userspace of cpu load changes via sysfs.
+ */
+void cpufreq_notify_utilization(struct cpufreq_policy *policy,
+		unsigned int util)
+{
+	if (policy)
+		policy->util = util;
 
+	if (policy->util >= MIN_CPU_UTIL_NOTIFY)
+		sysfs_notify(&policy->kobj, NULL, "cpu_utilization");
 
+}
 
 /*********************************************************************
  *                          SYSFS INTERFACE                          *
@@ -370,6 +385,7 @@
 show_one(scaling_min_freq, min);
 show_one(scaling_max_freq, max);
 show_one(scaling_cur_freq, cur);
+show_one(cpu_utilization, util);
 
 static int __cpufreq_set_policy(struct cpufreq_policy *data,
 				struct cpufreq_policy *policy);
@@ -459,6 +475,8 @@
 	policy->user_policy.policy = policy->policy;
 	policy->user_policy.governor = policy->governor;
 
+	sysfs_notify(&policy->kobj, NULL, "scaling_governor");
+
 	if (ret)
 		return ret;
 	else
@@ -584,6 +602,7 @@
 cpufreq_freq_attr_ro(bios_limit);
 cpufreq_freq_attr_ro(related_cpus);
 cpufreq_freq_attr_ro(affected_cpus);
+cpufreq_freq_attr_ro(cpu_utilization);
 cpufreq_freq_attr_rw(scaling_min_freq);
 cpufreq_freq_attr_rw(scaling_max_freq);
 cpufreq_freq_attr_rw(scaling_governor);
@@ -596,6 +615,7 @@
 	&scaling_min_freq.attr,
 	&scaling_max_freq.attr,
 	&affected_cpus.attr,
+	&cpu_utilization.attr,
 	&related_cpus.attr,
 	&scaling_governor.attr,
 	&scaling_driver.attr,
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index 2d33096..cfc2534 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -552,7 +552,11 @@
 
 static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
 {
+	/* Extrapolated load of this CPU */
+	unsigned int load_at_max_freq = 0;
 	unsigned int max_load_freq;
+	/* Current load across this CPU */
+	unsigned int cur_load = 0;
 
 	struct cpufreq_policy *policy;
 	unsigned int j;
@@ -579,7 +583,7 @@
 		struct cpu_dbs_info_s *j_dbs_info;
 		cputime64_t cur_wall_time, cur_idle_time, cur_iowait_time;
 		unsigned int idle_time, wall_time, iowait_time;
-		unsigned int load, load_freq;
+		unsigned int load_freq;
 		int freq_avg;
 
 		j_dbs_info = &per_cpu(od_cpu_dbs_info, j);
@@ -629,16 +633,20 @@
 		if (unlikely(!wall_time || wall_time < idle_time))
 			continue;
 
-		load = 100 * (wall_time - idle_time) / wall_time;
+		cur_load = 100 * (wall_time - idle_time) / wall_time;
 
 		freq_avg = __cpufreq_driver_getavg(policy, j);
 		if (freq_avg <= 0)
 			freq_avg = policy->cur;
 
-		load_freq = load * freq_avg;
+		load_freq = cur_load * freq_avg;
 		if (load_freq > max_load_freq)
 			max_load_freq = load_freq;
 	}
+	/* calculate the scaled load across CPU */
+	load_at_max_freq = (cur_load * policy->cur)/policy->cpuinfo.max_freq;
+
+	cpufreq_notify_utilization(policy, load_at_max_freq);
 
 	/* Check for frequency increase */
 	if (max_load_freq > dbs_tuners_ins.up_threshold * policy->cur) {
diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index fff494c..2a191d5 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -352,7 +352,7 @@
 	}
 	kzfree(handle);
 	file->private_data = NULL;
-	if (podev->platform_support.bus_scale_table != NULL)
+	if (podev != NULL && podev->platform_support.bus_scale_table != NULL)
 		qcedev_ce_high_bw_req(podev, false);
 	return 0;
 }
diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c
index 21c3aff..63dfc2d 100644
--- a/drivers/crypto/msm/qcrypto.c
+++ b/drivers/crypto/msm/qcrypto.c
@@ -888,7 +888,7 @@
 						ctx->authsize, 1);
 
 			} else {
-				unsigned char tmp[SHA256_DIGESTSIZE];
+				unsigned char tmp[SHA256_DIGESTSIZE] = {0};
 
 				/* compare icv from src */
 				scatterwalk_map_and_copy(tmp,
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index 940af32..56f986d 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -996,19 +996,41 @@
 {
 	struct ion_client *client = s->private;
 	struct rb_node *n;
+	struct rb_node *n2;
 
-	seq_printf(s, "%16.16s: %16.16s : %16.16s : %16.16s\n", "heap_name",
-			"size_in_bytes", "handle refcount", "buffer");
+	seq_printf(s, "%16.16s: %16.16s : %16.16s : %12.12s : %12.12s : %s\n",
+			"heap_name", "size_in_bytes", "handle refcount",
+			"buffer", "physical", "[domain,partition] - virt");
+
 	mutex_lock(&client->lock);
 	for (n = rb_first(&client->handles); n; n = rb_next(n)) {
 		struct ion_handle *handle = rb_entry(n, struct ion_handle,
 						     node);
+		enum ion_heap_type type = handle->buffer->heap->type;
 
-		seq_printf(s, "%16.16s: %16x : %16d : %16p\n",
+		seq_printf(s, "%16.16s: %16x : %16d : %12p",
 				handle->buffer->heap->name,
 				handle->buffer->size,
 				atomic_read(&handle->ref.refcount),
 				handle->buffer);
+
+		if (type == ION_HEAP_TYPE_SYSTEM_CONTIG ||
+			type == ION_HEAP_TYPE_CARVEOUT ||
+			type == ION_HEAP_TYPE_CP)
+			seq_printf(s, " : %12lx", handle->buffer->priv_phys);
+		else
+			seq_printf(s, " : %12s", "N/A");
+
+		for (n2 = rb_first(&handle->buffer->iommu_maps); n2;
+				   n2 = rb_next(n2)) {
+			struct ion_iommu_map *imap =
+				rb_entry(n2, struct ion_iommu_map, node);
+			seq_printf(s, " : [%d,%d] - %8lx",
+					imap->domain_info[DI_DOMAIN_NUM],
+					imap->domain_info[DI_PARTITION_NUM],
+					imap->iova_addr);
+		}
+		seq_printf(s, "\n");
 	}
 
 	seq_printf(s, "%16.16s %d\n", "client refcount:",
@@ -1652,12 +1674,158 @@
 	return size;
 }
 
+/**
+ * Searches through a clients handles to find if the buffer is owned
+ * by this client. Used for debug output.
+ * @param client pointer to candidate owner of buffer
+ * @param buf pointer to buffer that we are trying to find the owner of
+ * @return 1 if found, 0 otherwise
+ */
+static int ion_debug_find_buffer_owner(const struct ion_client *client,
+				       const struct ion_buffer *buf)
+{
+	struct rb_node *n;
+
+	for (n = rb_first(&client->handles); n; n = rb_next(n)) {
+		const struct ion_handle *handle = rb_entry(n,
+						     const struct ion_handle,
+						     node);
+		if (handle->buffer == buf)
+			return 1;
+	}
+	return 0;
+}
+
+/**
+ * Adds mem_map_data pointer to the tree of mem_map
+ * Used for debug output.
+ * @param mem_map The mem_map tree
+ * @param data The new data to add to the tree
+ */
+static void ion_debug_mem_map_add(struct rb_root *mem_map,
+				  struct mem_map_data *data)
+{
+	struct rb_node **p = &mem_map->rb_node;
+	struct rb_node *parent = NULL;
+	struct mem_map_data *entry;
+
+	while (*p) {
+		parent = *p;
+		entry = rb_entry(parent, struct mem_map_data, node);
+
+		if (data->addr < entry->addr) {
+			p = &(*p)->rb_left;
+		} else if (data->addr > entry->addr) {
+			p = &(*p)->rb_right;
+		} else {
+			pr_err("%s: mem_map_data already found.", __func__);
+			BUG();
+		}
+	}
+	rb_link_node(&data->node, parent, p);
+	rb_insert_color(&data->node, mem_map);
+}
+
+/**
+ * Search for an owner of a buffer by iterating over all ION clients.
+ * @param dev ion device containing pointers to all the clients.
+ * @param buffer pointer to buffer we are trying to find the owner of.
+ * @return name of owner.
+ */
+const char *ion_debug_locate_owner(const struct ion_device *dev,
+					 const struct ion_buffer *buffer)
+{
+	struct rb_node *j;
+	const char *client_name = NULL;
+
+	for (j = rb_first(&dev->user_clients); j && !client_name;
+			  j = rb_next(j)) {
+		struct ion_client *client = rb_entry(j, struct ion_client,
+						     node);
+		if (ion_debug_find_buffer_owner(client, buffer))
+			client_name = client->name;
+	}
+	for (j = rb_first(&dev->kernel_clients); j && !client_name;
+			  j = rb_next(j)) {
+		struct ion_client *client = rb_entry(j, struct ion_client,
+						     node);
+		if (ion_debug_find_buffer_owner(client, buffer))
+			client_name = client->name;
+	}
+	return client_name;
+}
+
+/**
+ * Create a mem_map of the heap.
+ * @param s seq_file to log error message to.
+ * @param heap The heap to create mem_map for.
+ * @param mem_map The mem map to be created.
+ */
+void ion_debug_mem_map_create(struct seq_file *s, struct ion_heap *heap,
+			      struct rb_root *mem_map)
+{
+	struct ion_device *dev = heap->dev;
+	struct rb_node *n;
+
+	for (n = rb_first(&dev->buffers); n; n = rb_next(n)) {
+		struct ion_buffer *buffer =
+				rb_entry(n, struct ion_buffer, node);
+		if (buffer->heap->id == heap->id) {
+			struct mem_map_data *data =
+					kzalloc(sizeof(*data), GFP_KERNEL);
+			if (!data) {
+				seq_printf(s, "ERROR: out of memory. "
+					   "Part of memory map will not be logged\n");
+				break;
+			}
+			data->addr = buffer->priv_phys;
+			data->addr_end = buffer->priv_phys + buffer->size-1;
+			data->size = buffer->size;
+			data->client_name = ion_debug_locate_owner(dev, buffer);
+			ion_debug_mem_map_add(mem_map, data);
+		}
+	}
+}
+
+/**
+ * Free the memory allocated by ion_debug_mem_map_create
+ * @param mem_map The mem map to free.
+ */
+static void ion_debug_mem_map_destroy(struct rb_root *mem_map)
+{
+	if (mem_map) {
+		struct rb_node *n;
+		while ((n = rb_first(mem_map)) != 0) {
+			struct mem_map_data *data =
+					rb_entry(n, struct mem_map_data, node);
+			rb_erase(&data->node, mem_map);
+			kfree(data);
+		}
+	}
+}
+
+/**
+ * Print heap debug information.
+ * @param s seq_file to log message to.
+ * @param heap pointer to heap that we will print debug information for.
+ */
+static void ion_heap_print_debug(struct seq_file *s, struct ion_heap *heap)
+{
+	if (heap->ops->print_debug) {
+		struct rb_root mem_map = RB_ROOT;
+		ion_debug_mem_map_create(s, heap, &mem_map);
+		heap->ops->print_debug(heap, s, &mem_map);
+		ion_debug_mem_map_destroy(&mem_map);
+	}
+}
+
 static int ion_debug_heap_show(struct seq_file *s, void *unused)
 {
 	struct ion_heap *heap = s->private;
 	struct ion_device *dev = heap->dev;
 	struct rb_node *n;
 
+	mutex_lock(&dev->lock);
 	seq_printf(s, "%16.s %16.s %16.s\n", "client", "pid", "size");
 	for (n = rb_first(&dev->user_clients); n; n = rb_next(n)) {
 		struct ion_client *client = rb_entry(n, struct ion_client,
@@ -1681,8 +1849,8 @@
 		seq_printf(s, "%16.s %16u %16x\n", client->name, client->pid,
 			   size);
 	}
-	if (heap->ops->print_debug)
-		heap->ops->print_debug(heap, s);
+	ion_heap_print_debug(s, heap);
+	mutex_unlock(&dev->lock);
 	return 0;
 }
 
diff --git a/drivers/gpu/ion/ion_carveout_heap.c b/drivers/gpu/ion/ion_carveout_heap.c
index ca2380b..3561a8a 100644
--- a/drivers/gpu/ion/ion_carveout_heap.c
+++ b/drivers/gpu/ion/ion_carveout_heap.c
@@ -30,6 +30,7 @@
 
 #include <mach/iommu_domains.h>
 #include <asm/mach/map.h>
+#include <asm/cacheflush.h>
 
 struct ion_carveout_heap {
 	struct ion_heap heap;
@@ -41,6 +42,7 @@
 	int (*release_region)(void *);
 	atomic_t map_count;
 	void *bus_id;
+	unsigned int has_outer_cache;
 };
 
 ion_phys_addr_t ion_carveout_allocate(struct ion_heap *heap,
@@ -229,29 +231,36 @@
 			void *vaddr, unsigned int offset, unsigned int length,
 			unsigned int cmd)
 {
-	unsigned long vstart, pstart;
-
-	pstart = buffer->priv_phys + offset;
-	vstart = (unsigned long)vaddr;
+	void (*outer_cache_op)(phys_addr_t, phys_addr_t);
+	struct ion_carveout_heap *carveout_heap =
+	     container_of(heap, struct  ion_carveout_heap, heap);
 
 	switch (cmd) {
 	case ION_IOC_CLEAN_CACHES:
-		clean_caches(vstart, length, pstart);
+		dmac_clean_range(vaddr, vaddr + length);
+		outer_cache_op = outer_clean_range;
 		break;
 	case ION_IOC_INV_CACHES:
-		invalidate_caches(vstart, length, pstart);
+		dmac_inv_range(vaddr, vaddr + length);
+		outer_cache_op = outer_inv_range;
 		break;
 	case ION_IOC_CLEAN_INV_CACHES:
-		clean_and_invalidate_caches(vstart, length, pstart);
+		dmac_flush_range(vaddr, vaddr + length);
+		outer_cache_op = outer_flush_range;
 		break;
 	default:
 		return -EINVAL;
 	}
 
+	if (carveout_heap->has_outer_cache) {
+		unsigned long pstart = buffer->priv_phys + offset;
+		outer_cache_op(pstart, pstart + length);
+	}
 	return 0;
 }
 
-static int ion_carveout_print_debug(struct ion_heap *heap, struct seq_file *s)
+static int ion_carveout_print_debug(struct ion_heap *heap, struct seq_file *s,
+				    const struct rb_root *mem_map)
 {
 	struct ion_carveout_heap *carveout_heap =
 		container_of(heap, struct ion_carveout_heap, heap);
@@ -260,6 +269,44 @@
 		carveout_heap->allocated_bytes);
 	seq_printf(s, "total heap size: %lx\n", carveout_heap->total_size);
 
+	if (mem_map) {
+		unsigned long base = carveout_heap->base;
+		unsigned long size = carveout_heap->total_size;
+		unsigned long end = base+size;
+		unsigned long last_end = base;
+		struct rb_node *n;
+
+		seq_printf(s, "\nMemory Map\n");
+		seq_printf(s, "%16.s %14.s %14.s %14.s\n",
+			   "client", "start address", "end address",
+			   "size (hex)");
+
+		for (n = rb_first(mem_map); n; n = rb_next(n)) {
+			struct mem_map_data *data =
+					rb_entry(n, struct mem_map_data, node);
+			const char *client_name = "(null)";
+
+			if (last_end < data->addr) {
+				seq_printf(s, "%16.s %14lx %14lx %14lu (%lx)\n",
+					   "FREE", last_end, data->addr-1,
+					   data->addr-last_end,
+					   data->addr-last_end);
+			}
+
+			if (data->client_name)
+				client_name = data->client_name;
+
+			seq_printf(s, "%16.s %14lx %14lx %14lu (%lx)\n",
+				   client_name, data->addr,
+				   data->addr_end,
+				   data->size, data->size);
+			last_end = data->addr_end+1;
+		}
+		if (last_end < end) {
+			seq_printf(s, "%16.s %14lx %14lx %14lu (%lx)\n", "FREE",
+				last_end, end-1, end-last_end, end-last_end);
+		}
+	}
 	return 0;
 }
 
@@ -287,13 +334,12 @@
 
 	extra = iova_length - buffer->size;
 
-	data->iova_addr = msm_allocate_iova_address(domain_num, partition_num,
-						data->mapped_size, align);
+	ret = msm_allocate_iova_address(domain_num, partition_num,
+						data->mapped_size, align,
+						&data->iova_addr);
 
-	if (!data->iova_addr) {
-		ret = -ENOMEM;
+	if (ret)
 		goto out;
-	}
 
 	domain = msm_get_iommu_domain(domain_num);
 
@@ -409,6 +455,7 @@
 	carveout_heap->heap.type = ION_HEAP_TYPE_CARVEOUT;
 	carveout_heap->allocated_bytes = 0;
 	carveout_heap->total_size = heap_data->size;
+	carveout_heap->has_outer_cache = heap_data->has_outer_cache;
 
 	if (heap_data->extra_data) {
 		struct ion_co_heap_pdata *extra_data =
diff --git a/drivers/gpu/ion/ion_cp_heap.c b/drivers/gpu/ion/ion_cp_heap.c
index 7f57fe6..1c50c04 100644
--- a/drivers/gpu/ion/ion_cp_heap.c
+++ b/drivers/gpu/ion/ion_cp_heap.c
@@ -34,6 +34,7 @@
  #include "ion_priv.h"
 
 #include <asm/mach/map.h>
+#include <asm/cacheflush.h>
 
 /**
  * struct ion_cp_heap - container for the heap and shared heap data
@@ -66,7 +67,8 @@
  * @reserved_vrange: reserved virtual address range for use with fmem
  * @iommu_map_all:	Indicates whether we should map whole heap into IOMMU.
  * @iommu_2x_map_domain: Indicates the domain to use for overmapping.
- */
+ * @has_outer_cache:    set to 1 if outer cache is used, 0 otherwise.
+*/
 struct ion_cp_heap {
 	struct ion_heap heap;
 	struct gen_pool *pool;
@@ -90,7 +92,7 @@
 	void *reserved_vrange;
 	int iommu_map_all;
 	int iommu_2x_map_domain;
-
+	unsigned int has_outer_cache;
 };
 
 enum {
@@ -243,7 +245,8 @@
 				cp_heap->total_size -
 				cp_heap->allocated_bytes, size);
 
-		if (cp_heap->reusable && !cp_heap->allocated_bytes) {
+		if (cp_heap->reusable && !cp_heap->allocated_bytes &&
+		    cp_heap->heap_protected == HEAP_NOT_PROTECTED) {
 			if (fmem_set_state(FMEM_T_STATE) != 0)
 				pr_err("%s: unable to transition heap to T-state\n",
 					__func__);
@@ -293,7 +296,8 @@
 	mutex_lock(&cp_heap->lock);
 	cp_heap->allocated_bytes -= size;
 
-	if (cp_heap->reusable && !cp_heap->allocated_bytes) {
+	if (cp_heap->reusable && !cp_heap->allocated_bytes &&
+	    cp_heap->heap_protected == HEAP_NOT_PROTECTED) {
 		if (fmem_set_state(FMEM_T_STATE) != 0)
 			pr_err("%s: unable to transition heap to T-state\n",
 				__func__);
@@ -539,29 +543,36 @@
 			void *vaddr, unsigned int offset, unsigned int length,
 			unsigned int cmd)
 {
-	unsigned long vstart, pstart;
-
-	pstart = buffer->priv_phys + offset;
-	vstart = (unsigned long)vaddr;
+	void (*outer_cache_op)(phys_addr_t, phys_addr_t);
+	struct ion_cp_heap *cp_heap =
+	     container_of(heap, struct  ion_cp_heap, heap);
 
 	switch (cmd) {
 	case ION_IOC_CLEAN_CACHES:
-		clean_caches(vstart, length, pstart);
+		dmac_clean_range(vaddr, vaddr + length);
+		outer_cache_op = outer_clean_range;
 		break;
 	case ION_IOC_INV_CACHES:
-		invalidate_caches(vstart, length, pstart);
+		dmac_inv_range(vaddr, vaddr + length);
+		outer_cache_op = outer_inv_range;
 		break;
 	case ION_IOC_CLEAN_INV_CACHES:
-		clean_and_invalidate_caches(vstart, length, pstart);
+		dmac_flush_range(vaddr, vaddr + length);
+		outer_cache_op = outer_flush_range;
 		break;
 	default:
 		return -EINVAL;
 	}
 
+	if (cp_heap->has_outer_cache) {
+		unsigned long pstart = buffer->priv_phys + offset;
+		outer_cache_op(pstart, pstart + length);
+	}
 	return 0;
 }
 
-static int ion_cp_print_debug(struct ion_heap *heap, struct seq_file *s)
+static int ion_cp_print_debug(struct ion_heap *heap, struct seq_file *s,
+			      const struct rb_root *mem_map)
 {
 	unsigned long total_alloc;
 	unsigned long total_size;
@@ -586,6 +597,45 @@
 	seq_printf(s, "heap protected: %s\n", heap_protected ? "Yes" : "No");
 	seq_printf(s, "reusable: %s\n", cp_heap->reusable  ? "Yes" : "No");
 
+	if (mem_map) {
+		unsigned long base = cp_heap->base;
+		unsigned long size = cp_heap->total_size;
+		unsigned long end = base+size;
+		unsigned long last_end = base;
+		struct rb_node *n;
+
+		seq_printf(s, "\nMemory Map\n");
+		seq_printf(s, "%16.s %14.s %14.s %14.s\n",
+			   "client", "start address", "end address",
+			   "size (hex)");
+
+		for (n = rb_first(mem_map); n; n = rb_next(n)) {
+			struct mem_map_data *data =
+					rb_entry(n, struct mem_map_data, node);
+			const char *client_name = "(null)";
+
+			if (last_end < data->addr) {
+				seq_printf(s, "%16.s %14lx %14lx %14lu (%lx)\n",
+					   "FREE", last_end, data->addr-1,
+					   data->addr-last_end,
+					   data->addr-last_end);
+			}
+
+			if (data->client_name)
+				client_name = data->client_name;
+
+			seq_printf(s, "%16.s %14lx %14lx %14lu (%lx)\n",
+				   client_name, data->addr,
+				   data->addr_end,
+				   data->size, data->size);
+			last_end = data->addr_end+1;
+		}
+		if (last_end < end) {
+			seq_printf(s, "%16.s %14lx %14lx %14lu (%lx)\n", "FREE",
+				last_end, end-1, end-last_end, end-last_end);
+		}
+	}
+
 	return 0;
 }
 
@@ -645,13 +695,15 @@
 	}
 	if (!ret_value && domain) {
 		unsigned long temp_phys = cp_heap->base;
-		unsigned long temp_iova =
-				msm_allocate_iova_address(domain_num, partition,
-						virt_addr_len, SZ_64K);
-		if (!temp_iova) {
+		unsigned long temp_iova;
+
+		ret_value = msm_allocate_iova_address(domain_num, partition,
+						virt_addr_len, SZ_64K,
+						&temp_iova);
+
+		if (ret_value) {
 			pr_err("%s: could not allocate iova from domain %lu, partition %d\n",
 				__func__, domain_num, partition);
-			ret_value = -ENOMEM;
 			goto out;
 		}
 		cp_heap->iommu_iova[domain_num] = temp_iova;
@@ -740,13 +792,12 @@
 
 	extra = iova_length - buffer->size;
 
-	data->iova_addr = msm_allocate_iova_address(domain_num, partition_num,
-						data->mapped_size, align);
+	ret = msm_allocate_iova_address(domain_num, partition_num,
+						data->mapped_size, align,
+						&data->iova_addr);
 
-	if (!data->iova_addr) {
-		ret = -ENOMEM;
+	if (ret)
 		goto out;
-	}
 
 	domain = msm_get_iommu_domain(domain_num);
 
@@ -872,6 +923,7 @@
 	cp_heap->heap_protected = HEAP_NOT_PROTECTED;
 	cp_heap->secure_base = cp_heap->base;
 	cp_heap->secure_size = heap_data->size;
+	cp_heap->has_outer_cache = heap_data->has_outer_cache;
 	if (heap_data->extra_data) {
 		struct ion_cp_heap_pdata *extra_data =
 				heap_data->extra_data;
@@ -916,6 +968,14 @@
 	cp_heap = NULL;
 }
 
+void ion_cp_heap_get_base(struct ion_heap *heap, unsigned long *base,
+		unsigned long *size) \
+{
+	struct ion_cp_heap *cp_heap =
+	     container_of(heap, struct  ion_cp_heap, heap);
+	*base = cp_heap->base;
+	*size = cp_heap->total_size;
+}
 
 /*  SCM related code for locking down memory for content protection */
 
diff --git a/drivers/gpu/ion/ion_iommu_heap.c b/drivers/gpu/ion/ion_iommu_heap.c
index 312ca42..621144b 100644
--- a/drivers/gpu/ion/ion_iommu_heap.c
+++ b/drivers/gpu/ion/ion_iommu_heap.c
@@ -23,10 +23,12 @@
 
 #include <asm/mach/map.h>
 #include <asm/page.h>
+#include <asm/cacheflush.h>
 #include <mach/iommu_domains.h>
 
 struct ion_iommu_heap {
 	struct ion_heap heap;
+	unsigned int has_outer_cache;
 };
 
 struct ion_iommu_priv_data {
@@ -190,13 +192,12 @@
 	data->mapped_size = iova_length;
 	extra = iova_length - buffer->size;
 
-	data->iova_addr = msm_allocate_iova_address(domain_num, partition_num,
-						data->mapped_size, align);
+	ret = msm_allocate_iova_address(domain_num, partition_num,
+						data->mapped_size, align,
+						&data->iova_addr);
 
-	if (!data->iova_addr) {
-		ret = -ENOMEM;
+	if (!data->iova_addr)
 		goto out;
-	}
 
 	domain = msm_get_iommu_domain(domain_num);
 
@@ -262,34 +263,39 @@
 			void *vaddr, unsigned int offset, unsigned int length,
 			unsigned int cmd)
 {
-	unsigned long vstart, pstart;
-	void (*op)(unsigned long, unsigned long, unsigned long);
-	unsigned int i;
-	struct ion_iommu_priv_data *data = buffer->priv_virt;
-
-	if (!data)
-		return -ENOMEM;
+	void (*outer_cache_op)(phys_addr_t, phys_addr_t);
+	struct ion_iommu_heap *iommu_heap =
+	     container_of(heap, struct  ion_iommu_heap, heap);
 
 	switch (cmd) {
 	case ION_IOC_CLEAN_CACHES:
-		op = clean_caches;
+		dmac_clean_range(vaddr, vaddr + length);
+		outer_cache_op = outer_clean_range;
 		break;
 	case ION_IOC_INV_CACHES:
-		op = invalidate_caches;
+		dmac_inv_range(vaddr, vaddr + length);
+		outer_cache_op = outer_inv_range;
 		break;
 	case ION_IOC_CLEAN_INV_CACHES:
-		op = clean_and_invalidate_caches;
+		dmac_flush_range(vaddr, vaddr + length);
+		outer_cache_op = outer_flush_range;
 		break;
 	default:
 		return -EINVAL;
 	}
 
-	vstart = (unsigned long) vaddr;
-	for (i = 0; i < data->nrpages; ++i, vstart += PAGE_SIZE) {
-		pstart = page_to_phys(data->pages[i]);
-		op(vstart, PAGE_SIZE, pstart);
-	}
+	if (iommu_heap->has_outer_cache) {
+		unsigned long pstart;
+		unsigned int i;
+		struct ion_iommu_priv_data *data = buffer->priv_virt;
+		if (!data)
+			return -ENOMEM;
 
+		for (i = 0; i < data->nrpages; ++i) {
+			pstart = page_to_phys(data->pages[i]);
+			outer_cache_op(pstart, pstart + PAGE_SIZE);
+		}
+	}
 	return 0;
 }
 
@@ -328,6 +334,7 @@
 
 	iommu_heap->heap.ops = &iommu_heap_ops;
 	iommu_heap->heap.type = ION_HEAP_TYPE_IOMMU;
+	iommu_heap->has_outer_cache = heap_data->has_outer_cache;
 
 	return &iommu_heap->heap;
 }
diff --git a/drivers/gpu/ion/ion_priv.h b/drivers/gpu/ion/ion_priv.h
index 98e11cf..00ce33f 100644
--- a/drivers/gpu/ion/ion_priv.h
+++ b/drivers/gpu/ion/ion_priv.h
@@ -155,7 +155,8 @@
 				unsigned long iova_length,
 				unsigned long flags);
 	void (*unmap_iommu)(struct ion_iommu_map *data);
-	int (*print_debug)(struct ion_heap *heap, struct seq_file *s);
+	int (*print_debug)(struct ion_heap *heap, struct seq_file *s,
+			   const struct rb_root *mem_map);
 	int (*secure_heap)(struct ion_heap *heap);
 	int (*unsecure_heap)(struct ion_heap *heap);
 };
@@ -185,7 +186,22 @@
 	const char *name;
 };
 
-
+/**
+ * struct mem_map_data - represents information about the memory map for a heap
+ * @node:		rb node used to store in the tree of mem_map_data
+ * @addr:		start address of memory region.
+ * @addr:		end address of memory region.
+ * @size:		size of memory region
+ * @client_name:		name of the client who owns this buffer.
+ *
+ */
+struct mem_map_data {
+	struct rb_node node;
+	unsigned long addr;
+	unsigned long addr_end;
+	unsigned long size;
+	const char *client_name;
+};
 
 #define iommu_map_domain(__m)		((__m)->domain_info[1])
 #define iommu_map_partition(__m)	((__m)->domain_info[0])
@@ -298,4 +314,9 @@
 			void *uaddr, unsigned long offset, unsigned long len,
 			unsigned int cmd);
 
+void ion_cp_heap_get_base(struct ion_heap *heap, unsigned long *base,
+			unsigned long *size);
+
+void ion_mem_map_show(struct ion_heap *heap);
+
 #endif /* _ION_PRIV_H */
diff --git a/drivers/gpu/ion/ion_system_heap.c b/drivers/gpu/ion/ion_system_heap.c
index ed9ae27..08b271b 100644
--- a/drivers/gpu/ion/ion_system_heap.c
+++ b/drivers/gpu/ion/ion_system_heap.c
@@ -26,9 +26,12 @@
 #include <mach/iommu_domains.h>
 #include "ion_priv.h"
 #include <mach/memory.h>
+#include <asm/cacheflush.h>
 
 static atomic_t system_heap_allocated;
 static atomic_t system_contig_heap_allocated;
+static unsigned int system_heap_has_outer_cache;
+static unsigned int system_heap_contig_has_outer_cache;
 
 static int ion_system_heap_allocate(struct ion_heap *heap,
 				     struct ion_buffer *buffer,
@@ -144,67 +147,71 @@
 			void *vaddr, unsigned int offset, unsigned int length,
 			unsigned int cmd)
 {
-	unsigned long vstart, pstart;
-	void *vend;
-	void *vtemp;
-	unsigned long ln = 0;
-	void (*op)(unsigned long, unsigned long, unsigned long);
+	void (*outer_cache_op)(phys_addr_t, phys_addr_t);
 
 	switch (cmd) {
 	case ION_IOC_CLEAN_CACHES:
-		op = clean_caches;
+		dmac_clean_range(vaddr, vaddr + length);
+		outer_cache_op = outer_clean_range;
 		break;
 	case ION_IOC_INV_CACHES:
-		op = invalidate_caches;
+		dmac_inv_range(vaddr, vaddr + length);
+		outer_cache_op = outer_inv_range;
 		break;
 	case ION_IOC_CLEAN_INV_CACHES:
-		op = clean_and_invalidate_caches;
+		dmac_flush_range(vaddr, vaddr + length);
+		outer_cache_op = outer_flush_range;
 		break;
 	default:
 		return -EINVAL;
 	}
 
-	vend = buffer->priv_virt + buffer->size;
-	vtemp = buffer->priv_virt + offset;
+	if (system_heap_has_outer_cache) {
+		unsigned long pstart;
+		void *vend;
+		void *vtemp;
+		unsigned long ln = 0;
+		vend = buffer->priv_virt + buffer->size;
+		vtemp = buffer->priv_virt + offset;
 
-	if ((vtemp+length) > vend) {
-		pr_err("Trying to flush outside of mapped range.\n");
-		pr_err("End of mapped range: %p, trying to flush to "
-			"address %p\n", vend, vtemp+length);
-		WARN(1, "%s: called with heap name %s, buffer size 0x%x, "
-			"vaddr 0x%p, offset 0x%x, length: 0x%x\n", __func__,
-			heap->name, buffer->size, vaddr, offset, length);
-		return -EINVAL;
-	}
-
-	for (vstart = (unsigned long) vaddr;
-			ln < length && vtemp < vend;
-			vtemp += PAGE_SIZE, ln += PAGE_SIZE,
-			vstart += PAGE_SIZE) {
-		struct page *page = vmalloc_to_page(vtemp);
-		if (!page) {
-			WARN(1, "Could not find page for virt. address %p\n",
-				vtemp);
-			return -EINVAL;
-		}
-		pstart = page_to_phys(page);
-		/*
-		 * If page -> phys is returning NULL, something
-		 * has really gone wrong...
-		 */
-		if (!pstart) {
-			WARN(1, "Could not translate %p to physical address\n",
-				vtemp);
+		if ((vtemp+length) > vend) {
+			pr_err("Trying to flush outside of mapped range.\n");
+			pr_err("End of mapped range: %p, trying to flush to "
+				"address %p\n", vend, vtemp+length);
+			WARN(1, "%s: called with heap name %s, buffer size 0x%x, "
+				"vaddr 0x%p, offset 0x%x, length: 0x%x\n",
+				__func__, heap->name, buffer->size, vaddr,
+				offset, length);
 			return -EINVAL;
 		}
 
-		op(vstart, PAGE_SIZE, pstart);
-	}
+		for (; ln < length && vtemp < vend;
+		      vtemp += PAGE_SIZE, ln += PAGE_SIZE) {
+			struct page *page = vmalloc_to_page(vtemp);
+			if (!page) {
+				WARN(1, "Could not find page for virt. address %p\n",
+					vtemp);
+				return -EINVAL;
+			}
+			pstart = page_to_phys(page);
+			/*
+			 * If page -> phys is returning NULL, something
+			 * has really gone wrong...
+			 */
+			if (!pstart) {
+				WARN(1, "Could not translate %p to physical address\n",
+					vtemp);
+				return -EINVAL;
+			}
 
+			outer_cache_op(pstart, pstart + PAGE_SIZE);
+		}
+	}
 	return 0;
 }
 
-static int ion_system_print_debug(struct ion_heap *heap, struct seq_file *s)
+static int ion_system_print_debug(struct ion_heap *heap, struct seq_file *s,
+				  const struct rb_root *unused)
 {
 	seq_printf(s, "total bytes currently allocated: %lx\n",
 			(unsigned long) atomic_read(&system_heap_allocated));
@@ -240,13 +247,12 @@
 	data->mapped_size = iova_length;
 	extra = iova_length - buffer->size;
 
-	data->iova_addr = msm_allocate_iova_address(domain_num, partition_num,
-						data->mapped_size, align);
+	ret = msm_allocate_iova_address(domain_num, partition_num,
+						data->mapped_size, align,
+						&data->iova_addr);
 
-	if (!data->iova_addr) {
-		ret = -ENOMEM;
+	if (ret)
 		goto out;
-	}
 
 	domain = msm_get_iommu_domain(domain_num);
 
@@ -314,7 +320,7 @@
 	.unmap_iommu = ion_system_heap_unmap_iommu,
 };
 
-struct ion_heap *ion_system_heap_create(struct ion_platform_heap *unused)
+struct ion_heap *ion_system_heap_create(struct ion_platform_heap *pheap)
 {
 	struct ion_heap *heap;
 
@@ -323,6 +329,7 @@
 		return ERR_PTR(-ENOMEM);
 	heap->ops = &vmalloc_ops;
 	heap->type = ION_HEAP_TYPE_SYSTEM;
+	system_heap_has_outer_cache = pheap->has_outer_cache;
 	return heap;
 }
 
@@ -394,36 +401,44 @@
 			unsigned int offset, unsigned int length,
 			unsigned int cmd)
 {
-	unsigned long vstart, pstart;
-
-	pstart = virt_to_phys(buffer->priv_virt) + offset;
-	if (!pstart) {
-		WARN(1, "Could not do virt to phys translation on %p\n",
-			buffer->priv_virt);
-		return -EINVAL;
-	}
-
-	vstart = (unsigned long) vaddr;
+	void (*outer_cache_op)(phys_addr_t, phys_addr_t);
 
 	switch (cmd) {
 	case ION_IOC_CLEAN_CACHES:
-		clean_caches(vstart, length, pstart);
+		dmac_clean_range(vaddr, vaddr + length);
+		outer_cache_op = outer_clean_range;
 		break;
 	case ION_IOC_INV_CACHES:
-		invalidate_caches(vstart, length, pstart);
+		dmac_inv_range(vaddr, vaddr + length);
+		outer_cache_op = outer_inv_range;
 		break;
 	case ION_IOC_CLEAN_INV_CACHES:
-		clean_and_invalidate_caches(vstart, length, pstart);
+		dmac_flush_range(vaddr, vaddr + length);
+		outer_cache_op = outer_flush_range;
 		break;
 	default:
 		return -EINVAL;
 	}
 
+	if (system_heap_contig_has_outer_cache) {
+		unsigned long pstart;
+
+		pstart = virt_to_phys(buffer->priv_virt) + offset;
+		if (!pstart) {
+			WARN(1, "Could not do virt to phys translation on %p\n",
+				buffer->priv_virt);
+			return -EINVAL;
+		}
+
+		outer_cache_op(pstart, pstart + PAGE_SIZE);
+	}
+
 	return 0;
 }
 
 static int ion_system_contig_print_debug(struct ion_heap *heap,
-					 struct seq_file *s)
+					 struct seq_file *s,
+					 const struct rb_root *unused)
 {
 	seq_printf(s, "total bytes currently allocated: %lx\n",
 		(unsigned long) atomic_read(&system_contig_heap_allocated));
@@ -458,13 +473,12 @@
 	data->mapped_size = iova_length;
 	extra = iova_length - buffer->size;
 
-	data->iova_addr = msm_allocate_iova_address(domain_num, partition_num,
-						data->mapped_size, align);
+	ret = msm_allocate_iova_address(domain_num, partition_num,
+						data->mapped_size, align,
+						&data->iova_addr);
 
-	if (!data->iova_addr) {
-		ret = -ENOMEM;
+	if (ret)
 		goto out;
-	}
 
 	domain = msm_get_iommu_domain(domain_num);
 
@@ -524,7 +538,7 @@
 	.unmap_iommu = ion_system_heap_unmap_iommu,
 };
 
-struct ion_heap *ion_system_contig_heap_create(struct ion_platform_heap *unused)
+struct ion_heap *ion_system_contig_heap_create(struct ion_platform_heap *pheap)
 {
 	struct ion_heap *heap;
 
@@ -533,6 +547,7 @@
 		return ERR_PTR(-ENOMEM);
 	heap->ops = &kmalloc_ops;
 	heap->type = ION_HEAP_TYPE_SYSTEM_CONTIG;
+	system_heap_contig_has_outer_cache = pheap->has_outer_cache;
 	return heap;
 }
 
diff --git a/drivers/gpu/ion/msm/msm_ion.c b/drivers/gpu/ion/msm/msm_ion.c
index c8bfce3..83afb25 100644
--- a/drivers/gpu/ion/msm/msm_ion.c
+++ b/drivers/gpu/ion/msm/msm_ion.c
@@ -136,9 +136,11 @@
 				}
 
 				cp_data->virt_addr = fmem_info->virt;
-				cp_data->secure_base = heap->base;
-				cp_data->secure_size =
+				if (!cp_data->secure_base) {
+					cp_data->secure_base = heap->base;
+					cp_data->secure_size =
 						heap->size + shared_heap->size;
+				}
 			} else if (!heap->base) {
 				ion_set_base_address(heap, shared_heap,
 					co_heap_data, cp_data);
@@ -280,6 +282,7 @@
 		struct ion_platform_heap *heap_data = &pdata->heaps[i];
 		msm_ion_allocate(heap_data);
 
+		heap_data->has_outer_cache = pdata->has_outer_cache;
 		heaps[i] = ion_heap_create(heap_data);
 		if (IS_ERR_OR_NULL(heaps[i])) {
 			heaps[i] = 0;
diff --git a/drivers/gpu/msm/a3xx_reg.h b/drivers/gpu/msm/a3xx_reg.h
index 0a71982..35af06e 100644
--- a/drivers/gpu/msm/a3xx_reg.h
+++ b/drivers/gpu/msm/a3xx_reg.h
@@ -248,6 +248,10 @@
 #define A3XX_VBIF_ARB_CTL 0x303C
 #define A3XX_VBIF_OUT_AXI_AOOO_EN 0x305E
 #define A3XX_VBIF_OUT_AXI_AOOO 0x305F
+#define A3XX_VBIF_ERR_PENDING  0x3064
+#define A3XX_VBIF_ERR_MASK 0x3066
+#define A3XX_VBIF_ERR_CLEAR 0x3067
+#define A3XX_VBIF_ERR_INFO 0x3068
 
 /* Bit flags for RBBM_CTL */
 #define RBBM_RBBM_CTL_RESET_PWR_CTR1  (1 << 1)
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 96390ac..2f503ae 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -21,6 +21,7 @@
 #include "kgsl_pwrscale.h"
 #include "kgsl_cffdump.h"
 #include "kgsl_sharedmem.h"
+#include "kgsl_iommu.h"
 
 #include "adreno.h"
 #include "adreno_pm4types.h"
@@ -158,7 +159,7 @@
 		"a300_pm4.fw", "a300_pfp.fw", &adreno_a3xx_gpudev,
 		512, 0, 2, SZ_256K },
 	/* A3XX doesn't use the pix_shader_start */
-	{ ADRENO_REV_A320, 3, 2, 0, 0,
+	{ ADRENO_REV_A320, 3, 2, 0, ANY_ID,
 		"a300_pm4.fw", "a300_pfp.fw", &adreno_a3xx_gpudev,
 		512, 0, 2, SZ_512K },
 
@@ -243,7 +244,144 @@
 	return result;
 }
 
-static void adreno_setstate(struct kgsl_device *device,
+static void adreno_iommu_setstate(struct kgsl_device *device,
+					uint32_t flags)
+{
+	unsigned int pt_val, reg_pt_val;
+	unsigned int link[200];
+	unsigned int *cmds = &link[0];
+	int sizedwords = 0;
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	struct kgsl_memdesc **reg_map_desc;
+	void *reg_map_array;
+	int num_iommu_units, i;
+
+	if (!adreno_dev->drawctxt_active)
+		return kgsl_mmu_device_setstate(&device->mmu, flags);
+	num_iommu_units = kgsl_mmu_get_reg_map_desc(&device->mmu,
+							&reg_map_array);
+	reg_map_desc = reg_map_array;
+
+	if (kgsl_mmu_enable_clk(&device->mmu,
+				KGSL_IOMMU_CONTEXT_USER))
+		goto done;
+
+	if (adreno_is_a225(adreno_dev))
+		cmds += adreno_add_change_mh_phys_limit_cmds(cmds, 0xFFFFF000,
+					device->mmu.setstate_memory.gpuaddr +
+					KGSL_IOMMU_SETSTATE_NOP_OFFSET);
+	else
+		cmds += adreno_add_bank_change_cmds(cmds,
+					KGSL_IOMMU_CONTEXT_USER,
+					device->mmu.setstate_memory.gpuaddr +
+					KGSL_IOMMU_SETSTATE_NOP_OFFSET);
+
+	if (flags & KGSL_MMUFLAGS_PTUPDATE) {
+		pt_val = kgsl_mmu_pt_get_base_addr(device->mmu.hwpagetable);
+		/*
+		 * We need to perfrom the following operations for all
+		 * IOMMU units
+		 */
+		for (i = 0; i < num_iommu_units; i++) {
+			reg_pt_val = (pt_val &
+				(KGSL_IOMMU_TTBR0_PA_MASK <<
+				KGSL_IOMMU_TTBR0_PA_SHIFT)) +
+				kgsl_mmu_get_pt_lsb(&device->mmu, i,
+					KGSL_IOMMU_CONTEXT_USER);
+			/*
+			 * Set address of the new pagetable by writng to IOMMU
+			 * TTBR0 register
+			 */
+			*cmds++ = cp_type3_packet(CP_MEM_WRITE, 2);
+			*cmds++ = reg_map_desc[i]->gpuaddr +
+				(KGSL_IOMMU_CONTEXT_USER <<
+				KGSL_IOMMU_CTX_SHIFT) + KGSL_IOMMU_TTBR0;
+			*cmds++ = reg_pt_val;
+			*cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
+			*cmds++ = 0x00000000;
+
+			/*
+			 * Read back the ttbr0 register as a barrier to ensure
+			 * above writes have completed
+			 */
+			cmds += adreno_add_read_cmds(device, cmds,
+				reg_map_desc[i]->gpuaddr +
+				(KGSL_IOMMU_CONTEXT_USER <<
+				KGSL_IOMMU_CTX_SHIFT) + KGSL_IOMMU_TTBR0,
+				reg_pt_val,
+				device->mmu.setstate_memory.gpuaddr +
+				KGSL_IOMMU_SETSTATE_NOP_OFFSET);
+
+			/* set the asid */
+			*cmds++ = cp_type3_packet(CP_MEM_WRITE, 2);
+			*cmds++ = reg_map_desc[i]->gpuaddr +
+				(KGSL_IOMMU_CONTEXT_USER <<
+				KGSL_IOMMU_CTX_SHIFT) + KGSL_IOMMU_CONTEXTIDR;
+			*cmds++ = kgsl_mmu_get_hwpagetable_asid(&device->mmu);
+			*cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
+			*cmds++ = 0x00000000;
+
+			/* Read back asid to ensure above write completes */
+			cmds += adreno_add_read_cmds(device, cmds,
+				reg_map_desc[i]->gpuaddr +
+				(KGSL_IOMMU_CONTEXT_USER <<
+				KGSL_IOMMU_CTX_SHIFT) + KGSL_IOMMU_CONTEXTIDR,
+				kgsl_mmu_get_hwpagetable_asid(&device->mmu),
+				device->mmu.setstate_memory.gpuaddr +
+				KGSL_IOMMU_SETSTATE_NOP_OFFSET);
+		}
+		/* invalidate all base pointers */
+		*cmds++ = cp_type3_packet(CP_INVALIDATE_STATE, 1);
+		*cmds++ = 0x7fff;
+
+		if (flags & KGSL_MMUFLAGS_TLBFLUSH)
+			cmds += __adreno_add_idle_indirect_cmds(cmds,
+				device->mmu.setstate_memory.gpuaddr +
+				KGSL_IOMMU_SETSTATE_NOP_OFFSET);
+	}
+	if (flags & KGSL_MMUFLAGS_TLBFLUSH) {
+		/*
+		 * tlb flush based on asid, no need to flush entire tlb
+		 */
+		for (i = 0; i < num_iommu_units; i++) {
+			*cmds++ = cp_type3_packet(CP_MEM_WRITE, 2);
+			*cmds++ = (reg_map_desc[i]->gpuaddr +
+				(KGSL_IOMMU_CONTEXT_USER <<
+				KGSL_IOMMU_CTX_SHIFT) +
+				KGSL_IOMMU_CTX_TLBIASID);
+			*cmds++ = kgsl_mmu_get_hwpagetable_asid(&device->mmu);
+			cmds += adreno_add_read_cmds(device, cmds,
+				reg_map_desc[i]->gpuaddr +
+				(KGSL_IOMMU_CONTEXT_USER <<
+				KGSL_IOMMU_CTX_SHIFT) +
+				KGSL_IOMMU_CONTEXTIDR,
+				kgsl_mmu_get_hwpagetable_asid(&device->mmu),
+				device->mmu.setstate_memory.gpuaddr +
+				KGSL_IOMMU_SETSTATE_NOP_OFFSET);
+		}
+	}
+
+	if (adreno_is_a225(adreno_dev))
+		cmds += adreno_add_change_mh_phys_limit_cmds(cmds,
+			reg_map_desc[num_iommu_units - 1]->gpuaddr - PAGE_SIZE,
+			device->mmu.setstate_memory.gpuaddr +
+			KGSL_IOMMU_SETSTATE_NOP_OFFSET);
+	else
+		cmds += adreno_add_bank_change_cmds(cmds,
+			KGSL_IOMMU_CONTEXT_PRIV,
+			device->mmu.setstate_memory.gpuaddr +
+			KGSL_IOMMU_SETSTATE_NOP_OFFSET);
+
+	sizedwords += (cmds - &link[0]);
+	if (sizedwords)
+		adreno_ringbuffer_issuecmds(device,
+			KGSL_CMD_FLAGS_PMODE, &link[0], sizedwords);
+done:
+	if (num_iommu_units)
+		kfree(reg_map_array);
+}
+
+static void adreno_gpummu_setstate(struct kgsl_device *device,
 					uint32_t flags)
 {
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
@@ -253,16 +391,6 @@
 	unsigned int mh_mmu_invalidate = 0x00000003; /*invalidate all and tc */
 
 	/*
-	 * A3XX doesn't support the fast path (the registers don't even exist)
-	 * so just bail out early
-	 */
-
-	if (adreno_is_a3xx(adreno_dev)) {
-		kgsl_mmu_device_setstate(&device->mmu, flags);
-		return;
-	}
-
-	/*
 	 * If possible, then set the state via the command stream to avoid
 	 * a CPU idle.  Otherwise, use the default setstate which uses register
 	 * writes For CFF dump we must idle and use the registers so that it is
@@ -348,6 +476,16 @@
 	}
 }
 
+static void adreno_setstate(struct kgsl_device *device,
+			uint32_t flags)
+{
+	/* call the mmu specific handler */
+	if (KGSL_MMU_TYPE_GPU == kgsl_mmu_get_mmutype())
+		return adreno_gpummu_setstate(device, flags);
+	else if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype())
+		return adreno_iommu_setstate(device, flags);
+}
+
 static unsigned int
 a3xx_getchipid(struct kgsl_device *device)
 {
@@ -362,10 +500,22 @@
 	 */
 
 	if (cpu_is_apq8064()) {
+		unsigned int version = socinfo_get_version();
+
 		/* A320 */
 		majorid = 2;
 		minorid = 0;
-		patchid = 0;
+
+		/*
+		 * V1.1 has some GPU work arounds that we need to communicate
+		 * up to user space via the patchid
+		 */
+
+		if ((SOCINFO_VERSION_MAJOR(version) == 1) &&
+			(SOCINFO_VERSION_MINOR(version) == 1))
+			patchid = 1;
+		else
+			patchid = 0;
 	} else if (cpu_is_msm8930()) {
 		/* A305 */
 		majorid = 0;
@@ -1129,16 +1279,12 @@
 static unsigned int _get_context_id(struct kgsl_context *k_ctxt)
 {
 	unsigned int context_id = KGSL_MEMSTORE_GLOBAL;
-
 	if (k_ctxt != NULL) {
 		struct adreno_context *a_ctxt = k_ctxt->devctxt;
-		/*
-		 * if the context was not created with per context timestamp
-		 * support, we must use the global timestamp since issueibcmds
-		 * will be returning that one.
-		 */
-		if (a_ctxt->flags & CTXT_FLAGS_PER_CONTEXT_TS)
-			context_id = a_ctxt->id;
+		if (k_ctxt->id == KGSL_CONTEXT_INVALID || a_ctxt == NULL)
+			context_id = KGSL_CONTEXT_INVALID;
+		else if (a_ctxt->flags & CTXT_FLAGS_PER_CONTEXT_TS)
+			context_id = k_ctxt->id;
 	}
 
 	return context_id;
@@ -1149,11 +1295,22 @@
 {
 	int status;
 	unsigned int ref_ts, enableflag;
-	unsigned int context_id = _get_context_id(context);
+	unsigned int context_id;
+
+	mutex_lock(&device->mutex);
+	context_id = _get_context_id(context);
+	/*
+	 * If the context ID is invalid, we are in a race with
+	 * the context being destroyed by userspace so bail.
+	 */
+	if (context_id == KGSL_CONTEXT_INVALID) {
+		KGSL_DRV_WARN(device, "context was detached");
+		status = -EINVAL;
+		goto unlock;
+	}
 
 	status = kgsl_check_timestamp(device, context, timestamp);
 	if (!status) {
-		mutex_lock(&device->mutex);
 		kgsl_sharedmem_readl(&device->memstore, &enableflag,
 			KGSL_MEMSTORE_OFFSET(context_id, ts_cmp_enable));
 		mb();
@@ -1187,8 +1344,9 @@
 			adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE,
 				&cmds[0], 2);
 		}
-		mutex_unlock(&device->mutex);
 	}
+unlock:
+	mutex_unlock(&device->mutex);
 
 	return status;
 }
@@ -1247,6 +1405,15 @@
 	msecs_first = (msecs <= 100) ? ((msecs + 4) / 5) : 100;
 	msecs_part = (msecs - msecs_first + 3) / 4;
 	for (retries = 0; retries < 5; retries++) {
+		/*
+		 * If the context ID is invalid, we are in a race with
+		 * the context being destroyed by userspace so bail.
+		 */
+		if (context_id == KGSL_CONTEXT_INVALID) {
+			KGSL_DRV_WARN(device, "context was detached");
+			status = -EINVAL;
+			goto done;
+		}
 		if (kgsl_check_timestamp(device, context, timestamp)) {
 			/* if the timestamp happens while we're not
 			 * waiting, there's a chance that an interrupt
@@ -1308,6 +1475,14 @@
 	unsigned int timestamp = 0;
 	unsigned int context_id = _get_context_id(context);
 
+	/*
+	 * If the context ID is invalid, we are in a race with
+	 * the context being destroyed by userspace so bail.
+	 */
+	if (context_id == KGSL_CONTEXT_INVALID) {
+		KGSL_DRV_WARN(device, "context was detached");
+		return timestamp;
+	}
 	switch (type) {
 	case KGSL_TIMESTAMP_QUEUED: {
 		struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index a7ea20c..4ce56a4 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -16,6 +16,7 @@
 #include "kgsl_device.h"
 #include "adreno_drawctxt.h"
 #include "adreno_ringbuffer.h"
+#include "kgsl_iommu.h"
 
 #define DEVICE_3D_NAME "kgsl-3d"
 #define DEVICE_3D0_NAME "kgsl-3d0"
@@ -223,4 +224,70 @@
 	return (ilog2(size) - 5) << 29;
 }
 
+static inline int __adreno_add_idle_indirect_cmds(unsigned int *cmds,
+						unsigned int nop_gpuaddr)
+{
+	/* Adding an indirect buffer ensures that the prefetch stalls until
+	 * the commands in indirect buffer have completed. We need to stall
+	 * prefetch with a nop indirect buffer when updating pagetables
+	 * because it provides stabler synchronization */
+	*cmds++ = CP_HDR_INDIRECT_BUFFER_PFD;
+	*cmds++ = nop_gpuaddr;
+	*cmds++ = 2;
+	*cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
+	*cmds++ = 0x00000000;
+	return 5;
+}
+
+static inline int adreno_add_change_mh_phys_limit_cmds(unsigned int *cmds,
+						unsigned int new_phys_limit,
+						unsigned int nop_gpuaddr)
+{
+	unsigned int *start = cmds;
+
+	cmds += __adreno_add_idle_indirect_cmds(cmds, nop_gpuaddr);
+	*cmds++ = cp_type0_packet(MH_MMU_MPU_END, 1);
+	*cmds++ = new_phys_limit;
+	cmds += __adreno_add_idle_indirect_cmds(cmds, nop_gpuaddr);
+	return cmds - start;
+}
+
+static inline int adreno_add_bank_change_cmds(unsigned int *cmds,
+					int cur_ctx_bank,
+					unsigned int nop_gpuaddr)
+{
+	unsigned int *start = cmds;
+
+	cmds += __adreno_add_idle_indirect_cmds(cmds, nop_gpuaddr);
+	*cmds++ = cp_type0_packet(REG_CP_STATE_DEBUG_INDEX, 1);
+	*cmds++ = (cur_ctx_bank ? 0 : 0x20);
+	cmds += __adreno_add_idle_indirect_cmds(cmds, nop_gpuaddr);
+	return cmds - start;
+}
+
+/*
+ * adreno_read_cmds - Add pm4 packets to perform read
+ * @device - Pointer to device structure
+ * @cmds - Pointer to memory where read commands need to be added
+ * @addr - gpu address of the read
+ * @val - The GPU will wait until the data at address addr becomes
+ * equal to value
+ */
+static inline int adreno_add_read_cmds(struct kgsl_device *device,
+				unsigned int *cmds, unsigned int addr,
+				unsigned int val, unsigned int nop_gpuaddr)
+{
+	unsigned int *start = cmds;
+
+	*cmds++ = cp_type3_packet(CP_WAIT_REG_MEM, 5);
+	/* MEM SPACE = memory, FUNCTION = equals */
+	*cmds++ = 0x13;
+	*cmds++ = addr;
+	*cmds++ = val;
+	*cmds++ = 0xFFFFFFFF;
+	*cmds++ = 0xFFFFFFFF;
+	cmds += __adreno_add_idle_indirect_cmds(cmds, nop_gpuaddr);
+	return cmds - start;
+}
+
 #endif /*__ADRENO_H */
diff --git a/drivers/gpu/msm/adreno_a2xx.c b/drivers/gpu/msm/adreno_a2xx.c
index eb936f8..8a132df 100644
--- a/drivers/gpu/msm/adreno_a2xx.c
+++ b/drivers/gpu/msm/adreno_a2xx.c
@@ -830,9 +830,6 @@
 	*cmds++ = 0x00010000;
 
 	if (adreno_is_a22x(adreno_dev)) {
-		*cmds++ = cp_type3_packet(CP_SET_DRAW_INIT_FLAGS, 1);
-		*cmds++ = 0;
-
 		*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 2);
 		*cmds++ = CP_REG(REG_A220_RB_LRZ_VSC_CONTROL);
 		*cmds++ = 0x0000000;
@@ -1052,9 +1049,6 @@
 	*cmds++ = 0x00010000;
 
 	if (adreno_is_a22x(adreno_dev)) {
-		*cmds++ = cp_type3_packet(CP_SET_DRAW_INIT_FLAGS, 1);
-		*cmds++ = 0;
-
 		*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 2);
 		*cmds++ = CP_REG(REG_A220_RB_LRZ_VSC_CONTROL);
 		*cmds++ = 0x0000000;
@@ -1848,8 +1842,13 @@
 
 	/* NQ and External Memory Swap */
 	GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
-	/* Protected mode error checking */
-	GSL_RB_WRITE(cmds, cmds_gpu, GSL_RB_PROTECTED_MODE_CONTROL);
+	/* Protected mode error checking
+	 * If iommu is used then protection needs to be turned off
+	 * to enable context bank switching */
+	if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype())
+		GSL_RB_WRITE(cmds, cmds_gpu, 0);
+	else
+		GSL_RB_WRITE(cmds, cmds_gpu, GSL_RB_PROTECTED_MODE_CONTROL);
 	/* Disable header dumping and Header dump address */
 	GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
 	/* Header dump size */
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index 5187eb1..8362b65 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -2335,6 +2335,39 @@
 	adreno_ringbuffer_submit(rb);
 }
 
+#define VBIF_MAX_CLIENTS 6
+
+static void a3xx_vbif_callback(struct adreno_device *adreno_dev,
+	unsigned int status)
+{
+	struct kgsl_device *device = &adreno_dev->dev;
+	int i;
+	char str[80], *ptr = str;
+	int slen = sizeof(str) - 1;
+
+	KGSL_DRV_INFO(device, "VBIF error | status=%X\n",
+		status);
+
+	for (i = 0; i < VBIF_MAX_CLIENTS; i++) {
+		if (status & (1 << i)) {
+			unsigned int err;
+			int ret;
+
+			adreno_regwrite(device, A3XX_VBIF_ERR_INFO, i);
+			adreno_regread(device, A3XX_VBIF_ERR_INFO, &err);
+
+			ret = snprintf(ptr, slen, "%d:%8.8X ", i, err);
+			ptr += ret;
+			slen -= ret;
+		}
+	}
+
+	KGSL_DRV_INFO(device, "%s\n", str);
+
+	/* Clear the errors */
+	adreno_regwrite(device, A3XX_VBIF_ERR_CLEAR, status);
+}
+
 static void a3xx_err_callback(struct adreno_device *adreno_dev, int bit)
 {
 	struct kgsl_device *device = &adreno_dev->dev;
@@ -2511,6 +2544,15 @@
 	if (status)
 		adreno_regwrite(&adreno_dev->dev, A3XX_RBBM_INT_CLEAR_CMD,
 			status);
+
+	/* Check for VBIF errors */
+	adreno_regread(&adreno_dev->dev, A3XX_VBIF_ERR_PENDING, &status);
+
+	if (status) {
+		a3xx_vbif_callback(adreno_dev, status);
+		ret = IRQ_HANDLED;
+	}
+
 	return ret;
 }
 
@@ -2518,10 +2560,17 @@
 {
 	struct kgsl_device *device = &adreno_dev->dev;
 
-	if (state)
+	if (state) {
 		adreno_regwrite(device, A3XX_RBBM_INT_0_MASK, A3XX_INT_MASK);
-	else
+
+		/* Enable VBIF interrupts - write 0 to enable them all */
+		adreno_regwrite(device, A3XX_VBIF_ERR_MASK, 0);
+		/* Clear outstanding VBIF errors */
+		adreno_regwrite(device, A3XX_VBIF_ERR_CLEAR, 0x3F);
+	} else {
 		adreno_regwrite(device, A3XX_RBBM_INT_0_MASK, 0);
+		adreno_regwrite(device, A3XX_VBIF_ERR_MASK, 0xFFFFFFFF);
+	}
 }
 
 static unsigned int a3xx_busy_cycles(struct adreno_device *adreno_dev)
diff --git a/drivers/gpu/msm/adreno_postmortem.c b/drivers/gpu/msm/adreno_postmortem.c
index ec38f75..7bb65ca 100644
--- a/drivers/gpu/msm/adreno_postmortem.c
+++ b/drivers/gpu/msm/adreno_postmortem.c
@@ -725,8 +725,8 @@
 				current_context));
 	context = idr_find(&device->context_idr, context_id);
 	if (context) {
-		ts_processed = device->ftbl->readtimestamp(device, context,
-				KGSL_TIMESTAMP_RETIRED);
+		ts_processed = kgsl_readtimestamp(device, context,
+						  KGSL_TIMESTAMP_RETIRED);
 		KGSL_LOG_DUMP(device, "CTXT: %d  TIMESTM RTRD: %08X\n",
 				context->id, ts_processed);
 	} else
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index 8d900b0..3d46221 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -928,8 +928,8 @@
 			" context id is invalid.\n");
 		return -EINVAL;
 	}
-	retired_timestamp = device->ftbl->readtimestamp(device, context,
-				KGSL_TIMESTAMP_RETIRED);
+	retired_timestamp = kgsl_readtimestamp(device, context,
+					       KGSL_TIMESTAMP_RETIRED);
 	KGSL_DRV_ERR(device, "GPU successfully executed till ts: %x\n",
 			retired_timestamp);
 	/*
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index adf2772..662a1c4 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -78,8 +78,7 @@
 		if (context == NULL)
 			return -EINVAL;
 	}
-	cur_ts = device->ftbl->readtimestamp(device, context,
-				KGSL_TIMESTAMP_RETIRED);
+	cur_ts = kgsl_readtimestamp(device, context, KGSL_TIMESTAMP_RETIRED);
 
 	/* Check to see if the requested timestamp has already fired */
 
@@ -135,8 +134,7 @@
 	struct kgsl_event *event, *event_tmp;
 	unsigned int id, cur;
 
-	cur = device->ftbl->readtimestamp(device, context,
-			KGSL_TIMESTAMP_RETIRED);
+	cur = kgsl_readtimestamp(device, context, KGSL_TIMESTAMP_RETIRED);
 	id = context->id;
 
 	list_for_each_entry_safe(event, event_tmp, &device->events, list) {
@@ -173,8 +171,8 @@
 		if (event->owner != owner)
 			continue;
 
-		cur = device->ftbl->readtimestamp(device, event->context,
-				KGSL_TIMESTAMP_RETIRED);
+		cur = kgsl_readtimestamp(device, event->context,
+					 KGSL_TIMESTAMP_RETIRED);
 
 		id = event->context ? event->context->id : KGSL_MEMSTORE_GLOBAL;
 		/*
@@ -363,28 +361,55 @@
 		return NULL;
 	}
 
+	kref_init(&context->refcount);
 	context->id = id;
 	context->dev_priv = dev_priv;
 
 	return context;
 }
 
-static void
-kgsl_destroy_context(struct kgsl_device_private *dev_priv,
-		     struct kgsl_context *context)
+/**
+ * kgsl_context_detach - Release the "master" context reference
+ * @context - The context that will be detached
+ *
+ * This is called when a context becomes unusable, because userspace
+ * has requested for it to be destroyed. The context itself may
+ * exist a bit longer until its reference count goes to zero.
+ * Other code referencing the context can detect that it has been
+ * detached because the context id will be set to KGSL_CONTEXT_INVALID.
+ */
+void
+kgsl_context_detach(struct kgsl_context *context)
 {
 	int id;
-
+	struct kgsl_device *device;
 	if (context == NULL)
 		return;
-
-	/* Fire a bug if the devctxt hasn't been freed */
-	BUG_ON(context->devctxt);
-
+	device = context->dev_priv->device;
+	trace_kgsl_context_detach(device, context);
 	id = context->id;
-	kfree(context);
 
-	idr_remove(&dev_priv->device->context_idr, id);
+	if (device->ftbl->drawctxt_destroy)
+		device->ftbl->drawctxt_destroy(device, context);
+	/*device specific drawctxt_destroy MUST clean up devctxt */
+	BUG_ON(context->devctxt);
+	/*
+	 * Cancel events after the device-specific context is
+	 * destroyed, to avoid possibly freeing memory while
+	 * it is still in use by the GPU.
+	 */
+	kgsl_cancel_events_ctxt(device, context);
+	idr_remove(&device->context_idr, id);
+	context->id = KGSL_CONTEXT_INVALID;
+	kgsl_context_put(context);
+}
+
+void
+kgsl_context_destroy(struct kref *kref)
+{
+	struct kgsl_context *context = container_of(kref, struct kgsl_context,
+						    refcount);
+	kfree(context);
 }
 
 void kgsl_timestamp_expired(struct work_struct *work)
@@ -399,8 +424,8 @@
 
 	/* Process expired events */
 	list_for_each_entry_safe(event, event_tmp, &device->events, list) {
-		ts_processed = device->ftbl->readtimestamp(device,
-				event->context, KGSL_TIMESTAMP_RETIRED);
+		ts_processed = kgsl_readtimestamp(device, event->context,
+						  KGSL_TIMESTAMP_RETIRED);
 		if (timestamp_cmp(ts_processed, event->timestamp) < 0)
 			continue;
 
@@ -495,8 +520,8 @@
 {
 	unsigned int ts_processed;
 
-	ts_processed = device->ftbl->readtimestamp(device, context,
-		KGSL_TIMESTAMP_RETIRED);
+	ts_processed = kgsl_readtimestamp(device, context,
+					  KGSL_TIMESTAMP_RETIRED);
 
 	return (timestamp_cmp(ts_processed, timestamp) >= 0);
 }
@@ -758,23 +783,23 @@
 	mutex_lock(&device->mutex);
 	kgsl_check_suspended(device);
 
-	/* clean up any to-be-freed entries that belong to this
-	 * process and this device
-	 */
-	kgsl_cancel_events(device, dev_priv);
-
 	while (1) {
 		context = idr_get_next(&device->context_idr, &next);
 		if (context == NULL)
 			break;
 
-		if (context->dev_priv == dev_priv) {
-			device->ftbl->drawctxt_destroy(device, context);
-			kgsl_destroy_context(dev_priv, context);
-		}
+		if (context->dev_priv == dev_priv)
+			kgsl_context_detach(context);
 
 		next = next + 1;
 	}
+	/*
+	 * Clean up any to-be-freed entries that belong to this
+	 * process and this device. This is done after the context
+	 * are destroyed to avoid possibly freeing memory while
+	 * it is still in use by the GPU.
+	 */
+	kgsl_cancel_events(device, dev_priv);
 
 	device->open_count--;
 	if (device->open_count == 0) {
@@ -995,19 +1020,25 @@
 		unsigned int timeout)
 {
 	int result = 0;
+	struct kgsl_device *device = dev_priv->device;
+	unsigned int context_id = context ? context->id : KGSL_MEMSTORE_GLOBAL;
 
 	/* Set the active count so that suspend doesn't do the wrong thing */
 
-	dev_priv->device->active_cnt++;
+	device->active_cnt++;
 
-	trace_kgsl_waittimestamp_entry(dev_priv->device,
-			context ? context->id : KGSL_MEMSTORE_GLOBAL,
-			timestamp, timeout);
+	trace_kgsl_waittimestamp_entry(device, context_id,
+				       kgsl_readtimestamp(device, context,
+							KGSL_TIMESTAMP_RETIRED),
+				       timestamp, timeout);
 
-	result = dev_priv->device->ftbl->waittimestamp(dev_priv->device,
+	result = device->ftbl->waittimestamp(dev_priv->device,
 					context, timestamp, timeout);
 
-	trace_kgsl_waittimestamp_exit(dev_priv->device, result);
+	trace_kgsl_waittimestamp_exit(device,
+				      kgsl_readtimestamp(device, context,
+							KGSL_TIMESTAMP_RETIRED),
+				      result);
 
 	/* Fire off any pending suspend operations that are in flight */
 
@@ -1024,7 +1055,7 @@
 {
 	struct kgsl_device_waittimestamp *param = data;
 
-	return _device_waittimestamp(dev_priv, KGSL_MEMSTORE_GLOBAL,
+	return _device_waittimestamp(dev_priv, NULL,
 			param->timestamp, param->timeout);
 }
 
@@ -1034,6 +1065,7 @@
 {
 	struct kgsl_device_waittimestamp_ctxtid *param = data;
 	struct kgsl_context *context;
+	int result;
 
 	context = kgsl_find_context(dev_priv, param->context_id);
 	if (context == NULL) {
@@ -1041,9 +1073,16 @@
 			param->context_id);
 		return -EINVAL;
 	}
-
-	return _device_waittimestamp(dev_priv, context,
+	/*
+	 * A reference count is needed here, because waittimestamp may
+	 * block with the device mutex unlocked and userspace could
+	 * request for the context to be destroyed during that time.
+	 */
+	kgsl_context_get(context);
+	result = _device_waittimestamp(dev_priv, context,
 			param->timestamp, param->timeout);
+	kgsl_context_put(context);
+	return result;
 }
 
 static long kgsl_ioctl_rb_issueibcmds(struct kgsl_device_private *dev_priv,
@@ -1117,7 +1156,7 @@
 					     &param->timestamp,
 					     param->flags);
 
-	trace_kgsl_issueibcmds(dev_priv->device, param, result);
+	trace_kgsl_issueibcmds(dev_priv->device, param, ibdesc, result);
 
 free_ibdesc:
 	kfree(ibdesc);
@@ -1130,8 +1169,7 @@
 		struct kgsl_context *context, unsigned int type,
 		unsigned int *timestamp)
 {
-	*timestamp = dev_priv->device->ftbl->readtimestamp(dev_priv->device,
-			context, type);
+	*timestamp = kgsl_readtimestamp(dev_priv->device, context, type);
 
 	trace_kgsl_readtimestamp(dev_priv->device,
 			context ? context->id : KGSL_MEMSTORE_GLOBAL,
@@ -1175,7 +1213,7 @@
 	spin_lock(&entry->priv->mem_lock);
 	rb_erase(&entry->node, &entry->priv->mem_rb);
 	spin_unlock(&entry->priv->mem_lock);
-	trace_kgsl_mem_timestamp_free(entry, id, timestamp);
+	trace_kgsl_mem_timestamp_free(device, entry, id, timestamp, 0);
 	kgsl_mem_entry_detach_process(entry);
 }
 
@@ -1186,27 +1224,25 @@
 	int result = 0;
 	struct kgsl_mem_entry *entry = NULL;
 	struct kgsl_device *device = dev_priv->device;
-	unsigned int cur;
 	unsigned int context_id = context ? context->id : KGSL_MEMSTORE_GLOBAL;
 
 	spin_lock(&dev_priv->process_priv->mem_lock);
 	entry = kgsl_sharedmem_find(dev_priv->process_priv, gpuaddr);
 	spin_unlock(&dev_priv->process_priv->mem_lock);
 
-	if (entry) {
-		cur = device->ftbl->readtimestamp(device, context,
-						KGSL_TIMESTAMP_RETIRED);
-
-		trace_kgsl_mem_timestamp_queue(entry, context_id, cur);
-		result = kgsl_add_event(dev_priv->device, context_id,
-				timestamp, kgsl_freemem_event_cb,
-				entry, dev_priv);
-	} else {
+	if (!entry) {
 		KGSL_DRV_ERR(dev_priv->device,
-			"invalid gpuaddr %08x\n", gpuaddr);
+				"invalid gpuaddr %08x\n", gpuaddr);
 		result = -EINVAL;
+		goto done;
 	}
-
+	trace_kgsl_mem_timestamp_queue(device, entry, context_id,
+				       kgsl_readtimestamp(device, context,
+						  KGSL_TIMESTAMP_RETIRED),
+				       timestamp);
+	result = kgsl_add_event(dev_priv->device, context_id, timestamp,
+				kgsl_freemem_event_cb, entry, dev_priv);
+done:
 	return result;
 }
 
@@ -1253,15 +1289,18 @@
 		goto done;
 	}
 
-	if (dev_priv->device->ftbl->drawctxt_create)
+	if (dev_priv->device->ftbl->drawctxt_create) {
 		result = dev_priv->device->ftbl->drawctxt_create(
 			dev_priv->device, dev_priv->process_priv->pagetable,
 			context, param->flags);
-
+		if (result)
+			goto done;
+	}
+	trace_kgsl_context_create(dev_priv->device, context, param->flags);
 	param->drawctxt_id = context->id;
 done:
 	if (result && context)
-		kgsl_destroy_context(dev_priv, context);
+		kgsl_context_detach(context);
 
 	return result;
 }
@@ -1280,14 +1319,7 @@
 		goto done;
 	}
 
-	kgsl_cancel_events_ctxt(dev_priv->device, context);
-
-	if (dev_priv->device->ftbl->drawctxt_destroy)
-		dev_priv->device->ftbl->drawctxt_destroy(dev_priv->device,
-			context);
-
-	kgsl_destroy_context(dev_priv, context);
-
+	kgsl_context_detach(context);
 done:
 	return result;
 }
@@ -2563,11 +2595,14 @@
 
 static void kgsl_core_exit(void)
 {
-	unregister_chrdev_region(kgsl_driver.major, KGSL_DEVICE_MAX);
-
-	kgsl_mmu_ptpool_destroy(&kgsl_driver.ptpool);
+	kgsl_mmu_ptpool_destroy(kgsl_driver.ptpool);
 	kgsl_driver.ptpool = NULL;
 
+	kgsl_drm_exit();
+	kgsl_cffdump_destroy();
+	kgsl_core_debugfs_close();
+	kgsl_sharedmem_uninit_sysfs();
+
 	device_unregister(&kgsl_driver.virtdev);
 
 	if (kgsl_driver.class) {
@@ -2575,10 +2610,7 @@
 		kgsl_driver.class = NULL;
 	}
 
-	kgsl_drm_exit();
-	kgsl_cffdump_destroy();
-	kgsl_core_debugfs_close();
-	kgsl_sharedmem_uninit_sysfs();
+	unregister_chrdev_region(kgsl_driver.major, KGSL_DEVICE_MAX);
 }
 
 static int __init kgsl_core_init(void)
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index da3e4b2..b67f460 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -122,6 +122,8 @@
 	int (*map_kernel_mem)(struct kgsl_memdesc *);
 };
 
+#define KGSL_MEMDESC_GUARD_PAGE BIT(0)
+
 /* shared memory allocation */
 struct kgsl_memdesc {
 	struct kgsl_pagetable *pagetable;
@@ -133,6 +135,7 @@
 	struct scatterlist *sg;
 	unsigned int sglen;
 	struct kgsl_memdesc_ops *ops;
+	int flags;
 };
 
 /* List of different memory entry types */
@@ -155,7 +158,6 @@
 	int flags;
 	void *priv_data;
 	struct rb_node node;
-	uint32_t free_timestamp;
 	unsigned int context_id;
 	/* back pointer to private structure under whose context this
 	* allocation is made */
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 0964458..5b2fd31 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -220,6 +220,7 @@
 	.last_expired_ctxt_id = KGSL_CONTEXT_INVALID
 
 struct kgsl_context {
+	struct kref refcount;
 	uint32_t id;
 
 	/* Pointer to the owning device instance */
@@ -293,6 +294,13 @@
 	return device->ftbl->gpuid(device);
 }
 
+static inline unsigned int kgsl_readtimestamp(struct kgsl_device *device,
+					      struct kgsl_context *context,
+					      enum kgsl_timestamp_type type)
+{
+	return device->ftbl->readtimestamp(device, context, type);
+}
+
 static inline int kgsl_create_device_sysfs_files(struct device *root,
 	const struct device_attribute **list)
 {
@@ -380,4 +388,32 @@
 	return pdev->dev.platform_data;
 }
 
+/**
+ * kgsl_context_get - Get context reference count
+ * @context
+ *
+ * Asynchronous code that holds a pointer to a context
+ * must hold a reference count on it. The kgsl device
+ * mutex must be held while the context reference count
+ * is changed.
+ */
+static inline void
+kgsl_context_get(struct kgsl_context *context)
+{
+	kref_get(&context->refcount);
+}
+
+void kgsl_context_destroy(struct kref *kref);
+
+/**
+ * kgsl_context_put - Release context reference count
+ * @context
+ *
+ */
+static inline void
+kgsl_context_put(struct kgsl_context *context)
+{
+	kref_put(&context->refcount, kgsl_context_destroy);
+}
+
 #endif  /* __KGSL_DEVICE_H */
diff --git a/drivers/gpu/msm/kgsl_gpummu.c b/drivers/gpu/msm/kgsl_gpummu.c
index ab47f40..429d035 100644
--- a/drivers/gpu/msm/kgsl_gpummu.c
+++ b/drivers/gpu/msm/kgsl_gpummu.c
@@ -21,6 +21,7 @@
 #include "kgsl_mmu.h"
 #include "kgsl_device.h"
 #include "kgsl_sharedmem.h"
+#include "kgsl_trace.h"
 
 #define KGSL_PAGETABLE_SIZE \
 	ALIGN(KGSL_PAGETABLE_ENTRIES(CONFIG_MSM_KGSL_PAGE_TABLE_SIZE) * \
@@ -410,6 +411,9 @@
 			reg & ~(PAGE_SIZE - 1),
 			kgsl_mmu_get_ptname_from_ptbase(ptbase),
 			reg & 0x02 ? "WRITE" : "READ", (reg >> 4) & 0xF);
+	trace_kgsl_mmu_pagefault(mmu->device, reg & ~(PAGE_SIZE - 1),
+			kgsl_mmu_get_ptname_from_ptbase(ptbase),
+			reg & 0x02 ? "WRITE" : "READ");
 }
 
 static void *kgsl_gpummu_create_pagetable(void)
@@ -591,7 +595,7 @@
 {
 	unsigned int numpages;
 	unsigned int pte, ptefirst, ptelast, superpte;
-	unsigned int range = memdesc->size;
+	unsigned int range = kgsl_sg_size(memdesc->sg, memdesc->sglen);
 	struct kgsl_gpummu_pt *gpummu_pt = mmu_specific_pt;
 
 	/* All GPU addresses as assigned are page aligned, but some
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index 2f83a40..2050827 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -23,6 +23,81 @@
 #include "kgsl_mmu.h"
 #include "kgsl_sharedmem.h"
 #include "kgsl_iommu.h"
+#include "adreno_pm4types.h"
+#include "adreno.h"
+#include "kgsl_trace.h"
+
+static struct kgsl_iommu_unit *get_iommu_unit(struct device *dev)
+{
+	int i, j, k;
+
+	for (i = 0; i < KGSL_DEVICE_MAX; i++) {
+		struct kgsl_mmu *mmu;
+		struct kgsl_iommu *iommu;
+
+		if (kgsl_driver.devp[i] == NULL)
+			continue;
+
+		mmu = kgsl_get_mmu(kgsl_driver.devp[i]);
+		if (mmu == NULL || mmu->priv == NULL)
+			continue;
+
+		iommu = mmu->priv;
+
+		for (j = 0; j < iommu->unit_count; j++) {
+			struct kgsl_iommu_unit *iommu_unit =
+				&iommu->iommu_units[j];
+			for (k = 0; k < iommu_unit->dev_count; k++) {
+				if (iommu_unit->dev[k].dev == dev)
+					return iommu_unit;
+			}
+		}
+	}
+
+	return NULL;
+}
+
+static struct kgsl_iommu_device *get_iommu_device(struct kgsl_iommu_unit *unit,
+		struct device *dev)
+{
+	int k;
+
+	for (k = 0; unit && k < unit->dev_count; k++) {
+		if (unit->dev[k].dev == dev)
+			return &(unit->dev[k]);
+	}
+
+	return NULL;
+}
+
+static int kgsl_iommu_fault_handler(struct iommu_domain *domain,
+	struct device *dev, unsigned long addr, int flags)
+{
+	struct kgsl_iommu_unit *iommu_unit = get_iommu_unit(dev);
+	struct kgsl_iommu_device *iommu_dev = get_iommu_device(iommu_unit, dev);
+	unsigned int ptbase, fsr;
+
+	if (!iommu_dev) {
+		KGSL_CORE_ERR("Invalid IOMMU device %p\n", dev);
+		return -ENOSYS;
+	}
+
+	ptbase = iommu_get_pt_base_addr(domain);
+
+	fsr = KGSL_IOMMU_GET_IOMMU_REG(iommu_unit->reg_map.hostptr,
+		iommu_dev->ctx_id, FSR);
+
+	KGSL_MEM_CRIT(iommu_dev->kgsldev,
+		"GPU PAGE FAULT: addr = %lX pid = %d\n",
+		addr, kgsl_mmu_get_ptname_from_ptbase(ptbase));
+	KGSL_MEM_CRIT(iommu_dev->kgsldev, "context = %d FSR = %X\n",
+		iommu_dev->ctx_id, fsr);
+
+	trace_kgsl_mmu_pagefault(iommu_dev->kgsldev, addr,
+			kgsl_mmu_get_ptname_from_ptbase(ptbase), 0);
+
+	return 0;
+}
 
 /*
  * kgsl_iommu_disable_clk - Disable iommu clocks
@@ -160,12 +235,16 @@
 				sizeof(struct kgsl_iommu_pt));
 		return NULL;
 	}
-	iommu_pt->domain = iommu_domain_alloc(0);
+	iommu_pt->domain = iommu_domain_alloc(MSM_IOMMU_DOMAIN_PT_CACHEABLE);
 	if (!iommu_pt->domain) {
 		KGSL_CORE_ERR("Failed to create iommu domain\n");
 		kfree(iommu_pt);
 		return NULL;
+	} else {
+		iommu_set_fault_handler(iommu_pt->domain,
+			kgsl_iommu_fault_handler);
 	}
+
 	return iommu_pt;
 }
 
@@ -302,6 +381,8 @@
 		}
 		iommu_unit->dev[iommu_unit->dev_count].ctx_id =
 						data->iommu_ctxs[i].ctx_id;
+		iommu_unit->dev[iommu_unit->dev_count].kgsldev = mmu->device;
+
 		KGSL_DRV_INFO(mmu->device,
 				"Obtained dev handle %p for iommu context %s\n",
 				iommu_unit->dev[iommu_unit->dev_count].dev,
@@ -499,6 +580,12 @@
 	if (status)
 		goto done;
 
+	/* A nop is required in an indirect buffer when switching
+	 * pagetables in-stream */
+	kgsl_sharedmem_writel(&mmu->setstate_memory,
+				KGSL_IOMMU_SETSTATE_NOP_OFFSET,
+				cp_nop_packet(1));
+
 	dev_info(mmu->device->dev, "|%s| MMU type set for device is IOMMU\n",
 			__func__);
 done:
@@ -580,16 +667,26 @@
 		if (status)
 			return -ENOMEM;
 	}
-	kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000);
+	/* We use the GPU MMU to control access to IOMMU registers on a225,
+	 * hence we still keep the MMU active on a225 */
+	if (adreno_is_a225(ADRENO_DEVICE(mmu->device))) {
+		struct kgsl_mh *mh = &(mmu->device->mh);
+		kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000001);
+		kgsl_regwrite(mmu->device, MH_MMU_MPU_END,
+			mh->mpu_base +
+			iommu->iommu_units
+				[iommu->unit_count - 1].reg_map.gpuaddr -
+				PAGE_SIZE);
+	} else {
+		kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000);
+	}
 
 	mmu->hwpagetable = mmu->defaultpagetable;
 
 	status = kgsl_attach_pagetable_iommu_domain(mmu);
-	if (!status) {
-		mmu->flags |= KGSL_FLAGS_STARTED;
-	} else {
-		kgsl_detach_pagetable_iommu_domain(mmu);
+	if (status) {
 		mmu->hwpagetable = NULL;
+		goto done;
 	}
 	status = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
 	if (status) {
@@ -621,6 +718,7 @@
 				CONTEXTIDR);
 
 	kgsl_iommu_disable_clk(mmu);
+	mmu->flags |= KGSL_FLAGS_STARTED;
 
 done:
 	if (status) {
@@ -635,7 +733,7 @@
 		struct kgsl_memdesc *memdesc)
 {
 	int ret;
-	unsigned int range = memdesc->size;
+	unsigned int range = kgsl_sg_size(memdesc->sg, memdesc->sglen);
 	struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
 
 	/* All GPU addresses as assigned are page aligned, but some
@@ -665,6 +763,7 @@
 	int ret;
 	unsigned int iommu_virt_addr;
 	struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
+	int size = kgsl_sg_size(memdesc->sg, memdesc->sglen);
 
 	BUG_ON(NULL == iommu_pt);
 
@@ -672,11 +771,11 @@
 	iommu_virt_addr = memdesc->gpuaddr;
 
 	ret = iommu_map_range(iommu_pt->domain, iommu_virt_addr, memdesc->sg,
-				memdesc->size, (IOMMU_READ | IOMMU_WRITE));
+				size, (IOMMU_READ | IOMMU_WRITE));
 	if (ret) {
 		KGSL_CORE_ERR("iommu_map_range(%p, %x, %p, %d, %d) "
 				"failed with err: %d\n", iommu_pt->domain,
-				iommu_virt_addr, memdesc->sg, memdesc->size,
+				iommu_virt_addr, memdesc->sg, size,
 				(IOMMU_READ | IOMMU_WRITE), ret);
 		return ret;
 	}
@@ -701,6 +800,7 @@
 	 */
 
 	if (mmu->flags & KGSL_FLAGS_STARTED) {
+		kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000);
 		/* detach iommu attachment */
 		kgsl_detach_pagetable_iommu_domain(mmu);
 		mmu->hwpagetable = NULL;
diff --git a/drivers/gpu/msm/kgsl_iommu.h b/drivers/gpu/msm/kgsl_iommu.h
index c2e84a6..efc3d9c 100644
--- a/drivers/gpu/msm/kgsl_iommu.h
+++ b/drivers/gpu/msm/kgsl_iommu.h
@@ -18,6 +18,8 @@
 /* IOMMU registers and masks */
 #define KGSL_IOMMU_TTBR0			0x10
 #define KGSL_IOMMU_TTBR1			0x14
+#define KGSL_IOMMU_FSR				0x20
+
 #define KGSL_IOMMU_TTBR0_PA_MASK		0x0003FFFF
 #define KGSL_IOMMU_TTBR0_PA_SHIFT		14
 #define KGSL_IOMMU_CTX_TLBIALL			0x800
@@ -55,6 +57,9 @@
 		(pt_val & ~(KGSL_IOMMU_TTBR0_PA_MASK <<			\
 				KGSL_IOMMU_TTBR0_PA_SHIFT))
 
+/* offset at which a nop command is placed in setstate_memory */
+#define KGSL_IOMMU_SETSTATE_NOP_OFFSET	1024
+
 /*
  * struct kgsl_iommu_device - Structure holding data about iommu contexts
  * @dev: Device pointer to iommu context
@@ -72,6 +77,7 @@
 	unsigned int pt_lsb;
 	enum kgsl_iommu_context_id ctx_id;
 	bool clk_enabled;
+	struct kgsl_device *kgsldev;
 };
 
 /*
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index 663ba0f..9092b96 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -545,8 +545,7 @@
 	struct kgsl_device *device = mmu->device;
 	if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type)
 		return;
-	else if (device->ftbl->setstate && (KGSL_MMU_TYPE_IOMMU !=
-						kgsl_mmu_type))
+	else if (device->ftbl->setstate)
 		device->ftbl->setstate(device, flags);
 	else if (mmu->mmu_ops->mmu_device_setstate)
 		mmu->mmu_ops->mmu_device_setstate(mmu, flags);
@@ -596,6 +595,7 @@
 {
 	int ret;
 	struct gen_pool *pool;
+	int size;
 
 	if (kgsl_mmu_type == KGSL_MMU_TYPE_NONE) {
 		if (memdesc->sglen == 1) {
@@ -615,13 +615,15 @@
 		}
 	}
 
+	size = kgsl_sg_size(memdesc->sg, memdesc->sglen);
+
 	/* Allocate from kgsl pool if it exists for global mappings */
 	pool = _get_pool(pagetable, memdesc->priv);
 
-	memdesc->gpuaddr = gen_pool_alloc(pool, memdesc->size);
+	memdesc->gpuaddr = gen_pool_alloc(pool, size);
 	if (memdesc->gpuaddr == 0) {
 		KGSL_CORE_ERR("gen_pool_alloc(%d) failed from pool: %s\n",
-			memdesc->size,
+			size,
 			(pool == pagetable->kgsl_pool) ?
 			"kgsl_pool" : "general_pool");
 		KGSL_CORE_ERR(" [%d] allocated=%d, entries=%d\n",
@@ -645,7 +647,7 @@
 	KGSL_STATS_ADD(1, pagetable->stats.entries,
 		       pagetable->stats.max_entries);
 
-	KGSL_STATS_ADD(memdesc->size, pagetable->stats.mapped,
+	KGSL_STATS_ADD(size, pagetable->stats.mapped,
 		       pagetable->stats.max_mapped);
 
 	spin_unlock(&pagetable->lock);
@@ -654,7 +656,7 @@
 
 err_free_gpuaddr:
 	spin_unlock(&pagetable->lock);
-	gen_pool_free(pool, memdesc->gpuaddr, memdesc->size);
+	gen_pool_free(pool, memdesc->gpuaddr, size);
 	memdesc->gpuaddr = 0;
 	return ret;
 }
@@ -665,6 +667,8 @@
 		struct kgsl_memdesc *memdesc)
 {
 	struct gen_pool *pool;
+	int size;
+
 	if (memdesc->size == 0 || memdesc->gpuaddr == 0)
 		return 0;
 
@@ -672,6 +676,9 @@
 		memdesc->gpuaddr = 0;
 		return 0;
 	}
+
+	size = kgsl_sg_size(memdesc->sg, memdesc->sglen);
+
 	if (KGSL_MMU_TYPE_IOMMU != kgsl_mmu_get_mmutype())
 		spin_lock(&pagetable->lock);
 	pagetable->pt_ops->mmu_unmap(pagetable->priv, memdesc);
@@ -679,12 +686,12 @@
 		spin_lock(&pagetable->lock);
 	/* Remove the statistics */
 	pagetable->stats.entries--;
-	pagetable->stats.mapped -= memdesc->size;
+	pagetable->stats.mapped -= size;
 
 	spin_unlock(&pagetable->lock);
 
 	pool = _get_pool(pagetable, memdesc->priv);
-	gen_pool_free(pool, memdesc->gpuaddr, memdesc->size);
+	gen_pool_free(pool, memdesc->gpuaddr, size);
 
 	/*
 	 * Don't clear the gpuaddr on global mappings because they
diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h
index df4a64b..2db327b 100644
--- a/drivers/gpu/msm/kgsl_mmu.h
+++ b/drivers/gpu/msm/kgsl_mmu.h
@@ -261,4 +261,37 @@
 		return 0;
 }
 
+static inline int kgsl_mmu_get_pt_lsb(struct kgsl_mmu *mmu,
+					unsigned int unit_id,
+					enum kgsl_iommu_context_id ctx_id)
+{
+	if (mmu->mmu_ops && mmu->mmu_ops->mmu_get_pt_lsb)
+		return mmu->mmu_ops->mmu_get_pt_lsb(mmu, unit_id, ctx_id);
+	else
+		return 0;
+}
+
+static inline int kgsl_mmu_get_hwpagetable_asid(struct kgsl_mmu *mmu)
+{
+	if (mmu->mmu_ops && mmu->mmu_ops->mmu_get_hwpagetable_asid)
+		return mmu->mmu_ops->mmu_get_hwpagetable_asid(mmu);
+	else
+		return 0;
+}
+
+static inline int kgsl_mmu_enable_clk(struct kgsl_mmu *mmu,
+					int ctx_id)
+{
+	if (mmu->mmu_ops && mmu->mmu_ops->mmu_enable_clk)
+		return mmu->mmu_ops->mmu_enable_clk(mmu, ctx_id);
+	else
+		return 0;
+}
+
+static inline void kgsl_mmu_disable_clk(struct kgsl_mmu *mmu)
+{
+	if (mmu->mmu_ops && mmu->mmu_ops->mmu_disable_clk)
+		mmu->mmu_ops->mmu_disable_clk(mmu);
+}
+
 #endif /* __KGSL_MMU_H */
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 3a29d71..6854d6c 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -443,8 +443,12 @@
 		if (!test_and_set_bit(KGSL_PWRFLAGS_POWER_ON,
 			&pwr->power_flags)) {
 			trace_kgsl_rail(device, state);
-			if (pwr->gpu_reg)
-				regulator_enable(pwr->gpu_reg);
+			if (pwr->gpu_reg) {
+				int status = regulator_enable(pwr->gpu_reg);
+				if (status)
+					KGSL_DRV_ERR(device, "regulator_enable "
+							"failed: %d\n", status);
+			}
 		}
 	}
 }
@@ -706,6 +710,7 @@
 		}
 		kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
 		kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_OFF, KGSL_STATE_NAP);
+		kgsl_mmu_disable_clk(&device->mmu);
 		kgsl_pwrctrl_set_state(device, KGSL_STATE_NAP);
 		if (device->idle_wakelock.name)
 			wake_unlock(&device->idle_wakelock);
@@ -749,6 +754,7 @@
 				gpu_freq);
 		_sleep_accounting(device);
 		kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_OFF, KGSL_STATE_SLEEP);
+		kgsl_mmu_disable_clk(&device->mmu);
 		kgsl_pwrctrl_set_state(device, KGSL_STATE_SLEEP);
 		wake_unlock(&device->idle_wakelock);
 		pm_qos_update_request(&device->pm_qos_req_dma,
@@ -888,6 +894,7 @@
 	/* Order pwrrail/clk sequence based upon platform */
 	kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_OFF);
 	kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_OFF, KGSL_STATE_SLEEP);
+	kgsl_mmu_disable_clk(&device->mmu);
 	kgsl_pwrctrl_pwrrail(device, KGSL_PWRFLAGS_OFF);
 }
 EXPORT_SYMBOL(kgsl_pwrctrl_disable);
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index a51f29f..8829102 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.c
+++ b/drivers/gpu/msm/kgsl_sharedmem.c
@@ -63,6 +63,13 @@
 }
 
 
+/*
+ * One page allocation for a guard region to protect against over-zealous
+ * GPU pre-fetch
+ */
+
+static struct page *kgsl_guard_page;
+
 /**
  * Given a kobj, find the process structure attached to it
  */
@@ -333,13 +340,20 @@
 {
 	int i = 0;
 	struct scatterlist *sg;
+	int sglen = memdesc->sglen;
+
+	/* Don't free the guard page if it was used */
+	if (memdesc->flags & KGSL_MEMDESC_GUARD_PAGE)
+		sglen--;
+
 	kgsl_driver.stats.page_alloc -= memdesc->size;
+
 	if (memdesc->hostptr) {
 		vunmap(memdesc->hostptr);
 		kgsl_driver.stats.vmalloc -= memdesc->size;
 	}
 	if (memdesc->sg)
-		for_each_sg(memdesc->sg, sg, memdesc->sglen, i)
+		for_each_sg(memdesc->sg, sg, sglen, i)
 			__free_page(sg_page(sg));
 }
 
@@ -362,17 +376,23 @@
 		pgprot_t page_prot = pgprot_writecombine(PAGE_KERNEL);
 		struct page **pages = NULL;
 		struct scatterlist *sg;
+		int sglen = memdesc->sglen;
 		int i;
+
+		/* Don't map the guard page if it exists */
+		if (memdesc->flags & KGSL_MEMDESC_GUARD_PAGE)
+			sglen--;
+
 		/* create a list of pages to call vmap */
-		pages = vmalloc(memdesc->sglen * sizeof(struct page *));
+		pages = vmalloc(sglen * sizeof(struct page *));
 		if (!pages) {
 			KGSL_CORE_ERR("vmalloc(%d) failed\n",
-				memdesc->sglen * sizeof(struct page *));
+				sglen * sizeof(struct page *));
 			return -ENOMEM;
 		}
-		for_each_sg(memdesc->sg, sg, memdesc->sglen, i)
+		for_each_sg(memdesc->sg, sg, sglen, i)
 			pages[i] = sg_page(sg);
-		memdesc->hostptr = vmap(pages, memdesc->sglen,
+		memdesc->hostptr = vmap(pages, sglen,
 					VM_IOREMAP, page_prot);
 		KGSL_STATS_ADD(memdesc->size, kgsl_driver.stats.vmalloc,
 				kgsl_driver.stats.vmalloc_max);
@@ -471,6 +491,14 @@
 	int sglen = PAGE_ALIGN(size) / PAGE_SIZE;
 	int i;
 
+	/*
+	 * Add guard page to the end of the allocation when the
+	 * IOMMU is in use.
+	 */
+
+	if (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_IOMMU)
+		sglen++;
+
 	memdesc->size = size;
 	memdesc->pagetable = pagetable;
 	memdesc->priv = KGSL_MEMFLAGS_CACHED;
@@ -490,7 +518,7 @@
 	memdesc->sglen = sglen;
 	sg_init_table(memdesc->sg, sglen);
 
-	for (i = 0; i < memdesc->sglen; i++) {
+	for (i = 0; i < PAGE_ALIGN(size) / PAGE_SIZE; i++) {
 		struct page *page = alloc_page(GFP_KERNEL | __GFP_ZERO |
 						__GFP_HIGHMEM);
 		if (!page) {
@@ -501,6 +529,22 @@
 		flush_dcache_page(page);
 		sg_set_page(&memdesc->sg[i], page, PAGE_SIZE, 0);
 	}
+
+	/* ADd the guard page to the end of the sglist */
+
+	if (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_IOMMU) {
+		if (kgsl_guard_page == NULL)
+			kgsl_guard_page = alloc_page(GFP_KERNEL | __GFP_ZERO |
+				__GFP_HIGHMEM);
+
+		if (kgsl_guard_page != NULL) {
+			sg_set_page(&memdesc->sg[sglen - 1], kgsl_guard_page,
+				PAGE_SIZE, 0);
+			memdesc->flags |= KGSL_MEMDESC_GUARD_PAGE;
+		} else
+			memdesc->sglen--;
+	}
+
 	outer_cache_range_op_sg(memdesc->sg, memdesc->sglen,
 				KGSL_CACHE_OP_FLUSH);
 
diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h
index fb8dd95..034ade4 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.h
+++ b/drivers/gpu/msm/kgsl_sharedmem.h
@@ -157,4 +157,15 @@
 	return ret;
 }
 
+static inline int kgsl_sg_size(struct scatterlist *sg, int sglen)
+{
+	int i, size = 0;
+	struct scatterlist *s;
+
+	for_each_sg(sg, s, sglen, i) {
+		size += s->length;
+	}
+
+	return size;
+}
 #endif /* __KGSL_SHAREDMEM_H */
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index f61c74f..080cb15 100644
--- a/drivers/gpu/msm/kgsl_snapshot.c
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -63,10 +63,10 @@
 	 * return the global timestamp for all contexts
 	 */
 
-	header->timestamp_queued = device->ftbl->readtimestamp(device,
-		context, KGSL_TIMESTAMP_QUEUED);
-	header->timestamp_retired = device->ftbl->readtimestamp(device,
-		context, KGSL_TIMESTAMP_RETIRED);
+	header->timestamp_queued = kgsl_readtimestamp(device, context,
+						      KGSL_TIMESTAMP_QUEUED);
+	header->timestamp_retired = kgsl_readtimestamp(device, context,
+						       KGSL_TIMESTAMP_RETIRED);
 
 	_ctxtptr += sizeof(struct kgsl_snapshot_linux_context);
 
diff --git a/drivers/gpu/msm/kgsl_trace.h b/drivers/gpu/msm/kgsl_trace.h
index 84d7f94..60231f6 100644
--- a/drivers/gpu/msm/kgsl_trace.h
+++ b/drivers/gpu/msm/kgsl_trace.h
@@ -22,6 +22,7 @@
 #define TRACE_INCLUDE_FILE kgsl_trace
 
 #include <linux/tracepoint.h>
+#include "kgsl_device.h"
 
 struct kgsl_device;
 struct kgsl_ringbuffer_issueibcmds;
@@ -33,9 +34,11 @@
 TRACE_EVENT(kgsl_issueibcmds,
 
 	TP_PROTO(struct kgsl_device *device,
-			struct kgsl_ringbuffer_issueibcmds *cmd, int result),
+			struct kgsl_ringbuffer_issueibcmds *cmd,
+			struct kgsl_ibdesc *ibdesc,
+			int result),
 
-	TP_ARGS(device, cmd, result),
+	TP_ARGS(device, cmd, ibdesc, result),
 
 	TP_STRUCT__entry(
 		__string(device_name, device->name)
@@ -50,7 +53,7 @@
 	TP_fast_assign(
 		__assign_str(device_name, device->name);
 		__entry->drawctxt_id = cmd->drawctxt_id;
-		__entry->ibdesc_addr = cmd->ibdesc_addr;
+		__entry->ibdesc_addr = ibdesc[0].gpuaddr;
 		__entry->numibs = cmd->numibs;
 		__entry->timestamp = cmd->timestamp;
 		__entry->flags = cmd->flags;
@@ -58,14 +61,19 @@
 	),
 
 	TP_printk(
-		"d_name=%s ctx=%u ib=%u numibs=%u timestamp=%u "
-		"flags=%u result=%d",
+		"d_name=%s ctx=%u ib=0x%u numibs=%u timestamp=0x%x "
+		"flags=0x%x(%s) result=%d",
 		__get_str(device_name),
 		__entry->drawctxt_id,
 		__entry->ibdesc_addr,
 		__entry->numibs,
 		__entry->timestamp,
 		__entry->flags,
+		__entry->flags ? __print_flags(__entry->flags, "|",
+			{ KGSL_CONTEXT_SAVE_GMEM, "SAVE_GMEM" },
+			{ KGSL_CONTEXT_SUBMIT_IB_LIST, "IB_LIST" },
+			{ KGSL_CONTEXT_CTX_SWITCH, "CTX_SWITCH" })
+			: "None",
 		__entry->result
 	)
 );
@@ -97,7 +105,7 @@
 	),
 
 	TP_printk(
-		"d_name=%s context_id=%u type=%u timestamp=%u",
+		"d_name=%s context_id=%u type=%u timestamp=0x%x",
 		__get_str(device_name),
 		__entry->context_id,
 		__entry->type,
@@ -112,30 +120,34 @@
 
 	TP_PROTO(struct kgsl_device *device,
 			unsigned int context_id,
-			unsigned int timestamp,
+			unsigned int curr_ts,
+			unsigned int wait_ts,
 			unsigned int timeout),
 
-	TP_ARGS(device, context_id, timestamp, timeout),
+	TP_ARGS(device, context_id, curr_ts, wait_ts, timeout),
 
 	TP_STRUCT__entry(
 		__string(device_name, device->name)
 		__field(unsigned int, context_id)
-		__field(unsigned int, timestamp)
+		__field(unsigned int, curr_ts)
+		__field(unsigned int, wait_ts)
 		__field(unsigned int, timeout)
 	),
 
 	TP_fast_assign(
 		__assign_str(device_name, device->name);
 		__entry->context_id = context_id;
-		__entry->timestamp = timestamp;
+		__entry->curr_ts = curr_ts;
+		__entry->wait_ts = wait_ts;
 		__entry->timeout = timeout;
 	),
 
 	TP_printk(
-		"d_name=%s context_id=%u timestamp=%u timeout=%u",
+		"d_name=%s context_id=%u curr_ts=%u timestamp=0x%x timeout=%u",
 		__get_str(device_name),
 		__entry->context_id,
-		__entry->timestamp,
+		__entry->curr_ts,
+		__entry->wait_ts,
 		__entry->timeout
 	)
 );
@@ -145,23 +157,27 @@
  */
 TRACE_EVENT(kgsl_waittimestamp_exit,
 
-	TP_PROTO(struct kgsl_device *device, int result),
+	TP_PROTO(struct kgsl_device *device, unsigned int curr_ts,
+		 int result),
 
-	TP_ARGS(device, result),
+	TP_ARGS(device, curr_ts, result),
 
 	TP_STRUCT__entry(
 		__string(device_name, device->name)
+		__field(unsigned int, curr_ts)
 		__field(int, result)
 	),
 
 	TP_fast_assign(
 		__assign_str(device_name, device->name);
+		__entry->curr_ts = curr_ts;
 		__entry->result = result;
 	),
 
 	TP_printk(
-		"d_name=%s result=%d",
+		"d_name=%s curr_ts=%u result=%d",
 		__get_str(device_name),
+		__entry->curr_ts,
 		__entry->result
 	)
 );
@@ -343,12 +359,13 @@
 
 DECLARE_EVENT_CLASS(kgsl_mem_timestamp_template,
 
-	TP_PROTO(struct kgsl_mem_entry *mem_entry, unsigned int id,
-		unsigned int curr_ts),
+	TP_PROTO(struct kgsl_device *device, struct kgsl_mem_entry *mem_entry,
+		unsigned int id, unsigned int curr_ts, unsigned int free_ts),
 
-	TP_ARGS(mem_entry, id, curr_ts),
+	TP_ARGS(device, mem_entry, id, curr_ts, free_ts),
 
 	TP_STRUCT__entry(
+		__string(device_name, device->name)
 		__field(unsigned int, gpuaddr)
 		__field(unsigned int, size)
 		__field(int, type)
@@ -358,33 +375,120 @@
 	),
 
 	TP_fast_assign(
+		__assign_str(device_name, device->name);
 		__entry->gpuaddr = mem_entry->memdesc.gpuaddr;
 		__entry->size = mem_entry->memdesc.size;
 		__entry->drawctxt_id = id;
 		__entry->type = mem_entry->memtype;
 		__entry->curr_ts = curr_ts;
-		__entry->free_ts = mem_entry->free_timestamp;
+		__entry->free_ts = free_ts;
 	),
 
 	TP_printk(
-		"gpuaddr=0x%08x size=%d type=%d ctx=%u curr_ts=0x%08x free_ts=0x%08x",
-		__entry->gpuaddr, __entry->size, __entry->type,
-		__entry->drawctxt_id, __entry->curr_ts, __entry->free_ts
+		"d_name=%s gpuaddr=0x%08x size=%d type=%d ctx=%u"
+		" curr_ts=0x%08x free_ts=0x%08x",
+		__get_str(device_name),
+		__entry->gpuaddr,
+		__entry->size,
+		__entry->type,
+		__entry->drawctxt_id,
+		__entry->curr_ts,
+		__entry->free_ts
 	)
 );
 
 DEFINE_EVENT(kgsl_mem_timestamp_template, kgsl_mem_timestamp_queue,
-	TP_PROTO(struct kgsl_mem_entry *mem_entry, unsigned int id,
-		unsigned int curr_ts),
-	TP_ARGS(mem_entry, id, curr_ts)
+	TP_PROTO(struct kgsl_device *device, struct kgsl_mem_entry *mem_entry,
+		unsigned int id, unsigned int curr_ts, unsigned int free_ts),
+	TP_ARGS(device, mem_entry, id, curr_ts, free_ts)
 );
 
 DEFINE_EVENT(kgsl_mem_timestamp_template, kgsl_mem_timestamp_free,
-	TP_PROTO(struct kgsl_mem_entry *mem_entry, unsigned int id,
-		unsigned int curr_ts),
-	TP_ARGS(mem_entry, id, curr_ts)
+	TP_PROTO(struct kgsl_device *device, struct kgsl_mem_entry *mem_entry,
+		unsigned int id, unsigned int curr_ts, unsigned int free_ts),
+	TP_ARGS(device, mem_entry, id, curr_ts, free_ts)
 );
 
+TRACE_EVENT(kgsl_context_create,
+
+	TP_PROTO(struct kgsl_device *device, struct kgsl_context *context,
+		 unsigned int flags),
+
+	TP_ARGS(device, context, flags),
+
+	TP_STRUCT__entry(
+		__string(device_name, device->name)
+		__field(unsigned int, id)
+		__field(unsigned int, flags)
+	),
+
+	TP_fast_assign(
+		__assign_str(device_name, device->name);
+		__entry->id = context->id;
+		__entry->flags = flags;
+	),
+
+	TP_printk(
+		"d_name=%s ctx=%u flags=0x%x %s",
+		__get_str(device_name), __entry->id, __entry->flags,
+		__entry->flags ? __print_flags(__entry->flags, "|",
+			{ KGSL_CONTEXT_NO_GMEM_ALLOC , "NO_GMEM_ALLOC" },
+			{ KGSL_CONTEXT_PREAMBLE, "PREAMBLE" },
+			{ KGSL_CONTEXT_TRASH_STATE, "TRASH_STATE" },
+			{ KGSL_CONTEXT_PER_CONTEXT_TS, "PER_CONTEXT_TS" })
+			: "None"
+	)
+);
+
+TRACE_EVENT(kgsl_context_detach,
+
+	TP_PROTO(struct kgsl_device *device, struct kgsl_context *context),
+
+	TP_ARGS(device, context),
+
+	TP_STRUCT__entry(
+		__string(device_name, device->name)
+		__field(unsigned int, id)
+	),
+
+	TP_fast_assign(
+		__assign_str(device_name, device->name);
+		__entry->id = context->id;
+	),
+
+	TP_printk(
+		"d_name=%s ctx=%u",
+		__get_str(device_name), __entry->id
+	)
+);
+
+TRACE_EVENT(kgsl_mmu_pagefault,
+
+	TP_PROTO(struct kgsl_device *device, unsigned int page,
+		 unsigned int pt, const char *op),
+
+	TP_ARGS(device, page, pt, op),
+
+	TP_STRUCT__entry(
+		__string(device_name, device->name)
+		__field(unsigned int, page)
+		__field(unsigned int, pt)
+		__string(op, op)
+	),
+
+	TP_fast_assign(
+		__assign_str(device_name, device->name);
+		__entry->page = page;
+		__entry->pt = pt;
+		__assign_str(op, op);
+	),
+
+	TP_printk(
+		"d_name=%s page=0x%08x pt=%d op=%s\n",
+		__get_str(device_name), __entry->page, __entry->pt,
+		__get_str(op)
+	)
+);
 
 #endif /* _KGSL_TRACE_H */
 
diff --git a/drivers/gud/Kconfig b/drivers/gud/Kconfig
new file mode 100644
index 0000000..3a241b7
--- /dev/null
+++ b/drivers/gud/Kconfig
@@ -0,0 +1,32 @@
+#
+# MobiCore configuration
+#
+config MOBICORE_SUPPORT
+	tristate "Linux MobiCore Support"
+	#depends on ARM_TRUSTZONE
+	---help---
+	  Enable Linux Kernel MobiCore Support
+
+config MOBICORE_DEBUG
+    bool "MobiCore Module debug mode"
+    depends on MOBICORE_SUPPORT
+    ---help---
+      Enable Debug mode in the MobiCore Driver.
+      It enables printing information about mobicore operations
+
+config MOBICORE_VERBOSE
+    bool "MobiCore Module verbose debug mode"
+    depends on MOBICORE_DEBUG
+    ---help---
+      Enable Verbose Debug mode in the MobiCore Driver.
+      It enables printing extra information about mobicore operations
+      Beware: this is only useful for debuging deep in the driver because
+      it prints too much logs
+
+
+config MOBICORE_API
+    tristate "Linux MobiCore API"
+    depends on MOBICORE_SUPPORT
+    ---help---
+      Enable Linux Kernel MobiCore API
+
diff --git a/drivers/gud/Makefile b/drivers/gud/Makefile
new file mode 100644
index 0000000..ea212c5
--- /dev/null
+++ b/drivers/gud/Makefile
@@ -0,0 +1,31 @@
+#
+# Makefile for the kernel mobicore drivers
+#
+GUD_ROOT_FOLDER := drivers/gud
+# add our modules to kernel.
+obj-$(CONFIG_MOBICORE_API) += mckernelapi.o
+obj-$(CONFIG_MOBICORE_SUPPORT) += mcdrvmodule.o
+
+mcdrvmodule-objs := mobicore_driver/logging.o mobicore_driver/main.o
+
+mckernelapi-objs := mobicore_kernelapi/main.o \
+		mobicore_kernelapi/clientlib.o \
+		mobicore_kernelapi/device.o \
+		mobicore_kernelapi/session.o \
+		mobicore_kernelapi/connection.o
+
+# Release mode by default
+ccflags-y := -DNDEBUG
+ccflags-y += -Wno-declaration-after-statement
+
+ccflags-$(CONFIG_MOBICORE_DEBUG) += -DDEBUG
+ccflags-$(CONFIG_MOBICORE_VERBOSE) += -DDEBUG_VERBOSE
+
+# Choose one platform from the folder
+MOBICORE_PLATFORM := $(shell (ls -1 $(PWD)/$(GUD_ROOT_FOLDER)/mobicore_driver/platforms | tail -1) )
+# Use the available platform folder
+ccflags-y += -I$(GUD_ROOT_FOLDER)/mobicore_driver/platforms/$(MOBICORE_PLATFORM)
+
+
+ccflags-y += -I$(GUD_ROOT_FOLDER)/mobicore_driver/public
+ccflags-y += -I$(GUD_ROOT_FOLDER)/mobicore_kernelapi/include
diff --git a/drivers/gud/README b/drivers/gud/README
new file mode 100644
index 0000000..c6d62a1
--- /dev/null
+++ b/drivers/gud/README
@@ -0,0 +1,6 @@
+MobiCore is an operating system being shipped with TZBSP
+on msm chipsets. MobiCore consists of several components in
+the secure world(TrustZone) and non-secure world(linux
+kernel, Android user space). The MobiCore driver
+communicates with the MobiCore kernel that exists in
+TrustZone.
diff --git a/drivers/gud/mobicore_driver/build_tag.h b/drivers/gud/mobicore_driver/build_tag.h
new file mode 100644
index 0000000..43541bb
--- /dev/null
+++ b/drivers/gud/mobicore_driver/build_tag.h
@@ -0,0 +1,29 @@
+/**
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2012-2012 -->
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *	notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *	notice, this list of conditions and the following disclaimer in the
+ *	documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *	products derived from this software without specific prior
+ *	written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#define MOBICORE_COMPONENT_BUILD_TAG "*** GC_MSM8960_Release_V010 ###"
diff --git a/drivers/gud/mobicore_driver/logging.c b/drivers/gud/mobicore_driver/logging.c
new file mode 100644
index 0000000..eb44c8a
--- /dev/null
+++ b/drivers/gud/mobicore_driver/logging.c
@@ -0,0 +1,336 @@
+/** MobiCore driver module.(interface to the secure world SWD)
+ * @addtogroup MCD_MCDIMPL_KMOD_LOGGING MobiCore Driver Logging Subsystem.
+ * @ingroup  MCD_MCDIMPL_KMOD
+ * @{
+ * @file
+ * MobiCore Driver Logging Subsystem.
+ * The logging subsytem provides the interface between the Mobicore trace
+ * buffer and the Linux log
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include "mc_drv_module.h"
+#include "mc_drv_module_linux_api.h"
+#include "mc_drv_module_fastcalls.h"
+
+/* Default len of the log ring buffer 256KB*/
+#define LOG_BUF_SIZE	(64 * PAGE_SIZE)
+
+/* Max Len of a log line for printing */
+#define LOG_LINE_SIZE	256
+
+static uint32_t log_size = LOG_BUF_SIZE;
+module_param(log_size, uint, 0);
+MODULE_PARM_DESC(log_size, " Size of the MobiCore log ringbuffer "
+						"(or 256KB default).");
+
+/*----------------------------------------------------------------------------*/
+/* Definitions for log version 2 */
+#define LOG_TYPE_MASK				(0x0007)
+#define LOG_TYPE_CHAR				0
+#define LOG_TYPE_INTEGER			1
+/* Field length */
+#define LOG_LENGTH_MASK				(0x00F8)
+#define LOG_LENGTH_SHIFT			3
+/* Extra attributes */
+#define LOG_EOL					(0x0100)
+#define LOG_INTEGER_DECIMAL			(0x0200)
+#define LOG_INTEGER_SIGNED			(0x0400)
+
+struct logmsg_struct {
+	/* Type and format of data */
+	uint16_t ctrl;
+	/* Unique value for each event source */
+	uint16_t source;
+	/* Value, if any */
+	uint32_t log_data;
+};
+
+/** MobiCore log previous position */
+static uint32_t log_pos;
+/** MobiCore log buffer structure */
+static struct mc_trace_buf *log_buf;
+/** Log Thread task structure */
+struct task_struct *log_thread;
+/** Log Line buffer */
+static char *log_line;
+
+static void log_msg(struct logmsg_struct *msg);
+
+/*----------------------------------------------------------------------------*/
+static void log_eol(void)
+{
+	if (!strnlen(log_line, LOG_LINE_SIZE))
+		return;
+	printk(KERN_INFO "%s\n", log_line);
+	log_line[0] = 0;
+}
+/*----------------------------------------------------------------------------*/
+/**
+ * Put a char to the log line if there is enough space if not then also
+ * output the line. Assume nobody else is updating the line! */
+static void log_char(char ch)
+{
+	uint32_t len;
+	if (ch == '\n' || ch == '\r') {
+		log_eol();
+		return;
+	}
+
+	if (strnlen(log_line, LOG_LINE_SIZE) >= LOG_LINE_SIZE - 1) {
+		printk(KERN_INFO "%s\n", log_line);
+		log_line[0] = 0;
+	}
+
+	len = strnlen(log_line, LOG_LINE_SIZE);
+	log_line[len] = ch;
+	log_line[len + 1] = 0;
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Put a string to the log line if there is enough space if not then also
+ * output the line. Assume nobody else is updating the line! */
+static void log_str(const char *s)
+{
+	int i;
+	for (i = 0; i < strnlen(s, LOG_LINE_SIZE); i++)
+		log_char(s[i]);
+}
+
+/*----------------------------------------------------------------------------*/
+static uint32_t process_v1log(void)
+{
+	char *last_char = log_buf->buff + log_buf->write_pos;
+	char *buff = log_buf->buff + log_pos;
+	while (buff != last_char) {
+		log_char(*(buff++));
+		/* Wrap around */
+		if (buff - (char *)log_buf >= log_size)
+			buff = log_buf->buff;
+	}
+	return buff - log_buf->buff;
+}
+
+/*----------------------------------------------------------------------------*/
+static uint32_t process_v2log(void)
+{
+	char *last_msg = log_buf->buff + log_buf->write_pos;
+	char *buff = log_buf->buff + log_pos;
+	while (buff != last_msg) {
+		log_msg((struct logmsg_struct *)buff);
+		buff += sizeof(struct logmsg_struct);
+		/* Wrap around */
+		if (buff + sizeof(struct logmsg_struct) >
+			(char *)log_buf + log_size)
+			buff = log_buf->buff;
+	}
+	return buff - log_buf->buff;
+}
+
+static const uint8_t HEX2ASCII[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
+				'8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+
+/*----------------------------------------------------------------------------*/
+static void dbg_raw_nro(uint32_t format, uint32_t value)
+{
+	int digits = 1;
+	uint32_t base = (format & LOG_INTEGER_DECIMAL) ? 10 : 16;
+	int width = (format & LOG_LENGTH_MASK) >> LOG_LENGTH_SHIFT;
+	int negative = FALSE;
+	uint32_t digit_base = 1;
+
+	if ((format & LOG_INTEGER_SIGNED) != 0 && ((signed int)value) < 0) {
+			negative = TRUE;
+			value = (uint32_t)(-(signed int)value);
+			width--;
+	}
+
+	/* Find length and divider to get largest digit */
+	while (value / digit_base >= base) {
+			digit_base *= base;
+			digits++;
+	}
+
+	if (width > digits) {
+		char ch = (base == 10) ? ' ' : '0';
+		while (width > digits) {
+			log_char(ch);
+			width--;
+		}
+	}
+
+	if (negative)
+		log_char('-');
+
+	while (digits-- > 0) {
+		uint32_t d = value / digit_base;
+		log_char(HEX2ASCII[d]);
+		value = value - d * digit_base;
+		digit_base /= base;
+	}
+}
+
+/*----------------------------------------------------------------------------*/
+static void log_msg(struct logmsg_struct *msg)
+{
+	unsigned char msgtxt[5];
+	int mpos = 0;
+	switch (msg->ctrl & LOG_TYPE_MASK) {
+	case LOG_TYPE_CHAR: {
+		uint32_t ch;
+		ch = msg->log_data;
+		while (ch != 0) {
+			msgtxt[mpos++] = ch&0xFF;
+			ch >>= 8;
+		}
+		msgtxt[mpos] = 0;
+		log_str(msgtxt);
+		break;
+	}
+	case LOG_TYPE_INTEGER: {
+		dbg_raw_nro(msg->ctrl, msg->log_data);
+		break;
+	}
+	default:
+		break;
+	}
+	if (msg->ctrl & LOG_EOL)
+		log_eol();
+}
+
+/*----------------------------------------------------------------------------*/
+static int log_worker(void *p)
+{
+	if (log_buf == NULL)
+		return -EFAULT;
+
+	/* The thread should have never started */
+	if (log_buf == NULL)
+		return -EFAULT;
+
+	while (!kthread_should_stop()) {
+		if (log_buf->write_pos == log_pos)
+			schedule_timeout_interruptible(MAX_SCHEDULE_TIMEOUT);
+
+		switch (log_buf->version) {
+		case 1:
+			log_pos = process_v1log();
+			break;
+		case 2:
+			log_pos = process_v2log();
+			break;
+		default:
+			MCDRV_DBG_ERROR("Unknown Mobicore log data "
+				"version %d logging disabled.",
+				log_buf->version);
+			log_pos = log_buf->write_pos;
+			/* Stop the thread as we have no idea what
+			 * happens next */
+			return -EFAULT;
+		}
+	}
+	MCDRV_DBG("Logging thread stopped!");
+	return 0;
+}
+
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Wakeup the log reader thread
+ * This should be called from the places where calls into MobiCore have
+ * generated some logs(eg, yield, SIQ...)
+ */
+void mobicore_log_read(void)
+{
+	if (log_thread == NULL || IS_ERR(log_thread))
+		return;
+
+	wake_up_process(log_thread);
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Setup mobicore kernel log. It assumes it's running on CORE 0!
+ * The fastcall will complain is that is not the case!
+ */
+long mobicore_log_setup(void *data)
+{
+	unsigned long phys_log_buf;
+	union fc_generic fc_log;
+
+	log_pos = 0;
+	log_buf = NULL;
+	log_thread = NULL;
+	log_line = NULL;
+
+	/* Sanity check for the log size */
+	if (log_size < PAGE_SIZE)
+		return -EFAULT;
+	else
+		log_size =
+			get_nr_of_pages_for_buffer(NULL, log_size) * PAGE_SIZE;
+
+	log_line = kzalloc(LOG_LINE_SIZE, GFP_KERNEL);
+	if (IS_ERR(log_line)) {
+		MCDRV_DBG_ERROR("failed to allocate log line!");
+		return -ENOMEM;
+	}
+
+	log_thread = kthread_create(log_worker, NULL, "mobicore_log");
+	if (IS_ERR(log_thread)) {
+		MCDRV_DBG_ERROR("mobicore log thread creation failed!");
+		return -EFAULT;
+	}
+
+	log_pos = 0;
+	log_buf = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
+					size_to_order(log_size));
+	if (!log_buf) {
+		MCDRV_DBG_ERROR("Failed to get page for logger!");
+		return -ENOMEM;
+	}
+	phys_log_buf = virt_to_phys(log_buf);
+
+	memset(&fc_log, 0, sizeof(fc_log));
+	fc_log.as_in.cmd      = MC_FC_NWD_TRACE;
+	fc_log.as_in.param[0] = phys_log_buf;
+	fc_log.as_in.param[1] = log_size;
+
+	MCDRV_DBG("fc_log virt=%p phys=%p ", log_buf, (void *)phys_log_buf);
+	mc_fastcall(&fc_log);
+	MCDRV_DBG("fc_log out ret=0x%08x", fc_log.as_out.ret);
+	/* If the setup failed we must free the memory allocated */
+	if (fc_log.as_out.ret) {
+		MCDRV_DBG_ERROR("MobiCore shared traces setup failed!");
+		kthread_stop(log_thread);
+		free_pages((unsigned long)log_buf, size_to_order(log_size));
+
+		log_buf = NULL;
+		log_thread = NULL;
+		return -EIO;
+	}
+
+	MCDRV_DBG("fc_log Logger version %u\n", log_buf->version);
+	return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Free kernel log componenets.
+ * ATTN: We can't free the log buffer because it's also in use by MobiCore and
+ * even if the module is unloaded MobiCore is still running.
+ */
+void mobicore_log_free(void)
+{
+	if (log_thread && !IS_ERR(log_thread)) {
+		/* We don't really care what the thread returns for exit */
+		kthread_stop(log_thread);
+	}
+
+	kfree(log_line);
+}
diff --git a/drivers/gud/mobicore_driver/main.c b/drivers/gud/mobicore_driver/main.c
new file mode 100644
index 0000000..9a99c5c
--- /dev/null
+++ b/drivers/gud/mobicore_driver/main.c
@@ -0,0 +1,2868 @@
+/** MobiCore driver module.(interface to the secure world SWD)
+ * @addtogroup MCD_MCDIMPL_KMOD_IMPL
+ * @{
+ * @file
+ * MobiCore Driver Kernel Module.
+ * This module is written as a Linux device driver.
+ * This driver represents the command proxy on the lowest layer, from the
+ * secure world to the non secure world, and vice versa.
+ * This driver is located in the non secure world (Linux).
+ * This driver offers IOCTL commands, for access to the secure world, and has
+ * the interface from the secure world to the normal world.
+ * The access to the driver is possible with a file descriptor,
+ * which has to be created by the fd = open(/dev/mobicore) command.
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "mc_drv_module.h"
+#include "mc_drv_module_linux_api.h"
+#include "mc_drv_module_android.h"
+#include "mc_drv_module_fastcalls.h"
+#include "public/mc_kernel_api.h"
+
+/* Initial value for the daemon sempahore signaling */
+#define DAEMON_SEM_VAL 0
+
+/** MobiCore interrupt context data */
+static struct mc_drv_kmod_ctx	mc_drv_kmod_ctx;
+
+/** MobiCore MCI information */
+static uint32_t mci_base;
+/*
+#############################################################################
+##
+## Convenience functions for Linux API functions
+##
+#############################################################################*/
+static int goto_cpu0(void);
+static int goto_all_cpu(void) __attribute__ ((unused));
+
+
+/*----------------------------------------------------------------------------*/
+static void init_and_add_to_list(
+	struct list_head *item,
+	struct list_head *list_head
+)
+{
+	INIT_LIST_HEAD(item);
+
+	list_add(item, list_head);
+}
+
+/*----------------------------------------------------------------------------*/
+/** check if CPU supports the ARM TrustZone Security Extensions
+ *	@return int TRUE or FALSE */
+static int has_security_extensions(
+	void
+)
+{
+	u32 fea = 0;
+	asm volatile(
+		"mrc p15, 0, %[fea], cr0, cr1, 0" :
+		[fea]"=r" (fea));
+
+	MCDRV_DBG_VERBOSE("CPU Features: 0x%X", fea);
+
+	/* If the CPU features ID has 0 for security features then the CPU
+	 * doesn't support TrustZone at all!
+	 */
+	if ((fea & ARM_SECURITY_EXTENSION_MASK) == 0)
+		return 0;
+
+	return 1;
+}
+
+/*----------------------------------------------------------------------------*/
+/** check if running in secure mode
+ *	@return int TRUE or FALSE */
+static int is_secure_mode(
+	void
+)
+{
+	u32 cpsr = 0, nsacr = 0;
+	asm volatile(
+		"mrc	p15, 0, %[nsacr], cr1, cr1, 2\n"
+		"mrs %[cpsr], cpsr\n" :
+		[nsacr]"=r" (nsacr),
+		[cpsr]"=r"(cpsr));
+
+	MCDRV_DBG_VERBOSE("CPRS.M = set to 0x%X\n", cpsr & ARM_CPSR_MASK);
+	MCDRV_DBG_VERBOSE("SCR.NS = set to 0x%X\n", nsacr);
+
+	/* If the NSACR contains the reset value(=0) then most likely we are
+	 * running in Secure MODE.
+	 * If the cpsr mode is set to monitor mode then we cannot load!
+	 */
+	if (nsacr == 0 || ((cpsr & ARM_CPSR_MASK) == ARM_MONITOR_MODE))
+		return 1;
+
+	return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+/** check if userland caller is privileged (aka has "root" access rights).
+	@return int TRUE or FALSE */
+static int is_userland_caller_privileged(
+	void
+) {
+	/* For some platforms we cannot run the Daemon as root - for Android
+	 * compliance tests it is not allowed, thus we assume the daemon is ran
+	 * as the system user.
+	 * In Android the system user for daemons has no particular capabilities
+	 * other than a fixed UID: AID_SYSTEM 1000
+	 * The actual number is guaranteed to be the same in all Android systems
+	 * so we will take it for granted: see android_filesystem_config.h in
+	 * the Android source tree for all UIDs and their meaning:
+	 * http://android-dls.com/wiki/index.php?title=Android_UIDs_and_GIDs
+	 */
+#ifdef MC_ANDROID_UID_CHECK
+	return current_euid() <= AID_SYSTEM;
+#else
+	/* capable should cover all possibilities, root or sudo, uid checking
+	 * was not very reliable */
+	return capable(CAP_SYS_ADMIN);
+#endif
+}
+
+
+
+/*----------------------------------------------------------------------------*/
+static void unlock_page_from_used_l2_table(
+	struct page *page
+){
+	/* REV axh: check if we should do this. */
+	SetPageDirty(page);
+
+	/* release page, old api was page_cache_release() */
+	ClearPageReserved(page);
+	put_page(page);
+}
+
+/*----------------------------------------------------------------------------*/
+/* convert L2 PTE to page pointer */
+static struct page *l2_pte_to_page(
+	pte_t pte
+) {
+	void *phys_page_addr	= (void *)((unsigned int)pte & PAGE_MASK);
+	unsigned int pfn	= addr_to_pfn(phys_page_addr);
+	struct page *page	= pfn_to_page(pfn);
+	return page;
+}
+
+/*----------------------------------------------------------------------------*/
+/* convert page pointer to L2 PTE */
+static pte_t page_to_l2_pte(
+	struct page *page
+)
+{
+	unsigned int pfn	= page_to_pfn(page);
+	void *phys_addr		= pfn_to_addr(pfn);
+	pte_t pte		= (pte_t)((unsigned int)phys_addr & PAGE_MASK);
+	return pte;
+}
+
+
+/*----------------------------------------------------------------------------*/
+static inline int lock_user_pages(
+	struct task_struct	*task,
+	void			*virt_start_page_addr,
+	int			nr_of_pages,
+	struct page		**pages
+)
+{
+	int		ret = 0;
+	int		locked_pages = 0;
+	unsigned int	i;
+
+	do {
+
+		/* lock user pages, must hold the mmap_sem to do this. */
+		down_read(&(task->mm->mmap_sem));
+		locked_pages = get_user_pages(
+					  task,
+					  task->mm,
+					  (unsigned long)virt_start_page_addr,
+					  nr_of_pages,
+					  1, /* write access */
+					  0, /* they say drivers should always
+						pass 0 here..... */
+					  pages,
+					  NULL); /* we don't need the VMAs */
+		up_read(&(task->mm->mmap_sem));
+
+		/* could as lock all pages? */
+		if (locked_pages != nr_of_pages) {
+			MCDRV_DBG_ERROR(
+				"get_user_pages() failed, "
+				"locked_pages=%d\n",
+				locked_pages);
+			ret = -ENOMEM;
+			/* check if an error has been returned. */
+			if (locked_pages < 0) {
+				ret = locked_pages;
+				locked_pages = 0;
+			}
+			break;
+		}
+
+		/* do cache maintenance on locked pages. */
+		for (i = 0; i < nr_of_pages; i++)
+			flush_dcache_page(pages[i]);
+
+	} while (FALSE);
+
+
+	if (ret != 0) {
+		/* release all locked pages. */
+		MCDRV_ASSERT(locked_pages >= 0);
+		for (i = 0; i < locked_pages; i++)
+			put_page(pages[i]);
+	}
+
+	return ret;
+
+}
+
+/*
+#############################################################################
+##
+## Driver implementation functions
+##
+#############################################################################*/
+/*----------------------------------------------------------------------------*/
+/* check if caller is MobiCore Daemon */
+static unsigned int is_caller_mc_daemon(
+	struct mc_instance *instance
+)
+{
+	return ((instance != NULL)
+		&& (mc_drv_kmod_ctx.daemon_inst == instance));
+}
+
+
+/*----------------------------------------------------------------------------*/
+/* Get process context from file pointer */
+static struct mc_instance *get_instance(
+	struct file *file
+) {
+	MCDRV_ASSERT(file != NULL);
+
+	return (struct mc_instance *)(file->private_data);
+}
+
+
+/*----------------------------------------------------------------------------*/
+/* Get a unique ID */
+static unsigned int get_mc_kmod_unique_id(
+	void
+)
+{
+	return (unsigned int)atomic_inc_return(
+			   &(mc_drv_kmod_ctx.unique_counter));
+}
+
+
+/*----------------------------------------------------------------------------*/
+/* Get kernel pointer to shared L2 table given a per-process reference */
+static struct l2table *get_l2_table_kernel_virt(
+	struct mc_used_l2_table	*used_l2table
+)
+{
+	MCDRV_ASSERT(used_l2table != NULL);
+	MCDRV_ASSERT(used_l2table->set != NULL);
+	MCDRV_ASSERT(used_l2table->set->kernel_virt != NULL);
+	return &(used_l2table->set->kernel_virt->table[used_l2table->idx]);
+}
+
+/*----------------------------------------------------------------------------*/
+/* Get physical address of a shared L2 table given a per-process reference */
+static struct l2table *get_l2_table_phys(
+	struct mc_used_l2_table  *used_l2table
+)
+{
+	MCDRV_ASSERT(used_l2table != NULL);
+	MCDRV_ASSERT(used_l2table->set != NULL);
+	MCDRV_ASSERT(used_l2table->set->phys != NULL);
+	return &(used_l2table->set->phys->table[used_l2table->idx]);
+}
+
+/*----------------------------------------------------------------------------*/
+static unsigned int is_in_use_used_l2_table(
+	struct mc_used_l2_table	*used_l2table
+)
+{
+	return ((used_l2table->flags &
+			  (MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_APP
+			   | MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC)) != 0);
+}
+
+
+
+/*----------------------------------------------------------------------------*/
+static struct mc_used_l2_table *find_used_l2_table_by_handle(
+	unsigned int	handle
+) {
+	struct mc_used_l2_table  *used_l2table;
+	struct mc_used_l2_table  *used_l2table_with_handle = NULL;
+
+	list_for_each_entry(
+		used_l2table,
+		&(mc_drv_kmod_ctx.mc_used_l2_tables),
+		list
+	) {
+		if (handle == used_l2table->handle) {
+			used_l2table_with_handle = used_l2table;
+			break;
+		}
+	}
+
+	return used_l2table_with_handle;
+}
+
+/*
+#############################################################################
+##
+## L2 Table Pool
+##
+#############################################################################*/
+
+/*----------------------------------------------------------------------------*/
+static struct mc_used_l2_table *allocate_used_l2_table(
+	struct mc_instance	*instance
+) {
+	int				ret = 0;
+	struct mc_l2_table_store	*l2table_store = NULL;
+	struct mc_l2_tables_set		*l2table_set = NULL;
+	struct mc_used_l2_table		*used_l2table = NULL;
+	struct page			*page;
+	unsigned int			i = 0;
+
+	do {
+		/* allocate a WSM L2 descriptor */
+		used_l2table  = kmalloc(sizeof(*used_l2table), GFP_KERNEL);
+		if (used_l2table == NULL) {
+			ret = -ENOMEM;
+			MCDRV_DBG_ERROR("out of memory\n");
+			break;
+		}
+		/* clean */
+		memset(used_l2table, 0, sizeof(*used_l2table));
+		used_l2table->handle = get_mc_kmod_unique_id();
+		used_l2table->owner = instance;
+
+		/* add to global list. */
+		init_and_add_to_list(
+			&(used_l2table->list),
+			&(mc_drv_kmod_ctx.mc_used_l2_tables));
+
+		/* walk though list to find free set. */
+		list_for_each_entry(
+			l2table_set,
+			&(mc_drv_kmod_ctx.mc_l2_tables_sets),
+			list
+		) {
+			for (i = 0; i < MC_DRV_KMOD_L2_TABLE_PER_PAGES; i++) {
+				if ((l2table_set->usage_bitmap & (1U << i))
+					== 0) {
+					/* found a set,
+						l2table_set and i are set. */
+					l2table_store =
+						l2table_set->kernel_virt;
+					break;
+				}
+			}
+			if (l2table_store != NULL)
+				break;
+		} /* end while */
+
+		if (l2table_store == NULL) {
+			l2table_store = (struct mc_l2_table_store *)
+						get_zeroed_page(GFP_KERNEL);
+			if (l2table_store == NULL) {
+				ret = -ENOMEM;
+				break;
+			}
+
+			/* Actually, locking is not necessary, because kernel
+				memory is not supposed to get swapped out. But
+				we play safe.... */
+			page = virt_to_page(l2table_store);
+			SetPageReserved(page);
+
+			/* allocate a descriptor */
+			l2table_set = kmalloc(sizeof(*l2table_set), GFP_KERNEL);
+			if (l2table_set == NULL) {
+				kfree(l2table_store);
+				ret = -ENOMEM;
+				break;
+			}
+			/* initialize */
+			memset(l2table_set, 0, sizeof(*l2table_set));
+
+			l2table_set->kernel_virt = l2table_store;
+			l2table_set->page = page;
+			l2table_set->phys = (void *)virt_to_phys(l2table_store);
+
+			/* init add to list. */
+			init_and_add_to_list(
+				&(l2table_set->list),
+				&(mc_drv_kmod_ctx.mc_l2_tables_sets));
+
+			/* use first table */
+			i = 0;
+		}
+
+		/* set set usage */
+		l2table_set->usage_bitmap |= (1U << i);
+
+		/* set set reference */
+		used_l2table->set = l2table_set;
+		used_l2table->idx = i;
+
+		MCDRV_DBG_VERBOSE(
+			"chunkPhys=%p,idx=%d\n",
+			l2table_set->phys, i);
+
+	} while (FALSE);
+
+	if (ret != 0) {
+		if (used_l2table != NULL) {
+			/* remove from list */
+			list_del(&(l2table_set->list));
+			/* free memory */
+			kfree(used_l2table);
+			used_l2table = NULL;
+		}
+	}
+
+	return used_l2table;
+}
+
+/*----------------------------------------------------------------------------*/
+static void free_used_l2_table(
+	struct mc_used_l2_table *used_l2table
+)
+{
+	struct mc_l2_tables_set	*l2table_set;
+	unsigned int		idx;
+
+	MCDRV_ASSERT(used_l2table != NULL);
+
+	l2table_set = used_l2table->set;
+	MCDRV_ASSERT(l2table_set != NULL);
+
+	/* clean usage flag */
+	idx = used_l2table->idx;
+	MCDRV_ASSERT(idx < MC_DRV_KMOD_L2_TABLE_PER_PAGES);
+	l2table_set->usage_bitmap &= ~(1U << idx);
+
+	/* if nobody uses this set, we can release it. */
+	if (l2table_set->usage_bitmap == 0) {
+		MCDRV_ASSERT(l2table_set->page != NULL);
+		ClearPageReserved(l2table_set->page);
+
+		MCDRV_ASSERT(l2table_set->kernel_virt != NULL);
+		free_page((unsigned long)l2table_set->kernel_virt);
+
+		/* remove from list */
+		list_del(&(l2table_set->list));
+
+		/* free memory */
+		kfree(l2table_set);
+	}
+
+	return;
+}
+
+
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Create a L2 table in a WSM container that has been allocates previously.
+ *
+ * @param task		pointer to task owning WSM
+ * @param wsm_buffer	user space WSM start
+ * @param wsm_len	WSM length
+ * @param used_l2table	Pointer to L2 table details
+ */
+static int map_buffer_into_used_l2_table(
+	struct task_struct	*task,
+	void			*wsm_buffer,
+	unsigned int		wsm_len,
+	struct mc_used_l2_table	*used_l2table
+)
+{
+	int		ret = 0;
+	unsigned int	i, nr_of_pages;
+	void		*virt_addr_page;
+	struct page	*page;
+	struct l2table	*l2table;
+	struct page	**l2table_as_array_of_pointers_to_page;
+
+	/* task can be null when called from kernel space */
+	MCDRV_ASSERT(wsm_buffer != NULL);
+	MCDRV_ASSERT(wsm_len != 0);
+	MCDRV_ASSERT(used_l2table != NULL);
+
+	MCDRV_DBG_VERBOSE("WSM addr=0x%p, len=0x%08x\n", wsm_buffer, wsm_len);
+
+	/* Check if called from kernel space wsm_buffer is actually
+	 * vmalloced or not */
+	if (task == NULL && !is_vmalloc_addr(wsm_buffer)) {
+		MCDRV_DBG_ERROR("WSM addr is not a vmalloc address");
+		return -EINVAL;
+	}
+
+	l2table = get_l2_table_kernel_virt(used_l2table);
+	/* We use the memory for the L2 table to hold the pointer
+	and convert them later. This works, as everything comes
+	down to a 32 bit value. */
+	l2table_as_array_of_pointers_to_page = (struct page **)l2table;
+
+	do {
+
+		/* no size > 1Mib supported */
+		if (wsm_len > SZ_1M) {
+			MCDRV_DBG_ERROR("size > 1 MiB\n");
+			ret = -EINVAL;
+			break;
+		}
+
+		/* calculate page usage */
+		virt_addr_page = get_page_start(wsm_buffer);
+		nr_of_pages  = get_nr_of_pages_for_buffer(wsm_buffer, wsm_len);
+
+
+		MCDRV_DBG_VERBOSE("virt addr pageStart=0x%p,pages=%d\n",
+				  virt_addr_page,
+				  nr_of_pages);
+
+		/* L2 table can hold max 1MiB in 256 pages. */
+		if ((nr_of_pages*PAGE_SIZE) > SZ_1M) {
+			MCDRV_DBG_ERROR("WSM paged exceed 1 MiB\n");
+			ret = -EINVAL;
+			break;
+		}
+
+		/* Request comes from user space */
+		if (task != NULL) {
+			/* lock user page in memory, so they do not get swapped
+			* out.
+			* REV axh:
+			* Kernel 2.6.27 added a new get_user_pages_fast()
+			* function, maybe it is called fast_gup() in some
+			* versions.
+			* handle user process doing a fork().
+			* Child should not get things.
+			* http://osdir.com/ml/linux-media/2009-07/msg00813.html
+			* http://lwn.net/Articles/275808/ */
+
+			ret = lock_user_pages(
+					  task,
+					  virt_addr_page,
+					  nr_of_pages,
+					  l2table_as_array_of_pointers_to_page);
+			if (ret != 0) {
+				MCDRV_DBG_ERROR("lock_user_pages() failed\n");
+				break;
+			}
+		}
+		/* Request comes from kernel space(vmalloc buffer) */
+		else {
+			void *uaddr = wsm_buffer;
+			for (i = 0; i < nr_of_pages; i++) {
+				page = vmalloc_to_page(uaddr);
+				if (!page) {
+					MCDRV_DBG_ERROR(
+						"vmalloc_to_Page()"
+						" failed to map address\n");
+					ret = -EINVAL;
+					break;
+				}
+				get_page(page);
+				/* Lock the page in memory, it can't be swapped
+				 * out */
+				SetPageReserved(page);
+				l2table_as_array_of_pointers_to_page[i] = page;
+				uaddr += PAGE_SIZE;
+			}
+		}
+
+		used_l2table->nr_of_pages = nr_of_pages;
+		used_l2table->flags |= MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_APP;
+
+		/* create L2 Table entries. used_l2table->table contains a list
+		of page pointers here. For a proper cleanup we have to ensure
+		that the following code either works and used_l2table contains
+		a valid L2 table - or fails and used_l2table->table contains the
+		list of page pointers. Any mixed contents will make cleanup
+		difficult.*/
+
+		for (i = 0; i < nr_of_pages; i++) {
+			pte_t pte;
+			page = l2table_as_array_of_pointers_to_page[i];
+
+			/* create L2 table entry, see ARM MMU docu for details
+			about flags stored in the lowest 12 bits. As a side
+			reference, the Article "ARM's multiply-mapped memory
+			mess" found in the collection at at
+			http://lwn.net/Articles/409032/ is also worth reading.*/
+			pte = page_to_l2_pte(page)
+					| L2_FLAG_AP1 | L2_FLAG_AP0
+					| L2_FLAG_C | L2_FLAG_B
+					| L2_FLAG_SMALL | L2_FLAG_SMALL_XN
+			/* Linux uses different mappings for SMP systems(the
+			 * sharing flag is set for the pte. In order not to
+			 * confuse things too much in Mobicore make sure the
+			 * shared buffers have the same flags.
+			 * This should also be done in SWD side
+			 */
+#ifdef CONFIG_SMP
+					| L2_FLAG_S | L2_FLAG_SMALL_TEX0
+#endif
+				  ;
+
+			l2table->table_entries[i] = pte;
+			MCDRV_DBG_VERBOSE("L2 entry %d:  0x%08x\n", i,
+					  (unsigned int)(pte));
+		}
+
+		/* ensure rest of table is empty */
+		while (i < 255)
+			l2table->table_entries[i++] = (pte_t)0;
+
+	} while (FALSE);
+
+	return ret;
+}
+
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Remove a L2 table in a WSM container. Afterwards the container may be
+ * released.
+ *
+ * @param used_l2table	Pointer to L2 table details
+ */
+
+static void unmap_buffers_from_used_l2_table(
+	struct mc_used_l2_table	*used_l2table
+)
+{
+	unsigned int	i;
+	struct l2table	*l2table;
+
+	MCDRV_ASSERT(used_l2table != NULL);
+	/* this should not happen, as we have no empty tables. */
+	MCDRV_ASSERT(!is_in_use_used_l2_table(used_l2table));
+
+	/* found the table, now release the resources. */
+	MCDRV_DBG_VERBOSE("clear L2 table, phys_base=%p, nr_of_pages=%d\n",
+			  get_l2_table_phys(used_l2table),
+			  used_l2table->nr_of_pages);
+
+	l2table = get_l2_table_kernel_virt(used_l2table);
+
+	/* release all locked user space pages */
+	for (i = 0; i < used_l2table->nr_of_pages; i++) {
+		/* convert physical entries from L2 table to page pointers */
+		pte_t pte = get_l2_table_kernel_virt(used_l2table)->
+							table_entries[i];
+		struct page *page = l2_pte_to_page(pte);
+		unlock_page_from_used_l2_table(page);
+	}
+
+	/* remember that all pages have been freed */
+	used_l2table->nr_of_pages = 0;
+
+	return;
+}
+
+
+/*
+#############################################################################
+##
+## Helper functions
+##
+#############################################################################*/
+/*----------------------------------------------------------------------------*/
+#define FREE_FROM_SWD	TRUE
+#define FREE_FROM_NWD	FALSE
+/** Delete a used l2 table. */
+static void delete_used_l2_table(
+	struct mc_used_l2_table	*used_l2table,
+	unsigned int		is_swd
+)
+{
+	if (is_swd) {
+		used_l2table->flags &=
+			~MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC;
+	} else {
+		used_l2table->flags &=
+			~MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_APP;
+		used_l2table->owner = NULL;
+	}
+
+	/* release if Nwd and Swd/MC do no longer use it. */
+	if (is_in_use_used_l2_table(used_l2table)) {
+		MCDRV_DBG_WARN(
+			"WSM L2 table still in use: physBase=%p, "
+			"nr_of_pages=%d\n",
+			get_l2_table_phys(used_l2table),
+			used_l2table->nr_of_pages);
+	} else {
+		unmap_buffers_from_used_l2_table(used_l2table);
+		free_used_l2_table(used_l2table);
+
+		list_del(&(used_l2table->list));
+
+		kfree(used_l2table);
+	}
+	return;
+}
+
+/*----------------------------------------------------------------------------*/
+/** Allocate L2 table and map buffer into it. That is, create respective table
+	entries. Must hold Semaphore mc_drv_kmod_ctx.wsm_l2_sem */
+static struct mc_used_l2_table *new_used_l2_table(
+	struct mc_instance	*instance,
+	struct task_struct	*task,
+	void			*wsm_buffer,
+	unsigned int		wsm_len
+) {
+	int			ret = 0;
+	struct mc_used_l2_table	*used_l2table;
+
+	do {
+		used_l2table = allocate_used_l2_table(instance);
+		if (used_l2table == NULL) {
+			MCDRV_DBG_ERROR(
+				"allocate_used_l2_table() failed\n");
+			break;
+		}
+
+		/* create the L2 page for the WSM */
+		ret = map_buffer_into_used_l2_table(
+				  task,
+				  wsm_buffer,
+				  wsm_len,
+				  used_l2table);
+		if (ret != 0) {
+			MCDRV_DBG_ERROR(
+				"map_buffer_into_used_l2_table() failed\n");
+			delete_used_l2_table(used_l2table, FREE_FROM_NWD);
+			used_l2table = NULL;
+			break;
+		}
+
+	} while (FALSE);
+
+
+	return used_l2table;
+}
+
+/*
+#############################################################################
+##
+## IoCtl handler
+##
+#############################################################################*/
+
+/**
+ * Map a virtual memory buffer structure to Mobicore
+ * @param instance
+ * @param addr		address of the buffer(NB it must be kernel virtual!)
+ * @param len		buffer length
+ * @param handle	pointer to handle
+ * @param phys_wsm_l2_table	pointer to physical L2 table(?)
+ *
+ * @return 0 if no error
+ *
+ */
+/*----------------------------------------------------------------------------*/
+int mobicore_map_vmem(
+	struct mc_instance	*instance,
+	void			*addr,
+	uint32_t		len,
+	uint32_t		*handle,
+	void			**phys_wsm_l2_table
+)
+{
+	int ret = 0;
+	struct mc_used_l2_table *used_l2table = NULL;
+	MCDRV_ASSERT(instance != NULL);
+
+	MCDRV_DBG_VERBOSE("enter\n");
+
+	do {
+		if (len == 0) {
+			MCDRV_DBG_ERROR("len=0 is not supported!\n");
+			ret = -EINVAL;
+			break;
+		}
+
+		/* try to get the semaphore */
+		ret = down_interruptible(&(mc_drv_kmod_ctx.wsm_l2_sem));
+		if (ret != 0) {
+			MCDRV_DBG_ERROR("down_interruptible() failed with %d\n",
+					ret);
+			ret = -ERESTARTSYS;
+			break;
+		}
+
+		do {
+			used_l2table = new_used_l2_table(
+						   instance,
+						   NULL,
+						   addr,
+						   len);
+
+			if (used_l2table == NULL) {
+				MCDRV_DBG_ERROR("new_used_l2_table() failed\n");
+				ret = -EINVAL;
+				break;
+			}
+
+			/* set response */
+			*handle = used_l2table->handle;
+			*phys_wsm_l2_table =
+				(void *)get_l2_table_phys(used_l2table);
+			MCDRV_DBG_VERBOSE("handle: %d, phys=%p\n",
+					  *handle,
+					  (void *)(*phys_wsm_l2_table));
+
+		} while (FALSE);
+
+		/* release semaphore */
+		up(&(mc_drv_kmod_ctx.wsm_l2_sem));
+
+	} while (FALSE);
+
+	MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
+
+	return ret;
+}
+EXPORT_SYMBOL(mobicore_map_vmem);
+/*----------------------------------------------------------------------------*/
+/**
+ *
+ * @param instance
+ * @param arg
+ *
+ * @return 0 if no error
+ *
+ */
+static int handle_ioctl_app_register_wsm_l2(
+	struct mc_instance			*instance,
+	union mc_ioctl_app_reg_wsm_l2_params	*user_params
+)
+{
+	int					ret = 0;
+	union mc_ioctl_app_reg_wsm_l2_params	params;
+	struct mc_used_l2_table			*used_l2table = NULL;
+	struct pid				*pid_struct = NULL;
+	struct task_struct			*task = current;
+
+	MCDRV_ASSERT(instance != NULL);
+
+	MCDRV_DBG_VERBOSE("enter\n");
+
+	do {
+		/* get use parameters */
+		ret = copy_from_user(
+				  &(params.in),
+				  &(user_params->in),
+				  sizeof(params.in));
+		if (ret != 0) {
+			MCDRV_DBG_ERROR("copy_from_user() failed\n");
+			break;
+		}
+
+		/* daemon can do this for another task. */
+		if (params.in.pid != 0) {
+			MCDRV_DBG_ERROR("pid != 0 unsupported\n");
+			ret = -EINVAL;
+			break;
+		}
+		if (params.in.len == 0) {
+			MCDRV_DBG_ERROR("len=0 is not supported!\n");
+			ret = -EINVAL;
+			break;
+		}
+
+		/* try to get the semaphore */
+		ret = down_interruptible(&(mc_drv_kmod_ctx.wsm_l2_sem));
+		if (ret != 0) {
+			MCDRV_DBG_ERROR("down_interruptible() failed with %d\n",
+					ret);
+			ret = -ERESTARTSYS;
+			break;
+		}
+
+		do {
+			used_l2table = new_used_l2_table(
+						   instance,
+						   task,
+						   (void *)(params.in.buffer),
+						   params.in.len);
+
+			if (used_l2table == NULL) {
+				MCDRV_DBG_ERROR("new_used_l2_table() failed\n");
+				ret = -EINVAL;
+				break;
+			}
+
+			/* if the daemon does this, we set the MC lock */
+			if (is_caller_mc_daemon(instance))
+				used_l2table->flags |=
+					MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC;
+
+			/* set response */
+			memset(&params.out, 0, sizeof(params.out));
+			params.out.handle = used_l2table->handle;
+			/* TODO: return the physical address for daemon only,
+				otherwise set NULL */
+			params.out.phys_wsm_l2_table =
+				(uint32_t)get_l2_table_phys(used_l2table);
+
+			MCDRV_DBG_VERBOSE("handle: %d, phys=%p\n",
+					params.out.handle,
+					(void *)(params.out.phys_wsm_l2_table));
+
+
+			/* copy L2Table to user space */
+			ret = copy_to_user(
+					  &(user_params->out),
+					  &(params.out),
+					  sizeof(params.out));
+			if (ret != 0) {
+				MCDRV_DBG_ERROR("copy_to_user() failed\n");
+
+				/* free the table again, as app does not know
+					about anything. */
+				if (is_caller_mc_daemon(instance)) {
+					used_l2table->flags &=
+					~MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC;
+				}
+				delete_used_l2_table(used_l2table,
+						FREE_FROM_NWD);
+				used_l2table = NULL;
+				break;
+			}
+
+		} while (FALSE);
+
+		/* release semaphore */
+		up(&(mc_drv_kmod_ctx.wsm_l2_sem));
+
+	} while (FALSE);
+
+
+
+	/* release PID struct reference */
+	if (pid_struct != NULL)
+		put_pid(pid_struct);
+
+
+	MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
+
+	return ret;
+}
+
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Unmap a virtual memory buffer from mobicore
+ * @param instance
+ * @param handle
+ *
+ * @return 0 if no error
+ *
+ */
+int mobicore_unmap_vmem(
+	struct mc_instance	*instance,
+	uint32_t		handle
+)
+{
+	int ret = 0;
+	struct mc_used_l2_table *used_l2table = NULL;
+
+	MCDRV_ASSERT(instance != NULL);
+	MCDRV_DBG_VERBOSE("enter\n");
+
+	do {
+		/* try to get the semaphore */
+		ret = down_interruptible(&(mc_drv_kmod_ctx.wsm_l2_sem));
+		if (ret != 0) {
+			MCDRV_DBG_ERROR("processOpenSession() failed with %d\n",
+					ret);
+			ret = -ERESTARTSYS;
+			break;
+		}
+
+		do {
+			used_l2table = find_used_l2_table_by_handle(handle);
+			if (used_l2table == NULL) {
+				ret = -EINVAL;
+				MCDRV_DBG_ERROR("entry not found\n");
+				break;
+			}
+
+			if (instance != used_l2table->owner) {
+				ret = -EINVAL;
+				MCDRV_DBG_ERROR("instance does no own it\n");
+				break;
+			}
+
+			/* free table (if no further locks exist) */
+			delete_used_l2_table(used_l2table, FREE_FROM_NWD);
+			used_l2table = NULL;
+			/* there are no out parameters */
+		} while (FALSE);
+		/* release semaphore */
+		up(&(mc_drv_kmod_ctx.wsm_l2_sem));
+
+	} while (FALSE);
+
+	MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
+
+	return ret;
+}
+EXPORT_SYMBOL(mobicore_unmap_vmem);
+/*----------------------------------------------------------------------------*/
+/**
+ *
+ * @param instance
+ * @param arg
+ *
+ * @return 0 if no error
+ *
+ */
+static int handle_ioctl_app_unregister_wsm_l2(
+	struct mc_instance			*instance,
+	struct mc_ioctl_app_unreg_wsm_l2_params	*user_params
+)
+{
+	int					ret = 0;
+	struct mc_ioctl_app_unreg_wsm_l2_params	params;
+	struct mc_used_l2_table			*used_l2table = NULL;
+
+	MCDRV_ASSERT(instance != NULL);
+	MCDRV_DBG_VERBOSE("enter\n");
+
+	do {
+		ret = copy_from_user(
+				  &(params.in),
+				  &(user_params->in),
+				  sizeof(params.in));
+
+		if (ret != 0) {
+			MCDRV_DBG_ERROR("copy_from_user\n");
+			break;
+		}
+
+		/* try to get the semaphore */
+		ret = down_interruptible(&(mc_drv_kmod_ctx.wsm_l2_sem));
+		if (ret != 0) {
+			MCDRV_DBG_ERROR("down_interruptible() failed with %d\n",
+					ret);
+			ret = -ERESTARTSYS;
+			break;
+		}
+
+		do {
+			/* daemon can do this for another task. */
+			if (params.in.pid != 0) {
+				MCDRV_DBG_ERROR("pid != 0 unsupported\n");
+				ret = -EINVAL;
+				break;
+			}
+
+			used_l2table =
+				find_used_l2_table_by_handle(params.in.handle);
+			if (used_l2table == NULL) {
+				ret = -EINVAL;
+				MCDRV_DBG_ERROR("entry not found\n");
+				break;
+			}
+
+			if (is_caller_mc_daemon(instance)) {
+				/* if daemon does this, we have to release the
+					MobiCore lock. */
+				used_l2table->flags &=
+					~MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC;
+			} else if (instance != used_l2table->owner) {
+				ret = -EINVAL;
+				MCDRV_DBG_ERROR("instance does no own it\n");
+				break;
+			}
+
+			/* free table (if no further locks exist) */
+			delete_used_l2_table(used_l2table, FREE_FROM_NWD);
+			used_l2table = NULL;
+
+			/* there are no out parameters */
+
+		} while (FALSE);
+
+		/* release semaphore */
+		up(&(mc_drv_kmod_ctx.wsm_l2_sem));
+
+	} while (FALSE);
+
+	MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
+
+	return ret;
+}
+
+
+/*----------------------------------------------------------------------------*/
+static int handle_ioctl_daemon_lock_wsm_l2(
+	struct mc_instance				*instance,
+	struct mc_ioctl_daemon_lock_wsm_l2_params	*user_params
+)
+{
+	int						ret = 0;
+	struct mc_ioctl_daemon_lock_wsm_l2_params	params;
+	struct mc_used_l2_table				*used_l2table = NULL;
+
+	MCDRV_ASSERT(instance != NULL);
+	MCDRV_DBG_VERBOSE("enter\n");
+
+	do {
+		if (!is_caller_mc_daemon(instance)) {
+			MCDRV_DBG_ERROR("caller not MobiCore Daemon\n");
+			ret = -EFAULT;
+			break;
+		}
+
+		ret = copy_from_user(
+				  &(params.in),
+				  &(user_params->in),
+				  sizeof(params.in));
+
+		if (ret != 0) {
+			MCDRV_DBG_ERROR("copy_from_user\n");
+			break;
+		}
+		/* try to get the semaphore */
+		ret = down_interruptible(&(mc_drv_kmod_ctx.wsm_l2_sem));
+		if (ret != 0) {
+			MCDRV_DBG_ERROR("down_interruptible() failed with %d\n",
+					ret);
+			ret = -ERESTARTSYS;
+			break;
+		}
+
+		do {
+			used_l2table =
+				find_used_l2_table_by_handle(params.in.handle);
+			if (used_l2table == NULL) {
+				ret = -EINVAL;
+				MCDRV_DBG_ERROR("entry not found\n");
+				break;
+			}
+			if (instance != used_l2table->owner) {
+				ret = -EINVAL;
+				MCDRV_DBG_ERROR("instance does no own it\n");
+				break;
+			}
+
+			/* lock entry */
+			if ((used_l2table->flags &
+				  MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC) != 0) {
+				MCDRV_DBG_WARN("entry already locked\n");
+			}
+			used_l2table->flags |=
+				MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC;
+
+			/* prepare response */
+			memset(&(params.out), 0, sizeof(params.out));
+			params.out.phys_wsm_l2_table =
+				(uint32_t)get_l2_table_phys(used_l2table);
+
+			/* copy to user space */
+			ret = copy_to_user(
+					  &(user_params->out),
+					  &(params.out),
+					  sizeof(params.out));
+			if (ret != 0) {
+				MCDRV_DBG_ERROR("copy_to_user() failed\n");
+
+				/* undo, as userspace did not get it. */
+				used_l2table->flags |=
+					MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC;
+				break;
+			}
+
+		} while (FALSE);
+
+		/* release semaphore */
+		up(&(mc_drv_kmod_ctx.wsm_l2_sem));
+
+	} while (FALSE);
+
+	MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
+
+	return ret;
+}
+
+
+/*----------------------------------------------------------------------------*/
+static int handle_ioctl_daemon_unlock_wsm_l2(
+	struct mc_instance				*instance,
+	struct mc_ioctl_daemon_unlock_wsm_l2_params	*user_params
+)
+{
+	int						ret = 0;
+	struct mc_ioctl_daemon_unlock_wsm_l2_params	params;
+	struct mc_used_l2_table				*used_l2table = NULL;
+
+	MCDRV_ASSERT(instance != NULL);
+	MCDRV_DBG_VERBOSE("enter\n");
+
+	do {
+		if (!is_caller_mc_daemon(instance)) {
+			MCDRV_DBG_ERROR("caller not MobiCore Daemon\n");
+			ret = -EFAULT;
+			break;
+		}
+
+		ret = copy_from_user(
+				  &(params.in),
+				  &(user_params->in),
+				  sizeof(params.in));
+
+		if (ret != 0) {
+			MCDRV_DBG_ERROR("copy_from_user\n");
+			break;
+		}
+		/* try to get the semaphore */
+		ret = down_interruptible(&(mc_drv_kmod_ctx.wsm_l2_sem));
+		if (ret != 0) {
+			MCDRV_DBG_ERROR("down_interruptible() failed with %d\n",
+						ret);
+			ret = -ERESTARTSYS;
+			break;
+		}
+
+		do {
+			used_l2table =
+				find_used_l2_table_by_handle(params.in.handle);
+			if (used_l2table == NULL) {
+				ret = -EINVAL;
+				MCDRV_DBG_ERROR("entry not found\n");
+				break;
+			}
+			if (instance != used_l2table->owner) {
+				ret = -EINVAL;
+				MCDRV_DBG_ERROR("instance does no own it\n");
+				break;
+			}
+
+			/* lock entry */
+			if ((used_l2table->flags &
+				  MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC) == 0) {
+				MCDRV_DBG_WARN("entry is not locked locked\n");
+			}
+
+			/* free table (if no further locks exist) */
+			delete_used_l2_table(used_l2table, FREE_FROM_SWD);
+			used_l2table = NULL;
+
+			/* there are no out parameters */
+
+		} while (FALSE);
+
+	} while (FALSE);
+
+
+	MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
+
+	return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+/** Clears the reserved bit of each page and frees the pages */
+static inline void free_continguous_pages(
+	void		*addr,
+	unsigned int	size
+)
+{
+	struct page *page = virt_to_page(addr);
+	int i;
+	for (i = 0; i < size; i++) {
+		MCDRV_DBG_VERBOSE("free page at 0x%p\n", page);
+		ClearPageReserved(page);
+		page++;
+	}
+	/* REV luh: see man kmalloc */
+	free_pages((unsigned long)addr, size_to_order(size));
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Free a WSM buffer allocated with mobicore_allocate_wsm
+ * @param instance
+ * @param handle		handle of the buffer
+ *
+ * @return 0 if no error
+ *
+ */
+int mobicore_free(
+	struct mc_instance	*instance,
+	uint32_t		handle
+)
+{
+	int ret = 0;
+	unsigned int i;
+	struct mc_contg_buffer	*contg_buffer;
+
+	do {
+		/* search for the given address in the contg_buffers list */
+		for (i = 0; i < MC_DRV_KMOD_CONTG_BUFFER_MAX; i++) {
+			contg_buffer = &(instance->contg_buffers[i]);
+			if (contg_buffer->handle == handle)
+				break;
+		}
+		if (i == MC_DRV_KMOD_CONTG_BUFFER_MAX) {
+			MCDRV_DBG_ERROR("contigous buffer not found\n");
+			ret = -EFAULT;
+			break;
+		}
+
+		MCDRV_DBG_VERBOSE("phys_addr=0x%p, virt_addr=0x%p\n",
+				contg_buffer->phys_addr,
+				contg_buffer->virt_kernel_addr);
+
+		free_continguous_pages(contg_buffer->virt_kernel_addr,
+					contg_buffer->num_pages);
+
+		memset(contg_buffer, 0, sizeof(*contg_buffer));
+
+		/* there are no out parameters */
+
+	} while (FALSE);
+
+
+	return ret;
+}
+EXPORT_SYMBOL(mobicore_free);
+/*----------------------------------------------------------------------------*/
+
+/**
+ *
+ * @param instance
+ * @param arg
+ *
+ * @return 0 if no error
+ *
+ */
+static int handle_ioctl_free(
+	struct mc_instance		*instance,
+	union mc_ioctl_free_params	*user_params
+)
+{
+	int				ret = 0;
+	union mc_ioctl_free_params	params;
+
+
+	MCDRV_ASSERT(instance != NULL);
+	MCDRV_DBG_VERBOSE("enter\n");
+
+	do {
+		ret = copy_from_user(
+				  &(params.in),
+				  &(user_params->in),
+				  sizeof(params.in));
+
+		if (ret != 0) {
+			MCDRV_DBG_ERROR("copy_from_user\n");
+			break;
+		}
+
+		/* daemon can do this for another task. */
+		if (params.in.pid != 0) {
+			MCDRV_DBG_ERROR("pid != 0 unsupported\n");
+			ret = -EINVAL;
+			break;
+		}
+
+		ret = mobicore_free(instance, params.in.handle);
+
+		/* there are no out parameters */
+
+	} while (FALSE);
+
+	MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
+
+	return ret;
+
+}
+
+
+/*----------------------------------------------------------------------------*/
+/**
+ *
+ * @param instance
+ * @param arg
+ *
+ * @return 0 if no error
+ *
+ */
+static int handle_ioctl_info(
+	struct mc_instance	*instance,
+	union mc_ioctl_info_params	*user_params
+)
+{
+	int			ret = 0;
+	union mc_ioctl_info_params	params;
+	union mc_fc_info		fc_info;
+
+
+	MCDRV_ASSERT(instance != NULL);
+	MCDRV_DBG_VERBOSE("enter\n");
+
+	do {
+		/* only the MobiCore Daemon is allowed to call this function */
+		if (!is_caller_mc_daemon(instance)) {
+			MCDRV_DBG_ERROR("caller not MobiCore Daemon\n");
+			ret = -EFAULT;
+			break;
+		}
+
+		ret = copy_from_user(
+				  &(params.in),
+				  &(user_params->in),
+				  sizeof(params.in));
+
+		if (ret != 0) {
+			MCDRV_DBG_ERROR("copy_from_user\n");
+			break;
+		}
+
+
+		memset(&fc_info, 0, sizeof(fc_info));
+		fc_info.as_in.cmd	   = MC_FC_INFO;
+		fc_info.as_in.ext_info_id = params.in.ext_info_id;
+
+		MCDRV_DBG(
+			"fc_info in cmd=0x%08x, ext_info_id=0x%08x "
+			"rfu=(0x%08x, 0x%08x)\n",
+			fc_info.as_in.cmd,
+			fc_info.as_in.ext_info_id,
+			fc_info.as_in.rfu[0],
+			fc_info.as_in.rfu[1]);
+
+		mc_fastcall(&(fc_info.as_generic));
+
+		MCDRV_DBG(
+			"fc_info out resp=0x%08x, ret=0x%08x "
+			"state=0x%08x, ext_info=0x%08x\n",
+			fc_info.as_out.resp,
+			fc_info.as_out.ret,
+			fc_info.as_out.state,
+			fc_info.as_out.ext_info);
+
+		ret = convert_fc_ret(fc_info.as_out.ret);
+		if (ret != 0)
+			break;
+
+		memset(&(params.out), 0, sizeof(params.out));
+		params.out.state  = fc_info.as_out.state;
+		params.out.ext_info = fc_info.as_out.ext_info;
+
+		ret = copy_to_user(
+				  &(user_params->out),
+				  &(params.out),
+				  sizeof(params.out));
+
+		if (ret != 0) {
+			MCDRV_DBG_ERROR("copy_to_user\n");
+			break;
+		}
+	} while (FALSE);
+
+	MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
+
+	return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ *
+ * @param instance
+ * @param arg
+ *
+ * @return 0 if no error
+ *
+ */
+static int handle_ioctl_yield(
+	struct mc_instance	*instance
+)
+{
+	int			ret = 0;
+	union mc_fc_s_yield	fc_s_yield;
+
+	MCDRV_ASSERT(instance != NULL);
+
+	/* avoid putting debug output here, as we do this very often */
+	MCDRV_DBG_VERBOSE("enter\n");
+
+	do {
+		/* only the MobiCore Daemon is allowed to call this function */
+		if (!is_caller_mc_daemon(instance)) {
+			MCDRV_DBG_ERROR("caller not MobiCore Daemon\n");
+			ret = -EFAULT;
+			break;
+		}
+
+		memset(&fc_s_yield, 0, sizeof(fc_s_yield));
+		fc_s_yield.as_in.cmd = MC_SMC_N_YIELD;
+		mc_fastcall(&(fc_s_yield.as_generic));
+		ret = convert_fc_ret(fc_s_yield.as_out.ret);
+		if (ret != 0)
+			break;
+
+	} while (FALSE);
+
+	MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
+
+	return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ * handle ioctl and call common notify
+ *
+ * @param instance
+ * @param arg
+ *
+ * @return 0 if no error
+ *
+ */
+static int handle_ioctl_nsiq(
+	struct mc_instance	*instance,
+	unsigned long		arg
+)
+{
+	int		ret = 0;
+
+	MCDRV_ASSERT(instance != NULL);
+
+	/* avoid putting debug output here, as we do this very often */
+	MCDRV_DBG_VERBOSE("enter\n");
+	/* only the MobiCore Daemon is allowed to call this function */
+	if (!is_caller_mc_daemon(instance)) {
+		MCDRV_DBG_ERROR("caller not MobiCore Daemon\n");
+		return -EFAULT;
+	}
+
+	do {
+		union mc_fc_nsiq fc_nsiq;
+		memset(&fc_nsiq, 0, sizeof(fc_nsiq));
+		fc_nsiq.as_in.cmd = MC_SMC_N_SIQ;
+		mc_fastcall(&(fc_nsiq.as_generic));
+		ret = convert_fc_ret(fc_nsiq.as_out.ret);
+		if (ret != 0)
+			break;
+	} while (FALSE);
+
+	MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
+
+	return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ *
+ * @param instance
+ * @param arg
+ *
+ * @return 0 if no error
+ *
+ */
+static int handle_ioctl_dump_status(
+	struct mc_instance	*instance,
+	unsigned long		arg
+)
+{
+	int		ret = 0;
+	int		i = 0;
+	union mc_fc_info	fc_info;
+
+	MCDRV_ASSERT(instance != NULL);
+	MCDRV_DBG_VERBOSE("enter\n");
+
+	do {
+		/* anybody with root access can do this. */
+		if (!is_userland_caller_privileged()) {
+			MCDRV_DBG_ERROR("caller must have root privileges\n");
+			ret = -EFAULT;
+			break;
+		}
+
+		/* loop ext_info */
+		while (TRUE) {
+			memset(&fc_info, 0, sizeof(fc_info));
+			fc_info.as_in.cmd	   = MC_FC_INFO;
+			fc_info.as_in.ext_info_id = i;
+
+			MCDRV_DBG(
+				"fc_info in cmd=0x%08x, ext_info_id=0x%08x "
+				"rfu=(0x%08x, 0x%08x)\n",
+				fc_info.as_in.cmd,
+				fc_info.as_in.ext_info_id,
+				fc_info.as_in.rfu[0],
+				fc_info.as_in.rfu[1]);
+
+			mc_fastcall(&(fc_info.as_generic));
+
+			MCDRV_DBG(
+				"fc_info out resp=0x%08x, ret=0x%08x "
+				"state=0x%08x, ext_info=0x%08x\n",
+				fc_info.as_out.resp,
+				fc_info.as_out.ret,
+				fc_info.as_out.state,
+				fc_info.as_out.ext_info);
+
+			ret = convert_fc_ret(fc_info.as_out.ret);
+			if (ret != 0)
+				break;
+
+			MCDRV_DBG("state=%08X, idx=%02d: ext_info=%08X\n",
+				fc_info.as_out.state,
+				i,
+				fc_info.as_out.ext_info);
+			i++;
+		};
+
+		if (ret != 0)
+			break;
+
+
+	} while (FALSE);
+
+	MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
+
+	return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ *
+ * @param instance
+ * @param arg
+ *
+ * @return 0 if no error
+ *
+ */
+static int handle_ioctl_init(
+	struct mc_instance	*instance,
+	union mc_ioctl_init_params	*user_params
+)
+{
+	int			ret = 0;
+	union mc_ioctl_init_params	params;
+	union mc_fc_init		fc_init;
+
+	MCDRV_ASSERT(instance != NULL);
+	MCDRV_DBG_VERBOSE("enter\n");
+
+	do {
+		/* only the MobiCore Daemon is allowed to call this function */
+		if (!is_caller_mc_daemon(instance)) {
+			MCDRV_DBG_ERROR("caller not MobiCore Daemon\n");
+			ret = -EFAULT;
+			break;
+		}
+
+		ret = copy_from_user(
+				  &(params.in),
+				  &(user_params->in),
+				  sizeof(params.in));
+		if (ret != 0) {
+			MCDRV_DBG_ERROR("copy_from_user failed\n");
+			break;
+		}
+
+		memset(&fc_init, 0, sizeof(fc_init));
+
+		fc_init.as_in.cmd	= MC_FC_INIT;
+		/* base address of mci buffer 4KB aligned */
+		fc_init.as_in.base   = (uint32_t)params.in.base;
+		/* notification buffer start/length [16:16] [start, length] */
+		fc_init.as_in.nq_info  = (params.in.nq_offset << 16)
+					  | (params.in.nq_length & 0xFFFF);
+		/* mcp buffer start/length [16:16] [start, length] */
+		fc_init.as_in.mcp_info = (params.in.mcp_offset << 16)
+					  | (params.in.mcp_length & 0xFFFF);
+
+		/* Set KMOD notification queue to start of MCI
+			mciInfo was already set up in mmap */
+		if (!mci_base) {
+			MCDRV_DBG_ERROR("No MCI set yet.\n");
+			return -EFAULT;
+		}
+		MCDRV_DBG("in cmd=0x%08x, base=0x%08x, "
+			  "nq_info=0x%08x, mcp_info=0x%08x\n",
+			  fc_init.as_in.cmd,
+			  fc_init.as_in.base,
+			  fc_init.as_in.nq_info,
+			  fc_init.as_in.mcp_info);
+
+		mc_fastcall(&(fc_init.as_generic));
+
+		MCDRV_DBG("out cmd=0x%08x, ret=0x%08x rfu=(0x%08x, 0x%08x)\n",
+			  fc_init.as_out.resp,
+			  fc_init.as_out.ret,
+			  fc_init.as_out.rfu[0],
+			  fc_init.as_out.rfu[1]);
+
+		ret = convert_fc_ret(fc_init.as_out.ret);
+		if (ret != 0)
+			break;
+
+		/* no ioctl response parameters */
+
+	} while (FALSE);
+
+	MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
+
+	return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ *
+ * @param instance
+ * @param arg
+ *
+ * @return 0 if no error
+ *
+ */
+static int handle_ioctl_fc_execute(
+	struct mc_instance		*instance,
+	union mc_ioctl_fc_execute_params	*user_params
+)
+{
+	int				ret = 0;
+	union mc_ioctl_fc_execute_params	params;
+	union fc_generic			fc_params;
+
+	MCDRV_ASSERT(instance != NULL);
+	MCDRV_DBG_VERBOSE("enter\n");
+
+	do {
+		/* only the MobiCore Daemon is allowed to call this function */
+		if (!is_caller_mc_daemon(instance)) {
+			MCDRV_DBG_ERROR("caller not MobiCore Daemon\n");
+			ret = -EFAULT;
+			break;
+		}
+
+		ret = copy_from_user(
+				  &(params.in),
+				  &(user_params->in),
+				  sizeof(params.in));
+		if (ret != 0) {
+			MCDRV_DBG_ERROR("copy_from_user failed\n");
+			break;
+		}
+
+		fc_params.as_in.cmd = -4;/*FC_EXECUTE */
+		fc_params.as_in.param[0] = params.in.phys_start_addr;
+		fc_params.as_in.param[1] = params.in.length;
+		fc_params.as_in.param[2] = 0;
+
+		MCDRV_DBG("in cmd=0x%08x, startAddr=0x%08x, length=0x%08x\n",
+			  fc_params.as_in.cmd,
+			  fc_params.as_in.param[0],
+			  fc_params.as_in.param[1]);
+
+		mc_fastcall(&fc_params);
+
+		MCDRV_DBG("out cmd=0x%08x, ret=0x%08x rfu=(0x%08x, 0x%08x)\n",
+			  fc_params.as_out.resp,
+			  fc_params.as_out.ret,
+			  fc_params.as_out.param[0],
+			  fc_params.as_out.param[1]);
+
+		ret = convert_fc_ret(fc_params.as_out.ret);
+		if (ret != 0)
+			break;
+
+		/* no ioctl response parameters */
+
+	} while (FALSE);
+
+	MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
+
+	return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+#define MC_MAKE_VERSION(major, minor) \
+		(((major & 0x0000ffff) << 16) | (minor & 0x0000ffff))
+/**
+ *
+ * @param instance
+ * @param arg
+ *
+ * @return 0 if no error
+ *
+ */
+static int handle_ioctl_get_version(
+	struct mc_instance			*instance,
+	struct mc_ioctl_get_version_params	*user_params
+)
+{
+	int ret = 0;
+	struct mc_ioctl_get_version_params params = {
+		{
+			MC_MAKE_VERSION(MCDRVMODULEAPI_VERSION_MAJOR,
+					MCDRVMODULEAPI_VERSION_MINOR)
+		}
+	};
+
+	MCDRV_ASSERT(instance != NULL);
+	MCDRV_DBG_VERBOSE("enter\n");
+
+	do {
+		MCDRV_DBG("mcDrvModuleApi version is %i.%i\n",
+				MCDRVMODULEAPI_VERSION_MAJOR,
+				MCDRVMODULEAPI_VERSION_MINOR);
+
+		/* no ioctl response parameters */
+		ret = copy_to_user(
+					&(user_params->out),
+					&(params.out),
+					sizeof(params.out));
+		if (ret != 0)
+			MCDRV_DBG_ERROR("copy_to_user() failed\n");
+
+	} while (FALSE);
+
+	MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
+
+	return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ * This function will be called from user space as ioctl(...).
+ * @param file	pointer to file
+ * @param cmd	command
+ * @param arg	arguments
+ *
+ * @return int 0 for OK and an errno in case of error
+ */
+static long mc_kernel_module_ioctl(
+	struct file	*file,
+	unsigned int	cmd,
+	unsigned long	arg
+)
+{
+	int ret;
+	struct mc_instance *instance = get_instance(file);
+
+	MCDRV_ASSERT(instance != NULL);
+
+	switch (cmd) {
+	/*--------------------------------------------------------------------*/
+	case MC_DRV_KMOD_IOCTL_DUMP_STATUS:
+		ret = handle_ioctl_dump_status(
+				instance,
+				arg);
+		break;
+
+	/*--------------------------------------------------------------------*/
+	case MC_DRV_KMOD_IOCTL_FC_INIT:
+		ret = handle_ioctl_init(
+				instance,
+				(union mc_ioctl_init_params *)arg);
+		break;
+	/*--------------------------------------------------------------------*/
+	case MC_DRV_KMOD_IOCTL_FC_INFO:
+		ret = handle_ioctl_info(
+				instance,
+				(union mc_ioctl_info_params *)arg);
+		break;
+
+	/*--------------------------------------------------------------------*/
+	case MC_DRV_KMOD_IOCTL_FC_YIELD:
+		ret = handle_ioctl_yield(
+				instance);
+		break;
+
+	/*--------------------------------------------------------------------*/
+	case MC_DRV_KMOD_IOCTL_FC_NSIQ:
+		ret = handle_ioctl_nsiq(
+				instance,
+				arg);
+		break;
+
+	/*--------------------------------------------------------------------*/
+	case MC_DRV_KMOD_IOCTL_DAEMON_LOCK_WSM_L2:
+		ret = handle_ioctl_daemon_lock_wsm_l2(
+			instance,
+			(struct mc_ioctl_daemon_lock_wsm_l2_params *)arg);
+		break;
+
+	/*--------------------------------------------------------------------*/
+	case MC_DRV_KMOD_IOCTL_DAEMON_UNLOCK_WSM_L2:
+		ret = handle_ioctl_daemon_unlock_wsm_l2(
+			instance,
+			(struct mc_ioctl_daemon_unlock_wsm_l2_params *)arg);
+		break;
+
+	/*--------------------------------------------------------------------*/
+	case MC_DRV_KMOD_IOCTL_FREE:
+		/* called by ClientLib */
+		ret = handle_ioctl_free(
+				instance,
+				(union mc_ioctl_free_params *)arg);
+		break;
+
+	/*--------------------------------------------------------------------*/
+	case MC_DRV_KMOD_IOCTL_APP_REGISTER_WSM_L2:
+		/* called by ClientLib */
+		ret = handle_ioctl_app_register_wsm_l2(
+				instance,
+				(union mc_ioctl_app_reg_wsm_l2_params *)arg);
+		break;
+
+	/*--------------------------------------------------------------------*/
+	case MC_DRV_KMOD_IOCTL_APP_UNREGISTER_WSM_L2:
+		/* called by ClientLib */
+		ret = handle_ioctl_app_unregister_wsm_l2(
+				instance,
+				(struct mc_ioctl_app_unreg_wsm_l2_params *)arg);
+		break;
+
+	/*--------------------------------------------------------------------*/
+	case MC_DRV_KMOD_IOCTL_FC_EXECUTE:
+		ret = handle_ioctl_fc_execute(
+				instance,
+				(union mc_ioctl_fc_execute_params *)arg);
+		break;
+
+	/*--------------------------------------------------------------------*/
+	case MC_DRV_KMOD_IOCTL_GET_VERSION:
+		ret = handle_ioctl_get_version(
+				instance,
+				(struct mc_ioctl_get_version_params *)arg);
+		break;
+
+	/*--------------------------------------------------------------------*/
+	default:
+		MCDRV_DBG_ERROR("unsupported cmd=%d\n", cmd);
+		ret = -EFAULT;
+		break;
+
+	} /* end switch(cmd) */
+
+#ifdef MC_MEM_TRACES
+	mobicore_log_read();
+#endif
+
+	return (int)ret;
+}
+
+
+/*----------------------------------------------------------------------------*/
+/**
+ * This function will be called from user space as read(...).
+ * The read function is blocking until a interrupt occurs. In that case the
+ * event counter is copied into user space and the function is finished.
+ * @param *file
+ * @param *buffer  buffer where to copy to(userspace)
+ * @param buffer_len	 number of requested data
+ * @param *pos	 not used
+ * @return ssize_t  ok case: number of copied data
+ *				error case: return errno
+ */
+static ssize_t mc_kernel_module_read(
+	struct file	*file,
+	char		*buffer,
+	size_t		buffer_len,
+	loff_t		*pos
+)
+{
+	int ret = 0, ssiq_counter;
+	size_t retLen = 0;
+	struct mc_instance *instance = get_instance(file);
+
+	MCDRV_ASSERT(instance != NULL);
+
+	/* avoid debug output on non-error, because this is call quite often */
+	MCDRV_DBG_VERBOSE("enter\n");
+
+	do {
+		/* only the MobiCore Daemon is allowed to call this function */
+		if (!is_caller_mc_daemon(instance)) {
+			MCDRV_DBG_ERROR("caller not MobiCore Daemon\n");
+			ret = -EFAULT;
+			break;
+		}
+
+		if (buffer_len < sizeof(unsigned int)) {
+			MCDRV_DBG_ERROR("invalid length\n");
+			ret = (ssize_t)(-EINVAL);
+			break;
+		}
+
+		for (;;) {
+			if (down_interruptible(
+					&mc_drv_kmod_ctx.daemon_ctx.sem)) {
+				MCDRV_DBG_VERBOSE("read interrupted\n");
+				ret = (ssize_t)-ERESTARTSYS;
+				break;
+			}
+
+			ssiq_counter = atomic_read(
+					&(mc_drv_kmod_ctx.ssiq_ctx.counter));
+			MCDRV_DBG_VERBOSE("ssiq_counter=%i, ctx.counter=%i\n",
+				ssiq_counter,
+				mc_drv_kmod_ctx.daemon_ctx.ssiq_counter);
+
+			if (ssiq_counter !=
+				mc_drv_kmod_ctx.daemon_ctx.ssiq_counter) {
+				/* read data and exit loop without
+					error */
+				mc_drv_kmod_ctx.daemon_ctx.ssiq_counter =
+					ssiq_counter;
+				ret = 0;
+				break;
+			}
+
+			/* end loop if non-blocking */
+			if ((file->f_flags & O_NONBLOCK) != 0) {
+				MCDRV_DBG_ERROR("non-blocking read\n");
+				ret = (ssize_t)(-EAGAIN);
+				break;
+			}
+
+			if (signal_pending(current) != 0) {
+				MCDRV_DBG_VERBOSE("received signal.\n");
+				ret = (ssize_t)(-ERESTARTSYS);
+				break;
+			}
+
+		}
+
+		/* we are here if an event occurred or we had an
+			error.*/
+		if (ret != 0)
+			break;
+
+		/* read data and exit loop */
+		ret = copy_to_user(
+				  buffer,
+				  &(mc_drv_kmod_ctx.daemon_ctx.ssiq_counter),
+				  sizeof(unsigned int));
+
+
+		if (ret != 0) {
+			MCDRV_DBG_ERROR("copy_to_user failed\n");
+			ret = (ssize_t)(-EFAULT);
+			break;
+		}
+
+		retLen = sizeof(s32);
+
+	} while (FALSE);
+
+	/* avoid debug on non-error. */
+	if (ret == 0)
+		ret = (size_t)retLen;
+	else
+		MCDRV_DBG("exit with %d/0x%08X\n", ret, ret);
+
+	return (ssize_t)ret;
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Allocate WSM for given instance
+ *
+ * @param instance		instance
+ * @param requested_size		size of the WSM
+ * @param handle		pointer where the handle will be saved
+ * @param virt_kernel_addr	pointer for the kernel virtual address
+ * @param phys_addr		pointer for the physical address
+ *
+ * @return error code or 0 for success
+ */
+int mobicore_allocate_wsm(
+	struct mc_instance	*instance,
+	unsigned long		requested_size,
+	uint32_t		*handle,
+	void			**virt_kernel_addr,
+	void			**phys_addr
+)
+{
+	unsigned int	i;
+	unsigned int	order;
+	unsigned long	allocated_size;
+	int		ret = 0;
+	struct mc_contg_buffer	*contg_buffer = 0;
+	void		*virt_kernel_addr_stack;
+	void		*phys_addr_stack;
+
+	MCDRV_ASSERT(instance != NULL);
+	MCDRV_DBG("%s (size=%ld)\n", __func__, requested_size);
+
+	order = size_to_order(requested_size);
+	if (order == INVALID_ORDER) {
+		MCDRV_DBG_ERROR(
+			"size to order converting failed for size %ld\n",
+			requested_size);
+		return INVALID_ORDER;
+	}
+
+	allocated_size = (1<<order)*PAGE_SIZE;
+
+	MCDRV_DBG("size %ld -> order %d --> %ld (2^n pages)\n",
+		  requested_size, order, allocated_size);
+
+	do {
+		/* Usual Wsm request, allocate contigous buffer. */
+		/* search for a free entry in the wsm buffer list
+		 * REV axh: serialize this over multiple instances. */
+		for (i = 0; i < MC_DRV_KMOD_CONTG_BUFFER_MAX; i++) {
+			contg_buffer = &(instance->contg_buffers[i]);
+			if (contg_buffer->handle == 0) {
+				contg_buffer->handle = get_mc_kmod_unique_id();
+				break;
+			}
+		}
+		if (i == MC_DRV_KMOD_CONTG_BUFFER_MAX) {
+			MCDRV_DBG_ERROR("no free contigous buffer\n");
+			ret = -EFAULT;
+			break;
+		}
+
+		/* Common code for all allocation paths */
+		virt_kernel_addr_stack = (void *)__get_free_pages(
+							GFP_USER | __GFP_COMP,
+							order);
+		if (virt_kernel_addr_stack == NULL) {
+			MCDRV_DBG_ERROR("get_free_pages failed\n");
+			ret = -ENOMEM;
+			break;
+		}
+
+		/* Get physical address to instance data */
+		phys_addr_stack = (void *)virt_to_phys(virt_kernel_addr_stack);
+		/* TODO: check for INVALID_ADDRESS? */
+
+		MCDRV_DBG(
+			"allocated phys=0x%p - 0x%p, "
+			"size=%ld, kernel_virt=0x%p, handle=%d\n",
+			phys_addr_stack,
+			(void *)((unsigned int)phys_addr_stack+allocated_size),
+			allocated_size,
+			virt_kernel_addr_stack,
+			contg_buffer->handle);
+
+		/* Usual Wsm request, allocate contg_buffer.
+		 *		Also, we never free a persistent Tci */
+		contg_buffer->phys_addr	 = phys_addr_stack;
+		contg_buffer->virt_kernel_addr = virt_kernel_addr_stack;
+		contg_buffer->virt_user_addr   = virt_kernel_addr_stack;
+		contg_buffer->num_pages	 = (1U << order);
+		*handle = contg_buffer->handle;
+		*virt_kernel_addr = virt_kernel_addr_stack;
+		*phys_addr = phys_addr_stack;
+
+	} while (FALSE);
+
+	MCDRV_DBG_VERBOSE("%s: exit with 0x%08X\n", __func__, ret);
+
+	return ret;
+}
+EXPORT_SYMBOL(mobicore_allocate_wsm);
+
+
+/*----------------------------------------------------------------------------*/
+/**
+ * This function will be called from user space as address = mmap(...).
+ *
+ * @param file
+ * @param vmarea
+ * vmarea.pg_offset != 0 is mapping of MCI is requested
+ *
+ * @return 0 if OK or -ENOMEM in case of error.
+ */
+static int mc_kernel_module_mmap(
+	struct file		*file,
+	struct vm_area_struct	*vmarea
+)
+{
+	unsigned int		i;
+	unsigned int		order;
+	void			*virt_kernel_addr_stack = 0;
+	void			*phys_addr = 0;
+	unsigned long		requested_size =
+					vmarea->vm_end - vmarea->vm_start;
+	unsigned long		allocated_size;
+	int			ret = 0;
+	struct mc_contg_buffer	*contg_buffer = 0;
+	unsigned int		handle = 0;
+	struct mc_instance	*instance = get_instance(file);
+	unsigned int		request = vmarea->vm_pgoff * 4096;
+#if defined(DEBUG)
+	bool release = false;
+#else
+	bool release = true;
+#endif
+
+	MCDRV_ASSERT(instance != NULL);
+	MCDRV_DBG("enter (vmaStart=0x%p, size=%ld, request=0x%x, mci=0x%x)\n",
+		  (void *)vmarea->vm_start,
+		  requested_size,
+		  request,
+		  mci_base);
+
+	order = size_to_order(requested_size);
+	if (order == INVALID_ORDER) {
+		MCDRV_DBG_ERROR(
+			"size to order converting failed for size %ld\n",
+			requested_size);
+		return -ENOMEM;
+	}
+
+	allocated_size = (1<<order)*PAGE_SIZE;
+
+	MCDRV_DBG("size %ld -> order %d --> %ld (2^n pages)\n",
+		  requested_size, order, allocated_size);
+
+	do {
+		/* Daemon tries to get an existing MCI */
+		if ((request == MC_DRV_KMOD_MMAP_MCI) && (mci_base != 0)) {
+			MCDRV_DBG("Request MCI, it is at (%x)\n", mci_base);
+
+			if (!is_caller_mc_daemon(instance)) {
+				ret = -EPERM;
+				break;
+			}
+			virt_kernel_addr_stack = (void *)mci_base;
+			phys_addr =
+				(void *)virt_to_phys(virt_kernel_addr_stack);
+		} else {
+			/* Usual Wsm request, allocate buffer. */
+			if (request == MC_DRV_KMOD_MMAP_WSM) {
+				/* search for a free entry in the buffer list
+				REV axh: serialize this over multiple instances.
+				*/
+				for (i = 0; i < MC_DRV_KMOD_CONTG_BUFFER_MAX;
+					i++) {
+					contg_buffer =
+						&(instance->contg_buffers[i]);
+					if (contg_buffer->handle == 0) {
+						contg_buffer->handle =
+							get_mc_kmod_unique_id();
+						break;
+					}
+				}
+				if (i == MC_DRV_KMOD_CONTG_BUFFER_MAX) {
+					MCDRV_DBG_ERROR(
+						"no free contigous buffer\n");
+					ret = -EFAULT;
+					break;
+				}
+			} else {
+				if (request <= MC_DRV_KMOD_MMAP_PERSISTENTWSM
+					|| release) {
+					/* Special Wsm request
+						--> only Daemon is allowed */
+					if (!is_caller_mc_daemon(instance)) {
+						ret = -EPERM;
+						break;
+					}
+				}
+			}
+			if (request <= MC_DRV_KMOD_MMAP_PERSISTENTWSM) {
+				/* Common code for all allocation paths
+					*  get physical address, */
+				virt_kernel_addr_stack =
+					(void *)__get_free_pages(
+							GFP_USER | __GFP_COMP,
+							order);
+				if (virt_kernel_addr_stack == NULL) {
+					MCDRV_DBG_ERROR(
+						"get_free_pages failed\n");
+					ret = -ENOMEM;
+					break;
+				}
+				if (request == MC_DRV_KMOD_MMAP_WSM)
+					handle = contg_buffer->handle;
+				/* Get physical address to instance data */
+				/* TODO: check for INVALID_ADDRESS? */
+				phys_addr = (void *)virt_to_phys(
+							virt_kernel_addr_stack);
+			} else {
+#if defined(DEBUG)
+				phys_addr = (void *)request;
+				virt_kernel_addr_stack = phys_to_virt(request);
+#endif
+			}
+		}
+		/* Common code for all mmap calls:
+		 * map page to user
+		 * store data in page */
+
+		MCDRV_DBG("allocated phys=0x%p - 0x%p, "
+			"size=%ld, kernel_virt=0x%p, handle=%d\n",
+			phys_addr,
+			(void *)((unsigned int)phys_addr+allocated_size),
+			allocated_size, virt_kernel_addr_stack, handle);
+
+		vmarea->vm_flags |= VM_RESERVED;
+		/* convert Kernel address to User Address. Kernel address begins
+			at PAGE_OFFSET, user Address range is below PAGE_OFFSET.
+			Remapping the area is always done, so multiple mappings
+			of one region are possible. Now remap kernel address
+			space into user space */
+		ret = (int)remap_pfn_range(
+				vmarea,
+				(vmarea->vm_start),
+				addr_to_pfn(phys_addr),
+				requested_size,
+				vmarea->vm_page_prot);
+		if (ret != 0) {
+			MCDRV_DBG_ERROR("remapPfnRange failed\n");
+
+			/* free allocated pages when mmap fails, however, do not
+				do it, when daemon tried to get an MCI that
+				existed */
+			if (!((request == MC_DRV_KMOD_MMAP_MCI) &&
+				  (mci_base != 0)))
+				free_continguous_pages(virt_kernel_addr_stack,
+							(1U << order));
+			break;
+		}
+
+		/* Usual Wsm request, allocate contg_buffer.
+			When requesting Mci, we do not associate the page with
+			the process.
+			Note: we also never free the Mci
+			Also, we never free a persistent Tci */
+		if (request == MC_DRV_KMOD_MMAP_WSM) {
+			contg_buffer->phys_addr = phys_addr;
+			contg_buffer->virt_kernel_addr = virt_kernel_addr_stack;
+			contg_buffer->virt_user_addr =
+						(void *)(vmarea->vm_start);
+			contg_buffer->num_pages = (1U << order);
+		}
+
+		/* set response in allocated buffer */
+		{
+			struct mc_mmap_resp *mmap_resp =
+				(struct mc_mmap_resp *)virt_kernel_addr_stack;
+			/* TODO: do this for daemon only, otherwise set NULL */
+			mmap_resp->phys_addr = (uint32_t)phys_addr;
+			mmap_resp->handle = handle;
+			if ((request == MC_DRV_KMOD_MMAP_MCI) &&
+				(mci_base != 0)) {
+				mmap_resp->is_reused = 1;
+			} else
+				mmap_resp->is_reused = 0;
+		}
+
+		/* store MCI pointer */
+		if ((request == MC_DRV_KMOD_MMAP_MCI) && (mci_base == 0)) {
+			mci_base = (uint32_t)virt_kernel_addr_stack;
+			MCDRV_DBG("MCI base set to 0x%x\n", mci_base);
+		}
+	} while (FALSE);
+
+	MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
+
+	return (int)ret;
+}
+
+#ifdef CONFIG_SMP
+/*----------------------------------------------------------------------------*/
+/**
+ * Force migration of current task to CPU0(where the monitor resides)
+ *
+ * @return Error code or 0 for success
+ */
+static int goto_cpu0(
+	void
+)
+{
+	int		ret = 0;
+	struct cpumask	mask =  CPU_MASK_CPU0;
+
+	MCDRV_DBG_VERBOSE("System has %d CPU's, we are on CPU #%d\n"
+		  "\tBinding this process to CPU #0.\n"
+		  "\tactive mask is %lx, setting it to mask=%lx\n",
+		  nr_cpu_ids,
+		  raw_smp_processor_id(),
+		  cpu_active_mask->bits[0],
+		  mask.bits[0]);
+	ret = set_cpus_allowed_ptr(current, &mask);
+	if (ret != 0)
+		MCDRV_DBG_ERROR("set_cpus_allowed_ptr=%d.\n", ret);
+	MCDRV_DBG_VERBOSE("And now we are on CPU #%d\n",
+				raw_smp_processor_id());
+
+	return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Restore CPU mask for current to ALL Cpus(reverse of goto_cpu0)
+ *
+ * @return Error code or 0 for success
+ */
+static int goto_all_cpu(
+	void
+)
+{
+	int		ret = 0;
+
+	struct cpumask	mask =  CPU_MASK_ALL;
+
+	MCDRV_DBG_VERBOSE("System has %d CPU's, we are on CPU #%d\n"
+		  "\tBinding this process to CPU #0.\n"
+		  "\tactive mask is %lx, setting it to mask=%lx\n",
+		  nr_cpu_ids,
+		  raw_smp_processor_id(),
+		  cpu_active_mask->bits[0],
+		  mask.bits[0]);
+	ret = set_cpus_allowed_ptr(current, &mask);
+	if (ret != 0)
+		MCDRV_DBG_ERROR("set_cpus_allowed_ptr=%d.\n", ret);
+	MCDRV_DBG_VERBOSE("And now we are on CPU #%d\n",
+				raw_smp_processor_id());
+
+	return ret;
+}
+
+#else
+static int goto_cpu0(void)
+{
+	return 0;
+}
+
+static int goto_all_cpu(void)
+{
+	return 0;
+}
+#endif
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Initialize a new mobicore API instance object
+ *
+ * @return Instance or NULL if no allocation was possible.
+ */
+struct mc_instance *mobicore_open(
+	void
+) {
+	struct mc_instance	*instance;
+	pid_t			pid_vnr;
+
+	instance = kzalloc(sizeof(*instance), GFP_KERNEL);
+	if (instance == NULL)
+		return NULL;
+
+	/* get a unique ID for this instance (PIDs are not unique) */
+	instance->handle = get_mc_kmod_unique_id();
+
+	/* get the PID of the calling process. We avoid using
+	 *	current->pid directly, as 2.6.24 introduced PID
+	 *	namespaces. See also http://lwn.net/Articles/259217 */
+	pid_vnr = task_pid_vnr(current);
+	instance->pid_vnr = pid_vnr;
+
+	return instance;
+}
+EXPORT_SYMBOL(mobicore_open);
+
+/*----------------------------------------------------------------------------*/
+/**
+ * This function will be called from user space as fd = open(...).
+ * A set of internal instance data are created and initialized.
+ *
+ * @param inode
+ * @param file
+ * @return 0 if OK or -ENOMEM if no allocation was possible.
+ */
+static int mc_kernel_module_open(
+	struct inode	*inode,
+	struct file	*file
+)
+{
+	struct mc_instance	*instance;
+	int			ret = 0;
+
+	MCDRV_DBG_VERBOSE("enter\n");
+
+	do {
+		instance = mobicore_open();
+		if (instance == NULL)
+			return -ENOMEM;
+
+		/* check if Daemon. We simply assume that the first to open us
+			with root privileges must be the daemon. */
+		if ((is_userland_caller_privileged())
+			&& (mc_drv_kmod_ctx.daemon_inst == NULL)) {
+			MCDRV_DBG("accept this as MobiCore Daemon\n");
+
+			/* Set the caller's CPU mask to CPU0*/
+			ret = goto_cpu0();
+			if (ret != 0) {
+				mobicore_release(instance);
+				file->private_data = NULL;
+				MCDRV_DBG("changing core failed!\n");
+				break;
+			}
+
+			mc_drv_kmod_ctx.daemon_inst = instance;
+			sema_init(&mc_drv_kmod_ctx.daemon_ctx.sem,
+					DAEMON_SEM_VAL);
+			/* init ssiq event counter */
+			mc_drv_kmod_ctx.daemon_ctx.ssiq_counter =
+				atomic_read(
+					&(mc_drv_kmod_ctx.ssiq_ctx.counter));
+
+#ifdef MC_MEM_TRACES
+			/* The traces have to be setup on CPU-0 since we must
+			 * do a fastcall to MobiCore. */
+			if (!mci_base)
+				/* Do the work only if MCI base is not
+				 * initialized properly */
+				work_on_cpu(0, mobicore_log_setup, NULL);
+#endif
+		}
+
+		/* store instance data reference */
+		file->private_data = instance;
+
+		/* TODO axh: link all instances to allow clean up? */
+
+	} while (FALSE);
+
+	MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
+
+	return (int)ret;
+
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Release a mobicore instance object and all objects related to it
+ * @param instance instance
+ * @return 0 if Ok or -E ERROR
+ */
+int mobicore_release(
+	struct mc_instance	*instance
+)
+{
+	int ret = 0;
+	int i;
+	struct mc_used_l2_table	*used_l2table, *used_l2table_temp;
+
+	do {
+		/* try to get the semaphore */
+		ret = down_interruptible(&(mc_drv_kmod_ctx.wsm_l2_sem));
+		if (ret != 0) {
+			MCDRV_DBG_ERROR(
+				"down_interruptible() failed with %d\n", ret);
+			/* TODO: can be block here? */
+			ret = -ERESTARTSYS;
+		} else {
+			/* Check if some WSM is still in use. */
+			list_for_each_entry_safe(
+				used_l2table,
+				used_l2table_temp,
+				&(mc_drv_kmod_ctx.mc_used_l2_tables),
+				list
+			) {
+				if (used_l2table->owner == instance) {
+					MCDRV_DBG_WARN(
+						"trying to release WSM L2: "
+						"physBase=%p ,nr_of_pages=%d\n",
+						get_l2_table_phys(used_l2table),
+						used_l2table->nr_of_pages);
+
+					/* unlock app usage and free if MobiCore
+					does not use it */
+					delete_used_l2_table(used_l2table,
+							FREE_FROM_NWD);
+				}
+			} /* end while */
+
+			/* release semaphore */
+			up(&(mc_drv_kmod_ctx.wsm_l2_sem));
+		}
+
+
+		/* release all mapped data */
+		for (i = 0; i < MC_DRV_KMOD_CONTG_BUFFER_MAX; i++) {
+			struct mc_contg_buffer *contg_buffer =
+					&(instance->contg_buffers[i]);
+
+			if (contg_buffer->virt_user_addr != 0) {
+				free_continguous_pages(
+					contg_buffer->virt_kernel_addr,
+					contg_buffer->num_pages);
+			}
+		}
+
+		/* release instance context */
+		kfree(instance);
+	} while (FALSE);
+
+	return ret;
+}
+EXPORT_SYMBOL(mobicore_release);
+
+/*----------------------------------------------------------------------------*/
+/**
+ * This function will be called from user space as close(...).
+ * The instance data are freed and the associated memory pages are unreserved.
+ *
+ * @param inode
+ * @param file
+ *
+ * @return 0
+ */
+static int mc_kernel_module_release(
+	struct inode	*inode,
+	struct file	*file
+)
+{
+	int			ret = 0;
+	struct mc_instance	*instance = get_instance(file);
+
+	MCDRV_DBG_VERBOSE("enter\n");
+
+	do {
+		/* check if daemon closes us. */
+		if (is_caller_mc_daemon(instance)) {
+			/* TODO: cleanup?
+				* mc_drv_kmod_ctx.mc_used_l2_tables remains */
+			MCDRV_DBG_WARN("WARNING: MobiCore Daemon died\n");
+			mc_drv_kmod_ctx.daemon_inst = NULL;
+		}
+
+		ret = mobicore_release(instance);
+
+	} while (FALSE);
+
+	MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
+
+	return (int)ret;
+}
+
+
+/*----------------------------------------------------------------------------*/
+/**
+ * This function represents the interrupt function of the mcDrvModule.
+ * It signals by incrementing of an event counter and the start of the read
+ * waiting queue, the read function a interrupt has occurred.
+ *
+ * @param   intr
+ * @param   *context  pointer to registered device data
+ *
+ * @return  IRQ_HANDLED
+ */
+static irqreturn_t mc_kernel_module_intr_ssiq(
+	int	intr,
+	void	*context
+)
+{
+	irqreturn_t	ret = IRQ_NONE;
+
+	/* we know the context. */
+	MCDRV_ASSERT(&mc_drv_kmod_ctx == context);
+
+	do {
+		if (intr != MC_INTR_SSIQ) {
+			/* this should not happen, as we did no register for any
+				other interrupt. For debugging, we print a
+				message, but continue */
+			MCDRV_DBG_WARN(
+				"unknown interrupt %d, expecting only %d\n",
+				intr, MC_INTR_SSIQ);
+		}
+		MCDRV_DBG_VERBOSE("received interrupt %d\n",
+				  intr);
+
+		/* increment interrupt event counter */
+		atomic_inc(&(mc_drv_kmod_ctx.ssiq_ctx.counter));
+
+		/* signal the daemon */
+		up(&mc_drv_kmod_ctx.daemon_ctx.sem);
+
+
+		ret = IRQ_HANDLED;
+
+	} while (FALSE);
+
+	return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+/** function table structure of this device driver. */
+static const struct file_operations mc_kernel_module_file_operations = {
+	.owner		= THIS_MODULE, /**< driver owner */
+	.open		= mc_kernel_module_open, /**< driver open function */
+	.release	= mc_kernel_module_release, /**< driver release function*/
+	.unlocked_ioctl	= mc_kernel_module_ioctl, /**< driver ioctl function */
+	.mmap		= mc_kernel_module_mmap, /**< driver mmap function */
+	.read		= mc_kernel_module_read, /**< driver read function */
+};
+
+/*----------------------------------------------------------------------------*/
+/** registration structure as miscdevice. */
+static struct miscdevice mc_kernel_module_device = {
+	.name	= MC_DRV_MOD_DEVNODE, /**< device name */
+	.minor	= MISC_DYNAMIC_MINOR, /**< device minor number */
+	/** device interface function structure */
+	.fops	= &mc_kernel_module_file_operations,
+};
+
+
+/*----------------------------------------------------------------------------*/
+/**
+ * This function is called the kernel during startup or by a insmod command.
+ * This device is installed and registered as miscdevice, then interrupt and
+ * queue handling is set up
+ *
+ * @return 0 for no error or -EIO if registration fails
+ */
+static int __init mc_kernel_module_init(
+	void
+)
+{
+	int ret = 0;
+
+	MCDRV_DBG("enter (Build " __TIMESTAMP__ ")\n");
+	MCDRV_DBG("mcDrvModuleApi version is %i.%i\n",
+			MCDRVMODULEAPI_VERSION_MAJOR,
+			MCDRVMODULEAPI_VERSION_MINOR);
+#ifdef MOBICORE_COMPONENT_BUILD_TAG
+	MCDRV_DBG("%s\n", MOBICORE_COMPONENT_BUILD_TAG);
+#endif
+	do {
+		/* Hardware does not support ARM TrustZone
+			-> Cannot continue! */
+		if (!has_security_extensions()) {
+			MCDRV_DBG_ERROR(
+				"Hardware does't support ARM TrustZone!\n");
+			ret = -ENODEV;
+			break;
+		}
+
+		/* Running in secure mode -> Cannot load the driver! */
+		if (is_secure_mode()) {
+			MCDRV_DBG_ERROR("Running in secure MODE!\n");
+			ret = -ENODEV;
+			break;
+		}
+
+		sema_init(&mc_drv_kmod_ctx.daemon_ctx.sem, DAEMON_SEM_VAL);
+		/* set up S-SIQ interrupt handler */
+		ret = request_irq(
+				  MC_INTR_SSIQ,
+				  mc_kernel_module_intr_ssiq,
+				  IRQF_TRIGGER_RISING,
+				  MC_DRV_MOD_DEVNODE,
+				  &mc_drv_kmod_ctx);
+		if (ret != 0) {
+			MCDRV_DBG_ERROR("interrupt request failed\n");
+			break;
+		}
+
+		ret = misc_register(&mc_kernel_module_device);
+		if (ret != 0) {
+			MCDRV_DBG_ERROR("device register failed\n");
+			break;
+		}
+
+		/* initialize event counter for signaling of an IRQ to zero */
+		atomic_set(&(mc_drv_kmod_ctx.ssiq_ctx.counter), 0);
+
+		/* init list for WSM L2 chunks. */
+		INIT_LIST_HEAD(&(mc_drv_kmod_ctx.mc_l2_tables_sets));
+
+		/* L2 table descriptor list. */
+		INIT_LIST_HEAD(&(mc_drv_kmod_ctx.mc_used_l2_tables));
+
+		sema_init(&(mc_drv_kmod_ctx.wsm_l2_sem), 1);
+
+		/* initialize unique number counter which we can use for
+			handles. It is limited to 2^32, but this should be
+			enough to be roll-over safe for us. We start with 1
+			instead of 0. */
+		atomic_set(&(mc_drv_kmod_ctx.unique_counter), 1);
+
+		mci_base = 0;
+		MCDRV_DBG("initialized\n");
+
+		ret = 0;
+
+	} while (FALSE);
+
+	MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
+
+	return (int)ret;
+}
+
+
+
+/*----------------------------------------------------------------------------*/
+/**
+ * This function removes this device driver from the Linux device manager .
+ */
+static void __exit mc_kernel_module_exit(
+	void
+)
+{
+	struct mc_used_l2_table	*used_l2table;
+
+	MCDRV_DBG_VERBOSE("enter\n");
+
+	mobicore_log_free();
+
+	/* Check if some WSM is still in use. */
+	list_for_each_entry(
+		used_l2table,
+		&(mc_drv_kmod_ctx.mc_used_l2_tables),
+		list
+	) {
+		MCDRV_DBG_WARN(
+			"WSM L2 still in use: physBase=%p ,nr_of_pages=%d\n",
+			get_l2_table_phys(used_l2table),
+			used_l2table->nr_of_pages);
+	} /* end while */
+
+	free_irq(MC_INTR_SSIQ, &mc_drv_kmod_ctx);
+
+	misc_deregister(&mc_kernel_module_device);
+	MCDRV_DBG_VERBOSE("exit");
+}
+
+
+/*----------------------------------------------------------------------------*/
+/* Linux Driver Module Macros */
+module_init(mc_kernel_module_init);
+module_exit(mc_kernel_module_exit);
+MODULE_AUTHOR("Giesecke & Devrient GmbH");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MobiCore driver");
+
+/** @} */
+
diff --git a/drivers/gud/mobicore_driver/mc_drv_module.h b/drivers/gud/mobicore_driver/mc_drv_module.h
new file mode 100644
index 0000000..8b402d6
--- /dev/null
+++ b/drivers/gud/mobicore_driver/mc_drv_module.h
@@ -0,0 +1,238 @@
+/**
+ * Header file of MobiCore Driver Kernel Module.
+ *
+ * @addtogroup MCD_MCDIMPL_KMOD_IMPL
+ * @{
+ * Internal structures of the McDrvModule
+ * @file
+ *
+ * Header file the MobiCore Driver Kernel Module,
+ * its internal structures and defines.
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _MC_DRV_KMOD_H_
+#define _MC_DRV_KMOD_H_
+
+#include "mc_drv_module_linux_api.h"
+#include "public/mc_drv_module_api.h"
+/** Platform specific settings */
+#include "platform.h"
+
+/** ARM Specific masks and modes */
+#define ARM_CPSR_MASK 0x1F
+#define ARM_MONITOR_MODE 0b10110
+#define ARM_SECURITY_EXTENSION_MASK 0x30
+
+/**
+ * Number of page table entries in one L2 table. This is ARM specific, an
+ *  L2 table covers 1 MiB by using 256 entry referring to 4KiB pages each.
+ */
+#define MC_ARM_L2_TABLE_ENTRIES		256
+
+/** Maximum number of contiguous buffer allocations for one driver instance. */
+#define MC_DRV_KMOD_CONTG_BUFFER_MAX	16
+
+/** Number of pages for L2 tables. There are 4 table in each page. */
+#define MC_DRV_KMOD_L2_TABLE_PER_PAGES	4
+
+/** ARM level 2 (L2) table with 256 entries. Size: 1k */
+struct l2table {
+	pte_t	table_entries[MC_ARM_L2_TABLE_ENTRIES];
+};
+
+#define INVALID_ADDRESS     ((void *)(-1))
+
+/** ARM L2 PTE bits */
+#define L2_FLAG_SMALL_XN    (1U <<  0)
+#define L2_FLAG_SMALL       (1U <<  1)
+#define L2_FLAG_B           (1U <<  2)
+#define L2_FLAG_C           (1U <<  3)
+#define L2_FLAG_AP0         (1U <<  4)
+#define L2_FLAG_AP1         (1U <<  5)
+#define L2_FLAG_SMALL_TEX0  (1U <<  6)
+#define L2_FLAG_SMALL_TEX1  (1U <<  7)
+#define L2_FLAG_SMALL_TEX2  (1U <<  8)
+#define L2_FLAG_APX         (1U <<  9)
+#define L2_FLAG_S           (1U << 10)
+#define L2_FLAG_NG          (1U << 11)
+
+/**
+ * Contiguous buffer allocated to TLCs.
+ * These buffers are uses as world shared memory (wsm) and shared with
+ * secure world.
+ * The virtual kernel address is added for a simpler search algorithm.
+ */
+struct mc_contg_buffer {
+	unsigned int	handle; /* unique handle */
+	void		*virt_user_addr; /**< virtual User start address */
+	void		*virt_kernel_addr; /**< virtual Kernel start address */
+	void		*phys_addr; /**< physical start address */
+	unsigned int	num_pages; /**< number of pages */
+};
+
+/** Instance data for MobiCore Daemon and TLCs. */
+struct mc_instance {
+	/** unique handle */
+	unsigned int	handle;
+	/** process that opened this instance */
+	pid_t		pid_vnr;
+	/** buffer list for mmap generated address space and
+		its virtual client address */
+	struct mc_contg_buffer	contg_buffers[MC_DRV_KMOD_CONTG_BUFFER_MAX];
+};
+
+/** Store for four L2 tables in one 4kb page*/
+struct mc_l2_table_store {
+	struct l2table table[MC_DRV_KMOD_L2_TABLE_PER_PAGES];
+};
+
+/** Usage and maintenance information about mc_l2_table_store */
+struct mc_l2_tables_set {
+	struct list_head		list;
+	unsigned int			usage_bitmap;	/**< usage bitmap */
+	struct mc_l2_table_store	*kernel_virt;	/**< kernel virtual address */
+	struct mc_l2_table_store	*phys;		/**< physical address */
+	struct page			*page;		/**< pointer to page struct */
+};
+
+/**
+ * L2 table allocated to the Daemon or a TLC describing a world shared buffer.
+ * When users map a malloc()ed area into SWd, a L2 table is allocated.
+ * In addition, the area of maximum 1MB virtual address space is mapped into
+ * the L2 table and a handle for this table is returned to the user.
+ */
+struct mc_used_l2_table {
+	struct list_head	list;
+
+	/** handle as communicated to user mode */
+	unsigned int		handle;
+	unsigned int		flags;
+
+	/** owner of this L2 table */
+	struct mc_instance	*owner;
+
+	/** set describing where our L2 table is stored */
+	struct mc_l2_tables_set	*set;
+
+	/** index into L2 table set */
+	unsigned int		idx;
+
+	/** size of buffer */
+	unsigned int		nr_of_pages;
+};
+
+#define MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_APP   (1U << 0)
+#define MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC    (1U << 1)
+
+
+/** MobiCore S-SIQ interrupt context data. */
+struct mc_ssiq_ctx {
+	/** S-SIQ interrupt counter */
+	atomic_t	counter;
+};
+
+/** MobiCore Daemon context data. */
+struct mc_daemon_ctx {
+	/** event semaphore */
+	struct semaphore	sem;
+	struct fasync_struct	*async_queue;
+	/** event counter */
+	unsigned int		ssiq_counter;
+};
+
+/** MobiCore Driver Kernel Module context data. */
+struct mc_drv_kmod_ctx {
+
+	/** ever incrementing counter */
+	atomic_t		unique_counter;
+
+	/** S-SIQ interrupt context */
+	struct mc_ssiq_ctx	ssiq_ctx;
+
+	/** MobiCore Daemon context */
+	struct mc_daemon_ctx	daemon_ctx;
+
+	/** pointer to instance of daemon */
+	struct mc_instance	*daemon_inst;
+
+	/** Backing store for L2 tables */
+	struct list_head	mc_l2_tables_sets;
+
+	/** Bookkeeping for used L2 tables */
+	struct list_head	mc_used_l2_tables;
+
+	/** semaphore to synchronize access to above lists */
+	struct semaphore	wsm_l2_sem;
+};
+
+/** MobiCore internal trace buffer structure. */
+struct mc_trace_buf {
+	uint32_t version; /**< version of trace buffer */
+	uint32_t length; /**< length of allocated buffer(includes header) */
+	uint32_t write_pos; /**< last write position */
+	char  buff[1]; /**< start of the log buffer */
+};
+
+/*** MobiCore internal trace log setup. */
+void mobicore_log_read(void);
+long mobicore_log_setup(void *);
+void mobicore_log_free(void);
+
+#define MCDRV_DBG_ERROR(txt, ...) \
+	printk(KERN_ERR "mcDrvKMod [%d] %s() ### ERROR: " txt, \
+		task_pid_vnr(current), \
+		__func__, \
+		##__VA_ARGS__)
+
+/* dummy function helper macro. */
+#define DUMMY_FUNCTION()    do {} while (0)
+
+#if defined(DEBUG)
+
+/* #define DEBUG_VERBOSE */
+#if defined(DEBUG_VERBOSE)
+#define MCDRV_DBG_VERBOSE          MCDRV_DBG
+#else
+#define MCDRV_DBG_VERBOSE(...)     DUMMY_FUNCTION()
+#endif
+
+#define MCDRV_DBG(txt, ...) \
+	printk(KERN_INFO "mcDrvKMod [%d on CPU%d] %s(): " txt, \
+		task_pid_vnr(current), \
+		raw_smp_processor_id(), \
+		__func__, \
+		##__VA_ARGS__)
+
+#define MCDRV_DBG_WARN(txt, ...) \
+	printk(KERN_WARNING "mcDrvKMod [%d] %s() WARNING: " txt, \
+		task_pid_vnr(current), \
+		__func__, \
+		##__VA_ARGS__)
+
+#define MCDRV_ASSERT(cond) \
+	do { \
+		if (unlikely(!(cond))) { \
+			panic("mcDrvKMod Assertion failed: %s:%d\n", \
+				__FILE__, __LINE__); \
+		} \
+	} while (0)
+
+#else
+
+#define MCDRV_DBG_VERBOSE(...)	DUMMY_FUNCTION()
+#define MCDRV_DBG(...)		DUMMY_FUNCTION()
+#define MCDRV_DBG_WARN(...)	DUMMY_FUNCTION()
+
+#define MCDRV_ASSERT(...)	DUMMY_FUNCTION()
+
+#endif /* [not] defined(DEBUG) */
+
+
+#endif /* _MC_DRV_KMOD_H_ */
+/** @} */
diff --git a/drivers/gud/mobicore_driver/mc_drv_module_android.h b/drivers/gud/mobicore_driver/mc_drv_module_android.h
new file mode 100644
index 0000000..319509f
--- /dev/null
+++ b/drivers/gud/mobicore_driver/mc_drv_module_android.h
@@ -0,0 +1,37 @@
+/**
+ * Header file of MobiCore Driver Kernel Module.
+ *
+ * @addtogroup MobiCore_Driver_Kernel_Module
+ * @{
+ * Android specific defines
+ * @file
+ *
+ * Android specific defines
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _MC_DRV_MODULE_ANDROID_H_
+#define _MC_DRV_MODULE_ANDROID_H_
+
+/* Defines needed to identify the Daemon in Android systems
+ * For the full list see:
+ * platform_system_core/include/private/android_filesystem_config.h in the
+ * Android source tree
+ */
+/* traditional unix root user */
+#define AID_ROOT	0
+/* system server */
+#define AID_SYSTEM	1000
+/* access to misc storage */
+#define AID_MISC	9998
+#define AID_NOBODY	9999
+/* first app user */
+#define AID_APP		10000
+
+#endif /* _MC_DRV_MODULE_ANDROID_H_ */
+/** @} */
diff --git a/drivers/gud/mobicore_driver/mc_drv_module_fastcalls.h b/drivers/gud/mobicore_driver/mc_drv_module_fastcalls.h
new file mode 100644
index 0000000..d058043
--- /dev/null
+++ b/drivers/gud/mobicore_driver/mc_drv_module_fastcalls.h
@@ -0,0 +1,227 @@
+/**
+ * Header file of MobiCore Driver Kernel Module.
+ *
+ * @addtogroup MobiCore_Driver_Kernel_Module
+ * @{
+ * Internal structures of the McDrvModule
+ * @file
+ *
+ * MobiCore Fast Call interface
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _MC_DRV_MODULE_FC_H_
+#define _MC_DRV_MODULE_FC_H_
+
+#include "mc_drv_module.h"
+
+/**
+ * MobiCore SMCs
+ */
+enum mc_smc_codes {
+	MC_SMC_N_YIELD  = 0x3, /**< Yield to switch from NWd to SWd. */
+	MC_SMC_N_SIQ    = 0x4  /**< SIQ to switch from NWd to SWd. */
+};
+
+/**
+ * MobiCore fast calls. See MCI documentation
+ */
+enum mc_fast_call_codes {
+	MC_FC_INIT      = -1,
+	MC_FC_INFO      = -2,
+	MC_FC_POWER     = -3,
+	MC_FC_DUMP      = -4,
+	MC_FC_NWD_TRACE = -31 /**< Mem trace setup fastcall */
+};
+
+/**
+ * return code for fast calls
+ */
+enum mc_fast_calls_result {
+	MC_FC_RET_OK                       = 0,
+	MC_FC_RET_ERR_INVALID              = 1,
+	MC_FC_RET_ERR_ALREADY_INITIALIZED  = 5
+};
+
+
+
+/*------------------------------------------------------------------------------
+	structure wrappers for specific fastcalls
+------------------------------------------------------------------------------*/
+
+/** generic fast call parameters */
+union fc_generic {
+	struct {
+		uint32_t cmd;
+		uint32_t param[3];
+	} as_in;
+	struct {
+		uint32_t resp;
+		uint32_t ret;
+		uint32_t param[2];
+	} as_out;
+};
+
+
+/** fast call init */
+union mc_fc_init {
+	union fc_generic as_generic;
+	struct {
+		uint32_t cmd;
+		uint32_t base;
+		uint32_t nq_info;
+		uint32_t mcp_info;
+	} as_in;
+	struct {
+		uint32_t resp;
+		uint32_t ret;
+		uint32_t rfu[2];
+	} as_out;
+};
+
+
+/** fast call info parameters */
+union mc_fc_info {
+	union fc_generic as_generic;
+	struct {
+		uint32_t cmd;
+		uint32_t ext_info_id;
+		uint32_t rfu[2];
+	} as_in;
+	struct {
+		uint32_t resp;
+		uint32_t ret;
+		uint32_t state;
+		uint32_t ext_info;
+	} as_out;
+};
+
+
+/** fast call S-Yield parameters */
+union mc_fc_s_yield {
+	union fc_generic as_generic;
+	struct {
+		uint32_t cmd;
+		uint32_t rfu[3];
+	} as_in;
+	struct {
+		uint32_t resp;
+		uint32_t ret;
+		uint32_t rfu[2];
+	} as_out;
+};
+
+
+/** fast call N-SIQ parameters */
+union mc_fc_nsiq {
+	union fc_generic as_generic;
+	struct {
+		uint32_t cmd;
+		uint32_t rfu[3];
+	} as_in;
+	struct {
+		uint32_t resp;
+		uint32_t ret;
+		uint32_t rfu[2];
+	} as_out;
+};
+
+
+/*----------------------------------------------------------------------------*/
+/**
+ * fast call to MobiCore
+ *
+ * @param fc_generic pointer to fast call data
+ */
+static inline void mc_fastcall(
+	union fc_generic *fc_generic
+)
+{
+	MCDRV_ASSERT(fc_generic != NULL);
+	/* We only expect to make smc calls on CPU0 otherwise something wrong
+	 * will happen */
+	MCDRV_ASSERT(raw_smp_processor_id() == 0);
+	mb();
+#ifdef MC_SMC_FASTCALL
+	{
+		int ret = 0;
+		MCDRV_DBG("Going into SCM()");
+		ret = smc_fastcall((void *)fc_generic, sizeof(*fc_generic));
+		MCDRV_DBG("Coming from SCM, scm_call=%i, resp=%d/0x%x\n",
+			ret,
+			fc_generic->as_out.resp, fc_generic->as_out.resp);
+	}
+#else
+	{
+		/* SVC expect values in r0-r3 */
+		register u32 reg0 __asm__("r0") = fc_generic->as_in.cmd;
+		register u32 reg1 __asm__("r1") = fc_generic->as_in.param[0];
+		register u32 reg2 __asm__("r2") = fc_generic->as_in.param[1];
+		register u32 reg3 __asm__("r3") = fc_generic->as_in.param[2];
+
+		/* one of the famous preprocessor hacks to stingitize things.*/
+#define __STR2(x)   #x
+#define __STR(x)    __STR2(x)
+
+		/* compiler does not support certain instructions
+		"SMC": secure monitor call.*/
+#define ASM_ARM_SMC         0xE1600070
+		/*   "BPKT": debugging breakpoint. We keep this, as is comes
+				quite handy for debugging. */
+#define ASM_ARM_BPKT        0xE1200070
+#define ASM_THUMB_BPKT      0xBE00
+
+
+		__asm__ volatile (
+			".word " __STR(ASM_ARM_SMC) "\n"
+			: "+r"(reg0), "+r"(reg1), "+r"(reg2), "+r"(reg3)
+		);
+
+		/* set response */
+		fc_generic->as_out.resp     = reg0;
+		fc_generic->as_out.ret      = reg1;
+		fc_generic->as_out.param[0] = reg2;
+		fc_generic->as_out.param[1] = reg3;
+	}
+#endif
+}
+
+
+/*----------------------------------------------------------------------------*/
+/**
+ * convert fast call return code to linux driver module error code
+ *
+ */
+static inline int convert_fc_ret(
+	uint32_t sret
+)
+{
+	int         ret = -EFAULT;
+
+	switch (sret) {
+
+	case MC_FC_RET_OK:
+		ret = 0;
+		break;
+
+	case MC_FC_RET_ERR_INVALID:
+		ret = -EINVAL;
+		break;
+
+	case MC_FC_RET_ERR_ALREADY_INITIALIZED:
+		ret = -EBUSY;
+		break;
+
+	default:
+		break;
+	} /* end switch( sret ) */
+	return ret;
+}
+
+#endif /* _MC_DRV_MODULE_FC_H_ */
+/** @} */
diff --git a/drivers/gud/mobicore_driver/mc_drv_module_linux_api.h b/drivers/gud/mobicore_driver/mc_drv_module_linux_api.h
new file mode 100644
index 0000000..b2a99f1
--- /dev/null
+++ b/drivers/gud/mobicore_driver/mc_drv_module_linux_api.h
@@ -0,0 +1,187 @@
+/**
+ * Header file of MobiCore Driver Kernel Module.
+ *
+ * @addtogroup MobiCore_Driver_Kernel_Module
+ * @{
+ * Wrapper for Linux API
+ * @file
+ *
+ * Some convenient wrappers for memory functions
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _MC_DRV_MODULE_LINUX_API_H_
+#define _MC_DRV_MODULE_LINUX_API_H_
+
+#include <linux/version.h>
+#include <linux/miscdevice.h>
+#include <linux/interrupt.h>
+#include <linux/highmem.h>
+#include <linux/kthread.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <asm/sizes.h>
+#include <asm/pgtable.h>
+#include <linux/semaphore.h>
+#include <linux/moduleparam.h>
+#include <linux/slab.h>
+
+
+/* make some nice types */
+#if !defined(TRUE)
+#define TRUE (1 == 1)
+#endif
+
+#if !defined(FALSE)
+#define FALSE (1 != 1)
+#endif
+
+
+/* Linux GCC modifiers */
+#if !defined(__init)
+#warning "missing definition: __init"
+/* define a dummy */
+#define __init
+#endif
+
+
+#if !defined(__exit)
+#warning "missing definition: __exit"
+/* define a dummy */
+#define __exit
+#endif
+
+
+#if !defined(__must_check)
+#warning "missing definition: __must_check"
+/* define a dummy */
+#define __must_check
+#endif
+
+
+#if !defined(__user)
+#warning "missing definition: __user"
+/* define a dummy */
+#define __user
+#endif
+
+#define INVALID_ORDER       ((unsigned int)(-1))
+
+/*----------------------------------------------------------------------------*/
+/* get start address of the 4 KiB page where the given addres is located in. */
+static inline void *get_page_start(
+	void *addr
+)
+{
+	return (void *)(((unsigned long)(addr)) & PAGE_MASK);
+}
+
+/*----------------------------------------------------------------------------*/
+/* get offset into the 4 KiB page where the given addres is located in. */
+static inline unsigned int get_offset_in_page(
+	void *addr
+)
+{
+	return (unsigned int)(((unsigned long)(addr)) & (~PAGE_MASK));
+}
+
+/*----------------------------------------------------------------------------*/
+/* get number of pages for a given buffer. */
+static inline unsigned int get_nr_of_pages_for_buffer(
+	void		*addr_start, /* may be null */
+	unsigned int	len
+)
+{
+	/* calculate used number of pages. Example:
+	offset+size    newSize+PAGE_SIZE-1    nr_of_pages
+	   0              4095                   0
+	   1              4096                   1
+	  4095            8190                   1
+	  4096            8191                   1
+	  4097            8192                   2 */
+
+	return (get_offset_in_page(addr_start) + len + PAGE_SIZE-1) / PAGE_SIZE;
+}
+
+
+/*----------------------------------------------------------------------------*/
+/**
+ * convert a given size to page order, which is equivalent to finding log_2(x).
+ * The maximum for order was 5 in Linux 2.0 corresponding to 32 pages.
+ * Later versions allow 9 corresponding to 512 pages, which is 2 MB on
+ * most platforms). Anyway, the bigger order is, the more likely it is
+ * that the allocation will fail.
+ * Size       0           1  4097  8193  12289  24577  28673   40961   61441
+ * Pages      -           1     2     3      4      7      8      15      16
+ * Order  INVALID_ORDER   0     1     1      2      2      3       3       4
+ *
+ * @param  size
+ * @return order
+ */
+static inline unsigned int size_to_order(
+	unsigned int size
+)
+{
+	unsigned int order = INVALID_ORDER;
+
+	if (size != 0) {
+		/* ARMv5 as a CLZ instruction which count the leading zeros of
+		the binary representation of a value. It return a value
+		between 0 and 32.
+		Value   0   1   2   3   4   5   6   7   8   9  10 ...
+		CLZ    32  31  30  30  29  29  29  29  28  28  28 ...
+
+		We have excluded Size==0 before, so this is safe. */
+		order = __builtin_clz(
+				get_nr_of_pages_for_buffer(NULL, size));
+
+		/* there is a size overflow in get_nr_of_pages_for_buffer when
+		 * the size is too large */
+		if (unlikely(order > 31))
+			return INVALID_ORDER;
+		order = 31 - order;
+
+		/* above algorithm rounds down: clz(5)=2 instead of 3 */
+		/* quick correction to fix it: */
+		if (((1<<order)*PAGE_SIZE) < size)
+			order++;
+	}
+	return order;
+}
+
+/* magic linux macro */
+#if !defined(list_for_each_entry)
+/* stop compiler */
+#error "missing macro: list_for_each_entry()"
+/* define a dummy */
+#define list_for_each_entry(a, b, c)    if (0)
+#endif
+
+/*----------------------------------------------------------------------------*/
+/* return the page frame number of an address */
+static inline unsigned int addr_to_pfn(
+	void *addr
+)
+{
+	/* there is no real API for this */
+	return ((unsigned int)(addr)) >> PAGE_SHIFT;
+}
+
+
+/*----------------------------------------------------------------------------*/
+/* return the address of a page frame number */
+static inline void *pfn_to_addr(
+	unsigned int pfn
+)
+{
+	/* there is no real API for this */
+	return (void *)(pfn << PAGE_SHIFT);
+}
+
+#endif /* _MC_DRV_MODULE_LINUX_API_H_ */
+/** @} */
diff --git a/drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h b/drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h
new file mode 100644
index 0000000..7034cb0
--- /dev/null
+++ b/drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h
@@ -0,0 +1,50 @@
+/**
+ * Header file of MobiCore Driver Kernel Module Platform
+ * specific structures
+ *
+ * @addtogroup MobiCore_Driver_Kernel_Module
+ * @{
+ * Internal structures of the McDrvModule
+ * @file
+ *
+ * Header file the MobiCore Driver Kernel Module,
+ * its internal structures and defines.
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _MC_DRV_PLATFORM_H_
+#define _MC_DRV_PLATFORM_H_
+
+/** MobiCore Interrupt for Qualcomm */
+#define MC_INTR_SSIQ						218
+
+/** Use SMC for fastcalls */
+#define MC_SMC_FASTCALL
+
+
+/*--------------- Implementation -------------- */
+#include <mach/scm.h>
+/* from following file */
+#define SCM_SVC_MOBICORE		250
+#define SCM_CMD_MOBICORE		1
+
+extern int scm_call(u32 svc_id, u32 cmd_id, const void *cmd_buf, size_t cmd_len,
+			void *resp_buf, size_t resp_len);
+
+static inline int smc_fastcall(void *fc_generic, size_t size)
+{
+	return scm_call(SCM_SVC_MOBICORE, SCM_CMD_MOBICORE,
+			   fc_generic, size,
+			   fc_generic, size);
+}
+
+/** Enable mobicore mem traces */
+#define MC_MEM_TRACES
+
+#endif /* _MC_DRV_PLATFORM_H_ */
+/** @} */
diff --git a/drivers/gud/mobicore_driver/public/mc_drv_module_api.h b/drivers/gud/mobicore_driver/public/mc_drv_module_api.h
new file mode 100644
index 0000000..59366f3
--- /dev/null
+++ b/drivers/gud/mobicore_driver/public/mc_drv_module_api.h
@@ -0,0 +1,311 @@
+/** @addtogroup MCD_MCDIMPL_KMOD_API Mobicore Driver Module API
+ * @ingroup  MCD_MCDIMPL_KMOD
+ * @{
+ * Interface to Mobicore Driver Kernel Module.
+ * @file
+ *
+ * <h2>Introduction</h2>
+ * The MobiCore Driver Kernel Module is a Linux device driver, which represents
+ * the command proxy on the lowest layer to the secure world (Swd). Additional
+ * services like memory allocation via mmap and generation of a L2 tables for
+ * given virtual memory are also supported. IRQ functionallity receives
+ * information from the SWd in the non secure world (NWd).
+ * As customary the driver is handled as linux device driver with "open",
+ * "close" and "ioctl" commands. Access to the driver is possible after the
+ * device "/dev/mobicore" has been opened.
+ * The MobiCore Driver Kernel Module must be installed via
+ * "insmod mcDrvModule.ko".
+ *
+ *
+ * <h2>Version history</h2>
+ * <table class="customtab">
+ * <tr><td width="100px"><b>Date</b></td><td width="80px"><b>Version</b></td>
+ * <td><b>Changes</b></td></tr>
+ * <tr><td>2010-05-25</td><td>0.1</td><td>Initial Release</td></tr>
+ * </table>
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2010-2012 -->
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *	notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *	notice, this list of conditions and the following disclaimer in the
+ *	documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *	products derived from this software without specific prior
+ *	written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _MC_DRV_MODULEAPI_H_
+#define _MC_DRV_MODULEAPI_H_
+
+#include "version.h"
+
+#define MC_DRV_MOD_DEVNODE		   "mobicore"
+#define MC_DRV_MOD_DEVNODE_FULLPATH  "/dev/" MC_DRV_MOD_DEVNODE
+
+/**
+ * Data exchange structure of the MC_DRV_MODULE_INIT ioctl command.
+ * INIT request data to SWD
+ */
+union mc_ioctl_init_params {
+	struct {
+		/** base address of mci buffer 4KB align */
+		uint32_t  base;
+		/** notification buffer start/length [16:16] [start, length] */
+		uint32_t  nq_offset;
+		/** length of notification queue */
+		uint32_t  nq_length;
+		/** mcp buffer start/length [16:16] [start, length] */
+		uint32_t  mcp_offset;
+		/** length of mcp buffer */
+		uint32_t  mcp_length;
+	} in;
+	struct {
+		/* nothing */
+	} out;
+};
+
+
+/**
+ * Data exchange structure of the MC_DRV_MODULE_INFO ioctl command.
+ * INFO request data to the SWD
+ */
+union mc_ioctl_info_params {
+	struct {
+		uint32_t  ext_info_id; /**< extended info ID */
+	} in;
+	struct {
+		uint32_t  state; /**< state */
+		uint32_t  ext_info; /**< extended info */
+	} out;
+};
+
+/**
+ * Mmap allocates and maps contiguous memory into a process.
+ * We use the third parameter, void *offset, to distinguish between some cases
+ * offset = MC_DRV_KMOD_MMAP_WSM	usual operation, pages are registered in
+					device structure and freed later.
+ * offset = MC_DRV_KMOD_MMAP_MCI	get Instance of MCI, allocates or mmaps
+					the MCI to daemon
+ * offset = MC_DRV_KMOD_MMAP_PERSISTENTWSM	special operation, without
+						registration of pages
+ *
+ * In mmap(), the offset specifies which of several device I/O pages is
+ *  requested. Linux only transfers the page number, i.e. the upper 20 bits to
+ *  kernel module. Therefore we define our special offsets as multiples of page
+ *  size.
+ */
+enum mc_mmap_memtype {
+	MC_DRV_KMOD_MMAP_WSM		= 0,
+	MC_DRV_KMOD_MMAP_MCI		= 4096,
+	MC_DRV_KMOD_MMAP_PERSISTENTWSM	= 8192
+};
+
+struct mc_mmap_resp {
+	uint32_t  handle; /**< WSN handle */
+	uint32_t  phys_addr; /**< physical address of WSM (or NULL) */
+	bool	  is_reused; /**< if WSM memory was reused, or new allocated */
+};
+
+/**
+ * Data exchange structure of the MC_DRV_KMOD_IOCTL_FREE ioctl command.
+ */
+union mc_ioctl_free_params {
+	struct {
+		uint32_t  handle; /**< driver handle */
+		uint32_t  pid; /**< process id */
+	} in;
+	struct {
+		/* nothing */
+	} out;
+};
+
+
+/**
+ * Data exchange structure of the MC_DRV_KMOD_IOCTL_APP_REGISTER_WSM_L2 command.
+ *
+ * Allocates a physical L2 table and maps the buffer into this page.
+ * Returns the physical address of the L2 table.
+ * The page alignment will be created and the appropriated pSize and pOffsetL2
+ * will be modified to the used values.
+ */
+union mc_ioctl_app_reg_wsm_l2_params {
+	struct {
+		uint32_t  buffer; /**< base address of the virtual address  */
+		uint32_t  len; /**< size of the virtual address space */
+		uint32_t  pid; /**< process id */
+	} in;
+	struct {
+		uint32_t  handle; /**< driver handle for locked memory */
+		uint32_t  phys_wsm_l2_table; /* physical address of the L2 table */
+	} out;
+};
+
+
+/**
+ * Data exchange structure of the MC_DRV_KMOD_IOCTL_APP_UNREGISTER_WSM_L2
+ * command.
+ */
+struct mc_ioctl_app_unreg_wsm_l2_params {
+	struct {
+		uint32_t  handle; /**< driver handle for locked memory */
+		uint32_t  pid; /**< process id */
+	} in;
+	struct {
+		/* nothing */
+	} out;
+};
+
+
+/**
+ * Data exchange structure of the MC_DRV_KMOD_IOCTL_DAEMON_LOCK_WSM_L2 command.
+ */
+struct mc_ioctl_daemon_lock_wsm_l2_params {
+	struct {
+		uint32_t  handle; /**< driver handle for locked memory */
+	} in;
+	struct {
+		uint32_t phys_wsm_l2_table;
+	} out;
+};
+
+
+/**
+ * Data exchange structure of the MC_DRV_KMOD_IOCTL_DAEMON_UNLOCK_WSM_L2
+ * command.
+ */
+struct mc_ioctl_daemon_unlock_wsm_l2_params {
+	struct {
+		uint32_t  handle; /**< driver handle for locked memory */
+	} in;
+	struct {
+		/* nothing */
+	} out;
+};
+
+/**
+ * Data exchange structure of the MC_DRV_MODULE_FC_EXECUTE ioctl command.
+ */
+union mc_ioctl_fc_execute_params {
+	struct {
+		/**< base address of mobicore binary */
+		uint32_t  phys_start_addr;
+		/**< length of DDR area */
+		uint32_t  length;
+	} in;
+	struct {
+		/* nothing */
+	} out;
+};
+
+/**
+ * Data exchange structure of the MC_DRV_MODULE_GET_VERSION ioctl command.
+ */
+struct mc_ioctl_get_version_params {
+	struct {
+		uint32_t	kernel_module_version;
+	} out;
+};
+
+/* @defgroup Mobicore_Driver_Kernel_Module_Interface IOCTL */
+
+
+
+
+/* TODO: use IOCTL macros like _IOWR. See Documentation/ioctl/ioctl-number.txt,
+	Documentation/ioctl/ioctl-decoding.txt */
+/**
+ * defines for the ioctl mobicore driver module function call from user space.
+ */
+enum mc_kmod_ioctl {
+
+	/*
+	 * get detailed MobiCore Status
+	 */
+	MC_DRV_KMOD_IOCTL_DUMP_STATUS  = 200,
+
+	/*
+	 * initialize MobiCore
+	 */
+	MC_DRV_KMOD_IOCTL_FC_INIT  = 201,
+
+	/*
+	 * get MobiCore status
+	 */
+	MC_DRV_KMOD_IOCTL_FC_INFO  = 202,
+
+	/**
+	 * ioctl parameter to send the YIELD command to the SWD.
+	 * Only possible in Privileged Mode.
+	 * ioctl(fd, MC_DRV_MODULE_YIELD)
+	 */
+	MC_DRV_KMOD_IOCTL_FC_YIELD =  203,
+	/**
+	 * ioctl parameter to send the NSIQ signal to the SWD.
+	 * Only possible in Privileged Mode
+	 * ioctl(fd, MC_DRV_MODULE_NSIQ)
+	 */
+	MC_DRV_KMOD_IOCTL_FC_NSIQ   =  204,
+	/**
+	 * ioctl parameter to tzbsp to start Mobicore binary from DDR.
+	 * Only possible in Privileged Mode
+	 * ioctl(fd, MC_DRV_KMOD_IOCTL_FC_EXECUTE)
+	 */
+	MC_DRV_KMOD_IOCTL_FC_EXECUTE =  205,
+
+	/**
+	 * Free's memory which is formerly allocated by the driver's mmap
+	 * command. The parameter must be this mmaped address.
+	 * The internal instance data regarding to this address are deleted as
+	 * well as each according memory page and its appropriated reserved bit
+	 * is cleared (ClearPageReserved).
+	 * Usage: ioctl(fd, MC_DRV_MODULE_FREE, &address) with address beeing of
+	 * type long address
+	 */
+	MC_DRV_KMOD_IOCTL_FREE = 218,
+
+	/**
+	 * Creates a L2 Table of the given base address and the size of the
+	 * data.
+	 * Parameter: mc_ioctl_app_reg_wsm_l2_params
+	 */
+	MC_DRV_KMOD_IOCTL_APP_REGISTER_WSM_L2 = 220,
+
+	/**
+	 * Frees the L2 table created by a MC_DRV_KMOD_IOCTL_APP_REGISTER_WSM_L2
+	 * ioctl.
+	 * Parameter: mc_ioctl_app_unreg_wsm_l2_params
+	 */
+	MC_DRV_KMOD_IOCTL_APP_UNREGISTER_WSM_L2 = 221,
+
+
+	/* TODO: comment this. */
+	MC_DRV_KMOD_IOCTL_DAEMON_LOCK_WSM_L2 = 222,
+	MC_DRV_KMOD_IOCTL_DAEMON_UNLOCK_WSM_L2 = 223,
+
+	/**
+	 * Return kernel driver version.
+	 * Parameter: mc_ioctl_get_version_params
+	 */
+	MC_DRV_KMOD_IOCTL_GET_VERSION = 224,
+};
+
+
+#endif /* _MC_DRV_MODULEAPI_H_ */
+/** @} */
diff --git a/drivers/gud/mobicore_driver/public/mc_kernel_api.h b/drivers/gud/mobicore_driver/public/mc_kernel_api.h
new file mode 100644
index 0000000..fdfc618
--- /dev/null
+++ b/drivers/gud/mobicore_driver/public/mc_kernel_api.h
@@ -0,0 +1,100 @@
+/** @addtogroup MCD_MCDIMPL_KMOD_KAPI Mobicore Driver Module API inside Kernel.
+ * @ingroup  MCD_MCDIMPL_KMOD
+ * @{
+ * Interface to Mobicore Driver Kernel Module inside Kernel.
+ * @file
+ *
+ * Interface to be used by module MobiCoreKernelAPI.
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2010-2012 -->
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _MOBICORE_KERNELMODULE_API_H_
+#define _MOBICORE_KERNELMODULE_API_H_
+
+struct mc_instance;
+
+/**
+ * Initialize a new mobicore API instance object
+ *
+ * @return Instance or NULL if no allocation was possible.
+ */
+struct mc_instance *mobicore_open(
+	void
+);
+
+/**
+ * Release a mobicore instance object and all objects related to it
+ * @param instance instance
+ * @return 0 if Ok or -E ERROR
+ */
+int mobicore_release(
+	struct mc_instance	*instance
+);
+
+/**
+ * Free a WSM buffer allocated with mobicore_allocate_wsm
+ * @param instance
+ * @param handle		handle of the buffer
+ *
+ * @return 0 if no error
+ *
+ */
+int mobicore_allocate_wsm(
+	struct mc_instance	*instance,
+	unsigned long		requested_size,
+	uint32_t		*handle,
+	void			**kernel_virt_addr,
+	void			**phys_addr
+);
+
+/**
+ * Free a WSM buffer allocated with mobicore_allocate_wsm
+ * @param instance
+ * @param handle		handle of the buffer
+ *
+ * @return 0 if no error
+ *
+ */
+int mobicore_free(
+	struct mc_instance	*instance,
+	uint32_t		handle
+);
+
+/**
+ * Map a virtual memory buffer structure to Mobicore
+ * @param instance
+ * @param addr		address of the buffer(NB it must be kernel virtual!)
+ * @param len		buffer length
+ * @param handle	pointer to handle
+ * @param phys_wsm_l2_table	pointer to physical L2 table(?)
+ *
+ * @return 0 if no error
+ *
+ */
+int mobicore_map_vmem(
+	struct mc_instance	*instance,
+	void			*addr,
+	uint32_t		len,
+	uint32_t		*handle,
+	void			**phys_wsm_l2_table
+);
+
+/**
+ * Unmap a virtual memory buffer from mobicore
+ * @param instance
+ * @param handle
+ *
+ * @return 0 if no error
+ *
+ */
+int mobicore_unmap_vmem(
+	struct mc_instance	*instance,
+	uint32_t		handle
+);
+#endif /* _MOBICORE_KERNELMODULE_API_H_ */
+/** @} */
diff --git a/drivers/gud/mobicore_driver/public/version.h b/drivers/gud/mobicore_driver/public/version.h
new file mode 100644
index 0000000..9b2dbca
--- /dev/null
+++ b/drivers/gud/mobicore_driver/public/version.h
@@ -0,0 +1,36 @@
+/** @addtogroup MCD_MCDIMPL_KMOD
+ * @{
+ * <!-- Copyright Giesecke & Devrient GmbH 2010-2012 -->
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _MC_DRV_VERSION_H_
+#define _MC_DRV_VERSION_H_
+
+#define MCDRVMODULEAPI_VERSION_MAJOR 0
+#define MCDRVMODULEAPI_VERSION_MINOR 1
+
+#endif /* _MC_DRV_VERSION_H_ */
diff --git a/drivers/gud/mobicore_kernelapi/clientlib.c b/drivers/gud/mobicore_kernelapi/clientlib.c
new file mode 100644
index 0000000..13826f2
--- /dev/null
+++ b/drivers/gud/mobicore_kernelapi/clientlib.c
@@ -0,0 +1,1093 @@
+/**
+ * MobiCore KernelApi module
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/netlink.h>
+#include <net/sock.h>
+#include <net/net_namespace.h>
+#include <linux/list.h>
+
+#include "public/mobicore_driver_api.h"
+#include "public/mobicore_driver_cmd.h"
+#include "device.h"
+#include "session.h"
+
+/* device list */
+LIST_HEAD(devices);
+
+/*----------------------------------------------------------------------------*/
+static struct mcore_device_t *resolve_device_id(
+	uint32_t device_id
+) {
+	struct mcore_device_t *tmp;
+	struct list_head *pos;
+
+	/* Get mcore_device_t for device_id */
+	list_for_each(pos, &devices) {
+		tmp = list_entry(pos, struct mcore_device_t, list);
+		if (tmp->device_id == device_id)
+			return tmp;
+	}
+	return NULL;
+}
+
+
+/*----------------------------------------------------------------------------*/
+static void add_device(
+	struct mcore_device_t *device
+) {
+	list_add_tail(&(device->list), &devices);
+}
+
+
+/*----------------------------------------------------------------------------*/
+static bool remove_device(
+	uint32_t device_id
+) {
+	struct mcore_device_t *tmp;
+	struct list_head *pos, *q;
+
+	list_for_each_safe(pos, q, &devices) {
+		tmp = list_entry(pos, struct mcore_device_t, list);
+		if (tmp->device_id == device_id) {
+			list_del(pos);
+			mcore_device_cleanup(tmp);
+			return true;
+		}
+	}
+	return false;
+}
+
+
+/*----------------------------------------------------------------------------*/
+enum mc_result mc_open_device(
+	uint32_t device_id
+) {
+	enum mc_result mc_result = MC_DRV_OK;
+	struct connection *dev_con = NULL;
+
+	MCDRV_DBG_VERBOSE("===%s()===", __func__);
+
+	/* Enter critical section */
+
+	do {
+		struct mcore_device_t *device = resolve_device_id(device_id);
+		if (device != NULL) {
+			MCDRV_DBG_ERROR("Device %d already opened", device_id);
+			mc_result = MC_DRV_ERR_INVALID_OPERATION;
+			break;
+		}
+
+		/* Open new connection to device */
+		dev_con = connection_new();
+		if (!connection_connect(dev_con, MC_DAEMON_PID)) {
+			MCDRV_DBG_ERROR(
+				"Could not setup netlink connection to PID %u",
+				MC_DAEMON_PID);
+			mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+			break;
+		}
+
+		/* Forward device open to the daemon and read result */
+		struct mc_drv_cmd_open_device_t mc_drv_cmd_open_device = {
+			/* C++ does not support C99 designated initializers */
+			/* .header = */ {
+			/* .command_id = */ MC_DRV_CMD_OPEN_DEVICE
+			},
+		/* .payload = */ {
+		/* .device_id = */ device_id
+			}
+		};
+
+		int len = connection_write_data(
+				dev_con,
+				&mc_drv_cmd_open_device,
+				sizeof(struct mc_drv_cmd_open_device_t));
+		if (len < 0) {
+			MCDRV_DBG_ERROR("CMD_OPEN_DEVICE writeCmd failed "
+				"ret=%d", len);
+			mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+			break;
+		}
+
+		struct mc_drv_response_header_t  rsp_header;
+		len = connection_read_datablock(
+					dev_con,
+					&rsp_header,
+					sizeof(rsp_header));
+		if (len != sizeof(rsp_header)) {
+			MCDRV_DBG_ERROR("CMD_OPEN_DEVICE readRsp failed "
+				"ret=%d", len);
+			mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+			break;
+		}
+		if (rsp_header.response_id != MC_DRV_RSP_OK) {
+			MCDRV_DBG_ERROR("CMD_OPEN_DEVICE failed, respId=%d",
+							rsp_header.response_id);
+			switch (rsp_header.response_id) {
+			case MC_DRV_RSP_PAYLOAD_LENGTH_ERROR:
+				mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+				break;
+			case MC_DRV_INVALID_DEVICE_NAME:
+				mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
+				break;
+			case MC_DRV_RSP_DEVICE_ALREADY_OPENED:
+			default:
+				mc_result = MC_DRV_ERR_INVALID_OPERATION;
+				break;
+			}
+			break;
+		}
+
+		/* there is no payload to read */
+
+		device = mcore_device_create(device_id, dev_con);
+		if (!mcore_device_open(device, MC_DRV_MOD_DEVNODE_FULLPATH)) {
+			mcore_device_cleanup(device);
+			MCDRV_DBG_ERROR("could not open device file: %s",
+				MC_DRV_MOD_DEVNODE_FULLPATH);
+			mc_result = MC_DRV_ERR_INVALID_DEVICE_FILE;
+			break;
+		}
+
+		add_device(device);
+
+	} while (false);
+
+	if (mc_result != MC_DRV_OK)
+		connection_cleanup(dev_con);
+
+	/* Exit critical section */
+
+	return mc_result;
+}
+EXPORT_SYMBOL(mc_open_device);
+
+/*----------------------------------------------------------------------------*/
+enum mc_result mc_close_device(
+	uint32_t device_id
+) {
+	enum mc_result mc_result = MC_DRV_OK;
+
+	MCDRV_DBG_VERBOSE("===%s()===", __func__);
+
+	/* Enter critical section */
+	do {
+		struct mcore_device_t *device = resolve_device_id(device_id);
+		if (device == NULL) {
+			MCDRV_DBG_ERROR("Device not found");
+			mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
+			break;
+		}
+		struct connection *dev_con = device->connection;
+
+		/* Return if not all sessions have been closed */
+		if (mcore_device_has_sessions(device)) {
+			MCDRV_DBG_ERROR("cannot close with sessions pending");
+			mc_result = MC_DRV_ERR_SESSION_PENDING;
+			break;
+		}
+
+		struct mc_drv_cmd_close_device_t mc_drv_cmd_close_device = {
+			/* C++ does not support C99 designated initializers */
+			/* .header = */ {
+				/* .command_id = */ MC_DRV_CMD_CLOSE_DEVICE
+			}
+		};
+		int len = connection_write_data(
+				dev_con,
+				&mc_drv_cmd_close_device,
+				sizeof(struct mc_drv_cmd_close_device_t));
+		/* ignore error, but log details */
+		if (len < 0) {
+			MCDRV_DBG_ERROR("CMD_CLOSE_DEVICE writeCmd failed "
+				"ret=%d", len);
+			mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+		}
+
+		struct mc_drv_response_header_t  rsp_header;
+		len = connection_read_datablock(
+					dev_con,
+					&rsp_header,
+					sizeof(rsp_header));
+		if (len != sizeof(rsp_header)) {
+			MCDRV_DBG_ERROR("CMD_CLOSE_DEVICE readResp failed "
+				" ret=%d", len);
+			mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+			break;
+		}
+
+		if (rsp_header.response_id != MC_DRV_RSP_OK) {
+			MCDRV_DBG_ERROR("CMD_CLOSE_DEVICE failed, respId=%d",
+							rsp_header.response_id);
+			mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+			break;
+		}
+
+		remove_device(device_id);
+
+	} while (false);
+
+	/* Exit critical section */
+
+	return mc_result;
+}
+EXPORT_SYMBOL(mc_close_device);
+
+/*----------------------------------------------------------------------------*/
+enum mc_result mc_open_session(
+	struct mc_session_handle *session,
+	const struct mc_uuid_t	*uuid,
+	uint8_t			*tci,
+	uint32_t		len
+) {
+	enum mc_result mc_result = MC_DRV_OK;
+
+	MCDRV_DBG_VERBOSE("===%s()===", __func__);
+
+	/* Enter critical section */
+
+	do {
+		if (session == NULL) {
+			MCDRV_DBG_ERROR("Session is null");
+			mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+			break;
+		}
+		if (uuid == NULL) {
+			MCDRV_DBG_ERROR("UUID is null");
+			mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+			break;
+		}
+		if (tci == NULL) {
+			MCDRV_DBG_ERROR("TCI is null");
+			mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+			break;
+		}
+		if (len > MC_MAX_TCI_LEN) {
+			MCDRV_DBG_ERROR("TCI length is longer than %d",
+				MC_MAX_TCI_LEN);
+			mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+			break;
+		}
+
+		/* Get the device associated with the given session */
+		struct mcore_device_t *device =
+				resolve_device_id(session->device_id);
+		if (device == NULL) {
+			MCDRV_DBG_ERROR("Device not found");
+			mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
+			break;
+		}
+		struct connection *dev_con = device->connection;
+
+		/* Get the physical address of the given TCI */
+		struct wsm *wsm =
+			mcore_device_find_contiguous_wsm(device, tci);
+		if (wsm == NULL) {
+			MCDRV_DBG_ERROR("Could not resolve TCI phy address ");
+			mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+			break;
+		}
+
+		if (wsm->len < len) {
+			MCDRV_DBG_ERROR("length is more than allocated TCI");
+			mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+			break;
+		}
+
+		/* Prepare open session command */
+		struct mc_drv_cmd_open_session_t cmdOpenSession = {
+			/* C++ does not support C99 designated initializers */
+			/* .header = */ {
+				/* .command_id = */ MC_DRV_CMD_OPEN_SESSION
+			},
+			/* .payload = */ {
+				/* .device_id = */ session->device_id,
+				/* .uuid = */ *uuid,
+				/* .tci = */ (uint32_t)wsm->phys_addr,
+				/* .len = */ len
+			}
+		};
+
+		/* Transmit command data */
+
+		int len = connection_write_data(
+						dev_con,
+						&cmdOpenSession,
+						sizeof(cmdOpenSession));
+		if (len != sizeof(cmdOpenSession)) {
+			MCDRV_DBG_ERROR("CMD_OPEN_SESSION writeData failed "
+				"ret=%d", len);
+			mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+			break;
+		}
+
+		/* Read command response */
+
+		/* read header first */
+		struct mc_drv_response_header_t rsp_header;
+		len = connection_read_datablock(
+					dev_con,
+					&rsp_header,
+					sizeof(rsp_header));
+		if (len != sizeof(rsp_header)) {
+			MCDRV_DBG_ERROR("CMD_OPEN_SESSION readResp failed "
+				" ret=%d", len);
+			mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+			break;
+		}
+
+		if (rsp_header.response_id != MC_DRV_RSP_OK) {
+			MCDRV_DBG_ERROR("CMD_OPEN_SESSION failed, respId=%d",
+							rsp_header.response_id);
+			switch (rsp_header.response_id) {
+			case MC_DRV_RSP_TRUSTLET_NOT_FOUND:
+				mc_result = MC_DRV_ERR_INVALID_DEVICE_FILE;
+				break;
+			case MC_DRV_RSP_PAYLOAD_LENGTH_ERROR:
+			case MC_DRV_RSP_DEVICE_NOT_OPENED:
+			case MC_DRV_RSP_FAILED:
+			default:
+				mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+				break;
+			}
+			break;
+		}
+
+		/* read payload */
+		struct mc_drv_rsp_open_session_payload_t
+						rsp_open_session_payload;
+		len = connection_read_datablock(
+					dev_con,
+					&rsp_open_session_payload,
+					sizeof(rsp_open_session_payload));
+		if (len != sizeof(rsp_open_session_payload)) {
+			MCDRV_DBG_ERROR("CMD_OPEN_SESSION readPayload failed "
+				"ret=%d", len);
+			mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+			break;
+		}
+
+		/* Register session with handle */
+		session->session_id = rsp_open_session_payload.session_id;
+
+		/* Set up second channel for notifications */
+		struct connection *session_connection = connection_new();
+		/*TODO: no real need to connect here? */
+		if (!connection_connect(session_connection, MC_DAEMON_PID)) {
+			MCDRV_DBG_ERROR(
+				"Could not setup netlink connection to PID %u",
+				MC_DAEMON_PID);
+			connection_cleanup(session_connection);
+			mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+			break;
+		}
+
+		/*TODO CONTINOUE HERE !!!! FIX RW RETURN HANDLING!!!! */
+
+		/* Write command to use channel for notifications */
+		struct mc_drv_cmd_nqconnect_t cmd_nqconnect = {
+			/* C++ does not support C99 designated initializers */
+			/* .header = */ {
+				/* .command_id = */ MC_DRV_CMD_NQ_CONNECT
+			},
+			/* .payload = */ {
+				/* .device_id =  */ session->device_id,
+				/* .session_id = */ session->session_id,
+				/* .device_session_id = */
+				rsp_open_session_payload.device_session_id,
+				/* .session_magic = */
+					rsp_open_session_payload.session_magic
+			}
+		};
+		connection_write_data(session_connection,
+			&cmd_nqconnect,
+			sizeof(cmd_nqconnect));
+
+		/* Read command response, header first */
+		len = connection_read_datablock(
+					session_connection,
+					&rsp_header,
+					sizeof(rsp_header));
+		if (len != sizeof(rsp_header)) {
+			MCDRV_DBG_ERROR("CMD_NQ_CONNECT readRsp failed "
+				"ret=%d", len);
+			connection_cleanup(session_connection);
+			mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+			break;
+		}
+
+		if (rsp_header.response_id != MC_DRV_RSP_OK) {
+			MCDRV_DBG_ERROR("CMD_NQ_CONNECT failed, respId=%d",
+					rsp_header.response_id);
+			connection_cleanup(session_connection);
+			mc_result = MC_DRV_ERR_NQ_FAILED;
+			break;
+		}
+
+		/* there is no payload. */
+
+		/* Session established, new session object must be created */
+		mcore_device_create_new_session(
+			device,
+			session->session_id,
+			session_connection);
+
+	} while (false);
+
+	/* Exit critical section */
+
+	return mc_result;
+}
+EXPORT_SYMBOL(mc_open_session);
+
+/*----------------------------------------------------------------------------*/
+enum mc_result mc_close_session(
+	struct mc_session_handle *session
+) {
+	enum mc_result mc_result = MC_DRV_OK;
+
+	MCDRV_DBG_VERBOSE("===%s()===", __func__);
+
+	/* Enter critical section */
+
+	do {
+		if (session == NULL) {
+			MCDRV_DBG_ERROR("Session is null");
+			mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+			break;
+		}
+
+		struct mcore_device_t  *device =
+					resolve_device_id(session->device_id);
+		if (device == NULL) {
+			MCDRV_DBG_ERROR("Device not found");
+			mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
+			break;
+		}
+		struct connection  *dev_con = device->connection;
+
+		struct session  *nq_session =
+		 mcore_device_resolve_session_id(device, session->session_id);
+		if (nq_session == NULL) {
+			MCDRV_DBG_ERROR("Session not found");
+			mc_result = MC_DRV_ERR_UNKNOWN_SESSION;
+			break;
+		}
+
+		/* Write close session command */
+		struct mc_drv_cmd_close_session_t cmd_close_session = {
+			/* C++ does not support C99 designated initializers */
+			/* .header = */ {
+				/* .command_id = */ MC_DRV_CMD_CLOSE_SESSION
+			},
+			/* .payload = */ {
+				/* .session_id = */ session->session_id,
+			}
+		};
+		connection_write_data(
+			dev_con,
+			&cmd_close_session,
+			sizeof(cmd_close_session));
+
+		/* Read command response */
+		struct mc_drv_response_header_t rsp_header;
+		int len = connection_read_datablock(
+						dev_con,
+						&rsp_header,
+						sizeof(rsp_header));
+		if (len != sizeof(rsp_header)) {
+			MCDRV_DBG_ERROR("CMD_CLOSE_SESSION readRsp failed "
+				"ret=%d", len);
+			mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+			break;
+		}
+
+		if (rsp_header.response_id != MC_DRV_RSP_OK) {
+			MCDRV_DBG_ERROR("CMD_CLOSE_SESSION failed, respId=%d",
+							rsp_header.response_id);
+			mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
+			break;
+		}
+
+		mcore_device_remove_session(device, session->session_id);
+		mc_result = MC_DRV_OK;
+
+	} while (false);
+
+	/* Exit critical section */
+
+	return mc_result;
+}
+EXPORT_SYMBOL(mc_close_session);
+
+/*----------------------------------------------------------------------------*/
+enum mc_result mc_notify(
+	struct mc_session_handle   *session
+) {
+	enum mc_result mc_result = MC_DRV_OK;
+
+	MCDRV_DBG_VERBOSE("===%s()===", __func__);
+
+	do {
+		if (session == NULL) {
+			MCDRV_DBG_ERROR("Session is null");
+			mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+			break;
+		}
+
+		struct mcore_device_t *device =
+					resolve_device_id(session->device_id);
+		if (device == NULL) {
+			MCDRV_DBG_ERROR("Device not found");
+			mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
+			break;
+		}
+		struct connection *dev_con = device->connection;
+
+		struct session  *nqsession =
+		 mcore_device_resolve_session_id(device, session->session_id);
+		if (nqsession == NULL) {
+			MCDRV_DBG_ERROR("Session not found");
+			mc_result = MC_DRV_ERR_UNKNOWN_SESSION;
+			break;
+		}
+
+		struct mc_drv_cmd_notify_t cmd_notify = {
+			/* C++ does not support C99 designated initializers */
+			/* .header = */ {
+				/* .command_id = */ MC_DRV_CMD_NOTIFY
+			},
+			/* .payload = */ {
+				/* .session_id = */ session->session_id,
+			}
+		};
+
+		connection_write_data(
+			dev_con,
+			&cmd_notify,
+			sizeof(cmd_notify));
+
+		/* Daemon will not return a response */
+
+	} while (false);
+
+	return mc_result;
+}
+EXPORT_SYMBOL(mc_notify);
+
+/*----------------------------------------------------------------------------*/
+enum mc_result mc_wait_notification(
+	struct mc_session_handle  *session,
+	int32_t			timeout
+) {
+	enum mc_result mc_result = MC_DRV_OK;
+
+	MCDRV_DBG_VERBOSE("===%s()===", __func__);
+
+	do {
+		if (session == NULL) {
+			mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+			break;
+		}
+
+		struct mcore_device_t  *device =
+					resolve_device_id(session->device_id);
+		if (device == NULL) {
+			MCDRV_DBG_ERROR("Device not found");
+			mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
+			break;
+		}
+
+		struct session  *nq_session =
+		 mcore_device_resolve_session_id(device, session->session_id);
+		if (nq_session == NULL) {
+			MCDRV_DBG_ERROR("Session not found");
+			mc_result = MC_DRV_ERR_UNKNOWN_SESSION;
+			break;
+		}
+
+		struct connection *nqconnection =
+					nq_session->notification_connection;
+		uint32_t count = 0;
+
+		/* Read notification queue till it's empty */
+		for (;;) {
+			struct notification notification;
+			ssize_t num_read = connection_read_data(
+				nqconnection,
+				&notification,
+				sizeof(notification),
+				timeout);
+			/* Exit on timeout in first run. Later runs have
+			 * timeout set to 0.
+			 * -2 means, there is no more data. */
+			if (count == 0 && num_read == -2) {
+				MCDRV_DBG_ERROR("read timeout");
+				mc_result = MC_DRV_ERR_TIMEOUT;
+				break;
+			}
+			/* After first notification the queue will be
+			 * drained, Thus we set no timeout for the
+			 * following reads */
+			timeout = 0;
+
+			if (num_read != sizeof(struct notification)) {
+				if (count == 0) {
+					/* failure in first read, notify it */
+					mc_result = MC_DRV_ERR_NOTIFICATION;
+					MCDRV_DBG_ERROR(
+					"read notification failed, "
+					"%i bytes received", (int)num_read);
+					break;
+				} else {
+					/* Read of the n-th notification
+					   failed/timeout. We don't tell the
+					   caller, as we got valid notifications
+					   before. */
+					mc_result = MC_DRV_OK;
+					break;
+				}
+			}
+
+			count++;
+			MCDRV_DBG_VERBOSE("readNq count=%d, SessionID=%d, "
+				"Payload=%d", count,
+				notification.session_id, notification.payload);
+
+			if (notification.payload != 0) {
+				/* Session end point died -> store exit code */
+				session_set_error_info(nq_session,
+					notification.payload);
+
+				mc_result = MC_DRV_INFO_NOTIFICATION;
+				break;
+			}
+		} /* for(;;) */
+
+	} while (false);
+
+	return mc_result;
+}
+EXPORT_SYMBOL(mc_wait_notification);
+
+/*----------------------------------------------------------------------------*/
+enum mc_result mc_malloc_wsm(
+	uint32_t	device_id,
+	uint32_t	align,
+	uint32_t	len,
+	uint8_t		**wsm,
+	uint32_t	wsm_flags
+) {
+	enum mc_result mc_result = MC_DRV_ERR_UNKNOWN;
+
+	MCDRV_DBG_VERBOSE("===%s()===", __func__);
+
+	/* Enter critical section */
+
+	do {
+		struct mcore_device_t *device = resolve_device_id(device_id);
+		if (device == NULL) {
+			MCDRV_DBG_ERROR("Device not found");
+			mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
+			break;
+		}
+		if (wsm == NULL) {
+			mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+			break;
+		}
+
+		struct wsm *wsm_stack =
+			mcore_device_allocate_contiguous_wsm(device, len);
+		if (wsm_stack == NULL) {
+			MCDRV_DBG_ERROR("Allocation of WSM failed");
+			mc_result = MC_DRV_ERR_NO_FREE_MEMORY;
+			break;
+		}
+
+		*wsm = (uint8_t *)wsm_stack->virt_addr;
+		mc_result = MC_DRV_OK;
+
+	} while (false);
+
+	/* Exit critical section */
+
+	return mc_result;
+}
+EXPORT_SYMBOL(mc_malloc_wsm);
+
+/*----------------------------------------------------------------------------*/
+enum mc_result mc_free_wsm(
+	uint32_t	device_id,
+	uint8_t		*wsm
+) {
+	enum mc_result mc_result = MC_DRV_ERR_UNKNOWN;
+	struct mcore_device_t *device;
+
+
+	MCDRV_DBG_VERBOSE("===%s()===", __func__);
+
+	/* Enter critical section */
+
+	do {
+
+		/* Get the device associated wit the given session */
+		device = resolve_device_id(device_id);
+		if (device == NULL) {
+			MCDRV_DBG_ERROR("Device not found");
+			mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
+			break;
+		}
+
+		/* find WSM object */
+		struct wsm *wsm_stack =
+			mcore_device_find_contiguous_wsm(device, wsm);
+		if (wsm_stack == NULL) {
+			MCDRV_DBG_ERROR("unknown address");
+			mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+			break;
+		}
+
+		/* Free the given virtual address */
+		if (!mcore_device_free_contiguous_wsm(device, wsm_stack)) {
+			MCDRV_DBG_ERROR("Free of virtual address failed");
+			mc_result = MC_DRV_ERR_FREE_MEMORY_FAILED;
+			break;
+		}
+		mc_result = MC_DRV_OK;
+
+	} while (false);
+
+	/* Exit critical section */
+
+	return mc_result;
+}
+EXPORT_SYMBOL(mc_free_wsm);
+
+/*----------------------------------------------------------------------------*/
+enum mc_result mc_map(
+	struct mc_session_handle	*session_handle,
+	void				*buf,
+	uint32_t			buf_len,
+	struct mc_bulk_map		*map_info
+) {
+	enum mc_result mc_result = MC_DRV_ERR_UNKNOWN;
+
+	MCDRV_DBG_VERBOSE("===%s()===", __func__);
+
+	/* Enter critical section */
+
+	do {
+		if (session_handle == NULL) {
+			MCDRV_DBG_ERROR("session_handle is null");
+			mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+			break;
+		}
+		if (map_info == NULL) {
+			MCDRV_DBG_ERROR("map_info is null");
+			mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+			break;
+		}
+		if (buf == NULL) {
+			MCDRV_DBG_ERROR("buf is null");
+			mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+			break;
+		}
+
+		/* Determine device the session belongs to */
+		struct mcore_device_t  *device = resolve_device_id(
+						session_handle->device_id);
+		if (device == NULL) {
+			MCDRV_DBG_ERROR("Device not found");
+			mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
+			break;
+		}
+		struct connection *dev_con = device->connection;
+
+		/* Get session */
+		struct session  *session =
+		mcore_device_resolve_session_id(device,
+						session_handle->session_id);
+		if (session == NULL) {
+			MCDRV_DBG_ERROR("Session not found");
+			mc_result = MC_DRV_ERR_UNKNOWN_SESSION;
+			break;
+		}
+
+		/* Register mapped bulk buffer to Kernel Module and keep mapped
+		   bulk buffer in mind */
+		struct bulk_buffer_descriptor *bulk_buf = session_add_bulk_buf(
+			session, buf, buf_len);
+		if (bulk_buf == NULL) {
+			MCDRV_DBG_ERROR("Error mapping bulk buffer");
+			mc_result = MC_DRV_ERR_BULK_MAPPING;
+			break;
+		}
+
+		/* Prepare map command */
+		struct mc_drv_cmd_map_bulk_mem_t mc_drv_cmd_map_bulk_mem = {
+			/* C++ does not support C99 designated initializers */
+			/* .header = */ {
+				/* .command_id = */ MC_DRV_CMD_MAP_BULK_BUF
+			},
+			/* .payload = */ {
+				/* .session_id = */ session->session_id,
+				/* .phys_addr_l2; = */
+					(uint32_t)bulk_buf->phys_addr_wsm_l2,
+				/* .offset_payload = */
+					(uint32_t)(bulk_buf->virt_addr) & 0xFFF,
+				/* .len_bulk_mem = */ bulk_buf->len
+			}
+		};
+
+		/* Transmit map command to MobiCore device */
+		connection_write_data(
+			dev_con,
+			&mc_drv_cmd_map_bulk_mem,
+			sizeof(mc_drv_cmd_map_bulk_mem));
+
+		/* Read command response */
+		struct mc_drv_response_header_t rsp_header;
+		int len = connection_read_datablock(
+						dev_con,
+						&rsp_header,
+						sizeof(rsp_header));
+		if (len != sizeof(rsp_header)) {
+			MCDRV_DBG_ERROR("CMD_MAP_BULK_BUF readRsp failed, "
+				"ret=%d", len);
+			mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+			break;
+		}
+
+		if (rsp_header.response_id != MC_DRV_RSP_OK) {
+			MCDRV_DBG_ERROR("CMD_MAP_BULK_BUF failed, respId=%d",
+							rsp_header.response_id);
+			/* REV We ignore Daemon Error code because client cannot
+			   handle it anyhow. */
+			mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+
+			/* Unregister mapped bulk buffer from Kernel Module and
+			   remove mapped bulk buffer from session maintenance */
+			if (!session_remove_bulk_buf(session, buf)) {
+				/* Removing of bulk buffer not possible */
+				MCDRV_DBG_ERROR("Unregistering of bulk memory"
+					"from Kernel Module failed");
+			}
+			break;
+		}
+
+		struct mc_drv_rsp_map_bulk_mem_payload_t
+						rsp_map_bulk_mem_payload;
+		connection_read_datablock(
+			dev_con,
+			&rsp_map_bulk_mem_payload,
+			sizeof(rsp_map_bulk_mem_payload));
+
+		/* Set mapping info for Trustlet */
+		map_info->secure_virt_addr =
+			(void *)(rsp_map_bulk_mem_payload.secure_virtual_adr);
+		map_info->secure_virt_len = buf_len;
+		mc_result = MC_DRV_OK;
+
+	} while (false);
+
+	/* Exit critical section */
+
+	return mc_result;
+}
+EXPORT_SYMBOL(mc_map);
+
+/*----------------------------------------------------------------------------*/
+enum mc_result mc_unmap(
+	struct mc_session_handle	*session_handle,
+	void				*buf,
+	struct mc_bulk_map		*map_info
+) {
+	enum mc_result mc_result = MC_DRV_ERR_UNKNOWN;
+
+	MCDRV_DBG_VERBOSE("===%s()===", __func__);
+
+	/* Enter critical section */
+
+	do {
+		if (session_handle == NULL) {
+			MCDRV_DBG_ERROR("session_handle is null");
+			mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+			break;
+		}
+		if (map_info == NULL) {
+			MCDRV_DBG_ERROR("map_info is null");
+			mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+			break;
+		}
+		if (buf == NULL) {
+			MCDRV_DBG_ERROR("buf is null");
+			mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+			break;
+		}
+
+		/* Determine device the session belongs to */
+		struct mcore_device_t  *device =
+			resolve_device_id(session_handle->device_id);
+		if (device == NULL) {
+			MCDRV_DBG_ERROR("Device not found");
+			mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
+			break;
+		}
+		struct connection  *dev_con = device->connection;
+
+		/* Get session */
+		struct session  *session =
+			mcore_device_resolve_session_id(device,
+						session_handle->session_id);
+		if (session == NULL) {
+			MCDRV_DBG_ERROR("Session not found");
+			mc_result = MC_DRV_ERR_UNKNOWN_SESSION;
+			break;
+		}
+
+		/* Prepare unmap command */
+		struct mc_drv_cmd_unmap_bulk_mem_t cmd_unmap_bulk_mem = {
+				/* .header = */ {
+					/* .command_id = */
+						MC_DRV_CMD_UNMAP_BULK_BUF
+				},
+				/* .payload = */ {
+					/* .session_id = */ session->session_id,
+					/* .secure_virtual_adr = */
+					(uint32_t)(map_info->secure_virt_addr),
+					/* .len_bulk_mem =
+						map_info->secure_virt_len*/
+				}
+			};
+
+		connection_write_data(
+			dev_con,
+			&cmd_unmap_bulk_mem,
+			sizeof(cmd_unmap_bulk_mem));
+
+		/* Read command response */
+		struct mc_drv_response_header_t rsp_header;
+		int len = connection_read_datablock(
+						dev_con,
+						&rsp_header,
+						sizeof(rsp_header));
+		if (len != sizeof(rsp_header)) {
+			MCDRV_DBG_ERROR("CMD_UNMAP_BULK_BUF readRsp failed, "
+				"ret=%d", len);
+			mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+			break;
+		}
+
+		if (rsp_header.response_id != MC_DRV_RSP_OK) {
+			MCDRV_DBG_ERROR("CMD_UNMAP_BULK_BUF failed, respId=%d",
+							rsp_header.response_id);
+			/* REV We ignore Daemon Error code because client
+			   cannot handle it anyhow. */
+			mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+			break;
+		}
+
+		struct mc_drv_rsp_unmap_bulk_mem_payload_t
+						rsp_unmap_bulk_mem_payload;
+		connection_read_datablock(
+			dev_con,
+			&rsp_unmap_bulk_mem_payload,
+			sizeof(rsp_unmap_bulk_mem_payload));
+
+		/* REV axh: what about check the payload? */
+
+		/* Unregister mapped bulk buffer from Kernel Module and
+		 * remove mapped bulk buffer from session maintenance */
+		if (!session_remove_bulk_buf(session, buf)) {
+			/* Removing of bulk buffer not possible */
+			MCDRV_DBG_ERROR("Unregistering of bulk memory from "
+							"Kernel Module failed");
+			mc_result = MC_DRV_ERR_BULK_UNMAPPING;
+			break;
+		}
+
+		mc_result = MC_DRV_OK;
+
+	} while (false);
+
+	/* Exit critical section */
+
+	return mc_result;
+}
+EXPORT_SYMBOL(mc_unmap);
+
+/*----------------------------------------------------------------------------*/
+enum mc_result mc_get_session_error_code(
+	struct mc_session_handle   *session,
+	int32_t			 *last_error
+) {
+	enum mc_result mc_result = MC_DRV_OK;
+
+	MCDRV_DBG_VERBOSE("===%s()===", __func__);
+
+	do {
+		if (session == NULL || last_error == NULL) {
+			mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+			break;
+		}
+
+		/* Get device */
+		struct mcore_device_t *device =
+					resolve_device_id(session->device_id);
+		if (device == NULL) {
+			MCDRV_DBG_ERROR("Device not found");
+			mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
+			break;
+		}
+
+		/* Get session */
+		struct session *nqsession =
+		 mcore_device_resolve_session_id(device, session->session_id);
+		if (nqsession == NULL) {
+			MCDRV_DBG_ERROR("Session not found");
+			mc_result = MC_DRV_ERR_UNKNOWN_SESSION;
+			break;
+		}
+
+		/* get session error code from session */
+		*last_error = session_get_last_err(nqsession);
+
+	} while (false);
+
+	return mc_result;
+}
+EXPORT_SYMBOL(mc_get_session_error_code);
+
+/*----------------------------------------------------------------------------*/
+enum mc_result mc_driver_ctrl(
+	enum mc_driver_ctrl  param,
+	uint8_t		 *data,
+	uint32_t		len
+) {
+	MCDRV_DBG_WARN("not implemented");
+	return MC_DRV_ERR_NOT_IMPLEMENTED;
+}
+EXPORT_SYMBOL(mc_driver_ctrl);
+
+/*----------------------------------------------------------------------------*/
+enum mc_result mc_manage(
+	uint32_t  device_id,
+	uint8_t   *data,
+	uint32_t  len
+) {
+	MCDRV_DBG_WARN("not implemented");
+	return MC_DRV_ERR_NOT_IMPLEMENTED;
+}
+EXPORT_SYMBOL(mc_manage);
+
diff --git a/drivers/gud/mobicore_kernelapi/common.h b/drivers/gud/mobicore_kernelapi/common.h
new file mode 100644
index 0000000..2a73474
--- /dev/null
+++ b/drivers/gud/mobicore_kernelapi/common.h
@@ -0,0 +1,97 @@
+/**
+ *
+ * Common data types
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef COMMON_H
+#define COMMON_H
+
+#include "connection.h"
+#include "mcinq.h"
+
+void mcapi_insert_connection(
+	struct connection *connection
+);
+
+void mcapi_remove_connection(
+	uint32_t seq
+);
+
+unsigned int mcapi_unique_id(
+	void
+);
+
+
+#define MC_DAEMON_PID 0xFFFFFFFF
+#define MC_DRV_MOD_DEVNODE_FULLPATH "/dev/mobicore"
+
+/* dummy function helper macro. */
+#define DUMMY_FUNCTION()	do {} while (0)
+
+#define MCDRV_ERROR(txt, ...) \
+	printk(KERN_ERR "mcKernelApi %s() ### ERROR: " txt, \
+		__func__, \
+		##__VA_ARGS__)
+
+#if defined(DEBUG)
+
+/* #define DEBUG_VERBOSE */
+#if defined(DEBUG_VERBOSE)
+#define MCDRV_DBG_VERBOSE		  MCDRV_DBG
+#else
+#define MCDRV_DBG_VERBOSE(...)	 DUMMY_FUNCTION()
+#endif
+
+#define MCDRV_DBG(txt, ...) \
+	printk(KERN_INFO "mcKernelApi %s(): " txt, \
+		__func__, \
+		##__VA_ARGS__)
+
+#define MCDRV_DBG_WARN(txt, ...) \
+	printk(KERN_WARNING "mcKernelApi %s() WARNING: " txt, \
+		__func__, \
+		##__VA_ARGS__)
+
+#define MCDRV_DBG_ERROR(txt, ...) \
+	printk(KERN_ERR "mcKernelApi %s() ### ERROR: " txt, \
+		__func__, \
+		##__VA_ARGS__)
+
+
+#define MCDRV_ASSERT(cond) \
+	do { \
+		if (unlikely(!(cond))) { \
+			panic("mcKernelApi Assertion failed: %s:%d\n", \
+				__FILE__, __LINE__); \
+		} \
+	} while (0)
+
+#elif defined(NDEBUG)
+
+#define MCDRV_DBG_VERBOSE(...)	DUMMY_FUNCTION()
+#define MCDRV_DBG(...)		DUMMY_FUNCTION()
+#define MCDRV_DBG_WARN(...)	DUMMY_FUNCTION()
+#define MCDRV_DBG_ERROR(...)	DUMMY_FUNCTION()
+
+#define MCDRV_ASSERT(...)	DUMMY_FUNCTION()
+
+#else
+#error "Define DEBUG or NDEBUG"
+#endif /* [not] defined(DEBUG_MCMODULE) */
+
+
+#define LOG_I MCDRV_DBG_VERBOSE
+#define LOG_W MCDRV_DBG_WARN
+#define LOG_E MCDRV_DBG_ERROR
+
+
+#define assert(expr) MCDRV_ASSERT(expr)
+
+#endif /* COMMON_H */
+
+/** @} */
diff --git a/drivers/gud/mobicore_kernelapi/connection.c b/drivers/gud/mobicore_kernelapi/connection.c
new file mode 100644
index 0000000..9048ae8
--- /dev/null
+++ b/drivers/gud/mobicore_kernelapi/connection.c
@@ -0,0 +1,229 @@
+/** @addtogroup MCD_MCDIMPL_DAEMON_SRV
+ * @{
+ * @file
+ *
+ * Connection data.
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/netlink.h>
+#include <linux/skbuff.h>
+#include <linux/netlink.h>
+#include <linux/semaphore.h>
+#include <linux/time.h>
+#include <net/sock.h>
+#include <net/net_namespace.h>
+
+#include "connection.h"
+#include "common.h"
+
+/* Define the initial state of the Data Available Semaphore */
+#define SEM_NO_DATA_AVAILABLE 0
+
+/*----------------------------------------------------------------------------*/
+struct connection *connection_new(
+	void
+) {
+	struct connection *conn = kzalloc(sizeof(struct connection),
+					GFP_KERNEL);
+	conn->sequence_magic = mcapi_unique_id();
+	mutex_init(&conn->data_lock);
+	/* No data available */
+	sema_init(&conn->data_available_sem, SEM_NO_DATA_AVAILABLE);
+
+	mcapi_insert_connection(conn);
+	return conn;
+}
+
+/*----------------------------------------------------------------------------*/
+struct connection *connection_create(
+	int	 socket_descriptor,
+	pid_t   dest
+) {
+	struct connection *conn = connection_new();
+
+	conn->peer_pid = dest;
+	return conn;
+}
+
+
+/*----------------------------------------------------------------------------*/
+void connection_cleanup(
+	struct connection *conn
+) {
+	if (!conn)
+		return;
+
+	kfree_skb(conn->skb);
+
+	mcapi_remove_connection(conn->sequence_magic);
+	kfree(conn);
+}
+
+
+/*----------------------------------------------------------------------------*/
+bool connection_connect(
+	struct connection *conn,
+	pid_t		dest
+) {
+	/* Nothing to connect */
+	conn->peer_pid = dest;
+	return true;
+}
+
+/*----------------------------------------------------------------------------*/
+size_t connection_readDataMsg(
+	struct connection *conn,
+	void *buffer,
+	uint32_t len
+) {
+	size_t ret = -1;
+	MCDRV_DBG_VERBOSE("reading connection data %u, connection data left %u",
+			len, conn->data_len);
+	/* trying to read more than the left data */
+	if (len > conn->data_len) {
+		ret = conn->data_len;
+		memcpy(buffer, conn->data_start, conn->data_len);
+		conn->data_len = 0;
+	} else {
+		ret = len;
+		memcpy(buffer, conn->data_start, len);
+		conn->data_len -= len;
+		conn->data_start += len;
+	}
+
+	if (conn->data_len == 0)	{
+		conn->data_start = NULL;
+		kfree_skb(conn->skb);
+		conn->skb = NULL;
+	}
+	MCDRV_DBG_VERBOSE("read %u",  ret);
+	return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+size_t connection_read_datablock(
+	struct connection *conn,
+	void		 *buffer,
+	uint32_t	 len
+) {
+	return connection_read_data(conn, buffer, len, -1);
+}
+
+
+/*----------------------------------------------------------------------------*/
+size_t connection_read_data(
+	struct connection *conn,
+	void		*buffer,
+	uint32_t	len,
+	int32_t		timeout
+) {
+	size_t ret = 0;
+
+	MCDRV_ASSERT(buffer != NULL);
+	MCDRV_ASSERT(conn->socket_descriptor != NULL);
+
+	MCDRV_DBG_VERBOSE("read data len = %u for PID = %u",
+						len, conn->sequence_magic);
+	do {
+		/* Wait until data is available or timeout
+		   msecs_to_jiffies(-1) -> wait forever for the sem */
+		if (down_timeout(&(conn->data_available_sem),
+				  msecs_to_jiffies(timeout))) {
+			MCDRV_DBG_VERBOSE("Timeout reading the data sem");
+			ret = -2;
+			break;
+		}
+
+		if (mutex_lock_interruptible(&(conn->data_lock))) {
+			MCDRV_DBG_ERROR("interrupted reading the data sem");
+			ret = -1;
+			break;
+		}
+		/* Have data, use it */
+		if (conn->data_len > 0)
+			ret = connection_readDataMsg(conn, buffer, len);
+
+			mutex_unlock(&(conn->data_lock));
+
+		/* There is still some data left */
+		if (conn->data_len > 0)
+			up(&conn->data_available_sem);
+	} while (0);
+
+	return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+size_t connection_write_data(
+	struct connection *conn,
+	void		 *buffer,
+	uint32_t	 len
+) {
+	struct sk_buff *skb = NULL;
+	struct nlmsghdr *nlh;
+	int ret = 0;
+
+	MCDRV_DBG_VERBOSE("buffer length %u from pid %u\n",
+		  len,  conn->sequence_magic);
+	do {
+		skb = nlmsg_new(NLMSG_SPACE(len), GFP_KERNEL);
+		if (!skb) {
+			ret = -1;
+			break;
+		}
+
+		nlh = nlmsg_put(skb, 0, conn->sequence_magic, 2,
+					  NLMSG_LENGTH(len), NLM_F_REQUEST);
+		if (!nlh) {
+			ret = -1;
+			break;
+		}
+		memcpy(NLMSG_DATA(nlh), buffer, len);
+
+		netlink_unicast(conn->socket_descriptor, skb,
+						conn->peer_pid, MSG_DONTWAIT);
+		ret = len;
+	} while (0);
+
+	if (!ret && skb != NULL)
+		kfree_skb(skb);
+
+	return ret;
+}
+
+int connection_process(
+	struct connection *conn,
+	struct sk_buff *skb
+)
+{
+	int ret = 0;
+	do {
+		if (mutex_lock_interruptible(&(conn->data_lock))) {
+			MCDRV_DBG_ERROR("Interrupted getting data semaphore!");
+			ret = -1;
+			break;
+		}
+
+		kfree_skb(conn->skb);
+
+		/* Get a reference to the incomming skb */
+		conn->skb = skb_get(skb);
+		if (conn->skb) {
+			conn->data_msg = nlmsg_hdr(conn->skb);
+			conn->data_len = NLMSG_PAYLOAD(conn->data_msg, 0);
+			conn->data_start = NLMSG_DATA(conn->data_msg);
+			up(&(conn->data_available_sem));
+		}
+		mutex_unlock(&(conn->data_lock));
+		ret = 0;
+	} while (0);
+	return ret;
+}
+/** @} */
diff --git a/drivers/gud/mobicore_kernelapi/connection.h b/drivers/gud/mobicore_kernelapi/connection.h
new file mode 100644
index 0000000..0b468e6
--- /dev/null
+++ b/drivers/gud/mobicore_kernelapi/connection.h
@@ -0,0 +1,122 @@
+/** @addtogroup MCD_MCDIMPL_DAEMON_SRV
+ * @{
+ * @file
+ *
+ * Connection data.
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef CONNECTION_H_
+#define CONNECTION_H_
+
+#include <linux/semaphore.h>
+
+#include <stddef.h>
+#include <stdbool.h>
+
+#define MAX_PAYLOAD_SIZE 128
+
+struct connection {
+	struct sock *socket_descriptor; /**< Netlink socket */
+	uint32_t sequence_magic; /**< Random? magic to match requests/answers */
+
+	struct nlmsghdr *data_msg;
+	uint32_t data_len; /**< How much connection data is left */
+	void *data_start; /**< Start pointer of remaining data */
+	struct sk_buff *skb;
+
+	struct mutex data_lock; /**< Data protection lock */
+	struct semaphore data_available_sem; /**< Data protection semaphore */
+
+	pid_t self_pid; /**< PID address used for local connection */
+	pid_t peer_pid; /**< Remote PID for connection */
+
+	struct list_head list; /**< The list param for using the kernel lists*/
+};
+
+struct connection *connection_new(
+	void
+);
+
+struct connection *connection_create(
+	int		  socket_descriptor,
+	pid_t		dest
+);
+
+void connection_cleanup(
+	struct connection *conn
+);
+
+/**
+  * Connect to destination.
+  *
+  * @param Destination pointer.
+  * @return true on success.
+  */
+bool connection_connect(
+	struct connection *conn,
+	pid_t		dest
+);
+
+
+/**
+  * Read bytes from the connection.
+  *
+  * @param buffer	Pointer to destination buffer.
+  * @param len	   Number of bytes to read.
+  * @return Number of bytes read.
+  */
+size_t connection_read_datablock(
+	struct connection *conn,
+	void		 *buffer,
+	uint32_t	 len
+);
+/**
+  * Read bytes from the connection.
+  *
+  * @param buffer	Pointer to destination buffer.
+  * @param len	   Number of bytes to read.
+  * @param timeout   Timeout in milliseconds
+  * @return Number of bytes read.
+  * @return -1 if select() failed (returned -1)
+  * @return -2 if no data available, i.e. timeout
+  */
+size_t connection_read_data(
+	struct connection *conn,
+	void		 *buffer,
+	uint32_t	 len,
+	int32_t	  timeout
+);
+
+/**
+  * Write bytes to the connection.
+  *
+  * @param buffer	Pointer to source buffer.
+  * @param len		Number of bytes to read.
+  * @return Number of bytes written.
+  */
+size_t connection_write_data(
+	struct connection *conn,
+	void		 *buffer,
+	uint32_t	  len
+);
+
+/**
+ * Write bytes to the connection.
+ *
+ * @param buffer	Pointer to source buffer.
+ * @param len		Number of bytes to read.
+ * @return Number of bytes written.
+ */
+int connection_process(
+	struct connection *conn,
+	struct sk_buff *skb
+);
+
+#endif /* CONNECTION_H_ */
+
+/** @} */
diff --git a/drivers/gud/mobicore_kernelapi/device.c b/drivers/gud/mobicore_kernelapi/device.c
new file mode 100644
index 0000000..dbeee6a
--- /dev/null
+++ b/drivers/gud/mobicore_kernelapi/device.c
@@ -0,0 +1,257 @@
+/** @addtogroup MCD_IMPL_LIB
+ * @{
+ * @file
+ *
+ * Client library device management.
+ *
+ * Device and Trustlet Session management Funtions.
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/list.h>
+#include <linux/slab.h>
+#include "mc_kernel_api.h"
+#include "public/mobicore_driver_api.h"
+
+#include "device.h"
+#include "common.h"
+
+/*----------------------------------------------------------------------------*/
+struct wsm *wsm_create(
+	void	*virt_addr,
+	uint32_t  len,
+	uint32_t  handle,
+	void	*phys_addr /*= NULL this may be unknown, so is can be omitted.*/
+	)
+{
+	struct wsm *wsm = kzalloc(sizeof(struct wsm), GFP_KERNEL);
+	wsm->virt_addr = virt_addr;
+	wsm->len = len;
+	wsm->handle = handle;
+	wsm->phys_addr = phys_addr;
+	return wsm;
+}
+
+
+/*----------------------------------------------------------------------------*/
+struct mcore_device_t *mcore_device_create(
+	uint32_t  device_id,
+	struct connection  *connection
+) {
+	struct mcore_device_t *dev =
+			kzalloc(sizeof(struct mcore_device_t), GFP_KERNEL);
+	dev->device_id = device_id;
+	dev->connection = connection;
+
+	INIT_LIST_HEAD(&dev->session_vector);
+	INIT_LIST_HEAD(&dev->wsm_l2_vector);
+
+	return dev;
+}
+
+
+/*----------------------------------------------------------------------------*/
+void mcore_device_cleanup(
+	struct mcore_device_t *dev
+) {
+	struct session *tmp;
+	struct wsm *wsm;
+	struct list_head *pos, *q;
+
+	/* Delete all session objects. Usually this should not be needed
+	 * as closeDevice()requires that all sessions have been closed before.*/
+	list_for_each_safe(pos, q, &dev->session_vector) {
+		tmp = list_entry(pos, struct session, list);
+		list_del(pos);
+		session_cleanup(tmp);
+	}
+
+	/* Free all allocated WSM descriptors */
+	list_for_each_safe(pos, q, &dev->wsm_l2_vector) {
+		wsm = list_entry(pos, struct wsm, list);
+		/* mcKMod_free(dev->instance, wsm->handle); */
+		list_del(pos);
+		kfree(wsm);
+	}
+	connection_cleanup(dev->connection);
+
+	mcore_device_close(dev);
+	kfree(dev);
+}
+
+
+/*----------------------------------------------------------------------------*/
+bool mcore_device_open(
+	struct mcore_device_t   *dev,
+	const char *deviceName
+) {
+	dev->instance = mobicore_open();
+	return (dev->instance != NULL);
+}
+
+
+/*----------------------------------------------------------------------------*/
+void mcore_device_close(
+	struct mcore_device_t *dev
+) {
+	mobicore_release(dev->instance);
+}
+
+
+/*----------------------------------------------------------------------------*/
+bool mcore_device_has_sessions(
+	struct mcore_device_t *dev
+) {
+	return !list_empty(&dev->session_vector);
+}
+
+
+/*----------------------------------------------------------------------------*/
+bool mcore_device_create_new_session(
+	struct mcore_device_t	*dev,
+	uint32_t		session_id,
+	struct connection	*connection
+) {
+	/* Check if session_id already exists */
+	if (mcore_device_resolve_session_id(dev, session_id)) {
+		MCDRV_DBG_ERROR(" session %u already exists", session_id);
+		return false;
+	}
+	struct session *session = session_create(session_id, dev->instance,
+						connection);
+	list_add_tail(&(session->list), &(dev->session_vector));
+	return true;
+}
+
+
+/*----------------------------------------------------------------------------*/
+bool mcore_device_remove_session(
+	struct mcore_device_t *dev,
+	uint32_t session_id
+) {
+	bool ret = false;
+	struct session *tmp;
+	struct list_head *pos, *q;
+
+	list_for_each_safe(pos, q, &dev->session_vector) {
+		tmp = list_entry(pos, struct session, list);
+		if (tmp->session_id == session_id) {
+			list_del(pos);
+			session_cleanup(tmp);
+			ret = true;
+			break;
+		}
+	}
+	return ret;
+}
+
+
+/*----------------------------------------------------------------------------*/
+struct session *mcore_device_resolve_session_id(
+	struct mcore_device_t *dev,
+	uint32_t session_id
+) {
+	struct session  *ret = NULL;
+	struct session *tmp;
+	struct list_head *pos;
+
+
+	/* Get session for session_id */
+	list_for_each(pos, &dev->session_vector) {
+		tmp = list_entry(pos, struct session, list);
+		if (tmp->session_id == session_id) {
+			ret = tmp;
+			break;
+		}
+	}
+	return ret;
+}
+
+
+/*----------------------------------------------------------------------------*/
+struct wsm *mcore_device_allocate_contiguous_wsm(
+	struct mcore_device_t *dev,
+	uint32_t len
+) {
+	struct wsm *wsm = NULL;
+	do {
+		if (len == 0)
+			break;
+
+		/* Allocate shared memory */
+		void	*virt_addr;
+		uint32_t  handle;
+		void	*phys_addr;
+		int ret = mobicore_allocate_wsm(dev->instance,
+						len,
+						&handle,
+						&virt_addr,
+						&phys_addr);
+		if (ret != 0)
+			break;
+
+		/* Register (vaddr,paddr) with device */
+		wsm = wsm_create(virt_addr, len, handle, phys_addr);
+
+		list_add_tail(&(wsm->list), &(dev->wsm_l2_vector));
+
+	} while (0);
+
+	/* Return pointer to the allocated memory */
+	return wsm;
+}
+
+
+/*----------------------------------------------------------------------------*/
+bool mcore_device_free_contiguous_wsm(
+	struct mcore_device_t  *dev,
+	struct wsm   *wsm
+) {
+	bool ret = false;
+	struct wsm *tmp;
+	struct list_head *pos;
+
+	list_for_each(pos, &dev->wsm_l2_vector) {
+		tmp = list_entry(pos, struct wsm, list);
+		if (tmp == wsm) {
+			ret = true;
+			break;
+		}
+	}
+
+	if (ret) {
+		MCDRV_DBG_VERBOSE("freeWsm virt_addr=0x%p, handle=%d",
+				wsm->virt_addr, wsm->handle);
+
+		/* ignore return code */
+		mobicore_free(dev->instance, wsm->handle);
+
+		list_del(pos);
+		kfree(wsm);
+	}
+	return ret;
+}
+
+
+/*----------------------------------------------------------------------------*/
+struct wsm *mcore_device_find_contiguous_wsm(
+	struct mcore_device_t *dev,
+	void   *virt_addr
+) {
+	struct wsm *wsm;
+	struct list_head *pos;
+
+	list_for_each(pos, &dev->wsm_l2_vector) {
+		wsm = list_entry(pos, struct wsm, list);
+		if (virt_addr == wsm->virt_addr)
+			return wsm;
+	}
+
+	return NULL;
+}
+
+/** @} */
diff --git a/drivers/gud/mobicore_kernelapi/device.h b/drivers/gud/mobicore_kernelapi/device.h
new file mode 100644
index 0000000..f40d993
--- /dev/null
+++ b/drivers/gud/mobicore_kernelapi/device.h
@@ -0,0 +1,139 @@
+/** @addtogroup MCD_IMPL_LIB
+ * @{
+ * @file
+ *
+ * Client library device management.
+ *
+ * Device and Trustlet Session management Functions.
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef DEVICE_H_
+#define DEVICE_H_
+
+#include <linux/list.h>
+
+#include "connection.h"
+#include "session.h"
+#include "wsm.h"
+
+
+struct mcore_device_t {
+	struct list_head session_vector; /**< MobiCore Trustlet session
+				associated with the device */
+	struct list_head	 wsm_l2_vector; /**< WSM L2 Table  */
+
+	uint32_t		device_id; /**< Device identifier */
+	struct connection	*connection; /**< The device connection */
+	struct mc_instance  *instance; /**< MobiCore Driver instance */
+
+	struct list_head list; /**< The list param for using the kernel lists*/
+};
+
+struct mcore_device_t *mcore_device_create(
+	uint32_t	  device_id,
+	struct connection  *connection
+);
+
+void mcore_device_cleanup(
+	struct mcore_device_t *dev
+);
+
+/**
+  * Open the device.
+  * @param deviceName Name of the kernel modules device file.
+  * @return true if the device has been opened successfully
+  */
+bool mcore_device_open(
+	struct mcore_device_t   *dev,
+	const char *deviceName
+);
+
+/**
+  * Closes the device.
+  */
+void mcore_device_close(
+	struct mcore_device_t *dev
+);
+
+/**
+  * Check if the device has open sessions.
+  * @return true if the device has one or more open sessions.
+  */
+bool mcore_device_has_sessions(
+	struct mcore_device_t *dev
+);
+
+/**
+  * Add a session to the device.
+  * @param session_id session ID
+  * @param connection session connection
+  */
+bool mcore_device_create_new_session(
+	struct mcore_device_t	  *dev,
+	uint32_t	session_id,
+	struct connection  *connection
+);
+
+/**
+  * Remove the specified session from the device.
+  * The session object will be destroyed and all resources associated with it
+  * will be freed.
+  *
+  * @param session_id Session of the session to remove.
+  * @return true if a session has been found and removed.
+  */
+bool mcore_device_remove_session(
+	struct mcore_device_t *dev,
+	uint32_t session_id
+);
+
+/**
+  * Get as session object for a given session ID.
+  * @param session_id Identified of a previously opened session.
+  * @return Session object if available or NULL if no session has been found.
+  */
+struct session *mcore_device_resolve_session_id(
+	struct mcore_device_t *dev,
+	uint32_t session_id
+);
+
+/**
+  * Allocate a block of contiguous WSM.
+  * @param len The virtual address to be registered.
+  * @return The virtual address of the allocated memory or NULL if no memory
+  * is available.
+  */
+struct wsm *mcore_device_allocate_contiguous_wsm(
+	struct mcore_device_t *dev,
+	uint32_t len
+);
+
+/**
+  * Unregister a vaddr from a device.
+  * @param vaddr The virtual address to be registered.
+  * @param paddr The physical address to be registered.
+  */
+bool mcore_device_free_contiguous_wsm(
+	struct mcore_device_t  *dev,
+	struct wsm *wsm
+);
+
+/**
+  * Get a WSM object for a given virtual address.
+  * @param vaddr The virtual address which has been allocate with mc_malloc_wsm()
+  * in advance.
+  * @return the WSM object or NULL if no address has been found.
+  */
+struct wsm *mcore_device_find_contiguous_wsm(
+	struct mcore_device_t *dev,
+	void   *virt_addr
+);
+
+#endif /* DEVICE_H_ */
+
+/** @} */
diff --git a/drivers/gud/mobicore_kernelapi/include/mcinq.h b/drivers/gud/mobicore_kernelapi/include/mcinq.h
new file mode 100644
index 0000000..3cb82be
--- /dev/null
+++ b/drivers/gud/mobicore_kernelapi/include/mcinq.h
@@ -0,0 +1,125 @@
+/** @addtogroup NQ
+ * @{
+ * Notifications inform the MobiCore runtime environment that information is
+ * pending in a WSM buffer.
+ * The Trustlet Connector (TLC) and the corresponding trustlet also utilize
+ * this buffer to notify each other about new data within the
+ * Trustlet Connector Interface (TCI).
+ *
+ * The buffer is set up as a queue, which means that more than one
+ * notification can be written to the buffer before the switch to the other
+ * world is performed. Each side therefore facilitates an incoming and an
+ * outgoing queue for communication with the other side.
+ *
+ * Notifications hold the session ID, which is used to reference the
+ * communication partner in the other world.
+ * So if, e.g., the TLC in the normal world wants to notify his trustlet
+ * about new data in the TLC buffer
+ *
+ * @file
+ * Notification queue declarations.
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *	notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *	notice, this list of conditions and the following disclaimer in the
+ *	documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *	products derived from this software without specific prior
+ *	written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef NQ_H_
+#define NQ_H_
+
+/** \name NQ Size Defines
+ * Minimum and maximum count of elements in the notification queue.
+ * @{ */
+#define MIN_NQ_ELEM 1   /**< Minimum notification queue elements. */
+#define MAX_NQ_ELEM 64 /**< Maximum notification queue elements. */
+/** @} */
+
+/** \name NQ Length Defines
+ * Minimum and maximum notification queue length.
+ * @{ */
+/**< Minimum notification length (in bytes). */
+#define MIN_NQ_LEN (MIN_NQ_ELEM * sizeof(notification))
+/**< Maximum notification length (in bytes). */
+#define MAX_NQ_LEN (MAX_NQ_ELEM * sizeof(notification))
+/** @} */
+
+/** \name Session ID Defines
+ * Standard Session IDs.
+ * @{ */
+/**< MCP session ID is used when directly communicating with the MobiCore
+ * (e.g. for starting and stopping of trustlets). */
+#define SID_MCP	   0
+/**< Invalid session id is returned in case of an error. */
+#define SID_INVALID   0xffffffff
+/** @} */
+
+/** Notification data structure. */
+struct notification {
+	uint32_t session_id; /**< Session ID. */
+	int32_t payload;	/**< Additional notification information. */
+};
+
+/** Notification payload codes.
+ * 0 indicated a plain simple notification,
+ * a positive value is a termination reason from the task,
+ * a negative value is a termination reason from MobiCore.
+ * Possible negative values are given below.
+ */
+enum notification_payload {
+	/**< task terminated, but exit code is invalid */
+	ERR_INVALID_EXIT_CODE   = -1,
+	/**< task terminated due to session end, no exit code available */
+	ERR_SESSION_CLOSE	   = -2,
+	/**< task terminated due to invalid operation */
+	ERR_INVALID_OPERATION   = -3,
+	/**< session ID is unknown */
+	ERR_INVALID_SID		 = -4,
+	/**<  session is not active */
+	ERR_SID_NOT_ACTIVE	  = -5
+};
+
+/** Declaration of the notification queue header.
+ * layout as specified in the data structure specification.
+ */
+struct notification_queue_header {
+	uint32_t write_cnt;  /**< Write counter. */
+	uint32_t read_cnt;   /**< Read counter. */
+	uint32_t queue_size; /**< Queue size. */
+};
+
+/** Queue struct which defines a queue object.
+ * The queue struct is accessed by the queue<operation> type of
+ * function. elementCnt must be a power of two and the power needs
+ * to be smaller than power of uint32_t (obviously 32).
+ */
+struct notification_queue {
+	/**< Queue header. */
+	struct notification_queue_header hdr;
+	/**< Notification elements. */
+	struct notification notification[MIN_NQ_ELEM];
+} ;
+
+#endif /** NQ_H_ */
+
+/** @} */
diff --git a/drivers/gud/mobicore_kernelapi/include/mcuuid.h b/drivers/gud/mobicore_kernelapi/include/mcuuid.h
new file mode 100644
index 0000000..b72acb8
--- /dev/null
+++ b/drivers/gud/mobicore_kernelapi/include/mcuuid.h
@@ -0,0 +1,74 @@
+/**
+ * @addtogroup MC_UUID mcUuid - Universally Unique Identifier.
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2011-2012 -->
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *	notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *	notice, this list of conditions and the following disclaimer in the
+ *	documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *	products derived from this software without specific prior
+ *	written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @ingroup  MC_DATA_TYPES
+ * @{
+ */
+
+#ifndef MC_UUID_H_
+#define MC_UUID_H_
+
+#define UUID_TYPE
+
+/** Universally Unique Identifier (UUID) according to ISO/IEC 11578. */
+struct mc_uuid_t {
+	uint8_t value[16]; /**< Value of the UUID. */
+};
+
+/** UUID value used as free marker in service provider containers. */
+#define MC_UUID_FREE_DEFINE \
+	{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+	  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }
+
+static const struct mc_uuid_t MC_UUID_FREE = {
+	MC_UUID_FREE_DEFINE
+};
+
+/** Reserved UUID. */
+#define MC_UUID_RESERVED_DEFINE \
+	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
+
+static const struct mc_uuid_t MC_UUID_RESERVED = {
+	MC_UUID_RESERVED_DEFINE
+};
+
+/** UUID for system applications. */
+#define MC_UUID_SYSTEM_DEFINE \
+	{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+	  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE }
+
+static const struct mc_uuid_t MC_UUID_SYSTEM = {
+	MC_UUID_SYSTEM_DEFINE
+};
+
+#endif /* MC_UUID_H_ */
+
+/** @} */
+
diff --git a/drivers/gud/mobicore_kernelapi/main.c b/drivers/gud/mobicore_kernelapi/main.c
new file mode 100644
index 0000000..62997f7
--- /dev/null
+++ b/drivers/gud/mobicore_kernelapi/main.c
@@ -0,0 +1,181 @@
+/**
+ * MobiCore KernelApi module
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/netlink.h>
+#include <linux/kthread.h>
+#include <net/sock.h>
+
+#include <linux/list.h>
+
+#include "connection.h"
+#include "common.h"
+
+#define MC_DAEMON_NETLINK  17
+
+struct mc_kernelapi_ctx {
+	struct sock *sk;
+	struct list_head peers;
+	atomic_t counter;
+};
+
+struct mc_kernelapi_ctx *mod_ctx; /* = NULL; */
+
+/*----------------------------------------------------------------------------*/
+/* get a unique ID */
+unsigned int mcapi_unique_id(
+	void
+)
+{
+	return (unsigned int)atomic_inc_return(
+		&(mod_ctx->counter));
+}
+
+
+/*----------------------------------------------------------------------------*/
+static struct connection *mcapi_find_connection(
+	uint32_t seq
+)
+{
+	struct connection *tmp;
+	struct list_head *pos;
+
+	/* Get session for session_id */
+	list_for_each(pos, &mod_ctx->peers) {
+		tmp = list_entry(pos, struct connection, list);
+		if (tmp->sequence_magic == seq)
+			return tmp;
+	}
+
+	return NULL;
+}
+
+/*----------------------------------------------------------------------------*/
+void mcapi_insert_connection(
+	struct connection *connection
+)
+{
+	list_add_tail(&(connection->list), &(mod_ctx->peers));
+	connection->socket_descriptor = mod_ctx->sk;
+}
+
+void mcapi_remove_connection(
+	uint32_t seq
+)
+{
+	struct connection *tmp;
+	struct list_head *pos, *q;
+
+	/* Delete all session objects. Usually this should not be needed as
+	   closeDevice() requires that all sessions have been closed before.*/
+	list_for_each_safe(pos, q, &mod_ctx->peers) {
+		tmp = list_entry(pos, struct connection, list);
+		if (tmp->sequence_magic == seq) {
+			list_del(pos);
+			break;
+		}
+	}
+}
+
+/*----------------------------------------------------------------------------*/
+static int mcapi_process(
+	struct sk_buff *skb,
+	struct nlmsghdr *nlh
+)
+{
+	struct connection *c;
+	int length;
+	int seq;
+	pid_t pid;
+	int ret;
+
+	pid = nlh->nlmsg_pid;
+	length = nlh->nlmsg_len;
+	seq = nlh->nlmsg_seq;
+	MCDRV_DBG_VERBOSE("nlmsg len %d type %d pid 0x%X seq %d\n",
+		   length, nlh->nlmsg_type, pid, seq);
+	do {
+		c = mcapi_find_connection(seq);
+		if (!c) {
+			MCDRV_ERROR("Invalid incomming connection - seq=%u!",
+				seq);
+			ret = -1;
+			break;
+		}
+
+		/* Pass the buffer to the appropriate connection */
+		connection_process(c, skb);
+
+		ret = 0;
+	} while (false);
+	return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+static void mcapi_callback(
+	struct sk_buff *skb
+)
+{
+	struct nlmsghdr *nlh = nlmsg_hdr(skb);
+	int len = skb->len;
+	int err = 0;
+
+	while (NLMSG_OK(nlh, len)) {
+		err = mcapi_process(skb, nlh);
+
+		/* if err or if this message says it wants a response */
+		if (err || (nlh->nlmsg_flags & NLM_F_ACK))
+			netlink_ack(skb, nlh, err);
+
+		nlh = NLMSG_NEXT(nlh, len);
+	}
+}
+
+/*----------------------------------------------------------------------------*/
+static int __init mcapi_init(void)
+{
+	printk(KERN_INFO "Mobicore API module initialized!\n");
+
+	mod_ctx = kzalloc(sizeof(struct mc_kernelapi_ctx), GFP_KERNEL);
+
+	/* start kernel thread */
+	mod_ctx->sk = netlink_kernel_create(&init_net, MC_DAEMON_NETLINK, 0,
+					mcapi_callback, NULL, THIS_MODULE);
+
+	if (!mod_ctx->sk) {
+		MCDRV_ERROR("register of recieve handler failed");
+		return -EFAULT;
+	}
+
+	INIT_LIST_HEAD(&mod_ctx->peers);
+	return 0;
+}
+
+static void __exit mcapi_exit(void)
+{
+	printk(KERN_INFO "Unloading Mobicore API module.\n");
+
+	if (mod_ctx->sk != NULL) {
+		netlink_kernel_release(mod_ctx->sk);
+		mod_ctx->sk = NULL;
+	}
+	kfree(mod_ctx);
+	mod_ctx = NULL;
+}
+
+module_init(mcapi_init);
+module_exit(mcapi_exit);
+
+MODULE_AUTHOR("Giesecke & Devrient GmbH");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MobiCore API driver");
diff --git a/drivers/gud/mobicore_kernelapi/public/mobicore_driver_api.h b/drivers/gud/mobicore_kernelapi/public/mobicore_driver_api.h
new file mode 100644
index 0000000..ccfb2e5
--- /dev/null
+++ b/drivers/gud/mobicore_kernelapi/public/mobicore_driver_api.h
@@ -0,0 +1,483 @@
+/**
+ * @defgroup MCD_API					MobiCore Driver API
+ * @addtogroup MCD_API
+ * @{
+ *
+ * @if DOXYGEN_MCDRV_API
+ *   @mainpage MobiCore Driver API.
+ * @endif
+ *
+ * MobiCore Driver API.
+ *
+ * The MobiCore (MC) Driver API provides access functions to the MobiCore
+ * runtime environment and the contained Trustlets.
+ *
+ * @image html DoxyOverviewDrvApi500x.png
+ * @image latex DoxyOverviewDrvApi500x.png "MobiCore Overview" width=12cm
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *	notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *	notice, this list of conditions and the following disclaimer in the
+ *	documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *	products derived from this software without specific prior
+ *	written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef MCDRIVER_H_
+#define MCDRIVER_H_
+
+#define __MC_CLIENT_LIB_API
+
+#include "mcuuid.h"
+
+/**
+ * Return values of MobiCore driver functions.
+ */
+enum mc_result {
+	/**< Function call succeeded. */
+	MC_DRV_OK		= 0,
+	/**< No notification available. */
+	MC_DRV_NO_NOTIFICATION	= 1,
+	/**< Error during notification on communication level. */
+	MC_DRV_ERR_NOTIFICATION	= 2,
+	/**< Function not implemented. */
+	MC_DRV_ERR_NOT_IMPLEMENTED = 3,
+	/**< No more resources available. */
+	MC_DRV_ERR_OUT_OF_RESOURCES = 4,
+	/**< Driver initialization failed. */
+	MC_DRV_ERR_INIT = 5,
+	/**< Unknown error. */
+	MC_DRV_ERR_UNKNOWN	= 6,
+	/**< The specified device is unknown. */
+	MC_DRV_ERR_UNKNOWN_DEVICE = 7,
+	/**< The specified session is unknown.*/
+	MC_DRV_ERR_UNKNOWN_SESSION = 8,
+	/**< The specified operation is not allowed. */
+	MC_DRV_ERR_INVALID_OPERATION = 9,
+	/**< The response header from the MC is invalid. */
+	MC_DRV_ERR_INVALID_RESPONSE = 10,
+	/**< Function call timed out. */
+	MC_DRV_ERR_TIMEOUT = 11,
+	/**< Can not allocate additional memory. */
+	MC_DRV_ERR_NO_FREE_MEMORY = 12,
+	/**< Free memory failed. */
+	MC_DRV_ERR_FREE_MEMORY_FAILED = 13,
+	/**< Still some open sessions pending. */
+	MC_DRV_ERR_SESSION_PENDING = 14,
+	/**< MC daemon not reachable */
+	MC_DRV_ERR_DAEMON_UNREACHABLE = 15,
+	/**< The device file of the kernel module could not be opened. */
+	MC_DRV_ERR_INVALID_DEVICE_FILE = 16,
+	/**< Invalid parameter. */
+	MC_DRV_ERR_INVALID_PARAMETER	= 17,
+	/**< Unspecified error from Kernel Module*/
+	MC_DRV_ERR_KERNEL_MODULE = 18,
+	/**< Error during mapping of additional bulk memory to session. */
+	MC_DRV_ERR_BULK_MAPPING = 19,
+	/**< Error during unmapping of additional bulk memory to session. */
+	MC_DRV_ERR_BULK_UNMAPPING = 20,
+	/**< Notification received, exit code available. */
+	MC_DRV_INFO_NOTIFICATION = 21,
+	/**< Set up of NWd connection failed. */
+	MC_DRV_ERR_NQ_FAILED = 22
+};
+
+
+/**
+ * Driver control command.
+ */
+enum mc_driver_ctrl {
+	MC_CTRL_GET_VERSION = 1 /**< Return the driver version */
+};
+
+
+/** Structure of Session Handle, includes the Session ID and the Device ID the
+ * Session belongs to.
+ * The session handle will be used for session-based MobiCore communication.
+ * It will be passed to calls which address a communication end point in the
+ * MobiCore environment.
+ */
+struct mc_session_handle {
+	uint32_t session_id; /**< MobiCore session ID */
+	uint32_t device_id; /**< Device ID the session belongs to */
+};
+
+/** Information structure about additional mapped Bulk buffer between the
+ * Trustlet Connector (Nwd) and the Trustlet (Swd). This structure is
+ * initialized from a Trustlet Connector by calling mc_map().
+ * In order to use the memory within a Trustlet the Trustlet Connector has to
+ * inform the Trustlet with the content of this structure via the TCI.
+ */
+struct mc_bulk_map {
+	/**< The virtual address of the Bulk buffer regarding the address space
+	 * of the Trustlet, already includes a possible offset! */
+	void *secure_virt_addr;
+	uint32_t secure_virt_len; /**< Length of the mapped Bulk buffer */
+};
+
+
+/**< The default device ID */
+#define MC_DEVICE_ID_DEFAULT	0
+/**< Wait infinite for a response of the MC. */
+#define MC_INFINITE_TIMEOUT	((int32_t)(-1))
+/**< Do not wait for a response of the MC. */
+#define MC_NO_TIMEOUT		0
+/**< TCI/DCI must not exceed 1MiB */
+#define MC_MAX_TCI_LEN		0x100000
+
+
+
+/** Open a new connection to a MobiCore device.
+ *
+ * mc_open_device() initializes all device specific resources required to
+ * communicate with an MobiCore instance located on the specified device in the
+ * system. If the device does not exist the function will return
+ * MC_DRV_ERR_UNKNOWN_DEVICE.
+ *
+ * @param [in] device_id Identifier for the MobiCore device to be used.
+ * MC_DEVICE_ID_DEFAULT refers to the default device.
+ *
+ * @return MC_DRV_OK if operation has been successfully completed.
+ * @return MC_DRV_ERR_INVALID_OPERATION if device already opened.
+ * @return MC_DRV_ERR_DAEMON_UNREACHABLE when problems with daemon occur.
+ * @return MC_DRV_ERR_UNKNOWN_DEVICE when device_id is unknown.
+ * @return MC_DRV_ERR_INVALID_DEVICE_FILE if kernel module under
+ * /dev/mobicore cannot be opened
+ *
+ * Uses a Mutex.
+ */
+__MC_CLIENT_LIB_API enum mc_result mc_open_device(
+	uint32_t device_id
+);
+
+/** Close the connection to a MobiCore device.
+ * When closing a device, active sessions have to be closed beforehand.
+ * Resources associated with the device will be released.
+ * The device may be opened again after it has been closed.
+ *
+ * @param [in] device_id Identifier for the MobiCore device.
+ * MC_DEVICE_ID_DEFAULT refers to the default device.
+ *
+ * @return MC_DRV_OK if operation has been successfully completed.
+ * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id is invalid.
+ * @return MC_DRV_ERR_SESSION_PENDING when a session is still open.
+ * @return MC_DRV_ERR_DAEMON_UNREACHABLE when problems with daemon occur.
+ *
+ * Uses a Mutex.
+ */
+__MC_CLIENT_LIB_API enum mc_result mc_close_device(
+	uint32_t device_id
+);
+
+/** Open a new session to a Trustlet. The trustlet with the given UUID has
+ * to be available in the flash filesystem.
+ *
+ * Write MCP open message to buffer and notify MobiCore about the availability
+ * of a new command.
+ * Waits till the MobiCore responses with the new session ID (stored in the MCP
+ * buffer).
+ *
+ * @param [in,out] session On success, the session data will be returned.
+ * Note that session.device_id has to be the device id of an opened device.
+ * @param [in] uuid UUID of the Trustlet to be opened.
+ * @param [in] tci TCI buffer for communicating with the trustlet.
+ * @param [in] tci_len Length of the TCI buffer. Maximum allowed value
+ * is MC_MAX_TCI_LEN.
+ *
+ * @return MC_DRV_OK if operation has been successfully completed.
+ * @return MC_DRV_INVALID_PARAMETER if session parameter is invalid.
+ * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id is invalid.
+ * @return MC_DRV_ERR_DAEMON_UNREACHABLE when problems with daemon socket occur.
+ * @return MC_DRV_ERR_UNKNOWN_DEVICE when daemon returns an error.
+ *
+ * Uses a Mutex.
+ */
+__MC_CLIENT_LIB_API enum mc_result mc_open_session(
+	struct mc_session_handle  *session,
+	const struct mc_uuid_t *uuid,
+	uint8_t *tci,
+	uint32_t tci_len
+);
+
+/** Close a Trustlet session.
+ *
+ * Closes the specified MobiCore session. The call will block until the
+ * session has been closed.
+ *
+ * @pre Device device_id has to be opened in advance.
+ *
+ * @param [in] session Session to be closed.
+ *
+ * @return MC_DRV_OK if operation has been successfully completed.
+ * @return MC_DRV_INVALID_PARAMETER if session parameter is invalid.
+ * @return MC_DRV_ERR_UNKNOWN_SESSION when session id is invalid.
+ * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id of session is invalid.
+ * @return MC_DRV_ERR_DAEMON_UNREACHABLE when problems with daemon occur.
+ * @return MC_DRV_ERR_INVALID_DEVICE_FILE when daemon cannot open trustlet file.
+ *
+ * Uses a Mutex.
+ */
+__MC_CLIENT_LIB_API enum mc_result mc_close_session(
+	struct mc_session_handle *session
+);
+
+/** Notify a session.
+ * Notifies the session end point about available message data.
+ * If the session parameter is correct, notify will always succeed.
+ * Corresponding errors can only be received by mc_wait_notification().
+ * @pre A session has to be opened in advance.
+ *
+ * @param session The session to be notified.
+ *
+ * @return MC_DRV_OK if operation has been successfully completed.
+ * @return MC_DRV_INVALID_PARAMETER if session parameter is invalid.
+ * @return MC_DRV_ERR_UNKNOWN_SESSION when session id is invalid.
+ * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id of session is invalid.
+ */
+__MC_CLIENT_LIB_API enum mc_result mc_notify(
+	struct mc_session_handle *session
+);
+
+/** Wait for a notification.
+ *
+ * Wait for a notification issued by the MobiCore for a specific session.
+ * The timeout parameter specifies the number of milliseconds the call will wait
+ * for a notification.
+ * If the caller passes 0 as timeout value the call will immediately return.
+ * If timeout value is below 0 the call will block until a notification for the
+ session has been received.
+ *
+ * @attention if timeout is below 0, call will block:
+ * Caller has to trust the other side to send a notification to wake him up
+ * again.
+ *
+ * @param [in] session The session the notification should correspond to.
+ * @param [in] timeout Time in milliseconds to wait
+ * (MC_NO_TIMEOUT : direct return, > 0 : milliseconds,
+ * MC_INFINITE_TIMEOUT : wait infinitely)
+ *
+ * @return MC_DRV_OK if notification is available.
+ * @return MC_DRV_ERR_TIMEOUT if no notification arrived in time.
+ * @return MC_DRV_INFO_NOTIFICATION if a problem with the session was
+ * encountered. Get more details with mc_get_session_error_code().
+ * @return MC_DRV_ERR_NOTIFICATION if a problem with the socket occurred.
+ * @return MC_DRV_INVALID_PARAMETER if a parameter is invalid.
+ * @return MC_DRV_ERR_UNKNOWN_SESSION when session id is invalid.
+ * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id of session is invalid.
+ */
+__MC_CLIENT_LIB_API enum mc_result mc_wait_notification(
+	struct mc_session_handle  *session,
+	int32_t			timeout
+);
+
+/**
+ * Allocate a block of world shared memory (WSM).
+ * The MC driver allocates a contiguous block of memory which can be used as
+ * WSM.
+ * This implicates that the allocated memory is aligned according to the
+ * alignment parameter.
+ * Always returns a buffer of size WSM_SIZE aligned to 4K.
+ *
+ * @param [in]  device_id The ID of an opened device to retrieve the WSM from.
+ * @param [in]  align The alignment (number of pages) of the memory block
+ * (e.g. 0x00000001 for 4kb).
+ * @param [in]  len	Length of the block in bytes.
+ * @param [out] wsm Virtual address of the world shared memory block.
+ * @param [in]  wsm_flags Platform specific flags describing the memory to
+ * be allocated.
+ *
+ * @attention: align and wsm_flags are currently ignored
+ *
+ * @return MC_DRV_OK if operation has been successfully completed.
+ * @return MC_DRV_INVALID_PARAMETER if a parameter is invalid.
+ * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id is invalid.
+ * @return MC_DRV_ERR_NO_FREE_MEMORY if no more contiguous memory is available
+ * in this size or for this process.
+ *
+ * Uses a Mutex.
+ */
+__MC_CLIENT_LIB_API enum mc_result mc_malloc_wsm(
+	uint32_t  device_id,
+	uint32_t  align,
+	uint32_t  len,
+	uint8_t   **wsm,
+	uint32_t  wsm_flags
+);
+
+/**
+ * Free a block of world shared memory (WSM).
+ * The MC driver will free a block of world shared memory (WSM) previously
+ * allocated with mc_malloc_wsm(). The caller has to assure that the address
+ * handed over to the driver is a valid WSM address.
+ *
+ * @param [in] device_id The ID to which the given address belongs.
+ * @param [in] wsm Address of WSM block to be freed.
+ *
+ * @return MC_DRV_OK if operation has been successfully completed.
+ * @return MC_DRV_INVALID_PARAMETER if a parameter is invalid.
+ * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id is invalid.
+ * @return MC_DRV_ERR_FREE_MEMORY_FAILED on failures.
+ *
+ * Uses a Mutex.
+ */
+__MC_CLIENT_LIB_API enum mc_result mc_free_wsm(
+	uint32_t  device_id,
+	uint8_t   *wsm
+);
+
+/**
+ * Map additional bulk buffer between a Trustlet Connector (TLC) and
+ * the Trustlet (TL) for a session.
+ * Memory allocated in user space of the TLC can be mapped as additional
+ * communication channel (besides TCI) to the Trustlet. Limitation of the
+ * Trustlet memory structure apply: only 6 chunks can be mapped with a maximum
+ * chunk size of 1 MiB each.
+ *
+ * @attention It is up to the application layer (TLC) to inform the Trustlet
+ * about the additional mapped bulk memory.
+ *
+ * @param [in] session Session handle with information of the device_id and
+ * the session_id. The
+ * given buffer is mapped to the session specified in the sessionHandle.
+ * @param [in] buf Virtual address of a memory portion (relative to TLC)
+ * to be shared with the Trustlet, already includes a possible offset!
+ * @param [in] len length of buffer block in bytes.
+ * @param [out] map_info Information structure about the mapped Bulk buffer
+ * between the TLC (Nwd) and
+ * the TL (Swd).
+ *
+ * @return MC_DRV_OK if operation has been successfully completed.
+ * @return MC_DRV_INVALID_PARAMETER if a parameter is invalid.
+ * @return MC_DRV_ERR_UNKNOWN_SESSION when session id is invalid.
+ * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id of session is invalid.
+ * @return MC_DRV_ERR_DAEMON_UNREACHABLE when problems with daemon occur.
+ * @return MC_DRV_ERR_BULK_MAPPING when buf is already uses as bulk buffer or
+ * when registering the buffer failed.
+ *
+ * Uses a Mutex.
+ */
+__MC_CLIENT_LIB_API enum mc_result mc_map(
+	struct mc_session_handle	*session,
+	void				*buf,
+	uint32_t			len,
+	struct mc_bulk_map		*map_info
+);
+
+/**
+ * Remove additional mapped bulk buffer between Trustlet Connector (TLC)
+ * and the Trustlet (TL) for a session.
+ *
+ * @attention The bulk buffer will immediately be unmapped from the session
+ * context.
+ * @attention The application layer (TLC) must inform the TL about unmapping
+ * of the additional bulk memory before calling mc_unmap!
+ *
+ * @param [in] session Session handle with information of the device_id and
+ * the session_id. The given buffer is unmapped from the session specified
+ * in the sessionHandle.
+ * @param [in] buf Virtual address of a memory portion (relative to TLC)
+ * shared with the TL, already includes a possible offset!
+ * @param [in] map_info Information structure about the mapped Bulk buffer
+ * between the TLC (Nwd) and
+ * the TL (Swd).
+ * @attention The clientlib currently ignores the len field in map_info.
+ *
+ * @return MC_DRV_OK if operation has been successfully completed.
+ * @return MC_DRV_INVALID_PARAMETER if a parameter is invalid.
+ * @return MC_DRV_ERR_UNKNOWN_SESSION when session id is invalid.
+ * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id of session is invalid.
+ * @return MC_DRV_ERR_DAEMON_UNREACHABLE when problems with daemon occur.
+ * @return MC_DRV_ERR_BULK_UNMAPPING when buf was not registered earlier
+ * or when unregistering failed.
+ *
+ * Uses a Mutex.
+ */
+__MC_CLIENT_LIB_API enum mc_result mc_unmap(
+	struct mc_session_handle	*session,
+	void				*buf,
+	struct mc_bulk_map		*map_info
+);
+
+
+/**
+ * @attention: Not implemented.
+ * Execute driver specific command.
+ * mc_driver_ctrl() can be used to execute driver specific commands.
+ * Besides the control command MC_CTRL_GET_VERSION commands are implementation
+ * specific.
+ * Please refer to the corresponding specification of the driver manufacturer.
+ *
+ * @param [in] param Command ID of the command to be executed.
+ * @param [in, out] data  Command data and response depending on command.
+ * @param [in] len Length of the data block.
+ *
+ * @return MC_DRV_ERR_NOT_IMPLEMENTED.
+ */
+__MC_CLIENT_LIB_API enum mc_result mc_driver_ctrl(
+	enum mc_driver_ctrl  param,
+	uint8_t		 *data,
+	uint32_t	len
+);
+
+/**
+ * @attention: Not implemented.
+ * Execute application management command.
+ * mc_manage() shall be used to exchange application management commands with
+ * the MobiCore.
+ * The MobiCore Application Management Protocol is described in [MCAMP].
+ *
+ * @param [in] device_id Identifier for the MobiCore device to be used.
+ * NULL refers to the default device.
+ * @param [in, out] data  Command data/response data depending on command.
+ * @param [in] len Length of the data block.
+ *
+ * @return MC_DRV_ERR_NOT_IMPLEMENTED.
+ */
+__MC_CLIENT_LIB_API enum mc_result mc_manage(
+	uint32_t  device_id,
+	uint8_t   *data,
+	uint32_t  len
+);
+
+/**
+ * Get additional error information of the last error that occured on a session.
+ * After the request the stored error code will be deleted.
+ *
+ * @param [in] session Session handle with information of the device_id and
+ * the session_id.
+ * @param [out] last_error >0 Trustlet has terminated itself with this value,
+ * <0 Trustlet is dead because of an error within the MobiCore
+ * (e.g. Kernel exception).
+ * See also MCI definition.
+ *
+ * @return MC_DRV_OK if operation has been successfully completed.
+ * @return MC_DRV_INVALID_PARAMETER if a parameter is invalid.
+ * @return MC_DRV_ERR_UNKNOWN_SESSION when session id is invalid.
+ * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id of session is invalid.
+ */
+__MC_CLIENT_LIB_API enum mc_result mc_get_session_error_code(
+	struct mc_session_handle  *session,
+	int32_t			*last_error
+);
+
+#endif /** MCDRIVER_H_ */
+
+/** @} */
diff --git a/drivers/gud/mobicore_kernelapi/public/mobicore_driver_cmd.h b/drivers/gud/mobicore_kernelapi/public/mobicore_driver_cmd.h
new file mode 100644
index 0000000..9ff7989
--- /dev/null
+++ b/drivers/gud/mobicore_kernelapi/public/mobicore_driver_cmd.h
@@ -0,0 +1,289 @@
+/** @addtogroup MCD_MCDIMPL_DAEMON
+ * @{
+ * @file
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *	notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *	notice, this list of conditions and the following disclaimer in the
+ *	documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *	products derived from this software without specific prior
+ *	written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef MCDAEMON_H_
+#define MCDAEMON_H_
+
+
+
+
+#include "mcuuid.h"
+
+enum mc_drv_cmd_t {
+	MC_DRV_CMD_PING			= 0,
+	MC_DRV_CMD_GET_INFO		= 1,
+	MC_DRV_CMD_OPEN_DEVICE		= 2,
+	MC_DRV_CMD_CLOSE_DEVICE		= 3,
+	MC_DRV_CMD_NQ_CONNECT		= 4,
+	MC_DRV_CMD_OPEN_SESSION		= 5,
+	MC_DRV_CMD_CLOSE_SESSION	= 6,
+	MC_DRV_CMD_NOTIFY		= 7,
+	MC_DRV_CMD_MAP_BULK_BUF		= 8,
+	MC_DRV_CMD_UNMAP_BULK_BUF	= 9
+};
+
+
+enum mc_drv_rsp_t {
+	MC_DRV_RSP_OK				= 0,
+	MC_DRV_RSP_FAILED			= 1,
+	MC_DRV_RSP_DEVICE_NOT_OPENED		= 2,
+	MC_DRV_RSP_DEVICE_ALREADY_OPENED	= 3,
+	MC_DRV_RSP_COMMAND_NOT_ALLOWED		= 4,
+	MC_DRV_INVALID_DEVICE_NAME		= 5,
+	MC_DRV_RSP_MAP_BULK_ERRO		= 6,
+	MC_DRV_RSP_TRUSTLET_NOT_FOUND		= 7,
+	MC_DRV_RSP_PAYLOAD_LENGTH_ERROR		= 8,
+};
+
+
+struct mc_drv_command_header_t {
+	uint32_t  command_id;
+};
+
+struct mc_drv_response_header_t {
+	uint32_t  response_id;
+};
+
+#define MC_DEVICE_ID_DEFAULT	0 /**< The default device ID */
+
+
+/*****************************************************************************/
+struct mc_drv_cmd_open_device_payload_t {
+	uint32_t  device_id;
+};
+
+struct mc_drv_cmd_open_device_t {
+	struct mc_drv_command_header_t header;
+	struct mc_drv_cmd_open_device_payload_t payload;
+};
+
+
+struct mc_drv_rsp_open_device_payload_t {
+	/* empty */
+};
+
+struct mc_drv_rsp_open_device_t {
+	struct mc_drv_response_header_t header;
+	struct mc_drv_rsp_open_device_payload_t payload;
+};
+
+
+/*****************************************************************************/
+struct mc_drv_cmd_close_device_t {
+	struct mc_drv_command_header_t header;
+	/* no payload here because close has none.
+	   If we use an empty struct, C++ will count it as 4 bytes.
+	   This will write too much into the socket at write(cmd,sizeof(cmd)) */
+};
+
+
+struct mc_drv_rsp_close_device_payload_t {
+	/* empty */
+};
+
+struct mc_drv_rsp_close_device_t {
+	struct mc_drv_response_header_t header;
+	struct mc_drv_rsp_close_device_payload_t payload;
+};
+
+
+/*****************************************************************************/
+struct mc_drv_cmd_open_session_payload_t {
+	uint32_t device_id;
+	struct mc_uuid_t uuid;
+	uint32_t tci;
+	uint32_t len;
+};
+
+struct mc_drv_cmd_open_session_t {
+	struct mc_drv_command_header_t header;
+	struct mc_drv_cmd_open_session_payload_t payload;
+};
+
+
+struct mc_drv_rsp_open_session_payload_t {
+	uint32_t device_id;
+	uint32_t session_id;
+	uint32_t device_session_id;
+	uint32_t mc_result;
+	uint32_t session_magic;
+};
+
+struct mc_drv_rsp_open_session_t {
+	struct mc_drv_response_header_t header;
+	struct mc_drv_rsp_open_session_payload_t  payload;
+};
+
+
+/*****************************************************************************/
+struct mc_drv_cmd_close_session_payload_t {
+	uint32_t  session_id;
+};
+
+struct mc_drv_cmd_close_session_t {
+	struct mc_drv_command_header_t header;
+	struct mc_drv_cmd_close_session_payload_t payload;
+};
+
+
+struct mc_drv_rsp_close_session_payload_t {
+	/* empty */
+};
+
+struct mc_drv_rsp_close_session_t {
+	struct mc_drv_response_header_t header;
+	struct mc_drv_rsp_close_session_payload_t payload;
+};
+
+
+/*****************************************************************************/
+struct mc_drv_cmd_notify_payload_t {
+	uint32_t session_id;
+};
+
+struct mc_drv_cmd_notify_t {
+	struct mc_drv_command_header_t header;
+	struct mc_drv_cmd_notify_payload_t payload;
+};
+
+
+struct mc_drv_rsp_notify_payload_t {
+	/* empty */
+};
+
+struct mc_drv_rsp_notify_t {
+	struct mc_drv_response_header_t header;
+	struct mc_drv_rsp_notify_payload_t  payload;
+};
+
+
+/*****************************************************************************/
+struct mc_drv_cmd_map_bulk_mem_payload_t {
+	uint32_t session_id;
+	uint32_t phys_addr_l2;
+	uint32_t offset_payload;
+	uint32_t len_bulk_mem;
+};
+
+struct mc_drv_cmd_map_bulk_mem_t {
+	struct mc_drv_command_header_t header;
+	struct mc_drv_cmd_map_bulk_mem_payload_t  payload;
+};
+
+
+struct mc_drv_rsp_map_bulk_mem_payload_t {
+	uint32_t session_id;
+	uint32_t secure_virtual_adr;
+	uint32_t mc_result;
+};
+
+struct mc_drv_rsp_map_bulk_mem_t {
+	struct mc_drv_response_header_t header;
+	struct mc_drv_rsp_map_bulk_mem_payload_t  payload;
+};
+
+
+/*****************************************************************************/
+struct mc_drv_cmd_unmap_bulk_mem_payload_t {
+	uint32_t session_id;
+	uint32_t secure_virtual_adr;
+	uint32_t len_bulk_mem;
+};
+
+struct mc_drv_cmd_unmap_bulk_mem_t {
+	struct mc_drv_command_header_t header;
+	struct mc_drv_cmd_unmap_bulk_mem_payload_t payload;
+};
+
+
+struct mc_drv_rsp_unmap_bulk_mem_payload_t {
+	uint32_t response_id;
+	uint32_t session_id;
+	uint32_t mc_result;
+};
+
+struct mc_drv_rsp_unmap_bulk_mem_t {
+	struct mc_drv_response_header_t header;
+	struct mc_drv_rsp_unmap_bulk_mem_payload_t payload;
+};
+
+
+/*****************************************************************************/
+struct mc_drv_cmd_nqconnect_payload_t {
+	uint32_t device_id;
+	uint32_t session_id;
+	uint32_t device_session_id;
+	uint32_t session_magic; /* Random data */
+};
+
+struct mc_drv_cmd_nqconnect_t {
+	struct mc_drv_command_header_t header;
+	struct mc_drv_cmd_nqconnect_payload_t  payload;
+};
+
+
+struct mc_drv_rsp_nqconnect_payload_t {
+	/* empty; */
+};
+
+struct mc_drv_rsp_nqconnect_t {
+	struct mc_drv_response_header_t header;
+	struct mc_drv_rsp_nqconnect_payload_t payload;
+};
+
+
+/*****************************************************************************/
+union mc_drv_command_t {
+	struct mc_drv_command_header_t		header;
+	struct mc_drv_cmd_open_device_t		mc_drv_cmd_open_device;
+	struct mc_drv_cmd_close_device_t	mc_drv_cmd_close_device;
+	struct mc_drv_cmd_open_session_t	mc_drv_cmd_open_session;
+	struct mc_drv_cmd_close_session_t	mc_drv_cmd_close_session;
+	struct mc_drv_cmd_nqconnect_t		mc_drv_cmd_nqconnect;
+	struct mc_drv_cmd_notify_t		mc_drv_cmd_notify;
+	struct mc_drv_cmd_map_bulk_mem_t	mc_drv_cmd_map_bulk_mem;
+	struct mc_drv_cmd_unmap_bulk_mem_t	mc_drv_cmd_unmap_bulk_mem;
+};
+
+union mc_drv_response_t {
+	struct mc_drv_response_header_t		header;
+	struct mc_drv_rsp_open_device_t		mc_drv_rsp_open_device;
+	struct mc_drv_rsp_close_device_t	mc_drv_rsp_close_device;
+	struct mc_drv_rsp_open_session_t	mc_drv_rsp_open_session;
+	struct mc_drv_rsp_close_session_t	mc_drv_rsp_close_session;
+	struct mc_drv_rsp_nqconnect_t		mc_drv_rsp_nqconnect;
+	struct mc_drv_rsp_notify_t		mc_drv_rsp_notify;
+	struct mc_drv_rsp_map_bulk_mem_t	mc_drv_rsp_map_bulk_mem;
+	struct mc_drv_rsp_unmap_bulk_mem_t	mc_drv_rsp_unmap_bulk_mem;
+};
+
+#endif /* MCDAEMON_H_ */
+
+/** @} */
diff --git a/drivers/gud/mobicore_kernelapi/session.c b/drivers/gud/mobicore_kernelapi/session.c
new file mode 100644
index 0000000..e62b4b3
--- /dev/null
+++ b/drivers/gud/mobicore_kernelapi/session.c
@@ -0,0 +1,202 @@
+/** @addtogroup MCD_IMPL_LIB
+ * @{
+ * @file
+ * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/types.h>
+#include <linux/slab.h>
+#include "mc_kernel_api.h"
+#include "public/mobicore_driver_api.h"
+
+#include "session.h"
+
+/*****************************************************************************/
+struct bulk_buffer_descriptor *bulk_buffer_descriptor_create(
+	void		*virt_addr,
+	uint32_t	len,
+	uint32_t	handle,
+	void		*phys_addr_wsm_l2
+) {
+	struct bulk_buffer_descriptor *desc =
+		kzalloc(sizeof(struct bulk_buffer_descriptor), GFP_KERNEL);
+	desc->virt_addr = virt_addr;
+	desc->len = len;
+	desc->handle = handle;
+	desc->phys_addr_wsm_l2 = phys_addr_wsm_l2;
+	return desc;
+}
+
+/*****************************************************************************/
+struct session *session_create(
+	uint32_t	session_id,
+	void		*instance,
+	struct connection *connection
+) {
+	struct session *session =
+			kzalloc(sizeof(struct session), GFP_KERNEL);
+	session->session_id = session_id;
+	session->instance = instance;
+	session->notification_connection = connection;
+
+	session->session_info.last_error = SESSION_ERR_NO;
+	session->session_info.state = SESSION_STATE_INITIAL;
+
+	INIT_LIST_HEAD(&(session->bulk_buffer_descriptors));
+	return session;
+}
+
+
+/*****************************************************************************/
+void session_cleanup(
+	struct session *session
+) {
+	struct bulk_buffer_descriptor  *bulk_buf_descr;
+	struct list_head *pos, *q;
+
+	/* Unmap still mapped buffers */
+	list_for_each_safe(pos, q, &session->bulk_buffer_descriptors) {
+		bulk_buf_descr =
+			list_entry(pos, struct bulk_buffer_descriptor, list);
+
+		MCDRV_DBG_VERBOSE("Physical Address of L2 Table = 0x%X, "
+				"handle= %d",
+				(unsigned int)bulk_buf_descr->phys_addr_wsm_l2,
+				bulk_buf_descr->handle);
+
+		/* ignore any error, as we cannot do anything in this case. */
+		int ret = mobicore_unmap_vmem(session->instance,
+						bulk_buf_descr->handle);
+		if (ret != 0)
+			MCDRV_DBG_ERROR("mobicore_unmap_vmem failed: %d", ret);
+
+		list_del(pos);
+		kfree(bulk_buf_descr);
+	}
+
+	/* Finally delete notification connection */
+	connection_cleanup(session->notification_connection);
+	kfree(session);
+}
+
+
+/*****************************************************************************/
+void session_set_error_info(
+	struct session *session,
+	int32_t   err
+) {
+	session->session_info.last_error = err;
+}
+
+
+/*****************************************************************************/
+int32_t session_get_last_err(
+	struct session *session
+) {
+	return session->session_info.last_error;
+}
+
+
+/*****************************************************************************/
+struct bulk_buffer_descriptor *session_add_bulk_buf(
+	struct session	*session,
+	void		*buf,
+	uint32_t	len
+) {
+	struct bulk_buffer_descriptor *bulk_buf_descr = NULL;
+	struct bulk_buffer_descriptor  *tmp;
+	struct list_head *pos;
+
+	/* Search bulk buffer descriptors for existing vAddr
+	   At the moment a virtual address can only be added one time */
+	list_for_each(pos, &session->bulk_buffer_descriptors) {
+		tmp = list_entry(pos, struct bulk_buffer_descriptor, list);
+		if (tmp->virt_addr == buf)
+			return NULL;
+	}
+
+	do {
+		/* Prepare the interface structure for memory registration in
+		   Kernel Module */
+		void	*l2_table_phys;
+		uint32_t  handle;
+
+		int ret = mobicore_map_vmem(session->instance,
+					buf,
+					len,
+					&handle,
+					&l2_table_phys);
+
+		if (ret != 0) {
+			MCDRV_DBG_ERROR("mobicore_map_vmem failed, ret=%d",
+					ret);
+			break;
+		}
+
+		MCDRV_DBG_VERBOSE("Physical Address of L2 Table = 0x%X, "
+				"handle=%d",
+				(unsigned int)l2_table_phys,
+				handle);
+
+		/* Create new descriptor */
+		bulk_buf_descr = bulk_buffer_descriptor_create(
+							buf,
+							len,
+							handle,
+							l2_table_phys);
+
+		/* Add to vector of descriptors */
+		list_add_tail(&(bulk_buf_descr->list),
+			&(session->bulk_buffer_descriptors));
+	} while (0);
+
+	return bulk_buf_descr;
+}
+
+
+/*****************************************************************************/
+bool session_remove_bulk_buf(
+	struct session *session,
+	void	*virt_addr
+) {
+	bool ret = true;
+	struct bulk_buffer_descriptor  *bulk_buf_descr = NULL;
+	struct bulk_buffer_descriptor  *tmp;
+	struct list_head *pos, *q;
+
+	MCDRV_DBG_VERBOSE("Virtual Address = 0x%X", (unsigned int) virt_addr);
+
+	/* Search and remove bulk buffer descriptor */
+	list_for_each_safe(pos, q, &session->bulk_buffer_descriptors) {
+		tmp = list_entry(pos, struct bulk_buffer_descriptor, list);
+		if (tmp->virt_addr == virt_addr) {
+			bulk_buf_descr = tmp;
+			list_del(pos);
+			break;
+		}
+	}
+
+	if (bulk_buf_descr == NULL) {
+		MCDRV_DBG_ERROR("Virtual Address not found");
+		ret = false;
+	} else {
+		MCDRV_DBG_VERBOSE("WsmL2 phys=0x%X, handle=%d",
+			(unsigned int)bulk_buf_descr->phys_addr_wsm_l2,
+			bulk_buf_descr->handle);
+
+		/* ignore any error, as we cannot do anything */
+		int ret = mobicore_unmap_vmem(session->instance,
+						bulk_buf_descr->handle);
+		if (ret != 0)
+			MCDRV_DBG_ERROR("mobicore_unmap_vmem failed: %d", ret);
+
+		kfree(bulk_buf_descr);
+	}
+
+	return ret;
+}
+
+/** @} */
diff --git a/drivers/gud/mobicore_kernelapi/session.h b/drivers/gud/mobicore_kernelapi/session.h
new file mode 100644
index 0000000..9a53740
--- /dev/null
+++ b/drivers/gud/mobicore_kernelapi/session.h
@@ -0,0 +1,136 @@
+/** @addtogroup MCD_IMPL_LIB
+ * @{
+ * @file
+ * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef SESSION_H_
+#define SESSION_H_
+
+#include "common.h"
+
+#include <linux/list.h>
+#include "connection.h"
+
+
+struct bulk_buffer_descriptor {
+	void		*virt_addr;/**< The virtual address of the Bulk buffer*/
+	uint32_t	len;	  /**< Length of the Bulk buffer*/
+	uint32_t	handle;
+	void		*phys_addr_wsm_l2; /**< The physical address of the
+				L2 table of the Bulk buffer*/
+	struct list_head list; /**< The list param for using the kernel lists*/
+};
+
+struct bulk_buffer_descriptor *bulk_buffer_descriptor_create(
+	void	*virt_addr,
+	uint32_t  len,
+	uint32_t  handle,
+	void	*phys_addr_wsm_l2
+);
+
+/** Session states.
+ * At the moment not used !!.
+ */
+enum session_state {
+	SESSION_STATE_INITIAL,
+	SESSION_STATE_OPEN,
+	SESSION_STATE_TRUSTLET_DEAD
+};
+
+#define SESSION_ERR_NO	  0 /**< No session error */
+
+/** Session information structure.
+ * The information structure is used to hold the state of the session, which
+ * will limit further actions for the session.
+ * Also the last error code will be stored till it's read.
+ */
+struct session_information {
+	enum session_state state;	   /**< Session state */
+	int32_t		last_error;	 /**< Last error of session */
+};
+
+
+struct session {
+	struct mc_instance		*instance;
+	/**< Descriptors of additional bulk buffer of a session */
+	struct list_head	bulk_buffer_descriptors;
+	/**< Informations about session */
+	struct session_information	 session_info;
+
+	uint32_t		 session_id;
+	struct connection	 *notification_connection;
+
+	/**< The list param for using the kernel lists*/
+	struct list_head list;
+};
+
+struct session *session_create(
+	uint32_t	 session_id,
+	void		 *instance,
+	struct connection *connection
+);
+
+void session_cleanup(
+	struct session *session
+);
+
+/**
+  * Add address information of additional bulk buffer memory to session and
+  * register virtual memory in kernel module.
+  *
+  * @attention The virtual address can only be added one time. If the virtual
+  * address already exist, NULL is returned.
+  *
+  * @param buf The virtual address of bulk buffer.
+  * @param len Length of bulk buffer.
+  *
+  * @return On success the actual Bulk buffer descriptor with all address
+  * information is retured, NULL if an error occurs.
+  */
+struct bulk_buffer_descriptor *session_add_bulk_buf(
+	struct session *session,
+	void	*buf,
+	uint32_t  len
+);
+
+/**
+  * Remove address information of additional bulk buffer memory from session and
+  * unregister virtual memory in kernel module
+  *
+  * @param buf The virtual address of the bulk buffer.
+  *
+  * @return true on success.
+  */
+bool session_remove_bulk_buf(
+	struct session *session,
+	void  *buf
+);
+
+/**
+  * Set additional error information of the last error that occured.
+  *
+  * @param errorCode The actual error.
+  */
+void session_set_error_info(
+	struct session *session,
+	int32_t err
+);
+
+/**
+  * Get additional error information of the last error that occured.
+  *
+  * @attention After request the information is set to SESSION_ERR_NO.
+  *
+  * @return Last stored error code or SESSION_ERR_NO.
+  */
+int32_t session_get_last_err(
+	struct session *session
+);
+
+#endif /* SESSION_H_ */
+
+/** @} */
diff --git a/drivers/gud/mobicore_kernelapi/wsm.h b/drivers/gud/mobicore_kernelapi/wsm.h
new file mode 100644
index 0000000..6877c53
--- /dev/null
+++ b/drivers/gud/mobicore_kernelapi/wsm.h
@@ -0,0 +1,35 @@
+/** @addtogroup MCD_MCDIMPL_DAEMON_SRV
+ * @{
+ * @file
+ *
+ * World shared memory definitions.
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef WSM_H_
+#define WSM_H_
+
+#include "common.h"
+#include <linux/list.h>
+
+struct wsm {
+	void *virt_addr;
+	uint32_t len;
+	uint32_t handle;
+	void *phys_addr;
+	struct list_head list;
+};
+
+struct wsm *wsm_create(
+	void	*virt_addr,
+	uint32_t  len,
+	uint32_t  handle,
+	void	*phys_addr /*= NULL this may be unknown, so is can be omitted.*/
+);
+#endif /* WSM_H_ */
+
+/** @} */
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 3238d33..701160c 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -777,7 +777,7 @@
 			input_report_abs(input_dev, ABS_MT_POSITION_Y,
 					finger[id].y);
 			input_report_abs(input_dev, ABS_MT_PRESSURE,
-					finger[id].area);
+					 finger[id].pressure);
 		} else {
 			finger[id].status = 0;
 		}
diff --git a/drivers/leds/leds-pm8xxx.c b/drivers/leds/leds-pm8xxx.c
index fa42c2c..ece7b0f 100644
--- a/drivers/leds/leds-pm8xxx.c
+++ b/drivers/leds/leds-pm8xxx.c
@@ -57,6 +57,7 @@
 #define WLED_OVP_VAL_BIT_SHFT		0x04
 #define WLED_BOOST_LIMIT_MASK		0xE0
 #define WLED_BOOST_LIMIT_BIT_SHFT	0x05
+#define WLED_BOOST_OFF			0x00
 #define WLED_EN_MASK			0x01
 #define WLED_CP_SELECT_MAX		0x03
 #define WLED_CP_SELECT_MASK		0x03
@@ -155,6 +156,7 @@
 	struct led_classdev	cdev;
 	int			id;
 	u8			reg;
+	u8			wled_mod_ctrl_val;
 	struct device		*dev;
 	struct work_struct	work;
 	struct mutex		lock;
@@ -237,6 +239,24 @@
 	if (value > WLED_MAX_LEVEL)
 		value = WLED_MAX_LEVEL;
 
+	if (value == 0) {
+		rc = pm8xxx_writeb(led->dev->parent, WLED_MOD_CTRL_REG,
+				WLED_BOOST_OFF);
+		if (rc) {
+			dev_err(led->dev->parent, "can't write wled ctrl config"
+				" register rc=%d\n", rc);
+			return rc;
+		}
+	} else {
+		rc = pm8xxx_writeb(led->dev->parent, WLED_MOD_CTRL_REG,
+				led->wled_mod_ctrl_val);
+		if (rc) {
+			dev_err(led->dev->parent, "can't write wled ctrl config"
+				" register rc=%d\n", rc);
+			return rc;
+		}
+	}
+
 	duty = (WLED_MAX_DUTY_CYCLE * value) / WLED_MAX_LEVEL;
 
 	num_wled_strings = led->wled_cfg->num_strings;
@@ -629,6 +649,7 @@
 			" register rc=%d\n", rc);
 		return rc;
 	}
+	led->wled_mod_ctrl_val = val;
 
 	/* dump wled registers */
 	wled_dump_regs(led);
diff --git a/drivers/media/dvb/dvb-core/demux.h b/drivers/media/dvb/dvb-core/demux.h
index ff0c9d8..e22bc64 100644
--- a/drivers/media/dvb/dvb-core/demux.h
+++ b/drivers/media/dvb/dvb-core/demux.h
@@ -136,6 +136,11 @@
 		    struct timespec timeout);
 	int (*start_filtering) (struct dmx_ts_feed* feed);
 	int (*stop_filtering) (struct dmx_ts_feed* feed);
+	int (*set_indexing_params) (struct dmx_ts_feed *feed,
+				struct dmx_indexing_video_params *params);
+	int (*get_decoder_buff_status)(
+			struct dmx_ts_feed *feed,
+			struct dmx_buffer_status *dmx_buffer_status);
 };
 
 /*--------------------------------------------------------------------------*/
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index ed3f731..f2f62a4 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -850,6 +850,42 @@
 
 	spin_lock_irq(&dmxdevfilter->dev->lock);
 
+	if ((dmxdevfilter->type == DMXDEV_TYPE_PES) &&
+		(dmxdevfilter->params.pes.output == DMX_OUT_DECODER)) {
+		struct dmxdev_feed *feed;
+		int ret;
+
+		/*
+		 * Ask for status of decoder's buffer from underlying HW.
+		 * In case of PCR/STC extraction, the filter's ring-buffer
+		 * is used to gather the PCR/STC data and not using
+		 * an internal decoder buffer.
+		 */
+		if (!(dmxdevfilter->dev->capabilities &
+			DMXDEV_CAP_PCR_EXTRACTION) ||
+			((dmxdevfilter->params.pes.pes_type != DMX_PES_PCR0) &&
+			(dmxdevfilter->params.pes.pes_type != DMX_PES_PCR1) &&
+			(dmxdevfilter->params.pes.pes_type != DMX_PES_PCR2) &&
+			(dmxdevfilter->params.pes.pes_type != DMX_PES_PCR3))) {
+			list_for_each_entry(feed, &dmxdevfilter->feed.ts,
+								next) {
+				if (feed->ts->get_decoder_buff_status)
+					ret = feed->ts->get_decoder_buff_status(
+							feed->ts,
+							dmx_buffer_status);
+				else
+					ret = -ENODEV;
+
+				/*
+				 * There should not be more than one ts feed
+				 * in the list as this is DECODER feed.
+				 */
+				spin_unlock_irq(&dmxdevfilter->dev->lock);
+				return ret;
+			}
+		}
+	}
+
 	dmx_buffer_status->error = buf->error;
 	if (buf->error)
 		dvb_ringbuffer_flush(buf);
@@ -1186,6 +1222,24 @@
 		return ret;
 	}
 
+	/* Support indexing for video PES */
+	if ((para->pes_type == DMX_PES_VIDEO0) ||
+	    (para->pes_type == DMX_PES_VIDEO1) ||
+	    (para->pes_type == DMX_PES_VIDEO2) ||
+	    (para->pes_type == DMX_PES_VIDEO3)) {
+
+		if (tsfeed->set_indexing_params) {
+			ret = tsfeed->set_indexing_params(tsfeed,
+							&para->video_params);
+
+			if (ret < 0) {
+				dmxdev->demux->release_ts_feed(dmxdev->demux,
+								tsfeed);
+				return ret;
+			}
+		}
+	}
+
 	ret = tsfeed->start_filtering(tsfeed);
 	if (ret < 0) {
 		dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed);
@@ -1464,6 +1518,23 @@
 	if (params->pes_type > DMX_PES_OTHER || params->pes_type < 0)
 		return -EINVAL;
 
+	if (params->flags & DMX_ENABLE_INDEXING) {
+		if (!(dmxdev->capabilities & DMXDEV_CAP_INDEXING))
+			return -EINVAL;
+
+		/* can do indexing only on video PES */
+		if ((params->pes_type != DMX_PES_VIDEO0) &&
+		    (params->pes_type != DMX_PES_VIDEO1) &&
+		    (params->pes_type != DMX_PES_VIDEO2) &&
+		    (params->pes_type != DMX_PES_VIDEO3))
+			return -EINVAL;
+
+		/* can do indexing only when recording */
+		if ((params->output != DMX_OUT_TS_TAP) &&
+		    (params->output != DMX_OUT_TSDEMUX_TAP))
+			return -EINVAL;
+	}
+
 	dmxdevfilter->type = DMXDEV_TYPE_PES;
 	memcpy(&dmxdevfilter->params, params,
 	       sizeof(struct dmx_pes_filter_params));
diff --git a/drivers/media/dvb/dvb-core/dmxdev.h b/drivers/media/dvb/dvb-core/dmxdev.h
index 82f8f6d..4c52e84 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.h
+++ b/drivers/media/dvb/dvb-core/dmxdev.h
@@ -108,6 +108,7 @@
 #define DMXDEV_CAP_DUPLEX			0x1
 #define DMXDEV_CAP_PULL_MODE		0x2
 #define DMXDEV_CAP_PCR_EXTRACTION	0x4
+#define DMXDEV_CAP_INDEXING		0x8
 
 	enum dmx_playback_mode_t playback_mode;
 	dmx_source_t source;
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index 966b48d..bc72fee 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -1027,6 +1027,44 @@
 	return ret;
 }
 
+static int dmx_ts_feed_decoder_buff_status(struct dmx_ts_feed *ts_feed,
+			struct dmx_buffer_status *dmx_buffer_status)
+{
+	struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
+	struct dvb_demux *demux = feed->demux;
+	int ret;
+
+	spin_lock_irq(&demux->lock);
+
+	if (feed->state < DMX_STATE_GO) {
+		spin_unlock_irq(&demux->lock);
+		return -EINVAL;
+	}
+
+	if (!demux->decoder_buffer_status) {
+		spin_unlock_irq(&demux->lock);
+		return -ENODEV;
+	}
+
+	ret = demux->decoder_buffer_status(feed, dmx_buffer_status);
+
+	spin_unlock_irq(&demux->lock);
+
+	return ret;
+}
+
+static int dmx_ts_set_indexing_params(
+	struct dmx_ts_feed *ts_feed,
+	struct dmx_indexing_video_params *params)
+{
+	struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
+
+	memcpy(&feed->indexing_params, params,
+			sizeof(struct dmx_indexing_video_params));
+
+	return 0;
+}
+
 static int dvbdmx_allocate_ts_feed(struct dmx_demux *dmx,
 				   struct dmx_ts_feed **ts_feed,
 				   dmx_ts_cb callback)
@@ -1048,6 +1086,8 @@
 	feed->pid = 0xffff;
 	feed->peslen = 0xfffa;
 	feed->buffer = NULL;
+	memset(&feed->indexing_params, 0,
+			sizeof(struct dmx_indexing_video_params));
 
 	/* default behaviour - pass first PES data even if it is
 	 * partial PES data from previous PES that we didn't receive its header.
@@ -1063,6 +1103,8 @@
 	(*ts_feed)->start_filtering = dmx_ts_feed_start_filtering;
 	(*ts_feed)->stop_filtering = dmx_ts_feed_stop_filtering;
 	(*ts_feed)->set = dmx_ts_feed_set;
+	(*ts_feed)->set_indexing_params = dmx_ts_set_indexing_params;
+	(*ts_feed)->get_decoder_buff_status = dmx_ts_feed_decoder_buff_status;
 
 	if (!(feed->filter = dvb_dmx_filter_alloc(demux))) {
 		feed->state = DMX_STATE_FREE;
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.h b/drivers/media/dvb/dvb-core/dvb_demux.h
index 297f3df..ebe34ad 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.h
+++ b/drivers/media/dvb/dvb-core/dvb_demux.h
@@ -95,10 +95,12 @@
 	int cc;
 	int pusi_seen;		/* prevents feeding of garbage from previous section */
 
-	u16 peslen;
+	u32 peslen;
 
 	struct list_head list_head;
 	unsigned int index;	/* a unique index for each feed (can be used as hardware pid filter index) */
+
+	struct dmx_indexing_video_params indexing_params;
 };
 
 struct dvb_demux {
@@ -114,6 +116,8 @@
 	int (*decoder_fullness_wait)(struct dvb_demux_feed *feed,
 				 size_t required_space);
 	int (*decoder_fullness_abort)(struct dvb_demux_feed *feed);
+	int (*decoder_buffer_status)(struct dvb_demux_feed *feed,
+				struct dmx_buffer_status *dmx_buffer_status);
 	u32 (*check_crc32)(struct dvb_demux_feed *feed,
 			    const u8 *buf, size_t len);
 	void (*memcopy)(struct dvb_demux_feed *feed, u8 *dst,
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 e7bbfcb..7223377 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c
@@ -34,16 +34,6 @@
 	   sizeof(struct mpq_adapter_video_meta_data)))
 
 /*
- * The following threshold defines gap from end of ring-buffer
- * from which new PES payload will not be written to make
- * sure that the PES payload does not wrap-around at end of the
- * buffer. Instead, padding will be inserted and the new PES will
- * be written from the beginning of the buffer.
- * Setting this to 0 means no padding will be added.
- */
-#define VIDEO_WRAP_AROUND_THRESHOLD			(1024*1024+512*1024)
-
-/*
  * PCR/STC information length saved in ring-buffer.
  * PCR / STC are saved in ring-buffer in the following form:
  * <8 bit flags><64 bits of STC> <64bits of PCR>
@@ -51,13 +41,85 @@
  * The current flags that are defined:
  * 0x00000001: discontinuity_indicator
  */
-#define PCR_STC_LEN							17
+#define PCR_STC_LEN					17
 
 
 /* Number of demux devices, has default of linux configuration */
 static int mpq_demux_device_num = CONFIG_DVB_MPQ_NUM_DMX_DEVICES;
 module_param(mpq_demux_device_num, int, S_IRUGO);
 
+/**
+ * Maximum allowed framing pattern size
+ */
+#define MPQ_MAX_PATTERN_SIZE				6
+
+/**
+ * Number of patterns to look for when doing framing, per video standard
+ */
+#define MPQ_MPEG2_PATTERN_NUM				5
+#define MPQ_H264_PATTERN_NUM				5
+#define MPQ_VC1_PATTERN_NUM				3
+
+/*
+ * mpq_framing_pattern_lookup_params - framing pattern lookup parameters.
+ *
+ * @pattern: the byte pattern to look for.
+ * @mask: the byte mask to use (same length as pattern).
+ * @size: the length of the pattern, in bytes.
+ * @type: the type of the pattern.
+ */
+struct mpq_framing_pattern_lookup_params {
+	u8 pattern[MPQ_MAX_PATTERN_SIZE];
+	u8 mask[MPQ_MAX_PATTERN_SIZE];
+	size_t size;
+	enum dmx_framing_pattern_type type;
+};
+
+/*
+ * Pre-defined video framing lookup pattern information.
+ * Note: the first pattern in each patterns database must
+ * be the Sequence Header (or equivalent SPS in H.264).
+ * The code assumes this is the case when prepending
+ * Sequence Header data in case it is required.
+ */
+static const struct mpq_framing_pattern_lookup_params
+		mpeg2_patterns[MPQ_MPEG2_PATTERN_NUM] = {
+	{{0x00, 0x00, 0x01, 0xB3}, {0xFF, 0xFF, 0xFF, 0xFF}, 4,
+			DMX_FRM_MPEG2_SEQUENCE_HEADER},
+	{{0x00, 0x00, 0x01, 0xB8}, {0xFF, 0xFF, 0xFF, 0xFF}, 4,
+			DMX_FRM_MPEG2_GOP_HEADER},
+	{{0x00, 0x00, 0x01, 0x00, 0x00, 0x08},
+			{0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x38}, 6,
+			DMX_FRM_MPEG2_I_PIC},
+	{{0x00, 0x00, 0x01, 0x00, 0x00, 0x10},
+			{0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x38}, 6,
+			DMX_FRM_MPEG2_P_PIC},
+	{{0x00, 0x00, 0x01, 0x00, 0x00, 0x18},
+			{0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x38}, 6,
+			DMX_FRM_MPEG2_B_PIC}
+};
+
+static const struct mpq_framing_pattern_lookup_params
+		h264_patterns[MPQ_H264_PATTERN_NUM] = {
+	{{0x00, 0x00, 0x01, 0x07}, {0xFF, 0xFF, 0xFF, 0x1F}, 4,
+			DMX_FRM_H264_SPS},
+	{{0x00, 0x00, 0x01, 0x08}, {0xFF, 0xFF, 0xFF, 0x1F}, 4,
+			DMX_FRM_H264_PPS},
+	{{0x00, 0x00, 0x01, 0x05, 0x80}, {0xFF, 0xFF, 0xFF, 0x1F, 0x80}, 5,
+			DMX_FRM_H264_IDR_PIC},
+	{{0x00, 0x00, 0x01, 0x01, 0x80}, {0xFF, 0xFF, 0xFF, 0x1F, 0x80}, 5,
+			DMX_FRM_H264_NON_IDR_PIC}
+};
+
+static const struct mpq_framing_pattern_lookup_params
+		vc1_patterns[MPQ_VC1_PATTERN_NUM] = {
+	{{0x00, 0x00, 0x01, 0x0F}, {0xFF, 0xFF, 0xFF, 0xFF}, 4,
+			DMX_FRM_VC1_SEQUENCE_HEADER},
+	{{0x00, 0x00, 0x01, 0x0E}, {0xFF, 0xFF, 0xFF, 0xFF}, 4,
+			DMX_FRM_VC1_ENTRY_POINT_HEADER},
+	{{0x00, 0x00, 0x01, 0x0D}, {0xFF, 0xFF, 0xFF, 0xFF}, 4,
+			DMX_FRM_VC1_FRAME_START_CODE}
+};
 
 /* Global data-structure for managing demux devices */
 static struct
@@ -73,14 +135,13 @@
 		decoder_buffers[MPQ_ADAPTER_MAX_NUM_OF_INTERFACES];
 
 	/*
-	 * Indicates whether we allow decoder's data to
-	 * wrap-around in the output buffer or padding is
-	 * inserted in such case.
+	 * Indicates whether the video decoder handles framing
+	 * or we are required to provide framing information
+	 * in the meta-data passed to the decoder.
 	 */
-	int decoder_data_wrap;
+	int decoder_framing;
 } mpq_dmx_info;
 
-
 /* Check that PES header is valid and that it is a video PES */
 static int mpq_dmx_is_valid_video_pes(struct pes_packet_header *pes_header)
 {
@@ -97,6 +158,321 @@
 	return 0;
 }
 
+/* Check if a framing pattern is a video frame pattern or a header pattern */
+static inline int mpq_dmx_is_video_frame(
+				enum dmx_indexing_video_standard standard,
+				enum dmx_framing_pattern_type pattern_type)
+{
+	switch (standard) {
+	case DMX_INDEXING_MPEG2:
+		if ((pattern_type == DMX_FRM_MPEG2_I_PIC) ||
+			(pattern_type == DMX_FRM_MPEG2_P_PIC) ||
+			(pattern_type == DMX_FRM_MPEG2_B_PIC))
+			return 1;
+		return 0;
+	case DMX_INDEXING_H264:
+		if ((pattern_type == DMX_FRM_H264_IDR_PIC) ||
+			(pattern_type == DMX_FRM_H264_NON_IDR_PIC))
+			return 1;
+		return 0;
+	case DMX_INDEXING_VC1:
+		if (pattern_type == DMX_FRM_VC1_FRAME_START_CODE)
+			return 1;
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+/*
+ * mpq_framing_pattern_lookup_results - framing lookup results
+ *
+ * @offset: The offset in the buffer where the pattern was found.
+ * If a pattern is found using a prefix (i.e. started on the
+ * previous buffer), offset is zero.
+ * @type: the type of the pattern found.
+ * @used_prefix_size: the prefix size that was used to find this pattern
+ */
+struct mpq_framing_pattern_lookup_results {
+	struct {
+		u32 offset;
+		enum dmx_framing_pattern_type type;
+		u32 used_prefix_size;
+	} info[MPQ_MAX_FOUND_PATTERNS];
+};
+
+/*
+ * Check if two patterns are identical, taking mask into consideration.
+ * @pattern1: the first byte pattern to compare.
+ * @pattern2: the second byte pattern to compare.
+ * @mask: the bit mask to use.
+ * @pattern_size: the length of both patterns and the mask, in bytes.
+ *
+ * Return: 1 if patterns match, 0 otherwise.
+ */
+static inline int mpq_dmx_patterns_match(const u8 *pattern1, const u8 *pattern2,
+					const u8 *mask, size_t pattern_size)
+{
+	int i;
+
+	/*
+	 * Assumption: it is OK to access pattern1, pattern2 and mask.
+	 * This function performs no sanity checks to keep things fast.
+	 */
+
+	for (i = 0; i < pattern_size; i++)
+		if ((pattern1[i] & mask[i]) != (pattern2[i] & mask[i]))
+			return 0;
+
+	return 1;
+}
+
+/*
+ * mpq_dmx_framing_pattern_search -
+ * search for framing patterns in a given buffer.
+ *
+ * Optimized version: first search for a common substring, e.g. 0x00 0x00 0x01.
+ * If this string is found, go over all the given patterns (all must start
+ * with this string) and search for their ending in the buffer.
+ *
+ * Assumption: the patterns we look for do not spread over more than two
+ * buffers.
+ *
+ * @paterns: the full patterns information to look for.
+ * @patterns_num: the number of patterns to look for.
+ * @buf: the buffer to search.
+ * @buf_size: the size of the buffer to search. we search the entire buffer.
+ * @prefix_size_masks: a bit mask (per pattern) of possible prefix sizes to use
+ * when searching for a pattern that started at the last buffer.
+ * Updated in this function for use in the next lookup.
+ * @results: lookup results (offset, type, used_prefix_size) per found pattern,
+ * up to MPQ_MAX_FOUND_PATTERNS.
+ *
+ * Return:
+ *   Number of patterns found (up to MPQ_MAX_FOUND_PATTERNS).
+ *   0 if pattern was not found.
+ *   Negative error value on failure.
+ */
+static int mpq_dmx_framing_pattern_search(
+		const struct mpq_framing_pattern_lookup_params *patterns,
+		int patterns_num,
+		const u8 *buf,
+		size_t buf_size,
+		struct mpq_framing_prefix_size_masks *prefix_size_masks,
+		struct mpq_framing_pattern_lookup_results *results)
+{
+	int i, j;
+	unsigned int current_size;
+	u32 prefix;
+	int found = 0;
+	int start_offset = 0;
+	/* the starting common substring to look for */
+	u8 string[] = {0x00, 0x00, 0x01};
+	/* the mask for the starting string */
+	u8 string_mask[] = {0xFF, 0xFF, 0xFF};
+	/* the size of the starting string (in bytes) */
+	size_t string_size = 3;
+
+	/* sanity checks - can be commented out for optimization purposes */
+	if ((patterns == NULL) || (patterns_num <= 0) || (buf == NULL)) {
+		MPQ_DVB_ERR_PRINT("%s: invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	memset(results, 0, sizeof(struct mpq_framing_pattern_lookup_results));
+
+	/*
+	 * handle prefix - disregard string, simply check all patterns,
+	 * looking for a matching suffix at the very beginning of the buffer.
+	 */
+	for (j = 0; (j < patterns_num) && !found; j++) {
+		prefix = prefix_size_masks->size_mask[j];
+		current_size = 32;
+		while (prefix) {
+			if (prefix & (0x1 << (current_size - 1))) {
+				/*
+				 * check that we don't look further
+				 * than buf_size boundary
+				 */
+				if ((int)(patterns[j].size - current_size) >
+						buf_size)
+					break;
+
+				if (mpq_dmx_patterns_match(
+					(patterns[j].pattern + current_size),
+					buf, (patterns[j].mask + current_size),
+					(patterns[j].size - current_size))) {
+
+					MPQ_DVB_DBG_PRINT(
+						"%s: Found matching pattern"
+						"using prefix of size %d\n",
+						__func__, current_size);
+					/*
+					 * pattern found using prefix at the
+					 * very beginning of the buffer, so
+					 * offset is 0, but we already zeroed
+					 * everything in the beginning of the
+					 * function. that's why the next line
+					 * is commented.
+					 */
+					/* results->info[found].offset = 0; */
+					results->info[found].type =
+							patterns[j].type;
+					results->info[found].used_prefix_size =
+							current_size;
+					found++;
+					/*
+					 * save offset to start looking from
+					 * in the buffer, to avoid reusing the
+					 * data of a pattern we already found.
+					 */
+					start_offset = (patterns[j].size -
+							current_size);
+
+					if (found >= MPQ_MAX_FOUND_PATTERNS)
+						goto next_prefix_lookup;
+					/*
+					 * we don't want to search for the same
+					 * pattern with several possible prefix
+					 * sizes if we have already found it,
+					 * so we break from the inner loop.
+					 * since we incremented 'found', we
+					 * will not search for additional
+					 * patterns using a prefix - that would
+					 * imply ambiguous patterns where one
+					 * pattern can be included in another.
+					 * the for loop will exit.
+					 */
+					break;
+				}
+			}
+			current_size--;
+			prefix &= ~(0x1 << (current_size - 1));
+		}
+	}
+
+	/*
+	 * Search buffer for entire pattern, starting with the string.
+	 * Note the external for loop does not execute if buf_size is
+	 * smaller than string_size (the cast to int is required, since
+	 * size_t is unsigned).
+	 */
+	for (i = start_offset; i < (int)(buf_size - string_size + 1); i++) {
+		if (mpq_dmx_patterns_match(string, (buf + i), string_mask,
+							string_size)) {
+			/* now search for patterns: */
+			for (j = 0; j < patterns_num; j++) {
+				/* avoid overflow to next buffer */
+				if ((i + patterns[j].size) > buf_size)
+					continue;
+
+				if (mpq_dmx_patterns_match(
+					(patterns[j].pattern + string_size),
+					(buf + i + string_size),
+					(patterns[j].mask + string_size),
+					(patterns[j].size - string_size))) {
+
+					results->info[found].offset = i;
+					results->info[found].type =
+						patterns[j].type;
+					/*
+					 * save offset to start next prefix
+					 * lookup, to avoid reusing the data
+					 * of any pattern we already found.
+					 */
+					if ((i + patterns[j].size) >
+							start_offset)
+						start_offset = (i +
+							patterns[j].size);
+					/*
+					 * did not use a prefix to find this
+					 * pattern, but we zeroed everything
+					 * in the beginning of the function.
+					 * So no need to zero used_prefix_size
+					 * for results->info[found]
+					 */
+
+					found++;
+					if (found >= MPQ_MAX_FOUND_PATTERNS)
+						goto next_prefix_lookup;
+					/*
+					 * theoretically we don't have to break
+					 * here, but we don't want to search
+					 * for the other matching patterns on
+					 * the very same same place in the
+					 * buffer. That would mean the
+					 * (pattern & mask) combinations are
+					 * not unique. So we break from inner
+					 * loop and move on to the next place
+					 * in the buffer.
+					 */
+					break;
+				}
+			}
+		}
+	}
+
+next_prefix_lookup:
+	/* check for possible prefix sizes for the next buffer */
+	for (j = 0; j < patterns_num; j++) {
+		prefix_size_masks->size_mask[j] = 0;
+		for (i = 1; i < patterns[j].size; i++) {
+			/*
+			 * avoid looking outside of the buffer
+			 * or reusing previously used data.
+			 */
+			if (i > (buf_size - start_offset))
+				break;
+
+			if (mpq_dmx_patterns_match(patterns[j].pattern,
+					(buf + buf_size - i),
+					patterns[j].mask, i)) {
+				prefix_size_masks->size_mask[j] |=
+						(1 << (i - 1));
+			}
+		}
+	}
+
+	return found;
+}
+
+/*
+ * mpq_dmx_get_pattern_params -
+ * get a pointer to the relevant pattern parameters structure,
+ * based on the video parameters.
+ *
+ * @video_params: the video parameters (e.g. video standard).
+ * @patterns: a pointer to a pointer to the pattern parameters,
+ * updated by this function.
+ * @patterns_num: number of patterns, updated by this function.
+ */
+static inline int mpq_dmx_get_pattern_params(
+		struct dmx_indexing_video_params *video_params,
+		const struct mpq_framing_pattern_lookup_params **patterns,
+		int *patterns_num)
+{
+	switch (video_params->standard) {
+	case DMX_INDEXING_MPEG2:
+		*patterns = mpeg2_patterns;
+		*patterns_num = MPQ_MPEG2_PATTERN_NUM;
+		break;
+	case DMX_INDEXING_H264:
+		*patterns = h264_patterns;
+		*patterns_num = MPQ_H264_PATTERN_NUM;
+		break;
+	case DMX_INDEXING_VC1:
+		*patterns = vc1_patterns;
+		*patterns_num = MPQ_VC1_PATTERN_NUM;
+		break;
+	default:
+		MPQ_DVB_ERR_PRINT("%s: invalid parameters\n", __func__);
+		*patterns = NULL;
+		*patterns_num = 0;
+		return -EINVAL;
+	}
+
+	return 0;
+}
 
 /* Extend dvb-demux debugfs with HW statistics */
 void mpq_dmx_init_hw_statistics(struct mpq_demux *mpq_demux)
@@ -199,8 +575,12 @@
 	mpq_dmx_info.devices = NULL;
 	mpq_dmx_info.ion_client = NULL;
 
-	/* TODO: the following should be set based on the decoder */
-	mpq_dmx_info.decoder_data_wrap = 0;
+	/*
+	 * TODO: the following should be set based on the decoder:
+	 * 0 means the decoder doesn't handle framing, so framing
+	 * is done by demux. 1 means the decoder handles framing.
+	 */
+	mpq_dmx_info.decoder_framing = 0;
 
 	/* Allocate memory for all MPQ devices */
 	mpq_dmx_info.devices =
@@ -339,9 +719,16 @@
 	int i;
 	int dvr_index;
 	int dmx_index;
-	struct mpq_demux *mpq_demux = (struct mpq_demux *)demux->priv;
+	struct dvb_demux *dvb_demux = demux->priv;
+	struct mpq_demux *mpq_demux;
 
-	if ((mpq_dmx_info.devices == NULL) || (mpq_demux == NULL)) {
+	if ((mpq_dmx_info.devices == NULL) || (dvb_demux == 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;
 	}
@@ -394,8 +781,7 @@
 	void *packet_buffer;
 	void *payload_buffer;
 	struct mpq_video_feed_info *feed_data;
-	struct mpq_demux *mpq_demux =
-		(struct mpq_demux *)feed->demux->priv;
+	struct mpq_demux *mpq_demux = feed->demux->priv;
 	struct mpq_streambuffer *stream_buffer;
 	int actual_buffer_size;
 
@@ -404,13 +790,27 @@
 
 	if (feed_data == NULL) {
 		MPQ_DVB_ERR_PRINT(
-			"%s: FAILED to private video feed data\n",
+			"%s: FAILED to allocate private video feed data\n",
 			__func__);
 
 		ret = -ENOMEM;
 		goto init_failed;
 	}
 
+	/* get and store framing information if required */
+	if (!mpq_dmx_info.decoder_framing) {
+		mpq_dmx_get_pattern_params(&feed->indexing_params,
+				&feed_data->patterns, &feed_data->patterns_num);
+		if (feed_data->patterns == NULL) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: FAILED to get framing pattern parameters\n",
+				__func__);
+
+			ret = -EINVAL;
+			goto init_failed_free_priv_data;
+		}
+	}
+
 	/* Allocate packet buffer holding the meta-data */
 	packet_buffer = vmalloc(VIDEO_META_DATA_BUFFER_SIZE);
 
@@ -430,12 +830,7 @@
 	 * flag set.
 	 */
 
-	if (mpq_dmx_info.decoder_data_wrap)
-		actual_buffer_size =
-			feed->buffer_size;
-	else
-		actual_buffer_size =
-			feed->buffer_size + VIDEO_WRAP_AROUND_THRESHOLD;
+	actual_buffer_size = feed->buffer_size;
 
 	actual_buffer_size += (SZ_4K - 1);
 	actual_buffer_size &= ~(SZ_4K - 1);
@@ -551,6 +946,14 @@
 	feed->pusi_seen = 0;
 	feed->peslen = 0;
 	feed_data->fullness_wait_cancel = 0;
+	feed_data->last_framing_match_address = 0;
+	feed_data->last_framing_match_type = DMX_FRM_UNKNOWN;
+	feed_data->found_sequence_header_pattern = 0;
+	memset(&feed_data->prefix_size, 0,
+			sizeof(struct mpq_framing_prefix_size_masks));
+	feed_data->first_pattern_offset = 0;
+	feed_data->first_prefix_size = 0;
+	feed_data->write_pts_dts = 0;
 
 	spin_lock(&mpq_demux->feed_lock);
 	feed->priv = (void *)feed_data;
@@ -589,11 +992,8 @@
 		return -EINVAL;
 	}
 
-	mpq_demux =
-		(struct mpq_demux *)feed->demux->priv;
-
-	feed_data =
-		(struct mpq_video_feed_info *)feed->priv;
+	mpq_demux = feed->demux->priv;
+	feed_data = feed->priv;
 
 	spin_lock(&mpq_demux->feed_lock);
 	feed->priv = NULL;
@@ -620,10 +1020,7 @@
 
 int mpq_dmx_decoder_fullness_init(struct dvb_demux_feed *feed)
 {
-	struct mpq_demux *mpq_demux;
-
-	mpq_demux =
-		(struct mpq_demux *)feed->demux->priv;
+	struct mpq_demux *mpq_demux = feed->demux->priv;
 
 	if (mpq_dmx_is_video_feed(feed)) {
 		struct mpq_video_feed_info *feed_data;
@@ -638,9 +1035,7 @@
 			return -EINVAL;
 		}
 
-		feed_data =
-			(struct mpq_video_feed_info *)feed->priv;
-
+		feed_data = feed->priv;
 		feed_data->fullness_wait_cancel = 0;
 
 		spin_unlock(&mpq_demux->feed_lock);
@@ -662,14 +1057,10 @@
 		struct dvb_demux_feed *feed,
 		size_t required_space)
 {
-	struct mpq_demux *mpq_demux;
-
-	mpq_demux =
-		(struct mpq_demux *)feed->demux->priv;
+	struct mpq_demux *mpq_demux = feed->demux->priv;
 
 	if (mpq_dmx_is_video_feed(feed)) {
 		int ret;
-		int gap;
 		struct mpq_video_feed_info *feed_data;
 		struct dvb_ringbuffer *video_buff;
 
@@ -680,21 +1071,8 @@
 			return -EINVAL;
 		}
 
-		feed_data =
-			(struct mpq_video_feed_info *)feed->priv;
-
-		video_buff =
-			&feed_data->video_buffer->raw_data;
-
-		/*
-		 * If we are now starting new PES and the
-		 * PES payload may wrap-around, extra padding
-		 * needs to be pushed into the buffer.
-		 */
-		gap = video_buff->size - video_buff->pwrite;
-		if ((!mpq_dmx_info.decoder_data_wrap) &&
-			(gap < VIDEO_WRAP_AROUND_THRESHOLD))
-			required_space += gap;
+		feed_data = feed->priv;
+		video_buff = &feed_data->video_buffer->raw_data;
 
 		ret = 0;
 		if ((feed_data != NULL) &&
@@ -752,10 +1130,7 @@
 
 int mpq_dmx_decoder_fullness_abort(struct dvb_demux_feed *feed)
 {
-	struct mpq_demux *mpq_demux;
-
-	mpq_demux =
-		(struct mpq_demux *)feed->demux->priv;
+	struct mpq_demux *mpq_demux = feed->demux->priv;
 
 	if (mpq_dmx_is_video_feed(feed)) {
 		struct mpq_video_feed_info *feed_data;
@@ -771,11 +1146,9 @@
 			return -EINVAL;
 		}
 
-		feed_data =
-			(struct mpq_video_feed_info *)feed->priv;
+		feed_data = feed->priv;
 
-		video_buff =
-			&feed_data->video_buffer->raw_data;
+		video_buff = &feed_data->video_buffer->raw_data;
 
 		feed_data->fullness_wait_cancel = 1;
 		spin_unlock(&mpq_demux->feed_lock);
@@ -795,13 +1168,206 @@
 }
 EXPORT_SYMBOL(mpq_dmx_decoder_fullness_abort);
 
-int mpq_dmx_process_video_packet(
+
+static inline int mpq_dmx_parse_mandatory_pes_header(
+				struct dvb_demux_feed *feed,
+				struct mpq_video_feed_info *feed_data,
+				struct pes_packet_header *pes_header,
+				const u8 *buf,
+				u32 *ts_payload_offset,
+				int *bytes_avail)
+{
+	int left_size, copy_len;
+
+	if (feed_data->pes_header_offset < PES_MANDATORY_FIELDS_LEN) {
+		left_size =
+			PES_MANDATORY_FIELDS_LEN -
+			feed_data->pes_header_offset;
+
+		copy_len = (left_size > *bytes_avail) ?
+					*bytes_avail :
+					left_size;
+
+		memcpy((u8 *)((u8 *)pes_header + feed_data->pes_header_offset),
+				(buf + *ts_payload_offset),
+				copy_len);
+
+		feed_data->pes_header_offset += copy_len;
+
+		if (left_size > *bytes_avail)
+			return -EINVAL;
+
+		/* else - we have beginning of PES header */
+		*bytes_avail -= left_size;
+		*ts_payload_offset += left_size;
+
+		/* Make sure the PES packet is valid */
+		if (mpq_dmx_is_valid_video_pes(pes_header) < 0) {
+			/*
+			 * Since the new PES header parsing
+			 * failed, reset pusi_seen to drop all
+			 * data until next PUSI
+			 */
+			feed->pusi_seen = 0;
+			feed_data->pes_header_offset = 0;
+
+			MPQ_DVB_ERR_PRINT(
+				"%s: invalid packet\n",
+				__func__);
+
+			return -EINVAL;
+		}
+
+		feed_data->pes_header_left_bytes =
+			pes_header->pes_header_data_length;
+	}
+
+	return 0;
+}
+
+static inline int mpq_dmx_parse_remaining_pes_header(
+				struct dvb_demux_feed *feed,
+				struct mpq_video_feed_info *feed_data,
+				struct pes_packet_header *pes_header,
+				const u8 *buf,
+				u32 *ts_payload_offset,
+				int *bytes_avail)
+{
+	int left_size, copy_len;
+
+	/* Remainning header bytes that need to be processed? */
+	if (!feed_data->pes_header_left_bytes)
+		return 0;
+
+	/* Did we capture the PTS value (if exists)? */
+	if ((*bytes_avail != 0) &&
+		(feed_data->pes_header_offset <
+		 (PES_MANDATORY_FIELDS_LEN+5)) &&
+		((pes_header->pts_dts_flag == 2) ||
+		 (pes_header->pts_dts_flag == 3))) {
+
+		/* 5 more bytes should be there */
+		left_size =
+			PES_MANDATORY_FIELDS_LEN + 5 -
+			feed_data->pes_header_offset;
+
+		copy_len = (left_size > *bytes_avail) ?
+					*bytes_avail :
+					left_size;
+
+		memcpy((u8 *)((u8 *)pes_header + feed_data->pes_header_offset),
+			(buf + *ts_payload_offset),
+			copy_len);
+
+		feed_data->pes_header_offset += copy_len;
+		feed_data->pes_header_left_bytes -= copy_len;
+
+		if (left_size > *bytes_avail)
+			return -EINVAL;
+
+		/* else - we have the PTS */
+		*bytes_avail -= copy_len;
+		*ts_payload_offset += copy_len;
+		feed_data->write_pts_dts = 1;
+	}
+
+	/* Did we capture the DTS value (if exist)? */
+	if ((*bytes_avail != 0) &&
+		(feed_data->pes_header_offset <
+		 (PES_MANDATORY_FIELDS_LEN+10)) &&
+		(pes_header->pts_dts_flag == 3)) {
+
+		/* 5 more bytes should be there */
+		left_size =
+			PES_MANDATORY_FIELDS_LEN + 10 -
+			feed_data->pes_header_offset;
+
+		copy_len = (left_size > *bytes_avail) ?
+					*bytes_avail :
+					left_size;
+
+		memcpy((u8 *)((u8 *)pes_header + feed_data->pes_header_offset),
+			(buf + *ts_payload_offset),
+			copy_len);
+
+		feed_data->pes_header_offset += copy_len;
+		feed_data->pes_header_left_bytes -= copy_len;
+
+		if (left_size > *bytes_avail)
+			return -EINVAL;
+
+		/* else - we have the DTS */
+		*bytes_avail -= copy_len;
+		*ts_payload_offset += copy_len;
+		feed_data->write_pts_dts = 1;
+	}
+
+	/* Any more header bytes?! */
+	if (feed_data->pes_header_left_bytes >= *bytes_avail) {
+		feed_data->pes_header_left_bytes -= *bytes_avail;
+		return -EINVAL;
+	}
+
+	/* Got PES header, process payload */
+	*bytes_avail -= feed_data->pes_header_left_bytes;
+	*ts_payload_offset += feed_data->pes_header_left_bytes;
+	feed_data->pes_header_left_bytes = 0;
+
+	return 0;
+}
+
+static inline void mpq_dmx_get_pts_dts(struct mpq_video_feed_info *feed_data,
+				struct pes_packet_header *pes_header,
+				struct mpq_adapter_video_meta_data *meta_data,
+				enum dmx_packet_type packet_type)
+{
+	struct dmx_pts_dts_info *info;
+
+	if (packet_type == DMX_PES_PACKET)
+		info = &(meta_data->info.pes.pts_dts_info);
+	else
+		info = &(meta_data->info.framing.pts_dts_info);
+
+	if (feed_data->write_pts_dts) {
+		if ((pes_header->pts_dts_flag == 2) ||
+			(pes_header->pts_dts_flag == 3)) {
+			info->pts_exist = 1;
+
+			info->pts =
+				((u64)pes_header->pts_1 << 30) |
+				((u64)pes_header->pts_2 << 22) |
+				((u64)pes_header->pts_3 << 15) |
+				((u64)pes_header->pts_4 << 7) |
+				(u64)pes_header->pts_5;
+		} else {
+			info->pts_exist = 0;
+			info->pts = 0;
+		}
+
+		if (pes_header->pts_dts_flag == 3) {
+			info->dts_exist = 1;
+
+			info->dts =
+				((u64)pes_header->dts_1 << 30) |
+				((u64)pes_header->dts_2 << 22) |
+				((u64)pes_header->dts_3 << 15) |
+				((u64)pes_header->dts_4 << 7) |
+				(u64)pes_header->dts_5;
+		} else {
+			info->dts_exist = 0;
+			info->dts = 0;
+		}
+	} else {
+		info->pts_exist = 0;
+		info->dts_exist = 0;
+	}
+}
+
+static int mpq_dmx_process_video_packet_framing(
 			struct dvb_demux_feed *feed,
 			const u8 *buf)
 {
 	int bytes_avail;
-	int left_size;
-	int copy_len;
 	u32 ts_payload_offset;
 	struct mpq_video_feed_info *feed_data;
 	const struct ts_packet_header *ts_header;
@@ -809,14 +1375,18 @@
 	struct pes_packet_header *pes_header;
 	struct mpq_demux *mpq_demux;
 
-	mpq_demux =
-		(struct mpq_demux *)feed->demux->priv;
+	struct mpq_framing_pattern_lookup_results framing_res;
+	int found_patterns = 0;
+	int first_pattern = 0;
+	int i;
+	u32 pattern_addr = 0;
+	int is_video_frame = 0;
+
+	mpq_demux = feed->demux->priv;
 
 	spin_lock(&mpq_demux->feed_lock);
 
-	feed_data =
-		(struct mpq_video_feed_info *)feed->priv;
-
+	feed_data = feed->priv;
 	if (unlikely(feed_data == NULL)) {
 		spin_unlock(&mpq_demux->feed_lock);
 		return 0;
@@ -824,13 +1394,11 @@
 
 	ts_header = (const struct ts_packet_header *)buf;
 
-	stream_buffer =
-			feed_data->video_buffer;
+	stream_buffer = feed_data->video_buffer;
 
-	pes_header =
-			&feed_data->pes_header;
+	pes_header = &feed_data->pes_header;
 
-/*	printk("TS packet: %X %X %X %X %X%X %X %X %X\n",
+	/* MPQ_DVB_DBG_PRINT("TS packet: %X %X %X %X %X%X %X %X %X\n",
 		ts_header->sync_byte,
 		ts_header->transport_error_indicator,
 		ts_header->payload_unit_start_indicator,
@@ -839,7 +1407,317 @@
 		ts_header->pid_lsb,
 		ts_header->transport_scrambling_control,
 		ts_header->adaptation_field_control,
-		ts_header->continuity_counter);*/
+		ts_header->continuity_counter); */
+
+	/* Make sure this TS packet has a payload and not scrambled */
+	if ((ts_header->sync_byte != 0x47) ||
+		(ts_header->adaptation_field_control == 0) ||
+		(ts_header->adaptation_field_control == 2) ||
+		(ts_header->transport_scrambling_control)) {
+		/* continue to next packet */
+		spin_unlock(&mpq_demux->feed_lock);
+		return 0;
+	}
+
+	if (ts_header->payload_unit_start_indicator) { /* PUSI? */
+		if (feed->pusi_seen) { /* Did we see PUSI before? */
+			/*
+			 * Double check that we are not in middle of
+			 * previous PES header parsing.
+			 */
+			if (feed_data->pes_header_left_bytes != 0) {
+				MPQ_DVB_ERR_PRINT(
+					"%s: received PUSI"
+					"while handling PES header"
+					"of previous PES\n",
+					__func__);
+			}
+
+			feed->peslen = 0;
+			feed_data->pes_header_offset = 0;
+			feed_data->pes_header_left_bytes =
+				PES_MANDATORY_FIELDS_LEN;
+			feed_data->write_pts_dts = 0;
+		} else {
+			feed->pusi_seen = 1;
+		}
+	}
+
+	/*
+	 * Parse PES data only if PUSI was encountered,
+	 * otherwise the data is dropped
+	 */
+	if (!feed->pusi_seen) {
+		spin_unlock(&mpq_demux->feed_lock);
+		return 0; /* drop and wait for next packets */
+	}
+
+	ts_payload_offset = sizeof(struct ts_packet_header);
+
+	/* Skip adaptation field if exists */
+	if (ts_header->adaptation_field_control == 3)
+		ts_payload_offset += buf[ts_payload_offset] + 1;
+
+	/* 188 bytes: the size of a TS packet including the TS packet header */
+	bytes_avail = 188 - ts_payload_offset;
+
+	/* Get the mandatory fields of the video PES header */
+	if (mpq_dmx_parse_mandatory_pes_header(feed, feed_data,
+						pes_header, buf,
+						&ts_payload_offset,
+						&bytes_avail)) {
+		spin_unlock(&mpq_demux->feed_lock);
+		return 0;
+	}
+
+	if (mpq_dmx_parse_remaining_pes_header(feed, feed_data,
+						pes_header, buf,
+						&ts_payload_offset,
+						&bytes_avail)) {
+		spin_unlock(&mpq_demux->feed_lock);
+		return 0;
+	}
+
+	/*
+	 * If we reached here,
+	 * then we are now at the PES payload data
+	 */
+	if (bytes_avail == 0) {
+		spin_unlock(&mpq_demux->feed_lock);
+		return 0;
+	}
+
+	/*
+	 * the decoder requires demux to do framing,
+	 * so search for the patterns now.
+	 */
+	found_patterns = mpq_dmx_framing_pattern_search(
+				feed_data->patterns,
+				feed_data->patterns_num,
+				(buf + ts_payload_offset),
+				bytes_avail,
+				&feed_data->prefix_size,
+				&framing_res);
+
+	if (!(feed_data->found_sequence_header_pattern)) {
+		for (i = 0; i < found_patterns; i++) {
+			if ((framing_res.info[i].type ==
+				DMX_FRM_MPEG2_SEQUENCE_HEADER) ||
+			    (framing_res.info[i].type ==
+				DMX_FRM_H264_SPS) ||
+			    (framing_res.info[i].type ==
+				DMX_FRM_VC1_SEQUENCE_HEADER)) {
+
+				MPQ_DVB_DBG_PRINT(
+					"%s: Found Sequence Pattern, buf %p, "
+					"i = %d, offset = %d, type = %d\n",
+					__func__, buf, i,
+					framing_res.info[i].offset,
+					framing_res.info[i].type);
+
+				first_pattern = i;
+				feed_data->found_sequence_header_pattern = 1;
+				ts_payload_offset +=
+					framing_res.info[i].offset;
+				bytes_avail -= framing_res.info[i].offset;
+
+				if (framing_res.info[i].used_prefix_size) {
+					feed_data->first_prefix_size =
+						framing_res.info[i].
+							used_prefix_size;
+				}
+				/*
+				 * if this is the first pattern we write,
+				 * no need to take offset into account since we
+				 * dropped all data before it (so effectively
+				 * offset is 0).
+				 * we save the first pattern offset and take
+				 * it into consideration for the rest of the
+				 * patterns found in this buffer.
+				 */
+				feed_data->first_pattern_offset =
+					framing_res.info[i].offset;
+				break;
+			}
+		}
+	}
+
+	/*
+	 * If decoder requires demux to do framing,
+	 * pass data to decoder only after sequence header
+	 * or equivalent is found. Otherwise the data is dropped.
+	 */
+	if (!(feed_data->found_sequence_header_pattern)) {
+		spin_unlock(&mpq_demux->feed_lock);
+		return 0;
+	}
+
+	/*
+	 * write prefix used to find first Sequence pattern, if needed.
+	 * feed_data->patterns[0].pattern always contains the Sequence
+	 * pattern.
+	 */
+	if (feed_data->first_prefix_size) {
+		if (mpq_streambuffer_data_write(stream_buffer,
+					(feed_data->patterns[0].pattern),
+					feed_data->first_prefix_size) < 0) {
+			mpq_demux->decoder_tsp_drop_count++;
+			spin_unlock(&mpq_demux->feed_lock);
+			return 0;
+		}
+		feed_data->first_prefix_size = 0;
+	}
+	/* write data to payload buffer */
+	if (mpq_streambuffer_data_write(stream_buffer,
+					(buf + ts_payload_offset),
+					bytes_avail) < 0) {
+		mpq_demux->decoder_tsp_drop_count++;
+	} else {
+		struct mpq_streambuffer_packet_header packet;
+		struct mpq_adapter_video_meta_data meta_data;
+
+		feed->peslen += bytes_avail;
+
+		meta_data.packet_type = DMX_FRAMING_INFO_PACKET;
+		packet.user_data_len =
+				sizeof(struct mpq_adapter_video_meta_data);
+
+		for (i = first_pattern; i < found_patterns; i++) {
+			if (feed_data->last_framing_match_address) {
+				is_video_frame = mpq_dmx_is_video_frame(
+					feed->indexing_params.standard,
+					feed_data->last_framing_match_type);
+				if (is_video_frame == 1) {
+					mpq_dmx_get_pts_dts(feed_data,
+						pes_header,
+						&meta_data,
+						DMX_FRAMING_INFO_PACKET);
+				} else {
+					meta_data.info.framing.
+						pts_dts_info.pts_exist = 0;
+					meta_data.info.framing.
+						pts_dts_info.dts_exist = 0;
+				}
+				/*
+				 * writing meta-data that includes
+				 * framing information
+				 */
+				meta_data.info.framing.pattern_type =
+					feed_data->last_framing_match_type;
+				packet.raw_data_addr =
+					feed_data->last_framing_match_address;
+
+				pattern_addr = feed_data->pes_payload_address +
+					framing_res.info[i].offset -
+					framing_res.info[i].used_prefix_size;
+
+				if ((pattern_addr -
+					feed_data->first_pattern_offset) <
+					feed_data->last_framing_match_address) {
+					/* wraparound case */
+					packet.raw_data_len =
+						(pattern_addr -
+						feed_data->
+						   last_framing_match_address +
+						stream_buffer->raw_data.size) -
+						feed_data->first_pattern_offset;
+				} else {
+					packet.raw_data_len =
+					  pattern_addr -
+					  feed_data->
+						last_framing_match_address -
+					  feed_data->first_pattern_offset;
+				}
+
+				MPQ_DVB_DBG_PRINT("Writing Packet: "
+					"addr = 0x%X, len = %d, type = %d, "
+					"isPts = %d, isDts = %d\n",
+					packet.raw_data_addr,
+					packet.raw_data_len,
+					meta_data.info.framing.pattern_type,
+					meta_data.info.framing.
+						pts_dts_info.pts_exist,
+					meta_data.info.framing.
+						pts_dts_info.dts_exist);
+
+				if (mpq_streambuffer_pkt_write(stream_buffer,
+						&packet,
+						(u8 *)&meta_data) < 0) {
+							MPQ_DVB_ERR_PRINT(
+								"%s: "
+								"Couldn't write packet. "
+								"Should never happen\n",
+								__func__);
+				} else {
+					if (is_video_frame == 1)
+						feed_data->write_pts_dts = 0;
+				}
+			}
+
+			/* save the last match for next time */
+			feed_data->last_framing_match_type =
+					framing_res.info[i].type;
+
+			feed_data->last_framing_match_address =
+				(feed_data->pes_payload_address +
+				framing_res.info[i].offset -
+				framing_res.info[i].used_prefix_size -
+				feed_data->first_pattern_offset);
+		}
+		/*
+		 * the first pattern offset is needed only for the group of
+		 * patterns that are found and written with the first pattern.
+		 */
+		feed_data->first_pattern_offset = 0;
+
+		feed_data->pes_payload_address =
+			(u32)stream_buffer->raw_data.data +
+			stream_buffer->raw_data.pwrite;
+	}
+
+	spin_unlock(&mpq_demux->feed_lock);
+
+	return 0;
+}
+
+static int mpq_dmx_process_video_packet_no_framing(
+			struct dvb_demux_feed *feed,
+			const u8 *buf)
+{
+	int bytes_avail;
+	u32 ts_payload_offset;
+	struct mpq_video_feed_info *feed_data;
+	const struct ts_packet_header *ts_header;
+	struct mpq_streambuffer *stream_buffer;
+	struct pes_packet_header *pes_header;
+	struct mpq_demux *mpq_demux;
+
+	mpq_demux = feed->demux->priv;
+
+	spin_lock(&mpq_demux->feed_lock);
+
+	feed_data = feed->priv;
+	if (unlikely(feed_data == NULL)) {
+		spin_unlock(&mpq_demux->feed_lock);
+		return 0;
+	}
+
+	ts_header = (const struct ts_packet_header *)buf;
+
+	stream_buffer =	feed_data->video_buffer;
+
+	pes_header = &feed_data->pes_header;
+
+	/* MPQ_DVB_DBG_PRINT("TS packet: %X %X %X %X %X%X %X %X %X\n",
+		ts_header->sync_byte,
+		ts_header->transport_error_indicator,
+		ts_header->payload_unit_start_indicator,
+		ts_header->transport_priority,
+		ts_header->pid_msb,
+		ts_header->pid_lsb,
+		ts_header->transport_scrambling_control,
+		ts_header->adaptation_field_control,
+		ts_header->continuity_counter); */
 
 	/* Make sure this TS packet has a payload and not scrambled */
 	if ((ts_header->sync_byte != 0x47) ||
@@ -869,46 +1747,15 @@
 
 				packet.raw_data_len = feed->peslen;
 
-				if ((!mpq_dmx_info.decoder_data_wrap) &&
-					((feed_data->pes_payload_address +
-					feed->peslen) >
-					((u32)stream_buffer->raw_data.data +
-					stream_buffer->raw_data.size)))
-					MPQ_DVB_ERR_PRINT(
-						"%s: "
-						"Video data has wrapped-around!\n",
-						__func__);
-
 				packet.user_data_len =
 					sizeof(struct
 						mpq_adapter_video_meta_data);
 
-				if ((pes_header->pts_dts_flag == 2) ||
-					(pes_header->pts_dts_flag == 3))
-					meta_data.pts_exist = 1;
-				else
-					meta_data.pts_exist = 0;
+				mpq_dmx_get_pts_dts(feed_data, pes_header,
+							&meta_data,
+							DMX_PES_PACKET);
 
-				meta_data.pts =
-					((u64)pes_header->pts_1 << 30) |
-					((u64)pes_header->pts_2 << 22) |
-					((u64)pes_header->pts_3 << 15) |
-					((u64)pes_header->pts_4 << 7) |
-					(u64)pes_header->pts_5;
-
-				if (pes_header->pts_dts_flag == 3)
-					meta_data.dts_exist = 1;
-				else
-					meta_data.dts_exist = 0;
-
-				meta_data.dts =
-					((u64)pes_header->dts_1 << 30) |
-					((u64)pes_header->dts_2 << 22) |
-					((u64)pes_header->dts_3 << 15) |
-					((u64)pes_header->dts_4 << 7) |
-					(u64)pes_header->dts_5;
-
-				meta_data.is_padding = 0;
+				meta_data.packet_type = DMX_PES_PACKET;
 
 				if (mpq_streambuffer_pkt_write(
 						stream_buffer,
@@ -919,6 +1766,8 @@
 						"Couldn't write packet. "
 						"Should never happen\n",
 						__func__);
+				else
+					feed_data->write_pts_dts = 0;
 			} else {
 				MPQ_DVB_ERR_PRINT(
 					"%s: received PUSI"
@@ -956,137 +1805,24 @@
 	if (ts_header->adaptation_field_control == 3)
 		ts_payload_offset += buf[ts_payload_offset] + 1;
 
+	/* 188 bytes: size of a TS packet including the TS packet header */
 	bytes_avail = 188 - ts_payload_offset;
 
-	/* Got the mandatory fields of the video PES header? */
-	if (feed_data->pes_header_offset < PES_MANDATORY_FIELDS_LEN) {
-		left_size =
-			PES_MANDATORY_FIELDS_LEN -
-			feed_data->pes_header_offset;
-
-		copy_len = (left_size > bytes_avail) ?
-					bytes_avail :
-					left_size;
-
-		memcpy((u8 *)pes_header+feed_data->pes_header_offset,
-				buf+ts_payload_offset,
-				copy_len);
-
-		feed_data->pes_header_offset += copy_len;
-
-		if (left_size > bytes_avail) {
-			spin_unlock(&mpq_demux->feed_lock);
-			return 0;
-		}
-
-		/* else - we have beginning of PES header */
-		bytes_avail -= left_size;
-		ts_payload_offset += left_size;
-
-		/* Make sure the PES packet is valid */
-		if (mpq_dmx_is_valid_video_pes(pes_header) < 0) {
-			/*
-			 * Since the new PES header parsing
-			 * failed, reset pusi_seen to drop all
-			 * data until next PUSI
-			 */
-			feed->pusi_seen = 0;
-			feed_data->pes_header_offset = 0;
-
-			MPQ_DVB_ERR_PRINT(
-				"%s: invalid packet\n",
-				__func__);
-
-			spin_unlock(&mpq_demux->feed_lock);
-			return 0;
-		}
-
-		feed_data->pes_header_left_bytes =
-			pes_header->pes_header_data_length;
+	/* Get the mandatory fields of the video PES header */
+	if (mpq_dmx_parse_mandatory_pes_header(feed, feed_data,
+						pes_header, buf,
+						&ts_payload_offset,
+						&bytes_avail)) {
+		spin_unlock(&mpq_demux->feed_lock);
+		return 0;
 	}
 
-	/* Remainning header bytes that need to be processed? */
-	if (feed_data->pes_header_left_bytes) {
-		/* Did we capture the PTS value (if exist)? */
-		if ((bytes_avail != 0) &&
-			(feed_data->pes_header_offset <
-			 (PES_MANDATORY_FIELDS_LEN+5)) &&
-			((pes_header->pts_dts_flag == 2) ||
-			 (pes_header->pts_dts_flag == 3))) {
-
-			/* 5 more bytes should be there */
-			left_size =
-				PES_MANDATORY_FIELDS_LEN +
-				5 -
-				feed_data->pes_header_offset;
-
-			copy_len = (left_size > bytes_avail) ?
-						bytes_avail :
-						left_size;
-
-			memcpy((u8 *)pes_header+
-				feed_data->pes_header_offset,
-				buf+ts_payload_offset,
-				copy_len);
-
-			feed_data->pes_header_offset += copy_len;
-			feed_data->pes_header_left_bytes -= copy_len;
-
-			if (left_size > bytes_avail) {
-				spin_unlock(&mpq_demux->feed_lock);
-				return 0;
-			}
-
-			/* else - we have the PTS */
-			bytes_avail -= copy_len;
-			ts_payload_offset += copy_len;
-		}
-
-		/* Did we capture the DTS value (if exist)? */
-		if ((bytes_avail != 0) &&
-			(feed_data->pes_header_offset <
-			 (PES_MANDATORY_FIELDS_LEN+10)) &&
-			(pes_header->pts_dts_flag == 3)) {
-
-			/* 5 more bytes should be there */
-			left_size =
-				PES_MANDATORY_FIELDS_LEN +
-				10 -
-				feed_data->pes_header_offset;
-
-			copy_len = (left_size > bytes_avail) ?
-						bytes_avail :
-						left_size;
-
-			memcpy((u8 *)pes_header+
-				feed_data->pes_header_offset,
-				buf+ts_payload_offset,
-				copy_len);
-
-			feed_data->pes_header_offset += copy_len;
-			feed_data->pes_header_left_bytes -= copy_len;
-
-			if (left_size > bytes_avail) {
-				spin_unlock(&mpq_demux->feed_lock);
-				return 0;
-			}
-
-			/* else - we have the DTS */
-			bytes_avail -= copy_len;
-			ts_payload_offset += copy_len;
-		}
-
-		/* Any more header bytes?! */
-		if (feed_data->pes_header_left_bytes >= bytes_avail) {
-			feed_data->pes_header_left_bytes -= bytes_avail;
-			spin_unlock(&mpq_demux->feed_lock);
-			return 0;
-		}
-
-		/* Got PES header, process payload */
-		bytes_avail -= feed_data->pes_header_left_bytes;
-		ts_payload_offset += feed_data->pes_header_left_bytes;
-		feed_data->pes_header_left_bytes = 0;
+	if (mpq_dmx_parse_remaining_pes_header(feed, feed_data,
+						pes_header, buf,
+						&ts_payload_offset,
+						&bytes_avail)) {
+		spin_unlock(&mpq_demux->feed_lock);
+		return 0;
 	}
 
 	/*
@@ -1098,56 +1834,6 @@
 		return 0;
 	}
 
-	if (feed->peslen == 0) { /* starting new PES */
-		/* gap till end of the buffer */
-		int gap =
-			stream_buffer->raw_data.size -
-			stream_buffer->raw_data.pwrite;
-
-		if ((!mpq_dmx_info.decoder_data_wrap) &&
-			(gap < VIDEO_WRAP_AROUND_THRESHOLD)) {
-			struct mpq_streambuffer_packet_header packet;
-			struct mpq_adapter_video_meta_data meta_data;
-
-			/*
-			 * Do not start writting new PES from
-			 * this location to prevent possible
-			 * wrap-around of the payload, fill padding instead.
-			 */
-
-			/* push a packet with padding indication */
-			meta_data.is_padding = 1;
-
-			packet.raw_data_len = gap;
-			packet.user_data_len =
-				sizeof(struct mpq_adapter_video_meta_data);
-			packet.raw_data_addr =
-				feed_data->pes_payload_address;
-
-			if (mpq_streambuffer_data_write_deposit(
-						stream_buffer,
-						gap) < 0) {
-				MPQ_DVB_ERR_PRINT(
-					"%s: mpq_streambuffer_data_write_deposit "
-					"failed!\n",
-					__func__);
-			} else if (mpq_streambuffer_pkt_write(
-							stream_buffer,
-							&packet,
-							(u8 *)&meta_data) < 0) {
-				MPQ_DVB_ERR_PRINT(
-					"%s: "
-					"Couldn't write packet. "
-					"Should never happen\n",
-					__func__);
-			} else {
-				feed_data->pes_payload_address =
-					(u32)stream_buffer->raw_data.data +
-					stream_buffer->raw_data.pwrite;
-			}
-		}
-	}
-
 	if (mpq_streambuffer_data_write(
 				stream_buffer,
 				buf+ts_payload_offset,
@@ -1160,8 +1846,61 @@
 
 	return 0;
 }
-EXPORT_SYMBOL(mpq_dmx_process_video_packet);
 
+int mpq_dmx_decoder_buffer_status(struct dvb_demux_feed *feed,
+		struct dmx_buffer_status *dmx_buffer_status)
+{
+	struct mpq_demux *mpq_demux = feed->demux->priv;
+
+	if (mpq_dmx_is_video_feed(feed)) {
+		struct mpq_video_feed_info *feed_data;
+		struct dvb_ringbuffer *video_buff;
+
+		spin_lock(&mpq_demux->feed_lock);
+
+		if (feed->priv == NULL) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: invalid feed, feed->priv is NULL\n",
+				__func__);
+			spin_unlock(&mpq_demux->feed_lock);
+			return -EINVAL;
+		}
+
+		feed_data = feed->priv;
+		video_buff = &feed_data->video_buffer->raw_data;
+
+		dmx_buffer_status->error = video_buff->error;
+		dmx_buffer_status->fullness = dvb_ringbuffer_avail(video_buff);
+		dmx_buffer_status->free_bytes = dvb_ringbuffer_free(video_buff);
+		dmx_buffer_status->read_offset = video_buff->pread;
+		dmx_buffer_status->write_offset = video_buff->pwrite;
+		dmx_buffer_status->size = video_buff->size;
+
+		spin_unlock(&mpq_demux->feed_lock);
+
+		return 0;
+	}
+
+	/* else */
+	MPQ_DVB_ERR_PRINT(
+		"%s: Invalid feed type %d\n",
+		__func__,
+		feed->pes_type);
+
+	return -EINVAL;
+}
+EXPORT_SYMBOL(mpq_dmx_decoder_buffer_status);
+
+int mpq_dmx_process_video_packet(
+			struct dvb_demux_feed *feed,
+			const u8 *buf)
+{
+	if (mpq_dmx_info.decoder_framing)
+		return mpq_dmx_process_video_packet_no_framing(feed, buf);
+	else
+		return mpq_dmx_process_video_packet_framing(feed, buf);
+}
+EXPORT_SYMBOL(mpq_dmx_process_video_packet);
 
 int mpq_dmx_process_pcr_packet(
 			struct dvb_demux_feed *feed,
@@ -1171,8 +1910,7 @@
 	u64 pcr;
 	u64 stc;
 	u8 output[PCR_STC_LEN];
-	struct mpq_demux *mpq_demux =
-		(struct mpq_demux *)feed->demux->priv;
+	struct mpq_demux *mpq_demux = feed->demux->priv;
 	const struct ts_packet_header *ts_header;
 	const struct ts_adaptation_field *adaptation_field;
 
@@ -1217,9 +1955,9 @@
 		(((u64)adaptation_field->program_clock_reference_ext_1) << 8) +
 		adaptation_field->program_clock_reference_ext_2;
 
-	stc = buf[189] << 16;
-	stc += buf[190] << 8;
-	stc += buf[191];
+	stc = buf[190] << 16;
+	stc += buf[189] << 8;
+	stc += buf[188];
 	stc *= 256; /* convert from 105.47 KHZ to 27MHz */
 
 	output[0] = adaptation_field->discontinuity_indicator;
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 d90bd89..68cfcd1 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.h
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.h
@@ -23,16 +23,16 @@
 #include "mpq_adapter.h"
 
 
-/**
- * Total number of filters per demux,
- * including section and PES feeds
- */
-#define MPQ_DMX_MAX_NUM_OF_FILTERS			64
+/* Max number open() request can be done on demux device */
+#define MPQ_MAX_DMX_FILES				128
+
 
 /**
  * TSIF alias name length
  */
-#define TSIF_NAME_LENGTH					10
+#define TSIF_NAME_LENGTH				10
+
+#define MPQ_MAX_FOUND_PATTERNS				5
 
 /**
  * struct mpq_demux - mpq demux information
@@ -252,6 +252,17 @@
 } __packed;
 
 /*
+ * mpq_framing_prefix_size_masks - possible prefix sizes.
+ *
+ * @size_mask: a bit mask (per pattern) of possible prefix sizes to use
+ * when searching for a pattern that started in the last buffer.
+ * Updated in mpq_dmx_framing_pattern_search for use in the next lookup
+ */
+struct mpq_framing_prefix_size_masks {
+	u32 size_mask[MPQ_MAX_FOUND_PATTERNS];
+};
+
+/*
  * mpq_video_feed_info - private data used for video feed.
  *
  * @plugin_data: Underlying plugin's own private data.
@@ -270,6 +281,30 @@
  * @payload_buff_handle: ION handle for the allocated payload buffer
  * @stream_interface: The ID of the video stream interface registered
  * with this stream buffer.
+ * @patterns: pointer to the framing patterns to look for.
+ * @patterns_num: number of framing patterns.
+ * @last_framing_match_address: Used for saving the raw data address of
+ * the previous pattern match found in this video feed.
+ * @last_framing_match_type: Used for saving the type of
+ * the previous pattern match found in this video feed.
+ * @found_sequence_header_pattern: Flag used to note that an MPEG-2
+ * Sequence Header, H.264 SPS or VC-1 Sequence Header pattern
+ * (whichever is relevant according to the video standard) had already
+ * been found.
+ * @prefix_size: a bit mask representing the size(s) of possible prefixes
+ * to the pattern, already found in the previous buffer. If bit 0 is set,
+ * a prefix of size 1 was found. If bit 1 is set, a prefix of size 2 was
+ * found, etc. This supports a prefix size of up to 32, which is more
+ * than we need. The search function updates prefix_size as needed
+ * for the next buffer search.
+ * @first_pattern_offset: used to save the offset of the first pattern written
+ * to the stream buffer.
+ * @first_prefix_size: used to save the prefix size used to find the first
+ * pattern written to the stream buffer.
+ * @write_pts_dts: Flag used to decide if to write PTS/DTS information
+ * (if it is available in the PES header) in the meta-data passed
+ * to the video decoder. PTS/DTS information is written in the first
+ * packet after it is available.
  */
 struct mpq_video_feed_info {
 	void *plugin_data;
@@ -281,6 +316,15 @@
 	int fullness_wait_cancel;
 	struct ion_handle *payload_buff_handle;
 	enum mpq_adapter_stream_if stream_interface;
+	const struct mpq_framing_pattern_lookup_params *patterns;
+	int patterns_num;
+	u32 last_framing_match_address;
+	enum dmx_framing_pattern_type last_framing_match_type;
+	int found_sequence_header_pattern;
+	struct mpq_framing_prefix_size_masks prefix_size;
+	u32 first_pattern_offset;
+	u32 first_prefix_size;
+	int write_pts_dts;
 };
 
 /**
@@ -382,6 +426,18 @@
 		struct dvb_demux_feed *feed);
 
 /**
+ * mpq_dmx_decoder_buffer_status - Returns the
+ * status of the decoder's buffer.
+ *
+ * @feed: The decoder's feed
+ * @dmx_buffer_status: Status of decoder's buffer
+ *
+ * Return     error code.
+ */
+int mpq_dmx_decoder_buffer_status(struct dvb_demux_feed *feed,
+		struct dmx_buffer_status *dmx_buffer_status);
+
+/**
  * mpq_dmx_process_video_packet - Assemble PES data and output it
  * to the stream-buffer connected to the decoder.
  *
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 5894a65..e7d6b74 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c
@@ -18,12 +18,18 @@
 #include "mpq_dvb_debug.h"
 #include "mpq_dmx_plugin_common.h"
 
+
 /* TSIF HW configuration: */
 #define TSIF_COUNT				2
+
+/* Max number of section filters */
+#define DMX_TSIF_MAX_SECTION_FILTER_NUM	64
+
 /* When TSIF driver notifies demux that new packets are received */
 #define DMX_TSIF_PACKETS_IN_CHUNK_DEF		16
 #define DMX_TSIF_CHUNKS_IN_BUF			8
 #define DMX_TSIF_TIME_LIMIT			10000
+
 /* TSIF_DRIVER_MODE: 3 means manual control from debugfs. use 1 normally. */
 #define DMX_TSIF_DRIVER_MODE_DEF		1
 
@@ -408,8 +414,7 @@
 static int mpq_tsif_dmx_start_filtering(struct dvb_demux_feed *feed)
 {
 	int ret = 0;
-	struct mpq_demux *mpq_demux =
-		(struct mpq_demux *)feed->demux->priv;
+	struct mpq_demux *mpq_demux = feed->demux->priv;
 
 	MPQ_DVB_DBG_PRINT(
 		"%s(%d) executed\n",
@@ -476,8 +481,7 @@
 static int mpq_tsif_dmx_stop_filtering(struct dvb_demux_feed *feed)
 {
 	int ret = 0;
-	struct mpq_demux *mpq_demux =
-		(struct mpq_demux *)feed->demux->priv;
+	struct mpq_demux *mpq_demux = feed->demux->priv;
 
 	MPQ_DVB_DBG_PRINT(
 		"%s(%d) executed\n",
@@ -542,6 +546,42 @@
 	return 0;
 }
 
+/**
+ * Returns demux capabilities of TSIF plugin
+ *
+ * @demux: demux device
+ * @caps: Returned capbabilities
+ *
+ * Return     error code
+ */
+static int mpq_tsif_dmx_get_caps(struct dmx_demux *demux,
+				struct dmx_caps *caps)
+{
+	struct dvb_demux *dvb_demux = demux->priv;
+
+	if ((dvb_demux == NULL) || (caps == NULL)) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: invalid parameters\n",
+			__func__);
+
+		return -EINVAL;
+	}
+
+	caps->caps = DMX_CAP_PULL_MODE | DMX_CAP_VIDEO_DECODER_DATA;
+	caps->num_decoders = MPQ_ADAPTER_MAX_NUM_OF_INTERFACES;
+	caps->num_demux_devices = CONFIG_DVB_MPQ_NUM_DMX_DEVICES;
+	caps->num_pid_filters = dvb_demux->feednum;
+	caps->num_section_filters = dvb_demux->filternum;
+	caps->num_section_filters_per_pid = dvb_demux->filternum;
+	caps->section_filter_length = DMX_FILTER_SIZE;
+	caps->num_demod_inputs = TSIF_COUNT;
+	caps->num_memory_inputs = CONFIG_DVB_MPQ_NUM_DMX_DEVICES;
+	caps->max_bitrate = 144;
+	caps->demod_input_max_bitrate = 72;
+	caps->memory_input_max_bitrate = 72;
+
+	return 0;
+}
 
 /**
  * Initialize a single demux device.
@@ -570,8 +610,8 @@
 
 	/* Set dvb-demux "virtual" function pointers */
 	mpq_demux->demux.priv = (void *)mpq_demux;
-	mpq_demux->demux.filternum = MPQ_DMX_MAX_NUM_OF_FILTERS;
-	mpq_demux->demux.feednum = MPQ_DMX_MAX_NUM_OF_FILTERS;
+	mpq_demux->demux.filternum = DMX_TSIF_MAX_SECTION_FILTER_NUM;
+	mpq_demux->demux.feednum = MPQ_MAX_DMX_FILES;
 	mpq_demux->demux.start_feed = mpq_tsif_dmx_start_filtering;
 	mpq_demux->demux.stop_feed = mpq_tsif_dmx_stop_filtering;
 	mpq_demux->demux.write_to_decoder = mpq_tsif_dmx_write_to_decoder;
@@ -585,6 +625,9 @@
 	mpq_demux->demux.decoder_fullness_abort =
 		mpq_dmx_decoder_fullness_abort;
 
+	mpq_demux->demux.decoder_buffer_status =
+		mpq_dmx_decoder_buffer_status;
+
 	/* Initialize dvb_demux object */
 	result = dvb_dmx_init(&mpq_demux->demux);
 	if (result < 0) {
@@ -593,14 +636,16 @@
 	}
 
 	/* Now initailize the dmx-dev object */
-	mpq_demux->dmxdev.filternum = MPQ_DMX_MAX_NUM_OF_FILTERS;
+	mpq_demux->dmxdev.filternum = MPQ_MAX_DMX_FILES;
 	mpq_demux->dmxdev.demux = &mpq_demux->demux.dmx;
 	mpq_demux->dmxdev.capabilities =
 		DMXDEV_CAP_DUPLEX |
 		DMXDEV_CAP_PULL_MODE |
-		DMXDEV_CAP_PCR_EXTRACTION;
+		DMXDEV_CAP_PCR_EXTRACTION |
+		DMXDEV_CAP_INDEXING;
 
 	mpq_demux->dmxdev.demux->set_source = mpq_dmx_set_source;
+	mpq_demux->dmxdev.demux->get_caps = mpq_tsif_dmx_get_caps;
 
 	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 406ae52..f374d91 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
@@ -18,9 +18,12 @@
 #include "mpq_dmx_plugin_common.h"
 
 
-#define TSIF_COUNT						2
+#define TSIF_COUNT					2
 
-#define TSPP_FILTERS_COUNT				16
+#define TSPP_MAX_PID_FILTER_NUM		16
+
+/* Max number of section filters */
+#define TSPP_MAX_SECTION_FILTER_NUM		64
 
 /* For each TSIF we allocate two pipes, one for PES and one for sections */
 #define TSPP_PES_CHANNEL				0
@@ -44,8 +47,12 @@
 
 #define TSPP_RAW_TTS_SIZE				192
 
-/* Size of single descriptor */
-#define TSPP_BUFFER_SIZE				(TSPP_RAW_TTS_SIZE * 35)
+/* Size of single descriptor.
+ * Assuming 20MBit/sec stream, with 200 packets
+ * per descriptor there would be about 68 descriptors.
+ * Meanning about 68 interrupts per second.
+ */
+#define TSPP_BUFFER_SIZE			(TSPP_RAW_TTS_SIZE * 200)
 
 /* Number of descriptors, total size: TSPP_BUFFER_SIZE*TSPP_BUFFER_COUNT */
 #define TSPP_BUFFER_COUNT				(16)
@@ -100,7 +107,7 @@
 		struct {
 			int pid;
 			int ref_count;
-		} filters[TSPP_FILTERS_COUNT];
+		} filters[TSPP_MAX_PID_FILTER_NUM];
 
 		/* workqueue that processes TS packets from specific TSIF */
 		struct workqueue_struct *workqueue;
@@ -136,11 +143,11 @@
 	int i;
 
 	if (TSPP_IS_PES_CHANNEL(channel_id)) {
-		for (i = 0; i < TSPP_FILTERS_COUNT; i++)
+		for (i = 0; i < TSPP_MAX_PID_FILTER_NUM; i++)
 			if (mpq_dmx_tspp_info.tsif[tsif].filters[i].pid == -1)
 				return i;
 	} else {
-		for (i = TSPP_FILTERS_COUNT-1; i >= 0; i--)
+		for (i = TSPP_MAX_PID_FILTER_NUM-1; i >= 0; i--)
 			if (mpq_dmx_tspp_info.tsif[tsif].filters[i].pid == -1)
 				return i;
 	}
@@ -160,7 +167,7 @@
 {
 	int i;
 
-	for (i = 0; i < TSPP_FILTERS_COUNT; i++)
+	for (i = 0; i < TSPP_MAX_PID_FILTER_NUM; i++)
 		if (mpq_dmx_tspp_info.tsif[tsif].filters[i].pid == pid)
 			return i;
 
@@ -257,7 +264,7 @@
  */
 static int mpq_tspp_dmx_add_channel(struct dvb_demux_feed *feed)
 {
-	struct mpq_demux *mpq_demux = (struct mpq_demux *)feed->demux->priv;
+	struct mpq_demux *mpq_demux = feed->demux->priv;
 	enum tspp_source tspp_source;
 	struct tspp_filter tspp_filter;
 	int tsif;
@@ -448,7 +455,7 @@
 	int channel_id;
 	int *channel_ref_count;
 	struct tspp_filter tspp_filter;
-	struct mpq_demux *mpq_demux = (struct mpq_demux *)feed->demux->priv;
+	struct mpq_demux *mpq_demux = feed->demux->priv;
 
 	/* determine the TSIF we are reading from */
 	if (mpq_demux->source == DMX_SOURCE_FRONT0) {
@@ -552,8 +559,7 @@
 static int mpq_tspp_dmx_start_filtering(struct dvb_demux_feed *feed)
 {
 	int ret;
-	struct mpq_demux *mpq_demux =
-		(struct mpq_demux *)feed->demux->priv;
+	struct mpq_demux *mpq_demux = feed->demux->priv;
 
 	MPQ_DVB_DBG_PRINT(
 		"%s(%d) executed\n",
@@ -613,7 +619,7 @@
 static int mpq_tspp_dmx_stop_filtering(struct dvb_demux_feed *feed)
 {
 	int ret = 0;
-	struct mpq_demux *mpq_demux = (struct mpq_demux *)feed->demux->priv;
+	struct mpq_demux *mpq_demux = feed->demux->priv;
 
 	MPQ_DVB_DBG_PRINT(
 		"%s(%d) executed\n",
@@ -640,6 +646,7 @@
 					const u8 *buf,
 					size_t len)
 {
+
 	/*
 	 * It is assumed that this function is called once for each
 	 * TS packet of the relevant feed.
@@ -658,6 +665,43 @@
 	return 0;
 }
 
+/**
+ * Returns demux capabilities of TSPPv1 plugin
+ *
+ * @demux: demux device
+ * @caps: Returned capbabilities
+ *
+ * Return     error code
+ */
+static int mpq_tspp_dmx_get_caps(struct dmx_demux *demux,
+				struct dmx_caps *caps)
+{
+	struct dvb_demux *dvb_demux = demux->priv;
+
+	if ((dvb_demux == NULL) || (caps == NULL)) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: invalid parameters\n",
+			__func__);
+
+		return -EINVAL;
+	}
+
+	caps->caps = DMX_CAP_PULL_MODE | DMX_CAP_VIDEO_DECODER_DATA;
+	caps->num_decoders = MPQ_ADAPTER_MAX_NUM_OF_INTERFACES;
+	caps->num_demux_devices = CONFIG_DVB_MPQ_NUM_DMX_DEVICES;
+	caps->num_pid_filters = TSPP_MAX_PID_FILTER_NUM;
+	caps->num_section_filters = dvb_demux->filternum;
+	caps->num_section_filters_per_pid = dvb_demux->filternum;
+	caps->section_filter_length = DMX_FILTER_SIZE;
+	caps->num_demod_inputs = TSIF_COUNT;
+	caps->num_memory_inputs = CONFIG_DVB_MPQ_NUM_DMX_DEVICES;
+	caps->max_bitrate = 144;
+	caps->demod_input_max_bitrate = 72;
+	caps->memory_input_max_bitrate = 72;
+
+	return 0;
+}
+
 static int mpq_tspp_dmx_init(
 			struct dvb_adapter *mpq_adapter,
 			struct mpq_demux *mpq_demux)
@@ -677,8 +721,8 @@
 
 	/* Set dvb-demux "virtual" function pointers */
 	mpq_demux->demux.priv = (void *)mpq_demux;
-	mpq_demux->demux.filternum = MPQ_DMX_MAX_NUM_OF_FILTERS;
-	mpq_demux->demux.feednum = MPQ_DMX_MAX_NUM_OF_FILTERS;
+	mpq_demux->demux.filternum = TSPP_MAX_SECTION_FILTER_NUM;
+	mpq_demux->demux.feednum = MPQ_MAX_DMX_FILES;
 	mpq_demux->demux.start_feed = mpq_tspp_dmx_start_filtering;
 	mpq_demux->demux.stop_feed = mpq_tspp_dmx_stop_filtering;
 	mpq_demux->demux.write_to_decoder = mpq_tspp_dmx_write_to_decoder;
@@ -692,6 +736,9 @@
 	mpq_demux->demux.decoder_fullness_abort =
 		mpq_dmx_decoder_fullness_abort;
 
+	mpq_demux->demux.decoder_buffer_status =
+		mpq_dmx_decoder_buffer_status;
+
 	/* Initialize dvb_demux object */
 	result = dvb_dmx_init(&mpq_demux->demux);
 	if (result < 0) {
@@ -700,14 +747,16 @@
 	}
 
 	/* Now initailize the dmx-dev object */
-	mpq_demux->dmxdev.filternum = MPQ_DMX_MAX_NUM_OF_FILTERS;
+	mpq_demux->dmxdev.filternum = MPQ_MAX_DMX_FILES;
 	mpq_demux->dmxdev.demux = &mpq_demux->demux.dmx;
 	mpq_demux->dmxdev.capabilities =
 		DMXDEV_CAP_DUPLEX |
 		DMXDEV_CAP_PULL_MODE |
-		DMXDEV_CAP_PCR_EXTRACTION;
+		DMXDEV_CAP_PCR_EXTRACTION |
+		DMXDEV_CAP_INDEXING;
 
 	mpq_demux->dmxdev.demux->set_source = mpq_dmx_set_source;
+	mpq_demux->dmxdev.demux->get_caps = mpq_tspp_dmx_get_caps;
 
 	result = dvb_dmxdev_init(&mpq_demux->dmxdev, mpq_adapter);
 	if (result < 0) {
@@ -753,7 +802,7 @@
 		INIT_WORK(&mpq_dmx_tspp_info.tsif[i].section_work.work,
 				  mpq_dmx_tspp_work);
 
-		for (j = 0; j < TSPP_FILTERS_COUNT; j++) {
+		for (j = 0; j < TSPP_MAX_PID_FILTER_NUM; j++) {
 			mpq_dmx_tspp_info.tsif[i].filters[j].pid = -1;
 			mpq_dmx_tspp_info.tsif[i].filters[j].ref_count = 0;
 		}
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v2.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v2.c
index d3c2c50..74b7c22 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v2.c
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v2.c
@@ -16,6 +16,17 @@
 #include "mpq_dmx_plugin_common.h"
 
 
+#define TSIF_COUNT				2
+
+#define BAM_INPUT_COUNT			4
+
+/* Max number of PID filters */
+#define TSPP_MAX_PID_FILTER_NUM		128
+
+/* Max number of section filters */
+#define TSPP_MAX_SECTION_FILTER_NUM		64
+
+
 static int mpq_tspp_dmx_start_filtering(struct dvb_demux_feed *feed)
 {
 	MPQ_DVB_DBG_PRINT(
@@ -41,6 +52,44 @@
 }
 
 /**
+ * Returns demux capabilities of TSPPv2 plugin
+ *
+ * @demux: demux device
+ * @caps: Returned capbabilities
+ *
+ * Return     error code
+ */
+static int mpq_tspp_dmx_get_caps(struct dmx_demux *demux,
+				struct dmx_caps *caps)
+{
+	struct dvb_demux *dvb_demux = demux->priv;
+
+	if ((dvb_demux == NULL) || (caps == NULL)) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: invalid parameters\n",
+			__func__);
+
+		return -EINVAL;
+	}
+
+	caps->caps = DMX_CAP_PULL_MODE | DMX_CAP_VIDEO_INDEXING |
+		DMX_CAP_VIDEO_DECODER_DATA;
+	caps->num_decoders = MPQ_ADAPTER_MAX_NUM_OF_INTERFACES;
+	caps->num_demux_devices = CONFIG_DVB_MPQ_NUM_DMX_DEVICES;
+	caps->num_pid_filters = TSPP_MAX_PID_FILTER_NUM;
+	caps->num_section_filters = dvb_demux->filternum;
+	caps->num_section_filters_per_pid = dvb_demux->filternum;
+	caps->section_filter_length = DMX_FILTER_SIZE;
+	caps->num_demod_inputs = TSIF_COUNT;
+	caps->num_memory_inputs = BAM_INPUT_COUNT;
+	caps->max_bitrate = 320;
+	caps->demod_input_max_bitrate = 96;
+	caps->memory_input_max_bitrate = 80;
+
+	return 0;
+}
+
+/**
  * Initialize a single demux device.
  *
  * @mpq_adapter: MPQ DVB adapter
@@ -67,14 +116,15 @@
 
 	/* Set dvb-demux "virtual" function pointers */
 	mpq_demux->demux.priv = (void *)mpq_demux;
-	mpq_demux->demux.filternum = MPQ_DMX_MAX_NUM_OF_FILTERS;
-	mpq_demux->demux.feednum = MPQ_DMX_MAX_NUM_OF_FILTERS;
+	mpq_demux->demux.filternum = TSPP_MAX_SECTION_FILTER_NUM;
+	mpq_demux->demux.feednum = MPQ_MAX_DMX_FILES;
 	mpq_demux->demux.start_feed = mpq_tspp_dmx_start_filtering;
 	mpq_demux->demux.stop_feed = mpq_tspp_dmx_stop_filtering;
 	mpq_demux->demux.write_to_decoder = NULL;
 	mpq_demux->demux.decoder_fullness_init = NULL;
 	mpq_demux->demux.decoder_fullness_wait = NULL;
 	mpq_demux->demux.decoder_fullness_abort = NULL;
+	mpq_demux->demux.decoder_buffer_status = NULL;
 
 	/* Initialize dvb_demux object */
 	result = dvb_dmx_init(&mpq_demux->demux);
@@ -84,14 +134,16 @@
 	}
 
 	/* Now initailize the dmx-dev object */
-	mpq_demux->dmxdev.filternum = MPQ_DMX_MAX_NUM_OF_FILTERS;
+	mpq_demux->dmxdev.filternum = MPQ_MAX_DMX_FILES;
 	mpq_demux->dmxdev.demux = &mpq_demux->demux.dmx;
 	mpq_demux->dmxdev.capabilities =
 		DMXDEV_CAP_DUPLEX |
 		DMXDEV_CAP_PULL_MODE |
-		DMXDEV_CAP_PCR_EXTRACTION;
+		DMXDEV_CAP_PCR_EXTRACTION |
+		DMXDEV_CAP_INDEXING;
 
 	mpq_demux->dmxdev.demux->set_source = mpq_dmx_set_source;
+	mpq_demux->dmxdev.demux->get_caps = mpq_tspp_dmx_get_caps;
 
 	result = dvb_dmxdev_init(&mpq_demux->dmxdev, mpq_adapter);
 	if (result < 0) {
diff --git a/drivers/media/dvb/mpq/include/mpq_adapter.h b/drivers/media/dvb/mpq/include/mpq_adapter.h
index c720f91..c9b2441 100644
--- a/drivers/media/dvb/mpq/include/mpq_adapter.h
+++ b/drivers/media/dvb/mpq/include/mpq_adapter.h
@@ -37,15 +37,38 @@
 };
 
 
-/** The meta-data used for video interface */
-struct mpq_adapter_video_meta_data {
-	/**
-	 * Indication whether this packet is just a padding packet.
-	 * In this case packet should be just disposed along
-	 * with the padding in the raw-data buffer.
-	 */
-	int is_padding;
+enum dmx_framing_pattern_type {
+	/* MPEG-2 */
+	DMX_FRM_MPEG2_SEQUENCE_HEADER,
+	DMX_FRM_MPEG2_GOP_HEADER,
+	DMX_FRM_MPEG2_I_PIC,
+	DMX_FRM_MPEG2_P_PIC,
+	DMX_FRM_MPEG2_B_PIC,
+	/* H.264 */
+	DMX_FRM_H264_SPS,
+	DMX_FRM_H264_PPS,
+	/* H.264 First Coded slice of an IDR Picture */
+	DMX_FRM_H264_IDR_PIC,
+	/* H.264 First Coded slice of a non-IDR Picture */
+	DMX_FRM_H264_NON_IDR_PIC,
+	/* VC-1 Sequence Header*/
+	DMX_FRM_VC1_SEQUENCE_HEADER,
+	/* VC-1 Entry Point Header (Advanced Profile only) */
+	DMX_FRM_VC1_ENTRY_POINT_HEADER,
+	/* VC-1 Frame Start Code */
+	DMX_FRM_VC1_FRAME_START_CODE,
+	/* Unknown or invalid framing information */
+	DMX_FRM_UNKNOWN
+};
 
+enum dmx_packet_type {
+	DMX_PADDING_PACKET,
+	DMX_PES_PACKET,
+	DMX_FRAMING_INFO_PACKET,
+	DMX_EOS_PACKET
+};
+
+struct dmx_pts_dts_info {
 	/** Indication whether PTS exist */
 	int pts_exist;
 
@@ -57,6 +80,30 @@
 
 	/** DTS value associated with the PES data if any */
 	u64 dts;
+};
+
+struct dmx_framing_packet_info {
+	/** framing pattern type */
+	enum dmx_framing_pattern_type pattern_type;
+	/** PTS/DTS information */
+	struct dmx_pts_dts_info pts_dts_info;
+};
+
+struct dmx_pes_packet_info {
+	/** PTS/DTS information */
+	struct dmx_pts_dts_info pts_dts_info;
+};
+
+/** The meta-data used for video interface */
+struct mpq_adapter_video_meta_data {
+	/** meta-data packet type */
+	enum dmx_packet_type packet_type;
+
+	/** packet-type specific information */
+	union {
+		struct dmx_framing_packet_info framing;
+		struct dmx_pes_packet_info pes;
+	} info;
 } __packed;
 
 
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index fd72638..3f0f8de 100644
--- a/drivers/media/radio/radio-iris.c
+++ b/drivers/media/radio/radio-iris.c
@@ -1590,8 +1590,8 @@
 
 	if (status)
 		return;
-
-	iris_q_event(radio, IRIS_EVT_RADIO_DISABLED);
+	if (radio->mode != FM_CALIB)
+		iris_q_event(radio, IRIS_EVT_RADIO_DISABLED);
 
 	radio_hci_req_complete(hdev, status);
 }
@@ -1629,8 +1629,8 @@
 
 	if (rsp->status)
 		return;
-
-	iris_q_event(radio, IRIS_EVT_RADIO_READY);
+	if (radio->mode != FM_CALIB)
+		iris_q_event(radio, IRIS_EVT_RADIO_READY);
 
 	radio_hci_req_complete(hdev, rsp->status);
 }
@@ -2455,22 +2455,26 @@
 	int retval = 0x00;
 
 	cal_mode = PROCS_CALIB_MODE;
+	radio->mode = FM_CALIB;
 	retval = hci_cmd(HCI_FM_ENABLE_RECV_CMD,
 			radio->fm_hdev);
 	if (retval < 0) {
 		FMDERR("Enable failed before calibration %x", retval);
+		radio->mode = FM_OFF;
 		return retval;
 	}
 	retval = radio_hci_request(radio->fm_hdev, hci_fm_do_cal_req,
 		(unsigned long)cal_mode, RADIO_HCI_TIMEOUT);
 	if (retval < 0) {
 		FMDERR("Do Process calibration failed %x", retval);
+		radio->mode = FM_RECV;
 		return retval;
 	}
 	retval = hci_cmd(HCI_FM_DISABLE_RECV_CMD,
 			radio->fm_hdev);
 	if (retval < 0)
 		FMDERR("Disable Failed after calibration %d", retval);
+	radio->mode = FM_OFF;
 	return retval;
 }
 static int iris_vidioc_g_ctrl(struct file *file, void *priv,
@@ -2880,12 +2884,12 @@
 		case FM_TRANS:
 			retval = hci_cmd(HCI_FM_ENABLE_TRANS_CMD,
 							 radio->fm_hdev);
-			radio->mode = FM_TRANS;
 			if (retval < 0) {
 				FMDERR("Error while enabling TRANS FM"
 							" %d\n", retval);
 				return retval;
 			}
+			radio->mode = FM_TRANS;
 			retval = hci_cmd(HCI_FM_GET_TX_CONFIG, radio->fm_hdev);
 			if (retval < 0)
 				FMDERR("get frequency failed %d\n", retval);
@@ -2895,17 +2899,23 @@
 			case FM_RECV:
 				retval = hci_cmd(HCI_FM_DISABLE_RECV_CMD,
 						radio->fm_hdev);
-				if (retval < 0)
+				if (retval < 0) {
 					FMDERR("Err on disable recv FM"
 						   " %d\n", retval);
+					return retval;
+				}
+				radio->mode = FM_OFF;
 				break;
 			case FM_TRANS:
 				retval = hci_cmd(HCI_FM_DISABLE_TRANS_CMD,
 						radio->fm_hdev);
 
-				if (retval < 0)
+				if (retval < 0) {
 					FMDERR("Err disabling trans FM"
 						" %d\n", retval);
+					return retval;
+				}
+				radio->mode = FM_OFF;
 				break;
 			default:
 				retval = -EINVAL;
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 5aaef24..7d53e11 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -1090,3 +1090,5 @@
 
 
 endif # V4L_MEM2MEM_DRIVERS
+
+source "drivers/media/video/msm_vidc/Kconfig"
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 65a2348..d2eabb9 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -158,6 +158,7 @@
 
 obj-$(CONFIG_MSM_VCAP) += vcap_v4l2.o
 obj-$(CONFIG_MSM_VCAP) += vcap_vc.o
+obj-$(CONFIG_MSM_VCAP) += vcap_vp.o
 obj-$(CONFIG_VIDEO_AK881X)		+= ak881x.o
 
 obj-$(CONFIG_VIDEO_OMAP2)		+= omap2cam.o
@@ -189,6 +190,7 @@
 
 obj-$(CONFIG_MSM_CAMERA) += msm/
 obj-$(CONFIG_ARCH_OMAP)	+= omap/
+obj-$(CONFIG_MSM_VIDC) += msm_vidc/
 
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
 EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
diff --git a/drivers/media/video/msm/Kconfig b/drivers/media/video/msm/Kconfig
index fbc3a37..ab4a6f2 100644
--- a/drivers/media/video/msm/Kconfig
+++ b/drivers/media/video/msm/Kconfig
@@ -177,6 +177,15 @@
 	  supports spotlight and flash light modes with
 	  differrent current levels.
 
+config MSM_CAMERA_FLASH_TPS61310
+	bool "Qualcomm MSM camera tps61310 flash support"
+	depends on MSM_CAMERA
+	default n
+	---help---
+	  Enable support for LED flash for msm camera.
+	  It is a Texas Instruments multiple LED Flash
+	  for camera flash and video light applications.
+
 config IMX072
 	bool "Sensor imx072 (Sony 5M)"
 	default n
@@ -271,3 +280,9 @@
 	  overlay driver. This allows video rendering
 	  apps to render overlaid video using Video4Linux2
 	  APIs, by using /dev/videoX device
+
+config OV7692
+	bool "Sensor OV7692 (VGA YUV)"
+	depends on MSM_CAMERA
+	---help---
+	  Omni Vision VGA YUV Sensor
diff --git a/drivers/media/video/msm/Makefile b/drivers/media/video/msm/Makefile
index ebfed6c..e4d4081 100644
--- a/drivers/media/video/msm/Makefile
+++ b/drivers/media/video/msm/Makefile
@@ -11,8 +11,10 @@
   EXTRA_CFLAGS += -Idrivers/media/video/msm/eeprom
   EXTRA_CFLAGS += -Idrivers/media/video/msm/sensors
   EXTRA_CFLAGS += -Idrivers/media/video/msm/actuators
+  EXTRA_CFLAGS += -Idrivers/media/video/msm/server
   obj-$(CONFIG_MSM_CAMERA) += msm_isp.o msm.o msm_mem.o msm_mctl.o msm_mctl_buf.o msm_mctl_pp.o
-  obj-$(CONFIG_MSM_CAMERA) += io/ eeprom/ sensors/ actuators/ csi/
+  obj-$(CONFIG_MSM_CAMERA) += server/ eeprom/ sensors/ actuators/ csi/
+  obj-$(CONFIG_MSM_CAMERA) += msm_gesture.o
 else
   obj-$(CONFIG_MSM_CAMERA) += msm_camera.o
 endif
diff --git a/drivers/media/video/msm/actuators/msm_actuator.c b/drivers/media/video/msm/actuators/msm_actuator.c
index e4d8368..3a8ae9e 100644
--- a/drivers/media/video/msm/actuators/msm_actuator.c
+++ b/drivers/media/video/msm/actuators/msm_actuator.c
@@ -253,6 +253,8 @@
 			target_step_pos = dest_step_pos;
 			target_lens_pos =
 				a_ctrl->step_position_table[target_step_pos];
+			if (curr_lens_pos == target_lens_pos)
+				return rc;
 			rc = a_ctrl->func_tbl->
 				actuator_write_focus(
 					a_ctrl,
@@ -273,6 +275,8 @@
 			target_step_pos = step_boundary;
 			target_lens_pos =
 				a_ctrl->step_position_table[target_step_pos];
+			if (curr_lens_pos == target_lens_pos)
+				return rc;
 			rc = a_ctrl->func_tbl->
 				actuator_write_focus(
 					a_ctrl,
@@ -371,38 +375,13 @@
 int32_t msm_actuator_power_down(struct msm_actuator_ctrl_t *a_ctrl)
 {
 	int32_t rc = 0;
-	int16_t step_pos = 0;
-	int16_t i = 0;
-	CDBG("%s called\n", __func__);
-
-	if (a_ctrl->step_position_table) {
-		if (a_ctrl->step_position_table[a_ctrl->curr_step_pos] >=
-			a_ctrl->step_position_table[a_ctrl->pwd_step]) {
-			step_pos = (a_ctrl->
-				step_position_table[a_ctrl->curr_step_pos] -
-				a_ctrl->step_position_table[a_ctrl->
-				pwd_step]) / 10;
-			for (i = 0; i < 10; i++) {
-				rc = a_ctrl->func_tbl->
-					actuator_i2c_write(a_ctrl,
-					i * step_pos, 0);
-				usleep(500);
-			}
-			rc = a_ctrl->func_tbl->actuator_i2c_write(a_ctrl,
-				a_ctrl->step_position_table[a_ctrl->
-				curr_step_pos],
-				0);
-		}
-		CDBG("%s after msm_actuator_set_default_focus\n", __func__);
-		kfree(a_ctrl->step_position_table);
-	}
-
 	if (a_ctrl->vcm_enable) {
 		rc = gpio_direction_output(a_ctrl->vcm_pwd, 0);
 		if (!rc)
 			gpio_free(a_ctrl->vcm_pwd);
 	}
 
+	kfree(a_ctrl->step_position_table);
 	a_ctrl->step_position_table = NULL;
 	return rc;
 }
diff --git a/drivers/media/video/msm/csi/msm_csic.c b/drivers/media/video/msm/csi/msm_csic.c
index 6a5a647..e8be393 100644
--- a/drivers/media/video/msm/csi/msm_csic.c
+++ b/drivers/media/video/msm/csi/msm_csic.c
@@ -289,6 +289,8 @@
 			return rc;
 		}
 	}
+	if (csic_dev->hw_version == CSIC_7X)
+		msm_camio_vfe_blk_reset_3();
 
 #if DBG_CSIC
 	enable_irq(csic_dev->irq->start);
@@ -433,12 +435,28 @@
 		goto csic_no_resource;
 	}
 	disable_irq(new_csic_dev->irq->start);
-	iounmap(new_csic_dev->base);
-	new_csic_dev->base = NULL;
 
 	new_csic_dev->pdev = pdev;
+
+	rc = msm_cam_clk_enable(&new_csic_dev->pdev->dev, &csic_7x_clk_info[2],
+				new_csic_dev->csic_clk, 1, 1);
+	new_csic_dev->base = ioremap(new_csic_dev->mem->start,
+		resource_size(new_csic_dev->mem));
+	if (!new_csic_dev->base) {
+		rc = -ENOMEM;
+		return rc;
+	}
+
+	msm_camera_io_w(MIPI_PWR_CNTL_DIS, new_csic_dev->base + MIPI_PWR_CNTL);
+
+	rc = msm_cam_clk_enable(&new_csic_dev->pdev->dev, &csic_7x_clk_info[2],
+				new_csic_dev->csic_clk, 1, 0);
+
+	iounmap(new_csic_dev->base);
+	new_csic_dev->base = NULL;
 	msm_cam_register_subdev_node(
 		&new_csic_dev->subdev, CSIC_DEV, pdev->id);
+
 	return 0;
 
 csic_no_resource:
diff --git a/drivers/media/video/msm/csi/msm_csid.c b/drivers/media/video/msm/csi/msm_csid.c
index c04ece2..111d878 100644
--- a/drivers/media/video/msm/csi/msm_csid.c
+++ b/drivers/media/video/msm/csi/msm_csid.c
@@ -107,6 +107,8 @@
 	void __iomem *csidbase;
 	csid_dev = v4l2_get_subdevdata(cfg_params->subdev);
 	csidbase = csid_dev->base;
+	if (csidbase == NULL)
+		return -ENOMEM;
 	csid_params = cfg_params->parms;
 
 	val = csid_params->lane_cnt - 1;
diff --git a/drivers/media/video/msm/csi/msm_csiphy.c b/drivers/media/video/msm/csi/msm_csiphy.c
index 7c59ae8..df01c6b 100644
--- a/drivers/media/video/msm/csi/msm_csiphy.c
+++ b/drivers/media/video/msm/csi/msm_csiphy.c
@@ -68,6 +68,9 @@
 	void __iomem *csiphybase;
 	csiphy_dev = v4l2_get_subdevdata(cfg_params->subdev);
 	csiphybase = csiphy_dev->base;
+	if (csiphybase == NULL)
+		return -ENOMEM;
+
 	csiphy_params = cfg_params->parms;
 	lane_mask = csiphy_params->lane_mask;
 	lane_cnt = csiphy_params->lane_cnt;
diff --git a/drivers/media/video/msm/flash.c b/drivers/media/video/msm/flash.c
index 0d17e13..ba86d8c 100644
--- a/drivers/media/video/msm/flash.c
+++ b/drivers/media/video/msm/flash.c
@@ -1,5 +1,5 @@
 
-/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -30,54 +30,54 @@
 	MSM_CAM_FLASH_ON,
 };
 
-#if defined CONFIG_MSM_CAMERA_FLASH_SC628A
 static struct i2c_client *sc628a_client;
 
-static const struct i2c_device_id sc628a_i2c_id[] = {
-	{"sc628a", 0},
-	{ }
-};
-
-static int32_t sc628a_i2c_txdata(unsigned short saddr,
+static int32_t flash_i2c_txdata(struct i2c_client *client,
 		unsigned char *txdata, int length)
 {
 	struct i2c_msg msg[] = {
 		{
-			.addr = saddr,
+			.addr = client->addr >> 1,
 			.flags = 0,
 			.len = length,
 			.buf = txdata,
 		},
 	};
-	if (i2c_transfer(sc628a_client->adapter, msg, 1) < 0) {
-		CDBG("sc628a_i2c_txdata faild 0x%x\n", saddr);
+	if (i2c_transfer(client->adapter, msg, 1) < 0) {
+		CDBG("flash_i2c_txdata faild 0x%x\n", client->addr >> 1);
 		return -EIO;
 	}
 
 	return 0;
 }
 
-static int32_t sc628a_i2c_write_b_flash(uint8_t waddr, uint8_t bdata)
+static int32_t flash_i2c_write_b(struct i2c_client *client,
+	uint8_t baddr, uint8_t bdata)
 {
 	int32_t rc = -EFAULT;
 	unsigned char buf[2];
-	if (!sc628a_client)
+	if (!client)
 		return  -ENOTSUPP;
 
 	memset(buf, 0, sizeof(buf));
-	buf[0] = waddr;
+	buf[0] = baddr;
 	buf[1] = bdata;
 
-	rc = sc628a_i2c_txdata(sc628a_client->addr>>1, buf, 2);
+	rc = flash_i2c_txdata(client, buf, 2);
 	if (rc < 0) {
 		CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n",
-				waddr, bdata);
+				baddr, bdata);
 	}
 	usleep_range(4000, 5000);
 
 	return rc;
 }
 
+static const struct i2c_device_id sc628a_i2c_id[] = {
+	{"sc628a", 0},
+	{ }
+};
+
 static int sc628a_i2c_probe(struct i2c_client *client,
 		const struct i2c_device_id *id)
 {
@@ -91,7 +91,7 @@
 
 	sc628a_client = client;
 
-	CDBG("sc628a_probe successed! rc = %d\n", rc);
+	CDBG("sc628a_probe success rc = %d\n", rc);
 	return 0;
 
 probe_failure:
@@ -107,7 +107,49 @@
 		.name = "sc628a",
 	},
 };
-#endif
+
+static struct i2c_client *tps61310_client;
+
+static const struct i2c_device_id tps61310_i2c_id[] = {
+	{"tps61310", 0},
+	{ }
+};
+
+static int tps61310_i2c_probe(struct i2c_client *client,
+		const struct i2c_device_id *id)
+{
+	int rc = 0;
+	CDBG("%s enter\n", __func__);
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		pr_err("i2c_check_functionality failed\n");
+		goto probe_failure;
+	}
+
+	tps61310_client = client;
+
+	rc = flash_i2c_write_b(tps61310_client, 0x01, 0x00);
+	if (rc < 0) {
+		tps61310_client = NULL;
+		goto probe_failure;
+	}
+
+	CDBG("%s success! rc = %d\n", __func__, rc);
+	return 0;
+
+probe_failure:
+	pr_err("%s failed! rc = %d\n", __func__, rc);
+	return rc;
+}
+
+static struct i2c_driver tps61310_i2c_driver = {
+	.id_table = tps61310_i2c_id,
+	.probe  = tps61310_i2c_probe,
+	.remove = __exit_p(tps61310_i2c_remove),
+	.driver = {
+		.name = "tps61310",
+	},
+};
 
 static int config_flash_gpio_table(enum msm_cam_flash_stat stat,
 			struct msm_camera_sensor_strobe_flash_data *sfdata)
@@ -278,18 +320,34 @@
 {
 	int rc = 0;
 
-#if defined CONFIG_MSM_CAMERA_FLASH_SC628A
 	switch (led_state) {
 
 	case MSM_CAMERA_LED_INIT:
-		if (!sc628a_client) {
-			rc = i2c_add_driver(&sc628a_i2c_driver);
-			if (rc < 0 || sc628a_client == NULL) {
-				rc = -ENOTSUPP;
-				CDBG("I2C add driver failed");
-				return rc;
+		if (external->flash_id == MAM_CAMERA_EXT_LED_FLASH_SC628A) {
+			if (!sc628a_client) {
+				rc = i2c_add_driver(&sc628a_i2c_driver);
+				if (rc < 0 || sc628a_client == NULL) {
+					pr_err("sc628a_i2c_driver add failed\n");
+					rc = -ENOTSUPP;
+					return rc;
+				}
 			}
+		} else if (external->flash_id ==
+			MAM_CAMERA_EXT_LED_FLASH_TPS61310) {
+			if (!tps61310_client) {
+				rc = i2c_add_driver(&tps61310_i2c_driver);
+				if (rc < 0 || tps61310_client == NULL) {
+					pr_err("tps61310_i2c_driver add failed\n");
+					rc = -ENOTSUPP;
+					return rc;
+				}
+			}
+		} else {
+			pr_err("Flash id not supported\n");
+			rc = -ENOTSUPP;
+			return rc;
 		}
+
 #if defined(CONFIG_GPIO_SX150X) || defined(CONFIG_GPIO_SX150X_MODULE)
 		if (external->expander_info && !sx150x_client) {
 			struct i2c_adapter *adapter =
@@ -298,20 +356,37 @@
 				sx150x_client = i2c_new_device(adapter,
 					external->expander_info->board_info);
 			if (!sx150x_client || !adapter) {
+				pr_err("sx150x_client is not available\n");
 				rc = -ENOTSUPP;
-				i2c_del_driver(&sc628a_i2c_driver);
-				sc628a_client = NULL;
+				if (sc628a_client) {
+					i2c_del_driver(&sc628a_i2c_driver);
+					sc628a_client = NULL;
+				}
+				if (tps61310_client) {
+					i2c_del_driver(&tps61310_i2c_driver);
+					tps61310_client = NULL;
+				}
 				return rc;
 			}
+			i2c_put_adapter(adapter);
 		}
 #endif
-		rc = gpio_request(external->led_en, "sc628a");
+		if (sc628a_client)
+			rc = gpio_request(external->led_en, "sc628a");
+		if (tps61310_client)
+			rc = gpio_request(external->led_en, "tps61310");
+
 		if (!rc) {
 			gpio_direction_output(external->led_en, 0);
 		} else {
-			goto err1;
+			goto error;
 		}
-		rc = gpio_request(external->led_flash_en, "sc628a");
+
+		if (sc628a_client)
+			rc = gpio_request(external->led_flash_en, "sc628a");
+		if (tps61310_client)
+			rc = gpio_request(external->led_flash_en, "tps61310");
+
 		if (!rc) {
 			gpio_direction_output(external->led_flash_en, 0);
 			break;
@@ -319,19 +394,32 @@
 
 		gpio_set_value_cansleep(external->led_en, 0);
 		gpio_free(external->led_en);
-
-err1:
-		i2c_del_driver(&sc628a_i2c_driver);
-		sc628a_client = NULL;
-
+error:
+		pr_err("%s gpio request failed\n", __func__);
+		if (sc628a_client) {
+			i2c_del_driver(&sc628a_i2c_driver);
+			sc628a_client = NULL;
+		}
+		if (tps61310_client) {
+			i2c_del_driver(&tps61310_i2c_driver);
+			tps61310_client = NULL;
+		}
 		break;
 
 	case MSM_CAMERA_LED_RELEASE:
-		if (sc628a_client) {
+		if (sc628a_client || tps61310_client) {
 			gpio_set_value_cansleep(external->led_en, 0);
 			gpio_free(external->led_en);
 			gpio_set_value_cansleep(external->led_flash_en, 0);
 			gpio_free(external->led_flash_en);
+			if (sc628a_client) {
+				i2c_del_driver(&sc628a_i2c_driver);
+				sc628a_client = NULL;
+			}
+			if (tps61310_client) {
+				i2c_del_driver(&tps61310_i2c_driver);
+				tps61310_client = NULL;
+			}
 		}
 #if defined(CONFIG_GPIO_SX150X) || defined(CONFIG_GPIO_SX150X_MODULE)
 		if (external->expander_info && sx150x_client) {
@@ -342,37 +430,38 @@
 		break;
 
 	case MSM_CAMERA_LED_OFF:
-		rc = sc628a_i2c_write_b_flash(0x02, 0x0);
-		if (sc628a_client) {
-			gpio_set_value_cansleep(external->led_en, 0);
-			gpio_set_value_cansleep(external->led_flash_en, 0);
-		}
+		if (sc628a_client)
+			rc = flash_i2c_write_b(sc628a_client, 0x02, 0x00);
+		if (tps61310_client)
+			rc = flash_i2c_write_b(tps61310_client, 0x01, 0x00);
+		gpio_set_value_cansleep(external->led_en, 0);
+		gpio_set_value_cansleep(external->led_flash_en, 0);
 		break;
 
 	case MSM_CAMERA_LED_LOW:
-		if (sc628a_client) {
-			gpio_set_value_cansleep(external->led_en, 1);
-			gpio_set_value_cansleep(external->led_flash_en, 1);
-			usleep_range(2000, 3000);
-		}
-		rc = sc628a_i2c_write_b_flash(0x02, 0x06);
+		gpio_set_value_cansleep(external->led_en, 1);
+		gpio_set_value_cansleep(external->led_flash_en, 1);
+		usleep_range(2000, 3000);
+		if (sc628a_client)
+			rc = flash_i2c_write_b(sc628a_client, 0x02, 0x06);
+		if (tps61310_client)
+			rc = flash_i2c_write_b(tps61310_client, 0x01, 0x86);
 		break;
 
 	case MSM_CAMERA_LED_HIGH:
-		if (sc628a_client) {
-			gpio_set_value_cansleep(external->led_en, 1);
-			gpio_set_value_cansleep(external->led_flash_en, 1);
-			usleep_range(2000, 3000);
-		}
-		rc = sc628a_i2c_write_b_flash(0x02, 0x49);
+		gpio_set_value_cansleep(external->led_en, 1);
+		gpio_set_value_cansleep(external->led_flash_en, 1);
+		usleep_range(2000, 3000);
+		if (sc628a_client)
+			rc = flash_i2c_write_b(sc628a_client, 0x02, 0x49);
+		if (tps61310_client)
+			rc = flash_i2c_write_b(tps61310_client, 0x01, 0x8B);
 		break;
 
 	default:
 		rc = -EFAULT;
 		break;
 	}
-#endif
-
 	return rc;
 }
 
diff --git a/drivers/media/video/msm/gemini/msm_gemini_hw.h b/drivers/media/video/msm/gemini/msm_gemini_hw.h
index e1702a5..233f082 100644
--- a/drivers/media/video/msm/gemini/msm_gemini_hw.h
+++ b/drivers/media/video/msm/gemini/msm_gemini_hw.h
@@ -15,8 +15,8 @@
 
 #include <media/msm_gemini.h>
 #include "msm_gemini_hw_reg.h"
-#include <mach/msm_subsystem_map.h>
 #include <linux/ion.h>
+#include <mach/iommu_domains.h>
 
 struct msm_gemini_hw_buf {
 	struct msm_gemini_buf vbuf;
diff --git a/drivers/media/video/msm/gemini/msm_gemini_platform.c b/drivers/media/video/msm/gemini/msm_gemini_platform.c
index 1ebc2f1..06b2aac 100644
--- a/drivers/media/video/msm/gemini/msm_gemini_platform.c
+++ b/drivers/media/video/msm/gemini/msm_gemini_platform.c
@@ -17,7 +17,7 @@
 #include <linux/io.h>
 #include <linux/android_pmem.h>
 #include <mach/camera.h>
-#include <mach/msm_subsystem_map.h>
+#include <mach/iommu_domains.h>
 
 #include "msm_gemini_platform.h"
 #include "msm_gemini_sync.h"
diff --git a/drivers/media/video/msm/gemini/msm_gemini_platform.h b/drivers/media/video/msm/gemini/msm_gemini_platform.h
index 4542129..eb6b9f0 100644
--- a/drivers/media/video/msm/gemini/msm_gemini_platform.h
+++ b/drivers/media/video/msm/gemini/msm_gemini_platform.h
@@ -16,6 +16,7 @@
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/ion.h>
+#include <linux/iommu.h>
 void msm_gemini_platform_p2v(struct file  *file,
 				struct ion_handle **ionhandle);
 uint32_t msm_gemini_platform_v2p(int fd, uint32_t len, struct file **file,
diff --git a/drivers/media/video/msm/gemini/msm_gemini_sync.c b/drivers/media/video/msm/gemini/msm_gemini_sync.c
index fe7c99f..b55ec18 100644
--- a/drivers/media/video/msm/gemini/msm_gemini_sync.c
+++ b/drivers/media/video/msm/gemini/msm_gemini_sync.c
@@ -453,6 +453,7 @@
 {
 	struct msm_gemini_core_buf *buf_p;
 	struct msm_gemini_buf buf_cmd;
+	int rc = 0;
 
 	if (copy_from_user(&buf_cmd, arg, sizeof(struct msm_gemini_buf))) {
 		GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
@@ -469,17 +470,25 @@
 		(int) buf_cmd.vaddr, buf_cmd.y_len);
 
 	if (pgmn_dev->op_mode == MSM_GEMINI_MODE_REALTIME_ENCODE) {
-		buf_p->y_buffer_addr    = buf_cmd.y_off;
+		rc = msm_iommu_map_contig_buffer(
+			(unsigned long)buf_cmd.y_off, CAMERA_DOMAIN, GEN_POOL,
+			((buf_cmd.y_len + buf_cmd.cbcr_len + 4095) & (~4095)),
+			SZ_4K, IOMMU_WRITE | IOMMU_READ,
+			(unsigned long *)&buf_p->y_buffer_addr);
+		if (rc < 0) {
+			pr_err("%s iommu mapping failed with error %d\n",
+				 __func__, rc);
+			kfree(buf_p);
+			return rc;
+		}
 	} else {
 	buf_p->y_buffer_addr    = msm_gemini_platform_v2p(buf_cmd.fd,
 		buf_cmd.y_len + buf_cmd.cbcr_len, &buf_p->file,
 		&buf_p->handle)	+ buf_cmd.offset;
 	}
 	buf_p->y_len          = buf_cmd.y_len;
-
 	buf_p->cbcr_buffer_addr = buf_p->y_buffer_addr + buf_cmd.y_len;
 	buf_p->cbcr_len       = buf_cmd.cbcr_len;
-
 	buf_p->num_of_mcu_rows = buf_cmd.num_of_mcu_rows;
 	GMN_DBG("%s: y_addr=%x,y_len=%x,cbcr_addr=%x,cbcr_len=%x\n", __func__,
 		buf_p->y_buffer_addr, buf_p->y_len, buf_p->cbcr_buffer_addr,
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 45761d5..946b985 100644
--- a/drivers/media/video/msm/io/msm_io_7x27a_v4l2.c
+++ b/drivers/media/video/msm/io/msm_io_7x27a_v4l2.c
@@ -85,27 +85,18 @@
 	clk_set_rate(clk, rate);
 }
 
-void msm_camio_vfe_blk_reset_2(int vfe_apps_reset)
+void msm_camio_vfe_blk_reset_2(void)
 {
 	uint32_t val;
 
-	if (apps_reset && !vfe_apps_reset)
-		return;
-
 	/* do apps reset */
 	val = readl_relaxed(appbase + 0x00000210);
-	if (apps_reset)
-		val |= 0x10A0001;
-	else
-		val |= 0x1;
+	val |= 0x1;
 	writel_relaxed(val, appbase + 0x00000210);
 	usleep_range(10000, 11000);
 
 	val = readl_relaxed(appbase + 0x00000210);
-	if (apps_reset)
-		val &= ~(0x10A0001);
-	else
-		val &= ~0x1;
+	val &= ~0x1;
 	writel_relaxed(val, appbase + 0x00000210);
 	usleep_range(10000, 11000);
 
@@ -122,6 +113,26 @@
 	usleep_range(10000, 11000);
 }
 
+void msm_camio_vfe_blk_reset_3(void)
+{
+	uint32_t val;
+
+	if (!apps_reset)
+		return;
+
+	/* do apps reset */
+	val = readl_relaxed(appbase + 0x00000210);
+	val |= 0x10A0000;
+	writel_relaxed(val, appbase + 0x00000210);
+	usleep_range(10000, 11000);
+
+	val = readl_relaxed(appbase + 0x00000210);
+	val &= ~(0x10A0000);
+	writel_relaxed(val, appbase + 0x00000210);
+	usleep_range(10000, 11000);
+	mb();
+}
+
 void msm_camio_set_perf_lvl(enum msm_bus_perf_setting perf_setting)
 {
 	switch (perf_setting) {
diff --git a/drivers/media/video/msm/io/msm_io_vfe31_v4l2.c b/drivers/media/video/msm/io/msm_io_vfe31_v4l2.c
index a1270ea..9dc097b 100644
--- a/drivers/media/video/msm/io/msm_io_vfe31_v4l2.c
+++ b/drivers/media/video/msm/io/msm_io_vfe31_v4l2.c
@@ -156,6 +156,11 @@
 	return;
 }
 
+void msm_camio_vfe_blk_reset_3(void)
+{
+	return;
+}
+
 static void msm_camio_axi_cfg(enum msm_bus_perf_setting perf_setting)
 {
 	switch (perf_setting) {
diff --git a/drivers/media/video/msm/msm.c b/drivers/media/video/msm/msm.c
index 1220b6e..0696b96 100644
--- a/drivers/media/video/msm/msm.c
+++ b/drivers/media/video/msm/msm.c
@@ -19,13 +19,9 @@
 #include <linux/spinlock.h>
 #include <linux/proc_fs.h>
 #include "msm.h"
-#include "msm_csid.h"
-#include "msm_csic.h"
-#include "msm_csiphy.h"
-#include "msm_ispif.h"
+#include "msm_cam_server.h"
 #include "msm_sensor.h"
 #include "msm_actuator.h"
-#include "msm_vfe32.h"
 #include "msm_camera_eeprom.h"
 
 #define MSM_MAX_CAMERA_SENSORS 5
@@ -37,107 +33,11 @@
 #endif
 
 static unsigned msm_camera_v4l2_nr = -1;
-static struct msm_cam_server_dev g_server_dev;
-static struct class *msm_class;
-static dev_t msm_devno;
 static int vnode_count;
 
 module_param(msm_camera_v4l2_nr, uint, 0644);
 MODULE_PARM_DESC(msm_camera_v4l2_nr, "videoX start number, -1 is autodetect");
 
-static void msm_queue_init(struct msm_device_queue *queue, const char *name)
-{
-	D("%s\n", __func__);
-	spin_lock_init(&queue->lock);
-	queue->len = 0;
-	queue->max = 0;
-	queue->name = name;
-	INIT_LIST_HEAD(&queue->list);
-	init_waitqueue_head(&queue->wait);
-}
-
-static void msm_enqueue(struct msm_device_queue *queue,
-			struct list_head *entry)
-{
-	unsigned long flags;
-	spin_lock_irqsave(&queue->lock, flags);
-	queue->len++;
-	if (queue->len > queue->max) {
-		queue->max = queue->len;
-		pr_info("%s: queue %s new max is %d\n", __func__,
-			queue->name, queue->max);
-	}
-	list_add_tail(entry, &queue->list);
-	wake_up(&queue->wait);
-	D("%s: woke up %s\n", __func__, queue->name);
-	spin_unlock_irqrestore(&queue->lock, flags);
-}
-
-static void msm_drain_eventq(struct msm_device_queue *queue)
-{
-	unsigned long flags;
-	struct msm_queue_cmd *qcmd;
-	spin_lock_irqsave(&queue->lock, flags);
-	while (!list_empty(&queue->list)) {
-		qcmd = list_first_entry(&queue->list,
-			struct msm_queue_cmd, list_eventdata);
-		list_del_init(&qcmd->list_eventdata);
-		kfree(qcmd->command);
-		free_qcmd(qcmd);
-	}
-	spin_unlock_irqrestore(&queue->lock, flags);
-}
-
-static int32_t msm_find_free_queue(void)
-{
-	int i;
-	for (i = 0; i < MAX_NUM_ACTIVE_CAMERA; i++) {
-		struct msm_cam_server_queue *queue;
-		queue = &g_server_dev.server_queue[i];
-		if (!queue->queue_active)
-			return i;
-	}
-	return -EINVAL;
-}
-
-uint32_t msm_camera_get_mctl_handle(void)
-{
-	uint32_t i;
-	if ((g_server_dev.mctl_handle_cnt << 8) == 0)
-		g_server_dev.mctl_handle_cnt++;
-	for (i = 0; i < MAX_NUM_ACTIVE_CAMERA; i++) {
-		if (g_server_dev.mctl[i].handle == 0) {
-			g_server_dev.mctl[i].handle =
-				(++g_server_dev.mctl_handle_cnt) << 8 | i;
-			memset(&g_server_dev.mctl[i].mctl,
-				   0, sizeof(g_server_dev.mctl[i].mctl));
-			return g_server_dev.mctl[i].handle;
-		}
-	}
-	return 0;
-}
-
-struct msm_cam_media_controller *msm_camera_get_mctl(uint32_t handle)
-{
-	uint32_t mctl_index;
-	mctl_index = handle & 0xff;
-	if ((mctl_index < MAX_NUM_ACTIVE_CAMERA) &&
-		(g_server_dev.mctl[mctl_index].handle == handle))
-		return &g_server_dev.mctl[mctl_index].mctl;
-	return NULL;
-}
-
-void msm_camera_free_mctl(uint32_t handle)
-{
-	uint32_t mctl_index;
-	mctl_index = handle & 0xff;
-	if ((mctl_index < MAX_NUM_ACTIVE_CAMERA) &&
-		(g_server_dev.mctl[mctl_index].handle == handle))
-		g_server_dev.mctl[mctl_index].handle = 0;
-	else
-		pr_err("%s: invalid free handle\n", __func__);
-}
-
 /* callback function from all subdevices of a msm_cam_v4l2_device */
 static void msm_cam_v4l2_subdev_notify(struct v4l2_subdev *sd,
 				unsigned int notification, void *arg)
@@ -153,655 +53,11 @@
 	if (pcam == NULL)
 		return;
 
-	pmctl = msm_camera_get_mctl(pcam->mctl_handle);
+	pmctl = msm_cam_server_get_mctl(pcam->mctl_handle);
 	if (pmctl == NULL)
 		return;
 }
 
-static int msm_ctrl_cmd_done(void *arg)
-{
-	void __user *uptr;
-	struct msm_queue_cmd *qcmd;
-	struct msm_camera_v4l2_ioctl_t *ioctl_ptr = arg;
-	struct msm_ctrl_cmd *command =
-		kzalloc(sizeof(struct msm_ctrl_cmd), GFP_KERNEL);
-	if (!command) {
-		pr_err("%s Insufficient memory. return", __func__);
-		return -ENOMEM;
-	}
-
-	D("%s\n", __func__);
-	if (copy_from_user(command, (void __user *)ioctl_ptr->ioctl_ptr,
-					   sizeof(struct msm_ctrl_cmd))) {
-		pr_err("%s: copy_from_user failed, size=%d\n",
-			   __func__, sizeof(struct msm_ctrl_cmd));
-		return -EINVAL;
-	}
-
-	g_server_dev.server_queue[command->queue_idx].ctrl = command;
-	if (command->evt_id !=
-		g_server_dev.server_queue[command->queue_idx].evt_id) {
-		pr_err("Invalid event id from userspace\n");
-		return -EINVAL;
-	}
-
-	mutex_lock(&g_server_dev.server_queue_lock);
-	qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_KERNEL);
-	atomic_set(&qcmd->on_heap, 1);
-	uptr = command->value;
-	qcmd->command = command;
-
-	if (command->length > 0) {
-		command->value =
-			g_server_dev.server_queue[command->queue_idx].ctrl_data;
-		if (command->length > max_control_command_size) {
-			pr_err("%s: user data %d is too big (max %d)\n",
-				__func__, command->length,
-				max_control_command_size);
-			free_qcmd(qcmd);
-			return -EINVAL;
-		}
-		if (copy_from_user(command->value, uptr, command->length)) {
-			free_qcmd(qcmd);
-			return -EINVAL;
-		}
-	}
-	msm_enqueue(&g_server_dev.server_queue
-		[command->queue_idx].ctrl_q, &qcmd->list_control);
-	mutex_unlock(&g_server_dev.server_queue_lock);
-	return 0;
-}
-
-/* send control command to config and wait for results*/
-static int msm_server_control(struct msm_cam_server_dev *server_dev,
-				struct msm_ctrl_cmd *out)
-{
-	int rc = 0;
-	void *value;
-	struct msm_queue_cmd *rcmd;
-	struct msm_queue_cmd *event_qcmd;
-	struct msm_ctrl_cmd *ctrlcmd;
-	struct msm_device_queue *queue =
-		&server_dev->server_queue[out->queue_idx].ctrl_q;
-
-	struct v4l2_event v4l2_evt;
-	struct msm_isp_event_ctrl *isp_event;
-	isp_event = kzalloc(sizeof(struct msm_isp_event_ctrl), GFP_KERNEL);
-	if (!isp_event) {
-		pr_err("%s Insufficient memory. return", __func__);
-		return -ENOMEM;
-	}
-	event_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_KERNEL);
-	if (!event_qcmd) {
-		pr_err("%s Insufficient memory. return", __func__);
-		return -ENOMEM;
-	}
-
-	D("%s\n", __func__);
-	mutex_lock(&server_dev->server_queue_lock);
-	if (++server_dev->server_evt_id == 0)
-		server_dev->server_evt_id++;
-
-	server_dev->server_queue[out->queue_idx].evt_id =
-		server_dev->server_evt_id;
-	v4l2_evt.type = V4L2_EVENT_PRIVATE_START + MSM_CAM_RESP_V4L2;
-	v4l2_evt.u.data[0] = out->queue_idx;
-	/* setup event object to transfer the command; */
-	isp_event->resptype = MSM_CAM_RESP_V4L2;
-	isp_event->isp_data.ctrl = *out;
-	isp_event->isp_data.ctrl.evt_id = server_dev->server_evt_id;
-
-	atomic_set(&event_qcmd->on_heap, 1);
-	event_qcmd->command = isp_event;
-
-	msm_enqueue(&server_dev->server_queue[out->queue_idx].eventData_q,
-				&event_qcmd->list_eventdata);
-
-	/* now send command to config thread in userspace,
-	 * and wait for results */
-	v4l2_event_queue(server_dev->server_command_queue.pvdev,
-					  &v4l2_evt);
-	D("%s v4l2_event_queue: type = 0x%x\n", __func__, v4l2_evt.type);
-	mutex_unlock(&server_dev->server_queue_lock);
-
-	/* wait for config return status */
-	D("Waiting for config status\n");
-	rc = wait_event_interruptible_timeout(queue->wait,
-		!list_empty_careful(&queue->list),
-		msecs_to_jiffies(out->timeout_ms));
-	D("Waiting is over for config status\n");
-	if (list_empty_careful(&queue->list)) {
-		if (!rc)
-			rc = -ETIMEDOUT;
-		if (rc < 0) {
-			kfree(isp_event);
-			pr_err("%s: wait_event error %d\n", __func__, rc);
-			return rc;
-		}
-	}
-
-	rcmd = msm_dequeue(queue, list_control);
-	BUG_ON(!rcmd);
-	D("%s Finished servicing ioctl\n", __func__);
-
-	ctrlcmd = (struct msm_ctrl_cmd *)(rcmd->command);
-	value = out->value;
-	if (ctrlcmd->length > 0 && value != NULL &&
-	    ctrlcmd->length <= out->length)
-		memcpy(value, ctrlcmd->value, ctrlcmd->length);
-
-	memcpy(out, ctrlcmd, sizeof(struct msm_ctrl_cmd));
-	out->value = value;
-
-	kfree(ctrlcmd);
-	server_dev->server_queue[out->queue_idx].ctrl = NULL;
-
-	free_qcmd(rcmd);
-	kfree(isp_event);
-	D("%s: rc %d\n", __func__, rc);
-	/* rc is the time elapsed. */
-	if (rc >= 0) {
-		/* TODO: Refactor msm_ctrl_cmd::status field */
-		if (out->status == 0)
-			rc = -1;
-		else if (out->status == 1 || out->status == 4)
-			rc = 0;
-		else
-			rc = -EINVAL;
-	}
-	return rc;
-}
-
-/*send open command to server*/
-static int msm_send_open_server(struct msm_cam_v4l2_device *pcam)
-{
-	int rc = 0;
-	struct msm_ctrl_cmd ctrlcmd;
-	D("%s\n", __func__);
-	ctrlcmd.type	   = MSM_V4L2_OPEN;
-	ctrlcmd.timeout_ms = 10000;
-	ctrlcmd.length	 = strnlen(g_server_dev.config_info.config_dev_name[0],
-				MAX_DEV_NAME_LEN)+1;
-	ctrlcmd.value    = (char *)g_server_dev.config_info.config_dev_name[0];
-	ctrlcmd.vnode_id = pcam->vnode_id;
-	ctrlcmd.queue_idx = pcam->server_queue_idx;
-	ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
-
-	/* send command to config thread in usersspace, and get return value */
-	rc = msm_server_control(&g_server_dev, &ctrlcmd);
-
-	return rc;
-}
-
-static int msm_send_close_server(struct msm_cam_v4l2_device *pcam)
-{
-	int rc = 0;
-	struct msm_ctrl_cmd ctrlcmd;
-	D("%s\n", __func__);
-	ctrlcmd.type	   = MSM_V4L2_CLOSE;
-	ctrlcmd.timeout_ms = 10000;
-	ctrlcmd.length	 = strnlen(g_server_dev.config_info.config_dev_name[0],
-				MAX_DEV_NAME_LEN)+1;
-	ctrlcmd.value    = (char *)g_server_dev.config_info.config_dev_name[0];
-	ctrlcmd.vnode_id = pcam->vnode_id;
-	ctrlcmd.queue_idx = pcam->server_queue_idx;
-	ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
-
-	/* send command to config thread in usersspace, and get return value */
-	rc = msm_server_control(&g_server_dev, &ctrlcmd);
-
-	return rc;
-}
-
-static int msm_server_set_fmt(struct msm_cam_v4l2_device *pcam, int idx,
-				 struct v4l2_format *pfmt)
-{
-	int rc = 0;
-	int i = 0;
-	struct v4l2_pix_format *pix = &pfmt->fmt.pix;
-	struct msm_ctrl_cmd ctrlcmd;
-	struct img_plane_info plane_info;
-
-	plane_info.width = pix->width;
-	plane_info.height = pix->height;
-	plane_info.pixelformat = pix->pixelformat;
-	plane_info.buffer_type = pfmt->type;
-	plane_info.ext_mode = pcam->dev_inst[idx]->image_mode;
-	plane_info.num_planes = 1;
-	D("%s: %d, %d, 0x%x\n", __func__,
-		pfmt->fmt.pix.width, pfmt->fmt.pix.height,
-		pfmt->fmt.pix.pixelformat);
-
-	if (pfmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		D("%s, Attention! Wrong buf-type %d\n", __func__, pfmt->type);
-
-	for (i = 0; i < pcam->num_fmts; i++)
-		if (pcam->usr_fmts[i].fourcc == pix->pixelformat)
-			break;
-	if (i == pcam->num_fmts) {
-		pr_err("%s: User requested pixelformat %x not supported\n",
-						__func__, pix->pixelformat);
-		return -EINVAL;
-	}
-
-	ctrlcmd.type       = MSM_V4L2_VID_CAP_TYPE;
-	ctrlcmd.length     = sizeof(struct img_plane_info);
-	ctrlcmd.value      = (void *)&plane_info;
-	ctrlcmd.timeout_ms = 10000;
-	ctrlcmd.vnode_id   = pcam->vnode_id;
-	ctrlcmd.queue_idx = pcam->server_queue_idx;
-	ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
-
-	/* send command to config thread in usersspace, and get return value */
-	rc = msm_server_control(&g_server_dev, &ctrlcmd);
-
-	if (rc >= 0) {
-		pcam->dev_inst[idx]->vid_fmt = *pfmt;
-		pcam->dev_inst[idx]->sensor_pxlcode
-					= pcam->usr_fmts[i].pxlcode;
-		D("%s:inst=0x%x,idx=%d,width=%d,heigth=%d\n",
-			 __func__, (u32)pcam->dev_inst[idx], idx,
-			 pcam->dev_inst[idx]->vid_fmt.fmt.pix.width,
-			 pcam->dev_inst[idx]->vid_fmt.fmt.pix.height);
-		pcam->dev_inst[idx]->plane_info = plane_info;
-	}
-
-	return rc;
-}
-
-static int msm_server_set_fmt_mplane(struct msm_cam_v4l2_device *pcam, int idx,
-				 struct v4l2_format *pfmt)
-{
-	int rc = 0;
-	int i = 0;
-	struct v4l2_pix_format_mplane *pix_mp = &pfmt->fmt.pix_mp;
-	struct msm_ctrl_cmd ctrlcmd;
-	struct img_plane_info plane_info;
-
-	plane_info.width = pix_mp->width;
-	plane_info.height = pix_mp->height;
-	plane_info.pixelformat = pix_mp->pixelformat;
-	plane_info.buffer_type = pfmt->type;
-	plane_info.ext_mode = pcam->dev_inst[idx]->image_mode;
-	plane_info.num_planes = pix_mp->num_planes;
-	if (plane_info.num_planes <= 0 ||
-		plane_info.num_planes > VIDEO_MAX_PLANES) {
-		pr_err("%s Invalid number of planes set %d", __func__,
-				plane_info.num_planes);
-		return -EINVAL;
-	}
-	D("%s: %d, %d, 0x%x\n", __func__,
-		pfmt->fmt.pix_mp.width, pfmt->fmt.pix_mp.height,
-		pfmt->fmt.pix_mp.pixelformat);
-
-	if (pfmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
-		pr_err("%s, Attention! Wrong buf-type %d\n",
-			__func__, pfmt->type);
-		return -EINVAL;
-	}
-
-	for (i = 0; i < pcam->num_fmts; i++)
-		if (pcam->usr_fmts[i].fourcc == pix_mp->pixelformat)
-			break;
-	if (i == pcam->num_fmts) {
-		pr_err("%s: User requested pixelformat %x not supported\n",
-						__func__, pix_mp->pixelformat);
-		return -EINVAL;
-	}
-
-	ctrlcmd.type       = MSM_V4L2_VID_CAP_TYPE;
-	ctrlcmd.length     = sizeof(struct img_plane_info);
-	ctrlcmd.value      = (void *)&plane_info;
-	ctrlcmd.timeout_ms = 10000;
-	ctrlcmd.vnode_id   = pcam->vnode_id;
-	ctrlcmd.queue_idx = pcam->server_queue_idx;
-
-	/* send command to config thread in usersspace, and get return value */
-	rc = msm_server_control(&g_server_dev, &ctrlcmd);
-	if (rc >= 0) {
-		pcam->dev_inst[idx]->vid_fmt = *pfmt;
-		pcam->dev_inst[idx]->sensor_pxlcode
-					= pcam->usr_fmts[i].pxlcode;
-		D("%s:inst=0x%x,idx=%d,width=%d,heigth=%d\n",
-			 __func__, (u32)pcam->dev_inst[idx], idx,
-			 pcam->dev_inst[idx]->vid_fmt.fmt.pix_mp.width,
-			 pcam->dev_inst[idx]->vid_fmt.fmt.pix_mp.height);
-		pcam->dev_inst[idx]->plane_info = plane_info;
-	}
-
-	return rc;
-}
-
-static int msm_server_streamon(struct msm_cam_v4l2_device *pcam, int idx)
-{
-	int rc = 0;
-	struct msm_ctrl_cmd ctrlcmd;
-	D("%s\n", __func__);
-	ctrlcmd.type	   = MSM_V4L2_STREAM_ON;
-	ctrlcmd.timeout_ms = 10000;
-	ctrlcmd.length	 = 0;
-	ctrlcmd.value    = NULL;
-	ctrlcmd.stream_type = pcam->dev_inst[idx]->image_mode;
-	ctrlcmd.vnode_id = pcam->vnode_id;
-	ctrlcmd.queue_idx = pcam->server_queue_idx;
-	ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
-
-
-	/* send command to config thread in usersspace, and get return value */
-	rc = msm_server_control(&g_server_dev, &ctrlcmd);
-
-	return rc;
-}
-
-static int msm_server_streamoff(struct msm_cam_v4l2_device *pcam, int idx)
-{
-	int rc = 0;
-	struct msm_ctrl_cmd ctrlcmd;
-
-	D("%s, pcam = 0x%x\n", __func__, (u32)pcam);
-	ctrlcmd.type        = MSM_V4L2_STREAM_OFF;
-	ctrlcmd.timeout_ms  = 10000;
-	ctrlcmd.length      = 0;
-	ctrlcmd.value       = NULL;
-	ctrlcmd.stream_type = pcam->dev_inst[idx]->image_mode;
-	ctrlcmd.vnode_id = pcam->vnode_id;
-	ctrlcmd.queue_idx = pcam->server_queue_idx;
-	ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
-
-	/* send command to config thread in usersspace, and get return value */
-	rc = msm_server_control(&g_server_dev, &ctrlcmd);
-
-	return rc;
-}
-
-static int msm_server_proc_ctrl_cmd(struct msm_cam_v4l2_device *pcam,
-				 struct v4l2_control *ctrl, int is_set_cmd)
-{
-	int rc = 0;
-	struct msm_ctrl_cmd ctrlcmd, *tmp_cmd;
-	uint8_t *ctrl_data = NULL;
-	void __user *uptr_cmd;
-	void __user *uptr_value;
-	uint32_t cmd_len = sizeof(struct msm_ctrl_cmd);
-	uint32_t value_len;
-
-	tmp_cmd = (struct msm_ctrl_cmd *)ctrl->value;
-	uptr_cmd = (void __user *)ctrl->value;
-	uptr_value = (void __user *)tmp_cmd->value;
-	value_len = tmp_cmd->length;
-
-	D("%s: cmd type = %d, up1=0x%x, ulen1=%d, up2=0x%x, ulen2=%d\n",
-		__func__, tmp_cmd->type, (uint32_t)uptr_cmd, cmd_len,
-		(uint32_t)uptr_value, tmp_cmd->length);
-
-	ctrl_data = kzalloc(value_len+cmd_len, GFP_KERNEL);
-	if (ctrl_data == 0) {
-		pr_err("%s could not allocate memory\n", __func__);
-		rc = -ENOMEM;
-		goto end;
-	}
-	tmp_cmd = (struct msm_ctrl_cmd *)ctrl_data;
-	if (copy_from_user((void *)ctrl_data, uptr_cmd,
-					cmd_len)) {
-		pr_err("%s: copy_from_user failed.\n", __func__);
-		rc = -EINVAL;
-		goto end;
-	}
-	tmp_cmd->value = (void *)(ctrl_data+cmd_len);
-	if (uptr_value && tmp_cmd->length > 0) {
-		if (copy_from_user((void *)tmp_cmd->value, uptr_value,
-						value_len)) {
-			pr_err("%s: copy_from_user failed, size=%d\n",
-				__func__, value_len);
-			rc = -EINVAL;
-			goto end;
-		}
-	} else
-	tmp_cmd->value = NULL;
-
-	ctrlcmd.type = MSM_V4L2_SET_CTRL_CMD;
-	ctrlcmd.length = cmd_len + value_len;
-	ctrlcmd.value = (void *)ctrl_data;
-	if (tmp_cmd->timeout_ms > 0)
-		ctrlcmd.timeout_ms = tmp_cmd->timeout_ms;
-	else
-		ctrlcmd.timeout_ms = 1000;
-	ctrlcmd.vnode_id = pcam->vnode_id;
-	ctrlcmd.queue_idx = pcam->server_queue_idx;
-	ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
-	/* send command to config thread in usersspace, and get return value */
-	rc = msm_server_control(&g_server_dev, &ctrlcmd);
-	D("%s: msm_server_control rc=%d\n", __func__, rc);
-	if (rc == 0) {
-		if (uptr_value && tmp_cmd->length > 0 &&
-			copy_to_user((void __user *)uptr_value,
-				(void *)(ctrl_data+cmd_len), tmp_cmd->length)) {
-			pr_err("%s: copy_to_user failed, size=%d\n",
-				__func__, tmp_cmd->length);
-			rc = -EINVAL;
-			goto end;
-		}
-		tmp_cmd->value = uptr_value;
-		if (copy_to_user((void __user *)uptr_cmd,
-			(void *)tmp_cmd, cmd_len)) {
-			pr_err("%s: copy_to_user failed in cpy, size=%d\n",
-				__func__, cmd_len);
-			rc = -EINVAL;
-			goto end;
-		}
-	}
-end:
-	D("%s: END, type = %d, vaddr = 0x%x, vlen = %d, status = %d, rc = %d\n",
-		__func__, tmp_cmd->type, (uint32_t)tmp_cmd->value,
-		tmp_cmd->length, tmp_cmd->status, rc);
-	kfree(ctrl_data);
-	return rc;
-}
-
-static int msm_server_s_ctrl(struct msm_cam_v4l2_device *pcam,
-				 struct v4l2_control *ctrl)
-{
-	int rc = 0;
-	struct msm_ctrl_cmd ctrlcmd;
-	uint8_t ctrl_data[max_control_command_size];
-
-	WARN_ON(ctrl == NULL);
-	if (ctrl == NULL) {
-		pr_err("%s Invalid control\n", __func__);
-		return -EINVAL;
-	}
-	if (ctrl->id == MSM_V4L2_PID_CTRL_CMD)
-		return msm_server_proc_ctrl_cmd(pcam, ctrl, 1);
-
-	memset(ctrl_data, 0, sizeof(ctrl_data));
-
-	ctrlcmd.type = MSM_V4L2_SET_CTRL;
-	ctrlcmd.length = sizeof(struct v4l2_control);
-	ctrlcmd.value = (void *)ctrl_data;
-	memcpy(ctrlcmd.value, ctrl, ctrlcmd.length);
-	ctrlcmd.timeout_ms = 1000;
-	ctrlcmd.vnode_id = pcam->vnode_id;
-	ctrlcmd.queue_idx = pcam->server_queue_idx;
-	ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
-
-	/* send command to config thread in usersspace, and get return value */
-	rc = msm_server_control(&g_server_dev, &ctrlcmd);
-
-	return rc;
-}
-
-static int msm_server_g_ctrl(struct msm_cam_v4l2_device *pcam,
-				 struct v4l2_control *ctrl)
-{
-	int rc = 0;
-	struct msm_ctrl_cmd ctrlcmd;
-	uint8_t ctrl_data[max_control_command_size];
-
-	WARN_ON(ctrl == NULL);
-	if (ctrl == NULL) {
-		pr_err("%s Invalid control\n", __func__);
-		return -EINVAL;
-	}
-	if (ctrl->id == MSM_V4L2_PID_CTRL_CMD)
-		return msm_server_proc_ctrl_cmd(pcam, ctrl, 0);
-
-	memset(ctrl_data, 0, sizeof(ctrl_data));
-
-	ctrlcmd.type = MSM_V4L2_GET_CTRL;
-	ctrlcmd.length = sizeof(struct v4l2_control);
-	ctrlcmd.value = (void *)ctrl_data;
-	memcpy(ctrlcmd.value, ctrl, ctrlcmd.length);
-	ctrlcmd.timeout_ms = 1000;
-	ctrlcmd.vnode_id = pcam->vnode_id;
-	ctrlcmd.queue_idx = pcam->server_queue_idx;
-	ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
-
-	/* send command to config thread in usersspace, and get return value */
-	rc = msm_server_control(&g_server_dev, &ctrlcmd);
-
-	ctrl->value = ((struct v4l2_control *)ctrlcmd.value)->value;
-
-	return rc;
-}
-
-static int msm_server_q_ctrl(struct msm_cam_v4l2_device *pcam,
-			struct v4l2_queryctrl *queryctrl)
-{
-	int rc = 0;
-	struct msm_ctrl_cmd ctrlcmd;
-	uint8_t ctrl_data[max_control_command_size];
-
-	WARN_ON(queryctrl == NULL);
-	memset(ctrl_data, 0, sizeof(ctrl_data));
-
-	ctrlcmd.type = MSM_V4L2_QUERY_CTRL;
-	ctrlcmd.length = sizeof(struct v4l2_queryctrl);
-	ctrlcmd.value = (void *)ctrl_data;
-	memcpy(ctrlcmd.value, queryctrl, ctrlcmd.length);
-	ctrlcmd.timeout_ms = 1000;
-	ctrlcmd.vnode_id = pcam->vnode_id;
-	ctrlcmd.queue_idx = pcam->server_queue_idx;
-	ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
-
-	/* send command to config thread in userspace, and get return value */
-	rc = msm_server_control(&g_server_dev, &ctrlcmd);
-	D("%s: rc = %d\n", __func__, rc);
-
-	if (rc >= 0)
-		memcpy(queryctrl, ctrlcmd.value, sizeof(struct v4l2_queryctrl));
-
-	return rc;
-}
-
-static int msm_server_get_fmt(struct msm_cam_v4l2_device *pcam,
-		 int idx, struct v4l2_format *pfmt)
-{
-	struct v4l2_pix_format *pix = &pfmt->fmt.pix;
-
-	pix->width        = pcam->dev_inst[idx]->vid_fmt.fmt.pix.width;
-	pix->height       = pcam->dev_inst[idx]->vid_fmt.fmt.pix.height;
-	pix->field        = pcam->dev_inst[idx]->vid_fmt.fmt.pix.field;
-	pix->pixelformat  = pcam->dev_inst[idx]->vid_fmt.fmt.pix.pixelformat;
-	pix->bytesperline = pcam->dev_inst[idx]->vid_fmt.fmt.pix.bytesperline;
-	pix->colorspace   = pcam->dev_inst[idx]->vid_fmt.fmt.pix.colorspace;
-	if (pix->bytesperline < 0)
-		return pix->bytesperline;
-
-	pix->sizeimage    = pix->height * pix->bytesperline;
-
-	return 0;
-}
-
-static int msm_server_get_fmt_mplane(struct msm_cam_v4l2_device *pcam,
-		 int idx, struct v4l2_format *pfmt)
-{
-	*pfmt = pcam->dev_inst[idx]->vid_fmt;
-	return 0;
-}
-
-static int msm_server_try_fmt(struct msm_cam_v4l2_device *pcam,
-				 struct v4l2_format *pfmt)
-{
-	int rc = 0;
-	int i = 0;
-	struct v4l2_pix_format *pix = &pfmt->fmt.pix;
-
-	D("%s: 0x%x\n", __func__, pix->pixelformat);
-	if (pfmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-		pr_err("%s: pfmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE!\n",
-							__func__);
-		return -EINVAL;
-	}
-
-	/* check if the format is supported by this host-sensor combo */
-	for (i = 0; i < pcam->num_fmts; i++) {
-		D("%s: usr_fmts.fourcc: 0x%x\n", __func__,
-			pcam->usr_fmts[i].fourcc);
-		if (pcam->usr_fmts[i].fourcc == pix->pixelformat)
-			break;
-	}
-
-	if (i == pcam->num_fmts) {
-		pr_err("%s: Format %x not found\n", __func__, pix->pixelformat);
-		return -EINVAL;
-	}
-	return rc;
-}
-
-static int msm_server_try_fmt_mplane(struct msm_cam_v4l2_device *pcam,
-				 struct v4l2_format *pfmt)
-{
-	int rc = 0;
-	int i = 0;
-	struct v4l2_pix_format_mplane *pix_mp = &pfmt->fmt.pix_mp;
-
-	D("%s: 0x%x\n", __func__, pix_mp->pixelformat);
-	if (pfmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
-		pr_err("%s: Incorrect format type %d ",
-			__func__, pfmt->type);
-		return -EINVAL;
-	}
-
-	/* check if the format is supported by this host-sensor combo */
-	for (i = 0; i < pcam->num_fmts; i++) {
-		D("%s: usr_fmts.fourcc: 0x%x\n", __func__,
-			pcam->usr_fmts[i].fourcc);
-		if (pcam->usr_fmts[i].fourcc == pix_mp->pixelformat)
-			break;
-	}
-
-	if (i == pcam->num_fmts) {
-		pr_err("%s: Format %x not found\n",
-			__func__, pix_mp->pixelformat);
-		return -EINVAL;
-	}
-	return rc;
-}
-
-static int msm_camera_get_crop(struct msm_cam_v4l2_device *pcam,
-				int idx, struct v4l2_crop *crop)
-{
-	int rc = 0;
-	struct msm_ctrl_cmd ctrlcmd;
-
-	BUG_ON(crop == NULL);
-
-	ctrlcmd.type = MSM_V4L2_GET_CROP;
-	ctrlcmd.length = sizeof(struct v4l2_crop);
-	ctrlcmd.value = (void *)crop;
-	ctrlcmd.timeout_ms = 1000;
-	ctrlcmd.vnode_id = pcam->vnode_id;
-	ctrlcmd.queue_idx = pcam->server_queue_idx;
-	ctrlcmd.stream_type = pcam->dev_inst[idx]->image_mode;
-	ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
-
-	/* send command to config thread in userspace, and get return value */
-	rc = msm_server_control(&g_server_dev, &ctrlcmd);
-	D("%s: rc = %d\n", __func__, rc);
-
-	return rc;
-}
-
 /*
  *
  * implementation of v4l2_ioctl_ops
@@ -1011,7 +267,7 @@
 static int msm_camera_v4l2_dqbuf(struct file *f, void *pctx,
 					struct v4l2_buffer *pb)
 {
-	int rc = 0;
+	int rc = 0, i = 0;
 	/* get the camera device */
 	struct msm_cam_v4l2_dev_inst *pcam_inst;
 	pcam_inst = container_of(f->private_data,
@@ -1023,6 +279,27 @@
 	rc = vb2_dqbuf(&pcam_inst->vid_bufq, pb,  f->f_flags & O_NONBLOCK);
 	D("%s, videobuf_dqbuf returns %d\n", __func__, rc);
 
+	if (pb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		/* Reject the buffer if planes array was not allocated */
+		if (pb->m.planes == NULL) {
+			pr_err("%s Planes array is null\n", __func__);
+			return -EINVAL;
+		}
+		for (i = 0; i < pcam_inst->plane_info.num_planes; i++) {
+			pb->m.planes[i].data_offset =
+				pcam_inst->buf_offset[pb->index][i].data_offset;
+			pb->m.planes[i].reserved[0] =
+				pcam_inst->buf_offset[pb->index][i].addr_offset;
+			D("%s stored offsets for plane %d as "
+				"addr offset %d, data offset %d\n",
+				__func__, i, pb->m.planes[i].reserved[0],
+				pb->m.planes[i].data_offset);
+		}
+	} else {
+		D("%s stored reserved info %d\n", __func__, pb->reserved);
+		pb->reserved = pcam_inst->buf_offset[pb->index][0].addr_offset;
+	}
+
 	return rc;
 }
 
@@ -1082,7 +359,7 @@
 		not in use when we free the buffers */
 	mutex_lock(&pcam->vid_lock);
 	pcam_inst->streamon = 0;
-	if (g_server_dev.use_count > 0)
+	if (msm_server_get_usecount() > 0)
 		rc = msm_server_streamoff(pcam, pcam_inst->my_index);
 	mutex_unlock(&pcam->vid_lock);
 	if (rc < 0)
@@ -1226,7 +503,7 @@
 		(void *)pfmt->fmt.pix.priv);
 	WARN_ON(pctx != f->private_data);
 
-	pmctl = msm_camera_get_mctl(pcam->mctl_handle);
+	pmctl = msm_cam_server_get_mctl(pcam->mctl_handle);
 	if (pmctl == NULL)
 		return -EINVAL;
 
@@ -1261,7 +538,7 @@
 	D("%s Inst %p\n", __func__, pcam_inst);
 	WARN_ON(pctx != f->private_data);
 
-	pmctl = msm_camera_get_mctl(pcam->mctl_handle);
+	pmctl = msm_cam_server_get_mctl(pcam->mctl_handle);
 	if (pmctl == NULL)
 		return -EINVAL;
 
@@ -1314,7 +591,7 @@
 	WARN_ON(pctx != f->private_data);
 
 	mutex_lock(&pcam->vid_lock);
-	rc = msm_camera_get_crop(pcam, pcam_inst->my_index, crop);
+	rc = msm_server_get_crop(pcam, pcam_inst->my_index, crop);
 	mutex_unlock(&pcam->vid_lock);
 	return rc;
 }
@@ -1407,55 +684,6 @@
 	return rc;
 }
 
-static int msm_server_v4l2_subscribe_event(struct v4l2_fh *fh,
-			struct v4l2_event_subscription *sub)
-{
-	int rc = 0;
-
-	D("%s: fh = 0x%x, type = 0x%x", __func__, (u32)fh, sub->type);
-	if (sub->type == V4L2_EVENT_ALL) {
-		/*sub->type = MSM_ISP_EVENT_START;*/
-		sub->type = V4L2_EVENT_PRIVATE_START + MSM_CAM_RESP_CTRL;
-		D("sub->type start = 0x%x\n", sub->type);
-		do {
-			rc = v4l2_event_subscribe(fh, sub);
-			if (rc < 0) {
-				D("%s: failed for evtType = 0x%x, rc = %d\n",
-						__func__, sub->type, rc);
-			/* unsubscribe all events here and return */
-			sub->type = V4L2_EVENT_ALL;
-			v4l2_event_unsubscribe(fh, sub);
-			return rc;
-			} else
-				D("%s: subscribed evtType = 0x%x, rc = %d\n",
-						__func__, sub->type, rc);
-			sub->type++;
-			D("sub->type while = 0x%x\n", sub->type);
-		} while (sub->type !=
-			V4L2_EVENT_PRIVATE_START + MSM_CAM_RESP_MAX);
-	} else {
-		D("sub->type not V4L2_EVENT_ALL = 0x%x\n", sub->type);
-		rc = v4l2_event_subscribe(fh, sub);
-		if (rc < 0)
-			D("%s: failed for evtType = 0x%x, rc = %d\n",
-						__func__, sub->type, rc);
-	}
-
-	D("%s: rc = %d\n", __func__, rc);
-	return rc;
-}
-
-static int msm_server_v4l2_unsubscribe_event(struct v4l2_fh *fh,
-			struct v4l2_event_subscription *sub)
-{
-	int rc = 0;
-
-	D("%s: fh = 0x%x\n", __func__, (u32)fh);
-	rc = v4l2_event_unsubscribe(fh, sub);
-	D("%s: rc = %d\n", __func__, rc);
-	return rc;
-}
-
 /* v4l2_ioctl_ops */
 static const struct v4l2_ioctl_ops g_msm_ioctl_ops = {
 	.vidioc_querycap = msm_camera_v4l2_querycap,
@@ -1497,69 +725,10 @@
 	.vidioc_unsubscribe_event = msm_camera_v4l2_unsubscribe_event,
 };
 
-/* open an active camera session to manage the streaming logic */
-static int msm_cam_server_open_session(struct msm_cam_server_dev *ps,
-	struct msm_cam_v4l2_device *pcam)
-{
-	int rc = 0;
-	struct msm_cam_media_controller *pmctl;
-
-	D("%s\n", __func__);
-
-	if (!ps || !pcam) {
-		pr_err("%s NULL pointer passed in!\n", __func__);
-		return rc;
-	}
-
-	/* The number of camera instance should be controlled by the
-		resource manager. Currently supporting one active instance
-		until multiple instances are supported */
-	if (atomic_read(&ps->number_pcam_active) > 0) {
-		pr_err("%s Cannot have more than one active camera %d\n",
-			__func__, atomic_read(&ps->number_pcam_active));
-		return -EINVAL;
-	}
-	/* book keeping this camera session*/
-	ps->pcam_active = pcam;
-	atomic_inc(&ps->number_pcam_active);
-
-	D("config pcam = 0x%p\n", ps->pcam_active);
-
-	/* initialization the media controller module*/
-	msm_mctl_init(pcam);
-
-	/*for single VFE msms (8660, 8960v1), just populate the session
-	with our VFE devices that registered*/
-	pmctl = msm_camera_get_mctl(pcam->mctl_handle);
-	pmctl->axi_sdev = ps->axi_device[0];
-	pmctl->isp_sdev = ps->isp_subdev[0];
-	return rc;
-}
-
-/* close an active camera session to server */
-static int msm_cam_server_close_session(struct msm_cam_server_dev *ps,
-	struct msm_cam_v4l2_device *pcam)
-{
-	int rc = 0;
-	D("%s\n", __func__);
-
-	if (!ps || !pcam) {
-		D("%s NULL pointer passed in!\n", __func__);
-		return rc;
-	}
-
-
-	atomic_dec(&ps->number_pcam_active);
-	ps->pcam_active = NULL;
-
-	msm_mctl_free(pcam);
-	return rc;
-}
 /* v4l2_file_operations */
 static int msm_open(struct file *f)
 {
-	int i;
-	int rc = -EINVAL;
+	int i, rc = -EINVAL;
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 	int ion_client_created = 0;
 #endif
@@ -1569,7 +738,6 @@
 	struct msm_cam_v4l2_device *pcam  = video_drvdata(f);
 	struct msm_cam_v4l2_dev_inst *pcam_inst;
 	struct msm_cam_media_controller *pmctl = NULL;
-	struct msm_cam_server_queue *queue = NULL;
 
 	D("%s\n", __func__);
 
@@ -1577,7 +745,7 @@
 		pr_err("%s NULL pointer passed in!\n", __func__);
 		return rc;
 	}
-	if (!g_server_dev.use_count) {
+	if (!msm_server_get_usecount()) {
 		pr_err("%s: error, daemon not yet started.", __func__);
 		return -EINVAL;
 	}
@@ -1610,24 +778,14 @@
 			pcam_inst->my_index,
 			pcam->vnode_id, pcam->use_count);
 	pcam->use_count++;
+	D("%s use_count %d\n", __func__, pcam->use_count);
 	if (pcam->use_count == 1) {
-		pcam->server_queue_idx = server_q_idx;
-		queue = &g_server_dev.server_queue[server_q_idx];
-		queue->ctrl = NULL;
-		queue->ctrl_data = kzalloc(sizeof(uint8_t) *
-			max_control_command_size, GFP_KERNEL);
-		msm_queue_init(&queue->ctrl_q, "control");
-		msm_queue_init(&queue->eventData_q, "eventdata");
-		queue->queue_active = 1;
-
-		rc = msm_cam_server_open_session(&g_server_dev, pcam);
+		rc = msm_server_begin_session(pcam, server_q_idx);
 		if (rc < 0) {
-			pr_err("%s: cam_server_open_session failed %d\n",
-			__func__, rc);
-			goto msm_cam_server_open_session_failed;
+			pr_err("%s error starting server session ", __func__);
+			goto msm_cam_server_begin_session_failed;
 		}
-
-		pmctl = msm_camera_get_mctl(pcam->mctl_handle);
+		pmctl = msm_cam_server_get_mctl(pcam->mctl_handle);
 
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 		pmctl->client = msm_ion_client_create(-1, "camera");
@@ -1669,14 +827,14 @@
 
 	if (pcam->use_count == 1) {
 		rc = msm_send_open_server(pcam);
-		if (rc < 0) {
+		if (rc < 0 && rc != -ERESTARTSYS) {
 			pr_err("%s: msm_send_open_server failed %d\n",
 				__func__, rc);
 			goto msm_send_open_server_failed;
 		}
 	}
 	mutex_unlock(&pcam->vid_lock);
-	D("%s: end", __func__);
+	D("%s: end\n", __func__);
 	return rc;
 
 msm_send_open_server_failed:
@@ -1690,29 +848,22 @@
 	if (pcam->use_count == 1) {
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 		if (ion_client_created) {
-			pr_err("%s: destroy ion client", __func__);
+			D("%s: destroy ion client", __func__);
 			kref_put(&pmctl->refcount, msm_release_ion_client);
 		}
 #endif
-		if (msm_cam_server_close_session(&g_server_dev, pcam) < 0)
-			pr_err("%s: msm_cam_server_close_session failed\n",
+		if (msm_server_end_session(pcam) < 0)
+			pr_err("%s: msm_server_end_session failed\n",
 				__func__);
 	}
-msm_cam_server_open_session_failed:
+msm_cam_server_begin_session_failed:
 	if (pcam->use_count == 1) {
-		queue->queue_active = 0;
-		msm_drain_eventq(&queue->eventData_q);
-		kfree(queue->ctrl_data);
-		queue->ctrl_data = NULL;
-		msm_queue_drain(&queue->ctrl_q, list_control);
-		msm_drain_eventq(&queue->eventData_q);
-		queue = NULL;
-
 		pcam->dev_inst[i] = NULL;
 		pcam->use_count = 0;
 	}
 	mutex_unlock(&pcam->vid_lock);
 	kfree(pcam_inst);
+	pr_err("%s: error end", __func__);
 	return rc;
 }
 
@@ -1725,7 +876,7 @@
 	int rc = 0;
 	struct msm_cam_media_controller *mctl;
 
-	mctl = msm_camera_get_mctl(pcam_inst->pcam->mctl_handle);
+	mctl = msm_cam_server_get_mctl(pcam_inst->pcam->mctl_handle);
 	if (!mctl) {
 		pr_err("%s: invalid mctl pointer", __func__);
 		return -EFAULT;
@@ -1783,8 +934,8 @@
 void msm_release_ion_client(struct kref *ref)
 {
 	struct msm_cam_media_controller *mctl = container_of(ref,
-			struct msm_cam_media_controller, refcount);
-	pr_err("%s Calling ion_client_destroy ", __func__);
+		struct msm_cam_media_controller, refcount);
+	pr_err("%s Calling ion_client_destroy\n", __func__);
 	ion_client_destroy(mctl->client);
 }
 
@@ -1793,7 +944,6 @@
 	int rc = 0;
 	struct msm_cam_v4l2_device *pcam;
 	struct msm_cam_v4l2_dev_inst *pcam_inst;
-	struct msm_cam_server_queue *queue;
 	struct msm_cam_media_controller *pmctl;
 	pcam_inst = container_of(f->private_data,
 		struct msm_cam_v4l2_dev_inst, eventHandle);
@@ -1803,7 +953,7 @@
 		return -EINVAL;
 	}
 
-	pmctl = msm_camera_get_mctl(pcam->mctl_handle);
+	pmctl = msm_cam_server_get_mctl(pcam->mctl_handle);
 	if (!pmctl) {
 		pr_err("%s NULL mctl pointer\n", __func__);
 		return -EINVAL;
@@ -1839,33 +989,24 @@
 	f->private_data = NULL;
 
 	if (pcam->use_count == 0) {
-		if (g_server_dev.use_count > 0) {
+		if (msm_server_get_usecount() > 0) {
 			rc = msm_send_close_server(pcam);
 			if (rc < 0)
 				pr_err("msm_send_close_server failed %d\n", rc);
 		}
+
 		if (pmctl->mctl_release) {
 			rc = pmctl->mctl_release(pmctl);
 			if (rc < 0)
 				pr_err("mctl_release fails %d\n", rc);
 		}
+
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 		kref_put(&pmctl->refcount, msm_release_ion_client);
 #endif
-		queue = &g_server_dev.server_queue[pcam->server_queue_idx];
-		queue->queue_active = 0;
-		kfree(queue->ctrl);
-		queue->ctrl = NULL;
-		kfree(queue->ctrl_data);
-		queue->ctrl_data = NULL;
-		msm_queue_drain(&queue->ctrl_q, list_control);
-		msm_drain_eventq(&queue->eventData_q);
-		rc = msm_cam_server_close_session(&g_server_dev, pcam);
+		rc = msm_server_end_session(pcam);
 		if (rc < 0)
-			pr_err("msm_cam_server_close_session fails %d\n", rc);
-
-		if (g_server_dev.use_count == 0)
-			mutex_unlock(&g_server_dev.server_lock);
+			pr_err("msm_server_end_session fails %d\n", rc);
 	}
 	mutex_unlock(&pcam->vid_lock);
 	return rc;
@@ -1900,252 +1041,8 @@
 	return rc;
 }
 
-static unsigned int msm_poll_server(struct file *fp,
-					struct poll_table_struct *wait)
-{
-	int rc = 0;
-
-	D("%s\n", __func__);
-	poll_wait(fp,
-		 &g_server_dev.server_command_queue.eventHandle.events->wait,
-		 wait);
-	if (v4l2_event_pending(&g_server_dev.server_command_queue.eventHandle))
-		rc |= POLLPRI;
-
-	return rc;
-}
-static long msm_ioctl_server(struct file *file, void *fh,
-		bool valid_prio, int cmd, void *arg)
-{
-	int rc = -EINVAL;
-	struct msm_camera_v4l2_ioctl_t *ioctl_ptr = arg;
-	struct msm_camera_info temp_cam_info;
-	struct msm_cam_config_dev_info temp_config_info;
-	struct msm_mctl_node_info temp_mctl_info;
-	int i;
-
-	D("%s: cmd %d\n", __func__, _IOC_NR(cmd));
-
-	switch (cmd) {
-	case MSM_CAM_V4L2_IOCTL_GET_CAMERA_INFO:
-		if (copy_from_user(&temp_cam_info,
-			(void __user *)ioctl_ptr->ioctl_ptr,
-			sizeof(struct msm_camera_info))) {
-			rc = -EINVAL;
-			return rc;
-		}
-		for (i = 0; i < g_server_dev.camera_info.num_cameras; i++) {
-			if (copy_to_user((void __user *)
-				temp_cam_info.video_dev_name[i],
-				g_server_dev.camera_info.video_dev_name[i],
-				strnlen(
-				g_server_dev.camera_info.video_dev_name[i],
-				MAX_DEV_NAME_LEN))) {
-				rc = -EINVAL;
-				return rc;
-			}
-			temp_cam_info.has_3d_support[i] =
-				g_server_dev.camera_info.has_3d_support[i];
-			temp_cam_info.is_internal_cam[i] =
-				g_server_dev.camera_info.is_internal_cam[i];
-			temp_cam_info.s_mount_angle[i] =
-				g_server_dev.camera_info.s_mount_angle[i];
-			temp_cam_info.sensor_type[i] =
-				g_server_dev.camera_info.sensor_type[i];
-
-		}
-		temp_cam_info.num_cameras =
-			g_server_dev.camera_info.num_cameras;
-		if (copy_to_user((void __user *)ioctl_ptr->ioctl_ptr,
-				&temp_cam_info,
-				sizeof(struct msm_camera_info))) {
-					rc = -EINVAL;
-					return rc;
-		}
-		rc = 0;
-		break;
-
-	case MSM_CAM_V4L2_IOCTL_GET_CONFIG_INFO:
-		if (copy_from_user(&temp_config_info,
-				(void __user *)ioctl_ptr->ioctl_ptr,
-				sizeof(struct msm_cam_config_dev_info))) {
-
-			rc = -EINVAL;
-			return rc;
-		}
-		for (i = 0;
-		 i < g_server_dev.config_info.num_config_nodes; i++) {
-			if (copy_to_user(
-			(void __user *)temp_config_info.config_dev_name[i],
-			g_server_dev.config_info.config_dev_name[i],
-			strlen(g_server_dev.config_info.config_dev_name[i]))) {
-				rc = -EINVAL;
-				return rc;
-			}
-		}
-		temp_config_info.num_config_nodes =
-			g_server_dev.config_info.num_config_nodes;
-		if (copy_to_user((void __user *)ioctl_ptr->ioctl_ptr,
-							  &temp_config_info,
-				sizeof(struct msm_cam_config_dev_info))) {
-			rc = -EINVAL;
-			return rc;
-		}
-		rc = 0;
-		break;
-	case MSM_CAM_V4L2_IOCTL_GET_MCTL_INFO:
-		if (copy_from_user(&temp_mctl_info,
-				(void __user *)ioctl_ptr->ioctl_ptr,
-				sizeof(struct msm_mctl_node_info))) {
-			rc = -EINVAL;
-			return rc;
-		}
-		for (i = 0; i < g_server_dev.mctl_node_info.num_mctl_nodes;
-				i++) {
-			if (copy_to_user((void __user *)
-			temp_mctl_info.mctl_node_name[i],
-			g_server_dev.mctl_node_info.mctl_node_name[i], strnlen(
-			g_server_dev.mctl_node_info.mctl_node_name[i],
-			MAX_DEV_NAME_LEN))) {
-				rc = -EINVAL;
-				return rc;
-			}
-		}
-		temp_mctl_info.num_mctl_nodes =
-			g_server_dev.mctl_node_info.num_mctl_nodes;
-		if (copy_to_user((void __user *)ioctl_ptr->ioctl_ptr,
-							  &temp_mctl_info,
-				sizeof(struct msm_mctl_node_info))) {
-			rc = -EINVAL;
-			return rc;
-		}
-		rc = 0;
-	break;
-
-	case MSM_CAM_V4L2_IOCTL_CTRL_CMD_DONE:
-		D("%s: MSM_CAM_IOCTL_CTRL_CMD_DONE\n", __func__);
-		rc = msm_ctrl_cmd_done(arg);
-		break;
-
-	case MSM_CAM_V4L2_IOCTL_GET_EVENT_PAYLOAD: {
-		struct msm_queue_cmd *event_cmd;
-		struct msm_isp_event_ctrl u_isp_event;
-		struct msm_isp_event_ctrl *k_isp_event;
-		struct msm_device_queue *queue;
-		void __user *u_ctrl_value = NULL;
-		if (copy_from_user(&u_isp_event,
-			(void __user *)ioctl_ptr->ioctl_ptr,
-			sizeof(struct msm_isp_event_ctrl))) {
-			rc = -EINVAL;
-			return rc;
-		}
-		queue = &g_server_dev.server_queue
-			[u_isp_event.isp_data.ctrl.queue_idx].eventData_q;
-		event_cmd = msm_dequeue(queue, list_eventdata);
-		if (!event_cmd) {
-			pr_err("%s: No event payload\n", __func__);
-			rc = -EINVAL;
-			return rc;
-		}
-		k_isp_event = (struct msm_isp_event_ctrl *)
-				event_cmd->command;
-		free_qcmd(event_cmd);
-
-		/* Save the pointer of the user allocated command buffer*/
-		u_ctrl_value = u_isp_event.isp_data.ctrl.value;
-
-		/* Copy the event structure into user struct*/
-		u_isp_event = *k_isp_event;
-
-		/* Restore the saved pointer of the user
-		 * allocated command buffer. */
-		u_isp_event.isp_data.ctrl.value = u_ctrl_value;
-
-		/* Copy the ctrl cmd, if present*/
-		if (k_isp_event->isp_data.ctrl.length > 0) {
-			void *k_ctrl_value =
-				k_isp_event->isp_data.ctrl.value;
-			if (copy_to_user(u_ctrl_value, k_ctrl_value,
-				 k_isp_event->isp_data.ctrl.length)) {
-				rc = -EINVAL;
-				break;
-			}
-		}
-		if (copy_to_user((void __user *)ioctl_ptr->ioctl_ptr,
-							  &u_isp_event,
-				sizeof(struct msm_isp_event_ctrl))) {
-			rc = -EINVAL;
-			return rc;
-		}
-		rc = 0;
-		break;
-	}
-	default:
-		pr_err("%s: Invalid IOCTL = %d", __func__, cmd);
-		break;
-	}
-	return rc;
-}
-
-static int msm_open_server(struct file *fp)
-{
-	int rc = 0;
-	D("%s: open %s\n", __func__, fp->f_path.dentry->d_name.name);
-	mutex_lock(&g_server_dev.server_lock);
-	g_server_dev.use_count++;
-	if (g_server_dev.use_count == 1)
-		fp->private_data =
-			&g_server_dev.server_command_queue.eventHandle;
-	mutex_unlock(&g_server_dev.server_lock);
-	return rc;
-}
-
-static unsigned int msm_poll_config(struct file *fp,
-					struct poll_table_struct *wait)
-{
-	int rc = 0;
-	struct msm_cam_config_dev *config = fp->private_data;
-	if (config == NULL)
-		return -EINVAL;
-
-	D("%s\n", __func__);
-
-	poll_wait(fp,
-	&config->config_stat_event_queue.eventHandle.events->wait, wait);
-	if (v4l2_event_pending(&config->config_stat_event_queue.eventHandle))
-		rc |= POLLPRI;
-	return rc;
-}
-
-static int msm_close_server(struct file *fp)
-{
-	struct v4l2_event_subscription sub;
-	D("%s\n", __func__);
-	mutex_lock(&g_server_dev.server_lock);
-	if (g_server_dev.use_count > 0)
-		g_server_dev.use_count--;
-	mutex_unlock(&g_server_dev.server_lock);
-	if (g_server_dev.use_count == 0) {
-		if (g_server_dev.pcam_active) {
-			struct v4l2_event v4l2_ev;
-			mutex_lock(&g_server_dev.server_lock);
-
-			v4l2_ev.type = V4L2_EVENT_PRIVATE_START
-				+ MSM_CAM_APP_NOTIFY_ERROR_EVENT;
-			ktime_get_ts(&v4l2_ev.timestamp);
-			v4l2_event_queue(
-				g_server_dev.pcam_active->pvdev, &v4l2_ev);
-		}
-	sub.type = V4L2_EVENT_ALL;
-	msm_server_v4l2_unsubscribe_event(
-		&g_server_dev.server_command_queue.eventHandle, &sub);
-	}
-	return 0;
-}
-
-
-static long msm_v4l2_evt_notify(struct msm_cam_media_controller *mctl,
-		unsigned int cmd, unsigned long evt)
+long msm_v4l2_evt_notify(struct msm_cam_media_controller *mctl,
+	unsigned int cmd, unsigned long evt)
 {
 	struct v4l2_event v4l2_ev;
 	struct msm_cam_v4l2_device *pcam = NULL;
@@ -2167,280 +1064,6 @@
 	return 0;
 }
 
-static long msm_ioctl_config(struct file *fp, unsigned int cmd,
-	unsigned long arg)
-{
-
-	int rc = 0;
-	struct v4l2_event ev;
-	struct msm_cam_config_dev *config_cam = fp->private_data;
-	struct v4l2_event_subscription temp_sub;
-
-	D("%s: cmd %d\n", __func__, _IOC_NR(cmd));
-
-	switch (cmd) {
-	/* memory management shall be handeld here*/
-	case MSM_CAM_IOCTL_REGISTER_PMEM:
-		return msm_register_pmem(
-			&config_cam->p_mctl->stats_info.pmem_stats_list,
-			(void __user *)arg, config_cam->p_mctl->client);
-		break;
-
-	case MSM_CAM_IOCTL_UNREGISTER_PMEM:
-		return msm_pmem_table_del(
-			&config_cam->p_mctl->stats_info.pmem_stats_list,
-			(void __user *)arg, config_cam->p_mctl->client);
-		break;
-
-	case VIDIOC_SUBSCRIBE_EVENT:
-		if (copy_from_user(&temp_sub,
-			(void __user *)arg,
-			sizeof(struct v4l2_event_subscription))) {
-			rc = -EINVAL;
-			return rc;
-		}
-		rc = msm_server_v4l2_subscribe_event
-			(&config_cam->config_stat_event_queue.eventHandle,
-			&temp_sub);
-		if (rc < 0) {
-			pr_err("%s: cam_v4l2_subscribe_event failed rc=%d\n",
-				__func__, rc);
-			return rc;
-		}
-		break;
-
-	case VIDIOC_UNSUBSCRIBE_EVENT:
-		if (copy_from_user(&temp_sub, (void __user *)arg,
-			sizeof(struct v4l2_event_subscription))) {
-			rc = -EINVAL;
-			return rc;
-		}
-		rc = msm_server_v4l2_unsubscribe_event
-			(&config_cam->config_stat_event_queue.eventHandle,
-			&temp_sub);
-		if (rc < 0) {
-			pr_err("%s: server_unsubscribe_event failed rc=%d\n",
-				__func__, rc);
-			return rc;
-		}
-		break;
-
-	case VIDIOC_DQEVENT: {
-		void __user *u_msg_value = NULL, *user_ptr = NULL;
-		struct msm_isp_event_ctrl u_isp_event;
-		struct msm_isp_event_ctrl *k_isp_event;
-
-		/* First, copy the v4l2 event structure from userspace */
-		D("%s: VIDIOC_DQEVENT\n", __func__);
-		if (copy_from_user(&ev, (void __user *)arg,
-				sizeof(struct v4l2_event)))
-			break;
-		/* Next, get the pointer to event_ctrl structure
-		 * embedded inside the v4l2_event.u.data array. */
-		user_ptr = (void __user *)(*((uint32_t *)ev.u.data));
-
-		/* Next, copy the userspace event ctrl structure */
-		if (copy_from_user((void *)&u_isp_event, user_ptr,
-				   sizeof(struct msm_isp_event_ctrl))) {
-			break;
-		}
-		/* Save the pointer of the user allocated command buffer*/
-		u_msg_value = u_isp_event.isp_data.isp_msg.data;
-
-		/* Dequeue the event queued into the v4l2 queue*/
-		rc = v4l2_event_dequeue(
-			&config_cam->config_stat_event_queue.eventHandle,
-			&ev, fp->f_flags & O_NONBLOCK);
-		if (rc < 0) {
-			pr_err("no pending events?");
-			break;
-		}
-		/* Use k_isp_event to point to the event_ctrl structure
-		 * embedded inside v4l2_event.u.data */
-		k_isp_event = (struct msm_isp_event_ctrl *)
-				(*((uint32_t *)ev.u.data));
-		/* Copy the event structure into user struct. */
-		u_isp_event = *k_isp_event;
-		if (ev.type != (V4L2_EVENT_PRIVATE_START +
-				MSM_CAM_RESP_DIV_FRAME_EVT_MSG) &&
-				ev.type != (V4L2_EVENT_PRIVATE_START +
-				MSM_CAM_RESP_MCTL_PP_EVENT)) {
-
-			/* Restore the saved pointer of the
-			 * user allocated command buffer. */
-			u_isp_event.isp_data.isp_msg.data = u_msg_value;
-
-			if (ev.type == (V4L2_EVENT_PRIVATE_START +
-					MSM_CAM_RESP_STAT_EVT_MSG)) {
-				if (k_isp_event->isp_data.isp_msg.len > 0) {
-					void *k_msg_value =
-					k_isp_event->isp_data.isp_msg.data;
-					if (copy_to_user(u_msg_value,
-							k_msg_value,
-					 k_isp_event->isp_data.isp_msg.len)) {
-						rc = -EINVAL;
-						break;
-					}
-					kfree(k_msg_value);
-				}
-			}
-		}
-		/* Copy the event ctrl structure back
-		 * into user's structure. */
-		if (copy_to_user(user_ptr,
-				(void *)&u_isp_event, sizeof(
-				struct msm_isp_event_ctrl))) {
-			rc = -EINVAL;
-			break;
-		}
-		kfree(k_isp_event);
-
-		/* Copy the v4l2_event structure back to the user*/
-		if (copy_to_user((void __user *)arg, &ev,
-				sizeof(struct v4l2_event))) {
-			rc = -EINVAL;
-			break;
-		}
-		}
-
-		break;
-
-	case MSM_CAM_IOCTL_V4L2_EVT_NOTIFY:
-		rc = msm_v4l2_evt_notify(config_cam->p_mctl, cmd, arg);
-		break;
-
-	case MSM_CAM_IOCTL_SET_MEM_MAP_INFO:
-		if (copy_from_user(&config_cam->mem_map, (void __user *)arg,
-				sizeof(struct msm_mem_map_info)))
-			rc = -EINVAL;
-		break;
-
-	default:{
-		/* For the rest of config command, forward to media controller*/
-		struct msm_cam_media_controller *p_mctl = config_cam->p_mctl;
-		if (p_mctl && p_mctl->mctl_cmd) {
-			rc = config_cam->p_mctl->mctl_cmd(p_mctl, cmd, arg);
-		} else {
-			rc = -EINVAL;
-			pr_err("%s: media controller is null\n", __func__);
-		}
-
-		break;
-	} /* end of default*/
-	} /* end of switch*/
-	return rc;
-}
-
-static int msm_mmap_config(struct file *fp, struct vm_area_struct *vma)
-{
-	struct msm_cam_config_dev *config_cam = fp->private_data;
-	int rc = 0;
-	int phyaddr;
-	int retval;
-	unsigned long size;
-
-	D("%s: phy_addr=0x%x", __func__, config_cam->mem_map.cookie);
-	phyaddr = (int)config_cam->mem_map.cookie;
-	if (!phyaddr) {
-		pr_err("%s: no physical memory to map", __func__);
-		return -EFAULT;
-	}
-	memset(&config_cam->mem_map, 0,
-		sizeof(struct msm_mem_map_info));
-	size = vma->vm_end - vma->vm_start;
-	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-	retval = remap_pfn_range(vma, vma->vm_start,
-					phyaddr >> PAGE_SHIFT,
-					size, vma->vm_page_prot);
-	if (retval) {
-		pr_err("%s: remap failed, rc = %d",
-					__func__, retval);
-		rc = -ENOMEM;
-		goto end;
-	}
-	D("%s: phy_addr=0x%x: %08lx-%08lx, pgoff %08lx\n",
-			__func__, (uint32_t)phyaddr,
-			vma->vm_start, vma->vm_end, vma->vm_pgoff);
-end:
-	return rc;
-}
-
-static int msm_open_config(struct inode *inode, struct file *fp)
-{
-	int rc;
-	struct msm_cam_config_dev *config_cam = container_of(inode->i_cdev,
-		struct msm_cam_config_dev, config_cdev);
-
-	D("%s: open %s\n", __func__, fp->f_path.dentry->d_name.name);
-
-	rc = nonseekable_open(inode, fp);
-	if (rc < 0) {
-		pr_err("%s: nonseekable_open error %d\n", __func__, rc);
-		return rc;
-	}
-	config_cam->use_count++;
-
-	/*config_cam->isp_subdev = g_server_dev.pcam_active->mctl.isp_sdev;*/
-	/* assume there is only one active camera possible*/
-	config_cam->p_mctl =
-		msm_camera_get_mctl(g_server_dev.pcam_active->mctl_handle);
-
-	INIT_HLIST_HEAD(&config_cam->p_mctl->stats_info.pmem_stats_list);
-	spin_lock_init(&config_cam->p_mctl->stats_info.pmem_stats_spinlock);
-
-	config_cam->p_mctl->config_device = config_cam;
-#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
-	kref_get(&config_cam->p_mctl->refcount);
-#endif
-	fp->private_data = config_cam;
-	return rc;
-}
-
-static int msm_close_config(struct inode *node, struct file *f)
-{
-#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
-	struct msm_cam_config_dev *config_cam = f->private_data;
-	D("%s Decrementing ref count of config node ", __func__);
-	kref_put(&config_cam->p_mctl->refcount, msm_release_ion_client);
-#endif
-	return 0;
-}
-
-static struct v4l2_file_operations g_msm_fops = {
-	.owner   = THIS_MODULE,
-	.open	= msm_open,
-	.poll	= msm_poll,
-	.mmap	= msm_mmap,
-	.release = msm_close,
-	.ioctl   = video_ioctl2,
-};
-
-/* Init a config node for ISP control,
- * which will create a config device (/dev/config0/ and plug in
- * ISP's operation "v4l2_ioctl_ops*"
- */
-static const struct v4l2_file_operations msm_fops_server = {
-	.owner = THIS_MODULE,
-	.open  = msm_open_server,
-	.poll  = msm_poll_server,
-	.unlocked_ioctl = video_ioctl2,
-	.release = msm_close_server,
-};
-
-static const struct v4l2_ioctl_ops msm_ioctl_ops_server = {
-	.vidioc_subscribe_event = msm_server_v4l2_subscribe_event,
-	.vidioc_default = msm_ioctl_server,
-};
-
-static const struct file_operations msm_fops_config = {
-	.owner = THIS_MODULE,
-	.open  = msm_open_config,
-	.poll  = msm_poll_config,
-	.unlocked_ioctl = msm_ioctl_config,
-	.mmap	= msm_mmap_config,
-	.release = msm_close_config,
-};
-
 int msm_setup_v4l2_event_queue(struct v4l2_fh *eventHandle,
 	struct video_device *pvdev)
 {
@@ -2468,309 +1091,14 @@
 	return rc;
 }
 
-static int msm_setup_config_dev(int node, char *device_name)
-{
-	int rc = -ENODEV;
-	struct device *device_config;
-	int dev_num = node;
-	dev_t devno;
-	struct msm_cam_config_dev *config_cam;
-
-	config_cam = kzalloc(sizeof(*config_cam), GFP_KERNEL);
-	if (!config_cam) {
-		pr_err("%s: could not allocate memory for msm_cam_config_device\n",
-			__func__);
-		return -ENOMEM;
-	}
-
-	D("%s\n", __func__);
-
-	devno = MKDEV(MAJOR(msm_devno), dev_num+1);
-	device_config = device_create(msm_class, NULL, devno, NULL, "%s%d",
-		device_name, dev_num);
-
-	if (IS_ERR(device_config)) {
-		rc = PTR_ERR(device_config);
-		pr_err("%s: error creating device: %d\n", __func__, rc);
-		goto config_setup_fail;
-	}
-
-	cdev_init(&config_cam->config_cdev, &msm_fops_config);
-	config_cam->config_cdev.owner = THIS_MODULE;
-
-	rc = cdev_add(&config_cam->config_cdev, devno, 1);
-	if (rc < 0) {
-		pr_err("%s: error adding cdev: %d\n", __func__, rc);
-		device_destroy(msm_class, devno);
-		goto config_setup_fail;
-	}
-
-	g_server_dev.config_info.config_dev_name[dev_num] =
-		dev_name(device_config);
-	D("%s Connected config device %s\n", __func__,
-		g_server_dev.config_info.config_dev_name[dev_num]);
-	g_server_dev.config_info.config_dev_id[dev_num] = dev_num;
-
-	config_cam->config_stat_event_queue.pvdev = video_device_alloc();
-	if (config_cam->config_stat_event_queue.pvdev == NULL) {
-		pr_err("%s: video_device_alloc failed\n", __func__);
-		goto config_setup_fail;
-	}
-
-	rc = msm_setup_v4l2_event_queue(
-		&config_cam->config_stat_event_queue.eventHandle,
-		config_cam->config_stat_event_queue.pvdev);
-	if (rc < 0) {
-		pr_err("%s failed to initialize event queue\n", __func__);
-		video_device_release(config_cam->config_stat_event_queue.pvdev);
-		goto config_setup_fail;
-	}
-
-	return rc;
-
-config_setup_fail:
-	kfree(config_cam);
-	return rc;
-}
-
-static void msm_cam_server_subdev_notify(struct v4l2_subdev *sd,
-				unsigned int notification, void *arg)
-{
-	int rc = -EINVAL;
-	struct msm_sensor_ctrl_t *s_ctrl;
-	struct msm_camera_sensor_info *sinfo;
-	struct msm_camera_device_platform_data *camdev;
-	uint8_t csid_core = 0;
-
-	if (notification == NOTIFY_CID_CHANGE ||
-		notification == NOTIFY_ISPIF_STREAM ||
-		notification == NOTIFY_PCLK_CHANGE ||
-		notification == NOTIFY_CSIPHY_CFG ||
-		notification == NOTIFY_CSID_CFG ||
-		notification == NOTIFY_CSIC_CFG) {
-		s_ctrl = get_sctrl(sd);
-		sinfo = (struct msm_camera_sensor_info *) s_ctrl->sensordata;
-		camdev = sinfo->pdata;
-		csid_core = camdev->csid_core;
-	}
-
-	switch (notification) {
-	case NOTIFY_CID_CHANGE:
-		/* reconfig the ISPIF*/
-		if (g_server_dev.ispif_device) {
-			struct msm_ispif_params_list ispif_params;
-			ispif_params.len = 1;
-			ispif_params.params[0].intftype = PIX0;
-			ispif_params.params[0].cid_mask = 0x0001;
-			ispif_params.params[0].csid = csid_core;
-
-			rc = v4l2_subdev_call(
-				g_server_dev.ispif_device, core, ioctl,
-				VIDIOC_MSM_ISPIF_CFG, &ispif_params);
-			if (rc < 0)
-				return;
-		}
-		break;
-	case NOTIFY_ISPIF_STREAM:
-		/* call ISPIF stream on/off */
-		rc = v4l2_subdev_call(g_server_dev.ispif_device, video,
-				s_stream, (int)arg);
-		if (rc < 0)
-			return;
-
-		break;
-	case NOTIFY_ISP_MSG_EVT:
-	case NOTIFY_VFE_MSG_OUT:
-	case NOTIFY_VFE_MSG_STATS:
-	case NOTIFY_VFE_MSG_COMP_STATS:
-	case NOTIFY_VFE_BUF_EVT:
-	case NOTIFY_VFE_BUF_FREE_EVT:
-		if (g_server_dev.isp_subdev[0] &&
-			g_server_dev.isp_subdev[0]->isp_notify) {
-			rc = g_server_dev.isp_subdev[0]->isp_notify(
-				g_server_dev.vfe_device[0], notification, arg);
-		}
-		break;
-	case NOTIFY_VPE_MSG_EVT: {
-		struct msm_cam_media_controller *pmctl =
-		(struct msm_cam_media_controller *)
-		v4l2_get_subdev_hostdata(sd);
-		struct msm_vpe_resp *vdata = (struct msm_vpe_resp *)arg;
-		msm_mctl_pp_notify(pmctl,
-		(struct msm_mctl_pp_frame_info *)
-		vdata->extdata);
-		break;
-	}
-	case NOTIFY_VFE_IRQ:{
-		struct msm_vfe_cfg_cmd cfg_cmd;
-		struct msm_camvfe_params vfe_params;
-		cfg_cmd.cmd_type = CMD_VFE_PROCESS_IRQ;
-		vfe_params.vfe_cfg = &cfg_cmd;
-		vfe_params.data = arg;
-		rc = v4l2_subdev_call(g_server_dev.vfe_device[0],
-			core, ioctl, 0, &vfe_params);
-	}
-		break;
-	case NOTIFY_AXI_IRQ:
-		rc = v4l2_subdev_call(g_server_dev.axi_device[0],
-			core, ioctl, VIDIOC_MSM_AXI_IRQ, arg);
-		break;
-	case NOTIFY_PCLK_CHANGE:
-		if (g_server_dev.axi_device[0])
-			rc = v4l2_subdev_call(g_server_dev.axi_device[0], video,
-				s_crystal_freq, *(uint32_t *)arg, 0);
-		else
-			rc = v4l2_subdev_call(g_server_dev.vfe_device[0], video,
-				s_crystal_freq, *(uint32_t *)arg, 0);
-		break;
-	case NOTIFY_CSIPHY_CFG:
-		rc = v4l2_subdev_call(g_server_dev.csiphy_device[csid_core],
-			core, ioctl, VIDIOC_MSM_CSIPHY_CFG, arg);
-		break;
-	case NOTIFY_CSID_CFG:
-		rc = v4l2_subdev_call(g_server_dev.csid_device[csid_core],
-			core, ioctl, VIDIOC_MSM_CSID_CFG, arg);
-		break;
-	case NOTIFY_CSIC_CFG:
-		rc = v4l2_subdev_call(g_server_dev.csic_device[csid_core],
-			core, ioctl, VIDIOC_MSM_CSIC_CFG, arg);
-		break;
-	default:
-		break;
-	}
-
-	return;
-}
-
-int msm_cam_register_subdev_node(struct v4l2_subdev *sd,
-	enum msm_cam_subdev_type sdev_type, uint8_t index)
-{
-	struct video_device *vdev;
-	int err = 0;
-
-	if (sdev_type == CSIPHY_DEV) {
-		if (index >= MAX_NUM_CSIPHY_DEV)
-			return -EINVAL;
-		g_server_dev.csiphy_device[index] = sd;
-	} else if (sdev_type == CSID_DEV) {
-		if (index >= MAX_NUM_CSID_DEV)
-			return -EINVAL;
-		g_server_dev.csid_device[index] = sd;
-	} else if (sdev_type == CSIC_DEV) {
-		if (index >= MAX_NUM_CSIC_DEV)
-			return -EINVAL;
-		g_server_dev.csic_device[index] = sd;
-	} else if (sdev_type == ISPIF_DEV) {
-		g_server_dev.ispif_device = sd;
-	} else if (sdev_type == VFE_DEV) {
-		if (index >= MAX_NUM_VFE_DEV)
-			return -EINVAL;
-		g_server_dev.vfe_device[index] = sd;
-	} else if (sdev_type == VPE_DEV) {
-		if (index >= MAX_NUM_VPE_DEV)
-			return -EINVAL;
-		g_server_dev.vpe_device[index] = sd;
-	} else if (sdev_type == AXI_DEV) {
-		if (index >= MAX_NUM_AXI_DEV)
-			return -EINVAL;
-		g_server_dev.axi_device[index] = sd;
-	}
-
-	err = v4l2_device_register_subdev(&g_server_dev.v4l2_dev, sd);
-	if (err < 0)
-		return err;
-
-	/* Register a device node for every subdev marked with the
-	 * V4L2_SUBDEV_FL_HAS_DEVNODE flag.
-	 */
-	if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE))
-		return err;
-
-	vdev = &sd->devnode;
-	strlcpy(vdev->name, sd->name, sizeof(vdev->name));
-	vdev->v4l2_dev = &g_server_dev.v4l2_dev;
-	vdev->fops = &v4l2_subdev_fops;
-	vdev->release = video_device_release_empty;
-	err = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1,
-						  sd->owner);
-	if (err < 0)
-		return err;
-#if defined(CONFIG_MEDIA_CONTROLLER)
-	sd->entity.v4l.major = VIDEO_MAJOR;
-	sd->entity.v4l.minor = vdev->minor;
-#endif
-	return 0;
-}
-
-static int msm_setup_server_dev(struct platform_device *pdev)
-{
-	int rc = -ENODEV, i;
-
-	D("%s\n", __func__);
-	g_server_dev.server_pdev = pdev;
-	g_server_dev.v4l2_dev.dev = &pdev->dev;
-	g_server_dev.v4l2_dev.notify = msm_cam_server_subdev_notify;
-	rc = v4l2_device_register(g_server_dev.v4l2_dev.dev,
-			&g_server_dev.v4l2_dev);
-	if (rc < 0)
-		return -EINVAL;
-
-	g_server_dev.video_dev = video_device_alloc();
-	if (g_server_dev.video_dev == NULL) {
-		pr_err("%s: video_device_alloc failed\n", __func__);
-		return rc;
-	}
-
-	strlcpy(g_server_dev.video_dev->name, pdev->name,
-			sizeof(g_server_dev.video_dev->name));
-
-	g_server_dev.video_dev->v4l2_dev = &g_server_dev.v4l2_dev;
-	g_server_dev.video_dev->fops = &msm_fops_server;
-	g_server_dev.video_dev->ioctl_ops = &msm_ioctl_ops_server;
-	g_server_dev.video_dev->release   = video_device_release;
-	g_server_dev.video_dev->minor = 100;
-	g_server_dev.video_dev->vfl_type = 1;
-
-	video_set_drvdata(g_server_dev.video_dev, &g_server_dev);
-
-	strlcpy(g_server_dev.media_dev.model, "qcamera",
-		sizeof(g_server_dev.media_dev.model));
-	g_server_dev.media_dev.dev = &pdev->dev;
-	rc = media_device_register(&g_server_dev.media_dev);
-	g_server_dev.v4l2_dev.mdev = &g_server_dev.media_dev;
-
-	rc = video_register_device(g_server_dev.video_dev,
-		VFL_TYPE_GRABBER, 100);
-
-	mutex_init(&g_server_dev.server_lock);
-	mutex_init(&g_server_dev.server_queue_lock);
-	g_server_dev.pcam_active = NULL;
-	g_server_dev.camera_info.num_cameras = 0;
-	atomic_set(&g_server_dev.number_pcam_active, 0);
-	g_server_dev.server_evt_id = 0;
-
-	/*initialize fake video device and event queue*/
-
-	g_server_dev.server_command_queue.pvdev = g_server_dev.video_dev;
-	rc = msm_setup_v4l2_event_queue(
-		&g_server_dev.server_command_queue.eventHandle,
-		g_server_dev.server_command_queue.pvdev);
-
-	if (rc < 0) {
-		pr_err("%s failed to initialize event queue\n", __func__);
-		video_device_release(g_server_dev.server_command_queue.pvdev);
-		return rc;
-	}
-
-	for (i = 0; i < MAX_NUM_ACTIVE_CAMERA; i++) {
-		struct msm_cam_server_queue *queue;
-		queue = &g_server_dev.server_queue[i];
-		queue->queue_active = 0;
-		msm_queue_init(&queue->ctrl_q, "control");
-		msm_queue_init(&queue->eventData_q, "eventdata");
-	}
-	return rc;
-}
+static struct v4l2_file_operations g_msm_fops = {
+	.owner   = THIS_MODULE,
+	.open	= msm_open,
+	.poll	= msm_poll,
+	.mmap	= msm_mmap,
+	.release = msm_close,
+	.ioctl   = video_ioctl2,
+};
 
 static int msm_cam_dev_init(struct msm_cam_v4l2_device *pcam)
 {
@@ -2811,7 +1139,7 @@
 	strlcpy(pvdev->name, pcam->sensor_sdev->name, sizeof(pvdev->name));
 
 	pvdev->release   = video_device_release;
-	pvdev->fops	  = &g_msm_fops;
+	pvdev->fops	     = &g_msm_fops;
 	pvdev->ioctl_ops = &g_msm_ioctl_ops;
 	pvdev->minor	 = -1;
 	pvdev->vfl_type  = 1;
@@ -2837,16 +1165,7 @@
 	pcam->pvdev	= pvdev;
 	video_set_drvdata(pcam->pvdev, pcam);
 
-	/* If isp HW registeration is successful,
-	 * then create event queue to
-	 * receievent event froms HW
-	*/
-	/* yyan: no global - each sensor will
-	 * create a new vidoe node! */
-	/* g_pmsm_camera_v4l2_dev = pmsm_camera_v4l2_dev; */
-	/* g_pmsm_camera_v4l2_dev->pvdev = pvdev; */
-
-	return rc ;
+	return rc;
 
 reg_fail:
 	video_device_release(pvdev);
@@ -2987,46 +1306,7 @@
 			 __func__, rc);
 		goto failure;
 	}
-
-	g_server_dev.camera_info.video_dev_name
-	[g_server_dev.camera_info.num_cameras]
-	= video_device_node_name(pcam->pvdev);
-	D("%s Connected video device %s\n", __func__,
-		g_server_dev.camera_info.video_dev_name
-		[g_server_dev.camera_info.num_cameras]);
-
-	g_server_dev.camera_info.s_mount_angle
-	[g_server_dev.camera_info.num_cameras]
-	= sdata->sensor_platform_info->mount_angle;
-
-	g_server_dev.camera_info.is_internal_cam
-	[g_server_dev.camera_info.num_cameras]
-	= sdata->camera_type;
-
-	g_server_dev.mctl_node_info.mctl_node_name
-	[g_server_dev.mctl_node_info.num_mctl_nodes]
-	= video_device_node_name(pcam->mctl_node.pvdev);
-
-	pr_info("%s mctl_node_name[%d] = %s\n", __func__,
-		g_server_dev.mctl_node_info.num_mctl_nodes,
-		g_server_dev.mctl_node_info.mctl_node_name
-		[g_server_dev.mctl_node_info.num_mctl_nodes]);
-
-	/*Temporary solution to store info in media device structure
-	  until we can expand media device structure to support more
-	  device info*/
-	snprintf(pcam->media_dev.serial,
-			sizeof(pcam->media_dev.serial),
-			"%s-%d-%d", QCAMERA_NAME,
-			sdata->sensor_platform_info->mount_angle,
-			sdata->camera_type);
-
-	g_server_dev.camera_info.num_cameras++;
-	g_server_dev.mctl_node_info.num_mctl_nodes++;
-
-	D("%s done, rc = %d\n", __func__, rc);
-	D("%s number of sensors connected is %d\n", __func__,
-		g_server_dev.camera_info.num_cameras);
+	msm_server_update_sensor_info(pcam, sdata);
 
 	/* register the subdevice, must be done for callbacks */
 	rc = msm_cam_register_subdev_node(sensor_sd, SENSOR_DEV, vnode_count);
@@ -3064,83 +1344,3 @@
 }
 EXPORT_SYMBOL(msm_sensor_register);
 
-static int __devinit msm_camera_probe(struct platform_device *pdev)
-{
-	int rc = 0, i;
-	/*for now just create a config 0 node
-	  put logic here later to know how many configs to create*/
-	g_server_dev.config_info.num_config_nodes = 1;
-
-	rc = msm_isp_init_module(g_server_dev.config_info.num_config_nodes);
-	if (rc < 0) {
-		pr_err("Failed to initialize isp\n");
-		return rc;
-	}
-
-	if (!msm_class) {
-		rc = alloc_chrdev_region(&msm_devno, 0,
-		g_server_dev.config_info.num_config_nodes+1, "msm_camera");
-		if (rc < 0) {
-			pr_err("%s: failed to allocate chrdev: %d\n", __func__,
-			rc);
-			return rc;
-		}
-
-		msm_class = class_create(THIS_MODULE, "msm_camera");
-		if (IS_ERR(msm_class)) {
-			rc = PTR_ERR(msm_class);
-			pr_err("%s: create device class failed: %d\n",
-			__func__, rc);
-			return rc;
-		}
-	}
-
-	D("creating server and config nodes\n");
-	rc = msm_setup_server_dev(pdev);
-	if (rc < 0) {
-		pr_err("%s: failed to create server dev: %d\n", __func__,
-		rc);
-		return rc;
-	}
-
-	for (i = 0; i < g_server_dev.config_info.num_config_nodes; i++) {
-		rc = msm_setup_config_dev(i, "config");
-		if (rc < 0) {
-			pr_err("%s:failed to create config dev: %d\n",
-			 __func__, rc);
-			return rc;
-		}
-	}
-
-	msm_isp_register(&g_server_dev);
-	return rc;
-}
-
-static int __exit msm_camera_exit(struct platform_device *pdev)
-{
-	msm_isp_unregister(&g_server_dev);
-	return 0;
-}
-
-
-static struct platform_driver msm_cam_server_driver = {
-	.probe = msm_camera_probe,
-	.remove = msm_camera_exit,
-	.driver = {
-		.name = "msm_cam_server",
-		.owner = THIS_MODULE,
-	},
-};
-
-static int __init msm_camera_init(void)
-{
-	return platform_driver_register(&msm_cam_server_driver);
-}
-
-static void __exit msm_cam_server_exit(void)
-{
-	platform_driver_unregister(&msm_cam_server_driver);
-}
-
-module_init(msm_camera_init);
-module_exit(msm_cam_server_exit);
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index 04e224c..9c3b548 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -32,6 +32,8 @@
 #include <mach/camera.h>
 #include <media/msm_isp.h>
 #include <linux/ion.h>
+#include <linux/iommu.h>
+#include <media/msm_gestures.h>
 
 #define MSM_V4L2_DIMENSION_SIZE 96
 #define MAX_DEV_NAME_LEN 50
@@ -69,6 +71,7 @@
 	SENSOR_DEV,
 	ACTUATOR_DEV,
 	EEPROM_DEV,
+	GESTURE_DEV,
 };
 
 /* msm queue management APIs*/
@@ -150,6 +153,8 @@
 	NOTIFY_VFE_BUF_FREE_EVT, /* arg = msm_camera_csic_params */
 	NOTIFY_VFE_IRQ,
 	NOTIFY_AXI_IRQ,
+	NOTIFY_GESTURE_EVT, /* arg = v4l2_event */
+	NOTIFY_GESTURE_CAM_EVT, /* arg = int */
 	NOTIFY_INVALID
 };
 
@@ -267,6 +272,12 @@
 
 	/*sensor info*/
 	struct msm_camera_sensor_info *sdata;
+
+	/*IOMMU mapped IMEM addresses*/
+	uint32_t ping_imem_y;
+	uint32_t ping_imem_cbcr;
+	uint32_t pong_imem_y;
+	uint32_t pong_imem_cbcr;
 };
 
 /* abstract camera device represents a VFE and connected sensor */
@@ -280,7 +291,8 @@
 		 unsigned int cmd, unsigned long arg);
 	int (*isp_notify)(struct v4l2_subdev *sd,
 		unsigned int notification, void *arg);
-	void (*isp_release)(struct v4l2_subdev *sd);
+	void (*isp_release)(struct msm_cam_media_controller *mctl,
+		struct v4l2_subdev *sd);
 	int (*isp_pp_cmd)(struct msm_cam_media_controller *pmctl,
 		 struct msm_mctl_pp_cmd, void *data);
 
@@ -330,6 +342,8 @@
 	struct msm_cam_v4l2_dev_inst *dev_inst[MSM_DEV_INST_MAX];
 	struct msm_cam_v4l2_dev_inst *dev_inst_map[MSM_MAX_IMG_MODE];
 	struct mutex dev_lock;
+	int active;
+	int use_count;
 };
 
 /* abstract camera device for each sensor successfully probed*/
@@ -384,13 +398,13 @@
 	struct msm_mem_map_info mem_map;
 };
 
-#define MAX_NUM_ACTIVE_CAMERA 2
+/* 2 for camera, 1 for gesture */
+#define MAX_NUM_ACTIVE_CAMERA 3
 
 struct msm_cam_server_queue {
 	uint32_t queue_active;
 	struct msm_device_queue ctrl_q;
 	struct msm_device_queue eventData_q;
-	struct msm_ctrl_cmd *ctrl;
 	uint8_t *ctrl_data;
 	uint32_t evt_id;
 };
@@ -444,11 +458,11 @@
 	struct v4l2_subdev *vfe_device[MAX_NUM_VFE_DEV];
 	struct v4l2_subdev *axi_device[MAX_NUM_AXI_DEV];
 	struct v4l2_subdev *vpe_device[MAX_NUM_VPE_DEV];
+	struct v4l2_subdev *gesture_device;
 };
 
 /* camera server related functions */
 
-
 /* ISP related functions */
 void msm_isp_vfe_dev_init(struct v4l2_subdev *vd);
 /*
@@ -563,9 +577,14 @@
 void msm_release_ion_client(struct kref *ref);
 int msm_cam_register_subdev_node(struct v4l2_subdev *sd,
 			enum msm_cam_subdev_type sdev_type, uint8_t index);
-uint32_t msm_camera_get_mctl_handle(void);
-struct msm_cam_media_controller *msm_camera_get_mctl(uint32_t handle);
-void msm_camera_free_mctl(uint32_t handle);
+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);
+int msm_cam_server_open_mctl_session(struct msm_cam_v4l2_device *pcam,
+	int *p_active);
+int msm_cam_server_close_mctl_session(struct msm_cam_v4l2_device *pcam);
+long msm_v4l2_evt_notify(struct msm_cam_media_controller *mctl,
+		unsigned int cmd, unsigned long evt);
 #endif /* __KERNEL__ */
 
 #endif /* _MSM_H */
diff --git a/drivers/media/video/msm/msm_gesture.c b/drivers/media/video/msm/msm_gesture.c
new file mode 100644
index 0000000..73d60aa
--- /dev/null
+++ b/drivers/media/video/msm/msm_gesture.c
@@ -0,0 +1,496 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <mach/camera.h>
+#include <media/v4l2-subdev.h>
+#include "msm.h"
+#include <media/msm_camera.h>
+#include <media/msm_gestures.h>
+#include <media/v4l2-ctrls.h>
+
+#ifdef CONFIG_MSM_CAMERA_DEBUG
+#define D(fmt, args...) pr_debug("msm_gesture: " fmt, ##args)
+#else
+#define D(fmt, args...) do {} while (0)
+#endif
+
+struct msm_gesture_ctrl {
+	int queue_id;
+	atomic_t active;
+	struct v4l2_ctrl_handler ctrl_handler;
+	int num_ctrls;
+	struct v4l2_fh *p_eventHandle;
+	struct v4l2_subdev *sd;
+	struct msm_ges_evt event;
+	int camera_opened;
+};
+
+static struct msm_gesture_ctrl g_gesture_ctrl;
+
+int msm_gesture_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
+	struct v4l2_event_subscription *sub)
+{
+	D("%s\n", __func__);
+	if (sub->type == V4L2_EVENT_ALL)
+		sub->type = MSM_GES_APP_NOTIFY_EVENT;
+	return v4l2_event_subscribe(fh, sub);
+}
+
+static int msm_gesture_send_ctrl(struct msm_gesture_ctrl *p_gesture_ctrl,
+	int type, void *value, int length, uint32_t timeout)
+{
+	int rc = 0;
+	struct msm_ctrl_cmd ctrlcmd;
+	D("%s qid %d\n", __func__, p_gesture_ctrl->queue_id);
+	ctrlcmd.type = type;
+	ctrlcmd.timeout_ms = timeout;
+	ctrlcmd.length = length;
+	ctrlcmd.value = value;
+	ctrlcmd.vnode_id = 0;
+	ctrlcmd.queue_idx = p_gesture_ctrl->queue_id;
+	ctrlcmd.config_ident = 0;
+
+	rc = msm_server_send_ctrl(&ctrlcmd, MSM_GES_RESP_V4L2);
+	return rc;
+}
+
+static int msm_gesture_proc_ctrl_cmd(struct msm_gesture_ctrl *p_gesture_ctrl,
+	struct v4l2_control *ctrl)
+{
+	int rc = 0;
+	struct msm_ctrl_cmd *tmp_cmd = NULL;
+	uint8_t *ctrl_data = NULL;
+	void __user *uptr_cmd;
+	void __user *uptr_value;
+	uint32_t cmd_len = sizeof(struct msm_ctrl_cmd);
+	uint32_t value_len;
+
+	tmp_cmd = (struct msm_ctrl_cmd *)ctrl->value;
+	uptr_cmd = (void __user *)ctrl->value;
+	uptr_value = (void __user *)tmp_cmd->value;
+	value_len = tmp_cmd->length;
+
+	D("%s: cmd type = %d, up1=0x%x, ulen1=%d, up2=0x%x, ulen2=%d\n",
+		__func__, tmp_cmd->type, (uint32_t)uptr_cmd, cmd_len,
+		(uint32_t)uptr_value, tmp_cmd->length);
+
+	ctrl_data = kzalloc(value_len + cmd_len, GFP_KERNEL);
+	if (ctrl_data == 0) {
+		pr_err("%s could not allocate memory\n", __func__);
+		rc = -ENOMEM;
+		goto end;
+	}
+	tmp_cmd = (struct msm_ctrl_cmd *)ctrl_data;
+	if (copy_from_user((void *)ctrl_data, uptr_cmd,
+			cmd_len)) {
+		pr_err("%s: copy_from_user failed.\n", __func__);
+		rc = -EINVAL;
+		goto end;
+	}
+	tmp_cmd->value = (void *)(ctrl_data + cmd_len);
+	if (uptr_value && tmp_cmd->length > 0) {
+		if (copy_from_user((void *)tmp_cmd->value, uptr_value,
+			value_len)) {
+			pr_err("%s: copy_from_user failed, size=%d\n",
+				__func__, value_len);
+			rc = -EINVAL;
+			goto end;
+		}
+	} else
+		tmp_cmd->value = NULL;
+
+	/* send command to config thread in usersspace, and get return value */
+	rc = msm_server_send_ctrl((struct msm_ctrl_cmd *)ctrl_data,
+			MSM_GES_RESP_V4L2);
+	D("%s: msm_server_control rc=%d\n", __func__, rc);
+	if (rc == 0) {
+		if (uptr_value && tmp_cmd->length > 0 &&
+			copy_to_user((void __user *)uptr_value,
+				(void *)(ctrl_data + cmd_len),
+				tmp_cmd->length)) {
+			pr_err("%s: copy_to_user failed, size=%d\n",
+				__func__, tmp_cmd->length);
+			rc = -EINVAL;
+			goto end;
+		}
+		tmp_cmd->value = uptr_value;
+		if (copy_to_user((void __user *)uptr_cmd,
+			(void *)tmp_cmd, cmd_len)) {
+			pr_err("%s: copy_to_user failed in cpy, size=%d\n",
+				__func__, cmd_len);
+			rc = -EINVAL;
+			goto end;
+		}
+	}
+end:
+	D("%s: END, type = %d, vaddr = 0x%x, vlen = %d, status = %d, rc = %d\n",
+		__func__, tmp_cmd->type, (uint32_t)tmp_cmd->value,
+		tmp_cmd->length, tmp_cmd->status, rc);
+	kfree(ctrl_data);
+	return rc;
+}
+
+static int msm_gesture_s_ctrl(struct v4l2_subdev *sd,
+	struct v4l2_control *ctrl)
+{
+	int rc = 0;
+	struct msm_gesture_ctrl *p_gesture_ctrl = &g_gesture_ctrl;
+	D("%s ctrl->id %d\n", __func__, ctrl->id);
+	rc = msm_gesture_proc_ctrl_cmd(p_gesture_ctrl, ctrl);
+	if (rc != 0) {
+		pr_err("%s set ctrl failed %d\n", __func__, rc);
+		return -EINVAL;
+	}
+	return rc;
+}
+
+static int msm_gesture_s_ctrl_ops(struct v4l2_ctrl *ctrl)
+{
+	int rc = 0;
+	struct v4l2_control control;
+	struct msm_gesture_ctrl *p_gesture_ctrl = &g_gesture_ctrl;
+	control.id = ctrl->id;
+	control.value = ctrl->val;
+	D("%s ctrl->id 0x%x\n", __func__, ctrl->id);
+	rc = msm_gesture_proc_ctrl_cmd(p_gesture_ctrl, &control);
+	if (rc != 0) {
+		pr_err("%s proc ctrl failed %d\n", __func__, rc);
+		return -EINVAL;
+	}
+	return rc;
+}
+
+static int msm_gesture_s_ctrl_ext(struct v4l2_subdev *sd,
+	struct v4l2_ext_controls *ctrls)
+{
+	int rc = 0;
+	struct v4l2_control control;
+	struct msm_gesture_ctrl *p_gesture_ctrl = &g_gesture_ctrl;
+	if ((ctrls->count < 1) || (NULL == ctrls->controls)) {
+		pr_err("%s invalid ctrl failed\n", __func__);
+		return -EINVAL;
+	}
+	control.id = ctrls->controls->id;
+	control.value = ctrls->controls->value;
+	D("%s ctrl->id %d\n", __func__, control.id);
+	rc = msm_gesture_proc_ctrl_cmd(p_gesture_ctrl, &control);
+	if (rc != 0) {
+		pr_err("%s proc ctrl failed %d\n", __func__, rc);
+		return -EINVAL;
+	}
+	return rc;
+}
+
+static int msm_gesture_handle_event(struct v4l2_subdev *sd,
+	struct msm_gesture_ctrl *p_gesture_ctrl, void* arg)
+{
+	int rc = 0;
+	struct v4l2_event *evt = (struct v4l2_event *)arg;
+	struct msm_ges_evt *p_ges_evt = NULL;
+	D("%s: Received gesture evt 0x%x ", __func__, evt->type);
+	p_gesture_ctrl->event.evt_len = 0;
+	p_gesture_ctrl->event.evt_data = NULL;
+
+	p_ges_evt = (struct msm_ges_evt *)evt->u.data;
+	D("%s: event data %p len %d", __func__,
+		p_ges_evt->evt_data,
+		p_ges_evt->evt_len);
+
+	if (p_ges_evt->evt_len > 0) {
+		p_gesture_ctrl->event.evt_data =
+			kzalloc(p_ges_evt->evt_len, GFP_KERNEL);
+
+		if (NULL == p_gesture_ctrl->event.evt_data) {
+			pr_err("%s: cannot allocate event", __func__);
+			rc = -ENOMEM;
+		} else {
+			if (copy_from_user(
+				(void *)p_gesture_ctrl->event.evt_data,
+				(void __user *)p_ges_evt->evt_data,
+				p_ges_evt->evt_len)) {
+				pr_err("%s: copy_from_user failed",
+					__func__);
+				rc = -EFAULT;
+			} else {
+				D("%s: copied the event", __func__);
+				p_gesture_ctrl->event.evt_len =
+					p_ges_evt->evt_len;
+			}
+		}
+	}
+
+	if (rc == 0) {
+		ktime_get_ts(&evt->timestamp);
+		v4l2_event_queue(&sd->devnode, evt);
+	}
+	D("%s: exit rc %d ", __func__, rc);
+	return rc;
+}
+
+static int msm_gesture_get_evt_payload(struct v4l2_subdev *sd,
+	struct msm_gesture_ctrl *p_gesture_ctrl, void* arg)
+{
+	int rc = 0;
+	struct msm_ges_evt *p_ges_evt = (struct msm_ges_evt *)arg;
+	D("%s: enter ", __func__);
+	if (NULL != p_gesture_ctrl->event.evt_data) {
+		D("%s: event data %p len %d", __func__,
+			p_gesture_ctrl->event.evt_data,
+			p_gesture_ctrl->event.evt_len);
+
+		if (copy_to_user((void __user *)p_ges_evt->evt_data,
+			p_gesture_ctrl->event.evt_data,
+			p_gesture_ctrl->event.evt_len)) {
+			pr_err("%s: copy_to_user failed.\n", __func__);
+			rc = -EFAULT;
+		} else {
+			D("%s: copied the event", __func__);
+			p_ges_evt->evt_len = p_gesture_ctrl->event.evt_len;
+		}
+	}
+	D("%s: exit rc %d ", __func__, rc);
+	return rc;
+}
+
+static int msm_gesture_handle_cam_event(struct v4l2_subdev *sd,
+	struct msm_gesture_ctrl *p_gesture_ctrl, int cam_evt)
+{
+	int rc = 0;
+	D("%s: cam_evt %d ", __func__, cam_evt);
+
+	if ((cam_evt != MSM_V4L2_GES_CAM_OPEN)
+		&& (cam_evt != MSM_V4L2_GES_CAM_CLOSE)) {
+		pr_err("%s: error invalid event %d ", __func__, cam_evt);
+		return -EINVAL;
+	}
+
+	p_gesture_ctrl->camera_opened =
+		(cam_evt == MSM_V4L2_GES_CAM_OPEN);
+
+	if (atomic_read(&p_gesture_ctrl->active) == 0) {
+		D("%s gesture not active\n", __func__);
+		return 0;
+	}
+
+	rc = msm_gesture_send_ctrl(p_gesture_ctrl, cam_evt, NULL,
+		0, 2000);
+	if (rc != 0) {
+		pr_err("%s gesture ctrl failed %d\n", __func__, rc);
+		rc = -EINVAL;
+	}
+	D("%s exit rc %d\n", __func__, rc);
+	return rc;
+}
+
+long msm_gesture_ioctl(struct v4l2_subdev *sd,
+	 unsigned int cmd, void *arg)
+{
+	int rc = 0;
+	struct msm_gesture_ctrl *p_gesture_ctrl = &g_gesture_ctrl;
+	D("%s\n", __func__);
+	switch (cmd) {
+	case MSM_GES_IOCTL_CTRL_COMMAND: {
+		struct v4l2_control *ctrl = (struct v4l2_control *)arg;
+		D("%s MSM_GES_IOCTL_CTRL_COMMAND arg %p size %d\n", __func__,
+			arg, sizeof(ctrl));
+		rc = msm_gesture_s_ctrl(sd, ctrl);
+		break;
+	}
+	case VIDIOC_MSM_GESTURE_EVT: {
+		rc = msm_gesture_handle_event(sd, p_gesture_ctrl, arg);
+		break;
+	}
+	case VIDIOC_MSM_GESTURE_CAM_EVT: {
+		int cam_evt = *((int *)arg);
+		rc = msm_gesture_handle_cam_event(sd, p_gesture_ctrl, cam_evt);
+		break;
+	}
+	case MSM_GES_GET_EVT_PAYLOAD: {
+		rc = msm_gesture_get_evt_payload(sd, p_gesture_ctrl, arg);
+		break;
+	}
+	default:
+		pr_err("%s: Invalid ioctl %d", __func__, cmd);
+		break;
+	}
+	D("%s exit rc %d\n", __func__, rc);
+	return rc;
+}
+
+static const struct v4l2_ctrl_ops msm_gesture_ctrl_ops = {
+	.s_ctrl = msm_gesture_s_ctrl_ops,
+};
+
+static const struct v4l2_ctrl_config msm_gesture_ctrl_filter = {
+	.ops = &msm_gesture_ctrl_ops,
+	.id = MSM_GESTURE_CID_CTRL_CMD,
+	.name = "Gesture ctrl",
+	.type = V4L2_CTRL_TYPE_INTEGER,
+	.flags = V4L2_CTRL_FLAG_SLIDER,
+	.max = 0x7fffffff,
+	.step = 1,
+	.min = 0x80000000,
+};
+
+static int msm_gesture_init_ctrl(struct v4l2_subdev *sd,
+	struct msm_gesture_ctrl *p_gesture_ctrl)
+{
+	int rc = 0;
+	p_gesture_ctrl->num_ctrls = 1;
+	p_gesture_ctrl->ctrl_handler.error = 0;
+	v4l2_ctrl_handler_init(&p_gesture_ctrl->ctrl_handler,
+		p_gesture_ctrl->num_ctrls);
+	v4l2_ctrl_new_custom(&p_gesture_ctrl->ctrl_handler,
+		&msm_gesture_ctrl_filter, p_gesture_ctrl);
+	if (p_gesture_ctrl->ctrl_handler.error) {
+		int err = p_gesture_ctrl->ctrl_handler.error;
+		D("%s: error adding control %d", __func__, err);
+		p_gesture_ctrl->ctrl_handler.error = 0;
+	}
+	sd->ctrl_handler = &p_gesture_ctrl->ctrl_handler;
+	return rc;
+}
+
+static int msm_gesture_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	int rc = 0, rc_err = 0;
+	struct msm_gesture_ctrl *p_gesture_ctrl = &g_gesture_ctrl;
+	D("%s\n", __func__);
+	if (atomic_read(&p_gesture_ctrl->active) != 0) {
+		pr_err("%s already opened\n", __func__);
+		return -EINVAL;
+	}
+	memset(&p_gesture_ctrl->event, 0x0, sizeof(struct msm_ges_evt));
+	rc = msm_server_open_client(&p_gesture_ctrl->queue_id);
+	if (rc != 0) {
+		pr_err("%s open failed %d\n", __func__, rc);
+		rc = -EINVAL;
+		goto err;
+	}
+
+	rc = msm_gesture_init_ctrl(sd, p_gesture_ctrl);
+	if (rc != 0) {
+		pr_err("%s init ctrl failed %d\n", __func__, rc);
+		rc = -EINVAL;
+		goto err;
+	}
+
+	rc = msm_gesture_send_ctrl(p_gesture_ctrl, MSM_V4L2_GES_OPEN, NULL,
+		0, 10000);
+	if (rc != 0) {
+		pr_err("%s gesture ctrl failed %d\n", __func__, rc);
+		rc = -EINVAL;
+		goto err;
+	}
+
+	atomic_inc(&p_gesture_ctrl->active);
+
+	return rc;
+
+err:
+	rc_err = msm_server_close_client(p_gesture_ctrl->queue_id);
+	if (rc_err != 0)
+		pr_err("%s failed %d\n", __func__, rc);
+	return rc;
+}
+
+static int msm_gesture_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	int rc = 0;
+	struct msm_gesture_ctrl *p_gesture_ctrl = &g_gesture_ctrl;
+	D("%s\n", __func__);
+	if (atomic_read(&p_gesture_ctrl->active) == 0) {
+		pr_err("%s already closed\n", __func__);
+		return -EINVAL;
+	}
+
+	rc = msm_gesture_send_ctrl(p_gesture_ctrl, MSM_V4L2_GES_CLOSE, NULL,
+		0, 10000);
+	if (rc != 0)
+		pr_err("%s gesture ctrl failed %d\n", __func__, rc);
+
+	rc = msm_server_close_client(p_gesture_ctrl->queue_id);
+	if (rc != 0)
+		pr_err("%s failed %d\n", __func__, rc);
+
+	v4l2_ctrl_handler_free(&p_gesture_ctrl->ctrl_handler);
+	kfree(p_gesture_ctrl->event.evt_data);
+
+	atomic_dec(&p_gesture_ctrl->active);
+	g_gesture_ctrl.queue_id = -1;
+	return 0;
+}
+
+static struct v4l2_subdev_core_ops msm_gesture_core_ops = {
+	.s_ctrl = msm_gesture_s_ctrl,
+	.s_ext_ctrls = msm_gesture_s_ctrl_ext,
+	.ioctl = msm_gesture_ioctl,
+	.subscribe_event = msm_gesture_subscribe_event,
+};
+
+static struct v4l2_subdev_video_ops msm_gesture_video_ops;
+
+static struct v4l2_subdev_ops msm_gesture_subdev_ops = {
+	.core = &msm_gesture_core_ops,
+	.video  = &msm_gesture_video_ops,
+};
+
+static const struct v4l2_subdev_internal_ops msm_gesture_internal_ops = {
+	.open = msm_gesture_open,
+	.close = msm_gesture_close,
+};
+
+static int msm_gesture_node_register(void)
+{
+	struct msm_gesture_ctrl *p_gesture_ctrl = &g_gesture_ctrl;
+	struct v4l2_subdev *gesture_subdev =
+		kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+	D("%s\n", __func__);
+	if (!gesture_subdev) {
+		pr_err("%s: no enough memory\n", __func__);
+		return -ENOMEM;
+	};
+
+	v4l2_subdev_init(gesture_subdev, &msm_gesture_subdev_ops);
+	gesture_subdev->internal_ops = &msm_gesture_internal_ops;
+	gesture_subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	snprintf(gesture_subdev->name,
+			 sizeof(gesture_subdev->name), "gesture");
+
+	media_entity_init(&gesture_subdev->entity, 0, NULL, 0);
+	gesture_subdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L;
+	gesture_subdev->entity.group_id = GESTURE_DEV;
+	gesture_subdev->entity.name = gesture_subdev->name;
+
+	/* events */
+	gesture_subdev->flags |= V4L2_SUBDEV_FL_HAS_EVENTS;
+	gesture_subdev->nevents = MAX_GES_EVENTS;
+
+	msm_cam_register_subdev_node(gesture_subdev, GESTURE_DEV, 0);
+
+	gesture_subdev->entity.revision = gesture_subdev->devnode.num;
+
+	atomic_set(&p_gesture_ctrl->active, 0);
+	p_gesture_ctrl->queue_id = -1;
+	p_gesture_ctrl->event.evt_data = NULL;
+	p_gesture_ctrl->event.evt_len = 0;
+	return 0;
+}
+
+static int __init msm_gesture_init_module(void)
+{
+	return msm_gesture_node_register();
+}
+
+module_init(msm_gesture_init_module);
+MODULE_DESCRIPTION("MSM Gesture driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/msm_isp.c b/drivers/media/video/msm/msm_isp.c
index d678d86..bd174fb 100644
--- a/drivers/media/video/msm/msm_isp.c
+++ b/drivers/media/video/msm/msm_isp.c
@@ -210,9 +210,9 @@
 	case VFE_MSG_V32_JPEG_CAPTURE:
 		D("%s:VFE_MSG_V32_JPEG_CAPTURE vdata->type %d\n", __func__,
 			vdata->type);
-		free_buf.num_planes = 1;
-		free_buf.ch_paddr[0] = IMEM_Y_PING_OFFSET;
-		free_buf.ch_paddr[1] = IMEM_CBCR_PING_OFFSET;
+		free_buf.num_planes = 2;
+		free_buf.ch_paddr[0] = pmctl->ping_imem_y;
+		free_buf.ch_paddr[1] = pmctl->ping_imem_cbcr;
 		cfgcmd.cmd_type = CMD_CONFIG_PING_ADDR;
 		cfgcmd.value = &vfe_id;
 		vfe_params.vfe_cfg = &cfgcmd;
@@ -221,8 +221,8 @@
 			__func__, free_buf.ch_paddr[0], free_buf.ch_paddr[1]);
 		rc = v4l2_subdev_call(sd, core, ioctl, 0, &vfe_params);
 		/* Write the same buffer into PONG */
-		free_buf.ch_paddr[0] = IMEM_Y_PONG_OFFSET;
-		free_buf.ch_paddr[1] = IMEM_CBCR_PONG_OFFSET;
+		free_buf.ch_paddr[0] = pmctl->pong_imem_y;
+		free_buf.ch_paddr[1] = pmctl->pong_imem_cbcr;
 		cfgcmd.cmd_type = CMD_CONFIG_PONG_ADDR;
 		cfgcmd.value = &vfe_id;
 		vfe_params.vfe_cfg = &cfgcmd;
@@ -246,7 +246,6 @@
 		pr_err("%s: Invalid vdata type: %d\n", __func__, vdata->type);
 		break;
 	}
-	msm_isp_sync_free(vdata);
 	return rc;
 }
 
@@ -465,19 +464,54 @@
 		return -EINVAL;
 	}
 
+	rc = msm_iommu_map_contig_buffer(
+		(unsigned long)IMEM_Y_PING_OFFSET, CAMERA_DOMAIN, GEN_POOL,
+		((IMEM_Y_SIZE + IMEM_CBCR_SIZE + 4095) & (~4095)),
+		SZ_4K, IOMMU_WRITE | IOMMU_READ,
+		(unsigned long *)&mctl->ping_imem_y);
+	mctl->ping_imem_cbcr = mctl->ping_imem_y + IMEM_Y_SIZE;
+	if (rc < 0) {
+		pr_err("%s: ping iommu mapping returned error %d\n",
+			__func__, rc);
+		mctl->ping_imem_y = 0;
+		mctl->ping_imem_cbcr = 0;
+	}
+	msm_iommu_map_contig_buffer(
+		(unsigned long)IMEM_Y_PONG_OFFSET, CAMERA_DOMAIN, GEN_POOL,
+		((IMEM_Y_SIZE + IMEM_CBCR_SIZE + 4095) & (~4095)),
+		SZ_4K, IOMMU_WRITE | IOMMU_READ,
+		(unsigned long *)&mctl->pong_imem_y);
+	mctl->pong_imem_cbcr = mctl->pong_imem_y + IMEM_Y_SIZE;
+	if (rc < 0) {
+		pr_err("%s: pong iommu mapping returned error %d\n",
+			 __func__, rc);
+		mctl->pong_imem_y = 0;
+		mctl->pong_imem_cbcr = 0;
+	}
+
 	rc = msm_vfe_subdev_init(sd, mctl);
 	if (rc < 0) {
 		pr_err("%s: vfe_init failed at %d\n",
-					__func__, rc);
+			__func__, rc);
 	}
 	return rc;
 }
 
-static void msm_isp_release(
+static void msm_isp_release(struct msm_cam_media_controller *mctl,
 	struct v4l2_subdev *sd)
 {
 	D("%s\n", __func__);
 	msm_vfe_subdev_release(sd);
+	msm_iommu_unmap_contig_buffer(mctl->ping_imem_y,
+		CAMERA_DOMAIN, GEN_POOL,
+		((IMEM_Y_SIZE + IMEM_CBCR_SIZE + 4095) & (~4095)));
+	msm_iommu_unmap_contig_buffer(mctl->pong_imem_y,
+		CAMERA_DOMAIN, GEN_POOL,
+		((IMEM_Y_SIZE + IMEM_CBCR_SIZE + 4095) & (~4095)));
+	mctl->ping_imem_y = 0;
+	mctl->ping_imem_cbcr = 0;
+	mctl->pong_imem_y = 0;
+	mctl->pong_imem_cbcr = 0;
 }
 
 static int msm_config_vfe(struct v4l2_subdev *sd,
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index e878063..0c87e3e81 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -28,6 +28,7 @@
 #include <linux/android_pmem.h>
 
 #include "msm.h"
+#include "msm_cam_server.h"
 #include "msm_csid.h"
 #include "msm_csic.h"
 #include "msm_csiphy.h"
@@ -699,7 +700,7 @@
 			pr_err("%s: axi release failed %d\n", __func__, rc);
 axi_init_failed:
 	if (p_mctl->isp_sdev && p_mctl->isp_sdev->isp_release)
-		p_mctl->isp_sdev->isp_release(p_mctl->isp_sdev->sd);
+		p_mctl->isp_sdev->isp_release(p_mctl, p_mctl->isp_sdev->sd);
 isp_open_failed:
 	if (camdev->is_csic)
 		if (v4l2_subdev_call(p_mctl->csic_sdev, core, ioctl,
@@ -762,7 +763,7 @@
 	}
 
 	if (p_mctl->isp_sdev && p_mctl->isp_sdev->isp_release)
-		p_mctl->isp_sdev->isp_release(
+		p_mctl->isp_sdev->isp_release(p_mctl,
 			p_mctl->isp_sdev->sd);
 
 	if (camdev->is_csid) {
@@ -858,13 +859,13 @@
 		pr_err("%s: param is NULL", __func__);
 		return -EINVAL;
 	}
-	pcam->mctl_handle = msm_camera_get_mctl_handle();
+	pcam->mctl_handle = msm_cam_server_get_mctl_handle();
 	if (pcam->mctl_handle == 0) {
 		pr_err("%s: cannot get mctl handle", __func__);
 		return -EINVAL;
 	}
 
-	pmctl = msm_camera_get_mctl(pcam->mctl_handle);
+	pmctl = msm_cam_server_get_mctl(pcam->mctl_handle);
 	if (!pmctl) {
 		pr_err("%s: invalid mctl controller", __func__);
 		return -EINVAL;
@@ -903,7 +904,7 @@
 	struct msm_cam_media_controller *pmctl = NULL;
 	D("%s\n", __func__);
 
-	pmctl = msm_camera_get_mctl(pcam->mctl_handle);
+	pmctl = msm_cam_server_get_mctl(pcam->mctl_handle);
 	if (!pmctl) {
 		pr_err("%s: invalid mctl controller", __func__);
 		return -EINVAL;
@@ -911,7 +912,7 @@
 
 	mutex_destroy(&pmctl->lock);
 	wake_lock_destroy(&pmctl->wake_lock);
-	msm_camera_free_mctl(pcam->mctl_handle);
+	msm_cam_server_free_mctl(pcam->mctl_handle);
 	return rc;
 }
 
@@ -923,7 +924,6 @@
 	struct msm_cam_v4l2_device *pcam  = NULL;
 	struct msm_cam_v4l2_dev_inst *pcam_inst;
 	struct msm_cam_media_controller *pmctl;
-	D("%s : E ", __func__);
 
 	if (f == NULL) {
 		pr_err("%s :: cannot open video driver data", __func__);
@@ -935,8 +935,8 @@
 		pr_err("%s NULL pointer passed in!\n", __func__);
 		return rc;
 	}
-	pmctl = msm_camera_get_mctl(pcam->mctl_handle);
 
+	D("%s : E use_count %d", __func__, pcam->mctl_node.use_count);
 	mutex_lock(&pcam->mctl_node.dev_lock);
 	for (i = 0; i < MSM_DEV_INST_MAX; i++) {
 		if (pcam->mctl_node.dev_inst[i] == NULL)
@@ -960,6 +960,21 @@
 
 	D("%s pcam_inst %p my_index = %d\n", __func__,
 		pcam_inst, pcam_inst->my_index);
+	rc = msm_cam_server_open_mctl_session(pcam,
+		&pcam->mctl_node.active);
+	if (rc < 0) {
+		pr_err("%s: mctl session open failed %d", __func__, rc);
+		mutex_unlock(&pcam->mctl_node.dev_lock);
+		return rc;
+	}
+
+	pmctl = msm_cam_server_get_mctl(pcam->mctl_handle);
+	if (!pmctl) {
+		pr_err("%s mctl NULL!\n", __func__);
+		return rc;
+	}
+
+	D("%s active %d\n", __func__, pcam->mctl_node.active);
 	rc = msm_setup_v4l2_event_queue(&pcam_inst->eventHandle,
 					pcam->mctl_node.pvdev);
 	if (rc < 0) {
@@ -973,6 +988,7 @@
 	D("f->private_data = 0x%x, pcam = 0x%x\n",
 		(u32)f->private_data, (u32)pcam_inst);
 
+	pcam->mctl_node.use_count++;
 	mutex_unlock(&pcam->mctl_node.dev_lock);
 	D("%s : X ", __func__);
 	return rc;
@@ -1028,8 +1044,19 @@
 		return -EINVAL;
 	}
 
-	pmctl = msm_camera_get_mctl(pcam->mctl_handle);
+	pmctl = msm_cam_server_get_mctl(pcam->mctl_handle);
 	mutex_lock(&pcam->mctl_node.dev_lock);
+	D("%s : active %d ", __func__, pcam->mctl_node.active);
+	if (pcam->mctl_node.active == 1) {
+		rc = msm_cam_server_close_mctl_session(pcam);
+		if (rc < 0) {
+			pr_err("%s: mctl session close failed %d",
+				__func__, rc);
+			mutex_unlock(&pcam->mctl_node.dev_lock);
+			return rc;
+		}
+		pmctl = NULL;
+	}
 	pcam_inst->streamon = 0;
 	pcam->mctl_node.dev_inst_map[pcam_inst->image_mode] = NULL;
 	if (pcam_inst->vbqueue_initialized)
@@ -1040,10 +1067,14 @@
 	v4l2_fh_exit(&pcam_inst->eventHandle);
 
 	kfree(pcam_inst);
-	kref_put(&pmctl->refcount, msm_release_ion_client);
+	if (NULL != pmctl) {
+		D("%s : release ion client", __func__);
+		kref_put(&pmctl->refcount, msm_release_ion_client);
+	}
 	f->private_data = NULL;
 	mutex_unlock(&pcam->mctl_node.dev_lock);
-	D("%s : X ", __func__);
+	pcam->mctl_node.use_count--;
+	D("%s : use_count %d X ", __func__, pcam->mctl_node.use_count);
 	return rc;
 }
 
@@ -1246,6 +1277,11 @@
 				pb->m.planes[i].data_offset;
 			pcam_inst->buf_offset[pb->index][i].addr_offset =
 				pb->m.planes[i].reserved[0];
+			pcam_inst->plane_info.plane[i].offset = 0;
+			D("%s, len %d user[%d] %p buf_len %d\n",
+				__func__, pb->length, i,
+				(void *)pb->m.planes[i].m.userptr,
+				pb->m.planes[i].length);
 		}
 	} else {
 		D("%s stored reserved info %d", __func__, pb->reserved);
@@ -1443,7 +1479,7 @@
 		(void *)pfmt->fmt.pix.priv);
 	WARN_ON(pctx != f->private_data);
 
-	pmctl = msm_camera_get_mctl(pcam->mctl_handle);
+	pmctl = msm_cam_server_get_mctl(pcam->mctl_handle);
 	if (!pcam_inst->vbqueue_initialized) {
 		pmctl->mctl_vbqueue_init(pcam_inst, &pcam_inst->vid_bufq,
 					V4L2_BUF_TYPE_VIDEO_CAPTURE);
@@ -1467,7 +1503,7 @@
 		pcam_inst, pcam_inst->vbqueue_initialized);
 	WARN_ON(pctx != f->private_data);
 
-	pmctl = msm_camera_get_mctl(pcam->mctl_handle);
+	pmctl = msm_cam_server_get_mctl(pcam->mctl_handle);
 	if (!pcam_inst->vbqueue_initialized) {
 		pmctl->mctl_vbqueue_init(pcam_inst, &pcam_inst->vid_bufq,
 					V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
diff --git a/drivers/media/video/msm/msm_mctl_buf.c b/drivers/media/video/msm/msm_mctl_buf.c
index 5bc81a7..522ea7d 100644
--- a/drivers/media/video/msm/msm_mctl_buf.c
+++ b/drivers/media/video/msm/msm_mctl_buf.c
@@ -26,6 +26,7 @@
 #include <linux/android_pmem.h>
 
 #include "msm.h"
+#include "msm_cam_server.h"
 #include "msm_ispif.h"
 
 #ifdef CONFIG_MSM_CAMERA_DEBUG
@@ -53,7 +54,7 @@
 
 	*num_planes = pcam_inst->plane_info.num_planes;
 	for (i = 0; i < pcam_inst->vid_fmt.fmt.pix_mp.num_planes; i++) {
-		sizes[i] = PAGE_ALIGN(pcam_inst->plane_info.plane[i].size);
+		sizes[i] = pcam_inst->plane_info.plane[i].size;
 		D("%s Inst %p : Plane %d Offset = %d Size = %ld"
 			"Aligned Size = %ld", __func__, pcam_inst, i,
 			pcam_inst->plane_info.plane[i].offset,
@@ -113,7 +114,7 @@
 			pcam_inst->plane_info.plane[0].offset;
 	}
 	buf_idx = vb->v4l2_buf.index;
-	pmctl = msm_camera_get_mctl(pcam->mctl_handle);
+	pmctl = msm_cam_server_get_mctl(pcam->mctl_handle);
 	for (i = 0; i < vb->num_planes; i++) {
 		mem = vb2_plane_cookie(vb, i);
 		if (buf_type == VIDEOBUF2_MULTIPLE_PLANES)
@@ -251,7 +252,7 @@
 		}
 		spin_unlock_irqrestore(&pcam_inst->vq_irqlock, flags);
 	}
-	pmctl = msm_camera_get_mctl(pcam->mctl_handle);
+	pmctl = msm_cam_server_get_mctl(pcam->mctl_handle);
 	for (i = 0; i < vb->num_planes; i++) {
 		mem = vb2_plane_cookie(vb, i);
 		videobuf2_pmem_contig_user_put(mem, pmctl->client);
@@ -431,8 +432,8 @@
 	int pp_divert_type = 0, pp_type = 0;
 
 	msm_mctl_check_pp(p_mctl, image_mode, &pp_divert_type, &pp_type);
-	D("%s: pp_type=%d, pp_divert_type = %d, frame_id = 0x%x",
-		__func__, pp_type, pp_divert_type, frame_id);
+	D("%s: pp_type=%d, pp_divert_type = %d, frame_id = 0x%x image_mode %d",
+		__func__, pp_type, pp_divert_type, frame_id, image_mode);
 	if (pp_type || pp_divert_type)
 		rc = msm_mctl_do_pp_divert(p_mctl,
 		image_mode, fbuf, frame_id, pp_type);
@@ -440,9 +441,26 @@
 		idx = msm_mctl_img_mode_to_inst_index(
 				p_mctl, image_mode, 0);
 		if (idx < 0) {
-			pr_err("%s Invalid instance, dropping buffer\n",
-				__func__);
-			return idx;
+			/* check mctl node */
+			if ((image_mode >= 0) &&
+				p_mctl->pcam_ptr->mctl_node.
+					dev_inst_map[image_mode]) {
+				int index = p_mctl->pcam_ptr->mctl_node.
+					   dev_inst_map[image_mode]->my_index;
+				pcam_inst = p_mctl->pcam_ptr->mctl_node.
+					dev_inst[index];
+				D("%s: Mctl node index %d inst %p",
+					__func__, index, pcam_inst);
+				rc = msm_mctl_buf_done_proc(p_mctl, pcam_inst,
+					image_mode, fbuf,
+					&frame_id, 1);
+				D("%s mctl node buf done %d\n", __func__, 0);
+				return -EINVAL;
+			} else {
+			  pr_err("%s Invalid instance, dropping buffer\n",
+				  __func__);
+			  return idx;
+			}
 		}
 		pcam_inst = p_mctl->pcam_ptr->dev_inst[idx];
 		rc = msm_mctl_buf_done_proc(p_mctl, pcam_inst,
@@ -455,7 +473,7 @@
 int msm_mctl_buf_init(struct msm_cam_v4l2_device *pcam)
 {
 	struct msm_cam_media_controller *pmctl;
-	pmctl = msm_camera_get_mctl(pcam->mctl_handle);
+	pmctl = msm_cam_server_get_mctl(pcam->mctl_handle);
 	pmctl->mctl_vbqueue_init = msm_vbqueue_init;
 	return 0;
 }
@@ -573,6 +591,10 @@
 					plane_offset =
 					mem->offset.sp_off.cbcr_off;
 
+				D("%s: data off %d plane off %d",
+					__func__,
+					pcam_inst->buf_offset[buf_idx][i].
+					data_offset, plane_offset);
 				free_buf->ch_paddr[i] =	(uint32_t)
 				videobuf2_to_pmem_contig(&buf->vidbuf, i) +
 				pcam_inst->buf_offset[buf_idx][i].data_offset +
diff --git a/drivers/media/video/msm/msm_vfe31_v4l2.c b/drivers/media/video/msm/msm_vfe31_v4l2.c
index 90ba214..d5f37dc 100644
--- a/drivers/media/video/msm/msm_vfe31_v4l2.c
+++ b/drivers/media/video/msm/msm_vfe31_v4l2.c
@@ -367,7 +367,6 @@
 static void vfe31_stop(void)
 {
 
-	uint8_t  axiBusyFlag = true;
 	unsigned long flags;
 
 	atomic_set(&vfe31_ctrl->vstate, 0);
@@ -397,7 +396,52 @@
 	 * at any time. stop camif immediately. */
 	msm_camera_io_w_mb(CAMIF_COMMAND_STOP_IMMEDIATELY,
 		vfe31_ctrl->vfebase + VFE_CAMIF_COMMAND);
+}
 
+void axi_start(void)
+{
+	switch (vfe31_ctrl->operation_mode) {
+	case VFE_OUTPUTS_PREVIEW:
+	case VFE_OUTPUTS_PREVIEW_AND_VIDEO:
+		if (vfe31_ctrl->outpath.output_mode &
+			VFE31_OUTPUT_MODE_PRIMARY) {
+			msm_camera_io_w(1, vfe31_ctrl->vfebase +
+			vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch0]);
+			msm_camera_io_w(1, vfe31_ctrl->vfebase +
+			vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch1]);
+		} else if (vfe31_ctrl->outpath.output_mode &
+			VFE31_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
+			msm_camera_io_w(1, vfe31_ctrl->vfebase +
+			vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch0]);
+			msm_camera_io_w(1, vfe31_ctrl->vfebase +
+			vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch1]);
+			msm_camera_io_w(1, vfe31_ctrl->vfebase +
+			vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch2]);
+		}
+		break;
+	default:
+		if (vfe31_ctrl->outpath.output_mode &
+			VFE31_OUTPUT_MODE_SECONDARY) {
+			msm_camera_io_w(1, vfe31_ctrl->vfebase +
+			vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch0]);
+			msm_camera_io_w(1, vfe31_ctrl->vfebase +
+			vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch1]);
+		} else if (vfe31_ctrl->outpath.output_mode &
+			VFE31_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
+			msm_camera_io_w(1, vfe31_ctrl->vfebase +
+			vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch0]);
+			msm_camera_io_w(1, vfe31_ctrl->vfebase +
+			vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch1]);
+			msm_camera_io_w(1, vfe31_ctrl->vfebase +
+			vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch2]);
+		}
+		break;
+	}
+}
+
+void axi_stop(void)
+{
+	uint8_t  axiBusyFlag = true;
 	/* axi halt command. */
 	msm_camera_io_w(AXI_HALT,
 		vfe31_ctrl->vfebase + VFE_AXI_CMD);
@@ -423,20 +467,15 @@
 
 static void vfe31_subdev_notify(int id, int path)
 {
-	struct msm_vfe_resp *rp;
+	struct msm_vfe_resp rp;
 	unsigned long flags;
 	spin_lock_irqsave(&vfe31_ctrl->sd_notify_lock, flags);
-	rp = msm_isp_sync_alloc(sizeof(struct msm_vfe_resp), GFP_ATOMIC);
-	if (!rp) {
-		CDBG("rp: cannot allocate buffer\n");
-		spin_unlock_irqrestore(&vfe31_ctrl->sd_notify_lock, flags);
-		return;
-	}
+	memset(&rp, 0, sizeof(struct msm_vfe_resp));
 	CDBG("vfe31_subdev_notify : msgId = %d\n", id);
-	rp->evt_msg.type   = MSM_CAMERA_MSG;
-	rp->evt_msg.msg_id = path;
-	rp->type	   = id;
-	v4l2_subdev_notify(&vfe31_ctrl->subdev, NOTIFY_VFE_BUF_EVT, rp);
+	rp.evt_msg.type   = MSM_CAMERA_MSG;
+	rp.evt_msg.msg_id = path;
+	rp.type	   = id;
+	v4l2_subdev_notify(&vfe31_ctrl->subdev, NOTIFY_VFE_BUF_EVT, &rp);
 	spin_unlock_irqrestore(&vfe31_ctrl->sd_notify_lock, flags);
 }
 
@@ -959,43 +998,6 @@
 	}
 	msm_camera_io_w(irq_comp_mask, vfe31_ctrl->vfebase + VFE_IRQ_COMP_MASK);
 
-	switch (vfe31_ctrl->operation_mode) {
-	case VFE_OUTPUTS_PREVIEW:
-	case VFE_OUTPUTS_PREVIEW_AND_VIDEO:
-		if (vfe31_ctrl->outpath.output_mode &
-			VFE31_OUTPUT_MODE_PRIMARY) {
-			msm_camera_io_w(1, vfe31_ctrl->vfebase +
-			vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch0]);
-			msm_camera_io_w(1, vfe31_ctrl->vfebase +
-			vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch1]);
-		} else if (vfe31_ctrl->outpath.output_mode &
-			VFE31_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
-			msm_camera_io_w(1, vfe31_ctrl->vfebase +
-			vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch0]);
-			msm_camera_io_w(1, vfe31_ctrl->vfebase +
-			vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch1]);
-			msm_camera_io_w(1, vfe31_ctrl->vfebase +
-			vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch2]);
-		}
-		break;
-	default:
-		if (vfe31_ctrl->outpath.output_mode &
-			VFE31_OUTPUT_MODE_SECONDARY) {
-			msm_camera_io_w(1, vfe31_ctrl->vfebase +
-			vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch0]);
-			msm_camera_io_w(1, vfe31_ctrl->vfebase +
-			vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch1]);
-		} else if (vfe31_ctrl->outpath.output_mode &
-			VFE31_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
-			msm_camera_io_w(1, vfe31_ctrl->vfebase +
-			vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch0]);
-			msm_camera_io_w(1, vfe31_ctrl->vfebase +
-			vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch1]);
-			msm_camera_io_w(1, vfe31_ctrl->vfebase +
-			vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch2]);
-		}
-		break;
-	}
 	msm_camio_bus_scale_cfg(
 		pmctl->sdata->pdata->cam_bus_scale_table, S_PREVIEW);
 	vfe31_start_common();
@@ -3330,12 +3332,14 @@
 		cmd->cmd_type != CMD_STATS_RS_BUF_RELEASE &&
 		cmd->cmd_type != CMD_STATS_CS_BUF_RELEASE &&
 		cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE) {
-		if (copy_from_user(&vfecmd,
-			(void __user *)(cmd->value),
-			sizeof(vfecmd))) {
-			pr_err("%s %d: copy_from_user failed\n", __func__,
-				__LINE__);
-			return -EFAULT;
+		if (NULL != cmd->value) {
+			if (copy_from_user(&vfecmd,
+				(void __user *)(cmd->value),
+				sizeof(vfecmd))) {
+				pr_err("%s %d: copy_from_user failed\n",
+					__func__, __LINE__);
+				return -EFAULT;
+			}
 		}
 	} else {
 	/* here eith stats release or frame release. */
@@ -3576,6 +3580,14 @@
 		}
 		break;
 
+	case CMD_AXI_START:
+		axi_start();
+		break;
+
+	case CMD_AXI_STOP:
+		axi_stop();
+		break;
+
 	default:
 		pr_err("%s Unsupported AXI configuration %x ", __func__,
 			cmd->cmd_type);
diff --git a/drivers/media/video/msm/msm_vfe32.c b/drivers/media/video/msm/msm_vfe32.c
index becdd95..220752a 100644
--- a/drivers/media/video/msm/msm_vfe32.c
+++ b/drivers/media/video/msm/msm_vfe32.c
@@ -358,7 +358,6 @@
 
 static void vfe32_stop(void)
 {
-	uint8_t  axiBusyFlag = true;
 	unsigned long flags;
 
 	atomic_set(&vfe32_ctrl->vstate, 0);
@@ -389,48 +388,19 @@
 	msm_camera_io_w(CAMIF_COMMAND_STOP_IMMEDIATELY,
 		vfe32_ctrl->vfebase + VFE_CAMIF_COMMAND);
 
-	/* axi halt command. */
-	msm_camera_io_w(AXI_HALT,
-		vfe32_ctrl->vfebase + VFE_AXI_CMD);
-	wmb();
-	while (axiBusyFlag) {
-		if (msm_camera_io_r(vfe32_ctrl->vfebase + VFE_AXI_STATUS) & 0x1)
-			axiBusyFlag = false;
-	}
-	/* Ensure the write order while writing
-	to the command register using the barrier */
-	msm_camera_io_w_mb(AXI_HALT_CLEAR,
-		vfe32_ctrl->vfebase + VFE_AXI_CMD);
-
-	/* after axi halt, then ok to apply global reset. */
-	/* enable reset_ack and async timer interrupt only while
-	stopping the pipeline.*/
-	msm_camera_io_w(0xf0000000,
-		vfe32_ctrl->vfebase + VFE_IRQ_MASK_0);
-	msm_camera_io_w(VFE_IMASK_WHILE_STOPPING_1,
-		vfe32_ctrl->vfebase + VFE_IRQ_MASK_1);
-
-	/* Ensure the write order while writing
-	to the command register using the barrier */
-	msm_camera_io_w_mb(VFE_RESET_UPON_STOP_CMD,
-		vfe32_ctrl->vfebase + VFE_GLOBAL_RESET);
 }
 
 static void vfe32_subdev_notify(int id, int path)
 {
-	struct msm_vfe_resp *rp;
+	struct msm_vfe_resp rp;
 	unsigned long flags = 0;
 	spin_lock_irqsave(&vfe32_ctrl->sd_notify_lock, flags);
-	rp = msm_isp_sync_alloc(sizeof(struct msm_vfe_resp), GFP_ATOMIC);
-	if (!rp) {
-		CDBG("rp: cannot allocate buffer\n");
-		return;
-	}
 	CDBG("vfe32_subdev_notify : msgId = %d\n", id);
-	rp->evt_msg.type   = MSM_CAMERA_MSG;
-	rp->evt_msg.msg_id = path;
-	rp->type	   = id;
-	v4l2_subdev_notify(&vfe32_ctrl->subdev, NOTIFY_VFE_BUF_EVT, rp);
+	memset(&rp, 0, sizeof(struct msm_vfe_resp));
+	rp.evt_msg.type   = MSM_CAMERA_MSG;
+	rp.evt_msg.msg_id = path;
+	rp.type	   = id;
+	v4l2_subdev_notify(&vfe32_ctrl->subdev, NOTIFY_VFE_BUF_EVT, &rp);
 	spin_unlock_irqrestore(&vfe32_ctrl->sd_notify_lock, flags);
 }
 
@@ -914,7 +884,6 @@
 static int vfe32_start(struct msm_cam_media_controller *pmctl)
 {
 	uint32_t irq_comp_mask = 0;
-
 	irq_comp_mask	=
 		msm_camera_io_r(vfe32_ctrl->vfebase + VFE_IRQ_COMP_MASK);
 
@@ -938,44 +907,6 @@
 	}
 	msm_camera_io_w(irq_comp_mask, vfe32_ctrl->vfebase + VFE_IRQ_COMP_MASK);
 
-	switch (vfe32_ctrl->operation_mode) {
-	case VFE_OUTPUTS_PREVIEW:
-	case VFE_OUTPUTS_PREVIEW_AND_VIDEO:
-		if (vfe32_ctrl->outpath.output_mode &
-			VFE32_OUTPUT_MODE_PRIMARY) {
-			msm_camera_io_w(1, vfe32_ctrl->vfebase +
-			vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out0.ch0]);
-			msm_camera_io_w(1, vfe32_ctrl->vfebase +
-			vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out0.ch1]);
-		} else if (vfe32_ctrl->outpath.output_mode &
-				VFE32_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
-			msm_camera_io_w(1, vfe32_ctrl->vfebase +
-			vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out0.ch0]);
-			msm_camera_io_w(1, vfe32_ctrl->vfebase +
-			vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out0.ch1]);
-			msm_camera_io_w(1, vfe32_ctrl->vfebase +
-			vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out0.ch2]);
-		}
-		break;
-	default:
-		if (vfe32_ctrl->outpath.output_mode &
-			VFE32_OUTPUT_MODE_SECONDARY) {
-			msm_camera_io_w(1, vfe32_ctrl->vfebase +
-			vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out1.ch0]);
-			msm_camera_io_w(1, vfe32_ctrl->vfebase +
-			vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out1.ch1]);
-		} else if (vfe32_ctrl->outpath.output_mode &
-			VFE32_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
-			msm_camera_io_w(1, vfe32_ctrl->vfebase +
-			vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out1.ch0]);
-			msm_camera_io_w(1, vfe32_ctrl->vfebase +
-			vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out1.ch1]);
-			msm_camera_io_w(1, vfe32_ctrl->vfebase +
-			vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out1.ch2]);
-		}
-		break;
-	}
-
 	msm_camio_bus_scale_cfg(
 		pmctl->sdata->pdata->cam_bus_scale_table, S_PREVIEW);
 	vfe32_start_common();
@@ -3056,7 +2987,7 @@
 		ch2_paddr = vfe32_get_ch_addr(ping_pong,
 			vfe32_ctrl->outpath.out1.ch2);
 
-		pr_debug("%s ch0 = 0x%x, ch1 = 0x%x, ch2 = 0x%x\n",
+		CDBG("%s ch0 = 0x%x, ch1 = 0x%x, ch2 = 0x%x\n",
 			__func__, ch0_paddr, ch1_paddr, ch2_paddr);
 		if (free_buf) {
 			/* Y channel */
@@ -4002,23 +3933,97 @@
 	vfe32_ctrl->vfebase = 0;
 }
 
+void axi_start(void)
+{
+	switch (vfe32_ctrl->operation_mode) {
+	case VFE_OUTPUTS_PREVIEW:
+	case VFE_OUTPUTS_PREVIEW_AND_VIDEO:
+		if (vfe32_ctrl->outpath.output_mode &
+			VFE32_OUTPUT_MODE_PRIMARY) {
+			msm_camera_io_w(1, vfe32_ctrl->vfebase +
+			vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out0.ch0]);
+			msm_camera_io_w(1, vfe32_ctrl->vfebase +
+			vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out0.ch1]);
+		} else if (vfe32_ctrl->outpath.output_mode &
+				VFE32_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
+			msm_camera_io_w(1, vfe32_ctrl->vfebase +
+			vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out0.ch0]);
+			msm_camera_io_w(1, vfe32_ctrl->vfebase +
+			vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out0.ch1]);
+			msm_camera_io_w(1, vfe32_ctrl->vfebase +
+			vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out0.ch2]);
+		}
+		break;
+	default:
+		if (vfe32_ctrl->outpath.output_mode &
+			VFE32_OUTPUT_MODE_SECONDARY) {
+			msm_camera_io_w(1, vfe32_ctrl->vfebase +
+			vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out1.ch0]);
+			msm_camera_io_w(1, vfe32_ctrl->vfebase +
+			vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out1.ch1]);
+		} else if (vfe32_ctrl->outpath.output_mode &
+			VFE32_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
+			msm_camera_io_w(1, vfe32_ctrl->vfebase +
+			vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out1.ch0]);
+			msm_camera_io_w(1, vfe32_ctrl->vfebase +
+			vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out1.ch1]);
+			msm_camera_io_w(1, vfe32_ctrl->vfebase +
+			vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out1.ch2]);
+		}
+		break;
+	}
+}
+
+void axi_stop(void)
+{
+	uint8_t  axiBusyFlag = true;
+		/* axi halt command. */
+	msm_camera_io_w(AXI_HALT,
+		vfe32_ctrl->vfebase + VFE_AXI_CMD);
+	wmb();
+	while (axiBusyFlag) {
+		if (msm_camera_io_r(vfe32_ctrl->vfebase + VFE_AXI_STATUS) & 0x1)
+			axiBusyFlag = false;
+	}
+	/* Ensure the write order while writing
+	to the command register using the barrier */
+	msm_camera_io_w_mb(AXI_HALT_CLEAR,
+		vfe32_ctrl->vfebase + VFE_AXI_CMD);
+
+	/* after axi halt, then ok to apply global reset. */
+	/* enable reset_ack and async timer interrupt only while
+	stopping the pipeline.*/
+	msm_camera_io_w(0xf0000000,
+		vfe32_ctrl->vfebase + VFE_IRQ_MASK_0);
+	msm_camera_io_w(VFE_IMASK_WHILE_STOPPING_1,
+		vfe32_ctrl->vfebase + VFE_IRQ_MASK_1);
+
+	/* Ensure the write order while writing
+	to the command register using the barrier */
+	msm_camera_io_w_mb(VFE_RESET_UPON_STOP_CMD,
+		vfe32_ctrl->vfebase + VFE_GLOBAL_RESET);
+}
+
 static int msm_axi_config(struct v4l2_subdev *sd, void __user *arg)
 {
 	struct msm_vfe_cfg_cmd cfgcmd;
 	struct msm_isp_cmd vfecmd;
 	int rc = 0;
 
-	if (copy_from_user(&cfgcmd, arg, sizeof(cfgcmd))) {
-		ERR_COPY_FROM_USER();
-		return -EFAULT;
+	if (NULL != arg) {
+		if (copy_from_user(&cfgcmd, arg, sizeof(cfgcmd))) {
+			ERR_COPY_FROM_USER();
+			return -EFAULT;
+		}
 	}
-
-	if (copy_from_user(&vfecmd,
-			(void __user *)(cfgcmd.value),
-			sizeof(vfecmd))) {
-		pr_err("%s %d: copy_from_user failed\n", __func__,
-			__LINE__);
-		return -EFAULT;
+	if (NULL != cfgcmd.value) {
+		if (copy_from_user(&vfecmd,
+				(void __user *)(cfgcmd.value),
+				sizeof(vfecmd))) {
+			pr_err("%s %d: copy_from_user failed\n", __func__,
+				__LINE__);
+			return -EFAULT;
+		}
 	}
 
 	switch (cfgcmd.cmd_type) {
@@ -4121,6 +4126,12 @@
 		pr_err("%s Invalid/Unsupported AXI configuration %x",
 			__func__, cfgcmd.cmd_type);
 		break;
+	case CMD_AXI_START:
+		axi_start();
+		break;
+	case CMD_AXI_STOP:
+		axi_stop();
+		break;
 	default:
 		pr_err("%s Unsupported AXI configuration %x ", __func__,
 			cfgcmd.cmd_type);
diff --git a/drivers/media/video/msm/msm_vfe7x27a_v4l2.c b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
index dd567d1..84943ed 100644
--- a/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
+++ b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
@@ -258,7 +258,8 @@
 	{VFE_CMD_DUMMY_9, VFE_MAX, VFE_MAX},
 	{VFE_CMD_STATS_AF_START, VFE_STATS_AUTOFOCUS_CONFIG, QDSP_CMDQUEUE,
 		"VFE_CMD_STATS_AF_START", "VFE_STATS_AUTOFOCUS_CONFIG"},
-	{VFE_CMD_STATS_AF_STOP, VFE_MAX, VFE_MAX},
+	{VFE_CMD_STATS_AF_STOP, VFE_STATS_AUTOFOCUS_CONFIG, QDSP_CMDQUEUE,
+		"VFE_CMD_STATS_AF_STOP", "VFE_STATS_AUTOFOCUS_CONFIG"},
 	{VFE_CMD_STATS_AE_START, VFE_MAX, VFE_MAX},
 	{VFE_CMD_STATS_AE_STOP, VFE_MAX, VFE_MAX},
 	{VFE_CMD_STATS_AWB_START, VFE_MAX, VFE_MAX},
@@ -341,7 +342,6 @@
 static uint32_t extlen;
 
 struct mutex vfe_lock;
-static int apps_reset;
 static uint8_t vfestopped;
 
 static struct stop_event stopevent;
@@ -396,7 +396,7 @@
 		void (*getevent)(void *ptr, size_t len))
 {
 	uint32_t evt_buf[3];
-	void *data;
+	void *data = NULL;
 	struct buf_info *outch = NULL;
 	uint32_t y_phy, cbcr_phy;
 	struct table_cmd *table_pending = NULL;
@@ -432,6 +432,7 @@
 				vfe_7x_ops(driver_data, MSG_OUTPUT_T,
 						len, getevent);
 			vfe2x_send_isp_msg(vfe2x_ctrl, MSG_ID_SNAPSHOT_DONE);
+			kfree(data);
 			return;
 		case MSG_OUTPUT_S:
 			outch = &vfe2x_ctrl->snap;
@@ -489,6 +490,10 @@
 					len = sizeof(fack);
 					msm_adsp_write(vfe_mod, QDSP_CMDQUEUE,
 						cmd_data, len);
+					if (!vfe2x_ctrl->zsl_mode) {
+						kfree(data);
+						return;
+					}
 				}
 			}
 			y_phy = ((struct vfe_endframe *)data)->y_address;
@@ -557,6 +562,10 @@
 					len = sizeof(fack);
 					msm_adsp_write(vfe_mod, QDSP_CMDQUEUE,
 						cmd_data, len);
+					if (!vfe2x_ctrl->zsl_mode) {
+						kfree(data);
+						return;
+					}
 				}
 			}
 			y_phy = ((struct vfe_endframe *)data)->y_address;
@@ -666,7 +675,9 @@
 						msgs_map[id].isp_id);
 			break;
 		default:
-			vfe2x_send_isp_msg(vfe2x_ctrl, msgs_map[id].isp_id);
+			if (MSG_TABLE_CMD_ACK != id)
+				vfe2x_send_isp_msg(vfe2x_ctrl,
+						msgs_map[id].isp_id);
 			break;
 		}
 	}
@@ -706,24 +717,30 @@
 				vfe2x_ctrl->update_pending = 0;
 			}
 			spin_unlock_irqrestore(&vfe2x_ctrl->table_lock, flags);
+			kfree(data);
 			return;
 		}
 		table_pending = list_first_entry(&vfe2x_ctrl->table_q,
 					struct table_cmd, list);
 		if (!table_pending) {
 			spin_unlock_irqrestore(&vfe2x_ctrl->table_lock, flags);
+			kfree(data);
 			return;
 		}
 		msm_adsp_write(vfe_mod, table_pending->queue,
 				table_pending->cmd, table_pending->size);
 		list_del(&table_pending->list);
 		kfree(table_pending->cmd);
+		kfree(table_pending);
 		vfe2x_ctrl->tableack_pending = 1;
 		spin_unlock_irqrestore(&vfe2x_ctrl->table_lock, flags);
 	} else if (!vfe2x_ctrl->tableack_pending) {
-		if (!list_empty(&vfe2x_ctrl->table_q))
+		if (!list_empty(&vfe2x_ctrl->table_q)) {
+			kfree(data);
 			return;
+		}
 	}
+	kfree(data);
 }
 
 static struct msm_adsp_ops vfe_7x_sync = {
@@ -834,19 +851,15 @@
 
 static void vfe2x_subdev_notify(int id, int path)
 {
-	struct msm_vfe_resp *rp;
+	struct msm_vfe_resp rp;
 	unsigned long flags = 0;
 	spin_lock_irqsave(&vfe2x_ctrl->sd_notify_lock, flags);
-	rp = msm_isp_sync_alloc(sizeof(struct msm_vfe_resp), GFP_ATOMIC);
-	if (!rp) {
-		CDBG("rp: cannot allocate buffer\n");
-		return;
-	}
+	memset(&rp, 0, sizeof(struct msm_vfe_resp));
 	CDBG("vfe2x_subdev_notify : msgId = %d\n", id);
-	rp->evt_msg.type   = MSM_CAMERA_MSG;
-	rp->evt_msg.msg_id = path;
-	rp->type	   = id;
-	v4l2_subdev_notify(&vfe2x_ctrl->subdev, NOTIFY_VFE_BUF_EVT, rp);
+	rp.evt_msg.type   = MSM_CAMERA_MSG;
+	rp.evt_msg.msg_id = path;
+	rp.type	   = id;
+	v4l2_subdev_notify(&vfe2x_ctrl->subdev, NOTIFY_VFE_BUF_EVT, &rp);
 	spin_unlock_irqrestore(&vfe2x_ctrl->sd_notify_lock, flags);
 }
 
@@ -1216,8 +1229,7 @@
 		if (queue == QDSP_CMDQUEUE) {
 			switch (vfecmd.id) {
 			case VFE_CMD_RESET:
-				msm_camio_vfe_blk_reset_2(apps_reset);
-				apps_reset = 0;
+				msm_camio_vfe_blk_reset_2();
 				vfestopped = 0;
 				break;
 			case VFE_CMD_START:
@@ -1270,7 +1282,10 @@
 				if ((!list_empty(&vfe2x_ctrl->table_q)) ||
 						vfe2x_ctrl->tableack_pending) {
 					CDBG("update pending\n");
-					vfe2x_ctrl->update_pending = 1;
+					vfe2x_ctrl->update_pending = 0;
+					vfe2x_send_isp_msg(vfe2x_ctrl,
+						msgs_map[MSG_UPDATE_ACK].
+						isp_id);
 					spin_unlock_irqrestore(
 							&vfe2x_ctrl->table_lock,
 							flags);
@@ -1588,29 +1603,30 @@
 
 config_send:
 	CDBG("send adsp command = %d\n", *(uint32_t *)cmd_data);
+	spin_lock_irqsave(&vfe2x_ctrl->table_lock, flags);
 	if (queue == QDSP_TABLEQUEUE &&
 			vfe2x_ctrl->tableack_pending) {
 		CDBG("store table cmd\n");
 		table_pending = kzalloc(sizeof(struct table_cmd), GFP_ATOMIC);
 		if (!table_pending) {
 			rc = -ENOMEM;
+			spin_unlock_irqrestore(&vfe2x_ctrl->table_lock, flags);
 			goto config_done;
 		}
 		table_pending->cmd = kzalloc(vfecmd.length + 4, GFP_ATOMIC);
 		if (!table_pending->cmd) {
 			kfree(table_pending);
 			rc = -ENOMEM;
+			spin_unlock_irqrestore(&vfe2x_ctrl->table_lock, flags);
 			goto config_done;
 		}
 		memcpy(table_pending->cmd, cmd_data, vfecmd.length + 4);
 		table_pending->queue = queue;
 		table_pending->size = vfecmd.length + 4;
-		spin_lock_irqsave(&vfe2x_ctrl->table_lock, flags);
 		list_add_tail(&table_pending->list, &vfe2x_ctrl->table_q);
 		spin_unlock_irqrestore(&vfe2x_ctrl->table_lock, flags);
 	} else {
 		if (queue == QDSP_TABLEQUEUE) {
-			spin_lock_irqsave(&vfe2x_ctrl->table_lock, flags);
 			CDBG("sending table cmd\n");
 			vfe2x_ctrl->tableack_pending = 1;
 			rc = msm_adsp_write(vfe_mod, queue,
@@ -1621,7 +1637,6 @@
 				uint32_t *ptr = cmd_data;
 				CDBG("%x %x %x\n", ptr[0], ptr[1], ptr[2]);
 			}
-			spin_lock_irqsave(&vfe2x_ctrl->table_lock, flags);
 			CDBG("send n-table cmd\n");
 			rc = msm_adsp_write(vfe_mod, queue,
 				cmd_data, vfecmd.length + 4);
@@ -1636,6 +1651,7 @@
 config_failure:
 	kfree(scfg);
 	kfree(axio);
+	kfree(sfcfg);
 	return rc;
 }
 
@@ -1717,8 +1733,6 @@
 	CDBG("msm_cam_clk_enable: disable vfe_clk\n");
 	msm_cam_clk_enable(&vfe2x_ctrl->pdev->dev, vfe2x_clk_info,
 			vfe2x_ctrl->vfe_clk, ARRAY_SIZE(vfe2x_clk_info), 0);
-	apps_reset = 1;
-
 	msm_adsp_disable(qcam_mod);
 	msm_adsp_disable(vfe_mod);
 
diff --git a/drivers/media/video/msm/sensors/Makefile b/drivers/media/video/msm/sensors/Makefile
index 13dc446..ea36bf6 100644
--- a/drivers/media/video/msm/sensors/Makefile
+++ b/drivers/media/video/msm/sensors/Makefile
@@ -13,5 +13,5 @@
 obj-$(CONFIG_S5K4E1) += s5k4e1_v4l2.o
 obj-$(CONFIG_MT9E013) += mt9e013_v4l2.o
 obj-$(CONFIG_WEBCAM_OV9726) += ov9726_v4l2.o
-obj-$(CONFIG_WEBCAM_OV7692_QRD) += ov7692_qrd_v4l2.o
+obj-$(CONFIG_OV7692) += ov7692_v4l2.o
 obj-$(CONFIG_VX6953) += vx6953.o
diff --git a/drivers/media/video/msm/sensors/msm_sensor.c b/drivers/media/video/msm/sensors/msm_sensor.c
index ff5bb49..5b9eb31 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.c
+++ b/drivers/media/video/msm/sensors/msm_sensor.c
@@ -22,6 +22,13 @@
 	uint16_t cur_line = 0;
 	uint16_t exp_fl_lines = 0;
 	if (s_ctrl->sensor_exp_gain_info) {
+		if (s_ctrl->prev_gain && s_ctrl->prev_line &&
+			s_ctrl->func_tbl->sensor_write_exp_gain)
+			s_ctrl->func_tbl->sensor_write_exp_gain(
+				s_ctrl,
+				s_ctrl->prev_gain,
+				s_ctrl->prev_line);
+
 		msm_camera_i2c_read(s_ctrl->sensor_i2c_client,
 			s_ctrl->sensor_exp_gain_info->coarse_int_time_addr,
 			&cur_line,
@@ -136,20 +143,9 @@
 int32_t msm_sensor_set_fps(struct msm_sensor_ctrl_t *s_ctrl,
 						struct fps_cfg *fps)
 {
-	uint16_t total_lines_per_frame;
-	int32_t rc = 0;
 	s_ctrl->fps_divider = fps->fps_div;
 
-	if (s_ctrl->curr_res != MSM_SENSOR_INVALID_RES) {
-		total_lines_per_frame = (uint16_t)
-			((s_ctrl->curr_frame_length_lines) *
-			s_ctrl->fps_divider/Q10);
-
-		rc = msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
-			s_ctrl->sensor_output_reg_addr->frame_length_lines,
-			total_lines_per_frame, MSM_CAMERA_I2C_WORD_DATA);
-	}
-	return rc;
+	return 0;
 }
 
 int32_t msm_sensor_write_exp_gain1(struct msm_sensor_ctrl_t *s_ctrl,
@@ -429,6 +425,8 @@
 					s_ctrl,
 					cdata.cfg.exp_gain.gain,
 					cdata.cfg.exp_gain.line);
+			s_ctrl->prev_gain = cdata.cfg.exp_gain.gain;
+			s_ctrl->prev_line = cdata.cfg.exp_gain.line;
 			break;
 
 		case CFG_SET_PICT_EXP_GAIN:
diff --git a/drivers/media/video/msm/sensors/msm_sensor.h b/drivers/media/video/msm/sensors/msm_sensor.h
index 22cc05b..556f036 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.h
+++ b/drivers/media/video/msm/sensors/msm_sensor.h
@@ -153,6 +153,8 @@
 
 	uint16_t curr_line_length_pclk;
 	uint16_t curr_frame_length_lines;
+	uint16_t prev_gain;
+	uint16_t prev_line;
 
 	uint32_t fps_divider;
 	enum msm_sensor_resolution_t curr_res;
@@ -232,12 +234,6 @@
 int32_t msm_sensor_setting1(struct msm_sensor_ctrl_t *s_ctrl,
 			int update_type, int res);
 
-int32_t msm_sensor_setting2(struct msm_sensor_ctrl_t *s_ctrl,
-			int update_type, int res);
-
-int32_t msm_sensor_setting3(struct msm_sensor_ctrl_t *s_ctrl,
-			int update_type, int res);
-
 int msm_sensor_enable_debugfs(struct msm_sensor_ctrl_t *s_ctrl);
 
 long msm_sensor_subdev_ioctl(struct v4l2_subdev *sd,
diff --git a/drivers/media/video/msm/sensors/ov2720.c b/drivers/media/video/msm/sensors/ov2720.c
index 7531a26..40867fb 100644
--- a/drivers/media/video/msm/sensors/ov2720.c
+++ b/drivers/media/video/msm/sensors/ov2720.c
@@ -330,7 +330,7 @@
 	{0x4005, 0x08},
 	{0x404f, 0x84},
 	{0x4051, 0x00},
-	{0x5000, 0xff},
+	{0x5000, 0xcf},
 	{0x3a18, 0x00},
 	{0x3a19, 0x80},
 	{0x3503, 0x07},
@@ -427,7 +427,7 @@
 	{0x4005, 0x08},
 	{0x404f, 0x84},
 	{0x4051, 0x00},
-	{0x5000, 0xff},
+	{0x5000, 0xcf},
 	{0x3a18, 0x00},
 	{0x3a19, 0x80},
 	{0x3503, 0x07},
@@ -436,8 +436,8 @@
 	{0x5184, 0xb0},
 	{0x5185, 0xb0},
 	{0x370c, 0x0c},
-	{0x3035, 0x20},
-	{0x3036, 0x14},
+	{0x3035, 0x30},
+	{0x3036, 0x1e},
 	{0x3037, 0x21},
 	{0x303e, 0x19},
 	{0x3038, 0x06},
@@ -524,7 +524,7 @@
 	{0x4005, 0x08},
 	{0x404f, 0x84},
 	{0x4051, 0x00},
-	{0x5000, 0xff},
+	{0x5000, 0xcf},
 	{0x3a18, 0x00},
 	{0x3a19, 0x80},
 	{0x3503, 0x07},
diff --git a/drivers/media/video/msm/sensors/ov5647_v4l2.c b/drivers/media/video/msm/sensors/ov5647_v4l2.c
index 48f1d5d..90186ee 100644
--- a/drivers/media/video/msm/sensors/ov5647_v4l2.c
+++ b/drivers/media/video/msm/sensors/ov5647_v4l2.c
@@ -457,7 +457,6 @@
 
 	CDBG(KERN_ERR "snapshot exposure seting 0x%x, 0x%x, %d"
 		, gain, line, line);
-
 	s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl);
 	if (line > 1964) {
 		msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
@@ -571,7 +570,7 @@
 	s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl);
 
 	/* adjust frame rate */
-	if (line > 980 && line <= 984) {
+	if (line > 980) {
 		msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
 		s_ctrl->sensor_output_reg_addr->frame_length_lines,
 		(uint8_t)((line+4) >> 8),
diff --git a/drivers/media/video/msm/sensors/ov7692_qrd_v4l2.c b/drivers/media/video/msm/sensors/ov7692_v4l2.c
similarity index 100%
rename from drivers/media/video/msm/sensors/ov7692_qrd_v4l2.c
rename to drivers/media/video/msm/sensors/ov7692_v4l2.c
diff --git a/drivers/media/video/msm/server/Makefile b/drivers/media/video/msm/server/Makefile
new file mode 100644
index 0000000..55abeed
--- /dev/null
+++ b/drivers/media/video/msm/server/Makefile
@@ -0,0 +1,11 @@
+GCC_VERSION      := $(shell $(CONFIG_SHELL) $(PWD)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc)
+
+ifeq ($(CONFIG_MSM_CAMERA_V4L2),y)
+  EXTRA_CFLAGS += -Idrivers/media/video/msm
+  EXTRA_CFLAGS += -Idrivers/media/video/msm/io
+  EXTRA_CFLAGS += -Idrivers/media/video/msm/csi
+  EXTRA_CFLAGS += -Idrivers/media/video/msm/eeprom
+  EXTRA_CFLAGS += -Idrivers/media/video/msm/sensors
+  EXTRA_CFLAGS += -Idrivers/media/video/msm/actuators
+  obj-$(CONFIG_MSM_CAMERA)   += msm_cam_server.o
+endif
diff --git a/drivers/media/video/msm/server/msm_cam_server.c b/drivers/media/video/msm/server/msm_cam_server.c
new file mode 100644
index 0000000..7154797f
--- /dev/null
+++ b/drivers/media/video/msm/server/msm_cam_server.c
@@ -0,0 +1,2318 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "msm_cam_server.h"
+#include "msm_csid.h"
+#include "msm_csic.h"
+#include "msm_csiphy.h"
+#include "msm_ispif.h"
+#include "msm_sensor.h"
+#include "msm_actuator.h"
+#include "msm_vfe32.h"
+
+#ifdef CONFIG_MSM_CAMERA_DEBUG
+#define D(fmt, args...) pr_debug("msm: " fmt, ##args)
+#else
+#define D(fmt, args...) do {} while (0)
+#endif
+
+static struct msm_cam_server_dev g_server_dev;
+static struct class *msm_class;
+static dev_t msm_devno;
+
+static long msm_server_send_v4l2_evt(void *evt);
+static void msm_cam_server_subdev_notify(struct v4l2_subdev *sd,
+	unsigned int notification, void *arg);
+
+static void msm_queue_init(struct msm_device_queue *queue, const char *name)
+{
+	D("%s\n", __func__);
+	spin_lock_init(&queue->lock);
+	queue->len = 0;
+	queue->max = 0;
+	queue->name = name;
+	INIT_LIST_HEAD(&queue->list);
+	init_waitqueue_head(&queue->wait);
+}
+
+static void msm_enqueue(struct msm_device_queue *queue,
+			struct list_head *entry)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&queue->lock, flags);
+	queue->len++;
+	if (queue->len > queue->max) {
+		queue->max = queue->len;
+		pr_info("%s: queue %s new max is %d\n", __func__,
+			queue->name, queue->max);
+	}
+	list_add_tail(entry, &queue->list);
+	wake_up(&queue->wait);
+	D("%s: woke up %s\n", __func__, queue->name);
+	spin_unlock_irqrestore(&queue->lock, flags);
+}
+
+static void msm_drain_eventq(struct msm_device_queue *queue)
+{
+	unsigned long flags;
+	struct msm_queue_cmd *qcmd;
+	struct msm_isp_event_ctrl *isp_event;
+	spin_lock_irqsave(&queue->lock, flags);
+	while (!list_empty(&queue->list)) {
+		qcmd = list_first_entry(&queue->list,
+			struct msm_queue_cmd, list_eventdata);
+		list_del_init(&qcmd->list_eventdata);
+		isp_event =
+			(struct msm_isp_event_ctrl *)
+			qcmd->command;
+		if (isp_event->isp_data.ctrl.value != NULL)
+			kfree(isp_event->isp_data.ctrl.value);
+		kfree(qcmd->command);
+		free_qcmd(qcmd);
+	}
+	spin_unlock_irqrestore(&queue->lock, flags);
+}
+
+int32_t msm_find_free_queue(void)
+{
+	int i;
+	for (i = 0; i < MAX_NUM_ACTIVE_CAMERA; i++) {
+		struct msm_cam_server_queue *queue;
+		queue = &g_server_dev.server_queue[i];
+		if (!queue->queue_active)
+			return i;
+	}
+	return -EINVAL;
+}
+
+uint32_t msm_cam_server_get_mctl_handle(void)
+{
+	uint32_t i;
+	if ((g_server_dev.mctl_handle_cnt << 8) == 0)
+		g_server_dev.mctl_handle_cnt++;
+	for (i = 0; i < MAX_NUM_ACTIVE_CAMERA; i++) {
+		if (g_server_dev.mctl[i].handle == 0) {
+			g_server_dev.mctl[i].handle =
+				(++g_server_dev.mctl_handle_cnt) << 8 | i;
+			memset(&g_server_dev.mctl[i].mctl,
+				   0, sizeof(g_server_dev.mctl[i].mctl));
+			return g_server_dev.mctl[i].handle;
+		}
+	}
+	return 0;
+}
+
+void msm_cam_server_free_mctl(uint32_t handle)
+{
+	uint32_t mctl_index;
+	mctl_index = handle & 0xff;
+	if ((mctl_index < MAX_NUM_ACTIVE_CAMERA) &&
+		(g_server_dev.mctl[mctl_index].handle == handle))
+		g_server_dev.mctl[mctl_index].handle = 0;
+	else
+		pr_err("%s: invalid free handle\n", __func__);
+}
+
+struct msm_cam_media_controller *msm_cam_server_get_mctl(uint32_t handle)
+{
+	uint32_t mctl_index;
+	mctl_index = handle & 0xff;
+	if ((mctl_index < MAX_NUM_ACTIVE_CAMERA) &&
+		(g_server_dev.mctl[mctl_index].handle == handle))
+		return &g_server_dev.mctl[mctl_index].mctl;
+	return NULL;
+}
+
+static int msm_ctrl_cmd_done(void *arg)
+{
+	void __user *uptr;
+	struct msm_queue_cmd *qcmd;
+	struct msm_camera_v4l2_ioctl_t *ioctl_ptr = arg;
+	struct msm_ctrl_cmd *command;
+	D("%s\n", __func__);
+
+	command = kzalloc(sizeof(struct msm_ctrl_cmd), GFP_KERNEL);
+	if (!command) {
+		pr_err("%s Insufficient memory. return", __func__);
+		goto command_alloc_fail;
+	}
+
+	qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_KERNEL);
+	if (!qcmd) {
+		pr_err("%s Insufficient memory. return", __func__);
+		goto qcmd_alloc_fail;
+	}
+
+	mutex_lock(&g_server_dev.server_queue_lock);
+
+	if (copy_from_user(command, (void __user *)ioctl_ptr->ioctl_ptr,
+					   sizeof(struct msm_ctrl_cmd))) {
+		pr_err("%s: copy_from_user failed, size=%d\n",
+			   __func__, sizeof(struct msm_ctrl_cmd));
+		goto ctrl_cmd_done_error;
+	}
+
+	if (!g_server_dev.server_queue[command->queue_idx].queue_active) {
+		pr_err("%s: Invalid queue\n", __func__);
+		goto ctrl_cmd_done_error;
+	}
+
+	D("%s qid %d evtid %d %d\n", __func__, command->queue_idx,
+		command->evt_id,
+		g_server_dev.server_queue[command->queue_idx].evt_id);
+
+	if (command->evt_id !=
+		g_server_dev.server_queue[command->queue_idx].evt_id) {
+		pr_err("Invalid event id from userspace\n");
+		goto ctrl_cmd_done_error;
+	}
+
+	atomic_set(&qcmd->on_heap, 1);
+	uptr = command->value;
+	qcmd->command = command;
+
+	if (command->length > 0) {
+		command->value =
+			g_server_dev.server_queue[command->queue_idx].ctrl_data;
+		if (command->length > max_control_command_size) {
+			pr_err("%s: user data %d is too big (max %d)\n",
+				__func__, command->length,
+				max_control_command_size);
+			goto ctrl_cmd_done_error;
+		}
+		if (copy_from_user(command->value, uptr, command->length)) {
+			pr_err("%s: copy_from_user failed, size=%d\n",
+				__func__, sizeof(struct msm_ctrl_cmd));
+			goto ctrl_cmd_done_error;
+		}
+	}
+	msm_enqueue(&g_server_dev.server_queue
+		[command->queue_idx].ctrl_q, &qcmd->list_control);
+	mutex_unlock(&g_server_dev.server_queue_lock);
+	return 0;
+
+ctrl_cmd_done_error:
+	mutex_unlock(&g_server_dev.server_queue_lock);
+	free_qcmd(qcmd);
+qcmd_alloc_fail:
+	kfree(command);
+command_alloc_fail:
+	return -EINVAL;
+}
+
+/* send control command to config and wait for results*/
+static int msm_server_control(struct msm_cam_server_dev *server_dev,
+				struct msm_ctrl_cmd *out)
+{
+	int rc = 0;
+	void *value;
+	struct msm_queue_cmd *rcmd;
+	struct msm_queue_cmd *event_qcmd;
+	struct msm_ctrl_cmd *ctrlcmd;
+	struct msm_device_queue *queue =
+		&server_dev->server_queue[out->queue_idx].ctrl_q;
+
+	struct v4l2_event v4l2_evt;
+	struct msm_isp_event_ctrl *isp_event;
+	void *ctrlcmd_data;
+
+	event_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_KERNEL);
+	if (!event_qcmd) {
+		pr_err("%s Insufficient memory. return", __func__);
+		rc = -ENOMEM;
+		goto event_qcmd_alloc_fail;
+	}
+
+	isp_event = kzalloc(sizeof(struct msm_isp_event_ctrl), GFP_KERNEL);
+	if (!isp_event) {
+		pr_err("%s Insufficient memory. return", __func__);
+		rc = -ENOMEM;
+		goto isp_event_alloc_fail;
+	}
+
+	D("%s\n", __func__);
+	mutex_lock(&server_dev->server_queue_lock);
+	if (++server_dev->server_evt_id == 0)
+		server_dev->server_evt_id++;
+
+	D("%s qid %d evtid %d\n", __func__, out->queue_idx,
+		server_dev->server_evt_id);
+	server_dev->server_queue[out->queue_idx].evt_id =
+		server_dev->server_evt_id;
+	v4l2_evt.type = V4L2_EVENT_PRIVATE_START + MSM_CAM_RESP_V4L2;
+	v4l2_evt.u.data[0] = out->queue_idx;
+	/* setup event object to transfer the command; */
+	isp_event->resptype = MSM_CAM_RESP_V4L2;
+	isp_event->isp_data.ctrl = *out;
+	isp_event->isp_data.ctrl.evt_id = server_dev->server_evt_id;
+
+	if (out->value != NULL && out->length != 0) {
+		ctrlcmd_data = kzalloc(out->length, GFP_KERNEL);
+		if (!ctrlcmd_data) {
+			rc = -ENOMEM;
+			goto ctrlcmd_alloc_fail;
+		}
+		memcpy(ctrlcmd_data, out->value, out->length);
+		isp_event->isp_data.ctrl.value = ctrlcmd_data;
+	}
+
+	atomic_set(&event_qcmd->on_heap, 1);
+	event_qcmd->command = isp_event;
+
+	msm_enqueue(&server_dev->server_queue[out->queue_idx].eventData_q,
+				&event_qcmd->list_eventdata);
+
+	/* now send command to config thread in userspace,
+	 * and wait for results */
+	v4l2_event_queue(server_dev->server_command_queue.pvdev,
+					  &v4l2_evt);
+	D("%s v4l2_event_queue: type = 0x%x\n", __func__, v4l2_evt.type);
+	mutex_unlock(&server_dev->server_queue_lock);
+
+	/* wait for config return status */
+	D("Waiting for config status\n");
+	rc = wait_event_interruptible_timeout(queue->wait,
+		!list_empty_careful(&queue->list),
+		msecs_to_jiffies(out->timeout_ms));
+	D("Waiting is over for config status\n");
+	if (list_empty_careful(&queue->list)) {
+		if (!rc)
+			rc = -ETIMEDOUT;
+		if (rc < 0) {
+			if (++server_dev->server_evt_id == 0)
+				server_dev->server_evt_id++;
+			pr_err("%s: wait_event error %d\n", __func__, rc);
+			return rc;
+		}
+	}
+
+	rcmd = msm_dequeue(queue, list_control);
+	BUG_ON(!rcmd);
+	D("%s Finished servicing ioctl\n", __func__);
+
+	ctrlcmd = (struct msm_ctrl_cmd *)(rcmd->command);
+	value = out->value;
+	if (ctrlcmd->length > 0 && value != NULL &&
+		ctrlcmd->length <= out->length)
+		memcpy(value, ctrlcmd->value, ctrlcmd->length);
+
+	memcpy(out, ctrlcmd, sizeof(struct msm_ctrl_cmd));
+	out->value = value;
+
+	kfree(ctrlcmd);
+	free_qcmd(rcmd);
+	D("%s: rc %d\n", __func__, rc);
+	/* rc is the time elapsed. */
+	if (rc >= 0) {
+		/* TODO: Refactor msm_ctrl_cmd::status field */
+		if (out->status == 0)
+			rc = -1;
+		else if (out->status == 1 || out->status == 4)
+			rc = 0;
+		else
+			rc = -EINVAL;
+	}
+	return rc;
+
+ctrlcmd_alloc_fail:
+	kfree(isp_event);
+isp_event_alloc_fail:
+	kfree(event_qcmd);
+event_qcmd_alloc_fail:
+	return rc;
+}
+
+int msm_server_get_crop(struct msm_cam_v4l2_device *pcam,
+				int idx, struct v4l2_crop *crop)
+{
+	int rc = 0;
+	struct msm_ctrl_cmd ctrlcmd;
+
+	BUG_ON(crop == NULL);
+
+	ctrlcmd.type = MSM_V4L2_GET_CROP;
+	ctrlcmd.length = sizeof(struct v4l2_crop);
+	ctrlcmd.value = (void *)crop;
+	ctrlcmd.timeout_ms = 1000;
+	ctrlcmd.vnode_id = pcam->vnode_id;
+	ctrlcmd.queue_idx = pcam->server_queue_idx;
+	ctrlcmd.stream_type = pcam->dev_inst[idx]->image_mode;
+	ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
+
+	/* send command to config thread in userspace, and get return value */
+	rc = msm_server_control(&g_server_dev, &ctrlcmd);
+	D("%s: rc = %d\n", __func__, rc);
+
+	return rc;
+}
+
+/*send open command to server*/
+int msm_send_open_server(struct msm_cam_v4l2_device *pcam)
+{
+	int rc = 0;
+	struct msm_ctrl_cmd ctrlcmd;
+	D("%s qid %d\n", __func__, pcam->server_queue_idx);
+	ctrlcmd.type	   = MSM_V4L2_OPEN;
+	ctrlcmd.timeout_ms = 10000;
+	ctrlcmd.length	 = strnlen(g_server_dev.config_info.config_dev_name[0],
+				MAX_DEV_NAME_LEN)+1;
+	ctrlcmd.value    = (char *)g_server_dev.config_info.config_dev_name[0];
+	ctrlcmd.vnode_id = pcam->vnode_id;
+	ctrlcmd.queue_idx = pcam->server_queue_idx;
+	ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
+
+	/* send command to config thread in usersspace, and get return value */
+	rc = msm_server_control(&g_server_dev, &ctrlcmd);
+
+	return rc;
+}
+
+int msm_send_close_server(struct msm_cam_v4l2_device *pcam)
+{
+	int rc = 0;
+	struct msm_ctrl_cmd ctrlcmd;
+	D("%s qid %d\n", __func__, pcam->server_queue_idx);
+	ctrlcmd.type	   = MSM_V4L2_CLOSE;
+	ctrlcmd.timeout_ms = 10000;
+	ctrlcmd.length	 = strnlen(g_server_dev.config_info.config_dev_name[0],
+				MAX_DEV_NAME_LEN)+1;
+	ctrlcmd.value    = (char *)g_server_dev.config_info.config_dev_name[0];
+	ctrlcmd.vnode_id = pcam->vnode_id;
+	ctrlcmd.queue_idx = pcam->server_queue_idx;
+	ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
+
+	/* send command to config thread in usersspace, and get return value */
+	rc = msm_server_control(&g_server_dev, &ctrlcmd);
+
+	return rc;
+}
+
+int msm_server_set_fmt(struct msm_cam_v4l2_device *pcam, int idx,
+				 struct v4l2_format *pfmt)
+{
+	int rc = 0;
+	int i = 0;
+	struct v4l2_pix_format *pix = &pfmt->fmt.pix;
+	struct msm_ctrl_cmd ctrlcmd;
+	struct img_plane_info plane_info;
+
+	plane_info.width = pix->width;
+	plane_info.height = pix->height;
+	plane_info.pixelformat = pix->pixelformat;
+	plane_info.buffer_type = pfmt->type;
+	plane_info.ext_mode = pcam->dev_inst[idx]->image_mode;
+	plane_info.num_planes = 1;
+	D("%s: %d, %d, 0x%x\n", __func__,
+		pfmt->fmt.pix.width, pfmt->fmt.pix.height,
+		pfmt->fmt.pix.pixelformat);
+
+	if (pfmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		D("%s, Attention! Wrong buf-type %d\n", __func__, pfmt->type);
+
+	for (i = 0; i < pcam->num_fmts; i++)
+		if (pcam->usr_fmts[i].fourcc == pix->pixelformat)
+			break;
+	if (i == pcam->num_fmts) {
+		pr_err("%s: User requested pixelformat %x not supported\n",
+						__func__, pix->pixelformat);
+		return -EINVAL;
+	}
+
+	ctrlcmd.type       = MSM_V4L2_VID_CAP_TYPE;
+	ctrlcmd.length     = sizeof(struct img_plane_info);
+	ctrlcmd.value      = (void *)&plane_info;
+	ctrlcmd.timeout_ms = 10000;
+	ctrlcmd.vnode_id   = pcam->vnode_id;
+	ctrlcmd.queue_idx = pcam->server_queue_idx;
+	ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
+
+	/* send command to config thread in usersspace, and get return value */
+	rc = msm_server_control(&g_server_dev, &ctrlcmd);
+
+	if (rc >= 0) {
+		pcam->dev_inst[idx]->vid_fmt = *pfmt;
+		pcam->dev_inst[idx]->sensor_pxlcode
+					= pcam->usr_fmts[i].pxlcode;
+		D("%s:inst=0x%x,idx=%d,width=%d,heigth=%d\n",
+			 __func__, (u32)pcam->dev_inst[idx], idx,
+			 pcam->dev_inst[idx]->vid_fmt.fmt.pix.width,
+			 pcam->dev_inst[idx]->vid_fmt.fmt.pix.height);
+		pcam->dev_inst[idx]->plane_info = plane_info;
+	}
+
+	return rc;
+}
+
+int msm_server_set_fmt_mplane(struct msm_cam_v4l2_device *pcam, int idx,
+				 struct v4l2_format *pfmt)
+{
+	int rc = 0;
+	int i = 0;
+	struct v4l2_pix_format_mplane *pix_mp = &pfmt->fmt.pix_mp;
+	struct msm_ctrl_cmd ctrlcmd;
+	struct img_plane_info plane_info;
+
+	plane_info.width = pix_mp->width;
+	plane_info.height = pix_mp->height;
+	plane_info.pixelformat = pix_mp->pixelformat;
+	plane_info.buffer_type = pfmt->type;
+	plane_info.ext_mode = pcam->dev_inst[idx]->image_mode;
+	plane_info.num_planes = pix_mp->num_planes;
+	if (plane_info.num_planes <= 0 ||
+		plane_info.num_planes > VIDEO_MAX_PLANES) {
+		pr_err("%s Invalid number of planes set %d", __func__,
+				plane_info.num_planes);
+		return -EINVAL;
+	}
+	D("%s: %d, %d, 0x%x\n", __func__,
+		pfmt->fmt.pix_mp.width, pfmt->fmt.pix_mp.height,
+		pfmt->fmt.pix_mp.pixelformat);
+
+	if (pfmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		pr_err("%s, Attention! Wrong buf-type %d\n",
+			__func__, pfmt->type);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < pcam->num_fmts; i++)
+		if (pcam->usr_fmts[i].fourcc == pix_mp->pixelformat)
+			break;
+	if (i == pcam->num_fmts) {
+		pr_err("%s: User requested pixelformat %x not supported\n",
+						__func__, pix_mp->pixelformat);
+		return -EINVAL;
+	}
+
+	ctrlcmd.type       = MSM_V4L2_VID_CAP_TYPE;
+	ctrlcmd.length     = sizeof(struct img_plane_info);
+	ctrlcmd.value      = (void *)&plane_info;
+	ctrlcmd.timeout_ms = 10000;
+	ctrlcmd.vnode_id   = pcam->vnode_id;
+	ctrlcmd.queue_idx = pcam->server_queue_idx;
+
+	/* send command to config thread in usersspace, and get return value */
+	rc = msm_server_control(&g_server_dev, &ctrlcmd);
+	if (rc >= 0) {
+		pcam->dev_inst[idx]->vid_fmt = *pfmt;
+		pcam->dev_inst[idx]->sensor_pxlcode
+					= pcam->usr_fmts[i].pxlcode;
+		D("%s:inst=0x%x,idx=%d,width=%d,heigth=%d\n",
+			 __func__, (u32)pcam->dev_inst[idx], idx,
+			 pcam->dev_inst[idx]->vid_fmt.fmt.pix_mp.width,
+			 pcam->dev_inst[idx]->vid_fmt.fmt.pix_mp.height);
+		pcam->dev_inst[idx]->plane_info = plane_info;
+	}
+
+	return rc;
+}
+
+int msm_server_streamon(struct msm_cam_v4l2_device *pcam, int idx)
+{
+	int rc = 0;
+	struct msm_ctrl_cmd ctrlcmd;
+	D("%s\n", __func__);
+	ctrlcmd.type	   = MSM_V4L2_STREAM_ON;
+	ctrlcmd.timeout_ms = 10000;
+	ctrlcmd.length	 = 0;
+	ctrlcmd.value    = NULL;
+	ctrlcmd.stream_type = pcam->dev_inst[idx]->image_mode;
+	ctrlcmd.vnode_id = pcam->vnode_id;
+	ctrlcmd.queue_idx = pcam->server_queue_idx;
+	ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
+
+
+	/* send command to config thread in usersspace, and get return value */
+	rc = msm_server_control(&g_server_dev, &ctrlcmd);
+
+	return rc;
+}
+
+int msm_server_streamoff(struct msm_cam_v4l2_device *pcam, int idx)
+{
+	int rc = 0;
+	struct msm_ctrl_cmd ctrlcmd;
+
+	D("%s, pcam = 0x%x\n", __func__, (u32)pcam);
+	ctrlcmd.type        = MSM_V4L2_STREAM_OFF;
+	ctrlcmd.timeout_ms  = 10000;
+	ctrlcmd.length      = 0;
+	ctrlcmd.value       = NULL;
+	ctrlcmd.stream_type = pcam->dev_inst[idx]->image_mode;
+	ctrlcmd.vnode_id = pcam->vnode_id;
+	ctrlcmd.queue_idx = pcam->server_queue_idx;
+	ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
+
+	/* send command to config thread in usersspace, and get return value */
+	rc = msm_server_control(&g_server_dev, &ctrlcmd);
+
+	return rc;
+}
+
+int msm_server_proc_ctrl_cmd(struct msm_cam_v4l2_device *pcam,
+				 struct v4l2_control *ctrl, int is_set_cmd)
+{
+	int rc = 0;
+	struct msm_ctrl_cmd ctrlcmd, *tmp_cmd;
+	uint8_t *ctrl_data = NULL;
+	void __user *uptr_cmd;
+	void __user *uptr_value;
+	uint32_t cmd_len = sizeof(struct msm_ctrl_cmd);
+	uint32_t value_len;
+
+	tmp_cmd = (struct msm_ctrl_cmd *)ctrl->value;
+	uptr_cmd = (void __user *)ctrl->value;
+	uptr_value = (void __user *)tmp_cmd->value;
+	value_len = tmp_cmd->length;
+
+	D("%s: cmd type = %d, up1=0x%x, ulen1=%d, up2=0x%x, ulen2=%d\n",
+		__func__, tmp_cmd->type, (uint32_t)uptr_cmd, cmd_len,
+		(uint32_t)uptr_value, tmp_cmd->length);
+
+	ctrl_data = kzalloc(value_len+cmd_len, GFP_KERNEL);
+	if (ctrl_data == 0) {
+		pr_err("%s could not allocate memory\n", __func__);
+		rc = -ENOMEM;
+		goto end;
+	}
+	tmp_cmd = (struct msm_ctrl_cmd *)ctrl_data;
+	if (copy_from_user((void *)ctrl_data, uptr_cmd,
+					cmd_len)) {
+		pr_err("%s: copy_from_user failed.\n", __func__);
+		rc = -EINVAL;
+		goto end;
+	}
+	tmp_cmd->value = (void *)(ctrl_data+cmd_len);
+	if (uptr_value && tmp_cmd->length > 0) {
+		if (copy_from_user((void *)tmp_cmd->value, uptr_value,
+						value_len)) {
+			pr_err("%s: copy_from_user failed, size=%d\n",
+				__func__, value_len);
+			rc = -EINVAL;
+			goto end;
+		}
+	} else
+	tmp_cmd->value = NULL;
+
+	ctrlcmd.type = MSM_V4L2_SET_CTRL_CMD;
+	ctrlcmd.length = cmd_len + value_len;
+	ctrlcmd.value = (void *)ctrl_data;
+	if (tmp_cmd->timeout_ms > 0)
+		ctrlcmd.timeout_ms = tmp_cmd->timeout_ms;
+	else
+		ctrlcmd.timeout_ms = 1000;
+	ctrlcmd.vnode_id = pcam->vnode_id;
+	ctrlcmd.queue_idx = pcam->server_queue_idx;
+	ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
+	/* send command to config thread in usersspace, and get return value */
+	rc = msm_server_control(&g_server_dev, &ctrlcmd);
+	D("%s: msm_server_control rc=%d\n", __func__, rc);
+	if (rc == 0) {
+		if (uptr_value && tmp_cmd->length > 0 &&
+			copy_to_user((void __user *)uptr_value,
+				(void *)(ctrl_data+cmd_len), tmp_cmd->length)) {
+			pr_err("%s: copy_to_user failed, size=%d\n",
+				__func__, tmp_cmd->length);
+			rc = -EINVAL;
+			goto end;
+		}
+		tmp_cmd->value = uptr_value;
+		if (copy_to_user((void __user *)uptr_cmd,
+			(void *)tmp_cmd, cmd_len)) {
+			pr_err("%s: copy_to_user failed in cpy, size=%d\n",
+				__func__, cmd_len);
+			rc = -EINVAL;
+			goto end;
+		}
+	}
+end:
+	D("%s: END, type = %d, vaddr = 0x%x, vlen = %d, status = %d, rc = %d\n",
+		__func__, tmp_cmd->type, (uint32_t)tmp_cmd->value,
+		tmp_cmd->length, tmp_cmd->status, rc);
+	kfree(ctrl_data);
+	return rc;
+}
+
+int msm_server_s_ctrl(struct msm_cam_v4l2_device *pcam,
+				 struct v4l2_control *ctrl)
+{
+	int rc = 0;
+	struct msm_ctrl_cmd ctrlcmd;
+	uint8_t ctrl_data[max_control_command_size];
+
+	WARN_ON(ctrl == NULL);
+	if (ctrl == NULL) {
+		pr_err("%s Invalid control\n", __func__);
+		return -EINVAL;
+	}
+	if (ctrl->id == MSM_V4L2_PID_CTRL_CMD)
+		return msm_server_proc_ctrl_cmd(pcam, ctrl, 1);
+
+	memset(ctrl_data, 0, sizeof(ctrl_data));
+
+	ctrlcmd.type = MSM_V4L2_SET_CTRL;
+	ctrlcmd.length = sizeof(struct v4l2_control);
+	ctrlcmd.value = (void *)ctrl_data;
+	memcpy(ctrlcmd.value, ctrl, ctrlcmd.length);
+	ctrlcmd.timeout_ms = 1000;
+	ctrlcmd.vnode_id = pcam->vnode_id;
+	ctrlcmd.queue_idx = pcam->server_queue_idx;
+	ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
+
+	/* send command to config thread in usersspace, and get return value */
+	rc = msm_server_control(&g_server_dev, &ctrlcmd);
+
+	return rc;
+}
+
+int msm_server_g_ctrl(struct msm_cam_v4l2_device *pcam,
+				 struct v4l2_control *ctrl)
+{
+	int rc = 0;
+	struct msm_ctrl_cmd ctrlcmd;
+	uint8_t ctrl_data[max_control_command_size];
+
+	WARN_ON(ctrl == NULL);
+	if (ctrl == NULL) {
+		pr_err("%s Invalid control\n", __func__);
+		return -EINVAL;
+	}
+	if (ctrl->id == MSM_V4L2_PID_CTRL_CMD)
+		return msm_server_proc_ctrl_cmd(pcam, ctrl, 0);
+
+	memset(ctrl_data, 0, sizeof(ctrl_data));
+
+	ctrlcmd.type = MSM_V4L2_GET_CTRL;
+	ctrlcmd.length = sizeof(struct v4l2_control);
+	ctrlcmd.value = (void *)ctrl_data;
+	memcpy(ctrlcmd.value, ctrl, ctrlcmd.length);
+	ctrlcmd.timeout_ms = 1000;
+	ctrlcmd.vnode_id = pcam->vnode_id;
+	ctrlcmd.queue_idx = pcam->server_queue_idx;
+	ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
+
+	/* send command to config thread in usersspace, and get return value */
+	rc = msm_server_control(&g_server_dev, &ctrlcmd);
+
+	ctrl->value = ((struct v4l2_control *)ctrlcmd.value)->value;
+
+	return rc;
+}
+
+int msm_server_q_ctrl(struct msm_cam_v4l2_device *pcam,
+			struct v4l2_queryctrl *queryctrl)
+{
+	int rc = 0;
+	struct msm_ctrl_cmd ctrlcmd;
+	uint8_t ctrl_data[max_control_command_size];
+
+	WARN_ON(queryctrl == NULL);
+	memset(ctrl_data, 0, sizeof(ctrl_data));
+
+	ctrlcmd.type = MSM_V4L2_QUERY_CTRL;
+	ctrlcmd.length = sizeof(struct v4l2_queryctrl);
+	ctrlcmd.value = (void *)ctrl_data;
+	memcpy(ctrlcmd.value, queryctrl, ctrlcmd.length);
+	ctrlcmd.timeout_ms = 1000;
+	ctrlcmd.vnode_id = pcam->vnode_id;
+	ctrlcmd.queue_idx = pcam->server_queue_idx;
+	ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
+
+	/* send command to config thread in userspace, and get return value */
+	rc = msm_server_control(&g_server_dev, &ctrlcmd);
+	D("%s: rc = %d\n", __func__, rc);
+
+	if (rc >= 0)
+		memcpy(queryctrl, ctrlcmd.value, sizeof(struct v4l2_queryctrl));
+
+	return rc;
+}
+
+int msm_server_get_fmt(struct msm_cam_v4l2_device *pcam,
+		 int idx, struct v4l2_format *pfmt)
+{
+	struct v4l2_pix_format *pix = &pfmt->fmt.pix;
+
+	pix->width        = pcam->dev_inst[idx]->vid_fmt.fmt.pix.width;
+	pix->height       = pcam->dev_inst[idx]->vid_fmt.fmt.pix.height;
+	pix->field        = pcam->dev_inst[idx]->vid_fmt.fmt.pix.field;
+	pix->pixelformat  = pcam->dev_inst[idx]->vid_fmt.fmt.pix.pixelformat;
+	pix->bytesperline = pcam->dev_inst[idx]->vid_fmt.fmt.pix.bytesperline;
+	pix->colorspace   = pcam->dev_inst[idx]->vid_fmt.fmt.pix.colorspace;
+	if (pix->bytesperline < 0)
+		return pix->bytesperline;
+
+	pix->sizeimage    = pix->height * pix->bytesperline;
+
+	return 0;
+}
+
+int msm_server_get_fmt_mplane(struct msm_cam_v4l2_device *pcam,
+		 int idx, struct v4l2_format *pfmt)
+{
+	*pfmt = pcam->dev_inst[idx]->vid_fmt;
+	return 0;
+}
+
+int msm_server_try_fmt(struct msm_cam_v4l2_device *pcam,
+				 struct v4l2_format *pfmt)
+{
+	int rc = 0;
+	int i = 0;
+	struct v4l2_pix_format *pix = &pfmt->fmt.pix;
+
+	D("%s: 0x%x\n", __func__, pix->pixelformat);
+	if (pfmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+		pr_err("%s: pfmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE!\n",
+							__func__);
+		return -EINVAL;
+	}
+
+	/* check if the format is supported by this host-sensor combo */
+	for (i = 0; i < pcam->num_fmts; i++) {
+		D("%s: usr_fmts.fourcc: 0x%x\n", __func__,
+			pcam->usr_fmts[i].fourcc);
+		if (pcam->usr_fmts[i].fourcc == pix->pixelformat)
+			break;
+	}
+
+	if (i == pcam->num_fmts) {
+		pr_err("%s: Format %x not found\n", __func__, pix->pixelformat);
+		return -EINVAL;
+	}
+	return rc;
+}
+
+int msm_server_try_fmt_mplane(struct msm_cam_v4l2_device *pcam,
+				 struct v4l2_format *pfmt)
+{
+	int rc = 0;
+	int i = 0;
+	struct v4l2_pix_format_mplane *pix_mp = &pfmt->fmt.pix_mp;
+
+	D("%s: 0x%x\n", __func__, pix_mp->pixelformat);
+	if (pfmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		pr_err("%s: Incorrect format type %d ",
+			__func__, pfmt->type);
+		return -EINVAL;
+	}
+
+	/* check if the format is supported by this host-sensor combo */
+	for (i = 0; i < pcam->num_fmts; i++) {
+		D("%s: usr_fmts.fourcc: 0x%x\n", __func__,
+			pcam->usr_fmts[i].fourcc);
+		if (pcam->usr_fmts[i].fourcc == pix_mp->pixelformat)
+			break;
+	}
+
+	if (i == pcam->num_fmts) {
+		pr_err("%s: Format %x not found\n",
+			__func__, pix_mp->pixelformat);
+		return -EINVAL;
+	}
+	return rc;
+}
+
+int msm_server_v4l2_subscribe_event(struct v4l2_fh *fh,
+			struct v4l2_event_subscription *sub)
+{
+	int rc = 0;
+
+	D("%s: fh = 0x%x, type = 0x%x", __func__, (u32)fh, sub->type);
+	if (sub->type == V4L2_EVENT_ALL) {
+		/*sub->type = MSM_ISP_EVENT_START;*/
+		sub->type = V4L2_EVENT_PRIVATE_START + MSM_CAM_RESP_CTRL;
+		D("sub->type start = 0x%x\n", sub->type);
+		do {
+			rc = v4l2_event_subscribe(fh, sub);
+			if (rc < 0) {
+				D("%s: failed for evtType = 0x%x, rc = %d\n",
+						__func__, sub->type, rc);
+			/* unsubscribe all events here and return */
+			sub->type = V4L2_EVENT_ALL;
+			v4l2_event_unsubscribe(fh, sub);
+			return rc;
+			} else
+				D("%s: subscribed evtType = 0x%x, rc = %d\n",
+						__func__, sub->type, rc);
+			sub->type++;
+			D("sub->type while = 0x%x\n", sub->type);
+		} while (sub->type !=
+			V4L2_EVENT_PRIVATE_START + MSM_SVR_RESP_MAX);
+	} else {
+		D("sub->type not V4L2_EVENT_ALL = 0x%x\n", sub->type);
+		rc = v4l2_event_subscribe(fh, sub);
+		if (rc < 0)
+			D("%s: failed for evtType = 0x%x, rc = %d\n",
+						__func__, sub->type, rc);
+	}
+
+	D("%s: rc = %d\n", __func__, rc);
+	return rc;
+}
+
+int msm_server_v4l2_unsubscribe_event(struct v4l2_fh *fh,
+			struct v4l2_event_subscription *sub)
+{
+	int rc = 0;
+
+	D("%s: fh = 0x%x\n", __func__, (u32)fh);
+	rc = v4l2_event_unsubscribe(fh, sub);
+	D("%s: rc = %d\n", __func__, rc);
+	return rc;
+}
+
+/* open an active camera session to manage the streaming logic */
+static int msm_cam_server_open_session(struct msm_cam_server_dev *ps,
+	struct msm_cam_v4l2_device *pcam)
+{
+	int rc = 0;
+	struct msm_cam_media_controller *pmctl;
+
+	D("%s\n", __func__);
+
+	if (!ps || !pcam) {
+		pr_err("%s NULL pointer passed in!\n", __func__);
+		return rc;
+	}
+
+	/* The number of camera instance should be controlled by the
+		resource manager. Currently supporting one active instance
+		until multiple instances are supported */
+	if (atomic_read(&ps->number_pcam_active) > 0) {
+		pr_err("%s Cannot have more than one active camera %d\n",
+			__func__, atomic_read(&ps->number_pcam_active));
+		return -EINVAL;
+	}
+	/* book keeping this camera session*/
+	ps->pcam_active = pcam;
+	atomic_inc(&ps->number_pcam_active);
+
+	D("config pcam = 0x%p\n", ps->pcam_active);
+
+	/* initialization the media controller module*/
+	msm_mctl_init(pcam);
+
+	/*for single VFE msms (8660, 8960v1), just populate the session
+	with our VFE devices that registered*/
+	pmctl = msm_cam_server_get_mctl(pcam->mctl_handle);
+	pmctl->axi_sdev = ps->axi_device[0];
+	pmctl->isp_sdev = ps->isp_subdev[0];
+	return rc;
+}
+
+/* close an active camera session to server */
+static int msm_cam_server_close_session(struct msm_cam_server_dev *ps,
+	struct msm_cam_v4l2_device *pcam)
+{
+	int rc = 0;
+	D("%s\n", __func__);
+
+	if (!ps || !pcam) {
+		D("%s NULL pointer passed in!\n", __func__);
+		return rc;
+	}
+
+
+	atomic_dec(&ps->number_pcam_active);
+	ps->pcam_active = NULL;
+
+	msm_mctl_free(pcam);
+	return rc;
+}
+
+static long msm_ioctl_server(struct file *file, void *fh,
+		bool valid_prio, int cmd, void *arg)
+{
+	int rc = -EINVAL;
+	struct msm_camera_v4l2_ioctl_t *ioctl_ptr = arg;
+	struct msm_camera_info temp_cam_info;
+	struct msm_cam_config_dev_info temp_config_info;
+	struct msm_mctl_node_info temp_mctl_info;
+	int i;
+
+	D("%s: cmd %d\n", __func__, _IOC_NR(cmd));
+
+	switch (cmd) {
+	case MSM_CAM_V4L2_IOCTL_GET_CAMERA_INFO:
+		if (copy_from_user(&temp_cam_info,
+				(void __user *)ioctl_ptr->ioctl_ptr,
+				sizeof(struct msm_camera_info))) {
+			pr_err("%s Copy from user failed for cmd %d",
+				__func__, cmd);
+			rc = -EINVAL;
+			return rc;
+		}
+		for (i = 0; i < g_server_dev.camera_info.num_cameras; i++) {
+			if (copy_to_user((void __user *)
+			temp_cam_info.video_dev_name[i],
+			g_server_dev.camera_info.video_dev_name[i],
+			strnlen(g_server_dev.camera_info.video_dev_name[i],
+				MAX_DEV_NAME_LEN))) {
+				pr_err("%s Copy to user failed for cmd %d",
+					__func__, cmd);
+				rc = -EINVAL;
+				return rc;
+			}
+			temp_cam_info.has_3d_support[i] =
+				g_server_dev.camera_info.has_3d_support[i];
+			temp_cam_info.is_internal_cam[i] =
+				g_server_dev.camera_info.is_internal_cam[i];
+			temp_cam_info.s_mount_angle[i] =
+				g_server_dev.camera_info.s_mount_angle[i];
+			temp_cam_info.sensor_type[i] =
+				g_server_dev.camera_info.sensor_type[i];
+
+		}
+		temp_cam_info.num_cameras =
+			g_server_dev.camera_info.num_cameras;
+		if (copy_to_user((void __user *)ioctl_ptr->ioctl_ptr,
+			&temp_cam_info,	sizeof(struct msm_camera_info))) {
+			pr_err("%s Copy to user failed for cmd %d",
+				__func__, cmd);
+			rc = -EINVAL;
+			return rc;
+		}
+		rc = 0;
+		break;
+
+	case MSM_CAM_V4L2_IOCTL_GET_CONFIG_INFO:
+		if (copy_from_user(&temp_config_info,
+			(void __user *)ioctl_ptr->ioctl_ptr,
+			sizeof(struct msm_cam_config_dev_info))) {
+			pr_err("%s Copy from user failed for cmd %d",
+				__func__, cmd);
+			rc = -EINVAL;
+			return rc;
+		}
+		for (i = 0;
+		 i < g_server_dev.config_info.num_config_nodes; i++) {
+			if (copy_to_user(
+			(void __user *)temp_config_info.config_dev_name[i],
+			g_server_dev.config_info.config_dev_name[i],
+			strnlen(g_server_dev.config_info.config_dev_name[i],
+				MAX_DEV_NAME_LEN))) {
+				pr_err("%s Copy to user failed for cmd %d",
+					__func__, cmd);
+				rc = -EINVAL;
+				return rc;
+			}
+		}
+		temp_config_info.num_config_nodes =
+			g_server_dev.config_info.num_config_nodes;
+		if (copy_to_user((void __user *)ioctl_ptr->ioctl_ptr,
+			&temp_config_info,
+			sizeof(struct msm_cam_config_dev_info))) {
+			pr_err("%s Copy to user failed for cmd %d",
+				__func__, cmd);
+			rc = -EINVAL;
+			return rc;
+		}
+		rc = 0;
+		break;
+	case MSM_CAM_V4L2_IOCTL_GET_MCTL_INFO:
+		if (copy_from_user(&temp_mctl_info,
+				(void __user *)ioctl_ptr->ioctl_ptr,
+				sizeof(struct msm_mctl_node_info))) {
+			pr_err("%s Copy from user failed for cmd %d",
+				__func__, cmd);
+			rc = -EINVAL;
+			return rc;
+		}
+		for (i = 0; i < g_server_dev.mctl_node_info.num_mctl_nodes;
+				i++) {
+			if (copy_to_user((void __user *)
+			temp_mctl_info.mctl_node_name[i],
+			g_server_dev.mctl_node_info.mctl_node_name[i], strnlen(
+			g_server_dev.mctl_node_info.mctl_node_name[i],
+			MAX_DEV_NAME_LEN))) {
+				pr_err("%s Copy to user failed for cmd %d",
+					__func__, cmd);
+				rc = -EINVAL;
+				return rc;
+			}
+		}
+		temp_mctl_info.num_mctl_nodes =
+			g_server_dev.mctl_node_info.num_mctl_nodes;
+		if (copy_to_user((void __user *)ioctl_ptr->ioctl_ptr,
+			&temp_mctl_info, sizeof(struct msm_mctl_node_info))) {
+			pr_err("%s Copy to user failed for cmd %d",
+				__func__, cmd);
+			rc = -EINVAL;
+			return rc;
+		}
+		rc = 0;
+	break;
+
+	case MSM_CAM_V4L2_IOCTL_CTRL_CMD_DONE:
+		D("%s: MSM_CAM_IOCTL_CTRL_CMD_DONE\n", __func__);
+		rc = msm_ctrl_cmd_done(arg);
+		break;
+
+	case MSM_CAM_V4L2_IOCTL_GET_EVENT_PAYLOAD: {
+		struct msm_queue_cmd *event_cmd;
+		struct msm_isp_event_ctrl u_isp_event;
+		struct msm_isp_event_ctrl *k_isp_event;
+		struct msm_device_queue *queue;
+		void __user *u_ctrl_value = NULL;
+		if (copy_from_user(&u_isp_event,
+			(void __user *)ioctl_ptr->ioctl_ptr,
+			sizeof(struct msm_isp_event_ctrl))) {
+			pr_err("%s Copy from user failed for cmd %d",
+				__func__, cmd);
+			rc = -EINVAL;
+			return rc;
+		}
+
+		mutex_lock(&g_server_dev.server_queue_lock);
+		if (!g_server_dev.server_queue
+			[u_isp_event.isp_data.ctrl.queue_idx].queue_active) {
+			pr_err("%s: Invalid queue\n", __func__);
+			mutex_unlock(&g_server_dev.server_queue_lock);
+			rc = -EINVAL;
+			return rc;
+		}
+		queue = &g_server_dev.server_queue
+			[u_isp_event.isp_data.ctrl.queue_idx].eventData_q;
+		event_cmd = msm_dequeue(queue, list_eventdata);
+		if (!event_cmd) {
+			pr_err("%s: No event payload\n", __func__);
+			rc = -EINVAL;
+			mutex_unlock(&g_server_dev.server_queue_lock);
+			return rc;
+		}
+		k_isp_event = (struct msm_isp_event_ctrl *)
+				event_cmd->command;
+		free_qcmd(event_cmd);
+
+		/* Save the pointer of the user allocated command buffer*/
+		u_ctrl_value = u_isp_event.isp_data.ctrl.value;
+
+		/* Copy the event structure into user struct*/
+		u_isp_event = *k_isp_event;
+
+		/* Restore the saved pointer of the user
+		 * allocated command buffer. */
+		u_isp_event.isp_data.ctrl.value = u_ctrl_value;
+
+		/* Copy the ctrl cmd, if present*/
+		if (k_isp_event->isp_data.ctrl.length > 0 &&
+			k_isp_event->isp_data.ctrl.value != NULL) {
+			void *k_ctrl_value =
+				k_isp_event->isp_data.ctrl.value;
+			if (copy_to_user(u_ctrl_value, k_ctrl_value,
+				 k_isp_event->isp_data.ctrl.length)) {
+				pr_err("%s Copy to user failed for cmd %d",
+					__func__, cmd);
+				kfree(k_isp_event->isp_data.ctrl.value);
+				kfree(k_isp_event);
+				rc = -EINVAL;
+				mutex_unlock(&g_server_dev.server_queue_lock);
+				break;
+			}
+			kfree(k_isp_event->isp_data.ctrl.value);
+		}
+		if (copy_to_user((void __user *)ioctl_ptr->ioctl_ptr,
+			&u_isp_event, sizeof(struct msm_isp_event_ctrl))) {
+			pr_err("%s Copy to user failed for cmd %d",
+				__func__, cmd);
+			kfree(k_isp_event);
+			mutex_unlock(&g_server_dev.server_queue_lock);
+			rc = -EINVAL;
+			return rc;
+		}
+		kfree(k_isp_event);
+		mutex_unlock(&g_server_dev.server_queue_lock);
+		rc = 0;
+		break;
+	}
+
+	case MSM_CAM_IOCTL_SEND_EVENT:
+		rc = msm_server_send_v4l2_evt(arg);
+		break;
+
+	default:
+		pr_err("%s: Invalid IOCTL = %d", __func__, cmd);
+		break;
+	}
+	return rc;
+}
+
+static int msm_open_server(struct file *fp)
+{
+	int rc = 0;
+	D("%s: open %s\n", __func__, fp->f_path.dentry->d_name.name);
+	mutex_lock(&g_server_dev.server_lock);
+	g_server_dev.use_count++;
+	if (g_server_dev.use_count == 1)
+		fp->private_data =
+			&g_server_dev.server_command_queue.eventHandle;
+	mutex_unlock(&g_server_dev.server_lock);
+	return rc;
+}
+
+static int msm_close_server(struct file *fp)
+{
+	struct v4l2_event_subscription sub;
+	D("%s\n", __func__);
+	mutex_lock(&g_server_dev.server_lock);
+	if (g_server_dev.use_count > 0)
+		g_server_dev.use_count--;
+	mutex_unlock(&g_server_dev.server_lock);
+
+	if (g_server_dev.use_count == 0) {
+		mutex_lock(&g_server_dev.server_lock);
+		if (g_server_dev.pcam_active) {
+			struct v4l2_event v4l2_ev;
+			struct msm_cam_media_controller *pmctl = NULL;
+			int rc;
+
+			pmctl = msm_cam_server_get_mctl(
+				g_server_dev.pcam_active->mctl_handle);
+			if (pmctl && pmctl->mctl_release) {
+				rc = pmctl->mctl_release(pmctl);
+				if (rc < 0)
+					pr_err("mctl_release fails %d\n", rc);
+				/*so that it isn't closed again*/
+				pmctl->mctl_release = NULL;
+			}
+
+			v4l2_ev.type = V4L2_EVENT_PRIVATE_START
+				+ MSM_CAM_APP_NOTIFY_ERROR_EVENT;
+			ktime_get_ts(&v4l2_ev.timestamp);
+			v4l2_event_queue(
+				g_server_dev.pcam_active->pvdev, &v4l2_ev);
+		}
+		sub.type = V4L2_EVENT_ALL;
+		msm_server_v4l2_unsubscribe_event(
+			&g_server_dev.server_command_queue.eventHandle, &sub);
+		mutex_unlock(&g_server_dev.server_lock);
+	}
+	return 0;
+}
+
+static unsigned int msm_poll_server(struct file *fp,
+					struct poll_table_struct *wait)
+{
+	int rc = 0;
+
+	D("%s\n", __func__);
+	poll_wait(fp,
+		 &g_server_dev.server_command_queue.eventHandle.events->wait,
+		 wait);
+	if (v4l2_event_pending(&g_server_dev.server_command_queue.eventHandle))
+		rc |= POLLPRI;
+
+	return rc;
+}
+
+int msm_server_get_usecount(void)
+{
+	return g_server_dev.use_count;
+}
+
+int msm_server_update_sensor_info(struct msm_cam_v4l2_device *pcam,
+	struct msm_camera_sensor_info *sdata)
+{
+	int rc = 0;
+
+	if (!pcam || !sdata) {
+		pr_err("%s Input data is null ", __func__);
+		return -EINVAL;
+	}
+
+	g_server_dev.camera_info.video_dev_name
+	[g_server_dev.camera_info.num_cameras]
+	= video_device_node_name(pcam->pvdev);
+	D("%s Connected video device %s\n", __func__,
+		g_server_dev.camera_info.video_dev_name
+		[g_server_dev.camera_info.num_cameras]);
+
+	g_server_dev.camera_info.s_mount_angle
+	[g_server_dev.camera_info.num_cameras]
+	= sdata->sensor_platform_info->mount_angle;
+
+	g_server_dev.camera_info.is_internal_cam
+	[g_server_dev.camera_info.num_cameras]
+	= sdata->camera_type;
+
+	g_server_dev.mctl_node_info.mctl_node_name
+	[g_server_dev.mctl_node_info.num_mctl_nodes]
+	= video_device_node_name(pcam->mctl_node.pvdev);
+
+	pr_info("%s mctl_node_name[%d] = %s\n", __func__,
+		g_server_dev.mctl_node_info.num_mctl_nodes,
+		g_server_dev.mctl_node_info.mctl_node_name
+		[g_server_dev.mctl_node_info.num_mctl_nodes]);
+
+	/*Temporary solution to store info in media device structure
+	  until we can expand media device structure to support more
+	  device info*/
+	snprintf(pcam->media_dev.serial,
+			sizeof(pcam->media_dev.serial),
+			"%s-%d-%d", QCAMERA_NAME,
+			sdata->sensor_platform_info->mount_angle,
+			sdata->camera_type);
+
+	g_server_dev.camera_info.num_cameras++;
+	g_server_dev.mctl_node_info.num_mctl_nodes++;
+
+	D("%s done, rc = %d\n", __func__, rc);
+	D("%s number of sensors connected is %d\n", __func__,
+		g_server_dev.camera_info.num_cameras);
+
+	return rc;
+}
+
+int msm_server_begin_session(struct msm_cam_v4l2_device *pcam,
+	int server_q_idx)
+{
+	int rc = -EINVAL, ges_evt;
+	struct msm_cam_server_queue *queue;
+
+	if (!pcam) {
+		pr_err("%s pcam passed is null ", __func__);
+		return rc;
+	}
+
+	ges_evt = MSM_V4L2_GES_CAM_OPEN;
+	D("%s send gesture evt\n", __func__);
+	msm_cam_server_subdev_notify(g_server_dev.gesture_device,
+		NOTIFY_GESTURE_CAM_EVT, &ges_evt);
+
+	pcam->server_queue_idx = server_q_idx;
+	queue = &g_server_dev.server_queue[server_q_idx];
+	queue->ctrl_data = kzalloc(sizeof(uint8_t) *
+			max_control_command_size, GFP_KERNEL);
+	msm_queue_init(&queue->ctrl_q, "control");
+	msm_queue_init(&queue->eventData_q, "eventdata");
+	queue->queue_active = 1;
+
+	rc = msm_cam_server_open_session(&g_server_dev, pcam);
+	if (rc < 0) {
+		pr_err("%s: cam_server_open_session failed %d\n",
+			__func__, rc);
+		goto error;
+	}
+
+	return rc;
+error:
+	ges_evt = MSM_V4L2_GES_CAM_CLOSE;
+	msm_cam_server_subdev_notify(g_server_dev.gesture_device,
+		NOTIFY_GESTURE_CAM_EVT, &ges_evt);
+
+	queue->queue_active = 0;
+	msm_drain_eventq(&queue->eventData_q);
+	msm_queue_drain(&queue->ctrl_q, list_control);
+	kfree(queue->ctrl_data);
+	queue->ctrl_data = NULL;
+	queue = NULL;
+	return rc;
+}
+
+int msm_server_end_session(struct msm_cam_v4l2_device *pcam)
+{
+	int rc = -EINVAL, ges_evt;
+	struct msm_cam_server_queue *queue;
+
+	mutex_lock(&g_server_dev.server_queue_lock);
+	queue = &g_server_dev.server_queue[pcam->server_queue_idx];
+	queue->queue_active = 0;
+	kfree(queue->ctrl_data);
+	queue->ctrl_data = NULL;
+	msm_queue_drain(&queue->ctrl_q, list_control);
+	msm_drain_eventq(&queue->eventData_q);
+	mutex_unlock(&g_server_dev.server_queue_lock);
+
+	rc = msm_cam_server_close_session(&g_server_dev, pcam);
+	if (rc < 0)
+		pr_err("msm_cam_server_close_session fails %d\n", rc);
+
+	ges_evt = MSM_V4L2_GES_CAM_CLOSE;
+	msm_cam_server_subdev_notify(g_server_dev.gesture_device,
+			NOTIFY_GESTURE_CAM_EVT, &ges_evt);
+
+	return rc;
+}
+
+/* Init a config node for ISP control,
+ * which will create a config device (/dev/config0/ and plug in
+ * ISP's operation "v4l2_ioctl_ops*"
+ */
+static const struct v4l2_file_operations msm_fops_server = {
+	.owner = THIS_MODULE,
+	.open  = msm_open_server,
+	.poll  = msm_poll_server,
+	.unlocked_ioctl = video_ioctl2,
+	.release = msm_close_server,
+};
+
+static const struct v4l2_ioctl_ops msm_ioctl_ops_server = {
+	.vidioc_subscribe_event = msm_server_v4l2_subscribe_event,
+	.vidioc_default = msm_ioctl_server,
+};
+
+static void msm_cam_server_subdev_notify(struct v4l2_subdev *sd,
+				unsigned int notification, void *arg)
+{
+	int rc = -EINVAL;
+	struct msm_sensor_ctrl_t *s_ctrl;
+	struct msm_camera_sensor_info *sinfo;
+	struct msm_camera_device_platform_data *camdev;
+	uint8_t csid_core = 0;
+
+	if (notification == NOTIFY_CID_CHANGE ||
+		notification == NOTIFY_ISPIF_STREAM ||
+		notification == NOTIFY_PCLK_CHANGE ||
+		notification == NOTIFY_CSIPHY_CFG ||
+		notification == NOTIFY_CSID_CFG ||
+		notification == NOTIFY_CSIC_CFG) {
+		s_ctrl = get_sctrl(sd);
+		sinfo = (struct msm_camera_sensor_info *) s_ctrl->sensordata;
+		camdev = sinfo->pdata;
+		csid_core = camdev->csid_core;
+	}
+
+	switch (notification) {
+	case NOTIFY_CID_CHANGE:
+		/* reconfig the ISPIF*/
+		if (g_server_dev.ispif_device) {
+			struct msm_ispif_params_list ispif_params;
+			ispif_params.len = 1;
+			ispif_params.params[0].intftype = PIX0;
+			ispif_params.params[0].cid_mask = 0x0001;
+			ispif_params.params[0].csid = csid_core;
+
+			rc = v4l2_subdev_call(
+				g_server_dev.ispif_device, core, ioctl,
+				VIDIOC_MSM_ISPIF_CFG, &ispif_params);
+			if (rc < 0)
+				return;
+		}
+		break;
+	case NOTIFY_ISPIF_STREAM:
+		/* call ISPIF stream on/off */
+		rc = v4l2_subdev_call(g_server_dev.ispif_device, video,
+				s_stream, (int)arg);
+		if (rc < 0)
+			return;
+
+		break;
+	case NOTIFY_ISP_MSG_EVT:
+	case NOTIFY_VFE_MSG_OUT:
+	case NOTIFY_VFE_MSG_STATS:
+	case NOTIFY_VFE_MSG_COMP_STATS:
+	case NOTIFY_VFE_BUF_EVT:
+	case NOTIFY_VFE_BUF_FREE_EVT:
+		if (g_server_dev.isp_subdev[0] &&
+			g_server_dev.isp_subdev[0]->isp_notify) {
+			rc = g_server_dev.isp_subdev[0]->isp_notify(
+				g_server_dev.vfe_device[0], notification, arg);
+		}
+		break;
+	case NOTIFY_VPE_MSG_EVT: {
+		struct msm_cam_media_controller *pmctl =
+		(struct msm_cam_media_controller *)
+		v4l2_get_subdev_hostdata(sd);
+		struct msm_vpe_resp *vdata = (struct msm_vpe_resp *)arg;
+		msm_mctl_pp_notify(pmctl,
+		(struct msm_mctl_pp_frame_info *)
+		vdata->extdata);
+		break;
+	}
+	case NOTIFY_VFE_IRQ:{
+		struct msm_vfe_cfg_cmd cfg_cmd;
+		struct msm_camvfe_params vfe_params;
+		cfg_cmd.cmd_type = CMD_VFE_PROCESS_IRQ;
+		vfe_params.vfe_cfg = &cfg_cmd;
+		vfe_params.data = arg;
+		rc = v4l2_subdev_call(g_server_dev.vfe_device[0],
+			core, ioctl, 0, &vfe_params);
+	}
+		break;
+	case NOTIFY_AXI_IRQ:
+		rc = v4l2_subdev_call(g_server_dev.axi_device[0],
+			core, ioctl, VIDIOC_MSM_AXI_IRQ, arg);
+		break;
+	case NOTIFY_PCLK_CHANGE:
+		if (g_server_dev.axi_device[0])
+			rc = v4l2_subdev_call(g_server_dev.axi_device[0], video,
+			s_crystal_freq, *(uint32_t *)arg, 0);
+		else
+			rc = v4l2_subdev_call(g_server_dev.vfe_device[0], video,
+			s_crystal_freq, *(uint32_t *)arg, 0);
+		break;
+	case NOTIFY_CSIPHY_CFG:
+		rc = v4l2_subdev_call(g_server_dev.csiphy_device[csid_core],
+			core, ioctl, VIDIOC_MSM_CSIPHY_CFG, arg);
+		break;
+	case NOTIFY_CSID_CFG:
+		rc = v4l2_subdev_call(g_server_dev.csid_device[csid_core],
+			core, ioctl, VIDIOC_MSM_CSID_CFG, arg);
+		break;
+	case NOTIFY_CSIC_CFG:
+		rc = v4l2_subdev_call(g_server_dev.csic_device[csid_core],
+			core, ioctl, VIDIOC_MSM_CSIC_CFG, arg);
+		break;
+	case NOTIFY_GESTURE_EVT:
+		rc = v4l2_subdev_call(g_server_dev.gesture_device,
+			core, ioctl, VIDIOC_MSM_GESTURE_EVT, arg);
+		break;
+	case NOTIFY_GESTURE_CAM_EVT:
+		rc = v4l2_subdev_call(g_server_dev.gesture_device,
+			core, ioctl, VIDIOC_MSM_GESTURE_CAM_EVT, arg);
+		break;
+	default:
+		break;
+	}
+
+	return;
+}
+
+int msm_cam_register_subdev_node(struct v4l2_subdev *sd,
+	enum msm_cam_subdev_type sdev_type, uint8_t index)
+{
+	struct video_device *vdev;
+	int err = 0;
+
+	switch (sdev_type) {
+	case CSIPHY_DEV:
+		if (index >= MAX_NUM_CSIPHY_DEV) {
+			pr_err("%s Invalid CSIPHY idx %d", __func__, index);
+			err = -EINVAL;
+			break;
+		}
+		g_server_dev.csiphy_device[index] = sd;
+		break;
+
+	case CSID_DEV:
+		if (index >= MAX_NUM_CSID_DEV) {
+			pr_err("%s Invalid CSID idx %d", __func__, index);
+			err = -EINVAL;
+			break;
+		}
+		g_server_dev.csid_device[index] = sd;
+		break;
+
+	case CSIC_DEV:
+		if (index >= MAX_NUM_CSIC_DEV) {
+			pr_err("%s Invalid CSIC idx %d", __func__, index);
+			err = -EINVAL;
+			break;
+		}
+		g_server_dev.csic_device[index] = sd;
+		break;
+
+	case ISPIF_DEV:
+		g_server_dev.ispif_device = sd;
+		break;
+
+	case VFE_DEV:
+		if (index >= MAX_NUM_VFE_DEV) {
+			pr_err("%s Invalid VFE idx %d", __func__, index);
+			err = -EINVAL;
+			break;
+		}
+		g_server_dev.vfe_device[index] = sd;
+		break;
+
+	case VPE_DEV:
+		if (index >= MAX_NUM_VPE_DEV) {
+			pr_err("%s Invalid VPE idx %d", __func__, index);
+			err = -EINVAL;
+			break;
+		}
+		g_server_dev.vpe_device[index] = sd;
+		break;
+
+	case AXI_DEV:
+		if (index >= MAX_NUM_VPE_DEV) {
+			pr_err("%s Invalid AXI idx %d", __func__, index);
+			err = -EINVAL;
+			break;
+		}
+		g_server_dev.axi_device[index] = sd;
+		break;
+
+	case GESTURE_DEV:
+		g_server_dev.gesture_device = sd;
+		break;
+	default:
+		break;
+	}
+
+	if (err < 0)
+		return err;
+
+	err = v4l2_device_register_subdev(&g_server_dev.v4l2_dev, sd);
+	if (err < 0) {
+		pr_err("%s v4l2 subdev register failed for %d ret = %d",
+			__func__, sdev_type, err);
+		return err;
+	}
+
+	/* Register a device node for every subdev marked with the
+	 * V4L2_SUBDEV_FL_HAS_DEVNODE flag.
+	 */
+	if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE))
+		return err;
+
+	vdev = &sd->devnode;
+	strlcpy(vdev->name, sd->name, sizeof(vdev->name));
+	vdev->v4l2_dev = &g_server_dev.v4l2_dev;
+	vdev->fops = &v4l2_subdev_fops;
+	vdev->release = video_device_release_empty;
+	err = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1,
+						  sd->owner);
+	if (err < 0)
+		return err;
+#if defined(CONFIG_MEDIA_CONTROLLER)
+	sd->entity.v4l.major = VIDEO_MAJOR;
+	sd->entity.v4l.minor = vdev->minor;
+#endif
+	return 0;
+}
+
+static int msm_setup_server_dev(struct platform_device *pdev)
+{
+	int rc = -ENODEV, i;
+
+	D("%s\n", __func__);
+	g_server_dev.server_pdev = pdev;
+	g_server_dev.v4l2_dev.dev = &pdev->dev;
+	g_server_dev.v4l2_dev.notify = msm_cam_server_subdev_notify;
+	rc = v4l2_device_register(g_server_dev.v4l2_dev.dev,
+			&g_server_dev.v4l2_dev);
+	if (rc < 0)
+		return -EINVAL;
+
+	g_server_dev.video_dev = video_device_alloc();
+	if (g_server_dev.video_dev == NULL) {
+		pr_err("%s: video_device_alloc failed\n", __func__);
+		return rc;
+	}
+
+	strlcpy(g_server_dev.video_dev->name, pdev->name,
+			sizeof(g_server_dev.video_dev->name));
+
+	g_server_dev.video_dev->v4l2_dev = &g_server_dev.v4l2_dev;
+	g_server_dev.video_dev->fops = &msm_fops_server;
+	g_server_dev.video_dev->ioctl_ops = &msm_ioctl_ops_server;
+	g_server_dev.video_dev->release   = video_device_release;
+	g_server_dev.video_dev->minor = 100;
+	g_server_dev.video_dev->vfl_type = 1;
+
+	video_set_drvdata(g_server_dev.video_dev, &g_server_dev);
+
+	strlcpy(g_server_dev.media_dev.model, "qcamera",
+		sizeof(g_server_dev.media_dev.model));
+	g_server_dev.media_dev.dev = &pdev->dev;
+	rc = media_device_register(&g_server_dev.media_dev);
+	g_server_dev.v4l2_dev.mdev = &g_server_dev.media_dev;
+
+	rc = video_register_device(g_server_dev.video_dev,
+		VFL_TYPE_GRABBER, 100);
+
+	mutex_init(&g_server_dev.server_lock);
+	mutex_init(&g_server_dev.server_queue_lock);
+	g_server_dev.pcam_active = NULL;
+	g_server_dev.camera_info.num_cameras = 0;
+	atomic_set(&g_server_dev.number_pcam_active, 0);
+	g_server_dev.server_evt_id = 0;
+
+	/*initialize fake video device and event queue*/
+
+	g_server_dev.server_command_queue.pvdev = g_server_dev.video_dev;
+	rc = msm_setup_v4l2_event_queue(
+		&g_server_dev.server_command_queue.eventHandle,
+		g_server_dev.server_command_queue.pvdev);
+
+	if (rc < 0) {
+		pr_err("%s failed to initialize event queue\n", __func__);
+		video_device_release(g_server_dev.server_command_queue.pvdev);
+		return rc;
+	}
+
+	for (i = 0; i < MAX_NUM_ACTIVE_CAMERA; i++) {
+		struct msm_cam_server_queue *queue;
+		queue = &g_server_dev.server_queue[i];
+		queue->queue_active = 0;
+		msm_queue_init(&queue->ctrl_q, "control");
+		msm_queue_init(&queue->eventData_q, "eventdata");
+	}
+	return rc;
+}
+
+static long msm_server_send_v4l2_evt(void *evt)
+{
+	struct v4l2_event *v4l2_ev = (struct v4l2_event *)evt;
+	int rc = 0;
+
+	if (NULL == evt) {
+		pr_err("%s: evt is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	D("%s: evt type 0x%x\n", __func__, v4l2_ev->type);
+	if ((v4l2_ev->type >= MSM_GES_APP_EVT_MIN) &&
+		(v4l2_ev->type < MSM_GES_APP_EVT_MAX)) {
+		msm_cam_server_subdev_notify(g_server_dev.gesture_device,
+			NOTIFY_GESTURE_EVT, v4l2_ev);
+	} else {
+		pr_err("%s: Invalid evt %d\n", __func__, v4l2_ev->type);
+		rc = -EINVAL;
+	}
+	D("%s: end\n", __func__);
+
+	return rc;
+}
+
+int msm_cam_server_open_mctl_session(struct msm_cam_v4l2_device *pcam,
+	int *p_active)
+{
+	int rc = 0;
+	struct msm_cam_media_controller *pmctl = NULL;
+	D("%s: %p", __func__, g_server_dev.pcam_active);
+	*p_active = 0;
+	if (g_server_dev.pcam_active) {
+		D("%s: Active camera present return", __func__);
+		return 0;
+	}
+	rc = msm_cam_server_open_session(&g_server_dev, pcam);
+	if (rc < 0) {
+		pr_err("%s: cam_server_open_session failed %d\n",
+		__func__, rc);
+		return rc;
+	}
+
+	pmctl = msm_cam_server_get_mctl(pcam->mctl_handle);
+	if (!pmctl->mctl_open) {
+		D("%s: media contoller is not inited\n",
+			 __func__);
+		rc = -ENODEV;
+		return rc;
+	}
+
+	D("%s: call mctl_open\n", __func__);
+	rc = pmctl->mctl_open(pmctl, MSM_APPS_ID_V4L2);
+
+	if (rc < 0) {
+		pr_err("%s: HW open failed rc = 0x%x\n",  __func__, rc);
+		return rc;
+	}
+	pmctl->pcam_ptr = pcam;
+	*p_active = 1;
+	return rc;
+}
+
+int msm_cam_server_close_mctl_session(struct msm_cam_v4l2_device *pcam)
+{
+	int rc = 0;
+	struct msm_cam_media_controller *pmctl = NULL;
+
+	pmctl = msm_cam_server_get_mctl(pcam->mctl_handle);
+	if (!pmctl) {
+		D("%s: invalid handle\n", __func__);
+		return -ENODEV;
+	}
+
+	if (pmctl->mctl_release) {
+		rc = pmctl->mctl_release(pmctl);
+		if (rc < 0)
+			pr_err("mctl_release fails %d\n", rc);
+	}
+
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+	kref_put(&pmctl->refcount, msm_release_ion_client);
+#endif
+
+	rc = msm_cam_server_close_session(&g_server_dev, pcam);
+	if (rc < 0)
+		pr_err("msm_cam_server_close_session fails %d\n", rc);
+
+	return rc;
+}
+
+int msm_server_open_client(int *p_qidx)
+{
+	int rc = 0;
+	int server_q_idx = 0;
+	struct msm_cam_server_queue *queue = NULL;
+
+	mutex_lock(&g_server_dev.server_lock);
+	server_q_idx = msm_find_free_queue();
+	if (server_q_idx < 0) {
+		mutex_unlock(&g_server_dev.server_lock);
+		return server_q_idx;
+	}
+
+	*p_qidx = server_q_idx;
+	queue = &g_server_dev.server_queue[server_q_idx];
+	queue->ctrl_data = kzalloc(sizeof(uint8_t) *
+		max_control_command_size, GFP_KERNEL);
+	msm_queue_init(&queue->ctrl_q, "control");
+	msm_queue_init(&queue->eventData_q, "eventdata");
+	queue->queue_active = 1;
+	mutex_unlock(&g_server_dev.server_lock);
+	return rc;
+}
+
+int msm_server_send_ctrl(struct msm_ctrl_cmd *out,
+	int ctrl_id)
+{
+	int rc = 0;
+	void *value;
+	struct msm_queue_cmd *rcmd;
+	struct msm_queue_cmd *event_qcmd;
+	struct msm_ctrl_cmd *ctrlcmd;
+	struct msm_cam_server_dev *server_dev = &g_server_dev;
+	struct msm_device_queue *queue =
+		&server_dev->server_queue[out->queue_idx].ctrl_q;
+
+	struct v4l2_event v4l2_evt;
+	struct msm_isp_event_ctrl *isp_event;
+	isp_event = kzalloc(sizeof(struct msm_isp_event_ctrl), GFP_KERNEL);
+	if (!isp_event) {
+		pr_err("%s Insufficient memory. return", __func__);
+		return -ENOMEM;
+	}
+	event_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_KERNEL);
+	if (!event_qcmd) {
+		pr_err("%s Insufficient memory. return", __func__);
+		kfree(isp_event);
+		return -ENOMEM;
+	}
+
+	D("%s\n", __func__);
+	mutex_lock(&server_dev->server_queue_lock);
+	if (++server_dev->server_evt_id == 0)
+		server_dev->server_evt_id++;
+
+	D("%s qid %d evtid %d\n", __func__, out->queue_idx,
+		server_dev->server_evt_id);
+	server_dev->server_queue[out->queue_idx].evt_id =
+		server_dev->server_evt_id;
+	v4l2_evt.type = V4L2_EVENT_PRIVATE_START + ctrl_id;
+	v4l2_evt.u.data[0] = out->queue_idx;
+	/* setup event object to transfer the command; */
+	isp_event->resptype = MSM_CAM_RESP_V4L2;
+	isp_event->isp_data.ctrl = *out;
+	isp_event->isp_data.ctrl.evt_id = server_dev->server_evt_id;
+
+	atomic_set(&event_qcmd->on_heap, 1);
+	event_qcmd->command = isp_event;
+
+	msm_enqueue(&server_dev->server_queue[out->queue_idx].eventData_q,
+				&event_qcmd->list_eventdata);
+
+	/* now send command to config thread in userspace,
+	 * and wait for results */
+	v4l2_event_queue(server_dev->server_command_queue.pvdev,
+					  &v4l2_evt);
+	D("%s v4l2_event_queue: type = 0x%x\n", __func__, v4l2_evt.type);
+	mutex_unlock(&server_dev->server_queue_lock);
+
+	/* wait for config return status */
+	D("Waiting for config status\n");
+	rc = wait_event_interruptible_timeout(queue->wait,
+		!list_empty_careful(&queue->list),
+		msecs_to_jiffies(out->timeout_ms));
+	D("Waiting is over for config status\n");
+	if (list_empty_careful(&queue->list)) {
+		if (!rc)
+			rc = -ETIMEDOUT;
+		if (rc < 0) {
+			kfree(isp_event);
+			pr_err("%s: wait_event error %d\n", __func__, rc);
+			return rc;
+		}
+	}
+
+	rcmd = msm_dequeue(queue, list_control);
+	BUG_ON(!rcmd);
+	D("%s Finished servicing ioctl\n", __func__);
+
+	ctrlcmd = (struct msm_ctrl_cmd *)(rcmd->command);
+	value = out->value;
+	if (ctrlcmd->length > 0 && value != NULL &&
+		ctrlcmd->length <= out->length)
+		memcpy(value, ctrlcmd->value, ctrlcmd->length);
+
+	memcpy(out, ctrlcmd, sizeof(struct msm_ctrl_cmd));
+	out->value = value;
+
+	kfree(ctrlcmd);
+	free_qcmd(rcmd);
+	kfree(isp_event);
+	D("%s: rc %d\n", __func__, rc);
+	/* rc is the time elapsed. */
+	if (rc >= 0) {
+		/* TODO: Refactor msm_ctrl_cmd::status field */
+		if (out->status == 0)
+			rc = -1;
+		else if (out->status == 1 || out->status == 4)
+			rc = 0;
+		else
+			rc = -EINVAL;
+	}
+	return rc;
+}
+
+int msm_server_close_client(int idx)
+{
+	int rc = 0;
+	struct msm_cam_server_queue *queue = NULL;
+	mutex_lock(&g_server_dev.server_lock);
+	queue = &g_server_dev.server_queue[idx];
+	queue->queue_active = 0;
+	kfree(queue->ctrl_data);
+	queue->ctrl_data = NULL;
+	msm_queue_drain(&queue->ctrl_q, list_control);
+	msm_drain_eventq(&queue->eventData_q);
+	mutex_unlock(&g_server_dev.server_lock);
+	return rc;
+}
+
+static unsigned int msm_poll_config(struct file *fp,
+					struct poll_table_struct *wait)
+{
+	int rc = 0;
+	struct msm_cam_config_dev *config = fp->private_data;
+	if (config == NULL)
+		return -EINVAL;
+
+	D("%s\n", __func__);
+
+	poll_wait(fp,
+	&config->config_stat_event_queue.eventHandle.events->wait, wait);
+	if (v4l2_event_pending(&config->config_stat_event_queue.eventHandle))
+		rc |= POLLPRI;
+	return rc;
+}
+
+static int msm_mmap_config(struct file *fp, struct vm_area_struct *vma)
+{
+	struct msm_cam_config_dev *config_cam = fp->private_data;
+	int rc = 0;
+	int phyaddr;
+	int retval;
+	unsigned long size;
+
+	D("%s: phy_addr=0x%x", __func__, config_cam->mem_map.cookie);
+	phyaddr = (int)config_cam->mem_map.cookie;
+	if (!phyaddr) {
+		pr_err("%s: no physical memory to map", __func__);
+		return -EFAULT;
+	}
+	memset(&config_cam->mem_map, 0,
+		sizeof(struct msm_mem_map_info));
+	size = vma->vm_end - vma->vm_start;
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+	retval = remap_pfn_range(vma, vma->vm_start,
+					phyaddr >> PAGE_SHIFT,
+					size, vma->vm_page_prot);
+	if (retval) {
+		pr_err("%s: remap failed, rc = %d",
+					__func__, retval);
+		rc = -ENOMEM;
+		goto end;
+	}
+	D("%s: phy_addr=0x%x: %08lx-%08lx, pgoff %08lx\n",
+			__func__, (uint32_t)phyaddr,
+			vma->vm_start, vma->vm_end, vma->vm_pgoff);
+end:
+	return rc;
+}
+
+static int msm_open_config(struct inode *inode, struct file *fp)
+{
+	int rc;
+	struct msm_cam_config_dev *config_cam = container_of(inode->i_cdev,
+		struct msm_cam_config_dev, config_cdev);
+
+	D("%s: open %s\n", __func__, fp->f_path.dentry->d_name.name);
+
+	rc = nonseekable_open(inode, fp);
+	if (rc < 0) {
+		pr_err("%s: nonseekable_open error %d\n", __func__, rc);
+		return rc;
+	}
+	config_cam->use_count++;
+
+	/* assume there is only one active camera possible*/
+	config_cam->p_mctl =
+		msm_cam_server_get_mctl(g_server_dev.pcam_active->mctl_handle);
+
+	INIT_HLIST_HEAD(&config_cam->p_mctl->stats_info.pmem_stats_list);
+	spin_lock_init(&config_cam->p_mctl->stats_info.pmem_stats_spinlock);
+
+	config_cam->p_mctl->config_device = config_cam;
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+	kref_get(&config_cam->p_mctl->refcount);
+#endif
+	fp->private_data = config_cam;
+	return rc;
+}
+
+static long msm_ioctl_config(struct file *fp, unsigned int cmd,
+	unsigned long arg)
+{
+
+	int rc = 0;
+	struct v4l2_event ev;
+	struct msm_cam_config_dev *config_cam = fp->private_data;
+	struct v4l2_event_subscription temp_sub;
+
+	D("%s: cmd %d\n", __func__, _IOC_NR(cmd));
+
+	switch (cmd) {
+	/* memory management shall be handeld here*/
+	case MSM_CAM_IOCTL_REGISTER_PMEM:
+		return msm_register_pmem(
+			&config_cam->p_mctl->stats_info.pmem_stats_list,
+			(void __user *)arg, config_cam->p_mctl->client);
+		break;
+
+	case MSM_CAM_IOCTL_UNREGISTER_PMEM:
+		return msm_pmem_table_del(
+			&config_cam->p_mctl->stats_info.pmem_stats_list,
+			(void __user *)arg, config_cam->p_mctl->client);
+		break;
+
+	case VIDIOC_SUBSCRIBE_EVENT:
+		if (copy_from_user(&temp_sub,
+			(void __user *)arg,
+			sizeof(struct v4l2_event_subscription))) {
+				pr_err("%s copy_from_user failed for cmd %d ",
+					__func__, cmd);
+				rc = -EINVAL;
+				return rc;
+		}
+		rc = msm_server_v4l2_subscribe_event
+			(&config_cam->config_stat_event_queue.eventHandle,
+				 &temp_sub);
+		if (rc < 0) {
+			pr_err("%s: cam_v4l2_subscribe_event failed rc=%d\n",
+				__func__, rc);
+			return rc;
+		}
+		break;
+
+	case VIDIOC_UNSUBSCRIBE_EVENT:
+		if (copy_from_user(&temp_sub, (void __user *)arg,
+			  sizeof(struct v4l2_event_subscription))) {
+			rc = -EINVAL;
+			return rc;
+		}
+		rc = msm_server_v4l2_unsubscribe_event
+			(&config_cam->config_stat_event_queue.eventHandle,
+			 &temp_sub);
+		if (rc < 0) {
+			pr_err("%s: cam_v4l2_unsubscribe_event failed rc=%d\n",
+				__func__, rc);
+			return rc;
+		}
+		break;
+
+	case VIDIOC_DQEVENT: {
+		void __user *u_msg_value = NULL, *user_ptr = NULL;
+		struct msm_isp_event_ctrl u_isp_event;
+		struct msm_isp_event_ctrl *k_isp_event;
+
+		/* First, copy the v4l2 event structure from userspace */
+		D("%s: VIDIOC_DQEVENT\n", __func__);
+		if (copy_from_user(&ev, (void __user *)arg,
+				sizeof(struct v4l2_event)))
+			break;
+		/* Next, get the pointer to event_ctrl structure
+		 * embedded inside the v4l2_event.u.data array. */
+		user_ptr = (void __user *)(*((uint32_t *)ev.u.data));
+
+		/* Next, copy the userspace event ctrl structure */
+		if (copy_from_user((void *)&u_isp_event, user_ptr,
+				   sizeof(struct msm_isp_event_ctrl))) {
+			break;
+		}
+		/* Save the pointer of the user allocated command buffer*/
+		u_msg_value = u_isp_event.isp_data.isp_msg.data;
+
+		/* Dequeue the event queued into the v4l2 queue*/
+		rc = v4l2_event_dequeue(
+			&config_cam->config_stat_event_queue.eventHandle,
+			&ev, fp->f_flags & O_NONBLOCK);
+		if (rc < 0) {
+			pr_err("no pending events?");
+			break;
+		}
+		/* Use k_isp_event to point to the event_ctrl structure
+		 * embedded inside v4l2_event.u.data */
+		k_isp_event = (struct msm_isp_event_ctrl *)
+				(*((uint32_t *)ev.u.data));
+		/* Copy the event structure into user struct. */
+		u_isp_event = *k_isp_event;
+		if (ev.type != (V4L2_EVENT_PRIVATE_START +
+				MSM_CAM_RESP_DIV_FRAME_EVT_MSG) &&
+				ev.type != (V4L2_EVENT_PRIVATE_START +
+				MSM_CAM_RESP_MCTL_PP_EVENT)) {
+
+			/* Restore the saved pointer of the
+			 * user allocated command buffer. */
+			u_isp_event.isp_data.isp_msg.data = u_msg_value;
+
+			if (ev.type == (V4L2_EVENT_PRIVATE_START +
+					MSM_CAM_RESP_STAT_EVT_MSG)) {
+				if (k_isp_event->isp_data.isp_msg.len > 0) {
+					void *k_msg_value =
+					k_isp_event->isp_data.isp_msg.data;
+					if (copy_to_user(u_msg_value,
+							k_msg_value,
+					 k_isp_event->isp_data.isp_msg.len)) {
+						rc = -EINVAL;
+						break;
+					}
+					kfree(k_msg_value);
+				}
+			}
+		}
+		/* Copy the event ctrl structure back
+		 * into user's structure. */
+		if (copy_to_user(user_ptr,
+				(void *)&u_isp_event, sizeof(
+				struct msm_isp_event_ctrl))) {
+			rc = -EINVAL;
+			break;
+		}
+		kfree(k_isp_event);
+
+		/* Copy the v4l2_event structure back to the user*/
+		if (copy_to_user((void __user *)arg, &ev,
+				sizeof(struct v4l2_event))) {
+			rc = -EINVAL;
+			break;
+		}
+		}
+
+		break;
+
+	case MSM_CAM_IOCTL_V4L2_EVT_NOTIFY:
+		rc = msm_v4l2_evt_notify(config_cam->p_mctl, cmd, arg);
+		break;
+
+	case MSM_CAM_IOCTL_SET_MEM_MAP_INFO:
+		if (copy_from_user(&config_cam->mem_map, (void __user *)arg,
+				sizeof(struct msm_mem_map_info)))
+			rc = -EINVAL;
+		break;
+
+	default:{
+		/* For the rest of config command, forward to media controller*/
+		struct msm_cam_media_controller *p_mctl = config_cam->p_mctl;
+		if (p_mctl && p_mctl->mctl_cmd) {
+			rc = config_cam->p_mctl->mctl_cmd(p_mctl, cmd, arg);
+		} else {
+			rc = -EINVAL;
+			pr_err("%s: media controller is null\n", __func__);
+		}
+
+		break;
+	} /* end of default*/
+	} /* end of switch*/
+	return rc;
+}
+
+static int msm_close_config(struct inode *node, struct file *f)
+{
+	struct v4l2_event ev;
+	struct v4l2_event_subscription sub;
+	struct msm_isp_event_ctrl *isp_event;
+	struct msm_cam_config_dev *config_cam = f->private_data;
+
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+	D("%s Decrementing ref count of config node ", __func__);
+	kref_put(&config_cam->p_mctl->refcount, msm_release_ion_client);
+#endif
+	sub.type = V4L2_EVENT_ALL;
+	msm_server_v4l2_unsubscribe_event(
+		&config_cam->config_stat_event_queue.eventHandle,
+		&sub);
+	while (v4l2_event_pending(
+		&config_cam->config_stat_event_queue.eventHandle)) {
+		v4l2_event_dequeue(
+			&config_cam->config_stat_event_queue.eventHandle,
+			&ev, O_NONBLOCK);
+		isp_event = (struct msm_isp_event_ctrl *)
+			(*((uint32_t *)ev.u.data));
+		if (isp_event) {
+			if (isp_event->isp_data.isp_msg.len != 0 &&
+				isp_event->isp_data.isp_msg.data != NULL)
+				kfree(isp_event->isp_data.isp_msg.data);
+			kfree(isp_event);
+		}
+	}
+	return 0;
+}
+
+static const struct file_operations msm_fops_config = {
+	.owner = THIS_MODULE,
+	.open  = msm_open_config,
+	.poll  = msm_poll_config,
+	.unlocked_ioctl = msm_ioctl_config,
+	.mmap	= msm_mmap_config,
+	.release = msm_close_config,
+};
+
+static int msm_setup_config_dev(int node, char *device_name)
+{
+	int rc = -ENODEV;
+	struct device *device_config;
+	int dev_num = node;
+	dev_t devno;
+	struct msm_cam_config_dev *config_cam;
+
+	config_cam = kzalloc(sizeof(*config_cam), GFP_KERNEL);
+	if (!config_cam) {
+		pr_err("%s: could not allocate memory for config_device\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	D("%s\n", __func__);
+
+	devno = MKDEV(MAJOR(msm_devno), dev_num+1);
+	device_config = device_create(msm_class, NULL, devno, NULL, "%s%d",
+		device_name, dev_num);
+
+	if (IS_ERR(device_config)) {
+		rc = PTR_ERR(device_config);
+		pr_err("%s: error creating device: %d\n", __func__, rc);
+		goto config_setup_fail;
+	}
+
+	cdev_init(&config_cam->config_cdev, &msm_fops_config);
+	config_cam->config_cdev.owner = THIS_MODULE;
+
+	rc = cdev_add(&config_cam->config_cdev, devno, 1);
+	if (rc < 0) {
+		pr_err("%s: error adding cdev: %d\n", __func__, rc);
+		device_destroy(msm_class, devno);
+		goto config_setup_fail;
+	}
+	g_server_dev.config_info.config_dev_name[dev_num] =
+		dev_name(device_config);
+	D("%s Connected config device %s\n", __func__,
+		g_server_dev.config_info.config_dev_name[dev_num]);
+	g_server_dev.config_info.config_dev_id[dev_num] =
+		dev_num;
+
+	config_cam->config_stat_event_queue.pvdev = video_device_alloc();
+	if (config_cam->config_stat_event_queue.pvdev == NULL) {
+		pr_err("%s: video_device_alloc failed\n", __func__);
+		goto config_setup_fail;
+	}
+
+	rc = msm_setup_v4l2_event_queue(
+		&config_cam->config_stat_event_queue.eventHandle,
+		config_cam->config_stat_event_queue.pvdev);
+	if (rc < 0) {
+		pr_err("%s failed to initialize event queue\n", __func__);
+		video_device_release(config_cam->config_stat_event_queue.pvdev);
+		goto config_setup_fail;
+	}
+
+	return rc;
+
+config_setup_fail:
+	kfree(config_cam);
+	return rc;
+}
+
+static int __devinit msm_camera_probe(struct platform_device *pdev)
+{
+	int rc = 0, i;
+	/*for now just create a config 0 node
+	  put logic here later to know how many configs to create*/
+	g_server_dev.config_info.num_config_nodes = 1;
+
+	rc = msm_isp_init_module(g_server_dev.config_info.num_config_nodes);
+	if (rc < 0) {
+		pr_err("Failed to initialize isp\n");
+		return rc;
+	}
+
+	if (!msm_class) {
+		rc = alloc_chrdev_region(&msm_devno, 0,
+		g_server_dev.config_info.num_config_nodes+1, "msm_camera");
+		if (rc < 0) {
+			pr_err("%s: failed to allocate chrdev: %d\n", __func__,
+			rc);
+			return rc;
+		}
+
+		msm_class = class_create(THIS_MODULE, "msm_camera");
+		if (IS_ERR(msm_class)) {
+			rc = PTR_ERR(msm_class);
+			pr_err("%s: create device class failed: %d\n",
+			__func__, rc);
+			return rc;
+		}
+	}
+
+	D("creating server and config nodes\n");
+	rc = msm_setup_server_dev(pdev);
+	if (rc < 0) {
+		pr_err("%s: failed to create server dev: %d\n", __func__,
+		rc);
+		return rc;
+	}
+
+	for (i = 0; i < g_server_dev.config_info.num_config_nodes; i++) {
+		rc = msm_setup_config_dev(i, "config");
+		if (rc < 0) {
+			pr_err("%s:failed to create config dev: %d\n",
+			 __func__, rc);
+			return rc;
+		}
+	}
+
+	msm_isp_register(&g_server_dev);
+	return rc;
+}
+
+static int __exit msm_camera_exit(struct platform_device *pdev)
+{
+	msm_isp_unregister(&g_server_dev);
+	return 0;
+}
+
+static struct platform_driver msm_cam_server_driver = {
+	.probe = msm_camera_probe,
+	.remove = msm_camera_exit,
+	.driver = {
+		.name = "msm_cam_server",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init msm_cam_server_init(void)
+{
+	return platform_driver_register(&msm_cam_server_driver);
+}
+
+static void __exit msm_cam_server_exit(void)
+{
+	platform_driver_unregister(&msm_cam_server_driver);
+}
+
+module_init(msm_cam_server_init);
+module_exit(msm_cam_server_exit);
+MODULE_DESCRIPTION("msm camera server");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/server/msm_cam_server.h b/drivers/media/video/msm/server/msm_cam_server.h
new file mode 100644
index 0000000..2fe4c2b
--- /dev/null
+++ b/drivers/media/video/msm/server/msm_cam_server.h
@@ -0,0 +1,65 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _MSM_CAM_SERVER_H
+#define _MSM_CAM_SERVER_H
+
+#include <linux/proc_fs.h>
+#include <linux/ioctl.h>
+#include <mach/camera.h>
+#include "msm.h"
+
+uint32_t msm_cam_server_get_mctl_handle(void);
+struct msm_cam_media_controller *msm_cam_server_get_mctl(uint32_t handle);
+void msm_cam_server_free_mctl(uint32_t handle);
+/* Server session control APIs */
+int msm_server_begin_session(struct msm_cam_v4l2_device *pcam,
+	int server_q_idx);
+int msm_server_end_session(struct msm_cam_v4l2_device *pcam);
+int msm_send_open_server(struct msm_cam_v4l2_device *pcam);
+int msm_send_close_server(struct msm_cam_v4l2_device *pcam);
+int msm_server_update_sensor_info(struct msm_cam_v4l2_device *pcam,
+	struct msm_camera_sensor_info *sdata);
+/* Server camera control APIs */
+int msm_server_streamon(struct msm_cam_v4l2_device *pcam, int idx);
+int msm_server_streamoff(struct msm_cam_v4l2_device *pcam, int idx);
+int msm_server_get_usecount(void);
+int32_t msm_find_free_queue(void);
+int msm_server_proc_ctrl_cmd(struct msm_cam_v4l2_device *pcam,
+	struct v4l2_control *ctrl, int is_set_cmd);
+int msm_server_s_ctrl(struct msm_cam_v4l2_device *pcam,
+	struct v4l2_control *ctrl);
+int msm_server_g_ctrl(struct msm_cam_v4l2_device *pcam,
+	struct v4l2_control *ctrl);
+int msm_server_q_ctrl(struct msm_cam_v4l2_device *pcam,
+	struct v4l2_queryctrl *queryctrl);
+int msm_server_set_fmt(struct msm_cam_v4l2_device *pcam, int idx,
+	struct v4l2_format *pfmt);
+int msm_server_set_fmt_mplane(struct msm_cam_v4l2_device *pcam, int idx,
+	struct v4l2_format *pfmt);
+int msm_server_get_fmt(struct msm_cam_v4l2_device *pcam,
+	int idx, struct v4l2_format *pfmt);
+int msm_server_get_fmt_mplane(struct msm_cam_v4l2_device *pcam,
+	int idx, struct v4l2_format *pfmt);
+int msm_server_try_fmt(struct msm_cam_v4l2_device *pcam,
+	struct v4l2_format *pfmt);
+int msm_server_try_fmt_mplane(struct msm_cam_v4l2_device *pcam,
+	struct v4l2_format *pfmt);
+int msm_server_v4l2_subscribe_event(struct v4l2_fh *fh,
+	struct v4l2_event_subscription *sub);
+int msm_server_v4l2_unsubscribe_event(struct v4l2_fh *fh,
+	struct v4l2_event_subscription *sub);
+int msm_server_get_crop(struct msm_cam_v4l2_device *pcam,
+	int idx, struct v4l2_crop *crop);
+
+#endif /* _MSM_CAM_SERVER_H */
diff --git a/drivers/media/video/msm/wfd/enc-subdev.c b/drivers/media/video/msm/wfd/enc-subdev.c
index b7ae0f4..c94fa13 100644
--- a/drivers/media/video/msm/wfd/enc-subdev.c
+++ b/drivers/media/video/msm/wfd/enc-subdev.c
@@ -191,7 +191,7 @@
 		}
 
 		vbuf->v4l2_buf.timestamp =
-			ns_to_timeval(frame_data->time_stamp);
+			ns_to_timeval(frame_data->time_stamp * NSEC_PER_USEC);
 
 		WFD_MSG_DBG("bytes used %d, ts: %d.%d, frame type is %d\n",
 				frame_data->data_len,
@@ -365,7 +365,15 @@
 		WFD_MSG_ERR("Failed to get out buf reqs rc = %d", rc);
 		goto err;
 	}
-	b->count = buf_req.actual_count;
+
+	buf_req.actual_count = b->count = max(buf_req.min_count, b->count);
+	rc = vcd_set_buffer_requirements(client_ctx->vcd_handle,
+			VCD_BUFFER_OUTPUT, &buf_req);
+	if (rc) {
+		WFD_MSG_ERR("Failed to set out buf reqs rc = %d", rc);
+		goto err;
+	}
+
 err:
 	return rc;
 }
@@ -1051,6 +1059,7 @@
 	struct v4l2_fract *frate = arg;
 	struct vcd_property_hdr vcd_property_hdr;
 	struct vcd_property_frame_rate vcd_frame_rate;
+	struct vcd_property_vop_timing_constant_delta vcd_delta;
 	int rc;
 	vcd_property_hdr.prop_id = VCD_I_FRAME_RATE;
 	vcd_property_hdr.sz =
@@ -1060,8 +1069,25 @@
 	vcd_frame_rate.fps_numerator = frate->denominator;
 	rc = vcd_set_property(client_ctx->vcd_handle,
 					&vcd_property_hdr, &vcd_frame_rate);
-	if (rc)
+	if (rc) {
 		WFD_MSG_ERR("Failed to set frame rate, rc = %d\n", rc);
+		goto set_framerate_fail;
+	}
+
+	vcd_property_hdr.prop_id = VCD_I_VOP_TIMING_CONSTANT_DELTA;
+	vcd_property_hdr.sz = sizeof(vcd_delta);
+
+	vcd_delta.constant_delta = (frate->numerator * USEC_PER_SEC) /
+					frate->denominator;
+	rc = vcd_set_property(client_ctx->vcd_handle,
+					&vcd_property_hdr, &vcd_delta);
+
+	if (rc) {
+		WFD_MSG_ERR("Failed to set frame delta, rc = %d", rc);
+		goto set_framerate_fail;
+	}
+
+set_framerate_fail:
 	return rc;
 }
 
@@ -1827,12 +1853,16 @@
 	struct venc_buf_info *venc_buf = arg;
 	struct mem_region *mregion = venc_buf->mregion;
 	struct vcd_frame_data vcd_input_buffer = {0};
+	int64_t ts = 0;
+
+	ts = venc_buf->timestamp;
+	do_div(ts, NSEC_PER_USEC);
 
 	vcd_input_buffer.virtual = mregion->kvaddr;
 	vcd_input_buffer.frm_clnt_data = (u32)mregion;
 	vcd_input_buffer.ip_frm_tag = (u32)mregion;
 	vcd_input_buffer.data_len = mregion->size;
-	vcd_input_buffer.time_stamp = venc_buf->timestamp;
+	vcd_input_buffer.time_stamp = ts;
 	vcd_input_buffer.offset = 0;
 
 	rc = vcd_encode_frame(client_ctx->vcd_handle,
diff --git a/drivers/media/video/msm/wfd/wfd-ioctl.c b/drivers/media/video/msm/wfd/wfd-ioctl.c
index 2242aa8..4f6c09d 100644
--- a/drivers/media/video/msm/wfd/wfd-ioctl.c
+++ b/drivers/media/video/msm/wfd/wfd-ioctl.c
@@ -498,7 +498,6 @@
 	if (rc)
 		WFD_MSG_ERR("Failed to free output buffer\n");
 	wfd_unregister_out_buf(inst, minfo);
-	wfd_free_input_buffers(wfd_dev, inst);
 }
 
 static int mdp_output_thread(void *data)
@@ -1344,12 +1343,13 @@
 	inst = filp->private_data;
 	if (inst) {
 		wfdioc_streamoff(filp, NULL, V4L2_BUF_TYPE_VIDEO_CAPTURE);
-		vb2_queue_release(&inst->vid_bufq);
 		rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl,
 				MDP_CLOSE, (void *)inst->mdp_inst);
 		if (rc)
 			WFD_MSG_ERR("Failed to CLOSE mdp subdevice: %d\n", rc);
 
+		vb2_queue_release(&inst->vid_bufq);
+		wfd_free_input_buffers(wfd_dev, inst);
 		rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
 				CLOSE, (void *)inst->venc_inst);
 
diff --git a/drivers/media/video/msm_vidc/Kconfig b/drivers/media/video/msm_vidc/Kconfig
new file mode 100644
index 0000000..0b5a5fe
--- /dev/null
+++ b/drivers/media/video/msm_vidc/Kconfig
@@ -0,0 +1,8 @@
+#
+# VIDEO CORE
+#
+
+menuconfig MSM_VIDC
+	bool "Qualcomm MSM Video Core Driver"
+		depends on ARCH_MSMCOPPER && VIDEO_V4L2
+		default y
diff --git a/drivers/media/video/msm_vidc/Makefile b/drivers/media/video/msm_vidc/Makefile
new file mode 100644
index 0000000..12c61c9
--- /dev/null
+++ b/drivers/media/video/msm_vidc/Makefile
@@ -0,0 +1,8 @@
+obj-$(CONFIG_MSM_VIDC) := 	msm_v4l2_vidc.o \
+				msm_vidc_common.o \
+				msm_vidc.o \
+				msm_vdec.o \
+				msm_venc.o \
+				msm_smem.o \
+				vidc_hal.o \
+				vidc_hal_interrupt_handler.o \
diff --git a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
index f125cdc..550fbde 100644
--- a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
@@ -41,11 +41,49 @@
 };
 
 struct msm_v4l2_vid_inst {
-	void *vidc_inst;
+	struct msm_vidc_inst vidc_inst;
 	void *mem_client;
 	struct list_head registered_bufs;
 };
 
+static inline struct msm_vidc_inst *get_vidc_inst(struct file *filp, void *fh)
+{
+	return container_of(filp->private_data,
+					struct msm_vidc_inst, event_handler);
+}
+
+static inline struct msm_v4l2_vid_inst *get_v4l2_inst(struct file *filp,
+			void *fh)
+{
+	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);
+	rc = v4l2_fh_init(&vidc_inst->event_handler, pvdev);
+	if (rc < 0)
+		return rc;
+	if (&vidc_inst->event_handler.events == NULL) {
+		rc = v4l2_event_init(&vidc_inst->event_handler);
+		if (rc < 0)
+			return rc;
+	}
+	rc = v4l2_event_alloc(&vidc_inst->event_handler, 32);
+	if (rc < 0)
+		return rc;
+	v4l2_fh_add(&vidc_inst->event_handler);
+	return rc;
+}
+
 struct buffer_info *get_registered_buf(struct list_head *list,
 				int fd, u32 buff_off, u32 size)
 {
@@ -79,7 +117,6 @@
 	struct msm_video_device *vid_dev =
 		container_of(vdev, struct msm_video_device, vdev);
 	struct msm_vidc_core *core = video_drvdata(filp);
-	void *inst;
 	struct msm_v4l2_vid_inst *v4l2_inst = kzalloc(sizeof(*v4l2_inst),
 						GFP_KERNEL);
 	if (!v4l2_inst) {
@@ -93,16 +130,17 @@
 		rc = -ENOMEM;
 		goto fail_mem_client;
 	}
-	inst = msm_vidc_open(core->id, vid_dev->type);
-	if (!inst) {
+	rc = msm_vidc_open(&v4l2_inst->vidc_inst, core->id, vid_dev->type);
+	if (rc) {
 		pr_err("Failed to create video instance, core: %d, type = %d\n",
 			core->id, vid_dev->type);
 		rc = -ENOMEM;
 		goto fail_open;
 	}
 	INIT_LIST_HEAD(&v4l2_inst->registered_bufs);
-	v4l2_inst->vidc_inst = inst;
-	filp->private_data = v4l2_inst;
+	rc = msm_vidc_v4l2_setup_event_queue(&v4l2_inst->vidc_inst, vdev);
+	clear_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags);
+	filp->private_data = &(v4l2_inst->vidc_inst.event_handler);
 	return rc;
 fail_open:
 	msm_smem_delete_client(v4l2_inst->mem_client);
@@ -117,8 +155,11 @@
 	int rc;
 	struct list_head *ptr, *next;
 	struct buffer_info *binfo;
-	struct msm_v4l2_vid_inst *v4l2_inst = filp->private_data;
-	rc = msm_vidc_close(v4l2_inst->vidc_inst);
+	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_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);
@@ -133,60 +174,94 @@
 static int msm_v4l2_querycap(struct file *filp, void *fh,
 			struct v4l2_capability *cap)
 {
-	struct msm_v4l2_vid_inst *v4l2_inst = filp->private_data;
-	return msm_vidc_querycap(v4l2_inst->vidc_inst, cap);
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(filp, fh);
+	return msm_vidc_querycap((void *)vidc_inst, cap);
 }
 
 int msm_v4l2_enum_fmt(struct file *file, void *fh,
 					struct v4l2_fmtdesc *f)
 {
-	struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
-	return msm_vidc_enum_fmt(v4l2_inst->vidc_inst, f);
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+	return msm_vidc_enum_fmt((void *)vidc_inst, f);
 }
 
 int msm_v4l2_s_fmt(struct file *file, void *fh,
 					struct v4l2_format *f)
 {
-	struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
-	return msm_vidc_s_fmt(v4l2_inst->vidc_inst, f);
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+	return msm_vidc_s_fmt((void *)vidc_inst, f);
 }
 
 int msm_v4l2_g_fmt(struct file *file, void *fh,
 					struct v4l2_format *f)
 {
-	struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
-	return msm_vidc_g_fmt(v4l2_inst->vidc_inst, f);
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+	return msm_vidc_g_fmt((void *)vidc_inst, f);
 }
 
 int msm_v4l2_s_ctrl(struct file *file, void *fh,
 					struct v4l2_control *a)
 {
-	struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
-	return msm_vidc_s_ctrl(v4l2_inst->vidc_inst, a);
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+	return msm_vidc_s_ctrl((void *)vidc_inst, a);
 }
 
 int msm_v4l2_g_ctrl(struct file *file, void *fh,
 					struct v4l2_control *a)
 {
-	struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
-	return msm_vidc_g_ctrl(v4l2_inst->vidc_inst, a);
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+	return msm_vidc_g_ctrl((void *)vidc_inst, a);
 }
 
 int msm_v4l2_reqbufs(struct file *file, void *fh,
 				struct v4l2_requestbuffers *b)
 {
-	struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
-	return msm_vidc_reqbufs(v4l2_inst->vidc_inst, b);
+	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;
+	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;
+				buffer_info.m.planes[0].reserved[0] =
+					bi->fd;
+				buffer_info.m.planes[0].reserved[1] =
+					bi->buff_off;
+				buffer_info.m.planes[0].length = bi->size;
+				buffer_info.m.planes[0].m.userptr =
+					bi->uvaddr;
+				buffer_info.length = 1;
+				pr_err("Releasing buffer: %d, %d, %d\n",
+				buffer_info.m.planes[0].reserved[0],
+				buffer_info.m.planes[0].reserved[1],
+				buffer_info.m.planes[0].length);
+				rc = msm_vidc_release_buf(&v4l2_inst->vidc_inst,
+					&buffer_info);
+				list_del(&bi->list);
+				msm_smem_free(v4l2_inst->mem_client,
+					bi->handle);
+				kfree(bi);
+			}
+		}
+	}
+	return msm_vidc_reqbufs((void *)vidc_inst, b);
 }
 
 int msm_v4l2_prepare_buf(struct file *file, void *fh,
 				struct v4l2_buffer *b)
 {
-	struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
 	struct msm_smem *handle;
 	struct buffer_info *binfo;
-	int rc = 0;
-	int i;
+	struct msm_vidc_inst *vidc_inst;
+	struct msm_v4l2_vid_inst *v4l2_inst;
+	int i, rc = 0;
+	vidc_inst = get_vidc_inst(file, fh);
+	v4l2_inst = get_v4l2_inst(file, fh);
 	if (!v4l2_inst->mem_client) {
 		pr_err("Failed to get memory client\n");
 		rc = -ENOMEM;
@@ -229,7 +304,7 @@
 		list_add_tail(&binfo->list, &v4l2_inst->registered_bufs);
 		b->m.planes[i].m.userptr = handle->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;
 }
@@ -237,10 +312,13 @@
 int msm_v4l2_qbuf(struct file *file, void *fh,
 				struct v4l2_buffer *b)
 {
-	struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
+	struct msm_vidc_inst *vidc_inst;
+	struct msm_v4l2_vid_inst *v4l2_inst;
 	struct buffer_info *binfo;
 	int rc = 0;
 	int i;
+	vidc_inst = get_vidc_inst(file, fh);
+	v4l2_inst = get_v4l2_inst(file, fh);
 	for (i = 0; i < b->length; ++i) {
 		binfo = get_registered_buf(&v4l2_inst->registered_bufs,
 				b->m.planes[i].reserved[0],
@@ -258,7 +336,7 @@
 		pr_debug("Queueing device address = %ld\n",
 				binfo->handle->device_addr);
 	}
-	rc = msm_vidc_qbuf(v4l2_inst->vidc_inst, b);
+	rc = msm_vidc_qbuf(&v4l2_inst->vidc_inst, b);
 err_invalid_buff:
 	return rc;
 }
@@ -266,22 +344,47 @@
 int msm_v4l2_dqbuf(struct file *file, void *fh,
 				struct v4l2_buffer *b)
 {
-	struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
-	return msm_vidc_dqbuf(v4l2_inst->vidc_inst, b);
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+	return msm_vidc_dqbuf((void *)vidc_inst, b);
 }
 
 int msm_v4l2_streamon(struct file *file, void *fh,
 				enum v4l2_buf_type i)
 {
-	struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
-	return msm_vidc_streamon(v4l2_inst->vidc_inst, i);
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+	return msm_vidc_streamon((void *)vidc_inst, i);
 }
 
 int msm_v4l2_streamoff(struct file *file, void *fh,
 				enum v4l2_buf_type i)
 {
-	struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
-	return msm_vidc_streamoff(v4l2_inst->vidc_inst, i);
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+	return msm_vidc_streamoff((void *)vidc_inst, i);
+}
+
+static int msm_v4l2_subscribe_event(struct v4l2_fh *fh,
+				struct v4l2_event_subscription *sub)
+{
+	int rc = 0;
+	if (sub->type == V4L2_EVENT_ALL)
+		sub->type = V4L2_EVENT_PRIVATE_START + V4L2_EVENT_VIDC_BASE;
+	rc = v4l2_event_subscribe(fh, sub);
+	return rc;
+}
+
+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;
+}
+
+static int msm_v4l2_decoder_cmd(struct file *file, void *fh,
+				struct v4l2_decoder_cmd *dec)
+{
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+	return msm_vidc_decoder_cmd((void *)vidc_inst, dec);
 }
 static const struct v4l2_ioctl_ops msm_v4l2_ioctl_ops = {
 	.vidioc_querycap = msm_v4l2_querycap,
@@ -299,6 +402,9 @@
 	.vidioc_streamoff = msm_v4l2_streamoff,
 	.vidioc_s_ctrl = msm_v4l2_s_ctrl,
 	.vidioc_g_ctrl = msm_v4l2_g_ctrl,
+	.vidioc_subscribe_event = msm_v4l2_subscribe_event,
+	.vidioc_unsubscribe_event = msm_v4l2_unsubscribe_event,
+	.vidioc_decoder_cmd = msm_v4l2_decoder_cmd,
 };
 
 static const struct v4l2_ioctl_ops msm_v4l2_enc_ioctl_ops = {
@@ -307,8 +413,8 @@
 static unsigned int msm_v4l2_poll(struct file *filp,
 	struct poll_table_struct *pt)
 {
-	struct msm_v4l2_vid_inst *v4l2_inst = filp->private_data;
-	return msm_vidc_poll(v4l2_inst->vidc_inst, filp, pt);
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(filp, NULL);
+	return msm_vidc_poll((void *)vidc_inst, filp, pt);
 }
 
 static const struct v4l2_file_operations msm_v4l2_vidc_fops = {
diff --git a/drivers/media/video/msm_vidc/msm_vdec.c b/drivers/media/video/msm_vidc/msm_vdec.c
index 879d324..9edab16 100644
--- a/drivers/media/video/msm_vidc/msm_vdec.c
+++ b/drivers/media/video/msm_vidc/msm_vdec.c
@@ -26,6 +26,7 @@
 #define MAX_NUM_OUTPUT_BUFFERS 6
 
 static const char *const mpeg_video_vidc_divx_format[] = {
+	"DIVX Format 3",
 	"DIVX Format 4",
 	"DIVX Format 5",
 	"DIVX Format 6",
@@ -153,8 +154,7 @@
 static u32 get_frame_size_nv12(int plane,
 					u32 height, u32 width)
 {
-	int stride = (width + 31) & (~31);
-	return height * stride * 3/2;
+	return (ALIGN(height, 32) * ALIGN(width, 32) * 3) / 2;
 }
 static u32 get_frame_size_nv21(int plane,
 					u32 height, u32 width)
@@ -217,6 +217,22 @@
 		.get_frame_size = get_frame_size_nv21,
 		.type = CAPTURE_PORT,
 	},
+	{
+		.name = "DIVX 311",
+		.description = "DIVX 311 compressed format",
+		.fourcc = V4L2_PIX_FMT_DIVX_311,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = OUTPUT_PORT,
+	},
+	{
+		.name = "DIVX",
+		.description = "DIVX 4/5/6 compressed format",
+		.fourcc = V4L2_PIX_FMT_DIVX,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = OUTPUT_PORT,
+	}
 };
 
 int msm_vdec_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i)
@@ -239,31 +255,12 @@
 {
 	int rc = 0;
 	struct vb2_queue *q;
-	unsigned long flags;
-	struct list_head *ptr, *next;
-	struct internal_buf *buf;
-	struct extradata_buf *ebuf;
 
 	q = msm_comm_get_vb2q(inst, i);
 	if (!q) {
 		pr_err("Failed to find buffer queue for type = %d\n", i);
 		return -EINVAL;
 	}
-	spin_lock_irqsave(&inst->lock, flags);
-	list_for_each_safe(ptr, next, &inst->internalbufs) {
-		buf = list_entry(ptr, struct internal_buf, list);
-		list_del(&buf->list);
-		msm_smem_free(inst->mem_client, buf->handle);
-		kfree(buf);
-		}
-	list_for_each_safe(ptr, next, &inst->extradatabufs) {
-		ebuf = list_entry(ptr, struct extradata_buf, list);
-		list_del(&ebuf->list);
-		msm_smem_free(inst->mem_client, ebuf->handle);
-		kfree(ebuf);
-		}
-	spin_unlock_irqrestore(&inst->lock, flags);
-
 	pr_debug("Calling streamoff\n");
 	rc = vb2_streamoff(q, i);
 	if (rc)
@@ -280,8 +277,7 @@
 	switch (b->type) {
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
 		break;
-	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: {
-		struct extradata_buf *binfo;
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
 		for (i = 0; i < b->length; i++) {
 			pr_err("device_addr = %ld, size = %d\n",
 				b->m.planes[i].m.userptr,
@@ -291,19 +287,8 @@
 			buffer_info.num_buffers = 1;
 			buffer_info.align_device_addr =
 				b->m.planes[i].m.userptr;
-			binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
-			if (!binfo) {
-				pr_err("Failed to allocate shared mem\n");
-				return -ENOMEM;
-			}
-			binfo->device_addr = b->m.planes[i].m.userptr;
-			rc = msm_comm_allocate_extradata_buffers(inst, binfo);
-			if (rc) {
-				pr_err("msm_comm_allocate_extradata_buffers failed");
-				break;
-			}
-			buffer_info.extradata_size = binfo->handle->size;
-			buffer_info.extradata_addr = binfo->handle->device_addr;
+			buffer_info.extradata_size = 0;
+			buffer_info.extradata_addr = 0;
 			rc = vidc_hal_session_set_buffers((void *)inst->session,
 					&buffer_info);
 			if (rc) {
@@ -312,7 +297,40 @@
 			}
 		}
 		break;
+	default:
+		pr_err("Buffer type not recognized: %d\n", b->type);
+		break;
 	}
+	return rc;
+}
+
+int msm_vdec_release_buf(struct msm_vidc_inst *inst,
+					struct v4l2_buffer *b)
+{
+	int rc = 0;
+	int i;
+	struct vidc_buffer_addr_info buffer_info;
+
+	switch (b->type) {
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+		break;
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+		for (i = 0; i < b->length; i++) {
+			pr_debug("Release device_addr = %ld, size = %d\n",
+				b->m.planes[i].m.userptr,
+				b->m.planes[i].length);
+			buffer_info.buffer_size = b->m.planes[i].length;
+			buffer_info.buffer_type = HAL_BUFFER_OUTPUT;
+			buffer_info.num_buffers = 1;
+			buffer_info.align_device_addr =
+				 b->m.planes[i].m.userptr;
+			buffer_info.extradata_addr = 0;
+			rc = vidc_hal_session_release_buffers(
+				(void *)inst->session, &buffer_info);
+			if (rc)
+				pr_err("vidc_hal_session_release_buffers failed");
+		}
+		break;
 	default:
 		pr_err("Buffer type not recognized: %d\n", b->type);
 		break;
@@ -345,7 +363,7 @@
 	}
 	rc = vb2_dqbuf(q, b, true);
 	if (rc)
-		pr_err("Failed to qbuf, %d\n", rc);
+		pr_err("Failed to dqbuf, %d\n", rc);
 	return rc;
 }
 
@@ -385,6 +403,10 @@
 
 	if (fmt) {
 		f->fmt.pix_mp.pixelformat = fmt->fourcc;
+		if (inst->in_reconfig == true) {
+			inst->height = inst->reconfig_height;
+			inst->width = inst->reconfig_width;
+		}
 		f->fmt.pix_mp.height = inst->height;
 		f->fmt.pix_mp.width = inst->width;
 		for (i = 0; i < fmt->num_planes; ++i) {
@@ -579,7 +601,6 @@
 	struct hal_nal_stream_format_supported stream_format;
 	struct hal_enable_picture enable_picture;
 	struct hal_enable hal_property;
-	struct hal_enable prop;
 	u32 control_idx = 0;
 	enum hal_property property_id = 0;
 	u32 property_val = 0;
@@ -649,7 +670,7 @@
 				break;
 			}
 			if (property_id) {
-				pr_err("Control: HAL property=%d,ctrl_id=%d,ctrl_value=%d\n",
+				pr_err("Control: HAL property=%x,ctrl_id=%x,ctrl_value=%d\n",
 					   property_id,
 					   msm_vdec_ctrls[control_idx].id,
 					   control.value);
@@ -662,12 +683,6 @@
 		}
 	}
 
-	prop.enable = 1;
-	rc = vidc_hal_session_set_property((void *)inst->session,
-			HAL_PARAM_VDEC_CONTINUE_DATA_TRANSFER, &prop);
-	if (rc)
-		pr_err("Failed to set smooth streaming\n");
-
 	rc = msm_comm_try_state(inst, MSM_VIDC_START_DONE);
 	if (rc) {
 		pr_err("Failed to move inst: %p to start done state\n",
@@ -709,6 +724,7 @@
 			rc = start_streaming(inst);
 		break;
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+		inst->in_reconfig = false;
 		if (inst->vb2_bufq[OUTPUT_PORT].streaming)
 			rc = start_streaming(inst);
 		break;
@@ -732,9 +748,12 @@
 	pr_debug("Streamoff called on: %d capability\n", q->type);
 	switch (q->type) {
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+		if (!inst->vb2_bufq[CAPTURE_PORT].streaming)
+			rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
 		break;
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
-		rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
+		if (!inst->vb2_bufq[OUTPUT_PORT].streaming)
+			rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
 		break;
 	default:
 		pr_err("Q-type is not supported: %d\n", q->type);
diff --git a/drivers/media/video/msm_vidc/msm_vdec.h b/drivers/media/video/msm_vidc/msm_vdec.h
index 6529065..1242fb4 100644
--- a/drivers/media/video/msm_vidc/msm_vdec.h
+++ b/drivers/media/video/msm_vidc/msm_vdec.h
@@ -26,6 +26,7 @@
 int msm_vdec_g_ctrl(void *instance, struct v4l2_control *a);
 int msm_vdec_reqbufs(void *instance, struct v4l2_requestbuffers *b);
 int msm_vdec_prepare_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_vdec_release_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
 int msm_vdec_qbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
 int msm_vdec_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
 int msm_vdec_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
diff --git a/drivers/media/video/msm_vidc/msm_venc.c b/drivers/media/video/msm_vidc/msm_venc.c
index 718acf0..5dfea04f 100644
--- a/drivers/media/video/msm_vidc/msm_venc.c
+++ b/drivers/media/video/msm_vidc/msm_venc.c
@@ -365,9 +365,9 @@
 
 static u32 get_frame_size_nv12(int plane, u32 height, u32 width)
 {
-	int stride = (width + 31) & (~31);
-	return height * stride * 3/2;
+	return ((height + 31) & (~31)) * ((width + 31) & (~31)) * 3/2;
 }
+
 static u32 get_frame_size_nv21(int plane, u32 height, u32 width)
 {
 	return height * width * 2;
@@ -375,8 +375,9 @@
 
 static u32 get_frame_size_compressed(int plane, u32 height, u32 width)
 {
-	return width * height / 2;
+	return ((height + 31) & (~31)) * ((width + 31) & (~31)) * 3/2;
 }
+
 static struct hal_quantization
 	venc_quantization = {I_FRAME_QP, P_FRAME_QP, B_FRAME_QP};
 static struct hal_intra_period
@@ -896,7 +897,7 @@
 		break;
 	}
 	if (property_id) {
-		pr_err("Control: HAL property=%d,ctrl_id=%d,ctrl_value=%d\n",
+		pr_debug("Control: HAL property=%d,ctrl_id=%d,ctrl_value=%d\n",
 				property_id,
 				msm_venc_ctrls[control_idx].id,
 				control.value);
@@ -1110,7 +1111,7 @@
 		break;
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
 		for (i = 0; i < b->length; i++) {
-			pr_err("device_addr = %ld, size = %d\n",
+			pr_debug("device_addr = %ld, size = %d\n",
 				b->m.planes[i].m.userptr,
 				b->m.planes[i].length);
 			buffer_info.buffer_size = b->m.planes[i].length;
diff --git a/drivers/media/video/msm_vidc/msm_vidc.c b/drivers/media/video/msm_vidc/msm_vidc.c
index 7fcb522..09d37ce 100644
--- a/drivers/media/video/msm_vidc/msm_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_vidc.c
@@ -29,11 +29,17 @@
 	struct vb2_buffer *out_vb = NULL;
 	struct vb2_buffer *cap_vb = NULL;
 	unsigned long flags;
+	poll_wait(filp, &inst->event_handler.events->wait, wait);
+	if (v4l2_event_pending(&inst->event_handler))
+		return POLLPRI;
 	if (!outq->streaming && !capq->streaming) {
 		pr_err("Returning POLLERR from here: %d, %d\n",
 			outq->streaming, capq->streaming);
 		return POLLERR;
 	}
+	poll_wait(filp, &inst->event_handler.events->wait, wait);
+	if (v4l2_event_pending(&inst->event_handler))
+		return POLLPRI;
 	poll_wait(filp, &capq->done_wq, wait);
 	poll_wait(filp, &outq->done_wq, wait);
 	spin_lock_irqsave(&capq->done_lock, flags);
@@ -129,6 +135,14 @@
 	return -EINVAL;
 }
 
+int msm_vidc_release_buf(void *instance, struct v4l2_buffer *b)
+{
+	struct msm_vidc_inst *inst = instance;
+	if (inst->session_type == MSM_VIDC_DECODER)
+		return msm_vdec_release_buf(instance, b);
+	return -EINVAL;
+}
+
 int msm_vidc_qbuf(void *instance, struct v4l2_buffer *b)
 {
 	struct msm_vidc_inst *inst = instance;
@@ -208,9 +222,9 @@
 	return vb2_queue_init(q);
 }
 
-void *msm_vidc_open(int core_id, int session_type)
+int msm_vidc_open(void *vidc_inst, int core_id, int session_type)
 {
-	struct msm_vidc_inst *inst = NULL;
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)vidc_inst;
 	struct msm_vidc_core *core = NULL;
 	unsigned long flags;
 	int rc = 0;
@@ -227,17 +241,11 @@
 		goto err_invalid_core;
 	}
 
-	inst = kzalloc(sizeof(*inst), GFP_KERNEL);
-	if (!inst) {
-		pr_err("Unable to allocate video instance\n");
-		goto err_no_mem;
-	}
 	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->extradatabufs);
 	inst->state = MSM_VIDC_CORE_UNINIT_DONE;
 	inst->core = core;
 	for (i = SESSION_MSG_INDEX(SESSION_MSG_START);
@@ -254,6 +262,7 @@
 		msm_vdec_ctrl_init(inst);
 	} else if (session_type == MSM_VIDC_ENCODER) {
 		msm_venc_inst_init(inst);
+		msm_venc_ctrl_init(inst);
 	}
 	rc = vb2_bufq_init(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
 			session_type);
@@ -275,15 +284,14 @@
 	spin_lock_irqsave(&core->lock, flags);
 	list_add_tail(&inst->list, &core->instances);
 	spin_unlock_irqrestore(&core->lock, flags);
-	return inst;
+	return rc;
 fail_init:
 	msm_smem_delete_client(inst->mem_client);
 fail_mem_client:
 	kfree(inst);
 	inst = NULL;
-err_no_mem:
 err_invalid_core:
-	return inst;
+	return rc;
 }
 
 static void cleanup_instance(struct msm_vidc_inst *inst)
@@ -292,25 +300,24 @@
 	struct list_head *ptr, *next;
 	struct vb2_buf_entry *entry;
 	struct internal_buf *buf;
-	struct extradata_buf *ebuf;
 	if (inst) {
 		spin_lock_irqsave(&inst->lock, flags);
-		list_for_each_safe(ptr, next, &inst->pendingq) {
-			entry = list_entry(ptr, struct vb2_buf_entry, list);
-			list_del(&entry->list);
-			kfree(entry);
+		if (!list_empty(&inst->pendingq)) {
+			list_for_each_safe(ptr, next, &inst->pendingq) {
+				entry = list_entry(ptr, struct vb2_buf_entry,
+						list);
+				list_del(&entry->list);
+				kfree(entry);
+			}
 		}
-		list_for_each_safe(ptr, next, &inst->internalbufs) {
-			buf = list_entry(ptr, struct internal_buf, list);
-			list_del(&buf->list);
-			msm_smem_free(inst->mem_client, buf->handle);
-			kfree(buf);
-		}
-		list_for_each_safe(ptr, next, &inst->extradatabufs) {
-			ebuf = list_entry(ptr, struct extradata_buf, list);
-			list_del(&ebuf->list);
-			msm_smem_free(inst->mem_client, ebuf->handle);
-			kfree(ebuf);
+		if (!list_empty(&inst->internalbufs)) {
+			list_for_each_safe(ptr, next, &inst->internalbufs) {
+				buf = list_entry(ptr, struct internal_buf,
+						list);
+				list_del(&buf->list);
+				msm_smem_free(inst->mem_client, buf->handle);
+				kfree(buf);
+			}
 		}
 		spin_unlock_irqrestore(&inst->lock, flags);
 		msm_smem_delete_client(inst->mem_client);
@@ -328,15 +335,13 @@
 	mutex_lock(&core->sync_lock);
 	list_for_each_safe(ptr, next, &core->instances) {
 		temp = list_entry(ptr, struct msm_vidc_inst, list);
-		if (temp == inst) {
+		if (temp == inst)
 			list_del(&inst->list);
-			kfree(inst);
-		}
 	}
 	mutex_unlock(&core->sync_lock);
 	rc = msm_comm_try_state(inst, MSM_VIDC_CORE_UNINIT);
 	if (rc)
-		pr_err("Failed to move video instance to init state\n");
+		pr_err("Failed to move video instance to uninit state\n");
 	cleanup_instance(inst);
 	pr_debug("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 e889b1c..52f1dca 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.c
@@ -149,7 +149,7 @@
 	enum command_response cmd)
 {
 	int rc = 0;
-	rc = wait_for_completion_timeout(
+	rc = wait_for_completion_interruptible_timeout(
 		&inst->completions[SESSION_MSG_INDEX(cmd)],
 		msecs_to_jiffies(HW_RESPONSE_TIMEOUT));
 	if (!rc) {
@@ -183,15 +183,54 @@
 {
 	struct msm_vidc_cb_cmd_done *response = data;
 	struct msm_vidc_inst *inst;
+	struct video_device *vdev;
+	struct v4l2_event dqevent;
+	struct msm_vidc_core *core;
 	if (response) {
 		inst = (struct msm_vidc_inst *)response->session_id;
 		signal_session_msg_receipt(cmd, inst);
+		core = inst->core;
+		if (inst->session_type == MSM_VIDC_ENCODER)
+			vdev = &core->vdev[MSM_VIDC_ENCODER].vdev;
+		else
+			vdev = &core->vdev[MSM_VIDC_DECODER].vdev;
+		dqevent.type = V4L2_EVENT_PRIVATE_START + V4L2_EVENT_VIDC_BASE;
+		dqevent.u.data[0] = (uint8_t)MSM_VIDC_OPEN_DONE;
+		v4l2_event_queue(vdev, &dqevent);
 		return;
 	} else {
 		pr_err("Failed to get valid response for session init\n");
 	}
 }
 
+static void handle_event_change(enum command_response cmd, void *data)
+{
+	struct msm_vidc_cb_cmd_done *response = data;
+	struct msm_vidc_inst *inst;
+	struct video_device *vdev;
+	struct v4l2_event dqevent;
+	struct msm_vidc_cb_event *event_notify;
+	struct msm_vidc_core *core;
+	if (response) {
+		inst = (struct msm_vidc_inst *)response->session_id;
+		core = inst->core;
+		if (inst->session_type == MSM_VIDC_ENCODER)
+			vdev = &core->vdev[MSM_VIDC_ENCODER].vdev;
+		else
+			vdev = &core->vdev[MSM_VIDC_DECODER].vdev;
+		dqevent.type = V4L2_EVENT_PRIVATE_START + V4L2_EVENT_VIDC_BASE;
+		dqevent.u.data[0] = (uint8_t)MSM_VIDC_DECODER_EVENT_CHANGE;
+		event_notify = (struct msm_vidc_cb_event *) response->data;
+		inst->reconfig_height = event_notify->height;
+		inst->reconfig_width = event_notify->width;
+		inst->in_reconfig = true;
+		v4l2_event_queue(vdev, &dqevent);
+		return;
+	} else {
+		pr_err("Failed to get valid response for event_change\n");
+	}
+}
+
 static void handle_session_prop_info(enum command_response cmd, void *data)
 {
 	struct msm_vidc_cb_cmd_done *response = data;
@@ -223,11 +262,22 @@
 {
 	struct msm_vidc_cb_cmd_done *response = data;
 	struct msm_vidc_inst *inst;
+	struct video_device *vdev;
+	struct v4l2_event dqevent;
+	struct msm_vidc_core *core;
 	if (response) {
 		inst = (struct msm_vidc_inst *)response->session_id;
 		signal_session_msg_receipt(cmd, inst);
+		core = inst->core;
+		if (inst->session_type == MSM_VIDC_ENCODER)
+			vdev = &core->vdev[MSM_VIDC_ENCODER].vdev;
+		else
+			vdev = &core->vdev[MSM_VIDC_DECODER].vdev;
+		dqevent.type = V4L2_EVENT_PRIVATE_START + V4L2_EVENT_VIDC_BASE;
+		dqevent.u.data[0] = (uint8_t)MSM_VIDC_START_DONE;
+		v4l2_event_queue(vdev, &dqevent);
 	} else {
-		pr_err("Failed to get valid response for start done\n");
+		pr_err("Failed to get valid response for start\n");
 	}
 }
 
@@ -235,11 +285,22 @@
 {
 	struct msm_vidc_cb_cmd_done *response = data;
 	struct msm_vidc_inst *inst;
+	struct video_device *vdev;
+	struct v4l2_event dqevent;
+	struct msm_vidc_core *core;
 	if (response) {
 		inst = (struct msm_vidc_inst *)response->session_id;
 		signal_session_msg_receipt(cmd, inst);
+		core = inst->core;
+		if (inst->session_type == MSM_VIDC_ENCODER)
+			vdev = &core->vdev[MSM_VIDC_ENCODER].vdev;
+		else
+			vdev = &core->vdev[MSM_VIDC_DECODER].vdev;
+		dqevent.type = V4L2_EVENT_PRIVATE_START + V4L2_EVENT_VIDC_BASE;
+		dqevent.u.data[0] = (uint8_t)MSM_VIDC_STOP_DONE;
+		v4l2_event_queue(vdev, &dqevent);
 	} else {
-		pr_err("Failed to get valid response for stop done\n");
+		pr_err("Failed to get valid response for stop\n");
 	}
 }
 
@@ -251,18 +312,51 @@
 		inst = (struct msm_vidc_inst *)response->session_id;
 		signal_session_msg_receipt(cmd, inst);
 	} else {
-		pr_err("Failed to get valid response for release"
-			   " resource done\n");
+		pr_err("Failed to get valid response for release resource\n");
 	}
 }
 
+static void handle_session_flush(enum command_response cmd, void *data)
+{
+	struct msm_vidc_cb_cmd_done *response = data;
+	struct msm_vidc_inst *inst;
+	struct video_device *vdev;
+	struct v4l2_event dqevent;
+	struct msm_vidc_core *core;
+	if (response) {
+		inst = (struct msm_vidc_inst *)response->session_id;
+		core = inst->core;
+		if (inst->session_type == MSM_VIDC_ENCODER)
+			vdev = &core->vdev[MSM_VIDC_ENCODER].vdev;
+		else
+			vdev = &core->vdev[MSM_VIDC_DECODER].vdev;
+		dqevent.type = V4L2_EVENT_PRIVATE_START + V4L2_EVENT_VIDC_BASE;
+		dqevent.u.data[0] = (uint8_t)MSM_VIDC_DECODER_FLUSH_DONE;
+		v4l2_event_queue(vdev, &dqevent);
+	} else {
+		pr_err("Failed to get valid response for flush\n");
+	}
+}
+
+
 static void handle_session_close(enum command_response cmd, void *data)
 {
 	struct msm_vidc_cb_cmd_done *response = data;
 	struct msm_vidc_inst *inst;
+	struct video_device *vdev;
+	struct v4l2_event dqevent;
+	struct msm_vidc_core *core;
 	if (response) {
 		inst = (struct msm_vidc_inst *)response->session_id;
 		signal_session_msg_receipt(cmd, inst);
+		core = inst->core;
+		if (inst->session_type == MSM_VIDC_ENCODER)
+			vdev = &core->vdev[MSM_VIDC_ENCODER].vdev;
+		else
+			vdev = &core->vdev[MSM_VIDC_DECODER].vdev;
+		dqevent.type = V4L2_EVENT_PRIVATE_START + V4L2_EVENT_VIDC_BASE;
+		dqevent.u.data[0] = (uint8_t)MSM_VIDC_CLOSE_DONE;
+		v4l2_event_queue(vdev, &dqevent);
 	} else {
 		pr_err("Failed to get valid response for session close\n");
 	}
@@ -320,10 +414,37 @@
 		(u32)fill_buf_done->packet_buffer1);
 	if (vb) {
 		vb->v4l2_planes[0].bytesused = fill_buf_done->filled_len1;
-		pr_err("Filled length = %d\n", vb->v4l2_planes[0].bytesused);
+		pr_debug("Filled length = %d\n", vb->v4l2_planes[0].bytesused);
 		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_EOS)
 			vb->v4l2_buf.flags |= V4L2_BUF_FLAG_EOS;
 		vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+	} else {
+		/*
+		 * FIXME:
+		 * Special handling for EOS case: if we sent a 0 length input
+		 * buf with EOS set, Venus doesn't return a valid output buffer.
+		 * So pick up a random buffer that's with us, and send it to
+		 * v4l2 client with EOS flag set.
+		 *
+		 * This would normally be OK unless client decides to send
+		 * frames even after EOS.
+		 *
+		 * This should be fixed in upcoming versions of firmware
+		 */
+		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_EOS
+			&& fill_buf_done->filled_len1 == 0) {
+			struct vb2_queue *q = &inst->vb2_bufq[CAPTURE_PORT];
+
+			if (!list_empty(&q->queued_list)) {
+				vb = list_first_entry(&q->queued_list,
+					struct vb2_buffer, queued_entry);
+				vb->v4l2_planes[0].bytesused = 0;
+				vb->v4l2_buf.flags |= V4L2_BUF_FLAG_EOS;
+				vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+			}
+
+		}
+
 	}
 }
 
@@ -361,6 +482,12 @@
 	case SESSION_END_DONE:
 		handle_session_close(cmd, data);
 		break;
+	case VIDC_EVENT_CHANGE:
+		handle_event_change(cmd, data);
+		break;
+	case SESSION_FLUSH_DONE:
+		handle_session_flush(cmd, data);
+		break;
 	default:
 		pr_err("response unhandled\n");
 		break;
@@ -499,9 +626,13 @@
 	case V4L2_PIX_FMT_VC1_ANNEX_L:
 		codec = HAL_VIDEO_CODEC_VC1;
 		break;
+	case V4L2_PIX_FMT_DIVX_311:
+		codec = HAL_VIDEO_CODEC_DIVX_311;
+		break;
+	case V4L2_PIX_FMT_DIVX:
+		codec = HAL_VIDEO_CODEC_DIVX;
+		break;
 		/*HAL_VIDEO_CODEC_MVC
-		  HAL_VIDEO_CODEC_DIVX_311
-		  HAL_VIDEO_CODEC_DIVX
 		  HAL_VIDEO_CODEC_SPARK
 		  HAL_VIDEO_CODEC_VP6
 		  HAL_VIDEO_CODEC_VP7
@@ -792,21 +923,9 @@
 					&frame_data);
 			pr_debug("Sent etb to HAL\n");
 		} else if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
-			struct extradata_buf *addr;
-			struct list_head *ptr, *next;
 			frame_data.filled_len = 0;
 			frame_data.buffer_type = HAL_BUFFER_OUTPUT;
 			frame_data.extradata_addr = 0;
-			list_for_each_safe(ptr, next, &inst->extradatabufs) {
-				addr = list_entry(ptr,
-						struct extradata_buf, list);
-				if (addr->device_addr ==
-						frame_data.device_addr) {
-					frame_data.extradata_addr =
-						addr->handle->device_addr;
-					break;
-				}
-			}
 			pr_debug("Sending ftb to hal...: Alloc: %d :filled: %d"
 				" extradata_addr: %d\n", frame_data.alloc_len,
 				   frame_data.filled_len,
@@ -850,35 +969,20 @@
 	return rc;
 }
 
-int msm_comm_allocate_extradata_buffers(struct msm_vidc_inst *inst,
-	struct extradata_buf *binfo)
+int msm_vidc_decoder_cmd(void *instance, struct v4l2_decoder_cmd *dec)
 {
 	int rc = 0;
-	unsigned long flags;
-	struct msm_smem *handle;
-	pr_debug("Extradata: num = %d, size = %d, align = %d\n",
-			inst->buff_req.buffer[4].buffer_count_actual,
-			inst->buff_req.buffer[4].buffer_size,
-			inst->buff_req.buffer[4].buffer_alignment);
-	if (!inst->buff_req.buffer[4].buffer_size) {
-		pr_err("invalid size: %d",
-			   inst->buff_req.buffer[4].buffer_size);
-		rc = -ENOMEM;
-		goto err_no_mem;
+	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+	mutex_lock(&inst->sync_lock);
+	if (dec->cmd != V4L2_DEC_CMD_STOP)
+		return -EINVAL;
+	rc = vidc_hal_session_flush((void *)inst->session, HAL_FLUSH_OUTPUT);
+	if (rc) {
+		pr_err("Failed to get property\n");
+		goto exit;
 	}
-	handle = msm_smem_alloc(inst->mem_client,
-			inst->buff_req.buffer[4].buffer_size,
-			inst->buff_req.buffer[4].buffer_alignment, 0);
-	if (!handle) {
-		pr_err("Failed to allocate Extradata memory\n");
-		rc = -ENOMEM;
-		goto err_no_mem;
-	}
-	binfo->handle = handle;
-	spin_lock_irqsave(&inst->lock, flags);
-	list_add_tail(&binfo->list, &inst->extradatabufs);
-	spin_unlock_irqrestore(&inst->lock, flags);
-err_no_mem:
+exit:
+	mutex_unlock(&inst->sync_lock);
 	return rc;
 }
 
@@ -887,12 +991,26 @@
 	int rc = 0;
 	struct msm_smem *handle;
 	struct internal_buf *binfo;
+	struct list_head *ptr, *next;
 	struct vidc_buffer_addr_info buffer_info;
 	unsigned long flags;
 	int i;
 	pr_debug("scratch: num = %d, size = %d\n",
 			inst->buff_req.buffer[6].buffer_count_actual,
 			inst->buff_req.buffer[6].buffer_size);
+	spin_lock_irqsave(&inst->lock, flags);
+	if (!list_empty(&inst->internalbufs)) {
+		list_for_each_safe(ptr, next, &inst->internalbufs) {
+			binfo = list_entry(ptr, struct internal_buf,
+					list);
+			list_del(&binfo->list);
+			msm_smem_free(inst->mem_client, binfo->handle);
+			kfree(binfo);
+		}
+	}
+	spin_unlock_irqrestore(&inst->lock, flags);
+
+
 	for (i = 0; i < inst->buff_req.buffer[6].buffer_count_actual;
 				i++) {
 		handle = msm_smem_alloc(inst->mem_client,
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.h b/drivers/media/video/msm_vidc/msm_vidc_common.h
index 45bfa7b..2fafa79 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.h
@@ -27,8 +27,6 @@
 		struct msm_vidc_inst *inst, enum v4l2_buf_type type);
 int msm_comm_try_state(struct msm_vidc_inst *inst, int state);
 int msm_comm_try_get_bufreqs(struct msm_vidc_inst *inst);
-int msm_comm_allocate_extradata_buffers(struct msm_vidc_inst *inst,
-	struct extradata_buf *binfo);
 int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst);
 int msm_comm_qbuf(struct vb2_buffer *vb);
 #define IS_PRIV_CTRL(idx) (\
diff --git a/drivers/media/video/msm_vidc/msm_vidc_internal.h b/drivers/media/video/msm_vidc/msm_vidc_internal.h
index dce2dee..fb1ab58 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_internal.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_internal.h
@@ -21,6 +21,7 @@
 #include <media/v4l2-dev.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
 #include <media/v4l2-ctrls.h>
 #include <media/videobuf2-core.h>
 #include <media/msm_vidc.h>
@@ -32,6 +33,8 @@
 #define MAX_DEBUGFS_NAME 50
 #define DEFAULT_TIMEOUT 3
 
+#define V4L2_EVENT_VIDC_BASE  10
+
 #define SYS_MSG_START VIDC_EVENT_CHANGE
 #define SYS_MSG_END SYS_DEBUG
 #define SESSION_MSG_START SESSION_LOAD_RESOURCE_DONE
@@ -72,6 +75,11 @@
 	MSM_VIDC_CORE_UNINIT,
 };
 
+enum vidc_resposes_id {
+	MSM_VIDC_DECODER_FLUSH_DONE = 0x11,
+	MSM_VIDC_DECODER_EVENT_CHANGE,
+};
+
 struct buf_info {
 	struct list_head list;
 	struct vb2_buffer *buf;
@@ -82,12 +90,6 @@
 	struct msm_smem *handle;
 };
 
-struct extradata_buf {
-	struct list_head list;
-	struct msm_smem *handle;
-	u32 device_addr;
-};
-
 struct msm_vidc_format {
 	char name[64];
 	u8 description[32];
@@ -141,11 +143,14 @@
 	spinlock_t lock;
 	struct list_head pendingq;
 	struct list_head internalbufs;
-	struct list_head extradatabufs;
 	struct buffer_requirements buff_req;
 	void *mem_client;
 	struct v4l2_ctrl_handler ctrl_handler;
 	struct completion completions[SESSION_MSG_END - SESSION_MSG_START + 1];
+	struct v4l2_fh event_handler;
+	bool in_reconfig;
+	u32 reconfig_width;
+	u32 reconfig_height;
 };
 
 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 f4c7878..1f33c2c 100644
--- a/drivers/media/video/msm_vidc/vidc_hal.c
+++ b/drivers/media/video/msm_vidc/vidc_hal.c
@@ -1793,7 +1793,7 @@
 
 static void vidc_hal_core_work_handler(struct work_struct *work)
 {
-	struct hal_device *device =	list_first_entry(
+	struct hal_device *device = list_first_entry(
 		&hal_ctxt.dev_head, struct hal_device, list);
 
 	HAL_MSG_INFO(" GOT INTERRUPT %s() ", __func__);
diff --git a/drivers/media/video/msm_vidc/vidc_hal_api.h b/drivers/media/video/msm_vidc/vidc_hal_api.h
index b32c190..036091b 100644
--- a/drivers/media/video/msm_vidc/vidc_hal_api.h
+++ b/drivers/media/video/msm_vidc/vidc_hal_api.h
@@ -18,7 +18,7 @@
 
 #define CONTAINS(__a, __sz, __t) ({\
 	int __rc = __t >= __a && \
-			__t <= __a + __sz; \
+			__t < __a + __sz; \
 	__rc; \
 })
 
@@ -834,6 +834,8 @@
 	u32 device_id;
 	u32 session_id;
 	u32 status;
+	u32 height;
+	u32 width;
 };
 
 /* Data callback structure */
diff --git a/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c b/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c
index 0fbcc1f..02b9699 100644
--- a/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c
+++ b/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c
@@ -74,6 +74,59 @@
 	return vidc_err;
 }
 
+void hal_process_sess_evt_seq_changed(struct hal_device *device,
+	struct hfi_msg_event_notify_packet *pkt)
+{
+	struct msm_vidc_cb_cmd_done cmd_done;
+	struct msm_vidc_cb_event event_notify;
+	int num_properties_changed;
+	struct hfi_frame_size frame_sz;
+	u8 *data_ptr;
+	enum HFI_PROPERTY prop_id;
+	HAL_MSG_LOW("RECEIVED:EVENT_NOTIFY");
+	if (sizeof(struct hfi_msg_event_notify_packet)
+		> pkt->size) {
+		HAL_MSG_ERROR("hal_process_session_init_done:bad_pkt_size");
+		return;
+	}
+
+	memset(&cmd_done, 0, sizeof(struct msm_vidc_cb_cmd_done));
+	memset(&event_notify, 0, sizeof(struct
+				msm_vidc_cb_event));
+
+	cmd_done.device_id = device->device_id;
+	cmd_done.session_id = ((struct hal_session *) pkt->session_id)->
+		session_id;
+	cmd_done.status = VIDC_ERR_NONE;
+	cmd_done.size = sizeof(struct msm_vidc_cb_event);
+	num_properties_changed = pkt->event_data2;
+	if (num_properties_changed) {
+		data_ptr = (u8 *) &pkt->rg_ext_event_data[0];
+		do {
+			prop_id = (enum HFI_PROPERTY) *((u32 *)data_ptr);
+			switch (prop_id) {
+			case HFI_PROPERTY_PARAM_FRAME_SIZE:
+				frame_sz.buffer =
+					(enum HFI_BUFFER)
+						*((((u32 *)data_ptr)+1));
+				frame_sz.width =
+					event_notify.width =
+						*((((u32 *)data_ptr)+2));
+				frame_sz.height =
+					event_notify.height =
+						*((((u32 *)data_ptr)+3));
+				data_ptr += 4;
+			break;
+			default:
+			break;
+			}
+			num_properties_changed--;
+		} while (num_properties_changed > 0);
+	}
+	cmd_done.data = &event_notify;
+	device->callback(VIDC_EVENT_CHANGE, &cmd_done);
+}
+
 static void hal_process_event_notify(struct hal_device *device,
 	struct hfi_msg_event_notify_packet *pkt)
 {
@@ -94,6 +147,7 @@
 		break;
 	case HFI_EVENT_SESSION_SEQUENCE_CHANGED:
 		HAL_MSG_INFO("HFI_EVENT_SESSION_SEQUENCE_CHANGED");
+		hal_process_sess_evt_seq_changed(device, pkt);
 		break;
 	case HFI_EVENT_SESSION_PROPERTY_CHANGED:
 		HAL_MSG_INFO("HFI_EVENT_SESSION_PROPERTY_CHANGED");
@@ -456,9 +510,12 @@
 		if (sizeof(struct
 			hfi_msg_session_fill_buffer_done_compressed_packet)
 			!= pkt->size) {
-			HAL_MSG_ERROR("hal_process_session_ftb_done:"
-						"bad_pkt_size");
+			HAL_MSG_ERROR("%s: bad_pkt_size", __func__);
 			return;
+		} else if (pkt->error_type != HFI_ERR_NONE) {
+			HAL_MSG_ERROR("%s: got buffer back with error %x",
+					__func__, pkt->error_type);
+			/* Proceed with the FBD */
 		}
 
 		data_done.device_id = device->device_id;
diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c
index deb35cc..737b726 100644
--- a/drivers/media/video/v4l2-compat-ioctl32.c
+++ b/drivers/media/video/v4l2-compat-ioctl32.c
@@ -958,6 +958,8 @@
 	case VIDIOC_G_ENC_INDEX:
 	case VIDIOC_ENCODER_CMD:
 	case VIDIOC_TRY_ENCODER_CMD:
+	case VIDIOC_DECODER_CMD:
+	case VIDIOC_TRY_DECODER_CMD:
 	case VIDIOC_DBG_S_REGISTER:
 	case VIDIOC_DBG_G_REGISTER:
 	case VIDIOC_DBG_G_CHIP_IDENT:
diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
index 5e44c90..d64ecb5 100644
--- a/drivers/media/video/v4l2-ioctl.c
+++ b/drivers/media/video/v4l2-ioctl.c
@@ -244,6 +244,8 @@
 	[_IOC_NR(VIDIOC_ENCODER_CMD)] 	   = "VIDIOC_ENCODER_CMD",
 	[_IOC_NR(VIDIOC_TRY_ENCODER_CMD)]  = "VIDIOC_TRY_ENCODER_CMD",
 
+	[_IOC_NR(VIDIOC_DECODER_CMD)]	   = "VIDIOC_DECODER_CMD",
+	[_IOC_NR(VIDIOC_TRY_DECODER_CMD)]  = "VIDIOC_TRY_DECODER_CMD",
 	[_IOC_NR(VIDIOC_DBG_S_REGISTER)]   = "VIDIOC_DBG_S_REGISTER",
 	[_IOC_NR(VIDIOC_DBG_G_REGISTER)]   = "VIDIOC_DBG_G_REGISTER",
 
@@ -1775,6 +1777,28 @@
 			dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags);
 		break;
 	}
+	case VIDIOC_DECODER_CMD:
+	{
+		struct v4l2_decoder_cmd *p = arg;
+
+		if (!ops->vidioc_decoder_cmd)
+			break;
+		ret = ops->vidioc_decoder_cmd(file, fh, p);
+		if (!ret)
+			dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags);
+		break;
+	}
+	case VIDIOC_TRY_DECODER_CMD:
+	{
+		struct v4l2_decoder_cmd *p = arg;
+
+		if (!ops->vidioc_try_decoder_cmd)
+			break;
+		ret = ops->vidioc_try_decoder_cmd(file, fh, p);
+		if (!ret)
+			dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags);
+		break;
+	}
 	case VIDIOC_G_PARM:
 	{
 		struct v4l2_streamparm *p = arg;
diff --git a/drivers/media/video/vcap_v4l2.c b/drivers/media/video/vcap_v4l2.c
index 219f7a0..b5037e8 100644
--- a/drivers/media/video/vcap_v4l2.c
+++ b/drivers/media/video/vcap_v4l2.c
@@ -20,7 +20,6 @@
 #include <linux/platform_device.h>
 #include <linux/memory_alloc.h>
 
-#include <mach/msm_subsystem_map.h>
 #include <mach/board.h>
 #include <mach/gpio.h>
 #include <mach/irqs.h>
@@ -39,10 +38,12 @@
 #include <linux/interrupt.h>
 #include <mach/msm_bus.h>
 #include <mach/msm_bus_board.h>
+#include <mach/iommu_domains.h>
 
 #include <media/vcap_v4l2.h>
 #include <media/vcap_fmt.h>
 #include "vcap_vc.h"
+#include "vcap_vp.h"
 
 #define NUM_INPUTS 1
 #define MSM_VCAP_DRV_NAME "msm_vcap"
@@ -57,6 +58,28 @@
 			printk(KERN_DEBUG "VCAP: " fmt, ## arg);	\
 	} while (0)
 
+enum vcap_op_mode determine_mode(struct vcap_client_data *cd)
+{
+	if (cd->set_cap == 1 && cd->set_vp_o == 0 &&
+			cd->set_decode == 0)
+		return VC_VCAP_OP;
+	else if (cd->set_cap == 1 && cd->set_vp_o == 1 &&
+			cd->set_decode == 0)
+		return VC_AND_VP_VCAP_OP;
+	else if (cd->set_cap == 0 && cd->set_vp_o == 1 &&
+			cd->set_decode == 1)
+		return VP_VCAP_OP;
+	else
+		return UNKNOWN_VCAP_OP;
+}
+
+void dealloc_resources(struct vcap_client_data *cd)
+{
+	cd->set_cap = false;
+	cd->set_decode = false;
+	cd->set_vp_o = false;
+}
+
 int get_phys_addr(struct vcap_dev *dev, struct vb2_queue *q,
 				  struct v4l2_buffer *b)
 {
@@ -103,6 +126,8 @@
 			&buf->paddr, (size_t *)&len);
 	if (rc < 0) {
 		pr_err("%s: Could not get phys addr\n", __func__);
+		ion_free(dev->ion_client, buf->ion_handle);
+		buf->ion_handle = NULL;
 		return -EFAULT;
 	}
 
@@ -148,7 +173,7 @@
 	return 0;
 }
 
-/* Videobuf operations */
+/* VC Videobuf operations */
 
 static int capture_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
 				unsigned int *nplanes, unsigned long sizes[],
@@ -157,7 +182,6 @@
 	*nbuffers += 2;
 	if (*nbuffers > VIDEO_MAX_FRAME)
 		return -EINVAL;
-
 	*nplanes = 1;
 	return 0;
 }
@@ -240,6 +264,197 @@
 	.buf_cleanup		= capture_buffer_cleanup,
 };
 
+/* VP I/P Videobuf operations */
+
+static int vp_in_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
+				unsigned int *nplanes, unsigned long sizes[],
+				void *alloc_ctxs[])
+{
+	if (*nbuffers >= VIDEO_MAX_FRAME && *nbuffers < 5)
+		*nbuffers = 5;
+
+	*nplanes = 1;
+	return 0;
+}
+
+static int vp_in_buffer_init(struct vb2_buffer *vb)
+{
+	return 0;
+}
+
+static int vp_in_buffer_prepare(struct vb2_buffer *vb)
+{
+	return 0;
+}
+
+static void vp_in_buffer_queue(struct vb2_buffer *vb)
+{
+	struct vcap_client_data *cd = vb2_get_drv_priv(vb->vb2_queue);
+	struct vcap_buffer *buf = container_of(vb, struct vcap_buffer, vb);
+	struct vp_action *vp_act = &cd->vid_vp_action;
+	struct vb2_queue *q = vb->vb2_queue;
+	unsigned long flags = 0;
+
+	spin_lock_irqsave(&cd->cap_slock, flags);
+	list_add_tail(&buf->list, &vp_act->in_active);
+	spin_unlock_irqrestore(&cd->cap_slock, flags);
+
+	if (atomic_read(&cd->dev->vp_enabled) == 0) {
+		if (cd->vid_vp_action.vp_state == VP_FRAME1) {
+			if (atomic_read(&q->queued_count) > 1 &&
+				atomic_read(&cd->vp_out_vidq.queued_count) > 0)
+				/* Valid code flow for VC-VP mode */
+				kickoff_vp(cd);
+		} else {
+			/* VP has already kicked off just needs cont */
+			continue_vp(cd);
+		}
+	}
+}
+
+static int vp_in_start_streaming(struct vb2_queue *vq)
+{
+	dprintk(2, "VP IN start streaming\n");
+	return 0;
+}
+
+static int vp_in_stop_streaming(struct vb2_queue *vq)
+{
+	struct vcap_client_data *c_data = vb2_get_drv_priv(vq);
+	struct vb2_buffer *vb;
+
+	dprintk(2, "VP stop streaming\n");
+
+	while (!list_empty(&c_data->vid_vp_action.in_active)) {
+		struct vcap_buffer *buf;
+		buf = list_entry(c_data->vid_vp_action.in_active.next,
+			struct vcap_buffer, list);
+		list_del(&buf->list);
+		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+	}
+
+	/* clean ion handles */
+	list_for_each_entry(vb, &vq->queued_list, queued_entry)
+		free_ion_handle_work(c_data->dev, vb);
+	return 0;
+}
+
+static int vp_in_buffer_finish(struct vb2_buffer *vb)
+{
+	return 0;
+}
+
+static void vp_in_buffer_cleanup(struct vb2_buffer *vb)
+{
+}
+
+static struct vb2_ops vp_in_video_qops = {
+	.queue_setup		= vp_in_queue_setup,
+	.buf_init			= vp_in_buffer_init,
+	.buf_prepare		= vp_in_buffer_prepare,
+	.buf_queue			= vp_in_buffer_queue,
+	.start_streaming	= vp_in_start_streaming,
+	.stop_streaming		= vp_in_stop_streaming,
+	.buf_finish			= vp_in_buffer_finish,
+	.buf_cleanup		= vp_in_buffer_cleanup,
+};
+
+
+/* VP O/P Videobuf operations */
+
+static int vp_out_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
+				unsigned int *nplanes, unsigned long sizes[],
+				void *alloc_ctxs[])
+{
+	if (*nbuffers >= VIDEO_MAX_FRAME && *nbuffers < 3)
+		*nbuffers = 3;
+
+	*nplanes = 1;
+	return 0;
+}
+
+static int vp_out_buffer_init(struct vb2_buffer *vb)
+{
+	return 0;
+}
+
+static int vp_out_buffer_prepare(struct vb2_buffer *vb)
+{
+	return 0;
+}
+
+static void vp_out_buffer_queue(struct vb2_buffer *vb)
+{
+	struct vcap_client_data *cd = vb2_get_drv_priv(vb->vb2_queue);
+	struct vcap_buffer *buf = container_of(vb, struct vcap_buffer, vb);
+	struct vp_action *vp_act = &cd->vid_vp_action;
+	struct vb2_queue *q = vb->vb2_queue;
+	unsigned long flags = 0;
+
+	spin_lock_irqsave(&cd->cap_slock, flags);
+	list_add_tail(&buf->list, &vp_act->out_active);
+	spin_unlock_irqrestore(&cd->cap_slock, flags);
+
+	if (atomic_read(&cd->dev->vp_enabled) == 0) {
+		if (cd->vid_vp_action.vp_state == VP_FRAME1) {
+			if (atomic_read(&q->queued_count) > 0 &&
+				atomic_read(&
+					cd->vp_in_vidq.queued_count) > 1)
+				kickoff_vp(cd);
+		} else {
+			/* VP has already kicked off just needs cont */
+			continue_vp(cd);
+		}
+	}
+}
+
+static int vp_out_start_streaming(struct vb2_queue *vq)
+{
+	return 0;
+}
+
+static int vp_out_stop_streaming(struct vb2_queue *vq)
+{
+	struct vcap_client_data *c_data = vb2_get_drv_priv(vq);
+	struct vb2_buffer *vb;
+
+	dprintk(2, "VP out q stop streaming\n");
+	vp_stop_capture(c_data);
+
+	while (!list_empty(&c_data->vid_vp_action.out_active)) {
+		struct vcap_buffer *buf;
+		buf = list_entry(c_data->vid_vp_action.out_active.next,
+			struct vcap_buffer, list);
+		list_del(&buf->list);
+		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+	}
+
+	/* clean ion handles */
+	list_for_each_entry(vb, &vq->queued_list, queued_entry)
+		free_ion_handle_work(c_data->dev, vb);
+	return 0;
+}
+
+static int vp_out_buffer_finish(struct vb2_buffer *vb)
+{
+	return 0;
+}
+
+static void vp_out_buffer_cleanup(struct vb2_buffer *vb)
+{
+}
+
+static struct vb2_ops vp_out_video_qops = {
+	.queue_setup		= vp_out_queue_setup,
+	.buf_init			= vp_out_buffer_init,
+	.buf_prepare		= vp_out_buffer_prepare,
+	.buf_queue			= vp_out_buffer_queue,
+	.start_streaming	= vp_out_start_streaming,
+	.stop_streaming		= vp_out_stop_streaming,
+	.buf_finish			= vp_out_buffer_finish,
+	.buf_cleanup		= vp_out_buffer_cleanup,
+};
+
 /* IOCTL vidioc handling */
 
 static int vidioc_querycap(struct file *file, void  *priv,
@@ -279,20 +494,16 @@
 					struct v4l2_format *f)
 {
 	int size;
-#ifdef NEW_S_FMT
+	struct vcap_priv_fmt *priv_fmt;
 	struct v4l2_format_vc_ext *vc_format;
-#endif
 	struct vcap_client_data *c_data = file->private_data;
 
-	switch (f->type) {
-	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-#ifdef NEW_S_FMT
-		vc_format = (struct v4l2_format_vc_ext *) f->fmt.raw_data;
+	priv_fmt = (struct vcap_priv_fmt *) f->fmt.raw_data;
+
+	switch (priv_fmt->type) {
+	case VC_TYPE:
+		vc_format = (struct v4l2_format_vc_ext *) &priv_fmt->u.timing;
 		c_data->vc_format = *vc_format;
-#else
-		c_data->vc_format =
-			vcap_vc_lut[f->fmt.pix.priv];
-#endif
 
 		config_vc_format(c_data);
 
@@ -304,22 +515,46 @@
 		else
 			size *= 2;
 
-#ifndef NEW_S_FMT
-		f->fmt.pix.bytesperline = size;
+		priv_fmt->u.timing.bytesperline = size;
 		size *= (c_data->vc_format.vactive_end -
 			c_data->vc_format.vactive_start);
-		f->fmt.pix.sizeimage = size;
-#endif
+		priv_fmt->u.timing.sizeimage = size;
 		vcap_ctrl->vc_client = c_data;
+		c_data->set_cap = true;
 		break;
-	case V4L2_BUF_TYPE_INTERLACED_IN_DECODER:
-		c_data->vp_buf_type_field = V4L2_BUF_TYPE_INTERLACED_IN_DECODER;
-		c_data->vp_format.field = f->fmt.pix.field;
-		c_data->vp_format.height = f->fmt.pix.height;
-		c_data->vp_format.width = f->fmt.pix.width;
-		c_data->vp_format.pixelformat = f->fmt.pix.pixelformat;
+	case VP_IN_TYPE:
+		vcap_ctrl->vp_client = c_data;
+		c_data->vp_in_fmt.width = priv_fmt->u.pix.width;
+		c_data->vp_in_fmt.height = priv_fmt->u.pix.height;
+		c_data->vp_in_fmt.pixfmt = priv_fmt->u.pix.pixelformat;
+
+		if (priv_fmt->u.pix.priv)
+			c_data->vid_vp_action.nr_enabled = 1;
+
+		size = c_data->vp_in_fmt.width * c_data->vp_in_fmt.height;
+		if (c_data->vp_in_fmt.pixfmt == V4L2_PIX_FMT_NV16)
+			size = size * 2;
+		else
+			size = size / 2 * 3;
+		priv_fmt->u.pix.sizeimage = size;
+		c_data->set_decode = true;
 		break;
-	case V4L2_BUF_TYPE_INTERLACED_IN_AFE:
+	case VP_OUT_TYPE:
+		vcap_ctrl->vp_client = c_data;
+		c_data->vp_out_fmt.width = priv_fmt->u.pix.width;
+		c_data->vp_out_fmt.height = priv_fmt->u.pix.height;
+		c_data->vp_out_fmt.pixfmt = priv_fmt->u.pix.pixelformat;
+
+		if (priv_fmt->u.pix.priv)
+			c_data->vid_vp_action.nr_enabled = 1;
+
+		size = c_data->vp_out_fmt.width * c_data->vp_out_fmt.height;
+		if (c_data->vp_out_fmt.pixfmt == V4L2_PIX_FMT_NV16)
+			size = size * 2;
+		else
+			size = size / 2 * 3;
+		priv_fmt->u.pix.sizeimage = size;
+		c_data->set_vp_o = true;
 		break;
 	default:
 		break;
@@ -332,9 +567,55 @@
 			  struct v4l2_requestbuffers *rb)
 {
 	struct vcap_client_data *c_data = file->private_data;
+	int rc;
+
+	dprintk(3, "In Req Buf %08x\n", (unsigned int)rb->type);
+	c_data->op_mode = determine_mode(c_data);
+	if (c_data->op_mode == UNKNOWN_VCAP_OP) {
+		pr_err("VCAP Error: %s: VCAP in unknown mode\n", __func__);
+		return -ENOTRECOVERABLE;
+	}
+
 	switch (rb->type) {
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		return vb2_reqbufs(&c_data->vc_vidq, rb);
+		if (c_data->op_mode == VC_AND_VP_VCAP_OP) {
+			if (c_data->vc_format.color_space) {
+				pr_err("VCAP Err: %s: VP No RGB support\n",
+					__func__);
+				return -ENOTRECOVERABLE;
+			}
+			if (!c_data->vc_format.mode) {
+				pr_err("VCAP Err: VP No prog support\n");
+				return -ENOTRECOVERABLE;
+			}
+			if (rb->count < 6) {
+				pr_err("VCAP Err: Not enough buf for VC_VP\n");
+				return -EINVAL;
+			}
+			rc = vb2_reqbufs(&c_data->vc_vidq, rb);
+			if (rc < 0)
+				return rc;
+
+			c_data->vp_in_fmt.width =
+				(c_data->vc_format.hactive_end -
+				c_data->vc_format.hactive_start);
+			c_data->vp_in_fmt.height =
+				(c_data->vc_format.vactive_end -
+				c_data->vc_format.vactive_start);
+			/* VC outputs YCbCr 4:2:2 */
+			c_data->vp_in_fmt.pixfmt = V4L2_PIX_FMT_NV16;
+			rb->type = V4L2_BUF_TYPE_INTERLACED_IN_DECODER;
+			rc = vb2_reqbufs(&c_data->vp_in_vidq, rb);
+			rb->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+			return rc;
+
+		} else {
+			return vb2_reqbufs(&c_data->vc_vidq, rb);
+		}
+	case V4L2_BUF_TYPE_INTERLACED_IN_DECODER:
+		return vb2_reqbufs(&c_data->vp_in_vidq, rb);
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+		return vb2_reqbufs(&c_data->vp_out_vidq, rb);
 	default:
 		pr_err("VCAP Error: %s: Unknown buffer type\n", __func__);
 		return -EINVAL;
@@ -359,16 +640,57 @@
 static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
 {
 	struct vcap_client_data *c_data = file->private_data;
+	struct vb2_buffer *vb;
+	struct vb2_queue *q;
 	int rc;
 
+	dprintk(3, "In Q Buf %08x\n", (unsigned int)p->type);
 	switch (p->type) {
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		if (get_phys_addr(c_data->dev, &c_data->vc_vidq, p))
-			return -EINVAL;
+		if (c_data->op_mode == VC_AND_VP_VCAP_OP) {
+			/* If buffer in vp_in_q it will be coming back */
+			q = &c_data->vp_in_vidq;
+			if (p->index >= q->num_buffers) {
+				dprintk(1, "qbuf: buffer index out of range\n");
+				return -EINVAL;
+			}
+
+			vb = q->bufs[p->index];
+			if (NULL == vb) {
+				dprintk(1, "qbuf: buffer is NULL\n");
+				return -EINVAL;
+			}
+
+			if (vb->state != VB2_BUF_STATE_DEQUEUED) {
+				dprintk(1, "qbuf: buffer already in use\n");
+				return -EINVAL;
+			}
+		}
+		rc = get_phys_addr(c_data->dev, &c_data->vc_vidq, p);
+		if (rc < 0)
+			return rc;
 		rc = vb2_qbuf(&c_data->vc_vidq, p);
 		if (rc < 0)
 			free_ion_handle(c_data->dev, &c_data->vc_vidq, p);
 		return rc;
+	case V4L2_BUF_TYPE_INTERLACED_IN_DECODER:
+		if (c_data->op_mode == VC_AND_VP_VCAP_OP)
+			return -EINVAL;
+		rc = get_phys_addr(c_data->dev, &c_data->vp_in_vidq, p);
+		if (rc < 0)
+			return rc;
+		rc = vb2_qbuf(&c_data->vp_in_vidq, p);
+		if (rc < 0)
+			free_ion_handle(c_data->dev, &c_data->vp_in_vidq, p);
+		return rc;
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+		rc = get_phys_addr(c_data->dev, &c_data->vp_out_vidq, p);
+		if (rc < 0)
+			return rc;
+		rc = vb2_qbuf(&c_data->vp_out_vidq, p);
+		if (rc < 0)
+			free_ion_handle(c_data->dev, &c_data->vp_out_vidq, p);
+		return rc;
 	default:
 		pr_err("VCAP Error: %s: Unknown buffer type\n", __func__);
 		return -EINVAL;
@@ -381,12 +703,29 @@
 	struct vcap_client_data *c_data = file->private_data;
 	int rc;
 
+	dprintk(3, "In DQ Buf %08x\n", (unsigned int)p->type);
 	switch (p->type) {
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		if (c_data->op_mode == VC_AND_VP_VCAP_OP)
+			return -EINVAL;
 		rc = vb2_dqbuf(&c_data->vc_vidq, p, file->f_flags & O_NONBLOCK);
 		if (rc < 0)
 			return rc;
 		return free_ion_handle(c_data->dev, &c_data->vc_vidq, p);
+	case V4L2_BUF_TYPE_INTERLACED_IN_DECODER:
+		if (c_data->op_mode == VC_AND_VP_VCAP_OP)
+			return -EINVAL;
+		rc = vb2_dqbuf(&c_data->vp_in_vidq, p, file->f_flags &
+				O_NONBLOCK);
+		if (rc < 0)
+			return rc;
+		return free_ion_handle(c_data->dev, &c_data->vp_in_vidq, p);
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+		rc = vb2_dqbuf(&c_data->vp_out_vidq, p, file->f_flags &
+				O_NONBLOCK);
+		if (rc < 0)
+			return rc;
+		return free_ion_handle(c_data->dev, &c_data->vp_out_vidq, p);
 	default:
 		pr_err("VCAP Error: %s: Unknown buffer type", __func__);
 		return -EINVAL;
@@ -394,15 +733,153 @@
 	return 0;
 }
 
+/*
+ * When calling streamon on multiple queues there is a need to first verify
+ * that the steamon will succeed on all queues, similarly for streamoff
+ */
+int streamon_validate_q(struct vb2_queue *q)
+{
+	if (q->fileio) {
+		dprintk(1, "streamon: file io in progress\n");
+		return -EBUSY;
+	}
+
+	if (q->streaming) {
+		dprintk(1, "streamon: already streaming\n");
+		return -EBUSY;
+	}
+
+	if (V4L2_TYPE_IS_OUTPUT(q->type)) {
+		if (list_empty(&q->queued_list)) {
+			dprintk(1, "streamon: no output buffers queued\n");
+			return -EINVAL;
+		}
+	}
+	return 0;
+}
+
 static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
 {
 	struct vcap_client_data *c_data = file->private_data;
+	int rc;
 
-	switch (i) {
-	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+	dprintk(3, "In Stream ON\n");
+	if (determine_mode(c_data) != c_data->op_mode) {
+		pr_err("VCAP Error: %s: s_fmt called after req_buf", __func__);
+		return -ENOTRECOVERABLE;
+	}
+
+	switch (c_data->op_mode) {
+	case VC_VCAP_OP:
+		c_data->dev->vc_client = c_data;
+		config_vc_format(c_data);
 		return vb2_streamon(&c_data->vc_vidq, i);
+	case VP_VCAP_OP:
+		rc = streamon_validate_q(&c_data->vp_in_vidq);
+		if (rc < 0)
+			return rc;
+		rc = streamon_validate_q(&c_data->vp_out_vidq);
+		if (rc < 0)
+			return rc;
+
+		c_data->dev->vp_client = c_data;
+
+		rc = config_vp_format(c_data);
+		if (rc < 0)
+			return rc;
+		rc = init_motion_buf(c_data);
+		if (rc < 0)
+			return rc;
+		if (c_data->vid_vp_action.nr_enabled) {
+			rc = init_nr_buf(c_data);
+			if (rc < 0)
+				goto s_on_deinit_m_buf;
+		}
+
+		c_data->vid_vp_action.vp_state = VP_FRAME1;
+
+		rc = vb2_streamon(&c_data->vp_in_vidq,
+				V4L2_BUF_TYPE_INTERLACED_IN_DECODER);
+		if (rc < 0)
+			goto s_on_deinit_nr_buf;
+
+		rc = vb2_streamon(&c_data->vp_out_vidq,
+				V4L2_BUF_TYPE_VIDEO_OUTPUT);
+		if (rc < 0)
+			goto s_on_deinit_nr_buf;
+		return rc;
+	case VC_AND_VP_VCAP_OP:
+		rc = streamon_validate_q(&c_data->vc_vidq);
+		if (rc < 0)
+			return rc;
+		rc = streamon_validate_q(&c_data->vp_in_vidq);
+		if (rc < 0)
+			return rc;
+		rc = streamon_validate_q(&c_data->vp_out_vidq);
+		if (rc < 0)
+			return rc;
+
+		c_data->dev->vc_client = c_data;
+		c_data->dev->vp_client = c_data;
+		c_data->dev->vc_to_vp_work.cd = c_data;
+
+		rc = config_vc_format(c_data);
+		if (rc < 0)
+			return rc;
+		rc = config_vp_format(c_data);
+		if (rc < 0)
+			return rc;
+		rc = init_motion_buf(c_data);
+		if (rc < 0)
+			return rc;
+		if (c_data->vid_vp_action.nr_enabled) {
+			rc = init_nr_buf(c_data);
+			if (rc < 0)
+				goto s_on_deinit_m_buf;
+		}
+		c_data->streaming = 1;
+
+		c_data->vid_vp_action.vp_state = VP_FRAME1;
+
+		/* These stream on calls should not fail */
+		rc = vb2_streamon(&c_data->vc_vidq,
+				V4L2_BUF_TYPE_VIDEO_CAPTURE);
+		if (rc < 0)
+			goto s_on_deinit_nr_buf;
+
+		rc = vb2_streamon(&c_data->vp_in_vidq,
+				V4L2_BUF_TYPE_INTERLACED_IN_DECODER);
+		if (rc < 0)
+			goto s_on_deinit_nr_buf;
+
+		rc = vb2_streamon(&c_data->vp_out_vidq,
+				V4L2_BUF_TYPE_VIDEO_OUTPUT);
+		if (rc < 0)
+			goto s_on_deinit_nr_buf;
+		return rc;
 	default:
-		pr_err("VCAP Error: %s: Unknown buffer type", __func__);
+		pr_err("VCAP Error: %s: Operation Mode type", __func__);
+		return -ENOTRECOVERABLE;
+	}
+	return 0;
+
+s_on_deinit_nr_buf:
+	if (c_data->vid_vp_action.nr_enabled)
+		deinit_nr_buf(c_data);
+s_on_deinit_m_buf:
+	deinit_motion_buf(c_data);
+	return rc;
+}
+
+int streamoff_validate_q(struct vb2_queue *q)
+{
+	if (q->fileio) {
+		dprintk(1, "streamoff: file io in progress\n");
+		return -EBUSY;
+	}
+
+	if (!q->streaming) {
+		dprintk(1, "streamoff: not streaming\n");
 		return -EINVAL;
 	}
 	return 0;
@@ -413,21 +890,78 @@
 	struct vcap_client_data *c_data = file->private_data;
 	int rc;
 
-	switch (i) {
-	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+	switch (c_data->op_mode) {
+	case VC_VCAP_OP:
 		rc = vb2_streamoff(&c_data->vc_vidq, i);
 		if (rc >= 0)
 			atomic_set(&c_data->dev->vc_enabled, 0);
 		return rc;
+	case VP_VCAP_OP:
+		rc = streamoff_validate_q(&c_data->vp_in_vidq);
+		if (rc < 0)
+			return rc;
+		rc = streamoff_validate_q(&c_data->vp_out_vidq);
+		if (rc < 0)
+			return rc;
+
+		/* These stream on calls should not fail */
+		rc = vb2_streamoff(&c_data->vp_in_vidq,
+				V4L2_BUF_TYPE_INTERLACED_IN_DECODER);
+		if (rc < 0)
+			return rc;
+
+		rc = vb2_streamoff(&c_data->vp_out_vidq,
+				V4L2_BUF_TYPE_VIDEO_OUTPUT);
+		if (rc < 0)
+			return rc;
+
+		deinit_motion_buf(c_data);
+		if (c_data->vid_vp_action.nr_enabled)
+			deinit_nr_buf(c_data);
+		atomic_set(&c_data->dev->vp_enabled, 0);
+		return rc;
+	case VC_AND_VP_VCAP_OP:
+		rc = streamoff_validate_q(&c_data->vc_vidq);
+		if (rc < 0)
+			return rc;
+		rc = streamoff_validate_q(&c_data->vp_in_vidq);
+		if (rc < 0)
+			return rc;
+		rc = streamoff_validate_q(&c_data->vp_out_vidq);
+		if (rc < 0)
+			return rc;
+
+		/* These stream on calls should not fail */
+		c_data->streaming = 0;
+		rc = vb2_streamoff(&c_data->vc_vidq,
+				V4L2_BUF_TYPE_VIDEO_CAPTURE);
+		if (rc < 0)
+			return rc;
+
+		rc = vb2_streamoff(&c_data->vp_in_vidq,
+				V4L2_BUF_TYPE_INTERLACED_IN_DECODER);
+		if (rc < 0)
+			return rc;
+
+		rc = vb2_streamoff(&c_data->vp_out_vidq,
+				V4L2_BUF_TYPE_VIDEO_OUTPUT);
+		if (rc < 0)
+			return rc;
+
+		deinit_motion_buf(c_data);
+		if (c_data->vid_vp_action.nr_enabled)
+			deinit_nr_buf(c_data);
+		atomic_set(&c_data->dev->vc_enabled, 0);
+		atomic_set(&c_data->dev->vp_enabled, 0);
+		return rc;
 	default:
-		pr_err("VCAP Error: %s: Unknown buffer type", __func__);
-		break;
+		pr_err("VCAP Error: %s: Unknown Operation mode", __func__);
+		return -ENOTRECOVERABLE;
 	}
 	return 0;
 }
 
 /* VCAP fops */
-
 static void *vcap_ops_get_userptr(void *alloc_ctx, unsigned long vaddr,
 					unsigned long size, int write)
 {
@@ -464,7 +998,7 @@
 
 	spin_lock_init(&c_data->cap_slock);
 
-	/* initialize queue */
+	/* initialize vc queue */
 	q = &c_data->vc_vidq;
 	memset(q, 0, sizeof(c_data->vc_vidq));
 	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
@@ -473,17 +1007,49 @@
 	q->buf_struct_size = sizeof(struct vcap_buffer);
 	q->ops = &capture_video_qops;
 	q->mem_ops = &vcap_mem_ops;
+	ret = vb2_queue_init(q);
+	if (ret < 0)
+		goto vc_q_failed;
+
+	/* initialize vp in queue */
+	q = &c_data->vp_in_vidq;
+	memset(q, 0, sizeof(c_data->vp_in_vidq));
+	q->type = V4L2_BUF_TYPE_INTERLACED_IN_DECODER;
+	q->io_modes = VB2_USERPTR;
+	q->drv_priv = c_data;
+	q->buf_struct_size = sizeof(struct vcap_buffer);
+	q->ops = &vp_in_video_qops;
+	q->mem_ops = &vcap_mem_ops;
+	ret = vb2_queue_init(q);
+	if (ret < 0)
+		goto vp_in_q_failed;
+
+	/* initialize vp out queue */
+	q = &c_data->vp_out_vidq;
+	memset(q, 0, sizeof(c_data->vp_out_vidq));
+	q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	q->io_modes = VB2_USERPTR;
+	q->drv_priv = c_data;
+	q->buf_struct_size = sizeof(struct vcap_buffer);
+	q->ops = &vp_out_video_qops;
+	q->mem_ops = &vcap_mem_ops;
 
 	ret = vb2_queue_init(q);
 	if (ret < 0)
-		goto open_failed;
+		goto vp_out_q_failed;
 
 	INIT_LIST_HEAD(&c_data->vid_vc_action.active);
+	INIT_LIST_HEAD(&c_data->vid_vp_action.in_active);
+	INIT_LIST_HEAD(&c_data->vid_vp_action.out_active);
 	file->private_data = c_data;
 
 	return 0;
 
-open_failed:
+vp_out_q_failed:
+	vb2_queue_release(&c_data->vp_in_vidq);
+vp_in_q_failed:
+	vb2_queue_release(&c_data->vc_vidq);
+vc_q_failed:
 	kfree(c_data);
 	return ret;
 }
@@ -491,6 +1057,8 @@
 static int vcap_close(struct file *file)
 {
 	struct vcap_client_data *c_data = file->private_data;
+	vb2_queue_release(&c_data->vp_out_vidq);
+	vb2_queue_release(&c_data->vp_in_vidq);
 	vb2_queue_release(&c_data->vc_vidq);
 	c_data->dev->vc_client = NULL;
 	c_data->dev->vp_client = NULL;
@@ -498,13 +1066,60 @@
 	return 0;
 }
 
+unsigned int poll_work(struct vb2_queue *q, struct file *file,
+	poll_table *wait, bool write_q)
+{
+	unsigned long flags;
+	struct vb2_buffer *vb = NULL;
+
+	if (q->num_buffers == 0)
+		return POLLERR;
+
+	if (list_empty(&q->queued_list))
+		return POLLERR;
+
+	poll_wait(file, &q->done_wq, wait);
+
+	spin_lock_irqsave(&q->done_lock, flags);
+	if (!list_empty(&q->done_list))
+		vb = list_first_entry(&q->done_list, struct vb2_buffer,
+					done_entry);
+	spin_unlock_irqrestore(&q->done_lock, flags);
+
+	if (vb && (vb->state == VB2_BUF_STATE_DONE
+			|| vb->state == VB2_BUF_STATE_ERROR)) {
+		return (write_q) ? POLLOUT | POLLWRNORM :
+			POLLIN | POLLRDNORM;
+	}
+	return 0;
+}
+
 static unsigned int vcap_poll(struct file *file,
 				  struct poll_table_struct *wait)
 {
 	struct vcap_client_data *c_data = file->private_data;
-	struct vb2_queue *q = &c_data->vc_vidq;
+	struct vb2_queue *q;
+	unsigned int mask = 0;
 
-	return vb2_poll(q, file, wait);
+	switch (c_data->op_mode) {
+	case VC_VCAP_OP:
+		q = &c_data->vc_vidq;
+		return vb2_poll(q, file, wait);
+	case VP_VCAP_OP:
+		q = &c_data->vp_in_vidq;
+		mask = poll_work(q, file, wait, 0);
+		q = &c_data->vp_out_vidq;
+		mask |= poll_work(q, file, wait, 1);
+		return mask;
+	case VC_AND_VP_VCAP_OP:
+		q = &c_data->vp_out_vidq;
+		mask = poll_work(q, file, wait, 0);
+		return mask;
+	default:
+		pr_err("VCAP Error: %s: Unknown operation mode", __func__);
+		return POLLERR;
+	}
+	return 0;
 }
 /* V4L2 and video device structures */
 
@@ -522,6 +1137,10 @@
 	.vidioc_g_fmt_vid_cap     = vidioc_g_fmt_vid_cap,
 	.vidioc_try_fmt_vid_cap   = vidioc_try_fmt_vid_cap,
 	.vidioc_s_fmt_vid_cap     = vidioc_s_fmt_vid_cap,
+	.vidioc_s_fmt_type_private     = vidioc_s_fmt_vid_cap,
+	.vidioc_g_fmt_type_private     = vidioc_g_fmt_vid_cap,
+	.vidioc_s_fmt_vid_out_mplane	= vidioc_s_fmt_vid_cap,
+	.vidioc_g_fmt_vid_out_mplane	= vidioc_g_fmt_vid_cap,
 	.vidioc_reqbufs       = vidioc_reqbufs,
 	.vidioc_querybuf      = vidioc_querybuf,
 	.vidioc_qbuf          = vidioc_qbuf,
@@ -537,9 +1156,9 @@
 	.release	= video_device_release,
 };
 
-int vcap_reg_powerup(struct vcap_dev *dev, struct device *ddev)
+int vcap_reg_powerup(struct vcap_dev *dev)
 {
-	dev->fs_vcap = regulator_get(ddev, "vdd");
+	dev->fs_vcap = regulator_get(NULL, "fs_vcap");
 	if (IS_ERR(dev->fs_vcap)) {
 		pr_err("%s: Regulator FS_VCAP get failed %ld\n", __func__,
 			PTR_ERR(dev->fs_vcap));
@@ -715,7 +1334,7 @@
 {
 	int rc;
 
-	rc = vcap_reg_powerup(dev, ddev);
+	rc = vcap_reg_powerup(dev);
 	if (rc < 0)
 		goto reg_failed;
 	rc = vcap_clk_powerup(dev, ddev);
@@ -751,6 +1370,11 @@
 	return 0;
 }
 
+static irqreturn_t vcap_vp_handler(int irq_num, void *data)
+{
+	return vp_handler(vcap_ctrl);
+}
+
 static irqreturn_t vcap_vc_handler(int irq_num, void *data)
 {
 	return vc_handler(vcap_ctrl);
@@ -793,26 +1417,44 @@
 		goto free_resource;
 	}
 
-	dev->vcapirq = platform_get_resource_byname(pdev,
-					IORESOURCE_IRQ, "vcap");
-	if (!dev->vcapirq) {
-		pr_err("%s: no irq resource?\n", __func__);
+	dev->vcirq = platform_get_resource_byname(pdev,
+					IORESOURCE_IRQ, "vc_irq");
+	if (!dev->vcirq) {
+		pr_err("%s: no vc irq resource?\n", __func__);
+		ret = -ENODEV;
+		goto free_resource;
+	}
+	dev->vpirq = platform_get_resource_byname(pdev,
+					IORESOURCE_IRQ, "vp_irq");
+	if (!dev->vpirq) {
+		pr_err("%s: no vp irq resource?\n", __func__);
 		ret = -ENODEV;
 		goto free_resource;
 	}
 
-	ret = request_irq(dev->vcapirq->start, vcap_vc_handler,
-		IRQF_TRIGGER_RISING, "vcap", 0);
+
+	ret = request_irq(dev->vcirq->start, vcap_vc_handler,
+		IRQF_TRIGGER_RISING, "vc_irq", 0);
 	if (ret < 0) {
-		pr_err("%s: irq request fail\n", __func__);
+		pr_err("%s: vc irq request fail\n", __func__);
 		ret = -EBUSY;
 		goto free_resource;
 	}
+	disable_irq(dev->vcirq->start);
 
-	disable_irq(dev->vcapirq->start);
+	ret = request_irq(dev->vpirq->start, vcap_vp_handler,
+		IRQF_TRIGGER_RISING, "vp_irq", 0);
+
+	if (ret < 0) {
+		pr_err("%s: vp irq request fail\n", __func__);
+		ret = -EBUSY;
+		goto free_resource;
+	}
+	disable_irq(dev->vpirq->start);
 
 	snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name),
 			"%s", MSM_VCAP_DRV_NAME);
+
 	ret = v4l2_device_register(NULL, &dev->v4l2_dev);
 	if (ret)
 		goto free_resource;
@@ -842,17 +1484,25 @@
 	dev->vfd = vfd;
 	video_set_drvdata(vfd, dev);
 
-	dev->ion_client = msm_ion_client_create(-1, "vcap");
-	if (IS_ERR((void *)dev->ion_client)) {
-		pr_err("could not get ion client");
+	dev->vcap_wq = create_workqueue("vcap");
+	if (!dev->vcap_wq) {
+		pr_err("Could not create workqueue");
 		goto rel_vdev;
 	}
 
+	dev->ion_client = msm_ion_client_create(-1, "vcap");
+	if (IS_ERR((void *)dev->ion_client)) {
+		pr_err("could not get ion client");
+		goto rel_vcap_wq;
+	}
+
 	atomic_set(&dev->vc_enabled, 0);
+	atomic_set(&dev->vp_enabled, 0);
 
 	dprintk(1, "Exit probe succesfully");
 	return 0;
-
+rel_vcap_wq:
+	destroy_workqueue(dev->vcap_wq);
 rel_vdev:
 	video_device_release(vfd);
 deinit_vc:
@@ -874,6 +1524,8 @@
 {
 	struct vcap_dev *dev = vcap_ctrl;
 	ion_client_destroy(dev->ion_client);
+	flush_workqueue(dev->vcap_wq);
+	destroy_workqueue(dev->vcap_wq);
 	video_device_release(dev->vfd);
 	deinit_vc();
 	vcap_disable(dev);
diff --git a/drivers/media/video/vcap_vc.c b/drivers/media/video/vcap_vc.c
index ed0bc25..2c4a243 100644
--- a/drivers/media/video/vcap_vc.c
+++ b/drivers/media/video/vcap_vc.c
@@ -34,401 +34,6 @@
 			printk(KERN_DEBUG "VC: " fmt, ## arg);		\
 	} while (0)
 
-struct v4l2_format_vc_ext vcap_vc_lut[] = {
-		/* 1080p */
-	{
-		HAL_VCAP_YUV_1080p_60_RH, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
-		HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 148.5,
-		32, 2200, 192, 2112, 4, 24, 0, 2, 0, 44, 0, 0, 0, 0,
-		0, 0
-	},
-	{
-		HAL_VCAP_YUV_1080p_60_FL, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
-		HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 148.5,
-		1125, 2200, 192, 2112, 41, 1121, 0, 5, 0, 44, 0, 0, 0,
-		0, 0, 0
-	},
-	{
-		HAL_VCAP_RGB_1080p_60_FL, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
-		HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_RGB, 148.5,
-		1125, 2200, 192, 2112, 41, 1121, 0, 5, 0, 44, 0, 0, 0,
-		0, 0, 0
-	},
-	{
-		HAL_VCAP_YUV_1080p_24_FL, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
-		HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 74.25,
-		1125, 2750, 192, 2112, 41, 1121, 0, 5, 0, 44, 0, 0, 0,
-		0, 0, 0
-	},
-	{
-		HAL_VCAP_YUV_1080p_24_RH, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
-		HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 74.25,
-		112, 2750, 192, 2112, 4, 110, 0, 2, 0, 44, 0, 0, 0,
-		0, 0, 0
-	},
-	{
-		HAL_VCAP_YUV_1080p_24_RW, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
-		HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 74.25,
-		1125, 275, 19, 211, 41, 1121, 0, 5, 0, 16, 0, 0, 0,
-		0, 0, 0
-	},
-	{
-		HAL_VCAP_YUV_1080p_60_RW, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
-		HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 148.5,
-		1125, 200, 22, 182, 41, 1121, 0, 5, 0, 16, 0, 0, 0,
-		0, 0, 0
-	},
-	{
-		HAL_VCAP_YUV_1080p_50_FL, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
-		HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 148.5,
-		1125, 2640, 192, 2112, 41, 1121, 0, 5, 0, 44, 0, 0, 0,
-		0, 0, 0
-	},
-	{
-		HAL_VCAP_YUV_1080p_50_RH, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
-		HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 148.5,
-		15, 2640, 192, 2112, 6, 13, 0, 5, 0, 44, 0, 0, 0,
-		0, 0, 0
-	},
-	{
-		HAL_VCAP_YUV_1080p_25_FL, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
-		HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 74.25,
-		1125, 2640, 192, 2112, 41, 1121, 0, 5, 0, 44, 0, 0,
-		0, 0, 0, 0
-	},
-	{
-		HAL_VCAP_YUV_1080p_25_RH, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
-		HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 74.25,
-		10, 2640, 192, 2112, 4, 8, 0, 2, 0, 44, 0, 0, 0,
-		0, 0, 0
-	},
-	{
-		HAL_VCAP_YUV_1080p_30_RH, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
-		HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 74.25,
-		1125, 2200, 192, 2112, 41, 1121, 0, 5, 0, 44, 0, 0, 0,
-		0, 0, 0
-	},
-	{
-		HAL_VCAP_RGB_1080p_25_FL, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
-		HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_RGB, 74.25,
-		1125, 2640, 192, 2112, 41, 1121, 0, 5, 0, 44, 0, 0, 0,
-		0, 0, 0
-	},
-	{
-		HAL_VCAP_RGB_1080p_25_RH, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
-		HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_RGB, 74.25,
-		10, 2640, 192, 2112, 4, 8, 0, 2, 0, 44, 0, 0, 0,
-		0, 0, 0
-	},
-		/* 1080i */
-	{
-		HAL_VCAP_YUV_1080i_60_FL, HAL_VCAP_MODE_INT, HAL_VCAP_POLAR_POS,
-		HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 74.25,
-		1125, 2200, 192, 2112, 20, 560, 0, 5, 0, 44, 583, 1123, 1100,
-		1100, 563, 568
-	},
-	{
-		HAL_VCAP_YUV_1080i_60_RH, HAL_VCAP_MODE_INT, HAL_VCAP_POLAR_POS,
-		HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 74.25,
-		18, 2200, 192, 2112, 3, 7, 0, 2, 0, 44, 11, 15, 1100,
-		1100, 8, 10
-	},
-	{
-		HAL_VCAP_YUV_1080i_60_RW, HAL_VCAP_MODE_INT, HAL_VCAP_POLAR_POS,
-		HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 74.25,
-		1125, 220, 19, 211, 20, 560, 0, 5, 0, 4, 583, 1123, 110,
-		110, 563, 568
-	},
-	{
-		HAL_VCAP_YUV_1080i_50_FL, HAL_VCAP_MODE_INT, HAL_VCAP_POLAR_POS,
-		HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 72.00,
-		1125, 2640, 192, 2112, 20, 560, 0, 5, 0, 44, 583, 1123, 1320,
-		1320, 563, 568
-	},
-	{
-		HAL_VCAP_YUV_1080i_50_RH, HAL_VCAP_MODE_INT, HAL_VCAP_POLAR_POS,
-		HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 72.00,
-		52, 2640, 192, 2112, 4, 24, 0, 2, 0, 44, 30, 50, 1320,
-		1320, 26, 28},
-	{
-		HAL_VCAP_YUV_1080i_50_RW, HAL_VCAP_MODE_INT, HAL_VCAP_POLAR_POS,
-		HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 72.00,
-		1125, 264, 19, 211, 20, 560, 0, 5, 0, 4, 583, 1123, 110,
-		110, 563, 568
-	},
-	{
-		HAL_VCAP_RGB_1080i_50_FL, HAL_VCAP_MODE_INT, HAL_VCAP_POLAR_POS,
-		HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_RGB, 72.00,
-		1125, 2640, 192, 2112, 20, 560, 0, 5, 0, 44, 583, 1123, 1320,
-		1320, 563, 568
-	},
-	{
-		HAL_VCAP_RGB_1080i_50_RH, HAL_VCAP_MODE_INT, HAL_VCAP_POLAR_POS,
-		HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_RGB, 72.00,
-		52, 2640, 192, 2112, 4, 24, 0, 2, 0, 44, 30, 50, 1320,
-		1320, 26, 28
-	},
-		/* 480i */
-	{
-		HAL_VCAP_YUV_480i_60_RH, HAL_VCAP_MODE_INT, HAL_VCAP_POLAR_NEG,
-		HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 27.027,
-		20, 1716, 238, 1678, 3, 7, 0, 2, 0, 124, 14, 18, 820,
-		820, 10, 12
-	},
-	{
-		HAL_VCAP_YUV_480i_60_FL, HAL_VCAP_MODE_INT, HAL_VCAP_POLAR_NEG,
-		HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 27.027,
-		525, 1716, 238, 1678, 18, 258, 0, 3, 0, 124, 281, 521, 858,
-		858, 262, 265
-	},
-	{
-		HAL_VCAP_YUV_480i_60_RW, HAL_VCAP_MODE_INT, HAL_VCAP_POLAR_NEG,
-		HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 27.027,
-		525, 172, 24, 168, 18, 258, 0, 3, 0, 12, 281, 521, 86,
-		86, 262, 265
-	},
-	{
-		HAL_VCAP_YUV_2880_480i_60_FL, HAL_VCAP_MODE_INT,
-		HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_POS,
-		HAL_VCAP_YUV, 54.000, 525, 3432, 476, 3356, 18, 258, 0, 3,
-		0, 248, 281, 521, 1716, 1716, 262, 265
-	},
-	{
-		HAL_VCAP_YUV_2880_480i_60_RH, HAL_VCAP_MODE_INT,
-		HAL_VCAP_POLAR_NEG,	HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_POS,
-		HAL_VCAP_YUV, 54.000, 32, 3432, 476, 3356, 4, 14, 0, 3, 0,
-		248, 20, 30, 1716, 1716, 16, 19
-	},
-		/* 480p */
-	{
-		HAL_VCAP_YUV_480p_60_RH, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_NEG,
-		HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 27.027,
-		8, 858, 122, 842, 2, 5, 0, 1, 0, 62, 0, 0, 0,
-		0, 0, 0
-	},
-	{
-		HAL_VCAP_RGB_480p_60_RH, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_NEG,
-		HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_POS, HAL_VCAP_RGB, 27.027,
-		52, 858, 122, 842, 3, 50, 0, 2, 0, 62, 0, 0, 0,
-		0, 0, 0
-	},
-	{
-		HAL_VCAP_RGB_480p_60_FL, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_NEG,
-		HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_POS, HAL_VCAP_RGB, 27.027,
-		525, 858, 122, 842, 36, 516, 0, 6, 0, 62, 0, 0, 0,
-		0, 0, 0
-	},
-	{
-		HAL_VCAP_YUV_480p_60_FL, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_NEG,
-		HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 27.027,
-		525, 858, 122, 842, 36, 516, 0, 6, 0, 62, 0, 0, 0, 0, 0, 0
-	},
-	{
-		HAL_VCAP_YUV_480p_60_RW, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_NEG,
-		HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 27.027,
-		525, 86, 12, 84, 36, 516, 0, 6, 0, 6, 0, 0, 0,
-		0, 0, 0
-	},
-	{
-		HAL_VCAP_YUV_2880_480p_60_FL, HAL_VCAP_MODE_PRO,
-		HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_POS,
-		HAL_VCAP_YUV, 108.000, 525, 3432, 488, 3368, 36, 516, 0, 6,
-		0, 248, 0, 0, 0, 0, 0, 0
-	},
-	{
-		HAL_VCAP_YUV_2880_480p_60_RH, HAL_VCAP_MODE_PRO,
-		HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_POS,
-		HAL_VCAP_YUV, 108.000, 25, 3432, 488, 3368, 8, 22, 0, 6, 0,
-		248, 0, 0, 0,	0, 0, 0
-	},
-		/* 720p */
-	{
-		HAL_VCAP_YUV_720p_60_FL, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
-		HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 74.25,
-		750, 1650, 260, 1540, 25, 745, 0, 5, 0, 40, 0, 0, 0,
-		0, 0, 0
-	},
-	{
-		HAL_VCAP_RGB_720p_60_FL, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
-		HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_RGB, 74.25,
-		750, 1650, 260, 1540, 25, 745, 0, 5, 0, 40, 0, 0, 0,
-		0, 0, 0
-	},
-	{
-		HAL_VCAP_YUV_720p_60_RW, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
-		HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 74.25,
-		750, 165, 26, 154, 25, 745, 0, 5, 0, 4, 0, 0, 0,
-		0, 0, 0
-	},
-	{
-		HAL_VCAP_YUV_720p_60_RH, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
-		HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 74.25,
-		35, 1650, 260, 1540, 5, 32, 0, 3, 0, 40, 0, 0, 0,
-		0, 0, 0
-	},
-	{
-		HAL_VCAP_YUV_720p_50_FL, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
-		HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 74.25,
-		750, 1980, 260, 1540, 25, 745, 0, 5, 0, 40, 0, 0, 0,
-		 0, 0, 0
-	},
-	{
-		HAL_VCAP_YUV_720p_50_RW, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
-		HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 74.25,
-		750, 198, 26, 154, 25, 745, 0, 5, 0, 4, 0, 0, 0,
-		0, 0, 0
-	},
-	{
-		HAL_VCAP_YUV_720p_50_RH, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
-		HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 74.25,
-		6, 1980, 260, 1540, 2, 5, 0, 1, 0, 40, 0, 0, 0,
-		0, 0, 0
-	},
-		/* 576p */
-	{
-		HAL_VCAP_YUV_576p_50_FL, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_NEG,
-		HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 27.0,
-		625, 864, 132, 852, 44, 620, 0, 5, 0, 64, 0, 0, 0,
-		0, 0, 0},
-	{
-		HAL_VCAP_RGB_576p_50_FL, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_NEG,
-		HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_POS, HAL_VCAP_RGB, 27.0,
-		625, 864, 132, 852, 44, 620, 0, 5, 0, 64, 0, 0, 0,
-		0, 0, 0
-	},
-	{
-		HAL_VCAP_YUV_576p_50_RW, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_NEG,
-		HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 27.0,
-		625, 86, 13, 85, 44, 620, 0, 5, 0, 6, 0, 0, 0,
-		0, 0, 0
-	},
-	{
-		HAL_VCAP_YUV_576p_50_RH, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_NEG,
-		HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 27.0,
-		25, 864, 132, 852, 4, 23, 0, 3, 0, 64, 0, 0, 0,
-		0, 0, 0
-	},
-	{
-		HAL_VCAP_YUV_1440_576p_50_RH, HAL_VCAP_MODE_PRO,
-		HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_POS,
-		HAL_VCAP_YUV, 54.000, 25, 1728, 264, 1704, 6, 23, 0, 5, 0,
-		128, 0, 0, 0,	0, 0, 0
-	},
-	{
-		HAL_VCAP_YUV_2880_576p_50_FL, HAL_VCAP_MODE_PRO,
-		HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_POS,
-		HAL_VCAP_YUV, 108.000, 625, 3456, 528, 3408, 44, 620, 0, 5,
-		0, 256, 0, 0, 0, 0, 0, 0
-	},
-	{
-		HAL_VCAP_YUV_2880_576p_50_RH, HAL_VCAP_MODE_PRO,
-		HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_POS,
-		HAL_VCAP_YUV, 108.000, 25, 3456, 528, 3408, 6, 23, 0, 5, 0,
-		256, 0, 0, 0, 0, 0, 0
-	},
-		/* 576i */
-	{
-		HAL_VCAP_YUV_576i_50_FL, HAL_VCAP_MODE_INT, HAL_VCAP_POLAR_NEG,
-		HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 27.0,
-		625, 1728, 264, 1704, 22, 310, 0, 3, 0, 126, 335, 623, 864,
-		864, 313, 316
-	},
-	{
-		HAL_VCAP_YUV_576i_50_RW, HAL_VCAP_MODE_INT, HAL_VCAP_POLAR_NEG,
-		HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 27.0,
-		625, 172, 26, 170, 22, 310, 0, 3, 0, 13, 335, 623, 86,
-		86, 313, 316
-	},
-	{
-		HAL_VCAP_YUV_576i_50_RH, HAL_VCAP_MODE_INT, HAL_VCAP_POLAR_NEG,
-		HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 27.0,
-		29, 1728, 264, 1704, 3, 13, 0, 1, 0, 126, 16, 26, 864, 864,
-		14, 15
-	},
-		/* XGA 1024x768 */
-	{
-		HAL_VCAP_YUV_XGA_FL, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
-		HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 63.5,
-		798, 1328, 256, 1280, 27, 795, 0, 4, 0, 104, 0, 0, 0,
-		0, 0, 0
-	},
-	{
-		HAL_VCAP_YUV_XGA_RH, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
-		HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 63.5,
-		12, 1328, 256, 1280, 6, 10, 0, 4, 0, 104, 0, 0, 0, 0,
-		0, 0
-	},
-	{
-		HAL_VCAP_YUV_XGA_RB, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
-		HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 63.5,
-		12, 1216, 112, 1136, 6, 10, 0, 4, 0, 32, 0, 0, 0, 0,
-		0, 0
-	},
-		/* SXGA 1280x1024 */
-	{
-		HAL_VCAP_YUV_SXGA_FL, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_NEG,
-		HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 109.0,
-		1063, 1712, 352, 1632, 36, 1060, 0, 7, 0, 136, 0, 0, 0,
-		0, 0, 0
-	},
-	{
-		HAL_VCAP_RGB_SXGA_FL, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_NEG,
-		HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_RGB, 109.0,
-		1063, 1712, 352, 1632, 36, 1060, 0, 7, 0, 136, 0, 0, 0,
-		0, 0, 0
-	},
-	{
-		HAL_VCAP_YUV_SXGA_RH, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_NEG,
-		HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 109.0,
-		17, 1712, 352, 1632, 8, 15, 0, 7, 0, 136, 0, 0, 0,
-		0, 0, 0
-	},
-	{
-		HAL_VCAP_YUV_SXGA_RB, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_NEG,
-		HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 109.0,
-		17, 1440, 112, 1392, 8, 15, 0, 7, 0, 32, 0, 0, 0, 0,
-		0, 0
-	},
-		/* UXGA 1600x1200 */
-	{
-		HAL_VCAP_YUV_UXGA_FL, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_NEG,
-		HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 161.0,
-		1245, 2160, 448, 2048, 42, 1242, 0, 4, 0, 168, 0,
-		0, 0, 0, 0, 0
-	},
-	{
-		HAL_VCAP_RGB_UXGA_FL, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_NEG,
-		HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_RGB, 161.0,
-		1245, 2160, 448, 2048, 42, 1242, 0, 4, 0, 168, 0,
-		0, 0, 0, 0, 0
-	},
-	{
-		HAL_VCAP_YUV_UXGA_RH, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_NEG,
-		HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 161.0,
-		12, 2160, 448, 2048, 6, 10, 0, 4, 0, 168, 0, 0, 0,
-		0, 0, 0
-	},
-	{
-		HAL_VCAP_YUV_UXGA_RB, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_NEG,
-		HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 161.0,
-		12, 1808, 112, 1712, 6, 10, 0, 4, 0, 32, 0, 0, 0, 0,
-		0, 0
-	},
-		/* test odd height */
-	{
-		HAL_VCAP_ODD_HEIGHT, HAL_VCAP_MODE_INT, HAL_VCAP_POLAR_POS,
-		HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_NEG, HAL_VCAP_YUV, 148.5,
-		65, 1728, 264, 1704, 5, 20, 0, 3, 0, 126, 25, 40, 864,
-		864, 21, 24
-	},
-		/* test odd width RGB only */
-	{
-		HAL_VCAP_ODD_WIDTH, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
-		HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_NEG, HAL_VCAP_RGB, 148.5,
-		52, 859, 122, 843, 3, 50, 0, 2, 0, 62, 0, 0, 0, 0, 0, 0
-	},
-};
-
 void config_buffer(struct vcap_client_data *c_data,
 			struct vcap_buffer *buf,
 			void __iomem *y_addr,
@@ -446,6 +51,61 @@
 	}
 }
 
+static void mov_buf_to_vp(struct work_struct *work)
+{
+	struct vp_work_t *vp_work = container_of(work, struct vp_work_t, work);
+	struct v4l2_buffer p;
+	struct vb2_buffer *vb_vc;
+	struct vcap_buffer *buf_vc;
+	struct vb2_buffer *vb_vp;
+	struct vcap_buffer *buf_vp;
+
+	int rc;
+	p.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	p.memory = V4L2_MEMORY_USERPTR;
+	while (1) {
+		if (!vp_work->cd->streaming)
+			return;
+		rc = vb2_dqbuf(&vp_work->cd->vc_vidq, &p, O_NONBLOCK);
+		if (rc < 0)
+			return;
+
+		vb_vc = vp_work->cd->vc_vidq.bufs[p.index];
+		if (NULL == vb_vc) {
+			dprintk(1, "%s: buffer is NULL\n", __func__);
+			vb2_qbuf(&vp_work->cd->vc_vidq, &p);
+			return;
+		}
+		buf_vc = container_of(vb_vc, struct vcap_buffer, vb);
+
+		vb_vp = vp_work->cd->vp_in_vidq.bufs[p.index];
+		if (NULL == vb_vp) {
+			dprintk(1, "%s: buffer is NULL\n", __func__);
+			vb2_qbuf(&vp_work->cd->vc_vidq, &p);
+			return;
+		}
+		buf_vp = container_of(vb_vp, struct vcap_buffer, vb);
+		buf_vp->ion_handle = buf_vc->ion_handle;
+		buf_vp->paddr = buf_vc->paddr;
+		buf_vc->ion_handle = NULL;
+		buf_vc->paddr = 0;
+
+		p.type = V4L2_BUF_TYPE_INTERLACED_IN_DECODER;
+
+		/* This call should not fail */
+		rc = vb2_qbuf(&vp_work->cd->vp_in_vidq, &p);
+		if (rc < 0) {
+			pr_err("%s: qbuf to vp_in failed\n", __func__);
+			buf_vc->ion_handle = buf_vp->ion_handle;
+			buf_vc->paddr = buf_vp->paddr;
+			buf_vp->ion_handle = NULL;
+			buf_vp->paddr = 0;
+			p.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+			vb2_qbuf(&vp_work->cd->vc_vidq, &p);
+		}
+	}
+}
+
 irqreturn_t vc_handler(struct vcap_dev *dev)
 {
 	uint32_t irq, timestamp;
@@ -454,6 +114,7 @@
 	struct vb2_buffer *vb = NULL;
 	struct vcap_client_data *c_data;
 
+
 	irq = readl_relaxed(VCAP_VC_INT_STATUS);
 
 	dprintk(1, "%s: irq=0x%08x\n", __func__, irq);
@@ -545,6 +206,10 @@
 		dev->vc_client->vid_vc_action.buf_ind = VC_BUF1;
 		irq = VC_BUF2;
 	}
+
+	if (c_data->op_mode == VC_AND_VP_VCAP_OP)
+		queue_work(dev->vcap_wq, &dev->vc_to_vp_work.work);
+
 	writel_relaxed(irq, VCAP_VC_INT_CLEAR);
 
 	return IRQ_HANDLED;
@@ -604,11 +269,11 @@
 			VCAP_VC_C_ADDR_2);
 
 	rc = readl_relaxed(VCAP_VC_CTRL);
-	writel_relaxed(rc | 0x1, VCAP_VC_CTRL);
+	writel_iowmb(rc | 0x1, VCAP_VC_CTRL);
 
 	writel_relaxed(0x6, VCAP_VC_INT_MASK);
 
-	enable_irq(dev->vcapirq->start);
+	enable_irq(dev->vcirq->start);
 	return 0;
 }
 
@@ -618,9 +283,12 @@
 	int rc;
 
 	rc = readl_relaxed(VCAP_VC_CTRL);
-	writel_relaxed(rc & ~(0x1), VCAP_VC_CTRL);
+	writel_iowmb(rc & ~(0x1), VCAP_VC_CTRL);
 
-	disable_irq(c_data->dev->vcapirq->start);
+	if (atomic_read(&dev->vc_enabled) == 1)
+		disable_irq(dev->vcirq->start);
+
+	flush_workqueue(dev->vcap_wq);
 }
 
 int config_vc_format(struct vcap_client_data *c_data)
@@ -646,14 +314,16 @@
 	}
 	writel_relaxed(0x00000000, VCAP_SW_RESET_REQ);
 
-	writel_relaxed(0x00000102, VCAP_VC_NPL_CTRL);
+	writel_iowmb(0x00000102, VCAP_VC_NPL_CTRL);
 	rc = readl_relaxed(VCAP_VC_NPL_CTRL);
 	rc = readl_relaxed(VCAP_VC_NPL_CTRL);
-	writel_relaxed(0x00000002, VCAP_VC_NPL_CTRL);
+	writel_iowmb(0x00000002, VCAP_VC_NPL_CTRL);
 
 	dprintk(2, "%s: Starting VC configuration\n", __func__);
-	writel_relaxed(0x00000002, VCAP_VC_NPL_CTRL);
-	writel_relaxed(0x00000004 | vc_format->color_space << 1, VCAP_VC_CTRL);
+	writel_iowmb(0x00000002, VCAP_VC_NPL_CTRL);
+	writel_iowmb(0x00000004 | vc_format->color_space << 1 |
+			vc_format->mode << 3 |
+			vc_format->mode << 10, VCAP_VC_CTRL);
 
 	writel_relaxed(vc_format->h_polar << 4 |
 			vc_format->v_polar << 0, VCAP_VC_POLARITY);
@@ -677,7 +347,7 @@
 			vc_format->hsync_start), VCAP_VC_HSYNC_HPOS);
 	writel_relaxed(((vc_format->f2_vsync_h_end << 16) |
 			vc_format->f2_vsync_h_start), VCAP_VC_VSYNC_F2_HPOS);
-	writel_relaxed(0x000033FF, VCAP_VC_BUF_CTRL);
+	writel_iowmb(0x000033FF, VCAP_VC_BUF_CTRL);
 
 	rc = vc_format->hactive_end - vc_format->hactive_start;
 	if (vc_format->color_space)
@@ -694,6 +364,7 @@
 	writel_relaxed(0x2f6ad272, VCAP_VC_IN_CTRL4);
 	writel_relaxed(0x00006b38, VCAP_VC_IN_CTRL5);
 
+	writel_iowmb(0x00000001 , VCAP_OFFSET(0x0d00));
 	dprintk(2, "%s: Done VC configuration\n", __func__);
 
 	return 0;
@@ -706,6 +377,7 @@
 	dprintk(1, "Hardware version: %08x\n", result);
 	if (result != VCAP_HARDWARE_VERSION)
 		return -ENODEV;
+	INIT_WORK(&dev->vc_to_vp_work.work, mov_buf_to_vp);
 	return 0;
 }
 
diff --git a/drivers/media/video/vcap_vc.h b/drivers/media/video/vcap_vc.h
index e431038..57d13cd 100644
--- a/drivers/media/video/vcap_vc.h
+++ b/drivers/media/video/vcap_vc.h
@@ -13,11 +13,9 @@
 #ifndef VCAP_VC_H
 #define VCAP_VC_H
 
-/* #define NEW_S_FMT */
 #include <linux/interrupt.h>
 
 #include <media/vcap_v4l2.h>
-extern struct v4l2_format_vc_ext vcap_vc_lut[];
 
 #define VCAP_HARDWARE_VERSION 0x10000000
 
diff --git a/drivers/media/video/vcap_vp.c b/drivers/media/video/vcap_vp.c
new file mode 100644
index 0000000..f8dfdc1
--- /dev/null
+++ b/drivers/media/video/vcap_vp.c
@@ -0,0 +1,606 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <mach/camera.h>
+#include <linux/io.h>
+#include <mach/clk.h>
+#include <linux/clk.h>
+
+#include <media/vcap_v4l2.h>
+#include <media/vcap_fmt.h>
+#include "vcap_vp.h"
+
+static unsigned debug;
+
+#define dprintk(level, fmt, arg...)					\
+	do {								\
+		if (debug >= level)					\
+			printk(KERN_DEBUG "VP: " fmt, ## arg);		\
+	} while (0)
+
+void config_nr_buffer(struct vcap_client_data *c_data,
+			struct vcap_buffer *buf)
+{
+	struct vcap_dev *dev = c_data->dev;
+	int size = c_data->vp_in_fmt.height * c_data->vp_in_fmt.width;
+
+	writel_relaxed(buf->paddr, VCAP_VP_NR_T2_Y_BASE_ADDR);
+	writel_relaxed(buf->paddr + size, VCAP_VP_NR_T2_C_BASE_ADDR);
+}
+
+void config_in_buffer(struct vcap_client_data *c_data,
+			struct vcap_buffer *buf)
+{
+	struct vcap_dev *dev = c_data->dev;
+	int size = c_data->vp_in_fmt.height * c_data->vp_in_fmt.width;
+
+	writel_relaxed(buf->paddr, VCAP_VP_T2_Y_BASE_ADDR);
+	writel_relaxed(buf->paddr + size, VCAP_VP_T2_C_BASE_ADDR);
+}
+
+void config_out_buffer(struct vcap_client_data *c_data,
+			struct vcap_buffer *buf)
+{
+	struct vcap_dev *dev = c_data->dev;
+	int size;
+	size = c_data->vp_out_fmt.height * c_data->vp_out_fmt.width;
+	writel_relaxed(buf->paddr, VCAP_VP_OUT_Y_BASE_ADDR);
+	writel_relaxed(buf->paddr + size, VCAP_VP_OUT_C_BASE_ADDR);
+}
+
+int vp_setup_buffers(struct vcap_client_data *c_data)
+{
+	struct vp_action *vp_act;
+	struct vcap_dev *dev;
+	unsigned long flags = 0;
+
+	if (!c_data->streaming)
+		return -ENOEXEC;
+	dev = c_data->dev;
+	dprintk(2, "Start setup buffers\n");
+
+	/* No need to verify vp_client is not NULL caller does so */
+	vp_act = &dev->vp_client->vid_vp_action;
+
+	spin_lock_irqsave(&dev->vp_client->cap_slock, flags);
+	if (list_empty(&vp_act->in_active)) {
+		spin_unlock_irqrestore(&dev->vp_client->cap_slock, flags);
+		dprintk(1, "%s: VP We have no more input buffers\n",
+				__func__);
+		return -EAGAIN;
+	}
+
+	if (list_empty(&vp_act->out_active)) {
+		spin_unlock_irqrestore(&dev->vp_client->cap_slock,
+			flags);
+		dprintk(1, "%s: VP We have no more output buffers\n",
+		   __func__);
+		return -EAGAIN;
+	}
+
+	vp_act->bufT2 = list_entry(vp_act->in_active.next,
+			struct vcap_buffer, list);
+	list_del(&vp_act->bufT2->list);
+
+	vp_act->bufOut = list_entry(vp_act->out_active.next,
+			struct vcap_buffer, list);
+	list_del(&vp_act->bufOut->list);
+	spin_unlock_irqrestore(&dev->vp_client->cap_slock, flags);
+
+	config_in_buffer(c_data, vp_act->bufT2);
+	config_out_buffer(c_data, vp_act->bufOut);
+	return 0;
+}
+
+static void mov_buf_to_vc(struct work_struct *work)
+{
+	struct vp_work_t *vp_work = container_of(work, struct vp_work_t, work);
+	struct v4l2_buffer p;
+	struct vb2_buffer *vb_vc;
+	struct vcap_buffer *buf_vc;
+	struct vb2_buffer *vb_vp;
+	struct vcap_buffer *buf_vp;
+	int rc;
+
+	p.type = V4L2_BUF_TYPE_INTERLACED_IN_DECODER;
+	p.memory = V4L2_MEMORY_USERPTR;
+
+	/* This loop exits when there is no more buffers left */
+	while (1) {
+		if (!vp_work->cd->streaming)
+			return;
+		rc = vb2_dqbuf(&vp_work->cd->vp_in_vidq, &p, O_NONBLOCK);
+		if (rc < 0)
+			return;
+
+		vb_vc = vp_work->cd->vc_vidq.bufs[p.index];
+		if (NULL == vb_vc) {
+			dprintk(1, "%s: buffer is NULL\n", __func__);
+			vb2_qbuf(&vp_work->cd->vp_in_vidq, &p);
+			return;
+		}
+		buf_vc = container_of(vb_vc, struct vcap_buffer, vb);
+
+		vb_vp = vp_work->cd->vp_in_vidq.bufs[p.index];
+		if (NULL == vb_vp) {
+			dprintk(1, "%s: buffer is NULL\n", __func__);
+			vb2_qbuf(&vp_work->cd->vp_in_vidq, &p);
+			return;
+		}
+		buf_vp = container_of(vb_vp, struct vcap_buffer, vb);
+		buf_vc->ion_handle = buf_vp->ion_handle;
+		buf_vc->paddr = buf_vp->paddr;
+		buf_vp->ion_handle = NULL;
+		buf_vp->paddr = 0;
+
+		p.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		/* This call should not fail */
+		rc = vb2_qbuf(&vp_work->cd->vc_vidq, &p);
+		if (rc < 0) {
+			dprintk(1, "%s: qbuf to vc failed\n", __func__);
+			buf_vp->ion_handle = buf_vc->ion_handle;
+			buf_vp->paddr = buf_vc->paddr;
+			buf_vc->ion_handle = NULL;
+			buf_vc->paddr = 0;
+			p.type = V4L2_BUF_TYPE_INTERLACED_IN_DECODER;
+			vb2_qbuf(&vp_work->cd->vp_in_vidq, &p);
+		}
+	}
+}
+
+static void vp_wq_fnc(struct work_struct *work)
+{
+	struct vp_work_t *vp_work = container_of(work, struct vp_work_t, work);
+	struct vcap_dev *dev;
+	struct vp_action *vp_act;
+	uint32_t irq;
+	int rc;
+#ifndef TOP_FIELD_FIX
+	bool top_field;
+#endif
+
+	if (vp_work && vp_work->cd && vp_work->cd->dev)
+		dev = vp_work->cd->dev;
+	else
+		return;
+
+	vp_act = &dev->vp_client->vid_vp_action;
+	irq = vp_work->irq;
+
+	rc = readl_relaxed(VCAP_OFFSET(0x048));
+	while (!(rc & 0x00000100))
+		rc = readl_relaxed(VCAP_OFFSET(0x048));
+
+	writel_relaxed(0x00000000, VCAP_VP_BAL_VMOTION_STATE);
+	writel_relaxed(0x40000000, VCAP_VP_REDUCT_AVG_MOTION2);
+
+	/* Queue the done buffers */
+	if (vp_act->vp_state == VP_NORMAL &&
+			vp_act->bufNR.nr_pos != TM1_BUF) {
+		vb2_buffer_done(&vp_act->bufTm1->vb, VB2_BUF_STATE_DONE);
+		if (vp_work->cd->op_mode == VC_AND_VP_VCAP_OP)
+			queue_work(dev->vcap_wq, &dev->vp_to_vc_work.work);
+	}
+
+	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 (vp_work->cd->vid_vp_action.nr_enabled) {
+		if (vp_act->bufNR.nr_pos == TM1_BUF)
+			vp_act->bufNR.nr_pos = BUF_NOT_IN_USE;
+
+		if (vp_act->bufNR.nr_pos != BUF_NOT_IN_USE)
+			vp_act->bufNR.nr_pos++;
+
+		vp_act->bufTm1 = vp_act->bufT0;
+		vp_act->bufT0 = vp_act->bufT1;
+		vp_act->bufT1 = vp_act->bufNRT2;
+		vp_act->bufNRT2 = vp_act->bufT2;
+		config_nr_buffer(vp_work->cd, vp_act->bufNRT2);
+	} else {
+		vp_act->bufTm1 = vp_act->bufT0;
+		vp_act->bufT0 = vp_act->bufT1;
+		vp_act->bufT1 = vp_act->bufT2;
+	}
+
+	rc = vp_setup_buffers(vp_work->cd);
+	if (rc < 0) {
+		/* setup_buf failed because we are waiting for buffers */
+		writel_relaxed(0x00000000, VCAP_VP_INTERRUPT_ENABLE);
+		writel_iowmb(irq, VCAP_VP_INT_CLEAR);
+		atomic_set(&dev->vp_enabled, 0);
+		return;
+	}
+
+	/* 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(0x00030000 | vp_act->top_field << 0, VCAP_VP_CTRL);
+#else
+	writel_iowmb(0x00000000 | top_field, VCAP_VP_CTRL);
+	writel_iowmb(0x00030000 | top_field, VCAP_VP_CTRL);
+#endif
+	enable_irq(dev->vpirq->start);
+	writel_iowmb(irq, VCAP_VP_INT_CLEAR);
+}
+
+irqreturn_t vp_handler(struct vcap_dev *dev)
+{
+	struct vcap_client_data *c_data;
+	struct vp_action *vp_act;
+	uint32_t irq;
+	int rc;
+
+	irq = readl_relaxed(VCAP_VP_INT_STATUS);
+
+	dprintk(1, "%s: irq=0x%08x\n", __func__, irq);
+	if (!irq & VP_PIC_DONE) {
+		writel_relaxed(irq, VCAP_VP_INT_CLEAR);
+		pr_err("VP IRQ shows some error\n");
+		return IRQ_HANDLED;
+	}
+
+	if (dev->vp_client == NULL) {
+		writel_relaxed(irq, VCAP_VP_INT_CLEAR);
+		pr_err("VC: There is no active vp client\n");
+		return IRQ_HANDLED;
+	}
+
+	vp_act = &dev->vp_client->vid_vp_action;
+	c_data = dev->vp_client;
+
+	if (vp_act->vp_state == VP_UNKNOWN) {
+		writel_relaxed(irq, VCAP_VP_INT_CLEAR);
+		pr_err("%s: VP is in an unknown state\n",
+				__func__);
+		return -EAGAIN;
+	}
+
+	INIT_WORK(&dev->vp_work.work, vp_wq_fnc);
+	dev->vp_work.cd = c_data;
+	dev->vp_work.irq = irq;
+	rc = queue_work(dev->vcap_wq, &dev->vp_work.work);
+
+	disable_irq_nosync(dev->vpirq->start);
+	return IRQ_HANDLED;
+}
+
+void vp_stop_capture(struct vcap_client_data *c_data)
+{
+	struct vcap_dev *dev = c_data->dev;
+
+	writel_iowmb(0x00000000, VCAP_VP_CTRL);
+	flush_workqueue(dev->vcap_wq);
+
+	if (atomic_read(&dev->vp_enabled) == 1)
+		disable_irq(dev->vpirq->start);
+
+	writel_iowmb(0x00000001, VCAP_VP_SW_RESET);
+	writel_iowmb(0x00000000, VCAP_VP_SW_RESET);
+}
+
+int config_vp_format(struct vcap_client_data *c_data)
+{
+	struct vcap_dev *dev = c_data->dev;
+
+	INIT_WORK(&dev->vp_to_vc_work.work, mov_buf_to_vc);
+	dev->vp_to_vc_work.cd = c_data;
+
+	/* SW restart VP */
+	writel_iowmb(0x00000001, VCAP_VP_SW_RESET);
+	writel_iowmb(0x00000000, VCAP_VP_SW_RESET);
+
+	/* Film Mode related settings */
+	writel_iowmb(0x00000000, VCAP_VP_FILM_PROJECTION_T0);
+	writel_relaxed(0x00000000, VCAP_VP_FILM_PROJECTION_T2);
+	writel_relaxed(0x00000000, VCAP_VP_FILM_PAST_MAX_PROJ);
+	writel_relaxed(0x00000000, VCAP_VP_FILM_PAST_MIN_PROJ);
+	writel_relaxed(0x00000000, VCAP_VP_FILM_SEQUENCE_HIST);
+	writel_relaxed(0x00000000, VCAP_VP_FILM_MODE_STATE);
+
+	writel_relaxed(0x00000000, VCAP_VP_BAL_VMOTION_STATE);
+	writel_relaxed(0x00000010, VCAP_VP_REDUCT_AVG_MOTION);
+	writel_relaxed(0x40000000, VCAP_VP_REDUCT_AVG_MOTION2);
+	writel_relaxed(0x40000000, VCAP_VP_NR_AVG_LUMA);
+	writel_relaxed(0x40000000, VCAP_VP_NR_AVG_CHROMA);
+	writel_relaxed(0x40000000, VCAP_VP_NR_CTRL_LUMA);
+	writel_relaxed(0x40000000, VCAP_VP_NR_CTRL_CHROMA);
+	writel_relaxed(0x00000000, VCAP_VP_BAL_AVG_BLEND);
+	writel_relaxed(0x00000000, VCAP_VP_VMOTION_HIST);
+	writel_relaxed(0x05047D19, VCAP_VP_FILM_ANALYSIS_CONFIG);
+	writel_relaxed(0x20260200, VCAP_VP_FILM_STATE_CONFIG);
+	writel_relaxed(0x23A60114, VCAP_VP_FVM_CONFIG);
+	writel_relaxed(0x03043210, VCAP_VP_FILM_ANALYSIS_CONFIG2);
+	writel_relaxed(0x04DB7A51, VCAP_VP_MIXED_ANALYSIS_CONFIG);
+	writel_relaxed(0x14224916, VCAP_VP_SPATIAL_CONFIG);
+	writel_relaxed(0x83270400, VCAP_VP_SPATIAL_CONFIG2);
+	writel_relaxed(0x0F000F92, VCAP_VP_SPATIAL_CONFIG3);
+	writel_relaxed(0x00000000, VCAP_VP_TEMPORAL_CONFIG);
+	writel_relaxed(0x00000000, VCAP_VP_PIXEL_DIFF_CONFIG);
+	writel_relaxed(0x0C090511, VCAP_VP_H_FREQ_CONFIG);
+	writel_relaxed(0x0A000000, VCAP_VP_NR_CONFIG);
+	writel_relaxed(0x008F4149, VCAP_VP_NR_LUMA_CONFIG);
+	writel_relaxed(0x008F4149, VCAP_VP_NR_CHROMA_CONFIG);
+	writel_relaxed(0x43C0FD0C, VCAP_VP_BAL_CONFIG);
+	writel_relaxed(0x00000255, VCAP_VP_BAL_MOTION_CONFIG);
+	writel_relaxed(0x24154252, VCAP_VP_BAL_LIGHT_COMB);
+	writel_relaxed(0x10024414, VCAP_VP_BAL_VMOTION_CONFIG);
+	writel_relaxed(0x00000002, VCAP_VP_NR_CONFIG2);
+	writel_relaxed((c_data->vp_out_fmt.height-1)<<16 |
+			(c_data->vp_out_fmt.width - 1), VCAP_VP_FRAME_SIZE);
+	writel_relaxed(0x00000000, VCAP_VP_SPLIT_SCRN_CTRL);
+
+	return 0;
+}
+
+int init_motion_buf(struct vcap_client_data *c_data)
+{
+	struct vcap_dev *dev = c_data->dev;
+	void *buf;
+	unsigned long motion_base_addr;
+	uint32_t size = ((c_data->vp_out_fmt.width + 63) >> 6) *
+		((c_data->vp_out_fmt.height + 7) >> 3) * 16;
+
+	if (c_data->vid_vp_action.bufMotion) {
+		pr_err("Motion buffer has already been created");
+		return -ENOEXEC;
+	}
+
+	buf = kzalloc(size, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	c_data->vid_vp_action.bufMotion = buf;
+	motion_base_addr = virt_to_phys(buf);
+	writel_iowmb(motion_base_addr, VCAP_VP_MOTION_EST_ADDR);
+	return 0;
+}
+
+void deinit_motion_buf(struct vcap_client_data *c_data)
+{
+	struct vcap_dev *dev = c_data->dev;
+	void *buf;
+
+	if (!c_data->vid_vp_action.bufMotion) {
+		dprintk(1, "Motion buffer has not been created");
+		return;
+	}
+
+	buf = c_data->vid_vp_action.bufMotion;
+
+	writel_iowmb(0x00000000, VCAP_VP_MOTION_EST_ADDR);
+	c_data->vid_vp_action.bufMotion = NULL;
+	kfree(buf);
+	return;
+}
+
+int init_nr_buf(struct vcap_client_data *c_data)
+{
+	struct vcap_dev *dev = c_data->dev;
+	struct nr_buffer *buf;
+	uint32_t frame_size, tot_size, rc;
+
+	if (c_data->vid_vp_action.bufNR.vaddr) {
+		pr_err("NR buffer has already been created");
+		return -ENOEXEC;
+	}
+	buf = &c_data->vid_vp_action.bufNR;
+
+	frame_size = c_data->vp_in_fmt.width * c_data->vp_in_fmt.height;
+	if (c_data->vp_in_fmt.pixfmt == V4L2_PIX_FMT_NV16)
+		tot_size = frame_size * 2;
+	else
+		tot_size = frame_size / 2 * 3;
+
+	buf->vaddr = kzalloc(tot_size, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	buf->paddr = virt_to_phys(buf->vaddr);
+	rc = readl_relaxed(VCAP_VP_NR_CONFIG2);
+	rc |= 0x02D00001;
+	writel_relaxed(rc, VCAP_VP_NR_CONFIG2);
+	writel_relaxed(buf->paddr, VCAP_VP_NR_T2_Y_BASE_ADDR);
+	writel_relaxed(buf->paddr + frame_size, VCAP_VP_NR_T2_C_BASE_ADDR);
+	buf->nr_pos = NRT2_BUF;
+	return 0;
+}
+
+void deinit_nr_buf(struct vcap_client_data *c_data)
+{
+	struct vcap_dev *dev = c_data->dev;
+	struct nr_buffer *buf;
+	uint32_t rc;
+
+	if (!c_data->vid_vp_action.bufNR.vaddr) {
+		pr_err("NR buffer has not been created");
+		return;
+	}
+
+	buf = &c_data->vid_vp_action.bufNR;
+
+	rc = readl_relaxed(VCAP_VP_NR_CONFIG2);
+	rc &= !(0x02D00001);
+	writel_relaxed(rc, VCAP_VP_NR_CONFIG2);
+
+	kfree(buf->vaddr);
+	buf->paddr = 0;
+	buf->vaddr = NULL;
+	return;
+}
+
+int kickoff_vp(struct vcap_client_data *c_data)
+{
+	struct vcap_dev *dev;
+	struct vp_action *vp_act;
+	unsigned long flags = 0;
+	unsigned int chroma_fmt = 0;
+	int size;
+#ifndef TOP_FIELD_FIX
+	bool top_field;
+#endif
+
+	if (!c_data->streaming)
+		return -ENOEXEC;
+
+	dev = c_data->dev;
+	dprintk(2, "Start Kickoff\n");
+
+	if (dev->vp_client == NULL) {
+		pr_err("No active vp client\n");
+		return -ENODEV;
+	}
+	vp_act = &dev->vp_client->vid_vp_action;
+
+	spin_lock_irqsave(&dev->vp_client->cap_slock, flags);
+	if (list_empty(&vp_act->in_active)) {
+		spin_unlock_irqrestore(&dev->vp_client->cap_slock, flags);
+		pr_err("%s: VP We have no more input buffers\n",
+				__func__);
+		return -EAGAIN;
+	}
+
+	vp_act->bufT1 = list_entry(vp_act->in_active.next,
+			struct vcap_buffer, list);
+	list_del(&vp_act->bufT1->list);
+
+	if (list_empty(&vp_act->in_active)) {
+		spin_unlock_irqrestore(&dev->vp_client->cap_slock, flags);
+		list_add(&vp_act->bufT1->list, &vp_act->in_active);
+		pr_err("%s: VP We have no more input buffers\n",
+				__func__);
+		return -EAGAIN;
+	}
+
+	vp_act->bufT2 = list_entry(vp_act->in_active.next,
+			struct vcap_buffer, list);
+	list_del(&vp_act->bufT2->list);
+
+	if (list_empty(&vp_act->out_active)) {
+		spin_unlock_irqrestore(&dev->vp_client->cap_slock, flags);
+		list_add(&vp_act->bufT2->list, &vp_act->in_active);
+		list_add(&vp_act->bufT1->list, &vp_act->in_active);
+		pr_err("%s: VP We have no more output buffers\n",
+				__func__);
+		return -EAGAIN;
+	}
+
+	vp_act->bufOut = list_entry(vp_act->out_active.next,
+			struct vcap_buffer, list);
+	list_del(&vp_act->bufOut->list);
+	spin_unlock_irqrestore(&dev->vp_client->cap_slock, flags);
+
+	size = c_data->vp_in_fmt.height * c_data->vp_in_fmt.width;
+	writel_relaxed(vp_act->bufT1->paddr, VCAP_VP_T1_Y_BASE_ADDR);
+	writel_relaxed(vp_act->bufT1->paddr + size, VCAP_VP_T1_C_BASE_ADDR);
+
+	config_in_buffer(c_data, vp_act->bufT2);
+	config_out_buffer(c_data, vp_act->bufOut);
+
+	/* Config VP */
+	if (c_data->vp_in_fmt.pixfmt == V4L2_PIX_FMT_NV16)
+		chroma_fmt = 1;
+	writel_relaxed((c_data->vp_in_fmt.width / 16) << 20 |
+			chroma_fmt << 11 | 0x2 << 4, VCAP_VP_IN_CONFIG);
+
+	chroma_fmt = 0;
+	if (c_data->vp_in_fmt.pixfmt == V4L2_PIX_FMT_NV16)
+		chroma_fmt = 1;
+
+	writel_relaxed((c_data->vp_in_fmt.width / 16) << 20 |
+			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(0x01100101, VCAP_VP_INTERRUPT_ENABLE);
+#ifdef TOP_FIELD_FIX
+	writel_iowmb(0x00000000 | vp_act->top_field << 0, VCAP_VP_CTRL);
+	writel_iowmb(0x00030000 | vp_act->top_field << 0, VCAP_VP_CTRL);
+#else
+	writel_iowmb(0x00000000 | top_field, VCAP_VP_CTRL);
+	writel_iowmb(0x00030000 | top_field, VCAP_VP_CTRL);
+#endif
+	atomic_set(&c_data->dev->vp_enabled, 1);
+	enable_irq(dev->vpirq->start);
+	return 0;
+}
+
+int continue_vp(struct vcap_client_data *c_data)
+{
+	struct vcap_dev *dev;
+	struct vp_action *vp_act;
+	int rc;
+#ifndef TOP_FIELD_FIX
+	bool top_field;
+#endif
+
+	dprintk(2, "Start Continue\n");
+	dev = c_data->dev;
+
+	if (dev->vp_client == NULL) {
+		pr_err("No active vp client\n");
+		return -ENODEV;
+	}
+	vp_act = &dev->vp_client->vid_vp_action;
+
+	if (vp_act->vp_state == VP_UNKNOWN) {
+		pr_err("%s: VP is in an unknown state\n",
+				__func__);
+		return -EAGAIN;
+	}
+
+	rc = vp_setup_buffers(c_data);
+	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(0x01100101, VCAP_VP_INTERRUPT_ENABLE);
+#ifdef TOP_FIELD_FIX
+	writel_iowmb(0x00000000 | vp_act->top_field << 0, VCAP_VP_CTRL);
+	writel_iowmb(0x00030000 | vp_act->top_field << 0, VCAP_VP_CTRL);
+#else
+	writel_iowmb(0x00000000 | top_field, VCAP_VP_CTRL);
+	writel_iowmb(0x00030000 | top_field, VCAP_VP_CTRL);
+#endif
+
+	atomic_set(&c_data->dev->vp_enabled, 1);
+	enable_irq(dev->vpirq->start);
+	return 0;
+}
diff --git a/drivers/media/video/vcap_vp.h b/drivers/media/video/vcap_vp.h
new file mode 100644
index 0000000..47ad8d4
--- /dev/null
+++ b/drivers/media/video/vcap_vp.h
@@ -0,0 +1,103 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef VCAP_VP_H
+#define VCAP_VP_H
+
+#include <linux/interrupt.h>
+
+#include <media/vcap_v4l2.h>
+
+#define VCAP_BASE (dev->vcapbase)
+#define VCAP_OFFSET(off) (VCAP_BASE + off)
+
+#define VCAP_VP_INT_STATUS (VCAP_BASE + 0x404)
+#define VCAP_VP_INT_CLEAR (VCAP_BASE + 0x40C)
+
+#define VCAP_VP_SW_RESET (VCAP_BASE + 0x410)
+#define VCAP_VP_INTERRUPT_ENABLE (VCAP_BASE + 0x408)
+
+#define VCAP_VP_FILM_PROJECTION_T0 (VCAP_BASE + 0x50C)
+#define VCAP_VP_FILM_PROJECTION_T2 (VCAP_BASE + 0x508)
+#define VCAP_VP_FILM_PAST_MAX_PROJ (VCAP_BASE + 0x510)
+#define VCAP_VP_FILM_PAST_MIN_PROJ (VCAP_BASE + 0x514)
+#define VCAP_VP_FILM_SEQUENCE_HIST (VCAP_BASE + 0x504)
+#define VCAP_VP_FILM_MODE_STATE (VCAP_BASE + 0x500)
+
+#define VCAP_VP_BAL_VMOTION_STATE (VCAP_BASE + 0x690)
+#define VCAP_VP_REDUCT_AVG_MOTION (VCAP_BASE + 0x610)
+#define VCAP_VP_REDUCT_AVG_MOTION2 (VCAP_BASE + 0x614)
+
+#define VCAP_VP_NR_AVG_LUMA (VCAP_BASE + 0x608)
+#define VCAP_VP_NR_AVG_CHROMA (VCAP_BASE + 0x60C)
+#define VCAP_VP_NR_CTRL_LUMA (VCAP_BASE + 0x600)
+#define VCAP_VP_NR_CTRL_CHROMA (VCAP_BASE + 0x604)
+
+#define VCAP_VP_BAL_AVG_BLEND (VCAP_BASE + 0x694)
+#define VCAP_VP_VMOTION_HIST (VCAP_BASE + 0x6F8)
+
+#define VCAP_VP_MOTION_EST_ADDR (VCAP_BASE + 0x4E0)
+#define VCAP_VP_FILM_ANALYSIS_CONFIG (VCAP_BASE + 0x520)
+#define VCAP_VP_FILM_STATE_CONFIG (VCAP_BASE + 0x524)
+
+#define VCAP_VP_FVM_CONFIG (VCAP_BASE + 0x550)
+#define VCAP_VP_FILM_ANALYSIS_CONFIG2 (VCAP_BASE + 0x52C)
+#define VCAP_VP_MIXED_ANALYSIS_CONFIG (VCAP_BASE + 0x530)
+
+#define VCAP_VP_SPATIAL_CONFIG (VCAP_BASE + 0x580)
+#define VCAP_VP_SPATIAL_CONFIG2 (VCAP_BASE + 0x584)
+#define VCAP_VP_SPATIAL_CONFIG3 (VCAP_BASE + 0x588)
+#define VCAP_VP_TEMPORAL_CONFIG (VCAP_BASE + 0x5C0)
+
+#define VCAP_VP_PIXEL_DIFF_CONFIG (VCAP_BASE + 0x6FC)
+#define VCAP_VP_H_FREQ_CONFIG (VCAP_BASE + 0x528)
+#define VCAP_VP_NR_CONFIG (VCAP_BASE + 0x620)
+#define VCAP_VP_NR_LUMA_CONFIG (VCAP_BASE + 0x624)
+#define VCAP_VP_NR_CHROMA_CONFIG (VCAP_BASE + 0x628)
+#define VCAP_VP_BAL_CONFIG (VCAP_BASE + 0x680)
+#define VCAP_VP_BAL_MOTION_CONFIG (VCAP_BASE + 0x684)
+#define VCAP_VP_BAL_LIGHT_COMB (VCAP_BASE + 0x688)
+#define VCAP_VP_BAL_VMOTION_CONFIG (VCAP_BASE + 0x68C)
+
+#define VCAP_VP_NR_CONFIG2 (VCAP_BASE + 0x484)
+#define VCAP_VP_FRAME_SIZE (VCAP_BASE + 0x48C)
+#define VCAP_VP_SPLIT_SCRN_CTRL (VCAP_BASE + 0x750)
+
+#define VCAP_VP_IN_CONFIG (VCAP_BASE + 0x480)
+#define VCAP_VP_OUT_CONFIG (VCAP_BASE + 0x488)
+
+#define VCAP_VP_T2_Y_BASE_ADDR (VCAP_BASE + 0x4C0)
+#define VCAP_VP_T2_C_BASE_ADDR (VCAP_BASE + 0x4C4)
+#define VCAP_VP_OUT_Y_BASE_ADDR (VCAP_BASE + 0x4CC)
+#define VCAP_VP_OUT_C_BASE_ADDR (VCAP_BASE + 0x4D0)
+#define VCAP_VP_OUT_CR_BASE_ADDR (VCAP_BASE + 0x4D4)
+
+#define VCAP_VP_CTRL (VCAP_BASE + 0x4D8)
+
+#define VCAP_VP_T1_Y_BASE_ADDR (VCAP_BASE + 0x4A8)
+#define VCAP_VP_T1_C_BASE_ADDR (VCAP_BASE + 0x4Ac)
+#define VCAP_VP_NR_T2_Y_BASE_ADDR (VCAP_BASE + 0x4B4)
+#define VCAP_VP_NR_T2_C_BASE_ADDR (VCAP_BASE + 0x4B8)
+
+#define VP_PIC_DONE (0x1 << 0)
+
+irqreturn_t vp_handler(struct vcap_dev *dev);
+int config_vp_format(struct vcap_client_data *c_data);
+void vp_stop_capture(struct vcap_client_data *c_data);
+int init_motion_buf(struct vcap_client_data *c_data);
+void deinit_motion_buf(struct vcap_client_data *c_data);
+int init_nr_buf(struct vcap_client_data *c_data);
+void deinit_nr_buf(struct vcap_client_data *c_data);
+int kickoff_vp(struct vcap_client_data *c_data);
+int continue_vp(struct vcap_client_data *c_data);
+
+#endif
diff --git a/drivers/media/video/videobuf2-msm-mem.c b/drivers/media/video/videobuf2-msm-mem.c
index 7782955..186195d 100644
--- a/drivers/media/video/videobuf2-msm-mem.c
+++ b/drivers/media/video/videobuf2-msm-mem.c
@@ -29,8 +29,8 @@
 #include <media/videobuf2-msm-mem.h>
 #include <media/msm_camera.h>
 #include <mach/memory.h>
-#include <mach/msm_subsystem_map.h>
 #include <media/videobuf2-core.h>
+#include <mach/iommu_domains.h>
 
 #define MAGIC_PMEM 0x0733ac64
 #define MAGIC_CHECK(is, should)               \
diff --git a/drivers/mfd/marimba-tsadc.c b/drivers/mfd/marimba-tsadc.c
index 8a7b781..32b93e1 100644
--- a/drivers/mfd/marimba-tsadc.c
+++ b/drivers/mfd/marimba-tsadc.c
@@ -437,7 +437,7 @@
 	struct marimba_tsadc *tsadc = dev_get_drvdata(dev);
 
 	if (tsadc->clk_enabled == true) {
-		clk_disable(tsadc->codec_ssbi);
+		clk_disable_unprepare(tsadc->codec_ssbi);
 		tsadc->clk_enabled = false;
 	}
 
@@ -462,7 +462,7 @@
 	marimba_tsadc_configure(tsadc_dev);
 fail_shutdown:
 	if (tsadc->clk_enabled == false) {
-		ret = clk_enable(tsadc->codec_ssbi);
+		ret = clk_prepare_enable(tsadc->codec_ssbi);
 		if (ret == 0)
 			tsadc->clk_enabled = true;
 	}
@@ -475,7 +475,7 @@
 	struct marimba_tsadc *tsadc = dev_get_drvdata(dev);
 
 	if (tsadc->clk_enabled == false) {
-		rc = clk_enable(tsadc->codec_ssbi);
+		rc = clk_prepare_enable(tsadc->codec_ssbi);
 		if (rc != 0) {
 			pr_err("%s: Clk enable failed\n", __func__);
 			return rc;
@@ -515,7 +515,7 @@
 		tsadc->pdata->marimba_tsadc_power(0);
 fail_tsadc_power:
 	if (tsadc->clk_enabled == true) {
-		clk_disable(tsadc->codec_ssbi);
+		clk_disable_unprepare(tsadc->codec_ssbi);
 		tsadc->clk_enabled = false;
 	}
 	return rc;
@@ -591,7 +591,7 @@
 		rc = PTR_ERR(tsadc->codec_ssbi);
 		goto fail_clk_get;
 	}
-	rc = clk_enable(tsadc->codec_ssbi);
+	rc = clk_prepare_enable(tsadc->codec_ssbi);
 	if (rc != 0)
 		goto fail_clk_enable;
 
@@ -623,7 +623,7 @@
 	return rc;
 
 fail_add_subdev:
-	clk_disable(tsadc->codec_ssbi);
+	clk_disable_unprepare(tsadc->codec_ssbi);
 
 fail_clk_enable:
 	clk_put(tsadc->codec_ssbi);
@@ -647,7 +647,7 @@
 	device_init_wakeup(&pdev->dev, 0);
 
 	if (tsadc->clk_enabled == true)
-		clk_disable(tsadc->codec_ssbi);
+		clk_disable_unprepare(tsadc->codec_ssbi);
 
 	clk_put(tsadc->codec_ssbi);
 
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index 2a25089..e2dff4b 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -41,7 +41,7 @@
 };
 
 struct wcd9xxx_i2c wcd9xxx_modules[MAX_WCD9XXX_DEVICE];
-static int wcd9xxx_intf;
+static int wcd9xxx_intf = -1;
 
 static int wcd9xxx_read(struct wcd9xxx *wcd9xxx, unsigned short reg,
 		       int bytes, void *dest, bool interface_reg)
@@ -331,17 +331,35 @@
 	pr_info("idbyte_0[%08x] idbyte_1[%08x] idbyte_2[%08x] idbyte_3[%08x]\n",
 			idbyte_0, idbyte_1, idbyte_2, idbyte_3);
 
-	if (!strncmp(wcd9xxx->slim->name, "tabla", 5)) {
+	if (wcd9xxx->slim != NULL) {
+		if (!strncmp(wcd9xxx->slim->name, "tabla", 5)) {
+			if (TABLA_IS_1_X(wcd9xxx->version)) {
+				wcd9xxx_dev = tabla1x_devs;
+				wcd9xxx_dev_size = ARRAY_SIZE(tabla1x_devs);
+			} else {
+				wcd9xxx_dev = tabla_devs;
+				wcd9xxx_dev_size = ARRAY_SIZE(tabla_devs);
+			}
+		} else {
+			wcd9xxx_dev = sitar_devs;
+			wcd9xxx_dev_size = ARRAY_SIZE(sitar_devs);
+		}
+	} else {
+		/* Need to add here check for Tabla.
+		 * For now the read of version takes
+		 * care of now only tabla.
+		 */
+		pr_debug("%s : Read codec version using I2C\n",	__func__);
 		if (TABLA_IS_1_X(wcd9xxx->version)) {
 			wcd9xxx_dev = tabla1x_devs;
 			wcd9xxx_dev_size = ARRAY_SIZE(tabla1x_devs);
-		} else {
+		} else if (TABLA_IS_2_0(wcd9xxx->version)) {
 			wcd9xxx_dev = tabla_devs;
 			wcd9xxx_dev_size = ARRAY_SIZE(tabla_devs);
+		} else {
+			wcd9xxx_dev = sitar_devs;
+			wcd9xxx_dev_size = ARRAY_SIZE(sitar_devs);
 		}
-	} else {
-		wcd9xxx_dev = sitar_devs;
-		wcd9xxx_dev_size = ARRAY_SIZE(sitar_devs);
 	}
 
 	ret = mfd_add_devices(wcd9xxx->dev, -1,
@@ -372,7 +390,8 @@
 	wake_lock_destroy(&wcd9xxx->wlock);
 	mutex_destroy(&wcd9xxx->io_lock);
 	mutex_destroy(&wcd9xxx->xfer_lock);
-	slim_remove_device(wcd9xxx->slim_slave);
+	if (wcd9xxx_intf == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+		slim_remove_device(wcd9xxx->slim_slave);
 	kfree(wcd9xxx);
 }
 
@@ -478,12 +497,11 @@
 };
 #endif
 
-static int wcd9xxx_enable_supplies(struct wcd9xxx *wcd9xxx)
+static int wcd9xxx_enable_supplies(struct wcd9xxx *wcd9xxx,
+				struct wcd9xxx_pdata *pdata)
 {
 	int ret;
 	int i;
-	struct wcd9xxx_pdata *pdata = wcd9xxx->slim->dev.platform_data;
-
 	wcd9xxx->supplies = kzalloc(sizeof(struct regulator_bulk_data) *
 				   ARRAY_SIZE(pdata->regulator),
 				   GFP_KERNEL);
@@ -546,10 +564,10 @@
 	return ret;
 }
 
-static void wcd9xxx_disable_supplies(struct wcd9xxx *wcd9xxx)
+static void wcd9xxx_disable_supplies(struct wcd9xxx *wcd9xxx,
+				     struct wcd9xxx_pdata *pdata)
 {
 	int i;
-	struct wcd9xxx_pdata *pdata = wcd9xxx->slim->dev.platform_data;
 
 	regulator_bulk_disable(ARRAY_SIZE(pdata->regulator),
 				    wcd9xxx->supplies);
@@ -695,6 +713,10 @@
 	int ret = 0;
 	static int device_id;
 
+	if (wcd9xxx_intf == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
+		pr_info("tabla card is already detected in slimbus mode\n");
+		return -ENODEV;
+	}
 	if (device_id > 0) {
 		wcd9xxx_modules[device_id++].client = client;
 		pr_info("probe for other slaves devices of tabla\n");
@@ -721,8 +743,7 @@
 	dev_set_drvdata(&client->dev, wcd9xxx);
 	wcd9xxx->dev = &client->dev;
 	wcd9xxx->reset_gpio = pdata->reset_gpio;
-
-	ret = wcd9xxx_enable_supplies(wcd9xxx);
+	ret = wcd9xxx_enable_supplies(wcd9xxx, pdata);
 	if (ret) {
 		pr_err("%s: Fail to enable Codec supplies\n", __func__);
 		goto err_codec;
@@ -759,7 +780,7 @@
 err_device_init:
 	wcd9xxx_free_reset(wcd9xxx);
 err_supplies:
-	wcd9xxx_disable_supplies(wcd9xxx);
+	wcd9xxx_disable_supplies(wcd9xxx, pdata);
 err_codec:
 	kfree(wcd9xxx);
 fail:
@@ -769,10 +790,10 @@
 static int __devexit wcd9xxx_i2c_remove(struct i2c_client *client)
 {
 	struct wcd9xxx *wcd9xxx;
-
+	struct wcd9xxx_pdata *pdata = client->dev.platform_data;
 	pr_debug("exit\n");
 	wcd9xxx = dev_get_drvdata(&client->dev);
-	wcd9xxx_disable_supplies(wcd9xxx);
+	wcd9xxx_disable_supplies(wcd9xxx, pdata);
 	wcd9xxx_device_exit(wcd9xxx);
 	return 0;
 }
@@ -809,7 +830,7 @@
 	wcd9xxx->reset_gpio = pdata->reset_gpio;
 	wcd9xxx->dev = &slim->dev;
 
-	ret = wcd9xxx_enable_supplies(wcd9xxx);
+	ret = wcd9xxx_enable_supplies(wcd9xxx, pdata);
 	if (ret)
 		goto err_codec;
 	usleep_range(5, 5);
@@ -901,7 +922,7 @@
 err_reset:
 	wcd9xxx_free_reset(wcd9xxx);
 err_supplies:
-	wcd9xxx_disable_supplies(wcd9xxx);
+	wcd9xxx_disable_supplies(wcd9xxx, pdata);
 err_codec:
 	kfree(wcd9xxx);
 err:
@@ -910,6 +931,7 @@
 static int wcd9xxx_slim_remove(struct slim_device *pdev)
 {
 	struct wcd9xxx *wcd9xxx;
+	struct wcd9xxx_pdata *pdata = pdev->dev.platform_data;
 
 #ifdef CONFIG_DEBUG_FS
 	debugfs_remove(debugfs_peek);
@@ -919,7 +941,7 @@
 	wcd9xxx = slim_get_devicedata(pdev);
 	wcd9xxx_deinit_slimslave(wcd9xxx);
 	slim_remove_device(wcd9xxx->slim_slave);
-	wcd9xxx_disable_supplies(wcd9xxx);
+	wcd9xxx_disable_supplies(wcd9xxx, pdata);
 	wcd9xxx_device_exit(wcd9xxx);
 	return 0;
 }
@@ -1032,6 +1054,22 @@
 	.suspend = wcd9xxx_slim_suspend,
 };
 
+static const struct slim_device_id sitar1p1_slimtest_id[] = {
+	{"sitar1p1-slim", 0},
+	{}
+};
+static struct slim_driver sitar1p1_slim_driver = {
+	.driver = {
+		.name = "sitar1p1-slim",
+		.owner = THIS_MODULE,
+	},
+	.probe = wcd9xxx_slim_probe,
+	.remove = wcd9xxx_slim_remove,
+	.id_table = sitar1p1_slimtest_id,
+	.resume = wcd9xxx_slim_resume,
+	.suspend = wcd9xxx_slim_suspend,
+};
+
 static const struct slim_device_id slimtest_id[] = {
 	{"tabla-slim", 0},
 	{}
@@ -1094,7 +1132,7 @@
 
 static int __init wcd9xxx_init(void)
 {
-	int ret1, ret2, ret3, ret4;
+	int ret1, ret2, ret3, ret4, ret5;
 
 	ret1 = slim_driver_register(&tabla_slim_driver);
 	if (ret1 != 0)
@@ -1109,10 +1147,14 @@
 		pr_err("failed to add the I2C driver\n");
 
 	ret4 = slim_driver_register(&sitar_slim_driver);
-	if (ret1 != 0)
+	if (ret4 != 0)
 		pr_err("Failed to register sitar SB driver: %d\n", ret4);
 
-	return (ret1 && ret2 && ret3 && ret4) ? -1 : 0;
+	ret5 = slim_driver_register(&sitar1p1_slim_driver);
+	if (ret5 != 0)
+		pr_err("Failed to register sitar SB driver: %d\n", ret5);
+
+	return (ret1 && ret2 && ret3 && ret4 && ret5) ? -1 : 0;
 }
 module_init(wcd9xxx_init);
 
diff --git a/drivers/mfd/wcd9xxx-slimslave.c b/drivers/mfd/wcd9xxx-slimslave.c
index 3aff7f17..889c416 100644
--- a/drivers/mfd/wcd9xxx-slimslave.c
+++ b/drivers/mfd/wcd9xxx-slimslave.c
@@ -461,7 +461,13 @@
 	pr_debug("%s: ch_cnt[%d]\n", __func__, ch_cnt);
 	for (i = 0; i < ch_cnt; i++) {
 		idx = (ch_num[i] - BASE_CH_NUM -
-				SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS - 1);
+			SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS - 1);
+		if (idx < 0) {
+			pr_err("%s: Error:-Invalid index found = %d\n",
+				__func__, idx);
+			ret = -EINVAL;
+			goto err;
+		}
 		sph[i] = rx[idx].sph;
 		grph = rx[idx].grph;
 	}
@@ -501,6 +507,12 @@
 	pr_debug("%s: ch_cnt[%d]\n", __func__, ch_cnt);
 	for (i = 0; i < ch_cnt; i++) {
 		idx = (ch_num[i] - BASE_CH_NUM);
+		if (idx < 0) {
+			pr_err("%s: Error:- Invalid index found = %d\n",
+				__func__, idx);
+			ret = -EINVAL;
+			goto err;
+		}
 		sph[i] = tx[idx].sph;
 		grph = tx[idx].grph;
 	}
diff --git a/drivers/misc/isa1200.c b/drivers/misc/isa1200.c
index 31c79a0..555dfdd 100644
--- a/drivers/misc/isa1200.c
+++ b/drivers/misc/isa1200.c
@@ -3,7 +3,7 @@
  *
  *  Copyright (C) 2009 Samsung Electronics
  *  Kyungmin Park <kyungmin.park@samsung.com>
- *  Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *  Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -32,6 +32,7 @@
 
 #define ISA1200_HCTRL5_VIB_STRT	0xD5
 #define ISA1200_HCTRL5_VIB_STOP	0x6B
+#define ISA1200_POWER_DOWN_MASK 0x7F
 
 struct isa1200_chip {
 	struct i2c_client *client;
@@ -45,6 +46,8 @@
 	unsigned int period_ns;
 	bool is_len_gpio_valid;
 	struct regulator **regs;
+	bool clk_on;
+	u8 hctrl0_val;
 };
 
 static int isa1200_read_reg(struct i2c_client *client, int reg)
@@ -74,32 +77,111 @@
 	int rc = 0;
 
 	if (enable) {
+		/* if hen and len are seperate then enable hen
+		 * otherwise set normal mode bit */
+		if (haptic->is_len_gpio_valid == true)
+			gpio_set_value_cansleep(haptic->pdata->hap_en_gpio, 1);
+		else {
+			rc = isa1200_write_reg(haptic->client, ISA1200_HCTRL0,
+				haptic->hctrl0_val | ~ISA1200_POWER_DOWN_MASK);
+			if (rc < 0) {
+				pr_err("%s: i2c write failure\n", __func__);
+				return;
+			}
+		}
+
 		if (haptic->pdata->mode_ctrl == PWM_INPUT_MODE) {
 			int period_us = haptic->period_ns / 1000;
+
 			rc = pwm_config(haptic->pwm,
 				(period_us * haptic->pdata->duty) / 100,
 				period_us);
-			if (rc < 0)
+			if (rc < 0) {
 				pr_err("%s: pwm_config fail\n", __func__);
+				goto chip_dwn;
+			}
+
 			rc = pwm_enable(haptic->pwm);
-			if (rc < 0)
+			if (rc < 0) {
 				pr_err("%s: pwm_enable fail\n", __func__);
+				goto chip_dwn;
+			}
 		} else if (haptic->pdata->mode_ctrl == PWM_GEN_MODE) {
+			/* vote for clock */
+			if (haptic->pdata->clk_enable && !haptic->clk_on) {
+				rc = haptic->pdata->clk_enable(true);
+				if (rc < 0) {
+					pr_err("%s: clk enable failed\n",
+								__func__);
+					goto chip_dwn;
+				}
+				haptic->clk_on = true;
+			}
+
 			rc = isa1200_write_reg(haptic->client,
 						ISA1200_HCTRL5,
 						ISA1200_HCTRL5_VIB_STRT);
-			if (rc < 0)
+			if (rc < 0) {
 				pr_err("%s: start vibartion fail\n", __func__);
+				goto dis_clk;
+			}
 		}
 	} else {
-		if (haptic->pdata->mode_ctrl == PWM_INPUT_MODE)
+		/* if hen and len are seperate then pull down hen
+		 * otherwise set power down bit */
+		if (haptic->is_len_gpio_valid == true)
+			gpio_set_value_cansleep(haptic->pdata->hap_en_gpio, 0);
+		else {
+			rc = isa1200_write_reg(haptic->client, ISA1200_HCTRL0,
+				haptic->hctrl0_val & ISA1200_POWER_DOWN_MASK);
+			if (rc < 0) {
+				pr_err("%s: i2c write failure\n", __func__);
+				return;
+			}
+		}
+
+		if (haptic->pdata->mode_ctrl == PWM_INPUT_MODE) {
 			pwm_disable(haptic->pwm);
-		else if (haptic->pdata->mode_ctrl == PWM_GEN_MODE) {
+		} else if (haptic->pdata->mode_ctrl == PWM_GEN_MODE) {
 			rc = isa1200_write_reg(haptic->client,
 						ISA1200_HCTRL5,
 						ISA1200_HCTRL5_VIB_STOP);
 			if (rc < 0)
 				pr_err("%s: stop vibartion fail\n", __func__);
+
+			/* de-vote clock */
+			if (haptic->pdata->clk_enable && haptic->clk_on) {
+				rc = haptic->pdata->clk_enable(false);
+				if (rc < 0) {
+					pr_err("%s: clk disable failed\n",
+								__func__);
+					return;
+				}
+				haptic->clk_on = false;
+			}
+		}
+	}
+
+	return;
+
+dis_clk:
+	if (haptic->pdata->clk_enable && haptic->clk_on) {
+		rc = haptic->pdata->clk_enable(false);
+		if (rc < 0) {
+			pr_err("%s: clk disable failed\n", __func__);
+			return;
+		}
+		haptic->clk_on = false;
+	}
+chip_dwn:
+	if (haptic->is_len_gpio_valid == true)
+		gpio_set_value_cansleep(haptic->pdata->hap_en_gpio, 0);
+	else {
+		rc = isa1200_write_reg(haptic->client, ISA1200_HCTRL0,
+			haptic->hctrl0_val & ISA1200_POWER_DOWN_MASK);
+		if (rc < 0) {
+			pr_err("%s: i2c write failure\n", __func__);
+			return;
 		}
 	}
 }
@@ -168,7 +250,8 @@
 static int isa1200_setup(struct i2c_client *client)
 {
 	struct isa1200_chip *haptic = i2c_get_clientdata(client);
-	int value, temp, rc;
+	int temp, rc;
+	u8 value;
 
 	gpio_set_value_cansleep(haptic->pdata->hap_en_gpio, 0);
 	if (haptic->is_len_gpio_valid == true)
@@ -218,6 +301,20 @@
 		goto reset_hctrl1;
 	}
 
+	/* if hen and len are seperate then pull down hen
+	 * otherwise set power down bit */
+	if (haptic->is_len_gpio_valid == true)
+		gpio_set_value_cansleep(haptic->pdata->hap_en_gpio, 0);
+	else {
+		rc = isa1200_write_reg(client, ISA1200_HCTRL0,
+					value & ISA1200_POWER_DOWN_MASK);
+		if (rc < 0) {
+			pr_err("%s: i2c write failure\n", __func__);
+			goto reset_hctrl1;
+		}
+	}
+
+	haptic->hctrl0_val = value;
 	dump_isa1200_reg("new:", client);
 	return 0;
 
@@ -388,6 +485,7 @@
 
 	spin_lock_init(&haptic->lock);
 	INIT_WORK(&haptic->work, isa1200_chip_work);
+	haptic->clk_on = false;
 
 	hrtimer_init(&haptic->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
 	haptic->timer.function = isa1200_vib_timer_func;
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 2c42bc7..4c92ee5 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -1271,9 +1271,11 @@
 {
 	struct ion_handle *ihandle;	/* Ion handle */
 	struct qseecom_load_img_req load_img_req;
-	int32_t ret;
+	int ret;
+	int set_cpu_ret = 0;
 	ion_phys_addr_t pa = 0;
 	uint32_t len;
+	struct cpumask mask;
 	struct qseecom_load_app_ireq load_req;
 	struct qseecom_command_scm_resp resp;
 
@@ -1302,14 +1304,25 @@
 	load_req.img_len = load_img_req.img_len;
 	load_req.phy_addr = pa;
 
+	/* SCM_CALL tied to Core0 */
+	mask = CPU_MASK_CPU0;
+	set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
+	if (set_cpu_ret) {
+		pr_err("set_cpus_allowed_ptr failed : ret %d\n",
+				set_cpu_ret);
+		ret = -EFAULT;
+		goto qseecom_load_external_elf_set_cpu_err;
+	}
+
 	/*  SCM_CALL to load the external elf */
 	ret = scm_call(SCM_SVC_TZSCHEDULER, 1,  &load_req,
 			sizeof(struct qseecom_load_app_ireq),
 			&resp, sizeof(resp));
 	if (ret) {
-		pr_err("scm_call to unload failed : ret %d\n",
+		pr_err("scm_call to load failed : ret %d\n",
 				ret);
 		ret = -EFAULT;
+		goto qseecom_load_external_elf_scm_err;
 	}
 
 	if (resp.result == QSEOS_RESULT_INCOMPLETE) {
@@ -1324,6 +1337,18 @@
 			ret = -EFAULT;
 		}
 	}
+
+qseecom_load_external_elf_scm_err:
+	/* Restore the CPU mask */
+	mask = CPU_MASK_ALL;
+	set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
+	if (set_cpu_ret) {
+		pr_err("set_cpus_allowed_ptr failed to restore mask: ret %d\n",
+				set_cpu_ret);
+		ret = -EFAULT;
+	}
+
+qseecom_load_external_elf_set_cpu_err:
 	/* Deallocate the handle */
 	if (!IS_ERR_OR_NULL(ihandle))
 		ion_free(qseecom.ion_clnt, ihandle);
@@ -1334,11 +1359,23 @@
 static int qseecom_unload_external_elf(struct qseecom_dev_handle *data)
 {
 	int ret = 0;
+	int set_cpu_ret = 0;
 	struct qseecom_command_scm_resp resp;
 	struct qseecom_unload_app_ireq req;
+	struct cpumask mask;
 
 	/* Populate the structure for sending scm call to unload image */
 	req.qsee_cmd_id = QSEOS_UNLOAD_EXTERNAL_ELF_COMMAND;
+
+	/* SCM_CALL tied to Core0 */
+	mask = CPU_MASK_CPU0;
+	ret = set_cpus_allowed_ptr(current, &mask);
+	if (ret) {
+		pr_err("set_cpus_allowed_ptr failed : ret %d\n",
+				ret);
+		return -EFAULT;
+	}
+
 	/* SCM_CALL to unload the external elf */
 	ret = scm_call(SCM_SVC_TZSCHEDULER, 1,  &req,
 			sizeof(struct qseecom_unload_app_ireq),
@@ -1346,7 +1383,8 @@
 	if (ret) {
 		pr_err("scm_call to unload failed : ret %d\n",
 				ret);
-		return -EFAULT;
+		ret = -EFAULT;
+		goto qseecom_unload_external_elf_scm_err;
 	}
 	if (resp.result == QSEOS_RESULT_INCOMPLETE) {
 		ret = __qseecom_process_incomplete_cmd(data, &resp);
@@ -1360,6 +1398,17 @@
 			ret = -EFAULT;
 		}
 	}
+
+qseecom_unload_external_elf_scm_err:
+	/* Restore the CPU mask */
+	mask = CPU_MASK_ALL;
+	set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
+	if (set_cpu_ret) {
+		pr_err("set_cpus_allowed_ptr failed to restore mask: ret %d\n",
+				set_cpu_ret);
+		ret = -EFAULT;
+	}
+
 	return ret;
 }
 
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 44228a6..e4935ae 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -59,6 +59,18 @@
 #define INAND_CMD38_ARG_SECTRIM1 0x81
 #define INAND_CMD38_ARG_SECTRIM2 0x88
 
+#define MMC_SANITIZE_REQ_TIMEOUT 240000 /* msec */
+#define mmc_req_rel_wr(req)	(((req->cmd_flags & REQ_FUA) || \
+			(req->cmd_flags & REQ_META)) && \
+			(rq_data_dir(req) == WRITE))
+#define PACKED_CMD_VER		0x01
+#define PACKED_CMD_WR		0x02
+#define MMC_BLK_UPDATE_STOP_REASON(stats, reason)			\
+	do {								\
+		if (stats->enabled)					\
+			stats->pack_stop_reason[reason]++;		\
+	} while (0)
+
 static DEFINE_MUTEX(block_mutex);
 
 /*
@@ -107,6 +119,7 @@
 	 */
 	unsigned int	part_curr;
 	struct device_attribute force_ro;
+	struct device_attribute num_wr_reqs_to_start_packing;
 };
 
 static DEFINE_MUTEX(open_lock);
@@ -121,9 +134,21 @@
 	MMC_BLK_ECC_ERR,
 };
 
+enum {
+        MMC_PACKED_N_IDX = -1,
+        MMC_PACKED_N_ZERO,
+        MMC_PACKED_N_SINGLE,
+};
+
 module_param(perdev_minors, int, 0444);
 MODULE_PARM_DESC(perdev_minors, "Minors numbers to allocate per device");
 
+static inline void mmc_blk_clear_packed(struct mmc_queue_req *mqrq)
+{
+        mqrq->packed_cmd = MMC_PACKED_NONE;
+        mqrq->packed_num = MMC_PACKED_N_ZERO;
+}
+
 static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
 {
 	struct mmc_blk_data *md;
@@ -193,6 +218,38 @@
 	return ret;
 }
 
+static ssize_t
+num_wr_reqs_to_start_packing_show(struct device *dev,
+				  struct device_attribute *attr, char *buf)
+{
+	struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
+	int num_wr_reqs_to_start_packing;
+	int ret;
+
+	num_wr_reqs_to_start_packing = md->queue.num_wr_reqs_to_start_packing;
+
+	ret = snprintf(buf, PAGE_SIZE, "%d\n", num_wr_reqs_to_start_packing);
+
+	mmc_blk_put(md);
+	return ret;
+}
+
+static ssize_t
+num_wr_reqs_to_start_packing_store(struct device *dev,
+				 struct device_attribute *attr,
+				 const char *buf, size_t count)
+{
+	int value;
+	struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
+
+	sscanf(buf, "%d", &value);
+	if (value >= 0)
+		md->queue.num_wr_reqs_to_start_packing = value;
+
+	mmc_blk_put(md);
+	return count;
+}
+
 static int mmc_blk_open(struct block_device *bdev, fmode_t mode)
 {
 	struct mmc_blk_data *md = mmc_blk_get(bdev->bd_disk);
@@ -802,18 +859,11 @@
 	unsigned int from, nr, arg;
 	int err = 0, type = MMC_BLK_SECDISCARD;
 
-	if (!(mmc_can_secure_erase_trim(card) || mmc_can_sanitize(card))) {
+	if (!(mmc_can_secure_erase_trim(card))) {
 		err = -EOPNOTSUPP;
 		goto out;
 	}
 
-	/* The sanitize operation is supported at v4.5 only */
-	if (mmc_can_sanitize(card)) {
-		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-				EXT_CSD_SANITIZE_START, 1, 0);
-		goto out;
-	}
-
 	from = blk_rq_pos(req);
 	nr = blk_rq_sectors(req);
 
@@ -856,6 +906,47 @@
 	return err ? 0 : 1;
 }
 
+static int mmc_blk_issue_sanitize_rq(struct mmc_queue *mq,
+				      struct request *req)
+{
+	struct mmc_blk_data *md = mq->data;
+	struct mmc_card *card = md->queue.card;
+	int err = 0;
+
+	BUG_ON(!card);
+	BUG_ON(!card->host);
+
+	if (!(mmc_can_sanitize(card) &&
+	     (card->host->caps2 & MMC_CAP2_SANITIZE))) {
+			pr_warning("%s: %s - SANITIZE is not supported\n",
+				   mmc_hostname(card->host), __func__);
+			err = -EOPNOTSUPP;
+			goto out;
+	}
+
+	pr_debug("%s: %s - SANITIZE IN PROGRESS...\n",
+		mmc_hostname(card->host), __func__);
+
+	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+					EXT_CSD_SANITIZE_START, 1,
+					MMC_SANITIZE_REQ_TIMEOUT);
+
+	if (err)
+		pr_err("%s: %s - mmc_switch() with "
+		       "EXT_CSD_SANITIZE_START failed. err=%d\n",
+		       mmc_hostname(card->host), __func__, err);
+
+	pr_debug("%s: %s - SANITIZE COMPLETED\n", mmc_hostname(card->host),
+					     __func__);
+
+out:
+	spin_lock_irq(&md->lock);
+	__blk_end_request(req, err, blk_rq_bytes(req));
+	spin_unlock_irq(&md->lock);
+
+	return err ? 0 : 1;
+}
+
 static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req)
 {
 	struct mmc_blk_data *md = mq->data;
@@ -989,12 +1080,60 @@
 	if (!brq->data.bytes_xfered)
 		return MMC_BLK_RETRY;
 
+	if (mq_mrq->packed_cmd != MMC_PACKED_NONE) {
+		if (unlikely(brq->data.blocks << 9 != brq->data.bytes_xfered))
+			return MMC_BLK_PARTIAL;
+		else
+			return MMC_BLK_SUCCESS;
+	}
+
 	if (blk_rq_bytes(req) != brq->data.bytes_xfered)
 		return MMC_BLK_PARTIAL;
 
 	return MMC_BLK_SUCCESS;
 }
 
+static int mmc_blk_packed_err_check(struct mmc_card *card,
+				    struct mmc_async_req *areq)
+{
+	struct mmc_queue_req *mq_rq = container_of(areq, struct mmc_queue_req,
+			mmc_active);
+	struct request *req = mq_rq->req;
+	int err, check, status;
+	u8 ext_csd[512];
+
+	check = mmc_blk_err_check(card, areq);
+	err = get_card_status(card, &status, 0);
+	if (err) {
+		pr_err("%s: error %d sending status command\n",
+				req->rq_disk->disk_name, err);
+		return MMC_BLK_ABORT;
+	}
+
+	if (status & R1_EXP_EVENT) {
+		err = mmc_send_ext_csd(card, ext_csd);
+		if (err) {
+			pr_err("%s: error %d sending ext_csd\n",
+					req->rq_disk->disk_name, err);
+			return MMC_BLK_ABORT;
+		}
+
+		if ((ext_csd[EXT_CSD_EXP_EVENTS_STATUS] &
+					EXT_CSD_PACKED_FAILURE) &&
+				(ext_csd[EXT_CSD_PACKED_CMD_STATUS] &
+				 EXT_CSD_PACKED_GENERIC_ERROR)) {
+			if (ext_csd[EXT_CSD_PACKED_CMD_STATUS] &
+					EXT_CSD_PACKED_INDEXED_ERROR) {
+				mq_rq->packed_fail_idx =
+				  ext_csd[EXT_CSD_PACKED_FAILURE_INDEX] - 1;
+				return MMC_BLK_PARTIAL;
+			}
+		}
+	}
+
+	return check;
+}
+
 static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
 			       struct mmc_card *card,
 			       int disable_multi,
@@ -1135,10 +1274,286 @@
 	mmc_queue_bounce_pre(mqrq);
 }
 
+static void mmc_blk_write_packing_control(struct mmc_queue *mq,
+					  struct request *req)
+{
+	struct mmc_host *host = mq->card->host;
+	int data_dir;
+
+	if (!(host->caps2 & MMC_CAP2_PACKED_WR))
+		return;
+
+	/*
+	 * In case the packing control is not supported by the host, it should
+	 * not have an effect on the write packing. Therefore we have to enable
+	 * the write packing
+	 */
+	if (!(host->caps2 & MMC_CAP2_PACKED_WR_CONTROL)) {
+		mq->wr_packing_enabled = true;
+		return;
+	}
+
+	if (!req || (req && (req->cmd_flags & REQ_FLUSH))) {
+		if (mq->num_of_potential_packed_wr_reqs >
+				mq->num_wr_reqs_to_start_packing)
+			mq->wr_packing_enabled = true;
+		return;
+	}
+
+	data_dir = rq_data_dir(req);
+
+	if (data_dir == READ) {
+		mq->num_of_potential_packed_wr_reqs = 0;
+		mq->wr_packing_enabled = false;
+		return;
+	} else if (data_dir == WRITE) {
+		mq->num_of_potential_packed_wr_reqs++;
+	}
+
+	if (mq->num_of_potential_packed_wr_reqs >
+			mq->num_wr_reqs_to_start_packing)
+		mq->wr_packing_enabled = true;
+
+}
+
+struct mmc_wr_pack_stats *mmc_blk_get_packed_statistics(struct mmc_card *card)
+{
+	if (!card)
+		return NULL;
+
+	return &card->wr_pack_stats;
+}
+EXPORT_SYMBOL(mmc_blk_get_packed_statistics);
+
+void mmc_blk_init_packed_statistics(struct mmc_card *card)
+{
+	int max_num_of_packed_reqs = 0;
+
+	if (!card || !card->wr_pack_stats.packing_events)
+		return;
+
+	max_num_of_packed_reqs = card->ext_csd.max_packed_writes;
+
+	spin_lock(&card->wr_pack_stats.lock);
+	memset(card->wr_pack_stats.packing_events, 0,
+		(max_num_of_packed_reqs + 1) *
+	       sizeof(*card->wr_pack_stats.packing_events));
+	memset(&card->wr_pack_stats.pack_stop_reason, 0,
+		sizeof(card->wr_pack_stats.pack_stop_reason));
+	card->wr_pack_stats.enabled = true;
+	spin_unlock(&card->wr_pack_stats.lock);
+}
+EXPORT_SYMBOL(mmc_blk_init_packed_statistics);
+
+static u8 mmc_blk_prep_packed_list(struct mmc_queue *mq, struct request *req)
+{
+	struct request_queue *q = mq->queue;
+	struct mmc_card *card = mq->card;
+	struct request *cur = req, *next = NULL;
+	struct mmc_blk_data *md = mq->data;
+	bool en_rel_wr = card->ext_csd.rel_param & EXT_CSD_WR_REL_PARAM_EN;
+	unsigned int req_sectors = 0, phys_segments = 0;
+	unsigned int max_blk_count, max_phys_segs;
+	u8 put_back = 0;
+	u8 max_packed_rw = 0;
+	u8 reqs = 0;
+	struct mmc_wr_pack_stats *stats = &card->wr_pack_stats;
+
+	mmc_blk_clear_packed(mq->mqrq_cur);
+
+	if (!(md->flags & MMC_BLK_CMD23) ||
+			!card->ext_csd.packed_event_en)
+		goto no_packed;
+
+	if (!mq->wr_packing_enabled)
+		goto no_packed;
+
+	if ((rq_data_dir(cur) == WRITE) &&
+			(card->host->caps2 & MMC_CAP2_PACKED_WR))
+		max_packed_rw = card->ext_csd.max_packed_writes;
+
+	if (max_packed_rw == 0)
+		goto no_packed;
+
+	if (mmc_req_rel_wr(cur) &&
+			(md->flags & MMC_BLK_REL_WR) &&
+			!en_rel_wr) {
+		goto no_packed;
+	}
+
+	max_blk_count = min(card->host->max_blk_count,
+			card->host->max_req_size >> 9);
+	if (unlikely(max_blk_count > 0xffff))
+		max_blk_count = 0xffff;
+
+	max_phys_segs = queue_max_segments(q);
+	req_sectors += blk_rq_sectors(cur);
+	phys_segments += cur->nr_phys_segments;
+
+	if (rq_data_dir(cur) == WRITE) {
+		req_sectors++;
+		phys_segments++;
+	}
+
+	spin_lock(&stats->lock);
+
+	while (reqs < max_packed_rw - 1) {
+		spin_lock_irq(q->queue_lock);
+		next = blk_fetch_request(q);
+		spin_unlock_irq(q->queue_lock);
+		if (!next) {
+			MMC_BLK_UPDATE_STOP_REASON(stats, EMPTY_QUEUE);
+			break;
+		}
+
+		if (next->cmd_flags & REQ_DISCARD ||
+				next->cmd_flags & REQ_FLUSH) {
+			MMC_BLK_UPDATE_STOP_REASON(stats, FLUSH_OR_DISCARD);
+			put_back = 1;
+			break;
+		}
+
+		if (rq_data_dir(cur) != rq_data_dir(next)) {
+			MMC_BLK_UPDATE_STOP_REASON(stats, WRONG_DATA_DIR);
+			put_back = 1;
+			break;
+		}
+
+		if (mmc_req_rel_wr(next) &&
+				(md->flags & MMC_BLK_REL_WR) &&
+				!en_rel_wr) {
+			MMC_BLK_UPDATE_STOP_REASON(stats, REL_WRITE);
+			put_back = 1;
+			break;
+		}
+
+		req_sectors += blk_rq_sectors(next);
+		if (req_sectors > max_blk_count) {
+			if (stats->enabled)
+				stats->pack_stop_reason[EXCEEDS_SECTORS]++;
+			put_back = 1;
+			break;
+		}
+
+		phys_segments +=  next->nr_phys_segments;
+		if (phys_segments > max_phys_segs) {
+			MMC_BLK_UPDATE_STOP_REASON(stats, EXCEEDS_SEGMENTS);
+			put_back = 1;
+			break;
+		}
+
+		if (rq_data_dir(next) == WRITE)
+			mq->num_of_potential_packed_wr_reqs++;
+		list_add_tail(&next->queuelist, &mq->mqrq_cur->packed_list);
+		cur = next;
+		reqs++;
+	}
+
+	if (put_back) {
+		spin_lock_irq(q->queue_lock);
+		blk_requeue_request(q, next);
+		spin_unlock_irq(q->queue_lock);
+	}
+
+	if (stats->enabled) {
+		if (reqs + 1 <= card->ext_csd.max_packed_writes)
+			stats->packing_events[reqs + 1]++;
+		if (reqs + 1 == max_packed_rw)
+			MMC_BLK_UPDATE_STOP_REASON(stats, THRESHOLD);
+	}
+
+	spin_unlock(&stats->lock);
+
+	if (reqs > 0) {
+		list_add(&req->queuelist, &mq->mqrq_cur->packed_list);
+		mq->mqrq_cur->packed_num = ++reqs;
+		return reqs;
+	}
+
+no_packed:
+	mmc_blk_clear_packed(mq->mqrq_cur);
+	return 0;
+}
+
+static void mmc_blk_packed_hdr_wrq_prep(struct mmc_queue_req *mqrq,
+					struct mmc_card *card,
+					struct mmc_queue *mq)
+{
+	struct mmc_blk_request *brq = &mqrq->brq;
+	struct request *req = mqrq->req;
+	struct request *prq;
+	struct mmc_blk_data *md = mq->data;
+	bool do_rel_wr;
+	u32 *packed_cmd_hdr = mqrq->packed_cmd_hdr;
+	u8 i = 1;
+
+	mqrq->packed_cmd = MMC_PACKED_WRITE;
+	mqrq->packed_blocks = 0;
+	mqrq->packed_fail_idx = MMC_PACKED_N_IDX;
+
+	memset(packed_cmd_hdr, 0, sizeof(mqrq->packed_cmd_hdr));
+	packed_cmd_hdr[0] = (mqrq->packed_num << 16) |
+		(PACKED_CMD_WR << 8) | PACKED_CMD_VER;
+
+	/*
+	 * Argument for each entry of packed group
+	 */
+	list_for_each_entry(prq, &mqrq->packed_list, queuelist) {
+		do_rel_wr = mmc_req_rel_wr(prq) && (md->flags & MMC_BLK_REL_WR);
+		/* Argument of CMD23*/
+		packed_cmd_hdr[(i * 2)] =
+			(do_rel_wr ? MMC_CMD23_ARG_REL_WR : 0) |
+			blk_rq_sectors(prq);
+		/* Argument of CMD18 or CMD25 */
+		packed_cmd_hdr[((i * 2)) + 1] =
+			mmc_card_blockaddr(card) ?
+			blk_rq_pos(prq) : blk_rq_pos(prq) << 9;
+		mqrq->packed_blocks += blk_rq_sectors(prq);
+		i++;
+	}
+
+	memset(brq, 0, sizeof(struct mmc_blk_request));
+	brq->mrq.cmd = &brq->cmd;
+	brq->mrq.data = &brq->data;
+	brq->mrq.sbc = &brq->sbc;
+	brq->mrq.stop = &brq->stop;
+
+	brq->sbc.opcode = MMC_SET_BLOCK_COUNT;
+	brq->sbc.arg = MMC_CMD23_ARG_PACKED | (mqrq->packed_blocks + 1);
+	brq->sbc.flags = MMC_RSP_R1 | MMC_CMD_AC;
+
+	brq->cmd.opcode = MMC_WRITE_MULTIPLE_BLOCK;
+	brq->cmd.arg = blk_rq_pos(req);
+	if (!mmc_card_blockaddr(card))
+		brq->cmd.arg <<= 9;
+	brq->cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+
+	brq->data.blksz = 512;
+	brq->data.blocks = mqrq->packed_blocks + 1;
+	brq->data.flags |= MMC_DATA_WRITE;
+
+	brq->stop.opcode = MMC_STOP_TRANSMISSION;
+	brq->stop.arg = 0;
+	brq->stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
+
+	mmc_set_data_timeout(&brq->data, card);
+
+	brq->data.sg = mqrq->sg;
+	brq->data.sg_len = mmc_queue_map_sg(mq, mqrq);
+
+	mqrq->mmc_active.mrq = &brq->mrq;
+	mqrq->mmc_active.err_check = mmc_blk_packed_err_check;
+
+	mmc_queue_bounce_pre(mqrq);
+}
+
 static int mmc_blk_cmd_err(struct mmc_blk_data *md, struct mmc_card *card,
 			   struct mmc_blk_request *brq, struct request *req,
 			   int ret)
 {
+	struct mmc_queue_req *mq_rq;
+	mq_rq = container_of(brq, struct mmc_queue_req, brq);
+
 	/*
 	 * If this is an SD card and we're writing, we can first
 	 * mark the known good sectors as ok.
@@ -1157,13 +1572,48 @@
 			spin_unlock_irq(&md->lock);
 		}
 	} else {
-		spin_lock_irq(&md->lock);
-		ret = __blk_end_request(req, 0, brq->data.bytes_xfered);
-		spin_unlock_irq(&md->lock);
+		if (mq_rq->packed_cmd == MMC_PACKED_NONE) {
+			spin_lock_irq(&md->lock);
+			ret = __blk_end_request(req, 0, brq->data.bytes_xfered);
+			spin_unlock_irq(&md->lock);
+		}
 	}
 	return ret;
 }
 
+static int mmc_blk_end_packed_req(struct mmc_queue *mq,
+				  struct mmc_queue_req *mq_rq)
+{
+	struct mmc_blk_data *md = mq->data;
+	struct request *prq;
+	int idx = mq_rq->packed_fail_idx, i = 0;
+	int ret = 0;
+
+	while (!list_empty(&mq_rq->packed_list)) {
+		prq = list_entry_rq(mq_rq->packed_list.next);
+		if (idx == i) {
+			/* retry from error index */
+			mq_rq->packed_num -= idx;
+			mq_rq->req = prq;
+			ret = 1;
+
+			if (mq_rq->packed_num == MMC_PACKED_N_SINGLE) {
+				list_del_init(&prq->queuelist);
+				mmc_blk_clear_packed(mq_rq);
+			}
+			return ret;
+		}
+		list_del_init(&prq->queuelist);
+		spin_lock_irq(&md->lock);
+		__blk_end_request(prq, 0, blk_rq_bytes(prq));
+		spin_unlock_irq(&md->lock);
+		i++;
+	}
+
+	mmc_blk_clear_packed(mq_rq);
+	return ret;
+}
+
 static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
 {
 	struct mmc_blk_data *md = mq->data;
@@ -1172,15 +1622,24 @@
 	int ret = 1, disable_multi = 0, retry = 0, type;
 	enum mmc_blk_status status;
 	struct mmc_queue_req *mq_rq;
-	struct request *req;
+	struct request *req, *prq;
 	struct mmc_async_req *areq;
+	const u8 packed_num = 2;
+	u8 reqs = 0;
 
 	if (!rqc && !mq->mqrq_prev->req)
 		return 0;
 
+	if (rqc)
+		reqs = mmc_blk_prep_packed_list(mq, rqc);
+
 	do {
 		if (rqc) {
-			mmc_blk_rw_rq_prep(mq->mqrq_cur, card, 0, mq);
+			if (reqs >= packed_num)
+				mmc_blk_packed_hdr_wrq_prep(mq->mqrq_cur,
+						card, mq);
+			else
+				mmc_blk_rw_rq_prep(mq->mqrq_cur, card, 0, mq);
 			areq = &mq->mqrq_cur->mmc_active;
 		} else
 			areq = NULL;
@@ -1194,6 +1653,13 @@
 		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:
@@ -1201,10 +1667,17 @@
 			 * A block was successfully transferred.
 			 */
 			mmc_blk_reset_success(md, type);
-			spin_lock_irq(&md->lock);
-			ret = __blk_end_request(req, 0,
+
+			if (mq_rq->packed_cmd != MMC_PACKED_NONE) {
+				ret = mmc_blk_end_packed_req(mq, mq_rq);
+				break;
+			} else {
+				spin_lock_irq(&md->lock);
+				ret = __blk_end_request(req, 0,
 						brq->data.bytes_xfered);
-			spin_unlock_irq(&md->lock);
+				spin_unlock_irq(&md->lock);
+			}
+
 			/*
 			 * If the blk_end_request function returns non-zero even
 			 * though all data has been transferred and no errors
@@ -1237,7 +1710,8 @@
 			err = mmc_blk_reset(md, card->host, type);
 			if (!err)
 				break;
-			if (err == -ENODEV)
+			if (err == -ENODEV ||
+				mq_rq->packed_cmd != MMC_PACKED_NONE)
 				goto cmd_abort;
 			/* Fall through */
 		}
@@ -1264,27 +1738,66 @@
 		}
 
 		if (ret) {
-			/*
-			 * In case of a incomplete request
-			 * prepare it again and resend.
-			 */
-			mmc_blk_rw_rq_prep(mq_rq, card, disable_multi, mq);
-			mmc_start_req(card->host, &mq_rq->mmc_active, NULL);
+			if (mq_rq->packed_cmd == MMC_PACKED_NONE) {
+				/*
+				 * In case of a incomplete request
+				 * prepare it again and resend.
+				 */
+				mmc_blk_rw_rq_prep(mq_rq, card,
+						disable_multi, mq);
+				mmc_start_req(card->host,
+						&mq_rq->mmc_active, NULL);
+			} else {
+				mmc_blk_packed_hdr_wrq_prep(mq_rq, card, mq);
+				mmc_start_req(card->host,
+						&mq_rq->mmc_active, NULL);
+			}
 		}
 	} while (ret);
 
 	return 1;
 
  cmd_abort:
-	spin_lock_irq(&md->lock);
-	if (mmc_card_removed(card))
-		req->cmd_flags |= REQ_QUIET;
-	while (ret)
-		ret = __blk_end_request(req, -EIO, blk_rq_cur_bytes(req));
-	spin_unlock_irq(&md->lock);
+	if (mq_rq->packed_cmd == MMC_PACKED_NONE) {
+		spin_lock_irq(&md->lock);
+		if (mmc_card_removed(card))
+			req->cmd_flags |= REQ_QUIET;
+		while (ret)
+			ret = __blk_end_request(req, -EIO,
+					blk_rq_cur_bytes(req));
+		spin_unlock_irq(&md->lock);
+	} else {
+		while (!list_empty(&mq_rq->packed_list)) {
+			prq = list_entry_rq(mq_rq->packed_list.next);
+			list_del_init(&prq->queuelist);
+			spin_lock_irq(&md->lock);
+			__blk_end_request(prq, -EIO, blk_rq_bytes(prq));
+			spin_unlock_irq(&md->lock);
+		}
+		mmc_blk_clear_packed(mq_rq);
+	}
 
  start_new_req:
 	if (rqc) {
+		/*
+		 * If current request is packed, it needs to put back.
+		 */
+		if (mq->mqrq_cur->packed_cmd != MMC_PACKED_NONE) {
+			while (!list_empty(&mq->mqrq_cur->packed_list)) {
+				prq = list_entry_rq(
+					mq->mqrq_cur->packed_list.prev);
+				if (prq->queuelist.prev !=
+						&mq->mqrq_cur->packed_list) {
+					list_del_init(&prq->queuelist);
+					spin_lock_irq(mq->queue->queue_lock);
+					blk_requeue_request(mq->queue, prq);
+					spin_unlock_irq(mq->queue->queue_lock);
+				} else {
+					list_del_init(&prq->queuelist);
+				}
+			}
+			mmc_blk_clear_packed(mq->mqrq_cur);
+		}
 		mmc_blk_rw_rq_prep(mq->mqrq_cur, card, 0, mq);
 		mmc_start_req(card->host, &mq->mqrq_cur->mmc_active, NULL);
 	}
@@ -1323,7 +1836,14 @@
 		goto out;
 	}
 
-	if (req && req->cmd_flags & REQ_DISCARD) {
+	mmc_blk_write_packing_control(mq, req);
+
+	if (req && req->cmd_flags & REQ_SANITIZE) {
+		/* complete ongoing async transfer before issuing sanitize */
+		if (card->host && card->host->areq)
+			mmc_blk_issue_rw_rq(mq, NULL);
+		ret = mmc_blk_issue_sanitize_rq(mq, req);
+	} else if (req && req->cmd_flags & REQ_DISCARD) {
 		/* complete ongoing async transfer before issuing discard */
 		if (card->host->areq)
 			mmc_blk_issue_rw_rq(mq, NULL);
@@ -1559,6 +2079,8 @@
 static void mmc_blk_remove_req(struct mmc_blk_data *md)
 {
 	if (md) {
+		device_remove_file(disk_to_dev(md->disk),
+				   &md->num_wr_reqs_to_start_packing);
 		if (md->disk->flags & GENHD_FL_UP) {
 			device_remove_file(disk_to_dev(md->disk), &md->force_ro);
 
@@ -1597,9 +2119,27 @@
 	md->force_ro.attr.name = "force_ro";
 	md->force_ro.attr.mode = S_IRUGO | S_IWUSR;
 	ret = device_create_file(disk_to_dev(md->disk), &md->force_ro);
-	if (ret)
+	if (ret) {
 		del_gendisk(md->disk);
+		goto out;
+	}
 
+	md->num_wr_reqs_to_start_packing.show =
+		num_wr_reqs_to_start_packing_show;
+	md->num_wr_reqs_to_start_packing.store =
+		num_wr_reqs_to_start_packing_store;
+	sysfs_attr_init(&md->num_wr_reqs_to_start_packing.attr);
+	md->num_wr_reqs_to_start_packing.attr.name =
+		"num_wr_reqs_to_start_packing";
+	md->num_wr_reqs_to_start_packing.attr.mode = S_IRUGO | S_IWUSR;
+	ret = device_create_file(disk_to_dev(md->disk),
+				 &md->num_wr_reqs_to_start_packing);
+	if (ret) {
+		device_remove_file(disk_to_dev(md->disk), &md->force_ro);
+		del_gendisk(md->disk);
+	}
+
+out:
 	return ret;
 }
 
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index 73f63c9..c3a718a 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -25,6 +25,13 @@
 #define MMC_QUEUE_SUSPENDED	(1 << 0)
 
 /*
+ * Based on benchmark tests the default num of requests to trigger the write
+ * packing was determined, to keep the read latency as low as possible and
+ * manage to keep the high write throughput.
+ */
+#define DEFAULT_NUM_REQS_TO_START_PACK 17
+
+/*
  * Prepare a MMC request. This just filters out odd stuff.
  */
 static int mmc_prep_request(struct request_queue *q, struct request *req)
@@ -67,6 +74,9 @@
 		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 {
@@ -74,6 +84,8 @@
 				set_current_state(TASK_RUNNING);
 				break;
 			}
+
+			mmc_start_bkops(mq->card);
 			up(&mq->thread_sem);
 			schedule();
 			down(&mq->thread_sem);
@@ -146,10 +158,15 @@
 	/* granularity must not be greater than max. discard */
 	if (card->pref_erase > max_discard)
 		q->limits.discard_granularity = 0;
-	if (mmc_can_secure_erase_trim(card) || mmc_can_sanitize(card))
+	if (mmc_can_secure_erase_trim(card))
 		queue_flag_set_unlocked(QUEUE_FLAG_SECDISCARD, q);
 }
 
+static void mmc_queue_setup_sanitize(struct request_queue *q)
+{
+	queue_flag_set_unlocked(QUEUE_FLAG_SANITIZE, q);
+}
+
 /**
  * mmc_init_queue - initialise a queue structure.
  * @mq: mmc queue
@@ -178,15 +195,21 @@
 
 	memset(&mq->mqrq_cur, 0, sizeof(mq->mqrq_cur));
 	memset(&mq->mqrq_prev, 0, sizeof(mq->mqrq_prev));
+	INIT_LIST_HEAD(&mqrq_cur->packed_list);
+	INIT_LIST_HEAD(&mqrq_prev->packed_list);
 	mq->mqrq_cur = mqrq_cur;
 	mq->mqrq_prev = mqrq_prev;
 	mq->queue->queuedata = mq;
+	mq->num_wr_reqs_to_start_packing = DEFAULT_NUM_REQS_TO_START_PACK;
 
 	blk_queue_prep_rq(mq->queue, mmc_prep_request);
 	queue_flag_set_unlocked(QUEUE_FLAG_NONROT, mq->queue);
 	if (mmc_can_erase(card))
 		mmc_queue_setup_discard(mq->queue, card);
 
+	if ((mmc_can_sanitize(card) && (host->caps2 & MMC_CAP2_SANITIZE)))
+		mmc_queue_setup_sanitize(mq->queue);
+
 #ifdef CONFIG_MMC_BLOCK_BOUNCE
 	if (host->max_segs == 1) {
 		unsigned int bouncesz;
@@ -378,6 +401,35 @@
 	}
 }
 
+static unsigned int mmc_queue_packed_map_sg(struct mmc_queue *mq,
+					    struct mmc_queue_req *mqrq,
+					    struct scatterlist *sg)
+{
+	struct scatterlist *__sg;
+	unsigned int sg_len = 0;
+	struct request *req;
+	enum mmc_packed_cmd cmd;
+
+	cmd = mqrq->packed_cmd;
+
+	if (cmd == MMC_PACKED_WRITE) {
+		__sg = sg;
+		sg_set_buf(__sg, mqrq->packed_cmd_hdr,
+				sizeof(mqrq->packed_cmd_hdr));
+		sg_len++;
+		__sg->page_link &= ~0x02;
+	}
+
+	__sg = sg + sg_len;
+	list_for_each_entry(req, &mqrq->packed_list, queuelist) {
+		sg_len += blk_rq_map_sg(mq->queue, req, __sg);
+		__sg = sg + (sg_len - 1);
+		(__sg++)->page_link &= ~0x02;
+	}
+	sg_mark_end(sg + (sg_len - 1));
+	return sg_len;
+}
+
 /*
  * Prepare the sg list(s) to be handed of to the host driver
  */
@@ -388,12 +440,19 @@
 	struct scatterlist *sg;
 	int i;
 
-	if (!mqrq->bounce_buf)
-		return blk_rq_map_sg(mq->queue, mqrq->req, mqrq->sg);
+	if (!mqrq->bounce_buf) {
+		if (!list_empty(&mqrq->packed_list))
+			return mmc_queue_packed_map_sg(mq, mqrq, mqrq->sg);
+		else
+			return blk_rq_map_sg(mq->queue, mqrq->req, mqrq->sg);
+	}
 
 	BUG_ON(!mqrq->bounce_sg);
 
-	sg_len = blk_rq_map_sg(mq->queue, mqrq->req, mqrq->bounce_sg);
+	if (!list_empty(&mqrq->packed_list))
+		sg_len = mmc_queue_packed_map_sg(mq, mqrq, mqrq->bounce_sg);
+	else
+		sg_len = blk_rq_map_sg(mq->queue, mqrq->req, mqrq->bounce_sg);
 
 	mqrq->bounce_sg_len = sg_len;
 
diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h
index d2a1eb4..6c29e0e 100644
--- a/drivers/mmc/card/queue.h
+++ b/drivers/mmc/card/queue.h
@@ -12,6 +12,11 @@
 	struct mmc_data		data;
 };
 
+enum mmc_packed_cmd {
+	MMC_PACKED_NONE = 0,
+	MMC_PACKED_WRITE,
+};
+
 struct mmc_queue_req {
 	struct request		*req;
 	struct mmc_blk_request	brq;
@@ -20,6 +25,12 @@
 	struct scatterlist	*bounce_sg;
 	unsigned int		bounce_sg_len;
 	struct mmc_async_req	mmc_active;
+	struct list_head	packed_list;
+	u32			packed_cmd_hdr[128];
+	unsigned int		packed_blocks;
+	enum mmc_packed_cmd	packed_cmd;
+	int		packed_fail_idx;
+	u8		packed_num;
 };
 
 struct mmc_queue {
@@ -33,6 +44,9 @@
 	struct mmc_queue_req	mqrq[2];
 	struct mmc_queue_req	*mqrq_cur;
 	struct mmc_queue_req	*mqrq_prev;
+	bool			wr_packing_enabled;
+	int			num_of_potential_packed_wr_reqs;
+	int			num_wr_reqs_to_start_packing;
 };
 
 extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *,
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 84983e0..bca06a5 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -246,6 +246,8 @@
 	card->dev.release = mmc_release_card;
 	card->dev.type = type;
 
+	spin_lock_init(&card->wr_pack_stats.lock);
+
 	return card;
 }
 
@@ -359,6 +361,8 @@
 		device_del(&card->dev);
 	}
 
+	kfree(card->wr_pack_stats.packing_events);
+
 	put_device(&card->dev);
 }
 
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 925c032..e0217d0 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -40,6 +40,12 @@
 #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;
 
 /*
@@ -223,21 +229,90 @@
 	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);
 }
 
-static void __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
+static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
 {
 	init_completion(&mrq->completion);
 	mrq->done = mmc_wait_done;
 	if (mmc_card_removed(host->card)) {
 		mrq->cmd->error = -ENOMEDIUM;
 		complete(&mrq->completion);
-		return;
+		return -ENOMEDIUM;
 	}
 	mmc_start_request(host, mrq);
+	return 0;
 }
 
 static void mmc_wait_for_req_done(struct mmc_host *host,
@@ -315,6 +390,7 @@
 {
 	int err = 0;
 	struct mmc_async_req *data = host->areq;
+	int start_err = 0;
 
 	/* Prepare a new request */
 	if (areq)
@@ -323,24 +399,23 @@
 	if (host->areq) {
 		mmc_wait_for_req_done(host, host->areq->mrq);
 		err = host->areq->err_check(host->card, host->areq);
-		if (err) {
-			mmc_post_req(host, host->areq->mrq, 0);
-			if (areq)
-				mmc_post_req(host, areq->mrq, -EINVAL);
-
-			host->areq = NULL;
-			goto out;
-		}
 	}
 
-	if (areq)
-		__mmc_start_req(host, areq->mrq);
+	if (!err && areq)
+		start_err = __mmc_start_req(host, areq->mrq);
 
 	if (host->areq)
 		mmc_post_req(host, host->areq->mrq, 0);
 
-	host->areq = areq;
- out:
+	/* Cancel a prepared request if it was not started. */
+	if ((err || start_err) && areq)
+			mmc_post_req(host, areq->mrq, -EINVAL);
+
+	if (err)
+		host->areq = NULL;
+	else
+		host->areq = areq;
+
 	if (error)
 		*error = err;
 	return data;
@@ -450,6 +525,69 @@
 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
@@ -2417,8 +2555,12 @@
 				err = -EBUSY;
 
 		if (!err) {
-			if (host->bus_ops->suspend)
+			if (host->bus_ops->suspend) {
+				if (mmc_card_doing_bkops(host->card))
+					mmc_interrupt_bkops(host->card);
+
 				err = host->bus_ops->suspend(host);
+			}
 			if (!(host->card && mmc_card_sdio(host->card)))
 				mmc_do_release_host(host);
 
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index c1b0405..0efcf9d 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -287,6 +287,164 @@
 	.llseek		= default_llseek,
 };
 
+static int mmc_wr_pack_stats_open(struct inode *inode, struct file *filp)
+{
+	struct mmc_card *card = inode->i_private;
+
+	filp->private_data = card;
+	card->wr_pack_stats.print_in_read = 1;
+	return 0;
+}
+
+#define TEMP_BUF_SIZE 256
+static ssize_t mmc_wr_pack_stats_read(struct file *filp, char __user *ubuf,
+				size_t cnt, loff_t *ppos)
+{
+	struct mmc_card *card = filp->private_data;
+	struct mmc_wr_pack_stats *pack_stats;
+	int i;
+	int max_num_of_packed_reqs = 0;
+	char *temp_buf;
+
+	if (!card)
+		return cnt;
+
+	if (!card->wr_pack_stats.print_in_read)
+		return 0;
+
+	if (!card->wr_pack_stats.enabled) {
+		pr_info("%s: write packing statistics are disabled\n",
+			 mmc_hostname(card->host));
+		goto exit;
+	}
+
+	pack_stats = &card->wr_pack_stats;
+
+	if (!pack_stats->packing_events) {
+		pr_info("%s: NULL packing_events\n", mmc_hostname(card->host));
+		goto exit;
+	}
+
+	max_num_of_packed_reqs = card->ext_csd.max_packed_writes;
+
+	temp_buf = kmalloc(TEMP_BUF_SIZE, GFP_KERNEL);
+	if (!temp_buf)
+		goto exit;
+
+	spin_lock(&pack_stats->lock);
+
+	snprintf(temp_buf, TEMP_BUF_SIZE, "%s: write packing statistics:\n",
+		mmc_hostname(card->host));
+	strlcat(ubuf, temp_buf, cnt);
+
+	for (i = 1 ; i <= max_num_of_packed_reqs ; ++i) {
+		if (pack_stats->packing_events[i]) {
+			snprintf(temp_buf, TEMP_BUF_SIZE,
+				 "%s: Packed %d reqs - %d times\n",
+				mmc_hostname(card->host), i,
+				pack_stats->packing_events[i]);
+			strlcat(ubuf, temp_buf, cnt);
+		}
+	}
+
+	snprintf(temp_buf, TEMP_BUF_SIZE,
+		 "%s: stopped packing due to the following reasons:\n",
+		 mmc_hostname(card->host));
+	strlcat(ubuf, temp_buf, cnt);
+
+	if (pack_stats->pack_stop_reason[EXCEEDS_SEGMENTS]) {
+		snprintf(temp_buf, TEMP_BUF_SIZE,
+			 "%s: %d times: exceed max num of segments\n",
+			 mmc_hostname(card->host),
+			 pack_stats->pack_stop_reason[EXCEEDS_SEGMENTS]);
+		strlcat(ubuf, temp_buf, cnt);
+	}
+	if (pack_stats->pack_stop_reason[EXCEEDS_SECTORS]) {
+		snprintf(temp_buf, TEMP_BUF_SIZE,
+			 "%s: %d times: exceed max num of sectors\n",
+			mmc_hostname(card->host),
+			pack_stats->pack_stop_reason[EXCEEDS_SECTORS]);
+		strlcat(ubuf, temp_buf, cnt);
+	}
+	if (pack_stats->pack_stop_reason[WRONG_DATA_DIR]) {
+		snprintf(temp_buf, TEMP_BUF_SIZE,
+			 "%s: %d times: wrong data direction\n",
+			mmc_hostname(card->host),
+			pack_stats->pack_stop_reason[WRONG_DATA_DIR]);
+		strlcat(ubuf, temp_buf, cnt);
+	}
+	if (pack_stats->pack_stop_reason[FLUSH_OR_DISCARD]) {
+		snprintf(temp_buf, TEMP_BUF_SIZE,
+			 "%s: %d times: flush or discard\n",
+			mmc_hostname(card->host),
+			pack_stats->pack_stop_reason[FLUSH_OR_DISCARD]);
+		strlcat(ubuf, temp_buf, cnt);
+	}
+	if (pack_stats->pack_stop_reason[EMPTY_QUEUE]) {
+		snprintf(temp_buf, TEMP_BUF_SIZE,
+			 "%s: %d times: empty queue\n",
+			mmc_hostname(card->host),
+			pack_stats->pack_stop_reason[EMPTY_QUEUE]);
+		strlcat(ubuf, temp_buf, cnt);
+	}
+	if (pack_stats->pack_stop_reason[REL_WRITE]) {
+		snprintf(temp_buf, TEMP_BUF_SIZE,
+			 "%s: %d times: rel write\n",
+			mmc_hostname(card->host),
+			pack_stats->pack_stop_reason[REL_WRITE]);
+		strlcat(ubuf, temp_buf, cnt);
+	}
+	if (pack_stats->pack_stop_reason[THRESHOLD]) {
+		snprintf(temp_buf, TEMP_BUF_SIZE,
+			 "%s: %d times: Threshold\n",
+			mmc_hostname(card->host),
+			pack_stats->pack_stop_reason[THRESHOLD]);
+		strlcat(ubuf, temp_buf, cnt);
+	}
+
+	spin_unlock(&pack_stats->lock);
+
+	kfree(temp_buf);
+
+	pr_info("%s", ubuf);
+
+exit:
+	if (card->wr_pack_stats.print_in_read == 1) {
+		card->wr_pack_stats.print_in_read = 0;
+		return strnlen(ubuf, cnt);
+	}
+
+	return 0;
+}
+
+static ssize_t mmc_wr_pack_stats_write(struct file *filp,
+				       const char __user *ubuf, size_t cnt,
+				       loff_t *ppos)
+{
+	struct mmc_card *card = filp->private_data;
+	int value;
+
+	if (!card)
+		return cnt;
+
+	sscanf(ubuf, "%d", &value);
+	if (value) {
+		mmc_blk_init_packed_statistics(card);
+	} else {
+		spin_lock(&card->wr_pack_stats.lock);
+		card->wr_pack_stats.enabled = false;
+		spin_unlock(&card->wr_pack_stats.lock);
+	}
+
+	return cnt;
+}
+
+static const struct file_operations mmc_dbg_wr_pack_stats_fops = {
+	.open		= mmc_wr_pack_stats_open,
+	.read		= mmc_wr_pack_stats_read,
+	.write		= mmc_wr_pack_stats_write,
+};
+
 void mmc_add_card_debugfs(struct mmc_card *card)
 {
 	struct mmc_host	*host = card->host;
@@ -319,6 +477,12 @@
 					&mmc_dbg_ext_csd_fops))
 			goto err;
 
+	if (mmc_card_mmc(card) && (card->ext_csd.rev >= 6) &&
+	    (card->host->caps2 & MMC_CAP2_PACKED_WR))
+		if (!debugfs_create_file("wr_pack_stats", S_IRUSR, root, card,
+					 &mmc_dbg_wr_pack_stats_fops))
+			goto err;
+
 	return;
 
 err:
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index a162586..ca54265 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -363,33 +363,24 @@
 show_perf(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct mmc_host *host = dev_get_drvdata(dev);
-	int64_t rtime_mmcq, wtime_mmcq, rtime_drv, wtime_drv;
-	unsigned long rbytes_mmcq, wbytes_mmcq, rbytes_drv, wbytes_drv;
+	int64_t rtime_drv, wtime_drv;
+	unsigned long rbytes_drv, wbytes_drv;
 
 	spin_lock(&host->lock);
 
-	rbytes_mmcq = host->perf.rbytes_mmcq;
-	wbytes_mmcq = host->perf.wbytes_mmcq;
 	rbytes_drv = host->perf.rbytes_drv;
 	wbytes_drv = host->perf.wbytes_drv;
 
-	rtime_mmcq = ktime_to_us(host->perf.rtime_mmcq);
-	wtime_mmcq = ktime_to_us(host->perf.wtime_mmcq);
 	rtime_drv = ktime_to_us(host->perf.rtime_drv);
 	wtime_drv = ktime_to_us(host->perf.wtime_drv);
 
 	spin_unlock(&host->lock);
 
-	return snprintf(buf, PAGE_SIZE, "Write performance at MMCQ Level:"
-					"%lu bytes in %lld microseconds\n"
-					"Read performance at MMCQ Level:"
-					"%lu bytes in %lld microseconds\n"
-					"Write performance at driver Level:"
+	return snprintf(buf, PAGE_SIZE, "Write performance at driver Level:"
 					"%lu bytes in %lld microseconds\n"
 					"Read performance at driver Level:"
 					"%lu bytes in %lld microseconds\n",
-					wbytes_mmcq, wtime_mmcq, rbytes_mmcq,
-					rtime_mmcq, wbytes_drv, wtime_drv,
+					wbytes_drv, wtime_drv,
 					rbytes_drv, rtime_drv);
 }
 
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 9385087..169fe68 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -425,6 +425,24 @@
 	}
 
 	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;
@@ -464,6 +482,11 @@
 			ext_csd[EXT_CSD_CACHE_SIZE + 1] << 8 |
 			ext_csd[EXT_CSD_CACHE_SIZE + 2] << 16 |
 			ext_csd[EXT_CSD_CACHE_SIZE + 3] << 24;
+
+		card->ext_csd.max_packed_writes =
+			ext_csd[EXT_CSD_MAX_PACKED_WRITES];
+		card->ext_csd.max_packed_reads =
+			ext_csd[EXT_CSD_MAX_PACKED_READS];
 	}
 
 out:
@@ -1183,6 +1206,43 @@
 		card->ext_csd.cache_ctrl = err ? 0 : 1;
 	}
 
+	if ((host->caps2 & MMC_CAP2_PACKED_CMD) &&
+			(card->ext_csd.max_packed_writes > 0) &&
+			(card->ext_csd.max_packed_reads > 0)) {
+		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+				EXT_CSD_EXP_EVENTS_CTRL,
+				EXT_CSD_PACKED_EVENT_EN,
+				card->ext_csd.generic_cmd6_time);
+		if (err && err != -EBADMSG)
+			goto free_card;
+		if (err) {
+			pr_warning("%s: Enabling packed event failed\n",
+					mmc_hostname(card->host));
+			card->ext_csd.packed_event_en = 0;
+			err = 0;
+		} else {
+			card->ext_csd.packed_event_en = 1;
+		}
+
+	}
+
+	if (!oldcard) {
+		if ((host->caps2 & MMC_CAP2_PACKED_CMD) &&
+		    (card->ext_csd.max_packed_writes > 0)) {
+			/*
+			 * We would like to keep the statistics in an index
+			 * that equals the num of packed requests
+			 * (1 to max_packed_writes)
+			 */
+			card->wr_pack_stats.packing_events = kzalloc(
+				(card->ext_csd.max_packed_writes + 1) *
+				sizeof(*card->wr_pack_stats.packing_events),
+				GFP_KERNEL);
+			if (!card->wr_pack_stats.packing_events)
+				goto free_card;
+		}
+	}
+
 	if (!oldcard)
 		host->card = card;
 
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 2438176..c4cecba 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -334,6 +334,7 @@
 	return mmc_send_cxd_data(card, card->host, MMC_SEND_EXT_CSD,
 			ext_csd, 512);
 }
+EXPORT_SYMBOL_GPL(mmc_send_ext_csd);
 
 int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp)
 {
@@ -391,13 +392,22 @@
 		  (index << 16) |
 		  (value << 8) |
 		  set;
-	cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
+		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.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;
+
 	mmc_delay(1);
 	/* Must check status to be sure of no errors */
 	do {
@@ -556,14 +566,14 @@
 {
 	struct mmc_command cmd = {0};
 	unsigned int opcode;
-	unsigned int flags;
+	unsigned int flags = MMC_CMD_AC;
 	int err;
 
 	opcode = card->ext_csd.hpi_cmd;
 	if (opcode == MMC_STOP_TRANSMISSION)
-		flags = MMC_RSP_R1 | MMC_CMD_AC;
+		flags |= MMC_RSP_R1B;
 	else if (opcode == MMC_SEND_STATUS)
-		flags = MMC_RSP_R1 | MMC_CMD_AC;
+		flags |= MMC_RSP_R1;
 
 	cmd.opcode = opcode;
 	cmd.arg = card->rca << 16 | 1;
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 25195b7..2e6e422 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -376,8 +376,8 @@
 {
 	host->curr.data = NULL;
 	host->curr.got_dataend = 0;
-	host->curr.wait_for_auto_prog_done = 0;
-	host->curr.got_auto_prog_done = 0;
+	host->curr.wait_for_auto_prog_done = false;
+	host->curr.got_auto_prog_done = false;
 	writel_relaxed(readl_relaxed(host->base + MMCIDATACTRL) &
 			(~(MCI_DPSM_ENABLE)), host->base + MMCIDATACTRL);
 	msmsdcc_sync_reg_wr(host); /* Allow the DPSM to be reset */
@@ -1118,7 +1118,7 @@
 	host->curr.xfer_remain = host->curr.xfer_size;
 	host->curr.data_xfered = 0;
 	host->curr.got_dataend = 0;
-	host->curr.got_auto_prog_done = 0;
+	host->curr.got_auto_prog_done = false;
 
 	datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
 
@@ -1167,6 +1167,8 @@
 
 	if (data->flags & MMC_DATA_READ)
 		datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
+	else if (host->curr.use_wr_data_pend)
+		datactrl |= MCI_DATA_PEND;
 
 	clks = (unsigned long long)data->timeout_ns * host->clk_rate;
 	do_div(clks, 1000000000UL);
@@ -1612,6 +1614,14 @@
 		cmd->error = -EILSEQ;
 	}
 
+	if (!cmd->error) {
+		if (cmd->cmd_timeout_ms > host->curr.req_tout_ms) {
+			host->curr.req_tout_ms = cmd->cmd_timeout_ms;
+			mod_timer(&host->req_tout_timer, (jiffies +
+				  msecs_to_jiffies(host->curr.req_tout_ms)));
+		}
+	}
+
 	if (!cmd->data || cmd->error) {
 		if (host->curr.data && host->dma.sg &&
 			host->is_dma_mode)
@@ -1634,7 +1644,7 @@
 					host->curr.cmd = cmd;
 			} else {
 				host->prog_enable = 0;
-				host->curr.wait_for_auto_prog_done = 0;
+				host->curr.wait_for_auto_prog_done = false;
 				if (host->dummy_52_needed)
 					host->dummy_52_needed = 0;
 				if (cmd->data && cmd->error)
@@ -1642,13 +1652,11 @@
 				msmsdcc_request_end(host, cmd->mrq);
 			}
 		}
-	} else if ((cmd == host->curr.mrq->sbc) && cmd->data) {
-		if (cmd->data->flags & MMC_DATA_READ)
-			msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
-		else
-			msmsdcc_request_start(host, host->curr.mrq);
 	} else if (cmd->data) {
-		if (!(cmd->data->flags & MMC_DATA_READ))
+		if (cmd == host->curr.mrq->sbc)
+			msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
+		else if ((cmd->data->flags & MMC_DATA_WRITE) &&
+			   !host->curr.use_wr_data_pend)
 			msmsdcc_start_data(host, cmd->data, NULL, 0);
 	}
 }
@@ -1691,14 +1699,17 @@
 			 * will take care of signaling sdio irq during
 			 * mmc_sdio_resume().
 			 */
-			if (host->sdcc_suspended)
+			if (host->sdcc_suspended) {
 				/*
 				 * This is a wakeup interrupt so hold wakelock
 				 * until SDCC resume is handled.
 				 */
 				wake_lock(&host->sdio_wlock);
-			else
+			} else {
+				spin_unlock(&host->lock);
 				mmc_signal_sdio_irq(host->mmc);
+				spin_lock(&host->lock);
+			}
 			ret = 1;
 			break;
 		}
@@ -1725,7 +1736,9 @@
 		if (status & MCI_SDIOINTROPE) {
 			if (host->sdcc_suspending)
 				wake_lock(&host->sdio_suspend_wlock);
+			spin_unlock(&host->lock);
 			mmc_signal_sdio_irq(host->mmc);
+			spin_lock(&host->lock);
 		}
 		data = host->curr.data;
 
@@ -1795,7 +1808,7 @@
 			/* Check for prog done */
 			if (host->curr.wait_for_auto_prog_done &&
 				(status & MCI_PROGDONE))
-				host->curr.got_auto_prog_done = 1;
+				host->curr.got_auto_prog_done = true;
 
 			/* Check for data done */
 			if (!host->curr.got_dataend && (status & MCI_DATAEND))
@@ -1924,12 +1937,17 @@
 static void
 msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
 {
-	if (mrq->data && mrq->data->flags & MMC_DATA_READ) {
+	if (mrq->data) {
 		/* Queue/read data, daisy-chain command when data starts */
-		if (mrq->sbc)
-			msmsdcc_start_data(host, mrq->data, mrq->sbc, 0);
+		if ((mrq->data->flags & MMC_DATA_READ) ||
+		    host->curr.use_wr_data_pend)
+			msmsdcc_start_data(host, mrq->data,
+					   mrq->sbc ? mrq->sbc : mrq->cmd,
+					   0);
 		else
-			msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
+			msmsdcc_start_command(host,
+					      mrq->sbc ? mrq->sbc : mrq->cmd,
+					      0);
 	} else {
 		msmsdcc_start_command(host, mrq->cmd, 0);
 	}
@@ -1939,7 +1957,7 @@
 msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
 {
 	struct msmsdcc_host *host = mmc_priv(mmc);
-	unsigned long		flags, timeout;
+	unsigned long		flags;
 
 	/*
 	 * Get the SDIO AL client out of LPM.
@@ -1996,50 +2014,40 @@
 	 * Set timeout value to 10 secs (or more in case of buggy cards)
 	 */
 	if ((mmc->card) && (mmc->card->quirks & MMC_QUIRK_INAND_DATA_TIMEOUT))
-		timeout = 20000;
+		host->curr.req_tout_ms = 20000;
 	else
-		timeout = MSM_MMC_REQ_TIMEOUT;
+		host->curr.req_tout_ms = MSM_MMC_REQ_TIMEOUT;
 	/*
 	 * Kick the software request timeout timer here with the timeout
 	 * value identified above
 	 */
 	mod_timer(&host->req_tout_timer,
-			(jiffies + msecs_to_jiffies(timeout)));
+			(jiffies +
+			 msecs_to_jiffies(host->curr.req_tout_ms)));
 
 	host->curr.mrq = mrq;
-	if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
-		if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
-			mrq->cmd->opcode == 54) {
-			if (!host->sdcc_version)
-				host->dummy_52_needed = 1;
-			else
-				/*
-				 * SDCCv4 supports AUTO_PROG_DONE bit for SDIO
-				 * write operations using CMD53 and CMD54.
-				 * Setting this bit with CMD53 would
-				 * automatically triggers PROG_DONE interrupt
-				 * without the need of sending dummy CMD52.
-				 */
-				host->curr.wait_for_auto_prog_done = 1;
-		} else if (mrq->cmd->opcode == MMC_WRITE_BLOCK &&
-				host->sdcc_version) {
-			host->curr.wait_for_auto_prog_done = 1;
-		}
-	}
-
-	if (mrq->data && mrq->sbc) {
+	if (mrq->sbc) {
 		mrq->sbc->mrq = mrq;
 		mrq->sbc->data = mrq->data;
-		if (mrq->data->flags & MMC_DATA_WRITE) {
-			host->curr.wait_for_auto_prog_done = 1;
-			msmsdcc_start_command(host, mrq->sbc, 0);
-		} else {
-			msmsdcc_request_start(host, mrq);
-		}
-	} else {
-		msmsdcc_request_start(host, mrq);
 	}
 
+	if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
+		if (host->sdcc_version) {
+			if (!mrq->stop)
+				host->curr.wait_for_auto_prog_done = true;
+		} else {
+			if ((mrq->cmd->opcode == SD_IO_RW_EXTENDED) ||
+			    (mrq->cmd->opcode == 54))
+				host->dummy_52_needed = 1;
+		}
+
+		if ((mrq->cmd->opcode == MMC_WRITE_BLOCK) ||
+		    (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK))
+			host->curr.use_wr_data_pend = true;
+	}
+
+	msmsdcc_request_start(host, mrq);
+
 	spin_unlock_irqrestore(&host->lock, flags);
 }
 
@@ -3102,15 +3110,14 @@
 	 * clocks mci_irqenable will be written to MASK0 register.
 	 */
 
+	spin_lock_irqsave(&host->lock, flags);
 	if (enable) {
-		spin_lock_irqsave(&host->lock, flags);
 		host->mci_irqenable |= MCI_SDIOINTOPERMASK;
 		if (host->clks_on) {
 			writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
 				MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
 			mb();
 		}
-		spin_unlock_irqrestore(&host->lock, flags);
 	} else {
 		host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
 		if (host->clks_on) {
@@ -3119,6 +3126,7 @@
 			mb();
 		}
 	}
+	spin_unlock_irqrestore(&host->lock, flags);
 }
 
 #ifdef CONFIG_PM_RUNTIME
@@ -3931,10 +3939,13 @@
 	}
 	if (host->plat->is_sdio_al_client) {
 		wake_lock(&host->sdio_wlock);
+		spin_unlock(&host->lock);
 		mmc_signal_sdio_irq(host->mmc);
+		goto out_unlocked;
 	}
 	spin_unlock(&host->lock);
 
+out_unlocked:
 	return IRQ_HANDLED;
 }
 
@@ -4370,7 +4381,7 @@
 }
 
 static ssize_t
-set_polling(struct device *dev, struct device_attribute *attr,
+store_polling(struct device *dev, struct device_attribute *attr,
 		const char *buf, size_t count)
 {
 	struct mmc_host *mmc = dev_get_drvdata(dev);
@@ -4394,9 +4405,6 @@
 	return count;
 }
 
-static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
-		show_polling, set_polling);
-
 static ssize_t
 show_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
 			char *buf)
@@ -4409,7 +4417,7 @@
 }
 
 static ssize_t
-set_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
+store_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
 		const char *buf, size_t count)
 {
 	struct mmc_host *mmc = dev_get_drvdata(dev);
@@ -4426,20 +4434,6 @@
 	return count;
 }
 
-static DEVICE_ATTR(max_bus_bw, S_IRUGO | S_IWUSR,
-		show_sdcc_to_mem_max_bus_bw, set_sdcc_to_mem_max_bus_bw);
-
-static struct attribute *dev_attrs[] = {
-	&dev_attr_max_bus_bw.attr,
-	/* if polling is enabled, this will be filled with dev_attr_polling */
-	NULL,
-	NULL,
-};
-
-static struct attribute_group dev_attr_grp = {
-	.attrs = dev_attrs,
-};
-
 #ifdef CONFIG_HAS_EARLYSUSPEND
 static void msmsdcc_early_suspend(struct early_suspend *h)
 {
@@ -4524,10 +4518,11 @@
 	}
 
 	pr_info("%s: got_dataend=%d, prog_enable=%d,"
-		" wait_for_auto_prog_done=%d, got_auto_prog_done=%d\n",
-		mmc_hostname(host->mmc), host->curr.got_dataend,
-		host->prog_enable, host->curr.wait_for_auto_prog_done,
-		host->curr.got_auto_prog_done);
+		" wait_for_auto_prog_done=%d, got_auto_prog_done=%d,"
+		" req_tout_ms=%d\n", mmc_hostname(host->mmc),
+		host->curr.got_dataend, host->prog_enable,
+		host->curr.wait_for_auto_prog_done,
+		host->curr.got_auto_prog_done, host->curr.req_tout_ms);
 	msmsdcc_print_rpm_info(host);
 }
 
@@ -4574,7 +4569,7 @@
 			}
 		} else {
 			host->prog_enable = 0;
-			host->curr.wait_for_auto_prog_done = 0;
+			host->curr.wait_for_auto_prog_done = false;
 			msmsdcc_reset_and_restore(host);
 			msmsdcc_request_end(host, mrq);
 		}
@@ -4998,7 +4993,11 @@
 		mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
 				MMC_CAP_SET_XPC_180);
 
+	mmc->caps2 |= MMC_CAP2_PACKED_WR;
+	mmc->caps2 |= MMC_CAP2_PACKED_WR_CONTROL;
 	mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_DETECT_ON_ERR);
+	mmc->caps2 |= MMC_CAP2_SANITIZE;
+
 	if (pdev->dev.of_node) {
 		if (of_get_property((&pdev->dev)->of_node,
 					"qcom,sdcc-hs200", NULL))
@@ -5009,6 +5008,8 @@
 		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;
 
@@ -5194,14 +5195,30 @@
 #if defined(CONFIG_DEBUG_FS)
 	msmsdcc_dbg_createhost(host);
 #endif
-	if (!plat->status_irq)
-		dev_attrs[1] = &dev_attr_polling.attr;
 
-	ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
+	host->max_bus_bw.show = show_sdcc_to_mem_max_bus_bw;
+	host->max_bus_bw.store = store_sdcc_to_mem_max_bus_bw;
+	sysfs_attr_init(&host->max_bus_bw.attr);
+	host->max_bus_bw.attr.name = "max_bus_bw";
+	host->max_bus_bw.attr.mode = S_IRUGO | S_IWUSR;
+	ret = device_create_file(&pdev->dev, &host->max_bus_bw);
 	if (ret)
 		goto platform_irq_free;
+
+	if (!plat->status_irq) {
+		host->polling.show = show_polling;
+		host->polling.store = store_polling;
+		sysfs_attr_init(&host->polling.attr);
+		host->polling.attr.name = "polling";
+		host->polling.attr.mode = S_IRUGO | S_IWUSR;
+		ret = device_create_file(&pdev->dev, &host->polling);
+		if (ret)
+			goto remove_max_bus_bw_file;
+	}
 	return 0;
 
+ remove_max_bus_bw_file:
+	device_remove_file(&pdev->dev, &host->max_bus_bw);
  platform_irq_free:
 	del_timer_sync(&host->req_tout_timer);
 	pm_runtime_disable(&(pdev)->dev);
@@ -5278,8 +5295,9 @@
 	DBG(host, "Removing SDCC device = %d\n", pdev->id);
 	plat = host->plat;
 
+	device_remove_file(&pdev->dev, &host->max_bus_bw);
 	if (!plat->status_irq)
-		sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
+		device_remove_file(&pdev->dev, &host->polling);
 
 	del_timer_sync(&host->req_tout_timer);
 	tasklet_kill(&host->dma_tlet);
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index e29ed91..ef1e05f 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -78,6 +78,7 @@
 #define MCI_DPSM_DIRECTION	(1 << 1)
 #define MCI_DPSM_MODE		(1 << 2)
 #define MCI_DPSM_DMAENABLE	(1 << 3)
+#define MCI_DATA_PEND		(1 << 17)
 #define MCI_AUTO_PROG_DONE	(1 << 19)
 #define MCI_RX_DATA_PEND	(1 << 20)
 
@@ -292,9 +293,11 @@
 	unsigned int		xfer_remain;	/* Bytes remaining to send */
 	unsigned int		data_xfered;	/* Bytes acked by BLKEND irq */
 	int			got_dataend;
-	int			wait_for_auto_prog_done;
-	int			got_auto_prog_done;
+	bool			wait_for_auto_prog_done;
+	bool			got_auto_prog_done;
+	bool			use_wr_data_pend;
 	int			user_pages;
+	u32			req_tout_ms;
 };
 
 struct msmsdcc_sps_ep_conn_data {
@@ -408,6 +411,8 @@
 	struct mutex clk_mutex;
 	bool pending_resume;
 	struct msmsdcc_msm_bus_vote msm_bus_vote;
+	struct device_attribute	max_bus_bw;
+	struct device_attribute	polling;
 };
 
 int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave);
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index dedf3da..e13b5c3 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -1437,6 +1437,8 @@
 			dto -= 13;
 		else
 			dto = 0;
+		/* Use the maximum timeout value allowed in the standard of 14
+		   or 0xE */
 		if (dto > 14)
 			dto = 14;
 	}
diff --git a/drivers/mtd/devices/msm_nand.c b/drivers/mtd/devices/msm_nand.c
index 3675d2c..798e9e2 100644
--- a/drivers/mtd/devices/msm_nand.c
+++ b/drivers/mtd/devices/msm_nand.c
@@ -76,6 +76,8 @@
 	uint32_t ecc_bch_cfg;
 	uint32_t ecc_parity_bytes;
 	unsigned cw_size;
+	unsigned int uncorrectable_bit_mask;
+	unsigned int num_err_mask;
 };
 
 #define CFG1_WIDE_FLASH (1U << 1)
@@ -1111,9 +1113,8 @@
 		}
 		if (pageerr) {
 			for (n = start_sector; n < cwperpage; n++) {
-				if (enable_bch_ecc ?
-			(dma_buffer->data.result[n].buffer_status & 0x10) :
-			(dma_buffer->data.result[n].buffer_status & 0x8)) {
+				if (dma_buffer->data.result[n].buffer_status &
+					chip->uncorrectable_bit_mask) {
 					/* not thread safe */
 					mtd->ecc_stats.failed++;
 					pageerr = -EBADMSG;
@@ -1123,9 +1124,9 @@
 		}
 		if (!rawerr) { /* check for corretable errors */
 			for (n = start_sector; n < cwperpage; n++) {
-				ecc_errors = enable_bch_ecc ?
-			(dma_buffer->data.result[n].buffer_status & 0xF) :
-			(dma_buffer->data.result[n].buffer_status & 0x7);
+				ecc_errors =
+				(dma_buffer->data.result[n].buffer_status
+				 & chip->num_err_mask);
 				if (ecc_errors) {
 					total_ecc_errors += ecc_errors;
 					/* not thread safe */
@@ -1893,7 +1894,7 @@
 		if (pageerr) {
 			for (n = start_sector; n < cwperpage; n++) {
 				if (dma_buffer->data.result[n].buffer_status
-					& MSM_NAND_BUF_STAT_UNCRCTBL_ERR) {
+					& chip->uncorrectable_bit_mask) {
 					/* not thread safe */
 					mtd->ecc_stats.failed++;
 					pageerr = -EBADMSG;
@@ -1905,7 +1906,7 @@
 			for (n = start_sector; n < cwperpage; n++) {
 				ecc_errors = dma_buffer->data.
 					result[n].buffer_status
-					& MSM_NAND_BUF_STAT_NUM_ERR_MASK;
+					& chip->num_err_mask;
 				if (ecc_errors) {
 					total_ecc_errors += ecc_errors;
 					/* not thread safe */
@@ -7043,6 +7044,15 @@
 	pr_info("%s: allocated dma buffer at %p, dma_addr %x\n",
 		__func__, info->msm_nand.dma_buffer, info->msm_nand.dma_addr);
 
+	/* Let default be VERSION_1 for backward compatibility */
+	info->msm_nand.uncorrectable_bit_mask = BIT(3);
+	info->msm_nand.num_err_mask = 0x7;
+
+	if (plat_data && (plat_data->version == VERSION_2)) {
+		info->msm_nand.uncorrectable_bit_mask = BIT(8);
+		info->msm_nand.num_err_mask = 0x1F;
+	}
+
 	info->mtd.name = dev_name(&pdev->dev);
 	info->mtd.priv = &info->msm_nand;
 	info->mtd.owner = THIS_MODULE;
diff --git a/drivers/mtd/devices/msm_nand.h b/drivers/mtd/devices/msm_nand.h
index 2729c6b..8156b92 100644
--- a/drivers/mtd/devices/msm_nand.h
+++ b/drivers/mtd/devices/msm_nand.h
@@ -187,9 +187,6 @@
 #define EBI2_CFG_REG		       	EBI2_REG(0x0004)
 #define EBI2_NAND_ADM_MUX       	EBI2_REG(0x005C)
 
-#define MSM_NAND_BUF_STAT_UNCRCTBL_ERR	(1 << 8)
-#define MSM_NAND_BUF_STAT_NUM_ERR_MASK	(enable_bch_ecc ? 0x1F : 0x0F)
-
 extern struct flash_platform_data msm_nand_data;
 
 #endif
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 8aab269..44041b8 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -3466,6 +3466,15 @@
 	  for routing IP packets within the MSM using
 	  BAM as a physical transport.
 
+config MSM_RMNET_SMUX
+	bool "RMNET SMUX Driver"
+	depends on N_SMUX
+	help
+	  Implements RMNET over SMUX interface.
+	  RMNET provides a virtual ethernet interface
+	  for routing IP packets within the MSM using
+	  HSUART as a physical transport.
+
 config MSM_RMNET_DEBUG
 	bool "MSM RMNET debug interface"
 	depends on MSM_RMNET
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 7b3cd59..7373a61 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -304,6 +304,7 @@
 obj-$(CONFIG_MSM_RMNET) += msm_rmnet.o
 obj-$(CONFIG_MSM_RMNET_SDIO) += msm_rmnet_sdio.o
 obj-$(CONFIG_MSM_RMNET_BAM) += msm_rmnet_bam.o
+obj-$(CONFIG_MSM_RMNET_SMUX) += msm_rmnet_smux.o
 
 obj-$(CONFIG_NIU) += niu.o
 obj-$(CONFIG_VIRTIO_NET) += virtio_net.o
diff --git a/drivers/net/msm_rmnet_smux.c b/drivers/net/msm_rmnet_smux.c
new file mode 100644
index 0000000..70e7182
--- /dev/null
+++ b/drivers/net/msm_rmnet_smux.c
@@ -0,0 +1,944 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+/*
+ * RMNET SMUX Module.
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/wakelock.h>
+#include <linux/if_arp.h>
+#include <linux/msm_rmnet.h>
+#include <linux/platform_device.h>
+#include <linux/smux.h>
+#include <linux/ip.h>
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
+
+
+/* Debug message support */
+static int msm_rmnet_smux_debug_mask;
+module_param_named(debug_enable, msm_rmnet_smux_debug_mask,
+				   int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+#define DEBUG_MASK_LVL0 (1U << 0)
+#define DEBUG_MASK_LVL1 (1U << 1)
+#define DEBUG_MASK_LVL2 (1U << 2)
+
+#define DBG(m, x...) do {			   \
+		if (msm_rmnet_smux_debug_mask & m) \
+			pr_info(x);		   \
+} while (0)
+
+#define DBG0(x...) DBG(DEBUG_MASK_LVL0, x)
+#define DBG1(x...) DBG(DEBUG_MASK_LVL1, x)
+#define DBG2(x...) DBG(DEBUG_MASK_LVL2, x)
+
+/* Configure device instances */
+#define RMNET_SMUX_DEVICE_COUNT (1)
+
+/* allow larger frames */
+#define RMNET_DATA_LEN 2000
+
+#define DEVICE_ID_INVALID   -1
+
+#define DEVICE_INACTIVE     0x00
+#define DEVICE_ACTIVE       0x01
+
+#define HEADROOM_FOR_SMUX    8 /* for mux header */
+#define HEADROOM_FOR_QOS     8
+#define TAILROOM             8 /* for padding by mux layer */
+
+struct rmnet_private {
+	struct net_device_stats stats;
+	uint32_t ch_id;
+#ifdef CONFIG_MSM_RMNET_DEBUG
+	ktime_t last_packet;
+	unsigned long wakeups_xmit;
+	unsigned long wakeups_rcv;
+	unsigned long timeout_us;
+#endif
+	spinlock_t lock;
+	struct tasklet_struct tsklt;
+	/* IOCTL specified mode (protocol, QoS header) */
+	u32 operation_mode;
+	uint8_t device_state;
+	uint8_t in_reset;
+};
+
+static struct net_device *netdevs[RMNET_SMUX_DEVICE_COUNT];
+
+#ifdef CONFIG_MSM_RMNET_DEBUG
+static unsigned long timeout_us;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+/*
+ * If early suspend is enabled then we specify two timeout values,
+ * screen on (default), and screen is off.
+ */
+static unsigned long timeout_suspend_us;
+static struct device *rmnet0;
+
+/* Set timeout in us when the screen is off. */
+static ssize_t timeout_suspend_store(struct device *d,
+				     struct device_attribute *attr,
+				     const char *buf, size_t n)
+{
+	timeout_suspend_us = strict_strtoul(buf, NULL, 10);
+	return n;
+}
+
+static ssize_t timeout_suspend_show(struct device *d,
+				    struct device_attribute *attr,
+				    char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%lu\n",
+			(unsigned long) timeout_suspend_us);
+}
+
+static DEVICE_ATTR(timeout_suspend, 0664, timeout_suspend_show,
+				   timeout_suspend_store);
+
+static void rmnet_early_suspend(struct early_suspend *handler)
+{
+	if (rmnet0) {
+		struct rmnet_private *p = netdev_priv(to_net_dev(rmnet0));
+		p->timeout_us = timeout_suspend_us;
+	}
+}
+
+static void rmnet_late_resume(struct early_suspend *handler)
+{
+	if (rmnet0) {
+		struct rmnet_private *p = netdev_priv(to_net_dev(rmnet0));
+		p->timeout_us = timeout_us;
+	}
+}
+
+static struct early_suspend rmnet_power_suspend = {
+	.suspend = rmnet_early_suspend,
+	.resume = rmnet_late_resume,
+};
+
+static int __init rmnet_late_init(void)
+{
+	register_early_suspend(&rmnet_power_suspend);
+	return 0;
+}
+
+late_initcall(rmnet_late_init);
+#endif /* CONFIG_HAS_EARLYSUSPEND */
+
+/* Returns 1 if packet caused rmnet to wakeup, 0 otherwise. */
+static int rmnet_cause_wakeup(struct rmnet_private *p)
+{
+	int ret = 0;
+	ktime_t now;
+	if (p->timeout_us == 0)	/* Check if disabled */
+		return 0;
+
+	/* Use real (wall) time. */
+	now = ktime_get_real();
+
+	if (ktime_us_delta(now, p->last_packet) > p->timeout_us)
+		ret = 1;
+
+	p->last_packet = now;
+	return ret;
+}
+
+static ssize_t wakeups_xmit_show(struct device *d,
+				 struct device_attribute *attr,
+				 char *buf)
+{
+	struct rmnet_private *p = netdev_priv(to_net_dev(d));
+	return snprintf(buf, PAGE_SIZE, "%lu\n", p->wakeups_xmit);
+}
+
+DEVICE_ATTR(wakeups_xmit, 0444, wakeups_xmit_show, NULL);
+
+static ssize_t wakeups_rcv_show(struct device *d,
+				struct device_attribute *attr,
+				char *buf)
+{
+	struct rmnet_private *p = netdev_priv(to_net_dev(d));
+	return snprintf(buf, PAGE_SIZE, "%lu\n", p->wakeups_rcv);
+}
+
+DEVICE_ATTR(wakeups_rcv, 0444, wakeups_rcv_show, NULL);
+
+/* Set timeout in us. */
+static ssize_t timeout_store(struct device *d,
+			     struct device_attribute *attr,
+			     const char *buf, size_t n)
+{
+#ifndef CONFIG_HAS_EARLYSUSPEND
+	struct rmnet_private *p = netdev_priv(to_net_dev(d));
+	p->timeout_us = timeout_us = strict_strtoul(buf, NULL, 10);
+#else
+/* If using early suspend/resume hooks do not write the value on store. */
+	timeout_us = strict_strtoul(buf, NULL, 10);
+#endif /* CONFIG_HAS_EARLYSUSPEND */
+	return n;
+}
+
+static ssize_t timeout_show(struct device *d,
+			    struct device_attribute *attr,
+			    char *buf)
+{
+	struct rmnet_private *p = netdev_priv(to_net_dev(d));
+	p = netdev_priv(to_net_dev(d));
+	return snprintf(buf, PAGE_SIZE, "%lu\n", timeout_us);
+}
+
+DEVICE_ATTR(timeout, 0664, timeout_show, timeout_store);
+#endif /* CONFIG_MSM_RMNET_DEBUG */
+
+/* Forward declaration */
+static int rmnet_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
+
+
+
+
+static int count_this_packet(void *_hdr, int len)
+{
+	struct ethhdr *hdr = _hdr;
+
+	if (len >= ETH_HLEN && hdr->h_proto == htons(ETH_P_ARP))
+		return 0;
+
+	return 1;
+}
+
+static __be16 rmnet_ip_type_trans(struct sk_buff *skb, struct net_device *dev)
+{
+	__be16 protocol = 0;
+
+	skb->dev = dev;
+
+	/* Determine L3 protocol */
+	switch (skb->data[0] & 0xf0) {
+	case 0x40:
+		protocol = htons(ETH_P_IP);
+		break;
+	case 0x60:
+		protocol = htons(ETH_P_IPV6);
+		break;
+	default:
+		pr_err("[%s] rmnet_recv() L3 protocol decode error: 0x%02x",
+			   dev->name, skb->data[0] & 0xf0);
+		/* skb will be dropped in upper layer for unknown protocol */
+	}
+	return protocol;
+}
+
+static void smux_read_done(void *rcv_dev, const void *meta_data)
+{
+	struct rmnet_private *p;
+	struct net_device *dev = rcv_dev;
+	u32 opmode;
+	unsigned long flags;
+	struct sk_buff *skb = NULL;
+	const struct smux_meta_read  *read_meta_info = meta_data;
+
+	if (!dev || !read_meta_info) {
+		DBG1("%s:invalid read_done callback recieved", __func__);
+		return;
+	}
+
+	p = netdev_priv(dev);
+
+	skb = (struct sk_buff *) read_meta_info->pkt_priv;
+
+	if (!skb || skb->dev != dev) {
+		DBG1("%s: ERR:skb pointer NULL in READ_DONE CALLBACK",
+		      __func__);
+		return;
+	}
+
+	/* Handle Rx frame format */
+	spin_lock_irqsave(&p->lock, flags);
+	opmode = p->operation_mode;
+	spin_unlock_irqrestore(&p->lock, flags);
+
+	if (RMNET_IS_MODE_IP(opmode)) {
+		/* Driver in IP mode */
+		skb->protocol =
+		rmnet_ip_type_trans(skb, dev);
+	} else {
+		/* Driver in Ethernet mode */
+		skb->protocol =
+		eth_type_trans(skb, dev);
+	}
+	if (RMNET_IS_MODE_IP(opmode) ||
+		count_this_packet(skb->data, skb->len)) {
+#ifdef CONFIG_MSM_RMNET_DEBUG
+		p->wakeups_rcv +=
+		rmnet_cause_wakeup(p);
+#endif
+		p->stats.rx_packets++;
+		p->stats.rx_bytes += skb->len;
+	}
+	DBG2("[%s] Rx packet #%lu len=%d\n",
+		 dev->name, p->stats.rx_packets,
+		 skb->len);
+	/* Deliver to network stack */
+	netif_rx(skb);
+
+	return;
+}
+
+static void smux_write_done(void *dev, const void *meta_data)
+{
+	struct rmnet_private *p = netdev_priv(dev);
+	u32 opmode;
+	struct sk_buff *skb = NULL;
+	const struct smux_meta_write  *write_meta_info = meta_data;
+	unsigned long flags;
+
+	if (!dev || !write_meta_info) {
+		DBG1("%s: ERR:invalid WRITE_DONE callback recieved", __func__);
+		return;
+	}
+
+	skb = (struct sk_buff *) write_meta_info->pkt_priv;
+
+	if (!skb) {
+		DBG1("%s: ERR:skb pointer NULL in WRITE_DONE"
+		     " CALLBACK", __func__);
+		return;
+	}
+
+	spin_lock_irqsave(&p->lock, flags);
+	opmode = p->operation_mode;
+	spin_unlock_irqrestore(&p->lock, flags);
+
+	DBG1("%s: write complete\n", __func__);
+	if (RMNET_IS_MODE_IP(opmode) ||
+		count_this_packet(skb->data, skb->len)) {
+		p->stats.tx_packets++;
+		p->stats.tx_bytes += skb->len;
+#ifdef CONFIG_MSM_RMNET_DEBUG
+		p->wakeups_xmit += rmnet_cause_wakeup(p);
+#endif
+	}
+	DBG1("[%s] Tx packet #%lu len=%d mark=0x%x\n",
+		 ((struct net_device *)(dev))->name, p->stats.tx_packets,
+		 skb->len, skb->mark);
+	dev_kfree_skb_any(skb);
+	if (netif_queue_stopped(dev) &&
+		msm_smux_is_ch_low(p->ch_id)) {
+		DBG0("%s: Low WM hit, waking queue=%p\n",
+			 __func__, skb);
+		netif_wake_queue(dev);
+	}
+}
+
+void rmnet_smux_notify(void *priv, int event_type, const void *metadata)
+{
+	struct rmnet_private *p;
+	struct net_device *dev;
+	unsigned long flags;
+	struct sk_buff *skb = NULL;
+	u32 opmode;
+	const struct smux_meta_disconnected *ssr_info;
+	const struct smux_meta_read *read_meta_info;
+	const struct smux_meta_write *write_meta_info = metadata;
+
+
+	if (!priv)
+		DBG0("%s: priv(cookie) NULL, ignoring notification:"
+		     " %d\n", __func__, event_type);
+
+	switch (event_type) {
+	case SMUX_CONNECTED:
+		p = netdev_priv(priv);
+		dev = priv;
+
+		DBG0("[%s] SMUX_CONNECTED event dev:%s\n", __func__, dev->name);
+
+		netif_carrier_on(dev);
+		netif_start_queue(dev);
+
+		spin_lock_irqsave(&p->lock, flags);
+		p->device_state = DEVICE_ACTIVE;
+		spin_unlock_irqrestore(&p->lock, flags);
+		break;
+
+	case SMUX_DISCONNECTED:
+		p = netdev_priv(priv);
+		dev = priv;
+		ssr_info = metadata;
+
+		DBG0("[%s] SMUX_DISCONNECTED event dev:%s\n",
+		      __func__, dev->name);
+
+		if (ssr_info && ssr_info->is_ssr == 1)
+			DBG0("SSR detected on :%s\n", dev->name);
+
+		netif_carrier_off(dev);
+		netif_stop_queue(dev);
+
+		spin_lock_irqsave(&p->lock, flags);
+		p->device_state = DEVICE_INACTIVE;
+		spin_unlock_irqrestore(&p->lock, flags);
+		break;
+
+	case SMUX_READ_DONE:
+		smux_read_done(priv, metadata);
+		break;
+
+	case SMUX_READ_FAIL:
+		p = netdev_priv(priv);
+		dev = priv;
+		read_meta_info = metadata;
+
+		if (!dev || !read_meta_info) {
+			DBG1("%s: ERR:invalid read failed callback"
+			     " recieved", __func__);
+			return;
+		}
+
+		skb = (struct sk_buff *) read_meta_info->pkt_priv;
+
+		if (!skb) {
+			DBG1("%s: ERR:skb pointer NULL in read fail"
+			     " CALLBACK", __func__);
+			return;
+		}
+
+		DBG0("%s: read failed\n", __func__);
+
+		opmode = p->operation_mode;
+
+		if (RMNET_IS_MODE_IP(opmode) ||
+		    count_this_packet(skb->data, skb->len))
+			p->stats.rx_dropped++;
+
+		dev_kfree_skb_any(skb);
+		break;
+
+	case SMUX_WRITE_DONE:
+		smux_write_done(priv, metadata);
+		break;
+
+	case SMUX_WRITE_FAIL:
+		p = netdev_priv(priv);
+		dev = priv;
+		write_meta_info = metadata;
+
+		if (!dev || !write_meta_info) {
+			DBG1("%s: ERR:invalid WRITE_DONE"
+			     "callback recieved", __func__);
+			return;
+		}
+
+		skb = (struct sk_buff *) write_meta_info->pkt_priv;
+
+		if (!skb) {
+			DBG1("%s: ERR:skb pointer NULL in"
+			     " WRITE_DONE CALLBACK", __func__);
+			return;
+		}
+
+		DBG0("%s: write failed\n", __func__);
+
+		opmode = p->operation_mode;
+
+		if (RMNET_IS_MODE_IP(opmode) ||
+		    count_this_packet(skb->data, skb->len)) {
+			p->stats.tx_dropped++;
+		}
+
+		dev_kfree_skb_any(skb);
+		break;
+
+	case SMUX_LOW_WM_HIT:
+		dev = priv;
+		DBG0("[%s] Low WM hit dev:%s\n", __func__, dev->name);
+		netif_start_queue(dev);
+		break;
+
+	case SMUX_HIGH_WM_HIT:
+		dev = priv;
+		DBG0("[%s] Low WM hit dev:%s\n", __func__, dev->name);
+		netif_stop_queue(dev);
+		break;
+
+	default:
+		dev = priv;
+		DBG0("[%s] Invalid event:%d received on"
+		     " dev: %s\n", __func__, event_type, dev->name);
+		break;
+	}
+
+	return;
+}
+
+int get_rx_buffers(void *priv, void **pkt_priv, void **buffer, int size)
+{
+	struct net_device *dev = (struct net_device *) priv;
+	struct sk_buff *skb = NULL;
+	void *ptr = NULL;
+
+	DBG0("[%s] dev:%s\n", __func__, dev->name);
+	skb = __dev_alloc_skb(size, GFP_ATOMIC);
+	if (skb == NULL) {
+		DBG0("%s: unable to alloc skb\n", __func__);
+		return -ENOMEM;
+	}
+
+	/* TODO skb_reserve(skb, NET_IP_ALIGN); for ethernet mode */
+	/* Populate some params now. */
+	skb->dev = dev;
+	ptr = skb_put(skb, size);
+
+	skb_set_network_header(skb, 0);
+
+	/* done with skb setup, return the buffer pointer. */
+	*pkt_priv = skb;
+	*buffer = ptr;
+
+	return 0;
+}
+
+static int __rmnet_open(struct net_device *dev)
+{
+	struct rmnet_private *p = netdev_priv(dev);
+
+	DBG0("[%s] __rmnet_open()\n", dev->name);
+
+	if (p->device_state == DEVICE_ACTIVE) {
+		return 0;
+	} else {
+		DBG0("[%s] Platform inactive\n", dev->name);
+		return -ENODEV;
+	}
+}
+
+static int rmnet_open(struct net_device *dev)
+{
+	int rc = 0;
+
+	DBG0("[%s] rmnet_open()\n", dev->name);
+
+	rc = __rmnet_open(dev);
+
+	if (rc == 0)
+		netif_start_queue(dev);
+
+	return rc;
+}
+
+static int rmnet_stop(struct net_device *dev)
+{
+	DBG0("[%s] rmnet_stop()\n", dev->name);
+
+	netif_stop_queue(dev);
+	return 0;
+}
+
+static int rmnet_change_mtu(struct net_device *dev, int new_mtu)
+{
+	if (0 > new_mtu || RMNET_DATA_LEN < new_mtu)
+		return -EINVAL;
+
+	DBG0("[%s] MTU change: old=%d new=%d\n",
+		 dev->name, dev->mtu, new_mtu);
+	dev->mtu = new_mtu;
+
+	return 0;
+}
+
+static int _rmnet_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct rmnet_private *p = netdev_priv(dev);
+	int smux_ret;
+	struct QMI_QOS_HDR_S *qmih;
+	u32 opmode;
+	unsigned long flags;
+
+	/* For QoS mode, prepend QMI header and assign flow ID from skb->mark */
+	spin_lock_irqsave(&p->lock, flags);
+	opmode = p->operation_mode;
+	spin_unlock_irqrestore(&p->lock, flags);
+
+	if (RMNET_IS_MODE_QOS(opmode)) {
+		qmih = (struct QMI_QOS_HDR_S *)
+			   skb_push(skb, sizeof(struct QMI_QOS_HDR_S));
+		qmih->version = 1;
+		qmih->flags = 0;
+		qmih->flow_id = skb->mark;
+	}
+
+	dev->trans_start = jiffies;
+
+	/* if write() succeeds, skb access is unsafe in this process */
+	smux_ret = msm_smux_write(p->ch_id, skb, skb->data, skb->len);
+
+	if (smux_ret != 0 && smux_ret != -EAGAIN) {
+		pr_err("[%s] %s: write returned error %d",
+			   dev->name, __func__, smux_ret);
+		return -EPERM;
+	}
+
+	return smux_ret;
+}
+
+static int rmnet_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct rmnet_private *p = netdev_priv(dev);
+	int ret = 0;
+
+	if (netif_queue_stopped(dev) || (p->device_state == DEVICE_INACTIVE)) {
+		pr_err("[%s]fatal: rmnet_xmit called when "
+			   "netif_queue is stopped", dev->name);
+		return 0;
+	}
+
+	ret = _rmnet_xmit(skb, dev);
+
+	if (ret == -EPERM) {
+		/* Do not stop the queue here.
+		 * It will lead to ir-recoverable state.
+		 */
+		ret = NETDEV_TX_BUSY;
+		goto exit;
+	}
+
+	if (msm_smux_is_ch_full(p->ch_id) || (ret == -EAGAIN)) {
+		/*
+		 * EAGAIN means we attempted to overflow the high watermark
+		 * Clearly the queue is not stopped like it should be, so
+		 * stop it and return BUSY to the TCP/IP framework.  It will
+		 * retry this packet with the queue is restarted which happens
+		 * low watermark is called.
+		 */
+		netif_stop_queue(dev);
+		ret = NETDEV_TX_BUSY;
+		goto exit;
+	}
+exit:
+	return ret;
+}
+
+static struct net_device_stats *rmnet_get_stats(struct net_device *dev)
+{
+	struct rmnet_private *p = netdev_priv(dev);
+	return &p->stats;
+}
+
+static void rmnet_set_multicast_list(struct net_device *dev)
+{
+}
+
+static void rmnet_tx_timeout(struct net_device *dev)
+{
+	pr_warning("[%s] rmnet_tx_timeout()\n", dev->name);
+}
+
+static const struct net_device_ops rmnet_ops_ether = {
+	.ndo_open = rmnet_open,
+	.ndo_stop = rmnet_stop,
+	.ndo_start_xmit = rmnet_xmit,
+	.ndo_get_stats = rmnet_get_stats,
+	.ndo_set_multicast_list = rmnet_set_multicast_list,
+	.ndo_tx_timeout = rmnet_tx_timeout,
+	.ndo_do_ioctl = rmnet_ioctl,
+	.ndo_change_mtu = rmnet_change_mtu,
+	.ndo_set_mac_address = eth_mac_addr,
+	.ndo_validate_addr = eth_validate_addr,
+};
+
+static const struct net_device_ops rmnet_ops_ip = {
+	.ndo_open = rmnet_open,
+	.ndo_stop = rmnet_stop,
+	.ndo_start_xmit = rmnet_xmit,
+	.ndo_get_stats = rmnet_get_stats,
+	.ndo_set_multicast_list = rmnet_set_multicast_list,
+	.ndo_tx_timeout = rmnet_tx_timeout,
+	.ndo_do_ioctl = rmnet_ioctl,
+	.ndo_change_mtu = rmnet_change_mtu,
+	.ndo_set_mac_address = 0,
+	.ndo_validate_addr = 0,
+};
+
+static int rmnet_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	struct rmnet_private *p = netdev_priv(dev);
+	u32 old_opmode = p->operation_mode;
+	unsigned long flags;
+	int prev_mtu = dev->mtu;
+	int rc = 0;
+
+	/* Process IOCTL command */
+	switch (cmd) {
+	case RMNET_IOCTL_SET_LLP_ETHERNET:	/* Set Ethernet protocol   */
+		/* Perform Ethernet config only if in IP mode currently*/
+		if (p->operation_mode & RMNET_MODE_LLP_IP) {
+			ether_setup(dev);
+			random_ether_addr(dev->dev_addr);
+			dev->mtu = prev_mtu;
+
+			dev->netdev_ops = &rmnet_ops_ether;
+			spin_lock_irqsave(&p->lock, flags);
+			p->operation_mode &= ~RMNET_MODE_LLP_IP;
+			p->operation_mode |= RMNET_MODE_LLP_ETH;
+			spin_unlock_irqrestore(&p->lock, flags);
+			DBG0("[%s] rmnet_ioctl(): "
+				 "set Ethernet protocol mode\n",
+				 dev->name);
+		}
+		break;
+
+	case RMNET_IOCTL_SET_LLP_IP:		/* Set RAWIP protocol      */
+		/* Perform IP config only if in Ethernet mode currently*/
+		if (p->operation_mode & RMNET_MODE_LLP_ETH) {
+
+			/* Undo config done in ether_setup() */
+			dev->header_ops         = 0;  /* No header */
+			dev->type               = ARPHRD_RAWIP;
+			dev->hard_header_len    = 0;
+			dev->mtu                = prev_mtu;
+			dev->addr_len           = 0;
+			dev->flags              &= ~(IFF_BROADCAST |
+						     IFF_MULTICAST);
+
+			dev->needed_headroom = HEADROOM_FOR_SMUX +
+							HEADROOM_FOR_QOS;
+			dev->needed_tailroom = TAILROOM;
+			dev->netdev_ops = &rmnet_ops_ip;
+			spin_lock_irqsave(&p->lock, flags);
+			p->operation_mode &= ~RMNET_MODE_LLP_ETH;
+			p->operation_mode |= RMNET_MODE_LLP_IP;
+			spin_unlock_irqrestore(&p->lock, flags);
+			DBG0("[%s] rmnet_ioctl(): "
+				 "set IP protocol mode\n",
+				 dev->name);
+		}
+		break;
+
+	case RMNET_IOCTL_GET_LLP:	/* Get link protocol state */
+		ifr->ifr_ifru.ifru_data =
+		(void *)(p->operation_mode &
+				 (RMNET_MODE_LLP_ETH|RMNET_MODE_LLP_IP));
+		break;
+
+	case RMNET_IOCTL_SET_QOS_ENABLE:	/* Set QoS header enabled */
+		spin_lock_irqsave(&p->lock, flags);
+		p->operation_mode |= RMNET_MODE_QOS;
+		spin_unlock_irqrestore(&p->lock, flags);
+		DBG0("[%s] rmnet_ioctl(): set QMI QOS header enable\n",
+			 dev->name);
+		break;
+
+	case RMNET_IOCTL_SET_QOS_DISABLE:	/* Set QoS header disabled */
+		spin_lock_irqsave(&p->lock, flags);
+		p->operation_mode &= ~RMNET_MODE_QOS;
+		spin_unlock_irqrestore(&p->lock, flags);
+		DBG0("[%s] rmnet_ioctl(): set QMI QOS header disable\n",
+			 dev->name);
+		break;
+
+	case RMNET_IOCTL_GET_QOS:	/* Get QoS header state */
+		ifr->ifr_ifru.ifru_data =
+		(void *)(p->operation_mode & RMNET_MODE_QOS);
+		break;
+
+	case RMNET_IOCTL_GET_OPMODE:	/* Get operation mode */
+		ifr->ifr_ifru.ifru_data = (void *)p->operation_mode;
+		break;
+
+	case RMNET_IOCTL_OPEN:		/* Open transport port */
+		rc = __rmnet_open(dev);
+		DBG0("[%s] rmnet_ioctl(): open transport port\n",
+			 dev->name);
+		break;
+
+	case RMNET_IOCTL_CLOSE:		/* Close transport port */
+		DBG0("[%s] rmnet_ioctl(): close transport port\n",
+			 dev->name);
+		break;
+
+	default:
+		pr_err("[%s] error: rmnet_ioct called for unsupported cmd[%d]",
+			   dev->name, cmd);
+		return -EINVAL;
+	}
+
+	DBG2("[%s] %s: cmd=0x%x opmode old=0x%08x new=0x%08x\n",
+		 dev->name, __func__, cmd, old_opmode, p->operation_mode);
+	return rc;
+}
+
+static void __init rmnet_setup(struct net_device *dev)
+{
+	/* Using Ethernet mode by default */
+	dev->netdev_ops = &rmnet_ops_ether;
+	ether_setup(dev);
+
+	/* set this after calling ether_setup */
+	dev->mtu = RMNET_DATA_LEN;
+	dev->needed_headroom = HEADROOM_FOR_SMUX + HEADROOM_FOR_QOS ;
+	dev->needed_tailroom = TAILROOM;
+	random_ether_addr(dev->dev_addr);
+
+	dev->watchdog_timeo = 1000;	/* 10 seconds? */
+}
+
+
+static int smux_rmnet_probe(struct platform_device *pdev)
+{
+	int i;
+	int r;
+	struct rmnet_private *p;
+
+	for (i = 0; i < RMNET_SMUX_DEVICE_COUNT; i++) {
+		p = netdev_priv(netdevs[i]);
+
+		if ((p != NULL) && (p->device_state == DEVICE_INACTIVE)) {
+			r =  msm_smux_open(p->ch_id,
+					   netdevs[i],
+					   rmnet_smux_notify,
+					   get_rx_buffers);
+
+			if (r < 0) {
+				DBG0("%s: ch=%d open failed with rc %d\n",
+				      __func__, p->ch_id, r);
+			}
+		}
+	}
+	return 0;
+}
+
+static int smux_rmnet_remove(struct platform_device *pdev)
+{
+	int i;
+	int r;
+	struct rmnet_private *p;
+
+	for (i = 0; i < RMNET_SMUX_DEVICE_COUNT; i++) {
+		p = netdev_priv(netdevs[i]);
+
+		if ((p != NULL) && (p->device_state == DEVICE_ACTIVE)) {
+			r =  msm_smux_close(p->ch_id);
+
+			if (r < 0) {
+				DBG0("%s: ch=%d close failed with rc %d\n",
+				     __func__, p->ch_id, r);
+				continue;
+			}
+			netif_carrier_off(netdevs[i]);
+			netif_stop_queue(netdevs[i]);
+		}
+	}
+	return 0;
+}
+
+
+static struct platform_driver smux_rmnet_driver = {
+	.probe  = smux_rmnet_probe,
+	.remove = smux_rmnet_remove,
+	.driver = {
+		.name = "SMUX_RMNET",
+		.owner = THIS_MODULE,
+	},
+};
+
+
+static int __init rmnet_init(void)
+{
+	int ret;
+	struct device *d;
+	struct net_device *dev;
+	struct rmnet_private *p;
+	unsigned n;
+
+#ifdef CONFIG_MSM_RMNET_DEBUG
+	timeout_us = 0;
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	timeout_suspend_us = 0;
+#endif /* CONFIG_HAS_EARLYSUSPEND */
+#endif /* CONFIG_MSM_RMNET_DEBUG */
+
+	for (n = 0; n < RMNET_SMUX_DEVICE_COUNT; n++) {
+		dev = alloc_netdev(sizeof(struct rmnet_private),
+				   "rmnet_smux%d", rmnet_setup);
+
+		if (!dev) {
+			pr_err("%s: no memory for netdev %d\n", __func__, n);
+			return -ENOMEM;
+		}
+
+		netdevs[n] = dev;
+		d = &(dev->dev);
+		p = netdev_priv(dev);
+		/* Initial config uses Ethernet */
+		p->operation_mode = RMNET_MODE_LLP_ETH;
+		p->ch_id = n;
+		p->in_reset = 0;
+		spin_lock_init(&p->lock);
+#ifdef CONFIG_MSM_RMNET_DEBUG
+		p->timeout_us = timeout_us;
+		p->wakeups_xmit = p->wakeups_rcv = 0;
+#endif
+
+		ret = register_netdev(dev);
+		if (ret) {
+			pr_err("%s: unable to register netdev"
+				   " %d rc=%d\n", __func__, n, ret);
+			free_netdev(dev);
+			return ret;
+		}
+
+#ifdef CONFIG_MSM_RMNET_DEBUG
+		if (device_create_file(d, &dev_attr_timeout))
+			continue;
+		if (device_create_file(d, &dev_attr_wakeups_xmit))
+			continue;
+		if (device_create_file(d, &dev_attr_wakeups_rcv))
+			continue;
+#ifdef CONFIG_HAS_EARLYSUSPEND
+		if (device_create_file(d, &dev_attr_timeout_suspend))
+			continue;
+
+		/* Only care about rmnet0 for suspend/resume tiemout hooks. */
+		if (n == 0)
+			rmnet0 = d;
+#endif /* CONFIG_HAS_EARLYSUSPEND */
+#endif /* CONFIG_MSM_RMNET_DEBUG */
+
+	}
+
+	ret = platform_driver_register(&smux_rmnet_driver);
+	if (ret) {
+		pr_err("%s: registration failed n=%d rc=%d\n",
+			   __func__, n, ret);
+		return ret;
+	}
+	return 0;
+}
+
+module_init(rmnet_init);
+MODULE_DESCRIPTION("MSM RMNET SMUX TRANSPORT");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index cc95fcd..ad9dc7d 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -45,7 +45,7 @@
 	int		smd_channel_ready;
 	unsigned int	serial_number;
 	int		thermal_mitigation;
-	void		(*tm_notify)(int);
+	void		(*tm_notify)(struct device *, int);
 	struct wcnss_wlan_config wlan_config;
 	struct delayed_work wcnss_work;
 } *penv = NULL;
@@ -99,7 +99,7 @@
 		return -EINVAL;
 	penv->thermal_mitigation = value;
 	if (penv->tm_notify)
-		(penv->tm_notify)(value);
+		(penv->tm_notify)(dev, value);
 	return count;
 }
 
@@ -275,14 +275,16 @@
 }
 EXPORT_SYMBOL(wcnss_wlan_unregister_pm_ops);
 
-void wcnss_register_thermal_mitigation(void (*tm_notify)(int))
+void wcnss_register_thermal_mitigation(struct device *dev,
+				void (*tm_notify)(struct device *, int))
 {
-	if (penv && tm_notify)
+	if (penv && dev && tm_notify)
 		penv->tm_notify = tm_notify;
 }
 EXPORT_SYMBOL(wcnss_register_thermal_mitigation);
 
-void wcnss_unregister_thermal_mitigation(void (*tm_notify)(int))
+void wcnss_unregister_thermal_mitigation(
+				void (*tm_notify)(struct device *, int))
 {
 	if (penv && tm_notify) {
 		if (tm_notify != penv->tm_notify)
diff --git a/drivers/platform/msm/sps/bam.c b/drivers/platform/msm/sps/bam.c
index d7edb82..cf98f68 100644
--- a/drivers/platform/msm/sps/bam.c
+++ b/drivers/platform/msm/sps/bam.c
@@ -649,6 +649,8 @@
 	u32 cfg_bits = 0xffffffff & ~(1 << 11);
 	u32 ver = 0;
 
+	SPS_DBG2("sps:%s:bam=0x%x(va).ee=%d.", __func__, (u32) base, ee);
+
 	ver = bam_read_reg_field(base, REVISION, BAM_REVISION);
 
 	if ((ver < BAM_MIN_VERSION) || (ver > BAM_MAX_VERSION)) {
@@ -743,6 +745,8 @@
 	u32 mask;
 	u32 pipe;
 
+	SPS_DBG2("sps:%s:bam=0x%x(va).", __func__, (u32) base);
+
 	/*
 	 * Discover the hardware version number and the number of pipes
 	 * supported by this BAM
@@ -782,6 +786,8 @@
 {
 	u32 ver = 0;
 
+	SPS_DBG2("sps:%s:bam=0x%x(va).", __func__, (u32) base);
+
 	if (!bam_read_reg_field(base, CTRL, BAM_EN)) {
 		SPS_ERR("sps:%s:bam 0x%x(va) is not enabled.\n",
 				__func__, (u32) base);
@@ -813,6 +819,8 @@
  */
 void bam_exit(void *base, u32 ee)
 {
+	SPS_DBG2("sps:%s:bam=0x%x(va).ee=%d.", __func__, (u32) base, ee);
+
 	bam_write_reg_field(base, IRQ_SRCS_MSK_EE(ee), BAM_IRQ, 0);
 
 	bam_write_reg(base, IRQ_EN, 0);
@@ -899,6 +907,8 @@
 int bam_pipe_init(void *base, u32 pipe,	struct bam_pipe_parameters *param,
 					u32 ee)
 {
+	SPS_DBG2("sps:%s:bam=0x%x(va).pipe=%d.", __func__, (u32) base, pipe);
+
 	/* Reset the BAM pipe */
 	bam_write_reg(base, P_RST(pipe), 1);
 	/* No delay needed */
@@ -967,6 +977,8 @@
  */
 void bam_pipe_exit(void *base, u32 pipe, u32 ee)
 {
+	SPS_DBG2("sps:%s:bam=0x%x(va).pipe=%d.", __func__, (u32) base, pipe);
+
 	bam_write_reg(base, P_IRQ_EN(pipe), 0);
 
 	/* Disable the Pipe Interrupt at the BAM level */
@@ -982,6 +994,8 @@
  */
 void bam_pipe_enable(void *base, u32 pipe)
 {
+	SPS_DBG2("sps:%s:bam=0x%x(va).pipe=%d.", __func__, (u32) base, pipe);
+
 	bam_write_reg_field(base, P_CTRL(pipe), P_EN, 1);
 }
 
@@ -991,6 +1005,8 @@
  */
 void bam_pipe_disable(void *base, u32 pipe)
 {
+	SPS_DBG2("sps:%s:bam=0x%x(va).pipe=%d.", __func__, (u32) base, pipe);
+
 	bam_write_reg_field(base, P_CTRL(pipe), P_EN, 0);
 }
 
@@ -1010,6 +1026,8 @@
 void bam_pipe_set_irq(void *base, u32 pipe, enum bam_enable irq_en,
 		      u32 src_mask, u32 ee)
 {
+	SPS_DBG2("sps:%s:bam=0x%x(va).pipe=%d.", __func__, (u32) base, pipe);
+
 	bam_write_reg(base, P_IRQ_EN(pipe), src_mask);
 	bam_write_reg_field(base, IRQ_SRCS_MSK_EE(ee), (1 << pipe), irq_en);
 }
@@ -1287,7 +1305,7 @@
 		"BAM_P_IRQ_STTS: 0x%x\n"
 		"BAM_P_IRQ_STTS_P_TRNSFR_END_IRQ: 0x%x\n"
 		"BAM_P_IRQ_STTS_P_PRCSD_DESC_IRQ: 0x%x\n"
-		"BAM_P_IRQ_EN: %d\n"
+		"BAM_P_IRQ_EN: 0x%x\n"
 		"BAM_P_PRDCR_SDBNDn_BAM_P_BYTES_FREE: 0x%x (%d)\n"
 		"BAM_P_CNSMR_SDBNDn_BAM_P_BYTES_AVAIL: 0x%x (%d)\n"
 		"BAM_P_SW_DESC_OFST: 0x%x\n"
@@ -1335,4 +1353,50 @@
 		bam_read_reg_field(base, P_EVNT_GEN_TRSHLD(pipe),
 					P_EVNT_GEN_TRSHLD_P_TRSHLD));
 }
+
+/* output descriptor FIFO of a pipe */
+void print_bam_pipe_desc_fifo(void *virt_addr, u32 pipe_index)
+{
+	void *base = virt_addr;
+	u32 pipe = pipe_index;
+	u32 desc_fifo_addr;
+	u32 desc_fifo_size;
+	u32 *desc_fifo;
+	int i;
+
+	if (base == NULL)
+		return;
+
+	desc_fifo_addr = bam_read_reg(base, P_DESC_FIFO_ADDR(pipe));
+	desc_fifo_size = bam_read_reg_field(base, P_FIFO_SIZES(pipe),
+						P_DESC_FIFO_SIZE);
+
+	if (desc_fifo_addr == 0) {
+		SPS_ERR("sps:%s:desc FIFO address of Pipe %d is NULL.\n",
+			__func__, pipe);
+		return;
+	} else if (desc_fifo_size == 0) {
+		SPS_ERR("sps:%s:desc FIFO size of Pipe %d is 0.\n",
+			__func__, pipe);
+		return;
+	}
+
+	SPS_INFO("\nsps:----- descriptor FIFO of Pipe %d -----\n", pipe);
+
+	SPS_INFO("BAM_P_DESC_FIFO_ADDR: 0x%x\n"
+		"BAM_P_DESC_FIFO_SIZE: 0x%x (%d)\n\n",
+		desc_fifo_addr, desc_fifo_size, desc_fifo_size);
+
+	desc_fifo = (u32 *) phys_to_virt(desc_fifo_addr);
+
+	SPS_INFO("-------------------- begin of FIFO --------------------\n");
+
+	for (i = 0; i < desc_fifo_size; i += 0x10)
+		SPS_INFO("addr 0x%x: 0x%x, 0x%x, 0x%x, 0x%x.\n",
+			desc_fifo_addr + i,
+			desc_fifo[i / 4], desc_fifo[(i / 4) + 1],
+			desc_fifo[(i / 4) + 2], desc_fifo[(i / 4) + 3]);
+
+	SPS_INFO("--------------------  end of FIFO  --------------------\n");
+}
 #endif
diff --git a/drivers/platform/msm/sps/sps.c b/drivers/platform/msm/sps/sps.c
index 0fe8f2a..fbaea09 100644
--- a/drivers/platform/msm/sps/sps.c
+++ b/drivers/platform/msm/sps/sps.c
@@ -327,6 +327,26 @@
 		print_bam_pipe_selected_reg(vir_addr, 4);
 		print_bam_pipe_selected_reg(vir_addr, 5);
 		break;
+	case 6: /* output desc FIFO of all active pipes */
+		for (i = 0; i < num_pipes; i++)
+			print_bam_pipe_desc_fifo(vir_addr, i);
+		break;
+	case 7: /* output desc FIFO of some pipes */
+		print_bam_pipe_desc_fifo(vir_addr, 4);
+		print_bam_pipe_desc_fifo(vir_addr, 5);
+		break;
+	case 8: /* output selected registers and valid desc FIFO of all pipes */
+		for (i = 0; i < num_pipes; i++) {
+			print_bam_pipe_selected_reg(vir_addr, i);
+			print_bam_pipe_desc_fifo(vir_addr, i);
+		}
+		break;
+	case 9: /* output selected registers and desc FIFO of some pipes */
+		print_bam_pipe_selected_reg(vir_addr, 4);
+		print_bam_pipe_desc_fifo(vir_addr, 4);
+		print_bam_pipe_selected_reg(vir_addr, 5);
+		print_bam_pipe_desc_fifo(vir_addr, 5);
+		break;
 	default:
 		pr_info("sps:no dump option is chosen yet.");
 	}
@@ -455,7 +475,7 @@
 	struct sps_bam_props bamdma_props = {0};
 #endif
 
-	SPS_DBG("sps:sps_device_init");
+	SPS_DBG2("sps:%s.", __func__);
 
 	success = false;
 
@@ -581,6 +601,8 @@
  */
 static int sps_client_init(struct sps_pipe *client)
 {
+	SPS_DBG("sps:%s.", __func__);
+
 	if (client == NULL)
 		return -EINVAL;
 
@@ -609,6 +631,8 @@
  */
 static int sps_client_de_init(struct sps_pipe *client)
 {
+	SPS_DBG("sps:%s.", __func__);
+
 	if (client->client_state != SPS_STATE_DISCONNECT) {
 		SPS_ERR("sps:De-init client in connected state: 0x%x",
 				   client->client_state);
@@ -637,6 +661,8 @@
 {
 	struct sps_bam *bam;
 
+	SPS_DBG("sps:%s.", __func__);
+
 	list_for_each_entry(bam, &sps->bams_q, list) {
 		if (bam->props.phys_addr == phys_addr)
 			return bam;
@@ -662,6 +688,13 @@
 {
 	struct sps_bam *bam;
 
+	SPS_DBG("sps:%s.", __func__);
+
+	if (handle == NULL) {
+		SPS_ERR("sps:%s:handle is NULL.\n", __func__);
+		return SPS_ERROR;
+	}
+
 	list_for_each_entry(bam, &sps->bams_q, list) {
 		if (bam->props.phys_addr == phys_addr) {
 			*handle = (u32) bam;
@@ -692,6 +725,8 @@
 int sps_setup_bam2bam_fifo(struct sps_mem_buffer *mem_buffer,
 		  u32 addr, u32 size, int use_offset)
 {
+	SPS_DBG("sps:%s.", __func__);
+
 	if ((mem_buffer == NULL) || (size == 0)) {
 		SPS_ERR("sps:invalid buffer address or size.");
 		return SPS_ERROR;
@@ -741,6 +776,8 @@
 {
 	struct sps_bam *bam;
 
+	SPS_DBG("sps:%s.", __func__);
+
 	if (h == SPS_DEV_HANDLE_MEM || h == SPS_DEV_HANDLE_INVALID)
 		return NULL;
 
@@ -816,6 +853,16 @@
 	struct sps_bam *bam;
 	int result;
 
+	SPS_DBG2("sps:%s.", __func__);
+
+	if (h == NULL) {
+		SPS_ERR("sps:%s:pipe is NULL.\n", __func__);
+		return SPS_ERROR;
+	} else if (connect == NULL) {
+		SPS_ERR("sps:%s:connection is NULL.\n", __func__);
+		return SPS_ERROR;
+	}
+
 	if (sps == NULL)
 		return -ENODEV;
 
@@ -902,6 +949,8 @@
 	struct sps_bam *bam;
 	int result;
 
+	SPS_DBG2("sps:%s.", __func__);
+
 	if (pipe == NULL) {
 		SPS_ERR("sps:Invalid pipe.");
 		return SPS_ERROR;
@@ -959,6 +1008,14 @@
 
 	SPS_DBG2("sps:%s.", __func__);
 
+	if (h == NULL) {
+		SPS_ERR("sps:%s:pipe is NULL.\n", __func__);
+		return SPS_ERROR;
+	} else if (reg == NULL) {
+		SPS_ERR("sps:%s:registered event is NULL.\n", __func__);
+		return SPS_ERROR;
+	}
+
 	if (sps == NULL)
 		return -ENODEV;
 
@@ -993,6 +1050,11 @@
 
 	SPS_DBG2("sps:%s.", __func__);
 
+	if (h == NULL) {
+		SPS_ERR("sps:%s:pipe is NULL.\n", __func__);
+		return SPS_ERROR;
+	}
+
 	bam = sps_bam_lock(pipe);
 	if (bam == NULL)
 		return SPS_ERROR;
@@ -1017,6 +1079,11 @@
 
 	SPS_DBG2("sps:%s.", __func__);
 
+	if (h == NULL) {
+		SPS_ERR("sps:%s:pipe is NULL.\n", __func__);
+		return SPS_ERROR;
+	}
+
 	bam = sps_bam_lock(pipe);
 	if (bam == NULL)
 		return SPS_ERROR;
@@ -1041,6 +1108,14 @@
 
 	SPS_DBG("sps:%s.", __func__);
 
+	if (h == NULL) {
+		SPS_ERR("sps:%s:pipe is NULL.\n", __func__);
+		return SPS_ERROR;
+	} else if (transfer == NULL) {
+		SPS_ERR("sps:%s:transfer is NULL.\n", __func__);
+		return SPS_ERROR;
+	}
+
 	bam = sps_bam_lock(pipe);
 	if (bam == NULL)
 		return SPS_ERROR;
@@ -1066,6 +1141,11 @@
 
 	SPS_DBG("sps:%s.", __func__);
 
+	if (h == NULL) {
+		SPS_ERR("sps:%s:pipe is NULL.\n", __func__);
+		return SPS_ERROR;
+	}
+
 	if ((flags & SPS_IOVEC_FLAG_NWD) &&
 		!(flags & (SPS_IOVEC_FLAG_EOT | SPS_IOVEC_FLAG_CMD))) {
 		SPS_ERR("sps:NWD is only valid with EOT or CMD.\n");
@@ -1119,6 +1199,14 @@
 
 	SPS_DBG("sps:%s.", __func__);
 
+	if (h == NULL) {
+		SPS_ERR("sps:%s:pipe is NULL.\n", __func__);
+		return SPS_ERROR;
+	} else if (notify == NULL) {
+		SPS_ERR("sps:%s:event_notify is NULL.\n", __func__);
+		return SPS_ERROR;
+	}
+
 	bam = sps_bam_lock(pipe);
 	if (bam == NULL)
 		return SPS_ERROR;
@@ -1142,6 +1230,14 @@
 
 	SPS_DBG("sps:%s.", __func__);
 
+	if (h == NULL) {
+		SPS_ERR("sps:%s:pipe is NULL.\n", __func__);
+		return SPS_ERROR;
+	} else if (empty == NULL) {
+		SPS_ERR("sps:%s:result pointer is NULL.\n", __func__);
+		return SPS_ERROR;
+	}
+
 	bam = sps_bam_lock(pipe);
 	if (bam == NULL)
 		return SPS_ERROR;
@@ -1165,6 +1261,14 @@
 
 	SPS_DBG("sps:%s.", __func__);
 
+	if (h == NULL) {
+		SPS_ERR("sps:%s:pipe is NULL.\n", __func__);
+		return SPS_ERROR;
+	} else if (count == NULL) {
+		SPS_ERR("sps:%s:result pointer is NULL.\n", __func__);
+		return SPS_ERROR;
+	}
+
 	bam = sps_bam_lock(pipe);
 	if (bam == NULL)
 		return SPS_ERROR;
@@ -1187,6 +1291,11 @@
 
 	SPS_DBG2("sps:%s: dev = 0x%x", __func__, dev);
 
+	if (dev == 0) {
+		SPS_ERR("sps:%s:device handle should not be 0.\n", __func__);
+		return SPS_ERROR;
+	}
+
 	mutex_lock(&sps->lock);
 	/* Search for the target BAM device */
 	bam = sps_h2bam(dev);
@@ -1219,8 +1328,13 @@
 {
 	struct sps_pipe *pipe = h;
 
-	if (config == NULL) {
-		SPS_ERR("sps:Config pointer is NULL");
+	SPS_DBG("sps:%s.", __func__);
+
+	if (h == NULL) {
+		SPS_ERR("sps:%s:pipe is NULL.\n", __func__);
+		return SPS_ERROR;
+	} else if (config == NULL) {
+		SPS_ERR("sps:%s:config pointer is NULL.\n", __func__);
 		return SPS_ERROR;
 	}
 
@@ -1243,6 +1357,14 @@
 
 	SPS_DBG("sps:%s.", __func__);
 
+	if (h == NULL) {
+		SPS_ERR("sps:%s:pipe is NULL.\n", __func__);
+		return SPS_ERROR;
+	} else if (config == NULL) {
+		SPS_ERR("sps:%s:config pointer is NULL.\n", __func__);
+		return SPS_ERROR;
+	}
+
 	bam = sps_bam_lock(pipe);
 	if (bam == NULL)
 		return SPS_ERROR;
@@ -1268,6 +1390,16 @@
 	struct sps_bam *bam;
 	int result;
 
+	SPS_DBG("sps:%s.", __func__);
+
+	if (h == NULL) {
+		SPS_ERR("sps:%s:pipe is NULL.\n", __func__);
+		return SPS_ERROR;
+	} else if (connect == NULL) {
+		SPS_ERR("sps:%s:connection is NULL.\n", __func__);
+		return SPS_ERROR;
+	}
+
 	if (owner != SPS_OWNER_REMOTE) {
 		SPS_ERR("sps:Unsupported ownership state: %d", owner);
 		return SPS_ERROR;
@@ -1309,6 +1441,13 @@
 int sps_alloc_mem(struct sps_pipe *h, enum sps_mem mem,
 		  struct sps_mem_buffer *mem_buffer)
 {
+	SPS_DBG("sps:%s.", __func__);
+
+	if (h == NULL) {
+		SPS_ERR("sps:%s:pipe is NULL.\n", __func__);
+		return SPS_ERROR;
+	}
+
 	if (sps == NULL)
 		return -ENODEV;
 
@@ -1340,6 +1479,13 @@
  */
 int sps_free_mem(struct sps_pipe *h, struct sps_mem_buffer *mem_buffer)
 {
+	SPS_DBG("sps:%s.", __func__);
+
+	if (h == NULL) {
+		SPS_ERR("sps:%s:pipe is NULL.\n", __func__);
+		return SPS_ERROR;
+	}
+
 	if (mem_buffer == NULL || mem_buffer->phys_base == SPS_ADDR_INVALID) {
 		SPS_ERR("sps:invalid memory to free");
 		return SPS_ERROR;
@@ -1364,6 +1510,14 @@
 
 	SPS_DBG("sps:%s.", __func__);
 
+	if (h == NULL) {
+		SPS_ERR("sps:%s:pipe is NULL.\n", __func__);
+		return SPS_ERROR;
+	} else if (desc_num == NULL) {
+		SPS_ERR("sps:%s:result pointer is NULL.\n", __func__);
+		return SPS_ERROR;
+	}
+
 	bam = sps_bam_lock(pipe);
 	if (bam == NULL)
 		return SPS_ERROR;
@@ -1390,6 +1544,16 @@
 	int ok;
 	int result;
 
+	SPS_DBG2("sps:%s.", __func__);
+
+	if (bam_props == NULL) {
+		SPS_ERR("sps:%s:bam_props is NULL.\n", __func__);
+		return SPS_ERROR;
+	} else if (dev_handle == NULL) {
+		SPS_ERR("sps:%s:device handle is NULL.\n", __func__);
+		return SPS_ERROR;
+	}
+
 	if (sps == NULL)
 		return SPS_ERROR;
 
@@ -1399,9 +1563,6 @@
 		return -EAGAIN;
 	}
 
-	if (bam_props == NULL || dev_handle == NULL)
-		return SPS_ERROR;
-
 	/* Check BAM parameters */
 	manage = bam_props->manage & SPS_BAM_MGR_ACCESS_MASK;
 	if (manage != SPS_BAM_MGR_NONE) {
@@ -1532,6 +1693,13 @@
 {
 	struct sps_bam *bam;
 
+	SPS_DBG2("sps:%s.", __func__);
+
+	if (dev_handle == 0) {
+		SPS_ERR("sps:%s:device handle should not be 0.\n", __func__);
+		return SPS_ERROR;
+	}
+
 	bam = sps_h2bam(dev_handle);
 	if (bam == NULL) {
 		SPS_ERR("sps:did not find a BAM for this handle");
@@ -1578,13 +1746,16 @@
 	struct sps_bam *bam;
 	int result;
 
-	if (h == NULL || iovec == NULL) {
-		SPS_ERR("sps:invalid pipe or iovec");
+	SPS_DBG("sps:%s.", __func__);
+
+	if (h == NULL) {
+		SPS_ERR("sps:%s:pipe is NULL.\n", __func__);
+		return SPS_ERROR;
+	} else if (iovec == NULL) {
+		SPS_ERR("sps:%s:iovec pointer is NULL.\n", __func__);
 		return SPS_ERROR;
 	}
 
-	SPS_DBG("sps:%s.", __func__);
-
 	bam = sps_bam_lock(pipe);
 	if (bam == NULL)
 		return SPS_ERROR;
@@ -1611,8 +1782,14 @@
 
 	SPS_DBG("sps:%s.", __func__);
 
-	if (h == NULL || timer_ctrl == NULL) {
-		SPS_ERR("sps:invalid pipe or timer ctrl");
+	if (h == NULL) {
+		SPS_ERR("sps:%s:pipe is NULL.\n", __func__);
+		return SPS_ERROR;
+	} else if (timer_ctrl == NULL) {
+		SPS_ERR("sps:%s:timer_ctrl pointer is NULL.\n", __func__);
+		return SPS_ERROR;
+	} else if (timer_result == NULL) {
+		SPS_ERR("sps:%s:result pointer is NULL.\n", __func__);
 		return SPS_ERROR;
 	}
 
@@ -1637,6 +1814,8 @@
 {
 	struct sps_pipe *ctx = NULL;
 
+	SPS_DBG("sps:%s.", __func__);
+
 	ctx = kzalloc(sizeof(struct sps_pipe), GFP_KERNEL);
 	if (ctx == NULL) {
 		SPS_ERR("sps:Fail to allocate pipe context.");
@@ -1657,6 +1836,13 @@
 {
 	int res;
 
+	SPS_DBG("sps:%s.", __func__);
+
+	if (ctx == NULL) {
+		SPS_ERR("sps:%s:pipe is NULL.\n", __func__);
+		return SPS_ERROR;
+	}
+
 	res = sps_client_de_init(ctx);
 
 	if (res == 0)
@@ -1674,6 +1860,8 @@
 	struct resource *resource;
 	struct msm_sps_platform_data *pdata;
 
+	SPS_DBG("sps:%s.", __func__);
+
 	pdata = pdev->dev.platform_data;
 
 	if (pdata == NULL) {
@@ -1736,6 +1924,8 @@
 #ifdef CONFIG_SPS_SUPPORT_BAMDMA
 	struct resource *resource;
 
+	SPS_DBG("sps:%s.", __func__);
+
 	if (of_property_read_u32((&pdev->dev)->of_node,
 				"qcom,bam-dma-res-pipes",
 				&sps->bamdma_restricted_pipes)) {
@@ -1786,7 +1976,7 @@
 {
 	int ret;
 
-	SPS_DBG("sps:msm_sps_probe.");
+	SPS_DBG2("sps:%s.", __func__);
 
 	if (pdev->dev.of_node) {
 		if (get_device_tree_data(pdev)) {
diff --git a/drivers/platform/msm/sps/sps_bam.c b/drivers/platform/msm/sps/sps_bam.c
index 0abd739..245ccd2 100644
--- a/drivers/platform/msm/sps/sps_bam.c
+++ b/drivers/platform/msm/sps/sps_bam.c
@@ -17,6 +17,7 @@
 #include <linux/slab.h>		/* kzalloc() */
 #include <linux/interrupt.h>	/* request_irq() */
 #include <linux/memory.h>	/* memset */
+#include <linux/vmalloc.h>
 
 #include "sps_bam.h"
 #include "bam.h"
@@ -220,7 +221,7 @@
 				    IRQF_TRIGGER_HIGH, "sps", dev);
 
 		if (result) {
-			SPS_ERR("sps:Failed to register BAM 0x%x IRQ %d",
+			SPS_ERR("sps:Failed to enable BAM 0x%x IRQ %d",
 				BAM_ID(dev), dev->props.irq);
 			return SPS_ERROR;
 		}
@@ -914,7 +915,11 @@
 		dev->pipe_remote_mask &= ~(1UL << pipe_index);
 		bam_pipe_exit(dev->base, pipe_index, dev->props.ee);
 		if (pipe->sys.desc_cache != NULL) {
-			kfree(pipe->sys.desc_cache);
+			u32 size = pipe->num_descs * sizeof(void *);
+			if (pipe->desc_size + size <= PAGE_SIZE)
+				kfree(pipe->sys.desc_cache);
+			else
+				vfree(pipe->sys.desc_cache);
 			pipe->sys.desc_cache = NULL;
 		}
 		dev->pipes[pipe_index] = BAM_PIPE_UNASSIGNED;
@@ -1034,8 +1039,16 @@
 	    && (pipe->state & BAM_STATE_BAM2BAM) == 0) {
 		/* Allocate both descriptor cache and user pointer array */
 		size = pipe->num_descs * sizeof(void *);
-		pipe->sys.desc_cache =
-		kzalloc(pipe->desc_size + size, GFP_KERNEL);
+
+		if (pipe->desc_size + size <= PAGE_SIZE)
+			pipe->sys.desc_cache =
+				kzalloc(pipe->desc_size + size, GFP_KERNEL);
+		else {
+			pipe->sys.desc_cache =
+				vmalloc(pipe->desc_size + size);
+			memset(pipe->sys.desc_cache, 0, pipe->desc_size + size);
+		}
+
 		if (pipe->sys.desc_cache == NULL) {
 			/*** MUST BE LAST POINT OF FAILURE (see below) *****/
 			SPS_ERR("sps:Desc cache error: BAM 0x%x pipe %d: %d",
diff --git a/drivers/platform/msm/sps/spsi.h b/drivers/platform/msm/sps/spsi.h
index 8e4907b..e8ab832 100644
--- a/drivers/platform/msm/sps/spsi.h
+++ b/drivers/platform/msm/sps/spsi.h
@@ -193,6 +193,9 @@
 
 /* output the content of selected BAM pipe registers */
 void print_bam_pipe_selected_reg(void *, u32);
+
+/* output descriptor FIFO of a pipe */
+void print_bam_pipe_desc_fifo(void *, u32);
 #endif
 
 /**
diff --git a/drivers/power/msm_battery.c b/drivers/power/msm_battery.c
index 0555399..5abc032 100644
--- a/drivers/power/msm_battery.c
+++ b/drivers/power/msm_battery.c
@@ -209,6 +209,7 @@
 struct msm_battery_info {
 	u32 voltage_max_design;
 	u32 voltage_min_design;
+	u32 voltage_fail_safe;
 	u32 chg_api_version;
 	u32 batt_technology;
 	u32 batt_api_version;
@@ -760,8 +761,10 @@
 
 	if (msm_batt_info.batt_handle != INVALID_BATT_HANDLE) {
 		rc = msm_batt_modify_client(msm_batt_info.batt_handle,
-				BATTERY_LOW, BATTERY_VOLTAGE_BELOW_THIS_LEVEL,
-				BATTERY_CB_ID_LOW_VOL, BATTERY_LOW);
+				msm_batt_info.voltage_fail_safe,
+				BATTERY_VOLTAGE_BELOW_THIS_LEVEL,
+				BATTERY_CB_ID_LOW_VOL,
+				msm_batt_info.voltage_fail_safe);
 
 		if (rc < 0) {
 			pr_err("%s: msm_batt_modify_client. rc=%d\n",
@@ -784,8 +787,9 @@
 
 	if (msm_batt_info.batt_handle != INVALID_BATT_HANDLE) {
 		rc = msm_batt_modify_client(msm_batt_info.batt_handle,
-				BATTERY_LOW, BATTERY_ALL_ACTIVITY,
-			       BATTERY_CB_ID_ALL_ACTIV, BATTERY_ALL_ACTIVITY);
+				msm_batt_info.voltage_fail_safe,
+				BATTERY_ALL_ACTIVITY,
+				BATTERY_CB_ID_ALL_ACTIV, BATTERY_ALL_ACTIVITY);
 		if (rc < 0) {
 			pr_err("%s: msm_batt_modify_client FAIL rc=%d\n",
 			       __func__, rc);
@@ -1373,6 +1377,8 @@
 
 	msm_batt_info.voltage_max_design = pdata->voltage_max_design;
 	msm_batt_info.voltage_min_design = pdata->voltage_min_design;
+	msm_batt_info.voltage_fail_safe  = pdata->voltage_fail_safe;
+
 	msm_batt_info.batt_technology = pdata->batt_technology;
 	msm_batt_info.calculate_capacity = pdata->calculate_capacity;
 
@@ -1380,6 +1386,8 @@
 		msm_batt_info.voltage_min_design = BATTERY_LOW;
 	if (!msm_batt_info.voltage_max_design)
 		msm_batt_info.voltage_max_design = BATTERY_HIGH;
+	if (!msm_batt_info.voltage_fail_safe)
+		msm_batt_info.voltage_fail_safe  = BATTERY_LOW;
 
 	if (msm_batt_info.batt_technology == POWER_SUPPLY_TECHNOLOGY_UNKNOWN)
 		msm_batt_info.batt_technology = POWER_SUPPLY_TECHNOLOGY_LION;
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index e7797b1..2c81f84 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -258,7 +258,6 @@
 	int				thermal_levels;
 	struct delayed_work		update_heartbeat_work;
 	struct delayed_work		eoc_work;
-	struct work_struct		unplug_ovp_fet_open_work;
 	struct delayed_work		unplug_check_work;
 	struct delayed_work		vin_collapse_check_work;
 	struct wake_lock		eoc_wake_lock;
@@ -1555,6 +1554,26 @@
 
 	pr_debug("Enter charge=%d\n", mA);
 
+	if (!the_chip) {
+		pr_err("chip not yet initalized\n");
+		return;
+	}
+
+	/*
+	 * Reject VBUS requests if USB connection is the only available
+	 * power source. This makes sure that if booting without
+	 * battery the iusb_max value is not decreased avoiding potential
+	 * brown_outs.
+	 *
+	 * This would also apply when the battery has been
+	 * removed from the running system.
+	 */
+	if (!get_prop_batt_present(the_chip)
+		&& !is_dc_chg_plugged_in(the_chip)) {
+		pr_err("rejected: no other power source connected\n");
+		return;
+	}
+
 	if (usb_max_current && mA > usb_max_current) {
 		pr_warn("restricting usb current to %d instead of %d\n",
 					usb_max_current, mA);
@@ -1978,11 +1997,8 @@
 
 #define WRITE_BANK_4		0xC0
 #define USB_OVP_DEBOUNCE_TIME 0x06
-static void unplug_ovp_fet_open_worker(struct work_struct *work)
+static void unplug_ovp_fet_open(struct pm8921_chg_chip *chip)
 {
-	struct pm8921_chg_chip *chip = container_of(work,
-				struct pm8921_chg_chip,
-				unplug_ovp_fet_open_work);
 	int chg_gone, usb_chg_plugged_in;
 	int count = 0;
 
@@ -2328,7 +2344,7 @@
 		/* run the worker directly */
 		pr_debug(" ver5 step: chg_gone=%d, usb_valid = %d\n",
 						chg_gone, usb_chg_plugged_in);
-		schedule_work(&chip->unplug_ovp_fet_open_work);
+		unplug_ovp_fet_open(chip);
 	}
 
 	if (!(reg_loop & VIN_ACTIVE_BIT)) {
@@ -2433,8 +2449,7 @@
 static irqreturn_t chg_gone_irq_handler(int irq, void *data)
 {
 	struct pm8921_chg_chip *chip = data;
-	u8 reg;
-	int rc, chg_gone, usb_chg_plugged_in;
+	int chg_gone, usb_chg_plugged_in;
 
 	usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
 	chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
@@ -2442,14 +2457,6 @@
 	pr_debug("chg_gone=%d, usb_valid = %d\n", chg_gone, usb_chg_plugged_in);
 	pr_debug("Chg gone fsm_state=%d\n", pm_chg_get_fsm_state(data));
 
-	rc = pm8xxx_readb(chip->dev->parent, CHG_CNTRL_3, &reg);
-	if (rc)
-		pr_err("Failed to read CHG_CNTRL_3 rc=%d\n", rc);
-
-	if (reg & CHG_USB_SUSPEND_BIT)
-		return IRQ_HANDLED;
-	schedule_work(&chip->unplug_ovp_fet_open_work);
-
 	power_supply_changed(&chip->batt_psy);
 	power_supply_changed(&chip->usb_psy);
 	return IRQ_HANDLED;
@@ -3363,13 +3370,6 @@
 		return rc;
 	}
 
-	/* init with the lowest USB current */
-	rc = pm_chg_iusbmax_set(chip, 0);
-	if (rc) {
-		pr_err("Failed to set usb max to %d rc=%d\n", 0, rc);
-		return rc;
-	}
-
 	if (chip->safety_time != 0) {
 		rc = pm_chg_tchg_max_set(chip, chip->safety_time);
 		if (rc) {
@@ -3872,8 +3872,6 @@
 	INIT_DELAYED_WORK(&chip->eoc_work, eoc_worker);
 	INIT_DELAYED_WORK(&chip->vin_collapse_check_work,
 						vin_collapse_check_worker);
-	INIT_WORK(&chip->unplug_ovp_fet_open_work,
-					unplug_ovp_fet_open_worker);
 	INIT_DELAYED_WORK(&chip->unplug_check_work, unplug_check_worker);
 
 	rc = request_irqs(chip, pdev);
diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c
index 76673c7..4c735df 100644
--- a/drivers/regulator/of_regulator.c
+++ b/drivers/regulator/of_regulator.c
@@ -12,6 +12,7 @@
 
 #include <linux/slab.h>
 #include <linux/of.h>
+#include <linux/string.h>
 #include <linux/regulator/machine.h>
 
 static void of_get_regulation_constraints(struct device_node *np,
@@ -57,6 +58,71 @@
 		constraints->valid_ops_mask |= REGULATOR_CHANGE_STATUS;
 }
 
+static const char *consumer_supply_prop_name = "qcom,consumer-supplies";
+#define MAX_DEV_NAME_LEN 256
+/*
+ * Fill in regulator init_data based on qcom legacy requirements.
+ */
+static int of_get_qcom_regulator_init_data(struct device *dev,
+					struct regulator_init_data **init_data)
+{
+	struct device_node *node = dev->of_node;
+	struct regulator_consumer_supply *consumer_supplies;
+	int i, rc, num_consumer_supplies, array_len;
+
+	array_len = of_property_count_strings(node, consumer_supply_prop_name);
+	if (array_len > 0) {
+		/* Array length must be divisible by 2. */
+		if (array_len & 1) {
+			dev_err(dev, "error: %s device node property value "
+				"contains an odd number of elements: %d\n",
+				consumer_supply_prop_name, array_len);
+			return -EINVAL;
+		}
+		num_consumer_supplies = array_len / 2;
+
+		consumer_supplies = devm_kzalloc(dev,
+			sizeof(struct regulator_consumer_supply)
+			* num_consumer_supplies, GFP_KERNEL);
+		if (consumer_supplies == NULL) {
+			dev_err(dev, "devm_kzalloc failed\n");
+			return -ENOMEM;
+		}
+
+		for (i = 0; i < num_consumer_supplies; i++) {
+			rc = of_property_read_string_index(node,
+				consumer_supply_prop_name, i * 2,
+				&consumer_supplies[i].supply);
+			if (rc) {
+				dev_err(dev, "of_property_read_string_index "
+					"failed, rc=%d\n", rc);
+				devm_kfree(dev, consumer_supplies);
+				return rc;
+			}
+
+			rc = of_property_read_string_index(node,
+				consumer_supply_prop_name, (i * 2) + 1,
+				&consumer_supplies[i].dev_name);
+			if (rc) {
+				dev_err(dev, "of_property_read_string_index "
+					"failed, rc=%d\n", rc);
+				devm_kfree(dev, consumer_supplies);
+				return rc;
+			}
+
+			/* Treat dev_name = "" as a wildcard. */
+			if (strnlen(consumer_supplies[i].dev_name,
+					MAX_DEV_NAME_LEN) == 0)
+				consumer_supplies[i].dev_name = NULL;
+		}
+
+		(*init_data)->consumer_supplies = consumer_supplies;
+		(*init_data)->num_consumer_supplies = num_consumer_supplies;
+	}
+
+	return 0;
+}
+
 /**
  * of_get_regulator_init_data - extract regulator_init_data structure info
  * @dev: device requesting for regulator_init_data
@@ -68,6 +134,7 @@
 struct regulator_init_data *of_get_regulator_init_data(struct device *dev)
 {
 	struct regulator_init_data *init_data;
+	int rc;
 
 	if (!dev->of_node)
 		return NULL;
@@ -77,5 +144,11 @@
 		return NULL; /* Out of memory? */
 
 	of_get_regulation_constraints(dev->of_node, &init_data);
+	rc = of_get_qcom_regulator_init_data(dev, &init_data);
+	if (rc) {
+		devm_kfree(dev, init_data);
+		return NULL;
+	}
+
 	return init_data;
 }
diff --git a/drivers/regulator/pm8xxx-regulator.c b/drivers/regulator/pm8xxx-regulator.c
index 833c513..dfdbb44 100644
--- a/drivers/regulator/pm8xxx-regulator.c
+++ b/drivers/regulator/pm8xxx-regulator.c
@@ -595,6 +595,29 @@
 	return enabled;
 }
 
+/*
+ * Adds delay when increasing in voltage to account for the slew rate of
+ * the regulator.
+ */
+static void pm8xxx_vreg_delay_for_slew(struct pm8xxx_vreg *vreg, int prev_uV,
+					int new_uV)
+{
+	int delay;
+
+	if (vreg->pdata.slew_rate == 0 || new_uV <= prev_uV ||
+	    !_pm8xxx_vreg_is_enabled(vreg))
+		return;
+
+	delay = DIV_ROUND_UP(new_uV - prev_uV, vreg->pdata.slew_rate);
+
+	if (delay >= 1000) {
+		mdelay(delay / 1000);
+		udelay(delay % 1000);
+	} else {
+		udelay(delay);
+	}
+}
+
 static int pm8xxx_pldo_get_voltage(struct regulator_dev *rdev)
 {
 	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
@@ -655,7 +678,7 @@
 {
 	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
 	int rc = 0, uV = min_uV;
-	int vmin;
+	int vmin, prev_uV;
 	unsigned vprog, fine_step;
 	u8 range_ext, range_sel, fine_step_reg, prev_reg;
 	bool reg_changed = false;
@@ -699,6 +722,8 @@
 		return -EINVAL;
 	}
 
+	prev_uV = pm8xxx_pldo_get_voltage(rdev);
+
 	mutex_lock(&vreg->pc_lock);
 
 	/* Write fine step, range select and program voltage update. */
@@ -746,8 +771,10 @@
 
 	if (rc)
 		vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
-	else
+	else {
+		pm8xxx_vreg_delay_for_slew(vreg, prev_uV, uV);
 		pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_VOLTAGE);
+	}
 
 	return rc;
 }
@@ -783,7 +810,7 @@
 {
 	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
 	unsigned vprog, fine_step_reg, prev_reg;
-	int rc;
+	int rc, prev_uV;
 	int uV = min_uV;
 
 	if (uV < NLDO_UV_MIN && max_uV >= NLDO_UV_MIN)
@@ -808,6 +835,8 @@
 		return -EINVAL;
 	}
 
+	prev_uV = pm8xxx_nldo_get_voltage(rdev);
+
 	mutex_lock(&vreg->pc_lock);
 
 	/* Write fine step. */
@@ -840,8 +869,10 @@
 
 	if (rc)
 		vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
-	else
+	else {
+		pm8xxx_vreg_delay_for_slew(vreg, prev_uV, uV);
 		pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_VOLTAGE);
+	}
 
 	return rc;
 }
@@ -897,7 +928,7 @@
 		int max_uV)
 {
 	u8 vprog, range;
-	int rc;
+	int rc, prev_uV;
 	int uV = min_uV;
 
 	if (uV < NLDO1200_LOW_UV_MIN && max_uV >= NLDO1200_LOW_UV_MIN)
@@ -931,6 +962,8 @@
 		return -EINVAL;
 	}
 
+	prev_uV = _pm8xxx_nldo1200_get_voltage(vreg);
+
 	/* Set to advanced mode */
 	rc = pm8xxx_vreg_masked_write(vreg, vreg->test_addr,
 		NLDO1200_ADVANCED_MODE | REGULATOR_BANK_SEL(2)
@@ -948,6 +981,7 @@
 
 	vreg->save_uV = uV;
 
+	pm8xxx_vreg_delay_for_slew(vreg, prev_uV, uV);
 bail:
 	if (rc)
 		vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
@@ -1208,6 +1242,9 @@
 {
 	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
 	int rc = 0;
+	int prev_uV, new_uV;
+
+	prev_uV = pm8xxx_smps_get_voltage(rdev);
 
 	mutex_lock(&vreg->pc_lock);
 
@@ -1218,8 +1255,12 @@
 
 	mutex_unlock(&vreg->pc_lock);
 
-	if (!rc)
+	new_uV = pm8xxx_smps_get_voltage(rdev);
+
+	if (!rc) {
+		pm8xxx_vreg_delay_for_slew(vreg, prev_uV, new_uV);
 		pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_VOLTAGE);
+	}
 
 	return rc;
 }
@@ -1291,6 +1332,7 @@
 	int rc = 0;
 	u8 vprog, band;
 	int uV = min_uV;
+	int prev_uV;
 
 	if (uV < FTSMPS_BAND1_UV_MIN && max_uV >= FTSMPS_BAND1_UV_MIN)
 		uV = FTSMPS_BAND1_UV_MIN;
@@ -1336,6 +1378,8 @@
 		return -EINVAL;
 	}
 
+	prev_uV = _pm8xxx_ftsmps_get_voltage(vreg);
+
 	/*
 	 * Do not set voltage if regulator is currently disabled because doing
 	 * so will enable it.
@@ -1358,6 +1402,8 @@
 
 	vreg->save_uV = uV;
 
+	pm8xxx_vreg_delay_for_slew(vreg, prev_uV, uV);
+
 bail:
 	if (rc)
 		vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
@@ -1402,7 +1448,7 @@
 				  int max_uV, unsigned *selector)
 {
 	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc;
+	int rc, prev_uV;
 	int uV = min_uV;
 	u8 val;
 
@@ -1426,13 +1472,17 @@
 		return -EINVAL;
 	}
 
+	prev_uV = pm8xxx_ncp_get_voltage(rdev);
+
 	/* voltage setting */
 	rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr, val,
 			NCP_VPROG_MASK, &vreg->ctrl_reg);
 	if (rc)
 		vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
-	else
+	else {
+		pm8xxx_vreg_delay_for_slew(vreg, prev_uV, uV);
 		pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_VOLTAGE);
+	}
 
 	return rc;
 }
@@ -1460,7 +1510,7 @@
 				   int max_uV, unsigned *selector)
 {
 	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc;
+	int rc, prev_uV;
 	int uV = min_uV;
 	u8 val;
 
@@ -1484,13 +1534,17 @@
 		return -EINVAL;
 	}
 
+	prev_uV = pm8xxx_boost_get_voltage(rdev);
+
 	/* voltage setting */
 	rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr, val,
 			BOOST_VPROG_MASK, &vreg->ctrl_reg);
 	if (rc)
 		vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
-	else
+	else {
+		pm8xxx_vreg_delay_for_slew(vreg, prev_uV, uV);
 		pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_VOLTAGE);
+	}
 
 	return rc;
 }
@@ -3151,6 +3205,16 @@
 			sizeof(struct pm8xxx_regulator_platform_data));
 		vreg->pdata.pin_ctrl = pin_ctrl;
 		vreg->pdata.pin_fn = pin_fn;
+		/*
+		 * If slew_rate isn't specified but enable_time is, then set
+		 * slew_rate = max_uV / enable_time.
+		 */
+		if (vreg->pdata.enable_time > 0
+		    && vreg->pdata.init_data.constraints.max_uV > 0
+		    && vreg->pdata.slew_rate <= 0)
+			vreg->pdata.slew_rate =
+			  DIV_ROUND_UP(vreg->pdata.init_data.constraints.max_uV,
+					vreg->pdata.enable_time);
 		vreg->dev = &pdev->dev;
 	} else {
 		/* Pin control regulator */
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index 2fc95af..152bbb4 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -392,6 +392,7 @@
 	u32 num_transfers;
 
 	atomic_set(&dd->rx_irq_called, 0);
+	atomic_set(&dd->tx_irq_called, 0);
 	if (dd->write_len && !dd->read_len) {
 		/* WR-WR transfer */
 		bytes_sent = dd->cur_msg_len - dd->tx_bytes_remaining;
@@ -712,6 +713,8 @@
 		    readl_relaxed(dd->base + SPI_OPERATIONAL) &
 		    SPI_OP_MAX_OUTPUT_DONE_FLAG) {
 			msm_spi_ack_transfer(dd);
+			if (atomic_inc_return(&dd->tx_irq_called) == 1)
+				return IRQ_HANDLED;
 			msm_spi_complete(dd);
 			return IRQ_HANDLED;
 		}
@@ -1586,9 +1589,12 @@
 	}
 	/* restore original context */
 	dd = container_of(cmd, struct msm_spi, tx_hdr);
-	if (result & DMOV_RSLT_DONE)
+	if (result & DMOV_RSLT_DONE) {
 		dd->stat_dmov_tx++;
-	else {
+		if ((atomic_inc_return(&dd->tx_irq_called) == 1))
+			return;
+		complete(&dd->transfer_complete);
+	} else {
 		/* Error or flush */
 		if (result & DMOV_RSLT_ERROR) {
 			dev_err(dd->dev, "DMA error (0x%08x)\n", result);
diff --git a/drivers/spi/spi_qsd.h b/drivers/spi/spi_qsd.h
index a434bbb..223fce6 100644
--- a/drivers/spi/spi_qsd.h
+++ b/drivers/spi/spi_qsd.h
@@ -285,6 +285,7 @@
 	int                      output_block_size;
 	int                      burst_size;
 	atomic_t                 rx_irq_called;
+	atomic_t                 tx_irq_called;
 	/* Used to pad messages unaligned to block size */
 	u8                       *tx_padding;
 	dma_addr_t               tx_padding_dma;
diff --git a/drivers/spmi/spmi.c b/drivers/spmi/spmi.c
index 20a290a..f0cb924 100644
--- a/drivers/spmi/spmi.c
+++ b/drivers/spmi/spmi.c
@@ -19,7 +19,7 @@
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/spmi.h>
-
+#include <linux/pm_runtime.h>
 struct spmii_boardinfo {
 	struct list_head	list;
 	struct spmi_boardinfo	board_info;
diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c
index 70131fa..ccb8012 100644
--- a/drivers/staging/android/lowmemorykiller.c
+++ b/drivers/staging/android/lowmemorykiller.c
@@ -29,14 +29,17 @@
  *
  */
 
-#include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/oom.h>
-#include <linux/sched.h>
-#include <linux/notifier.h>
+#include <linux/kobject.h>
 #include <linux/memory.h>
 #include <linux/memory_hotplug.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+#include <linux/oom.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
 
 static uint32_t lowmem_debug_level = 2;
 static int lowmem_adj[6] = {
@@ -54,9 +57,12 @@
 };
 static int lowmem_minfree_size = 4;
 
+static size_t lowmem_minfree_notif_trigger;
+
 static unsigned int offlining;
 static struct task_struct *lowmem_deathpending;
 static unsigned long lowmem_deathpending_timeout;
+static struct kobject *lowmem_kobj;
 
 #define lowmem_print(level, x...)			\
 	do {						\
@@ -108,6 +114,29 @@
 
 
 
+static void lowmem_notify_killzone_approach(void);
+
+static inline void get_free_ram(int *other_free, int *other_file)
+{
+	struct zone *zone;
+	*other_free = global_page_state(NR_FREE_PAGES);
+	*other_file = global_page_state(NR_FILE_PAGES) -
+						global_page_state(NR_SHMEM);
+
+	if (offlining) {
+		/* Discount all free space in the section being offlined */
+		for_each_zone(zone) {
+			 if (zone_idx(zone) == ZONE_MOVABLE) {
+				*other_free -= zone_page_state(zone,
+						NR_FREE_PAGES);
+				lowmem_print(4, "lowmem_shrink discounted "
+					"%lu pages in movable zone\n",
+					zone_page_state(zone, NR_FREE_PAGES));
+			}
+		}
+	}
+}
+
 static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc)
 {
 	struct task_struct *p;
@@ -119,23 +148,8 @@
 	int selected_tasksize = 0;
 	int selected_oom_adj;
 	int array_size = ARRAY_SIZE(lowmem_adj);
-	int other_free = global_page_state(NR_FREE_PAGES);
-	int other_file = global_page_state(NR_FILE_PAGES) -
-						global_page_state(NR_SHMEM);
-	struct zone *zone;
-
-	if (offlining) {
-		/* Discount all free space in the section being offlined */
-		for_each_zone(zone) {
-			 if (zone_idx(zone) == ZONE_MOVABLE) {
-				other_free -= zone_page_state(zone,
-						NR_FREE_PAGES);
-				lowmem_print(4, "lowmem_shrink discounted "
-					"%lu pages in movable zone\n",
-					zone_page_state(zone, NR_FREE_PAGES));
-			}
-		}
-	}
+	int other_free;
+	int other_file;
 	/*
 	 * If we already have a death outstanding, then
 	 * bail out right away; indicating to vmscan
@@ -147,6 +161,13 @@
 	    time_before_eq(jiffies, lowmem_deathpending_timeout))
 		return 0;
 
+	get_free_ram(&other_free, &other_file);
+
+	if (other_free < lowmem_minfree_notif_trigger &&
+			other_file < lowmem_minfree_notif_trigger) {
+		lowmem_notify_killzone_approach();
+	}
+
 	if (lowmem_adj_size < array_size)
 		array_size = lowmem_adj_size;
 	if (lowmem_minfree_size < array_size)
@@ -228,18 +249,91 @@
 	.seeks = DEFAULT_SEEKS * 16
 };
 
+static void lowmem_notify_killzone_approach(void)
+{
+	lowmem_print(3, "notification trigger activated\n");
+	sysfs_notify(lowmem_kobj, NULL, "notify_trigger_active");
+}
+
+static ssize_t lowmem_notify_trigger_active_show(struct kobject *k,
+		struct kobj_attribute *attr, char *buf)
+{
+	int other_free, other_file;
+	get_free_ram(&other_free, &other_file);
+	if (other_free < lowmem_minfree_notif_trigger &&
+			other_file < lowmem_minfree_notif_trigger)
+		return snprintf(buf, 3, "1\n");
+	else
+		return snprintf(buf, 3, "0\n");
+}
+
+static struct kobj_attribute lowmem_notify_trigger_active_attr =
+	__ATTR(notify_trigger_active, S_IRUGO,
+			lowmem_notify_trigger_active_show, NULL);
+
+static struct attribute *lowmem_default_attrs[] = {
+	&lowmem_notify_trigger_active_attr.attr,
+	NULL,
+};
+
+static ssize_t lowmem_show(struct kobject *k, struct attribute *attr, char *buf)
+{
+	struct kobj_attribute *kobj_attr;
+	kobj_attr = container_of(attr, struct kobj_attribute, attr);
+	return kobj_attr->show(k, kobj_attr, buf);
+}
+
+static const struct sysfs_ops lowmem_ops = {
+	.show = lowmem_show,
+};
+
+static void lowmem_kobj_release(struct kobject *kobj)
+{
+	/* Nothing to be done here */
+}
+
+static struct kobj_type lowmem_kobj_type = {
+	.release = lowmem_kobj_release,
+	.sysfs_ops = &lowmem_ops,
+	.default_attrs = lowmem_default_attrs,
+};
+
 static int __init lowmem_init(void)
 {
+	int rc;
 	task_free_register(&task_nb);
 	register_shrinker(&lowmem_shrinker);
 #ifdef CONFIG_MEMORY_HOTPLUG
 	hotplug_memory_notifier(lmk_hotplug_callback, 0);
 #endif
+
+	lowmem_kobj = kzalloc(sizeof(*lowmem_kobj), GFP_KERNEL);
+	if (!lowmem_kobj) {
+		rc = -ENOMEM;
+		goto err;
+	}
+
+	rc = kobject_init_and_add(lowmem_kobj, &lowmem_kobj_type,
+			mm_kobj, "lowmemkiller");
+	if (rc)
+		goto err_kobj;
+
 	return 0;
+
+err_kobj:
+	kfree(lowmem_kobj);
+
+err:
+	unregister_shrinker(&lowmem_shrinker);
+	task_free_unregister(&task_nb);
+
+	return rc;
 }
 
 static void __exit lowmem_exit(void)
 {
+	kobject_put(lowmem_kobj);
+	kfree(lowmem_kobj);
 	unregister_shrinker(&lowmem_shrinker);
 	task_free_unregister(&task_nb);
 }
@@ -250,6 +344,8 @@
 module_param_array_named(minfree, lowmem_minfree, uint, &lowmem_minfree_size,
 			 S_IRUGO | S_IWUSR);
 module_param_named(debug_level, lowmem_debug_level, uint, S_IRUGO | S_IWUSR);
+module_param_named(notify_trigger, lowmem_minfree_notif_trigger, uint,
+			 S_IRUGO | S_IWUSR);
 
 module_init(lowmem_init);
 module_exit(lowmem_exit);
diff --git a/drivers/thermal/msm8960_tsens.c b/drivers/thermal/msm8960_tsens.c
index fbb377e..78a1292 100644
--- a/drivers/thermal/msm8960_tsens.c
+++ b/drivers/thermal/msm8960_tsens.c
@@ -723,7 +723,8 @@
 	} else if (tmdev->hw_type == APQ_8064) {
 		reg_cntl |= TSENS_8960_SLP_CLK_ENA |
 			(TSENS_MEASURE_PERIOD << 18) |
-			TSENS_8064_SENSORS_EN;
+			(((1 << tmdev->tsens_num_sensor) - 1)
+					<< TSENS_SENSOR0_SHIFT);
 		writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
 		reg_status_cntl = readl_relaxed(TSENS_8064_STATUS_CNTL);
 		reg_status_cntl |= TSENS_MIN_STATUS_MASK |
@@ -823,7 +824,8 @@
 	} else if (tmdev->hw_type == APQ_8064) {
 		reg_cntl |= TSENS_8960_SLP_CLK_ENA |
 			(TSENS_MEASURE_PERIOD << 18) |
-			TSENS_8064_SENSORS_EN;
+			(((1 << tmdev->tsens_num_sensor) - 1)
+					<< TSENS_SENSOR0_SHIFT);
 		writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
 		reg_status_cntl = readl_relaxed(TSENS_8064_STATUS_CNTL);
 		reg_status_cntl |= TSENS_LOWER_STATUS_CLR |
diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig
index bd7cc05..ae5a62c 100644
--- a/drivers/tty/Kconfig
+++ b/drivers/tty/Kconfig
@@ -319,6 +319,25 @@
 	  This line discipline provides support for the GSM MUX protocol and
 	  presents the mux as a set of 61 individual tty devices.
 
+config N_SMUX
+	tristate "SMUX line discipline support"
+	depends on NET && SERIAL_MSM_HS
+	help
+	  This line discipline provides support for the Serial MUX protocol
+	  and provides a TTY and kernel API for multiple logical channels.
+
+config N_SMUX_LOOPBACK
+	tristate "SMUX line discipline loopback support"
+	depends on N_SMUX
+	help
+	  Provides loopback and unit testing support for the Serial MUX Protocol.
+
+config SMUX_CTL
+	tristate "SMUX control driver"
+	depends on N_SMUX
+	help
+	  Support for SMUX control driver on top of serial MUX.
+
 config TRACE_ROUTER
 	tristate "Trace data router for MIPI P1149.7 cJTAG standard"
 	depends on TRACE_SINK
diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile
index ea89b0b..3078e8d 100644
--- a/drivers/tty/Makefile
+++ b/drivers/tty/Makefile
@@ -6,6 +6,9 @@
 obj-$(CONFIG_MAGIC_SYSRQ)	+= sysrq.o
 obj-$(CONFIG_N_HDLC)		+= n_hdlc.o
 obj-$(CONFIG_N_GSM)		+= n_gsm.o
+obj-$(CONFIG_N_SMUX)		+= n_smux.o
+obj-$(CONFIG_N_SMUX_LOOPBACK)	+= smux_test.o smux_loopback.o
+obj-$(CONFIG_SMUX_CTL)		+= smux_ctl.o
 obj-$(CONFIG_TRACE_ROUTER)	+= n_tracerouter.o
 obj-$(CONFIG_TRACE_SINK)	+= n_tracesink.o
 obj-$(CONFIG_R3964)		+= n_r3964.o
diff --git a/drivers/tty/n_smux.c b/drivers/tty/n_smux.c
new file mode 100644
index 0000000..5b5de03
--- /dev/null
+++ b/drivers/tty/n_smux.c
@@ -0,0 +1,3146 @@
+/* drivers/tty/n_smux.c
+ *
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/tty_driver.h>
+#include <linux/smux.h>
+#include <linux/list.h>
+#include <linux/kfifo.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <mach/msm_serial_hs.h>
+#include "smux_private.h"
+#include "smux_loopback.h"
+
+#define SMUX_NOTIFY_FIFO_SIZE	128
+#define SMUX_TX_QUEUE_SIZE	256
+#define SMUX_WM_LOW 2
+#define SMUX_WM_HIGH 4
+#define SMUX_PKT_LOG_SIZE 80
+
+/* Maximum size we can accept in a single RX buffer */
+#define TTY_RECEIVE_ROOM 65536
+#define TTY_BUFFER_FULL_WAIT_MS 50
+
+/* maximum sleep time between wakeup attempts */
+#define SMUX_WAKEUP_DELAY_MAX (1 << 20)
+
+/* minimum delay for scheduling delayed work */
+#define SMUX_WAKEUP_DELAY_MIN (1 << 15)
+
+/* inactivity timeout for no rx/tx activity */
+#define SMUX_INACTIVITY_TIMEOUT_MS 1000
+
+/* RX get_rx_buffer retry timeout values */
+#define SMUX_RX_RETRY_MIN_MS (1 << 0)  /* 1 ms */
+#define SMUX_RX_RETRY_MAX_MS (1 << 10) /* 1024 ms */
+
+enum {
+	MSM_SMUX_DEBUG = 1U << 0,
+	MSM_SMUX_INFO = 1U << 1,
+	MSM_SMUX_POWER_INFO = 1U << 2,
+	MSM_SMUX_PKT = 1U << 3,
+};
+
+static int smux_debug_mask;
+module_param_named(debug_mask, smux_debug_mask,
+		   int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+/* Simulated wakeup used for testing */
+int smux_byte_loopback;
+module_param_named(byte_loopback, smux_byte_loopback,
+		   int, S_IRUGO | S_IWUSR | S_IWGRP);
+int smux_simulate_wakeup_delay = 1;
+module_param_named(simulate_wakeup_delay, smux_simulate_wakeup_delay,
+		   int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+#define SMUX_DBG(x...) do {                              \
+	if (smux_debug_mask & MSM_SMUX_DEBUG) \
+			pr_info(x);  \
+} while (0)
+
+#define SMUX_LOG_PKT_RX(pkt) do { \
+	if (smux_debug_mask & MSM_SMUX_PKT) \
+			smux_log_pkt(pkt, 1); \
+} while (0)
+
+#define SMUX_LOG_PKT_TX(pkt) do { \
+	if (smux_debug_mask & MSM_SMUX_PKT) \
+			smux_log_pkt(pkt, 0); \
+} while (0)
+
+/**
+ * Return true if channel is fully opened (both
+ * local and remote sides are in the OPENED state).
+ */
+#define IS_FULLY_OPENED(ch) \
+	(ch && (ch)->local_state == SMUX_LCH_LOCAL_OPENED \
+	 && (ch)->remote_state == SMUX_LCH_REMOTE_OPENED)
+
+static struct platform_device smux_devs[] = {
+	{.name = "SMUX_CTL", .id = -1},
+	{.name = "SMUX_RMNET", .id = -1},
+	{.name = "SMUX_DUN_DATA_HSUART", .id = 0},
+	{.name = "SMUX_RMNET_DATA_HSUART", .id = 1},
+	{.name = "SMUX_RMNET_CTL_HSUART", .id = 0},
+	{.name = "SMUX_DIAG", .id = -1},
+};
+
+enum {
+	SMUX_CMD_STATUS_RTC = 1 << 0,
+	SMUX_CMD_STATUS_RTR = 1 << 1,
+	SMUX_CMD_STATUS_RI = 1 << 2,
+	SMUX_CMD_STATUS_DCD = 1 << 3,
+	SMUX_CMD_STATUS_FLOW_CNTL = 1 << 4,
+};
+
+/* Channel mode */
+enum {
+	SMUX_LCH_MODE_NORMAL,
+	SMUX_LCH_MODE_LOCAL_LOOPBACK,
+	SMUX_LCH_MODE_REMOTE_LOOPBACK,
+};
+
+enum {
+	SMUX_RX_IDLE,
+	SMUX_RX_MAGIC,
+	SMUX_RX_HDR,
+	SMUX_RX_PAYLOAD,
+	SMUX_RX_FAILURE,
+};
+
+/**
+ * Power states.
+ *
+ * The _FLUSH states are internal transitional states and are not part of the
+ * official state machine.
+ */
+enum {
+	SMUX_PWR_OFF,
+	SMUX_PWR_TURNING_ON,
+	SMUX_PWR_ON,
+	SMUX_PWR_TURNING_OFF_FLUSH,
+	SMUX_PWR_TURNING_OFF,
+	SMUX_PWR_OFF_FLUSH,
+};
+
+/**
+ * Logical Channel Structure.  One instance per channel.
+ *
+ * Locking Hierarchy
+ * Each lock has a postfix that describes the locking level.  If multiple locks
+ * are required, only increasing lock hierarchy numbers may be locked which
+ * ensures avoiding a deadlock.
+ *
+ * Locking Example
+ * If state_lock_lhb1 is currently held and the TX list needs to be
+ * manipulated, then tx_lock_lhb2 may be locked since it's locking hierarchy
+ * is greater.  However, if tx_lock_lhb2 is held, then state_lock_lhb1 may
+ * not be acquired since it would result in a deadlock.
+ *
+ * Note that the Line Discipline locks (*_lha) should always be acquired
+ * before the logical channel locks.
+ */
+struct smux_lch_t {
+	/* channel state */
+	spinlock_t state_lock_lhb1;
+	uint8_t lcid;
+	unsigned local_state;
+	unsigned local_mode;
+	uint8_t local_tiocm;
+
+	unsigned remote_state;
+	unsigned remote_mode;
+	uint8_t remote_tiocm;
+
+	int tx_flow_control;
+
+	/* client callbacks and private data */
+	void *priv;
+	void (*notify)(void *priv, int event_type, const void *metadata);
+	int (*get_rx_buffer)(void *priv, void **pkt_priv, void **buffer,
+								int size);
+
+	/* RX Info */
+	struct list_head rx_retry_queue;
+	unsigned rx_retry_queue_cnt;
+	struct delayed_work rx_retry_work;
+
+	/* TX Info */
+	spinlock_t tx_lock_lhb2;
+	struct list_head tx_queue;
+	struct list_head tx_ready_list;
+	unsigned tx_pending_data_cnt;
+	unsigned notify_lwm;
+};
+
+union notifier_metadata {
+	struct smux_meta_disconnected disconnected;
+	struct smux_meta_read read;
+	struct smux_meta_write write;
+	struct smux_meta_tiocm tiocm;
+};
+
+struct smux_notify_handle {
+	void (*notify)(void *priv, int event_type, const void *metadata);
+	void *priv;
+	int event_type;
+	union notifier_metadata *metadata;
+};
+
+/**
+ * Get RX Buffer Retry structure.
+ *
+ * This is used for clients that are unable to provide an RX buffer
+ * immediately.  This temporary structure will be used to temporarily hold the
+ * data and perform a retry.
+ */
+struct smux_rx_pkt_retry {
+	struct smux_pkt_t *pkt;
+	struct list_head rx_retry_list;
+	unsigned timeout_in_ms;
+};
+
+/**
+ * Receive worker data structure.
+ *
+ * One instance is created for every call to smux_rx_state_machine.
+ */
+struct smux_rx_worker_data {
+	const unsigned char *data;
+	int len;
+	int flag;
+
+	struct work_struct work;
+	struct completion work_complete;
+};
+
+/**
+ * Line discipline and module structure.
+ *
+ * Only one instance since multiple instances of line discipline are not
+ * allowed.
+ */
+struct smux_ldisc_t {
+	spinlock_t lock_lha0;
+
+	int is_initialized;
+	int in_reset;
+	int ld_open_count;
+	struct tty_struct *tty;
+
+	/* RX State Machine (singled-threaded access by smux_rx_wq) */
+	unsigned char recv_buf[SMUX_MAX_PKT_SIZE];
+	unsigned int recv_len;
+	unsigned int pkt_remain;
+	unsigned rx_state;
+
+	/* RX Activity - accessed by multiple threads */
+	spinlock_t rx_lock_lha1;
+	unsigned rx_activity_flag;
+
+	/* TX / Power */
+	spinlock_t tx_lock_lha2;
+	struct list_head lch_tx_ready_list;
+	unsigned power_state;
+	unsigned pwr_wakeup_delay_us;
+	unsigned tx_activity_flag;
+	unsigned powerdown_enabled;
+};
+
+
+/* data structures */
+static struct smux_lch_t smux_lch[SMUX_NUM_LOGICAL_CHANNELS];
+static struct smux_ldisc_t smux;
+static const char *tty_error_type[] = {
+	[TTY_NORMAL] = "normal",
+	[TTY_OVERRUN] = "overrun",
+	[TTY_BREAK] = "break",
+	[TTY_PARITY] = "parity",
+	[TTY_FRAME] = "framing",
+};
+
+static const char *smux_cmds[] = {
+	[SMUX_CMD_DATA] = "DATA",
+	[SMUX_CMD_OPEN_LCH] = "OPEN",
+	[SMUX_CMD_CLOSE_LCH] = "CLOSE",
+	[SMUX_CMD_STATUS] = "STATUS",
+	[SMUX_CMD_PWR_CTL] = "PWR",
+	[SMUX_CMD_BYTE] = "Raw Byte",
+};
+
+static void smux_notify_local_fn(struct work_struct *work);
+static DECLARE_WORK(smux_notify_local, smux_notify_local_fn);
+
+static struct workqueue_struct *smux_notify_wq;
+static size_t handle_size;
+static struct kfifo smux_notify_fifo;
+static int queued_fifo_notifications;
+static DEFINE_SPINLOCK(notify_lock_lhc1);
+
+static struct workqueue_struct *smux_tx_wq;
+static struct workqueue_struct *smux_rx_wq;
+static void smux_tx_worker(struct work_struct *work);
+static DECLARE_WORK(smux_tx_work, smux_tx_worker);
+
+static void smux_wakeup_worker(struct work_struct *work);
+static void smux_rx_retry_worker(struct work_struct *work);
+static void smux_rx_worker(struct work_struct *work);
+static DECLARE_WORK(smux_wakeup_work, smux_wakeup_worker);
+static DECLARE_DELAYED_WORK(smux_wakeup_delayed_work, smux_wakeup_worker);
+
+static void smux_inactivity_worker(struct work_struct *work);
+static DECLARE_WORK(smux_inactivity_work, smux_inactivity_worker);
+static DECLARE_DELAYED_WORK(smux_delayed_inactivity_work,
+		smux_inactivity_worker);
+
+static long msm_smux_tiocm_get_atomic(struct smux_lch_t *ch);
+static void list_channel(struct smux_lch_t *ch);
+static int smux_send_status_cmd(struct smux_lch_t *ch);
+static int smux_dispatch_rx_pkt(struct smux_pkt_t *pkt);
+
+/**
+ * Convert TTY Error Flags to string for logging purposes.
+ *
+ * @flag    TTY_* flag
+ * @returns String description or NULL if unknown
+ */
+static const char *tty_flag_to_str(unsigned flag)
+{
+	if (flag < ARRAY_SIZE(tty_error_type))
+		return tty_error_type[flag];
+	return NULL;
+}
+
+/**
+ * Convert SMUX Command to string for logging purposes.
+ *
+ * @cmd    SMUX command
+ * @returns String description or NULL if unknown
+ */
+static const char *cmd_to_str(unsigned cmd)
+{
+	if (cmd < ARRAY_SIZE(smux_cmds))
+		return smux_cmds[cmd];
+	return NULL;
+}
+
+/**
+ * Set the reset state due to an unrecoverable failure.
+ */
+static void smux_enter_reset(void)
+{
+	pr_err("%s: unrecoverable failure, waiting for ssr\n", __func__);
+	smux.in_reset = 1;
+}
+
+static int lch_init(void)
+{
+	unsigned int id;
+	struct smux_lch_t *ch;
+	int i = 0;
+
+	handle_size = sizeof(struct smux_notify_handle *);
+
+	smux_notify_wq = create_singlethread_workqueue("smux_notify_wq");
+	smux_tx_wq = create_singlethread_workqueue("smux_tx_wq");
+	smux_rx_wq = create_singlethread_workqueue("smux_rx_wq");
+
+	if (IS_ERR(smux_notify_wq) || IS_ERR(smux_tx_wq)) {
+		SMUX_DBG("%s: create_singlethread_workqueue ENOMEM\n",
+							__func__);
+		return -ENOMEM;
+	}
+
+	i |= kfifo_alloc(&smux_notify_fifo,
+			SMUX_NOTIFY_FIFO_SIZE * handle_size,
+			GFP_KERNEL);
+	i |= smux_loopback_init();
+
+	if (i) {
+		pr_err("%s: out of memory error\n", __func__);
+		return -ENOMEM;
+	}
+
+	for (id = 0 ; id < SMUX_NUM_LOGICAL_CHANNELS; id++) {
+		ch = &smux_lch[id];
+
+		spin_lock_init(&ch->state_lock_lhb1);
+		ch->lcid = id;
+		ch->local_state = SMUX_LCH_LOCAL_CLOSED;
+		ch->local_mode = SMUX_LCH_MODE_NORMAL;
+		ch->local_tiocm = 0x0;
+		ch->remote_state = SMUX_LCH_REMOTE_CLOSED;
+		ch->remote_mode = SMUX_LCH_MODE_NORMAL;
+		ch->remote_tiocm = 0x0;
+		ch->tx_flow_control = 0;
+		ch->priv = 0;
+		ch->notify = 0;
+		ch->get_rx_buffer = 0;
+
+		INIT_LIST_HEAD(&ch->rx_retry_queue);
+		ch->rx_retry_queue_cnt = 0;
+		INIT_DELAYED_WORK(&ch->rx_retry_work, smux_rx_retry_worker);
+
+		spin_lock_init(&ch->tx_lock_lhb2);
+		INIT_LIST_HEAD(&ch->tx_queue);
+		INIT_LIST_HEAD(&ch->tx_ready_list);
+		ch->tx_pending_data_cnt = 0;
+		ch->notify_lwm = 0;
+	}
+
+	return 0;
+}
+
+int smux_assert_lch_id(uint32_t lcid)
+{
+	if (lcid >= SMUX_NUM_LOGICAL_CHANNELS)
+		return -ENXIO;
+	else
+		return 0;
+}
+
+/**
+ * Log packet information for debug purposes.
+ *
+ * @pkt     Packet to log
+ * @is_recv 1 = RX packet; 0 = TX Packet
+ *
+ * [DIR][LCID] [LOCAL_STATE][LOCAL_MODE]:[REMOTE_STATE][REMOTE_MODE] PKT Info
+ *
+ * PKT Info:
+ *   [CMD] flags [flags] len [PAYLOAD_LEN]:[PAD_LEN] [Payload hex bytes]
+ *
+ * Direction:  R = Receive, S = Send
+ * Local State:  C = Closed; c = closing; o = opening; O = Opened
+ * Local Mode: L = Local loopback; R = Remote loopback; N = Normal
+ * Remote State: C = Closed; O = Opened
+ * Remote Mode: R = Remote loopback; N = Normal
+ */
+static void smux_log_pkt(struct smux_pkt_t *pkt, int is_recv)
+{
+	char logbuf[SMUX_PKT_LOG_SIZE];
+	char cmd_extra[16];
+	int i = 0;
+	int count;
+	int len;
+	char local_state;
+	char local_mode;
+	char remote_state;
+	char remote_mode;
+	struct smux_lch_t *ch;
+	unsigned char *data;
+
+	ch = &smux_lch[pkt->hdr.lcid];
+
+	switch (ch->local_state) {
+	case SMUX_LCH_LOCAL_CLOSED:
+		local_state = 'C';
+		break;
+	case SMUX_LCH_LOCAL_OPENING:
+		local_state = 'o';
+		break;
+	case SMUX_LCH_LOCAL_OPENED:
+		local_state = 'O';
+		break;
+	case SMUX_LCH_LOCAL_CLOSING:
+		local_state = 'c';
+		break;
+	default:
+		local_state = 'U';
+		break;
+	}
+
+	switch (ch->local_mode) {
+	case SMUX_LCH_MODE_LOCAL_LOOPBACK:
+		local_mode = 'L';
+		break;
+	case SMUX_LCH_MODE_REMOTE_LOOPBACK:
+		local_mode = 'R';
+		break;
+	case SMUX_LCH_MODE_NORMAL:
+		local_mode = 'N';
+		break;
+	default:
+		local_mode = 'U';
+		break;
+	}
+
+	switch (ch->remote_state) {
+	case SMUX_LCH_REMOTE_CLOSED:
+		remote_state = 'C';
+		break;
+	case SMUX_LCH_REMOTE_OPENED:
+		remote_state = 'O';
+		break;
+
+	default:
+		remote_state = 'U';
+		break;
+	}
+
+	switch (ch->remote_mode) {
+	case SMUX_LCH_MODE_REMOTE_LOOPBACK:
+		remote_mode = 'R';
+		break;
+	case SMUX_LCH_MODE_NORMAL:
+		remote_mode = 'N';
+		break;
+	default:
+		remote_mode = 'U';
+		break;
+	}
+
+	/* determine command type (ACK, etc) */
+	cmd_extra[0] = '\0';
+	switch (pkt->hdr.cmd) {
+	case SMUX_CMD_OPEN_LCH:
+		if (pkt->hdr.flags & SMUX_CMD_OPEN_ACK)
+			snprintf(cmd_extra, sizeof(cmd_extra), " ACK");
+		break;
+	case SMUX_CMD_CLOSE_LCH:
+		if (pkt->hdr.flags & SMUX_CMD_CLOSE_ACK)
+			snprintf(cmd_extra, sizeof(cmd_extra), " ACK");
+		break;
+	};
+
+	i += snprintf(logbuf + i, SMUX_PKT_LOG_SIZE - i,
+			"smux: %c%d %c%c:%c%c %s%s flags %x len %d:%d ",
+			is_recv ? 'R' : 'S', pkt->hdr.lcid,
+			local_state, local_mode,
+			remote_state, remote_mode,
+			cmd_to_str(pkt->hdr.cmd), cmd_extra, pkt->hdr.flags,
+			pkt->hdr.payload_len, pkt->hdr.pad_len);
+
+	len = (pkt->hdr.payload_len > 16) ? 16 : pkt->hdr.payload_len;
+	data = (unsigned char *)pkt->payload;
+	for (count = 0; count < len; count++)
+		i += snprintf(logbuf + i, SMUX_PKT_LOG_SIZE - i,
+				"%02x ", (unsigned)data[count]);
+
+	pr_info("%s\n", logbuf);
+}
+
+static void smux_notify_local_fn(struct work_struct *work)
+{
+	struct smux_notify_handle *notify_handle = NULL;
+	union notifier_metadata *metadata = NULL;
+	unsigned long flags;
+	int i;
+
+	for (;;) {
+		/* retrieve notification */
+		spin_lock_irqsave(&notify_lock_lhc1, flags);
+		if (kfifo_len(&smux_notify_fifo) >= handle_size) {
+			i = kfifo_out(&smux_notify_fifo,
+				&notify_handle,
+				handle_size);
+		if (i != handle_size) {
+			pr_err("%s: unable to retrieve handle %d expected %d\n",
+					__func__, i, handle_size);
+			spin_unlock_irqrestore(&notify_lock_lhc1, flags);
+			break;
+			}
+		} else {
+			spin_unlock_irqrestore(&notify_lock_lhc1, flags);
+			break;
+		}
+		--queued_fifo_notifications;
+		spin_unlock_irqrestore(&notify_lock_lhc1, flags);
+
+		/* notify client */
+		metadata = notify_handle->metadata;
+		notify_handle->notify(notify_handle->priv,
+			notify_handle->event_type,
+			metadata);
+
+		kfree(metadata);
+		kfree(notify_handle);
+	}
+}
+
+/**
+ * Initialize existing packet.
+ */
+void smux_init_pkt(struct smux_pkt_t *pkt)
+{
+	memset(pkt, 0x0, sizeof(*pkt));
+	pkt->hdr.magic = SMUX_MAGIC;
+	INIT_LIST_HEAD(&pkt->list);
+}
+
+/**
+ * Allocate and initialize packet.
+ *
+ * If a payload is needed, either set it directly and ensure that it's freed or
+ * use smd_alloc_pkt_payload() to allocate a packet and it will be freed
+ * automatically when smd_free_pkt() is called.
+ */
+struct smux_pkt_t *smux_alloc_pkt(void)
+{
+	struct smux_pkt_t *pkt;
+
+	/* Consider a free list implementation instead of kmalloc */
+	pkt = kmalloc(sizeof(struct smux_pkt_t), GFP_ATOMIC);
+	if (!pkt) {
+		pr_err("%s: out of memory\n", __func__);
+		return NULL;
+	}
+	smux_init_pkt(pkt);
+	pkt->allocated = 1;
+
+	return pkt;
+}
+
+/**
+ * Free packet.
+ *
+ * @pkt Packet to free (may be NULL)
+ *
+ * If payload was allocated using smux_alloc_pkt_payload(), then it is freed as
+ * well.  Otherwise, the caller is responsible for freeing the payload.
+ */
+void smux_free_pkt(struct smux_pkt_t *pkt)
+{
+	if (pkt) {
+		if (pkt->free_payload)
+			kfree(pkt->payload);
+		if (pkt->allocated)
+			kfree(pkt);
+	}
+}
+
+/**
+ * Allocate packet payload.
+ *
+ * @pkt Packet to add payload to
+ *
+ * @returns 0 on success, <0 upon error
+ *
+ * A flag is set to signal smux_free_pkt() to free the payload.
+ */
+int smux_alloc_pkt_payload(struct smux_pkt_t *pkt)
+{
+	if (!pkt)
+		return -EINVAL;
+
+	pkt->payload = kmalloc(pkt->hdr.payload_len, GFP_ATOMIC);
+	pkt->free_payload = 1;
+	if (!pkt->payload) {
+		pr_err("%s: unable to malloc %d bytes for payload\n",
+				__func__, pkt->hdr.payload_len);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static int schedule_notify(uint8_t lcid, int event,
+			const union notifier_metadata *metadata)
+{
+	struct smux_notify_handle *notify_handle = 0;
+	union notifier_metadata *meta_copy = 0;
+	struct smux_lch_t *ch;
+	int i;
+	unsigned long flags;
+	int ret = 0;
+
+	ch = &smux_lch[lcid];
+	notify_handle = kzalloc(sizeof(struct smux_notify_handle),
+						GFP_ATOMIC);
+	if (!notify_handle) {
+		pr_err("%s: out of memory\n", __func__);
+		ret = -ENOMEM;
+		goto free_out;
+	}
+
+	notify_handle->notify = ch->notify;
+	notify_handle->priv = ch->priv;
+	notify_handle->event_type = event;
+	if (metadata) {
+		meta_copy = kzalloc(sizeof(union notifier_metadata),
+							GFP_ATOMIC);
+		if (!meta_copy) {
+			pr_err("%s: out of memory\n", __func__);
+			ret = -ENOMEM;
+			goto free_out;
+		}
+		*meta_copy = *metadata;
+		notify_handle->metadata = meta_copy;
+	} else {
+		notify_handle->metadata = NULL;
+	}
+
+	spin_lock_irqsave(&notify_lock_lhc1, flags);
+	i = kfifo_avail(&smux_notify_fifo);
+	if (i < handle_size) {
+		pr_err("%s: fifo full error %d expected %d\n",
+					__func__, i, handle_size);
+		ret = -ENOMEM;
+		goto unlock_out;
+	}
+
+	i = kfifo_in(&smux_notify_fifo, &notify_handle, handle_size);
+	if (i < 0 || i != handle_size) {
+		pr_err("%s: fifo not available error %d (expected %d)\n",
+				__func__, i, handle_size);
+		ret = -ENOSPC;
+		goto unlock_out;
+	}
+	++queued_fifo_notifications;
+
+unlock_out:
+	spin_unlock_irqrestore(&notify_lock_lhc1, flags);
+
+free_out:
+	queue_work(smux_notify_wq, &smux_notify_local);
+	if (ret < 0 && notify_handle) {
+		kfree(notify_handle->metadata);
+		kfree(notify_handle);
+	}
+	return ret;
+}
+
+/**
+ * Returns the serialized size of a packet.
+ *
+ * @pkt Packet to serialize
+ *
+ * @returns Serialized length of packet
+ */
+static unsigned int smux_serialize_size(struct smux_pkt_t *pkt)
+{
+	unsigned int size;
+
+	size = sizeof(struct smux_hdr_t);
+	size += pkt->hdr.payload_len;
+	size += pkt->hdr.pad_len;
+
+	return size;
+}
+
+/**
+ * Serialize packet @pkt into output buffer @data.
+ *
+ * @pkt		Packet to serialize
+ * @out     Destination buffer pointer
+ * @out_len	Size of serialized packet
+ *
+ * @returns 0 for success
+ */
+int smux_serialize(struct smux_pkt_t *pkt, char *out,
+					unsigned int *out_len)
+{
+	char *data_start = out;
+
+	if (smux_serialize_size(pkt) > SMUX_MAX_PKT_SIZE) {
+		pr_err("%s: packet size %d too big\n",
+				__func__, smux_serialize_size(pkt));
+		return -E2BIG;
+	}
+
+	memcpy(out, &pkt->hdr, sizeof(struct smux_hdr_t));
+	out += sizeof(struct smux_hdr_t);
+	if (pkt->payload) {
+		memcpy(out, pkt->payload, pkt->hdr.payload_len);
+		out += pkt->hdr.payload_len;
+	}
+	if (pkt->hdr.pad_len) {
+		memset(out, 0x0,  pkt->hdr.pad_len);
+		out += pkt->hdr.pad_len;
+	}
+	*out_len = out - data_start;
+	return 0;
+}
+
+/**
+ * Serialize header and provide pointer to the data.
+ *
+ * @pkt             Packet
+ * @out[out]        Pointer to the serialized header data
+ * @out_len[out]    Pointer to the serialized header length
+ */
+static void smux_serialize_hdr(struct smux_pkt_t *pkt, char **out,
+					unsigned int *out_len)
+{
+	*out = (char *)&pkt->hdr;
+	*out_len = sizeof(struct smux_hdr_t);
+}
+
+/**
+ * Serialize payload and provide pointer to the data.
+ *
+ * @pkt             Packet
+ * @out[out]        Pointer to the serialized payload data
+ * @out_len[out]    Pointer to the serialized payload length
+ */
+static void smux_serialize_payload(struct smux_pkt_t *pkt, char **out,
+					unsigned int *out_len)
+{
+	*out = pkt->payload;
+	*out_len = pkt->hdr.payload_len;
+}
+
+/**
+ * Serialize padding and provide pointer to the data.
+ *
+ * @pkt             Packet
+ * @out[out]        Pointer to the serialized padding (always NULL)
+ * @out_len[out]    Pointer to the serialized payload length
+ *
+ * Since the padding field value is undefined, only the size of the patting
+ * (@out_len) is set and the buffer pointer (@out) will always be NULL.
+ */
+static void smux_serialize_padding(struct smux_pkt_t *pkt, char **out,
+					unsigned int *out_len)
+{
+	*out = NULL;
+	*out_len = pkt->hdr.pad_len;
+}
+
+/**
+ * Write data to TTY framework and handle breaking the writes up if needed.
+ *
+ * @data    Data to write
+ * @len     Length of data
+ *
+ * @returns 0 for success, < 0 for failure
+ */
+static int write_to_tty(char *data, unsigned len)
+{
+	int data_written;
+
+	if (!data)
+		return 0;
+
+	while (len > 0) {
+		data_written = smux.tty->ops->write(smux.tty, data, len);
+		if (data_written >= 0) {
+			len -= data_written;
+			data += data_written;
+		} else {
+			pr_err("%s: TTY write returned error %d\n",
+					__func__, data_written);
+			return data_written;
+		}
+
+		if (len)
+			tty_wait_until_sent(smux.tty,
+				msecs_to_jiffies(TTY_BUFFER_FULL_WAIT_MS));
+
+		/* FUTURE - add SSR logic */
+	}
+	return 0;
+}
+
+/**
+ * Write packet to TTY.
+ *
+ * @pkt packet to write
+ *
+ * @returns 0 on success
+ */
+static int smux_tx_tty(struct smux_pkt_t *pkt)
+{
+	char *data;
+	unsigned int len;
+	int ret;
+
+	if (!smux.tty) {
+		pr_err("%s: TTY not initialized", __func__);
+		return -ENOTTY;
+	}
+
+	if (pkt->hdr.cmd == SMUX_CMD_BYTE) {
+		SMUX_DBG("%s: tty send single byte\n", __func__);
+		ret = write_to_tty(&pkt->hdr.flags, 1);
+		return ret;
+	}
+
+	smux_serialize_hdr(pkt, &data, &len);
+	ret = write_to_tty(data, len);
+	if (ret) {
+		pr_err("%s: failed %d to write header %d\n",
+				__func__, ret, len);
+		return ret;
+	}
+
+	smux_serialize_payload(pkt, &data, &len);
+	ret = write_to_tty(data, len);
+	if (ret) {
+		pr_err("%s: failed %d to write payload %d\n",
+				__func__, ret, len);
+		return ret;
+	}
+
+	smux_serialize_padding(pkt, &data, &len);
+	while (len > 0) {
+		char zero = 0x0;
+		ret = write_to_tty(&zero, 1);
+		if (ret) {
+			pr_err("%s: failed %d to write padding %d\n",
+					__func__, ret, len);
+			return ret;
+		}
+		--len;
+	}
+	return 0;
+}
+
+/**
+ * Send a single character.
+ *
+ * @ch Character to send
+ */
+static void smux_send_byte(char ch)
+{
+	struct smux_pkt_t pkt;
+
+	smux_init_pkt(&pkt);
+
+	pkt.hdr.cmd = SMUX_CMD_BYTE;
+	pkt.hdr.flags = ch;
+	pkt.hdr.lcid = 0;
+	pkt.hdr.flags = ch;
+	SMUX_LOG_PKT_TX(&pkt);
+	if (!smux_byte_loopback)
+		smux_tx_tty(&pkt);
+	else
+		smux_tx_loopback(&pkt);
+}
+
+/**
+ * Receive a single-character packet (used for internal testing).
+ *
+ * @ch   Character to receive
+ * @lcid Logical channel ID for packet
+ *
+ * @returns 0 for success
+ */
+static int smux_receive_byte(char ch, int lcid)
+{
+	struct smux_pkt_t pkt;
+
+	smux_init_pkt(&pkt);
+	pkt.hdr.lcid = lcid;
+	pkt.hdr.cmd = SMUX_CMD_BYTE;
+	pkt.hdr.flags = ch;
+
+	return smux_dispatch_rx_pkt(&pkt);
+}
+
+/**
+ * Queue packet for transmit.
+ *
+ * @pkt_ptr  Packet to queue
+ * @ch       Channel to queue packet on
+ * @queue    Queue channel on ready list
+ */
+static void smux_tx_queue(struct smux_pkt_t *pkt_ptr, struct smux_lch_t *ch,
+		int queue)
+{
+	unsigned long flags;
+
+	SMUX_DBG("%s: queuing pkt %p\n", __func__, pkt_ptr);
+
+	spin_lock_irqsave(&ch->tx_lock_lhb2, flags);
+	list_add_tail(&pkt_ptr->list, &ch->tx_queue);
+	spin_unlock_irqrestore(&ch->tx_lock_lhb2, flags);
+
+	if (queue)
+		list_channel(ch);
+}
+
+/**
+ * Handle receive OPEN ACK command.
+ *
+ * @pkt  Received packet
+ *
+ * @returns 0 for success
+ */
+static int smux_handle_rx_open_ack(struct smux_pkt_t *pkt)
+{
+	uint8_t lcid;
+	int ret;
+	struct smux_lch_t *ch;
+	int enable_powerdown = 0;
+
+	lcid = pkt->hdr.lcid;
+	ch = &smux_lch[lcid];
+
+	spin_lock(&ch->state_lock_lhb1);
+	if (ch->local_state == SMUX_LCH_LOCAL_OPENING) {
+		SMUX_DBG("lcid %d local state 0x%x -> 0x%x\n", lcid,
+				ch->local_state,
+				SMUX_LCH_LOCAL_OPENED);
+
+		if (pkt->hdr.flags & SMUX_CMD_OPEN_POWER_COLLAPSE)
+			enable_powerdown = 1;
+
+		ch->local_state = SMUX_LCH_LOCAL_OPENED;
+		if (ch->remote_state == SMUX_LCH_REMOTE_OPENED)
+			schedule_notify(lcid, SMUX_CONNECTED, NULL);
+		ret = 0;
+	} else if (ch->remote_mode == SMUX_LCH_MODE_REMOTE_LOOPBACK) {
+		SMUX_DBG("Remote loopback OPEN ACK received\n");
+		ret = 0;
+	} else {
+		pr_err("%s: lcid %d state 0x%x open ack invalid\n",
+				__func__, lcid, ch->local_state);
+		ret = -EINVAL;
+	}
+	spin_unlock(&ch->state_lock_lhb1);
+
+	if (enable_powerdown) {
+		spin_lock(&smux.tx_lock_lha2);
+		if (!smux.powerdown_enabled) {
+			smux.powerdown_enabled = 1;
+			SMUX_DBG("%s: enabling power-collapse support\n",
+					__func__);
+		}
+		spin_unlock(&smux.tx_lock_lha2);
+	}
+
+	return ret;
+}
+
+static int smux_handle_close_ack(struct smux_pkt_t *pkt)
+{
+	uint8_t lcid;
+	int ret;
+	struct smux_lch_t *ch;
+	union notifier_metadata meta_disconnected;
+	unsigned long flags;
+
+	lcid = pkt->hdr.lcid;
+	ch = &smux_lch[lcid];
+	meta_disconnected.disconnected.is_ssr = 0;
+
+	spin_lock_irqsave(&ch->state_lock_lhb1, flags);
+
+	if (ch->local_state == SMUX_LCH_LOCAL_CLOSING) {
+		SMUX_DBG("lcid %d local state 0x%x -> 0x%x\n", lcid,
+				SMUX_LCH_LOCAL_CLOSING,
+				SMUX_LCH_LOCAL_CLOSED);
+		ch->local_state = SMUX_LCH_LOCAL_CLOSED;
+		if (ch->remote_state == SMUX_LCH_REMOTE_CLOSED)
+			schedule_notify(lcid, SMUX_DISCONNECTED,
+				&meta_disconnected);
+		ret = 0;
+	} else if (ch->remote_mode == SMUX_LCH_MODE_REMOTE_LOOPBACK) {
+		SMUX_DBG("Remote loopback CLOSE ACK received\n");
+		ret = 0;
+	} else {
+		pr_err("%s: lcid %d state 0x%x close ack invalid\n",
+				__func__, lcid,	ch->local_state);
+		ret = -EINVAL;
+	}
+	spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
+	return ret;
+}
+
+/**
+ * Handle receive OPEN command.
+ *
+ * @pkt  Received packet
+ *
+ * @returns 0 for success
+ */
+static int smux_handle_rx_open_cmd(struct smux_pkt_t *pkt)
+{
+	uint8_t lcid;
+	int ret;
+	struct smux_lch_t *ch;
+	struct smux_pkt_t *ack_pkt;
+	unsigned long flags;
+	int tx_ready = 0;
+	int enable_powerdown = 0;
+
+	if (pkt->hdr.flags & SMUX_CMD_OPEN_ACK)
+		return smux_handle_rx_open_ack(pkt);
+
+	lcid = pkt->hdr.lcid;
+	ch = &smux_lch[lcid];
+
+	spin_lock_irqsave(&ch->state_lock_lhb1, flags);
+
+	if (ch->remote_state == SMUX_LCH_REMOTE_CLOSED) {
+		SMUX_DBG("lcid %d remote state 0x%x -> 0x%x\n", lcid,
+				SMUX_LCH_REMOTE_CLOSED,
+				SMUX_LCH_REMOTE_OPENED);
+
+		ch->remote_state = SMUX_LCH_REMOTE_OPENED;
+		if (pkt->hdr.flags & SMUX_CMD_OPEN_POWER_COLLAPSE)
+			enable_powerdown = 1;
+
+		/* Send Open ACK */
+		ack_pkt = smux_alloc_pkt();
+		if (!ack_pkt) {
+			/* exit out to allow retrying this later */
+			ret = -ENOMEM;
+			goto out;
+		}
+		ack_pkt->hdr.cmd = SMUX_CMD_OPEN_LCH;
+		ack_pkt->hdr.flags = SMUX_CMD_OPEN_ACK
+			| SMUX_CMD_OPEN_POWER_COLLAPSE;
+		ack_pkt->hdr.lcid = lcid;
+		ack_pkt->hdr.payload_len = 0;
+		ack_pkt->hdr.pad_len = 0;
+		if (pkt->hdr.flags & SMUX_CMD_OPEN_REMOTE_LOOPBACK) {
+			ch->remote_mode = SMUX_LCH_MODE_REMOTE_LOOPBACK;
+			ack_pkt->hdr.flags |= SMUX_CMD_OPEN_REMOTE_LOOPBACK;
+		}
+		smux_tx_queue(ack_pkt, ch, 0);
+		tx_ready = 1;
+
+		if (ch->remote_mode == SMUX_LCH_MODE_REMOTE_LOOPBACK) {
+			/*
+			 * Send an Open command to the remote side to
+			 * simulate our local client doing it.
+			 */
+			ack_pkt = smux_alloc_pkt();
+			if (ack_pkt) {
+				ack_pkt->hdr.lcid = lcid;
+				ack_pkt->hdr.cmd = SMUX_CMD_OPEN_LCH;
+				ack_pkt->hdr.flags =
+					SMUX_CMD_OPEN_POWER_COLLAPSE;
+				ack_pkt->hdr.payload_len = 0;
+				ack_pkt->hdr.pad_len = 0;
+				smux_tx_queue(ack_pkt, ch, 0);
+				tx_ready = 1;
+			} else {
+				pr_err("%s: Remote loopack allocation failure\n",
+						__func__);
+			}
+		} else if (ch->local_state == SMUX_LCH_LOCAL_OPENED) {
+			schedule_notify(lcid, SMUX_CONNECTED, NULL);
+		}
+		ret = 0;
+	} else {
+		pr_err("%s: lcid %d remote state 0x%x open invalid\n",
+			   __func__, lcid, ch->remote_state);
+		ret = -EINVAL;
+	}
+
+out:
+	spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
+
+	if (enable_powerdown) {
+		spin_lock_irqsave(&smux.tx_lock_lha2, flags);
+		if (!smux.powerdown_enabled) {
+			smux.powerdown_enabled = 1;
+			SMUX_DBG("%s: enabling power-collapse support\n",
+					__func__);
+		}
+		spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
+	}
+
+	if (tx_ready)
+		list_channel(ch);
+
+	return ret;
+}
+
+/**
+ * Handle receive CLOSE command.
+ *
+ * @pkt  Received packet
+ *
+ * @returns 0 for success
+ */
+static int smux_handle_rx_close_cmd(struct smux_pkt_t *pkt)
+{
+	uint8_t lcid;
+	int ret;
+	struct smux_lch_t *ch;
+	struct smux_pkt_t *ack_pkt;
+	union notifier_metadata meta_disconnected;
+	unsigned long flags;
+	int tx_ready = 0;
+
+	if (pkt->hdr.flags & SMUX_CMD_CLOSE_ACK)
+		return smux_handle_close_ack(pkt);
+
+	lcid = pkt->hdr.lcid;
+	ch = &smux_lch[lcid];
+	meta_disconnected.disconnected.is_ssr = 0;
+
+	spin_lock_irqsave(&ch->state_lock_lhb1, flags);
+	if (ch->remote_state == SMUX_LCH_REMOTE_OPENED) {
+		SMUX_DBG("lcid %d remote state 0x%x -> 0x%x\n", lcid,
+				SMUX_LCH_REMOTE_OPENED,
+				SMUX_LCH_REMOTE_CLOSED);
+
+		ack_pkt = smux_alloc_pkt();
+		if (!ack_pkt) {
+			/* exit out to allow retrying this later */
+			ret = -ENOMEM;
+			goto out;
+		}
+		ch->remote_state = SMUX_LCH_REMOTE_CLOSED;
+		ack_pkt->hdr.cmd = SMUX_CMD_CLOSE_LCH;
+		ack_pkt->hdr.flags = SMUX_CMD_CLOSE_ACK;
+		ack_pkt->hdr.lcid = lcid;
+		ack_pkt->hdr.payload_len = 0;
+		ack_pkt->hdr.pad_len = 0;
+		smux_tx_queue(ack_pkt, ch, 0);
+		tx_ready = 1;
+
+		if (ch->remote_mode == SMUX_LCH_MODE_REMOTE_LOOPBACK) {
+			/*
+			 * Send a Close command to the remote side to simulate
+			 * our local client doing it.
+			 */
+			ack_pkt = smux_alloc_pkt();
+			if (ack_pkt) {
+				ack_pkt->hdr.lcid = lcid;
+				ack_pkt->hdr.cmd = SMUX_CMD_CLOSE_LCH;
+				ack_pkt->hdr.flags = 0;
+				ack_pkt->hdr.payload_len = 0;
+				ack_pkt->hdr.pad_len = 0;
+				smux_tx_queue(ack_pkt, ch, 0);
+				tx_ready = 1;
+			} else {
+				pr_err("%s: Remote loopack allocation failure\n",
+						__func__);
+			}
+		}
+
+		if (ch->local_state == SMUX_LCH_LOCAL_CLOSED)
+			schedule_notify(lcid, SMUX_DISCONNECTED,
+				&meta_disconnected);
+		ret = 0;
+	} else {
+		pr_err("%s: lcid %d remote state 0x%x close invalid\n",
+				__func__, lcid, ch->remote_state);
+		ret = -EINVAL;
+	}
+out:
+	spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
+	if (tx_ready)
+		list_channel(ch);
+
+	return ret;
+}
+
+/*
+ * Handle receive DATA command.
+ *
+ * @pkt  Received packet
+ *
+ * @returns 0 for success
+ */
+static int smux_handle_rx_data_cmd(struct smux_pkt_t *pkt)
+{
+	uint8_t lcid;
+	int ret = 0;
+	int do_retry = 0;
+	int tmp;
+	int rx_len;
+	struct smux_lch_t *ch;
+	union notifier_metadata metadata;
+	int remote_loopback;
+	struct smux_pkt_t *ack_pkt;
+	unsigned long flags;
+
+	if (!pkt || smux_assert_lch_id(pkt->hdr.lcid)) {
+		ret = -ENXIO;
+		goto out;
+	}
+
+	rx_len = pkt->hdr.payload_len;
+	if (rx_len == 0) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	lcid = pkt->hdr.lcid;
+	ch = &smux_lch[lcid];
+	spin_lock_irqsave(&ch->state_lock_lhb1, flags);
+	remote_loopback = ch->remote_mode == SMUX_LCH_MODE_REMOTE_LOOPBACK;
+
+	if (ch->local_state != SMUX_LCH_LOCAL_OPENED
+		&& !remote_loopback) {
+		pr_err("smux: ch %d error data on local state 0x%x",
+					lcid, ch->local_state);
+		ret = -EIO;
+		spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
+		goto out;
+	}
+
+	if (ch->remote_state != SMUX_LCH_REMOTE_OPENED) {
+		pr_err("smux: ch %d error data on remote state 0x%x",
+					lcid, ch->remote_state);
+		ret = -EIO;
+		spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
+		goto out;
+	}
+
+	if (!list_empty(&ch->rx_retry_queue)) {
+		do_retry = 1;
+		if ((ch->rx_retry_queue_cnt + 1) > SMUX_RX_RETRY_MAX_PKTS) {
+			/* retry queue full */
+			schedule_notify(lcid, SMUX_READ_FAIL, NULL);
+			ret = -ENOMEM;
+			spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
+			goto out;
+		}
+	}
+	spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
+
+	if (remote_loopback) {
+		/* Echo the data back to the remote client. */
+		ack_pkt = smux_alloc_pkt();
+		if (ack_pkt) {
+			ack_pkt->hdr.lcid = lcid;
+			ack_pkt->hdr.cmd = SMUX_CMD_DATA;
+			ack_pkt->hdr.flags = 0;
+			ack_pkt->hdr.payload_len = pkt->hdr.payload_len;
+			if (ack_pkt->hdr.payload_len) {
+				smux_alloc_pkt_payload(ack_pkt);
+				memcpy(ack_pkt->payload, pkt->payload,
+						ack_pkt->hdr.payload_len);
+			}
+			ack_pkt->hdr.pad_len = pkt->hdr.pad_len;
+			smux_tx_queue(ack_pkt, ch, 0);
+			list_channel(ch);
+		} else {
+			pr_err("%s: Remote loopack allocation failure\n",
+					__func__);
+		}
+	} else if (!do_retry) {
+		/* request buffer from client */
+		metadata.read.pkt_priv = 0;
+		metadata.read.buffer = 0;
+		tmp = ch->get_rx_buffer(ch->priv,
+				(void **)&metadata.read.pkt_priv,
+				(void **)&metadata.read.buffer,
+				rx_len);
+
+		if (tmp == 0 && metadata.read.buffer) {
+			/* place data into RX buffer */
+			memcpy(metadata.read.buffer, pkt->payload,
+					rx_len);
+			metadata.read.len = rx_len;
+			schedule_notify(lcid, SMUX_READ_DONE,
+							&metadata);
+		} else if (tmp == -EAGAIN ||
+				(tmp == 0 && !metadata.read.buffer)) {
+			/* buffer allocation failed - add to retry queue */
+			do_retry = 1;
+		} else if (tmp < 0) {
+			schedule_notify(lcid, SMUX_READ_FAIL, NULL);
+			ret = -ENOMEM;
+		}
+	}
+
+	if (do_retry) {
+		struct smux_rx_pkt_retry *retry;
+
+		retry = kmalloc(sizeof(struct smux_rx_pkt_retry), GFP_KERNEL);
+		if (!retry) {
+			pr_err("%s: retry alloc failure\n", __func__);
+			ret = -ENOMEM;
+			schedule_notify(lcid, SMUX_READ_FAIL, NULL);
+			goto out;
+		}
+		INIT_LIST_HEAD(&retry->rx_retry_list);
+		retry->timeout_in_ms = SMUX_RX_RETRY_MIN_MS;
+
+		/* copy packet */
+		retry->pkt = smux_alloc_pkt();
+		if (!retry->pkt) {
+			kfree(retry);
+			pr_err("%s: pkt alloc failure\n", __func__);
+			ret = -ENOMEM;
+			schedule_notify(lcid, SMUX_READ_FAIL, NULL);
+			goto out;
+		}
+		retry->pkt->hdr.lcid = lcid;
+		retry->pkt->hdr.payload_len = pkt->hdr.payload_len;
+		retry->pkt->hdr.pad_len = pkt->hdr.pad_len;
+		if (retry->pkt->hdr.payload_len) {
+			smux_alloc_pkt_payload(retry->pkt);
+			memcpy(retry->pkt->payload, pkt->payload,
+					retry->pkt->hdr.payload_len);
+		}
+
+		/* add to retry queue */
+		spin_lock_irqsave(&ch->state_lock_lhb1, flags);
+		list_add_tail(&retry->rx_retry_list, &ch->rx_retry_queue);
+		++ch->rx_retry_queue_cnt;
+		if (ch->rx_retry_queue_cnt == 1)
+			queue_delayed_work(smux_rx_wq, &ch->rx_retry_work,
+				msecs_to_jiffies(retry->timeout_in_ms));
+		spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
+	}
+
+out:
+	return ret;
+}
+
+/**
+ * Handle receive byte command for testing purposes.
+ *
+ * @pkt  Received packet
+ *
+ * @returns 0 for success
+ */
+static int smux_handle_rx_byte_cmd(struct smux_pkt_t *pkt)
+{
+	uint8_t lcid;
+	int ret;
+	struct smux_lch_t *ch;
+	union notifier_metadata metadata;
+	unsigned long flags;
+
+	if (!pkt || smux_assert_lch_id(pkt->hdr.lcid))
+		return -ENXIO;
+
+	lcid = pkt->hdr.lcid;
+	ch = &smux_lch[lcid];
+	spin_lock_irqsave(&ch->state_lock_lhb1, flags);
+
+	if (ch->local_state != SMUX_LCH_LOCAL_OPENED) {
+		pr_err("smux: ch %d error data on local state 0x%x",
+					lcid, ch->local_state);
+		ret = -EIO;
+		goto out;
+	}
+
+	if (ch->remote_state != SMUX_LCH_REMOTE_OPENED) {
+		pr_err("smux: ch %d error data on remote state 0x%x",
+					lcid, ch->remote_state);
+		ret = -EIO;
+		goto out;
+	}
+
+	metadata.read.pkt_priv = (void *)(int)pkt->hdr.flags;
+	metadata.read.buffer = 0;
+	schedule_notify(lcid, SMUX_READ_DONE, &metadata);
+	ret = 0;
+
+out:
+	spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
+	return ret;
+}
+
+/**
+ * Handle receive status command.
+ *
+ * @pkt  Received packet
+ *
+ * @returns 0 for success
+ */
+static int smux_handle_rx_status_cmd(struct smux_pkt_t *pkt)
+{
+	uint8_t lcid;
+	int ret;
+	struct smux_lch_t *ch;
+	union notifier_metadata meta;
+	unsigned long flags;
+	int tx_ready = 0;
+
+	lcid = pkt->hdr.lcid;
+	ch = &smux_lch[lcid];
+
+	spin_lock_irqsave(&ch->state_lock_lhb1, flags);
+	meta.tiocm.tiocm_old = ch->remote_tiocm;
+	meta.tiocm.tiocm_new = pkt->hdr.flags;
+
+	/* update logical channel flow control */
+	if ((meta.tiocm.tiocm_old & SMUX_CMD_STATUS_FLOW_CNTL) ^
+		(meta.tiocm.tiocm_new & SMUX_CMD_STATUS_FLOW_CNTL)) {
+		/* logical channel flow control changed */
+		if (pkt->hdr.flags & SMUX_CMD_STATUS_FLOW_CNTL) {
+			/* disabled TX */
+			SMUX_DBG("TX Flow control enabled\n");
+			ch->tx_flow_control = 1;
+		} else {
+			/* re-enable channel */
+			SMUX_DBG("TX Flow control disabled\n");
+			ch->tx_flow_control = 0;
+			tx_ready = 1;
+		}
+	}
+	meta.tiocm.tiocm_old = msm_smux_tiocm_get_atomic(ch);
+	ch->remote_tiocm = pkt->hdr.flags;
+	meta.tiocm.tiocm_new = msm_smux_tiocm_get_atomic(ch);
+
+	/* client notification for status change */
+	if (IS_FULLY_OPENED(ch)) {
+		if (meta.tiocm.tiocm_old != meta.tiocm.tiocm_new)
+			schedule_notify(lcid, SMUX_TIOCM_UPDATE, &meta);
+		ret = 0;
+	}
+	spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
+	if (tx_ready)
+		list_channel(ch);
+
+	return ret;
+}
+
+/**
+ * Handle receive power command.
+ *
+ * @pkt  Received packet
+ *
+ * @returns 0 for success
+ */
+static int smux_handle_rx_power_cmd(struct smux_pkt_t *pkt)
+{
+	int tx_ready = 0;
+	struct smux_pkt_t *ack_pkt;
+	unsigned long flags;
+
+	spin_lock_irqsave(&smux.tx_lock_lha2, flags);
+	if (pkt->hdr.flags & SMUX_CMD_PWR_CTL_ACK) {
+		/* local sleep request ack */
+		if (smux.power_state == SMUX_PWR_TURNING_OFF) {
+			/* Power-down complete, turn off UART */
+			SMUX_DBG("%s: Power %d->%d\n", __func__,
+					smux.power_state, SMUX_PWR_OFF_FLUSH);
+			smux.power_state = SMUX_PWR_OFF_FLUSH;
+			queue_work(smux_tx_wq, &smux_inactivity_work);
+		} else {
+			pr_err("%s: sleep request ack invalid in state %d\n",
+					__func__, smux.power_state);
+		}
+	} else {
+		/* remote sleep request */
+		if (smux.power_state == SMUX_PWR_ON
+			|| smux.power_state == SMUX_PWR_TURNING_OFF) {
+			ack_pkt = smux_alloc_pkt();
+			if (ack_pkt) {
+				SMUX_DBG("%s: Power %d->%d\n", __func__,
+						smux.power_state,
+						SMUX_PWR_TURNING_OFF_FLUSH);
+
+				/* send power-down request */
+				ack_pkt->hdr.cmd = SMUX_CMD_PWR_CTL;
+				ack_pkt->hdr.flags = SMUX_CMD_PWR_CTL_ACK;
+				ack_pkt->hdr.lcid = pkt->hdr.lcid;
+				smux_tx_queue(ack_pkt,
+					      &smux_lch[ack_pkt->hdr.lcid], 0);
+				tx_ready = 1;
+				smux.power_state = SMUX_PWR_TURNING_OFF_FLUSH;
+				queue_delayed_work(smux_tx_wq,
+					&smux_delayed_inactivity_work,
+					msecs_to_jiffies(
+						SMUX_INACTIVITY_TIMEOUT_MS));
+			}
+		} else {
+			pr_err("%s: sleep request invalid in state %d\n",
+					__func__, smux.power_state);
+		}
+	}
+	spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
+
+	if (tx_ready)
+		list_channel(&smux_lch[ack_pkt->hdr.lcid]);
+
+	return 0;
+}
+
+/**
+ * Handle dispatching a completed packet for receive processing.
+ *
+ * @pkt Packet to process
+ *
+ * @returns 0 for success
+ */
+static int smux_dispatch_rx_pkt(struct smux_pkt_t *pkt)
+{
+	int ret;
+
+	SMUX_LOG_PKT_RX(pkt);
+
+	switch (pkt->hdr.cmd) {
+	case SMUX_CMD_OPEN_LCH:
+		ret = smux_handle_rx_open_cmd(pkt);
+		break;
+
+	case SMUX_CMD_DATA:
+		ret = smux_handle_rx_data_cmd(pkt);
+		break;
+
+	case SMUX_CMD_CLOSE_LCH:
+		ret = smux_handle_rx_close_cmd(pkt);
+		break;
+
+	case SMUX_CMD_STATUS:
+		ret = smux_handle_rx_status_cmd(pkt);
+		break;
+
+	case SMUX_CMD_PWR_CTL:
+		ret = smux_handle_rx_power_cmd(pkt);
+		break;
+
+	case SMUX_CMD_BYTE:
+		ret = smux_handle_rx_byte_cmd(pkt);
+		break;
+
+	default:
+		pr_err("%s: command %d unknown\n", __func__, pkt->hdr.cmd);
+		ret = -EINVAL;
+	}
+	return ret;
+}
+
+/**
+ * Deserializes a packet and dispatches it to the packet receive logic.
+ *
+ * @data    Raw data for one packet
+ * @len     Length of the data
+ *
+ * @returns 0 for success
+ */
+static int smux_deserialize(unsigned char *data, int len)
+{
+	struct smux_pkt_t recv;
+	uint8_t lcid;
+
+	smux_init_pkt(&recv);
+
+	/*
+	 * It may be possible to optimize this to not use the
+	 * temporary buffer.
+	 */
+	memcpy(&recv.hdr, data, sizeof(struct smux_hdr_t));
+
+	if (recv.hdr.magic != SMUX_MAGIC) {
+		pr_err("%s: invalid header magic\n", __func__);
+		return -EINVAL;
+	}
+
+	lcid = recv.hdr.lcid;
+	if (smux_assert_lch_id(lcid)) {
+		pr_err("%s: invalid channel id %d\n", __func__, lcid);
+		return -ENXIO;
+	}
+
+	if (recv.hdr.payload_len)
+		recv.payload = data + sizeof(struct smux_hdr_t);
+
+	return smux_dispatch_rx_pkt(&recv);
+}
+
+/**
+ * Handle wakeup request byte.
+ */
+static void smux_handle_wakeup_req(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&smux.tx_lock_lha2, flags);
+	if (smux.power_state == SMUX_PWR_OFF
+		|| smux.power_state == SMUX_PWR_TURNING_ON) {
+		/* wakeup system */
+		SMUX_DBG("%s: Power %d->%d\n", __func__,
+				smux.power_state, SMUX_PWR_ON);
+		smux.power_state = SMUX_PWR_ON;
+		queue_work(smux_tx_wq, &smux_wakeup_work);
+		queue_work(smux_tx_wq, &smux_tx_work);
+		queue_delayed_work(smux_tx_wq, &smux_delayed_inactivity_work,
+			msecs_to_jiffies(SMUX_INACTIVITY_TIMEOUT_MS));
+		smux_send_byte(SMUX_WAKEUP_ACK);
+	} else {
+		smux_send_byte(SMUX_WAKEUP_ACK);
+	}
+	spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
+}
+
+/**
+ * Handle wakeup request ack.
+ */
+static void smux_handle_wakeup_ack(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&smux.tx_lock_lha2, flags);
+	if (smux.power_state == SMUX_PWR_TURNING_ON) {
+		/* received response to wakeup request */
+		SMUX_DBG("%s: Power %d->%d\n", __func__,
+				smux.power_state, SMUX_PWR_ON);
+		smux.power_state = SMUX_PWR_ON;
+		queue_work(smux_tx_wq, &smux_tx_work);
+		queue_delayed_work(smux_tx_wq, &smux_delayed_inactivity_work,
+			msecs_to_jiffies(SMUX_INACTIVITY_TIMEOUT_MS));
+
+	} else if (smux.power_state != SMUX_PWR_ON) {
+		/* invalid message */
+		pr_err("%s: wakeup request ack invalid in state %d\n",
+				__func__, smux.power_state);
+	}
+	spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
+}
+
+/**
+ * RX State machine - IDLE state processing.
+ *
+ * @data  New RX data to process
+ * @len   Length of the data
+ * @used  Return value of length processed
+ * @flag  Error flag - TTY_NORMAL 0 for no failure
+ */
+static void smux_rx_handle_idle(const unsigned char *data,
+		int len, int *used, int flag)
+{
+	int i;
+
+	if (flag) {
+		if (smux_byte_loopback)
+			smux_receive_byte(SMUX_UT_ECHO_ACK_FAIL,
+					smux_byte_loopback);
+		pr_err("%s: TTY error 0x%x - ignoring\n", __func__, flag);
+		++*used;
+		return;
+	}
+
+	for (i = *used; i < len && smux.rx_state == SMUX_RX_IDLE; i++) {
+		switch (data[i]) {
+		case SMUX_MAGIC_WORD1:
+			smux.rx_state = SMUX_RX_MAGIC;
+			break;
+		case SMUX_WAKEUP_REQ:
+			smux_handle_wakeup_req();
+			break;
+		case SMUX_WAKEUP_ACK:
+			smux_handle_wakeup_ack();
+			break;
+		default:
+			/* unexpected character */
+			if (smux_byte_loopback && data[i] == SMUX_UT_ECHO_REQ)
+				smux_receive_byte(SMUX_UT_ECHO_ACK_OK,
+						smux_byte_loopback);
+			pr_err("%s: parse error 0x%02x - ignoring\n", __func__,
+					(unsigned)data[i]);
+			break;
+		}
+	}
+
+	*used = i;
+}
+
+/**
+ * RX State machine - Header Magic state processing.
+ *
+ * @data  New RX data to process
+ * @len   Length of the data
+ * @used  Return value of length processed
+ * @flag  Error flag - TTY_NORMAL 0 for no failure
+ */
+static void smux_rx_handle_magic(const unsigned char *data,
+		int len, int *used, int flag)
+{
+	int i;
+
+	if (flag) {
+		pr_err("%s: TTY RX error %d\n", __func__, flag);
+		smux_enter_reset();
+		smux.rx_state = SMUX_RX_FAILURE;
+		++*used;
+		return;
+	}
+
+	for (i = *used; i < len && smux.rx_state == SMUX_RX_MAGIC; i++) {
+		/* wait for completion of the magic */
+		if (data[i] == SMUX_MAGIC_WORD2) {
+			smux.recv_len = 0;
+			smux.recv_buf[smux.recv_len++] = SMUX_MAGIC_WORD1;
+			smux.recv_buf[smux.recv_len++] = SMUX_MAGIC_WORD2;
+			smux.rx_state = SMUX_RX_HDR;
+		} else {
+			/* unexpected / trash character */
+			pr_err("%s: rx parse error for char %c; *used=%d, len=%d\n",
+					__func__, data[i], *used, len);
+			smux.rx_state = SMUX_RX_IDLE;
+		}
+	}
+
+	*used = i;
+}
+
+/**
+ * RX State machine - Packet Header state processing.
+ *
+ * @data  New RX data to process
+ * @len   Length of the data
+ * @used  Return value of length processed
+ * @flag  Error flag - TTY_NORMAL 0 for no failure
+ */
+static void smux_rx_handle_hdr(const unsigned char *data,
+		int len, int *used, int flag)
+{
+	int i;
+	struct smux_hdr_t *hdr;
+
+	if (flag) {
+		pr_err("%s: TTY RX error %d\n", __func__, flag);
+		smux_enter_reset();
+		smux.rx_state = SMUX_RX_FAILURE;
+		++*used;
+		return;
+	}
+
+	for (i = *used; i < len && smux.rx_state == SMUX_RX_HDR; i++) {
+		smux.recv_buf[smux.recv_len++] = data[i];
+
+		if (smux.recv_len == sizeof(struct smux_hdr_t)) {
+			/* complete header received */
+			hdr = (struct smux_hdr_t *)smux.recv_buf;
+			smux.pkt_remain = hdr->payload_len + hdr->pad_len;
+			smux.rx_state = SMUX_RX_PAYLOAD;
+		}
+	}
+	*used = i;
+}
+
+/**
+ * RX State machine - Packet Payload state processing.
+ *
+ * @data  New RX data to process
+ * @len   Length of the data
+ * @used  Return value of length processed
+ * @flag  Error flag - TTY_NORMAL 0 for no failure
+ */
+static void smux_rx_handle_pkt_payload(const unsigned char *data,
+		int len, int *used, int flag)
+{
+	int remaining;
+
+	if (flag) {
+		pr_err("%s: TTY RX error %d\n", __func__, flag);
+		smux_enter_reset();
+		smux.rx_state = SMUX_RX_FAILURE;
+		++*used;
+		return;
+	}
+
+	/* copy data into rx buffer */
+	if (smux.pkt_remain < (len - *used))
+		remaining = smux.pkt_remain;
+	else
+		remaining = len - *used;
+
+	memcpy(&smux.recv_buf[smux.recv_len], &data[*used], remaining);
+	smux.recv_len += remaining;
+	smux.pkt_remain -= remaining;
+	*used += remaining;
+
+	if (smux.pkt_remain == 0) {
+		/* complete packet received */
+		smux_deserialize(smux.recv_buf, smux.recv_len);
+		smux.rx_state = SMUX_RX_IDLE;
+	}
+}
+
+/**
+ * Feed data to the receive state machine.
+ *
+ * @data Pointer to data block
+ * @len  Length of data
+ * @flag TTY_NORMAL (0) for no error, otherwise TTY Error Flag
+ */
+void smux_rx_state_machine(const unsigned char *data,
+						int len, int flag)
+{
+	struct smux_rx_worker_data work;
+
+	work.data = data;
+	work.len = len;
+	work.flag = flag;
+	INIT_WORK_ONSTACK(&work.work, smux_rx_worker);
+	work.work_complete = COMPLETION_INITIALIZER_ONSTACK(work.work_complete);
+
+	queue_work(smux_rx_wq, &work.work);
+	wait_for_completion(&work.work_complete);
+}
+
+/**
+ * Add channel to transmit-ready list and trigger transmit worker.
+ *
+ * @ch Channel to add
+ */
+static void list_channel(struct smux_lch_t *ch)
+{
+	unsigned long flags;
+
+	SMUX_DBG("%s: listing channel %d\n",
+			__func__, ch->lcid);
+
+	spin_lock_irqsave(&smux.tx_lock_lha2, flags);
+	spin_lock(&ch->tx_lock_lhb2);
+	smux.tx_activity_flag = 1;
+	if (list_empty(&ch->tx_ready_list))
+		list_add_tail(&ch->tx_ready_list, &smux.lch_tx_ready_list);
+	spin_unlock(&ch->tx_lock_lhb2);
+	spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
+
+	queue_work(smux_tx_wq, &smux_tx_work);
+}
+
+/**
+ * Transmit packet on correct transport and then perform client
+ * notification.
+ *
+ * @ch   Channel to transmit on
+ * @pkt  Packet to transmit
+ */
+static void smux_tx_pkt(struct smux_lch_t *ch, struct smux_pkt_t *pkt)
+{
+	union notifier_metadata meta_write;
+	int ret;
+
+	if (ch && pkt) {
+		SMUX_LOG_PKT_TX(pkt);
+		if (ch->local_mode == SMUX_LCH_MODE_LOCAL_LOOPBACK)
+			ret = smux_tx_loopback(pkt);
+		else
+			ret = smux_tx_tty(pkt);
+
+		if (pkt->hdr.cmd == SMUX_CMD_DATA) {
+			/* notify write-done */
+			meta_write.write.pkt_priv = pkt->priv;
+			meta_write.write.buffer = pkt->payload;
+			meta_write.write.len = pkt->hdr.payload_len;
+			if (ret >= 0) {
+				SMUX_DBG("%s: PKT write done", __func__);
+				schedule_notify(ch->lcid, SMUX_WRITE_DONE,
+						&meta_write);
+			} else {
+				pr_err("%s: failed to write pkt %d\n",
+						__func__, ret);
+				schedule_notify(ch->lcid, SMUX_WRITE_FAIL,
+						&meta_write);
+			}
+		}
+	}
+}
+
+/**
+ * Power-up the UART.
+ */
+static void smux_uart_power_on(void)
+{
+	struct uart_state *state;
+
+	if (!smux.tty || !smux.tty->driver_data) {
+		pr_err("%s: unable to find UART port for tty %p\n",
+				__func__, smux.tty);
+		return;
+	}
+	state = smux.tty->driver_data;
+	msm_hs_request_clock_on(state->uart_port);
+}
+
+/**
+ * Power down the UART.
+ */
+static void smux_uart_power_off(void)
+{
+	struct uart_state *state;
+
+	if (!smux.tty || !smux.tty->driver_data) {
+		pr_err("%s: unable to find UART port for tty %p\n",
+				__func__, smux.tty);
+		return;
+	}
+	state = smux.tty->driver_data;
+	msm_hs_request_clock_off(state->uart_port);
+}
+
+/**
+ * TX Wakeup Worker
+ *
+ * @work Not used
+ *
+ * Do an exponential back-off wakeup sequence with a maximum period
+ * of approximately 1 second (1 << 20 microseconds).
+ */
+static void smux_wakeup_worker(struct work_struct *work)
+{
+	unsigned long flags;
+	unsigned wakeup_delay;
+	int complete = 0;
+
+	for (;;) {
+		spin_lock_irqsave(&smux.tx_lock_lha2, flags);
+		if (smux.power_state == SMUX_PWR_ON) {
+			/* wakeup complete */
+			complete = 1;
+			spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
+			break;
+		} else {
+			/* retry */
+			wakeup_delay = smux.pwr_wakeup_delay_us;
+			smux.pwr_wakeup_delay_us <<= 1;
+			if (smux.pwr_wakeup_delay_us > SMUX_WAKEUP_DELAY_MAX)
+				smux.pwr_wakeup_delay_us =
+					SMUX_WAKEUP_DELAY_MAX;
+		}
+		spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
+		SMUX_DBG("%s: triggering wakeup\n", __func__);
+		smux_send_byte(SMUX_WAKEUP_REQ);
+
+		if (wakeup_delay < SMUX_WAKEUP_DELAY_MIN) {
+			SMUX_DBG("%s: sleeping for %u us\n", __func__,
+					wakeup_delay);
+			usleep_range(wakeup_delay, 2*wakeup_delay);
+		} else {
+			/* schedule delayed work */
+			SMUX_DBG("%s: scheduling delayed wakeup in %u ms\n",
+					__func__, wakeup_delay / 1000);
+			queue_delayed_work(smux_tx_wq,
+					&smux_wakeup_delayed_work,
+					msecs_to_jiffies(wakeup_delay / 1000));
+			break;
+		}
+	}
+
+	if (complete) {
+		SMUX_DBG("%s: wakeup complete\n", __func__);
+		/*
+		 * Cancel any pending retry.  This avoids a race condition with
+		 * a new power-up request because:
+		 * 1) this worker doesn't modify the state
+		 * 2) this worker is processed on the same single-threaded
+		 *    workqueue as new TX wakeup requests
+		 */
+		cancel_delayed_work(&smux_wakeup_delayed_work);
+	}
+}
+
+
+/**
+ * Inactivity timeout worker.  Periodically scheduled when link is active.
+ * When it detects inactivity, it will power-down the UART link.
+ *
+ * @work  Work structure (not used)
+ */
+static void smux_inactivity_worker(struct work_struct *work)
+{
+	int tx_ready = 0;
+	struct smux_pkt_t *pkt;
+	unsigned long flags;
+
+	spin_lock_irqsave(&smux.rx_lock_lha1, flags);
+	spin_lock(&smux.tx_lock_lha2);
+
+	if (!smux.tx_activity_flag && !smux.rx_activity_flag) {
+		/* no activity */
+		if (smux.powerdown_enabled) {
+			if (smux.power_state == SMUX_PWR_ON) {
+				/* start power-down sequence */
+				pkt = smux_alloc_pkt();
+				if (pkt) {
+					SMUX_DBG("%s: Power %d->%d\n", __func__,
+						smux.power_state,
+						SMUX_PWR_TURNING_OFF);
+					smux.power_state = SMUX_PWR_TURNING_OFF;
+
+					/* send power-down request */
+					pkt->hdr.cmd = SMUX_CMD_PWR_CTL;
+					pkt->hdr.flags = 0;
+					pkt->hdr.lcid = 0;
+					smux_tx_queue(pkt,
+						&smux_lch[SMUX_TEST_LCID],
+						0);
+					tx_ready = 1;
+				}
+			}
+		} else {
+			SMUX_DBG("%s: link inactive, but powerdown disabled\n",
+					__func__);
+		}
+	}
+	smux.tx_activity_flag = 0;
+	smux.rx_activity_flag = 0;
+
+	spin_unlock(&smux.tx_lock_lha2);
+	spin_unlock_irqrestore(&smux.rx_lock_lha1, flags);
+
+	if (tx_ready)
+		list_channel(&smux_lch[SMUX_TEST_LCID]);
+
+	if ((smux.power_state == SMUX_PWR_OFF_FLUSH) ||
+	    (smux.power_state == SMUX_PWR_TURNING_OFF_FLUSH)) {
+		/* ready to power-down the UART */
+		SMUX_DBG("%s: Power %d->%d\n", __func__,
+				smux.power_state, SMUX_PWR_OFF);
+		smux_uart_power_off();
+		spin_lock_irqsave(&smux.tx_lock_lha2, flags);
+		smux.power_state = SMUX_PWR_OFF;
+		spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
+	}
+
+	/* reschedule inactivity worker */
+	if (smux.power_state != SMUX_PWR_OFF)
+		queue_delayed_work(smux_tx_wq, &smux_delayed_inactivity_work,
+			msecs_to_jiffies(SMUX_INACTIVITY_TIMEOUT_MS));
+}
+
+/**
+ * Remove RX retry packet from channel and free it.
+ *
+ * Must be called with state_lock_lhb1 locked.
+ *
+ * @ch    Channel for retry packet
+ * @retry Retry packet to remove
+ */
+void smux_remove_rx_retry(struct smux_lch_t *ch,
+		struct smux_rx_pkt_retry *retry)
+{
+	list_del(&retry->rx_retry_list);
+	--ch->rx_retry_queue_cnt;
+	smux_free_pkt(retry->pkt);
+	kfree(retry);
+}
+
+/**
+ * RX worker handles all receive operations.
+ *
+ * @work  Work structure contained in TBD structure
+ */
+static void smux_rx_worker(struct work_struct *work)
+{
+	unsigned long flags;
+	int used;
+	int initial_rx_state;
+	struct smux_rx_worker_data *w;
+	const unsigned char *data;
+	int len;
+	int flag;
+
+	w =  container_of(work, struct smux_rx_worker_data, work);
+	data = w->data;
+	len = w->len;
+	flag = w->flag;
+
+	spin_lock_irqsave(&smux.rx_lock_lha1, flags);
+	smux.rx_activity_flag = 1;
+	spin_unlock_irqrestore(&smux.rx_lock_lha1, flags);
+
+	SMUX_DBG("%s: %p, len=%d, flag=%d\n", __func__, data, len, flag);
+	used = 0;
+	do {
+		SMUX_DBG("%s: state %d; %d of %d\n",
+				__func__, smux.rx_state, used, len);
+		initial_rx_state = smux.rx_state;
+
+		switch (smux.rx_state) {
+		case SMUX_RX_IDLE:
+			smux_rx_handle_idle(data, len, &used, flag);
+			break;
+		case SMUX_RX_MAGIC:
+			smux_rx_handle_magic(data, len, &used, flag);
+			break;
+		case SMUX_RX_HDR:
+			smux_rx_handle_hdr(data, len, &used, flag);
+			break;
+		case SMUX_RX_PAYLOAD:
+			smux_rx_handle_pkt_payload(data, len, &used, flag);
+			break;
+		default:
+			SMUX_DBG("%s: invalid state %d\n",
+					__func__, smux.rx_state);
+			smux.rx_state = SMUX_RX_IDLE;
+			break;
+		}
+	} while (used < len || smux.rx_state != initial_rx_state);
+
+	complete(&w->work_complete);
+}
+
+/**
+ * RX Retry worker handles retrying get_rx_buffer calls that previously failed
+ * because the client was not ready (-EAGAIN).
+ *
+ * @work  Work structure contained in smux_lch_t structure
+ */
+static void smux_rx_retry_worker(struct work_struct *work)
+{
+	struct smux_lch_t *ch;
+	struct smux_rx_pkt_retry *retry;
+	union notifier_metadata metadata;
+	int tmp;
+	unsigned long flags;
+
+	ch = container_of(work, struct smux_lch_t, rx_retry_work.work);
+
+	/* get next retry packet */
+	spin_lock_irqsave(&ch->state_lock_lhb1, flags);
+	if (ch->local_state != SMUX_LCH_LOCAL_OPENED) {
+		/* port has been closed - remove all retries */
+		while (!list_empty(&ch->rx_retry_queue)) {
+			retry = list_first_entry(&ch->rx_retry_queue,
+						struct smux_rx_pkt_retry,
+						rx_retry_list);
+			smux_remove_rx_retry(ch, retry);
+		}
+	}
+
+	if (list_empty(&ch->rx_retry_queue)) {
+		SMUX_DBG("%s: retry list empty for channel %d\n",
+				__func__, ch->lcid);
+		spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
+		return;
+	}
+	retry = list_first_entry(&ch->rx_retry_queue,
+					struct smux_rx_pkt_retry,
+					rx_retry_list);
+	spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
+
+	SMUX_DBG("%s: retrying rx pkt %p\n", __func__, retry);
+	metadata.read.pkt_priv = 0;
+	metadata.read.buffer = 0;
+	tmp = ch->get_rx_buffer(ch->priv,
+			(void **)&metadata.read.pkt_priv,
+			(void **)&metadata.read.buffer,
+			retry->pkt->hdr.payload_len);
+	if (tmp == 0 && metadata.read.buffer) {
+		/* have valid RX buffer */
+		memcpy(metadata.read.buffer, retry->pkt->payload,
+						retry->pkt->hdr.payload_len);
+		metadata.read.len = retry->pkt->hdr.payload_len;
+
+		spin_lock_irqsave(&ch->state_lock_lhb1, flags);
+		smux_remove_rx_retry(ch, retry);
+		spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
+
+		schedule_notify(ch->lcid, SMUX_READ_DONE, &metadata);
+	} else if (tmp == -EAGAIN ||
+			(tmp == 0 && !metadata.read.buffer)) {
+		/* retry again */
+		retry->timeout_in_ms <<= 1;
+		if (retry->timeout_in_ms > SMUX_RX_RETRY_MAX_MS) {
+			/* timed out */
+			spin_lock_irqsave(&ch->state_lock_lhb1, flags);
+			smux_remove_rx_retry(ch, retry);
+			schedule_notify(ch->lcid, SMUX_READ_FAIL, NULL);
+			spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
+		}
+	} else {
+		/* client error - drop packet */
+		spin_lock_irqsave(&ch->state_lock_lhb1, flags);
+		smux_remove_rx_retry(ch, retry);
+		spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
+
+		schedule_notify(ch->lcid, SMUX_READ_FAIL, NULL);
+	}
+
+	/* schedule next retry */
+	spin_lock_irqsave(&ch->state_lock_lhb1, flags);
+	if (!list_empty(&ch->rx_retry_queue)) {
+		retry = list_first_entry(&ch->rx_retry_queue,
+						struct smux_rx_pkt_retry,
+						rx_retry_list);
+		queue_delayed_work(smux_rx_wq, &ch->rx_retry_work,
+				msecs_to_jiffies(retry->timeout_in_ms));
+	}
+	spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
+}
+
+/**
+ * Transmit worker handles serializing and transmitting packets onto the
+ * underlying transport.
+ *
+ * @work  Work structure (not used)
+ */
+static void smux_tx_worker(struct work_struct *work)
+{
+	struct smux_pkt_t *pkt;
+	struct smux_lch_t *ch;
+	unsigned low_wm_notif;
+	unsigned lcid;
+	unsigned long flags;
+
+
+	/*
+	 * Transmit packets in round-robin fashion based upon ready
+	 * channels.
+	 *
+	 * To eliminate the need to hold a lock for the entire
+	 * iteration through the channel ready list, the head of the
+	 * ready-channel list is always the next channel to be
+	 * processed.  To send a packet, the first valid packet in
+	 * the head channel is removed and the head channel is then
+	 * rescheduled at the end of the queue by removing it and
+	 * inserting after the tail.  The locks can then be released
+	 * while the packet is processed.
+	 */
+	for (;;) {
+		pkt = NULL;
+		low_wm_notif = 0;
+
+		/* get the next ready channel */
+		spin_lock_irqsave(&smux.tx_lock_lha2, flags);
+		if (list_empty(&smux.lch_tx_ready_list)) {
+			/* no ready channels */
+			SMUX_DBG("%s: no more ready channels, exiting\n",
+					__func__);
+			spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
+			break;
+		}
+		smux.tx_activity_flag = 1;
+
+		if (smux.power_state != SMUX_PWR_ON
+			&& smux.power_state != SMUX_PWR_TURNING_OFF
+			&& smux.power_state != SMUX_PWR_TURNING_OFF_FLUSH) {
+			/* Link isn't ready to transmit */
+			if (smux.power_state == SMUX_PWR_OFF) {
+				/* link is off, trigger wakeup */
+				smux.pwr_wakeup_delay_us = 1;
+				SMUX_DBG("%s: Power %d->%d\n", __func__,
+						smux.power_state,
+						SMUX_PWR_TURNING_ON);
+				smux.power_state = SMUX_PWR_TURNING_ON;
+				spin_unlock_irqrestore(&smux.tx_lock_lha2,
+						flags);
+				smux_uart_power_on();
+				queue_work(smux_tx_wq, &smux_wakeup_work);
+			} else {
+				SMUX_DBG("%s: can not tx with power state %d\n",
+						__func__,
+						smux.power_state);
+				spin_unlock_irqrestore(&smux.tx_lock_lha2,
+						flags);
+			}
+			break;
+		}
+
+		/* get the next packet to send and rotate channel list */
+		ch = list_first_entry(&smux.lch_tx_ready_list,
+						struct smux_lch_t,
+						tx_ready_list);
+
+		spin_lock(&ch->state_lock_lhb1);
+		spin_lock(&ch->tx_lock_lhb2);
+		if (!list_empty(&ch->tx_queue)) {
+			/*
+			 * If remote TX flow control is enabled or
+			 * the channel is not fully opened, then only
+			 * send command packets.
+			 */
+			if (ch->tx_flow_control || !IS_FULLY_OPENED(ch)) {
+				struct smux_pkt_t *curr;
+				list_for_each_entry(curr, &ch->tx_queue, list) {
+					if (curr->hdr.cmd != SMUX_CMD_DATA) {
+						pkt = curr;
+						break;
+					}
+				}
+			} else {
+				/* get next cmd/data packet to send */
+				pkt = list_first_entry(&ch->tx_queue,
+						struct smux_pkt_t, list);
+			}
+		}
+
+		if (pkt) {
+			list_del(&pkt->list);
+
+			/* update packet stats */
+			if (pkt->hdr.cmd == SMUX_CMD_DATA) {
+				--ch->tx_pending_data_cnt;
+				if (ch->notify_lwm &&
+					ch->tx_pending_data_cnt
+						<= SMUX_WM_LOW) {
+					ch->notify_lwm = 0;
+					low_wm_notif = 1;
+				}
+			}
+
+			/* advance to the next ready channel */
+			list_rotate_left(&smux.lch_tx_ready_list);
+		} else {
+			/* no data in channel to send, remove from ready list */
+			list_del(&ch->tx_ready_list);
+			INIT_LIST_HEAD(&ch->tx_ready_list);
+		}
+		lcid = ch->lcid;
+		spin_unlock(&ch->tx_lock_lhb2);
+		spin_unlock(&ch->state_lock_lhb1);
+		spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
+
+		if (low_wm_notif)
+			schedule_notify(lcid, SMUX_LOW_WM_HIT, NULL);
+
+		/* send the packet */
+		smux_tx_pkt(ch, pkt);
+		smux_free_pkt(pkt);
+	}
+}
+
+
+/**********************************************************************/
+/* Kernel API                                                         */
+/**********************************************************************/
+
+/**
+ * Set or clear channel option using the SMUX_CH_OPTION_* channel
+ * flags.
+ *
+ * @lcid   Logical channel ID
+ * @set    Options to set
+ * @clear  Options to clear
+ *
+ * @returns 0 for success, < 0 for failure
+ */
+int msm_smux_set_ch_option(uint8_t lcid, uint32_t set, uint32_t clear)
+{
+	unsigned long flags;
+	struct smux_lch_t *ch;
+	int tx_ready = 0;
+	int ret = 0;
+
+	if (smux_assert_lch_id(lcid))
+		return -ENXIO;
+
+	ch = &smux_lch[lcid];
+	spin_lock_irqsave(&ch->state_lock_lhb1, flags);
+
+	/* Local loopback mode */
+	if (set & SMUX_CH_OPTION_LOCAL_LOOPBACK)
+		ch->local_mode = SMUX_LCH_MODE_LOCAL_LOOPBACK;
+
+	if (clear & SMUX_CH_OPTION_LOCAL_LOOPBACK)
+		ch->local_mode = SMUX_LCH_MODE_NORMAL;
+
+	/* Remote loopback mode */
+	if (set & SMUX_CH_OPTION_REMOTE_LOOPBACK)
+		ch->local_mode = SMUX_LCH_MODE_REMOTE_LOOPBACK;
+
+	if (clear & SMUX_CH_OPTION_REMOTE_LOOPBACK)
+		ch->local_mode = SMUX_LCH_MODE_NORMAL;
+
+	/* Flow control */
+	if (set & SMUX_CH_OPTION_REMOTE_TX_STOP) {
+		ch->local_tiocm |= SMUX_CMD_STATUS_FLOW_CNTL;
+		ret = smux_send_status_cmd(ch);
+		tx_ready = 1;
+	}
+
+	if (clear & SMUX_CH_OPTION_REMOTE_TX_STOP) {
+		ch->local_tiocm &= ~SMUX_CMD_STATUS_FLOW_CNTL;
+		ret = smux_send_status_cmd(ch);
+		tx_ready = 1;
+	}
+
+	spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
+
+	if (tx_ready)
+		list_channel(ch);
+
+	return ret;
+}
+
+/**
+ * Starts the opening sequence for a logical channel.
+ *
+ * @lcid          Logical channel ID
+ * @priv          Free for client usage
+ * @notify        Event notification function
+ * @get_rx_buffer Function used to provide a receive buffer to SMUX
+ *
+ * @returns 0 for success, <0 otherwise
+ *
+ * A channel must be fully closed (either not previously opened or
+ * msm_smux_close() has been called and the SMUX_DISCONNECTED has been
+ * received.
+ *
+ * One the remote side is opened, the client will receive a SMUX_CONNECTED
+ * event.
+ */
+int msm_smux_open(uint8_t lcid, void *priv,
+	void (*notify)(void *priv, int event_type, const void *metadata),
+	int (*get_rx_buffer)(void *priv, void **pkt_priv, void **buffer,
+								int size))
+{
+	int ret;
+	struct smux_lch_t *ch;
+	struct smux_pkt_t *pkt;
+	int tx_ready = 0;
+	unsigned long flags;
+
+	if (smux_assert_lch_id(lcid))
+		return -ENXIO;
+
+	ch = &smux_lch[lcid];
+	spin_lock_irqsave(&ch->state_lock_lhb1, flags);
+
+	if (ch->local_state == SMUX_LCH_LOCAL_CLOSING) {
+		ret = -EAGAIN;
+		goto out;
+	}
+
+	if (ch->local_state != SMUX_LCH_LOCAL_CLOSED) {
+		pr_err("%s: open lcid %d local state %x invalid\n",
+				__func__, lcid, ch->local_state);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	SMUX_DBG("lcid %d local state 0x%x -> 0x%x\n", lcid,
+			ch->local_state,
+			SMUX_LCH_LOCAL_OPENING);
+
+	ch->local_state = SMUX_LCH_LOCAL_OPENING;
+
+	ch->priv = priv;
+	ch->notify = notify;
+	ch->get_rx_buffer = get_rx_buffer;
+	ret = 0;
+
+	/* Send Open Command */
+	pkt = smux_alloc_pkt();
+	if (!pkt) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	pkt->hdr.magic = SMUX_MAGIC;
+	pkt->hdr.cmd = SMUX_CMD_OPEN_LCH;
+	pkt->hdr.flags = SMUX_CMD_OPEN_POWER_COLLAPSE;
+	if (ch->local_mode == SMUX_LCH_MODE_REMOTE_LOOPBACK)
+		pkt->hdr.flags |= SMUX_CMD_OPEN_REMOTE_LOOPBACK;
+	pkt->hdr.lcid = lcid;
+	pkt->hdr.payload_len = 0;
+	pkt->hdr.pad_len = 0;
+	smux_tx_queue(pkt, ch, 0);
+	tx_ready = 1;
+
+out:
+	spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
+	if (tx_ready)
+		list_channel(ch);
+	return ret;
+}
+
+/**
+ * Starts the closing sequence for a logical channel.
+ *
+ * @lcid    Logical channel ID
+ *
+ * @returns 0 for success, <0 otherwise
+ *
+ * Once the close event has been acknowledge by the remote side, the client
+ * will receive a SMUX_DISCONNECTED notification.
+ */
+int msm_smux_close(uint8_t lcid)
+{
+	int ret = 0;
+	struct smux_lch_t *ch;
+	struct smux_pkt_t *pkt;
+	int tx_ready = 0;
+	unsigned long flags;
+
+	if (smux_assert_lch_id(lcid))
+		return -ENXIO;
+
+	ch = &smux_lch[lcid];
+	spin_lock_irqsave(&ch->state_lock_lhb1, flags);
+	ch->local_tiocm = 0x0;
+	ch->remote_tiocm = 0x0;
+	ch->tx_pending_data_cnt = 0;
+	ch->notify_lwm = 0;
+
+	/* Purge TX queue */
+	spin_lock(&ch->tx_lock_lhb2);
+	while (!list_empty(&ch->tx_queue)) {
+		pkt = list_first_entry(&ch->tx_queue, struct smux_pkt_t,
+							list);
+		list_del(&pkt->list);
+
+		if (pkt->hdr.cmd == SMUX_CMD_OPEN_LCH) {
+			/* Open was never sent, just force to closed state */
+			union notifier_metadata meta_disconnected;
+
+			ch->local_state = SMUX_LCH_LOCAL_CLOSED;
+			meta_disconnected.disconnected.is_ssr = 0;
+			schedule_notify(lcid, SMUX_DISCONNECTED,
+				&meta_disconnected);
+		} else if (pkt->hdr.cmd == SMUX_CMD_DATA) {
+			/* Notify client of failed write */
+			union notifier_metadata meta_write;
+
+			meta_write.write.pkt_priv = pkt->priv;
+			meta_write.write.buffer = pkt->payload;
+			meta_write.write.len = pkt->hdr.payload_len;
+			schedule_notify(ch->lcid, SMUX_WRITE_FAIL, &meta_write);
+		}
+		smux_free_pkt(pkt);
+	}
+	spin_unlock(&ch->tx_lock_lhb2);
+
+	/* Send Close Command */
+	if (ch->local_state == SMUX_LCH_LOCAL_OPENED ||
+		ch->local_state == SMUX_LCH_LOCAL_OPENING) {
+		SMUX_DBG("lcid %d local state 0x%x -> 0x%x\n", lcid,
+				ch->local_state,
+				SMUX_LCH_LOCAL_CLOSING);
+
+		ch->local_state = SMUX_LCH_LOCAL_CLOSING;
+		pkt = smux_alloc_pkt();
+		if (pkt) {
+			pkt->hdr.cmd = SMUX_CMD_CLOSE_LCH;
+			pkt->hdr.flags = 0;
+			pkt->hdr.lcid = lcid;
+			pkt->hdr.payload_len = 0;
+			pkt->hdr.pad_len = 0;
+			smux_tx_queue(pkt, ch, 0);
+			tx_ready = 1;
+		} else {
+			pr_err("%s: pkt allocation failed\n", __func__);
+			ret = -ENOMEM;
+		}
+
+		/* Purge RX retry queue */
+		if (ch->rx_retry_queue_cnt)
+			queue_delayed_work(smux_rx_wq, &ch->rx_retry_work, 0);
+	}
+	spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
+
+	if (tx_ready)
+		list_channel(ch);
+
+	return ret;
+}
+
+/**
+ * Write data to a logical channel.
+ *
+ * @lcid      Logical channel ID
+ * @pkt_priv  Client data that will be returned with the SMUX_WRITE_DONE or
+ *            SMUX_WRITE_FAIL notification.
+ * @data      Data to write
+ * @len       Length of @data
+ *
+ * @returns   0 for success, <0 otherwise
+ *
+ * Data may be written immediately after msm_smux_open() is called,
+ * but the data will wait in the transmit queue until the channel has
+ * been fully opened.
+ *
+ * Once the data has been written, the client will receive either a completion
+ * (SMUX_WRITE_DONE) or a failure notice (SMUX_WRITE_FAIL).
+ */
+int msm_smux_write(uint8_t lcid, void *pkt_priv, const void *data, int len)
+{
+	struct smux_lch_t *ch;
+	struct smux_pkt_t *pkt;
+	int tx_ready = 0;
+	unsigned long flags;
+	int ret;
+
+	if (smux_assert_lch_id(lcid))
+		return -ENXIO;
+
+	ch = &smux_lch[lcid];
+	spin_lock_irqsave(&ch->state_lock_lhb1, flags);
+
+	if (ch->local_state != SMUX_LCH_LOCAL_OPENED &&
+		ch->local_state != SMUX_LCH_LOCAL_OPENING) {
+		pr_err("%s: hdr.invalid local state %d channel %d\n",
+					__func__, ch->local_state, lcid);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (len > SMUX_MAX_PKT_SIZE - sizeof(struct smux_hdr_t)) {
+		pr_err("%s: payload %d too large\n",
+				__func__, len);
+		ret = -E2BIG;
+		goto out;
+	}
+
+	pkt = smux_alloc_pkt();
+	if (!pkt) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	pkt->hdr.cmd = SMUX_CMD_DATA;
+	pkt->hdr.lcid = lcid;
+	pkt->hdr.flags = 0;
+	pkt->hdr.payload_len = len;
+	pkt->payload = (void *)data;
+	pkt->priv = pkt_priv;
+	pkt->hdr.pad_len = 0;
+
+	spin_lock(&ch->tx_lock_lhb2);
+	/* verify high watermark */
+	SMUX_DBG("%s: pending %d", __func__, ch->tx_pending_data_cnt);
+
+	if (ch->tx_pending_data_cnt >= SMUX_WM_HIGH) {
+		pr_err("%s: ch %d high watermark %d exceeded %d\n",
+				__func__, lcid, SMUX_WM_HIGH,
+				ch->tx_pending_data_cnt);
+		ret = -EAGAIN;
+		goto out_inner;
+	}
+
+	/* queue packet for transmit */
+	if (++ch->tx_pending_data_cnt == SMUX_WM_HIGH) {
+		ch->notify_lwm = 1;
+		pr_err("%s: high watermark hit\n", __func__);
+		schedule_notify(lcid, SMUX_HIGH_WM_HIT, NULL);
+	}
+	list_add_tail(&pkt->list, &ch->tx_queue);
+
+	/* add to ready list */
+	if (IS_FULLY_OPENED(ch))
+		tx_ready = 1;
+
+	ret = 0;
+
+out_inner:
+	spin_unlock(&ch->tx_lock_lhb2);
+
+out:
+	if (ret)
+		smux_free_pkt(pkt);
+	spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
+
+	if (tx_ready)
+		list_channel(ch);
+
+	return ret;
+}
+
+/**
+ * Returns true if the TX queue is currently full (high water mark).
+ *
+ * @lcid      Logical channel ID
+ * @returns   0 if channel is not full
+ *            1 if it is full
+ *            < 0 for error
+ */
+int msm_smux_is_ch_full(uint8_t lcid)
+{
+	struct smux_lch_t *ch;
+	unsigned long flags;
+	int is_full = 0;
+
+	if (smux_assert_lch_id(lcid))
+		return -ENXIO;
+
+	ch = &smux_lch[lcid];
+
+	spin_lock_irqsave(&ch->tx_lock_lhb2, flags);
+	if (ch->tx_pending_data_cnt >= SMUX_WM_HIGH)
+		is_full = 1;
+	spin_unlock_irqrestore(&ch->tx_lock_lhb2, flags);
+
+	return is_full;
+}
+
+/**
+ * Returns true if the TX queue has space for more packets it is at or
+ * below the low water mark).
+ *
+ * @lcid      Logical channel ID
+ * @returns   0 if channel is above low watermark
+ *            1 if it's at or below the low watermark
+ *            < 0 for error
+ */
+int msm_smux_is_ch_low(uint8_t lcid)
+{
+	struct smux_lch_t *ch;
+	unsigned long flags;
+	int is_low = 0;
+
+	if (smux_assert_lch_id(lcid))
+		return -ENXIO;
+
+	ch = &smux_lch[lcid];
+
+	spin_lock_irqsave(&ch->tx_lock_lhb2, flags);
+	if (ch->tx_pending_data_cnt <= SMUX_WM_LOW)
+		is_low = 1;
+	spin_unlock_irqrestore(&ch->tx_lock_lhb2, flags);
+
+	return is_low;
+}
+
+/**
+ * Send TIOCM status update.
+ *
+ * @ch  Channel for update
+ *
+ * @returns 0 for success, <0 for failure
+ *
+ * Channel lock must be held before calling.
+ */
+static int smux_send_status_cmd(struct smux_lch_t *ch)
+{
+	struct smux_pkt_t *pkt;
+
+	if (!ch)
+		return -EINVAL;
+
+	pkt = smux_alloc_pkt();
+	if (!pkt)
+		return -ENOMEM;
+
+	pkt->hdr.lcid = ch->lcid;
+	pkt->hdr.cmd = SMUX_CMD_STATUS;
+	pkt->hdr.flags = ch->local_tiocm;
+	pkt->hdr.payload_len = 0;
+	pkt->hdr.pad_len = 0;
+	smux_tx_queue(pkt, ch, 0);
+
+	return 0;
+}
+
+/**
+ * Internal helper function for getting the TIOCM status with
+ * state_lock_lhb1 already locked.
+ *
+ * @ch      Channel pointer
+ *
+ * @returns TIOCM status
+ */
+static long msm_smux_tiocm_get_atomic(struct smux_lch_t *ch)
+{
+	long status = 0x0;
+
+	status |= (ch->remote_tiocm & SMUX_CMD_STATUS_RTC) ? TIOCM_DSR : 0;
+	status |= (ch->remote_tiocm & SMUX_CMD_STATUS_RTR) ? TIOCM_CTS : 0;
+	status |= (ch->remote_tiocm & SMUX_CMD_STATUS_RI) ? TIOCM_RI : 0;
+	status |= (ch->remote_tiocm & SMUX_CMD_STATUS_DCD) ? TIOCM_CD : 0;
+
+	status |= (ch->local_tiocm & SMUX_CMD_STATUS_RTC) ? TIOCM_DTR : 0;
+	status |= (ch->local_tiocm & SMUX_CMD_STATUS_RTR) ? TIOCM_RTS : 0;
+
+	return status;
+}
+
+/**
+ * Get the TIOCM status bits.
+ *
+ * @lcid      Logical channel ID
+ *
+ * @returns   >= 0 TIOCM status bits
+ *            < 0  Error condition
+ */
+long msm_smux_tiocm_get(uint8_t lcid)
+{
+	struct smux_lch_t *ch;
+	unsigned long flags;
+	long status = 0x0;
+
+	if (smux_assert_lch_id(lcid))
+		return -ENXIO;
+
+	ch = &smux_lch[lcid];
+	spin_lock_irqsave(&ch->state_lock_lhb1, flags);
+	status = msm_smux_tiocm_get_atomic(ch);
+	spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
+
+	return status;
+}
+
+/**
+ * Set/clear the TIOCM status bits.
+ *
+ * @lcid      Logical channel ID
+ * @set       Bits to set
+ * @clear     Bits to clear
+ *
+ * @returns   0 for success; < 0 for failure
+ *
+ * If a bit is specified in both the @set and @clear masks, then the clear bit
+ * definition will dominate and the bit will be cleared.
+ */
+int msm_smux_tiocm_set(uint8_t lcid, uint32_t set, uint32_t clear)
+{
+	struct smux_lch_t *ch;
+	unsigned long flags;
+	uint8_t old_status;
+	uint8_t status_set = 0x0;
+	uint8_t status_clear = 0x0;
+	int tx_ready = 0;
+	int ret = 0;
+
+	if (smux_assert_lch_id(lcid))
+		return -ENXIO;
+
+	ch = &smux_lch[lcid];
+	spin_lock_irqsave(&ch->state_lock_lhb1, flags);
+
+	status_set |= (set & TIOCM_DTR) ? SMUX_CMD_STATUS_RTC : 0;
+	status_set |= (set & TIOCM_RTS) ? SMUX_CMD_STATUS_RTR : 0;
+	status_set |= (set & TIOCM_RI) ? SMUX_CMD_STATUS_RI : 0;
+	status_set |= (set & TIOCM_CD) ? SMUX_CMD_STATUS_DCD : 0;
+
+	status_clear |= (clear & TIOCM_DTR) ? SMUX_CMD_STATUS_RTC : 0;
+	status_clear |= (clear & TIOCM_RTS) ? SMUX_CMD_STATUS_RTR : 0;
+	status_clear |= (clear & TIOCM_RI) ? SMUX_CMD_STATUS_RI : 0;
+	status_clear |= (clear & TIOCM_CD) ? SMUX_CMD_STATUS_DCD : 0;
+
+	old_status = ch->local_tiocm;
+	ch->local_tiocm |= status_set;
+	ch->local_tiocm &= ~status_clear;
+
+	if (ch->local_tiocm != old_status) {
+		ret = smux_send_status_cmd(ch);
+		tx_ready = 1;
+	}
+	spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
+
+	if (tx_ready)
+		list_channel(ch);
+
+	return ret;
+}
+
+/**********************************************************************/
+/* Line Discipline Interface                                          */
+/**********************************************************************/
+static int smuxld_open(struct tty_struct *tty)
+{
+	int i;
+	int tmp;
+	unsigned long flags;
+
+	if (!smux.is_initialized)
+		return -ENODEV;
+
+	spin_lock_irqsave(&smux.lock_lha0, flags);
+	if (smux.ld_open_count) {
+		pr_err("%s: %p multiple instances not supported\n",
+			__func__, tty);
+		spin_unlock_irqrestore(&smux.lock_lha0, flags);
+		return -EEXIST;
+	}
+
+	++smux.ld_open_count;
+	if (tty->ops->write == NULL) {
+		spin_unlock_irqrestore(&smux.lock_lha0, flags);
+		return -EINVAL;
+	}
+
+	/* connect to TTY */
+	smux.tty = tty;
+	tty->disc_data = &smux;
+	tty->receive_room = TTY_RECEIVE_ROOM;
+	tty_driver_flush_buffer(tty);
+
+	/* power-down the UART if we are idle */
+	spin_lock(&smux.tx_lock_lha2);
+	if (smux.power_state == SMUX_PWR_OFF) {
+		SMUX_DBG("%s: powering off uart\n", __func__);
+		smux.power_state = SMUX_PWR_OFF_FLUSH;
+		spin_unlock(&smux.tx_lock_lha2);
+		queue_work(smux_tx_wq, &smux_inactivity_work);
+	} else {
+		spin_unlock(&smux.tx_lock_lha2);
+	}
+	spin_unlock_irqrestore(&smux.lock_lha0, flags);
+
+	/* register platform devices */
+	for (i = 0; i < ARRAY_SIZE(smux_devs); ++i) {
+		tmp = platform_device_register(&smux_devs[i]);
+		if (tmp)
+			pr_err("%s: error %d registering device %s\n",
+				   __func__, tmp, smux_devs[i].name);
+	}
+	return 0;
+}
+
+static void smuxld_close(struct tty_struct *tty)
+{
+	unsigned long flags;
+	int i;
+
+	spin_lock_irqsave(&smux.lock_lha0, flags);
+	if (smux.ld_open_count <= 0) {
+		pr_err("%s: invalid ld count %d\n", __func__,
+			smux.ld_open_count);
+		spin_unlock_irqrestore(&smux.lock_lha0, flags);
+		return;
+	}
+	spin_unlock_irqrestore(&smux.lock_lha0, flags);
+
+	for (i = 0; i < ARRAY_SIZE(smux_devs); ++i)
+		platform_device_unregister(&smux_devs[i]);
+
+	--smux.ld_open_count;
+}
+
+/**
+ * Receive data from TTY Line Discipline.
+ *
+ * @tty  TTY structure
+ * @cp   Character data
+ * @fp   Flag data
+ * @count Size of character and flag data
+ */
+void smuxld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
+			   char *fp, int count)
+{
+	int i;
+	int last_idx = 0;
+	const char *tty_name = NULL;
+	char *f;
+
+	if (smux_debug_mask & MSM_SMUX_DEBUG)
+		print_hex_dump(KERN_INFO, "smux tty rx: ", DUMP_PREFIX_OFFSET,
+				     16, 1, cp, count, true);
+
+	/* verify error flags */
+	for (i = 0, f = fp; i < count; ++i, ++f) {
+		if (*f != TTY_NORMAL) {
+			if (tty)
+				tty_name = tty->name;
+			pr_err("%s: TTY %s Error %d (%s)\n", __func__,
+				   tty_name, *f, tty_flag_to_str(*f));
+
+			/* feed all previous valid data to the parser */
+			smux_rx_state_machine(cp + last_idx, i - last_idx,
+					TTY_NORMAL);
+
+			/* feed bad data to parser */
+			smux_rx_state_machine(cp + i, 1, *f);
+			last_idx = i + 1;
+		}
+	}
+
+	/* feed data to RX state machine */
+	smux_rx_state_machine(cp + last_idx, count - last_idx, TTY_NORMAL);
+}
+
+static void smuxld_flush_buffer(struct tty_struct *tty)
+{
+	pr_err("%s: not supported\n", __func__);
+}
+
+static ssize_t	smuxld_chars_in_buffer(struct tty_struct *tty)
+{
+	pr_err("%s: not supported\n", __func__);
+	return -ENODEV;
+}
+
+static ssize_t	smuxld_read(struct tty_struct *tty, struct file *file,
+		unsigned char __user *buf, size_t nr)
+{
+	pr_err("%s: not supported\n", __func__);
+	return -ENODEV;
+}
+
+static ssize_t	smuxld_write(struct tty_struct *tty, struct file *file,
+		 const unsigned char *buf, size_t nr)
+{
+	pr_err("%s: not supported\n", __func__);
+	return -ENODEV;
+}
+
+static int	smuxld_ioctl(struct tty_struct *tty, struct file *file,
+		 unsigned int cmd, unsigned long arg)
+{
+	pr_err("%s: not supported\n", __func__);
+	return -ENODEV;
+}
+
+static unsigned int smuxld_poll(struct tty_struct *tty, struct file *file,
+			 struct poll_table_struct *tbl)
+{
+	pr_err("%s: not supported\n", __func__);
+	return -ENODEV;
+}
+
+static void smuxld_write_wakeup(struct tty_struct *tty)
+{
+	pr_err("%s: not supported\n", __func__);
+}
+
+static struct tty_ldisc_ops smux_ldisc_ops = {
+	.owner           = THIS_MODULE,
+	.magic           = TTY_LDISC_MAGIC,
+	.name            = "n_smux",
+	.open            = smuxld_open,
+	.close           = smuxld_close,
+	.flush_buffer    = smuxld_flush_buffer,
+	.chars_in_buffer = smuxld_chars_in_buffer,
+	.read            = smuxld_read,
+	.write           = smuxld_write,
+	.ioctl           = smuxld_ioctl,
+	.poll            = smuxld_poll,
+	.receive_buf     = smuxld_receive_buf,
+	.write_wakeup    = smuxld_write_wakeup
+};
+
+static int __init smux_init(void)
+{
+	int ret;
+
+	spin_lock_init(&smux.lock_lha0);
+
+	spin_lock_init(&smux.rx_lock_lha1);
+	smux.rx_state = SMUX_RX_IDLE;
+	smux.power_state = SMUX_PWR_OFF;
+	smux.pwr_wakeup_delay_us = 1;
+	smux.powerdown_enabled = 0;
+	smux.rx_activity_flag = 0;
+	smux.tx_activity_flag = 0;
+	smux.recv_len = 0;
+	smux.tty = NULL;
+	smux.ld_open_count = 0;
+	smux.in_reset = 0;
+	smux.is_initialized = 1;
+	smux_byte_loopback = 0;
+
+	spin_lock_init(&smux.tx_lock_lha2);
+	INIT_LIST_HEAD(&smux.lch_tx_ready_list);
+
+	ret	= tty_register_ldisc(N_SMUX, &smux_ldisc_ops);
+	if (ret != 0) {
+		pr_err("%s: error %d registering line discipline\n",
+				__func__, ret);
+		return ret;
+	}
+
+	ret = lch_init();
+	if (ret != 0) {
+		pr_err("%s: lch_init failed\n", __func__);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void __exit smux_exit(void)
+{
+	int ret;
+
+	ret	= tty_unregister_ldisc(N_SMUX);
+	if (ret != 0) {
+		pr_err("%s error %d unregistering line discipline\n",
+				__func__, ret);
+		return;
+	}
+}
+
+module_init(smux_init);
+module_exit(smux_exit);
+
+MODULE_DESCRIPTION("Serial Mux TTY Line Discipline");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS_LDISC(N_SMUX);
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index d310381..d0b8323 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -1964,12 +1964,25 @@
 	INIT_WORK(&msm_uport->clock_off_w, hsuart_clock_off_work);
 	mutex_init(&msm_uport->clk_mutex);
 
+	clk_prepare_enable(msm_uport->clk);
+	if (msm_uport->pclk)
+		clk_prepare_enable(msm_uport->pclk);
+
 	ret = uartdm_init_port(uport);
-	if (unlikely(ret))
+	if (unlikely(ret)) {
+		clk_disable_unprepare(msm_uport->clk);
+		if (msm_uport->pclk)
+			clk_disable_unprepare(msm_uport->pclk);
 		return ret;
+	}
 
 	/* configure the CR Protection to Enable */
 	msm_hs_write(uport, UARTDM_CR_ADDR, CR_PROTECTION_EN);
+
+	clk_disable_unprepare(msm_uport->clk);
+	if (msm_uport->pclk)
+		clk_disable_unprepare(msm_uport->pclk);
+
 	/*
 	 * Enable Command register protection before going ahead as this hw
 	 * configuration makes sure that issued cmd to CR register gets complete
diff --git a/drivers/tty/serial/msm_serial_hs_lite.c b/drivers/tty/serial/msm_serial_hs_lite.c
index 62d25cf..4a65177 100644
--- a/drivers/tty/serial/msm_serial_hs_lite.c
+++ b/drivers/tty/serial/msm_serial_hs_lite.c
@@ -123,7 +123,7 @@
 	{}
 };
 static struct dentry *debug_base;
-static inline void wait_for_xmitr(struct uart_port *port, int bits);
+static inline void wait_for_xmitr(struct uart_port *port);
 static int get_console_state(struct uart_port *port);
 static inline void msm_hsl_write(struct uart_port *port,
 				 unsigned int val, unsigned int off)
@@ -383,15 +383,16 @@
 
 	/* Handle x_char */
 	if (port->x_char) {
-		wait_for_xmitr(port, UARTDM_ISR_TX_READY_BMSK);
-		msm_hsl_write(port, tx_count + 1,
-			regmap[vid][UARTDM_NCF_TX]);
+		wait_for_xmitr(port);
+		msm_hsl_write(port, tx_count + 1, regmap[vid][UARTDM_NCF_TX]);
+		msm_hsl_read(port, regmap[vid][UARTDM_NCF_TX]);
 		msm_hsl_write(port, port->x_char, regmap[vid][UARTDM_TF]);
 		port->icount.tx++;
 		port->x_char = 0;
 	} else if (tx_count) {
-		wait_for_xmitr(port, UARTDM_ISR_TX_READY_BMSK);
+		wait_for_xmitr(port);
 		msm_hsl_write(port, tx_count, regmap[vid][UARTDM_NCF_TX]);
+		msm_hsl_read(port, regmap[vid][UARTDM_NCF_TX]);
 	}
 	if (!tx_count) {
 		msm_hsl_stop_tx(port);
@@ -1103,7 +1104,7 @@
 /*
  *  Wait for transmitter & holding register to empty
  *  Derived from wait_for_xmitr in 8250 serial driver by Russell King  */
-void wait_for_xmitr(struct uart_port *port, int bits)
+static void wait_for_xmitr(struct uart_port *port)
 {
 	struct msm_hsl_port *msm_hsl_port = UART_TO_MSM(port);
 	unsigned int vid = msm_hsl_port->ver_id;
@@ -1111,8 +1112,8 @@
 
 	if (!(msm_hsl_read(port, regmap[vid][UARTDM_SR]) &
 			UARTDM_SR_TXEMT_BMSK)) {
-		while ((msm_hsl_read(port, regmap[vid][UARTDM_ISR]) &
-					bits) != bits) {
+		while (!(msm_hsl_read(port, regmap[vid][UARTDM_ISR]) &
+			UARTDM_ISR_TX_READY_BMSK)) {
 			udelay(1);
 			touch_nmi_watchdog();
 			cpu_relax();
@@ -1130,7 +1131,7 @@
 {
 	unsigned int vid = UART_TO_MSM(port)->ver_id;
 
-	wait_for_xmitr(port, UARTDM_ISR_TX_READY_BMSK);
+	wait_for_xmitr(port);
 	msm_hsl_write(port, 1, regmap[vid][UARTDM_NCF_TX]);
 	/*
 	 * Dummy read to add 1 AHB clock delay to fix UART hardware bug.
@@ -1219,6 +1220,9 @@
 	msm_hsl_write(port, CR_PROTECTION_EN, regmap[vid][UARTDM_CR]);
 	msm_hsl_write(port, UARTDM_CR_TX_EN_BMSK, regmap[vid][UARTDM_CR]);
 
+	msm_hsl_write(port, 1, regmap[vid][UARTDM_NCF_TX]);
+	msm_hsl_read(port, regmap[vid][UARTDM_NCF_TX]);
+
 	printk(KERN_INFO "msm_serial_hsl: console setup on port #%d\n",
 	       port->line);
 
diff --git a/drivers/tty/smux_ctl.c b/drivers/tty/smux_ctl.c
new file mode 100644
index 0000000..69adbf3
--- /dev/null
+++ b/drivers/tty/smux_ctl.c
@@ -0,0 +1,937 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * Serial Mux Control Driver -- Provides a binary serial muxed control
+ * port interface.
+ */
+
+#define DEBUG
+
+#include <linux/cdev.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/uaccess.h>
+#include <linux/workqueue.h>
+#include <linux/atomic.h>
+#include <linux/platform_device.h>
+#include <linux/smux.h>
+#include <linux/slab.h>
+#include <linux/debugfs.h>
+
+#include <asm/ioctls.h>
+
+#define MAX_WRITE_RETRY 5
+#define MAGIC_NO_V1 0x33FC
+#define DEVICE_NAME "smuxctl"
+#define SMUX_CTL_MAX_BUF_SIZE 2048
+#define SMUX_CTL_MODULE_NAME "smux_ctl"
+#define DEBUG
+
+static int msm_smux_ctl_debug_mask;
+module_param_named(debug_mask, msm_smux_ctl_debug_mask,
+	int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+static uint32_t smux_ctl_ch_id[] = {
+	SMUX_DATA_CTL_0,
+	SMUX_DATA_CTL_1,
+	SMUX_DATA_CTL_2,
+	SMUX_DATA_CTL_3,
+	SMUX_DATA_CTL_4,
+	SMUX_DATA_CTL_5,
+	SMUX_DATA_CTL_6,
+	SMUX_DATA_CTL_7,
+	SMUX_USB_RMNET_CTL_0,
+	SMUX_CSVT_CTL_0
+};
+
+#define SMUX_CTL_NUM_CHANNELS ARRAY_SIZE(smux_ctl_ch_id)
+
+struct smux_ctl_dev {
+	int id;
+	char name[10];
+	struct cdev cdev;
+	struct device *devicep;
+	struct mutex dev_lock;
+	atomic_t ref_count;
+	int state;
+	int is_channel_reset;
+	int is_high_wm;
+	int write_pending;
+
+	struct mutex rx_lock;
+	uint32_t read_avail;
+	struct list_head rx_list;
+
+	wait_queue_head_t read_wait_queue;
+	wait_queue_head_t write_wait_queue;
+
+	struct {
+		uint32_t bytes_tx;
+		uint32_t bytes_rx;
+		uint32_t pkts_tx;
+		uint32_t pkts_rx;
+		uint32_t cnt_ssr;
+		uint32_t cnt_read_fail;
+		uint32_t cnt_write_fail;
+		uint32_t cnt_high_wm_hit;
+	} stats;
+
+} *smux_ctl_devp[SMUX_CTL_NUM_CHANNELS];
+
+struct smux_ctl_pkt {
+	int data_size;
+	void *data;
+};
+
+struct smux_ctl_list_elem {
+	struct list_head list;
+	struct smux_ctl_pkt ctl_pkt;
+};
+
+struct class *smux_ctl_classp;
+static dev_t smux_ctl_number;
+static uint32_t smux_ctl_inited;
+
+enum {
+	MSM_SMUX_CTL_DEBUG = 1U << 0,
+	MSM_SMUX_CTL_DUMP_BUFFER = 1U << 1,
+};
+
+#if defined(DEBUG)
+
+static const char *smux_ctl_event_str[] = {
+	"SMUX_CONNECTED",
+	"SMUX_DISCONNECTED",
+	"SMUX_READ_DONE",
+	"SMUX_READ_FAIL",
+	"SMUX_WRITE_DONE",
+	"SMUX_WRITE_FAIL",
+	"SMUX_TIOCM_UPDATE",
+	"SMUX_LOW_WM_HIT",
+	"SMUX_HIGH_WM_HIT",
+};
+
+#define SMUXCTL_DUMP_BUFFER(prestr, cnt, buf) \
+do { \
+	if (msm_smux_ctl_debug_mask & MSM_SMUX_CTL_DUMP_BUFFER) { \
+		int i; \
+		pr_err("%s", prestr); \
+		for (i = 0; i < cnt; i++) \
+			pr_err("%.2x", buf[i]); \
+		pr_err("\n"); \
+	} \
+} while (0)
+
+#define SMUXCTL_DBG(x...) \
+do { \
+	if (msm_smux_ctl_debug_mask & MSM_SMUX_CTL_DEBUG) \
+		pr_err(x); \
+} while (0)
+
+
+#else
+#define SMUXCTL_DUMP_BUFFER(prestr, cnt, buf) do {} while (0)
+#define SMUXCTL_DBG(x...) do {} while (0)
+#endif
+
+#if defined(DEBUG_LOOPBACK)
+#define SMUXCTL_SET_LOOPBACK(lcid) \
+	msm_smux_set_ch_option(lcid, SMUX_CH_OPTION_LOCAL_LOOPBACK, 0)
+#else
+#define SMUXCTL_SET_LOOPBACK(lcid) do {} while (0)
+#endif
+
+static int get_ctl_dev_index(int id)
+{
+	int dev_index;
+	for (dev_index = 0; dev_index < SMUX_CTL_NUM_CHANNELS; dev_index++) {
+		if (smux_ctl_ch_id[dev_index] == id)
+			return dev_index;
+	}
+	return -ENODEV;
+}
+
+static int smux_ctl_get_rx_buf_cb(void *priv, void **pkt_priv,
+		void **buffer, int size)
+{
+	void *buf = NULL;
+	int id = ((struct smux_ctl_dev *)(priv))->id;
+	int dev_index;
+
+	if (id < 0 || id > smux_ctl_ch_id[SMUX_CTL_NUM_CHANNELS - 1])
+		return -ENODEV;
+
+	if (!buffer || 0 >= size)
+		return -EINVAL;
+
+	dev_index = get_ctl_dev_index(id);
+	if (dev_index < 0) {
+		pr_err(SMUX_CTL_MODULE_NAME ": %s: Ch%d is not "
+					"exported to user-space\n",
+				__func__, id);
+		return -ENODEV;
+	}
+
+	SMUXCTL_DBG(SMUX_CTL_MODULE_NAME ": %s: Allocating Rx buf size %d "
+			"for ch%d\n",
+			__func__, size, smux_ctl_devp[dev_index]->id);
+
+	buf = kmalloc(size, GFP_KERNEL);
+	if (!buf) {
+		pr_err(SMUX_CTL_MODULE_NAME ": %s: buffer allocation failed: "
+				"Ch%d, size %d ", __func__, id, size);
+		return -ENOMEM;
+	}
+
+	*buffer = buf;
+	*pkt_priv = NULL;
+	return 0;
+
+}
+
+void smux_ctl_notify_cb(void *priv, int event_type, const void *metadata)
+{
+	int id = ((struct smux_ctl_dev *)(priv))->id;
+	struct smux_ctl_list_elem *list_elem = NULL;
+	int dev_index;
+	void *data;
+	int len;
+
+	if (id < 0 || id > smux_ctl_ch_id[SMUX_CTL_NUM_CHANNELS - 1])
+		return;
+
+	dev_index = get_ctl_dev_index(id);
+	if (dev_index < 0) {
+		pr_err(SMUX_CTL_MODULE_NAME ": %s: Ch%d is not exported "
+				"to user-space\n", __func__, id);
+		return;
+	}
+
+	SMUXCTL_DBG(SMUX_CTL_MODULE_NAME ": %s: Ch%d, Event %d (%s)\n",
+			__func__, smux_ctl_devp[dev_index]->id,
+				event_type, smux_ctl_event_str[event_type]);
+
+
+	switch (event_type) {
+	case SMUX_CONNECTED:
+		mutex_lock(&smux_ctl_devp[dev_index]->dev_lock);
+		smux_ctl_devp[dev_index]->state = SMUX_CONNECTED;
+		smux_ctl_devp[dev_index]->is_high_wm = 0;
+		smux_ctl_devp[dev_index]->is_channel_reset = 0;
+		smux_ctl_devp[dev_index]->read_avail = 0;
+		mutex_unlock(&smux_ctl_devp[dev_index]->dev_lock);
+		wake_up(&smux_ctl_devp[dev_index]->write_wait_queue);
+		break;
+
+	case SMUX_DISCONNECTED:
+		mutex_lock(&smux_ctl_devp[dev_index]->dev_lock);
+		smux_ctl_devp[dev_index]->state = SMUX_DISCONNECTED;
+		smux_ctl_devp[dev_index]->is_channel_reset =
+			((struct smux_meta_disconnected *)metadata)->is_ssr;
+		if (smux_ctl_devp[dev_index]->is_channel_reset)
+			smux_ctl_devp[dev_index]->stats.cnt_ssr++;
+		mutex_unlock(&smux_ctl_devp[dev_index]->dev_lock);
+		wake_up(&smux_ctl_devp[dev_index]->write_wait_queue);
+		wake_up(&smux_ctl_devp[dev_index]->read_wait_queue);
+		break;
+
+	case SMUX_READ_FAIL:
+		data = ((struct smux_meta_read *)metadata)->buffer;
+		kfree(data);
+		mutex_lock(&smux_ctl_devp[dev_index]->dev_lock);
+		smux_ctl_devp[dev_index]->stats.cnt_read_fail++;
+		mutex_unlock(&smux_ctl_devp[dev_index]->dev_lock);
+		wake_up(&smux_ctl_devp[dev_index]->read_wait_queue);
+		break;
+
+	case SMUX_READ_DONE:
+		data = ((struct smux_meta_read *)metadata)->buffer;
+		len = ((struct smux_meta_read *)metadata)->len;
+
+		if (data && len > 0) {
+			list_elem = kmalloc(sizeof(struct smux_ctl_list_elem),
+							GFP_KERNEL);
+			if (list_elem) {
+				list_elem->ctl_pkt.data = data;
+				list_elem->ctl_pkt.data_size = len;
+
+				mutex_lock(&smux_ctl_devp[dev_index]->rx_lock);
+				list_add_tail(&list_elem->list,
+					&smux_ctl_devp[dev_index]->rx_list);
+				smux_ctl_devp[dev_index]->read_avail += len;
+				mutex_unlock(
+					&smux_ctl_devp[dev_index]->rx_lock);
+			} else {
+				kfree(data);
+			}
+		}
+
+		wake_up(&smux_ctl_devp[dev_index]->read_wait_queue);
+		break;
+
+	case SMUX_WRITE_DONE:
+		mutex_lock(&smux_ctl_devp[dev_index]->dev_lock);
+		smux_ctl_devp[dev_index]->write_pending = 0;
+		mutex_unlock(&smux_ctl_devp[dev_index]->dev_lock);
+		data = ((struct smux_meta_write *)metadata)->buffer;
+		kfree(data);
+		wake_up(&smux_ctl_devp[dev_index]->write_wait_queue);
+		break;
+
+	case SMUX_WRITE_FAIL:
+		data = ((struct smux_meta_write *)metadata)->buffer;
+		kfree(data);
+		mutex_lock(&smux_ctl_devp[dev_index]->dev_lock);
+		smux_ctl_devp[dev_index]->stats.cnt_write_fail++;
+		mutex_unlock(&smux_ctl_devp[dev_index]->dev_lock);
+		wake_up(&smux_ctl_devp[dev_index]->write_wait_queue);
+		break;
+
+	case SMUX_LOW_WM_HIT:
+		mutex_lock(&smux_ctl_devp[dev_index]->dev_lock);
+		smux_ctl_devp[dev_index]->is_high_wm = 0;
+		mutex_unlock(&smux_ctl_devp[dev_index]->dev_lock);
+		wake_up(&smux_ctl_devp[dev_index]->write_wait_queue);
+		break;
+
+	case SMUX_HIGH_WM_HIT:
+		mutex_lock(&smux_ctl_devp[dev_index]->dev_lock);
+		smux_ctl_devp[dev_index]->is_high_wm = 1;
+		smux_ctl_devp[dev_index]->stats.cnt_high_wm_hit++;
+		mutex_unlock(&smux_ctl_devp[dev_index]->dev_lock);
+		break;
+
+	case SMUX_TIOCM_UPDATE:
+	default:
+		pr_err(SMUX_CTL_MODULE_NAME ": %s: Event %d not supported\n",
+				__func__, event_type);
+		break;
+
+	}
+
+}
+
+int smux_ctl_open(struct inode *inode, struct file *file)
+{
+	int r = 0;
+	struct smux_ctl_dev *devp;
+
+	if (!smux_ctl_inited)
+		return -EIO;
+
+	devp = container_of(inode->i_cdev, struct smux_ctl_dev, cdev);
+	if (!devp)
+		return -ENODEV;
+
+	SMUXCTL_DBG(SMUX_CTL_MODULE_NAME ": %s called on smuxctl%d device\n",
+			__func__, devp->id);
+
+	if (1 == atomic_add_return(1, &devp->ref_count)) {
+
+		SMUXCTL_SET_LOOPBACK(devp->id);
+		r = msm_smux_open(devp->id,
+				devp,
+				smux_ctl_notify_cb,
+				smux_ctl_get_rx_buf_cb);
+		if (r < 0) {
+			pr_err(SMUX_CTL_MODULE_NAME ": %s: smux_open failed "
+					"for smuxctl%d with rc %d\n",
+					__func__, devp->id, r);
+			atomic_dec(&devp->ref_count);
+			return r;
+		}
+
+		r = wait_event_interruptible_timeout(
+				devp->write_wait_queue,
+				(devp->state == SMUX_CONNECTED),
+				(5 * HZ));
+		if (r == 0)
+			r = -ETIMEDOUT;
+
+		if (r < 0) {
+			pr_err(SMUX_CTL_MODULE_NAME ": %s: "
+				"SMUX open timed out: %d, LCID %d\n",
+			       __func__, r, devp->id);
+			atomic_dec(&devp->ref_count);
+			msm_smux_close(devp->id);
+			return r;
+
+		} else if (devp->state != SMUX_CONNECTED) {
+			pr_err(SMUX_CTL_MODULE_NAME ": %s: "
+				"Invalid open notification\n", __func__);
+			r = -ENODEV;
+			atomic_dec(&devp->ref_count);
+			msm_smux_close(devp->id);
+			return r;
+		}
+	}
+
+	file->private_data = devp;
+	return 0;
+}
+
+int smux_ctl_release(struct inode *inode, struct file *file)
+{
+	struct smux_ctl_dev *devp;
+	struct smux_ctl_list_elem *list_elem = NULL;
+
+	devp = file->private_data;
+	if (!devp)
+		return -EINVAL;
+
+	SMUXCTL_DBG(SMUX_CTL_MODULE_NAME ": %s called on smuxctl%d device\n",
+			__func__, devp->id);
+
+	mutex_lock(&devp->dev_lock);
+	if (atomic_dec_and_test(&devp->ref_count)) {
+		mutex_lock(&devp->rx_lock);
+		while (!list_empty(&devp->rx_list)) {
+			list_elem = list_first_entry(
+					&devp->rx_list,
+					struct smux_ctl_list_elem,
+					list);
+			list_del(&list_elem->list);
+			kfree(list_elem->ctl_pkt.data);
+			kfree(list_elem);
+		}
+		devp->read_avail = 0;
+		mutex_unlock(&devp->rx_lock);
+		msm_smux_close(devp->id);
+	}
+	mutex_unlock(&devp->dev_lock);
+	file->private_data = NULL;
+
+	return 0;
+}
+
+static int smux_ctl_readable(int id)
+{
+	int r;
+	int dev_index;
+
+	if (id < 0 || id > smux_ctl_ch_id[SMUX_CTL_NUM_CHANNELS - 1])
+		return -ENODEV;
+
+	dev_index = get_ctl_dev_index(id);
+	if (dev_index < 0) {
+		pr_err(SMUX_CTL_MODULE_NAME ": %s: Ch%d "
+				"is not exported to user-space\n",
+			__func__, id);
+		return -ENODEV;
+	}
+
+	mutex_lock(&smux_ctl_devp[dev_index]->dev_lock);
+
+	if (signal_pending(current))
+		r = -ERESTARTSYS;
+
+	if (smux_ctl_devp[dev_index]->state == SMUX_DISCONNECTED &&
+	    smux_ctl_devp[dev_index]->is_channel_reset != 0)
+		r = -ENETRESET;
+
+	else if (smux_ctl_devp[dev_index]->state != SMUX_CONNECTED)
+		r = -ENODEV;
+
+	else
+		r = smux_ctl_devp[dev_index]->read_avail;
+
+
+	mutex_unlock(&smux_ctl_devp[dev_index]->dev_lock);
+
+	return r;
+
+}
+
+ssize_t smux_ctl_read(struct file *file,
+			char __user *buf,
+			size_t count,
+			loff_t *ppos)
+{
+	int r = 0, id, bytes_to_read, read_err;
+	struct smux_ctl_dev *devp;
+	struct smux_ctl_list_elem *list_elem = NULL;
+
+	devp = file->private_data;
+
+	if (!devp)
+		return -ENODEV;
+
+	SMUXCTL_DBG(SMUX_CTL_MODULE_NAME ": %s: read from ch%d\n",
+			__func__, devp->id);
+
+	id = devp->id;
+	mutex_lock(&devp->rx_lock);
+	while (devp->read_avail <= 0) {
+		mutex_unlock(&devp->rx_lock);
+		r = wait_event_interruptible(devp->read_wait_queue,
+				0 != (read_err = smux_ctl_readable(id)));
+
+		if (r < 0) {
+			pr_err(SMUX_CTL_MODULE_NAME ": %s:"
+					"wait_event_interruptible "
+					"ret %i\n", __func__, r);
+			return r;
+		}
+
+		if (read_err < 0) {
+			pr_err(SMUX_CTL_MODULE_NAME ": %s:"
+				" Read block failed for Ch%d, err %d\n",
+					__func__, devp->id, read_err);
+			return read_err;
+		}
+
+		mutex_lock(&devp->rx_lock);
+	}
+
+	if (list_empty(&devp->rx_list)) {
+		mutex_unlock(&devp->rx_lock);
+		SMUXCTL_DBG(SMUX_CTL_MODULE_NAME ": %s: "
+			"Nothing in ch%d's rx_list\n", __func__,
+			devp->id);
+		return -EAGAIN;
+	}
+
+	list_elem = list_first_entry(&devp->rx_list,
+			struct smux_ctl_list_elem, list);
+	bytes_to_read = (uint32_t)(list_elem->ctl_pkt.data_size);
+	if (bytes_to_read > count) {
+		mutex_unlock(&devp->rx_lock);
+		pr_err(SMUX_CTL_MODULE_NAME ": %s: "
+			"Packet size %d > buf size %d\n", __func__,
+			bytes_to_read, count);
+		return -ENOMEM;
+	}
+
+	if (copy_to_user(buf, list_elem->ctl_pkt.data, bytes_to_read)) {
+		mutex_unlock(&devp->rx_lock);
+		pr_err(SMUX_CTL_MODULE_NAME ": %s: "
+			"copy_to_user failed for ch%d\n", __func__,
+			devp->id);
+		return -EFAULT;
+	}
+
+	devp->read_avail -= bytes_to_read;
+	list_del(&list_elem->list);
+	kfree(list_elem->ctl_pkt.data);
+	kfree(list_elem);
+	devp->stats.pkts_rx++;
+	devp->stats.bytes_rx += bytes_to_read;
+	mutex_unlock(&devp->rx_lock);
+
+	SMUXCTL_DBG(SMUX_CTL_MODULE_NAME ": %s: "
+		"Returning %d bytes to ch%d\n", __func__,
+			bytes_to_read, devp->id);
+	return bytes_to_read;
+}
+
+static int smux_ctl_writeable(int id)
+{
+	int r;
+	int dev_index;
+
+	if (id < 0 || id > smux_ctl_ch_id[SMUX_CTL_NUM_CHANNELS - 1])
+		return -ENODEV;
+
+	dev_index = get_ctl_dev_index(id);
+	if (dev_index < 0) {
+		pr_err(SMUX_CTL_MODULE_NAME ": %s: "
+			"Ch%d is not exported to user-space\n",
+			__func__, id);
+		return -ENODEV;
+	}
+
+	mutex_lock(&smux_ctl_devp[dev_index]->dev_lock);
+
+	if (signal_pending(current))
+		r = -ERESTARTSYS;
+	else if (smux_ctl_devp[dev_index]->state == SMUX_DISCONNECTED &&
+	    smux_ctl_devp[dev_index]->is_channel_reset != 0)
+		r = -ENETRESET;
+	else if (smux_ctl_devp[dev_index]->state != SMUX_CONNECTED)
+		r = -ENODEV;
+	else if (smux_ctl_devp[dev_index]->is_high_wm ||
+			smux_ctl_devp[dev_index]->write_pending)
+		r = 0;
+	else
+		r = SMUX_CTL_MAX_BUF_SIZE;
+
+	mutex_unlock(&smux_ctl_devp[dev_index]->dev_lock);
+
+	return r;
+
+}
+
+ssize_t smux_ctl_write(struct file *file,
+		const char __user *buf,
+		size_t count,
+		loff_t *ppos)
+{
+	int r = 0, id, write_err;
+	char *temp_buf;
+	struct smux_ctl_dev *devp;
+
+	if (count <= 0)
+		return -EINVAL;
+
+	devp = file->private_data;
+	if (!devp)
+		return -ENODEV;
+
+	SMUXCTL_DBG(SMUX_CTL_MODULE_NAME ": %s: writing %i bytes on ch%d\n",
+			__func__, count, devp->id);
+
+	id = devp->id;
+	r = wait_event_interruptible(devp->write_wait_queue,
+			0 != (write_err = smux_ctl_writeable(id)));
+
+	if (r < 0) {
+		pr_err(SMUX_CTL_MODULE_NAME
+				": %s: wait_event_interruptible "
+				"ret %i\n", __func__, r);
+		return r;
+	}
+
+	if (write_err < 0) {
+		pr_err(SMUX_CTL_MODULE_NAME ": %s:"
+				"Write block failed for Ch%d, err %d\n",
+				__func__, devp->id, write_err);
+		return write_err;
+	}
+
+	temp_buf = kmalloc(count, GFP_KERNEL);
+	if (!temp_buf) {
+		pr_err(SMUX_CTL_MODULE_NAME
+				": %s: temp_buf alloc failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	if (copy_from_user(temp_buf, buf, count)) {
+		pr_err(SMUX_CTL_MODULE_NAME
+				": %s: copy_from_user failed\n", __func__);
+		kfree(temp_buf);
+		return -EFAULT;
+	}
+
+	mutex_lock(&devp->dev_lock);
+	devp->write_pending = 1;
+	mutex_unlock(&devp->dev_lock);
+
+	r = msm_smux_write(id, NULL, (void *)temp_buf, count);
+	if (r < 0) {
+		pr_err(SMUX_CTL_MODULE_NAME
+			": %s: smux_write on Ch%dfailed, err %d\n",
+				__func__, id, r);
+		mutex_lock(&devp->dev_lock);
+		devp->write_pending = 0;
+		mutex_unlock(&devp->dev_lock);
+		return r;
+	}
+
+	r = wait_event_interruptible(devp->write_wait_queue,
+			0 != (write_err = smux_ctl_writeable(id)));
+	if (r < 0) {
+		pr_err(SMUX_CTL_MODULE_NAME " :%s: wait_event_interruptible "
+				"ret %i\n", __func__, r);
+		mutex_lock(&devp->dev_lock);
+		devp->write_pending = 0;
+		mutex_unlock(&devp->dev_lock);
+		return r;
+	}
+
+	mutex_lock(&devp->dev_lock);
+	devp->write_pending = 0;
+	devp->stats.pkts_tx++;
+	devp->stats.bytes_tx += count;
+	mutex_unlock(&devp->dev_lock);
+	return count;
+}
+
+static long smux_ctl_ioctl(struct file *file, unsigned int cmd,
+				unsigned long arg)
+{
+	int ret;
+	struct smux_ctl_dev *devp;
+
+	devp = file->private_data;
+	if (!devp)
+		return -ENODEV;
+
+	SMUXCTL_DBG(SMUX_CTL_MODULE_NAME ": %s called on smuxctl%d device\n",
+			__func__, devp->id);
+
+	switch (cmd) {
+	case TIOCMGET:
+		ret = msm_smux_tiocm_get(devp->id);
+		break;
+	case TIOCMSET:
+		ret = msm_smux_tiocm_set(devp->id, arg, ~arg);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static const struct file_operations smux_ctl_fops = {
+	.owner = THIS_MODULE,
+	.open = smux_ctl_open,
+	.release = smux_ctl_release,
+	.read = smux_ctl_read,
+	.write = smux_ctl_write,
+	.unlocked_ioctl = smux_ctl_ioctl,
+};
+
+static int smux_ctl_probe(struct platform_device *pdev)
+{
+	int i;
+	int r;
+
+	SMUXCTL_DBG(SMUX_CTL_MODULE_NAME ": %s Begins\n", __func__);
+
+	for (i = 0; i < SMUX_CTL_NUM_CHANNELS; ++i) {
+		smux_ctl_devp[i] = kzalloc(sizeof(struct smux_ctl_dev),
+							GFP_KERNEL);
+		if (IS_ERR(smux_ctl_devp[i])) {
+			pr_err(SMUX_CTL_MODULE_NAME
+				 ": %s kmalloc() ENOMEM\n", __func__);
+			r = -ENOMEM;
+			goto error0;
+		}
+
+		smux_ctl_devp[i]->id = smux_ctl_ch_id[i];
+		atomic_set(&smux_ctl_devp[i]->ref_count, 0);
+		smux_ctl_devp[i]->is_high_wm = 0;
+		smux_ctl_devp[i]->write_pending = 0;
+		smux_ctl_devp[i]->is_channel_reset = 0;
+		smux_ctl_devp[i]->state = SMUX_DISCONNECTED;
+		smux_ctl_devp[i]->read_avail = 0;
+
+		smux_ctl_devp[i]->stats.bytes_tx = 0;
+		smux_ctl_devp[i]->stats.bytes_rx = 0;
+		smux_ctl_devp[i]->stats.pkts_tx = 0;
+		smux_ctl_devp[i]->stats.pkts_rx = 0;
+		smux_ctl_devp[i]->stats.cnt_ssr = 0;
+		smux_ctl_devp[i]->stats.cnt_read_fail = 0;
+		smux_ctl_devp[i]->stats.cnt_write_fail = 0;
+		smux_ctl_devp[i]->stats.cnt_high_wm_hit = 0;
+
+		mutex_init(&smux_ctl_devp[i]->dev_lock);
+		init_waitqueue_head(&smux_ctl_devp[i]->read_wait_queue);
+		init_waitqueue_head(&smux_ctl_devp[i]->write_wait_queue);
+		mutex_init(&smux_ctl_devp[i]->rx_lock);
+		INIT_LIST_HEAD(&smux_ctl_devp[i]->rx_list);
+	}
+
+	r = alloc_chrdev_region(&smux_ctl_number, 0, SMUX_CTL_NUM_CHANNELS,
+							DEVICE_NAME);
+	if (IS_ERR_VALUE(r)) {
+		pr_err(SMUX_CTL_MODULE_NAME ": %s: "
+				"alloc_chrdev_region() ret %i.\n",
+					 __func__, r);
+		goto error0;
+	}
+
+	smux_ctl_classp = class_create(THIS_MODULE, DEVICE_NAME);
+	if (IS_ERR(smux_ctl_classp)) {
+		pr_err(SMUX_CTL_MODULE_NAME ": %s: "
+				"class_create() ENOMEM\n", __func__);
+		r = -ENOMEM;
+		goto error1;
+	}
+
+	for (i = 0; i < SMUX_CTL_NUM_CHANNELS; ++i) {
+		cdev_init(&smux_ctl_devp[i]->cdev, &smux_ctl_fops);
+		smux_ctl_devp[i]->cdev.owner = THIS_MODULE;
+
+		r = cdev_add(&smux_ctl_devp[i]->cdev, (smux_ctl_number + i), 1);
+
+		if (IS_ERR_VALUE(r)) {
+			pr_err(SMUX_CTL_MODULE_NAME ": %s: "
+					"cdev_add() ret %i\n", __func__, r);
+			kfree(smux_ctl_devp[i]);
+			goto error2;
+		}
+
+		smux_ctl_devp[i]->devicep =
+				device_create(smux_ctl_classp, NULL,
+					(smux_ctl_number + i), NULL,
+					DEVICE_NAME "%d", smux_ctl_ch_id[i]);
+
+		if (IS_ERR(smux_ctl_devp[i]->devicep)) {
+			pr_err(SMUX_CTL_MODULE_NAME ": %s: "
+					"device_create() ENOMEM\n", __func__);
+			r = -ENOMEM;
+			cdev_del(&smux_ctl_devp[i]->cdev);
+			kfree(smux_ctl_devp[i]);
+			goto error2;
+		}
+	}
+
+	smux_ctl_inited = 1;
+	SMUXCTL_DBG(SMUX_CTL_MODULE_NAME ": %s: "
+		"SMUX Control Port Driver Initialized.\n", __func__);
+	return 0;
+
+error2:
+	while (--i >= 0) {
+		cdev_del(&smux_ctl_devp[i]->cdev);
+		device_destroy(smux_ctl_classp,
+			MKDEV(MAJOR(smux_ctl_number), i));
+	}
+
+	class_destroy(smux_ctl_classp);
+	i = SMUX_CTL_NUM_CHANNELS;
+
+error1:
+	unregister_chrdev_region(MAJOR(smux_ctl_number),
+			SMUX_CTL_NUM_CHANNELS);
+
+error0:
+	while (--i >= 0)
+		kfree(smux_ctl_devp[i]);
+
+	return r;
+}
+
+static int smux_ctl_remove(struct platform_device *pdev)
+{
+	int i;
+
+	SMUXCTL_DBG(SMUX_CTL_MODULE_NAME ": %s Begins\n", __func__);
+
+	for (i = 0; i < SMUX_CTL_NUM_CHANNELS; ++i) {
+		cdev_del(&smux_ctl_devp[i]->cdev);
+		kfree(smux_ctl_devp[i]);
+		device_destroy(smux_ctl_classp,
+			MKDEV(MAJOR(smux_ctl_number), i));
+	}
+	class_destroy(smux_ctl_classp);
+	unregister_chrdev_region(MAJOR(smux_ctl_number),
+			SMUX_CTL_NUM_CHANNELS);
+
+	return 0;
+}
+
+static struct platform_driver smux_ctl_driver = {
+	.probe = smux_ctl_probe,
+	.remove = smux_ctl_remove,
+	.driver = {
+		.name = "SMUX_CTL",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init smux_ctl_init(void)
+{
+	msm_smux_ctl_debug_mask = MSM_SMUX_CTL_DEBUG | MSM_SMUX_CTL_DUMP_BUFFER;
+
+	SMUXCTL_DBG(SMUX_CTL_MODULE_NAME ": %s Begins\n", __func__);
+	return platform_driver_register(&smux_ctl_driver);
+}
+
+
+#if defined(CONFIG_DEBUG_FS)
+
+#define DEBUG_BUFMAX 4096
+static char debug_buffer[DEBUG_BUFMAX];
+
+static ssize_t debug_read(struct file *file, char __user *buf,
+				size_t count, loff_t *ppos)
+{
+	int bsize = 0;
+	int i;
+	if (!smux_ctl_inited) {
+		pr_err(SMUX_CTL_MODULE_NAME ": %s: SMUX_CTL not yet inited\n",
+				__func__);
+		return -EIO;
+	}
+
+	bsize += scnprintf(debug_buffer + bsize, DEBUG_BUFMAX - bsize,
+				"SMUX_CTL Channel States:\n");
+
+	for (i = 0; i < SMUX_CTL_NUM_CHANNELS; ++i) {
+		bsize += scnprintf(debug_buffer + bsize, DEBUG_BUFMAX - bsize,
+		"Ch%02d %s RefCnt=%01d State=%02d "
+		"SSR=%02d HighWM=%02d ReadAvail=%04d WritePending=%02d\n",
+		smux_ctl_devp[i]->id,
+		smux_ctl_devp[i]->name,
+		atomic_read(&smux_ctl_devp[i]->ref_count),
+		smux_ctl_devp[i]->state,
+		smux_ctl_devp[i]->is_channel_reset,
+		smux_ctl_devp[i]->is_high_wm,
+		smux_ctl_devp[i]->read_avail,
+		smux_ctl_devp[i]->write_pending);
+	}
+
+	bsize += scnprintf(debug_buffer + bsize, DEBUG_BUFMAX - bsize,
+				"\nSMUX_CTL Channel Statistics:\n");
+	for (i = 0; i < SMUX_CTL_NUM_CHANNELS; ++i) {
+		bsize += scnprintf(debug_buffer + bsize, DEBUG_BUFMAX - bsize,
+			"Ch%02d %s BytesTX=%08d "
+				"BytesRx=%08d PktsTx=%04d PktsRx=%04d"
+			"CntSSR=%02d CntHighWM=%02d "
+				"CntReadFail%02d CntWriteFailed=%02d\n",
+			smux_ctl_devp[i]->id,
+			smux_ctl_devp[i]->name,
+			smux_ctl_devp[i]->stats.bytes_tx,
+			smux_ctl_devp[i]->stats.bytes_rx,
+			smux_ctl_devp[i]->stats.pkts_tx,
+			smux_ctl_devp[i]->stats.pkts_rx,
+			smux_ctl_devp[i]->stats.cnt_ssr,
+			smux_ctl_devp[i]->stats.cnt_high_wm_hit,
+			smux_ctl_devp[i]->stats.cnt_read_fail,
+			smux_ctl_devp[i]->stats.cnt_write_fail);
+	}
+
+	return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize);
+}
+
+static int debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static const struct file_operations debug_ops = {
+	.read = debug_read,
+	.open = debug_open,
+};
+
+static int __init smux_debugfs_init(void)
+{
+	struct dentry *dent;
+
+	dent = debugfs_create_dir("smux_ctl", 0);
+	if (!IS_ERR(dent))
+		debugfs_create_file("smux_ctl_state", 0444, dent,
+			NULL, &debug_ops);
+
+	return 0;
+}
+
+late_initcall(smux_debugfs_init);
+#endif
+
+module_init(smux_ctl_init);
+MODULE_DESCRIPTION("MSM SMUX Control Port");
+MODULE_LICENSE("GPL v2");
+
+
diff --git a/drivers/tty/smux_loopback.c b/drivers/tty/smux_loopback.c
new file mode 100644
index 0000000..bf6d50b
--- /dev/null
+++ b/drivers/tty/smux_loopback.c
@@ -0,0 +1,288 @@
+/* drivers/tty/smux_loopback.c
+ *
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/types.h>
+#include <linux/err.h>
+#include <linux/workqueue.h>
+#include <linux/kfifo.h>
+#include <linux/slab.h>
+#include <linux/smux.h>
+#include "smux_private.h"
+
+#define SMUX_LOOP_FIFO_SIZE	128
+
+static void smux_loopback_rx_worker(struct work_struct *work);
+static struct workqueue_struct *smux_loopback_wq;
+static DECLARE_WORK(smux_loopback_work, smux_loopback_rx_worker);
+static struct kfifo smux_loop_pkt_fifo;
+static DEFINE_SPINLOCK(hw_fn_lock);
+
+/**
+ * Initialize loopback framework (called by n_smux.c).
+ */
+int smux_loopback_init(void)
+{
+	int ret = 0;
+
+	spin_lock_init(&hw_fn_lock);
+	smux_loopback_wq = create_singlethread_workqueue("smux_loopback_wq");
+	if (IS_ERR(smux_loopback_wq)) {
+		pr_err("%s: failed to create workqueue\n", __func__);
+		return -ENOMEM;
+	}
+
+	ret |= kfifo_alloc(&smux_loop_pkt_fifo,
+			SMUX_LOOP_FIFO_SIZE * sizeof(struct smux_pkt_t *),
+			GFP_KERNEL);
+
+	return ret;
+}
+
+/**
+ * Simulate a write to the TTY hardware by duplicating
+ * the TX packet and putting it into the RX queue.
+ *
+ * @pkt     Packet to write
+ *
+ * @returns 0 on success
+ */
+int smux_tx_loopback(struct smux_pkt_t *pkt_ptr)
+{
+	struct smux_pkt_t *send_pkt;
+	unsigned long flags;
+	int i;
+	int ret;
+
+	/* duplicate packet */
+	send_pkt = smux_alloc_pkt();
+	send_pkt->hdr = pkt_ptr->hdr;
+	if (pkt_ptr->hdr.payload_len) {
+		ret = smux_alloc_pkt_payload(send_pkt);
+		if (ret) {
+			ret = -ENOMEM;
+			goto out;
+		}
+		memcpy(send_pkt->payload, pkt_ptr->payload,
+				pkt_ptr->hdr.payload_len);
+	}
+
+	/* queue duplicate as pseudo-RX data */
+	spin_lock_irqsave(&hw_fn_lock, flags);
+	i = kfifo_avail(&smux_loop_pkt_fifo);
+	if (i < sizeof(struct smux_pkt_t *)) {
+		pr_err("%s: no space in fifo\n", __func__);
+		ret = -ENOMEM;
+		goto unlock;
+	}
+
+	i = kfifo_in(&smux_loop_pkt_fifo,
+			&send_pkt,
+			sizeof(struct smux_pkt_t *));
+	if (i < 0) {
+		pr_err("%s: fifo error\n", __func__);
+		ret = -ENOMEM;
+		goto unlock;
+	}
+	queue_work(smux_loopback_wq, &smux_loopback_work);
+	ret = 0;
+
+unlock:
+	spin_unlock_irqrestore(&hw_fn_lock, flags);
+out:
+	return ret;
+}
+
+/**
+ * Receive loopback byte processor.
+ *
+ * @pkt  Incoming packet
+ */
+static void smux_loopback_rx_byte(struct smux_pkt_t *pkt)
+{
+	static int simulated_retry_cnt;
+	const char ack = SMUX_WAKEUP_ACK;
+
+	switch (pkt->hdr.flags) {
+	case SMUX_WAKEUP_REQ:
+		/* reply with ACK after appropriate delays */
+		++simulated_retry_cnt;
+		if (simulated_retry_cnt >= smux_simulate_wakeup_delay) {
+			pr_err("%s: completed %d of %d\n",
+				__func__, simulated_retry_cnt,
+				smux_simulate_wakeup_delay);
+			pr_err("%s: simulated wakeup\n", __func__);
+			simulated_retry_cnt = 0;
+			smux_rx_state_machine(&ack, 1, 0);
+		} else {
+			/* force retry */
+			pr_err("%s: dropping wakeup request %d of %d\n",
+					__func__, simulated_retry_cnt,
+					smux_simulate_wakeup_delay);
+		}
+		break;
+	case SMUX_WAKEUP_ACK:
+		/* this shouldn't happen since we don't send requests */
+		pr_err("%s: wakeup ACK unexpected\n", __func__);
+		break;
+
+	default:
+		/* invalid character */
+		pr_err("%s: invalid character 0x%x\n",
+				__func__, (unsigned)pkt->hdr.flags);
+		break;
+	}
+}
+
+/**
+ * Simulated remote hardware used for local loopback testing.
+ *
+ * @work Not used
+ */
+static void smux_loopback_rx_worker(struct work_struct *work)
+{
+	struct smux_pkt_t *pkt;
+	struct smux_pkt_t reply_pkt;
+	char *data;
+	int len;
+	int lcid;
+	int i;
+	unsigned long flags;
+
+	data = kzalloc(SMUX_MAX_PKT_SIZE, GFP_ATOMIC);
+
+	spin_lock_irqsave(&hw_fn_lock, flags);
+	while (kfifo_len(&smux_loop_pkt_fifo) >= sizeof(struct smux_pkt_t *)) {
+		i = kfifo_out(&smux_loop_pkt_fifo, &pkt,
+					sizeof(struct smux_pkt_t *));
+		spin_unlock_irqrestore(&hw_fn_lock, flags);
+
+		if (pkt->hdr.magic != SMUX_MAGIC) {
+			pr_err("%s: invalid magic %x\n", __func__,
+					pkt->hdr.magic);
+			return;
+		}
+
+		lcid = pkt->hdr.lcid;
+		if (smux_assert_lch_id(lcid)) {
+			pr_err("%s: invalid channel id %d\n", __func__, lcid);
+			return;
+		}
+
+		switch (pkt->hdr.cmd) {
+		case SMUX_CMD_OPEN_LCH:
+			if (pkt->hdr.flags & SMUX_CMD_OPEN_ACK)
+				break;
+
+			/* Reply with Open ACK */
+			smux_init_pkt(&reply_pkt);
+			reply_pkt.hdr.lcid = lcid;
+			reply_pkt.hdr.cmd = SMUX_CMD_OPEN_LCH;
+			reply_pkt.hdr.flags = SMUX_CMD_OPEN_ACK
+				| SMUX_CMD_OPEN_POWER_COLLAPSE;
+			reply_pkt.hdr.payload_len = 0;
+			reply_pkt.hdr.pad_len = 0;
+			smux_serialize(&reply_pkt, data, &len);
+			smux_rx_state_machine(data, len, 0);
+
+			/* Send Remote Open */
+			smux_init_pkt(&reply_pkt);
+			reply_pkt.hdr.lcid = lcid;
+			reply_pkt.hdr.cmd = SMUX_CMD_OPEN_LCH;
+			reply_pkt.hdr.flags = SMUX_CMD_OPEN_POWER_COLLAPSE;
+			reply_pkt.hdr.payload_len = 0;
+			reply_pkt.hdr.pad_len = 0;
+			smux_serialize(&reply_pkt, data, &len);
+			smux_rx_state_machine(data, len, 0);
+			break;
+
+		case SMUX_CMD_CLOSE_LCH:
+			if (pkt->hdr.flags == SMUX_CMD_CLOSE_ACK)
+				break;
+
+			/* Reply with Close ACK */
+			smux_init_pkt(&reply_pkt);
+			reply_pkt.hdr.lcid = lcid;
+			reply_pkt.hdr.cmd = SMUX_CMD_CLOSE_LCH;
+			reply_pkt.hdr.flags = SMUX_CMD_CLOSE_ACK;
+			reply_pkt.hdr.payload_len = 0;
+			reply_pkt.hdr.pad_len = 0;
+			smux_serialize(&reply_pkt, data, &len);
+			smux_rx_state_machine(data, len, 0);
+
+			/* Send Remote Close */
+			smux_init_pkt(&reply_pkt);
+			reply_pkt.hdr.lcid = lcid;
+			reply_pkt.hdr.cmd = SMUX_CMD_CLOSE_LCH;
+			reply_pkt.hdr.flags = 0;
+			reply_pkt.hdr.payload_len = 0;
+			reply_pkt.hdr.pad_len = 0;
+			smux_serialize(&reply_pkt, data, &len);
+			smux_rx_state_machine(data, len, 0);
+			break;
+
+		case SMUX_CMD_DATA:
+			/* Echo back received data */
+			smux_init_pkt(&reply_pkt);
+			reply_pkt.hdr.lcid = lcid;
+			reply_pkt.hdr.cmd = SMUX_CMD_DATA;
+			reply_pkt.hdr.flags = 0;
+			reply_pkt.hdr.payload_len = pkt->hdr.payload_len;
+			reply_pkt.payload = pkt->payload;
+			reply_pkt.hdr.pad_len = pkt->hdr.pad_len;
+			smux_serialize(&reply_pkt, data, &len);
+			smux_rx_state_machine(data, len, 0);
+			break;
+
+		case SMUX_CMD_STATUS:
+			/* Echo back received status */
+			smux_init_pkt(&reply_pkt);
+			reply_pkt.hdr.lcid = lcid;
+			reply_pkt.hdr.cmd = SMUX_CMD_STATUS;
+			reply_pkt.hdr.flags = pkt->hdr.flags;
+			reply_pkt.hdr.payload_len = 0;
+			reply_pkt.payload = NULL;
+			reply_pkt.hdr.pad_len = pkt->hdr.pad_len;
+			smux_serialize(&reply_pkt, data, &len);
+			smux_rx_state_machine(data, len, 0);
+			break;
+
+		case SMUX_CMD_PWR_CTL:
+			/* reply with ack */
+			smux_init_pkt(&reply_pkt);
+			reply_pkt.hdr.lcid = lcid;
+			reply_pkt.hdr.cmd = SMUX_CMD_PWR_CTL;
+			reply_pkt.hdr.flags = SMUX_CMD_PWR_CTL_ACK;
+			reply_pkt.hdr.payload_len = 0;
+			reply_pkt.payload = NULL;
+			reply_pkt.hdr.pad_len = pkt->hdr.pad_len;
+			smux_serialize(&reply_pkt, data, &len);
+			smux_rx_state_machine(data, len, 0);
+			break;
+
+		case SMUX_CMD_BYTE:
+			smux_loopback_rx_byte(pkt);
+			break;
+
+		default:
+			pr_err("%s: unknown command %d\n",
+					__func__, pkt->hdr.cmd);
+			break;
+		};
+
+		smux_free_pkt(pkt);
+		spin_lock_irqsave(&hw_fn_lock, flags);
+	}
+	spin_unlock_irqrestore(&hw_fn_lock, flags);
+	kfree(data);
+}
diff --git a/drivers/tty/smux_loopback.h b/drivers/tty/smux_loopback.h
new file mode 100644
index 0000000..85c6c23
--- /dev/null
+++ b/drivers/tty/smux_loopback.h
@@ -0,0 +1,39 @@
+/* drivers/tty/smux_loopback.h
+ *
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef SMUX_LOOPBACK_H
+#define SMUX_LOOPBACK_H
+
+#include "smux_private.h"
+
+#ifdef CONFIG_N_SMUX_LOOPBACK
+
+int smux_loopback_init(void);
+int smux_tx_loopback(struct smux_pkt_t *pkt_ptr);
+
+#else
+static inline int smux_loopback_init(void)
+{
+	return 0;
+}
+
+static inline int smux_tx_loopback(struct smux_pkt_t *pkt_ptr)
+{
+	return -ENODEV;
+}
+
+
+#endif /* CONFIG_N_SMUX_LOOPBACK */
+#endif /* SMUX_LOOPBACK_H */
+
diff --git a/drivers/tty/smux_private.h b/drivers/tty/smux_private.h
new file mode 100644
index 0000000..2c8819c
--- /dev/null
+++ b/drivers/tty/smux_private.h
@@ -0,0 +1,117 @@
+/* drivers/tty/smux_private.h
+ *
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef SMUX_PRIVATE_H
+#define SMUX_PRIVATE_H
+
+#define SMUX_MAX_PKT_SIZE   8192
+
+/* SMUX Protocol Characters */
+#define SMUX_MAGIC          0x33FC
+#define SMUX_MAGIC_WORD1    0xFC
+#define SMUX_MAGIC_WORD2    0x33
+#define SMUX_WAKEUP_REQ     0xFD
+#define SMUX_WAKEUP_ACK     0xFE
+
+/* Unit testing characters */
+#define SMUX_UT_ECHO_REQ    0xF0
+#define SMUX_UT_ECHO_ACK_OK 0xF1
+#define SMUX_UT_ECHO_ACK_FAIL 0xF2
+
+/* Maximum number of packets in retry queue */
+#define SMUX_RX_RETRY_MAX_PKTS 32
+
+struct tty_struct;
+
+/* Packet header. */
+struct smux_hdr_t {
+	uint16_t magic;
+	uint8_t flags;
+	uint8_t cmd;
+	uint8_t pad_len;
+	uint8_t lcid;
+	uint16_t payload_len;
+};
+
+/* Internal packet structure. */
+struct smux_pkt_t {
+	struct smux_hdr_t hdr;
+	int allocated;
+	unsigned char *payload;
+	int free_payload;
+	struct list_head list;
+	void *priv;
+};
+
+/* SMUX Packet Commands */
+enum {
+	SMUX_CMD_DATA = 0x0,
+	SMUX_CMD_OPEN_LCH = 0x1,
+	SMUX_CMD_CLOSE_LCH = 0x2,
+	SMUX_CMD_STATUS = 0x3,
+	SMUX_CMD_PWR_CTL = 0x4,
+
+	SMUX_CMD_BYTE, /* for internal usage */
+	SMUX_NUM_COMMANDS
+};
+
+/* Open command flags */
+enum {
+	SMUX_CMD_OPEN_ACK = 1 << 0,
+	SMUX_CMD_OPEN_POWER_COLLAPSE = 1 << 1,
+	SMUX_CMD_OPEN_REMOTE_LOOPBACK = 1 << 2,
+};
+
+/* Close command flags */
+enum {
+	SMUX_CMD_CLOSE_ACK = 1 << 0,
+};
+
+/* Power command flags */
+enum {
+	SMUX_CMD_PWR_CTL_ACK =  1 << 0,
+};
+
+/* Local logical channel states */
+enum {
+	SMUX_LCH_LOCAL_CLOSED,
+	SMUX_LCH_LOCAL_OPENING,
+	SMUX_LCH_LOCAL_OPENED,
+	SMUX_LCH_LOCAL_CLOSING,
+};
+
+/* Remote logical channel states */
+enum {
+	SMUX_LCH_REMOTE_CLOSED,
+	SMUX_LCH_REMOTE_OPENED,
+};
+
+
+int smux_assert_lch_id(uint32_t lcid);
+void smux_init_pkt(struct smux_pkt_t *pkt);
+struct smux_pkt_t *smux_alloc_pkt(void);
+int smux_alloc_pkt_payload(struct smux_pkt_t *pkt);
+void smux_free_pkt(struct smux_pkt_t *pkt);
+int smux_serialize(struct smux_pkt_t *pkt, char *out,
+					unsigned int *out_len);
+
+void smux_rx_state_machine(const unsigned char *data, int len, int flag);
+void smuxld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
+			   char *fp, int count);
+
+/* testing parameters */
+extern int smux_byte_loopback;
+extern int smux_simulate_wakeup_delay;
+
+#endif /* SMUX_PRIVATE_H */
diff --git a/drivers/tty/smux_test.c b/drivers/tty/smux_test.c
new file mode 100644
index 0000000..62e9465
--- /dev/null
+++ b/drivers/tty/smux_test.c
@@ -0,0 +1,1639 @@
+/* drivers/tty/smux_test.c
+ *
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/debugfs.h>
+#include <linux/list.h>
+#include <linux/ctype.h>
+#include <linux/jiffies.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/completion.h>
+#include <linux/termios.h>
+#include <linux/smux.h>
+#include "smux_private.h"
+
+#define DEBUG_BUFMAX 4096
+
+/**
+ * Unit test assertion for logging test cases.
+ *
+ * @a lval
+ * @b rval
+ * @cmp comparison operator
+ *
+ * Assertion fails if (@a cmp @b) is not true which then
+ * logs the function and line number where the error occurred
+ * along with the values of @a and @b.
+ *
+ * Assumes that the following local variables exist:
+ * @buf - buffer to write failure message to
+ * @i - number of bytes written to buffer
+ * @max - maximum size of the buffer
+ * @failed - set to true if test fails
+ */
+#define UT_ASSERT_INT(a, cmp, b) \
+	if (!((a)cmp(b))) { \
+		i += scnprintf(buf + i, max - i, \
+			"%s:%d Fail: " #a "(%d) " #cmp " " #b "(%d)\n", \
+				__func__, __LINE__, \
+				a, b); \
+		failed = 1; \
+		break; \
+	} \
+	do {} while (0)
+
+#define UT_ASSERT_PTR(a, cmp, b) \
+	if (!((a)cmp(b))) { \
+		i += scnprintf(buf + i, max - i, \
+			"%s:%d Fail: " #a "(%p) " #cmp " " #b "(%p)\n", \
+				__func__, __LINE__, \
+				a, b); \
+		failed = 1; \
+		break; \
+	} \
+	do {} while (0)
+
+#define UT_ASSERT_UINT(a, cmp, b) \
+	if (!((a)cmp(b))) { \
+		i += scnprintf(buf + i, max - i, \
+			"%s:%d Fail: " #a "(%u) " #cmp " " #b "(%u)\n", \
+				__func__, __LINE__, \
+				a, b); \
+		failed = 1; \
+		break; \
+	} \
+	do {} while (0)
+
+/**
+ * In-range unit test assertion for test cases.
+ *
+ * @a lval
+ * @minv Minimum value
+ * @maxv Maximum value
+ *
+ * Assertion fails if @a is not on the exclusive range minv, maxv
+ * ((@a < @minv) or (@a > @maxv)).  In the failure case, the macro
+ * logs the function and line number where the error occurred along
+ * with the values of @a and @minv, @maxv.
+ *
+ * Assumes that the following local variables exist:
+ * @buf - buffer to write failure message to
+ * @i - number of bytes written to buffer
+ * @max - maximum size of the buffer
+ * @failed - set to true if test fails
+ */
+#define UT_ASSERT_INT_IN_RANGE(a, minv, maxv) \
+	if (((a) < (minv)) || ((a) > (maxv))) { \
+		i += scnprintf(buf + i, max - i, \
+			"%s:%d Fail: " #a "(%d) < " #minv "(%d) or " \
+				 #a "(%d) > " #maxv "(%d)\n", \
+				__func__, __LINE__, \
+				a, minv, a, maxv); \
+		failed = 1; \
+		break; \
+	} \
+	do {} while (0)
+
+
+static unsigned char test_array[] = {1, 1, 2, 3, 5, 8, 13, 21, 34, 55,
+					89, 144, 233};
+
+/* when 1, forces failure of get_rx_buffer_mock function */
+static int get_rx_buffer_mock_fail;
+
+
+/* Used for mapping local to remote TIOCM signals */
+struct tiocm_test_vector {
+	uint32_t input;
+	uint32_t set_old;
+	uint32_t set_new;
+	uint32_t clr_old;
+};
+
+/**
+ * Allocates a new buffer for SMUX for every call.
+ */
+int get_rx_buffer(void *priv, void **pkt_priv, void **buffer, int size)
+{
+	void *rx_buf;
+
+	rx_buf = kmalloc(size, GFP_KERNEL);
+	*pkt_priv = (void *)0x1234;
+	*buffer = rx_buf;
+
+	return 0;
+}
+
+/* Test vector for packet tests. */
+struct test_vector {
+	const char *data;
+	const unsigned len;
+};
+
+/* Mock object metadata for SMUX_READ_DONE event */
+struct mock_read_event {
+	struct list_head list;
+	struct smux_meta_read meta;
+};
+
+/* Mock object metadata for SMUX_WRITE_DONE event */
+struct mock_write_event {
+	struct list_head list;
+	struct smux_meta_write meta;
+};
+
+/* Mock object metadata for get_rx_buffer failure event */
+struct mock_get_rx_buff_event {
+	struct list_head list;
+	int size;
+	unsigned long jiffies;
+};
+
+/* Mock object for all SMUX callback events */
+struct smux_mock_callback {
+	int cb_count;
+	struct completion cb_completion;
+	spinlock_t lock;
+
+	/* status changes */
+	int event_connected;
+	int event_disconnected;
+	int event_disconnected_ssr;
+	int event_low_wm;
+	int event_high_wm;
+
+	/* TIOCM changes */
+	int event_tiocm;
+	struct smux_meta_tiocm tiocm_meta;
+
+	/* read event data */
+	int event_read_done;
+	int event_read_failed;
+	struct list_head read_events;
+
+	/* read retry data */
+	int get_rx_buff_retry_count;
+	struct list_head get_rx_buff_retry_events;
+
+	/* write event data */
+	int event_write_done;
+	int event_write_failed;
+	struct list_head write_events;
+};
+
+/**
+ * Initialize mock callback data. Only call once.
+ *
+ * @cb  Mock callback data
+ */
+void mock_cb_data_init(struct smux_mock_callback *cb)
+{
+	init_completion(&cb->cb_completion);
+	spin_lock_init(&cb->lock);
+	INIT_LIST_HEAD(&cb->read_events);
+	INIT_LIST_HEAD(&cb->get_rx_buff_retry_events);
+	INIT_LIST_HEAD(&cb->write_events);
+}
+
+/**
+ * Reset mock callback data to default values.
+ *
+ * @cb  Mock callback data
+ *
+ * All packets are freed and counters reset to zero.
+ */
+void mock_cb_data_reset(struct smux_mock_callback *cb)
+{
+	cb->cb_count = 0;
+	INIT_COMPLETION(cb->cb_completion);
+	cb->event_connected = 0;
+	cb->event_disconnected = 0;
+	cb->event_disconnected_ssr = 0;
+	cb->event_low_wm = 0;
+	cb->event_high_wm = 0;
+	cb->event_tiocm = 0;
+	cb->tiocm_meta.tiocm_old = 0;
+	cb->tiocm_meta.tiocm_new = 0;
+
+	cb->event_read_done = 0;
+	cb->event_read_failed = 0;
+	while (!list_empty(&cb->read_events)) {
+		struct mock_read_event *meta;
+		meta = list_first_entry(&cb->read_events,
+				struct mock_read_event,
+				list);
+		kfree(meta->meta.buffer);
+		list_del(&meta->list);
+		kfree(meta);
+	}
+
+	cb->get_rx_buff_retry_count = 0;
+	while (!list_empty(&cb->get_rx_buff_retry_events)) {
+		struct mock_get_rx_buff_event *meta;
+		meta = list_first_entry(&cb->get_rx_buff_retry_events,
+				struct mock_get_rx_buff_event,
+				list);
+		list_del(&meta->list);
+		kfree(meta);
+	}
+
+	cb->event_write_done = 0;
+	cb->event_write_failed = 0;
+	while (!list_empty(&cb->write_events)) {
+		struct mock_write_event *meta;
+		meta = list_first_entry(&cb->write_events,
+				struct mock_write_event,
+				list);
+		list_del(&meta->list);
+		kfree(meta);
+	}
+}
+
+/**
+ * Dump the values of the mock callback data for debug purposes.
+ *
+ * @cb  Mock callback data
+ * @buf Print buffer
+ * @max Maximum number of characters to print
+ *
+ * @returns Number of characters added to buffer
+ */
+static int mock_cb_data_print(const struct smux_mock_callback *cb,
+		char *buf, int max)
+{
+	int i = 0;
+
+	i += scnprintf(buf + i, max - i,
+		"\tcb_count=%d\n"
+		"\tcb_completion.done=%d\n"
+		"\tevent_connected=%d\n"
+		"\tevent_disconnected=%d\n"
+		"\tevent_disconnected_ssr=%d\n"
+		"\tevent_low_wm=%d\n"
+		"\tevent_high_wm=%d\n"
+		"\tevent_tiocm=%d\n"
+		"\tevent_read_done=%d\n"
+		"\tevent_read_failed=%d\n"
+		"\tread_events=%d\n"
+		"\tget_rx_retry=%d\n"
+		"\tget_rx_retry_events=%d\n"
+		"\tevent_write_done=%d\n"
+		"\tevent_write_failed=%d\n"
+		"\twrite_events=%d\n",
+		cb->cb_count,
+		cb->cb_completion.done,
+		cb->event_connected,
+		cb->event_disconnected,
+		cb->event_disconnected_ssr,
+		cb->event_low_wm,
+		cb->event_high_wm,
+		cb->event_tiocm,
+		cb->event_read_done,
+		cb->event_read_failed,
+		!list_empty(&cb->read_events),
+		cb->get_rx_buff_retry_count,
+		!list_empty(&cb->get_rx_buff_retry_events),
+		cb->event_write_done,
+		cb->event_write_failed,
+		list_empty(&cb->write_events)
+		);
+
+	return i;
+}
+
+/**
+ * Mock object event callback.  Used to logs events for analysis in the unit
+ * tests.
+ */
+void smux_mock_cb(void *priv, int event, const void *metadata)
+{
+	struct smux_mock_callback *cb_data_ptr;
+	struct mock_write_event *write_event_meta;
+	struct mock_read_event *read_event_meta;
+	unsigned long flags;
+
+	cb_data_ptr = (struct smux_mock_callback *)priv;
+	if (cb_data_ptr == NULL) {
+		pr_err("%s: invalid private data\n", __func__);
+		return;
+	}
+
+	switch (event) {
+	case SMUX_CONNECTED:
+		spin_lock_irqsave(&cb_data_ptr->lock, flags);
+		++cb_data_ptr->event_connected;
+		spin_unlock_irqrestore(&cb_data_ptr->lock, flags);
+		break;
+
+	case SMUX_DISCONNECTED:
+		spin_lock_irqsave(&cb_data_ptr->lock, flags);
+		++cb_data_ptr->event_disconnected;
+		cb_data_ptr->event_disconnected_ssr =
+			((struct smux_meta_disconnected *)metadata)->is_ssr;
+		spin_unlock_irqrestore(&cb_data_ptr->lock, flags);
+		break;
+
+	case SMUX_READ_DONE:
+		read_event_meta = kmalloc(sizeof(struct mock_read_event),
+						GFP_KERNEL);
+		spin_lock_irqsave(&cb_data_ptr->lock, flags);
+		++cb_data_ptr->event_read_done;
+		if (read_event_meta) {
+			read_event_meta->meta =
+				*(struct smux_meta_read *)metadata;
+			list_add_tail(&read_event_meta->list,
+						&cb_data_ptr->read_events);
+		}
+		spin_unlock_irqrestore(&cb_data_ptr->lock, flags);
+		break;
+
+	case SMUX_READ_FAIL:
+		read_event_meta = kmalloc(sizeof(struct mock_read_event),
+						GFP_KERNEL);
+		spin_lock_irqsave(&cb_data_ptr->lock, flags);
+		++cb_data_ptr->event_read_failed;
+		if (read_event_meta) {
+			if (metadata)
+				read_event_meta->meta =
+					*(struct smux_meta_read *)metadata;
+			else
+				memset(&read_event_meta->meta, 0x0,
+						sizeof(struct smux_meta_read));
+			list_add_tail(&read_event_meta->list,
+					&cb_data_ptr->read_events);
+		}
+		spin_unlock_irqrestore(&cb_data_ptr->lock, flags);
+		break;
+
+	case SMUX_WRITE_DONE:
+		write_event_meta = kmalloc(sizeof(struct mock_write_event),
+						GFP_KERNEL);
+		spin_lock_irqsave(&cb_data_ptr->lock, flags);
+		++cb_data_ptr->event_write_done;
+		if (write_event_meta) {
+			write_event_meta->meta =
+					*(struct smux_meta_write *)metadata;
+			list_add_tail(&write_event_meta->list,
+					&cb_data_ptr->write_events);
+		}
+		spin_unlock_irqrestore(&cb_data_ptr->lock, flags);
+		break;
+
+	case SMUX_WRITE_FAIL:
+		write_event_meta = kmalloc(sizeof(struct mock_write_event),
+						GFP_KERNEL);
+		spin_lock_irqsave(&cb_data_ptr->lock, flags);
+		++cb_data_ptr->event_write_failed;
+		if (write_event_meta) {
+			write_event_meta->meta =
+				*(struct smux_meta_write *)metadata;
+			list_add_tail(&write_event_meta->list,
+					&cb_data_ptr->write_events);
+		}
+		spin_unlock_irqrestore(&cb_data_ptr->lock, flags);
+		break;
+
+	case SMUX_LOW_WM_HIT:
+		spin_lock_irqsave(&cb_data_ptr->lock, flags);
+		++cb_data_ptr->event_low_wm;
+		spin_unlock_irqrestore(&cb_data_ptr->lock, flags);
+		break;
+
+	case SMUX_HIGH_WM_HIT:
+		spin_lock_irqsave(&cb_data_ptr->lock, flags);
+		++cb_data_ptr->event_high_wm;
+		spin_unlock_irqrestore(&cb_data_ptr->lock, flags);
+		break;
+
+	case SMUX_TIOCM_UPDATE:
+		spin_lock_irqsave(&cb_data_ptr->lock, flags);
+		++cb_data_ptr->event_tiocm;
+		cb_data_ptr->tiocm_meta = *(struct smux_meta_tiocm *)metadata;
+		spin_unlock_irqrestore(&cb_data_ptr->lock, flags);
+		break;
+
+	default:
+		pr_err("%s: unknown event %d\n", __func__, event);
+	};
+
+	spin_lock_irqsave(&cb_data_ptr->lock, flags);
+	++cb_data_ptr->cb_count;
+	complete(&cb_data_ptr->cb_completion);
+	spin_unlock_irqrestore(&cb_data_ptr->lock, flags);
+}
+
+/**
+ * Test Read/write usage.
+ *
+ * @buf       Output buffer for failure/status messages
+ * @max       Size of @buf
+ * @vectors   Test vector data (must end with NULL item)
+ * @name      Name of the test case for failure messages
+ *
+ * Perform a sanity test consisting of opening a port, writing test packet(s),
+ * reading the response(s), and closing the port.
+ *
+ * The port should already be configured to use either local or remote
+ * loopback.
+ */
+static int smux_ut_basic_core(char *buf, int max,
+	const struct test_vector *vectors,
+	const char *name)
+{
+	int i = 0;
+	int failed = 0;
+	static struct smux_mock_callback cb_data;
+	static int cb_initialized;
+	int ret;
+
+	if (!cb_initialized)
+		mock_cb_data_init(&cb_data);
+
+	mock_cb_data_reset(&cb_data);
+	while (!failed) {
+		struct mock_write_event *write_event;
+		struct mock_read_event *read_event;
+
+		/* open port */
+		ret = msm_smux_open(SMUX_TEST_LCID, &cb_data, smux_mock_cb,
+					get_rx_buffer);
+		UT_ASSERT_INT(ret, ==, 0);
+		UT_ASSERT_INT(
+			(int)wait_for_completion_timeout(
+					&cb_data.cb_completion, HZ), >, 0);
+		UT_ASSERT_INT(cb_data.cb_count, ==, 1);
+		UT_ASSERT_INT(cb_data.event_connected, ==, 1);
+		mock_cb_data_reset(&cb_data);
+
+		/* write, read, and verify the test vector data */
+		for (; vectors->data != NULL; ++vectors) {
+			const char *test_data = vectors->data;
+			const unsigned test_len = vectors->len;
+
+			i += scnprintf(buf + i, max - i,
+					"Writing vector %p len %d\n",
+					test_data, test_len);
+
+			/* write data */
+			msm_smux_write(SMUX_TEST_LCID, (void *)0xCAFEFACE,
+					test_data, test_len);
+			UT_ASSERT_INT(ret, ==, 0);
+			UT_ASSERT_INT(
+					(int)wait_for_completion_timeout(
+					&cb_data.cb_completion, HZ), >, 0);
+
+			/* wait for write and echo'd read to complete */
+			INIT_COMPLETION(cb_data.cb_completion);
+			if (cb_data.cb_count < 2)
+				UT_ASSERT_INT(
+					(int)wait_for_completion_timeout(
+						&cb_data.cb_completion, HZ),
+					>, 0);
+
+			UT_ASSERT_INT(cb_data.cb_count, >=, 1);
+			UT_ASSERT_INT(cb_data.event_write_done, ==, 1);
+			UT_ASSERT_INT(list_empty(&cb_data.write_events), ==, 0);
+
+			write_event = list_first_entry(&cb_data.write_events,
+					struct mock_write_event, list);
+			UT_ASSERT_PTR(write_event->meta.pkt_priv, ==,
+							(void *)0xCAFEFACE);
+			UT_ASSERT_PTR(write_event->meta.buffer, ==,
+							(void *)test_data);
+			UT_ASSERT_INT(write_event->meta.len, ==, test_len);
+
+			/* verify read event */
+			UT_ASSERT_INT(cb_data.event_read_done, ==, 1);
+			UT_ASSERT_INT(list_empty(&cb_data.read_events), ==, 0);
+			read_event = list_first_entry(&cb_data.read_events,
+					struct mock_read_event, list);
+			UT_ASSERT_PTR(read_event->meta.pkt_priv, ==,
+							(void *)0x1234);
+			UT_ASSERT_PTR(read_event->meta.buffer, !=, NULL);
+
+			if (read_event->meta.len != test_len ||
+				memcmp(read_event->meta.buffer,
+						test_data, test_len)) {
+				/* data mismatch */
+				char linebuff[80];
+
+				hex_dump_to_buffer(test_data, test_len,
+					16, 1, linebuff, sizeof(linebuff), 1);
+				i += scnprintf(buf + i, max - i,
+						"Expected:\n%s\n\n", linebuff);
+
+				hex_dump_to_buffer(read_event->meta.buffer,
+					read_event->meta.len,
+					16, 1, linebuff, sizeof(linebuff), 1);
+				i += scnprintf(buf + i, max - i,
+						"Actual:\n%s\n", linebuff);
+				failed = 1;
+				break;
+			}
+			mock_cb_data_reset(&cb_data);
+		}
+
+		/* close port */
+		ret = msm_smux_close(SMUX_TEST_LCID);
+		UT_ASSERT_INT(ret, ==, 0);
+		UT_ASSERT_INT(
+			(int)wait_for_completion_timeout(
+				&cb_data.cb_completion, HZ),
+			>, 0);
+		UT_ASSERT_INT(cb_data.cb_count, ==, 1);
+		UT_ASSERT_INT(cb_data.event_disconnected, ==, 1);
+		UT_ASSERT_INT(cb_data.event_disconnected_ssr, ==, 0);
+		break;
+	}
+
+	if (!failed) {
+		i += scnprintf(buf + i, max - i, "\tOK\n");
+	} else {
+		pr_err("%s: Failed\n", name);
+		i += scnprintf(buf + i, max - i, "\tFailed\n");
+		i += mock_cb_data_print(&cb_data, buf + i, max - i);
+		msm_smux_close(SMUX_TEST_LCID);
+	}
+
+	mock_cb_data_reset(&cb_data);
+	return i;
+}
+
+/**
+ * Verify Basic Local Loopback Support
+ *
+ * Perform a sanity test consisting of opening a port in local loopback
+ * mode and writing a packet and reading the echo'd packet back.
+ */
+static int smux_ut_basic(char *buf, int max)
+{
+	const struct test_vector test_data[] = {
+		{"hello\0world\n", sizeof("hello\0world\n")},
+		{0, 0},
+	};
+	int i = 0;
+	int failed = 0;
+	int ret;
+
+	i += scnprintf(buf + i, max - i, "Running %s\n", __func__);
+	while (!failed) {
+		/* enable loopback mode */
+		ret = msm_smux_set_ch_option(SMUX_TEST_LCID,
+				SMUX_CH_OPTION_LOCAL_LOOPBACK, 0);
+		UT_ASSERT_INT(ret, ==, 0);
+
+		i += smux_ut_basic_core(buf + i, max - i, test_data, __func__);
+		break;
+	}
+
+	if (failed) {
+		pr_err("%s: Failed\n", __func__);
+		i += scnprintf(buf + i, max - i, "\tFailed\n");
+	}
+	return i;
+}
+
+/**
+ * Verify Basic Remote Loopback Support
+ *
+ * Perform a sanity test consisting of opening a port in remote loopback
+ * mode and writing a packet and reading the echo'd packet back.
+ */
+static int smux_ut_remote_basic(char *buf, int max)
+{
+	const struct test_vector test_data[] = {
+		{"hello\0world\n", sizeof("hello\0world\n")},
+		{0, 0},
+	};
+	int i = 0;
+	int failed = 0;
+	int ret;
+
+	i += scnprintf(buf + i, max - i, "Running %s\n", __func__);
+	while (!failed) {
+		/* enable remote mode */
+		ret = msm_smux_set_ch_option(SMUX_TEST_LCID,
+				SMUX_CH_OPTION_REMOTE_LOOPBACK, 0);
+		UT_ASSERT_INT(ret, ==, 0);
+
+		i += smux_ut_basic_core(buf + i, max - i, test_data, __func__);
+		break;
+	}
+
+	if (failed) {
+		pr_err("%s: Failed\n", __func__);
+		i += scnprintf(buf + i, max - i, "\tFailed\n");
+	}
+	return i;
+}
+
+/**
+ * Fill test pattern into provided buffer including an optional
+ * redzone 16 bytes before and 16 bytes after the buffer.
+ *
+ * buf ---------
+ *      redzone
+ *     --------- <- returned pointer
+ *       data
+ *     --------- <- returned pointer + len
+ *      redzone
+ *     ---------
+ *
+ * @buf  Pointer to the buffer of size len or len+32 (redzone)
+ * @len  Length of the *data* buffer (excluding 32-byte redzone)
+ * @redzone If true, adds redzone data
+ *
+ * @returns pointer to buffer (buf + 16 if redzone enabled)
+ */
+uint8_t *test_pattern_fill(char *buf, int len, int redzone)
+{
+	void *ret;
+	uint8_t ch;
+
+	ret = buf;
+	if (redzone) {
+		memset((char *)buf, 0xAB, 16);
+		memset((char *)buf + len, 0xBA, 16);
+		ret += 16;
+	}
+
+	/* fill with test pattern */
+	for (ch = 0; len > 0; --len, ++ch)
+		*buf++ = (char)ch;
+
+	return ret;
+}
+
+/**
+ * Verify test pattern generated by test_pattern_fill.
+ *
+ * @buf_ptr    Pointer to buffer pointer
+ * @len        Length of the *data* buffer (excluding 32-byte redzone)
+ * @redzone    If true, verifies redzone and adjusts *buf_ptr
+ * @errmsg     Buffer for error message
+ * @errmsg_max Size of error message buffer
+ *
+ * @returns    0 for success; length of error message otherwise
+ */
+unsigned test_pattern_verify(char **buf_ptr, int len, int redzone,
+					char *errmsg, int errmsg_max)
+{
+	int n;
+	int i = 0;
+	char linebuff[80];
+
+	if (redzone) {
+		*buf_ptr -= 16;
+
+		/* verify prefix redzone */
+		for (n = 0; n < 16; ++n) {
+			if (*buf_ptr[n] != 0xAB) {
+				hex_dump_to_buffer(*buf_ptr, 16,
+					16, 1, linebuff, sizeof(linebuff), 1);
+				i += scnprintf(errmsg + i, errmsg_max - i,
+					"Redzone violation: %s\n", linebuff);
+				break;
+			}
+		}
+
+		/* verify postfix redzone */
+		for (n = 0; n < 16; ++n) {
+			if (*buf_ptr[len + n] != 0xBA) {
+				hex_dump_to_buffer(&(*buf_ptr)[len], 16,
+					16, 1, linebuff, sizeof(linebuff), 1);
+				i += scnprintf(errmsg + i, errmsg_max - i,
+					"Redzone violation: %s\n", linebuff);
+				break;
+			}
+		}
+	}
+	return i;
+}
+
+/**
+ * Write a multiple packets in ascending size and verify packet is received
+ * correctly.
+ *
+ * @buf  Buffer for status message
+ * @max  Size of buffer
+ * @name Name of the test for error reporting
+ *
+ * @returns Number of bytes written to @buf
+ *
+ * Requires that the port already be opened and loopback mode is
+ * configured correctly (if required).
+ */
+static int smux_ut_loopback_big_pkt(char *buf, int max, const char *name)
+{
+	struct test_vector test_data[] = {
+		{0, 64},
+		{0, 128},
+		{0, 256},
+		{0, 512},
+		{0, 1024},
+		{0, 2048},
+		{0, 4096},
+		{0, 0},
+	};
+	int i = 0;
+	int failed = 0;
+	struct test_vector *tv;
+
+	/* generate test data */
+	for (tv = test_data; tv->len > 0; ++tv) {
+		tv->data = kmalloc(tv->len + 32, GFP_KERNEL);
+		pr_err("%s: allocating %p len %d\n",
+				__func__, tv->data, tv->len);
+		if (!tv->data) {
+			i += scnprintf(buf + i, max - i,
+					"%s: Unable to allocate %d bytes\n",
+					__func__, tv->len);
+			failed = 1;
+			goto out;
+		}
+		test_pattern_fill((uint8_t *)tv->data, tv->len, 1);
+	}
+
+	/* run test */
+	i += scnprintf(buf + i, max - i, "Running %s\n", name);
+	while (!failed) {
+		i += smux_ut_basic_core(buf + i, max - i, test_data, name);
+		break;
+	}
+
+out:
+	if (failed) {
+		pr_err("%s: Failed\n", name);
+		i += scnprintf(buf + i, max - i, "\tFailed\n");
+	}
+
+	for (tv = test_data; tv->len > 0; ++tv) {
+		if (!tv->data) {
+			i += test_pattern_verify((char **)&tv->data,
+						tv->len, 1, buf + i, max - i);
+			pr_err("%s: freeing %p len %d\n", __func__,
+							tv->data, tv->len);
+			kfree(tv->data);
+		}
+	}
+
+	return i;
+}
+
+/**
+ * Verify Large-packet Local Loopback Support.
+ *
+ * @buf  Buffer for status message
+ * @max  Size of buffer
+ *
+ * @returns Number of bytes written to @buf
+ *
+ * Open port in local loopback mode and write a multiple packets in ascending
+ * size and verify packet is received correctly.
+ */
+static int smux_ut_local_big_pkt(char *buf, int max)
+{
+	int i = 0;
+	int ret;
+
+	ret = msm_smux_set_ch_option(SMUX_TEST_LCID,
+			SMUX_CH_OPTION_LOCAL_LOOPBACK, 0);
+
+	if (ret == 0) {
+		smux_byte_loopback = SMUX_TEST_LCID;
+		i += smux_ut_loopback_big_pkt(buf, max, __func__);
+		smux_byte_loopback = 0;
+	} else {
+		i += scnprintf(buf + i, max - i,
+				"%s: Unable to set loopback mode\n",
+				__func__);
+	}
+
+	return i;
+}
+
+/**
+ * Verify Large-packet Remote Loopback Support.
+ *
+ * @buf  Buffer for status message
+ * @max  Size of buffer
+ *
+ * @returns Number of bytes written to @buf
+ *
+ * Open port in remote loopback mode and write a multiple packets in ascending
+ * size and verify packet is received correctly.
+ */
+static int smux_ut_remote_big_pkt(char *buf, int max)
+{
+	int i = 0;
+	int ret;
+
+	ret = msm_smux_set_ch_option(SMUX_TEST_LCID,
+			SMUX_CH_OPTION_REMOTE_LOOPBACK, 0);
+	if (ret == 0) {
+		i += smux_ut_loopback_big_pkt(buf, max, __func__);
+	} else {
+		i += scnprintf(buf + i, max - i,
+				"%s: Unable to set loopback mode\n",
+				__func__);
+	}
+
+	return i;
+}
+
+/**
+ * Verify set and get operations for each TIOCM bit.
+ *
+ * @buf  Buffer for status message
+ * @max  Size of buffer
+ * @name Name of the test for error reporting
+ *
+ * @returns Number of bytes written to @buf
+ */
+static int smux_ut_tiocm(char *buf, int max, const char *name)
+{
+	static struct smux_mock_callback cb_data;
+	static int cb_initialized;
+	static const struct tiocm_test_vector tiocm_vectors[] = {
+		/* bit to set, set old, set new, clear old */
+		{TIOCM_DTR, TIOCM_DTR, TIOCM_DTR | TIOCM_DSR, TIOCM_DSR},
+		{TIOCM_RTS, TIOCM_RTS, TIOCM_RTS | TIOCM_CTS, TIOCM_CTS},
+		{TIOCM_RI, 0x0, TIOCM_RI, TIOCM_RI},
+		{TIOCM_CD, 0x0, TIOCM_CD, TIOCM_CD},
+	};
+	int i = 0;
+	int failed = 0;
+	int n;
+	int ret;
+
+	i += scnprintf(buf + i, max - i, "Running %s\n", name);
+
+	if (!cb_initialized)
+		mock_cb_data_init(&cb_data);
+
+	mock_cb_data_reset(&cb_data);
+	while (!failed) {
+		/* open port */
+		ret = msm_smux_open(SMUX_TEST_LCID, &cb_data, smux_mock_cb,
+								get_rx_buffer);
+		UT_ASSERT_INT(ret, ==, 0);
+		UT_ASSERT_INT(
+				(int)wait_for_completion_timeout(
+					&cb_data.cb_completion, HZ), >, 0);
+		UT_ASSERT_INT(cb_data.cb_count, ==, 1);
+		UT_ASSERT_INT(cb_data.event_connected, ==, 1);
+		mock_cb_data_reset(&cb_data);
+
+		/* set and clear each TIOCM bit */
+		for (n = 0; n < ARRAY_SIZE(tiocm_vectors) && !failed; ++n) {
+			/* set signal and verify */
+			ret = msm_smux_tiocm_set(SMUX_TEST_LCID,
+						tiocm_vectors[n].input, 0x0);
+			UT_ASSERT_INT(ret, ==, 0);
+			UT_ASSERT_INT(
+				(int)wait_for_completion_timeout(
+					&cb_data.cb_completion, HZ), >, 0);
+			UT_ASSERT_INT(cb_data.cb_count, ==, 1);
+			UT_ASSERT_INT(cb_data.event_tiocm, ==, 1);
+			UT_ASSERT_INT(cb_data.tiocm_meta.tiocm_old, ==,
+						tiocm_vectors[n].set_old);
+			UT_ASSERT_INT(cb_data.tiocm_meta.tiocm_new, ==,
+						tiocm_vectors[n].set_new);
+			mock_cb_data_reset(&cb_data);
+
+			/* clear signal and verify */
+			ret = msm_smux_tiocm_set(SMUX_TEST_LCID, 0x0,
+						tiocm_vectors[n].input);
+			UT_ASSERT_INT(ret, ==, 0);
+			UT_ASSERT_INT(
+				(int)wait_for_completion_timeout(
+					&cb_data.cb_completion, HZ),
+				>, 0);
+			UT_ASSERT_INT(cb_data.cb_count, ==, 1);
+			UT_ASSERT_INT(cb_data.event_tiocm, ==, 1);
+			UT_ASSERT_INT(cb_data.tiocm_meta.tiocm_old, ==,
+						tiocm_vectors[n].clr_old);
+			UT_ASSERT_INT(cb_data.tiocm_meta.tiocm_new, ==, 0x0);
+			mock_cb_data_reset(&cb_data);
+		}
+		if (failed)
+			break;
+
+		/* close port */
+		ret = msm_smux_close(SMUX_TEST_LCID);
+		UT_ASSERT_INT(ret, ==, 0);
+		UT_ASSERT_INT(
+			(int)wait_for_completion_timeout(
+				&cb_data.cb_completion, HZ),
+			>, 0);
+		UT_ASSERT_INT(cb_data.cb_count, ==, 1);
+		UT_ASSERT_INT(cb_data.event_disconnected, ==, 1);
+		UT_ASSERT_INT(cb_data.event_disconnected_ssr, ==, 0);
+		break;
+	}
+
+	if (!failed) {
+		i += scnprintf(buf + i, max - i, "\tOK\n");
+	} else {
+		pr_err("%s: Failed\n", name);
+		i += scnprintf(buf + i, max - i, "\tFailed\n");
+		i += mock_cb_data_print(&cb_data, buf + i, max - i);
+		msm_smux_close(SMUX_TEST_LCID);
+	}
+
+	mock_cb_data_reset(&cb_data);
+	return i;
+}
+
+/**
+ * Verify TIOCM Status Bits for local loopback.
+ *
+ * @buf  Buffer for status message
+ * @max  Size of buffer
+ *
+ * @returns Number of bytes written to @buf
+ */
+static int smux_ut_local_tiocm(char *buf, int max)
+{
+	int i = 0;
+	int ret;
+
+	ret = msm_smux_set_ch_option(SMUX_TEST_LCID,
+			SMUX_CH_OPTION_LOCAL_LOOPBACK, 0);
+
+	if (ret == 0) {
+		smux_byte_loopback = SMUX_TEST_LCID;
+		i += smux_ut_tiocm(buf, max, __func__);
+		smux_byte_loopback = 0;
+	} else {
+		i += scnprintf(buf + i, max - i,
+				"%s: Unable to set loopback mode\n",
+				__func__);
+	}
+
+	return i;
+}
+
+/**
+ * Verify TIOCM Status Bits for remote loopback.
+ *
+ * @buf  Buffer for status message
+ * @max  Size of buffer
+ *
+ * @returns Number of bytes written to @buf
+ */
+static int smux_ut_remote_tiocm(char *buf, int max)
+{
+	int i = 0;
+	int ret;
+
+	ret = msm_smux_set_ch_option(SMUX_TEST_LCID,
+			SMUX_CH_OPTION_REMOTE_LOOPBACK, 0);
+	if (ret == 0) {
+		i += smux_ut_tiocm(buf, max, __func__);
+	} else {
+		i += scnprintf(buf + i, max - i,
+				"%s: Unable to set loopback mode\n",
+				__func__);
+	}
+
+	return i;
+}
+
+/**
+ * Verify High/Low Watermark notifications.
+ *
+ * @buf  Buffer for status message
+ * @max  Size of buffer
+ *
+ * @returns Number of bytes written to @buf
+ */
+static int smux_ut_local_wm(char *buf, int max)
+{
+	static struct smux_mock_callback cb_data;
+	static int cb_initialized;
+	int i = 0;
+	int failed = 0;
+	int ret;
+
+	i += scnprintf(buf + i, max - i, "Running %s\n", __func__);
+	pr_err("%s", buf);
+
+	if (!cb_initialized)
+		mock_cb_data_init(&cb_data);
+
+	mock_cb_data_reset(&cb_data);
+	smux_byte_loopback = SMUX_TEST_LCID;
+	while (!failed) {
+		/* open port for loopback with TX disabled */
+		ret = msm_smux_set_ch_option(SMUX_TEST_LCID,
+				SMUX_CH_OPTION_LOCAL_LOOPBACK
+				| SMUX_CH_OPTION_REMOTE_TX_STOP,
+				0);
+		UT_ASSERT_INT(ret, ==, 0);
+
+		ret = msm_smux_open(SMUX_TEST_LCID, &cb_data, smux_mock_cb,
+								get_rx_buffer);
+		UT_ASSERT_INT(ret, ==, 0);
+		UT_ASSERT_INT(
+				(int)wait_for_completion_timeout(
+					&cb_data.cb_completion, HZ), >, 0);
+		UT_ASSERT_INT(cb_data.cb_count, ==, 1);
+		UT_ASSERT_INT(cb_data.event_connected, ==, 1);
+		mock_cb_data_reset(&cb_data);
+
+		/* transmit 4 packets and verify high-watermark notification */
+		ret = 0;
+		ret |= msm_smux_write(SMUX_TEST_LCID, (void *)1,
+					test_array, sizeof(test_array));
+		ret |= msm_smux_write(SMUX_TEST_LCID, (void *)2,
+					test_array, sizeof(test_array));
+		ret |= msm_smux_write(SMUX_TEST_LCID, (void *)3,
+					test_array, sizeof(test_array));
+		UT_ASSERT_INT(ret, ==, 0);
+		UT_ASSERT_INT(cb_data.cb_count, ==, 0);
+		UT_ASSERT_INT(cb_data.event_high_wm, ==, 0);
+
+		ret = msm_smux_write(SMUX_TEST_LCID, (void *)4,
+					test_array, sizeof(test_array));
+		UT_ASSERT_INT(ret, ==, 0);
+		UT_ASSERT_INT(
+			(int)wait_for_completion_timeout(
+				&cb_data.cb_completion, HZ),
+			>, 0);
+		UT_ASSERT_INT(cb_data.event_high_wm, ==, 1);
+		UT_ASSERT_INT(cb_data.event_low_wm, ==, 0);
+		mock_cb_data_reset(&cb_data);
+
+		/* exceed watermark and verify failure return value */
+		ret = msm_smux_write(SMUX_TEST_LCID, (void *)5,
+					test_array, sizeof(test_array));
+		UT_ASSERT_INT(ret, ==, -EAGAIN);
+
+		/* re-enable TX and verify low-watermark notification */
+		ret = msm_smux_set_ch_option(SMUX_TEST_LCID,
+				0, SMUX_CH_OPTION_REMOTE_TX_STOP);
+		UT_ASSERT_INT(ret, ==, 0);
+		while (cb_data.cb_count < 9) {
+			UT_ASSERT_INT(
+				(int)wait_for_completion_timeout(
+					&cb_data.cb_completion, HZ),
+				>, 0);
+			INIT_COMPLETION(cb_data.cb_completion);
+		}
+		if (failed)
+			break;
+
+		UT_ASSERT_INT(cb_data.event_high_wm, ==, 0);
+		UT_ASSERT_INT(cb_data.event_low_wm, ==, 1);
+		UT_ASSERT_INT(cb_data.event_write_done, ==, 4);
+		mock_cb_data_reset(&cb_data);
+
+		/* close port */
+		ret = msm_smux_close(SMUX_TEST_LCID);
+		UT_ASSERT_INT(ret, ==, 0);
+		UT_ASSERT_INT(
+			(int)wait_for_completion_timeout(
+				&cb_data.cb_completion, HZ),
+			>, 0);
+		UT_ASSERT_INT(cb_data.cb_count, ==, 1);
+		UT_ASSERT_INT(cb_data.event_disconnected, ==, 1);
+		UT_ASSERT_INT(cb_data.event_disconnected_ssr, ==, 0);
+		break;
+	}
+
+	if (!failed) {
+		i += scnprintf(buf + i, max - i, "\tOK\n");
+	} else {
+		pr_err("%s: Failed\n", __func__);
+		i += scnprintf(buf + i, max - i, "\tFailed\n");
+		i += mock_cb_data_print(&cb_data, buf + i, max - i);
+		msm_smux_close(SMUX_TEST_LCID);
+	}
+	smux_byte_loopback = 0;
+	mock_cb_data_reset(&cb_data);
+	return i;
+}
+
+/**
+ * Verify smuxld_receive_buf regular and error processing.
+ *
+ * @buf  Buffer for status message
+ * @max  Size of buffer
+ *
+ * @returns Number of bytes written to @buf
+ */
+static int smux_ut_local_smuxld_receive_buf(char *buf, int max)
+{
+	static struct smux_mock_callback cb_data;
+	static int cb_initialized;
+	struct mock_read_event *meta;
+	int i = 0;
+	int failed = 0;
+	int ret;
+	char data[] = {SMUX_UT_ECHO_REQ,
+		SMUX_UT_ECHO_REQ, SMUX_UT_ECHO_REQ,
+	};
+	char flags[] = {0x0, 0x1, 0x0,};
+
+
+	i += scnprintf(buf + i, max - i, "Running %s\n", __func__);
+
+	if (!cb_initialized)
+		mock_cb_data_init(&cb_data);
+
+	mock_cb_data_reset(&cb_data);
+	smux_byte_loopback = SMUX_TEST_LCID;
+	while (!failed) {
+		/* open port for loopback */
+		ret = msm_smux_set_ch_option(SMUX_TEST_LCID,
+				SMUX_CH_OPTION_LOCAL_LOOPBACK, 0);
+		UT_ASSERT_INT(ret, ==, 0);
+
+		ret = msm_smux_open(SMUX_TEST_LCID, &cb_data, smux_mock_cb,
+								get_rx_buffer);
+		UT_ASSERT_INT(ret, ==, 0);
+		UT_ASSERT_INT(
+				(int)wait_for_completion_timeout(
+					&cb_data.cb_completion, HZ), >, 0);
+		UT_ASSERT_INT(cb_data.cb_count, ==, 1);
+		UT_ASSERT_INT(cb_data.event_connected, ==, 1);
+		mock_cb_data_reset(&cb_data);
+
+		/*
+		 * Verify RX error processing by sending 3 echo requests:
+		 *     one OK, one fail, and a final OK
+		 *
+		 * The parsing framework should process the requests
+		 * and send us three BYTE command packets with
+		 * ECHO ACK FAIL and ECHO ACK OK characters.
+		 */
+		smuxld_receive_buf(0, data, flags, sizeof(data));
+
+		/* verify response characters */
+		do {
+			UT_ASSERT_INT(
+				(int)wait_for_completion_timeout(
+					&cb_data.cb_completion, HZ), >, 0);
+			INIT_COMPLETION(cb_data.cb_completion);
+		} while (cb_data.cb_count < 3);
+		UT_ASSERT_INT(cb_data.cb_count, ==, 3);
+		UT_ASSERT_INT(cb_data.event_read_done, ==, 3);
+
+		meta = list_first_entry(&cb_data.read_events,
+				struct mock_read_event, list);
+		UT_ASSERT_INT((int)meta->meta.pkt_priv, ==,
+				SMUX_UT_ECHO_ACK_OK);
+		list_del(&meta->list);
+
+		meta = list_first_entry(&cb_data.read_events,
+				struct mock_read_event, list);
+		UT_ASSERT_INT((int)meta->meta.pkt_priv, ==,
+				SMUX_UT_ECHO_ACK_FAIL);
+		list_del(&meta->list);
+
+		meta = list_first_entry(&cb_data.read_events,
+				struct mock_read_event, list);
+		UT_ASSERT_INT((int)meta->meta.pkt_priv, ==,
+				SMUX_UT_ECHO_ACK_OK);
+		list_del(&meta->list);
+		mock_cb_data_reset(&cb_data);
+
+		/* close port */
+		ret = msm_smux_close(SMUX_TEST_LCID);
+		UT_ASSERT_INT(ret, ==, 0);
+		UT_ASSERT_INT(
+			(int)wait_for_completion_timeout(
+				&cb_data.cb_completion, HZ),
+			>, 0);
+		UT_ASSERT_INT(cb_data.cb_count, ==, 1);
+		UT_ASSERT_INT(cb_data.event_disconnected, ==, 1);
+		UT_ASSERT_INT(cb_data.event_disconnected_ssr, ==, 0);
+		break;
+	}
+
+	if (!failed) {
+		i += scnprintf(buf + i, max - i, "\tOK\n");
+	} else {
+		pr_err("%s: Failed\n", __func__);
+		i += scnprintf(buf + i, max - i, "\tFailed\n");
+		i += mock_cb_data_print(&cb_data, buf + i, max - i);
+		msm_smux_close(SMUX_TEST_LCID);
+	}
+	smux_byte_loopback = 0;
+	mock_cb_data_reset(&cb_data);
+	return i;
+}
+
+/**
+ * Allocates a new buffer or returns a failure based upon the
+ * global @get_rx_buffer_mock_fail.
+ */
+static int get_rx_buffer_mock(void *priv, void **pkt_priv,
+		void **buffer, int size)
+{
+	void *rx_buf;
+	unsigned long flags;
+	struct smux_mock_callback *cb_ptr;
+
+	cb_ptr = (struct smux_mock_callback *)priv;
+	if (!cb_ptr) {
+		pr_err("%s: no callback data\n", __func__);
+		return -ENXIO;
+	}
+
+	if (get_rx_buffer_mock_fail) {
+		/* force failure and log failure event */
+		struct mock_get_rx_buff_event *meta;
+		meta = kmalloc(sizeof(struct mock_get_rx_buff_event),
+				GFP_KERNEL);
+		if (!meta) {
+			pr_err("%s: unable to allocate metadata\n", __func__);
+			return -ENOMEM;
+		}
+		INIT_LIST_HEAD(&meta->list);
+		meta->size = size;
+		meta->jiffies = jiffies;
+
+		spin_lock_irqsave(&cb_ptr->lock, flags);
+		++cb_ptr->get_rx_buff_retry_count;
+		list_add_tail(&meta->list, &cb_ptr->get_rx_buff_retry_events);
+		++cb_ptr->cb_count;
+		complete(&cb_ptr->cb_completion);
+		spin_unlock_irqrestore(&cb_ptr->lock, flags);
+		return -EAGAIN;
+	} else {
+		rx_buf = kmalloc(size, GFP_KERNEL);
+		*pkt_priv = (void *)0x1234;
+		*buffer = rx_buf;
+		return 0;
+	}
+	return 0;
+}
+
+/**
+ * Verify get_rx_buffer callback retry.
+ *
+ * @buf  Buffer for status message
+ * @max  Size of buffer
+ *
+ * @returns Number of bytes written to @buf
+ */
+static int smux_ut_local_get_rx_buff_retry(char *buf, int max)
+{
+	static struct smux_mock_callback cb_data;
+	static int cb_initialized;
+	int i = 0;
+	int failed = 0;
+	char try_two[] = "try 2";
+	int ret;
+	unsigned long start_j;
+	struct mock_get_rx_buff_event *event;
+	struct mock_read_event *read_event;
+	int try;
+
+	i += scnprintf(buf + i, max - i, "Running %s\n", __func__);
+	pr_err("%s", buf);
+
+	if (!cb_initialized)
+		mock_cb_data_init(&cb_data);
+
+	mock_cb_data_reset(&cb_data);
+	smux_byte_loopback = SMUX_TEST_LCID;
+	while (!failed) {
+		/* open port for loopback */
+		ret = msm_smux_set_ch_option(SMUX_TEST_LCID,
+				SMUX_CH_OPTION_LOCAL_LOOPBACK,
+				0);
+		UT_ASSERT_INT(ret, ==, 0);
+
+		ret = msm_smux_open(SMUX_TEST_LCID, &cb_data,
+				smux_mock_cb, get_rx_buffer_mock);
+		UT_ASSERT_INT(ret, ==, 0);
+		UT_ASSERT_INT(
+				(int)wait_for_completion_timeout(
+					&cb_data.cb_completion, HZ), >, 0);
+		UT_ASSERT_INT(cb_data.cb_count, ==, 1);
+		UT_ASSERT_INT(cb_data.event_connected, ==, 1);
+		mock_cb_data_reset(&cb_data);
+
+		/*
+		 * Force get_rx_buffer failure for a single RX packet
+		 *
+		 * The get_rx_buffer calls should follow an exponential
+		 * back-off with a maximum timeout of 1024 ms after which we
+		 * will get a failure notification.
+		 *
+		 * Try   Post Delay (ms)
+		 *  0      -
+		 *  1      1
+		 *  2      2
+		 *  3      4
+		 *  4      8
+		 *  5     16
+		 *  6     32
+		 *  7     64
+		 *  8    128
+		 *  9    256
+		 * 10    512
+		 * 11   1024
+		 * 12   Fail
+		 *
+		 * All times are limited by the precision of the timer
+		 * framework, so ranges are used in the test
+		 * verification.
+		 */
+		get_rx_buffer_mock_fail = 1;
+		start_j = jiffies;
+		ret = msm_smux_write(SMUX_TEST_LCID, (void *)1,
+					test_array, sizeof(test_array));
+		UT_ASSERT_INT(ret, ==, 0);
+		ret = msm_smux_write(SMUX_TEST_LCID, (void *)2,
+					try_two, sizeof(try_two));
+		UT_ASSERT_INT(ret, ==, 0);
+
+		/* wait for RX failure event */
+		while (cb_data.event_read_failed == 0) {
+			UT_ASSERT_INT(
+				(int)wait_for_completion_timeout(
+					&cb_data.cb_completion, 2*HZ),
+				>, 0);
+			INIT_COMPLETION(cb_data.cb_completion);
+		}
+		if (failed)
+			break;
+
+		/* verify retry attempts */
+		UT_ASSERT_INT(cb_data.get_rx_buff_retry_count, ==, 12);
+		event = list_first_entry(&cb_data.get_rx_buff_retry_events,
+				struct mock_get_rx_buff_event, list);
+		pr_err("%s: event->jiffies = %d (ms)\n", __func__,
+				jiffies_to_msecs(event->jiffies - start_j));
+		UT_ASSERT_INT_IN_RANGE(
+				jiffies_to_msecs(event->jiffies - start_j),
+				0, 0 + 20);
+		start_j = event->jiffies;
+
+		event = list_first_entry(&event->list,
+				struct mock_get_rx_buff_event, list);
+		pr_err("%s: event->jiffies = %d (ms)\n", __func__,
+				jiffies_to_msecs(event->jiffies - start_j));
+		UT_ASSERT_INT_IN_RANGE(
+				jiffies_to_msecs(event->jiffies - start_j),
+				1, 1 + 20);
+		start_j = event->jiffies;
+
+		event = list_first_entry(&event->list,
+				struct mock_get_rx_buff_event, list);
+		pr_err("%s: event->jiffies = %d (ms)\n", __func__,
+				jiffies_to_msecs(event->jiffies - start_j));
+		UT_ASSERT_INT_IN_RANGE(
+				jiffies_to_msecs(event->jiffies - start_j),
+				2, 2 + 20);
+		start_j = event->jiffies;
+
+		event = list_first_entry(&event->list,
+				struct mock_get_rx_buff_event, list);
+		pr_err("%s: event->jiffies = %d (ms)\n", __func__,
+				jiffies_to_msecs(event->jiffies - start_j));
+		UT_ASSERT_INT_IN_RANGE(
+				jiffies_to_msecs(event->jiffies - start_j),
+				4, 4 + 20);
+		start_j = event->jiffies;
+
+		event = list_first_entry(&event->list,
+				struct mock_get_rx_buff_event, list);
+		pr_err("%s: event->jiffies = %d (ms)\n", __func__,
+				jiffies_to_msecs(event->jiffies - start_j));
+		UT_ASSERT_INT_IN_RANGE(
+				jiffies_to_msecs(event->jiffies - start_j),
+				8, 8 + 20);
+		start_j = event->jiffies;
+
+		event = list_first_entry(&event->list,
+				struct mock_get_rx_buff_event, list);
+		pr_err("%s: event->jiffies = %d (ms)\n", __func__,
+				jiffies_to_msecs(event->jiffies - start_j));
+		UT_ASSERT_INT_IN_RANGE(
+				jiffies_to_msecs(event->jiffies - start_j),
+				16, 16 + 20);
+		start_j = event->jiffies;
+
+		event = list_first_entry(&event->list,
+				struct mock_get_rx_buff_event, list);
+		pr_err("%s: event->jiffies = %d (ms)\n", __func__,
+				jiffies_to_msecs(event->jiffies - start_j));
+		UT_ASSERT_INT_IN_RANGE(
+				jiffies_to_msecs(event->jiffies - start_j),
+				32 - 20, 32 + 20);
+		start_j = event->jiffies;
+
+		event = list_first_entry(&event->list,
+				struct mock_get_rx_buff_event, list);
+		pr_err("%s: event->jiffies = %d (ms)\n", __func__,
+				jiffies_to_msecs(event->jiffies - start_j));
+		UT_ASSERT_INT_IN_RANGE(
+				jiffies_to_msecs(event->jiffies - start_j),
+				64 - 20, 64 + 20);
+		start_j = event->jiffies;
+
+		event = list_first_entry(&event->list,
+				struct mock_get_rx_buff_event, list);
+		pr_err("%s: event->jiffies = %d (ms)\n", __func__,
+				jiffies_to_msecs(event->jiffies - start_j));
+		UT_ASSERT_INT_IN_RANGE(
+				jiffies_to_msecs(event->jiffies - start_j),
+				128 - 20, 128 + 20);
+		start_j = event->jiffies;
+
+		event = list_first_entry(&event->list,
+				struct mock_get_rx_buff_event, list);
+		pr_err("%s: event->jiffies = %d (ms)\n", __func__,
+				jiffies_to_msecs(event->jiffies - start_j));
+		UT_ASSERT_INT_IN_RANGE(
+				jiffies_to_msecs(event->jiffies - start_j),
+				256 - 20, 256 + 20);
+		start_j = event->jiffies;
+
+		event = list_first_entry(&event->list,
+				struct mock_get_rx_buff_event, list);
+		pr_err("%s: event->jiffies = %d (ms)\n", __func__,
+				jiffies_to_msecs(event->jiffies - start_j));
+		UT_ASSERT_INT_IN_RANGE(
+				jiffies_to_msecs(event->jiffies - start_j),
+				512 - 20, 512 + 20);
+		start_j = event->jiffies;
+
+		event = list_first_entry(&event->list,
+				struct mock_get_rx_buff_event, list);
+		pr_err("%s: event->jiffies = %d (ms)\n", __func__,
+				jiffies_to_msecs(event->jiffies - start_j));
+		UT_ASSERT_INT_IN_RANGE(
+				jiffies_to_msecs(event->jiffies - start_j),
+				1024 - 20, 1024 + 20);
+		mock_cb_data_reset(&cb_data);
+
+		/* verify 2nd pending RX packet goes through */
+		get_rx_buffer_mock_fail = 0;
+		INIT_COMPLETION(cb_data.cb_completion);
+		if (cb_data.event_read_done == 0)
+			UT_ASSERT_INT(
+				(int)wait_for_completion_timeout(
+					&cb_data.cb_completion, HZ),
+				>, 0);
+		UT_ASSERT_INT(cb_data.event_read_done, ==, 1);
+		UT_ASSERT_INT(list_empty(&cb_data.read_events), ==, 0);
+		read_event = list_first_entry(&cb_data.read_events,
+				struct mock_read_event, list);
+		UT_ASSERT_PTR(read_event->meta.pkt_priv, ==, (void *)0x1234);
+		UT_ASSERT_PTR(read_event->meta.buffer, !=, NULL);
+		UT_ASSERT_INT(0, ==, memcmp(read_event->meta.buffer, try_two,
+				sizeof(try_two)));
+		mock_cb_data_reset(&cb_data);
+
+		/* Test maximum retry queue size */
+		get_rx_buffer_mock_fail = 1;
+		for (try = 0; try < (SMUX_RX_RETRY_MAX_PKTS + 1); ++try) {
+			mock_cb_data_reset(&cb_data);
+			ret = msm_smux_write(SMUX_TEST_LCID, (void *)1,
+						test_array, sizeof(test_array));
+			UT_ASSERT_INT(ret, ==, 0);
+			UT_ASSERT_INT(
+				(int)wait_for_completion_timeout(
+					&cb_data.cb_completion, HZ),
+				>, 0);
+		}
+
+		/* should have 32 successful rx packets and 1 failed */
+		while (cb_data.event_read_failed == 0) {
+			UT_ASSERT_INT(
+				(int)wait_for_completion_timeout(
+					&cb_data.cb_completion, 2*HZ),
+				>, 0);
+			INIT_COMPLETION(cb_data.cb_completion);
+		}
+		if (failed)
+			break;
+
+		get_rx_buffer_mock_fail = 0;
+		while (cb_data.event_read_done < SMUX_RX_RETRY_MAX_PKTS) {
+			UT_ASSERT_INT(
+				(int)wait_for_completion_timeout(
+					&cb_data.cb_completion, 2*HZ),
+				>, 0);
+			INIT_COMPLETION(cb_data.cb_completion);
+		}
+		if (failed)
+			break;
+
+		UT_ASSERT_INT(1, ==, cb_data.event_read_failed);
+		UT_ASSERT_INT(SMUX_RX_RETRY_MAX_PKTS, ==,
+				cb_data.event_read_done);
+		mock_cb_data_reset(&cb_data);
+
+		/* close port */
+		ret = msm_smux_close(SMUX_TEST_LCID);
+		UT_ASSERT_INT(ret, ==, 0);
+		UT_ASSERT_INT(
+			(int)wait_for_completion_timeout(
+				&cb_data.cb_completion, HZ),
+			>, 0);
+		UT_ASSERT_INT(cb_data.cb_count, ==, 1);
+		UT_ASSERT_INT(cb_data.event_disconnected, ==, 1);
+		UT_ASSERT_INT(cb_data.event_disconnected_ssr, ==, 0);
+		break;
+	}
+
+	if (!failed) {
+		i += scnprintf(buf + i, max - i, "\tOK\n");
+	} else {
+		pr_err("%s: Failed\n", __func__);
+		i += scnprintf(buf + i, max - i, "\tFailed\n");
+		i += mock_cb_data_print(&cb_data, buf + i, max - i);
+		msm_smux_close(SMUX_TEST_LCID);
+	}
+	smux_byte_loopback = 0;
+	mock_cb_data_reset(&cb_data);
+	return i;
+}
+
+static char debug_buffer[DEBUG_BUFMAX];
+
+static ssize_t debug_read(struct file *file, char __user *buf,
+			  size_t count, loff_t *ppos)
+{
+	int (*fill)(char *buf, int max) = file->private_data;
+	int bsize;
+
+	if (*ppos != 0)
+		return 0;
+
+	bsize = fill(debug_buffer, DEBUG_BUFMAX);
+	return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize);
+}
+
+static int debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static const struct file_operations debug_ops = {
+	.read = debug_read,
+	.open = debug_open,
+};
+
+static void debug_create(const char *name, mode_t mode,
+			 struct dentry *dent,
+			 int (*fill)(char *buf, int max))
+{
+	debugfs_create_file(name, mode, dent, fill, &debug_ops);
+}
+
+static int __init smux_debugfs_init(void)
+{
+	struct dentry *dent;
+
+	dent = debugfs_create_dir("n_smux", 0);
+	if (IS_ERR(dent))
+		return PTR_ERR(dent);
+
+	/*
+	 * Add Unit Test entries.
+	 *
+	 * The idea with unit tests is that you can run all of them
+	 * from ADB shell by doing:
+	 *  adb shell
+	 *	cat ut*
+	 *
+	 * And if particular tests fail, you can then repeatedly run the failing
+	 * tests as you debug and resolve the failing test.
+	 */
+	debug_create("ut_local_basic", 0444, dent, smux_ut_basic);
+	debug_create("ut_remote_basic", 0444, dent,	smux_ut_remote_basic);
+	debug_create("ut_local_big_pkt", 0444, dent, smux_ut_local_big_pkt);
+	debug_create("ut_remote_big_pkt", 0444, dent, smux_ut_remote_big_pkt);
+	debug_create("ut_local_tiocm", 0444, dent, smux_ut_local_tiocm);
+	debug_create("ut_remote_tiocm", 0444, dent,	smux_ut_remote_tiocm);
+	debug_create("ut_local_wm", 0444, dent, smux_ut_local_wm);
+	debug_create("ut_local_smuxld_receive_buf", 0444, dent,
+			smux_ut_local_smuxld_receive_buf);
+	debug_create("ut_local_get_rx_buff_retry", 0444, dent,
+			smux_ut_local_get_rx_buff_retry);
+
+	return 0;
+}
+
+late_initcall(smux_debugfs_init);
+
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 1d26d45..37f0799 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -1588,6 +1588,9 @@
 	usbmon_urb_complete(&hcd->self, urb, status);
 	usb_unanchor_urb(urb);
 
+	if (hcd->driver->log_urb_complete)
+		hcd->driver->log_urb_complete(urb, "C", status);
+
 	/* pass ownership to the completion handler */
 	urb->status = status;
 	urb->complete (urb);
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index d74959e..92e95a6 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -61,6 +61,8 @@
 #include "u_rmnet_ctrl_smd.c"
 #include "u_ctrl_hsic.c"
 #include "u_data_hsic.c"
+#include "u_ctrl_hsuart.c"
+#include "u_data_hsuart.c"
 #include "f_serial.c"
 #include "f_acm.c"
 #include "f_adb.c"
@@ -200,7 +202,8 @@
 	u32 swfi_latency = 0;
 	static int last_vote = -1;
 
-	if (!pdata || vote == last_vote)
+	if (!pdata || vote == last_vote
+		|| !pdata->swfi_latency)
 		return;
 
 	swfi_latency = pdata->swfi_latency + 1;
@@ -223,6 +226,7 @@
 	char **uevent_envp = NULL;
 	static enum android_device_state last_uevent, next_state;
 	unsigned long flags;
+	int pm_qos_vote = -1;
 
 	spin_lock_irqsave(&cdev->lock, flags);
 	if (cdev->config) {
@@ -232,13 +236,16 @@
 		uevent_envp = dev->connected ? connected : disconnected;
 		next_state = dev->connected ? USB_CONNECTED : USB_DISCONNECTED;
 		if (dev->connected && strncmp(dev->pm_qos, "low", 3))
-			android_pm_qos_update_latency(dev, 1);
+			pm_qos_vote = 1;
 		else if (!dev->connected || !strncmp(dev->pm_qos, "low", 3))
-			android_pm_qos_update_latency(dev, 0);
+			pm_qos_vote = 0;
 	}
 	dev->sw_connected = dev->connected;
 	spin_unlock_irqrestore(&cdev->lock, flags);
 
+	if (pm_qos_vote != -1)
+		android_pm_qos_update_latency(dev, pm_qos_vote);
+
 	if (uevent_envp) {
 		/*
 		 * Some userspace modules, e.g. MTP, work correctly only if
diff --git a/drivers/usb/gadget/ci13xxx_msm.c b/drivers/usb/gadget/ci13xxx_msm.c
index 863143b..7fd120f 100644
--- a/drivers/usb/gadget/ci13xxx_msm.c
+++ b/drivers/usb/gadget/ci13xxx_msm.c
@@ -16,6 +16,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/usb/msm_hsusb_hw.h>
 #include <linux/usb/ulpi.h>
+#include <mach/gpio.h>
 
 #include "ci13xxx_udc.c"
 
@@ -24,7 +25,11 @@
 struct ci13xxx_udc_context {
 	int irq;
 	void __iomem *regs;
+	int wake_gpio;
+	int wake_irq;
+	bool wake_irq_state;
 };
+
 static struct ci13xxx_udc_context _udc_ctxt;
 
 static irqreturn_t msm_udc_irq(int irq, void *data)
@@ -32,22 +37,71 @@
 	return udc_irq();
 }
 
+static void ci13xxx_msm_suspend(void)
+{
+	struct device *dev = _udc->gadget.dev.parent;
+	dev_dbg(dev, "ci13xxx_msm_suspend\n");
+
+	if (_udc_ctxt.wake_irq && !_udc_ctxt.wake_irq_state) {
+		enable_irq_wake(_udc_ctxt.wake_irq);
+		enable_irq(_udc_ctxt.wake_irq);
+		_udc_ctxt.wake_irq_state = true;
+	}
+}
+
+static void ci13xxx_msm_resume(void)
+{
+	struct device *dev = _udc->gadget.dev.parent;
+	dev_dbg(dev, "ci13xxx_msm_resume\n");
+
+	if (_udc_ctxt.wake_irq && _udc_ctxt.wake_irq_state) {
+		disable_irq_wake(_udc_ctxt.wake_irq);
+		disable_irq(_udc_ctxt.wake_irq);
+		_udc_ctxt.wake_irq_state = false;
+	}
+}
+
 static void ci13xxx_msm_notify_event(struct ci13xxx *udc, unsigned event)
 {
 	struct device *dev = udc->gadget.dev.parent;
 
 	switch (event) {
 	case CI13XXX_CONTROLLER_RESET_EVENT:
-		dev_dbg(dev, "CI13XXX_CONTROLLER_RESET_EVENT received\n");
+		dev_info(dev, "CI13XXX_CONTROLLER_RESET_EVENT received\n");
 		writel(0, USB_AHBBURST);
 		writel_relaxed(0x08, USB_AHBMODE);
 		break;
+	case CI13XXX_CONTROLLER_DISCONNECT_EVENT:
+		dev_info(dev, "CI13XXX_CONTROLLER_DISCONNECT_EVENT received\n");
+		ci13xxx_msm_resume();
+		break;
+	case CI13XXX_CONTROLLER_SUSPEND_EVENT:
+		dev_info(dev, "CI13XXX_CONTROLLER_SUSPEND_EVENT received\n");
+		ci13xxx_msm_suspend();
+		break;
+	case CI13XXX_CONTROLLER_RESUME_EVENT:
+		dev_info(dev, "CI13XXX_CONTROLLER_RESUME_EVENT received\n");
+		ci13xxx_msm_resume();
+		break;
+
 	default:
 		dev_dbg(dev, "unknown ci13xxx_udc event\n");
 		break;
 	}
 }
 
+static irqreturn_t ci13xxx_msm_resume_irq(int irq, void *data)
+{
+	struct ci13xxx *udc = _udc;
+
+	if (udc->transceiver && udc->vbus_active && udc->suspended)
+		otg_set_suspend(udc->transceiver, 0);
+	else if (!udc->suspended)
+		ci13xxx_msm_resume();
+
+	return IRQ_HANDLED;
+}
+
 static struct ci13xxx_udc_driver ci13xxx_msm_udc_driver = {
 	.name			= "ci13xxx_msm",
 	.flags			= CI13XXX_REGS_SHARED |
@@ -60,6 +114,52 @@
 	.notify_event		= ci13xxx_msm_notify_event,
 };
 
+static int ci13xxx_msm_install_wake_gpio(struct platform_device *pdev,
+				struct resource *res)
+{
+	int wake_irq;
+	int ret;
+
+	dev_dbg(&pdev->dev, "ci13xxx_msm_install_wake_gpio\n");
+
+	_udc_ctxt.wake_gpio = res->start;
+	gpio_request(_udc_ctxt.wake_gpio, "USB_RESUME");
+	gpio_direction_input(_udc_ctxt.wake_gpio);
+	wake_irq = MSM_GPIO_TO_INT(_udc_ctxt.wake_gpio);
+	if (wake_irq < 0) {
+		dev_err(&pdev->dev, "could not register USB_RESUME GPIO.\n");
+		return -ENXIO;
+	}
+
+	dev_dbg(&pdev->dev, "_udc_ctxt.gpio_irq = %d and irq = %d\n",
+			_udc_ctxt.wake_gpio, wake_irq);
+	ret = request_irq(wake_irq, ci13xxx_msm_resume_irq,
+		IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "usb resume", NULL);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "could not register USB_RESUME IRQ.\n");
+		goto gpio_free;
+	}
+	disable_irq(wake_irq);
+	_udc_ctxt.wake_irq = wake_irq;
+
+	return 0;
+
+gpio_free:
+	gpio_free(_udc_ctxt.wake_gpio);
+	_udc_ctxt.wake_gpio = 0;
+	return ret;
+}
+
+static void ci13xxx_msm_uninstall_wake_gpio(struct platform_device *pdev)
+{
+	dev_dbg(&pdev->dev, "ci13xxx_msm_uninstall_wake_gpio\n");
+
+	if (_udc_ctxt.wake_gpio) {
+		gpio_free(_udc_ctxt.wake_gpio);
+		_udc_ctxt.wake_gpio = 0;
+	}
+}
+
 static int ci13xxx_msm_probe(struct platform_device *pdev)
 {
 	struct resource *res;
@@ -92,11 +192,20 @@
 		goto udc_remove;
 	}
 
+	res = platform_get_resource_byname(pdev, IORESOURCE_IO, "USB_RESUME");
+	if (res) {
+		ret = ci13xxx_msm_install_wake_gpio(pdev, res);
+		if (ret < 0) {
+			dev_err(&pdev->dev, "gpio irq install failed\n");
+			goto udc_remove;
+		}
+	}
+
 	ret = request_irq(_udc_ctxt.irq, msm_udc_irq, IRQF_SHARED, pdev->name,
 					  pdev);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "request_irq failed\n");
-		goto udc_remove;
+		goto gpio_uninstall;
 	}
 
 	pm_runtime_no_callbacks(&pdev->dev);
@@ -104,6 +213,8 @@
 
 	return 0;
 
+gpio_uninstall:
+	ci13xxx_msm_uninstall_wake_gpio(pdev);
 udc_remove:
 	udc_remove();
 iounmap:
@@ -116,6 +227,7 @@
 {
 	pm_runtime_disable(&pdev->dev);
 	free_irq(_udc_ctxt.irq, pdev);
+	ci13xxx_msm_uninstall_wake_gpio(pdev);
 	udc_remove();
 	iounmap(_udc_ctxt.regs);
 	return 0;
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index b612a0b..a86fc22 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -2005,6 +2005,51 @@
 }
 
 /**
+ * isr_resume_handler: USB PCI interrupt handler
+ * @udc: UDC device
+ *
+ */
+static void isr_resume_handler(struct ci13xxx *udc)
+{
+	udc->gadget.speed = hw_port_is_high_speed() ?
+		USB_SPEED_HIGH : USB_SPEED_FULL;
+	if (udc->suspended) {
+		spin_unlock(udc->lock);
+		if (udc->udc_driver->notify_event)
+			udc->udc_driver->notify_event(udc,
+			  CI13XXX_CONTROLLER_RESUME_EVENT);
+		if (udc->transceiver)
+			otg_set_suspend(udc->transceiver, 0);
+		udc->driver->resume(&udc->gadget);
+		spin_lock(udc->lock);
+		udc->suspended = 0;
+	}
+}
+
+/**
+ * isr_resume_handler: USB SLI interrupt handler
+ * @udc: UDC device
+ *
+ */
+static void isr_suspend_handler(struct ci13xxx *udc)
+{
+	if (udc->gadget.speed != USB_SPEED_UNKNOWN &&
+		udc->vbus_active) {
+		if (udc->suspended == 0) {
+			spin_unlock(udc->lock);
+			udc->driver->suspend(&udc->gadget);
+			if (udc->udc_driver->notify_event)
+				udc->udc_driver->notify_event(udc,
+				CI13XXX_CONTROLLER_SUSPEND_EVENT);
+			if (udc->transceiver)
+				otg_set_suspend(udc->transceiver, 1);
+			spin_lock(udc->lock);
+			udc->suspended = 1;
+		}
+	}
+}
+
+/**
  * isr_get_status_complete: get_status request complete function
  * @ep:  endpoint
  * @req: request handled
@@ -2865,6 +2910,9 @@
 		} else {
 			hw_device_state(0);
 			_gadget_stop_activity(&udc->gadget);
+			if (udc->udc_driver->notify_event)
+				udc->udc_driver->notify_event(udc,
+					CI13XXX_CONTROLLER_DISCONNECT_EVENT);
 			pm_runtime_put_sync(&_gadget->dev);
 		}
 	}
@@ -3174,14 +3222,7 @@
 		}
 		if (USBi_PCI & intr) {
 			isr_statistics.pci++;
-			udc->gadget.speed = hw_port_is_high_speed() ?
-				USB_SPEED_HIGH : USB_SPEED_FULL;
-			if (udc->suspended) {
-				spin_unlock(udc->lock);
-				udc->driver->resume(&udc->gadget);
-				spin_lock(udc->lock);
-				udc->suspended = 0;
-			}
+			isr_resume_handler(udc);
 		}
 		if (USBi_UEI & intr)
 			isr_statistics.uei++;
@@ -3190,15 +3231,7 @@
 			isr_tr_complete_handler(udc);
 		}
 		if (USBi_SLI & intr) {
-			if (udc->gadget.speed != USB_SPEED_UNKNOWN) {
-				udc->suspended = 1;
-				spin_unlock(udc->lock);
-				udc->driver->suspend(&udc->gadget);
-				if (udc->udc_driver->notify_event)
-					udc->udc_driver->notify_event(udc,
-					  CI13XXX_CONTROLLER_SUSPEND_EVENT);
-				spin_lock(udc->lock);
-			}
+			isr_suspend_handler(udc);
 			isr_statistics.sli++;
 		}
 		retval = IRQ_HANDLED;
@@ -3273,9 +3306,8 @@
 	udc->gadget.dev.parent   = dev;
 	udc->gadget.dev.release  = udc_release;
 
-	udc->transceiver = otg_get_transceiver();
-
 	if (udc->udc_driver->flags & CI13XXX_REQUIRE_TRANSCEIVER) {
+		udc->transceiver = otg_get_transceiver();
 		if (udc->transceiver == NULL) {
 			retval = -ENODEV;
 			goto free_udc;
diff --git a/drivers/usb/gadget/ci13xxx_udc.h b/drivers/usb/gadget/ci13xxx_udc.h
index 8e2b093..8cb62da 100644
--- a/drivers/usb/gadget/ci13xxx_udc.h
+++ b/drivers/usb/gadget/ci13xxx_udc.h
@@ -124,6 +124,8 @@
 #define CI13XXX_CONTROLLER_CONNECT_EVENT		1
 #define CI13XXX_CONTROLLER_SUSPEND_EVENT		2
 #define CI13XXX_CONTROLLER_REMOTE_WAKEUP_EVENT	3
+#define CI13XXX_CONTROLLER_RESUME_EVENT	        4
+#define CI13XXX_CONTROLLER_DISCONNECT_EVENT	    5
 	void	(*notify_event) (struct ci13xxx *udc, unsigned event);
 };
 
diff --git a/drivers/usb/gadget/f_mbim.c b/drivers/usb/gadget/f_mbim.c
index 02b2cc3..41a1777 100644
--- a/drivers/usb/gadget/f_mbim.c
+++ b/drivers/usb/gadget/f_mbim.c
@@ -153,7 +153,7 @@
 	.wNdpOutDivisor = cpu_to_le16(4),
 	.wNdpOutPayloadRemainder = cpu_to_le16(0),
 	.wNdpOutAlignment = cpu_to_le16(4),
-	.wNtbOutMaxDatagrams = cpu_to_le16(4),
+	.wNtbOutMaxDatagrams = 0,
 };
 
 /*
@@ -216,7 +216,7 @@
 	.wMaxControlMessage =	cpu_to_le16(0x1000),
 	.bNumberFilters =	0x10,
 	.bMaxFilterSize =	0x80,
-	.wMaxSegmentSize =	cpu_to_le16(0x1000),
+	.wMaxSegmentSize =	cpu_to_le16(0xfe0),
 	.bmNetworkCapabilities = 0x20,
 };
 
diff --git a/drivers/usb/gadget/f_mtp.c b/drivers/usb/gadget/f_mtp.c
index 0e619e6..87244e9 100644
--- a/drivers/usb/gadget/f_mtp.c
+++ b/drivers/usb/gadget/f_mtp.c
@@ -708,7 +708,8 @@
 		ret = usb_ep_queue(dev->ep_in, req, GFP_KERNEL);
 		if (ret < 0) {
 			DBG(cdev, "send_file_work: xfer error %d\n", ret);
-			dev->state = STATE_ERROR;
+			if (dev->state != STATE_OFFLINE)
+				dev->state = STATE_ERROR;
 			r = -EIO;
 			break;
 		}
@@ -760,7 +761,8 @@
 			ret = usb_ep_queue(dev->ep_out, read_req, GFP_KERNEL);
 			if (ret < 0) {
 				r = -EIO;
-				dev->state = STATE_ERROR;
+				if (dev->state != STATE_OFFLINE)
+					dev->state = STATE_ERROR;
 				break;
 			}
 		}
@@ -772,7 +774,8 @@
 			DBG(cdev, "vfs_write %d\n", ret);
 			if (ret != write_req->actual) {
 				r = -EIO;
-				dev->state = STATE_ERROR;
+				if (dev->state != STATE_OFFLINE)
+					dev->state = STATE_ERROR;
 				break;
 			}
 			write_req = NULL;
diff --git a/drivers/usb/gadget/f_rmnet.c b/drivers/usb/gadget/f_rmnet.c
index f7230fe..414a7b9 100644
--- a/drivers/usb/gadget/f_rmnet.c
+++ b/drivers/usb/gadget/f_rmnet.c
@@ -55,9 +55,11 @@
 static unsigned int nr_rmnet_ports;
 static unsigned int no_ctrl_smd_ports;
 static unsigned int no_ctrl_hsic_ports;
+static unsigned int no_ctrl_hsuart_ports;
 static unsigned int no_data_bam_ports;
 static unsigned int no_data_bam2bam_ports;
 static unsigned int no_data_hsic_ports;
+static unsigned int no_data_hsuart_ports;
 static struct rmnet_ports {
 	enum transport_type		data_xport;
 	enum transport_type		ctrl_xport;
@@ -162,6 +164,8 @@
 	NULL,
 };
 
+static void frmnet_ctrl_response_available(struct f_rmnet *dev);
+
 /* ------- misc functions --------------------*/
 
 static inline struct f_rmnet *func_to_rmnet(struct usb_function *f)
@@ -232,12 +236,12 @@
 	int	port_idx;
 	int	i;
 
-	pr_debug("%s: bam ports: %u bam2bam ports: %u data hsic ports: %u"
-		" smd ports: %u ctrl hsic ports: %u"
+	pr_debug("%s: bam ports: %u bam2bam ports: %u data hsic ports: %u data hsuart ports: %u"
+		" smd ports: %u ctrl hsic ports: %u ctrl hsuart ports: %u"
 	" nr_rmnet_ports: %u\n",
 		__func__, no_data_bam_ports, no_data_bam2bam_ports,
-		no_data_hsic_ports, no_ctrl_smd_ports,
-		no_ctrl_hsic_ports, nr_rmnet_ports);
+		no_data_hsic_ports, no_data_hsuart_ports, no_ctrl_smd_ports,
+		no_ctrl_hsic_ports, no_ctrl_hsuart_ports, nr_rmnet_ports);
 
 	if (no_data_bam_ports || no_data_bam2bam_ports) {
 		ret = gbam_setup(no_data_bam_ports,
@@ -280,6 +284,34 @@
 		}
 	}
 
+	if (no_data_hsuart_ports) {
+		port_idx = ghsuart_data_setup(no_data_hsuart_ports,
+				USB_GADGET_RMNET);
+		if (port_idx < 0)
+			return port_idx;
+		for (i = 0; i < nr_rmnet_ports; i++) {
+			if (rmnet_ports[i].data_xport ==
+					USB_GADGET_XPORT_HSUART) {
+				rmnet_ports[i].data_xport_num = port_idx;
+				port_idx++;
+			}
+		}
+	}
+
+	if (no_ctrl_hsuart_ports) {
+		port_idx = ghsuart_ctrl_setup(no_ctrl_hsuart_ports,
+				USB_GADGET_RMNET);
+		if (port_idx < 0)
+			return port_idx;
+		for (i = 0; i < nr_rmnet_ports; i++) {
+			if (rmnet_ports[i].ctrl_xport ==
+					USB_GADGET_XPORT_HSUART) {
+				rmnet_ports[i].ctrl_xport_num = port_idx;
+				port_idx++;
+			}
+		}
+	}
+
 	return 0;
 }
 
@@ -312,6 +344,14 @@
 			return ret;
 		}
 		break;
+	case USB_GADGET_XPORT_HSUART:
+		ret = ghsuart_ctrl_connect(&dev->port, port_num);
+		if (ret) {
+			pr_err("%s: ghsuart_ctrl_connect failed: err:%d\n",
+					__func__, ret);
+			return ret;
+		}
+		break;
 	case USB_GADGET_XPORT_NONE:
 		break;
 	default:
@@ -342,6 +382,15 @@
 			return ret;
 		}
 		break;
+	case USB_GADGET_XPORT_HSUART:
+		ret = ghsuart_data_connect(&dev->port, port_num);
+		if (ret) {
+			pr_err("%s: ghsuart_data_connect failed: err:%d\n",
+					__func__, ret);
+			ghsuart_ctrl_disconnect(&dev->port, port_num);
+			return ret;
+		}
+		break;
 	case USB_GADGET_XPORT_NONE:
 		 break;
 	default:
@@ -371,6 +420,9 @@
 	case USB_GADGET_XPORT_HSIC:
 		ghsic_ctrl_disconnect(&dev->port, port_num);
 		break;
+	case USB_GADGET_XPORT_HSUART:
+		ghsuart_ctrl_disconnect(&dev->port, port_num);
+		break;
 	case USB_GADGET_XPORT_NONE:
 		break;
 	default:
@@ -388,6 +440,9 @@
 	case USB_GADGET_XPORT_HSIC:
 		ghsic_data_disconnect(&dev->port, port_num);
 		break;
+	case USB_GADGET_XPORT_HSUART:
+		ghsuart_data_disconnect(&dev->port, port_num);
+		break;
 	case USB_GADGET_XPORT_NONE:
 		break;
 	default:
@@ -501,6 +556,7 @@
 	struct f_rmnet			*dev = func_to_rmnet(f);
 	struct usb_composite_dev	*cdev = dev->cdev;
 	int				ret;
+	struct list_head *cpkt;
 
 	pr_debug("%s:dev:%p port#%d\n", __func__, dev, dev->port_num);
 
@@ -537,6 +593,11 @@
 
 	atomic_set(&dev->online, 1);
 
+	/* In case notifications were aborted, but there are pending control
+	   packets in the response queue, re-add the notifications */
+	list_for_each(cpkt, &dev->cpkt_resp_q)
+		frmnet_ctrl_response_available(dev);
+
 	return ret;
 }
 
@@ -998,6 +1059,8 @@
 	no_data_bam2bam_ports = 0;
 	no_ctrl_hsic_ports = 0;
 	no_data_hsic_ports = 0;
+	no_ctrl_hsuart_ports = 0;
+	no_data_hsuart_ports = 0;
 }
 
 static int frmnet_init_port(const char *ctrl_name, const char *data_name)
@@ -1041,6 +1104,10 @@
 		rmnet_port->ctrl_xport_num = no_ctrl_hsic_ports;
 		no_ctrl_hsic_ports++;
 		break;
+	case USB_GADGET_XPORT_HSUART:
+		rmnet_port->ctrl_xport_num = no_ctrl_hsuart_ports;
+		no_ctrl_hsuart_ports++;
+		break;
 	case USB_GADGET_XPORT_NONE:
 		break;
 	default:
@@ -1063,6 +1130,10 @@
 		rmnet_port->data_xport_num = no_data_hsic_ports;
 		no_data_hsic_ports++;
 		break;
+	case USB_GADGET_XPORT_HSUART:
+		rmnet_port->data_xport_num = no_data_hsuart_ports;
+		no_data_hsuart_ports++;
+		break;
 	case USB_GADGET_XPORT_NONE:
 		break;
 	default:
@@ -1084,6 +1155,8 @@
 	no_data_bam_ports = 0;
 	no_ctrl_hsic_ports = 0;
 	no_data_hsic_ports = 0;
+	no_ctrl_hsuart_ports = 0;
+	no_data_hsuart_ports = 0;
 
 	return ret;
 }
diff --git a/drivers/usb/gadget/f_serial.c b/drivers/usb/gadget/f_serial.c
index 8d9f090..08a1712 100644
--- a/drivers/usb/gadget/f_serial.c
+++ b/drivers/usb/gadget/f_serial.c
@@ -27,7 +27,7 @@
  * CDC ACM driver.  However, for many purposes it's just as functional
  * if you can arrange appropriate host side drivers.
  */
-#define GSERIAL_NO_PORTS 2
+#define GSERIAL_NO_PORTS 3
 
 
 struct f_gser {
@@ -67,6 +67,7 @@
 static unsigned int no_sdio_ports;
 static unsigned int no_smd_ports;
 static unsigned int no_hsic_sports;
+static unsigned int no_hsuart_sports;
 static unsigned int nr_ports;
 
 static struct port_info {
@@ -249,9 +250,9 @@
 	int i;
 
 	pr_debug("%s: no_tty_ports: %u no_sdio_ports: %u"
-		" no_smd_ports: %u no_hsic_sports: %u nr_ports: %u\n",
+		" no_smd_ports: %u no_hsic_sports: %u no_hsuart_ports: %u nr_ports: %u\n",
 			__func__, no_tty_ports, no_sdio_ports, no_smd_ports,
-			no_hsic_sports, nr_ports);
+			no_hsic_sports, no_hsuart_sports, nr_ports);
 
 	if (no_tty_ports)
 		ret = gserial_setup(c->cdev->gadget, no_tty_ports);
@@ -278,6 +279,22 @@
 			return ret;
 		return 0;
 	}
+	if (no_hsuart_sports) {
+		port_idx = ghsuart_data_setup(no_hsuart_sports,
+					USB_GADGET_SERIAL);
+		if (port_idx < 0)
+			return port_idx;
+
+		for (i = 0; i < nr_ports; i++) {
+			if (gserial_ports[i].transport ==
+					USB_GADGET_XPORT_HSUART) {
+				gserial_ports[i].client_port_num = port_idx;
+				port_idx++;
+			}
+		}
+
+		return 0;
+	}
 	return ret;
 }
 
@@ -317,6 +334,14 @@
 			return ret;
 		}
 		break;
+	case USB_GADGET_XPORT_HSUART:
+		ret = ghsuart_data_connect(&gser->port, port_num);
+		if (ret) {
+			pr_err("%s: ghsuart_data_connect failed: err:%d\n",
+					__func__, ret);
+			return ret;
+		}
+		break;
 	default:
 		pr_err("%s: Un-supported transport: %s\n", __func__,
 				xport_to_str(gser->transport));
@@ -350,6 +375,9 @@
 		ghsic_ctrl_disconnect(&gser->port, port_num);
 		ghsic_data_disconnect(&gser->port, port_num);
 		break;
+	case USB_GADGET_XPORT_HSUART:
+		ghsuart_data_disconnect(&gser->port, port_num);
+		break;
 	default:
 		pr_err("%s: Un-supported transport:%s\n", __func__,
 				xport_to_str(gser->transport));
@@ -854,11 +882,13 @@
 	gser->port.func.disable = gser_disable;
 	gser->transport		= gserial_ports[port_num].transport;
 #ifdef CONFIG_MODEM_SUPPORT
-	/* We support only two ports for now */
+	/* We support only three ports for now */
 	if (port_num == 0)
 		gser->port.func.name = "modem";
-	else
+	else if (port_num == 1)
 		gser->port.func.name = "nmea";
+	else
+		gser->port.func.name = "modem2";
 	gser->port.func.setup = gser_setup;
 	gser->port.connect = gser_connect;
 	gser->port.get_dtr = gser_get_dtr;
@@ -910,6 +940,10 @@
 		/*client port number will be updated in gport_setup*/
 		no_hsic_sports++;
 		break;
+	case USB_GADGET_XPORT_HSUART:
+		/*client port number will be updated in gport_setup*/
+		no_hsuart_sports++;
+		break;
 	default:
 		pr_err("%s: Un-supported transport transport: %u\n",
 				__func__, gserial_ports[port_num].transport);
diff --git a/drivers/usb/gadget/msm72k_udc.c b/drivers/usb/gadget/msm72k_udc.c
index 863ddcd..0d53da0 100644
--- a/drivers/usb/gadget/msm72k_udc.c
+++ b/drivers/usb/gadget/msm72k_udc.c
@@ -2018,10 +2018,14 @@
 static int
 msm72k_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
 {
-	struct msm_endpoint *ept = to_msm_endpoint(_ep);
-	unsigned char ep_type =
-			desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+	struct msm_endpoint *ept;
+	unsigned char ep_type;
 
+	if (_ep == NULL || desc == NULL)
+		return -EINVAL;
+
+	ept = to_msm_endpoint(_ep);
+	ep_type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
 	_ep->maxpacket = le16_to_cpu(desc->wMaxPacketSize);
 	config_ept(ept);
 	ept->wedged = 0;
diff --git a/drivers/usb/gadget/u_ctrl_hsuart.c b/drivers/usb/gadget/u_ctrl_hsuart.c
new file mode 100644
index 0000000..7102d81
--- /dev/null
+++ b/drivers/usb/gadget/u_ctrl_hsuart.c
@@ -0,0 +1,576 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/termios.h>
+#include <linux/debugfs.h>
+#include <linux/smux.h>
+
+#include <mach/usb_gadget_xport.h>
+
+#define CH_OPENED 0
+#define CH_READY 1
+
+static unsigned int num_ctrl_ports;
+
+static const char *ghsuart_ctrl_names[] = {
+	"SMUX_RMNET_CTL_HSUART"
+};
+
+struct ghsuart_ctrl_port {
+	/* port */
+	unsigned port_num;
+	/* gadget */
+	enum gadget_type gtype;
+	spinlock_t port_lock;
+	void *port_usb;
+	/* work queue*/
+	struct workqueue_struct	*wq;
+	struct work_struct connect_w;
+	struct work_struct disconnect_w;
+	/*ctrl pkt response cb*/
+	int (*send_cpkt_response)(void *g, void *buf, size_t len);
+	void *ctxt;
+	unsigned int ch_id;
+	/* flow control bits */
+	unsigned long flags;
+	int (*send_pkt)(void *, void *, size_t actual);
+	/* Channel status */
+	unsigned long channel_sts;
+	/* control bits */
+	unsigned cbits_tomodem;
+	/* counters */
+	unsigned long to_modem;
+	unsigned long to_host;
+	unsigned long drp_cpkt_cnt;
+};
+
+static struct {
+	struct ghsuart_ctrl_port	*port;
+	struct platform_driver	pdrv;
+} ghsuart_ctrl_ports[NUM_HSUART_PORTS];
+
+static int ghsuart_ctrl_receive(void *dev, void *buf, size_t actual);
+
+static void smux_control_event(void *priv, int event_type, const void *metadata)
+{
+	struct grmnet		*gr = NULL;
+	struct ghsuart_ctrl_port	*port = priv;
+	void			*buf;
+	unsigned long		flags;
+	size_t			len;
+
+	switch (event_type) {
+	case SMUX_CONNECTED:
+		spin_lock_irqsave(&port->port_lock, flags);
+		if (!port->port_usb) {
+			spin_unlock_irqrestore(&port->port_lock, flags);
+			return;
+		}
+		spin_unlock_irqrestore(&port->port_lock, flags);
+		set_bit(CH_OPENED, &port->channel_sts);
+		if (port->gtype == USB_GADGET_RMNET) {
+			gr = port->port_usb;
+			if (gr && gr->connect)
+				gr->connect(gr);
+		}
+		break;
+	case SMUX_DISCONNECTED:
+		clear_bit(CH_OPENED, &port->channel_sts);
+		break;
+	case SMUX_READ_DONE:
+		len = ((struct smux_meta_read *)metadata)->len;
+		buf = ((struct smux_meta_read *)metadata)->buffer;
+		ghsuart_ctrl_receive(port, buf, len);
+		break;
+	case SMUX_READ_FAIL:
+		buf = ((struct smux_meta_read *)metadata)->buffer;
+		kfree(buf);
+		break;
+	case SMUX_WRITE_DONE:
+	case SMUX_WRITE_FAIL:
+		buf = ((struct smux_meta_write *)metadata)->buffer;
+		kfree(buf);
+		break;
+	case SMUX_LOW_WM_HIT:
+	case SMUX_HIGH_WM_HIT:
+	case SMUX_TIOCM_UPDATE:
+		break;
+	default:
+		pr_err("%s Event %d not supported\n", __func__, event_type);
+	};
+}
+
+static int rx_control_buffer(void *priv, void **pkt_priv, void **buffer,
+			int size)
+{
+	void *rx_buf;
+
+	rx_buf = kmalloc(size, GFP_KERNEL);
+	if (!rx_buf)
+		return -EAGAIN;
+	*buffer = rx_buf;
+	*pkt_priv = NULL;
+
+	return 0;
+}
+
+static int ghsuart_ctrl_receive(void *dev, void *buf, size_t actual)
+{
+	struct ghsuart_ctrl_port	*port = dev;
+	int retval = 0;
+
+	pr_debug_ratelimited("%s: read complete bytes read: %d\n",
+			__func__, actual);
+
+	/* send it to USB here */
+	if (port && port->send_cpkt_response) {
+		retval = port->send_cpkt_response(port->port_usb, buf, actual);
+		port->to_host++;
+	}
+	kfree(buf);
+	return retval;
+}
+
+static int
+ghsuart_send_cpkt_tomodem(u8 portno, void *buf, size_t len)
+{
+	void			*cbuf;
+	struct ghsuart_ctrl_port	*port;
+	int			ret;
+
+	if (portno >= num_ctrl_ports) {
+		pr_err("%s: Invalid portno#%d\n", __func__, portno);
+		return -ENODEV;
+	}
+
+	port = ghsuart_ctrl_ports[portno].port;
+	if (!port) {
+		pr_err("%s: port is null\n", __func__);
+		return -ENODEV;
+	}
+	/* drop cpkt if ch is not open */
+	if (!test_bit(CH_OPENED, &port->channel_sts)) {
+		port->drp_cpkt_cnt++;
+		return 0;
+	}
+	cbuf = kmalloc(len, GFP_ATOMIC);
+	if (!cbuf)
+		return -ENOMEM;
+
+	memcpy(cbuf, buf, len);
+
+	pr_debug("%s: ctrl_pkt:%d bytes\n", __func__, len);
+
+	ret = msm_smux_write(port->ch_id, port, (void *)cbuf, len);
+	if (ret < 0) {
+		pr_err_ratelimited("%s: write error:%d\n",
+				__func__, ret);
+		port->drp_cpkt_cnt++;
+		kfree(cbuf);
+		return ret;
+	}
+	port->to_modem++;
+
+	return 0;
+}
+
+static void
+ghsuart_send_cbits_tomodem(void *gptr, u8 portno, int cbits)
+{
+	struct ghsuart_ctrl_port	*port;
+
+	if (portno >= num_ctrl_ports || !gptr) {
+		pr_err("%s: Invalid portno#%d\n", __func__, portno);
+		return;
+	}
+
+	port = ghsuart_ctrl_ports[portno].port;
+	if (!port) {
+		pr_err("%s: port is null\n", __func__);
+		return;
+	}
+
+	if (cbits == port->cbits_tomodem)
+		return;
+
+	port->cbits_tomodem = cbits;
+
+	if (!test_bit(CH_OPENED, &port->channel_sts))
+		return;
+
+	pr_debug("%s: ctrl_tomodem:%d\n", __func__, cbits);
+	/* Send the control bits to the Modem */
+	msm_smux_tiocm_set(port->ch_id, cbits, ~cbits);
+}
+
+static void ghsuart_ctrl_connect_w(struct work_struct *w)
+{
+	struct ghsuart_ctrl_port	*port =
+			container_of(w, struct ghsuart_ctrl_port, connect_w);
+	int			retval;
+
+	if (!port || !test_bit(CH_READY, &port->channel_sts))
+		return;
+
+	pr_debug("%s: port:%p\n", __func__, port);
+
+	retval = msm_smux_open(port->ch_id, port->ctxt, smux_control_event,
+				rx_control_buffer);
+	if (retval < 0) {
+		pr_err(" %s smux_open failed\n", __func__);
+		return;
+	}
+
+}
+
+int ghsuart_ctrl_connect(void *gptr, int port_num)
+{
+	struct ghsuart_ctrl_port	*port;
+	struct grmnet		*gr;
+	unsigned long		flags;
+
+	pr_debug("%s: port#%d\n", __func__, port_num);
+
+	if (port_num > num_ctrl_ports || !gptr) {
+		pr_err("%s: invalid portno#%d\n", __func__, port_num);
+		return -ENODEV;
+	}
+
+	port = ghsuart_ctrl_ports[port_num].port;
+	if (!port) {
+		pr_err("%s: port is null\n", __func__);
+		return -ENODEV;
+	}
+
+	spin_lock_irqsave(&port->port_lock, flags);
+
+	gr = gptr;
+	port->send_cpkt_response = gr->send_cpkt_response;
+	gr->send_encap_cmd = ghsuart_send_cpkt_tomodem;
+	gr->notify_modem = ghsuart_send_cbits_tomodem;
+
+	port->port_usb = gptr;
+	port->to_host = 0;
+	port->to_modem = 0;
+	port->drp_cpkt_cnt = 0;
+	spin_unlock_irqrestore(&port->port_lock, flags);
+
+	if (test_bit(CH_READY, &port->channel_sts))
+		queue_work(port->wq, &port->connect_w);
+
+	return 0;
+}
+
+static void ghsuart_ctrl_disconnect_w(struct work_struct *w)
+{
+	struct ghsuart_ctrl_port	*port =
+			container_of(w, struct ghsuart_ctrl_port, disconnect_w);
+
+	if (!test_bit(CH_OPENED, &port->channel_sts))
+		return;
+
+	msm_smux_close(port->ch_id);
+	clear_bit(CH_OPENED, &port->channel_sts);
+}
+
+void ghsuart_ctrl_disconnect(void *gptr, int port_num)
+{
+	struct gctrl_port	*port;
+	struct grmnet		*gr = NULL;
+	unsigned long		flags;
+
+	pr_debug("%s: port#%d\n", __func__, port_num);
+
+	if (port_num > num_ctrl_ports) {
+		pr_err("%s: invalid portno#%d\n", __func__, port_num);
+		return;
+	}
+
+	port = gctrl_ports[port_num].port;
+
+	if (!gptr || !port) {
+		pr_err("%s: grmnet port is null\n", __func__);
+		return;
+	}
+
+	gr = gptr;
+
+	spin_lock_irqsave(&port->port_lock, flags);
+	gr->send_encap_cmd = 0;
+	gr->notify_modem = 0;
+	port->cbits_tomodem = 0;
+	port->port_usb = 0;
+	port->send_cpkt_response = 0;
+	spin_unlock_irqrestore(&port->port_lock, flags);
+
+	queue_work(port->wq, &port->disconnect_w);
+}
+
+static int ghsuart_ctrl_probe(struct platform_device *pdev)
+{
+	struct ghsuart_ctrl_port	*port;
+	unsigned long		flags;
+
+	pr_debug("%s: name:%s\n", __func__, pdev->name);
+
+	port = ghsuart_ctrl_ports[pdev->id].port;
+	set_bit(CH_READY, &port->channel_sts);
+
+	/* if usb is online, start read */
+	spin_lock_irqsave(&port->port_lock, flags);
+	if (port->port_usb)
+		queue_work(port->wq, &port->connect_w);
+	spin_unlock_irqrestore(&port->port_lock, flags);
+
+	return 0;
+}
+
+static int ghsuart_ctrl_remove(struct platform_device *pdev)
+{
+	struct ghsuart_ctrl_port	*port;
+	struct grmnet		*gr = NULL;
+	unsigned long		flags;
+
+	pr_debug("%s: name:%s\n", __func__, pdev->name);
+
+	port = ghsuart_ctrl_ports[pdev->id].port;
+
+	spin_lock_irqsave(&port->port_lock, flags);
+	if (!port->port_usb) {
+		spin_unlock_irqrestore(&port->port_lock, flags);
+		goto not_ready;
+	}
+
+	gr = port->port_usb;
+
+	spin_unlock_irqrestore(&port->port_lock, flags);
+
+	if (gr && gr->disconnect)
+		gr->disconnect(gr);
+
+	clear_bit(CH_OPENED, &port->channel_sts);
+not_ready:
+	clear_bit(CH_READY, &port->channel_sts);
+
+	return 0;
+}
+
+static void ghsuart_ctrl_port_free(int portno)
+{
+	struct ghsuart_ctrl_port	*port = ghsuart_ctrl_ports[portno].port;
+	struct platform_driver	*pdrv = &gctrl_ports[portno].pdrv;
+
+	destroy_workqueue(port->wq);
+	if (pdrv)
+		platform_driver_unregister(pdrv);
+	kfree(port);
+}
+
+static int ghsuart_ctrl_port_alloc(int portno, enum gadget_type gtype)
+{
+	struct ghsuart_ctrl_port	*port;
+	struct platform_driver	*pdrv;
+	int err;
+
+	port = kzalloc(sizeof(struct ghsuart_ctrl_port), GFP_KERNEL);
+	if (!port)
+		return -ENOMEM;
+
+	port->wq = create_singlethread_workqueue(ghsuart_ctrl_names[portno]);
+	if (!port->wq) {
+		pr_err("%s: Unable to create workqueue:%s\n",
+			__func__, ghsuart_ctrl_names[portno]);
+		kfree(port);
+		return -ENOMEM;
+	}
+
+	port->port_num = portno;
+	port->gtype = gtype;
+
+	spin_lock_init(&port->port_lock);
+
+	INIT_WORK(&port->connect_w, ghsuart_ctrl_connect_w);
+	INIT_WORK(&port->disconnect_w, ghsuart_ctrl_disconnect_w);
+
+	port->ch_id = SMUX_USB_RMNET_CTL_0;
+	port->ctxt = port;
+	port->send_pkt = ghsuart_ctrl_receive;
+	ghsuart_ctrl_ports[portno].port = port;
+
+	pdrv = &ghsuart_ctrl_ports[portno].pdrv;
+	pdrv->probe = ghsuart_ctrl_probe;
+	pdrv->remove = ghsuart_ctrl_remove;
+	pdrv->driver.name = ghsuart_ctrl_names[portno];
+	pdrv->driver.owner = THIS_MODULE;
+
+	err = platform_driver_register(pdrv);
+	if (unlikely(err < 0))
+		return err;
+	pr_debug("%s: port:%p portno:%d\n", __func__, port, portno);
+
+	return 0;
+}
+
+int ghsuart_ctrl_setup(unsigned int num_ports, enum gadget_type gtype)
+{
+	int	first_port_id = num_ctrl_ports;
+	int	total_num_ports = num_ports + num_ctrl_ports;
+	int	i;
+	int	ret = 0;
+
+	if (!num_ports || total_num_ports > NUM_HSUART_PORTS) {
+		pr_err("%s: Invalid num of ports count:%d\n",
+				__func__, num_ports);
+		return -EINVAL;
+	}
+
+	pr_debug("%s: requested ports:%d\n", __func__, num_ports);
+
+	for (i = first_port_id; i < (first_port_id + num_ports); i++) {
+
+		num_ctrl_ports++;
+		ret = ghsuart_ctrl_port_alloc(i, gtype);
+		if (ret) {
+			num_ctrl_ports--;
+			pr_err("%s: Unable to alloc port:%d\n", __func__, i);
+			goto free_ports;
+		}
+	}
+
+	return first_port_id;
+
+free_ports:
+	for (i = first_port_id; i < num_ctrl_ports; i++)
+		ghsuart_ctrl_port_free(i);
+		num_ctrl_ports = first_port_id;
+	return ret;
+}
+
+#define DEBUG_BUF_SIZE	1024
+static ssize_t ghsuart_ctrl_read_stats(struct file *file, char __user *ubuf,
+		size_t count, loff_t *ppos)
+{
+	struct ghsuart_ctrl_port	*port;
+	char			*buf;
+	unsigned long		flags;
+	int			ret;
+	int			i;
+	int			temp = 0;
+
+	buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	for (i = 0; i < num_ctrl_ports; i++) {
+		port = ghsuart_ctrl_ports[i].port;
+		if (!port)
+			continue;
+		spin_lock_irqsave(&port->port_lock, flags);
+
+		temp += scnprintf(buf + temp, DEBUG_BUF_SIZE - temp,
+				"#PORT:%d port: %p\n"
+				"to_usbhost:    %lu\n"
+				"to_modem:      %lu\n"
+				"cpkt_drp_cnt:  %lu\n"
+				"DTR:           %s\n",
+				i, port,
+				port->to_host, port->to_modem,
+				port->drp_cpkt_cnt,
+				port->cbits_tomodem ? "HIGH" : "LOW");
+
+		spin_unlock_irqrestore(&port->port_lock, flags);
+	}
+
+	ret = simple_read_from_buffer(ubuf, count, ppos, buf, temp);
+
+	kfree(buf);
+
+	return ret;
+}
+
+static ssize_t ghsuart_ctrl_reset_stats(struct file *file,
+	const char __user *buf, size_t count, loff_t *ppos)
+{
+	struct ghsuart_ctrl_port	*port;
+	int			i;
+	unsigned long		flags;
+
+	for (i = 0; i < num_ctrl_ports; i++) {
+		port = ghsuart_ctrl_ports[i].port;
+		if (!port)
+			continue;
+
+		spin_lock_irqsave(&port->port_lock, flags);
+		port->to_host = 0;
+		port->to_modem = 0;
+		port->drp_cpkt_cnt = 0;
+		spin_unlock_irqrestore(&port->port_lock, flags);
+	}
+	return count;
+}
+
+static const struct file_operations ghsuart_ctrl_stats_ops = {
+	.read = ghsuart_ctrl_read_stats,
+	.write = ghsuart_ctrl_reset_stats,
+};
+
+static struct dentry	*ghsuart_ctrl_dent;
+static int ghsuart_ctrl_debugfs_init(void)
+{
+	struct dentry	*ghsuart_ctrl_dfile;
+
+	ghsuart_ctrl_dent = debugfs_create_dir("ghsuart_ctrl_xport", 0);
+	if (!ghsuart_ctrl_dent || IS_ERR(ghsuart_ctrl_dent))
+		return -ENODEV;
+
+	ghsuart_ctrl_dfile =
+		debugfs_create_file("status", S_IRUGO | S_IWUSR,
+				ghsuart_ctrl_dent, 0, &gctrl_stats_ops);
+	if (!ghsuart_ctrl_dfile || IS_ERR(ghsuart_ctrl_dfile)) {
+		debugfs_remove(ghsuart_ctrl_dent);
+		ghsuart_ctrl_dent = NULL;
+		return -ENODEV;
+	}
+	return 0;
+}
+
+static void ghsuart_ctrl_debugfs_exit(void)
+{
+	debugfs_remove_recursive(ghsuart_ctrl_dent);
+}
+
+static int __init ghsuart_ctrl_init(void)
+{
+	int ret;
+
+	ret = ghsuart_ctrl_debugfs_init();
+	if (ret) {
+		pr_debug("mode debugfs file is not available\n");
+		return ret;
+	}
+	return 0;
+}
+module_init(ghsuart_ctrl_init);
+
+static void __exit ghsuart_ctrl_exit(void)
+{
+	ghsuart_ctrl_debugfs_exit();
+}
+module_exit(ghsuart_ctrl_exit);
+
+MODULE_DESCRIPTION("HSUART control xport for RmNet");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/gadget/u_data_hsuart.c b/drivers/usb/gadget/u_data_hsuart.c
new file mode 100644
index 0000000..b2c57c4
--- /dev/null
+++ b/drivers/usb/gadget/u_data_hsuart.c
@@ -0,0 +1,1142 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/termios.h>
+#include <linux/netdevice.h>
+#include <linux/debugfs.h>
+#include <linux/bitops.h>
+#include <linux/smux.h>
+
+#include <mach/usb_gadget_xport.h>
+
+static unsigned int num_data_ports;
+
+static const char *ghsuart_data_names[] = {
+	"SMUX_DUN_DATA_HSUART",
+	"SMUX_RMNET_DATA_HSUART"
+};
+
+#define DATA_BRIDGE_NAME_MAX_LEN		20
+
+#define GHSUART_DATA_RMNET_RX_Q_SIZE		10
+#define GHSUART_DATA_RMNET_TX_Q_SIZE		20
+#define GHSUART_DATA_SERIAL_RX_Q_SIZE		5
+#define GHSUART_DATA_SERIAL_TX_Q_SIZE		5
+#define GHSUART_DATA_RX_REQ_SIZE		2048
+#define GHSUART_DATA_TX_INTR_THRESHOLD		1
+
+/* from cdc-acm.h */
+#define ACM_CTRL_RTS		(1 << 1)	/* unused with full duplex */
+#define ACM_CTRL_DTR		(1 << 0)	/* host is ready for data r/w */
+#define ACM_CTRL_OVERRUN	(1 << 6)
+#define ACM_CTRL_PARITY		(1 << 5)
+#define ACM_CTRL_FRAMING	(1 << 4)
+#define ACM_CTRL_RI		(1 << 3)
+#define ACM_CTRL_BRK		(1 << 2)
+#define ACM_CTRL_DSR		(1 << 1)
+#define ACM_CTRL_DCD		(1 << 0)
+
+static unsigned int ghsuart_data_rmnet_tx_q_size = GHSUART_DATA_RMNET_TX_Q_SIZE;
+module_param(ghsuart_data_rmnet_tx_q_size, uint, S_IRUGO | S_IWUSR);
+
+static unsigned int ghsuart_data_rmnet_rx_q_size = GHSUART_DATA_RMNET_RX_Q_SIZE;
+module_param(ghsuart_data_rmnet_rx_q_size, uint, S_IRUGO | S_IWUSR);
+
+static unsigned int ghsuart_data_serial_tx_q_size =
+					GHSUART_DATA_SERIAL_TX_Q_SIZE;
+module_param(ghsuart_data_serial_tx_q_size, uint, S_IRUGO | S_IWUSR);
+
+static unsigned int ghsuart_data_serial_rx_q_size =
+				GHSUART_DATA_SERIAL_RX_Q_SIZE;
+module_param(ghsuart_data_serial_rx_q_size, uint, S_IRUGO | S_IWUSR);
+
+static unsigned int ghsuart_data_rx_req_size = GHSUART_DATA_RX_REQ_SIZE;
+module_param(ghsuart_data_rx_req_size, uint, S_IRUGO | S_IWUSR);
+
+unsigned int ghsuart_data_tx_intr_thld = GHSUART_DATA_TX_INTR_THRESHOLD;
+module_param(ghsuart_data_tx_intr_thld, uint, S_IRUGO | S_IWUSR);
+
+#define CH_OPENED 0
+#define CH_READY 1
+
+struct ghsuart_data_port {
+	/* port */
+	unsigned		port_num;
+
+	/* gadget */
+	atomic_t		connected;
+	struct usb_ep		*in;
+	struct usb_ep		*out;
+
+	enum gadget_type	gtype;
+	spinlock_t		port_lock;
+	void *port_usb;
+
+	/* data transfer queues */
+	unsigned int		tx_q_size;
+	struct list_head	tx_idle;
+	struct sk_buff_head	tx_skb_q;
+	spinlock_t		tx_lock;
+
+	unsigned int		rx_q_size;
+	struct list_head	rx_idle;
+	struct sk_buff_head	rx_skb_q;
+	spinlock_t		rx_lock;
+
+	/* work */
+	struct workqueue_struct	*wq;
+	struct work_struct	connect_w;
+	struct work_struct	disconnect_w;
+	struct work_struct	write_tomdm_w;
+	struct work_struct	write_tohost_w;
+	void *ctx;
+	unsigned int ch_id;
+	/* flow control bits */
+	unsigned long flags;
+	/* channel status */
+	unsigned long		channel_sts;
+
+	unsigned int		n_tx_req_queued;
+
+	/* control bits */
+	unsigned		cbits_tomodem;
+	unsigned		cbits_tohost;
+
+	/* counters */
+	unsigned long		to_modem;
+	unsigned long		to_host;
+	unsigned int		tomodem_drp_cnt;
+};
+
+static struct {
+	struct ghsuart_data_port	*port;
+	struct platform_driver	pdrv;
+} ghsuart_data_ports[NUM_HSUART_PORTS];
+
+static void ghsuart_data_start_rx(struct ghsuart_data_port *port);
+
+static void ghsuart_data_free_requests(struct usb_ep *ep,
+				 struct list_head *head)
+{
+	struct usb_request	*req;
+
+	while (!list_empty(head)) {
+		req = list_entry(head->next, struct usb_request, list);
+		list_del(&req->list);
+		usb_ep_free_request(ep, req);
+	}
+}
+
+static int ghsuart_data_alloc_requests(struct usb_ep *ep,
+		struct list_head *head,
+		int num,
+		void (*cb)(struct usb_ep *ep, struct usb_request *),
+		gfp_t flags)
+{
+	int			i;
+	struct usb_request	*req;
+
+	pr_debug("%s: ep:%s head:%p num:%d cb:%p", __func__,
+			ep->name, head, num, cb);
+
+	for (i = 0; i < num; i++) {
+		req = usb_ep_alloc_request(ep, flags);
+		if (!req) {
+			pr_err("%s: req allocated:%d\n", __func__, i);
+			return list_empty(head) ? -ENOMEM : 0;
+		}
+		req->complete = cb;
+		list_add(&req->list, head);
+	}
+
+	return 0;
+}
+
+static void ghsuart_data_write_tohost(struct work_struct *w)
+{
+	unsigned long		flags;
+	struct sk_buff		*skb;
+	int			ret;
+	struct usb_request	*req;
+	struct usb_ep		*ep;
+	struct ghsuart_data_port	*port;
+
+	port = container_of(w, struct ghsuart_data_port, write_tohost_w);
+
+	if (!port || !atomic_read(&port->connected))
+		return;
+
+	spin_lock_irqsave(&port->tx_lock, flags);
+	ep = port->in;
+	if (!ep) {
+		spin_unlock_irqrestore(&port->tx_lock, flags);
+		return;
+	}
+
+	while (!list_empty(&port->tx_idle)) {
+		skb = __skb_dequeue(&port->tx_skb_q);
+		if (!skb)
+			break;
+
+		req = list_first_entry(&port->tx_idle, struct usb_request,
+				list);
+		req->context = skb;
+		req->buf = skb->data;
+		req->length = skb->len;
+
+		port->n_tx_req_queued++;
+		if (port->n_tx_req_queued == ghsuart_data_tx_intr_thld) {
+			req->no_interrupt = 0;
+			port->n_tx_req_queued = 0;
+		} else {
+			req->no_interrupt = 1;
+		}
+
+		list_del(&req->list);
+
+		spin_unlock_irqrestore(&port->tx_lock, flags);
+		ret = usb_ep_queue(ep, req, GFP_KERNEL);
+		spin_lock_irqsave(&port->tx_lock, flags);
+		if (ret) {
+			pr_err("%s: usb epIn failed\n", __func__);
+			list_add(&req->list, &port->tx_idle);
+			dev_kfree_skb_any(skb);
+			break;
+		}
+		port->to_host++;
+	}
+	spin_unlock_irqrestore(&port->tx_lock, flags);
+}
+
+static void ghsuart_data_write_tomdm(struct work_struct *w)
+{
+	struct ghsuart_data_port	*port;
+	struct sk_buff		*skb;
+	unsigned long		flags;
+	int			ret;
+
+	port = container_of(w, struct ghsuart_data_port, write_tomdm_w);
+
+	if (!port || !atomic_read(&port->connected))
+		return;
+
+	spin_lock_irqsave(&port->rx_lock, flags);
+	if (test_bit(TX_THROTTLED, &port->flags)) {
+		spin_unlock_irqrestore(&port->rx_lock, flags);
+		return;
+	}
+
+	while ((skb = __skb_dequeue(&port->rx_skb_q))) {
+		pr_debug("%s: port:%p tom:%lu pno:%d\n", __func__,
+				port, port->to_modem, port->port_num);
+
+		spin_unlock_irqrestore(&port->rx_lock, flags);
+		ret = msm_smux_write(port->ch_id, skb, skb->data, skb->len);
+		spin_lock_irqsave(&port->rx_lock, flags);
+		if (ret < 0) {
+			if (ret == -EAGAIN) {
+				/*flow control*/
+				set_bit(TX_THROTTLED, &port->flags);
+				__skb_queue_head(&port->rx_skb_q, skb);
+				break;
+			}
+			pr_err_ratelimited("%s: write error:%d\n",
+					__func__, ret);
+			port->tomodem_drp_cnt++;
+			dev_kfree_skb_any(skb);
+			break;
+		}
+		port->to_modem++;
+	}
+	spin_unlock_irqrestore(&port->rx_lock, flags);
+	ghsuart_data_start_rx(port);
+}
+
+static void ghsuart_data_epin_complete(struct usb_ep *ep,
+				struct usb_request *req)
+{
+	struct ghsuart_data_port	*port = ep->driver_data;
+	struct sk_buff		*skb = req->context;
+	int			status = req->status;
+
+	switch (status) {
+	case 0:
+		/* successful completion */
+		break;
+	case -ECONNRESET:
+	case -ESHUTDOWN:
+		/* connection gone */
+		dev_kfree_skb_any(skb);
+		req->buf = 0;
+		usb_ep_free_request(ep, req);
+		return;
+	default:
+		pr_err("%s: data tx ep error %d\n", __func__, status);
+		break;
+	}
+
+	dev_kfree_skb_any(skb);
+
+	spin_lock(&port->tx_lock);
+	list_add_tail(&req->list, &port->tx_idle);
+	spin_unlock(&port->tx_lock);
+
+	queue_work(port->wq, &port->write_tohost_w);
+}
+
+static void
+ghsuart_data_epout_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct ghsuart_data_port	*port = ep->driver_data;
+	struct sk_buff		*skb = req->context;
+	int			status = req->status;
+	int			queue = 0;
+
+	switch (status) {
+	case 0:
+		skb_put(skb, req->actual);
+		queue = 1;
+		break;
+	case -ECONNRESET:
+	case -ESHUTDOWN:
+		/* cable disconnection */
+		dev_kfree_skb_any(skb);
+		req->buf = 0;
+		usb_ep_free_request(ep, req);
+		return;
+	default:
+		pr_err_ratelimited("%s: %s response error %d, %d/%d\n",
+					__func__, ep->name, status,
+				req->actual, req->length);
+		dev_kfree_skb_any(skb);
+		list_add_tail(&req->list, &port->rx_idle);
+		return;
+	}
+
+	spin_lock(&port->rx_lock);
+	if (queue) {
+		__skb_queue_tail(&port->rx_skb_q, skb);
+		list_add_tail(&req->list, &port->rx_idle);
+		queue_work(port->wq, &port->write_tomdm_w);
+	}
+	spin_unlock(&port->rx_lock);
+}
+
+static void ghsuart_data_start_rx(struct ghsuart_data_port *port)
+{
+	struct usb_request	*req;
+	struct usb_ep		*ep;
+	unsigned long		flags;
+	int			ret;
+	struct sk_buff		*skb;
+
+	pr_debug("%s: port:%p\n", __func__, port);
+	if (!port)
+		return;
+
+	spin_lock_irqsave(&port->rx_lock, flags);
+	ep = port->out;
+	if (!ep) {
+		spin_unlock_irqrestore(&port->rx_lock, flags);
+		return;
+	}
+
+	if (test_bit(TX_THROTTLED, &port->flags)) {
+		spin_unlock_irqrestore(&port->rx_lock, flags);
+		return;
+	}
+
+	while (atomic_read(&port->connected) && !list_empty(&port->rx_idle)) {
+
+		req = list_first_entry(&port->rx_idle,
+					struct usb_request, list);
+
+		skb = alloc_skb(ghsuart_data_rx_req_size, GFP_ATOMIC);
+		if (!skb)
+			break;
+		list_del(&req->list);
+		req->buf = skb->data;
+		req->length = ghsuart_data_rx_req_size;
+		req->context = skb;
+
+		spin_unlock_irqrestore(&port->rx_lock, flags);
+		ret = usb_ep_queue(ep, req, GFP_KERNEL);
+		spin_lock_irqsave(&port->rx_lock, flags);
+		if (ret) {
+			dev_kfree_skb_any(skb);
+
+			pr_err_ratelimited("%s: rx queue failed\n", __func__);
+
+			if (atomic_read(&port->connected))
+				list_add(&req->list, &port->rx_idle);
+			else
+				usb_ep_free_request(ep, req);
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&port->rx_lock, flags);
+}
+
+static void ghsuart_data_start_io(struct ghsuart_data_port *port)
+{
+	unsigned long	flags;
+	struct usb_ep	*ep;
+	int		ret;
+
+	pr_debug("%s: port:%p\n", __func__, port);
+
+	if (!port)
+		return;
+
+	spin_lock_irqsave(&port->rx_lock, flags);
+	ep = port->out;
+	if (!ep) {
+		spin_unlock_irqrestore(&port->rx_lock, flags);
+		return;
+	}
+
+	ret = ghsuart_data_alloc_requests(ep, &port->rx_idle,
+		port->rx_q_size, ghsuart_data_epout_complete, GFP_ATOMIC);
+	if (ret) {
+		pr_err("%s: rx req allocation failed\n", __func__);
+		spin_unlock_irqrestore(&port->rx_lock, flags);
+		return;
+	}
+	spin_unlock_irqrestore(&port->rx_lock, flags);
+
+	spin_lock_irqsave(&port->tx_lock, flags);
+	ep = port->in;
+	if (!ep) {
+		spin_unlock_irqrestore(&port->tx_lock, flags);
+		return;
+	}
+
+	ret = ghsuart_data_alloc_requests(ep, &port->tx_idle,
+		port->tx_q_size, ghsuart_data_epin_complete, GFP_ATOMIC);
+	if (ret) {
+		pr_err("%s: tx req allocation failed\n", __func__);
+		ghsuart_data_free_requests(ep, &port->rx_idle);
+		spin_unlock_irqrestore(&port->tx_lock, flags);
+		return;
+	}
+	spin_unlock_irqrestore(&port->tx_lock, flags);
+
+	/* queue out requests */
+	ghsuart_data_start_rx(port);
+}
+
+static void ghsuart_dunctrl_status(void *ctxt, unsigned int ctrl_bits)
+{
+	struct ghsuart_data_port  *port = ctxt;
+	struct gserial          *gser;
+	unsigned long	flags;
+
+	pr_debug("%s - input control lines: dcd%c dsr%c break%c "
+	"ring%c framing%c parity%c overrun%c\n", __func__,
+	ctrl_bits & ACM_CTRL_DCD ? '+' : '-',
+	ctrl_bits & ACM_CTRL_DSR ? '+' : '-',
+	ctrl_bits & ACM_CTRL_BRK ? '+' : '-',
+	ctrl_bits & ACM_CTRL_RI  ? '+' : '-',
+	ctrl_bits & ACM_CTRL_FRAMING ? '+' : '-',
+	ctrl_bits & ACM_CTRL_PARITY ? '+' : '-',
+	ctrl_bits & ACM_CTRL_OVERRUN ? '+' : '-');
+
+	spin_lock_irqsave(&port->port_lock, flags);
+	port->cbits_tohost = ctrl_bits;
+	gser = port->port_usb;
+	spin_unlock_irqrestore(&port->port_lock, flags);
+	if (gser && gser->send_modem_ctrl_bits)
+		gser->send_modem_ctrl_bits(gser, ctrl_bits);
+}
+
+const char *event_string(int event_type)
+{
+	switch (event_type) {
+	case SMUX_CONNECTED:
+		return "SMUX_CONNECTED";
+	case SMUX_DISCONNECTED:
+		return "SMUX_DISCONNECTED";
+	case SMUX_READ_DONE:
+		return "SMUX_READ_DONE";
+	case SMUX_READ_FAIL:
+		return "SMUX_READ_FAIL";
+	case SMUX_WRITE_DONE:
+		return "SMUX_WRITE_DONE";
+	case SMUX_WRITE_FAIL:
+		return "SMUX_WRITE_FAIL";
+	case SMUX_HIGH_WM_HIT:
+		return "SMUX_HIGH_WM_HIT";
+	case SMUX_LOW_WM_HIT:
+		return "SMUX_LOW_WM_HIT";
+	case SMUX_TIOCM_UPDATE:
+		return "SMUX_TIOCM_UPDATE";
+	default:
+		return "UNDEFINED";
+	}
+}
+
+static void ghsuart_notify_event(void *priv, int event_type,
+				const void *metadata)
+{
+	struct ghsuart_data_port	*port = priv;
+	struct smux_meta_write *meta_write =
+				(struct smux_meta_write *) metadata;
+	struct smux_meta_read *meta_read =
+				(struct smux_meta_read *) metadata;
+	struct sk_buff		*skb;
+	unsigned long		flags;
+	unsigned int		cbits;
+	struct gserial		*gser;
+
+	pr_debug("%s: event type: %s ", __func__, event_string(event_type));
+	switch (event_type) {
+	case SMUX_CONNECTED:
+		set_bit(CH_OPENED, &port->channel_sts);
+		if (port->gtype == USB_GADGET_SERIAL) {
+			cbits = msm_smux_tiocm_get(port->ch_id);
+			if (cbits & ACM_CTRL_DCD) {
+				gser = port->port_usb;
+				if (gser && gser->connect)
+					gser->connect(gser);
+			}
+		}
+		ghsuart_data_start_io(port);
+		break;
+	case SMUX_DISCONNECTED:
+		clear_bit(CH_OPENED, &port->channel_sts);
+		break;
+	case SMUX_READ_DONE:
+		skb = meta_read->pkt_priv;
+		skb->data = meta_read->buffer;
+		skb->len = meta_read->len;
+		spin_lock_irqsave(&port->tx_lock, flags);
+		__skb_queue_tail(&port->tx_skb_q, skb);
+		spin_unlock_irqrestore(&port->tx_lock, flags);
+		queue_work(port->wq, &port->write_tohost_w);
+		break;
+	case SMUX_WRITE_DONE:
+		skb = meta_write->pkt_priv;
+		skb->data = meta_write->buffer;
+		dev_kfree_skb_any(skb);
+		queue_work(port->wq, &port->write_tomdm_w);
+		break;
+	case SMUX_READ_FAIL:
+		skb = meta_read->pkt_priv;
+		skb->data = meta_read->buffer;
+		dev_kfree_skb_any(skb);
+		break;
+	case SMUX_WRITE_FAIL:
+		skb = meta_write->pkt_priv;
+		skb->data = meta_write->buffer;
+		dev_kfree_skb_any(skb);
+		break;
+	case SMUX_HIGH_WM_HIT:
+		spin_lock_irqsave(&port->rx_lock, flags);
+		set_bit(TX_THROTTLED, &port->flags);
+		spin_unlock_irqrestore(&port->rx_lock, flags);
+	case SMUX_LOW_WM_HIT:
+		spin_lock_irqsave(&port->rx_lock, flags);
+		clear_bit(TX_THROTTLED, &port->flags);
+		spin_unlock_irqrestore(&port->rx_lock, flags);
+		queue_work(port->wq, &port->write_tomdm_w);
+		break;
+	case SMUX_TIOCM_UPDATE:
+		if (port->gtype == USB_GADGET_SERIAL) {
+			cbits = msm_smux_tiocm_get(port->ch_id);
+			ghsuart_dunctrl_status(port, cbits);
+		}
+		break;
+	default:
+		pr_err("%s:wrong event recieved\n", __func__);
+	}
+}
+
+static int ghsuart_get_rx_buffer(void *priv, void **pkt_priv,
+			void **buffer, int size)
+{
+	struct sk_buff		*skb;
+
+	skb = alloc_skb(size, GFP_ATOMIC);
+	if (!skb)
+		return -ENOMEM;
+	*pkt_priv = skb;
+	*buffer = skb->data;
+
+	return 0;
+}
+
+static void ghsuart_data_connect_w(struct work_struct *w)
+{
+	struct ghsuart_data_port	*port =
+		container_of(w, struct ghsuart_data_port, connect_w);
+	int			ret;
+
+	if (!port || !atomic_read(&port->connected) ||
+		!test_bit(CH_READY, &port->channel_sts))
+		return;
+
+	pr_debug("%s: port:%p\n", __func__, port);
+
+	ret = msm_smux_open(port->ch_id, port, &ghsuart_notify_event,
+				&ghsuart_get_rx_buffer);
+	if (ret) {
+		pr_err("%s: unable to open smux ch:%d err:%d\n",
+				__func__, port->ch_id, ret);
+		return;
+	}
+}
+
+static void ghsuart_data_disconnect_w(struct work_struct *w)
+{
+	struct ghsuart_data_port	*port =
+		container_of(w, struct ghsuart_data_port, disconnect_w);
+
+	if (!test_bit(CH_OPENED, &port->channel_sts))
+		return;
+
+	msm_smux_close(port->ch_id);
+	clear_bit(CH_OPENED, &port->channel_sts);
+}
+
+static void ghsuart_data_free_buffers(struct ghsuart_data_port *port)
+{
+	struct sk_buff	*skb;
+	unsigned long	flags;
+
+	if (!port)
+		return;
+
+	spin_lock_irqsave(&port->tx_lock, flags);
+	if (!port->in) {
+		spin_unlock_irqrestore(&port->tx_lock, flags);
+		return;
+	}
+
+	ghsuart_data_free_requests(port->in, &port->tx_idle);
+
+	while ((skb = __skb_dequeue(&port->tx_skb_q)))
+		dev_kfree_skb_any(skb);
+	spin_unlock_irqrestore(&port->tx_lock, flags);
+
+	spin_lock_irqsave(&port->rx_lock, flags);
+	if (!port->out) {
+		spin_unlock_irqrestore(&port->rx_lock, flags);
+		return;
+	}
+
+	ghsuart_data_free_requests(port->out, &port->rx_idle);
+
+	while ((skb = __skb_dequeue(&port->rx_skb_q)))
+		dev_kfree_skb_any(skb);
+	spin_unlock_irqrestore(&port->rx_lock, flags);
+}
+
+static int ghsuart_data_probe(struct platform_device *pdev)
+{
+	struct ghsuart_data_port *port;
+
+	pr_debug("%s: name:%s num_data_ports= %d\n",
+		__func__, pdev->name, num_data_ports);
+
+	if (pdev->id >= num_data_ports) {
+		pr_err("%s: invalid port: %d\n", __func__, pdev->id);
+		return -EINVAL;
+	}
+
+	port = ghsuart_data_ports[pdev->id].port;
+	set_bit(CH_READY, &port->channel_sts);
+
+	/* if usb is online, try opening bridge */
+	if (atomic_read(&port->connected))
+		queue_work(port->wq, &port->connect_w);
+
+	return 0;
+}
+
+/* mdm disconnect */
+static int ghsuart_data_remove(struct platform_device *pdev)
+{
+	struct ghsuart_data_port *port;
+	struct usb_ep	*ep_in;
+	struct usb_ep	*ep_out;
+	int ret;
+	struct gserial		*gser = NULL;
+	unsigned long	flags;
+
+	pr_debug("%s: name:%s\n", __func__, pdev->name);
+
+	if (pdev->id >= num_data_ports) {
+		pr_err("%s: invalid port: %d\n", __func__, pdev->id);
+		return -EINVAL;
+	}
+
+	port = ghsuart_data_ports[pdev->id].port;
+
+	ep_in = port->in;
+	if (ep_in)
+		usb_ep_fifo_flush(ep_in);
+
+	ep_out = port->out;
+	if (ep_out)
+		usb_ep_fifo_flush(ep_out);
+
+	ghsuart_data_free_buffers(port);
+
+	if (port->gtype == USB_GADGET_SERIAL) {
+		spin_lock_irqsave(&port->port_lock, flags);
+		gser = port->port_usb;
+		port->cbits_tohost = 0;
+		spin_unlock_irqrestore(&port->port_lock, flags);
+		if (gser && gser->disconnect)
+			gser->disconnect(gser);
+	}
+
+	ret = msm_smux_close(port->ch_id);
+	if (ret < 0)
+		pr_err("%s:Unable to close smux channel: %d\n",
+				__func__, port->ch_id);
+
+	clear_bit(CH_READY, &port->channel_sts);
+	clear_bit(CH_OPENED, &port->channel_sts);
+
+	return 0;
+}
+
+static void ghsuart_data_port_free(int portno)
+{
+	struct ghsuart_data_port	*port = ghsuart_data_ports[portno].port;
+	struct platform_driver	*pdrv = &ghsuart_data_ports[portno].pdrv;
+
+	destroy_workqueue(port->wq);
+	kfree(port);
+
+	if (pdrv)
+		platform_driver_unregister(pdrv);
+}
+
+static void
+ghsuart_send_controlbits_tomodem(void *gptr, u8 portno, int cbits)
+{
+	struct ghsuart_data_port	*port;
+
+	if (portno >= num_ctrl_ports || !gptr) {
+		pr_err("%s: Invalid portno#%d\n", __func__, portno);
+		return;
+	}
+
+	port = ghsuart_data_ports[portno].port;
+	if (!port) {
+		pr_err("%s: port is null\n", __func__);
+		return;
+	}
+
+	if (cbits == port->cbits_tomodem)
+		return;
+
+	port->cbits_tomodem = cbits;
+
+	if (!test_bit(CH_OPENED, &port->channel_sts))
+		return;
+
+	/* if DTR is high, update latest modem info to Host */
+	if (port->cbits_tomodem & ACM_CTRL_DTR) {
+		unsigned int i;
+
+		i = msm_smux_tiocm_get(port->ch_id);
+		ghsuart_dunctrl_status(port, i);
+	}
+
+	pr_debug("%s: ctrl_tomodem:%d\n", __func__, cbits);
+	/* Send the control bits to the Modem */
+	msm_smux_tiocm_set(port->ch_id, cbits, ~cbits);
+}
+
+static int ghsuart_data_port_alloc(unsigned port_num, enum gadget_type gtype)
+{
+	struct ghsuart_data_port	*port;
+	struct platform_driver	*pdrv;
+
+	port = kzalloc(sizeof(struct ghsuart_data_port), GFP_KERNEL);
+	if (!port)
+		return -ENOMEM;
+
+	port->wq = create_singlethread_workqueue(ghsuart_data_names[port_num]);
+	if (!port->wq) {
+		pr_err("%s: Unable to create workqueue:%s\n",
+			__func__, ghsuart_data_names[port_num]);
+		kfree(port);
+		return -ENOMEM;
+	}
+	port->port_num = port_num;
+
+	/* port initialization */
+	spin_lock_init(&port->port_lock);
+	spin_lock_init(&port->rx_lock);
+	spin_lock_init(&port->tx_lock);
+
+	INIT_WORK(&port->connect_w, ghsuart_data_connect_w);
+	INIT_WORK(&port->disconnect_w, ghsuart_data_disconnect_w);
+	INIT_WORK(&port->write_tohost_w, ghsuart_data_write_tohost);
+	INIT_WORK(&port->write_tomdm_w, ghsuart_data_write_tomdm);
+
+	INIT_LIST_HEAD(&port->tx_idle);
+	INIT_LIST_HEAD(&port->rx_idle);
+
+	skb_queue_head_init(&port->tx_skb_q);
+	skb_queue_head_init(&port->rx_skb_q);
+
+	port->gtype = gtype;
+	if (port->gtype == USB_GADGET_SERIAL)
+		port->ch_id = SMUX_USB_DUN_0;
+	else
+		port->ch_id = SMUX_USB_RMNET_DATA_0;
+	port->ctx = port;
+	ghsuart_data_ports[port_num].port = port;
+
+	pdrv = &ghsuart_data_ports[port_num].pdrv;
+	pdrv->probe = ghsuart_data_probe;
+	pdrv->remove = ghsuart_data_remove;
+	pdrv->driver.name = ghsuart_data_names[port_num];
+	pdrv->driver.owner = THIS_MODULE;
+
+	platform_driver_register(pdrv);
+
+	pr_debug("%s: port:%p portno:%d\n", __func__, port, port_num);
+
+	return 0;
+}
+
+void ghsuart_data_disconnect(void *gptr, int port_num)
+{
+	struct ghsuart_data_port	*port;
+	unsigned long		flags;
+	struct gserial		*gser = NULL;
+
+	pr_debug("%s: port#%d\n", __func__, port_num);
+
+	port = ghsuart_data_ports[port_num].port;
+
+	if (port_num > num_data_ports) {
+		pr_err("%s: invalid portno#%d\n", __func__, port_num);
+		return;
+	}
+
+	if (!gptr || !port) {
+		pr_err("%s: port is null\n", __func__);
+		return;
+	}
+
+	ghsuart_data_free_buffers(port);
+
+	/* disable endpoints */
+	if (port->in)
+		usb_ep_disable(port->in);
+
+	if (port->out)
+		usb_ep_disable(port->out);
+
+	atomic_set(&port->connected, 0);
+
+	if (port->gtype == USB_GADGET_SERIAL) {
+		gser = gptr;
+		spin_lock_irqsave(&port->port_lock, flags);
+		gser->notify_modem = 0;
+		port->cbits_tomodem = 0;
+		port->port_usb = 0;
+		spin_unlock_irqrestore(&port->port_lock, flags);
+	}
+
+	spin_lock_irqsave(&port->tx_lock, flags);
+	port->in = NULL;
+	port->n_tx_req_queued = 0;
+	clear_bit(RX_THROTTLED, &port->flags);
+	spin_unlock_irqrestore(&port->tx_lock, flags);
+
+	spin_lock_irqsave(&port->rx_lock, flags);
+	port->out = NULL;
+	clear_bit(TX_THROTTLED, &port->flags);
+	spin_unlock_irqrestore(&port->rx_lock, flags);
+
+	queue_work(port->wq, &port->disconnect_w);
+}
+
+int ghsuart_data_connect(void *gptr, int port_num)
+{
+	struct ghsuart_data_port		*port;
+	struct gserial			*gser;
+	struct grmnet			*gr;
+	unsigned long			flags;
+	int				ret = 0;
+
+	pr_debug("%s: port#%d\n", __func__, port_num);
+
+	port = ghsuart_data_ports[port_num].port;
+
+	if (port_num > num_data_ports) {
+		pr_err("%s: invalid portno#%d\n", __func__, port_num);
+		return -ENODEV;
+	}
+
+	if (!gptr || !port) {
+		pr_err("%s: port is null\n", __func__);
+		return -ENODEV;
+	}
+
+	if (port->gtype == USB_GADGET_SERIAL) {
+		gser = gptr;
+
+		spin_lock_irqsave(&port->tx_lock, flags);
+		port->in = gser->in;
+		spin_unlock_irqrestore(&port->tx_lock, flags);
+
+		spin_lock_irqsave(&port->rx_lock, flags);
+		port->out = gser->out;
+		spin_unlock_irqrestore(&port->rx_lock, flags);
+
+
+		port->tx_q_size = ghsuart_data_serial_tx_q_size;
+		port->rx_q_size = ghsuart_data_serial_rx_q_size;
+		gser->in->driver_data = port;
+		gser->out->driver_data = port;
+
+		spin_lock_irqsave(&port->port_lock, flags);
+		gser->notify_modem = ghsuart_send_controlbits_tomodem;
+		port->port_usb = gptr;
+		spin_unlock_irqrestore(&port->port_lock, flags);
+	} else {
+		gr = gptr;
+
+		spin_lock_irqsave(&port->tx_lock, flags);
+		port->in = gr->in;
+		spin_unlock_irqrestore(&port->tx_lock, flags);
+
+		spin_lock_irqsave(&port->rx_lock, flags);
+		port->out = gr->out;
+		spin_unlock_irqrestore(&port->rx_lock, flags);
+
+		port->tx_q_size = ghsuart_data_rmnet_tx_q_size;
+		port->rx_q_size = ghsuart_data_rmnet_rx_q_size;
+		gr->in->driver_data = port;
+		gr->out->driver_data = port;
+	}
+
+	ret = usb_ep_enable(port->in);
+	if (ret) {
+		pr_err("%s: usb_ep_enable failed eptype:IN ep:%p",
+				__func__, port->in);
+		goto fail;
+	}
+
+	ret = usb_ep_enable(port->out);
+	if (ret) {
+		pr_err("%s: usb_ep_enable failed eptype:OUT ep:%p",
+				__func__, port->out);
+		usb_ep_disable(port->in);
+		goto fail;
+	}
+
+	atomic_set(&port->connected, 1);
+
+	spin_lock_irqsave(&port->tx_lock, flags);
+	port->to_host = 0;
+	spin_unlock_irqrestore(&port->tx_lock, flags);
+
+	spin_lock_irqsave(&port->rx_lock, flags);
+	port->to_modem = 0;
+	port->tomodem_drp_cnt = 0;
+	spin_unlock_irqrestore(&port->rx_lock, flags);
+
+	queue_work(port->wq, &port->connect_w);
+fail:
+	return ret;
+}
+
+#define DEBUG_BUF_SIZE 1024
+static ssize_t ghsuart_data_read_stats(struct file *file,
+	char __user *ubuf, size_t count, loff_t *ppos)
+{
+	struct ghsuart_data_port	*port;
+	struct platform_driver	*pdrv;
+	char			*buf;
+	unsigned long		flags;
+	int			ret;
+	int			i;
+	int			temp = 0;
+
+	buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	for (i = 0; i < num_data_ports; i++) {
+		port = ghsuart_data_ports[i].port;
+		if (!port)
+			continue;
+		pdrv = &ghsuart_data_ports[i].pdrv;
+
+		spin_lock_irqsave(&port->rx_lock, flags);
+		temp += scnprintf(buf + temp, DEBUG_BUF_SIZE - temp,
+				"\nName:           %s\n"
+				"#PORT:%d port#:   %p\n"
+				"data_ch_open:	   %d\n"
+				"data_ch_ready:    %d\n"
+				"\n******UL INFO*****\n\n"
+				"dpkts_to_modem:   %lu\n"
+				"tomodem_drp_cnt:  %u\n"
+				"rx_buf_len:       %u\n"
+				"TX_THROTTLED      %d\n",
+				pdrv->driver.name,
+				i, port,
+				test_bit(CH_OPENED, &port->channel_sts),
+				test_bit(CH_READY, &port->channel_sts),
+				port->to_modem,
+				port->tomodem_drp_cnt,
+				port->rx_skb_q.qlen,
+				test_bit(TX_THROTTLED, &port->flags));
+		spin_unlock_irqrestore(&port->rx_lock, flags);
+
+		spin_lock_irqsave(&port->tx_lock, flags);
+		temp += scnprintf(buf + temp, DEBUG_BUF_SIZE - temp,
+				"\n******DL INFO******\n\n"
+				"dpkts_to_usbhost: %lu\n"
+				"tx_buf_len:	   %u\n"
+				"RX_THROTTLED	   %d\n",
+				port->to_host,
+				port->tx_skb_q.qlen,
+				test_bit(RX_THROTTLED, &port->flags));
+		spin_unlock_irqrestore(&port->tx_lock, flags);
+
+	}
+
+	ret = simple_read_from_buffer(ubuf, count, ppos, buf, temp);
+
+	kfree(buf);
+
+	return ret;
+}
+
+static ssize_t ghsuart_data_reset_stats(struct file *file,
+	const char __user *buf, size_t count, loff_t *ppos)
+{
+	struct ghsuart_data_port	*port;
+	int			i;
+	unsigned long		flags;
+
+	for (i = 0; i < num_data_ports; i++) {
+		port = ghsuart_data_ports[i].port;
+		if (!port)
+			continue;
+
+		spin_lock_irqsave(&port->rx_lock, flags);
+		port->to_modem = 0;
+		port->tomodem_drp_cnt = 0;
+		spin_unlock_irqrestore(&port->rx_lock, flags);
+
+		spin_lock_irqsave(&port->tx_lock, flags);
+		port->to_host = 0;
+		spin_unlock_irqrestore(&port->tx_lock, flags);
+	}
+	return count;
+}
+
+const struct file_operations ghsuart_data_stats_ops = {
+	.read = ghsuart_data_read_stats,
+	.write = ghsuart_data_reset_stats,
+};
+
+static struct dentry	*ghsuart_data_dent;
+static int ghsuart_data_debugfs_init(void)
+{
+	struct dentry	 *ghsuart_data_dfile;
+
+	ghsuart_data_dent = debugfs_create_dir("ghsic_data_xport", 0);
+	if (!ghsuart_data_dent || IS_ERR(ghsuart_data_dent))
+		return -ENODEV;
+
+	ghsuart_data_dfile = debugfs_create_file("status", S_IRUGO | S_IWUSR,
+				 ghsuart_data_dent, 0, &ghsuart_data_stats_ops);
+	if (!ghsuart_data_dfile || IS_ERR(ghsuart_data_dfile)) {
+		debugfs_remove(ghsuart_data_dent);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static void ghsuart_data_debugfs_exit(void)
+{
+	debugfs_remove_recursive(ghsuart_data_dent);
+}
+
+int ghsuart_data_setup(unsigned num_ports, enum gadget_type gtype)
+{
+	int		first_port_id = num_data_ports;
+	int		total_num_ports = num_ports + num_data_ports;
+	int		ret = 0;
+	int		i;
+
+	if (!num_ports || total_num_ports > NUM_PORTS) {
+		pr_err("%s: Invalid num of ports count:%d\n",
+				__func__, num_ports);
+		return -EINVAL;
+	}
+	pr_debug("%s: count: %d\n", __func__, num_ports);
+
+	for (i = first_port_id; i < total_num_ports; i++) {
+
+		/*probe can be called while port_alloc,so update no_data_ports*/
+		num_data_ports++;
+		ret = ghsuart_data_port_alloc(i, gtype);
+		if (ret) {
+			num_data_ports--;
+			pr_err("%s: Unable to alloc port:%d\n", __func__, i);
+			goto free_ports;
+		}
+	}
+
+	/*return the starting index*/
+	return first_port_id;
+
+free_ports:
+	for (i = first_port_id; i < num_data_ports; i++)
+		ghsuart_data_port_free(i);
+		num_data_ports = first_port_id;
+
+	return ret;
+}
+
+static int __init ghsuart_data_init(void)
+{
+	int ret;
+
+	ret = ghsuart_data_debugfs_init();
+	if (ret) {
+		pr_debug("mode debugfs file is not available");
+		return ret;
+	}
+
+	return 0;
+}
+module_init(ghsuart_data_init);
+
+static void __exit ghsuart_data_exit(void)
+{
+	ghsuart_data_debugfs_exit();
+}
+module_exit(ghsuart_data_exit);
+
+MODULE_DESCRIPTION("hsuart data xport driver for DUN and RMNET");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 902d07cb..6aa3594 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -632,6 +632,9 @@
 	hw->hw_alt_next = QTD_NEXT(ehci, ehci->async->dummy->qtd_dma);
 
 	/* clear interrupt enables, set irq latency */
+	if (ehci->max_log2_irq_thresh)
+		log2_irq_thresh = ehci->max_log2_irq_thresh;
+
 	if (log2_irq_thresh < 0 || log2_irq_thresh > 6)
 		log2_irq_thresh = 0;
 	temp = 1 << (16 + log2_irq_thresh);
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index af638f4..4e7c35f 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -261,6 +261,11 @@
 		if (t1 & PORT_OWNER)
 			set_bit(port, &ehci->owned_ports);
 		else if ((t1 & PORT_PE) && !(t1 & PORT_SUSPEND)) {
+			/*clear RS bit before setting SUSP bit
+			* and wait for HCH to get set*/
+			if (ehci->susp_sof_bug)
+				ehci_halt(ehci);
+
 			t2 |= PORT_SUSPEND;
 			set_bit(port, &ehci->bus_suspended);
 		}
@@ -311,8 +316,10 @@
 	if (ehci->bus_suspended)
 		udelay(150);
 
-	/* turn off now-idle HC */
-	ehci_halt (ehci);
+	/*if this bit is set, controller is already haled*/
+	if (!ehci->susp_sof_bug)
+		ehci_halt(ehci); /* turn off now-idle HC */
+
 	hcd->state = HC_STATE_SUSPENDED;
 
 	if (ehci->reclaim)
@@ -1199,8 +1206,10 @@
 			if ((temp & PORT_PE) == 0
 					|| (temp & PORT_RESET) != 0)
 				goto error;
-
-			ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
+			/*port gets suspended as part of bus suspend routine*/
+			if (!ehci->susp_sof_bug)
+				ehci_writel(ehci, temp | PORT_SUSPEND,
+						status_reg);
 #ifdef	CONFIG_USB_OTG
 			if (hcd->self.otg_port == (wIndex + 1) &&
 					hcd->self.b_hnp_enable) {
@@ -1215,7 +1224,11 @@
 			 */
 			temp &= ~PORT_WKCONN_E;
 			temp |= PORT_WKDISC_E | PORT_WKOC_E;
-			ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
+			if (ehci->susp_sof_bug)
+				ehci_writel(ehci, temp, status_reg);
+			else
+				ehci_writel(ehci, temp | PORT_SUSPEND,
+						status_reg);
 			if (hostpc_reg) {
 				spin_unlock_irqrestore(&ehci->lock, flags);
 				msleep(5);/* 5ms for HCD enter low pwr mode */
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index 82373e2..5ed16cc 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -39,6 +39,7 @@
 #include <mach/msm_iomap.h>
 #include <mach/msm_xo.h>
 #include <linux/spinlock.h>
+#include <linux/cpu.h>
 
 #define MSM_USB_BASE (hcd->regs)
 
@@ -56,11 +57,191 @@
 	struct wake_lock	wlock;
 	int			peripheral_status_irq;
 	int			wakeup_irq;
+	int			wakeup_gpio;
 	bool			wakeup_irq_enabled;
+	atomic_t		pm_usage_cnt;
 	uint32_t		bus_perf_client;
+	uint32_t		wakeup_int_cnt;
 };
 
 static bool debug_bus_voting_enabled = true;
+
+static unsigned int enable_dbg_log = 1;
+module_param(enable_dbg_log, uint, S_IRUGO | S_IWUSR);
+/*by default log ep0 and efs sync ep*/
+static unsigned int ep_addr_rxdbg_mask = 9;
+module_param(ep_addr_rxdbg_mask, uint, S_IRUGO | S_IWUSR);
+static unsigned int ep_addr_txdbg_mask = 9;
+module_param(ep_addr_txdbg_mask, uint, S_IRUGO | S_IWUSR);
+
+/* Maximum debug message length */
+#define DBG_MSG_LEN   100UL
+
+/* Maximum number of messages */
+#define DBG_MAX_MSG   256UL
+
+#define TIME_BUF_LEN  20
+
+enum event_type {
+	EVENT_UNDEF = -1,
+	URB_SUBMIT,
+	URB_COMPLETE,
+	EVENT_NONE,
+};
+
+#define EVENT_STR_LEN	5
+
+static char *event_to_str(enum event_type e)
+{
+	switch (e) {
+	case URB_SUBMIT:
+		return "S";
+	case URB_COMPLETE:
+		return "C";
+	case EVENT_NONE:
+		return "NONE";
+	default:
+		return "UNDEF";
+	}
+}
+
+static enum event_type str_to_event(const char *name)
+{
+	if (!strncasecmp("S", name, EVENT_STR_LEN))
+		return URB_SUBMIT;
+	if (!strncasecmp("C", name, EVENT_STR_LEN))
+		return URB_COMPLETE;
+	if (!strncasecmp("", name, EVENT_STR_LEN))
+		return EVENT_NONE;
+
+	return EVENT_UNDEF;
+}
+
+/*log ep0 activity*/
+static struct {
+	char     (buf[DBG_MAX_MSG])[DBG_MSG_LEN];   /* buffer */
+	unsigned idx;   /* index */
+	rwlock_t lck;   /* lock */
+} dbg_hsic_ctrl = {
+	.idx = 0,
+	.lck = __RW_LOCK_UNLOCKED(lck)
+};
+
+static struct {
+	char     (buf[DBG_MAX_MSG])[DBG_MSG_LEN];   /* buffer */
+	unsigned idx;   /* index */
+	rwlock_t lck;   /* lock */
+} dbg_hsic_data = {
+	.idx = 0,
+	.lck = __RW_LOCK_UNLOCKED(lck)
+};
+
+/**
+ * dbg_inc: increments debug event index
+ * @idx: buffer index
+ */
+static void dbg_inc(unsigned *idx)
+{
+	*idx = (*idx + 1) & (DBG_MAX_MSG-1);
+}
+
+/*get_timestamp - returns time of day in us */
+static char *get_timestamp(char *tbuf)
+{
+	unsigned long long t;
+	unsigned long nanosec_rem;
+
+	t = cpu_clock(smp_processor_id());
+	nanosec_rem = do_div(t, 1000000000)/1000;
+	scnprintf(tbuf, TIME_BUF_LEN, "[%5lu.%06lu] ", (unsigned long)t,
+		nanosec_rem);
+	return tbuf;
+}
+
+static int allow_dbg_log(int ep_addr)
+{
+	int dir, num;
+
+	dir = ep_addr & USB_DIR_IN ? USB_DIR_IN : USB_DIR_OUT;
+	num = ep_addr & ~USB_DIR_IN;
+	num = 1 << num;
+
+	if ((dir == USB_DIR_IN) && (num & ep_addr_rxdbg_mask))
+		return 1;
+	if ((dir == USB_DIR_OUT) && (num & ep_addr_txdbg_mask))
+		return 1;
+
+	return 0;
+}
+
+static void dbg_log_event(struct urb *urb, char * event, unsigned extra)
+{
+	unsigned long flags;
+	int ep_addr;
+	char tbuf[TIME_BUF_LEN];
+
+	if (!enable_dbg_log)
+		return;
+
+	if (!urb) {
+		write_lock_irqsave(&dbg_hsic_ctrl.lck, flags);
+		scnprintf(dbg_hsic_ctrl.buf[dbg_hsic_ctrl.idx], DBG_MSG_LEN,
+			"%s: %s : %u\n", get_timestamp(tbuf), event, extra);
+		dbg_inc(&dbg_hsic_ctrl.idx);
+		write_unlock_irqrestore(&dbg_hsic_ctrl.lck, flags);
+		return;
+	}
+
+	ep_addr = urb->ep->desc.bEndpointAddress;
+	if (!allow_dbg_log(ep_addr))
+		return;
+
+	if ((ep_addr & 0x0f) == 0x0) {
+		/*submit event*/
+		if (!str_to_event(event)) {
+			write_lock_irqsave(&dbg_hsic_ctrl.lck, flags);
+			scnprintf(dbg_hsic_ctrl.buf[dbg_hsic_ctrl.idx],
+				DBG_MSG_LEN, "%s: [%s : %p]:[%s] "
+				  "%02x %02x %04x %04x %04x  %u %d\n",
+				  get_timestamp(tbuf), event, urb,
+				  (ep_addr & USB_DIR_IN) ? "in" : "out",
+				  urb->setup_packet[0], urb->setup_packet[1],
+				  (urb->setup_packet[3] << 8) |
+				  urb->setup_packet[2],
+				  (urb->setup_packet[5] << 8) |
+				  urb->setup_packet[4],
+				  (urb->setup_packet[7] << 8) |
+				  urb->setup_packet[6],
+				  urb->transfer_buffer_length, urb->status);
+
+			dbg_inc(&dbg_hsic_ctrl.idx);
+			write_unlock_irqrestore(&dbg_hsic_ctrl.lck, flags);
+		} else {
+			write_lock_irqsave(&dbg_hsic_ctrl.lck, flags);
+			scnprintf(dbg_hsic_ctrl.buf[dbg_hsic_ctrl.idx],
+				DBG_MSG_LEN, "%s: [%s : %p]:[%s] %u %d\n",
+				  get_timestamp(tbuf), event, urb,
+				  (ep_addr & USB_DIR_IN) ? "in" : "out",
+				  urb->actual_length, extra);
+
+			dbg_inc(&dbg_hsic_ctrl.idx);
+			write_unlock_irqrestore(&dbg_hsic_ctrl.lck, flags);
+		}
+	} else {
+		write_lock_irqsave(&dbg_hsic_data.lck, flags);
+		scnprintf(dbg_hsic_data.buf[dbg_hsic_data.idx], DBG_MSG_LEN,
+			  "%s: [%s : %p]:ep%d[%s]  %u %d\n",
+			  get_timestamp(tbuf), event, urb, ep_addr & 0x0f,
+			  (ep_addr & USB_DIR_IN) ? "in" : "out",
+			  str_to_event(event) ? urb->actual_length :
+			  urb->transfer_buffer_length,
+			  str_to_event(event) ?  extra : urb->status);
+
+		dbg_inc(&dbg_hsic_data.idx);
+		write_unlock_irqrestore(&dbg_hsic_data.lck, flags);
+	}
+}
+
 static inline struct msm_hsic_hcd *hcd_to_hsic(struct usb_hcd *hcd)
 {
 	return (struct msm_hsic_hcd *) (hcd->hcd_priv);
@@ -186,9 +367,20 @@
 		goto free_strobe;
 		}
 
+	if (mehci->wakeup_gpio) {
+		rc = gpio_request(mehci->wakeup_gpio, "HSIC_WAKEUP_GPIO");
+		if (rc < 0) {
+			dev_err(mehci->dev, "gpio request failed for HSIC WAKEUP\n");
+			goto free_data;
+		}
+	}
+
 	return 0;
 
 free_gpio:
+	if (mehci->wakeup_gpio)
+		gpio_free(mehci->wakeup_gpio);
+free_data:
 	gpio_free(pdata->data);
 free_strobe:
 	gpio_free(pdata->strobe);
@@ -321,6 +513,9 @@
 		ulpi_write(mehci, 0xA9, 0x30);
 	}
 
+	/*disable auto resume*/
+	ulpi_write(mehci, ULPI_IFC_CTRL_AUTORESUME, ULPI_CLR(ULPI_IFC_CTRL));
+
 	return 0;
 }
 
@@ -339,6 +534,12 @@
 		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 */
@@ -408,6 +609,11 @@
 
 	atomic_set(&mehci->in_lpm, 1);
 	enable_irq(hcd->irq);
+
+	mehci->wakeup_irq_enabled = 1;
+	enable_irq_wake(mehci->wakeup_irq);
+	enable_irq(mehci->wakeup_irq);
+
 	wake_unlock(&mehci->wlock);
 
 	dev_info(mehci->dev, "HSIC-USB in low power mode\n");
@@ -426,6 +632,12 @@
 		return 0;
 	}
 
+	if (mehci->wakeup_irq_enabled) {
+		disable_irq_wake(mehci->wakeup_irq);
+		disable_irq_nosync(mehci->wakeup_irq);
+		mehci->wakeup_irq_enabled = 0;
+	}
+
 	wake_lock(&mehci->wlock);
 
 	if (mehci->bus_perf_client && debug_bus_voting_enabled) {
@@ -478,6 +690,15 @@
 
 skip_phy_resume:
 
+	if (!(readl_relaxed(USB_USBCMD) & CMD_RUN) &&
+			(readl_relaxed(USB_PORTSC) & PORT_SUSPEND)) {
+		writel_relaxed(readl_relaxed(USB_USBCMD) | CMD_RUN ,
+				USB_USBCMD);
+		dbg_log_event(NULL, "Set RS", readl_relaxed(USB_USBCMD));
+	}
+
+	usb_hcd_resume_root_hub(hcd);
+
 	atomic_set(&mehci->in_lpm, 0);
 
 	if (mehci->async_int) {
@@ -486,6 +707,11 @@
 		enable_irq(hcd->irq);
 	}
 
+	if (atomic_read(&mehci->pm_usage_cnt)) {
+		atomic_set(&mehci->pm_usage_cnt, 0);
+		pm_runtime_put_noidle(mehci->dev);
+	}
+
 	dev_info(mehci->dev, "HSIC-USB exited from low power mode\n");
 
 	return 0;
@@ -548,6 +774,25 @@
 	return 0;
 }
 
+static int ehci_hsic_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
+		gfp_t mem_flags)
+{
+	dbg_log_event(urb, event_to_str(URB_SUBMIT), 0);
+	return ehci_urb_enqueue(hcd, urb, mem_flags);
+}
+
+static int ehci_hsic_bus_suspend(struct usb_hcd *hcd)
+{
+	dbg_log_event(NULL, "Suspend RH", 0);
+	return ehci_bus_suspend(hcd);
+}
+
+static int ehci_hsic_bus_resume(struct usb_hcd *hcd)
+{
+	dbg_log_event(NULL, "Resume RH", 0);
+	return ehci_bus_resume(hcd);
+}
+
 static struct hc_driver msm_hsic_driver = {
 	.description		= hcd_name,
 	.product_desc		= "Qualcomm EHCI Host Controller using HSIC",
@@ -568,7 +813,7 @@
 	/*
 	 * managing i/o requests and associated device resources
 	 */
-	.urb_enqueue		= ehci_urb_enqueue,
+	.urb_enqueue		= ehci_hsic_urb_enqueue,
 	.urb_dequeue		= ehci_urb_dequeue,
 	.endpoint_disable	= ehci_endpoint_disable,
 	.endpoint_reset		= ehci_endpoint_reset,
@@ -590,8 +835,10 @@
 	/*
 	 * PM support
 	 */
-	.bus_suspend		= ehci_bus_suspend,
-	.bus_resume		= ehci_bus_resume,
+	.bus_suspend		= ehci_hsic_bus_suspend,
+	.bus_resume		= ehci_hsic_bus_resume,
+
+	.log_urb_complete	= dbg_log_event,
 };
 
 static int msm_hsic_init_clocks(struct msm_hsic_hcd *mehci, u32 init)
@@ -687,7 +934,12 @@
 {
 	struct msm_hsic_hcd *mehci = data;
 
-	dev_dbg(mehci->dev, "%s: hsic remote wakeup interrupt\n", __func__);
+	mehci->wakeup_int_cnt++;
+	dbg_log_event(NULL, "Remote Wakeup IRQ", mehci->wakeup_int_cnt);
+	dev_dbg(mehci->dev, "%s: hsic remote wakeup interrupt cnt: %u\n",
+			__func__, mehci->wakeup_int_cnt);
+
+	wake_lock(&mehci->wlock);
 
 	if (mehci->wakeup_irq_enabled) {
 		mehci->wakeup_irq_enabled = 0;
@@ -695,6 +947,11 @@
 		disable_irq_nosync(irq);
 	}
 
+	if (!atomic_read(&mehci->pm_usage_cnt)) {
+		atomic_set(&mehci->pm_usage_cnt, 1);
+		pm_runtime_get(mehci->dev);
+	}
+
 	return IRQ_HANDLED;
 }
 
@@ -751,6 +1008,89 @@
 	.release = single_release,
 };
 
+static int ehci_hsic_msm_wakeup_cnt_show(struct seq_file *s, void *unused)
+{
+	struct msm_hsic_hcd *mehci = s->private;
+
+	seq_printf(s, "%u\n", mehci->wakeup_int_cnt);
+
+	return 0;
+}
+
+static int ehci_hsic_msm_wakeup_cnt_open(struct inode *inode, struct file *f)
+{
+	return single_open(f, ehci_hsic_msm_wakeup_cnt_show, inode->i_private);
+}
+
+const struct file_operations ehci_hsic_msm_wakeup_cnt_fops = {
+	.open = ehci_hsic_msm_wakeup_cnt_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static int ehci_hsic_msm_data_events_show(struct seq_file *s, void *unused)
+{
+	unsigned long	flags;
+	unsigned	i;
+
+	read_lock_irqsave(&dbg_hsic_data.lck, flags);
+
+	i = dbg_hsic_data.idx;
+	for (dbg_inc(&i); i != dbg_hsic_data.idx; dbg_inc(&i)) {
+		if (!strnlen(dbg_hsic_data.buf[i], DBG_MSG_LEN))
+			continue;
+		seq_printf(s, "%s\n", dbg_hsic_data.buf[i]);
+	}
+
+	read_unlock_irqrestore(&dbg_hsic_data.lck, flags);
+
+	return 0;
+}
+
+static int ehci_hsic_msm_data_events_open(struct inode *inode, struct file *f)
+{
+	return single_open(f, ehci_hsic_msm_data_events_show, inode->i_private);
+}
+
+const struct file_operations ehci_hsic_msm_dbg_data_fops = {
+	.open = ehci_hsic_msm_data_events_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static int ehci_hsic_msm_ctrl_events_show(struct seq_file *s, void *unused)
+{
+	unsigned long	flags;
+	unsigned	i;
+
+	read_lock_irqsave(&dbg_hsic_ctrl.lck, flags);
+
+	i = dbg_hsic_ctrl.idx;
+	for (dbg_inc(&i); i != dbg_hsic_ctrl.idx; dbg_inc(&i)) {
+		if (!strnlen(dbg_hsic_ctrl.buf[i], DBG_MSG_LEN))
+			continue;
+		seq_printf(s, "%s\n", dbg_hsic_ctrl.buf[i]);
+	}
+
+	read_unlock_irqrestore(&dbg_hsic_ctrl.lck, flags);
+
+	return 0;
+}
+
+static int ehci_hsic_msm_ctrl_events_open(struct inode *inode, struct file *f)
+{
+	return single_open(f, ehci_hsic_msm_ctrl_events_show, inode->i_private);
+}
+
+const struct file_operations ehci_hsic_msm_dbg_ctrl_fops = {
+	.open = ehci_hsic_msm_ctrl_events_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
 static struct dentry *ehci_hsic_msm_dbg_root;
 static int ehci_hsic_msm_debugfs_init(struct msm_hsic_hcd *mehci)
 {
@@ -771,6 +1111,36 @@
 		return -ENODEV;
 	}
 
+	ehci_hsic_msm_dentry = debugfs_create_file("wakeup_cnt",
+		S_IRUGO,
+		ehci_hsic_msm_dbg_root, mehci,
+		&ehci_hsic_msm_wakeup_cnt_fops);
+
+	if (!ehci_hsic_msm_dentry) {
+		debugfs_remove_recursive(ehci_hsic_msm_dbg_root);
+		return -ENODEV;
+	}
+
+	ehci_hsic_msm_dentry = debugfs_create_file("show_ctrl_events",
+		S_IRUGO,
+		ehci_hsic_msm_dbg_root, mehci,
+		&ehci_hsic_msm_dbg_ctrl_fops);
+
+	if (!ehci_hsic_msm_dentry) {
+		debugfs_remove_recursive(ehci_hsic_msm_dbg_root);
+		return -ENODEV;
+	}
+
+	ehci_hsic_msm_dentry = debugfs_create_file("show_data_events",
+		S_IRUGO,
+		ehci_hsic_msm_dbg_root, mehci,
+		&ehci_hsic_msm_dbg_data_fops);
+
+	if (!ehci_hsic_msm_dentry) {
+		debugfs_remove_recursive(ehci_hsic_msm_dbg_root);
+		return -ENODEV;
+	}
+
 	return 0;
 }
 
@@ -830,12 +1200,23 @@
 	mehci = hcd_to_hsic(hcd);
 	mehci->dev = &pdev->dev;
 
+	mehci->ehci.susp_sof_bug = 1;
+
+	mehci->ehci.max_log2_irq_thresh = 6;
+
 	res = platform_get_resource_byname(pdev,
 			IORESOURCE_IRQ,
 			"peripheral_status_irq");
 	if (res)
 		mehci->peripheral_status_irq = res->start;
 
+	res = platform_get_resource_byname(pdev, IORESOURCE_IO, "wakeup");
+	if (res) {
+		mehci->wakeup_gpio = res->start;
+		mehci->wakeup_irq = MSM_GPIO_TO_INT(res->start);
+		dev_dbg(mehci->dev, "wakeup_irq: %d\n", mehci->wakeup_irq);
+	}
+
 	ret = msm_hsic_init_clocks(mehci, 1);
 	if (ret) {
 		dev_err(&pdev->dev, "unable to initialize clocks\n");
@@ -878,12 +1259,9 @@
 	}
 
 	/* configure wakeup irq */
-	ret = platform_get_irq(pdev, 2);
-	if (ret > 0) {
-		mehci->wakeup_irq = ret;
-		dev_dbg(&pdev->dev, "wakeup_irq: %d\n", mehci->wakeup_irq);
+	if (mehci->wakeup_irq) {
 		ret = request_irq(mehci->wakeup_irq, msm_hsic_wakeup_irq,
-				IRQF_TRIGGER_LOW,
+				IRQF_TRIGGER_HIGH,
 				"msm_hsic_wakeup", mehci);
 		if (!ret) {
 			disable_irq_nosync(mehci->wakeup_irq);
@@ -988,6 +1366,8 @@
 
 	dev_dbg(dev, "ehci-msm-hsic PM suspend\n");
 
+	dbg_log_event(NULL, "PM Suspend", 0);
+
 	if (device_may_wakeup(dev))
 		enable_irq_wake(hcd->irq);
 
@@ -999,39 +1379,17 @@
 	return ret;
 }
 
-static int msm_hsic_pm_suspend_noirq(struct device *dev)
-{
-	struct usb_hcd *hcd = dev_get_drvdata(dev);
-	struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
-
-	dev_dbg(dev, "ehci-msm-hsic PM suspend_noirq\n");
-
-	if (device_may_wakeup(dev) && !mehci->wakeup_irq_enabled) {
-		enable_irq(mehci->wakeup_irq);
-		enable_irq_wake(mehci->wakeup_irq);
-		mehci->wakeup_irq_enabled = 1;
-	}
-
-	return 0;
-}
-
 static int msm_hsic_pm_resume(struct device *dev)
 {
 	int ret;
 	struct usb_hcd *hcd = dev_get_drvdata(dev);
 	struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
 
-	dev_dbg(dev, "ehci-msm-hsic PM resume\n");
+	dbg_log_event(NULL, "PM Resume", 0);
 
 	if (device_may_wakeup(dev))
 		disable_irq_wake(hcd->irq);
 
-	if (mehci->wakeup_irq_enabled) {
-		mehci->wakeup_irq_enabled = 0;
-		disable_irq_wake(mehci->wakeup_irq);
-		disable_irq_nosync(mehci->wakeup_irq);
-	}
-
 	ret = msm_hsic_resume(mehci);
 	if (ret)
 		return ret;
@@ -1058,6 +1416,9 @@
 	struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
 
 	dev_dbg(dev, "EHCI runtime suspend\n");
+
+	dbg_log_event(NULL, "Run Time PM Suspend", 0);
+
 	return msm_hsic_suspend(mehci);
 }
 
@@ -1067,6 +1428,9 @@
 	struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
 
 	dev_dbg(dev, "EHCI runtime resume\n");
+
+	dbg_log_event(NULL, "Run Time PM Resume", 0);
+
 	return msm_hsic_resume(mehci);
 }
 #endif
@@ -1074,7 +1438,6 @@
 #ifdef CONFIG_PM
 static const struct dev_pm_ops msm_hsic_dev_pm_ops = {
 	SET_SYSTEM_SLEEP_PM_OPS(msm_hsic_pm_suspend, msm_hsic_pm_resume)
-	.suspend_noirq = msm_hsic_pm_suspend_noirq,
 	SET_RUNTIME_PM_OPS(msm_hsic_runtime_suspend, msm_hsic_runtime_resume,
 				msm_hsic_runtime_idle)
 };
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 3a5a5cc..a49ab99 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -124,6 +124,8 @@
 	ktime_t			last_periodic_enable;
 	u32			command;
 
+	unsigned		max_log2_irq_thresh;
+
 	/* SILICON QUIRKS */
 	unsigned		no_selective_suspend:1;
 	unsigned		has_fsl_port_bug:1; /* FreeScale */
@@ -138,6 +140,7 @@
 	unsigned		use_dummy_qh:1;	/* AMD Frame List table quirk*/
 	unsigned		has_synopsys_hc_bug:1; /* Synopsys HC */
 	unsigned		frame_index_bug:1; /* MosChip (AKA NetMos) */
+	unsigned		susp_sof_bug:1; /*Chip Idea HC*/
 
 	/* required for usb32 quirk */
 	#define OHCI_CTRL_HCFS          (3 << 6)
diff --git a/drivers/usb/misc/mdm_ctrl_bridge.c b/drivers/usb/misc/mdm_ctrl_bridge.c
index c23c7b1..49591cd 100644
--- a/drivers/usb/misc/mdm_ctrl_bridge.c
+++ b/drivers/usb/misc/mdm_ctrl_bridge.c
@@ -255,7 +255,7 @@
 	}
 }
 
-int ctrl_bridge_start_read(struct ctrl_bridge *dev)
+static int ctrl_bridge_start_read(struct ctrl_bridge *dev)
 {
 	int	retval = 0;
 
@@ -281,7 +281,6 @@
 int ctrl_bridge_open(struct bridge *brdg)
 {
 	struct ctrl_bridge	*dev;
-	int			ret;
 
 	if (!brdg) {
 		err("bridge is null\n");
@@ -304,16 +303,10 @@
 	dev->set_ctrl_line_sts = 0;
 	dev->notify_ser_state = 0;
 
-	ret = usb_autopm_get_interface(dev->intf);
-	if (ret < 0) {
-		dev_err(&dev->udev->dev, "%s autopm_get fail: %d\n",
-			__func__, ret);
-		return ret;
-	}
+	if (brdg->ops.send_cbits)
+		brdg->ops.send_cbits(brdg->ctx, dev->cbits_tohost);
 
-	ret = ctrl_bridge_start_read(dev);
-	usb_autopm_put_interface(dev->intf);
-	return ret;
+	return 0;
 }
 EXPORT_SYMBOL(ctrl_bridge_open);
 
@@ -504,11 +497,7 @@
 		}
 	}
 
-	/* if the bridge is open, resume reading */
-	if (dev->brdg)
-		return ctrl_bridge_start_read(dev);
-
-	return 0;
+	return ctrl_bridge_start_read(dev);
 }
 
 #if defined(CONFIG_DEBUG_FS)
@@ -711,7 +700,7 @@
 
 	ch_id++;
 
-	return retval;
+	return ctrl_bridge_start_read(dev);
 
 free_rbuf:
 	kfree(dev->readbuf);
diff --git a/drivers/usb/otg/msm72k_otg.c b/drivers/usb/otg/msm72k_otg.c
index 0ee1827..891a4e2 100644
--- a/drivers/usb/otg/msm72k_otg.c
+++ b/drivers/usb/otg/msm72k_otg.c
@@ -889,7 +889,13 @@
 	if (can_phy_power_collapse(dev) && dev->pdata->ldo_enable)
 		dev->pdata->ldo_enable(1);
 
-	msm_otg_get_resume(dev);
+	if (pm_runtime_enabled(dev->otg.dev)) {
+		msm_otg_get_resume(dev);
+	} else {
+		pm_runtime_get_noresume(dev->otg.dev);
+		msm_otg_resume(dev);
+		pm_runtime_set_active(dev->otg.dev);
+	}
 
 	if (!is_phy_clk_disabled())
 		goto phy_resumed;
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index deb4064..d3e92f2 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -75,6 +75,7 @@
 static struct regulator *hsusb_vddcx;
 static struct regulator *vbus_otg;
 static struct regulator *mhl_analog_switch;
+static struct power_supply *psy;
 
 static bool aca_id_turned_on;
 static inline bool aca_enabled(void)
@@ -673,8 +674,7 @@
 {
 	struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
 
-	if (aca_enabled() || (test_bit(ID, &motg->inputs) &&
-				 !test_bit(ID_A, &motg->inputs)))
+	if (aca_enabled())
 		return 0;
 
 	if (suspend) {
@@ -688,6 +688,14 @@
 			clear_bit(A_BUS_REQ, &motg->inputs);
 			queue_work(system_nrt_wq, &motg->sm_work);
 			break;
+		case OTG_STATE_B_PERIPHERAL:
+			pr_debug("peripheral bus suspend\n");
+			if (!(motg->caps & ALLOW_LPM_ON_DEV_SUSPEND))
+				break;
+			set_bit(A_BUS_SUSPEND, &motg->inputs);
+			queue_work(system_nrt_wq, &motg->sm_work);
+			break;
+
 		default:
 			break;
 		}
@@ -701,6 +709,13 @@
 			/* ensure hardware is not in low power mode */
 			pm_runtime_resume(otg->dev);
 			break;
+		case OTG_STATE_B_PERIPHERAL:
+			pr_debug("peripheral bus resume\n");
+			if (!(motg->caps & ALLOW_LPM_ON_DEV_SUSPEND))
+				break;
+			clear_bit(A_BUS_SUSPEND, &motg->inputs);
+			queue_work(system_nrt_wq, &motg->sm_work);
+			break;
 		default:
 			break;
 		}
@@ -718,7 +733,7 @@
 	struct usb_bus *bus = otg->host;
 	struct msm_otg_platform_data *pdata = motg->pdata;
 	int cnt = 0;
-	bool host_bus_suspend, dcp;
+	bool host_bus_suspend, device_bus_suspend, dcp;
 	u32 phy_ctrl_val = 0, cmd_val;
 	unsigned ret;
 	u32 portsc;
@@ -728,6 +743,9 @@
 
 	disable_irq(motg->irq);
 	host_bus_suspend = otg->host && !test_bit(ID, &motg->inputs);
+	device_bus_suspend = otg->gadget && test_bit(ID, &motg->inputs) &&
+		test_bit(A_BUS_SUSPEND, &motg->inputs) &&
+		motg->caps & ALLOW_LPM_ON_DEV_SUSPEND;
 	dcp = motg->chg_type == USB_DCP_CHARGER;
 	/*
 	 * Chipidea 45-nm PHY suspend sequence:
@@ -791,8 +809,8 @@
 	 * PMIC notifications are unavailable.
 	 */
 	cmd_val = readl_relaxed(USB_USBCMD);
-	if (host_bus_suspend || (motg->pdata->otg_control == OTG_PHY_CONTROL &&
-				dcp))
+	if (host_bus_suspend || device_bus_suspend ||
+		(motg->pdata->otg_control == OTG_PHY_CONTROL && dcp))
 		cmd_val |= ASYNC_INTR_CTRL | ULPI_STP_CTRL;
 	else
 		cmd_val |= ULPI_STP_CTRL;
@@ -802,7 +820,8 @@
 	 * BC1.2 spec mandates PD to enable VDP_SRC when charging from DCP.
 	 * PHY retention and collapse can not happen with VDP_SRC enabled.
 	 */
-	if (motg->caps & ALLOW_PHY_RETENTION && !host_bus_suspend && !dcp) {
+	if (motg->caps & ALLOW_PHY_RETENTION && !host_bus_suspend &&
+		!device_bus_suspend && !dcp) {
 		phy_ctrl_val = readl_relaxed(USB_PHY_CTRL);
 		if (motg->pdata->otg_control == OTG_PHY_CONTROL)
 			/* Enable PHY HV interrupts to wake MPM/Link */
@@ -819,10 +838,14 @@
 	clk_disable_unprepare(motg->core_clk);
 
 	/* usb phy no more require TCXO clock, hence vote for TCXO disable */
-	ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_OFF);
-	if (ret)
-		dev_err(otg->dev, "%s failed to devote for "
-			"TCXO D0 buffer%d\n", __func__, ret);
+	if (!host_bus_suspend) {
+		ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_OFF);
+		if (ret)
+			dev_err(otg->dev, "%s failed to devote for "
+				"TCXO D0 buffer%d\n", __func__, ret);
+		else
+			motg->lpm_flags |= XO_SHUTDOWN;
+	}
 
 	if (motg->caps & ALLOW_PHY_POWER_COLLAPSE &&
 			!host_bus_suspend && !dcp) {
@@ -867,10 +890,13 @@
 	wake_lock(&motg->wlock);
 
 	/* Vote for TCXO when waking up the phy */
-	ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_ON);
-	if (ret)
-		dev_err(otg->dev, "%s failed to vote for "
-			"TCXO D0 buffer%d\n", __func__, ret);
+	if (motg->lpm_flags & XO_SHUTDOWN) {
+		ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_ON);
+		if (ret)
+			dev_err(otg->dev, "%s failed to vote for "
+				"TCXO D0 buffer%d\n", __func__, ret);
+		motg->lpm_flags &= ~XO_SHUTDOWN;
+	}
 
 	clk_prepare_enable(motg->core_clk);
 
@@ -976,9 +1002,7 @@
 
 static int msm_otg_notify_power_supply(struct msm_otg *motg, unsigned mA)
 {
-	struct power_supply *psy;
 
-	psy = power_supply_get_by_name("usb");
 	if (!psy)
 		goto psy_not_supported;
 
@@ -1192,10 +1216,12 @@
 
 	/*
 	 * if entering host mode tell the charger to not draw any current
-	 * from usb - if exiting host mode let the charger draw current
+	 * from usb before turning on the boost.
+	 * if exiting host mode disable the boost before enabling to draw
+	 * current from the source.
 	 */
-	pm8921_disable_source_current(on);
 	if (on) {
+		pm8921_disable_source_current(on);
 		ret = regulator_enable(vbus_otg);
 		if (ret) {
 			pr_err("unable to enable vbus_otg\n");
@@ -1208,6 +1234,7 @@
 			pr_err("unable to disable vbus_otg\n");
 			return;
 		}
+		pm8921_disable_source_current(on);
 		vbus_is_on = false;
 	}
 }
@@ -1980,6 +2007,9 @@
 	case OTG_STATE_UNDEFINED:
 		msm_otg_reset(otg);
 		msm_otg_init_sm(motg);
+		psy = power_supply_get_by_name("usb");
+		if (!psy)
+			pr_err("couldn't get usb power supply\n");
 		otg->state = OTG_STATE_B_IDLE;
 		if (!test_bit(B_SESS_VLD, &motg->inputs) &&
 				test_bit(ID, &motg->inputs)) {
@@ -2130,6 +2160,13 @@
 			 */
 			otg->host->is_b_host = 1;
 			msm_otg_start_host(otg, 1);
+		} else if (test_bit(A_BUS_SUSPEND, &motg->inputs) &&
+				   test_bit(B_SESS_VLD, &motg->inputs)) {
+			pr_debug("a_bus_suspend && b_sess_vld\n");
+			if (motg->caps & ALLOW_LPM_ON_DEV_SUSPEND) {
+				pm_runtime_put_noidle(otg->dev);
+				pm_runtime_suspend(otg->dev);
+			}
 		} else if (test_bit(ID_C, &motg->inputs)) {
 			msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX);
 		}
@@ -2566,6 +2603,8 @@
 		} else {
 			pr_debug("BSV clear\n");
 			clear_bit(B_SESS_VLD, &motg->inputs);
+			clear_bit(A_BUS_SUSPEND, &motg->inputs);
+
 			msm_chg_check_aca_intr(motg);
 		}
 		work = 1;
@@ -3386,6 +3425,9 @@
 			motg->caps = ALLOW_PHY_RETENTION;
 	}
 
+	if (motg->pdata->enable_lpm_on_dev_suspend)
+		motg->caps |= ALLOW_LPM_ON_DEV_SUSPEND;
+
 	wake_lock(&motg->wlock);
 	pm_runtime_set_active(&pdev->dev);
 	pm_runtime_enable(&pdev->dev);
diff --git a/drivers/video/msm/external_common.c b/drivers/video/msm/external_common.c
index 7f603dd..0212142 100644
--- a/drivers/video/msm/external_common.c
+++ b/drivers/video/msm/external_common.c
@@ -26,6 +26,8 @@
 #include "external_common.h"
 #include "mhl_api.h"
 
+#include "mdp.h"
+
 struct external_common_state_type *external_common_state;
 EXPORT_SYMBOL(external_common_state);
 DEFINE_MUTEX(external_common_state_hpd_mutex);
@@ -77,6 +79,23 @@
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDF};
 #endif /* DEBUG_EDID */
 
+#define DMA_E_BASE 0xB0000
+void mdp_vid_quant_set(void)
+{
+	if ((external_common_state->video_resolution == \
+		HDMI_VFRMT_720x480p60_4_3) || \
+		(external_common_state->video_resolution == \
+		HDMI_VFRMT_720x480p60_16_9)) {
+		MDP_OUTP(MDP_BASE + DMA_E_BASE + 0x70, 0x00EB0010);
+		MDP_OUTP(MDP_BASE + DMA_E_BASE + 0x74, 0x00EB0010);
+		MDP_OUTP(MDP_BASE + DMA_E_BASE + 0x78, 0x00EB0010);
+	} else {
+		MDP_OUTP(MDP_BASE + DMA_E_BASE + 0x70, 0x00FF0000);
+		MDP_OUTP(MDP_BASE + DMA_E_BASE + 0x74, 0x00FF0000);
+		MDP_OUTP(MDP_BASE + DMA_E_BASE + 0x78, 0x00FF0000);
+	}
+}
+
 const char *video_format_2string(uint32 format)
 {
 	switch (format) {
diff --git a/drivers/video/msm/hdmi_msm.c b/drivers/video/msm/hdmi_msm.c
index 7f6585c..a372016 100644
--- a/drivers/video/msm/hdmi_msm.c
+++ b/drivers/video/msm/hdmi_msm.c
@@ -3641,8 +3641,8 @@
 	 0x10,	0x10,	0x10,	0x10,	0x10, 0x10, 0x10}, /*00*/
 	{0x18,	0x18,	0x28,	0x28,	0x28,	 0x28,	0x28,	0x28,	0x28,
 	 0x28,	0x28,	0x28,	0x28,	0x18, 0x28, 0x18}, /*01*/
-	{0x04,	0x04,	0x04,	0x04,	0x04,	 0x04,	0x04,	0x04,	0x04,
-	 0x04,	0x04,	0x04,	0x04,	0x88, 0x04, 0x04}, /*02*/
+	{0x00,	0x04,	0x04,	0x04,	0x04,	 0x04,	0x04,	0x04,	0x04,
+	 0x04,	0x04,	0x04,	0x04,	0x88, 0x00, 0x04}, /*02*/
 	{0x02,	0x06,	0x11,	0x15,	0x04,	 0x13,	0x10,	0x05,	0x1F,
 	 0x14,	0x20,	0x22,	0x21,	0x01, 0x03, 0x11}, /*03*/
 	{0x00,	0x01,	0x00,	0x01,	0x00,	 0x00,	0x00,	0x00,	0x00,
diff --git a/drivers/video/msm/logo.c b/drivers/video/msm/logo.c
index c061e86..57d754e 100644
--- a/drivers/video/msm/logo.c
+++ b/drivers/video/msm/logo.c
@@ -37,7 +37,7 @@
 }
 
 /* 565RLE image format: [count(2 bytes), rle(2 bytes)] */
-int load_565rle_image(char *filename)
+int load_565rle_image(char *filename, bool bf_supported)
 {
 	struct fb_info *info;
 	int fd, count, err = 0;
@@ -76,6 +76,12 @@
 
 	max = fb_width(info) * fb_height(info);
 	ptr = data;
+	if (bf_supported && (info->node == 1 || info->node == 2)) {
+		err = -EPERM;
+		pr_err("%s:%d no info->creen_base on fb%d!\n",
+		       __func__, __LINE__, info->node);
+		goto err_logo_free_data;
+	}
 	bits = (unsigned short *)(info->screen_base);
 	while (count > 3) {
 		unsigned n = ptr[0];
diff --git a/drivers/video/msm/lvds.c b/drivers/video/msm/lvds.c
index 18225fb..88c24b9 100644
--- a/drivers/video/msm/lvds.c
+++ b/drivers/video/msm/lvds.c
@@ -65,28 +65,14 @@
 	usleep(1000);
 
 	/* LVDS PHY PLL configuration */
-	MDP_OUTP(MDP_BASE + 0xc3000, 0x08);
-	MDP_OUTP(MDP_BASE + 0xc3004, 0x87);
+	MDP_OUTP(MDP_BASE + 0xc3004, 0x62);
 	MDP_OUTP(MDP_BASE + 0xc3008, 0x30);
-	MDP_OUTP(MDP_BASE + 0xc300c, 0x06);
-	MDP_OUTP(MDP_BASE + 0xc3014, 0x20);
-	MDP_OUTP(MDP_BASE + 0xc3018, 0x0F);
-	MDP_OUTP(MDP_BASE + 0xc301c, 0x01);
+	MDP_OUTP(MDP_BASE + 0xc300c, 0xc4);
+	MDP_OUTP(MDP_BASE + 0xc3014, 0x10);
+	MDP_OUTP(MDP_BASE + 0xc3018, 0x05);
+	MDP_OUTP(MDP_BASE + 0xc301c, 0x62);
 	MDP_OUTP(MDP_BASE + 0xc3020, 0x41);
 	MDP_OUTP(MDP_BASE + 0xc3024, 0x0d);
-	MDP_OUTP(MDP_BASE + 0xc3028, 0x07);
-	MDP_OUTP(MDP_BASE + 0xc302c, 0x00);
-	MDP_OUTP(MDP_BASE + 0xc3030, 0x1c);
-	MDP_OUTP(MDP_BASE + 0xc3034, 0x01);
-	MDP_OUTP(MDP_BASE + 0xc3038, 0x00);
-	MDP_OUTP(MDP_BASE + 0xc3040, 0xC0);
-	MDP_OUTP(MDP_BASE + 0xc3044, 0x00);
-	MDP_OUTP(MDP_BASE + 0xc3048, 0x30);
-	MDP_OUTP(MDP_BASE + 0xc304c, 0x00);
-
-	MDP_OUTP(MDP_BASE + 0xc3000, 0x11);
-	MDP_OUTP(MDP_BASE + 0xc3064, 0x05);
-	MDP_OUTP(MDP_BASE + 0xc3050, 0x20);
 
 	MDP_OUTP(MDP_BASE + 0xc3000, 0x01);
 	/* Wait until LVDS PLL is locked and ready */
@@ -210,6 +196,10 @@
 	if (lvds_clk)
 		clk_disable_unprepare(lvds_clk);
 
+	MDP_OUTP(MDP_BASE +  0xc3100, 0x0);
+	MDP_OUTP(MDP_BASE + 0xc3000, 0x0);
+	usleep(10);
+
 	if (lvds_pdata && lvds_pdata->lcdc_power_save)
 		lvds_pdata->lcdc_power_save(0);
 
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index 471ed4e..7fd2d91 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -93,7 +93,7 @@
 static struct delayed_work mdp_pipe_ctrl_worker;
 
 static boolean mdp_suspended = FALSE;
-DEFINE_MUTEX(mdp_suspend_mutex);
+static DEFINE_MUTEX(mdp_suspend_mutex);
 
 #ifdef CONFIG_FB_MSM_MDP40
 struct mdp_dma_data dma2_data;
@@ -659,6 +659,7 @@
 		goto error_extra;
 
 	INIT_WORK(&mgmt->mdp_histogram_worker, mdp_hist_read_work);
+	mgmt->hist = NULL;
 
 	mdp_hist_mgmt_array[index] = mgmt;
 	return 0;
@@ -685,7 +686,8 @@
 {
 	struct mdp_hist_mgmt *temp;
 	int i, ret;
-	mdp_hist_wq = alloc_workqueue("mdp_hist_wq", WQ_UNBOUND, 0);
+	mdp_hist_wq = alloc_workqueue("mdp_hist_wq",
+					WQ_NON_REENTRANT | WQ_UNBOUND, 0);
 
 	for (i = 0; i < MDP_HIST_MGMT_MAX; i++)
 		mdp_hist_mgmt_array[i] = NULL;
@@ -897,6 +899,7 @@
 	mgmt->frame_cnt = req->frame_cnt;
 	mgmt->bit_mask = req->bit_mask;
 	mgmt->num_bins = req->num_bins;
+	mgmt->hist = NULL;
 
 	ret = mdp_histogram_enable(mgmt);
 
@@ -1080,8 +1083,11 @@
 		goto error;
 	}
 
-	/* if read was triggered by an underrun, don't wake up readers*/
-	if (mgmt->mdp_is_hist_valid && mgmt->mdp_is_hist_init) {
+	/*
+	 * 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) {
 		mgmt->hist = NULL;
 		complete(&mgmt->mdp_hist_comp);
 	}
@@ -1177,6 +1183,11 @@
 		goto error_lock;
 	}
 
+	if (mgmt->hist != NULL) {
+		pr_err("%s; histogram attempted to be read twice\n", __func__);
+		ret = -EPERM;
+		goto error_lock;
+	}
 	mgmt->hist = hist;
 	mutex_unlock(&mgmt->mdp_hist_mutex);
 
@@ -1562,7 +1573,8 @@
 		__mdp_histogram_kickoff(mgmt);
 
 	if (isr & INTR_HIST_DONE) {
-		if (waitqueue_active(&mgmt->mdp_hist_comp.wait)) {
+		if ((waitqueue_active(&mgmt->mdp_hist_comp.wait))
+			 && (mgmt->hist != NULL)) {
 			if (!queue_work(mdp_hist_wq,
 						&mgmt->mdp_histogram_worker)) {
 				pr_err("%s %d- can't queue hist_read\n",
@@ -1740,7 +1752,6 @@
 	spin_lock_init(&mdp_spin_lock);
 	mdp_dma_wq = create_singlethread_workqueue("mdp_dma_wq");
 	mdp_vsync_wq = create_singlethread_workqueue("mdp_vsync_wq");
-	mdp_hist_wq = create_singlethread_workqueue("mdp_hist_wq");
 	mdp_pipe_ctrl_wq = create_singlethread_workqueue("mdp_pipe_ctrl_wq");
 	INIT_DELAYED_WORK(&mdp_pipe_ctrl_worker,
 			  mdp_pipe_ctrl_workqueue_handler);
@@ -2564,6 +2575,17 @@
 	return rc;
 }
 
+unsigned int mdp_check_suspended(void)
+{
+	unsigned int ret;
+
+	mutex_lock(&mdp_suspend_mutex);
+	ret = mdp_suspended;
+	mutex_unlock(&mdp_suspend_mutex);
+
+	return ret;
+}
+
 void mdp_footswitch_ctrl(boolean on)
 {
 	mutex_lock(&mdp_suspend_mutex);
@@ -2630,6 +2652,7 @@
 #ifdef CONFIG_FB_MSM_DTV
 	mdp4_dtv_set_black_screen();
 #endif
+	mdp4_iommu_detach();
 	mdp_footswitch_ctrl(FALSE);
 }
 
diff --git a/drivers/video/msm/mdp.h b/drivers/video/msm/mdp.h
index 6224dba..b104b33 100644
--- a/drivers/video/msm/mdp.h
+++ b/drivers/video/msm/mdp.h
@@ -801,6 +801,7 @@
 void mdp_histogram_handle_isr(struct mdp_hist_mgmt *mgmt);
 void __mdp_histogram_kickoff(struct mdp_hist_mgmt *mgmt);
 void __mdp_histogram_reset(struct mdp_hist_mgmt *mgmt);
+unsigned int mdp_check_suspended(void);
 void mdp_footswitch_ctrl(boolean on);
 
 #ifdef CONFIG_FB_MSM_MDP303
@@ -828,6 +829,10 @@
 {
 	/* empty */
 }
+static inline void mdp4_iommu_detach(void)
+{
+    /* empty */
+}
 #endif
 
 int mdp_ppp_v4l2_overlay_set(struct fb_info *info, struct mdp_overlay *req);
@@ -836,4 +841,5 @@
 	unsigned long srcp0_addr, unsigned long srcp0_size,
 	unsigned long srcp1_addr, unsigned long srcp1_size);
 
+void mdp_vid_quant_set(void);
 #endif /* MDP_H */
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index 860209f..905fc21 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -48,12 +48,6 @@
 	OVERLAY_PERF_LEVEL4
 };
 
-enum mdp4_overlay_status {
-	MDP4_OVERLAY_TYPE_UNSET,
-	MDP4_OVERLAY_TYPE_SET,
-	MDP4_OVERLAY_TYPE_MAX
-};
-
 typedef int (*cmd_fxn_t)(struct platform_device *pdev);
 
 enum {		/* display */
@@ -516,6 +510,7 @@
 struct mdp4_overlay_pipe *mdp4_overlay_stage_pipe(int mixer, int stage);
 void mdp4_mixer_stage_up(struct mdp4_overlay_pipe *pipe);
 void mdp4_mixer_stage_down(struct mdp4_overlay_pipe *pipe);
+void mdp4_mixer_pipe_cleanup(int mixer);
 int mdp4_mixer_stage_can_run(struct mdp4_overlay_pipe *pipe);
 void mdp4_overlayproc_cfg(struct mdp4_overlay_pipe *pipe);
 void mdp4_mddi_overlay(struct msm_fb_data_type *mfd);
@@ -538,7 +533,7 @@
 void mdp4_overlay0_done_lcdc(struct mdp_dma_data *dma);
 void mdp4_overlay0_done_mddi(struct mdp_dma_data *dma);
 void mdp4_dma_s_done_mddi(void);
-void mdp4_dma_p_done_mddi(void);
+void mdp4_dma_p_done_mddi(struct mdp_dma_data *dma);
 void mdp4_dma_p_done_dsi(struct mdp_dma_data *dma);
 void mdp4_dma_p_done_dsi_video(struct mdp_dma_data *dma);
 void mdp4_dma_p_done_lcdc(void);
@@ -562,10 +557,32 @@
 {
 	/* empty */
 }
+static inline void mdp4_mddi_blt_dmap_busy_wait(struct msm_fb_data_type *mfd)
+{
+	/* empty */
+}
 static inline void mdp4_mddi_overlay_restore(void)
 {
 	/* empty */
 }
+static inline void mdp4_mddi_overlay_blt_start(struct msm_fb_data_type *mfd)
+{
+	/*empty*/
+}
+static inline void mdp4_mddi_overlay_blt_stop(struct msm_fb_data_type *mfd)
+{
+	/*empty*/
+}
+static inline void mdp4_mddi_overlay_blt_offset(struct msm_fb_data_type *mfd,
+					struct msmfb_overlay_blt *req)
+{
+	/* empty */
+}
+static inline void mdp4_mddi_overlay_blt(struct msm_fb_data_type *mfd,
+					struct msmfb_overlay_blt *req)
+{
+	/* empty*/
+}
 #endif
 
 void mdp4_mddi_overlay_kickoff(struct msm_fb_data_type *mfd,
@@ -603,6 +620,13 @@
 }
 #endif
 #else
+int mdp4_mddi_overlay_blt_offset(struct msm_fb_data_type *mfd,
+					struct msmfb_overlay_blt *req);
+void mdp4_mddi_overlay_blt(struct msm_fb_data_type *mfd,
+					struct msmfb_overlay_blt *req);
+int mdp4_mddi_overlay_blt_start(struct msm_fb_data_type *mfd);
+int mdp4_mddi_overlay_blt_stop(struct msm_fb_data_type *mfd);
+void mdp4_mddi_blt_dmap_busy_wait(struct msm_fb_data_type *mfd);
 static inline int mdp4_dsi_overlay_blt_start(struct msm_fb_data_type *mfd)
 {
 	return -ENODEV;
@@ -645,9 +669,6 @@
 void mdp4_lcdc_overlay_blt_stop(struct msm_fb_data_type *mfd);
 void mdp4_dtv_overlay_blt_start(struct msm_fb_data_type *mfd);
 void mdp4_dtv_overlay_blt_stop(struct msm_fb_data_type *mfd);
-
-int mdp4_mddi_overlay_blt_offset(int *off);
-void mdp4_mddi_overlay_blt(ulong addr);
 void mdp4_overlay_panel_mode(int mixer_num, uint32 mode);
 void mdp4_overlay_panel_mode_unset(int mixer_num, uint32 mode);
 int mdp4_overlay_mixer_play(int mixer_num);
@@ -726,8 +747,6 @@
 void mdp4_overlay_dsi_video_wait4vsync(struct msm_fb_data_type *mfd);
 void mdp4_primary_vsync_dsi_video(void);
 uint32_t mdp4_ss_table_value(int8_t param, int8_t index);
-void mdp4_overlay_status_write(enum mdp4_overlay_status type, bool val);
-bool mdp4_overlay_status_read(enum mdp4_overlay_status type);
 void mdp4_overlay_ctrl_db_reset(void);
 
 int mdp4_overlay_writeback_on(struct platform_device *pdev);
@@ -766,6 +785,7 @@
 int mdp4_igc_lut_config(struct mdp_igc_lut_data *cfg);
 void mdp4_iommu_unmap(struct mdp4_overlay_pipe *pipe);
 void mdp4_iommu_attach(void);
+void mdp4_iommu_detach(void);
 int mdp4_v4l2_overlay_set(struct fb_info *info, struct mdp_overlay *req,
 		struct mdp4_overlay_pipe **ppipe);
 void mdp4_v4l2_overlay_clear(struct mdp4_overlay_pipe *pipe);
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index 34fd399..ce0dd3d 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -23,6 +23,7 @@
 #include <mach/hardware.h>
 #include <mach/iommu_domains.h>
 #include <mach/iommu.h>
+#include <linux/iommu.h>
 #include <linux/io.h>
 #include <linux/debugfs.h>
 #include <linux/fb.h>
@@ -197,19 +198,6 @@
 	}
 }
 
-/* static array with index 0 for unset status and 1 for set status */
-static bool overlay_status[MDP4_OVERLAY_TYPE_MAX];
-
-void mdp4_overlay_status_write(enum mdp4_overlay_status type, bool val)
-{
-	overlay_status[type] = val;
-}
-
-bool mdp4_overlay_status_read(enum mdp4_overlay_status type)
-{
-	return overlay_status[type];
-}
-
 void mdp4_overlay_ctrl_db_reset(void)
 {
 	int i;
@@ -287,9 +275,7 @@
 		MDP_OUTP(MDP_BASE + 0xb3014, 0x1000080);
 		MDP_OUTP(MDP_BASE + 0xb4004, 0x67686970);
 	} else {
-		MDP_OUTP(MDP_BASE + 0xb0070, 0xff0000);
-		MDP_OUTP(MDP_BASE + 0xb0074, 0xff0000);
-		MDP_OUTP(MDP_BASE + 0xb0078, 0xff0000);
+		mdp_vid_quant_set();
 	}
 
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
@@ -670,12 +656,14 @@
 		case MDP_BGR_565:
 		case MDP_XRGB_8888:
 		case MDP_RGB_888:
+		case MDP_YCBCR_H1V1:
+		case MDP_YCRCB_H1V1:
 			*luma_off = pipe->src_x * pipe->bpp;
 			break;
 
 		default:
-			pr_err("Source format %u not supported for x offset adjustment\n",
-				pipe->src_format);
+			pr_err("%s: fmt %u not supported for adjustment\n",
+				__func__, pipe->src_format);
 			break;
 		}
 	}
@@ -1497,6 +1485,21 @@
 	}
 }
 
+void mdp4_mixer_pipe_cleanup(int mixer)
+{
+	struct mdp4_overlay_pipe *pipe;
+	int j;
+
+	for (j = MDP4_MIXER_STAGE_MAX - 1; j > MDP4_MIXER_STAGE_BASE; j--) {
+		pipe = ctrl->stage[mixer][j];
+		if (pipe == NULL)
+			continue;
+		pr_debug("%s(): pipe %u\n", __func__, pipe->pipe_ndx);
+		mdp4_mixer_stage_down(pipe);
+		mdp4_overlay_pipe_free(pipe);
+	}
+}
+
 static void mdp4_mixer_stage_commit(int mixer)
 {
 	struct mdp4_overlay_pipe *pipe;
@@ -1552,15 +1555,14 @@
 			       mixer, data, flush_bits);
 
 			outpdw(MDP_BASE + off, data); /* LAYERMIXER_IN_CFG */
-			if (pull_mode)
+			if (pull_mode) {
 				outpdw(MDP_BASE + 0x18000, flush_bits);
+			/* wait for vsync on both pull mode interfaces */
+				msleep(20);
+			}
 		}
 
 		if (ctrl->mixer_cfg[MDP4_MIXER2] != cfg[MDP4_MIXER2]) {
-			/* wait for vsync on both pull mode interfaces */
-			if (pull_mode)
-				msleep(20);
-
 			off = 0x100F0;
 			ctrl->mixer_cfg[MDP4_MIXER2] = cfg[MDP4_MIXER2];
 			data = cfg[MDP4_MIXER2];
@@ -1700,7 +1702,8 @@
 			/*
 			 * If solid fill is enabled, flip and scale
 			 * have to be disabled. otherwise, h/w
-			 * underruns.
+			 * underruns. Also flush the pipe inorder
+			 * to take solid fill into effect.
 			 */
 			op_mode = inpdw(rgb_base + 0x0058);
 			op_mode &= ~(MDP4_OP_FLIP_LR + MDP4_OP_SCALEX_EN);
@@ -1708,6 +1711,7 @@
 			outpdw(rgb_base + 0x0058, op_mode);
 			outpdw(rgb_base + 0x50, rgb_src_format);
 			outpdw(rgb_base + 0x1008, constant_color);
+			mdp4_overlay_reg_flush(bg_pipe, 0);
 		}
 	} else if (fg_alpha) {
 		blend_op = (MDP4_BLEND_BG_ALPHA_FG_PIXEL |
@@ -2213,6 +2217,8 @@
 		mdp4_dsi_video_overlay_blt(mfd, req);
 	else if (ctrl->panel_mode & MDP4_PANEL_LCDC)
 		mdp4_lcdc_overlay_blt(mfd, req);
+	else if (ctrl->panel_mode & MDP4_PANEL_MDDI)
+		mdp4_mddi_overlay_blt(mfd, req);
 
 	mutex_unlock(&mfd->dma->ov_mutex);
 
@@ -2234,6 +2240,8 @@
 		ret = mdp4_dsi_video_overlay_blt_offset(mfd, req);
 	else if (ctrl->panel_mode & MDP4_PANEL_LCDC)
 		ret = mdp4_lcdc_overlay_blt_offset(mfd, req);
+	else if (ctrl->panel_mode & MDP4_PANEL_MDDI)
+		mdp4_mddi_overlay_blt_offset(mfd, req);
 
 	mutex_unlock(&mfd->dma->ov_mutex);
 
@@ -2290,7 +2298,7 @@
 	if (mdp4_extn_disp)
 		return OVERLAY_PERF_LEVEL1;
 
-	if (req->flags & MDP_DEINTERLACE)
+	if (req->flags & (MDP_DEINTERLACE | MDP_BACKEND_COMPOSITION))
 		return OVERLAY_PERF_LEVEL1;
 
 	for (i = 0, cnt = 0; i < OVERLAY_PIPE_MAX; i++) {
@@ -2354,19 +2362,25 @@
 		return;
 
 	if (mfd->use_ov0_blt) {
-		if (mfd->panel_info.type == LCDC_PANEL)
+		if (mfd->panel_info.type == LCDC_PANEL ||
+		    mfd->panel_info.type == LVDS_PANEL)
 			mdp4_lcdc_overlay_blt_start(mfd);
 		else if (mfd->panel_info.type == MIPI_VIDEO_PANEL)
 			mdp4_dsi_video_blt_start(mfd);
 		else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD)
 			mdp4_dsi_overlay_blt_start(mfd);
+		else if (ctrl->panel_mode & MDP4_PANEL_MDDI)
+			mdp4_mddi_overlay_blt_start(mfd);
 	} else {
-		if (mfd->panel_info.type == LCDC_PANEL)
+		if (mfd->panel_info.type == LCDC_PANEL ||
+		    mfd->panel_info.type == LVDS_PANEL)
 			mdp4_lcdc_overlay_blt_stop(mfd);
 		else if (mfd->panel_info.type == MIPI_VIDEO_PANEL)
 			mdp4_dsi_video_blt_stop(mfd);
 		else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD)
 			mdp4_dsi_overlay_blt_stop(mfd);
+		else if (ctrl->panel_mode & MDP4_PANEL_MDDI)
+			mdp4_mddi_overlay_blt_stop(mfd);
 	}
 	mfd->ov0_blt_state = mfd->use_ov0_blt;
 }
@@ -2407,6 +2421,12 @@
 			use_blt = 1;
 	}
 
+	if (mfd->panel_info.type == MDDI_PANEL) {
+		if ((req->src_rect.h/2) >= req->dst_rect.h ||
+			(req->src_rect.w/2) >= req->dst_rect.w)
+				use_blt = 1;
+	}
+
 	if (mfd->mdp_rev == MDP_REV_41) {
 		/*
 		* writeback (blt) mode to provide work around for
@@ -2498,12 +2518,6 @@
 
 	mdp4_stat.overlay_set[pipe->mixer_num]++;
 
-	if (ctrl->panel_mode & MDP4_PANEL_MDDI) {
-		if (mdp_hw_revision == MDP4_REVISION_V2_1 &&
-			pipe->mixer_num == MDP4_MIXER0)
-			mdp4_overlay_status_write(MDP4_OVERLAY_TYPE_SET, true);
-	}
-
 	if (ctrl->panel_mode & MDP4_PANEL_DTV &&
 	    pipe->mixer_num == MDP4_MIXER1) {
 		u32 use_blt = mdp4_overlay_blt_enable(req, mfd, perf_level);
@@ -2539,6 +2553,7 @@
 					mdp4_set_perf_level();
 			} else if (ctrl->panel_mode & MDP4_PANEL_MDDI) {
 				mdp4_mddi_dma_busy_wait(mfd);
+				mdp4_mddi_blt_dmap_busy_wait(mfd);
 				mdp4_set_perf_level();
 			}
 		} else {
@@ -2589,7 +2604,7 @@
 #else
 		if (ctrl->panel_mode & MDP4_PANEL_MDDI) {
 			if (mfd->panel_power_on)
-				mdp4_mddi_dma_busy_wait(mfd);
+				mdp4_mddi_blt_dmap_busy_wait(mfd);
 		}
 #endif
 	}
@@ -2621,9 +2636,6 @@
 			}
 #else
 			if (ctrl->panel_mode & MDP4_PANEL_MDDI) {
-				if (mdp_hw_revision == MDP4_REVISION_V2_1)
-					mdp4_overlay_status_write(
-						MDP4_OVERLAY_TYPE_UNSET, true);
 				if (mfd->panel_power_on)
 					mdp4_mddi_overlay_restore();
 			}
@@ -2730,7 +2742,7 @@
 	if (mfd->use_ov1_blt)
 		mdp4_overlay1_update_blt_mode(mfd);
 
-	mdp4_overlay_dtv_wait_for_ov(mfd, pipe);
+	mdp4_overlay_dtv_wait4vsync();
 	mdp4_iommu_unmap(pipe);
 
 	mutex_unlock(&mfd->dma->ov_mutex);
@@ -2918,17 +2930,21 @@
 		/* primary interface */
 		ctrl->mixer0_played++;
 		if (ctrl->panel_mode & MDP4_PANEL_LCDC) {
-			if (!mfd->use_ov0_blt)
-				mdp4_overlay_update_blt_mode(mfd);
+			mdp4_overlay_reg_flush(pipe, 0);
 			mdp4_overlay_lcdc_start();
 			mdp4_overlay_lcdc_vsync_push(mfd, pipe);
+			if (!mfd->use_ov0_blt &&
+					!(pipe->flags & MDP_OV_PLAY_NOWAIT))
+				mdp4_overlay_update_blt_mode(mfd);
 		}
 #ifdef CONFIG_FB_MSM_MIPI_DSI
 		else if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) {
-			if (!mfd->use_ov0_blt)
-				mdp4_overlay_update_blt_mode(mfd);
+			mdp4_overlay_reg_flush(pipe, 0);
 			mdp4_overlay_dsi_video_start();
 			mdp4_overlay_dsi_video_vsync_push(mfd, pipe);
+			if (!mfd->use_ov0_blt &&
+					!(pipe->flags & MDP_OV_PLAY_NOWAIT))
+				mdp4_overlay_update_blt_mode(mfd);
 		}
 #endif
 		else {
@@ -2981,33 +2997,40 @@
 } msm_iommu_ctx_names[] = {
 	/* Display */
 	{
-		.name = "mdp_vg1",
+		.name = "mdp_port0_cb0",
 		.domain = DISPLAY_DOMAIN,
 	},
 	/* Display */
 	{
-		.name = "mdp_vg2",
+		.name = "mdp_port0_cb1",
 		.domain = DISPLAY_DOMAIN,
 	},
 	/* Display */
 	{
-		.name = "mdp_rgb1",
+		.name = "mdp_port1_cb0",
 		.domain = DISPLAY_DOMAIN,
 	},
 	/* Display */
 	{
-		.name = "mdp_rgb2",
+		.name = "mdp_port1_cb1",
 		.domain = DISPLAY_DOMAIN,
 	},
 };
 
+static int iommu_enabled;
+static int mdp_iommu_fault_handler(struct iommu_domain *domain,
+	struct device *dev, unsigned long iova, int flags)
+{
+	pr_err("MDP IOMMU page fault: iova 0x%lx", iova);
+	return 0;
+}
+
 void mdp4_iommu_attach(void)
 {
-	static int done;
 	struct iommu_domain *domain;
 	int i;
 
-	if (!done) {
+	if (!iommu_enabled) {
 		for (i = 0; i < ARRAY_SIZE(msm_iommu_ctx_names); i++) {
 			int domain_idx;
 			struct device *ctx = msm_iommu_get_ctx(
@@ -3022,6 +3045,8 @@
 			if (!domain)
 				continue;
 
+			iommu_set_fault_handler(domain,
+				mdp_iommu_fault_handler);
 			if (iommu_attach_device(domain,	ctx)) {
 				WARN(1, "%s: could not attach domain %d to context %s."
 					" iommu programming will not occur.\n",
@@ -3030,7 +3055,38 @@
 				continue;
 			}
 		}
-		done = 1;
+		pr_debug("Attached MDP IOMMU device\n");
+		iommu_enabled = 1;
+	}
+}
+
+void mdp4_iommu_detach(void)
+{
+	struct iommu_domain *domain;
+	int i;
+
+	if (!mdp_check_suspended() || mdp4_extn_disp)
+		return;
+
+	if (iommu_enabled) {
+		for (i = 0; i < ARRAY_SIZE(msm_iommu_ctx_names); i++) {
+			int domain_idx;
+			struct device *ctx = msm_iommu_get_ctx(
+				msm_iommu_ctx_names[i].name);
+
+			if (!ctx)
+				continue;
+
+			domain_idx = msm_iommu_ctx_names[i].domain;
+
+			domain = msm_get_iommu_domain(domain_idx);
+			if (!domain)
+				continue;
+
+			iommu_detach_device(domain,	ctx);
+		}
+		pr_debug("Detached MDP IOMMU device\n");
+		iommu_enabled = 0;
 	}
 }
 
@@ -3119,10 +3175,12 @@
 	else
 		mdp4_overlay_rgb_setup(pipe);
 
+	if (ctrl->panel_mode & MDP4_PANEL_LCDC)
+		mdp4_overlay_reg_flush(pipe, 1);
+
 	mdp4_mixer_stage_up(pipe);
 
 	if (ctrl->panel_mode & MDP4_PANEL_LCDC) {
-		mdp4_overlay_reg_flush(pipe, 1);
 		mdp4_overlay_lcdc_vsync_push(mfd, pipe);
 	} else {
 #ifdef CONFIG_FB_MSM_MIPI_DSI
diff --git a/drivers/video/msm/mdp4_overlay_atv.c b/drivers/video/msm/mdp4_overlay_atv.c
index dd827aa..753ff23 100644
--- a/drivers/video/msm/mdp4_overlay_atv.c
+++ b/drivers/video/msm/mdp4_overlay_atv.c
@@ -113,11 +113,10 @@
 
 	mdp4_overlay_rgb_setup(pipe);
 
-	mdp4_mixer_stage_up(pipe);
-
 	mdp4_overlayproc_cfg(pipe);
 
 	mdp4_overlay_reg_flush(pipe, 1);
+	mdp4_mixer_stage_up(pipe);
 
 	if (ret == 0)
 		mdp_pipe_ctrl(MDP_OVERLAY1_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
@@ -185,8 +184,8 @@
 		pipe->srcp0_addr = (uint32)(buf + buf_offset);
 	}
 	mdp4_overlay_rgb_setup(pipe);
-	mdp4_mixer_stage_up(pipe);
 	mdp4_overlay_reg_flush(pipe, 0);
+	mdp4_mixer_stage_up(pipe);
 
 	printk(KERN_INFO "mdp4_atv_overlay: pipe=%x ndx=%d\n",
 					(int)pipe, pipe->pipe_ndx);
diff --git a/drivers/video/msm/mdp4_overlay_dsi_video.c b/drivers/video/msm/mdp4_overlay_dsi_video.c
index 8ab12590..574a657 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_video.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_video.c
@@ -24,6 +24,9 @@
 #include <linux/spinlock.h>
 #include <linux/fb.h>
 #include <linux/msm_mdp.h>
+#include <linux/ktime.h>
+#include <linux/wakelock.h>
+#include <linux/time.h>
 #include <asm/system.h>
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
@@ -32,6 +35,8 @@
 #include "mdp4.h"
 #include "mipi_dsi.h"
 
+#include <mach/iommu_domains.h>
+
 #define DSI_VIDEO_BASE	0xE0000
 
 static int first_pixel_start_x;
@@ -180,14 +185,10 @@
 	pipe->srcp0_ystride = fbi->fix.line_length;
 	pipe->bpp = bpp;
 
-	if (mfd->map_buffer) {
-		pipe->srcp0_addr = (unsigned int)mfd->map_buffer->iova[0] + \
-			buf_offset;
-		pr_debug("start 0x%lx srcp0_addr 0x%x\n", mfd->
-			map_buffer->iova[0], pipe->srcp0_addr);
-	} else {
+	if (mfd->display_iova)
+		pipe->srcp0_addr = mfd->display_iova + buf_offset;
+	else
 		pipe->srcp0_addr = (uint32)(buf + buf_offset);
-	}
 
 	pipe->dst_h = fbi->var.yres;
 	pipe->dst_w = fbi->var.xres;
@@ -197,8 +198,6 @@
 
 	mdp4_overlay_rgb_setup(pipe);
 
-	mdp4_mixer_stage_up(pipe);
-
 	mdp4_overlayproc_cfg(pipe);
 
 	/*
@@ -275,6 +274,7 @@
 	MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x30, dsi_hsync_skew);
 	MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x38, ctrl_polarity);
 	mdp4_overlay_reg_flush(pipe, 1);
+	mdp4_mixer_stage_up(pipe);
 
 	mdp_histogram_ctrl_all(TRUE);
 
@@ -297,6 +297,7 @@
 
 	/* MDP cmd block enable */
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+	mdp4_mixer_pipe_cleanup(dsi_pipe->mixer_num);
 	MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE, 0);
 	dsi_video_enabled = 0;
 	/* MDP cmd block disable */
@@ -305,6 +306,9 @@
 	mdp_histogram_ctrl_all(FALSE);
 	ret = panel_next_off(pdev);
 
+	/* delay to make sure the last frame finishes */
+	msleep(20);
+
 	/* dis-engage rgb0 from mixer0 */
 	if (dsi_pipe) {
 		mdp4_mixer_stage_down(dsi_pipe);
@@ -369,14 +373,10 @@
 	pipe->dst_y = 0;
 	pipe->dst_x = 0;
 
-	if (mfd->map_buffer) {
-		pipe->srcp0_addr = (unsigned int)mfd->map_buffer->iova[0] + \
-			buf_offset;
-		pr_debug("start 0x%lx srcp0_addr 0x%x\n", mfd->
-			map_buffer->iova[0], pipe->srcp0_addr);
-	} else {
+	if (mfd->display_iova)
+		pipe->srcp0_addr = mfd->display_iova + buf_offset;
+	else
 		pipe->srcp0_addr = (uint32)(buf + buf_offset);
-	}
 
 	mdp4_overlay_rgb_setup(pipe);
 
@@ -386,6 +386,8 @@
 
 	mdp4_overlay_dmap_cfg(mfd, 1);
 
+	mdp4_overlay_reg_flush(pipe, 1);
+
 	mdp4_mixer_stage_up(pipe);
 
 	mb();
@@ -445,6 +447,94 @@
 }
 
 /*
+ * MDP Timer/Functions
+ * Set up an HR timer to wake up the CPU's just before the return of a VSync
+ * This reduces any latencies that may arise if the CPU's were power collapsed
+ * in between.
+ */
+#define VSYNC_INTERVAL	16
+#define WAKE_DELAY	3 /* 3 ioctls * 600 us = 2ms + 1ms buffer */
+#define MAX_VSYNC_GAP   4 /* Marker to detect whether to skip timer */
+
+/* Move the globals into context data structure for 3.4 upgrade */
+static int first_time = 1;
+static ktime_t last_vsync_time_ns;
+struct hrtimer hr_mdp_timer_pc;
+
+static unsigned long compute_vsync_interval(void)
+{
+	ktime_t currtime_us;
+	unsigned long diff_from_vsync, vsync_interval;
+	/*
+	 * Get interval beween last vsync and current time
+	 * Current time = CPU programming MDP for next Vsync
+	 */
+	currtime_us = ktime_get();
+	diff_from_vsync =
+		(ktime_to_us(ktime_sub(currtime_us, last_vsync_time_ns)));
+	diff_from_vsync /= USEC_PER_MSEC;
+	/*
+	 * If the last Vsync occurred more than 64 ms ago, skip programming
+	 * the timer
+	 */
+	if (diff_from_vsync < (VSYNC_INTERVAL*MAX_VSYNC_GAP)) {
+		vsync_interval =
+			(VSYNC_INTERVAL-diff_from_vsync)%VSYNC_INTERVAL;
+	} else
+		vsync_interval = VSYNC_INTERVAL+1;
+
+	return vsync_interval;
+}
+
+enum hrtimer_restart mdp_pc_hrtimer_callback(struct hrtimer *timer)
+{
+	if (!wake_lock_active(&mdp_idle_wakelock)) {
+		/* Hold Wakelock if no locks held */
+		wake_lock(&mdp_idle_wakelock);
+	}
+	return HRTIMER_NORESTART;
+}
+
+void init_pc_timer(void)
+{
+	/*
+	 * Initialize hr timer which fires a few ms before Vsync - this
+	 * gets rid of any latencies that may arise due to
+	 * wake up from PC
+	 */
+	hrtimer_init(&hr_mdp_timer_pc, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	hr_mdp_timer_pc.function = &mdp_pc_hrtimer_callback;
+}
+
+void program_pc_timer(unsigned long diff_interval)
+{
+	ktime_t ktime_pc;
+	unsigned long delay_in_ns = 0;
+
+	/* Skip programming timer due to invalid delay */
+	if (diff_interval > VSYNC_INTERVAL)
+		return;
+
+	if (diff_interval < WAKE_DELAY) {
+		/*
+		 * Difference from last vsync was a multiple of refresh rate
+		 * (16*x)%16). Reset it to actual time to next vsync
+		 */
+		if (diff_interval == 0)
+			delay_in_ns = VSYNC_INTERVAL-WAKE_DELAY;
+		else
+			return;	/* too close to vsync to fire timer - skip */
+	} else if (diff_interval == WAKE_DELAY) {
+		delay_in_ns = 1;  /* diff_interval/WAKE_DELAY */
+	} else {
+		delay_in_ns = diff_interval-WAKE_DELAY;
+	}
+	delay_in_ns *= NSEC_PER_MSEC;
+	ktime_pc = ktime_set(0, delay_in_ns);
+	hrtimer_start(&hr_mdp_timer_pc, ktime_pc, HRTIMER_MODE_REL);
+}
+
+/*
  * mdp4_overlay_dsi_video_wait4event:
  * INTR_DMA_P_DONE and INTR_PRIMARY_VSYNC event only
  * no INTR_OVERLAY0_DONE event allowed.
@@ -454,12 +544,21 @@
 {
 	unsigned long flag;
 	unsigned int data;
+	unsigned long vsync_interval;
 
 	data = inpdw(MDP_BASE + DSI_VIDEO_BASE);
 	data &= 0x01;
 	if (data == 0)	/* timing generator disabled */
 		return;
-
+	if ((intr_done == INTR_PRIMARY_VSYNC) ||
+			(intr_done == INTR_DMA_P_DONE)) {
+		if (first_time) {
+			init_pc_timer();
+			first_time = 0;
+		}
+		vsync_interval = compute_vsync_interval();
+		program_pc_timer(vsync_interval);
+	}
 	spin_lock_irqsave(&mdp_spin_lock, flag);
 	INIT_COMPLETION(dsi_video_comp);
 	mfd->dma->waiting = TRUE;
@@ -546,6 +645,10 @@
 void mdp4_primary_vsync_dsi_video(void)
 {
 	complete_all(&dsi_video_comp);
+	last_vsync_time_ns = ktime_get();
+	/* Release Wakelock */
+	if (wake_lock_active(&mdp_idle_wakelock))
+		wake_unlock(&mdp_idle_wakelock);
 }
 
  /*
@@ -572,6 +675,10 @@
 		blt_cfg_changed = 0;
 	}
 	complete_all(&dsi_video_comp);
+	last_vsync_time_ns = ktime_get();
+	/*  Release Wakelock */
+	if (wake_lock_active(&mdp_idle_wakelock))
+		wake_unlock(&mdp_idle_wakelock);
 }
 
 /*
@@ -695,18 +802,14 @@
 
 	pipe = dsi_pipe;
 
-	if (mfd->map_buffer) {
-		pipe->srcp0_addr = (unsigned int)mfd->map_buffer->iova[0] + \
-			buf_offset;
-		pr_debug("start 0x%lx srcp0_addr 0x%x\n", mfd->
-			map_buffer->iova[0], pipe->srcp0_addr);
-	} else {
+	if (mfd->display_iova)
+		pipe->srcp0_addr = mfd->display_iova + buf_offset;
+	else
 		pipe->srcp0_addr = (uint32)(buf + buf_offset);
-	}
 
 	mdp4_overlay_rgb_setup(pipe);
-	mdp4_mixer_stage_up(pipe);
 	mdp4_overlay_reg_flush(pipe, 0);
+	mdp4_mixer_stage_up(pipe);
 	mdp4_overlay_dsi_video_start();
 	mdp4_overlay_dsi_video_vsync_push(mfd, pipe);
 	mdp4_iommu_unmap(pipe);
diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c
index e3917e6..dd96439 100644
--- a/drivers/video/msm/mdp4_overlay_dtv.c
+++ b/drivers/video/msm/mdp4_overlay_dtv.c
@@ -208,6 +208,8 @@
 
 	/* MDP cmd block enable */
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+	mdp4_mixer_pipe_cleanup(dtv_pipe->mixer_num);
+	msleep(20);
 	MDP_OUTP(MDP_BASE + DTV_BASE, 0);
 	dtv_enabled = 0;
 	/* MDP cmd block disable */
@@ -260,6 +262,10 @@
 
 	if (dtv_pipe != NULL) {
 		mdp4_dtv_stop(mfd);
+
+		/* delay to make sure the last frame finishes */
+		msleep(20);
+
 		mdp4_mixer_stage_down(dtv_pipe);
 		mdp4_overlay_pipe_free(dtv_pipe);
 		mdp4_iommu_unmap(dtv_pipe);
@@ -268,6 +274,7 @@
 	mdp4_overlay_panel_mode_unset(MDP4_MIXER1, MDP4_PANEL_DTV);
 
 	ret = panel_next_off(pdev);
+	mdp4_iommu_detach();
 	mdp_footswitch_ctrl(FALSE);
 
 	dev_info(&pdev->dev, "mdp4_overlay_dtv: off");
@@ -343,8 +350,8 @@
 		mdp4_overlay_rgb_setup(pipe);
 	}
 
-	mdp4_mixer_stage_up(pipe);
 	mdp4_overlay_reg_flush(pipe, 1);
+	mdp4_mixer_stage_up(pipe);
 
 	dtv_pipe = pipe; /* keep it */
 }
@@ -693,8 +700,8 @@
 		pipe->srcp0_addr = (uint32) mfd->ibuf.buf;
 		mdp4_overlay_rgb_setup(pipe);
 	}
-	mdp4_mixer_stage_up(pipe);
 	mdp4_overlay_reg_flush(pipe, 0);
+	mdp4_mixer_stage_up(pipe);
 	mdp4_overlay_dtv_start();
 	mdp4_overlay_dtv_ov_done_push(mfd, pipe);
 	mdp4_iommu_unmap(pipe);
diff --git a/drivers/video/msm/mdp4_overlay_lcdc.c b/drivers/video/msm/mdp4_overlay_lcdc.c
index 3f90380..a1fecb6 100644
--- a/drivers/video/msm/mdp4_overlay_lcdc.c
+++ b/drivers/video/msm/mdp4_overlay_lcdc.c
@@ -142,14 +142,11 @@
 	pipe->src_w = fbi->var.xres;
 	pipe->src_y = 0;
 	pipe->src_x = 0;
-	if (mfd->map_buffer) {
-		pipe->srcp0_addr = (unsigned int)mfd->map_buffer->iova[0] + \
-			buf_offset;
-		pr_debug("start 0x%lx srcp0_addr 0x%x\n", mfd->
-			map_buffer->iova[0], pipe->srcp0_addr);
-	} else {
+
+	if (mfd->display_iova)
+		pipe->srcp0_addr = mfd->display_iova + buf_offset;
+	else
 		pipe->srcp0_addr = (uint32)(buf + buf_offset);
-	}
 
 	pipe->srcp0_ystride = fbi->fix.line_length;
 	pipe->bpp = bpp;
@@ -159,8 +156,6 @@
 
 	mdp4_overlay_rgb_setup(pipe);
 
-	mdp4_mixer_stage_up(pipe);
-
 	mdp4_overlayproc_cfg(pipe);
 
 	/*
@@ -243,6 +238,7 @@
 	MDP_OUTP(MDP_BASE + LCDC_BASE + 0x24, active_v_end);
 
 	mdp4_overlay_reg_flush(pipe, 1);
+	mdp4_mixer_stage_up(pipe);
 
 #ifdef CONFIG_MSM_BUS_SCALING
 	mdp_bus_scale_update_request(2);
@@ -267,6 +263,7 @@
 
 	/* MDP cmd block enable */
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+	mdp4_mixer_pipe_cleanup(lcdc_pipe->mixer_num);
 	MDP_OUTP(MDP_BASE + LCDC_BASE, 0);
 	lcdc_enabled = 0;
 	/* MDP cmd block disable */
@@ -279,7 +276,7 @@
 	mutex_unlock(&mfd->dma->ov_mutex);
 
 	/* delay to make sure the last frame finishes */
-	msleep(16);
+	msleep(20);
 
 	/* dis-engage rgb0 from mixer0 */
 	if (lcdc_pipe) {
@@ -588,17 +585,15 @@
 	mutex_lock(&mfd->dma->ov_mutex);
 
 	pipe = lcdc_pipe;
-	if (mfd->map_buffer) {
-		pipe->srcp0_addr = (unsigned int)mfd->map_buffer->iova[0] + \
-			buf_offset;
-		pr_debug("start 0x%lx srcp0_addr 0x%x\n", mfd->
-			map_buffer->iova[0], pipe->srcp0_addr);
-	} else {
+
+	if (mfd->display_iova)
+		pipe->srcp0_addr = mfd->display_iova + buf_offset;
+	else
 		pipe->srcp0_addr = (uint32)(buf + buf_offset);
-	}
+
 	mdp4_overlay_rgb_setup(pipe);
-	mdp4_mixer_stage_up(pipe);
 	mdp4_overlay_reg_flush(pipe, 0);
+	mdp4_mixer_stage_up(pipe);
 	mdp4_overlay_lcdc_start();
 	mdp4_overlay_lcdc_vsync_push(mfd, pipe);
 	mdp4_iommu_unmap(pipe);
diff --git a/drivers/video/msm/mdp4_overlay_mddi.c b/drivers/video/msm/mdp4_overlay_mddi.c
index 83959df..82864918 100644
--- a/drivers/video/msm/mdp4_overlay_mddi.c
+++ b/drivers/video/msm/mdp4_overlay_mddi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -124,7 +124,6 @@
 			printk(KERN_INFO "%s: format2type failed\n", __func__);
 
 		mddi_pipe = pipe; /* keep it */
-		mddi_pipe->blt_end = 1;	/* mark as end */
 		mddi_ld_param = 0;
 		mddi_vdo_packet_reg = mfd->panel_info.mddi.vdopkt;
 
@@ -163,6 +162,8 @@
 			 (MDDI_VDO_PACKET_DESC << 16) | mddi_vdo_packet_reg);
 
 		MDP_OUTP(MDP_BASE + 0x00098, 0x01);
+		mdp4_init_writeback_buf(mfd, MDP4_MIXER0);
+		pipe->blt_addr = 0;
 	} else {
 		pipe = mddi_pipe;
 	}
@@ -246,59 +247,82 @@
 
 	/* MDP cmd block disable */
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-
 }
 
-int mdp4_mddi_overlay_blt_offset(int *off)
-{
-	if (mdp_hw_revision < MDP4_REVISION_V2_1) { /* need dmas dmap switch */
-		if (mddi_pipe->blt_end ||
-			(mdp4_overlay_mixer_play(mddi_pipe->mixer_num) == 0)) {
-			*off = -1;
-			return -EINVAL;
-		}
-	} else {
-		/* no dmas dmap switch */
-		if (mddi_pipe->blt_end) {
-			*off = -1;
-			return -EINVAL;
-		}
-	}
-
-	if (mddi_pipe->blt_cnt & 0x01)
-		*off = mddi_pipe->src_height * mddi_pipe->src_width * 3;
-	else
-		*off = 0;
-
-	return 0;
-}
-
-void mdp4_mddi_overlay_blt(ulong addr)
+int mdp4_mddi_overlay_blt_start(struct msm_fb_data_type *mfd)
 {
 	unsigned long flag;
 
-	spin_lock_irqsave(&mdp_spin_lock, flag);
-	if (addr) {
-		mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-		mdp_intr_mask |= INTR_DMA_P_DONE;
-		outp32(MDP_INTR_ENABLE, mdp_intr_mask);
-		mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-		mddi_pipe->blt_cnt = 0;
-		mddi_pipe->blt_end = 0;
-		mddi_pipe->blt_addr = addr;
-	} else {
-		mddi_pipe->blt_end = 1;	/* mark as end */
+	pr_debug("%s: blt_end=%d blt_addr=%x pid=%d\n",
+	__func__, mddi_pipe->blt_end, (int)mddi_pipe->blt_addr, current->pid);
+
+	mdp4_allocate_writeback_buf(mfd, MDP4_MIXER0);
+
+	if (mfd->ov0_wb_buf->phys_addr == 0) {
+		pr_info("%s: no blt_base assigned\n", __func__);
+		return -EBUSY;
 	}
-	spin_unlock_irqrestore(&mdp_spin_lock, flag);
+
+	if (mddi_pipe->blt_addr == 0) {
+		mdp4_mddi_dma_busy_wait(mfd);
+		spin_lock_irqsave(&mdp_spin_lock, flag);
+		mddi_pipe->blt_end = 0;
+		mddi_pipe->blt_cnt = 0;
+		mddi_pipe->ov_cnt = 0;
+		mddi_pipe->dmap_cnt = 0;
+		mddi_pipe->blt_addr = mfd->ov0_wb_buf->phys_addr;
+		mdp4_stat.blt_mddi++;
+		spin_unlock_irqrestore(&mdp_spin_lock, flag);
+	return 0;
+}
+
+	return -EBUSY;
+}
+
+int mdp4_mddi_overlay_blt_stop(struct msm_fb_data_type *mfd)
+{
+	unsigned long flag;
+
+	pr_debug("%s: blt_end=%d blt_addr=%x\n",
+		 __func__, mddi_pipe->blt_end, (int)mddi_pipe->blt_addr);
+
+	if ((mddi_pipe->blt_end == 0) && mddi_pipe->blt_addr) {
+		spin_lock_irqsave(&mdp_spin_lock, flag);
+		mddi_pipe->blt_end = 1;	/* mark as end */
+		spin_unlock_irqrestore(&mdp_spin_lock, flag);
+		return 0;
+	}
+
+	return -EBUSY;
+}
+
+int mdp4_mddi_overlay_blt_offset(struct msm_fb_data_type *mfd,
+					struct msmfb_overlay_blt *req)
+{
+	req->offset = 0;
+	req->width = mddi_pipe->src_width;
+	req->height = mddi_pipe->src_height;
+	req->bpp = mddi_pipe->bpp;
+
+	return sizeof(*req);
+}
+
+void mdp4_mddi_overlay_blt(struct msm_fb_data_type *mfd,
+					struct msmfb_overlay_blt *req)
+{
+	if (req->enable)
+		mdp4_mddi_overlay_blt_start(mfd);
+	else if (req->enable == 0)
+		mdp4_mddi_overlay_blt_stop(mfd);
+
 }
 
 void mdp4_blt_xy_update(struct mdp4_overlay_pipe *pipe)
 {
-	uint32 off, addr;
+	uint32 off, addr, addr2;
 	int bpp;
 	char *overlay_base;
 
-
 	if (pipe->blt_addr == 0)
 		return;
 
@@ -317,29 +341,62 @@
 	/* dmap */
 	MDP_OUTP(MDP_BASE + 0x90008, addr);
 
+	off = 0;
+	if (pipe->ov_cnt & 0x01)
+		off = pipe->src_height * pipe->src_width * bpp;
+	addr2 = pipe->blt_addr + off;
 	/* overlay 0 */
 	overlay_base = MDP_BASE + MDP4_OVERLAYPROC0_BASE;/* 0x10000 */
-	outpdw(overlay_base + 0x000c, addr);
-	outpdw(overlay_base + 0x001c, addr);
+	outpdw(overlay_base + 0x000c, addr2);
+	outpdw(overlay_base + 0x001c, addr2);
 }
 
 /*
  * mdp4_dmap_done_mddi: called from isr
  */
-void mdp4_dma_p_done_mddi(void)
+void mdp4_dma_p_done_mddi(struct mdp_dma_data *dma)
 {
-	if (mddi_pipe->blt_end) {
-		mddi_pipe->blt_addr = 0;
-		mdp_intr_mask &= ~INTR_DMA_P_DONE;
-		outp32(MDP_INTR_ENABLE, mdp_intr_mask);
-		mdp4_overlayproc_cfg(mddi_pipe);
-		mdp4_overlay_dmap_xy(mddi_pipe);
+	int diff;
+
+	mddi_pipe->dmap_cnt++;
+	diff = mddi_pipe->ov_cnt - mddi_pipe->dmap_cnt;
+	pr_debug("%s: ov_cnt=%d dmap_cnt=%d\n",
+			__func__, mddi_pipe->ov_cnt, mddi_pipe->dmap_cnt);
+
+	if (diff <= 0) {
+		spin_lock(&mdp_spin_lock);
+		dma->dmap_busy = FALSE;
+		complete(&dma->dmap_comp);
+		spin_unlock(&mdp_spin_lock);
+
+		if (mddi_pipe->blt_end) {
+			mddi_pipe->blt_end = 0;
+			mddi_pipe->blt_addr = 0;
+			pr_debug("%s: END, ov_cnt=%d dmap_cnt=%d\n", __func__,
+				mddi_pipe->ov_cnt, mddi_pipe->dmap_cnt);
+			mdp_intr_mask &= ~INTR_DMA_P_DONE;
+			outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+		}
+
+		mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_OFF, TRUE);
+		mdp_disable_irq_nosync(MDP_DMA2_TERM);  /* disable intr */
+		return;
 	}
 
-	/*
-	 * single buffer, no need to increase
-	 * mdd_pipe->dmap_cnt here
-	 */
+	spin_lock(&mdp_spin_lock);
+	dma->busy = FALSE;
+	spin_unlock(&mdp_spin_lock);
+	complete(&dma->comp);
+	if (busy_wait_cnt)
+		busy_wait_cnt--;
+
+	pr_debug("%s: kickoff dmap\n", __func__);
+
+	mdp4_blt_xy_update(mddi_pipe);
+	/* kick off dmap */
+	outpdw(MDP_BASE + 0x000c, 0x0);
+	mdp4_stat.kickoff_dmap++;
+	mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_OFF, TRUE);
 }
 
 /*
@@ -347,37 +404,60 @@
  */
 void mdp4_overlay0_done_mddi(struct mdp_dma_data *dma)
 {
-	mdp_disable_irq_nosync(MDP_OVERLAY0_TERM);
+	int diff;
 
+	if (mddi_pipe->blt_addr == 0) {
+		mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_OFF, TRUE);
+		spin_lock(&mdp_spin_lock);
+		dma->busy = FALSE;
+		spin_unlock(&mdp_spin_lock);
+		complete(&dma->comp);
+
+		if (busy_wait_cnt)
+			busy_wait_cnt--;
+		mdp_disable_irq_nosync(MDP_OVERLAY0_TERM);
+
+		return;
+	}
+
+	/* blt enabled */
+	if (mddi_pipe->blt_end == 0)
+		mddi_pipe->ov_cnt++;
+
+	pr_debug("%s: ov_cnt=%d dmap_cnt=%d\n",
+			__func__, mddi_pipe->ov_cnt, mddi_pipe->dmap_cnt);
+
+	if (mddi_pipe->blt_cnt == 0) {
+		/* first kickoff since blt enabled */
+		mdp_intr_mask |= INTR_DMA_P_DONE;
+		outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+	}
+
+	mddi_pipe->blt_cnt++;
+
+	diff = mddi_pipe->ov_cnt - mddi_pipe->dmap_cnt;
+	if (diff >= 2) {
+		mdp_disable_irq_nosync(MDP_OVERLAY0_TERM);
+		return;
+	}
+
+	spin_lock(&mdp_spin_lock);
 	dma->busy = FALSE;
+	dma->dmap_busy = TRUE;
+	spin_unlock(&mdp_spin_lock);
 	complete(&dma->comp);
-	mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK,
-			MDP_BLOCK_POWER_OFF, TRUE);
 
 	if (busy_wait_cnt)
 		busy_wait_cnt--;
 
-	pr_debug("%s: ISR-done\n", __func__);
+	pr_debug("%s: kickoff dmap\n", __func__);
 
-	if (mddi_pipe->blt_addr) {
-		if (mddi_pipe->blt_cnt == 0) {
-			mdp4_overlayproc_cfg(mddi_pipe);
-			mdp4_overlay_dmap_xy(mddi_pipe);
-			mddi_pipe->ov_cnt = 0;
-			mddi_pipe->dmap_cnt = 0;
-			/* BLT start from next frame */
-		} else {
-			mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_ON,
-						FALSE);
-			mdp4_blt_xy_update(mddi_pipe);
-			outpdw(MDP_BASE + 0x000c, 0x0); /* start DMAP */
-		}
-		mddi_pipe->blt_cnt++;
-		mddi_pipe->ov_cnt++;
-	}
-
-
-
+	mdp4_blt_xy_update(mddi_pipe);
+	mdp_enable_irq(MDP_DMA2_TERM);	/* enable intr */
+	/* kick off dmap */
+	outpdw(MDP_BASE + 0x000c, 0x0);
+	mdp4_stat.kickoff_dmap++;
+	mdp_disable_irq_nosync(MDP_OVERLAY0_TERM);
 }
 
 void mdp4_mddi_overlay_restore(void)
@@ -392,6 +472,9 @@
 	if (mddi_mfd && mddi_pipe) {
 		mdp4_mddi_dma_busy_wait(mddi_mfd);
 		mdp4_overlay_update_lcd(mddi_mfd);
+
+		if (mddi_pipe->blt_addr)
+			mdp4_mddi_blt_dmap_busy_wait(mddi_mfd);
 		mdp4_mddi_overlay_kickoff(mddi_mfd, mddi_pipe);
 		mddi_mfd->dma_update_flag = 1;
 	}
@@ -399,9 +482,27 @@
 		mdp4_mddi_overlay_dmas_restore();
 }
 
+void mdp4_mddi_blt_dmap_busy_wait(struct msm_fb_data_type *mfd)
+{
+	unsigned long flag;
+	int need_wait = 0;
+
+	spin_lock_irqsave(&mdp_spin_lock, flag);
+	if (mfd->dma->dmap_busy == TRUE) {
+		INIT_COMPLETION(mfd->dma->dmap_comp);
+		need_wait++;
+	}
+	spin_unlock_irqrestore(&mdp_spin_lock, flag);
+
+	if (need_wait) {
+		/* wait until DMA finishes the current job */
+		wait_for_completion(&mfd->dma->dmap_comp);
+	}
+}
+
 /*
  * mdp4_mddi_cmd_dma_busy_wait: check mddi link activity
- * dsi link is a shared resource and it can only be used
+ * mddi link is a shared resource and it can only be used
  * while it is in idle state.
  * ov_mutex need to be acquired before call this function.
  */
@@ -432,7 +533,24 @@
 void mdp4_mddi_kickoff_video(struct msm_fb_data_type *mfd,
 				struct mdp4_overlay_pipe *pipe)
 {
-	pr_debug("%s: pid=%d\n", __func__, current->pid);
+	/*
+	 * a video kickoff may happen before UI kickoff after
+	 * blt enabled. mdp4_overlay_update_lcd() need
+	 * to be called before kickoff.
+	 * vice versa for blt disabled.
+	 */
+	if (mddi_pipe->blt_addr && mddi_pipe->blt_cnt == 0)
+		mdp4_overlay_update_lcd(mfd); /* first time */
+	else if (mddi_pipe->blt_addr == 0  && mddi_pipe->blt_cnt) {
+		mdp4_overlay_update_lcd(mfd); /* last time */
+		mddi_pipe->blt_cnt = 0;
+	}
+
+	pr_debug("%s: blt_addr=%d blt_cnt=%d\n",
+		__func__, (int)mddi_pipe->blt_addr, mddi_pipe->blt_cnt);
+
+	if (mddi_pipe->blt_addr)
+		mdp4_mddi_blt_dmap_busy_wait(mddi_mfd);
 	mdp4_mddi_overlay_kickoff(mfd, pipe);
 }
 
@@ -447,32 +565,16 @@
 void mdp4_mddi_overlay_kickoff(struct msm_fb_data_type *mfd,
 				struct mdp4_overlay_pipe *pipe)
 {
+	unsigned long flag;
 	/* change mdp clk while mdp is idle` */
 	mdp4_set_perf_level();
 
-	if (mdp_hw_revision == MDP4_REVISION_V2_1) {
-		if (mdp4_overlay_status_read(MDP4_OVERLAY_TYPE_UNSET)) {
-			uint32  data;
-			data = inpdw(MDP_BASE + 0x0028);
-			data &= ~0x0300;        /* bit 8, 9, MASTER4 */
-			if (mfd->fbi->var.xres == 540) /* qHD, 540x960 */
-				data |= 0x0200;
-			else
-				data |= 0x0100;
-			MDP_OUTP(MDP_BASE + 0x00028, data);
-			mdp4_overlay_status_write(MDP4_OVERLAY_TYPE_UNSET,
-				false);
-		}
-		if (mdp4_overlay_status_read(MDP4_OVERLAY_TYPE_SET)) {
-			uint32  data;
-			data = inpdw(MDP_BASE + 0x0028);
-			data &= ~0x0300;        /* bit 8, 9, MASTER4 */
-			MDP_OUTP(MDP_BASE + 0x00028, data);
-			mdp4_overlay_status_write(MDP4_OVERLAY_TYPE_SET, false);
-		}
-	}
 	mdp_enable_irq(MDP_OVERLAY0_TERM);
+	spin_lock_irqsave(&mdp_spin_lock, flag);
 	mfd->dma->busy = TRUE;
+	if (mddi_pipe->blt_addr)
+		mfd->dma->dmap_busy = TRUE;
+	spin_unlock_irqrestore(&mdp_spin_lock, flag);
 	/* start OVERLAY pipe */
 	mdp_pipe_kickoff(MDP_OVERLAY0_TERM, mfd);
 	mdp4_stat.kickoff_ov0++;
@@ -554,7 +656,10 @@
 	mdp4_set_perf_level();
 
 	mdp_enable_irq(MDP_DMA_S_TERM);
-	mfd->dma->busy = TRUE;
+
+	if (mddi_pipe->blt_addr == 0)
+		mfd->dma->busy = TRUE;
+
 	mfd->ibuf_flushed = TRUE;
 	/* start dma_s pipe */
 	mdp_pipe_kickoff(MDP_DMA_S_TERM, mfd);
@@ -582,6 +687,10 @@
 
 	if (mfd && mfd->panel_power_on) {
 		mdp4_mddi_dma_busy_wait(mfd);
+
+		if (mddi_pipe && mddi_pipe->blt_addr)
+			mdp4_mddi_blt_dmap_busy_wait(mfd);
+
 		mdp4_overlay_update_lcd(mfd);
 
 		if (mdp_hw_revision < MDP4_REVISION_V2_1) {
diff --git a/drivers/video/msm/mdp4_overlay_writeback.c b/drivers/video/msm/mdp4_overlay_writeback.c
index 2fba83d..f1a2ada 100644
--- a/drivers/video/msm/mdp4_overlay_writeback.c
+++ b/drivers/video/msm/mdp4_overlay_writeback.c
@@ -98,11 +98,14 @@
 		pipe = writeback_pipe;
 	}
 	ret = panel_next_on(pdev);
+
 	/* MDP_LAYERMIXER_WB_MUX_SEL to use mixer1 axi for mixer2 writeback */
-	data = inpdw(MDP_BASE + 0x100F4);
-	data &= ~0x02; /* clear the mixer1 mux bit */
-	data |= 0x02;
+	if (hdmi_prim_display)
+		data = 0x01;
+	else
+		data = 0x02;
 	outpdw(MDP_BASE + 0x100F4, data);
+
 	MDP_OUTP(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x5004,
 		((0x0 & 0xFFF) << 16) | /* 12-bit B */
 			(0x0 & 0xFFF));         /* 12-bit G */
@@ -117,7 +120,6 @@
 int mdp4_overlay_writeback_off(struct platform_device *pdev)
 {
 	int ret;
-	uint32 data;
 	struct msm_fb_data_type *mfd =
 			(struct msm_fb_data_type *)platform_get_drvdata(pdev);
 	if (mfd && writeback_pipe) {
@@ -129,11 +131,8 @@
 	}
 	ret = panel_next_off(pdev);
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	/* MDP_LAYERMIXER_WB_MUX_SEL to restore
-	 * mixer1 axi for mixer1 writeback */
-	data = inpdw(MDP_BASE + 0x100F4);
-	data &= ~0x02; /* clear the mixer1 mux bit */
-	outpdw(MDP_BASE + 0x100F4, data);
+	/* MDP_LAYERMIXER_WB_MUX_SEL to restore to default cfg*/
+	outpdw(MDP_BASE + 0x100F4, 0x0);
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 	return ret;
 }
@@ -175,14 +174,10 @@
 	pipe->dst_y = 0;
 	pipe->dst_x = 0;
 
-	if (mfd->map_buffer) {
-		pipe->srcp0_addr = (unsigned int)mfd->map_buffer->iova[0] + \
-			buf_offset;
-		pr_debug("start 0x%lx srcp0_addr 0x%x\n", mfd->
-			map_buffer->iova[0], pipe->srcp0_addr);
-	} else {
+	if (mfd->display_iova)
+		pipe->srcp0_addr = mfd->display_iova + buf_offset;
+	else
 		pipe->srcp0_addr = (uint32)(buf + buf_offset);
-	}
 
 	mdp4_mixer_stage_up(pipe);
 
@@ -273,6 +268,7 @@
 	if (node) {
 		list_del(&(node->active_entry));
 		node->state = IN_BUSY_QUEUE;
+		mfd->writeback_active_cnt++;
 	}
 	mutex_unlock(&mfd->writeback_mutex);
 
@@ -295,6 +291,7 @@
 	mutex_lock(&mfd->writeback_mutex);
 	list_add_tail(&node->active_entry, &mfd->writeback_busy_queue);
 	mutex_unlock(&mfd->writeback_mutex);
+	mfd->writeback_active_cnt--;
 	mutex_unlock(&mfd->unregister_mutex);
 	wake_up(&mfd->wait_q);
 }
@@ -323,6 +320,7 @@
 	if (node) {
 		list_del(&(node->active_entry));
 		node->state = IN_BUSY_QUEUE;
+		mfd->writeback_active_cnt++;
 	}
 	mutex_unlock(&mfd->writeback_mutex);
 
@@ -367,6 +365,7 @@
 
 	mutex_lock(&mfd->writeback_mutex);
 	list_add_tail(&node->active_entry, &mfd->writeback_busy_queue);
+	mfd->writeback_active_cnt--;
 	mutex_unlock(&mfd->writeback_mutex);
 	wake_up(&mfd->wait_q);
 fail_no_blt_addr:
@@ -523,13 +522,26 @@
 	return rc;
 }
 
+static bool is_writeback_inactive(struct msm_fb_data_type *mfd)
+{
+	bool active;
+	mutex_lock(&mfd->writeback_mutex);
+	active = !mfd->writeback_active_cnt;
+	mutex_unlock(&mfd->writeback_mutex);
+	return active;
+}
 int mdp4_writeback_stop(struct fb_info *info)
 {
 	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
 	mutex_lock(&mfd->writeback_mutex);
 	mfd->writeback_state = WB_STOPING;
 	mutex_unlock(&mfd->writeback_mutex);
+	/* Wait for all pending writebacks to finish */
+	wait_event_interruptible(mfd->wait_q, is_writeback_inactive(mfd));
+
+	/* Wake up dequeue thread in case of no UI update*/
 	wake_up(&mfd->wait_q);
+
 	return 0;
 }
 int mdp4_writeback_init(struct fb_info *info)
@@ -549,8 +561,19 @@
 	struct list_head *ptr, *next;
 	struct msmfb_writeback_data_list *temp;
 	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+	int rc = 0;
+
 	mutex_lock(&mfd->unregister_mutex);
 	mutex_lock(&mfd->writeback_mutex);
+
+	if (mfd->writeback_state != WB_STOPING &&
+		mfd->writeback_state != WB_STOP) {
+		pr_err("%s called without stopping\n", __func__);
+		rc = -EPERM;
+		goto terminate_err;
+
+	}
+
 	if (!list_empty(&mfd->writeback_register_queue)) {
 		list_for_each_safe(ptr, next,
 				&mfd->writeback_register_queue) {
@@ -564,7 +587,10 @@
 	INIT_LIST_HEAD(&mfd->writeback_register_queue);
 	INIT_LIST_HEAD(&mfd->writeback_busy_queue);
 	INIT_LIST_HEAD(&mfd->writeback_free_queue);
+
+
+terminate_err:
 	mutex_unlock(&mfd->writeback_mutex);
 	mutex_unlock(&mfd->unregister_mutex);
-	return 0;
+	return rc;
 }
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index b2657cf..82fbb65 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -522,7 +522,7 @@
 		}
 #else
 		else { /* MDDI */
-			mdp4_dma_p_done_mddi();
+			mdp4_dma_p_done_mddi(dma);
 			mdp_pipe_ctrl(MDP_DMA2_BLOCK,
 				MDP_BLOCK_POWER_OFF, TRUE);
 			complete(&dma->comp);
diff --git a/drivers/video/msm/mdp_dma.c b/drivers/video/msm/mdp_dma.c
index 32856ef..2ba2c85 100644
--- a/drivers/video/msm/mdp_dma.c
+++ b/drivers/video/msm/mdp_dma.c
@@ -529,8 +529,9 @@
 	down(&mfd->sem);
 
 	iBuf = &mfd->ibuf;
-	if (mfd->map_buffer)
-		iBuf->buf = (uint8 *)mfd->map_buffer->iova[0];
+
+	if (mfd->display_iova)
+		iBuf->buf = (uint8 *)mfd->display_iova;
 	else
 		iBuf->buf = (uint8 *) info->fix.smem_start;
 
diff --git a/drivers/video/msm/mdp_ppp_v20.c b/drivers/video/msm/mdp_ppp_v20.c
index d271b85..418528e 100644
--- a/drivers/video/msm/mdp_ppp_v20.c
+++ b/drivers/video/msm/mdp_ppp_v20.c
@@ -2403,7 +2403,10 @@
 			   uint32 width,
 			   uint32 height, int bpp, MDPIBUF *iBuf, int layer)
 {
-	*src0 += (x + y * width) * bpp;
+	if (iBuf->mdpImg.imgType == MDP_Y_CBCR_H2V2_ADRENO && layer == 0)
+		*src0 += (x + y * ALIGN(width, 32)) * bpp;
+	else
+		*src0 += (x + y * width) * bpp;
 
 	/* if it's dest/bg buffer, we need to adjust it for rotation */
 	if (layer != 0)
@@ -2414,9 +2417,14 @@
 		 * MDP_Y_CBCR_H2V2/MDP_Y_CRCB_H2V2 cosite for now
 		 * we need to shift x direction same as y dir for offsite
 		 */
-		*src1 +=
-		    ((x / h_slice) * h_slice +
-		     ((y == 0) ? 0 : ((y + 1) / v_slice - 1) * width)) * bpp;
+		if (iBuf->mdpImg.imgType == MDP_Y_CBCR_H2V2_ADRENO
+							&& layer == 0)
+			*src1 += ((x / h_slice) * h_slice + ((y == 0) ? 0 :
+			(((y + 1) / v_slice - 1) * (ALIGN(width/2, 32) * 2))))
+									* bpp;
+		else
+			*src1 += ((x / h_slice) * h_slice +
+			((y == 0) ? 0 : ((y + 1) / v_slice - 1) * width)) * bpp;
 
 		/* if it's dest/bg buffer, we need to adjust it for rotation */
 		if (layer != 0)
diff --git a/drivers/video/msm/mipi_chimei_wuxga.c b/drivers/video/msm/mipi_chimei_wuxga.c
index 6ddf74d..e9e291e 100644
--- a/drivers/video/msm/mipi_chimei_wuxga.c
+++ b/drivers/video/msm/mipi_chimei_wuxga.c
@@ -143,6 +143,7 @@
 	pinfo->mipi.data_lane1 = true;
 	pinfo->mipi.data_lane2 = true;
 	pinfo->mipi.data_lane3 = true;
+	pinfo->mipi.esc_byte_ratio = 6;
 
 	pinfo->mipi.mode = DSI_VIDEO_MODE;
 	/*
diff --git a/drivers/video/msm/mipi_chimei_wxga_pt.c b/drivers/video/msm/mipi_chimei_wxga_pt.c
index 1ab50b7..88a5193 100644
--- a/drivers/video/msm/mipi_chimei_wxga_pt.c
+++ b/drivers/video/msm/mipi_chimei_wxga_pt.c
@@ -130,6 +130,7 @@
 	pinfo->mipi.tx_eot_append = true;
 	pinfo->mipi.t_clk_post = 34;		/* Calculated */
 	pinfo->mipi.t_clk_pre = 64;		/* Calculated */
+	pinfo->mipi.esc_byte_ratio = 4;
 
 	pinfo->mipi.dsi_phy_db = &dsi_video_mode_phy_db;
 
diff --git a/drivers/video/msm/mipi_dsi.c b/drivers/video/msm/mipi_dsi.c
index baad0a8..1ba1444 100644
--- a/drivers/video/msm/mipi_dsi.c
+++ b/drivers/video/msm/mipi_dsi.c
@@ -36,6 +36,7 @@
 #include "mdp4.h"
 
 u32 dsi_irq;
+u32 esc_byte_ratio;
 
 static boolean tlmm_settings = FALSE;
 
@@ -164,6 +165,7 @@
 	fbi = mfd->fbi;
 	var = &fbi->var;
 	pinfo = &mfd->panel_info;
+	esc_byte_ratio = pinfo->mipi.esc_byte_ratio;
 
 	if (mipi_dsi_pdata && mipi_dsi_pdata->dsi_power_save)
 		mipi_dsi_pdata->dsi_power_save(1);
@@ -178,6 +180,17 @@
 	clk_rate = mfd->fbi->var.pixclock;
 	clk_rate = min(clk_rate, mfd->panel_info.clk_max);
 
+	mipi_dsi_phy_ctrl(1);
+
+	if (mdp_rev == MDP_REV_42 && mipi_dsi_pdata)
+		target_type = mipi_dsi_pdata->target_type;
+
+	mipi_dsi_phy_init(0, &(mfd->panel_info), target_type);
+
+	local_bh_disable();
+	mipi_dsi_clk_enable();
+	local_bh_enable();
+
 	MIPI_OUTP(MIPI_DSI_BASE + 0x114, 1);
 	MIPI_OUTP(MIPI_DSI_BASE + 0x114, 0);
 
@@ -190,17 +203,6 @@
 	width = mfd->panel_info.xres;
 	height = mfd->panel_info.yres;
 
-	mipi_dsi_phy_ctrl(1);
-
-	if (mdp_rev == MDP_REV_42 && mipi_dsi_pdata)
-		target_type = mipi_dsi_pdata->target_type;
-
-	mipi_dsi_phy_init(0, &(mfd->panel_info), target_type);
-
-	local_bh_disable();
-	mipi_dsi_clk_enable();
-	local_bh_enable();
-
 	mipi  = &mfd->panel_info.mipi;
 	if (mfd->panel_info.type == MIPI_VIDEO_PANEL) {
 		dummy_xres = mfd->panel_info.lcdc.xres_pad;
diff --git a/drivers/video/msm/mipi_dsi.h b/drivers/video/msm/mipi_dsi.h
index ff2910f..2bc49c0 100644
--- a/drivers/video/msm/mipi_dsi.h
+++ b/drivers/video/msm/mipi_dsi.h
@@ -126,6 +126,7 @@
 extern struct device dsi_dev;
 extern int mipi_dsi_clk_on;
 extern u32 dsi_irq;
+extern u32 esc_byte_ratio;
 
 extern void  __iomem *periph_base;
 extern char *mmss_cc_base;	/* mutimedia sub system clock control */
@@ -259,6 +260,8 @@
 char *mipi_dsi_buf_reserve_hdr(struct dsi_buf *dp, int hlen);
 char *mipi_dsi_buf_init(struct dsi_buf *dp);
 void mipi_dsi_init(void);
+void mipi_dsi_lane_cfg(void);
+void mipi_dsi_bist_ctrl(void);
 int mipi_dsi_buf_alloc(struct dsi_buf *, int size);
 int mipi_dsi_cmd_dma_add(struct dsi_buf *dp, struct dsi_cmd_desc *cm);
 int mipi_dsi_cmds_tx(struct msm_fb_data_type *mfd,
diff --git a/drivers/video/msm/mipi_novatek_cmd_qhd_pt.c b/drivers/video/msm/mipi_novatek_cmd_qhd_pt.c
index fbd2495..f139f4c 100644
--- a/drivers/video/msm/mipi_novatek_cmd_qhd_pt.c
+++ b/drivers/video/msm/mipi_novatek_cmd_qhd_pt.c
@@ -73,6 +73,7 @@
 	pinfo.mipi.dst_format = DSI_CMD_DST_FORMAT_RGB888;
 	pinfo.mipi.vc = 0;
 	pinfo.mipi.data_lane0 = TRUE;
+	pinfo.mipi.esc_byte_ratio = 4;
 #if defined(NOVATEK_TWO_LANE)
 	pinfo.mipi.data_lane1 = TRUE;
 #endif
diff --git a/drivers/video/msm/mipi_novatek_video_qhd_pt.c b/drivers/video/msm/mipi_novatek_video_qhd_pt.c
index 42ddfbe..7a9d556 100644
--- a/drivers/video/msm/mipi_novatek_video_qhd_pt.c
+++ b/drivers/video/msm/mipi_novatek_video_qhd_pt.c
@@ -73,6 +73,7 @@
 	pinfo.mipi.vc = 0;
 	pinfo.mipi.rgb_swap = DSI_RGB_SWAP_BGR;
 	pinfo.mipi.data_lane0 = TRUE;
+	pinfo.mipi.esc_byte_ratio = 4;
 #if defined(NOVATEK_TWO_LANE)
 	pinfo.mipi.data_lane1 = TRUE;
 #endif
diff --git a/drivers/video/msm/mipi_orise_video_720p_pt.c b/drivers/video/msm/mipi_orise_video_720p_pt.c
index 629ff10..da8b5e5 100644
--- a/drivers/video/msm/mipi_orise_video_720p_pt.c
+++ b/drivers/video/msm/mipi_orise_video_720p_pt.c
@@ -85,6 +85,7 @@
 	pinfo.mipi.frame_rate = 55;
 	pinfo.mipi.dsi_phy_db = &dsi_video_mode_phy_db;
 	pinfo.mipi.tx_eot_append = TRUE;
+	pinfo.mipi.esc_byte_ratio = 4;
 
 	ret = mipi_orise_device_register(&pinfo, MIPI_DSI_PRIM,
 						MIPI_DSI_PANEL_720P_PT);
diff --git a/drivers/video/msm/mipi_toshiba_video_wsvga_pt.c b/drivers/video/msm/mipi_toshiba_video_wsvga_pt.c
index 48bdb1d..6edd776 100644
--- a/drivers/video/msm/mipi_toshiba_video_wsvga_pt.c
+++ b/drivers/video/msm/mipi_toshiba_video_wsvga_pt.c
@@ -20,7 +20,7 @@
 static struct mipi_dsi_phy_ctrl dsi_video_mode_phy_db = {
 	/* 600*1024, RGB888, 3 Lane 55 fps video mode */
     /* regulator */
-	{0x03, 0x0a, 0x04, 0x00, 0x20},
+	{0x09, 0x08, 0x05, 0x00, 0x20},
 	/* timing */
 	{0xab, 0x8a, 0x18, 0x00, 0x92, 0x97, 0x1b, 0x8c,
 	0x0c, 0x03, 0x04, 0xa0},
@@ -86,6 +86,7 @@
 	pinfo.mipi.data_lane2 = TRUE;
 	pinfo.mipi.t_clk_post = 0x20;
 	pinfo.mipi.t_clk_pre = 0x2d;
+	pinfo.mipi.esc_byte_ratio = 4;
 	pinfo.mipi.stream = 0; /* dma_p */
 	pinfo.mipi.mdp_trigger = 0;
 	pinfo.mipi.dma_trigger = DSI_CMD_TRIGGER_SW;
diff --git a/drivers/video/msm/mipi_toshiba_video_wuxga.c b/drivers/video/msm/mipi_toshiba_video_wuxga.c
index 297248f..8eddce4 100644
--- a/drivers/video/msm/mipi_toshiba_video_wuxga.c
+++ b/drivers/video/msm/mipi_toshiba_video_wuxga.c
@@ -85,6 +85,7 @@
 	pinfo.mipi.dma_trigger = DSI_CMD_TRIGGER_SW;
 	pinfo.mipi.frame_rate = 60;
 	pinfo.mipi.dsi_phy_db = &dsi_video_mode_phy_db;
+	pinfo.mipi.esc_byte_ratio = 9;
 
 	ret = mipi_toshiba_device_register(&pinfo, MIPI_DSI_PRIM,
 						MIPI_DSI_PANEL_WUXGA);
diff --git a/drivers/video/msm/msm_dss_io_7x27a.c b/drivers/video/msm/msm_dss_io_7x27a.c
index 28204a5..17ee976 100644
--- a/drivers/video/msm/msm_dss_io_7x27a.c
+++ b/drivers/video/msm/msm_dss_io_7x27a.c
@@ -256,8 +256,11 @@
 	int i, off;
 
 	MIPI_OUTP(MIPI_DSI_BASE + 0x128, 0x0001);/* start phy sw reset */
-	msleep(100);
+	wmb();
+	usleep(1000);
 	MIPI_OUTP(MIPI_DSI_BASE + 0x128, 0x0000);/* end phy w reset */
+	wmb();
+	usleep(1000);
 	MIPI_OUTP(MIPI_DSI_BASE + 0x2cc, 0x0003);/* regulator_ctrl_0 */
 	MIPI_OUTP(MIPI_DSI_BASE + 0x2d0, 0x0001);/* regulator_ctrl_1 */
 	MIPI_OUTP(MIPI_DSI_BASE + 0x2d4, 0x0001);/* regulator_ctrl_2 */
diff --git a/drivers/video/msm/msm_dss_io_8960.c b/drivers/video/msm/msm_dss_io_8960.c
index 30edbd1..70c8afc 100644
--- a/drivers/video/msm/msm_dss_io_8960.c
+++ b/drivers/video/msm/msm_dss_io_8960.c
@@ -231,6 +231,45 @@
 		__func__, (int) ahb, MIPI_INP_SECURE(ahb));
 }
 
+void mipi_dsi_lane_cfg(void)
+{
+	int i, ln_offset;
+
+	ln_offset = 0x300;
+	for (i = 0; i < 4; i++) {
+		/* DSI1_DSIPHY_LN_CFG0 */
+		MIPI_OUTP(MIPI_DSI_BASE + ln_offset, 0x80);
+		/* DSI1_DSIPHY_LN_CFG1 */
+		MIPI_OUTP(MIPI_DSI_BASE + ln_offset + 0x04, 0x45);
+		/* DSI1_DSIPHY_LN_CFG2 */
+		MIPI_OUTP(MIPI_DSI_BASE + ln_offset + 0x08, 0x0);
+		/* DSI1_DSIPHY_LN_TEST_DATAPATH */
+		MIPI_OUTP(MIPI_DSI_BASE + ln_offset + 0x0c, 0x0);
+		/* DSI1_DSIPHY_LN_TEST_STR0 */
+		MIPI_OUTP(MIPI_DSI_BASE + ln_offset + 0x14, 0x1);
+		/* DSI1_DSIPHY_LN_TEST_STR1 */
+		MIPI_OUTP(MIPI_DSI_BASE + ln_offset + 0x18, 0x66);
+		ln_offset += 0x40;
+	}
+
+	MIPI_OUTP(MIPI_DSI_BASE + 0x0400, 0x40); /* DSI1_DSIPHY_LNCK_CFG0 */
+	MIPI_OUTP(MIPI_DSI_BASE + 0x0404, 0x67); /* DSI1_DSIPHY_LNCK_CFG1 */
+	MIPI_OUTP(MIPI_DSI_BASE + 0x0408, 0x0); /* DSI1_DSIPHY_LNCK_CFG2 */
+	/* DSI1_DSIPHY_LNCK_TEST_DATAPATH */
+	MIPI_OUTP(MIPI_DSI_BASE + 0x040c, 0x0);
+	MIPI_OUTP(MIPI_DSI_BASE + 0x0414, 0x1); /* DSI1_DSIPHY_LNCK_TEST_STR0 */
+	/* DSI1_DSIPHY_LNCK_TEST_STR1 */
+	MIPI_OUTP(MIPI_DSI_BASE + 0x0418, 0x88);
+}
+
+void mipi_dsi_bist_ctrl(void)
+{
+	MIPI_OUTP(MIPI_DSI_BASE + 0x049c, 0x0f); /* DSI1_DSIPHY_BIST_CTRL4 */
+	MIPI_OUTP(MIPI_DSI_BASE + 0x0490, 0x03); /* DSI1_DSIPHY_BIST_CTRL1 */
+	MIPI_OUTP(MIPI_DSI_BASE + 0x048c, 0x03); /* DSI1_DSIPHY_BIST_CTRL0 */
+	MIPI_OUTP(MIPI_DSI_BASE + 0x049c, 0x0); /* DSI1_DSIPHY_BIST_CTRL4 */
+}
+
 static void mipi_dsi_calibration(void)
 {
 	int i = 0;
@@ -238,7 +277,7 @@
 	int cal_busy = MIPI_INP(MIPI_DSI_BASE + 0x550);
 
 	/* DSI1_DSIPHY_REGULATOR_CAL_PWR_CFG */
-	MIPI_OUTP(MIPI_DSI_BASE + 0x0518, 0x01);
+	MIPI_OUTP(MIPI_DSI_BASE + 0x0518, 0x03);
 
 	/* DSI1_DSIPHY_CAL_SW_CFG2 */
 	MIPI_OUTP(MIPI_DSI_BASE + 0x0534, 0x0);
@@ -487,14 +526,19 @@
 	int i, off;
 
 	MIPI_OUTP(MIPI_DSI_BASE + 0x128, 0x0001);/* start phy sw reset */
-	msleep(100);
+	wmb();
+	usleep(1);
 	MIPI_OUTP(MIPI_DSI_BASE + 0x128, 0x0000);/* end phy w reset */
+	wmb();
+	usleep(1);
 	MIPI_OUTP(MIPI_DSI_BASE + 0x500, 0x0003);/* regulator_ctrl_0 */
 	MIPI_OUTP(MIPI_DSI_BASE + 0x504, 0x0001);/* regulator_ctrl_1 */
 	MIPI_OUTP(MIPI_DSI_BASE + 0x508, 0x0001);/* regulator_ctrl_2 */
 	MIPI_OUTP(MIPI_DSI_BASE + 0x50c, 0x0000);/* regulator_ctrl_3 */
 	MIPI_OUTP(MIPI_DSI_BASE + 0x510, 0x0100);/* regulator_ctrl_4 */
 
+	MIPI_OUTP(MIPI_DSI_BASE + 0x4b0, 0x04);/* DSIPHY_LDO_CNTRL */
+
 	pd = (panel_info->mipi).dsi_phy_db;
 
 	off = 0x0480;	/* strength 0 - 2 */
@@ -518,6 +562,8 @@
 		off += 4;
 	}
 	mipi_dsi_calibration();
+	mipi_dsi_lane_cfg(); /* lane cfgs */
+	mipi_dsi_bist_ctrl(); /* bist ctrl */
 
 	off = 0x0204;	/* pll ctrl 1 - 19, skip 0 */
 	for (i = 1; i < 20; i++) {
@@ -615,8 +661,8 @@
 	if (clk_set_rate(dsi_byte_div_clk, 1) < 0)	/* divided by 1 */
 		pr_err("%s: dsi_byte_div_clk - "
 			"clk_set_rate failed\n", __func__);
-	if (clk_set_rate(dsi_esc_clk, 2) < 0) /* divided by 2 */
-		pr_err("%s: dsi_esc_clk - "
+	if (clk_set_rate(dsi_esc_clk, esc_byte_ratio) < 0) /* divided by esc */
+		pr_err("%s: dsi_esc_clk - "			 /* clk ratio */
 			"clk_set_rate failed\n", __func__);
 	mipi_dsi_pclk_ctrl(&dsi_pclk, 1);
 	mipi_dsi_clk_ctrl(&dsicore_clk, 1);
diff --git a/drivers/video/msm/msm_dss_io_8x60.c b/drivers/video/msm/msm_dss_io_8x60.c
index bbee726..a1897e3 100644
--- a/drivers/video/msm/msm_dss_io_8x60.c
+++ b/drivers/video/msm/msm_dss_io_8x60.c
@@ -346,8 +346,11 @@
 	int i, off;
 
 	MIPI_OUTP(MIPI_DSI_BASE + 0x128, 0x0001);/* start phy sw reset */
-	msleep(100);
+	wmb();
+	usleep(1);
 	MIPI_OUTP(MIPI_DSI_BASE + 0x128, 0x0000);/* end phy w reset */
+	wmb();
+	usleep(1);
 	MIPI_OUTP(MIPI_DSI_BASE + 0x2cc, 0x0003);/* regulator_ctrl_0 */
 	MIPI_OUTP(MIPI_DSI_BASE + 0x2d0, 0x0001);/* regulator_ctrl_1 */
 	MIPI_OUTP(MIPI_DSI_BASE + 0x2d4, 0x0001);/* regulator_ctrl_2 */
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index b4d8db0..450fa85 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -29,6 +29,7 @@
 #include <linux/dma-mapping.h>
 #include <mach/board.h>
 #include <linux/uaccess.h>
+#include <mach/iommu_domains.h>
 
 #include <linux/workqueue.h>
 #include <linux/string.h>
@@ -48,18 +49,17 @@
 #include "mdp.h"
 #include "mdp4.h"
 
-#ifdef CONFIG_FB_MSM_LOGO
-#define INIT_IMAGE_FILE "/initlogo.rle"
-extern int load_565rle_image(char *filename);
-#endif
-
 #ifdef CONFIG_FB_MSM_TRIPLE_BUFFER
 #define MSM_FB_NUM	3
 #endif
 
+/*  Idle wakelock to prevent PC between wake up and Vsync */
+struct wake_lock mdp_idle_wakelock;
+
 static unsigned char *fbram;
 static unsigned char *fbram_phys;
 static int fbram_size;
+static boolean bf_supported;
 
 static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST];
 static int pdev_list_cnt;
@@ -289,6 +289,9 @@
 	case MIPI_CMD_PANEL:
 		ret = snprintf(buf, PAGE_SIZE, "mipi dsi cmd panel\n");
 		break;
+	case WRITEBACK_PANEL:
+		ret = snprintf(buf, PAGE_SIZE, "writeback panel\n");
+		break;
 	default:
 		ret = snprintf(buf, PAGE_SIZE, "unknown panel\n");
 		break;
@@ -375,6 +378,9 @@
 #ifdef CONFIG_FB_MSM_OVERLAY
 	mfd->overlay_play_enable = 1;
 #endif
+
+	bf_supported = mdp4_overlay_borderfill_supported();
+
 	rc = msm_fb_register(mfd);
 	if (rc)
 		return rc;
@@ -440,6 +446,10 @@
 	complete(&mfd->msmfb_no_update_notify);
 	complete(&mfd->msmfb_update_notify);
 
+	/* Do this only for the primary panel */
+	if (mfd->fbi->node == 0)
+		wake_lock_destroy(&mdp_idle_wakelock);
+
 	/* remove /dev/fb* */
 	unregister_framebuffer(mfd->fbi);
 
@@ -1027,9 +1037,6 @@
 	int *id;
 	int fbram_offset;
 	int remainder, remainder_mode2;
-	static int subsys_id[2] = {MSM_SUBSYSTEM_DISPLAY,
-		MSM_SUBSYSTEM_ROTATOR};
-	unsigned int flags = MSM_SUBSYSTEM_MAP_IOVA;
 
 	/*
 	 * fb info initialization
@@ -1179,18 +1186,26 @@
 	if (!remainder_mode2)
 		remainder_mode2 = PAGE_SIZE;
 
-	/* calculate smem_len based on max size of two supplied modes */
-	fix->smem_len = MAX((msm_fb_line_length(mfd->index, panel_info->xres,
-					      bpp) *
-			    panel_info->yres + PAGE_SIZE -
-				remainder) * mfd->fb_page,
-			    (msm_fb_line_length(mfd->index,
-					       panel_info->mode2_xres,
-					       bpp) *
-			    panel_info->mode2_yres + PAGE_SIZE -
-				remainder_mode2) * mfd->fb_page);
-
-
+	/*
+	 * calculate smem_len based on max size of two supplied modes.
+	 * Only fb0 has mem. fb1 and fb2 don't have mem.
+	 */
+	if (!bf_supported || mfd->index == 0)
+		fix->smem_len = MAX((msm_fb_line_length(mfd->index,
+							panel_info->xres,
+							bpp) *
+				     panel_info->yres + PAGE_SIZE -
+				     remainder) * mfd->fb_page,
+				    (msm_fb_line_length(mfd->index,
+							panel_info->mode2_xres,
+							bpp) *
+				     panel_info->mode2_yres + PAGE_SIZE -
+				     remainder_mode2) * mfd->fb_page);
+	else if (mfd->index == 1 || mfd->index == 2) {
+		pr_debug("%s:%d no memory is allocated for fb%d!\n",
+			__func__, __LINE__, mfd->index);
+		fix->smem_len = 0;
+	}
 
 	mfd->var_xres = panel_info->xres;
 	mfd->var_yres = panel_info->yres;
@@ -1294,25 +1309,33 @@
 	fbram_phys += fbram_offset;
 	fbram_size -= fbram_offset;
 
-	if (fbram_size < fix->smem_len) {
-		printk(KERN_ERR "error: no more framebuffer memory!\n");
-		return -ENOMEM;
-	}
+	if (!bf_supported || mfd->index == 0)
+		if (fbram_size < fix->smem_len) {
+			pr_err("error: no more framebuffer memory!\n");
+			return -ENOMEM;
+		}
 
 	fbi->screen_base = fbram;
 	fbi->fix.smem_start = (unsigned long)fbram_phys;
 
-	mfd->map_buffer = msm_subsystem_map_buffer(
-		fbi->fix.smem_start, fbi->fix.smem_len,
-		flags, subsys_id, 2);
-	if (mfd->map_buffer) {
-		pr_debug("%s(): buf 0x%lx, mfd->map_buffer->iova[0] 0x%lx\n"
-			"mfd->map_buffer->iova[1] 0x%lx", __func__,
-			fbi->fix.smem_start, mfd->map_buffer->iova[0],
-			mfd->map_buffer->iova[1]);
-	}
+	msm_iommu_map_contig_buffer(fbi->fix.smem_start,
+					DISPLAY_DOMAIN,
+					GEN_POOL,
+					fbi->fix.smem_len,
+					SZ_4K,
+					1,
+					&(mfd->display_iova));
 
-	memset(fbi->screen_base, 0x0, fix->smem_len);
+	msm_iommu_map_contig_buffer(fbi->fix.smem_start,
+					ROTATOR_DOMAIN,
+					GEN_POOL,
+					fbi->fix.smem_len,
+					SZ_4K,
+					1,
+					&(mfd->rotator_iova));
+
+	if (!bf_supported || mfd->index == 0)
+		memset(fbi->screen_base, 0x0, fix->smem_len);
 
 	mfd->op_enable = TRUE;
 	mfd->panel_power_on = FALSE;
@@ -1348,6 +1371,9 @@
 		return -EPERM;
 	}
 
+	if (fbi->node == 0)
+		wake_lock_init(&mdp_idle_wakelock, WAKE_LOCK_IDLE, "mdp");
+
 	fbram += fix->smem_len;
 	fbram_phys += fix->smem_len;
 	fbram_size -= fix->smem_len;
@@ -1357,7 +1383,9 @@
 	     mfd->index, fbi->var.xres, fbi->var.yres, fbi->fix.smem_len);
 
 #ifdef CONFIG_FB_MSM_LOGO
-	if (!load_565rle_image(INIT_IMAGE_FILE)) ;	/* Flip buffer */
+	/* Flip buffer */
+	if (!load_565rle_image(INIT_IMAGE_FILE, bf_supported))
+		;
 #endif
 	ret = 0;
 
@@ -1517,7 +1545,12 @@
 	}
 
 	if (!mfd->ref_cnt) {
-		mdp_set_dma_pan_info(info, NULL, TRUE);
+		if (!bf_supported ||
+			(info->node != 1 && info->node != 2))
+			mdp_set_dma_pan_info(info, NULL, TRUE);
+		else
+			pr_debug("%s:%d no mdp_set_dma_pan_info %d\n",
+				__func__, __LINE__, info->node);
 
 		if (msm_fb_blank_sub(FB_BLANK_UNBLANK, info, mfd->op_enable)) {
 			printk(KERN_ERR "msm_fb_open: can't turn on display!\n");
@@ -1565,6 +1598,16 @@
 	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
 	struct msm_fb_panel_data *pdata;
 
+	/*
+	 * If framebuffer is 1 or 2, io pen display is not allowed.
+	 */
+	if (bf_supported &&
+		(info->node == 1 || info->node == 2)) {
+		pr_err("%s: no pan display for fb%d!",
+		       __func__, info->node);
+		return -EPERM;
+	}
+
 	if (info->node != 0 || mfd->cont_splash_done)	/* primary */
 		if ((!mfd->op_enable) || (!mfd->panel_power_on))
 			return -EPERM;
@@ -1585,6 +1628,7 @@
 
 	/* "UPDT" */
 	if (var->reserved[0] == 0x54445055) {
+
 		dirty.xoffset = var->reserved[1] & 0xffff;
 		dirty.yoffset = (var->reserved[1] >> 16) & 0xffff;
 
@@ -1738,9 +1782,13 @@
 	if ((var->xres_virtual <= 0) || (var->yres_virtual <= 0))
 		return -EINVAL;
 
-	if (info->fix.smem_len <
-		(var->xres_virtual*var->yres_virtual*(var->bits_per_pixel/8)))
-		return -EINVAL;
+	if (!bf_supported ||
+		(info->node != 1 && info->node != 2))
+		if (info->fix.smem_len <
+		    (var->xres_virtual*
+		     var->yres_virtual*
+		     (var->bits_per_pixel/8)))
+			return -EINVAL;
 
 	if ((var->xres == 0) || (var->yres == 0))
 		return -EINVAL;
@@ -2593,7 +2641,12 @@
 	struct mdp_blit_req_list req_list_header;
 
 	int count, i, req_list_count;
-
+	if (bf_supported &&
+		(info->node == 1 || info->node == 2)) {
+		pr_err("%s: no pan display for fb%d.",
+		       __func__, info->node);
+		return -EPERM;
+	}
 	/* Get the count size for the total BLIT request. */
 	if (copy_from_user(&req_list_header, p, sizeof(req_list_header)))
 		return -EFAULT;
@@ -3625,10 +3678,19 @@
 	}
 
 	mfd = (struct msm_fb_data_type *)info->par;
-	if (mfd->map_buffer)
-		*start = mfd->map_buffer->iova[subsys_id];
-	else
-		*start = info->fix.smem_start;
+
+	if (subsys_id == DISPLAY_SUBSYSTEM_ID) {
+		if (mfd->display_iova)
+			*start = mfd->display_iova;
+		else
+			*start = info->fix.smem_start;
+	} else {
+		if (mfd->rotator_iova)
+			*start = mfd->rotator_iova;
+		else
+			*start = info->fix.smem_start;
+	}
+
 	*len = info->fix.smem_len;
 
 	return 0;
diff --git a/drivers/video/msm/msm_fb.h b/drivers/video/msm/msm_fb.h
index b63c022..8d45f07 100644
--- a/drivers/video/msm/msm_fb.h
+++ b/drivers/video/msm/msm_fb.h
@@ -23,7 +23,6 @@
 #include "linux/proc_fs.h"
 
 #include <mach/hardware.h>
-#include <mach/msm_subsystem_map.h>
 #include <linux/io.h>
 #include <mach/board.h>
 
@@ -34,6 +33,7 @@
 #include <linux/spinlock.h>
 #include <linux/workqueue.h>
 #include <linux/hrtimer.h>
+#include <linux/wakelock.h>
 
 #include <linux/fb.h>
 #include <linux/list.h>
@@ -44,6 +44,9 @@
 #include <linux/earlysuspend.h>
 #endif
 
+/*  Idle wakelock to prevent PC between wake up and Vsync */
+extern struct wake_lock mdp_idle_wakelock;
+
 #include "msm_fb_panel.h"
 #include "mdp.h"
 
@@ -175,7 +178,8 @@
 	struct list_head writeback_register_queue;
 	wait_queue_head_t wait_q;
 	struct ion_client *iclient;
-	struct msm_mapped_buffer *map_buffer;
+	unsigned long display_iova;
+	unsigned long rotator_iova;
 	struct mdp_buf_type *ov0_wb_buf;
 	struct mdp_buf_type *ov1_wb_buf;
 	u32 ov_start;
@@ -184,6 +188,7 @@
 	u32 use_ov0_blt, ov0_blt_state;
 	u32 use_ov1_blt, ov1_blt_state;
 	u32 writeback_state;
+	bool writeback_active_cnt;
 	int cont_splash_done;
 };
 
@@ -214,4 +219,9 @@
 int msm_fb_check_frame_rate(struct msm_fb_data_type *mfd,
 				struct fb_info *info);
 
+#ifdef CONFIG_FB_MSM_LOGO
+#define INIT_IMAGE_FILE "/initlogo.rle"
+int load_565rle_image(char *filename, bool bf_supported);
+#endif
+
 #endif /* MSM_FB_H */
diff --git a/drivers/video/msm/msm_fb_panel.h b/drivers/video/msm/msm_fb_panel.h
index 9d16b7b..8ccc21c 100644
--- a/drivers/video/msm/msm_fb_panel.h
+++ b/drivers/video/msm/msm_fb_panel.h
@@ -129,6 +129,8 @@
 	char mdp_trigger;
 	char dma_trigger;
 	uint32 dsi_pclk_rate;
+	/* byte to esc clk ratio */
+	uint32 esc_byte_ratio;
 	/* The packet-size should not bet changed */
 	char no_max_pkt_size;
 	/* Clock required during LP commands */
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c
index 8da0995..81b1436 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c
@@ -471,6 +471,10 @@
 	struct ddl_encoder_data *encoder =
 		&ddl->codec_data.encoder;
 	u32 vcd_status = VCD_S_SUCCESS;
+	struct vcd_transc *transc;
+	transc = (struct vcd_transc *)(ddl->client_data);
+	DDL_MSG_LOW("%s: transc = 0x%x, in_use = %u",
+		__func__, (u32)ddl->client_data, transc->in_use);
 	if (encoder->slice_delivery_info.enable) {
 		return ddl_encode_frame_batch(ddl_handle,
 					input_frame,
@@ -480,7 +484,6 @@
 					client_data);
 	}
 
-	DDL_MSG_HIGH("ddl_encode_frame");
 	ddl_set_core_start_time(__func__, ENC_OP_TIME);
 	ddl_context = ddl_get_context();
 	if (!DDL_IS_INITIALIZED(ddl_context)) {
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
index 86f282e..ac1ff24 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
@@ -469,6 +469,8 @@
 u32  ddl_check_reconfig(struct ddl_client_context *ddl);
 void ddl_handle_reconfig(u32 res_change, struct ddl_client_context *ddl);
 void ddl_fill_dec_desc_buffer(struct ddl_client_context *ddl);
+void ddl_set_vidc_timeout(struct ddl_client_context *ddl);
+
 
 #ifdef DDL_BUF_LOG
 void ddl_list_buffers(struct ddl_client_context *ddl);
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h
index 41604b0..8a33512 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h
@@ -30,6 +30,9 @@
 #define DDL_MAX_FRAME_WIDTH   1920
 #define DDL_MAX_FRAME_HEIGHT  1088
 
+#define DDL_MAX_VC1_FRAME_WIDTH		(DDL_MAX_FRAME_WIDTH)
+#define DDL_MAX_VC1_FRAME_HEIGHT	(1280)
+
 #define MAX_DPB_SIZE_L4PT0_MBS    DDL_KILO_BYTE(32)
 #define MAX_FRAME_SIZE_L4PT0_MBS  DDL_KILO_BYTE(8)
 
@@ -55,6 +58,13 @@
 #define DDL_HW_TIMEOUT_IN_MS             1000
 #define DDL_STREAMBUF_ALIGN_GUARD_BYTES  0x7FF
 
+#define DDL_VIDC_1080P_48MHZ			(48000000)
+#define DDL_VIDC_1080P_133MHZ			(133330000)
+#define DDL_VIDC_1080P_200MHZ			(200000000)
+#define DDL_VIDC_1080P_48MHZ_TIMEOUT_VALUE	(0xCB8)
+#define DDL_VIDC_1080P_133MHZ_TIMEOUT_VALUE	(0x2355)
+#define DDL_VIDC_1080P_200MHZ_TIMEOUT_VALUE	(0x3500)
+
 #define DDL_CONTEXT_MEMORY (1024 * 15 * (VCD_MAX_NO_CLIENT + 1))
 
 #define DDL_ENC_MIN_DPB_BUFFERS           2
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
index 6d3a05a..64d2976 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
@@ -744,11 +744,11 @@
 				memset(dec_bufs->desc.align_virtual_addr,
 					   0, buf_size.sz_desc);
 				msm_ion_do_cache_op(
-						ddl_context->video_ion_client,
-						dec_bufs->desc.alloc_handle,
-						dec_bufs->desc.alloc_handle,
-						dec_bufs->desc.buffer_size,
-						ION_IOC_CLEAN_INV_CACHES);
+					ddl_context->video_ion_client,
+					dec_bufs->desc.alloc_handle,
+					dec_bufs->desc.virtual_base_addr,
+					dec_bufs->desc.buffer_size,
+					ION_IOC_CLEAN_INV_CACHES);
 			}
 		}
 	}
@@ -1061,3 +1061,14 @@
 			   ip_bitstream->desc_buf,
 			   ip_bitstream->desc_size);
 }
+
+void ddl_set_vidc_timeout(struct ddl_client_context *ddl)
+{
+	u32 vidc_time_out = 0;
+	if (ddl->codec_data.decoder.idr_only_decoding)
+		vidc_time_out = 2 * DDL_VIDC_1080P_200MHZ_TIMEOUT_VALUE;
+	DDL_MSG_HIGH("%s Video core time out value = 0x%x",
+		 __func__, vidc_time_out);
+	vidc_sm_set_video_core_timeout_value(
+		&ddl->shared_mem[ddl->command_channel], vidc_time_out);
+}
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 5b9aea8..6b8f5b2 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
@@ -34,6 +34,8 @@
 static void ddl_handle_slice_done_slice_batch(struct ddl_client_context *ddl);
 static void ddl_handle_enc_frame_done_slice_mode(
 		struct ddl_client_context *ddl, u32 eos_present);
+static void ddl_handle_enc_skipframe_slice_mode(
+		struct ddl_client_context *ddl, u32 eos_present);
 
 static void ddl_fw_status_done_callback(struct ddl_context *ddl_context)
 {
@@ -310,6 +312,20 @@
 					return process_further;
 				}
 			break;
+		case VCD_CODEC_VC1:
+		case VCD_CODEC_VC1_RCV:
+			if ((seq_hdr_info.img_size_x >
+					DDL_MAX_VC1_FRAME_WIDTH) ||
+				(seq_hdr_info.img_size_y >
+					DDL_MAX_VC1_FRAME_HEIGHT)) {
+				DDL_MSG_ERROR("Unsupported VC1 clip: "
+					"Resolution X=%d and Y=%d",
+					seq_hdr_info.img_size_x,
+					seq_hdr_info.img_size_y);
+					ddl_client_fatal_cb(ddl);
+					return process_further;
+			}
+			break;
 		default:
 			break;
 		}
@@ -511,11 +527,15 @@
 		if (encoder->enc_frame_info.enc_frame_size ||
 			(encoder->enc_frame_info.enc_frame ==
 			VIDC_1080P_ENCODE_FRAMETYPE_SKIPPED) ||
-			DDLCLIENT_STATE_IS(ddl,
-			DDL_CLIENT_WAIT_FOR_EOS_DONE)) {
+			DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_WAIT_FOR_EOS_DONE)) {
 			if (encoder->slice_delivery_info.enable) {
-				ddl_handle_enc_frame_done_slice_mode(ddl,
-								eos_present);
+				if (encoder->enc_frame_info.enc_frame ==
+					VIDC_1080P_ENCODE_FRAMETYPE_SKIPPED)
+					ddl_handle_enc_skipframe_slice_mode(
+							ddl, eos_present);
+				else
+					ddl_handle_enc_frame_done_slice_mode(
+							ddl, eos_present);
 			} else {
 				ddl_handle_enc_frame_done(ddl, eos_present);
 			}
@@ -1892,3 +1912,78 @@
 				(u32 *) ddl, ddl->client_data);
 	}
 }
+
+static void ddl_handle_enc_skipframe_slice_mode(
+		struct ddl_client_context *ddl, u32 eos_present)
+{
+	struct ddl_context       *ddl_context = ddl->ddl_context;
+	struct ddl_encoder_data  *encoder = &(ddl->codec_data.encoder);
+	struct vcd_frame_data    *output_frame = NULL;
+	u32 bottom_frame_tag;
+	u8 *input_buffer_address = NULL;
+	u32 index = 0;
+	DDL_MSG_HIGH("ddl_handle_enc_skipframe_slice_mode: frame skipped");
+	vidc_sm_set_encoder_slice_batch_int_ctrl(
+			&ddl->shared_mem[ddl->command_channel],
+			1);
+	for (index = 0;
+		index < encoder->batch_frame.num_output_frames;
+		index++) {
+		output_frame =
+			&(encoder->batch_frame.output_frame[index].vcd_frm);
+		DDL_MSG_MED("output buffer: vcd_frm = 0x%x "
+				"frmbfr(virtual) = 0x%x frmbfr(physical) = 0x%x",
+				(u32)output_frame, (u32)output_frame->virtual,
+				(u32)output_frame->physical);
+		vidc_sm_get_frame_tags(
+				&ddl->shared_mem[ddl->command_channel],
+				&output_frame->ip_frm_tag,
+				&bottom_frame_tag);
+		ddl_get_encoded_frame(
+				output_frame,
+				encoder->codec.codec,
+				encoder->enc_frame_info.enc_frame);
+		output_frame->data_len = 0;
+		ddl->output_frame.frm_trans_end = false;
+		if (encoder->batch_frame.num_output_frames ==
+			(index + 1)) {
+			DDL_MSG_MED("last output bfr for skip frame, set EOF");
+			output_frame->flags |= VCD_FRAME_FLAG_ENDOFFRAME;
+			ddl_vidc_encode_dynamic_property(ddl, false);
+			if (eos_present)
+				ddl->output_frame.frm_trans_end = false;
+			else
+				ddl->output_frame.frm_trans_end = true;
+		}
+		ddl->output_frame.vcd_frm = *output_frame;
+		ddl_context->ddl_callback(
+				VCD_EVT_RESP_OUTPUT_DONE,
+				VCD_S_SUCCESS,
+				&(ddl->output_frame),
+				sizeof(struct ddl_frame_data_tag),
+				(u32 *)ddl,
+				ddl->client_data);
+
+		if (encoder->batch_frame.num_output_frames ==
+			(index + 1)) {
+			ddl->input_frame.frm_trans_end = false;
+			input_buffer_address =
+				ddl_context->dram_base_a.physical_base_addr +
+				(encoder->enc_frame_info.enc_luma_address);
+			ddl_get_input_frame_from_pool(ddl,
+					input_buffer_address);
+			DDL_MSG_MED("InpBfr: vcd_frm 0x%x frmbfr(virtual) 0x%x"
+					" frmbfr(physical) 0x%x",
+					(u32)&(ddl->input_frame.vcd_frm),
+					(u32)ddl->input_frame.vcd_frm.virtual,
+					(u32)ddl->input_frame.vcd_frm.physical);
+			ddl_context->ddl_callback(
+					VCD_EVT_RESP_INPUT_DONE,
+					VCD_S_SUCCESS,
+					&(ddl->input_frame),
+					sizeof(struct ddl_frame_data_tag),
+					(u32 *)ddl,
+					ddl->client_data);
+		}
+	}
+}
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
index 363fe53..3827bc1 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
@@ -983,8 +983,7 @@
 			DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_OPEN)) {
 			encoder->slice_delivery_info.enable
 				= *(u32 *)property_value;
-			DDL_MSG_HIGH("set encoder->slice_delivery_mode"
-				"  = %u\n",
+			DDL_MSG_HIGH("set encoder->slice_delivery_mode = %u\n",
 				encoder->slice_delivery_info.enable);
 			output_buf_size =
 				encoder->client_output_buf_req.sz;
@@ -998,8 +997,26 @@
 			encoder->slice_delivery_info.num_slices =
 				num_slices;
 			if (num_slices <= DDL_MAX_NUM_BFRS_FOR_SLICE_BATCH) {
-				encoder->client_output_buf_req.min_count
-				= ((DDL_ENC_SLICE_BATCH_FACTOR * num_slices + 2)
+				DDL_MSG_HIGH("%s: currently slice info "
+					"metadata is not supported when slice "
+					"delivery mode is enabled. hence "
+					"disabling slice info metadata.\n",
+					__func__);
+				slice_property_hdr.prop_id =
+					VCD_I_METADATA_ENABLE;
+				slice_property_hdr.sz =
+					sizeof(struct \
+					vcd_property_meta_data_enable);
+				ddl_get_metadata_params(ddl,
+						&slice_property_hdr,
+						&slice_meta_data);
+				slice_meta_data.meta_data_enable_flag
+					&= ~VCD_METADATA_ENC_SLICE;
+				ddl_set_metadata_params(ddl,
+						&slice_property_hdr,
+						&slice_meta_data);
+				encoder->client_output_buf_req.min_count =
+				((DDL_ENC_SLICE_BATCH_FACTOR * num_slices + 2)
 				> DDL_MAX_BUFFER_COUNT)
 				? DDL_MAX_BUFFER_COUNT :
 				(DDL_ENC_SLICE_BATCH_FACTOR * num_slices + 2);
@@ -1016,18 +1033,6 @@
 				encoder->client_output_buf_req.min_count,
 				output_buf_size,
 				encoder->client_output_buf_req.sz);
-				slice_property_hdr.prop_id =
-					VCD_I_METADATA_ENABLE;
-				slice_property_hdr.sz =
-				sizeof(struct vcd_property_meta_data_enable);
-				ddl_get_metadata_params(ddl,
-						&slice_property_hdr,
-						&slice_meta_data);
-				slice_meta_data.meta_data_enable_flag
-					&= ~VCD_METADATA_ENC_SLICE;
-				ddl_set_metadata_params(ddl,
-						&slice_property_hdr,
-						&slice_meta_data);
 				vcd_status = VCD_S_SUCCESS;
 			}
 		}
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
index ac81916..839a9c1 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
@@ -207,7 +207,7 @@
 #define VIDC_SM_MPEG4_ASPECT_RATIO_INFO_SHFT         0x0
 #define VIDC_SM_EXTENDED_PAR_ADDR                    0x00cc
 #define VIDC_SM_EXTENDED_PAR_WIDTH_BMSK              0xffff0000
-#define VIDC_SM_EXTENDED_PAR_WIDTH_SHFT              0xf
+#define VIDC_SM_EXTENDED_PAR_WIDTH_SHFT              16
 #define VIDC_SM_EXTENDED_PAR_HEIGHT_BMSK             0x0000ffff
 #define VIDC_SM_EXTENDED_PAR_HEIGHT_SHFT             0x0
 
@@ -243,6 +243,10 @@
 
 #define VIDC_SM_NUM_STUFF_BYTES_CONSUME_ADDR    0X01ac
 
+#define VIDC_SM_TIMEOUT_VALUE_ADDR        0x0158
+#define VIDC_SM_TIMEOUT_VALUE_BMSK        0xffffffff
+#define VIDC_SM_TIMEOUT_VALUE_SHFT        0
+
 #define VIDC_SM_ENC_EXT_CTRL_CLOSED_GOP_ENABLE_BMSK	0x40
 #define VIDC_SM_ENC_EXT_CTRL_CLOSED_GOP_ENABLE_SHFT	6
 
@@ -862,3 +866,11 @@
 	*output_buffer_size = DDL_MEM_READ_32(shared_mem,
 			VIDC_SM_BATCH_OUTPUT_SIZE_ADDR);
 }
+
+void vidc_sm_set_video_core_timeout_value(struct ddl_buf_addr *shared_mem,
+	u32 timeout)
+{
+	DDL_MEM_WRITE_32(shared_mem, VIDC_SM_TIMEOUT_VALUE_ADDR,
+			timeout);
+}
+
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
index 7d9896f..6cd75595 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
@@ -191,4 +191,6 @@
 				u32 output_buffer_size);
 void vidc_sm_get_encoder_batch_output_size(struct ddl_buf_addr *shared_mem,
 	u32 *output_buffer_size);
+void vidc_sm_set_video_core_timeout_value(struct ddl_buf_addr *shared_mem,
+	u32 timeout);
 #endif
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
index 97c8d0d..d0cf4e8 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
@@ -977,6 +977,7 @@
 		DDL_MSG_ERROR("STATE-CRITICAL");
 		return VCD_ERR_FAIL;
 	}
+	ddl_set_vidc_timeout(ddl);
 	ddl_vidc_decode_set_metadata_output(decoder);
 	if (decoder->dp_buf.no_of_dec_pic_buf <
 		decoder->client_output_buf_req.actual_count)
diff --git a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
index e71259a..c8365ce 100644
--- a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
+++ b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
@@ -382,7 +382,7 @@
 	return status;
 }
 
-static u32 res_trk_get_clk_rate(unsigned long *phclk_rate)
+u32 res_trk_get_clk_rate(unsigned long *phclk_rate)
 {
 	u32 status = true;
 	mutex_lock(&resource_context.lock);
diff --git a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker_api.h b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker_api.h
index 99b123c..2ae2512 100644
--- a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker_api.h
+++ b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker_api.h
@@ -49,4 +49,5 @@
 int res_trk_disable_footswitch(void);
 void res_trk_release_fw_addr(void);
 u32 res_trk_estimate_perf_level(u32 pn_perf_lvl);
+u32 res_trk_get_clk_rate(unsigned long *phclk_rate);
 #endif
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c b/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c
index 0d5ba9c..5019d31 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c
@@ -502,7 +502,12 @@
 	}
 
 	rc = ddl_set_property(cctxt->ddl_handle, prop_hdr, prop_val);
-	VCD_FAILED_RETURN(rc, "Failed: ddl_set_property");
+	if (rc) {
+		/* Some properties aren't known to ddl that we can handle */
+		if (prop_hdr->prop_id != VCD_I_VOP_TIMING_CONSTANT_DELTA)
+			VCD_FAILED_RETURN(rc, "Failed: ddl_set_property");
+	}
+
 	switch (prop_hdr->prop_id) {
 	case VCD_I_META_BUFFER_MODE:
 		{
@@ -537,16 +542,30 @@
 			break;
 		}
 	case VCD_I_INTRA_PERIOD:
-	   {
-		  struct vcd_property_i_period *iperiod =
-			 (struct vcd_property_i_period *)prop_val;
-		  cctxt->bframe = iperiod->b_frames;
-		  break;
-	   }
+		{
+			struct vcd_property_i_period *iperiod =
+				(struct vcd_property_i_period *)prop_val;
+			cctxt->bframe = iperiod->b_frames;
+			break;
+		}
 	case VCD_REQ_PERF_LEVEL:
 		rc = vcd_req_perf_level(cctxt,
-			(struct vcd_property_perf_level *)prop_val);
+				(struct vcd_property_perf_level *)prop_val);
 		break;
+	case VCD_I_VOP_TIMING_CONSTANT_DELTA:
+		{
+			struct vcd_property_vop_timing_constant_delta *delta =
+				prop_val;
+
+			if (delta->constant_delta > 0) {
+				cctxt->time_frame_delta = delta->constant_delta;
+				rc = VCD_S_SUCCESS;
+			} else {
+				VCD_MSG_ERROR("Frame delta must be positive");
+				rc = VCD_ERR_ILLEGAL_PARM;
+			}
+			break;
+		}
 	default:
 		{
 			break;
@@ -559,6 +578,7 @@
     (struct vcd_clnt_ctxt *cctxt,
      struct vcd_property_hdr *prop_hdr, void *prop_val)
 {
+	int rc;
 	VCD_MSG_LOW("vcd_get_property_cmn in %d:", cctxt->clnt_state.state);
 	VCD_MSG_LOW("property Id = %d", prop_hdr->prop_id);
 	if (!prop_hdr->sz || !prop_hdr->prop_id) {
@@ -566,7 +586,24 @@
 
 		return VCD_ERR_ILLEGAL_PARM;
 	}
-	return ddl_get_property(cctxt->ddl_handle, prop_hdr, prop_val);
+	rc = ddl_get_property(cctxt->ddl_handle, prop_hdr, prop_val);
+	if (rc) {
+		/* Some properties aren't known to ddl that we can handle */
+		if (prop_hdr->prop_id != VCD_I_VOP_TIMING_CONSTANT_DELTA)
+			VCD_FAILED_RETURN(rc, "Failed: ddl_set_property");
+	}
+
+	switch (prop_hdr->prop_id) {
+	case VCD_I_VOP_TIMING_CONSTANT_DELTA:
+	{
+		struct vcd_property_vop_timing_constant_delta *delta =
+			(struct vcd_property_vop_timing_constant_delta *)
+			prop_val;
+		delta->constant_delta = cctxt->time_frame_delta;
+		rc = VCD_S_SUCCESS;
+	}
+	}
+	return rc;
 }
 
 static u32 vcd_set_buffer_requirements_cmn
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_core.h b/drivers/video/msm/vidc/common/vcd/vcd_core.h
index d228146..7ae4f45 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_core.h
+++ b/drivers/video/msm/vidc/common/vcd/vcd_core.h
@@ -191,6 +191,7 @@
 	u32 frm_p_units;
 	u32 reqd_perf_lvl;
 	u32 time_resoln;
+	u32 time_frame_delta;
 
 	struct vcd_buffer_pool in_buf_pool;
 	struct vcd_buffer_pool out_buf_pool;
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_device_sm.c b/drivers/video/msm/vidc/common/vcd/vcd_device_sm.c
index 49d885c..d517028 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_device_sm.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_device_sm.c
@@ -129,10 +129,16 @@
 		{
 			transc = (struct vcd_transc *)client_data;
 
-			if (!transc || !transc->in_use
-				|| !transc->cctxt) {
+			if (!transc || !transc->in_use || !transc->cctxt) {
 				VCD_MSG_ERROR("Invalid clientdata "
-							  "received from DDL ");
+					"received from DDL, transc = 0x%x\n",
+					(u32)transc);
+				if (transc) {
+					VCD_MSG_ERROR("transc->in_use = %u, "
+						"transc->cctxt = 0x%x\n",
+						transc->in_use,
+						(u32)transc->cctxt);
+				}
 			} else {
 				cctxt = transc->cctxt;
 
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_sub.c b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
index 2df7144..6ca4dbe 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_sub.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
@@ -1900,9 +1900,10 @@
 	} else {
 		memset(&dev_ctxt->trans_tbl[i], 0,
 			   sizeof(struct vcd_transc));
-
 		dev_ctxt->trans_tbl[i].in_use = true;
-
+		VCD_MSG_LOW("%s: Get transc = 0x%x, in_use = %u\n",
+			__func__, (u32)(&dev_ctxt->trans_tbl[i]),
+			dev_ctxt->trans_tbl[i].in_use);
 		return &dev_ctxt->trans_tbl[i];
 	}
 }
@@ -1911,7 +1912,8 @@
 {
 	if (trans_entry) {
 		trans_entry->in_use = false;
-		VCD_MSG_LOW("%s in_use set to false\n", __func__);
+		VCD_MSG_LOW("%s: Free transc = 0x%x, in_use = %u\n",
+			__func__, (u32)trans_entry, trans_entry->in_use);
 	}
 }
 
@@ -2387,6 +2389,7 @@
 	u32 rc, seqhdr_present = 0;
 	struct vcd_property_hdr prop_hdr;
 	struct vcd_sequence_hdr seq_hdr;
+	struct vcd_property_sps_pps_for_idr_enable idr_enable;
 	struct vcd_property_codec codec;
 	*handled = true;
 	prop_hdr.prop_id = DDL_I_SEQHDR_PRESENT;
@@ -2403,29 +2406,64 @@
 	rc = ddl_get_property(cctxt->ddl_handle, &prop_hdr, &codec);
 	if (!VCD_FAILED(rc)) {
 		if (codec.codec != VCD_CODEC_H263) {
-			prop_hdr.prop_id = VCD_I_SEQ_HEADER;
-			prop_hdr.sz = sizeof(struct vcd_sequence_hdr);
-			seq_hdr.sequence_header = frm_entry->virtual;
-			seq_hdr.sequence_header_len =
-				frm_entry->alloc_len;
-			rc = ddl_get_property(cctxt->ddl_handle,
-				&prop_hdr, &seq_hdr);
-			if (!VCD_FAILED(rc)) {
-				frm_entry->data_len =
-					seq_hdr.sequence_header_len;
-				frm_entry->time_stamp = 0;
-				frm_entry->flags |=
-					VCD_FRAME_FLAG_CODECCONFIG;
+			/*
+			 * The seq. header is stored in a seperate internal
+			 * buffer and is memcopied into the output buffer
+			 * that we provide.  In secure sessions, we aren't
+			 * allowed to touch these buffers.  In these cases
+			 * seq. headers are returned to client as part of
+			 * I-frames. So for secure session, just return
+			 * empty buffer.
+			 */
+			if (!cctxt->secure) {
+				prop_hdr.prop_id = VCD_I_SEQ_HEADER;
+				prop_hdr.sz = sizeof(struct vcd_sequence_hdr);
+				seq_hdr.sequence_header = frm_entry->virtual;
+				seq_hdr.sequence_header_len =
+					frm_entry->alloc_len;
+				rc = ddl_get_property(cctxt->ddl_handle,
+						&prop_hdr, &seq_hdr);
+				if (!VCD_FAILED(rc)) {
+					frm_entry->data_len =
+						seq_hdr.sequence_header_len;
+					frm_entry->time_stamp = 0;
+					frm_entry->flags |=
+						VCD_FRAME_FLAG_CODECCONFIG;
+				} else
+					VCD_MSG_ERROR("rc = 0x%x. Failed:"
+							"ddl_get_property: VCD_I_SEQ_HEADER",
+							rc);
+			} else {
+				/*
+				 * First check that the proper props are enabled
+				 * so  client can get the proper info eventually
+				 */
+				prop_hdr.prop_id = VCD_I_ENABLE_SPS_PPS_FOR_IDR;
+				prop_hdr.sz = sizeof(idr_enable);
+				rc = ddl_get_property(cctxt->ddl_handle,
+						&prop_hdr, &idr_enable);
+				if (!VCD_FAILED(rc)) {
+					if (!idr_enable.
+						sps_pps_for_idr_enable_flag) {
+						VCD_MSG_ERROR("SPS/PPS per IDR "
+							"needs to be enabled");
+						rc = VCD_ERR_BAD_STATE;
+					} else {
+						/* Send zero len frame */
+						frm_entry->data_len = 0;
+						frm_entry->time_stamp = 0;
+						frm_entry->flags = 0;
+					}
+				}
+
+			}
+
+			if (!VCD_FAILED(rc))
 				cctxt->callback(VCD_EVT_RESP_OUTPUT_DONE,
-					VCD_S_SUCCESS, frm_entry,
-					sizeof(struct vcd_frame_data),
-					cctxt,
-					cctxt->client_data);
-			} else
-			VCD_MSG_ERROR(
-				"rc = 0x%x. Failed:\
-				ddl_get_property: VCD_I_SEQ_HEADER",
-				rc);
+						VCD_S_SUCCESS, frm_entry,
+						sizeof(struct vcd_frame_data),
+						cctxt,
+						cctxt->client_data);
 		} else
 			VCD_MSG_LOW("Codec Type is H.263\n");
 	} else
@@ -3052,13 +3090,15 @@
 	u32 frm_delta;
 	u64 temp, max = ~((u64)0);
 
-	if (frame->time_stamp >= cctxt->status.prev_ts)
+	if (cctxt->time_frame_delta)
+		temp = cctxt->time_frame_delta;
+	else if (frame->time_stamp >= cctxt->status.prev_ts)
 		temp = frame->time_stamp - cctxt->status.prev_ts;
 	else
 		temp = (max - cctxt->status.prev_ts) +
 			frame->time_stamp;
 
-	VCD_MSG_LOW("Curr_ts=%lld  Prev_ts=%lld Diff=%llu",
+	VCD_MSG_LOW("Curr_ts=%lld  Prev_ts=%lld Diff=%llu\n",
 			frame->time_stamp, cctxt->status.prev_ts, temp);
 
 	temp *= cctxt->time_resoln;
diff --git a/fs/fat/misc.c b/fs/fat/misc.c
index 6d93360..a1d192d 100644
--- a/fs/fat/misc.c
+++ b/fs/fat/misc.c
@@ -56,7 +56,11 @@
 	va_start(args, fmt);
 	vaf.fmt = fmt;
 	vaf.va = &args;
-	printk("%sFAT-fs (%s): %pV\n", level, sb->s_id, &vaf);
+	if (!strncmp(level, KERN_ERR, sizeof(KERN_ERR)))
+		printk_ratelimited("%sFAT-fs (%s): %pV\n", level,
+				   sb->s_id, &vaf);
+	else
+		printk("%sFAT-fs (%s): %pV\n", level, sb->s_id, &vaf);
 	va_end(args);
 }
 
diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
index 6395692..47b1fe3 100644
--- a/include/linux/blk_types.h
+++ b/include/linux/blk_types.h
@@ -151,6 +151,7 @@
 	__REQ_IO_STAT,		/* account I/O stat */
 	__REQ_MIXED_MERGE,	/* merge of different types, fail separately */
 	__REQ_SECURE,		/* secure discard (used with __REQ_DISCARD) */
+	__REQ_SANITIZE,		/* sanitize */
 	__REQ_NR_BITS,		/* stops here */
 };
 
@@ -161,13 +162,14 @@
 #define REQ_SYNC		(1 << __REQ_SYNC)
 #define REQ_META		(1 << __REQ_META)
 #define REQ_DISCARD		(1 << __REQ_DISCARD)
+#define REQ_SANITIZE		(1 << __REQ_SANITIZE)
 #define REQ_NOIDLE		(1 << __REQ_NOIDLE)
 
 #define REQ_FAILFAST_MASK \
 	(REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER)
 #define REQ_COMMON_MASK \
 	(REQ_WRITE | REQ_FAILFAST_MASK | REQ_SYNC | REQ_META | REQ_DISCARD | \
-	 REQ_NOIDLE | REQ_FLUSH | REQ_FUA | REQ_SECURE)
+	 REQ_NOIDLE | REQ_FLUSH | REQ_FUA | REQ_SECURE | REQ_SANITIZE)
 #define REQ_CLONE_MASK		REQ_COMMON_MASK
 
 #define REQ_RAHEAD		(1 << __REQ_RAHEAD)
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 1b13021..4dc4b3e 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -403,6 +403,7 @@
 #define QUEUE_FLAG_NOXMERGES   15	/* No extended merges */
 #define QUEUE_FLAG_ADD_RANDOM  16	/* Contributes to random pool */
 #define QUEUE_FLAG_SECDISCARD  17	/* supports SECDISCARD */
+#define QUEUE_FLAG_SANITIZE    19	/* supports SANITIZE */
 
 #define QUEUE_FLAG_DEFAULT	((1 << QUEUE_FLAG_IO_STAT) |		\
 				 (1 << QUEUE_FLAG_STACKABLE)	|	\
@@ -485,6 +486,7 @@
 #define blk_queue_stackable(q)	\
 	test_bit(QUEUE_FLAG_STACKABLE, &(q)->queue_flags)
 #define blk_queue_discard(q)	test_bit(QUEUE_FLAG_DISCARD, &(q)->queue_flags)
+#define blk_queue_sanitize(q)	test_bit(QUEUE_FLAG_SANITIZE, &(q)->queue_flags)
 #define blk_queue_secdiscard(q)	(blk_queue_discard(q) && \
 	test_bit(QUEUE_FLAG_SECDISCARD, &(q)->queue_flags))
 
@@ -922,6 +924,7 @@
 extern int blkdev_issue_flush(struct block_device *, gfp_t, sector_t *);
 extern int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
 		sector_t nr_sects, gfp_t gfp_mask, unsigned long flags);
+extern int blkdev_issue_sanitize(struct block_device *bdev, gfp_t gfp_mask);
 extern int blkdev_issue_zeroout(struct block_device *bdev, sector_t sector,
 			sector_t nr_sects, gfp_t gfp_mask);
 static inline int sb_issue_discard(struct super_block *sb, sector_t block,
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 957c5b4..2e0e32e 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -56,6 +56,10 @@
 #define CPUFREQ_POLICY_POWERSAVE	(1)
 #define CPUFREQ_POLICY_PERFORMANCE	(2)
 
+/* Minimum frequency cutoff to notify the userspace about cpu utilization
+ * changes */
+#define MIN_CPU_UTIL_NOTIFY   40
+
 /* Frequency values here are CPU kHz so that hardware which doesn't run
  * with some frequencies can complain without having to guess what per
  * cent / per mille means.
@@ -96,6 +100,7 @@
 	unsigned int		max;    /* in kHz */
 	unsigned int		cur;    /* in kHz, only needed if cpufreq
 					 * governors are used */
+	unsigned int            util;  /* CPU utilization at max frequency */
 	unsigned int		policy; /* see above */
 	struct cpufreq_governor	*governor; /* see below */
 
@@ -255,7 +260,8 @@
 
 
 void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state);
-
+void cpufreq_notify_utilization(struct cpufreq_policy *policy,
+		unsigned int load);
 
 static inline void cpufreq_verify_within_limits(struct cpufreq_policy *policy, unsigned int min, unsigned int max)
 {
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index e50a054..537960b 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -52,7 +52,7 @@
 #define APQ8030_TOOLS_ID	4079
 #define MSM8627_TOOLS_ID	4080
 #define MSM8227_TOOLS_ID	4081
-#define MSM8974_TOOLS_ID	4072
+#define MSM8974_TOOLS_ID	4083
 
 #define MSG_MASK_0			(0x00000001)
 #define MSG_MASK_1			(0x00000002)
diff --git a/include/linux/dvb/dmx.h b/include/linux/dvb/dmx.h
index 7f963e6..e0058d3 100644
--- a/include/linux/dvb/dmx.h
+++ b/include/linux/dvb/dmx.h
@@ -99,16 +99,40 @@
 } dmx_filter_t;
 
 
+/* Filter flags */
+#define DMX_CHECK_CRC		0x01
+#define DMX_ONESHOT		0x02
+#define DMX_IMMEDIATE_START	0x04
+#define DMX_ENABLE_INDEXING	0x08
+#define DMX_KERNEL_CLIENT	0x8000
+
 struct dmx_sct_filter_params
 {
 	__u16          pid;
 	dmx_filter_t   filter;
 	__u32          timeout;
 	__u32          flags;
-#define DMX_CHECK_CRC       1
-#define DMX_ONESHOT         2
-#define DMX_IMMEDIATE_START 4
-#define DMX_KERNEL_CLIENT   0x8000
+};
+
+
+/* Indexing: supported video standards */
+enum dmx_indexing_video_standard {
+	DMX_INDEXING_MPEG2,
+	DMX_INDEXING_H264,
+	DMX_INDEXING_VC1
+};
+
+/* Indexing: Supported video profiles */
+enum dmx_indexing_video_profile {
+	DMX_INDEXING_MPEG2_ANY,
+	DMX_INDEXING_H264_ANY,
+	DMX_INDEXING_VC1_ANY
+};
+
+/* Indexing: video configuration parameters */
+struct dmx_indexing_video_params {
+	enum dmx_indexing_video_standard standard;
+	enum dmx_indexing_video_profile profile;
 };
 
 
@@ -119,6 +143,8 @@
 	dmx_output_t   output;
 	dmx_pes_type_t pes_type;
 	__u32          flags;
+
+	struct dmx_indexing_video_params video_params;
 };
 
 struct dmx_buffer_status {
@@ -146,7 +172,60 @@
 
 typedef struct dmx_caps {
 	__u32 caps;
+
+/* Indicates whether demux support playback from memory in pull mode */
+#define DMX_CAP_PULL_MODE				0x01
+
+/* Indicates whether demux support indexing of recorded video stream */
+#define DMX_CAP_VIDEO_INDEXING			0x02
+
+/* Indicates whether demux support sending data directly to video decoder */
+#define DMX_CAP_VIDEO_DECODER_DATA		0x04
+
+/* Indicates whether demux support sending data directly to audio decoder */
+#define DMX_CAP_AUDIO_DECODER_DATA		0x08
+
+/* Indicates whether demux support sending data directly to subtitle decoder */
+#define DMX_CAP_SUBTITLE_DECODER_DATA	0x10
+
+	/* Number of decoders demux can output data to */
 	int num_decoders;
+
+	/* Number of demux devices */
+	int num_demux_devices;
+
+	/* Max number of PID filters */
+	int num_pid_filters;
+
+	/* Max number of section filters */
+	int num_section_filters;
+
+	/*
+	 * Max number of section filters using same PID,
+	 * 0 if not supported
+	 */
+	int num_section_filters_per_pid;
+
+	/*
+	 * Length of section filter, not including section
+	 * length field (2 bytes).
+	 */
+	int section_filter_length;
+
+	/* Max number of demod based input */
+	int num_demod_inputs;
+
+	/* Max number of memory based input */
+	int num_memory_inputs;
+
+	/* Overall bitrate from all inputs concurrently. Mbit/sec */
+	int max_bitrate;
+
+	/* Max bitrate from single demod input. Mbit/sec */
+	int demod_input_max_bitrate;
+
+	/* Max bitrate from single memory input. Mbit/sec */
+	int memory_input_max_bitrate;
 } dmx_caps_t;
 
 typedef enum {
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 35e4edf..1c91125 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -317,6 +317,7 @@
 #define BLKPBSZGET _IO(0x12,123)
 #define BLKDISCARDZEROES _IO(0x12,124)
 #define BLKSECDISCARD _IO(0x12,125)
+#define BLKSANITIZE _IO(0x12, 126)
 
 #define BMAP_IOCTL 1		/* obsolete - kept for compatibility */
 #define FIBMAP	   _IO(0x00,1)	/* bmap access */
diff --git a/include/linux/i2c/isa1200.h b/include/linux/i2c/isa1200.h
index 4c36d59..9dab3eb 100644
--- a/include/linux/i2c/isa1200.h
+++ b/include/linux/i2c/isa1200.h
@@ -3,7 +3,7 @@
  *
  *  Copyright (C) 2009 Samsung Electronics
  *  Kyungmin Park <kyungmin.park@samsung.com>
- *  Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *  Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -55,6 +55,7 @@
 	u8 num_regulators;
 	int (*power_on)(int on);
 	int (*dev_setup)(bool on);
+	int (*clk_enable)(bool on);
 };
 
 #endif /* __LINUX_ISA1200_H */
diff --git a/include/linux/input.h b/include/linux/input.h
index 6e7d6d9..191f7d7 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -817,7 +817,8 @@
 #define SW_ROTATE_LOCK		0x0c  /* set = rotate locked/disabled */
 #define SW_HPHL_OVERCURRENT	0x0d  /* set = over current on left hph */
 #define SW_HPHR_OVERCURRENT	0x0e  /* set = over current on right hph */
-#define SW_MAX			0x0f
+#define SW_UNSUPPORT_INSERT	0x0f  /* set = unsupported device inserted */
+#define SW_MAX			0x10
 #define SW_CNT			(SW_MAX+1)
 
 /*
diff --git a/include/linux/ion.h b/include/linux/ion.h
index b5495a0..d9443ff 100644
--- a/include/linux/ion.h
+++ b/include/linux/ion.h
@@ -148,6 +148,7 @@
  * @base:	base address of heap in physical memory if applicable
  * @size:	size of the heap in bytes if applicable
  * @memory_type:Memory type used for the heap
+ * @has_outer_cache:    set to 1 if outer cache is used, 0 otherwise.
  * @extra_data:	Extra data specific to each heap type
  */
 struct ion_platform_heap {
@@ -157,6 +158,7 @@
 	ion_phys_addr_t base;
 	size_t size;
 	enum ion_memory_types memory_type;
+	unsigned int has_outer_cache;
 	void *extra_data;
 };
 
@@ -228,6 +230,7 @@
 
 /**
  * struct ion_platform_data - array of platform heaps passed from board file
+ * @has_outer_cache:    set to 1 if outer cache is used, 0 otherwise.
  * @nr:    number of structures in the array
  * @request_region: function to be called when the number of allocations goes
  *						from 0 -> 1
@@ -239,6 +242,7 @@
  * Provided by the board file in the form of platform data to a platform device.
  */
 struct ion_platform_data {
+	unsigned int has_outer_cache;
 	int nr;
 	int (*request_region)(void *);
 	int (*release_region)(void *);
diff --git a/include/linux/memblock.h b/include/linux/memblock.h
index 7525e38..b693b75 100644
--- a/include/linux/memblock.h
+++ b/include/linux/memblock.h
@@ -84,6 +84,7 @@
 extern void memblock_enforce_memory_limit(phys_addr_t memory_limit);
 extern int memblock_is_memory(phys_addr_t addr);
 extern int memblock_is_region_memory(phys_addr_t base, phys_addr_t size);
+extern int memblock_overlaps_memory(phys_addr_t base, phys_addr_t size);
 extern int memblock_is_reserved(phys_addr_t addr);
 extern int memblock_is_region_reserved(phys_addr_t base, phys_addr_t size);
 
diff --git a/include/linux/mfd/wcd9xxx/core.h b/include/linux/mfd/wcd9xxx/core.h
index fca9a94..7917d24 100644
--- a/include/linux/mfd/wcd9xxx/core.h
+++ b/include/linux/mfd/wcd9xxx/core.h
@@ -30,6 +30,13 @@
 	(((ver == TABLA_VERSION_1_0) || (ver == TABLA_VERSION_1_1)) ? 1 : 0)
 #define TABLA_IS_2_0(ver) ((ver == TABLA_VERSION_2_0) ? 1 : 0)
 
+#define SITAR_VERSION_1P0 0
+#define SITAR_VERSION_1P1 1
+#define SITAR_IS_1P0(ver) \
+	((ver == SITAR_VERSION_1P0) ? 1 : 0)
+#define SITAR_IS_1P1(ver) \
+	((ver == SITAR_VERSION_1P1) ? 1 : 0)
+
 enum {
 	TABLA_IRQ_SLIMBUS = 0,
 	TABLA_IRQ_MBHC_REMOVAL,
diff --git a/include/linux/mfd/wcd9xxx/wcd9304_registers.h b/include/linux/mfd/wcd9xxx/wcd9304_registers.h
index 70902bc..53ae67b 100644
--- a/include/linux/mfd/wcd9xxx/wcd9304_registers.h
+++ b/include/linux/mfd/wcd9xxx/wcd9304_registers.h
@@ -432,8 +432,14 @@
 
 #define SITAR_A_CDC_TX1_MUX_CTL			(0x223)
 #define SITAR_A_CDC_TX1_MUX_CTL__POR			(0x00000008)
-#define SITAR_A_CDC_TX1_CLK_FS_CTL			(0x224)
-#define SITAR_A_CDC_TX1_CLK_FS_CTL__POR			(0x00000003)
+#define SITAR_A_CDC_TX1_CLK_FS_CTL                      (0x00000224)
+#define SITAR_A_CDC_TX1_CLK_FS_CTL__POR                 (0x00000003)
+#define SITAR_A_CDC_TX2_CLK_FS_CTL                      (0x0000022C)
+#define SITAR_A_CDC_TX2_CLK_FS_CTL__POR                 (0x00000003)
+#define SITAR_A_CDC_TX3_CLK_FS_CTL                      (0x00000234)
+#define SITAR_A_CDC_TX3_CLK_FS_CTL__POR                 (0x00000003)
+#define SITAR_A_CDC_TX4_CLK_FS_CTL                      (0x0000023C)
+#define SITAR_A_CDC_TX4_CLK_FS_CTL__POR                 (0x00000003)
 #define SITAR_A_CDC_TX1_DMIC_CTL			(0x225)
 #define SITAR_A_CDC_TX1_DMIC_CTL__POR			(0x00000000)
 #define SITAR_A_CDC_TX2_MUX_CTL                 (0x22B)
@@ -479,18 +485,18 @@
 #define SITAR_A_CDC_RX3_B4_CTL__POR			 (0x00000000)
 
 #define SITAR_A_CDC_RX1_B5_CTL                  (0x000002B4)
-#define SITAR_A_CDC_RX1_B5_CTL__POR			 (0x00000060)
+#define SITAR_A_CDC_RX1_B5_CTL__POR			 (0x00000078)
 #define SITAR_A_CDC_RX2_B5_CTL                  (0x000002BC)
-#define SITAR_A_CDC_RX2_B5_CTL__POR			 (0x00000060)
+#define SITAR_A_CDC_RX2_B5_CTL__POR			 (0x00000078)
 #define SITAR_A_CDC_RX3_B5_CTL                  (0x000002C4)
-#define SITAR_A_CDC_RX3_B5_CTL__POR			 (0x00000060)
+#define SITAR_A_CDC_RX3_B5_CTL__POR			 (0x00000078)
 
 #define SITAR_A_CDC_RX1_B6_CTL                  (0x000002B5)
-#define SITAR_A_CDC_RX1_B6_CTL__POR			 (0x00000000)
+#define SITAR_A_CDC_RX1_B6_CTL__POR			 (0x00000080)
 #define SITAR_A_CDC_RX2_B6_CTL                  (0x000002BD)
-#define SITAR_A_CDC_RX2_B6_CTL__POR			 (0x00000000)
+#define SITAR_A_CDC_RX2_B6_CTL__POR			 (0x00000080)
 #define SITAR_A_CDC_RX3_B6_CTL                  (0x000002C5)
-#define SITAR_A_CDC_RX3_B6_CTL__POR			 (0x00000000)
+#define SITAR_A_CDC_RX3_B6_CTL__POR			 (0x00000080)
 
 
 #define SITAR_A_CDC_RX1_VOL_CTL_B1_CTL			(0x2B6)
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index aa808dc..beb5470 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -52,6 +52,9 @@
 	u8			part_config;
 	u8			cache_ctrl;
 	u8			rst_n_function;
+	u8			max_packed_writes;
+	u8			max_packed_reads;
+	u8			packed_event_en;
 	unsigned int		part_time;		/* Units: ms */
 	unsigned int		sa_timeout;		/* Units: 100ns */
 	unsigned int		generic_cmd6_time;	/* Units: 10ms */
@@ -72,6 +75,9 @@
 	bool			hpi_en;			/* HPI enablebit */
 	bool			hpi;			/* HPI support bit */
 	unsigned int		hpi_cmd;		/* cmd used as HPI */
+	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 */
@@ -85,6 +91,7 @@
 	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;
@@ -169,6 +176,25 @@
 
 #define SDIO_MAX_FUNCS		7
 
+enum mmc_packed_stop_reasons {
+	EXCEEDS_SEGMENTS = 0,
+	EXCEEDS_SECTORS,
+	WRONG_DATA_DIR,
+	FLUSH_OR_DISCARD,
+	EMPTY_QUEUE,
+	REL_WRITE,
+	THRESHOLD,
+	MAX_REASONS,
+};
+
+struct mmc_wr_pack_stats {
+	u32 *packing_events;
+	u32 pack_stop_reason[MAX_REASONS];
+	spinlock_t lock;
+	bool enabled;
+	bool print_in_read;
+};
+
 /*
  * MMC device
  */
@@ -191,6 +217,9 @@
 #define MMC_CARD_SDXC		(1<<6)		/* card is SDXC */
 #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_NEED_BKOPS	(1<<9)		/* card need to do BKOPS */
+#define MMC_STATE_DOING_BKOPS	(1<<10)		/* card is doing BKOPS */
+#define MMC_STATE_CHECK_BKOPS	(1<<11)		/* 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 */
@@ -236,6 +265,8 @@
 	unsigned int		sd_bus_speed;	/* Bus Speed Mode set for the card */
 
 	struct dentry		*debugfs_root;
+
+	struct mmc_wr_pack_stats wr_pack_stats; /* packed commands stats*/
 };
 
 /*
@@ -336,6 +367,9 @@
 #define mmc_sd_card_uhs(c) ((c)->state & MMC_STATE_ULTRAHIGHSPEED)
 #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_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)
@@ -346,6 +380,14 @@
 #define mmc_sd_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED)
 #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_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)
+
 
 /*
  * Quirk add/remove for MMC products.
@@ -427,4 +469,8 @@
 extern void mmc_fixup_device(struct mmc_card *card,
 			     const struct mmc_fixup *table);
 
+extern struct mmc_wr_pack_stats *mmc_blk_get_packed_statistics(
+			struct mmc_card *card);
+extern void mmc_blk_init_packed_statistics(struct mmc_card *card);
+
 #endif
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index 7f30e24..8b2ff74 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -18,6 +18,9 @@
 struct mmc_command {
 	u32			opcode;
 	u32			arg;
+#define MMC_CMD23_ARG_REL_WR	(1 << 31)
+#define MMC_CMD23_ARG_PACKED	((0 << 31) | (1 << 30))
+#define MMC_CMD23_ARG_TAG_REQ	(1 << 29)
 	u32			resp[4];
 	unsigned int		flags;		/* expected response type */
 #define MMC_RSP_PRESENT	(1 << 0)
@@ -134,6 +137,9 @@
 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 *);
@@ -143,6 +149,7 @@
 extern int mmc_wait_for_app_cmd(struct mmc_host *, struct mmc_card *,
 	struct mmc_command *, int);
 extern int mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int);
+extern int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd);
 
 #define MMC_ERASE_ARG		0x00000000
 #define MMC_SECURE_ERASE_ARG	0x80000000
@@ -163,6 +170,7 @@
 extern int mmc_can_secure_erase_trim(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 c9a17de..ae06ccf 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -245,11 +245,21 @@
 #define MMC_CAP2_CACHE_CTRL	(1 << 1)	/* Allow cache control */
 #define MMC_CAP2_POWEROFF_NOTIFY (1 << 2)	/* Notify poweroff supported */
 #define MMC_CAP2_NO_MULTI_READ	(1 << 3)	/* Multiblock reads don't work */
+#define MMC_CAP2_SANITIZE	(1<<4)		/* Support Sanitize */
 #define MMC_CAP2_HS200_1_8V_SDR	(1 << 5)        /* can support */
 #define MMC_CAP2_HS200_1_2V_SDR	(1 << 6)        /* can support */
 #define MMC_CAP2_HS200		(MMC_CAP2_HS200_1_8V_SDR | \
 				 MMC_CAP2_HS200_1_2V_SDR)
-#define MMC_CAP2_DETECT_ON_ERR	(1 << 8)	/* On I/O err check card removal */
+#define MMC_CAP2_DETECT_ON_ERR	(1 << 7)	/* On I/O err check card removal */
+#define MMC_CAP2_PACKED_RD	(1 << 10)	/* Allow packed read */
+#define MMC_CAP2_PACKED_WR	(1 << 11)	/* Allow packed write */
+#define MMC_CAP2_PACKED_CMD	(MMC_CAP2_PACKED_RD | \
+				 MMC_CAP2_PACKED_WR) /* Allow packed commands */
+#define MMC_CAP2_PACKED_WR_CONTROL (1 << 12) /* Allow write packing control */
+
+#define MMC_CAP2_BKOPS		    (1 << 14)	/* BKOPS supported */
+#define MMC_CAP2_INIT_BKOPS	    (1 << 15)	/* Need to set BKOPS_EN */
+
 	mmc_pm_flag_t		pm_caps;	/* supported pm features */
 	unsigned int        power_notify_type;
 #define MMC_HOST_PW_NOTIFY_NONE		0
@@ -344,12 +354,8 @@
 #ifdef CONFIG_MMC_PERF_PROFILING
 	struct {
 
-		unsigned long rbytes_mmcq; /* Rd bytes MMC queue */
-		unsigned long wbytes_mmcq; /* Wr bytes MMC queue */
 		unsigned long rbytes_drv;  /* Rd bytes MMC Host  */
 		unsigned long wbytes_drv;  /* Wr bytes MMC Host  */
-		ktime_t rtime_mmcq;	   /* Rd time  MMC queue */
-		ktime_t wtime_mmcq;	   /* Wr time  MMC queue */
 		ktime_t rtime_drv;	   /* Rd time  MMC Host  */
 		ktime_t wtime_drv;	   /* Wr time  MMC Host  */
 		ktime_t start;
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index e124fbe..37b5344 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -139,7 +139,9 @@
 #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 */
 
 #define R1_STATE_IDLE	0
 #define R1_STATE_READY	1
@@ -275,10 +277,16 @@
 #define EXT_CSD_FLUSH_CACHE		32      /* W */
 #define EXT_CSD_CACHE_CTRL		33      /* R/W */
 #define EXT_CSD_POWER_OFF_NOTIFICATION	34	/* R/W */
+#define EXT_CSD_PACKED_FAILURE_INDEX	35	/* RO */
+#define EXT_CSD_PACKED_CMD_STATUS	36	/* RO */
+#define EXT_CSD_EXP_EVENTS_STATUS	54	/* RO, 2 bytes */
+#define EXT_CSD_EXP_EVENTS_CTRL	56	/* R/W, 2 bytes */
 #define EXT_CSD_PARTITION_ATTRIBUTE	156	/* R/W */
 #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_ERASE_GROUP_DEF		175	/* R/W */
@@ -311,9 +319,13 @@
 #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 */
+#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 */
 
 /*
@@ -426,6 +438,14 @@
 #define EXT_CSD_PWR_CL_4BIT_MASK	0x0F	/* 8 bit PWR CLS */
 #define EXT_CSD_PWR_CL_8BIT_SHIFT	4
 #define EXT_CSD_PWR_CL_4BIT_SHIFT	0
+
+#define EXT_CSD_PACKED_EVENT_EN	(1 << 3)
+
+#define EXT_CSD_PACKED_FAILURE	(1 << 3)
+
+#define EXT_CSD_PACKED_GENERIC_ERROR	(1 << 0)
+#define EXT_CSD_PACKED_INDEXED_ERROR	(1 << 1)
+
 /*
  * MMC_SWITCH access modes
  */
@@ -435,5 +455,16 @@
 #define MMC_SWITCH_MODE_CLEAR_BITS	0x02	/* Clear bits which are 1 in value */
 #define MMC_SWITCH_MODE_WRITE_BYTE	0x03	/* Set target to value */
 
+/*
+ * 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  /* MMC_MMC_PROTOCOL_H */
 
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index cb394e8..b4e14d2 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -292,7 +292,7 @@
 #define INPUT_DEVICE_ID_LED_MAX		0x0f
 #define INPUT_DEVICE_ID_SND_MAX		0x07
 #define INPUT_DEVICE_ID_FF_MAX		0x7f
-#define INPUT_DEVICE_ID_SW_MAX		0x0f
+#define INPUT_DEVICE_ID_SW_MAX		0x10
 
 #define INPUT_DEVICE_ID_MATCH_BUS	1
 #define INPUT_DEVICE_ID_MATCH_VENDOR	2
diff --git a/include/linux/msm_charm.h b/include/linux/msm_charm.h
index 779fd38..c31e493 100644
--- a/include/linux/msm_charm.h
+++ b/include/linux/msm_charm.h
@@ -10,6 +10,7 @@
 #define NORMAL_BOOT_DONE	_IOW(CHARM_CODE, 5, int)
 #define RAM_DUMP_DONE		_IOW(CHARM_CODE, 6, int)
 #define WAIT_FOR_RESTART	_IOR(CHARM_CODE, 7, int)
+#define GET_DLOAD_STATUS	_IOR(CHARM_CODE, 8, int)
 
 enum charm_boot_type {
 	CHARM_NORMAL_BOOT = 0,
diff --git a/include/linux/regulator/pm8xxx-regulator.h b/include/linux/regulator/pm8xxx-regulator.h
index ddf1901..6b42263 100644
--- a/include/linux/regulator/pm8xxx-regulator.h
+++ b/include/linux/regulator/pm8xxx-regulator.h
@@ -66,6 +66,9 @@
  * @enable_time:	time in us taken to enable a regulator to the maximum
  *			allowed voltage for the system.  This is dependent upon
  *			the load and capacitance for a regulator on the board.
+ * @slew_rate:		worst case rate of change of regulator output voltage
+ *			in units of uV/us (V/s).  This is dependent upon the
+ *			load and capacitance for a regulator on the board.
  * @ocp_enable:		enable over current protection logic (available for
  *			LVS and MVS type switches)
  * @ocp_enable_time:	time in us to delay between enabling the switch and then
@@ -80,6 +83,7 @@
 	enum pm8xxx_vreg_pin_function	pin_fn;
 	int				system_uA;
 	int				enable_time;
+	int				slew_rate;
 	unsigned			ocp_enable;
 	int				ocp_enable_time;
 };
diff --git a/include/linux/smux.h b/include/linux/smux.h
new file mode 100644
index 0000000..308f969
--- /dev/null
+++ b/include/linux/smux.h
@@ -0,0 +1,297 @@
+/* include/linux/smux.h
+ *
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef SMUX_H
+#define SMUX_H
+
+/**
+ * Logical Channel IDs
+ *
+ * This must be identical between local and remote clients.
+ */
+enum {
+	/* Data Ports */
+	SMUX_DATA_0,
+	SMUX_DATA_1,
+	SMUX_DATA_2,
+	SMUX_DATA_3,
+	SMUX_DATA_4,
+	SMUX_DATA_5,
+	SMUX_DATA_6,
+	SMUX_DATA_7,
+	SMUX_DATA_8,
+	SMUX_DATA_9,
+	SMUX_USB_RMNET_DATA_0,
+	SMUX_USB_DUN_0,
+	SMUX_USB_DIAG_0,
+	SMUX_SYS_MONITOR_0,
+	SMUX_CSVT_0,
+	/* add new data ports here */
+
+	/* Control Ports */
+	SMUX_DATA_CTL_0 = 32,
+	SMUX_DATA_CTL_1,
+	SMUX_DATA_CTL_2,
+	SMUX_DATA_CTL_3,
+	SMUX_DATA_CTL_4,
+	SMUX_DATA_CTL_5,
+	SMUX_DATA_CTL_6,
+	SMUX_DATA_CTL_7,
+	SMUX_DATA_CTL_8,
+	SMUX_DATA_CTL_9,
+	SMUX_USB_RMNET_CTL_0,
+	SMUX_USB_DUN_CTL_0_UNUSED,
+	SMUX_USB_DIAG_CTL_0,
+	SMUX_SYS_MONITOR_CTL_0,
+	SMUX_CSVT_CTL_0,
+	/* add new control ports here */
+
+	SMUX_TEST_LCID,
+	SMUX_NUM_LOGICAL_CHANNELS,
+};
+
+/**
+ * Notification events that are passed to the notify() function.
+ *
+ * If the @metadata argument in the notifier is non-null, then it will
+ * point to the associated struct smux_meta_* structure.
+ */
+enum {
+	SMUX_CONNECTED,       /* @metadata is null */
+	SMUX_DISCONNECTED,
+	SMUX_READ_DONE,
+	SMUX_READ_FAIL,
+	SMUX_WRITE_DONE,
+	SMUX_WRITE_FAIL,
+	SMUX_TIOCM_UPDATE,
+	SMUX_LOW_WM_HIT,      /* @metadata is NULL */
+	SMUX_HIGH_WM_HIT,     /* @metadata is NULL */
+};
+
+/**
+ * Channel options used to modify channel behavior.
+ */
+enum {
+	SMUX_CH_OPTION_LOCAL_LOOPBACK = 1 << 0,
+	SMUX_CH_OPTION_REMOTE_LOOPBACK = 1 << 1,
+	SMUX_CH_OPTION_REMOTE_TX_STOP = 1 << 2,
+};
+
+/**
+ * Metadata for SMUX_DISCONNECTED notification
+ *
+ * @is_ssr:  Disconnect caused by subsystem restart
+ */
+struct smux_meta_disconnected {
+	int is_ssr;
+};
+
+/**
+ * Metadata for SMUX_READ_DONE/SMUX_READ_FAIL notification
+ *
+ * @pkt_priv: Packet-specific private data
+ * @buffer:   Buffer pointer passed into msm_smux_write
+ * @len:      Buffer length passed into  msm_smux_write
+ */
+struct smux_meta_read {
+	void *pkt_priv;
+	void *buffer;
+	int len;
+};
+
+/**
+ * Metadata for SMUX_WRITE_DONE/SMUX_WRITE_FAIL notification
+ *
+ * @pkt_priv: Packet-specific private data
+ * @buffer:  Buffer pointer returned by get_rx_buffer()
+ * @len:     Buffer length returned by get_rx_buffer()
+ */
+struct smux_meta_write {
+	void *pkt_priv;
+	void *buffer;
+	int len;
+};
+
+/**
+ * Metadata for SMUX_TIOCM_UPDATE notification
+ *
+ * @tiocm_old:  Previous TIOCM state
+ * @tiocm_new:   Current TIOCM state
+ */
+struct smux_meta_tiocm {
+	uint32_t tiocm_old;
+	uint32_t tiocm_new;
+};
+
+
+#ifdef CONFIG_N_SMUX
+/**
+ * Starts the opening sequence for a logical channel.
+ *
+ * @lcid          Logical channel ID
+ * @priv          Free for client usage
+ * @notify        Event notification function
+ * @get_rx_buffer Function used to provide a receive buffer to SMUX
+ *
+ * @returns 0 for success, <0 otherwise
+ *
+ * A channel must be fully closed (either not previously opened or
+ * msm_smux_close() has been called and the SMUX_DISCONNECTED has been
+ * recevied.
+ *
+ * One the remote side is opened, the client will receive a SMUX_CONNECTED
+ * event.
+ */
+int msm_smux_open(uint8_t lcid, void *priv,
+	void (*notify)(void *priv, int event_type, const void *metadata),
+	int (*get_rx_buffer)(void *priv, void **pkt_priv,
+					void **buffer, int size));
+
+/**
+ * Starts the closing sequence for a logical channel.
+ *
+ * @lcid    Logical channel ID
+ * @returns 0 for success, <0 otherwise
+ *
+ * Once the close event has been acknowledge by the remote side, the client
+ * will receive a SMUX_DISCONNECTED notification.
+ */
+int msm_smux_close(uint8_t lcid);
+
+/**
+ * Write data to a logical channel.
+ *
+ * @lcid      Logical channel ID
+ * @pkt_priv  Client data that will be returned with the SMUX_WRITE_DONE or
+ *            SMUX_WRITE_FAIL notification.
+ * @data      Data to write
+ * @len       Length of @data
+ *
+ * @returns   0 for success, <0 otherwise
+ *
+ * Data may be written immediately after msm_smux_open() is called, but
+ * the data will wait in the transmit queue until the channel has been
+ * fully opened.
+ *
+ * Once the data has been written, the client will receive either a completion
+ * (SMUX_WRITE_DONE) or a failure notice (SMUX_WRITE_FAIL).
+ */
+int msm_smux_write(uint8_t lcid, void *pkt_priv, const void *data, int len);
+
+/**
+ * Returns true if the TX queue is currently full (high water mark).
+ *
+ * @lcid      Logical channel ID
+ *
+ * @returns   0 if channel is not full; 1 if it is full; < 0 for error
+ */
+int msm_smux_is_ch_full(uint8_t lcid);
+
+/**
+ * Returns true if the TX queue has space for more packets it is at or
+ * below the low water mark).
+ *
+ * @lcid      Logical channel ID
+ *
+ * @returns   0 if channel is above low watermark
+ *            1 if it's at or below the low watermark
+ *            < 0 for error
+ */
+int msm_smux_is_ch_low(uint8_t lcid);
+
+/**
+ * Get the TIOCM status bits.
+ *
+ * @lcid      Logical channel ID
+ *
+ * @returns   >= 0 TIOCM status bits
+ *            < 0  Error condition
+ */
+long msm_smux_tiocm_get(uint8_t lcid);
+
+/**
+ * Set/clear the TIOCM status bits.
+ *
+ * @lcid      Logical channel ID
+ * @set       Bits to set
+ * @clear     Bits to clear
+ *
+ * @returns   0 for success; < 0 for failure
+ *
+ * If a bit is specified in both the @set and @clear masks, then the clear bit
+ * definition will dominate and the bit will be cleared.
+ */
+int msm_smux_tiocm_set(uint8_t lcid, uint32_t set, uint32_t clear);
+
+/**
+ * Set or clear channel option using the SMUX_CH_OPTION_* channel
+ * flags.
+ *
+ * @lcid   Logical channel ID
+ * @set    Options to set
+ * @clear  Options to clear
+ *
+ * @returns 0 for success, < 0 for failure
+ */
+int msm_smux_set_ch_option(uint8_t lcid, uint32_t set, uint32_t clear);
+
+#else
+static inline int msm_smux_open(uint8_t lcid, void *priv,
+	void (*notify)(void *priv, int event_type, const void *metadata),
+	int (*get_rx_buffer)(void *priv, void **pkt_priv,
+					void **buffer, int size))
+{
+	return -ENODEV;
+}
+
+static inline int msm_smux_close(uint8_t lcid)
+{
+	return -ENODEV;
+}
+
+static inline int msm_smux_write(uint8_t lcid, void *pkt_priv,
+				const void *data, int len)
+{
+	return -ENODEV;
+}
+
+static inline int msm_smux_is_ch_full(uint8_t lcid)
+{
+	return -ENODEV;
+}
+
+static inline int msm_smux_is_ch_low(uint8_t lcid)
+{
+	return -ENODEV;
+}
+
+static inline long msm_smux_tiocm_get(uint8_t lcid)
+{
+	return 0;
+}
+
+static inline int msm_smux_tiocm_set(uint8_t lcid, uint32_t set, uint32_t clear)
+{
+	return -ENODEV;
+}
+
+static inline int msm_smux_set_ch_option(uint8_t lcid, uint32_t set,
+					uint32_t clear)
+{
+	return -ENODEV;
+}
+
+#endif /* CONFIG_N_SMUX */
+
+#endif /* SMUX_H */
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 1ff6b62..818d189 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -52,6 +52,7 @@
 #define N_TI_WL		22	/* for TI's WL BT, FM, GPS combo chips */
 #define N_TRACESINK	23	/* Trace data routing for MIPI P1149.7 */
 #define N_TRACEROUTER	24	/* Trace data routing for MIPI P1149.7 */
+#define N_SMUX		25	/* Serial MUX */
 
 /*
  * This character is the same as _POSIX_VDISABLE: it cannot be used as
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index 5762463..a255388 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -343,6 +343,10 @@
 		 * address is set
 		 */
 	int	(*update_device)(struct usb_hcd *, struct usb_device *);
+
+	/* to log completion events*/
+	void	(*log_urb_complete)(struct urb *urb, char * event,
+			unsigned extra);
 };
 
 extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 6e96f85..d36e45f 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -177,6 +177,9 @@
  * @enable_dcd: Enable Data Contact Detection circuit. if not set
  *              wait for 600msec before proceeding to primary
  *              detection.
+ * @enable_lpm_on_suspend: Enable the USB core to go into Low
+ *              Power Mode, when USB bus is suspended but cable
+ *              is connected.
  * @bus_scale_table: parameters for bus bandwidth requirements
  */
 struct msm_otg_platform_data {
@@ -192,6 +195,7 @@
 	bool mhl_enable;
 	bool disable_reset_on_disconnect;
 	bool enable_dcd;
+	bool enable_lpm_on_dev_suspend;
 	struct msm_bus_scale_pdata *bus_scale_table;
 };
 
@@ -322,9 +326,15 @@
 	 * voltage regulator(VDDCX).
 	 */
 #define ALLOW_PHY_RETENTION		BIT(1)
+	  /*
+	   * 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)
 	unsigned long lpm_flags;
 #define PHY_PWR_COLLAPSED		BIT(0)
 #define PHY_RETENTIONED			BIT(1)
+#define XO_SHUTDOWN			BIT(2)
 	int reset_counter;
 	unsigned long b_last_se0_sess;
 	unsigned long tmouts;
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 131c856..45855b1 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -386,6 +386,9 @@
 #define V4L2_PIX_FMT_XVID     v4l2_fourcc('X', 'V', 'I', 'D') /* Xvid           */
 #define V4L2_PIX_FMT_VC1_ANNEX_G v4l2_fourcc('V', 'C', '1', 'G') /* SMPTE 421M Annex G compliant stream */
 #define V4L2_PIX_FMT_VC1_ANNEX_L v4l2_fourcc('V', 'C', '1', 'L') /* SMPTE 421M Annex L compliant stream */
+#define V4L2_PIX_FMT_DIVX_311  v4l2_fourcc('D', 'I', 'V', '3') /* DIVX311     */
+#define V4L2_PIX_FMT_DIVX      v4l2_fourcc('D', 'I', 'V', 'X') /* DIVX        */
+#define V4L2_PIX_FMT_VP8 v4l2_fourcc('V', 'P', '8', '0') /* ON2 VP8 stream */
 
 /*  Vendor-specific formats   */
 #define V4L2_PIX_FMT_CPIA1    v4l2_fourcc('C', 'P', 'I', 'A') /* cpia1 YUV */
@@ -1860,6 +1863,54 @@
 	};
 };
 
+/* Decoder commands */
+#define V4L2_DEC_CMD_START       (0)
+#define V4L2_DEC_CMD_STOP        (1)
+#define V4L2_DEC_CMD_PAUSE       (2)
+#define V4L2_DEC_CMD_RESUME      (3)
+
+/* Flags for V4L2_DEC_CMD_START */
+#define V4L2_DEC_CMD_START_MUTE_AUDIO	(1 << 0)
+
+/* Flags for V4L2_DEC_CMD_PAUSE */
+#define V4L2_DEC_CMD_PAUSE_TO_BLACK	(1 << 0)
+
+/* Flags for V4L2_DEC_CMD_STOP */
+#define V4L2_DEC_CMD_STOP_TO_BLACK	(1 << 0)
+#define V4L2_DEC_CMD_STOP_IMMEDIATELY	(1 << 1)
+
+/* Play format requirements (returned by the driver): */
+
+/* The decoder has no special format requirements */
+#define V4L2_DEC_START_FMT_NONE		(0)
+/* The decoder requires full GOPs */
+#define V4L2_DEC_START_FMT_GOP		(1)
+
+/* The structure must be zeroed before use by the application
+   This ensures it can be extended safely in the future. */
+struct v4l2_decoder_cmd {
+	__u32 cmd;
+	__u32 flags;
+	union {
+		struct {
+			__u64 pts;
+		} stop;
+
+		struct {
+			/* 0 or 1000 specifies normal speed,
+			   1 specifies forward single stepping,
+			   -1 specifies backward single stepping,
+			   >1: playback at speed/1000 of the normal speed,
+			   <-1: reverse playback at (-speed/1000) of the normal speed. */
+			__s32 speed;
+			__u32 format;
+		} start;
+
+		struct {
+			__u32 data[16];
+		} raw;
+	};
+};
 #endif
 
 
@@ -2226,6 +2277,15 @@
 #define VIDIOC_CREATE_BUFS	_IOWR('V', 92, struct v4l2_create_buffers)
 #define VIDIOC_PREPARE_BUF	_IOWR('V', 93, struct v4l2_buffer)
 
+/* Experimental selection API */
+#define VIDIOC_G_SELECTION	_IOWR('V', 94, struct v4l2_selection)
+#define VIDIOC_S_SELECTION	_IOWR('V', 95, struct v4l2_selection)
+
+/* Experimental, these two ioctls may change over the next couple of kernel
+   versions. */
+#define VIDIOC_DECODER_CMD	_IOWR('V', 96, struct v4l2_decoder_cmd)
+#define VIDIOC_TRY_DECODER_CMD	_IOWR('V', 97, struct v4l2_decoder_cmd)
+
 /* Reminder: when adding new ioctls please add support for them to
    drivers/media/video/v4l2-compat-ioctl32.c as well! */
 
diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h
index 1c492f9..d7e65b0 100644
--- a/include/linux/wcnss_wlan.h
+++ b/include/linux/wcnss_wlan.h
@@ -35,8 +35,10 @@
 				const struct dev_pm_ops *pm_ops);
 void wcnss_wlan_unregister_pm_ops(struct device *dev,
 				const struct dev_pm_ops *pm_ops);
-void wcnss_register_thermal_mitigation(void (*tm_notify)(int));
-void wcnss_unregister_thermal_mitigation(void (*tm_notify)(int));
+void wcnss_register_thermal_mitigation(struct device *dev,
+				void (*tm_notify)(struct device *dev, int));
+void wcnss_unregister_thermal_mitigation(
+				void (*tm_notify)(struct device *dev, int));
 struct platform_device *wcnss_get_platform_device(void);
 struct wcnss_wlan_config *wcnss_get_wlan_config(void);
 int wcnss_wlan_power(struct device *dev,
diff --git a/include/media/Kbuild b/include/media/Kbuild
index 8dfb0fc..03951ce 100644
--- a/include/media/Kbuild
+++ b/include/media/Kbuild
@@ -4,4 +4,4 @@
 header-y += vcap_fmt.h
 header-y += msm_isp.h
 header-y += msm_gemini.h
-header-y += msm_v4l2_overlay.h
+header-y += msm_gestures.h
diff --git a/include/media/msm/vcd_api.h b/include/media/msm/vcd_api.h
index 32a1759..c93b696 100644
--- a/include/media/msm/vcd_api.h
+++ b/include/media/msm/vcd_api.h
@@ -66,7 +66,7 @@
 	u32 alloc_len;
 	u32 data_len;
 	u32 offset;
-	s64 time_stamp;
+	s64 time_stamp; /* in usecs*/
 	u32 flags;
 	u32 frm_clnt_data;
 	struct vcd_property_dec_output_buffer dec_op_prop;
diff --git a/include/media/msm/vcd_property.h b/include/media/msm/vcd_property.h
index e776d41..cd00800 100644
--- a/include/media/msm/vcd_property.h
+++ b/include/media/msm/vcd_property.h
@@ -53,6 +53,7 @@
 #define VCD_I_ENABLE_SPS_PPS_FOR_IDR (VCD_START_BASE + 0x25)
 #define VCD_REQ_PERF_LEVEL (VCD_START_BASE + 0x26)
 #define VCD_I_SLICE_DELIVERY_MODE (VCD_START_BASE + 0x27)
+#define VCD_I_VOP_TIMING_CONSTANT_DELTA (VCD_START_BASE + 0x28)
 
 #define VCD_START_REQ      (VCD_START_BASE + 0x1000)
 #define VCD_I_REQ_IFRAME   (VCD_START_REQ + 0x1)
@@ -300,6 +301,10 @@
 	u32   vop_time_resolution;
 };
 
+struct vcd_property_vop_timing_constant_delta {
+	u32 constant_delta; /*In usecs */
+};
+
 struct vcd_property_short_header {
 	u32             short_header;
 };
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index 3f647dc..8222b67 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -448,6 +448,9 @@
 #define CMD_AXI_CFG_SEC			0xF4
 #define CMD_AXI_CFG_SEC_ALL_CHNLS	0xF8
 
+#define CMD_AXI_START  0xE1
+#define CMD_AXI_STOP   0xE2
+
 /* vfe config command: config command(from config thread)*/
 struct msm_vfe_cfg_cmd {
 	int cmd_type;
@@ -1433,6 +1436,9 @@
 #define MSM_CAM_V4L2_IOCTL_GET_EVENT_PAYLOAD \
 	_IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct msm_camera_v4l2_ioctl_t *)
 
+#define MSM_CAM_IOCTL_SEND_EVENT \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 6, struct v4l2_event)
+
 struct msm_camera_v4l2_ioctl_t {
 	void __user *ioctl_ptr;
 };
diff --git a/include/media/msm_gestures.h b/include/media/msm_gestures.h
new file mode 100644
index 0000000..c9af034
--- /dev/null
+++ b/include/media/msm_gestures.h
@@ -0,0 +1,66 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __LINUX_MSM_GESTURES_H
+#define __LINUX_MSM_GESTURES_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <media/msm_camera.h>
+
+#define MSM_GES_IOCTL_CTRL_COMMAND \
+	_IOW('V', BASE_VIDIOC_PRIVATE + 20, struct v4l2_control)
+
+#define VIDIOC_MSM_GESTURE_EVT \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 21, struct v4l2_event)
+
+#define MSM_GES_GET_EVT_PAYLOAD \
+	_IOW('V', BASE_VIDIOC_PRIVATE + 22, struct msm_ges_evt)
+
+#define VIDIOC_MSM_GESTURE_CAM_EVT \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 23, int)
+
+#define MSM_GES_RESP_V4L2  MSM_CAM_RESP_MAX
+#define MSM_GES_RESP_MAX  (MSM_GES_RESP_V4L2 + 1)
+
+#define MSM_SVR_RESP_MAX  MSM_GES_RESP_MAX
+
+
+#define MSM_V4L2_GES_BASE                             100
+#define MSM_V4L2_GES_OPEN         (MSM_V4L2_GES_BASE + 0)
+#define MSM_V4L2_GES_CLOSE        (MSM_V4L2_GES_BASE + 1)
+#define MSM_V4L2_GES_CAM_OPEN     (MSM_V4L2_GES_BASE + 2)
+#define MSM_V4L2_GES_CAM_CLOSE    (MSM_V4L2_GES_BASE + 3)
+
+#define MSM_GES_APP_EVT_MIN     (V4L2_EVENT_PRIVATE_START + 0x14)
+#define MSM_GES_APP_NOTIFY_EVENT        (MSM_GES_APP_EVT_MIN + 0)
+#define MSM_GES_APP_NOTIFY_ERROR_EVENT  (MSM_GES_APP_EVT_MIN + 1)
+#define MSM_GES_APP_EVT_MAX             (MSM_GES_APP_EVT_MIN + 2)
+
+#define MSM_GESTURE_CID_CTRL_CMD V4L2_CID_BRIGHTNESS
+
+#define MAX_GES_EVENTS 25
+
+struct msm_ges_ctrl_cmd {
+	int type;
+	void *value;
+	int len;
+	int fd;
+	uint32_t cookie;
+};
+
+struct msm_ges_evt {
+	void *evt_data;
+	int evt_len;
+};
+
+#endif /*__LINUX_MSM_GESTURES_H*/
diff --git a/include/media/msm_vidc.h b/include/media/msm_vidc.h
index b883ffa..baa6a28 100644
--- a/include/media/msm_vidc.h
+++ b/include/media/msm_vidc.h
@@ -28,7 +28,7 @@
 	MSM_VIDC_MAX_DEVICES,
 };
 
-void *msm_vidc_open(int core_id, int session_type);
+int msm_vidc_open(void *vidc_inst, 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);
@@ -38,10 +38,12 @@
 int msm_vidc_g_ctrl(void *instance, struct v4l2_control *a);
 int msm_vidc_reqbufs(void *instance, struct v4l2_requestbuffers *b);
 int msm_vidc_prepare_buf(void *instance, struct v4l2_buffer *b);
+int msm_vidc_release_buf(void *instance, struct v4l2_buffer *b);
 int msm_vidc_qbuf(void *instance, struct v4l2_buffer *b);
 int msm_vidc_dqbuf(void *instance, struct v4l2_buffer *b);
 int msm_vidc_streamon(void *instance, enum v4l2_buf_type i);
 int msm_vidc_streamoff(void *instance, enum v4l2_buf_type i);
+int msm_vidc_decoder_cmd(void *instance, struct v4l2_decoder_cmd *dec);
 int msm_vidc_poll(void *instance, struct file *filp,
 		struct poll_table_struct *pt);
 #endif
diff --git a/include/media/radio-iris.h b/include/media/radio-iris.h
index dfad18d..b5e8f2e 100644
--- a/include/media/radio-iris.h
+++ b/include/media/radio-iris.h
@@ -516,6 +516,7 @@
 	FM_RECV,
 	FM_TRANS,
 	FM_RESET,
+	FM_CALIB
 };
 
 enum v4l2_cid_private_iris_t {
diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h
index 4d1c74a..46c13ba 100644
--- a/include/media/v4l2-ioctl.h
+++ b/include/media/v4l2-ioctl.h
@@ -207,6 +207,10 @@
 					struct v4l2_encoder_cmd *a);
 	int (*vidioc_try_encoder_cmd)  (struct file *file, void *fh,
 					struct v4l2_encoder_cmd *a);
+	int (*vidioc_decoder_cmd)      (struct file *file, void *fh,
+					struct v4l2_decoder_cmd *a);
+	int (*vidioc_try_decoder_cmd)  (struct file *file, void *fh,
+					struct v4l2_decoder_cmd *a);
 
 	/* Stream type-dependent parameter ioctls */
 	int (*vidioc_g_parm)           (struct file *file, void *fh,
diff --git a/include/media/vcap_fmt.h b/include/media/vcap_fmt.h
index 4a62bc3..51b45ac 100644
--- a/include/media/vcap_fmt.h
+++ b/include/media/vcap_fmt.h
@@ -14,8 +14,8 @@
 #ifndef VCAP_FMT_H
 #define VCAP_FMT_H
 
-#define V4L2_BUF_TYPE_INTERLACED_IN_AFE (V4L2_BUF_TYPE_PRIVATE)
-#define V4L2_BUF_TYPE_INTERLACED_IN_DECODER (V4L2_BUF_TYPE_PRIVATE + 1)
+#define V4L2_BUF_TYPE_INTERLACED_IN_DECODER (V4L2_BUF_TYPE_PRIVATE)
+#define V4L2_BUF_TYPE_VP_OUT (V4L2_BUF_TYPE_PRIVATE + 1)
 
 enum hal_vcap_mode {
 	HAL_VCAP_MODE_PRO = 0,
@@ -32,87 +32,7 @@
 	HAL_VCAP_RGB,
 };
 
-enum hal_vcap_vc_fmt {
-	/* 1080p */
-	HAL_VCAP_YUV_1080p_60_RH = 0,
-	HAL_VCAP_YUV_1080p_60_FL,
-	HAL_VCAP_RGB_1080p_60_FL,
-	HAL_VCAP_YUV_1080p_24_FL,
-	HAL_VCAP_YUV_1080p_24_RH,
-	HAL_VCAP_YUV_1080p_24_RW,
-	HAL_VCAP_YUV_1080p_60_RW,
-	HAL_VCAP_YUV_1080p_50_FL,
-	HAL_VCAP_YUV_1080p_50_RH,
-	HAL_VCAP_YUV_1080p_25_FL,
-	HAL_VCAP_YUV_1080p_25_RH,
-	HAL_VCAP_YUV_1080p_30_RH,
-	HAL_VCAP_RGB_1080p_25_FL,
-	HAL_VCAP_RGB_1080p_25_RH,
-	/* 1080i */
-	HAL_VCAP_YUV_1080i_60_FL,
-	HAL_VCAP_YUV_1080i_60_RH,
-	HAL_VCAP_YUV_1080i_60_RW,
-	HAL_VCAP_YUV_1080i_50_FL,
-	HAL_VCAP_YUV_1080i_50_RH,
-	HAL_VCAP_YUV_1080i_50_RW,
-	HAL_VCAP_RGB_1080i_50_FL,
-	HAL_VCAP_RGB_1080i_50_RH,
-	/* 480i */
-	HAL_VCAP_YUV_480i_60_RH,
-	HAL_VCAP_YUV_480i_60_FL,
-	HAL_VCAP_YUV_480i_60_RW,
-	HAL_VCAP_YUV_2880_480i_60_FL,
-	HAL_VCAP_YUV_2880_480i_60_RH,
-	/* 480p */
-	HAL_VCAP_YUV_480p_60_RH,
-	HAL_VCAP_RGB_480p_60_RH,
-	HAL_VCAP_RGB_480p_60_FL,
-	HAL_VCAP_YUV_480p_60_FL,
-	HAL_VCAP_YUV_480p_60_RW,
-	HAL_VCAP_YUV_2880_480p_60_FL,
-	HAL_VCAP_YUV_2880_480p_60_RH,
-	/* 720p */
-	HAL_VCAP_YUV_720p_60_FL,
-	HAL_VCAP_RGB_720p_60_FL,
-	HAL_VCAP_YUV_720p_60_RW,
-	HAL_VCAP_YUV_720p_60_RH,
-	HAL_VCAP_YUV_720p_50_FL,
-	HAL_VCAP_YUV_720p_50_RW,
-	HAL_VCAP_YUV_720p_50_RH,
-	/* 576p */
-	HAL_VCAP_YUV_576p_50_FL,
-	HAL_VCAP_RGB_576p_50_FL,
-	HAL_VCAP_YUV_576p_50_RW,
-	HAL_VCAP_YUV_576p_50_RH,
-	HAL_VCAP_YUV_1440_576p_50_RH,
-	HAL_VCAP_YUV_2880_576p_50_FL,
-	HAL_VCAP_YUV_2880_576p_50_RH,
-	/* 576i */
-	HAL_VCAP_YUV_576i_50_FL,
-	HAL_VCAP_YUV_576i_50_RW,
-	HAL_VCAP_YUV_576i_50_RH,
-	/* XGA 1024x768 */
-	HAL_VCAP_YUV_XGA_FL,
-	HAL_VCAP_YUV_XGA_RH,
-	HAL_VCAP_YUV_XGA_RB,
-	/* SXGA 1280x1024 */
-	HAL_VCAP_YUV_SXGA_FL,
-	HAL_VCAP_RGB_SXGA_FL,
-	HAL_VCAP_YUV_SXGA_RH,
-	HAL_VCAP_YUV_SXGA_RB,
-	/* UXGA 1600x1200 */
-	HAL_VCAP_YUV_UXGA_FL,
-	HAL_VCAP_RGB_UXGA_FL,
-	HAL_VCAP_YUV_UXGA_RH,
-	HAL_VCAP_YUV_UXGA_RB,
-	/* test odd height */
-	HAL_VCAP_ODD_HEIGHT,
-	/* test odd width RGB only */
-	HAL_VCAP_ODD_WIDTH,
-};
-
 struct v4l2_format_vc_ext {
-	enum hal_vcap_vc_fmt   format;
 	enum hal_vcap_mode     mode;
 	enum hal_vcap_polar    h_polar;
 	enum hal_vcap_polar    v_polar;
@@ -136,5 +56,22 @@
 	uint32_t f2_vsync_h_end;
 	uint32_t f2_vsync_v_start;
 	uint32_t f2_vsync_v_end;
+	uint32_t sizeimage;
+	uint32_t bytesperline;
+};
+
+enum vcap_type {
+	VC_TYPE,
+	VP_IN_TYPE,
+	VP_OUT_TYPE,
+};
+
+struct vcap_priv_fmt {
+	enum vcap_type type;
+	union {
+		struct v4l2_format_vc_ext timing;
+		struct v4l2_pix_format pix;
+		/* Once VP is created there will be another type in here */
+	} u;
 };
 #endif
diff --git a/include/media/vcap_v4l2.h b/include/media/vcap_v4l2.h
index 57f9703..374e681 100644
--- a/include/media/vcap_v4l2.h
+++ b/include/media/vcap_v4l2.h
@@ -14,6 +14,7 @@
 #ifndef VCAP_V4L2_H
 #define VCAP_V4L2_H
 
+#define TOP_FIELD_FIX
 #ifdef __KERNEL__
 #include <linux/types.h>
 #include <linux/videodev2.h>
@@ -28,6 +29,12 @@
 #include <media/vcap_fmt.h>
 #include <mach/board.h>
 
+#define writel_iowmb(val, addr)		\
+	do {							\
+		__iowmb();					\
+		writel_relaxed(val, addr);	\
+	} while (0)
+
 struct vcap_client_data;
 
 enum rdy_buf {
@@ -37,11 +44,34 @@
 	VC_BUF1N2 = 0x11 << 1,
 };
 
+enum vp_state {
+	VP_UNKNOWN = 0,
+	VP_FRAME1,
+	VP_FRAME2,
+	VP_FRAME3,
+	VP_NORMAL,
+};
+
+enum nr_buf_pos {
+	BUF_NOT_IN_USE = 0,
+	NRT2_BUF,
+	T1_BUF,
+	T0_BUF,
+	TM1_BUF,
+};
+
 struct vcap_buf_info {
 	unsigned long vaddr;
 	unsigned long size;
 };
 
+enum vcap_op_mode {
+	UNKNOWN_VCAP_OP = 0,
+	VC_VCAP_OP,
+	VP_VCAP_OP,
+	VC_AND_VP_VCAP_OP,
+};
+
 struct vcap_action {
 	struct list_head		active;
 
@@ -61,13 +91,50 @@
 	int						ini_jiffies;
 };
 
+struct nr_buffer {
+	void						*vaddr;
+	unsigned long				paddr;
+	enum nr_buf_pos				nr_pos;
+};
+
+struct vp_action {
+	struct list_head		in_active;
+	struct list_head		out_active;
+
+	/* Buffer index */
+	enum vp_state			vp_state;
+#ifdef TOP_FIELD_FIX
+	bool					top_field;
+#endif
+
+	/* Buffers inside vc */
+	struct vcap_buffer      *bufTm1;
+	struct vcap_buffer      *bufT0;
+	struct vcap_buffer      *bufT1;
+	struct vcap_buffer      *bufT2;
+	struct vcap_buffer      *bufNRT2;
+
+	struct vcap_buffer      *bufOut;
+
+	void					*bufMotion;
+	struct nr_buffer		bufNR;
+	bool					nr_enabled;
+};
+
+struct vp_work_t {
+	struct work_struct work;
+	struct vcap_client_data *cd;
+	uint32_t irq;
+};
+
 struct vcap_dev {
 	struct v4l2_device		v4l2_dev;
 
 	struct video_device		*vfd;
 	struct ion_client       *ion_client;
 
-	struct resource         *vcapirq;
+	struct resource         *vcirq;
+	struct resource         *vpirq;
 
 	struct resource			*vcapmem;
 	struct resource			*vcapio;
@@ -87,15 +154,20 @@
 	struct vcap_client_data *vp_client;
 
 	atomic_t			    vc_enabled;
+	atomic_t			    vp_enabled;
+
 	atomic_t				vc_resource;
 	atomic_t				vp_resource;
+
+	struct workqueue_struct	*vcap_wq;
+	struct vp_work_t		vp_work;
+	struct vp_work_t		vc_to_vp_work;
+	struct vp_work_t		vp_to_vc_work;
 };
 
 struct vp_format_data {
 	unsigned int		width, height;
-	unsigned int		pixelformat;
-	enum v4l2_field		field;
-
+	unsigned int		pixfmt;
 };
 
 struct vcap_buffer {
@@ -107,18 +179,23 @@
 };
 
 struct vcap_client_data {
+	bool set_cap, set_decode, set_vp_o;
 	struct vcap_dev *dev;
 
 	struct vb2_queue		vc_vidq;
-	/*struct vb2_queue		vb__vidq;*/
-	/*struct vb2_queue		vb_cap_vidq;*/
+	struct vb2_queue		vp_in_vidq;
+	struct vb2_queue		vp_out_vidq;
+
+	enum vcap_op_mode		op_mode;
 
 	struct v4l2_format_vc_ext vc_format;
 
 	enum v4l2_buf_type		vp_buf_type_field;
-	struct vp_format_data	vp_format;
+	struct vp_format_data	vp_in_fmt;
+	struct vp_format_data	vp_out_fmt;
 
 	struct vcap_action		vid_vc_action;
+	struct vp_action		vid_vp_action;
 	struct workqueue_struct *vcap_work_q;
 	struct ion_handle			*vc_ion_handle;
 
@@ -126,7 +203,20 @@
 	uint32_t				hold_vp;
 
 	spinlock_t				cap_slock;
+	bool					streaming;
 };
 
+struct vcap_hacked_vals {
+	uint32_t	value;
+	uint32_t	offset;
+};
+
+extern struct vcap_hacked_vals hacked_buf[];
+
 #endif
+int free_ion_handle(struct vcap_dev *dev, struct vb2_queue *q,
+					 struct v4l2_buffer *b);
+
+int get_phys_addr(struct vcap_dev *dev, struct vb2_queue *q,
+				  struct v4l2_buffer *b);
 #endif
diff --git a/include/media/videobuf2-msm-mem.h b/include/media/videobuf2-msm-mem.h
index 822dd69..84e2bea 100644
--- a/include/media/videobuf2-msm-mem.h
+++ b/include/media/videobuf2-msm-mem.h
@@ -16,7 +16,7 @@
 #define _VIDEOBUF2_PMEM_CONTIG_H
 
 #include <media/videobuf2-core.h>
-#include <mach/msm_subsystem_map.h>
+#include <mach/iommu_domains.h>
 #include <linux/ion.h>
 
 struct videobuf2_mapping {
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 5749293..47b856c 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -26,7 +26,7 @@
 #define __HCI_CORE_H
 
 #include <net/bluetooth/hci.h>
-
+#include <linux/wakelock.h>
 /* HCI upper protocols */
 #define HCI_PROTO_L2CAP	0
 #define HCI_PROTO_SCO	1
@@ -326,7 +326,7 @@
 
 	struct work_struct work_add;
 	struct work_struct work_del;
-
+	struct wake_lock idle_lock;
 	struct device	dev;
 	atomic_t	devref;
 
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
new file mode 100644
index 0000000..695fea9
--- /dev/null
+++ b/include/sound/apr_audio-v2.h
@@ -0,0 +1,6172 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 2 and
+* only version 2 as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*/
+
+
+#ifndef _APR_AUDIO_V2_H_
+#define _APR_AUDIO_V2_H_
+
+#include <mach/qdsp6v2/apr.h>
+
+#define ADSP_ADM_VERSION    0x00070000
+
+#define ADM_CMD_SHARED_MEM_MAP_REGIONS    0x00010322
+#define ADM_CMDRSP_SHARED_MEM_MAP_REGIONS 0x00010323
+#define ADM_CMD_SHARED_MEM_UNMAP_REGIONS 0x00010324
+
+#define ADM_CMD_MATRIX_MAP_ROUTINGS_V5 0x00010325
+
+/* Enumeration for an audio Rx matrix ID.*/
+#define ADM_MATRIX_ID_AUDIO_RX              0
+
+#define ADM_MATRIX_ID_AUDIO_TX              1
+
+/* Enumeration for an audio Tx matrix ID.*/
+#define ADM_MATRIX_ID_AUDIOX              1
+
+#define ADM_MAX_COPPS 5
+
+
+/*  Session map node structure.
+*	Immediately following this structure are num_copps
+*	entries of COPP IDs. The COPP IDs are 16 bits, so
+*	there might be a padding 16-bit field if num_copps
+*	is odd.
+*/
+struct adm_session_map_node_v5 {
+	u16                  session_id;
+/* Handle of the ASM session to be routed. Supported values: 1
+* to 8.
+*/
+
+
+	u16                  num_copps;
+	/* Number of COPPs to which this session is to be routed.
+			Supported values: 0 < num_copps <= ADM_MAX_COPPS.
+	*/
+} __packed;
+
+/*  Payload of the #ADM_CMD_MATRIX_MAP_ROUTINGS_V5 command.
+*	Immediately following this structure are num_sessions of the session map
+*	node payload (adm_session_map_node_v5).
+*/
+
+struct adm_cmd_matrix_map_routings_v5 {
+	struct apr_hdr	hdr;
+
+	u32                  matrix_id;
+/* Specifies whether the matrix ID is Audio Rx (0) or Audio Tx
+* (1). Use the ADM_MATRIX_ID_AUDIO_RX or ADM_MATRIX_ID_AUDIOX
+* macros to set this field.
+*/
+	u32                  num_sessions;
+	/* Number of sessions being updated by this command (optional).*/
+} __packed;
+
+/* This command allows a client to open a COPP/Voice Proc. TX module
+*	and sets up	the device session: Matrix -> COPP -> AFE on the RX
+*	and AFE -> COPP -> Matrix on the TX. This enables PCM data to
+*	be transferred to/from the endpoint (AFEPortID).
+*
+*	@return
+*	#ADM_CMDRSP_DEVICE_OPEN_V5 with the resulting status and
+*	COPP ID.
+*/
+#define ADM_CMD_DEVICE_OPEN_V5                          0x00010326
+
+/* Indicates that endpoint_id_2 is to be ignored.*/
+#define ADM_CMD_COPP_OPEN_END_POINT_ID_2_IGNORE				0xFFFF
+
+#define ADM_CMD_COPP_OPEN_MODE_OF_OPERATION_RX_PATH_COPP		 1
+
+#define ADM_CMD_COPP_OPEN_MODE_OF_OPERATIONX_PATH_LIVE_COPP		 2
+
+#define ADM_CMD_COPP_OPEN_MODE_OF_OPERATIONX_PATH_NON_LIVE_COPP	 3
+
+/* Indicates that an audio COPP is to send/receive a mono PCM
+ * stream to/from
+ *	END_POINT_ID_1.
+ */
+#define ADM_CMD_COPP_OPEN_CHANNEL_CONFIG_MONO		1
+
+/* Indicates that an audio COPP is to send/receive a
+ *	stereo PCM stream to/from END_POINT_ID_1.
+ */
+#define ADM_CMD_COPP_OPEN_CHANNEL_CONFIG_STEREO		2
+
+/* Sample rate is 8000 Hz.*/
+#define ADM_CMD_COPP_OPEN_SAMPLE_RATE_8K 8000
+
+/* Sample rate is 16000 Hz.*/
+#define ADM_CMD_COPP_OPEN_SAMPLE_RATE_16K 16000
+
+/* Sample rate is 48000 Hz.*/
+#define ADM_CMD_COPP_OPEN_SAMPLE_RATE_48K 48000
+
+/* Definition for a COPP live input flag bitmask.*/
+#define ADM_BIT_MASK_COPP_LIVE_INPUT_FLAG (0x0001U)
+
+/* Definition for a COPP live shift value bitmask.*/
+#define ADM_SHIFT_COPP_LIVE_INPUT_FLAG	 0
+
+/* Definition for the COPP ID bitmask.*/
+#define ADM_BIT_MASK_COPP_ID  (0x0000FFFFUL)
+
+/* Definition for the COPP ID shift value.*/
+#define ADM_SHIFT_COPP_ID	0
+
+/* Definition for the service ID bitmask.*/
+#define ADM_BIT_MASK_SERVICE_ID  (0x00FF0000UL)
+
+/* Definition for the service ID shift value.*/
+#define ADM_SHIFT_SERVICE_ID	16
+
+/* Definition for the domain ID bitmask.*/
+#define ADM_BIT_MASK_DOMAIN_ID    (0xFF000000UL)
+
+/* Definition for the domain ID shift value.*/
+#define ADM_SHIFT_DOMAIN_ID	24
+
+/*  ADM device open command payload of the
+	#ADM_CMD_DEVICE_OPEN_V5 command.
+*/
+struct adm_cmd_device_open_v5 {
+	struct apr_hdr		hdr;
+	u16                  flags;
+/* Reserved for future use. Clients must set this field
+ * to zero.
+ */
+
+	u16                  mode_of_operation;
+/* Specifies whether the COPP must be opened on the Tx or Rx
+ * path. Use the ADM_CMD_COPP_OPEN_MODE_OF_OPERATION_* macros for
+ * supported values and interpretation.
+ * Supported values:
+ * - 0x1 -- Rx path COPP
+ * - 0x2 -- Tx path live COPP
+ * - 0x3 -- Tx path nonlive COPP
+ * Live connections cause sample discarding in the Tx device
+ * matrix if the destination output ports do not pull them
+ * fast enough. Nonlive connections queue the samples
+ * indefinitely.
+ */
+
+	u16                  endpoint_id_1;
+/* Logical and physical endpoint ID of the audio path.
+ * If the ID is a voice processor Tx block, it receives near
+ * samples.	Supported values: Any pseudoport, AFE Rx port,
+ * or AFE Tx port For a list of valid IDs, refer to
+ * @xhyperref{Q4,[Q4]}.
+ * Q4 = Hexagon Multimedia: AFE Interface Specification
+ */
+
+	u16                  endpoint_id_2;
+/* Logical and physical endpoint ID 2 for a voice processor
+ * Tx block.
+ * This is not applicable to audio COPP.
+ * Supported values:
+ * - AFE Rx port
+ * - 0xFFFF -- Endpoint 2 is unavailable and the voice
+ * processor Tx
+ * block ignores this endpoint
+ * When the voice processor Tx block is created on the audio
+ * record path,
+ * it can receive far-end samples from an AFE Rx port if the
+ * voice call
+ * is active. The ID of the AFE port is provided in this
+ * field.
+ * For a list of valid IDs, refer @xhyperref{Q4,[Q4]}.
+ */
+
+	u32                  topology_id;
+	/* Audio COPP topology ID; 32-bit GUID. */
+
+	u16                  dev_num_channel;
+/* Number of channels the audio COPP sends to/receives from
+ * the endpoint.
+ * Supported values: 1 to 8.
+ * The value is ignored for the voice processor Tx block,
+ * where channel
+ * configuration is derived from the topology ID.
+ */
+
+	u16                  bit_width;
+/* Bit width (in bits) that the audio COPP sends to/receives
+ * from the
+ * endpoint. The value is ignored for the voice processing
+ * Tx block,
+ * where the PCM width is 16 bits.
+ */
+
+	u32                  sample_rate;
+/* Sampling rate at which the audio COPP/voice processor
+ * Tx block
+ * interfaces with the endpoint.
+ * Supported values for voice processor Tx: 8000, 16000,
+ * 48000 Hz
+ * Supported values for audio COPP: >0 and <=192 kHz
+ */
+
+	u8                   dev_channel_mapping[8];
+/* Array of channel mapping of buffers that the audio COPP
+ * sends to the endpoint. Channel[i] mapping describes channel
+ * I inside the buffer, where 0 < i < dev_num_channel.
+ * This value is relevent only for an audio Rx COPP.
+ * For the voice processor block and Tx audio block, this field
+ * is set to zero and is ignored.
+ */
+} __packed;
+
+/*
+ *	This command allows the client to close a COPP and disconnect
+ *	the device session.
+ */
+#define ADM_CMD_DEVICE_CLOSE_V5                         0x00010327
+
+/* Sets one or more parameters to a COPP.
+*/
+#define ADM_CMD_SET_PP_PARAMS_V5                        0x00010328
+
+/*  Payload of the #ADM_CMD_SET_PP_PARAMS_V5 command.
+ *	If the data_payload_addr_lsw and data_payload_addr_msw element
+ *	are NULL, a series of adm_param_datastructures immediately
+ *	follows, whose total size is data_payload_size bytes.
+ */
+struct adm_cmd_set_pp_params_v5 {
+	struct apr_hdr hdr;
+		u32                  data_payload_addr_lsw;
+	/* LSW of parameter data payload address.*/
+	u32                  data_payload_addr_msw;
+	/* MSW of parameter data payload address.*/
+
+		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;
+/* Size in bytes of the variable payload accompanying this
+ * message or
+ * in shared memory. This is used for parsing the parameter
+ * payload.
+ */
+} __packed;
+
+/*  Payload format for COPP parameter data.
+ * Immediately following this structure are param_size bytes
+ * of parameter
+ * data.
+ */
+struct adm_param_data_v5 {
+	u32                  module_id;
+	/* Unique ID of the module. */
+	u32                  param_id;
+	/* Unique ID of the parameter. */
+	u16                  param_size;
+	/* Data size of the param_id/module_id combination.
+	This value is a
+		multiple of 4 bytes. */
+	u16                  reserved;
+	/* Reserved for future enhancements.
+	 * This field must be set to zero.
+	 */
+} __packed;
+
+/* Returns the status and COPP ID to an #ADM_CMD_DEVICE_OPEN_V5 command.
+ */
+#define ADM_CMDRSP_DEVICE_OPEN_V5                      0x00010329
+
+/*  Payload of the #ADM_CMDRSP_DEVICE_OPEN_V5 message,
+ *	which returns the
+ *	status and COPP ID to an #ADM_CMD_DEVICE_OPEN_V5 command.
+ */
+struct adm_cmd_rsp_device_open_v5 {
+	u32                  status;
+	/* Status message (error code).*/
+
+	u16                  copp_id;
+	/* COPP ID:  Supported values: 0 <= copp_id < ADM_MAX_COPPS*/
+
+	u16                  reserved;
+	/* Reserved. This field must be set to zero.*/
+} __packed;
+
+/* This command allows a query of one COPP parameter.
+*/
+#define ADM_CMD_GET_PP_PARAMS_V5                                0x0001032A
+
+/*  Payload an #ADM_CMD_GET_PP_PARAMS_V5 command.
+*/
+struct adm_cmd_get_pp_params_v5 {
+	u32                  data_payload_addr_lsw;
+	/* LSW of parameter data payload address.*/
+
+	u32                  data_payload_addr_msw;
+	/* MSW of parameter data payload address.*/
+
+	/* If the mem_map_handle is non zero,
+	 * on ACK, the ParamData payloads begin at
+	 * the address specified (out-of-band).
+	 */
+
+	u32                  mem_map_handle;
+	/* Memory map handle returned
+	 * by ADM_CMD_SHARED_MEM_MAP_REGIONS command.
+	 * If the mem_map_handle is 0, it implies that
+	 * the ACK's payload will contain the ParamData (in-band).
+	 */
+
+	u32                  module_id;
+	/* Unique ID of the module. */
+
+	u32                  param_id;
+	/* Unique ID of the parameter. */
+
+	u16                  param_max_size;
+	/* Maximum data size of the parameter
+	 *ID/module ID combination. This
+	 * field is a multiple of 4 bytes.
+	 */
+	u16                  reserved;
+	/* Reserved for future enhancements.
+	 * This field must be set to zero.
+	 */
+} __packed;
+
+/* Returns parameter values
+ *	in response to an #ADM_CMD_GET_PP_PARAMS_V5 command.
+ */
+#define ADM_CMDRSP_GET_PP_PARAMS_V5		0x0001032B
+
+/* Payload of the #ADM_CMDRSP_GET_PP_PARAMS_V5 message,
+ * which returns parameter values in response
+ * to an #ADM_CMD_GET_PP_PARAMS_V5 command.
+ * Immediately following this
+ * structure is the adm_param_data_v5
+ * structure containing the pre/postprocessing
+ * parameter data. For an in-band
+ * scenario, the variable payload depends
+ * on the size of the parameter.
+*/
+struct adm_cmd_rsp_get_pp_params_v5 {
+	u32                  status;
+	/* Status message (error code).*/
+} __packed;
+
+/* Allows a client to control the gains on various session-to-COPP paths.
+ */
+#define ADM_CMD_MATRIX_RAMP_GAINS_V5                                 0x0001032C
+
+/* Indicates that the target gain in the
+ *	current adm_session_copp_gain_v5
+ *	structure is to be applied to all
+ *	the session-to-COPP paths that exist for
+ *	the specified session.
+ */
+#define ADM_CMD_MATRIX_RAMP_GAINS_COPP_ID_ALL_CONNECTED_COPPS     0xFFFF
+
+/* Indicates that the target gain is
+ * to be immediately applied to the
+ * specified session-to-COPP path,
+ * without a ramping fashion.
+ */
+#define ADM_CMD_MATRIX_RAMP_GAINS_RAMP_DURATION_IMMEDIATE         0x0000
+
+/* Enumeration for a linear ramping curve.*/
+#define ADM_CMD_MATRIX_RAMP_GAINS_RAMP_CURVE_LINEAR               0x0000
+
+/*  Payload of the #ADM_CMD_MATRIX_RAMP_GAINS_V5 command.
+ * Immediately following this structure are num_gains of the
+ * adm_session_copp_gain_v5structure.
+ */
+struct adm_cmd_matrix_ramp_gains_v5 {
+	u32                  matrix_id;
+/* Specifies whether the matrix ID is Audio Rx (0) or Audio Tx (1).
+ * Use the ADM_MATRIX_ID_AUDIO_RX or  ADM_MATRIX_ID_AUDIOX
+ * macros to set this field.
+*/
+
+	u16                  num_gains;
+	/* Number of gains being applied. */
+
+	u16                  reserved_for_align;
+	/* Reserved. This field must be set to zero.*/
+} __packed;
+
+/*  Session-to-COPP path gain structure, used by the
+ *	#ADM_CMD_MATRIX_RAMP_GAINS_V5 command.
+ *	This structure specifies the target
+ *	gain (per channel) that must be applied
+ *	to a particular session-to-COPP path in
+ *	the audio matrix. The structure can
+ *	also be used to apply the gain globally
+ *	to all session-to-COPP paths that
+ *	exist for the given session.
+ *	The aDSP uses device channel mapping to
+ *	determine which channel gains to
+ *	use from this command. For example,
+ *	if the device is configured as stereo,
+ *	the aDSP uses only target_gain_ch_1 and
+ *	target_gain_ch_2, and it ignores
+ *	the others.
+ */
+struct adm_session_copp_gain_v5 {
+	u16                  session_id;
+/* Handle of the ASM session.
+ *	Supported values: 1 to 8.
+ */
+
+	u16                  copp_id;
+/* Handle of the COPP. Gain will be applied on the Session ID
+ * COPP ID path.
+ */
+
+	u16                  ramp_duration;
+/* Duration (in milliseconds) of the ramp over
+ * which target gains are
+ * to be applied. Use
+ * #ADM_CMD_MATRIX_RAMP_GAINS_RAMP_DURATION_IMMEDIATE
+ * to indicate that gain must be applied immediately.
+ */
+
+	u16                  step_duration;
+/* Duration (in milliseconds) of each step in the ramp.
+ * This parameter is ignored if ramp_duration is equal to
+ * #ADM_CMD_MATRIX_RAMP_GAINS_RAMP_DURATION_IMMEDIATE.
+ * Supported value: 1
+ */
+
+	u16                  ramp_curve;
+/* Type of ramping curve.
+ * Supported value: #ADM_CMD_MATRIX_RAMP_GAINS_RAMP_CURVE_LINEAR
+ */
+
+	u16                  reserved_for_align;
+	/* Reserved. This field must be set to zero. */
+
+	u16                  target_gain_ch_1;
+	/* Target linear gain for channel 1 in Q13 format; */
+
+	u16                  target_gain_ch_2;
+	/* Target linear gain for channel 2 in Q13 format; */
+
+	u16                  target_gain_ch_3;
+	/* Target linear gain for channel 3 in Q13 format; */
+
+	u16                  target_gain_ch_4;
+	/* Target linear gain for channel 4 in Q13 format; */
+
+	u16                  target_gain_ch_5;
+	/* Target linear gain for channel 5 in Q13 format; */
+
+	u16                  target_gain_ch_6;
+	/* Target linear gain for channel 6 in Q13 format; */
+
+	u16                  target_gain_ch_7;
+	/* Target linear gain for channel 7 in Q13 format; */
+
+	u16                  target_gain_ch_8;
+	/* Target linear gain for channel 8 in Q13 format; */
+} __packed;
+
+/* Allows to set mute/unmute on various session-to-COPP paths.
+ *	For every session-to-COPP path (stream-device interconnection),
+ *	mute/unmute can be set individually on the output channels.
+ */
+#define ADM_CMD_MATRIX_MUTE_V5                                0x0001032D
+
+/* Indicates that mute/unmute in the
+ *	current adm_session_copp_mute_v5structure
+ *	is to be applied to all the session-to-COPP
+ *	paths that exist for the specified session.
+ */
+#define ADM_CMD_MATRIX_MUTE_COPP_ID_ALL_CONNECTED_COPPS     0xFFFF
+
+/*  Payload of the #ADM_CMD_MATRIX_MUTE_V5 command*/
+struct adm_cmd_matrix_mute_v5 {
+	u32                  matrix_id;
+/* Specifies whether the matrix ID is Audio Rx (0) or Audio Tx (1).
+ * Use the ADM_MATRIX_ID_AUDIO_RX or  ADM_MATRIX_ID_AUDIOX
+ * macros to set this field.
+ */
+
+	u16                  session_id;
+/* Handle of the ASM session.
+ * Supported values: 1 to 8.
+ */
+
+	u16                  copp_id;
+/* Handle of the COPP.
+ * Use ADM_CMD_MATRIX_MUTE_COPP_ID_ALL_CONNECTED_COPPS
+ * to indicate that mute/unmute must be applied to
+ * all the COPPs connected to session_id.
+ * Supported values:
+ * - 0xFFFF -- Apply mute/unmute to all connected COPPs
+ * - Other values -- Valid COPP ID
+ */
+
+	u8                  mute_flag_ch_1;
+	/* Mute flag for channel 1 is set to unmute (0) or mute (1). */
+
+	u8                  mute_flag_ch_2;
+	/* Mute flag for channel 2 is set to unmute (0) or mute (1). */
+
+	u8                  mute_flag_ch_3;
+	/* Mute flag for channel 3 is set to unmute (0) or mute (1). */
+
+	u8                  mute_flag_ch_4;
+	/* Mute flag for channel 4 is set to unmute (0) or mute (1). */
+
+	u8                  mute_flag_ch_5;
+	/* Mute flag for channel 5 is set to unmute (0) or mute (1). */
+
+	u8                  mute_flag_ch_6;
+	/* Mute flag for channel 6 is set to unmute (0) or mute (1). */
+
+	u8                  mute_flag_ch_7;
+	/* Mute flag for channel 7 is set to unmute (0) or mute (1). */
+
+	u8                  mute_flag_ch_8;
+	/* Mute flag for channel 8 is set to unmute (0) or mute (1). */
+
+	u16                 ramp_duration;
+/* Period (in milliseconds) over which the soft mute/unmute will be
+ * applied.
+ * Supported values: 0 (Default) to 0xFFFF
+ * The default of 0 means mute/unmute will be applied immediately.
+ */
+
+	u16                 reserved_for_align;
+	/* Clients must set this field to zero.*/
+} __packed;
+
+/* Allows a client to connect the desired stream to
+ * the desired AFE port through the stream router
+ *
+ * This command allows the client to connect specified session to
+ * specified AFE port. This is used for compressed streams only
+ * opened using the #ASM_STREAM_CMD_OPEN_WRITE_COMPRESSED or
+ * #ASM_STREAM_CMD_OPEN_READ_COMPRESSED command.
+ *
+ * @prerequisites
+ * Session ID and AFE Port ID must be valid.
+ * #ASM_STREAM_CMD_OPEN_WRITE_COMPRESSED or
+ * #ASM_STREAM_CMD_OPEN_READ_COMPRESSED
+ * must have been called on this session.
+ */
+
+#define ADM_CMD_CONNECT_AFE_PORT_V5	0x0001032E
+#define ADM_CMD_DISCONNECT_AFE_PORT_V5	0x0001032F
+/* Enumeration for the Rx stream router ID.*/
+#define ADM_STRTR_ID_RX                    0
+/* Enumeration for the Tx stream router ID.*/
+#define ADM_STRTR_IDX                    1
+
+/*  Payload of the #ADM_CMD_CONNECT_AFE_PORT_V5 command.*/
+struct adm_cmd_connect_afe_port_v5 {
+	u8                  mode;
+/* ID of the stream router (RX/TX). Use the
+ * ADM_STRTR_ID_RX or ADM_STRTR_IDX macros
+ * to set this field.
+ */
+
+	u8                  session_id;
+	/* Session ID of the stream to connect */
+
+	u16                 afe_port_id;
+	/* Port ID of the AFE port to connect to.*/
+	u32                 num_channels;
+/* Number of device channels
+ * Supported values: 2(Audio Sample Packet),
+ * 8 (HBR Audio Stream Sample Packet)
+ */
+
+	u32                 sampling_rate;
+/* Device sampling rate
+* Supported values: Any
+*/
+} __packed;
+
+
+/* adsp_adm_api.h */
+
+
+/* Port ID. Update afe_get_port_index
+ *	when a new port is added here. */
+#define PRIMARY_I2S_RX 0		/* index = 0 */
+#define PRIMARY_I2S_TX 1		/* index = 1 */
+#define PCM_RX 2			/* index = 2 */
+#define PCM_TX 3			/* index = 3 */
+#define SECONDARY_I2S_RX 4		/* index = 4 */
+#define SECONDARY_I2S_TX 5		/* index = 5 */
+#define MI2S_RX 6			/* index = 6 */
+#define MI2S_TX 7			/* index = 7 */
+#define HDMI_RX 8			/* index = 8 */
+#define RSVD_2 9			/* index = 9 */
+#define RSVD_3 10			/* index = 10 */
+#define DIGI_MIC_TX 11			/* index = 11 */
+#define VOICE_RECORD_RX 0x8003		/* index = 12 */
+#define VOICE_RECORD_TX 0x8004		/* index = 13 */
+#define VOICE_PLAYBACK_TX 0x8005	/* index = 14 */
+
+/* Slimbus Multi channel port id pool  */
+#define SLIMBUS_0_RX		0x4000		/* index = 15 */
+#define SLIMBUS_0_TX		0x4001		/* index = 16 */
+#define SLIMBUS_1_RX		0x4002		/* index = 17 */
+#define SLIMBUS_1_TX		0x4003		/* index = 18 */
+#define SLIMBUS_2_RX		0x4004
+#define SLIMBUS_2_TX		0x4005
+#define SLIMBUS_3_RX		0x4006
+#define SLIMBUS_3_TX		0x4007
+#define SLIMBUS_4_RX		0x4008
+#define SLIMBUS_4_TX		0x4009		/* index = 24 */
+#define INT_BT_SCO_RX 0x3000		/* index = 25 */
+#define INT_BT_SCO_TX 0x3001		/* index = 26 */
+#define INT_BT_A2DP_RX 0x3002		/* index = 27 */
+#define INT_FM_RX 0x3004		/* index = 28 */
+#define INT_FM_TX 0x3005		/* index = 29 */
+#define RT_PROXY_PORT_001_RX	0x2000    /* index = 30 */
+#define RT_PROXY_PORT_001_TX	0x2001    /* index = 31 */
+
+#define AFE_PORT_INVALID 0xFFFF
+#define SLIMBUS_INVALID AFE_PORT_INVALID
+
+#define AFE_PORT_CMD_START 0x000100ca
+
+#define AFE_EVENT_RTPORT_START 0
+#define AFE_EVENT_RTPORT_STOP 1
+#define AFE_EVENT_RTPORT_LOW_WM 2
+#define AFE_EVENT_RTPORT_HI_WM 3
+
+#define ADSP_AFE_VERSION    0x00200000
+
+/* Size of the range of port IDs for the audio interface. */
+#define  AFE_PORT_ID_AUDIO_IF_PORT_RANGE_SIZE	0xF
+
+/* Size of the range of port IDs for internal BT-FM ports. */
+#define AFE_PORT_ID_INTERNAL_BT_FM_RANGE_SIZE	0x6
+
+/* Size of the range of port IDs for SLIMbus<sup>&reg;
+ * </sup> multichannel
+ * ports.
+ */
+#define AFE_PORT_ID_SLIMBUS_RANGE_SIZE	0xA
+
+/* Size of the range of port IDs for real-time proxy ports. */
+#define  AFE_PORT_ID_RT_PROXY_PORT_RANGE_SIZE	0x2
+
+/* Size of the range of port IDs for pseudoports. */
+#define AFE_PORT_ID_PSEUDOPORT_RANGE_SIZE	0x5
+
+/* Start of the range of port IDs for the audio interface. */
+#define  AFE_PORT_ID_AUDIO_IF_PORT_RANGE_START	0x1000
+
+/* End of the range of port IDs for the audio interface. */
+#define  AFE_PORT_ID_AUDIO_IF_PORT_RANGE_END \
+	(AFE_PORT_ID_AUDIO_IF_PORT_RANGE_START +\
+	AFE_PORT_ID_AUDIO_IF_PORT_RANGE_SIZE - 1)
+
+/* Start of the range of port IDs for real-time proxy ports. */
+#define  AFE_PORT_ID_RT_PROXY_PORT_RANGE_START	0x2000
+
+/* End of the range of port IDs for real-time proxy ports. */
+#define  AFE_PORT_ID_RT_PROXY_PORT_RANGE_END \
+	(AFE_PORT_ID_RT_PROXY_PORT_RANGE_START +\
+	AFE_PORT_ID_RT_PROXY_PORT_RANGE_SIZE-1)
+
+/* Start of the range of port IDs for internal BT-FM devices. */
+#define AFE_PORT_ID_INTERNAL_BT_FM_RANGE_START	0x3000
+
+/* End of the range of port IDs for internal BT-FM devices. */
+#define AFE_PORT_ID_INTERNAL_BT_FM_RANGE_END \
+	(AFE_PORT_ID_INTERNAL_BT_FM_RANGE_START +\
+	AFE_PORT_ID_INTERNAL_BT_FM_RANGE_SIZE-1)
+
+/*	Start of the range of port IDs for SLIMbus devices. */
+#define AFE_PORT_ID_SLIMBUS_RANGE_START	0x4000
+
+/*	End of the range of port IDs for SLIMbus devices. */
+#define AFE_PORT_ID_SLIMBUS_RANGE_END \
+	(AFE_PORT_ID_SLIMBUS_RANGE_START +\
+	AFE_PORT_ID_SLIMBUS_RANGE_SIZE-1)
+
+/* Start of the range of port IDs for pseudoports. */
+#define AFE_PORT_ID_PSEUDOPORT_RANGE_START	0x8001
+
+/* End of the range of port IDs for pseudoports.  */
+#define AFE_PORT_ID_PSEUDOPORT_RANGE_END \
+	(AFE_PORT_ID_PSEUDOPORT_RANGE_START +\
+	AFE_PORT_ID_PSEUDOPORT_RANGE_SIZE-1)
+
+#define AFE_PORT_ID_PRIMARY_MI2S_RX         0x1000
+#define AFE_PORT_ID_PRIMARY_MI2S_TX         0x1001
+#define AFE_PORT_ID_SECONDARY_MI2S_RX       0x1002
+#define AFE_PORT_ID_SECONDARY_MI2S_TX       0x1003
+#define AFE_PORT_IDERTIARY_MI2S_RX        0x1004
+#define AFE_PORT_IDERTIARY_MI2S_TX        0x1005
+#define AFE_PORT_ID_QUATERNARY_MI2S_RX      0x1006
+#define AFE_PORT_ID_QUATERNARY_MI2S_TX      0x1007
+#define AUDIO_PORT_ID_I2S_RX				0x1008
+#define AFE_PORT_ID_DIGITAL_MIC_TX          0x1009
+#define AFE_PORT_ID_PRIMARY_PCM_RX          0x100A
+#define AFE_PORT_ID_PRIMARY_PCM_TX          0x100B
+#define AFE_PORT_ID_SECONDARY_PCM_RX        0x100C
+#define AFE_PORT_ID_SECONDARY_PCM_TX        0x100D
+#define AFE_PORT_ID_MULTICHAN_HDMI_RX       0x100E
+#define  AFE_PORT_ID_RT_PROXY_PORT_001_RX   0x2000
+#define  AFE_PORT_ID_RT_PROXY_PORT_001_TX   0x2001
+#define AFE_PORT_ID_INTERNAL_BT_SCO_RX      0x3000
+#define AFE_PORT_ID_INTERNAL_BT_SCO_TX      0x3001
+#define AFE_PORT_ID_INTERNAL_BT_A2DP_RX     0x3002
+#define AFE_PORT_ID_INTERNAL_FM_RX          0x3004
+#define AFE_PORT_ID_INTERNAL_FM_TX          0x3005
+/* SLIMbus Rx port on channel 0. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_0_RX      0x4000
+/* SLIMbus Tx port on channel 0. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_0_TX      0x4001
+/* SLIMbus Rx port on channel 1. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_1_RX      0x4002
+/* SLIMbus Tx port on channel 1. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_1_TX      0x4003
+/* SLIMbus Rx port on channel 2. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_2_RX      0x4004
+/* SLIMbus Tx port on channel 2. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_2_TX      0x4005
+/* SLIMbus Rx port on channel 3. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_3_RX      0x4006
+/* SLIMbus Tx port on channel 3. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_3_TX      0x4007
+/* SLIMbus Rx port on channel 4. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_4_RX      0x4008
+/* SLIMbus Tx port on channel 4. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_4_TX      0x4009
+/* SLIMbus Rx port on channel 0. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_0_RX      0x4000
+/* SLIMbus Tx port on channel 0. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_0_TX      0x4001
+/* SLIMbus Rx port on channel 1. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_1_RX      0x4002
+/* SLIMbus Tx port on channel 1. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_1_TX      0x4003
+/* SLIMbus Rx port on channel 2. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_2_RX      0x4004
+/* SLIMbus Tx port on channel 2. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_2_TX      0x4005
+/* SLIMbus Rx port on channel 3. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_3_RX      0x4006
+/* SLIMbus Tx port on channel 3. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_3_TX      0x4007
+/* SLIMbus Rx port on channel 4. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_4_RX      0x4008
+/* SLIMbus Tx port on channel 4. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_4_TX      0x4009
+/* Generic pseudoport 1. */
+#define AFE_PORT_ID_PSEUDOPORT_01      0x8001
+/* Generic pseudoport 2. */
+#define AFE_PORT_ID_PSEUDOPORT_02      0x8002
+
+/* @xreflabel{hdr:AfePortIdPrimaryAuxPcmTx}
+	Primary Aux PCM Tx port ID.
+*/
+#define AFE_PORT_ID_PRIMARY_PCM_TX      0x100B
+/* Pseudoport that corresponds to the voice Rx path.
+ * For recording, the voice Rx path samples are written to this
+ * port and consumed by the audio path.
+ */
+
+#define AFE_PORT_ID_VOICE_RECORD_RX	0x8003
+
+/* Pseudoport that corresponds to the voice Tx path.
+ * For recording, the voice Tx path samples are written to this
+ * port and consumed by the audio path.
+ */
+
+#define AFE_PORT_ID_VOICE_RECORD_TX	0x8004
+/* Pseudoport that corresponds to in-call voice delivery samples.
+ * During in-call audio delivery, the audio path delivers samples
+ * to this port from where the voice path delivers them on the
+ * Rx path.
+ */
+#define AFE_PORT_ID_VOICE_PLAYBACK_TX   0x8005
+#define AFE_PORT_ID_INVALID             0xFFFF
+
+#define AAC_ENC_MODE_AAC_LC 0x02
+#define AAC_ENC_MODE_AAC_P 0x05
+#define AAC_ENC_MODE_EAAC_P 0x1D
+
+#define AFE_PSEUDOPORT_CMD_START 0x000100cf
+struct afe_pseudoport_start_command {
+	struct apr_hdr hdr;
+	u16 port_id;		/* Pseudo Port 1 = 0x8000 */
+				/* Pseudo Port 2 = 0x8001 */
+				/* Pseudo Port 3 = 0x8002 */
+	u16 timing;		/* FTRT = 0 , AVTimer = 1, */
+} __packed;
+
+#define AFE_PSEUDOPORT_CMD_STOP 0x000100d0
+struct afe_pseudoport_stop_command {
+	struct apr_hdr hdr;
+	u16 port_id;		/* Pseudo Port 1 = 0x8000 */
+				/* Pseudo Port 2 = 0x8001 */
+				/* Pseudo Port 3 = 0x8002 */
+	u16 reserved;
+} __packed;
+
+
+#define AFE_MODULE_SIDETONE_IIR_FILTER	0x00010202
+#define AFE_PARAM_ID_ENABLE	0x00010203
+
+/*  Payload of the #AFE_PARAM_ID_ENABLE
+ * parameter, which enables or
+ * disables any module.
+ * The fixed size of this structure is four bytes.
+ */
+
+struct afe_mod_enable_param {
+	u16                  enable;
+	/* Enables (1) or disables (0) the module. */
+
+	u16                  reserved;
+	/* This field must be set to zero.
+		*/
+} __packed;
+
+/* ID of the configuration parameter used by the
+ * #AFE_MODULE_SIDETONE_IIR_FILTER module.
+ */
+#define AFE_PARAM_ID_SIDETONE_IIR_FILTER_CONFIG	0x00010204
+
+struct afe_sidetone_iir_filter_config_params {
+	u16                  num_biquad_stages;
+/* Number of stages.
+ * Supported values: Minimum of 5 and maximum of 10
+ */
+
+	u16                  pregain;
+/* Pregain for the compensating filter response.
+ * Supported values: Any number in Q13 format
+ */
+} __packed;
+
+#define AFE_MODULE_LOOPBACK	0x00010205
+#define AFE_PARAM_ID_LOOPBACK_GAIN_PER_PATH	0x00010206
+
+/* Payload of the #AFE_PARAM_ID_LOOPBACK_GAIN_PER_PATH parameter,
+ * which gets/sets loopback gain of a port to an Rx port.
+ * The Tx port ID of the loopback is part of the set_param command.
+ */
+
+/*  Payload of the #AFE_PORT_CMD_SET_PARAM_V2 command's
+ * configuration/calibration settings for the AFE port.
+ */
+struct afe_port_cmd_set_param_v2 {
+	u16 port_id;
+/* Port interface and direction (Rx or Tx) to start.
+ */
+
+	u16 payload_size;
+/* Actual size of the payload in bytes.
+ * This is used for parsing the parameter payload.
+ * Supported values: > 0
+ */
+
+u32 payload_address_lsw;
+/* LSW of 64 bit Payload address.
+ * Address should be 32-byte,
+ * 4kbyte aligned and must be contiguous memory.
+ */
+
+u32 payload_address_msw;
+/* MSW of 64 bit Payload address.
+ * In case of 32-bit shared memory address,
+ * this field must be set to zero.
+ * In case of 36-bit shared memory address,
+ * bit-4 to bit-31 must be set to zero.
+ * Address should be 32-byte, 4kbyte aligned
+ * and must be contiguous memory.
+ */
+
+u32 mem_map_handle;
+/* Memory map handle returned by
+ * AFE_SERVICE_CMD_SHARED_MEM_MAP_REGIONS commands.
+ * Supported Values:
+ * - NULL -- Message. The parameter data is in-band.
+ * - Non-NULL -- The parameter data is Out-band.Pointer to
+ * the physical address
+ * in shared memory of the payload data.
+ * An optional field is available if parameter
+ * data is in-band:
+ * afe_param_data_v2 param_data[...].
+ * For detailed payload content, see the
+ * afe_port_param_data_v2 structure.
+ */
+} __packed;
+
+#define AFE_PORT_CMD_SET_PARAM_V2	0x000100EF
+
+struct afe_port_param_data_v2 {
+	u32 module_id;
+/* ID of the module to be configured.
+ * Supported values: Valid module ID
+ */
+
+u32 param_id;
+/* ID of the parameter corresponding to the supported parameters
+ * for the module ID.
+ * Supported values: Valid parameter ID
+ */
+
+u16 param_size;
+/* Actual size of the data for the
+ * module_id/param_id pair. The size is a
+ * multiple of four bytes.
+ * Supported values: > 0
+ */
+
+u16 reserved;
+/* This field must be set to zero.
+ */
+} __packed;
+
+struct afe_loopback_gain_per_path_param {
+	struct apr_hdr	hdr;
+	struct afe_port_cmd_set_param_v2 param;
+	struct afe_port_param_data_v2    pdata;
+	u16                  rx_port_id;
+/* Rx port of the loopback. */
+
+u16                  gain;
+/* Loopback gain per path of the port.
+ * Supported values: Any number in Q13 format
+ */
+} __packed;
+
+/* Parameter ID used to configure and enable/disable the
+ * loopback path. The difference with respect to the existing
+ * API, AFE_PORT_CMD_LOOPBACK, is that it allows Rx port to be
+ * configured as source port in loopback path. Port-id in
+ * AFE_PORT_CMD_SET_PARAM cmd is the source port whcih can be
+ * Tx or Rx port. In addition, we can configure the type of
+ * routing mode to handle different use cases.
+ */
+#define AFE_PARAM_ID_LOOPBACK_CONFIG	0x0001020B
+#define AFE_API_VERSION_LOOPBACK_CONFIG	0x1
+
+enum afe_loopback_routing_mode {
+	LB_MODE_DEFAULT = 1,
+	/* Regular loopback from source to destination port */
+	LB_MODE_SIDETONE,
+	/* Sidetone feed from Tx source to Rx destination port */
+	LB_MODE_EC_REF_VOICE_AUDIO,
+	/* Echo canceller reference, voice + audio + DTMF */
+	LB_MODE_EC_REF_VOICE
+	/* Echo canceller reference, voice alone */
+} __packed;
+
+/*  Payload of the #AFE_PARAM_ID_LOOPBACK_CONFIG ,
+ * which enables/disables one AFE loopback.
+ */
+struct afe_loopback_cfg_v1 {
+	struct apr_hdr	hdr;
+	struct afe_port_cmd_set_param_v2 param;
+	struct afe_port_param_data_v2    pdata;
+	u32		loopback_cfg_minor_version;
+/* Minor version used for tracking the version of the RMC module
+ * configuration interface.
+ * Supported values: #AFE_API_VERSION_LOOPBACK_CONFIG
+ */
+	u16                  dst_port_id;
+	/* Destination Port Id. */
+	u16                  routing_mode;
+/* Specifies data path type from src to dest port.
+ * Supported values:
+ * #LB_MODE_DEFAULT
+ * #LB_MODE_SIDETONE
+ * #LB_MODE_EC_REF_VOICE_AUDIO
+ * #LB_MODE_EC_REF_VOICE_A
+ * #LB_MODE_EC_REF_VOICE
+ */
+
+	u16                  enable;
+/* Specifies whether to enable (1) or
+ * disable (0) an AFE loopback.
+ */
+	u16                  reserved;
+/* Reserved for 32-bit alignment. This field must be set to 0.
+ */
+
+} __packed;
+
+#define AFE_MODULE_SPEAKER_PROTECTION	0x00010209
+#define AFE_PARAM_ID_SPKR_PROT_CONFIG	0x0001020a
+#define AFE_API_VERSION_SPKR_PROT_CONFIG	0x1
+#define AFE_SPKR_PROT_EXCURSIONF_LEN	512
+struct afe_spkr_prot_cfg_param_v1 {
+	u32       spkr_prot_minor_version;
+/*
+ * Minor version used for tracking the version of the
+ * speaker protection module configuration interface.
+ * Supported values: #AFE_API_VERSION_SPKR_PROT_CONFIG
+ */
+
+int16_t        win_size;
+/* Analysis and synthesis window size (nWinSize).
+ * Supported values: 1024, 512, 256 samples
+ */
+
+int16_t        margin;
+/* Allowable margin for excursion prediction,
+ * in L16Q15 format. This is a
+ * control parameter to allow
+ * for overestimation of peak excursion.
+ */
+
+int16_t        spkr_exc_limit;
+/* Speaker excursion limit, in L16Q15 format.*/
+
+int16_t        spkr_resonance_freq;
+/* Resonance frequency of the speaker; used
+ * to define a frequency range
+ * for signal modification.
+ *
+ * Supported values: 0 to 2000 Hz */
+
+int16_t        limhresh;
+/* Threshold of the hard limiter; used to
+ * prevent overshooting beyond a
+ * signal level that was set by the limiter
+ * prior to speaker protection.
+ * Supported values: 0 to 32767
+ */
+
+int16_t        hpf_cut_off_freq;
+/* High pass filter cutoff frequency.
+ * Supported values: 100, 200, 300 Hz
+ */
+
+int16_t        hpf_enable;
+/* Specifies whether the high pass filter
+ * is enabled (0) or disabled (1).
+ */
+
+int16_t        reserved;
+/* This field must be set to zero. */
+
+int32_t        amp_gain;
+/* Amplifier gain in L32Q15 format.
+ * This is the RMS voltage at the
+ * loudspeaker when a 0dBFS tone
+ * is played in the digital domain.
+ */
+
+int16_t        excursionf[AFE_SPKR_PROT_EXCURSIONF_LEN];
+/* Array of the excursion transfer function.
+ * The peak excursion of the
+ * loudspeaker diaphragm is
+ * measured in millimeters for 1 Vrms Sine
+ * tone at all FFT bin frequencies.
+ * Supported values: Q15 format
+ */
+} __packed;
+
+
+#define AFE_SERVICE_CMD_REGISTER_RT_PORT_DRIVER	0x000100E0
+
+/*  Payload of the #AFE_SERVICE_CMD_REGISTER_RT_PORT_DRIVER
+ * command, which registers a real-time port driver
+ * with the AFE service.
+ */
+struct afe_service_cmd_register_rt_port_driver {
+	struct apr_hdr hdr;
+	u16                  port_id;
+/* Port ID with which the real-time driver exchanges data
+ * (registers for events).
+ * Supported values: #AFE_PORT_ID_RT_PROXY_PORT_RANGE_START to
+ * #AFE_PORT_ID_RT_PROXY_PORT_RANGE_END
+ */
+
+	u16                  reserved;
+	/* This field must be set to zero. */
+} __packed;
+
+#define AFE_SERVICE_CMD_UNREGISTER_RT_PORT_DRIVER	0x000100E1
+
+/*  Payload of the #AFE_SERVICE_CMD_UNREGISTER_RT_PORT_DRIVER
+ * command, which unregisters a real-time port driver from
+ * the AFE service.
+ */
+struct afe_service_cmd_unregister_rt_port_driver {
+	struct apr_hdr hdr;
+	u16                  port_id;
+/* Port ID from which the real-time
+ * driver unregisters for events.
+ * Supported values: #AFE_PORT_ID_RT_PROXY_PORT_RANGE_START to
+ * #AFE_PORT_ID_RT_PROXY_PORT_RANGE_END
+ */
+
+	u16                  reserved;
+	/* This field must be set to zero.	*/
+} __packed;
+
+#define AFE_EVENT_RT_PROXY_PORT_STATUS	0x00010105
+#define AFE_EVENTYPE_RT_PROXY_PORT_START	0
+#define AFE_EVENTYPE_RT_PROXY_PORT_STOP	1
+#define AFE_EVENTYPE_RT_PROXY_PORT_LOW_WATER_MARK	2
+#define AFE_EVENTYPE_RT_PROXY_PORT_HIGH_WATER_MARK	3
+#define AFE_EVENTYPE_RT_PROXY_PORT_INVALID	0xFFFF
+
+/*  Payload of the #AFE_EVENT_RT_PROXY_PORT_STATUS
+ * message, which sends an event from the AFE service
+ * to a registered client.
+ */
+struct afe_event_rt_proxy_port_status {
+	u16                  port_id;
+/* Port ID to which the event is sent.
+ * Supported values: #AFE_PORT_ID_RT_PROXY_PORT_RANGE_START to
+ * #AFE_PORT_ID_RT_PROXY_PORT_RANGE_END
+ */
+
+	u16                  eventype;
+/* Type of event.
+ * Supported values:
+ * - #AFE_EVENTYPE_RT_PROXY_PORT_START
+ * - #AFE_EVENTYPE_RT_PROXY_PORT_STOP
+ * - #AFE_EVENTYPE_RT_PROXY_PORT_LOW_WATER_MARK
+ * - #AFE_EVENTYPE_RT_PROXY_PORT_HIGH_WATER_MARK
+ */
+} __packed;
+
+#define AFE_PORT_DATA_CMD_RT_PROXY_PORT_WRITE_V2 0x000100ED
+
+struct afe_port_data_cmd_rt_proxy_port_write_v2 {
+	struct apr_hdr hdr;
+	u16                  port_id;
+/* Tx (mic) proxy port ID with which the real-time
+ * driver exchanges data.
+ * Supported values: #AFE_PORT_ID_RT_PROXY_PORT_RANGE_START to
+ * #AFE_PORT_ID_RT_PROXY_PORT_RANGE_END
+ */
+
+	u16                  reserved;
+	/* This field must be set to zero. */
+
+	u32                  buffer_address_lsw;
+/* LSW Address of the buffer containing the
+ * data from the real-time source
+ * device on a client.
+ */
+
+	u32                  buffer_address_msw;
+/* MSW Address of the buffer containing the
+ * data from the real-time source
+ * device on a client.
+ */
+
+	u32					mem_map_handle;
+/* A memory map handle encapsulating shared memory
+ * attributes is returned if
+ * AFE_SERVICE_CMD_SHARED_MEM_MAP_REGIONS
+ * command is successful.
+ * Supported Values:
+ * - Any 32 bit value
+ */
+
+	u32                  available_bytes;
+/* Number of valid bytes available
+ * in the buffer (including all
+ * channels: number of bytes per
+ * channel = availableBytesumChannels).
+ * Supported values: > 0
+ *
+ * This field must be equal to the frame
+ * size specified in the #AFE_PORT_AUDIO_IF_CONFIG
+ * command that was sent to configure this
+ * port.
+ */
+} __packed;
+
+#define AFE_PORT_DATA_CMD_RT_PROXY_PORT_READ_V2	0x000100EE
+
+/*  Payload of the
+ * #AFE_PORT_DATA_CMD_RT_PROXY_PORT_READ_V2 command, which
+ * delivers an empty buffer to the AFE service. On
+ * acknowledgment, data is filled in the buffer.
+ */
+struct afe_port_data_cmd_rt_proxy_port_read_v2 {
+	struct apr_hdr hdr;
+	u16                  port_id;
+/* Rx proxy port ID with which the real-time
+ * driver exchanges data.
+ * Supported values: #AFE_PORT_ID_RT_PROXY_PORT_RANGE_START to
+ * #AFE_PORT_ID_RT_PROXY_PORT_RANGE_END
+ * (This must be an Rx (speaker) port.)
+ */
+
+	u16                  reserved;
+	/* This field must be set to zero. */
+
+	u32                  buffer_address_lsw;
+/* LSW Address of the buffer containing the data sent from the AFE
+ * service to a real-time sink device on the client.
+ */
+
+
+	u32                  buffer_address_msw;
+/* MSW Address of the buffer containing the data sent from the AFE
+ * service to a real-time sink device on the client.
+ */
+
+		u32				mem_map_handle;
+/* A memory map handle encapsulating shared memory attributes is
+ * returned if AFE_SERVICE_CMD_SHARED_MEM_MAP_REGIONS command is
+ * successful.
+ * Supported Values:
+ * - Any 32 bit value
+ */
+
+	u32                  available_bytes;
+/* Number of valid bytes available in the buffer (including all
+ * channels).
+ * Supported values: > 0
+ * This field must be equal to the frame size specified in the
+ * #AFE_PORT_AUDIO_IF_CONFIG command that was sent to configure
+ * this port.
+ */
+} __packed;
+
+/* This module ID is related to device configuring like I2S,PCM,
+ * HDMI, SLIMBus etc. This module supports follwing parameter ids.
+ * - #AFE_PARAM_ID_I2S_CONFIG
+ * - #AFE_PARAM_ID_PCM_CONFIG
+ * - #AFE_PARAM_ID_DIGI_MIC_CONFIG
+ * - #AFE_PARAM_ID_HDMI_CONFIG
+ * - #AFE_PARAM_ID_INTERNAL_BT_FM_CONFIG
+ * - #AFE_PARAM_ID_SLIMBUS_CONFIG
+ * - #AFE_PARAM_ID_RT_PROXY_CONFIG
+ */
+
+#define AFE_MODULE_AUDIO_DEV_INTERFACE    0x0001020C
+#define AFE_PORT_SAMPLE_RATE_8K           8000
+#define AFE_PORT_SAMPLE_RATE_16K          16000
+#define AFE_PORT_SAMPLE_RATE_48K          48000
+#define AFE_PORT_SAMPLE_RATE_96K          96000
+#define AFE_PORT_SAMPLE_RATE_192K         192000
+#define AFE_LINEAR_PCM_DATA				0x0
+#define AFE_NON_LINEAR_DATA				0x1
+#define AFE_LINEAR_PCM_DATA_PACKED_60958 0x2
+#define AFE_NON_LINEAR_DATA_PACKED_60958 0x3
+
+/* This param id is used to configure I2S interface */
+#define AFE_PARAM_ID_I2S_CONFIG	0x0001020D
+#define AFE_API_VERSION_I2S_CONFIG	0x1
+/*	Enumeration for setting the I2S configuration
+ * channel_mode parameter to
+ * serial data wire number 1-3 (SD3).
+ */
+#define AFE_PORT_I2S_SD0                     0x1
+#define AFE_PORT_I2S_SD1                     0x2
+#define AFE_PORT_I2S_SD2                     0x3
+#define AFE_PORT_I2S_SD3                     0x4
+#define AFE_PORT_I2S_QUAD01                  0x5
+#define AFE_PORT_I2S_QUAD23                  0x6
+#define AFE_PORT_I2S_6CHS                    0x7
+#define AFE_PORT_I2S_8CHS                    0x8
+#define AFE_PORT_I2S_MONO                    0x0
+#define AFE_PORT_I2S_STEREO                  0x1
+#define AFE_PORT_CONFIG_I2S_WS_SRC_EXTERNAL  0x0
+#define AFE_PORT_CONFIG_I2S_WS_SRC_INTERNAL  0x1
+
+/*  Payload of the #AFE_PARAM_ID_I2S_CONFIG
+ * command's (I2S configuration
+ * parameter).
+ */
+struct afe_param_id_i2s_cfg {
+	u32                  i2s_cfg_minor_version;
+/* Minor version used for tracking the version of the I2S
+ * configuration interface.
+ * Supported values: #AFE_API_VERSION_I2S_CONFIG
+ */
+
+	u16                  bit_width;
+/* Bit width of the sample.
+ * Supported values: 16, 24
+ */
+
+	u16                  channel_mode;
+/* I2S lines and multichannel operation.
+ * Supported values:
+ * - #AFE_PORT_I2S_SD0
+ * - #AFE_PORT_I2S_SD1
+ * - #AFE_PORT_I2S_SD2
+ * - #AFE_PORT_I2S_SD3
+ * - #AFE_PORT_I2S_QUAD01
+ * - #AFE_PORT_I2S_QUAD23
+ * - #AFE_PORT_I2S_6CHS
+ * - #AFE_PORT_I2S_8CHS
+ */
+
+	u16                  mono_stereo;
+/* Specifies mono or stereo. This applies only when
+ * a single I2S line is used.
+ * Supported values:
+ * - #AFE_PORT_I2S_MONO
+ * - #AFE_PORT_I2S_STEREO
+ */
+
+	u16                  ws_src;
+/* Word select source: internal or external.
+ * Supported values:
+ * - #AFE_PORT_CONFIG_I2S_WS_SRC_EXTERNAL
+ * - #AFE_PORT_CONFIG_I2S_WS_SRC_INTERNAL
+ */
+
+	u32                  sample_rate;
+/* Sampling rate of the port.
+ * Supported values:
+ * - #AFE_PORT_SAMPLE_RATE_8K
+ * - #AFE_PORT_SAMPLE_RATE_16K
+ * - #AFE_PORT_SAMPLE_RATE_48K
+ * - #AFE_PORT_SAMPLE_RATE_96K
+ * - #AFE_PORT_SAMPLE_RATE_192K
+ */
+
+	u16					data_format;
+/* data format
+ * Supported values:
+ * - #LINEAR_PCM_DATA
+ * - #NON_LINEAR_DATA
+ * - #LINEAR_PCM_DATA_PACKED_IN_60958
+ * - #NON_LINEAR_DATA_PACKED_IN_60958
+ */
+		u16                  reserved;
+	/* This field must be set to zero. */
+} __packed;
+
+/*
+ * This param id is used to configure PCM interface
+ */
+#define AFE_PARAM_ID_PCM_CONFIG        0x0001020E
+#define AFE_API_VERSION_PCM_CONFIG	0x1
+/* Enumeration for the auxiliary PCM synchronization signal
+ * provided by an external source.
+ */
+
+#define AFE_PORT_PCM_SYNC_SRC_EXTERNAL 0x0
+/*	Enumeration for the auxiliary PCM synchronization signal
+ * provided by an internal source.
+ */
+#define AFE_PORT_PCM_SYNC_SRC_INTERNAL  0x1
+/*	Enumeration for the PCM configuration aux_mode parameter,
+ * which configures the auxiliary PCM interface to use
+ * short synchronization.
+ */
+#define AFE_PORT_PCM_AUX_MODE_PCM  0x0
+/*
+ * Enumeration for the PCM configuration aux_mode parameter,
+ * which configures the auxiliary PCM interface to use long
+ * synchronization.
+ */
+#define AFE_PORT_PCM_AUX_MODE_AUX    0x1
+/*
+ * Enumeration for setting the PCM configuration frame to 8.
+ */
+#define AFE_PORT_PCM_BITS_PER_FRAME_8  0x0
+/*
+ * Enumeration for setting the PCM configuration frame to 16.
+ */
+#define AFE_PORT_PCM_BITS_PER_FRAME_16   0x1
+
+/*	Enumeration for setting the PCM configuration frame to 32.*/
+#define AFE_PORT_PCM_BITS_PER_FRAME_32 0x2
+
+/*	Enumeration for setting the PCM configuration frame to 64.*/
+#define AFE_PORT_PCM_BITS_PER_FRAME_64   0x3
+
+/*	Enumeration for setting the PCM configuration frame to 128.*/
+#define AFE_PORT_PCM_BITS_PER_FRAME_128 0x4
+
+/*	Enumeration for setting the PCM configuration frame to 256.*/
+#define AFE_PORT_PCM_BITS_PER_FRAME_256 0x5
+
+/*	Enumeration for setting the PCM configuration
+ * quantype parameter to A-law with no padding.
+ */
+#define AFE_PORT_PCM_ALAW_NOPADDING 0x0
+
+/* Enumeration for setting the PCM configuration quantype
+ * parameter to mu-law with no padding.
+ */
+#define AFE_PORT_PCM_MULAW_NOPADDING 0x1
+/*	Enumeration for setting the PCM configuration quantype
+ * parameter to linear with no padding.
+ */
+#define AFE_PORT_PCM_LINEAR_NOPADDING 0x2
+/*	Enumeration for setting the PCM configuration quantype
+ * parameter to A-law with padding.
+ */
+#define AFE_PORT_PCM_ALAW_PADDING  0x3
+/*	Enumeration for setting the PCM configuration quantype
+ * parameter to mu-law with padding.
+ */
+#define AFE_PORT_PCM_MULAW_PADDING 0x4
+/*	Enumeration for setting the PCM configuration quantype
+ * parameter to linear with padding.
+ */
+#define AFE_PORT_PCM_LINEAR_PADDING 0x5
+/*	Enumeration for disabling the PCM configuration
+ * ctrl_data_out_enable parameter.
+ * The PCM block is the only master.
+ */
+#define AFE_PORT_PCM_CTRL_DATA_OE_DISABLE 0x0
+/*
+ * Enumeration for enabling the PCM configuration
+ * ctrl_data_out_enable parameter. The PCM block shares
+ * the signal with other masters.
+ */
+#define AFE_PORT_PCM_CTRL_DATA_OE_ENABLE  0x1
+
+/*  Payload of the #AFE_PARAM_ID_PCM_CONFIG command's
+ * (PCM configuration parameter).
+ */
+
+struct afe_param_id_pcm_cfg {
+	u32                  pcm_cfg_minor_version;
+/* Minor version used for tracking the version of the AUX PCM
+ * configuration interface.
+ * Supported values: #AFE_API_VERSION_PCM_CONFIG
+ */
+
+	u16                  aux_mode;
+/* PCM synchronization setting.
+ * Supported values:
+ * - #AFE_PORT_PCM_AUX_MODE_PCM
+ * - #AFE_PORT_PCM_AUX_MODE_AUX
+ */
+
+	u16                  sync_src;
+/* Synchronization source.
+ * Supported values:
+ * - #AFE_PORT_PCM_SYNC_SRC_EXTERNAL
+ * - #AFE_PORT_PCM_SYNC_SRC_INTERNAL
+ */
+
+	u16                  frame_setting;
+/* Number of bits per frame.
+ * Supported values:
+ * - #AFE_PORT_PCM_BITS_PER_FRAME_8
+ * - #AFE_PORT_PCM_BITS_PER_FRAME_16
+ * - #AFE_PORT_PCM_BITS_PER_FRAME_32
+ * - #AFE_PORT_PCM_BITS_PER_FRAME_64
+ * - #AFE_PORT_PCM_BITS_PER_FRAME_128
+ * - #AFE_PORT_PCM_BITS_PER_FRAME_256
+ */
+
+	u16                  quantype;
+/* PCM quantization type.
+ * Supported values:
+ * - #AFE_PORT_PCM_ALAW_NOPADDING
+ * - #AFE_PORT_PCM_MULAW_NOPADDING
+ * - #AFE_PORT_PCM_LINEAR_NOPADDING
+ * - #AFE_PORT_PCM_ALAW_PADDING
+ * - #AFE_PORT_PCM_MULAW_PADDING
+ * - #AFE_PORT_PCM_LINEAR_PADDING
+ */
+
+	u16                  ctrl_data_out_enable;
+/* Specifies whether the PCM block shares the data-out
+ * signal to the drive with other masters.
+ * Supported values:
+ * - #AFE_PORT_PCM_CTRL_DATA_OE_DISABLE
+ * - #AFE_PORT_PCM_CTRL_DATA_OE_ENABLE
+ */
+		u16                  reserved;
+	/* This field must be set to zero. */
+
+	u32                  sample_rate;
+/* Sampling rate of the port.
+ * Supported values:
+ * - #AFE_PORT_SAMPLE_RATE_8K
+ * - #AFE_PORT_SAMPLE_RATE_16K
+ */
+
+	u16                  bit_width;
+/* Bit width of the sample.
+ * Supported values: 16
+ */
+
+	u16                  num_channels;
+/* Number of channels.
+ * Supported values: 1 to 4
+ */
+
+	u16                  slot_number_mapping[4];
+/* Specifies the slot number for the each channel in
+ * multi channel scenario.
+ * Supported values: 1 to 32
+ */
+} __packed;
+
+/*
+ * This param id is used to configure DIGI MIC interface
+ */
+#define AFE_PARAM_ID_DIGI_MIC_CONFIG	0x0001020F
+/*  This version information is used to handle the new
+ *   additions to the config interface in future in backward
+ *   compatible manner.
+ */
+#define AFE_API_VERSION_DIGI_MIC_CONFIG 0x1
+
+/* Enumeration for setting the digital mic configuration
+ * channel_mode parameter to left 0.
+ */
+
+#define AFE_PORT_DIGI_MIC_MODE_LEFT0  0x1
+
+/*Enumeration for setting the digital mic configuration
+ * channel_mode parameter to right 0.
+ */
+
+
+#define AFE_PORT_DIGI_MIC_MODE_RIGHT0  0x2
+
+/* Enumeration for setting the digital mic configuration
+ * channel_mode parameter to left 1.
+ */
+
+#define AFE_PORT_DIGI_MIC_MODE_LEFT1  0x3
+
+/* Enumeration for setting the digital mic configuration
+ * channel_mode parameter to right 1.
+ */
+
+#define AFE_PORT_DIGI_MIC_MODE_RIGHT1 0x4
+
+/* Enumeration for setting the digital mic configuration
+ * channel_mode parameter to stereo 0.
+ */
+#define AFE_PORT_DIGI_MIC_MODE_STEREO0  0x5
+
+/* Enumeration for setting the digital mic configuration
+ * channel_mode parameter to stereo 1.
+ */
+
+
+#define AFE_PORT_DIGI_MIC_MODE_STEREO1    0x6
+
+/* Enumeration for setting the digital mic configuration
+ * channel_mode parameter to quad.
+ */
+
+#define AFE_PORT_DIGI_MIC_MODE_QUAD     0x7
+
+/*  Payload of the #AFE_PARAM_ID_DIGI_MIC_CONFIG command's
+ * (DIGI MIC configuration
+ * parameter).
+ */
+struct afe_param_id_digi_mic_cfg {
+	u32                  digi_mic_cfg_minor_version;
+/* Minor version used for tracking the version of the DIGI Mic
+ * configuration interface.
+ * Supported values: #AFE_API_VERSION_DIGI_MIC_CONFIG
+ */
+
+	u16                  bit_width;
+/* Bit width of the sample.
+ * Supported values: 16
+ */
+
+	u16                  channel_mode;
+/* Digital mic and multichannel operation.
+ * Supported values:
+ * - #AFE_PORT_DIGI_MIC_MODE_LEFT0
+ * - #AFE_PORT_DIGI_MIC_MODE_RIGHT0
+ * - #AFE_PORT_DIGI_MIC_MODE_LEFT1
+ * - #AFE_PORT_DIGI_MIC_MODE_RIGHT1
+ * - #AFE_PORT_DIGI_MIC_MODE_STEREO0
+ * - #AFE_PORT_DIGI_MIC_MODE_STEREO1
+ * - #AFE_PORT_DIGI_MIC_MODE_QUAD
+ */
+
+	u32                  sample_rate;
+/* Sampling rate of the port.
+ * Supported values:
+ * - #AFE_PORT_SAMPLE_RATE_8K
+ * - #AFE_PORT_SAMPLE_RATE_16K
+ * - #AFE_PORT_SAMPLE_RATE_48K
+ */
+} __packed;
+
+/*
+* This param id is used to configure HDMI interface
+*/
+#define AFE_PARAM_ID_HDMI_CONFIG     0x00010210
+
+/*  This version information is used to handle the new
+*   additions to the config interface in future in backward
+*   compatible manner.
+*/
+#define AFE_API_VERSION_HDMI_CONFIG 0x1
+
+/* Payload of the #AFE_PARAM_ID_HDMI_CONFIG command,
+ * which configures a multichannel HDMI audio interface.
+ */
+struct afe_param_id_hdmi_multi_chan_audio_cfg {
+	u32                  hdmi_cfg_minor_version;
+/* Minor version used for tracking the version of the HDMI
+ * configuration interface.
+ * Supported values: #AFE_API_VERSION_HDMI_CONFIG
+ */
+
+u16                  dataype;
+/* data type
+ * Supported values:
+ * - #LINEAR_PCM_DATA
+ * - #NON_LINEAR_DATA
+ * - #LINEAR_PCM_DATA_PACKED_IN_60958
+ * - #NON_LINEAR_DATA_PACKED_IN_60958
+ */
+
+u16                  channel_allocation;
+/* HDMI channel allocation information for programming an HDMI
+ * frame. The default is 0 (Stereo).
+ *
+ * This information is defined in the HDMI standard, CEA 861-D
+ * (refer to @xhyperref{S1,[S1]}). The number of channels is also
+ * inferred from this parameter.
+*/
+
+
+u32                  sample_rate;
+/* Sampling rate of the port.
+ * Supported values:
+ * - #AFE_PORT_SAMPLE_RATE_8K
+ * - #AFE_PORT_SAMPLE_RATE_16K
+ * - #AFE_PORT_SAMPLE_RATE_48K
+ * - #AFE_PORT_SAMPLE_RATE_96K
+ * - 22050, 44100, 176400 for compressed streams
+ */
+
+	u16                  bit_width;
+/* Bit width of the sample.
+ * Supported values: 16, 24
+ */
+		u16                  reserved;
+	/* This field must be set to zero. */
+} __packed;
+
+/*
+* This param id is used to configure BT or FM(RIVA) interface
+*/
+#define AFE_PARAM_ID_INTERNAL_BT_FM_CONFIG  0x00010211
+
+/*  This version information is used to handle the new
+*   additions to the config interface in future in backward
+*   compatible manner.
+*/
+#define AFE_API_VERSION_INTERNAL_BT_FM_CONFIG	0x1
+
+/*  Payload of the #AFE_PARAM_ID_INTERNAL_BT_FM_CONFIG
+ * command's BT voice/BT audio/FM configuration parameter.
+ */
+struct afe_param_id_internal_bt_fm_cfg {
+	u32                  bt_fm_cfg_minor_version;
+/* Minor version used for tracking the version of the BT and FM
+ * configuration interface.
+ * Supported values: #AFE_API_VERSION_INTERNAL_BT_FM_CONFIG
+ */
+
+	u16                  num_channels;
+/* Number of channels.
+ * Supported values: 1 to 2
+ */
+
+	u16                  bit_width;
+/* Bit width of the sample.
+ * Supported values: 16
+ */
+
+	u32                  sample_rate;
+/* Sampling rate of the port.
+ * Supported values:
+ * - #AFE_PORT_SAMPLE_RATE_8K (only for BTSCO)
+ * - #AFE_PORT_SAMPLE_RATE_16K (only for BTSCO)
+ * - #AFE_PORT_SAMPLE_RATE_48K (FM and A2DP)
+ */
+} __packed;
+
+/* This param id is used to configure SLIMBUS interface using
+ * shared channel approach.
+ */
+
+
+#define AFE_PARAM_ID_SLIMBUS_CONFIG    0x00010212
+
+/*  This version information is used to handle the new
+*   additions to the config interface in future in backward
+*   compatible manner.
+*/
+#define AFE_API_VERSION_SLIMBUS_CONFIG 0x1
+
+/*	Enumeration for setting SLIMbus device ID 1.
+*/
+#define AFE_SLIMBUS_DEVICE_1           0x0
+
+/*	Enumeration for setting SLIMbus device ID 2.
+*/
+#define AFE_SLIMBUS_DEVICE_2          0x1
+
+/*	Enumeration for setting the SLIMbus data formats.
+*/
+#define AFE_SB_DATA_FORMAT_NOT_INDICATED 0x0
+
+/* Enumeration for setting the maximum number of streams per
+ * device.
+ */
+
+#define AFE_PORT_MAX_AUDIO_CHAN_CNT	0x8
+
+/* Payload of the #AFE_PORT_CMD_SLIMBUS_CONFIG command's SLIMbus
+ * port configuration parameter.
+ */
+
+struct afe_param_id_slimbus_cfg {
+	u32                  sb_cfg_minor_version;
+/* Minor version used for tracking the version of the SLIMBUS
+ * configuration interface.
+ * Supported values: #AFE_API_VERSION_SLIMBUS_CONFIG
+ */
+
+	u16                  slimbus_dev_id;
+/* SLIMbus hardware device ID, which is required to handle
+ * multiple SLIMbus hardware blocks.
+ * Supported values: - #AFE_SLIMBUS_DEVICE_1 - #AFE_SLIMBUS_DEVICE_2
+ */
+
+
+	u16                  bit_width;
+/* Bit width of the sample.
+ * Supported values: 16, 24
+ */
+
+	u16                  data_format;
+/* Data format supported by the SLIMbus hardware. The default is
+ * 0 (#AFE_SB_DATA_FORMAT_NOT_INDICATED), which indicates the
+ * hardware does not perform any format conversions before the data
+ * transfer.
+ */
+
+
+	u16                  num_channels;
+/* Number of channels.
+ * Supported values: 1 to #AFE_PORT_MAX_AUDIO_CHAN_CNT
+ */
+
+	u8  shared_ch_mapping[AFE_PORT_MAX_AUDIO_CHAN_CNT];
+/* Mapping of shared channel IDs (128 to 255) to which the
+ * master port is to be connected.
+ * Shared_channel_mapping[i] represents the shared channel assigned
+ * for audio channel i in multichannel audio data.
+ */
+
+	u32              sample_rate;
+/* Sampling rate of the port.
+ * Supported values:
+ * - #AFE_PORT_SAMPLE_RATE_8K
+ * - #AFE_PORT_SAMPLE_RATE_16K
+ * - #AFE_PORT_SAMPLE_RATE_48K
+ * - #AFE_PORT_SAMPLE_RATE_96K
+ * - #AFE_PORT_SAMPLE_RATE_192K
+ */
+} __packed;
+
+/*
+* This param id is used to configure Real Time Proxy interface.
+*/
+#define AFE_PARAM_ID_RT_PROXY_CONFIG 0x00010213
+
+/*  This version information is used to handle the new
+*   additions to the config interface in future in backward
+*   compatible manner.
+*/
+#define AFE_API_VERSION_RT_PROXY_CONFIG 0x1
+
+/*  Payload of the #AFE_PARAM_ID_RT_PROXY_CONFIG
+ * command (real-time proxy port configuration parameter).
+ */
+struct afe_param_id_rt_proxy_port_cfg {
+	u32                  rt_proxy_cfg_minor_version;
+/* Minor version used for tracking the version of rt-proxy
+ * config interface.
+ */
+
+	u16                  bit_width;
+/* Bit width of the sample.
+ * Supported values: 16
+ */
+
+	u16                  interleaved;
+/* Specifies whether the data exchanged between the AFE
+ * interface and real-time port is interleaved.
+ * Supported values: - 0 -- Non-interleaved (samples from each
+ * channel are contiguous in the buffer) - 1 -- Interleaved
+ * (corresponding samples from each input channel are interleaved
+ * within the buffer)
+ */
+
+
+	u16                  frame_size;
+ /* Size of the frames that are used for PCM exchanges with this
+ * port.
+ * Supported values: > 0, in bytes
+ * For example, 5 ms buffers of 16 bits and 16 kHz stereo samples
+ * is 5 ms * 16 samples/ms * 2 bytes/sample * 2 channels = 320
+ * bytes.
+ */
+	u16                  jitter_allowance;
+/* Configures the amount of jitter that the port will allow.
+ * Supported values: > 0
+ * For example, if +/-10 ms of jitter is anticipated in the timing
+ * of sending frames to the port, and the configuration is 16 kHz
+ * mono with 16-bit samples, this field is 10 ms * 16 samples/ms * 2
+ * bytes/sample = 320.
+ */
+
+	u16                  low_water_mark;
+/* Low watermark in bytes (including all channels).
+ * Supported values:
+ * - 0 -- Do not send any low watermark events
+ * - > 0 -- Low watermark for triggering an event
+ * If the number of bytes in an internal circular buffer is lower
+ * than this low_water_mark parameter, a LOW_WATER_MARK event is
+ * sent to applications (via the #AFE_EVENT_RT_PROXY_PORT_STATUS
+ * event).
+ * Use of watermark events is optional for debugging purposes.
+ */
+
+	u16                  high_water_mark;
+/* High watermark in bytes (including all channels).
+ * Supported values:
+ * - 0 -- Do not send any high watermark events
+ * - > 0 -- High watermark for triggering an event
+ * If the number of bytes in an internal circular buffer exceeds
+ * TOTAL_CIRC_BUF_SIZE minus high_water_mark, a high watermark event
+ * is sent to applications (via the #AFE_EVENT_RT_PROXY_PORT_STATUS
+ * event).
+ * The use of watermark events is optional and for debugging
+ * purposes.
+ */
+
+
+	u32					sample_rate;
+/* Sampling rate of the port.
+ * Supported values:
+ * - #AFE_PORT_SAMPLE_RATE_8K
+ * - #AFE_PORT_SAMPLE_RATE_16K
+ * - #AFE_PORT_SAMPLE_RATE_48K
+ */
+
+	u16                  num_channels;
+/* Number of channels.
+ * Supported values: 1 to #AFE_PORT_MAX_AUDIO_CHAN_CNT
+ */
+
+	u16                  reserved;
+	/* For 32 bit alignment. */
+} __packed;
+
+union afe_port_config {
+	struct afe_param_id_pcm_cfg               pcm;
+	struct afe_param_id_i2s_cfg               i2s;
+	struct afe_param_id_hdmi_multi_chan_audio_cfg hdmi_multi_ch;
+	struct afe_param_id_slimbus_cfg           slim_sch;
+	struct afe_param_id_rt_proxy_port_cfg     rtproxy;
+} __packed;
+
+struct afe_audioif_config_command {
+	struct apr_hdr			hdr;
+	struct afe_port_cmd_set_param_v2 param;
+	struct afe_port_param_data_v2    pdata;
+	union afe_port_config            port;
+} __packed;
+
+#define AFE_PORT_CMD_DEVICE_START 0x000100E5
+
+/*  Payload of the #AFE_PORT_CMD_DEVICE_START.*/
+struct afe_port_cmd_device_start {
+	struct apr_hdr hdr;
+	u16                  port_id;
+/* Port interface and direction (Rx or Tx) to start. An even
+ * number represents the Rx direction, and an odd number represents
+ * the Tx direction.
+ */
+
+
+	u16                  reserved;
+/* Reserved for 32-bit alignment. This field must be set to 0.*/
+
+} __packed;
+
+#define AFE_PORT_CMD_DEVICE_STOP  0x000100E6
+
+/*  Payload of the #AFE_PORT_CMD_DEVICE_STOP.
+*/
+struct afe_port_cmd_device_stop {
+	struct apr_hdr hdr;
+	u16                  port_id;
+/* Port interface and direction (Rx or Tx) to start. An even
+ * number represents the Rx direction, and an odd number represents
+ * the Tx direction.
+ */
+
+	u16                  reserved;
+/* Reserved for 32-bit alignment. This field must be set to 0.*/
+} __packed;
+
+#define AFE_SERVICE_CMD_SHARED_MEM_MAP_REGIONS 0x000100EA
+
+/*  Memory map regions command payload used by the
+ * #AFE_SERVICE_CMD_SHARED_MEM_MAP_REGIONS .
+ * This structure allows clients to map multiple shared memory
+ * regions in a single command. Following this structure are
+ * num_regions of afe_service_shared_map_region_payload.
+ */
+struct afe_service_cmd_shared_mem_map_regions {
+	struct apr_hdr hdr;
+u16                  mem_pool_id;
+/* Type of memory on which this memory region is mapped.
+ * Supported values:
+ * - #ADSP_MEMORY_MAP_EBI_POOL
+ * - #ADSP_MEMORY_MAP_SMI_POOL
+ * - #ADSP_MEMORY_MAP_SHMEM8_4K_POOL
+ * - Other values are reserved
+ *
+ * The memory pool ID implicitly defines the characteristics of the
+ * memory. Characteristics may include alignment type, permissions,
+ * etc.
+ *
+ * ADSP_MEMORY_MAP_EBI_POOL is External Buffer Interface type memory
+ * ADSP_MEMORY_MAP_SMI_POOL is Shared Memory Interface type memory
+ * ADSP_MEMORY_MAP_SHMEM8_4K_POOL is shared memory, byte
+ * addressable, and 4 KB aligned.
+ */
+
+
+	u16                  num_regions;
+/* Number of regions to map.
+ * Supported values:
+ * - Any value greater than zero
+ */
+
+	u32                  property_flag;
+/* Configures one common property for all the regions in the
+ * payload.
+ *
+ * Supported values: - 0x00000000 to 0x00000001
+ *
+ * b0 - bit 0 indicates physical or virtual mapping 0 Shared memory
+ * address provided in afe_service_shared_map_region_payloadis a
+ * physical address. The shared memory needs to be mapped( hardware
+ * TLB entry) and a software entry needs to be added for internal
+ * book keeping.
+ *
+ * 1 Shared memory address provided in
+ * afe_service_shared_map_region_payloadis a virtual address. The
+ * shared memory must not be mapped (since hardware TLB entry is
+ * already available) but a software entry needs to be added for
+ * internal book keeping. This can be useful if two services with in
+ * ADSP is communicating via APR. They can now directly communicate
+ * via the Virtual address instead of Physical address. The virtual
+ * regions must be contiguous. num_regions must be 1 in this case.
+ *
+ * b31-b1 - reserved bits. must be set to zero
+ */
+
+
+} __packed;
+/*  Map region payload used by the
+ * afe_service_shared_map_region_payloadstructure.
+ */
+struct afe_service_shared_map_region_payload {
+	u32                  shm_addr_lsw;
+/* least significant word of starting address in the memory
+ * region to map. It must be contiguous memory, and it must be 4 KB
+ * aligned.
+ * Supported values: - Any 32 bit value
+ */
+
+
+	u32                  shm_addr_msw;
+/* most significant word of startng address in the memory region
+ * to map. For 32 bit shared memory address, this field must be set
+ * to zero. For 36 bit shared memory address, bit31 to bit 4 must be
+ * set to zero
+ *
+ * Supported values: - For 32 bit shared memory address, this field
+ * must be set to zero. - For 36 bit shared memory address, bit31 to
+ * bit 4 must be set to zero - For 64 bit shared memory address, any
+ * 32 bit value
+ */
+
+
+	u32                  mem_size_bytes;
+/* Number of bytes in the region. The aDSP will always map the
+ * regions as virtual contiguous memory, but the memory size must be
+ * in multiples of 4 KB to avoid gaps in the virtually contiguous
+ * mapped memory.
+ *
+ * Supported values: - multiples of 4KB
+ */
+
+} __packed;
+
+#define AFE_SERVICE_CMDRSP_SHARED_MEM_MAP_REGIONS 0x000100EB
+struct afe_service_cmdrsp_shared_mem_map_regions {
+	u32                  mem_map_handle;
+/* A memory map handle encapsulating shared memory attributes is
+ * returned iff AFE_SERVICE_CMD_SHARED_MEM_MAP_REGIONS command is
+ * successful. In the case of failure , a generic APR error response
+ * is returned to the client.
+ *
+ * Supported Values: - Any 32 bit value
+ */
+
+} __packed;
+#define AFE_SERVICE_CMD_SHARED_MEM_UNMAP_REGIONS 0x000100EC
+/* Memory unmap regions command payload used by the
+ * #AFE_SERVICE_CMD_SHARED_MEM_UNMAP_REGIONS
+ *
+ * This structure allows clients to unmap multiple shared memory
+ * regions in a single command.
+ */
+
+
+struct afe_service_cmd_shared_mem_unmap_regions {
+	struct apr_hdr hdr;
+u32                  mem_map_handle;
+/* memory map handle returned by
+ * AFE_SERVICE_CMD_SHARED_MEM_MAP_REGIONS commands
+ *
+ * Supported Values:
+ * - Any 32 bit value
+ */
+} __packed;
+
+#define  AFE_PORT_CMD_GET_PARAM_V2 0x000100F0
+
+/*  Payload of the #AFE_PORT_CMD_GET_PARAM_V2 command,
+ * which queries for one post/preprocessing parameter of a
+ * stream.
+ */
+struct afe_port_cmd_get_param_v2 {
+
+	struct apr_hdr hdr;
+u16                  port_id;
+/* Port interface and direction (Rx or Tx) to start. */
+
+	u16                  payload_size;
+/* Maximum data size of the parameter ID/module ID combination.
+ * This is a multiple of four bytes
+ * Supported values: > 0
+ */
+
+	u32 payload_address_lsw;
+/* LSW of 64 bit Payload address. Address should be 32-byte,
+ * 4kbyte aligned and must be contig memory.
+ */
+
+
+	u32 payload_address_msw;
+/* MSW of 64 bit Payload address. In case of 32-bit shared
+ * memory address, this field must be set to zero. In case of 36-bit
+ * shared memory address, bit-4 to bit-31 must be set to zero.
+ * Address should be 32-byte, 4kbyte aligned and must be contiguous
+ * memory.
+ */
+
+	u32 mem_map_handle;
+/* Memory map handle returned by
+ * AFE_SERVICE_CMD_SHARED_MEM_MAP_REGIONS commands.
+ * Supported Values: - NULL -- Message. The parameter data is
+ * in-band. - Non-NULL -- The parameter data is Out-band.Pointer to
+ * - the physical address in shared memory of the payload data.
+ * For detailed payload content, see the afe_port_param_data_v2
+ * structure
+ */
+
+
+	u32                  module_id;
+/* ID of the module to be queried.
+ * Supported values: Valid module ID
+ */
+
+	u32                  param_id;
+/* ID of the parameter to be queried.
+ * Supported values: Valid parameter ID
+ */
+} __packed;
+
+#define AFE_PORT_CMDRSP_GET_PARAM_V2 0x00010106
+
+/* Payload of the #AFE_PORT_CMDRSP_GET_PARAM_V2 message, which
+ * responds to an #AFE_PORT_CMD_GET_PARAM_V2 command.
+ *
+ * Immediately following this structure is the parameters structure
+ * (afe_port_param_data) containing the response(acknowledgment)
+ * parameter payload. This payload is included for an in-band
+ * scenario. For an address/shared memory-based set parameter, this
+ * payload is not needed.
+ */
+
+
+struct afe_port_cmdrsp_get_param_v2 {
+	u32                  status;
+} __packed;
+
+/* adsp_afe_service_commands.h */
+
+#define ADSP_MEMORY_MAP_EBI_POOL      0
+
+#define ADSP_MEMORY_MAP_SMI_POOL      1
+#define ADSP_MEMORY_MAP_IMEM_POOL      2
+#define ADSP_MEMORY_MAP_SHMEM8_4K_POOL      3
+/*
+* Definition of virtual memory flag
+*/
+#define ADSP_MEMORY_MAP_VIRTUAL_MEMORY 1
+
+/*
+* Definition of physical memory flag
+*/
+#define ADSP_MEMORY_MAP_PHYSICAL_MEMORY 0
+
+
+#define DEFAULT_COPP_TOPOLOGY				0x00010be3
+#define DEFAULT_POPP_TOPOLOGY				0x00010be4
+#define VPM_TX_SM_ECNS_COPP_TOPOLOGY			0x00010F71
+#define VPM_TX_DM_FLUENCE_COPP_TOPOLOGY			0x00010F72
+#define VPM_TX_QMIC_FLUENCE_COPP_TOPOLOGY		0x00010F75
+
+/* Memory map regions command payload used by the
+ * #ASM_CMD_SHARED_MEM_MAP_REGIONS ,#ADM_CMD_SHARED_MEM_MAP_REGIONS
+ * commands.
+ *
+ * This structure allows clients to map multiple shared memory
+ * regions in a single command. Following this structure are
+ * num_regions of avs_shared_map_region_payload.
+ */
+
+
+struct avs_cmd_shared_mem_map_regions {
+	struct apr_hdr hdr;
+	u16                  mem_pool_id;
+/* Type of memory on which this memory region is mapped.
+ *
+ * Supported values: - #ADSP_MEMORY_MAP_EBI_POOL -
+ * #ADSP_MEMORY_MAP_SMI_POOL - #ADSP_MEMORY_MAP_IMEM_POOL
+ * (unsupported) - #ADSP_MEMORY_MAP_SHMEM8_4K_POOL - Other values
+ * are reserved
+ *
+ * The memory ID implicitly defines the characteristics of the
+ * memory. Characteristics may include alignment type, permissions,
+ * etc.
+ *
+ * SHMEM8_4K is shared memory, byte addressable, and 4 KB aligned.
+ */
+
+
+	u16                  num_regions;
+	/* Number of regions to map.*/
+
+	u32                  property_flag;
+/* Configures one common property for all the regions in the
+ * payload. No two regions in the same memory map regions cmd can
+ * have differnt property. Supported values: - 0x00000000 to
+ * 0x00000001
+ *
+ * b0 - bit 0 indicates physical or virtual mapping 0 shared memory
+ * address provided in avs_shared_map_regions_payload is physical
+ * address. The shared memory needs to be mapped( hardware TLB
+ * entry)
+ *
+ * and a software entry needs to be added for internal book keeping.
+ *
+ * 1 Shared memory address provided in MayPayload[usRegions] is
+ * virtual address. The shared memory must not be mapped (since
+ * hardware TLB entry is already available) but a software entry
+ * needs to be added for internal book keeping. This can be useful
+ * if two services with in ADSP is communicating via APR. They can
+ * now directly communicate via the Virtual address instead of
+ * Physical address. The virtual regions must be contiguous.
+ *
+ * b31-b1 - reserved bits. must be set to zero
+ */
+
+} __packed;
+
+struct avs_shared_map_region_payload {
+	u32                  shm_addr_lsw;
+/* least significant word of shared memory address of the memory
+ * region to map. It must be contiguous memory, and it must be 4 KB
+ * aligned.
+ */
+
+	u32                  shm_addr_msw;
+/* most significant word of shared memory address of the memory
+ * region to map. For 32 bit shared memory address, this field must
+ * tbe set to zero. For 36 bit shared memory address, bit31 to bit 4
+ * must be set to zero
+ */
+
+	u32                  mem_size_bytes;
+/* Number of bytes in the region.
+ *
+ * The aDSP will always map the regions as virtual contiguous
+ * memory, but the memory size must be in multiples of 4 KB to avoid
+ * gaps in the virtually contiguous mapped memory.
+ */
+
+} __packed;
+
+struct avs_cmd_shared_mem_unmap_regions {
+	struct apr_hdr       hdr;
+	u32                  mem_map_handle;
+/* memory map handle returned by ASM_CMD_SHARED_MEM_MAP_REGIONS
+ * , ADM_CMD_SHARED_MEM_MAP_REGIONS, commands
+ */
+
+} __packed;
+
+/* Memory map command response payload used by the
+ * #ASM_CMDRSP_SHARED_MEM_MAP_REGIONS
+ * ,#ADM_CMDRSP_SHARED_MEM_MAP_REGIONS
+ */
+
+
+struct avs_cmdrsp_shared_mem_map_regions {
+	u32                  mem_map_handle;
+/* A memory map handle encapsulating shared memory attributes is
+ * returned
+ */
+
+} __packed;
+
+/*adsp_audio_memmap_api.h*/
+
+/* ASM related data structures */
+struct asm_wma_cfg {
+	u16 format_tag;
+	u16 ch_cfg;
+	u32 sample_rate;
+	u32 avg_bytes_per_sec;
+	u16 block_align;
+	u16 valid_bits_per_sample;
+	u32 ch_mask;
+	u16 encode_opt;
+	u16 adv_encode_opt;
+	u32 adv_encode_opt2;
+	u32 drc_peak_ref;
+	u32 drc_peak_target;
+	u32 drc_ave_ref;
+	u32 drc_ave_target;
+} __packed;
+
+struct asm_wmapro_cfg {
+	u16 format_tag;
+	u16 ch_cfg;
+	u32 sample_rate;
+	u32 avg_bytes_per_sec;
+	u16 block_align;
+	u16 valid_bits_per_sample;
+	u32 ch_mask;
+	u16 encode_opt;
+	u16 adv_encode_opt;
+	u32 adv_encode_opt2;
+	u32 drc_peak_ref;
+	u32 drc_peak_target;
+	u32 drc_ave_ref;
+	u32 drc_ave_target;
+} __packed;
+
+struct asm_aac_cfg {
+	u16 format;
+	u16 aot;
+	u16 ep_config;
+	u16 section_data_resilience;
+	u16 scalefactor_data_resilience;
+	u16 spectral_data_resilience;
+	u16 ch_cfg;
+	u16 reserved;
+	u32 sample_rate;
+} __packed;
+
+struct asm_softpause_params {
+	u32 enable;
+	u32 period;
+	u32 step;
+	u32 rampingcurve;
+} __packed;
+
+struct asm_softvolume_params {
+	u32 period;
+	u32 step;
+	u32 rampingcurve;
+} __packed;
+
+#define ASM_END_POINT_DEVICE_MATRIX     0
+/* Front left channel. */
+#define PCM_CHANNEL_FL    1
+
+/* Front right channel. */
+#define PCM_CHANNEL_FR    2
+
+/* Front center channel. */
+#define PCM_CHANNEL_FC    3
+
+/* Left surround channel.*/
+#define PCM_CHANNEL_LS   4
+
+/* Right surround channel.*/
+#define PCM_CHANNEL_RS   5
+
+/* Low frequency effect channel. */
+#define PCM_CHANNEL_LFE  6
+
+/* Center surround channel; Rear center channel. */
+#define PCM_CHANNEL_CS   7
+
+/* Left back channel; Rear left channel. */
+#define PCM_CHANNEL_LB   8
+
+/* Right back channel; Rear right channel. */
+#define PCM_CHANNEL_RB   9
+
+/* Top surround channel. */
+#define PCM_CHANNELS   10
+
+/* Center vertical height channel.*/
+#define PCM_CHANNEL_CVH  11
+
+/* Mono surround channel.*/
+#define PCM_CHANNEL_MS   12
+
+/* Front left of center. */
+#define PCM_CHANNEL_FLC  13
+
+/* Front right of center. */
+#define PCM_CHANNEL_FRC  14
+
+/* Rear left of center. */
+#define PCM_CHANNEL_RLC  15
+
+/* Rear right of center. */
+#define PCM_CHANNEL_RRC  16
+
+#define PCM_FORMAT_MAX_NUM_CHANNEL  8
+
+#define ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2 0x00010DA5
+
+#define ASM_STREAM_POSTPROC_TOPO_ID_DEFAULT 0x00010BE4
+
+#define ASM_MEDIA_FMT_EVRCB_FS 0x00010BEF
+
+#define ASM_MEDIA_FMT_EVRCWB_FS 0x00010BF0
+
+#define ASM_MAX_EQ_BANDS 12
+
+#define ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2 0x00010D98
+
+struct asm_data_cmd_media_fmt_update_v2 {
+u32                    fmt_blk_size;
+	/* Media format block size in bytes.*/
+}  __packed;
+
+struct asm_multi_channel_pcm_fmt_blk_v2 {
+	struct apr_hdr hdr;
+	struct asm_data_cmd_media_fmt_update_v2 fmt_blk;
+
+	u16  num_channels;
+	/* Number of channels. Supported values: 1 to 8 */
+	u16  bits_per_sample;
+/* Number of bits per sample per channel. * Supported values:
+ * 16, 24 * When used for playback, the client must send 24-bit
+ * samples packed in 32-bit words. The 24-bit samples must be placed
+ * in the most significant 24 bits of the 32-bit word. When used for
+ * recording, the aDSP sends 24-bit samples packed in 32-bit words.
+ * The 24-bit samples are placed in the most significant 24 bits of
+ * the 32-bit word.
+ */
+
+
+	u32  sample_rate;
+/* Number of samples per second (in Hertz).
+ * Supported values: 2000 to 48000
+ */
+
+	u16  is_signed;
+	/* Flag that indicates the samples are signed (1). */
+
+	u16  reserved;
+	/* reserved field for 32 bit alignment. must be set to zero. */
+
+	u8   channel_mapping[8];
+/* Channel array of size 8.
+ * Supported values:
+ * - #PCM_CHANNEL_L
+ * - #PCM_CHANNEL_R
+ * - #PCM_CHANNEL_C
+ * - #PCM_CHANNEL_LS
+ * - #PCM_CHANNEL_RS
+ * - #PCM_CHANNEL_LFE
+ * - #PCM_CHANNEL_CS
+ * - #PCM_CHANNEL_LB
+ * - #PCM_CHANNEL_RB
+ * - #PCM_CHANNELS
+ * - #PCM_CHANNEL_CVH
+ * - #PCM_CHANNEL_MS
+ * - #PCM_CHANNEL_FLC
+ * - #PCM_CHANNEL_FRC
+ * - #PCM_CHANNEL_RLC
+ * - #PCM_CHANNEL_RRC
+ *
+ * Channel[i] mapping describes channel I. Each element i of the
+ * array describes channel I inside the buffer where 0 @le I <
+ * num_channels. An unused channel is set to zero.
+ */
+} __packed;
+
+struct asm_stream_cmd_set_encdec_param {
+		u32                  param_id;
+	/* ID of the parameter. */
+
+	u32                  param_size;
+/* Data size of this parameter, in bytes. The size is a multiple
+ * of 4 bytes.
+ */
+
+} __packed;
+
+struct asm_enc_cfg_blk_param_v2 {
+	u32                  frames_per_buf;
+/* Number of encoded frames to pack into each buffer.
+ *
+ * @note1hang This is only guidance information for the aDSP. The
+ * number of encoded frames put into each buffer (specified by the
+ * client) is less than or equal to this number.
+ */
+
+	u32                  enc_cfg_blk_size;
+/* Size in bytes of the encoder configuration block that follows
+ * this member.
+ */
+
+} __packed;
+
+/* @brief Multichannel PCM encoder configuration structure used
+ * in the #ASM_STREAM_CMD_OPEN_READ_V2 command.
+ */
+
+struct asm_multi_channel_pcm_enc_cfg_v2 {
+	struct apr_hdr hdr;
+	struct asm_stream_cmd_set_encdec_param  encdec;
+	struct asm_enc_cfg_blk_param_v2	encblk;
+	uint16_t  num_channels;
+/*< Number of PCM channels.
+ *
+ * Supported values: - 0 -- Native mode - 1 -- 8 Native mode
+ * indicates that encoding must be performed with the number of
+ * channels at the input.
+ */
+
+	uint16_t  bits_per_sample;
+/*< Number of bits per sample per channel.
+ * Supported values: 16, 24
+ */
+
+	uint32_t  sample_rate;
+/*< Number of samples per second (in Hertz).
+ *
+ * Supported values: 0, 8000 to 48000 A value of 0 indicates the
+ * native sampling rate. Encoding is performed at the input sampling
+ * rate.
+ */
+
+	uint16_t  is_signed;
+/*< Specifies whether the samples are signed (1). Currently,
+ * only signed samples are supported.
+ */
+
+	uint16_t  reserved;
+/*< reserved field for 32 bit alignment. must be set to zero.*/
+
+
+	uint8_t   channel_mapping[8];
+} __packed;
+
+#define ASM_MEDIA_FMT_MP3 0x00010BE9
+#define ASM_MEDIA_FMT_AAC_V2 0x00010DA6
+
+/* @xreflabel
+ * {hdr:AsmMediaFmtDolbyAac} Media format ID for the
+ * Dolby AAC decoder. This format ID is be used if the client wants
+ * to use the Dolby AAC decoder to decode MPEG2 and MPEG4 AAC
+ * contents.
+ */
+
+#define ASM_MEDIA_FMT_DOLBY_AAC 0x00010D86
+
+/* Enumeration for the audio data transport stream AAC format. */
+#define ASM_MEDIA_FMT_AAC_FORMAT_FLAG_ADTS 0
+
+/* Enumeration for low overhead audio stream AAC format. */
+#define ASM_MEDIA_FMT_AAC_FORMAT_FLAG_LOAS                      1
+
+/* Enumeration for the audio data interchange format
+ * AAC format.
+ */
+#define ASM_MEDIA_FMT_AAC_FORMAT_FLAG_ADIF   2
+
+/* Enumeration for the raw AAC format. */
+#define ASM_MEDIA_FMT_AAC_FORMAT_FLAG_RAW    3
+
+#define ASM_MEDIA_FMT_AAC_AOT_LC             2
+#define ASM_MEDIA_FMT_AAC_AOT_SBR            5
+#define ASM_MEDIA_FMT_AAC_AOT_PS             29
+#define ASM_MEDIA_FMT_AAC_AOT_BSAC           22
+
+struct asm_aac_fmt_blk_v2 {
+	struct apr_hdr hdr;
+	struct asm_data_cmd_media_fmt_update_v2 fmt_blk;
+
+		u16          aac_fmt_flag;
+/* Bitstream format option.
+ * Supported values:
+ * - #ASM_MEDIA_FMT_AAC_FORMAT_FLAG_ADTS
+ * - #ASM_MEDIA_FMT_AAC_FORMAT_FLAG_LOAS
+ * - #ASM_MEDIA_FMT_AAC_FORMAT_FLAG_ADIF
+ * - #ASM_MEDIA_FMT_AAC_FORMAT_FLAG_RAW
+ */
+
+	u16          audio_objype;
+/* Audio Object Type (AOT) present in the AAC stream.
+ * Supported values:
+ * - #ASM_MEDIA_FMT_AAC_AOT_LC
+ * - #ASM_MEDIA_FMT_AAC_AOT_SBR
+ * - #ASM_MEDIA_FMT_AAC_AOT_BSAC
+ * - #ASM_MEDIA_FMT_AAC_AOT_PS
+ * - Otherwise -- Not supported
+ */
+
+	u16          channel_config;
+/* Number of channels present in the AAC stream.
+ * Supported values:
+ * - 1 -- Mono
+ * - 2 -- Stereo
+ * - 6 -- 5.1 content
+ */
+
+	u16          reserved;
+	/* Reserved. Clients must set this field to zero. */
+
+	u16          total_size_of_PCE_bits;
+/* greater or equal to zero. * -In case of RAW formats and
+ * channel config = 0 (PCE), client can send * the bit stream
+ * containing PCE immediately following this structure * (in-band).
+ * -This number does not include bits included for 32 bit alignment.
+ * -If zero, then the PCE info is assumed to be available in the
+ * audio -bit stream & not in-band.
+ */
+
+	u32          sample_rate;
+/* Number of samples per second (in Hertz).
+ *
+ * Supported values: 8000, 11025, 12000, 16000, 22050, 24000, 32000,
+ * 44100, 48000
+ *
+ * This field must be equal to the sample rate of the AAC-LC
+ * decoder's output. - For MP4 or 3GP containers, this is indicated
+ * by the samplingFrequencyIndex field in the AudioSpecificConfig
+ * element. - For ADTS format, this is indicated by the
+ * samplingFrequencyIndex in the ADTS fixed header. - For ADIF
+ * format, this is indicated by the samplingFrequencyIndex in the
+ * program_config_element present in the ADIF header.
+ */
+
+} __packed;
+
+struct asm_aac_enc_cfg_v2 {
+	struct apr_hdr hdr;
+	struct asm_stream_cmd_set_encdec_param  encdec;
+	struct asm_enc_cfg_blk_param_v2	encblk;
+
+	u32          bit_rate;
+	/* Encoding rate in bits per second. */
+	u32          enc_mode;
+/* Encoding mode.
+ * Supported values:
+ * - #ASM_MEDIA_FMT_AAC_AOT_LC
+ * - #ASM_MEDIA_FMT_AAC_AOT_SBR
+ * - #ASM_MEDIA_FMT_AAC_AOT_PS
+ */
+	u16          aac_fmt_flag;
+/* AAC format flag.
+ * Supported values:
+ * - #ASM_MEDIA_FMT_AAC_FORMAT_FLAG_ADTS
+ * - #ASM_MEDIA_FMT_AAC_FORMAT_FLAG_RAW
+ */
+	u16          channel_cfg;
+/* Number of channels to encode.
+ * Supported values:
+ * - 0 -- Native mode
+ * - 1 -- Mono
+ * - 2 -- Stereo
+ * - Other values are not supported.
+ * @note1hang The eAAC+ encoder mode supports only stereo.
+ * Native mode indicates that encoding must be performed with the
+ * number of channels at the input.
+ * The number of channels must not change during encoding.
+ */
+
+	u32          sample_rate;
+/* Number of samples per second.
+ * Supported values: - 0 -- Native mode - For other values,
+ * Native mode indicates that encoding must be performed with the
+ * sampling rate at the input.
+ * The sampling rate must not change during encoding.
+ */
+
+} __packed;
+
+#define ASM_MEDIA_FMT_AMRNB_FS                  0x00010BEB
+
+/* Enumeration for 4.75 kbps AMR-NB Encoding mode. */
+#define ASM_MEDIA_FMT_AMRNB_FS_ENCODE_MODE_MR475                0
+
+/* Enumeration for 5.15 kbps AMR-NB Encoding mode. */
+#define ASM_MEDIA_FMT_AMRNB_FS_ENCODE_MODE_MR515                1
+
+/* Enumeration for 5.90 kbps AMR-NB Encoding mode. */
+#define ASM_MEDIA_FMT_AMRNB_FS_ENCODE_MODE_MMR59                2
+
+/* Enumeration for 6.70 kbps AMR-NB Encoding mode. */
+#define ASM_MEDIA_FMT_AMRNB_FS_ENCODE_MODE_MMR67                3
+
+/* Enumeration for 7.40 kbps AMR-NB Encoding mode. */
+#define ASM_MEDIA_FMT_AMRNB_FS_ENCODE_MODE_MMR74                4
+
+/* Enumeration for 7.95 kbps AMR-NB Encoding mode. */
+#define ASM_MEDIA_FMT_AMRNB_FS_ENCODE_MODE_MMR795               5
+
+/* Enumeration for 10.20 kbps AMR-NB Encoding mode. */
+#define ASM_MEDIA_FMT_AMRNB_FS_ENCODE_MODE_MMR102               6
+
+/* Enumeration for 12.20 kbps AMR-NB Encoding mode. */
+#define ASM_MEDIA_FMT_AMRNB_FS_ENCODE_MODE_MMR122               7
+
+/* Enumeration for AMR-NB Discontinuous Transmission mode off. */
+#define ASM_MEDIA_FMT_AMRNB_FS_DTX_MODE_OFF                     0
+
+/* Enumeration for AMR-NB DTX mode VAD1. */
+#define ASM_MEDIA_FMT_AMRNB_FS_DTX_MODE_VAD1                    1
+
+/* Enumeration for AMR-NB DTX mode VAD2. */
+#define ASM_MEDIA_FMT_AMRNB_FS_DTX_MODE_VAD2                    2
+
+/* Enumeration for AMR-NB DTX mode auto.
+	*/
+#define ASM_MEDIA_FMT_AMRNB_FS_DTX_MODE_AUTO                    3
+
+struct asm_amrnb_enc_cfg {
+	struct apr_hdr hdr;
+	struct asm_stream_cmd_set_encdec_param  encdec;
+	struct asm_enc_cfg_blk_param_v2	encblk;
+
+	u16          enc_mode;
+/* AMR-NB encoding rate.
+ * Supported values:
+ * Use the ASM_MEDIA_FMT_AMRNB_FS_ENCODE_MODE_*
+ * macros
+ */
+
+	u16          dtx_mode;
+/* Specifies whether DTX mode is disabled or enabled.
+ * Supported values:
+ * - #ASM_MEDIA_FMT_AMRNB_FS_DTX_MODE_OFF
+ * - #ASM_MEDIA_FMT_AMRNB_FS_DTX_MODE_VAD1
+ */
+} __packed;
+
+#define ASM_MEDIA_FMT_AMRWB_FS                  0x00010BEC
+
+/* Enumeration for 6.6 kbps AMR-WB Encoding mode. */
+#define ASM_MEDIA_FMT_AMRWB_FS_ENCODE_MODE_MR66                 0
+
+/* Enumeration for 8.85 kbps AMR-WB Encoding mode. */
+#define ASM_MEDIA_FMT_AMRWB_FS_ENCODE_MODE_MR885                1
+
+/* Enumeration for 12.65 kbps AMR-WB Encoding mode. */
+#define ASM_MEDIA_FMT_AMRWB_FS_ENCODE_MODE_MR1265               2
+
+/* Enumeration for 14.25 kbps AMR-WB Encoding mode. */
+#define ASM_MEDIA_FMT_AMRWB_FS_ENCODE_MODE_MR1425               3
+
+/* Enumeration for 15.85 kbps AMR-WB Encoding mode. */
+#define ASM_MEDIA_FMT_AMRWB_FS_ENCODE_MODE_MR1585               4
+
+/* Enumeration for 18.25 kbps AMR-WB Encoding mode. */
+#define ASM_MEDIA_FMT_AMRWB_FS_ENCODE_MODE_MR1825               5
+
+/* Enumeration for 19.85 kbps AMR-WB Encoding mode. */
+#define ASM_MEDIA_FMT_AMRWB_FS_ENCODE_MODE_MR1985               6
+
+/* Enumeration for 23.05 kbps AMR-WB Encoding mode. */
+#define ASM_MEDIA_FMT_AMRWB_FS_ENCODE_MODE_MR2305               7
+
+/* Enumeration for 23.85 kbps AMR-WB Encoding mode.
+	*/
+#define ASM_MEDIA_FMT_AMRWB_FS_ENCODE_MODE_MR2385               8
+
+struct asm_amrwb_enc_cfg {
+	struct apr_hdr hdr;
+	struct asm_stream_cmd_set_encdec_param  encdec;
+	struct asm_enc_cfg_blk_param_v2	encblk;
+
+	u16          enc_mode;
+/* AMR-WB encoding rate.
+ * Suupported values:
+ * Use the ASM_MEDIA_FMT_AMRWB_FS_ENCODE_MODE_*
+ * macros
+ */
+
+	u16          dtx_mode;
+/* Specifies whether DTX mode is disabled or enabled.
+ * Supported values:
+ * - #ASM_MEDIA_FMT_AMRNB_FS_DTX_MODE_OFF
+ * - #ASM_MEDIA_FMT_AMRNB_FS_DTX_MODE_VAD1
+ */
+} __packed;
+
+#define ASM_MEDIA_FMT_V13K_FS                      0x00010BED
+
+/* Enumeration for 14.4 kbps V13K Encoding mode. */
+#define ASM_MEDIA_FMT_V13K_FS_ENCODE_MODE_MR1440                0
+
+/* Enumeration for 12.2 kbps V13K Encoding mode. */
+#define ASM_MEDIA_FMT_V13K_FS_ENCODE_MODE_MR1220                1
+
+/* Enumeration for 11.2 kbps V13K Encoding mode. */
+#define ASM_MEDIA_FMT_V13K_FS_ENCODE_MODE_MR1120                2
+
+/* Enumeration for 9.0 kbps V13K Encoding mode. */
+#define ASM_MEDIA_FMT_V13K_FS_ENCODE_MODE_MR90                  3
+
+/* Enumeration for 7.2 kbps V13K eEncoding mode. */
+#define ASM_MEDIA_FMT_V13K_FS_ENCODE_MODE_MR720                 4
+
+/* Enumeration for 1/8 vocoder rate.*/
+#define ASM_MEDIA_FMT_VOC_ONE_EIGHTH_RATE          1
+
+/* Enumeration for 1/4 vocoder rate. */
+#define ASM_MEDIA_FMT_VOC_ONE_FOURTH_RATE       2
+
+/* Enumeration for 1/2 vocoder rate. */
+#define ASM_MEDIA_FMT_VOC_HALF_RATE             3
+
+/* Enumeration for full vocoder rate.
+	*/
+#define ASM_MEDIA_FMT_VOC_FULL_RATE             4
+
+struct asm_v13k_enc_cfg {
+	struct apr_hdr hdr;
+	struct asm_stream_cmd_set_encdec_param  encdec;
+	struct asm_enc_cfg_blk_param_v2	encblk;
+		u16          max_rate;
+/* Maximum allowed encoder frame rate.
+ * Supported values:
+ * - #ASM_MEDIA_FMT_VOC_ONE_EIGHTH_RATE
+ * - #ASM_MEDIA_FMT_VOC_ONE_FOURTH_RATE
+ * - #ASM_MEDIA_FMT_VOC_HALF_RATE
+ * - #ASM_MEDIA_FMT_VOC_FULL_RATE
+ */
+
+	u16          min_rate;
+/* Minimum allowed encoder frame rate.
+ * Supported values:
+ * - #ASM_MEDIA_FMT_VOC_ONE_EIGHTH_RATE
+ * - #ASM_MEDIA_FMT_VOC_ONE_FOURTH_RATE
+ * - #ASM_MEDIA_FMT_VOC_HALF_RATE
+ * - #ASM_MEDIA_FMT_VOC_FULL_RATE
+ */
+
+	u16          reduced_rate_cmd;
+/* Reduced rate command, used to change
+ * the average bitrate of the V13K
+ * vocoder.
+ * Supported values:
+ * - #ASM_MEDIA_FMT_V13K_FS_ENCODE_MODE_MR1440 (Default)
+ * - #ASM_MEDIA_FMT_V13K_FS_ENCODE_MODE_MR1220
+ * - #ASM_MEDIA_FMT_V13K_FS_ENCODE_MODE_MR1120
+ * - #ASM_MEDIA_FMT_V13K_FS_ENCODE_MODE_MR90
+ * - #ASM_MEDIA_FMT_V13K_FS_ENCODE_MODE_MR720
+ */
+
+	u16          rate_mod_cmd;
+/* Rate modulation command. Default = 0.
+ *- If bit 0=1, rate control is enabled.
+ *- If bit 1=1, the maximum number of consecutive full rate
+ *			frames is limited with numbers supplied in
+ *			bits 2 to 10.
+ *- If bit 1=0, the minimum number of non-full rate frames
+ *			in between two full rate frames is forced to
+ * the number supplied in bits 2 to 10. In both cases, if necessary,
+ * half rate is used to substitute full rate. - Bits 15 to 10 are
+ * reserved and must all be set to zero.
+ */
+
+} __packed;
+
+#define ASM_MEDIA_FMT_EVRC_FS                   0x00010BEE
+
+/*  EVRC encoder configuration structure used in the
+ * #ASM_STREAM_CMD_OPEN_READ_V2 command.
+ */
+struct asm_evrc_enc_cfg {
+	struct apr_hdr hdr;
+	struct asm_stream_cmd_set_encdec_param  encdec;
+	struct asm_enc_cfg_blk_param_v2	encblk;
+	u16          max_rate;
+/* Maximum allowed encoder frame rate.
+ * Supported values:
+ * - #ASM_MEDIA_FMT_VOC_ONE_EIGHTH_RATE
+ * - #ASM_MEDIA_FMT_VOC_ONE_FOURTH_RATE
+ * - #ASM_MEDIA_FMT_VOC_HALF_RATE
+ * - #ASM_MEDIA_FMT_VOC_FULL_RATE
+ */
+
+	u16          min_rate;
+/* Minimum allowed encoder frame rate.
+ * Supported values:
+ * - #ASM_MEDIA_FMT_VOC_ONE_EIGHTH_RATE
+ * - #ASM_MEDIA_FMT_VOC_ONE_FOURTH_RATE
+ * - #ASM_MEDIA_FMT_VOC_HALF_RATE
+ * - #ASM_MEDIA_FMT_VOC_FULL_RATE
+ */
+
+	u16          rate_mod_cmd;
+/* Rate modulation command. Default: 0.
+ * - If bit 0=1, rate control is enabled.
+ * - If bit 1=1, the maximum number of consecutive full rate frames
+ * is limited with numbers supplied in bits 2 to 10.
+ *
+ * - If bit 1=0, the minimum number of non-full rate frames in
+ * between two full rate frames is forced to the number supplied in
+ * bits 2 to 10. In both cases, if necessary, half rate is used to
+ * substitute full rate.
+ *
+ * - Bits 15 to 10 are reserved and must all be set to zero.
+ */
+
+	u16          reserved;
+	/* Reserved. Clients must set this field to zero. */
+} __packed;
+
+#define ASM_MEDIA_FMT_WMA_V10PRO_V2                0x00010DA7
+
+struct asm_wmaprov10_fmt_blk_v2 {
+	struct apr_hdr hdr;
+	struct asm_data_cmd_media_fmt_update_v2 fmtblk;
+
+	u16          fmtag;
+/* WMA format type.
+ * Supported values:
+ * - 0x162 -- WMA 9 Pro
+ * - 0x163 -- WMA 9 Pro Lossless
+ * - 0x166 -- WMA 10 Pro
+ * - 0x167 -- WMA 10 Pro Lossless
+ */
+
+	u16          num_channels;
+/* Number of channels encoded in the input stream.
+ * Supported values: 1 to 8
+ */
+
+	u32          sample_rate;
+/* Number of samples per second (in Hertz).
+ * Supported values: 11025, 16000, 22050, 32000, 44100, 48000,
+ * 88200, 96000
+ */
+
+	u32          avg_bytes_per_sec;
+/* Bitrate expressed as the average bytes per second.
+ * Supported values: 2000 to 96000
+ */
+
+	u16          blk_align;
+/* Size of the bitstream packet size in bytes. WMA Pro files
+ * have a payload of one block per bitstream packet.
+ * Supported values: @le 13376
+ */
+
+	u16          bits_per_sample;
+/* Number of bits per sample in the encoded WMA stream.
+ * Supported values: 16, 24
+ */
+
+	u32          channel_mask;
+/* Bit-packed double word (32-bits) that indicates the
+ * recommended speaker positions for each source channel.
+ */
+
+	u16          enc_options;
+/* Bit-packed word with values that indicate whether certain
+ * features of the bitstream are used.
+ * Supported values: - 0x0001 -- ENCOPT3_PURE_LOSSLESS - 0x0006 --
+ * ENCOPT3_FRM_SIZE_MOD - 0x0038 -- ENCOPT3_SUBFRM_DIV - 0x0040 --
+ * ENCOPT3_WRITE_FRAMESIZE_IN_HDR - 0x0080 --
+ * ENCOPT3_GENERATE_DRC_PARAMS - 0x0100 -- ENCOPT3_RTMBITS
+ */
+
+
+	u16          usAdvancedEncodeOpt;
+	/* Advanced encoding option.  */
+
+	u32          advanced_enc_options2;
+	/* Advanced encoding option 2. */
+
+} __packed;
+
+#define ASM_MEDIA_FMT_WMA_V9_V2                    0x00010DA8
+struct asm_wmastdv9_fmt_blk_v2 {
+	struct apr_hdr hdr;
+	struct asm_data_cmd_media_fmt_update_v2 fmtblk;
+	u16          fmtag;
+/* WMA format tag.
+ * Supported values: 0x161 (WMA 9 standard)
+ */
+
+	u16          num_channels;
+/* Number of channels in the stream.
+ * Supported values: 1, 2
+ */
+
+	u32          sample_rate;
+/* Number of samples per second (in Hertz).
+ * Supported values: 48000
+ */
+
+	u32          avg_bytes_per_sec;
+	/* Bitrate expressed as the average bytes per second. */
+
+	u16          blk_align;
+/* Block align. All WMA files with a maximum packet size of
+ * 13376 are supported.
+ */
+
+
+	u16          bits_per_sample;
+/* Number of bits per sample in the output.
+ * Supported values: 16
+ */
+
+	u32          channel_mask;
+/* Channel mask.
+ * Supported values:
+ * - 3 -- Stereo (front left/front right)
+ * - 4 -- Mono (center)
+ */
+
+	u16          enc_options;
+	/* Options used during encoding. */
+
+} __packed;
+
+#define ASM_MEDIA_FMT_WMA_V8                    0x00010D91
+
+struct asm_wmastdv8_enc_cfg {
+	struct apr_hdr hdr;
+	struct asm_stream_cmd_set_encdec_param  encdec;
+	struct asm_enc_cfg_blk_param_v2	encblk;
+	u32          bit_rate;
+	/* Encoding rate in bits per second. */
+
+	u32          sample_rate;
+/* Number of samples per second.
+ *
+ * Supported values:
+ * - 0 -- Native mode
+ * - Other Supported values are 22050, 32000, 44100, and 48000.
+ *
+ * Native mode indicates that encoding must be performed with the
+ * sampling rate at the input.
+ * The sampling rate must not change during encoding.
+ */
+
+	u16          channel_cfg;
+/* Number of channels to encode.
+ * Supported values:
+ * - 0 -- Native mode
+ * - 1 -- Mono
+ * - 2 -- Stereo
+ * - Other values are not supported.
+ *
+ * Native mode indicates that encoding must be performed with the
+ * number of channels at the input.
+ * The number of channels must not change during encoding.
+ */
+
+	u16          reserved;
+	/* Reserved. Clients must set this field to zero.*/
+	} __packed;
+
+#define ASM_MEDIA_FMT_AMR_WB_PLUS_V2               0x00010DA9
+
+struct asm_amrwbplus_fmt_blk_v2 {
+	struct apr_hdr hdr;
+	struct asm_data_cmd_media_fmt_update_v2 fmtblk;
+	u32          amr_frame_fmt;
+/* AMR frame format.
+ * Supported values:
+ * - 6 -- Transport Interface Format (TIF)
+ * - Any other value -- File storage format (FSF)
+ *
+ * TIF stream contains 2-byte header for each frame within the
+ * superframe. FSF stream contains one 2-byte header per superframe.
+ */
+
+} __packed;
+
+#define ASM_MEDIA_FMT_AC3_DEC                   0x00010BF6
+#define ASM_MEDIA_FMT_EAC3_DEC                   0x00010C3C
+#define ASM_MEDIA_FMT_DTS                    0x00010D88
+
+/* Media format ID for adaptive transform acoustic coding. This
+ * ID is used by the #ASM_STREAM_CMD_OPEN_WRITE_COMPRESSED command
+ * only.
+ */
+
+#define ASM_MEDIA_FMT_ATRAC                  0x00010D89
+
+/* Media format ID for metadata-enhanced audio transmission.
+ * This ID is used by the #ASM_STREAM_CMD_OPEN_WRITE_COMPRESSED
+ * command only.
+ */
+
+#define ASM_MEDIA_FMT_MAT                    0x00010D8A
+
+/*  adsp_media_fmt.h */
+
+#define ASM_DATA_CMD_WRITE_V2 0x00010DAB
+
+struct asm_data_cmd_write_v2 {
+	struct apr_hdr hdr;
+	u32                  buf_addr_lsw;
+/* The 64 bit address msw-lsw should be a valid, mapped address.
+ * 64 bit address should be a multiple of 32 bytes
+ */
+
+	u32                  buf_addr_msw;
+/* The 64 bit address msw-lsw should be a valid, mapped address.
+ * 64 bit address should be a multiple of 32 bytes.
+ * -Address of the buffer containing the data to be decoded.
+ * The buffer should be aligned to a 32 byte boundary.
+ * -In the case of 32 bit Shared memory address, msw field must
+ * -be set to zero.
+ * -In the case of 36 bit shared memory address, bit 31 to bit 4
+ * -of msw must be set to zero.
+ */
+	u32                  mem_map_handle;
+/* memory map handle returned by DSP through
+ * ASM_CMD_SHARED_MEM_MAP_REGIONS command
+ */
+	u32                  buf_size;
+/* Number of valid bytes available in the buffer for decoding. The
+ * first byte starts at buf_addr.
+ */
+
+	u32                  seq_id;
+	/* Optional buffer sequence ID. */
+
+	u32                  timestamp_lsw;
+/* Lower 32 bits of the 64-bit session time in microseconds of the
+ * first buffer sample.
+ */
+
+	u32                  timestamp_msw;
+/* Upper 32 bits of the 64-bit session time in microseconds of the
+ * first buffer sample.
+ */
+
+	u32                  flags;
+/* Bitfield of flags.
+ * Supported values for bit 31:
+ * - 1 -- Valid timestamp.
+ * - 0 -- Invalid timestamp.
+ * - Use #ASM_BIT_MASKIMESTAMP_VALID_FLAG as the bitmask and
+ * #ASM_SHIFTIMESTAMP_VALID_FLAG as the shift value to set this bit.
+ * Supported values for bit 30:
+ * - 1 -- Last buffer.
+ * - 0 -- Not the last buffer.
+ *
+ * Supported values for bit 29:
+ * - 1 -- Continue the timestamp from the previous buffer.
+ * - 0 -- Timestamp of the current buffer is not related
+ * to the timestamp of the previous buffer.
+ * - Use #ASM_BIT_MASKS_CONTINUE_FLAG and #ASM_SHIFTS_CONTINUE_FLAG
+ * to set this bit.
+ *
+ * Supported values for bit 4:
+ * - 1 -- End of the frame.
+ * - 0 -- Not the end of frame, or this information is not known.
+ * - Use #ASM_BIT_MASK_EOF_FLAG as the bitmask and #ASM_SHIFT_EOF_FLAG
+ * as the shift value to set this bit.
+ *
+ * All other bits are reserved and must be set to 0.
+ *
+ * If bit 31=0 and bit 29=1: The timestamp of the first sample in
+ * this buffer continues from the timestamp of the last sample in
+ * the previous buffer. If there is no previous buffer (i.e., this
+ * is the first buffer sent after opening the stream or after a
+ * flush operation), or if the previous buffer does not have a valid
+ * timestamp, the samples in the current buffer also do not have a
+ * valid timestamp. They are played out as soon as possible.
+ *
+ *
+ * If bit 31=0 and bit 29=0: No timestamp is associated with the
+ * first sample in this buffer. The samples are played out as soon
+ * as possible.
+ *
+ *
+ * If bit 31=1 and bit 29 is ignored: The timestamp specified in
+ * this payload is honored.
+ *
+ *
+ * If bit 30=0: Not the last buffer in the stream. This is useful
+ * in removing trailing samples.
+ *
+ *
+ * For bit 4: The client can set this flag for every buffer sent in
+ * which the last byte is the end of a frame. If this flag is set,
+ * the buffer can contain data from multiple frames, but it should
+ * always end at a frame boundary. Restrictions allow the aDSP to
+ * detect an end of frame without requiring additional processing.
+ */
+
+} __packed;
+
+#define ASM_DATA_CMD_READ_V2 0x00010DAC
+
+struct asm_data_cmd_read_v2 {
+	struct apr_hdr       hdr;
+	u32                  buf_addr_lsw;
+/* the 64 bit address msw-lsw should be a valid mapped address
+ * and should be a multiple of 32 bytes
+ */
+
+
+	u32                  buf_addr_msw;
+/* the 64 bit address msw-lsw should be a valid mapped address
+ * and should be a multiple of 32 bytes.
+* - Address of the buffer where the DSP puts the encoded data,
+* potentially, at an offset specified by the uOffset field in
+* ASM_DATA_EVENT_READ_DONE structure. The buffer should be aligned
+* to a 32 byte boundary.
+*- In the case of 32 bit Shared memory address, msw field must
+*- be set to zero.
+*- In the case of 36 bit shared memory address, bit 31 to bit
+*- 4 of msw must be set to zero.
+*/
+	u32                  mem_map_handle;
+/* memory map handle returned by DSP through
+ * ASM_CMD_SHARED_MEM_MAP_REGIONS command.
+ */
+
+	u32                  buf_size;
+/* Number of bytes available for the aDSP to write. The aDSP
+ * starts writing from buf_addr.
+ */
+
+	u32                  seq_id;
+	/* Optional buffer sequence ID.
+			*/
+} __packed;
+
+#define ASM_DATA_CMD_EOS               0x00010BDB
+#define ASM_DATA_EVENT_RENDERED_EOS    0x00010C1C
+#define ASM_DATA_EVENT_EOS             0x00010BDD
+
+#define ASM_DATA_EVENT_WRITE_DONE_V2 0x00010D99
+struct asm_data_event_write_done_v2 {
+	u32                  buf_addr_lsw;
+	/* lsw of the 64 bit address */
+	u32                  buf_addr_msw;
+	/* msw of the 64 bit address. address given by the client in
+	* ASM_DATA_CMD_WRITE_V2 command.
+	*/
+	u32                  mem_map_handle;
+	/* memory map handle in the ASM_DATA_CMD_WRITE_V2  */
+
+	u32                  status;
+/* Status message (error code) that indicates whether the
+ * referenced buffer has been successfully consumed.
+ * Supported values: Refer to @xhyperref{Q3,[Q3]}
+ */
+} __packed;
+
+#define ASM_DATA_EVENT_READ_DONE_V2 0x00010D9A
+
+/* Definition of the frame metadata flag bitmask.*/
+#define ASM_BIT_MASK_FRAME_METADATA_FLAG (0x40000000UL)
+
+/* Definition of the frame metadata flag shift value. */
+#define ASM_SHIFT_FRAME_METADATA_FLAG 30
+
+struct asm_data_event_read_done_v2 {
+	u32                  status;
+/* Status message (error code).
+ * Supported values: Refer to @xhyperref{Q3,[Q3]}
+ */
+
+u32                  buf_addr_lsw;
+/* 64 bit address msw-lsw is a valid, mapped address. 64 bit
+ * address is a multiple of 32 bytes.
+ */
+
+u32                  buf_addr_msw;
+/* 64 bit address msw-lsw is a valid, mapped address. 64 bit
+* address is a multiple of 32 bytes.
+*
+* -Same address provided by the client in ASM_DATA_CMD_READ_V2
+* -In the case of 32 bit Shared memory address, msw field is set to
+* zero.
+* -In the case of 36 bit shared memory address, bit 31 to bit 4
+* -of msw is set to zero.
+*/
+
+u32                  mem_map_handle;
+/* memory map handle in the ASM_DATA_CMD_READ_V2  */
+
+u32                  enc_framesotal_size;
+/* Total size of the encoded frames in bytes.
+ * Supported values: >0
+ */
+
+u32                  offset;
+/* Offset (from buf_addr) to the first byte of the first encoded
+ * frame. All encoded frames are consecutive, starting from this
+ * offset.
+ * Supported values: > 0
+ */
+
+u32                  timestamp_lsw;
+/* Lower 32 bits of the 64-bit session time in microseconds of
+ * the first sample in the buffer. If Bit 5 of mode_flags flag of
+ * ASM_STREAM_CMD_OPEN_READ_V2 is 1 then the 64 bit timestamp is
+ * absolute capture time otherwise it is relative session time. The
+ * absolute timestamp doesnt reset unless the system is reset.
+ */
+
+
+u32                  timestamp_msw;
+/* Upper 32 bits of the 64-bit session time in microseconds of
+ * the first sample in the buffer.
+ */
+
+
+u32                  flags;
+/* Bitfield of flags. Bit 30 indicates whether frame metadata is
+ * present. If frame metadata is present, num_frames consecutive
+ * instances of @xhyperref{hdr:FrameMetaData,Frame metadata} start
+ * at the buffer address.
+ * Supported values for bit 31:
+ * - 1 -- Timestamp is valid.
+ * - 0 -- Timestamp is invalid.
+ * - Use #ASM_BIT_MASKIMESTAMP_VALID_FLAG and
+ * #ASM_SHIFTIMESTAMP_VALID_FLAG to set this bit.
+ *
+ * Supported values for bit 30:
+ * - 1 -- Frame metadata is present.
+ * - 0 -- Frame metadata is absent.
+ * - Use #ASM_BIT_MASK_FRAME_METADATA_FLAG and
+ * #ASM_SHIFT_FRAME_METADATA_FLAG to set this bit.
+ *
+ * All other bits are reserved; the aDSP sets them to 0.
+ */
+
+u32                  num_frames;
+/* Number of encoded frames in the buffer. */
+
+u32                  seq_id;
+/* Optional buffer sequence ID.	*/
+} __packed;
+
+struct asm_data_read_buf_metadata_v2 {
+	u32          offset;
+/* Offset from buf_addr in #ASM_DATA_EVENT_READ_DONE_PAYLOAD to
+ * the frame associated with this metadata.
+ * Supported values: > 0
+ */
+
+u32          frm_size;
+/* Size of the encoded frame in bytes.
+ * Supported values: > 0
+ */
+
+u32          num_encoded_pcm_samples;
+/* Number of encoded PCM samples (per channel) in the frame
+ * associated with this metadata.
+ * Supported values: > 0
+ */
+
+u32          timestamp_lsw;
+/* Lower 32 bits of the 64-bit session time in microseconds of the
+ * first sample for this frame.
+ * If Bit 5 of mode_flags flag of ASM_STREAM_CMD_OPEN_READ_V2 is 1
+ * then the 64 bit timestamp is absolute capture time otherwise it
+ * is relative session time. The absolute timestamp doesnt reset
+ * unless the system is reset.
+ */
+
+
+u32          timestamp_msw;
+/* Lower 32 bits of the 64-bit session time in microseconds of the
+ * first sample for this frame.
+ */
+
+u32          flags;
+/* Frame flags.
+ * Supported values for bit 31:
+ * - 1 -- Time stamp is valid
+ * - 0 -- Time stamp is not valid
+ * - All other bits are reserved; the aDSP sets them to 0.
+*/
+} __packed;
+
+/* Notifies the client of a change in the data sampling rate or
+ * Channel mode. This event is raised by the decoder service. The
+ * event is enabled through the mode flags of
+ * #ASM_STREAM_CMD_OPEN_WRITE_V2 or
+ * #ASM_STREAM_CMD_OPEN_READWRITE_V2. - The decoder detects a change
+ * in the output sampling frequency or the number/positioning of
+ * output channels, or if it is the first frame decoded.The new
+ * sampling frequency or the new channel configuration is
+ * communicated back to the client asynchronously.
+ */
+
+#define ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY 0x00010C65
+
+/*  Payload of the #ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY event.
+ * This event is raised when the following conditions are both true:
+ * - The event is enabled through the mode_flags of
+ * #ASM_STREAM_CMD_OPEN_WRITE_V2 or
+ * #ASM_STREAM_CMD_OPEN_READWRITE_V2. - The decoder detects a change
+ * in either the output sampling frequency or the number/positioning
+ * of output channels, or if it is the first frame decoded.
+ * This event is not raised (even if enabled) if the decoder is
+ * MIDI, because
+ */
+
+
+struct asm_data_event_sr_cm_change_notify {
+	u32                  sample_rate;
+/* New sampling rate (in Hertz) after detecting a change in the
+ * bitstream.
+ * Supported values: 2000 to 48000
+ */
+
+	u16                  num_channels;
+/* New number of channels after detecting a change in the
+ * bitstream.
+ * Supported values: 1 to 8
+ */
+
+
+	u16                  reserved;
+	/* Reserved for future use. This field must be set to 0.*/
+
+	u8                   channel_mapping[8];
+
+} __packed;
+
+/* Notifies the client of a data sampling rate or channel mode
+ * change. This event is raised by the encoder service.
+ * This event is raised when :
+ * - Native mode encoding was requested in the encoder
+ * configuration (i.e., the channel number was 0), the sample rate
+ * was 0, or both were 0.
+ *
+ * - The input data frame at the encoder is the first one, or the
+ * sampling rate/channel mode is different from the previous input
+ * data frame.
+ *
+ */
+#define ASM_DATA_EVENT_ENC_SR_CM_CHANGE_NOTIFY 0x00010BDE
+
+struct asm_data_event_enc_sr_cm_change_notify {
+	u32                  sample_rate;
+/* New sampling rate (in Hertz) after detecting a change in the
+ * input data.
+ * Supported values: 2000 to 48000
+ */
+
+
+	u16                  num_channels;
+/* New number of channels after detecting a change in the input
+ * data. Supported values: 1 to 8
+ */
+
+
+	u16                  bits_per_sample;
+/* New bits per sample after detecting a change in the input
+ * data.
+ * Supported values: 16, 24
+ */
+
+
+	u8                   channel_mapping[8];
+
+} __packed;
+#define ASM_DATA_CMD_IEC_60958_FRAME_RATE 0x00010D87
+
+
+/* Payload of the #ASM_DATA_CMD_IEC_60958_FRAME_RATE command,
+ * which is used to indicate the IEC 60958 frame rate of a given
+ * packetized audio stream.
+ */
+
+struct asm_data_cmd_iec_60958_frame_rate {
+	u32                  frame_rate;
+/* IEC 60958 frame rate of the incoming IEC 61937 packetized stream.
+ * Supported values: Any valid frame rate
+ */
+} __packed;
+
+/* adsp_asm_data_commands.h*/
+#define ASM_SVC_CMD_GET_STREAM_HANDLES         0x00010C0B
+
+#define ASM_SVC_CMDRSP_GET_STREAM_HANDLES      0x00010C1B
+
+/* Definition of the stream ID bitmask.*/
+#define ASM_BIT_MASK_STREAM_ID                 (0x000000FFUL)
+
+/* Definition of the stream ID shift value.*/
+#define ASM_SHIFT_STREAM_ID                    0
+
+/* Definition of the session ID bitmask.*/
+#define ASM_BIT_MASK_SESSION_ID                (0x0000FF00UL)
+
+/* Definition of the session ID shift value.*/
+#define ASM_SHIFT_SESSION_ID                   8
+
+/* Definition of the service ID bitmask.*/
+#define ASM_BIT_MASK_SERVICE_ID                (0x00FF0000UL)
+
+/* Definition of the service ID shift value.*/
+#define ASM_SHIFT_SERVICE_ID                   16
+
+/* Definition of the domain ID bitmask.*/
+#define ASM_BIT_MASK_DOMAIN_ID                (0xFF000000UL)
+
+/* Definition of the domain ID shift value.*/
+#define ASM_SHIFT_DOMAIN_ID                    24
+
+/* Payload of the #ASM_SVC_CMDRSP_GET_STREAM_HANDLES message,
+ * which returns a list of currently active stream handles.
+ * Immediately following this structure are num_handles of uint32
+ * stream handles.
+ */
+
+
+struct asm_svc_cmdrsp_get_stream_handles {
+	u32                  num_handles;
+	/* Number of active stream handles.	*/
+} __packed;
+
+#define ASM_CMD_SHARED_MEM_MAP_REGIONS               0x00010D92
+#define ASM_CMDRSP_SHARED_MEM_MAP_REGIONS     0x00010D93
+#define ASM_CMD_SHARED_MEM_UNMAP_REGIONS              0x00010D94
+
+/* adsp_asm_service_commands.h */
+
+#define ASM_MAX_SESSION_ID  (8)
+
+/* Maximum number of sessions.*/
+#define ASM_MAX_NUM_SESSIONS                ASM_MAX_SESSION_ID
+
+/* Maximum number of streams per session.*/
+#define ASM_MAX_STREAMS_PER_SESSION (8)
+#define ASM_SESSION_CMD_RUN_V2                   0x00010DAA
+#define ASM_SESSION_CMD_RUN_STARTIME_RUN_IMMEDIATE  0
+#define ASM_SESSION_CMD_RUN_STARTIME_RUN_AT_ABSOLUTEIME 1
+#define ASM_SESSION_CMD_RUN_STARTIME_RUN_AT_RELATIVEIME 2
+#define ASM_SESSION_CMD_RUN_STARTIME_RUN_WITH_DELAY     3
+
+#define ASM_BIT_MASK_RUN_STARTIME                 (0x00000003UL)
+
+/* Bit shift value used to specify the start time for the
+ * ASM_SESSION_CMD_RUN_V2 command.
+ */
+#define ASM_SHIFT_RUN_STARTIME 0
+struct asm_session_cmd_run_v2 {
+	struct apr_hdr hdr;
+	u32                  flags;
+/* Specifies whether to run immediately or at a specific
+ * rendering time or with a specified delay. Run with delay is
+ * useful for delaying in case of ASM loopback opened through
+ * ASM_STREAM_CMD_OPEN_LOOPBACK_V2. Use #ASM_BIT_MASK_RUN_STARTIME
+ * and #ASM_SHIFT_RUN_STARTIME to set this 2-bit flag.
+ *
+ *
+ *Bits 0 and 1 can take one of four possible values:
+ *
+ *- #ASM_SESSION_CMD_RUN_STARTIME_RUN_IMMEDIATE
+ *- #ASM_SESSION_CMD_RUN_STARTIME_RUN_AT_ABSOLUTEIME
+ *- #ASM_SESSION_CMD_RUN_STARTIME_RUN_AT_RELATIVEIME
+ *- #ASM_SESSION_CMD_RUN_STARTIME_RUN_WITH_DELAY
+ *
+ *All other bits are reserved; clients must set them to zero.
+ */
+
+	u32                  time_lsw;
+/* Lower 32 bits of the time in microseconds used to align the
+ * session origin time. When bits 0-1 of flags is
+ * ASM_SESSION_CMD_RUN_START_RUN_WITH_DELAY, time lsw is the lsw of
+ * the delay in us. For ASM_SESSION_CMD_RUN_START_RUN_WITH_DELAY,
+ * maximum value of the 64 bit delay is 150 ms.
+ */
+
+	u32                  time_msw;
+/* Upper 32 bits of the time in microseconds used to align the
+ * session origin time. When bits 0-1 of flags is
+ * ASM_SESSION_CMD_RUN_START_RUN_WITH_DELAY, time msw is the msw of
+ * the delay in us. For ASM_SESSION_CMD_RUN_START_RUN_WITH_DELAY,
+ * maximum value of the 64 bit delay is 150 ms.
+ */
+
+} __packed;
+
+#define ASM_SESSION_CMD_PAUSE 0x00010BD3
+#define ASM_SESSION_CMD_GET_SESSIONTIME_V3 0x00010D9D
+#define ASM_SESSION_CMD_REGISTER_FOR_RX_UNDERFLOW_EVENTS 0x00010BD5
+
+struct asm_session_cmd_rgstr_rx_underflow {
+	struct apr_hdr hdr;
+	u16                  enable_flag;
+/* Specifies whether a client is to receive events when an Rx
+ * session underflows.
+ * Supported values:
+ * - 0 -- Do not send underflow events
+ * - 1 -- Send underflow events
+ */
+	u16                  reserved;
+	/* Reserved. This field must be set to zero.*/
+} __packed;
+
+#define ASM_SESSION_CMD_REGISTER_FORX_OVERFLOW_EVENTS 0x00010BD6
+
+struct asm_session_cmd_regx_overflow {
+	struct apr_hdr hdr;
+	u16                  enable_flag;
+/* Specifies whether a client is to receive events when a Tx
+* session overflows.
+ * Supported values:
+ * - 0 -- Do not send overflow events
+ * - 1 -- Send overflow events
+ */
+
+	u16                  reserved;
+	/* Reserved. This field must be set to zero.*/
+} __packed;
+
+#define ASM_SESSION_EVENT_RX_UNDERFLOW        0x00010C17
+#define ASM_SESSION_EVENTX_OVERFLOW           0x00010C18
+#define ASM_SESSION_CMDRSP_GET_SESSIONTIME_V3 0x00010D9E
+
+struct asm_session_cmdrsp_get_sessiontime_v3 {
+	u32                  status;
+	/* Status message (error code).
+	* Supported values: Refer to @xhyperref{Q3,[Q3]}
+	*/
+
+	u32                  sessiontime_lsw;
+	/* Lower 32 bits of the current session time in microseconds.*/
+
+	u32                  sessiontime_msw;
+	/* Upper 32 bits of the current session time in microseconds.*/
+
+	u32                  absolutetime_lsw;
+/* Lower 32 bits in micro seconds of the absolute time at which
+ * the * sample corresponding to the above session time gets
+ * rendered * to hardware. This absolute time may be slightly in the
+ * future or past.
+ */
+
+
+	u32                  absolutetime_msw;
+/* Upper 32 bits in micro seconds of the absolute time at which
+ * the * sample corresponding to the above session time gets
+ * rendered to * hardware. This absolute time may be slightly in the
+ * future or past.
+ */
+
+} __packed;
+
+#define ASM_SESSION_CMD_ADJUST_SESSION_CLOCK_V2     0x00010D9F
+
+struct asm_session_cmd_adjust_session_clock_v2 {
+	struct apr_hdr hdr;
+u32                  adjustime_lsw;
+/* Lower 32 bits of the signed 64-bit quantity that specifies the
+ * adjustment time in microseconds to the session clock.
+ *
+ * Positive values indicate advancement of the session clock.
+ * Negative values indicate delay of the session clock.
+ */
+
+
+	u32                  adjustime_msw;
+/* Upper 32 bits of the signed 64-bit quantity that specifies
+ * the adjustment time in microseconds to the session clock.
+ * Positive values indicate advancement of the session clock.
+ * Negative values indicate delay of the session clock.
+ */
+
+} __packed;
+
+#define ASM_SESSION_CMDRSP_ADJUST_SESSION_CLOCK_V2    0x00010DA0
+
+struct asm_session_cmdrsp_adjust_session_clock_v2 {
+	u32                  status;
+/* Status message (error code).
+ * Supported values: Refer to @xhyperref{Q3,[Q3]}
+ * An error means the session clock is not adjusted. In this case,
+ * the next two fields are irrelevant.
+ */
+
+
+	u32                  actual_adjustime_lsw;
+/* Lower 32 bits of the signed 64-bit quantity that specifies
+ * the actual adjustment in microseconds performed by the aDSP.
+ * A positive value indicates advancement of the session clock. A
+ * negative value indicates delay of the session clock.
+ */
+
+
+	u32                  actual_adjustime_msw;
+/* Upper 32 bits of the signed 64-bit quantity that specifies
+ * the actual adjustment in microseconds performed by the aDSP.
+ * A positive value indicates advancement of the session clock. A
+ * negative value indicates delay of the session clock.
+ */
+
+
+	u32                  cmd_latency_lsw;
+/* Lower 32 bits of the unsigned 64-bit quantity that specifies
+ * the amount of time in microseconds taken to perform the session
+ * clock adjustment.
+ */
+
+
+	u32                  cmd_latency_msw;
+/* Upper 32 bits of the unsigned 64-bit quantity that specifies
+ * the amount of time in microseconds taken to perform the session
+ * clock adjustment.
+ */
+
+} __packed;
+
+#define ASM_SESSION_CMD_GET_PATH_DELAY_V2	 0x00010DAF
+#define ASM_SESSION_CMDRSP_GET_PATH_DELAY_V2 0x00010DB0
+
+struct asm_session_cmdrsp_get_path_delay_v2 {
+	u32                  status;
+/* Status message (error code). Whether this get delay operation
+ * is successful or not. Delay value is valid only if status is
+ * success.
+ * Supported values: Refer to @xhyperref{Q5,[Q5]}
+ */
+
+	u32                  audio_delay_lsw;
+	/* Upper 32 bits of the aDSP delay in microseconds. */
+
+	u32                  audio_delay_msw;
+	/* Lower 32 bits of the aDSP delay  in microseconds. */
+
+} __packed;
+
+/* adsp_asm_session_command.h*/
+#define ASM_STREAM_CMD_OPEN_WRITE_V2       0x00010D8F
+
+struct asm_stream_cmd_open_write_v2 {
+	struct apr_hdr			hdr;
+	uint32_t                    mode_flags;
+/* Mode flags that configure the stream to notify the client
+ * whenever it detects an SR/CM change at the input to its POPP.
+ * Supported values for bits 0 to 1:
+ * - Reserved; clients must set them to zero.
+ * Supported values for bit 2:
+ * - 0 -- SR/CM change notification event is disabled.
+ * - 1 -- SR/CM change notification event is enabled.
+ * - Use #ASM_BIT_MASK_SR_CM_CHANGE_NOTIFY_FLAG and
+ * #ASM_SHIFT_SR_CM_CHANGE_NOTIFY_FLAG to set or get this bit.
+ *
+ * Supported values for bit 31:
+ * - 0 -- Stream to be opened in on-Gapless mode.
+ * - 1 -- Stream to be opened in Gapless mode. In Gapless mode,
+ * successive streams must be opened with same session ID but
+ * different stream IDs.
+ *
+ * - Use #ASM_BIT_MASK_GAPLESS_MODE_FLAG and
+ * #ASM_SHIFT_GAPLESS_MODE_FLAG to set or get this bit.
+ *
+ *
+ * @note1hang MIDI and DTMF streams cannot be opened in Gapless mode.
+ */
+
+	uint16_t                    sink_endpointype;
+/*< Sink point type.
+ * Supported values:
+ * - 0 -- Device matrix
+ * - Other values are reserved.
+ *
+ * The device matrix is the gateway to the hardware ports.
+ */
+
+	uint16_t                    bits_per_sample;
+/*< Number of bits per sample processed by ASM modules.
+ * Supported values: 16 and 24 bits per sample
+ */
+
+	uint32_t                    postprocopo_id;
+/*< Specifies the topology (order of processing) of
+ * postprocessing algorithms. <i>None</i> means no postprocessing.
+ * Supported values:
+ * - #ASM_STREAM_POSTPROCOPO_ID_DEFAULT
+ * - #ASM_STREAM_POSTPROCOPO_ID_MCH_PEAK_VOL
+ * - #ASM_STREAM_POSTPROCOPO_ID_NONE
+ *
+ * This field can also be enabled through SetParams flags.
+ */
+
+	uint32_t                    dec_fmt_id;
+/*< Configuration ID of the decoder media format.
+ *
+ * Supported values:
+ * - #ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2
+ * - #ASM_MEDIA_FMT_ADPCM
+ * - #ASM_MEDIA_FMT_MP3
+ * - #ASM_MEDIA_FMT_AAC_V2
+ * - #ASM_MEDIA_FMT_DOLBY_AAC
+ * - #ASM_MEDIA_FMT_AMRNB_FS
+ * - #ASM_MEDIA_FMT_AMRWB_FS
+ * - #ASM_MEDIA_FMT_AMR_WB_PLUS_V2
+ * - #ASM_MEDIA_FMT_V13K_FS
+ * - #ASM_MEDIA_FMT_EVRC_FS
+ * - #ASM_MEDIA_FMT_EVRCB_FS
+ * - #ASM_MEDIA_FMT_EVRCWB_FS
+ * - #ASM_MEDIA_FMT_SBC
+ * - #ASM_MEDIA_FMT_WMA_V10PRO_V2
+ * - #ASM_MEDIA_FMT_WMA_V9_V2
+ * - #ASM_MEDIA_FMT_AC3_DEC
+ * - #ASM_MEDIA_FMT_EAC3_DEC
+ * - #ASM_MEDIA_FMT_G711_ALAW_FS
+ * - #ASM_MEDIA_FMT_G711_MLAW_FS
+ * - #ASM_MEDIA_FMT_G729A_FS
+ * - #ASM_MEDIA_FMT_FR_FS
+ * - #ASM_MEDIA_FMT_VORBIS
+ * - #ASM_MEDIA_FMT_FLAC
+ * - #ASM_MEDIA_FMT_EXAMPLE
+ */
+} __packed;
+
+#define ASM_STREAM_CMD_OPEN_READ_V2                 0x00010D8C
+/* Definition of the timestamp type flag bitmask */
+#define ASM_BIT_MASKIMESTAMPYPE_FLAG        (0x00000020UL)
+
+/* Definition of the timestamp type flag shift value. */
+#define ASM_SHIFTIMESTAMPYPE_FLAG 5
+
+/* Relative timestamp is identified by this value.*/
+#define ASM_RELATIVEIMESTAMP      0
+
+/* Absolute timestamp is identified by this value.*/
+#define ASM_ABSOLUTEIMESTAMP      1
+
+
+struct asm_stream_cmd_open_read_v2 {
+	struct apr_hdr hdr;
+	u32                    mode_flags;
+/* Mode flags that indicate whether meta information per encoded
+ * frame is to be provided.
+ * Supported values for bit 4:
+ *
+ * - 0 -- Return data buffer contains all encoded frames only; it
+ * does not contain frame metadata.
+ *
+ * - 1 -- Return data buffer contains an array of metadata and
+ * encoded frames.
+ *
+ * - Use #ASM_BIT_MASK_META_INFO_FLAG as the bitmask and
+ * #ASM_SHIFT_META_INFO_FLAG as the shift value for this bit.
+ *
+ *
+ * Supported values for bit 5:
+ *
+ * - ASM_RELATIVEIMESTAMP -- ASM_DATA_EVENT_READ_DONE_V2 will have
+ * - relative time-stamp.
+ * - ASM_ABSOLUTEIMESTAMP -- ASM_DATA_EVENT_READ_DONE_V2 will
+ * - have absolute time-stamp.
+ *
+ * - Use #ASM_BIT_MASKIMESTAMPYPE_FLAG as the bitmask and
+ * #ASM_SHIFTIMESTAMPYPE_FLAG as the shift value for this bit.
+ *
+ * All other bits are reserved; clients must set them to zero.
+ */
+
+	u32                    src_endpointype;
+/* Specifies the endpoint providing the input samples.
+ * Supported values:
+ * - 0 -- Device matrix
+ * - All other values are reserved; clients must set them to zero.
+ * Otherwise, an error is returned.
+ * The device matrix is the gateway from the tunneled Tx ports.
+ */
+
+	u32                    preprocopo_id;
+/* Specifies the topology (order of processing) of preprocessing
+ * algorithms. <i>None</i> means no preprocessing.
+ * Supported values:
+ * - #ASM_STREAM_PREPROCOPO_ID_DEFAULT
+ * - #ASM_STREAM_PREPROCOPO_ID_NONE
+ *
+ * This field can also be enabled through SetParams flags.
+ */
+
+	u32                    enc_cfg_id;
+/* Media configuration ID for encoded output.
+ * Supported values:
+ * - #ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2
+ * - #ASM_MEDIA_FMT_AAC_V2
+ * - #ASM_MEDIA_FMT_AMRNB_FS
+ * - #ASM_MEDIA_FMT_AMRWB_FS
+ * - #ASM_MEDIA_FMT_V13K_FS
+ * - #ASM_MEDIA_FMT_EVRC_FS
+ * - #ASM_MEDIA_FMT_EVRCB_FS
+ * - #ASM_MEDIA_FMT_EVRCWB_FS
+ * - #ASM_MEDIA_FMT_SBC
+ * - #ASM_MEDIA_FMT_G711_ALAW_FS
+ * - #ASM_MEDIA_FMT_G711_MLAW_FS
+ * - #ASM_MEDIA_FMT_G729A_FS
+ * - #ASM_MEDIA_FMT_EXAMPLE
+ * - #ASM_MEDIA_FMT_WMA_V8
+ */
+
+	u16                    bits_per_sample;
+/* Number of bits per sample processed by ASM modules.
+ * Supported values: 16 and 24 bits per sample
+ */
+
+	u16                    reserved;
+/* Reserved for future use. This field must be set to zero.*/
+} __packed;
+
+#define ASM_POPP_OUTPUT_SR_NATIVE_RATE                                  0
+
+/* Enumeration for the maximum sampling rate at the POPP output.*/
+#define ASM_POPP_OUTPUT_SR_MAX_RATE             48000
+
+#define ASM_STREAM_CMD_OPEN_READWRITE_V2        0x00010D8D
+#define ASM_STREAM_CMD_OPEN_READWRITE_V2        0x00010D8D
+#define ASM_STREAM_CMD_OPEN_READ_V2             0x00010D8C
+
+struct asm_stream_cmd_open_readwrite_v2 {
+	struct apr_hdr         hdr;
+	u32                    mode_flags;
+/* Mode flags.
+ * Supported values for bit 2:
+ * - 0 -- SR/CM change notification event is disabled.
+ * - 1 -- SR/CM change notification event is enabled. Use
+ * #ASM_BIT_MASK_SR_CM_CHANGE_NOTIFY_FLAG and
+ * #ASM_SHIFT_SR_CM_CHANGE_NOTIFY_FLAG to set or
+ * getting this flag.
+ *
+ * Supported values for bit 4:
+ * - 0 -- Return read data buffer contains all encoded frames only; it
+ * does not contain frame metadata.
+ * - 1 -- Return read data buffer contains an array of metadata and
+ * encoded frames.
+ *
+ * All other bits are reserved; clients must set them to zero.
+ */
+
+	u32                    postprocopo_id;
+/* Specifies the topology (order of processing) of postprocessing
+ * algorithms. <i>None</i> means no postprocessing.
+ *
+ * Supported values:
+ * - #ASM_STREAM_POSTPROCOPO_ID_DEFAULT
+ * - #ASM_STREAM_POSTPROCOPO_ID_MCH_PEAK_VOL
+ * - #ASM_STREAM_POSTPROCOPO_ID_NONE
+ */
+
+	u32                    dec_fmt_id;
+/* Specifies the media type of the input data. PCM indicates that
+ * no decoding must be performed, e.g., this is an NT encoder
+ * session.
+ * Supported values:
+ * - #ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2
+ * - #ASM_MEDIA_FMT_ADPCM
+ * - #ASM_MEDIA_FMT_MP3
+ * - #ASM_MEDIA_FMT_AAC_V2
+ * - #ASM_MEDIA_FMT_DOLBY_AAC
+ * - #ASM_MEDIA_FMT_AMRNB_FS
+ * - #ASM_MEDIA_FMT_AMRWB_FS
+ * - #ASM_MEDIA_FMT_V13K_FS
+ * - #ASM_MEDIA_FMT_EVRC_FS
+ * - #ASM_MEDIA_FMT_EVRCB_FS
+ * - #ASM_MEDIA_FMT_EVRCWB_FS
+ * - #ASM_MEDIA_FMT_SBC
+ * - #ASM_MEDIA_FMT_WMA_V10PRO_V2
+ * - #ASM_MEDIA_FMT_WMA_V9_V2
+ * - #ASM_MEDIA_FMT_AMR_WB_PLUS_V2
+ * - #ASM_MEDIA_FMT_AC3_DEC
+ * - #ASM_MEDIA_FMT_G711_ALAW_FS
+ * - #ASM_MEDIA_FMT_G711_MLAW_FS
+ * - #ASM_MEDIA_FMT_G729A_FS
+ * - #ASM_MEDIA_FMT_EXAMPLE
+ */
+
+	u32                    enc_cfg_id;
+/* Specifies the media type for the output of the stream. PCM
+ * indicates that no encoding must be performed, e.g., this is an NT
+ * decoder session.
+ * Supported values:
+ * - #ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2
+ * - #ASM_MEDIA_FMT_AAC_V2
+ * - #ASM_MEDIA_FMT_AMRNB_FS
+ * - #ASM_MEDIA_FMT_AMRWB_FS
+ * - #ASM_MEDIA_FMT_V13K_FS
+ * - #ASM_MEDIA_FMT_EVRC_FS
+ * - #ASM_MEDIA_FMT_EVRCB_FS
+ * - #ASM_MEDIA_FMT_EVRCWB_FS
+ * - #ASM_MEDIA_FMT_SBC
+ * - #ASM_MEDIA_FMT_G711_ALAW_FS
+ * - #ASM_MEDIA_FMT_G711_MLAW_FS
+ * - #ASM_MEDIA_FMT_G729A_FS
+ * - #ASM_MEDIA_FMT_EXAMPLE
+ * - #ASM_MEDIA_FMT_WMA_V8
+ */
+
+	u16                    bits_per_sample;
+/* Number of bits per sample processed by ASM modules.
+ * Supported values: 16 and 24 bits per sample
+ */
+
+	u16                    reserved;
+/* Reserved for future use. This field must be set to zero.*/
+
+} __packed;
+
+#define ASM_STREAM_CMD_OPEN_LOOPBACK_V2 0x00010D8E
+struct asm_stream_cmd_open_loopback_v2 {
+	struct apr_hdr         hdr;
+	u32                    mode_flags;
+/* Mode flags.
+ * Bit 0-31: reserved; client should set these bits to 0
+ */
+	u16                    src_endpointype;
+	/* Endpoint type. 0 = Tx Matrix */
+	u16                    sink_endpointype;
+	/* Endpoint type. 0 = Rx Matrix */
+	u32                    postprocopo_id;
+/* Postprocessor topology ID. Specifies the topology of
+ * postprocessing algorithms.
+ */
+
+	u16                    bits_per_sample;
+/* The number of bits per sample processed by ASM modules
+ * Supported values: 16 and 24 bits per sample
+ */
+	u16                    reserved;
+/* Reserved for future use. This field must be set to zero. */
+} __packed;
+
+#define ASM_STREAM_CMD_CLOSE             0x00010BCD
+#define ASM_STREAM_CMD_FLUSH             0x00010BCE
+
+
+#define ASM_STREAM_CMD_FLUSH_READBUFS   0x00010C09
+#define ASM_STREAM_CMD_SET_PP_PARAMS_V2 0x00010DA1
+
+struct asm_stream_cmd_set_pp_params_v2 {
+	u32                  data_payload_addr_lsw;
+/* LSW of parameter data payload address. Supported values: any. */
+	u32                  data_payload_addr_msw;
+/* MSW of Parameter data payload address. Supported values: any.
+ * - Must be set to zero for in-band data.
+ * - In the case of 32 bit Shared memory address, msw  field must be
+ * - set to zero.
+ * - In the case of 36 bit shared memory address, bit 31 to bit 4 of
+ * msw
+ *
+ * - must be set to zero.
+ */
+	u32                  mem_map_handle;
+/* Supported Values: Any.
+* memory map handle returned by DSP through
+* ASM_CMD_SHARED_MEM_MAP_REGIONS
+* command.
+* if mmhandle is NULL, the ParamData payloads are within the
+* message payload (in-band).
+* If mmhandle is non-NULL, the ParamData payloads begin at the
+* address specified in the address msw and lsw (out-of-band).
+*/
+
+	u32                  data_payload_size;
+/* Size in bytes of the variable payload accompanying the
+message, or in shared memory. This field is used for parsing the
+parameter payload. */
+
+} __packed;
+
+
+struct asm_stream_param_data_v2 {
+	u32                  module_id;
+	/* Unique module ID. */
+
+	u32                  param_id;
+	/* Unique parameter ID. */
+
+	u16                  param_size;
+/* Data size of the param_id/module_id combination. This is
+ * a multiple of 4 bytes.
+ */
+
+	u16                  reserved;
+/* Reserved for future enhancements. This field must be set to
+ * zero.
+ */
+
+} __packed;
+
+#define ASM_STREAM_CMD_GET_PP_PARAMS_V2		0x00010DA2
+
+struct asm_stream_cmd_get_pp_params_v2 {
+	u32                  data_payload_addr_lsw;
+	/* LSW of the parameter data payload address. */
+	u32                  data_payload_addr_msw;
+/* MSW of the parameter data payload address.
+ * - Size of the shared memory, if specified, shall be large enough
+ * to contain the whole ParamData payload, including Module ID,
+ * Param ID, Param Size, and Param Values
+ * - Must be set to zero for in-band data
+ * - In the case of 32 bit Shared memory address, msw field must be
+ * set to zero.
+ * - In the case of 36 bit shared memory address, bit 31 to bit 4 of
+ * msw must be set to zero.
+ */
+
+	u32                  mem_map_handle;
+/* Supported Values: Any.
+* memory map handle returned by DSP through ASM_CMD_SHARED_MEM_MAP_REGIONS
+* command.
+* if mmhandle is NULL, the ParamData payloads in the ACK are within the
+* message payload (in-band).
+* If mmhandle is non-NULL, the ParamData payloads in the ACK begin at the
+* address specified in the address msw and lsw.
+* (out-of-band).
+*/
+
+	u32                  module_id;
+	/* Unique module ID. */
+
+	u32                  param_id;
+	/* Unique parameter ID. */
+
+	u16                  param_max_size;
+/* Maximum data size of the module_id/param_id combination. This
+ * is a multiple of 4 bytes.
+ */
+
+
+	u16                  reserved;
+/* Reserved for backward compatibility. Clients must set this
+* field to zero.
+*/
+
+} __packed;
+
+#define ASM_STREAM_CMD_SET_ENCDEC_PARAM 0x00010C10
+
+#define ASM_PARAM_ID_ENCDEC_BITRATE     0x00010C13
+
+struct asm_bitrate_param {
+	u32                  bitrate;
+/* Maximum supported bitrate. Only the AAC encoder is supported.*/
+
+} __packed;
+
+#define ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2 0x00010DA3
+#define ASM_PARAM_ID_AAC_SBR_PS_FLAG		 0x00010C63
+
+/* Flag to turn off both SBR and PS processing, if they are
+ * present in the bitstream.
+ */
+
+#define ASM_AAC_SBR_OFF_PS_OFF (2)
+
+/* Flag to turn on SBR but turn off PS processing,if they are
+ * present in the bitstream.
+ */
+
+#define ASM_AAC_SBR_ON_PS_OFF  (1)
+
+/* Flag to turn on both SBR and PS processing, if they are
+ * present in the bitstream (default behavior).
+ */
+
+
+#define ASM_AAC_SBR_ON_PS_ON   (0)
+
+/* Structure for an AAC SBR PS processing flag. */
+
+/*  Payload of the #ASM_PARAM_ID_AAC_SBR_PS_FLAG parameter in the
+ * #ASM_STREAM_CMD_SET_ENCDEC_PARAM command.
+ */
+struct asm_aac_sbr_ps_flag_param {
+	struct apr_hdr hdr;
+	struct asm_stream_cmd_set_encdec_param  encdec;
+	struct asm_enc_cfg_blk_param_v2	encblk;
+
+	u32                  sbr_ps_flag;
+/* Control parameter to enable or disable SBR/PS processing in
+ * the AAC bitstream. Use the following macros to set this field:
+ * - #ASM_AAC_SBR_OFF_PS_OFF -- Turn off both SBR and PS
+ * processing, if they are present in the bitstream.
+ * - #ASM_AAC_SBR_ON_PS_OFF -- Turn on SBR processing, but not PS
+ * processing, if they are present in the bitstream.
+ * - #ASM_AAC_SBR_ON_PS_ON -- Turn on both SBR and PS processing,
+ * if they are present in the bitstream (default behavior).
+ * - All other values are invalid.
+ * Changes are applied to the next decoded frame.
+ */
+} __packed;
+
+#define ASM_PARAM_ID_AAC_DUAL_MONO_MAPPING                      0x00010C64
+
+/*	First single channel element in a dual mono bitstream.*/
+#define ASM_AAC_DUAL_MONO_MAP_SCE_1                                 (1)
+
+/*	Second single channel element in a dual mono bitstream.*/
+#define ASM_AAC_DUAL_MONO_MAP_SCE_2                                 (2)
+
+/* Structure for AAC decoder dual mono channel mapping. */
+
+
+struct asm_aac_dual_mono_mapping_param {
+	struct apr_hdr							hdr;
+	struct asm_stream_cmd_set_encdec_param	encdec;
+	struct asm_enc_cfg_blk_param_v2			encblk;
+	u16    left_channel_sce;
+	u16    right_channel_sce;
+
+} __packed;
+
+#define ASM_STREAM_CMDRSP_GET_PP_PARAMS_V2 0x00010DA4
+
+struct asm_stream_cmdrsp_get_pp_params_v2 {
+	u32                  status;
+} __packed;
+
+#define ASM_PARAM_ID_AC3_KARAOKE_MODE 0x00010D73
+
+/* Enumeration for both vocals in a karaoke stream.*/
+#define AC3_KARAOKE_MODE_NO_VOCAL     (0)
+
+/* Enumeration for only the left vocal in a karaoke stream.*/
+#define AC3_KARAOKE_MODE_LEFT_VOCAL   (1)
+
+/* Enumeration for only the right vocal in a karaoke stream.*/
+#define AC3_KARAOKE_MODE_RIGHT_VOCAL (2)
+
+/* Enumeration for both vocal channels in a karaoke stream.*/
+#define AC3_KARAOKE_MODE_BOTH_VOCAL             (3)
+#define ASM_PARAM_ID_AC3_DRC_MODE               0x00010D74
+/* Enumeration for the Custom Analog mode.*/
+#define AC3_DRC_MODE_CUSTOM_ANALOG              (0)
+
+/* Enumeration for the Custom Digital mode.*/
+#define AC3_DRC_MODE_CUSTOM_DIGITAL             (1)
+/* Enumeration for the Line Out mode (light compression).*/
+#define AC3_DRC_MODE_LINE_OUT  (2)
+
+/* Enumeration for the RF remodulation mode (heavy compression).*/
+#define AC3_DRC_MODE_RF_REMOD                         (3)
+#define ASM_PARAM_ID_AC3_DUAL_MONO_MODE               0x00010D75
+
+/* Enumeration for playing dual mono in stereo mode.*/
+#define AC3_DUAL_MONO_MODE_STEREO                     (0)
+
+/* Enumeration for playing left mono.*/
+#define AC3_DUAL_MONO_MODE_LEFT_MONO                  (1)
+
+/* Enumeration for playing right mono.*/
+#define AC3_DUAL_MONO_MODE_RIGHT_MONO                 (2)
+
+/* Enumeration for mixing both dual mono channels and playing them.*/
+#define AC3_DUAL_MONO_MODE_MIXED_MONO        (3)
+#define ASM_PARAM_ID_AC3_STEREO_DOWNMIX_MODE 0x00010D76
+
+/* Enumeration for using the Downmix mode indicated in the bitstream. */
+
+#define AC3_STEREO_DOWNMIX_MODE_AUTO_DETECT  (0)
+
+/* Enumeration for Surround Compatible mode (preserves the
+ * surround information).
+ */
+
+#define AC3_STEREO_DOWNMIX_MODE_LT_RT        (1)
+/* Enumeration for Mono Compatible mode (if the output is to be
+ * further downmixed to mono).
+ */
+
+#define AC3_STEREO_DOWNMIX_MODE_LO_RO (2)
+
+/* ID of the AC3 PCM scale factor parameter in the
+ * #ASM_STREAM_CMD_SET_ENCDEC_PARAM command.
+ */
+#define ASM_PARAM_ID_AC3_PCM_SCALEFACTOR 0x00010D78
+
+/* ID of the AC3 DRC boost scale factor parameter in the
+ * #ASM_STREAM_CMD_SET_ENCDEC_PARAM command.
+ */
+#define ASM_PARAM_ID_AC3_DRC_BOOST_SCALEFACTOR 0x00010D79
+
+/* ID of the AC3 DRC cut scale factor parameter in the
+ * #ASM_STREAM_CMD_SET_ENCDEC_PARAM command.
+ */
+#define ASM_PARAM_ID_AC3_DRC_CUT_SCALEFACTOR 0x00010D7A
+
+/* Structure for AC3 Generic Parameter. */
+
+/*  Payload of the AC3 parameters in the
+ * #ASM_STREAM_CMD_SET_ENCDEC_PARAM command.
+ */
+struct asm_ac3_generic_param {
+	struct apr_hdr hdr;
+	struct asm_stream_cmd_set_encdec_param  encdec;
+	struct asm_enc_cfg_blk_param_v2	encblk;
+	u32                  generic_parameter;
+/* AC3 generic parameter. Select from one of the following
+ * possible values.
+ *
+ * For #ASM_PARAM_ID_AC3_KARAOKE_MODE, supported values are:
+ * - AC3_KARAOKE_MODE_NO_VOCAL
+ * - AC3_KARAOKE_MODE_LEFT_VOCAL
+ * - AC3_KARAOKE_MODE_RIGHT_VOCAL
+ * - AC3_KARAOKE_MODE_BOTH_VOCAL
+ *
+ * For #ASM_PARAM_ID_AC3_DRC_MODE, supported values are:
+ * - AC3_DRC_MODE_CUSTOM_ANALOG
+ * - AC3_DRC_MODE_CUSTOM_DIGITAL
+ * - AC3_DRC_MODE_LINE_OUT
+ * - AC3_DRC_MODE_RF_REMOD
+ *
+ * For #ASM_PARAM_ID_AC3_DUAL_MONO_MODE, supported values are:
+ * - AC3_DUAL_MONO_MODE_STEREO
+ * - AC3_DUAL_MONO_MODE_LEFT_MONO
+ * - AC3_DUAL_MONO_MODE_RIGHT_MONO
+ * - AC3_DUAL_MONO_MODE_MIXED_MONO
+ *
+ * For #ASM_PARAM_ID_AC3_STEREO_DOWNMIX_MODE, supported values are:
+ * - AC3_STEREO_DOWNMIX_MODE_AUTO_DETECT
+ * - AC3_STEREO_DOWNMIX_MODE_LT_RT
+ * - AC3_STEREO_DOWNMIX_MODE_LO_RO
+ *
+ * For #ASM_PARAM_ID_AC3_PCM_SCALEFACTOR, supported values are
+ * 0 to 1 in Q31 format.
+ *
+ * For #ASM_PARAM_ID_AC3_DRC_BOOST_SCALEFACTOR, supported values are
+ * 0 to 1 in Q31 format.
+ *
+ * For #ASM_PARAM_ID_AC3_DRC_CUT_SCALEFACTOR, supported values are
+ * 0 to 1 in Q31 format.
+ */
+} __packed;
+
+/* Enumeration for Raw mode (no downmixing), which specifies
+ * that all channels in the bitstream are to be played out as is
+ * without any downmixing. (Default)
+ */
+
+#define WMAPRO_CHANNEL_MASK_RAW (-1)
+
+/* Enumeration for setting the channel mask to 0. The 7.1 mode
+ * (Home Theater) is assigned.
+ */
+
+
+#define WMAPRO_CHANNEL_MASK_ZERO 0x0000
+
+/* Speaker layout mask for one channel (Home Theater, mono).
+ * - Speaker front center
+ */
+#define WMAPRO_CHANNEL_MASK_1_C 0x0004
+
+/* Speaker layout mask for two channels (Home Theater, stereo).
+ * - Speaker front left
+ * - Speaker front right
+ */
+#define WMAPRO_CHANNEL_MASK_2_L_R 0x0003
+
+/* Speaker layout mask for three channels (Home Theater).
+ * - Speaker front left
+ * - Speaker front right
+ * - Speaker front center
+ */
+#define WMAPRO_CHANNEL_MASK_3_L_C_R 0x0007
+
+/* Speaker layout mask for two channels (stereo).
+ * - Speaker back left
+ * - Speaker back right
+ */
+#define WMAPRO_CHANNEL_MASK_2_Bl_Br  0x0030
+
+/* Speaker layout mask for four channels.
+ * - Speaker front left
+ * - Speaker front right
+ * - Speaker back left
+ * - Speaker back right
+*/
+#define WMAPRO_CHANNEL_MASK_4_L_R_Bl_Br 0x0033
+
+/* Speaker layout mask for four channels (Home Theater).
+ * - Speaker front left
+ * - Speaker front right
+ * - Speaker front center
+ * - Speaker back center
+*/
+#define WMAPRO_CHANNEL_MASK_4_L_R_C_Bc_HT 0x0107
+/* Speaker layout mask for five channels.
+ * - Speaker front left
+ * - Speaker front right
+ * - Speaker front center
+ * - Speaker back left
+ * - Speaker back right
+ */
+#define WMAPRO_CHANNEL_MASK_5_L_C_R_Bl_Br  0x0037
+
+/* Speaker layout mask for five channels (5 mode, Home Theater).
+ * - Speaker front left
+ * - Speaker front right
+ * - Speaker front center
+ * - Speaker side left
+ * - Speaker side right
+ */
+#define WMAPRO_CHANNEL_MASK_5_L_C_R_Sl_Sr_HT   0x0607
+/* Speaker layout mask for six channels (5.1 mode).
+ * - Speaker front left
+ * - Speaker front right
+ * - Speaker front center
+ * - Speaker low frequency
+ * - Speaker back left
+ * - Speaker back right
+ */
+#define WMAPRO_CHANNEL_MASK_5DOT1_L_C_R_Bl_Br_SLF  0x003F
+/* Speaker layout mask for six channels (5.1 mode, Home Theater).
+ * - Speaker front left
+ * - Speaker front right
+ * - Speaker front center
+ * - Speaker low frequency
+ * - Speaker side left
+ * - Speaker side right
+ */
+#define WMAPRO_CHANNEL_MASK_5DOT1_L_C_R_Sl_Sr_SLF_HT  0x060F
+/* Speaker layout mask for six channels (5.1 mode, no LFE).
+ * - Speaker front left
+ * - Speaker front right
+ * - Speaker front center
+ * - Speaker back left
+ * - Speaker back right
+ * - Speaker back center
+ */
+#define WMAPRO_CHANNEL_MASK_5DOT1_L_C_R_Bl_Br_Bc  0x0137
+/* Speaker layout mask for six channels (5.1 mode, Home Theater,
+  * no LFE).
+  * - Speaker front left
+  * - Speaker front right
+  * - Speaker front center
+  * - Speaker back center
+  * - Speaker side left
+  * - Speaker side right
+ */
+#define WMAPRO_CHANNEL_MASK_5DOT1_L_C_R_Sl_Sr_Bc_HT   0x0707
+
+/* Speaker layout mask for seven channels (6.1 mode).
+ * - Speaker front left
+ * - Speaker front right
+ * - Speaker front center
+ * - Speaker low frequency
+ * - Speaker back left
+ * - Speaker back right
+ * - Speaker back center
+ */
+#define WMAPRO_CHANNEL_MASK_6DOT1_L_C_R_Bl_Br_Bc_SLF   0x013F
+
+/* Speaker layout mask for seven channels (6.1 mode, Home
+  * Theater).
+  * - Speaker front left
+  * - Speaker front right
+  * - Speaker front center
+  * - Speaker low frequency
+  * - Speaker back center
+  * - Speaker side left
+  * - Speaker side right
+*/
+#define WMAPRO_CHANNEL_MASK_6DOT1_L_C_R_Sl_Sr_Bc_SLF_HT 0x070F
+
+/* Speaker layout mask for seven channels (6.1 mode, no LFE).
+ * - Speaker front left
+ * - Speaker front right
+ * - Speaker front center
+ * - Speaker back left
+ * - Speaker back right
+ * - Speaker front left of center
+ * - Speaker front right of center
+*/
+#define WMAPRO_CHANNEL_MASK_6DOT1_L_C_R_Bl_Br_SFLOC_SFROC   0x00F7
+
+/* Speaker layout mask for seven channels (6.1 mode, Home
+ * Theater, no LFE).
+ * - Speaker front left
+ * - Speaker front right
+ * - Speaker front center
+ * - Speaker side left
+ * - Speaker side right
+ * - Speaker front left of center
+ * - Speaker front right of center
+*/
+#define WMAPRO_CHANNEL_MASK_6DOT1_L_C_R_Sl_Sr_SFLOC_SFROC_HT 0x0637
+
+/* Speaker layout mask for eight channels (7.1 mode).
+ * - Speaker front left
+ * - Speaker front right
+ * - Speaker front center
+ * - Speaker back left
+ * - Speaker back right
+ * - Speaker low frequency
+ * - Speaker front left of center
+ * - Speaker front right of center
+ */
+#define WMAPRO_CHANNEL_MASK_7DOT1_L_C_R_Bl_Br_SLF_SFLOC_SFROC \
+					0x00FF
+
+/* Speaker layout mask for eight channels (7.1 mode, Home Theater).
+ * - Speaker front left
+ * - Speaker front right
+ * - Speaker front center
+ * - Speaker side left
+ * - Speaker side right
+ * - Speaker low frequency
+ * - Speaker front left of center
+ * - Speaker front right of center
+ *
+*/
+#define WMAPRO_CHANNEL_MASK_7DOT1_L_C_R_Sl_Sr_SLF_SFLOC_SFROC_HT \
+					0x063F
+
+#define ASM_PARAM_ID_DEC_OUTPUT_CHAN_MAP  0x00010D82
+
+/*	Maximum number of decoder output channels.*/
+#define MAX_CHAN_MAP_CHANNELS  16
+
+/* Structure for decoder output channel mapping. */
+
+/* Payload of the #ASM_PARAM_ID_DEC_OUTPUT_CHAN_MAP parameter in the
+ * #ASM_STREAM_CMD_SET_ENCDEC_PARAM command.
+ */
+struct asm_dec_out_chan_map_param {
+	struct apr_hdr hdr;
+	struct asm_stream_cmd_set_encdec_param  encdec;
+	struct asm_enc_cfg_blk_param_v2	encblk;
+	u32                 num_channels;
+/* Number of decoder output channels.
+ * Supported values: 0 to #MAX_CHAN_MAP_CHANNELS
+ *
+ * A value of 0 indicates native channel mapping, which is valid
+ * only for NT mode. This means the output of the decoder is to be
+ * preserved as is.
+ */
+	u8                  channel_mapping[MAX_CHAN_MAP_CHANNELS];
+} __packed;
+
+#define ASM_STREAM_CMD_OPEN_WRITE_COMPRESSED  0x00010D84
+
+/* Bitmask for the IEC 61937 enable flag.*/
+#define ASM_BIT_MASK_IEC_61937_STREAM_FLAG   (0x00000001UL)
+
+/* Shift value for the IEC 61937 enable flag.*/
+#define ASM_SHIFT_IEC_61937_STREAM_FLAG  0
+
+/* Bitmask for the IEC 60958 enable flag.*/
+#define ASM_BIT_MASK_IEC_60958_STREAM_FLAG   (0x00000002UL)
+
+/* Shift value for the IEC 60958 enable flag.*/
+#define ASM_SHIFT_IEC_60958_STREAM_FLAG   1
+
+/* Payload format for open write compressed comand */
+
+/* Payload format for the #ASM_STREAM_CMD_OPEN_WRITE_COMPRESSED
+ * comand, which opens a stream for a given session ID and stream ID
+ * to be rendered in the compressed format.
+ */
+
+struct asm_stream_cmd_open_write_compressed {
+	struct apr_hdr hdr;
+	u32                    flags;
+/* Mode flags that configure the stream for a specific format.
+ * Supported values:
+ * - Bit 0 -- IEC 61937 compatibility
+ *   - 0 -- Stream is not in IEC 61937 format
+ *   - 1 -- Stream is in IEC 61937 format
+ * - Bit 1 -- IEC 60958 compatibility
+ *   - 0 -- Stream is not in IEC 60958 format
+ *   - 1 -- Stream is in IEC 60958 format
+ * - Bits 2 to 31 -- 0 (Reserved)
+ *
+ * For the same stream, bit 0 cannot be set to 0 and bit 1 cannot
+ * be set to 1. A compressed stream connot have IEC 60958
+ * packetization applied without IEC 61937 packetization.
+ * @note1hang Currently, IEC 60958 packetized input streams are not
+ * supported.
+ */
+
+
+	u32                    fmt_id;
+/* Specifies the media type of the HDMI stream to be opened.
+ * Supported values:
+ * - #ASM_MEDIA_FMT_AC3_DEC
+ * - #ASM_MEDIA_FMT_EAC3_DEC
+ * - #ASM_MEDIA_FMT_DTS
+ * - #ASM_MEDIA_FMT_ATRAC
+ * - #ASM_MEDIA_FMT_MAT
+ *
+ * @note1hang This field must be set to a valid media type even if
+ * IEC 61937 packetization is not performed by the aDSP.
+ */
+
+} __packed;
+
+#define ASM_STREAM_CMD_OPEN_READ_COMPRESSED                        0x00010D95
+
+struct asm_stream_cmd_open_read_compressed {
+	struct apr_hdr hdr;
+	u32                    mode_flags;
+/* Mode flags that indicate whether meta information per encoded
+ * frame is to be provided.
+ * Supported values for bit 4:
+ * - 0 -- Return data buffer contains all encoded frames only; it does
+ *      not contain frame metadata.
+ * - 1 -- Return data buffer contains an array of metadata and encoded
+ *      frames.
+ * - Use #ASM_BIT_MASK_META_INFO_FLAG to set the bitmask and
+ * #ASM_SHIFT_META_INFO_FLAG to set the shift value for this bit.
+ * All other bits are reserved; clients must set them to zero.
+ */
+
+	u32                    frames_per_buf;
+/* Indicates the number of frames that need to be returned per
+ * read buffer
+ * Supported values: should be greater than 0
+ */
+
+} __packed;
+
+/* adsp_asm_stream_commands.h*/
+
+
+/* adsp_asm_api.h (no changes)*/
+#define ASM_STREAM_POSTPROCOPO_ID_DEFAULT \
+								0x00010BE4
+#define ASM_STREAM_POSTPROCOPO_ID_PEAKMETER \
+								0x00010D83
+#define ASM_STREAM_POSTPROCOPO_ID_NONE \
+								0x00010C68
+#define ASM_STREAM_POSTPROCOPO_ID_MCH_PEAK_VOL \
+								0x00010D8B
+#define ASM_STREAM_PREPROCOPO_ID_DEFAULT \
+			ASM_STREAM_POSTPROCOPO_ID_DEFAULT
+#define ASM_STREAM_PREPROCOPO_ID_NONE \
+			ASM_STREAM_POSTPROCOPO_ID_NONE
+#define ADM_CMD_COPP_OPENOPOLOGY_ID_NONE_AUDIO_COPP \
+			0x00010312
+#define ADM_CMD_COPP_OPENOPOLOGY_ID_SPEAKER_MONO_AUDIO_COPP \
+								0x00010313
+#define ADM_CMD_COPP_OPENOPOLOGY_ID_SPEAKER_STEREO_AUDIO_COPP \
+								0x00010314
+#define ADM_CMD_COPP_OPENOPOLOGY_ID_SPEAKER_STEREO_IIR_AUDIO_COPP\
+								0x00010704
+#define ADM_CMD_COPP_OPENOPOLOGY_ID_SPEAKER_MONO_AUDIO_COPP_MBDRCV2\
+								0x0001070D
+#define ADM_CMD_COPP_OPENOPOLOGY_ID_SPEAKER_STEREO_AUDIO_COPP_MBDRCV2\
+								0x0001070E
+#define ADM_CMD_COPP_OPENOPOLOGY_ID_SPEAKER_STEREO_IIR_AUDIO_COPP_MBDRCV2\
+								0x0001070F
+#define ADM_CMD_COPP_OPENOPOLOGY_ID_SPEAKER_MCH_PEAK_VOL \
+								0x0001031B
+#define ADM_CMD_COPP_OPENOPOLOGY_ID_MIC_MONO_AUDIO_COPP  0x00010315
+#define ADM_CMD_COPP_OPENOPOLOGY_ID_MIC_STEREO_AUDIO_COPP 0x00010316
+#define AUDPROC_COPPOPOLOGY_ID_MCHAN_IIR_AUDIO           0x00010715
+#define ADM_CMD_COPP_OPENOPOLOGY_ID_DEFAULT_AUDIO_COPP   0x00010BE3
+#define ADM_CMD_COPP_OPENOPOLOGY_ID_PEAKMETER_AUDIO_COPP 0x00010317
+#define AUDPROC_MODULE_ID_AIG   0x00010716
+#define AUDPROC_PARAM_ID_AIG_ENABLE		0x00010717
+#define AUDPROC_PARAM_ID_AIG_CONFIG		0x00010718
+
+struct Audio_AigParam {
+	uint16_t	mode;
+/*< Mode word for enabling AIG/SIG mode .
+ * Byte offset: 0
+ */
+	int16_t		staticGainL16Q12;
+/*< Static input gain when aigMode is set to 1.
+ * Byte offset: 2
+ */
+	int16_t		initialGainDBL16Q7;
+/*<Initial value that the adaptive gain update starts from dB
+ * Q7 Byte offset: 4
+ */
+	int16_t		idealRMSDBL16Q7;
+/*<Average RMS level that AIG attempts to achieve Q8.7
+ * Byte offset: 6
+ */
+	int32_t		noiseGateL32;
+/*Threshold below which signal is considered as noise and AIG
+ * Byte offset: 8
+ */
+	int32_t		minGainL32Q15;
+/*Minimum gain that can be provided by AIG Q16.15
+ * Byte offset: 12
+ */
+	int32_t		maxGainL32Q15;
+/*Maximum gain that can be provided by AIG Q16.15
+ * Byte offset: 16
+ */
+	uint32_t		gainAtRtUL32Q31;
+/*Attack/release time for AIG update Q1.31
+ * Byte offset: 20
+ */
+	uint32_t		longGainAtRtUL32Q31;
+/*Long attack/release time while updating gain for
+ * noise/silence Q1.31 Byte offset: 24
+ */
+
+	uint32_t		rmsTavUL32Q32;
+/* RMS smoothing time constant used for long-term RMS estimate
+ * Q0.32 Byte offset: 28
+ */
+
+	uint32_t		gainUpdateStartTimMsUL32Q0;
+/* The waiting time before which AIG starts to apply adaptive
+ * gain update Q32.0 Byte offset: 32
+ */
+
+} __packed;
+
+
+#define ADM_MODULE_ID_EANS                            0x00010C4A
+#define ADM_PARAM_ID_EANS_ENABLE                      0x00010C4B
+#define ADM_PARAM_ID_EANS_PARAMS                      0x00010C4C
+
+struct adm_eans_enable {
+
+	uint32_t                  enable_flag;
+/*< Specifies whether EANS is disabled (0) or enabled
+ * (nonzero).
+ * This is supported only for sampling rates of 8, 12, 16, 24, 32,
+ * and 48 kHz. It is not supported for sampling rates of 11.025,
+ * 22.05, or 44.1 kHz.
+ */
+
+} __packed;
+
+
+struct adm_eans_params {
+	int16_t                         eans_mode;
+/*< Mode word for enabling/disabling submodules.
+ * Byte offset: 0
+ */
+
+	int16_t                         eans_input_gain;
+/*< Q2.13 input gain to the EANS module.
+ * Byte offset: 2
+ */
+
+	int16_t                         eans_output_gain;
+/*< Q2.13 output gain to the EANS module.
+ * Byte offset: 4
+ */
+
+	int16_t                         eansarget_ns;
+/*< Target noise suppression level in dB.
+ * Byte offset: 6
+ */
+
+	int16_t                         eans_s_alpha;
+/*< Q3.12 over-subtraction factor for stationary noise
+ * suppression.
+ * Byte offset: 8
+ */
+
+	int16_t                         eans_n_alpha;
+/* < Q3.12 over-subtraction factor for nonstationary noise
+ * suppression.
+ * Byte offset: 10
+ */
+
+	int16_t                         eans_n_alphamax;
+/*< Q3.12 maximum over-subtraction factor for nonstationary
+ * noise suppression.
+ * Byte offset: 12
+ */
+	int16_t                         eans_e_alpha;
+/*< Q15 scaling factor for excess noise suppression.
+ * Byte offset: 14
+ */
+
+	int16_t                         eans_ns_snrmax;
+/*< Upper boundary in dB for SNR estimation.
+ * Byte offset: 16
+ */
+
+	int16_t                         eans_sns_block;
+/*< Quarter block size for stationary noise suppression.
+ * Byte offset: 18
+ */
+
+	int16_t                         eans_ns_i;
+/*< Initialization block size for noise suppression.
+ * Byte offset: 20
+ */
+	int16_t                         eans_np_scale;
+/*< Power scale factor for nonstationary noise update.
+ * Byte offset: 22
+ */
+
+	int16_t                         eans_n_lambda;
+/*< Smoothing factor for higher level nonstationary noise
+ * update.
+ * Byte offset: 24
+ */
+
+	int16_t                         eans_n_lambdaf;
+/*< Medium averaging factor for noise update.
+ * Byte offset: 26
+ */
+
+	int16_t                         eans_gs_bias;
+/*< Bias factor in dB for gain calculation.
+ * Byte offset: 28
+ */
+
+	int16_t                         eans_gs_max;
+/*< SNR lower boundary in dB for aggressive gain calculation.
+ * Byte offset: 30
+ */
+
+	int16_t                         eans_s_alpha_hb;
+/*< Q3.12 over-subtraction factor for high-band stationary
+ * noise suppression.
+ * Byte offset: 32
+ */
+
+	int16_t                         eans_n_alphamax_hb;
+/*< Q3.12 maximum over-subtraction factor for high-band
+ * nonstationary noise suppression.
+ * Byte offset: 34
+ */
+
+	int16_t                         eans_e_alpha_hb;
+/*< Q15 scaling factor for high-band excess noise suppression.
+ * Byte offset: 36
+ */
+
+	int16_t                         eans_n_lambda0;
+/*< Smoothing factor for nonstationary noise update during
+ * speech activity.
+ * Byte offset: 38
+ */
+
+	int16_t                         thresh;
+/*< Threshold for generating a binary VAD decision.
+ * Byte offset: 40
+ */
+
+	int16_t                         pwr_scale;
+/*< Indirect lower boundary of the noise level estimate.
+ * Byte offset: 42
+ */
+
+	int16_t                         hangover_max;
+/*< Avoids mid-speech clipping and reliably detects weak speech
+ * bursts at the end of speech activity.
+ * Byte offset: 44
+ */
+
+	int16_t                         alpha_snr;
+/*< Controls responsiveness of the VAD.
+ * Byte offset: 46
+ */
+
+	int16_t                         snr_diff_max;
+/*< Maximum SNR difference. Decreasing this parameter value may
+ * help in making correct decisions during abrupt changes; however,
+ * decreasing too much may increase false alarms during long
+ * pauses/silences.
+ * Byte offset: 48
+ */
+
+	int16_t                         snr_diff_min;
+/*< Minimum SNR difference. Decreasing this parameter value may
+ * help in making correct decisions during abrupt changes; however,
+ * decreasing too much may increase false alarms during long
+ * pauses/silences.
+ * Byte offset: 50
+ */
+
+	int16_t                         init_length;
+/*< Defines the number of frames for which a noise level
+ * estimate is set to a fixed value.
+ * Byte offset: 52
+ */
+
+	int16_t                         max_val;
+/*< Defines the upper limit of the noise level.
+ * Byte offset: 54
+ */
+
+	int16_t                         init_bound;
+/*< Defines the initial bounding value for the noise level
+ * estimate. This is used during the initial segment defined by the
+ * init_length parameter.
+ * Byte offset: 56
+ */
+
+	int16_t                         reset_bound;
+/*< Reset boundary for noise tracking.
+ * Byte offset: 58
+ */
+
+	int16_t                         avar_scale;
+/*< Defines the bias factor in noise estimation.
+ * Byte offset: 60
+ */
+
+	int16_t                         sub_nc;
+/*< Defines the window length for noise estimation.
+ * Byte offset: 62
+ */
+
+	int16_t                         spow_min;
+/*< Defines the minimum signal power required to update the
+ * boundaries for the noise floor estimate.
+ * Byte offset: 64
+ */
+
+	int16_t                         eans_gs_fast;
+/*< Fast smoothing factor for postprocessor gain.
+ * Byte offset: 66
+ */
+
+	int16_t                         eans_gs_med;
+/*< Medium smoothing factor for postprocessor gain.
+ * Byte offset: 68
+ */
+
+	int16_t                         eans_gs_slow;
+/*< Slow smoothing factor for postprocessor gain.
+ * Byte offset: 70
+ */
+
+	int16_t                         eans_swb_salpha;
+/*< Q3.12 super wideband aggressiveness factor for stationary
+ * noise suppression.
+ * Byte offset: 72
+ */
+
+	int16_t                         eans_swb_nalpha;
+/*< Q3.12 super wideband aggressiveness factor for
+ * nonstationary noise suppression.
+ * Byte offset: 74
+ */
+} __packed;
+#define ADM_MODULE_IDX_MIC_GAIN_CTRL   0x00010C35
+
+/* @addtogroup audio_pp_param_ids
+ * ID of the Tx mic gain control parameter used by the
+ * #ADM_MODULE_IDX_MIC_GAIN_CTRL module.
+ * @messagepayload
+ * @structure{admx_mic_gain}
+ * @tablespace
+ * @inputtable{Audio_Postproc_ADM_PARAM_IDX_MIC_GAIN.tex}
+ */
+#define ADM_PARAM_IDX_MIC_GAIN       0x00010C36
+
+/* Structure for a Tx mic gain parameter for the mic gain
+ * control module.
+ */
+
+
+/* @brief Payload of the #ADM_PARAM_IDX_MIC_GAIN parameter in the
+ * Tx Mic Gain Control module.
+ */
+struct admx_mic_gain {
+	uint16_t                  tx_mic_gain;
+	/*< Linear gain in Q13 format. */
+
+	uint16_t                  reserved;
+	/*< Clients must set this field to zero. */
+} __packed;
+
+/* end_addtogroup audio_pp_param_ids */
+
+/* @ingroup audio_pp_module_ids
+ * ID of the Rx Codec Gain Control module.
+ *
+ * This module supports the following parameter ID:
+ * - #ADM_PARAM_ID_RX_CODEC_GAIN
+ */
+#define ADM_MODULE_ID_RX_CODEC_GAIN_CTRL       0x00010C37
+
+/* @addtogroup audio_pp_param_ids
+ * ID of the Rx codec gain control parameter used by the
+ * #ADM_MODULE_ID_RX_CODEC_GAIN_CTRL module.
+ *
+ * @messagepayload
+ * @structure{adm_rx_codec_gain}
+ * @tablespace
+ * @inputtable{Audio_Postproc_ADM_PARAM_ID_RX_CODEC_GAIN.tex}
+*/
+#define ADM_PARAM_ID_RX_CODEC_GAIN   0x00010C38
+
+/* Structure for the Rx common codec gain control module. */
+
+
+/* @brief Payload of the #ADM_PARAM_ID_RX_CODEC_GAIN parameter
+ * in the Rx Codec Gain Control module.
+ */
+
+
+struct adm_rx_codec_gain {
+	uint16_t                  rx_codec_gain;
+	/*< Linear gain in Q13 format. */
+
+	uint16_t                  reserved;
+	/*< Clients must set this field to zero.*/
+} __packed;
+
+/* end_addtogroup audio_pp_param_ids */
+
+/* @ingroup audio_pp_module_ids
+ * ID of the HPF Tuning Filter module on the Tx path.
+ * This module supports the following parameter IDs:
+ * - #ADM_PARAM_ID_HPF_IIRX_FILTER_ENABLE_CONFIG
+ * - #ADM_PARAM_ID_HPF_IIRX_FILTER_PRE_GAIN
+ * - #ADM_PARAM_ID_HPF_IIRX_FILTER_CONFIG_PARAMS
+ */
+#define ADM_MODULE_ID_HPF_IIRX_FILTER    0x00010C3D
+
+/* @addtogroup audio_pp_param_ids */
+/* ID of the Tx HPF IIR filter enable parameter used by the
+ * #ADM_MODULE_ID_HPF_IIRX_FILTER module.
+ * @parspace Message payload
+ * @structure{adm_hpfx_iir_filter_enable_cfg}
+ * @tablespace
+ * @inputtable{Audio_Postproc_ADM_PARAM_ID_HPF_IIRX_FILTER_ENABLE_CONFIG.tex}
+ */
+#define ADM_PARAM_ID_HPF_IIRX_FILTER_ENABLE_CONFIG   0x00010C3E
+
+/* ID of the Tx HPF IIR filter pregain parameter used by the
+ * #ADM_MODULE_ID_HPF_IIRX_FILTER module.
+ * @parspace Message payload
+ * @structure{adm_hpfx_iir_filter_pre_gain}
+ * @tablespace
+ * @inputtable{Audio_Postproc_ADM_PARAM_ID_HPF_IIRX_FILTER_PRE_GAIN.tex}
+ */
+#define ADM_PARAM_ID_HPF_IIRX_FILTER_PRE_GAIN   0x00010C3F
+
+/* ID of the Tx HPF IIR filter configuration parameters used by the
+ * #ADM_MODULE_ID_HPF_IIRX_FILTER module.
+ * @parspace Message payload
+ * @structure{adm_hpfx_iir_filter_cfg_params}
+ * @tablespace
+ * @inputtable{Audio_Postproc_ADM_PARAM_ID_HPF_IIRX_FILTER_CONFIG_PA
+ * RAMS.tex}
+ */
+#define ADM_PARAM_ID_HPF_IIRX_FILTER_CONFIG_PARAMS  0x00010C40
+
+/* Structure for enabling a configuration parameter for
+ * the HPF IIR tuning filter module on the Tx path.
+ */
+
+/* @brief Payload of the #ADM_PARAM_ID_HPF_IIRX_FILTER_ENABLE_CONFIG
+ * parameter in the Tx path HPF Tuning Filter module.
+ */
+struct adm_hpfx_iir_filter_enable_cfg {
+	uint32_t                  enable_flag;
+/*< Specifies whether the HPF tuning filter is disabled (0) or
+ * enabled (nonzero).
+ */
+} __packed;
+
+
+/* Structure for the pregain parameter for the HPF
+	IIR tuning filter module on the Tx path. */
+
+
+/* @brief Payload of the #ADM_PARAM_ID_HPF_IIRX_FILTER_PRE_GAIN parameter
+ * in the Tx path HPF Tuning Filter module.
+ */
+struct adm_hpfx_iir_filter_pre_gain {
+	uint16_t                  pre_gain;
+	/*< Linear gain in Q13 format. */
+
+	uint16_t                  reserved;
+	/*< Clients must set this field to zero.*/
+} __packed;
+
+
+/* Structure for the configuration parameter for the
+	HPF IIR tuning filter module on the Tx path. */
+
+
+/* @brief Payload of the #ADM_PARAM_ID_HPF_IIRX_FILTER_CONFIG_PARAMS
+ * parameters in the Tx path HPF Tuning Filter module. \n
+ * \n
+ * This structure is followed by tuning filter coefficients as follows: \n
+ * - Sequence of int32_t FilterCoeffs.
+ * Each band has five coefficients, each in int32_t format in the order of
+ * b0, b1, b2, a1, a2.
+ * - Sequence of int16_t NumShiftFactor.
+ * One int16_t per band. The numerator shift factor is related to the Q
+ * factor of the filter coefficients.
+ * - Sequence of uint16_t PanSetting.
+ * One uint16_t for each band to indicate application of the filter to
+ * left (0), right (1), or both (2) channels.
+ */
+struct adm_hpfx_iir_filter_cfg_params {
+	uint16_t                  num_biquad_stages;
+/*< Number of bands.
+ * Supported values: 0 to 20
+ */
+
+	uint16_t                  reserved;
+	/*< Clients must set this field to zero.*/
+} __packed;
+
+/* end_addtogroup audio_pp_module_ids */
+
+/* @addtogroup audio_pp_module_ids */
+/* ID of the Tx path IIR Tuning Filter module.
+ *	This module supports the following parameter IDs:
+ *	- #ADM_PARAM_IDX_IIR_FILTER_ENABLE_CONFIG
+ */
+#define ADM_MODULE_IDX_IIR_FILTER 0x00010C41
+
+/* ID of the Rx path IIR Tuning Filter module for the left channel.
+ *	The parameter IDs of the IIR tuning filter module
+ *	(#ASM_MODULE_ID_IIRUNING_FILTER) are used for the left IIR Rx tuning
+ *	filter.
+ *
+ * Pan parameters are not required for this per-channel IIR filter; the pan
+ * parameters are ignored by this module.
+ */
+#define ADM_MODULE_ID_LEFT_IIRUNING_FILTER      0x00010705
+
+/* ID of the the Rx path IIR Tuning Filter module for the right
+ * channel.
+ * The parameter IDs of the IIR tuning filter module
+ * (#ASM_MODULE_ID_IIRUNING_FILTER) are used for the right IIR Rx
+ * tuning filter.
+ *
+ * Pan parameters are not required for this per-channel IIR filter;
+ * the pan parameters are ignored by this module.
+ */
+#define ADM_MODULE_ID_RIGHT_IIRUNING_FILTER    0x00010706
+
+/* end_addtogroup audio_pp_module_ids */
+
+/* @addtogroup audio_pp_param_ids */
+
+/* ID of the Tx IIR filter enable parameter used by the
+ * #ADM_MODULE_IDX_IIR_FILTER module.
+ * @parspace Message payload
+ * @structure{admx_iir_filter_enable_cfg}
+ * @tablespace
+ * @inputtable{Audio_Postproc_ADM_PARAM_IDX_IIR_FILTER_ENABLE_CONFIG.tex}
+ */
+#define ADM_PARAM_IDX_IIR_FILTER_ENABLE_CONFIG   0x00010C42
+
+/* ID of the Tx IIR filter pregain parameter used by the
+ * #ADM_MODULE_IDX_IIR_FILTER module.
+ * @parspace Message payload
+ * @structure{admx_iir_filter_pre_gain}
+ * @tablespace
+ * @inputtable{Audio_Postproc_ADM_PARAM_IDX_IIR_FILTER_PRE_GAIN.tex}
+ */
+#define ADM_PARAM_IDX_IIR_FILTER_PRE_GAIN    0x00010C43
+
+/* ID of the Tx IIR filter configuration parameters used by the
+ * #ADM_MODULE_IDX_IIR_FILTER module.
+ * @parspace Message payload
+ * @structure{admx_iir_filter_cfg_params}
+ * @tablespace
+ * @inputtable{Audio_Postproc_ADM_PARAM_IDX_IIR_FILTER_CONFIG_PARAMS.tex}
+ */
+#define ADM_PARAM_IDX_IIR_FILTER_CONFIG_PARAMS     0x00010C44
+
+/* Structure for enabling the configuration parameter for the
+ * IIR filter module on the Tx path.
+ */
+
+/* @brief Payload of the #ADM_PARAM_IDX_IIR_FILTER_ENABLE_CONFIG
+ * parameter in the Tx Path IIR Tuning Filter module.
+ */
+
+struct admx_iir_filter_enable_cfg {
+	uint32_t                  enable_flag;
+/*< Specifies whether the IIR tuning filter is disabled (0) or
+ * enabled (nonzero).
+ */
+
+} __packed;
+
+
+/* Structure for the pregain parameter for the
+ * IIR filter module on the Tx path.
+ */
+
+
+/* @brief Payload of the #ADM_PARAM_IDX_IIR_FILTER_PRE_GAIN
+ * parameter in the Tx Path IIR Tuning Filter module.
+ */
+
+struct admx_iir_filter_pre_gain {
+	uint16_t                  pre_gain;
+	/*< Linear gain in Q13 format. */
+
+	uint16_t                  reserved;
+	/*< Clients must set this field to zero.*/
+} __packed;
+
+
+/* Structure for the configuration parameter for the
+ * IIR filter module on the Tx path.
+ */
+
+
+/* @brief Payload of the #ADM_PARAM_IDX_IIR_FILTER_CONFIG_PARAMS
+ * parameter in the Tx Path IIR Tuning Filter module. \n
+ *	\n
+ * This structure is followed by the HPF IIR filter coefficients on
+ * the Tx path as follows: \n
+ * - Sequence of int32_t ulFilterCoeffs. Each band has five
+ * coefficients, each in int32_t format in the order of b0, b1, b2,
+ * a1, a2.
+ * - Sequence of int16_t sNumShiftFactor. One int16_t per band. The
+ * numerator shift factor is related to the Q factor of the filter
+ * coefficients.
+ * - Sequence of uint16_t usPanSetting. One uint16_t for each band
+ * to indicate if the filter is applied to left (0), right (1), or
+ * both (2) channels.
+ */
+struct admx_iir_filter_cfg_params {
+	uint16_t                  num_biquad_stages;
+/*< Number of bands.
+ * Supported values: 0 to 20
+ */
+
+	uint16_t                  reserved;
+	/*< Clients must set this field to zero.*/
+} __packed;
+
+/* end_addtogroup audio_pp_module_ids */
+
+/* @ingroup audio_pp_module_ids
+ *	ID of the QEnsemble module.
+ *	This module supports the following parameter IDs:
+ *	- #ADM_PARAM_ID_QENSEMBLE_ENABLE
+ *	- #ADM_PARAM_ID_QENSEMBLE_BACKGAIN
+ *	- #ADM_PARAM_ID_QENSEMBLE_SET_NEW_ANGLE
+ */
+#define ADM_MODULE_ID_QENSEMBLE    0x00010C59
+
+/* @addtogroup audio_pp_param_ids */
+/* ID of the QEnsemble enable parameter used by the
+ * #ADM_MODULE_ID_QENSEMBLE module.
+ * @messagepayload
+ * @structure{adm_qensemble_enable}
+ * @tablespace
+ * @inputtable{Audio_Postproc_ADM_PARAM_ID_QENSEMBLE_ENABLE.tex}
+ */
+#define ADM_PARAM_ID_QENSEMBLE_ENABLE   0x00010C60
+
+/* ID of the QEnsemble back gain parameter used by the
+ * #ADM_MODULE_ID_QENSEMBLE module.
+ * @messagepayload
+ * @structure{adm_qensemble_param_backgain}
+ * @tablespace
+ * @inputtable{Audio_Postproc_ADM_PARAM_ID_QENSEMBLE_BACKGAIN.tex}
+ */
+#define ADM_PARAM_ID_QENSEMBLE_BACKGAIN   0x00010C61
+
+/* ID of the QEnsemble new angle parameter used by the
+ * #ADM_MODULE_ID_QENSEMBLE module.
+ * @messagepayload
+ * @structure{adm_qensemble_param_set_new_angle}
+ * @tablespace
+ * @inputtable{Audio_Postproc_ADM_PARAM_ID_QENSEMBLE_SET_NEW_ANGLE.tex}
+ */
+#define ADM_PARAM_ID_QENSEMBLE_SET_NEW_ANGLE    0x00010C62
+
+/* Structure for enabling the configuration parameter for the
+ * QEnsemble module.
+ */
+
+
+/* @brief Payload of the #ADM_PARAM_ID_QENSEMBLE_ENABLE
+ * parameter used by the QEnsemble module.
+ */
+struct adm_qensemble_enable {
+	uint32_t                  enable_flag;
+/*< Specifies whether the QEnsemble module is disabled (0) or enabled
+ * (nonzero).
+ */
+} __packed;
+
+
+/* Structure for the background gain for the QEnsemble module. */
+
+
+/* @brief Payload of the #ADM_PARAM_ID_QENSEMBLE_BACKGAIN
+ * parameter used by
+ * the QEnsemble module.
+ */
+struct adm_qensemble_param_backgain {
+	int16_t                  back_gain;
+/*< Linear gain in Q15 format.
+ * Supported values: 0 to 32767
+ */
+
+	uint16_t                 reserved;
+	/*< Clients must set this field to zero.*/
+} __packed;
+/* Structure for setting a new angle for the QEnsemble module. */
+
+
+/* @brief Payload of the #ADM_PARAM_ID_QENSEMBLE_SET_NEW_ANGLE
+ * parameter used
+ * by the QEnsemble module.
+ */
+struct adm_qensemble_param_set_new_angle {
+	int16_t                    new_angle;
+/*< New angle in degrees.
+ * Supported values: 0 to 359
+ */
+
+	int16_t                    time_ms;
+/*< Transition time in milliseconds to set the new angle.
+ * Supported values: 0 to 32767
+ */
+} __packed;
+
+/* end_addtogroup audio_pp_module_ids */
+
+/* @ingroup audio_pp_module_ids
+ * ID of the Volume Control module pre/postprocessing block.
+ * This module supports the following parameter IDs:
+ * - #ASM_PARAM_ID_VOL_CTRL_MASTER_GAIN
+ * - #ASM_PARAM_ID_VOL_CTRL_LR_CHANNEL_GAIN
+ * - #ASM_PARAM_ID_VOL_CTRL_MUTE_CONFIG
+ * - #ASM_PARAM_ID_SOFT_VOL_STEPPING_PARAMETERS
+ * - #ASM_PARAM_ID_SOFT_PAUSE_PARAMETERS
+ * - #ASM_PARAM_ID_MULTICHANNEL_GAIN
+ * - #ASM_PARAM_ID_MULTICHANNEL_MUTE
+ */
+#define ASM_MODULE_ID_VOL_CTRL   0x00010BFE
+
+/* @addtogroup audio_pp_param_ids */
+/* ID of the master gain parameter used by the #ASM_MODULE_ID_VOL_CTRL
+ * module.
+ * @messagepayload
+ * @structure{asm_volume_ctrl_master_gain}
+ * @tablespace
+ * @inputtable{Audio_Postproc_ASM_PARAM_ID_VOL_CTRL_MASTER_GAIN.tex}
+ */
+#define ASM_PARAM_ID_VOL_CTRL_MASTER_GAIN    0x00010BFF
+
+/* ID of the left/right channel gain parameter used by the
+ * #ASM_MODULE_ID_VOL_CTRL module.
+ * @messagepayload
+ * @structure{asm_volume_ctrl_lr_chan_gain}
+ * @tablespace
+ * @inputtable{Audio_Postproc_ASM_PARAM_ID_VOL_CTRL_LR_CHANNEL_GAIN.tex}
+ */
+#define ASM_PARAM_ID_VOL_CTRL_LR_CHANNEL_GAIN     0x00010C00
+
+/* ID of the mute configuration parameter used by the
+ * #ASM_MODULE_ID_VOL_CTRL module.
+ * @messagepayload
+ * @structure{asm_volume_ctrl_mute_config}
+ * @tablespace
+ * @inputtable{Audio_Postproc_ASM_PARAM_ID_VOL_CTRL_MUTE_CONFIG.tex}
+ */
+#define ASM_PARAM_ID_VOL_CTRL_MUTE_CONFIG   0x00010C01
+
+/* ID of the soft stepping volume parameters used by the
+ * #ASM_MODULE_ID_VOL_CTRL module.
+ * @messagepayload
+ * @structure{asm_soft_step_volume_params}
+ * @tablespace
+ * @inputtable{Audio_Postproc_ASM_PARAM_ID_SOFT_VOL_STEPPING_PARAMET
+ * ERS.tex}
+ */
+#define ASM_PARAM_ID_SOFT_VOL_STEPPING_PARAMETERS  0x00010C29
+
+/* ID of the soft pause parameters used by the #ASM_MODULE_ID_VOL_CTRL
+ * module.
+ */
+#define ASM_PARAM_ID_SOFT_PAUSE_PARAMETERS   0x00010D6A
+
+/* ID of the multiple-channel volume control parameters used by the
+ * #ASM_MODULE_ID_VOL_CTRL module.
+ */
+#define ASM_PARAM_ID_MULTICHANNEL_GAIN  0x00010713
+
+/* ID of the multiple-channel mute configuration parameters used by the
+ * #ASM_MODULE_ID_VOL_CTRL module.
+ */
+
+#define ASM_PARAM_ID_MULTICHANNEL_MUTE  0x00010714
+
+/* Structure for the master gain parameter for a volume control
+ * module.
+ */
+
+
+/* @brief Payload of the #ASM_PARAM_ID_VOL_CTRL_MASTER_GAIN
+ * parameter used by the Volume Control module.
+ */
+
+
+
+struct asm_volume_ctrl_master_gain {
+	struct apr_hdr	hdr;
+	struct asm_stream_cmd_set_pp_params_v2 param;
+	struct asm_stream_param_data_v2 data;
+	uint16_t                  master_gain;
+	/*< Linear gain in Q13 format. */
+
+	uint16_t                  reserved;
+	/*< Clients must set this field to zero.
+		*/
+} __packed;
+
+
+/* Structure for the left/right channel gain parameter for a
+ * volume control module.
+ */
+
+
+/* @brief Payload of the #ASM_PARAM_ID_VOL_CTRL_LR_CHANNEL_GAIN
+ * parameters used by the Volume Control module.
+ */
+
+
+
+struct asm_volume_ctrl_lr_chan_gain {
+	struct apr_hdr	hdr;
+	struct asm_stream_cmd_set_pp_params_v2 param;
+	struct asm_stream_param_data_v2 data;
+
+	uint16_t                  l_chan_gain;
+	/*< Linear gain in Q13 format for the left channel. */
+
+	uint16_t                  r_chan_gain;
+	/*< Linear gain in Q13 format for the right channel.*/
+} __packed;
+
+
+/* Structure for the mute configuration parameter for a
+	volume control module. */
+
+
+/* @brief Payload of the #ASM_PARAM_ID_VOL_CTRL_MUTE_CONFIG
+ * parameter used by the Volume Control module.
+ */
+
+
+struct asm_volume_ctrl_mute_config {
+	struct apr_hdr	hdr;
+	struct asm_stream_cmd_set_pp_params_v2 param;
+	struct asm_stream_param_data_v2 data;
+	uint32_t                  mute_flag;
+/*< Specifies whether mute is disabled (0) or enabled (nonzero).*/
+
+} __packed;
+
+/*
+ * Supported parameters for a soft stepping linear ramping curve.
+ */
+#define ASM_PARAM_SVC_RAMPINGCURVE_LINEAR  0
+
+/*
+ * Exponential ramping curve.
+ */
+#define ASM_PARAM_SVC_RAMPINGCURVE_EXP    1
+
+/*
+ * Logarithmic ramping curve.
+ */
+#define ASM_PARAM_SVC_RAMPINGCURVE_LOG    2
+
+/* Structure for holding soft stepping volume parameters. */
+
+
+/*  Payload of the #ASM_PARAM_ID_SOFT_VOL_STEPPING_PARAMETERS
+ * parameters used by the Volume Control module.
+ */
+struct asm_soft_step_volume_params {
+	struct apr_hdr	hdr;
+	struct asm_stream_cmd_set_pp_params_v2 param;
+	struct asm_stream_param_data_v2 data;
+	uint32_t                  period;
+/*< Period in milliseconds.
+ * Supported values: 0 to 15000
+ */
+
+	uint32_t                  step;
+/*< Step in microseconds.
+ * Supported values: 0 to 15000000
+ */
+
+	uint32_t                  ramping_curve;
+/*< Ramping curve type.
+ * Supported values:
+ * - #ASM_PARAM_SVC_RAMPINGCURVE_LINEAR
+ * - #ASM_PARAM_SVC_RAMPINGCURVE_EXP
+ * - #ASM_PARAM_SVC_RAMPINGCURVE_LOG
+ */
+} __packed;
+
+
+/* Structure for holding soft pause parameters. */
+
+
+/* Payload of the #ASM_PARAM_ID_SOFT_PAUSE_PARAMETERS
+ * parameters used by the Volume Control module.
+ */
+
+
+struct asm_soft_pause_params {
+	struct apr_hdr	hdr;
+	struct asm_stream_cmd_set_pp_params_v2 param;
+	struct asm_stream_param_data_v2 data;
+	uint32_t                  enable_flag;
+/*< Specifies whether soft pause is disabled (0) or enabled
+ * (nonzero).
+ */
+
+
+
+	uint32_t                  period;
+/*< Period in milliseconds.
+ * Supported values: 0 to 15000
+ */
+
+	uint32_t                  step;
+/*< Step in microseconds.
+ * Supported values: 0 to 15000000
+ */
+
+	uint32_t                  ramping_curve;
+/*< Ramping curve.
+ * Supported values:
+ * - #ASM_PARAM_SVC_RAMPINGCURVE_LINEAR
+ * - #ASM_PARAM_SVC_RAMPINGCURVE_EXP
+ * - #ASM_PARAM_SVC_RAMPINGCURVE_LOG
+ */
+} __packed;
+
+
+/* Maximum number of channels.*/
+#define VOLUME_CONTROL_MAX_CHANNELS                       8
+
+/* Structure for holding one channel type - gain pair. */
+
+
+/* Payload of the #ASM_PARAM_ID_MULTICHANNEL_GAIN channel
+ * type/gain pairs used by the Volume Control module. \n \n This
+ * structure immediately follows the
+ * asm_volume_ctrl_multichannel_gain structure.
+ */
+
+
+struct asm_volume_ctrl_channelype_gain_pair {
+	struct apr_hdr	hdr;
+	struct asm_stream_cmd_set_pp_params_v2 param;
+	struct asm_stream_param_data_v2 data;
+	uint8_t                   channelype;
+/*< Channel type for which the gain setting is to be applied.
+ * Supported values:
+ * - #PCM_CHANNEL_L
+ * - #PCM_CHANNEL_R
+ * - #PCM_CHANNEL_C
+ * - #PCM_CHANNEL_LS
+ * - #PCM_CHANNEL_RS
+ * - #PCM_CHANNEL_LFE
+ * - #PCM_CHANNEL_CS
+ * - #PCM_CHANNEL_LB
+ * - #PCM_CHANNEL_RB
+ * - #PCM_CHANNELS
+ * - #PCM_CHANNEL_CVH
+ * - #PCM_CHANNEL_MS
+ * - #PCM_CHANNEL_FLC
+ * - #PCM_CHANNEL_FRC
+ * - #PCM_CHANNEL_RLC
+ * - #PCM_CHANNEL_RRC
+ */
+
+	uint8_t                   reserved1;
+	/*< Clients must set this field to zero. */
+
+	uint8_t                   reserved2;
+	/*< Clients must set this field to zero. */
+
+	uint8_t                   reserved3;
+	/*< Clients must set this field to zero. */
+
+	uint32_t                  gain;
+/*< Gain value for this channel in Q28 format.
+ * Supported values: Any
+ */
+} __packed;
+
+
+/* Structure for the multichannel gain command */
+
+
+/* Payload of the #ASM_PARAM_ID_MULTICHANNEL_GAIN
+ * parameters used by the Volume Control module.
+ */
+
+
+struct asm_volume_ctrl_multichannel_gain {
+	struct apr_hdr	hdr;
+	struct asm_stream_cmd_set_pp_params_v2 param;
+	struct asm_stream_param_data_v2 data;
+	uint32_t                  num_channels;
+/*< Number of channels for which gain values are provided. Any
+ * channels present in the data for which gain is not provided are
+ * set to unity gain.
+ * Supported values: 1 to 8
+ */
+
+
+	struct asm_volume_ctrl_channelype_gain_pair
+		gain_data[VOLUME_CONTROL_MAX_CHANNELS];
+	/*< Array of channel type/gain pairs.*/
+} __packed;
+
+
+/* Structure for holding one channel type - mute pair. */
+
+
+/* Payload of the #ASM_PARAM_ID_MULTICHANNEL_MUTE channel
+ * type/mute setting pairs used by the Volume Control module. \n \n
+ * This structure immediately follows the
+ * asm_volume_ctrl_multichannel_mute structure.
+ */
+
+
+struct asm_volume_ctrl_channelype_mute_pair {
+	struct apr_hdr	hdr;
+	struct asm_stream_cmd_set_pp_params_v2 param;
+	struct asm_stream_param_data_v2 data;
+	uint8_t                   channelype;
+/*< Channel type for which the mute setting is to be applied.
+ * Supported values:
+ * - #PCM_CHANNEL_L
+ * - #PCM_CHANNEL_R
+ * - #PCM_CHANNEL_C
+ * - #PCM_CHANNEL_LS
+ * - #PCM_CHANNEL_RS
+ * - #PCM_CHANNEL_LFE
+ * - #PCM_CHANNEL_CS
+ * - #PCM_CHANNEL_LB
+ * - #PCM_CHANNEL_RB
+ * - #PCM_CHANNELS
+ * - #PCM_CHANNEL_CVH
+ * - #PCM_CHANNEL_MS
+ * - #PCM_CHANNEL_FLC
+ * - #PCM_CHANNEL_FRC
+ * - #PCM_CHANNEL_RLC
+ * - #PCM_CHANNEL_RRC
+ */
+
+	uint8_t                   reserved1;
+	/*< Clients must set this field to zero. */
+
+	uint8_t                   reserved2;
+	/*< Clients must set this field to zero. */
+
+	uint8_t                   reserved3;
+	/*< Clients must set this field to zero. */
+
+	uint32_t                  mute;
+/*< Mute setting for this channel.
+ * Supported values:
+ * - 0 = Unmute
+ * - Nonzero = Mute
+ */
+} __packed;
+
+
+/* Structure for the multichannel mute command */
+
+
+/* @brief Payload of the #ASM_PARAM_ID_MULTICHANNEL_MUTE
+ * parameters used by the Volume Control module.
+ */
+
+
+struct asm_volume_ctrl_multichannel_mute {
+	struct apr_hdr	hdr;
+	struct asm_stream_cmd_set_pp_params_v2 param;
+	struct asm_stream_param_data_v2 data;
+	uint32_t                  num_channels;
+/*< Number of channels for which mute configuration is
+ * provided. Any channels present in the data for which mute
+ * configuration is not provided are set to unmute.
+ * Supported values: 1 to 8
+ */
+
+struct asm_volume_ctrl_channelype_mute_pair
+				mute_data[VOLUME_CONTROL_MAX_CHANNELS];
+	/*< Array of channel type/mute setting pairs.*/
+} __packed;
+/* end_addtogroup audio_pp_param_ids */
+
+/* audio_pp_module_ids
+ * ID of the IIR Tuning Filter module.
+ * This module supports the following parameter IDs:
+ * - #ASM_PARAM_ID_IIRUNING_FILTER_ENABLE_CONFIG
+ * - #ASM_PARAM_ID_IIRUNING_FILTER_PRE_GAIN
+ * - #ASM_PARAM_ID_IIRUNING_FILTER_CONFIG_PARAMS
+ */
+#define ASM_MODULE_ID_IIRUNING_FILTER   0x00010C02
+
+/* @addtogroup audio_pp_param_ids */
+/* ID of the IIR tuning filter enable parameter used by the
+ * #ASM_MODULE_ID_IIRUNING_FILTER module.
+ * @messagepayload
+ * @structure{asm_iiruning_filter_enable}
+ * @tablespace
+ * @inputtable{Audio_Postproc_ASM_PARAM_ID_IIRUNING_FILTER_ENABLE_CO
+ * NFIG.tex}
+ */
+#define ASM_PARAM_ID_IIRUNING_FILTER_ENABLE_CONFIG   0x00010C03
+
+/* ID of the IIR tuning filter pregain parameter used by the
+ * #ASM_MODULE_ID_IIRUNING_FILTER module.
+ */
+#define ASM_PARAM_ID_IIRUNING_FILTER_PRE_GAIN  0x00010C04
+
+/* ID of the IIR tuning filter configuration parameters used by the
+ * #ASM_MODULE_ID_IIRUNING_FILTER module.
+ */
+#define ASM_PARAM_ID_IIRUNING_FILTER_CONFIG_PARAMS  0x00010C05
+
+/* Structure for an enable configuration parameter for an
+ * IIR tuning filter module.
+ */
+
+
+/* @brief Payload of the #ASM_PARAM_ID_IIRUNING_FILTER_ENABLE_CONFIG
+ * parameter used by the IIR Tuning Filter module.
+ */
+struct asm_iiruning_filter_enable {
+	uint32_t                  enable_flag;
+/*< Specifies whether the IIR tuning filter is disabled (0) or
+ * enabled (1).
+ */
+} __packed;
+
+/* Structure for the pregain parameter for an IIR tuning filter module. */
+
+
+/* Payload of the #ASM_PARAM_ID_IIRUNING_FILTER_PRE_GAIN
+ * parameters used by the IIR Tuning Filter module.
+ */
+struct asm_iiruning_filter_pregain {
+	uint16_t                  pregain;
+	/*< Linear gain in Q13 format. */
+
+	uint16_t                  reserved;
+	/*< Clients must set this field to zero.*/
+} __packed;
+
+/* Structure for the configuration parameter for an IIR tuning filter
+ * module.
+ */
+
+
+/* @brief Payload of the #ASM_PARAM_ID_IIRUNING_FILTER_CONFIG_PARAMS
+ * parameters used by the IIR Tuning Filter module. \n
+ * \n
+ * This structure is followed by the IIR filter coefficients: \n
+ * - Sequence of int32_t FilterCoeffs \n
+ * Five coefficients for each band. Each coefficient is in int32_t format, in
+ * the order of b0, b1, b2, a1, a2.
+ * - Sequence of int16_t NumShiftFactor \n
+ * One int16_t per band. The numerator shift factor is related to the Q
+ * factor of the filter coefficients.
+ * - Sequence of uint16_t PanSetting \n
+ * One uint16_t per band, indicating if the filter is applied to left (0),
+ * right (1), or both (2) channels.
+ */
+struct asm_iir_filter_config_params {
+	uint16_t                  num_biquad_stages;
+/*< Number of bands.
+ * Supported values: 0 to 20
+ */
+
+	uint16_t                  reserved;
+	/*< Clients must set this field to zero.*/
+} __packed;
+
+/* audio_pp_module_ids
+ * ID of the Multiband Dynamic Range Control (MBDRC) module on the Tx/Rx
+ * paths.
+ * This module supports the following parameter IDs:
+ * - #ASM_PARAM_ID_MBDRC_ENABLE
+ * - #ASM_PARAM_ID_MBDRC_CONFIG_PARAMS
+ */
+#define ASM_MODULE_ID_MBDRC   0x00010C06
+
+/* audio_pp_param_ids */
+/* ID of the MBDRC enable parameter used by the #ASM_MODULE_ID_MBDRC module.
+ * @messagepayload
+ * @structure{asm_mbdrc_enable}
+ * @tablespace
+ * @inputtable{Audio_Postproc_ASM_PARAM_ID_MBDRC_ENABLE.tex}
+ */
+#define ASM_PARAM_ID_MBDRC_ENABLE   0x00010C07
+
+/* ID of the MBDRC configuration parameters used by the
+ * #ASM_MODULE_ID_MBDRC module.
+ * @messagepayload
+ * @structure{asm_mbdrc_config_params}
+ * @tablespace
+ * @inputtable{Audio_Postproc_ASM_PARAM_ID_MBDRC_CONFIG_PARAMS.tex}
+ *
+ * @parspace Sub-band DRC configuration parameters
+ * @structure{asm_subband_drc_config_params}
+ * @tablespace
+ * @inputtable{Audio_Postproc_ASM_PARAM_ID_MBDRC_CONFIG_PARAMS_subband_DRC.tex}
+ *
+ * @keep{6}
+ * To obtain legacy ADRC from MBDRC, use the calibration tool to:
+ *
+ * - Enable MBDRC (EnableFlag = TRUE)
+ * - Set number of bands to 1 (uiNumBands = 1)
+ * - Enable the first MBDRC band (DrcMode[0] = DRC_ENABLED = 1)
+ * - Clear the first band mute flag (MuteFlag[0] = 0)
+ * - Set the first band makeup gain to unity (compMakeUpGain[0] = 0x2000)
+ * - Use the legacy ADRC parameters to calibrate the rest of the MBDRC
+ * parameters.
+ */
+#define ASM_PARAM_ID_MBDRC_CONFIG_PARAMS  0x00010C08
+
+/* end_addtogroup audio_pp_param_ids */
+
+/* audio_pp_module_ids
+ * ID of the MMBDRC module version 2 pre/postprocessing block.
+ * This module differs from the original MBDRC (#ASM_MODULE_ID_MBDRC) in
+ * the length of the filters used in each sub-band.
+ * This module supports the following parameter ID:
+ * - #ASM_PARAM_ID_MBDRC_CONFIG_PARAMS_IMPROVED_FILTBANK_V2
+ */
+#define ASM_MODULE_ID_MBDRCV2                                0x0001070B
+
+/* @addtogroup audio_pp_param_ids */
+/* ID of the configuration parameters used by the
+ * #ASM_MODULE_ID_MBDRCV2 module for the improved filter structure
+ * of the MBDRC v2 pre/postprocessing block.
+ * The update to this configuration structure from the original
+ * MBDRC is the number of filter coefficients in the filter
+ * structure. The sequence for is as follows:
+ * - 1 band = 0 FIR coefficient + 1 mute flag + uint16_t padding
+ * - 2 bands = 141 FIR coefficients + 2 mute flags + uint16_t padding
+ * - 3 bands = 141+81 FIR coefficients + 3 mute flags + uint16_t padding
+ * - 4 bands = 141+81+61 FIR coefficients + 4 mute flags + uint16_t
+ * padding
+ * - 5 bands = 141+81+61+61 FIR coefficients + 5 mute flags +
+ * uint16_t padding
+ *	This block uses the same parameter structure as
+ *	#ASM_PARAM_ID_MBDRC_CONFIG_PARAMS.
+ */
+#define ASM_PARAM_ID_MBDRC_CONFIG_PARAMS_IMPROVED_FILTBANK_V2 \
+								0x0001070C
+
+/* Structure for the enable parameter for an MBDRC module. */
+
+
+/* Payload of the #ASM_PARAM_ID_MBDRC_ENABLE parameter used by the
+ * MBDRC module.
+ */
+struct asm_mbdrc_enable {
+	uint32_t                  enable_flag;
+/*< Specifies whether MBDRC is disabled (0) or enabled (nonzero).*/
+} __packed;
+
+/* Structure for the configuration parameters for an MBDRC module. */
+
+
+/* Payload of the #ASM_PARAM_ID_MBDRC_CONFIG_PARAMS
+ * parameters used by the MBDRC module. \n \n Following this
+ * structure is the payload for sub-band DRC configuration
+ * parameters (asm_subband_drc_config_params). This sub-band
+ * structure must be repeated for each band.
+ */
+
+
+struct asm_mbdrc_config_params {
+	uint16_t                  num_bands;
+/*< Number of bands.
+ * Supported values: 1 to 5
+ */
+
+	int16_t                   limiterhreshold;
+/*< Threshold in decibels for the limiter output.
+ * Supported values: -72 to 18 \n
+ * Recommended value: 3994 (-0.22 db in Q3.12 format)
+ */
+
+	int16_t                   limiter_makeup_gain;
+/*< Makeup gain in decibels for the limiter output.
+ * Supported values: -42 to 42 \n
+ * Recommended value: 256 (0 dB in Q7.8 format)
+ */
+
+	int16_t                   limiter_gc;
+/*< Limiter gain recovery coefficient.
+ * Supported values: 0.5 to 0.99 \n
+ * Recommended value: 32440 (0.99 in Q15 format)
+ */
+
+	int16_t                   limiter_delay;
+/*< Limiter delay in samples.
+ * Supported values: 0 to 10 \n
+ * Recommended value: 262 (0.008 samples in Q15 format)
+ */
+
+	int16_t                   limiter_max_wait;
+/*< Maximum limiter waiting time in samples.
+ * Supported values: 0 to 10 \n
+ * Recommended value: 262 (0.008 samples in Q15 format)
+ */
+} __packed;
+
+/* DRC configuration structure for each sub-band of an MBDRC module. */
+
+
+/* Payload of the #ASM_PARAM_ID_MBDRC_CONFIG_PARAMS DRC
+ * configuration parameters for each sub-band in the MBDRC module.
+ * After this DRC structure is configured for valid bands, the next
+ * MBDRC setparams expects the sequence of sub-band MBDRC filter
+ * coefficients (the length depends on the number of bands) plus the
+ * mute flag for that band plus uint16_t padding.
+ *
+ * @keep{10}
+ * The filter coefficient and mute flag are of type int16_t:
+ * - FIR coefficient = int16_t firFilter
+ * - Mute flag = int16_t fMuteFlag
+ *
+ * The sequence is as follows:
+ * - 1 band = 0 FIR coefficient + 1 mute flag + uint16_t padding
+ * - 2 bands = 97 FIR coefficients + 2 mute flags + uint16_t padding
+ * - 3 bands = 97+33 FIR coefficients + 3 mute flags + uint16_t padding
+ * - 4 bands = 97+33+33 FIR coefficients + 4 mute flags + uint16_t padding
+ * - 5 bands = 97+33+33+33 FIR coefficients + 5 mute flags + uint16_t padding
+ *
+ * For improved filterbank, the sequence is as follows:
+ * - 1 band = 0 FIR coefficient + 1 mute flag + uint16_t padding
+ * - 2 bands = 141 FIR coefficients + 2 mute flags + uint16_t padding
+ * - 3 bands = 141+81 FIR coefficients + 3 mute flags + uint16_t padding
+ * - 4 bands = 141+81+61 FIR coefficients + 4 mute flags + uint16_t padding
+ * - 5 bands = 141+81+61+61 FIR coefficients + 5 mute flags + uint16_t padding
+ */
+struct asm_subband_drc_config_params {
+	int16_t                   drc_stereo_linked_flag;
+/*< Specifies whether all stereo channels have the same applied
+ * dynamics (1) or if they process their dynamics independently (0).
+ * Supported values:
+ * - 0 -- Not linked
+ * - 1 -- Linked
+ */
+
+	int16_t                   drc_mode;
+/*< Specifies whether DRC mode is bypassed for sub-bands.
+ * Supported values:
+ * - 0 -- Disabled
+ * - 1 -- Enabled
+ */
+
+	int16_t                   drc_down_sample_level;
+/*< DRC down sample level.
+ * Supported values: @ge 1
+ */
+
+	int16_t                   drc_delay;
+/*< DRC delay in samples.
+ * Supported values: 0 to 1200
+ */
+
+	uint16_t                  drc_rmsime_avg_const;
+/*< RMS signal energy time-averaging constant.
+ * Supported values: 0 to 2^16-1
+ */
+
+	uint16_t                  drc_makeup_gain;
+/*< DRC makeup gain in decibels.
+ * Supported values: 258 to 64917
+ */
+	/* Down expander settings */
+	int16_t                   down_expdrhreshold;
+/*< Down expander threshold.
+ * Supported Q7 format values: 1320 to up_cmpsrhreshold
+ */
+
+	int16_t                   down_expdr_slope;
+/*< Down expander slope.
+ * Supported Q8 format values: -32768 to 0.
+ */
+
+	uint32_t                  down_expdr_attack;
+/*< Down expander attack constant.
+ * Supported Q31 format values: 196844 to 2^31.
+ */
+
+	uint32_t                  down_expdr_release;
+/*< Down expander release constant.
+ * Supported Q31 format values: 19685 to 2^31
+ */
+
+	uint16_t                  down_expdr_hysteresis;
+/*< Down expander hysteresis constant.
+ * Supported Q14 format values: 1 to 32690
+ */
+
+	uint16_t                  reserved;
+	/*< Clients must set this field to zero. */
+
+	int32_t                   down_expdr_min_gain_db;
+/*< Down expander minimum gain.
+ * Supported Q23 format values: -805306368 to 0.
+ */
+
+	/* Up compressor settings */
+
+	int16_t                   up_cmpsrhreshold;
+/*< Up compressor threshold.
+ * Supported Q7 format values: down_expdrhreshold to
+ * down_cmpsrhreshold.
+ */
+
+	uint16_t                  up_cmpsr_slope;
+/*< Up compressor slope.
+ * Supported Q16 format values: 0 to 64881.
+ */
+
+	uint32_t                  up_cmpsr_attack;
+/*< Up compressor attack constant.
+ * Supported Q31 format values: 196844 to 2^31.
+ */
+
+	uint32_t                  up_cmpsr_release;
+/*< Up compressor release constant.
+ * Supported Q31 format values: 19685 to 2^31.
+ */
+
+	uint16_t                  up_cmpsr_hysteresis;
+/*< Up compressor hysteresis constant.
+  * Supported Q14 format values: 1 to 32690.
+  */
+
+	/* Down compressor settings */
+
+	int16_t                   down_cmpsrhreshold;
+/*< Down compressor threshold.
+ * Supported Q7 format values: up_cmpsrhreshold to 11560.
+ */
+
+	uint16_t                  down_cmpsr_slope;
+/*< Down compressor slope.
+ * Supported Q16 format values: 0 to 64881.
+ */
+
+	uint16_t                  reserved1;
+/*< Clients must set this field to zero. */
+
+	uint32_t                  down_cmpsr_attack;
+/*< Down compressor attack constant.
+ * Supported Q31 format values: 196844 to 2^31.
+ */
+
+	uint32_t                  down_cmpsr_release;
+/*< Down compressor release constant.
+ * Supported Q31 format values: 19685 to 2^31.
+ */
+
+	uint16_t                  down_cmpsr_hysteresis;
+/*< Down compressor hysteresis constant.
+ * Supported Q14 values: 1 to 32690.
+ */
+
+	uint16_t                  reserved2;
+/*< Clients must set this field to zero.*/
+} __packed;
+
+#define ASM_MODULE_ID_EQUALIZER            0x00010C27
+#define ASM_PARAM_ID_EQUALIZER_PARAMETERS  0x00010C28
+
+#define ASM_MAX_EQ_BANDS 12
+
+struct asm_eq_per_band_params {
+	uint32_t                  band_idx;
+/*< Band index.
+ * Supported values: 0 to 11
+ */
+
+	uint32_t                  filterype;
+/*< Type of filter.
+ * Supported values:
+ * - #ASM_PARAM_EQYPE_NONE
+ * - #ASM_PARAM_EQ_BASS_BOOST
+ * - #ASM_PARAM_EQ_BASS_CUT
+ * - #ASM_PARAM_EQREBLE_BOOST
+ * - #ASM_PARAM_EQREBLE_CUT
+ * - #ASM_PARAM_EQ_BAND_BOOST
+ * - #ASM_PARAM_EQ_BAND_CUT
+ */
+
+	uint32_t                  center_freq_hz;
+	/*< Filter band center frequency in Hertz. */
+
+	int32_t                   filter_gain;
+/*< Filter band initial gain.
+ * Supported values: +12 to -12 dB in 1 dB increments
+ */
+
+	int32_t                   q_factor;
+/*< Filter band quality factor expressed as a Q8 number, i.e., a
+ * fixed-point number with q factor of 8. For example, 3000/(2^8).
+ */
+} __packed;
+
+struct asm_eq_params {
+	struct apr_hdr	hdr;
+	struct asm_stream_cmd_set_pp_params_v2 param;
+	struct asm_stream_param_data_v2 data;
+		uint32_t                  enable_flag;
+/*< Specifies whether the equalizer module is disabled (0) or enabled
+ * (nonzero).
+ */
+
+		uint32_t                  num_bands;
+/*< Number of bands.
+ * Supported values: 1 to 12
+ */
+	struct asm_eq_per_band_params eq_bands[ASM_MAX_EQ_BANDS];
+
+} __packed;
+
+/*	No equalizer effect.*/
+#define ASM_PARAM_EQYPE_NONE      0
+
+/*	Bass boost equalizer effect.*/
+#define ASM_PARAM_EQ_BASS_BOOST     1
+
+/*Bass cut equalizer effect.*/
+#define ASM_PARAM_EQ_BASS_CUT       2
+
+/*	Treble boost equalizer effect */
+#define ASM_PARAM_EQREBLE_BOOST   3
+
+/*	Treble cut equalizer effect.*/
+#define ASM_PARAM_EQREBLE_CUT     4
+
+/*	Band boost equalizer effect.*/
+#define ASM_PARAM_EQ_BAND_BOOST     5
+
+/*	Band cut equalizer effect.*/
+#define ASM_PARAM_EQ_BAND_CUT       6
+
+
+/* ERROR CODES */
+/* Success. The operation completed with no errors. */
+#define ADSP_EOK          0x00000000
+/* General failure. */
+#define ADSP_EFAILED      0x00000001
+/* Bad operation parameter. */
+#define ADSP_EBADPARAM    0x00000002
+/* Unsupported routine or operation. */
+#define ADSP_EUNSUPPORTED 0x00000003
+/* Unsupported version. */
+#define ADSP_EVERSION     0x00000004
+/* Unexpected problem encountered. */
+#define ADSP_EUNEXPECTED  0x00000005
+/* Unhandled problem occurred. */
+#define ADSP_EPANIC       0x00000006
+/* Unable to allocate resource. */
+#define ADSP_ENORESOURCE  0x00000007
+/* Invalid handle. */
+#define ADSP_EHANDLE      0x00000008
+/* Operation is already processed. */
+#define ADSP_EALREADY     0x00000009
+/* Operation is not ready to be processed. */
+#define ADSP_ENOTREADY    0x0000000A
+/* Operation is pending completion. */
+#define ADSP_EPENDING     0x0000000B
+/* Operation could not be accepted or processed. */
+#define ADSP_EBUSY        0x0000000C
+/* Operation aborted due to an error. */
+#define ADSP_EABORTED     0x0000000D
+/* Operation preempted by a higher priority. */
+#define ADSP_EPREEMPTED   0x0000000E
+/* Operation requests intervention to complete. */
+#define ADSP_ECONTINUE    0x0000000F
+/* Operation requests immediate intervention to complete. */
+#define ADSP_EIMMEDIATE   0x00000010
+/* Operation is not implemented. */
+#define ADSP_ENOTIMPL     0x00000011
+/* Operation needs more data or resources. */
+#define ADSP_ENEEDMORE    0x00000012
+/* Operation does not have memory. */
+#define ADSP_ENOMEMORY     0x00000014
+/* Item does not exist. */
+#define ADSP_ENOTEXIST      0x00000015
+/* Operation is finished. */
+#define ADSP_ETERMINATED    0x00011174
+
+/*bharath, adsp_error_codes.h */
+
+#endif /*_APR_AUDIO_V2_H_ */
diff --git a/include/sound/apr_audio.h b/include/sound/apr_audio.h
index 134d044..96795a3 100644
--- a/include/sound/apr_audio.h
+++ b/include/sound/apr_audio.h
@@ -611,6 +611,19 @@
 #define VPM_TX_DM_FLUENCE_COPP_TOPOLOGY			0x00010F72
 #define VPM_TX_QMIC_FLUENCE_COPP_TOPOLOGY		0x00010F75
 
+/* SRS TRUMEDIA GUIDS */
+/* topology */
+#define SRS_TRUMEDIA_TOPOLOGY_ID			0x00010D90
+/* module */
+#define SRS_TRUMEDIA_MODULE_ID				0x10005010
+/* parameters */
+#define SRS_TRUMEDIA_PARAMS				0x10005011
+#define SRS_TRUMEDIA_PARAMS_WOWHD			0x10005012
+#define SRS_TRUMEDIA_PARAMS_CSHP			0x10005013
+#define SRS_TRUMEDIA_PARAMS_HPF				0x10005014
+#define SRS_TRUMEDIA_PARAMS_PEQ				0x10005015
+#define SRS_TRUMEDIA_PARAMS_HL				0x10005016
+
 #define ASM_MAX_EQ_BANDS 12
 
 struct asm_eq_band {
@@ -1427,4 +1440,96 @@
 #define ADSP_ENOTIMPL     0x00000011 /* Operation is not implemented. */
 #define ADSP_ENEEDMORE    0x00000012 /* Operation needs more data or resources*/
 
+/* SRS TRUMEDIA start */
+#define SRS_ID_GLOBAL	0x00000001
+#define SRS_ID_WOWHD	0x00000002
+#define SRS_ID_CSHP	0x00000003
+#define SRS_ID_HPF	0x00000004
+#define SRS_ID_PEQ	0x00000005
+#define SRS_ID_HL	0x00000006
+
+#define SRS_CMD_UPLOAD		0x7FFF0000
+#define SRS_PARAM_INDEX_MASK	0x80000000
+#define SRS_PARAM_OFFSET_MASK	0x3FFF0000
+#define SRS_PARAM_VALUE_MASK	0x0000FFFF
+
+struct srs_trumedia_params_GLOBAL {
+	uint8_t                  v1;
+	uint8_t                  v2;
+	uint8_t                  v3;
+	uint8_t                  v4;
+	uint8_t                  v5;
+	uint8_t                  v6;
+	uint8_t                  v7;
+	uint8_t                  v8;
+} __packed;
+
+struct srs_trumedia_params_WOWHD {
+	uint32_t				v1;
+	uint16_t				v2;
+	uint16_t				v3;
+	uint16_t				v4;
+	uint16_t				v5;
+	uint16_t				v6;
+	uint16_t				v7;
+	uint16_t				v8;
+	uint16_t				v____A1;
+	uint32_t				v9;
+	uint16_t				v10;
+	uint16_t				v11;
+	uint32_t				v12[16];
+} __packed;
+
+struct srs_trumedia_params_CSHP {
+	uint32_t				v1;
+	uint16_t				v2;
+	uint16_t				v3;
+	uint16_t				v4;
+	uint16_t				v5;
+	uint16_t				v6;
+	uint16_t				v____A1;
+	uint32_t				v7;
+	uint16_t				v8;
+	uint16_t				v9;
+	uint32_t				v10[16];
+} __packed;
+
+struct srs_trumedia_params_HPF {
+	uint32_t				v1;
+	uint32_t				v2[26];
+} __packed;
+
+struct srs_trumedia_params_PEQ {
+	uint32_t				v1;
+	uint16_t				v2;
+	uint16_t				v3;
+	uint16_t				v4;
+	uint16_t				v____A1;
+	uint32_t				v5[26];
+	uint32_t				v6[26];
+} __packed;
+
+struct srs_trumedia_params_HL {
+	uint16_t				v1;
+	uint16_t				v2;
+	uint16_t				v3;
+	uint16_t				v____A1;
+	int32_t					v4;
+	uint32_t				v5;
+	uint16_t				v6;
+	uint16_t				v____A2;
+	uint32_t				v7;
+} __packed;
+
+struct srs_trumedia_params {
+	struct srs_trumedia_params_GLOBAL	global;
+	struct srs_trumedia_params_WOWHD	wowhd;
+	struct srs_trumedia_params_CSHP		cshp;
+	struct srs_trumedia_params_HPF		hpf;
+	struct srs_trumedia_params_PEQ		peq;
+	struct srs_trumedia_params_HL		hl;
+} __packed;
+int srs_trumedia_open(int port_id, int srs_tech_id, void *srs_params);
+/* SRS TruMedia end */
+
 #endif /*_APR_AUDIO_H_*/
diff --git a/include/sound/jack.h b/include/sound/jack.h
index ccdc341..1b13cbb 100644
--- a/include/sound/jack.h
+++ b/include/sound/jack.h
@@ -35,24 +35,26 @@
  * sound/core/jack.c.
  */
 enum snd_jack_types {
-	SND_JACK_HEADPHONE	= 0x0001,
-	SND_JACK_MICROPHONE	= 0x0002,
+	SND_JACK_HEADPHONE	= 0x0000001,
+	SND_JACK_MICROPHONE	= 0x0000002,
 	SND_JACK_HEADSET	= SND_JACK_HEADPHONE | SND_JACK_MICROPHONE,
-	SND_JACK_LINEOUT	= 0x0004,
-	SND_JACK_MECHANICAL	= 0x0008, /* If detected separately */
-	SND_JACK_VIDEOOUT	= 0x0010,
+	SND_JACK_LINEOUT	= 0x0000004,
+	SND_JACK_MECHANICAL	= 0x0000008, /* If detected separately */
+	SND_JACK_VIDEOOUT	= 0x0000010,
 	SND_JACK_AVOUT		= SND_JACK_LINEOUT | SND_JACK_VIDEOOUT,
-	SND_JACK_OC_HPHL	= 0x0020,
-	SND_JACK_OC_HPHR	= 0x0040,
+	/* */
+	SND_JACK_OC_HPHL	= 0x0000020,
+	SND_JACK_OC_HPHR	= 0x0000040,
+	SND_JACK_UNSUPPORTED	= 0x0000080,
 	/* Kept separate from switches to facilitate implementation */
-	SND_JACK_BTN_0		= 0x4000,
-	SND_JACK_BTN_1		= 0x2000,
-	SND_JACK_BTN_2		= 0x1000,
-	SND_JACK_BTN_3		= 0x0800,
-	SND_JACK_BTN_4		= 0x0400,
-	SND_JACK_BTN_5		= 0x0200,
-	SND_JACK_BTN_6		= 0x0100,
-	SND_JACK_BTN_7		= 0x0080,
+	SND_JACK_BTN_0		= 0x4000000,
+	SND_JACK_BTN_1		= 0x2000000,
+	SND_JACK_BTN_2		= 0x1000000,
+	SND_JACK_BTN_3		= 0x0800000,
+	SND_JACK_BTN_4		= 0x0400000,
+	SND_JACK_BTN_5		= 0x0200000,
+	SND_JACK_BTN_6		= 0x0100000,
+	SND_JACK_BTN_7		= 0x0080000,
 };
 
 struct snd_jack {
diff --git a/include/sound/msm-dai-q6-v2.h b/include/sound/msm-dai-q6-v2.h
new file mode 100644
index 0000000..3d5ffdd
--- /dev/null
+++ b/include/sound/msm-dai-q6-v2.h
@@ -0,0 +1,42 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MSM_DAI_Q6_PDATA_H__
+
+#define __MSM_DAI_Q6_PDATA_H__
+
+#define MSM_MI2S_SD0 (1 << 0)
+#define MSM_MI2S_SD1 (1 << 1)
+#define MSM_MI2S_SD2 (1 << 2)
+#define MSM_MI2S_SD3 (1 << 3)
+#define MSM_MI2S_CAP_RX 0
+#define MSM_MI2S_CAP_TX 1
+
+struct msm_dai_auxpcm_pdata {
+	const char *clk;
+	u16 mode;
+	u16 sync;
+	u16 frame;
+	u16 quant;
+	/* modify slot to arr[4] to specify
+	* the slot number for each channel
+	* in multichannel scenario */
+	u16 slot;
+	u16 data;
+	int pcm_clk_rate;
+};
+
+struct msm_i2s_data {
+	u32 capability; /* RX or TX */
+	u16 sd_lines;
+};
+#endif
diff --git a/include/sound/msm-dai-q6.h b/include/sound/msm-dai-q6.h
index 6328256..042aa6f 100644
--- a/include/sound/msm-dai-q6.h
+++ b/include/sound/msm-dai-q6.h
@@ -21,8 +21,7 @@
 #define MSM_MI2S_CAP_RX 0
 #define MSM_MI2S_CAP_TX 1
 
-struct msm_dai_auxpcm_pdata {
-	const char *clk;
+struct msm_dai_auxpcm_config {
 	u16 mode;
 	u16 sync;
 	u16 frame;
@@ -36,4 +35,11 @@
 	u16 rx_sd_lines;
 	u16 tx_sd_lines;
 };
+
+struct msm_dai_auxpcm_pdata {
+	const char *clk;
+	struct msm_dai_auxpcm_config mode_8k;
+	struct msm_dai_auxpcm_config mode_16k;
+};
+
 #endif
diff --git a/include/sound/q6adm-v2.h b/include/sound/q6adm-v2.h
new file mode 100644
index 0000000..cb2f3d7
--- /dev/null
+++ b/include/sound/q6adm-v2.h
@@ -0,0 +1,50 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __Q6_ADM_V2_H__
+#define __Q6_ADM_V2_H__
+
+
+#define ADM_PATH_PLAYBACK 0x1
+#define ADM_PATH_LIVE_REC 0x2
+#define ADM_PATH_NONLIVE_REC 0x3
+#include <sound/q6audio-v2.h>
+
+#define Q6_AFE_MAX_PORTS 32
+
+/* multiple copp per stream. */
+struct route_payload {
+	unsigned int copp_ids[Q6_AFE_MAX_PORTS];
+	unsigned short num_copps;
+	unsigned int session_id;
+};
+
+int adm_open(int port, int path, int rate, int mode, int topology);
+
+int adm_multi_ch_copp_open(int port, int path, int rate, int mode,
+				int topology);
+
+int adm_memory_map_regions(int port_id, uint32_t *buf_add, uint32_t mempool_id,
+				uint32_t *bufsz, uint32_t bufcnt);
+
+int adm_memory_unmap_regions(int port_id, uint32_t *buf_add, uint32_t *bufsz,
+						uint32_t bufcnt);
+
+int adm_close(int port);
+
+int adm_matrix_map(int session_id, int path, int num_copps,
+				unsigned int *port_id, int copp_id);
+
+int adm_connect_afe_port(int mode, int session_id, int port_id);
+
+int adm_get_copp_id(int port_id);
+
+#endif /* __Q6_ADM_V2_H__ */
diff --git a/include/sound/q6afe-v2.h b/include/sound/q6afe-v2.h
new file mode 100644
index 0000000..1587d38
--- /dev/null
+++ b/include/sound/q6afe-v2.h
@@ -0,0 +1,107 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __Q6AFE_V2_H__
+#define __Q6AFE_V2_H__
+#include <sound/apr_audio-v2.h>
+
+#define MSM_AFE_MONO        0
+#define MSM_AFE_MONO_RIGHT  1
+#define MSM_AFE_MONO_LEFT   2
+#define MSM_AFE_STEREO      3
+#define MSM_AFE_4CHANNELS   4
+#define MSM_AFE_6CHANNELS   6
+#define MSM_AFE_8CHANNELS   8
+
+#define MSM_AFE_I2S_FORMAT_LPCM		0
+#define MSM_AFE_I2S_FORMAT_COMPR		1
+#define MSM_AFE_I2S_FORMAT_IEC60958_LPCM	2
+#define MSM_AFE_I2S_FORMAT_IEC60958_COMPR	3
+
+#define MSM_AFE_PORT_TYPE_RX 0
+#define MSM_AFE_PORT_TYPE_TX 1
+
+#define RT_PROXY_DAI_001_RX	0xE0
+#define RT_PROXY_DAI_001_TX	0xF0
+#define RT_PROXY_DAI_002_RX	0xF1
+#define RT_PROXY_DAI_002_TX	0xE1
+#define VIRTUAL_ID_TO_PORTID(val) ((val & 0xF) | 0x2000)
+
+enum {
+	IDX_PRIMARY_I2S_RX = 0,
+	IDX_PRIMARY_I2S_TX = 1,
+	IDX_PCM_RX = 2,
+	IDX_PCM_TX = 3,
+	IDX_SECONDARY_I2S_RX = 4,
+	IDX_SECONDARY_I2S_TX = 5,
+	IDX_MI2S_RX = 6,
+	IDX_MI2S_TX = 7,
+	IDX_HDMI_RX = 8,
+	IDX_RSVD_2 = 9,
+	IDX_RSVD_3 = 10,
+	IDX_DIGI_MIC_TX = 11,
+	IDX_VOICE_RECORD_RX = 12,
+	IDX_VOICE_RECORD_TX = 13,
+	IDX_VOICE_PLAYBACK_TX = 14,
+	IDX_SLIMBUS_0_RX = 15,
+	IDX_SLIMBUS_0_TX = 16,
+	IDX_SLIMBUS_1_RX = 17,
+	IDX_SLIMBUS_1_TX = 18,
+	IDX_SLIMBUS_2_RX = 19,
+	IDX_SLIMBUS_2_TX = 20,
+	IDX_SLIMBUS_3_RX = 21,
+	IDX_SLIMBUS_3_TX = 22,
+	IDX_SLIMBUS_4_RX = 23,
+	IDX_SLIMBUS_4_TX = 24,
+	IDX_INT_BT_SCO_RX = 25,
+	IDX_INT_BT_SCO_TX = 26,
+	IDX_INT_BT_A2DP_RX = 27,
+	IDX_INT_FM_RX = 28,
+	IDX_INT_FM_TX = 29,
+	IDX_RT_PROXY_PORT_001_RX = 30,
+	IDX_RT_PROXY_PORT_001_TX = 31,
+	AFE_MAX_PORTS
+};
+
+int afe_open(u16 port_id, union afe_port_config *afe_config, int rate);
+int afe_close(int port_id);
+int afe_loopback(u16 enable, u16 rx_port, u16 tx_port);
+int afe_sidetone(u16 tx_port_id, u16 rx_port_id, u16 enable, uint16_t gain);
+int afe_loopback_gain(u16 port_id, u16 volume);
+int afe_validate_port(u16 port_id);
+int afe_start_pseudo_port(u16 port_id);
+int afe_stop_pseudo_port(u16 port_id);
+int afe_cmd_memory_map(u32 dma_addr_p, u32 dma_buf_sz);
+int afe_cmd_memory_map_nowait(int port_id, u32 dma_addr_p, u32 dma_buf_sz);
+int afe_cmd_memory_unmap(u32 dma_addr_p);
+int afe_cmd_memory_unmap_nowait(u32 dma_addr_p);
+
+int afe_register_get_events(u16 port_id,
+		void (*cb) (uint32_t opcode,
+		uint32_t token, uint32_t *payload, void *priv),
+		void *private_data);
+int afe_unregister_get_events(u16 port_id);
+int afe_rt_proxy_port_write(u32 buf_addr_p, u32 mem_map_handle, int bytes);
+int afe_rt_proxy_port_read(u32 buf_addr_p, u32 mem_map_handle, int bytes);
+int afe_port_start_nowait(u16 port_id, union afe_port_config *afe_config,
+	u32 rate);
+int afe_port_stop_nowait(int port_id);
+int afe_apply_gain(u16 port_id, u16 gain);
+int afe_q6_interface_prepare(void);
+int afe_get_port_type(u16 port_id);
+/* if port_id is virtual, convert to physical..
+ * if port_id is already physical, return physical
+ */
+int afe_convert_virtual_to_portid(u16 port_id);
+
+int afe_pseudo_port_start_nowait(u16 port_id);
+int afe_pseudo_port_stop_nowait(u16 port_id);
+#endif /* __Q6AFE_V2_H__ */
diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h
new file mode 100644
index 0000000..7ef15ac
--- /dev/null
+++ b/include/sound/q6asm-v2.h
@@ -0,0 +1,303 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __Q6_ASM_V2_H__
+#define __Q6_ASM_V2_H__
+
+#include <mach/qdsp6v2/apr.h>
+#include <mach/msm_subsystem_map.h>
+#include <sound/apr_audio-v2.h>
+#include <linux/list.h>
+#include <linux/ion.h>
+
+#define IN                      0x000
+#define OUT                     0x001
+#define CH_MODE_MONO            0x001
+#define CH_MODE_STEREO          0x002
+
+#define FORMAT_LINEAR_PCM   0x0000
+#define FORMAT_DTMF         0x0001
+#define FORMAT_ADPCM	    0x0002
+#define FORMAT_YADPCM       0x0003
+#define FORMAT_MP3          0x0004
+#define FORMAT_MPEG4_AAC    0x0005
+#define FORMAT_AMRNB	    0x0006
+#define FORMAT_AMRWB	    0x0007
+#define FORMAT_V13K	    0x0008
+#define FORMAT_EVRC	    0x0009
+#define FORMAT_EVRCB	    0x000a
+#define FORMAT_EVRCWB	    0x000b
+#define FORMAT_MIDI	    0x000c
+#define FORMAT_SBC	    0x000d
+#define FORMAT_WMA_V10PRO   0x000e
+#define FORMAT_WMA_V9	    0x000f
+#define FORMAT_AMR_WB_PLUS  0x0010
+#define FORMAT_MPEG4_MULTI_AAC 0x0011
+#define FORMAT_MULTI_CHANNEL_LINEAR_PCM 0x0012
+
+#define ENCDEC_SBCBITRATE   0x0001
+#define ENCDEC_IMMEDIATE_DECODE 0x0002
+#define ENCDEC_CFG_BLK          0x0003
+
+#define CMD_PAUSE          0x0001
+#define CMD_FLUSH          0x0002
+#define CMD_EOS            0x0003
+#define CMD_CLOSE          0x0004
+#define CMD_OUT_FLUSH      0x0005
+
+/* bit 0:1 represents priority of stream */
+#define STREAM_PRIORITY_NORMAL	0x0000
+#define STREAM_PRIORITY_LOW	0x0001
+#define STREAM_PRIORITY_HIGH	0x0002
+
+/* bit 4 represents META enable of encoded data buffer */
+#define BUFFER_META_ENABLE	0x0010
+
+/* Enable Sample_Rate/Channel_Mode notification event from Decoder */
+#define SR_CM_NOTIFY_ENABLE	0x0004
+
+#define ASYNC_IO_MODE	0x0002
+#define SYNC_IO_MODE	0x0001
+#define NO_TIMESTAMP    0xFF00
+#define SET_TIMESTAMP   0x0000
+
+#define SOFT_PAUSE_ENABLE	1
+#define SOFT_PAUSE_DISABLE	0
+
+#define SESSION_MAX	0x08
+
+#define SOFT_PAUSE_PERIOD       30   /* ramp up/down for 30ms    */
+#define SOFT_PAUSE_STEP         2000 /* Step value 2ms or 2000us */
+enum {
+	SOFT_PAUSE_CURVE_LINEAR = 0,
+	SOFT_PAUSE_CURVE_EXP,
+	SOFT_PAUSE_CURVE_LOG,
+};
+
+#define SOFT_VOLUME_PERIOD       30   /* ramp up/down for 30ms    */
+#define SOFT_VOLUME_STEP         2000 /* Step value 2ms or 2000us */
+enum {
+	SOFT_VOLUME_CURVE_LINEAR = 0,
+	SOFT_VOLUME_CURVE_EXP,
+	SOFT_VOLUME_CURVE_LOG,
+};
+
+typedef void (*app_cb)(uint32_t opcode, uint32_t token,
+			uint32_t *payload, void *priv);
+
+struct audio_buffer {
+	dma_addr_t phys;
+	void       *data;
+	uint32_t   used;
+	uint32_t   size;/* size of buffer */
+	uint32_t   actual_size; /* actual number of bytes read by DSP */
+	struct      ion_handle *handle;
+	struct      ion_client *client;
+};
+
+struct audio_aio_write_param {
+	unsigned long paddr;
+	uint32_t      len;
+	uint32_t      uid;
+	uint32_t      lsw_ts;
+	uint32_t      msw_ts;
+	uint32_t      flags;
+};
+
+struct audio_aio_read_param {
+	unsigned long paddr;
+	uint32_t      len;
+	uint32_t      uid;
+};
+
+struct audio_port_data {
+	struct audio_buffer *buf;
+	uint32_t	    max_buf_cnt;
+	uint32_t	    dsp_buf;
+	uint32_t	    cpu_buf;
+	struct list_head    mem_map_handle;
+	uint32_t	    tmp_hdl;
+	/* read or write locks */
+	struct mutex	    lock;
+	spinlock_t	    dsp_lock;
+};
+
+struct audio_client {
+	int                    session;
+	app_cb		       cb;
+	atomic_t	       cmd_state;
+	/* Relative or absolute TS */
+	uint32_t	       time_flag;
+	void		       *priv;
+	uint32_t               io_mode;
+	uint64_t	       time_stamp;
+	struct apr_svc         *apr;
+	struct apr_svc         *mmap_apr;
+	struct mutex	       cmd_lock;
+	/* idx:1 out port, 0: in port*/
+	struct audio_port_data port[2];
+	wait_queue_head_t      cmd_wait;
+};
+
+void q6asm_audio_client_free(struct audio_client *ac);
+
+struct audio_client *q6asm_audio_client_alloc(app_cb cb, void *priv);
+
+struct audio_client *q6asm_get_audio_client(int session_id);
+
+int q6asm_audio_client_buf_alloc(unsigned int dir/* 1:Out,0:In */,
+				struct audio_client *ac,
+				unsigned int bufsz,
+				unsigned int bufcnt);
+int q6asm_audio_client_buf_alloc_contiguous(unsigned int dir
+				/* 1:Out,0:In */,
+				struct audio_client *ac,
+				unsigned int bufsz,
+				unsigned int bufcnt);
+
+int q6asm_audio_client_buf_free_contiguous(unsigned int dir,
+			struct audio_client *ac);
+
+int q6asm_open_read(struct audio_client *ac, uint32_t format
+		/*, uint16_t bits_per_sample*/);
+
+int q6asm_open_write(struct audio_client *ac, uint32_t format
+		/*, uint16_t bits_per_sample*/);
+
+int q6asm_open_read_write(struct audio_client *ac,
+			uint32_t rd_format,
+			uint32_t wr_format);
+
+int q6asm_write(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
+				uint32_t lsw_ts, uint32_t flags);
+int q6asm_write_nolock(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
+				uint32_t lsw_ts, uint32_t flags);
+
+int q6asm_async_write(struct audio_client *ac,
+					  struct audio_aio_write_param *param);
+
+int q6asm_async_read(struct audio_client *ac,
+					  struct audio_aio_read_param *param);
+
+int q6asm_read(struct audio_client *ac);
+int q6asm_read_nolock(struct audio_client *ac);
+
+int q6asm_memory_map(struct audio_client *ac, uint32_t buf_add,
+			int dir, uint32_t bufsz, uint32_t bufcnt);
+
+int q6asm_memory_unmap(struct audio_client *ac, uint32_t buf_add,
+							int dir);
+
+int q6asm_run(struct audio_client *ac, uint32_t flags,
+		uint32_t msw_ts, uint32_t lsw_ts);
+
+int q6asm_run_nowait(struct audio_client *ac, uint32_t flags,
+		uint32_t msw_ts, uint32_t lsw_ts);
+
+int q6asm_reg_tx_overflow(struct audio_client *ac, uint16_t enable);
+
+int q6asm_cmd(struct audio_client *ac, int cmd);
+
+int q6asm_cmd_nowait(struct audio_client *ac, int cmd);
+
+void *q6asm_is_cpu_buf_avail(int dir, struct audio_client *ac,
+				uint32_t *size, uint32_t *idx);
+
+void *q6asm_is_cpu_buf_avail_nolock(int dir, struct audio_client *ac,
+					uint32_t *size, uint32_t *idx);
+
+int q6asm_is_dsp_buf_avail(int dir, struct audio_client *ac);
+
+/* File format specific configurations to be added below */
+
+int q6asm_enc_cfg_blk_aac(struct audio_client *ac,
+			 uint32_t frames_per_buf,
+			uint32_t sample_rate, uint32_t channels,
+			 uint32_t bit_rate,
+			 uint32_t mode, uint32_t format);
+
+int q6asm_enc_cfg_blk_pcm(struct audio_client *ac,
+			uint32_t rate, uint32_t channels);
+
+int q6asm_set_encdec_chan_map(struct audio_client *ac,
+		uint32_t num_channels);
+
+int q6asm_enable_sbrps(struct audio_client *ac,
+			uint32_t sbr_ps);
+
+int q6asm_cfg_dual_mono_aac(struct audio_client *ac,
+			uint16_t sce_left, uint16_t sce_right);
+
+int q6asm_enc_cfg_blk_qcelp(struct audio_client *ac, uint32_t frames_per_buf,
+		uint16_t min_rate, uint16_t max_rate,
+		uint16_t reduced_rate_level, uint16_t rate_modulation_cmd);
+
+int q6asm_enc_cfg_blk_evrc(struct audio_client *ac, uint32_t frames_per_buf,
+		uint16_t min_rate, uint16_t max_rate,
+		uint16_t rate_modulation_cmd);
+
+int q6asm_enc_cfg_blk_amrnb(struct audio_client *ac, uint32_t frames_per_buf,
+		uint16_t band_mode, uint16_t dtx_enable);
+
+int q6asm_enc_cfg_blk_amrwb(struct audio_client *ac, uint32_t frames_per_buf,
+		uint16_t band_mode, uint16_t dtx_enable);
+
+int q6asm_media_format_block_pcm(struct audio_client *ac,
+			uint32_t rate, uint32_t channels);
+
+int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
+				uint32_t rate, uint32_t channels);
+
+int q6asm_media_format_block_aac(struct audio_client *ac,
+			struct asm_aac_cfg *cfg);
+
+int q6asm_media_format_block_multi_aac(struct audio_client *ac,
+			struct asm_aac_cfg *cfg);
+
+int q6asm_media_format_block_wma(struct audio_client *ac,
+			void *cfg);
+
+int q6asm_media_format_block_wmapro(struct audio_client *ac,
+			void *cfg);
+
+/* PP specific */
+int q6asm_equalizer(struct audio_client *ac, void *eq);
+
+/* Send Volume Command */
+int q6asm_set_volume(struct audio_client *ac, int volume);
+
+/* Set SoftPause Params */
+int q6asm_set_softpause(struct audio_client *ac,
+			struct asm_softpause_params *param);
+
+/* Set Softvolume Params */
+int q6asm_set_softvolume(struct audio_client *ac,
+			struct asm_softvolume_params *param);
+
+/* Send left-right channel gain */
+int q6asm_set_lrgain(struct audio_client *ac, int left_gain, int right_gain);
+
+/* Enable Mute/unmute flag */
+int q6asm_set_mute(struct audio_client *ac, int muteflag);
+
+uint64_t q6asm_get_session_time(struct audio_client *ac);
+
+/* Client can set the IO mode to either AIO/SIO mode */
+int q6asm_set_io_mode(struct audio_client *ac, uint32_t mode);
+
+/* Get Service ID for APR communication */
+int q6asm_get_apr_service_id(int session_id);
+
+/* Common format block without any payload
+*/
+int q6asm_media_format_block(struct audio_client *ac, uint32_t format);
+
+#endif /* __Q6_ASM_H__ */
diff --git a/include/sound/q6audio-v2.h b/include/sound/q6audio-v2.h
new file mode 100644
index 0000000..1a5dce1
--- /dev/null
+++ b/include/sound/q6audio-v2.h
@@ -0,0 +1,26 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _Q6_AUDIO_H_
+#define _Q6_AUDIO_H_
+
+#include <mach/qdsp6v2/apr.h>
+
+int q6audio_get_port_index(u16 port_id);
+
+int q6audio_convert_virtual_to_portid(u16 port_id);
+
+int q6audio_validate_port(u16 port_id);
+
+int q6audio_get_port_id(u16 port_id);
+
+#endif
diff --git a/include/sound/snd_compress_params.h b/include/sound/snd_compress_params.h
index e9f6748..f1e3ea2 100644
--- a/include/sound/snd_compress_params.h
+++ b/include/sound/snd_compress_params.h
@@ -72,6 +72,7 @@
 #define SND_AUDIOCODEC_AC3		     ((__u32) 0x0000000E)
 #define SND_AUDIOCODEC_DTS		     ((__u32) 0x0000000F)
 #define SND_AUDIOCODEC_AC3_PASS_THROUGH		((__u32) 0x00000010)
+#define SND_AUDIOCODEC_WMA_PRO               ((__u32) 0x000000011)
 /*
  * Profile and modes are listed with bit masks. This allows for a
  * more compact representation of fields that will not evolve
diff --git a/kernel/power/main.c b/kernel/power/main.c
index 9b279cc..c634367 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -399,8 +399,6 @@
 #endif
 
 static struct attribute *g[] = {
-	&touch_event_attr.attr,
-	&touch_event_timer_attr.attr,
 	&state_attr.attr,
 #ifdef CONFIG_PM_TRACE
 	&pm_trace_attr.attr,
@@ -409,6 +407,8 @@
 #ifdef CONFIG_PM_SLEEP
 	&pm_async_attr.attr,
 	&wakeup_count_attr.attr,
+	&touch_event_attr.attr,
+	&touch_event_timer_attr.attr,
 #ifdef CONFIG_PM_DEBUG
 	&pm_test_attr.attr,
 #endif
diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c
index 6957aa2..fa1d639 100644
--- a/kernel/trace/blktrace.c
+++ b/kernel/trace/blktrace.c
@@ -1792,6 +1792,8 @@
 		rwbs[i++] = 'W';
 	else if (rw & REQ_DISCARD)
 		rwbs[i++] = 'D';
+	else if (rw & REQ_SANITIZE)
+		rwbs[i++] = 'Z';
 	else if (bytes)
 		rwbs[i++] = 'R';
 	else
diff --git a/mm/memblock.c b/mm/memblock.c
index 5338237..b7abce5 100644
--- a/mm/memblock.c
+++ b/mm/memblock.c
@@ -720,6 +720,12 @@
 		 memblock.memory.regions[idx].size) >= end;
 }
 
+int __init_memblock memblock_overlaps_memory(phys_addr_t base, phys_addr_t size)
+{
+	memblock_cap_size(base, &size);
+	return memblock_overlaps_region(&memblock.memory, base, size) >= 0;
+}
+
 int __init_memblock memblock_is_region_reserved(phys_addr_t base, phys_addr_t size)
 {
 	memblock_cap_size(base, &size);
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 25b559b1..02ea082 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -448,6 +448,7 @@
 
 	conn->power_save = 1;
 	conn->disc_timeout = HCI_DISCONN_TIMEOUT;
+	wake_lock_init(&conn->idle_lock, WAKE_LOCK_SUSPEND, "bt_idle");
 
 	switch (type) {
 	case ACL_LINK:
@@ -521,6 +522,7 @@
 
 	/* Make sure no timers are running */
 	del_timer(&conn->idle_timer);
+	wake_lock_destroy(&conn->idle_lock);
 	del_timer(&conn->disc_timer);
 	del_timer(&conn->smp_timer);
 	__cancel_delayed_work(&conn->rssi_update_work);
@@ -962,9 +964,11 @@
 	}
 
 timer:
-	if (hdev->idle_timeout > 0)
+	if (hdev->idle_timeout > 0) {
 		mod_timer(&conn->idle_timer,
 			jiffies + msecs_to_jiffies(hdev->idle_timeout));
+		wake_lock(&conn->idle_lock);
+	}
 }
 
 static inline void hci_conn_stop_rssi_timer(struct hci_conn *conn)
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 395a95c..2b14423 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1813,6 +1813,15 @@
 			struct hci_cp_auth_requested cp;
 			hci_remove_link_key(hdev, &conn->dst);
 			cp.handle = cpu_to_le16(conn->handle);
+			/*Initiates dedicated bonding as pin or key is missing
+			on remote device*/
+			/*In case if remote device is ssp supported,
+			reduce the security level to MEDIUM if it is HIGH*/
+			if (conn->ssp_mode && conn->auth_initiator &&
+				conn->io_capability != 0x03) {
+				conn->pending_sec_level = BT_SECURITY_HIGH;
+				conn->auth_type = HCI_AT_DEDICATED_BONDING_MITM;
+			}
 			hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED,
 							sizeof(cp), &cp);
 			hci_dev_unlock(hdev);
@@ -2556,6 +2565,9 @@
 			else
 				conn->power_save = 0;
 		}
+		if (conn->mode == HCI_CM_SNIFF)
+			if (wake_lock_active(&conn->idle_lock))
+				wake_unlock(&conn->idle_lock);
 
 		if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->pend))
 			hci_sco_setup(conn, ev->status);
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index a7b95d3..3ecc6d4 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -5397,9 +5397,6 @@
 
 	BT_DBG("sk %p", sk);
 
-	if (!sk)
-		return;
-
 	lock_sock(sk);
 
 	if (sk->sk_state != BT_CONNECTED && !l2cap_pi(sk)->amp_id) {
@@ -5539,8 +5536,11 @@
 		container_of(work, struct l2cap_logical_link_work, work);
 	struct sock *sk = log_link_work->chan->l2cap_sk;
 
-	l2cap_logical_link_complete(log_link_work->chan, log_link_work->status);
-	sock_put(sk);
+	if (sk) {
+		l2cap_logical_link_complete(log_link_work->chan,
+							log_link_work->status);
+		sock_put(sk);
+	}
 	hci_chan_put(log_link_work->chan);
 	kfree(log_link_work);
 }
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 80f4bd6..86ae763 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -308,7 +308,7 @@
 
 		cmd = list_entry(p, struct pending_cmd, list);
 
-		if (cmd->opcode != opcode)
+		if (opcode > 0 && cmd->opcode != opcode)
 			continue;
 
 		if (index >= 0 && cmd->index != index)
@@ -2475,6 +2475,14 @@
 	return err;
 }
 
+static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
+{
+	u8 *status = data;
+
+	cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
+	mgmt_pending_remove(cmd);
+}
+
 int mgmt_index_added(u16 index)
 {
 	BT_DBG("%d", index);
@@ -2483,7 +2491,12 @@
 
 int mgmt_index_removed(u16 index)
 {
+	u8 status = ENODEV;
+
 	BT_DBG("%d", index);
+
+	mgmt_pending_foreach(0, index, cmd_status_rsp, &status);
+
 	return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
 }
 
@@ -2522,6 +2535,11 @@
 
 	mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
 
+	if (!powered) {
+		u8 status = ENETDOWN;
+		mgmt_pending_foreach(0, index, cmd_status_rsp, &status);
+	}
+
 	ev.val = powered;
 
 	ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
diff --git a/scripts/gcc-wrapper.py b/scripts/gcc-wrapper.py
index d3d393d..16c623c 100755
--- a/scripts/gcc-wrapper.py
+++ b/scripts/gcc-wrapper.py
@@ -44,8 +44,8 @@
     "alignment.c:720",
     "async.c:122",
     "async.c:270",
-    "block.c:835",
-    "block.c:836",
+    "block.c:885",
+    "block.c:886",
     "dir.c:43",
     "dm.c:1053",
     "dm.c:1080",
diff --git a/sound/core/jack.c b/sound/core/jack.c
index 80453a9..675f45b 100644
--- a/sound/core/jack.c
+++ b/sound/core/jack.c
@@ -32,6 +32,7 @@
 	SW_VIDEOOUT_INSERT,
 	SW_HPHL_OVERCURRENT,
 	SW_HPHR_OVERCURRENT,
+	SW_UNSUPPORT_INSERT,
 };
 
 static int snd_jack_dev_free(struct snd_device *device)
diff --git a/sound/soc/codecs/wcd9304-tables.c b/sound/soc/codecs/wcd9304-tables.c
index 823f926..252cb0e 100644
--- a/sound/soc/codecs/wcd9304-tables.c
+++ b/sound/soc/codecs/wcd9304-tables.c
@@ -590,6 +590,8 @@
 	[SITAR_A_CDC_RX1_B3_CTL] = 1,
 	[SITAR_A_CDC_RX1_B4_CTL] = 1,
 	[SITAR_A_CDC_RX1_B5_CTL] = 1,
+	[SITAR_A_CDC_RX2_B5_CTL] = 1,
+	[SITAR_A_CDC_RX3_B5_CTL] = 1,
 	[SITAR_A_CDC_RX1_B6_CTL] = 1,
 	[SITAR_A_CDC_RX1_VOL_CTL_B1_CTL] = 1,
 	[SITAR_A_CDC_RX1_VOL_CTL_B2_CTL] = 1,
diff --git a/sound/soc/codecs/wcd9304.c b/sound/soc/codecs/wcd9304.c
index 9041bd7..54f527c 100644
--- a/sound/soc/codecs/wcd9304.c
+++ b/sound/soc/codecs/wcd9304.c
@@ -257,6 +257,23 @@
 struct sitar_priv *debug_sitar_priv;
 #endif
 
+static int sitar_get_anc_slot(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+	ucontrol->value.integer.value[0] = sitar->anc_slot;
+	return 0;
+}
+
+static int sitar_put_anc_slot(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+	sitar->anc_slot = ucontrol->value.integer.value[0];
+	return 0;
+}
 
 static int sitar_pa_gain_get(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
@@ -536,6 +553,9 @@
 	SOC_SINGLE("MICBIAS1 CAPLESS Switch", SITAR_A_MICB_1_CTL, 4, 1, 1),
 	SOC_SINGLE("MICBIAS2 CAPLESS Switch", SITAR_A_MICB_2_CTL, 4, 1, 1),
 
+	SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 0, 100, sitar_get_anc_slot,
+				   sitar_put_anc_slot),
+
 	SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
 
 	SOC_SINGLE("TX1 HPF Switch", SITAR_A_CDC_TX1_MUX_CTL, 3, 1, 0),
@@ -629,24 +649,32 @@
 };
 
 static const char *sb_tx5_mux_text[] = {
-	"ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
-		"DEC5"
+	"ZERO", "RMIX1", "RMIX2", "RMIX3", "DEC1", "DEC2", "DEC3", "DEC4"
 };
 
 static const char *dec1_mux_text[] = {
-	"ZERO", "DMIC1", "ADC1", "ADC2", "ADC3", "MBADC", "DMIC4", "ANCFB1",
+	"ZERO", "DMIC1", "ADC1", "ADC2", "ADC3", "MBADC", "DMIC4", "ANC1_FB",
 };
 
 static const char *dec2_mux_text[] = {
-	"ZERO", "DMIC2", "ADC1", "ADC2", "ADC3", "MBADC", "DMIC3", "ANCFB2",
+	"ZERO", "DMIC2", "ADC1", "ADC2", "ADC3", "MBADC", "DMIC3", "ANC2_FB",
 };
 
 static const char *dec3_mux_text[] = {
-	"ZERO", "DMIC2", "DMIC3", "DMIC4", "ADC1", "ADC2", "ADC3", "MBADC",
+	"ZERO", "DMIC3", "ADC1", "ADC2", "ADC3", "MBADC", "DMIC2", "DMIC4"
 };
 
 static const char *dec4_mux_text[] = {
-	"ZERO", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "ADC1", "ADC2", "ADC3",
+	"ZERO", "DMIC4", "ADC1", "ADC2", "ADC3", "DMIC3", "DMIC2", "DMIC1"
+};
+
+static const char const *anc_mux_text[] = {
+	"ZERO", "ADC1", "ADC2", "ADC3", "RSVD1", "RSVD2", "RSVD3",
+	"MBADC", "RSVD4", "DMIC1", "DMIC2",	"DMIC3", "DMIC4"
+};
+
+static const char const *anc1_fb_mux_text[] = {
+	"ZERO", "EAR_HPH_L", "EAR_LINE_1",
 };
 
 static const char *iir1_inp1_text[] = {
@@ -711,6 +739,15 @@
 static const struct soc_enum dec4_mux_enum =
 	SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_B2_CTL, 3, 8, dec4_mux_text);
 
+static const struct soc_enum anc1_mux_enum =
+	SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_ANC_B1_CTL, 0, 13, anc_mux_text);
+
+static const struct soc_enum anc2_mux_enum =
+	SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_ANC_B1_CTL, 4, 13, anc_mux_text);
+
+static const struct soc_enum anc1_fb_mux_enum =
+	SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_ANC_B2_CTL, 0, 3, anc1_fb_mux_text);
+
 static const struct soc_enum iir1_inp1_mux_enum =
 	SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_EQ1_B1_CTL, 0, 16, iir1_inp1_text);
 
@@ -774,6 +811,15 @@
 static const struct snd_kcontrol_new iir1_inp1_mux =
 	SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
 
+static const struct snd_kcontrol_new anc1_mux =
+	SOC_DAPM_ENUM("ANC1 MUX Mux", anc1_mux_enum);
+
+static const struct snd_kcontrol_new anc2_mux =
+	SOC_DAPM_ENUM("ANC2 MUX Mux", anc2_mux_enum);
+
+static const struct snd_kcontrol_new anc1_fb_mux =
+	SOC_DAPM_ENUM("ANC1 FB MUX Mux", anc1_fb_mux_enum);
+
 static const struct snd_kcontrol_new dac1_switch[] = {
 	SOC_DAPM_SINGLE("Switch", SITAR_A_RX_EAR_EN, 5, 1, 0),
 };
@@ -804,27 +850,39 @@
 {
 	struct snd_soc_codec *codec = w->codec;
 	u16 adc_reg;
+	u8 init_bit_shift;
 
 	pr_debug("%s %d\n", __func__, event);
 
 	if (w->reg == SITAR_A_TX_1_2_EN)
 		adc_reg = SITAR_A_TX_1_2_TEST_CTL;
+	else if (w->reg == SITAR_A_TX_3_EN)
+		adc_reg = SITAR_A_TX_3_TEST_CTL;
 	else {
 		pr_err("%s: Error, invalid adc register\n", __func__);
 		return -EINVAL;
 	}
 
+	if (w->shift == 3)
+		init_bit_shift = 6;
+	else if (w->shift == 7)
+		init_bit_shift = 7;
+	else {
+		pr_err("%s: Error, invalid init bit postion adc register\n",
+				__func__);
+		return -EINVAL;
+	}
+
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
 		sitar_codec_enable_adc_block(codec, 1);
+		snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
+							1 << init_bit_shift);
 		break;
 	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_update_bits(codec, adc_reg, 1 << w->shift,
-			1 << w->shift);
-		usleep_range(1000, 1000);
-		snd_soc_update_bits(codec, adc_reg, 1 << w->shift, 0x00);
-		usleep_range(1000, 1000);
-		snd_soc_update_bits(codec, adc_reg, 0x08, 0x08);
+
+		snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
+
 		break;
 	case SND_SOC_DAPM_POST_PMD:
 		sitar_codec_enable_adc_block(codec, 0);
@@ -898,7 +956,7 @@
 	unsigned int dmic;
 	int ret;
 
-	ret = kstrtouint(strpbrk(w->name, "12"), 10, &dmic);
+	ret = kstrtouint(strpbrk(w->name, "1234"), 10, &dmic);
 	if (ret < 0) {
 		pr_err("%s: Invalid DMIC line on the codec\n", __func__);
 		return -EINVAL;
@@ -950,6 +1008,115 @@
 	return 0;
 }
 
+static int sitar_codec_enable_anc(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	const char *filename;
+	const struct firmware *fw;
+	int i;
+	int ret;
+	int num_anc_slots;
+	struct anc_header *anc_head;
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+	u32 anc_writes_size = 0;
+	int anc_size_remaining;
+	u32 *anc_ptr;
+	u16 reg;
+	u8 mask, val, old_val;
+
+	pr_debug("%s %d\n", __func__, event);
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+
+		/* Use the same firmware file as that of WCD9310,
+		 * since the register sequences are same for
+		 * WCD9310 and WCD9304
+		 */
+		filename = "wcd9310/wcd9310_anc.bin";
+
+		ret = request_firmware(&fw, filename, codec->dev);
+		if (ret != 0) {
+			dev_err(codec->dev, "Failed to acquire ANC data: %d\n",
+				ret);
+			return -ENODEV;
+		}
+
+		if (fw->size < sizeof(struct anc_header)) {
+			dev_err(codec->dev, "Not enough data\n");
+			release_firmware(fw);
+			return -ENOMEM;
+		}
+
+		/* First number is the number of register writes */
+		anc_head = (struct anc_header *)(fw->data);
+		anc_ptr = (u32 *)((u32)fw->data + sizeof(struct anc_header));
+		anc_size_remaining = fw->size - sizeof(struct anc_header);
+		num_anc_slots = anc_head->num_anc_slots;
+
+		if (sitar->anc_slot >= num_anc_slots) {
+			dev_err(codec->dev, "Invalid ANC slot selected\n");
+			release_firmware(fw);
+			return -EINVAL;
+		}
+
+		for (i = 0; i < num_anc_slots; i++) {
+
+			if (anc_size_remaining < SITAR_PACKED_REG_SIZE) {
+				dev_err(codec->dev, "Invalid register format\n");
+				release_firmware(fw);
+				return -EINVAL;
+			}
+			anc_writes_size = (u32)(*anc_ptr);
+			anc_size_remaining -= sizeof(u32);
+			anc_ptr += 1;
+
+			if (anc_writes_size * SITAR_PACKED_REG_SIZE
+				> anc_size_remaining) {
+				dev_err(codec->dev, "Invalid register format\n");
+				release_firmware(fw);
+				return -ENOMEM;
+			}
+
+			if (sitar->anc_slot == i)
+				break;
+
+			anc_size_remaining -= (anc_writes_size *
+				SITAR_PACKED_REG_SIZE);
+			anc_ptr += anc_writes_size;
+		}
+		if (i == num_anc_slots) {
+			dev_err(codec->dev, "Selected ANC slot not present\n");
+			release_firmware(fw);
+			return -ENOMEM;
+		}
+
+		for (i = 0; i < anc_writes_size; i++) {
+			SITAR_CODEC_UNPACK_ENTRY(anc_ptr[i], reg,
+				mask, val);
+			old_val = snd_soc_read(codec, reg);
+			snd_soc_write(codec, reg, (old_val & ~mask) |
+				(val & mask));
+		}
+
+		release_firmware(fw);
+
+		/* For Sitar, it is required to enable both Feed-forward
+		 * and Feed back clocks to enable ANC
+		 */
+		snd_soc_write(codec, SITAR_A_CDC_CLK_ANC_CLK_EN_CTL, 0x0F);
+
+		break;
+
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_write(codec, SITAR_A_CDC_CLK_ANC_RESET_CTL, 0xFF);
+		snd_soc_write(codec, SITAR_A_CDC_CLK_ANC_CLK_EN_CTL, 0x00);
+		break;
+	}
+	return 0;
+}
+
+
 static void sitar_codec_start_hs_polling(struct snd_soc_codec *codec)
 {
 	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
@@ -1250,7 +1417,7 @@
 		break;
 	case SND_SOC_DAPM_POST_PMU:
 		if (sitar->mbhc_polling_active &&
-		    sitar->micbias == micb_line) {
+		    sitar->mbhc_cfg.micbias == micb_line) {
 			SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
 			sitar_codec_pause_hs_polling(codec);
 			sitar_codec_start_hs_polling(codec);
@@ -1709,10 +1876,20 @@
 	SND_SOC_DAPM_MUX_E("DEC4 MUX", SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL, 3, 0,
 		&dec4_mux, sitar_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
 
+	SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
+	SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
+
+	SND_SOC_DAPM_MIXER_E("ANC", SND_SOC_NOPM, 0, 0, NULL, 0,
+		sitar_codec_enable_anc, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
+
 	SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, 0, 0, &sb_tx1_mux),
 	SND_SOC_DAPM_MUX("SLIM TX2 MUX", SND_SOC_NOPM, 0, 0, &sb_tx2_mux),
 	SND_SOC_DAPM_MUX("SLIM TX3 MUX", SND_SOC_NOPM, 0, 0, &sb_tx3_mux),
 	SND_SOC_DAPM_MUX("SLIM TX4 MUX", SND_SOC_NOPM, 0, 0, &sb_tx4_mux),
+	SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, 0, 0, &sb_tx5_mux),
 
 	SND_SOC_DAPM_AIF_OUT_E("SLIM TX1", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
 				0, sitar_codec_enable_slimtx,
@@ -1729,6 +1906,10 @@
 				0, sitar_codec_enable_slimtx,
 				SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
 
+	SND_SOC_DAPM_AIF_OUT_E("SLIM TX5", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
+				0, sitar_codec_enable_slimtx,
+				SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
 	/* Digital Mic Inputs */
 	SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
 		sitar_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
@@ -1770,11 +1951,18 @@
 	{"LINEOUT1 PA", NULL, "LINEOUT1 DAC"},
 	{"LINEOUT1 DAC", NULL, "DAC2 MUX"},
 
+	{"ANC1 FB MUX", "EAR_HPH_L", "RX2 MIX1"},
+	{"ANC1 FB MUX", "EAR_LINE_1", "RX3 MIX1"},
+	{"ANC", NULL, "ANC1 FB MUX"},
+
 
 	/* Headset (RX MIX1 and RX MIX2) */
 	{"HEADPHONE", NULL, "HPHL"},
 	{"HEADPHONE", NULL, "HPHR"},
 
+	{"HPHL DAC", NULL, "CP"},
+	{"HPHR DAC", NULL, "CP"},
+
 	{"HPHL", NULL, "HPHL DAC"},
 	{"HPHL DAC", "NULL", "DAC4 MUX"},
 	{"HPHR", NULL, "HPHR DAC"},
@@ -1798,6 +1986,21 @@
 	{"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
 	{"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
 
+	/* ANC */
+	{"ANC", NULL, "ANC1 MUX"},
+	{"ANC", NULL, "ANC2 MUX"},
+	{"ANC1 MUX", "ADC1", "ADC1"},
+	{"ANC1 MUX", "ADC2", "ADC2"},
+	{"ANC1 MUX", "ADC3", "ADC3"},
+	{"ANC2 MUX", "ADC1", "ADC1"},
+	{"ANC2 MUX", "ADC2", "ADC2"},
+	{"ANC2 MUX", "ADC3", "ADC3"},
+
+	{"ANC", NULL, "CDC_CONN"},
+
+	{"RX2 MIX1", NULL, "ANC"},
+	{"RX3 MIX1", NULL, "ANC"},
+
 	/* SLIMBUS Connections */
 
 	/* Slimbus port 5 is non functional in Sitar 1.0 */
@@ -1838,11 +2041,16 @@
 	{"SLIM TX2", NULL, "SLIM TX2 MUX"},
 	{"SLIM TX3", NULL, "SLIM TX3 MUX"},
 	{"SLIM TX4", NULL, "SLIM TX4 MUX"},
+	{"SLIM TX5", NULL, "SLIM TX5 MUX"},
 
 	{"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
 	{"SLIM TX2 MUX", "DEC2", "DEC2 MUX"},
 	{"SLIM TX3 MUX", "DEC3", "DEC3 MUX"},
 	{"SLIM TX4 MUX", "DEC4", "DEC4 MUX"},
+	{"SLIM TX5 MUX", "DEC1", "DEC1 MUX"},
+	{"SLIM TX5 MUX", "DEC2", "DEC2 MUX"},
+	{"SLIM TX5 MUX", "DEC3", "DEC3 MUX"},
+	{"SLIM TX5 MUX", "DEC4", "DEC4 MUX"},
 
 	/* Decimator Inputs */
 	{"DEC1 MUX", "DMIC1", "DMIC1"},
@@ -1862,7 +2070,7 @@
 	{"DEC3 MUX", "ADC2", "ADC2"},
 	{"DEC3 MUX", "ADC3", "ADC3"},
 	{"DEC3 MUX", "DMIC2", "DMIC2"},
-	{"DEC3 MUX", "DMIC3", "DMIC4"},
+	{"DEC3 MUX", "DMIC4", "DMIC4"},
 	{"DEC3 MUX", NULL, "CDC_CONN"},
 	{"DEC4 MUX", "DMIC4", "DMIC4"},
 	{"DEC4 MUX", "ADC1", "ADC1"},
@@ -1950,9 +2158,11 @@
 
 static void sitar_codec_enable_audio_mode_bandgap(struct snd_soc_codec *codec)
 {
+	struct wcd9xxx *sitar_core = dev_get_drvdata(codec->dev->parent);
 
-	snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x0C, 0x04);
-	snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x80, 0x80);
+	if (SITAR_IS_1P0(sitar_core->version))
+		snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x80, 0x80);
+
 	snd_soc_update_bits(codec, SITAR_A_BIAS_CURR_CTL_2, 0x0C, 0x08);
 	usleep_range(1000, 1000);
 	snd_soc_write(codec, SITAR_A_BIAS_REF_CTL, 0x1C);
@@ -1971,6 +2181,7 @@
 	enum sitar_bandgap_type choice)
 {
 	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+	struct wcd9xxx *sitar_core = dev_get_drvdata(codec->dev->parent);
 
 	/* TODO lock resources accessed by audio streams and threaded
 	* interrupt handlers
@@ -1986,6 +2197,7 @@
 		(choice == SITAR_BANDGAP_AUDIO_MODE)) {
 		sitar_codec_enable_audio_mode_bandgap(codec);
 	} else if (choice == SITAR_BANDGAP_MBHC_MODE) {
+		snd_soc_update_bits(codec, SITAR_A_BIAS_CURR_CTL_2, 0x0C, 0x08);
 		snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x2,
 			0x2);
 		snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x80,
@@ -2005,7 +2217,9 @@
 	} else if (choice == SITAR_BANDGAP_OFF) {
 		snd_soc_update_bits(codec, SITAR_A_BIAS_CURR_CTL_2, 0x0C, 0x00);
 		snd_soc_write(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x50);
-		snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0xFF, 0x65);
+		if (SITAR_IS_1P0(sitar_core->version))
+			snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1,
+								0xFF, 0x65);
 		usleep_range(1000, 1000);
 	} else {
 		pr_err("%s: Error, Invalid bandgap settings\n", __func__);
@@ -2321,10 +2535,10 @@
 		}
 	} else if (dai->id == AIF1_CAP) {
 		*tx_num = sitar_dai[dai->id - 1].capture.channels_max;
-		while (cnt < *tx_num) {
-			tx_slot[cnt] = tx_ch[cnt];
-			cnt++;
-		}
+		tx_slot[0] = tx_ch[cnt];
+		tx_slot[1] = tx_ch[4 + cnt];
+		tx_slot[2] = tx_ch[2 + cnt];
+		tx_slot[3] = tx_ch[3 + cnt];
 	}
 	return 0;
 }
@@ -4327,6 +4541,8 @@
 	}
 
 	/* Set voltage level and always use LDO */
+	snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x0C,
+		(pdata->micbias.ldoh_v << 2));
 
 	snd_soc_update_bits(codec, SITAR_A_MICB_CFILT_1_VAL, 0xFC,
 		(k1 << 2));
@@ -4392,23 +4608,20 @@
 
 static const struct sitar_reg_mask_val sitar_1_1_reg_defaults[] = {
 
-	/* Sitar 1.1 MICBIAS changes */
 	SITAR_REG_VAL(SITAR_A_MICB_1_INT_RBIAS, 0x24),
 	SITAR_REG_VAL(SITAR_A_MICB_2_INT_RBIAS, 0x24),
 
-	/* Sitar 1.1 HPH changes */
 	SITAR_REG_VAL(SITAR_A_RX_HPH_BIAS_PA, 0x57),
 	SITAR_REG_VAL(SITAR_A_RX_HPH_BIAS_LDO, 0x56),
 
-	/* Sitar 1.1 EAR PA changes */
 	SITAR_REG_VAL(SITAR_A_RX_EAR_BIAS_PA, 0xA6),
 	SITAR_REG_VAL(SITAR_A_RX_EAR_GAIN, 0x02),
 	SITAR_REG_VAL(SITAR_A_RX_EAR_VCM, 0x03),
 
-	/* Sitar 1.1 RX Changes */
 	SITAR_REG_VAL(SITAR_A_CDC_RX1_B5_CTL, 0x78),
+	SITAR_REG_VAL(SITAR_A_CDC_RX2_B5_CTL, 0x78),
+	SITAR_REG_VAL(SITAR_A_CDC_RX3_B5_CTL, 0x78),
 
-	/* Sitar 1.1 RX1 and RX2 Changes */
 	SITAR_REG_VAL(SITAR_A_CDC_RX1_B6_CTL, 0x80),
 
 	SITAR_REG_VAL(SITAR_A_CDC_CLSG_FREQ_THRESH_B3_CTL, 0x1B),
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index 2d5eab2..88bdcad 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -56,7 +56,8 @@
 #define NUM_ATTEMPTS_INSERT_DETECT 25
 #define NUM_ATTEMPTS_TO_REPORT 5
 
-#define TABLA_JACK_MASK (SND_JACK_HEADSET | SND_JACK_OC_HPHL | SND_JACK_OC_HPHR)
+#define TABLA_JACK_MASK (SND_JACK_HEADSET | SND_JACK_OC_HPHL | \
+			 SND_JACK_OC_HPHR | SND_JACK_UNSUPPORTED)
 
 #define TABLA_I2S_MASTER_MODE_MASK 0x08
 
@@ -67,8 +68,9 @@
 #define AIF2_PB 3
 #define AIF2_CAP 4
 #define AIF3_CAP 5
+#define AIF3_PB  6
 
-#define NUM_CODEC_DAIS 5
+#define NUM_CODEC_DAIS 6
 #define TABLA_COMP_DIGITAL_GAIN_OFFSET 3
 
 struct tabla_codec_dai_data {
@@ -102,6 +104,8 @@
 
 #define TABLA_GPIO_IRQ_DEBOUNCE_TIME_US 5000
 
+#define TABLA_MBHC_GND_MIC_SWAP_THRESHOLD 2
+
 #define TABLA_ACQUIRE_LOCK(x) do { mutex_lock(&x); } while (0)
 #define TABLA_RELEASE_LOCK(x) do { mutex_unlock(&x); } while (0)
 
@@ -214,6 +218,7 @@
 	PLUG_TYPE_HEADSET,
 	PLUG_TYPE_HEADPHONE,
 	PLUG_TYPE_HIGH_HPH,
+	PLUG_TYPE_GND_MIC_SWAP,
 };
 
 enum tabla_mbhc_state {
@@ -240,6 +245,10 @@
 	u32 cfilt2_cnt;
 	u32 cfilt3_cnt;
 	u32 rx_bias_count;
+	s32 dmic_1_2_clk_cnt;
+	s32 dmic_3_4_clk_cnt;
+	s32 dmic_5_6_clk_cnt;
+
 	enum tabla_bandgap_type bandgap_type;
 	bool mclk_enabled;
 	bool clock_active;
@@ -1175,6 +1184,9 @@
 static const struct soc_enum rx_mix1_inp2_chain_enum =
 	SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B1_CTL, 4, 12, rx_mix1_text);
 
+static const struct soc_enum rx_mix1_inp3_chain_enum =
+	SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B2_CTL, 0, 12, rx_mix1_text);
+
 static const struct soc_enum rx2_mix1_inp1_chain_enum =
 	SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B1_CTL, 0, 12, rx_mix1_text);
 
@@ -1317,6 +1329,9 @@
 static const struct snd_kcontrol_new rx_mix1_inp2_mux =
 	SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
 
+static const struct snd_kcontrol_new rx_mix1_inp3_mux =
+	SOC_DAPM_ENUM("RX1 MIX1 INP3 Mux", rx_mix1_inp3_chain_enum);
+
 static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
 	SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
 
@@ -1741,6 +1756,10 @@
 		(choice == TABLA_BANDGAP_AUDIO_MODE)) {
 		tabla_codec_enable_audio_mode_bandgap(codec);
 	} else if (choice == TABLA_BANDGAP_MBHC_MODE) {
+		/* bandgap mode becomes fast,
+		 * mclk should be off or clk buff source souldn't be VBG
+		 * Let's turn off mclk always */
+		WARN_ON(snd_soc_read(codec, TABLA_A_CLK_BUFF_EN2) & (1 << 2));
 		snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x2,
 			0x2);
 		snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
@@ -1770,9 +1789,10 @@
 	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
 	pr_debug("%s\n", __func__);
 	snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x00);
-	ndelay(160);
+	usleep_range(50, 50);
 	snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x02);
 	snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x00);
+	usleep_range(50, 50);
 	tabla->clock_active = false;
 }
 
@@ -1813,21 +1833,23 @@
 	pr_debug("%s: enable = %d\n", __func__, enable);
 	if (enable) {
 		snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x10, 0);
+		/* bandgap mode to fast */
 		snd_soc_write(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x17);
 		usleep_range(5, 5);
 		snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80,
-			0x80);
+				    0x80);
 		snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80,
-			0x80);
+				    0x80);
 		usleep_range(10, 10);
 		snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80, 0);
-		usleep_range(20, 20);
+		usleep_range(10000, 10000);
 		snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x08);
 	} else {
 		snd_soc_update_bits(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x1,
-			0);
+				    0);
 		snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80, 0);
-		snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
+		/* clk source to ext clk and clk buff ref to VBG */
+		snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x0C, 0x04);
 	}
 	tabla->config_mode_active = enable ? true : false;
 
@@ -1835,29 +1857,32 @@
 }
 
 static int tabla_codec_enable_clock_block(struct snd_soc_codec *codec,
-	int config_mode)
+					  int config_mode)
 {
 	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
 
 	pr_debug("%s: config_mode = %d\n", __func__, config_mode);
 
+	/* transit to RCO requires mclk off */
+	WARN_ON(snd_soc_read(codec, TABLA_A_CLK_BUFF_EN2) & (1 << 2));
 	if (config_mode) {
+		/* enable RCO and switch to it */
 		tabla_codec_enable_config_mode(codec, 1);
-		snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x00);
 		snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
-		snd_soc_write(codec, TABLA_A_CLK_BUFF_EN1, 0x0D);
 		usleep_range(1000, 1000);
-	} else
+	} else {
+		/* switch to MCLK */
 		snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
 
-	if (!config_mode && tabla->mbhc_polling_active) {
-		snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
-		tabla_codec_enable_config_mode(codec, 0);
-
+		if (tabla->mbhc_polling_active) {
+			snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
+			tabla_codec_enable_config_mode(codec, 0);
+		}
 	}
 
-	snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x05);
+	snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x01, 0x01);
 	snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x00);
+	/* on MCLK */
 	snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x04);
 	snd_soc_update_bits(codec, TABLA_A_CDC_CLK_MCLK_CTL, 0x01, 0x01);
 	usleep_range(50, 50);
@@ -2013,8 +2038,9 @@
 	struct snd_kcontrol *kcontrol, int event)
 {
 	struct snd_soc_codec *codec = w->codec;
-	u16 tx_dmic_ctl_reg;
-	u8 dmic_clk_sel, dmic_clk_en;
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+	u8  dmic_clk_en;
+	s32 *dmic_clk_cnt;
 	unsigned int dmic;
 	int ret;
 
@@ -2027,20 +2053,31 @@
 	switch (dmic) {
 	case 1:
 	case 2:
-		dmic_clk_sel = 0x02;
 		dmic_clk_en = 0x01;
+		dmic_clk_cnt = &(tabla->dmic_1_2_clk_cnt);
+
+		pr_debug("%s() event %d DMIC%d dmic_1_2_clk_cnt %d\n",
+			__func__, event,  dmic, *dmic_clk_cnt);
+
 		break;
 
 	case 3:
 	case 4:
-		dmic_clk_sel = 0x08;
 		dmic_clk_en = 0x04;
+		dmic_clk_cnt = &(tabla->dmic_3_4_clk_cnt);
+
+		pr_debug("%s() event %d DMIC%d dmic_3_4_clk_cnt %d\n",
+			__func__, event,  dmic, *dmic_clk_cnt);
 		break;
 
 	case 5:
 	case 6:
-		dmic_clk_sel = 0x20;
 		dmic_clk_en = 0x10;
+		dmic_clk_cnt = &(tabla->dmic_5_6_clk_cnt);
+
+		pr_debug("%s() event %d DMIC%d dmic_5_6_clk_cnt %d\n",
+			__func__, event,  dmic, *dmic_clk_cnt);
+
 		break;
 
 	default:
@@ -2048,24 +2085,21 @@
 		return -EINVAL;
 	}
 
-	tx_dmic_ctl_reg = TABLA_A_CDC_TX1_DMIC_CTL + 8 * (dmic - 1);
-
-	pr_debug("%s %d\n", __func__, event);
-
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
 
-		snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
-				dmic_clk_sel, dmic_clk_sel);
+		(*dmic_clk_cnt)++;
+		if (*dmic_clk_cnt == 1)
+			snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
+					dmic_clk_en, dmic_clk_en);
 
-		snd_soc_update_bits(codec, tx_dmic_ctl_reg, 0x1, 0x1);
-
-		snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
-				dmic_clk_en, dmic_clk_en);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
-				dmic_clk_en, 0);
+
+		(*dmic_clk_cnt)--;
+		if (*dmic_clk_cnt  == 0)
+			snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
+					dmic_clk_en, 0);
 		break;
 	}
 	return 0;
@@ -2447,7 +2481,6 @@
 
 		tabla->mbhc_micbias_switched = true;
 		pr_debug("%s: VDDIO switch enabled\n", __func__);
-
 	} else if (!vddio_switch && tabla->mbhc_micbias_switched) {
 		if ((!checkpolling || tabla->mbhc_polling_active) &&
 		    restartpolling)
@@ -3198,6 +3231,7 @@
 
 	{"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
 	{"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
+	{"RX1 MIX1", NULL, "RX1 MIX1 INP3"},
 	{"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
 	{"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
 	{"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
@@ -3224,6 +3258,7 @@
 	{"RX1 MIX1 INP1", "RX2", "SLIM RX2"},
 	{"RX1 MIX1 INP1", "RX3", "SLIM RX3"},
 	{"RX1 MIX1 INP1", "RX4", "SLIM RX4"},
+	{"RX1 MIX1 INP1", "RX5", "SLIM RX5"},
 	{"RX1 MIX1 INP1", "RX6", "SLIM RX6"},
 	{"RX1 MIX1 INP1", "RX7", "SLIM RX7"},
 	{"RX1 MIX1 INP1", "IIR1", "IIR1"},
@@ -3231,13 +3266,22 @@
 	{"RX1 MIX1 INP2", "RX2", "SLIM RX2"},
 	{"RX1 MIX1 INP2", "RX3", "SLIM RX3"},
 	{"RX1 MIX1 INP2", "RX4", "SLIM RX4"},
+	{"RX1 MIX1 INP2", "RX5", "SLIM RX5"},
 	{"RX1 MIX1 INP2", "RX6", "SLIM RX6"},
 	{"RX1 MIX1 INP2", "RX7", "SLIM RX7"},
 	{"RX1 MIX1 INP2", "IIR1", "IIR1"},
+	{"RX1 MIX1 INP3", "RX1", "SLIM RX1"},
+	{"RX1 MIX1 INP3", "RX2", "SLIM RX2"},
+	{"RX1 MIX1 INP3", "RX3", "SLIM RX3"},
+	{"RX1 MIX1 INP3", "RX4", "SLIM RX4"},
+	{"RX1 MIX1 INP3", "RX5", "SLIM RX5"},
+	{"RX1 MIX1 INP3", "RX6", "SLIM RX6"},
+	{"RX1 MIX1 INP3", "RX7", "SLIM RX7"},
 	{"RX2 MIX1 INP1", "RX1", "SLIM RX1"},
 	{"RX2 MIX1 INP1", "RX2", "SLIM RX2"},
 	{"RX2 MIX1 INP1", "RX3", "SLIM RX3"},
 	{"RX2 MIX1 INP1", "RX4", "SLIM RX4"},
+	{"RX2 MIX1 INP1", "RX5", "SLIM RX5"},
 	{"RX2 MIX1 INP1", "RX6", "SLIM RX6"},
 	{"RX2 MIX1 INP1", "RX7", "SLIM RX7"},
 	{"RX2 MIX1 INP1", "IIR1", "IIR1"},
@@ -3245,6 +3289,7 @@
 	{"RX2 MIX1 INP2", "RX2", "SLIM RX2"},
 	{"RX2 MIX1 INP2", "RX3", "SLIM RX3"},
 	{"RX2 MIX1 INP2", "RX4", "SLIM RX4"},
+	{"RX2 MIX1 INP2", "RX5", "SLIM RX5"},
 	{"RX2 MIX1 INP2", "RX6", "SLIM RX6"},
 	{"RX2 MIX1 INP2", "RX7", "SLIM RX7"},
 	{"RX2 MIX1 INP2", "IIR1", "IIR1"},
@@ -3252,6 +3297,7 @@
 	{"RX3 MIX1 INP1", "RX2", "SLIM RX2"},
 	{"RX3 MIX1 INP1", "RX3", "SLIM RX3"},
 	{"RX3 MIX1 INP1", "RX4", "SLIM RX4"},
+	{"RX3 MIX1 INP1", "RX5", "SLIM RX5"},
 	{"RX3 MIX1 INP1", "RX6", "SLIM RX6"},
 	{"RX3 MIX1 INP1", "RX7", "SLIM RX7"},
 	{"RX3 MIX1 INP1", "IIR1", "IIR1"},
@@ -3259,6 +3305,7 @@
 	{"RX3 MIX1 INP2", "RX2", "SLIM RX2"},
 	{"RX3 MIX1 INP2", "RX3", "SLIM RX3"},
 	{"RX3 MIX1 INP2", "RX4", "SLIM RX4"},
+	{"RX3 MIX1 INP2", "RX5", "SLIM RX5"},
 	{"RX3 MIX1 INP2", "RX6", "SLIM RX6"},
 	{"RX3 MIX1 INP2", "RX7", "SLIM RX7"},
 	{"RX3 MIX1 INP2", "IIR1", "IIR1"},
@@ -3266,12 +3313,14 @@
 	{"RX4 MIX1 INP1", "RX2", "SLIM RX2"},
 	{"RX4 MIX1 INP1", "RX3", "SLIM RX3"},
 	{"RX4 MIX1 INP1", "RX4", "SLIM RX4"},
+	{"RX4 MIX1 INP1", "RX5", "SLIM RX5"},
 	{"RX4 MIX1 INP1", "RX6", "SLIM RX6"},
 	{"RX4 MIX1 INP1", "RX7", "SLIM RX7"},
 	{"RX4 MIX1 INP1", "IIR1", "IIR1"},
 	{"RX4 MIX1 INP2", "RX1", "SLIM RX1"},
 	{"RX4 MIX1 INP2", "RX2", "SLIM RX2"},
 	{"RX4 MIX1 INP2", "RX3", "SLIM RX3"},
+	{"RX4 MIX1 INP2", "RX5", "SLIM RX5"},
 	{"RX4 MIX1 INP2", "RX4", "SLIM RX4"},
 	{"RX4 MIX1 INP2", "RX6", "SLIM RX6"},
 	{"RX4 MIX1 INP2", "RX7", "SLIM RX7"},
@@ -3280,6 +3329,7 @@
 	{"RX5 MIX1 INP1", "RX2", "SLIM RX2"},
 	{"RX5 MIX1 INP1", "RX3", "SLIM RX3"},
 	{"RX5 MIX1 INP1", "RX4", "SLIM RX4"},
+	{"RX5 MIX1 INP1", "RX5", "SLIM RX5"},
 	{"RX5 MIX1 INP1", "RX6", "SLIM RX6"},
 	{"RX5 MIX1 INP1", "RX7", "SLIM RX7"},
 	{"RX5 MIX1 INP1", "IIR1", "IIR1"},
@@ -3287,6 +3337,7 @@
 	{"RX5 MIX1 INP2", "RX2", "SLIM RX2"},
 	{"RX5 MIX1 INP2", "RX3", "SLIM RX3"},
 	{"RX5 MIX1 INP2", "RX4", "SLIM RX4"},
+	{"RX5 MIX1 INP2", "RX5", "SLIM RX5"},
 	{"RX5 MIX1 INP2", "RX6", "SLIM RX6"},
 	{"RX5 MIX1 INP2", "RX7", "SLIM RX7"},
 	{"RX5 MIX1 INP2", "IIR1", "IIR1"},
@@ -3294,6 +3345,7 @@
 	{"RX6 MIX1 INP1", "RX2", "SLIM RX2"},
 	{"RX6 MIX1 INP1", "RX3", "SLIM RX3"},
 	{"RX6 MIX1 INP1", "RX4", "SLIM RX4"},
+	{"RX6 MIX1 INP1", "RX5", "SLIM RX5"},
 	{"RX6 MIX1 INP1", "RX6", "SLIM RX6"},
 	{"RX6 MIX1 INP1", "RX7", "SLIM RX7"},
 	{"RX6 MIX1 INP1", "IIR1", "IIR1"},
@@ -3301,6 +3353,7 @@
 	{"RX6 MIX1 INP2", "RX2", "SLIM RX2"},
 	{"RX6 MIX1 INP2", "RX3", "SLIM RX3"},
 	{"RX6 MIX1 INP2", "RX4", "SLIM RX4"},
+	{"RX6 MIX1 INP2", "RX5", "SLIM RX5"},
 	{"RX6 MIX1 INP2", "RX6", "SLIM RX6"},
 	{"RX6 MIX1 INP2", "RX7", "SLIM RX7"},
 	{"RX6 MIX1 INP2", "IIR1", "IIR1"},
@@ -3308,6 +3361,7 @@
 	{"RX7 MIX1 INP1", "RX2", "SLIM RX2"},
 	{"RX7 MIX1 INP1", "RX3", "SLIM RX3"},
 	{"RX7 MIX1 INP1", "RX4", "SLIM RX4"},
+	{"RX7 MIX1 INP1", "RX5", "SLIM RX5"},
 	{"RX7 MIX1 INP1", "RX6", "SLIM RX6"},
 	{"RX7 MIX1 INP1", "RX7", "SLIM RX7"},
 	{"RX7 MIX1 INP1", "IIR1", "IIR1"},
@@ -3315,6 +3369,7 @@
 	{"RX7 MIX1 INP2", "RX2", "SLIM RX2"},
 	{"RX7 MIX1 INP2", "RX3", "SLIM RX3"},
 	{"RX7 MIX1 INP2", "RX4", "SLIM RX4"},
+	{"RX7 MIX1 INP2", "RX5", "SLIM RX5"},
 	{"RX7 MIX1 INP2", "RX6", "SLIM RX6"},
 	{"RX7 MIX1 INP2", "RX7", "SLIM RX7"},
 	{"RX7 MIX1 INP2", "IIR1", "IIR1"},
@@ -3536,6 +3591,10 @@
 	if (tabla_is_digital_gain_register(reg))
 		return 1;
 
+	/* HPH status registers */
+	if (reg == TABLA_A_RX_HPH_L_STATUS || reg == TABLA_A_RX_HPH_R_STATUS)
+		return 1;
+
 	return 0;
 }
 
@@ -3689,16 +3748,18 @@
 	if (mclk_enable) {
 		tabla->mclk_enabled = true;
 
-		if (tabla->mbhc_polling_active && (tabla->mclk_enabled)) {
+		if (tabla->mbhc_polling_active) {
 			tabla_codec_pause_hs_polling(codec);
+			tabla_codec_disable_clock_block(codec);
 			tabla_codec_enable_bandgap(codec,
-					TABLA_BANDGAP_AUDIO_MODE);
+						   TABLA_BANDGAP_AUDIO_MODE);
 			tabla_codec_enable_clock_block(codec, 0);
 			tabla_codec_calibrate_hs_polling(codec);
 			tabla_codec_start_hs_polling(codec);
 		} else {
+			tabla_codec_disable_clock_block(codec);
 			tabla_codec_enable_bandgap(codec,
-					TABLA_BANDGAP_AUDIO_MODE);
+						   TABLA_BANDGAP_AUDIO_MODE);
 			tabla_codec_enable_clock_block(codec, 0);
 		}
 	} else {
@@ -3712,21 +3773,20 @@
 		tabla->mclk_enabled = false;
 
 		if (tabla->mbhc_polling_active) {
-			if (!tabla->mclk_enabled) {
-				tabla_codec_pause_hs_polling(codec);
-				tabla_codec_enable_bandgap(codec,
-					TABLA_BANDGAP_MBHC_MODE);
-				tabla_enable_rx_bias(codec, 1);
-				tabla_codec_enable_clock_block(codec, 1);
-				tabla_codec_calibrate_hs_polling(codec);
-				tabla_codec_start_hs_polling(codec);
-			}
+			tabla_codec_pause_hs_polling(codec);
+			tabla_codec_disable_clock_block(codec);
+			tabla_codec_enable_bandgap(codec,
+						   TABLA_BANDGAP_MBHC_MODE);
+			tabla_enable_rx_bias(codec, 1);
+			tabla_codec_enable_clock_block(codec, 1);
+			tabla_codec_calibrate_hs_polling(codec);
+			tabla_codec_start_hs_polling(codec);
 			snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1,
 					0x05, 0x01);
 		} else {
 			tabla_codec_disable_clock_block(codec);
 			tabla_codec_enable_bandgap(codec,
-				TABLA_BANDGAP_OFF);
+						   TABLA_BANDGAP_OFF);
 		}
 	}
 	if (dapm)
@@ -3790,9 +3850,10 @@
 		pr_err("%s: Invalid\n", __func__);
 		return -EINVAL;
 	}
-	pr_debug("%s: DAI-ID %x %d %d\n", __func__, dai->id, tx_num, rx_num);
+	pr_debug("%s(): dai_name = %s DAI-ID %x tx_ch %d rx_ch %d\n",
+			__func__, dai->name, dai->id, tx_num, rx_num);
 
-	if (dai->id == AIF1_PB || dai->id == AIF2_PB) {
+	if (dai->id == AIF1_PB || dai->id == AIF2_PB || dai->id == AIF3_PB) {
 		for (i = 0; i < rx_num; i++) {
 			tabla->dai[dai->id - 1].ch_num[i]  = rx_slot[i];
 			tabla->dai[dai->id - 1].ch_act = 0;
@@ -3824,7 +3885,7 @@
 		pr_err("%s: Invalid\n", __func__);
 		return -EINVAL;
 	}
-	pr_debug("%s: DAI-ID %x\n", __func__, dai->id);
+
 	/* for virtual port, codec driver needs to do
 	 * housekeeping, for now should be ok
 	 */
@@ -3852,11 +3913,21 @@
 		tx_slot[0] = tx_ch[cnt];
 		tx_slot[1] = tx_ch[1 + cnt];
 		tx_slot[2] = tx_ch[5 + cnt];
+		tx_slot[3] = tx_ch[3 + cnt];
+
+	} else if (dai->id == AIF3_PB) {
+		*rx_num = tabla_dai[dai->id - 1].playback.channels_max;
+		rx_slot[0] = rx_ch[3];
+		rx_slot[1] = rx_ch[4];
+
 	} else if (dai->id == AIF3_CAP) {
 		*tx_num = tabla_dai[dai->id - 1].capture.channels_max;
 		tx_slot[cnt] = tx_ch[2 + cnt];
 		tx_slot[cnt + 1] = tx_ch[4 + cnt];
 	}
+	pr_debug("%s(): dai_name = %s DAI-ID %x tx_ch %d rx_ch %d\n",
+			__func__, dai->name, dai->id, *tx_num, *rx_num);
+
 
 	return 0;
 }
@@ -3872,8 +3943,9 @@
 	u8 tx_fs_rate, rx_fs_rate, rx_state, tx_state;
 	u32 compander_fs;
 
-	pr_debug("%s: DAI-ID %x rate %d\n", __func__, dai->id,
-						params_rate(params));
+	pr_debug("%s: dai_name = %s DAI-ID %x rate %d num_ch %d\n", __func__,
+		 dai->name, dai->id, params_rate(params),
+		 params_channels(params));
 
 	switch (params_rate(params)) {
 	case 8000:
@@ -3970,7 +4042,7 @@
 	 * If current dai is a rx dai, set sample rate to
 	 * all the rx paths that are currently not active
 	 */
-	if (dai->id == AIF1_PB || dai->id == AIF2_PB) {
+	if (dai->id == AIF1_PB || dai->id == AIF2_PB || dai->id == AIF3_PB) {
 
 		rx_state = snd_soc_read(codec,
 			TABLA_A_CDC_CLK_RX_B1_CTL);
@@ -4095,6 +4167,20 @@
 		},
 		.ops = &tabla_dai_ops,
 	},
+	{
+		.name = "tabla_rx3",
+		.id = AIF3_PB,
+		.playback = {
+			.stream_name = "AIF3 Playback",
+			.rates = WCD9310_RATES,
+			.formats = TABLA_FORMATS,
+			.rate_min = 8000,
+			.rate_max = 192000,
+			.channels_min = 1,
+			.channels_max = 2,
+		},
+		.ops = &tabla_dai_ops,
+	},
 };
 
 static struct snd_soc_dai_driver tabla_i2s_dai[] = {
@@ -4141,6 +4227,9 @@
 	/* Execute the callback only if interface type is slimbus */
 	if (tabla_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
 		return 0;
+
+	pr_debug("%s: %s %d\n", __func__, w->name, event);
+
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
 		for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
@@ -4209,7 +4298,8 @@
 	case SND_SOC_DAPM_POST_PMU:
 		for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
 			if (tabla_dai[j].id == AIF1_PB ||
-				tabla_dai[j].id == AIF2_PB)
+				tabla_dai[j].id == AIF2_PB ||
+				tabla_dai[j].id == AIF3_PB)
 				continue;
 			if (!strncmp(w->sname,
 				tabla_dai[j].capture.stream_name, 13)) {
@@ -4226,7 +4316,8 @@
 	case SND_SOC_DAPM_POST_PMD:
 		for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
 			if (tabla_dai[j].id == AIF1_PB ||
-				tabla_dai[j].id == AIF2_PB)
+				tabla_dai[j].id == AIF2_PB ||
+				tabla_dai[j].id == AIF3_PB)
 				continue;
 			if (!strncmp(w->sname,
 				tabla_dai[j].capture.stream_name, 13)) {
@@ -4265,9 +4356,16 @@
 	SND_SOC_DAPM_AIF_IN_E("SLIM RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0,
 				0, tabla_codec_enable_slimrx,
 				SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_AIF_IN_E("SLIM RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0,
+				0, tabla_codec_enable_slimrx,
+				SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
 
-	SND_SOC_DAPM_AIF_IN("SLIM RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
-	SND_SOC_DAPM_AIF_IN("SLIM RX4", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN_E("SLIM RX4", "AIF3 Playback", 0, SND_SOC_NOPM, 0,
+				0, tabla_codec_enable_slimrx,
+				SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_AIF_IN_E("SLIM RX5", "AIF3 Playback", 0, SND_SOC_NOPM, 0,
+				0, tabla_codec_enable_slimrx,
+				SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
 
 	SND_SOC_DAPM_AIF_IN_E("SLIM RX6", "AIF2 Playback", 0, SND_SOC_NOPM, 0,
 				0, tabla_codec_enable_slimrx,
@@ -4376,6 +4474,8 @@
 		&rx_mix1_inp1_mux),
 	SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
 		&rx_mix1_inp2_mux),
+	SND_SOC_DAPM_MUX("RX1 MIX1 INP3", SND_SOC_NOPM, 0, 0,
+		&rx_mix1_inp3_mux),
 	SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
 		&rx2_mix1_inp1_mux),
 	SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
@@ -4569,7 +4669,7 @@
 				SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
 
 	SND_SOC_DAPM_MUX("SLIM TX4 MUX", SND_SOC_NOPM, 0, 0, &sb_tx4_mux),
-	SND_SOC_DAPM_AIF_OUT_E("SLIM TX4", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
+	SND_SOC_DAPM_AIF_OUT_E("SLIM TX4", "AIF2 Capture", 0, SND_SOC_NOPM, 0,
 				0, tabla_codec_enable_slimtx,
 				SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
 
@@ -4762,6 +4862,7 @@
 	}
 
 	if (!tabla->mclk_enabled) {
+		tabla_codec_disable_clock_block(codec);
 		tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_MBHC_MODE);
 		tabla_enable_rx_bias(codec, 1);
 		tabla_codec_enable_clock_block(codec, 1);
@@ -4915,8 +5016,8 @@
 				tabla->buttons_pressed &=
 							~TABLA_JACK_BUTTON_MASK;
 			}
-			pr_debug("%s: Reporting removal %d\n", __func__,
-				 jack_type);
+			pr_debug("%s: Reporting removal %d(%x)\n", __func__,
+				 jack_type, tabla->hph_status);
 			tabla_snd_soc_jack_report(tabla,
 						  tabla->mbhc_cfg.headset_jack,
 						  tabla->hph_status,
@@ -4935,13 +5036,15 @@
 
 		if (jack_type == SND_JACK_HEADPHONE)
 			tabla->current_plug = PLUG_TYPE_HEADPHONE;
+		else if (jack_type == SND_JACK_UNSUPPORTED)
+			tabla->current_plug = PLUG_TYPE_GND_MIC_SWAP;
 		else if (jack_type == SND_JACK_HEADSET) {
 			tabla->mbhc_polling_active = true;
 			tabla->current_plug = PLUG_TYPE_HEADSET;
 		}
 		if (tabla->mbhc_cfg.headset_jack) {
-			pr_debug("%s: Reporting insertion %d\n", __func__,
-				 jack_type);
+			pr_debug("%s: Reporting insertion %d(%x)\n", __func__,
+				 jack_type, tabla->hph_status);
 			tabla_snd_soc_jack_report(tabla,
 						  tabla->mbhc_cfg.headset_jack,
 						  tabla->hph_status,
@@ -5861,8 +5964,8 @@
 	return IRQ_HANDLED;
 }
 
-static bool tabla_is_invalid_insertion_range(struct snd_soc_codec *codec,
-					     s32 mic_volt, bool highhph)
+static bool tabla_is_inval_ins_range(struct snd_soc_codec *codec,
+				     s32 mic_volt, bool highhph, bool *highv)
 {
 	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
 	bool invalid = false;
@@ -5872,7 +5975,8 @@
 	 * needs to be considered as invalid
 	 */
 	v_hs_max = tabla_get_current_v_hs_max(tabla);
-	if (!highhph && (mic_volt > v_hs_max))
+	*highv = mic_volt > v_hs_max;
+	if (!highhph && *highv)
 		invalid = true;
 	else if (mic_volt < tabla->mbhc_data.v_inval_ins_high &&
 		 (mic_volt > tabla->mbhc_data.v_inval_ins_low))
@@ -5881,16 +5985,11 @@
 	return invalid;
 }
 
-static bool tabla_is_inval_insert_delta(struct snd_soc_codec *codec,
-					int mic_volt, int mic_volt_prev,
-					int threshold)
+static bool tabla_is_inval_ins_delta(struct snd_soc_codec *codec,
+				     int mic_volt, int mic_volt_prev,
+				     int threshold)
 {
-	int delta = abs(mic_volt - mic_volt_prev);
-	if (delta > threshold) {
-		pr_debug("%s: volt delta %dmv\n", __func__, delta);
-		return true;
-	}
-	return false;
+	return abs(mic_volt - mic_volt_prev) > threshold;
 }
 
 /* called under codec_resource_lock acquisition */
@@ -5899,13 +5998,21 @@
 {
 	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
 
-	if (plug_type == PLUG_TYPE_HEADPHONE
-		&& tabla->current_plug == PLUG_TYPE_NONE) {
+	if (plug_type == PLUG_TYPE_HEADPHONE &&
+	    tabla->current_plug == PLUG_TYPE_NONE) {
 		/* Nothing was reported previously
-		 * reporte a headphone
+		 * report a headphone or unsupported
 		 */
 		tabla_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
 		tabla_codec_cleanup_hs_polling(codec);
+	} else if (plug_type == PLUG_TYPE_GND_MIC_SWAP) {
+		if (tabla->current_plug == PLUG_TYPE_HEADSET)
+			tabla_codec_report_plug(codec, 0, SND_JACK_HEADSET);
+		else if (tabla->current_plug == PLUG_TYPE_HEADPHONE)
+			tabla_codec_report_plug(codec, 0, SND_JACK_HEADPHONE);
+
+		tabla_codec_report_plug(codec, 1, SND_JACK_UNSUPPORTED);
+		tabla_codec_cleanup_hs_polling(codec);
 	} else if (plug_type == PLUG_TYPE_HEADSET) {
 		/* If Headphone was reported previously, this will
 		 * only report the mic line
@@ -5923,6 +6030,9 @@
 					     MBHC_USE_MB_TRIGGER |
 					     MBHC_USE_HPHL_TRIGGER,
 					     false);
+	} else {
+		WARN(1, "Unexpected current plug_type %d, plug_type %d\n",
+		     tabla->current_plug, plug_type);
 	}
 }
 
@@ -5977,66 +6087,86 @@
 	enum tabla_mbhc_plug_type plug_type[num_det];
 	s16 mb_v[num_det];
 	s32 mic_mv[num_det];
-	bool inval = false;
+	bool inval;
+	bool highdelta;
+	bool ahighv = false, highv;
 
 	/* make sure override is on */
 	WARN_ON(!(snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_CTL) & 0x04));
 
+	/* GND and MIC swap detection requires at least 2 rounds of DCE */
+	BUG_ON(num_det < 2);
+
+	plug_type_ptr =
+	    TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
+
+	plug_type[0] = PLUG_TYPE_INVALID;
+
 	/* performs DCEs for N times
 	 * 1st: check if voltage is in invalid range
 	 * 2nd - N-2nd: check voltage range and delta
 	 * N-1st: check voltage range, delta with HPHR GND switch
 	 * Nth: check voltage range with VDDIO switch if micbias V != vddio V*/
-	for (i = 0; i < num_det && !inval; i++) {
+	for (i = 0; i < num_det; i++) {
 		gndswitch = (i == (num_det - 1 - vddio));
-		vddioswitch = (vddio && (i == num_det - 1));
+		vddioswitch = (vddio && ((i == num_det - 1) ||
+					 (i == num_det - 2)));
 		if (i == 0) {
 			mb_v[i] = tabla_codec_setup_hs_polling(codec);
 			mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
-			inval = tabla_is_invalid_insertion_range(codec,
-								 mic_mv[i],
-								 highhph);
+			inval = tabla_is_inval_ins_range(codec, mic_mv[i],
+							 highhph, &highv);
+			ahighv |= highv;
 			scaled = mic_mv[i];
-		} else if (vddioswitch) {
-			__tabla_codec_switch_micbias(tabla->codec, 1, false,
-						     false);
-			mb_v[i] = __tabla_codec_sta_dce(codec, 1, true, true);
-			mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
-			scaled = tabla_scale_v_micb_vddio(tabla, mic_mv[i],
-							  false);
-			inval = (tabla_is_invalid_insertion_range(codec,
-								  mic_mv[i],
-								  highhph) ||
-				 tabla_is_inval_insert_delta(codec, scaled,
-					  mic_mv[i - 1],
-					  TABLA_MBHC_FAKE_INS_DELTA_SCALED_MV));
-			__tabla_codec_switch_micbias(tabla->codec, 0, false,
-						     false);
 		} else {
+			if (vddioswitch)
+				__tabla_codec_switch_micbias(tabla->codec, 1,
+							     false, false);
 			if (gndswitch)
 				tabla_codec_hphr_gnd_switch(codec, true);
 			mb_v[i] = __tabla_codec_sta_dce(codec, 1, true, true);
 			mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
-			inval = (tabla_is_invalid_insertion_range(codec,
+			if (vddioswitch)
+				scaled = tabla_scale_v_micb_vddio(tabla,
 								  mic_mv[i],
-								  highhph) ||
-				 tabla_is_inval_insert_delta(codec, mic_mv[i],
-					  mic_mv[i - 1],
-					  TABLA_MBHC_FAKE_INS_DELTA_SCALED_MV));
+								  false);
+			else
+				scaled = mic_mv[i];
+			/* !gndswitch & vddioswitch means the previous DCE
+			 * was done with gndswitch, don't compare with DCE
+			 * with gndswitch */
+			highdelta = tabla_is_inval_ins_delta(codec, scaled,
+					mic_mv[i - !gndswitch - vddioswitch],
+					TABLA_MBHC_FAKE_INS_DELTA_SCALED_MV);
+			inval = (tabla_is_inval_ins_range(codec, mic_mv[i],
+							  highhph, &highv) ||
+				 highdelta);
+			ahighv |= highv;
 			if (gndswitch)
 				tabla_codec_hphr_gnd_switch(codec, false);
-			scaled = mic_mv[i];
+			if (vddioswitch)
+				__tabla_codec_switch_micbias(tabla->codec, 0,
+							     false, false);
+			/* claim UNSUPPORTED plug insertion when
+			 * good headset is detected but HPHR GND switch makes
+			 * delta difference */
+			if (i == (num_det - 2) && highdelta && !ahighv)
+				plug_type[0] = PLUG_TYPE_GND_MIC_SWAP;
+			else if (i == (num_det - 1) && inval)
+				plug_type[0] = PLUG_TYPE_INVALID;
 		}
 		pr_debug("%s: DCE #%d, %04x, V %d, scaled V %d, GND %d, "
-			 "invalid %d\n", __func__,
+			 "VDDIO %d, inval %d\n", __func__,
 			 i + 1, mb_v[i] & 0xffff, mic_mv[i], scaled, gndswitch,
-			 inval);
+			 vddioswitch, inval);
+		/* don't need to run further DCEs */
+		if (ahighv && inval)
+			break;
+		mic_mv[i] = scaled;
 	}
 
-	plug_type_ptr =
-	    TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
-	plug_type[0] = PLUG_TYPE_INVALID;
-	for (i = 0; !inval && i < num_det; i++) {
+	for (i = 0; (plug_type[0] != PLUG_TYPE_GND_MIC_SWAP && !inval) &&
+		     i < num_det; i++) {
 		/*
 		 * If we are here, means none of the all
 		 * measurements are fake, continue plug type detection.
@@ -6066,6 +6196,7 @@
 		}
 	}
 
+	pr_debug("%s: Detected plug type %d\n", __func__, plug_type[0]);
 	return plug_type[0];
 }
 
@@ -6073,7 +6204,7 @@
 {
 	struct tabla_priv *tabla;
 	struct snd_soc_codec *codec;
-	int retry = 0;
+	int retry = 0, pt_gnd_mic_swap_cnt = 0;
 	bool correction = false;
 	enum tabla_mbhc_plug_type plug_type;
 	unsigned long timeout;
@@ -6124,14 +6255,33 @@
 			}
 		} else if (plug_type == PLUG_TYPE_HEADPHONE) {
 			pr_debug("Good headphone detected, continue polling mic\n");
-			if (tabla->current_plug == PLUG_TYPE_NONE) {
+			if (tabla->current_plug == PLUG_TYPE_NONE)
 				tabla_codec_report_plug(codec, 1,
 							SND_JACK_HEADPHONE);
-			}
 		} else {
+			if (plug_type == PLUG_TYPE_GND_MIC_SWAP) {
+				pt_gnd_mic_swap_cnt++;
+				if (pt_gnd_mic_swap_cnt <
+				    TABLA_MBHC_GND_MIC_SWAP_THRESHOLD)
+					continue;
+				else if (pt_gnd_mic_swap_cnt >
+					 TABLA_MBHC_GND_MIC_SWAP_THRESHOLD) {
+					/* This is due to GND/MIC switch didn't
+					 * work,  Report unsupported plug */
+				} else if (tabla->mbhc_cfg.swap_gnd_mic) {
+					/* if switch is toggled, check again,
+					 * otherwise report unsupported plug */
+					if (tabla->mbhc_cfg.swap_gnd_mic(codec))
+						continue;
+				}
+			} else
+				pt_gnd_mic_swap_cnt = 0;
+
 			TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
 			/* Turn off override */
 			tabla_turn_onoff_override(codec, false);
+			/* The valid plug also includes PLUG_TYPE_GND_MIC_SWAP
+			 */
 			tabla_find_plug_and_report(codec, plug_type);
 			TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
 			pr_debug("Attempt %d found correct plug %d\n", retry,
@@ -6154,8 +6304,8 @@
 /* called under codec_resource_lock acquisition */
 static void tabla_codec_decide_gpio_plug(struct snd_soc_codec *codec)
 {
-	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
 	enum tabla_mbhc_plug_type plug_type;
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
 
 	pr_debug("%s: enter\n", __func__);
 
@@ -6169,7 +6319,8 @@
 		return;
 	}
 
-	if (plug_type == PLUG_TYPE_INVALID) {
+	if (plug_type == PLUG_TYPE_INVALID ||
+	    plug_type == PLUG_TYPE_GND_MIC_SWAP) {
 		tabla_schedule_hs_detect_plug(tabla);
 	} else if (plug_type == PLUG_TYPE_HEADPHONE) {
 		tabla_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
@@ -6211,18 +6362,21 @@
 		return;
 	}
 
-	plug_type = tabla_codec_get_plug_type(codec, tabla->mbhc_cfg.gpio ?
-						     true : false);
+	plug_type = tabla_codec_get_plug_type(codec, false);
 	tabla_turn_onoff_override(codec, false);
 
 	if (plug_type == PLUG_TYPE_INVALID) {
 		pr_debug("%s: Invalid plug type detected\n", __func__);
-		snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
-				    0x02, 0x02);
+		snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x02, 0x02);
 		tabla_codec_cleanup_hs_polling(codec);
 		tabla_codec_enable_hs_detect(codec, 1,
 					     MBHC_USE_MB_TRIGGER |
 					     MBHC_USE_HPHL_TRIGGER, false);
+	} else if (plug_type == PLUG_TYPE_GND_MIC_SWAP) {
+		pr_debug("%s: GND-MIC swapped plug type detected\n", __func__);
+		tabla_codec_report_plug(codec, 1, SND_JACK_UNSUPPORTED);
+		tabla_codec_cleanup_hs_polling(codec);
+		tabla_codec_enable_hs_detect(codec, 0, 0, false);
 	} else if (plug_type == PLUG_TYPE_HEADPHONE) {
 		pr_debug("%s: Headphone Detected\n", __func__);
 		tabla_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
@@ -6284,7 +6438,13 @@
 		 * it is possible that micbias will be switched to VDDIO.
 		 */
 		tabla_codec_switch_micbias(codec, 0);
-		tabla_codec_report_plug(codec, 0, SND_JACK_HEADPHONE);
+		if (priv->current_plug == PLUG_TYPE_HEADPHONE)
+			tabla_codec_report_plug(codec, 0, SND_JACK_HEADPHONE);
+		else if (priv->current_plug == PLUG_TYPE_GND_MIC_SWAP)
+			tabla_codec_report_plug(codec, 0, SND_JACK_UNSUPPORTED);
+		else
+			WARN(1, "%s: Unexpected current plug type %d\n",
+			     __func__, priv->current_plug);
 		tabla_codec_shutdown_hs_removal_detect(codec);
 		tabla_codec_enable_hs_detect(codec, 1,
 					     MBHC_USE_MB_TRIGGER |
@@ -6598,6 +6758,9 @@
 		if (tabla->current_plug == PLUG_TYPE_HEADPHONE) {
 			tabla_codec_report_plug(codec, 0, SND_JACK_HEADPHONE);
 			is_removed = true;
+		} else if (tabla->current_plug == PLUG_TYPE_GND_MIC_SWAP) {
+			tabla_codec_report_plug(codec, 0, SND_JACK_UNSUPPORTED);
+			is_removed = true;
 		} else if (tabla->current_plug == PLUG_TYPE_HEADSET) {
 			tabla_codec_pause_hs_polling(codec);
 			tabla_codec_cleanup_hs_polling(codec);
@@ -6650,17 +6813,70 @@
 	return r;
 }
 
+static int tabla_mbhc_init_and_calibrate(struct tabla_priv *tabla)
+{
+	int ret = 0;
+	struct snd_soc_codec *codec = tabla->codec;
+
+	tabla->mbhc_cfg.mclk_cb_fn(codec, 1, false);
+	tabla_mbhc_init(codec);
+	tabla_mbhc_cal(codec);
+	tabla_mbhc_calc_thres(codec);
+	tabla->mbhc_cfg.mclk_cb_fn(codec, 0, false);
+	tabla_codec_calibrate_hs_polling(codec);
+	if (!tabla->mbhc_cfg.gpio) {
+		ret = tabla_codec_enable_hs_detect(codec, 1,
+						   MBHC_USE_MB_TRIGGER |
+						   MBHC_USE_HPHL_TRIGGER,
+						   false);
+
+		if (IS_ERR_VALUE(ret))
+			pr_err("%s: Failed to setup MBHC detection\n",
+			       __func__);
+	} else {
+		/* Enable Mic Bias pull down and HPH Switch to GND */
+		snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg,
+				    0x01, 0x01);
+		snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x01, 0x01);
+		INIT_WORK(&tabla->hs_correct_plug_work,
+			  tabla_hs_correct_gpio_plug);
+	}
+
+	if (!IS_ERR_VALUE(ret)) {
+		snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10, 0x10);
+		wcd9xxx_enable_irq(codec->control_data,
+				 TABLA_IRQ_HPH_PA_OCPL_FAULT);
+		wcd9xxx_enable_irq(codec->control_data,
+				 TABLA_IRQ_HPH_PA_OCPR_FAULT);
+
+		if (tabla->mbhc_cfg.gpio) {
+			ret = request_threaded_irq(tabla->mbhc_cfg.gpio_irq,
+					       NULL,
+					       tabla_mechanical_plug_detect_irq,
+					       (IRQF_TRIGGER_RISING |
+						IRQF_TRIGGER_FALLING),
+					       "tabla-gpio", codec);
+			if (!IS_ERR_VALUE(ret)) {
+				ret = enable_irq_wake(tabla->mbhc_cfg.gpio_irq);
+				/* Bootup time detection */
+				tabla_hs_gpio_handler(codec);
+			}
+		}
+	}
+
+	return ret;
+}
+
 static void mbhc_fw_read(struct work_struct *work)
 {
 	struct delayed_work *dwork;
 	struct tabla_priv *tabla;
 	struct snd_soc_codec *codec;
 	const struct firmware *fw;
-	int ret = -1, retry = 0, rc;
+	int ret = -1, retry = 0;
 
 	dwork = to_delayed_work(work);
-	tabla = container_of(dwork, struct tabla_priv,
-				mbhc_firmware_dwork);
+	tabla = container_of(dwork, struct tabla_priv, mbhc_firmware_dwork);
 	codec = tabla->codec;
 
 	while (retry < MBHC_FW_READ_ATTEMPTS) {
@@ -6672,7 +6888,7 @@
 
 		if (ret != 0) {
 			usleep_range(MBHC_FW_READ_TIMEOUT,
-					MBHC_FW_READ_TIMEOUT);
+				     MBHC_FW_READ_TIMEOUT);
 		} else {
 			pr_info("%s: MBHC Firmware read succesful\n", __func__);
 			break;
@@ -6691,32 +6907,7 @@
 		tabla->mbhc_fw = fw;
 	}
 
-	tabla->mbhc_cfg.mclk_cb_fn(codec, 1, false);
-	tabla_mbhc_init(codec);
-	tabla_mbhc_cal(codec);
-	tabla_mbhc_calc_thres(codec);
-	tabla->mbhc_cfg.mclk_cb_fn(codec, 0, false);
-	tabla_codec_calibrate_hs_polling(codec);
-	if (!tabla->mbhc_cfg.gpio) {
-		rc = tabla_codec_enable_hs_detect(codec, 1,
-						  MBHC_USE_MB_TRIGGER |
-						  MBHC_USE_HPHL_TRIGGER,
-						  false);
-
-		if (IS_ERR_VALUE(rc))
-			pr_err("%s: Failed to setup MBHC detection\n",
-			       __func__);
-	} else {
-		/* Enable Mic Bias pull down and HPH Switch to GND */
-		snd_soc_update_bits(codec,
-				    tabla->mbhc_bias_regs.ctl_reg, 0x01,
-				    0x01);
-		snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x01,
-				    0x01);
-		INIT_WORK(&tabla->hs_correct_plug_work,
-				  tabla_hs_correct_gpio_plug);
-	}
-
+	(void) tabla_mbhc_init_and_calibrate(tabla);
 }
 
 int tabla_hs_detect(struct snd_soc_codec *codec,
@@ -6756,53 +6947,11 @@
 	INIT_WORK(&tabla->hphrocp_work, hphrocp_off_report);
 	INIT_DELAYED_WORK(&tabla->mbhc_insert_dwork, mbhc_insert_work);
 
-	if (!tabla->mbhc_cfg.read_fw_bin) {
-		tabla->mbhc_cfg.mclk_cb_fn(codec, 1, false);
-		tabla_mbhc_init(codec);
-		tabla_mbhc_cal(codec);
-		tabla_mbhc_calc_thres(codec);
-		tabla->mbhc_cfg.mclk_cb_fn(codec, 0, false);
-		tabla_codec_calibrate_hs_polling(codec);
-		if (!tabla->mbhc_cfg.gpio) {
-			rc =  tabla_codec_enable_hs_detect(codec, 1,
-							  MBHC_USE_MB_TRIGGER |
-							  MBHC_USE_HPHL_TRIGGER,
-							  false);
-		} else {
-			/* Enable Mic Bias pull down and HPH Switch to GND */
-			snd_soc_update_bits(codec,
-					    tabla->mbhc_bias_regs.ctl_reg, 0x01,
-					    0x01);
-			snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x01,
-					    0x01);
-			INIT_WORK(&tabla->hs_correct_plug_work,
-				  tabla_hs_correct_gpio_plug);
-		}
-	} else {
+	if (!tabla->mbhc_cfg.read_fw_bin)
+		rc = tabla_mbhc_init_and_calibrate(tabla);
+	else
 		schedule_delayed_work(&tabla->mbhc_firmware_dwork,
 				      usecs_to_jiffies(MBHC_FW_READ_TIMEOUT));
-	}
-
-	if (!IS_ERR_VALUE(rc)) {
-		snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10, 0x10);
-		wcd9xxx_enable_irq(codec->control_data,
-				 TABLA_IRQ_HPH_PA_OCPL_FAULT);
-		wcd9xxx_enable_irq(codec->control_data,
-				 TABLA_IRQ_HPH_PA_OCPR_FAULT);
-	}
-
-	if (!IS_ERR_VALUE(rc) && tabla->mbhc_cfg.gpio) {
-		rc = request_threaded_irq(tabla->mbhc_cfg.gpio_irq, NULL,
-					   tabla_mechanical_plug_detect_irq,
-					   (IRQF_TRIGGER_RISING |
-					    IRQF_TRIGGER_FALLING),
-					   "tabla-gpio", codec);
-		if (!IS_ERR_VALUE(rc)) {
-			rc = enable_irq_wake(tabla->mbhc_cfg.gpio_irq);
-			/* Bootup time detection */
-			tabla_hs_gpio_handler(codec);
-		}
-	}
 
 	return rc;
 }
@@ -6837,7 +6986,6 @@
 	return IRQ_HANDLED;
 }
 
-
 static int tabla_handle_pdata(struct tabla_priv *tabla)
 {
 	struct snd_soc_codec *codec = tabla->codec;
@@ -7106,6 +7254,22 @@
 	{TABLA_A_CDC_TX8_MUX_CTL, 0x8, 0x0},
 	{TABLA_A_CDC_TX9_MUX_CTL, 0x8, 0x0},
 	{TABLA_A_CDC_TX10_MUX_CTL, 0x8, 0x0},
+
+	/* config Decimator for DMIC CLK_MODE_1(3.072Mhz@12.88Mhz mclk) */
+	{TABLA_A_CDC_TX1_DMIC_CTL, 0x1, 0x1},
+	{TABLA_A_CDC_TX2_DMIC_CTL, 0x1, 0x1},
+	{TABLA_A_CDC_TX3_DMIC_CTL, 0x1, 0x1},
+	{TABLA_A_CDC_TX4_DMIC_CTL, 0x1, 0x1},
+	{TABLA_A_CDC_TX5_DMIC_CTL, 0x1, 0x1},
+	{TABLA_A_CDC_TX6_DMIC_CTL, 0x1, 0x1},
+	{TABLA_A_CDC_TX7_DMIC_CTL, 0x1, 0x1},
+	{TABLA_A_CDC_TX8_DMIC_CTL, 0x1, 0x1},
+	{TABLA_A_CDC_TX9_DMIC_CTL, 0x1, 0x1},
+	{TABLA_A_CDC_TX10_DMIC_CTL, 0x1, 0x1},
+
+	/* config DMIC clk to CLK_MODE_1 (3.072Mhz@12.88Mhz mclk) */
+	{TABLA_A_CDC_CLK_DMIC_CTL, 0x2A, 0x2A},
+
 };
 
 static const struct tabla_reg_mask_val tabla_1_x_codec_reg_init_val[] = {
@@ -7248,6 +7412,9 @@
 		       p->v_inval_ins_low);
 	n += scnprintf(buffer + n, size - n, "v_inval_ins_high = %d\n",
 		       p->v_inval_ins_high);
+	if (tabla->mbhc_cfg.gpio)
+		n += scnprintf(buffer + n, size - n, "GPIO insert = %d\n",
+			       tabla_hs_gpio_level_remove(tabla));
 	buffer[n] = 0;
 
 	return simple_read_from_buffer(buf, count, pos, buffer, n);
@@ -7449,6 +7616,9 @@
 		case AIF2_CAP:
 			ch_cnt = tabla_dai[i].capture.channels_max;
 			break;
+		case AIF3_PB:
+			ch_cnt = tabla_dai[i].playback.channels_max;
+			break;
 		case AIF3_CAP:
 			ch_cnt = tabla_dai[i].capture.channels_max;
 			break;
diff --git a/sound/soc/codecs/wcd9310.h b/sound/soc/codecs/wcd9310.h
index 38ec27c..1cca360 100644
--- a/sound/soc/codecs/wcd9310.h
+++ b/sound/soc/codecs/wcd9310.h
@@ -176,6 +176,8 @@
 	unsigned int gpio;
 	unsigned int gpio_irq;
 	int gpio_level_insert;
+	/* swap_gnd_mic returns true if extern GND/MIC swap switch toggled */
+	bool (*swap_gnd_mic) (struct snd_soc_codec *);
 };
 
 extern int tabla_hs_detect(struct snd_soc_codec *codec,
diff --git a/sound/soc/msm/Makefile b/sound/soc/msm/Makefile
index b3cffd1..43c678d 100644
--- a/sound/soc/msm/Makefile
+++ b/sound/soc/msm/Makefile
@@ -75,3 +75,12 @@
 # for MDM 9615 sound card driver
 snd-soc-mdm9615-objs := mdm9615.o
 obj-$(CONFIG_SND_SOC_MDM9615) += snd-soc-mdm9615.o
+
+# for MSM 8974 sound card driver
+obj-$(CONFIG_SND_SOC_MSM_QDSP6V2_INTF) += qdsp6v2/
+snd-soc-msm8974-objs := msm8974.o
+obj-$(CONFIG_SND_SOC_MSM8974) += snd-soc-msm8974.o
+
+snd-soc-qdsp6v2-objs := msm-dai-fe.o msm-dai-stub.o
+obj-$(CONFIG_SND_SOC_QDSP6V2) += snd-soc-qdsp6v2.o
+
diff --git a/sound/soc/msm/apq8064.c b/sound/soc/msm/apq8064.c
index c8ef419..72c7e47 100644
--- a/sound/soc/msm/apq8064.c
+++ b/sound/soc/msm/apq8064.c
@@ -58,13 +58,16 @@
 #define TABLA_MBHC_DEF_BUTTONS 8
 #define TABLA_MBHC_DEF_RLOADS 5
 
+#define JACK_DETECT_GPIO 38
+
 /* Shared channel numbers for Slimbus ports that connect APQ to MDM. */
 enum {
 	SLIM_1_RX_1 = 145, /* BT-SCO and USB TX */
 	SLIM_1_TX_1 = 146, /* BT-SCO and USB RX */
 	SLIM_3_RX_1 = 151, /* External echo-cancellation ref */
 	SLIM_3_RX_2 = 152, /* External echo-cancellation ref */
-	SLIM_3_TX_1 = 147, /* HDMI RX */
+	SLIM_3_TX_1 = 153, /* HDMI RX */
+	SLIM_3_TX_2 = 154, /* HDMI RX */
 	SLIM_4_TX_1 = 148, /* In-call recording RX */
 	SLIM_4_TX_2 = 149, /* In-call recording RX */
 	SLIM_4_RX_1 = 150, /* In-call music delivery TX */
@@ -97,6 +100,15 @@
 static struct snd_soc_jack hs_jack;
 static struct snd_soc_jack button_jack;
 
+static int apq8064_hs_detect_use_gpio = -1;
+module_param(apq8064_hs_detect_use_gpio, int, 0444);
+MODULE_PARM_DESC(apq8064_hs_detect_use_gpio, "Use GPIO for headset detection");
+
+static bool apq8064_hs_detect_use_firmware;
+module_param(apq8064_hs_detect_use_firmware, bool, 0444);
+MODULE_PARM_DESC(apq8064_hs_detect_use_firmware, "Use firmware for headset "
+		 "detection");
+
 static int msm_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
 				    bool dapm);
 
@@ -108,7 +120,7 @@
 	.micbias = TABLA_MICBIAS2,
 	.mclk_cb_fn = msm_enable_codec_ext_clk,
 	.mclk_rate = TABLA_EXT_CLK_RATE,
-	.gpio = 0, /* MBHC GPIO is not configured */
+	.gpio = 0,
 	.gpio_irq = 0,
 	.gpio_level_insert = 1,
 };
@@ -973,6 +985,7 @@
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 	int ret = 0;
 	unsigned int rx_ch[2] = {SLIM_3_RX_1, SLIM_3_RX_2};
+	unsigned int tx_ch[2] = {SLIM_3_TX_1, SLIM_3_TX_2};
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		pr_debug("%s: slim_3_rx_ch %d, sch %d %d\n",
@@ -988,7 +1001,16 @@
 			goto end;
 		}
 	} else {
-		pr_err("%s: SLIMBUS_3_TX not defined for this DAI\n", __func__);
+		pr_debug("%s: MDM RX -> SLIMBUS_3_TX -> APQ HDMI ch: %d, %d\n",
+			__func__, tx_ch[0], tx_ch[1]);
+
+		ret = snd_soc_dai_set_channel_map(cpu_dai, 2, tx_ch, 0, 0);
+		if (ret < 0) {
+			pr_err("%s: Erorr %d setting SLIM_3 TX channel map\n",
+				__func__, ret);
+
+			goto end;
+		}
 	}
 
 end:
@@ -1037,10 +1059,10 @@
 	return ret;
 }
 
-
 static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
 {
 	int err;
+	uint32_t revision;
 	struct snd_soc_codec *codec = rtd->codec;
 	struct snd_soc_dapm_context *dapm = &codec->dapm;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
@@ -1097,6 +1119,48 @@
 
 	codec_clk = clk_get(cpu_dai->dev, "osr_clk");
 
+	/* APQ8064 Rev 1.1 CDP and Liquid have mechanical switch */
+	revision = socinfo_get_version();
+	if (apq8064_hs_detect_use_gpio != -1) {
+		if (apq8064_hs_detect_use_gpio == 1)
+			pr_debug("%s: MBHC mechanical is enabled by request\n",
+				 __func__);
+		else if (apq8064_hs_detect_use_gpio == 0)
+			pr_debug("%s: MBHC mechanical is disabled by request\n",
+				 __func__);
+		else
+			pr_warn("%s: Invalid hs_detect_use_gpio %d\n", __func__,
+				apq8064_hs_detect_use_gpio);
+	} else if (SOCINFO_VERSION_MAJOR(revision) == 0) {
+		pr_warn("%s: Unknown HW revision detected %d.%d\n", __func__,
+			SOCINFO_VERSION_MAJOR(revision),
+			SOCINFO_VERSION_MINOR(revision));
+	} else if ((SOCINFO_VERSION_MAJOR(revision) == 1 &&
+		    SOCINFO_VERSION_MINOR(revision) >= 1 &&
+		    (machine_is_apq8064_cdp() ||
+		     machine_is_apq8064_liquid())) ||
+		   SOCINFO_VERSION_MAJOR(revision) > 1) {
+		pr_debug("%s: MBHC mechanical switch available APQ8064 "
+			 "detected\n", __func__);
+		apq8064_hs_detect_use_gpio = 1;
+	}
+
+	if (apq8064_hs_detect_use_gpio == 1) {
+		pr_debug("%s: Using MBHC mechanical switch\n", __func__);
+		mbhc_cfg.gpio = JACK_DETECT_GPIO;
+		mbhc_cfg.gpio_irq = gpio_to_irq(JACK_DETECT_GPIO);
+		err = gpio_request(mbhc_cfg.gpio, "MBHC_HS_DETECT");
+		if (err < 0) {
+			pr_err("%s: gpio_request %d failed %d\n", __func__,
+			       mbhc_cfg.gpio, err);
+			return err;
+		}
+		gpio_direction_input(JACK_DETECT_GPIO);
+	} else
+		pr_debug("%s: Not using MBHC mechanical switch\n", __func__);
+
+	mbhc_cfg.read_fw_bin = apq8064_hs_detect_use_firmware;
+
 	err = tabla_hs_detect(codec, &mbhc_cfg);
 
 	return err;
@@ -1119,7 +1183,8 @@
 	},
 };
 
-static struct snd_soc_dsp_link slimbus0_hl_media = {
+/* bi-directional media definition for hostless PCM device */
+static struct snd_soc_dsp_link bidir_hl_media = {
 	.playback = true,
 	.capture = true,
 	.trigger = {
@@ -1128,9 +1193,8 @@
 	},
 };
 
-static struct snd_soc_dsp_link int_fm_hl_media = {
+static struct snd_soc_dsp_link hdmi_rx_hl = {
 	.playback = true,
-	.capture = true,
 	.trigger = {
 		SND_SOC_DSP_TRIGGER_POST,
 		SND_SOC_DSP_TRIGGER_POST
@@ -1185,6 +1249,22 @@
 	return 0;
 }
 
+static int msm_slim_3_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+			struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+			SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+			SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	pr_debug("%s()\n", __func__);
+	rate->min = rate->max = 48000;
+	channels->min = channels->max = 2;
+
+	return 0;
+}
+
 static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 			struct snd_pcm_hw_params *params)
 {
@@ -1377,7 +1457,7 @@
 		.name = "MSM8960 Media2",
 		.stream_name = "MultiMedia2",
 		.cpu_dai_name	= "MultiMedia2",
-		.platform_name  = "msm-pcm-dsp",
+		.platform_name  = "msm-multi-ch-pcm-dsp",
 		.dynamic = 1,
 		.dsp_link = &fe_media,
 		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
@@ -1418,7 +1498,7 @@
 		.cpu_dai_name	= "SLIMBUS0_HOSTLESS",
 		.platform_name  = "msm-pcm-hostless",
 		.dynamic = 1,
-		.dsp_link = &slimbus0_hl_media,
+		.dsp_link = &bidir_hl_media,
 		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
 		.ignore_suspend = 1,
 		/* .be_id = do not care */
@@ -1429,7 +1509,7 @@
 		.cpu_dai_name	= "INT_FM_HOSTLESS",
 		.platform_name  = "msm-pcm-hostless",
 		.dynamic = 1,
-		.dsp_link = &int_fm_hl_media,
+		.dsp_link = &bidir_hl_media,
 		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
 		.ignore_suspend = 1,
 		/* .be_id = do not care */
@@ -1453,6 +1533,37 @@
 		.ignore_suspend = 1,
 	},
 	{
+		.name = "MSM8960 Compr",
+		.stream_name = "COMPR",
+		.cpu_dai_name	= "MultiMedia4",
+		.platform_name  = "msm-compr-dsp",
+		.dynamic = 1,
+		.dsp_link = &lpa_fe_media,
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA4,
+	},
+	{
+		.name = "AUXPCM Hostless",
+		.stream_name = "AUXPCM Hostless",
+		.cpu_dai_name	= "AUXPCM_HOSTLESS",
+		.platform_name  = "msm-pcm-hostless",
+		.dynamic = 1,
+		.dsp_link = &bidir_hl_media,
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+	},
+	/* HDMI Hostless */
+	{
+		.name = "HDMI_RX_HOSTLESS",
+		.stream_name = "HDMI_RX_HOSTLESS",
+		.cpu_dai_name = "HDMI_HOSTLESS",
+		.platform_name = "msm-pcm-hostless",
+		.dynamic = 1,
+		.dsp_link = &hdmi_rx_hl,
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.no_codec = 1,
+		.ignore_suspend = 1,
+	},
+	{
 		.name = "Voice Stub",
 		.stream_name = "Voice Stub",
 		.cpu_dai_name = "VOICE_STUB",
@@ -1716,6 +1827,18 @@
 		.be_hw_params_fixup = msm_slim_3_rx_be_hw_params_fixup,
 		.ops = &msm_slimbus_3_be_ops,
 	},
+	{
+		.name = LPASS_BE_SLIMBUS_3_TX,
+		.stream_name = "Slimbus3 Capture",
+		.cpu_dai_name = "msm-dai-q6.16391",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_3_TX,
+		.be_hw_params_fixup = msm_slim_3_tx_be_hw_params_fixup,
+		.ops = &msm_slimbus_3_be_ops,
+	},
 };
 
 struct snd_soc_card snd_soc_card_msm = {
@@ -1826,6 +1949,8 @@
 	}
 	msm_free_headset_mic_gpios();
 	platform_device_unregister(msm_snd_device);
+	if (mbhc_cfg.gpio)
+		gpio_free(mbhc_cfg.gpio);
 	kfree(mbhc_cfg.calibration);
 }
 module_exit(msm_audio_exit);
diff --git a/sound/soc/msm/mdm9615.c b/sound/soc/msm/mdm9615.c
index f02a7ef..7060677 100644
--- a/sound/soc/msm/mdm9615.c
+++ b/sound/soc/msm/mdm9615.c
@@ -16,6 +16,7 @@
 #include <linux/mfd/pm8xxx/pm8018.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
+#include <linux/io.h>
 #include <sound/core.h>
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
@@ -26,6 +27,7 @@
 #include <mach/socinfo.h>
 #include "msm-pcm-routing.h"
 #include "../codecs/wcd9310.h"
+#include <mach/gpiomux.h>
 
 /* 9615 machine driver */
 
@@ -56,8 +58,189 @@
 #define TABLA_MBHC_DEF_BUTTONS 8
 #define TABLA_MBHC_DEF_RLOADS 5
 
-static u32 top_spk_pamp_gpio  = PM8018_GPIO_PM_TO_SYS(18);
-static u32 bottom_spk_pamp_gpio = PM8018_GPIO_PM_TO_SYS(19);
+/*
+ * Added for I2S
+ */
+#define GPIO_SPKR_I2S_MCLK	24
+#define GPIO_PRIM_I2S_SCK	20
+#define GPIO_PRIM_I2S_DOUT	23
+#define GPIO_PRIM_I2S_WS	21
+#define GPIO_PRIM_I2S_DIN	22
+#define GPIO_SEC_I2S_SCK	25
+#define GPIO_SEC_I2S_WS		26
+#define GPIO_SEC_I2S_DOUT	28
+#define GPIO_SEC_I2S_DIN	27
+
+static struct gpiomux_setting cdc_i2s_mclk = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting cdc_i2s_sclk = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting cdc_i2s_dout = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting cdc_i2s_ws = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting cdc_i2s_din = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+
+static struct msm_gpiomux_config msm9615_audio_prim_i2s_codec_configs[] = {
+	{
+		.gpio = GPIO_SPKR_I2S_MCLK,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &cdc_i2s_mclk,
+		},
+	},
+	{
+		.gpio = GPIO_PRIM_I2S_SCK,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &cdc_i2s_sclk,
+		},
+	},
+	{
+		.gpio = GPIO_PRIM_I2S_DOUT,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &cdc_i2s_dout,
+		},
+	},
+	{
+		.gpio = GPIO_PRIM_I2S_WS,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &cdc_i2s_ws,
+		},
+	},
+	{
+		.gpio = GPIO_PRIM_I2S_DIN,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &cdc_i2s_din,
+		},
+	},
+};
+
+/* Physical address for LPA CSR
+ * LPA SIF mux registers. These are
+ * ioremap( ) for Virtual address.
+ */
+#define LPASS_CSR_BASE	0x28000000
+#define LPA_IF_BASE		0x28100000
+#define SIF_MUX_REG_BASE (LPASS_CSR_BASE + 0x00000000)
+#define LPA_IF_REG_BASE (LPA_IF_BASE + 0x00000000)
+#define LPASS_SIF_MUX_ADDR  (SIF_MUX_REG_BASE + 0x00004000)
+#define LPAIF_SPARE_ADDR (LPA_IF_REG_BASE + 0x00000070)
+/* SIF & SPARE MUX Values */
+#define MSM_SIF_FUNC_PCM              0
+#define MSM_SIF_FUNC_I2S_MIC        1
+#define MSM_SIF_FUNC_I2S_SPKR      2
+#define MSM_LPAIF_SPARE_DISABLE                 0x0
+#define MSM_LPAIF_SPARE_BOTH_ENABLE     0x3
+
+/* I2S INTF CTL */
+#define MSM_INTF_PRIM        0
+#define MSM_INTF_SECN        1
+#define MSM_INTF_BOTH       2
+
+/* I2S Dir CTL */
+#define MSM_DIR_RX         0
+#define MSM_DIR_TX         1
+#define MSM_DIR_BOTH   2
+#define MSM_DIR_MAX     3
+
+/* I2S HW Params */
+#define NO_OF_BITS_PER_SAMPLE  16
+#define I2S_MIC_SCLK_RATE 1536000
+static int msm9615_i2s_rx_ch = 1;
+static int msm9615_i2s_tx_ch = 1;
+static int msm9615_i2s_spk_control;
+/* SIF mux bit mask & shift */
+#define LPASS_SIF_MUX_CTL_PRI_MUX_SEL_BMSK                   0x30000
+#define LPASS_SIF_MUX_CTL_PRI_MUX_SEL_SHFT                      0x10
+#define LPASS_SIF_MUX_CTL_SEC_MUX_SEL_BMSK                       0x3
+#define LPASS_SIF_MUX_CTL_SEC_MUX_SEL_SHFT                       0x0
+
+#define LPAIF_SPARE_MUX_CTL_SEC_MUX_SEL_BMSK		0x3
+#define LPAIF_SPARE_MUX_CTL_SEC_MUX_SEL_SHFT		0x2
+#define LPAIF_SPARE_MUX_CTL_PRI_MUX_SEL_BMSK	0x3
+#define LPAIF_SPARE_MUX_CTL_PRI_MUX_SEL_SHFT		0x0
+
+static u32 spare_shadow;
+static u32 sif_shadow;
+
+
+struct msm_i2s_mux_ctl {
+	const u8 sifconfig;
+	const u8 spareconfig;
+};
+struct msm_clk {
+	struct clk *osr_clk;
+	struct clk *bit_clk;
+	int clk_enable;
+};
+struct msm_i2s_clk {
+	struct msm_clk rx_clk;
+	struct msm_clk tx_clk;
+};
+struct msm_i2s_ctl {
+	struct msm_i2s_clk prim_clk;
+	struct msm_i2s_clk sec_clk;
+	struct msm_i2s_mux_ctl mux_ctl[MSM_DIR_MAX];
+	u8 intf_status[MSM_INTF_BOTH][MSM_DIR_BOTH];
+	void *sif_virt_addr;
+	void *spare_virt_addr;
+};
+static struct msm_i2s_ctl msm9x15_i2s_ctl = {
+	{{NULL, NULL, 0}, {NULL, NULL, 0} }, /* prim_clk */
+	{{NULL, NULL, 0}, {NULL, NULL, 0} }, /* sec_clk */
+	/* mux_ctl */
+	{
+		/* Rx path only */
+		{ MSM_SIF_FUNC_I2S_SPKR, MSM_LPAIF_SPARE_DISABLE },
+		/* Tx path only */
+		{  MSM_SIF_FUNC_I2S_MIC, MSM_LPAIF_SPARE_DISABLE },
+		/* Rx + Tx path only */
+		{ MSM_SIF_FUNC_I2S_SPKR, MSM_LPAIF_SPARE_BOTH_ENABLE },
+	},
+	/* intf_status */
+	{
+		/* Prim I2S */
+		{0, 0},
+		/* Sec I2S */
+		{0, 0}
+	},
+	/* sif_virt_addr */
+	NULL,
+	/* spare_virt_addr */
+	NULL,
+};
+
+enum msm9x15_set_i2s_clk {
+	MSM_I2S_CLK_SET_FALSE,
+	MSM_I2S_CLK_SET_TRUE,
+	MSM_I2S_CLK_SET_RATE0,
+};
+/*
+ * Added for I2S
+ */
+
+static u32 top_spk_pamp_gpio  = PM8018_GPIO_PM_TO_SYS(3);
+static u32 bottom_spk_pamp_gpio = PM8018_GPIO_PM_TO_SYS(5);
 static int mdm9615_spk_control;
 static int mdm9615_ext_bottom_spk_pamp;
 static int mdm9615_ext_top_spk_pamp;
@@ -318,16 +501,15 @@
 		pr_debug("%s: clk_users = %d\n", __func__, clk_users);
 		if (clk_users != 1)
 			return 0;
+		if (IS_ERR(codec_clk)) {
 
-		if (codec_clk) {
-			clk_set_rate(codec_clk, TABLA_EXT_CLK_RATE);
-			clk_prepare_enable(codec_clk);
-			tabla_mclk_enable(codec, 1, dapm);
-		} else {
 			pr_err("%s: Error setting Tabla MCLK\n", __func__);
 			clk_users--;
 			return -EINVAL;
 		}
+		clk_set_rate(codec_clk, TABLA_EXT_CLK_RATE);
+		clk_prepare_enable(codec_clk);
+		tabla_mclk_enable(codec, 1, dapm);
 	} else {
 		pr_debug("%s: clk_users = %d\n", __func__, clk_users);
 		if (clk_users == 0)
@@ -651,6 +833,20 @@
 	return tabla_cal;
 }
 
+static int msm9615_i2s_set_spk(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
+
+	pr_debug("%s()\n", __func__);
+	if (msm9615_i2s_spk_control == ucontrol->value.integer.value[0])
+		return 0;
+
+	msm9615_i2s_spk_control = ucontrol->value.integer.value[0];
+	mdm9615_ext_control(codec);
+	return 1;
+}
+
 static int mdm9615_hw_params(struct snd_pcm_substream *substream,
 				struct snd_pcm_hw_params *params)
 {
@@ -704,13 +900,567 @@
 								__func__);
 			goto end;
 		}
-
-
 	}
 end:
 	return ret;
 }
 
+static int msm9615_i2s_rx_ch_get(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm9615_i2s_rx_ch  = %d\n", __func__,
+		 msm9615_i2s_rx_ch);
+	ucontrol->value.integer.value[0] = msm9615_i2s_rx_ch - 1;
+	return 0;
+}
+
+static int msm9615_i2s_rx_ch_put(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	msm9615_i2s_rx_ch = ucontrol->value.integer.value[0] + 1;
+
+	pr_debug("%s: msm9615_i2s_rx_ch = %d\n", __func__,
+		 msm9615_i2s_rx_ch);
+	return 1;
+}
+
+static int msm9615_i2s_tx_ch_get(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm9615_i2s_tx_ch  = %d\n", __func__,
+		 msm9615_i2s_tx_ch);
+	ucontrol->value.integer.value[0] = msm9615_i2s_tx_ch - 1;
+	return 0;
+}
+
+static int msm9615_i2s_tx_ch_put(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	msm9615_i2s_tx_ch = ucontrol->value.integer.value[0] + 1;
+
+	pr_debug("%s: msm9615_i2s_tx_ch = %d\n", __func__,
+		 msm9615_i2s_tx_ch);
+	return 1;
+}
+
+static int msm9615_i2s_get_spk(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm9615_spk_control = %d", __func__, mdm9615_spk_control);
+	ucontrol->value.integer.value[0] = msm9615_i2s_spk_control;
+	return 0;
+}
+
+static const struct snd_kcontrol_new tabla_msm9615_i2s_controls[] = {
+	SOC_ENUM_EXT("Speaker Function", mdm9615_enum[0], msm9615_i2s_get_spk,
+		     msm9615_i2s_set_spk),
+	SOC_ENUM_EXT("PRI_RX Channels", mdm9615_enum[1],
+		     msm9615_i2s_rx_ch_get, msm9615_i2s_rx_ch_put),
+	SOC_ENUM_EXT("PRI_TX Channels", mdm9615_enum[2],
+		     msm9615_i2s_tx_ch_get, msm9615_i2s_tx_ch_put),
+};
+
+static int msm9615_i2s_audrx_init(struct snd_soc_pcm_runtime *rtd)
+{
+	int err;
+	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	err = snd_soc_add_controls(codec, tabla_msm9615_i2s_controls,
+		ARRAY_SIZE(tabla_msm9615_i2s_controls));
+	if (err < 0) {
+		pr_err("returning loc 1 err = %d\n", err);
+		return err;
+	}
+
+	snd_soc_dapm_new_controls(dapm, mdm9615_dapm_widgets,
+				  ARRAY_SIZE(mdm9615_dapm_widgets));
+
+	snd_soc_dapm_add_routes(dapm, common_audio_map,
+		ARRAY_SIZE(common_audio_map));
+	snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
+	snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
+	snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
+	snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
+
+	snd_soc_dapm_sync(dapm);
+
+	err = snd_soc_jack_new(codec, "Headset Jack",
+			       (SND_JACK_HEADSET | SND_JACK_OC_HPHL|
+			       SND_JACK_OC_HPHR), &hs_jack);
+	if (err) {
+		pr_err("failed to create new jack\n");
+		return err;
+	}
+	err = snd_soc_jack_new(codec, "Button Jack",
+			       TABLA_JACK_BUTTON_MASK, &button_jack);
+	if (err) {
+		pr_err("failed to create new jack\n");
+		return err;
+	}
+	codec_clk = clk_get(cpu_dai->dev, "osr_clk");
+	err = tabla_hs_detect(codec, &mbhc_cfg);
+	return err;
+}
+
+static int msm9615_i2s_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+					     struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+	SNDRV_PCM_HW_PARAM_RATE);
+	struct snd_interval *channels = hw_param_interval(params,
+						SNDRV_PCM_HW_PARAM_CHANNELS);
+	rate->min = rate->max = 48000;
+	channels->min = channels->max = msm9615_i2s_rx_ch;
+
+	return 0;
+}
+
+static int msm9615_i2s_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+					     struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+	SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+			SNDRV_PCM_HW_PARAM_CHANNELS);
+	rate->min = rate->max = 48000;
+
+	channels->min = channels->max = msm9615_i2s_tx_ch;
+
+	return 0;
+}
+
+static int mdm9615_i2s_free_gpios(u8 i2s_intf, u8 i2s_dir)
+{
+	struct msm_i2s_ctl *pintf = &msm9x15_i2s_ctl;
+	if (i2s_intf == MSM_INTF_PRIM) {
+		if (i2s_dir == MSM_DIR_RX)
+			gpio_free(GPIO_PRIM_I2S_DOUT);
+		if (i2s_dir == MSM_DIR_TX)
+			gpio_free(GPIO_PRIM_I2S_DIN);
+		if (pintf->intf_status[i2s_intf][MSM_DIR_TX] == 0 &&
+			pintf->intf_status[i2s_intf][MSM_DIR_RX] == 0) {
+			gpio_free(GPIO_PRIM_I2S_SCK);
+			gpio_free(GPIO_PRIM_I2S_WS);
+		}
+	} else if (i2s_intf == MSM_INTF_SECN) {
+		if (i2s_dir == MSM_DIR_RX)
+			gpio_free(GPIO_SEC_I2S_DOUT);
+		if (i2s_dir == MSM_DIR_TX)
+			gpio_free(GPIO_SEC_I2S_DIN);
+		if (pintf->intf_status[i2s_intf][MSM_DIR_TX] == 0 &&
+			pintf->intf_status[i2s_intf][MSM_DIR_RX] == 0) {
+			gpio_free(GPIO_SEC_I2S_WS);
+			gpio_free(GPIO_SEC_I2S_SCK);
+		}
+	}
+	return 0;
+}
+
+int msm9615_i2s_intf_dir_sel(const char *cpu_dai_name,
+			     u8 *i2s_intf, u8 *i2s_dir)
+{
+	int ret = 0;
+	if (i2s_intf == NULL || i2s_dir == NULL || cpu_dai_name == NULL) {
+		ret = 1;
+		goto err;
+	}
+	if (!strncmp(cpu_dai_name, "msm-dai-q6.0", 12)) {
+		*i2s_intf = MSM_INTF_PRIM;
+		*i2s_dir = MSM_DIR_RX;
+	} else if (!strncmp(cpu_dai_name, "msm-dai-q6.1", 12)) {
+		*i2s_intf = MSM_INTF_PRIM;
+		*i2s_dir = MSM_DIR_TX;
+	} else if (!strncmp(cpu_dai_name, "msm-dai-q6.4", 12)) {
+		*i2s_intf = MSM_INTF_SECN;
+		*i2s_dir = MSM_DIR_RX;
+	} else if (!strncmp(cpu_dai_name, "msm-dai-q6.5", 12)) {
+		*i2s_intf = MSM_INTF_SECN;
+		*i2s_dir = MSM_DIR_TX;
+	} else {
+		pr_err("Error in I2S cpu dai name\n");
+		ret = 1;
+	}
+err:
+	return ret;
+}
+
+int msm9615_enable_i2s_gpio(u8 i2s_intf, u8 i2s_dir)
+{
+	u8 ret = 0;
+	struct msm_i2s_ctl *pintf = &msm9x15_i2s_ctl;
+	if (i2s_intf == MSM_INTF_PRIM) {
+		if (i2s_dir == MSM_DIR_TX) {
+			ret = gpio_request(GPIO_PRIM_I2S_DIN, "I2S_PRIM_DIN");
+			if (ret) {
+				pr_err("%s: Failed to request gpio %d\n",
+				       __func__, GPIO_PRIM_I2S_DIN);
+				goto err;
+			}
+		} else if (i2s_dir == MSM_DIR_RX) {
+			ret = gpio_request(GPIO_PRIM_I2S_DOUT,
+					       "I2S_PRIM_DOUT");
+			if (ret) {
+				pr_err("%s: Failed to request gpio %d\n",
+				       __func__, GPIO_PRIM_I2S_DOUT);
+				goto err;
+			}
+		} else if (pintf->intf_status[i2s_intf][MSM_DIR_TX] == 0 &&
+			   pintf->intf_status[i2s_intf][MSM_DIR_RX] == 0) {
+			ret = gpio_request(GPIO_PRIM_I2S_SCK, "I2S_PRIM_SCK");
+			if (ret) {
+				pr_err("%s: Failed to request gpio %d\n",
+				       __func__, GPIO_PRIM_I2S_SCK);
+				goto err;
+			}
+			ret = gpio_request(GPIO_PRIM_I2S_WS, "I2S_PRIM_WS");
+			if (ret) {
+				pr_err("%s: Failed to request gpio %d\n",
+				       __func__, GPIO_PRIM_I2S_WS);
+				goto err;
+			}
+		}
+	} else if (i2s_intf == MSM_INTF_SECN) {
+		if (i2s_dir == MSM_DIR_RX) {
+			ret = gpio_request(GPIO_SEC_I2S_DOUT, "I2S_SEC_DOUT");
+			if (ret) {
+				pr_err("%s: Failed to request gpio %d\n",
+				       __func__, GPIO_SEC_I2S_DOUT);
+				goto err;
+			}
+		} else if (i2s_dir == MSM_DIR_TX) {
+			ret = gpio_request(GPIO_SEC_I2S_DIN, "I2S_SEC_DIN");
+			if (ret) {
+				pr_err("%s: Failed to request gpio %d\n",
+				       __func__, GPIO_SEC_I2S_DIN);
+				goto err;
+			}
+		} else if (pintf->intf_status[i2s_intf][MSM_DIR_TX] == 0 &&
+			   pintf->intf_status[i2s_intf][MSM_DIR_RX] == 0) {
+			ret = gpio_request(GPIO_SEC_I2S_SCK, "I2S_SEC_SCK");
+			if (ret) {
+				pr_err("%s: Failed to request gpio %d\n",
+				       __func__, GPIO_SEC_I2S_SCK);
+				goto err;
+			}
+			ret = gpio_request(GPIO_SEC_I2S_WS, "I2S_SEC_WS");
+			if (ret) {
+				pr_err("%s: Failed to request gpio %d\n",
+				       __func__, GPIO_SEC_I2S_WS);
+				goto err;
+			}
+		}
+	}
+err:
+	return ret;
+}
+
+static int msm9615_set_i2s_osr_bit_clk(struct snd_soc_dai *cpu_dai,
+				       u8 i2s_intf, u8 i2s_dir,
+				       enum msm9x15_set_i2s_clk enable)
+{
+
+	struct msm_i2s_ctl *pintf = &msm9x15_i2s_ctl;
+	struct msm_i2s_clk *pclk = &pintf->prim_clk;
+	struct msm_clk *clk_ctl = &pclk->rx_clk;
+	u8 ret = 0;
+	pr_debug("Dev name %s Intf =%d, Dir = %d, Enable=%d\n",
+		cpu_dai->name, i2s_intf, i2s_dir, enable);
+	if (i2s_intf == MSM_INTF_PRIM)
+		pclk = &pintf->prim_clk;
+	else if (i2s_intf == MSM_INTF_SECN)
+		pclk = &pintf->sec_clk;
+
+	if (i2s_dir == MSM_DIR_TX)
+		clk_ctl = &pclk->tx_clk;
+	else if (i2s_dir == MSM_DIR_RX)
+		clk_ctl = &pclk->rx_clk;
+
+	if (enable == MSM_I2S_CLK_SET_TRUE ||
+	    enable == MSM_I2S_CLK_SET_RATE0) {
+		if (clk_ctl->clk_enable != 0) {
+			pr_info("%s: I2S Clk is already enabled"
+				"clk users %d\n", __func__,
+				clk_ctl->clk_enable);
+			ret = 0;
+			goto err;
+		}
+		clk_ctl->osr_clk = clk_get(cpu_dai->dev, "osr_clk");
+		if (IS_ERR(clk_ctl->osr_clk)) {
+			pr_err("%s: Fail to get OSR CLK\n", __func__);
+			ret = -EINVAL;
+			goto err;
+		}
+		ret = clk_prepare(clk_ctl->osr_clk);
+		if (ret != 0) {
+			pr_err("Unable to prepare i2s_spkr_osr_clk\n");
+			goto err;
+		}
+		clk_set_rate(clk_ctl->osr_clk, TABLA_EXT_CLK_RATE);
+		ret = clk_enable(clk_ctl->osr_clk);
+		if (ret != 0) {
+			pr_err("Fail to enable i2s_spkr_osr_clk\n");
+			clk_unprepare(clk_ctl->osr_clk);
+			goto err;
+		}
+		clk_ctl->bit_clk = clk_get(cpu_dai->dev, "bit_clk");
+		if (IS_ERR(clk_ctl->bit_clk)) {
+			pr_err("Fail to get i2s_spkr_bit_clk\n");
+			clk_disable(clk_ctl->osr_clk);
+			clk_unprepare(clk_ctl->osr_clk);
+			clk_put(clk_ctl->osr_clk);
+			ret = -EINVAL;
+			goto err;
+		}
+		ret = clk_prepare(clk_ctl->bit_clk);
+		if (ret != 0) {
+			clk_disable(clk_ctl->osr_clk);
+			clk_unprepare(clk_ctl->osr_clk);
+			clk_put(clk_ctl->osr_clk);
+			pr_err("Fail to prepare i2s_spkr_osr_clk\n");
+			goto err;
+		}
+		if (enable == MSM_I2S_CLK_SET_RATE0)
+			clk_set_rate(clk_ctl->bit_clk, 0);
+		else
+			clk_set_rate(clk_ctl->bit_clk, 8);
+		ret = clk_enable(clk_ctl->bit_clk);
+		if (ret != 0) {
+			clk_disable(clk_ctl->osr_clk);
+			clk_unprepare(clk_ctl->osr_clk);
+			clk_put(clk_ctl->osr_clk);
+			clk_unprepare(clk_ctl->bit_clk);
+			pr_err("Unable to enable i2s_spkr_osr_clk\n");
+			goto err;
+		}
+		clk_ctl->clk_enable++;
+	} else if (enable == MSM_I2S_CLK_SET_FALSE &&
+		   clk_ctl->clk_enable != 0) {
+		clk_disable(clk_ctl->osr_clk);
+		clk_disable(clk_ctl->bit_clk);
+		clk_unprepare(clk_ctl->osr_clk);
+		clk_unprepare(clk_ctl->bit_clk);
+		clk_put(clk_ctl->bit_clk);
+		clk_put(clk_ctl->osr_clk);
+		clk_ctl->bit_clk = NULL;
+		clk_ctl->osr_clk = NULL;
+		clk_ctl->clk_enable--;
+		ret = 0;
+	}
+err:
+	return ret;
+}
+
+void msm9615_config_i2s_sif_mux(u8 value)
+{
+	struct msm_i2s_ctl *pintf = &msm9x15_i2s_ctl;
+	sif_shadow  = 0x00000;
+	sif_shadow = (sif_shadow & LPASS_SIF_MUX_CTL_PRI_MUX_SEL_BMSK) |
+		     (value << LPASS_SIF_MUX_CTL_PRI_MUX_SEL_SHFT);
+	iowrite32(sif_shadow, pintf->sif_virt_addr);
+	/* Dont read SIF register. Device crashes. */
+	pr_debug("%s() SIF Reg = 0x%x\n", __func__, sif_shadow);
+}
+
+void msm9615_config_i2s_spare_mux(u8 value, u8 i2s_intf)
+{
+	struct msm_i2s_ctl *pintf = &msm9x15_i2s_ctl;
+	if (i2s_intf == MSM_INTF_PRIM) {
+		/* Configure Primary SIF */
+	    spare_shadow = (spare_shadow & LPAIF_SPARE_MUX_CTL_PRI_MUX_SEL_BMSK
+			   ) | (value << LPAIF_SPARE_MUX_CTL_PRI_MUX_SEL_SHFT);
+	}
+	if (i2s_intf == MSM_INTF_SECN) {
+		/*Secondary interface configuration*/
+	    spare_shadow = (spare_shadow & LPAIF_SPARE_MUX_CTL_SEC_MUX_SEL_BMSK
+			   ) | (value << LPAIF_SPARE_MUX_CTL_SEC_MUX_SEL_SHFT);
+	}
+	iowrite32(spare_shadow, pintf->spare_virt_addr);
+	/* Dont read SPARE register. Device crashes. */
+	pr_debug("%s( ): SPARE Reg =0x%x\n", __func__, spare_shadow);
+}
+
+static int msm9615_i2s_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params)
+{
+	int rate = params_rate(params);
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct msm_i2s_ctl *pintf = &msm9x15_i2s_ctl;
+	struct msm_i2s_clk *pclk = &pintf->prim_clk;
+	struct msm_clk *clk_ctl = &pclk->rx_clk;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	int bit_clk_set = 0;
+	u8 i2s_intf, i2s_dir;
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		if (!msm9615_i2s_intf_dir_sel(cpu_dai->name,
+		    &i2s_intf, &i2s_dir)) {
+			bit_clk_set = TABLA_EXT_CLK_RATE /
+				      (rate * 2 * NO_OF_BITS_PER_SAMPLE);
+			 if (bit_clk_set != 8) {
+				if (i2s_intf == MSM_INTF_PRIM)
+					pclk = &pintf->prim_clk;
+				else if (i2s_intf == MSM_INTF_SECN)
+					pclk = &pintf->sec_clk;
+				clk_ctl = &pclk->rx_clk;
+				pr_debug("%s( ): New rate = %d",
+					__func__, bit_clk_set);
+				clk_set_rate(clk_ctl->bit_clk, bit_clk_set);
+			 }
+		}
+	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		bit_clk_set = I2S_MIC_SCLK_RATE / (rate * 2 *
+						NO_OF_BITS_PER_SAMPLE);
+		/* Not required to modify TX rate.
+		  * Speaker clock are looped back
+		  * to Mic.
+		  */
+	}
+	return 1;
+}
+
+static int msm9615_i2s_startup(struct snd_pcm_substream *substream)
+{
+	u8 ret = 0;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct msm_i2s_ctl *pintf = &msm9x15_i2s_ctl;
+	u8 i2s_intf, i2s_dir;
+	if (!msm9615_i2s_intf_dir_sel(cpu_dai->name, &i2s_intf, &i2s_dir)) {
+		pr_debug("%s( ): cpu name = %s intf =%d dir = %d\n",
+			 __func__, cpu_dai->name, i2s_intf, i2s_dir);
+		pr_debug("%s( ): Enable status Rx =%d Tx = %d\n", __func__,
+			 pintf->intf_status[i2s_intf][MSM_DIR_RX],
+			 pintf->intf_status[i2s_intf][MSM_DIR_TX]);
+		msm9615_enable_i2s_gpio(i2s_intf, i2s_dir);
+		if (i2s_dir == MSM_DIR_TX) {
+			if (pintf->intf_status[i2s_intf][MSM_DIR_RX] > 0) {
+				/* This means that Rx is enabled before */
+				ret = msm9615_set_i2s_osr_bit_clk(cpu_dai,
+						    i2s_intf, i2s_dir,
+						    MSM_I2S_CLK_SET_RATE0);
+				if (ret != 0) {
+					pr_err("%s: Fail enable I2S clock\n",
+					       __func__);
+					return -EINVAL;
+				}
+				msm9615_config_i2s_sif_mux(
+				       pintf->mux_ctl[MSM_DIR_BOTH].sifconfig);
+				msm9615_config_i2s_spare_mux(
+				      pintf->mux_ctl[MSM_DIR_BOTH].spareconfig,
+				      i2s_intf);
+				ret = snd_soc_dai_set_fmt(cpu_dai,
+						       SND_SOC_DAIFMT_CBM_CFM);
+				if (ret < 0)
+					pr_err("set fmt cpu dai failed\n");
+					ret = snd_soc_dai_set_fmt(codec_dai,
+						       SND_SOC_DAIFMT_CBS_CFS);
+				if (ret < 0)
+					pr_err("set fmt codec dai failed\n");
+			} else if (pintf->intf_status[i2s_intf][i2s_dir] == 0) {
+				/* This means that Rx is
+				 * not enabled before.
+				 * only Tx will be used.
+				 */
+				ret = msm9615_set_i2s_osr_bit_clk(cpu_dai,
+							i2s_intf, i2s_dir,
+							MSM_I2S_CLK_SET_TRUE);
+				if (ret != 0) {
+					pr_err("%s: Fail Tx I2S clock\n",
+					       __func__);
+					return -EINVAL;
+				}
+				msm9615_config_i2s_sif_mux(
+					pintf->mux_ctl[MSM_DIR_TX].sifconfig);
+				msm9615_config_i2s_spare_mux(
+					pintf->mux_ctl[MSM_DIR_TX].spareconfig,
+					i2s_intf);
+				ret = snd_soc_dai_set_fmt(cpu_dai,
+						       SND_SOC_DAIFMT_CBS_CFS);
+				if (ret < 0)
+					pr_err("set fmt cpu dai failed\n");
+					ret = snd_soc_dai_set_fmt(codec_dai,
+						       SND_SOC_DAIFMT_CBS_CFS);
+				if (ret < 0)
+					pr_err("set fmt codec dai failed\n");
+	}
+		} else if (i2s_dir == MSM_DIR_RX) {
+			if (pintf->intf_status[i2s_intf][MSM_DIR_TX] > 0) {
+				pr_err("%s: Error shutdown Tx first\n",
+				       __func__);
+				return -EINVAL;
+			} else if (pintf->intf_status[i2s_intf][i2s_dir]
+				   == 0) {
+				ret = msm9615_set_i2s_osr_bit_clk(cpu_dai,
+						i2s_intf, i2s_dir,
+						MSM_I2S_CLK_SET_TRUE);
+				if (ret != 0) {
+					pr_err("%s: Fail Rx I2S clock\n",
+						__func__);
+					return -EINVAL;
+				}
+				msm9615_config_i2s_sif_mux(
+					pintf->mux_ctl[MSM_DIR_RX].sifconfig);
+				msm9615_config_i2s_spare_mux(
+					pintf->mux_ctl[MSM_DIR_RX].spareconfig,
+					i2s_intf);
+				ret = snd_soc_dai_set_fmt(cpu_dai,
+						SND_SOC_DAIFMT_CBS_CFS);
+				if (ret < 0)
+					pr_err("set fmt cpu dai failed\n");
+				ret = snd_soc_dai_set_fmt(codec_dai,
+					SND_SOC_DAIFMT_CBS_CFS);
+				if (ret < 0)
+					pr_err("set fmt codec dai failed\n");
+			}
+		}
+		pintf->intf_status[i2s_intf][i2s_dir]++;
+	} else {
+		pr_err("%s: Err in i2s_intf_dir_sel\n", __func__);
+		return -EINVAL;
+	}
+	pr_debug("Exit %s() Enable status Rx =%d Tx = %d\n", __func__,
+		 pintf->intf_status[i2s_intf][MSM_DIR_RX],
+		 pintf->intf_status[i2s_intf][MSM_DIR_TX]);
+	return ret;
+}
+
+static void msm9615_i2s_shutdown(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct msm_i2s_ctl *pintf = &msm9x15_i2s_ctl;
+	u8 i2s_intf = 0, i2s_dir = 0, ret = 0;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	pr_debug("%s( ): Enable status Rx =%d Tx = %d\n",
+		__func__, pintf->intf_status[i2s_intf][MSM_DIR_RX],
+		pintf->intf_status[i2s_intf][MSM_DIR_TX]);
+	if (!msm9615_i2s_intf_dir_sel(cpu_dai->name, &i2s_intf, &i2s_dir)) {
+		pr_debug("%s( ): intf =%d dir = %d\n", __func__,
+			 i2s_intf, i2s_dir);
+		if (i2s_dir == MSM_DIR_RX)
+			if (pintf->intf_status[i2s_intf][MSM_DIR_TX] > 0)
+				pr_err("%s: Shutdown Tx First then by RX\n",
+				       __func__);
+		ret = msm9615_set_i2s_osr_bit_clk(cpu_dai, i2s_intf, i2s_dir,
+							MSM_I2S_CLK_SET_FALSE);
+		if (ret != 0)
+			pr_err("%s: Cannot disable I2S clock\n",
+			       __func__);
+		pintf->intf_status[i2s_intf][i2s_dir]--;
+		mdm9615_i2s_free_gpios(i2s_intf, i2s_dir);
+	}
+	pr_debug("%s( ): Enable status Rx =%d Tx = %d\n", __func__,
+		 pintf->intf_status[i2s_intf][MSM_DIR_RX],
+		 pintf->intf_status[i2s_intf][MSM_DIR_TX]);
+}
+
+static struct snd_soc_ops msm9615_i2s_be_ops = {
+	.startup = msm9615_i2s_startup,
+	.shutdown = msm9615_i2s_shutdown,
+	.hw_params = msm9615_i2s_hw_params,
+};
+
 static int mdm9615_audrx_init(struct snd_soc_pcm_runtime *rtd)
 {
 	int err;
@@ -896,6 +1646,7 @@
 
 	return 0;
 }
+
 static int mdm9615_startup(struct snd_pcm_substream *substream)
 {
 	pr_debug("%s(): substream = %s  stream = %d\n", __func__,
@@ -1107,8 +1858,37 @@
 
 };
 
-static struct snd_soc_dai_link mdm9615_dai_delta_tabla[] = {
-	/* Backend DAI Links */
+static struct snd_soc_dai_link mdm9615_dai_i2s_tabla[] = {
+	/* Backend I2S DAI Links */
+	{
+		.name = LPASS_BE_PRI_I2S_RX,
+		.stream_name = "Primary I2S Playback",
+		.cpu_dai_name = "msm-dai-q6.0",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "tabla_codec",
+		.codec_dai_name	= "tabla_i2s_rx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_PRI_I2S_RX,
+		.init = &msm9615_i2s_audrx_init,
+		.be_hw_params_fixup = msm9615_i2s_rx_be_hw_params_fixup,
+		.ops = &msm9615_i2s_be_ops,
+	},
+	{
+		.name = LPASS_BE_PRI_I2S_TX,
+		.stream_name = "Primary I2S Capture",
+		.cpu_dai_name = "msm-dai-q6.1",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "tabla_codec",
+		.codec_dai_name	= "tabla_i2s_tx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_PRI_I2S_TX,
+		.be_hw_params_fixup = msm9615_i2s_tx_be_hw_params_fixup,
+		.ops = &msm9615_i2s_be_ops,
+	},
+};
+
+static struct snd_soc_dai_link mdm9615_dai_slimbus_tabla[] = {
+	/* Backend SlimBus DAI Links */
 	{
 		.name = LPASS_BE_SLIMBUS_0_RX,
 		.stream_name = "Slimbus Playback",
@@ -1136,14 +1916,17 @@
 	},
 };
 
-static struct snd_soc_dai_link mdm9615_dai[
+static struct snd_soc_dai_link mdm9615_i2s_dai[
 					 ARRAY_SIZE(mdm9615_dai_common) +
-					 ARRAY_SIZE(mdm9615_dai_delta_tabla)];
+					 ARRAY_SIZE(mdm9615_dai_i2s_tabla)];
+
+static struct snd_soc_dai_link mdm9615_slimbus_dai[
+					 ARRAY_SIZE(mdm9615_dai_common) +
+					 ARRAY_SIZE(mdm9615_dai_slimbus_tabla)];
+
 
 static struct snd_soc_card snd_soc_card_mdm9615 = {
 		.name		= "mdm9615-tabla-snd-card",
-		.dai_link	= mdm9615_dai,
-		.num_links	= ARRAY_SIZE(mdm9615_dai),
 };
 
 static struct platform_device *mdm9615_snd_device;
@@ -1199,6 +1982,11 @@
 	}
 }
 
+void  __init install_codec_i2s_gpio(void)
+{
+	msm_gpiomux_install(msm9615_audio_prim_i2s_codec_configs,
+			ARRAY_SIZE(msm9615_audio_prim_i2s_codec_configs));
+}
 static int __init mdm9615_audio_init(void)
 {
 	int ret;
@@ -1220,11 +2008,28 @@
 		kfree(mbhc_cfg.calibration);
 		return -ENOMEM;
 	}
-
-	memcpy(mdm9615_dai, mdm9615_dai_common, sizeof(mdm9615_dai_common));
-	memcpy(mdm9615_dai + ARRAY_SIZE(mdm9615_dai_common),
-		mdm9615_dai_delta_tabla, sizeof(mdm9615_dai_delta_tabla));
-
+	pr_err("%s: Interface Type = %d\n", __func__,
+			wcd9xxx_get_intf_type());
+	if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
+		memcpy(mdm9615_slimbus_dai, mdm9615_dai_common,
+			sizeof(mdm9615_dai_common));
+		memcpy(mdm9615_slimbus_dai + ARRAY_SIZE(mdm9615_dai_common),
+		       mdm9615_dai_slimbus_tabla,
+		       sizeof(mdm9615_dai_slimbus_tabla));
+		snd_soc_card_mdm9615.dai_link = mdm9615_slimbus_dai;
+		snd_soc_card_mdm9615.num_links =
+				ARRAY_SIZE(mdm9615_slimbus_dai);
+	} else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C) {
+		install_codec_i2s_gpio();
+		memcpy(mdm9615_i2s_dai, mdm9615_dai_common,
+		       sizeof(mdm9615_dai_common));
+		memcpy(mdm9615_i2s_dai + ARRAY_SIZE(mdm9615_dai_common),
+		       mdm9615_dai_i2s_tabla,
+		       sizeof(mdm9615_dai_i2s_tabla));
+		snd_soc_card_mdm9615.dai_link = mdm9615_i2s_dai;
+		snd_soc_card_mdm9615.num_links =
+				ARRAY_SIZE(mdm9615_i2s_dai);
+	}
 	platform_set_drvdata(mdm9615_snd_device, &snd_soc_card_mdm9615);
 	ret = platform_device_add(mdm9615_snd_device);
 	if (ret) {
@@ -1232,13 +2037,15 @@
 		kfree(mbhc_cfg.calibration);
 		return ret;
 	}
-
 	if (mdm9615_configure_headset_mic_gpios()) {
 		pr_err("%s Fail to configure headset mic gpios\n", __func__);
 		mdm9615_headset_gpios_configured = 0;
 	} else
 		mdm9615_headset_gpios_configured = 1;
 
+	msm9x15_i2s_ctl.sif_virt_addr = ioremap(LPASS_SIF_MUX_ADDR, 4);
+	msm9x15_i2s_ctl.spare_virt_addr = ioremap(LPAIF_SPARE_ADDR, 4);
+
 	return ret;
 
 }
@@ -1253,6 +2060,9 @@
 	mdm9615_free_headset_mic_gpios();
 	platform_device_unregister(mdm9615_snd_device);
 	kfree(mbhc_cfg.calibration);
+	iounmap(msm9x15_i2s_ctl.sif_virt_addr);
+	iounmap(msm9x15_i2s_ctl.spare_virt_addr);
+
 }
 module_exit(mdm9615_audio_exit);
 
diff --git a/sound/soc/msm/msm-compr-q6.c b/sound/soc/msm/msm-compr-q6.c
index 776337d..68f218f 100644
--- a/sound/soc/msm/msm-compr-q6.c
+++ b/sound/soc/msm/msm-compr-q6.c
@@ -192,6 +192,7 @@
 	struct msm_audio *prtd = &compr->prtd;
 	struct asm_aac_cfg aac_cfg;
 	struct asm_wma_cfg wma_cfg;
+	struct asm_wmapro_cfg wma_pro_cfg;
 	int ret;
 
 	pr_debug("compressed stream prepare\n");
@@ -250,6 +251,26 @@
 		if (ret < 0)
 			pr_err("%s: CMD Format block failed\n", __func__);
 		break;
+	case SND_AUDIOCODEC_WMA_PRO:
+		pr_debug("SND_AUDIOCODEC_WMA_PRO\n");
+		memset(&wma_pro_cfg, 0x0, sizeof(struct asm_wmapro_cfg));
+		wma_pro_cfg.format_tag = compr->info.codec_param.codec.format;
+		wma_pro_cfg.ch_cfg = compr->info.codec_param.codec.ch_in;
+		wma_pro_cfg.sample_rate = runtime->rate;
+		wma_pro_cfg.avg_bytes_per_sec =
+			compr->info.codec_param.codec.bit_rate/8;
+		wma_pro_cfg.block_align = compr->info.codec_param.codec.align;
+		wma_pro_cfg.valid_bits_per_sample =
+		compr->info.codec_param.codec.options.wma.bits_per_sample;
+		wma_pro_cfg.ch_mask =
+			compr->info.codec_param.codec.options.wma.channelmask;
+		wma_pro_cfg.encode_opt =
+			compr->info.codec_param.codec.options.wma.encodeopt;
+		ret = q6asm_media_format_block_wmapro(prtd->audio_client,
+				&wma_pro_cfg);
+		if (ret < 0)
+			pr_err("%s: CMD Format block failed\n", __func__);
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -316,6 +337,7 @@
 	compr->info.compr_cap.codecs[1] = SND_AUDIOCODEC_AAC;
 	compr->info.compr_cap.codecs[2] = SND_AUDIOCODEC_AC3_PASS_THROUGH;
 	compr->info.compr_cap.codecs[3] = SND_AUDIOCODEC_WMA;
+	compr->info.compr_cap.codecs[4] = SND_AUDIOCODEC_WMA_PRO;
 	/* Add new codecs here */
 }
 
@@ -638,6 +660,10 @@
 			pr_debug("SND_AUDIOCODEC_WMA\n");
 			compr->codec = FORMAT_WMA_V9;
 			break;
+		case SND_AUDIOCODEC_WMA_PRO:
+			pr_debug("SND_AUDIOCODEC_WMA_PRO\n");
+			compr->codec = FORMAT_WMA_V10PRO;
+			break;
 		default:
 			pr_debug("FORMAT_LINEAR_PCM\n");
 			compr->codec = FORMAT_LINEAR_PCM;
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 6c44cba..a050771 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -256,21 +256,21 @@
 	{
 		.playback = {
 			.stream_name = "AUXPCM Hostless Playback",
-			.rates = SNDRV_PCM_RATE_8000,
+			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE,
 			.channels_min = 1,
 			.channels_max = 1,
 			.rate_min =     8000,
-			.rate_max =     8000,
+			.rate_max =     16000,
 		},
 		.capture = {
 			.stream_name = "AUXPCM Hostless Capture",
-			.rates = SNDRV_PCM_RATE_8000,
+			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE,
 			.channels_min = 1,
 			.channels_max = 1,
 			.rate_min =     8000,
-			.rate_max =    48000,
+			.rate_max =    16000,
 		},
 		.ops = &msm_fe_dai_ops,
 		.name = "AUXPCM_HOSTLESS",
diff --git a/sound/soc/msm/msm-dai-q6-hdmi.c b/sound/soc/msm/msm-dai-q6-hdmi.c
index 3333344..dfb090e 100644
--- a/sound/soc/msm/msm-dai-q6-hdmi.c
+++ b/sound/soc/msm/msm-dai-q6-hdmi.c
@@ -38,6 +38,46 @@
 	union afe_port_config port_config;
 };
 
+static int msm_dai_q6_hdmi_format_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+
+	struct msm_dai_q6_hdmi_dai_data *dai_data = kcontrol->private_data;
+	int value = ucontrol->value.integer.value[0];
+	dai_data->port_config.hdmi_multi_ch.data_type = value;
+	pr_debug("%s: value = %d\n", __func__, value);
+	return 0;
+}
+
+static int msm_dai_q6_hdmi_format_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+
+	struct msm_dai_q6_hdmi_dai_data *dai_data = kcontrol->private_data;
+	ucontrol->value.integer.value[0] =
+		dai_data->port_config.hdmi_multi_ch.data_type;
+	return 0;
+}
+
+
+/* HDMI format field for AFE_PORT_MULTI_CHAN_HDMI_AUDIO_IF_CONFIG command
+ *  0: linear PCM
+ *  1: non-linear PCM
+ */
+static const char *hdmi_format[] = {
+	"LPCM",
+	"Compr"
+};
+
+static const struct soc_enum hdmi_config_enum[] = {
+	SOC_ENUM_SINGLE_EXT(2, hdmi_format),
+};
+
+static const struct snd_kcontrol_new hdmi_config_controls[] = {
+	SOC_ENUM_EXT("HDMI RX Format", hdmi_config_enum[0],
+				 msm_dai_q6_hdmi_format_get,
+				 msm_dai_q6_hdmi_format_put),
+};
 
 /* Current implementation assumes hw_param is called once
  * This may not be the case but what to do when ADM and AFE
@@ -54,7 +94,6 @@
 
 	dai_data->channels = params_channels(params);
 	dai_data->rate = params_rate(params);
-	dai_data->port_config.hdmi_multi_ch.data_type = 0;
 	dai_data->port_config.hdmi_multi_ch.reserved = 0;
 
 	switch (dai_data->channels) {
@@ -78,9 +117,11 @@
 		return -EINVAL;
 	}
 	dev_dbg(dai->dev, "%s() num_ch = %u rate =%u"
-		" channel_allocation = %u\n", __func__, dai_data->channels,
+		" channel_allocation = %u data type = %d\n", __func__,
+		dai_data->channels,
 		dai_data->rate,
-		dai_data->port_config.hdmi_multi_ch.channel_allocation);
+		dai_data->port_config.hdmi_multi_ch.channel_allocation,
+		dai_data->port_config.hdmi_multi_ch.data_type);
 
 	return 0;
 }
@@ -168,6 +209,7 @@
 static int msm_dai_q6_hdmi_dai_probe(struct snd_soc_dai *dai)
 {
 	struct msm_dai_q6_hdmi_dai_data *dai_data;
+	const struct snd_kcontrol_new *kcontrol;
 	int rc = 0;
 
 	dai_data = kzalloc(sizeof(struct msm_dai_q6_hdmi_dai_data),
@@ -180,6 +222,10 @@
 	} else
 		dev_set_drvdata(dai->dev, dai_data);
 
+	kcontrol = &hdmi_config_controls[0];
+
+	rc = snd_ctl_add(dai->card->snd_card,
+					 snd_ctl_new1(kcontrol, dai_data));
 	return rc;
 }
 
diff --git a/sound/soc/msm/msm-dai-q6.c b/sound/soc/msm/msm-dai-q6.c
index fb7756c..965559f 100644
--- a/sound/soc/msm/msm-dai-q6.c
+++ b/sound/soc/msm/msm-dai-q6.c
@@ -532,17 +532,28 @@
 	}
 	dai_data->channels = params_channels(params);
 
-	if (params_rate(params) != 8000) {
-		dev_err(dai->dev, "AUX PCM supports only 8KHz sampling rate\n");
+	dai_data->rate = params_rate(params);
+	switch (dai_data->rate) {
+	case 8000:
+		dai_data->port_config.pcm.mode = auxpcm_pdata->mode_8k.mode;
+		dai_data->port_config.pcm.sync = auxpcm_pdata->mode_8k.sync;
+		dai_data->port_config.pcm.frame = auxpcm_pdata->mode_8k.frame;
+		dai_data->port_config.pcm.quant = auxpcm_pdata->mode_8k.quant;
+		dai_data->port_config.pcm.slot = auxpcm_pdata->mode_8k.slot;
+		dai_data->port_config.pcm.data = auxpcm_pdata->mode_8k.data;
+		break;
+	case 16000:
+		dai_data->port_config.pcm.mode = auxpcm_pdata->mode_16k.mode;
+		dai_data->port_config.pcm.sync = auxpcm_pdata->mode_16k.sync;
+		dai_data->port_config.pcm.frame = auxpcm_pdata->mode_16k.frame;
+		dai_data->port_config.pcm.quant = auxpcm_pdata->mode_16k.quant;
+		dai_data->port_config.pcm.slot = auxpcm_pdata->mode_16k.slot;
+		dai_data->port_config.pcm.data = auxpcm_pdata->mode_16k.data;
+		break;
+	default:
+		dev_err(dai->dev, "AUX PCM supports only 8kHz and 16kHz sampling rate\n");
 		return -EINVAL;
 	}
-	dai_data->rate = params_rate(params);
-	dai_data->port_config.pcm.mode = auxpcm_pdata->mode;
-	dai_data->port_config.pcm.sync = auxpcm_pdata->sync;
-	dai_data->port_config.pcm.frame = auxpcm_pdata->frame;
-	dai_data->port_config.pcm.quant = auxpcm_pdata->quant;
-	dai_data->port_config.pcm.slot = auxpcm_pdata->slot;
-	dai_data->port_config.pcm.data = auxpcm_pdata->data;
 
 	return 0;
 }
@@ -593,7 +604,9 @@
 	case SLIMBUS_3_RX:
 	case SLIMBUS_0_TX:
 	case SLIMBUS_1_TX:
+	case SLIMBUS_2_RX:
 	case SLIMBUS_2_TX:
+	case SLIMBUS_3_TX:
 	case SLIMBUS_4_RX:
 	case SLIMBUS_4_TX:
 		rc = msm_dai_q6_slim_bus_hw_params(params, dai,
@@ -702,9 +715,9 @@
 {
 	struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
 	int rc = 0;
-
 	struct msm_dai_auxpcm_pdata *auxpcm_pdata =
 			(struct msm_dai_auxpcm_pdata *) dai->dev->platform_data;
+	unsigned long pcm_clk_rate;
 
 	mutex_lock(&aux_pcm_mutex);
 
@@ -753,8 +766,17 @@
 	afe_open(PCM_RX, &dai_data->port_config, dai_data->rate);
 
 	afe_open(PCM_TX, &dai_data->port_config, dai_data->rate);
+	if (dai_data->rate == 8000) {
+		pcm_clk_rate = auxpcm_pdata->mode_8k.pcm_clk_rate;
+	} else if (dai_data->rate == 16000) {
+		pcm_clk_rate = auxpcm_pdata->mode_8k.pcm_clk_rate;
+	} else {
+		dev_err(dai->dev, "%s: Invalid AUX PCM rate %d\n", __func__,
+			  dai_data->rate);
+		return -EINVAL;
+	}
 
-	rc = clk_set_rate(pcm_clk, auxpcm_pdata->pcm_clk_rate);
+	rc = clk_set_rate(pcm_clk, pcm_clk_rate);
 	if (rc < 0) {
 		pr_err("%s: clk_set_rate failed\n", __func__);
 		return rc;
@@ -1107,17 +1129,16 @@
 static int msm_dai_q6_set_channel_map(struct snd_soc_dai *dai,
 				unsigned int tx_num, unsigned int *tx_slot,
 				unsigned int rx_num, unsigned int *rx_slot)
-
 {
 	int rc = 0;
 	struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
 	unsigned int i = 0;
 
-	dev_dbg(dai->dev, "enter %s, id = %d\n", __func__,
-							dai->id);
+	dev_dbg(dai->dev, "%s: dai_id = %d\n", __func__, dai->id);
 	switch (dai->id) {
 	case SLIMBUS_0_RX:
 	case SLIMBUS_1_RX:
+	case SLIMBUS_2_RX:
 	case SLIMBUS_3_RX:
 	case SLIMBUS_4_RX:
 		/* channel number to be between 128 and 255. For RX port
@@ -1144,6 +1165,7 @@
 	case SLIMBUS_0_TX:
 	case SLIMBUS_1_TX:
 	case SLIMBUS_2_TX:
+	case SLIMBUS_3_TX:
 	case SLIMBUS_4_TX:
 		/* channel number to be between 128 and 255. For RX port
 		 * use channel numbers from 138 to 144, for TX port
@@ -1377,11 +1399,11 @@
 
 static struct snd_soc_dai_driver msm_dai_q6_aux_pcm_rx_dai = {
 	.playback = {
-		.rates = SNDRV_PCM_RATE_8000,
+		.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
 		.formats = SNDRV_PCM_FMTBIT_S16_LE,
 		.channels_min = 1,
 		.channels_max = 1,
-		.rate_max = 8000,
+		.rate_max = 16000,
 		.rate_min = 8000,
 	},
 	.ops = &msm_dai_q6_auxpcm_ops,
@@ -1391,11 +1413,11 @@
 
 static struct snd_soc_dai_driver msm_dai_q6_aux_pcm_tx_dai = {
 	.capture = {
-		.rates = SNDRV_PCM_RATE_8000,
+		.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
 		.formats = SNDRV_PCM_FMTBIT_S16_LE,
 		.channels_min = 1,
 		.channels_max = 1,
-		.rate_max = 8000,
+		.rate_max = 16000,
 		.rate_min = 8000,
 	},
 	.ops = &msm_dai_q6_auxpcm_ops,
@@ -1452,6 +1474,22 @@
 	.remove = msm_dai_q6_dai_remove,
 };
 
+static struct snd_soc_dai_driver msm_dai_q6_slimbus_2_rx_dai = {
+	.playback = {
+		.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+		SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 |
+		SNDRV_PCM_RATE_192000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		.channels_min = 1,
+		.channels_max = 2,
+		.rate_min =     8000,
+		.rate_max =	192000,
+	},
+	.ops = &msm_dai_q6_ops,
+	.probe = msm_dai_q6_dai_probe,
+	.remove = msm_dai_q6_dai_remove,
+};
+
 static struct snd_soc_dai_driver msm_dai_q6_slimbus_2_tx_dai = {
 	.capture = {
 		.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
@@ -1514,6 +1552,7 @@
 		break;
 	case SLIMBUS_0_TX:
 	case SLIMBUS_4_TX:
+	case SLIMBUS_3_TX:
 		rc = snd_soc_register_dai(&pdev->dev,
 				&msm_dai_q6_slimbus_tx_dai);
 		break;
@@ -1525,6 +1564,10 @@
 		rc = snd_soc_register_dai(&pdev->dev,
 				&msm_dai_q6_slimbus_1_tx_dai);
 		break;
+	case SLIMBUS_2_RX:
+		rc = snd_soc_register_dai(&pdev->dev,
+				&msm_dai_q6_slimbus_2_rx_dai);
+		break;
 	case SLIMBUS_2_TX:
 		rc = snd_soc_register_dai(&pdev->dev,
 				&msm_dai_q6_slimbus_2_tx_dai);
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index 7fbb592..217158c 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -110,6 +110,43 @@
 /* This array is indexed by back-end DAI ID defined in msm-pcm-routing.h
  * If new back-end is defined, add new back-end DAI ID at the end of enum
  */
+
+union srs_trumedia_params_u {
+	struct srs_trumedia_params srs_params;
+	unsigned short int raw_params[1];
+};
+static union srs_trumedia_params_u msm_srs_trumedia_params[2];
+static int srs_port_id = -1;
+
+static void srs_send_params(int port_id, unsigned int techs,
+		int param_block_idx) {
+	pr_debug("SRS %s: called, port_id = %d, techs flags = %u,"
+			" paramblockidx %d", __func__, port_id, techs,
+			param_block_idx);
+	/* force all if techs is set to 1 */
+	if (techs == 1)
+		techs = 0xFFFFFFFF;
+
+	if (techs & (1 << SRS_ID_WOWHD))
+		srs_trumedia_open(port_id, SRS_ID_WOWHD,
+	(void *)&msm_srs_trumedia_params[param_block_idx].srs_params.wowhd);
+	if (techs & (1 << SRS_ID_CSHP))
+		srs_trumedia_open(port_id, SRS_ID_CSHP,
+	(void *)&msm_srs_trumedia_params[param_block_idx].srs_params.cshp);
+	if (techs & (1 << SRS_ID_HPF))
+		srs_trumedia_open(port_id, SRS_ID_HPF,
+	(void *)&msm_srs_trumedia_params[param_block_idx].srs_params.hpf);
+	if (techs & (1 << SRS_ID_PEQ))
+		srs_trumedia_open(port_id, SRS_ID_PEQ,
+	(void *)&msm_srs_trumedia_params[param_block_idx].srs_params.peq);
+	if (techs & (1 << SRS_ID_HL))
+		srs_trumedia_open(port_id, SRS_ID_HL,
+	(void *)&msm_srs_trumedia_params[param_block_idx].srs_params.hl);
+	if (techs & (1 << SRS_ID_GLOBAL))
+		srs_trumedia_open(port_id, SRS_ID_GLOBAL,
+	(void *)&msm_srs_trumedia_params[param_block_idx].srs_params.global);
+}
+
 static struct msm_pcm_routing_bdai_data msm_bedais[MSM_BACKEND_DAI_MAX] = {
 	{ PRIMARY_I2S_RX, 0, 0, 0, 0, 0},
 	{ PRIMARY_I2S_TX, 0, 0, 0, 0, 0},
@@ -135,6 +172,7 @@
 	{ SLIMBUS_4_RX, 0, 0, 0, 0, 0},
 	{ SLIMBUS_4_TX, 0, 0, 0, 0, 0},
 	{ SLIMBUS_3_RX, 0, 0, 0, 0, 0},
+	{ SLIMBUS_3_TX, 0, 0, 0, 0, 0},
 	{ SLIMBUS_EXTPROC_RX, 0, 0, 0, 0, 0},
 	{ SLIMBUS_EXTPROC_RX, 0, 0, 0, 0, 0},
 	{ SLIMBUS_EXTPROC_RX, 0, 0, 0, 0, 0},
@@ -749,6 +787,104 @@
 	return 0;
 }
 
+static int msm_routing_get_srs_trumedia_control(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = 0;
+	return 0;
+}
+
+static int msm_routing_set_srs_trumedia_control_(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	unsigned int techs = 0;
+	unsigned short offset, value, max, index;
+
+	max = sizeof(msm_srs_trumedia_params) >> 1;
+	index = (unsigned short)((ucontrol->value.integer.value[0] &
+			SRS_PARAM_INDEX_MASK) >> 31);
+	if (SRS_CMD_UPLOAD ==
+		(ucontrol->value.integer.value[0] & SRS_CMD_UPLOAD)) {
+		techs = ucontrol->value.integer.value[0] & 0xFF;
+		pr_debug("SRS %s: send params request, flags = %u",
+			__func__, techs);
+		if (srs_port_id >= 0 && techs)
+			srs_send_params(srs_port_id, techs, index);
+		return 0;
+	}
+	offset = (unsigned short)((ucontrol->value.integer.value[0] &
+			SRS_PARAM_OFFSET_MASK) >> 16);
+	value = (unsigned short)(ucontrol->value.integer.value[0] &
+			SRS_PARAM_VALUE_MASK);
+	if (offset < max) {
+		msm_srs_trumedia_params[index].raw_params[offset] = value;
+		pr_debug("SRS %s: index set... (max %d, requested %d,"
+			" val %d, paramblockidx %d)", __func__, max, offset,
+			value, index);
+	} else {
+		pr_err("SRS %s: index out of bounds! (max %d, requested %d)",
+				__func__, max, offset);
+	}
+	if (offset == 4) {
+		int i;
+		for (i = 0; i < max; i++) {
+			if (i == 0) {
+				pr_debug("SRS %s: global block start",
+						__func__);
+			}
+			if (i ==
+			(sizeof(struct srs_trumedia_params_GLOBAL) >> 1)) {
+				break;
+				pr_debug("SRS %s: wowhd block start at"
+					" offset %d word offset %d", __func__,
+					i, i>>1);
+			}
+			pr_debug("SRS %s: param_index %d index %d val %d",
+				__func__, index, i,
+				msm_srs_trumedia_params[index].raw_params[i]);
+		}
+	}
+	return 0;
+}
+
+static int msm_routing_set_srs_trumedia_control(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol) {
+	int ret;
+
+	pr_debug("SRS control normal called");
+	mutex_lock(&routing_lock);
+	srs_port_id = SLIMBUS_0_RX;
+	ret = msm_routing_set_srs_trumedia_control_(kcontrol, ucontrol);
+	mutex_unlock(&routing_lock);
+	return ret;
+}
+
+static int msm_routing_set_srs_trumedia_control_I2S(
+		struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol) {
+	int ret;
+
+	pr_debug("SRS control I2S called");
+	mutex_lock(&routing_lock);
+	srs_port_id = PRIMARY_I2S_RX;
+	ret = msm_routing_set_srs_trumedia_control_(kcontrol, ucontrol);
+	mutex_unlock(&routing_lock);
+	return ret;
+}
+
+static int msm_routing_set_srs_trumedia_control_HDMI(
+		struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol) {
+	int ret;
+
+	pr_debug("SRS control HDMI called");
+	mutex_lock(&routing_lock);
+	srs_port_id = HDMI_RX;
+	ret =  msm_routing_set_srs_trumedia_control_(kcontrol, ucontrol);
+	mutex_unlock(&routing_lock);
+	return ret;
+}
+
 static void msm_send_eq_values(int eq_idx)
 {
 	int result;
@@ -1273,6 +1409,9 @@
 	SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_MI2S_TX,
 	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
 	msm_routing_put_voice_stub_mixer),
+	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),
 };
 
 static const struct snd_kcontrol_new sbus_0_rx_port_mixer_controls[] = {
@@ -1330,6 +1469,9 @@
 	SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_HDMI_RX,
 	MSM_BACKEND_DAI_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
 	msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("SLIM_3_TX", MSM_BACKEND_DAI_HDMI_RX,
+	MSM_BACKEND_DAI_SLIMBUS_3_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[] = {
@@ -1378,6 +1520,63 @@
 	msm_routing_set_compressed_vol_mixer, compressed_rx_vol_gain),
 };
 
+static const struct snd_kcontrol_new lpa_SRS_trumedia_controls[] = {
+	{.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "SRS TruMedia",
+	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+			SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.info = snd_soc_info_volsw, \
+	.get = msm_routing_get_srs_trumedia_control,
+	.put = msm_routing_set_srs_trumedia_control,
+	.private_value = ((unsigned long)&(struct soc_mixer_control)
+	{.reg = SND_SOC_NOPM,
+	.shift = 0,
+	.rshift = 0,
+	.max = 0xFFFFFFFF,
+	.platform_max = 0xFFFFFFFF,
+	.invert = 0
+	})
+	}
+};
+
+static const struct snd_kcontrol_new lpa_SRS_trumedia_controls_HDMI[] = {
+	{.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "SRS TruMedia HDMI",
+	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+			SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.info = snd_soc_info_volsw, \
+	.get = msm_routing_get_srs_trumedia_control,
+	.put = msm_routing_set_srs_trumedia_control_HDMI,
+	.private_value = ((unsigned long)&(struct soc_mixer_control)
+	{.reg = SND_SOC_NOPM,
+	.shift = 0,
+	.rshift = 0,
+	.max = 0xFFFFFFFF,
+	.platform_max = 0xFFFFFFFF,
+	.invert = 0
+	})
+	}
+};
+
+static const struct snd_kcontrol_new lpa_SRS_trumedia_controls_I2S[] = {
+	{.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "SRS TruMedia I2S",
+	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+		SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.info = snd_soc_info_volsw, \
+	.get = msm_routing_get_srs_trumedia_control,
+	.put = msm_routing_set_srs_trumedia_control_I2S,
+	.private_value = ((unsigned long)&(struct soc_mixer_control)
+	{.reg = SND_SOC_NOPM,
+	.shift = 0,
+	.rshift = 0,
+	.max = 0xFFFFFFFF,
+	.platform_max = 0xFFFFFFFF,
+	.invert = 0
+	})
+	}
+};
+
 static const struct snd_kcontrol_new eq_enable_mixer_controls[] = {
 	SOC_SINGLE_EXT("MultiMedia1 EQ Enable", SND_SOC_NOPM,
 	MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_eq_enable_mixer,
@@ -1633,6 +1832,7 @@
 	SND_SOC_DAPM_AIF_IN("SLIMBUS_1_TX", "Slimbus1 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("STUB_1_TX", "Stub1 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("SLIMBUS_3_RX", "Slimbus3 Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("SLIMBUS_3_TX", "Slimbus3 Capture", 0, 0, 0, 0),
 
 	/* Switch Definitions */
 	SND_SOC_DAPM_SWITCH("SLIMBUS_DL_HL", SND_SOC_NOPM, 0, 0,
@@ -1911,6 +2111,7 @@
 	{"Voice Stub Tx Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
 	{"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_UL", NULL, "Voice Stub Tx Mixer"},
 
 	{"STUB_RX Mixer", "Voice Stub", "VOICE_STUB_DL"},
@@ -1920,6 +2121,7 @@
 	{"INTERNAL_BT_SCO_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
 	{"MI2S_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
 	{"MI2S_RX", NULL, "MI2S_RX_Voice Mixer"},
+	{"HDMI_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
 
 	{"SLIMBUS_3_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
 	{"SLIMBUS_3_RX", NULL, "SLIMBUS_3_RX_Voice Mixer"},
@@ -1934,6 +2136,7 @@
 
 
 	{"HDMI_RX Port Mixer", "MI2S_TX", "MI2S_TX"},
+	{"HDMI_RX Port Mixer", "SLIM_3_TX", "SLIMBUS_3_TX"},
 	{"HDMI", NULL, "HDMI_RX Port Mixer"},
 
 	{"SEC_I2S_RX Port Mixer", "MI2S_TX", "MI2S_TX"},
@@ -1980,8 +2183,10 @@
 	mutex_lock(&routing_lock);
 
 	for_each_set_bit(i, &bedai->fe_sessions, MSM_FRONTEND_DAI_MM_SIZE) {
-		if (fe_dai_map[i][session_type] != INVALID_SESSION)
+		if (fe_dai_map[i][session_type] != INVALID_SESSION) {
 			adm_close(bedai->port_id);
+			srs_port_id = -1;
+		}
 	}
 
 	bedai->active = 0;
@@ -2047,6 +2252,8 @@
 
 			msm_pcm_routing_build_matrix(i,
 				fe_dai_map[i][session_type], path_type);
+			srs_port_id = bedai->port_id;
+			srs_send_params(srs_port_id, 1, 0);
 		}
 	}
 
@@ -2115,6 +2322,18 @@
 				compressed_vol_mixer_controls,
 			ARRAY_SIZE(compressed_vol_mixer_controls));
 
+	snd_soc_add_platform_controls(platform,
+				lpa_SRS_trumedia_controls,
+			ARRAY_SIZE(lpa_SRS_trumedia_controls));
+
+	snd_soc_add_platform_controls(platform,
+				lpa_SRS_trumedia_controls_HDMI,
+			ARRAY_SIZE(lpa_SRS_trumedia_controls_HDMI));
+
+	snd_soc_add_platform_controls(platform,
+				lpa_SRS_trumedia_controls_I2S,
+			ARRAY_SIZE(lpa_SRS_trumedia_controls_I2S));
+
 	return 0;
 }
 
diff --git a/sound/soc/msm/msm-pcm-routing.h b/sound/soc/msm/msm-pcm-routing.h
index 5f5c12a..e1a0e6c 100644
--- a/sound/soc/msm/msm-pcm-routing.h
+++ b/sound/soc/msm/msm-pcm-routing.h
@@ -39,6 +39,7 @@
 #define LPASS_BE_SLIMBUS_1_TX "(Backend) SLIMBUS_1_TX"
 #define LPASS_BE_STUB_1_TX "(Backend) STUB_1_TX"
 #define LPASS_BE_SLIMBUS_3_RX "(Backend) SLIMBUS_3_RX"
+#define LPASS_BE_SLIMBUS_3_TX "(Backend) SLIMBUS_3_TX"
 #define LPASS_BE_SLIMBUS_4_RX "(Backend) SLIMBUS_4_RX"
 #define LPASS_BE_SLIMBUS_4_TX "(Backend) SLIMBUS_4_TX"
 
@@ -90,6 +91,7 @@
 	MSM_BACKEND_DAI_SLIMBUS_4_RX,
 	MSM_BACKEND_DAI_SLIMBUS_4_TX,
 	MSM_BACKEND_DAI_SLIMBUS_3_RX,
+	MSM_BACKEND_DAI_SLIMBUS_3_TX,
 	MSM_BACKEND_DAI_EXTPROC_RX,
 	MSM_BACKEND_DAI_EXTPROC_TX,
 	MSM_BACKEND_DAI_EXTPROC_EC_TX,
diff --git a/sound/soc/msm/msm-pcm-voice.c b/sound/soc/msm/msm-pcm-voice.c
index 59b8bbd..7bdb4f0 100644
--- a/sound/soc/msm/msm-pcm-voice.c
+++ b/sound/soc/msm/msm-pcm-voice.c
@@ -33,7 +33,9 @@
 
 static struct snd_pcm_hardware msm_pcm_hardware = {
 
-	.info =                 SNDRV_PCM_INFO_INTERLEAVED,
+	.info =                 (SNDRV_PCM_INFO_INTERLEAVED|
+				SNDRV_PCM_INFO_PAUSE |
+				SNDRV_PCM_INFO_RESUME),
 	.formats =              SNDRV_PCM_FMTBIT_S16_LE,
 	.rates =                SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
 	.rate_min =             8000,
@@ -205,6 +207,55 @@
 	return 0;
 }
 
+static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	int ret = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_voice *prtd = runtime->private_data;
+	uint16_t session_id = 0;
+
+	pr_debug("%s: cmd = %d\n", __func__, cmd);
+	if (is_volte(prtd))
+		session_id = voc_get_session_id(VOLTE_SESSION_NAME);
+	else
+		session_id = voc_get_session_id(VOICE_SESSION_NAME);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_STOP:
+		pr_debug("Start & Stop Voice call not handled in Trigger.\n");
+	break;
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		pr_debug("%s: resume call session_id = %d\n", __func__,
+			 session_id);
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			ret = msm_pcm_playback_prepare(substream);
+		else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+			ret = msm_pcm_capture_prepare(substream);
+		if (prtd->playback_start && prtd->capture_start)
+			voc_resume_voice_call(session_id);
+	break;
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		pr_debug("%s: pause call session_id=%d\n",
+			 __func__, session_id);
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+			if (prtd->playback_start)
+				prtd->playback_start = 0;
+		} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+			if (prtd->capture_start)
+				prtd->capture_start = 0;
+		}
+		voc_standby_voice_call(session_id);
+	break;
+	default:
+		ret = -EINVAL;
+	break;
+	}
+	return ret;
+}
+
 static int msm_voice_volume_get(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
@@ -437,6 +488,7 @@
 	.hw_params	= msm_pcm_hw_params,
 	.close          = msm_pcm_close,
 	.prepare        = msm_pcm_prepare,
+	.trigger        = msm_pcm_trigger,
 };
 
 
diff --git a/sound/soc/msm/msm8930.c b/sound/soc/msm/msm8930.c
index b31ed65..063fe6b 100644
--- a/sound/soc/msm/msm8930.c
+++ b/sound/soc/msm/msm8930.c
@@ -39,14 +39,21 @@
 #define SPK_AMP_POS	0x1
 #define SPK_AMP_NEG	0x2
 #define SPKR_BOOST_GPIO 15
+#define DEFAULT_PMIC_SPK_GAIN 0x0D
 #define SITAR_EXT_CLK_RATE 12288000
 
-#define SITAR_MBHC_DEF_BUTTONS 3
+#define SITAR_MBHC_DEF_BUTTONS 8
 #define SITAR_MBHC_DEF_RLOADS 5
 
+#define GPIO_AUX_PCM_DOUT 63
+#define GPIO_AUX_PCM_DIN 64
+#define GPIO_AUX_PCM_SYNC 65
+#define GPIO_AUX_PCM_CLK 66
+
 static int msm8930_spk_control;
 static int msm8930_slim_0_rx_ch = 1;
 static int msm8930_slim_0_tx_ch = 1;
+static int msm8930_pmic_spk_gain = DEFAULT_PMIC_SPK_GAIN;
 
 static int msm8930_ext_spk_pamp;
 static int msm8930_btsco_rate = BTSCO_RATE_8KHZ;
@@ -305,11 +312,11 @@
 	{"MIC BIAS2 Internal1", NULL, "Headset Mic"},
 
 	/* Microphone path */
-	{"AMIC1", NULL, "MIC BIAS2 Internal1"},
-	{"MIC BIAS2 Internal1", NULL, "ANCLeft Headset Mic"},
+	{"AMIC1", NULL, "MIC BIAS2 External"},
+	{"MIC BIAS2 External", NULL, "ANCLeft Headset Mic"},
 
-	{"AMIC3", NULL, "MIC BIAS2 Internal1"},
-	{"MIC BIAS2 Internal1", NULL, "ANCRight Headset Mic"},
+	{"AMIC3", NULL, "MIC BIAS2 External"},
+	{"MIC BIAS2 External", NULL, "ANCRight Headset Mic"},
 
 	{"HEADPHONE", NULL, "LDO_H"},
 
@@ -319,17 +326,17 @@
 	 */
 
 	/**
-	 * Digital Mic1. Front Bottom left Digital Mic on Fluid and MTP.
+	 * Digital Mic1. Front Bottom left Mic on Fluid and MTP.
 	 * Digital Mic GM5 on CDP mainboard.
-	 * Conncted to DMIC2 Input on Sitar codec.
+	 * Conncted to DMIC1 Input on Sitar codec.
 	 */
 	{"DMIC1", NULL, "MIC BIAS1 External"},
 	{"MIC BIAS1 External", NULL, "Digital Mic1"},
 
 	/**
-	 * Digital Mic2. Front Bottom right Digital Mic on Fluid and MTP.
+	 * Digital Mic2. Back top MIC on Fluid.
 	 * Digital Mic GM6 on CDP mainboard.
-	 * Conncted to DMIC1 Input on Sitar codec.
+	 * Conncted to DMIC2 Input on Sitar codec.
 	 */
 	{"DMIC2", NULL, "MIC BIAS1 External"},
 	{"MIC BIAS1 External", NULL, "Digital Mic2"},
@@ -431,6 +438,39 @@
 	return 0;
 }
 
+static const char *pmic_spk_gain_text[] = {
+	"NEG_6_DB", "NEG_4_DB", "NEG_2_DB", "ZERO_DB", "POS_2_DB", "POS_4_DB",
+	"POS_6_DB", "POS_8_DB", "POS_10_DB", "POS_12_DB", "POS_14_DB",
+	"POS_16_DB", "POS_18_DB", "POS_20_DB", "POS_22_DB", "POS_24_DB"
+};
+
+static const struct soc_enum msm8960_pmic_spk_gain_enum[] = {
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(pmic_spk_gain_text),
+						pmic_spk_gain_text),
+};
+
+static int msm8930_pmic_gain_get(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm8930_pmic_spk_gain = %d\n", __func__,
+			 msm8930_pmic_spk_gain);
+	ucontrol->value.integer.value[0] = msm8930_pmic_spk_gain;
+	return 0;
+}
+
+static int msm8930_pmic_gain_put(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	int ret = 0;
+	msm8930_pmic_spk_gain = ucontrol->value.integer.value[0];
+	ret = pm8xxx_spk_gain(msm8930_pmic_spk_gain);
+	pr_debug("%s: msm8930_pmic_spk_gain = %d"
+			 " ucontrol->value.integer.value[0] = %d\n", __func__,
+			 msm8930_pmic_spk_gain,
+			 (int) ucontrol->value.integer.value[0]);
+	return ret;
+}
+
 static const struct snd_kcontrol_new sitar_msm8930_controls[] = {
 	SOC_ENUM_EXT("Speaker Function", msm8930_enum[0], msm8930_get_spk,
 		msm8930_set_spk),
@@ -438,6 +478,8 @@
 		msm8930_slim_0_rx_ch_get, msm8930_slim_0_rx_ch_put),
 	SOC_ENUM_EXT("SLIM_0_TX Channels", msm8930_enum[2],
 		msm8930_slim_0_tx_ch_get, msm8930_slim_0_tx_ch_put),
+	SOC_ENUM_EXT("PMIC SPK Gain", msm8960_pmic_spk_gain_enum[0],
+		msm8930_pmic_gain_get, msm8930_pmic_gain_put),
 };
 
 static const struct snd_kcontrol_new int_btsco_rate_mixer_controls[] = {
@@ -489,7 +531,7 @@
 #undef S
 #define S(X, Y) ((SITAR_MBHC_CAL_PLUG_TYPE_PTR(sitar_cal)->X) = (Y))
 	S(v_no_mic, 30);
-	S(v_hs_max, 1550);
+	S(v_hs_max, 1650);
 #undef S
 #define S(X, Y) ((SITAR_MBHC_CAL_BTN_DET_PTR(sitar_cal)->X) = (Y))
 	S(c[0], 62);
@@ -631,7 +673,7 @@
 	}
 
 	err = snd_soc_jack_new(codec, "Button Jack",
-				SND_JACK_BTN_0, &button_jack);
+				SITAR_JACK_BUTTON_MASK, &button_jack);
 	if (err) {
 		pr_err("failed to create new jack\n");
 		return err;
@@ -642,6 +684,9 @@
 	mbhc_cfg.gpio_irq = gpio_to_irq(mbhc_cfg.gpio);
 	sitar_hs_detect(codec, &mbhc_cfg);
 
+	/* Initialize default PMIC speaker gain */
+	pm8xxx_spk_gain(DEFAULT_PMIC_SPK_GAIN);
+
 	return 0;
 }
 
@@ -772,6 +817,80 @@
 	return 0;
 }
 
+static int msm8930_auxpcm_be_params_fixup(struct snd_soc_pcm_runtime *rtd,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+					 SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	/* PCM only supports mono output with 8khz sample rate */
+	rate->min = rate->max = 8000;
+	channels->min = channels->max = 1;
+
+	return 0;
+}
+
+static int msm8930_aux_pcm_get_gpios(void)
+{
+	int ret = 0;
+
+	pr_debug("%s\n", __func__);
+
+	ret = gpio_request(GPIO_AUX_PCM_DOUT, "AUX PCM DOUT");
+	if (ret < 0) {
+		pr_err("%s: Failed to request gpio(%d): AUX PCM DOUT",
+				__func__, GPIO_AUX_PCM_DOUT);
+
+		goto fail_dout;
+	}
+
+	ret = gpio_request(GPIO_AUX_PCM_DIN, "AUX PCM DIN");
+	if (ret < 0) {
+		pr_err("%s: Failed to request gpio(%d): AUX PCM DIN",
+				 __func__, GPIO_AUX_PCM_DIN);
+		goto fail_din;
+	}
+
+	ret = gpio_request(GPIO_AUX_PCM_SYNC, "AUX PCM SYNC");
+	if (ret < 0) {
+		pr_err("%s: Failed to request gpio(%d): AUX PCM SYNC",
+				__func__, GPIO_AUX_PCM_SYNC);
+		goto fail_sync;
+	}
+
+	ret = gpio_request(GPIO_AUX_PCM_CLK, "AUX PCM CLK");
+	if (ret < 0) {
+		pr_err("%s: Failed to request gpio(%d): AUX PCM CLK",
+				 __func__, GPIO_AUX_PCM_CLK);
+		goto fail_clk;
+	}
+
+	return 0;
+
+fail_clk:
+	gpio_free(GPIO_AUX_PCM_SYNC);
+fail_sync:
+	gpio_free(GPIO_AUX_PCM_DIN);
+fail_din:
+	gpio_free(GPIO_AUX_PCM_DOUT);
+fail_dout:
+
+	return ret;
+}
+
+static int msm8930_aux_pcm_free_gpios(void)
+{
+	gpio_free(GPIO_AUX_PCM_DIN);
+	gpio_free(GPIO_AUX_PCM_DOUT);
+	gpio_free(GPIO_AUX_PCM_SYNC);
+	gpio_free(GPIO_AUX_PCM_CLK);
+
+	return 0;
+}
+
 static int msm8930_startup(struct snd_pcm_substream *substream)
 {
 	pr_debug("%s(): substream = %s  stream = %d\n", __func__,
@@ -779,6 +898,26 @@
 	return 0;
 }
 
+static int msm8930_auxpcm_startup(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+
+	pr_debug("%s(): substream = %s\n", __func__, substream->name);
+	ret = msm8930_aux_pcm_get_gpios();
+	if (ret < 0) {
+		pr_err("%s: Aux PCM GPIO request failed\n", __func__);
+		return -EINVAL;
+	}
+	return 0;
+
+}
+
+static void msm8930_auxpcm_shutdown(struct snd_pcm_substream *substream)
+{
+	pr_debug("%s(): substream = %s\n", __func__, substream->name);
+	msm8930_aux_pcm_free_gpios();
+}
+
 static void msm8930_shutdown(struct snd_pcm_substream *substream)
 {
 	pr_debug("%s(): substream = %s  stream = %d\n", __func__,
@@ -791,6 +930,11 @@
 	.shutdown = msm8930_shutdown,
 };
 
+static struct snd_soc_ops msm8930_auxpcm_be_ops = {
+	.startup = msm8930_auxpcm_startup,
+	.shutdown = msm8930_auxpcm_shutdown,
+};
+
 /* Digital audio interface glue - connects codec <---> CPU */
 static struct snd_soc_dai_link msm8930_dai[] = {
 	/* FrontEnd DAI Links */
@@ -1021,6 +1165,30 @@
 		.no_pcm = 1,
 		.be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
 	},
+	/* AUX PCM Backend DAI Links */
+	{
+		.name = LPASS_BE_AUXPCM_RX,
+		.stream_name = "AUX PCM Playback",
+		.cpu_dai_name = "msm-dai-q6.2",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_AUXPCM_RX,
+		.be_hw_params_fixup = msm8930_auxpcm_be_params_fixup,
+		.ops = &msm8930_auxpcm_be_ops,
+	},
+	{
+		.name = LPASS_BE_AUXPCM_TX,
+		.stream_name = "AUX PCM Capture",
+		.cpu_dai_name = "msm-dai-q6.3",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_AUXPCM_TX,
+		.be_hw_params_fixup = msm8930_auxpcm_be_params_fixup,
+	},
 	/* Incall Music BACK END DAI Link */
 	{
 		.name = LPASS_BE_VOICE_PLAYBACK_TX,
diff --git a/sound/soc/msm/msm8960.c b/sound/soc/msm/msm8960.c
index f78f58d..8f0fa32 100644
--- a/sound/soc/msm/msm8960.c
+++ b/sound/soc/msm/msm8960.c
@@ -41,8 +41,8 @@
 #define msm8960_SLIM_0_RX_MAX_CHANNELS		2
 #define msm8960_SLIM_0_TX_MAX_CHANNELS		4
 
-#define BTSCO_RATE_8KHZ 8000
-#define BTSCO_RATE_16KHZ 16000
+#define SAMPLE_RATE_8KHZ 8000
+#define SAMPLE_RATE_16KHZ 16000
 
 #define BOTTOM_SPK_AMP_POS	0x1
 #define BOTTOM_SPK_AMP_NEG	0x2
@@ -61,6 +61,7 @@
 
 #define JACK_DETECT_GPIO 38
 #define JACK_DETECT_INT PM8921_GPIO_IRQ(PM8921_IRQ_BASE, JACK_DETECT_GPIO)
+#define JACK_US_EURO_SEL_GPIO 35
 
 static u32 top_spk_pamp_gpio  = PM8921_GPIO_PM_TO_SYS(18);
 static u32 bottom_spk_pamp_gpio = PM8921_GPIO_PM_TO_SYS(19);
@@ -70,9 +71,11 @@
 static int msm8960_slim_0_rx_ch = 1;
 static int msm8960_slim_0_tx_ch = 1;
 
-static int msm8960_btsco_rate = BTSCO_RATE_8KHZ;
+static int msm8960_btsco_rate = SAMPLE_RATE_8KHZ;
 static int msm8960_btsco_ch = 1;
 
+static int msm8960_auxpcm_rate = SAMPLE_RATE_8KHZ;
+
 static struct clk *codec_clk;
 static int clk_users;
 
@@ -91,6 +94,7 @@
 
 static int msm8960_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
 					bool dapm);
+static bool msm8960_swap_gnd_mic(struct snd_soc_codec *codec);
 
 static struct tabla_mbhc_config mbhc_cfg = {
 	.headset_jack = &hs_jack,
@@ -103,8 +107,11 @@
 	.gpio = 0,
 	.gpio_irq = 0,
 	.gpio_level_insert = 1,
+	.swap_gnd_mic = NULL,
 };
 
+static u32 us_euro_sel_gpio = PM8921_GPIO_PM_TO_SYS(JACK_US_EURO_SEL_GPIO);
+
 static struct mutex cdc_mclk_mutex;
 
 static void msm8960_enable_ext_spk_amp_gpio(u32 spk_amp_gpio)
@@ -372,6 +379,15 @@
 	return r;
 }
 
+static bool msm8960_swap_gnd_mic(struct snd_soc_codec *codec)
+{
+	int value = gpio_get_value_cansleep(us_euro_sel_gpio);
+	pr_debug("%s: US EURO select switch %d to %d\n", __func__, value,
+		 !value);
+	gpio_set_value_cansleep(us_euro_sel_gpio, !value);
+	return true;
+}
+
 static int msm8960_mclk_event(struct snd_soc_dapm_widget *w,
 		struct snd_kcontrol *kcontrol, int event)
 {
@@ -512,6 +528,11 @@
 		SOC_ENUM_SINGLE_EXT(2, btsco_rate_text),
 };
 
+static const char *auxpcm_rate_text[] = {"rate_8000", "rate_16000"};
+static const struct soc_enum msm8960_auxpcm_enum[] = {
+		SOC_ENUM_SINGLE_EXT(2, auxpcm_rate_text),
+};
+
 static int msm8960_slim_0_rx_ch_get(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
@@ -563,19 +584,49 @@
 {
 	switch (ucontrol->value.integer.value[0]) {
 	case 0:
-		msm8960_btsco_rate = BTSCO_RATE_8KHZ;
+		msm8960_btsco_rate = SAMPLE_RATE_8KHZ;
 		break;
 	case 1:
-		msm8960_btsco_rate = BTSCO_RATE_16KHZ;
+		msm8960_btsco_rate = SAMPLE_RATE_16KHZ;
 		break;
 	default:
-		msm8960_btsco_rate = BTSCO_RATE_8KHZ;
+		msm8960_btsco_rate = SAMPLE_RATE_8KHZ;
 		break;
 	}
 	pr_debug("%s: msm8960_btsco_rate = %d\n", __func__, msm8960_btsco_rate);
 	return 0;
 }
 
+static int msm8960_auxpcm_rate_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm8960_auxpcm_rate  = %d", __func__,
+		msm8960_auxpcm_rate);
+	ucontrol->value.integer.value[0] = msm8960_auxpcm_rate;
+	return 0;
+}
+
+static int msm8960_auxpcm_rate_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	switch (ucontrol->value.integer.value[0]) {
+	case 0:
+		msm8960_auxpcm_rate = SAMPLE_RATE_8KHZ;
+		break;
+	case 1:
+		msm8960_auxpcm_rate = SAMPLE_RATE_16KHZ;
+		break;
+	default:
+		msm8960_auxpcm_rate = SAMPLE_RATE_8KHZ;
+		break;
+	}
+	pr_debug("%s: msm8960_auxpcm_rate = %d"
+		"ucontrol->value.integer.value[0] = %d\n", __func__,
+		msm8960_auxpcm_rate,
+		(int)ucontrol->value.integer.value[0]);
+	return 0;
+}
+
 static const struct snd_kcontrol_new tabla_msm8960_controls[] = {
 	SOC_ENUM_EXT("Speaker Function", msm8960_enum[0], msm8960_get_spk,
 		msm8960_set_spk),
@@ -590,6 +641,11 @@
 		msm8960_btsco_rate_get, msm8960_btsco_rate_put),
 };
 
+static const struct snd_kcontrol_new auxpcm_rate_mixer_controls[] = {
+	SOC_ENUM_EXT("AUX PCM SampleRate", msm8960_auxpcm_enum[0],
+		msm8960_auxpcm_rate_get, msm8960_auxpcm_rate_put),
+};
+
 static int msm8960_btsco_init(struct snd_soc_pcm_runtime *rtd)
 {
 	int err = 0;
@@ -603,6 +659,19 @@
 	return 0;
 }
 
+static int msm8960_auxpcm_init(struct snd_soc_pcm_runtime *rtd)
+{
+	int err = 0;
+	struct snd_soc_platform *platform = rtd->platform;
+
+	err = snd_soc_add_platform_controls(platform,
+		auxpcm_rate_mixer_controls,
+		ARRAY_SIZE(auxpcm_rate_mixer_controls));
+	if (err < 0)
+		return err;
+	return 0;
+}
+
 static void *def_tabla_mbhc_cal(void)
 {
 	void *tabla_cal;
@@ -795,7 +864,7 @@
 
 	err = snd_soc_jack_new(codec, "Headset Jack",
 			       (SND_JACK_HEADSET | SND_JACK_OC_HPHL |
-				SND_JACK_OC_HPHR),
+				SND_JACK_OC_HPHR | SND_JACK_UNSUPPORTED),
 			       &hs_jack);
 	if (err) {
 		pr_err("failed to create new jack\n");
@@ -811,6 +880,9 @@
 
 	codec_clk = clk_get(cpu_dai->dev, "osr_clk");
 
+	if (machine_is_msm8960_cdp())
+		mbhc_cfg.swap_gnd_mic = msm8960_swap_gnd_mic;
+
 	if (hs_detect_use_gpio) {
 		mbhc_cfg.gpio = PM8921_GPIO_PM_TO_SYS(JACK_DETECT_GPIO);
 		mbhc_cfg.gpio_irq = JACK_DETECT_INT;
@@ -819,8 +891,8 @@
 	if (mbhc_cfg.gpio) {
 		err = pm8xxx_gpio_config(mbhc_cfg.gpio, &jack_gpio_cfg);
 		if (err) {
-			pr_err("%s: pm8xxx_gpio_config failed %d\n", __func__,
-			       err);
+			pr_err("%s: pm8xxx_gpio_config JACK_DETECT failed %d\n",
+			       __func__, err);
 			return err;
 		}
 	}
@@ -951,8 +1023,8 @@
 	struct snd_interval *channels = hw_param_interval(params,
 					SNDRV_PCM_HW_PARAM_CHANNELS);
 
-	/* PCM only supports mono output with 8khz sample rate */
-	rate->min = rate->max = 8000;
+	rate->min = rate->max = msm8960_auxpcm_rate;
+	/* PCM only supports mono output */
 	channels->min = channels->max = 1;
 
 	return 0;
@@ -1279,6 +1351,7 @@
 		.platform_name = "msm-pcm-routing",
 		.codec_name = "msm-stub-codec.1",
 		.codec_dai_name = "msm-stub-rx",
+		.init = &msm8960_auxpcm_init,
 		.no_pcm = 1,
 		.be_id = MSM_BACKEND_DAI_AUXPCM_RX,
 		.be_hw_params_fixup = msm8960_auxpcm_be_params_fixup,
@@ -1468,19 +1541,19 @@
 	else
 		gpio_direction_output(PM8921_GPIO_PM_TO_SYS(23), 0);
 
-	ret = gpio_request(PM8921_GPIO_PM_TO_SYS(35), "US_EURO_SWITCH");
+	ret = gpio_request(us_euro_sel_gpio, "US_EURO_SWITCH");
 	if (ret) {
 		pr_err("%s: Failed to request gpio %d\n", __func__,
-			PM8921_GPIO_PM_TO_SYS(35));
+		       us_euro_sel_gpio);
 		gpio_free(PM8921_GPIO_PM_TO_SYS(23));
 		return ret;
 	}
-	ret = pm8xxx_gpio_config(PM8921_GPIO_PM_TO_SYS(35), &param);
+	ret = pm8xxx_gpio_config(us_euro_sel_gpio, &param);
 	if (ret)
 		pr_err("%s: Failed to configure gpio %d\n", __func__,
-			PM8921_GPIO_PM_TO_SYS(35));
+		       us_euro_sel_gpio);
 	else
-		gpio_direction_output(PM8921_GPIO_PM_TO_SYS(35), 0);
+		gpio_direction_output(us_euro_sel_gpio, 0);
 
 	return 0;
 }
@@ -1488,7 +1561,7 @@
 {
 	if (msm8960_headset_gpios_configured) {
 		gpio_free(PM8921_GPIO_PM_TO_SYS(23));
-		gpio_free(PM8921_GPIO_PM_TO_SYS(35));
+		gpio_free(us_euro_sel_gpio);
 	}
 }
 
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
new file mode 100644
index 0000000..d47910b
--- /dev/null
+++ b/sound/soc/msm/msm8974.c
@@ -0,0 +1,752 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/soc-dsp.h>
+#include <sound/pcm.h>
+#include <sound/jack.h>
+#include <asm/mach-types.h>
+#include <mach/socinfo.h>
+#include <qdsp6v2/msm-pcm-routing-v2.h>
+#include "../codecs/wcd9310.h"
+
+/* 8974 machine driver */
+
+#define PM8921_GPIO_BASE		NR_GPIO_IRQS
+#define PM8921_GPIO_PM_TO_SYS(pm_gpio)  (pm_gpio - 1 + PM8921_GPIO_BASE)
+
+#define MSM8974_SPK_ON 1
+#define MSM8974_SPK_OFF 0
+
+#define MSM_SLIM_0_RX_MAX_CHANNELS		2
+#define MSM_SLIM_0_TX_MAX_CHANNELS		4
+
+#define BTSCO_RATE_8KHZ 8000
+#define BTSCO_RATE_16KHZ 16000
+
+#define BOTTOM_SPK_AMP_POS	0x1
+#define BOTTOM_SPK_AMP_NEG	0x2
+#define TOP_SPK_AMP_POS		0x4
+#define TOP_SPK_AMP_NEG		0x8
+
+#define GPIO_AUX_PCM_DOUT 43
+#define GPIO_AUX_PCM_DIN 44
+#define GPIO_AUX_PCM_SYNC 45
+#define GPIO_AUX_PCM_CLK 46
+
+#define TABLA_EXT_CLK_RATE 12288000
+
+#define TABLA_MBHC_DEF_BUTTONS 8
+#define TABLA_MBHC_DEF_RLOADS 5
+
+/* Shared channel numbers for Slimbus ports that connect APQ to MDM. */
+enum {
+	SLIM_1_RX_1 = 145, /* BT-SCO and USB TX */
+	SLIM_1_TX_1 = 146, /* BT-SCO and USB RX */
+	SLIM_2_RX_1 = 147, /* HDMI RX */
+	SLIM_3_RX_1 = 148, /* In-call recording RX */
+	SLIM_3_RX_2 = 149, /* In-call recording RX */
+	SLIM_4_TX_1 = 150, /* In-call musid delivery TX */
+};
+
+static u32 top_spk_pamp_gpio  = PM8921_GPIO_PM_TO_SYS(18);
+static u32 bottom_spk_pamp_gpio = PM8921_GPIO_PM_TO_SYS(19);
+static int msm_spk_control;
+static int msm_ext_bottom_spk_pamp;
+static int msm_ext_top_spk_pamp;
+static int msm_slim_0_rx_ch = 1;
+static int msm_slim_0_tx_ch = 1;
+
+static int msm_btsco_rate = BTSCO_RATE_8KHZ;
+static int msm_headset_gpios_configured;
+
+static struct snd_soc_jack hs_jack;
+static struct snd_soc_jack button_jack;
+
+static int msm_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
+				    bool dapm);
+
+static struct tabla_mbhc_config mbhc_cfg = {
+	.headset_jack = &hs_jack,
+	.button_jack = &button_jack,
+	.read_fw_bin = false,
+	.calibration = NULL,
+	.micbias = TABLA_MICBIAS2,
+	.mclk_cb_fn = msm_enable_codec_ext_clk,
+	.mclk_rate = TABLA_EXT_CLK_RATE,
+	.gpio = 0, /* MBHC GPIO is not configured */
+	.gpio_irq = 0,
+	.gpio_level_insert = 1,
+};
+
+static void msm_enable_ext_spk_amp_gpio(u32 spk_amp_gpio)
+{
+	int ret = 0;
+
+	struct pm_gpio param = {
+		.direction      = PM_GPIO_DIR_OUT,
+		.output_buffer  = PM_GPIO_OUT_BUF_CMOS,
+		.output_value   = 1,
+		.pull      = PM_GPIO_PULL_NO,
+		.vin_sel	= PM_GPIO_VIN_S4,
+		.out_strength   = PM_GPIO_STRENGTH_MED,
+		.
+			function       = PM_GPIO_FUNC_NORMAL,
+	};
+
+	if (spk_amp_gpio == bottom_spk_pamp_gpio) {
+
+		ret = gpio_request(bottom_spk_pamp_gpio, "BOTTOM_SPK_AMP");
+		if (ret) {
+			pr_err("%s: Error requesting BOTTOM SPK AMP GPIO %u\n",
+				__func__, bottom_spk_pamp_gpio);
+			return;
+		}
+		ret = pm8xxx_gpio_config(bottom_spk_pamp_gpio, &param);
+		if (ret)
+			pr_err("%s: Failed to configure Bottom Spk Ampl"
+				" gpio %u\n", __func__, bottom_spk_pamp_gpio);
+		else {
+			pr_debug("%s: enable Bottom spkr amp gpio\n", __func__);
+			gpio_direction_output(bottom_spk_pamp_gpio, 1);
+		}
+
+	} else if (spk_amp_gpio == top_spk_pamp_gpio) {
+
+		ret = gpio_request(top_spk_pamp_gpio, "TOP_SPK_AMP");
+		if (ret) {
+			pr_err("%s: Error requesting GPIO %d\n", __func__,
+				top_spk_pamp_gpio);
+			return;
+		}
+		ret = pm8xxx_gpio_config(top_spk_pamp_gpio, &param);
+		if (ret)
+			pr_err("%s: Failed to configure Top Spk Ampl"
+				" gpio %u\n", __func__, top_spk_pamp_gpio);
+		else {
+			pr_debug("%s: enable Top spkr amp gpio\n", __func__);
+			gpio_direction_output(top_spk_pamp_gpio, 1);
+		}
+	} else {
+		pr_err("%s: ERROR : Invalid External Speaker Ampl GPIO."
+			" gpio = %u\n", __func__, spk_amp_gpio);
+		return;
+	}
+}
+
+static void msm_ext_spk_power_amp_on(u32 spk)
+{
+	if (spk & (BOTTOM_SPK_AMP_POS | BOTTOM_SPK_AMP_NEG)) {
+
+		if ((msm_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_POS) &&
+			(msm_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_NEG)) {
+
+			pr_debug("%s() External Bottom Speaker Ampl already "
+				"turned on. spk = 0x%08x\n", __func__, spk);
+			return;
+		}
+
+		msm_ext_bottom_spk_pamp |= spk;
+
+		if ((msm_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_POS) &&
+			(msm_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_NEG)) {
+
+			msm_enable_ext_spk_amp_gpio(bottom_spk_pamp_gpio);
+			pr_debug("%s: slepping 4 ms after turning on external "
+				" Bottom Speaker Ampl\n", __func__);
+			usleep_range(4000, 4000);
+		}
+
+	} else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG)) {
+
+		if ((msm_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
+			(msm_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) {
+
+			pr_debug("%s() External Top Speaker Ampl already"
+				"turned on. spk = 0x%08x\n", __func__, spk);
+			return;
+		}
+
+		msm_ext_top_spk_pamp |= spk;
+
+		if ((msm_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
+			(msm_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) {
+
+			msm_enable_ext_spk_amp_gpio(top_spk_pamp_gpio);
+			pr_debug("%s: sleeping 4 ms after turning on "
+				" external Top Speaker Ampl\n", __func__);
+			usleep_range(4000, 4000);
+		}
+	} else  {
+
+		pr_err("%s: ERROR : Invalid External Speaker Ampl. spk = 0x%08x\n",
+			__func__, spk);
+		return;
+	}
+}
+
+static void msm_ext_spk_power_amp_off(u32 spk)
+{
+	if (spk & (BOTTOM_SPK_AMP_POS | BOTTOM_SPK_AMP_NEG)) {
+
+		if (!msm_ext_bottom_spk_pamp)
+			return;
+
+		gpio_direction_output(bottom_spk_pamp_gpio, 0);
+		gpio_free(bottom_spk_pamp_gpio);
+		msm_ext_bottom_spk_pamp = 0;
+
+		pr_debug("%s: sleeping 4 ms after turning off external Bottom"
+			" Speaker Ampl\n", __func__);
+
+		usleep_range(4000, 4000);
+
+	} else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG)) {
+
+		if (!msm_ext_top_spk_pamp)
+			return;
+
+		gpio_direction_output(top_spk_pamp_gpio, 0);
+		gpio_free(top_spk_pamp_gpio);
+		msm_ext_top_spk_pamp = 0;
+
+		pr_debug("%s: sleeping 4 ms after turning off external Top"
+			" Spkaker Ampl\n", __func__);
+
+		usleep_range(4000, 4000);
+	} else  {
+
+		pr_err("%s: ERROR : Invalid Ext Spk Ampl. spk = 0x%08x\n",
+			__func__, spk);
+		return;
+	}
+}
+
+static void msm_ext_control(struct snd_soc_codec *codec)
+{
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+	pr_debug("%s: msm_spk_control = %d", __func__, msm_spk_control);
+	if (msm_spk_control == MSM8974_SPK_ON) {
+		snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
+		snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
+		snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
+		snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
+	} else {
+		snd_soc_dapm_disable_pin(dapm, "Ext Spk Bottom Pos");
+		snd_soc_dapm_disable_pin(dapm, "Ext Spk Bottom Neg");
+		snd_soc_dapm_disable_pin(dapm, "Ext Spk Top Pos");
+		snd_soc_dapm_disable_pin(dapm, "Ext Spk Top Neg");
+	}
+
+	snd_soc_dapm_sync(dapm);
+}
+
+static int msm_get_spk(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm_spk_control = %d", __func__, msm_spk_control);
+	ucontrol->value.integer.value[0] = msm_spk_control;
+	return 0;
+}
+static int msm_set_spk(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+	pr_debug("%s()\n", __func__);
+	if (msm_spk_control == ucontrol->value.integer.value[0])
+		return 0;
+
+	msm_spk_control = ucontrol->value.integer.value[0];
+	msm_ext_control(codec);
+	return 1;
+}
+static int msm_spkramp_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *k, int event)
+{
+	pr_debug("%s() %x\n", __func__, SND_SOC_DAPM_EVENT_ON(event));
+
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		if (!strncmp(w->name, "Ext Spk Bottom Pos", 18))
+			msm_ext_spk_power_amp_on(BOTTOM_SPK_AMP_POS);
+		else if (!strncmp(w->name, "Ext Spk Bottom Neg", 18))
+			msm_ext_spk_power_amp_on(BOTTOM_SPK_AMP_NEG);
+		else if (!strncmp(w->name, "Ext Spk Top Pos", 15))
+			msm_ext_spk_power_amp_on(TOP_SPK_AMP_POS);
+		else if  (!strncmp(w->name, "Ext Spk Top Neg", 15))
+			msm_ext_spk_power_amp_on(TOP_SPK_AMP_NEG);
+		else {
+			pr_err("%s() Invalid Speaker Widget = %s\n",
+					__func__, w->name);
+			return -EINVAL;
+		}
+
+	} else {
+		if (!strncmp(w->name, "Ext Spk Bottom Pos", 18))
+			msm_ext_spk_power_amp_off(BOTTOM_SPK_AMP_POS);
+		else if (!strncmp(w->name, "Ext Spk Bottom Neg", 18))
+			msm_ext_spk_power_amp_off(BOTTOM_SPK_AMP_NEG);
+		else if (!strncmp(w->name, "Ext Spk Top Pos", 15))
+			msm_ext_spk_power_amp_off(TOP_SPK_AMP_POS);
+		else if  (!strncmp(w->name, "Ext Spk Top Neg", 15))
+			msm_ext_spk_power_amp_off(TOP_SPK_AMP_NEG);
+		else {
+			pr_err("%s() Invalid Speaker Widget = %s\n",
+					__func__, w->name);
+			return -EINVAL;
+		}
+	}
+	return 0;
+}
+
+static int msm_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
+				    bool dapm)
+{
+	return 0;
+}
+
+static int msm_mclk_event(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget msm_dapm_widgets[] = {
+
+	SND_SOC_DAPM_SUPPLY("MCLK",  SND_SOC_NOPM, 0, 0,
+	msm_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_SPK("Ext Spk Bottom Pos", msm_spkramp_event),
+	SND_SOC_DAPM_SPK("Ext Spk Bottom Neg", msm_spkramp_event),
+
+	SND_SOC_DAPM_SPK("Ext Spk Top Pos", msm_spkramp_event),
+	SND_SOC_DAPM_SPK("Ext Spk Top Neg", msm_spkramp_event),
+
+	SND_SOC_DAPM_MIC("Handset Mic", NULL),
+	SND_SOC_DAPM_MIC("Headset Mic", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic1", NULL),
+	SND_SOC_DAPM_MIC("ANCRight Headset Mic", NULL),
+	SND_SOC_DAPM_MIC("ANCLeft Headset Mic", NULL),
+
+	SND_SOC_DAPM_MIC("Digital Mic1", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic2", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic3", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic4", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic5", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic6", NULL),
+
+};
+
+static const struct snd_soc_dapm_route common_audio_map[] = {
+
+	{"RX_BIAS", NULL, "MCLK"},
+	{"LDO_H", NULL, "MCLK"},
+
+	/* Speaker path */
+	{"Ext Spk Bottom Pos", NULL, "LINEOUT1"},
+	{"Ext Spk Bottom Neg", NULL, "LINEOUT3"},
+
+	{"Ext Spk Top Pos", NULL, "LINEOUT2"},
+	{"Ext Spk Top Neg", NULL, "LINEOUT4"},
+
+	/* Microphone path */
+	{"AMIC1", NULL, "MIC BIAS1 Internal1"},
+	{"MIC BIAS1 Internal1", NULL, "Handset Mic"},
+
+	{"AMIC2", NULL, "MIC BIAS2 External"},
+	{"MIC BIAS2 External", NULL, "Headset Mic"},
+
+	/**
+	 * AMIC3 and AMIC4 inputs are connected to ANC microphones
+	 * These mics are biased differently on CDP and FLUID
+	 * routing entries below are based on bias arrangement
+	 * on FLUID.
+	 */
+	{"AMIC3", NULL, "MIC BIAS3 Internal1"},
+	{"MIC BIAS3 Internal1", NULL, "ANCRight Headset Mic"},
+
+	{"AMIC4", NULL, "MIC BIAS1 Internal2"},
+	{"MIC BIAS1 Internal2", NULL, "ANCLeft Headset Mic"},
+
+	{"HEADPHONE", NULL, "LDO_H"},
+
+	/**
+	 * The digital Mic routes are setup considering
+	 * fluid as default device.
+	 */
+
+	/**
+	 * Digital Mic1. Front Bottom left Digital Mic on Fluid and MTP.
+	 * Digital Mic GM5 on CDP mainboard.
+	 * Conncted to DMIC2 Input on Tabla codec.
+	 */
+	{"DMIC2", NULL, "MIC BIAS1 External"},
+	{"MIC BIAS1 External", NULL, "Digital Mic1"},
+
+	/**
+	 * Digital Mic2. Front Bottom right Digital Mic on Fluid and MTP.
+	 * Digital Mic GM6 on CDP mainboard.
+	 * Conncted to DMIC1 Input on Tabla codec.
+	 */
+	{"DMIC1", NULL, "MIC BIAS1 External"},
+	{"MIC BIAS1 External", NULL, "Digital Mic2"},
+
+	/**
+	 * Digital Mic3. Back Bottom Digital Mic on Fluid.
+	 * Digital Mic GM1 on CDP mainboard.
+	 * Conncted to DMIC4 Input on Tabla codec.
+	 */
+	{"DMIC4", NULL, "MIC BIAS3 External"},
+	{"MIC BIAS3 External", NULL, "Digital Mic3"},
+
+	/**
+	 * Digital Mic4. Back top Digital Mic on Fluid.
+	 * Digital Mic GM2 on CDP mainboard.
+	 * Conncted to DMIC3 Input on Tabla codec.
+	 */
+	{"DMIC3", NULL, "MIC BIAS3 External"},
+	{"MIC BIAS3 External", NULL, "Digital Mic4"},
+
+	/**
+	 * Digital Mic5. Front top Digital Mic on Fluid.
+	 * Digital Mic GM3 on CDP mainboard.
+	 * Conncted to DMIC5 Input on Tabla codec.
+	 */
+	{"DMIC5", NULL, "MIC BIAS4 External"},
+	{"MIC BIAS4 External", NULL, "Digital Mic5"},
+
+	/* Tabla digital Mic6 - back bottom digital Mic on Liquid and
+	 * bottom mic on CDP. FLUID/MTP do not have dmic6 installed.
+	 */
+	{"DMIC6", NULL, "MIC BIAS4 External"},
+	{"MIC BIAS4 External", NULL, "Digital Mic6"},
+};
+
+static const char *spk_function[] = {"Off", "On"};
+static const char *slim0_rx_ch_text[] = {"One", "Two"};
+static const char *slim0_tx_ch_text[] = {"One", "Two", "Three", "Four"};
+
+static const struct soc_enum msm_enum[] = {
+	SOC_ENUM_SINGLE_EXT(2, spk_function),
+	SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
+	SOC_ENUM_SINGLE_EXT(4, slim0_tx_ch_text),
+};
+
+static const char *btsco_rate_text[] = {"8000", "16000"};
+static const struct soc_enum msm_btsco_enum[] = {
+		SOC_ENUM_SINGLE_EXT(2, btsco_rate_text),
+};
+
+static int msm_slim_0_rx_ch_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm_slim_0_rx_ch  = %d\n", __func__,
+			msm_slim_0_rx_ch);
+	ucontrol->value.integer.value[0] = msm_slim_0_rx_ch - 1;
+	return 0;
+}
+
+static int msm_slim_0_rx_ch_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	msm_slim_0_rx_ch = ucontrol->value.integer.value[0] + 1;
+
+	pr_debug("%s: msm_slim_0_rx_ch = %d\n", __func__,
+			msm_slim_0_rx_ch);
+	return 1;
+}
+
+static int msm_slim_0_tx_ch_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm_slim_0_tx_ch  = %d\n", __func__,
+			msm_slim_0_tx_ch);
+	ucontrol->value.integer.value[0] = msm_slim_0_tx_ch - 1;
+	return 0;
+}
+
+static int msm_slim_0_tx_ch_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	msm_slim_0_tx_ch = ucontrol->value.integer.value[0] + 1;
+
+	pr_debug("%s: msm_slim_0_tx_ch = %d\n", __func__,
+			msm_slim_0_tx_ch);
+	return 1;
+}
+
+static int msm_btsco_rate_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm_btsco_rate  = %d", __func__,
+					msm_btsco_rate);
+	ucontrol->value.integer.value[0] = msm_btsco_rate;
+	return 0;
+}
+
+static int msm_btsco_rate_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	switch (ucontrol->value.integer.value[0]) {
+	case 0:
+		msm_btsco_rate = BTSCO_RATE_8KHZ;
+		break;
+	case 1:
+		msm_btsco_rate = BTSCO_RATE_16KHZ;
+		break;
+	default:
+		msm_btsco_rate = BTSCO_RATE_8KHZ;
+		break;
+	}
+	pr_debug("%s: msm_btsco_rate = %d\n", __func__,
+					msm_btsco_rate);
+	return 0;
+}
+
+static const struct snd_kcontrol_new tabla_msm_controls[] = {
+	SOC_ENUM_EXT("Speaker Function", msm_enum[0], msm_get_spk,
+		msm_set_spk),
+	SOC_ENUM_EXT("SLIM_0_RX Channels", msm_enum[1],
+		msm_slim_0_rx_ch_get, msm_slim_0_rx_ch_put),
+	SOC_ENUM_EXT("SLIM_0_TX Channels", msm_enum[2],
+		msm_slim_0_tx_ch_get, msm_slim_0_tx_ch_put),
+};
+
+static const struct snd_kcontrol_new int_btsco_rate_mixer_controls[] = {
+	SOC_ENUM_EXT("Internal BTSCO SampleRate", msm_btsco_enum[0],
+		msm_btsco_rate_get, msm_btsco_rate_put),
+};
+
+static struct snd_soc_dsp_link lpa_fe_media = {
+	.playback = true,
+	.trigger = {
+		SND_SOC_DSP_TRIGGER_POST,
+		SND_SOC_DSP_TRIGGER_POST
+	},
+};
+static struct snd_soc_dsp_link fe_media = {
+	.playback = true,
+	.capture = true,
+	.trigger = {
+		SND_SOC_DSP_TRIGGER_POST,
+		SND_SOC_DSP_TRIGGER_POST
+	},
+};
+static int msm_auxpcm_be_params_fixup(struct snd_soc_pcm_runtime *rtd,
+					struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	/* PCM only supports mono output with 8khz sample rate */
+	rate->min = rate->max = 8000;
+	channels->min = channels->max = 1;
+
+	return 0;
+}
+static int msm_aux_pcm_get_gpios(void)
+{
+	int ret = 0;
+
+	pr_debug("%s\n", __func__);
+
+	ret = gpio_request(GPIO_AUX_PCM_DOUT, "AUX PCM DOUT");
+	if (ret < 0) {
+		pr_err("%s: Failed to request gpio(%d): AUX PCM DOUT",
+				__func__, GPIO_AUX_PCM_DOUT);
+		goto fail_dout;
+	}
+
+	ret = gpio_request(GPIO_AUX_PCM_DIN, "AUX PCM DIN");
+	if (ret < 0) {
+		pr_err("%s: Failed to request gpio(%d): AUX PCM DIN",
+				__func__, GPIO_AUX_PCM_DIN);
+		goto fail_din;
+	}
+
+	ret = gpio_request(GPIO_AUX_PCM_SYNC, "AUX PCM SYNC");
+	if (ret < 0) {
+		pr_err("%s: Failed to request gpio(%d): AUX PCM SYNC",
+				__func__, GPIO_AUX_PCM_SYNC);
+		goto fail_sync;
+	}
+	ret = gpio_request(GPIO_AUX_PCM_CLK, "AUX PCM CLK");
+	if (ret < 0) {
+		pr_err("%s: Failed to request gpio(%d): AUX PCM CLK",
+				__func__, GPIO_AUX_PCM_CLK);
+		goto fail_clk;
+	}
+
+	return 0;
+
+fail_clk:
+	gpio_free(GPIO_AUX_PCM_SYNC);
+fail_sync:
+	gpio_free(GPIO_AUX_PCM_DIN);
+fail_din:
+	gpio_free(GPIO_AUX_PCM_DOUT);
+fail_dout:
+
+	return ret;
+}
+static int msm_aux_pcm_free_gpios(void)
+{
+	gpio_free(GPIO_AUX_PCM_DIN);
+	gpio_free(GPIO_AUX_PCM_DOUT);
+	gpio_free(GPIO_AUX_PCM_SYNC);
+	gpio_free(GPIO_AUX_PCM_CLK);
+
+	return 0;
+}
+
+static int msm_auxpcm_startup(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+
+	pr_debug("%s(): substream = %s\n", __func__, substream->name);
+	ret = msm_aux_pcm_get_gpios();
+	if (ret < 0) {
+		pr_err("%s: Aux PCM GPIO request failed\n", __func__);
+		return -EINVAL;
+	}
+	return ret;
+}
+
+static void msm_auxpcm_shutdown(struct snd_pcm_substream *substream)
+{
+
+	pr_debug("%s(): substream = %s\n", __func__, substream->name);
+	msm_aux_pcm_free_gpios();
+}
+static struct snd_soc_ops msm_auxpcm_be_ops = {
+	.startup = msm_auxpcm_startup,
+	.shutdown = msm_auxpcm_shutdown,
+};
+/* Digital audio interface glue - connects codec <---> CPU */
+static struct snd_soc_dai_link msm_dai[] = {
+	/* FrontEnd DAI Links */
+	{
+		.name = "MSM8974 Media1",
+		.stream_name = "MultiMedia1",
+		.cpu_dai_name	= "MultiMedia1",
+		.platform_name  = "msm-pcm-dsp",
+		.dynamic = 1,
+		.dsp_link = &fe_media,
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA1
+	},
+	{
+		.name = "MSM8974 LPA",
+		.stream_name = "LPA",
+		.cpu_dai_name	= "MultiMedia3",
+		.platform_name  = "msm-pcm-lpa",
+		.dynamic = 1,
+		.dsp_link = &lpa_fe_media,
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA3,
+	},
+
+	/* AUX PCM Backend DAI Links */
+	{
+		.name = LPASS_BE_AUXPCM_RX,
+		.stream_name = "AUX PCM Playback",
+		.cpu_dai_name = "msm-dai-q6.4106",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_AUXPCM_RX,
+		.be_hw_params_fixup = msm_auxpcm_be_params_fixup,
+		.ops = &msm_auxpcm_be_ops,
+	},
+	{
+		.name = LPASS_BE_AUXPCM_TX,
+		.stream_name = "AUX PCM Capture",
+		.cpu_dai_name = "msm-dai-q6.4107",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_AUXPCM_TX,
+		.be_hw_params_fixup = msm_auxpcm_be_params_fixup,
+	},
+
+};
+
+struct snd_soc_card snd_soc_card_msm = {
+	.name		= "msm8974-taiko-snd-card",
+	.dai_link	= msm_dai,
+	.num_links	= ARRAY_SIZE(msm_dai),
+};
+
+static struct platform_device *msm_snd_device;
+
+static void msm_free_headset_mic_gpios(void)
+{
+	if (msm_headset_gpios_configured) {
+		gpio_free(PM8921_GPIO_PM_TO_SYS(23));
+		gpio_free(PM8921_GPIO_PM_TO_SYS(35));
+	}
+}
+
+static int __init msm_audio_init(void)
+{
+	int ret = 0;
+	if (!machine_is_copper_sim()) {
+		pr_err("%s: Not the right machine type\n", __func__);
+		return -ENODEV;
+	}
+	msm_snd_device = platform_device_alloc("soc-audio", 0);
+	if (!msm_snd_device) {
+		pr_err("Platform device allocation failed\n");
+		kfree(mbhc_cfg.calibration);
+		return -ENOMEM;
+	}
+
+	platform_set_drvdata(msm_snd_device, &snd_soc_card_msm);
+	ret = platform_device_add(msm_snd_device);
+	if (ret) {
+		platform_device_put(msm_snd_device);
+		kfree(mbhc_cfg.calibration);
+		return ret;
+	}
+	return ret;
+
+}
+module_init(msm_audio_init);
+
+static void __exit msm_audio_exit(void)
+{
+	if (!machine_is_copper_sim()) {
+		pr_err("%s: Not the right machine type\n", __func__);
+		return ;
+	}
+	msm_free_headset_mic_gpios();
+	platform_device_unregister(msm_snd_device);
+	kfree(mbhc_cfg.calibration);
+}
+module_exit(msm_audio_exit);
+
+MODULE_DESCRIPTION("ALSA SoC msm");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/qdsp6/q6adm.c b/sound/soc/msm/qdsp6/q6adm.c
index 676ecf1..bf6f743 100644
--- a/sound/soc/msm/qdsp6/q6adm.c
+++ b/sound/soc/msm/qdsp6/q6adm.c
@@ -45,6 +45,189 @@
 
 static struct adm_ctl			this_adm;
 
+int srs_trumedia_open(int port_id, int srs_tech_id, void *srs_params)
+{
+	struct asm_pp_params_command *open = NULL;
+	int ret = 0, sz = 0;
+	int index;
+
+	pr_debug("SRS - %s", __func__);
+	switch (srs_tech_id) {
+	case SRS_ID_GLOBAL: {
+		struct srs_trumedia_params_GLOBAL *glb_params = NULL;
+		sz = sizeof(struct asm_pp_params_command) +
+			sizeof(struct srs_trumedia_params_GLOBAL);
+		open = kzalloc(sz, GFP_KERNEL);
+		open->payload_size = sizeof(struct srs_trumedia_params_GLOBAL) +
+					sizeof(struct asm_pp_param_data_hdr);
+		open->params.param_id = SRS_TRUMEDIA_PARAMS;
+		open->params.param_size =
+				sizeof(struct srs_trumedia_params_GLOBAL);
+		glb_params = (struct srs_trumedia_params_GLOBAL *)((u8 *)open +
+				sizeof(struct asm_pp_params_command));
+		memcpy(glb_params, srs_params,
+			sizeof(struct srs_trumedia_params_GLOBAL));
+		pr_debug("SRS - %s: Global params - 1 = %x, 2 = %x, 3 = %x,"
+				" 4 = %x, 5 = %x, 6 = %x, 7 = %x, 8 = %x\n",
+				__func__, (int)glb_params->v1,
+				(int)glb_params->v2, (int)glb_params->v3,
+				(int)glb_params->v4, (int)glb_params->v5,
+				(int)glb_params->v6, (int)glb_params->v7,
+				(int)glb_params->v8);
+		break;
+	}
+	case SRS_ID_WOWHD: {
+		struct srs_trumedia_params_WOWHD *whd_params = NULL;
+		sz = sizeof(struct asm_pp_params_command) +
+			sizeof(struct srs_trumedia_params_WOWHD);
+		open = kzalloc(sz, GFP_KERNEL);
+		open->payload_size = sizeof(struct srs_trumedia_params_WOWHD) +
+					sizeof(struct asm_pp_param_data_hdr);
+		open->params.param_id = SRS_TRUMEDIA_PARAMS_WOWHD;
+		open->params.param_size =
+				sizeof(struct srs_trumedia_params_WOWHD);
+		whd_params = (struct srs_trumedia_params_WOWHD *)((u8 *)open +
+				sizeof(struct asm_pp_params_command));
+		memcpy(whd_params, srs_params,
+				sizeof(struct srs_trumedia_params_WOWHD));
+		pr_debug("SRS - %s: WOWHD params - 1 = %x, 2 = %x, 3 = %x,"
+			" 4 = %x, 5 = %x, 6 = %x, 7 = %x, 8 = %x, 9 = %x,"
+			" 10 = %x, 11 = %x\n", __func__, (int)whd_params->v1,
+			(int)whd_params->v2, (int)whd_params->v3,
+			(int)whd_params->v4, (int)whd_params->v5,
+			(int)whd_params->v6, (int)whd_params->v7,
+			(int)whd_params->v8, (int)whd_params->v9,
+			(int)whd_params->v10, (int)whd_params->v11);
+		break;
+	}
+	case SRS_ID_CSHP: {
+		struct srs_trumedia_params_CSHP *chp_params = NULL;
+		sz = sizeof(struct asm_pp_params_command) +
+			sizeof(struct srs_trumedia_params_CSHP);
+		open = kzalloc(sz, GFP_KERNEL);
+		open->payload_size = sizeof(struct srs_trumedia_params_CSHP) +
+					sizeof(struct asm_pp_param_data_hdr);
+		open->params.param_id = SRS_TRUMEDIA_PARAMS_CSHP;
+		open->params.param_size =
+					sizeof(struct srs_trumedia_params_CSHP);
+		chp_params = (struct srs_trumedia_params_CSHP *)((u8 *)open +
+				sizeof(struct asm_pp_params_command));
+		memcpy(chp_params, srs_params,
+				sizeof(struct srs_trumedia_params_CSHP));
+		pr_debug("SRS - %s: CSHP params - 1 = %x, 2 = %x, 3 = %x,"
+				" 4 = %x, 5 = %x, 6 = %x, 7 = %x, 8 = %x,"
+				" 9 = %x\n", __func__, (int)chp_params->v1,
+				(int)chp_params->v2, (int)chp_params->v3,
+				(int)chp_params->v4, (int)chp_params->v5,
+				(int)chp_params->v6, (int)chp_params->v7,
+				(int)chp_params->v8, (int)chp_params->v9);
+		break;
+	}
+	case SRS_ID_HPF: {
+		struct srs_trumedia_params_HPF *hpf_params = NULL;
+		sz = sizeof(struct asm_pp_params_command) +
+			sizeof(struct srs_trumedia_params_HPF);
+		open = kzalloc(sz, GFP_KERNEL);
+		open->payload_size = sizeof(struct srs_trumedia_params_HPF) +
+					sizeof(struct asm_pp_param_data_hdr);
+		open->params.param_id = SRS_TRUMEDIA_PARAMS_HPF;
+		open->params.param_size =
+					sizeof(struct srs_trumedia_params_HPF);
+		hpf_params = (struct srs_trumedia_params_HPF *)((u8 *)open +
+				sizeof(struct asm_pp_params_command));
+		memcpy(hpf_params, srs_params,
+			sizeof(struct srs_trumedia_params_HPF));
+		pr_debug("SRS - %s: HPF params - 1 = %x\n", __func__,
+				(int)hpf_params->v1);
+		break;
+	}
+	case SRS_ID_PEQ: {
+		struct srs_trumedia_params_PEQ *peq_params = NULL;
+		sz = sizeof(struct asm_pp_params_command) +
+			sizeof(struct srs_trumedia_params_PEQ);
+		open = kzalloc(sz, GFP_KERNEL);
+		open->payload_size = sizeof(struct srs_trumedia_params_PEQ) +
+					sizeof(struct asm_pp_param_data_hdr);
+		open->params.param_id = SRS_TRUMEDIA_PARAMS_PEQ;
+		open->params.param_size =
+					sizeof(struct srs_trumedia_params_PEQ);
+		peq_params = (struct srs_trumedia_params_PEQ *)((u8 *)open +
+				sizeof(struct asm_pp_params_command));
+		memcpy(peq_params, srs_params,
+				sizeof(struct srs_trumedia_params_PEQ));
+		pr_debug("SRS - %s: PEQ params - 1 = %x 2 = %x, 3 = %x,"
+			" 4 = %x\n", __func__, (int)peq_params->v1,
+			(int)peq_params->v2, (int)peq_params->v3,
+			(int)peq_params->v4);
+		break;
+	}
+	case SRS_ID_HL: {
+		struct srs_trumedia_params_HL *hl_params = NULL;
+		sz = sizeof(struct asm_pp_params_command) +
+			sizeof(struct srs_trumedia_params_HL);
+		open = kzalloc(sz, GFP_KERNEL);
+		open->payload_size = sizeof(struct srs_trumedia_params_HL) +
+					sizeof(struct asm_pp_param_data_hdr);
+		open->params.param_id = SRS_TRUMEDIA_PARAMS_HL;
+		open->params.param_size = sizeof(struct srs_trumedia_params_HL);
+		hl_params = (struct srs_trumedia_params_HL *)((u8 *)open +
+				sizeof(struct asm_pp_params_command));
+		memcpy(hl_params, srs_params,
+				sizeof(struct srs_trumedia_params_HL));
+		pr_debug("SRS - %s: HL params - 1 = %x, 2 = %x, 3 = %x, 4 = %x,"
+				" 5 = %x, 6 = %x, 7 = %x\n", __func__,
+				(int)hl_params->v1, (int)hl_params->v2,
+				(int)hl_params->v3, (int)hl_params->v4,
+				(int)hl_params->v5, (int)hl_params->v6,
+				(int)hl_params->v7);
+		break;
+	}
+	default:
+		goto fail_cmd;
+	}
+
+	open->payload = NULL;
+	open->params.module_id = SRS_TRUMEDIA_MODULE_ID;
+	open->params.reserved = 0;
+	open->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	open->hdr.pkt_size = sz;
+	open->hdr.src_svc = APR_SVC_ADM;
+	open->hdr.src_domain = APR_DOMAIN_APPS;
+	open->hdr.src_port = port_id;
+	open->hdr.dest_svc = APR_SVC_ADM;
+	open->hdr.dest_domain = APR_DOMAIN_ADSP;
+	index = afe_get_port_index(port_id);
+	open->hdr.dest_port = atomic_read(&this_adm.copp_id[index]);
+	open->hdr.token = port_id;
+	open->hdr.opcode = ADM_CMD_SET_PARAMS;
+	pr_debug("SRS - %s: Command was sent now check Q6 - port id = %d,"
+			" size %d, module id %x, param id %x.\n", __func__,
+			open->hdr.dest_port, open->payload_size,
+			open->params.module_id, open->params.param_id);
+
+	ret = apr_send_pkt(this_adm.apr, (uint32_t *)open);
+	if (ret < 0) {
+		pr_err("SRS - %s: ADM enable for port %d failed\n", __func__,
+			port_id);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+	/* Wait for the callback with copp id */
+	ret = wait_event_timeout(this_adm.wait, 1,
+			msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("SRS - %s: ADM open failed for port %d\n", __func__,
+			port_id);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+
+fail_cmd:
+	kfree(open);
+	return ret;
+}
+
 static int32_t adm_callback(struct apr_client_data *data, void *priv)
 {
 	uint32_t *payload;
@@ -528,9 +711,7 @@
 			if ((open.topology_id ==
 				VPM_TX_SM_ECNS_COPP_TOPOLOGY) ||
 			    (open.topology_id ==
-				VPM_TX_DM_FLUENCE_COPP_TOPOLOGY) ||
-			    (open.topology_id ==
-				VPM_TX_QMIC_FLUENCE_COPP_TOPOLOGY))
+				VPM_TX_DM_FLUENCE_COPP_TOPOLOGY))
 				rate = 16000;
 		}
 
diff --git a/sound/soc/msm/qdsp6/q6afe.c b/sound/soc/msm/qdsp6/q6afe.c
index 9f058b9..ce81cca 100644
--- a/sound/soc/msm/qdsp6/q6afe.c
+++ b/sound/soc/msm/qdsp6/q6afe.c
@@ -147,6 +147,7 @@
 	case HDMI_RX:
 	case SLIMBUS_0_RX:
 	case SLIMBUS_1_RX:
+	case SLIMBUS_2_RX:
 	case SLIMBUS_3_RX:
 	case INT_BT_SCO_RX:
 	case INT_BT_A2DP_RX:
@@ -166,6 +167,7 @@
 	case SLIMBUS_0_TX:
 	case SLIMBUS_1_TX:
 	case SLIMBUS_2_TX:
+	case SLIMBUS_3_TX:
 	case INT_FM_TX:
 	case VOICE_RECORD_RX:
 	case INT_BT_SCO_TX:
@@ -206,8 +208,10 @@
 	case SLIMBUS_0_TX:
 	case SLIMBUS_1_RX:
 	case SLIMBUS_1_TX:
+	case SLIMBUS_2_RX:
 	case SLIMBUS_2_TX:
 	case SLIMBUS_3_RX:
+	case SLIMBUS_3_TX:
 	case INT_BT_SCO_RX:
 	case INT_BT_SCO_TX:
 	case INT_BT_A2DP_RX:
@@ -272,8 +276,10 @@
 	case SLIMBUS_0_TX: return IDX_SLIMBUS_0_TX;
 	case SLIMBUS_1_RX: return IDX_SLIMBUS_1_RX;
 	case SLIMBUS_1_TX: return IDX_SLIMBUS_1_TX;
+	case SLIMBUS_2_RX: return IDX_SLIMBUS_2_RX;
 	case SLIMBUS_2_TX: return IDX_SLIMBUS_2_TX;
 	case SLIMBUS_3_RX: return IDX_SLIMBUS_3_RX;
+	case SLIMBUS_3_TX: return IDX_SLIMBUS_3_TX;
 	case INT_BT_SCO_RX: return IDX_INT_BT_SCO_RX;
 	case INT_BT_SCO_TX: return IDX_INT_BT_SCO_TX;
 	case INT_BT_A2DP_RX: return IDX_INT_BT_A2DP_RX;
@@ -307,8 +313,10 @@
 	case SLIMBUS_0_TX:
 	case SLIMBUS_1_RX:
 	case SLIMBUS_1_TX:
+	case SLIMBUS_2_RX:
 	case SLIMBUS_2_TX:
 	case SLIMBUS_3_RX:
+	case SLIMBUS_3_TX:
 	case SLIMBUS_4_RX:
 	case SLIMBUS_4_TX:
 		ret_size = SIZEOF_CFG_CMD(afe_port_slimbus_sch_cfg);
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index fc08febf..09bfd94 100644
--- a/sound/soc/msm/qdsp6/q6asm.c
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -526,6 +526,7 @@
 						pr_err("%s: ION create client"
 						" for AUDIO failed\n",
 						__func__);
+						mutex_unlock(&ac->cmd_lock);
 						goto fail;
 					}
 					buf[cnt].handle = ion_alloc
@@ -536,6 +537,7 @@
 						pr_err("%s: ION memory"
 					" allocation for AUDIO failed\n",
 							__func__);
+						mutex_unlock(&ac->cmd_lock);
 						goto fail;
 					}
 
@@ -548,6 +550,7 @@
 						pr_err("%s: ION Get Physical"
 						" for AUDIO failed, rc = %d\n",
 							__func__, rc);
+						mutex_unlock(&ac->cmd_lock);
 						goto fail;
 					}
 
@@ -558,6 +561,7 @@
 						buf[cnt].data)) {
 						pr_err("%s: ION memory"
 				" mapping for AUDIO failed\n", __func__);
+						mutex_unlock(&ac->cmd_lock);
 						goto fail;
 					}
 					memset((void *)buf[cnt].data, 0, bufsz);
@@ -661,6 +665,7 @@
 	buf[0].client = msm_ion_client_create(UINT_MAX, "audio_client");
 	if (IS_ERR_OR_NULL((void *)buf[0].client)) {
 		pr_err("%s: ION create client for AUDIO failed\n", __func__);
+		mutex_unlock(&ac->cmd_lock);
 		goto fail;
 	}
 	buf[0].handle = ion_alloc(buf[0].client, bufsz * bufcnt, SZ_4K,
@@ -668,6 +673,7 @@
 	if (IS_ERR_OR_NULL((void *) buf[0].handle)) {
 		pr_err("%s: ION memory allocation for AUDIO failed\n",
 			__func__);
+		mutex_unlock(&ac->cmd_lock);
 		goto fail;
 	}
 
@@ -676,12 +682,14 @@
 	if (rc) {
 		pr_err("%s: ION Get Physical for AUDIO failed, rc = %d\n",
 			__func__, rc);
+		mutex_unlock(&ac->cmd_lock);
 		goto fail;
 	}
 
 	buf[0].data = ion_map_kernel(buf[0].client, buf[0].handle, 0);
 	if (IS_ERR_OR_NULL((void *) buf[0].data)) {
 		pr_err("%s: ION memory mapping for AUDIO failed\n", __func__);
+		mutex_unlock(&ac->cmd_lock);
 		goto fail;
 	}
 	memset((void *)buf[0].data, 0, (bufsz * bufcnt));
diff --git a/sound/soc/msm/qdsp6/q6voice.c b/sound/soc/msm/qdsp6/q6voice.c
index 18a1f43..0c30dc9 100644
--- a/sound/soc/msm/qdsp6/q6voice.c
+++ b/sound/soc/msm/qdsp6/q6voice.c
@@ -3383,7 +3383,7 @@
 
 	mutex_lock(&v->lock);
 
-	if (v->voc_state == VOC_RUN) {
+	if (v->voc_state == VOC_RUN || v->voc_state == VOC_STANDBY) {
 		if (v->dev_tx.port_id != RT_PROXY_PORT_001_TX &&
 			v->dev_rx.port_id != RT_PROXY_PORT_001_RX)
 			afe_sidetone(v->dev_tx.port_id, v->dev_rx.port_id,
@@ -3399,6 +3399,51 @@
 	return ret;
 }
 
+int voc_resume_voice_call(uint16_t session_id)
+{
+	struct voice_data *v = voice_get_session(session_id);
+	struct apr_hdr mvm_start_voice_cmd;
+	int ret = 0;
+	void *apr_mvm;
+	u16 mvm_handle;
+
+	pr_debug("%s:\n", __func__);
+	if (v == NULL) {
+		pr_err("%s: v is NULL\n", __func__);
+		return -EINVAL;
+	}
+	apr_mvm = common.apr_q6_mvm;
+
+	if (!apr_mvm) {
+		pr_err("%s: apr_mvm is NULL.\n", __func__);
+		return -EINVAL;
+	}
+	mvm_handle = voice_get_mvm_handle(v);
+
+	mvm_start_voice_cmd.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+						APR_HDR_LEN(APR_HDR_SIZE),
+						APR_PKT_VER);
+	mvm_start_voice_cmd.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				sizeof(mvm_start_voice_cmd) - APR_HDR_SIZE);
+	pr_debug("send mvm_start_voice_cmd pkt size = %d\n",
+				mvm_start_voice_cmd.pkt_size);
+	mvm_start_voice_cmd.src_port = v->session_id;
+	mvm_start_voice_cmd.dest_port = mvm_handle;
+	mvm_start_voice_cmd.token = 0;
+	mvm_start_voice_cmd.opcode = VSS_IMVM_CMD_START_VOICE;
+
+	v->mvm_state = CMD_STATUS_FAIL;
+	ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_start_voice_cmd);
+	if (ret < 0) {
+		pr_err("Fail in sending VSS_IMVM_CMD_START_VOICE\n");
+		goto fail;
+	}
+	v->voc_state = VOC_RUN;
+	return 0;
+fail:
+	return -EINVAL;
+}
+
 int voc_start_voice_call(uint16_t session_id)
 {
 	struct voice_data *v = voice_get_session(session_id);
@@ -3452,11 +3497,62 @@
 		}
 
 		v->voc_state = VOC_RUN;
+	} else if (v->voc_state == VOC_STANDBY) {
+		pr_err("Error: PCM Prepare when in Standby\n");
+		ret = -EINVAL;
+		goto fail;
 	}
 fail:	mutex_unlock(&v->lock);
 	return ret;
 }
 
+int voc_standby_voice_call(uint16_t session_id)
+{
+	struct voice_data *v = voice_get_session(session_id);
+	struct apr_hdr mvm_standby_voice_cmd;
+	void *apr_mvm;
+	u16 mvm_handle;
+	int ret = 0;
+
+	pr_debug("%s: voc state=%d", __func__, v->voc_state);
+	if (v == NULL) {
+		pr_err("%s: v is NULL\n", __func__);
+		return -EINVAL;
+	}
+	if (v->voc_state == VOC_RUN) {
+		apr_mvm = common.apr_q6_mvm;
+		if (!apr_mvm) {
+			pr_err("%s: apr_mvm is NULL.\n", __func__);
+			ret = -EINVAL;
+			goto fail;
+		}
+		mvm_handle = voice_get_mvm_handle(v);
+		mvm_standby_voice_cmd.hdr_field =
+			APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+			APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+		mvm_standby_voice_cmd.pkt_size =
+			APR_PKT_SIZE(APR_HDR_SIZE,
+			sizeof(mvm_standby_voice_cmd) - APR_HDR_SIZE);
+		pr_debug("send mvm_standby_voice_cmd pkt size = %d\n",
+					mvm_standby_voice_cmd.pkt_size);
+		mvm_standby_voice_cmd.src_port = v->session_id;
+		mvm_standby_voice_cmd.dest_port = mvm_handle;
+		mvm_standby_voice_cmd.token = 0;
+		mvm_standby_voice_cmd.opcode = VSS_IMVM_CMD_STANDBY_VOICE;
+		v->mvm_state = CMD_STATUS_FAIL;
+		ret = apr_send_pkt(apr_mvm,
+				(uint32_t *)&mvm_standby_voice_cmd);
+		if (ret < 0) {
+			pr_err("Fail in sending VSS_IMVM_CMD_STANDBY_VOICE\n");
+			ret = -EINVAL;
+			goto fail;
+		}
+		v->voc_state = VOC_STANDBY;
+	}
+fail:
+	return ret;
+}
+
 void voc_register_mvs_cb(ul_cb_fn ul_cb,
 			   dl_cb_fn dl_cb,
 			   void *private_data)
@@ -3551,6 +3647,7 @@
 			case VSS_ICOMMON_CMD_SET_VOICE_TIMING:
 			case VSS_IWIDEVOICE_CMD_SET_WIDEVOICE:
 			case VSS_IMVM_CMD_SET_POLICY_DUAL_CONTROL:
+			case VSS_IMVM_CMD_STANDBY_VOICE:
 				pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
 				v->mvm_state = CMD_STATUS_SUCCESS;
 				wake_up(&v->mvm_wait);
diff --git a/sound/soc/msm/qdsp6/q6voice.h b/sound/soc/msm/qdsp6/q6voice.h
index cf691c0..88ab0d5 100644
--- a/sound/soc/msm/qdsp6/q6voice.h
+++ b/sound/soc/msm/qdsp6/q6voice.h
@@ -58,6 +58,7 @@
 	VOC_RUN,
 	VOC_CHANGE,
 	VOC_RELEASE,
+	VOC_STANDBY,
 };
 
 /* Common */
@@ -139,7 +140,14 @@
 */
 
 #define VSS_IMVM_CMD_START_VOICE			0x00011190
-/**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
+/*
+ * Start Voice call command.
+ * Wait for APRV2_IBASIC_RSP_RESULT response.
+ * No pay load.
+ */
+
+#define VSS_IMVM_CMD_STANDBY_VOICE	0x00011191
+/* No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
 
 #define VSS_IMVM_CMD_STOP_VOICE				0x00011192
 /**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
@@ -964,6 +972,8 @@
 uint8_t voc_get_tty_mode(uint16_t session_id);
 int voc_set_tty_mode(uint16_t session_id, uint8_t tty_mode);
 int voc_start_voice_call(uint16_t session_id);
+int voc_standby_voice_call(uint16_t session_id);
+int voc_resume_voice_call(uint16_t session_id);
 int voc_end_voice_call(uint16_t session_id);
 int voc_set_rxtx_port(uint16_t session_id,
 		      uint32_t dev_port_id,
diff --git a/sound/soc/msm/qdsp6v2/Makefile b/sound/soc/msm/qdsp6v2/Makefile
new file mode 100644
index 0000000..6f765d1
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/Makefile
@@ -0,0 +1,4 @@
+snd-soc-qdsp6v2-objs += msm-dai-q6-v2.o msm-pcm-q6-v2.o msm-pcm-routing-v2.o msm-compr-q6-v2.o  msm-multi-ch-pcm-q6-v2.o
+snd-soc-qdsp6v2-objs += msm-pcm-lpa-v2.o msm-pcm-afe-v2.o
+obj-$(CONFIG_SND_SOC_QDSP6V2) += snd-soc-qdsp6v2.o
+obj-y += q6adm.o q6afe.o q6asm.o q6audio-v2.o
diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
new file mode 100644
index 0000000..daba79d
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
@@ -0,0 +1,666 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <asm/dma.h>
+#include <linux/dma-mapping.h>
+#include <linux/android_pmem.h>
+
+#include "msm-compr-q6-v2.h"
+#include "msm-pcm-routing-v2.h"
+
+struct snd_msm {
+	struct msm_audio *prtd;
+	unsigned volume;
+};
+static struct snd_msm compressed_audio = {NULL, 0x2000} ;
+
+static struct audio_locks the_locks;
+
+static struct snd_pcm_hardware msm_compr_hardware_playback = {
+	.info =		 (SNDRV_PCM_INFO_MMAP |
+				SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				SNDRV_PCM_INFO_MMAP_VALID |
+				SNDRV_PCM_INFO_INTERLEAVED |
+				SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+	.formats =	      SNDRV_PCM_FMTBIT_S16_LE,
+	.rates =		SNDRV_PCM_RATE_8000_48000,
+	.rate_min =	     8000,
+	.rate_max =	     48000,
+	.channels_min =	 1,
+	.channels_max =	 2,
+	.buffer_bytes_max =     1200 * 1024 * 2,
+	.period_bytes_min =	4800,
+	.period_bytes_max =     1200 * 1024,
+	.periods_min =	  2,
+	.periods_max =	  512,
+	.fifo_size =	    0,
+};
+
+/* Conventional and unconventional sample rate supported */
+static unsigned int supported_sample_rates[] = {
+	8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+};
+
+static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
+	.count = ARRAY_SIZE(supported_sample_rates),
+	.list = supported_sample_rates,
+	.mask = 0,
+};
+
+static void compr_event_handler(uint32_t opcode,
+		uint32_t token, uint32_t *payload, void *priv)
+{
+	struct compr_audio *compr = priv;
+	struct msm_audio *prtd = &compr->prtd;
+	struct snd_pcm_substream *substream = prtd->substream;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct audio_aio_write_param param;
+	struct audio_buffer *buf = NULL;
+	int i = 0;
+
+	pr_debug("%s opcode =%08x\n", __func__, opcode);
+	switch (opcode) {
+	case ASM_DATA_EVENT_WRITE_DONE_V2: {
+		uint32_t *ptrmem = (uint32_t *)&param;
+		pr_debug("ASM_DATA_EVENT_WRITE_DONE\n");
+		pr_debug("Buffer Consumed = 0x%08x\n", *ptrmem);
+		prtd->pcm_irq_pos += prtd->pcm_count;
+		if (atomic_read(&prtd->start))
+			snd_pcm_period_elapsed(substream);
+		atomic_inc(&prtd->out_count);
+		wake_up(&the_locks.write_wait);
+		if (!atomic_read(&prtd->start)) {
+			atomic_set(&prtd->pending_buffer, 1);
+			break;
+		} else
+			atomic_set(&prtd->pending_buffer, 0);
+
+		if (runtime->status->hw_ptr >= runtime->control->appl_ptr)
+			break;
+		buf = prtd->audio_client->port[IN].buf;
+		pr_debug("%s:writing %d bytes of buffer[%d] to dsp 2\n",
+				__func__, prtd->pcm_count, prtd->out_head);
+		pr_debug("%s:writing buffer[%d] from 0x%08x\n",
+				__func__, prtd->out_head,
+				((unsigned int)buf[0].phys
+				+ (prtd->out_head * prtd->pcm_count)));
+
+		param.paddr = (unsigned long)buf[0].phys
+				+ (prtd->out_head * prtd->pcm_count);
+		param.len = prtd->pcm_count;
+		param.msw_ts = 0;
+		param.lsw_ts = 0;
+		param.flags = NO_TIMESTAMP;
+		param.uid =  (unsigned long)buf[0].phys
+				+ (prtd->out_head * prtd->pcm_count);
+		for (i = 0; i < sizeof(struct audio_aio_write_param)/4;
+					i++, ++ptrmem)
+			pr_debug("cmd[%d]=0x%08x\n", i, *ptrmem);
+		if (q6asm_async_write(prtd->audio_client,
+					&param) < 0)
+			pr_err("%s:q6asm_async_write failed\n",
+				__func__);
+		else
+			prtd->out_head =
+				(prtd->out_head + 1) & (runtime->periods - 1);
+		break;
+	}
+	case ASM_DATA_EVENT_RENDERED_EOS:
+		pr_debug("ASM_DATA_CMDRSP_EOS\n");
+		prtd->cmd_ack = 1;
+		wake_up(&the_locks.eos_wait);
+		break;
+	case APR_BASIC_RSP_RESULT: {
+		switch (payload[0]) {
+		case ASM_SESSION_CMD_RUN_V2: {
+			if (!atomic_read(&prtd->pending_buffer))
+				break;
+			pr_debug("%s:writing %d bytes"
+				" of buffer[%d] to dsp\n",
+				__func__, prtd->pcm_count, prtd->out_head);
+			buf = prtd->audio_client->port[IN].buf;
+			pr_debug("%s:writing buffer[%d] from 0x%08x\n",
+				__func__, prtd->out_head,
+				((unsigned int)buf[0].phys
+				+ (prtd->out_head * prtd->pcm_count)));
+			param.paddr = (unsigned long)buf[prtd->out_head].phys;
+			param.len = prtd->pcm_count;
+			param.msw_ts = 0;
+			param.lsw_ts = 0;
+			param.flags = NO_TIMESTAMP;
+			param.uid =  (unsigned long)buf[prtd->out_head].phys;
+			if (q6asm_async_write(prtd->audio_client,
+						&param) < 0)
+				pr_err("%s:q6asm_async_write failed\n",
+					__func__);
+			else
+				prtd->out_head =
+					(prtd->out_head + 1)
+					& (runtime->periods - 1);
+			atomic_set(&prtd->pending_buffer, 0);
+		}
+			break;
+		case ASM_STREAM_CMD_FLUSH:
+			pr_debug("ASM_STREAM_CMD_FLUSH\n");
+			prtd->cmd_ack = 1;
+			wake_up(&the_locks.eos_wait);
+			break;
+		default:
+			break;
+		}
+		break;
+	}
+	default:
+		pr_debug("Not Supported Event opcode[0x%x]\n", opcode);
+		break;
+	}
+}
+
+static int msm_compr_playback_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct compr_audio *compr = runtime->private_data;
+	struct msm_audio *prtd = &compr->prtd;
+	struct asm_aac_cfg aac_cfg;
+	int ret;
+
+	pr_debug("%s\n", __func__);
+	prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
+	prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
+	prtd->pcm_irq_pos = 0;
+	/* rate and channels are sent to audio driver */
+	prtd->samp_rate = runtime->rate;
+	prtd->channel_mode = runtime->channels;
+	prtd->out_head = 0;
+	atomic_set(&prtd->out_count, runtime->periods);
+
+	if (prtd->enabled)
+		return 0;
+
+	switch (compr->info.codec_param.codec.id) {
+	case SND_AUDIOCODEC_MP3:
+		/* No media format block for mp3 */
+		break;
+	case SND_AUDIOCODEC_AAC:
+		pr_debug("SND_AUDIOCODEC_AAC\n");
+		memset(&aac_cfg, 0x0, sizeof(struct asm_aac_cfg));
+		aac_cfg.aot = AAC_ENC_MODE_EAAC_P;
+		aac_cfg.format = 0x03;
+		aac_cfg.ch_cfg = runtime->channels;
+		aac_cfg.sample_rate =  runtime->rate;
+		ret = q6asm_media_format_block_aac(prtd->audio_client,
+					&aac_cfg);
+		if (ret < 0)
+			pr_err("%s: CMD Format block failed\n", __func__);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	prtd->enabled = 1;
+	prtd->cmd_ack = 0;
+
+	return 0;
+}
+
+static int msm_compr_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	int ret = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct compr_audio *compr = runtime->private_data;
+	struct msm_audio *prtd = &compr->prtd;
+
+	pr_debug("%s\n", __func__);
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		prtd->pcm_irq_pos = 0;
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		pr_debug("%s: Trigger start\n", __func__);
+		q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
+		atomic_set(&prtd->start, 1);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
+		atomic_set(&prtd->start, 0);
+		break;
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		pr_debug("SNDRV_PCM_TRIGGER_PAUSE\n");
+		q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
+		atomic_set(&prtd->start, 0);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static void populate_codec_list(struct compr_audio *compr,
+		struct snd_pcm_runtime *runtime)
+{
+	pr_debug("%s\n", __func__);
+	/* MP3 Block */
+	compr->info.compr_cap.num_codecs = 1;
+	compr->info.compr_cap.min_fragment_size = runtime->hw.period_bytes_min;
+	compr->info.compr_cap.max_fragment_size = runtime->hw.period_bytes_max;
+	compr->info.compr_cap.min_fragments = runtime->hw.periods_min;
+	compr->info.compr_cap.max_fragments = runtime->hw.periods_max;
+	compr->info.compr_cap.codecs[0] = SND_AUDIOCODEC_MP3;
+	compr->info.compr_cap.codecs[1] = SND_AUDIOCODEC_AAC;
+	/* Add new codecs here */
+}
+
+static int msm_compr_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+	struct compr_audio *compr;
+	struct msm_audio *prtd;
+	int ret = 0;
+	struct asm_softpause_params softpause = {
+		.enable = SOFT_PAUSE_ENABLE,
+		.period = SOFT_PAUSE_PERIOD,
+		.step = SOFT_PAUSE_STEP,
+		.rampingcurve = SOFT_PAUSE_CURVE_LINEAR,
+	};
+	struct asm_softvolume_params softvol = {
+		.period = SOFT_VOLUME_PERIOD,
+		.step = SOFT_VOLUME_STEP,
+		.rampingcurve = SOFT_VOLUME_CURVE_LINEAR,
+	};
+
+	/* Capture path */
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		return -EINVAL;
+
+	pr_debug("%s\n", __func__);
+	compr = kzalloc(sizeof(struct compr_audio), GFP_KERNEL);
+	if (compr == NULL) {
+		pr_err("Failed to allocate memory for msm_audio\n");
+		return -ENOMEM;
+	}
+	prtd = &compr->prtd;
+	prtd->substream = substream;
+	prtd->audio_client = q6asm_audio_client_alloc(
+				(app_cb)compr_event_handler, compr);
+	if (!prtd->audio_client) {
+		pr_info("%s: Could not allocate memory\n", __func__);
+		kfree(prtd);
+		return -ENOMEM;
+	}
+	runtime->hw = msm_compr_hardware_playback;
+
+	pr_info("%s: session ID %d\n", __func__, prtd->audio_client->session);
+
+	prtd->session_id = prtd->audio_client->session;
+	msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
+			prtd->session_id, substream->stream);
+
+	prtd->cmd_ack = 1;
+
+	ret = snd_pcm_hw_constraint_list(runtime, 0,
+			SNDRV_PCM_HW_PARAM_RATE,
+			&constraints_sample_rates);
+	if (ret < 0)
+		pr_info("snd_pcm_hw_constraint_list failed\n");
+	/* Ensure that buffer size is a multiple of period size */
+	ret = snd_pcm_hw_constraint_integer(runtime,
+			    SNDRV_PCM_HW_PARAM_PERIODS);
+	if (ret < 0)
+		pr_info("snd_pcm_hw_constraint_integer failed\n");
+
+	prtd->dsp_cnt = 0;
+	atomic_set(&prtd->pending_buffer, 1);
+	compr->codec = FORMAT_MP3;
+	populate_codec_list(compr, runtime);
+	runtime->private_data = compr;
+	compressed_audio.prtd =  &compr->prtd;
+	ret = compressed_set_volume(compressed_audio.volume);
+	if (ret < 0)
+		pr_err("%s : Set Volume failed : %d", __func__, ret);
+
+	ret = q6asm_set_softpause(compressed_audio.prtd->audio_client,
+								&softpause);
+	if (ret < 0)
+		pr_err("%s: Send SoftPause Param failed ret=%d\n",
+			__func__, ret);
+	ret = q6asm_set_softvolume(compressed_audio.prtd->audio_client,
+								&softvol);
+	if (ret < 0)
+		pr_err("%s: Send SoftVolume Param failed ret=%d\n",
+			__func__, ret);
+
+	return 0;
+}
+
+int compressed_set_volume(unsigned volume)
+{
+	int rc = 0;
+	if (compressed_audio.prtd && compressed_audio.prtd->audio_client) {
+		rc = q6asm_set_volume(compressed_audio.prtd->audio_client,
+								 volume);
+		if (rc < 0) {
+			pr_err("%s: Send Volume command failed"
+					" rc=%d\n", __func__, rc);
+		}
+	}
+	compressed_audio.volume = volume;
+	return rc;
+}
+
+static int msm_compr_playback_close(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+	struct compr_audio *compr = runtime->private_data;
+	struct msm_audio *prtd = &compr->prtd;
+	int dir = 0;
+
+	pr_debug("%s\n", __func__);
+
+	dir = IN;
+	atomic_set(&prtd->pending_buffer, 0);
+	q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+	compressed_audio.prtd = NULL;
+	q6asm_audio_client_buf_free_contiguous(dir,
+				prtd->audio_client);
+
+	msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
+	SNDRV_PCM_STREAM_PLAYBACK);
+	q6asm_audio_client_free(prtd->audio_client);
+	kfree(prtd);
+	return 0;
+}
+
+static int msm_compr_close(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = msm_compr_playback_close(substream);
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		ret = EINVAL;
+	return ret;
+}
+static int msm_compr_prepare(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = msm_compr_playback_prepare(substream);
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		ret = EINVAL;
+	return ret;
+}
+
+static snd_pcm_uframes_t msm_compr_pointer(struct snd_pcm_substream *substream)
+{
+
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct compr_audio *compr = runtime->private_data;
+	struct msm_audio *prtd = &compr->prtd;
+
+	if (prtd->pcm_irq_pos >= prtd->pcm_size)
+		prtd->pcm_irq_pos = 0;
+
+	pr_debug("pcm_irq_pos = %d\n", prtd->pcm_irq_pos);
+	return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
+}
+
+static int msm_compr_mmap(struct snd_pcm_substream *substream,
+				struct vm_area_struct *vma)
+{
+	int result = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct compr_audio *compr = runtime->private_data;
+	struct msm_audio *prtd = &compr->prtd;
+
+	pr_debug("%s\n", __func__);
+	prtd->mmap_flag = 1;
+	if (runtime->dma_addr && runtime->dma_bytes) {
+		vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+		result = remap_pfn_range(vma, vma->vm_start,
+				runtime->dma_addr >> PAGE_SHIFT,
+				runtime->dma_bytes,
+				vma->vm_page_prot);
+	} else {
+		pr_err("Physical address or size of buf is NULL");
+		return -EINVAL;
+	}
+	return result;
+}
+
+static int msm_compr_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct compr_audio *compr = runtime->private_data;
+	struct msm_audio *prtd = &compr->prtd;
+	struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
+	struct audio_buffer *buf;
+	int dir, ret;
+
+	pr_debug("%s\n", __func__);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		dir = IN;
+	else
+		return -EINVAL;
+
+	ret = q6asm_open_write(prtd->audio_client, compr->codec);
+	if (ret < 0) {
+		pr_err("%s: Session out open failed\n", __func__);
+		return -ENOMEM;
+	}
+	ret = q6asm_set_io_mode(prtd->audio_client, ASYNC_IO_MODE);
+	if (ret < 0) {
+		pr_err("%s: Set IO mode failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	ret = q6asm_audio_client_buf_alloc_contiguous(dir,
+			prtd->audio_client,
+			runtime->hw.period_bytes_min,
+			runtime->hw.periods_max);
+	if (ret < 0) {
+		pr_err("Audio Start: Buffer Allocation failed "
+					"rc = %d\n", ret);
+		return -ENOMEM;
+	}
+	buf = prtd->audio_client->port[dir].buf;
+
+	pr_debug("%s:buf = %p\n", __func__, buf);
+	dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
+	dma_buf->dev.dev = substream->pcm->card->dev;
+	dma_buf->private_data = NULL;
+	dma_buf->area = buf[0].data;
+	dma_buf->addr =  buf[0].phys;
+	dma_buf->bytes = runtime->hw.buffer_bytes_max;
+	if (!dma_buf->area)
+		return -ENOMEM;
+
+	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+	return 0;
+}
+
+static int msm_compr_ioctl(struct snd_pcm_substream *substream,
+		unsigned int cmd, void *arg)
+{
+	int rc = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct compr_audio *compr = runtime->private_data;
+	struct msm_audio *prtd = &compr->prtd;
+	uint64_t timestamp;
+	uint64_t temp;
+
+	switch (cmd) {
+	case SNDRV_COMPRESS_TSTAMP: {
+		struct snd_compr_tstamp tstamp;
+		pr_debug("SNDRV_COMPRESS_TSTAMP\n");
+
+		memset(&tstamp, 0x0, sizeof(struct snd_compr_tstamp));
+		timestamp = q6asm_get_session_time(prtd->audio_client);
+		if (timestamp < 0) {
+			pr_err("%s: Get Session Time return value =%lld\n",
+				__func__, timestamp);
+			return -EAGAIN;
+		}
+		temp = (timestamp * 2 * runtime->channels);
+		temp = temp * (runtime->rate/1000);
+		temp = div_u64(temp, 1000);
+		tstamp.sampling_rate = runtime->rate;
+		tstamp.rendered = (size_t)(temp & 0xFFFFFFFF);
+		tstamp.decoded  = (size_t)((temp >> 32) & 0xFFFFFFFF);
+		tstamp.timestamp = timestamp;
+		pr_debug("%s: bytes_consumed:lsb = %d, msb = %d,"
+			"timestamp = %lld,\n",
+			 __func__, tstamp.rendered, tstamp.decoded,
+			tstamp.timestamp);
+		if (copy_to_user((void *) arg, &tstamp,
+			sizeof(struct snd_compr_tstamp)))
+				return -EFAULT;
+		return 0;
+	}
+	case SNDRV_COMPRESS_GET_CAPS:
+		pr_debug("SNDRV_COMPRESS_GET_CAPS\n");
+		if (copy_to_user((void *) arg, &compr->info.compr_cap,
+			sizeof(struct snd_compr_caps))) {
+			rc = -EFAULT;
+			pr_err("%s: ERROR: copy to user\n", __func__);
+			return rc;
+		}
+		return 0;
+	case SNDRV_COMPRESS_SET_PARAMS:
+		pr_debug("SNDRV_COMPRESS_SET_PARAMS: ");
+		if (copy_from_user(&compr->info.codec_param, (void *) arg,
+			sizeof(struct snd_compr_params))) {
+			rc = -EFAULT;
+			pr_err("%s: ERROR: copy from user\n", __func__);
+			return rc;
+		}
+		switch (compr->info.codec_param.codec.id) {
+		case SND_AUDIOCODEC_MP3:
+			/* For MP3 we dont need any other parameter */
+			pr_debug("SND_AUDIOCODEC_MP3\n");
+			compr->codec = FORMAT_MP3;
+			break;
+		case SND_AUDIOCODEC_AAC:
+			pr_debug("SND_AUDIOCODEC_AAC\n");
+			compr->codec = FORMAT_MPEG4_AAC;
+			break;
+		default:
+			pr_debug("FORMAT_LINEAR_PCM\n");
+			compr->codec = FORMAT_LINEAR_PCM;
+			break;
+		}
+		return 0;
+	case SNDRV_PCM_IOCTL1_RESET:
+		prtd->cmd_ack = 0;
+		rc = q6asm_cmd(prtd->audio_client, CMD_FLUSH);
+		if (rc < 0)
+			pr_err("%s: flush cmd failed rc=%d\n", __func__, rc);
+		rc = wait_event_timeout(the_locks.eos_wait,
+			prtd->cmd_ack, 5 * HZ);
+		if (rc < 0)
+			pr_err("Flush cmd timeout\n");
+		prtd->pcm_irq_pos = 0;
+		break;
+	default:
+		break;
+	}
+	return snd_pcm_lib_ioctl(substream, cmd, arg);
+}
+
+static struct snd_pcm_ops msm_compr_ops = {
+	.open	   = msm_compr_open,
+	.hw_params	= msm_compr_hw_params,
+	.close	  = msm_compr_close,
+	.ioctl	  = msm_compr_ioctl,
+	.prepare	= msm_compr_prepare,
+	.trigger	= msm_compr_trigger,
+	.pointer	= msm_compr_pointer,
+	.mmap		= msm_compr_mmap,
+};
+
+static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_card *card = rtd->card->snd_card;
+	int ret = 0;
+
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+	return ret;
+}
+
+static struct snd_soc_platform_driver msm_soc_platform = {
+	.ops		= &msm_compr_ops,
+	.pcm_new	= msm_asoc_pcm_new,
+};
+
+static __devinit int msm_compr_probe(struct platform_device *pdev)
+{
+	pr_info("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
+	return snd_soc_register_platform(&pdev->dev,
+				   &msm_soc_platform);
+}
+
+static int msm_compr_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_platform(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver msm_compr_driver = {
+	.driver = {
+		.name = "msm-compr-dsp",
+		.owner = THIS_MODULE,
+	},
+	.probe = msm_compr_probe,
+	.remove = __devexit_p(msm_compr_remove),
+};
+
+static int __init msm_soc_platform_init(void)
+{
+	init_waitqueue_head(&the_locks.enable_wait);
+	init_waitqueue_head(&the_locks.eos_wait);
+	init_waitqueue_head(&the_locks.write_wait);
+	init_waitqueue_head(&the_locks.read_wait);
+
+	return platform_driver_register(&msm_compr_driver);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+	platform_driver_unregister(&msm_compr_driver);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("PCM module platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.h b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.h
new file mode 100644
index 0000000..2183690
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _MSM_COMPR_H
+#define _MSM_COMPR_H
+#include <sound/apr_audio-v2.h>
+#include <sound/q6asm-v2.h>
+#include <sound/snd_compress_params.h>
+#include <sound/compress_offload.h>
+#include <sound/compress_driver.h>
+
+#include "msm-pcm-q6-v2.h"
+
+struct compr_info {
+	struct snd_compr_caps compr_cap;
+	struct snd_compr_codec_caps codec_caps;
+	struct snd_compr_params codec_param;
+};
+
+struct compr_audio {
+	struct msm_audio prtd;
+	struct compr_info info;
+	uint32_t codec;
+};
+
+#endif /*_MSM_COMPR_H*/
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
new file mode 100644
index 0000000..1605062
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -0,0 +1,1229 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/wcd9xxx/core.h>
+#include <linux/bitops.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/apr_audio-v2.h>
+#include <sound/q6afe-v2.h>
+#include <sound/msm-dai-q6-v2.h>
+#include <sound/pcm_params.h>
+#include <mach/clk.h>
+
+enum {
+	STATUS_PORT_STARTED, /* track if AFE port has started */
+	STATUS_MAX
+};
+
+struct msm_dai_q6_dai_data {
+	DECLARE_BITMAP(status_mask, STATUS_MAX);
+	u32 rate;
+	u32 channels;
+	union afe_port_config port_config;
+};
+
+static struct clk *pcm_clk;
+static DEFINE_MUTEX(aux_pcm_mutex);
+static int aux_pcm_count;
+static struct msm_dai_auxpcm_pdata *auxpcm_plat_data;
+
+static u8 num_of_bits_set(u8 sd_line_mask)
+{
+	u8 num_bits_set = 0;
+
+	while (sd_line_mask) {
+		num_bits_set++;
+		sd_line_mask = sd_line_mask & (sd_line_mask - 1);
+	}
+	return num_bits_set;
+}
+
+static int msm_dai_q6_cdc_hw_params(struct snd_pcm_hw_params *params,
+				    struct snd_soc_dai *dai, int stream)
+{
+	struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
+
+	dai_data->channels = params_channels(params);
+	switch (dai_data->channels) {
+	case 2:
+		dai_data->port_config.i2s.mono_stereo = MSM_AFE_STEREO;
+		break;
+	case 1:
+		dai_data->port_config.i2s.mono_stereo = MSM_AFE_MONO;
+		break;
+	default:
+		return -EINVAL;
+		break;
+	}
+	dai_data->rate = params_rate(params);
+	dai_data->port_config.i2s.sample_rate = dai_data->rate;
+	dai_data->port_config.i2s.i2s_cfg_minor_version =
+						AFE_API_VERSION_I2S_CONFIG;
+	dai_data->port_config.i2s.data_format =  AFE_LINEAR_PCM_DATA;
+	dev_dbg(dai->dev, " channel %d sample rate %d entered\n",
+	dai_data->channels, dai_data->rate);
+
+	/* Q6 only supports 16 as now */
+	dai_data->port_config.i2s.bit_width = 16;
+	dai_data->port_config.i2s.channel_mode = 1;
+	return 0;
+}
+
+static int msm_dai_q6_i2s_hw_params(struct snd_pcm_hw_params *params,
+				    struct snd_soc_dai *dai, int stream)
+{
+	struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
+	struct msm_i2s_data *i2s_pdata =
+			(struct msm_i2s_data *) dai->dev->platform_data;
+
+	dai_data->channels = params_channels(params);
+	if (num_of_bits_set(i2s_pdata->sd_lines) == 1) {
+		switch (dai_data->channels) {
+		case 2:
+			dai_data->port_config.i2s.mono_stereo = MSM_AFE_STEREO;
+			break;
+		case 1:
+			dai_data->port_config.i2s.mono_stereo = MSM_AFE_MONO;
+			break;
+		default:
+			pr_warn("greater than stereo has not been validated");
+			break;
+		}
+	}
+	dai_data->rate = params_rate(params);
+	dai_data->port_config.i2s.sample_rate = dai_data->rate;
+	dai_data->port_config.i2s.i2s_cfg_minor_version =
+						AFE_API_VERSION_I2S_CONFIG;
+	dai_data->port_config.i2s.data_format =  AFE_LINEAR_PCM_DATA;
+	/* Q6 only supports 16 as now */
+	dai_data->port_config.i2s.bit_width = 16;
+	dai_data->port_config.i2s.channel_mode = 1;
+
+	return 0;
+}
+
+static int msm_dai_q6_i2s_platform_data_validation(
+					struct snd_soc_dai *dai)
+{
+	u8 num_of_sd_lines;
+	struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
+	struct msm_i2s_data *i2s_pdata =
+			(struct msm_i2s_data *)dai->dev->platform_data;
+	struct snd_soc_dai_driver *dai_driver =
+			(struct snd_soc_dai_driver *)dai->driver;
+
+	num_of_sd_lines = num_of_bits_set(i2s_pdata->sd_lines);
+
+	switch (num_of_sd_lines) {
+	case 1:
+		switch (i2s_pdata->sd_lines) {
+		case MSM_MI2S_SD0:
+			dai_data->port_config.i2s.channel_mode =
+					AFE_PORT_I2S_SD0;
+			break;
+		case MSM_MI2S_SD1:
+			dai_data->port_config.i2s.channel_mode =
+					AFE_PORT_I2S_SD1;
+			break;
+		case MSM_MI2S_SD2:
+			dai_data->port_config.i2s.channel_mode =
+					AFE_PORT_I2S_SD2;
+			break;
+		case MSM_MI2S_SD3:
+			dai_data->port_config.i2s.channel_mode =
+					AFE_PORT_I2S_SD3;
+			break;
+		default:
+			pr_err("%s: invalid SD line\n",
+				   __func__);
+			goto error_invalid_data;
+		}
+		break;
+	case 2:
+		switch (i2s_pdata->sd_lines) {
+		case MSM_MI2S_SD0 | MSM_MI2S_SD1:
+			dai_data->port_config.i2s.channel_mode =
+					AFE_PORT_I2S_QUAD01;
+			break;
+		case MSM_MI2S_SD2 | MSM_MI2S_SD3:
+			dai_data->port_config.i2s.channel_mode =
+					AFE_PORT_I2S_QUAD23;
+			break;
+		default:
+			pr_err("%s: invalid SD line\n",
+				   __func__);
+			goto error_invalid_data;
+		}
+		break;
+	case 3:
+		switch (i2s_pdata->sd_lines) {
+		case MSM_MI2S_SD0 | MSM_MI2S_SD1 | MSM_MI2S_SD2:
+			dai_data->port_config.i2s.channel_mode =
+					AFE_PORT_I2S_6CHS;
+			break;
+		default:
+			pr_err("%s: invalid SD lines\n",
+				   __func__);
+			goto error_invalid_data;
+		}
+		break;
+	case 4:
+		switch (i2s_pdata->sd_lines) {
+		case MSM_MI2S_SD0 | MSM_MI2S_SD1 | MSM_MI2S_SD2 | MSM_MI2S_SD3:
+			dai_data->port_config.i2s.channel_mode =
+					AFE_PORT_I2S_8CHS;
+			break;
+		default:
+			pr_err("%s: invalid SD lines\n",
+				   __func__);
+			goto error_invalid_data;
+		}
+		break;
+	default:
+		pr_err("%s: invalid SD lines\n", __func__);
+		goto error_invalid_data;
+	}
+	if (i2s_pdata->capability == MSM_MI2S_CAP_RX)
+		dai_driver->playback.channels_max = num_of_sd_lines << 1;
+
+	return 0;
+
+error_invalid_data:
+	return -EINVAL;
+}
+
+static int msm_dai_q6_cdc_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		dai_data->port_config.i2s.ws_src = 1; /* CPU is master */
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		dai_data->port_config.i2s.ws_src = 0; /* CPU is slave */
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+
+static int msm_dai_q6_slim_bus_hw_params(struct snd_pcm_hw_params *params,
+				    struct snd_soc_dai *dai, int stream)
+{
+	struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
+
+	dai_data->channels = params_channels(params);
+	dai_data->rate = params_rate(params);
+
+	/* Q6 only supports 16 as now */
+	dai_data->port_config.slim_sch.sb_cfg_minor_version =
+				AFE_API_VERSION_SLIMBUS_CONFIG;
+	dai_data->port_config.slim_sch.bit_width = 16;
+	dai_data->port_config.slim_sch.data_format = 0;
+	dai_data->port_config.slim_sch.num_channels = dai_data->channels;
+	dai_data->port_config.slim_sch.sample_rate = dai_data->rate;
+
+	dev_dbg(dai->dev, "%s:slimbus_dev_id[%hu] bit_wd[%hu] format[%hu]\n"
+		"num_channel %hu  shared_ch_mapping[0]  %hu\n"
+		"slave_port_mapping[1]  %hu slave_port_mapping[2]  %hu\n"
+		"sample_rate %d\n", __func__,
+		dai_data->port_config.slim_sch.slimbus_dev_id,
+		dai_data->port_config.slim_sch.bit_width,
+		dai_data->port_config.slim_sch.data_format,
+		dai_data->port_config.slim_sch.num_channels,
+		dai_data->port_config.slim_sch.shared_ch_mapping[0],
+		dai_data->port_config.slim_sch.shared_ch_mapping[1],
+		dai_data->port_config.slim_sch.shared_ch_mapping[2],
+		dai_data->rate);
+
+	return 0;
+}
+
+static int msm_dai_q6_bt_fm_hw_params(struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai, int stream)
+{
+	struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
+
+	dai_data->channels = params_channels(params);
+	dai_data->rate = params_rate(params);
+
+	dev_dbg(dai->dev, "channels %d sample rate %d entered\n",
+		dai_data->channels, dai_data->rate);
+
+	memset(&dai_data->port_config, 0, sizeof(dai_data->port_config));
+
+	return 0;
+}
+static int msm_dai_q6_auxpcm_hw_params(
+				struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
+	struct msm_dai_auxpcm_pdata *auxpcm_pdata =
+			(struct msm_dai_auxpcm_pdata *) dai->dev->platform_data;
+
+	if (params_channels(params) != 1) {
+		dev_err(dai->dev, "AUX PCM supports only mono stream\n");
+		return -EINVAL;
+	}
+	dai_data->channels = params_channels(params);
+
+	if (params_rate(params) != 8000) {
+		dev_err(dai->dev, "AUX PCM supports only 8KHz sampling rate\n");
+		return -EINVAL;
+	}
+	dai_data->rate = params_rate(params);
+
+	dai_data->port_config.pcm.pcm_cfg_minor_version =
+				AFE_API_VERSION_PCM_CONFIG;
+	dai_data->port_config.pcm.aux_mode = auxpcm_pdata->mode;
+	dai_data->port_config.pcm.sync_src = auxpcm_pdata->sync;
+	dai_data->port_config.pcm.frame_setting = auxpcm_pdata->frame;
+	dai_data->port_config.pcm.quantype = auxpcm_pdata->quant;
+	dai_data->port_config.pcm.ctrl_data_out_enable = auxpcm_pdata->data;
+	dai_data->port_config.pcm.sample_rate = dai_data->rate;
+	dai_data->port_config.pcm.num_channels = dai_data->channels;
+	dai_data->port_config.pcm.bit_width = 16;
+	dai_data->port_config.pcm.slot_number_mapping[0] = auxpcm_pdata->slot;
+
+	return 0;
+}
+
+static int msm_dai_q6_afe_rtproxy_hw_params(struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
+
+	dai_data->rate = params_rate(params);
+	dai_data->port_config.rtproxy.num_channels = params_channels(params);
+	dai_data->port_config.rtproxy.sample_rate = params_rate(params);
+
+	pr_debug("channel %d entered,dai_id: %d,rate: %d\n",
+	dai_data->port_config.rtproxy.num_channels, dai->id, dai_data->rate);
+
+	dai_data->port_config.rtproxy.rt_proxy_cfg_minor_version =
+				AFE_API_VERSION_RT_PROXY_CONFIG;
+	dai_data->port_config.rtproxy.bit_width = 16; /* Q6 only supports 16 */
+	dai_data->port_config.rtproxy.interleaved = 1;
+	dai_data->port_config.rtproxy.frame_size = params_period_bytes(params);
+	dai_data->port_config.rtproxy.jitter_allowance =
+				dai_data->port_config.rtproxy.frame_size/2;
+	dai_data->port_config.rtproxy.low_water_mark = 0;
+	dai_data->port_config.rtproxy.high_water_mark = 0;
+
+	return 0;
+}
+
+/* Current implementation assumes hw_param is called once
+ * This may not be the case but what to do when ADM and AFE
+ * port are already opened and parameter changes
+ */
+static int msm_dai_q6_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	int rc = 0;
+
+	switch (dai->id) {
+	case PRIMARY_I2S_TX:
+	case PRIMARY_I2S_RX:
+	case SECONDARY_I2S_RX:
+		rc = msm_dai_q6_cdc_hw_params(params, dai, substream->stream);
+		break;
+	case MI2S_RX:
+		rc = msm_dai_q6_i2s_hw_params(params, dai, substream->stream);
+		break;
+	case SLIMBUS_0_RX:
+	case SLIMBUS_1_RX:
+	case SLIMBUS_0_TX:
+	case SLIMBUS_1_TX:
+		rc = msm_dai_q6_slim_bus_hw_params(params, dai,
+				substream->stream);
+		break;
+	case INT_BT_SCO_RX:
+	case INT_BT_SCO_TX:
+	case INT_FM_RX:
+	case INT_FM_TX:
+		rc = msm_dai_q6_bt_fm_hw_params(params, dai, substream->stream);
+		break;
+	case RT_PROXY_DAI_001_TX:
+	case RT_PROXY_DAI_001_RX:
+	case RT_PROXY_DAI_002_TX:
+	case RT_PROXY_DAI_002_RX:
+		rc = msm_dai_q6_afe_rtproxy_hw_params(params, dai);
+		break;
+	case VOICE_PLAYBACK_TX:
+	case VOICE_RECORD_RX:
+	case VOICE_RECORD_TX:
+		rc = 0;
+		break;
+	default:
+		dev_err(dai->dev, "invalid AFE port ID\n");
+		rc = -EINVAL;
+		break;
+	}
+
+	return rc;
+}
+
+static void msm_dai_q6_auxpcm_shutdown(struct snd_pcm_substream *substream,
+				struct snd_soc_dai *dai)
+{
+	int rc = 0;
+
+	mutex_lock(&aux_pcm_mutex);
+
+	if (aux_pcm_count == 0) {
+		dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count is 0. Just"
+				" return\n", __func__, dai->id);
+		mutex_unlock(&aux_pcm_mutex);
+		return;
+	}
+
+	aux_pcm_count--;
+
+	if (aux_pcm_count > 0) {
+		dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d\n",
+			__func__, dai->id, aux_pcm_count);
+		mutex_unlock(&aux_pcm_mutex);
+		return;
+	} else if (aux_pcm_count < 0) {
+		dev_err(dai->dev, "%s(): ERROR: dai->id %d"
+			" aux_pcm_count = %d < 0\n",
+			__func__, dai->id, aux_pcm_count);
+		aux_pcm_count = 0;
+		mutex_unlock(&aux_pcm_mutex);
+		return;
+	}
+
+	pr_debug("%s: dai->id = %d aux_pcm_count = %d\n", __func__,
+			dai->id, aux_pcm_count);
+
+	rc = afe_close(PCM_RX); /* can block */
+	if (IS_ERR_VALUE(rc))
+		dev_err(dai->dev, "fail to close PCM_RX  AFE port\n");
+
+	rc = afe_close(PCM_TX);
+	if (IS_ERR_VALUE(rc))
+		dev_err(dai->dev, "fail to close AUX PCM TX port\n");
+
+	mutex_unlock(&aux_pcm_mutex);
+}
+
+static void msm_dai_q6_shutdown(struct snd_pcm_substream *substream,
+				struct snd_soc_dai *dai)
+{
+	struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
+	int rc = 0;
+
+	if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
+		switch (dai->id) {
+		case VOICE_PLAYBACK_TX:
+		case VOICE_RECORD_TX:
+		case VOICE_RECORD_RX:
+			pr_debug("%s, stop pseudo port:%d\n",
+						__func__,  dai->id);
+			rc = afe_stop_pseudo_port(dai->id);
+			break;
+		default:
+			rc = afe_close(dai->id); /* can block */
+			break;
+		}
+		if (IS_ERR_VALUE(rc))
+			dev_err(dai->dev, "fail to close AFE port\n");
+		pr_debug("%s: dai_data->status_mask = %ld\n", __func__,
+			*dai_data->status_mask);
+		clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
+	}
+}
+
+static int msm_dai_q6_auxpcm_prepare(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+	struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
+	int rc = 0;
+
+	mutex_lock(&aux_pcm_mutex);
+
+	if (aux_pcm_count == 2) {
+		dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count is 2. Just"
+			" return.\n", __func__, dai->id);
+		mutex_unlock(&aux_pcm_mutex);
+		return 0;
+	} else if (aux_pcm_count > 2) {
+		dev_err(dai->dev, "%s(): ERROR: dai->id %d"
+			" aux_pcm_count = %d > 2\n",
+			__func__, dai->id, aux_pcm_count);
+		mutex_unlock(&aux_pcm_mutex);
+		return 0;
+	}
+
+	aux_pcm_count++;
+	if (aux_pcm_count == 2)  {
+		dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d after "
+			" increment\n", __func__, dai->id, aux_pcm_count);
+		mutex_unlock(&aux_pcm_mutex);
+		return 0;
+	}
+
+	pr_debug("%s:dai->id:%d  aux_pcm_count = %d. opening afe\n",
+			__func__, dai->id, aux_pcm_count);
+
+	rc = afe_q6_interface_prepare();
+	if (IS_ERR_VALUE(rc))
+		dev_err(dai->dev, "fail to open AFE APR\n");
+
+	/*
+	 * For AUX PCM Interface the below sequence of clk
+	 * settings and afe_open is a strict requirement.
+	 *
+	 * Also using afe_open instead of afe_port_start_nowait
+	 * to make sure the port is open before deasserting the
+	 * clock line. This is required because pcm register is
+	 * not written before clock deassert. Hence the hw does
+	 * not get updated with new setting if the below clock
+	 * assert/deasset and afe_open sequence is not followed.
+	 */
+
+	afe_open(PCM_RX, &dai_data->port_config, dai_data->rate);
+
+	afe_open(PCM_TX, &dai_data->port_config, dai_data->rate);
+
+	mutex_unlock(&aux_pcm_mutex);
+
+	return rc;
+}
+
+static int msm_dai_q6_prepare(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+	struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
+	int rc = 0;
+
+	if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
+		/* PORT START should be set if prepare called in active state */
+		rc = afe_q6_interface_prepare();
+		if (IS_ERR_VALUE(rc))
+			dev_err(dai->dev, "fail to open AFE APR\n");
+	}
+	return rc;
+}
+
+static int msm_dai_q6_auxpcm_trigger(struct snd_pcm_substream *substream,
+		int cmd, struct snd_soc_dai *dai)
+{
+	int rc = 0;
+
+	pr_debug("%s:port:%d  cmd:%d  aux_pcm_count= %d",
+		__func__, dai->id, cmd, aux_pcm_count);
+
+	switch (cmd) {
+
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		/* afe_open will be called from prepare */
+		return 0;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		return 0;
+
+	default:
+		rc = -EINVAL;
+	}
+
+	return rc;
+
+}
+
+static int msm_dai_q6_trigger(struct snd_pcm_substream *substream, int cmd,
+		struct snd_soc_dai *dai)
+{
+	struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
+	int rc = 0;
+
+	/* Start/stop port without waiting for Q6 AFE response. Need to have
+	 * native q6 AFE driver propagates AFE response in order to handle
+	 * port start/stop command error properly if error does arise.
+	 */
+	pr_debug("%s:port:%d  cmd:%d dai_data->status_mask = %ld",
+		__func__, dai->id, cmd, *dai_data->status_mask);
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
+			switch (dai->id) {
+			case VOICE_PLAYBACK_TX:
+			case VOICE_RECORD_TX:
+			case VOICE_RECORD_RX:
+				afe_pseudo_port_start_nowait(dai->id);
+				break;
+			default:
+				afe_port_start_nowait(dai->id,
+					&dai_data->port_config, dai_data->rate);
+				break;
+			}
+			set_bit(STATUS_PORT_STARTED,
+				dai_data->status_mask);
+		}
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
+			switch (dai->id) {
+			case VOICE_PLAYBACK_TX:
+			case VOICE_RECORD_TX:
+			case VOICE_RECORD_RX:
+				afe_pseudo_port_stop_nowait(dai->id);
+				break;
+			default:
+				afe_port_stop_nowait(dai->id);
+				break;
+			}
+			clear_bit(STATUS_PORT_STARTED,
+				dai_data->status_mask);
+		}
+		break;
+
+	default:
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
+static int msm_dai_q6_dai_auxpcm_probe(struct snd_soc_dai *dai)
+{
+	struct msm_dai_q6_dai_data *dai_data;
+	int rc = 0;
+
+	struct msm_dai_auxpcm_pdata *auxpcm_pdata =
+			(struct msm_dai_auxpcm_pdata *) dai->dev->platform_data;
+
+	mutex_lock(&aux_pcm_mutex);
+
+	if (!auxpcm_plat_data)
+		auxpcm_plat_data = auxpcm_pdata;
+	else if (auxpcm_plat_data != auxpcm_pdata) {
+
+		dev_err(dai->dev, "AUX PCM RX and TX devices does not have"
+				" same platform data\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * The clk name for AUX PCM operation is passed as platform
+	 * data to the cpu driver, since cpu drive is unaware of any
+	 * boarc specific configuration.
+	 */
+	if (!pcm_clk)
+		pcm_clk = clk_get(dai->dev, auxpcm_pdata->clk);
+
+	mutex_unlock(&aux_pcm_mutex);
+
+	dai_data = kzalloc(sizeof(struct msm_dai_q6_dai_data), GFP_KERNEL);
+
+	if (!dai_data) {
+		dev_err(dai->dev, "DAI-%d: fail to allocate dai data\n",
+		dai->id);
+		rc = -ENOMEM;
+	} else
+		dev_set_drvdata(dai->dev, dai_data);
+
+	pr_err("%s : probe done for dai->id %d\n", __func__, dai->id);
+	return rc;
+}
+
+static int msm_dai_q6_dai_auxpcm_remove(struct snd_soc_dai *dai)
+{
+	struct msm_dai_q6_dai_data *dai_data;
+	int rc;
+
+	dai_data = dev_get_drvdata(dai->dev);
+
+	mutex_lock(&aux_pcm_mutex);
+
+	if (aux_pcm_count == 0) {
+		dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count is 0. clean"
+				" up and return\n", __func__, dai->id);
+		goto done;
+	}
+
+	aux_pcm_count--;
+
+	if (aux_pcm_count > 0) {
+		dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d\n",
+			__func__, dai->id, aux_pcm_count);
+		goto done;
+	} else if (aux_pcm_count < 0) {
+		dev_err(dai->dev, "%s(): ERROR: dai->id %d"
+			" aux_pcm_count = %d < 0\n",
+			__func__, dai->id, aux_pcm_count);
+		goto done;
+	}
+
+	dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d."
+			"closing afe\n",
+		__func__, dai->id, aux_pcm_count);
+
+	rc = afe_close(PCM_RX); /* can block */
+	if (IS_ERR_VALUE(rc))
+		dev_err(dai->dev, "fail to close AUX PCM RX AFE port\n");
+
+	rc = afe_close(PCM_TX);
+	if (IS_ERR_VALUE(rc))
+		dev_err(dai->dev, "fail to close AUX PCM TX AFE port\n");
+
+done:
+	kfree(dai_data);
+	snd_soc_unregister_dai(dai->dev);
+
+	mutex_unlock(&aux_pcm_mutex);
+
+	return 0;
+}
+static int msm_dai_q6_dai_i2s_probe(struct snd_soc_dai *dai)
+{
+	struct msm_dai_q6_dai_data *dai_data;
+	int rc = 0;
+
+	dai_data = kzalloc(sizeof(struct msm_dai_q6_dai_data),
+		GFP_KERNEL);
+
+	if (!dai_data) {
+		dev_err(dai->dev, "DAI-%d: fail to allocate dai data\n",
+		dai->id);
+		rc = -ENOMEM;
+		goto rtn;
+	} else
+		dev_set_drvdata(dai->dev, dai_data);
+
+	rc = msm_dai_q6_i2s_platform_data_validation(dai);
+	if (rc != 0) {
+		pr_err("%s: The msm_dai_q6_i2s_platform_data_validation failed\n",
+			    __func__);
+		kfree(dai_data);
+	}
+rtn:
+	return rc;
+}
+
+static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai)
+{
+	struct msm_dai_q6_dai_data *dai_data;
+	int rc = 0;
+
+	dai_data = kzalloc(sizeof(struct msm_dai_q6_dai_data),
+		GFP_KERNEL);
+
+	if (!dai_data) {
+		dev_err(dai->dev, "DAI-%d: fail to allocate dai data\n",
+		dai->id);
+		rc = -ENOMEM;
+	} else
+		dev_set_drvdata(dai->dev, dai_data);
+
+	return rc;
+}
+
+static int msm_dai_q6_dai_remove(struct snd_soc_dai *dai)
+{
+	struct msm_dai_q6_dai_data *dai_data;
+	int rc;
+
+	dai_data = dev_get_drvdata(dai->dev);
+
+	/* If AFE port is still up, close it */
+	if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
+		switch (dai->id) {
+		case VOICE_PLAYBACK_TX:
+		case VOICE_RECORD_TX:
+		case VOICE_RECORD_RX:
+			pr_debug("%s, stop pseudo port:%d\n",
+						__func__,  dai->id);
+			rc = afe_stop_pseudo_port(dai->id);
+			break;
+		default:
+			rc = afe_close(dai->id); /* can block */
+		}
+		if (IS_ERR_VALUE(rc))
+			dev_err(dai->dev, "fail to close AFE port\n");
+		clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
+	}
+	kfree(dai_data);
+	snd_soc_unregister_dai(dai->dev);
+
+	return 0;
+}
+
+static int msm_dai_q6_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	int rc = 0;
+
+	dev_dbg(dai->dev, "enter %s, id = %d fmt[%d]\n", __func__,
+							dai->id, fmt);
+	switch (dai->id) {
+	case PRIMARY_I2S_TX:
+	case PRIMARY_I2S_RX:
+	case MI2S_RX:
+	case SECONDARY_I2S_RX:
+		rc = msm_dai_q6_cdc_set_fmt(dai, fmt);
+		break;
+	default:
+		dev_err(dai->dev, "invalid cpu_dai set_fmt\n");
+		rc = -EINVAL;
+		break;
+	}
+
+	return rc;
+}
+
+static int msm_dai_q6_set_channel_map(struct snd_soc_dai *dai,
+				unsigned int tx_num, unsigned int *tx_slot,
+				unsigned int rx_num, unsigned int *rx_slot)
+
+{
+	int rc = 0;
+	struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
+	unsigned int i = 0;
+
+	dev_dbg(dai->dev, "enter %s, id = %d\n", __func__,
+							dai->id);
+	switch (dai->id) {
+	case SLIMBUS_0_RX:
+	case SLIMBUS_1_RX:
+		/* channel number to be between 128 and 255. For RX port
+		 * use channel numbers from 138 to 144, for TX port
+		 * use channel numbers from 128 to 137
+		 * For ports between MDM-APQ use channel numbers from 145
+		 */
+		if (!rx_slot)
+			return -EINVAL;
+		for (i = 0; i < rx_num; i++) {
+			dai_data->port_config.slim_sch.shared_ch_mapping[i] =
+							rx_slot[i];
+			pr_debug("%s: find number of channels[%d] ch[%d]\n",
+							__func__, i,
+							rx_slot[i]);
+		}
+		dai_data->port_config.slim_sch.num_channels = rx_num;
+		pr_debug("%s:SLIMBUS_0_RX cnt[%d] ch[%d %d]\n", __func__,
+		rx_num, dai_data->port_config.slim_sch.shared_ch_mapping[0],
+		dai_data->port_config.slim_sch.shared_ch_mapping[1]);
+
+		break;
+	case SLIMBUS_0_TX:
+	case SLIMBUS_1_TX:
+		/* channel number to be between 128 and 255. For RX port
+		 * use channel numbers from 138 to 144, for TX port
+		 * use channel numbers from 128 to 137
+		 * For ports between MDM-APQ use channel numbers from 145
+		 */
+		if (!tx_slot)
+			return -EINVAL;
+		for (i = 0; i < tx_num; i++) {
+			dai_data->port_config.slim_sch.shared_ch_mapping[i] =
+							tx_slot[i];
+			pr_debug("%s: find number of channels[%d] ch[%d]\n",
+						__func__, i, tx_slot[i]);
+		}
+		dai_data->port_config.slim_sch.num_channels = tx_num;
+		pr_debug("%s:SLIMBUS_0_TX cnt[%d] ch[%d %d]\n", __func__,
+		tx_num, dai_data->port_config.slim_sch.shared_ch_mapping[0],
+		dai_data->port_config.slim_sch.shared_ch_mapping[1]);
+		break;
+	default:
+		dev_err(dai->dev, "invalid cpu_dai set_fmt\n");
+		rc = -EINVAL;
+		break;
+	}
+	return rc;
+}
+
+static struct snd_soc_dai_ops msm_dai_q6_ops = {
+	.prepare	= msm_dai_q6_prepare,
+	.trigger	= msm_dai_q6_trigger,
+	.hw_params	= msm_dai_q6_hw_params,
+	.shutdown	= msm_dai_q6_shutdown,
+	.set_fmt	= msm_dai_q6_set_fmt,
+	.set_channel_map = msm_dai_q6_set_channel_map,
+};
+
+static struct snd_soc_dai_ops msm_dai_q6_auxpcm_ops = {
+	.prepare	= msm_dai_q6_auxpcm_prepare,
+	.trigger	= msm_dai_q6_auxpcm_trigger,
+	.hw_params	= msm_dai_q6_auxpcm_hw_params,
+	.shutdown	= msm_dai_q6_auxpcm_shutdown,
+};
+
+static struct snd_soc_dai_driver msm_dai_q6_i2s_rx_dai = {
+	.playback = {
+		.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+		SNDRV_PCM_RATE_16000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		.channels_min = 1,
+		.channels_max = 4,
+		.rate_min =     8000,
+		.rate_max =	48000,
+	},
+	.ops = &msm_dai_q6_ops,
+	.probe = msm_dai_q6_dai_i2s_probe,
+	.remove = msm_dai_q6_dai_remove,
+};
+
+static struct snd_soc_dai_driver msm_dai_q6_i2s_tx_dai = {
+	.capture = {
+		.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+		SNDRV_PCM_RATE_16000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		.channels_min = 1,
+		.channels_max = 2,
+		.rate_min =     8000,
+		.rate_max =	48000,
+	},
+	.ops = &msm_dai_q6_ops,
+	.probe = msm_dai_q6_dai_probe,
+	.remove = msm_dai_q6_dai_remove,
+};
+
+static struct snd_soc_dai_driver msm_dai_q6_afe_rx_dai = {
+	.playback = {
+		.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+		SNDRV_PCM_RATE_16000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		.channels_min = 1,
+		.channels_max = 2,
+		.rate_min =     8000,
+		.rate_max =	48000,
+	},
+	.ops = &msm_dai_q6_ops,
+	.probe = msm_dai_q6_dai_probe,
+	.remove = msm_dai_q6_dai_remove,
+};
+
+static struct snd_soc_dai_driver msm_dai_q6_afe_tx_dai = {
+	.capture = {
+		.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+		SNDRV_PCM_RATE_16000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		.channels_min = 1,
+		.channels_max = 2,
+		.rate_min =     8000,
+		.rate_max =	48000,
+	},
+	.ops = &msm_dai_q6_ops,
+	.probe = msm_dai_q6_dai_probe,
+	.remove = msm_dai_q6_dai_remove,
+};
+
+static struct snd_soc_dai_driver msm_dai_q6_voice_playback_tx_dai = {
+	.playback = {
+		.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+		SNDRV_PCM_RATE_16000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		.channels_min = 1,
+		.channels_max = 2,
+		.rate_max =     48000,
+		.rate_min =     8000,
+	},
+	.ops = &msm_dai_q6_ops,
+	.probe = msm_dai_q6_dai_probe,
+	.remove = msm_dai_q6_dai_remove,
+};
+
+static struct snd_soc_dai_driver msm_dai_q6_slimbus_rx_dai = {
+	.playback = {
+		.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+		SNDRV_PCM_RATE_16000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		.channels_min = 1,
+		.channels_max = 2,
+		.rate_min =     8000,
+		.rate_max =	48000,
+	},
+	.ops = &msm_dai_q6_ops,
+	.probe = msm_dai_q6_dai_probe,
+	.remove = msm_dai_q6_dai_remove,
+};
+
+static struct snd_soc_dai_driver msm_dai_q6_slimbus_tx_dai = {
+	.capture = {
+		.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+		SNDRV_PCM_RATE_16000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		.channels_min = 1,
+		.channels_max = 2,
+		.rate_min =     8000,
+		.rate_max =	48000,
+	},
+	.ops = &msm_dai_q6_ops,
+	.probe = msm_dai_q6_dai_probe,
+	.remove = msm_dai_q6_dai_remove,
+};
+
+static struct snd_soc_dai_driver msm_dai_q6_incall_record_dai = {
+	.capture = {
+		.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+		SNDRV_PCM_RATE_16000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		.channels_min = 1,
+		.channels_max = 2,
+		.rate_min =     8000,
+		.rate_max =     48000,
+	},
+	.ops = &msm_dai_q6_ops,
+	.probe = msm_dai_q6_dai_probe,
+	.remove = msm_dai_q6_dai_remove,
+};
+
+static struct snd_soc_dai_driver msm_dai_q6_bt_sco_rx_dai = {
+	.playback = {
+		.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		.channels_min = 1,
+		.channels_max = 1,
+		.rate_max = 16000,
+		.rate_min = 8000,
+	},
+	.ops = &msm_dai_q6_ops,
+	.probe = msm_dai_q6_dai_probe,
+	.remove = msm_dai_q6_dai_remove,
+};
+
+static struct snd_soc_dai_driver msm_dai_q6_bt_sco_tx_dai = {
+	.playback = {
+		.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		.channels_min = 1,
+		.channels_max = 1,
+		.rate_max = 16000,
+		.rate_min = 8000,
+	},
+	.ops = &msm_dai_q6_ops,
+	.probe = msm_dai_q6_dai_probe,
+	.remove = msm_dai_q6_dai_remove,
+};
+
+static struct snd_soc_dai_driver msm_dai_q6_fm_rx_dai = {
+	.playback = {
+		.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+		SNDRV_PCM_RATE_16000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		.channels_min = 2,
+		.channels_max = 2,
+		.rate_max = 48000,
+		.rate_min = 8000,
+	},
+	.ops = &msm_dai_q6_ops,
+	.probe = msm_dai_q6_dai_probe,
+	.remove = msm_dai_q6_dai_remove,
+};
+
+static struct snd_soc_dai_driver msm_dai_q6_fm_tx_dai = {
+	.playback = {
+		.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+		SNDRV_PCM_RATE_16000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		.channels_min = 2,
+		.channels_max = 2,
+		.rate_max = 48000,
+		.rate_min = 8000,
+	},
+	.ops = &msm_dai_q6_ops,
+	.probe = msm_dai_q6_dai_probe,
+	.remove = msm_dai_q6_dai_remove,
+};
+
+static struct snd_soc_dai_driver msm_dai_q6_aux_pcm_rx_dai = {
+	.playback = {
+		.rates = SNDRV_PCM_RATE_8000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		.channels_min = 1,
+		.channels_max = 1,
+		.rate_max = 8000,
+		.rate_min = 8000,
+	},
+	.ops = &msm_dai_q6_auxpcm_ops,
+	.probe = msm_dai_q6_dai_auxpcm_probe,
+	.remove = msm_dai_q6_dai_auxpcm_remove,
+};
+
+static struct snd_soc_dai_driver msm_dai_q6_aux_pcm_tx_dai = {
+	.capture = {
+		.rates = SNDRV_PCM_RATE_8000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		.channels_min = 1,
+		.channels_max = 1,
+		.rate_max = 8000,
+		.rate_min = 8000,
+	},
+	.ops = &msm_dai_q6_auxpcm_ops,
+	.probe = msm_dai_q6_dai_auxpcm_probe,
+	.remove = msm_dai_q6_dai_auxpcm_remove,
+};
+
+
+static struct snd_soc_dai_driver msm_dai_q6_slimbus_1_rx_dai = {
+	.playback = {
+		.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		.channels_min = 1,
+		.channels_max = 1,
+		.rate_min = 8000,
+		.rate_max = 16000,
+	},
+	.ops = &msm_dai_q6_ops,
+	.probe = msm_dai_q6_dai_probe,
+	.remove = msm_dai_q6_dai_remove,
+};
+
+static struct snd_soc_dai_driver msm_dai_q6_slimbus_1_tx_dai = {
+	.capture = {
+		.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		.channels_min = 1,
+		.channels_max = 1,
+		.rate_min = 8000,
+		.rate_max = 16000,
+	},
+	.ops = &msm_dai_q6_ops,
+	.probe = msm_dai_q6_dai_probe,
+	.remove = msm_dai_q6_dai_remove,
+};
+
+static __devinit int msm_dai_q6_dev_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+
+	dev_dbg(&pdev->dev, "dev name %s\n", dev_name(&pdev->dev));
+
+	switch (pdev->id) {
+	case PRIMARY_I2S_RX:
+	case SECONDARY_I2S_RX:
+		rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_i2s_rx_dai);
+		break;
+	case PRIMARY_I2S_TX:
+		rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_i2s_tx_dai);
+		break;
+	case AFE_PORT_ID_PRIMARY_PCM_RX:
+		rc = snd_soc_register_dai(&pdev->dev,
+				&msm_dai_q6_aux_pcm_rx_dai);
+		break;
+	case AFE_PORT_ID_PRIMARY_PCM_TX:
+		rc = snd_soc_register_dai(&pdev->dev,
+				&msm_dai_q6_aux_pcm_tx_dai);
+		break;
+	case MI2S_RX:
+		rc = snd_soc_register_dai(&pdev->dev,
+					&msm_dai_q6_i2s_rx_dai);
+		break;
+	case SLIMBUS_0_RX:
+		rc = snd_soc_register_dai(&pdev->dev,
+				&msm_dai_q6_slimbus_rx_dai);
+		break;
+	case SLIMBUS_0_TX:
+		rc = snd_soc_register_dai(&pdev->dev,
+				&msm_dai_q6_slimbus_tx_dai);
+		break;
+
+	case SLIMBUS_1_RX:
+		rc = snd_soc_register_dai(&pdev->dev,
+				&msm_dai_q6_slimbus_1_rx_dai);
+		break;
+	case SLIMBUS_1_TX:
+		rc = snd_soc_register_dai(&pdev->dev,
+				&msm_dai_q6_slimbus_1_tx_dai);
+		break;
+	case INT_BT_SCO_RX:
+		rc = snd_soc_register_dai(&pdev->dev,
+					&msm_dai_q6_bt_sco_rx_dai);
+		break;
+	case INT_BT_SCO_TX:
+		rc = snd_soc_register_dai(&pdev->dev,
+					&msm_dai_q6_bt_sco_tx_dai);
+		break;
+	case INT_FM_RX:
+		rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_fm_rx_dai);
+		break;
+	case INT_FM_TX:
+		rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_fm_tx_dai);
+		break;
+	case RT_PROXY_DAI_001_RX:
+	case RT_PROXY_DAI_002_RX:
+		rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_afe_rx_dai);
+		break;
+	case RT_PROXY_DAI_001_TX:
+	case RT_PROXY_DAI_002_TX:
+		rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_afe_tx_dai);
+		break;
+	case VOICE_PLAYBACK_TX:
+		rc = snd_soc_register_dai(&pdev->dev,
+					&msm_dai_q6_voice_playback_tx_dai);
+		break;
+	case VOICE_RECORD_RX:
+	case VOICE_RECORD_TX:
+		rc = snd_soc_register_dai(&pdev->dev,
+						&msm_dai_q6_incall_record_dai);
+		break;
+	default:
+		rc = -ENODEV;
+		break;
+	}
+	return rc;
+}
+
+static __devexit int msm_dai_q6_dev_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_dai(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver msm_dai_q6_driver = {
+	.probe  = msm_dai_q6_dev_probe,
+	.remove = msm_dai_q6_dev_remove,
+	.driver = {
+		.name = "msm-dai-q6",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init msm_dai_q6_init(void)
+{
+	return platform_driver_register(&msm_dai_q6_driver);
+}
+module_init(msm_dai_q6_init);
+
+static void __exit msm_dai_q6_exit(void)
+{
+	platform_driver_unregister(&msm_dai_q6_driver);
+}
+module_exit(msm_dai_q6_exit);
+
+/* Module information */
+MODULE_DESCRIPTION("MSM DSP DAI driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/qdsp6v2/msm-multi-ch-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-multi-ch-pcm-q6-v2.c
new file mode 100644
index 0000000..cab689d
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-multi-ch-pcm-q6-v2.c
@@ -0,0 +1,777 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/android_pmem.h>
+#include <asm/dma.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+
+#include "msm-pcm-q6-v2.h"
+#include "msm-pcm-routing-v2.h"
+
+static struct audio_locks the_locks;
+
+struct snd_msm {
+	struct snd_card *card;
+	struct snd_pcm *pcm;
+};
+
+struct snd_msm_volume {
+	struct msm_audio *prtd;
+	unsigned volume;
+};
+static struct snd_msm_volume multi_ch_pcm_audio = {NULL, 0x2000};
+
+#define PLAYBACK_NUM_PERIODS	8
+#define PLAYBACK_PERIOD_SIZE	4032
+#define CAPTURE_NUM_PERIODS	16
+#define CAPTURE_PERIOD_SIZE	320
+
+static struct snd_pcm_hardware msm_pcm_hardware_capture = {
+	.info =                 (SNDRV_PCM_INFO_MMAP |
+				SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				SNDRV_PCM_INFO_MMAP_VALID |
+				SNDRV_PCM_INFO_INTERLEAVED |
+				SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+	.formats =              SNDRV_PCM_FMTBIT_S16_LE,
+	.rates =                SNDRV_PCM_RATE_8000_48000,
+	.rate_min =             8000,
+	.rate_max =             48000,
+	.channels_min =         1,
+	.channels_max =         2,
+	.buffer_bytes_max =     CAPTURE_NUM_PERIODS * CAPTURE_PERIOD_SIZE,
+	.period_bytes_min =	CAPTURE_PERIOD_SIZE,
+	.period_bytes_max =     CAPTURE_PERIOD_SIZE,
+	.periods_min =          CAPTURE_NUM_PERIODS,
+	.periods_max =          CAPTURE_NUM_PERIODS,
+	.fifo_size =            0,
+};
+
+static struct snd_pcm_hardware msm_pcm_hardware_playback = {
+	.info =                 (SNDRV_PCM_INFO_MMAP |
+				SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				SNDRV_PCM_INFO_MMAP_VALID |
+				SNDRV_PCM_INFO_INTERLEAVED |
+				SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+	.formats =              SNDRV_PCM_FMTBIT_S16_LE,
+	.rates =                SNDRV_PCM_RATE_8000_48000,
+	.rate_min =             8000,
+	.rate_max =             48000,
+	.channels_min =         1,
+	.channels_max =         6,
+	.buffer_bytes_max =     PLAYBACK_NUM_PERIODS * PLAYBACK_PERIOD_SIZE,
+	.period_bytes_min =	PLAYBACK_PERIOD_SIZE,
+	.period_bytes_max =     PLAYBACK_PERIOD_SIZE,
+	.periods_min =          PLAYBACK_NUM_PERIODS,
+	.periods_max =          PLAYBACK_NUM_PERIODS,
+	.fifo_size =            0,
+};
+
+/* Conventional and unconventional sample rate supported */
+static unsigned int supported_sample_rates[] = {
+	8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+};
+
+static uint32_t in_frame_info[CAPTURE_NUM_PERIODS][2];
+
+static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
+	.count = ARRAY_SIZE(supported_sample_rates),
+	.list = supported_sample_rates,
+	.mask = 0,
+};
+
+static void event_handler(uint32_t opcode,
+		uint32_t token, uint32_t *payload, void *priv)
+{
+	struct msm_audio *prtd = priv;
+	struct snd_pcm_substream *substream = prtd->substream;
+	uint32_t *ptrmem = (uint32_t *)payload;
+	int i = 0;
+	uint32_t idx = 0;
+	uint32_t size = 0;
+
+	pr_debug("%s\n", __func__);
+	switch (opcode) {
+	case ASM_DATA_EVENT_WRITE_DONE_V2: {
+		pr_debug("ASM_DATA_EVENT_WRITE_DONE\n");
+		pr_debug("Buffer Consumed = 0x%08x\n", *ptrmem);
+		prtd->pcm_irq_pos += prtd->pcm_count;
+		if (atomic_read(&prtd->start))
+			snd_pcm_period_elapsed(substream);
+		atomic_inc(&prtd->out_count);
+		wake_up(&the_locks.write_wait);
+		if (!atomic_read(&prtd->start))
+			break;
+		if (!prtd->mmap_flag)
+			break;
+		if (q6asm_is_cpu_buf_avail_nolock(IN,
+				prtd->audio_client,
+				&size, &idx)) {
+			pr_debug("%s:writing %d bytes of buffer to dsp 2\n",
+					__func__, prtd->pcm_count);
+			q6asm_write_nolock(prtd->audio_client,
+				prtd->pcm_count, 0, 0, NO_TIMESTAMP);
+		}
+		break;
+	}
+	case ASM_DATA_EVENT_RENDERED_EOS:
+		pr_debug("ASM_DATA_CMDRSP_EOS\n");
+		prtd->cmd_ack = 1;
+		wake_up(&the_locks.eos_wait);
+		break;
+	case ASM_DATA_EVENT_READ_DONE_V2: {
+		pr_debug("ASM_DATA_EVENT_READ_DONE\n");
+		pr_debug("token = 0x%08x\n", token);
+		for (i = 0; i < 8; i++, ++ptrmem)
+			pr_debug("cmd[%d]=0x%08x\n", i, *ptrmem);
+		in_frame_info[token][0] = payload[2];
+		in_frame_info[token][1] = payload[3];
+		prtd->pcm_irq_pos += in_frame_info[token][0];
+		pr_debug("pcm_irq_pos=%d\n", prtd->pcm_irq_pos);
+		if (atomic_read(&prtd->start))
+			snd_pcm_period_elapsed(substream);
+		if (atomic_read(&prtd->in_count) <= prtd->periods)
+			atomic_inc(&prtd->in_count);
+		wake_up(&the_locks.read_wait);
+		if (prtd->mmap_flag
+			&& q6asm_is_cpu_buf_avail_nolock(OUT,
+				prtd->audio_client,
+				&size, &idx))
+			q6asm_read_nolock(prtd->audio_client);
+		break;
+	}
+	case APR_BASIC_RSP_RESULT: {
+		switch (payload[0]) {
+		case ASM_SESSION_CMD_RUN_V2:
+			if (substream->stream
+				!= SNDRV_PCM_STREAM_PLAYBACK) {
+				atomic_set(&prtd->start, 1);
+				break;
+			}
+			if (prtd->mmap_flag) {
+				pr_debug("%s:writing %d bytes"
+					" of buffer to dsp\n",
+					__func__,
+					prtd->pcm_count);
+				q6asm_write_nolock(prtd->audio_client,
+					prtd->pcm_count,
+					0, 0, NO_TIMESTAMP);
+			} else {
+				while (atomic_read(&prtd->out_needed)) {
+					pr_debug("%s:writing %d bytes"
+						 " of buffer to dsp\n",
+						__func__,
+						prtd->pcm_count);
+					q6asm_write_nolock(prtd->audio_client,
+						prtd->pcm_count,
+						0, 0, NO_TIMESTAMP);
+					atomic_dec(&prtd->out_needed);
+					wake_up(&the_locks.write_wait);
+				};
+			}
+			atomic_set(&prtd->start, 1);
+			break;
+		default:
+			break;
+		}
+	}
+	break;
+	default:
+		pr_debug("Not Supported Event opcode[0x%x]\n", opcode);
+		break;
+	}
+}
+
+static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+	int ret;
+
+	pr_debug("%s\n", __func__);
+	prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
+	prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
+	prtd->pcm_irq_pos = 0;
+	/* rate and channels are sent to audio driver */
+	prtd->samp_rate = runtime->rate;
+	prtd->channel_mode = runtime->channels;
+	if (prtd->enabled)
+		return 0;
+
+	ret = q6asm_media_format_block_pcm(prtd->audio_client,
+			runtime->rate, runtime->channels);
+	if (ret < 0)
+		pr_info("%s: CMD Format block failed\n", __func__);
+
+	atomic_set(&prtd->out_count, runtime->periods);
+
+	prtd->enabled = 1;
+	prtd->cmd_ack = 0;
+
+	return 0;
+}
+
+static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+	int ret = 0;
+	int i = 0;
+	pr_debug("%s\n", __func__);
+	prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
+	prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
+	prtd->pcm_irq_pos = 0;
+
+	/* rate and channels are sent to audio driver */
+	prtd->samp_rate = runtime->rate;
+	prtd->channel_mode = runtime->channels;
+
+	if (prtd->enabled)
+		return 0;
+
+	pr_debug("Samp_rate = %d\n", prtd->samp_rate);
+	pr_debug("Channel = %d\n", prtd->channel_mode);
+	ret = q6asm_enc_cfg_blk_pcm(prtd->audio_client, prtd->samp_rate,
+					prtd->channel_mode);
+	if (ret < 0)
+		pr_debug("%s: cmd cfg pcm was block failed", __func__);
+
+	for (i = 0; i < runtime->periods; i++)
+		q6asm_read(prtd->audio_client);
+	prtd->periods = runtime->periods;
+
+	prtd->enabled = 1;
+
+	return ret;
+}
+
+static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	int ret = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		pr_debug("%s: Trigger start\n", __func__);
+		q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
+		atomic_set(&prtd->start, 0);
+		if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
+			break;
+		prtd->cmd_ack = 0;
+		q6asm_cmd_nowait(prtd->audio_client, CMD_EOS);
+		break;
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		pr_debug("SNDRV_PCM_TRIGGER_PAUSE\n");
+		q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
+		atomic_set(&prtd->start, 0);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static int msm_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+	struct msm_audio *prtd;
+	int ret = 0;
+	struct asm_softpause_params softpause = {
+		.enable = SOFT_PAUSE_ENABLE,
+		.period = SOFT_PAUSE_PERIOD,
+		.step = SOFT_PAUSE_STEP,
+		.rampingcurve = SOFT_PAUSE_CURVE_LINEAR,
+	};
+	struct asm_softvolume_params softvol = {
+		.period = SOFT_VOLUME_PERIOD,
+		.step = SOFT_VOLUME_STEP,
+		.rampingcurve = SOFT_VOLUME_CURVE_LINEAR,
+	};
+
+	pr_debug("%s\n", __func__);
+	prtd = kzalloc(sizeof(struct msm_audio), GFP_KERNEL);
+	if (prtd == NULL) {
+		pr_err("Failed to allocate memory for msm_audio\n");
+		return -ENOMEM;
+	}
+	prtd->substream = substream;
+	prtd->audio_client = q6asm_audio_client_alloc(
+				(app_cb)event_handler, prtd);
+	if (!prtd->audio_client) {
+		pr_err("%s: Could not allocate memory\n", __func__);
+		kfree(prtd);
+		return -ENOMEM;
+	}
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		runtime->hw = msm_pcm_hardware_playback;
+		ret = q6asm_open_write(prtd->audio_client,
+				FORMAT_MULTI_CHANNEL_LINEAR_PCM);
+		if (ret < 0) {
+			pr_err("%s: pcm out open failed\n", __func__);
+			q6asm_audio_client_free(prtd->audio_client);
+			kfree(prtd);
+			return -ENOMEM;
+		}
+	}
+	/* Capture path */
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		runtime->hw = msm_pcm_hardware_capture;
+		ret = q6asm_open_read(prtd->audio_client, FORMAT_LINEAR_PCM);
+		if (ret < 0) {
+			pr_err("%s: pcm in open failed\n", __func__);
+			q6asm_audio_client_free(prtd->audio_client);
+			kfree(prtd);
+			return -ENOMEM;
+		}
+	}
+
+	pr_debug("%s: session ID %d\n", __func__, prtd->audio_client->session);
+
+	prtd->session_id = prtd->audio_client->session;
+	msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
+			prtd->session_id, substream->stream);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		prtd->cmd_ack = 1;
+
+	ret = snd_pcm_hw_constraint_list(runtime, 0,
+				SNDRV_PCM_HW_PARAM_RATE,
+				&constraints_sample_rates);
+	if (ret < 0)
+		pr_err("snd_pcm_hw_constraint_list failed\n");
+	/* Ensure that buffer size is a multiple of period size */
+	ret = snd_pcm_hw_constraint_integer(runtime,
+					    SNDRV_PCM_HW_PARAM_PERIODS);
+	if (ret < 0)
+		pr_err("snd_pcm_hw_constraint_integer failed\n");
+
+	prtd->dsp_cnt = 0;
+	runtime->private_data = prtd;
+	pr_debug("substream->pcm->device = %d\n", substream->pcm->device);
+	pr_debug("soc_prtd->dai_link->be_id = %d\n", soc_prtd->dai_link->be_id);
+	multi_ch_pcm_audio.prtd = prtd;
+	ret = multi_ch_pcm_set_volume(multi_ch_pcm_audio.volume);
+	if (ret < 0)
+		pr_err("%s : Set Volume failed : %d", __func__, ret);
+
+	ret = q6asm_set_softpause(multi_ch_pcm_audio.prtd->audio_client,
+								 &softpause);
+	if (ret < 0)
+		pr_err("%s: Send SoftPause Param failed ret=%d\n",
+			__func__, ret);
+	ret = q6asm_set_softvolume(multi_ch_pcm_audio.prtd->audio_client,
+								 &softvol);
+	if (ret < 0)
+		pr_err("%s: Send SoftVolume Param failed ret=%d\n",
+			__func__, ret);
+
+	return 0;
+}
+
+int multi_ch_pcm_set_volume(unsigned volume)
+{
+	int rc = 0;
+	pr_err("multi_ch_pcm_set_volume\n");
+
+	if (multi_ch_pcm_audio.prtd && multi_ch_pcm_audio.prtd->audio_client) {
+		pr_err("%s q6asm_set_volume\n", __func__);
+		rc = q6asm_set_volume(multi_ch_pcm_audio.prtd->audio_client,
+								volume);
+		if (rc < 0) {
+			pr_err("%s: Send Volume command failed"
+				" rc=%d\n", __func__, rc);
+		}
+	}
+	multi_ch_pcm_audio.volume = volume;
+	return rc;
+}
+
+
+static int msm_pcm_playback_copy(struct snd_pcm_substream *substream, int a,
+	snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
+{
+	int ret = 0;
+	int fbytes = 0;
+	int xfer = 0;
+	char *bufptr = NULL;
+	void *data = NULL;
+	uint32_t idx = 0;
+	uint32_t size = 0;
+
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	fbytes = frames_to_bytes(runtime, frames);
+	pr_debug("%s: prtd->out_count = %d\n",
+				__func__, atomic_read(&prtd->out_count));
+	ret = wait_event_timeout(the_locks.write_wait,
+			(atomic_read(&prtd->out_count)), 5 * HZ);
+	if (ret < 0) {
+		pr_err("%s: wait_event_timeout failed\n", __func__);
+		goto fail;
+	}
+
+	if (!atomic_read(&prtd->out_count)) {
+		pr_err("%s: pcm stopped out_count 0\n", __func__);
+		return 0;
+	}
+
+	data = q6asm_is_cpu_buf_avail(IN, prtd->audio_client, &size, &idx);
+	bufptr = data;
+	if (bufptr) {
+		pr_debug("%s:fbytes =%d: xfer=%d size=%d\n",
+					__func__, fbytes, xfer, size);
+		xfer = fbytes;
+		if (copy_from_user(bufptr, buf, xfer)) {
+			ret = -EFAULT;
+			goto fail;
+		}
+		buf += xfer;
+		fbytes -= xfer;
+		pr_debug("%s:fbytes = %d: xfer=%d\n", __func__, fbytes, xfer);
+		if (atomic_read(&prtd->start)) {
+			pr_debug("%s:writing %d bytes of buffer to dsp\n",
+					__func__, xfer);
+			ret = q6asm_write(prtd->audio_client, xfer,
+						0, 0, NO_TIMESTAMP);
+			if (ret < 0) {
+				ret = -EFAULT;
+				goto fail;
+			}
+		} else
+			atomic_inc(&prtd->out_needed);
+		atomic_dec(&prtd->out_count);
+	}
+fail:
+	return  ret;
+}
+
+static int msm_pcm_playback_close(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+	struct msm_audio *prtd = runtime->private_data;
+	int dir = 0;
+	int ret = 0;
+
+	pr_debug("%s\n", __func__);
+
+	dir = IN;
+	ret = wait_event_timeout(the_locks.eos_wait,
+				prtd->cmd_ack, 5 * HZ);
+	if (ret < 0)
+		pr_err("%s: CMD_EOS failed\n", __func__);
+	q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+	q6asm_audio_client_buf_free_contiguous(dir,
+				prtd->audio_client);
+
+	msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
+	SNDRV_PCM_STREAM_PLAYBACK);
+	multi_ch_pcm_audio.prtd = NULL;
+	q6asm_audio_client_free(prtd->audio_client);
+	kfree(prtd);
+	return 0;
+}
+
+static int msm_pcm_capture_copy(struct snd_pcm_substream *substream,
+		 int channel, snd_pcm_uframes_t hwoff, void __user *buf,
+						 snd_pcm_uframes_t frames)
+{
+	int ret = 0;
+	int fbytes = 0;
+	int xfer;
+	char *bufptr;
+	void *data = NULL;
+	static uint32_t idx;
+	static uint32_t size;
+	uint32_t offset = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = substream->runtime->private_data;
+
+
+	pr_debug("%s\n", __func__);
+	fbytes = frames_to_bytes(runtime, frames);
+
+	pr_debug("appl_ptr %d\n", (int)runtime->control->appl_ptr);
+	pr_debug("hw_ptr %d\n", (int)runtime->status->hw_ptr);
+	pr_debug("avail_min %d\n", (int)runtime->control->avail_min);
+
+	ret = wait_event_timeout(the_locks.read_wait,
+			(atomic_read(&prtd->in_count)), 5 * HZ);
+	if (ret < 0) {
+		pr_debug("%s: wait_event_timeout failed\n", __func__);
+		goto fail;
+	}
+	if (!atomic_read(&prtd->in_count)) {
+		pr_debug("%s: pcm stopped in_count 0\n", __func__);
+		return 0;
+	}
+	pr_debug("Checking if valid buffer is available...%08x\n",
+						(unsigned int) data);
+	data = q6asm_is_cpu_buf_avail(OUT, prtd->audio_client, &size, &idx);
+	bufptr = data;
+	pr_debug("Size = %d\n", size);
+	pr_debug("fbytes = %d\n", fbytes);
+	pr_debug("idx = %d\n", idx);
+	if (bufptr) {
+		xfer = fbytes;
+		if (xfer > size)
+			xfer = size;
+		offset = in_frame_info[idx][1];
+		pr_debug("Offset value = %d\n", offset);
+		if (copy_to_user(buf, bufptr+offset, xfer)) {
+			pr_err("Failed to copy buf to user\n");
+			ret = -EFAULT;
+			goto fail;
+		}
+		fbytes -= xfer;
+		size -= xfer;
+		in_frame_info[idx][1] += xfer;
+		pr_debug("%s:fbytes = %d: size=%d: xfer=%d\n",
+					__func__, fbytes, size, xfer);
+		pr_debug(" Sending next buffer to dsp\n");
+		memset(&in_frame_info[idx], 0,
+			sizeof(uint32_t) * 2);
+		atomic_dec(&prtd->in_count);
+		ret = q6asm_read(prtd->audio_client);
+		if (ret < 0) {
+			pr_err("q6asm read failed\n");
+			ret = -EFAULT;
+			goto fail;
+		}
+	} else
+		pr_err("No valid buffer\n");
+
+	pr_debug("Returning from capture_copy... %d\n", ret);
+fail:
+	return ret;
+}
+
+static int msm_pcm_capture_close(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+	struct msm_audio *prtd = runtime->private_data;
+	int dir = OUT;
+
+	pr_debug("%s\n", __func__);
+	q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+	q6asm_audio_client_buf_free_contiguous(dir,
+				prtd->audio_client);
+	msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
+	SNDRV_PCM_STREAM_CAPTURE);
+	q6asm_audio_client_free(prtd->audio_client);
+	kfree(prtd);
+
+	return 0;
+}
+
+static int msm_pcm_copy(struct snd_pcm_substream *substream, int a,
+	 snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
+{
+	int ret = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = msm_pcm_playback_copy(substream, a, hwoff, buf, frames);
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		ret = msm_pcm_capture_copy(substream, a, hwoff, buf, frames);
+	return ret;
+}
+
+static int msm_pcm_close(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = msm_pcm_playback_close(substream);
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		ret = msm_pcm_capture_close(substream);
+	return ret;
+}
+static int msm_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = msm_pcm_playback_prepare(substream);
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		ret = msm_pcm_capture_prepare(substream);
+	return ret;
+}
+
+static snd_pcm_uframes_t msm_pcm_pointer(struct snd_pcm_substream *substream)
+{
+
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	if (prtd->pcm_irq_pos >= prtd->pcm_size)
+		prtd->pcm_irq_pos = 0;
+
+	pr_debug("pcm_irq_pos = %d\n", prtd->pcm_irq_pos);
+	return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
+}
+
+static int msm_pcm_mmap(struct snd_pcm_substream *substream,
+				struct vm_area_struct *vma)
+{
+	int result = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	pr_debug("%s\n", __func__);
+	prtd->mmap_flag = 1;
+
+	if (runtime->dma_addr && runtime->dma_bytes) {
+		vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+		result = remap_pfn_range(vma, vma->vm_start,
+				runtime->dma_addr >> PAGE_SHIFT,
+				runtime->dma_bytes,
+				vma->vm_page_prot);
+	} else {
+		pr_err("Physical address or size of buf is NULL");
+		return -EINVAL;
+	}
+
+	return result;
+}
+
+static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+	struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
+	struct audio_buffer *buf;
+	int dir, ret;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		dir = IN;
+	else
+		dir = OUT;
+
+	ret = q6asm_audio_client_buf_alloc_contiguous(dir,
+			prtd->audio_client,
+			runtime->hw.period_bytes_min,
+			runtime->hw.periods_max);
+	if (ret < 0) {
+		pr_err("Audio Start: Buffer Allocation failed rc = %d\n", ret);
+		return -ENOMEM;
+	}
+	buf = prtd->audio_client->port[dir].buf;
+
+	pr_debug("%s:buf = %p\n", __func__, buf);
+	dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
+	dma_buf->dev.dev = substream->pcm->card->dev;
+	dma_buf->private_data = NULL;
+	dma_buf->area = buf[0].data;
+	dma_buf->addr =  buf[0].phys;
+	dma_buf->bytes = runtime->hw.buffer_bytes_max;
+	if (!dma_buf->area)
+		return -ENOMEM;
+
+	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+	return 0;
+}
+
+static struct snd_pcm_ops msm_pcm_ops = {
+	.open           = msm_pcm_open,
+	.copy		= msm_pcm_copy,
+	.hw_params	= msm_pcm_hw_params,
+	.close          = msm_pcm_close,
+	.ioctl          = snd_pcm_lib_ioctl,
+	.prepare        = msm_pcm_prepare,
+	.trigger        = msm_pcm_trigger,
+	.pointer        = msm_pcm_pointer,
+	.mmap		= msm_pcm_mmap,
+};
+
+static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_card *card = rtd->card->snd_card;
+	int ret = 0;
+
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+	return ret;
+}
+
+static struct snd_soc_platform_driver msm_soc_platform = {
+	.ops		= &msm_pcm_ops,
+	.pcm_new	= msm_asoc_pcm_new,
+};
+
+static __devinit int msm_pcm_probe(struct platform_device *pdev)
+{
+	pr_info("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
+	return snd_soc_register_platform(&pdev->dev,
+				   &msm_soc_platform);
+}
+
+static int msm_pcm_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_platform(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver msm_pcm_driver = {
+	.driver = {
+		.name = "msm-multi-ch-pcm-dsp",
+		.owner = THIS_MODULE,
+	},
+	.probe = msm_pcm_probe,
+	.remove = __devexit_p(msm_pcm_remove),
+};
+
+static int __init msm_soc_platform_init(void)
+{
+	init_waitqueue_head(&the_locks.enable_wait);
+	init_waitqueue_head(&the_locks.eos_wait);
+	init_waitqueue_head(&the_locks.write_wait);
+	init_waitqueue_head(&the_locks.read_wait);
+
+	return platform_driver_register(&msm_pcm_driver);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+	platform_driver_unregister(&msm_pcm_driver);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("Multi channel PCM module platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
new file mode 100644
index 0000000..4593784
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
@@ -0,0 +1,581 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 2 and
+* only version 2 as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*/
+
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/android_pmem.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <sound/q6adm-v2.h>
+#include <asm/dma.h>
+#include "msm-pcm-afe-v2.h"
+
+#define MIN_PERIOD_SIZE (128 * 2)
+#define MAX_PERIOD_SIZE (128 * 2 * 2 * 6)
+static struct snd_pcm_hardware msm_afe_hardware = {
+	.info =			(SNDRV_PCM_INFO_MMAP |
+				SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				SNDRV_PCM_INFO_MMAP_VALID |
+				SNDRV_PCM_INFO_INTERLEAVED),
+	.formats =              SNDRV_PCM_FMTBIT_S16_LE,
+	.rates =                (SNDRV_PCM_RATE_8000 |
+				SNDRV_PCM_RATE_16000 |
+				SNDRV_PCM_RATE_48000),
+	.rate_min =             8000,
+	.rate_max =             48000,
+	.channels_min =         1,
+	.channels_max =         2,
+	.buffer_bytes_max =     MAX_PERIOD_SIZE * 32,
+	.period_bytes_min =     MIN_PERIOD_SIZE,
+	.period_bytes_max =     MAX_PERIOD_SIZE,
+	.periods_min =          32,
+	.periods_max =          384,
+	.fifo_size =            0,
+};
+static enum hrtimer_restart afe_hrtimer_callback(struct hrtimer *hrt);
+static enum hrtimer_restart afe_hrtimer_rec_callback(struct hrtimer *hrt);
+
+static enum hrtimer_restart afe_hrtimer_callback(struct hrtimer *hrt)
+{
+	struct pcm_afe_info *prtd =
+		container_of(hrt, struct pcm_afe_info, hrt);
+	struct snd_pcm_substream *substream = prtd->substream;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	u32 mem_map_handle = 0;
+	if (prtd->start) {
+		pr_debug("sending frame to DSP: poll_time: %d\n",
+				prtd->poll_time);
+		if (prtd->dsp_cnt == runtime->periods)
+			prtd->dsp_cnt = 0;
+		pr_debug("%s: mem_map_handle 0x%x\n", __func__, mem_map_handle);
+		afe_rt_proxy_port_write(
+		(prtd->dma_addr +
+		(prtd->dsp_cnt *
+		snd_pcm_lib_period_bytes(prtd->substream))), mem_map_handle,
+		snd_pcm_lib_period_bytes(prtd->substream));
+		prtd->dsp_cnt++;
+		hrtimer_forward_now(hrt, ns_to_ktime(prtd->poll_time
+					* 1000));
+
+		return HRTIMER_RESTART;
+	} else
+		return HRTIMER_NORESTART;
+}
+static enum hrtimer_restart afe_hrtimer_rec_callback(struct hrtimer *hrt)
+{
+	struct pcm_afe_info *prtd =
+		container_of(hrt, struct pcm_afe_info, hrt);
+	struct snd_pcm_substream *substream = prtd->substream;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	u32 mem_map_handle = 0;
+	if (prtd->start) {
+		if (prtd->dsp_cnt == runtime->periods)
+			prtd->dsp_cnt = 0;
+		pr_err("%s: mem_map_handle 0x%x\n", __func__, mem_map_handle);
+		afe_rt_proxy_port_read(
+		(prtd->dma_addr + (prtd->dsp_cnt
+		* snd_pcm_lib_period_bytes(prtd->substream))), mem_map_handle,
+		snd_pcm_lib_period_bytes(prtd->substream));
+		prtd->dsp_cnt++;
+		pr_debug("sending frame rec to DSP: poll_time: %d\n",
+				prtd->poll_time);
+		hrtimer_forward_now(hrt, ns_to_ktime(prtd->poll_time
+				* 1000));
+
+		return HRTIMER_RESTART;
+	} else
+		return HRTIMER_NORESTART;
+}
+static void pcm_afe_process_tx_pkt(uint32_t opcode,
+		uint32_t token, uint32_t *payload,
+		 void *priv)
+{
+	struct pcm_afe_info *prtd = priv;
+	unsigned long dsp_flags;
+	struct snd_pcm_substream *substream = NULL;
+	struct snd_pcm_runtime *runtime = NULL;
+	uint16_t event;
+
+	if (prtd == NULL)
+		return;
+	substream =  prtd->substream;
+	runtime = substream->runtime;
+	pr_debug("%s\n", __func__);
+	spin_lock_irqsave(&prtd->dsp_lock, dsp_flags);
+	switch (opcode) {
+	case AFE_EVENT_RT_PROXY_PORT_STATUS: {
+		event = (uint16_t)((0xFFFF0000 & payload[0]) >> 0x10);
+			switch (event) {
+			case AFE_EVENT_RTPORT_START: {
+				prtd->dsp_cnt = 0;
+				prtd->poll_time = ((unsigned long)((
+						snd_pcm_lib_period_bytes
+						(prtd->substream) *
+						1000 * 1000)/
+						(runtime->rate *
+						runtime->channels * 2)));
+				pr_debug("prtd->poll_time: %d",
+						prtd->poll_time);
+				hrtimer_start(&prtd->hrt,
+					ns_to_ktime(0),
+					HRTIMER_MODE_REL);
+				break;
+			}
+			case AFE_EVENT_RTPORT_STOP:
+				pr_debug("%s: event!=0\n", __func__);
+				prtd->start = 0;
+				snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
+				break;
+			case AFE_EVENT_RTPORT_LOW_WM:
+				pr_debug("%s: Underrun\n", __func__);
+				break;
+			case AFE_EVENT_RTPORT_HI_WM:
+				pr_debug("%s: Overrun\n", __func__);
+				break;
+			default:
+				break;
+			}
+			break;
+	}
+	case APR_BASIC_RSP_RESULT: {
+		switch (payload[0]) {
+		case AFE_PORT_DATA_CMD_RT_PROXY_PORT_WRITE_V2:
+			pr_debug("write done\n");
+			prtd->pcm_irq_pos += snd_pcm_lib_period_bytes
+							(prtd->substream);
+			snd_pcm_period_elapsed(prtd->substream);
+			break;
+		default:
+			break;
+		}
+		break;
+	}
+	default:
+		break;
+	}
+	spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
+}
+
+static void pcm_afe_process_rx_pkt(uint32_t opcode,
+		uint32_t token, uint32_t *payload,
+		 void *priv)
+{
+	struct pcm_afe_info *prtd = priv;
+	unsigned long dsp_flags;
+	struct snd_pcm_substream *substream = NULL;
+	struct snd_pcm_runtime *runtime = NULL;
+	uint16_t event;
+
+	if (prtd == NULL)
+		return;
+	substream =  prtd->substream;
+	runtime = substream->runtime;
+	pr_debug("%s\n", __func__);
+	spin_lock_irqsave(&prtd->dsp_lock, dsp_flags);
+	switch (opcode) {
+	case AFE_EVENT_RT_PROXY_PORT_STATUS: {
+		event = (uint16_t)((0xFFFF0000 & payload[0]) >> 0x10);
+		switch (event) {
+		case AFE_EVENT_RTPORT_START: {
+			prtd->dsp_cnt = 0;
+			prtd->poll_time = ((unsigned long)((
+				snd_pcm_lib_period_bytes(prtd->substream)
+					* 1000 * 1000)/(runtime->rate
+					* runtime->channels * 2)));
+			hrtimer_start(&prtd->hrt,
+				ns_to_ktime(0),
+				HRTIMER_MODE_REL);
+			pr_debug("prtd->poll_time : %d", prtd->poll_time);
+			break;
+		}
+		case AFE_EVENT_RTPORT_STOP:
+			pr_debug("%s: event!=0\n", __func__);
+			prtd->start = 0;
+			snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
+			break;
+		case AFE_EVENT_RTPORT_LOW_WM:
+			pr_debug("%s: Underrun\n", __func__);
+			break;
+		case AFE_EVENT_RTPORT_HI_WM:
+			pr_debug("%s: Overrun\n", __func__);
+			break;
+		default:
+			break;
+		}
+		break;
+	}
+	case APR_BASIC_RSP_RESULT: {
+		switch (payload[0]) {
+		case AFE_PORT_DATA_CMD_RT_PROXY_PORT_READ_V2:
+			pr_debug("Read done\n");
+			prtd->pcm_irq_pos += snd_pcm_lib_period_bytes
+							(prtd->substream);
+			snd_pcm_period_elapsed(prtd->substream);
+			break;
+		default:
+			break;
+		}
+		break;
+	}
+	default:
+		break;
+	}
+	spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
+}
+
+static int msm_afe_playback_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct pcm_afe_info *prtd = runtime->private_data;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *dai = rtd->cpu_dai;
+	int ret = 0;
+
+	pr_debug("%s: sample_rate=%d\n", __func__, runtime->rate);
+
+	pr_debug("%s: dai->id =%x\n", __func__, dai->id);
+	ret = afe_register_get_events(dai->id,
+			pcm_afe_process_tx_pkt, prtd);
+	if (ret < 0) {
+		pr_err("afe-pcm:register for events failed\n");
+		return ret;
+	}
+	pr_debug("%s:success\n", __func__);
+	prtd->prepared++;
+	return ret;
+}
+
+static int msm_afe_capture_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct pcm_afe_info *prtd = runtime->private_data;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *dai = rtd->cpu_dai;
+	int ret = 0;
+
+	pr_debug("%s\n", __func__);
+
+	pr_debug("%s: dai->id =%x\n", __func__, dai->id);
+	ret = afe_register_get_events(dai->id,
+			pcm_afe_process_rx_pkt, prtd);
+	if (ret < 0) {
+		pr_err("afe-pcm:register for events failed\n");
+		return ret;
+	}
+	pr_debug("%s:success\n", __func__);
+	prtd->prepared++;
+	return 0;
+}
+
+/* Conventional and unconventional sample rate supported */
+static unsigned int supported_sample_rates[] = {
+	8000, 16000, 48000
+};
+
+static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
+	.count = ARRAY_SIZE(supported_sample_rates),
+	.list = supported_sample_rates,
+	.mask = 0,
+};
+
+static int msm_afe_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct pcm_afe_info *prtd = NULL;
+	int ret = 0;
+
+	prtd = kzalloc(sizeof(struct pcm_afe_info), GFP_KERNEL);
+	if (prtd == NULL) {
+		pr_err("Failed to allocate memory for msm_audio\n");
+		return -ENOMEM;
+	} else
+		pr_debug("prtd %x\n", (unsigned int)prtd);
+
+	mutex_init(&prtd->lock);
+	spin_lock_init(&prtd->dsp_lock);
+	prtd->dsp_cnt = 0;
+
+	mutex_lock(&prtd->lock);
+
+	runtime->hw = msm_afe_hardware;
+	prtd->substream = substream;
+	runtime->private_data = prtd;
+	mutex_unlock(&prtd->lock);
+	hrtimer_init(&prtd->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		prtd->hrt.function = afe_hrtimer_callback;
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		prtd->hrt.function = afe_hrtimer_rec_callback;
+
+	ret = snd_pcm_hw_constraint_list(runtime, 0,
+				SNDRV_PCM_HW_PARAM_RATE,
+				&constraints_sample_rates);
+	if (ret < 0)
+		pr_err("snd_pcm_hw_constraint_list failed\n");
+	/* Ensure that buffer size is a multiple of period size */
+	ret = snd_pcm_hw_constraint_integer(runtime,
+					    SNDRV_PCM_HW_PARAM_PERIODS);
+	if (ret < 0)
+		pr_err("snd_pcm_hw_constraint_integer failed\n");
+
+	return 0;
+}
+
+static int msm_afe_close(struct snd_pcm_substream *substream)
+{
+	int rc = 0;
+	struct snd_dma_buffer *dma_buf;
+	struct snd_pcm_runtime *runtime;
+	struct pcm_afe_info *prtd;
+	struct snd_soc_pcm_runtime *rtd = NULL;
+	struct snd_soc_dai *dai = NULL;
+	int ret = 0;
+
+	pr_debug("%s\n", __func__);
+	if (substream == NULL) {
+		pr_err("substream is NULL\n");
+		return -EINVAL;
+	}
+	rtd = substream->private_data;
+	dai = rtd->cpu_dai;
+	runtime = substream->runtime;
+	prtd = runtime->private_data;
+
+	mutex_lock(&prtd->lock);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		ret =  afe_unregister_get_events(dai->id);
+		if (ret < 0)
+			pr_err("AFE unregister for events failed\n");
+	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		ret =  afe_unregister_get_events(dai->id);
+		if (ret < 0)
+			pr_err("AFE unregister for events failed\n");
+	}
+	hrtimer_cancel(&prtd->hrt);
+
+	rc = afe_cmd_memory_unmap(runtime->dma_addr);
+	if (rc < 0)
+		pr_err("AFE memory unmap failed\n");
+
+	pr_debug("release all buffer\n");
+	dma_buf = &substream->dma_buffer;
+	if (dma_buf == NULL) {
+		pr_debug("dma_buf is NULL\n");
+			goto done;
+		}
+	if (dma_buf->area != NULL) {
+		dma_free_coherent(substream->pcm->card->dev,
+			runtime->hw.buffer_bytes_max, dma_buf->area,
+			dma_buf->addr);
+		dma_buf->area = NULL;
+	}
+done:
+	pr_debug("%s: dai->id =%x\n", __func__, dai->id);
+	mutex_unlock(&prtd->lock);
+	prtd->prepared--;
+	kfree(prtd);
+	return 0;
+}
+static int msm_afe_prepare(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct pcm_afe_info *prtd = runtime->private_data;
+
+	prtd->pcm_irq_pos = 0;
+	if (prtd->prepared)
+		return 0;
+	mutex_lock(&prtd->lock);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = msm_afe_playback_prepare(substream);
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		ret = msm_afe_capture_prepare(substream);
+	mutex_unlock(&prtd->lock);
+	return ret;
+}
+static int msm_afe_mmap(struct snd_pcm_substream *substream,
+				struct vm_area_struct *vma)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct pcm_afe_info *prtd = runtime->private_data;
+
+	pr_debug("%s\n", __func__);
+	prtd->mmap_flag = 1;
+	dma_mmap_coherent(substream->pcm->card->dev, vma,
+				runtime->dma_area,
+				runtime->dma_addr,
+				runtime->dma_bytes);
+	return 0;
+}
+static int msm_afe_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	int ret = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct pcm_afe_info *prtd = runtime->private_data;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		pr_debug("%s: SNDRV_PCM_TRIGGER_START\n", __func__);
+		prtd->start = 1;
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		pr_debug("%s: SNDRV_PCM_TRIGGER_STOP\n", __func__);
+		prtd->start = 0;
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+static int msm_afe_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
+	struct pcm_afe_info *prtd = runtime->private_data;
+	int rc;
+
+	pr_debug("%s:\n", __func__);
+
+	mutex_lock(&prtd->lock);
+
+	dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
+	dma_buf->dev.dev = substream->pcm->card->dev;
+	dma_buf->private_data = NULL;
+	dma_buf->area = dma_alloc_coherent(dma_buf->dev.dev,
+				runtime->hw.buffer_bytes_max,
+				&dma_buf->addr, GFP_KERNEL);
+
+	pr_debug("%s: dma_buf->area: 0x%p, dma_buf->addr: 0x%x", __func__,
+			(unsigned int *) dma_buf->area, dma_buf->addr);
+	if (!dma_buf->area) {
+		pr_err("%s:MSM AFE memory allocation failed\n", __func__);
+		mutex_unlock(&prtd->lock);
+		return -ENOMEM;
+	}
+	dma_buf->bytes = runtime->hw.buffer_bytes_max;
+	memset(dma_buf->area, 0, runtime->hw.buffer_bytes_max);
+	prtd->dma_addr = (u32) dma_buf->addr;
+
+	mutex_unlock(&prtd->lock);
+
+	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+
+	rc = afe_cmd_memory_map(dma_buf->addr, dma_buf->bytes);
+	if (rc < 0)
+		pr_err("fail to map memory to DSP\n");
+
+	return rc;
+}
+static snd_pcm_uframes_t msm_afe_pointer(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct pcm_afe_info *prtd = runtime->private_data;
+
+	if (prtd->pcm_irq_pos >= snd_pcm_lib_buffer_bytes(substream))
+		prtd->pcm_irq_pos = 0;
+
+	pr_debug("pcm_irq_pos = %d\n", prtd->pcm_irq_pos);
+	return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
+}
+
+static struct snd_pcm_ops msm_afe_ops = {
+	.open           = msm_afe_open,
+	.hw_params	= msm_afe_hw_params,
+	.trigger	= msm_afe_trigger,
+	.close          = msm_afe_close,
+	.prepare        = msm_afe_prepare,
+	.mmap		= msm_afe_mmap,
+	.pointer	= msm_afe_pointer,
+};
+
+
+static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_card *card = rtd->card->snd_card;
+	int ret = 0;
+
+	pr_debug("%s\n", __func__);
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+	return ret;
+}
+
+static int msm_afe_afe_probe(struct snd_soc_platform *platform)
+{
+	pr_debug("%s\n", __func__);
+	return 0;
+}
+
+static struct snd_soc_platform_driver msm_soc_platform = {
+	.ops		= &msm_afe_ops,
+	.pcm_new	= msm_asoc_pcm_new,
+	.probe		= msm_afe_afe_probe,
+};
+
+static __devinit int msm_afe_probe(struct platform_device *pdev)
+{
+	pr_debug("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
+	return snd_soc_register_platform(&pdev->dev,
+				   &msm_soc_platform);
+}
+
+static int msm_afe_remove(struct platform_device *pdev)
+{
+	pr_debug("%s\n", __func__);
+	snd_soc_unregister_platform(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver msm_afe_driver = {
+	.driver = {
+		.name = "msm-pcm-afe",
+		.owner = THIS_MODULE,
+	},
+	.probe = msm_afe_probe,
+	.remove = __devexit_p(msm_afe_remove),
+};
+
+static int __init msm_soc_platform_init(void)
+{
+	pr_debug("%s\n", __func__);
+	return platform_driver_register(&msm_afe_driver);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+	pr_debug("%s\n", __func__);
+	platform_driver_unregister(&msm_afe_driver);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("AFE PCM module platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.h
new file mode 100644
index 0000000..20d6377
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.h
@@ -0,0 +1,45 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef _MSM_PCM_AFE_H
+#define _MSM_PCM_AFE_H
+#include <sound/apr_audio-v2.h>
+#include <sound/q6afe-v2.h>
+
+
+struct pcm_afe_info {
+	unsigned long dma_addr;
+	struct snd_pcm_substream *substream;
+	unsigned int pcm_irq_pos;       /* IRQ position */
+	struct mutex lock;
+	spinlock_t dsp_lock;
+	uint32_t samp_rate;
+	uint32_t channel_mode;
+	uint8_t start;
+	uint32_t dsp_cnt;
+	uint32_t buf_phys;
+	int32_t mmap_flag;
+	int prepared;
+	struct hrtimer hrt;
+	int poll_time;
+};
+
+
+#define MSM_EXT(xname, fp_info, fp_get, fp_put, addr) \
+	{.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+	.name = xname, \
+	.info = fp_info,\
+	.get = fp_get, .put = fp_put, \
+	.private_value = addr, \
+	}
+
+#endif /*_MSM_PCM_AFE_H*/
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
new file mode 100644
index 0000000..ee92753
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
@@ -0,0 +1,609 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <asm/dma.h>
+#include <linux/dma-mapping.h>
+#include <linux/android_pmem.h>
+#include <sound/snd_compress_params.h>
+#include <sound/compress_offload.h>
+#include <sound/compress_driver.h>
+#include <sound/timer.h>
+
+#include "msm-pcm-q6-v2.h"
+#include "msm-pcm-routing-v2.h"
+
+static struct audio_locks the_locks;
+
+struct snd_msm {
+	struct msm_audio *prtd;
+	unsigned volume;
+};
+static struct snd_msm lpa_audio;
+
+static struct snd_pcm_hardware msm_pcm_hardware = {
+	.info =                 (SNDRV_PCM_INFO_MMAP |
+				SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				SNDRV_PCM_INFO_MMAP_VALID |
+				SNDRV_PCM_INFO_INTERLEAVED |
+				SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+	.formats =              SNDRV_PCM_FMTBIT_S16_LE,
+	.rates =                SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT,
+	.rate_min =             8000,
+	.rate_max =             48000,
+	.channels_min =         1,
+	.channels_max =         2,
+	.buffer_bytes_max =     2 * 1024 * 1024,
+	.period_bytes_min =	128 * 1024,
+	.period_bytes_max =     512 * 1024,
+	.periods_min =          4,
+	.periods_max =          16,
+	.fifo_size =            0,
+};
+
+/* Conventional and unconventional sample rate supported */
+static unsigned int supported_sample_rates[] = {
+	8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+};
+
+static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
+	.count = ARRAY_SIZE(supported_sample_rates),
+	.list = supported_sample_rates,
+	.mask = 0,
+};
+
+static void event_handler(uint32_t opcode,
+		uint32_t token, uint32_t *payload, void *priv)
+{
+	struct msm_audio *prtd = priv;
+	struct snd_pcm_substream *substream = prtd->substream;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct audio_aio_write_param param;
+	struct audio_buffer *buf = NULL;
+	unsigned long flag = 0;
+	int i = 0;
+
+	pr_debug("%s\n", __func__);
+	spin_lock_irqsave(&the_locks.event_lock, flag);
+	switch (opcode) {
+	case ASM_DATA_EVENT_WRITE_DONE_V2: {
+		uint32_t *ptrmem = (uint32_t *)&param;
+		pr_debug("ASM_DATA_EVENT_WRITE_DONE_V2\n");
+		pr_debug("Buffer Consumed = 0x%08x\n", *ptrmem);
+		prtd->pcm_irq_pos += prtd->pcm_count;
+		if (prtd->pcm_irq_pos >= prtd->pcm_size)
+			prtd->pcm_irq_pos = 0;
+		if (atomic_read(&prtd->start))
+			snd_pcm_period_elapsed(substream);
+		else
+			if (substream->timer_running)
+				snd_timer_interrupt(substream->timer, 1);
+
+		atomic_inc(&prtd->out_count);
+		wake_up(&the_locks.write_wait);
+		if (!atomic_read(&prtd->start)) {
+			atomic_set(&prtd->pending_buffer, 1);
+			break;
+		} else
+			atomic_set(&prtd->pending_buffer, 0);
+		if (runtime->status->hw_ptr >= runtime->control->appl_ptr)
+			break;
+		pr_debug("%s:writing %d bytes of buffer to dsp 2\n",
+				__func__, prtd->pcm_count);
+
+		buf = prtd->audio_client->port[IN].buf;
+		param.paddr = (unsigned long)buf[0].phys
+				+ (prtd->out_head * prtd->pcm_count);
+		param.len = prtd->pcm_count;
+		param.msw_ts = 0;
+		param.lsw_ts = 0;
+		param.flags = NO_TIMESTAMP;
+		param.uid =  (unsigned long)buf[0].phys
+				+ (prtd->out_head * prtd->pcm_count);
+		for (i = 0; i < sizeof(struct audio_aio_write_param)/4;
+					i++, ++ptrmem)
+			pr_debug("cmd[%d]=0x%08x\n", i, *ptrmem);
+		if (q6asm_async_write(prtd->audio_client,
+					&param) < 0)
+			pr_err("%s:q6asm_async_write failed\n",
+				__func__);
+		else
+			prtd->out_head =
+				(prtd->out_head + 1) & (runtime->periods - 1);
+		atomic_set(&prtd->pending_buffer, 0);
+		break;
+	}
+	case ASM_DATA_EVENT_RENDERED_EOS:
+		pr_debug("ASM_DATA_CMDRSP_EOS\n");
+		prtd->cmd_ack = 1;
+		wake_up(&the_locks.eos_wait);
+		break;
+	case APR_BASIC_RSP_RESULT: {
+		switch (payload[0]) {
+		case ASM_SESSION_CMD_RUN_V2: {
+			if (!atomic_read(&prtd->pending_buffer))
+				break;
+			if (runtime->status->hw_ptr >=
+				runtime->control->appl_ptr)
+				break;
+			pr_debug("%s:writing %d bytes"
+				" of buffer to dsp\n",
+				__func__, prtd->pcm_count);
+			buf = prtd->audio_client->port[IN].buf;
+			param.paddr = (unsigned long)buf[prtd->out_head].phys;
+			param.len = prtd->pcm_count;
+			param.msw_ts = 0;
+			param.lsw_ts = 0;
+			param.flags = NO_TIMESTAMP;
+			param.uid =  (unsigned long)buf[prtd->out_head].phys;
+			if (q6asm_async_write(prtd->audio_client,
+						&param) < 0)
+				pr_err("%s:q6asm_async_write failed\n",
+					__func__);
+			else
+				prtd->out_head =
+					(prtd->out_head + 1)
+					& (runtime->periods - 1);
+			atomic_set(&prtd->pending_buffer, 0);
+		}
+			break;
+		case ASM_STREAM_CMD_FLUSH:
+			pr_debug("ASM_STREAM_CMD_FLUSH\n");
+			prtd->cmd_ack = 1;
+			wake_up(&the_locks.eos_wait);
+			break;
+		default:
+			break;
+		}
+		break;
+	}
+	default:
+		pr_debug("Not Supported Event opcode[0x%x]\n", opcode);
+		break;
+	}
+	spin_unlock_irqrestore(&the_locks.event_lock, flag);
+}
+
+static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+	int ret;
+
+	pr_debug("%s\n", __func__);
+	prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
+	prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
+	prtd->pcm_irq_pos = 0;
+	/* rate and channels are sent to audio driver */
+	prtd->samp_rate = runtime->rate;
+	prtd->channel_mode = runtime->channels;
+	prtd->out_head = 0;
+	if (prtd->enabled)
+		return 0;
+
+	ret = q6asm_media_format_block_pcm(prtd->audio_client, runtime->rate,
+				runtime->channels);
+	if (ret < 0)
+		pr_debug("%s: CMD Format block failed\n", __func__);
+
+	atomic_set(&prtd->out_count, runtime->periods);
+	prtd->enabled = 1;
+	prtd->cmd_ack = 0;
+	return 0;
+}
+
+static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	int ret = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+	pr_debug("%s\n", __func__);
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		prtd->pcm_irq_pos = 0;
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		pr_debug("SNDRV_PCM_TRIGGER_START\n");
+		q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
+		atomic_set(&prtd->start, 1);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
+		atomic_set(&prtd->start, 0);
+		if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
+			break;
+		break;
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		pr_debug("SNDRV_PCM_TRIGGER_PAUSE\n");
+		q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
+		atomic_set(&prtd->start, 0);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static int msm_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+	struct msm_audio *prtd;
+	struct asm_softpause_params softpause = {
+		.enable = SOFT_PAUSE_ENABLE,
+		.period = SOFT_PAUSE_PERIOD,
+		.step = SOFT_PAUSE_STEP,
+		.rampingcurve = SOFT_PAUSE_CURVE_LINEAR,
+	};
+	struct asm_softvolume_params softvol = {
+		.period = SOFT_VOLUME_PERIOD,
+		.step = SOFT_VOLUME_STEP,
+		.rampingcurve = SOFT_VOLUME_CURVE_LINEAR,
+	};
+	int ret = 0;
+
+	pr_debug("%s\n", __func__);
+	prtd = kzalloc(sizeof(struct msm_audio), GFP_KERNEL);
+	if (prtd == NULL) {
+		pr_err("Failed to allocate memory for msm_audio\n");
+		return -ENOMEM;
+	}
+	runtime->hw = msm_pcm_hardware;
+	prtd->substream = substream;
+	prtd->audio_client = q6asm_audio_client_alloc(
+				(app_cb)event_handler, prtd);
+	if (!prtd->audio_client) {
+		pr_debug("%s: Could not allocate memory\n", __func__);
+		kfree(prtd);
+		return -ENOMEM;
+	}
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		ret = q6asm_open_write(prtd->audio_client, FORMAT_LINEAR_PCM);
+		if (ret < 0) {
+			pr_err("%s: pcm out open failed\n", __func__);
+			q6asm_audio_client_free(prtd->audio_client);
+			kfree(prtd);
+			return -ENOMEM;
+		}
+		ret = q6asm_set_io_mode(prtd->audio_client, ASYNC_IO_MODE);
+		if (ret < 0) {
+			pr_err("%s: Set IO mode failed\n", __func__);
+			q6asm_audio_client_free(prtd->audio_client);
+			kfree(prtd);
+			return -ENOMEM;
+		}
+	}
+	/* Capture path */
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		return -EPERM;
+	pr_debug("%s: session ID %d\n", __func__, prtd->audio_client->session);
+	prtd->session_id = prtd->audio_client->session;
+	msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
+		prtd->session_id, substream->stream);
+
+	ret = snd_pcm_hw_constraint_list(runtime, 0,
+				SNDRV_PCM_HW_PARAM_RATE,
+				&constraints_sample_rates);
+	if (ret < 0)
+		pr_debug("snd_pcm_hw_constraint_list failed\n");
+	/* Ensure that buffer size is a multiple of period size */
+	ret = snd_pcm_hw_constraint_integer(runtime,
+					    SNDRV_PCM_HW_PARAM_PERIODS);
+	if (ret < 0)
+		pr_debug("snd_pcm_hw_constraint_integer failed\n");
+
+	prtd->dsp_cnt = 0;
+	atomic_set(&prtd->pending_buffer, 1);
+	runtime->private_data = prtd;
+	lpa_audio.prtd = prtd;
+	lpa_set_volume(lpa_audio.volume);
+	ret = q6asm_set_softpause(lpa_audio.prtd->audio_client, &softpause);
+	if (ret < 0)
+		pr_err("%s: Send SoftPause Param failed ret=%d\n",
+			__func__, ret);
+	ret = q6asm_set_softvolume(lpa_audio.prtd->audio_client, &softvol);
+	if (ret < 0)
+		pr_err("%s: Send SoftVolume Param failed ret=%d\n",
+			__func__, ret);
+
+	return 0;
+}
+
+int lpa_set_volume(unsigned volume)
+{
+	int rc = 0;
+	if (lpa_audio.prtd && lpa_audio.prtd->audio_client) {
+		rc = q6asm_set_volume(lpa_audio.prtd->audio_client, volume);
+		if (rc < 0) {
+			pr_err("%s: Send Volume command failed"
+					" rc=%d\n", __func__, rc);
+		}
+	}
+	lpa_audio.volume = volume;
+	return rc;
+}
+
+static int msm_pcm_playback_close(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+	struct msm_audio *prtd = runtime->private_data;
+	int dir = 0;
+	int rc = 0;
+
+	/*
+	If routing is still enabled, we need to issue EOS to
+	the DSP
+	To issue EOS to dsp, we need to be run state otherwise
+	EOS is not honored.
+	*/
+	if (msm_routing_check_backend_enabled(soc_prtd->dai_link->be_id)) {
+		rc = q6asm_run(prtd->audio_client, 0, 0, 0);
+		atomic_set(&prtd->pending_buffer, 0);
+		prtd->cmd_ack = 0;
+		q6asm_cmd_nowait(prtd->audio_client, CMD_EOS);
+		pr_debug("%s\n", __func__);
+		rc = wait_event_timeout(the_locks.eos_wait,
+			prtd->cmd_ack, 5 * HZ);
+		if (rc < 0)
+			pr_err("EOS cmd timeout\n");
+		prtd->pcm_irq_pos = 0;
+	}
+
+	dir = IN;
+	atomic_set(&prtd->pending_buffer, 0);
+	lpa_audio.prtd = NULL;
+	q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+	q6asm_audio_client_buf_free_contiguous(dir,
+				prtd->audio_client);
+
+	pr_debug("%s\n", __func__);
+	msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
+		SNDRV_PCM_STREAM_PLAYBACK);
+	pr_debug("%s\n", __func__);
+	q6asm_audio_client_free(prtd->audio_client);
+	kfree(prtd);
+
+	return 0;
+}
+
+static int msm_pcm_close(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = msm_pcm_playback_close(substream);
+	return ret;
+}
+
+static int msm_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = msm_pcm_playback_prepare(substream);
+	return ret;
+}
+
+static snd_pcm_uframes_t msm_pcm_pointer(struct snd_pcm_substream *substream)
+{
+
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	pr_debug("%s: pcm_irq_pos = %d\n", __func__, prtd->pcm_irq_pos);
+	return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
+}
+
+static int msm_pcm_mmap(struct snd_pcm_substream *substream,
+				struct vm_area_struct *vma)
+{
+	int result = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	pr_debug("%s\n", __func__);
+	prtd->mmap_flag = 1;
+
+	if (runtime->dma_addr && runtime->dma_bytes) {
+		vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+		result = remap_pfn_range(vma, vma->vm_start,
+				runtime->dma_addr >> PAGE_SHIFT,
+				runtime->dma_bytes,
+				vma->vm_page_prot);
+	} else {
+		pr_err("Physical address or size of buf is NULL");
+		return -EINVAL;
+	}
+	return result;
+}
+
+static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+	struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
+	struct audio_buffer *buf;
+	int dir, ret;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		dir = IN;
+	else
+		return -EPERM;
+	ret = q6asm_audio_client_buf_alloc_contiguous(dir,
+			prtd->audio_client,
+			runtime->hw.period_bytes_min,
+			runtime->hw.periods_max);
+	if (ret < 0) {
+		pr_err("Audio Start: Buffer Allocation failed "
+					"rc = %d\n", ret);
+		return -ENOMEM;
+	}
+	buf = prtd->audio_client->port[dir].buf;
+
+	if (buf == NULL || buf[0].data == NULL)
+		return -ENOMEM;
+
+	pr_debug("%s:buf = %p\n", __func__, buf);
+	dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
+	dma_buf->dev.dev = substream->pcm->card->dev;
+	dma_buf->private_data = NULL;
+	dma_buf->area = buf[0].data;
+	dma_buf->addr =  buf[0].phys;
+	dma_buf->bytes = runtime->hw.buffer_bytes_max;
+	if (!dma_buf->area)
+		return -ENOMEM;
+
+	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+	return 0;
+}
+
+static int msm_pcm_ioctl(struct snd_pcm_substream *substream,
+		unsigned int cmd, void *arg)
+{
+	int rc = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+	uint64_t timestamp;
+	uint64_t temp;
+
+	switch (cmd) {
+	case SNDRV_COMPRESS_TSTAMP: {
+		struct snd_compr_tstamp tstamp;
+		pr_debug("SNDRV_COMPRESS_TSTAMP\n");
+
+		memset(&tstamp, 0x0, sizeof(struct snd_compr_tstamp));
+		timestamp = q6asm_get_session_time(prtd->audio_client);
+		if (timestamp < 0) {
+			pr_err("%s: Get Session Time return value =%lld\n",
+				__func__, timestamp);
+			return -EAGAIN;
+		}
+		temp = (timestamp * 2 * runtime->channels);
+		temp = temp * (runtime->rate/1000);
+		temp = div_u64(temp, 1000);
+		tstamp.sampling_rate = runtime->rate;
+		tstamp.rendered = (size_t)(temp & 0xFFFFFFFF);
+		tstamp.decoded  = (size_t)((temp >> 32) & 0xFFFFFFFF);
+		tstamp.timestamp = timestamp;
+		pr_debug("%s: bytes_consumed:lsb = %d, msb = %d,"
+			"timestamp = %lld,\n",
+			__func__, tstamp.rendered, tstamp.decoded,
+			tstamp.timestamp);
+		if (copy_to_user((void *) arg, &tstamp,
+			sizeof(struct snd_compr_tstamp)))
+			return -EFAULT;
+		return 0;
+	}
+	case SNDRV_PCM_IOCTL1_RESET:
+		prtd->cmd_ack = 0;
+		rc = q6asm_cmd(prtd->audio_client, CMD_FLUSH);
+		if (rc < 0)
+			pr_err("%s: flush cmd failed rc=%d\n", __func__, rc);
+		rc = wait_event_timeout(the_locks.eos_wait,
+			prtd->cmd_ack, 5 * HZ);
+		if (rc < 0)
+			pr_err("Flush cmd timeout\n");
+		prtd->pcm_irq_pos = 0;
+		break;
+	default:
+		break;
+	}
+	return snd_pcm_lib_ioctl(substream, cmd, arg);
+}
+
+static struct snd_pcm_ops msm_pcm_ops = {
+	.open           = msm_pcm_open,
+	.hw_params	= msm_pcm_hw_params,
+	.close          = msm_pcm_close,
+	.ioctl          = msm_pcm_ioctl,
+	.prepare        = msm_pcm_prepare,
+	.trigger        = msm_pcm_trigger,
+	.pointer        = msm_pcm_pointer,
+	.mmap		= msm_pcm_mmap,
+};
+
+static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_card *card = rtd->card->snd_card;
+	int ret = 0;
+
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+	return ret;
+}
+
+static struct snd_soc_platform_driver msm_soc_platform = {
+	.ops		= &msm_pcm_ops,
+	.pcm_new	= msm_asoc_pcm_new,
+};
+
+static __devinit int msm_pcm_probe(struct platform_device *pdev)
+{
+	dev_info(&pdev->dev, "%s: dev name %s\n",
+			__func__, dev_name(&pdev->dev));
+	return snd_soc_register_platform(&pdev->dev,
+				&msm_soc_platform);
+}
+
+static int msm_pcm_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_platform(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver msm_pcm_driver = {
+	.driver = {
+		.name = "msm-pcm-lpa",
+		.owner = THIS_MODULE,
+	},
+	.probe = msm_pcm_probe,
+	.remove = __devexit_p(msm_pcm_remove),
+};
+
+static int __init msm_soc_platform_init(void)
+{
+	spin_lock_init(&the_locks.event_lock);
+	init_waitqueue_head(&the_locks.enable_wait);
+	init_waitqueue_head(&the_locks.eos_wait);
+	init_waitqueue_head(&the_locks.write_wait);
+	init_waitqueue_head(&the_locks.read_wait);
+
+	return platform_driver_register(&msm_pcm_driver);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+	platform_driver_unregister(&msm_pcm_driver);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("PCM module platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
new file mode 100644
index 0000000..f94e6c1
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -0,0 +1,725 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <asm/dma.h>
+#include <linux/dma-mapping.h>
+#include <linux/android_pmem.h>
+
+#include "msm-pcm-q6-v2.h"
+#include "msm-pcm-routing-v2.h"
+
+static struct audio_locks the_locks;
+
+struct snd_msm {
+	struct snd_card *card;
+	struct snd_pcm *pcm;
+};
+
+#define PLAYBACK_NUM_PERIODS	8
+#define PLAYBACK_PERIOD_SIZE	2048
+#define CAPTURE_NUM_PERIODS	16
+#define CAPTURE_PERIOD_SIZE	512
+
+static struct snd_pcm_hardware msm_pcm_hardware_capture = {
+	.info =                 (SNDRV_PCM_INFO_MMAP |
+				SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				SNDRV_PCM_INFO_MMAP_VALID |
+				SNDRV_PCM_INFO_INTERLEAVED |
+				SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+	.formats =              SNDRV_PCM_FMTBIT_S16_LE,
+	.rates =                SNDRV_PCM_RATE_8000_48000,
+	.rate_min =             8000,
+	.rate_max =             48000,
+	.channels_min =         1,
+	.channels_max =         2,
+	.buffer_bytes_max =     CAPTURE_NUM_PERIODS * CAPTURE_PERIOD_SIZE,
+	.period_bytes_min =	CAPTURE_PERIOD_SIZE,
+	.period_bytes_max =     CAPTURE_PERIOD_SIZE,
+	.periods_min =          CAPTURE_NUM_PERIODS,
+	.periods_max =          CAPTURE_NUM_PERIODS,
+	.fifo_size =            0,
+};
+
+static struct snd_pcm_hardware msm_pcm_hardware_playback = {
+	.info =                 (SNDRV_PCM_INFO_MMAP |
+				SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				SNDRV_PCM_INFO_MMAP_VALID |
+				SNDRV_PCM_INFO_INTERLEAVED |
+				SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+	.formats =              SNDRV_PCM_FMTBIT_S16_LE,
+	.rates =                SNDRV_PCM_RATE_8000_48000,
+	.rate_min =             8000,
+	.rate_max =             48000,
+	.channels_min =         1,
+	.channels_max =         2,
+	.buffer_bytes_max =     PLAYBACK_NUM_PERIODS * PLAYBACK_PERIOD_SIZE,
+	.period_bytes_min =	PLAYBACK_PERIOD_SIZE,
+	.period_bytes_max =     PLAYBACK_PERIOD_SIZE,
+	.periods_min =          PLAYBACK_NUM_PERIODS,
+	.periods_max =          PLAYBACK_NUM_PERIODS,
+	.fifo_size =            0,
+};
+
+/* Conventional and unconventional sample rate supported */
+static unsigned int supported_sample_rates[] = {
+	8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+};
+
+static uint32_t in_frame_info[CAPTURE_NUM_PERIODS][2];
+
+static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
+	.count = ARRAY_SIZE(supported_sample_rates),
+	.list = supported_sample_rates,
+	.mask = 0,
+};
+
+static void event_handler(uint32_t opcode,
+		uint32_t token, uint32_t *payload, void *priv)
+{
+	struct msm_audio *prtd = priv;
+	struct snd_pcm_substream *substream = prtd->substream;
+	uint32_t *ptrmem = (uint32_t *)payload;
+	uint32_t idx = 0;
+	uint32_t size = 0;
+
+	pr_err("%s\n", __func__);
+	switch (opcode) {
+	case ASM_DATA_EVENT_WRITE_DONE_V2: {
+		pr_debug("ASM_DATA_EVENT_WRITE_DONE_V2\n");
+		pr_debug("Buffer Consumed = 0x%08x\n", *ptrmem);
+		prtd->pcm_irq_pos += prtd->pcm_count;
+		if (atomic_read(&prtd->start))
+			snd_pcm_period_elapsed(substream);
+		atomic_inc(&prtd->out_count);
+		wake_up(&the_locks.write_wait);
+		if (!atomic_read(&prtd->start))
+			break;
+		if (!prtd->mmap_flag)
+			break;
+		if (q6asm_is_cpu_buf_avail_nolock(IN,
+				prtd->audio_client,
+				&size, &idx)) {
+			pr_debug("%s:writing %d bytes of buffer to dsp 2\n",
+					__func__, prtd->pcm_count);
+			q6asm_write_nolock(prtd->audio_client,
+				prtd->pcm_count, 0, 0, NO_TIMESTAMP);
+		}
+		break;
+	}
+	case ASM_DATA_EVENT_RENDERED_EOS:
+		pr_debug("ASM_DATA_EVENT_RENDERED_EOS\n");
+		prtd->cmd_ack = 1;
+		wake_up(&the_locks.eos_wait);
+		break;
+	case ASM_DATA_EVENT_READ_DONE_V2: {
+		pr_debug("ASM_DATA_EVENT_READ_DONE_V2\n");
+		pr_debug("token = 0x%08x\n", token);
+		in_frame_info[token][0] = payload[4];
+		in_frame_info[token][1] = payload[5];
+		prtd->pcm_irq_pos += in_frame_info[token][0];
+		pr_debug("pcm_irq_pos=%d\n", prtd->pcm_irq_pos);
+		if (atomic_read(&prtd->start))
+			snd_pcm_period_elapsed(substream);
+		if (atomic_read(&prtd->in_count) <= prtd->periods)
+			atomic_inc(&prtd->in_count);
+		wake_up(&the_locks.read_wait);
+		if (prtd->mmap_flag
+			&& q6asm_is_cpu_buf_avail_nolock(OUT,
+				prtd->audio_client,
+				&size, &idx))
+			q6asm_read_nolock(prtd->audio_client);
+		break;
+	}
+	case APR_BASIC_RSP_RESULT: {
+		switch (payload[0]) {
+		case ASM_SESSION_CMD_RUN_V2:
+			if (substream->stream
+				!= SNDRV_PCM_STREAM_PLAYBACK) {
+				atomic_set(&prtd->start, 1);
+				break;
+			}
+			if (prtd->mmap_flag) {
+				pr_debug("%s:writing %d bytes"
+					" of buffer to dsp\n",
+					__func__,
+					prtd->pcm_count);
+				q6asm_write_nolock(prtd->audio_client,
+					prtd->pcm_count,
+					0, 0, NO_TIMESTAMP);
+			} else {
+				while (atomic_read(&prtd->out_needed)) {
+					pr_debug("%s:writing %d bytes"
+						 " of buffer to dsp\n",
+						__func__,
+						prtd->pcm_count);
+					q6asm_write_nolock(prtd->audio_client,
+						prtd->pcm_count,
+						0, 0, NO_TIMESTAMP);
+					atomic_dec(&prtd->out_needed);
+					wake_up(&the_locks.write_wait);
+				};
+			}
+			atomic_set(&prtd->start, 1);
+			break;
+		default:
+			pr_debug("%s:Payload = [0x%x]stat[0x%x]\n",
+				__func__, payload[0], payload[1]);
+			break;
+		}
+	}
+	break;
+	default:
+		pr_debug("Not Supported Event opcode[0x%x]\n", opcode);
+		break;
+	}
+}
+
+static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+	int ret;
+
+	pr_debug("%s\n", __func__);
+	prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
+	prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
+	prtd->pcm_irq_pos = 0;
+	/* rate and channels are sent to audio driver */
+	prtd->samp_rate = runtime->rate;
+	prtd->channel_mode = runtime->channels;
+	if (prtd->enabled)
+		return 0;
+
+	ret = q6asm_media_format_block_pcm(prtd->audio_client, runtime->rate,
+				runtime->channels);
+	if (ret < 0)
+		pr_info("%s: CMD Format block failed\n", __func__);
+
+	atomic_set(&prtd->out_count, runtime->periods);
+
+	prtd->enabled = 1;
+	prtd->cmd_ack = 0;
+
+	return 0;
+}
+
+static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+	int ret = 0;
+	int i = 0;
+	pr_debug("%s\n", __func__);
+	prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
+	prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
+	prtd->pcm_irq_pos = 0;
+
+	/* rate and channels are sent to audio driver */
+	prtd->samp_rate = runtime->rate;
+	prtd->channel_mode = runtime->channels;
+
+	if (prtd->enabled)
+		return 0;
+
+	pr_debug("Samp_rate = %d\n", prtd->samp_rate);
+	pr_debug("Channel = %d\n", prtd->channel_mode);
+	ret = q6asm_enc_cfg_blk_pcm(prtd->audio_client, prtd->samp_rate,
+					prtd->channel_mode);
+	if (ret < 0)
+		pr_debug("%s: cmd cfg pcm was block failed", __func__);
+
+	for (i = 0; i < runtime->periods; i++)
+		q6asm_read(prtd->audio_client);
+	prtd->periods = runtime->periods;
+
+	prtd->enabled = 1;
+
+	return ret;
+}
+
+static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	int ret = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		pr_debug("%s: Trigger start\n", __func__);
+		q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
+		atomic_set(&prtd->start, 0);
+		if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
+			break;
+		prtd->cmd_ack = 0;
+		q6asm_cmd_nowait(prtd->audio_client, CMD_EOS);
+		break;
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		pr_debug("SNDRV_PCM_TRIGGER_PAUSE\n");
+		q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
+		atomic_set(&prtd->start, 0);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static int msm_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+	struct msm_audio *prtd;
+	int ret = 0;
+
+	pr_debug("%s\n", __func__);
+	prtd = kzalloc(sizeof(struct msm_audio), GFP_KERNEL);
+	if (prtd == NULL) {
+		pr_err("Failed to allocate memory for msm_audio\n");
+		return -ENOMEM;
+	}
+	prtd->substream = substream;
+	prtd->audio_client = q6asm_audio_client_alloc(
+				(app_cb)event_handler, prtd);
+	if (!prtd->audio_client) {
+		pr_info("%s: Could not allocate memory\n", __func__);
+		kfree(prtd);
+		return -ENOMEM;
+	}
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		runtime->hw = msm_pcm_hardware_playback;
+		ret = q6asm_open_write(prtd->audio_client, FORMAT_LINEAR_PCM);
+		if (ret < 0) {
+			pr_err("%s: pcm out open failed\n", __func__);
+			q6asm_audio_client_free(prtd->audio_client);
+			kfree(prtd);
+			return -ENOMEM;
+		}
+	}
+	/* Capture path */
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		runtime->hw = msm_pcm_hardware_capture;
+		ret = q6asm_open_read(prtd->audio_client, FORMAT_LINEAR_PCM);
+		if (ret < 0) {
+			pr_err("%s: pcm in open failed\n", __func__);
+			q6asm_audio_client_free(prtd->audio_client);
+			kfree(prtd);
+			return -ENOMEM;
+		}
+	}
+
+	pr_debug("%s: session ID %d\n", __func__, prtd->audio_client->session);
+
+	prtd->session_id = prtd->audio_client->session;
+	msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
+			prtd->session_id, substream->stream);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		prtd->cmd_ack = 1;
+
+	ret = snd_pcm_hw_constraint_list(runtime, 0,
+				SNDRV_PCM_HW_PARAM_RATE,
+				&constraints_sample_rates);
+	if (ret < 0)
+		pr_info("snd_pcm_hw_constraint_list failed\n");
+	/* Ensure that buffer size is a multiple of period size */
+	ret = snd_pcm_hw_constraint_integer(runtime,
+					    SNDRV_PCM_HW_PARAM_PERIODS);
+	if (ret < 0)
+		pr_info("snd_pcm_hw_constraint_integer failed\n");
+
+	prtd->dsp_cnt = 0;
+	runtime->private_data = prtd;
+
+	return 0;
+}
+
+static int msm_pcm_playback_copy(struct snd_pcm_substream *substream, int a,
+	snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
+{
+	int ret = 0;
+	int fbytes = 0;
+	int xfer = 0;
+	char *bufptr = NULL;
+	void *data = NULL;
+	uint32_t idx = 0;
+	uint32_t size = 0;
+
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	fbytes = frames_to_bytes(runtime, frames);
+	pr_debug("%s: prtd->out_count = %d\n",
+				__func__, atomic_read(&prtd->out_count));
+	ret = wait_event_timeout(the_locks.write_wait,
+			(atomic_read(&prtd->out_count)), 5 * HZ);
+	if (ret < 0) {
+		pr_err("%s: wait_event_timeout failed\n", __func__);
+		goto fail;
+	}
+
+	if (!atomic_read(&prtd->out_count)) {
+		pr_err("%s: pcm stopped out_count 0\n", __func__);
+		return 0;
+	}
+
+	data = q6asm_is_cpu_buf_avail(IN, prtd->audio_client, &size, &idx);
+	bufptr = data;
+	if (bufptr) {
+		pr_debug("%s:fbytes =%d: xfer=%d size=%d\n",
+					__func__, fbytes, xfer, size);
+		xfer = fbytes;
+		if (copy_from_user(bufptr, buf, xfer)) {
+			ret = -EFAULT;
+			goto fail;
+		}
+		buf += xfer;
+		fbytes -= xfer;
+		pr_debug("%s:fbytes = %d: xfer=%d\n", __func__, fbytes, xfer);
+		if (atomic_read(&prtd->start)) {
+			pr_debug("%s:writing %d bytes of buffer to dsp\n",
+					__func__, xfer);
+			ret = q6asm_write(prtd->audio_client, xfer,
+						0, 0, NO_TIMESTAMP);
+			if (ret < 0) {
+				ret = -EFAULT;
+				goto fail;
+			}
+		} else
+			atomic_inc(&prtd->out_needed);
+		atomic_dec(&prtd->out_count);
+	}
+fail:
+	return  ret;
+}
+
+static int msm_pcm_playback_close(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+	struct msm_audio *prtd = runtime->private_data;
+	int dir = 0;
+	int ret = 0;
+
+	pr_debug("%s\n", __func__);
+
+	dir = IN;
+	ret = wait_event_timeout(the_locks.eos_wait,
+				prtd->cmd_ack, 5 * HZ);
+	if (ret < 0)
+		pr_err("%s: CMD_EOS failed\n", __func__);
+	q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+	q6asm_audio_client_buf_free_contiguous(dir,
+				prtd->audio_client);
+
+	msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
+	SNDRV_PCM_STREAM_PLAYBACK);
+	q6asm_audio_client_free(prtd->audio_client);
+	kfree(prtd);
+	return 0;
+}
+
+static int msm_pcm_capture_copy(struct snd_pcm_substream *substream,
+		 int channel, snd_pcm_uframes_t hwoff, void __user *buf,
+						 snd_pcm_uframes_t frames)
+{
+	int ret = 0;
+	int fbytes = 0;
+	int xfer;
+	char *bufptr;
+	void *data = NULL;
+	static uint32_t idx;
+	static uint32_t size;
+	uint32_t offset = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = substream->runtime->private_data;
+
+
+	pr_debug("%s\n", __func__);
+	fbytes = frames_to_bytes(runtime, frames);
+
+	pr_debug("appl_ptr %d\n", (int)runtime->control->appl_ptr);
+	pr_debug("hw_ptr %d\n", (int)runtime->status->hw_ptr);
+	pr_debug("avail_min %d\n", (int)runtime->control->avail_min);
+
+	ret = wait_event_timeout(the_locks.read_wait,
+			(atomic_read(&prtd->in_count)), 5 * HZ);
+	if (ret < 0) {
+		pr_debug("%s: wait_event_timeout failed\n", __func__);
+		goto fail;
+	}
+	if (!atomic_read(&prtd->in_count)) {
+		pr_debug("%s: pcm stopped in_count 0\n", __func__);
+		return 0;
+	}
+	pr_debug("Checking if valid buffer is available...%08x\n",
+						(unsigned int) data);
+	data = q6asm_is_cpu_buf_avail(OUT, prtd->audio_client, &size, &idx);
+	bufptr = data;
+	pr_debug("Size = %d\n", size);
+	pr_debug("fbytes = %d\n", fbytes);
+	pr_debug("idx = %d\n", idx);
+	if (bufptr) {
+		xfer = fbytes;
+		if (xfer > size)
+			xfer = size;
+		offset = in_frame_info[idx][1];
+		pr_debug("Offset value = %d\n", offset);
+		if (copy_to_user(buf, bufptr+offset, xfer)) {
+			pr_err("Failed to copy buf to user\n");
+			ret = -EFAULT;
+			goto fail;
+		}
+		fbytes -= xfer;
+		size -= xfer;
+		in_frame_info[idx][1] += xfer;
+		pr_debug("%s:fbytes = %d: size=%d: xfer=%d\n",
+					__func__, fbytes, size, xfer);
+		pr_debug(" Sending next buffer to dsp\n");
+		memset(&in_frame_info[idx], 0,
+			sizeof(uint32_t) * 2);
+		atomic_dec(&prtd->in_count);
+		ret = q6asm_read(prtd->audio_client);
+		if (ret < 0) {
+			pr_err("q6asm read failed\n");
+			ret = -EFAULT;
+			goto fail;
+		}
+	} else
+		pr_err("No valid buffer\n");
+
+	pr_debug("Returning from capture_copy... %d\n", ret);
+fail:
+	return ret;
+}
+
+static int msm_pcm_capture_close(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+	struct msm_audio *prtd = runtime->private_data;
+	int dir = OUT;
+
+	pr_debug("%s\n", __func__);
+	q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+	q6asm_audio_client_buf_free_contiguous(dir,
+				prtd->audio_client);
+	msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
+	SNDRV_PCM_STREAM_CAPTURE);
+	q6asm_audio_client_free(prtd->audio_client);
+	kfree(prtd);
+
+	return 0;
+}
+
+static int msm_pcm_copy(struct snd_pcm_substream *substream, int a,
+	 snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
+{
+	int ret = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = msm_pcm_playback_copy(substream, a, hwoff, buf, frames);
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		ret = msm_pcm_capture_copy(substream, a, hwoff, buf, frames);
+	return ret;
+}
+
+static int msm_pcm_close(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = msm_pcm_playback_close(substream);
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		ret = msm_pcm_capture_close(substream);
+	return ret;
+}
+static int msm_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = msm_pcm_playback_prepare(substream);
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		ret = msm_pcm_capture_prepare(substream);
+	return ret;
+}
+
+static snd_pcm_uframes_t msm_pcm_pointer(struct snd_pcm_substream *substream)
+{
+
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	if (prtd->pcm_irq_pos >= prtd->pcm_size)
+		prtd->pcm_irq_pos = 0;
+
+	pr_debug("pcm_irq_pos = %d\n", prtd->pcm_irq_pos);
+	return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
+}
+
+static int msm_pcm_mmap(struct snd_pcm_substream *substream,
+				struct vm_area_struct *vma)
+{
+	int result = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	pr_debug("%s\n", __func__);
+	prtd->mmap_flag = 1;
+
+	if (runtime->dma_addr && runtime->dma_bytes) {
+		vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+		result = remap_pfn_range(vma, vma->vm_start,
+				runtime->dma_addr >> PAGE_SHIFT,
+				runtime->dma_bytes,
+				vma->vm_page_prot);
+	} else {
+		pr_err("Physical address or size of buf is NULL");
+		return -EINVAL;
+	}
+
+	return result;
+}
+
+static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+	struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
+	struct audio_buffer *buf;
+	int dir, ret;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		dir = IN;
+	else
+		dir = OUT;
+pr_err("%s: before buf alloc\n", __func__);
+	ret = q6asm_audio_client_buf_alloc_contiguous(dir,
+			prtd->audio_client,
+			runtime->hw.period_bytes_min,
+			runtime->hw.periods_max);
+	if (ret < 0) {
+		pr_err("Audio Start: Buffer Allocation failed "
+					"rc = %d\n", ret);
+		return -ENOMEM;
+	}
+pr_err("%s: after buf alloc\n", __func__);
+	buf = prtd->audio_client->port[dir].buf;
+	if (buf == NULL || buf[0].data == NULL)
+		return -ENOMEM;
+
+	pr_debug("%s:buf = %p\n", __func__, buf);
+	dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
+	dma_buf->dev.dev = substream->pcm->card->dev;
+	dma_buf->private_data = NULL;
+	dma_buf->area = buf[0].data;
+	dma_buf->addr =  buf[0].phys;
+	dma_buf->bytes = runtime->hw.buffer_bytes_max;
+	if (!dma_buf->area)
+		return -ENOMEM;
+
+	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+	return 0;
+}
+
+static struct snd_pcm_ops msm_pcm_ops = {
+	.open           = msm_pcm_open,
+	.copy		= msm_pcm_copy,
+	.hw_params	= msm_pcm_hw_params,
+	.close          = msm_pcm_close,
+	.ioctl          = snd_pcm_lib_ioctl,
+	.prepare        = msm_pcm_prepare,
+	.trigger        = msm_pcm_trigger,
+	.pointer        = msm_pcm_pointer,
+	.mmap		= msm_pcm_mmap,
+};
+
+static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_card *card = rtd->card->snd_card;
+	int ret = 0;
+
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+	return ret;
+}
+
+static struct snd_soc_platform_driver msm_soc_platform = {
+	.ops		= &msm_pcm_ops,
+	.pcm_new	= msm_asoc_pcm_new,
+};
+
+static __devinit int msm_pcm_probe(struct platform_device *pdev)
+{
+	pr_info("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
+	return snd_soc_register_platform(&pdev->dev,
+				   &msm_soc_platform);
+}
+
+static int msm_pcm_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_platform(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver msm_pcm_driver = {
+	.driver = {
+		.name = "msm-pcm-dsp",
+		.owner = THIS_MODULE,
+	},
+	.probe = msm_pcm_probe,
+	.remove = __devexit_p(msm_pcm_remove),
+};
+
+static int __init msm_soc_platform_init(void)
+{
+	init_waitqueue_head(&the_locks.enable_wait);
+	init_waitqueue_head(&the_locks.eos_wait);
+	init_waitqueue_head(&the_locks.write_wait);
+	init_waitqueue_head(&the_locks.read_wait);
+
+	return platform_driver_register(&msm_pcm_driver);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+	platform_driver_unregister(&msm_pcm_driver);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("PCM module platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h
new file mode 100644
index 0000000..44395b7
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2012 Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org.
+ */
+
+#ifndef _MSM_PCM_H
+#define _MSM_PCM_H
+#include <sound/apr_audio-v2.h>
+#include <sound/q6asm-v2.h>
+
+
+
+/* Support unconventional sample rates 12000, 24000 as well */
+#define USE_RATE                \
+			(SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT)
+
+extern int copy_count;
+
+struct buffer {
+	void *data;
+	unsigned size;
+	unsigned used;
+	unsigned addr;
+};
+
+struct buffer_rec {
+	void *data;
+	unsigned int size;
+	unsigned int read;
+	unsigned int addr;
+};
+
+struct audio_locks {
+	spinlock_t event_lock;
+	wait_queue_head_t read_wait;
+	wait_queue_head_t write_wait;
+	wait_queue_head_t eos_wait;
+	wait_queue_head_t enable_wait;
+};
+
+struct msm_audio {
+	struct snd_pcm_substream *substream;
+	unsigned int pcm_size;
+	unsigned int pcm_count;
+	unsigned int pcm_irq_pos;       /* IRQ position */
+	uint16_t source; /* Encoding source bit mask */
+
+	struct audio_client *audio_client;
+
+	uint16_t session_id;
+
+	uint32_t samp_rate;
+	uint32_t channel_mode;
+	uint32_t dsp_cnt;
+
+	int abort; /* set when error, like sample rate mismatch */
+
+	int enabled;
+	int close_ack;
+	int cmd_ack;
+	atomic_t start;
+	atomic_t out_count;
+	atomic_t in_count;
+	atomic_t out_needed;
+	int out_head;
+	int periods;
+	int mmap_flag;
+	atomic_t pending_buffer;
+};
+
+#endif /*_MSM_PCM_H*/
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
new file mode 100644
index 0000000..2eebae5
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -0,0 +1,1834 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/bitops.h>
+#include <linux/mutex.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <sound/q6adm-v2.h>
+#include <sound/q6asm-v2.h>
+#include <sound/q6afe-v2.h>
+#include <sound/tlv.h>
+#include "msm-pcm-routing-v2.h"
+#include "../qdsp6/q6voice.h"
+
+struct msm_pcm_routing_bdai_data {
+	u16 port_id; /* AFE port ID */
+	u8 active; /* track if this backend is enabled */
+	struct snd_pcm_hw_params *hw_params; /* to get freq and channel mode */
+	unsigned long fe_sessions; /* Front-end sessions */
+	unsigned long port_sessions; /* track Tx BE ports -> Rx BE */
+};
+
+#define INVALID_SESSION -1
+#define SESSION_TYPE_RX 0
+#define SESSION_TYPE_TX 1
+
+static struct mutex routing_lock;
+
+static int fm_switch_enable;
+
+#define INT_FM_RX_VOL_MAX_STEPS 100
+#define INT_FM_RX_VOL_GAIN 2000
+
+static int msm_route_fm_vol_control;
+static const DECLARE_TLV_DB_SCALE(fm_rx_vol_gain, 0,
+			INT_FM_RX_VOL_MAX_STEPS, 0);
+
+#define INT_RX_VOL_MAX_STEPS 100
+#define INT_RX_VOL_GAIN 0x2000
+
+static int msm_route_lpa_vol_control;
+static const DECLARE_TLV_DB_SCALE(lpa_rx_vol_gain, 0,
+			INT_RX_VOL_MAX_STEPS, 0);
+
+static int msm_route_multimedia2_vol_control;
+static const DECLARE_TLV_DB_SCALE(multimedia2_rx_vol_gain, 0,
+			INT_RX_VOL_MAX_STEPS, 0);
+
+static int msm_route_compressed_vol_control;
+static const DECLARE_TLV_DB_SCALE(compressed_rx_vol_gain, 0,
+			INT_RX_VOL_MAX_STEPS, 0);
+
+
+
+/* Equal to Frontend after last of the MULTIMEDIA SESSIONS */
+#define MAX_EQ_SESSIONS		MSM_FRONTEND_DAI_CS_VOICE
+
+enum {
+	EQ_BAND1 = 0,
+	EQ_BAND2,
+	EQ_BAND3,
+	EQ_BAND4,
+	EQ_BAND5,
+	EQ_BAND6,
+	EQ_BAND7,
+	EQ_BAND8,
+	EQ_BAND9,
+	EQ_BAND10,
+	EQ_BAND11,
+	EQ_BAND12,
+	EQ_BAND_MAX,
+};
+
+struct msm_audio_eq_band {
+	uint16_t     band_idx; /* The band index, 0 .. 11 */
+	uint32_t     filter_type; /* Filter band type */
+	uint32_t     center_freq_hz; /* Filter band center frequency */
+	uint32_t     filter_gain; /* Filter band initial gain (dB) */
+			/* Range is +12 dB to -12 dB with 1dB increments. */
+	uint32_t     q_factor;
+} __packed;
+
+struct msm_audio_eq_stream_config {
+	uint32_t	enable; /* Number of consequtive bands specified */
+	uint32_t	num_bands;
+	struct msm_audio_eq_band	eq_bands[EQ_BAND_MAX];
+} __packed;
+
+struct msm_audio_eq_stream_config	eq_data[MAX_EQ_SESSIONS];
+
+static void msm_send_eq_values(int eq_idx);
+/* This array is indexed by back-end DAI ID defined in msm-pcm-routing.h
+ * If new back-end is defined, add new back-end DAI ID at the end of enum
+ */
+static struct msm_pcm_routing_bdai_data msm_bedais[MSM_BACKEND_DAI_MAX] = {
+	{ PRIMARY_I2S_RX, 0, NULL, 0, 0},
+	{ PRIMARY_I2S_TX, 0, NULL, 0, 0},
+	{ SLIMBUS_0_RX, 0, NULL, 0, 0},
+	{ SLIMBUS_0_TX, 0, NULL, 0, 0},
+	{ HDMI_RX, 0, NULL,  0, 0},
+	{ INT_BT_SCO_RX, 0, NULL, 0, 0},
+	{ INT_BT_SCO_TX, 0, NULL, 0, 0},
+	{ INT_FM_RX, 0, NULL, 0, 0},
+	{ INT_FM_TX, 0, NULL, 0, 0},
+	{ RT_PROXY_PORT_001_RX, 0, NULL, 0, 0},
+	{ RT_PROXY_PORT_001_TX, 0, NULL, 0, 0},
+	{ PCM_RX, 0, NULL, 0, 0},
+	{ PCM_TX, 0, NULL, 0, 0},
+	{ VOICE_PLAYBACK_TX, 0, NULL, 0, 0},
+	{ VOICE_RECORD_RX, 0, NULL, 0, 0},
+	{ VOICE_RECORD_TX, 0, NULL, 0, 0},
+	{ MI2S_RX, 0, NULL, 0, 0},
+	{ SECONDARY_I2S_RX, 0, NULL, 0, 0},
+	{ SLIMBUS_1_RX, 0, NULL, 0, 0},
+	{ SLIMBUS_1_TX, 0, NULL, 0, 0},
+	{ SLIMBUS_INVALID, 0, NULL, 0, 0},
+};
+
+
+/* Track ASM playback & capture sessions of DAI */
+static int fe_dai_map[MSM_FRONTEND_DAI_MM_SIZE][2] = {
+	/* MULTIMEDIA1 */
+	{INVALID_SESSION, INVALID_SESSION},
+	/* MULTIMEDIA2 */
+	{INVALID_SESSION, INVALID_SESSION},
+	/* MULTIMEDIA3 */
+	{INVALID_SESSION, INVALID_SESSION},
+	/* MULTIMEDIA4 */
+	{INVALID_SESSION, INVALID_SESSION},
+};
+
+static void msm_pcm_routing_build_matrix(int fedai_id, int dspst_id,
+	int path_type)
+{
+	int i, port_type;
+	struct route_payload payload;
+
+	payload.num_copps = 0;
+	port_type = (path_type == ADM_PATH_PLAYBACK ?
+		MSM_AFE_PORT_TYPE_RX : MSM_AFE_PORT_TYPE_TX);
+
+	for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
+		if ((afe_get_port_type(msm_bedais[i].port_id) ==
+			port_type) &&
+			msm_bedais[i].active && (test_bit(fedai_id,
+				&msm_bedais[i].fe_sessions)))
+			payload.copp_ids[payload.num_copps++] =
+					msm_bedais[i].port_id;
+	}
+
+	if (payload.num_copps)
+		adm_matrix_map(dspst_id, path_type,
+			payload.num_copps, payload.copp_ids, 0);
+}
+
+void msm_pcm_routing_reg_phy_stream(int fedai_id, int dspst_id, int stream_type)
+{
+	int i, session_type, path_type, port_type;
+	struct route_payload payload;
+	u32 channels;
+
+	if (fedai_id > MSM_FRONTEND_DAI_MM_MAX_ID) {
+		/* bad ID assigned in machine driver */
+		pr_err("%s: bad MM ID %d\n", __func__, fedai_id);
+		return;
+	}
+
+	if (stream_type == SNDRV_PCM_STREAM_PLAYBACK) {
+		session_type = SESSION_TYPE_RX;
+		path_type = ADM_PATH_PLAYBACK;
+		port_type = MSM_AFE_PORT_TYPE_RX;
+	} else {
+		session_type = SESSION_TYPE_TX;
+		path_type = ADM_PATH_LIVE_REC;
+		port_type = MSM_AFE_PORT_TYPE_TX;
+	}
+
+	mutex_lock(&routing_lock);
+
+	payload.num_copps = 0; /* only RX needs to use payload */
+	fe_dai_map[fedai_id][session_type] = dspst_id;
+	/* re-enable EQ if active */
+	if (eq_data[fedai_id].enable)
+		msm_send_eq_values(fedai_id);
+	for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
+		if ((afe_get_port_type(msm_bedais[i].port_id) ==
+			port_type) && msm_bedais[i].active &&
+			(test_bit(fedai_id,
+			&msm_bedais[i].fe_sessions))) {
+
+			channels = params_channels(msm_bedais[i].hw_params);
+
+			if ((stream_type == SNDRV_PCM_STREAM_PLAYBACK) &&
+				(channels > 2))
+				adm_multi_ch_copp_open(msm_bedais[i].port_id,
+				path_type,
+				params_rate(msm_bedais[i].hw_params),
+				channels,
+				DEFAULT_COPP_TOPOLOGY);
+			else
+				adm_open(msm_bedais[i].port_id,
+				path_type,
+				params_rate(msm_bedais[i].hw_params),
+				params_channels(msm_bedais[i].hw_params),
+				DEFAULT_COPP_TOPOLOGY);
+
+			payload.copp_ids[payload.num_copps++] =
+				msm_bedais[i].port_id;
+		}
+	}
+	if (payload.num_copps)
+		adm_matrix_map(dspst_id, path_type,
+			payload.num_copps, payload.copp_ids, 0);
+
+	mutex_unlock(&routing_lock);
+}
+
+void msm_pcm_routing_dereg_phy_stream(int fedai_id, int stream_type)
+{
+	int i, port_type, session_type;
+
+	if (fedai_id > MSM_FRONTEND_DAI_MM_MAX_ID) {
+		/* bad ID assigned in machine driver */
+		pr_err("%s: bad MM ID\n", __func__);
+		return;
+	}
+
+	if (stream_type == SNDRV_PCM_STREAM_PLAYBACK) {
+		port_type = MSM_AFE_PORT_TYPE_RX;
+		session_type = SESSION_TYPE_RX;
+	} else {
+		port_type = MSM_AFE_PORT_TYPE_TX;
+		session_type = SESSION_TYPE_TX;
+	}
+
+	mutex_lock(&routing_lock);
+
+	for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
+		if ((afe_get_port_type(msm_bedais[i].port_id) ==
+			port_type) && msm_bedais[i].active &&
+			(test_bit(fedai_id,
+			&msm_bedais[i].fe_sessions)))
+			adm_close(msm_bedais[i].port_id);
+	}
+
+	fe_dai_map[fedai_id][session_type] = INVALID_SESSION;
+
+	mutex_unlock(&routing_lock);
+}
+
+/* Check if FE/BE route is set */
+static bool msm_pcm_routing_route_is_set(u16 be_id, u16 fe_id)
+{
+	bool rc = false;
+
+	if (fe_id > MSM_FRONTEND_DAI_MM_MAX_ID) {
+		/* recheck FE ID in the mixer control defined in this file */
+		pr_err("%s: bad MM ID\n", __func__);
+		return rc;
+	}
+
+	if (test_bit(fe_id, &msm_bedais[be_id].fe_sessions))
+		rc = true;
+
+	return rc;
+}
+
+static void msm_pcm_routing_process_audio(u16 reg, u16 val, int set)
+{
+	int session_type, path_type;
+	u32 channels;
+
+	pr_debug("%s: reg %x val %x set %x\n", __func__, reg, val, set);
+
+	if (val > MSM_FRONTEND_DAI_MM_MAX_ID) {
+		/* recheck FE ID in the mixer control defined in this file */
+		pr_err("%s: bad MM ID\n", __func__);
+		return;
+	}
+
+	if (afe_get_port_type(msm_bedais[reg].port_id) ==
+		MSM_AFE_PORT_TYPE_RX) {
+		session_type = SESSION_TYPE_RX;
+		path_type = ADM_PATH_PLAYBACK;
+	} else {
+		session_type = SESSION_TYPE_TX;
+		path_type = ADM_PATH_LIVE_REC;
+	}
+
+	mutex_lock(&routing_lock);
+
+	if (set) {
+		set_bit(val, &msm_bedais[reg].fe_sessions);
+		if (msm_bedais[reg].active && fe_dai_map[val][session_type] !=
+			INVALID_SESSION) {
+
+			channels = params_channels(msm_bedais[reg].hw_params);
+
+			if ((session_type == SESSION_TYPE_RX) && (channels > 2))
+				adm_multi_ch_copp_open(msm_bedais[reg].port_id,
+				path_type,
+				params_rate(msm_bedais[reg].hw_params),
+				channels,
+				DEFAULT_COPP_TOPOLOGY);
+			else
+				adm_open(msm_bedais[reg].port_id,
+				path_type,
+				params_rate(msm_bedais[reg].hw_params),
+				params_channels(msm_bedais[reg].hw_params),
+				DEFAULT_COPP_TOPOLOGY);
+
+			msm_pcm_routing_build_matrix(val,
+				fe_dai_map[val][session_type], path_type);
+		}
+	} else {
+		clear_bit(val, &msm_bedais[reg].fe_sessions);
+		if (msm_bedais[reg].active && fe_dai_map[val][session_type] !=
+			INVALID_SESSION) {
+			adm_close(msm_bedais[reg].port_id);
+			msm_pcm_routing_build_matrix(val,
+				fe_dai_map[val][session_type], path_type);
+		}
+	}
+	mutex_unlock(&routing_lock);
+}
+
+static int msm_routing_get_audio_mixer(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+	(struct soc_mixer_control *)kcontrol->private_value;
+
+	if (test_bit(mc->shift, &msm_bedais[mc->reg].fe_sessions))
+		ucontrol->value.integer.value[0] = 1;
+	else
+		ucontrol->value.integer.value[0] = 0;
+
+	pr_info("%s: reg %x shift %x val %ld\n", __func__, mc->reg, mc->shift,
+	ucontrol->value.integer.value[0]);
+
+	return 0;
+}
+
+static int msm_routing_put_audio_mixer(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+
+
+	if (ucontrol->value.integer.value[0] &&
+	    msm_pcm_routing_route_is_set(mc->reg, mc->shift) == false) {
+		msm_pcm_routing_process_audio(mc->reg, mc->shift, 1);
+		snd_soc_dapm_mixer_update_power(widget, kcontrol, 1);
+	} else if (!ucontrol->value.integer.value[0] &&
+		   msm_pcm_routing_route_is_set(mc->reg, mc->shift) == true) {
+		msm_pcm_routing_process_audio(mc->reg, mc->shift, 0);
+		snd_soc_dapm_mixer_update_power(widget, kcontrol, 0);
+	}
+	pr_info("%s: reg %x shift %x val %ld\n", __func__, mc->reg, mc->shift,
+					ucontrol->value.integer.value[0]);
+
+	return 1;
+}
+
+static void msm_pcm_routing_process_voice(u16 reg, u16 val, int set)
+{
+	return;
+}
+
+static int msm_routing_get_voice_mixer(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+	(struct soc_mixer_control *)kcontrol->private_value;
+
+	mutex_lock(&routing_lock);
+
+	if (test_bit(mc->shift, &msm_bedais[mc->reg].fe_sessions))
+		ucontrol->value.integer.value[0] = 1;
+	else
+		ucontrol->value.integer.value[0] = 0;
+
+	mutex_unlock(&routing_lock);
+
+	pr_debug("%s: reg %x shift %x val %ld\n", __func__, mc->reg, mc->shift,
+			ucontrol->value.integer.value[0]);
+
+	return 0;
+}
+
+static int msm_routing_put_voice_mixer(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+
+	if (ucontrol->value.integer.value[0]) {
+		msm_pcm_routing_process_voice(mc->reg, mc->shift, 1);
+		snd_soc_dapm_mixer_update_power(widget, kcontrol, 1);
+	} else {
+		msm_pcm_routing_process_voice(mc->reg, mc->shift, 0);
+		snd_soc_dapm_mixer_update_power(widget, kcontrol, 0);
+	}
+
+	return 1;
+}
+
+static int msm_routing_get_voice_stub_mixer(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+
+	mutex_lock(&routing_lock);
+
+	if (test_bit(mc->shift, &msm_bedais[mc->reg].fe_sessions))
+		ucontrol->value.integer.value[0] = 1;
+	else
+		ucontrol->value.integer.value[0] = 0;
+
+	mutex_unlock(&routing_lock);
+
+	pr_debug("%s: reg %x shift %x val %ld\n", __func__, mc->reg, mc->shift,
+		ucontrol->value.integer.value[0]);
+
+	return 0;
+}
+
+static int msm_routing_put_voice_stub_mixer(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+
+	if (ucontrol->value.integer.value[0]) {
+		mutex_lock(&routing_lock);
+		set_bit(mc->shift, &msm_bedais[mc->reg].fe_sessions);
+		mutex_unlock(&routing_lock);
+
+		snd_soc_dapm_mixer_update_power(widget, kcontrol, 1);
+	} else {
+		mutex_lock(&routing_lock);
+		clear_bit(mc->shift, &msm_bedais[mc->reg].fe_sessions);
+		mutex_unlock(&routing_lock);
+
+		snd_soc_dapm_mixer_update_power(widget, kcontrol, 0);
+	}
+
+	pr_debug("%s: reg %x shift %x val %ld\n", __func__, mc->reg, mc->shift,
+		ucontrol->value.integer.value[0]);
+
+	return 1;
+}
+
+static int msm_routing_get_switch_mixer(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = fm_switch_enable;
+	pr_debug("%s: FM Switch enable %ld\n", __func__,
+		ucontrol->value.integer.value[0]);
+	return 0;
+}
+
+static int msm_routing_put_switch_mixer(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+
+	pr_debug("%s: FM Switch enable %ld\n", __func__,
+			ucontrol->value.integer.value[0]);
+	if (ucontrol->value.integer.value[0])
+		snd_soc_dapm_mixer_update_power(widget, kcontrol, 1);
+	else
+		snd_soc_dapm_mixer_update_power(widget, kcontrol, 0);
+	fm_switch_enable = ucontrol->value.integer.value[0];
+	return 1;
+}
+
+static int msm_routing_get_port_mixer(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+	(struct soc_mixer_control *)kcontrol->private_value;
+
+	if (test_bit(mc->shift, &msm_bedais[mc->reg].port_sessions))
+		ucontrol->value.integer.value[0] = 1;
+	else
+		ucontrol->value.integer.value[0] = 0;
+
+	pr_debug("%s: reg %x shift %x val %ld\n", __func__, mc->reg, mc->shift,
+	ucontrol->value.integer.value[0]);
+
+	return 0;
+}
+
+static int msm_routing_put_port_mixer(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+
+	pr_debug("%s: reg %x shift %x val %ld\n", __func__, mc->reg,
+		mc->shift, ucontrol->value.integer.value[0]);
+
+	if (ucontrol->value.integer.value[0]) {
+		afe_loopback(1, msm_bedais[mc->reg].port_id,
+			     msm_bedais[mc->shift].port_id);
+		set_bit(mc->shift,
+		&msm_bedais[mc->reg].port_sessions);
+	} else {
+		afe_loopback(0, msm_bedais[mc->reg].port_id,
+			     msm_bedais[mc->shift].port_id);
+		clear_bit(mc->shift,
+		&msm_bedais[mc->reg].port_sessions);
+	}
+
+	return 1;
+}
+
+static int msm_routing_get_fm_vol_mixer(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = msm_route_fm_vol_control;
+	return 0;
+}
+
+static int msm_routing_set_fm_vol_mixer(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	afe_loopback_gain(INT_FM_TX , ucontrol->value.integer.value[0]);
+
+	msm_route_fm_vol_control = ucontrol->value.integer.value[0];
+
+	return 0;
+}
+
+static int msm_routing_get_lpa_vol_mixer(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = msm_route_lpa_vol_control;
+	return 0;
+}
+
+static int msm_routing_set_lpa_vol_mixer(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	if (!lpa_set_volume(ucontrol->value.integer.value[0]))
+		msm_route_lpa_vol_control =
+			ucontrol->value.integer.value[0];
+
+	return 0;
+
+}
+
+static int msm_routing_get_multimedia2_vol_mixer(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+
+	ucontrol->value.integer.value[0] = msm_route_multimedia2_vol_control;
+	return 0;
+}
+
+static int msm_routing_set_multimedia2_vol_mixer(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	if (!multi_ch_pcm_set_volume(ucontrol->value.integer.value[0]))
+		msm_route_multimedia2_vol_control =
+			ucontrol->value.integer.value[0];
+	return 0;
+}
+
+static int msm_routing_get_compressed_vol_mixer(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+
+	ucontrol->value.integer.value[0] = msm_route_compressed_vol_control;
+	return 0;
+}
+
+static int msm_routing_set_compressed_vol_mixer(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	if (!compressed_set_volume(ucontrol->value.integer.value[0]))
+		msm_route_compressed_vol_control =
+			ucontrol->value.integer.value[0];
+	return 0;
+}
+
+static void msm_send_eq_values(int eq_idx)
+{
+	int result;
+	struct audio_client *ac =
+		q6asm_get_audio_client(fe_dai_map[eq_idx][SESSION_TYPE_RX]);
+
+	if (ac == NULL) {
+		pr_err("%s: Could not get audio client for session: %d\n",
+		       __func__, fe_dai_map[eq_idx][SESSION_TYPE_RX]);
+		goto done;
+	}
+
+	result = q6asm_equalizer(ac, &eq_data[eq_idx]);
+
+	if (result < 0)
+		pr_err("%s: Call to ASM equalizer failed, returned = %d\n",
+		       __func__, result);
+done:
+	return;
+}
+
+static int msm_routing_get_eq_enable_mixer(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	int eq_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->reg;
+
+	ucontrol->value.integer.value[0] = eq_data[eq_idx].enable;
+
+	pr_debug("%s: EQ #%d enable %d\n", __func__,
+		eq_idx, eq_data[eq_idx].enable);
+	return 0;
+}
+
+static int msm_routing_put_eq_enable_mixer(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	int eq_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->reg;
+	int value = ucontrol->value.integer.value[0];
+
+	pr_debug("%s: EQ #%d enable %d\n", __func__,
+		eq_idx, value);
+	eq_data[eq_idx].enable = value;
+
+	msm_send_eq_values(eq_idx);
+	return 0;
+}
+
+static int msm_routing_get_eq_band_count_audio_mixer(
+					struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	int eq_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->reg;
+
+	ucontrol->value.integer.value[0] = eq_data[eq_idx].num_bands;
+
+	pr_debug("%s: EQ #%d bands %d\n", __func__,
+		eq_idx, eq_data[eq_idx].num_bands);
+	return eq_data[eq_idx].num_bands;
+}
+
+static int msm_routing_put_eq_band_count_audio_mixer(
+					struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	int eq_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->reg;
+	int value = ucontrol->value.integer.value[0];
+
+	pr_debug("%s: EQ #%d bands %d\n", __func__,
+		eq_idx, value);
+	eq_data[eq_idx].num_bands = value;
+	return 0;
+}
+
+static int msm_routing_get_eq_band_audio_mixer(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	int eq_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->reg;
+	int band_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->shift;
+
+	ucontrol->value.integer.value[0] =
+			eq_data[eq_idx].eq_bands[band_idx].band_idx;
+	ucontrol->value.integer.value[1] =
+			eq_data[eq_idx].eq_bands[band_idx].filter_type;
+	ucontrol->value.integer.value[2] =
+			eq_data[eq_idx].eq_bands[band_idx].center_freq_hz;
+	ucontrol->value.integer.value[3] =
+			eq_data[eq_idx].eq_bands[band_idx].filter_gain;
+	ucontrol->value.integer.value[4] =
+			eq_data[eq_idx].eq_bands[band_idx].q_factor;
+
+	pr_debug("%s: band_idx = %d\n", __func__,
+			eq_data[eq_idx].eq_bands[band_idx].band_idx);
+	pr_debug("%s: filter_type = %d\n", __func__,
+			eq_data[eq_idx].eq_bands[band_idx].filter_type);
+	pr_debug("%s: center_freq_hz = %d\n", __func__,
+			eq_data[eq_idx].eq_bands[band_idx].center_freq_hz);
+	pr_debug("%s: filter_gain = %d\n", __func__,
+			eq_data[eq_idx].eq_bands[band_idx].filter_gain);
+	pr_debug("%s: q_factor = %d\n", __func__,
+			eq_data[eq_idx].eq_bands[band_idx].q_factor);
+	return 0;
+}
+
+static int msm_routing_put_eq_band_audio_mixer(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	int eq_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->reg;
+	int band_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->shift;
+
+	eq_data[eq_idx].eq_bands[band_idx].band_idx =
+					ucontrol->value.integer.value[0];
+	eq_data[eq_idx].eq_bands[band_idx].filter_type =
+					ucontrol->value.integer.value[1];
+	eq_data[eq_idx].eq_bands[band_idx].center_freq_hz =
+					ucontrol->value.integer.value[2];
+	eq_data[eq_idx].eq_bands[band_idx].filter_gain =
+					ucontrol->value.integer.value[3];
+	eq_data[eq_idx].eq_bands[band_idx].q_factor =
+					ucontrol->value.integer.value[4];
+	return 0;
+}
+
+static const struct snd_kcontrol_new pri_i2s_rx_mixer_controls[] = {
+	SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_PRI_I2S_RX ,
+	MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_PRI_I2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_PRI_I2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_PRI_I2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new sec_i2s_rx_mixer_controls[] = {
+	SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_SEC_I2S_RX ,
+	MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_SEC_I2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_SEC_I2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_SEC_I2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new slimbus_rx_mixer_controls[] = {
+	SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_SLIMBUS_0_RX ,
+	MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new mi2s_rx_mixer_controls[] = {
+	SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_MI2S_RX ,
+	MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new hdmi_mixer_controls[] = {
+	SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_HDMI_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_HDMI_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_HDMI_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_HDMI_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+};
+	/* incall music delivery mixer */
+static const struct snd_kcontrol_new incall_music_delivery_mixer_controls[] = {
+	SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new int_bt_sco_rx_mixer_controls[] = {
+	SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new int_fm_rx_mixer_controls[] = {
+	SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_INT_FM_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_INT_FM_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_INT_FM_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_INT_FM_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new afe_pcm_rx_mixer_controls[] = {
+	SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_AFE_PCM_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_AFE_PCM_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_AFE_PCM_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_AFE_PCM_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new auxpcm_rx_mixer_controls[] = {
+	SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_AUXPCM_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_AUXPCM_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_AUXPCM_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_AUXPCM_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new mmul1_mixer_controls[] = {
+	SOC_SINGLE_EXT("PRI_TX", MSM_BACKEND_DAI_PRI_I2S_TX,
+		MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+		msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+		MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+		msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_AUXPCM_TX,
+		MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+		msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX,
+		MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+		msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX,
+		MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+		msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX,
+		MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+		msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("VOC_REC_DL", MSM_BACKEND_DAI_INCALL_RECORD_RX,
+		MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+		msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("VOC_REC_UL", MSM_BACKEND_DAI_INCALL_RECORD_TX,
+		MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+		msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new mmul2_mixer_controls[] = {
+	SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new pri_rx_voice_mixer_controls[] = {
+	SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_PRI_I2S_RX,
+	MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_PRI_I2S_RX,
+	MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+};
+
+static const struct snd_kcontrol_new sec_i2s_rx_voice_mixer_controls[] = {
+	SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_SEC_I2S_RX,
+	MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_SEC_I2S_RX,
+	MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+};
+
+static const struct snd_kcontrol_new slimbus_rx_voice_mixer_controls[] = {
+	SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+	MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_SLIMBUS_0_RX ,
+	MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+};
+
+static const struct snd_kcontrol_new bt_sco_rx_voice_mixer_controls[] = {
+	SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+	MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_INT_BT_SCO_RX ,
+	MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_INT_BT_SCO_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 afe_pcm_rx_voice_mixer_controls[] = {
+	SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_AFE_PCM_RX,
+	MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_AFE_PCM_RX,
+	MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_AFE_PCM_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 aux_pcm_rx_voice_mixer_controls[] = {
+	SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_AUXPCM_RX,
+	MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_AUXPCM_RX,
+	MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_AUXPCM_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 hdmi_rx_voice_mixer_controls[] = {
+	SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_HDMI_RX,
+	MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_HDMI_RX,
+	MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+};
+
+static const struct snd_kcontrol_new stub_rx_mixer_controls[] = {
+	SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_INVALID,
+	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 slimbus_1_rx_mixer_controls[] = {
+	SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_SLIMBUS_1_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 tx_voice_mixer_controls[] = {
+	SOC_SINGLE_EXT("PRI_TX_Voice", MSM_BACKEND_DAI_PRI_I2S_TX,
+	MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("SLIM_0_TX_Voice", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+	MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX_Voice",
+	MSM_BACKEND_DAI_INT_BT_SCO_TX, MSM_FRONTEND_DAI_CS_VOICE, 1, 0,
+	msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("AFE_PCM_TX_Voice", MSM_BACKEND_DAI_AFE_PCM_TX,
+	MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("AUX_PCM_TX_Voice", MSM_BACKEND_DAI_AUXPCM_TX,
+	MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+};
+
+static const struct snd_kcontrol_new tx_voip_mixer_controls[] = {
+	SOC_SINGLE_EXT("PRI_TX_Voip", MSM_BACKEND_DAI_PRI_I2S_TX,
+	MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("SLIM_0_TX_Voip", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+	MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX_Voip", MSM_BACKEND_DAI_INT_BT_SCO_TX,
+	MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("AFE_PCM_TX_Voip", MSM_BACKEND_DAI_AFE_PCM_TX,
+	MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("AUX_PCM_TX_Voip", MSM_BACKEND_DAI_AUXPCM_TX,
+	MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+};
+
+static const struct snd_kcontrol_new tx_voice_stub_mixer_controls[] = {
+	SOC_SINGLE_EXT("STUB_TX_HL", MSM_BACKEND_DAI_INVALID,
+	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+	msm_routing_put_voice_stub_mixer),
+	SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX,
+	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+	msm_routing_put_voice_stub_mixer),
+	SOC_SINGLE_EXT("SLIM_1_TX", MSM_BACKEND_DAI_SLIMBUS_1_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[] = {
+	SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+	MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer,
+	msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+	MSM_BACKEND_DAI_SLIMBUS_0_TX, 1, 0, msm_routing_get_port_mixer,
+	msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+	MSM_BACKEND_DAI_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer,
+	msm_routing_put_port_mixer),
+};
+
+static const struct snd_kcontrol_new auxpcm_rx_port_mixer_controls[] = {
+	SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_AUXPCM_RX,
+	MSM_BACKEND_DAI_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer,
+	msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_AUXPCM_RX,
+	MSM_BACKEND_DAI_SLIMBUS_0_TX, 1, 0, msm_routing_get_port_mixer,
+	msm_routing_put_port_mixer),
+};
+
+static const struct snd_kcontrol_new sbus_1_rx_port_mixer_controls[] = {
+	SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_SLIMBUS_1_RX,
+	MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0, msm_routing_get_port_mixer,
+	msm_routing_put_port_mixer),
+};
+
+static const struct snd_kcontrol_new bt_sco_rx_port_mixer_controls[] = {
+	SOC_SINGLE_EXT("SLIM_1_TX", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+	MSM_BACKEND_DAI_SLIMBUS_1_TX, 1, 0, msm_routing_get_port_mixer,
+	msm_routing_put_port_mixer),
+};
+
+static const struct snd_kcontrol_new fm_switch_mixer_controls =
+	SOC_SINGLE_EXT("Switch", SND_SOC_NOPM,
+	0, 1, 0, msm_routing_get_switch_mixer,
+	msm_routing_put_switch_mixer);
+
+static const struct snd_kcontrol_new int_fm_vol_mixer_controls[] = {
+	SOC_SINGLE_EXT_TLV("Internal FM RX Volume", SND_SOC_NOPM, 0,
+	INT_FM_RX_VOL_GAIN, 0, msm_routing_get_fm_vol_mixer,
+	msm_routing_set_fm_vol_mixer, fm_rx_vol_gain),
+};
+
+static const struct snd_kcontrol_new lpa_vol_mixer_controls[] = {
+	SOC_SINGLE_EXT_TLV("LPA RX Volume", SND_SOC_NOPM, 0,
+	INT_RX_VOL_GAIN, 0, msm_routing_get_lpa_vol_mixer,
+	msm_routing_set_lpa_vol_mixer, lpa_rx_vol_gain),
+};
+
+static const struct snd_kcontrol_new multimedia2_vol_mixer_controls[] = {
+	SOC_SINGLE_EXT_TLV("HIFI2 RX Volume", SND_SOC_NOPM, 0,
+	INT_RX_VOL_GAIN, 0, msm_routing_get_multimedia2_vol_mixer,
+	msm_routing_set_multimedia2_vol_mixer, multimedia2_rx_vol_gain),
+};
+
+static const struct snd_kcontrol_new compressed_vol_mixer_controls[] = {
+	SOC_SINGLE_EXT_TLV("COMPRESSED RX Volume", SND_SOC_NOPM, 0,
+	INT_RX_VOL_GAIN, 0, msm_routing_get_compressed_vol_mixer,
+	msm_routing_set_compressed_vol_mixer, compressed_rx_vol_gain),
+};
+
+static const struct snd_kcontrol_new eq_enable_mixer_controls[] = {
+	SOC_SINGLE_EXT("MultiMedia1 EQ Enable", SND_SOC_NOPM,
+	MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_eq_enable_mixer,
+	msm_routing_put_eq_enable_mixer),
+	SOC_SINGLE_EXT("MultiMedia2 EQ Enable", SND_SOC_NOPM,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_eq_enable_mixer,
+	msm_routing_put_eq_enable_mixer),
+	SOC_SINGLE_EXT("MultiMedia3 EQ Enable", SND_SOC_NOPM,
+	MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_eq_enable_mixer,
+	msm_routing_put_eq_enable_mixer),
+};
+
+static const struct snd_kcontrol_new eq_band_mixer_controls[] = {
+	SOC_SINGLE_EXT("MultiMedia1 EQ Band Count", SND_SOC_NOPM,
+	MSM_FRONTEND_DAI_MULTIMEDIA1, 11, 0,
+	msm_routing_get_eq_band_count_audio_mixer,
+	msm_routing_put_eq_band_count_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia2 EQ Band Count", SND_SOC_NOPM,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 11, 0,
+	msm_routing_get_eq_band_count_audio_mixer,
+	msm_routing_put_eq_band_count_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia3 EQ Band Count", SND_SOC_NOPM,
+	MSM_FRONTEND_DAI_MULTIMEDIA3, 11, 0,
+	msm_routing_get_eq_band_count_audio_mixer,
+	msm_routing_put_eq_band_count_audio_mixer),
+};
+
+static const struct snd_kcontrol_new eq_coeff_mixer_controls[] = {
+	SOC_SINGLE_MULTI_EXT("MultiMedia1 EQ Band1", EQ_BAND1,
+	MSM_FRONTEND_DAI_MULTIMEDIA1, 255, 0, 5,
+	msm_routing_get_eq_band_audio_mixer,
+	msm_routing_put_eq_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("MultiMedia1 EQ Band2", EQ_BAND2,
+	MSM_FRONTEND_DAI_MULTIMEDIA1, 255, 0, 5,
+	msm_routing_get_eq_band_audio_mixer,
+	msm_routing_put_eq_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("MultiMedia1 EQ Band3", EQ_BAND3,
+	MSM_FRONTEND_DAI_MULTIMEDIA1, 255, 0, 5,
+	msm_routing_get_eq_band_audio_mixer,
+	msm_routing_put_eq_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("MultiMedia1 EQ Band4", EQ_BAND4,
+	MSM_FRONTEND_DAI_MULTIMEDIA1, 255, 0, 5,
+	msm_routing_get_eq_band_audio_mixer,
+	msm_routing_put_eq_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("MultiMedia1 EQ Band5", EQ_BAND5,
+	MSM_FRONTEND_DAI_MULTIMEDIA1, 255, 0, 5,
+	msm_routing_get_eq_band_audio_mixer,
+	msm_routing_put_eq_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("MultiMedia1 EQ Band6", EQ_BAND6,
+	MSM_FRONTEND_DAI_MULTIMEDIA1, 255, 0, 5,
+	msm_routing_get_eq_band_audio_mixer,
+	msm_routing_put_eq_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("MultiMedia1 EQ Band7", EQ_BAND7,
+	MSM_FRONTEND_DAI_MULTIMEDIA1, 255, 0, 5,
+	msm_routing_get_eq_band_audio_mixer,
+	msm_routing_put_eq_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("MultiMedia1 EQ Band8", EQ_BAND8,
+	MSM_FRONTEND_DAI_MULTIMEDIA1, 255, 0, 5,
+	msm_routing_get_eq_band_audio_mixer,
+	msm_routing_put_eq_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("MultiMedia1 EQ Band9", EQ_BAND9,
+	MSM_FRONTEND_DAI_MULTIMEDIA1, 255, 0, 5,
+	msm_routing_get_eq_band_audio_mixer,
+	msm_routing_put_eq_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("MultiMedia1 EQ Band10", EQ_BAND10,
+	MSM_FRONTEND_DAI_MULTIMEDIA1, 255, 0, 5,
+	msm_routing_get_eq_band_audio_mixer,
+	msm_routing_put_eq_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("MultiMedia1 EQ Band11", EQ_BAND11,
+	MSM_FRONTEND_DAI_MULTIMEDIA1, 255, 0, 5,
+	msm_routing_get_eq_band_audio_mixer,
+	msm_routing_put_eq_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("MultiMedia1 EQ Band12", EQ_BAND12,
+	MSM_FRONTEND_DAI_MULTIMEDIA1, 255, 0, 5,
+	msm_routing_get_eq_band_audio_mixer,
+	msm_routing_put_eq_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("MultiMedia2 EQ Band1", EQ_BAND1,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 255, 0, 5,
+	msm_routing_get_eq_band_audio_mixer,
+	msm_routing_put_eq_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("MultiMedia2 EQ Band2", EQ_BAND2,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 255, 0, 5,
+	msm_routing_get_eq_band_audio_mixer,
+	msm_routing_put_eq_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("MultiMedia2 EQ Band3", EQ_BAND3,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 255, 0, 5,
+	msm_routing_get_eq_band_audio_mixer,
+	msm_routing_put_eq_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("MultiMedia2 EQ Band4", EQ_BAND4,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 255, 0, 5,
+	msm_routing_get_eq_band_audio_mixer,
+	msm_routing_put_eq_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("MultiMedia2 EQ Band5", EQ_BAND5,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 255, 0, 5,
+	msm_routing_get_eq_band_audio_mixer,
+	msm_routing_put_eq_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("MultiMedia2 EQ Band6", EQ_BAND6,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 255, 0, 5,
+	msm_routing_get_eq_band_audio_mixer,
+	msm_routing_put_eq_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("MultiMedia2 EQ Band7", EQ_BAND7,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 255, 0, 5,
+	msm_routing_get_eq_band_audio_mixer,
+	msm_routing_put_eq_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("MultiMedia2 EQ Band8", EQ_BAND8,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 255, 0, 5,
+	msm_routing_get_eq_band_audio_mixer,
+	msm_routing_put_eq_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("MultiMedia2 EQ Band9", EQ_BAND9,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 255, 0, 5,
+	msm_routing_get_eq_band_audio_mixer,
+	msm_routing_put_eq_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("MultiMedia2 EQ Band10", EQ_BAND10,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 255, 0, 5,
+	msm_routing_get_eq_band_audio_mixer,
+	msm_routing_put_eq_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("MultiMedia2 EQ Band11", EQ_BAND11,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 255, 0, 5,
+	msm_routing_get_eq_band_audio_mixer,
+	msm_routing_put_eq_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("MultiMedia2 EQ Band12", EQ_BAND12,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 255, 0, 5,
+	msm_routing_get_eq_band_audio_mixer,
+	msm_routing_put_eq_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("MultiMedia3 EQ Band1", EQ_BAND1,
+	MSM_FRONTEND_DAI_MULTIMEDIA3, 255, 0, 5,
+	msm_routing_get_eq_band_audio_mixer,
+	msm_routing_put_eq_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("MultiMedia3 EQ Band2", EQ_BAND2,
+	MSM_FRONTEND_DAI_MULTIMEDIA3, 255, 0, 5,
+	msm_routing_get_eq_band_audio_mixer,
+	msm_routing_put_eq_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("MultiMedia3 EQ Band3", EQ_BAND3,
+	MSM_FRONTEND_DAI_MULTIMEDIA3, 255, 0, 5,
+	msm_routing_get_eq_band_audio_mixer,
+	msm_routing_put_eq_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("MultiMedia3 EQ Band4", EQ_BAND4,
+	MSM_FRONTEND_DAI_MULTIMEDIA3, 255, 0, 5,
+	msm_routing_get_eq_band_audio_mixer,
+	msm_routing_put_eq_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("MultiMedia3 EQ Band5", EQ_BAND5,
+	MSM_FRONTEND_DAI_MULTIMEDIA3, 255, 0, 5,
+	msm_routing_get_eq_band_audio_mixer,
+	msm_routing_put_eq_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("MultiMedia3 EQ Band6", EQ_BAND6,
+	MSM_FRONTEND_DAI_MULTIMEDIA3, 255, 0, 5,
+	msm_routing_get_eq_band_audio_mixer,
+	msm_routing_put_eq_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("MultiMedia3 EQ Band7", EQ_BAND7,
+	MSM_FRONTEND_DAI_MULTIMEDIA3, 255, 0, 5,
+	msm_routing_get_eq_band_audio_mixer,
+	msm_routing_put_eq_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("MultiMedia3 EQ Band8", EQ_BAND8,
+	MSM_FRONTEND_DAI_MULTIMEDIA3, 255, 0, 5,
+	msm_routing_get_eq_band_audio_mixer,
+	msm_routing_put_eq_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("MultiMedia3 EQ Band9", EQ_BAND9,
+	MSM_FRONTEND_DAI_MULTIMEDIA3, 255, 0, 5,
+	msm_routing_get_eq_band_audio_mixer,
+	msm_routing_put_eq_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("MultiMedia3 EQ Band10", EQ_BAND10,
+	MSM_FRONTEND_DAI_MULTIMEDIA3, 255, 0, 5,
+	msm_routing_get_eq_band_audio_mixer,
+	msm_routing_put_eq_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("MultiMedia3 EQ Band11", EQ_BAND11,
+	MSM_FRONTEND_DAI_MULTIMEDIA3, 255, 0, 5,
+	msm_routing_get_eq_band_audio_mixer,
+	msm_routing_put_eq_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("MultiMedia3 EQ Band12", EQ_BAND12,
+	MSM_FRONTEND_DAI_MULTIMEDIA3, 255, 0, 5,
+	msm_routing_get_eq_band_audio_mixer,
+	msm_routing_put_eq_band_audio_mixer),
+};
+
+static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
+	/* Frontend AIF */
+	/* Widget name equals to Front-End DAI name<Need confirmation>,
+	 * Stream name must contains substring of front-end dai name
+	 */
+	SND_SOC_DAPM_AIF_IN("MM_DL1", "MultiMedia1 Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("MM_DL2", "MultiMedia2 Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("MM_DL3", "MultiMedia3 Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("MM_DL4", "MultiMedia4 Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("VOIP_DL", "VoIP Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("MM_UL1", "MultiMedia1 Capture", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("MM_UL2", "MultiMedia2 Capture", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("CS-VOICE_DL1", "CS-VOICE Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("CS-VOICE_UL1", "CS-VOICE Capture", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("VOIP_UL", "VoIP Capture", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("SLIM0_DL_HL", "SLIMBUS0_HOSTLESS Playback",
+		0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("SLIM0_UL_HL", "SLIMBUS0_HOSTLESS Capture",
+		0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("INTFM_DL_HL", "INT_FM_HOSTLESS Playback",
+		0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("INTFM_UL_HL", "INT_FM_HOSTLESS Capture",
+		0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("HDMI_DL_HL", "HDMI_HOSTLESS Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("AUXPCM_DL_HL", "AUXPCM_HOSTLESS Playback",
+		0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AUXPCM_UL_HL", "AUXPCM_HOSTLESS Capture",
+		0, 0, 0, 0),
+
+	/* Backend AIF */
+	/* Stream name equals to backend dai link stream name
+	 */
+	SND_SOC_DAPM_AIF_OUT("PRI_I2S_RX", "Primary I2S Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("SEC_I2S_RX", "Secondary I2S Playback",
+				0, 0, 0 , 0),
+	SND_SOC_DAPM_AIF_OUT("SLIMBUS_0_RX", "Slimbus Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("HDMI", "HDMI Playback", 0, 0, 0 , 0),
+	SND_SOC_DAPM_AIF_OUT("MI2S_RX", "MI2S Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("PRI_I2S_TX", "Primary I2S Capture", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("SLIMBUS_0_TX", "Slimbus Capture", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("INT_BT_SCO_RX", "Internal BT-SCO Playback",
+				0, 0, 0 , 0),
+	SND_SOC_DAPM_AIF_IN("INT_BT_SCO_TX", "Internal BT-SCO Capture",
+				0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("INT_FM_RX", "Internal FM Playback",
+				0, 0, 0 , 0),
+	SND_SOC_DAPM_AIF_IN("INT_FM_TX", "Internal FM Capture",
+				0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("PCM_RX", "AFE Playback",
+				0, 0, 0 , 0),
+	SND_SOC_DAPM_AIF_IN("PCM_TX", "AFE Capture",
+				0, 0, 0 , 0),
+	/* incall */
+	SND_SOC_DAPM_AIF_OUT("VOICE_PLAYBACK_TX", "Voice Farend Playback",
+				0, 0, 0 , 0),
+	SND_SOC_DAPM_AIF_IN("INCALL_RECORD_TX", "Voice Uplink Capture",
+				0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("INCALL_RECORD_RX", "Voice Downlink Capture",
+				0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AUX_PCM_RX", "AUX PCM Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("AUX_PCM_TX", "AUX PCM Capture", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("VOICE_STUB_DL", "VOICE_STUB Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("VOICE_STUB_UL", "VOICE_STUB Capture", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("STUB_RX", "Stub Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("STUB_TX", "Stub Capture", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("SLIMBUS_1_RX", "Slimbus1 Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("SLIMBUS_1_TX", "Slimbus1 Capture", 0, 0, 0, 0),
+
+	/* Switch Definitions */
+	SND_SOC_DAPM_SWITCH("SLIMBUS_DL_HL", SND_SOC_NOPM, 0, 0,
+				&fm_switch_mixer_controls),
+	/* Mixer definitions */
+	SND_SOC_DAPM_MIXER("PRI_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+	pri_i2s_rx_mixer_controls, ARRAY_SIZE(pri_i2s_rx_mixer_controls)),
+	SND_SOC_DAPM_MIXER("SEC_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+	sec_i2s_rx_mixer_controls, ARRAY_SIZE(sec_i2s_rx_mixer_controls)),
+	SND_SOC_DAPM_MIXER("SLIMBUS_0_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+	slimbus_rx_mixer_controls, ARRAY_SIZE(slimbus_rx_mixer_controls)),
+	SND_SOC_DAPM_MIXER("HDMI Mixer", SND_SOC_NOPM, 0, 0,
+	hdmi_mixer_controls, ARRAY_SIZE(hdmi_mixer_controls)),
+	SND_SOC_DAPM_MIXER("MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+	mi2s_rx_mixer_controls, ARRAY_SIZE(mi2s_rx_mixer_controls)),
+	SND_SOC_DAPM_MIXER("MultiMedia1 Mixer", SND_SOC_NOPM, 0, 0,
+	mmul1_mixer_controls, ARRAY_SIZE(mmul1_mixer_controls)),
+	SND_SOC_DAPM_MIXER("MultiMedia2 Mixer", SND_SOC_NOPM, 0, 0,
+	mmul2_mixer_controls, ARRAY_SIZE(mmul2_mixer_controls)),
+	SND_SOC_DAPM_MIXER("AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+	auxpcm_rx_mixer_controls, ARRAY_SIZE(auxpcm_rx_mixer_controls)),
+	/* incall */
+	SND_SOC_DAPM_MIXER("Incall_Music Audio Mixer", SND_SOC_NOPM, 0, 0,
+			incall_music_delivery_mixer_controls,
+			ARRAY_SIZE(incall_music_delivery_mixer_controls)),
+	/* Voice Mixer */
+	SND_SOC_DAPM_MIXER("PRI_RX_Voice Mixer",
+				SND_SOC_NOPM, 0, 0, pri_rx_voice_mixer_controls,
+				ARRAY_SIZE(pri_rx_voice_mixer_controls)),
+	SND_SOC_DAPM_MIXER("SEC_RX_Voice Mixer",
+				SND_SOC_NOPM, 0, 0,
+				sec_i2s_rx_voice_mixer_controls,
+				ARRAY_SIZE(sec_i2s_rx_voice_mixer_controls)),
+	SND_SOC_DAPM_MIXER("SLIM_0_RX_Voice Mixer",
+				SND_SOC_NOPM, 0, 0,
+				slimbus_rx_voice_mixer_controls,
+				ARRAY_SIZE(slimbus_rx_voice_mixer_controls)),
+	SND_SOC_DAPM_MIXER("INTERNAL_BT_SCO_RX_Voice Mixer",
+				SND_SOC_NOPM, 0, 0,
+				bt_sco_rx_voice_mixer_controls,
+				ARRAY_SIZE(bt_sco_rx_voice_mixer_controls)),
+	SND_SOC_DAPM_MIXER("AFE_PCM_RX_Voice Mixer",
+				SND_SOC_NOPM, 0, 0,
+				afe_pcm_rx_voice_mixer_controls,
+				ARRAY_SIZE(afe_pcm_rx_voice_mixer_controls)),
+	SND_SOC_DAPM_MIXER("AUX_PCM_RX_Voice Mixer",
+				SND_SOC_NOPM, 0, 0,
+				aux_pcm_rx_voice_mixer_controls,
+				ARRAY_SIZE(aux_pcm_rx_voice_mixer_controls)),
+	SND_SOC_DAPM_MIXER("HDMI_RX_Voice Mixer",
+				SND_SOC_NOPM, 0, 0,
+				hdmi_rx_voice_mixer_controls,
+				ARRAY_SIZE(hdmi_rx_voice_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Voice_Tx Mixer",
+				SND_SOC_NOPM, 0, 0, tx_voice_mixer_controls,
+				ARRAY_SIZE(tx_voice_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Voip_Tx Mixer",
+				SND_SOC_NOPM, 0, 0, tx_voip_mixer_controls,
+				ARRAY_SIZE(tx_voip_mixer_controls)),
+	SND_SOC_DAPM_MIXER("INTERNAL_BT_SCO_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+	int_bt_sco_rx_mixer_controls, ARRAY_SIZE(int_bt_sco_rx_mixer_controls)),
+	SND_SOC_DAPM_MIXER("INTERNAL_FM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+	int_fm_rx_mixer_controls, ARRAY_SIZE(int_fm_rx_mixer_controls)),
+	SND_SOC_DAPM_MIXER("AFE_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+	afe_pcm_rx_mixer_controls, ARRAY_SIZE(afe_pcm_rx_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Voice Stub Tx Mixer", SND_SOC_NOPM, 0, 0,
+	tx_voice_stub_mixer_controls, ARRAY_SIZE(tx_voice_stub_mixer_controls)),
+	SND_SOC_DAPM_MIXER("STUB_RX Mixer", SND_SOC_NOPM, 0, 0,
+	stub_rx_mixer_controls, ARRAY_SIZE(stub_rx_mixer_controls)),
+	SND_SOC_DAPM_MIXER("SLIMBUS_1_RX Mixer", SND_SOC_NOPM, 0, 0,
+	slimbus_1_rx_mixer_controls, ARRAY_SIZE(slimbus_1_rx_mixer_controls)),
+	SND_SOC_DAPM_MIXER("SLIMBUS_0_RX Port Mixer",
+	SND_SOC_NOPM, 0, 0, sbus_0_rx_port_mixer_controls,
+	ARRAY_SIZE(sbus_0_rx_port_mixer_controls)),
+	SND_SOC_DAPM_MIXER("AUXPCM_RX Port Mixer",
+	SND_SOC_NOPM, 0, 0, auxpcm_rx_port_mixer_controls,
+	ARRAY_SIZE(auxpcm_rx_port_mixer_controls)),
+	SND_SOC_DAPM_MIXER("SLIMBUS_1_RX Port Mixer", SND_SOC_NOPM, 0, 0,
+	sbus_1_rx_port_mixer_controls,
+	ARRAY_SIZE(sbus_1_rx_port_mixer_controls)),
+	SND_SOC_DAPM_MIXER("INTERNAL_BT_SCO_RX Port Mixer", SND_SOC_NOPM, 0, 0,
+	bt_sco_rx_port_mixer_controls,
+	ARRAY_SIZE(bt_sco_rx_port_mixer_controls)),
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+	{"PRI_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+	{"PRI_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+	{"PRI_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+	{"PRI_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+	{"PRI_I2S_RX", NULL, "PRI_RX Audio Mixer"},
+
+	{"SEC_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+	{"SEC_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+	{"SEC_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+	{"SEC_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+	{"SEC_I2S_RX", NULL, "SEC_RX Audio Mixer"},
+
+	{"SLIMBUS_0_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+	{"SLIMBUS_0_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+	{"SLIMBUS_0_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+	{"SLIMBUS_0_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+	{"SLIMBUS_0_RX", NULL, "SLIMBUS_0_RX Audio Mixer"},
+
+	{"HDMI Mixer", "MultiMedia1", "MM_DL1"},
+	{"HDMI Mixer", "MultiMedia2", "MM_DL2"},
+	{"HDMI Mixer", "MultiMedia3", "MM_DL3"},
+	{"HDMI Mixer", "MultiMedia4", "MM_DL4"},
+	{"HDMI", NULL, "HDMI Mixer"},
+
+		/* incall */
+	{"Incall_Music Audio Mixer", "MultiMedia1", "MM_DL1"},
+	{"Incall_Music Audio Mixer", "MultiMedia2", "MM_DL2"},
+	{"VOICE_PLAYBACK_TX", NULL, "Incall_Music Audio Mixer"},
+
+	{"MultiMedia1 Mixer", "VOC_REC_UL", "INCALL_RECORD_TX"},
+	{"MultiMedia1 Mixer", "VOC_REC_DL", "INCALL_RECORD_RX"},
+	{"MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+	{"MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+	{"MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+	{"MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+	{"MI2S_RX", NULL, "MI2S_RX Audio Mixer"},
+
+	{"MultiMedia1 Mixer", "PRI_TX", "PRI_I2S_TX"},
+	{"MultiMedia1 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+	{"MultiMedia1 Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+
+	{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+	{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+	{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+	{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+	{"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX Audio Mixer"},
+
+	{"INTERNAL_FM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+	{"INTERNAL_FM_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+	{"INTERNAL_FM_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+	{"INTERNAL_FM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+	{"INT_FM_RX", NULL, "INTERNAL_FM_RX Audio Mixer"},
+
+	{"AFE_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+	{"AFE_PCM_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+	{"AFE_PCM_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+	{"AFE_PCM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+	{"PCM_RX", NULL, "AFE_PCM_RX Audio Mixer"},
+
+	{"MultiMedia1 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+	{"MultiMedia1 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+
+	{"MultiMedia1 Mixer", "AFE_PCM_TX", "PCM_TX"},
+	{"MM_UL1", NULL, "MultiMedia1 Mixer"},
+	{"MultiMedia2 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+	{"MM_UL2", NULL, "MultiMedia2 Mixer"},
+
+	{"AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+	{"AUX_PCM_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+	{"AUX_PCM_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+	{"AUX_PCM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+	{"AUX_PCM_RX", NULL, "AUX_PCM_RX Audio Mixer"},
+
+	{"PRI_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+	{"PRI_RX_Voice Mixer", "Voip", "VOIP_DL"},
+	{"PRI_I2S_RX", NULL, "PRI_RX_Voice Mixer"},
+
+	{"SEC_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+	{"SEC_RX_Voice Mixer", "Voip", "VOIP_DL"},
+	{"SEC_I2S_RX", NULL, "SEC_RX_Voice Mixer"},
+
+	{"SLIM_0_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+	{"SLIM_0_RX_Voice Mixer", "Voip", "VOIP_DL"},
+	{"SLIMBUS_0_RX", NULL, "SLIM_0_RX_Voice Mixer"},
+
+	{"INTERNAL_BT_SCO_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+	{"INTERNAL_BT_SCO_RX_Voice Mixer", "Voip", "VOIP_DL"},
+	{"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX_Voice Mixer"},
+
+	{"AFE_PCM_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+	{"AFE_PCM_RX_Voice Mixer", "Voip", "VOIP_DL"},
+	{"PCM_RX", NULL, "AFE_PCM_RX_Voice Mixer"},
+
+	{"AUX_PCM_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+	{"AUX_PCM_RX_Voice Mixer", "Voip", "VOIP_DL"},
+	{"AUX_PCM_RX", NULL, "AUX_PCM_RX_Voice Mixer"},
+
+	{"HDMI_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+	{"HDMI_RX_Voice Mixer", "Voip", "VOIP_DL"},
+	{"HDMI", NULL, "HDMI_RX_Voice Mixer"},
+	{"HDMI", NULL, "HDMI_DL_HL"},
+
+	{"Voice_Tx Mixer", "PRI_TX_Voice", "PRI_I2S_TX"},
+	{"Voice_Tx Mixer", "SLIM_0_TX_Voice", "SLIMBUS_0_TX"},
+	{"Voice_Tx Mixer", "INTERNAL_BT_SCO_TX_Voice", "INT_BT_SCO_TX"},
+	{"Voice_Tx Mixer", "AFE_PCM_TX_Voice", "PCM_TX"},
+	{"Voice_Tx Mixer", "AUX_PCM_TX_Voice", "AUX_PCM_TX"},
+	{"CS-VOICE_UL1", NULL, "Voice_Tx Mixer"},
+	{"Voip_Tx Mixer", "PRI_TX_Voip", "PRI_I2S_TX"},
+	{"Voip_Tx Mixer", "SLIM_0_TX_Voip", "SLIMBUS_0_TX"},
+	{"Voip_Tx Mixer", "INTERNAL_BT_SCO_TX_Voip", "INT_BT_SCO_TX"},
+	{"Voip_Tx Mixer", "AFE_PCM_TX_Voip", "PCM_TX"},
+	{"Voip_Tx Mixer", "AUX_PCM_TX_Voip", "AUX_PCM_TX"},
+
+	{"VOIP_UL", NULL, "Voip_Tx Mixer"},
+	{"SLIMBUS_DL_HL", "Switch", "SLIM0_DL_HL"},
+	{"SLIMBUS_0_RX", NULL, "SLIMBUS_DL_HL"},
+	{"SLIM0_UL_HL", NULL, "SLIMBUS_0_TX"},
+	{"INT_FM_RX", NULL, "INTFM_DL_HL"},
+	{"INTFM_UL_HL", NULL, "INT_FM_TX"},
+	{"AUX_PCM_RX", NULL, "AUXPCM_DL_HL"},
+	{"AUXPCM_UL_HL", NULL, "AUX_PCM_TX"},
+	{"SLIMBUS_0_RX Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+	{"SLIMBUS_0_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+	{"SLIMBUS_0_RX Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+	{"SLIMBUS_0_RX", NULL, "SLIMBUS_0_RX Port Mixer"},
+
+	{"AUXPCM_RX Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+	{"AUXPCM_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+	{"AUX_PCM_RX", NULL, "AUXPCM_RX Port Mixer"},
+
+	{"Voice Stub Tx Mixer", "STUB_TX_HL", "STUB_TX"},
+	{"Voice Stub Tx Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
+	{"Voice Stub Tx Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+	{"VOICE_STUB_UL", NULL, "Voice Stub Tx Mixer"},
+
+	{"STUB_RX Mixer", "Voice Stub", "VOICE_STUB_DL"},
+	{"STUB_RX", NULL, "STUB_RX Mixer"},
+	{"SLIMBUS_1_RX Mixer", "Voice Stub", "VOICE_STUB_DL"},
+	{"SLIMBUS_1_RX", NULL, "SLIMBUS_1_RX Mixer"},
+	{"INTERNAL_BT_SCO_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+
+	{"SLIMBUS_1_RX Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+	{"SLIMBUS_1_RX", NULL, "SLIMBUS_1_RX Port Mixer"},
+	{"INTERNAL_BT_SCO_RX Port Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
+	{"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX Port Mixer"},
+};
+
+static int msm_pcm_routing_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	unsigned int be_id = rtd->dai_link->be_id;
+
+	if (be_id >= MSM_BACKEND_DAI_MAX) {
+		pr_err("%s: unexpected be_id %d\n", __func__, be_id);
+		return -EINVAL;
+	}
+
+	mutex_lock(&routing_lock);
+	msm_bedais[be_id].hw_params = params;
+	mutex_unlock(&routing_lock);
+	return 0;
+}
+
+static int msm_pcm_routing_close(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	unsigned int be_id = rtd->dai_link->be_id;
+	int i, session_type;
+	struct msm_pcm_routing_bdai_data *bedai;
+
+	if (be_id >= MSM_BACKEND_DAI_MAX) {
+		pr_err("%s: unexpected be_id %d\n", __func__, be_id);
+		return -EINVAL;
+	}
+
+	bedai = &msm_bedais[be_id];
+
+	session_type = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+		0 : 1);
+
+	mutex_lock(&routing_lock);
+
+	for_each_set_bit(i, &bedai->fe_sessions, MSM_FRONTEND_DAI_MM_SIZE) {
+		if (fe_dai_map[i][session_type] != INVALID_SESSION)
+			adm_close(bedai->port_id);
+	}
+
+	bedai->active = 0;
+	bedai->hw_params = NULL;
+
+	mutex_unlock(&routing_lock);
+
+	return 0;
+}
+
+static int msm_pcm_routing_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	unsigned int be_id = rtd->dai_link->be_id;
+	int i, path_type, session_type;
+	struct msm_pcm_routing_bdai_data *bedai;
+	u32 channels;
+
+	if (be_id >= MSM_BACKEND_DAI_MAX) {
+		pr_err("%s: unexpected be_id %d\n", __func__, be_id);
+		return -EINVAL;
+	}
+
+
+	bedai = &msm_bedais[be_id];
+
+	if (bedai->hw_params == NULL) {
+		pr_err("%s: HW param is not configured", __func__);
+		return -EINVAL;
+	}
+
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		path_type = ADM_PATH_PLAYBACK;
+		session_type = SESSION_TYPE_RX;
+	} else {
+		path_type = ADM_PATH_LIVE_REC;
+		session_type = SESSION_TYPE_TX;
+	}
+
+	mutex_lock(&routing_lock);
+
+	if (bedai->active == 1)
+		goto done; /* Ignore prepare if back-end already active */
+
+	/* AFE port is not active at this point. However, still
+	 * go ahead setting active flag under the notion that
+	 * QDSP6 is able to handle ADM starting before AFE port
+	 * is started.
+	 */
+	bedai->active = 1;
+
+	for_each_set_bit(i, &bedai->fe_sessions, MSM_FRONTEND_DAI_MM_SIZE) {
+		if (fe_dai_map[i][session_type] != INVALID_SESSION) {
+
+			channels = params_channels(bedai->hw_params);
+			if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) &&
+				(channels > 2))
+				adm_multi_ch_copp_open(bedai->port_id,
+				path_type,
+				params_rate(bedai->hw_params),
+				channels,
+				DEFAULT_COPP_TOPOLOGY);
+			else
+				adm_open(bedai->port_id,
+				path_type,
+				params_rate(bedai->hw_params),
+				params_channels(bedai->hw_params),
+				DEFAULT_COPP_TOPOLOGY);
+
+			msm_pcm_routing_build_matrix(i,
+				fe_dai_map[i][session_type], path_type);
+		}
+	}
+
+done:
+	mutex_unlock(&routing_lock);
+
+	return 0;
+}
+
+static struct snd_pcm_ops msm_routing_pcm_ops = {
+	.hw_params	= msm_pcm_routing_hw_params,
+	.close          = msm_pcm_routing_close,
+	.prepare        = msm_pcm_routing_prepare,
+};
+
+static unsigned int msm_routing_read(struct snd_soc_platform *platform,
+				 unsigned int reg)
+{
+	dev_dbg(platform->dev, "reg %x\n", reg);
+	return 0;
+}
+
+/* Not used but frame seems to require it */
+static int msm_routing_write(struct snd_soc_platform *platform,
+	unsigned int reg, unsigned int val)
+{
+	dev_dbg(platform->dev, "reg %x val %x\n", reg, val);
+	return 0;
+}
+
+/* Not used but frame seems to require it */
+static int msm_routing_probe(struct snd_soc_platform *platform)
+{
+	snd_soc_dapm_new_controls(&platform->dapm, msm_qdsp6_widgets,
+			    ARRAY_SIZE(msm_qdsp6_widgets));
+	snd_soc_dapm_add_routes(&platform->dapm, intercon,
+		ARRAY_SIZE(intercon));
+
+	snd_soc_dapm_new_widgets(&platform->dapm);
+
+	snd_soc_add_platform_controls(platform,
+				int_fm_vol_mixer_controls,
+			ARRAY_SIZE(int_fm_vol_mixer_controls));
+
+	snd_soc_add_platform_controls(platform,
+				lpa_vol_mixer_controls,
+			ARRAY_SIZE(lpa_vol_mixer_controls));
+
+	snd_soc_add_platform_controls(platform,
+				eq_enable_mixer_controls,
+			ARRAY_SIZE(eq_enable_mixer_controls));
+
+	snd_soc_add_platform_controls(platform,
+				eq_band_mixer_controls,
+			ARRAY_SIZE(eq_band_mixer_controls));
+
+	snd_soc_add_platform_controls(platform,
+				eq_coeff_mixer_controls,
+			ARRAY_SIZE(eq_coeff_mixer_controls));
+
+	snd_soc_add_platform_controls(platform,
+				multimedia2_vol_mixer_controls,
+			ARRAY_SIZE(multimedia2_vol_mixer_controls));
+
+	snd_soc_add_platform_controls(platform,
+				compressed_vol_mixer_controls,
+			ARRAY_SIZE(compressed_vol_mixer_controls));
+
+	return 0;
+}
+
+static struct snd_soc_platform_driver msm_soc_routing_platform = {
+	.ops		= &msm_routing_pcm_ops,
+	.probe		= msm_routing_probe,
+	.read		= msm_routing_read,
+	.write		= msm_routing_write,
+};
+
+static __devinit int msm_routing_pcm_probe(struct platform_device *pdev)
+{
+	dev_dbg(&pdev->dev, "dev name %s\n", dev_name(&pdev->dev));
+	return snd_soc_register_platform(&pdev->dev,
+				   &msm_soc_routing_platform);
+}
+
+static int msm_routing_pcm_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_platform(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver msm_routing_pcm_driver = {
+	.driver = {
+		.name = "msm-pcm-routing",
+		.owner = THIS_MODULE,
+	},
+	.probe = msm_routing_pcm_probe,
+	.remove = __devexit_p(msm_routing_pcm_remove),
+};
+
+int msm_routing_check_backend_enabled(int fedai_id)
+{
+	int i;
+	if (fedai_id >= MSM_FRONTEND_DAI_MM_MAX_ID) {
+		/* bad ID assigned in machine driver */
+		pr_err("%s: bad MM ID\n", __func__);
+		return 0;
+	}
+	for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
+		if ((test_bit(fedai_id,
+			&msm_bedais[i].fe_sessions))) {
+			return msm_bedais[i].active;
+		}
+	}
+	return 0;
+}
+
+static int __init msm_soc_routing_platform_init(void)
+{
+	mutex_init(&routing_lock);
+	return platform_driver_register(&msm_routing_pcm_driver);
+}
+module_init(msm_soc_routing_platform_init);
+
+static void __exit msm_soc_routing_platform_exit(void)
+{
+	platform_driver_unregister(&msm_routing_pcm_driver);
+}
+module_exit(msm_soc_routing_platform_exit);
+
+MODULE_DESCRIPTION("MSM routing platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
new file mode 100644
index 0000000..b971787
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
@@ -0,0 +1,103 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef _MSM_PCM_ROUTING_H
+#define _MSM_PCM_ROUTING_H
+#include <sound/apr_audio-v2.h>
+
+#define LPASS_BE_PRI_I2S_RX "(Backend) PRIMARY_I2S_RX"
+#define LPASS_BE_PRI_I2S_TX "(Backend) PRIMARY_I2S_TX"
+#define LPASS_BE_SLIMBUS_0_RX "(Backend) SLIMBUS_0_RX"
+#define LPASS_BE_SLIMBUS_0_TX "(Backend) SLIMBUS_0_TX"
+#define LPASS_BE_HDMI "(Backend) HDMI"
+#define LPASS_BE_INT_BT_SCO_RX "(Backend) INT_BT_SCO_RX"
+#define LPASS_BE_INT_BT_SCO_TX "(Backend) INT_BT_SCO_TX"
+#define LPASS_BE_INT_FM_RX "(Backend) INT_FM_RX"
+#define LPASS_BE_INT_FM_TX "(Backend) INT_FM_TX"
+#define LPASS_BE_AFE_PCM_RX "(Backend) RT_PROXY_DAI_001_RX"
+#define LPASS_BE_AFE_PCM_TX "(Backend) RT_PROXY_DAI_002_TX"
+#define LPASS_BE_AUXPCM_RX "(Backend) AUX_PCM_RX"
+#define LPASS_BE_AUXPCM_TX "(Backend) AUX_PCM_TX"
+#define LPASS_BE_VOICE_PLAYBACK_TX "(Backend) VOICE_PLAYBACK_TX"
+#define LPASS_BE_INCALL_RECORD_RX "(Backend) INCALL_RECORD_TX"
+#define LPASS_BE_INCALL_RECORD_TX "(Backend) INCALL_RECORD_RX"
+#define LPASS_BE_SEC_I2S_RX "(Backend) SECONDARY_I2S_RX"
+
+#define LPASS_BE_MI2S_RX "(Backend) MI2S_RX"
+#define LPASS_BE_STUB_RX "(Backend) STUB_RX"
+#define LPASS_BE_STUB_TX "(Backend) STUB_TX"
+#define LPASS_BE_SLIMBUS_1_RX "(Backend) SLIMBUS_1_RX"
+#define LPASS_BE_SLIMBUS_1_TX "(Backend) SLIMBUS_1_TX"
+
+/* For multimedia front-ends, asm session is allocated dynamically.
+ * Hence, asm session/multimedia front-end mapping has to be maintained.
+ * Due to this reason, additional multimedia front-end must be placed before
+ * non-multimedia front-ends.
+ */
+
+enum {
+	MSM_FRONTEND_DAI_MULTIMEDIA1 = 0,
+	MSM_FRONTEND_DAI_MULTIMEDIA2,
+	MSM_FRONTEND_DAI_MULTIMEDIA3,
+	MSM_FRONTEND_DAI_MULTIMEDIA4,
+	MSM_FRONTEND_DAI_CS_VOICE,
+	MSM_FRONTEND_DAI_VOIP,
+	MSM_FRONTEND_DAI_AFE_RX,
+	MSM_FRONTEND_DAI_AFE_TX,
+	MSM_FRONTEND_DAI_VOICE_STUB,
+	MSM_FRONTEND_DAI_MAX,
+};
+
+#define MSM_FRONTEND_DAI_MM_SIZE (MSM_FRONTEND_DAI_MULTIMEDIA4 + 1)
+#define MSM_FRONTEND_DAI_MM_MAX_ID MSM_FRONTEND_DAI_MULTIMEDIA4
+
+enum {
+	MSM_BACKEND_DAI_PRI_I2S_RX = 0,
+	MSM_BACKEND_DAI_PRI_I2S_TX,
+	MSM_BACKEND_DAI_SLIMBUS_0_RX,
+	MSM_BACKEND_DAI_SLIMBUS_0_TX,
+	MSM_BACKEND_DAI_HDMI_RX,
+	MSM_BACKEND_DAI_INT_BT_SCO_RX,
+	MSM_BACKEND_DAI_INT_BT_SCO_TX,
+	MSM_BACKEND_DAI_INT_FM_RX,
+	MSM_BACKEND_DAI_INT_FM_TX,
+	MSM_BACKEND_DAI_AFE_PCM_RX,
+	MSM_BACKEND_DAI_AFE_PCM_TX,
+	MSM_BACKEND_DAI_AUXPCM_RX,
+	MSM_BACKEND_DAI_AUXPCM_TX,
+	MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
+	MSM_BACKEND_DAI_INCALL_RECORD_RX,
+	MSM_BACKEND_DAI_INCALL_RECORD_TX,
+	MSM_BACKEND_DAI_MI2S_RX,
+	MSM_BACKEND_DAI_SEC_I2S_RX,
+	MSM_BACKEND_DAI_SLIMBUS_1_RX,
+	MSM_BACKEND_DAI_SLIMBUS_1_TX,
+	MSM_BACKEND_DAI_INVALID,
+	MSM_BACKEND_DAI_MAX,
+};
+
+/* dai_id: front-end ID,
+ * dspst_id:  DSP audio stream ID
+ * stream_type: playback or capture
+ */
+void msm_pcm_routing_reg_phy_stream(int fedai_id, int dspst_id,
+	int stream_type);
+void msm_pcm_routing_dereg_phy_stream(int fedai_id, int stream_type);
+
+int lpa_set_volume(unsigned volume);
+
+int msm_routing_check_backend_enabled(int fedai_id);
+
+int multi_ch_pcm_set_volume(unsigned volume);
+
+int compressed_set_volume(unsigned volume);
+
+#endif /*_MSM_PCM_H*/
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
new file mode 100644
index 0000000..691ca21
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -0,0 +1,621 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/jiffies.h>
+#include <linux/uaccess.h>
+#include <linux/atomic.h>
+
+
+#include <mach/qdsp6v2/audio_acdb.h>
+#include <mach/qdsp6v2/rtac.h>
+
+#include <sound/apr_audio-v2.h>
+#include <mach/qdsp6v2/apr.h>
+#include <sound/q6adm-v2.h>
+#include <sound/q6audio-v2.h>
+
+
+#define TIMEOUT_MS 1000
+
+#define RESET_COPP_ID 99
+#define INVALID_COPP_ID 0xFF
+
+struct adm_ctl {
+	void *apr;
+	atomic_t copp_id[Q6_AFE_MAX_PORTS];
+	atomic_t copp_cnt[Q6_AFE_MAX_PORTS];
+	atomic_t copp_stat[Q6_AFE_MAX_PORTS];
+	u32      mem_map_handle[Q6_AFE_MAX_PORTS];
+	wait_queue_head_t wait[Q6_AFE_MAX_PORTS];
+};
+
+static struct adm_ctl			this_adm;
+
+static int32_t adm_callback(struct apr_client_data *data, void *priv)
+{
+	uint32_t *payload;
+	int i, index;
+	payload = data->payload;
+
+	if (data->opcode == RESET_EVENTS) {
+		pr_debug("adm_callback: Reset event is received: %d %d apr[%p]\n",
+				data->reset_event, data->reset_proc,
+				this_adm.apr);
+		if (this_adm.apr) {
+			apr_reset(this_adm.apr);
+			for (i = 0; i < Q6_AFE_MAX_PORTS; i++) {
+				atomic_set(&this_adm.copp_id[i],
+							RESET_COPP_ID);
+				atomic_set(&this_adm.copp_cnt[i], 0);
+				atomic_set(&this_adm.copp_stat[i], 0);
+			}
+			this_adm.apr = NULL;
+		}
+		return 0;
+	}
+
+	pr_debug("%s: code = 0x%x PL#0[%x], PL#1[%x], size = %d\n", __func__,
+			data->opcode, payload[0], payload[1],
+					data->payload_size);
+
+	if (data->payload_size) {
+		index = q6audio_get_port_index(data->token);
+		if (index < 0 || index >= Q6_AFE_MAX_PORTS) {
+			pr_err("%s: invalid port idx %d token %d\n",
+					__func__, index, data->token);
+			return 0;
+		}
+		if (data->opcode == APR_BASIC_RSP_RESULT) {
+			pr_debug("APR_BASIC_RSP_RESULT\n");
+			switch (payload[0]) {
+			case ADM_CMD_SET_PP_PARAMS_V5:
+				if (rtac_make_adm_callback(
+					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");
+				atomic_set(&this_adm.copp_stat[index], 1);
+				wake_up(&this_adm.wait[index]);
+				break;
+			default:
+				pr_err("%s: Unknown Cmd: 0x%x\n", __func__,
+								payload[0]);
+				break;
+			}
+			return 0;
+		}
+
+		switch (data->opcode) {
+		case ADM_CMDRSP_DEVICE_OPEN_V5: {
+			struct adm_cmd_rsp_device_open_v5 *open =
+			(struct adm_cmd_rsp_device_open_v5 *)data->payload;
+			if (open->copp_id == INVALID_COPP_ID) {
+				pr_err("%s: invalid coppid rxed %d\n",
+					__func__, open->copp_id);
+				atomic_set(&this_adm.copp_stat[index], 1);
+				wake_up(&this_adm.wait[index]);
+				break;
+			}
+			atomic_set(&this_adm.copp_id[index], open->copp_id);
+			atomic_set(&this_adm.copp_stat[index], 1);
+			pr_debug("%s: coppid rxed=%d\n", __func__,
+							open->copp_id);
+			wake_up(&this_adm.wait[index]);
+			}
+			break;
+		case ADM_CMD_GET_PP_PARAMS_V5:
+			pr_debug("%s: ADM_CMD_GET_PP_PARAMS_V5\n", __func__);
+			rtac_make_adm_callback(payload,
+				data->payload_size);
+			break;
+		default:
+			pr_err("%s: Unknown cmd:0x%x\n", __func__,
+							data->opcode);
+			break;
+		}
+	}
+	return 0;
+}
+
+/* TODO: send_adm_cal_block function to be defined
+	when calibration available for 8974 */
+static void send_adm_cal(int port_id, int path)
+{
+	/* function to be defined when calibration available for 8974 */
+	pr_debug("%s\n", __func__);
+}
+
+int adm_open(int port_id, int path, int rate, int channel_mode, int topology)
+{
+	struct adm_cmd_device_open_v5	open;
+	int ret = 0;
+	int index;
+	int tmp_port = q6audio_get_port_id(port_id);
+
+	pr_debug("%s: port %d path:%d rate:%d mode:%d\n", __func__,
+				port_id, path, rate, channel_mode);
+
+	port_id = q6audio_convert_virtual_to_portid(port_id);
+
+	if (q6audio_validate_port(port_id) < 0) {
+		pr_err("%s port idi[%d] is invalid\n", __func__, port_id);
+		return -ENODEV;
+	}
+
+	index = q6audio_get_port_index(port_id);
+	pr_debug("%s: Port ID %d, index %d\n", __func__, port_id, index);
+
+	if (this_adm.apr == NULL) {
+		this_adm.apr = apr_register("ADSP", "ADM", adm_callback,
+						0xFFFFFFFF, &this_adm);
+		if (this_adm.apr == NULL) {
+			pr_err("%s: Unable to register ADM\n", __func__);
+			ret = -ENODEV;
+			return ret;
+		}
+		rtac_set_adm_handle(this_adm.apr);
+	}
+
+
+	/* Create a COPP if port id are not enabled */
+	if (atomic_read(&this_adm.copp_cnt[index]) == 0) {
+
+		open.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+		open.hdr.pkt_size = sizeof(open);
+		open.hdr.src_svc = APR_SVC_ADM;
+		open.hdr.src_domain = APR_DOMAIN_APPS;
+		open.hdr.src_port = tmp_port;
+		open.hdr.dest_svc = APR_SVC_ADM;
+		open.hdr.dest_domain = APR_DOMAIN_ADSP;
+		open.hdr.dest_port = tmp_port;
+		open.hdr.token = port_id;
+		open.hdr.opcode = ADM_CMD_DEVICE_OPEN_V5;
+
+		open.mode_of_operation = path;
+		/* Reserved for future use, need to set this to 0 */
+		open.flags = 0x00;
+		open.endpoint_id_1 = tmp_port;
+		open.endpoint_id_2 = 0xFFFF;
+
+		/* convert path to acdb path */
+		if (path == ADM_PATH_PLAYBACK)
+			open.topology_id = get_adm_rx_topology();
+		else {
+			open.topology_id = get_adm_tx_topology();
+			if ((open.topology_id ==
+				VPM_TX_SM_ECNS_COPP_TOPOLOGY) ||
+			    (open.topology_id ==
+				VPM_TX_DM_FLUENCE_COPP_TOPOLOGY))
+				rate = 16000;
+		}
+
+		if (open.topology_id  == 0)
+			open.topology_id = topology;
+
+		open.dev_num_channel = channel_mode & 0x00FF;
+		open.bit_width = 16;
+		open.sample_rate  = rate;
+		memset(open.dev_channel_mapping, 0, 8);
+
+		if (channel_mode == 1)	{
+			open.dev_channel_mapping[0] = PCM_CHANNEL_FC;
+		} else if (channel_mode == 2) {
+			open.dev_channel_mapping[0] = PCM_CHANNEL_FL;
+			open.dev_channel_mapping[1] = PCM_CHANNEL_FR;
+		} else if (channel_mode == 6) {
+			open.dev_channel_mapping[0] = PCM_CHANNEL_FL;
+			open.dev_channel_mapping[1] = PCM_CHANNEL_FR;
+			open.dev_channel_mapping[2] = PCM_CHANNEL_LFE;
+			open.dev_channel_mapping[3] = PCM_CHANNEL_FC;
+			open.dev_channel_mapping[4] = PCM_CHANNEL_LB;
+			open.dev_channel_mapping[5] = PCM_CHANNEL_RB;
+		} else {
+			pr_err("%s invalid num_chan %d\n", __func__,
+					channel_mode);
+			return -EINVAL;
+		}
+
+		pr_debug("%s: port_id=%d rate=%d"
+			"topology_id=0x%X\n", __func__,	open.endpoint_id_1, \
+				  open.sample_rate, open.topology_id);
+
+		atomic_set(&this_adm.copp_stat[index], 0);
+
+		ret = apr_send_pkt(this_adm.apr, (uint32_t *)&open);
+		if (ret < 0) {
+			pr_err("%s:ADM enable for port %d for[%d] failed\n",
+						__func__, tmp_port, port_id);
+			ret = -EINVAL;
+			goto fail_cmd;
+		}
+		/* Wait for the callback with copp id */
+		ret = wait_event_timeout(this_adm.wait[index],
+			atomic_read(&this_adm.copp_stat[index]),
+			msecs_to_jiffies(TIMEOUT_MS));
+		if (!ret) {
+			pr_err("%s ADM open failed for port %d"
+			"for [%d]\n", __func__, tmp_port, port_id);
+			ret = -EINVAL;
+			goto fail_cmd;
+		}
+	}
+	atomic_inc(&this_adm.copp_cnt[index]);
+	return 0;
+
+fail_cmd:
+
+	return ret;
+}
+
+
+int adm_multi_ch_copp_open(int port_id, int path, int rate, int channel_mode,
+				int topology)
+{
+	int ret = 0;
+
+	ret = adm_open(port_id, path, rate, channel_mode, topology);
+
+	return ret;
+}
+
+int adm_matrix_map(int session_id, int path, int num_copps,
+			unsigned int *port_id, int copp_id)
+{
+	struct adm_cmd_matrix_map_routings_v5	*route;
+	struct adm_session_map_node_v5 *node;
+	uint32_t *copps_list;
+	int cmd_size = 0;
+	int ret = 0, i = 0;
+	void *payload = NULL;
+	void *matrix_map = NULL;
+
+	/* Assumes port_ids have already been validated during adm_open */
+	int index = q6audio_get_port_index(copp_id);
+	if (index < 0 || index >= Q6_AFE_MAX_PORTS) {
+		pr_err("%s: invalid port idx %d token %d\n",
+					__func__, index, copp_id);
+		return 0;
+	}
+	cmd_size = (sizeof(struct adm_cmd_matrix_map_routings_v5) +
+			sizeof(struct adm_session_map_node_v5) +
+			(sizeof(uint32_t) * num_copps));
+	matrix_map = kzalloc(cmd_size, GFP_KERNEL);
+	if (matrix_map == NULL) {
+		pr_err("%s: Mem alloc failed\n", __func__);
+		ret = -EINVAL;
+		return ret;
+	}
+	route = (struct adm_cmd_matrix_map_routings_v5 *)matrix_map;
+
+	pr_debug("%s: session 0x%x path:%d num_copps:%d port_id[0] :%d coppid[%d]\n",
+		 __func__, session_id, path, num_copps, port_id[0], copp_id);
+
+	route->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	route->hdr.pkt_size = cmd_size;
+	route->hdr.src_svc = 0;
+	route->hdr.src_domain = APR_DOMAIN_APPS;
+	route->hdr.src_port = copp_id;
+	route->hdr.dest_svc = APR_SVC_ADM;
+	route->hdr.dest_domain = APR_DOMAIN_ADSP;
+	route->hdr.dest_port = atomic_read(&this_adm.copp_id[index]);
+	route->hdr.token = copp_id;
+	route->hdr.opcode = ADM_CMD_MATRIX_MAP_ROUTINGS_V5;
+	route->num_sessions = 1;
+
+	switch (path) {
+	case 0x1:
+		route->matrix_id = ADM_MATRIX_ID_AUDIO_RX;
+		break;
+	case 0x2:
+	case 0x3:
+		route->matrix_id = ADM_MATRIX_ID_AUDIO_TX;
+		break;
+	default:
+		pr_err("%s: Wrong path set[%d]\n", __func__, path);
+		break;
+	}
+	payload = ((u8 *)matrix_map +
+			sizeof(struct adm_cmd_matrix_map_routings_v5));
+	node = (struct adm_session_map_node_v5 *)payload;
+
+	node->session_id = session_id;
+	node->num_copps = num_copps;
+	payload = (u8 *)node + sizeof(struct adm_session_map_node_v5);
+	copps_list = (uint32_t *)payload;
+	for (i = 0; i < num_copps; i++) {
+		int tmp;
+		port_id[i] = q6audio_convert_virtual_to_portid(port_id[i]);
+
+		tmp = q6audio_get_port_index(port_id[i]);
+
+
+		if (tmp >= 0 && tmp < Q6_AFE_MAX_PORTS)
+			copps_list[i] =
+					atomic_read(&this_adm.copp_id[tmp]);
+		pr_debug("%s: port_id[%d]: %d, index: %d act coppid[0x%x]\n",
+			__func__, i, port_id[i], tmp,
+			atomic_read(&this_adm.copp_id[tmp]));
+	}
+	atomic_set(&this_adm.copp_stat[index], 0);
+
+	ret = apr_send_pkt(this_adm.apr, (uint32_t *)matrix_map);
+	if (ret < 0) {
+		pr_err("%s: ADM routing for port %d failed\n",
+					__func__, port_id[0]);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+	ret = wait_event_timeout(this_adm.wait[index],
+				atomic_read(&this_adm.copp_stat[index]),
+				msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: ADM cmd Route failed for port %d\n",
+					__func__, port_id[0]);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+	for (i = 0; i < num_copps; i++)
+		send_adm_cal(port_id[i], path);
+
+fail_cmd:
+	kfree(matrix_map);
+	return ret;
+}
+
+int adm_memory_map_regions(int port_id,
+		uint32_t *buf_add, uint32_t mempool_id,
+		uint32_t *bufsz, uint32_t bufcnt)
+{
+	struct  avs_cmd_shared_mem_map_regions *mmap_regions = NULL;
+	struct  avs_shared_map_region_payload *mregions = NULL;
+	void    *mmap_region_cmd = NULL;
+	void    *payload = NULL;
+	int     ret = 0;
+	int     i = 0;
+	int     cmd_size = 0;
+	int     index = 0;
+
+	pr_debug("%s\n", __func__);
+	if (this_adm.apr == NULL) {
+		this_adm.apr = apr_register("ADSP", "ADM", adm_callback,
+						0xFFFFFFFF, &this_adm);
+		if (this_adm.apr == NULL) {
+			pr_err("%s: Unable to register ADM\n", __func__);
+			ret = -ENODEV;
+			return ret;
+		}
+		rtac_set_adm_handle(this_adm.apr);
+	}
+
+	port_id = q6audio_convert_virtual_to_portid(port_id);
+
+	if (q6audio_validate_port(port_id) < 0) {
+		pr_err("%s port id[%d] is invalid\n", __func__, port_id);
+		return -ENODEV;
+	}
+
+	index = q6audio_get_port_index(port_id);
+
+	cmd_size = sizeof(struct avs_cmd_shared_mem_map_regions)
+			+ sizeof(struct avs_shared_map_region_payload)
+			* bufcnt;
+
+	mmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL);
+	if (!mmap_region_cmd) {
+		pr_err("%s: allocate mmap_region_cmd failed\n", __func__);
+		return -ENOMEM;
+	}
+	mmap_regions = (struct avs_cmd_shared_mem_map_regions *)mmap_region_cmd;
+	mmap_regions->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+						APR_HDR_LEN(APR_HDR_SIZE),
+								APR_PKT_VER);
+	mmap_regions->hdr.pkt_size = cmd_size;
+	mmap_regions->hdr.src_port = 0;
+	mmap_regions->hdr.dest_port = 0;
+	mmap_regions->hdr.token = 0;
+	mmap_regions->hdr.opcode = ADM_CMD_SHARED_MEM_MAP_REGIONS;
+	mmap_regions->mem_pool_id = ADSP_MEMORY_MAP_EBI_POOL & 0x00ff;
+	mmap_regions->num_regions = bufcnt & 0x00ff;
+	mmap_regions->property_flag = 0x00;
+
+	pr_debug("%s: map_regions->num_regions = %d\n", __func__,
+				mmap_regions->num_regions);
+	payload = ((u8 *) mmap_region_cmd +
+				sizeof(struct avs_cmd_shared_mem_map_regions));
+	mregions = (struct avs_shared_map_region_payload *)payload;
+
+	for (i = 0; i < bufcnt; i++) {
+		mregions->shm_addr_lsw = buf_add[i];
+		mregions->shm_addr_msw = 0x00;
+		mregions->mem_size_bytes = bufsz[i];
+		++mregions;
+	}
+
+	atomic_set(&this_adm.copp_stat[0], 0);
+	ret = apr_send_pkt(this_adm.apr, (uint32_t *) mmap_region_cmd);
+	if (ret < 0) {
+		pr_err("%s: mmap_regions op[0x%x]rc[%d]\n", __func__,
+					mmap_regions->hdr.opcode, ret);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+
+	ret = wait_event_timeout(this_adm.wait[index],
+			atomic_read(&this_adm.copp_stat[0]), 5 * HZ);
+	if (!ret) {
+		pr_err("%s: timeout. waited for memory_map\n", __func__);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+fail_cmd:
+	kfree(mmap_region_cmd);
+	return ret;
+}
+
+int adm_memory_unmap_regions(int32_t port_id, uint32_t *buf_add,
+			uint32_t *bufsz, uint32_t bufcnt)
+{
+	struct  avs_cmd_shared_mem_unmap_regions unmap_regions;
+	int     ret = 0;
+	int     cmd_size = 0;
+	int     index = 0;
+
+	pr_debug("%s\n", __func__);
+
+	if (this_adm.apr == NULL) {
+		pr_err("%s APR handle NULL\n", __func__);
+		return -EINVAL;
+	}
+	port_id = q6audio_convert_virtual_to_portid(port_id);
+
+	if (q6audio_validate_port(port_id) < 0) {
+		pr_err("%s port idi[%d] is invalid\n", __func__, port_id);
+		return -ENODEV;
+	}
+
+	index = q6audio_get_port_index(port_id);
+
+	unmap_regions.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+						APR_HDR_LEN(APR_HDR_SIZE),
+							APR_PKT_VER);
+	unmap_regions.hdr.pkt_size = cmd_size;
+	unmap_regions.hdr.src_port = 0;
+	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];
+	atomic_set(&this_adm.copp_stat[0], 0);
+	ret = apr_send_pkt(this_adm.apr, (uint32_t *) &unmap_regions);
+	if (ret < 0) {
+		pr_err("%s: mmap_regions op[0x%x]rc[%d]\n", __func__,
+				unmap_regions.hdr.opcode, ret);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+
+	ret = wait_event_timeout(this_adm.wait[index],
+			atomic_read(&this_adm.copp_stat[0]), 5 * HZ);
+	if (!ret) {
+		pr_err("%s: timeout. waited for memory_unmap\n", __func__);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+fail_cmd:
+	return ret;
+}
+
+int adm_get_copp_id(int port_index)
+{
+	pr_debug("%s\n", __func__);
+
+	if (port_index < 0) {
+		pr_err("%s: invalid port_id = %d\n", __func__, port_index);
+		return -EINVAL;
+	}
+
+	return atomic_read(&this_adm.copp_id[port_index]);
+}
+
+int adm_close(int port_id)
+{
+	struct apr_hdr close;
+
+	int ret = 0;
+	int index = 0;
+
+	port_id = q6audio_convert_virtual_to_portid(port_id);
+
+	index = q6audio_get_port_index(port_id);
+	if (q6audio_validate_port(port_id) < 0)
+		return -EINVAL;
+
+	pr_debug("%s port_id=%d index %d\n", __func__, port_id, index);
+
+	if (!(atomic_read(&this_adm.copp_cnt[index]))) {
+		pr_err("%s: copp count for port[%d]is 0\n", __func__, port_id);
+
+		goto fail_cmd;
+	}
+	atomic_dec(&this_adm.copp_cnt[index]);
+	if (!(atomic_read(&this_adm.copp_cnt[index]))) {
+
+		close.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+			APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+		close.pkt_size = sizeof(close);
+		close.src_svc = APR_SVC_ADM;
+		close.src_domain = APR_DOMAIN_APPS;
+		close.src_port = port_id;
+		close.dest_svc = APR_SVC_ADM;
+		close.dest_domain = APR_DOMAIN_ADSP;
+		close.dest_port = atomic_read(&this_adm.copp_id[index]);
+		close.token = port_id;
+		close.opcode = ADM_CMD_DEVICE_CLOSE_V5;
+
+		atomic_set(&this_adm.copp_id[index], RESET_COPP_ID);
+		atomic_set(&this_adm.copp_stat[index], 0);
+
+
+		pr_debug("%s:coppid %d portid=%d index=%d coppcnt=%d\n",
+				__func__,
+				atomic_read(&this_adm.copp_id[index]),
+				port_id, index,
+				atomic_read(&this_adm.copp_cnt[index]));
+
+		ret = apr_send_pkt(this_adm.apr, (uint32_t *)&close);
+		if (ret < 0) {
+			pr_err("%s ADM close failed\n", __func__);
+			ret = -EINVAL;
+			goto fail_cmd;
+		}
+
+		ret = wait_event_timeout(this_adm.wait[index],
+				atomic_read(&this_adm.copp_stat[index]),
+				msecs_to_jiffies(TIMEOUT_MS));
+		if (!ret) {
+			pr_err("%s: ADM cmd Route failed for port %d\n",
+						__func__, port_id);
+			ret = -EINVAL;
+			goto fail_cmd;
+		}
+
+		rtac_remove_adm_device(port_id);
+	}
+
+fail_cmd:
+	return ret;
+}
+
+static int __init adm_init(void)
+{
+	int i = 0;
+	this_adm.apr = NULL;
+
+	for (i = 0; i < Q6_AFE_MAX_PORTS; i++) {
+		atomic_set(&this_adm.copp_id[i], RESET_COPP_ID);
+		atomic_set(&this_adm.copp_cnt[i], 0);
+		atomic_set(&this_adm.copp_stat[i], 0);
+		init_waitqueue_head(&this_adm.wait[i]);
+	}
+	return 0;
+}
+
+device_initcall(adm_init);
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
new file mode 100644
index 0000000..5b30e8e
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -0,0 +1,1584 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/slab.h>
+#include <linux/debugfs.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+#include <linux/jiffies.h>
+#include <linux/sched.h>
+#include <mach/qdsp6v2/audio_acdb.h>
+#include <sound/apr_audio-v2.h>
+#include <sound/q6afe-v2.h>
+
+#include <sound/q6audio-v2.h>
+
+
+struct afe_ctl {
+	void *apr;
+	atomic_t state;
+	atomic_t status;
+	wait_queue_head_t wait[AFE_MAX_PORTS];
+	void (*tx_cb) (uint32_t opcode,
+		uint32_t token, uint32_t *payload, void *priv);
+	void (*rx_cb) (uint32_t opcode,
+		uint32_t token, uint32_t *payload, void *priv);
+	void *tx_private_data;
+	void *rx_private_data;
+};
+
+static struct afe_ctl this_afe;
+
+static struct acdb_cal_block afe_cal_addr[MAX_AUDPROC_TYPES];
+
+#define TIMEOUT_MS 1000
+#define Q6AFE_MAX_VOLUME 0x3FFF
+
+#define SIZEOF_CFG_CMD(y) \
+		(sizeof(struct apr_hdr) + sizeof(u16) + (sizeof(struct y)))
+
+static int32_t afe_callback(struct apr_client_data *data, void *priv)
+{
+	if (data->opcode == RESET_EVENTS) {
+		pr_debug("q6afe: reset event = %d %d apr[%p]\n",
+			data->reset_event, data->reset_proc, this_afe.apr);
+		if (this_afe.apr) {
+			apr_reset(this_afe.apr);
+			atomic_set(&this_afe.state, 0);
+			this_afe.apr = NULL;
+		}
+		return 0;
+	}
+	pr_debug("%s:opcode = 0x%x cmd = 0x%x status = 0x%x\n",
+				__func__, data->opcode,
+				((uint32_t *)(data->payload))[0],
+				((uint32_t *)(data->payload))[1]);
+	if (data->payload_size) {
+		uint32_t *payload;
+		uint16_t port_id = 0;
+		payload = data->payload;
+		pr_debug("%s:opcode = 0x%x cmd = 0x%x status = 0x%x token=%d\n",
+					__func__, data->opcode,
+					payload[0], payload[1], data->token);
+		/* payload[1] contains the error status for response */
+		if (payload[1] != 0) {
+			atomic_set(&this_afe.status, -1);
+			pr_err("%s: cmd = 0x%x returned error = 0x%x\n",
+					__func__, payload[0], payload[1]);
+		}
+		if (data->opcode == APR_BASIC_RSP_RESULT) {
+			switch (payload[0]) {
+			case AFE_PORT_CMD_DEVICE_STOP:
+			case AFE_PORT_CMD_DEVICE_START:
+			case AFE_PORT_CMD_SET_PARAM_V2:
+			case AFE_PSEUDOPORT_CMD_START:
+			case AFE_PSEUDOPORT_CMD_STOP:
+			case AFE_SERVICE_CMD_SHARED_MEM_MAP_REGIONS:
+			case AFE_SERVICE_CMD_SHARED_MEM_UNMAP_REGIONS:
+			case AFE_SERVICE_CMD_UNREGISTER_RT_PORT_DRIVER:
+				atomic_set(&this_afe.state, 0);
+				wake_up(&this_afe.wait[data->token]);
+				break;
+			case AFE_SERVICE_CMD_REGISTER_RT_PORT_DRIVER:
+				break;
+			case AFE_PORT_DATA_CMD_RT_PROXY_PORT_WRITE_V2:
+				port_id = RT_PROXY_PORT_001_TX;
+				break;
+			case AFE_PORT_DATA_CMD_RT_PROXY_PORT_READ_V2:
+				port_id = RT_PROXY_PORT_001_RX;
+				break;
+			default:
+				pr_err("%s:Unknown cmd 0x%x\n", __func__,
+						payload[0]);
+				break;
+			}
+		} else if (data->opcode == AFE_EVENT_RT_PROXY_PORT_STATUS) {
+			port_id = (uint16_t)(0x0000FFFF & payload[0]);
+		}
+		pr_debug("%s:port_id = %x\n", __func__, port_id);
+		switch (port_id) {
+		case RT_PROXY_PORT_001_TX: {
+			if (this_afe.tx_cb) {
+				this_afe.tx_cb(data->opcode, data->token,
+					data->payload,
+					this_afe.tx_private_data);
+			}
+			break;
+		}
+		case RT_PROXY_PORT_001_RX: {
+			if (this_afe.rx_cb) {
+				this_afe.rx_cb(data->opcode, data->token,
+					data->payload,
+					this_afe.rx_private_data);
+			}
+			break;
+		}
+		default:
+			break;
+		}
+	}
+	return 0;
+}
+
+
+int afe_get_port_type(u16 port_id)
+{
+	int ret;
+
+	switch (port_id) {
+	case PRIMARY_I2S_RX:
+	case PCM_RX:
+	case SECONDARY_I2S_RX:
+	case MI2S_RX:
+	case HDMI_RX:
+	case SLIMBUS_0_RX:
+	case SLIMBUS_1_RX:
+	case INT_BT_SCO_RX:
+	case INT_BT_A2DP_RX:
+	case INT_FM_RX:
+	case VOICE_PLAYBACK_TX:
+	case RT_PROXY_PORT_001_RX:
+		ret = MSM_AFE_PORT_TYPE_RX;
+		break;
+
+	case PRIMARY_I2S_TX:
+	case PCM_TX:
+	case SECONDARY_I2S_TX:
+	case MI2S_TX:
+	case DIGI_MIC_TX:
+	case VOICE_RECORD_TX:
+	case SLIMBUS_0_TX:
+	case SLIMBUS_1_TX:
+	case INT_FM_TX:
+	case VOICE_RECORD_RX:
+	case INT_BT_SCO_TX:
+	case RT_PROXY_PORT_001_TX:
+		ret = MSM_AFE_PORT_TYPE_TX;
+		break;
+
+	default:
+		pr_err("%s: invalid port id %d\n", __func__, port_id);
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+int afe_sizeof_cfg_cmd(u16 port_id)
+{
+	int ret_size;
+	switch (port_id) {
+	case PRIMARY_I2S_RX:
+	case PRIMARY_I2S_TX:
+	case SECONDARY_I2S_RX:
+	case SECONDARY_I2S_TX:
+	case MI2S_RX:
+	case MI2S_TX:
+		ret_size = SIZEOF_CFG_CMD(afe_param_id_i2s_cfg);
+		break;
+	case HDMI_RX:
+		ret_size =
+		SIZEOF_CFG_CMD(afe_param_id_hdmi_multi_chan_audio_cfg);
+		break;
+	case SLIMBUS_0_RX:
+	case SLIMBUS_0_TX:
+	case SLIMBUS_1_RX:
+	case SLIMBUS_1_TX:
+		ret_size = SIZEOF_CFG_CMD(afe_param_id_slimbus_cfg);
+		break;
+	case RT_PROXY_PORT_001_RX:
+	case RT_PROXY_PORT_001_TX:
+		ret_size = SIZEOF_CFG_CMD(afe_param_id_rt_proxy_port_cfg);
+		break;
+	case PCM_RX:
+	case PCM_TX:
+	default:
+		ret_size = SIZEOF_CFG_CMD(afe_param_id_pcm_cfg);
+		break;
+	}
+	return ret_size;
+}
+
+int afe_q6_interface_prepare(void)
+{
+	int ret = 0;
+
+	pr_debug("%s:", __func__);
+
+	if (this_afe.apr == NULL) {
+		this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
+			0xFFFFFFFF, &this_afe);
+		if (this_afe.apr == NULL) {
+			pr_err("%s: Unable to register AFE\n", __func__);
+			ret = -ENODEV;
+		}
+	}
+	return ret;
+}
+static void afe_send_cal_block(int32_t path, u16 port_id)
+{
+	/* To come back */
+}
+
+void afe_send_cal(u16 port_id)
+{
+	pr_debug("%s\n", __func__);
+
+	if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_TX)
+		afe_send_cal_block(TX_CAL, port_id);
+	else if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_RX)
+		afe_send_cal_block(RX_CAL, port_id);
+}
+
+int afe_port_start_nowait(u16 port_id, union afe_port_config *afe_config,
+	u32 rate) /* This function is no blocking */
+{
+	struct afe_port_cmd_device_start start;
+	struct afe_audioif_config_command config;
+	int ret;
+	int cfg_type;
+	int index = 0;
+
+	if (!afe_config) {
+		pr_err("%s: Error, no configuration data\n", __func__);
+		ret = -EINVAL;
+		return ret;
+	}
+	pr_err("%s: %d %d\n", __func__, port_id, rate);
+	index = q6audio_get_port_index(port_id);
+	if (q6audio_validate_port(port_id) < 0)
+		return -EINVAL;
+
+	if ((port_id == RT_PROXY_DAI_001_RX) ||
+		(port_id == RT_PROXY_DAI_002_TX))
+		return -EINVAL;
+	if ((port_id == RT_PROXY_DAI_002_RX) ||
+		(port_id == RT_PROXY_DAI_001_TX))
+		port_id = VIRTUAL_ID_TO_PORTID(port_id);
+
+	ret = afe_q6_interface_prepare();
+	if (ret != 0)
+		return ret;
+	if (q6audio_validate_port(port_id) < 0) {
+		pr_err("%s: Failed : Invalid Port id = %d\n", __func__,
+				port_id);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+
+	config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	config.hdr.pkt_size = afe_sizeof_cfg_cmd(port_id);
+	config.hdr.src_port = 0;
+	config.hdr.dest_port = 0;
+
+	config.hdr.token = index;
+	switch (port_id) {
+	case PRIMARY_I2S_RX:
+	case PRIMARY_I2S_TX:
+		cfg_type = AFE_PARAM_ID_PCM_CONFIG;
+		break;
+	case PCM_RX:
+	case PCM_TX:
+		cfg_type = AFE_PARAM_ID_HDMI_CONFIG;
+		break;
+	case SECONDARY_I2S_RX:
+	case SECONDARY_I2S_TX:
+	case MI2S_RX:
+	case MI2S_TX:
+		cfg_type = AFE_PARAM_ID_I2S_CONFIG;
+		break;
+	case HDMI_RX:
+		cfg_type = AFE_PARAM_ID_HDMI_CONFIG;
+		break;
+	case SLIMBUS_0_RX:
+	case SLIMBUS_0_TX:
+	case SLIMBUS_1_RX:
+	case SLIMBUS_1_TX:
+	case SLIMBUS_2_RX:
+	case SLIMBUS_2_TX:
+	case SLIMBUS_3_RX:
+	case SLIMBUS_3_TX:
+	case SLIMBUS_4_RX:
+	case SLIMBUS_4_TX:
+		cfg_type = AFE_PARAM_ID_SLIMBUS_CONFIG;
+		break;
+	default:
+		pr_err("%s: Invalid port id 0x%x\n", __func__, port_id);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+	config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+	config.param.port_id = port_id;
+	config.param.payload_size = (afe_sizeof_cfg_cmd(port_id) +
+				sizeof(struct afe_port_param_data_v2));
+	config.param.payload_address_lsw = 0x00;
+	config.param.payload_address_msw = 0x00;
+	config.param.mem_map_handle = 0x00;
+	config.pdata.module_id = AFE_MODULE_AUDIO_DEV_INTERFACE;
+	config.pdata.param_id = cfg_type;
+	config.pdata.param_size =  afe_sizeof_cfg_cmd(port_id);
+
+	config.port = *afe_config;
+
+	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &config);
+	if (ret < 0) {
+		pr_err("%s: AFE enable for port %d failed\n", __func__,
+				port_id);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+
+	/* send AFE cal */
+	afe_send_cal(port_id);
+
+	start.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	start.hdr.pkt_size = sizeof(start);
+	start.hdr.src_port = 0;
+	start.hdr.dest_port = 0;
+	start.hdr.token = 0;
+	start.hdr.opcode = AFE_PORT_CMD_DEVICE_START;
+	start.port_id = port_id;
+
+	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
+
+	if (IS_ERR_VALUE(ret)) {
+		pr_err("%s: AFE enable for port %d failed\n", __func__,
+				port_id);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+
+	return 0;
+
+fail_cmd:
+	return ret;
+}
+
+int afe_open(u16 port_id,
+		union afe_port_config *afe_config, int rate)
+{
+	struct afe_port_cmd_device_start start;
+	struct afe_audioif_config_command config;
+	int ret = 0;
+	int cfg_type;
+	int index = 0;
+
+	if (!afe_config) {
+		pr_err("%s: Error, no configuration data\n", __func__);
+		ret = -EINVAL;
+		return ret;
+	}
+
+	pr_err("%s: %d %d\n", __func__, port_id, rate);
+
+	index = q6audio_get_port_index(port_id);
+	if (q6audio_validate_port(port_id) < 0)
+		return -EINVAL;
+
+	if ((port_id == RT_PROXY_DAI_001_RX) ||
+		(port_id == RT_PROXY_DAI_002_TX))
+		return -EINVAL;
+	if ((port_id == RT_PROXY_DAI_002_RX) ||
+		(port_id == RT_PROXY_DAI_001_TX))
+		port_id = VIRTUAL_ID_TO_PORTID(port_id);
+
+	ret = afe_q6_interface_prepare();
+	if (ret != 0)
+		return ret;
+
+	if (q6audio_validate_port(port_id) < 0) {
+		pr_err("%s: Failed : Invalid Port id = %d\n", __func__,
+				port_id);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+
+	config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	config.hdr.pkt_size = sizeof(config);
+	config.hdr.src_port = 0;
+	config.hdr.dest_port = 0;
+	config.hdr.token = index;
+	switch (port_id) {
+	case PRIMARY_I2S_RX:
+	case PRIMARY_I2S_TX:
+		cfg_type = AFE_PARAM_ID_I2S_CONFIG;
+		break;
+	case PCM_RX:
+	case PCM_TX:
+		cfg_type = AFE_PARAM_ID_PCM_CONFIG;
+		break;
+	case SECONDARY_I2S_RX:
+	case SECONDARY_I2S_TX:
+	case MI2S_RX:
+	case MI2S_TX:
+		cfg_type = AFE_PARAM_ID_I2S_CONFIG;
+		break;
+	case HDMI_RX:
+		cfg_type = AFE_PARAM_ID_HDMI_CONFIG;
+		break;
+	case SLIMBUS_0_RX:
+	case SLIMBUS_0_TX:
+	case SLIMBUS_1_RX:
+	case SLIMBUS_1_TX:
+	case SLIMBUS_2_RX:
+	case SLIMBUS_2_TX:
+	case SLIMBUS_3_RX:
+	case SLIMBUS_3_TX:
+	case SLIMBUS_4_RX:
+	case SLIMBUS_4_TX:
+		cfg_type = AFE_PARAM_ID_SLIMBUS_CONFIG;
+		break;
+	default:
+		pr_err("%s: Invalid port id 0x%x\n", __func__, port_id);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+	config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+	config.param.port_id = q6audio_get_port_id(port_id);
+	config.param.payload_size = sizeof(config) - sizeof(struct apr_hdr)
+				 - sizeof(config.param);
+	config.param.payload_address_lsw = 0x00;
+	config.param.payload_address_msw = 0x00;
+	config.param.mem_map_handle = 0x00;
+	config.pdata.module_id = AFE_MODULE_AUDIO_DEV_INTERFACE;
+	config.pdata.param_id = cfg_type;
+	config.pdata.param_size =  sizeof(config.port);
+
+	config.port = *afe_config;
+	pr_debug("%s: param PL size=%d iparam_size[%d][%d %d %d %d]"
+		" param_id[%x]\n",
+		__func__, config.param.payload_size, config.pdata.param_size,
+		sizeof(config), sizeof(config.param), sizeof(config.port),
+		sizeof(struct apr_hdr), config.pdata.param_id);
+	atomic_set(&this_afe.state, 1);
+	atomic_set(&this_afe.status, 0);
+	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &config);
+	if (ret < 0) {
+		pr_err("%s: AFE enable for port %d opcode[0x%x]failed\n",
+			__func__, port_id, cfg_type);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+
+	ret = wait_event_timeout(this_afe.wait[index],
+			(atomic_read(&this_afe.state) == 0),
+				msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+	if (atomic_read(&this_afe.status) != 0) {
+		pr_err("%s: config cmd failed\n", __func__);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+	start.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	start.hdr.pkt_size = sizeof(start);
+	start.hdr.src_port = 0;
+	start.hdr.dest_port = 0;
+	start.hdr.token = index;
+	start.hdr.opcode = AFE_PORT_CMD_DEVICE_START;
+	start.port_id = q6audio_get_port_id(port_id);
+	pr_debug("%s: cmd device start opcode[0x%x] port id[0x%x]\n",
+		__func__, start.hdr.opcode, start.port_id);
+	atomic_set(&this_afe.state, 1);
+	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
+	if (ret < 0) {
+		pr_err("%s: AFE enable for port %d failed\n", __func__,
+				port_id);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+	ret = wait_event_timeout(this_afe.wait[index],
+			(atomic_read(&this_afe.state) == 0),
+				msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+
+	return 0;
+fail_cmd:
+	return ret;
+}
+
+int afe_loopback(u16 enable, u16 rx_port, u16 tx_port)
+{
+	struct afe_loopback_cfg_v1 lb_cmd;
+	int ret = 0;
+	int index = 0;
+
+	ret = afe_q6_interface_prepare();
+	if (ret != 0)
+		return ret;
+
+	index = q6audio_get_port_index(rx_port);
+	if (q6audio_validate_port(rx_port) < 0)
+		return -EINVAL;
+
+	lb_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+						APR_HDR_LEN(20), APR_PKT_VER);
+	lb_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+						sizeof(lb_cmd) - APR_HDR_SIZE);
+	lb_cmd.hdr.src_port = 0;
+	lb_cmd.hdr.dest_port = 0;
+	lb_cmd.hdr.token = 0;
+	lb_cmd.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+	lb_cmd.param.port_id = tx_port;
+	lb_cmd.param.payload_size = (sizeof(lb_cmd) -
+			sizeof(struct apr_hdr) -
+			sizeof(struct afe_port_cmd_set_param_v2));
+	lb_cmd.param.payload_address_lsw = 0x00;
+	lb_cmd.param.payload_address_msw = 0x00;
+	lb_cmd.param.mem_map_handle = 0x00;
+	lb_cmd.pdata.module_id = AFE_MODULE_LOOPBACK;
+	lb_cmd.pdata.param_id = AFE_PARAM_ID_LOOPBACK_CONFIG;
+	lb_cmd.pdata.param_size =  lb_cmd.param.payload_size -
+				sizeof(struct afe_port_param_data_v2);
+
+	lb_cmd.dst_port_id = rx_port;
+	lb_cmd.routing_mode = LB_MODE_DEFAULT;
+	lb_cmd.enable = (enable ? 1 : 0);
+	lb_cmd.loopback_cfg_minor_version =
+					AFE_API_VERSION_LOOPBACK_CONFIG;
+	atomic_set(&this_afe.state, 1);
+
+	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &lb_cmd);
+	if (ret < 0) {
+		pr_err("%s: AFE loopback failed\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+	ret = wait_event_timeout(this_afe.wait[index],
+		(atomic_read(&this_afe.state) == 0),
+				msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		ret = -EINVAL;
+	}
+done:
+	return ret;
+}
+
+int afe_loopback_gain(u16 port_id, u16 volume)
+{
+	struct afe_loopback_gain_per_path_param set_param;
+	int ret = 0;
+	int index = 0;
+
+	if (this_afe.apr == NULL) {
+		this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
+					0xFFFFFFFF, &this_afe);
+		pr_debug("%s: Register AFE\n", __func__);
+		if (this_afe.apr == NULL) {
+			pr_err("%s: Unable to register AFE\n", __func__);
+			ret = -ENODEV;
+			return ret;
+		}
+	}
+
+	if (q6audio_validate_port(port_id) < 0) {
+
+		pr_err("%s: Failed : Invalid Port id = %d\n", __func__,
+				port_id);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+	index = q6audio_get_port_index(port_id);
+	if (q6audio_validate_port(port_id) < 0)
+		return -EINVAL;
+
+	/* RX ports numbers are even .TX ports numbers are odd. */
+	if (port_id % 2 == 0) {
+		pr_err("%s: Failed : afe loopback gain only for TX ports."
+			" port_id %d\n", __func__, port_id);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+
+	pr_debug("%s: %d %hX\n", __func__, port_id, volume);
+
+	set_param.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	set_param.hdr.pkt_size = sizeof(set_param);
+	set_param.hdr.src_port = 0;
+	set_param.hdr.dest_port = 0;
+	set_param.hdr.token = 0;
+	set_param.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+
+	set_param.param.port_id		= port_id;
+	set_param.param.payload_size		=
+		(sizeof(struct afe_loopback_gain_per_path_param) -
+		 sizeof(struct apr_hdr) -
+		sizeof(struct afe_port_cmd_set_param_v2));
+	set_param.param.payload_address_lsw	= 0;
+	set_param.param.payload_address_msw	= 0;
+	set_param.param.mem_map_handle        = 0;
+
+	set_param.pdata.module_id	= AFE_MODULE_LOOPBACK;
+	set_param.pdata.param_id	= AFE_PARAM_ID_LOOPBACK_GAIN_PER_PATH;
+	set_param.pdata.param_size = (set_param.param.payload_size -
+				sizeof(struct afe_port_param_data_v2));
+	set_param.rx_port_id = port_id;
+	set_param.gain	= volume;
+
+	set_param.hdr.token = index;
+
+	atomic_set(&this_afe.state, 1);
+	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &set_param);
+	if (ret < 0) {
+		pr_err("%s: AFE param set failed for port %d\n",
+					__func__, port_id);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+
+	ret = wait_event_timeout(this_afe.wait[index],
+		(atomic_read(&this_afe.state) == 0),
+			msecs_to_jiffies(TIMEOUT_MS));
+	if (ret < 0) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return ret;
+}
+
+int afe_pseudo_port_start_nowait(u16 port_id)
+{
+	struct afe_pseudoport_start_command start;
+	int ret = 0;
+
+	pr_debug("%s: port_id=%d\n", __func__, port_id);
+	if (this_afe.apr == NULL) {
+		pr_err("%s: AFE APR is not registered\n", __func__);
+		return -ENODEV;
+	}
+
+
+	start.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	start.hdr.pkt_size = sizeof(start);
+	start.hdr.src_port = 0;
+	start.hdr.dest_port = 0;
+	start.hdr.token = 0;
+	start.hdr.opcode = AFE_PSEUDOPORT_CMD_START;
+	start.port_id = port_id;
+	start.timing = 1;
+
+	atomic_set(&this_afe.state, 1);
+	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
+	if (ret < 0) {
+		pr_err("%s: AFE enable for port %d failed %d\n",
+		       __func__, port_id, ret);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+int afe_start_pseudo_port(u16 port_id)
+{
+	int ret = 0;
+	struct afe_pseudoport_start_command start;
+	int index = 0;
+
+	pr_debug("%s: port_id=%d\n", __func__, port_id);
+
+	ret = afe_q6_interface_prepare();
+	if (ret != 0)
+		return ret;
+
+	index = q6audio_get_port_index(port_id);
+	if (q6audio_validate_port(port_id) < 0)
+		return -EINVAL;
+
+	start.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	start.hdr.pkt_size = sizeof(start);
+	start.hdr.src_port = 0;
+	start.hdr.dest_port = 0;
+	start.hdr.token = 0;
+	start.hdr.opcode = AFE_PSEUDOPORT_CMD_START;
+	start.port_id = port_id;
+	start.timing = 1;
+
+	start.hdr.token = index;
+	atomic_set(&this_afe.state, 1);
+	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
+	if (ret < 0) {
+		pr_err("%s: AFE enable for port %d failed %d\n",
+		       __func__, port_id, ret);
+		return -EINVAL;
+	}
+
+	ret = wait_event_timeout(this_afe.wait[index],
+				 (atomic_read(&this_afe.state) == 0),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+int afe_pseudo_port_stop_nowait(u16 port_id)
+{
+	int ret = 0;
+	struct afe_pseudoport_stop_command stop;
+	int index = 0;
+
+	pr_debug("%s: port_id=%d\n", __func__, port_id);
+
+	if (this_afe.apr == NULL) {
+		pr_err("%s: AFE is already closed\n", __func__);
+		return -EINVAL;
+	}
+	index = q6audio_get_port_index(port_id);
+	if (q6audio_validate_port(port_id) < 0)
+		return -EINVAL;
+
+	stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	stop.hdr.pkt_size = sizeof(stop);
+	stop.hdr.src_port = 0;
+	stop.hdr.dest_port = 0;
+	stop.hdr.token = 0;
+	stop.hdr.opcode = AFE_PSEUDOPORT_CMD_STOP;
+	stop.port_id = port_id;
+	stop.reserved = 0;
+
+	stop.hdr.token = index;
+	atomic_set(&this_afe.state, 1);
+	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &stop);
+	if (ret < 0) {
+		pr_err("%s: AFE close failed %d\n", __func__, ret);
+		return -EINVAL;
+	}
+
+	return 0;
+
+}
+
+int afe_stop_pseudo_port(u16 port_id)
+{
+	int ret = 0;
+	struct afe_pseudoport_stop_command stop;
+	int index = 0;
+
+	pr_debug("%s: port_id=%d\n", __func__, port_id);
+
+	if (this_afe.apr == NULL) {
+		pr_err("%s: AFE is already closed\n", __func__);
+		return -EINVAL;
+	}
+
+	index = q6audio_get_port_index(port_id);
+	if (q6audio_validate_port(port_id) < 0)
+		return -EINVAL;
+
+	stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	stop.hdr.pkt_size = sizeof(stop);
+	stop.hdr.src_port = 0;
+	stop.hdr.dest_port = 0;
+	stop.hdr.token = 0;
+	stop.hdr.opcode = AFE_PSEUDOPORT_CMD_STOP;
+	stop.port_id = port_id;
+	stop.reserved = 0;
+
+	stop.hdr.token = index;
+	atomic_set(&this_afe.state, 1);
+	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &stop);
+	if (ret < 0) {
+		pr_err("%s: AFE close failed %d\n", __func__, ret);
+		return -EINVAL;
+	}
+
+	ret = wait_event_timeout(this_afe.wait[index],
+				 (atomic_read(&this_afe.state) == 0),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*bharath, memory map handle needs to be stored by AFE client */
+int afe_cmd_memory_map(u32 dma_addr_p, u32 dma_buf_sz)
+{
+	int ret = 0;
+	int cmd_size = 0;
+	void    *payload = NULL;
+	void    *mmap_region_cmd = NULL;
+	struct afe_service_cmd_shared_mem_map_regions *mregion = NULL;
+	struct  afe_service_shared_map_region_payload *mregion_pl = NULL;
+	int index = 0;
+
+	pr_debug("%s:\n", __func__);
+
+	if (this_afe.apr == NULL) {
+		this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
+					0xFFFFFFFF, &this_afe);
+		pr_debug("%s: Register AFE\n", __func__);
+		if (this_afe.apr == NULL) {
+			pr_err("%s: Unable to register AFE\n", __func__);
+			ret = -ENODEV;
+			return ret;
+		}
+	}
+
+	cmd_size = sizeof(struct afe_service_cmd_shared_mem_map_regions) \
+		+ sizeof(struct afe_service_shared_map_region_payload);
+
+	mmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL);
+	if (!mmap_region_cmd) {
+		pr_err("%s: allocate mmap_region_cmd failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	mregion = (struct afe_service_cmd_shared_mem_map_regions *)
+							mmap_region_cmd;
+	mregion->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	mregion->hdr.pkt_size = sizeof(mregion);
+	mregion->hdr.src_port = 0;
+	mregion->hdr.dest_port = 0;
+	mregion->hdr.token = 0;
+	mregion->hdr.opcode = AFE_SERVICE_CMD_SHARED_MEM_MAP_REGIONS;
+	mregion->mem_pool_id = ADSP_MEMORY_MAP_EBI_POOL;
+	mregion->num_regions = 1;
+	mregion->property_flag = 0x00;
+	/* Todo */
+	index = mregion->hdr.token = IDX_RSVD_2;
+
+	payload = ((u8 *) mmap_region_cmd +
+		   sizeof(struct afe_service_cmd_shared_mem_map_regions));
+
+	mregion_pl = (struct afe_service_shared_map_region_payload *)payload;
+
+	mregion_pl->shm_addr_lsw = dma_addr_p;
+	mregion_pl->shm_addr_msw = 0x00;
+	mregion_pl->mem_size_bytes = dma_buf_sz;
+
+	atomic_set(&this_afe.state, 1);
+	ret = apr_send_pkt(this_afe.apr, (uint32_t *) mmap_region_cmd);
+	if (ret < 0) {
+		pr_err("%s: AFE memory map cmd failed %d\n",
+		       __func__, ret);
+		ret = -EINVAL;
+		return ret;
+	}
+
+	ret = wait_event_timeout(this_afe.wait[index],
+				 (atomic_read(&this_afe.state) == 0),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		ret = -EINVAL;
+		return ret;
+	}
+
+	return 0;
+}
+
+int afe_cmd_memory_map_nowait(int port_id, u32 dma_addr_p, u32 dma_buf_sz)
+{
+	int ret = 0;
+	int cmd_size = 0;
+	void    *payload = NULL;
+	void    *mmap_region_cmd = NULL;
+	struct afe_service_cmd_shared_mem_map_regions *mregion = NULL;
+	struct  afe_service_shared_map_region_payload *mregion_pl = NULL;
+	int index = 0;
+
+	pr_debug("%s:\n", __func__);
+
+	if (this_afe.apr == NULL) {
+		this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
+					0xFFFFFFFF, &this_afe);
+		pr_debug("%s: Register AFE\n", __func__);
+		if (this_afe.apr == NULL) {
+			pr_err("%s: Unable to register AFE\n", __func__);
+			ret = -ENODEV;
+			return ret;
+		}
+	}
+	index = q6audio_get_port_index(port_id);
+	if (q6audio_validate_port(port_id) < 0)
+		return -EINVAL;
+
+	cmd_size = sizeof(struct afe_service_cmd_shared_mem_map_regions)
+		+ sizeof(struct afe_service_shared_map_region_payload);
+
+	mmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL);
+	if (!mmap_region_cmd) {
+		pr_err("%s: allocate mmap_region_cmd failed\n", __func__);
+		return -ENOMEM;
+	}
+	mregion = (struct afe_service_cmd_shared_mem_map_regions *)
+						mmap_region_cmd;
+	mregion->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	mregion->hdr.pkt_size = sizeof(mregion);
+	mregion->hdr.src_port = 0;
+	mregion->hdr.dest_port = 0;
+	mregion->hdr.token = 0;
+	mregion->hdr.opcode = AFE_SERVICE_CMD_SHARED_MEM_MAP_REGIONS;
+	mregion->mem_pool_id = ADSP_MEMORY_MAP_EBI_POOL;
+	mregion->num_regions = 1;
+	mregion->property_flag = 0x00;
+
+	payload = ((u8 *) mmap_region_cmd +
+		sizeof(struct afe_service_cmd_shared_mem_map_regions));
+	mregion_pl = (struct afe_service_shared_map_region_payload *)payload;
+
+	mregion_pl->shm_addr_lsw = dma_addr_p;
+	mregion_pl->shm_addr_msw = 0x00;
+	mregion_pl->mem_size_bytes = dma_buf_sz;
+
+	atomic_set(&this_afe.state, 1);
+	ret = apr_send_pkt(this_afe.apr, (uint32_t *) mmap_region_cmd);
+	if (ret < 0) {
+		pr_err("%s: AFE memory map cmd failed %d\n",
+		       __func__, ret);
+		ret = -EINVAL;
+		return ret;
+	}
+	return 0;
+}
+
+int afe_cmd_memory_unmap(u32 mem_map_handle)
+{
+	int ret = 0;
+	struct afe_service_cmd_shared_mem_unmap_regions mregion;
+	int index = 0;
+
+	pr_debug("%s:\n", __func__);
+
+	if (this_afe.apr == NULL) {
+		this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
+					0xFFFFFFFF, &this_afe);
+		pr_debug("%s: Register AFE\n", __func__);
+		if (this_afe.apr == NULL) {
+			pr_err("%s: Unable to register AFE\n", __func__);
+			ret = -ENODEV;
+			return ret;
+		}
+	}
+
+	mregion.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	mregion.hdr.pkt_size = sizeof(mregion);
+	mregion.hdr.src_port = 0;
+	mregion.hdr.dest_port = 0;
+	mregion.hdr.token = 0;
+	mregion.hdr.opcode = AFE_SERVICE_CMD_SHARED_MEM_UNMAP_REGIONS;
+	mregion.mem_map_handle = mem_map_handle;
+
+	/* Todo */
+	index = mregion.hdr.token = IDX_RSVD_2;
+
+	atomic_set(&this_afe.state, 1);
+	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &mregion);
+	if (ret < 0) {
+		pr_err("%s: AFE memory unmap cmd failed %d\n",
+		       __func__, ret);
+		ret = -EINVAL;
+		return ret;
+	}
+
+	ret = wait_event_timeout(this_afe.wait[index],
+				 (atomic_read(&this_afe.state) == 0),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		ret = -EINVAL;
+		return ret;
+	}
+	return 0;
+}
+
+int afe_cmd_memory_unmap_nowait(u32 mem_map_handle)
+{
+	int ret = 0;
+	struct afe_service_cmd_shared_mem_unmap_regions mregion;
+
+	pr_debug("%s:\n", __func__);
+
+	if (this_afe.apr == NULL) {
+		this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
+					0xFFFFFFFF, &this_afe);
+		pr_debug("%s: Register AFE\n", __func__);
+		if (this_afe.apr == NULL) {
+			pr_err("%s: Unable to register AFE\n", __func__);
+			ret = -ENODEV;
+			return ret;
+		}
+	}
+
+	mregion.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	mregion.hdr.pkt_size = sizeof(mregion);
+	mregion.hdr.src_port = 0;
+	mregion.hdr.dest_port = 0;
+	mregion.hdr.token = 0;
+	mregion.hdr.opcode = AFE_SERVICE_CMD_SHARED_MEM_UNMAP_REGIONS;
+	mregion.mem_map_handle = mem_map_handle;
+
+	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &mregion);
+	if (ret < 0) {
+		pr_err("%s: AFE memory unmap cmd failed %d\n",
+			__func__, ret);
+		ret = -EINVAL;
+	}
+	return 0;
+}
+
+int afe_register_get_events(u16 port_id,
+		void (*cb) (uint32_t opcode,
+		uint32_t token, uint32_t *payload, void *priv),
+		void *private_data)
+{
+	int ret = 0;
+	struct afe_service_cmd_register_rt_port_driver rtproxy;
+
+	pr_debug("%s:\n", __func__);
+
+	if (this_afe.apr == NULL) {
+		this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
+					0xFFFFFFFF, &this_afe);
+		pr_debug("%s: Register AFE\n", __func__);
+		if (this_afe.apr == NULL) {
+			pr_err("%s: Unable to register AFE\n", __func__);
+			ret = -ENODEV;
+			return ret;
+		}
+	}
+	if ((port_id == RT_PROXY_DAI_002_RX) ||
+		(port_id == RT_PROXY_DAI_001_TX))
+		port_id = VIRTUAL_ID_TO_PORTID(port_id);
+	else
+		return -EINVAL;
+
+	if (port_id == RT_PROXY_PORT_001_TX) {
+		this_afe.tx_cb = cb;
+		this_afe.tx_private_data = private_data;
+	} else if (port_id == RT_PROXY_PORT_001_RX) {
+		this_afe.rx_cb = cb;
+		this_afe.rx_private_data = private_data;
+	}
+
+	rtproxy.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	rtproxy.hdr.pkt_size = sizeof(rtproxy);
+	rtproxy.hdr.src_port = 1;
+	rtproxy.hdr.dest_port = 1;
+	rtproxy.hdr.opcode = AFE_SERVICE_CMD_REGISTER_RT_PORT_DRIVER;
+	rtproxy.port_id = port_id;
+	rtproxy.reserved = 0;
+
+	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &rtproxy);
+	if (ret < 0) {
+		pr_err("%s: AFE  reg. rtproxy_event failed %d\n",
+			   __func__, ret);
+		ret = -EINVAL;
+		return ret;
+	}
+	return 0;
+}
+
+int afe_unregister_get_events(u16 port_id)
+{
+	int ret = 0;
+	struct afe_service_cmd_unregister_rt_port_driver rtproxy;
+	int index = 0;
+
+	pr_debug("%s:\n", __func__);
+
+	if (this_afe.apr == NULL) {
+		this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
+					0xFFFFFFFF, &this_afe);
+		pr_debug("%s: Register AFE\n", __func__);
+		if (this_afe.apr == NULL) {
+			pr_err("%s: Unable to register AFE\n", __func__);
+			ret = -ENODEV;
+			return ret;
+		}
+	}
+	index = q6audio_get_port_index(port_id);
+	if (q6audio_validate_port(port_id) < 0)
+		return -EINVAL;
+
+	if ((port_id == RT_PROXY_DAI_002_RX) ||
+		(port_id == RT_PROXY_DAI_001_TX))
+		port_id = VIRTUAL_ID_TO_PORTID(port_id);
+	else
+		return -EINVAL;
+
+	rtproxy.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	rtproxy.hdr.pkt_size = sizeof(rtproxy);
+	rtproxy.hdr.src_port = 0;
+	rtproxy.hdr.dest_port = 0;
+	rtproxy.hdr.token = 0;
+	rtproxy.hdr.opcode = AFE_SERVICE_CMD_UNREGISTER_RT_PORT_DRIVER;
+	rtproxy.port_id = port_id;
+	rtproxy.reserved = 0;
+
+	rtproxy.hdr.token = index;
+
+	if (port_id == RT_PROXY_PORT_001_TX) {
+		this_afe.tx_cb = NULL;
+		this_afe.tx_private_data = NULL;
+	} else if (port_id == RT_PROXY_PORT_001_RX) {
+		this_afe.rx_cb = NULL;
+		this_afe.rx_private_data = NULL;
+	}
+
+	atomic_set(&this_afe.state, 1);
+	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &rtproxy);
+	if (ret < 0) {
+		pr_err("%s: AFE enable Unreg. rtproxy_event failed %d\n",
+			   __func__, ret);
+		ret = -EINVAL;
+		return ret;
+	}
+
+	ret = wait_event_timeout(this_afe.wait[index],
+				 (atomic_read(&this_afe.state) == 0),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		ret = -EINVAL;
+		return ret;
+	}
+	return 0;
+}
+
+int afe_rt_proxy_port_write(u32 buf_addr_p, u32 mem_map_handle, int bytes)
+{
+	int ret = 0;
+	struct afe_port_data_cmd_rt_proxy_port_write_v2 afecmd_wr;
+
+	if (this_afe.apr == NULL) {
+		pr_err("%s:register to AFE is not done\n", __func__);
+		ret = -ENODEV;
+		return ret;
+	}
+	pr_debug("%s: buf_addr_p = 0x%08x bytes = %d\n", __func__,
+						buf_addr_p, bytes);
+
+	afecmd_wr.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	afecmd_wr.hdr.pkt_size = sizeof(afecmd_wr);
+	afecmd_wr.hdr.src_port = 0;
+	afecmd_wr.hdr.dest_port = 0;
+	afecmd_wr.hdr.token = 0;
+	afecmd_wr.hdr.opcode = AFE_PORT_DATA_CMD_RT_PROXY_PORT_WRITE_V2;
+	afecmd_wr.port_id = RT_PROXY_PORT_001_TX;
+	afecmd_wr.buffer_address_lsw = (uint32_t)buf_addr_p;
+	afecmd_wr.buffer_address_msw = 0x00;
+	afecmd_wr.mem_map_handle = mem_map_handle;
+	afecmd_wr.available_bytes = bytes;
+	afecmd_wr.reserved = 0;
+
+	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &afecmd_wr);
+	if (ret < 0) {
+		pr_err("%s: AFE rtproxy write to port 0x%x failed %d\n",
+			   __func__, afecmd_wr.port_id, ret);
+		ret = -EINVAL;
+		return ret;
+	}
+	return 0;
+
+}
+
+int afe_rt_proxy_port_read(u32 buf_addr_p, u32 mem_map_handle, int bytes)
+{
+	int ret = 0;
+	struct afe_port_data_cmd_rt_proxy_port_read_v2 afecmd_rd;
+
+	if (this_afe.apr == NULL) {
+		pr_err("%s: register to AFE is not done\n", __func__);
+		ret = -ENODEV;
+		return ret;
+	}
+	pr_debug("%s: buf_addr_p = 0x%08x bytes = %d\n", __func__,
+						buf_addr_p, bytes);
+
+	afecmd_rd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	afecmd_rd.hdr.pkt_size = sizeof(afecmd_rd);
+	afecmd_rd.hdr.src_port = 0;
+	afecmd_rd.hdr.dest_port = 0;
+	afecmd_rd.hdr.token = 0;
+	afecmd_rd.hdr.opcode = AFE_PORT_DATA_CMD_RT_PROXY_PORT_READ_V2;
+	afecmd_rd.port_id = RT_PROXY_PORT_001_RX;
+	afecmd_rd.buffer_address_lsw = (uint32_t)buf_addr_p;
+	afecmd_rd.buffer_address_msw = 0x00;
+	afecmd_rd.available_bytes = bytes;
+
+	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &afecmd_rd);
+	if (ret < 0) {
+		pr_err("%s: AFE rtproxy read  cmd to port 0x%x failed %d\n",
+			   __func__, afecmd_rd.port_id, ret);
+		ret = -EINVAL;
+		return ret;
+	}
+	return 0;
+}
+
+#ifdef CONFIG_DEBUG_FS
+static struct dentry *debugfs_afelb;
+static struct dentry *debugfs_afelb_gain;
+
+static int afe_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	pr_info("debug intf %s\n", (char *) file->private_data);
+	return 0;
+}
+
+static int afe_get_parameters(char *buf, long int *param1, int num_of_par)
+{
+	char *token;
+	int base, cnt;
+
+	token = strsep(&buf, " ");
+
+	for (cnt = 0; cnt < num_of_par; cnt++) {
+		if (token != NULL) {
+			if ((token[1] == 'x') || (token[1] == 'X'))
+				base = 16;
+			else
+				base = 10;
+
+			if (strict_strtoul(token, base, &param1[cnt]) != 0)
+				return -EINVAL;
+
+			token = strsep(&buf, " ");
+		} else
+			return -EINVAL;
+	}
+	return 0;
+}
+#define AFE_LOOPBACK_ON (1)
+#define AFE_LOOPBACK_OFF (0)
+static ssize_t afe_debug_write(struct file *filp,
+	const char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+	char *lb_str = filp->private_data;
+	char lbuf[32];
+	int rc;
+	unsigned long param[5];
+
+	if (cnt > sizeof(lbuf) - 1)
+		return -EINVAL;
+
+	rc = copy_from_user(lbuf, ubuf, cnt);
+	if (rc)
+		return -EFAULT;
+
+	lbuf[cnt] = '\0';
+
+	if (!strncmp(lb_str, "afe_loopback", 12)) {
+		rc = afe_get_parameters(lbuf, param, 3);
+		if (!rc) {
+			pr_info("%s %lu %lu %lu\n", lb_str, param[0], param[1],
+				param[2]);
+
+			if ((param[0] != AFE_LOOPBACK_ON) && (param[0] !=
+				AFE_LOOPBACK_OFF)) {
+				pr_err("%s: Error, parameter 0 incorrect\n",
+					__func__);
+				rc = -EINVAL;
+				goto afe_error;
+			}
+			if ((q6audio_validate_port(param[1]) < 0) ||
+			    (q6audio_validate_port(param[2])) < 0) {
+				pr_err("%s: Error, invalid afe port\n",
+					__func__);
+			}
+			if (this_afe.apr == NULL) {
+				pr_err("%s: Error, AFE not opened\n", __func__);
+				rc = -EINVAL;
+			} else {
+				rc = afe_loopback(param[0], param[1], param[2]);
+			}
+		} else {
+			pr_err("%s: Error, invalid parameters\n", __func__);
+			rc = -EINVAL;
+		}
+
+	} else if (!strncmp(lb_str, "afe_loopback_gain", 17)) {
+		rc = afe_get_parameters(lbuf, param, 2);
+		if (!rc) {
+			pr_info("%s %lu %lu\n", lb_str, param[0], param[1]);
+
+			if (q6audio_validate_port(param[0]) < 0) {
+				pr_err("%s: Error, invalid afe port\n",
+					__func__);
+				rc = -EINVAL;
+				goto afe_error;
+			}
+
+			if (param[1] < 0 || param[1] > 100) {
+				pr_err("%s: Error, volume shoud be 0 to 100"
+					" percentage param = %lu\n",
+					__func__, param[1]);
+				rc = -EINVAL;
+				goto afe_error;
+			}
+
+			param[1] = (Q6AFE_MAX_VOLUME * param[1]) / 100;
+
+			if (this_afe.apr == NULL) {
+				pr_err("%s: Error, AFE not opened\n", __func__);
+				rc = -EINVAL;
+			} else {
+				rc = afe_loopback_gain(param[0], param[1]);
+			}
+		} else {
+			pr_err("%s: Error, invalid parameters\n", __func__);
+			rc = -EINVAL;
+		}
+	}
+
+afe_error:
+	if (rc == 0)
+		rc = cnt;
+	else
+		pr_err("%s: rc = %d\n", __func__, rc);
+
+	return rc;
+}
+
+static const struct file_operations afe_debug_fops = {
+	.open = afe_debug_open,
+	.write = afe_debug_write
+};
+
+static void config_debug_fs_init(void)
+{
+	debugfs_afelb = debugfs_create_file("afe_loopback",
+	S_IFREG | S_IWUGO, NULL, (void *) "afe_loopback",
+	&afe_debug_fops);
+
+	debugfs_afelb_gain = debugfs_create_file("afe_loopback_gain",
+	S_IFREG | S_IWUGO, NULL, (void *) "afe_loopback_gain",
+	&afe_debug_fops);
+}
+static void config_debug_fs_exit(void)
+{
+	if (debugfs_afelb)
+		debugfs_remove(debugfs_afelb);
+	if (debugfs_afelb_gain)
+		debugfs_remove(debugfs_afelb_gain);
+}
+#else
+static void config_debug_fs_init(void)
+{
+	return;
+}
+static void config_debug_fs_exit(void)
+{
+	return;
+}
+#endif
+int afe_sidetone(u16 tx_port_id, u16 rx_port_id, u16 enable, uint16_t gain)
+{
+	struct afe_loopback_cfg_v1 cmd_sidetone;
+	int ret = 0;
+	int index = 0;
+
+	pr_info("%s: tx_port_id:%d rx_port_id:%d enable:%d gain:%d\n", __func__,
+					tx_port_id, rx_port_id, enable, gain);
+	index = q6audio_get_port_index(rx_port_id);
+	if (q6audio_validate_port(rx_port_id) < 0)
+		return -EINVAL;
+
+	cmd_sidetone.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	cmd_sidetone.hdr.pkt_size = sizeof(cmd_sidetone);
+	cmd_sidetone.hdr.src_port = 0;
+	cmd_sidetone.hdr.dest_port = 0;
+	cmd_sidetone.hdr.token = 0;
+	cmd_sidetone.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+	/* should it be rx or tx port id ?? , bharath*/
+	cmd_sidetone.param.port_id = tx_port_id;
+	/* size of data param & payload */
+	cmd_sidetone.param.payload_size = (sizeof(cmd_sidetone) -
+			sizeof(struct apr_hdr) -
+			sizeof(struct afe_port_cmd_set_param_v2));
+	cmd_sidetone.param.payload_address_lsw = 0x00;
+	cmd_sidetone.param.payload_address_msw = 0x00;
+	cmd_sidetone.param.mem_map_handle = 0x00;
+	cmd_sidetone.pdata.module_id = AFE_MODULE_LOOPBACK;
+	cmd_sidetone.pdata.param_id = AFE_PARAM_ID_LOOPBACK_CONFIG;
+	/* size of actual payload only */
+	cmd_sidetone.pdata.param_size =  cmd_sidetone.param.payload_size -
+				sizeof(struct afe_port_param_data_v2);
+
+	cmd_sidetone.loopback_cfg_minor_version =
+					AFE_API_VERSION_LOOPBACK_CONFIG;
+	cmd_sidetone.dst_port_id = rx_port_id;
+	cmd_sidetone.routing_mode = LB_MODE_SIDETONE;
+	cmd_sidetone.enable = enable;
+
+	atomic_set(&this_afe.state, 1);
+	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &cmd_sidetone);
+	if (ret < 0) {
+		pr_err("%s: AFE sidetone failed for tx_port:%d rx_port:%d\n",
+					__func__, tx_port_id, rx_port_id);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+
+	ret = wait_event_timeout(this_afe.wait[index],
+		(atomic_read(&this_afe.state) == 0),
+			msecs_to_jiffies(TIMEOUT_MS));
+	if (ret < 0) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return ret;
+}
+
+int afe_port_stop_nowait(int port_id)
+{
+	struct afe_port_cmd_device_stop stop;
+	int ret = 0;
+
+	if (this_afe.apr == NULL) {
+		pr_err("AFE is already closed\n");
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+	pr_debug("%s: port_id=%d\n", __func__, port_id);
+	port_id = q6audio_convert_virtual_to_portid(port_id);
+
+	stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	stop.hdr.pkt_size = sizeof(stop);
+	stop.hdr.src_port = 0;
+	stop.hdr.dest_port = 0;
+	stop.hdr.token = 0;
+	stop.hdr.opcode = AFE_PORT_CMD_DEVICE_STOP;
+	stop.port_id = port_id;
+	stop.reserved = 0;
+
+	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &stop);
+
+	if (IS_ERR_VALUE(ret)) {
+		pr_err("%s: AFE close failed\n", __func__);
+		ret = -EINVAL;
+	}
+
+fail_cmd:
+	return ret;
+
+}
+
+int afe_close(int port_id)
+{
+	struct afe_port_cmd_device_stop stop;
+	int ret = 0;
+	int index = 0;
+
+
+	if (this_afe.apr == NULL) {
+		pr_err("AFE is already closed\n");
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+	pr_debug("%s: port_id=%d\n", __func__, port_id);
+
+	index = q6audio_get_port_index(port_id);
+	if (q6audio_validate_port(port_id) < 0)
+		return -EINVAL;
+
+	port_id = q6audio_convert_virtual_to_portid(port_id);
+
+	stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	stop.hdr.pkt_size = sizeof(stop);
+	stop.hdr.src_port = 0;
+	stop.hdr.dest_port = 0;
+	stop.hdr.token = index;
+	stop.hdr.opcode = AFE_PORT_CMD_DEVICE_STOP;
+	stop.port_id = q6audio_get_port_id(port_id);
+	stop.reserved = 0;
+
+	atomic_set(&this_afe.state, 1);
+	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &stop);
+
+	if (ret < 0) {
+		pr_err("%s: AFE close failed\n", __func__);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+
+	ret = wait_event_timeout(this_afe.wait[index],
+			(atomic_read(&this_afe.state) == 0),
+					msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+fail_cmd:
+	return ret;
+}
+
+static int __init afe_init(void)
+{
+	int i = 0;
+	atomic_set(&this_afe.state, 0);
+	atomic_set(&this_afe.status, 0);
+	this_afe.apr = NULL;
+	for (i = 0; i < AFE_MAX_PORTS; i++)
+		init_waitqueue_head(&this_afe.wait[i]);
+
+	config_debug_fs_init();
+	return 0;
+}
+
+static void __exit afe_exit(void)
+{
+	int i;
+
+	config_debug_fs_exit();
+	for (i = 0; i < MAX_AUDPROC_TYPES; i++) {
+		if (afe_cal_addr[i].cal_paddr != 0)
+			afe_cmd_memory_unmap_nowait(
+				afe_cal_addr[i].cal_paddr);
+	}
+}
+
+device_initcall(afe_init);
+__exitcall(afe_exit);
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
new file mode 100644
index 0000000..f982134
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -0,0 +1,3342 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/fs.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/dma-mapping.h>
+#include <linux/miscdevice.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/msm_audio.h>
+#include <linux/android_pmem.h>
+#include <linux/memory_alloc.h>
+#include <linux/debugfs.h>
+#include <linux/time.h>
+#include <linux/atomic.h>
+
+#include <asm/ioctls.h>
+
+#include <mach/memory.h>
+#include <mach/debug_mm.h>
+#include <mach/peripheral-loader.h>
+#include <mach/qdsp6v2/audio_acdb.h>
+#include <mach/qdsp6v2/rtac.h>
+#include <mach/msm_subsystem_map.h>
+
+#include <sound/apr_audio-v2.h>
+#include <sound/q6asm-v2.h>
+
+#define TRUE        0x01
+#define FALSE       0x00
+#define READDONE_IDX_STATUS 0
+#define READDONE_IDX_BUFADD_LSW 1
+#define READDONE_IDX_BUFADD_MSW 2
+#define READDONE_IDX_MEMMAP_HDL 3
+#define READDONE_IDX_SIZE 4
+#define READDONE_IDX_OFFSET 5
+#define READDONE_IDX_LSW_TS 6
+#define READDONE_IDX_MSW_TS 7
+#define READDONE_IDX_FLAGS 8
+#define READDONE_IDX_NUMFRAMES 9
+#define READDONE_IDX_SEQ_ID 10
+
+/* TODO, combine them together */
+static DEFINE_MUTEX(session_lock);
+struct asm_mmap {
+	atomic_t ref_cnt;
+	void *apr;
+};
+
+static struct asm_mmap this_mmap;
+/* session id: 0 reserved */
+static struct audio_client *session[SESSION_MAX+1];
+
+struct asm_buffer_node {
+	struct list_head list;
+	uint32_t  buf_addr_lsw;
+	uint32_t  mmap_hdl;
+};
+static int32_t q6asm_mmapcallback(struct apr_client_data *data, void *priv);
+static int32_t q6asm_callback(struct apr_client_data *data, void *priv);
+static void q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr,
+			uint32_t pkt_size, uint32_t cmd_flg);
+static void q6asm_add_hdr_async(struct audio_client *ac, struct apr_hdr *hdr,
+			uint32_t pkt_size, uint32_t cmd_flg);
+static int q6asm_memory_map_regions(struct audio_client *ac, int dir,
+				uint32_t bufsz, uint32_t bufcnt);
+static int q6asm_memory_unmap_regions(struct audio_client *ac, int dir,
+				uint32_t bufsz, uint32_t bufcnt);
+static void q6asm_reset_buf_state(struct audio_client *ac);
+
+
+#ifdef CONFIG_DEBUG_FS
+#define OUT_BUFFER_SIZE 56
+#define IN_BUFFER_SIZE 24
+
+static struct timeval out_cold_tv;
+static struct timeval out_warm_tv;
+static struct timeval out_cont_tv;
+static struct timeval in_cont_tv;
+static long out_enable_flag;
+static long in_enable_flag;
+static struct dentry *out_dentry;
+static struct dentry *in_dentry;
+static int in_cont_index;
+/*This var is used to keep track of first write done for cold output latency */
+static int out_cold_index;
+static char *out_buffer;
+static char *in_buffer;
+static int audio_output_latency_dbgfs_open(struct inode *inode,
+							struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+static ssize_t audio_output_latency_dbgfs_read(struct file *file,
+				char __user *buf, size_t count, loff_t *ppos)
+{
+	snprintf(out_buffer, OUT_BUFFER_SIZE, "%ld,%ld,%ld,%ld,%ld,%ld,",\
+		out_cold_tv.tv_sec, out_cold_tv.tv_usec, out_warm_tv.tv_sec,\
+		out_warm_tv.tv_usec, out_cont_tv.tv_sec, out_cont_tv.tv_usec);
+	return  simple_read_from_buffer(buf, OUT_BUFFER_SIZE, ppos,
+						out_buffer, OUT_BUFFER_SIZE);
+}
+static ssize_t audio_output_latency_dbgfs_write(struct file *file,
+			const char __user *buf, size_t count, loff_t *ppos)
+{
+	char *temp;
+
+	if (count > 2*sizeof(char))
+		return -EINVAL;
+	else
+		temp  = kmalloc(2*sizeof(char), GFP_KERNEL);
+
+	out_cold_index = 0;
+
+	if (temp) {
+		if (copy_from_user(temp, buf, 2*sizeof(char))) {
+			kfree(temp);
+			return -EFAULT;
+		}
+		if (!strict_strtol(temp, 10, &out_enable_flag)) {
+			kfree(temp);
+			return count;
+		}
+		kfree(temp);
+	}
+	return -EINVAL;
+}
+static const struct file_operations audio_output_latency_debug_fops = {
+	.open = audio_output_latency_dbgfs_open,
+	.read = audio_output_latency_dbgfs_read,
+	.write = audio_output_latency_dbgfs_write
+};
+static int audio_input_latency_dbgfs_open(struct inode *inode,
+							struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+static ssize_t audio_input_latency_dbgfs_read(struct file *file,
+				char __user *buf, size_t count, loff_t *ppos)
+{
+	snprintf(in_buffer, IN_BUFFER_SIZE, "%ld,%ld,",\
+				in_cont_tv.tv_sec, in_cont_tv.tv_usec);
+	return  simple_read_from_buffer(buf, IN_BUFFER_SIZE, ppos,
+						in_buffer, IN_BUFFER_SIZE);
+}
+static ssize_t audio_input_latency_dbgfs_write(struct file *file,
+			const char __user *buf, size_t count, loff_t *ppos)
+{
+	char *temp;
+
+	if (count > 2*sizeof(char))
+		return -EINVAL;
+	else
+		temp  = kmalloc(2*sizeof(char), GFP_KERNEL);
+	if (temp) {
+		if (copy_from_user(temp, buf, 2*sizeof(char))) {
+			kfree(temp);
+			return -EFAULT;
+		}
+		if (!strict_strtol(temp, 10, &in_enable_flag)) {
+			kfree(temp);
+			return count;
+		}
+		kfree(temp);
+	}
+	return -EINVAL;
+}
+static const struct file_operations audio_input_latency_debug_fops = {
+	.open = audio_input_latency_dbgfs_open,
+	.read = audio_input_latency_dbgfs_read,
+	.write = audio_input_latency_dbgfs_write
+};
+
+static void config_debug_fs_write_cb(void)
+{
+	if (out_enable_flag) {
+		/* For first Write done log the time and reset
+		out_cold_index*/
+		if (out_cold_index != 1) {
+			do_gettimeofday(&out_cold_tv);
+			pr_debug("COLD: apr_send_pkt at %ld"
+				"sec %ld microsec\n",\
+				out_cold_tv.tv_sec,\
+				out_cold_tv.tv_usec);
+			out_cold_index = 1;
+		}
+		pr_debug("out_enable_flag %ld",\
+				out_enable_flag);
+	}
+}
+static void config_debug_fs_read_cb(void)
+{
+	if (in_enable_flag) {
+		/* when in_cont_index == 7, DSP would be
+		* writing into the 8th 512 byte buffer and this
+		* timestamp is tapped here.Once done it then writes
+		* to 9th 512 byte buffer.These two buffers(8th, 9th)
+		* reach the test application in 5th iteration and that
+		* timestamp is tapped at user level. The difference
+		* of these two timestamps gives us the time between
+		* the time at which dsp started filling the sample
+		* required and when it reached the test application.
+		* Hence continuous input latency
+		*/
+		if (in_cont_index == 7) {
+			do_gettimeofday(&in_cont_tv);
+			pr_err("In_CONT:previous read buffer done"
+				"at %ld sec %ld microsec\n",\
+				in_cont_tv.tv_sec, in_cont_tv.tv_usec);
+		}
+		in_cont_index++;
+	}
+}
+
+static void config_debug_fs_reset_index(void)
+{
+	in_cont_index = 0;
+}
+
+static void config_debug_fs_run(void)
+{
+	if (out_enable_flag) {
+		do_gettimeofday(&out_cold_tv);
+		pr_debug("COLD: apr_send_pkt at %ld sec %ld microsec\n",\
+				out_cold_tv.tv_sec, out_cold_tv.tv_usec);
+	}
+}
+
+static void config_debug_fs_write(struct audio_buffer *ab)
+{
+	if (out_enable_flag) {
+		char zero_pattern[2] = {0x00, 0x00};
+		/* If First two byte is non zero and last two byte
+		is zero then it is warm output pattern */
+		if ((strncmp(((char *)ab->data), zero_pattern, 2)) &&
+		(!strncmp(((char *)ab->data + 2), zero_pattern, 2))) {
+			do_gettimeofday(&out_warm_tv);
+			pr_debug("WARM:apr_send_pkt at"
+			"%ld sec %ld microsec\n", out_warm_tv.tv_sec,\
+			out_warm_tv.tv_usec);
+			pr_debug("Warm Pattern Matched");
+		}
+		/* If First two byte is zero and last two byte is
+		non zero then it is cont ouput pattern */
+		else if ((!strncmp(((char *)ab->data), zero_pattern, 2))
+		&& (strncmp(((char *)ab->data + 2), zero_pattern, 2))) {
+			do_gettimeofday(&out_cont_tv);
+			pr_debug("CONT:apr_send_pkt at"
+			"%ld sec %ld microsec\n", out_cont_tv.tv_sec,\
+			out_cont_tv.tv_usec);
+			pr_debug("Cont Pattern Matched");
+		}
+	}
+}
+static void config_debug_fs_init(void)
+{
+	out_buffer = kmalloc(OUT_BUFFER_SIZE, GFP_KERNEL);
+	out_dentry = debugfs_create_file("audio_out_latency_measurement_node",\
+				S_IFREG | S_IRUGO | S_IWUGO,\
+				NULL, NULL, &audio_output_latency_debug_fops);
+	if (IS_ERR(out_dentry))
+		pr_err("debugfs_create_file failed\n");
+	in_buffer = kmalloc(IN_BUFFER_SIZE, GFP_KERNEL);
+	in_dentry = debugfs_create_file("audio_in_latency_measurement_node",\
+				S_IFREG | S_IRUGO | S_IWUGO,\
+				NULL, NULL, &audio_input_latency_debug_fops);
+	if (IS_ERR(in_dentry))
+		pr_err("debugfs_create_file failed\n");
+}
+#else
+static void config_debug_fs_write(struct audio_buffer *ab)
+{
+	return;
+}
+static void config_debug_fs_run(void)
+{
+	return;
+}
+static void config_debug_fs_reset_index(void)
+{
+	return;
+}
+static void config_debug_fs_read_cb(void)
+{
+	return;
+}
+static void config_debug_fs_write_cb(void)
+{
+	return;
+}
+static void config_debug_fs_init(void)
+{
+	return;
+}
+#endif
+
+
+static int q6asm_session_alloc(struct audio_client *ac)
+{
+	int n;
+	mutex_lock(&session_lock);
+	for (n = 1; n <= SESSION_MAX; n++) {
+		if (!session[n]) {
+			session[n] = ac;
+			mutex_unlock(&session_lock);
+			return n;
+		}
+	}
+	mutex_unlock(&session_lock);
+	return -ENOMEM;
+}
+
+static void q6asm_session_free(struct audio_client *ac)
+{
+	pr_debug("%s: sessionid[%d]\n", __func__, ac->session);
+	rtac_remove_popp_from_adm_devices(ac->session);
+	mutex_lock(&session_lock);
+	session[ac->session] = 0;
+	mutex_unlock(&session_lock);
+	ac->session = 0;
+	return;
+}
+
+int q6asm_audio_client_buf_free(unsigned int dir,
+			struct audio_client *ac)
+{
+	struct audio_port_data *port;
+	int cnt = 0;
+	int rc = 0;
+	pr_debug("%s: Session id %d\n", __func__, ac->session);
+	mutex_lock(&ac->cmd_lock);
+	if (ac->io_mode == SYNC_IO_MODE) {
+		port = &ac->port[dir];
+		if (!port->buf) {
+			mutex_unlock(&ac->cmd_lock);
+			return 0;
+		}
+		cnt = port->max_buf_cnt - 1;
+
+		if (cnt >= 0) {
+			rc = q6asm_memory_unmap_regions(ac, dir,
+							port->buf[0].size,
+							port->max_buf_cnt);
+			if (rc < 0)
+				pr_err("%s CMD Memory_unmap_regions failed\n",
+								__func__);
+		}
+
+		while (cnt >= 0) {
+			if (port->buf[cnt].data) {
+				ion_unmap_kernel(port->buf[cnt].client,
+						port->buf[cnt].handle);
+				ion_free(port->buf[cnt].client,
+						port->buf[cnt].handle);
+				ion_client_destroy(port->buf[cnt].client);
+				port->buf[cnt].data = NULL;
+				port->buf[cnt].phys = 0;
+				--(port->max_buf_cnt);
+			}
+			--cnt;
+		}
+		kfree(port->buf);
+		port->buf = NULL;
+	}
+	mutex_unlock(&ac->cmd_lock);
+	return 0;
+}
+
+int q6asm_audio_client_buf_free_contiguous(unsigned int dir,
+			struct audio_client *ac)
+{
+	struct audio_port_data *port;
+	int cnt = 0;
+	int rc = 0;
+	pr_debug("%s: Session id %d\n", __func__, ac->session);
+	mutex_lock(&ac->cmd_lock);
+	port = &ac->port[dir];
+	if (!port->buf) {
+		mutex_unlock(&ac->cmd_lock);
+		return 0;
+	}
+	cnt = port->max_buf_cnt - 1;
+
+	if (cnt >= 0) {
+		rc = q6asm_memory_unmap(ac, port->buf[0].phys, dir);
+		if (rc < 0)
+			pr_err("%s CMD Memory_unmap_regions failed\n",
+							__func__);
+	}
+
+	if (port->buf[0].data) {
+		ion_unmap_kernel(port->buf[0].client, port->buf[0].handle);
+		ion_free(port->buf[0].client, port->buf[0].handle);
+		ion_client_destroy(port->buf[0].client);
+		pr_debug("%s:data[%p]phys[%p][%p]"
+			", client[%p] handle[%p]\n",
+			__func__,
+			(void *)port->buf[0].data,
+			(void *)port->buf[0].phys,
+			(void *)&port->buf[0].phys,
+			(void *)port->buf[0].client,
+			(void *)port->buf[0].handle);
+	}
+
+	while (cnt >= 0) {
+		port->buf[cnt].data = NULL;
+		port->buf[cnt].phys = 0;
+		cnt--;
+	}
+	port->max_buf_cnt = 0;
+	kfree(port->buf);
+	port->buf = NULL;
+	mutex_unlock(&ac->cmd_lock);
+	return 0;
+}
+
+int q6asm_mmap_apr_dereg(void)
+{
+	if (atomic_read(&this_mmap.ref_cnt) <= 0) {
+		pr_err("%s: APR Common Port Already Closed\n", __func__);
+		goto done;
+	}
+	atomic_dec(&this_mmap.ref_cnt);
+	if (atomic_read(&this_mmap.ref_cnt) == 0) {
+		apr_deregister(this_mmap.apr);
+		pr_debug("%s:APR De-Register common port\n", __func__);
+	}
+done:
+	return 0;
+}
+
+
+void q6asm_audio_client_free(struct audio_client *ac)
+{
+	int loopcnt;
+	struct audio_port_data *port;
+	if (!ac || !ac->session)
+		return;
+	pr_debug("%s: Session id %d\n", __func__, ac->session);
+	if (ac->io_mode == SYNC_IO_MODE) {
+		for (loopcnt = 0; loopcnt <= OUT; loopcnt++) {
+			port = &ac->port[loopcnt];
+			if (!port->buf)
+				continue;
+			pr_debug("%s:loopcnt = %d\n", __func__, loopcnt);
+			q6asm_audio_client_buf_free(loopcnt, ac);
+		}
+	}
+
+	apr_deregister(ac->apr);
+	ac->mmap_apr = NULL;
+	q6asm_session_free(ac);
+	q6asm_mmap_apr_dereg();
+
+	pr_debug("%s: APR De-Register\n", __func__);
+
+/*done:*/
+	kfree(ac);
+	return;
+}
+
+int q6asm_set_io_mode(struct audio_client *ac, uint32_t mode)
+{
+	if (ac == NULL) {
+		pr_err("%s APR handle NULL\n", __func__);
+		return -EINVAL;
+	}
+	if ((mode == ASYNC_IO_MODE) || (mode == SYNC_IO_MODE)) {
+		ac->io_mode = mode;
+		pr_debug("%s:Set Mode to %d\n", __func__, ac->io_mode);
+		return 0;
+	} else {
+		pr_err("%s:Not an valid IO Mode:%d\n", __func__, ac->io_mode);
+		return -EINVAL;
+	}
+}
+
+void *q6asm_mmap_apr_reg(void)
+{
+	if (atomic_read(&this_mmap.ref_cnt) == 0) {
+		this_mmap.apr = apr_register("ADSP", "ASM", \
+					(apr_fn)q6asm_mmapcallback,\
+					0x0FFFFFFFF, &this_mmap);
+		if (this_mmap.apr == NULL) {
+			pr_debug("%s Unable to register"
+				"APR ASM common port\n", __func__);
+			goto fail;
+		}
+	}
+	atomic_inc(&this_mmap.ref_cnt);
+	return this_mmap.apr;
+fail:
+	return NULL;
+}
+
+struct audio_client *q6asm_audio_client_alloc(app_cb cb, void *priv)
+{
+	struct audio_client *ac;
+	int n;
+	int lcnt = 0;
+
+	ac = kzalloc(sizeof(struct audio_client), GFP_KERNEL);
+	if (!ac)
+		return NULL;
+	n = q6asm_session_alloc(ac);
+	if (n <= 0)
+		goto fail_session;
+	ac->session = n;
+	ac->cb = cb;
+	ac->priv = priv;
+	ac->io_mode = SYNC_IO_MODE;
+	ac->apr = apr_register("ADSP", "ASM", \
+				(apr_fn)q6asm_callback,\
+				((ac->session) << 8 | 0x0001),\
+				ac);
+
+	if (ac->apr == NULL) {
+		pr_err("%s Registration with APR failed\n", __func__);
+			goto fail;
+	}
+	rtac_set_asm_handle(n, ac->apr);
+
+	pr_debug("%s Registering the common port with APR\n", __func__);
+	ac->mmap_apr = q6asm_mmap_apr_reg();
+	if (ac->mmap_apr == NULL)
+		goto fail;
+
+	init_waitqueue_head(&ac->cmd_wait);
+	INIT_LIST_HEAD(&ac->port[0].mem_map_handle);
+	INIT_LIST_HEAD(&ac->port[1].mem_map_handle);
+	pr_debug("%s: mem_map_handle list init'ed\n", __func__);
+	mutex_init(&ac->cmd_lock);
+	for (lcnt = 0; lcnt <= OUT; lcnt++) {
+		mutex_init(&ac->port[lcnt].lock);
+		spin_lock_init(&ac->port[lcnt].dsp_lock);
+	}
+	atomic_set(&ac->cmd_state, 0);
+
+	pr_debug("%s: session[%d]\n", __func__, ac->session);
+
+	return ac;
+fail:
+	q6asm_audio_client_free(ac);
+	return NULL;
+fail_session:
+	kfree(ac);
+	return NULL;
+}
+
+struct audio_client *q6asm_get_audio_client(int session_id)
+{
+	if ((session_id <= 0) || (session_id > SESSION_MAX)) {
+		pr_err("%s: invalid session: %d\n", __func__, session_id);
+		goto err;
+	}
+
+	if (!session[session_id]) {
+		pr_err("%s: session not active: %d\n", __func__, session_id);
+		goto err;
+	}
+
+	return session[session_id];
+err:
+	return NULL;
+}
+
+int q6asm_audio_client_buf_alloc(unsigned int dir,
+			struct audio_client *ac,
+			unsigned int bufsz,
+			unsigned int bufcnt)
+{
+	int cnt = 0;
+	int rc = 0;
+	struct audio_buffer *buf;
+	int len;
+
+	if (!(ac) || ((dir != IN) && (dir != OUT)))
+		return -EINVAL;
+
+	pr_debug("%s: session[%d]bufsz[%d]bufcnt[%d]\n", __func__, ac->session,
+		bufsz, bufcnt);
+
+	if (ac->session <= 0 || ac->session > 8)
+		goto fail;
+
+	if (ac->io_mode == SYNC_IO_MODE) {
+		if (ac->port[dir].buf) {
+			pr_debug("%s: buffer already allocated\n", __func__);
+			return 0;
+		}
+		mutex_lock(&ac->cmd_lock);
+		buf = kzalloc(((sizeof(struct audio_buffer))*bufcnt),
+				GFP_KERNEL);
+
+		if (!buf) {
+			mutex_unlock(&ac->cmd_lock);
+			goto fail;
+		}
+
+		ac->port[dir].buf = buf;
+
+		while (cnt < bufcnt) {
+			if (bufsz > 0) {
+				if (!buf[cnt].data) {
+					buf[cnt].client = msm_ion_client_create
+						(UINT_MAX, "audio_client");
+					if (IS_ERR_OR_NULL((void *)
+						buf[cnt].client)) {
+						pr_err("%s: ION create client"
+						" for AUDIO failed\n",
+						__func__);
+						goto fail;
+					}
+					buf[cnt].handle = ion_alloc
+						(buf[cnt].client, bufsz, SZ_4K,
+						(0x1 << ION_AUDIO_HEAP_ID));
+					if (IS_ERR_OR_NULL((void *)
+						buf[cnt].handle)) {
+						pr_err("%s: ION memory"
+					" allocation for AUDIO failed\n",
+							__func__);
+						goto fail;
+					}
+
+					rc = ion_phys(buf[cnt].client,
+						buf[cnt].handle,
+						(ion_phys_addr_t *)
+						&buf[cnt].phys,
+						(size_t *)&len);
+					if (rc) {
+						pr_err("%s: ION Get Physical"
+						" for AUDIO failed, rc = %d\n",
+							__func__, rc);
+						goto fail;
+					}
+
+					buf[cnt].data = ion_map_kernel
+					(buf[cnt].client, buf[cnt].handle,
+							 0);
+					if (IS_ERR_OR_NULL((void *)
+						buf[cnt].data)) {
+						pr_err("%s: ION memory"
+				" mapping for AUDIO failed\n", __func__);
+						goto fail;
+					}
+					memset((void *)buf[cnt].data, 0, bufsz);
+					buf[cnt].used = 1;
+					buf[cnt].size = bufsz;
+					buf[cnt].actual_size = bufsz;
+					pr_debug("%s data[%p]phys[%p][%p]\n",
+						__func__,
+					   (void *)buf[cnt].data,
+					   (void *)buf[cnt].phys,
+					   (void *)&buf[cnt].phys);
+					cnt++;
+				}
+			}
+		}
+		ac->port[dir].max_buf_cnt = cnt;
+
+		mutex_unlock(&ac->cmd_lock);
+		rc = q6asm_memory_map_regions(ac, dir, bufsz, cnt);
+		if (rc < 0) {
+			pr_err("%s:CMD Memory_map_regions failed\n", __func__);
+			goto fail;
+		}
+	}
+	return 0;
+fail:
+	q6asm_audio_client_buf_free(dir, ac);
+	return -EINVAL;
+}
+
+int q6asm_audio_client_buf_alloc_contiguous(unsigned int dir,
+			struct audio_client *ac,
+			unsigned int bufsz,
+			unsigned int bufcnt)
+{
+	int cnt = 0;
+	int rc = 0;
+	struct audio_buffer *buf;
+	int len;
+
+	if (!(ac) || ((dir != IN) && (dir != OUT)))
+		return -EINVAL;
+
+	pr_debug("%s: session[%d]bufsz[%d]bufcnt[%d]\n",
+			__func__, ac->session,
+			bufsz, bufcnt);
+
+	if (ac->session <= 0 || ac->session > 8)
+		goto fail;
+
+	if (ac->port[dir].buf) {
+		pr_debug("%s: buffer already allocated\n", __func__);
+		return 0;
+	}
+	mutex_lock(&ac->cmd_lock);
+	buf = kzalloc(((sizeof(struct audio_buffer))*bufcnt),
+			GFP_KERNEL);
+
+	if (!buf) {
+		mutex_unlock(&ac->cmd_lock);
+		goto fail;
+	}
+
+	ac->port[dir].buf = buf;
+
+	buf[0].client = msm_ion_client_create(UINT_MAX, "audio_client");
+	if (IS_ERR_OR_NULL((void *)buf[0].client)) {
+		pr_err("%s: ION create client for AUDIO failed\n", __func__);
+		goto fail;
+	}
+	buf[0].handle = ion_alloc(buf[0].client, bufsz * bufcnt, SZ_4K,
+				  (0x1 << ION_AUDIO_HEAP_ID));
+	if (IS_ERR_OR_NULL((void *) buf[0].handle)) {
+		pr_err("%s: ION memory allocation for AUDIO failed\n",
+			__func__);
+		goto fail;
+	}
+
+	rc = ion_phys(buf[0].client, buf[0].handle,
+		  (ion_phys_addr_t *)&buf[0].phys, (size_t *)&len);
+	if (rc) {
+		pr_err("%s: ION Get Physical for AUDIO failed, rc = %d\n",
+			__func__, rc);
+		goto fail;
+	}
+
+	buf[0].data = ion_map_kernel(buf[0].client, buf[0].handle, 0);
+	if (IS_ERR_OR_NULL((void *) buf[0].data)) {
+		pr_err("%s: ION memory mapping for AUDIO failed\n", __func__);
+		goto fail;
+	}
+	memset((void *)buf[0].data, 0, (bufsz * bufcnt));
+	if (!buf[0].data) {
+		pr_err("%s:invalid vaddr,"
+			" iomap failed\n", __func__);
+		mutex_unlock(&ac->cmd_lock);
+		goto fail;
+	}
+
+	buf[0].used = dir ^ 1;
+	buf[0].size = bufsz;
+	buf[0].actual_size = bufsz;
+	cnt = 1;
+	while (cnt < bufcnt) {
+		if (bufsz > 0) {
+			buf[cnt].data =  buf[0].data + (cnt * bufsz);
+			buf[cnt].phys =  buf[0].phys + (cnt * bufsz);
+			if (!buf[cnt].data) {
+				pr_err("%s Buf alloc failed\n",
+							__func__);
+				mutex_unlock(&ac->cmd_lock);
+				goto fail;
+			}
+			buf[cnt].used = dir ^ 1;
+			buf[cnt].size = bufsz;
+			buf[cnt].actual_size = bufsz;
+			pr_debug("%s data[%p]phys[%p][%p]\n", __func__,
+				   (void *)buf[cnt].data,
+				   (void *)buf[cnt].phys,
+				   (void *)&buf[cnt].phys);
+		}
+		cnt++;
+	}
+	ac->port[dir].max_buf_cnt = cnt;
+	mutex_unlock(&ac->cmd_lock);
+	rc = q6asm_memory_map_regions(ac, dir, bufsz, cnt);
+	if (rc < 0) {
+		pr_err("%s:CMD Memory_map_regions failed\n", __func__);
+		goto fail;
+	}
+	return 0;
+fail:
+	q6asm_audio_client_buf_free_contiguous(dir, ac);
+	return -EINVAL;
+}
+
+static int32_t q6asm_mmapcallback(struct apr_client_data *data, void *priv)
+{
+	uint32_t sid = 0;
+	uint32_t dir = 0;
+	uint32_t *payload = data->payload;
+	unsigned long dsp_flags;
+
+	struct audio_client *ac = NULL;
+	struct audio_port_data *port;
+
+	if (!data) {
+		pr_err("%s: Invalid CB\n", __func__);
+		return 0;
+	}
+	if (data->opcode == RESET_EVENTS) {
+		pr_debug("%s: Reset event is received: %d %d apr[%p]\n",
+				__func__,
+				data->reset_event,
+				data->reset_proc,
+				this_mmap.apr);
+		apr_reset(this_mmap.apr);
+		atomic_set(&this_mmap.ref_cnt, 0);
+		this_mmap.apr = NULL;
+		return 0;
+	}
+	sid = (data->token >> 8) & 0x0F;
+	ac = q6asm_get_audio_client(sid);
+	pr_debug("%s:ptr0[0x%x]ptr1[0x%x]opcode[0x%x]"
+		"token[0x%x]payload_s[%d] src[%d] dest[%d]sid[%d]dir[%d]\n",
+		__func__, payload[0], payload[1], data->opcode, data->token,
+		data->payload_size, data->src_port, data->dest_port, sid, dir);
+	pr_debug("%s:Payload = [0x%x] status[0x%x]\n",
+			__func__, payload[0], payload[1]);
+
+	if (data->opcode == APR_BASIC_RSP_RESULT) {
+		switch (payload[0]) {
+		case ASM_CMD_SHARED_MEM_MAP_REGIONS:
+		case ASM_CMD_SHARED_MEM_UNMAP_REGIONS:
+			if (atomic_read(&ac->cmd_state)) {
+				atomic_set(&ac->cmd_state, 0);
+				wake_up(&ac->cmd_wait);
+			}
+			pr_debug("%s:Payload = [0x%x] status[0x%x]\n",
+					__func__, payload[0], payload[1]);
+			break;
+		default:
+			pr_debug("%s:command[0x%x] not expecting rsp\n",
+						__func__, payload[0]);
+			break;
+		}
+		return 0;
+	}
+
+	dir = (data->token & 0x0F);
+	port = &ac->port[dir];
+
+	switch (data->opcode) {
+	case ASM_CMDRSP_SHARED_MEM_MAP_REGIONS:{
+		pr_debug("%s:PL#0[0x%x]PL#1 [0x%x] dir=%x s_id=%x\n",
+				__func__, payload[0], payload[1], dir, sid);
+		spin_lock_irqsave(&port->dsp_lock, dsp_flags);
+		if (atomic_read(&ac->cmd_state)) {
+			ac->port[dir].tmp_hdl = payload[0];
+			atomic_set(&ac->cmd_state, 0);
+			wake_up(&ac->cmd_wait);
+		}
+		spin_unlock_irqrestore(&port->dsp_lock, dsp_flags);
+		break;
+	}
+	case ASM_CMD_SHARED_MEM_UNMAP_REGIONS:{
+		pr_debug("%s:PL#0[0x%x]PL#1 [0x%x]\n",
+					__func__, payload[0], payload[1]);
+		spin_lock_irqsave(&port->dsp_lock, dsp_flags);
+		if (atomic_read(&ac->cmd_state)) {
+			atomic_set(&ac->cmd_state, 0);
+			wake_up(&ac->cmd_wait);
+		}
+		spin_unlock_irqrestore(&port->dsp_lock, dsp_flags);
+
+		break;
+	}
+	default:
+		pr_debug("%s:command[0x%x]success [0x%x]\n",
+					__func__, payload[0], payload[1]);
+	}
+	if (ac->cb)
+		ac->cb(data->opcode, data->token,
+			data->payload, ac->priv);
+	return 0;
+}
+
+
+static int32_t q6asm_callback(struct apr_client_data *data, void *priv)
+{
+	int i = 0;
+	struct audio_client *ac = (struct audio_client *)priv;
+	uint32_t token;
+	unsigned long dsp_flags;
+	uint32_t *payload;
+
+
+	if ((ac == NULL) || (data == NULL)) {
+		pr_err("ac or priv NULL\n");
+		return -EINVAL;
+	}
+	if (ac->session <= 0 || ac->session > 8) {
+		pr_err("%s:Session ID is invalid, session = %d\n", __func__,
+			ac->session);
+		return -EINVAL;
+	}
+
+	payload = data->payload;
+
+	if (data->opcode == RESET_EVENTS) {
+		pr_debug("q6asm_callback: Reset event is received: %d %d apr[%p]\n",
+				data->reset_event, data->reset_proc, ac->apr);
+			if (ac->cb)
+				ac->cb(data->opcode, data->token,
+					(uint32_t *)data->payload, ac->priv);
+		apr_reset(ac->apr);
+		return 0;
+	}
+
+	pr_debug("%s: session[%d]opcode[0x%x]"
+		"token[0x%x]payload_s[%d] src[%d] dest[%d]\n", __func__,
+		ac->session, data->opcode,
+		data->token, data->payload_size, data->src_port,
+		data->dest_port);
+	if ((data->opcode != ASM_DATA_EVENT_RENDERED_EOS) &&
+			(data->opcode != ASM_DATA_EVENT_EOS))
+		pr_debug("%s:Payload = [0x%x] status[0x%x]\n",
+			__func__, payload[0], payload[1]);
+	if (data->opcode == APR_BASIC_RSP_RESULT) {
+		token = data->token;
+		switch (payload[0]) {
+		case ASM_STREAM_CMD_SET_PP_PARAMS_V2:
+			if (rtac_make_asm_callback(ac->session, payload,
+					data->payload_size))
+				break;
+		case ASM_SESSION_CMD_PAUSE:
+		case ASM_DATA_CMD_EOS:
+		case ASM_STREAM_CMD_CLOSE:
+		case ASM_STREAM_CMD_FLUSH:
+		case ASM_SESSION_CMD_RUN_V2:
+		case ASM_SESSION_CMD_REGISTER_FORX_OVERFLOW_EVENTS:
+		case ASM_STREAM_CMD_FLUSH_READBUFS:
+		pr_debug("%s:Payload = [0x%x]\n", __func__, payload[0]);
+		if (token != ac->session) {
+			pr_err("%s:Invalid session[%d] rxed expected[%d]",
+					__func__, token, ac->session);
+			return -EINVAL;
+		}
+		case ASM_STREAM_CMD_OPEN_READ_V2:
+		case ASM_STREAM_CMD_OPEN_WRITE_V2:
+		case ASM_STREAM_CMD_OPEN_READWRITE_V2:
+		case ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2:
+		case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
+		pr_debug("%s:Payload = [0x%x]stat[0x%x]\n",
+				__func__, payload[0], payload[1]);
+			if (atomic_read(&ac->cmd_state)) {
+				atomic_set(&ac->cmd_state, 0);
+				wake_up(&ac->cmd_wait);
+			}
+			if (ac->cb)
+				ac->cb(data->opcode, data->token,
+					(uint32_t *)data->payload, ac->priv);
+			break;
+		default:
+			pr_debug("%s:command[0x%x] not expecting rsp\n",
+							__func__, payload[0]);
+			break;
+		}
+		return 0;
+	}
+
+	switch (data->opcode) {
+	case ASM_DATA_EVENT_WRITE_DONE_V2:{
+		struct audio_port_data *port = &ac->port[IN];
+		pr_debug("%s: Rxed opcode[0x%x] status[0x%x] token[%d]",
+				__func__, payload[0], payload[1],
+				data->token);
+		if (ac->io_mode == SYNC_IO_MODE) {
+			if (port->buf == NULL) {
+				pr_err("%s: Unexpected Write Done\n",
+								__func__);
+				return -EINVAL;
+			}
+			spin_lock_irqsave(&port->dsp_lock, dsp_flags);
+			if (port->buf[data->token].phys !=
+				payload[0]) {
+				pr_err("Buf expected[%p]rxed[%p]\n",\
+				   (void *)port->buf[data->token].phys,\
+				   (void *)payload[0]);
+				spin_unlock_irqrestore(&port->dsp_lock,
+								dsp_flags);
+				return -EINVAL;
+			}
+			token = data->token;
+			port->buf[token].used = 1;
+			spin_unlock_irqrestore(&port->dsp_lock, dsp_flags);
+
+			config_debug_fs_write_cb();
+
+			for (i = 0; i < port->max_buf_cnt; i++)
+				pr_debug("%d ", port->buf[i].used);
+
+		}
+		break;
+	}
+	case ASM_STREAM_CMDRSP_GET_PP_PARAMS_V2:
+		rtac_make_asm_callback(ac->session, payload,
+			data->payload_size);
+		break;
+	case ASM_DATA_EVENT_READ_DONE_V2:{
+
+		struct audio_port_data *port = &ac->port[OUT];
+
+		config_debug_fs_read_cb();
+
+		pr_debug("%s:R-D: status=%d buff_add=%x act_size=%d offset=%d\n",
+				__func__, payload[READDONE_IDX_STATUS],
+				payload[READDONE_IDX_BUFADD_LSW],
+				payload[READDONE_IDX_SIZE],
+				payload[READDONE_IDX_OFFSET]);
+
+		pr_debug("%s:R-D:msw_ts=%d lsw_ts=%d memmap_hdl=%x flags=%d id=%d num=%d\n",
+				__func__, payload[READDONE_IDX_MSW_TS],
+				payload[READDONE_IDX_LSW_TS],
+				payload[READDONE_IDX_MEMMAP_HDL],
+				payload[READDONE_IDX_FLAGS],
+				payload[READDONE_IDX_SEQ_ID],
+				payload[READDONE_IDX_NUMFRAMES]);
+
+		if (ac->io_mode == SYNC_IO_MODE) {
+			if (port->buf == NULL) {
+				pr_err("%s: Unexpected Write Done\n", __func__);
+				return -EINVAL;
+			}
+			spin_lock_irqsave(&port->dsp_lock, dsp_flags);
+			token = data->token;
+			port->buf[token].used = 0;
+			if (port->buf[token].phys !=
+				payload[READDONE_IDX_BUFADD_LSW]) {
+				pr_err("Buf expected[%p]rxed[%p]\n",\
+				   (void *)port->buf[token].phys,\
+				   (void *)payload[READDONE_IDX_BUFADD_LSW]);
+				spin_unlock_irqrestore(&port->dsp_lock,
+							dsp_flags);
+				break;
+			}
+			port->buf[token].actual_size =
+				payload[READDONE_IDX_SIZE];
+			spin_unlock_irqrestore(&port->dsp_lock, dsp_flags);
+		}
+		break;
+	}
+	case ASM_DATA_EVENT_EOS:
+	case ASM_DATA_EVENT_RENDERED_EOS:
+		pr_debug("%s:EOS ACK received: rxed opcode[0x%x]\n",
+				  __func__, data->opcode);
+		break;
+	case ASM_SESSION_EVENTX_OVERFLOW:
+		pr_err("ASM_SESSION_EVENTX_OVERFLOW\n");
+		break;
+	case ASM_SESSION_CMDRSP_GET_SESSIONTIME_V3:
+		pr_debug("%s: ASM_SESSION_CMDRSP_GET_SESSIONTIME_V3, "
+				"payload[0] = %d, payload[1] = %d, "
+				"payload[2] = %d\n", __func__,
+				 payload[0], payload[1], payload[2]);
+		ac->time_stamp = (uint64_t)(((uint64_t)payload[1] << 32) |
+				payload[2]);
+		if (atomic_read(&ac->cmd_state)) {
+			atomic_set(&ac->cmd_state, 0);
+			wake_up(&ac->cmd_wait);
+		}
+		break;
+	case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY:
+	case ASM_DATA_EVENT_ENC_SR_CM_CHANGE_NOTIFY:
+		pr_debug("%s: ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY, "
+				"payload[0] = %d, payload[1] = %d, "
+				"payload[2] = %d, payload[3] = %d\n", __func__,
+				payload[0], payload[1], payload[2],
+				payload[3]);
+		break;
+	}
+	if (ac->cb)
+		ac->cb(data->opcode, data->token,
+			data->payload, ac->priv);
+
+	return 0;
+}
+
+void *q6asm_is_cpu_buf_avail(int dir, struct audio_client *ac, uint32_t *size,
+				uint32_t *index)
+{
+	void *data;
+	unsigned char idx;
+	struct audio_port_data *port;
+
+	if (!ac || ((dir != IN) && (dir != OUT)))
+		return NULL;
+
+	if (ac->io_mode == SYNC_IO_MODE) {
+		port = &ac->port[dir];
+
+		mutex_lock(&port->lock);
+		idx = port->cpu_buf;
+		if (port->buf == NULL) {
+			pr_debug("%s:Buffer pointer null\n", __func__);
+			mutex_unlock(&port->lock);
+			return NULL;
+		}
+		/*  dir 0: used = 0 means buf in use
+			dir 1: used = 1 means buf in use */
+		if (port->buf[idx].used == dir) {
+			/* To make it more robust, we could loop and get the
+			next avail buf, its risky though */
+			pr_debug("%s:Next buf idx[0x%x] not available,"
+				"dir[%d]\n", __func__, idx, dir);
+			mutex_unlock(&port->lock);
+			return NULL;
+		}
+		*size = port->buf[idx].actual_size;
+		*index = port->cpu_buf;
+		data = port->buf[idx].data;
+		pr_debug("%s:session[%d]index[%d] data[%p]size[%d]\n",
+						__func__,
+						ac->session,
+						port->cpu_buf,
+						data, *size);
+		/* By default increase the cpu_buf cnt
+		user accesses this function,increase cpu
+		buf(to avoid another api)*/
+		port->buf[idx].used = dir;
+		port->cpu_buf = ((port->cpu_buf + 1) & (port->max_buf_cnt - 1));
+		mutex_unlock(&port->lock);
+		return data;
+	}
+	return NULL;
+}
+
+void *q6asm_is_cpu_buf_avail_nolock(int dir, struct audio_client *ac,
+					uint32_t *size, uint32_t *index)
+{
+	void *data;
+	unsigned char idx;
+	struct audio_port_data *port;
+
+	if (!ac || ((dir != IN) && (dir != OUT)))
+		return NULL;
+
+	port = &ac->port[dir];
+
+	idx = port->cpu_buf;
+	if (port->buf == NULL) {
+		pr_debug("%s:Buffer pointer null\n", __func__);
+		return NULL;
+	}
+	/*
+	 * dir 0: used = 0 means buf in use
+	 * dir 1: used = 1 means buf in use
+	 */
+	if (port->buf[idx].used == dir) {
+		/*
+		 * To make it more robust, we could loop and get the
+		 * next avail buf, its risky though
+		 */
+		pr_debug("%s:Next buf idx[0x%x] not available,"
+			"dir[%d]\n", __func__, idx, dir);
+		return NULL;
+	}
+	*size = port->buf[idx].actual_size;
+	*index = port->cpu_buf;
+	data = port->buf[idx].data;
+	pr_debug("%s:session[%d]index[%d] data[%p]size[%d]\n",
+		__func__, ac->session, port->cpu_buf,
+		data, *size);
+	/*
+	 * By default increase the cpu_buf cnt
+	 * user accesses this function,increase cpu
+	 * buf(to avoid another api)
+	 */
+	port->buf[idx].used = dir;
+	port->cpu_buf = ((port->cpu_buf + 1) & (port->max_buf_cnt - 1));
+	return data;
+}
+
+int q6asm_is_dsp_buf_avail(int dir, struct audio_client *ac)
+{
+	int ret = -1;
+	struct audio_port_data *port;
+	uint32_t idx;
+
+	if (!ac || (dir != OUT))
+		return ret;
+
+	if (ac->io_mode == SYNC_IO_MODE) {
+		port = &ac->port[dir];
+
+		mutex_lock(&port->lock);
+		idx = port->dsp_buf;
+
+		if (port->buf[idx].used == (dir ^ 1)) {
+			/* To make it more robust, we could loop and get the
+			next avail buf, its risky though */
+			pr_err("Next buf idx[0x%x] not available, dir[%d]\n",
+								idx, dir);
+			mutex_unlock(&port->lock);
+			return ret;
+		}
+		pr_debug("%s: session[%d]dsp_buf=%d cpu_buf=%d\n", __func__,
+			ac->session, port->dsp_buf, port->cpu_buf);
+		ret = ((port->dsp_buf != port->cpu_buf) ? 0 : -1);
+		mutex_unlock(&port->lock);
+	}
+	return ret;
+}
+
+static void q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr,
+			uint32_t pkt_size, uint32_t cmd_flg)
+{
+	pr_debug("%s:pkt_size=%d cmd_flg=%d session=%d\n", __func__, pkt_size,
+		cmd_flg, ac->session);
+	mutex_lock(&ac->cmd_lock);
+	hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, \
+				APR_HDR_LEN(sizeof(struct apr_hdr)),\
+				APR_PKT_VER);
+	hdr->src_svc = ((struct apr_svc *)ac->apr)->id;
+	hdr->src_domain = APR_DOMAIN_APPS;
+	hdr->dest_svc = APR_SVC_ASM;
+	hdr->dest_domain = APR_DOMAIN_ADSP;
+	hdr->src_port = ((ac->session << 8) & 0xFF00) | 0x01;
+	hdr->dest_port = ((ac->session << 8) & 0xFF00) | 0x01;
+	if (cmd_flg) {
+		hdr->token = ac->session;
+		atomic_set(&ac->cmd_state, 1);
+	}
+	hdr->pkt_size  = pkt_size;
+	mutex_unlock(&ac->cmd_lock);
+	return;
+}
+
+static void q6asm_add_hdr_async(struct audio_client *ac, struct apr_hdr *hdr,
+			uint32_t pkt_size, uint32_t cmd_flg)
+{
+	pr_debug("pkt_size = %d, cmd_flg = %d, session = %d\n",
+			pkt_size, cmd_flg, ac->session);
+	hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, \
+				APR_HDR_LEN(sizeof(struct apr_hdr)),\
+				APR_PKT_VER);
+	hdr->src_svc = ((struct apr_svc *)ac->apr)->id;
+	hdr->src_domain = APR_DOMAIN_APPS;
+	hdr->dest_svc = APR_SVC_ASM;
+	hdr->dest_domain = APR_DOMAIN_ADSP;
+	hdr->src_port = ((ac->session << 8) & 0xFF00) | 0x01;
+	hdr->dest_port = ((ac->session << 8) & 0xFF00) | 0x01;
+	if (cmd_flg) {
+		hdr->token = ac->session;
+		atomic_set(&ac->cmd_state, 1);
+	}
+	hdr->pkt_size  = pkt_size;
+	return;
+}
+
+static void q6asm_add_mmaphdr(struct audio_client *ac, struct apr_hdr *hdr,
+			u32 pkt_size, u32 cmd_flg, u32 token)
+{
+	pr_debug("%s:pkt size=%d cmd_flg=%d\n", __func__, pkt_size, cmd_flg);
+	hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, \
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	hdr->src_port = 0;
+	hdr->dest_port = 0;
+	if (cmd_flg) {
+		hdr->token = token;
+		atomic_set(&ac->cmd_state, 1);
+	}
+	hdr->pkt_size  = pkt_size;
+	return;
+}
+int q6asm_open_read(struct audio_client *ac,
+		uint32_t format)
+{
+	int rc = 0x00;
+	struct asm_stream_cmd_open_read_v2 open;
+
+	uint16_t bits_per_sample = 16;
+
+
+	config_debug_fs_reset_index();
+
+	if ((ac == NULL) || (ac->apr == NULL)) {
+		pr_err("%s: APR handle NULL\n", __func__);
+		return -EINVAL;
+	}
+	pr_debug("%s:session[%d]", __func__, ac->session);
+
+	q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
+	open.hdr.opcode = ASM_STREAM_CMD_OPEN_READ_V2;
+	/* Stream prio : High, provide meta info with encoded frames */
+	open.src_endpointype = ASM_END_POINT_DEVICE_MATRIX;
+
+	open.preprocopo_id = get_asm_topology();
+	if (open.preprocopo_id == 0)
+		open.preprocopo_id = ASM_STREAM_POSTPROC_TOPO_ID_DEFAULT;
+	open.bits_per_sample = bits_per_sample;
+
+	switch (format) {
+	case FORMAT_LINEAR_PCM:
+		open.mode_flags = 0x00;
+		open.enc_cfg_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
+		break;
+	case FORMAT_MPEG4_AAC:
+		open.mode_flags = BUFFER_META_ENABLE;
+		open.enc_cfg_id = ASM_MEDIA_FMT_AAC_V2;
+		break;
+	case FORMAT_V13K:
+		open.mode_flags = BUFFER_META_ENABLE;
+		open.enc_cfg_id = ASM_MEDIA_FMT_V13K_FS;
+		break;
+	case FORMAT_EVRC:
+		open.mode_flags = BUFFER_META_ENABLE;
+		open.enc_cfg_id = ASM_MEDIA_FMT_EVRC_FS;
+		break;
+	case FORMAT_AMRNB:
+		open.mode_flags = BUFFER_META_ENABLE ;
+		open.enc_cfg_id = ASM_MEDIA_FMT_AMRNB_FS;
+		break;
+	case FORMAT_AMRWB:
+		open.mode_flags = BUFFER_META_ENABLE ;
+		open.enc_cfg_id = ASM_MEDIA_FMT_AMRWB_FS;
+		break;
+	default:
+		pr_err("Invalid format[%d]\n", format);
+		goto fail_cmd;
+	}
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
+	if (rc < 0) {
+		pr_err("open failed op[0x%x]rc[%d]\n", \
+						open.hdr.opcode, rc);
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("%s: timeout. waited for open read rc[%d]\n", __func__,
+			rc);
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+int q6asm_open_write(struct audio_client *ac, uint32_t format)
+{
+	int rc = 0x00;
+	struct asm_stream_cmd_open_write_v2 open;
+
+	if ((ac == NULL) || (ac->apr == NULL)) {
+		pr_err("%s: APR handle NULL\n", __func__);
+		return -EINVAL;
+	}
+	pr_debug("%s: session[%d] wr_format[0x%x]", __func__, ac->session,
+		format);
+
+	q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
+
+	open.hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE_V2;
+	open.mode_flags = 0x00;
+	/* source endpoint : matrix */
+	open.sink_endpointype = ASM_END_POINT_DEVICE_MATRIX;
+	open.bits_per_sample = 16;
+
+	open.postprocopo_id = get_asm_topology();
+	if (open.postprocopo_id == 0)
+		open.postprocopo_id = ASM_STREAM_POSTPROC_TOPO_ID_DEFAULT;
+
+	switch (format) {
+	case FORMAT_LINEAR_PCM:
+		open.dec_fmt_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
+		break;
+	case FORMAT_MPEG4_AAC:
+		open.dec_fmt_id = ASM_MEDIA_FMT_AAC_V2;
+		break;
+	case FORMAT_MPEG4_MULTI_AAC:
+		open.dec_fmt_id = ASM_MEDIA_FMT_DOLBY_AAC;
+		break;
+	case FORMAT_WMA_V9:
+		open.dec_fmt_id = ASM_MEDIA_FMT_WMA_V9_V2;
+		break;
+	case FORMAT_WMA_V10PRO:
+		open.dec_fmt_id = ASM_MEDIA_FMT_WMA_V10PRO_V2;
+		break;
+	case FORMAT_MP3:
+		open.dec_fmt_id = ASM_MEDIA_FMT_MP3;
+		break;
+	default:
+		pr_err("%s: Invalid format[%d]\n", __func__, format);
+		goto fail_cmd;
+	}
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
+	if (rc < 0) {
+		pr_err("%s: open failed op[0x%x]rc[%d]\n", \
+					__func__, open.hdr.opcode, rc);
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("%s: timeout. waited for open write rc[%d]\n", __func__,
+			rc);
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
+int q6asm_open_read_write(struct audio_client *ac,
+			uint32_t rd_format,
+			uint32_t wr_format)
+{
+	int rc = 0x00;
+	struct asm_stream_cmd_open_readwrite_v2 open;
+
+	if ((ac == NULL) || (ac->apr == NULL)) {
+		pr_err("APR handle NULL\n");
+		return -EINVAL;
+	}
+	pr_debug("%s: session[%d]", __func__, ac->session);
+	pr_debug("wr_format[0x%x]rd_format[0x%x]",
+				wr_format, rd_format);
+
+	q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
+	open.hdr.opcode = ASM_STREAM_CMD_OPEN_READWRITE_V2;
+
+	open.mode_flags = BUFFER_META_ENABLE;
+	open.bits_per_sample = 16;
+	/* source endpoint : matrix */
+	open.postprocopo_id = get_asm_topology();
+	if (open.postprocopo_id == 0)
+		open.postprocopo_id = ASM_STREAM_POSTPROC_TOPO_ID_DEFAULT;
+
+	switch (wr_format) {
+	case FORMAT_LINEAR_PCM:
+		open.dec_fmt_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
+		break;
+	case FORMAT_MPEG4_AAC:
+		open.dec_fmt_id = ASM_MEDIA_FMT_AAC_V2;
+		break;
+	case FORMAT_MPEG4_MULTI_AAC:
+		open.dec_fmt_id = ASM_MEDIA_FMT_DOLBY_AAC;
+		break;
+	case FORMAT_WMA_V9:
+		open.dec_fmt_id = ASM_MEDIA_FMT_WMA_V9_V2;
+		break;
+	case FORMAT_WMA_V10PRO:
+		open.dec_fmt_id = ASM_MEDIA_FMT_WMA_V10PRO_V2;
+		break;
+	case FORMAT_AMRNB:
+		open.dec_fmt_id = ASM_MEDIA_FMT_AMRNB_FS;
+		break;
+	case FORMAT_AMRWB:
+		open.dec_fmt_id = ASM_MEDIA_FMT_AMRWB_FS;
+		break;
+	case FORMAT_V13K:
+		open.dec_fmt_id = ASM_MEDIA_FMT_V13K_FS;
+		break;
+	case FORMAT_EVRC:
+		open.dec_fmt_id = ASM_MEDIA_FMT_EVRC_FS;
+		break;
+	case FORMAT_EVRCB:
+		open.dec_fmt_id = ASM_MEDIA_FMT_EVRCB_FS;
+		break;
+	case FORMAT_EVRCWB:
+		open.dec_fmt_id = ASM_MEDIA_FMT_EVRCWB_FS;
+		break;
+	case FORMAT_MP3:
+		open.dec_fmt_id = ASM_MEDIA_FMT_MP3;
+		break;
+	default:
+		pr_err("Invalid format[%d]\n", wr_format);
+		goto fail_cmd;
+	}
+
+	switch (rd_format) {
+	case FORMAT_LINEAR_PCM:
+		open.enc_cfg_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
+		break;
+	case FORMAT_MPEG4_AAC:
+		open.enc_cfg_id = ASM_MEDIA_FMT_AAC_V2;
+		break;
+	case FORMAT_V13K:
+		open.enc_cfg_id = ASM_MEDIA_FMT_V13K_FS;
+		break;
+	case FORMAT_EVRC:
+		open.enc_cfg_id = ASM_MEDIA_FMT_EVRC_FS;
+		break;
+	case FORMAT_AMRNB:
+		open.enc_cfg_id = ASM_MEDIA_FMT_AMRNB_FS;
+		break;
+	case FORMAT_AMRWB:
+		open.enc_cfg_id = ASM_MEDIA_FMT_AMRWB_FS;
+		break;
+	default:
+		pr_err("Invalid format[%d]\n", rd_format);
+		goto fail_cmd;
+	}
+	pr_debug("%s:rdformat[0x%x]wrformat[0x%x]\n", __func__,
+			open.enc_cfg_id, open.dec_fmt_id);
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
+	if (rc < 0) {
+		pr_err("open failed op[0x%x]rc[%d]\n", \
+						open.hdr.opcode, rc);
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("timeout. waited for open read-write rc[%d]\n", rc);
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
+int q6asm_run(struct audio_client *ac, uint32_t flags,
+		uint32_t msw_ts, uint32_t lsw_ts)
+{
+	struct asm_session_cmd_run_v2 run;
+	int rc;
+	if (!ac || ac->apr == NULL) {
+		pr_err("APR handle NULL\n");
+		return -EINVAL;
+	}
+	pr_debug("%s session[%d]", __func__, ac->session);
+	q6asm_add_hdr(ac, &run.hdr, sizeof(run), TRUE);
+
+	run.hdr.opcode = ASM_SESSION_CMD_RUN_V2;
+	run.flags    = flags;
+	run.time_lsw = lsw_ts;
+	run.time_msw = msw_ts;
+
+	config_debug_fs_run();
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &run);
+	if (rc < 0) {
+		pr_err("Commmand run failed[%d]", rc);
+		goto fail_cmd;
+	}
+
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("timeout. waited for run success rc[%d]", rc);
+		goto fail_cmd;
+	}
+
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
+int q6asm_run_nowait(struct audio_client *ac, uint32_t flags,
+		uint32_t msw_ts, uint32_t lsw_ts)
+{
+	struct asm_session_cmd_run_v2 run;
+	int rc;
+	if (!ac || ac->apr == NULL) {
+		pr_err("%s:APR handle NULL\n", __func__);
+		return -EINVAL;
+	}
+	pr_debug("session[%d]", ac->session);
+	q6asm_add_hdr_async(ac, &run.hdr, sizeof(run), TRUE);
+
+	run.hdr.opcode = ASM_SESSION_CMD_RUN_V2;
+	run.flags    = flags;
+	run.time_lsw = lsw_ts;
+	run.time_msw = msw_ts;
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &run);
+	if (rc < 0) {
+		pr_err("%s:Commmand run failed[%d]", __func__, rc);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+
+int q6asm_enc_cfg_blk_aac(struct audio_client *ac,
+			 uint32_t frames_per_buf,
+			uint32_t sample_rate, uint32_t channels,
+			uint32_t bit_rate, uint32_t mode, uint32_t format)
+{
+	struct asm_aac_enc_cfg_v2 enc_cfg;
+	int rc = 0;
+
+	pr_debug("%s:session[%d]frames[%d]SR[%d]ch[%d]bitrate[%d]mode[%d]"
+		"format[%d]", __func__, ac->session, frames_per_buf,
+		sample_rate, channels, bit_rate, mode, format);
+
+	q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+
+	enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+	enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
+	enc_cfg.encdec.param_size = sizeof(struct asm_aac_enc_cfg_v2) -
+				sizeof(struct asm_stream_cmd_set_encdec_param);
+	enc_cfg.encblk.frames_per_buf = frames_per_buf;
+	enc_cfg.encblk.enc_cfg_blk_size  = enc_cfg.encdec.param_size -
+				sizeof(struct asm_enc_cfg_blk_param_v2);
+	enc_cfg.bit_rate = bit_rate;
+	enc_cfg.enc_mode = mode;
+	enc_cfg.aac_fmt_flag = format;
+	enc_cfg.channel_cfg = channels;
+	enc_cfg.sample_rate = sample_rate;
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
+	if (rc < 0) {
+		pr_err("Comamnd %d failed\n", ASM_STREAM_CMD_SET_ENCDEC_PARAM);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("timeout. waited for FORMAT_UPDATE\n");
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
+int q6asm_set_encdec_chan_map(struct audio_client *ac,
+			uint32_t num_channels)
+{
+	/* Todo: */
+	return 0;
+}
+
+int q6asm_enc_cfg_blk_pcm(struct audio_client *ac,
+			uint32_t rate, uint32_t channels)
+{
+	struct asm_multi_channel_pcm_enc_cfg_v2  enc_cfg;
+	u8 *channel_mapping;
+	u32 frames_per_buf = 0;
+
+	int rc = 0;
+
+	pr_debug("%s: Session %d, rate = %d, channels = %d\n", __func__,
+			 ac->session, rate, channels);
+
+	q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+	enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+	enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
+	enc_cfg.encdec.param_size = sizeof(enc_cfg) - sizeof(enc_cfg.hdr) -
+				sizeof(enc_cfg.encdec);
+	enc_cfg.encblk.frames_per_buf = frames_per_buf;
+	enc_cfg.encblk.enc_cfg_blk_size  = enc_cfg.encdec.param_size -
+					sizeof(struct asm_enc_cfg_blk_param_v2);
+
+	enc_cfg.num_channels = channels;
+	enc_cfg.bits_per_sample = 16;
+	enc_cfg.sample_rate = rate;
+	enc_cfg.is_signed = 1;
+	channel_mapping = enc_cfg.channel_mapping;  /* ??? PHANI */
+
+	memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
+
+	if (channels == 1)  {
+		channel_mapping[0] = PCM_CHANNEL_FL;
+	} else if (channels == 2) {
+		channel_mapping[0] = PCM_CHANNEL_FL;
+		channel_mapping[1] = PCM_CHANNEL_FR;
+	} else if (channels == 6) {
+		channel_mapping[0] = PCM_CHANNEL_FC;
+		channel_mapping[1] = PCM_CHANNEL_FL;
+		channel_mapping[2] = PCM_CHANNEL_FR;
+		channel_mapping[3] = PCM_CHANNEL_LB;
+		channel_mapping[4] = PCM_CHANNEL_RB;
+		channel_mapping[5] = PCM_CHANNEL_LFE;
+	} else {
+		pr_err("%s: ERROR.unsupported num_ch = %u\n", __func__,
+				channels);
+		return -EINVAL;
+	}
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
+	if (rc < 0) {
+		pr_err("Comamnd open failed\n");
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("timeout opcode[0x%x] ", enc_cfg.hdr.opcode);
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
+int q6asm_enable_sbrps(struct audio_client *ac,
+			uint32_t sbr_ps_enable)
+{
+	struct asm_aac_sbr_ps_flag_param  sbrps;
+	u32 frames_per_buf = 0;
+
+	int rc = 0;
+
+	pr_debug("%s: Session %d\n", __func__, ac->session);
+
+	q6asm_add_hdr(ac, &sbrps.hdr, sizeof(sbrps), TRUE);
+
+	sbrps.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+	sbrps.encdec.param_id = ASM_PARAM_ID_AAC_SBR_PS_FLAG;
+	sbrps.encdec.param_size = sizeof(struct asm_aac_sbr_ps_flag_param) -
+				sizeof(struct asm_stream_cmd_set_encdec_param);
+	sbrps.encblk.frames_per_buf = frames_per_buf;
+	sbrps.encblk.enc_cfg_blk_size  = sbrps.encdec.param_size -
+				sizeof(struct asm_enc_cfg_blk_param_v2);
+
+	sbrps.sbr_ps_flag = sbr_ps_enable;
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &sbrps);
+	if (rc < 0) {
+		pr_err("Command opcode[0x%x]paramid[0x%x] failed\n",
+				ASM_STREAM_CMD_SET_ENCDEC_PARAM,
+				ASM_PARAM_ID_AAC_SBR_PS_FLAG);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("timeout opcode[0x%x] ", sbrps.hdr.opcode);
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
+int q6asm_cfg_dual_mono_aac(struct audio_client *ac,
+			uint16_t sce_left, uint16_t sce_right)
+{
+	struct asm_aac_dual_mono_mapping_param dual_mono;
+	u32 frames_per_buf = 0;
+
+	int rc = 0;
+
+	pr_debug("%s: Session %d, sce_left = %d, sce_right = %d\n",
+			 __func__, ac->session, sce_left, sce_right);
+
+	q6asm_add_hdr(ac, &dual_mono.hdr, sizeof(dual_mono), TRUE);
+
+	dual_mono.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+	dual_mono.encdec.param_id = ASM_PARAM_ID_AAC_DUAL_MONO_MAPPING;
+	dual_mono.encdec.param_size = sizeof(struct asm_aac_enc_cfg_v2) -
+				sizeof(struct asm_stream_cmd_set_encdec_param);
+	dual_mono.encblk.frames_per_buf = frames_per_buf;
+	dual_mono.encblk.enc_cfg_blk_size  = dual_mono.encdec.param_size -
+				sizeof(struct asm_enc_cfg_blk_param_v2);
+	dual_mono.left_channel_sce = sce_left;
+	dual_mono.right_channel_sce = sce_right;
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &dual_mono);
+	if (rc < 0) {
+		pr_err("%s:Command opcode[0x%x]paramid[0x%x] failed\n",
+				__func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM,
+				ASM_PARAM_ID_AAC_DUAL_MONO_MAPPING);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("%s:timeout opcode[0x%x]\n", __func__,
+						dual_mono.hdr.opcode);
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
+int q6asm_enc_cfg_blk_qcelp(struct audio_client *ac, uint32_t frames_per_buf,
+		uint16_t min_rate, uint16_t max_rate,
+		uint16_t reduced_rate_level, uint16_t rate_modulation_cmd)
+{
+	struct asm_v13k_enc_cfg enc_cfg;
+	int rc = 0;
+
+	pr_debug("%s:session[%d]frames[%d]min_rate[0x%4x]max_rate[0x%4x]"
+		"reduced_rate_level[0x%4x]rate_modulation_cmd[0x%4x]", __func__,
+		ac->session, frames_per_buf, min_rate, max_rate,
+		reduced_rate_level, rate_modulation_cmd);
+
+	q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+	enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+	enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
+	enc_cfg.encdec.param_size = sizeof(struct asm_v13k_enc_cfg) -
+				sizeof(struct asm_stream_cmd_set_encdec_param);
+	enc_cfg.encblk.frames_per_buf = frames_per_buf;
+	enc_cfg.encblk.enc_cfg_blk_size  = enc_cfg.encdec.param_size -
+				sizeof(struct asm_enc_cfg_blk_param_v2);
+
+	enc_cfg.min_rate = min_rate;
+	enc_cfg.max_rate = max_rate;
+	enc_cfg.reduced_rate_cmd = reduced_rate_level;
+	enc_cfg.rate_mod_cmd = rate_modulation_cmd;
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
+	if (rc < 0) {
+		pr_err("Comamnd %d failed\n", ASM_STREAM_CMD_SET_ENCDEC_PARAM);
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("timeout. waited for setencdec v13k resp\n");
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
+int q6asm_enc_cfg_blk_evrc(struct audio_client *ac, uint32_t frames_per_buf,
+		uint16_t min_rate, uint16_t max_rate,
+		uint16_t rate_modulation_cmd)
+{
+	struct asm_evrc_enc_cfg enc_cfg;
+	int rc = 0;
+
+	pr_debug("%s:session[%d]frames[%d]min_rate[0x%4x]max_rate[0x%4x]"
+		"rate_modulation_cmd[0x%4x]", __func__, ac->session,
+		frames_per_buf,	min_rate, max_rate, rate_modulation_cmd);
+
+	q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+	enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+	enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
+	enc_cfg.encdec.param_size = sizeof(struct asm_evrc_enc_cfg) -
+				sizeof(struct asm_stream_cmd_set_encdec_param);
+	enc_cfg.encblk.frames_per_buf = frames_per_buf;
+	enc_cfg.encblk.enc_cfg_blk_size  = enc_cfg.encdec.param_size -
+				sizeof(struct asm_enc_cfg_blk_param_v2);
+
+	enc_cfg.min_rate = min_rate;
+	enc_cfg.max_rate = max_rate;
+	enc_cfg.rate_mod_cmd = rate_modulation_cmd;
+	enc_cfg.reserved = 0;
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
+	if (rc < 0) {
+		pr_err("Comamnd %d failed\n", ASM_STREAM_CMD_SET_ENCDEC_PARAM);
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("timeout. waited for encdec evrc\n");
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
+int q6asm_enc_cfg_blk_amrnb(struct audio_client *ac, uint32_t frames_per_buf,
+			uint16_t band_mode, uint16_t dtx_enable)
+{
+	struct asm_amrnb_enc_cfg enc_cfg;
+	int rc = 0;
+
+	pr_debug("%s:session[%d]frames[%d]band_mode[0x%4x]dtx_enable[0x%4x]",
+		__func__, ac->session, frames_per_buf, band_mode, dtx_enable);
+
+	q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+	enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+	enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
+	enc_cfg.encdec.param_size = sizeof(struct asm_amrnb_enc_cfg) -
+				sizeof(struct asm_stream_cmd_set_encdec_param);
+	enc_cfg.encblk.frames_per_buf = frames_per_buf;
+	enc_cfg.encblk.enc_cfg_blk_size  = enc_cfg.encdec.param_size -
+				sizeof(struct asm_enc_cfg_blk_param_v2);
+
+	enc_cfg.enc_mode = band_mode;
+	enc_cfg.dtx_mode = dtx_enable;
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
+	if (rc < 0) {
+		pr_err("Comamnd %d failed\n", ASM_STREAM_CMD_SET_ENCDEC_PARAM);
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("timeout. waited for set encdec amrnb\n");
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
+int q6asm_enc_cfg_blk_amrwb(struct audio_client *ac, uint32_t frames_per_buf,
+			uint16_t band_mode, uint16_t dtx_enable)
+{
+	struct asm_amrwb_enc_cfg enc_cfg;
+	int rc = 0;
+
+	pr_debug("%s:session[%d]frames[%d]band_mode[0x%4x]dtx_enable[0x%4x]",
+		__func__, ac->session, frames_per_buf, band_mode, dtx_enable);
+
+	q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+	enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+	enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
+	enc_cfg.encdec.param_size = sizeof(struct asm_amrwb_enc_cfg) -
+				sizeof(struct asm_stream_cmd_set_encdec_param);
+	enc_cfg.encblk.frames_per_buf = frames_per_buf;
+	enc_cfg.encblk.enc_cfg_blk_size  = enc_cfg.encdec.param_size -
+				sizeof(struct asm_enc_cfg_blk_param_v2);
+
+	enc_cfg.enc_mode = band_mode;
+	enc_cfg.dtx_mode = dtx_enable;
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
+	if (rc < 0) {
+		pr_err("Comamnd %d failed\n", ASM_STREAM_CMD_SET_ENCDEC_PARAM);
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("timeout. waited for FORMAT_UPDATE\n");
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
+
+int q6asm_media_format_block_aac(struct audio_client *ac,
+			struct asm_aac_cfg *cfg)
+{
+	return q6asm_media_format_block_multi_aac(ac, cfg);
+}
+
+int q6asm_media_format_block_pcm(struct audio_client *ac,
+				uint32_t rate, uint32_t channels)
+{
+	struct asm_multi_channel_pcm_fmt_blk_v2 fmt;
+	u8 *channel_mapping;
+	int rc = 0;
+
+	pr_debug("%s:session[%d]rate[%d]ch[%d]\n", __func__, ac->session, rate,
+		channels);
+
+	q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
+
+	fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
+	fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
+					sizeof(fmt.fmt_blk);
+	fmt.num_channels = channels;
+	fmt.bits_per_sample = 16;
+	fmt.sample_rate = rate;
+	fmt.is_signed = 1;
+
+	channel_mapping = fmt.channel_mapping;
+
+	memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
+
+	if (channels == 1)  {
+		channel_mapping[0] = PCM_CHANNEL_FL;
+	} else if (channels == 2) {
+		channel_mapping[0] = PCM_CHANNEL_FL;
+		channel_mapping[1] = PCM_CHANNEL_FR;
+	} else if (channels == 6) {
+		channel_mapping[0] = PCM_CHANNEL_FC;
+		channel_mapping[1] = PCM_CHANNEL_FL;
+		channel_mapping[2] = PCM_CHANNEL_FR;
+		channel_mapping[3] = PCM_CHANNEL_LB;
+		channel_mapping[4] = PCM_CHANNEL_RB;
+		channel_mapping[5] = PCM_CHANNEL_LFE;
+	} else {
+		pr_err("%s: ERROR.unsupported num_ch = %u\n", __func__,
+				channels);
+		return -EINVAL;
+	}
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
+	if (rc < 0) {
+		pr_err("%s:Comamnd open failed\n", __func__);
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("%s:timeout. waited for format update\n", __func__);
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
+int q6asm_media_format_block_multi_aac(struct audio_client *ac,
+				struct asm_aac_cfg *cfg)
+{
+	struct asm_aac_fmt_blk_v2 fmt;
+	int rc = 0;
+
+	pr_debug("%s:session[%d]rate[%d]ch[%d]\n", __func__, ac->session,
+		cfg->sample_rate, cfg->ch_cfg);
+
+	q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
+
+	fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
+	fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
+					sizeof(fmt.fmt_blk);
+	fmt.aac_fmt_flag = cfg->format;
+	fmt.audio_objype = cfg->aot;
+	/* If zero, PCE is assumed to be available in bitstream*/
+	fmt.total_size_of_PCE_bits = 0;
+	fmt.channel_config = cfg->ch_cfg;
+	fmt.sample_rate = cfg->sample_rate;
+
+	pr_info("%s:format=%x cfg_size=%d aac-cfg=%x aot=%d ch=%d sr=%d\n",
+			__func__, fmt.aac_fmt_flag, fmt.fmt_blk.fmt_blk_size,
+			fmt.aac_fmt_flag,
+			fmt.audio_objype,
+			fmt.channel_config,
+			fmt.sample_rate);
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
+	if (rc < 0) {
+		pr_err("%s:Comamnd open failed\n", __func__);
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("%s:timeout. waited for FORMAT_UPDATE\n", __func__);
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
+int q6asm_media_format_block_wma(struct audio_client *ac,
+				void *cfg)
+{
+	struct asm_wmastdv9_fmt_blk_v2 fmt;
+	struct asm_wma_cfg *wma_cfg = (struct asm_wma_cfg *)cfg;
+	int rc = 0;
+
+	pr_debug("session[%d]format_tag[0x%4x] rate[%d] ch[0x%4x] bps[%d],"
+		"balign[0x%4x], bit_sample[0x%4x], ch_msk[%d], enc_opt[0x%4x]\n",
+		ac->session, wma_cfg->format_tag, wma_cfg->sample_rate,
+		wma_cfg->ch_cfg, wma_cfg->avg_bytes_per_sec,
+		wma_cfg->block_align, wma_cfg->valid_bits_per_sample,
+		wma_cfg->ch_mask, wma_cfg->encode_opt);
+
+	q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
+
+	fmt.hdr.opcode = ASM_MEDIA_FMT_WMA_V9_V2;
+
+	fmt.fmtag = wma_cfg->format_tag;
+	fmt.num_channels = wma_cfg->ch_cfg;
+	fmt.sample_rate = wma_cfg->sample_rate;
+	fmt.avg_bytes_per_sec = wma_cfg->avg_bytes_per_sec;
+	fmt.blk_align = wma_cfg->block_align;
+	fmt.bits_per_sample =
+			wma_cfg->valid_bits_per_sample;
+	fmt.channel_mask = wma_cfg->ch_mask;
+	fmt.enc_options = wma_cfg->encode_opt;
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
+	if (rc < 0) {
+		pr_err("%s:Comamnd open failed\n", __func__);
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("%s:timeout. waited for FORMAT_UPDATE\n", __func__);
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
+int q6asm_media_format_block_wmapro(struct audio_client *ac,
+				void *cfg)
+{
+	struct asm_wmaprov10_fmt_blk_v2 fmt;
+	struct asm_wmapro_cfg *wmapro_cfg = (struct asm_wmapro_cfg *)cfg;
+	int rc = 0;
+
+	pr_debug("session[%d]format_tag[0x%4x] rate[%d] ch[0x%4x] bps[%d],"
+		"balign[0x%4x], bit_sample[0x%4x], ch_msk[%d], enc_opt[0x%4x],"
+		"adv_enc_opt[0x%4x], adv_enc_opt2[0x%8x]\n",
+		ac->session, wmapro_cfg->format_tag, wmapro_cfg->sample_rate,
+		wmapro_cfg->ch_cfg,  wmapro_cfg->avg_bytes_per_sec,
+		wmapro_cfg->block_align, wmapro_cfg->valid_bits_per_sample,
+		wmapro_cfg->ch_mask, wmapro_cfg->encode_opt,
+		wmapro_cfg->adv_encode_opt, wmapro_cfg->adv_encode_opt2);
+
+	q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
+
+	fmt.hdr.opcode = ASM_MEDIA_FMT_WMA_V10PRO_V2;
+
+	fmt.fmtag = wmapro_cfg->format_tag;
+	fmt.num_channels = wmapro_cfg->ch_cfg;
+	fmt.sample_rate = wmapro_cfg->sample_rate;
+	fmt.avg_bytes_per_sec =
+				wmapro_cfg->avg_bytes_per_sec;
+	fmt.blk_align = wmapro_cfg->block_align;
+	fmt.bits_per_sample = wmapro_cfg->valid_bits_per_sample;
+	fmt.channel_mask = wmapro_cfg->ch_mask;
+	fmt.enc_options = wmapro_cfg->encode_opt;
+	fmt.usAdvancedEncodeOpt = wmapro_cfg->adv_encode_opt;
+	fmt.advanced_enc_options2 = wmapro_cfg->adv_encode_opt2;
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
+	if (rc < 0) {
+		pr_err("%s:Comamnd open failed\n", __func__);
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("%s:timeout. waited for FORMAT_UPDATE\n", __func__);
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
+int q6asm_memory_map(struct audio_client *ac, uint32_t buf_add, int dir,
+				uint32_t bufsz, uint32_t bufcnt)
+{
+	struct avs_cmd_shared_mem_map_regions *mmap_regions = NULL;
+	struct avs_shared_map_region_payload  *mregions = NULL;
+	struct audio_port_data *port = NULL;
+	struct audio_buffer *ab = NULL;
+	void	*mmap_region_cmd = NULL;
+	void	*payload = NULL;
+	struct asm_buffer_node *buffer_node = NULL;
+	int	rc = 0;
+	int	i = 0;
+	int	cmd_size = 0;
+
+	if (!ac || ac->apr == NULL || ac->mmap_apr == NULL) {
+		pr_err("APR handle NULL\n");
+		return -EINVAL;
+	}
+	pr_debug("%s: Session[%d]\n", __func__, ac->session);
+
+	buffer_node = kmalloc(sizeof(struct asm_buffer_node), GFP_KERNEL);
+	if (!buffer_node)
+		return -ENOMEM;
+	cmd_size = sizeof(struct avs_cmd_shared_mem_map_regions)
+			+ sizeof(struct avs_shared_map_region_payload) * bufcnt;
+
+	mmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL);
+	if (mmap_region_cmd == NULL) {
+		pr_err("%s: Mem alloc failed\n", __func__);
+		rc = -EINVAL;
+		return rc;
+	}
+	mmap_regions = (struct avs_cmd_shared_mem_map_regions *)
+							mmap_region_cmd;
+	q6asm_add_mmaphdr(ac, &mmap_regions->hdr, cmd_size,
+			TRUE, ((ac->session << 8) | dir));
+	mmap_regions->hdr.opcode = ASM_CMD_SHARED_MEM_MAP_REGIONS;
+	mmap_regions->mem_pool_id = ADSP_MEMORY_MAP_EBI_POOL;
+	mmap_regions->num_regions = bufcnt & 0x00ff;
+	mmap_regions->property_flag = 0x00;
+	pr_debug("map_regions->nregions = %d\n", mmap_regions->num_regions);
+	payload = ((u8 *) mmap_region_cmd +
+		sizeof(struct avs_cmd_shared_mem_map_regions));
+	mregions = (struct avs_shared_map_region_payload *)payload;
+
+	ac->port[dir].tmp_hdl = 0;
+	port = &ac->port[dir];
+	for (i = 0; i < bufcnt; i++) {
+		ab = &port->buf[i];
+		mregions->shm_addr_lsw = ab->phys;
+		/* Using only 32 bit address */
+		mregions->shm_addr_msw = 0;
+		mregions->mem_size_bytes = ab->size;
+		++mregions;
+	}
+
+	rc = apr_send_pkt(ac->mmap_apr, (uint32_t *) mmap_region_cmd);
+	if (rc < 0) {
+		pr_err("mmap op[0x%x]rc[%d]\n",
+					mmap_regions->hdr.opcode, rc);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0 &&
+			 ac->port[dir].tmp_hdl), 5*HZ);
+	if (!rc) {
+		pr_err("timeout. waited for memory_map\n");
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+	buffer_node->buf_addr_lsw = buf_add;
+	buffer_node->mmap_hdl = ac->port[dir].tmp_hdl;
+	list_add_tail(&buffer_node->list, &ac->port[dir].mem_map_handle);
+	ac->port[dir].tmp_hdl = 0;
+	rc = 0;
+
+fail_cmd:
+	kfree(mmap_region_cmd);
+	return rc;
+}
+
+int q6asm_memory_unmap(struct audio_client *ac, uint32_t buf_add, int dir)
+{
+	struct avs_cmd_shared_mem_unmap_regions mem_unmap;
+	struct asm_buffer_node *buf_node = NULL;
+	struct list_head *ptr, *next;
+
+	int rc = 0;
+
+	if (!ac || ac->apr == NULL || this_mmap.apr == NULL) {
+		pr_err("APR handle NULL\n");
+		return -EINVAL;
+	}
+	pr_debug("%s: Session[%d]\n", __func__, ac->session);
+
+	q6asm_add_mmaphdr(ac, &mem_unmap.hdr,
+			sizeof(struct avs_cmd_shared_mem_unmap_regions),
+			TRUE, ((ac->session << 8) | dir));
+
+	mem_unmap.hdr.opcode = ASM_CMD_SHARED_MEM_UNMAP_REGIONS;
+	list_for_each_safe(ptr, next, &ac->port[dir].mem_map_handle) {
+		buf_node = list_entry(ptr, struct asm_buffer_node,
+						list);
+		if (buf_node->buf_addr_lsw == buf_add) {
+			pr_info("%s: Found the element\n", __func__);
+			mem_unmap.mem_map_handle = buf_node->mmap_hdl;
+			break;
+		}
+	}
+	pr_debug("%s: mem_unmap-mem_map_handle: 0x%x",
+		__func__, mem_unmap.mem_map_handle);
+	rc = apr_send_pkt(ac->mmap_apr, (uint32_t *) &mem_unmap);
+	if (rc < 0) {
+		pr_err("mem_unmap op[0x%x]rc[%d]\n",
+					mem_unmap.hdr.opcode, rc);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5 * HZ);
+	if (!rc) {
+		pr_err("timeout. waited for memory_map\n");
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+	list_for_each_safe(ptr, next, &ac->port[dir].mem_map_handle) {
+		buf_node = list_entry(ptr, struct asm_buffer_node,
+						list);
+		if (buf_node->buf_addr_lsw == buf_add) {
+			list_del(&buf_node->list);
+			kfree(buf_node);
+		}
+	}
+
+	rc = 0;
+fail_cmd:
+	return rc;
+}
+
+
+static int q6asm_memory_map_regions(struct audio_client *ac, int dir,
+				uint32_t bufsz, uint32_t bufcnt)
+{
+	struct avs_cmd_shared_mem_map_regions *mmap_regions = NULL;
+	struct avs_shared_map_region_payload  *mregions = NULL;
+	struct audio_port_data *port = NULL;
+	struct audio_buffer *ab = NULL;
+	void	*mmap_region_cmd = NULL;
+	void	*payload = NULL;
+	struct asm_buffer_node *buffer_node = NULL;
+	int	rc = 0;
+	int	i = 0;
+	int	cmd_size = 0;
+
+	if (!ac || ac->apr == NULL || ac->mmap_apr == NULL) {
+		pr_err("APR handle NULL\n");
+		return -EINVAL;
+	}
+	pr_debug("%s: Session[%d]\n", __func__, ac->session);
+
+	cmd_size = sizeof(struct avs_cmd_shared_mem_map_regions)
+			+ (sizeof(struct avs_shared_map_region_payload));
+
+	buffer_node = kzalloc(sizeof(struct asm_buffer_node) * bufcnt,
+				GFP_KERNEL);
+
+	mmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL);
+	if ((mmap_region_cmd == NULL) || (buffer_node == NULL)) {
+		pr_err("%s: Mem alloc failed\n", __func__);
+		rc = -EINVAL;
+		return rc;
+	}
+	mmap_regions = (struct avs_cmd_shared_mem_map_regions *)
+							mmap_region_cmd;
+	q6asm_add_mmaphdr(ac, &mmap_regions->hdr, cmd_size, TRUE,
+					((ac->session << 8) | dir));
+	pr_debug("mmap_region=0x%p token=0x%x\n",
+		mmap_regions, ((ac->session << 8) | dir));
+
+	mmap_regions->hdr.opcode = ASM_CMD_SHARED_MEM_MAP_REGIONS;
+	mmap_regions->mem_pool_id = ADSP_MEMORY_MAP_EBI_POOL;
+	mmap_regions->num_regions = 1; /*bufcnt & 0x00ff; */
+	mmap_regions->property_flag = 0x00;
+	pr_debug("map_regions->nregions = %d\n", mmap_regions->num_regions);
+	payload = ((u8 *) mmap_region_cmd +
+		sizeof(struct avs_cmd_shared_mem_map_regions));
+	mregions = (struct avs_shared_map_region_payload *)payload;
+
+	ac->port[dir].tmp_hdl = 0;
+	port = &ac->port[dir];
+	ab = &port->buf[0];
+	mregions->shm_addr_lsw = ab->phys;
+	/* Using only 32 bit address */
+	mregions->shm_addr_msw = 0;
+	mregions->mem_size_bytes = (bufsz * bufcnt);
+
+	rc = apr_send_pkt(ac->mmap_apr, (uint32_t *) mmap_region_cmd);
+	if (rc < 0) {
+		pr_err("mmap_regions op[0x%x]rc[%d]\n",
+					mmap_regions->hdr.opcode, rc);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0)
+			 , 5*HZ);
+			 /*ac->port[dir].tmp_hdl), 5*HZ);*/
+	if (!rc) {
+		pr_err("timeout. waited for memory_map\n");
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+	mutex_lock(&ac->cmd_lock);
+
+	for (i = 0; i < bufcnt; i++) {
+		ab = &port->buf[i];
+		buffer_node[i].buf_addr_lsw = ab->phys;
+		buffer_node[i].mmap_hdl = ac->port[dir].tmp_hdl;
+		list_add_tail(&buffer_node[i].list,
+			&ac->port[dir].mem_map_handle);
+		pr_debug("%s: i=%d, bufadd[i] = 0x%x, maphdl[i] = 0x%x\n",
+			__func__, i, buffer_node[i].buf_addr_lsw,
+			buffer_node[i].mmap_hdl);
+	}
+	ac->port[dir].tmp_hdl = 0;
+	mutex_unlock(&ac->cmd_lock);
+	rc = 0;
+	pr_debug("%s: exit\n", __func__);
+fail_cmd:
+	kfree(mmap_region_cmd);
+	return rc;
+}
+
+static int q6asm_memory_unmap_regions(struct audio_client *ac, int dir,
+				uint32_t bufsz, uint32_t bufcnt)
+{
+	struct avs_cmd_shared_mem_unmap_regions mem_unmap;
+	struct audio_port_data *port = NULL;
+	struct asm_buffer_node *buf_node = NULL;
+	struct list_head *ptr, *next;
+	uint32_t buf_add;
+	int	rc = 0;
+	int	cmd_size = 0;
+
+	if (!ac || ac->apr == NULL || ac->mmap_apr == NULL) {
+		pr_err("APR handle NULL\n");
+		return -EINVAL;
+	}
+	pr_debug("%s: Session[%d]\n", __func__, ac->session);
+
+	cmd_size = sizeof(struct avs_cmd_shared_mem_unmap_regions);
+	q6asm_add_mmaphdr(ac, &mem_unmap.hdr, cmd_size,
+			TRUE, ((ac->session << 8) | dir));
+	port = &ac->port[dir];
+	buf_add = (uint32_t)port->buf->phys;
+	mem_unmap.hdr.opcode = ASM_CMD_SHARED_MEM_UNMAP_REGIONS;
+	list_for_each_safe(ptr, next, &ac->port[dir].mem_map_handle) {
+		buf_node = list_entry(ptr, struct asm_buffer_node,
+						list);
+		if (buf_node->buf_addr_lsw == buf_add) {
+			pr_debug("%s: Found the element\n", __func__);
+			mem_unmap.mem_map_handle = buf_node->mmap_hdl;
+			break;
+		}
+	}
+
+	pr_debug("%s: mem_unmap-mem_map_handle: 0x%x",
+			__func__, mem_unmap.mem_map_handle);
+	rc = apr_send_pkt(ac->mmap_apr, (uint32_t *) &mem_unmap);
+	if (rc < 0) {
+		pr_err("mmap_regions op[0x%x]rc[%d]\n",
+					mem_unmap.hdr.opcode, rc);
+		goto fail_cmd;
+	}
+
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("timeout. waited for memory_unmap\n");
+		goto fail_cmd;
+	}
+	list_for_each_safe(ptr, next, &ac->port[dir].mem_map_handle) {
+		buf_node = list_entry(ptr, struct asm_buffer_node,
+						list);
+		if (buf_node->buf_addr_lsw == buf_add) {
+			list_del(&buf_node->list);
+			kfree(buf_node);
+		}
+	}
+	rc = 0;
+
+fail_cmd:
+	return rc;
+}
+
+int q6asm_set_lrgain(struct audio_client *ac, int left_gain, int right_gain)
+{
+	struct asm_volume_ctrl_lr_chan_gain lrgain;
+	int sz = 0;
+	int rc  = 0;
+
+	sz = sizeof(struct asm_volume_ctrl_lr_chan_gain);
+	q6asm_add_hdr_async(ac, &lrgain.hdr, sz, TRUE);
+	lrgain.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
+	lrgain.param.data_payload_addr_lsw = 0;
+	lrgain.param.data_payload_addr_msw = 0;
+	lrgain.param.mem_map_handle = 0;
+	lrgain.param.data_payload_size = sizeof(lrgain) -
+				sizeof(lrgain.hdr) - sizeof(lrgain.param);
+	lrgain.data.module_id = ASM_MODULE_ID_VOL_CTRL;
+	lrgain.data.param_id = ASM_PARAM_ID_VOL_CTRL_LR_CHANNEL_GAIN;
+	lrgain.data.param_size = lrgain.param.data_payload_size -
+				sizeof(lrgain.data);
+	lrgain.data.reserved = 0;
+	lrgain.l_chan_gain = left_gain;
+	lrgain.r_chan_gain = right_gain;
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &lrgain);
+	if (rc < 0) {
+		pr_err("%s: set-params send failed paramid[0x%x]\n", __func__,
+						lrgain.data.param_id);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
+						lrgain.data.param_id);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+	rc = 0;
+fail_cmd:
+	return rc;
+}
+
+int q6asm_set_mute(struct audio_client *ac, int muteflag)
+{
+	struct asm_volume_ctrl_mute_config mute;
+	int sz = 0;
+	int rc  = 0;
+
+	sz = sizeof(struct asm_volume_ctrl_mute_config);
+	q6asm_add_hdr_async(ac, &mute.hdr, sz, TRUE);
+	mute.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
+	mute.param.data_payload_addr_lsw = 0;
+	mute.param.data_payload_addr_msw = 0;
+	mute.param.mem_map_handle = 0;
+	mute.param.data_payload_size = sizeof(mute) -
+				sizeof(mute.hdr) - sizeof(mute.param);
+	mute.data.module_id = ASM_MODULE_ID_VOL_CTRL;
+	mute.data.param_id = ASM_PARAM_ID_VOL_CTRL_MUTE_CONFIG;
+	mute.data.param_size = mute.param.data_payload_size - sizeof(mute.data);
+	mute.data.reserved = 0;
+	mute.mute_flag = muteflag;
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &mute);
+	if (rc < 0) {
+		pr_err("%s: set-params send failed paramid[0x%x]\n", __func__,
+						mute.data.param_id);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
+						mute.data.param_id);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+	rc = 0;
+fail_cmd:
+	return rc;
+}
+
+int q6asm_set_volume(struct audio_client *ac, int volume)
+{
+	struct asm_volume_ctrl_master_gain vol;
+	int sz = 0;
+	int rc  = 0;
+
+	sz = sizeof(struct asm_volume_ctrl_master_gain);
+	q6asm_add_hdr_async(ac, &vol.hdr, sz, TRUE);
+	vol.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
+	vol.param.data_payload_addr_lsw = 0;
+	vol.param.data_payload_addr_msw = 0;
+
+
+	vol.param.mem_map_handle = 0;
+	vol.param.data_payload_size = sizeof(vol) -
+				sizeof(vol.hdr) - sizeof(vol.param);
+	vol.data.module_id = ASM_MODULE_ID_VOL_CTRL;
+	vol.data.param_id = ASM_PARAM_ID_VOL_CTRL_MASTER_GAIN;
+	vol.data.param_size = vol.param.data_payload_size - sizeof(vol.data);
+	vol.data.reserved = 0;
+	vol.master_gain = volume;
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &vol);
+	if (rc < 0) {
+		pr_err("%s: set-params send failed paramid[0x%x]\n", __func__,
+						vol.data.param_id);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
+						vol.data.param_id);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+	rc = 0;
+fail_cmd:
+	return rc;
+}
+int q6asm_set_softpause(struct audio_client *ac,
+			struct asm_softpause_params *pause_param)
+{
+	struct asm_soft_pause_params softpause;
+	int sz = 0;
+	int rc  = 0;
+
+	sz = sizeof(struct asm_soft_pause_params);
+	q6asm_add_hdr_async(ac, &softpause.hdr, sz, TRUE);
+	softpause.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
+
+	softpause.param.data_payload_addr_lsw = 0;
+	softpause.param.data_payload_addr_msw = 0;
+	softpause.param.mem_map_handle = 0;
+	softpause.param.data_payload_size = sizeof(softpause) -
+				sizeof(softpause.hdr) - sizeof(softpause.param);
+	softpause.data.module_id = ASM_MODULE_ID_VOL_CTRL;
+	softpause.data.param_id = ASM_PARAM_ID_SOFT_PAUSE_PARAMETERS;
+	softpause.data.param_size = softpause.param.data_payload_size -
+				sizeof(softpause.data);
+	softpause.data.reserved = 0;
+	softpause.enable_flag = pause_param->enable;
+	softpause.period = pause_param->period;
+	softpause.step = pause_param->step;
+	softpause.ramping_curve = pause_param->rampingcurve;
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &softpause);
+	if (rc < 0) {
+		pr_err("%s: set-params send failed paramid[0x%x]\n", __func__,
+						softpause.data.param_id);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
+						softpause.data.param_id);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+	rc = 0;
+fail_cmd:
+	return rc;
+}
+
+int q6asm_set_softvolume(struct audio_client *ac,
+			struct asm_softvolume_params *softvol_param)
+{
+	struct asm_soft_step_volume_params softvol;
+	int sz = 0;
+	int rc  = 0;
+
+	sz = sizeof(struct asm_soft_step_volume_params);
+	q6asm_add_hdr_async(ac, &softvol.hdr, sz, TRUE);
+	softvol.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
+	softvol.param.data_payload_addr_lsw = 0;
+	softvol.param.data_payload_addr_msw = 0;
+	softvol.param.mem_map_handle = 0;
+	softvol.param.data_payload_size = sizeof(softvol) -
+				sizeof(softvol.hdr) - sizeof(softvol.param);
+	softvol.data.module_id = ASM_MODULE_ID_VOL_CTRL;
+	softvol.data.param_id = ASM_PARAM_ID_SOFT_VOL_STEPPING_PARAMETERS;
+	softvol.data.param_size = softvol.param.data_payload_size -
+				sizeof(softvol.data);
+	softvol.data.reserved = 0;
+	softvol.period = softvol_param->period;
+	softvol.step = softvol_param->step;
+	softvol.ramping_curve = softvol_param->rampingcurve;
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &softvol);
+	if (rc < 0) {
+		pr_err("%s: set-params send failed paramid[0x%x]\n", __func__,
+						softvol.data.param_id);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
+						softvol.data.param_id);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+	rc = 0;
+fail_cmd:
+	return rc;
+}
+
+int q6asm_equalizer(struct audio_client *ac, void *eq_p)
+{
+	struct asm_eq_params eq;
+	struct msm_audio_eq_stream_config *eq_params = NULL;
+	int i  = 0;
+	int sz = 0;
+	int rc  = 0;
+
+	if (eq_p == NULL) {
+		pr_err("%s[%d]: Invalid Eq param\n", __func__, ac->session);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+	sz = sizeof(struct asm_eq_params);
+	eq_params = (struct msm_audio_eq_stream_config *) eq_p;
+	q6asm_add_hdr(ac, &eq.hdr, sz, TRUE);
+
+	eq.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
+	eq.param.data_payload_addr_lsw = 0;
+	eq.param.data_payload_addr_msw = 0;
+	eq.param.mem_map_handle = 0;
+	eq.param.data_payload_size = sizeof(eq) -
+				sizeof(eq.hdr) - sizeof(eq.param);
+	eq.data.module_id = ASM_MODULE_ID_EQUALIZER;
+	eq.data.param_id = ASM_PARAM_ID_EQUALIZER_PARAMETERS;
+	eq.data.param_size = eq.param.data_payload_size - sizeof(eq.data);
+	eq.enable_flag = eq_params->enable;
+	eq.num_bands = eq_params->num_bands;
+
+	pr_debug("%s: enable:%d numbands:%d\n", __func__, eq_params->enable,
+							eq_params->num_bands);
+	for (i = 0; i < eq_params->num_bands; i++) {
+		eq.eq_bands[i].band_idx =
+					eq_params->eq_bands[i].band_idx;
+		eq.eq_bands[i].filterype =
+					eq_params->eq_bands[i].filter_type;
+		eq.eq_bands[i].center_freq_hz =
+					eq_params->eq_bands[i].center_freq_hz;
+		eq.eq_bands[i].filter_gain =
+					eq_params->eq_bands[i].filter_gain;
+		eq.eq_bands[i].q_factor =
+					eq_params->eq_bands[i].q_factor;
+		pr_debug("%s: filter_type:%u bandnum:%d\n", __func__,
+				eq_params->eq_bands[i].filter_type, i);
+		pr_debug("%s: center_freq_hz:%u bandnum:%d\n", __func__,
+				eq_params->eq_bands[i].center_freq_hz, i);
+		pr_debug("%s: filter_gain:%d bandnum:%d\n", __func__,
+				eq_params->eq_bands[i].filter_gain, i);
+		pr_debug("%s: q_factor:%d bandnum:%d\n", __func__,
+				eq_params->eq_bands[i].q_factor, i);
+	}
+	rc = apr_send_pkt(ac->apr, (uint32_t *)&eq);
+	if (rc < 0) {
+		pr_err("%s: set-params send failed paramid[0x%x]\n", __func__,
+						eq.data.param_id);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
+						eq.data.param_id);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+	rc = 0;
+fail_cmd:
+	return rc;
+}
+
+int q6asm_read(struct audio_client *ac)
+{
+	struct asm_data_cmd_read_v2 read;
+	struct asm_buffer_node *buf_node = NULL;
+	struct list_head *ptr, *next;
+	struct audio_buffer        *ab;
+	int dsp_buf;
+	struct audio_port_data     *port;
+	int rc;
+	if (!ac || ac->apr == NULL) {
+		pr_err("APR handle NULL\n");
+		return -EINVAL;
+	}
+	if (ac->io_mode == SYNC_IO_MODE) {
+		port = &ac->port[OUT];
+
+		q6asm_add_hdr(ac, &read.hdr, sizeof(read), FALSE);
+
+		mutex_lock(&port->lock);
+
+		dsp_buf = port->dsp_buf;
+		ab = &port->buf[dsp_buf];
+
+		pr_debug("%s:session[%d]dsp-buf[%d][%p]cpu_buf[%d][%p]\n",
+					__func__,
+					ac->session,
+					dsp_buf,
+					(void *)port->buf[dsp_buf].data,
+					port->cpu_buf,
+					(void *)port->buf[port->cpu_buf].phys);
+
+		read.hdr.opcode = ASM_DATA_CMD_READ_V2;
+		read.buf_addr_lsw = ab->phys;
+		read.buf_addr_msw = 0;
+
+		list_for_each_safe(ptr, next, &ac->port[OUT].mem_map_handle) {
+			buf_node = list_entry(ptr, struct asm_buffer_node,
+						list);
+			if (buf_node->buf_addr_lsw == (uint32_t) ab->phys)
+				read.mem_map_handle = buf_node->mmap_hdl;
+		}
+		pr_debug("memory_map handle in q6asm_read: [%0x]:",
+			read.mem_map_handle);
+		read.buf_size = ab->size;
+		read.seq_id = port->dsp_buf;
+		read.hdr.token = port->dsp_buf;
+		port->dsp_buf = (port->dsp_buf + 1) & (port->max_buf_cnt - 1);
+		mutex_unlock(&port->lock);
+		pr_debug("%s:buf add[0x%x] token[%d] uid[%d]\n", __func__,
+						read.buf_addr_lsw,
+						read.hdr.token,
+						read.seq_id);
+		rc = apr_send_pkt(ac->apr, (uint32_t *) &read);
+		if (rc < 0) {
+			pr_err("read op[0x%x]rc[%d]\n", read.hdr.opcode, rc);
+			goto fail_cmd;
+		}
+		return 0;
+	}
+fail_cmd:
+	return -EINVAL;
+}
+
+int q6asm_read_nolock(struct audio_client *ac)
+{
+	struct asm_data_cmd_read_v2 read;
+	struct asm_buffer_node *buf_node = NULL;
+	struct list_head *ptr, *next;
+	struct audio_buffer        *ab;
+	int dsp_buf;
+	struct audio_port_data     *port;
+	int rc;
+	if (!ac || ac->apr == NULL) {
+		pr_err("APR handle NULL\n");
+		return -EINVAL;
+	}
+	if (ac->io_mode == SYNC_IO_MODE) {
+		port = &ac->port[OUT];
+
+		q6asm_add_hdr_async(ac, &read.hdr, sizeof(read), FALSE);
+
+
+		dsp_buf = port->dsp_buf;
+		ab = &port->buf[dsp_buf];
+
+		pr_debug("%s:session[%d]dsp-buf[%d][%p]cpu_buf[%d][%p]\n",
+					__func__,
+					ac->session,
+					dsp_buf,
+					(void *)port->buf[dsp_buf].data,
+					port->cpu_buf,
+					(void *)port->buf[port->cpu_buf].phys);
+
+		read.hdr.opcode = ASM_DATA_CMD_READ_V2;
+		read.buf_addr_lsw = ab->phys;
+		read.buf_addr_msw = 0;
+		read.buf_size = ab->size;
+		read.seq_id = port->dsp_buf;
+		read.hdr.token = port->dsp_buf;
+
+		list_for_each_safe(ptr, next, &ac->port[OUT].mem_map_handle) {
+			buf_node = list_entry(ptr, struct asm_buffer_node,
+						list);
+			if (buf_node->buf_addr_lsw == (uint32_t)ab->phys) {
+				read.mem_map_handle = buf_node->mmap_hdl;
+				break;
+			}
+		}
+
+		port->dsp_buf = (port->dsp_buf + 1) & (port->max_buf_cnt - 1);
+		pr_debug("%s:buf add[0x%x] token[%d] uid[%d]\n", __func__,
+					read.buf_addr_lsw,
+					read.hdr.token,
+					read.seq_id);
+		pr_debug("q6asm_read_nolock mem-map handle is %x",
+				read.mem_map_handle);
+		rc = apr_send_pkt(ac->apr, (uint32_t *) &read);
+		if (rc < 0) {
+			pr_err("read op[0x%x]rc[%d]\n", read.hdr.opcode, rc);
+			goto fail_cmd;
+		}
+		return 0;
+	}
+fail_cmd:
+	return -EINVAL;
+}
+
+int q6asm_async_write(struct audio_client *ac,
+					  struct audio_aio_write_param *param)
+{
+	int rc = 0;
+	struct asm_data_cmd_write_v2 write;
+	struct asm_buffer_node *buf_node = NULL;
+	struct list_head *ptr, *next;
+	struct audio_buffer        *ab;
+	struct audio_port_data     *port;
+
+	if (!ac || ac->apr == NULL) {
+		pr_err("%s: APR handle NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	q6asm_add_hdr_async(ac, &write.hdr, sizeof(write), FALSE);
+
+	port = &ac->port[IN];
+	ab = &port->buf[port->dsp_buf];
+
+	/* Pass physical address as token for AIO scheme */
+	write.hdr.token = param->uid;
+	write.hdr.opcode = ASM_DATA_CMD_WRITE_V2;
+	write.buf_addr_lsw = param->paddr;
+	write.buf_addr_msw = 0x00;
+	write.buf_size = param->len;
+	write.timestamp_msw = param->msw_ts;
+	write.timestamp_lsw = param->lsw_ts;
+	pr_debug("%s: token[0x%x], buf_addr_lsw[0x%x], buf_size[0x%x],"
+		"ts_msw[0x%x], ts_lsw[0x%x]\n",
+		__func__, write.hdr.token, write.buf_addr_lsw,
+		write.buf_size, write.timestamp_msw,
+		write.timestamp_lsw);
+	/* Use 0xFF00 for disabling timestamps */
+	if (param->flags == 0xFF00)
+		write.flags = (0x00000000 | (param->flags & 0x800000FF));
+	else
+		write.flags = (0x80000000 | param->flags);
+
+	write.seq_id = param->uid;
+	list_for_each_safe(ptr, next, &ac->port[IN].mem_map_handle) {
+		buf_node = list_entry(ptr, struct asm_buffer_node,
+						list);
+		if (buf_node->buf_addr_lsw == (uint32_t)write.buf_addr_lsw) {
+			write.mem_map_handle = buf_node->mmap_hdl;
+			pr_debug("%s:buf_node->mmap_hdl = 0x%x,"
+				"write.mem_map_handle = 0x%x\n",
+					__func__,
+					buf_node->mmap_hdl,
+					(uint32_t)write.mem_map_handle);
+			break;
+		}
+	}
+
+	pr_debug("%s: session[%d] bufadd[0x%x]len[0x%x],"
+			"mem_map_handle[0x%x]\n", __func__, ac->session,
+		write.buf_addr_lsw, write.buf_size, write.mem_map_handle);
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &write);
+	if (rc < 0) {
+		pr_debug("[%s] write op[0x%x]rc[%d]\n", __func__,
+			write.hdr.opcode, rc);
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
+int q6asm_async_read(struct audio_client *ac,
+					  struct audio_aio_read_param *param)
+{
+	int rc = 0;
+	struct asm_data_cmd_read_v2 read;
+	struct asm_buffer_node *buf_node = NULL;
+	struct list_head *ptr, *next;
+
+	if (!ac || ac->apr == NULL) {
+		pr_err("%s: APR handle NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	q6asm_add_hdr_async(ac, &read.hdr, sizeof(read), FALSE);
+
+	/* Pass physical address as token for AIO scheme */
+	read.hdr.token = param->paddr;
+	read.hdr.opcode = ASM_DATA_CMD_READ_V2;
+	read.buf_addr_lsw = param->paddr;
+	read.buf_addr_msw = 0;
+	read.buf_size = param->len;
+	read.seq_id = param->uid;
+
+	list_for_each_safe(ptr, next, &ac->port[IN].mem_map_handle) {
+		buf_node = list_entry(ptr, struct asm_buffer_node,
+						list);
+			if (buf_node->buf_addr_lsw == param->paddr)
+				read.mem_map_handle = buf_node->mmap_hdl;
+	}
+
+	pr_debug("%s: session[%d] bufadd[0x%x]len[0x%x]", __func__, ac->session,
+		read.buf_addr_lsw, read.buf_size);
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &read);
+	if (rc < 0) {
+		pr_debug("[%s] read op[0x%x]rc[%d]\n", __func__,
+			read.hdr.opcode, rc);
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
+int q6asm_write(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
+		uint32_t lsw_ts, uint32_t flags)
+{
+	int rc = 0;
+	struct asm_data_cmd_write_v2 write;
+	struct asm_buffer_node *buf_node = NULL;
+	struct audio_port_data *port;
+	struct audio_buffer    *ab;
+	int dsp_buf = 0;
+
+	if (!ac || ac->apr == NULL) {
+		pr_err("APR handle NULL\n");
+		return -EINVAL;
+	}
+	pr_debug("%s: session[%d] len=%d", __func__, ac->session, len);
+	if (ac->io_mode == SYNC_IO_MODE) {
+		port = &ac->port[IN];
+
+		q6asm_add_hdr(ac, &write.hdr, sizeof(write),
+				FALSE);
+		mutex_lock(&port->lock);
+
+		dsp_buf = port->dsp_buf;
+		ab = &port->buf[dsp_buf];
+
+		write.hdr.token = port->dsp_buf;
+		write.hdr.opcode = ASM_DATA_CMD_WRITE_V2;
+		write.buf_addr_lsw = ab->phys;
+		write.buf_addr_msw = 0;
+		write.buf_size = len;
+		write.seq_id = port->dsp_buf;
+		write.timestamp_lsw = lsw_ts;
+		write.timestamp_msw = msw_ts;
+		/* Use 0xFF00 for disabling timestamps */
+		if (flags == 0xFF00)
+			write.flags = (0x00000000 | (flags & 0x800000FF));
+		else
+			write.flags = (0x80000000 | flags);
+		port->dsp_buf = (port->dsp_buf + 1) & (port->max_buf_cnt - 1);
+		buf_node = list_first_entry(&ac->port[IN].mem_map_handle,
+						struct asm_buffer_node,
+						list);
+		write.mem_map_handle = buf_node->mmap_hdl;
+
+		pr_debug("%s:ab->phys[0x%x]bufadd[0x%x]"
+			"token[0x%x]buf_id[0x%x]buf_size[0x%x]mmaphdl[0x%x]"
+						, __func__,
+						ab->phys,
+						write.buf_addr_lsw,
+						write.hdr.token,
+						write.seq_id,
+						write.buf_size,
+						write.mem_map_handle);
+		mutex_unlock(&port->lock);
+
+		config_debug_fs_write(ab);
+
+		rc = apr_send_pkt(ac->apr, (uint32_t *) &write);
+		if (rc < 0) {
+			pr_err("write op[0x%x]rc[%d]\n", write.hdr.opcode, rc);
+			goto fail_cmd;
+		}
+		pr_debug("%s: WRITE SUCCESS\n", __func__);
+		return 0;
+	}
+fail_cmd:
+	return -EINVAL;
+}
+
+int q6asm_write_nolock(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
+			uint32_t lsw_ts, uint32_t flags)
+{
+	int rc = 0;
+	struct asm_data_cmd_write_v2 write;
+	struct asm_buffer_node *buf_node = NULL;
+	struct audio_port_data *port;
+	struct audio_buffer    *ab;
+	int dsp_buf = 0;
+
+	if (!ac || ac->apr == NULL) {
+		pr_err("APR handle NULL\n");
+		return -EINVAL;
+	}
+	pr_debug("%s: session[%d] len=%d", __func__, ac->session, len);
+	if (ac->io_mode == SYNC_IO_MODE) {
+		port = &ac->port[IN];
+
+		q6asm_add_hdr_async(ac, &write.hdr, sizeof(write),
+					FALSE);
+
+		dsp_buf = port->dsp_buf;
+		ab = &port->buf[dsp_buf];
+
+		write.hdr.token = port->dsp_buf;
+		write.hdr.opcode = ASM_DATA_CMD_WRITE_V2;
+		write.buf_addr_lsw = ab->phys;
+		write.buf_addr_msw = 0;
+		write.buf_size = len;
+		write.seq_id = port->dsp_buf;
+		write.timestamp_lsw = lsw_ts;
+		write.timestamp_msw = msw_ts;
+		buf_node = list_first_entry(&ac->port[IN].mem_map_handle,
+						struct asm_buffer_node,
+						list);
+		write.mem_map_handle = buf_node->mmap_hdl;
+		/* Use 0xFF00 for disabling timestamps */
+		if (flags == 0xFF00)
+			write.flags = (0x00000000 | (flags & 0x800000FF));
+		else
+			write.flags = (0x80000000 | flags);
+		port->dsp_buf = (port->dsp_buf + 1) & (port->max_buf_cnt - 1);
+
+		pr_err("%s:ab->phys[0x%x]bufadd[0x%x]token[0x%x]"
+			"buf_id[0x%x]buf_size[0x%x]mmaphdl[0x%x]"
+							, __func__,
+							ab->phys,
+							write.buf_addr_lsw,
+							write.hdr.token,
+							write.seq_id,
+							write.buf_size,
+							write.mem_map_handle);
+
+		rc = apr_send_pkt(ac->apr, (uint32_t *) &write);
+		if (rc < 0) {
+			pr_err("write op[0x%x]rc[%d]\n", write.hdr.opcode, rc);
+			goto fail_cmd;
+		}
+		pr_debug("%s: WRITE SUCCESS\n", __func__);
+		return 0;
+	}
+fail_cmd:
+	return -EINVAL;
+}
+
+uint64_t q6asm_get_session_time(struct audio_client *ac)
+{
+	struct apr_hdr hdr;
+	int rc;
+
+	if (!ac || ac->apr == NULL) {
+		pr_err("APR handle NULL\n");
+		return -EINVAL;
+	}
+	q6asm_add_hdr(ac, &hdr, sizeof(hdr), TRUE);
+	hdr.opcode = ASM_SESSION_CMD_GET_SESSIONTIME_V3;
+	atomic_set(&ac->cmd_state, 1);
+
+	pr_debug("%s: session[%d]opcode[0x%x]\n", __func__,
+						ac->session,
+						hdr.opcode);
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &hdr);
+	if (rc < 0) {
+		pr_err("Commmand 0x%x failed\n", hdr.opcode);
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("%s: timeout in getting session time from DSP\n",
+			__func__);
+		goto fail_cmd;
+	}
+	return ac->time_stamp;
+
+fail_cmd:
+	return -EINVAL;
+}
+
+int q6asm_cmd(struct audio_client *ac, int cmd)
+{
+	struct apr_hdr hdr;
+	int rc;
+	atomic_t *state;
+	int cnt = 0;
+
+	if (!ac || ac->apr == NULL) {
+		pr_err("APR handle NULL\n");
+		return -EINVAL;
+	}
+	q6asm_add_hdr(ac, &hdr, sizeof(hdr), TRUE);
+	switch (cmd) {
+	case CMD_PAUSE:
+		pr_debug("%s:CMD_PAUSE\n", __func__);
+		hdr.opcode = ASM_SESSION_CMD_PAUSE;
+		state = &ac->cmd_state;
+		break;
+	case CMD_FLUSH:
+		pr_debug("%s:CMD_FLUSH\n", __func__);
+		hdr.opcode = ASM_STREAM_CMD_FLUSH;
+		state = &ac->cmd_state;
+		break;
+	case CMD_OUT_FLUSH:
+		pr_debug("%s:CMD_OUT_FLUSH\n", __func__);
+		hdr.opcode = ASM_STREAM_CMD_FLUSH_READBUFS;
+		state = &ac->cmd_state;
+		break;
+	case CMD_EOS:
+		pr_debug("%s:CMD_EOS\n", __func__);
+		hdr.opcode = ASM_DATA_CMD_EOS;
+		atomic_set(&ac->cmd_state, 0);
+		state = &ac->cmd_state;
+		break;
+	case CMD_CLOSE:
+		pr_debug("%s:CMD_CLOSE\n", __func__);
+		hdr.opcode = ASM_STREAM_CMD_CLOSE;
+		state = &ac->cmd_state;
+		break;
+	default:
+		pr_err("Invalid format[%d]\n", cmd);
+		goto fail_cmd;
+	}
+	pr_debug("%s:session[%d]opcode[0x%x] ", __func__,
+						ac->session,
+						hdr.opcode);
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &hdr);
+	if (rc < 0) {
+		pr_err("Commmand 0x%x failed\n", hdr.opcode);
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(ac->cmd_wait, (atomic_read(state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("timeout. waited for response opcode[0x%x]\n",
+							hdr.opcode);
+		goto fail_cmd;
+	}
+	if (cmd == CMD_FLUSH)
+		q6asm_reset_buf_state(ac);
+	if (cmd == CMD_CLOSE) {
+		/* check if DSP return all buffers */
+		if (ac->port[IN].buf) {
+			for (cnt = 0; cnt < ac->port[IN].max_buf_cnt;
+								cnt++) {
+				if (ac->port[IN].buf[cnt].used == IN) {
+					pr_debug("Write Buf[%d] not returned\n",
+									cnt);
+				}
+			}
+		}
+		if (ac->port[OUT].buf) {
+			for (cnt = 0; cnt < ac->port[OUT].max_buf_cnt; cnt++) {
+				if (ac->port[OUT].buf[cnt].used == OUT) {
+					pr_debug("Read Buf[%d] not returned\n",
+									cnt);
+				}
+			}
+		}
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
+int q6asm_cmd_nowait(struct audio_client *ac, int cmd)
+{
+	struct apr_hdr hdr;
+	int rc;
+
+	if (!ac || ac->apr == NULL) {
+		pr_err("%s:APR handle NULL\n", __func__);
+		return -EINVAL;
+	}
+	q6asm_add_hdr_async(ac, &hdr, sizeof(hdr), TRUE);
+	switch (cmd) {
+	case CMD_PAUSE:
+		pr_debug("%s:CMD_PAUSE\n", __func__);
+		hdr.opcode = ASM_SESSION_CMD_PAUSE;
+		break;
+	case CMD_EOS:
+		pr_debug("%s:CMD_EOS\n", __func__);
+		hdr.opcode = ASM_DATA_CMD_EOS;
+		break;
+	default:
+		pr_err("%s:Invalid format[%d]\n", __func__, cmd);
+		goto fail_cmd;
+	}
+	pr_debug("%s:session[%d]opcode[0x%x] ", __func__,
+						ac->session,
+						hdr.opcode);
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &hdr);
+	if (rc < 0) {
+		pr_err("%s:Commmand 0x%x failed\n", __func__, hdr.opcode);
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
+static void q6asm_reset_buf_state(struct audio_client *ac)
+{
+	int cnt = 0;
+	int loopcnt = 0;
+	struct audio_port_data *port = NULL;
+
+	if (ac->io_mode == SYNC_IO_MODE) {
+		mutex_lock(&ac->cmd_lock);
+		for (loopcnt = 0; loopcnt <= OUT; loopcnt++) {
+			port = &ac->port[loopcnt];
+			cnt = port->max_buf_cnt - 1;
+			port->dsp_buf = 0;
+			port->cpu_buf = 0;
+			while (cnt >= 0) {
+				if (!port->buf)
+					continue;
+				port->buf[cnt].used = 1;
+				cnt--;
+			}
+		}
+		mutex_unlock(&ac->cmd_lock);
+	}
+}
+
+int q6asm_reg_tx_overflow(struct audio_client *ac, uint16_t enable)
+{
+	struct asm_session_cmd_regx_overflow tx_overflow;
+	int rc;
+
+	if (!ac || ac->apr == NULL) {
+		pr_err("APR handle NULL\n");
+		return -EINVAL;
+	}
+	pr_debug("%s:session[%d]enable[%d]\n", __func__,
+						ac->session, enable);
+	q6asm_add_hdr(ac, &tx_overflow.hdr, sizeof(tx_overflow), TRUE);
+
+	tx_overflow.hdr.opcode = \
+			ASM_SESSION_CMD_REGISTER_FORX_OVERFLOW_EVENTS;
+	/* tx overflow event: enable */
+	tx_overflow.enable_flag = enable;
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &tx_overflow);
+	if (rc < 0) {
+		pr_err("tx overflow op[0x%x]rc[%d]\n", \
+						tx_overflow.hdr.opcode, rc);
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(ac->cmd_wait,
+				(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("timeout. waited for tx overflow\n");
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
+int q6asm_get_apr_service_id(int session_id)
+{
+	pr_debug("%s\n", __func__);
+
+	if (session_id < 0 || session_id > SESSION_MAX) {
+		pr_err("%s: invalid session_id = %d\n", __func__, session_id);
+		return -EINVAL;
+	}
+
+	return ((struct apr_svc *)session[session_id]->apr)->id;
+}
+
+
+static int __init q6asm_init(void)
+{
+	pr_debug("%s\n", __func__);
+	memset(session, 0, sizeof(session));
+
+	config_debug_fs_init();
+
+	return 0;
+}
+
+device_initcall(q6asm_init);
diff --git a/sound/soc/msm/qdsp6v2/q6audio-v2.c b/sound/soc/msm/qdsp6v2/q6audio-v2.c
new file mode 100644
index 0000000..8c524fa
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/q6audio-v2.c
@@ -0,0 +1,151 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/jiffies.h>
+#include <linux/uaccess.h>
+#include <linux/atomic.h>
+#include <sound/q6afe-v2.h>
+#include <sound/q6audio-v2.h>
+
+int q6audio_get_port_index(u16 port_id)
+{
+	switch (port_id) {
+	case PRIMARY_I2S_RX: return IDX_PRIMARY_I2S_RX;
+	case PRIMARY_I2S_TX: return IDX_PRIMARY_I2S_TX;
+	case PCM_RX: return IDX_PCM_RX;
+	case PCM_TX: return IDX_PCM_TX;
+	case SECONDARY_I2S_RX: return IDX_SECONDARY_I2S_RX;
+	case SECONDARY_I2S_TX: return IDX_SECONDARY_I2S_TX;
+	case MI2S_RX: return IDX_MI2S_RX;
+	case MI2S_TX: return IDX_MI2S_TX;
+	case HDMI_RX: return IDX_HDMI_RX;
+	case RSVD_2: return IDX_RSVD_2;
+	case RSVD_3: return IDX_RSVD_3;
+	case DIGI_MIC_TX: return IDX_DIGI_MIC_TX;
+	case VOICE_RECORD_RX: return IDX_VOICE_RECORD_RX;
+	case VOICE_RECORD_TX: return IDX_VOICE_RECORD_TX;
+	case VOICE_PLAYBACK_TX: return IDX_VOICE_PLAYBACK_TX;
+	case SLIMBUS_0_RX: return IDX_SLIMBUS_0_RX;
+	case SLIMBUS_0_TX: return IDX_SLIMBUS_0_TX;
+	case SLIMBUS_1_RX: return IDX_SLIMBUS_1_RX;
+	case SLIMBUS_1_TX: return IDX_SLIMBUS_1_TX;
+	case INT_BT_SCO_RX: return IDX_INT_BT_SCO_RX;
+	case INT_BT_SCO_TX: return IDX_INT_BT_SCO_TX;
+	case INT_BT_A2DP_RX: return IDX_INT_BT_A2DP_RX;
+	case INT_FM_RX: return IDX_INT_FM_RX;
+	case INT_FM_TX: return IDX_INT_FM_TX;
+	case RT_PROXY_PORT_001_RX: return IDX_RT_PROXY_PORT_001_RX;
+	case RT_PROXY_PORT_001_TX: return IDX_RT_PROXY_PORT_001_TX;
+
+	default: return -EINVAL;
+	}
+}
+
+int q6audio_get_port_id(u16 port_id)
+{
+	switch (port_id) {
+	case PRIMARY_I2S_RX: return AFE_PORT_ID_PRIMARY_MI2S_RX;
+	case PRIMARY_I2S_TX: return AFE_PORT_ID_PRIMARY_MI2S_TX;
+	case PCM_RX: return AFE_PORT_ID_PRIMARY_PCM_RX;
+	case PCM_TX: return AFE_PORT_ID_PRIMARY_PCM_TX;
+	case SECONDARY_I2S_RX: return AFE_PORT_ID_SECONDARY_MI2S_RX;
+	case SECONDARY_I2S_TX: return AFE_PORT_ID_SECONDARY_MI2S_TX;
+	case MI2S_RX: return AFE_PORT_ID_PRIMARY_MI2S_RX;
+	case MI2S_TX: return AFE_PORT_ID_PRIMARY_MI2S_TX;
+	case HDMI_RX: return AFE_PORT_ID_MULTICHAN_HDMI_RX;
+	case RSVD_2: return IDX_RSVD_2;
+	case RSVD_3: return IDX_RSVD_3;
+	case DIGI_MIC_TX: return AFE_PORT_ID_DIGITAL_MIC_TX;
+	case VOICE_RECORD_RX: return AFE_PORT_ID_VOICE_RECORD_RX;
+	case VOICE_RECORD_TX: return AFE_PORT_ID_VOICE_RECORD_TX;
+	case VOICE_PLAYBACK_TX: return AFE_PORT_ID_VOICE_PLAYBACK_TX;
+	case SLIMBUS_0_RX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_0_RX;
+	case SLIMBUS_0_TX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_0_TX;
+	case SLIMBUS_1_RX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_1_RX;
+	case SLIMBUS_1_TX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_1_TX;
+	case INT_BT_SCO_RX: return AFE_PORT_ID_INTERNAL_BT_SCO_RX;
+	case INT_BT_SCO_TX: return AFE_PORT_ID_INTERNAL_BT_SCO_TX;
+	case INT_BT_A2DP_RX: return AFE_PORT_ID_INTERNAL_BT_A2DP_RX;
+	case INT_FM_RX: return AFE_PORT_ID_INTERNAL_FM_RX;
+	case INT_FM_TX: return AFE_PORT_ID_INTERNAL_FM_TX;
+	case RT_PROXY_PORT_001_RX: return AFE_PORT_ID_RT_PROXY_PORT_001_RX;
+	case RT_PROXY_PORT_001_TX: return AFE_PORT_ID_RT_PROXY_PORT_001_TX;
+
+	default: return -EINVAL;
+	}
+}
+int q6audio_convert_virtual_to_portid(u16 port_id)
+{
+	int ret;
+
+	/* if port_id is virtual, convert to physical..
+	 * if port_id is already physical, return physical
+	 */
+	if (q6audio_validate_port(port_id) < 0) {
+		if (port_id == RT_PROXY_DAI_001_RX ||
+			port_id == RT_PROXY_DAI_001_TX ||
+			port_id == RT_PROXY_DAI_002_RX ||
+			port_id == RT_PROXY_DAI_002_TX)
+			ret = VIRTUAL_ID_TO_PORTID(port_id);
+		else
+			ret = -EINVAL;
+	} else
+		ret = port_id;
+
+	return ret;
+}
+
+int q6audio_validate_port(u16 port_id)
+{
+	int ret;
+
+	switch (port_id) {
+	case PRIMARY_I2S_RX:
+	case PRIMARY_I2S_TX:
+	case PCM_RX:
+	case PCM_TX:
+	case SECONDARY_I2S_RX:
+	case SECONDARY_I2S_TX:
+	case MI2S_RX:
+	case MI2S_TX:
+	case HDMI_RX:
+	case RSVD_2:
+	case RSVD_3:
+	case DIGI_MIC_TX:
+	case VOICE_RECORD_RX:
+	case VOICE_RECORD_TX:
+	case VOICE_PLAYBACK_TX:
+	case SLIMBUS_0_RX:
+	case SLIMBUS_0_TX:
+	case SLIMBUS_1_RX:
+	case SLIMBUS_1_TX:
+	case INT_BT_SCO_RX:
+	case INT_BT_SCO_TX:
+	case INT_BT_A2DP_RX:
+	case INT_FM_RX:
+	case INT_FM_TX:
+	case RT_PROXY_PORT_001_RX:
+	case RT_PROXY_PORT_001_TX:
+	{
+		ret = 0;
+		break;
+	}
+
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 2284f19..b6ddcc8a 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -1543,10 +1543,17 @@
 
 			trace_snd_soc_dapm_widget_power(w, power);
 
-			if (power)
+			if (power) {
 				dapm_seq_insert(w, &up_list, true);
-			else
+				dev_dbg(w->dapm->dev,
+					"%s(): power up . widget  %s\n",
+					__func__, w->name);
+			} else {
 				dapm_seq_insert(w, &down_list, false);
+				dev_dbg(w->dapm->dev,
+					"%s(): power down . widget  %s\n",
+					__func__, w->name);
+			}
 
 			w->power = power;
 			break;