Merge "msm: kgsl: Set the context ID of iommu bank based on address"
diff --git a/Documentation/arm/msm/msm_smp2p.txt b/Documentation/arm/msm/msm_smp2p.txt
new file mode 100644
index 0000000..4f77614
--- /dev/null
+++ b/Documentation/arm/msm/msm_smp2p.txt
@@ -0,0 +1,416 @@
+Introduction
+============
+The Shared Memory Point to Point (SMP2P) protocol facilitates communication of
+a single 32-bit value between two processors.  Each value has a single writer
+(the local side) and a single reader (the remote side).  Values are uniquely
+identified in the system by the directed edge (local processor ID to remote
+processor ID) and a string identifier.
+
+Version and feature negotiation has been included in the design to allow for
+phased upgrades of all processors.
+
+Software Architecture Description
+=================================
+The data and interrupt coupling between processors is shown in Fig. 1.  Each
+processor is responsible for creating the outgoing SMEM items and each item is
+writable by the local processor and readable by the remote processor.  By using
+two separate SMEM items that are single-reader and single-writer, SMP2P does
+not require any remote locking mechanisms.
+
+The client API uses the Linux GPIO and interrupt framework to expose a virtual
+GPIO and a virtual interrupt controller for each entry.
+
+                                      =================
+                                      |               |
+                     -----write------>|SMEM item A->B |-----read------
+                    |                 |               |               |
+                    |                 =================               |
+                    |                                                 |
+                    |                                                 v
+  GPIO API =>  ------------    ======= Interrupt line ======>     ------------
+               Processor A                                        Processor B
+ Interrupt <=  ------------    <====== Interrupt line =======     ------------
+    API             ^                                                 |
+                    |                                                 |
+                    |                                                 |
+                    |                 =================               |
+                    |                 |               |               |
+                     ------read-------|SMEM item A<-B |<-----write----
+                                      |               |
+                                      =================
+
+                                    Fig 1
+
+
+Design
+======
+Each SMEM item contains a header that is used to identify and manage the edge
+along with an array of actual entries.  The overall structure is captured in
+Fig 2 and the details of the header and entries are covered later in this
+section.  The memory format of all shared structures is little-endian.
+
+      -----------------------------------------------
+     |               SMEM item A->B                  |
+     |                                               |
+     |   -----------------------------------------   |
+     |  |31      24|       16|         8|        0|  |
+     |  |----------|---------|----------|---------|  |
+     |  |       Identifier Constant(Magic Number) |  |
+     |  |----------|---------|----------|---------|  |
+     |  | Feature Flags                 |Version  |  |
+     |  |                               |Number   |  |
+     |  |----------|---------|----------|---------|  |
+     |  | Remote Proc ID     |Local Proc ID       |  |
+     |  |----------|---------|----------|---------|  |
+     |  | Entries Valid      | Entries Total      |  |
+     |  |-----------------------------------------|  |
+     |                                               |
+     |                                               |
+     |   -----------------------------------------   |
+     |   |            Entry 0                    |   |
+     |   |  ----------------------------------   |   |
+     |   |  |       Identifier String         |  |   |
+     |   |  |---------------------------------|  |   |
+     |   |  |       Data                      |  |   |
+     |   |  |---------------------------------|  |   |
+     |   |---------------------------------------|   |
+     |   -----------------------------------------   |
+     |   |            Entry 1                    |   |
+     |   |  ----------------------------------   |   |
+     |   |  |       Identifier String         |  |   |
+     |   |  |---------------------------------|  |   |
+     |   |  |       Data                      |  |   |
+     |   |  |---------------------------------|  |   |
+     |   |---------------------------------------|   |
+     |                      -                        |
+     |                      -                        |
+     |                      -                        |
+     |   -----------------------------------------   |
+     |   |            Entry N                    |   |
+     |   |  ----------------------------------   |   |
+     |   |  |       Identifier String         |  |   |
+     |   |  |---------------------------------|  |   |
+     |   |  |       Data                      |  |   |
+     |   |  |---------------------------------|  |   |
+     |   |---------------------------------------|   |
+      -----------------------------------------------
+
+                            Fig 2
+
+
+The header of each SMEM item contains metadata that describes the processors
+using the edge, the version information, and the entry count.  The constant
+identifier is used as a magic number to enable extraction of the items from a
+memory dump.  The size of each entry depends upon the version, but the number
+of total entries (and hence the size of each SMEM item) is configurable with a
+suggested value of 16.
+
+The number of valid entries is used to indicate how many of the Entries Total
+are currently used and are current valid.
+
+   ---------------------------------------------------------------------------
+  |Field        Size       Description                Valid Values            |
+   ---------------------------------------------------------------------------
+  | Identifier  4 Bytes    Value used to identify                             |
+  | Constant               structure in memory.     Must be set to $SMP       |
+  |                        Useful for debugging.    (0x504D5324)              |
+   ---------------------------------------------------------------------------
+  | Local       2 Bytes    Writing processor ID.    Refer Processor ID Table 3|
+  | Processor                                                                 |
+  | ID                                                                        |
+   ---------------------------------------------------------------------------
+  | Remote      2 Bytes    Reading processor ID.    Refer Processor ID Table 3|
+  | Processor                                                                 |
+  | ID                                                                        |
+   ---------------------------------------------------------------------------
+  | Version      1 Bytes   Refer to Version                                   |
+  | Number                 Feature Negotiation      Must be set to 1.         |
+  |                        section.                                           |
+   ---------------------------------------------------------------------------
+  | Feature      3 Bytes   Refer to Version                                   |
+  | flags                  and Feature Negotiation  Must be set to zero.      |
+  |                        section.                                           |
+   ---------------------------------------------------------------------------
+  | Entries      2 Bytes   Total number of          Must be 0 or greater.     |
+  | Total                  entries.                                           |
+   ---------------------------------------------------------------------------
+  | Entries      2 Bytes   Number of valid          Must be between 0         |
+  | Valid                  entries.                 and Entries Total.        |
+   ---------------------------------------------------------------------------
+  | Reserved     4 Bytes   Reserved                 Must be set to 0.         |
+   ---------------------------------------------------------------------------
+                           Table 1 - SMEM Item Header
+
+The content of each SMEM entries is described in Table 2 and consists of a
+string identifier and a 32-bit data value.  The string identifier must be
+unique for each SMEM item.  The data value is opaque to SMP2P giving the client
+complete flexibility as to its usage.
+
+   ----------------------- --------------------- -----------------------------
+  | Field      | Size     | Description         |      Valid Values           |
+   ------------|----------|---------------------|-----------------------------
+  |            |          |                     |                             |
+  | Identifier | 16 Bytes | Null Terminated     |     NON-NULL for            |
+  | String     |          | ASCII string.       |     valid entries.          |
+  |            |          |                     |                             |
+   ------------|----------|---------------------|-----------------------------
+  | Data       |  4 Bytes | Data                |     Any (client defined)    |
+   ------------ ---------- --------------------- -----------------------------
+                              Table 2 - Entry Format
+
+
+The processor IDs in the system are fixed and new processors IDs will be
+added to the end of the list (Table 3).
+
+              -------------------------------------------------
+             | Processor Name             |     ID value       |
+              -------------------------------------------------
+             | Application processor      |        0           |
+              -------------------------------------------------
+             | Modem processor            |        1           |
+              -------------------------------------------------
+             | Audio processor            |        2           |
+              -------------------------------------------------
+             | Sensor processor           |        3           |
+              -------------------------------------------------
+             | Wireless processor         |        4           |
+              -------------------------------------------------
+             | Modem Fw                   |        5           |
+              -------------------------------------------------
+             | Power processor            |        6           |
+              -------------------------------------------------
+             | NUM PROCESSORS             |        7           |
+              -------------------------------------------------
+                            Table 3 - Processor IDs
+
+SMEM Item
+---------
+The responsibility of creating an SMEM item is with the local processor that is
+initiating outbound traffic.  After creating the item, the local and remote
+processors negotiate the version and feature flags for the item to ensure
+compatibility.
+
+Table 4 lists the SMEM item base identifiers.  To get the SMEM item ID for a
+particular edge, the remote processor ID (Table 3) is added to the base item ID
+for the local processor (Table 4).  For example, the Apps ==> Modem (id 1) SMEM
+Item ID will be 427 + 1 = 428.
+
+          --------------------------------------------------
+         | Description                   | SMEM ID value    |
+          --------------------------------------------------
+         | Apps SMP2P SMEM Item base     |       427        |
+          --------------------------------------------------
+         | Modem SMP2P SMEM Item base    |       435        |
+          --------------------------------------------------
+         | Audio SMP2P SMEM Item base    |       443        |
+          --------------------------------------------------
+         | Wireless SMP2P SMEM Item base |       451        |
+          --------------------------------------------------
+         | Power SMP2P SMEM Item base    |       459        |
+          --------------------------------------------------
+                      Table 4 - SMEM Items Base IDs
+
+
+Version and Feature Negotiation
+-------------------------------
+To enable upgrading without breaking the system and to enable graceful feature
+fall-back support, SMP2P supports a version number and feature flags.  The
+combination of the version number and feature flags enable:
+ 1) SMP2P software updates to be rolled out to each processor separately.
+ 2) Individual features to be enabled or disabled per connection or edge.
+
+The version number represents any change in SMP2P that breaks compatibility
+between processors.  Examples would be a change in the shared data structures
+or changes to fundamental behavior.  Each implementation of SMP2P must be able
+to support a minimum of the current version and the previous version.
+
+The feature flags represent any changes in SMP2P that are optional and
+backwards compatible.  Endpoints will negotiate the supported flag when the
+SMEM items are created and they cannot be changed after negotiation has been
+completed.
+
+
+Negotiation Algorithm
+----------------------
+While creating the SMEM item the following algorithm shall be used.
+
+    if remote endpoint's SMEM Item exists
+        Read remote version number and flags
+        Local version number must be lower of
+            - remote version number
+            - highest supported local version number
+        Flags value is bitwise AND of
+            - remote feature flags
+            - locally supported flags
+        Create SMEM item and populate negotiated number and flags
+        Interrupt remote processor
+        if version and flags match, negotiation is complete, else wait
+        for remote interrupt below.
+    Else
+        Create SMEM item and populate it with highest supported version and any
+        requested feature flag.
+        Interrupt remote processor.
+        Wait for Interrupt below.
+
+Upon receiving the interrupt from remote processor and negotiation is not
+complete, check the version number and feature flags:
+    if equal, negotiation is complete.
+    if remote number is less than local number, and remote number is
+    supported:
+        Set local version number to remote version number
+        Bitwise AND local flags with remote flags
+        Interrupt remote processor
+        Negotiation is complete
+    if remote number is not supported, then negotiation has failed
+        Set version number to 0xFF and report failure in kernel log.
+    if remote number is more than local number:
+        Wait for remote endpoint to process our interrupt and negotiate down.
+
+
+Creating an SMEM Entry
+----------------------
+Each new SMEM entry used in data transfer must be created at the end of the
+entry array in the SMEM item and cannot be deleted until the system is
+rebooted.  The following sequence is be followed:
+    1) Compare Entries Valid and Entries Total to verify if there is room in the
+       entry array for this request (if not, return error code to client).
+    2) Populate the Identifier of new entry and do a write memory barrier.
+    3) Update Entries Valid and Entries Total and do a write memory barrier.
+    4) Interrupt remote endpoint.
+
+
+Entry Write
+-----------
+An entry write is achieved by the following sequence of operations:
+    1) Update data field in the entry and do a write memory barrier.
+    2) Interrupt remote endpoint.
+
+
+Entry Read / Receiving Interrupts
+---------------------------------
+An interrupt will be received from the remote system for one or more of the following events:
+    1) Initialization
+    2) Entry change
+    3) New Entry
+
+As long as the SMEM item initialization is complete, then each interrupt should
+trigger SMP2P to:
+    1) Compare valid entry data value to cached value and notify client if it
+       has changed.
+    2) Compare Entries Valid to cached value.  If changed, initialize new entries.
+
+Performance
+===========
+No performance issues are anticipated as the signaling rate is expected to be
+low and is performed in interrupt context which minimizes latency.
+
+Interfaces
+================
+SMP2P is only supported in the kernel and interfaces with clients through the
+GPIO and interrupt subsystems.
+
+To map an entry to the client, the client must add two nodes to the Device
+Tree:
+  1) A node that matches "qcom,smp2pgpio" to create the entry
+  2) A node that matches the client driver to provide the GPIO pin mapping
+
+The details of the device tree entries are contained in the file
+Documentionat/devicetree/bindings/arm/msm/smp2p.txt.
+
+
+    /* SMP2P Test Driver for inbound entry. */
+    smp2pgpio_smp2p_7_in: qcom,smp2pgpio-smp2p-7-in {
+        compatible = "qcom,smp2pgpio";
+        qcom,entry-name = "smp2p";
+        qcom,remote-pid = <7>;
+        qcom,is_inbound;
+        gpio-controller;
+        #gpio-cells = <2>;
+        interrupt-controller;
+        #interrupt-cells = <2>;
+    };
+
+    /* SMP2P Test Client for inbound entry. */
+    qcom,smp2pgpio_test_smp2p_7_in {
+        compatible = "qcom,smp2pgpio_test_smp2p_7_in";
+        gpios = <&smp2pgpio_smp2p_7_in 0 0>,
+            <&smp2pgpio_smp2p_7_in 1 0>,
+            . . .
+            <&smp2pgpio_smp2p_7_in 31 0>;
+    };
+
+    /* SMP2P Test Driver for outbound entries */
+    smp2pgpio_smp2p_345_out: qcom,smp2pgpio-smp2p-7-out {
+        compatible = "qcom,smp2pgpio";
+        qcom,entry-name = "smp2p";
+        qcom,remote-pid = <7>;
+        gpio-controller;
+        #gpio-cells = <2>;
+        interrupt-controller;
+        #interrupt-cells = <2>;
+    };
+
+    /* SMP2P Test Client for outbound entry. */
+    qcom,smp2pgpio_test_smp2p_7_out {
+        compatible = "qcom,smp2pgpio_test_smp2p_7_out";
+        gpios = <&smp2pgpio_smp2p_7_out 0 0>,
+            <&smp2pgpio_smp2p_7_out 1 0>,
+            . . .
+            <&smp2pgpio_smp2p_7_out 31 0>;
+
+The client can use a match entry for "qcom,smp2pgpio_test_smp2p_7_in" to
+retrieve the Device Tree configuration node.  Once that node has been
+retrieved, the client can call of_get_gpio() to get the virtual GPIO pin and
+also use gpio_to_irq() to map the GPIO pin to a virtual interrupt.  After that
+point, the standard GPIO and Interrupt APIs can be used to manipulate the SMP2P
+entries and receive notifications of changes.  Examples of typical function
+calls are shown below:
+    of_get_gpio()
+    gpio_get_value()
+    gpio_set_value()
+    gpio_to_irq()
+    request_irq()
+    free_irq()
+
+Please reference the unit test code for example usage.
+
+Debug
+=====
+The state values and names for all entries accessible by the Apps are
+accessible through debugfs nodes for general debug purposes.
+
+Debugfs entries for triggering unit-tests are also exported.
+
+Internal logging will be performed using the IPC Logging module to enable
+post-mortem analysis.
+
+Testing
+=======
+On-target unit testing will be done to verify internal functionality and the
+GPIO/IRQ API's.
+
+Driver parameters
+=================
+One module parameter will be provided to change the verbosity of internal logging.
+
+Config options
+==============
+Configuration of interrupts will be done using Device Tree.  By default, the
+testing components will be enabled since it does not affect performance and has
+a minimal impact on kernel size.  However, customers can disable the testing
+components for size optimization.
+
+    CONFIG_MSM_SMP2P - enables SMP2P core functionality
+    CONFIG_MSM_SMP2P_TEST - enables unit test support
+
+Dependencies
+===========
+Requires SMEM for creating the SMEM items.
+
+User Space utilities
+====================
+No userspace utilities are planned.
+
+Known issues
+============
+None.
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_tspp.txt b/Documentation/devicetree/bindings/arm/msm/msm_tspp.txt
new file mode 100644
index 0000000..2b5e143
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/msm_tspp.txt
@@ -0,0 +1,73 @@
+TSPP Driver
+
+For information on the TSPP driver, please refer to the TSPP driver
+documentation: Documentation/arm/msm/tspp.txt.
+
+The devicetree representation of the TSPP block should be:
+
+Required properties:
+
+- compatible: "qcom,msm_tspp"
+- cell-index: <0> - represents device ID.
+- reg: physical memory base addresses and sizes for the following:
+	TSIF0, TSIF1, TSPP and TSPP_BAM.
+- reg-names: names of the memory regions.
+- interrupts: represents IRQ numbers for the following:
+	TSIF_TSPP_IRQ, TSIF0_IRQ, TSIF1_IRQ, TSIF_BAM_IRQ.
+- interrupt-names: TSPP, TSIF and BAM interrupt names.
+- qcom,tsif-pclk: interface clock name.
+- qcom,tsif-ref-clk: reference clock name.
+	The driver uses clk_get to get the clocks by name. The clocks
+	should be defined in the relevant clock file (e.g. clock-8974.c).
+- gpios: GPIO numbers for TSIF0 (CLK, EN, DATA and SYNC) and TSIF1 (same).
+- qcom,gpio-names: GPIO names - strings describing the GPIO functionality.
+- qcom,gpios-func: GPIO functionality according to the GPIO functionality table.
+	GPIO pins can have more than a single functionality, and the TSPP driver
+	is responsible for configuring the GPIOs to work in TSIF functionality
+	based on this parameter.
+	Note: it is assumed that the functionality value (e.g. 1 in 8974 case)
+	is applicable to all TSIF GPIOs.
+
+Example (for 8974 platform, avaialble at msm8974.dtsi):
+
+	tspp: msm_tspp@f99d8000 {
+		compatible = "qcom,msm_tspp";
+		cell-index = <0>;
+		reg = <0xf99d8000 0x1000>, /* MSM_TSIF0_PHYS */
+		      <0xf99d9000 0x1000>, /* MSM_TSIF1_PHYS */
+		      <0xf99da000 0x1000>, /* MSM_TSPP_PHYS  */
+		      <0xf99c4000 0x14000>; /* MSM_TSPP_BAM_PHYS */
+		reg-names = "MSM_TSIF0_PHYS",
+			"MSM_TSIF1_PHYS",
+			"MSM_TSPP_PHYS",
+			"MSM_TSPP_BAM_PHYS";
+		interrupts = <0 153 0>, /* TSIF_TSPP_IRQ */
+			<0 151 0>, /* TSIF0_IRQ */
+			<0 152 0>, /* TSIF1_IRQ */
+			<0 154 0>; /* TSIF_BAM_IRQ */
+		interrupt-names = "TSIF_TSPP_IRQ",
+			"TSIF0_IRQ",
+			"TSIF1_IRQ",
+			"TSIF_BAM_IRQ";
+		qcom,tsif-pclk = "iface_clk";
+		qcom,tsif-ref-clk = "ref_clk";
+		gpios = <&msmgpio 89 0>, /* TSIF0 CLK  */
+			<&msmgpio 90 0>, /* TSIF0 EN   */
+			<&msmgpio 91 0>, /* TSIF0 DATA */
+			<&msmgpio 92 0>, /* TSIF0 SYNC */
+			<&msmgpio 93 0>, /* TSIF1 CLK  */
+			<&msmgpio 94 0>, /* TSIF1 EN   */
+			<&msmgpio 95 0>, /* TSIF1 DATA */
+			<&msmgpio 96 0>; /* TSIF1 SYNC */
+		qcom,gpio-names = "tsif_clk",
+				"tsif_en",
+				"tsif_data",
+				"tsif_sync",
+				"tsif_clk",
+				"tsif_en",
+				"tsif_data",
+				"tsif_sync";
+		qcom,gpios-func = <1>;
+	};
+
+
diff --git a/Documentation/devicetree/bindings/arm/msm/rpm-smd.txt b/Documentation/devicetree/bindings/arm/msm/rpm-smd.txt
index 8ebd3ba..7235a1a 100644
--- a/Documentation/devicetree/bindings/arm/msm/rpm-smd.txt
+++ b/Documentation/devicetree/bindings/arm/msm/rpm-smd.txt
@@ -20,6 +20,17 @@
 - rpm-channel-type: The interal SMD edge for this subsystem found in
 			<mach/msm_smd.h>
 
+Optional properties
+- rpm-standlone: Allow the driver to run in standalone mode. This is a
+			suggestion to the RPM driver and if the SMD
+			channel is made available for RPM, the driver
+			would continue to send requests to RPM processor,
+			but if the SMD channel is unavailable, driver will
+			return success even though the data is not sent
+			to the RPM processor. In the absence of this
+			option, the driver will fail if the SMD channel
+			is unavailable.
+
 Example:
 
 	qcom,rpm-smd {
diff --git a/Documentation/devicetree/bindings/arm/msm/smp2p.txt b/Documentation/devicetree/bindings/arm/msm/smp2p.txt
new file mode 100644
index 0000000..7a5f506
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/smp2p.txt
@@ -0,0 +1,21 @@
+Qualcomm SMSM Point-to-Point (SMP2P)
+
+Required properties:
+-compatible : should be "qcom,smp2p"
+-reg : the location and offset of the irq register base memory
+-reg-names : "irq-reg-base", "irq-reg-offset" - string to identify the irq
+             register region and offset values
+-qcom,remote-pid : the SMP2P remote processor ID (see smp2p_private_api.h)
+-qcom,irq-bitmask : the sending irq bitmask
+-interrupts : the receiving interrupt line
+
+Example:
+
+	qcom,smp2p-modem {
+		compatible = "qcom,smp2p";
+		reg = <0xfa006000 0x1000>, <0x8 0x0>;
+		reg-names = "irq-reg-base", "irq-reg-offset";
+		qcom,remote-pid = <1>;
+		qcom,irq-bitmask = <0x4000>;
+		interrupts = <0 27 1>;
+	};
diff --git a/Documentation/devicetree/bindings/gpio/gpio-smp2p.txt b/Documentation/devicetree/bindings/gpio/gpio-smp2p.txt
new file mode 100644
index 0000000..131c9d1
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/gpio-smp2p.txt
@@ -0,0 +1,77 @@
+Qualcomm SMSM Point-to-Point (SMP2P) GPIO Driver
+
+Used to map an SMP2P entry and remote processor ID to a virtual GPIO controller
+and virtual interrupt controller.
+
+Required properties:
+-compatible : should be "qcom,smp2pgpio";
+-qcom,entry-name : name of the SMP2P entry
+-qcom,remote-pid : the SMP2P remote processor ID (see smp2p_private_api.h)
+-gpio-controller : specifies that this is a GPIO controller
+-#gpio-cells : number of GPIO cells (should always be <2>)
+-interrupt-controller : specifies that this is an interrupt controller
+-#interrupt-cells : number of interrupt cells (should always be <2>)
+
+Optional properties:
+-qcom,is-inbound : specifies that this is an inbound entry (default is outbound)
+
+Comments:
+All device tree entries must be unique.  Therefore to prevent naming collisions
+between clients, it is recommended that the DT nodes should be named using the
+format:
+	smp2pgpio_<ENTRY_NAME>_<REMOTE PID>_<in|out>
+
+Example:
+	/* Maps inbound "smp2p" entry on remote PID 7 to GPIO controller. */
+	smp2pgpio_smp2p_7_in: qcom,smp2pgpio-smp2p-7-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <7>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	/*
+	 * Maps inbound "smp2p" entry on remote PID 7 to client driver
+	 * "qcom,smp2pgpio_test_smp2p_7_in".
+	 *
+	 * Note:  If all 32-pins are used by this client, then you
+	 *        can just list pin 0 here as a shortcut.
+	 */
+	qcom,smp2pgpio_test_smp2p_7_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_7_in";
+		gpios = <&smp2pgpio_smp2p_7_in 0 0>, /* pin 0 */
+			<&smp2pgpio_smp2p_7_in 1 0>,
+			. . .
+			<&smp2pgpio_smp2p_7_in 31 0>;    /* pin 31 */
+	};
+
+
+	/* Maps outbound "smp2p" entry on remote PID 7 to GPIO controller. */
+	smp2pgpio_smp2p_7_out: qcom,smp2pgpio-smp2p-7-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <7>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	/*
+	 * Maps outbound "smp2p" entry on remote PID 7 to client driver
+	 * "qcom,smp2pgpio_test_smp2p_7_out".
+	 *
+	 * Note:  If all 32-pins are used by this client, then you
+	 *        can just list pin 0 here as a shortcut.
+	 */
+	qcom,smp2pgpio_test_smp2p_7_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_7_out";
+		gpios = <&smp2pgpio_smp2p_7_out 0 0>, /* pin 0 */
+			<&smp2pgpio_smp2p_7_out 1 0>,
+			. . .
+			<&smp2pgpio_smp2p_7_out 31 0>;    /* pin 31 */
+	};
diff --git a/Documentation/devicetree/bindings/media/video/msm-vidc.txt b/Documentation/devicetree/bindings/media/video/msm-vidc.txt
index 2f2ea22..6af445b 100644
--- a/Documentation/devicetree/bindings/media/video/msm-vidc.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-vidc.txt
@@ -3,6 +3,11 @@
 Required properties:
 - compatible : one of:
 	- "qcom,msm-vidc"
+- hfi : supported Host-Firmware Interface, one of:
+        - "venus"
+        - "q6"
+
+Optional properties:
 - reg : offset and length of the register set for the device.
 - interrupts : should contain the vidc interrupt.
 - vidc-cp-map : start and size of device virtual address range for secure buffers.
@@ -13,9 +18,6 @@
   or non-secure.
 - load-freq-tbl : load (in macroblocks/sec) and corresponding vcodec clock
   required for optimal performance in descending order.
-- hfi : supported Host-Firmware Interface, one of:
-	- "venus"
-	- "q6"
 
 Example:
 
diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
index 5bef9b8..22e43ab 100644
--- a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
@@ -20,6 +20,8 @@
 		      images and self-authentication is not desired;
 		      <1> if the hardware requires self-authenticating images.
 - qcom,is-loadable:   if PIL is required to load the modem image
+- qcom,gpio-err-fatal: GPIO used by the modem to indicate error fatal to the apps.
+- qcom,gpio-force-stop: GPIO used by the apps to force the modem to shutdown.
 
 Example:
 	qcom,mss@fc880000 {
@@ -38,4 +40,10 @@
 		qcom,is-loadable;
 		qcom,firmware-name = "mba";
 		qcom,pil-self-auth = <1>;
+
+		/* GPIO inputs from mss */
+		gpio_err_fatal = <&smp2pgpio_ssr_smp2p_1_in 0 0>;
+
+		/* GPIO output to mss */
+		gpio_force_stop = <&smp2pgpio_ssr_smp2p_1_out 0 0>;
 	};
diff --git a/Documentation/devicetree/bindings/regulator/krait-regulator.txt b/Documentation/devicetree/bindings/regulator/krait-regulator.txt
index fddae80..e3da903 100644
--- a/Documentation/devicetree/bindings/regulator/krait-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/krait-regulator.txt
@@ -2,7 +2,12 @@
 
 Required properties:
 - compatible:			Must be "qcom,krait-regulator"
-- reg:				Specifies the address and size for this regulator device
+- reg:				Specifies the address and size for this regulator device,
+				also specifies the address and the size for the MDD area
+				to be used along with the regulator
+- reg-names:			"acs" -string to identify the area where main power control
+					registers reside.
+				"mdd" - string to identify the area where mdd registers reside.
 - qcom,headroom-voltage:	The minimum required voltage drop between the input
 			 	voltage and the output voltage for the LDO to be
 			 	operational, in microvolts
@@ -17,7 +22,9 @@
 	krait0_vreg: regulator@f9088000 {
 		compatible = "qcom,krait-regulator";
 		regulator-name = "krait0";
-		reg = <0xf9088000 0x1000>;
+		reg = <0xf9088000 0x1000>, /* APCS_ALIAS0_KPSS_ACS */
+			<0xf908a800 0x1000>; /* APCS_ALIAS0_KPSS_MDD */
+		reg-names = "acs", "mdd";
 		regulator-min-microvolt = <500000>;
 		regulator-max-microvolt = <1100000>;
 		qcom,headroom-voltage = <150000>;
@@ -25,3 +32,4 @@
 		qcom,ldo-default-voltage = <745000>;
 		qcom,ldo-threshold-voltage = <750000>;
 	};
+
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 3d022a3..925c8eb 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -85,9 +85,11 @@
  - qcom,msm-dai-q6-dev-id : The slimbus multi channel port ID
                             Value is from 16384 to 16393
                             BT SCO port ID value from 12288 to 12289
-                            RT Proxy port ID values from 224 to 225 and 240 to 241
+                            RT Proxy port ID values from 224 to 225 and 240 to
+			    241
                             FM Rx and TX port ID values from 12292 to 12293
-                            incall record Rx and TX port ID values from 32771 to 32772
+                            incall record Rx and TX port ID values from 32771 to
+			    32772
 
 * msm-auxpcm
 
@@ -161,22 +163,24 @@
 
  - qcom,msm_bus,num_cases:                 Total number of use cases
 
- - qcom,msm_bus,active_only:               Context flag for requests in active or
-                                           dual (active & sleep) contex
+ - qcom,msm_bus,active_only:               Context flag for requests in active
+					   or dual (active & sleep) contex
 
  - qcom,msm_bus,num_paths:                 Total number of master-slave pairs
 
- - qcom,msm_bus,vectors:                   Arrays of unsigned integers representing:
-                                           master-id, slave-id, arbitrated bandwidth,
-                                           instantaneous bandwidth
+ - qcom,msm_bus,vectors:                   Arrays of unsigned integers
+					   representing:
+					       master-id, slave-id, arbitrated
+					       bandwidth,
+					       instantaneous bandwidth
 * wcd9xxx_intc
 
 Required properties:
 
  - compatible :                            "qcom,wcd9xxx-irq"
 
- - interrupt-controller :                  Mark this device node as an interrupt
-                                           controller
+ - interrupt-controller :                  Mark this device node as an
+					   interrupt controller
 
  - #interrupt-cells :                      Should be 1
 
@@ -442,25 +446,34 @@
 Required properties:
 
  - compatible : "qcom,msm-dai-q6-mi2s"
- - qcom,msm-dai-q6-mi2s-dev-id: MSM or MDM can use Slimbus or I2S interface to transfer data
-								to (WCD9XXX) codec. If slimbus interface is used then
-								"msm-dai-q6" needs to be filled with correct data for slimbus
-								interface. The sections "msm-dai-mi2s" is used by MDM or MSM
-								to use I2S interface with codec. This section is used by CPU
-								driver in ASOC MSM to configure MI2S interface. MSM internally
-								has multiple MI2S namely Primary, Secondary, Tertiary and
-								Quaternary MI2S. They are represented with id 0, 1, 2, 3
-								respectively. The field "qcom,msm-dai-q6-mi2s-dev-id" represents
-								which of the MI2S block is used. These MI2S are connected to I2S
-								interface.
+ - qcom,msm-dai-q6-mi2s-dev-id: MSM or MDM can use Slimbus or I2S interface to
+				transfer data to (WCD9XXX) codec.
+				If slimbus interface is used then "msm-dai-q6"
+				needs to be filled with correct data for
+				slimbus interface.
+				The sections "msm-dai-mi2s" is used by MDM or
+				MSM to use I2S interface with codec.
+				This section is used by CPU driver in ASOC MSM
+				to configure MI2S interface. MSM internally
+				has multiple MI2S namely Primary, Secondary,
+				Tertiary and Quaternary MI2S.
+				They are represented with id 0, 1, 2, 3
+				respectively.
+				The field "qcom,msm-dai-q6-mi2s-dev-id"
+				represents which of the MI2S block is used.
+				These MI2S are connected to I2S interface.
 
- - qcom,msm-mi2s-rx-lines:		Each MI2S interface in MSM has one or more SD lines. These lines
-								are used for data transfer between codec and MSM. This element in
-								indicates which output RX lines are used in the MI2S interface.
+ - qcom,msm-mi2s-rx-lines:	Each MI2S interface in MSM has one or more SD
+				lines. These lines are used for data transfer
+				between codec and MSM.
+				This element in indicates which output RX lines
+				are used in the MI2S interface.
 
- - qcom,msm-mi2s-tx-lines:  	Each MI2S interface in MSM has one or more SD lines. These lines
-								are used for data transfer between codec and MSM. This element in
-								indicates which input TX lines are used in the MI2S interface.
+ - qcom,msm-mi2s-tx-lines:  	Each MI2S interface in MSM has one or more SD
+				lines. These lines are used for data transfer
+				between codec and MSM.
+				This element in indicates which input TX lines
+				are used in the MI2S interface.
 
 Example:
 
@@ -540,9 +553,9 @@
 	It is possible that some MSM use PIL to load the ADSP image. While
 	other MSM may use SBL to load the ADSP image at boot. Audio APR needs
 	state of ADSP to register and enable APR to be used for sending commands
-	to ADSP. so adsp-state represents the state of ADSP to ADSP loader. Value
-	of 0 indicates ADSP loader needs to use PIL and value of 2 means ADSP
-	image is already loaded by SBL.
+	to ADSP. so adsp-state represents the state of ADSP to ADSP loader.
+	Value of 0 indicates ADSP loader needs to use PIL and value of 2 means
+	ADSP image is already loaded by SBL.
 
 Example:
 
diff --git a/Documentation/devicetree/bindings/sound/taiko_codec.txt b/Documentation/devicetree/bindings/sound/taiko_codec.txt
index 74c25a0..989bea8 100644
--- a/Documentation/devicetree/bindings/sound/taiko_codec.txt
+++ b/Documentation/devicetree/bindings/sound/taiko_codec.txt
@@ -8,33 +8,39 @@
   - qcom,cdc-reset-gpio: gpio used for codec SOC reset.
 
   - <supply-name>-supply: phandle to the regulator device tree node
-  - qcom,<supply-name>-voltage -  specifies voltage levels for supply. Should be
-       specified in pairs (min, max), units mV.
+  - qcom,<supply-name>-voltage - specifies voltage levels for supply.
+      Should be specified in pairs (min, max), units mV.
   - qcom,<supply-name>-current - specifies max current in mA that can drawn
-       from the <supply-name>.
+      from the <supply-name>.
 
-    above three properties with "supply-name" set to  "qcom,cdc-vdd-buck", "qcom,cdc-vdd-tx-h",
-     "qcom,cdc-vdd-rx-h", "qcom,cdc-vddpx-1", "qcom,cdc-vdd-a-1p2v", "qcom,cdc-vddcx-1",
-     "qcom,cdc-vddcx-2" should be present.
+    above three properties with "supply-name" set to "qcom,cdc-vdd-buck",
+        "qcom,cdc-vdd-tx-h", "qcom,cdc-vdd-rx-h", "qcom,cdc-vddpx-1",
+	"qcom,cdc-vdd-a-1p2v", "qcom,cdc-vddcx-1", "qcom,cdc-vddcx-2"
+	should be present.
 
- - qcom,cdc-micbias-ldoh-v - LDOH output in volts ( should be 1.95 V and 3.00 V).
+ - qcom,cdc-micbias-ldoh-v - LDOH output in volts (should be 1.95 V and 3.00 V).
 
  - qcom,cdc-micbias-cfilt1-mv - cfilt1 output voltage in milli volts.
  - qcom,cdc-micbias-cfilt2-mv - cfilt2 output voltage in milli volts.
  - qcom,cdc-micbias-cfilt3-mv - cfilt3 output voltage in milli volts.
    cfilt voltage can be set to max of qcom,cdc-micbias-ldoh-v - 0.15V.
 
- - qcom,cdc-micbias1-cfilt-sel = cfilt to use for micbias1 (should be from 1 to 3).
- - qcom,cdc-micbias2-cfilt-sel = cfilt to use for micbias2 (should be from 1 to 3).
- - qcom,cdc-micbias3-cfilt-sel = cfilt to use for micbias3 (should be from 1 to 3).
- - qcom,cdc-micbias4-cfilt-sel = cfilt to use for micbias4 (should be from 1 to 3).
+ - qcom,cdc-micbias1-cfilt-sel = cfilt to use for micbias1
+				 (should be from 1 to 3).
+ - qcom,cdc-micbias2-cfilt-sel = cfilt to use for micbias2
+				 (should be from 1 to 3).
+ - qcom,cdc-micbias3-cfilt-sel = cfilt to use for micbias3
+				 (should be from 1 to 3).
+ - qcom,cdc-micbias4-cfilt-sel = cfilt to use for micbias4
+				 (should be from 1 to 3).
    This value represents the connected CFLIT to MIC Bias.
 
  - qcom,cdc-micbias1-ext-cap: Boolean. Enable micbias 1 external capacitor mode.
  - qcom,cdc-micbias2-ext-cap: Boolean. Enable micbias 2 external capacitor mode.
  - qcom,cdc-micbias3-ext-cap: Boolean. Enable micbias 3 external capacitor mode.
  - qcom,cdc-micbias4-ext-cap: Boolean. Enable micbias 4 external capacitor mode.
- - qcom,cdc-mclk-clk-rate - Specifies the master clock rate in Hz required for codec.
+ - qcom,cdc-mclk-clk-rate - Specifies the master clock rate in Hz required for
+			    codec.
  - qcom,cdc-slim-ifd-dev - namme of the codec slim interface device.
  - qcom,cdc-slim-ifd-elemental-addr - codec slimbus slave interface device
 				     enumeration address.
@@ -97,33 +103,39 @@
   - reg: represents the slave address provided to the I2C driver.
   - qcom,cdc-reset-gpio: gpio used for codec SOC reset.
   - <supply-name>-supply: phandle to the regulator device tree node.
-  - qcom,<supply-name>-voltage -  specifies voltage levels for supply. Should be
-       specified in pairs (min, max), units mV.
+  - qcom,<supply-name>-voltage -  specifies voltage levels for supply.
+      Should be specified in pairs (min, max), units mV.
   - qcom,<supply-name>-current - specifies max current in mA that can drawn
-       from the <supply-name>.
+      from the <supply-name>.
 
-    above three properties with "supply-name" set to  "qcom,cdc-vdd-buck", "qcom,cdc-vdd-tx-h",
-     "qcom,cdc-vdd-rx-h", "qcom,cdc-vddpx-1", "qcom,cdc-vdd-a-1p2v", "qcom,cdc-vddcx-1",
-     "qcom,cdc-vddcx-2" should be present.
+    above three properties with "supply-name" set to  "qcom,cdc-vdd-buck",
+    "qcom,cdc-vdd-tx-h", "qcom,cdc-vdd-rx-h", "qcom,cdc-vddpx-1",
+    "qcom,cdc-vdd-a-1p2v", "qcom,cdc-vddcx-1", "qcom,cdc-vddcx-2"
+    should be present.
 
- - qcom,cdc-micbias-ldoh-v - LDOH output in volts ( should be 1.95 V and 3.00 V).
+ - qcom,cdc-micbias-ldoh-v - LDOH output in volts (should be 1.95 V and 3.00 V).
 
  - qcom,cdc-micbias-cfilt1-mv - cfilt1 output voltage in milli volts.
  - qcom,cdc-micbias-cfilt2-mv - cfilt2 output voltage in milli volts.
  - qcom,cdc-micbias-cfilt3-mv - cfilt3 output voltage in milli volts.
    cfilt voltage can be set to max of qcom,cdc-micbias-ldoh-v - 0.15V.
 
- - qcom,cdc-micbias1-cfilt-sel = cfilt to use for micbias1 (should be from 1 to 3).
- - qcom,cdc-micbias2-cfilt-sel = cfilt to use for micbias2 (should be from 1 to 3).
- - qcom,cdc-micbias3-cfilt-sel = cfilt to use for micbias3 (should be from 1 to 3).
- - qcom,cdc-micbias4-cfilt-sel = cfilt to use for micbias4 (should be from 1 to 3).
+ - qcom,cdc-micbias1-cfilt-sel = cfilt to use for micbias1
+     (should be from 1 to 3).
+ - qcom,cdc-micbias2-cfilt-sel = cfilt to use for micbias2
+     (should be from 1 to 3).
+ - qcom,cdc-micbias3-cfilt-sel = cfilt to use for micbias3
+     (should be from 1 to 3).
+ - qcom,cdc-micbias4-cfilt-sel = cfilt to use for micbias4
+     (should be from 1 to 3).
    This value represents the connected CFLIT to MIC Bias.
 
  - qcom,cdc-micbias1-ext-cap: Boolean. Enable micbias 1 external capacitor mode.
  - qcom,cdc-micbias2-ext-cap: Boolean. Enable micbias 2 external capacitor mode.
  - qcom,cdc-micbias3-ext-cap: Boolean. Enable micbias 3 external capacitor mode.
  - qcom,cdc-micbias4-ext-cap: Boolean. Enable micbias 4 external capacitor mode.
- - qcom,cdc-mclk-clk-rate - Specifies the master clock rate in Hz required for codec.
+ - qcom,cdc-mclk-clk-rate - Specifies the master clock rate in Hz required for
+			    codec.
 
 Example:
 i2c@f9925000 {
@@ -143,7 +155,8 @@
 		reg = <0x0d>;
 		qcom,cdc-reset-gpio = <&msmgpio 22 0>;
 		interrupt-parent = <&wcd9xxx_intc>;
-		interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28>;
+		interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
+			      20 21 22 23 24 25 26 27 28>;
 
 		cdc-vdd-buck-supply = <&pm8019_l11>;
 		qcom,cdc-vdd-buck-voltage = <1800000 1800000>;
diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
index 8b7b31b..2cb2182 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -75,6 +75,34 @@
 				<87 512 60000000 960000000>;
 	};
 
+MSM HSUSB EHCI controller
+
+Required properties :
+- compatible : should be "qcom,ehci-host"
+- reg : offset and length of the register set in the memory map
+- interrupts: IRQ lines used by this controller
+- interrupt-names : Required interrupt resource entries are:
+            HSUSB EHCI expects "core_irq" and optionally "async_irq".
+- <supply-name>-supply: handle to the regulator device tree node
+  Required "supply-name" is "HSUSB_VDDCX" "HSUSB_1p8-supply" "HSUSB_3p3-supply".
+- qcom,usb2-power-budget: maximum vbus power (in mA) that can be provided.
+
+Optional properties :
+- qcom,usb2-enable-hsphy2: If present, select second PHY for USB operation.
+
+Example MSM HSUSB EHCI controller device node :
+	ehci: qcom,ehci-host@f9a55000 {
+		compatible = "qcom,ehci-host";
+		reg = <0xf9a55000 0x400>;
+		interrupts = <0 134 0>, <0 140 0>;
+		interrupt-names = "core_irq", "async_irq";
+		HSUSB_VDDCX-supply = <&pm8841_s2>;
+		HSUSB_1p8-supply = <&pm8941_l6>;
+		HSUSB_3p3-supply = <&pm8941_l24>;
+		qcom,usb2-enable-hsphy2;
+		qcom,usb2-power-budget = <500>;
+	};
+
 ANDROID USB:
 
 Required properties:
@@ -154,6 +182,8 @@
 Optional properties :
 - qcom,ignore-core-reset-ack: If present then BAM ignores ACK from USB core
 	    while performing PIPE RESET
+- qcom,disable-clk-gating: If present then disable BAM clock gating.
+
 
 Example USB BAM controller device node:
 
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index 5aecb48..2d4a6db 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -1098,6 +1098,11 @@
 	Functional default: enabled if accept_ra is enabled.
 			    disabled if accept_ra is disabled.
 
+accept_ra_prefix_route - BOOLEAN
+	Set the prefix route for the autoconfigured interface address
+
+	Functional default: enabled
+
 accept_redirects - BOOLEAN
 	Accept Redirects.
 
diff --git a/arch/arm/boot/dts/msm8226-pm.dtsi b/arch/arm/boot/dts/msm8226-pm.dtsi
new file mode 100644
index 0000000..e107b36
--- /dev/null
+++ b/arch/arm/boot/dts/msm8226-pm.dtsi
@@ -0,0 +1,402 @@
+/* Copyright (c) 2013 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+	qcom,spm@f9089000 {
+		compatible = "qcom,spm-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xf9089000 0x1000>;
+		qcom,core-id = <0>;
+		qcom,saw2-ver-reg = <0xfd0>;
+		qcom,saw2-cfg = <0x01>;
+		qcom,saw2-spm-dly= <0x20000400>;
+		qcom,saw2-spm-ctl = <0x1>;
+		qcom,saw2-spm-cmd-wfi = [60 03 60 76 76 0b 0f];
+		qcom,saw2-spm-cmd-spc = [00 20 10 80 90 5b 60 03 60 3b 76 76 94
+				5b 80 10 2b 30 06 26 30 0f];
+		qcom,saw2-spm-cmd-pc = [00 20 10 80 90 5b 60 07 3b 76 76 0b 94
+				5b 80 10 2b 30 06 26 30 0f];
+	};
+
+	qcom,spm@f9099000 {
+		compatible = "qcom,spm-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xf9099000 0x1000>;
+		qcom,core-id = <1>;
+		qcom,saw2-ver-reg = <0xfd0>;
+		qcom,saw2-cfg = <0x01>;
+		qcom,saw2-spm-dly= <0x20000400>;
+		qcom,saw2-spm-ctl = <0x1>;
+		qcom,saw2-spm-cmd-wfi = [60 03 60 76 76 0b 0f];
+		qcom,saw2-spm-cmd-spc = [00 20 10 80 90 5b 60 03 60 3b 76 76 94
+				5b 80 10 2b 30 06 26 30 0f];
+		qcom,saw2-spm-cmd-pc = [00 20 10 80 90 5b 60 07 3b 76 76 0b 94
+				5b 80 10 2b 30 06 26 30 0f];
+	};
+
+	qcom,spm@f90a9000 {
+		compatible = "qcom,spm-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xf90a9000 0x1000>;
+		qcom,core-id = <2>;
+		qcom,saw2-ver-reg = <0xfd0>;
+		qcom,saw2-cfg = <0x01>;
+		qcom,saw2-spm-dly= <0x20000400>;
+		qcom,saw2-spm-ctl = <0x1>;
+		qcom,saw2-spm-cmd-wfi = [60 03 60 76 76 0b 0f];
+		qcom,saw2-spm-cmd-spc = [00 20 10 80 90 5b 60 03 60 3b 76 76 94
+				5b 80 10 2b 30 06 26 30 0f];
+		qcom,saw2-spm-cmd-pc = [00 20 10 80 90 5b 60 07 3b 76 76 0b 94
+				5b 80 10 2b 30 06 26 30 0f];
+	};
+
+	qcom,spm@f90b9000 {
+		compatible = "qcom,spm-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xf90b9000 0x1000>;
+		qcom,core-id = <3>;
+		qcom,saw2-ver-reg = <0xfd0>;
+		qcom,saw2-cfg = <0x01>;
+		qcom,saw2-spm-dly= <0x20000400>;
+		qcom,saw2-spm-ctl = <0x1>;
+		qcom,saw2-spm-cmd-wfi = [60 03 60 76 76 0b 0f];
+		qcom,saw2-spm-cmd-spc = [00 20 10 80 90 5b 60 03 60 3b 76 76 94
+				5b 80 10 2b 30 06 26 30 0f];
+		qcom,saw2-spm-cmd-pc = [00 20 10 80 90 5b 60 07 3b 76 76 0b 94
+				5b 80 10 2b 30 06 26 30 0f];
+	};
+
+	qcom,spm@f9012000 {
+		compatible = "qcom,spm-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xf9012000 0x1000>;
+		qcom,core-id = <0xffff>; /* L2/APCS SAW */
+		qcom,saw2-ver-reg = <0xfd0>;
+		qcom,saw2-cfg = <0x14>;
+		qcom,saw2-spm-dly= <0x20000400>;
+		qcom,saw2-spm-ctl = <0x1>;
+		qcom,saw2-pmic-data0 = <0x02030080>;
+		qcom,saw2-pmic-data1 = <0x00030000>;
+		qcom,vctl-timeout-us = <50>;
+		qcom,vctl-port = <0x0>;
+		qcom,phase-port = <0x1>;
+		qcom,pfm-port = <0x2>;
+		qcom,saw2-spm-cmd-ret = [0b 00 03 00 7b 0f];
+		qcom,saw2-spm-cmd-gdhs = [00 20 32 60 70 80 0b 6b c0 e0 d0 42 07
+				78 1f 80 4e d0 e0 c0 22 6b 50 4b 60 02 32 50 7b
+				0f];
+		qcom,saw2-spm-cmd-pc = [00 32 60 70 80 b0 0b 10 e0 d0 6b c0
+				42 f0 11 07 01 b0 78 1f 80 4e c0 d0 12 e0 6b 50 4b
+				60 02 32 50 f0 7b 0f]; /*APCS_PMIC_OFF_L2RAM_OFF*/
+	};
+
+	qcom,lpm-resources {
+		compatible = "qcom,lpm-resources";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		qcom,lpm-resources@0 {
+			reg = <0x0>;
+			qcom,name = "vdd-dig";
+			qcom,resource-type = <0>;
+			qcom,type = <0x62706d73>;	/* "smpb" */
+			qcom,id = <0x02>;
+			qcom,key = <0x6e726f63>;	/* "corn" */
+			qcom,init-value = <5>;		/* Super Turbo */
+		};
+
+		qcom,lpm-resources@1 {
+			reg = <0x1>;
+			qcom,name = "vdd-mem";
+			qcom,resource-type = <0>;
+			qcom,type = <0x62706d73>;	/* "smpb" */
+			qcom,id = <0x01>;
+			qcom,key = <0x7675>;		/* "uv" */
+			qcom,init-value = <1050000>;	/* Super Turbo */
+		};
+
+		qcom,lpm-resources@2 {
+			reg = <0x2>;
+			qcom,name = "pxo";
+			qcom,resource-type = <0>;
+			qcom,type = <0x306b6c63>;	/* "clk0" */
+			qcom,id = <0x00>;
+			qcom,key = <0x62616e45>;	/* "Enab" */
+			qcom,init-value = <1>;		/* On */
+		};
+
+		qcom,lpm-resources@3 {
+			reg = <0x3>;
+			qcom,name = "l2";
+			qcom,resource-type = <1>;
+			qcom,init-value = <2>;		/* Retention */
+		};
+	};
+
+	qcom,lpm-levels {
+		compatible = "qcom,lpm-levels";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		qcom,lpm-level@0 {
+			reg = <0x0>;
+			qcom,mode = <0>;        /* MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT */
+			qcom,xo = <1>;          /* ON */
+			qcom,l2 = <3>;          /* ACTIVE */
+			qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
+			qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
+			qcom,vdd-dig-upper-bound = <5>; /* MAX */
+			qcom,vdd-dig-lower-bound = <3>;  /* ACTIVE */
+			qcom,latency-us = <1>;
+			qcom,ss-power = <784>;
+			qcom,energy-overhead = <190000>;
+			qcom,time-overhead = <100>;
+		};
+
+		qcom,lpm-level@1 {
+			reg = <0x1>;
+			qcom,mode = <4>;        /* MSM_PM_SLEEP_MODE_RETENTION*/
+			qcom,xo = <1>;          /* ON */
+			qcom,l2 = <3>;          /* ACTIVE */
+			qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
+			qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
+			qcom,vdd-dig-upper-bound = <5>; /* MAX */
+			qcom,vdd-dig-lower-bound = <3>;  /* ACTIVE */
+			qcom,latency-us = <75>;
+			qcom,ss-power = <735>;
+			qcom,energy-overhead = <77341>;
+			qcom,time-overhead = <105>;
+		};
+
+
+		qcom,lpm-level@2 {
+			reg = <0x2>;
+			qcom,mode = <2>;        /* MSM_PM_SLEEP_MODE_STANDALONE_POWER_COLLAPSE */
+			qcom,xo = <1>;          /* ON */
+			qcom,l2 = <3>;          /* ACTIVE */
+			qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
+			qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
+			qcom,vdd-dig-upper-bound = <5>; /* MAX */
+			qcom,vdd-dig-lower-bound = <3>;  /* ACTIVE */
+			qcom,latency-us = <95>;
+			qcom,ss-power = <725>;
+			qcom,energy-overhead = <99500>;
+			qcom,time-overhead = <130>;
+		};
+
+		qcom,lpm-level@3 {
+			reg = <0x3>;
+			qcom,mode = <3>;        /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+			qcom,xo = <1>;          /* ON */
+			qcom,l2 = <1>;          /* GDHS */
+			qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
+			qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
+			qcom,vdd-dig-upper-bound = <5>; /* MAX */
+			qcom,vdd-dig-lower-bound = <3>;  /* ACTIVE */
+			qcom,latency-us = <2000>;
+			qcom,ss-power = <138>;
+			qcom,energy-overhead = <1208400>;
+			qcom,time-overhead = <3200>;
+		};
+
+		qcom,lpm-level@4 {
+			reg = <0x4>;
+			qcom,mode = <3>;        /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+			qcom,xo = <1>;          /* ON */
+			qcom,l2 = <0>;          /* OFF */
+			qcom,vdd-mem-upper-bound = <1050000>; /* ACTIVE */
+			qcom,vdd-mem-lower-bound = <750000>;  /* RETENTION HIGH */
+			qcom,vdd-dig-upper-bound = <3>;  /* ACTIVE */
+			qcom,vdd-dig-lower-bound = <2>;  /* RETENTION HIGH */
+			qcom,latency-us = <3000>;
+			qcom,ss-power = <110>;
+			qcom,energy-overhead = <1250300>;
+			qcom,time-overhead = <3500>;
+		};
+
+		qcom,lpm-level@5 {
+			reg = <0x5>;
+			qcom,mode = <3>;        /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+			qcom,xo = <0>;          /* OFF */
+			qcom,l2 = <1>;          /* GDHS */
+			qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
+			qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
+			qcom,vdd-dig-upper-bound = <5>; /* MAX */
+			qcom,vdd-dig-lower-bound = <3>;  /* ACTIVE */
+			qcom,latency-us = <3000>;
+			qcom,ss-power = <68>;
+			qcom,energy-overhead = <1350200>;
+			qcom,time-overhead = <4000>;
+		};
+
+		qcom,lpm-level@6 {
+			reg = <0x6>;
+			qcom,mode = <3>;        /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+			qcom,xo = <0>;          /* OFF */
+			qcom,l2 = <0>;          /* OFF */
+			qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
+			qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
+			qcom,vdd-dig-upper-bound = <5>; /* MAX */
+			qcom,vdd-dig-lower-bound = <3>;  /* ACTIVE */
+			qcom,latency-us = <10300>;
+			qcom,ss-power = <63>;
+			qcom,energy-overhead = <2128000>;
+			qcom,time-overhead = <18200>;
+		};
+
+		qcom,lpm-level@7 {
+			reg = <0x7>;
+			qcom,mode= <3>;         /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+			qcom,xo = <0>;          /* OFF */
+			qcom,l2 = <0>;          /* OFF */
+			qcom,vdd-mem-upper-bound = <1050000>; /* ACTIVE */
+			qcom,vdd-mem-lower-bound = <750000>;  /* RETENTION HIGH */
+			qcom,vdd-dig-upper-bound = <3>;  /* ACTIVE */
+			qcom,vdd-dig-lower-bound = <2>;  /* RETIONTION HIGH */
+			qcom,latency-us = <18000>;
+			qcom,ss-power = <10>;
+			qcom,energy-overhead = <3202600>;
+			qcom,time-overhead = <27000>;
+		};
+
+		qcom,lpm-level@8 {
+			reg = <0x8>;
+			qcom,mode= <3>;         /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+			qcom,xo = <0>;          /* OFF */
+			qcom,l2 = <0>;          /* OFF */
+			qcom,vdd-mem-upper-bound = <750000>; /* RETENTION HIGH */
+			qcom,vdd-mem-lower-bound = <750000>; /* RETENTION LOW */
+			qcom,vdd-dig-upper-bound = <2>; /* RETENTION HIGH */
+			qcom,vdd-dig-lower-bound = <0>; /* RETENTION LOW */
+			qcom,latency-us = <20000>;
+			qcom,ss-power = <2>;
+			qcom,energy-overhead = <4252000>;
+			qcom,time-overhead = <32000>;
+		};
+	};
+
+	qcom,pm-boot {
+		compatible = "qcom,pm-boot";
+		qcom,mode = <0>; /* MSM_PM_BOOT_CONFIG_TZ */
+	};
+
+	qcom,mpm@fc4281d0 {
+		compatible = "qcom,mpm-v2";
+		reg = <0xfc4281d0 0x1000>, /* MSM_RPM_MPM_BASE 4K */
+		    <0xf9011008 0x4>;   /* MSM_APCS_GCC_BASE 4K */
+		reg-names = "vmpm", "ipc";
+		interrupts = <0 171 1>;
+
+		qcom,ipc-bit-offset = <1>;
+
+		qcom,gic-parent = <&intc>;
+		qcom,gic-map = <47 172>, /* usb2_hsic_async_wakeup_irq */
+			<53 104>, /* mdss_irq */
+			<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
+			<0xff 57>,  /* mss_to_apps_irq(0) */
+			<0xff 58>,  /* mss_to_apps_irq(1) */
+			<0xff 59>,  /* mss_to_apps_irq(2) */
+			<0xff 60>,  /* mss_to_apps_irq(3) */
+			<0xff 173>, /* o_wcss_apss_smd_hi */
+			<0xff 174>, /* o_wcss_apss_smd_med */
+			<0xff 175>, /* o_wcss_apss_smd_low */
+			<0xff 176>, /* o_wcss_apss_smsm_irq */
+			<0xff 177>, /* o_wcss_apss_wlan_data_xfer_done */
+			<0xff 178>, /* o_wcss_apss_wlan_rx_data_avail */
+			<0xff 179>, /* o_wcss_apss_asic_intr
+
+			<0xff 188>, /* lpass_irq_out_apcs(0) */
+			<0xff 189>, /* lpass_irq_out_apcs(1) */
+			<0xff 190>, /* lpass_irq_out_apcs(2) */
+			<0xff 191>, /* lpass_irq_out_apcs(3) */
+			<0xff 192>, /* lpass_irq_out_apcs(4) */
+			<0xff 193>, /* lpass_irq_out_apcs(5) */
+			<0xff 194>, /* lpass_irq_out_apcs(6) */
+			<0xff 195>, /* lpass_irq_out_apcs(7) */
+			<0xff 196>, /* lpass_irq_out_apcs(8) */
+			<0xff 197>, /* lpass_irq_out_apcs(9) */
+			<0xff 200>, /* rpm_ipc(4) */
+			<0xff 201>, /* rpm_ipc(5) */
+			<0xff 202>, /* rpm_ipc(6) */
+			<0xff 203>, /* rpm_ipc(7) */
+			<0xff 204>, /* rpm_ipc(24) */
+			<0xff 205>, /* rpm_ipc(25) */
+			<0xff 206>, /* rpm_ipc(26) */
+			<0xff 207>, /* rpm_ipc(27) */
+			<0xff 240>; /* summary_irq_kpss */
+
+		qcom,gpio-parent = <&msmgpio>;
+		qcom,gpio-map = <3  102>,
+			<4  1 >,
+			<5  5 >,
+			<6  9 >,
+			<7  18>,
+			<8  20>,
+			<9  24>,
+			<10  27>,
+			<11  28>,
+			<12  34>,
+			<13  35>,
+			<14  37>,
+			<15  42>,
+			<16  44>,
+			<17  46>,
+			<18  50>,
+			<19  54>,
+			<20  59>,
+			<21  61>,
+			<22  62>,
+			<23  64>,
+			<24  65>,
+			<25  66>,
+			<26  67>,
+			<27  68>,
+			<28  71>,
+			<29  72>,
+			<30  73>,
+			<31  74>,
+			<32  75>,
+			<33  77>,
+			<34  79>,
+			<35  80>,
+			<36  82>,
+			<37  86>,
+			<38  92>,
+			<39  93>,
+			<40  95>;
+	};
+
+	qcom,pc-cntr@fe805664 {
+		compatible = "qcom,pc-cntr";
+		reg = <0xfe805664 0x40>;
+	};
+
+	qcom,pm-8x60 {
+		compatible = "qcom,pm-8x60";
+		qcom,pc-mode = <0>; /*MSM_PC_TZ_L2_INT */
+		qcom,use-sync-timer;
+	};
+
+	qcom,rpm-stats@0xfc19dbd0{
+		compatible = "qcom,rpm-stats";
+		reg = <0xfc19dbd0 0x1000>;
+		reg-names = "phys_addr_base";
+		qcom,sleep-stats-version = <2>;
+	};
+};
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index 854a708..9f0ff92 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -14,6 +14,7 @@
 /include/ "msm8226-ion.dtsi"
 /include/ "msm-gdsc.dtsi"
 /include/ "msm8226-iommu.dtsi"
+/include/ "msm8226-pm.dtsi"
 
 / {
 	model = "Qualcomm MSM 8226";
@@ -388,6 +389,13 @@
 		};
 	};
 
+	rpm_bus: qcom,rpm-smd {
+		compatible = "qcom,rpm-smd";
+		rpm-channel-name = "rpm_requests";
+		rpm-channel-type = <15>; /* SMD_APPS_RPM */
+		rpm-standalone;
+	};
+
 	sdcc1: qcom,sdcc@f9824000 {
 		cell-index = <1>; /* SDC1 eMMC slot */
 		compatible = "qcom,msm-sdcc";
diff --git a/arch/arm/boot/dts/msm8910-iommu-domains.dtsi b/arch/arm/boot/dts/msm8610-iommu-domains.dtsi
similarity index 93%
rename from arch/arm/boot/dts/msm8910-iommu-domains.dtsi
rename to arch/arm/boot/dts/msm8610-iommu-domains.dtsi
index dbdbd5f..52a8c47 100644
--- a/arch/arm/boot/dts/msm8910-iommu-domains.dtsi
+++ b/arch/arm/boot/dts/msm8610-iommu-domains.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
diff --git a/arch/arm/boot/dts/msm8910-ion.dtsi b/arch/arm/boot/dts/msm8610-ion.dtsi
similarity index 95%
rename from arch/arm/boot/dts/msm8910-ion.dtsi
rename to arch/arm/boot/dts/msm8610-ion.dtsi
index 88bb1ab..0abaca5 100644
--- a/arch/arm/boot/dts/msm8910-ion.dtsi
+++ b/arch/arm/boot/dts/msm8610-ion.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
diff --git a/arch/arm/boot/dts/msm8910-regulator.dtsi b/arch/arm/boot/dts/msm8610-regulator.dtsi
similarity index 98%
rename from arch/arm/boot/dts/msm8910-regulator.dtsi
rename to arch/arm/boot/dts/msm8610-regulator.dtsi
index a32d4ab..a81c082 100644
--- a/arch/arm/boot/dts/msm8910-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8610-regulator.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
diff --git a/arch/arm/boot/dts/msm8910-rumi.dts b/arch/arm/boot/dts/msm8610-rumi.dts
similarity index 75%
rename from arch/arm/boot/dts/msm8910-rumi.dts
rename to arch/arm/boot/dts/msm8610-rumi.dts
index 0d944aa..d889268 100644
--- a/arch/arm/boot/dts/msm8910-rumi.dts
+++ b/arch/arm/boot/dts/msm8610-rumi.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -12,11 +12,11 @@
 
 /dts-v1/;
 
-/include/ "msm8910.dtsi"
+/include/ "msm8610.dtsi"
 
 / {
-	model = "Qualcomm MSM 8910 Rumi";
-	compatible = "qcom,msm8910-rumi", "qcom,msm8910";
+	model = "Qualcomm MSM 8610 Rumi";
+	compatible = "qcom,msm8610-rumi", "qcom,msm8610";
 	qcom,msm-id = <147 1 0>;
 
 	serial@f991f000 {
diff --git a/arch/arm/boot/dts/msm8910-sim.dts b/arch/arm/boot/dts/msm8610-sim.dts
similarity index 74%
rename from arch/arm/boot/dts/msm8910-sim.dts
rename to arch/arm/boot/dts/msm8610-sim.dts
index aae88b1..73ba807 100644
--- a/arch/arm/boot/dts/msm8910-sim.dts
+++ b/arch/arm/boot/dts/msm8610-sim.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -12,11 +12,11 @@
 
 /dts-v1/;
 
-/include/ "msm8910.dtsi"
+/include/ "msm8610.dtsi"
 
 / {
-	model = "Qualcomm MSM 8910 Simulator";
-	compatible = "qcom,msm8910-sim", "qcom,msm8910";
+	model = "Qualcomm MSM 8610 Simulator";
+	compatible = "qcom,msm8610-sim", "qcom,msm8610";
 	qcom,msm-id = <147 1 0>;
 
 	serial@f991f000 {
diff --git a/arch/arm/boot/dts/msm8910.dtsi b/arch/arm/boot/dts/msm8610.dtsi
similarity index 93%
rename from arch/arm/boot/dts/msm8910.dtsi
rename to arch/arm/boot/dts/msm8610.dtsi
index a08c165..b80a1c5 100644
--- a/arch/arm/boot/dts/msm8910.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -12,12 +12,12 @@
 
 /include/ "skeleton.dtsi"
 /include/ "msm-iommu-v1.dtsi"
-/include/ "msm8910-ion.dtsi"
+/include/ "msm8610-ion.dtsi"
 /include/ "msm-gdsc.dtsi"
 
 / {
-	model = "Qualcomm MSM 8910";
-	compatible = "qcom,msm8910";
+	model = "Qualcomm MSM 8610";
+	compatible = "qcom,msm8610";
 	interrupt-parent = <&intc>;
 
 	intc: interrupt-controller@f9000000 {
@@ -46,6 +46,11 @@
 		clock-frequency = <19200000>;
 	};
 
+	qcom,msm-adsp-loader {
+		compatible = "qcom,adsp-loader";
+		qcom,adsp-state = <0>;
+	};
+
 	serial@f991f000 {
 		compatible = "qcom,msm-lsuart-v14";
 		reg = <0xf991f000 0x1000>;
@@ -53,6 +58,11 @@
 		status = "disabled";
 	};
 
+	qcom,vidc@fdc00000 {
+		compatible = "qcom,msm-vidc";
+		hfi = "q6";
+	};
+
 	usb@f9a55000 {
 		compatible = "qcom,hsusb-otg";
 		reg = <0xf9a55000 0x400>;
@@ -308,6 +318,15 @@
 					 <0x155000cf>; /* LDO_22 */
 	};
 
+	qcom,lpass@fe200000 {
+		compatible = "qcom,pil-q6v5-lpass";
+		reg = <0xfe200000 0x00100>,
+		      <0xfd485100 0x00010>;
+		reg-names = "qdsp6_base", "halt_base";
+		interrupts = <0 162 1>;
+
+		qcom,firmware-name = "adsp";
+	};
 };
 
 &gdsc_vfe {
@@ -342,7 +361,7 @@
 	status = "ok";
 };
 
-/include/ "msm8910-iommu-domains.dtsi"
+/include/ "msm8610-iommu-domains.dtsi"
 
-/include/ "msm8910-regulator.dtsi"
+/include/ "msm8610-regulator.dtsi"
 /include/ "msm-pm8110.dtsi"
diff --git a/arch/arm/boot/dts/msm8974-regulator.dtsi b/arch/arm/boot/dts/msm8974-regulator.dtsi
index a7a7c88..5fa2364 100644
--- a/arch/arm/boot/dts/msm8974-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8974-regulator.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -110,9 +110,17 @@
 		pm8841_s4: regulator-s4 {
 			regulator-min-microvolt = <815000>;
 			regulator-max-microvolt = <900000>;
-			qcom,init-voltage = <815000>;
 			status = "okay";
 		};
+		pm8841_s4_corner: regulator-s4-corner {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8841_s4_corner";
+			qcom,set = <3>;
+			qcom,use-voltage-corner;
+			regulator-min-microvolt = <1>;
+			regulator-max-microvolt = <7>;
+			qcom,init-voltage-corner = <3>; /* SVS SOC */
+		};
 	};
 
 	rpm-regulator-smpa1 {
@@ -418,48 +426,56 @@
 	krait0_vreg: regulator@f9088000 {
 		compatible = "qcom,krait-regulator";
 		regulator-name = "krait0";
-		reg = <0xf9088000 0x1000>;
+		reg = <0xf9088000 0x1000>, /* APCS_ALIAS0_KPSS_ACS */
+			<0xf908a800 0x1000>; /* APCS_ALIAS0_KPSS_MDD */
+		reg-names = "acs", "mdd";
 		regulator-min-microvolt = <500000>;
 		regulator-max-microvolt = <1100000>;
 		qcom,headroom-voltage = <150000>;
-		qcom,retention-voltage = <745000>;
-		qcom,ldo-default-voltage = <745000>;
+		qcom,retention-voltage = <675000>;
+		qcom,ldo-default-voltage = <750000>;
 		qcom,ldo-threshold-voltage = <750000>;
 	};
 
 	krait1_vreg: regulator@f9098000 {
 		compatible = "qcom,krait-regulator";
 		regulator-name = "krait1";
-		reg = <0xf9098000 0x1000>;
+		reg = <0xf9098000 0x1000>, /* APCS_ALIAS1_KPSS_ACS */
+			<0xf909a800 0x1000>; /* APCS_ALIAS1_KPSS_MDD */
+		reg-names = "acs", "mdd";
 		regulator-min-microvolt = <500000>;
 		regulator-max-microvolt = <1100000>;
 		qcom,headroom-voltage = <150000>;
-		qcom,retention-voltage = <745000>;
-		qcom,ldo-default-voltage = <745000>;
+		qcom,retention-voltage = <675000>;
+		qcom,ldo-default-voltage = <750000>;
 		qcom,ldo-threshold-voltage = <750000>;
 	};
 
 	krait2_vreg: regulator@f90a8000 {
 		compatible = "qcom,krait-regulator";
 		regulator-name = "krait2";
-		reg = <0xf90a8000 0x1000>;
+		reg = <0xf90a8000 0x1000>, /* APCS_ALIAS2_KPSS_ACS */
+			<0xf90aa800 0x1000>; /* APCS_ALIAS2_KPSS_MDD */
+		reg-names = "acs", "mdd";
 		regulator-min-microvolt = <500000>;
 		regulator-max-microvolt = <1100000>;
 		qcom,headroom-voltage = <150000>;
-		qcom,retention-voltage = <745000>;
-		qcom,ldo-default-voltage = <745000>;
+		qcom,retention-voltage = <675000>;
+		qcom,ldo-default-voltage = <750000>;
 		qcom,ldo-threshold-voltage = <750000>;
 	};
 
 	krait3_vreg: regulator@f90b8000 {
 		compatible = "qcom,krait-regulator";
 		regulator-name = "krait3";
-		reg = <0xf90b8000 0x1000>;
+		reg = <0xf90b8000 0x1000>, /* APCS_ALIAS3_KPSS_ACS */
+			<0xf90ba800 0x1000>; /* APCS_ALIAS3_KPSS_MDD */
+		reg-names = "acs", "mdd";
 		regulator-min-microvolt = <500000>;
 		regulator-max-microvolt = <1100000>;
 		qcom,headroom-voltage = <150000>;
-		qcom,retention-voltage = <745000>;
-		qcom,ldo-default-voltage = <745000>;
+		qcom,retention-voltage = <675000>;
+		qcom,ldo-default-voltage = <750000>;
 		qcom,ldo-threshold-voltage = <750000>;
 	};
 
diff --git a/arch/arm/boot/dts/msm8974-rumi.dtsi b/arch/arm/boot/dts/msm8974-rumi.dtsi
index 4919391..38e552e 100644
--- a/arch/arm/boot/dts/msm8974-rumi.dtsi
+++ b/arch/arm/boot/dts/msm8974-rumi.dtsi
@@ -75,7 +75,7 @@
 		interrupts = <0 105 0>;
 		interrupt-names = "qup_err_intr";
 		qcom,i2c-bus-freq = <100000>;
-		qcom,i2c-src-freq = <24000000>;
+		qcom,i2c-src-freq = <19200000>;
 		gpios = <&msmgpio 83 0>, /* DAT  */
 			<&msmgpio 84 0>; /* CLK */
 	};
diff --git a/arch/arm/boot/dts/msm8974-smp2p.dtsi b/arch/arm/boot/dts/msm8974-smp2p.dtsi
new file mode 100644
index 0000000..60f63a8
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974-smp2p.dtsi
@@ -0,0 +1,194 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+/ {
+	qcom,smp2p-modem {
+		compatible = "qcom,smp2p";
+		reg = <0xfa006000 0x1000>, <0x8 0x0>;
+		reg-names = "irq-reg-base", "irq-reg-offset";
+		qcom,remote-pid = <1>;
+		qcom,irq-bitmask = <0x4000>;
+		interrupts = <0 27 1>;
+	};
+
+	qcom,smp2p-adsp {
+		compatible = "qcom,smp2p";
+		reg = <0xfa006000 0x1000>, <0x8 0x0>;
+		reg-names = "irq-reg-base", "irq-reg-offset";
+		qcom,remote-pid = <2>;
+		qcom,irq-bitmask = <0x400>;
+		interrupts = <0 158 1>;
+	};
+
+	qcom,smp2p-wcnss {
+		compatible = "qcom,smp2p";
+		reg = <0xfa006000 0x1000>, <0x8 0x0>;
+		reg-names = "irq-reg-base", "irq-reg-offset";
+		qcom,remote-pid = <4>;
+		qcom,irq-bitmask = <0x40000>;
+		interrupts = <0 143 1>;
+	};
+
+	/* SMP2P Test Driver for inbound entries */
+	smp2pgpio_smp2p_7_in: qcom,smp2pgpio-smp2p-7-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <7>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_7_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_7_in";
+		gpios = <&smp2pgpio_smp2p_7_in 0 0>;
+	};
+
+	/* SMP2P Test Driver for outbound entries */
+	smp2pgpio_smp2p_7_out: qcom,smp2pgpio-smp2p-7-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <7>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_7_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_7_out";
+		gpios = <&smp2pgpio_smp2p_7_out 0 0>;
+	};
+
+	/* SMP2P Test Driver for modem inbound */
+	smp2pgpio_smp2p_1_in: qcom,smp2pgpio-smp2p-1-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <1>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_1_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_1_in";
+		gpios = <&smp2pgpio_smp2p_1_in 0 0>;
+	};
+
+	/* SMP2P Test Driver for modem output */
+	smp2pgpio_smp2p_1_out: qcom,smp2pgpio-smp2p-1-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <1>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_1_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_1_out";
+		gpios = <&smp2pgpio_smp2p_1_out 0 0>;
+	};
+
+	/* SMP2P SSR Driver for inbound entry from modem. */
+	smp2pgpio_ssr_smp2p_1_in: qcom,smp2pgpio-ssr-smp2p-1-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "slave-kernel";
+		qcom,remote-pid = <1>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	/* SMP2P SSR Driver for outbound entry to modem */
+	smp2pgpio_ssr_smp2p_1_out: qcom,smp2pgpio-ssr-smp2p-1-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "master-kernel";
+		qcom,remote-pid = <1>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	/* SMP2P Test Driver for adsp inbound */
+	smp2pgpio_smp2p_2_in: qcom,smp2pgpio-smp2p-2-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <2>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_2_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_2_in";
+		gpios = <&smp2pgpio_smp2p_2_in 0 0>;
+	};
+
+	/* SMP2P Test Driver for adsp output */
+	smp2pgpio_smp2p_2_out: qcom,smp2pgpio-smp2p-2-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <2>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_2_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_2_out";
+		gpios = <&smp2pgpio_smp2p_2_out 0 0>;
+	};
+
+	/* SMP2P Test Driver for wcnss inbound */
+	smp2pgpio_smp2p_4_in: qcom,smp2pgpio-smp2p-4-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <4>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_4_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_4_in";
+		gpios = <&smp2pgpio_smp2p_4_in 0 0>;
+	};
+
+	/* SMP2P Test Driver for wcnss output */
+	smp2pgpio_smp2p_4_out: qcom,smp2pgpio-smp2p-4-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <4>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_4_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_4_out";
+		gpios = <&smp2pgpio_smp2p_4_out 0 0>;
+	};
+};
diff --git a/arch/arm/boot/dts/msm8974-cdp.dts b/arch/arm/boot/dts/msm8974-v1-cdp.dts
similarity index 86%
rename from arch/arm/boot/dts/msm8974-cdp.dts
rename to arch/arm/boot/dts/msm8974-v1-cdp.dts
index b8b3141..15ff424 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dts
+++ b/arch/arm/boot/dts/msm8974-v1-cdp.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -12,7 +12,7 @@
 
 /dts-v1/;
 
-/include/ "msm8974.dtsi"
+/include/ "msm8974-v1.dtsi"
 /include/ "msm8974-cdp.dtsi"
 
 / {
diff --git a/arch/arm/boot/dts/msm8974-fluid.dts b/arch/arm/boot/dts/msm8974-v1-fluid.dts
similarity index 86%
rename from arch/arm/boot/dts/msm8974-fluid.dts
rename to arch/arm/boot/dts/msm8974-v1-fluid.dts
index b014e14..0b435a3 100644
--- a/arch/arm/boot/dts/msm8974-fluid.dts
+++ b/arch/arm/boot/dts/msm8974-v1-fluid.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -12,7 +12,7 @@
 
 /dts-v1/;
 
-/include/ "msm8974.dtsi"
+/include/ "msm8974-v1.dtsi"
 /include/ "msm8974-fluid.dtsi"
 
 / {
diff --git a/arch/arm/boot/dts/msm8974-liquid.dts b/arch/arm/boot/dts/msm8974-v1-liquid.dts
similarity index 86%
rename from arch/arm/boot/dts/msm8974-liquid.dts
rename to arch/arm/boot/dts/msm8974-v1-liquid.dts
index ef38036..5c12569 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dts
+++ b/arch/arm/boot/dts/msm8974-v1-liquid.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -12,7 +12,7 @@
 
 /dts-v1/;
 
-/include/ "msm8974.dtsi"
+/include/ "msm8974-v1.dtsi"
 /include/ "msm8974-liquid.dtsi"
 
 / {
diff --git a/arch/arm/boot/dts/msm8974-mtp.dts b/arch/arm/boot/dts/msm8974-v1-mtp.dts
similarity index 86%
rename from arch/arm/boot/dts/msm8974-mtp.dts
rename to arch/arm/boot/dts/msm8974-v1-mtp.dts
index 9946cf0..01e9fe2 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dts
+++ b/arch/arm/boot/dts/msm8974-v1-mtp.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -12,7 +12,7 @@
 
 /dts-v1/;
 
-/include/ "msm8974.dtsi"
+/include/ "msm8974-v1.dtsi"
 /include/ "msm8974-mtp.dtsi"
 
 / {
diff --git a/arch/arm/boot/dts/msm8974-rumi.dts b/arch/arm/boot/dts/msm8974-v1-rumi.dts
similarity index 86%
rename from arch/arm/boot/dts/msm8974-rumi.dts
rename to arch/arm/boot/dts/msm8974-v1-rumi.dts
index 738ff86..ebb37b7 100644
--- a/arch/arm/boot/dts/msm8974-rumi.dts
+++ b/arch/arm/boot/dts/msm8974-v1-rumi.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -12,7 +12,7 @@
 
 /dts-v1/;
 
-/include/ "msm8974.dtsi"
+/include/ "msm8974-v1.dtsi"
 /include/ "msm8974-rumi.dtsi"
 
 / {
diff --git a/arch/arm/boot/dts/msm8974-sim.dts b/arch/arm/boot/dts/msm8974-v1-sim.dts
similarity index 86%
rename from arch/arm/boot/dts/msm8974-sim.dts
rename to arch/arm/boot/dts/msm8974-v1-sim.dts
index 09ea419..29add5d 100644
--- a/arch/arm/boot/dts/msm8974-sim.dts
+++ b/arch/arm/boot/dts/msm8974-v1-sim.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -12,7 +12,7 @@
 
 /dts-v1/;
 
-/include/ "msm8974.dtsi"
+/include/ "msm8974-v1.dtsi"
 /include/ "msm8974-sim.dtsi"
 
 / {
diff --git a/arch/arm/boot/dts/msm8974-mtp.dts b/arch/arm/boot/dts/msm8974-v1.dtsi
similarity index 66%
copy from arch/arm/boot/dts/msm8974-mtp.dts
copy to arch/arm/boot/dts/msm8974-v1.dtsi
index 9946cf0..6f91ee8 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dts
+++ b/arch/arm/boot/dts/msm8974-v1.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -10,13 +10,10 @@
  * GNU General Public License for more details.
  */
 
-/dts-v1/;
+/*
+ * As a general rule, only version-specific property overrides should be placed
+ * inside this file. However, device definitions should be placed inside the
+ * msm8974.dtsi file.
+ */
 
 /include/ "msm8974.dtsi"
-/include/ "msm8974-mtp.dtsi"
-
-/ {
-	model = "Qualcomm MSM 8974 MTP";
-	compatible = "qcom,msm8974-mtp", "qcom,msm8974";
-	qcom,msm-id = <126 8 0>;
-};
diff --git a/arch/arm/boot/dts/msm8974-cdp.dts b/arch/arm/boot/dts/msm8974-v2-cdp.dts
similarity index 77%
copy from arch/arm/boot/dts/msm8974-cdp.dts
copy to arch/arm/boot/dts/msm8974-v2-cdp.dts
index b8b3141..58e172f 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dts
+++ b/arch/arm/boot/dts/msm8974-v2-cdp.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -12,11 +12,11 @@
 
 /dts-v1/;
 
-/include/ "msm8974.dtsi"
+/include/ "msm8974-v2.dtsi"
 /include/ "msm8974-cdp.dtsi"
 
 / {
-	model = "Qualcomm MSM 8974 CDP";
+	model = "Qualcomm MSM 8974v2 CDP";
 	compatible = "qcom,msm8974-cdp", "qcom,msm8974";
-	qcom,msm-id = <126 1 0>;
+	qcom,msm-id = <126 1 0x20000>;
 };
diff --git a/arch/arm/boot/dts/msm8974-fluid.dts b/arch/arm/boot/dts/msm8974-v2-fluid.dts
similarity index 77%
copy from arch/arm/boot/dts/msm8974-fluid.dts
copy to arch/arm/boot/dts/msm8974-v2-fluid.dts
index b014e14..5759b56 100644
--- a/arch/arm/boot/dts/msm8974-fluid.dts
+++ b/arch/arm/boot/dts/msm8974-v2-fluid.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -12,11 +12,11 @@
 
 /dts-v1/;
 
-/include/ "msm8974.dtsi"
+/include/ "msm8974-v2.dtsi"
 /include/ "msm8974-fluid.dtsi"
 
 / {
-	model = "Qualcomm MSM 8974 FLUID";
+	model = "Qualcomm MSM 8974v2 FLUID";
 	compatible = "qcom,msm8974-fluid", "qcom,msm8974";
-	qcom,msm-id = <126 3 0>;
+	qcom,msm-id = <126 3 0x20000>;
 };
diff --git a/arch/arm/boot/dts/msm8974-liquid.dts b/arch/arm/boot/dts/msm8974-v2-liquid.dts
similarity index 77%
copy from arch/arm/boot/dts/msm8974-liquid.dts
copy to arch/arm/boot/dts/msm8974-v2-liquid.dts
index ef38036..6812f60 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dts
+++ b/arch/arm/boot/dts/msm8974-v2-liquid.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -12,11 +12,11 @@
 
 /dts-v1/;
 
-/include/ "msm8974.dtsi"
+/include/ "msm8974-v2.dtsi"
 /include/ "msm8974-liquid.dtsi"
 
 / {
-	model = "Qualcomm MSM 8974 LIQUID";
+	model = "Qualcomm MSM 8974v2 LIQUID";
 	compatible = "qcom,msm8974-liquid", "qcom,msm8974";
-	qcom,msm-id = <126 9 0>;
+	qcom,msm-id = <126 9 0x20000>;
 };
diff --git a/arch/arm/boot/dts/msm8974-mtp.dts b/arch/arm/boot/dts/msm8974-v2-mtp.dts
similarity index 77%
copy from arch/arm/boot/dts/msm8974-mtp.dts
copy to arch/arm/boot/dts/msm8974-v2-mtp.dts
index 9946cf0..b29d4ca 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dts
+++ b/arch/arm/boot/dts/msm8974-v2-mtp.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -12,11 +12,11 @@
 
 /dts-v1/;
 
-/include/ "msm8974.dtsi"
+/include/ "msm8974-v2.dtsi"
 /include/ "msm8974-mtp.dtsi"
 
 / {
-	model = "Qualcomm MSM 8974 MTP";
+	model = "Qualcomm MSM 8974v2 MTP";
 	compatible = "qcom,msm8974-mtp", "qcom,msm8974";
-	qcom,msm-id = <126 8 0>;
+	qcom,msm-id = <126 8 0x20000>;
 };
diff --git a/arch/arm/boot/dts/msm8974-mtp.dts b/arch/arm/boot/dts/msm8974-v2.dtsi
similarity index 66%
copy from arch/arm/boot/dts/msm8974-mtp.dts
copy to arch/arm/boot/dts/msm8974-v2.dtsi
index 9946cf0..6f91ee8 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dts
+++ b/arch/arm/boot/dts/msm8974-v2.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -10,13 +10,10 @@
  * GNU General Public License for more details.
  */
 
-/dts-v1/;
+/*
+ * As a general rule, only version-specific property overrides should be placed
+ * inside this file. However, device definitions should be placed inside the
+ * msm8974.dtsi file.
+ */
 
 /include/ "msm8974.dtsi"
-/include/ "msm8974-mtp.dtsi"
-
-/ {
-	model = "Qualcomm MSM 8974 MTP";
-	compatible = "qcom,msm8974-mtp", "qcom,msm8974";
-	qcom,msm-id = <126 8 0>;
-};
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 8838953..bde795f 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -19,6 +19,7 @@
 /include/ "msm8974-ion.dtsi"
 /include/ "msm8974-gpu.dtsi"
 /include/ "msm8974-mdss.dtsi"
+/include/ "msm8974-smp2p.dtsi"
 
 / {
 	model = "Qualcomm MSM 8974";
@@ -595,7 +596,7 @@
 		interrupts = <0 105 0>;
 		interrupt-names = "qup_err_intr";
 		qcom,i2c-bus-freq = <100000>;
-		qcom,i2c-src-freq = <24000000>;
+		qcom,i2c-src-freq = <19200000>;
 	};
 
 	i2c@f9924000 {
@@ -608,7 +609,7 @@
 		interrupts = <0 96 0>;
 		interrupt-names = "qup_err_intr";
 		qcom,i2c-bus-freq = <100000>;
-		qcom,i2c-src-freq = <24000000>;
+		qcom,i2c-src-freq = <19200000>;
 	};
 
 	spi@f9923000 {
@@ -672,7 +673,7 @@
 	};
 
 	gdsc_oxili_gx: qcom,gdsc@fd8c4024 {
-		parent-supply = <&pm8841_s4>;
+		parent-supply = <&pm8841_s4_corner>;
 	};
 
 	qcom,lpass@fe200000 {
@@ -896,6 +897,12 @@
 		qcom,is-loadable;
 		qcom,firmware-name = "mba";
 		qcom,pil-self-auth = <1>;
+
+		/* GPIO input from mss */
+		qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_1_in 0 0>;
+
+		/* GPIO output to mss */
+		qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_1_out 0 0>;
 	};
 
 	qcom,pronto@fb21b000 {
@@ -1095,6 +1102,7 @@
 		qcom,usb-bam-num-pipes = <16>;
 		qcom,usb-base-address = <0xf9200000>;
 		qcom,ignore-core-reset-ack;
+		qcom,disable-clk-gating;
 
 		qcom,pipe1 {
 			label = "usb-to-peri-qdss-dwc3";
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index d374b59..3dfbd8a 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -81,7 +81,7 @@
 		vbus_otg-supply = <&usb_vbus>;
 
 		qcom,hsusb-otg-phy-type = <2>;
-		qcom,hsusb-otg-mode = <3>;
+		qcom,hsusb-otg-mode = <1>;
 		qcom,hsusb-otg-otg-control = <1>;
 		qcom,hsusb-otg-disable-reset;
 	};
@@ -111,6 +111,7 @@
 		qcom,usb-total-bam-num = <3>;
 		qcom,usb-bam-num-pipes = <16>;
 		qcom,ignore-core-reset-ack;
+		qcom,disable-clk-gating;
 
 		qcom,pipe0 {
 			label = "usb-to-ipa";
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 3db20a2..6793a65 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -34,7 +34,6 @@
 CONFIG_PARTITION_ADVANCED=y
 CONFIG_EFI_PARTITION=y
 CONFIG_ARCH_MSM=y
-CONFIG_ARCH_MSM8910=y
 CONFIG_ARCH_MSM8610=y
 CONFIG_ARCH_MSM8226=y
 CONFIG_SND_SOC_MSM8226=y
@@ -44,7 +43,13 @@
 # CONFIG_MSM_PROC_COMM is not set
 CONFIG_MSM_SMD=y
 CONFIG_MSM_SMD_PKG4=y
+CONFIG_MSM_IPC_ROUTER=y
+CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
+CONFIG_MSM_QMI_INTERFACE=y
 # CONFIG_MSM_HW3D is not set
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_PIL=y
+CONFIG_MSM_PIL_LPASS_QDSP6V5=y
 CONFIG_MSM_DIRECT_SCLK_ACCESS=y
 CONFIG_MSM_WATCHDOG_V2=y
 CONFIG_MSM_ADSP_LOADER=m
@@ -177,3 +182,9 @@
 # CONFIG_CRYPTO_HW is not set
 CONFIG_CRC_CCITT=y
 CONFIG_LIBCRC32C=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_VIDEOBUF2_MSM_MEM=y
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_OCMEM=y
diff --git a/arch/arm/configs/msm8910_defconfig b/arch/arm/configs/msm8910_defconfig
deleted file mode 100644
index dfd6b5e..0000000
--- a/arch/arm/configs/msm8910_defconfig
+++ /dev/null
@@ -1,181 +0,0 @@
-# CONFIG_ARM_PATCH_PHYS_VIRT is not set
-CONFIG_EXPERIMENTAL=y
-# CONFIG_LOCALVERSION_AUTO is not set
-CONFIG_SYSVIPC=y
-CONFIG_RCU_FAST_NO_HZ=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_CGROUPS=y
-CONFIG_CGROUP_DEBUG=y
-CONFIG_CGROUP_FREEZER=y
-CONFIG_CGROUP_CPUACCT=y
-CONFIG_RESOURCE_COUNTERS=y
-CONFIG_CGROUP_SCHED=y
-CONFIG_RT_GROUP_SCHED=y
-CONFIG_NAMESPACES=y
-# CONFIG_UTS_NS is not set
-# CONFIG_IPC_NS is not set
-# CONFIG_USER_NS is not set
-# CONFIG_PID_NS is not set
-CONFIG_RELAY=y
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_RD_BZIP2=y
-CONFIG_RD_LZMA=y
-CONFIG_PANIC_TIMEOUT=5
-CONFIG_KALLSYMS_ALL=y
-CONFIG_ASHMEM=y
-CONFIG_EMBEDDED=y
-CONFIG_PROFILING=y
-CONFIG_OPROFILE=m
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
-CONFIG_MODVERSIONS=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_EFI_PARTITION=y
-CONFIG_ARCH_MSM=y
-CONFIG_ARCH_MSM8910=y
-CONFIG_ARCH_MSM8226=y
-CONFIG_SND_SOC_MSM8226=y
-# CONFIG_MSM_STACKED_MEMORY is not set
-CONFIG_CPU_HAS_L2_PMU=y
-# CONFIG_MSM_FIQ_SUPPORT is not set
-# CONFIG_MSM_PROC_COMM is not set
-CONFIG_MSM_SMD=y
-CONFIG_MSM_SMD_PKG4=y
-CONFIG_MSM_IPC_ROUTER=y
-CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
-CONFIG_MSM_QMI_INTERFACE=y
-# CONFIG_MSM_HW3D is not set
-CONFIG_MSM_DIRECT_SCLK_ACCESS=y
-CONFIG_MSM_WATCHDOG_V2=y
-CONFIG_MSM_ADSP_LOADER=m
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_SMP=y
-CONFIG_SCHED_MC=y
-CONFIG_ARM_ARCH_TIMER=y
-CONFIG_HOTPLUG_CPU=y
-CONFIG_PREEMPT=y
-CONFIG_AEABI=y
-CONFIG_HIGHMEM=y
-CONFIG_VMALLOC_RESERVE=0x19000000
-CONFIG_USE_OF=y
-CONFIG_VFP=y
-CONFIG_NEON=y
-# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
-# CONFIG_SUSPEND is not set
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_ADVANCED_ROUTER=y
-CONFIG_IP_MULTIPLE_TABLES=y
-CONFIG_IP_ROUTE_VERBOSE=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
-CONFIG_IPV6=y
-CONFIG_IPV6_PRIVACY=y
-CONFIG_IPV6_ROUTER_PREF=y
-CONFIG_IPV6_ROUTE_INFO=y
-CONFIG_IPV6_OPTIMISTIC_DAD=y
-CONFIG_INET6_AH=y
-CONFIG_INET6_ESP=y
-CONFIG_INET6_IPCOMP=y
-CONFIG_IPV6_MIP6=y
-CONFIG_IPV6_MULTIPLE_TABLES=y
-CONFIG_IPV6_SUBTREES=y
-CONFIG_NETFILTER=y
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_MD=y
-CONFIG_BLK_DEV_DM=y
-CONFIG_DM_CRYPT=y
-CONFIG_NETDEVICES=y
-CONFIG_DUMMY=y
-CONFIG_INPUT_EVDEV=y
-CONFIG_INPUT_EVBUG=m
-CONFIG_INPUT_MISC=y
-CONFIG_INPUT_UINPUT=y
-CONFIG_INPUT_GPIO=m
-CONFIG_SERIAL_MSM_HSL=y
-CONFIG_SERIAL_MSM_HSL_CONSOLE=y
-CONFIG_DIAG_CHAR=y
-CONFIG_HW_RANDOM=y
-CONFIG_SPMI=y
-CONFIG_SPMI_MSM_PMIC_ARB=y
-CONFIG_MSM_QPNP_INT=y
-CONFIG_SLIMBUS=y
-CONFIG_SLIMBUS_MSM_NGD=y
-CONFIG_DEBUG_GPIO=y
-CONFIG_GPIO_SYSFS=y
-CONFIG_I2C=y
-CONFIG_WCD9306_CODEC=y
-# CONFIG_HWMON is not set
-CONFIG_REGULATOR=y
-CONFIG_REGULATOR_STUB=y
-CONFIG_ION=y
-CONFIG_ION_MSM=y
-CONFIG_FB=y
-CONFIG_FB_VIRTUAL=y
-CONFIG_SOUND=y
-CONFIG_SND=y
-CONFIG_SND_SOC=y
-CONFIG_USB_GADGET=y
-CONFIG_USB_GADGET_DEBUG_FILES=y
-CONFIG_USB_GADGET_DEBUG_FS=y
-CONFIG_USB_CI13XXX_MSM=y
-CONFIG_USB_G_ANDROID=y
-CONFIG_MMC=y
-CONFIG_MMC_PERF_PROFILING=y
-CONFIG_MMC_UNSAFE_RESUME=y
-CONFIG_MMC_CLKGATE=y
-CONFIG_MMC_EMBEDDED_SDIO=y
-CONFIG_MMC_PARANOID_SD_INIT=y
-CONFIG_MMC_BLOCK_MINORS=32
-CONFIG_MMC_TEST=m
-CONFIG_MMC_MSM=y
-CONFIG_STAGING=y
-CONFIG_ANDROID=y
-CONFIG_ANDROID_BINDER_IPC=y
-CONFIG_ANDROID_LOGGER=y
-CONFIG_ANDROID_RAM_CONSOLE=y
-CONFIG_ANDROID_TIMED_GPIO=y
-CONFIG_ANDROID_LOW_MEMORY_KILLER=y
-CONFIG_MSM_IOMMU=y
-CONFIG_SPS=y
-CONFIG_SPS_SUPPORT_NDP_BAM=y
-CONFIG_MMC_MSM_SPS_SUPPORT=y
-CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
-CONFIG_EXT3_FS=y
-# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
-CONFIG_EXT4_FS=y
-CONFIG_FUSE_FS=y
-CONFIG_VFAT_FS=y
-CONFIG_TMPFS=y
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_ASCII=y
-CONFIG_NLS_ISO8859_1=y
-CONFIG_PRINTK_TIME=y
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_FS=y
-CONFIG_SCHEDSTATS=y
-CONFIG_TIMER_STATS=y
-CONFIG_DEBUG_INFO=y
-CONFIG_DEBUG_MEMORY_INIT=y
-CONFIG_DYNAMIC_DEBUG=y
-CONFIG_DEBUG_USER=y
-CONFIG_KEYS=y
-CONFIG_CRYPTO_MD4=y
-CONFIG_CRYPTO_SHA256=y
-CONFIG_CRYPTO_AES=y
-CONFIG_CRYPTO_ARC4=y
-CONFIG_CRYPTO_TWOFISH=y
-# CONFIG_CRYPTO_HW is not set
-CONFIG_CRC_CCITT=y
-CONFIG_LIBCRC32C=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index 53c97ce..94009bc 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -339,6 +339,7 @@
 CONFIG_MFD_PM8XXX_BATT_ALARM=y
 CONFIG_WCD9304_CODEC=y
 CONFIG_WCD9310_CODEC=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
 CONFIG_REGULATOR_PM8XXX=y
 CONFIG_REGULATOR_MSM_GPIO=y
 CONFIG_MEDIA_SUPPORT=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 2d97769..6efdafa 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -344,6 +344,7 @@
 CONFIG_MFD_PM8XXX_BATT_ALARM=y
 CONFIG_WCD9304_CODEC=y
 CONFIG_WCD9310_CODEC=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
 CONFIG_REGULATOR_PM8XXX=y
 CONFIG_REGULATOR_MSM_GPIO=y
 CONFIG_MEDIA_SUPPORT=y
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index be2e483..76a13f9 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -45,6 +45,8 @@
 CONFIG_MSM_SMD=y
 CONFIG_MSM_SMD_PKG4=y
 CONFIG_MSM_BAM_DMUX=y
+CONFIG_MSM_SMP2P=y
+CONFIG_MSM_SMP2P_TEST=y
 CONFIG_MSM_IPC_LOGGING=y
 CONFIG_MSM_IPC_ROUTER=y
 CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
@@ -76,6 +78,7 @@
 CONFIG_MSM_L1_ERR_LOG=y
 CONFIG_MSM_L2_ERP_2BIT_PANIC=y
 CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
+CONFIG_MSM_UARTDM_Core_v14=y
 CONFIG_STRICT_MEMORY_RWX=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
@@ -260,6 +263,7 @@
 CONFIG_TOUCHSCREEN_ATMEL_MXT=y
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_UINPUT=y
+CONFIG_SERIAL_MSM_HS=y
 CONFIG_SERIAL_MSM_HSL=y
 CONFIG_SERIAL_MSM_HSL_CONSOLE=y
 CONFIG_DIAG_CHAR=y
@@ -337,9 +341,11 @@
 CONFIG_SND_USB_AUDIO=y
 CONFIG_SND_SOC=y
 CONFIG_SND_SOC_MSM8974=y
+CONFIG_USB_SUSPEND=y
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_EHCI_MSM=y
 CONFIG_USB_EHCI_MSM_HSIC=y
 CONFIG_USB_ACM=y
 CONFIG_USB_STORAGE=y
@@ -430,3 +436,5 @@
 CONFIG_CRC_CCITT=y
 CONFIG_SYNC=y
 CONFIG_SW_SYNC=y
+CONFIG_MOBICORE_SUPPORT=m
+CONFIG_MOBICORE_API=m
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index c882db5..f025ab3 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -44,6 +44,8 @@
 CONFIG_MSM_SMD=y
 CONFIG_MSM_SMD_PKG4=y
 CONFIG_MSM_BAM_DMUX=y
+CONFIG_MSM_SMP2P=y
+CONFIG_MSM_SMP2P_TEST=y
 CONFIG_MSM_IPC_LOGGING=y
 CONFIG_MSM_IPC_ROUTER=y
 CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
@@ -80,6 +82,7 @@
 CONFIG_MSM_CACHE_DUMP=y
 CONFIG_MSM_CACHE_DUMP_ON_PANIC=y
 CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
+CONFIG_MSM_UARTDM_Core_v14=y
 CONFIG_STRICT_MEMORY_RWX=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
@@ -264,6 +267,7 @@
 CONFIG_TOUCHSCREEN_ATMEL_MXT=y
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_UINPUT=y
+CONFIG_SERIAL_MSM_HS=y
 CONFIG_SERIAL_MSM_HSL=y
 CONFIG_SERIAL_MSM_HSL_CONSOLE=y
 CONFIG_DIAG_CHAR=y
@@ -340,9 +344,11 @@
 CONFIG_SND_USB_AUDIO=y
 CONFIG_SND_SOC=y
 CONFIG_SND_SOC_MSM8974=y
+CONFIG_USB_SUSPEND=y
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_EHCI_MSM=y
 CONFIG_USB_EHCI_MSM_HSIC=y
 CONFIG_USB_ACM=y
 CONFIG_USB_STORAGE=y
@@ -446,3 +452,5 @@
 CONFIG_CRC_CCITT=y
 CONFIG_SYNC=y
 CONFIG_SW_SYNC=y
+CONFIG_MOBICORE_SUPPORT=m
+CONFIG_MOBICORE_API=m
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index a2d21d9..fda9074 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -99,6 +99,7 @@
 CONFIG_NF_CONNTRACK_PPTP=y
 CONFIG_NF_CONNTRACK_SIP=y
 CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
 CONFIG_NETFILTER_XT_MARK=y
 CONFIG_NETFILTER_XT_CONNMARK=y
 CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=y
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 94210fd..baaa09d 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -378,8 +378,8 @@
 	select CPU_HAS_L2_PMU
 	select MSM_JTAG_MM if MSM_QDSS
 
-config ARCH_MSM8910
-	bool "MSM8910"
+config ARCH_MSM8610
+	bool "MSM8610"
 	select ARM_GIC
 	select GIC_SECURE
 	select ARCH_MSM_CORTEXMP
@@ -393,6 +393,9 @@
 	select MSM_NATIVE_RESTART
 	select MSM_RESTART_V2
 	select QMI_ENCDEC
+	select MSM_QDSP6_APRV2
+	select MSM_QDSP6V2_CODECS
+	select MSM_AUDIO_QDSP6V2 if SND_SOC
 
 config ARCH_MSM8226
 	bool "MSM8226"
@@ -411,6 +414,11 @@
 	select MSM_QDSP6_APRV2
 	select MSM_QDSP6V2_CODECS
 	select MSM_AUDIO_QDSP6V2 if SND_SOC
+	select QMI_ENCDEC
+	select MSM_RPM_SMD
+	select MSM_SPM_V2
+	select MSM_L2_SPM
+	select MSM_PM8X60 if PM
 endmenu
 
 choice
@@ -528,7 +536,7 @@
 
 config MSM_LPM_TEST
 	bool "Low Power Mode test framework"
-	depends on MSM_RPM
+	depends on MSM_RPM || MSM_RPM_SMD
 	depends on MSM_PM8X60
 	help
 	  LPM_TEST is a test framework that assists in exercising the low
@@ -1002,7 +1010,7 @@
 	default "0x00000000" if ARCH_MSM8974
 	default "0x00000000" if ARCH_MPQ8092
 	default "0x00000000" if ARCH_MSM8226
-	default "0x00000000" if ARCH_MSM8910
+	default "0x00000000" if ARCH_MSM8610
 	default "0x10000000" if ARCH_FSM9XXX
 	default "0x00200000" if ARCH_MSM9625
 	default "0x00200000" if !MSM_STACKED_MEMORY
@@ -1442,6 +1450,27 @@
 	  Supports APPS-QDSP SMSM communication along with
 	  normal APPS-MODEM SMSM communication.
 
+config MSM_SMP2P
+	bool "SMSM Point-to-Point (SMP2P)"
+	depends on MSM_SMD
+	help
+	  Provide point-to-point remote signaling support.
+	  SMP2P enables transferring 32-bit values between
+	  the local and a remote system using shared
+	  memory and interrupts.  A client can open multiple
+	  32-bit values by specifying a unique string and
+	  remote processor ID.
+
+config MSM_SMP2P_TEST
+	bool "SMSM Point-to-Point Test"
+	depends on MSM_SMP2P
+	help
+	  Enables loopback and unit testing support for
+	  SMP2P.  Loopback support is used by other
+	  processors to do unit testing.  Unit tests
+	  are used to verify the local and remote
+	  implementations.
+
 config MSM_RESET_MODEM
 	tristate "Reset Modem Driver"
 	depends on MSM_SMD
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index b69f397..336c2fc 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -73,7 +73,8 @@
 	$(call if_changed,mkrpcsym)
 
 obj-$(CONFIG_MSM_SMD) += smd.o smd_debug.o remote_spinlock.o smd_private.o
-
+obj-$(CONFIG_MSM_SMP2P) += smp2p.o smp2p_debug.o smp2p_gpio.o
+obj-$(CONFIG_MSM_SMP2P_TEST) += smp2p_loopback.o smp2p_test.o smp2p_gpio_test.o smp2p_spinlock_test.o
 obj-$(CONFIG_MSM_SCM) += scm.o scm-boot.o
 obj-$(CONFIG_MSM_SECURE_IO) += scm-io.o
 obj-$(CONFIG_MSM_PIL) += peripheral-loader.o
@@ -113,7 +114,7 @@
 ifndef CONFIG_ARCH_MSM8226
 ifndef CONFIG_ARCH_MSM9625
 ifndef CONFIG_ARCH_MPQ8092
-ifndef CONFIG_ARCH_MSM8910
+ifndef CONFIG_ARCH_MSM8610
 	obj-y += nand_partitions.o
 endif
 endif
@@ -290,15 +291,15 @@
 obj-$(CONFIG_ARCH_MSM8974) += gdsc.o
 obj-$(CONFIG_ARCH_MSM9625) += gdsc.o
 obj-$(CONFIG_ARCH_MSM8226) += gdsc.o
-obj-$(CONFIG_ARCH_MSM8910) += gdsc.o
+obj-$(CONFIG_ARCH_MSM8610) += gdsc.o
 obj-$(CONFIG_ARCH_MSM8974) += krait-regulator.o
 obj-$(CONFIG_ARCH_MSM9625) += board-9625.o board-9625-gpiomux.o
 obj-$(CONFIG_ARCH_MSM9625) += clock-local2.o clock-pll.o clock-9625.o clock-rpm.o clock-voter.o acpuclock-9625.o
 obj-$(CONFIG_ARCH_MSM8930) += acpuclock-8930.o acpuclock-8627.o acpuclock-8930aa.o acpuclock-8930ab.o
 obj-$(CONFIG_ARCH_MPQ8092) += board-8092.o board-8092-gpiomux.o
 obj-$(CONFIG_ARCH_MSM8226) += board-8226.o board-8226-gpiomux.o
-obj-$(CONFIG_ARCH_MSM8910) += board-8910.o board-8910-gpiomux.o
-obj-$(CONFIG_ARCH_MSM8910) += clock-local2.o clock-pll.o clock-8910.o clock-rpm.o clock-voter.o
+obj-$(CONFIG_ARCH_MSM8610) += board-8610.o board-8610-gpiomux.o
+obj-$(CONFIG_ARCH_MSM8610) += clock-local2.o clock-pll.o clock-8610.o clock-rpm.o clock-voter.o
 
 obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire.o board-sapphire-gpio.o
 obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-keypad.o board-sapphire-panel.o
@@ -356,7 +357,7 @@
 obj-$(CONFIG_ARCH_MSM9625) += gpiomux-v2.o gpiomux.o
 obj-$(CONFIG_ARCH_MPQ8092) += gpiomux-v2.o gpiomux.o
 obj-$(CONFIG_ARCH_MSM8226) += gpiomux-v2.o gpiomux.o
-obj-$(CONFIG_ARCH_MSM8910) += gpiomux-v2.o gpiomux.o
+obj-$(CONFIG_ARCH_MSM8610) += gpiomux-v2.o gpiomux.o
 
 obj-$(CONFIG_MSM_SLEEP_STATS_DEVICE) += idle_stats_device.o
 obj-$(CONFIG_MSM_DCVS) += msm_dcvs_scm.o msm_dcvs.o msm_mpdecision.o
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index e74d61a..e04a9a0 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -47,12 +47,16 @@
 
 # MSM8974
    zreladdr-$(CONFIG_ARCH_MSM8974)	:= 0x00008000
-        dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974-cdp.dtb
-        dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974-fluid.dtb
-        dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974-liquid.dtb
-        dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974-mtp.dtb
-        dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974-rumi.dtb
-        dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974-sim.dtb
+        dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974-v1-cdp.dtb
+        dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974-v1-fluid.dtb
+        dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974-v1-liquid.dtb
+        dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974-v1-mtp.dtb
+        dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974-v1-rumi.dtb
+        dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974-v1-sim.dtb
+        dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974-v2-cdp.dtb
+        dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974-v2-fluid.dtb
+        dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974-v2-liquid.dtb
+        dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974-v2-mtp.dtb
 
 # MSM9615
    zreladdr-$(CONFIG_ARCH_MSM9615)	:= 0x40808000
@@ -75,7 +79,7 @@
 # MPQ8092
    zreladdr-$(CONFIG_ARCH_MPQ8092)	:= 0x00008000
 
-# MSM8910
-   zreladdr-$(CONFIG_ARCH_MSM8910)	:= 0x00008000
-        dtb-$(CONFIG_ARCH_MSM8910)	+= msm8910-rumi.dtb
-        dtb-$(CONFIG_ARCH_MSM8910)	+= msm8910-sim.dtb
+# MSM8610
+   zreladdr-$(CONFIG_ARCH_MSM8610)	:= 0x00008000
+        dtb-$(CONFIG_ARCH_MSM8610)	+= msm8610-rumi.dtb
+        dtb-$(CONFIG_ARCH_MSM8610)	+= msm8610-sim.dtb
diff --git a/arch/arm/mach-msm/acpuclock-8064.c b/arch/arm/mach-msm/acpuclock-8064.c
index 359a156..a0727b7 100644
--- a/arch/arm/mach-msm/acpuclock-8064.c
+++ b/arch/arm/mach-msm/acpuclock-8064.c
@@ -650,6 +650,7 @@
 	.l2_freq_tbl_size = sizeof(l2_freq_tbl),
 	.bus_scale = &bus_scale_data,
 	.pte_efuse_phys = 0x007000C0,
+	.get_bin_info = get_krait_bin_format_a,
 	.stby_khz = 384000,
 };
 
diff --git a/arch/arm/mach-msm/acpuclock-8627.c b/arch/arm/mach-msm/acpuclock-8627.c
index ac29cac..405b26b 100644
--- a/arch/arm/mach-msm/acpuclock-8627.c
+++ b/arch/arm/mach-msm/acpuclock-8627.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -142,6 +142,7 @@
 	.l2_freq_tbl_size = sizeof(l2_freq_tbl),
 	.bus_scale = &bus_scale_data,
 	.pte_efuse_phys = 0x007000C0,
+	.get_bin_info = get_krait_bin_format_a,
 	.stby_khz = 384000,
 };
 
diff --git a/arch/arm/mach-msm/acpuclock-8930.c b/arch/arm/mach-msm/acpuclock-8930.c
index 40326cb..6915343 100644
--- a/arch/arm/mach-msm/acpuclock-8930.c
+++ b/arch/arm/mach-msm/acpuclock-8930.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -227,6 +227,7 @@
 	.l2_freq_tbl_size = sizeof(l2_freq_tbl),
 	.bus_scale = &bus_scale_data,
 	.pte_efuse_phys = 0x007000C0,
+	.get_bin_info = get_krait_bin_format_a,
 	.stby_khz = 384000,
 };
 
diff --git a/arch/arm/mach-msm/acpuclock-8930aa.c b/arch/arm/mach-msm/acpuclock-8930aa.c
index 7d1ce09..9aebac9 100644
--- a/arch/arm/mach-msm/acpuclock-8930aa.c
+++ b/arch/arm/mach-msm/acpuclock-8930aa.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -203,6 +203,7 @@
 	.l2_freq_tbl_size = sizeof(l2_freq_tbl),
 	.bus_scale = &bus_scale_data,
 	.pte_efuse_phys = 0x007000C0,
+	.get_bin_info = get_krait_bin_format_a,
 	.stby_khz = 384000,
 };
 
diff --git a/arch/arm/mach-msm/acpuclock-8930ab.c b/arch/arm/mach-msm/acpuclock-8930ab.c
index 5003862..bddac00 100644
--- a/arch/arm/mach-msm/acpuclock-8930ab.c
+++ b/arch/arm/mach-msm/acpuclock-8930ab.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -257,6 +257,7 @@
 	.l2_freq_tbl_size = sizeof(l2_freq_tbl),
 	.bus_scale = &bus_scale_data,
 	.pte_efuse_phys = 0x007000C0,
+	.get_bin_info = get_krait_bin_format_a,
 	.stby_khz = 384000,
 };
 
diff --git a/arch/arm/mach-msm/acpuclock-8960.c b/arch/arm/mach-msm/acpuclock-8960.c
index d7d3edd..317729f 100644
--- a/arch/arm/mach-msm/acpuclock-8960.c
+++ b/arch/arm/mach-msm/acpuclock-8960.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -210,6 +210,7 @@
 	.l2_freq_tbl_size = sizeof(l2_freq_tbl),
 	.bus_scale = &bus_scale_data,
 	.pte_efuse_phys = 0x007000C0,
+	.get_bin_info = get_krait_bin_format_a,
 	.stby_khz = 384000,
 };
 
diff --git a/arch/arm/mach-msm/acpuclock-8960ab.c b/arch/arm/mach-msm/acpuclock-8960ab.c
index d2e88fb..38658a2 100644
--- a/arch/arm/mach-msm/acpuclock-8960ab.c
+++ b/arch/arm/mach-msm/acpuclock-8960ab.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -252,6 +252,7 @@
 	.l2_freq_tbl_size = sizeof(l2_freq_tbl),
 	.bus_scale = &bus_scale_data,
 	.pte_efuse_phys = 0x007000C0,
+	.get_bin_info = get_krait_bin_format_a,
 	.stby_khz = 384000,
 };
 
diff --git a/arch/arm/mach-msm/acpuclock-8974.c b/arch/arm/mach-msm/acpuclock-8974.c
index 94a4d3e..8eb4b28 100644
--- a/arch/arm/mach-msm/acpuclock-8974.c
+++ b/arch/arm/mach-msm/acpuclock-8974.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -112,14 +112,14 @@
 };
 
 static struct l2_level l2_freq_tbl[] __initdata = {
-	[0]  = { {  300000, PLL_0, 0,   0 }, LVL_LOW,  1050000, 0 },
-	[1]  = { {  345600, HFPLL, 2,  36 }, LVL_NOM,  1050000, 1 },
-	[2]  = { {  422400, HFPLL, 2,  44 }, LVL_NOM,  1050000, 1 },
-	[3]  = { {  499200, HFPLL, 2,  52 }, LVL_NOM,  1050000, 2 },
-	[4]  = { {  576000, HFPLL, 1,  30 }, LVL_NOM,  1050000, 2 },
-	[5]  = { {  652800, HFPLL, 1,  34 }, LVL_NOM,  1050000, 3 },
-	[6]  = { {  729600, HFPLL, 1,  38 }, LVL_NOM,  1050000, 3 },
-	[7]  = { {  806400, HFPLL, 1,  42 }, LVL_NOM,  1050000, 3 },
+	[0]  = { {  300000, PLL_0, 0,   0 }, LVL_LOW,   950000, 0 },
+	[1]  = { {  345600, HFPLL, 2,  36 }, LVL_NOM,   950000, 1 },
+	[2]  = { {  422400, HFPLL, 2,  44 }, LVL_NOM,   950000, 1 },
+	[3]  = { {  499200, HFPLL, 2,  52 }, LVL_NOM,   950000, 2 },
+	[4]  = { {  576000, HFPLL, 1,  30 }, LVL_NOM,   950000, 2 },
+	[5]  = { {  652800, HFPLL, 1,  34 }, LVL_NOM,   950000, 3 },
+	[6]  = { {  729600, HFPLL, 1,  38 }, LVL_NOM,   950000, 3 },
+	[7]  = { {  806400, HFPLL, 1,  42 }, LVL_HIGH, 1050000, 3 },
 	[8]  = { {  883200, HFPLL, 1,  46 }, LVL_HIGH, 1050000, 4 },
 	[9]  = { {  960000, HFPLL, 1,  50 }, LVL_HIGH, 1050000, 4 },
 	[10] = { { 1036800, HFPLL, 1,  54 }, LVL_HIGH, 1050000, 4 },
@@ -129,50 +129,135 @@
 	[14] = { { 1344000, HFPLL, 1,  70 }, LVL_HIGH, 1050000, 6 },
 	[15] = { { 1420800, HFPLL, 1,  74 }, LVL_HIGH, 1050000, 7 },
 	[16] = { { 1497600, HFPLL, 1,  78 }, LVL_HIGH, 1050000, 7 },
-	[17] = { { 1574400, HFPLL, 1,  82 }, LVL_HIGH, 1050000, 7 },
-	[18] = { { 1651200, HFPLL, 1,  86 }, LVL_HIGH, 1050000, 7 },
-	[19] = { { 1728000, HFPLL, 1,  90 }, LVL_HIGH, 1050000, 7 },
-	[20] = { { 1804800, HFPLL, 1,  94 }, LVL_HIGH, 1050000, 7 },
-	[21] = { { 1881600, HFPLL, 1,  98 }, LVL_HIGH, 1050000, 7 },
-	[22] = { { 1958400, HFPLL, 1, 102 }, LVL_HIGH, 1050000, 7 },
-	[23] = { { 2035200, HFPLL, 1, 106 }, LVL_HIGH, 1050000, 7 },
-	[24] = { { 2112000, HFPLL, 1, 110 }, LVL_HIGH, 1050000, 7 },
-	[25] = { { 2188800, HFPLL, 1, 114 }, LVL_HIGH, 1050000, 7 },
 	{ }
 };
 
-static struct acpu_level acpu_freq_tbl[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 }, L2(0),   850000,  400000 },
-	{ 0, {  345600, HFPLL, 2,  36 }, L2(0),   850000, 3200000 },
-	{ 1, {  422400, HFPLL, 2,  44 }, L2(0),   850000, 3200000 },
-	{ 0, {  499200, HFPLL, 2,  52 }, L2(0),   850000, 3200000 },
-	{ 1, {  576000, HFPLL, 1,  30 }, L2(0),   850000, 3200000 },
-	{ 1, {  652800, HFPLL, 1,  34 }, L2(16),  850000, 3200000 },
-	{ 0, {  729600, HFPLL, 1,  38 }, L2(16),  850000, 3200000 },
-	{ 1, {  806400, HFPLL, 1,  42 }, L2(16),  850000, 3200000 },
-	{ 1, {  883200, HFPLL, 1,  46 }, L2(16),  870000, 3200000 },
-	{ 1, {  960000, HFPLL, 1,  50 }, L2(16),  880000, 3200000 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(16),  900000, 3200000 },
-	{ 1, { 1113600, HFPLL, 1,  58 }, L2(16),  915000, 3200000 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(16),  935000, 3200000 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(16),  950000, 3200000 },
-	{ 1, { 1344000, HFPLL, 1,  70 }, L2(16),  970000, 3200000 },
-	{ 1, { 1420800, HFPLL, 1,  74 }, L2(16),  985000, 3200000 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16), 1000000, 3200000 },
+static struct acpu_level acpu_freq_tbl_pvs0[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 }, L2(0),   825000,  400000 },
+	{ 0, {  345600, HFPLL, 2,  36 }, L2(3),   825000, 3200000 },
+	{ 1, {  422400, HFPLL, 2,  44 }, L2(3),   825000, 3200000 },
+	{ 0, {  499200, HFPLL, 2,  52 }, L2(6),   825000, 3200000 },
+	{ 1, {  576000, HFPLL, 1,  30 }, L2(6),   825000, 3200000 },
+	{ 1, {  652800, HFPLL, 1,  34 }, L2(6),   825000, 3200000 },
+	{ 0, {  729600, HFPLL, 1,  38 }, L2(6),   825000, 3200000 },
+	{ 1, {  806400, HFPLL, 1,  42 }, L2(8),   835000, 3200000 },
+	{ 1, {  883200, HFPLL, 1,  46 }, L2(8),   845000, 3200000 },
+	{ 1, {  960000, HFPLL, 1,  50 }, L2(8),   860000, 3200000 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(8),   880000, 3200000 },
+	{ 1, { 1113600, HFPLL, 1,  58 }, L2(12),  905000, 3200000 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(12),  920000, 3200000 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(12),  940000, 3200000 },
+	{ 1, { 1344000, HFPLL, 1,  70 }, L2(12),  960000, 3200000 },
+	{ 1, { 1420800, HFPLL, 1,  74 }, L2(16),  980000, 3200000 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  995000, 3200000 },
 	{ 1, { 1574400, HFPLL, 1,  82 }, L2(16), 1015000, 3200000 },
 	{ 1, { 1651200, HFPLL, 1,  86 }, L2(16), 1030000, 3200000 },
 	{ 1, { 1728000, HFPLL, 1,  90 }, L2(16), 1050000, 3200000 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(16), 1050000, 3200000 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(16), 1050000, 3200000 },
-	{ 0, { 1958400, HFPLL, 1, 102 }, L2(16), 1050000, 3200000 },
-	{ 0, { 1996800, HFPLL, 1, 104 }, L2(16), 1050000, 3200000 },
 	{ 0, { 0 } }
 };
 
-static struct pvs_table pvs_tables[NUM_SPEED_BINS][NUM_PVS]  __initdata = {
-	[0][PVS_SLOW]    = { acpu_freq_tbl, sizeof(acpu_freq_tbl) },
-	[0][PVS_NOMINAL] = { acpu_freq_tbl, sizeof(acpu_freq_tbl) },
-	[0][PVS_FAST]    = { acpu_freq_tbl, sizeof(acpu_freq_tbl) },
+static struct acpu_level acpu_freq_tbl_pvs1[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 }, L2(0),   825000,  400000 },
+	{ 0, {  345600, HFPLL, 2,  36 }, L2(3),   825000, 3200000 },
+	{ 1, {  422400, HFPLL, 2,  44 }, L2(3),   825000, 3200000 },
+	{ 0, {  499200, HFPLL, 2,  52 }, L2(6),   825000, 3200000 },
+	{ 1, {  576000, HFPLL, 1,  30 }, L2(6),   825000, 3200000 },
+	{ 1, {  652800, HFPLL, 1,  34 }, L2(6),   825000, 3200000 },
+	{ 0, {  729600, HFPLL, 1,  38 }, L2(6),   825000, 3200000 },
+	{ 1, {  806400, HFPLL, 1,  42 }, L2(8),   835000, 3200000 },
+	{ 1, {  883200, HFPLL, 1,  46 }, L2(8),   845000, 3200000 },
+	{ 1, {  960000, HFPLL, 1,  50 }, L2(8),   860000, 3200000 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(8),   880000, 3200000 },
+	{ 1, { 1113600, HFPLL, 1,  58 }, L2(12),  905000, 3200000 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(12),  920000, 3200000 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(12),  940000, 3200000 },
+	{ 1, { 1344000, HFPLL, 1,  70 }, L2(12),  960000, 3200000 },
+	{ 1, { 1420800, HFPLL, 1,  74 }, L2(16),  980000, 3200000 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  995000, 3200000 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(16), 1015000, 3200000 },
+	{ 1, { 1651200, HFPLL, 1,  86 }, L2(16), 1030000, 3200000 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(16), 1050000, 3200000 },
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_freq_tbl_pvs2[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 }, L2(0),   825000,  400000 },
+	{ 0, {  345600, HFPLL, 2,  36 }, L2(3),   825000, 3200000 },
+	{ 1, {  422400, HFPLL, 2,  44 }, L2(3),   825000, 3200000 },
+	{ 0, {  499200, HFPLL, 2,  52 }, L2(6),   825000, 3200000 },
+	{ 1, {  576000, HFPLL, 1,  30 }, L2(6),   825000, 3200000 },
+	{ 1, {  652800, HFPLL, 1,  34 }, L2(6),   825000, 3200000 },
+	{ 0, {  729600, HFPLL, 1,  38 }, L2(6),   825000, 3200000 },
+	{ 1, {  806400, HFPLL, 1,  42 }, L2(8),   825000, 3200000 },
+	{ 1, {  883200, HFPLL, 1,  46 }, L2(8),   825000, 3200000 },
+	{ 1, {  960000, HFPLL, 1,  50 }, L2(8),   835000, 3200000 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(8),   855000, 3200000 },
+	{ 1, { 1113600, HFPLL, 1,  58 }, L2(12),  875000, 3200000 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(12),  895000, 3200000 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(12),  915000, 3200000 },
+	{ 1, { 1344000, HFPLL, 1,  70 }, L2(12),  930000, 3200000 },
+	{ 1, { 1420800, HFPLL, 1,  74 }, L2(16),  945000, 3200000 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  960000, 3200000 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(16),  975000, 3200000 },
+	{ 1, { 1651200, HFPLL, 1,  86 }, L2(16),  990000, 3200000 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(16), 1000000, 3200000 },
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_freq_tbl_pvs3[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 }, L2(0),   825000,  400000 },
+	{ 0, {  345600, HFPLL, 2,  36 }, L2(3),   825000, 3200000 },
+	{ 1, {  422400, HFPLL, 2,  44 }, L2(3),   825000, 3200000 },
+	{ 0, {  499200, HFPLL, 2,  52 }, L2(6),   825000, 3200000 },
+	{ 1, {  576000, HFPLL, 1,  30 }, L2(6),   825000, 3200000 },
+	{ 1, {  652800, HFPLL, 1,  34 }, L2(6),   825000, 3200000 },
+	{ 0, {  729600, HFPLL, 1,  38 }, L2(6),   825000, 3200000 },
+	{ 1, {  806400, HFPLL, 1,  42 }, L2(8),   825000, 3200000 },
+	{ 1, {  883200, HFPLL, 1,  46 }, L2(8),   825000, 3200000 },
+	{ 1, {  960000, HFPLL, 1,  50 }, L2(8),   835000, 3200000 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(8),   855000, 3200000 },
+	{ 1, { 1113600, HFPLL, 1,  58 }, L2(12),  875000, 3200000 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(12),  895000, 3200000 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(12),  915000, 3200000 },
+	{ 1, { 1344000, HFPLL, 1,  70 }, L2(12),  930000, 3200000 },
+	{ 1, { 1420800, HFPLL, 1,  74 }, L2(16),  945000, 3200000 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  960000, 3200000 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(16),  975000, 3200000 },
+	{ 1, { 1651200, HFPLL, 1,  86 }, L2(16),  990000, 3200000 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(16), 1000000, 3200000 },
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_freq_tbl_pvs4[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 }, L2(0),  825000,  400000 },
+	{ 0, {  345600, HFPLL, 2,  36 }, L2(3),  825000, 3200000 },
+	{ 1, {  422400, HFPLL, 2,  44 }, L2(3),  825000, 3200000 },
+	{ 0, {  499200, HFPLL, 2,  52 }, L2(6),  825000, 3200000 },
+	{ 1, {  576000, HFPLL, 1,  30 }, L2(6),  825000, 3200000 },
+	{ 1, {  652800, HFPLL, 1,  34 }, L2(6),  825000, 3200000 },
+	{ 0, {  729600, HFPLL, 1,  38 }, L2(6),  825000, 3200000 },
+	{ 1, {  806400, HFPLL, 1,  42 }, L2(8),  825000, 3200000 },
+	{ 1, {  883200, HFPLL, 1,  46 }, L2(8),  825000, 3200000 },
+	{ 1, {  960000, HFPLL, 1,  50 }, L2(8),  825000, 3200000 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(8),  825000, 3200000 },
+	{ 1, { 1113600, HFPLL, 1,  58 }, L2(12), 835000, 3200000 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(12), 855000, 3200000 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(12), 870000, 3200000 },
+	{ 1, { 1344000, HFPLL, 1,  70 }, L2(12), 885000, 3200000 },
+	{ 1, { 1420800, HFPLL, 1,  74 }, L2(16), 900000, 3200000 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16), 910000, 3200000 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(16), 925000, 3200000 },
+	{ 1, { 1651200, HFPLL, 1,  86 }, L2(16), 940000, 3200000 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(16), 950000, 3200000 },
+	{ 0, { 0 } }
+};
+
+static struct pvs_table pvs_tables[NUM_SPEED_BINS][NUM_PVS] __initdata = {
+	[0][0] = { acpu_freq_tbl_pvs0, sizeof(acpu_freq_tbl_pvs0) },
+	[0][1] = { acpu_freq_tbl_pvs1, sizeof(acpu_freq_tbl_pvs1) },
+	[0][2] = { acpu_freq_tbl_pvs2, sizeof(acpu_freq_tbl_pvs2) },
+	[0][3] = { acpu_freq_tbl_pvs3, sizeof(acpu_freq_tbl_pvs3) },
+	[0][4] = { acpu_freq_tbl_pvs4, sizeof(acpu_freq_tbl_pvs4) },
 };
 
 static struct acpuclk_krait_params acpuclk_8974_params __initdata = {
@@ -184,11 +269,41 @@
 	.l2_freq_tbl_size = sizeof(l2_freq_tbl),
 	.bus_scale = &bus_scale_data,
 	.pte_efuse_phys = 0xFC4B80B0,
+	.get_bin_info = get_krait_bin_format_b,
 	.stby_khz = 300000,
 };
 
+static void __init apply_l2_workaround(void)
+{
+	static struct l2_level resticted_l2_tbl[] __initdata = {
+		[0] = { {  300000, PLL_0, 0,   0 }, LVL_LOW,  1050000, 0 },
+		[1] = { { 1497600, HFPLL, 1,  78 }, LVL_HIGH, 1050000, 7 },
+		{ }
+	};
+	struct acpu_level *l;
+	int s, p;
+
+	for (s = 0; s < NUM_SPEED_BINS; s++)
+		for (p = 0; p < NUM_PVS; p++)
+			for (l = pvs_tables[s][p].table; l && l->speed.khz; l++)
+				l->l2_level = l->l2_level > 5 ? 1 : 0;
+
+	acpuclk_8974_params.l2_freq_tbl = resticted_l2_tbl;
+	acpuclk_8974_params.l2_freq_tbl_size = sizeof(resticted_l2_tbl);
+}
+
 static int __init acpuclk_8974_probe(struct platform_device *pdev)
 {
+	/*
+	 * 8974 hardware revisions older than v1.2 may experience L2 parity
+	 * errors when running at some performance points between 300MHz
+	 * and 1497.6MHz (non-inclusive), or when vdd_mx is less than 1.05V.
+	 * Restrict L2 operation to safe performance points on these devices.
+	 */
+	if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) < 2 &&
+	    SOCINFO_VERSION_MINOR(socinfo_get_version()) < 2)
+		apply_l2_workaround();
+
 	return acpuclk_krait_init(&pdev->dev, &acpuclk_8974_params);
 }
 
diff --git a/arch/arm/mach-msm/acpuclock-krait.c b/arch/arm/mach-msm/acpuclock-krait.c
index 10c4d6c..9566cea 100644
--- a/arch/arm/mach-msm/acpuclock-krait.c
+++ b/arch/arm/mach-msm/acpuclock-krait.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -1019,7 +1019,7 @@
 	.notifier_call = acpuclk_cpu_callback,
 };
 
-static const int krait_needs_vmin(void)
+static const int __init krait_needs_vmin(void)
 {
 	switch (read_cpuid_id()) {
 	case 0x511F04D0: /* KR28M2A20 */
@@ -1031,7 +1031,7 @@
 	};
 }
 
-static void krait_apply_vmin(struct acpu_level *tbl)
+static void __init krait_apply_vmin(struct acpu_level *tbl)
 {
 	for (; tbl->speed.khz != 0; tbl++) {
 		if (tbl->vdd_core < 1150000)
@@ -1040,62 +1040,78 @@
 	}
 }
 
-static int __init get_speed_bin(u32 pte_efuse)
+void __init get_krait_bin_format_a(void __iomem *base, struct bin_info *bin)
 {
-	uint32_t speed_bin;
+	u32 pte_efuse = readl_relaxed(base);
 
-	speed_bin = pte_efuse & 0xF;
-	if (speed_bin == 0xF)
-		speed_bin = (pte_efuse >> 4) & 0xF;
+	bin->speed = pte_efuse & 0xF;
+	if (bin->speed == 0xF)
+		bin->speed = (pte_efuse >> 4) & 0xF;
+	bin->speed_valid = bin->speed != 0xF;
 
-	if (speed_bin == 0xF) {
-		speed_bin = 0;
-		dev_warn(drv.dev, "SPEED BIN: Defaulting to %d\n", speed_bin);
-	} else {
-		dev_info(drv.dev, "SPEED BIN: %d\n", speed_bin);
-	}
-
-	return speed_bin;
+	bin->pvs = (pte_efuse >> 10) & 0x7;
+	if (bin->pvs == 0x7)
+		bin->pvs = (pte_efuse >> 13) & 0x7;
+	bin->pvs_valid = bin->pvs != 0x7;
 }
 
-static int __init get_pvs_bin(u32 pte_efuse)
+void __init get_krait_bin_format_b(void __iomem *base, struct bin_info *bin)
 {
-	uint32_t pvs_bin;
+	u32 pte_efuse, redundant_sel;
 
-	pvs_bin = (pte_efuse >> 10) & 0x7;
-	if (pvs_bin == 0x7)
-		pvs_bin = (pte_efuse >> 13) & 0x7;
+	pte_efuse = readl_relaxed(base);
+	redundant_sel = (pte_efuse >> 24) & 0x7;
+	bin->speed = pte_efuse & 0x7;
+	bin->pvs = (pte_efuse >> 6) & 0x7;
 
-	if (pvs_bin == 0x7) {
-		pvs_bin = 0;
-		dev_warn(drv.dev, "ACPU PVS: Defaulting to %d\n", pvs_bin);
-	} else {
-		dev_info(drv.dev, "ACPU PVS: %d\n", pvs_bin);
+	switch (redundant_sel) {
+	case 1:
+		bin->speed = (pte_efuse >> 27) & 0x7;
+		break;
+	case 2:
+		bin->pvs = (pte_efuse >> 27) & 0x7;
+		break;
 	}
+	bin->speed_valid = true;
 
-	return pvs_bin;
+	/* Check PVS_BLOW_STATUS */
+	pte_efuse = readl_relaxed(base + 0x4);
+	bin->pvs_valid = !!(pte_efuse & BIT(21));
 }
 
-static struct pvs_table * __init select_freq_plan(u32 pte_efuse_phys,
-			struct pvs_table (*pvs_tables)[NUM_PVS])
+static struct pvs_table * __init select_freq_plan(
+		const struct acpuclk_krait_params *params)
 {
-	void __iomem *pte_efuse;
-	u32 pte_efuse_val;
+	void __iomem *pte_efuse_base;
+	struct bin_info bin;
 
-	pte_efuse = ioremap(pte_efuse_phys, 4);
-	if (!pte_efuse) {
-		dev_err(drv.dev, "Unable to map QFPROM base\n");
+	pte_efuse_base = ioremap(params->pte_efuse_phys, 8);
+	if (!pte_efuse_base) {
+		dev_err(drv.dev, "Unable to map PTE eFuse base\n");
 		return NULL;
 	}
+	params->get_bin_info(pte_efuse_base, &bin);
+	iounmap(pte_efuse_base);
 
-	pte_efuse_val = readl_relaxed(pte_efuse);
-	iounmap(pte_efuse);
+	if (bin.speed_valid) {
+		drv.speed_bin = bin.speed;
+		dev_info(drv.dev, "SPEED BIN: %d\n", drv.speed_bin);
+	} else {
+		drv.speed_bin = 0;
+		dev_warn(drv.dev, "SPEED BIN: Defaulting to %d\n",
+			 drv.speed_bin);
+	}
 
-	/* Select frequency tables. */
-	drv.speed_bin = get_speed_bin(pte_efuse_val);
-	drv.pvs_bin = get_pvs_bin(pte_efuse_val);
+	if (bin.pvs_valid) {
+		drv.pvs_bin = bin.pvs;
+		dev_info(drv.dev, "ACPU PVS: %d\n", drv.pvs_bin);
+	} else {
+		drv.pvs_bin = 0;
+		dev_warn(drv.dev, "ACPU PVS: Defaulting to %d\n",
+			 drv.pvs_bin);
+	}
 
-	return &pvs_tables[drv.speed_bin][drv.pvs_bin];
+	return &params->pvs_tables[drv.speed_bin][drv.pvs_bin];
 }
 
 static void __init drv_data_init(struct device *dev,
@@ -1124,7 +1140,7 @@
 		GFP_KERNEL);
 	BUG_ON(!drv.bus_scale->usecase);
 
-	pvs = select_freq_plan(params->pte_efuse_phys, params->pvs_tables);
+	pvs = select_freq_plan(params);
 	BUG_ON(!pvs->table);
 
 	drv.acpu_freq_tbl = kmemdup(pvs->table, pvs->size, GFP_KERNEL);
diff --git a/arch/arm/mach-msm/acpuclock-krait.h b/arch/arm/mach-msm/acpuclock-krait.h
index ca8013e..00f64fc 100644
--- a/arch/arm/mach-msm/acpuclock-krait.h
+++ b/arch/arm/mach-msm/acpuclock-krait.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -152,7 +152,7 @@
 struct acpu_level {
 	const int use_for_scaling;
 	const struct core_speed speed;
-	const unsigned int l2_level;
+	unsigned int l2_level;
 	int vdd_core;
 	int ua_core;
 	unsigned int avsdscr_setting;
@@ -227,6 +227,20 @@
 };
 
 /**
+ * struct bin_info - Hardware speed and voltage binning info.
+ * @speed_valid: @speed field is valid
+ * @pvs_valid: @pvs field is valid
+ * @speed: Speed bin ID
+ * @pvs: PVS bin ID
+ */
+struct bin_info {
+	bool speed_valid;
+	bool pvs_valid;
+	int speed;
+	int pvs;
+};
+
+/**
  * struct pvs_table - CPU performance level table and size.
  * @table: CPU performance level table
  * @size: sizeof(@table)
@@ -247,6 +261,7 @@
  * @l2_freq_tbl: L2 frequency table.
  * @l2_freq_tbl_size: Size of @l2_freq_tbl.
  * @pte_efuse_phys: Physical address of PTE EFUSE.
+ * @get_bin_info: Function to populate bin_info from pte_efuse.
  * @bus_scale: MSM bus driver parameters.
  * @stby_khz: KHz value corresponding to an always-on clock source.
  */
@@ -258,6 +273,7 @@
 	struct l2_level *l2_freq_tbl;
 	size_t l2_freq_tbl_size;
 	phys_addr_t pte_efuse_phys;
+	void (*get_bin_info)(void __iomem *base, struct bin_info *bin);
 	struct msm_bus_scale_pdata *bus_scale;
 	unsigned long stby_khz;
 };
@@ -297,6 +313,16 @@
 };
 
 /**
+ * get_krait_bin_format_a - Populate bin_info from a 'Format A' pte_efuse
+ */
+void __init get_krait_bin_format_a(void __iomem *base, struct bin_info *bin);
+
+/**
+ * get_krait_bin_format_b - Populate bin_info from a 'Format B' pte_efuse
+ */
+void __init get_krait_bin_format_b(void __iomem *base, struct bin_info *bin);
+
+/**
  * acpuclk_krait_init - Initialize the Krait CPU clock driver give SoC params.
  */
 extern int acpuclk_krait_init(struct device *dev,
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index 040660a..9da5436 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -891,6 +891,7 @@
 write_fail3:
 	kfree(pkt);
 write_fail2:
+	skb_pull(skb, sizeof(struct bam_mux_hdr));
 	if (new_skb)
 		dev_kfree_skb_any(new_skb);
 write_fail:
diff --git a/arch/arm/mach-msm/board-8064-bt.c b/arch/arm/mach-msm/board-8064-bt.c
index a8ae9fa..963b1a3 100644
--- a/arch/arm/mach-msm/board-8064-bt.c
+++ b/arch/arm/mach-msm/board-8064-bt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -121,7 +121,7 @@
 
 	const struct bahama_config_register *p;
 
-	u8 version;
+	int version;
 
 	const struct bahama_config_register v10_bt_on[] = {
 		{ 0xE9, 0x00, 0xFF },
@@ -203,7 +203,7 @@
 	u8 offset = 0; /* index into bahama configs */
 	on = on ? 1 : 0;
 	version = marimba_read_bahama_ver(&config);
-	if ((int)version < 0 || version == BAHAMA_VER_UNSUPPORTED) {
+	if (version < 0 || version == BAHAMA_VER_UNSUPPORTED) {
 		dev_err(&msm_bt_power_device.dev,
 			"%s : Bahama version read Error, version = %d\n",
 			__func__, version);
@@ -237,10 +237,9 @@
 				__func__, (p+i)->reg,
 				value, (p+i)->mask);
 		value = 0;
-		rc = marimba_read_bit_mask(&config,
+		if (marimba_read_bit_mask(&config,
 				(p+i)->reg, &value,
-				sizeof((p+i)->value), (p+i)->mask);
-		if (rc < 0)
+				sizeof((p+i)->value), (p+i)->mask) < 0)
 			dev_err(&msm_bt_power_device.dev,
 				"%s marimba_read_bit_mask- error",
 				__func__);
@@ -298,15 +297,14 @@
 			dev_err(&msm_bt_power_device.dev,
 				"%s: could not %sable regulator %s: %d\n",
 					__func__, "dis", bt_vregs[i].name, rc);
-			goto reg_disable;
 		}
 	}
 
 	return rc;
 reg_disable:
 	pr_err("bluetooth_switch_regulators - FAIL!!!!\n");
-	while (i) {
-		if (on) {
+	if (on) {
+		while (i) {
 			i--;
 			regulator_disable(bt_vregs[i].reg);
 			regulator_put(bt_vregs[i].reg);
@@ -419,8 +417,9 @@
 	int rc = 0;
 	const char *id = "BTPW";
 	int cid = 0;
+	int bt_state = 0;
+	struct marimba config = { .mod_id =  SLAVE_ID_BAHAMA};
 
-	pr_debug("bluetooth_power entered....\n");
 	cid = adie_get_detected_connectivity_type();
 	if (cid != BAHAMA_ID) {
 		pr_err("%s: unexpected adie connectivity type: %d\n",
@@ -429,6 +428,7 @@
 	}
 
 	if (on) {
+		pr_debug("%s: Powering up the BT module.\n", __func__);
 		rc = bluetooth_switch_regulators(on);
 		if (rc < 0) {
 			pr_err("%s: bluetooth_switch_regulators rc = %d",
@@ -437,11 +437,13 @@
 		}
 		/* UART GPIO configuration to be done by by UART module*/
 		/*Setup BT clocks*/
+		pr_debug("%s: Voting for the 19.2MHz clock\n", __func__);
 		bt_clock = msm_xo_get(MSM_XO_TCXO_A2, id);
 		if (IS_ERR(bt_clock)) {
 			rc = PTR_ERR(bt_clock);
 			pr_err("%s: failed to get the handle for A2(%d)\n",
 					__func__, rc);
+			goto fail_power;
 		}
 		rc = msm_xo_mode_vote(bt_clock, MSM_XO_MODE_ON);
 		if (rc < 0) {
@@ -451,20 +453,23 @@
 		msleep(20);
 
 		/*I2C config for Bahama*/
+		pr_debug("%s: BT Turn On sequence in-progress.\n", __func__);
 		rc = bahama_bt(1);
 		if (rc < 0) {
 			pr_err("%s: bahama_bt rc = %d", __func__, rc);
-			goto fail_i2c;
+			goto fail_xo_vote;
 		}
 		msleep(20);
 
 		/*setup BT PCM lines*/
+		pr_debug("%s: Configuring PCM lines.\n", __func__);
 		rc = config_pcm(BT_PCM_ON);
 		if (rc < 0) {
-			pr_err("%s: config_pcm , rc =%d\n",
+			pr_err("%s: config_pcm , rc = %d\n",
 				__func__, rc);
-				goto fail_power;
+			goto fail_i2c;
 		}
+		pr_debug("%s: BT Turn On complete.\n", __func__);
 		/* TO DO - Enable PIN CTRL */
 		/*
 		rc = msm_xo_mode_vote(bt_clock, MSM_XO_MODE_PIN_CTRL);
@@ -474,9 +479,12 @@
 			goto fail_xo_vote;
 		} */
 	} else {
-		rc = bahama_bt(0);
-		if (rc < 0)
-			pr_err("%s: bahama_bt rc = %d", __func__, rc);
+		pr_debug("%s: Turning BT Off.\n", __func__);
+		bt_state = marimba_get_bt_status(&config);
+		if (!bt_state) {
+			pr_err("%s: BT is already turned OFF.\n", __func__);
+			return 0;
+		}
 
 		rc = config_pcm(BT_PCM_OFF);
 		if (rc < 0) {
@@ -484,19 +492,21 @@
 				__func__, rc);
 		}
 fail_i2c:
-		pr_err("bluetooth_power...FAIL_I2C\n");
-
+		rc = bahama_bt(0);
+		if (rc < 0)
+			pr_err("%s: bahama_bt rc = %d", __func__, rc);
 fail_xo_vote:
-		pr_err("bluetooth_power...FAIL_XO_VOTE\n");
+		pr_debug("%s: Voting off the 19.2MHz clk\n", __func__);
 		msm_xo_put(bt_clock);
 fail_power:
-		pr_err("bluetooth_power...FAIL POWER\n");
+		pr_debug("%s: Switching off voltage regulators.\n", __func__);
 		rc = bluetooth_switch_regulators(0);
 		if (rc < 0) {
 			pr_err("%s: switch_regulators : rc = %d",\
 				__func__, rc);
 			goto exit;
 		}
+		pr_debug("%s: BT Power Off complete.\n", __func__);
 	}
 	return rc;
 exit:
diff --git a/arch/arm/mach-msm/board-8064-gpiomux.c b/arch/arm/mach-msm/board-8064-gpiomux.c
index 67760ee..57d1b6c 100644
--- a/arch/arm/mach-msm/board-8064-gpiomux.c
+++ b/arch/arm/mach-msm/board-8064-gpiomux.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -74,259 +74,207 @@
 #endif
 
 #ifdef CONFIG_MSM_VCAP
-static struct gpiomux_setting gpio_vcap_config[] = {
-	{
-		.func = GPIOMUX_FUNC_GPIO,
-		.drv = GPIOMUX_DRV_2MA,
-		.pull = GPIOMUX_PULL_DOWN,
-	},
-	{
-		.func = GPIOMUX_FUNC_1,
-		.drv = GPIOMUX_DRV_2MA,
-		.pull = GPIOMUX_PULL_DOWN,
-	},
-	{
-		.func = GPIOMUX_FUNC_2,
-		.drv = GPIOMUX_DRV_2MA,
-		.pull = GPIOMUX_PULL_DOWN,
-	},
-	{
-		.func = GPIOMUX_FUNC_3,
-		.drv = GPIOMUX_DRV_2MA,
-		.pull = GPIOMUX_PULL_DOWN,
-	},
-	{
-		.func = GPIOMUX_FUNC_4,
-		.drv = GPIOMUX_DRV_2MA,
-		.pull = GPIOMUX_PULL_DOWN,
-	},
-	{
-		.func = GPIOMUX_FUNC_5,
-		.drv = GPIOMUX_DRV_2MA,
-		.pull = GPIOMUX_PULL_DOWN,
-	},
-	{
-		.func = GPIOMUX_FUNC_6,
-		.drv = GPIOMUX_DRV_2MA,
-		.pull = GPIOMUX_PULL_DOWN,
-	},
-	{
-		.func = GPIOMUX_FUNC_7,
-		.drv = GPIOMUX_DRV_2MA,
-		.pull = GPIOMUX_PULL_DOWN,
-	},
-	{
-		.func = GPIOMUX_FUNC_8,
-		.drv = GPIOMUX_DRV_2MA,
-		.pull = GPIOMUX_PULL_DOWN,
-	},
-	{
-		.func = GPIOMUX_FUNC_9,
-		.drv = GPIOMUX_DRV_2MA,
-		.pull = GPIOMUX_PULL_DOWN,
-	},
-	{
-		.func = GPIOMUX_FUNC_A,
-		.drv = GPIOMUX_DRV_2MA,
-		.pull = GPIOMUX_PULL_DOWN,
-	},
+static struct gpiomux_setting gpio_vcap_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
 };
 
 struct msm_gpiomux_config vcap_configs[] = {
 	{
 		.gpio = 20,
 		.settings = {
-			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[7],
-			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[7],
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config,
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config,
 		}
 	},
 	{
 		.gpio = 25,
 		.settings = {
-			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[2],
-			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[2],
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config,
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config,
 		}
 	},
 	{
 		.gpio = 24,
 		.settings = {
-			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[1],
-			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[1],
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config,
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config,
 		}
 	},
 	{
 		.gpio = 23,
 		.settings = {
-			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[2],
-			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[2],
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config,
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config,
 		}
 	},
 	{
 		.gpio = 19,
 		.settings = {
-			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[8],
-			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[8],
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config,
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config,
 		}
 	},
 	{
 		.gpio = 22,
 		.settings = {
-			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[2],
-			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[2],
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config,
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config,
 		}
 	},
 	{
 		.gpio = 21,
 		.settings = {
-			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[7],
-			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[7],
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config,
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config,
 		}
 	},
 	{
 		.gpio = 12,
 		.settings = {
-			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[6],
-			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[6],
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config,
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config,
 		}
 	},
 	{
 		.gpio = 18,
 		.settings = {
-			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[9],
-			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[9],
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config,
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config,
 		}
 	},
 	{
 		.gpio = 11,
 		.settings = {
-			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[10],
-			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[10],
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config,
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config,
 		}
 	},
 	{
 		.gpio = 10,
 		.settings = {
-			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[9],
-			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[9],
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config,
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config,
 		}
 	},
 	{
 		.gpio = 9,
 		.settings = {
-			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[2],
-			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[2],
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config,
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config,
 		}
 	},
 	{
 		.gpio = 26,
 		.settings = {
-			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[1],
-			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[1],
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config,
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config,
 		}
 	},
 	{
 		.gpio = 8,
 		.settings = {
-			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[3],
-			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[3],
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config,
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config,
 		}
 	},
 	{
 		.gpio = 7,
 		.settings = {
-			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[7],
-			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[7],
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config,
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config,
 		}
 	},
 	{
 		.gpio = 6,
 		.settings = {
-			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[7],
-			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[7],
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config,
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config,
 		}
 	},
 	{
 		.gpio = 80,
 		.settings = {
-			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[2],
-			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[2],
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config,
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config,
 		}
 	},
 	{
 		.gpio = 86,
 		.settings = {
-			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[1],
-			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[1],
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config,
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config,
 		}
 	},
 	{
 		.gpio = 85,
 		.settings = {
-			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[4],
-			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[4],
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config,
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config,
 		}
 	},
 	{
 		.gpio = 84,
 		.settings = {
-			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[3],
-			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[3],
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config,
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config,
 		}
 	},
 	{
 		.gpio = 5,
 		.settings = {
-			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[2],
-			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[2],
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config,
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config,
 		}
 	},
 	{
 		.gpio = 4,
 		.settings = {
-			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[3],
-			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[3],
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config,
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config,
 		}
 	},
 	{
 		.gpio = 3,
 		.settings = {
-			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[6],
-			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[6],
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config,
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config,
 		}
 	},
 	{
 		.gpio = 2,
 		.settings = {
-			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[5],
-			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[5],
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config,
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config,
 		}
 	},
 	{
 		.gpio = 82,
 		.settings = {
-			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[4],
-			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[4],
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config,
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config,
 		}
 	},
 	{
 		.gpio = 83,
 		.settings = {
-			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[4],
-			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[4],
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config,
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config,
 		}
 	},
 	{
 		.gpio = 87,
 		.settings = {
-			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[2],
-			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[2],
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config,
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config,
 		}
 	},
 	{
 		.gpio = 13,
 		.settings = {
-			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[6],
-			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[6],
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config,
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config,
 		}
 	},
 };
@@ -1621,6 +1569,10 @@
 	} else {
 		msm_gpiomux_install(apq8064_slimbus_config,
 				ARRAY_SIZE(apq8064_slimbus_config));
+	}
+
+	if (!(machine_is_mpq8064_cdp() || machine_is_mpq8064_hrd() ||
+		 machine_is_mpq8064_dtv()) && !machine_is_apq8064_mtp()) {
 		msm_gpiomux_install(apq8064_gsbi1_i2c_8ma_configs,
 				ARRAY_SIZE(apq8064_gsbi1_i2c_8ma_configs));
 	}
@@ -1705,8 +1657,11 @@
 			     ARRAY_SIZE(apq8064_sdc4_configs));
 #endif
 
-	msm_gpiomux_install(apq8064_sdc3_configs,
-			ARRAY_SIZE(apq8064_sdc3_configs));
+	if (!(machine_is_mpq8064_cdp() || machine_is_mpq8064_hrd() ||
+		 machine_is_mpq8064_dtv())) {
+		msm_gpiomux_install(apq8064_sdc3_configs,
+				ARRAY_SIZE(apq8064_sdc3_configs));
+	}
 	 if (machine_is_mpq8064_hrd() || machine_is_mpq8064_dtv())
 		msm_gpiomux_install(mpq8064_uartdm_configs,
 				ARRAY_SIZE(mpq8064_uartdm_configs));
diff --git a/arch/arm/mach-msm/board-8064-regulator.c b/arch/arm/mach-msm/board-8064-regulator.c
index 16b53fb..57ecc27 100644
--- a/arch/arm/mach-msm/board-8064-regulator.c
+++ b/arch/arm/mach-msm/board-8064-regulator.c
@@ -458,6 +458,16 @@
 		.active_low	= _active_low, \
 	}
 
+#define FIXED_VREG_INIT(_id, _supply_regulator) \
+	{ \
+		.constraints = { \
+			.valid_ops_mask	= REGULATOR_CHANGE_STATUS, \
+		}, \
+		.num_consumer_supplies	= ARRAY_SIZE(vreg_consumers_##_id), \
+		.consumer_supplies	= vreg_consumers_##_id, \
+		.supply_regulator	= _supply_regulator, \
+	}
+
 #define SAW_VREG_INIT(_id, _name, _min_uV, _max_uV) \
 	{ \
 		.constraints = { \
@@ -597,6 +607,17 @@
 					SX150X_GPIO(4, 15), "avc_5v", 0),
 };
 
+/* Fixed regulator constraints */
+static struct regulator_init_data mpq8064_3p3_regulator_init =
+	/*              ID        supply */
+	FIXED_VREG_INIT(EXT_3P3V, NULL);
+
+struct fixed_voltage_config mpq8064_3p3_regulator_pdata = {
+	.supply_name = "ext_3p3v",
+	.gpio = -EINVAL,
+	.init_data = &mpq8064_3p3_regulator_init,
+};
+
 /* SAW regulator constraints */
 struct regulator_init_data msm8064_saw_regulator_pdata_8921_s5 =
 	/*	      ID  vreg_name	       min_uV   max_uV */
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 3fe0838..476a191 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -2073,9 +2073,8 @@
 {
 	msm_shared_ram_phys = MSM_SHARED_RAM_PHYS;
 	msm_map_apq8064_io();
-
-	if (IS_ERR_OR_NULL(socinfo_init()))
-		pr_err("socinfo_init() failed!\n");
+	if (socinfo_init() < 0)
+		pr_err("%s: socinfo_init() failed\n", __func__);
 }
 
 static void __init apq8064_init_irq(void)
@@ -2494,6 +2493,13 @@
 	}
 }
 
+static struct platform_device mpq8064_device_ext_3p3v_vreg = {
+	.name			= "reg-fixed-voltage",
+	.dev			= {
+		.platform_data	= &mpq8064_3p3_regulator_pdata,
+	},
+};
+
 static struct platform_device apq8064_device_ext_5v_vreg __devinitdata = {
 	.name	= GPIO_REGULATOR_DEV_NAME,
 	.id	= PM8921_MPP_PM_TO_SYS(7),
@@ -2605,6 +2611,7 @@
 static struct platform_device *pm8921_mpq_hrd_common_devices[] __initdata = {
 	&apq8064_device_ext_5v_vreg,
 	&apq8064_device_ext_mpp8_vreg,
+	&mpq8064_device_ext_3p3v_vreg,
 	&apq8064_device_ssbi_pmic1,
 	&apq8064_device_ssbi_pmic2,
 };
@@ -3580,7 +3587,7 @@
 	platform_device_register(&msm_gpio_device);
 	msm_tsens_early_init(&apq_tsens_pdata);
 	msm_thermal_init(&msm_thermal_pdata);
-	if (IS_ERR_OR_NULL(socinfo_init()))
+	if (socinfo_init() < 0)
 		pr_err("socinfo_init() failed!\n");
 	BUG_ON(msm_rpm_init(&apq8064_rpm_data));
 	BUG_ON(msm_rpmrs_levels_init(&msm_rpmrs_data));
diff --git a/arch/arm/mach-msm/board-8064.h b/arch/arm/mach-msm/board-8064.h
index 4cdf939..adc037b 100644
--- a/arch/arm/mach-msm/board-8064.h
+++ b/arch/arm/mach-msm/board-8064.h
@@ -14,6 +14,7 @@
 #define __ARCH_ARM_MACH_MSM_BOARD_APQ8064_H
 
 #include <linux/regulator/msm-gpio-regulator.h>
+#include <linux/regulator/fixed.h>
 #include <linux/mfd/pm8xxx/pm8921.h>
 #include <linux/mfd/pm8xxx/pm8821.h>
 #include <mach/msm_memtypes.h>
@@ -65,6 +66,8 @@
 extern struct gpio_regulator_platform_data
 	mpq8064_gpio_regulator_pdata[] __devinitdata;
 
+extern struct fixed_voltage_config mpq8064_3p3_regulator_pdata;
+
 extern struct rpm_regulator_platform_data
 	apq8064_rpm_regulator_pdata __devinitdata;
 
diff --git a/arch/arm/mach-msm/board-8092.c b/arch/arm/mach-msm/board-8092.c
index c7d01bf..b4c63f9 100644
--- a/arch/arm/mach-msm/board-8092.c
+++ b/arch/arm/mach-msm/board-8092.c
@@ -96,10 +96,8 @@
 static void __init mpq8092_init(void)
 {
 	struct of_dev_auxdata *adata = mpq8092_auxdata_lookup;
-	struct device *parent;
 
-	parent = socinfo_init();
-	if (IS_ERR_OR_NULL(parent))
+	if (socinfo_init() < 0)
 		pr_err("%s: socinfo_init() failed\n", __func__);
 
 	mpq8092_init_gpiomux();
diff --git a/arch/arm/mach-msm/board-8226.c b/arch/arm/mach-msm/board-8226.c
index 0f8bfd4..3a6eb7f 100644
--- a/arch/arm/mach-msm/board-8226.c
+++ b/arch/arm/mach-msm/board-8226.c
@@ -42,9 +42,14 @@
 #include <mach/socinfo.h>
 #include <mach/board.h>
 #include <mach/clk-provider.h>
+#include <mach/msm_smd.h>
+#include <mach/rpm-smd.h>
+#include <linux/msm_thermal.h>
 #include "board-dt.h"
 #include "clock.h"
 #include "platsmp.h"
+#include "spm.h"
+#include "lpm_resources.h"
 
 static struct memtype_reserve msm8226_reserve_table[] __initdata = {
 	[MEMTYPE_SMI] = {
@@ -121,19 +126,27 @@
 	msm_reserve();
 }
 
+
+void __init msm8226_add_drivers(void)
+{
+	msm_rpm_driver_init();
+	msm_lpmrs_module_init();
+	msm_spm_device_init();
+	msm_thermal_device_init();
+}
+
 void __init msm8226_init(void)
 {
 	struct of_dev_auxdata *adata = msm8226_auxdata_lookup;
-	struct device *parent;
 
-	parent = socinfo_init();
-	if (IS_ERR_OR_NULL(parent))
+	if (socinfo_init() < 0)
 		pr_err("%s: socinfo_init() failed\n", __func__);
 
 	msm8226_init_gpiomux();
-
+	msm8226_add_drivers();
 	msm_clock_init(&msm_dummy_clock_init_data);
 	of_platform_populate(NULL, of_default_bus_match_table, adata, NULL);
+
 }
 
 static const char *msm8226_dt_match[] __initconst = {
@@ -143,7 +156,7 @@
 
 DT_MACHINE_START(MSM8226_DT, "Qualcomm MSM 8226 (Flattened Device Tree)")
 	.map_io = msm_map_msm8226_io,
-	.init_irq = msm_dt_init_irq_nompm,
+	.init_irq = msm_dt_init_irq,
 	.init_machine = msm8226_init,
 	.handle_irq = gic_handle_irq,
 	.timer = &msm_dt_timer,
diff --git a/arch/arm/mach-msm/board-8910-gpiomux.c b/arch/arm/mach-msm/board-8610-gpiomux.c
similarity index 86%
rename from arch/arm/mach-msm/board-8910-gpiomux.c
rename to arch/arm/mach-msm/board-8610-gpiomux.c
index a295a17..49d8236 100644
--- a/arch/arm/mach-msm/board-8910-gpiomux.c
+++ b/arch/arm/mach-msm/board-8610-gpiomux.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -17,7 +17,7 @@
 #include <mach/gpio.h>
 #include <mach/gpiomux.h>
 
-void __init msm8910_init_gpiomux(void)
+void __init msm8610_init_gpiomux(void)
 {
 	int rc;
 
diff --git a/arch/arm/mach-msm/board-8910.c b/arch/arm/mach-msm/board-8610.c
similarity index 64%
rename from arch/arm/mach-msm/board-8910.c
rename to arch/arm/mach-msm/board-8610.c
index f779c1f..0e514dc 100644
--- a/arch/arm/mach-msm/board-8910.c
+++ b/arch/arm/mach-msm/board-8610.c
@@ -44,7 +44,7 @@
 #include "clock.h"
 #include "platsmp.h"
 
-static struct memtype_reserve msm8910_reserve_table[] __initdata = {
+static struct memtype_reserve msm8610_reserve_table[] __initdata = {
 	[MEMTYPE_SMI] = {
 	},
 	[MEMTYPE_EBI0] = {
@@ -55,12 +55,12 @@
 	},
 };
 
-static int msm8910_paddr_to_memtype(unsigned int paddr)
+static int msm8610_paddr_to_memtype(unsigned int paddr)
 {
 	return MEMTYPE_EBI1;
 }
 
-static struct of_dev_auxdata msm8910_auxdata_lookup[] __initdata = {
+static struct of_dev_auxdata msm8610_auxdata_lookup[] __initdata = {
 	OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF9824000, \
 			"msm_sdcc.1", NULL),
 	OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF98A4000, \
@@ -68,54 +68,52 @@
 	{}
 };
 
-static struct reserve_info msm8910_reserve_info __initdata = {
-	.memtype_reserve_table = msm8910_reserve_table,
-	.paddr_to_memtype = msm8910_paddr_to_memtype,
+static struct reserve_info msm8610_reserve_info __initdata = {
+	.memtype_reserve_table = msm8610_reserve_table,
+	.paddr_to_memtype = msm8610_paddr_to_memtype,
 };
 
-static void __init msm8910_early_memory(void)
+static void __init msm8610_early_memory(void)
 {
-	reserve_info = &msm8910_reserve_info;
-	of_scan_flat_dt(dt_scan_for_memory_reserve, msm8910_reserve_table);
+	reserve_info = &msm8610_reserve_info;
+	of_scan_flat_dt(dt_scan_for_memory_reserve, msm8610_reserve_table);
 }
 
-static void __init msm8910_reserve(void)
+static void __init msm8610_reserve(void)
 {
 	msm_reserve();
 }
 
-void __init msm8910_init(void)
+void __init msm8610_init(void)
 {
-	struct of_dev_auxdata *adata = msm8910_auxdata_lookup;
-	struct device *parent;
+	struct of_dev_auxdata *adata = msm8610_auxdata_lookup;
 
-	parent = socinfo_init();
-	if (IS_ERR_OR_NULL(parent))
+	if (socinfo_init() < 0)
 		pr_err("%s: socinfo_init() failed\n", __func__);
 
-	msm8910_init_gpiomux();
+	msm8610_init_gpiomux();
 
-	if (machine_is_msm8910_rumi())
-		msm_clock_init(&msm8910_rumi_clock_init_data);
+	if (machine_is_msm8610_rumi())
+		msm_clock_init(&msm8610_rumi_clock_init_data);
 	else
-		msm_clock_init(&msm8910_clock_init_data);
+		msm_clock_init(&msm8610_clock_init_data);
 	of_platform_populate(NULL, of_default_bus_match_table, adata, NULL);
 }
 
-static const char *msm8910_dt_match[] __initconst = {
-	"qcom,msm8910",
+static const char *msm8610_dt_match[] __initconst = {
+	"qcom,msm8610",
 	NULL
 };
 
-DT_MACHINE_START(MSM8910_DT, "Qualcomm MSM 8910 (Flattened Device Tree)")
-	.map_io = msm_map_msm8910_io,
+DT_MACHINE_START(MSM8610_DT, "Qualcomm MSM 8610 (Flattened Device Tree)")
+	.map_io = msm_map_msm8610_io,
 	.init_irq = msm_dt_init_irq_nompm,
-	.init_machine = msm8910_init,
+	.init_machine = msm8610_init,
 	.handle_irq = gic_handle_irq,
 	.timer = &msm_dt_timer,
-	.dt_compat = msm8910_dt_match,
+	.dt_compat = msm8610_dt_match,
 	.restart = msm_restart,
-	.reserve = msm8910_reserve,
-	.init_very_early = msm8910_early_memory,
+	.reserve = msm8610_reserve,
+	.init_very_early = msm8610_early_memory,
 	.smp = &arm_smp_ops,
 MACHINE_END
diff --git a/arch/arm/mach-msm/board-8930-pmic.c b/arch/arm/mach-msm/board-8930-pmic.c
index c0402ef..4fb5fe9 100644
--- a/arch/arm/mach-msm/board-8930-pmic.c
+++ b/arch/arm/mach-msm/board-8930-pmic.c
@@ -455,7 +455,7 @@
 
 static struct pm8xxx_spk_platform_data pm8xxx_spk_pdata = {
 	.spk_add_enable		= false,
-	.cd_ng_threshold	= 0x6,
+	.cd_ng_threshold	= 0x0,
 	.cd_nf_preamp_bias	= 0x1,
 	.cd_ng_hold		= 0x6,
 	.cd_ng_max_atten	= 0x0,
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index 194c77f..6323c49 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -1465,7 +1465,7 @@
 	msm_shared_ram_phys = MSM_SHARED_RAM_PHYS;
 	msm_map_msm8930_io();
 
-	if (IS_ERR_OR_NULL(socinfo_init()))
+	if (socinfo_init() < 0)
 		pr_err("socinfo_init() failed!\n");
 
 }
@@ -2502,7 +2502,6 @@
 	&msm_pcm_hostless,
 	&msm_multi_ch_pcm,
 	&msm_lowlatency_pcm,
-	&msm_fm_loopback,
 };
 
 static void __init msm8930_i2c_init(void)
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index f4e7880..3e71725 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -1438,26 +1438,49 @@
 
 static struct resource tspp_resources[] = {
 	[0] = {
+		.name = "TSIF_TSPP_IRQ",
 		.flags = IORESOURCE_IRQ,
 		.start = TSIF_TSPP_IRQ,
-		.end   = TSIF1_IRQ,
+		.end   = TSIF_TSPP_IRQ,
 	},
 	[1] = {
+		.name = "TSIF0_IRQ",
+		.flags = IORESOURCE_IRQ,
+		.start = TSIF1_IRQ,
+		.end   = TSIF1_IRQ,
+	},
+	[2] = {
+		.name = "TSIF1_IRQ",
+		.flags = IORESOURCE_IRQ,
+		.start = TSIF2_IRQ,
+		.end   = TSIF2_IRQ,
+	},
+	[3] = {
+		.name = "TSIF_BAM_IRQ",
+		.flags = IORESOURCE_IRQ,
+		.start = TSIF_BAM_IRQ,
+		.end   = TSIF_BAM_IRQ,
+	},
+	[4] = {
+		.name = "MSM_TSIF0_PHYS",
 		.flags = IORESOURCE_MEM,
 		.start = MSM_TSIF0_PHYS,
 		.end   = MSM_TSIF0_PHYS + MSM_TSIF_SIZE - 1,
 	},
-	[2] = {
+	[5] = {
+		.name = "MSM_TSIF1_PHYS",
 		.flags = IORESOURCE_MEM,
 		.start = MSM_TSIF1_PHYS,
 		.end   = MSM_TSIF1_PHYS + MSM_TSIF_SIZE - 1,
 	},
-	[3] = {
+	[6] = {
+		.name = "MSM_TSPP_PHYS",
 		.flags = IORESOURCE_MEM,
 		.start = MSM_TSPP_PHYS,
 		.end   = MSM_TSPP_PHYS + MSM_TSPP_SIZE - 1,
 	},
-	[4] = {
+	[7] = {
+		.name = "MSM_TSPP_BAM_PHYS",
 		.flags = IORESOURCE_MEM,
 		.start = MSM_TSPP_BAM_PHYS,
 		.end   = MSM_TSPP_BAM_PHYS + MSM_TSPP_BAM_SIZE - 1,
@@ -1487,7 +1510,7 @@
 {
 	msm_shared_ram_phys = MSM_SHARED_RAM_PHYS;
 	msm_map_msm8960_io();
-	if (IS_ERR_OR_NULL(socinfo_init()))
+	if (socinfo_init() < 0)
 		pr_err("socinfo_init() failed!\n");
 
 }
diff --git a/arch/arm/mach-msm/board-8974-gpiomux.c b/arch/arm/mach-msm/board-8974-gpiomux.c
index b1e107d..ac93b00 100644
--- a/arch/arm/mach-msm/board-8974-gpiomux.c
+++ b/arch/arm/mach-msm/board-8974-gpiomux.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
diff --git a/arch/arm/mach-msm/board-8974.c b/arch/arm/mach-msm/board-8974.c
index b90d75b..2fdceae 100644
--- a/arch/arm/mach-msm/board-8974.c
+++ b/arch/arm/mach-msm/board-8974.c
@@ -300,6 +300,8 @@
 static struct of_dev_auxdata msm8974_auxdata_lookup[] __initdata = {
 	OF_DEV_AUXDATA("qcom,hsusb-otg", 0xF9A55000, \
 			"msm_otg", NULL),
+	OF_DEV_AUXDATA("qcom,ehci-host", 0xF9A55000, \
+			"msm_ehci_host", NULL),
 	OF_DEV_AUXDATA("qcom,dwc-usb3-msm", 0xF9200000, \
 			"msm_dwc3", NULL),
 	OF_DEV_AUXDATA("qcom,usb-bam-msm", 0xF9304000, \
@@ -364,10 +366,8 @@
 void __init msm8974_init(void)
 {
 	struct of_dev_auxdata *adata = msm8974_auxdata_lookup;
-	struct device *parent;
 
-	parent = socinfo_init();
-	if (IS_ERR_OR_NULL(parent))
+	if (socinfo_init() < 0)
 		pr_err("%s: socinfo_init() failed\n", __func__);
 
 	msm_8974_init_gpiomux();
diff --git a/arch/arm/mach-msm/board-9625.c b/arch/arm/mach-msm/board-9625.c
index 07c37dd..9cfee09 100644
--- a/arch/arm/mach-msm/board-9625.c
+++ b/arch/arm/mach-msm/board-9625.c
@@ -237,10 +237,7 @@
 
 void __init msm9625_init(void)
 {
-	struct device *parent;
-
-	parent = socinfo_init();
-	if (IS_ERR_OR_NULL(parent))
+	if (socinfo_init() < 0)
 		pr_err("%s: socinfo_init() failed\n", __func__);
 
 	msm9625_init_gpiomux();
diff --git a/arch/arm/mach-msm/board-fsm9xxx.c b/arch/arm/mach-msm/board-fsm9xxx.c
index 16740b2..cb2e766 100644
--- a/arch/arm/mach-msm/board-fsm9xxx.c
+++ b/arch/arm/mach-msm/board-fsm9xxx.c
@@ -1002,7 +1002,7 @@
 {
 	msm_shared_ram_phys = 0x00100000;
 	msm_map_fsm9xxx_io();
-	if (IS_ERR_OR_NULL(socinfo_init()))
+	if (socinfo_init() < 0)
 		pr_err("socinfo_init() failed!\n");
 }
 
diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c
index 752c99a..0654a0d 100644
--- a/arch/arm/mach-msm/board-msm7x30.c
+++ b/arch/arm/mach-msm/board-msm7x30.c
@@ -7349,7 +7349,7 @@
 {
 	msm_shared_ram_phys = 0x00100000;
 	msm_map_msm7x30_io();
-	if (IS_ERR_OR_NULL(socinfo_init()))
+	if (socinfo_init() < 0)
 		pr_err("socinfo_init() failed!\n");
 }
 
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index e678dfb..c45cf11 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -7541,7 +7541,7 @@
 {
 	msm_shared_ram_phys = MSM_SHARED_RAM_PHYS;
 	msm_map_msm8x60_io();
-	if (IS_ERR_OR_NULL(socinfo_init()))
+	if (socinfo_init() < 0)
 		pr_err("socinfo_init() failed!\n");
 
 }
diff --git a/arch/arm/mach-msm/board-qsd8x50.c b/arch/arm/mach-msm/board-qsd8x50.c
index 57c548e..e3b42bc 100644
--- a/arch/arm/mach-msm/board-qsd8x50.c
+++ b/arch/arm/mach-msm/board-qsd8x50.c
@@ -2521,7 +2521,7 @@
 	msm_shared_ram_phys = MSM_SHARED_RAM_PHYS;
 	msm_map_qsd8x50_io();
 	qsd8x50_allocate_memory_regions();
-	if (IS_ERR_OR_NULL(socinfo_init()))
+	if (socinfo_init() < 0)
 		pr_err("socinfo_init() failed!\n");
 }
 
diff --git a/arch/arm/mach-msm/clock-8910.c b/arch/arm/mach-msm/clock-8610.c
similarity index 98%
rename from arch/arm/mach-msm/clock-8910.c
rename to arch/arm/mach-msm/clock-8610.c
index c5541b4..159f151 100644
--- a/arch/arm/mach-msm/clock-8910.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -1272,6 +1272,8 @@
 	.cbcr_reg = LPASS_Q6_AXI_CBCR,
 	.has_sibling = 1,
 	.base = &virt_bases[GCC_BASE],
+	 /* FIXME: Remove this once simulation is fixed. */
+	.halt_check = DELAY,
 	.c = {
 		.dbg_name = "gcc_lpass_q6_axi_clk",
 		.ops = &clk_ops_branch,
@@ -1735,6 +1737,8 @@
 	.cbcr_reg = BIMC_GFX_CBCR,
 	.has_sibling = 1,
 	.base = &virt_bases[MMSS_BASE],
+	 /* FIXME: Remove this once simulation is fixed. */
+	.halt_check = DELAY,
 	.c = {
 		.dbg_name = "bimc_gfx_clk",
 		.ops = &clk_ops_branch,
@@ -1843,7 +1847,7 @@
 	.has_sibling = 1,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
-		.parent = &csi0_clk_src.c,
+		.parent = &csi1_clk_src.c,
 		.dbg_name = "csi1pix_clk",
 		.ops = &clk_ops_branch,
 		CLK_INIT(csi1pix_clk.c),
@@ -1855,7 +1859,7 @@
 	.has_sibling = 1,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
-		.parent = &csi0_clk_src.c,
+		.parent = &csi1_clk_src.c,
 		.dbg_name = "csi1rdi_clk",
 		.ops = &clk_ops_branch,
 		CLK_INIT(csi1rdi_clk.c),
@@ -1995,6 +1999,8 @@
 	.cbcr_reg = MDP_AXI_CBCR,
 	.has_sibling = 1,
 	.base = &virt_bases[MMSS_BASE],
+	 /* FIXME: Remove this once simulation is fixed. */
+	.halt_check = DELAY,
 	.c = {
 		.parent = &axi_clk_src.c,
 		.dbg_name = "mdp_axi_clk",
@@ -2148,6 +2154,8 @@
 	.cbcr_reg = VFE_AXI_CBCR,
 	.has_sibling = 1,
 	.base = &virt_bases[MMSS_BASE],
+	 /* FIXME: Remove this once simulation is fixed. */
+	.halt_check = DELAY,
 	.c = {
 		.parent = &axi_clk_src.c,
 		.dbg_name = "vfe_axi_clk",
@@ -2921,7 +2929,7 @@
 	.multiplier = 1,
 };
 
-static struct clk_lookup msm_clocks_8910[] = {
+static struct clk_lookup msm_clocks_8610[] = {
 	CLK_LOOKUP("xo",	gcc_xo_clk_src.c, "msm_otg"),
 	CLK_LOOKUP("xo",	gcc_xo_clk_src.c, "fe200000.qcom,lpass"),
 	CLK_LOOKUP("xo",	gcc_xo_clk_src.c, "pil-q6v5-mss"),
@@ -3157,7 +3165,7 @@
 	CLK_LOOKUP("reg_clk",        q6ss_ahbm_clk.c,  "fe200000.qcom,lpass"),
 };
 
-static struct clk_lookup msm_clocks_8910_rumi[] = {
+static struct clk_lookup msm_clocks_8610_rumi[] = {
 	CLK_DUMMY("core_clk",   BLSP1_UART_CLK, "f991f000.serial", OFF),
 	CLK_DUMMY("iface_clk",  BLSP1_UART_CLK, "f991f000.serial", OFF),
 	CLK_DUMMY("iface_clk",  HSUSB_IFACE_CLK, "f9a55000.usb", OFF),
@@ -3183,9 +3191,9 @@
 	CLK_DUMMY("core_clk",   NULL, "fd010000.qcom,iommu", OFF),
 };
 
-struct clock_init_data msm8910_rumi_clock_init_data __initdata = {
-	.table = msm_clocks_8910_rumi,
-	.size = ARRAY_SIZE(msm_clocks_8910_rumi),
+struct clock_init_data msm8610_rumi_clock_init_data __initdata = {
+	.table = msm_clocks_8610_rumi,
+	.size = ARRAY_SIZE(msm_clocks_8610_rumi),
 };
 
 static struct pll_config_regs gpll0_regs __initdata = {
@@ -3346,7 +3354,7 @@
 	WARN(ret, "LPASS Audio Core GDSC did not power on.\n");
 }
 
-static void __init msm8910_clock_post_init(void)
+static void __init msm8610_clock_post_init(void)
 {
 	/*
 	 * Hold an active set vote for CXO; this is because CXO is expected
@@ -3377,29 +3385,29 @@
 #define APCS_GCC_CC_PHYS	0xF9011000
 #define APCS_GCC_CC_SIZE	SZ_4K
 
-static void __init msm8910_clock_pre_init(void)
+static void __init msm8610_clock_pre_init(void)
 {
 	virt_bases[GCC_BASE] = ioremap(GCC_CC_PHYS, GCC_CC_SIZE);
 	if (!virt_bases[GCC_BASE])
-		panic("clock-8910: Unable to ioremap GCC memory!");
+		panic("clock-8610: Unable to ioremap GCC memory!");
 
 	virt_bases[MMSS_BASE] = ioremap(MMSS_CC_PHYS, MMSS_CC_SIZE);
 	if (!virt_bases[MMSS_BASE])
-		panic("clock-8910: Unable to ioremap MMSS_CC memory!");
+		panic("clock-8610: Unable to ioremap MMSS_CC memory!");
 
 	virt_bases[LPASS_BASE] = ioremap(LPASS_CC_PHYS, LPASS_CC_SIZE);
 	if (!virt_bases[LPASS_BASE])
-		panic("clock-8910: Unable to ioremap LPASS_CC memory!");
+		panic("clock-8610: Unable to ioremap LPASS_CC memory!");
 
 	virt_bases[APCS_BASE] = ioremap(APCS_GCC_CC_PHYS, APCS_GCC_CC_SIZE);
 	if (!virt_bases[APCS_BASE])
-		panic("clock-8910: Unable to ioremap APCS_GCC_CC memory!");
+		panic("clock-8610: Unable to ioremap APCS_GCC_CC memory!");
 
 	clk_ops_local_pll.enable = sr_hpm_lp_pll_clk_enable;
 
 	vdd_dig_reg = rpm_regulator_get(NULL, "vdd_dig");
 	if (IS_ERR(vdd_dig_reg))
-		panic("clock-8910: Unable to get the vdd_dig regulator!");
+		panic("clock-8610: Unable to get the vdd_dig regulator!");
 
 	/*
 	 * TODO: Set a voltage and enable vdd_dig, leaving the voltage high
@@ -3429,15 +3437,15 @@
 	clk_prepare_enable(&audio_core_ixfabric_clk.c);
 }
 
-static int __init msm8910_clock_late_init(void)
+static int __init msm8610_clock_late_init(void)
 {
 	return unvote_vdd_level(&vdd_dig, VDD_DIG_HIGH);
 }
 
-struct clock_init_data msm8910_clock_init_data __initdata = {
-	.table = msm_clocks_8910,
-	.size = ARRAY_SIZE(msm_clocks_8910),
-	.pre_init = msm8910_clock_pre_init,
-	.post_init = msm8910_clock_post_init,
-	.late_init = msm8910_clock_late_init,
+struct clock_init_data msm8610_clock_init_data __initdata = {
+	.table = msm_clocks_8610,
+	.size = ARRAY_SIZE(msm_clocks_8610),
+	.pre_init = msm8610_clock_pre_init,
+	.post_init = msm8610_clock_post_init,
+	.late_init = msm8610_clock_late_init,
 };
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 66c01d6..a48bf94 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -770,6 +770,8 @@
 		.dbg_name = "mmpll1_clk_src",
 		.rate = 846000000,
 		.ops = &clk_ops_pll_vote,
+		/* May be reassigned at runtime; alloc memory at compile time */
+		VDD_DIG_FMAX_MAP1(LOW, 846000000),
 		CLK_INIT(mmpll1_clk_src.c),
 	},
 };
@@ -781,7 +783,7 @@
 	.c = {
 		.parent = &cxo_clk_src.c,
 		.dbg_name = "mmpll3_clk_src",
-		.rate = 1000000000,
+		.rate = 820000000,
 		.ops = &clk_ops_local_pll,
 		CLK_INIT(mmpll3_clk_src.c),
 	},
@@ -2393,6 +2395,19 @@
 	F_END
 };
 
+static struct clk_freq_tbl ftbl_mmss_axi_v2_clk[] = {
+	F_MM( 19200000,    cxo,     1,   0,   0),
+	F_MM( 37500000,  gpll0,    16,   0,   0),
+	F_MM( 50000000,  gpll0,    12,   0,   0),
+	F_MM( 75000000,  gpll0,     8,   0,   0),
+	F_MM(100000000,  gpll0,     6,   0,   0),
+	F_MM(150000000,  gpll0,     4,   0,   0),
+	F_MM(333430000, mmpll1,   3.5,   0,   0),
+	F_MM(400000000, mmpll0,     2,   0,   0),
+	F_MM(466800000, mmpll1,   2.5,   0,   0),
+	F_END
+};
+
 static struct rcg_clk axi_clk_src = {
 	.cmd_rcgr_reg = 0x5040,
 	.set_rate = set_rate_hid,
@@ -2420,6 +2435,18 @@
 	F_END
 };
 
+static struct clk_freq_tbl ftbl_ocmemnoc_v2_clk[] = {
+	F_MM( 19200000,    cxo,   1,   0,   0),
+	F_MM( 37500000,  gpll0,  16,   0,   0),
+	F_MM( 50000000,  gpll0,  12,   0,   0),
+	F_MM( 75000000,  gpll0,   8,   0,   0),
+	F_MM(100000000,  gpll0,   6,   0,   0),
+	F_MM(150000000,  gpll0,   4,   0,   0),
+	F_MM(333430000, mmpll1, 3.5,   0,   0),
+	F_MM(400000000, mmpll0,   2,   0,   0),
+	F_END
+};
+
 struct rcg_clk ocmemnoc_clk_src = {
 	.cmd_rcgr_reg = OCMEMNOC_CMD_RCGR,
 	.set_rate = set_rate_hid,
@@ -3183,6 +3210,16 @@
 	F_END
 };
 
+static struct clk_freq_tbl ftbl_venus0_vcodec0_v2_clk[] = {
+	F_MM( 50000000,  gpll0,  12,   0,   0),
+	F_MM(100000000,  gpll0,   6,   0,   0),
+	F_MM(133330000, mmpll0,   6,   0,   0),
+	F_MM(200000000, mmpll0,   4,   0,   0),
+	F_MM(266670000, mmpll0,   3,   0,   0),
+	F_MM(465000000, mmpll3,   2,   0,   0),
+	F_END
+};
+
 static struct rcg_clk vcodec0_clk_src = {
 	.cmd_rcgr_reg = VCODEC0_CMD_RCGR,
 	.set_rate = set_rate_mnd,
@@ -5057,6 +5094,7 @@
 	CLK_LOOKUP("iface_clk", gcc_blsp2_ahb_clk.c, "f9967000.i2c"),
 	CLK_LOOKUP("iface_clk", gcc_blsp2_ahb_clk.c, "f9966000.spi"),
 	CLK_LOOKUP("iface_clk", gcc_blsp2_ahb_clk.c, "f995e000.serial"),
+	CLK_LOOKUP("iface_clk", gcc_blsp2_ahb_clk.c, "f995d000.uart"),
 	CLK_LOOKUP("core_clk", gcc_blsp2_qup1_i2c_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk", gcc_blsp2_qup1_spi_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk", gcc_blsp2_qup2_i2c_apps_clk.c, ""),
@@ -5069,7 +5107,7 @@
 	CLK_LOOKUP("core_clk", gcc_blsp2_qup5_spi_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk", gcc_blsp2_qup6_i2c_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk", gcc_blsp2_qup6_spi_apps_clk.c, ""),
-	CLK_LOOKUP("core_clk", gcc_blsp2_uart1_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp2_uart1_apps_clk.c, "f995d000.uart"),
 	CLK_LOOKUP("core_clk", gcc_blsp2_uart2_apps_clk.c, "f995e000.serial"),
 	CLK_LOOKUP("core_clk", gcc_blsp2_uart3_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk", gcc_blsp2_uart4_apps_clk.c, ""),
@@ -5116,8 +5154,8 @@
 	CLK_LOOKUP("iface_clk", gcc_sdcc4_ahb_clk.c, "msm_sdcc.4"),
 	CLK_LOOKUP("core_clk", gcc_sdcc4_apps_clk.c, "msm_sdcc.4"),
 
-	CLK_LOOKUP("iface_clk", gcc_tsif_ahb_clk.c, ""),
-	CLK_LOOKUP("ref_clk", gcc_tsif_ref_clk.c, ""),
+	CLK_LOOKUP("iface_clk", gcc_tsif_ahb_clk.c, "f99d8000.msm_tspp"),
+	CLK_LOOKUP("ref_clk", gcc_tsif_ref_clk.c, "f99d8000.msm_tspp"),
 
 	CLK_LOOKUP("mem_clk", gcc_usb30_master_clk.c,           "usb_bam"),
 	CLK_LOOKUP("mem_iface_clk", gcc_sys_noc_usb3_axi_clk.c, "usb_bam"),
@@ -5136,6 +5174,9 @@
 	CLK_LOOKUP("cal_clk", gcc_usb_hsic_io_cal_clk.c,  "msm_hsic_host"),
 	CLK_LOOKUP("core_clk", gcc_usb_hsic_system_clk.c, "msm_hsic_host"),
 	CLK_LOOKUP("ref_clk", div_clk2.c, "msm_smsc_hub"),
+	CLK_LOOKUP("iface_clk", gcc_usb_hs_ahb_clk.c,     "msm_ehci_host"),
+	CLK_LOOKUP("core_clk", gcc_usb_hs_system_clk.c,   "msm_ehci_host"),
+	CLK_LOOKUP("sleep_clk", gcc_usb2b_phy_sleep_clk.c, "msm_ehci_host"),
 	CLK_LOOKUP("pwm_clk", div_clk2.c, "0-0048"),
 
 	/* Multimedia clocks */
@@ -5531,7 +5572,7 @@
 	.base = &virt_bases[MMSS_BASE],
 };
 
-/* MMPLL1 at 1000 MHz, main output enabled. */
+/* MMPLL1 at 846 MHz, main output enabled. */
 static struct pll_config mmpll1_config __initdata = {
 	.l = 0x2C,
 	.m = 0x1,
@@ -5548,6 +5589,23 @@
 	.main_output_mask = BIT(0),
 };
 
+/* MMPLL1 at 1167 MHz, main output enabled. */
+static struct pll_config mmpll1_v2_config __initdata = {
+	.l = 60,
+	.m = 25,
+	.n = 32,
+	.vco_val = 0x0,
+	.vco_mask = BM(21, 20),
+	.pre_div_val = 0x0,
+	.pre_div_mask = BM(14, 12),
+	.post_div_val = 0x0,
+	.post_div_mask = BM(9, 8),
+	.mn_ena_val = BIT(24),
+	.mn_ena_mask = BIT(24),
+	.main_output_val = BIT(0),
+	.main_output_mask = BIT(0),
+};
+
 static struct pll_config_regs mmpll3_regs __initdata = {
 	.l_reg = (void __iomem *)MMPLL3_L_REG,
 	.m_reg = (void __iomem *)MMPLL3_M_REG,
@@ -5574,6 +5632,23 @@
 	.main_output_mask = BIT(0),
 };
 
+/* MMPLL3 at 930 MHz, main output enabled. */
+static struct pll_config mmpll3_v2_config __initdata = {
+	.l = 48,
+	.m = 7,
+	.n = 16,
+	.vco_val = 0x0,
+	.vco_mask = BM(21, 20),
+	.pre_div_val = 0x0,
+	.pre_div_mask = BM(14, 12),
+	.post_div_val = 0x0,
+	.post_div_mask = BM(9, 8),
+	.mn_ena_val = BIT(24),
+	.mn_ena_mask = BIT(24),
+	.main_output_val = BIT(0),
+	.main_output_mask = BIT(0),
+};
+
 static struct pll_config_regs lpapll0_regs __initdata = {
 	.l_reg = (void __iomem *)LPAPLL_L_REG,
 	.m_reg = (void __iomem *)LPAPLL_M_REG,
@@ -5620,8 +5695,14 @@
 	int ret;
 
 	configure_sr_hpm_lp_pll(&mmpll0_config, &mmpll0_regs, 1);
-	configure_sr_hpm_lp_pll(&mmpll1_config, &mmpll1_regs, 1);
-	configure_sr_hpm_lp_pll(&mmpll3_config, &mmpll3_regs, 0);
+
+	if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 2) {
+		configure_sr_hpm_lp_pll(&mmpll1_v2_config, &mmpll1_regs, 1);
+		configure_sr_hpm_lp_pll(&mmpll3_v2_config, &mmpll3_regs, 0);
+	} else {
+		configure_sr_hpm_lp_pll(&mmpll1_config, &mmpll1_regs, 1);
+		configure_sr_hpm_lp_pll(&mmpll3_config, &mmpll3_regs, 0);
+	}
 	configure_sr_hpm_lp_pll(&lpapll0_config, &lpapll0_regs, 1);
 
 	/* Vote for GPLL0 to turn on. Needed by acpuclock. */
@@ -5677,8 +5758,13 @@
 
 static void __init msm8974_clock_post_init(void)
 {
-	clk_set_rate(&axi_clk_src.c, 282000000);
-	clk_set_rate(&ocmemnoc_clk_src.c, 282000000);
+	if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 2) {
+		clk_set_rate(&axi_clk_src.c, 333430000);
+		clk_set_rate(&ocmemnoc_clk_src.c, 333430000);
+	} else {
+		clk_set_rate(&axi_clk_src.c, 282000000);
+		clk_set_rate(&ocmemnoc_clk_src.c, 282000000);
+	}
 
 	/*
 	 * Hold an active set vote at a rate of 40MHz for the MMSS NOC AHB
@@ -5784,6 +5870,25 @@
 	enable_rpm_scaling();
 
 	reg_init();
+
+	/* v2 specific changes */
+	if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 2) {
+		mmpll3_clk_src.c.rate =  930000000;
+		mmpll1_clk_src.c.rate = 1167000000;
+		mmpll1_clk_src.c.fmax[VDD_DIG_NOMINAL] = 1167000000;
+
+		ocmemnoc_clk_src.freq_tbl = ftbl_ocmemnoc_v2_clk;
+		ocmemnoc_clk_src.c.fmax[VDD_DIG_NOMINAL] = 333430000;
+
+		axi_clk_src.freq_tbl = ftbl_mmss_axi_v2_clk;
+		axi_clk_src.c.fmax[VDD_DIG_NOMINAL] = 333430000;
+		axi_clk_src.c.fmax[VDD_DIG_HIGH] = 466800000;
+
+		vcodec0_clk_src.freq_tbl = ftbl_venus0_vcodec0_v2_clk;
+		vcodec0_clk_src.c.fmax[VDD_DIG_HIGH] = 465000000;
+
+		mdp_clk_src.c.fmax[VDD_DIG_NOMINAL] = 240000000;
+	}
 }
 
 static int __init msm8974_clock_late_init(void)
diff --git a/arch/arm/mach-msm/clock.h b/arch/arm/mach-msm/clock.h
index 181cf4c..002ee96 100644
--- a/arch/arm/mach-msm/clock.h
+++ b/arch/arm/mach-msm/clock.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -49,8 +49,8 @@
 extern struct clock_init_data msm8930_pm8917_clock_init_data;
 extern struct clock_init_data msm8974_clock_init_data;
 extern struct clock_init_data msm8974_rumi_clock_init_data;
-extern struct clock_init_data msm8910_clock_init_data;
-extern struct clock_init_data msm8910_rumi_clock_init_data;
+extern struct clock_init_data msm8610_clock_init_data;
+extern struct clock_init_data msm8610_rumi_clock_init_data;
 
 int msm_clock_init(struct clock_init_data *data);
 int find_vdd_level(struct clk *clk, unsigned long rate);
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index 67485dc..c986064 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -754,26 +754,49 @@
 
 static struct resource tspp_resources[] = {
 	[0] = {
+		.name = "TSIF_TSPP_IRQ",
 		.flags = IORESOURCE_IRQ,
 		.start = TSIF_TSPP_IRQ,
-		.end   = TSIF1_IRQ,
+		.end   = TSIF_TSPP_IRQ,
 	},
 	[1] = {
+		.name = "TSIF0_IRQ",
+		.flags = IORESOURCE_IRQ,
+		.start = TSIF1_IRQ,
+		.end   = TSIF1_IRQ,
+	},
+	[2] = {
+		.name = "TSIF1_IRQ",
+		.flags = IORESOURCE_IRQ,
+		.start = TSIF2_IRQ,
+		.end   = TSIF2_IRQ,
+	},
+	[3] = {
+		.name = "TSIF_BAM_IRQ",
+		.flags = IORESOURCE_IRQ,
+		.start = TSIF_BAM_IRQ,
+		.end   = TSIF_BAM_IRQ,
+	},
+	[4] = {
+		.name = "MSM_TSIF0_PHYS",
 		.flags = IORESOURCE_MEM,
 		.start = MSM_TSIF0_PHYS,
 		.end   = MSM_TSIF0_PHYS + MSM_TSIF_SIZE - 1,
 	},
-	[2] = {
+	[5] = {
+		.name = "MSM_TSIF1_PHYS",
 		.flags = IORESOURCE_MEM,
 		.start = MSM_TSIF1_PHYS,
 		.end   = MSM_TSIF1_PHYS + MSM_TSIF_SIZE - 1,
 	},
-	[3] = {
+	[6] = {
+		.name = "MSM_TSPP_PHYS",
 		.flags = IORESOURCE_MEM,
 		.start = MSM_TSPP_PHYS,
 		.end   = MSM_TSPP_PHYS + MSM_TSPP_SIZE - 1,
 	},
-	[4] = {
+	[7] = {
+		.name = "MSM_TSPP_BAM_PHYS",
 		.flags = IORESOURCE_MEM,
 		.start = MSM_TSPP_BAM_PHYS,
 		.end   = MSM_TSPP_BAM_PHYS + MSM_TSPP_BAM_SIZE - 1,
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 8762aa1..446f3f2 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -2459,11 +2459,6 @@
 	.id	= -1,
 };
 
-struct platform_device msm_fm_loopback = {
-	.name	= "msm-pcm-loopback",
-	.id	= -1,
-};
-
 static struct fs_driver_data gfx2d0_fs_data = {
 	.clks = (struct fs_clk_data[]){
 		{ .name = "core_clk" },
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index 15994565..ee6c5cb 100644
--- a/arch/arm/mach-msm/devices-9615.c
+++ b/arch/arm/mach-msm/devices-9615.c
@@ -1546,7 +1546,7 @@
 	msm_shared_ram_phys = MSM_SHARED_RAM_PHYS;
 	msm_map_msm9615_io();
 	l2x0_cache_init();
-	if (IS_ERR_OR_NULL(socinfo_init()))
+	if (socinfo_init() < 0)
 		pr_err("socinfo_init() failed!\n");
 }
 
diff --git a/arch/arm/mach-msm/devices-msm7x27a.c b/arch/arm/mach-msm/devices-msm7x27a.c
index c8b160c..907af68 100644
--- a/arch/arm/mach-msm/devices-msm7x27a.c
+++ b/arch/arm/mach-msm/devices-msm7x27a.c
@@ -2147,7 +2147,7 @@
 void __init msm_common_io_init(void)
 {
 	msm_map_common_io();
-	if (IS_ERR_OR_NULL(socinfo_init()))
+	if (socinfo_init() < 0)
 		pr_err("socinfo_init() failed!\n");
 	msm7x27x_cache_init();
 }
@@ -2163,7 +2163,7 @@
 {
 	msm_map_msm8625_io();
 
-	if (IS_ERR_OR_NULL(socinfo_init()))
+	if (socinfo_init() < 0)
 		pr_err("socinfo_init() failed!\n");
 	msm7x27x_cache_init();
 }
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 3471a30..248af88 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -1,7 +1,7 @@
 /* linux/arch/arm/mach-msm/devices.h
  *
  * Copyright (C) 2008 Google, Inc.
- * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -253,7 +253,6 @@
 extern struct platform_device msm_i2s_cpudai4;
 extern struct platform_device msm_i2s_cpudai5;
 extern struct platform_device msm_cpudai_stub;
-extern struct platform_device msm_fm_loopback;
 
 extern struct platform_device msm_pil_q6v3;
 extern struct platform_device msm_pil_modem;
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index 0a8afa9..56c78c6 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -588,9 +588,9 @@
 void msm_map_msm8226_io(void);
 void msm8226_init_irq(void);
 void msm8226_init_gpiomux(void);
-void msm8910_init_gpiomux(void);
-void msm_map_msm8910_io(void);
-void msm8910_init_irq(void);
+void msm8610_init_gpiomux(void);
+void msm_map_msm8610_io(void);
+void msm8610_init_irq(void);
 
 /* Dump debug info (states, rate, etc) of clocks */
 #if defined(CONFIG_ARCH_MSM7X27)
diff --git a/arch/arm/mach-msm/include/mach/irqs.h b/arch/arm/mach-msm/include/mach/irqs.h
index 6955c80..65d5d02 100644
--- a/arch/arm/mach-msm/include/mach/irqs.h
+++ b/arch/arm/mach-msm/include/mach/irqs.h
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2013, The Linux Foundation. All rights reserved.
  * Author: Brian Swetland <swetland@google.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -108,7 +108,7 @@
 #define NR_QPNP_IRQS 32768
 #define NR_BOARD_IRQS NR_QPNP_IRQS
 
-#elif defined(CONFIG_ARCH_MSM8910) || defined(CONFIG_ARCH_MSM8226)
+#elif defined(CONFIG_ARCH_MSM8610) || defined(CONFIG_ARCH_MSM8226)
 #define NR_MSM_IRQS 256
 #define NR_GPIO_IRQS 117
 #define NR_QPNP_IRQS 32768
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8910.h b/arch/arm/mach-msm/include/mach/msm_iomap-8610.h
similarity index 61%
rename from arch/arm/mach-msm/include/mach/msm_iomap-8910.h
rename to arch/arm/mach-msm/include/mach/msm_iomap-8610.h
index 64990da..05544af 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8910.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8610.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -10,8 +10,8 @@
  * GNU General Public License for more details.
  */
 
-#ifndef __ASM_ARCH_MSM_IOMAP_8910_H
-#define __ASM_ARCH_MSM_IOMAP_8910_H
+#ifndef __ASM_ARCH_MSM_IOMAP_8610_H
+#define __ASM_ARCH_MSM_IOMAP_8610_H
 
 /* Physical base address and size of peripherals.
  * Ordered by the virtual base addresses they will be mapped at.
@@ -22,21 +22,21 @@
  *
  */
 
-#define MSM8910_MSM_SHARED_RAM_PHYS	0x0D600000
+#define MSM8610_MSM_SHARED_RAM_PHYS	0x0D600000
 
-#define MSM8910_APCS_GCC_PHYS	0xF9011000
-#define MSM8910_APCS_GCC_SIZE	SZ_4K
+#define MSM8610_APCS_GCC_PHYS	0xF9011000
+#define MSM8610_APCS_GCC_SIZE	SZ_4K
 
-#define MSM8910_TLMM_PHYS	0xFD510000
-#define MSM8910_TLMM_SIZE	SZ_16K
+#define MSM8610_TLMM_PHYS	0xFD510000
+#define MSM8610_TLMM_SIZE	SZ_16K
 
-#define MSM8910_IMEM_PHYS	0xFE805000
-#define MSM8910_IMEM_SIZE	SZ_4K
+#define MSM8610_IMEM_PHYS	0xFE805000
+#define MSM8610_IMEM_SIZE	SZ_4K
 
-#define MSM8910_MPM2_PSHOLD_PHYS	0xFC4AB000
-#define MSM8910_MPM2_PSHOLD_SIZE	SZ_4K
+#define MSM8610_MPM2_PSHOLD_PHYS	0xFC4AB000
+#define MSM8610_MPM2_PSHOLD_SIZE	SZ_4K
 
-#ifdef CONFIG_DEBUG_MSM8910_UART
+#ifdef CONFIG_DEBUG_MSM8610_UART
 #define MSM_DEBUG_UART_BASE	IOMEM(0xFA71E000)
 #define MSM_DEBUG_UART_PHYS	0xF991E000
 #endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap.h b/arch/arm/mach-msm/include/mach/msm_iomap.h
index f372b1e..8c49539 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap.h
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2013, The Linux Foundation. All rights reserved.
  * Author: Brian Swetland <swetland@google.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -54,7 +54,7 @@
 	defined(CONFIG_ARCH_MSM7X25) || defined(CONFIG_ARCH_MSM7X01A) || \
 	defined(CONFIG_ARCH_MSM8625) || defined(CONFIG_ARCH_MSM7X30) || \
 	defined(CONFIG_ARCH_MSM9625) || defined(CONFIG_ARCH_MPQ8092) || \
-	defined(CONFIG_ARCH_MSM8226) || defined(CONFIG_ARCH_MSM8910)
+	defined(CONFIG_ARCH_MSM8226) || defined(CONFIG_ARCH_MSM8610)
 
 /* Unified iomap */
 
@@ -122,7 +122,7 @@
 #include "msm_iomap-9625.h"
 #include "msm_iomap-8092.h"
 #include "msm_iomap-8226.h"
-#include "msm_iomap-8910.h"
+#include "msm_iomap-8610.h"
 
 #else
 /* Legacy single-target iomap */
diff --git a/arch/arm/mach-msm/include/mach/msm_smsm.h b/arch/arm/mach-msm/include/mach/msm_smsm.h
index c77c181..e88c4df 100644
--- a/arch/arm/mach-msm/include/mach/msm_smsm.h
+++ b/arch/arm/mach-msm/include/mach/msm_smsm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -198,7 +198,11 @@
 	SMEM_SSR_REASON_LPASS0,
 	SMEM_SSR_REASON_DSPS0,
 	SMEM_SSR_REASON_VCODEC0,
-	SMEM_MEM_LAST = SMEM_SSR_REASON_VCODEC0,
+	SMEM_SMP2P_APPS_BASE = 427,
+	SMEM_SMP2P_MODEM_BASE = 435,
+	SMEM_SMP2P_AUDIO_BASE = 443,
+	SMEM_SMP2P_WIRLESS_BASE = 451,
+	SMEM_SMP2P_POWER_BASE = 459,
 	SMEM_NUM_ITEMS,
 };
 
diff --git a/arch/arm/mach-msm/include/mach/socinfo.h b/arch/arm/mach-msm/include/mach/socinfo.h
index 345f09c..5b4f00e 100644
--- a/arch/arm/mach-msm/include/mach/socinfo.h
+++ b/arch/arm/mach-msm/include/mach/socinfo.h
@@ -56,14 +56,14 @@
 	of_machine_is_compatible("qcom,msm8226-sim")
 #define machine_is_msm8226_rumi()		\
 	of_machine_is_compatible("qcom,msm8226-rumi")
-#define early_machine_is_msm8910()	\
-	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msm8910")
-#define machine_is_msm8910()		\
-	of_machine_is_compatible("qcom,msm8910")
-#define machine_is_msm8910_sim()		\
-	of_machine_is_compatible("qcom,msm8910-sim")
-#define machine_is_msm8910_rumi()		\
-	of_machine_is_compatible("qcom,msm8910-rumi")
+#define early_machine_is_msm8610()	\
+	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msm8610")
+#define machine_is_msm8610()		\
+	of_machine_is_compatible("qcom,msm8610")
+#define machine_is_msm8610_sim()		\
+	of_machine_is_compatible("qcom,msm8610-sim")
+#define machine_is_msm8610_rumi()		\
+	of_machine_is_compatible("qcom,msm8610-rumi")
 #else
 #define early_machine_is_msm8974()	0
 #define machine_is_msm8974()		0
@@ -77,10 +77,10 @@
 #define machine_is_msm8226()		0
 #define machine_is_msm8226_sim()	0
 #define machine_is_msm8226_rumi()	0
-#define early_machine_is_msm8910()	0
-#define machine_is_msm8910()		0
-#define machine_is_msm8910_sim()	0
-#define machine_is_msm8910_rumi()	0
+#define early_machine_is_msm8610()	0
+#define machine_is_msm8610()		0
+#define machine_is_msm8610_sim()	0
+#define machine_is_msm8610_rumi()	0
 
 #endif
 
@@ -105,6 +105,7 @@
 	MSM_CPU_7X25AB,
 	MSM_CPU_8064,
 	MSM_CPU_8064AB,
+	MSM_CPU_8064AA,
 	MSM_CPU_8930,
 	MSM_CPU_8930AA,
 	MSM_CPU_8930AB,
@@ -116,7 +117,7 @@
 	MSM_CPU_9625,
 	MSM_CPU_8092,
 	MSM_CPU_8226,
-	MSM_CPU_8910,
+	MSM_CPU_8610,
 	MSM_CPU_8625Q,
 };
 
@@ -147,7 +148,7 @@
 uint32_t socinfo_get_platform_version(void);
 enum pmic_model socinfo_get_pmic_model(void);
 uint32_t socinfo_get_pmic_die_revision(void);
-struct device * __init socinfo_init(void) __must_check;
+int __init socinfo_init(void) __must_check;
 const int read_msm_cpu_type(void);
 const int get_core_count(void);
 const int cpu_is_krait(void);
@@ -332,6 +333,15 @@
 #endif
 }
 
+static inline int cpu_is_apq8064aa(void)
+{
+#ifdef CONFIG_ARCH_APQ8064
+	return read_msm_cpu_type() == MSM_CPU_8064AA;
+#else
+	return 0;
+#endif
+}
+
 static inline int cpu_is_msm8930(void)
 {
 #ifdef CONFIG_ARCH_MSM8930
@@ -442,13 +452,13 @@
 #endif
 }
 
-static inline int cpu_is_msm8910(void)
+static inline int cpu_is_msm8610(void)
 {
-#ifdef CONFIG_ARCH_MSM8910
+#ifdef CONFIG_ARCH_MSM8610
 	enum msm_cpu cpu = socinfo_get_msm_cpu();
 
 	BUG_ON(cpu == MSM_CPU_UNKNOWN);
-	return cpu == MSM_CPU_8910;
+	return cpu == MSM_CPU_8610;
 #else
 	return 0;
 #endif
@@ -473,7 +483,7 @@
 
 static inline int soc_class_is_apq8064(void)
 {
-	return cpu_is_apq8064() || cpu_is_apq8064ab();
+	return cpu_is_apq8064() || cpu_is_apq8064ab() || cpu_is_apq8064aa();
 }
 
 static inline int soc_class_is_msm8930(void)
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index cd70ae9..013b4b2 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -3,7 +3,7 @@
  * MSM7K, QSD io support
  *
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2013, The Linux Foundation. All rights reserved.
  * Author: Brian Swetland <swetland@google.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -538,12 +538,12 @@
 }
 #endif /* CONFIG_ARCH_MSM8226 */
 
-#ifdef CONFIG_ARCH_MSM8910
-static struct map_desc msm8910_io_desc[] __initdata = {
-	MSM_CHIP_DEVICE(APCS_GCC, MSM8910),
-	MSM_CHIP_DEVICE(TLMM, MSM8910),
-	MSM_CHIP_DEVICE(MPM2_PSHOLD, MSM8910),
-	MSM_CHIP_DEVICE(IMEM, MSM8910),
+#ifdef CONFIG_ARCH_MSM8610
+static struct map_desc msm8610_io_desc[] __initdata = {
+	MSM_CHIP_DEVICE(APCS_GCC, MSM8610),
+	MSM_CHIP_DEVICE(TLMM, MSM8610),
+	MSM_CHIP_DEVICE(MPM2_PSHOLD, MSM8610),
+	MSM_CHIP_DEVICE(IMEM, MSM8610),
 	{
 		.virtual =  (unsigned long) MSM_SHARED_RAM_BASE,
 		.length =   MSM_SHARED_RAM_SIZE,
@@ -551,9 +551,9 @@
 	},
 };
 
-void __init msm_map_msm8910_io(void)
+void __init msm_map_msm8610_io(void)
 {
-	msm_shared_ram_phys = MSM8910_MSM_SHARED_RAM_PHYS;
-	msm_map_io(msm8910_io_desc, ARRAY_SIZE(msm8910_io_desc));
+	msm_shared_ram_phys = MSM8610_MSM_SHARED_RAM_PHYS;
+	msm_map_io(msm8610_io_desc, ARRAY_SIZE(msm8610_io_desc));
 }
-#endif /* CONFIG_ARCH_MSM8910 */
+#endif /* CONFIG_ARCH_MSM8610 */
diff --git a/arch/arm/mach-msm/krait-regulator.c b/arch/arm/mach-msm/krait-regulator.c
index dd61db3..b6d6965 100644
--- a/arch/arm/mach-msm/krait-regulator.c
+++ b/arch/arm/mach-msm/krait-regulator.c
@@ -36,19 +36,17 @@
  *                   from
  *                   pmic
  *                   gang
- *                    |        LDO BYP [6]
- *                    |         /
- *                    |        /
- *                    |_______/   _____
- *                    |                |
- *                 ___|___             |
- *		  |       |            |
- *		  |       |               /
- *		  |  LDO  |              /
- *		  |       |             /    BHS[6]
- *                |_______|            |
- *                    |                |
- *                    |________________|
+ *                    |
+ *                    |________________________________
+ *                    |                |               |
+ *                 ___|___             |               |
+ *		  |       |            |               |
+ *		  |       |               /               /
+ *		  |  LDO  |              /               /LDO BYP [6]
+ *		  |       |             /    BHS[6]     /(bypass is a weak BHS
+ *                |_______|            |               |  needs to be on when in
+ *                    |                |               |  BHS mode)
+ *                    |________________|_______________|
  *                    |
  *            ________|________
  *           |                 |
@@ -88,6 +86,10 @@
 #define PWR_GATE_CONFIG		0x00000044
 #define VERSION			0x00000FD0
 
+/* MDD register group */
+#define MDD_CONFIG_CTL		0x00000000
+#define MDD_MODE		0x00000010
+
 /* bit definitions for APC_PWR_GATE_CTL */
 #define BHS_CNT_BIT_POS		24
 #define BHS_CNT_MASK		KRAIT_MASK(31, 24)
@@ -155,6 +157,7 @@
 	int				load_uA;
 	enum krait_supply_mode		mode;
 	void __iomem			*reg_base;
+	void __iomem			*mdd_base;
 	int				ldo_default_uV;
 	int				retention_uV;
 	int				headroom_uV;
@@ -225,15 +228,13 @@
 {
 	if (kvreg->mode == HS_MODE)
 		return 0;
-
-	/*
-	 * enable ldo bypass - the krait is powered still by LDO since
-	 * LDO is enabled and BHS is disabled
-	 */
-	krait_masked_write(kvreg, APC_PWR_GATE_CTL, LDO_BYP_MASK, LDO_BYP_MASK);
-
 	/* enable bhs */
-	krait_masked_write(kvreg, APC_PWR_GATE_CTL, BHS_EN_MASK, BHS_EN_MASK);
+	krait_masked_write(kvreg, APC_PWR_GATE_CTL,
+		BHS_SEG_EN_MASK | BHS_EN_MASK,
+		BHS_SEG_EN_DEFAULT << BHS_SEG_EN_BIT_POS | BHS_EN_MASK);
+
+	/* complete the above write before the delay */
+	mb();
 
 	/*
 	 * wait for the bhs to settle - note that
@@ -242,6 +243,12 @@
 	 */
 	udelay(BHS_SETTLING_DELAY_US);
 
+	/*
+	 * enable ldo bypass - the krait is powered still by LDO since
+	 * LDO is enabled
+	 */
+	krait_masked_write(kvreg, APC_PWR_GATE_CTL, LDO_BYP_MASK, LDO_BYP_MASK);
+
 	/* disable ldo - only the BHS provides voltage to the cpu after this */
 	krait_masked_write(kvreg, APC_PWR_GATE_CTL,
 				LDO_PWR_DWN_MASK, LDO_PWR_DWN_MASK);
@@ -272,6 +279,9 @@
 	 */
 	krait_masked_write(kvreg, APC_PWR_GATE_CTL, LDO_PWR_DWN_MASK, 0);
 
+	/* complete the writes before the delay */
+	mb();
+
 	/* wait for the ldo to settle */
 	udelay(LDO_SETTLING_DELAY_US);
 
@@ -281,6 +291,7 @@
 	 */
 	krait_masked_write(kvreg, APC_PWR_GATE_CTL,
 		BHS_EN_MASK | LDO_BYP_MASK, 0);
+	krait_masked_write(kvreg, APC_PWR_GATE_CTL, BHS_SEG_EN_MASK, 0);
 
 	kvreg->mode = LDO_MODE;
 	pr_debug("%s using LDO\n", kvreg->name);
@@ -378,6 +389,10 @@
 		return rc;
 	}
 
+
+	/* complete the above writes before the delay */
+	mb();
+
 	/* delay until the voltage is settled when it is raised */
 	settling_us = DIV_ROUND_UP(vmax - pvreg->pmic_vmax_uV, SLEW_RATE);
 	udelay(settling_us);
@@ -438,6 +453,9 @@
 			return rc;
 		}
 
+		/* complete the writes before the delay */
+		mb();
+
 		/*
 		 * delay until the phases are settled when
 		 * the count is raised
@@ -728,18 +746,14 @@
 	 * bhs_cnt value sets the ramp-up time from power collapse,
 	 * initialize the ramp up time
 	 */
-	krait_masked_write(kvreg, APC_PWR_GATE_CTL,
-		BHS_CNT_MASK, BHS_CNT_DEFAULT << BHS_CNT_BIT_POS);
-
-	krait_masked_write(kvreg, APC_PWR_GATE_CTL,
-		CLK_SRC_SEL_MASK, CLK_SRC_DEFAULT << CLK_SRC_SEL_BIT_POS);
-
-	/* BHS has six different segments, turn them all on */
-	krait_masked_write(kvreg, APC_PWR_GATE_CTL,
-		BHS_SEG_EN_MASK, BHS_SEG_EN_DEFAULT << BHS_SEG_EN_BIT_POS);
-
 	set_krait_retention_uv(kvreg, kvreg->retention_uV);
 	set_krait_ldo_uv(kvreg, kvreg->ldo_default_uV);
+
+	/* setup the bandgap that configures the reference to the LDO */
+	writel_relaxed(0x00000190, kvreg->mdd_base + MDD_CONFIG_CTL);
+	/* Enable MDD */
+	writel_relaxed(0x00000002, kvreg->mdd_base + MDD_MODE);
+	mb();
 }
 
 static void glb_init(struct platform_device *pdev)
@@ -772,7 +786,7 @@
 static int __devinit krait_power_probe(struct platform_device *pdev)
 {
 	struct krait_power_vreg *kvreg;
-	struct resource *res;
+	struct resource *res, *res_mdd;
 	struct regulator_init_data *init_data = pdev->dev.platform_data;
 	int rc = 0;
 	int headroom_uV, retention_uV, ldo_default_uV, ldo_threshold_uV;
@@ -864,12 +878,18 @@
 		return -EINVAL;
 	}
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "acs");
 	if (!res) {
 		dev_err(&pdev->dev, "missing physical register addresses\n");
 		return -EINVAL;
 	}
 
+	res_mdd = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mdd");
+	if (!res_mdd) {
+		dev_err(&pdev->dev, "missing mdd register addresses\n");
+		return -EINVAL;
+	}
+
 	kvreg = devm_kzalloc(&pdev->dev,
 			sizeof(struct krait_power_vreg), GFP_KERNEL);
 	if (!kvreg) {
@@ -880,6 +900,9 @@
 	kvreg->reg_base = devm_ioremap(&pdev->dev,
 				res->start, resource_size(res));
 
+	kvreg->mdd_base = devm_ioremap(&pdev->dev,
+				res_mdd->start, resource_size(res));
+
 	kvreg->pvreg		= the_gang;
 	kvreg->name		= init_data->constraints.name;
 	kvreg->desc.name	= kvreg->name;
@@ -959,25 +982,36 @@
 {
 	platform_driver_unregister(&krait_power_driver);
 }
-
 module_exit(krait_power_exit);
 
 void secondary_cpu_hs_init(void *base_ptr)
 {
-	/* 605mV retention and 705mV operational voltage */
-	writel_relaxed(0x1C30, base_ptr + APC_LDO_VREF_SET);
-	/* HS_EN_DLY=3; LDO_BYP_DLY=1; */
-	writel_relaxed(0x430000, base_ptr + APC_PWR_GATE_DLY);
-	/* MODE = BHS; EN=1; */
-	writel_relaxed(0x21, base_ptr + APC_PWR_GATE_MODE);
-
 	/* Turn on the BHS, turn off LDO Bypass and power down LDO */
-	writel_relaxed(0x403F007F, base_ptr + APC_PWR_GATE_CTL);
+	writel_relaxed(
+		BHS_CNT_DEFAULT << BHS_CNT_BIT_POS
+		| LDO_PWR_DWN_MASK
+		| CLK_SRC_DEFAULT << CLK_SRC_SEL_BIT_POS
+		| BHS_SEG_EN_DEFAULT << BHS_SEG_EN_BIT_POS
+		| BHS_EN_MASK,
+		base_ptr + APC_PWR_GATE_CTL);
+
+	/* complete the above write before the delay */
 	mb();
-	udelay(1);
+
+	/*
+	 * wait for the bhs to settle
+	 */
+	udelay(BHS_SETTLING_DELAY_US);
 
 	/* Finally turn on the bypass so that BHS supplies power */
-	writel_relaxed(0x403F3F7F, base_ptr + APC_PWR_GATE_CTL);
+	writel_relaxed(
+		BHS_CNT_DEFAULT << BHS_CNT_BIT_POS
+		| LDO_PWR_DWN_MASK
+		| CLK_SRC_DEFAULT << CLK_SRC_SEL_BIT_POS
+		| LDO_BYP_MASK
+		| BHS_SEG_EN_DEFAULT << BHS_SEG_EN_BIT_POS
+		| BHS_EN_MASK,
+		base_ptr + APC_PWR_GATE_CTL);
 }
 
 MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/lpm_levels.c b/arch/arm/mach-msm/lpm_levels.c
index 61c2aa8..b84d345 100644
--- a/arch/arm/mach-msm/lpm_levels.c
+++ b/arch/arm/mach-msm/lpm_levels.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -37,6 +37,10 @@
 static struct msm_rpmrs_level *msm_lpm_levels;
 static int msm_lpm_level_count;
 
+static DEFINE_PER_CPU(uint32_t , msm_lpm_sleep_time);
+static DEFINE_PER_CPU(int , lpm_permitted_level);
+static DEFINE_PER_CPU(struct atomic_notifier_head, lpm_notify_head);
+
 static void msm_lpm_level_update(void)
 {
 	unsigned int lpm_level;
@@ -55,6 +59,12 @@
 	int ret = 0;
 	int debug_mask;
 	struct msm_rpmrs_limits *l = (struct msm_rpmrs_limits *)limits;
+	struct msm_lpm_sleep_data sleep_data;
+
+	sleep_data.limits = limits;
+	sleep_data.kernel_sleep = __get_cpu_var(msm_lpm_sleep_time);
+	atomic_notifier_call_chain(&__get_cpu_var(lpm_notify_head),
+		MSM_LPM_STATE_ENTER, &sleep_data);
 
 	ret = msm_rpm_enter_sleep();
 	if (ret) {
@@ -88,6 +98,8 @@
 	msm_rpm_exit_sleep();
 	msm_lpmrs_exit_sleep((struct msm_rpmrs_limits *)limits,
 				from_idle, notify_rpm, collapsed);
+	atomic_notifier_call_chain(&__get_cpu_var(lpm_notify_head),
+			MSM_LPM_STATE_EXIT, NULL);
 }
 
 void msm_lpm_show_resources(void)
@@ -96,6 +108,48 @@
 	return;
 }
 
+uint32_t msm_pm_get_pxo(struct msm_rpmrs_limits *limits)
+{
+	return limits->pxo;
+}
+
+uint32_t msm_pm_get_l2_cache(struct msm_rpmrs_limits *limits)
+{
+	return limits->l2_cache;
+}
+
+uint32_t msm_pm_get_vdd_mem(struct msm_rpmrs_limits *limits)
+{
+	return limits->vdd_mem_upper_bound;
+}
+
+uint32_t msm_pm_get_vdd_dig(struct msm_rpmrs_limits *limits)
+{
+	return limits->vdd_dig_upper_bound;
+}
+
+static bool lpm_level_permitted(int cur_level_count)
+{
+	if (__get_cpu_var(lpm_permitted_level) == msm_lpm_level_count + 1)
+		return true;
+	return (__get_cpu_var(lpm_permitted_level) == cur_level_count);
+}
+
+int msm_lpm_register_notifier(int cpu, int level_iter,
+			struct notifier_block *nb, bool is_latency_measure)
+{
+	per_cpu(lpm_permitted_level, cpu) = level_iter;
+	return atomic_notifier_chain_register(&per_cpu(lpm_notify_head,
+			cpu), nb);
+}
+
+int msm_lpm_unregister_notifier(int cpu, struct notifier_block *nb)
+{
+	per_cpu(lpm_permitted_level, cpu) = msm_lpm_level_count + 1;
+	return atomic_notifier_chain_unregister(&per_cpu(lpm_notify_head, cpu),
+				nb);
+}
+
 s32 msm_cpuidle_get_deep_idle_latency(void)
 {
 	int i;
@@ -127,7 +181,7 @@
 	struct msm_rpmrs_level *best_level = NULL;
 	uint32_t pwr;
 	int i;
-
+	int best_level_iter = msm_lpm_level_count + 1;
 	if (!msm_lpm_levels)
 		return NULL;
 
@@ -170,14 +224,31 @@
 			level->rs_limits.latency_us[cpu] = level->latency_us;
 			level->rs_limits.power[cpu] = pwr;
 			best_level = level;
-
+			best_level_iter = i;
 			if (power)
 				*power = pwr;
 		}
 	}
+	if (best_level && !lpm_level_permitted(best_level_iter))
+		best_level = NULL;
+	else
+		per_cpu(msm_lpm_sleep_time, cpu) =
+			time_param->modified_time_us ?
+			time_param->modified_time_us : time_param->sleep_us;
 
 	return best_level ? &best_level->rs_limits : NULL;
 }
+
+static struct lpm_test_platform_data lpm_test_pdata;
+
+static struct platform_device msm_lpm_test_device = {
+	.name		= "lpm_test",
+	.id		= -1,
+	.dev		= {
+		.platform_data = &lpm_test_pdata,
+	},
+};
+
 static struct msm_pm_sleep_ops msm_lpm_ops = {
 	.lowest_limits = msm_lpm_lowest_limits,
 	.enter_sleep = msm_lpm_enter_sleep,
@@ -194,6 +265,7 @@
 	int ret = 0;
 	uint32_t num_levels = 0;
 	int idx = 0;
+	unsigned int m_cpu = 0;
 
 	for_each_child_of_node(pdev->dev.of_node, node)
 		num_levels++;
@@ -279,6 +351,14 @@
 	msm_lpm_levels = levels;
 	msm_lpm_level_count = idx;
 
+	lpm_test_pdata.msm_lpm_test_levels = msm_lpm_levels;
+	lpm_test_pdata.msm_lpm_test_level_count = msm_lpm_level_count;
+
+	for_each_possible_cpu(m_cpu)
+		per_cpu(lpm_permitted_level, m_cpu) =
+					msm_lpm_level_count + 1;
+
+	platform_device_register(&msm_lpm_test_device);
 	msm_pm_set_sleep_ops(&msm_lpm_ops);
 
 	return 0;
diff --git a/arch/arm/mach-msm/lpm_resources.h b/arch/arm/mach-msm/lpm_resources.h
index 120832f..42e43c2 100644
--- a/arch/arm/mach-msm/lpm_resources.h
+++ b/arch/arm/mach-msm/lpm_resources.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -15,6 +15,7 @@
 #define __ARCH_ARM_MACH_MSM_LPM_RESOURCES_H
 
 #include "pm.h"
+#include "test-lpm.h"
 
 enum {
 	MSM_LPM_PXO_OFF = 0,
@@ -50,6 +51,93 @@
 	uint32_t time_overhead_us;
 };
 
+enum {
+	MSM_LPM_STATE_ENTER = 0,
+	MSM_LPM_STATE_EXIT = 1,
+};
+
+#define MSM_PM(field) MSM_LPM_##field
+
+/**
+ * msm_pm_get_pxo() -  get the limits for pxo
+ * @limits:            pointer to the msm_rpmrs_limits structure
+ *
+ * This function gets the limits to the resource pxo on
+ * 8974
+ */
+
+uint32_t msm_pm_get_pxo(struct msm_rpmrs_limits *limits);
+
+/**
+ * msm_pm_get_l2_cache() -  get the limits for l2 cache
+ * @limits:            pointer to the msm_rpmrs_limits structure
+ *
+ * This function gets the limits to the resource l2 cache
+ * on 8974
+ */
+
+uint32_t msm_pm_get_l2_cache(struct msm_rpmrs_limits *limits);
+
+/**
+ * msm_pm_get_vdd_mem() -  get the limits for pxo
+ * @limits:            pointer to the msm_rpmrs_limits structure
+ *
+ * This function gets the limits to the resource vdd mem
+ * on 8974
+ */
+
+uint32_t msm_pm_get_vdd_mem(struct msm_rpmrs_limits *limits);
+
+/**
+ * msm_pm_get_vdd_dig() -  get the limits for vdd dig
+ * @limits:            pointer to the msm_rpmrs_limits structure
+ *
+ * This function gets the limits to the resource on 8974
+ */
+
+uint32_t msm_pm_get_vdd_dig(struct msm_rpmrs_limits *limits);
+
+/**
+ * struct msm_lpm_sleep_data - abstraction to get sleep data
+ * @limits:	pointer to the msm_rpmrs_limits structure
+ * @kernel_sleep:	kernel sleep time as decided by the power calculation
+ *			algorithm
+ *
+ * This structure is an abstraction to get the limits and kernel sleep time
+ * during enter sleep.
+ */
+
+struct msm_lpm_sleep_data {
+	struct msm_rpmrs_limits *limits;
+	uint32_t kernel_sleep;
+};
+
+/**
+ * msm_lpm_register_notifier() - register for notifications
+ * @cpu:               cpu to debug
+ * @level_iter:        low power level index to debug
+ * @nb:       notifier block to callback on notifications
+ * @is_latency_measure: is it latency measure
+ *
+ * This function sets the permitted level to the index of the
+ * level under test and registers notifier for callback.
+ */
+
+int msm_lpm_register_notifier(int cpu, int level_iter,
+		struct notifier_block *nb, bool is_latency_measure);
+
+/**
+ * msm_lpm_unregister_notifier() - unregister from notifications
+ * @cpu:               cpu to debug
+ * @nb:       notifier block to callback on notifications
+ *
+ * This function sets the permitted level to a value one more than
+ * available levels count which indicates that all levels are
+ * permitted and it also unregisters notifier for callback.
+ */
+
+int msm_lpm_unregister_notifier(int cpu, struct notifier_block *nb);
+
 #ifdef CONFIG_MSM_RPM_SMD
 
 /**
diff --git a/arch/arm/mach-msm/no-pm.c b/arch/arm/mach-msm/no-pm.c
index d460c70..0db6e68 100644
--- a/arch/arm/mach-msm/no-pm.c
+++ b/arch/arm/mach-msm/no-pm.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2011, 2013 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -48,3 +48,4 @@
 	return -ENOSYS;
 }
 
+void msm_pm_enable_retention(bool enable) {}
diff --git a/arch/arm/mach-msm/pil-q6v5-mss.c b/arch/arm/mach-msm/pil-q6v5-mss.c
index ed85c95..7cf61ab 100644
--- a/arch/arm/mach-msm/pil-q6v5-mss.c
+++ b/arch/arm/mach-msm/pil-q6v5-mss.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -24,6 +24,7 @@
 #include <linux/of.h>
 #include <linux/regulator/consumer.h>
 #include <linux/interrupt.h>
+#include <linux/of_gpio.h>
 
 #include <mach/subsystem_restart.h>
 #include <mach/clk.h>
@@ -87,6 +88,8 @@
 	bool crash_shutdown;
 	bool ignore_errors;
 	int is_loadable;
+	int err_fatal_irq;
+	int force_stop_gpio;
 };
 
 static int pbl_mba_boot_timeout_ms = 100;
@@ -442,18 +445,17 @@
 	subsystem_restart_dev(drv->subsys);
 }
 
-static void smsm_state_cb(void *data, uint32_t old_state, uint32_t new_state)
+static irqreturn_t modem_err_fatal_intr_handler(int irq, void *dev_id)
 {
-	struct mba_data *drv = data;
+	struct mba_data *drv = dev_id;
 
-	/* Ignore if we're the one that set SMSM_RESET */
+	/* Ignore if we're the one that set the force stop GPIO */
 	if (drv->crash_shutdown)
-		return;
+		return IRQ_HANDLED;
 
-	if (new_state & SMSM_RESET) {
-		pr_err("Probable fatal error on the modem.\n");
-		restart_modem(drv);
-	}
+	pr_err("Fatal error on the modem.\n");
+	restart_modem(drv);
+	return IRQ_HANDLED;
 }
 
 static int modem_shutdown(const struct subsys_desc *subsys)
@@ -493,7 +495,7 @@
 {
 	struct mba_data *drv = subsys_to_drv(subsys);
 	drv->crash_shutdown = true;
-	smsm_reset_modem(SMSM_RESET);
+	gpio_set_value(drv->force_stop_gpio, 1);
 }
 
 static struct ramdump_segment smem_segments[] = {
@@ -630,10 +632,11 @@
 		goto err_irq;
 	}
 
-	ret = smsm_state_cb_register(SMSM_MODEM_STATE, SMSM_RESET,
-		smsm_state_cb, drv);
+	ret = devm_request_irq(&pdev->dev, drv->err_fatal_irq,
+			modem_err_fatal_intr_handler,
+			IRQF_TRIGGER_RISING, "pil-mss", drv);
 	if (ret < 0) {
-		dev_err(&pdev->dev, "Unable to register SMSM callback!\n");
+		dev_err(&pdev->dev, "Unable to register SMP2P err fatal handler!\n");
 		goto err_irq;
 	}
 
@@ -643,14 +646,11 @@
 		ret = PTR_ERR(drv->adsp_state_notifier);
 		dev_err(&pdev->dev, "%s: Registration with the SSR notification driver failed (%d)",
 			__func__, ret);
-		goto err_smsm;
+		goto err_irq;
 	}
 
 	return 0;
 
-err_smsm:
-	smsm_state_cb_deregister(SMSM_MODEM_STATE, SMSM_RESET, smsm_state_cb,
-			drv);
 err_irq:
 	destroy_ramdump_device(drv->smem_ramdump_dev);
 err_ramdump_smem:
@@ -759,7 +759,7 @@
 static int __devinit pil_mss_driver_probe(struct platform_device *pdev)
 {
 	struct mba_data *drv;
-	int ret;
+	int ret, err_fatal_gpio;
 
 	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
 	if (!drv)
@@ -774,6 +774,22 @@
 			return ret;
 	}
 
+	/* Get the IRQ from the GPIO for registering inbound handler */
+	err_fatal_gpio = of_get_named_gpio(pdev->dev.of_node,
+			"qcom,gpio-err-fatal", 0);
+	if (err_fatal_gpio < 0)
+		return err_fatal_gpio;
+
+	drv->err_fatal_irq = gpio_to_irq(err_fatal_gpio);
+	if (drv->err_fatal_irq < 0)
+		return drv->err_fatal_irq;
+
+	/* Get the GPIO pin for writing the outbound bits: add more as needed */
+	drv->force_stop_gpio = of_get_named_gpio(pdev->dev.of_node,
+			"qcom,gpio-force-stop", 0);
+	if (drv->force_stop_gpio < 0)
+		return drv->force_stop_gpio;
+
 	return pil_subsys_init(drv, pdev);
 }
 
@@ -783,8 +799,6 @@
 
 	subsys_notif_unregister_notifier(drv->adsp_state_notifier,
 						&adsp_state_notifier_block);
-	smsm_state_cb_deregister(SMSM_MODEM_STATE, SMSM_RESET,
-			smsm_state_cb, drv);
 	subsys_unregister(drv->subsys);
 	destroy_ramdump_device(drv->smem_ramdump_dev);
 	destroy_ramdump_device(drv->ramdump_dev);
diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c
index 80f6014..b034525 100644
--- a/arch/arm/mach-msm/platsmp.c
+++ b/arch/arm/mach-msm/platsmp.c
@@ -1,7 +1,7 @@
 /*
  *  Copyright (C) 2002 ARM Ltd.
  *  All Rights Reserved
- *  Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
+ *  Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -263,7 +263,7 @@
 	pr_debug("Starting secondary CPU %d\n", cpu);
 
 	if (per_cpu(cold_boot_done, cpu) == false) {
-		if (machine_is_msm8226_sim() || machine_is_msm8910_sim())
+		if (machine_is_msm8226_sim() || machine_is_msm8610_sim())
 			release_secondary_sim(0xf9088000, cpu);
 
 		per_cpu(cold_boot_done, cpu) = true;
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index e35d843..261d433 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -118,6 +118,7 @@
 static struct msm_pm_init_data_type msm_pm_init_data;
 static struct hrtimer pm_hrtimer;
 static struct msm_pm_sleep_ops pm_sleep_ops;
+static bool msm_pm_ldo_retention_enabled = true;
 /*
  * Write out the attribute.
  */
@@ -820,6 +821,14 @@
 			}
 			/* fall through */
 		case MSM_PM_SLEEP_MODE_RETENTION:
+			/*
+			 * The Krait BHS regulator doesn't have enough head
+			 * room to drive the retention voltage on LDO and so
+			 * has disabled retention
+			 */
+			if (!msm_pm_ldo_retention_enabled)
+				break;
+
 			if (!allow)
 				break;
 
@@ -995,6 +1004,34 @@
 		msm_pm_swfi();
 }
 
+static void msm_pm_ack_retention_disable(void *data)
+{
+	/*
+	 * This is a NULL function to ensure that the core has woken up
+	 * and is safe to disable retention.
+	 */
+}
+/**
+ * msm_pm_enable_retention() - Disable/Enable retention on all cores
+ * @enable: Enable/Disable retention
+ *
+ */
+void msm_pm_enable_retention(bool enable)
+{
+	msm_pm_ldo_retention_enabled = enable;
+	/*
+	 * If retention is being disabled, wakeup all online core to ensure
+	 * that it isn't executing retention. Offlined cores need not be woken
+	 * up as they enter the deepest sleep mode, namely RPM assited power
+	 * collapse
+	 */
+	if (!enable)
+		smp_call_function_many(cpu_online_mask,
+				msm_pm_ack_retention_disable,
+				NULL, true);
+}
+EXPORT_SYMBOL(msm_pm_enable_retention);
+
 static int msm_pm_enter(suspend_state_t state)
 {
 	bool allow[MSM_PM_SLEEP_MODE_NR];
diff --git a/arch/arm/mach-msm/pm-data.c b/arch/arm/mach-msm/pm-data.c
index 6f4743f..08cdf5d 100644
--- a/arch/arm/mach-msm/pm-data.c
+++ b/arch/arm/mach-msm/pm-data.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, 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,7 +30,7 @@
 
 	[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_RETENTION)] = {
 		.idle_supported = 1,
-		.suspend_supported = 1,
+		.suspend_supported = 0,
 		.idle_enabled = 0,
 		.suspend_enabled = 0,
 	},
diff --git a/arch/arm/mach-msm/pm.h b/arch/arm/mach-msm/pm.h
index 86d8f98..399194a 100644
--- a/arch/arm/mach-msm/pm.h
+++ b/arch/arm/mach-msm/pm.h
@@ -1,7 +1,7 @@
 /* arch/arm/mach-msm/pm.h
  *
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
  * Author: San Mehat <san@android.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -114,6 +114,7 @@
 int msm_pm_idle_enter(enum msm_pm_sleep_mode sleep_mode);
 void msm_pm_cpu_enter_lowpower(unsigned int cpu);
 void __init msm_pm_set_tz_retention_flag(unsigned int flag);
+void msm_pm_enable_retention(bool enable);
 
 #ifdef CONFIG_MSM_PM8X60
 void msm_pm_set_rpm_wakeup_irq(unsigned int irq);
diff --git a/arch/arm/mach-msm/qdsp6v2/apr_tal.c b/arch/arm/mach-msm/qdsp6v2/apr_tal.c
index 03f0513..d734739 100644
--- a/arch/arm/mach-msm/qdsp6v2/apr_tal.c
+++ b/arch/arm/mach-msm/qdsp6v2/apr_tal.c
@@ -133,12 +133,12 @@
 		spin_unlock_irqrestore(&apr_ch->lock, flags);
 		break;
 	case SMD_EVENT_OPEN:
-		pr_info("apr_tal: SMD_EVENT_OPEN\n");
+		pr_debug("apr_tal: SMD_EVENT_OPEN\n");
 		apr_ch->smd_state = 1;
 		wake_up(&apr_ch->wait);
 		break;
 	case SMD_EVENT_CLOSE:
-		pr_info("apr_tal: SMD_EVENT_CLOSE\n");
+		pr_debug("apr_tal: SMD_EVENT_CLOSE\n");
 		break;
 	}
 }
diff --git a/arch/arm/mach-msm/qdsp6v2/apr_v2.c b/arch/arm/mach-msm/qdsp6v2/apr_v2.c
index ed494e4..f554cf3 100644
--- a/arch/arm/mach-msm/qdsp6v2/apr_v2.c
+++ b/arch/arm/mach-msm/qdsp6v2/apr_v2.c
@@ -50,16 +50,16 @@
 			pr_err("%s: adsp not up\n", __func__);
 			return NULL;
 		}
-		pr_info("%s: adsp Up\n", __func__);
+		pr_debug("%s: adsp Up\n", __func__);
 	} else if ((dest_id == APR_DEST_MODEM) &&
 		   (apr_get_modem_state() == APR_SUBSYS_DOWN)) {
-		pr_info("%s: Wait for modem to bootup\n", __func__);
+		pr_debug("%s: Wait for modem to bootup\n", __func__);
 		rc = apr_wait_for_device_up(dest_id);
 		if (rc == 0) {
 			pr_err("%s: Modem is not Up\n", __func__);
 			return NULL;
 		}
-		pr_info("%s: modem Up\n", __func__);
+		pr_debug("%s: modem Up\n", __func__);
 	}
 
 	if (apr_get_svc(svc_name, dest_id, &client_id, &svc_idx, &svc_id)) {
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_aac.c b/arch/arm/mach-msm/qdsp6v2/audio_aac.c
index 44ab611..2a8d5c8 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-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -135,10 +135,9 @@
 		} else {
 			uint16_t sce_left = 1, sce_right = 2;
 			aac_config = audio->codec_cfg;
-			if ((aac_config->dual_mono_mode <
-				AUDIO_AAC_DUAL_MONO_PL_PR) ||
-				(aac_config->dual_mono_mode >
-				AUDIO_AAC_DUAL_MONO_PL_SR)) {
+			/* PL_PR is 0 only need to check PL_SR */
+			if (aac_config->dual_mono_mode >
+			    AUDIO_AAC_DUAL_MONO_PL_SR) {
 				pr_err("%s:AUDIO_SET_AAC_CONFIG: Invalid"
 					"dual_mono mode =%d\n", __func__,
 					aac_config->dual_mono_mode);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c b/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c
index b53edd9..658c07b 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c
@@ -2,7 +2,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -147,10 +147,8 @@
 		} else {
 			uint16_t sce_left = 1, sce_right = 2;
 			aac_config = audio->codec_cfg;
-			if ((aac_config->dual_mono_mode <
-				AUDIO_AAC_DUAL_MONO_PL_PR) ||
-				(aac_config->dual_mono_mode >
-				AUDIO_AAC_DUAL_MONO_PL_SR)) {
+			if (aac_config->dual_mono_mode >
+			    AUDIO_AAC_DUAL_MONO_PL_SR) {
 				pr_err("%s:AUDIO_SET_AAC_CONFIG: Invalid dual_mono mode =%d\n",
 					 __func__, aac_config->dual_mono_mode);
 			} else {
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
index ad5f1b5..67ef0ad 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
@@ -1,6 +1,6 @@
 /* Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2013, 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
@@ -861,10 +861,9 @@
 	}
 	param.msw_ts = buf_node->meta_info.meta_in.ntimestamp.highpart;
 	param.lsw_ts = buf_node->meta_info.meta_in.ntimestamp.lowpart;
+	param.flags  = buf_node->meta_info.meta_in.nflags;
 	/* If no meta_info enaled, indicate no time stamp valid */
-	if (audio->buf_cfg.meta_info_enable)
-		param.flags = 0;
-	else
+	if (!audio->buf_cfg.meta_info_enable)
 		param.flags = 0xFF00;
 
 	if ((buf_node != NULL) &&
diff --git a/arch/arm/mach-msm/qdsp6v2/dsp_debug.c b/arch/arm/mach-msm/qdsp6v2/dsp_debug.c
index 3635fbd..26c8f75 100644
--- a/arch/arm/mach-msm/qdsp6v2/dsp_debug.c
+++ b/arch/arm/mach-msm/qdsp6v2/dsp_debug.c
@@ -38,12 +38,14 @@
 
 void q6audio_dsp_not_responding(void)
 {
+	int i;
+
 	if (cb_ptr)
 		cb_ptr(DSP_STATE_CRASHED);
 	if (atomic_add_return(1, &dsp_crash_count) != 1) {
 		pr_err("q6audio_dsp_not_responding() \
 			- parking additional crasher...\n");
-		for (;;)
+		for (i = 0; i < 600; i++)
 			msleep(1000);
 	}
 	if (dsp_wait_count) {
diff --git a/arch/arm/mach-msm/qdsp6v2/q6audio_common.h b/arch/arm/mach-msm/qdsp6v2/q6audio_common.h
index 5ffffd2..de4e1f0 100644
--- a/arch/arm/mach-msm/qdsp6v2/q6audio_common.h
+++ b/arch/arm/mach-msm/qdsp6v2/q6audio_common.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, 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,7 +16,7 @@
 #define __Q6_AUDIO_COMMON_H__
 
 #if defined(CONFIG_ARCH_MSM8974) || defined(CONFIG_ARCH_MSM9625) \
-	|| defined(CONFIG_ARCH_MSM8226)
+	|| defined(CONFIG_ARCH_MSM8226) || defined(CONFIG_ARCH_MSM8610)
 
 #include <sound/apr_audio-v2.h>
 #include <sound/q6asm-v2.h>
diff --git a/arch/arm/mach-msm/qdsp6v2/q6core.c b/arch/arm/mach-msm/qdsp6v2/q6core.c
index 9dd66e1..f23ba67 100644
--- a/arch/arm/mach-msm/qdsp6v2/q6core.c
+++ b/arch/arm/mach-msm/qdsp6v2/q6core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -253,8 +253,6 @@
 	int len;
 	static int t_len;
 
-	if (count < 0)
-		return 0;
 	len = count > 63 ? 63 : count;
 	if (copy_from_user(l_buf + 20 , buf, len)) {
 		pr_info("Unable to copy data from user space\n");
diff --git a/arch/arm/mach-msm/rpm-smd.c b/arch/arm/mach-msm/rpm-smd.c
index ccd0861..4295fd4 100644
--- a/arch/arm/mach-msm/rpm-smd.c
+++ b/arch/arm/mach-msm/rpm-smd.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -960,6 +960,9 @@
  */
 int msm_rpm_enter_sleep(void)
 {
+	if (standalone)
+		return 0;
+
 	return smd_mask_receive_interrupt(msm_rpm_data.ch_info, true);
 }
 EXPORT_SYMBOL(msm_rpm_enter_sleep);
@@ -970,20 +973,13 @@
  */
 void msm_rpm_exit_sleep(void)
 {
+	if (standalone)
+		return;
+
 	smd_mask_receive_interrupt(msm_rpm_data.ch_info, false);
 }
 EXPORT_SYMBOL(msm_rpm_exit_sleep);
 
-static bool msm_rpm_set_standalone(void)
-{
-	if (machine_is_msm9625() || machine_is_msm8974_rumi()) {
-		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;
@@ -1001,6 +997,9 @@
 	if (ret)
 		goto fail;
 
+	key = "rpm-standalone";
+	standalone = of_property_read_bool(pdev->dev.of_node, key);
+
 	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);
@@ -1012,9 +1011,14 @@
 		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);
+	} else {
+		/*
+		 * Override DT's suggestion to try standalone; since we have an
+		 * SMD channel.
+		 */
+		standalone = false;
 	}
 
 	wait_for_completion(&msm_rpm_data.smd_open);
@@ -1029,6 +1033,10 @@
 	}
 
 	of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+
+	if (standalone)
+		pr_info("%s(): RPM running in standalone mode\n", __func__);
+
 	return 0;
 fail:
 	pr_err("%s(): Failed to read node: %s, key=%s\n", __func__,
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index c607202..eda8950 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -1,7 +1,7 @@
 /* arch/arm/mach-msm/smd.c
  *
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2013, The Linux Foundation. All rights reserved.
  * Author: Brian Swetland <swetland@google.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -3153,6 +3153,17 @@
 }
 EXPORT_SYMBOL(smsm_state_cb_deregister);
 
+/**
+ * smem_get_remote_spinlock - Remote spinlock pointer for unit testing.
+ *
+ * @returns: pointer to SMEM remote spinlock
+ */
+remote_spinlock_t *smem_get_remote_spinlock(void)
+{
+	return &remote_spinlock;
+}
+EXPORT_SYMBOL(smem_get_remote_spinlock);
+
 int smd_module_init_notifier_register(struct notifier_block *nb)
 {
 	int ret;
diff --git a/arch/arm/mach-msm/smd_private.h b/arch/arm/mach-msm/smd_private.h
index 2033fbe..50bfb13 100644
--- a/arch/arm/mach-msm/smd_private.h
+++ b/arch/arm/mach-msm/smd_private.h
@@ -1,7 +1,7 @@
 /* arch/arm/mach-msm/smd_private.h
  *
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2007-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2007-2013, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -18,6 +18,8 @@
 
 #include <linux/types.h>
 #include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/remote_spinlock.h>
 #include <mach/msm_smsm.h>
 #include <mach/msm_smd.h>
 
@@ -271,4 +273,6 @@
 };
 extern struct interrupt_stat interrupt_stats[NUM_SMD_SUBSYSTEMS];
 
+/* used for unit testing spinlocks */
+remote_spinlock_t *smem_get_remote_spinlock(void);
 #endif
diff --git a/arch/arm/mach-msm/smp2p.c b/arch/arm/mach-msm/smp2p.c
new file mode 100644
index 0000000..6d2df2a
--- /dev/null
+++ b/arch/arm/mach-msm/smp2p.c
@@ -0,0 +1,1706 @@
+/* arch/arm/mach-msm/smp2p.c
+ *
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/list.h>
+#include <linux/ctype.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <mach/msm_smsm.h>
+#include <mach/msm_ipc_logging.h>
+#include "smp2p_private_api.h"
+#include "smp2p_private.h"
+
+#define NUM_LOG_PAGES 3
+
+/**
+ * struct msm_smp2p_out - This structure represents the outbound SMP2P entry.
+ *
+ * @remote_pid: Outbound processor ID.
+ * @name: Entry name.
+ * @out_edge_list: Adds this structure into smp2p_out_list_item::list.
+ * @msm_smp2p_notifier_list: Notifier block head used to notify for open event.
+ * @open_nb: Notifier block used to notify for open event.
+ * @l_smp2p_entry: Pointer to the actual entry in the SMEM item.
+ */
+struct msm_smp2p_out {
+	int remote_pid;
+	char name[SMP2P_MAX_ENTRY_NAME];
+	struct list_head out_edge_list;
+	struct raw_notifier_head msm_smp2p_notifier_list;
+	struct notifier_block *open_nb;
+	uint32_t *l_smp2p_entry;
+};
+
+/**
+ * struct smp2p_out_list_item - Maintains the state of outbound edge.
+ *
+ * @out_item_lock_lha1: Lock protecting all elements of the structure.
+ * @list: list of outbound entries (struct msm_smp2p_out).
+ * @smem_edge_out: Pointer to outbound smem item.
+ * @smem_edge_state: State of the outbound edge.
+ * @ops_ptr: Pointer to internal version-specific SMEM item access functions.
+ */
+struct smp2p_out_list_item {
+	spinlock_t out_item_lock_lha1;
+
+	struct list_head list;
+	struct smp2p_smem *smem_edge_out;
+	enum msm_smp2p_edge_state smem_edge_state;
+	struct smp2p_version_if *ops_ptr;
+};
+static struct smp2p_out_list_item out_list[SMP2P_NUM_PROCS];
+
+static void *log_ctx;
+static int smp2p_debug_mask = MSM_SMP2P_INFO;
+module_param_named(debug_mask, smp2p_debug_mask,
+		   int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+/**
+ * struct smp2p_in - Represents the entry on remote processor.
+ *
+ * @name: Name of the entry.
+ * @remote_pid: Outbound processor ID.
+ * @in_edge_list: Adds this structure into smp2p_in_list_item::list.
+ * @in_notifier_list: List for notifier block for entry opening/updates.
+ * @entry_val: Previous value of the entry.
+ * @entry_ptr: Points to the current value in smem item.
+ * @notifier_count: Counts the number of notifier registered per pid,entry.
+ */
+struct smp2p_in {
+	int remote_pid;
+	char name[SMP2P_MAX_ENTRY_NAME];
+	struct list_head in_edge_list;
+	struct raw_notifier_head in_notifier_list;
+	uint32_t entry_val;
+	uint32_t *entry_ptr;
+	uint32_t notifier_count;
+};
+
+/**
+ * struct smp2p_in_list_item - Maintains the inbound edge state.
+ *
+ * @in_item_lock_lhb1: Lock protecting all elements of the structure.
+ * @list: List head for the entries on remote processor.
+ * @smem_edge_in: Pointer to the remote smem item.
+ */
+struct smp2p_in_list_item {
+	spinlock_t in_item_lock_lhb1;
+	struct list_head list;
+	struct smp2p_smem *smem_edge_in;
+	uint32_t item_size;
+	uint32_t safe_total_entries;
+};
+static struct smp2p_in_list_item in_list[SMP2P_NUM_PROCS];
+
+/**
+ * SMEM Item access function interface.
+ *
+ * This interface is used to help isolate the implementation of
+ * the functionality from any changes in the shared data structures
+ * that may happen as versions are changed.
+ *
+ * @is_supported: True if this version is supported by SMP2P
+ * @negotiate_features: Returns (sub)set of supported features
+ * @find_entry: Finds existing / next empty entry
+ * @create_entry: Creates a new entry
+ * @read_entry: Reads the value of an entry
+ * @write_entry: Writes a new value to an entry
+ * @modify_entry: Does a read/modify/write of an entry
+ * validate_size: Verifies the size of the remote SMEM item to ensure that
+ *                an invalid item size doesn't result in an out-of-bounds
+ *                memory access.
+ */
+struct smp2p_version_if {
+	/* common functions */
+	bool is_supported;
+	uint32_t (*negotiate_features)(uint32_t features);
+	void (*find_entry)(struct smp2p_smem *item, uint32_t entries_total,
+			char *name, uint32_t **entry_ptr, int *empty_spot);
+
+	/* outbound entry functions */
+	int (*create_entry)(struct msm_smp2p_out *);
+	int (*read_entry)(struct msm_smp2p_out *, uint32_t *);
+	int (*write_entry)(struct msm_smp2p_out *, uint32_t);
+	int (*modify_entry)(struct msm_smp2p_out *, uint32_t, uint32_t);
+
+	/* inbound entry functions */
+	struct smp2p_smem *(*validate_size)(int remote_pid,
+			struct smp2p_smem *, uint32_t);
+};
+
+static int smp2p_do_negotiation(int remote_pid, struct smp2p_out_list_item *p);
+static void smp2p_send_interrupt(int remote_pid);
+
+/* v0 (uninitialized SMEM item) interface functions */
+static uint32_t smp2p_negotiate_features_v0(uint32_t features);
+static void smp2p_find_entry_v0(struct smp2p_smem *item,
+		uint32_t entries_total, char *name, uint32_t **entry_ptr,
+		int *empty_spot);
+static int smp2p_out_create_v0(struct msm_smp2p_out *);
+static int smp2p_out_read_v0(struct msm_smp2p_out *, uint32_t *);
+static int smp2p_out_write_v0(struct msm_smp2p_out *, uint32_t);
+static int smp2p_out_modify_v0(struct msm_smp2p_out *, uint32_t, uint32_t);
+static struct smp2p_smem *smp2p_in_validate_size_v0(int remote_pid,
+		struct smp2p_smem *smem_item, uint32_t size);
+
+/* v1 interface functions */
+static uint32_t smp2p_negotiate_features_v1(uint32_t features);
+static void smp2p_find_entry_v1(struct smp2p_smem *item,
+		uint32_t entries_total, char *name, uint32_t **entry_ptr,
+		int *empty_spot);
+static int smp2p_out_create_v1(struct msm_smp2p_out *);
+static int smp2p_out_read_v1(struct msm_smp2p_out *, uint32_t *);
+static int smp2p_out_write_v1(struct msm_smp2p_out *, uint32_t);
+static int smp2p_out_modify_v1(struct msm_smp2p_out *, uint32_t, uint32_t);
+static struct smp2p_smem *smp2p_in_validate_size_v1(int remote_pid,
+		struct smp2p_smem *smem_item, uint32_t size);
+
+/* Version interface functions */
+static struct smp2p_version_if version_if[] = {
+	[0] = {
+		.negotiate_features = smp2p_negotiate_features_v0,
+		.find_entry = smp2p_find_entry_v0,
+		.create_entry = smp2p_out_create_v0,
+		.read_entry = smp2p_out_read_v0,
+		.write_entry = smp2p_out_write_v0,
+		.modify_entry = smp2p_out_modify_v0,
+		.validate_size = smp2p_in_validate_size_v0,
+	},
+	[1] = {
+		.is_supported = true,
+		.negotiate_features = smp2p_negotiate_features_v1,
+		.find_entry = smp2p_find_entry_v1,
+		.create_entry = smp2p_out_create_v1,
+		.read_entry = smp2p_out_read_v1,
+		.write_entry = smp2p_out_write_v1,
+		.modify_entry = smp2p_out_modify_v1,
+		.validate_size = smp2p_in_validate_size_v1,
+	},
+};
+
+/* interrupt configuration (filled by device tree) */
+static struct smp2p_interrupt_config smp2p_int_cfgs[SMP2P_NUM_PROCS] = {
+	[SMP2P_MODEM_PROC].name = "modem",
+	[SMP2P_AUDIO_PROC].name = "lpass",
+	[SMP2P_WIRELESS_PROC].name = "wcnss",
+	[SMP2P_REMOTE_MOCK_PROC].name = "mock",
+};
+
+/**
+ * smp2p_get_log_ctx - Return log context for other SMP2P modules.
+ *
+ * @returns: Log context or NULL if none.
+ */
+void *smp2p_get_log_ctx(void)
+{
+	return log_ctx;
+}
+
+/**
+ * smp2p_get_debug_mask - Return debug mask.
+ *
+ * @returns: Current debug mask.
+ */
+int smp2p_get_debug_mask(void)
+{
+	return smp2p_debug_mask;
+}
+
+/**
+ * smp2p_interrupt_config -  Return interrupt configuration.
+ *
+ * @returns interrupt configuration array for usage by debugfs.
+ */
+struct smp2p_interrupt_config *smp2p_get_interrupt_config(void)
+{
+	return smp2p_int_cfgs;
+}
+
+/**
+ * smp2p_pid_to_name -  Lookup name for remote pid.
+ *
+ * @returns: name (may be NULL).
+ */
+const char *smp2p_pid_to_name(int remote_pid)
+{
+	if (remote_pid >= SMP2P_NUM_PROCS)
+		return NULL;
+
+	return smp2p_int_cfgs[remote_pid].name;
+}
+
+/**
+ * smp2p_get_in_item - Return pointer to remote smem item.
+ *
+ * @remote_pid: Processor ID of the remote system.
+ * @returns:    Pointer to inbound SMEM item
+ *
+ * This is used by debugfs to print the smem items.
+ */
+struct smp2p_smem *smp2p_get_in_item(int remote_pid)
+{
+	void *ret = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&in_list[remote_pid].in_item_lock_lhb1, flags);
+	if (remote_pid < SMP2P_NUM_PROCS)
+		ret = in_list[remote_pid].smem_edge_in;
+	spin_unlock_irqrestore(&in_list[remote_pid].in_item_lock_lhb1,
+								flags);
+
+	return ret;
+}
+
+/**
+ * smp2p_get_out_item - Return pointer to outbound SMEM item.
+ *
+ * @remote_pid: Processor ID of remote system.
+ * @state:      Edge state of the outbound SMEM item.
+ * @returns:    Pointer to outbound (remote) SMEM item.
+ */
+struct smp2p_smem *smp2p_get_out_item(int remote_pid, int *state)
+{
+	void *ret = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&out_list[remote_pid].out_item_lock_lha1, flags);
+	if (remote_pid < SMP2P_NUM_PROCS) {
+		ret = out_list[remote_pid].smem_edge_out;
+		if (state)
+			*state = out_list[remote_pid].smem_edge_state;
+	}
+	spin_unlock_irqrestore(&out_list[remote_pid].out_item_lock_lha1, flags);
+
+	return ret;
+}
+
+/**
+ * smp2p_get_smem_item_id - Return the proper SMEM item ID.
+ *
+ * @write_id:	Processor that will write to the item.
+ * @read_id:    Processor that will read from the item.
+ * @returns:    SMEM ID
+ */
+static int smp2p_get_smem_item_id(int write_pid, int read_pid)
+{
+	int ret = -EINVAL;
+
+	switch (write_pid) {
+	case SMP2P_APPS_PROC:
+		ret = SMEM_SMP2P_APPS_BASE + read_pid;
+		break;
+	case SMP2P_MODEM_PROC:
+		ret = SMEM_SMP2P_MODEM_BASE + read_pid;
+		break;
+	case SMP2P_AUDIO_PROC:
+		ret = SMEM_SMP2P_AUDIO_BASE + read_pid;
+		break;
+	case SMP2P_WIRELESS_PROC:
+		ret = SMEM_SMP2P_WIRLESS_BASE + read_pid;
+		break;
+	case SMP2P_POWER_PROC:
+		ret = SMEM_SMP2P_POWER_BASE + read_pid;
+		break;
+	}
+
+	return ret;
+}
+
+/**
+ * Return pointer to SMEM item owned by the local processor.
+ *
+ * @remote_pid: Remote processor ID
+ * @returns:    NULL for failure; otherwise pointer to SMEM item
+ *
+ * Must be called with out_item_lock_lha1 locked for mock proc.
+ */
+static void *smp2p_get_local_smem_item(int remote_pid)
+{
+	struct smp2p_smem *item_ptr = NULL;
+
+	if (remote_pid < SMP2P_REMOTE_MOCK_PROC) {
+		unsigned size;
+		int smem_id;
+
+		/* lookup or allocate SMEM item */
+		smem_id = smp2p_get_smem_item_id(SMP2P_APPS_PROC, remote_pid);
+		if (smem_id >= 0) {
+			item_ptr = smem_get_entry(smem_id, &size);
+
+			if (!item_ptr) {
+				size = sizeof(struct smp2p_smem_item);
+				item_ptr = smem_alloc2(smem_id, size);
+			}
+		}
+	} else if (remote_pid == SMP2P_REMOTE_MOCK_PROC) {
+		/*
+		 * This path is only used during unit testing so
+		 * the GFP_ATOMIC allocation should not be a
+		 * concern.
+		 */
+		if (!out_list[SMP2P_REMOTE_MOCK_PROC].smem_edge_out)
+			item_ptr = kzalloc(
+					sizeof(struct smp2p_smem_item),
+					GFP_ATOMIC);
+	}
+	return item_ptr;
+}
+
+/**
+ * smp2p_get_remote_smem_item - Return remote SMEM item.
+ *
+ * @remote_pid: Remote processor ID
+ * @out_item:   Pointer to the output item structure
+ * @returns:    NULL for failure; otherwise pointer to SMEM item
+ *
+ * Return pointer to SMEM item owned by the remote processor.
+ *
+ * Note that this function does an SMEM lookup which uses a remote spinlock,
+ * so this function should not be called more than necessary.
+ *
+ * Must be called with out_item_lock_lha1 and in_item_lock_lhb1 locked.
+ */
+static void *smp2p_get_remote_smem_item(int remote_pid,
+	struct smp2p_out_list_item *out_item)
+{
+	void *item_ptr = NULL;
+	unsigned size;
+
+	if (!out_item)
+		return item_ptr;
+
+	if (remote_pid < SMP2P_REMOTE_MOCK_PROC) {
+		int smem_id;
+
+		smem_id = smp2p_get_smem_item_id(remote_pid, SMP2P_APPS_PROC);
+		if (smem_id >= 0)
+			item_ptr = smem_get_entry(smem_id, &size);
+	} else if (remote_pid == SMP2P_REMOTE_MOCK_PROC) {
+		item_ptr = msm_smp2p_get_remote_mock_smem_item(&size);
+	}
+	item_ptr = out_item->ops_ptr->validate_size(remote_pid, item_ptr, size);
+
+	return item_ptr;
+}
+
+/**
+ * smp2p_negotiate_features_v0 - Initial feature negotiation.
+ *
+ * @features: Inbound feature set.
+ * @returns: Supported features (will be a same/subset of @features).
+ */
+static uint32_t smp2p_negotiate_features_v1(uint32_t features)
+{
+	/* no supported features */
+	return 0;
+}
+
+/**
+ * smp2p_find_entry_v1 - Search for an entry in SMEM item.
+ *
+ * @item: Pointer to the smem item.
+ * @entries_total: Total number of entries in @item.
+ * @name: Name of the entry.
+ * @entry_ptr: Set to pointer of entry if found, NULL otherwise.
+ * @empty_spot: If non-null, set to the value of the next empty entry.
+ *
+ * Searches for entry @name in the SMEM item.  If found, a pointer
+ * to the item is returned.  If it isn't found, the first empty
+ * index is returned in @empty_spot.
+ */
+static void smp2p_find_entry_v1(struct smp2p_smem *item,
+		uint32_t entries_total, char *name, uint32_t **entry_ptr,
+		int *empty_spot)
+{
+	int i;
+	struct smp2p_entry_v1 *pos;
+
+	if (!item || !name || !entry_ptr) {
+		SMP2P_ERR("%s: invalid arguments %p, %p, %p\n",
+				__func__, item, name, entry_ptr);
+		return;
+	}
+
+	*entry_ptr = NULL;
+	if (empty_spot)
+		*empty_spot = -1;
+
+	pos = (struct smp2p_entry_v1 *)(char *)(item + 1);
+	for (i = 0; i < entries_total; i++, ++pos) {
+		if (pos->name[0]) {
+			if (!strncmp(pos->name, name, SMP2P_MAX_ENTRY_NAME)) {
+				*entry_ptr = &pos->entry;
+				break;
+			}
+		} else if (empty_spot && *empty_spot < 0) {
+			*empty_spot = i;
+		}
+	}
+}
+
+/**
+ * smp2p_out_create_v1 - Creates a outbound SMP2P entry.
+ *
+ * @out_entry: Pointer to the SMP2P entry structure.
+ * @returns: 0 on success, standard Linux error code otherwise.
+ *
+ * Must be called with out_item_lock_lha1 locked.
+ */
+static int smp2p_out_create_v1(struct msm_smp2p_out *out_entry)
+{
+	struct smp2p_smem *smp2p_h_ptr;
+	struct smp2p_out_list_item *p_list;
+	uint32_t *state_entry_ptr;
+	uint32_t empty_spot;
+	uint32_t entries_total;
+	uint32_t entries_valid;
+
+	if (!out_entry)
+		return -EINVAL;
+
+	p_list = &out_list[out_entry->remote_pid];
+	if (p_list->smem_edge_state != SMP2P_EDGE_STATE_OPENED) {
+		SMP2P_ERR("%s: item '%s':%d opened - wrong create called\n",
+			__func__, out_entry->name, out_entry->remote_pid);
+		return -ENODEV;
+	}
+
+	smp2p_h_ptr = p_list->smem_edge_out;
+	entries_total = SMP2P_GET_ENT_TOTAL(smp2p_h_ptr->valid_total_ent);
+	entries_valid = SMP2P_GET_ENT_VALID(smp2p_h_ptr->valid_total_ent);
+
+	p_list->ops_ptr->find_entry(smp2p_h_ptr, entries_total,
+			out_entry->name, &state_entry_ptr, &empty_spot);
+	if (state_entry_ptr) {
+		/* re-use existing entry */
+		out_entry->l_smp2p_entry = state_entry_ptr;
+
+		SMP2P_DBG("%s: item '%s':%d reused\n", __func__,
+				out_entry->name, out_entry->remote_pid);
+	} else if (entries_valid >= entries_total) {
+		/* need to allocate entry, but not more space */
+		SMP2P_ERR("%s: no space for item '%s':%d\n",
+			__func__, out_entry->name, out_entry->remote_pid);
+		return -ENOMEM;
+	} else {
+		/* allocate a new entry */
+		struct smp2p_entry_v1 *entry_ptr;
+
+		entry_ptr = (struct smp2p_entry_v1 *)((char *)(smp2p_h_ptr + 1)
+			+ empty_spot * sizeof(struct smp2p_entry_v1));
+		strlcpy(entry_ptr->name, out_entry->name,
+				sizeof(entry_ptr->name));
+		out_entry->l_smp2p_entry = &entry_ptr->entry;
+		++entries_valid;
+		SMP2P_DBG("%s: item '%s':%d fully created as entry %d of %d\n",
+				__func__, out_entry->name,
+				out_entry->remote_pid,
+				entries_valid, entries_total);
+		SMP2P_SET_ENT_VALID(smp2p_h_ptr->valid_total_ent,
+				entries_valid);
+		smp2p_send_interrupt(out_entry->remote_pid);
+	}
+	raw_notifier_call_chain(&out_entry->msm_smp2p_notifier_list,
+		  SMP2P_OPEN, 0);
+
+	return 0;
+}
+
+/**
+ * smp2p_out_read_v1 -  Read the data from an outbound entry.
+ *
+ * @out_entry: Pointer to the SMP2P entry structure.
+ * @data: Out pointer, the data is available in this argument on success.
+ * @returns: 0 on success, standard Linux error code otherwise.
+ *
+ * Must be called with out_item_lock_lha1 locked.
+ */
+static int smp2p_out_read_v1(struct msm_smp2p_out *out_entry, uint32_t *data)
+{
+	struct smp2p_smem  *smp2p_h_ptr;
+	uint32_t remote_pid;
+
+	if (!out_entry)
+		return -EINVAL;
+
+	smp2p_h_ptr = out_list[out_entry->remote_pid].smem_edge_out;
+	remote_pid = SMP2P_GET_REMOTE_PID(smp2p_h_ptr->rem_loc_proc_id);
+
+	if (remote_pid != out_entry->remote_pid)
+		return -EINVAL;
+
+	if (out_entry->l_smp2p_entry) {
+		*data = readl_relaxed(out_entry->l_smp2p_entry);
+	} else {
+		SMP2P_ERR("%s: '%s':%d not yet OPEN\n", __func__,
+				out_entry->name, remote_pid);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+/**
+ * smp2p_out_write_v1 - Writes an outbound entry value.
+ *
+ * @out_entry: Pointer to the SMP2P entry structure.
+ * @data: The data to be written.
+ * @returns: 0 on success, standard Linux error code otherwise.
+ *
+ * Must be called with out_item_lock_lha1 locked.
+ */
+static int smp2p_out_write_v1(struct msm_smp2p_out *out_entry, uint32_t data)
+{
+	struct smp2p_smem  *smp2p_h_ptr;
+	uint32_t remote_pid;
+
+	if (!out_entry)
+		return -EINVAL;
+
+	smp2p_h_ptr = out_list[out_entry->remote_pid].smem_edge_out;
+	remote_pid = SMP2P_GET_REMOTE_PID(smp2p_h_ptr->rem_loc_proc_id);
+
+	if (remote_pid != out_entry->remote_pid)
+		return -EINVAL;
+
+	if (out_entry->l_smp2p_entry) {
+		writel_relaxed(data, out_entry->l_smp2p_entry);
+		smp2p_send_interrupt(remote_pid);
+	} else {
+		SMP2P_ERR("%s: '%s':%d not yet OPEN\n", __func__,
+				out_entry->name, remote_pid);
+		return -ENODEV;
+	}
+	return 0;
+}
+
+/**
+ * smp2p_out_modify_v1 - Modifies and outbound value.
+ *
+ * @set_mask:  Mask containing the bits that needs to be set.
+ * @clear_mask: Mask containing the bits that needs to be cleared.
+ * @returns: 0 on success, standard Linux error code otherwise.
+ *
+ * The clear mask is applied first, so  if a bit is set in both clear and
+ * set mask, the result will be that the bit is set.
+ *
+ * Must be called with out_item_lock_lha1 locked.
+ */
+static int smp2p_out_modify_v1(struct msm_smp2p_out *out_entry,
+		uint32_t set_mask, uint32_t clear_mask)
+{
+	struct smp2p_smem  *smp2p_h_ptr;
+	uint32_t remote_pid;
+
+	if (!out_entry)
+		return -EINVAL;
+
+	smp2p_h_ptr = out_list[out_entry->remote_pid].smem_edge_out;
+	remote_pid = SMP2P_GET_REMOTE_PID(smp2p_h_ptr->rem_loc_proc_id);
+
+	if (remote_pid != out_entry->remote_pid)
+			return -EINVAL;
+
+	if (out_entry->l_smp2p_entry) {
+		uint32_t curr_value;
+
+		curr_value = readl_relaxed(out_entry->l_smp2p_entry);
+		writel_relaxed((curr_value & ~clear_mask) | set_mask,
+			out_entry->l_smp2p_entry);
+	} else {
+		SMP2P_ERR("%s: '%s':%d not yet OPEN\n", __func__,
+				out_entry->name, remote_pid);
+		return -ENODEV;
+	}
+
+	smp2p_send_interrupt(remote_pid);
+	return 0;
+}
+
+/**
+ * smp2p_in_validate_size_v1 - Size validation for version 1.
+ *
+ * @remote_pid: Remote processor ID.
+ * @smem_item:  Pointer to the inbound SMEM item.
+ * @size:       Size of the SMEM item.
+ * @returns:    Validated smem_item pointer (or NULL if size is too small).
+ *
+ * Validates we don't end up with out-of-bounds array access due to invalid
+ * smem item size.  If out-of-bound array access can't be avoided, then an
+ * error message is printed and NULL is returned to prevent usage of the
+ * item.
+ *
+ * Must be called with in_item_lock_lhb1 locked.
+ */
+static struct smp2p_smem *smp2p_in_validate_size_v1(int remote_pid,
+		struct smp2p_smem *smem_item, uint32_t size)
+{
+	uint32_t total_entries;
+	unsigned expected_size;
+	struct smp2p_smem *item_ptr;
+	struct smp2p_in_list_item *in_item;
+
+	if (remote_pid >= SMP2P_NUM_PROCS || !smem_item)
+		return NULL;
+
+	in_item = &in_list[remote_pid];
+	item_ptr = (struct smp2p_smem *)smem_item;
+
+	total_entries = SMP2P_GET_ENT_TOTAL(item_ptr->valid_total_ent);
+	if (total_entries > 0) {
+		in_item->safe_total_entries = total_entries;
+		in_item->item_size = size;
+
+		expected_size =	sizeof(struct smp2p_smem) +
+			(total_entries * sizeof(struct smp2p_entry_v1));
+
+		if (size < expected_size) {
+			unsigned new_size;
+
+			new_size = size;
+			new_size -= sizeof(struct smp2p_smem);
+			new_size /= sizeof(struct smp2p_entry_v1);
+			in_item->safe_total_entries = new_size;
+
+			SMP2P_ERR(
+				"%s pid %d item too small for %d entries; expected: %d actual: %d; reduced to %d entries\n",
+				__func__, remote_pid, total_entries,
+				expected_size, size, new_size);
+		}
+	} else {
+		/*
+		 * Total entries is 0, so the entry is still being initialized
+		 * or is invalid.  Either way, treat it as if the item does
+		 * not exist yet.
+		 */
+		in_item->safe_total_entries = 0;
+		in_item->item_size = 0;
+	}
+	return item_ptr;
+}
+
+/**
+ * smp2p_negotiate_features_v0 - Initial feature negotiation.
+ *
+ * @features: Inbound feature set.
+ * @returns: 0 (no features supported for v0).
+ */
+static uint32_t smp2p_negotiate_features_v0(uint32_t features)
+{
+	/* no supported features */
+	return 0;
+}
+
+/**
+ * smp2p_find_entry_v0 - Stub function.
+ *
+ * @item: Pointer to the smem item.
+ * @entries_total: Total number of entries in @item.
+ * @name: Name of the entry.
+ * @entry_ptr: Set to pointer of entry if found, NULL otherwise.
+ * @empty_spot: If non-null, set to the value of the next empty entry.
+ *
+ * Entries cannot be searched for until item negotiation has been completed.
+ */
+static void smp2p_find_entry_v0(struct smp2p_smem *item,
+		uint32_t entries_total, char *name, uint32_t **entry_ptr,
+		int *empty_spot)
+{
+	if (entry_ptr)
+		*entry_ptr = NULL;
+
+	if (empty_spot)
+		*empty_spot = -1;
+
+	SMP2P_ERR("%s: invalid - item negotiation incomplete\n", __func__);
+}
+
+/**
+ * smp2p_out_create_v0 - Initial creation function.
+ *
+ * @out_entry: Pointer to the SMP2P entry structure.
+ * @returns: 0 on success, standard Linux error code otherwise.
+ *
+ * If the outbound SMEM item negotiation is not complete, then
+ * this function is called to start the negotiation process.
+ * Eventually when the negotiation process is complete, this
+ * function pointer is switched with the appropriate function
+ * for the version of SMP2P being created.
+ *
+ * Must be called with out_item_lock_lha1 locked.
+ */
+static int smp2p_out_create_v0(struct msm_smp2p_out *out_entry)
+{
+	int edge_state;
+	struct smp2p_out_list_item *item_ptr;
+
+	if (!out_entry)
+		return -EINVAL;
+
+	edge_state = out_list[out_entry->remote_pid].smem_edge_state;
+
+	switch (edge_state) {
+	case SMP2P_EDGE_STATE_CLOSED:
+		/* start negotiation */
+		item_ptr = &out_list[out_entry->remote_pid];
+		edge_state = smp2p_do_negotiation(out_entry->remote_pid,
+				item_ptr);
+		break;
+
+	case SMP2P_EDGE_STATE_OPENING:
+		/* still negotiating */
+		break;
+
+	case SMP2P_EDGE_STATE_OPENED:
+		SMP2P_ERR("%s: item '%s':%d opened - wrong create called\n",
+			__func__, out_entry->name, out_entry->remote_pid);
+		break;
+
+	default:
+		SMP2P_ERR("%s: item '%s':%d invalid SMEM item state %d\n",
+			__func__, out_entry->name, out_entry->remote_pid,
+			edge_state);
+		break;
+	}
+	return 0;
+}
+
+/**
+ * smp2p_out_read_v0 - Stub function.
+ *
+ * @out_entry: Pointer to the SMP2P entry structure.
+ * @data: Out pointer, the data is available in this argument on success.
+ * @returns: -ENODEV
+ */
+static int smp2p_out_read_v0(struct msm_smp2p_out *out_entry, uint32_t *data)
+{
+	SMP2P_ERR("%s: item '%s':%d not OPEN\n",
+		__func__, out_entry->name, out_entry->remote_pid);
+
+	return -ENODEV;
+}
+
+/**
+ * smp2p_out_write_v0 - Stub function.
+ *
+ * @out_entry: Pointer to the SMP2P entry structure.
+ * @data: The data to be written.
+ * @returns: -ENODEV
+ */
+static int smp2p_out_write_v0(struct msm_smp2p_out *out_entry, uint32_t data)
+{
+	SMP2P_ERR("%s: item '%s':%d not yet OPEN\n",
+		__func__, out_entry->name, out_entry->remote_pid);
+
+	return -ENODEV;
+}
+
+/**
+ * smp2p_out_modify_v0 - Stub function.
+ *
+ * @set_mask:  Mask containing the bits that needs to be set.
+ * @clear_mask: Mask containing the bits that needs to be cleared.
+ * @returns: -ENODEV
+ */
+static int smp2p_out_modify_v0(struct msm_smp2p_out *out_entry,
+		uint32_t set_mask, uint32_t clear_mask)
+{
+	SMP2P_ERR("%s: item '%s':%d not yet OPEN\n",
+		__func__, out_entry->name, out_entry->remote_pid);
+
+	return -ENODEV;
+}
+
+/**
+ * smp2p_in_validate_size_v0 - Stub function.
+ *
+ * @remote_pid: Remote processor ID.
+ * @smem_item:  Pointer to the inbound SMEM item.
+ * @size:       Size of the SMEM item.
+ * @returns:    Validated smem_item pointer (or NULL if size is too small).
+ *
+ * Validates we don't end up with out-of-bounds array access due to invalid
+ * smem item size.  If out-of-bound array access can't be avoided, then an
+ * error message is printed and NULL is returned to prevent usage of the
+ * item.
+ *
+ * Must be called with in_item_lock_lhb1 locked.
+ */
+static struct smp2p_smem *smp2p_in_validate_size_v0(int remote_pid,
+		struct smp2p_smem *smem_item, uint32_t size)
+{
+	struct smp2p_in_list_item *in_item;
+
+	if (remote_pid >= SMP2P_NUM_PROCS || !smem_item)
+		return NULL;
+
+	in_item = &in_list[remote_pid];
+
+	if (size < sizeof(struct smp2p_smem)) {
+		SMP2P_ERR(
+			"%s pid %d item size too small; expected: %d actual: %d\n",
+			__func__, remote_pid,
+			sizeof(struct smp2p_smem), size);
+		smem_item = NULL;
+		in_item->item_size = 0;
+	} else {
+		in_item->item_size = size;
+	}
+	return smem_item;
+}
+
+/**
+ * smp2p_init_header - Initializes the header of the smem item.
+ *
+ * @header_ptr: Pointer to the smp2p header.
+ * @local_pid: Local processor ID.
+ * @remote_pid: Remote processor ID.
+ * @feature: Features of smp2p implementation.
+ * @version: Version of smp2p implementation.
+ *
+ * Initializes the header as defined in the protocol specification.
+ */
+void smp2p_init_header(struct smp2p_smem *header_ptr,
+		int local_pid, int remote_pid,
+		uint32_t features, uint32_t version)
+{
+	header_ptr->magic = SMP2P_MAGIC;
+	SMP2P_SET_LOCAL_PID(header_ptr->rem_loc_proc_id, local_pid);
+	SMP2P_SET_REMOTE_PID(header_ptr->rem_loc_proc_id, remote_pid);
+	SMP2P_SET_FEATURES(header_ptr->feature_version, features);
+	SMP2P_SET_ENT_TOTAL(header_ptr->valid_total_ent, SMP2P_MAX_ENTRY);
+	SMP2P_SET_ENT_VALID(header_ptr->valid_total_ent, 0);
+	header_ptr->reserved = 0;
+
+	/* ensure that all fields are valid before version is written */
+	wmb();
+	SMP2P_SET_VERSION(header_ptr->feature_version, version);
+}
+
+/**
+ * smp2p_do_negotiation - Implements negotiation algorithm.
+ *
+ * @remote_pid: Remote processor ID.
+ * @out_item: Pointer to the outbound list item.
+ * @returns: 0 on success, standard Linux error code otherwise.
+ *
+ * Must be called with out_item_lock_lha1 locked.  Will internally lock
+ * in_item_lock_lhb1.
+ */
+static int smp2p_do_negotiation(int remote_pid,
+		struct smp2p_out_list_item *out_item)
+{
+	struct smp2p_smem *r_smem_ptr, *l_smem_ptr;
+	uint32_t r_version;
+	uint32_t r_feature;
+	uint32_t l_version, l_feature;
+	int prev_state;
+
+	if (remote_pid >= SMP2P_NUM_PROCS || !out_item)
+		return -EINVAL;
+	if (out_item->smem_edge_state == SMP2P_EDGE_STATE_FAILED)
+		return -EPERM;
+
+	prev_state = out_item->smem_edge_state;
+
+	/* create local item */
+	if (!out_item->smem_edge_out) {
+		out_item->smem_edge_out = smp2p_get_local_smem_item(remote_pid);
+		if (!out_item->smem_edge_out) {
+			SMP2P_ERR(
+				"%s unable to allocate SMEM item for pid %d\n",
+				__func__, remote_pid);
+			return -ENODEV;
+		}
+		out_item->smem_edge_state = SMP2P_EDGE_STATE_OPENING;
+	}
+	l_smem_ptr = out_item->smem_edge_out;
+
+	/* retrieve remote side and version */
+	spin_lock(&in_list[remote_pid].in_item_lock_lhb1);
+	r_smem_ptr = smp2p_get_remote_smem_item(remote_pid, out_item);
+	spin_unlock(&in_list[remote_pid].in_item_lock_lhb1);
+
+	r_version = 0;
+	if (r_smem_ptr) {
+		r_version = SMP2P_GET_VERSION(r_smem_ptr->feature_version);
+		r_feature = SMP2P_GET_FEATURES(r_smem_ptr->feature_version);
+	}
+
+	if (r_version == 0) {
+		/*
+		 * Either remote side doesn't exist, or is in the
+		 * process of being initialized (the version is set last).
+		 *
+		 * In either case, treat as if the other side doesn't exist
+		 * and write out our maximum supported version.
+		 */
+		r_smem_ptr = NULL;
+		r_version = ARRAY_SIZE(version_if) - 1;
+		r_feature = ~0U;
+	}
+
+	/* find maximum supported version and feature set */
+	l_version = min(r_version, ARRAY_SIZE(version_if) - 1);
+	for (; l_version > 0; --l_version) {
+		if (!version_if[l_version].is_supported)
+			continue;
+
+		/* found valid version */
+		l_feature = version_if[l_version].negotiate_features(~0U);
+		if (l_version == r_version)
+			l_feature &= r_feature;
+		break;
+	}
+
+	if (l_version == 0) {
+		SMP2P_ERR(
+			"%s: negotiation failure pid %d: RV %d RF %x\n",
+			__func__, remote_pid, r_version, r_feature
+			);
+		SMP2P_SET_VERSION(l_smem_ptr->feature_version,
+			SMP2P_EDGE_STATE_FAILED);
+		smp2p_send_interrupt(remote_pid);
+		out_item->smem_edge_state = SMP2P_EDGE_STATE_FAILED;
+		return -EPERM;
+	}
+
+	/* update header and notify remote side */
+	smp2p_init_header(l_smem_ptr, SMP2P_APPS_PROC, remote_pid,
+		l_feature, l_version);
+	smp2p_send_interrupt(remote_pid);
+
+	/* handle internal state changes */
+	if (r_smem_ptr && l_version == r_version &&
+			l_feature == r_feature) {
+		struct msm_smp2p_out *pos;
+
+		/* negotiation complete */
+		out_item->smem_edge_state = SMP2P_EDGE_STATE_OPENED;
+		out_item->ops_ptr = &version_if[l_version];
+		SMP2P_INFO(
+			"%s: negotiation complete pid %d: State %d->%d F0x%08x\n",
+			__func__, remote_pid, prev_state,
+			out_item->smem_edge_state, l_feature);
+
+		/* create any pending outbound entries */
+		list_for_each_entry(pos, &out_item->list, out_edge_list) {
+			out_item->ops_ptr->create_entry(pos);
+		}
+
+		/* update inbound edge */
+		spin_lock(&in_list[remote_pid].in_item_lock_lhb1);
+		(void)out_item->ops_ptr->validate_size(remote_pid, r_smem_ptr,
+				in_list[remote_pid].item_size);
+		in_list[remote_pid].smem_edge_in = r_smem_ptr;
+		spin_unlock(&in_list[remote_pid].in_item_lock_lhb1);
+	} else {
+		SMP2P_INFO("%s: negotiation pid %d: State %d->%d F0x%08x\n",
+			__func__, remote_pid, prev_state,
+			out_item->smem_edge_state, l_feature);
+	}
+	return 0;
+}
+
+/**
+ * msm_smp2p_out_open - Opens an outbound entry.
+ *
+ * @remote_pid: Outbound processor ID.
+ * @name: Name of the entry.
+ * @open_notifier: Notifier block for the open notification.
+ * @handle: Handle to the smem entry structure.
+ * @returns: 0 on success, standard Linux error code otherwise.
+ *
+ * Opens an outbound entry with the name specified by entry, from the
+ * local processor to the remote processor(remote_pid). If the entry, remote_pid
+ * and open_notifier are valid, then handle will be set and zero will be
+ * returned. The smem item that holds this entry will be created if it has
+ * not been created according to the version negotiation algorithm.
+ * The open_notifier will be used to notify the clients about the
+ * availability of the entry.
+ */
+int msm_smp2p_out_open(int remote_pid, const char *name,
+				   struct notifier_block *open_notifier,
+				   struct msm_smp2p_out **handle)
+{
+	struct msm_smp2p_out *out_entry;
+	struct msm_smp2p_out *pos;
+	int ret = 0;
+	unsigned long flags;
+
+	if (handle)
+		*handle = NULL;
+
+	if (remote_pid >= SMP2P_NUM_PROCS || !name || !open_notifier || !handle)
+		return -EINVAL;
+
+	/* Allocate the smp2p object and node */
+	out_entry = kzalloc(sizeof(*out_entry), GFP_KERNEL);
+	if (!out_entry)
+		return -ENOMEM;
+
+	/* Handle duplicate registration */
+	spin_lock_irqsave(&out_list[remote_pid].out_item_lock_lha1, flags);
+	list_for_each_entry(pos, &out_list[remote_pid].list,
+			out_edge_list) {
+		if (!strcmp(pos->name, name)) {
+			spin_unlock_irqrestore(
+				&out_list[remote_pid].out_item_lock_lha1,
+				flags);
+			kfree(out_entry);
+			SMP2P_ERR("%s: duplicate registration '%s':%d\n",
+				__func__, name, remote_pid);
+			return -EBUSY;
+		}
+	}
+
+	out_entry->remote_pid = remote_pid;
+	RAW_INIT_NOTIFIER_HEAD(&out_entry->msm_smp2p_notifier_list);
+	strlcpy(out_entry->name, name, SMP2P_MAX_ENTRY_NAME);
+	out_entry->open_nb = open_notifier;
+	raw_notifier_chain_register(&out_entry->msm_smp2p_notifier_list,
+		  out_entry->open_nb);
+	list_add(&out_entry->out_edge_list, &out_list[remote_pid].list);
+
+	ret = out_list[remote_pid].ops_ptr->create_entry(out_entry);
+	if (ret) {
+		list_del(&out_entry->out_edge_list);
+		raw_notifier_chain_unregister(
+			&out_entry->msm_smp2p_notifier_list,
+			out_entry->open_nb);
+		spin_unlock_irqrestore(
+			&out_list[remote_pid].out_item_lock_lha1, flags);
+		kfree(out_entry);
+		SMP2P_ERR("%s: unable to open '%s':%d error %d\n",
+				__func__, name, remote_pid, ret);
+		return ret;
+	}
+	spin_unlock_irqrestore(&out_list[remote_pid].out_item_lock_lha1,
+			flags);
+	*handle = out_entry;
+
+	return 0;
+}
+EXPORT_SYMBOL(msm_smp2p_out_open);
+
+/**
+ * msm_smp2p_out_close - Closes the handle to an outbound entry.
+ *
+ * @handle: Pointer to smp2p out entry handle.
+ * @returns: 0 on success, standard Linux error code otherwise.
+ *
+ * The actual entry will not be deleted and can be re-opened at a later
+ * time.  The handle will be set to NULL.
+ */
+int msm_smp2p_out_close(struct msm_smp2p_out **handle)
+{
+	unsigned long flags;
+	struct msm_smp2p_out *out_entry;
+	struct smp2p_out_list_item *out_item;
+
+	if (!handle || !*handle)
+		return -EINVAL;
+
+	out_entry = *handle;
+	*handle = NULL;
+
+	out_item = &out_list[out_entry->remote_pid];
+	spin_lock_irqsave(&out_item->out_item_lock_lha1, flags);
+	list_del(&out_entry->out_edge_list);
+	raw_notifier_chain_unregister(&out_entry->msm_smp2p_notifier_list,
+		out_entry->open_nb);
+	spin_unlock_irqrestore(&out_item->out_item_lock_lha1, flags);
+
+	kfree(out_entry);
+
+	return 0;
+}
+EXPORT_SYMBOL(msm_smp2p_out_close);
+
+/**
+ * msm_smp2p_out_read - Allows reading the entry.
+ *
+ * @handle: Handle to the smem entry structure.
+ * @data: Out pointer that holds the read data.
+ * @returns: 0 on success, standard Linux error code otherwise.
+ *
+ * Allows reading of the outbound entry for read-modify-write
+ * operation.
+ */
+int msm_smp2p_out_read(struct msm_smp2p_out *handle, uint32_t *data)
+{
+	int ret = -EINVAL;
+	unsigned long flags;
+	struct smp2p_out_list_item *out_item;
+
+	if (!handle || !data)
+		return ret;
+
+	out_item = &out_list[handle->remote_pid];
+	spin_lock_irqsave(&out_item->out_item_lock_lha1, flags);
+	ret = out_item->ops_ptr->read_entry(handle, data);
+	spin_unlock_irqrestore(&out_item->out_item_lock_lha1, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL(msm_smp2p_out_read);
+
+/**
+ * msm_smp2p_out_write - Allows writing to the entry.
+ *
+ * @handle: Handle to smem entry structure.
+ * @data: Data that has to be written.
+ * @returns: 0 on success, standard Linux error code otherwise.
+ *
+ * Writes a new value to the output entry. Multiple back-to-back writes
+ * may overwrite previous writes before the remote processor get a chance
+ * to see them leading to ABA race condition. The client must implement
+ * their own synchronization mechanism (such as echo mechanism) if this is
+ * not acceptable.
+ */
+int msm_smp2p_out_write(struct msm_smp2p_out *handle, uint32_t data)
+{
+	int ret = -EINVAL;
+	unsigned long flags;
+	struct smp2p_out_list_item *out_item;
+
+	if (!handle)
+		return ret;
+
+	out_item = &out_list[handle->remote_pid];
+	spin_lock_irqsave(&out_item->out_item_lock_lha1, flags);
+	ret = out_item->ops_ptr->write_entry(handle, data);
+	spin_unlock_irqrestore(&out_item->out_item_lock_lha1, flags);
+
+	return ret;
+
+}
+EXPORT_SYMBOL(msm_smp2p_out_write);
+
+/**
+ * msm_smp2p_out_modify - Modifies the entry.
+ *
+ * @handle: Handle to the smem entry structure.
+ * @set_mask: Specifies the bits that needs to be set.
+ * @clear_mask: Specifies the bits that needs to be cleared.
+ * @returns: 0 on success, standard Linux error code otherwise.
+ *
+ * The modification is done by doing a bitwise AND of clear mask followed by
+ * the bit wise OR of set mask. The clear bit mask is applied first to the
+ * data, so if a bit is set in both the clear mask and the set mask, then in
+ * the result is a set bit.  Multiple back-to-back modifications may overwrite
+ * previous values before the remote processor gets a chance to see them
+ * leading to ABA race condition. The client must implement their own
+ * synchronization mechanism (such as echo mechanism) if this is not
+ * acceptable.
+ */
+int msm_smp2p_out_modify(struct msm_smp2p_out *handle, uint32_t set_mask,
+							uint32_t clear_mask)
+{
+	int ret = -EINVAL;
+	unsigned long flags;
+	struct smp2p_out_list_item *out_item;
+
+	if (!handle)
+		return ret;
+
+	out_item = &out_list[handle->remote_pid];
+	spin_lock_irqsave(&out_item->out_item_lock_lha1, flags);
+	ret = out_item->ops_ptr->modify_entry(handle, set_mask, clear_mask);
+	spin_unlock_irqrestore(&out_item->out_item_lock_lha1, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL(msm_smp2p_out_modify);
+
+/**
+ * msm_smp2p_in_read - Read an entry on a remote processor.
+ *
+ * @remote_pid: Processor ID of the remote processor.
+ * @name: Name of the entry that is to be read.
+ * @data: Output pointer, the value will be placed here if successful.
+ * @returns: 0 on success, standard Linux error code otherwise.
+ */
+int msm_smp2p_in_read(int remote_pid, const char *name, uint32_t *data)
+{
+	unsigned long flags;
+	struct smp2p_out_list_item *out_item;
+	uint32_t *entry_ptr;
+
+	if (remote_pid >= SMP2P_NUM_PROCS)
+		return -EINVAL;
+
+	out_item = &out_list[remote_pid];
+	spin_lock_irqsave(&out_item->out_item_lock_lha1, flags);
+	spin_lock(&in_list[remote_pid].in_item_lock_lhb1);
+
+	if (in_list[remote_pid].smem_edge_in)
+		out_item->ops_ptr->find_entry(
+			in_list[remote_pid].smem_edge_in,
+			in_list[remote_pid].safe_total_entries,
+			(char *)name, &entry_ptr, NULL);
+
+	spin_unlock(&in_list[remote_pid].in_item_lock_lhb1);
+	spin_unlock_irqrestore(&out_item->out_item_lock_lha1, flags);
+
+	if (!entry_ptr)
+		return -ENODEV;
+
+	*data = readl_relaxed(entry_ptr);
+	return 0;
+}
+EXPORT_SYMBOL(msm_smp2p_in_read);
+
+/**
+ * msm_smp2p_in_register -  Notifies the change in value of the entry.
+ *
+ * @pid: Remote processor ID.
+ * @name: Name of the entry.
+ * @in_notifier: Notifier block used to notify about the event.
+ * @returns: 0 on success, standard Linux error code otherwise.
+ *
+ * Register for change notifications for a remote entry. If the remote entry
+ * does not exist yet, then the registration request will be held until the
+ * remote side opens. Once the entry is open, then the SMP2P_OPEN notification
+ * will be sent. Any changes to the entry will trigger a call to the notifier
+ * block with an SMP2P_ENTRY_UPDATE event and the data field will point to an
+ * msm_smp2p_update_notif structure containing the current and previous value.
+ */
+int msm_smp2p_in_register(int pid, const char *name,
+	struct notifier_block *in_notifier)
+{
+	struct smp2p_in *pos;
+	struct smp2p_in *in = NULL;
+	int ret;
+	unsigned long flags;
+	struct msm_smp2p_update_notif data;
+	uint32_t *entry_ptr;
+
+	if (pid >= SMP2P_NUM_PROCS || !name || !in_notifier)
+		return -EINVAL;
+
+	/* Pre-allocate before spinlock since we will likely needed it */
+	in = kzalloc(sizeof(*in), GFP_KERNEL);
+	if (!in)
+		return -ENOMEM;
+
+	/* Search for existing entry */
+	spin_lock_irqsave(&out_list[pid].out_item_lock_lha1, flags);
+	spin_lock(&in_list[pid].in_item_lock_lhb1);
+
+	list_for_each_entry(pos, &in_list[pid].list, in_edge_list) {
+		if (!strncmp(pos->name, name,
+					SMP2P_MAX_ENTRY_NAME)) {
+			kfree(in);
+			in = pos;
+			break;
+		}
+	}
+
+	/* Create and add it to the list */
+	in->remote_pid = pid;
+	strlcpy(in->name, name, SMP2P_MAX_ENTRY_NAME);
+	RAW_INIT_NOTIFIER_HEAD(&in->in_notifier_list);
+	list_add(&in->in_edge_list, &in_list[pid].list);
+	ret = raw_notifier_chain_register(&in->in_notifier_list,
+			in_notifier);
+	if (ret) {
+		SMP2P_DBG("%s: '%s':%d failed %d\n", __func__, name, pid, ret);
+		goto bail;
+	}
+	in->notifier_count++;
+
+	if (out_list[pid].smem_edge_state == SMP2P_EDGE_STATE_OPENED) {
+		out_list[pid].ops_ptr->find_entry(
+				in_list[pid].smem_edge_in,
+				in_list[pid].safe_total_entries, (char *)name,
+				&entry_ptr, NULL);
+		if (entry_ptr) {
+			in->entry_ptr = entry_ptr;
+			in->entry_val = *(entry_ptr);
+
+			data.previous_value = in->entry_val;
+			data.current_value = *(in->entry_ptr);
+			in_notifier->notifier_call(in_notifier, SMP2P_OPEN,
+					(void *)&data);
+		}
+	}
+	SMP2P_DBG("%s: '%s':%d registered\n", __func__, name, pid);
+
+bail:
+	spin_unlock(&in_list[pid].in_item_lock_lhb1);
+	spin_unlock_irqrestore(&out_list[pid].out_item_lock_lha1, flags);
+	return ret;
+
+}
+EXPORT_SYMBOL(msm_smp2p_in_register);
+
+/**
+ * msm_smp2p_in_unregister - Unregister the notifier for remote entry.
+ *
+ * @remote_pid: Processor Id of the remote processor.
+ * @name: The name of the entry.
+ * @in_notifier: Notifier block passed during registration.
+ * @returns: 0 on success, standard Linux error code otherwise.
+ */
+int msm_smp2p_in_unregister(int remote_pid, const char *name,
+				struct notifier_block *in_notifier)
+{
+	struct smp2p_in *pos;
+	struct smp2p_in *in = NULL;
+	int ret = -ENODEV;
+	unsigned long flags;
+
+	if (remote_pid >= SMP2P_NUM_PROCS || !name || !in_notifier)
+		return -EINVAL;
+
+	spin_lock_irqsave(&in_list[remote_pid].in_item_lock_lhb1, flags);
+	list_for_each_entry(pos, &in_list[remote_pid].list,
+			in_edge_list) {
+		if (!strncmp(pos->name, name, SMP2P_MAX_ENTRY_NAME)) {
+			in = pos;
+			break;
+		}
+	}
+	if (!in)
+		goto fail;
+
+	ret = raw_notifier_chain_unregister(&pos->in_notifier_list,
+			in_notifier);
+	if (ret == 0) {
+		pos->notifier_count--;
+		if (!pos->notifier_count) {
+			list_del(&pos->in_edge_list);
+			kfree(pos);
+			ret = 0;
+		}
+	} else {
+		SMP2P_ERR("%s: unregister failure '%s':%d\n", __func__,
+			name, remote_pid);
+		ret = -ENODEV;
+	}
+
+fail:
+	spin_unlock_irqrestore(&in_list[remote_pid].in_item_lock_lhb1, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL(msm_smp2p_in_unregister);
+
+/**
+ * smp2p_send_interrupt - Send interrupt to remote system.
+ *
+ * @remote_pid:  Processor ID of the remote system
+ *
+ * Must be called with out_item_lock_lha1 locked.
+ */
+static void smp2p_send_interrupt(int remote_pid)
+{
+	if (smp2p_int_cfgs[remote_pid].name)
+		SMP2P_DBG("SMP2P Int Apps->%s(%d)\n",
+			smp2p_int_cfgs[remote_pid].name, remote_pid);
+
+	++smp2p_int_cfgs[remote_pid].out_interrupt_count;
+	if (remote_pid != SMP2P_REMOTE_MOCK_PROC &&
+			smp2p_int_cfgs[remote_pid].out_int_mask) {
+		/* flush any pending writes before triggering interrupt */
+		wmb();
+		writel_relaxed(smp2p_int_cfgs[remote_pid].out_int_mask,
+			smp2p_int_cfgs[remote_pid].out_int_ptr);
+	} else {
+		smp2p_remote_mock_rx_interrupt();
+	}
+}
+
+/**
+ * smp2p_in_edge_notify - Notifies the entry changed on remote processor.
+ *
+ * @pid: Processor ID of the remote processor.
+ *
+ * This function is invoked on an incoming interrupt, it scans
+ * the list of the clients registered for the entries on the remote
+ * processor and notifies them if  the data changes.
+ *
+ * Must be called with out_item_lock_lha1 locked.
+ */
+static void smp2p_in_edge_notify(int pid)
+{
+	struct smp2p_in *pos;
+	uint32_t *entry_ptr;
+	unsigned long flags;
+	struct smp2p_smem *smem_h_ptr;
+	uint32_t curr_data;
+	struct  msm_smp2p_update_notif data;
+
+	spin_lock_irqsave(&in_list[pid].in_item_lock_lhb1, flags);
+	smem_h_ptr = in_list[pid].smem_edge_in;
+	if (!smem_h_ptr) {
+		SMP2P_DBG("%s: No remote SMEM item for pid %d\n",
+			__func__, pid);
+		spin_unlock_irqrestore(&in_list[pid].in_item_lock_lhb1, flags);
+		return;
+	}
+
+	list_for_each_entry(pos, &in_list[pid].list, in_edge_list) {
+		if (pos->entry_ptr != NULL) {
+			/* entry already open */
+			curr_data = *(pos->entry_ptr);
+			if (curr_data != pos->entry_val) {
+				data.previous_value = pos->entry_val;
+				data.current_value = curr_data;
+				pos->entry_val = curr_data;
+				raw_notifier_call_chain(
+					&pos->in_notifier_list,
+					SMP2P_ENTRY_UPDATE, (void *)&data);
+			}
+		} else {
+			/* entry not open - try to open it */
+			out_list[pid].ops_ptr->find_entry(smem_h_ptr,
+				in_list[pid].safe_total_entries, pos->name,
+				&entry_ptr, NULL);
+
+			if (entry_ptr) {
+				pos->entry_ptr = entry_ptr;
+				data.previous_value = 0;
+				data.current_value =
+					*(entry_ptr);
+				raw_notifier_call_chain(
+					    &pos->in_notifier_list,
+					    SMP2P_OPEN, (void *)&data);
+			}
+		}
+	}
+	spin_unlock_irqrestore(&in_list[pid].in_item_lock_lhb1, flags);
+}
+
+/**
+ * smp2p_interrupt_handler - Incoming interrupt handler.
+ *
+ * @irq: Interrupt ID
+ * @data: Edge
+ * @returns: IRQ_HANDLED or IRQ_NONE for invalid interrupt
+ */
+static irqreturn_t smp2p_interrupt_handler(int irq, void *data)
+{
+	unsigned long flags;
+	uint32_t remote_pid = (uint32_t)data;
+
+	if (remote_pid >= SMP2P_NUM_PROCS) {
+		SMP2P_ERR("%s: invalid interrupt pid %d\n",
+			__func__, remote_pid);
+		return IRQ_NONE;
+	}
+
+	if (smp2p_int_cfgs[remote_pid].name)
+		SMP2P_DBG("SMP2P Int %s(%d)->Apps\n",
+			smp2p_int_cfgs[remote_pid].name, remote_pid);
+
+	spin_lock_irqsave(&out_list[remote_pid].out_item_lock_lha1, flags);
+	++smp2p_int_cfgs[remote_pid].in_interrupt_count;
+
+	if (out_list[remote_pid].smem_edge_state != SMP2P_EDGE_STATE_OPENED)
+		smp2p_do_negotiation(remote_pid, &out_list[remote_pid]);
+
+	if (out_list[remote_pid].smem_edge_state == SMP2P_EDGE_STATE_OPENED)
+		smp2p_in_edge_notify(remote_pid);
+	spin_unlock_irqrestore(&out_list[remote_pid].out_item_lock_lha1, flags);
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * smp2p_reset_mock_edge - Reinitializes the mock edge.
+ *
+ * @returns: 0 on success, -EAGAIN to retry later.
+ *
+ * Reinitializes the mock edge to initial power-up state values.
+ */
+int smp2p_reset_mock_edge(void)
+{
+	const int rpid = SMP2P_REMOTE_MOCK_PROC;
+	unsigned long flags;
+	int ret = 0;
+
+	spin_lock_irqsave(&out_list[rpid].out_item_lock_lha1, flags);
+	spin_lock(&in_list[rpid].in_item_lock_lhb1);
+
+	if (!list_empty(&out_list[rpid].list) ||
+			!list_empty(&in_list[rpid].list)) {
+		ret = -EAGAIN;
+		goto fail;
+	}
+
+	kfree(out_list[rpid].smem_edge_out);
+	out_list[rpid].smem_edge_out = NULL;
+	out_list[rpid].ops_ptr = &version_if[0];
+	out_list[rpid].smem_edge_state = SMP2P_EDGE_STATE_CLOSED;
+
+	in_list[rpid].smem_edge_in = NULL;
+	in_list[rpid].item_size = 0;
+	in_list[rpid].safe_total_entries = 0;
+
+fail:
+	spin_unlock(&in_list[rpid].in_item_lock_lhb1);
+	spin_unlock_irqrestore(&out_list[rpid].out_item_lock_lha1, flags);
+
+	return ret;
+}
+
+/**
+ * msm_smp2p_interrupt_handler - Triggers incoming interrupt.
+ *
+ * @remote_pid: Remote processor ID
+ *
+ * This function is used with the remote mock infrastructure
+ * used for testing. It simulates triggering of interrupt in
+ * a testing environment.
+ */
+void msm_smp2p_interrupt_handler(int remote_pid)
+{
+	smp2p_interrupt_handler(0, (void *)remote_pid);
+}
+
+/**
+ * msm_smp2p_probe - Device tree probe function.
+ *
+ * @pdev: Pointer to device tree data.
+ * @returns: 0 on success; -ENODEV otherwise
+ */
+static int __devinit msm_smp2p_probe(struct platform_device *pdev)
+{
+	struct resource *irq_out_base;
+	struct resource *irq_offset;
+	char *key;
+	uint32_t edge;
+	int ret;
+	struct device_node *node;
+	uint32_t irq_bitmask;
+	uint32_t irq_line;
+
+	node = pdev->dev.of_node;
+
+	key = "qcom,remote-pid";
+	ret = of_property_read_u32(node, key, &edge);
+	if (ret) {
+		SMP2P_ERR("%s: missing edge '%s'\n", __func__, key);
+		goto fail;
+	}
+
+	key = "irq-reg-base";
+	irq_out_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, key);
+	if (!irq_out_base)
+		goto missing_key;
+
+	key = "irq-reg-offset";
+	irq_offset = platform_get_resource_byname(pdev, IORESOURCE_MEM, key);
+	if (!irq_offset)
+		goto missing_key;
+
+	key = "qcom,irq-bitmask";
+	ret = of_property_read_u32(node, key, &irq_bitmask);
+	if (ret)
+		goto missing_key;
+
+	key = "interrupts";
+	irq_line = platform_get_irq(pdev, 0);
+	if (irq_line == -ENXIO)
+		goto missing_key;
+
+	ret = request_irq(irq_line, smp2p_interrupt_handler,
+			IRQF_TRIGGER_RISING, "smp2p", (void *)edge);
+	if (ret < 0) {
+		SMP2P_ERR("%s: request_irq() failed on %d (edge %d)\n",
+				__func__, irq_line, edge);
+		goto fail;
+	}
+
+	ret = enable_irq_wake(irq_line);
+	if (ret < 0)
+		SMP2P_ERR("%s: enable_irq_wake() failed on %d (edge %d)\n",
+				__func__, irq_line, edge);
+
+	/*
+	 * Set entry (keep is_configured last to prevent usage before
+	 * initialization).
+	 */
+	smp2p_int_cfgs[edge].in_int_id = irq_line;
+	smp2p_int_cfgs[edge].out_int_mask = irq_bitmask;
+	smp2p_int_cfgs[edge].out_int_ptr =
+		(uint32_t *)((uint32_t)irq_out_base->start +
+				(uint32_t)irq_offset->start);
+	smp2p_int_cfgs[edge].is_configured = true;
+	return 0;
+
+missing_key:
+	SMP2P_ERR("%s: missing '%s' for edge %d\n", __func__, key, edge);
+fail:
+	return -ENODEV;
+}
+
+static struct of_device_id msm_smp2p_match_table[] = {
+	{ .compatible = "qcom,smp2p" },
+	{},
+};
+
+static struct platform_driver msm_smp2p_driver = {
+	.probe = msm_smp2p_probe,
+	.driver = {
+		.name = "msm_smp2p",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_smp2p_match_table,
+	},
+};
+
+/**
+ * msm_smp2p_init -  Initialization function for the module.
+ *
+ * @returns: 0 on success, standard Linux error code otherwise.
+ */
+static int __init msm_smp2p_init(void)
+{
+	int i;
+	int rc;
+
+	for (i = 0; i < SMP2P_NUM_PROCS; i++) {
+		spin_lock_init(&out_list[i].out_item_lock_lha1);
+		INIT_LIST_HEAD(&out_list[i].list);
+		out_list[i].smem_edge_out = NULL;
+		out_list[i].smem_edge_state = SMP2P_EDGE_STATE_CLOSED;
+		out_list[i].ops_ptr = &version_if[0];
+
+		spin_lock_init(&in_list[i].in_item_lock_lhb1);
+		INIT_LIST_HEAD(&in_list[i].list);
+		in_list[i].smem_edge_in = NULL;
+	}
+
+	log_ctx = ipc_log_context_create(NUM_LOG_PAGES, "smp2p");
+	if (!log_ctx)
+		SMP2P_ERR("%s: unable to create log context\n", __func__);
+
+	rc = platform_driver_register(&msm_smp2p_driver);
+	if (rc) {
+		SMP2P_ERR("%s: msm_smp2p_driver register failed %d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	return 0;
+}
+module_init(msm_smp2p_init);
+
+MODULE_DESCRIPTION("MSM Shared Memory Point to Point");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/smp2p_debug.c b/arch/arm/mach-msm/smp2p_debug.c
new file mode 100644
index 0000000..1a5c96e
--- /dev/null
+++ b/arch/arm/mach-msm/smp2p_debug.c
@@ -0,0 +1,328 @@
+/* arch/arm/mach-msm/smp2p_debug.c
+ *
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/ctype.h>
+#include <linux/list.h>
+#include <linux/debugfs.h>
+#include "smp2p_private.h"
+
+#if defined(CONFIG_DEBUG_FS)
+
+/**
+ * Dump interrupt statistics.
+ *
+ * @s:   pointer to output file
+ */
+static void smp2p_int_stats(struct seq_file *s)
+{
+	struct smp2p_interrupt_config *int_cfg;
+	int pid;
+
+	int_cfg = smp2p_get_interrupt_config();
+	if (!int_cfg)
+		return;
+
+	seq_printf(s, "| Processor | Incoming Id | Incoming # |");
+	seq_printf(s, " Outgoing # | Base Ptr |   Mask   |\n");
+
+	for (pid = 0; pid < SMP2P_NUM_PROCS; ++pid) {
+		if (!int_cfg[pid].is_configured &&
+				pid != SMP2P_REMOTE_MOCK_PROC)
+			continue;
+
+		seq_printf(s,
+			"| %5s (%d) | %11u | %10u | %10u | %p | %08x |\n",
+			int_cfg[pid].name,
+			pid, int_cfg[pid].in_int_id,
+			int_cfg[pid].in_interrupt_count,
+			int_cfg[pid].out_interrupt_count,
+			int_cfg[pid].out_int_ptr,
+			int_cfg[pid].out_int_mask);
+	}
+}
+
+/**
+ * Dump item header line 1.
+ *
+ * @buf:      output buffer
+ * @max:      length of output buffer
+ * @item_ptr: SMEM item pointer
+ * @state:    item state
+ * @returns: Number of bytes written to output buffer
+ */
+static int smp2p_item_header1(char *buf, int max, struct smp2p_smem *item_ptr,
+	enum msm_smp2p_edge_state state)
+{
+	int i = 0;
+	const char *state_text;
+
+	if (!item_ptr) {
+		i += scnprintf(buf + i, max - i, "None");
+		return i;
+	}
+
+	switch (state) {
+	case SMP2P_EDGE_STATE_CLOSED:
+		state_text = "State: Closed";
+		break;
+	case SMP2P_EDGE_STATE_OPENING:
+		state_text = "State: Opening";
+		break;
+	case SMP2P_EDGE_STATE_OPENED:
+		state_text = "State: Opened";
+		break;
+	default:
+		state_text = "";
+		break;
+	}
+
+	i += scnprintf(buf + i, max - i,
+		"%-14s LPID %d RPID %d",
+		state_text,
+		SMP2P_GET_LOCAL_PID(item_ptr->rem_loc_proc_id),
+		SMP2P_GET_REMOTE_PID(item_ptr->rem_loc_proc_id)
+		);
+
+	return i;
+}
+
+/**
+ * Dump item header line 2.
+ *
+ * @buf:      output buffer
+ * @max:      length of output buffer
+ * @item_ptr: SMEM item pointer
+ * @returns: Number of bytes written to output buffer
+ */
+static int smp2p_item_header2(char *buf, int max, struct smp2p_smem *item_ptr)
+{
+	int i = 0;
+
+	if (!item_ptr) {
+		i += scnprintf(buf + i, max - i, "None");
+		return i;
+	}
+
+	i += scnprintf(buf + i, max - i,
+		"Version: %08x Features: %08x",
+		SMP2P_GET_VERSION(item_ptr->feature_version),
+		SMP2P_GET_FEATURES(item_ptr->feature_version)
+		);
+
+	return i;
+}
+
+/**
+ * Dump item header line 3.
+ *
+ * @buf:      output buffer
+ * @max:      length of output buffer
+ * @item_ptr: SMEM item pointer
+ * @state:    item state
+ * @returns: Number of bytes written to output buffer
+ */
+static int smp2p_item_header3(char *buf, int max, struct smp2p_smem *item_ptr)
+{
+	int i = 0;
+
+	if (!item_ptr) {
+		i += scnprintf(buf + i, max - i, "None");
+		return i;
+	}
+
+	i += scnprintf(buf + i, max - i,
+		"Entries Valid/Max: %d/%d",
+		SMP2P_GET_ENT_VALID(item_ptr->valid_total_ent),
+		SMP2P_GET_ENT_TOTAL(item_ptr->valid_total_ent)
+		);
+
+	return i;
+}
+
+/**
+ * Dump individual input/output item pair.
+ *
+ * @s:   pointer to output file
+ */
+static void smp2p_item(struct seq_file *s, int remote_pid)
+{
+	struct smp2p_smem *out_ptr;
+	struct smp2p_smem *in_ptr;
+	struct smp2p_interrupt_config *int_cfg;
+	char tmp_buff[64];
+	int state;
+	int entry;
+	struct smp2p_entry_v1 *out_entries = NULL;
+	struct smp2p_entry_v1 *in_entries = NULL;
+	int out_valid = 0;
+	int in_valid = 0;
+
+	int_cfg = smp2p_get_interrupt_config();
+	if (!int_cfg)
+		return;
+	if (!int_cfg[remote_pid].is_configured &&
+			remote_pid != SMP2P_REMOTE_MOCK_PROC)
+		return;
+
+	out_ptr = smp2p_get_out_item(remote_pid, &state);
+	in_ptr = smp2p_get_in_item(remote_pid);
+
+	if (!out_ptr && !in_ptr)
+		return;
+
+	/* print item headers */
+	seq_printf(s, "%s%s\n",
+		" ====================================== ",
+		"======================================");
+	scnprintf(tmp_buff, sizeof(tmp_buff),
+		"Apps(%d)->%s(%d)",
+		SMP2P_APPS_PROC, int_cfg[remote_pid].name, remote_pid);
+	seq_printf(s, "| %-37s", tmp_buff);
+
+	scnprintf(tmp_buff, sizeof(tmp_buff),
+		"%s(%d)->Apps(%d)",
+		int_cfg[remote_pid].name, remote_pid, SMP2P_APPS_PROC);
+	seq_printf(s, "| %-37s|\n", tmp_buff);
+	seq_printf(s, "%s%s\n",
+		" ====================================== ",
+		"======================================");
+
+	smp2p_item_header1(tmp_buff, sizeof(tmp_buff), out_ptr, state);
+	seq_printf(s, "| %-37s", tmp_buff);
+	smp2p_item_header1(tmp_buff, sizeof(tmp_buff), in_ptr, -1);
+	seq_printf(s, "| %-37s|\n", tmp_buff);
+
+	smp2p_item_header2(tmp_buff, sizeof(tmp_buff), out_ptr);
+	seq_printf(s, "| %-37s", tmp_buff);
+	smp2p_item_header2(tmp_buff, sizeof(tmp_buff), in_ptr);
+	seq_printf(s, "| %-37s|\n", tmp_buff);
+
+	smp2p_item_header3(tmp_buff, sizeof(tmp_buff), out_ptr);
+	seq_printf(s, "| %-37s", tmp_buff);
+	smp2p_item_header3(tmp_buff, sizeof(tmp_buff), in_ptr);
+	seq_printf(s, "| %-37s|\n", tmp_buff);
+
+	seq_printf(s, " %s%s\n",
+		"-------------------------------------- ",
+		"--------------------------------------");
+	seq_printf(s, "| %-37s",
+		"Entry Name       Value");
+	seq_printf(s, "| %-37s|\n",
+		"Entry Name       Value");
+	seq_printf(s, " %s%s\n",
+		"-------------------------------------- ",
+		"--------------------------------------");
+
+	/* print entries */
+	if (out_ptr) {
+		out_entries = (struct smp2p_entry_v1 *)((void *)out_ptr +
+				sizeof(struct smp2p_smem));
+		out_valid = SMP2P_GET_ENT_VALID(out_ptr->valid_total_ent);
+	}
+
+	if (in_ptr) {
+		in_entries = (struct smp2p_entry_v1 *)((void *)in_ptr +
+				sizeof(struct smp2p_smem));
+		in_valid = SMP2P_GET_ENT_VALID(out_ptr->valid_total_ent);
+	}
+
+	for (entry = 0; out_entries || in_entries; ++entry) {
+		if (out_entries && entry < out_valid) {
+			scnprintf(tmp_buff, sizeof(tmp_buff),
+					"%-16s 0x%08x",
+					out_entries->name,
+					out_entries->entry);
+			++out_entries;
+		} else {
+			out_entries = NULL;
+			scnprintf(tmp_buff, sizeof(tmp_buff), "None");
+		}
+		seq_printf(s, "| %-37s", tmp_buff);
+
+		if (in_entries && entry < in_valid) {
+			scnprintf(tmp_buff, sizeof(tmp_buff),
+					"%-16s 0x%08x",
+					in_entries->name,
+					in_entries->entry);
+			++in_entries;
+		} else {
+			in_entries = NULL;
+			scnprintf(tmp_buff, sizeof(tmp_buff), "None");
+		}
+		seq_printf(s, "| %-37s|\n", tmp_buff);
+	}
+	seq_printf(s, " %s%s\n\n",
+		"-------------------------------------- ",
+		"--------------------------------------");
+}
+
+/**
+ * Dump item state.
+ *
+ * @s:   pointer to output file
+ */
+static void smp2p_items(struct seq_file *s)
+{
+	int pid;
+
+	for (pid = 0; pid < SMP2P_NUM_PROCS; ++pid)
+		smp2p_item(s, pid);
+}
+
+static struct dentry *dent;
+
+static int debugfs_show(struct seq_file *s, void *data)
+{
+	void (*show)(struct seq_file *) = s->private;
+
+	show(s);
+
+	return 0;
+}
+
+static int debug_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, debugfs_show, inode->i_private);
+}
+
+static const struct file_operations debug_ops = {
+	.open = debug_open,
+	.release = single_release,
+	.read = seq_read,
+	.llseek = seq_lseek,
+};
+
+void debug_create(const char *name,
+			 void (*show)(struct seq_file *))
+{
+	struct dentry *file;
+
+	file = debugfs_create_file(name, 0444, dent, show, &debug_ops);
+	if (!file)
+		pr_err("%s: unable to create file '%s'\n", __func__, name);
+}
+
+static int __init smp2p_debugfs_init(void)
+{
+	dent = debugfs_create_dir("smp2p", 0);
+	if (IS_ERR(dent))
+		return PTR_ERR(dent);
+
+	debug_create("int_stats", smp2p_int_stats);
+	debug_create("items", smp2p_items);
+
+	return 0;
+}
+
+late_initcall(smp2p_debugfs_init);
+#endif /* CONFIG_DEBUG_FS */
diff --git a/arch/arm/mach-msm/smp2p_gpio.c b/arch/arm/mach-msm/smp2p_gpio.c
new file mode 100644
index 0000000..2a85e5f
--- /dev/null
+++ b/arch/arm/mach-msm/smp2p_gpio.c
@@ -0,0 +1,757 @@
+/* arch/arm/mach-msm/smp2p_gpio.c
+ *
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/bitmap.h>
+#include <linux/of.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <mach/msm_ipc_logging.h>
+#include "smp2p_private_api.h"
+#include "smp2p_private.h"
+
+/* GPIO device - one per SMP2P entry. */
+struct smp2p_chip_dev {
+	struct list_head entry_list;
+	char name[SMP2P_MAX_ENTRY_NAME];
+	int remote_pid;
+	bool is_inbound;
+	bool is_open;
+	struct notifier_block out_notifier;
+	struct notifier_block in_notifier;
+	struct msm_smp2p_out *out_handle;
+
+	struct gpio_chip gpio;
+	struct irq_domain *irq_domain;
+	int irq_base;
+
+	spinlock_t irq_lock;
+	DECLARE_BITMAP(irq_enabled, SMP2P_BITS_PER_ENTRY);
+	DECLARE_BITMAP(irq_rising_edge, SMP2P_BITS_PER_ENTRY);
+	DECLARE_BITMAP(irq_falling_edge, SMP2P_BITS_PER_ENTRY);
+};
+
+static struct platform_driver smp2p_gpio_driver;
+static struct lock_class_key smp2p_gpio_lock_class;
+static struct irq_chip smp2p_gpio_irq_chip;
+static DEFINE_SPINLOCK(smp2p_entry_lock_lha1);
+static LIST_HEAD(smp2p_entry_list);
+
+/* Used for mapping edge to name for logging. */
+static const char * const edge_names[] = {
+	"-",
+	"0->1",
+	"1->0",
+	"-",
+};
+
+/* Used for mapping edge to value for logging. */
+static const char * const edge_name_rising[] = {
+	"-",
+	"0->1",
+};
+
+/* Used for mapping edge to value for logging. */
+static const char * const edge_name_falling[] = {
+	"-",
+	"1->0",
+};
+
+static int smp2p_gpio_to_irq(struct gpio_chip *cp,
+	unsigned offset);
+
+/**
+ * smp2p_get_value - Retrieves GPIO value.
+ *
+ * @cp:      GPIO chip pointer
+ * @offset:  Pin offset
+ * @returns: >=0: value of GPIO Pin; < 0 for error
+ *
+ * Error codes:
+ *   -ENODEV - chip/entry invalid
+ *   -ENETDOWN - valid entry, but entry not yet created
+ */
+static int smp2p_get_value(struct gpio_chip *cp,
+	unsigned offset)
+{
+	struct smp2p_chip_dev *chip;
+	int ret = 0;
+	uint32_t data;
+
+	if (!cp)
+		return -ENODEV;
+
+	chip = container_of(cp, struct smp2p_chip_dev, gpio);
+	if (!chip->is_open)
+		return -ENETDOWN;
+
+	if (chip->is_inbound)
+		ret = msm_smp2p_in_read(chip->remote_pid, chip->name, &data);
+	else
+		ret = msm_smp2p_out_read(chip->out_handle, &data);
+
+	if (!ret)
+		ret = (data & (1 << offset)) ? 1 : 0;
+
+	return ret;
+}
+
+/**
+ * smp2p_set_value - Sets GPIO value.
+ *
+ * @cp:     GPIO chip pointer
+ * @offset: Pin offset
+ * @value:  New value
+ */
+static void smp2p_set_value(struct gpio_chip *cp, unsigned offset, int value)
+{
+	struct smp2p_chip_dev *chip;
+	uint32_t data_set;
+	uint32_t data_clear;
+	int ret;
+
+	if (!cp)
+		return;
+
+	chip = container_of(cp, struct smp2p_chip_dev, gpio);
+	if (!chip->is_open)
+		return;
+
+	if (chip->is_inbound) {
+		SMP2P_ERR("%s: '%s':%d virq %d invalid operation\n",
+			__func__, chip->name, chip->remote_pid,
+			chip->irq_base + offset);
+		return;
+	}
+
+	if (value) {
+		data_set = 1 << offset;
+		data_clear = 0;
+	} else {
+		data_set = 0;
+		data_clear = 1 << offset;
+	}
+
+	ret = msm_smp2p_out_modify(chip->out_handle,
+			data_set, data_clear);
+
+	if (ret)
+		SMP2P_GPIO("'%s':%d gpio %d set to %d failed (%d)\n",
+			chip->name, chip->remote_pid,
+			chip->gpio.base + offset, value, ret);
+	else
+		SMP2P_GPIO("'%s':%d gpio %d set to %d\n",
+			chip->name, chip->remote_pid,
+			chip->gpio.base + offset, value);
+}
+
+/**
+ * smp2p_direction_input - Sets GPIO direction to input.
+ *
+ * @cp:      GPIO chip pointer
+ * @offset:  Pin offset
+ * @returns: 0 for success; < 0 for failure
+ */
+static int smp2p_direction_input(struct gpio_chip *cp, unsigned offset)
+{
+	struct smp2p_chip_dev *chip;
+
+	if (!cp)
+		return -ENODEV;
+
+	chip = container_of(cp, struct smp2p_chip_dev, gpio);
+	if (!chip->is_inbound)
+		return -EPERM;
+
+	return 0;
+}
+
+/**
+ * smp2p_direction_output - Sets GPIO direction to output.
+ *
+ * @cp:      GPIO chip pointer
+ * @offset:  Pin offset
+ * @value:   Direction
+ * @returns: 0 for success; < 0 for failure
+ */
+static int smp2p_direction_output(struct gpio_chip *cp,
+	unsigned offset, int value)
+{
+	struct smp2p_chip_dev *chip;
+
+	if (!cp)
+		return -ENODEV;
+
+	chip = container_of(cp, struct smp2p_chip_dev, gpio);
+	if (chip->is_inbound)
+		return -EPERM;
+
+	return 0;
+}
+
+/**
+ * smp2p_gpio_to_irq - Convert GPIO pin to virtual IRQ pin.
+ *
+ * @cp:      GPIO chip pointer
+ * @offset:  Pin offset
+ * @returns: >0 for virtual irq value; < 0 for failure
+ */
+static int smp2p_gpio_to_irq(struct gpio_chip *cp, unsigned offset)
+{
+	struct smp2p_chip_dev *chip;
+
+	chip = container_of(cp, struct smp2p_chip_dev, gpio);
+	if (!cp || chip->irq_base <= 0)
+		return -ENODEV;
+
+	return chip->irq_base + offset;
+}
+
+/**
+ * smp2p_gpio_irq_mask_helper - Mask/Unmask interrupt.
+ *
+ * @d:    IRQ data
+ * @mask: true to mask (disable), false to unmask (enable)
+ */
+static void smp2p_gpio_irq_mask_helper(struct irq_data *d, bool mask)
+{
+	struct smp2p_chip_dev *chip;
+	int offset;
+	unsigned long flags;
+
+	chip = (struct smp2p_chip_dev *)irq_get_chip_data(d->irq);
+	if (!chip || chip->irq_base <= 0)
+		return;
+
+	offset = d->irq - chip->irq_base;
+	spin_lock_irqsave(&chip->irq_lock, flags);
+	if (mask)
+		clear_bit(offset, chip->irq_enabled);
+	else
+		set_bit(offset, chip->irq_enabled);
+	spin_unlock_irqrestore(&chip->irq_lock, flags);
+}
+
+/**
+ * smp2p_gpio_irq_mask - Mask interrupt.
+ *
+ * @d: IRQ data
+ */
+static void smp2p_gpio_irq_mask(struct irq_data *d)
+{
+	smp2p_gpio_irq_mask_helper(d, true);
+}
+
+/**
+ * smp2p_gpio_irq_unmask - Unmask interrupt.
+ *
+ * @d: IRQ data
+ */
+static void smp2p_gpio_irq_unmask(struct irq_data *d)
+{
+	smp2p_gpio_irq_mask_helper(d, false);
+}
+
+/**
+ * smp2p_gpio_irq_set_type - Set interrupt edge type.
+ *
+ * @d:      IRQ data
+ * @type:   Edge type for interrupt
+ * @returns 0 for success; < 0 for failure
+ */
+static int smp2p_gpio_irq_set_type(struct irq_data *d, unsigned int type)
+{
+	struct smp2p_chip_dev *chip;
+	int offset;
+	unsigned long flags;
+	int ret = 0;
+
+	chip = (struct smp2p_chip_dev *)irq_get_chip_data(d->irq);
+	if (!chip)
+		return -ENODEV;
+
+	if (chip->irq_base <= 0) {
+		SMP2P_ERR("%s: '%s':%d virqbase %d invalid\n",
+			__func__, chip->name, chip->remote_pid,
+			chip->irq_base);
+		return -ENODEV;
+	}
+
+	offset = d->irq - chip->irq_base;
+
+	spin_lock_irqsave(&chip->irq_lock, flags);
+	clear_bit(offset, chip->irq_rising_edge);
+	clear_bit(offset, chip->irq_falling_edge);
+	switch (type) {
+	case IRQ_TYPE_EDGE_RISING:
+		set_bit(offset, chip->irq_rising_edge);
+		break;
+
+	case IRQ_TYPE_EDGE_FALLING:
+		set_bit(offset, chip->irq_falling_edge);
+		break;
+
+	case IRQ_TYPE_NONE:
+	case IRQ_TYPE_DEFAULT:
+	case IRQ_TYPE_EDGE_BOTH:
+		set_bit(offset, chip->irq_rising_edge);
+		set_bit(offset, chip->irq_falling_edge);
+		break;
+
+	default:
+		SMP2P_ERR("%s: unsupported interrupt type 0x%x\n",
+				__func__, type);
+		ret = -EINVAL;
+		break;
+	}
+	spin_unlock_irqrestore(&chip->irq_lock, flags);
+	return ret;
+}
+
+/**
+ * smp2p_irq_map - Creates or updates binding of virtual IRQ
+ *
+ * @domain_ptr: Interrupt domain pointer
+ * @virq:       Virtual IRQ
+ * @hw:         Hardware IRQ (same as virq for nomap)
+ * @returns:    0 for success
+ */
+static int smp2p_irq_map(struct irq_domain *domain_ptr, unsigned int virq,
+	irq_hw_number_t hw)
+{
+	struct smp2p_chip_dev *chip;
+
+	chip = domain_ptr->host_data;
+	if (!chip) {
+		SMP2P_ERR("%s: invalid domain ptr %p\n", __func__, domain_ptr);
+		return -ENODEV;
+	}
+
+	/* map chip structures to device */
+	irq_set_lockdep_class(virq, &smp2p_gpio_lock_class);
+	irq_set_chip_and_handler(virq, &smp2p_gpio_irq_chip,
+				 handle_level_irq);
+	irq_set_chip_data(virq, chip);
+	set_irq_flags(virq, IRQF_VALID);
+
+	return 0;
+}
+
+static struct irq_chip smp2p_gpio_irq_chip = {
+	.name = "smp2p_gpio",
+	.irq_mask = smp2p_gpio_irq_mask,
+	.irq_unmask = smp2p_gpio_irq_unmask,
+	.irq_set_type = smp2p_gpio_irq_set_type,
+};
+
+/* No-map interrupt Domain */
+static const struct irq_domain_ops smp2p_irq_domain_ops = {
+	.map = smp2p_irq_map,
+};
+
+/**
+ * msm_summary_irq_handler - Handles inbound entry change notification.
+ *
+ * @chip:  GPIO chip pointer
+ * @entry: Change notification data
+ *
+ * Whenever an entry changes, this callback is triggered to determine
+ * which bits changed and if the corresponding interrupts need to be
+ * triggered.
+ */
+static void msm_summary_irq_handler(struct smp2p_chip_dev *chip,
+	struct msm_smp2p_update_notif *entry)
+{
+	int i;
+	uint32_t cur_val;
+	uint32_t prev_val;
+	uint32_t edge;
+	unsigned long flags;
+	bool trigger_interrrupt;
+	bool irq_rising;
+	bool irq_falling;
+
+	cur_val = entry->current_value;
+	prev_val = entry->previous_value;
+
+	if (chip->irq_base <= 0)
+		return;
+
+	SMP2P_GPIO("'%s':%d GPIO Summary IRQ Change %08x->%08x\n",
+			chip->name, chip->remote_pid, prev_val, cur_val);
+
+	for (i = 0; i < SMP2P_BITS_PER_ENTRY; ++i) {
+		spin_lock_irqsave(&chip->irq_lock, flags);
+		trigger_interrrupt = false;
+		edge = (prev_val & 0x1) << 1 | (cur_val & 0x1);
+		irq_rising = test_bit(i, chip->irq_rising_edge);
+		irq_falling = test_bit(i, chip->irq_falling_edge);
+
+		if (test_bit(i, chip->irq_enabled)) {
+			if (edge == 0x1 && irq_rising)
+				/* 0->1 transition */
+				trigger_interrrupt = true;
+			else if (edge == 0x2 && irq_falling)
+				/* 1->0 transition */
+				trigger_interrrupt = true;
+		} else {
+			SMP2P_GPIO(
+				"'%s':%d GPIO bit %d virq %d (%s,%s) - edge %s disabled\n",
+				chip->name, chip->remote_pid, i,
+				chip->irq_base + i,
+				edge_name_rising[irq_rising],
+				edge_name_falling[irq_falling],
+				edge_names[edge]);
+		}
+		spin_unlock_irqrestore(&chip->irq_lock, flags);
+
+		if (trigger_interrrupt) {
+			SMP2P_GPIO(
+				"'%s':%d GPIO bit %d virq %d (%s,%s) - edge %s triggering\n",
+				chip->name, chip->remote_pid, i,
+				chip->irq_base + i,
+				edge_name_rising[irq_rising],
+				edge_name_falling[irq_falling],
+				edge_names[edge]);
+			(void)generic_handle_irq(chip->irq_base + i);
+		}
+
+		cur_val >>= 1;
+		prev_val >>= 1;
+	}
+}
+
+/**
+ * Adds an interrupt domain based upon the DT node.
+ *
+ * @chip: pointer to GPIO chip
+ * @node: pointer to Device Tree node
+ */
+static void smp2p_add_irq_domain(struct smp2p_chip_dev *chip,
+	struct device_node *node)
+{
+	int i;
+
+	/* map GPIO pins to interrupts */
+	chip->irq_domain = irq_domain_add_nomap(node, 0,
+			&smp2p_irq_domain_ops, chip);
+	if (!chip->irq_domain) {
+		SMP2P_ERR("%s: unable to create interrupt domain '%s':%d\n",
+				__func__, chip->name, chip->remote_pid);
+		return;
+	}
+
+	for (i = 0; i < SMP2P_BITS_PER_ENTRY; ++i) {
+		unsigned int virt_irq;
+
+		virt_irq = irq_create_direct_mapping(chip->irq_domain);
+		if (virt_irq == NO_IRQ) {
+			SMP2P_ERR("%s: gpio->virt IRQ mapping failed '%s':%d\n",
+					__func__, chip->name, chip->remote_pid);
+		} else if (!chip->irq_base) {
+			chip->irq_base = virt_irq;
+		}
+	}
+}
+
+/**
+ * Notifier function passed into smp2p API for out bound entries.
+ *
+ * @self:       Pointer to calling notifier block
+ * @event:	    Event
+ * @data:       Event-specific data
+ * @returns:    0
+ */
+static int smp2p_gpio_out_notify(struct notifier_block *self,
+		unsigned long event, void *data)
+{
+	struct smp2p_chip_dev *chip;
+
+	chip = container_of(self, struct smp2p_chip_dev, out_notifier);
+
+	switch (event) {
+	case SMP2P_OPEN:
+		chip->is_open = 1;
+		SMP2P_GPIO("%s: Opened out '%s':%d\n", __func__,
+				chip->name, chip->remote_pid);
+		break;
+	case SMP2P_ENTRY_UPDATE:
+		break;
+	default:
+		SMP2P_ERR("%s: Unknown event\n", __func__);
+		break;
+	}
+	return 0;
+}
+
+/**
+ * Notifier function passed into smp2p API for in bound entries.
+ *
+ * @self:       Pointer to calling notifier block
+ * @event:	    Event
+ * @data:       Event-specific data
+ * @returns:    0
+ */
+static int smp2p_gpio_in_notify(struct notifier_block *self,
+		unsigned long event, void *data)
+{
+	struct smp2p_chip_dev *chip;
+
+	chip = container_of(self, struct smp2p_chip_dev, in_notifier);
+
+	switch (event) {
+	case SMP2P_OPEN:
+		chip->is_open = 1;
+		SMP2P_GPIO("%s: Opened in '%s':%d\n", __func__,
+				chip->name, chip->remote_pid);
+		break;
+	case SMP2P_ENTRY_UPDATE:
+		msm_summary_irq_handler(chip, data);
+		break;
+	default:
+		SMP2P_ERR("%s: Unknown event\n", __func__);
+		break;
+	}
+	return 0;
+}
+
+/**
+ * Device tree probe function.
+ *
+ * @pdev:	 Pointer to device tree data.
+ * @returns: 0 on success; -ENODEV otherwise
+ *
+ * Called for each smp2pgpio entry in the device tree.
+ */
+static int __devinit smp2p_gpio_probe(struct platform_device *pdev)
+{
+	struct device_node *node;
+	char *key;
+	struct smp2p_chip_dev *chip;
+	const char *name_tmp;
+	unsigned long flags;
+	bool is_test_entry = false;
+	int ret;
+
+	chip = kzalloc(sizeof(struct smp2p_chip_dev), GFP_KERNEL);
+	if (!chip) {
+		SMP2P_ERR("%s: out of memory\n", __func__);
+		ret = -ENOMEM;
+		goto fail;
+	}
+	spin_lock_init(&chip->irq_lock);
+
+	/* parse device tree */
+	node = pdev->dev.of_node;
+	key = "qcom,entry-name";
+	ret = of_property_read_string(node, key, &name_tmp);
+	if (ret) {
+		SMP2P_ERR("%s: missing DT key '%s'\n", __func__, key);
+		goto fail;
+	}
+	strlcpy(chip->name, name_tmp, sizeof(chip->name));
+
+	key = "qcom,remote-pid";
+	ret = of_property_read_u32(node, key, &chip->remote_pid);
+	if (ret) {
+		SMP2P_ERR("%s: missing DT key '%s'\n", __func__, key);
+		goto fail;
+	}
+
+	key = "qcom,is-inbound";
+	chip->is_inbound = of_property_read_bool(node, key);
+
+	/* create virtual GPIO controller */
+	chip->gpio.label = chip->name;
+	chip->gpio.dev = &pdev->dev;
+	chip->gpio.owner = THIS_MODULE;
+	chip->gpio.direction_input	= smp2p_direction_input,
+	chip->gpio.get = smp2p_get_value;
+	chip->gpio.direction_output = smp2p_direction_output,
+	chip->gpio.set = smp2p_set_value;
+	chip->gpio.to_irq = smp2p_gpio_to_irq,
+	chip->gpio.base = -1;	/* use dynamic GPIO pin allocation */
+	chip->gpio.ngpio = SMP2P_BITS_PER_ENTRY;
+	ret = gpiochip_add(&chip->gpio);
+	if (ret) {
+		SMP2P_ERR("%s: unable to register GPIO '%s' ret %d\n",
+				__func__, chip->name, ret);
+		goto fail;
+	}
+
+	/*
+	 * Test entries opened by GPIO Test conflict with loopback
+	 * support, so the test entries must be explicitly opened
+	 * in the unit test framework.
+	 */
+	if (strncmp("smp2p", chip->name, SMP2P_MAX_ENTRY_NAME) == 0)
+		is_test_entry = true;
+
+	if (!chip->is_inbound)	{
+		chip->out_notifier.notifier_call = smp2p_gpio_out_notify;
+		if (!is_test_entry) {
+			ret = msm_smp2p_out_open(chip->remote_pid, chip->name,
+					   &chip->out_notifier,
+					   &chip->out_handle);
+			if (ret < 0)
+				goto fail;
+		}
+	} else {
+		chip->in_notifier.notifier_call = smp2p_gpio_in_notify;
+		if (!is_test_entry) {
+			ret = msm_smp2p_in_register(chip->remote_pid,
+					chip->name,
+					&chip->in_notifier);
+			if (ret < 0)
+				goto fail;
+		}
+	}
+
+	spin_lock_irqsave(&smp2p_entry_lock_lha1, flags);
+	list_add(&chip->entry_list, &smp2p_entry_list);
+	spin_unlock_irqrestore(&smp2p_entry_lock_lha1, flags);
+
+	/*
+	 * Create interrupt domain - note that chip can't be removed from the
+	 * interrupt domain, so chip cannot be deleted after this point.
+	 */
+	if (chip->is_inbound)
+		smp2p_add_irq_domain(chip, node);
+	else
+		chip->irq_base = -1;
+
+	SMP2P_GPIO("%s: added %s%s entry '%s':%d gpio %d irq %d",
+			__func__,
+			is_test_entry ? "test " : "",
+			chip->is_inbound ? "in" : "out",
+			chip->name, chip->remote_pid,
+			chip->gpio.base, chip->irq_base);
+
+	return 0;
+
+fail:
+	kfree(chip);
+	return ret;
+}
+
+/**
+ * smp2p_gpio_open_close - Opens or closes entry.
+ *
+ * @entry:   Entry to open or close
+ * @do_open: true = open port; false = close
+ */
+static void smp2p_gpio_open_close(struct smp2p_chip_dev *entry,
+	bool do_open)
+{
+	int ret;
+
+	if (do_open) {
+		/* open entry */
+		if (entry->is_inbound)
+			ret = msm_smp2p_in_register(entry->remote_pid,
+					entry->name, &entry->in_notifier);
+		else
+			ret = msm_smp2p_out_open(entry->remote_pid,
+					entry->name, &entry->out_notifier,
+					&entry->out_handle);
+		SMP2P_GPIO("%s: opened %s '%s':%d ret %d\n",
+				__func__,
+				entry->is_inbound ? "in" : "out",
+				entry->name, entry->remote_pid,
+				ret);
+	} else {
+		/* close entry */
+		if (entry->is_inbound)
+			ret = msm_smp2p_in_unregister(entry->remote_pid,
+					entry->name, &entry->in_notifier);
+		else
+			ret = msm_smp2p_out_close(&entry->out_handle);
+		entry->is_open = false;
+		SMP2P_GPIO("%s: closed %s '%s':%d ret %d\n",
+				__func__,
+				entry->is_inbound ? "in" : "out",
+				entry->name, entry->remote_pid, ret);
+	}
+}
+
+/**
+ * smp2p_gpio_open_test_entry - Opens or closes test entries for unit testing.
+ *
+ * @name:       Name of the entry
+ * @remote_pid: Remote processor ID
+ * @do_open:    true = open port; false = close
+ */
+void smp2p_gpio_open_test_entry(const char *name, int remote_pid, bool do_open)
+{
+	struct smp2p_chip_dev *entry;
+	struct smp2p_chip_dev *start_entry;
+	unsigned long flags;
+
+	spin_lock_irqsave(&smp2p_entry_lock_lha1, flags);
+	if (list_empty(&smp2p_entry_list)) {
+		spin_unlock_irqrestore(&smp2p_entry_lock_lha1, flags);
+		return;
+	}
+	start_entry = list_first_entry(&smp2p_entry_list,
+					struct smp2p_chip_dev,
+					entry_list);
+	entry = start_entry;
+	do {
+		if (!strncmp(entry->name, name, SMP2P_MAX_ENTRY_NAME)
+				&& entry->remote_pid == remote_pid) {
+			/* found entry to change */
+			spin_unlock_irqrestore(&smp2p_entry_lock_lha1, flags);
+			smp2p_gpio_open_close(entry, do_open);
+			spin_lock_irqsave(&smp2p_entry_lock_lha1, flags);
+		}
+		list_rotate_left(&smp2p_entry_list);
+		entry = list_first_entry(&smp2p_entry_list,
+						struct smp2p_chip_dev,
+						entry_list);
+	} while (entry != start_entry);
+	spin_unlock_irqrestore(&smp2p_entry_lock_lha1, flags);
+}
+
+static struct of_device_id msm_smp2p_match_table[] __devinitdata = {
+	{.compatible = "qcom,smp2pgpio", },
+	{},
+};
+
+static struct platform_driver smp2p_gpio_driver = {
+	.probe = smp2p_gpio_probe,
+	.driver = {
+		.name = "smp2pgpio",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_smp2p_match_table,
+	},
+};
+
+static int __devinit smp2p_init(void)
+{
+	INIT_LIST_HEAD(&smp2p_entry_list);
+	return platform_driver_register(&smp2p_gpio_driver);
+}
+module_init(smp2p_init);
+
+static void __exit smp2p_exit(void)
+{
+	platform_driver_unregister(&smp2p_gpio_driver);
+}
+module_exit(smp2p_exit);
+
+MODULE_DESCRIPTION("SMP2P GPIO");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/smp2p_gpio_test.c b/arch/arm/mach-msm/smp2p_gpio_test.c
new file mode 100644
index 0000000..70de20a
--- /dev/null
+++ b/arch/arm/mach-msm/smp2p_gpio_test.c
@@ -0,0 +1,624 @@
+/* arch/arm/mach-msm/smp2p_gpio_test.c
+ *
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of_gpio.h>
+#include <linux/of_irq.h>
+#include <linux/gpio.h>
+#include <linux/debugfs.h>
+#include <linux/completion.h>
+#include <linux/irq.h>
+#include <linux/bitmap.h>
+#include "smp2p_private.h"
+#include "smp2p_test_common.h"
+
+/* Interrupt callback data */
+struct gpio_info {
+	int gpio_base_id;
+	int irq_base_id;
+
+	bool initialized;
+	struct completion cb_completion;
+	int cb_count;
+	DECLARE_BITMAP(triggered_irqs, SMP2P_BITS_PER_ENTRY);
+};
+
+/* GPIO Inbound/Outbound callback info */
+struct gpio_inout {
+	struct gpio_info in;
+	struct gpio_info out;
+};
+
+static struct gpio_inout gpio_info[SMP2P_NUM_PROCS];
+
+/**
+ * Init/reset the callback data.
+ *
+ * @info: Pointer to callback data
+ */
+static void cb_data_reset(struct gpio_info *info)
+{
+	int n;
+
+	if (!info)
+		return;
+
+	if (!info->initialized) {
+		init_completion(&info->cb_completion);
+		info->initialized = true;
+	}
+	info->cb_count = 0;
+
+	for (n = 0; n < SMP2P_BITS_PER_ENTRY; ++n)
+		clear_bit(n,  info->triggered_irqs);
+
+	INIT_COMPLETION(info->cb_completion);
+}
+
+static int __devinit smp2p_gpio_test_probe(struct platform_device *pdev)
+{
+	int id;
+	int cnt;
+	struct device_node *node = pdev->dev.of_node;
+	struct gpio_info *gpio_info_ptr = NULL;
+
+	/*
+	 * NOTE:  This does a string-lookup of the GPIO pin name and doesn't
+	 * actually directly link to the SMP2P GPIO driver since all
+	 * GPIO/Interrupt access must be through standard
+	 * Linux GPIO / Interrupt APIs.
+	 */
+	if (strcmp("qcom,smp2pgpio_test_smp2p_1_in", node->name) == 0) {
+		gpio_info_ptr = &gpio_info[SMP2P_MODEM_PROC].in;
+	} else if (strcmp("qcom,smp2pgpio_test_smp2p_1_out", node->name) == 0) {
+		gpio_info_ptr = &gpio_info[SMP2P_MODEM_PROC].out;
+	} else if (strcmp("qcom,smp2pgpio_test_smp2p_2_in", node->name) == 0) {
+		gpio_info_ptr = &gpio_info[SMP2P_AUDIO_PROC].in;
+	} else if (strcmp("qcom,smp2pgpio_test_smp2p_2_out", node->name) == 0) {
+		gpio_info_ptr = &gpio_info[SMP2P_AUDIO_PROC].out;
+	} else if (strcmp("qcom,smp2pgpio_test_smp2p_4_in", node->name) == 0) {
+		gpio_info_ptr = &gpio_info[SMP2P_WIRELESS_PROC].in;
+	} else if (strcmp("qcom,smp2pgpio_test_smp2p_4_out", node->name) == 0) {
+		gpio_info_ptr = &gpio_info[SMP2P_WIRELESS_PROC].out;
+	} else if (strcmp("qcom,smp2pgpio_test_smp2p_7_in", node->name) == 0) {
+		gpio_info_ptr = &gpio_info[SMP2P_REMOTE_MOCK_PROC].in;
+	} else if (strcmp("qcom,smp2pgpio_test_smp2p_7_out", node->name) == 0) {
+		gpio_info_ptr = &gpio_info[SMP2P_REMOTE_MOCK_PROC].out;
+	} else {
+		pr_err("%s: unable to match device type '%s'\n",
+				__func__, node->name);
+		return -ENODEV;
+	}
+
+	/* retrieve the GPIO and interrupt ID's */
+	cnt = of_gpio_count(node);
+	if (cnt && gpio_info_ptr) {
+		/*
+		 * Instead of looping through all 32-bits, we can just get the
+		 * first pin to get the base IDs.  This saves on the verbosity
+		 * of the device tree nodes as well.
+		 */
+		id = of_get_gpio(node, 0);
+		gpio_info_ptr->gpio_base_id = id;
+		gpio_info_ptr->irq_base_id = gpio_to_irq(id);
+	}
+	return 0;
+}
+
+/*
+ * NOTE:  Instead of match table and device driver, you may be able to just
+ * call of_find_compatible_node() in your init function.
+ */
+static struct of_device_id msm_smp2p_match_table[] __devinitdata = {
+	/* modem */
+	{.compatible = "qcom,smp2pgpio_test_smp2p_1_out", },
+	{.compatible = "qcom,smp2pgpio_test_smp2p_1_in", },
+
+	/* audio (adsp) */
+	{.compatible = "qcom,smp2pgpio_test_smp2p_2_out", },
+	{.compatible = "qcom,smp2pgpio_test_smp2p_2_in", },
+
+	/* wcnss */
+	{.compatible = "qcom,smp2pgpio_test_smp2p_4_out", },
+	{.compatible = "qcom,smp2pgpio_test_smp2p_4_in", },
+
+	/* mock loopback */
+	{.compatible = "qcom,smp2pgpio_test_smp2p_7_out", },
+	{.compatible = "qcom,smp2pgpio_test_smp2p_7_in", },
+	{},
+};
+
+static struct platform_driver smp2p_gpio_driver = {
+	.probe = smp2p_gpio_test_probe,
+	.driver = {
+		.name = "smp2pgpio_test",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_smp2p_match_table,
+	},
+};
+
+/**
+ * smp2p_ut_local_gpio_out - Verify outbound functionality.
+ *
+ * @s:   pointer to output file
+ */
+static void smp2p_ut_local_gpio_out(struct seq_file *s)
+{
+	int failed = 0;
+	struct gpio_info *cb_info = &gpio_info[SMP2P_REMOTE_MOCK_PROC].out;
+	int ret;
+	int id;
+	struct msm_smp2p_remote_mock *mock;
+
+	seq_printf(s, "Running %s\n", __func__);
+	do {
+		/* initialize mock edge */
+		ret = smp2p_reset_mock_edge();
+		UT_ASSERT_INT(ret, ==, 0);
+
+		mock = msm_smp2p_get_remote_mock();
+		UT_ASSERT_PTR(mock, !=, NULL);
+
+		mock->rx_interrupt_count = 0;
+		memset(&mock->remote_item, 0,
+			sizeof(struct smp2p_smem_item));
+		smp2p_init_header((struct smp2p_smem *)&mock->remote_item,
+			SMP2P_REMOTE_MOCK_PROC, SMP2P_APPS_PROC,
+			0, 1);
+		strlcpy(mock->remote_item.entries[0].name, "smp2p",
+			SMP2P_MAX_ENTRY_NAME);
+		SMP2P_SET_ENT_VALID(
+			mock->remote_item.header.valid_total_ent, 1);
+		msm_smp2p_set_remote_mock_exists(true);
+		mock->tx_interrupt();
+
+		/* open GPIO entry */
+		smp2p_gpio_open_test_entry("smp2p",
+				SMP2P_REMOTE_MOCK_PROC, true);
+
+		/* verify set/get functions */
+		UT_ASSERT_INT(0, <, cb_info->gpio_base_id);
+		for (id = 0; id < SMP2P_BITS_PER_ENTRY && !failed; ++id) {
+			int pin = cb_info->gpio_base_id + id;
+
+			mock->rx_interrupt_count = 0;
+			gpio_set_value(pin, 1);
+			UT_ASSERT_INT(1, ==, mock->rx_interrupt_count);
+			UT_ASSERT_INT(1, ==, gpio_get_value(pin));
+
+			gpio_set_value(pin, 0);
+			UT_ASSERT_INT(2, ==, mock->rx_interrupt_count);
+			UT_ASSERT_INT(0, ==, gpio_get_value(pin));
+		}
+		if (failed)
+			break;
+
+		seq_printf(s, "\tOK\n");
+	} while (0);
+
+	if (failed) {
+		pr_err("%s: Failed\n", __func__);
+		seq_printf(s, "\tFailed\n");
+	}
+
+	smp2p_gpio_open_test_entry("smp2p",
+			SMP2P_REMOTE_MOCK_PROC, false);
+}
+
+/**
+ * smp2p_gpio_irq - Interrupt handler for inbound entries.
+ *
+ * @irq:         Virtual IRQ being triggered
+ * @data:        Cookie data (struct gpio_info * in this case)
+ * @returns:     Number of bytes written
+ */
+static irqreturn_t smp2p_gpio_irq(int irq, void *data)
+{
+	struct gpio_info *gpio_ptr = (struct gpio_info *)data;
+	int offset;
+
+	if (!gpio_ptr) {
+		pr_err("%s: gpio_ptr is NULL for irq %d\n", __func__, irq);
+		return IRQ_HANDLED;
+	}
+
+	offset = irq - gpio_ptr->irq_base_id;
+	if (offset >= 0 &&  offset < SMP2P_BITS_PER_ENTRY)
+		set_bit(offset, gpio_ptr->triggered_irqs);
+	else
+		pr_err("%s: invalid irq offset base %d; irq %d\n",
+			__func__, gpio_ptr->irq_base_id, irq);
+
+	++gpio_ptr->cb_count;
+	complete(&gpio_ptr->cb_completion);
+	return IRQ_HANDLED;
+}
+
+/**
+ * smp2p_ut_local_gpio_in - Verify inbound functionality.
+ *
+ * @s:   pointer to output file
+ */
+static void smp2p_ut_local_gpio_in(struct seq_file *s)
+{
+	int failed = 0;
+	struct gpio_info *cb_info = &gpio_info[SMP2P_REMOTE_MOCK_PROC].in;
+	int id;
+	int ret;
+	int virq;
+	struct msm_smp2p_remote_mock *mock;
+
+	seq_printf(s, "Running %s\n", __func__);
+
+	cb_data_reset(cb_info);
+	do {
+		/* initialize mock edge */
+		ret = smp2p_reset_mock_edge();
+		UT_ASSERT_INT(ret, ==, 0);
+
+		mock = msm_smp2p_get_remote_mock();
+		UT_ASSERT_PTR(mock, !=, NULL);
+
+		mock->rx_interrupt_count = 0;
+		memset(&mock->remote_item, 0,
+			sizeof(struct smp2p_smem_item));
+		smp2p_init_header((struct smp2p_smem *)&mock->remote_item,
+			SMP2P_REMOTE_MOCK_PROC, SMP2P_APPS_PROC,
+			0, 1);
+		strlcpy(mock->remote_item.entries[0].name, "smp2p",
+			SMP2P_MAX_ENTRY_NAME);
+		SMP2P_SET_ENT_VALID(
+			mock->remote_item.header.valid_total_ent, 1);
+		msm_smp2p_set_remote_mock_exists(true);
+		mock->tx_interrupt();
+
+		smp2p_gpio_open_test_entry("smp2p",
+				SMP2P_REMOTE_MOCK_PROC, true);
+
+		/* verify set/get functions locally */
+		UT_ASSERT_INT(0, <, cb_info->gpio_base_id);
+		for (id = 0; id < SMP2P_BITS_PER_ENTRY && !failed; ++id) {
+			int pin;
+			int current_value;
+
+			/* verify pin value cannot be set */
+			pin = cb_info->gpio_base_id + id;
+			current_value = gpio_get_value(pin);
+
+			gpio_set_value(pin, 0);
+			UT_ASSERT_INT(current_value, ==, gpio_get_value(pin));
+			gpio_set_value(pin, 1);
+			UT_ASSERT_INT(current_value, ==, gpio_get_value(pin));
+
+			/* verify no interrupts */
+			UT_ASSERT_INT(0, ==, cb_info->cb_count);
+		}
+		if (failed)
+			break;
+
+		/* register for interrupts */
+		UT_ASSERT_INT(0, <, cb_info->irq_base_id);
+		for (id = 0; id < SMP2P_BITS_PER_ENTRY && !failed; ++id) {
+			virq = cb_info->irq_base_id + id;
+			UT_ASSERT_INT(0, >, (unsigned int)irq_to_desc(virq));
+			ret = request_irq(virq,
+					smp2p_gpio_irq,	IRQF_TRIGGER_RISING,
+					"smp2p_test", cb_info);
+			UT_ASSERT_INT(0, ==, ret);
+		}
+		if (failed)
+			break;
+
+		/* verify both rising and falling edge interrupts */
+		for (id = 0; id < SMP2P_BITS_PER_ENTRY && !failed; ++id) {
+			virq = cb_info->irq_base_id + id;
+			irq_set_irq_type(virq, IRQ_TYPE_EDGE_BOTH);
+			cb_data_reset(cb_info);
+
+			/* verify rising-edge interrupt */
+			mock->remote_item.entries[0].entry = 1 << id;
+			mock->tx_interrupt();
+			UT_ASSERT_INT(cb_info->cb_count, ==, 1);
+			UT_ASSERT_INT(0, <,
+				test_bit(id, cb_info->triggered_irqs));
+			test_bit(id, cb_info->triggered_irqs);
+
+			/* verify falling-edge interrupt */
+			mock->remote_item.entries[0].entry = 0;
+			mock->tx_interrupt();
+			UT_ASSERT_INT(cb_info->cb_count, ==, 2);
+			UT_ASSERT_INT(0, <,
+					test_bit(id, cb_info->triggered_irqs));
+		}
+		if (failed)
+			break;
+
+		/* verify rising-edge interrupts */
+		for (id = 0; id < SMP2P_BITS_PER_ENTRY && !failed; ++id) {
+			virq = cb_info->irq_base_id + id;
+			irq_set_irq_type(virq, IRQ_TYPE_EDGE_RISING);
+			cb_data_reset(cb_info);
+
+			/* verify only rising-edge interrupt is triggered */
+			mock->remote_item.entries[0].entry = 1 << id;
+			mock->tx_interrupt();
+			UT_ASSERT_INT(cb_info->cb_count, ==, 1);
+			UT_ASSERT_INT(0, <,
+				test_bit(id, cb_info->triggered_irqs));
+			test_bit(id, cb_info->triggered_irqs);
+
+			mock->remote_item.entries[0].entry = 0;
+			mock->tx_interrupt();
+			UT_ASSERT_INT(cb_info->cb_count, ==, 1);
+			UT_ASSERT_INT(0, <,
+				test_bit(id, cb_info->triggered_irqs));
+		}
+		if (failed)
+			break;
+
+		/* verify falling-edge interrupts */
+		for (id = 0; id < SMP2P_BITS_PER_ENTRY && !failed; ++id) {
+			virq = cb_info->irq_base_id + id;
+			irq_set_irq_type(virq, IRQ_TYPE_EDGE_FALLING);
+			cb_data_reset(cb_info);
+
+			/* verify only rising-edge interrupt is triggered */
+			mock->remote_item.entries[0].entry = 1 << id;
+			mock->tx_interrupt();
+			UT_ASSERT_INT(cb_info->cb_count, ==, 0);
+			UT_ASSERT_INT(0, ==,
+				test_bit(id, cb_info->triggered_irqs));
+
+			mock->remote_item.entries[0].entry = 0;
+			mock->tx_interrupt();
+			UT_ASSERT_INT(cb_info->cb_count, ==, 1);
+			UT_ASSERT_INT(0, <,
+				test_bit(id, cb_info->triggered_irqs));
+		}
+		if (failed)
+			break;
+
+		seq_printf(s, "\tOK\n");
+	} while (0);
+
+	if (failed) {
+		pr_err("%s: Failed\n", __func__);
+		seq_printf(s, "\tFailed\n");
+	}
+
+	/* unregister for interrupts */
+	if (cb_info->irq_base_id) {
+		for (id = 0; id < SMP2P_BITS_PER_ENTRY; ++id)
+			free_irq(cb_info->irq_base_id + id, cb_info);
+	}
+
+	smp2p_gpio_open_test_entry("smp2p",
+			SMP2P_REMOTE_MOCK_PROC, false);
+}
+
+/**
+ * smp2p_gpio_write_bits - writes value to each GPIO pin specified in mask.
+ *
+ * @gpio: gpio test structure
+ * @mask: 1 = write gpio_value to this GPIO pin
+ * @gpio_value: value to write to GPIO pin
+ */
+static void smp2p_gpio_write_bits(struct gpio_info *gpio, uint32_t mask,
+	int gpio_value)
+{
+	int n;
+
+	for (n = 0; n < SMP2P_BITS_PER_ENTRY; ++n) {
+		if (mask & 0x1)
+			gpio_set_value(gpio->gpio_base_id + n, gpio_value);
+		mask >>= 1;
+	}
+}
+
+static void smp2p_gpio_set_bits(struct gpio_info *gpio, uint32_t mask)
+{
+	smp2p_gpio_write_bits(gpio, mask, 1);
+}
+
+static void smp2p_gpio_clr_bits(struct gpio_info *gpio, uint32_t mask)
+{
+	smp2p_gpio_write_bits(gpio, mask, 0);
+}
+
+/**
+ * smp2p_gpio_get_value - reads entire 32-bits of GPIO
+ *
+ * @gpio: gpio structure
+ * @returns: 32 bit value of GPIO pins
+ */
+static uint32_t smp2p_gpio_get_value(struct gpio_info *gpio)
+{
+	int n;
+	uint32_t value = 0;
+
+	for (n = 0; n < SMP2P_BITS_PER_ENTRY; ++n) {
+		if (gpio_get_value(gpio->gpio_base_id + n))
+			value |= 1 << n;
+	}
+	return value;
+}
+
+/**
+ * smp2p_ut_remote_inout_core - Verify inbound/outbound functionality.
+ *
+ * @s:   pointer to output file
+ * @remote_pid:  Remote processor to test
+ * @name:        Name of the test for reporting
+ *
+ * This test verifies inbound/outbound functionality for the remote processor.
+ */
+static void smp2p_ut_remote_inout_core(struct seq_file *s, int remote_pid,
+		const char *name)
+{
+	int failed = 0;
+	uint32_t request;
+	uint32_t response;
+	struct gpio_info *cb_in;
+	struct gpio_info *cb_out;
+	int id;
+	int ret;
+
+	seq_printf(s, "Running %s for '%s' remote pid %d\n",
+		   __func__, smp2p_pid_to_name(remote_pid), remote_pid);
+
+	cb_in = &gpio_info[remote_pid].in;
+	cb_out = &gpio_info[remote_pid].out;
+	cb_data_reset(cb_in);
+	cb_data_reset(cb_out);
+	do {
+		/* open test entries */
+		msm_smp2p_deinit_rmt_lpb_proc(remote_pid);
+		smp2p_gpio_open_test_entry("smp2p", remote_pid, true);
+
+		/* register for interrupts */
+		UT_ASSERT_INT(0, <, cb_in->gpio_base_id);
+		UT_ASSERT_INT(0, <, cb_in->irq_base_id);
+		for (id = 0; id < SMP2P_BITS_PER_ENTRY && !failed; ++id) {
+			int virq = cb_in->irq_base_id + id;
+			UT_ASSERT_INT(0, >, (unsigned int)irq_to_desc(virq));
+			ret = request_irq(virq,
+				smp2p_gpio_irq,
+				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+				"smp2p_test", cb_in);
+			UT_ASSERT_INT(0, ==, ret);
+		}
+		if (failed)
+			break;
+
+		/* write echo of data value 0 */
+		UT_ASSERT_INT(0, <, cb_out->gpio_base_id);
+		request = 0x0;
+		SMP2P_SET_RMT_CMD_TYPE(request, 1);
+		SMP2P_SET_RMT_CMD(request, SMP2P_LB_CMD_ECHO);
+		SMP2P_SET_RMT_DATA(request, 0x0);
+
+		smp2p_gpio_set_bits(cb_out, SMP2P_RMT_IGNORE_MASK);
+		smp2p_gpio_clr_bits(cb_out, ~SMP2P_RMT_IGNORE_MASK);
+		smp2p_gpio_set_bits(cb_out, request);
+
+		UT_ASSERT_INT(cb_in->cb_count, ==, 0);
+		smp2p_gpio_clr_bits(cb_out, SMP2P_RMT_IGNORE_MASK);
+
+		/* verify response */
+		do {
+			/* wait for up to 32 changes */
+			if (wait_for_completion_timeout(
+					&cb_in->cb_completion, HZ / 2) == 0)
+				break;
+			INIT_COMPLETION(cb_in->cb_completion);
+		} while (cb_in->cb_count < 32);
+		UT_ASSERT_INT(cb_in->cb_count, >, 0);
+		response = smp2p_gpio_get_value(cb_in);
+		SMP2P_SET_RMT_CMD_TYPE(request, 0);
+		UT_ASSERT_HEX(request, ==, response);
+
+		/* write echo of data value of all 1's */
+		request = 0x0;
+		SMP2P_SET_RMT_CMD_TYPE(request, 1);
+		SMP2P_SET_RMT_CMD(request, SMP2P_LB_CMD_ECHO);
+		SMP2P_SET_RMT_DATA(request, ~0);
+
+		smp2p_gpio_set_bits(cb_out, SMP2P_RMT_IGNORE_MASK);
+		cb_data_reset(cb_in);
+		smp2p_gpio_clr_bits(cb_out, ~SMP2P_RMT_IGNORE_MASK);
+		smp2p_gpio_set_bits(cb_out, request);
+
+		UT_ASSERT_INT(cb_in->cb_count, ==, 0);
+		smp2p_gpio_clr_bits(cb_out, SMP2P_RMT_IGNORE_MASK);
+
+		/* verify response including 24 interrupts */
+		do {
+			UT_ASSERT_INT(
+				(int)wait_for_completion_timeout(
+					&cb_in->cb_completion, HZ / 2),
+			   >, 0);
+			INIT_COMPLETION(cb_in->cb_completion);
+		} while (cb_in->cb_count < 24);
+		response = smp2p_gpio_get_value(cb_in);
+		SMP2P_SET_RMT_CMD_TYPE(request, 0);
+		UT_ASSERT_HEX(request, ==, response);
+		UT_ASSERT_INT(24, ==, cb_in->cb_count);
+
+		seq_printf(s, "\tOK\n");
+	} while (0);
+
+	if (failed) {
+		pr_err("%s: Failed\n", name);
+		seq_printf(s, "\tFailed\n");
+	}
+
+	/* unregister for interrupts */
+	if (cb_in->irq_base_id) {
+		for (id = 0; id < SMP2P_BITS_PER_ENTRY; ++id)
+			free_irq(cb_in->irq_base_id + id, cb_in);
+	}
+
+	smp2p_gpio_open_test_entry("smp2p",	remote_pid, false);
+	msm_smp2p_init_rmt_lpb_proc(remote_pid);
+}
+
+/**
+ * smp2p_ut_remote_inout - Verify inbound/outbound functionality for all.
+ *
+ * @s:   pointer to output file
+ *
+ * This test verifies inbound and outbound functionality for all
+ * configured remote processor.
+ */
+static void smp2p_ut_remote_inout(struct seq_file *s)
+{
+	struct smp2p_interrupt_config *int_cfg;
+	int pid;
+
+	int_cfg = smp2p_get_interrupt_config();
+	if (!int_cfg) {
+		seq_printf(s, "Remote processor config unavailable\n");
+		return;
+	}
+
+	for (pid = 0; pid < SMP2P_NUM_PROCS; ++pid) {
+		if (!int_cfg[pid].is_configured)
+			continue;
+
+		smp2p_ut_remote_inout_core(s, pid, __func__);
+	}
+}
+
+static int __init smp2p_debugfs_init(void)
+{
+	/* register GPIO pins */
+	(void)platform_driver_register(&smp2p_gpio_driver);
+
+	/*
+	 * 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.
+	 */
+	smp2p_debug_create("ut_local_gpio_out", smp2p_ut_local_gpio_out);
+	smp2p_debug_create("ut_local_gpio_in", smp2p_ut_local_gpio_in);
+	smp2p_debug_create("ut_remote_gpio_inout", smp2p_ut_remote_inout);
+	return 0;
+}
+late_initcall(smp2p_debugfs_init);
diff --git a/arch/arm/mach-msm/smp2p_loopback.c b/arch/arm/mach-msm/smp2p_loopback.c
new file mode 100644
index 0000000..d95c93f
--- /dev/null
+++ b/arch/arm/mach-msm/smp2p_loopback.c
@@ -0,0 +1,440 @@
+/* arch/arm/mach-msm/smp2p_loopback.c
+ *
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/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/module.h>
+#include <linux/remote_spinlock.h>
+#include "smd_private.h"
+#include "smp2p_private.h"
+
+/**
+ * struct smp2p_loopback_ctx - Representation of remote loopback object.
+ *
+ * @proc_id: Processor id of the processor that sends the loopback commands.
+ * @out: Handle to the  smem entry structure for providing the response.
+ * @out_nb: Notifies the opening of local entry.
+ * @out_is_active: Outbound entry events should be processed.
+ * @in_nb: Notifies changes in the remote entry.
+ * @in_is_active: Inbound entry events should be processed.
+ * @rmt_lpb_work: Work item that handles the incoming loopback commands.
+ * @rmt_cmd: Structure that holds the current and previous value of the entry.
+ */
+struct smp2p_loopback_ctx {
+	int proc_id;
+	struct msm_smp2p_out *out;
+	struct notifier_block out_nb;
+	bool out_is_active;
+	struct notifier_block in_nb;
+	bool in_is_active;
+	struct work_struct  rmt_lpb_work;
+	struct msm_smp2p_update_notif rmt_cmd;
+};
+
+static struct smp2p_loopback_ctx  remote_loopback[SMP2P_NUM_PROCS];
+static struct msm_smp2p_remote_mock remote_mock;
+
+/**
+ * remote_spinlock_test - Handles remote spinlock test.
+ *
+ * @ctx: Loopback context
+ */
+static void remote_spinlock_test(struct smp2p_loopback_ctx *ctx)
+{
+	uint32_t test_request;
+	uint32_t test_response;
+	unsigned long flags;
+	int n;
+	unsigned lock_count = 0;
+	remote_spinlock_t *smem_spinlock;
+
+	test_request = 0x0;
+	SMP2P_SET_RMT_CMD_TYPE_REQ(test_request);
+	smem_spinlock = smem_get_remote_spinlock();
+	if (!smem_spinlock) {
+		pr_err("%s: unable to get remote spinlock\n", __func__);
+		return;
+	}
+
+	for (;;) {
+		remote_spin_lock_irqsave(smem_spinlock, flags);
+		++lock_count;
+		SMP2P_SET_RMT_CMD(test_request, SMP2P_LB_CMD_RSPIN_LOCKED);
+		(void)msm_smp2p_out_write(ctx->out, test_request);
+
+		for (n = 0; n < 10000; ++n) {
+			(void)msm_smp2p_in_read(ctx->proc_id,
+					"smp2p", &test_response);
+			test_response = SMP2P_GET_RMT_CMD(test_response);
+
+			if (test_response == SMP2P_LB_CMD_RSPIN_END)
+				break;
+
+			if (test_response != SMP2P_LB_CMD_RSPIN_UNLOCKED)
+				SMP2P_ERR("%s: invalid spinlock command %x\n",
+					__func__, test_response);
+		}
+
+		if (test_response == SMP2P_LB_CMD_RSPIN_END) {
+			SMP2P_SET_RMT_CMD_TYPE_RESP(test_request);
+			SMP2P_SET_RMT_CMD(test_request,
+					SMP2P_LB_CMD_RSPIN_END);
+			SMP2P_SET_RMT_DATA(test_request, lock_count);
+			(void)msm_smp2p_out_write(ctx->out, test_request);
+			break;
+		}
+
+		SMP2P_SET_RMT_CMD(test_request, SMP2P_LB_CMD_RSPIN_UNLOCKED);
+		(void)msm_smp2p_out_write(ctx->out, test_request);
+		remote_spin_unlock_irqrestore(smem_spinlock, flags);
+	}
+	remote_spin_unlock_irqrestore(smem_spinlock, flags);
+}
+
+/**
+ * smp2p_rmt_lpb_worker - Handles incoming remote loopback commands.
+ *
+ * @work: Work Item scheduled to handle the incoming commands.
+ */
+static void smp2p_rmt_lpb_worker(struct work_struct *work)
+{
+	struct smp2p_loopback_ctx *ctx;
+	int lpb_cmd;
+	int lpb_cmd_type;
+	int lpb_data;
+
+	ctx = container_of(work, struct smp2p_loopback_ctx, rmt_lpb_work);
+
+	if (!ctx->in_is_active || !ctx->out_is_active)
+		return;
+
+	if (ctx->rmt_cmd.previous_value == ctx->rmt_cmd.current_value)
+		return;
+
+	lpb_cmd_type =  SMP2P_GET_RMT_CMD_TYPE(ctx->rmt_cmd.current_value);
+	lpb_cmd = SMP2P_GET_RMT_CMD(ctx->rmt_cmd.current_value);
+	lpb_data = SMP2P_GET_RMT_DATA(ctx->rmt_cmd.current_value);
+
+	if (lpb_cmd & SMP2P_RLPB_IGNORE)
+		return;
+
+	switch (lpb_cmd) {
+	case SMP2P_LB_CMD_NOOP:
+	    /* Do nothing */
+	    break;
+
+	case SMP2P_LB_CMD_ECHO:
+		SMP2P_SET_RMT_CMD_TYPE(ctx->rmt_cmd.current_value, 0);
+		SMP2P_SET_RMT_DATA(ctx->rmt_cmd.current_value,
+							lpb_data);
+		(void)msm_smp2p_out_write(ctx->out,
+					ctx->rmt_cmd.current_value);
+	    break;
+
+	case SMP2P_LB_CMD_CLEARALL:
+		ctx->rmt_cmd.current_value = 0;
+		(void)msm_smp2p_out_write(ctx->out,
+					ctx->rmt_cmd.current_value);
+	    break;
+
+	case SMP2P_LB_CMD_PINGPONG:
+		SMP2P_SET_RMT_CMD_TYPE(ctx->rmt_cmd.current_value, 0);
+		if (lpb_data) {
+			lpb_data--;
+			SMP2P_SET_RMT_DATA(ctx->rmt_cmd.current_value,
+					lpb_data);
+			(void)msm_smp2p_out_write(ctx->out,
+					ctx->rmt_cmd.current_value);
+		}
+	    break;
+
+	case SMP2P_LB_CMD_RSPIN_START:
+		remote_spinlock_test(ctx);
+		break;
+
+	case SMP2P_LB_CMD_RSPIN_LOCKED:
+	case SMP2P_LB_CMD_RSPIN_UNLOCKED:
+	case SMP2P_LB_CMD_RSPIN_END:
+		/* not used for remote spinlock test */
+		break;
+
+	default:
+		SMP2P_DBG("%s: Unknown loopback command %x\n",
+				__func__, lpb_cmd);
+		break;
+	}
+}
+
+/**
+ * smp2p_rmt_in_edge_notify -  Schedules a work item to handle the commands.
+ *
+ * @nb: Notifier block, this is called when the value in remote entry changes.
+ * @event: Takes value SMP2P_ENTRY_UPDATE or SMP2P_OPEN based on the event.
+ * @data: Consists of previous and current value in case of entry update.
+ * @returns: 0 for success (return value required for notifier chains).
+ */
+static int smp2p_rmt_in_edge_notify(struct notifier_block *nb,
+				unsigned long event, void *data)
+{
+	struct smp2p_loopback_ctx *ctx;
+
+	if (!(event == SMP2P_ENTRY_UPDATE || event == SMP2P_OPEN))
+		return 0;
+
+	ctx = container_of(nb, struct smp2p_loopback_ctx, in_nb);
+	if (data && ctx->in_is_active) {
+			ctx->rmt_cmd =
+			    *(struct msm_smp2p_update_notif *)data;
+			schedule_work(&ctx->rmt_lpb_work);
+	}
+
+	return 0;
+}
+
+/**
+ * smp2p_rmt_out_edge_notify - Notifies on the opening of the outbound entry.
+ *
+ * @nb: Notifier block, this is called when the local entry is open.
+ * @event: Takes on value SMP2P_OPEN when the local entry is open.
+ * @data: Consist of current value of the remote entry, if entry is open.
+ * @returns: 0 for success (return value required for notifier chains).
+ */
+static int smp2p_rmt_out_edge_notify(struct notifier_block  *nb,
+				unsigned long event, void *data)
+{
+	struct smp2p_loopback_ctx *ctx;
+
+	ctx = container_of(nb, struct smp2p_loopback_ctx, out_nb);
+	if (event == SMP2P_OPEN)
+		SMP2P_DBG("%s: 'smp2p':%d opened\n", __func__,
+				ctx->proc_id);
+
+	return 0;
+}
+
+/**
+ * msm_smp2p_init_rmt_lpb -  Initializes the remote loopback object.
+ *
+ * @ctx: Pointer to remote loopback object that needs to be initialized.
+ * @pid: Processor id  of the processor that is sending the commands.
+ * @entry: Name of the entry that needs to be opened locally.
+ * @returns: 0 on success, standard Linux error code otherwise.
+ */
+static int msm_smp2p_init_rmt_lpb(struct  smp2p_loopback_ctx *ctx,
+			int pid, const char *entry)
+{
+	int ret = 0;
+	int tmp;
+
+	if (!ctx || !entry || pid > SMP2P_NUM_PROCS)
+		return -EINVAL;
+
+	ctx->in_nb.notifier_call = smp2p_rmt_in_edge_notify;
+	ctx->out_nb.notifier_call = smp2p_rmt_out_edge_notify;
+	ctx->proc_id = pid;
+	ctx->in_is_active = true;
+	ctx->out_is_active = true;
+	tmp = msm_smp2p_out_open(pid, entry, &ctx->out_nb,
+						&ctx->out);
+	if (tmp) {
+		SMP2P_ERR("%s: open failed outbound entry '%s':%d - ret %d\n",
+				__func__, entry, pid, tmp);
+		ret = tmp;
+	}
+
+	tmp = msm_smp2p_in_register(ctx->proc_id,
+				SMP2P_RLPB_ENTRY_NAME,
+				&ctx->in_nb);
+	if (tmp) {
+		SMP2P_ERR("%s: unable to open inbound entry '%s':%d - ret %d\n",
+				__func__, entry, pid, tmp);
+		ret = tmp;
+	}
+
+	return ret;
+}
+
+/**
+ * msm_smp2p_init_rmt_lpb_proc - Wrapper over msm_smp2p_init_rmt_lpb
+ *
+ * @remote_pid: Processor ID of the processor that sends loopback command.
+ * @returns: Pointer to outbound entry handle.
+ */
+void *msm_smp2p_init_rmt_lpb_proc(int remote_pid)
+{
+	int tmp;
+	void *ret = NULL;
+
+	tmp = msm_smp2p_init_rmt_lpb(&remote_loopback[remote_pid],
+			remote_pid, SMP2P_RLPB_ENTRY_NAME);
+	if (!tmp)
+		ret = remote_loopback[remote_pid].out;
+
+	return ret;
+}
+EXPORT_SYMBOL(msm_smp2p_init_rmt_lpb_proc);
+
+/**
+ * msm_smp2p_deinit_rmt_lpb_proc - Unregister support for remote processor.
+ *
+ * @remote_pid:  Processor ID of the remote system.
+ * @returns: 0 on success, standard Linux error code otherwise.
+ *
+ * Unregister loopback support for remote processor.
+ */
+int msm_smp2p_deinit_rmt_lpb_proc(int remote_pid)
+{
+	int ret = 0;
+	int tmp;
+	struct smp2p_loopback_ctx *ctx;
+
+	if (remote_pid >= SMP2P_NUM_PROCS)
+		return -EINVAL;
+
+	ctx = &remote_loopback[remote_pid];
+
+	/* abort any pending notifications */
+	remote_loopback[remote_pid].out_is_active = false;
+	remote_loopback[remote_pid].in_is_active = false;
+	flush_work(&ctx->rmt_lpb_work);
+
+	/* unregister entries */
+	tmp = msm_smp2p_out_close(&remote_loopback[remote_pid].out);
+	remote_loopback[remote_pid].out = NULL;
+	if (tmp) {
+		SMP2P_ERR("%s: outbound 'smp2p':%d close failed %d\n",
+				__func__, remote_pid, tmp);
+		ret = tmp;
+	}
+
+	tmp = msm_smp2p_in_unregister(remote_pid,
+		SMP2P_RLPB_ENTRY_NAME, &remote_loopback[remote_pid].in_nb);
+	if (tmp) {
+		SMP2P_ERR("%s: inbound 'smp2p':%d close failed %d\n",
+				__func__, remote_pid, tmp);
+		ret = tmp;
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(msm_smp2p_deinit_rmt_lpb_proc);
+
+/**
+ * msm_smp2p_set_remote_mock_exists - Sets the remote mock configuration.
+ *
+ * @item_exists: true = Remote mock SMEM item exists
+ *
+ * This is used in the testing environment to simulate the existence of the
+ * remote smem item in order to test the negotiation algorithm.
+ */
+void msm_smp2p_set_remote_mock_exists(bool item_exists)
+{
+	remote_mock.item_exists = item_exists;
+}
+EXPORT_SYMBOL(msm_smp2p_set_remote_mock_exists);
+
+/**
+ * msm_smp2p_get_remote_mock - Get remote mock object.
+ *
+ * @returns: Point to the remote mock object.
+ */
+void *msm_smp2p_get_remote_mock(void)
+{
+	return &remote_mock;
+}
+EXPORT_SYMBOL(msm_smp2p_get_remote_mock);
+
+/**
+ * msm_smp2p_get_remote_mock_smem_item - Returns a pointer to remote item.
+ *
+ * @size:    Size of item.
+ * @returns: Pointer to mock remote smem item.
+ */
+void *msm_smp2p_get_remote_mock_smem_item(uint32_t *size)
+{
+	void *ptr = NULL;
+	if (remote_mock.item_exists) {
+		*size = sizeof(remote_mock.remote_item);
+		ptr = &(remote_mock.remote_item);
+	}
+
+	return ptr;
+}
+EXPORT_SYMBOL(msm_smp2p_get_remote_mock_smem_item);
+
+/**
+ * smp2p_remote_mock_rx_interrupt - Triggers receive interrupt for mock proc.
+ *
+ * @returns: 0 for success
+ *
+ * This function simulates the receiving of interrupt by the mock remote
+ * processor in a testing environment.
+ */
+int smp2p_remote_mock_rx_interrupt(void)
+{
+	remote_mock.rx_interrupt_count++;
+	if (remote_mock.initialized)
+		complete(&remote_mock.cb_completion);
+	return 0;
+}
+EXPORT_SYMBOL(smp2p_remote_mock_rx_interrupt);
+
+/**
+ * smp2p_remote_mock_tx_interrupt - Calls the SMP2P interrupt handler.
+ *
+ * This function calls the interrupt handler of the Apps processor to simulate
+ * receiving interrupts from a remote processor.
+ */
+static void smp2p_remote_mock_tx_interrupt(void)
+{
+	msm_smp2p_interrupt_handler(SMP2P_REMOTE_MOCK_PROC);
+}
+
+/**
+ * smp2p_remote_mock_init - Initialize the remote mock and loopback objects.
+ *
+ * @returns: 0 for success
+ */
+static int __init smp2p_remote_mock_init(void)
+{
+	int i;
+
+	smp2p_init_header(&remote_mock.remote_item.header,
+			SMP2P_REMOTE_MOCK_PROC, SMP2P_APPS_PROC,
+			0, 0);
+	remote_mock.rx_interrupt_count = 0;
+	remote_mock.rx_interrupt = smp2p_remote_mock_rx_interrupt;
+	remote_mock.tx_interrupt = smp2p_remote_mock_tx_interrupt;
+	remote_mock.item_exists = false;
+	init_completion(&remote_mock.cb_completion);
+	remote_mock.initialized = true;
+
+	for (i = 0; i < SMP2P_NUM_PROCS; i++) {
+		INIT_WORK(&(remote_loopback[i].rmt_lpb_work),
+				smp2p_rmt_lpb_worker);
+		if (i == SMP2P_REMOTE_MOCK_PROC)
+			/* do not register loopback for remote mock proc */
+			continue;
+
+		msm_smp2p_init_rmt_lpb(&remote_loopback[i],
+			i, SMP2P_RLPB_ENTRY_NAME);
+	}
+	return 0;
+}
+module_init(smp2p_remote_mock_init);
diff --git a/arch/arm/mach-msm/smp2p_private.h b/arch/arm/mach-msm/smp2p_private.h
new file mode 100644
index 0000000..b9a5cfe
--- /dev/null
+++ b/arch/arm/mach-msm/smp2p_private.h
@@ -0,0 +1,226 @@
+/* arch/arm/mach-msm/smp2p_private.h
+ *
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef _ARCH_ARM_MACH_MSM_MSM_SMP2P_PRIVATE_H_
+#define _ARCH_ARM_MACH_MSM_MSM_SMP2P_PRIVATE_H_
+
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <mach/msm_ipc_logging.h>
+#include "smp2p_private_api.h"
+
+#define SMP2P_MAX_ENTRY 16
+#define SMP2P_LOCAL_VERSION 1
+#define SMP2P_LOCAL_FEATURE  0x0
+
+/* SMEM Item Header Macros */
+#define SMP2P_MAGIC 0x504D5324
+#define SMP2P_LOCAL_PID_MASK 0x0000ffff
+#define SMP2P_LOCAL_PID_BIT 0
+#define SMP2P_REMOTE_PID_MASK 0xffff0000
+#define SMP2P_REMOTE_PID_BIT 16
+#define SMP2P_VERSION_MASK 0x000000ff
+#define SMP2P_VERSION_BIT 0
+#define SMP2P_FEATURE_MASK 0xffffff00
+#define SMP2P_FEATURE_BIT 8
+#define SMP2P_ENT_TOTAL_MASK 0x0000ffff
+#define SMP2P_ENT_TOTAL_BIT 0
+#define SMP2P_ENT_VALID_MASK 0xffff0000
+#define SMP2P_ENT_VALID_BIT 16
+
+#define SMP2P_GET_BITS(hdr_val, mask, bit) \
+	(((hdr_val) & (mask)) >> (bit))
+#define SMP2P_SET_BITS(hdr_val, mask, bit, new_value) \
+	do {\
+		hdr_val = (hdr_val & ~(mask)) \
+		| (((new_value) << (bit)) & (mask)); \
+	} while (0)
+
+#define SMP2P_GET_LOCAL_PID(hdr) \
+	SMP2P_GET_BITS(hdr, SMP2P_LOCAL_PID_MASK, SMP2P_LOCAL_PID_BIT)
+#define SMP2P_SET_LOCAL_PID(hdr, pid) \
+	SMP2P_SET_BITS(hdr, SMP2P_LOCAL_PID_MASK, SMP2P_LOCAL_PID_BIT, pid)
+
+#define SMP2P_GET_REMOTE_PID(hdr) \
+	SMP2P_GET_BITS(hdr, SMP2P_REMOTE_PID_MASK, SMP2P_REMOTE_PID_BIT)
+#define SMP2P_SET_REMOTE_PID(hdr, pid) \
+	SMP2P_SET_BITS(hdr, SMP2P_REMOTE_PID_MASK, SMP2P_REMOTE_PID_BIT, pid)
+
+#define SMP2P_GET_VERSION(hdr) \
+	SMP2P_GET_BITS(hdr, SMP2P_VERSION_MASK, SMP2P_VERSION_BIT)
+#define SMP2P_SET_VERSION(hdr, version) \
+	SMP2P_SET_BITS(hdr, SMP2P_VERSION_MASK, SMP2P_VERSION_BIT, version)
+
+#define SMP2P_GET_FEATURES(hdr) \
+	SMP2P_GET_BITS(hdr, SMP2P_FEATURE_MASK, SMP2P_FEATURE_BIT)
+#define SMP2P_SET_FEATURES(hdr, features) \
+	SMP2P_SET_BITS(hdr, SMP2P_FEATURE_MASK, SMP2P_FEATURE_BIT, features)
+
+#define SMP2P_GET_ENT_TOTAL(hdr) \
+	SMP2P_GET_BITS(hdr, SMP2P_ENT_TOTAL_MASK, SMP2P_ENT_TOTAL_BIT)
+#define SMP2P_SET_ENT_TOTAL(hdr, entries) \
+	SMP2P_SET_BITS(hdr, SMP2P_ENT_TOTAL_MASK, SMP2P_ENT_TOTAL_BIT, entries)
+
+#define SMP2P_GET_ENT_VALID(hdr) \
+	SMP2P_GET_BITS(hdr, SMP2P_ENT_VALID_MASK, SMP2P_ENT_VALID_BIT)
+#define SMP2P_SET_ENT_VALID(hdr, entries) \
+	SMP2P_SET_BITS(hdr,  SMP2P_ENT_VALID_MASK, SMP2P_ENT_VALID_BIT,\
+		entries)
+
+/* Loopback Command Macros */
+#define SMP2P_RMT_CMD_TYPE_MASK 0x80000000
+#define SMP2P_RMT_CMD_TYPE_BIT 31
+#define SMP2P_RMT_IGNORE_MASK 0x40000000
+#define SMP2P_RMT_IGNORE_BIT 30
+#define SMP2P_RMT_CMD_MASK 0x3f000000
+#define SMP2P_RMT_CMD_BIT 24
+#define SMP2P_RMT_DATA_MASK 0x00ffffff
+#define SMP2P_RMT_DATA_BIT 0
+
+#define SMP2P_GET_RMT_CMD_TYPE(val) \
+	SMP2P_GET_BITS(val, SMP2P_RMT_CMD_TYPE_MASK, SMP2P_RMT_CMD_TYPE_BIT)
+#define SMP2P_GET_RMT_CMD(val) \
+	SMP2P_GET_BITS(val, SMP2P_RMT_CMD_MASK, SMP2P_RMT_CMD_BIT)
+
+#define SMP2P_GET_RMT_DATA(val) \
+	SMP2P_GET_BITS(val, SMP2P_RMT_DATA_MASK, SMP2P_RMT_DATA_BIT)
+
+#define SMP2P_SET_RMT_CMD_TYPE(val, cmd_type) \
+	SMP2P_SET_BITS(val, SMP2P_RMT_CMD_TYPE_MASK, SMP2P_RMT_CMD_TYPE_BIT, \
+		cmd_type)
+#define SMP2P_SET_RMT_CMD_TYPE_REQ(val) \
+	SMP2P_SET_RMT_CMD_TYPE(val, 1)
+#define SMP2P_SET_RMT_CMD_TYPE_RESP(val) \
+	SMP2P_SET_RMT_CMD_TYPE(val, 0)
+
+#define SMP2P_SET_RMT_CMD(val, cmd) \
+	SMP2P_SET_BITS(val, SMP2P_RMT_CMD_MASK, SMP2P_RMT_CMD_BIT, \
+		cmd)
+#define SMP2P_SET_RMT_DATA(val, data) \
+	SMP2P_SET_BITS(val, SMP2P_RMT_DATA_MASK, SMP2P_RMT_DATA_BIT, data)
+
+enum {
+	SMP2P_LB_CMD_NOOP = 0x0,
+	SMP2P_LB_CMD_ECHO,
+	SMP2P_LB_CMD_CLEARALL,
+	SMP2P_LB_CMD_PINGPONG,
+	SMP2P_LB_CMD_RSPIN_START,
+	SMP2P_LB_CMD_RSPIN_LOCKED,
+	SMP2P_LB_CMD_RSPIN_UNLOCKED,
+	SMP2P_LB_CMD_RSPIN_END,
+};
+#define SMP2P_RLPB_IGNORE 0x40
+#define SMP2P_RLPB_ENTRY_NAME "smp2p"
+
+/* Debug Logging Macros */
+enum {
+	MSM_SMP2P_INFO = 1U << 0,
+	MSM_SMP2P_DEBUG = 1U << 1,
+	MSM_SMP2P_GPIO = 1U << 2,
+};
+
+#define SMP2P_IPC_LOG_STR(x...) do { \
+	if (smp2p_get_log_ctx()) \
+		ipc_log_string(smp2p_get_log_ctx(), x); \
+} while (0)
+
+#define SMP2P_DBG(x...) do {                              \
+	if (smp2p_get_debug_mask() & MSM_SMP2P_DEBUG) \
+			SMP2P_IPC_LOG_STR(x);  \
+} while (0)
+
+#define SMP2P_INFO(x...) do {                              \
+	if (smp2p_get_debug_mask() & MSM_SMP2P_INFO) \
+			SMP2P_IPC_LOG_STR(x);  \
+} while (0)
+
+#define SMP2P_ERR(x...) do {                              \
+	pr_err(x); \
+	SMP2P_IPC_LOG_STR(x);  \
+} while (0)
+
+#define SMP2P_GPIO(x...) do {                              \
+	if (smp2p_get_debug_mask() & MSM_SMP2P_GPIO) \
+			SMP2P_IPC_LOG_STR(x);  \
+} while (0)
+
+
+enum msm_smp2p_edge_state {
+	SMP2P_EDGE_STATE_CLOSED,
+	SMP2P_EDGE_STATE_OPENING,
+	SMP2P_EDGE_STATE_OPENED,
+	SMP2P_EDGE_STATE_FAILED = 0xff,
+};
+
+struct smp2p_smem {
+	uint32_t magic;
+	uint32_t feature_version;
+	uint32_t rem_loc_proc_id;
+	uint32_t valid_total_ent;
+	uint32_t reserved;
+};
+
+struct smp2p_entry_v1 {
+	char name[SMP2P_MAX_ENTRY_NAME];
+	uint32_t entry;
+};
+
+struct smp2p_smem_item {
+	struct smp2p_smem header;
+	struct smp2p_entry_v1 entries[SMP2P_MAX_ENTRY];
+};
+
+/* Mock object for internal loopback testing. */
+struct msm_smp2p_remote_mock {
+	struct smp2p_smem_item remote_item;
+	int rx_interrupt_count;
+	int (*rx_interrupt)(void);
+	void (*tx_interrupt)(void);
+
+	bool item_exists;
+	bool initialized;
+	struct completion cb_completion;
+};
+
+void smp2p_init_header(struct smp2p_smem *header_ptr, int local_pid,
+		int remote_pid, uint32_t features, uint32_t version);
+void *msm_smp2p_get_remote_mock(void);
+int smp2p_remote_mock_rx_interrupt(void);
+int smp2p_reset_mock_edge(void);
+void msm_smp2p_interrupt_handler(int);
+void msm_smp2p_set_remote_mock_exists(bool item_exists);
+void *msm_smp2p_get_remote_mock_smem_item(uint32_t *size);
+void *msm_smp2p_init_rmt_lpb_proc(int remote_pid);
+int msm_smp2p_deinit_rmt_lpb_proc(int remote_pid);
+void *smp2p_get_log_ctx(void);
+int smp2p_get_debug_mask(void);
+
+/* Inbound / outbound Interrupt configuration. */
+struct smp2p_interrupt_config {
+	bool is_configured;
+	uint32_t *out_int_ptr;
+	uint32_t out_int_mask;
+	int in_int_id;
+	const char *name;
+
+	/* interrupt stats */
+	unsigned in_interrupt_count;
+	unsigned out_interrupt_count;
+};
+
+struct smp2p_interrupt_config *smp2p_get_interrupt_config(void);
+const char *smp2p_pid_to_name(int remote_pid);
+struct smp2p_smem *smp2p_get_in_item(int remote_pid);
+struct smp2p_smem *smp2p_get_out_item(int remote_pid, int *state);
+void smp2p_gpio_open_test_entry(const char *name, int remote_pid, bool do_open);
+#endif
diff --git a/arch/arm/mach-msm/smp2p_private_api.h b/arch/arm/mach-msm/smp2p_private_api.h
new file mode 100644
index 0000000..c757eec
--- /dev/null
+++ b/arch/arm/mach-msm/smp2p_private_api.h
@@ -0,0 +1,79 @@
+/* arch/arm/mach-msm/smp2p_private_api.h
+ *
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef _ARCH_ARM_MACH_MSM_SMP2P_PRIVATE_API_H_
+#define _ARCH_ARM_MACH_MSM_SMP2P_PRIVATE_API_H_
+
+#include <linux/notifier.h>
+
+struct msm_smp2p_out;
+
+/* Maximum size of the entry name and trailing null. */
+#define SMP2P_MAX_ENTRY_NAME 16
+
+/* Bits per entry */
+#define SMP2P_BITS_PER_ENTRY 32
+
+/* Processor ID's */
+enum {
+	SMP2P_APPS_PROC       = 0,
+	SMP2P_MODEM_PROC      = 1,
+	SMP2P_AUDIO_PROC      = 2,
+	SMP2P_RESERVED_PROC_1 = 3,
+	SMP2P_WIRELESS_PROC   = 4,
+	SMP2P_RESERVED_PROC_2 = 5,
+	SMP2P_POWER_PROC      = 6,
+	/* add new processors here */
+
+	SMP2P_REMOTE_MOCK_PROC,
+	SMP2P_NUM_PROCS,
+};
+
+/**
+ * Notification events that are passed to notifier for incoming and outgoing
+ * entries.
+ *
+ * If the @metadata argument in the notifier is non-null, then it will
+ * point to the associated struct smux_meta_* structure.
+ */
+enum msm_smp2p_events {
+	SMP2P_OPEN,         /* data is NULL */
+	SMP2P_ENTRY_UPDATE, /* data => struct msm_smp2p_update_notif */
+};
+
+/**
+ * Passed in response to a SMP2P_ENTRY_UPDATE event.
+ *
+ * @prev_value:     previous value of entry
+ * @current_value:  latest value of entry
+ */
+struct msm_smp2p_update_notif {
+	uint32_t previous_value;
+	uint32_t current_value;
+};
+
+int msm_smp2p_out_open(int remote_pid, const char *entry,
+	struct notifier_block *open_notifier,
+	struct msm_smp2p_out **handle);
+int msm_smp2p_out_close(struct msm_smp2p_out **handle);
+int msm_smp2p_out_read(struct msm_smp2p_out *handle, uint32_t *data);
+int msm_smp2p_out_write(struct msm_smp2p_out *handle, uint32_t data);
+int msm_smp2p_out_modify(struct msm_smp2p_out *handle, uint32_t set_mask,
+	uint32_t clear_mask);
+int msm_smp2p_in_read(int remote_pid, const char *entry, uint32_t *data);
+int msm_smp2p_in_register(int remote_pid, const char *entry,
+	struct notifier_block *in_notifier);
+int msm_smp2p_in_unregister(int remote_pid, const char *entry,
+	struct notifier_block *in_notifier);
+
+#endif /* _ARCH_ARM_MACH_MSM_SMP2P_PRIVATE_API_H_ */
diff --git a/arch/arm/mach-msm/smp2p_spinlock_test.c b/arch/arm/mach-msm/smp2p_spinlock_test.c
new file mode 100644
index 0000000..09d7c0d
--- /dev/null
+++ b/arch/arm/mach-msm/smp2p_spinlock_test.c
@@ -0,0 +1,487 @@
+/* arch/arm/mach-msm/smp2p_spinlock_test.c
+ *
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/debugfs.h>
+#include <linux/ctype.h>
+#include <linux/jiffies.h>
+#include <linux/delay.h>
+#include <linux/completion.h>
+#include <linux/remote_spinlock.h>
+#include <mach/msm_smsm.h>
+#include "smd_private.h"
+#include "smp2p_private.h"
+#include "smp2p_test_common.h"
+
+#define REMOTE_SPIN_PID 1
+#define RS_END_THIEF_PID_BIT 20
+#define RS_END_THIEF_MASK 0x00f00000
+
+/* Spinlock commands used for testing Apps<->RPM spinlocks. */
+enum RPM_SPINLOCK_CMDS {
+	RPM_CMD_INVALID,
+	RPM_CMD_START,
+	RPM_CMD_LOCKED,
+	RPM_CMD_UNLOCKED,
+	RPM_CMD_END,
+};
+
+/* Shared structure for testing Apps<->RPM spinlocks. */
+struct rpm_spinlock_test {
+	uint32_t apps_cmd;
+	uint32_t apps_lock_count;
+	uint32_t rpm_cmd;
+	uint32_t rpm_lock_count;
+};
+
+/**
+ * smp2p_ut_remote_spinlock_core - Verify remote spinlock.
+ *
+ * @s:           Pointer to output file
+ * @remote_pid:  Remote processor to test
+ * @use_trylock: Use trylock to prevent an Apps deadlock if the
+ *               remote spinlock fails.
+ */
+static void smp2p_ut_remote_spinlock_core(struct seq_file *s, int remote_pid,
+		bool use_trylock)
+{
+	int failed = 0;
+	unsigned lock_count = 0;
+	struct msm_smp2p_out *handle = NULL;
+	int ret;
+	uint32_t test_request;
+	uint32_t test_response;
+	struct mock_cb_data cb_out;
+	struct mock_cb_data cb_in;
+	unsigned long flags;
+	unsigned n;
+	unsigned test_num;
+	bool have_lock;
+	bool timeout;
+	int failed_tmp;
+	int spinlock_owner;
+	remote_spinlock_t *smem_spinlock;
+
+	seq_printf(s, "Running %s for '%s' remote pid %d\n",
+		   __func__, smp2p_pid_to_name(remote_pid), remote_pid);
+
+	cb_out.initialized = false;
+	cb_in.initialized = false;
+	mock_cb_data_init(&cb_out);
+	mock_cb_data_init(&cb_in);
+	do {
+		smem_spinlock = smem_get_remote_spinlock();
+		UT_ASSERT_PTR(smem_spinlock, !=, NULL);
+
+		/* Open output entry */
+		ret = msm_smp2p_out_open(remote_pid, SMP2P_RLPB_ENTRY_NAME,
+			&cb_out.nb, &handle);
+		UT_ASSERT_INT(ret, ==, 0);
+		UT_ASSERT_INT(
+			(int)wait_for_completion_timeout(
+					&cb_out.cb_completion, HZ * 2),
+			>, 0);
+		UT_ASSERT_INT(cb_out.cb_count, ==, 1);
+		UT_ASSERT_INT(cb_out.event_open, ==, 1);
+
+		/* Open inbound entry */
+		ret = msm_smp2p_in_register(remote_pid, SMP2P_RLPB_ENTRY_NAME,
+				&cb_in.nb);
+		UT_ASSERT_INT(ret, ==, 0);
+		UT_ASSERT_INT(
+			(int)wait_for_completion_timeout(
+					&cb_in.cb_completion, HZ * 2),
+			>, 0);
+		UT_ASSERT_INT(cb_in.cb_count, ==, 1);
+		UT_ASSERT_INT(cb_in.event_open, ==, 1);
+
+		/* Send start */
+		mock_cb_data_reset(&cb_in);
+		mock_cb_data_reset(&cb_out);
+		test_request = 0x0;
+		SMP2P_SET_RMT_CMD_TYPE_REQ(test_request);
+		SMP2P_SET_RMT_CMD(test_request, SMP2P_LB_CMD_RSPIN_START);
+		SMP2P_SET_RMT_DATA(test_request, 0x0);
+		ret = msm_smp2p_out_write(handle, test_request);
+		UT_ASSERT_INT(ret, ==, 0);
+
+		UT_ASSERT_INT(
+			(int)wait_for_completion_timeout(
+					&cb_in.cb_completion, HZ * 2),
+			>, 0);
+		UT_ASSERT_INT(cb_in.cb_count, ==, 1);
+		UT_ASSERT_INT(cb_in.event_entry_update, ==, 1);
+		ret = msm_smp2p_in_read(remote_pid, SMP2P_RLPB_ENTRY_NAME,
+				&test_response);
+		UT_ASSERT_INT(ret, ==, 0);
+
+		test_response = SMP2P_GET_RMT_CMD(test_response);
+		if (test_response != SMP2P_LB_CMD_RSPIN_LOCKED &&
+				test_response != SMP2P_LB_CMD_RSPIN_UNLOCKED) {
+			/* invalid response from remote - abort test */
+			test_request = 0x0;
+			SMP2P_SET_RMT_CMD_TYPE(test_request, 1);
+			SMP2P_SET_RMT_CMD(test_request, SMP2P_LB_CMD_RSPIN_END);
+			SMP2P_SET_RMT_DATA(test_request, 0x0);
+			ret = msm_smp2p_out_write(handle, test_request);
+			UT_ASSERT_HEX(SMP2P_LB_CMD_RSPIN_LOCKED, ==,
+					test_response);
+		}
+
+		/* Run spinlock test */
+		if (use_trylock)
+			seq_printf(s, "\tUsing remote_spin_trylock\n");
+		else
+			seq_printf(s, "\tUsing remote_spin_lock\n");
+
+		flags = 0;
+		have_lock = false;
+		timeout = false;
+		spinlock_owner = 0;
+		test_request = 0x0;
+		SMP2P_SET_RMT_CMD_TYPE_REQ(test_request);
+		for (test_num = 0; !failed && test_num < 10000; ++test_num) {
+			/* try to acquire spinlock */
+			if (use_trylock) {
+				unsigned long j_start = jiffies;
+				while (!remote_spin_trylock_irqsave(
+						smem_spinlock, flags)) {
+					if (jiffies_to_msecs(jiffies - j_start)
+							> 1000) {
+						seq_printf(s,
+							"\tFail: Timeout trying to get the lock\n");
+						timeout = true;
+						break;
+					}
+				}
+				if (timeout)
+					break;
+			} else {
+				remote_spin_lock_irqsave(smem_spinlock, flags);
+			}
+			have_lock = true;
+			++lock_count;
+
+			/* tell the remote side that we have the lock */
+			SMP2P_SET_RMT_DATA(test_request, lock_count);
+			SMP2P_SET_RMT_CMD(test_request,
+					SMP2P_LB_CMD_RSPIN_LOCKED);
+			ret = msm_smp2p_out_write(handle, test_request);
+			UT_ASSERT_INT(ret, ==, 0);
+
+			/* verify the other side doesn't say it has the lock */
+			for (n = 0; n < 1000; ++n) {
+				spinlock_owner =
+					remote_spin_owner(smem_spinlock);
+				if (spinlock_owner != REMOTE_SPIN_PID) {
+					/* lock stolen by remote side */
+					seq_printf(s,
+						"\tFail: Remote side (%d) stole lock (pid %d)\n",
+						remote_pid, spinlock_owner);
+					failed = true;
+					break;
+				}
+				spinlock_owner = 0;
+
+				ret = msm_smp2p_in_read(remote_pid,
+					SMP2P_RLPB_ENTRY_NAME, &test_response);
+				UT_ASSERT_INT(ret, ==, 0);
+				test_response =
+					SMP2P_GET_RMT_CMD(test_response);
+				UT_ASSERT_HEX(SMP2P_LB_CMD_RSPIN_UNLOCKED, ==,
+					test_response);
+			}
+			if (failed)
+				break;
+
+			/* tell remote side we are unlocked and release lock */
+			SMP2P_SET_RMT_CMD(test_request,
+					SMP2P_LB_CMD_RSPIN_UNLOCKED);
+			(void)msm_smp2p_out_write(handle, test_request);
+			have_lock = false;
+			remote_spin_unlock_irqrestore(smem_spinlock, flags);
+		}
+		if (have_lock)
+			remote_spin_unlock_irqrestore(smem_spinlock, flags);
+
+		/* End test */
+		mock_cb_data_reset(&cb_in);
+		SMP2P_SET_RMT_CMD(test_request, SMP2P_LB_CMD_RSPIN_END);
+		SMP2P_SET_RMT_DATA(test_request, lock_count |
+				(spinlock_owner << RS_END_THIEF_PID_BIT));
+		(void)msm_smp2p_out_write(handle, test_request);
+
+		failed_tmp = failed;
+		failed = false;
+		do {
+			UT_ASSERT_INT(
+				(int)wait_for_completion_timeout(
+					&cb_in.cb_completion, HZ * 2),
+				>, 0);
+			INIT_COMPLETION(cb_in.cb_completion);
+			ret = msm_smp2p_in_read(remote_pid,
+					SMP2P_RLPB_ENTRY_NAME, &test_response);
+			UT_ASSERT_INT(ret, ==, 0);
+		} while (!failed &&
+			SMP2P_GET_RMT_CMD(test_response) !=
+			SMP2P_LB_CMD_RSPIN_END);
+		if (failed)
+			break;
+		failed = failed_tmp;
+
+		test_response = SMP2P_GET_RMT_DATA(test_response);
+		seq_printf(s,
+			"\tLocked spinlock local %u times; remote %u times",
+			lock_count,
+			test_response & ((1 << RS_END_THIEF_PID_BIT) - 1)
+			);
+		if (test_response & RS_END_THIEF_MASK) {
+			seq_printf(s,
+				"Remote side reporting lock stolen by pid %d.\n",
+				SMP2P_GET_BITS(test_response,
+					RS_END_THIEF_MASK,
+					RS_END_THIEF_PID_BIT));
+			failed = 1;
+		}
+		seq_printf(s, "\n");
+
+		/* Cleanup */
+		ret = msm_smp2p_out_close(&handle);
+		UT_ASSERT_INT(ret, ==, 0);
+		UT_ASSERT_PTR(handle, ==, NULL);
+		ret = msm_smp2p_in_unregister(remote_pid,
+				SMP2P_RLPB_ENTRY_NAME, &cb_in.nb);
+		UT_ASSERT_INT(ret, ==, 0);
+
+		if (!failed && !timeout)
+			seq_printf(s, "\tOK\n");
+	} while (0);
+
+	if (failed) {
+		if (handle) {
+			/* send end command */
+			test_request = 0;
+			SMP2P_SET_RMT_CMD(test_request, SMP2P_LB_CMD_RSPIN_END);
+			SMP2P_SET_RMT_DATA(test_request, lock_count);
+			(void)msm_smp2p_out_write(handle, test_request);
+			(void)msm_smp2p_out_close(&handle);
+		}
+		(void)msm_smp2p_in_unregister(remote_pid,
+				SMP2P_RLPB_ENTRY_NAME, &cb_in.nb);
+
+		pr_err("%s: Failed\n", __func__);
+		seq_printf(s, "\tFailed\n");
+	}
+}
+
+/**
+ * smp2p_ut_remote_spinlock_pid - Verify remote spinlock for a processor.
+ *
+ * @s:           Pointer to output file
+ * @pid:         Processor to test
+ * @use_trylock: Use trylock to prevent an Apps deadlock if the
+ *               remote spinlock fails.
+ */
+static void smp2p_ut_remote_spinlock_pid(struct seq_file *s, int pid,
+		bool use_trylock)
+{
+	struct smp2p_interrupt_config *int_cfg;
+
+	int_cfg = smp2p_get_interrupt_config();
+	if (!int_cfg) {
+		seq_printf(s, "Remote processor config unavailable\n");
+		return;
+	}
+
+	if (pid >= SMP2P_NUM_PROCS || !int_cfg[pid].is_configured)
+		return;
+
+	msm_smp2p_deinit_rmt_lpb_proc(pid);
+	smp2p_ut_remote_spinlock_core(s, pid, use_trylock);
+	msm_smp2p_init_rmt_lpb_proc(pid);
+}
+
+/**
+ * smp2p_ut_remote_spinlock - Verify remote spinlock for all processors.
+ *
+ * @s:   pointer to output file
+ */
+static void smp2p_ut_remote_spinlock(struct seq_file *s)
+{
+	int pid;
+
+	for (pid = 0; pid < SMP2P_NUM_PROCS; ++pid)
+		smp2p_ut_remote_spinlock_pid(s, pid, false);
+}
+
+/**
+ * smp2p_ut_remote_spin_trylock - Verify remote trylock for all processors.
+ *
+ * @s:   Pointer to output file
+ */
+static void smp2p_ut_remote_spin_trylock(struct seq_file *s)
+{
+	int pid;
+
+	for (pid = 0; pid < SMP2P_NUM_PROCS; ++pid)
+		smp2p_ut_remote_spinlock_pid(s, pid, true);
+}
+
+/**
+ * smp2p_ut_remote_spinlock - Verify remote spinlock for all processors.
+ *
+ * @s:   pointer to output file
+ *
+ * This test verifies inbound and outbound functionality for all
+ * configured remote processor.
+ */
+static void smp2p_ut_remote_spinlock_modem(struct seq_file *s)
+{
+	smp2p_ut_remote_spinlock_pid(s, SMP2P_MODEM_PROC, false);
+}
+
+static void smp2p_ut_remote_spinlock_adsp(struct seq_file *s)
+{
+	smp2p_ut_remote_spinlock_pid(s, SMP2P_AUDIO_PROC, false);
+}
+
+static void smp2p_ut_remote_spinlock_wcnss(struct seq_file *s)
+{
+	smp2p_ut_remote_spinlock_pid(s, SMP2P_WIRELESS_PROC, false);
+}
+
+/**
+ * smp2p_ut_remote_spinlock_rpm - Verify remote spinlock.
+ *
+ * @s:   pointer to output file
+ * @remote_pid:  Remote processor to test
+ */
+static void smp2p_ut_remote_spinlock_rpm(struct seq_file *s)
+{
+	int failed = 0;
+	unsigned long flags;
+	unsigned n;
+	unsigned test_num;
+	struct rpm_spinlock_test *data_ptr;
+	remote_spinlock_t *smem_spinlock;
+	bool have_lock;
+
+	seq_printf(s, "Running %s for Apps<->RPM Test\n",
+		   __func__);
+	do {
+		smem_spinlock = smem_get_remote_spinlock();
+		UT_ASSERT_PTR(smem_spinlock, !=, NULL);
+
+		data_ptr = smem_alloc2(SMEM_ID_VENDOR0,
+				sizeof(struct rpm_spinlock_test));
+		UT_ASSERT_PTR(0, !=, data_ptr);
+
+		/* Send start */
+		writel_relaxed(0, &data_ptr->apps_lock_count);
+		writel_relaxed(RPM_CMD_START, &data_ptr->apps_cmd);
+
+		seq_printf(s, "\tWaiting for RPM to start test\n");
+		for (n = 0; n < 1000; ++n) {
+			if (readl_relaxed(&data_ptr->rpm_cmd) !=
+					RPM_CMD_INVALID)
+				break;
+			usleep(1000);
+		}
+		if (readl_relaxed(&data_ptr->rpm_cmd) == RPM_CMD_INVALID) {
+			/* timeout waiting for RPM */
+			writel_relaxed(RPM_CMD_INVALID, &data_ptr->apps_cmd);
+			UT_ASSERT_INT(RPM_CMD_LOCKED, !=, RPM_CMD_INVALID);
+		}
+
+		/* Run spinlock test */
+		flags = 0;
+		have_lock = false;
+		for (test_num = 0; !failed && test_num < 10000; ++test_num) {
+			/* acquire spinlock */
+			remote_spin_lock_irqsave(smem_spinlock, flags);
+			have_lock = true;
+			writel_relaxed(++data_ptr->apps_lock_count,
+				&data_ptr->apps_lock_count);
+			writel_relaxed(RPM_CMD_LOCKED, &data_ptr->apps_cmd);
+			/*
+			 * Ensure that the remote side sees our lock has
+			 * been acquired before we start polling their status.
+			 */
+			wmb();
+
+			/* verify the other side doesn't say it has the lock */
+			for (n = 0; n < 1000; ++n) {
+				UT_ASSERT_HEX(RPM_CMD_UNLOCKED, ==,
+					readl_relaxed(&data_ptr->rpm_cmd));
+			}
+			if (failed)
+				break;
+
+			/* release spinlock */
+			have_lock = false;
+			writel_relaxed(RPM_CMD_UNLOCKED, &data_ptr->apps_cmd);
+			/*
+			 * Ensure that our status-update write was committed
+			 * before we unlock the spinlock.
+			 */
+			wmb();
+			remote_spin_unlock_irqrestore(smem_spinlock, flags);
+		}
+		if (have_lock)
+			remote_spin_unlock_irqrestore(smem_spinlock, flags);
+
+		/* End test */
+		writel_relaxed(RPM_CMD_INVALID, &data_ptr->apps_cmd);
+		seq_printf(s,
+				"\tLocked spinlock local %u remote %u\n",
+				readl_relaxed(&data_ptr->apps_lock_count),
+				readl_relaxed(&data_ptr->rpm_lock_count));
+
+		if (!failed)
+			seq_printf(s, "\tOK\n");
+	} while (0);
+
+	if (failed) {
+		pr_err("%s: Failed\n", __func__);
+		seq_printf(s, "\tFailed\n");
+	}
+}
+
+static int __init smp2p_debugfs_init(void)
+{
+	/*
+	 * 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.
+	 */
+	smp2p_debug_create("ut_remote_spinlock",
+		smp2p_ut_remote_spinlock);
+	smp2p_debug_create("ut_remote_spin_trylock",
+		smp2p_ut_remote_spin_trylock);
+	smp2p_debug_create("ut_remote_spinlock_modem",
+		smp2p_ut_remote_spinlock_modem);
+	smp2p_debug_create("ut_remote_spinlock_adsp",
+		smp2p_ut_remote_spinlock_adsp);
+	smp2p_debug_create("ut_remote_spinlock_wcnss",
+		smp2p_ut_remote_spinlock_wcnss);
+	smp2p_debug_create("ut_remote_spinlock_rpm",
+		smp2p_ut_remote_spinlock_rpm);
+
+	return 0;
+}
+module_init(smp2p_debugfs_init);
diff --git a/arch/arm/mach-msm/smp2p_test.c b/arch/arm/mach-msm/smp2p_test.c
new file mode 100644
index 0000000..10f7575
--- /dev/null
+++ b/arch/arm/mach-msm/smp2p_test.c
@@ -0,0 +1,913 @@
+/* arch/arm/mach-msm/smp2p_test.c
+ *
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/debugfs.h>
+#include <linux/ctype.h>
+#include <linux/jiffies.h>
+#include <linux/delay.h>
+#include <linux/completion.h>
+#include "smp2p_private.h"
+#include "smp2p_test_common.h"
+
+/**
+ * smp2p_ut_local_basic - Basic sanity test using local loopback.
+ *
+ * @s: pointer to output file
+ *
+ * This test simulates a simple write and read
+ * when remote processor does not exist.
+ */
+static void smp2p_ut_local_basic(struct seq_file *s)
+{
+	int failed = 0;
+	struct msm_smp2p_out *smp2p_obj;
+	struct msm_smp2p_remote_mock *rmp = NULL;
+	int ret;
+	uint32_t test_request;
+	uint32_t test_response = 0;
+	static struct mock_cb_data cb_data;
+
+	seq_printf(s, "Running %s\n", __func__);
+	mock_cb_data_init(&cb_data);
+	do {
+		/* initialize mock edge and start opening */
+		ret = smp2p_reset_mock_edge();
+		UT_ASSERT_INT(ret, ==, 0);
+
+		rmp = msm_smp2p_get_remote_mock();
+		UT_ASSERT_PTR(rmp, !=, NULL);
+
+		rmp->rx_interrupt_count = 0;
+		memset(&rmp->remote_item, 0,
+			sizeof(struct smp2p_smem_item));
+
+		msm_smp2p_set_remote_mock_exists(false);
+
+		ret = msm_smp2p_out_open(SMP2P_REMOTE_MOCK_PROC, "smp2p",
+			&cb_data.nb, &smp2p_obj);
+		UT_ASSERT_INT(ret, ==, 0);
+
+		UT_ASSERT_INT(rmp->rx_interrupt_count, ==, 1);
+		UT_ASSERT_INT(cb_data.cb_count, ==, 0);
+		rmp->rx_interrupt_count = 0;
+
+		/* simulate response from remote side */
+		rmp->remote_item.header.magic = SMP2P_MAGIC;
+		SMP2P_SET_LOCAL_PID(
+		rmp->remote_item.header.rem_loc_proc_id,
+					SMP2P_REMOTE_MOCK_PROC);
+		SMP2P_SET_REMOTE_PID(
+		rmp->remote_item.header.rem_loc_proc_id,
+					SMP2P_APPS_PROC);
+		SMP2P_SET_VERSION(
+		rmp->remote_item.header.feature_version, 1);
+		SMP2P_SET_FEATURES(
+		rmp->remote_item.header.feature_version, 0);
+		SMP2P_SET_ENT_TOTAL(
+		rmp->remote_item.header.valid_total_ent, SMP2P_MAX_ENTRY);
+		SMP2P_SET_ENT_VALID(
+		rmp->remote_item.header.valid_total_ent, 0);
+		rmp->remote_item.header.reserved = 0x0;
+		msm_smp2p_set_remote_mock_exists(true);
+		rmp->tx_interrupt();
+
+		/* verify port was opened */
+		UT_ASSERT_INT(
+			(int)wait_for_completion_timeout(
+					&cb_data.cb_completion, HZ / 2), >, 0);
+		UT_ASSERT_INT(cb_data.cb_count, ==, 1);
+		UT_ASSERT_INT(cb_data.event_open, ==, 1);
+		UT_ASSERT_INT(rmp->rx_interrupt_count, ==, 2);
+
+		/* do write (test outbound entries) */
+		rmp->rx_interrupt_count = 0;
+		test_request = 0xC0DE;
+		ret = msm_smp2p_out_write(smp2p_obj, test_request);
+		UT_ASSERT_INT(ret, ==, 0);
+		UT_ASSERT_INT(rmp->rx_interrupt_count, ==, 1);
+
+		/* do read (test inbound entries) */
+		ret = msm_smp2p_out_read(smp2p_obj, &test_response);
+		UT_ASSERT_INT(ret, ==, 0);
+		UT_ASSERT_INT(test_request, ==, test_response);
+
+		ret = msm_smp2p_out_close(&smp2p_obj);
+		UT_ASSERT_INT(ret, ==, 0);
+		UT_ASSERT_PTR(smp2p_obj, ==, 0);
+
+		seq_printf(s, "\tOK\n");
+	} while (0);
+
+	if (failed) {
+		pr_err("%s: Failed\n", __func__);
+		seq_printf(s, "\tFailed\n");
+		(void)msm_smp2p_out_close(&smp2p_obj);
+	}
+}
+
+/**
+ * smp2p_ut_local_late_open - Verify post-negotiation opening.
+ *
+ * @s: pointer to output file
+ *
+ * Verify entry creation for opening entries after negotiation is complete.
+ */
+static void smp2p_ut_local_late_open(struct seq_file *s)
+{
+	int failed = 0;
+	struct msm_smp2p_out *smp2p_obj;
+	struct msm_smp2p_remote_mock *rmp = NULL;
+	int ret;
+	uint32_t test_request;
+	uint32_t test_response = 0;
+	static struct mock_cb_data cb_data;
+
+	seq_printf(s, "Running %s\n", __func__);
+	mock_cb_data_init(&cb_data);
+	do {
+		/* initialize mock edge */
+		ret = smp2p_reset_mock_edge();
+		UT_ASSERT_INT(ret, ==, 0);
+
+		rmp = msm_smp2p_get_remote_mock();
+		UT_ASSERT_PTR(rmp, !=, NULL);
+
+		rmp->rx_interrupt_count = 0;
+		memset(&rmp->remote_item, 0,
+			sizeof(struct smp2p_smem_item));
+		rmp->remote_item.header.magic = SMP2P_MAGIC;
+		SMP2P_SET_LOCAL_PID(
+		rmp->remote_item.header.rem_loc_proc_id,
+						SMP2P_REMOTE_MOCK_PROC);
+		SMP2P_SET_REMOTE_PID(
+		rmp->remote_item.header.rem_loc_proc_id,
+						SMP2P_APPS_PROC);
+		SMP2P_SET_VERSION(
+			rmp->remote_item.header.feature_version, 1);
+		SMP2P_SET_FEATURES(
+			rmp->remote_item.header.feature_version, 0);
+		SMP2P_SET_ENT_TOTAL(
+			rmp->remote_item.header.valid_total_ent,
+			SMP2P_MAX_ENTRY);
+		SMP2P_SET_ENT_VALID(
+		rmp->remote_item.header.valid_total_ent, 0);
+		rmp->remote_item.header.reserved = 0x0;
+
+		msm_smp2p_set_remote_mock_exists(true);
+
+		ret = msm_smp2p_out_open(SMP2P_REMOTE_MOCK_PROC, "smp2p",
+			&cb_data.nb, &smp2p_obj);
+		UT_ASSERT_INT(ret, ==, 0);
+
+		/* verify port was opened */
+		UT_ASSERT_INT(
+			(int)wait_for_completion_timeout(
+					&cb_data.cb_completion, HZ / 2),
+			>, 0);
+		UT_ASSERT_INT(cb_data.cb_count, ==, 1);
+		UT_ASSERT_INT(cb_data.event_open, ==, 1);
+		UT_ASSERT_INT(rmp->rx_interrupt_count, ==, 2);
+
+		/* do write (test outbound entries) */
+		rmp->rx_interrupt_count = 0;
+		test_request = 0xC0DE;
+		ret = msm_smp2p_out_write(smp2p_obj, test_request);
+		UT_ASSERT_INT(ret, ==, 0);
+		UT_ASSERT_INT(rmp->rx_interrupt_count, ==, 1);
+
+		/* do read (test inbound entries) */
+		ret = msm_smp2p_out_read(smp2p_obj, &test_response);
+		UT_ASSERT_INT(ret, ==, 0);
+		UT_ASSERT_INT(test_request, ==, test_response);
+
+		ret = msm_smp2p_out_close(&smp2p_obj);
+		UT_ASSERT_INT(ret, ==, 0);
+		UT_ASSERT_PTR(smp2p_obj, ==, 0);
+
+		seq_printf(s, "\tOK\n");
+	} while (0);
+
+	if (failed) {
+		pr_err("%s: Failed\n", __func__);
+		seq_printf(s, "\tFailed\n");
+		(void)msm_smp2p_out_close(&smp2p_obj);
+	}
+}
+
+/**
+ * smp2p_ut_local_early_open - Verify pre-negotiation opening.
+ *
+ * @s: pointer to output file
+ *
+ * Verify entry creation for opening entries before negotiation is complete.
+ */
+static void smp2p_ut_local_early_open(struct seq_file *s)
+{
+	int failed = 0;
+	struct msm_smp2p_out *smp2p_obj;
+	struct msm_smp2p_remote_mock *rmp = NULL;
+	struct smp2p_smem *outbound_item;
+	int negotiation_state;
+	int ret;
+	uint32_t test_request;
+	uint32_t test_response = 0;
+	static struct mock_cb_data cb_data;
+
+	seq_printf(s, "Running %s\n", __func__);
+	mock_cb_data_init(&cb_data);
+	do {
+		/* initialize mock edge, but don't enable, yet */
+		ret = smp2p_reset_mock_edge();
+		UT_ASSERT_INT(ret, ==, 0);
+
+		rmp = msm_smp2p_get_remote_mock();
+		UT_ASSERT_PTR(rmp, !=, NULL);
+
+		rmp->rx_interrupt_count = 0;
+		memset(&rmp->remote_item, 0,
+			sizeof(struct smp2p_smem_item));
+		rmp->remote_item.header.magic = SMP2P_MAGIC;
+		SMP2P_SET_LOCAL_PID(
+		rmp->remote_item.header.rem_loc_proc_id,
+						SMP2P_REMOTE_MOCK_PROC);
+		SMP2P_SET_REMOTE_PID(
+		rmp->remote_item.header.rem_loc_proc_id,
+						SMP2P_APPS_PROC);
+		SMP2P_SET_VERSION(
+		rmp->remote_item.header.feature_version, 1);
+		SMP2P_SET_FEATURES(
+		rmp->remote_item.header.feature_version, 0);
+		SMP2P_SET_ENT_TOTAL(
+		rmp->remote_item.header.valid_total_ent, SMP2P_MAX_ENTRY);
+		SMP2P_SET_ENT_VALID(
+		rmp->remote_item.header.valid_total_ent, 0);
+		rmp->remote_item.header.reserved = 0x0;
+
+		msm_smp2p_set_remote_mock_exists(false);
+		UT_ASSERT_PTR(NULL, ==,
+				smp2p_get_in_item(SMP2P_REMOTE_MOCK_PROC));
+
+		/* initiate open, but verify it doesn't complete */
+		ret = msm_smp2p_out_open(SMP2P_REMOTE_MOCK_PROC, "smp2p",
+			&cb_data.nb, &smp2p_obj);
+		UT_ASSERT_INT(ret, ==, 0);
+
+		UT_ASSERT_INT(
+			(int)wait_for_completion_timeout(
+					&cb_data.cb_completion, HZ / 8),
+			==, 0);
+		UT_ASSERT_INT(cb_data.cb_count, ==, 0);
+		UT_ASSERT_INT(cb_data.event_open, ==, 0);
+		UT_ASSERT_INT(rmp->rx_interrupt_count, ==, 1);
+
+		outbound_item = smp2p_get_out_item(SMP2P_REMOTE_MOCK_PROC,
+				&negotiation_state);
+		UT_ASSERT_PTR(outbound_item, !=, NULL);
+		UT_ASSERT_INT(negotiation_state, ==, SMP2P_EDGE_STATE_OPENING);
+		UT_ASSERT_INT(0, ==,
+			SMP2P_GET_ENT_VALID(outbound_item->valid_total_ent));
+
+		/* verify that read/write don't work yet */
+		rmp->rx_interrupt_count = 0;
+		test_request = 0x0;
+		ret = msm_smp2p_out_write(smp2p_obj, test_request);
+		UT_ASSERT_INT(ret, ==, -ENODEV);
+		UT_ASSERT_INT(rmp->rx_interrupt_count, ==, 0);
+
+		ret = msm_smp2p_out_read(smp2p_obj, &test_response);
+		UT_ASSERT_INT(ret, ==, -ENODEV);
+
+		/* allocate remote entry and verify open */
+		msm_smp2p_set_remote_mock_exists(true);
+		rmp->tx_interrupt();
+
+		UT_ASSERT_INT(
+			(int)wait_for_completion_timeout(
+					&cb_data.cb_completion, HZ / 2),
+			>, 0);
+		UT_ASSERT_INT(cb_data.cb_count, ==, 1);
+		UT_ASSERT_INT(cb_data.event_open, ==, 1);
+		UT_ASSERT_INT(rmp->rx_interrupt_count, ==, 2);
+
+		/* do write (test outbound entries) */
+		rmp->rx_interrupt_count = 0;
+		test_request = 0xC0DE;
+		ret = msm_smp2p_out_write(smp2p_obj, test_request);
+		UT_ASSERT_INT(ret, ==, 0);
+		UT_ASSERT_INT(rmp->rx_interrupt_count, ==, 1);
+
+		/* do read (test inbound entries) */
+		ret = msm_smp2p_out_read(smp2p_obj, &test_response);
+		UT_ASSERT_INT(ret, ==, 0);
+		UT_ASSERT_INT(test_request, ==, test_response);
+
+		ret = msm_smp2p_out_close(&smp2p_obj);
+		UT_ASSERT_INT(ret, ==, 0);
+		UT_ASSERT_PTR(smp2p_obj, ==, 0);
+
+		seq_printf(s, "\tOK\n");
+	} while (0);
+
+	if (failed) {
+		pr_err("%s: Failed\n", __func__);
+		seq_printf(s, "\tFailed\n");
+		(void)msm_smp2p_out_close(&smp2p_obj);
+	}
+}
+
+/**
+ * smp2p_ut_mock_loopback - Exercise the remote loopback using remote mock.
+ *
+ * @s: pointer to output file
+ *
+ * This test exercises the remote loopback code using
+ * remote mock object. The remote mock object simulates the remote
+ * processor sending remote loopback commands to the local processor.
+ */
+static void smp2p_ut_mock_loopback(struct seq_file *s)
+{
+	int failed = 0;
+	struct msm_smp2p_remote_mock *rmp = NULL;
+	int ret;
+	uint32_t test_request = 0;
+	uint32_t test_response = 0;
+	struct msm_smp2p_out  *local;
+
+	seq_printf(s, "Running %s\n", __func__);
+	do {
+		/* Initialize the mock edge */
+		ret = smp2p_reset_mock_edge();
+		UT_ASSERT_INT(ret, ==, 0);
+
+		rmp = msm_smp2p_get_remote_mock();
+		UT_ASSERT_PTR(rmp, !=, NULL);
+
+		memset(&rmp->remote_item, 0,
+			sizeof(struct smp2p_smem_item));
+		rmp->remote_item.header.magic = SMP2P_MAGIC;
+		SMP2P_SET_LOCAL_PID(
+		rmp->remote_item.header.rem_loc_proc_id,
+						SMP2P_REMOTE_MOCK_PROC);
+		SMP2P_SET_REMOTE_PID(
+		rmp->remote_item.header.rem_loc_proc_id,
+						SMP2P_APPS_PROC);
+		SMP2P_SET_VERSION(
+		rmp->remote_item.header.feature_version, 1);
+		SMP2P_SET_FEATURES(
+		rmp->remote_item.header.feature_version, 0);
+		SMP2P_SET_ENT_TOTAL(
+		rmp->remote_item.header.valid_total_ent, SMP2P_MAX_ENTRY);
+		SMP2P_SET_ENT_VALID(
+		rmp->remote_item.header.valid_total_ent, 1);
+		rmp->remote_item.header.reserved = 0x0;
+		msm_smp2p_set_remote_mock_exists(true);
+
+		/* Create test entry and attach loopback server */
+		rmp->rx_interrupt_count = 0;
+		INIT_COMPLETION(rmp->cb_completion);
+		strlcpy(rmp->remote_item.entries[0].name, "smp2p",
+							SMP2P_MAX_ENTRY_NAME);
+		rmp->remote_item.entries[0].entry = 0;
+		rmp->tx_interrupt();
+
+		local = msm_smp2p_init_rmt_lpb_proc(SMP2P_REMOTE_MOCK_PROC);
+		UT_ASSERT_INT(
+			(int)wait_for_completion_timeout(
+					&rmp->cb_completion, HZ / 2),
+			>, 0);
+		UT_ASSERT_INT(rmp->rx_interrupt_count, ==, 2);
+
+		/* Send Echo Command */
+		rmp->rx_interrupt_count = 0;
+		INIT_COMPLETION(rmp->cb_completion);
+		SMP2P_SET_RMT_CMD_TYPE(test_request, 1);
+		SMP2P_SET_RMT_CMD(test_request, SMP2P_LB_CMD_ECHO);
+		SMP2P_SET_RMT_DATA(test_request, 10);
+		rmp->remote_item.entries[0].entry = test_request;
+		rmp->tx_interrupt();
+		UT_ASSERT_INT(
+			(int)wait_for_completion_timeout(
+					&rmp->cb_completion, HZ / 2),
+			>, 0);
+
+		/* Verify Echo Response */
+		UT_ASSERT_INT(rmp->rx_interrupt_count, ==, 1);
+		ret = msm_smp2p_out_read(local,
+							&test_response);
+		UT_ASSERT_INT(ret, ==, 0);
+		test_response = SMP2P_GET_RMT_DATA(test_response);
+		UT_ASSERT_INT(test_response, ==, 10);
+
+		/* Send PINGPONG command */
+		test_request = 0;
+		test_response = 0;
+		rmp->rx_interrupt_count = 0;
+		INIT_COMPLETION(rmp->cb_completion);
+		SMP2P_SET_RMT_CMD_TYPE(test_request, 1);
+		SMP2P_SET_RMT_CMD(test_request, SMP2P_LB_CMD_PINGPONG);
+		SMP2P_SET_RMT_DATA(test_request, 10);
+		rmp->remote_item.entries[0].entry = test_request;
+		rmp->tx_interrupt();
+		UT_ASSERT_INT(
+			(int)wait_for_completion_timeout(
+					&rmp->cb_completion, HZ / 2),
+			>, 0);
+
+		/* Verify PINGPONG Response */
+		UT_ASSERT_INT(rmp->rx_interrupt_count, ==, 1);
+		ret = msm_smp2p_out_read(local, &test_response);
+		UT_ASSERT_INT(ret, ==, 0);
+		test_response = SMP2P_GET_RMT_DATA(test_response);
+		UT_ASSERT_INT(test_response, ==, 9);
+
+		/* Send CLEARALL command */
+		test_request = 0;
+		test_response = 0;
+		rmp->rx_interrupt_count = 0;
+		INIT_COMPLETION(rmp->cb_completion);
+		SMP2P_SET_RMT_CMD_TYPE(test_request, 1);
+		SMP2P_SET_RMT_CMD(test_request, SMP2P_LB_CMD_CLEARALL);
+		SMP2P_SET_RMT_DATA(test_request, 10);
+		rmp->remote_item.entries[0].entry = test_request;
+		rmp->tx_interrupt();
+		UT_ASSERT_INT(
+			(int)wait_for_completion_timeout(
+					&rmp->cb_completion, HZ / 2),
+			>, 0);
+
+		/* Verify CLEARALL response */
+		UT_ASSERT_INT(rmp->rx_interrupt_count, ==, 1);
+		ret = msm_smp2p_out_read(local, &test_response);
+		UT_ASSERT_INT(ret, ==, 0);
+		test_response = SMP2P_GET_RMT_DATA(test_response);
+		UT_ASSERT_INT(test_response, ==, 0);
+
+		ret = msm_smp2p_deinit_rmt_lpb_proc(SMP2P_REMOTE_MOCK_PROC);
+		UT_ASSERT_INT(ret, ==, 0);
+		seq_printf(s, "\tOK\n");
+	} while (0);
+
+	if (failed) {
+		pr_err("%s: Failed\n", __func__);
+		seq_printf(s, "\tFailed\n");
+		msm_smp2p_deinit_rmt_lpb_proc(SMP2P_REMOTE_MOCK_PROC);
+	}
+}
+
+/**
+ * smp2p_ut_remote_inout_core - Verify inbound/outbound functionality.
+ *
+ * @s: pointer to output file
+ * @remote_pid:  Remote processor to test
+ *
+ * This test verifies inbound/outbound functionality for the remote processor.
+ */
+static void smp2p_ut_remote_inout_core(struct seq_file *s, int remote_pid)
+{
+	int failed = 0;
+	struct msm_smp2p_out *handle;
+	int ret;
+	uint32_t test_request;
+	uint32_t test_response = 0;
+	static struct mock_cb_data cb_out;
+	static struct mock_cb_data cb_in;
+
+	seq_printf(s, "Running %s for '%s' remote pid %d\n",
+		   __func__, smp2p_pid_to_name(remote_pid), remote_pid);
+	mock_cb_data_init(&cb_out);
+	mock_cb_data_init(&cb_in);
+	do {
+		/* Open output entry */
+		ret = msm_smp2p_out_open(remote_pid, "smp2p",
+			&cb_out.nb, &handle);
+		UT_ASSERT_INT(ret, ==, 0);
+		UT_ASSERT_INT(
+			(int)wait_for_completion_timeout(
+					&cb_out.cb_completion, HZ / 2),
+			>, 0);
+		UT_ASSERT_INT(cb_out.cb_count, ==, 1);
+		UT_ASSERT_INT(cb_out.event_open, ==, 1);
+
+		/* Open inbound entry */
+		ret = msm_smp2p_in_register(remote_pid, "smp2p",
+				&cb_in.nb);
+		UT_ASSERT_INT(ret, ==, 0);
+		UT_ASSERT_INT(
+			(int)wait_for_completion_timeout(
+					&cb_in.cb_completion, HZ / 2),
+			>, 0);
+		UT_ASSERT_INT(cb_in.cb_count, ==, 1);
+		UT_ASSERT_INT(cb_in.event_open, ==, 1);
+
+		/* Write an echo request */
+		mock_cb_data_reset(&cb_out);
+		mock_cb_data_reset(&cb_in);
+		test_request = 0x0;
+		SMP2P_SET_RMT_CMD_TYPE(test_request, 1);
+		SMP2P_SET_RMT_CMD(test_request, SMP2P_LB_CMD_ECHO);
+		SMP2P_SET_RMT_DATA(test_request, 0xAA55);
+		ret = msm_smp2p_out_write(handle, test_request);
+		UT_ASSERT_INT(ret, ==, 0);
+
+		/* Verify inbound reply */
+		UT_ASSERT_INT(
+			(int)wait_for_completion_timeout(
+					&cb_in.cb_completion, HZ / 2),
+			>, 0);
+		UT_ASSERT_INT(cb_in.cb_count, ==, 1);
+		UT_ASSERT_INT(cb_in.event_entry_update, ==, 1);
+		UT_ASSERT_INT(SMP2P_GET_RMT_DATA(
+			    cb_in.entry_data.current_value), ==, 0xAA55);
+
+		ret = msm_smp2p_in_read(remote_pid, "smp2p", &test_response);
+		UT_ASSERT_INT(ret, ==, 0);
+		UT_ASSERT_INT(0, ==, SMP2P_GET_RMT_CMD_TYPE(test_response));
+		UT_ASSERT_INT(SMP2P_LB_CMD_ECHO, ==,
+				SMP2P_GET_RMT_CMD(test_response));
+		UT_ASSERT_INT(0xAA55, ==, SMP2P_GET_RMT_DATA(test_response));
+
+		/* Write a clear all request */
+		mock_cb_data_reset(&cb_in);
+		test_request = 0x0;
+		SMP2P_SET_RMT_CMD_TYPE(test_request, 1);
+		SMP2P_SET_RMT_CMD(test_request, SMP2P_LB_CMD_CLEARALL);
+		SMP2P_SET_RMT_DATA(test_request, 0xAA55);
+		ret = msm_smp2p_out_write(handle, test_request);
+		UT_ASSERT_INT(ret, ==, 0);
+
+		/* Verify inbound reply */
+		UT_ASSERT_INT(
+			(int)wait_for_completion_timeout(
+					&cb_in.cb_completion, HZ / 2),
+			>, 0);
+		UT_ASSERT_INT(cb_in.cb_count, ==, 1);
+		UT_ASSERT_INT(cb_in.event_entry_update, ==, 1);
+		UT_ASSERT_INT(SMP2P_GET_RMT_DATA(
+			    cb_in.entry_data.current_value), ==, 0x0000);
+
+		ret = msm_smp2p_in_read(remote_pid, "smp2p", &test_response);
+		UT_ASSERT_INT(ret, ==, 0);
+		UT_ASSERT_INT(0, ==, SMP2P_GET_RMT_CMD_TYPE(test_response));
+		UT_ASSERT_INT(0x0000, ==, SMP2P_GET_RMT_DATA(test_response));
+
+		/* Write a decrement request */
+		mock_cb_data_reset(&cb_in);
+		test_request = 0x0;
+		SMP2P_SET_RMT_CMD_TYPE(test_request, 1);
+		SMP2P_SET_RMT_CMD(test_request, SMP2P_LB_CMD_PINGPONG);
+		SMP2P_SET_RMT_DATA(test_request, 0xAA55);
+		ret = msm_smp2p_out_write(handle, test_request);
+		UT_ASSERT_INT(ret, ==, 0);
+
+		/* Verify inbound reply */
+		UT_ASSERT_INT(
+			(int)wait_for_completion_timeout(
+					&cb_in.cb_completion, HZ / 2),
+			>, 0);
+		UT_ASSERT_INT(cb_in.cb_count, ==, 1);
+		UT_ASSERT_INT(cb_in.event_entry_update, ==, 1);
+		UT_ASSERT_INT(SMP2P_GET_RMT_DATA(
+			    cb_in.entry_data.current_value), ==, 0xAA54);
+
+		ret = msm_smp2p_in_read(remote_pid, "smp2p", &test_response);
+		UT_ASSERT_INT(ret, ==, 0);
+		UT_ASSERT_INT(0, ==, SMP2P_GET_RMT_CMD_TYPE(test_response));
+		UT_ASSERT_INT(SMP2P_LB_CMD_PINGPONG, ==,
+				SMP2P_GET_RMT_CMD(test_response));
+		UT_ASSERT_INT(0xAA54, ==, SMP2P_GET_RMT_DATA(test_response));
+
+		/* Test the ignore flag */
+		mock_cb_data_reset(&cb_in);
+		test_request = 0x0;
+		SMP2P_SET_RMT_CMD_TYPE(test_request, 1);
+		SMP2P_SET_RMT_CMD(test_request, SMP2P_RLPB_IGNORE);
+		SMP2P_SET_RMT_DATA(test_request, 0xAA55);
+		ret = msm_smp2p_out_write(handle, test_request);
+		UT_ASSERT_INT(ret, ==, 0);
+
+		UT_ASSERT_INT(
+			(int)wait_for_completion_timeout(
+					&cb_in.cb_completion, HZ / 2),
+			==, 0);
+		UT_ASSERT_INT(cb_in.cb_count, ==, 0);
+		UT_ASSERT_INT(cb_in.event_entry_update, ==, 0);
+		ret = msm_smp2p_in_read(remote_pid, "smp2p", &test_response);
+		UT_ASSERT_INT(ret, ==, 0);
+		UT_ASSERT_INT(0xAA54, ==, SMP2P_GET_RMT_DATA(test_response));
+
+		/* Cleanup */
+		ret = msm_smp2p_out_close(&handle);
+		UT_ASSERT_INT(ret, ==, 0);
+		UT_ASSERT_PTR(handle, ==, 0);
+		ret = msm_smp2p_in_unregister(remote_pid, "smp2p", &cb_in.nb);
+		UT_ASSERT_INT(ret, ==, 0);
+
+		seq_printf(s, "\tOK\n");
+	} while (0);
+
+	if (failed) {
+		if (handle)
+			(void)msm_smp2p_out_close(&handle);
+		(void)msm_smp2p_in_unregister(remote_pid, "smp2p", &cb_in.nb);
+
+		pr_err("%s: Failed\n", __func__);
+		seq_printf(s, "\tFailed\n");
+	}
+}
+
+/**
+ * smp2p_ut_remote_inout - Verify inbound/outbound functionality for all.
+ *
+ * @s: pointer to output file
+ *
+ * This test verifies inbound and outbound functionality for all
+ * configured remote processor.
+ */
+static void smp2p_ut_remote_inout(struct seq_file *s)
+{
+	struct smp2p_interrupt_config *int_cfg;
+	int pid;
+
+	int_cfg = smp2p_get_interrupt_config();
+	if (!int_cfg) {
+		seq_printf(s,
+			"Remote processor config unavailable\n");
+		return;
+	}
+
+	for (pid = 0; pid < SMP2P_NUM_PROCS; ++pid) {
+		if (!int_cfg[pid].is_configured)
+			continue;
+
+		msm_smp2p_deinit_rmt_lpb_proc(pid);
+		smp2p_ut_remote_inout_core(s, pid);
+		msm_smp2p_init_rmt_lpb_proc(pid);
+	}
+}
+
+/**
+ * smp2p_ut_remote_out_max_entries_core - Verify open functionality.
+ *
+ * @s: pointer to output file
+ * @remote_pid:  Remote processor for which the test is executed.
+ *
+ * This test verifies open functionality by creating maximum outbound entries.
+ */
+static void smp2p_ut_remote_out_max_entries_core(struct seq_file *s,
+	int remote_pid)
+{
+	int j = 0;
+	int failed = 0;
+	struct msm_smp2p_out *handle[SMP2P_MAX_ENTRY];
+	int ret;
+	static struct mock_cb_data cb_out[SMP2P_MAX_ENTRY];
+	char entry_name[SMP2P_MAX_ENTRY_NAME];
+	int num_created;
+
+	seq_printf(s, "Running %s for '%s' remote pid %d\n",
+		   __func__, smp2p_pid_to_name(remote_pid), remote_pid);
+
+	for (j = 0; j < SMP2P_MAX_ENTRY; j++) {
+		handle[j] = NULL;
+		mock_cb_data_init(&cb_out[j]);
+	}
+
+	do {
+		num_created = 0;
+		for (j = 0; j < SMP2P_MAX_ENTRY; j++) {
+			/* Open as many output entries as possible */
+			scnprintf((char *)entry_name, SMP2P_MAX_ENTRY_NAME,
+				"smp2p%d", j);
+			ret = msm_smp2p_out_open(remote_pid, entry_name,
+				&cb_out[j].nb, &handle[j]);
+			if (ret == -ENOMEM)
+				/* hit max number */
+				break;
+			UT_ASSERT_INT(ret, ==, 0);
+			++num_created;
+		}
+		if (failed)
+			break;
+
+		/* verify we created more than 1 entry */
+		UT_ASSERT_INT(num_created, <=, SMP2P_MAX_ENTRY);
+		UT_ASSERT_INT(num_created, >, 0);
+
+		seq_printf(s, "\tOK\n");
+	} while (0);
+
+	if (failed) {
+		pr_err("%s: Failed\n", __func__);
+		seq_printf(s, "\tFailed\n");
+	}
+
+	/* cleanup */
+	for (j = 0; j < SMP2P_MAX_ENTRY; j++)
+		ret = msm_smp2p_out_close(&handle[j]);
+}
+
+/**
+ * smp2p_ut_remote_out_max_entries - Verify open for all configured processors.
+ *
+ * @s: pointer to output file
+ *
+ * This test verifies creating max number of entries for
+ * all configured remote processor.
+ */
+static void smp2p_ut_remote_out_max_entries(struct seq_file *s)
+{
+	struct smp2p_interrupt_config *int_cfg;
+	int pid;
+
+	int_cfg = smp2p_get_interrupt_config();
+	if (!int_cfg) {
+		seq_printf(s,
+			"Remote processor config unavailable\n");
+		return;
+	}
+
+	for (pid = 0; pid < SMP2P_NUM_PROCS; ++pid) {
+		if (!int_cfg[pid].is_configured)
+			continue;
+
+		smp2p_ut_remote_out_max_entries_core(s, pid);
+	}
+}
+
+/**
+ * smp2p_ut_local_in_max_entries - Verify registering and unregistering.
+ *
+ * @s: pointer to output file
+ *
+ * This test verifies registering and unregistering for inbound entries using
+ * the remote mock processor.
+ */
+static void smp2p_ut_local_in_max_entries(struct seq_file *s)
+{
+	int j = 0;
+	int failed = 0;
+	struct msm_smp2p_remote_mock *rmp = NULL;
+	int ret;
+	static struct mock_cb_data cb_in[SMP2P_MAX_ENTRY];
+	static struct mock_cb_data cb_out;
+
+	seq_printf(s, "Running %s\n", __func__);
+
+	for (j = 0; j < SMP2P_MAX_ENTRY; j++)
+		mock_cb_data_init(&cb_in[j]);
+
+	mock_cb_data_init(&cb_out);
+
+	do {
+		/* Initialize mock edge */
+		ret = smp2p_reset_mock_edge();
+		UT_ASSERT_INT(ret, ==, 0);
+
+		rmp = msm_smp2p_get_remote_mock();
+		UT_ASSERT_PTR(rmp, !=, NULL);
+
+		rmp->rx_interrupt_count = 0;
+		memset(&rmp->remote_item, 0,
+			sizeof(struct smp2p_smem_item));
+		rmp->remote_item.header.magic = SMP2P_MAGIC;
+		SMP2P_SET_LOCAL_PID(
+		rmp->remote_item.header.rem_loc_proc_id,
+						SMP2P_REMOTE_MOCK_PROC);
+		SMP2P_SET_REMOTE_PID(
+		rmp->remote_item.header.rem_loc_proc_id,
+						SMP2P_APPS_PROC);
+		SMP2P_SET_VERSION(
+		rmp->remote_item.header.feature_version, 1);
+		SMP2P_SET_FEATURES(
+		rmp->remote_item.header.feature_version, 0);
+		SMP2P_SET_ENT_TOTAL(
+		rmp->remote_item.header.valid_total_ent, SMP2P_MAX_ENTRY);
+		SMP2P_SET_ENT_VALID(
+		rmp->remote_item.header.valid_total_ent, 0);
+		rmp->remote_item.header.reserved = 0x0;
+		msm_smp2p_set_remote_mock_exists(true);
+
+		/* Create Max Entries in the remote mock object */
+		for (j = 0; j < SMP2P_MAX_ENTRY; j++) {
+			scnprintf(rmp->remote_item.entries[j].name,
+				SMP2P_MAX_ENTRY_NAME, "smp2p%d", j);
+			rmp->remote_item.entries[j].entry = 0;
+			rmp->tx_interrupt();
+		}
+
+		/* Register for in entries */
+		for (j = 0; j < SMP2P_MAX_ENTRY; j++) {
+			ret = msm_smp2p_in_register(SMP2P_REMOTE_MOCK_PROC,
+				rmp->remote_item.entries[j].name,
+				&(cb_in[j].nb));
+			UT_ASSERT_INT(ret, ==, 0);
+			UT_ASSERT_INT(
+				(int)wait_for_completion_timeout(
+					&(cb_in[j].cb_completion), HZ / 2),
+				>, 0);
+			UT_ASSERT_INT(cb_in[j].cb_count, ==, 1);
+			UT_ASSERT_INT(cb_in[j].event_entry_update, ==, 0);
+		}
+		UT_ASSERT_INT(j, ==, SMP2P_MAX_ENTRY);
+
+		/* Unregister */
+		for (j = 0; j < SMP2P_MAX_ENTRY; j++) {
+			ret = msm_smp2p_in_unregister(SMP2P_REMOTE_MOCK_PROC,
+				rmp->remote_item.entries[j].name,
+				&(cb_in[j].nb));
+		    UT_ASSERT_INT(ret, ==, 0);
+		}
+		UT_ASSERT_INT(j, ==, SMP2P_MAX_ENTRY);
+
+		seq_printf(s, "\tOK\n");
+	} while (0);
+
+	if (failed) {
+		pr_err("%s: Failed\n", __func__);
+		seq_printf(s, "\tFailed\n");
+
+		for (j = 0; j < SMP2P_MAX_ENTRY; j++)
+			ret = msm_smp2p_in_unregister(SMP2P_REMOTE_MOCK_PROC,
+				rmp->remote_item.entries[j].name,
+				&(cb_in[j].nb));
+	}
+}
+
+static struct dentry *dent;
+
+static int debugfs_show(struct seq_file *s, void *data)
+{
+	void (*show)(struct seq_file *) = s->private;
+
+	show(s);
+
+	return 0;
+}
+
+static int debug_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, debugfs_show, inode->i_private);
+}
+
+static const struct file_operations debug_ops = {
+	.open = debug_open,
+	.release = single_release,
+	.read = seq_read,
+	.llseek = seq_lseek,
+};
+
+void smp2p_debug_create(const char *name,
+			 void (*show)(struct seq_file *))
+{
+	struct dentry *file;
+
+	file = debugfs_create_file(name, 0444, dent, show, &debug_ops);
+	if (!file)
+		pr_err("%s: unable to create file '%s'\n", __func__, name);
+}
+
+static int __init smp2p_debugfs_init(void)
+{
+	dent = debugfs_create_dir("smp2p_test", 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.
+	 */
+	smp2p_debug_create("ut_local_basic",
+			smp2p_ut_local_basic);
+	smp2p_debug_create("ut_local_late_open",
+			smp2p_ut_local_late_open);
+	smp2p_debug_create("ut_local_early_open",
+			smp2p_ut_local_early_open);
+	smp2p_debug_create("ut_mock_loopback",
+			smp2p_ut_mock_loopback);
+	smp2p_debug_create("ut_remote_inout",
+			smp2p_ut_remote_inout);
+	smp2p_debug_create("ut_local_in_max_entries",
+		smp2p_ut_local_in_max_entries);
+	smp2p_debug_create("ut_remote_out_max_entries",
+			smp2p_ut_remote_out_max_entries);
+
+	return 0;
+}
+module_init(smp2p_debugfs_init);
diff --git a/arch/arm/mach-msm/smp2p_test_common.h b/arch/arm/mach-msm/smp2p_test_common.h
new file mode 100644
index 0000000..b9cddc4
--- /dev/null
+++ b/arch/arm/mach-msm/smp2p_test_common.h
@@ -0,0 +1,217 @@
+/* arch/arm/mach-msm/smp2p_test_common.h
+ *
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef _ARCH_ARM_MACH_MSM_SMP2P_TEST_COMMON_H_
+#define _ARCH_ARM_MACH_MSM_SMP2P_TEST_COMMON_H_
+
+#include <linux/debugfs.h>
+
+/**
+ * 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:
+ * @s - sequential output file pointer
+ * @failed - set to true if test fails
+ */
+#define UT_ASSERT_INT(a, cmp, b) \
+	{ \
+	int a_tmp = (a); \
+	int b_tmp = (b); \
+	if (!((a_tmp)cmp(b_tmp))) { \
+		seq_printf(s, \
+			"%s:%d Fail: " #a "(%d) " #cmp " " #b "(%d)\n", \
+				__func__, __LINE__, \
+				a_tmp, b_tmp); \
+		failed = 1; \
+		break; \
+	} \
+	}
+
+#define UT_ASSERT_PTR(a, cmp, b) \
+	{ \
+	void *a_tmp = (a); \
+	void *b_tmp = (b); \
+	if (!((a_tmp)cmp(b_tmp))) { \
+		seq_printf(s, \
+			"%s:%d Fail: " #a "(%p) " #cmp " " #b "(%p)\n", \
+				__func__, __LINE__, \
+				a_tmp, b_tmp); \
+		failed = 1; \
+		break; \
+	} \
+	}
+
+#define UT_ASSERT_UINT(a, cmp, b) \
+	{ \
+	unsigned a_tmp = (a); \
+	unsigned b_tmp = (b); \
+	if (!((a_tmp)cmp(b_tmp))) { \
+		seq_printf(s, \
+			"%s:%d Fail: " #a "(%u) " #cmp " " #b "(%u)\n", \
+				__func__, __LINE__, \
+				a_tmp, b_tmp); \
+		failed = 1; \
+		break; \
+	} \
+	}
+
+#define UT_ASSERT_HEX(a, cmp, b) \
+	{ \
+	unsigned a_tmp = (a); \
+	unsigned b_tmp = (b); \
+	if (!((a_tmp)cmp(b_tmp))) { \
+		seq_printf(s, \
+			"%s:%d Fail: " #a "(%x) " #cmp " " #b "(%x)\n", \
+				__func__, __LINE__, \
+				a_tmp, b_tmp); \
+		failed = 1; \
+		break; \
+	} \
+	}
+
+/**
+ * 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:
+ * @s - sequential output file pointer
+ * @failed - set to true if test fails
+ */
+#define UT_ASSERT_INT_IN_RANGE(a, minv, maxv) \
+	{ \
+	int a_tmp = (a); \
+	int minv_tmp = (minv); \
+	int maxv_tmp = (maxv); \
+	if (((a_tmp) < (minv_tmp)) || ((a_tmp) > (maxv_tmp))) { \
+		seq_printf(s, \
+			"%s:%d Fail: " #a "(%d) < " #minv "(%d) or " \
+				 #a "(%d) > " #maxv "(%d)\n", \
+				__func__, __LINE__, \
+				a_tmp, minv_tmp, a_tmp, maxv_tmp); \
+		failed = 1; \
+		break; \
+	} \
+	}
+
+/* Structure to track state changes for the notifier callback. */
+struct mock_cb_data {
+	bool initialized;
+	spinlock_t lock;
+	struct notifier_block nb;
+
+	/* events */
+	struct completion cb_completion;
+	int cb_count;
+	int event_open;
+	int event_entry_update;
+	struct msm_smp2p_update_notif entry_data;
+};
+
+void smp2p_debug_create(const char *name, void (*show)(struct seq_file *));
+static inline int smp2p_test_notify(struct notifier_block *self,
+	unsigned long event, void *data);
+
+/**
+ * Reset mock callback data to default values.
+ *
+ * @cb:  Mock callback data
+ */
+static inline void mock_cb_data_reset(struct mock_cb_data *cb)
+{
+	INIT_COMPLETION(cb->cb_completion);
+	cb->cb_count = 0;
+	cb->event_open = 0;
+	cb->event_entry_update = 0;
+	memset(&cb->entry_data, 0,
+		sizeof(struct msm_smp2p_update_notif));
+}
+
+
+/**
+ * Initialize mock callback data.
+ *
+ * @cb:  Mock callback data
+ */
+static inline void mock_cb_data_init(struct mock_cb_data *cb)
+{
+	if (!cb->initialized) {
+		init_completion(&cb->cb_completion);
+		spin_lock_init(&cb->lock);
+		cb->initialized = true;
+		cb->nb.notifier_call = smp2p_test_notify;
+		memset(&cb->entry_data, 0,
+			sizeof(struct msm_smp2p_update_notif));
+	}
+	mock_cb_data_reset(cb);
+}
+
+/**
+ * Notifier function passed into SMP2P for testing.
+ *
+ * @self:       Pointer to calling notifier block
+ * @event:	    Event
+ * @data:       Event-specific data
+ * @returns:    0
+ */
+static inline int smp2p_test_notify(struct notifier_block *self,
+		unsigned long event, void *data)
+{
+	struct mock_cb_data *cb_data_ptr;
+	unsigned long flags;
+
+	cb_data_ptr = container_of(self, struct mock_cb_data, nb);
+
+	spin_lock_irqsave(&cb_data_ptr->lock, flags);
+
+	switch (event) {
+	case SMP2P_OPEN:
+		++cb_data_ptr->event_open;
+		if (data) {
+			cb_data_ptr->entry_data =
+			*(struct msm_smp2p_update_notif *)(data);
+		}
+		break;
+	case SMP2P_ENTRY_UPDATE:
+		++cb_data_ptr->event_entry_update;
+		if (data) {
+			cb_data_ptr->entry_data =
+			*(struct msm_smp2p_update_notif *)(data);
+		}
+		break;
+	default:
+		pr_err("%s Unknown event\n", __func__);
+		break;
+	}
+
+	++cb_data_ptr->cb_count;
+	complete(&cb_data_ptr->cb_completion);
+	spin_unlock_irqrestore(&cb_data_ptr->lock, flags);
+	return 0;
+}
+#endif /* _ARCH_ARM_MACH_MSM_SMP2P_TEST_COMMON_H_ */
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index ef40743..ee459d6 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -303,8 +303,8 @@
 	/* 8092 IDs */
 	[146] = MSM_CPU_8092,
 
-	/* 8910 IDs */
-	[147] = MSM_CPU_8910,
+	/* 8610 IDs */
+	[147] = MSM_CPU_8610,
 
 	/* 8064AB IDs */
 	[153] = MSM_CPU_8064AB,
@@ -320,6 +320,8 @@
 	[169] = MSM_CPU_8625Q,
 	[170] = MSM_CPU_8625Q,
 
+	/* 8064AA IDs */
+	[172] = MSM_CPU_8064AA,
 
 	/* Uninitialized IDs are not known to run Linux.
 	   MSM_CPU_UNKNOWN is set to 0 to ensure these IDs are
@@ -814,67 +816,6 @@
 	return 0;
 }
 
-static int __init socinfo_init_sysdev(void)
-{
-	int err;
-
-	if (!socinfo) {
-		pr_err("%s: No socinfo found!\n", __func__);
-		return -ENODEV;
-	}
-
-	err = sysdev_class_register(&soc_sysdev_class);
-	if (err) {
-		pr_err("%s: sysdev_class_register fail (%d)\n",
-		       __func__, err);
-		return err;
-	}
-	err = sysdev_register(&soc_sys_device);
-	if (err) {
-		pr_err("%s: sysdev_register fail (%d)\n",
-		       __func__, err);
-		return err;
-	}
-	socinfo_create_files(&soc_sys_device, socinfo_v1_files,
-				ARRAY_SIZE(socinfo_v1_files));
-	if (socinfo->v1.format < 2)
-		return err;
-	socinfo_create_files(&soc_sys_device, socinfo_v2_files,
-				ARRAY_SIZE(socinfo_v2_files));
-
-	if (socinfo->v1.format < 3)
-		return err;
-
-	socinfo_create_files(&soc_sys_device, socinfo_v3_files,
-				ARRAY_SIZE(socinfo_v3_files));
-
-	if (socinfo->v1.format < 4)
-		return err;
-
-	socinfo_create_files(&soc_sys_device, socinfo_v4_files,
-				ARRAY_SIZE(socinfo_v4_files));
-
-	if (socinfo->v1.format < 5)
-		return err;
-
-	socinfo_create_files(&soc_sys_device, socinfo_v5_files,
-				ARRAY_SIZE(socinfo_v5_files));
-
-	if (socinfo->v1.format < 6)
-		return err;
-
-	socinfo_create_files(&soc_sys_device, socinfo_v6_files,
-				ARRAY_SIZE(socinfo_v6_files));
-
-	if (socinfo->v1.format < 7)
-		return err;
-
-	return socinfo_create_files(&soc_sys_device, socinfo_v7_files,
-				ARRAY_SIZE(socinfo_v7_files));
-}
-
-arch_initcall(socinfo_init_sysdev);
-
 static void * __init setup_dummy_socinfo(void)
 {
 	if (machine_is_msm8960_cdp())
@@ -899,9 +840,9 @@
 		dummy_socinfo.id = 146;
 		strlcpy(dummy_socinfo.build_id, "mpq8092 - ",
 		sizeof(dummy_socinfo.build_id));
-	} else if (early_machine_is_msm8910()) {
+	} else if (early_machine_is_msm8610()) {
 		dummy_socinfo.id = 147;
-		strlcpy(dummy_socinfo.build_id, "msm8910 - ",
+		strlcpy(dummy_socinfo.build_id, "msm8610 - ",
 			sizeof(dummy_socinfo.build_id));
 	}
 	strlcat(dummy_socinfo.build_id, "Dummy socinfo",
@@ -964,6 +905,88 @@
 
 }
 
+static int __init socinfo_init_sysdev(void)
+{
+	int err;
+	struct device *msm_soc_device;
+	struct soc_device *soc_dev;
+	struct soc_device_attribute *soc_dev_attr;
+
+	if (!socinfo) {
+		pr_err("%s: No socinfo found!\n", __func__);
+		return -ENODEV;
+	}
+
+	soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
+	if (!soc_dev_attr) {
+		pr_err("%s: Soc Device alloc failed!\n", __func__);
+		return -ENOMEM;
+	}
+
+	soc_info_populate(soc_dev_attr);
+	soc_dev = soc_device_register(soc_dev_attr);
+	if (IS_ERR_OR_NULL(soc_dev)) {
+		kfree(soc_dev_attr);
+		 pr_err("%s: Soc device register failed\n", __func__);
+		 return -EIO;
+	}
+
+	msm_soc_device = soc_device_to_device(soc_dev);
+	populate_soc_sysfs_files(msm_soc_device);
+	err = sysdev_class_register(&soc_sysdev_class);
+	if (err) {
+		pr_err("%s: sysdev_class_register fail (%d)\n",
+		       __func__, err);
+		return err;
+	}
+	err = sysdev_register(&soc_sys_device);
+	if (err) {
+		pr_err("%s: sysdev_register fail (%d)\n",
+		       __func__, err);
+		return err;
+	}
+	socinfo_create_files(&soc_sys_device, socinfo_v1_files,
+				ARRAY_SIZE(socinfo_v1_files));
+	if (socinfo->v1.format < 2)
+		return err;
+	socinfo_create_files(&soc_sys_device, socinfo_v2_files,
+				ARRAY_SIZE(socinfo_v2_files));
+
+	if (socinfo->v1.format < 3)
+		return err;
+
+	socinfo_create_files(&soc_sys_device, socinfo_v3_files,
+				ARRAY_SIZE(socinfo_v3_files));
+
+	if (socinfo->v1.format < 4)
+		return err;
+
+	socinfo_create_files(&soc_sys_device, socinfo_v4_files,
+				ARRAY_SIZE(socinfo_v4_files));
+
+	if (socinfo->v1.format < 5)
+		return err;
+
+	socinfo_create_files(&soc_sys_device, socinfo_v5_files,
+				ARRAY_SIZE(socinfo_v5_files));
+
+	if (socinfo->v1.format < 6)
+		return err;
+
+	socinfo_create_files(&soc_sys_device, socinfo_v6_files,
+				ARRAY_SIZE(socinfo_v6_files));
+
+	if (socinfo->v1.format < 7)
+		return err;
+
+	socinfo_create_files(&soc_sys_device, socinfo_v7_files,
+				ARRAY_SIZE(socinfo_v7_files));
+
+	return 0;
+}
+
+arch_initcall(socinfo_init_sysdev);
+
 static void socinfo_print(void)
 {
 	switch (socinfo->v1.format) {
@@ -1043,12 +1066,8 @@
 	}
 }
 
-struct device *  __init socinfo_init(void)
+int __init socinfo_init(void)
 {
-	struct device *msm_soc_device;
-	struct soc_device *soc_dev;
-	struct soc_device_attribute *soc_dev_attr;
-
 	socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID, sizeof(struct socinfo_v7));
 
 	if (!socinfo)
@@ -1089,21 +1108,8 @@
 		cur_cpu = cpu_of_id[socinfo->v1.id];
 
 	socinfo_print();
-	soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
-	if (!soc_dev_attr)
-		return ERR_PTR(-ENOMEM);
 
-	soc_info_populate(soc_dev_attr);
-	soc_dev = soc_device_register(soc_dev_attr);
-	if (IS_ERR_OR_NULL(soc_dev)) {
-		kfree(soc_dev_attr);
-		return ERR_PTR(-EIO);
-	}
-
-	msm_soc_device = soc_device_to_device(soc_dev);
-	populate_soc_sysfs_files(msm_soc_device);
-
-	return msm_soc_device;
+	return 0;
 }
 
 const int get_core_count(void)
diff --git a/arch/arm/mach-msm/test-lpm.c b/arch/arm/mach-msm/test-lpm.c
index dbc8100..031b2dc 100644
--- a/arch/arm/mach-msm/test-lpm.c
+++ b/arch/arm/mach-msm/test-lpm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -26,6 +26,9 @@
 #if defined(CONFIG_MSM_RPM)
 #include "rpm_resources.h"
 #endif
+#if defined(CONFIG_MSM_RPM_SMD)
+#include "lpm_resources.h"
+#endif
 #include "timer.h"
 #include "test-lpm.h"
 
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 79f20a4..0d5ad6a 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -81,7 +81,6 @@
 #define SMD_DATA_TYPE 0
 #define SMD_CNTL_TYPE 1
 #define SMD_DCI_TYPE 2
-#define MAX_PROC	10
 
 /* Maximum number of pkt reg supported at initialization*/
 extern unsigned int diag_max_reg;
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 564e085..d2454f4 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -80,9 +80,6 @@
     means that the diag packet has a delayed response. */
 static uint16_t delayed_rsp_id = 1;
 
-/* Array of valid token ids */
-static int token_list[MAX_PROC] = {0, -1, -2, -3, -4, -5, -6, -7, -8, -9};
-
 #define DIAGPKT_MAX_DELAYED_RSP 0xFFFF
 
 /* returns the next delayed rsp id - rollsover the id if wrapping is
@@ -384,10 +381,13 @@
 {
 	uint16_t remote_dev = 0;
 
+	/* Check for MDM processor */
 	if (driver->hsic_inited)
-		remote_dev |= (1 << 0);
+		remote_dev |= 1 << 0;
+
+	/* Check for QSC processor */
 	if (driver->diag_smux_enabled)
-		remote_dev |= (1 << 1);
+		remote_dev |= 1 << 1;
 
 	return remote_dev;
 }
@@ -395,15 +395,22 @@
 inline uint16_t diag_get_remote_device_mask(void) { return 0; }
 #endif
 
-static int diag_get_token(int token)
+static int diag_get_remote(int remote_info)
 {
-	int i;
+	int val = (remote_info < 0) ? -remote_info : remote_info;
+	int remote_val;
 
-	for (i = 0; i < MAX_PROC; i++)
-		if (token_list[i] == token)
-			return 1 << i;
+	switch (val) {
+	case MDM:
+	case QSC:
+		remote_val = -remote_info;
+		break;
+	default:
+		remote_val = 0;
+		break;
+	}
 
-	return 0;
+	return remote_val;
 }
 
 long diagchar_ioctl(struct file *filp,
@@ -811,6 +818,7 @@
 	struct diag_dci_client_tbl *entry;
 	int index = -1, i = 0, ret = 0;
 	int num_data = 0, data_type;
+	int remote_token;
 
 	for (i = 0; i < driver->num_clients; i++)
 		if (driver->client_map[i].pid == current->tgid)
@@ -831,7 +839,7 @@
 		unsigned long spin_lock_flags;
 		struct diag_write_device hsic_buf_tbl[NUM_HSIC_BUF_TBL_ENTRIES];
 #endif
-
+		remote_token = 0;
 		pr_debug("diag: process woken up\n");
 		/*Copy the type of data being passed*/
 		data_type = driver->data_ready[index] & USER_SPACE_DATA_TYPE;
@@ -907,9 +915,12 @@
 #ifdef CONFIG_DIAG_SDIO_PIPE
 		/* copy 9K data over SDIO */
 		if (driver->in_busy_sdio == 1) {
+			remote_token = diag_get_remote(MDM);
 			num_data++;
-			/*Copy the negative  token of data being passed*/
-			COPY_USER_SPACE_OR_EXIT(buf+ret, token_list[MDM], 4);
+
+			/*Copy the negative token of data being passed*/
+			COPY_USER_SPACE_OR_EXIT(buf+ret,
+						remote_token, 4);
 			/*Copy the length of data being passed*/
 			COPY_USER_SPACE_OR_EXIT(buf+ret,
 				 (driver->write_ptr_mdm->length), 4);
@@ -933,6 +944,7 @@
 		spin_unlock_irqrestore(&driver->hsic_spinlock,
 					spin_lock_flags);
 
+		remote_token = diag_get_remote(MDM);
 		for (i = 0; i < driver->poolsize_hsic_write; i++) {
 			if (hsic_buf_tbl[i].length > 0) {
 				pr_debug("diag: HSIC copy to user, i: %d, buf: %x, len: %d\n",
@@ -941,8 +953,8 @@
 				num_data++;
 
 				/* Copy the negative token */
-				if (copy_to_user(buf+ret, &token_list[MDM],
-									4)) {
+				if (copy_to_user(buf+ret,
+						&remote_token, 4)) {
 					num_data--;
 					goto drop_hsic;
 				}
@@ -977,10 +989,12 @@
 			}
 		}
 		if (driver->in_busy_smux == 1) {
+			remote_token = diag_get_remote(QSC);
 			num_data++;
 
 			/* Copy the negative  token of data being passed */
-			COPY_USER_SPACE_OR_EXIT(buf+ret, token_list[QSC], 4);
+			COPY_USER_SPACE_OR_EXIT(buf+ret,
+						remote_token, 4);
 			/* Copy the length of data being passed */
 			COPY_USER_SPACE_OR_EXIT(buf+ret,
 					(driver->write_ptr_mdm->length), 4);
@@ -1142,7 +1156,7 @@
 		err = copy_from_user(driver->user_space_data, buf + 4,
 							 payload_size);
 		/* Check for proc_type */
-		remote_proc = diag_get_token(*(int *)driver->user_space_data);
+		remote_proc = diag_get_remote(*(int *)driver->user_space_data);
 
 		if (remote_proc) {
 			token_offset = 4;
@@ -1167,7 +1181,7 @@
 #endif
 #ifdef CONFIG_DIAG_SDIO_PIPE
 		/* send masks to 9k too */
-		if (driver->sdio_ch && (remote_proc & MDM)) {
+		if (driver->sdio_ch && (remote_proc == MDM)) {
 			wait_event_interruptible(driver->wait_q,
 				 (sdio_write_avail(driver->sdio_ch) >=
 					 payload_size));
@@ -1181,7 +1195,7 @@
 #ifdef CONFIG_DIAGFWD_BRIDGE_CODE
 		/* send masks to 9k too */
 		if (driver->hsic_ch && (payload_size > 0) &&
-						(remote_proc & MDM)) {
+						(remote_proc == MDM)) {
 			/* wait sending mask updates if HSIC ch not ready */
 			if (driver->in_busy_hsic_write)
 				wait_event_interruptible(driver->wait_q,
@@ -1204,7 +1218,7 @@
 					driver->in_busy_hsic_write = 0;
 			}
 		}
-		if (driver->diag_smux_enabled && (remote_proc & QSC)
+		if (driver->diag_smux_enabled && (remote_proc == QSC)
 						&& driver->lcid) {
 			if (payload_size > 0) {
 				err = msm_smux_write(driver->lcid, NULL,
diff --git a/drivers/coresight/coresight-tmc.c b/drivers/coresight/coresight-tmc.c
index 09cda5d..d49652f 100644
--- a/drivers/coresight/coresight-tmc.c
+++ b/drivers/coresight/coresight-tmc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -26,6 +26,7 @@
 #include <linux/delay.h>
 #include <linux/spinlock.h>
 #include <linux/clk.h>
+#include <linux/of.h>
 #include <linux/of_coresight.h>
 #include <linux/coresight.h>
 #include <linux/usb/usb_qdss.h>
@@ -1111,10 +1112,18 @@
 	devid = tmc_readl(drvdata, CORESIGHT_DEVID);
 	drvdata->config_type = BMVAL(devid, 6, 7);
 
-	if (drvdata->config_type == TMC_CONFIG_TYPE_ETR)
-		drvdata->size = SZ_1M;
-	else
+	if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
+		if (pdev->dev.of_node) {
+			ret = of_property_read_u32(pdev->dev.of_node,
+				"qcom,memory-reservation-size", &drvdata->size);
+			if (ret) {
+				clk_disable_unprepare(drvdata->clk);
+				return ret;
+			}
+		}
+	} else {
 		drvdata->size = tmc_readl(drvdata, TMC_RSZ) * BYTES_PER_WORD;
+	}
 
 	clk_disable_unprepare(drvdata->clk);
 
diff --git a/drivers/coresight/coresight.c b/drivers/coresight/coresight.c
index 3974f2e..39bc9ff 100644
--- a/drivers/coresight/coresight.c
+++ b/drivers/coresight/coresight.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -566,6 +566,9 @@
 	struct coresight_device *csdev;
 	struct coresight_connection *conns;
 
+	if (IS_ERR_OR_NULL(desc))
+		return ERR_PTR(-EINVAL);
+
 	csdev = kzalloc(sizeof(*csdev), GFP_KERNEL);
 	if (!csdev) {
 		ret = -ENOMEM;
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c
index d605a61..ab9e83a 100644
--- a/drivers/crypto/msm/qce50.c
+++ b/drivers/crypto/msm/qce50.c
@@ -1,6 +1,6 @@
 /* Qualcomm Crypto Engine driver.
  *
- * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2012-2013, 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
@@ -1248,8 +1248,27 @@
 			notify->data.transfer.iovec.addr,
 			notify->data.transfer.iovec.size,
 			notify->data.transfer.iovec.flags);
-	/* done */
-	_aead_complete(pce_dev);
+
+	if (pce_dev->ce_sps.producer_state == QCE_PIPE_STATE_COMP) {
+		pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_IDLE;
+		/* done */
+		_aead_complete(pce_dev);
+	} else {
+		int rc = 0;
+		pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_COMP;
+		pce_dev->ce_sps.out_transfer.iovec_count = 0;
+		_qce_sps_add_data(GET_PHYS_ADDR(pce_dev->ce_sps.result_dump),
+					CRYPTO_RESULT_DUMP_SIZE,
+					  &pce_dev->ce_sps.out_transfer);
+		_qce_set_flag(&pce_dev->ce_sps.out_transfer,
+				SPS_IOVEC_FLAG_EOT|SPS_IOVEC_FLAG_INT);
+		rc = sps_transfer(pce_dev->ce_sps.producer.pipe,
+					  &pce_dev->ce_sps.out_transfer);
+		if (rc) {
+			pr_err("sps_xfr() fail (producer pipe=0x%x) rc = %d,",
+				(u32)pce_dev->ce_sps.producer.pipe, rc);
+		}
+	}
 };
 
 static void _aead_sps_consumer_callback(struct sps_event_notify *notify)
@@ -1304,8 +1323,27 @@
 			notify->data.transfer.iovec.addr,
 			notify->data.transfer.iovec.size,
 			notify->data.transfer.iovec.flags);
-	/* done */
-	_ablk_cipher_complete(pce_dev);
+
+	if (pce_dev->ce_sps.producer_state == QCE_PIPE_STATE_COMP) {
+		pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_IDLE;
+		/* done */
+		_ablk_cipher_complete(pce_dev);
+	} else {
+		int rc = 0;
+		pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_COMP;
+		pce_dev->ce_sps.out_transfer.iovec_count = 0;
+		_qce_sps_add_data(GET_PHYS_ADDR(pce_dev->ce_sps.result_dump),
+					CRYPTO_RESULT_DUMP_SIZE,
+					  &pce_dev->ce_sps.out_transfer);
+		_qce_set_flag(&pce_dev->ce_sps.out_transfer,
+				SPS_IOVEC_FLAG_EOT|SPS_IOVEC_FLAG_INT);
+		rc = sps_transfer(pce_dev->ce_sps.producer.pipe,
+					  &pce_dev->ce_sps.out_transfer);
+		if (rc) {
+			pr_err("sps_xfr() fail (producer pipe=0x%x) rc = %d,",
+				(u32)pce_dev->ce_sps.producer.pipe, rc);
+		}
+	}
 };
 
 static void _ablk_cipher_sps_consumer_callback(struct sps_event_notify *notify)
@@ -2255,7 +2293,6 @@
 		pr_err("Producer callback registration failed rc = %d\n", rc);
 		goto bad;
 	}
-
 	/* Register callback event for EOT (End of transfer) event. */
 	pce_dev->ce_sps.consumer.event.callback = _aead_sps_consumer_callback;
 	rc = sps_register_event(pce_dev->ce_sps.consumer.pipe,
@@ -2280,11 +2317,21 @@
 		_qce_sps_add_sg_data(pce_dev, areq->dst, out_len +
 					areq->assoclen + hw_pad_out,
 				&pce_dev->ce_sps.out_transfer);
-		_qce_sps_add_data(GET_PHYS_ADDR(pce_dev->ce_sps.result_dump),
+		if (totallen_in > SPS_MAX_PKT_SIZE) {
+			_qce_set_flag(&pce_dev->ce_sps.out_transfer,
+							SPS_IOVEC_FLAG_INT);
+			pce_dev->ce_sps.producer.event.options =
+							SPS_O_DESC_DONE;
+			pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_IDLE;
+		} else {
+			_qce_sps_add_data(GET_PHYS_ADDR(
+					pce_dev->ce_sps.result_dump),
 					CRYPTO_RESULT_DUMP_SIZE,
-					&pce_dev->ce_sps.out_transfer);
-		_qce_set_flag(&pce_dev->ce_sps.out_transfer,
-					SPS_IOVEC_FLAG_INT);
+					  &pce_dev->ce_sps.out_transfer);
+			_qce_set_flag(&pce_dev->ce_sps.out_transfer,
+							SPS_IOVEC_FLAG_INT);
+			pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_COMP;
+		}
 	} else {
 		_qce_sps_add_sg_data(pce_dev, areq->assoc, areq->assoclen,
 					 &pce_dev->ce_sps.in_transfer);
@@ -2304,11 +2351,21 @@
 		/* Pass through to ignore hw_pad (padding of the MAC data) */
 		_qce_sps_add_data(GET_PHYS_ADDR(pce_dev->ce_sps.ignore_buffer),
 				hw_pad_out, &pce_dev->ce_sps.out_transfer);
-
-		_qce_sps_add_data(GET_PHYS_ADDR(pce_dev->ce_sps.result_dump),
-			CRYPTO_RESULT_DUMP_SIZE, &pce_dev->ce_sps.out_transfer);
-		_qce_set_flag(&pce_dev->ce_sps.out_transfer,
-					SPS_IOVEC_FLAG_INT);
+		if (totallen_in > SPS_MAX_PKT_SIZE) {
+			_qce_set_flag(&pce_dev->ce_sps.out_transfer,
+							SPS_IOVEC_FLAG_INT);
+			pce_dev->ce_sps.producer.event.options =
+							SPS_O_DESC_DONE;
+			pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_IDLE;
+		} else {
+			_qce_sps_add_data(
+				GET_PHYS_ADDR(pce_dev->ce_sps.result_dump),
+					CRYPTO_RESULT_DUMP_SIZE,
+					  &pce_dev->ce_sps.out_transfer);
+			_qce_set_flag(&pce_dev->ce_sps.out_transfer,
+							SPS_IOVEC_FLAG_INT);
+			pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_COMP;
+		}
 	}
 	rc = _qce_sps_transfer(pce_dev);
 	if (rc)
@@ -2392,7 +2449,6 @@
 		pr_err("Producer callback registration failed rc = %d\n", rc);
 		goto bad;
 	}
-
 	/* Register callback event for EOT (End of transfer) event. */
 	pce_dev->ce_sps.consumer.event.callback =
 			_ablk_cipher_sps_consumer_callback;
@@ -2414,10 +2470,19 @@
 
 	_qce_sps_add_sg_data(pce_dev, areq->dst, areq->nbytes,
 					&pce_dev->ce_sps.out_transfer);
-	_qce_sps_add_data(GET_PHYS_ADDR(pce_dev->ce_sps.result_dump),
+	if (areq->nbytes > SPS_MAX_PKT_SIZE) {
+		_qce_set_flag(&pce_dev->ce_sps.out_transfer,
+							SPS_IOVEC_FLAG_INT);
+		pce_dev->ce_sps.producer.event.options = SPS_O_DESC_DONE;
+		pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_IDLE;
+	} else {
+		pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_COMP;
+		_qce_sps_add_data(GET_PHYS_ADDR(pce_dev->ce_sps.result_dump),
 					CRYPTO_RESULT_DUMP_SIZE,
 					  &pce_dev->ce_sps.out_transfer);
-	_qce_set_flag(&pce_dev->ce_sps.out_transfer, SPS_IOVEC_FLAG_INT);
+		_qce_set_flag(&pce_dev->ce_sps.out_transfer,
+							SPS_IOVEC_FLAG_INT);
+	}
 	rc = _qce_sps_transfer(pce_dev);
 	if (rc)
 		goto bad;
diff --git a/drivers/gpu/msm/a3xx_reg.h b/drivers/gpu/msm/a3xx_reg.h
index 90f14e6..4a47c59 100644
--- a/drivers/gpu/msm/a3xx_reg.h
+++ b/drivers/gpu/msm/a3xx_reg.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -67,6 +67,10 @@
 #define A3XX_RBBM_INT_0_STATUS 0x064
 #define A3XX_RBBM_PERFCTR_CTL 0x80
 #define A3XX_RBBM_GPU_BUSY_MASKED 0x88
+#define A3XX_RBBM_PERFCTR_SP_5_LO 0xDC
+#define A3XX_RBBM_PERFCTR_SP_5_HI 0xDD
+#define A3XX_RBBM_PERFCTR_SP_6_LO 0xDE
+#define A3XX_RBBM_PERFCTR_SP_6_HI 0xDF
 #define A3XX_RBBM_PERFCTR_SP_7_LO 0xE0
 #define A3XX_RBBM_PERFCTR_SP_7_HI 0xE1
 #define A3XX_RBBM_RBBM_CTL 0x100
@@ -164,6 +168,8 @@
 #define A3XX_VPC_VPC_DEBUG_RAM_READ 0xE62
 #define A3XX_UCHE_CACHE_MODE_CONTROL_REG 0xE82
 #define A3XX_UCHE_CACHE_INVALIDATE0_REG 0xEA0
+#define A3XX_SP_PERFCOUNTER5_SELECT 0xEC9
+#define A3XX_SP_PERFCOUNTER6_SELECT 0xECA
 #define A3XX_SP_PERFCOUNTER7_SELECT 0xECB
 #define A3XX_GRAS_CL_CLIP_CNTL 0x2040
 #define A3XX_GRAS_CL_GB_CLIP_ADJ 0x2044
@@ -539,5 +545,8 @@
 
 /* COUNTABLE FOR SP PERFCOUNTER */
 #define SP_FS_FULL_ALU_INSTRUCTIONS    0x0E
+#define SP_ALU_ACTIVE_CYCLES           0x1D
+#define SP0_ICL1_MISSES                0x1A
+#define SP_FS_CFLOW_INSTRUCTIONS       0x0C
 
 #endif
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index d581578..5c98599 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -130,6 +130,10 @@
 	REG_CP_IB2_BASE,
 	REG_CP_IB2_BUFSZ,
 	0,
+	0,
+	0,
+	0,
+	0,
 	0
 };
 
@@ -304,6 +308,8 @@
 	num_iommu_units = kgsl_mmu_get_num_iommu_units(&device->mmu);
 
 	context = idr_find(&device->context_idr, context_id);
+	if (context == NULL)
+		return;
 	adreno_ctx = context->devctxt;
 
 	if (kgsl_mmu_enable_clk(&device->mmu,
@@ -454,6 +460,8 @@
 	 */
 	if (!kgsl_cff_dump_enable && adreno_dev->drawctxt_active) {
 		context = idr_find(&device->context_idr, context_id);
+		if (context == NULL)
+			return;
 		adreno_ctx = context->devctxt;
 
 		if (flags & KGSL_MMUFLAGS_PTUPDATE) {
@@ -1271,6 +1279,10 @@
 	if (adreno_is_a3xx(adreno_dev)) {
 		hang_detect_regs[6] = A3XX_RBBM_PERFCTR_SP_7_LO;
 		hang_detect_regs[7] = A3XX_RBBM_PERFCTR_SP_7_HI;
+		hang_detect_regs[8] = A3XX_RBBM_PERFCTR_SP_6_LO;
+		hang_detect_regs[9] = A3XX_RBBM_PERFCTR_SP_6_HI;
+		hang_detect_regs[10] = A3XX_RBBM_PERFCTR_SP_5_LO;
+		hang_detect_regs[11] = A3XX_RBBM_PERFCTR_SP_5_HI;
 	}
 
 	status = kgsl_mmu_start(device);
@@ -1805,6 +1817,7 @@
 				unsigned int sizebytes)
 {
 	int status = -EINVAL;
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 
 	switch (type) {
 	case KGSL_PROP_PWRCTRL: {
@@ -1824,10 +1837,11 @@
 			if (enable) {
 				if (pdata->nap_allowed)
 					device->pwrctrl.nap_allowed = true;
-
+				adreno_dev->fast_hang_detect = 1;
 				kgsl_pwrscale_enable(device);
 			} else {
 				device->pwrctrl.nap_allowed = false;
+				adreno_dev->fast_hang_detect = 0;
 				kgsl_pwrscale_disable(device);
 			}
 
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index 2466a5c..c408f1b 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -2873,12 +2873,22 @@
 	adreno_regwrite(device, A3XX_RBBM_PERFCTR_CTL, 0x01);
 
 	/*
-	 * Set SP perfcounter 7 to count SP_FS_FULL_ALU_INSTRUCTIONS
+	 * Set SP perfcounter 5 to count SP_ALU_ACTIVE_CYCLES, it includes
+	 * all ALU instruction execution regardless precision or shader ID.
+	 * Set SP perfcounter 6 to count SP0_ICL1_MISSES, It counts
+	 * USP L1 instruction miss request.
+	 * Set SP perfcounter 7 to count SP_FS_FULL_ALU_INSTRUCTIONS, it
+	 * counts USP flow control instruction execution.
 	 * we will use this to augment our hang detection
 	 */
-
-	adreno_regwrite(device, A3XX_SP_PERFCOUNTER7_SELECT,
-		SP_FS_FULL_ALU_INSTRUCTIONS);
+	if (adreno_dev->fast_hang_detect) {
+		adreno_regwrite(device, A3XX_SP_PERFCOUNTER5_SELECT,
+			SP_ALU_ACTIVE_CYCLES);
+		adreno_regwrite(device, A3XX_SP_PERFCOUNTER6_SELECT,
+			SP0_ICL1_MISSES);
+		adreno_regwrite(device, A3XX_SP_PERFCOUNTER7_SELECT,
+			SP_FS_CFLOW_INSTRUCTIONS);
+	}
 }
 
 /* Defined in adreno_a3xx_snapshot.c */
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 557ce23..65598ba 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -26,7 +26,7 @@
 
 #define KGSL_TIMEOUT_NONE       0
 #define KGSL_TIMEOUT_DEFAULT    0xFFFFFFFF
-#define KGSL_TIMEOUT_PART       2000 /* 2 sec */
+#define KGSL_TIMEOUT_PART       50 /* 50 msec */
 
 #define FIRST_TIMEOUT (HZ / 2)
 
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 8311a2d..10f8ae1 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -1003,7 +1003,7 @@
 	}
 
 	/* Set the CPU latency to 501usec to allow low latency PC modes */
-	pwr->pm_qos_latency = 501;
+	pwr->pm_qos_latency = 3;
 
 	pm_runtime_enable(device->parentdev);
 	register_early_suspend(&device->display_off);
diff --git a/drivers/media/dvb/dvb-core/demux.h b/drivers/media/dvb/dvb-core/demux.h
index 042ba37..844c65f 100644
--- a/drivers/media/dvb/dvb-core/demux.h
+++ b/drivers/media/dvb/dvb-core/demux.h
@@ -7,7 +7,7 @@
  * Copyright (c) 2000 Nokia Research Center
  *                    Tampere, FINLAND
  *
- * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public License
@@ -100,6 +100,9 @@
 			int disc_indicator_set;
 			int pes_length_mismatch;
 			u64 stc;
+			u32 tei_counter;
+			u32 cont_err_counter;
+			u32 ts_packets_num;
 		} pes_end;
 
 		struct {
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index f5a505c..bddbb5f 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -1861,6 +1861,9 @@
 
 			event.params.pes.flags = 0;
 			event.params.pes.stc = 0;
+			event.params.pes.transport_error_indicator_counter = 0;
+			event.params.pes.continuity_error_counter = 0;
+			event.params.pes.ts_packets_num = 0;
 
 			dvb_dmxdev_add_event(events, &event);
 			events->current_event_data_size = 0;
@@ -2109,6 +2112,13 @@
 					DMX_FILTER_PES_LENGTH_ERROR;
 
 			event.params.pes.stc = dmx_data_ready->pes_end.stc;
+			event.params.pes.transport_error_indicator_counter =
+				dmx_data_ready->pes_end.tei_counter;
+			event.params.pes.continuity_error_counter =
+				dmx_data_ready->pes_end.cont_err_counter;
+			event.params.pes.ts_packets_num =
+				dmx_data_ready->pes_end.ts_packets_num;
+
 			dvb_dmxdev_add_event(events, &event);
 
 			events->current_event_data_size = 0;
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index eea83c2..488f42c 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -5,7 +5,7 @@
  *		       & Marcus Metzler <marcus@convergence.de>
  *			 for convergence integrated media GmbH
  *
- * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public License
@@ -127,15 +127,15 @@
 {
 	int count = payload(buf);
 	int p;
-	//int ccok;
-	//u8 cc;
+	int ccok;
+	u8 cc;
+	struct dmx_data_ready data;
 
 	if (count == 0)
 		return -1;
 
 	p = 188 - count;
 
-	/*
 	cc = buf[3] & 0x0f;
 	if (feed->first_cc)
 		ccok = 1;
@@ -144,26 +144,41 @@
 
 	feed->first_cc = 0;
 	feed->cc = cc;
-	if (!ccok)
-		printk("missed packet!\n");
-	*/
 
 	/* PUSI ? */
 	if (buf[1] & 0x40) {
-		if (feed->pusi_seen)
+		if (feed->pusi_seen) {
 			/* We had seen PUSI before, this means
 			 * that previous PES can be closed now.
 			 */
-			feed->cb.ts(NULL, 0, NULL, 0,
-						&feed->feed.ts, DMX_OK_PES_END);
+			data.status = DMX_OK_PES_END;
+			data.data_length = 0;
+			data.pes_end.start_gap = 0;
+			data.pes_end.actual_length = feed->peslen;
+			data.pes_end.disc_indicator_set = 0;
+			data.pes_end.pes_length_mismatch = 0;
+			data.pes_end.stc = 0;
+			data.pes_end.tei_counter = feed->pes_tei_counter;
+			data.pes_end.cont_err_counter =
+				feed->pes_cont_err_counter;
+			data.pes_end.ts_packets_num = feed->pes_ts_packets_num;
+			feed->data_ready_cb.ts(&feed->feed.ts, &data);
+		}
 
 		feed->pusi_seen = 1;
 		feed->peslen = 0;
+		feed->pes_tei_counter = 0;
+		feed->pes_ts_packets_num = 0;
+		feed->pes_cont_err_counter = 0;
 	}
 
 	if (feed->pusi_seen == 0)
 		return 0;
 
+	feed->pes_ts_packets_num++;
+	feed->pes_cont_err_counter += !ccok;
+	feed->pes_tei_counter += (buf[1] & 0x80) ? 1 : 0;
+
 	feed->peslen += count;
 
 	return feed->cb.ts(&buf[p], count, NULL, 0, &feed->feed.ts, DMX_OK);
@@ -1243,6 +1258,9 @@
 	feed->demux = demux;
 	feed->pid = 0xffff;
 	feed->peslen = 0;
+	feed->pes_tei_counter = 0;
+	feed->pes_ts_packets_num = 0;
+	feed->pes_cont_err_counter = 0;
 	feed->buffer = NULL;
 	feed->tsp_out_format = DMX_TSP_FORMAT_188;
 	memset(&feed->indexing_params, 0,
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.h b/drivers/media/dvb/dvb-core/dvb_demux.h
index 2e4a468..5e98ea1 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.h
+++ b/drivers/media/dvb/dvb-core/dvb_demux.h
@@ -4,7 +4,7 @@
  * Copyright (C) 2000-2001 Marcus Metzler & Ralph Metzler
  *                         for convergence integrated media GmbH
  *
- * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public License
@@ -105,6 +105,9 @@
 	int pusi_seen;		/* prevents feeding of garbage from previous section */
 
 	u32 peslen;
+	u32 pes_tei_counter;
+	u32 pes_cont_err_counter;
+	u32 pes_ts_packets_num;
 
 	struct list_head list_head;
 	unsigned int index;	/* a unique index for each feed (can be used as hardware pid filter index) */
diff --git a/drivers/media/video/msm_vidc/hfi_packetization.c b/drivers/media/video/msm_vidc/hfi_packetization.c
index 4d3d07d..06e230d 100644
--- a/drivers/media/video/msm_vidc/hfi_packetization.c
+++ b/drivers/media/video/msm_vidc/hfi_packetization.c
@@ -1104,3 +1104,36 @@
 	}
 	return rc;
 }
+
+static int get_hfi_ssr_type(enum hal_ssr_trigger_type type)
+{
+	int rc = HFI_TEST_SSR_HW_WDOG_IRQ;
+	switch (type) {
+	case SSR_ERR_FATAL:
+		rc = HFI_TEST_SSR_SW_ERR_FATAL;
+		break;
+	case SSR_SW_DIV_BY_ZERO:
+		rc = HFI_TEST_SSR_SW_DIV_BY_ZERO;
+		break;
+	case SSR_HW_WDOG_IRQ:
+		rc = HFI_TEST_SSR_HW_WDOG_IRQ;
+		break;
+	default:
+		dprintk(VIDC_WARN,
+			"SSR trigger type not recognized, using WDOG.\n");
+	}
+	return rc;
+}
+
+int create_pkt_ssr_cmd(enum hal_ssr_trigger_type type,
+		struct hfi_cmd_sys_test_ssr_packet *pkt)
+{
+	if (!pkt) {
+		dprintk(VIDC_ERR, "Invalid params, device: %p\n", pkt);
+		return -EINVAL;
+	}
+	pkt->size = sizeof(struct hfi_cmd_sys_test_ssr_packet);
+	pkt->packet_type = HFI_CMD_SYS_TEST_SSR;
+	pkt->trigger_type = get_hfi_ssr_type(type);
+	return 0;
+}
diff --git a/drivers/media/video/msm_vidc/hfi_packetization.h b/drivers/media/video/msm_vidc/hfi_packetization.h
index a3edc7c..b2c6e08 100644
--- a/drivers/media/video/msm_vidc/hfi_packetization.h
+++ b/drivers/media/video/msm_vidc/hfi_packetization.h
@@ -79,5 +79,6 @@
 		struct hfi_cmd_session_set_property_packet *pkt,
 		u32 session_id, enum hal_property ptype, void *pdata);
 
+int create_pkt_ssr_cmd(enum hal_ssr_trigger_type type,
+		struct hfi_cmd_sys_test_ssr_packet *pkt);
 #endif
-
diff --git a/drivers/media/video/msm_vidc/hfi_response_handler.c b/drivers/media/video/msm_vidc/hfi_response_handler.c
index 23829e5..cedd789 100644
--- a/drivers/media/video/msm_vidc/hfi_response_handler.c
+++ b/drivers/media/video/msm_vidc/hfi_response_handler.c
@@ -650,8 +650,8 @@
 		data_done.output_done.offset1 = pkt->offset;
 		data_done.output_done.frame_width = pkt->frame_width;
 		data_done.output_done.frame_height = pkt->frame_height;
-		data_done.output_done.start_xCoord = pkt->start_x_coord;
-		data_done.output_done.start_yCoord = pkt->start_y_coord;
+		data_done.output_done.start_x_coord = pkt->start_x_coord;
+		data_done.output_done.start_y_coord = pkt->start_y_coord;
 		data_done.output_done.input_tag1 = pkt->input_tag;
 		data_done.output_done.picture_type = pkt->picture_type;
 		data_done.output_done.packet_buffer1 = pkt->packet_buffer;
diff --git a/drivers/media/video/msm_vidc/msm_venc.c b/drivers/media/video/msm_vidc/msm_venc.c
index 0326c79..05d3570 100644
--- a/drivers/media/video/msm_vidc/msm_venc.c
+++ b/drivers/media/video/msm_vidc/msm_venc.c
@@ -390,10 +390,16 @@
 		.name = "Slice Mode",
 		.type = V4L2_CTRL_TYPE_MENU,
 		.minimum = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE,
-		.maximum = V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES,
+		.maximum = V4L2_MPEG_VIDEO_MULTI_SLICE_GOB,
 		.default_value = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE,
 		.step = 1,
-		.menu_skip_mask = 0,
+		.menu_skip_mask = ~(
+		(1 << V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE) |
+		(1 << V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) |
+		(1 << V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) |
+		(1 << V4L2_MPEG_VIDEO_MULTI_SLICE_GOB)
+		),
+		.qmenu = NULL,
 		.cluster = MSM_VENC_CTRL_CLUSTER_SLICING,
 	},
 	{
@@ -421,6 +427,18 @@
 		.cluster = MSM_VENC_CTRL_CLUSTER_SLICING,
 	},
 	{
+		.id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_GOB,
+		.name = "Slice GOB",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = MAX_SLICE_MB_SIZE,
+		.default_value = 1,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+		.cluster = MSM_VENC_CTRL_CLUSTER_SLICING,
+	},
+	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE,
 		.name = "Intra Refresh Mode",
 		.type = V4L2_CTRL_TYPE_MENU,
@@ -1281,6 +1299,9 @@
 		case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES:
 			temp = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES;
 			break;
+		case V4L2_MPEG_VIDEO_MULTI_SLICE_GOB:
+			temp = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_GOB;
+			break;
 		case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE:
 		default:
 			temp = 0;
@@ -1300,6 +1321,7 @@
 	}
 	case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:
 	case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:
+	case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_GOB:
 		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE);
 
 		property_id =
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.c b/drivers/media/video/msm_vidc/msm_vidc_common.c
index 955f4ca..7e8732a 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.c
@@ -422,6 +422,9 @@
 			inst->buff_req.buffer[i].buffer_count_actual,
 			inst->buff_req.buffer[i].buffer_size);
 	}
+	dprintk(VIDC_PROF, "Input buffers: %d, Output buffers: %d\n",
+			inst->buff_req.buffer[0].buffer_count_actual,
+			inst->buff_req.buffer[1].buffer_count_actual);
 	signal_session_msg_receipt(cmd, inst);
 }
 
@@ -716,8 +719,13 @@
 		(u32)fill_buf_done->packet_buffer1);
 	if (vb) {
 		vb->v4l2_planes[0].bytesused = fill_buf_done->filled_len1;
+		vb->v4l2_planes[0].reserved[2] = fill_buf_done->start_x_coord;
+		vb->v4l2_planes[0].reserved[3] = fill_buf_done->start_y_coord;
+		vb->v4l2_planes[0].reserved[4] = fill_buf_done->frame_width;
+		vb->v4l2_planes[0].reserved[5] = fill_buf_done->frame_height;
 		if (!(fill_buf_done->flags1 &
-			HAL_BUFFERFLAG_TIMESTAMPINVALID)) {
+			HAL_BUFFERFLAG_TIMESTAMPINVALID) &&
+			fill_buf_done->filled_len1) {
 			int64_t time_usec = fill_buf_done->timestamp_hi;
 			time_usec = (time_usec << 32) |
 				fill_buf_done->timestamp_lo;
@@ -1100,7 +1108,8 @@
 	}
 	msm_comm_scale_clocks_and_bus(inst);
 	if (list_empty(&core->instances)) {
-		msm_comm_unset_ocmem(core);
+		if (inst->state != MSM_VIDC_CORE_INVALID)
+			msm_comm_unset_ocmem(core);
 		hdev->free_ocmem(hdev->hfi_device_data);
 		dprintk(VIDC_DBG, "Calling vidc_hal_core_release\n");
 		rc = hdev->core_release(hdev->hfi_device_data);
@@ -2100,7 +2109,7 @@
 	op_flush = flags & V4L2_QCOM_CMD_FLUSH_CAPTURE;
 
 	if (ip_flush && !op_flush) {
-		dprintk(VIDC_WARN, "Input only flush not supported\n");
+		dprintk(VIDC_INFO, "Input only flush not supported\n");
 		return 0;
 	}
 	if (inst->state == MSM_VIDC_CORE_INVALID ||
@@ -2206,3 +2215,18 @@
 	}
 	return ret;
 };
+
+int msm_vidc_trigger_ssr(struct msm_vidc_core *core,
+	enum hal_ssr_trigger_type type)
+{
+	int rc = 0;
+	struct hfi_device *hdev;
+	if (!core && !core->device) {
+		dprintk(VIDC_WARN, "Invalid parameters: %p\n", core);
+		return -EINVAL;
+	}
+	hdev = core->device;
+	if (core->state == VIDC_CORE_INIT_DONE)
+		rc = hdev->core_trigger_ssr(hdev->hfi_device_data, type);
+	return rc;
+}
diff --git a/drivers/media/video/msm_vidc/msm_vidc_debug.c b/drivers/media/video/msm_vidc/msm_vidc_debug.c
index ff829d7..65a518f 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_debug.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_debug.c
@@ -87,6 +87,33 @@
 	.read = core_info_read,
 };
 
+static int trigger_ssr_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t trigger_ssr_write(struct file *filp, const char __user *buf,
+		size_t count, loff_t *ppos) {
+	u32 ssr_trigger_val;
+	int rc;
+	struct msm_vidc_core *core = filp->private_data;
+	rc = sscanf(buf, "%d", &ssr_trigger_val);
+	if (rc < 0) {
+		dprintk(VIDC_WARN, "returning error err %d\n", rc);
+		rc = -EINVAL;
+	} else {
+		msm_vidc_trigger_ssr(core, ssr_trigger_val);
+		rc = count;
+	}
+	return rc;
+}
+
+static const struct file_operations ssr_fops = {
+	.open = trigger_ssr_open,
+	.write = trigger_ssr_write,
+};
+
 struct dentry *msm_vidc_debugfs_init_core(struct msm_vidc_core *core,
 		struct dentry *parent)
 {
@@ -117,6 +144,11 @@
 		dprintk(VIDC_ERR, "debugfs_create_file: fail\n");
 		goto failed_create_dir;
 	}
+	if (!debugfs_create_file("trigger_ssr", S_IWUSR,
+			dir, core, &ssr_fops)) {
+		dprintk(VIDC_ERR, "debugfs_create_file: fail\n");
+		goto failed_create_dir;
+	}
 failed_create_dir:
 	return dir;
 }
@@ -165,6 +197,10 @@
 		completion_done(&inst->completions[SESSION_MSG_INDEX(i)]) ?
 		"pending" : "done");
 	}
+	write_str(&dbg_buf, "ETB Count: %d\n", inst->count.etb);
+	write_str(&dbg_buf, "EBD Count: %d\n", inst->count.ebd);
+	write_str(&dbg_buf, "FTB Count: %d\n", inst->count.ftb);
+	write_str(&dbg_buf, "FBD Count: %d\n", inst->count.fbd);
 	return simple_read_from_buffer(buf, count, ppos,
 		dbg_buf.ptr, dbg_buf.filled_size);
 }
@@ -213,8 +249,12 @@
 	break;
 	case MSM_VIDC_DEBUGFS_EVENT_EBD:
 		inst->count.ebd++;
-		if (inst->count.ebd && inst->count.ebd == inst->count.etb)
+		if (inst->count.ebd && inst->count.ebd == inst->count.etb) {
 			toc(inst, FRAME_PROCESSING);
+			dprintk(VIDC_PROF, "EBD: FW needs input buffers\n");
+		}
+		if (inst->count.ftb == inst->count.fbd)
+			dprintk(VIDC_PROF, "EBD: FW needs output buffers\n");
 	break;
 	case MSM_VIDC_DEBUGFS_EVENT_FTB: {
 		inst->count.ftb++;
@@ -226,8 +266,12 @@
 	break;
 	case MSM_VIDC_DEBUGFS_EVENT_FBD:
 		inst->debug.samples++;
-		if (inst->count.ebd && inst->count.fbd == inst->count.ftb)
+		if (inst->count.ebd && inst->count.fbd == inst->count.ftb) {
 			toc(inst, FRAME_PROCESSING);
+			dprintk(VIDC_PROF, "FBD: FW needs output buffers\n");
+		}
+		if (inst->count.etb == inst->count.ebd)
+			dprintk(VIDC_PROF, "FBD: FW needs input buffers\n");
 		break;
 	default:
 		dprintk(VIDC_ERR, "Invalid state in debugfs: %d\n", e);
diff --git a/drivers/media/video/msm_vidc/msm_vidc_internal.h b/drivers/media/video/msm_vidc/msm_vidc_internal.h
index 52c1de8..16bf753 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_internal.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_internal.h
@@ -237,4 +237,6 @@
 };
 
 void handle_cmd_response(enum command_response cmd, void *data);
+int msm_vidc_trigger_ssr(struct msm_vidc_core *core,
+	enum hal_ssr_trigger_type type);
 #endif
diff --git a/drivers/media/video/msm_vidc/venus_hfi.c b/drivers/media/video/msm_vidc/venus_hfi.c
index 015ed11..0cd6b9f 100644
--- a/drivers/media/video/msm_vidc/venus_hfi.c
+++ b/drivers/media/video/msm_vidc/venus_hfi.c
@@ -1224,7 +1224,9 @@
 	if (dev->hal_client) {
 		venus_hfi_write_register(dev->hal_data->register_base_addr,
 				VIDC_CPU_CS_SCIACMDARG3, 0, 0);
-		disable_irq_nosync(dev->hal_data->irq);
+		if (!(dev->intr_status & VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK))
+			disable_irq_nosync(dev->hal_data->irq);
+		dev->intr_status = 0;
 		venus_hfi_interface_queues_release(dev);
 	}
 	dprintk(VIDC_INFO, "HAL exited\n");
@@ -1369,6 +1371,33 @@
 	return rc;
 }
 
+static int venus_hfi_core_trigger_ssr(void *device,
+	enum hal_ssr_trigger_type type)
+{
+	struct hfi_cmd_sys_test_ssr_packet pkt;
+	int rc = 0;
+	struct venus_hfi_device *dev;
+
+	if (device) {
+		dev = device;
+	} else {
+		dprintk(VIDC_ERR, "invalid device");
+		return -ENODEV;
+	}
+
+	rc = create_pkt_ssr_cmd(type, &pkt);
+	if (rc) {
+		dprintk(VIDC_ERR, "core_ping: failed to create packet");
+		goto err_create_pkt;
+	}
+
+	if (venus_hfi_iface_cmdq_write(dev, &pkt))
+		rc = -ENOTEMPTY;
+
+err_create_pkt:
+	return rc;
+}
+
 static int venus_hfi_session_set_property(void *sess,
 					enum hal_property ptype, void *pdata)
 {
@@ -1940,7 +1969,6 @@
 				struct venus_hfi_device *device)
 {
 	struct msm_vidc_cb_cmd_done cmd_done;
-	device->intr_status &= ~VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK;
 	memset(&cmd_done, 0, sizeof(struct msm_vidc_cb_cmd_done));
 	cmd_done.device_id = device->device_id;
 	device->callback(SYS_WATCHDOG_TIMEOUT, &cmd_done);
@@ -1987,7 +2015,8 @@
 	}
 	venus_hfi_core_clear_interrupt(device);
 	venus_hfi_response_handler(device);
-	enable_irq(device->hal_data->irq);
+	if (!(device->intr_status & VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK))
+		enable_irq(device->hal_data->irq);
 }
 static DECLARE_WORK(venus_hfi_work, venus_hfi_core_work_handler);
 
@@ -2190,7 +2219,7 @@
 			break;
 		ret = table[i].freq;
 	}
-	dprintk(VIDC_DBG, "Required clock rate = %lu\n", ret);
+	dprintk(VIDC_PROF, "Required clock rate = %lu\n", ret);
 	return ret;
 }
 
@@ -2402,14 +2431,14 @@
 static int venus_hfi_get_bus_vector(int load)
 {
 	int num_rows = sizeof(venus_hfi_bus_table)/(sizeof(u32));
-	int i;
+	int i, j;
 	for (i = 0; i < num_rows; i++) {
 		if (load <= venus_hfi_bus_table[i])
 			break;
 	}
-	i++;
-	dprintk(VIDC_DBG, "Required bus = %d\n", i);
-	return i;
+	j = clamp(i, 0, num_rows-1) + 1;
+	dprintk(VIDC_DBG, "Required bus = %d\n", j);
+	return j;
 }
 
 static int venus_hfi_scale_bus(void *dev, int load,
@@ -2975,6 +3004,7 @@
 	hdev->core_release = venus_hfi_core_release;
 	hdev->core_pc_prep = venus_hfi_core_pc_prep;
 	hdev->core_ping = venus_hfi_core_ping;
+	hdev->core_trigger_ssr = venus_hfi_core_trigger_ssr;
 	hdev->session_init = venus_hfi_session_init;
 	hdev->session_end = venus_hfi_session_end;
 	hdev->session_abort = venus_hfi_session_abort;
diff --git a/drivers/media/video/msm_vidc/vidc_hfi_api.h b/drivers/media/video/msm_vidc/vidc_hfi_api.h
index 370785c..e12153a 100644
--- a/drivers/media/video/msm_vidc/vidc_hfi_api.h
+++ b/drivers/media/video/msm_vidc/vidc_hfi_api.h
@@ -407,6 +407,12 @@
 	HAL_UNUSED_COLOR = 0x10000000,
 };
 
+enum hal_ssr_trigger_type {
+	SSR_ERR_FATAL = 1,
+	SSR_SW_DIV_BY_ZERO,
+	SSR_HW_WDOG_IRQ,
+};
+
 struct hal_uncompressed_format_select {
 	enum hal_buffer buffer_type;
 	enum hal_uncompressed_format format;
@@ -924,8 +930,8 @@
 	u32 offset1;
 	u32 frame_width;
 	u32 frame_height;
-	u32 start_xCoord;
-	u32 start_yCoord;
+	u32 start_x_coord;
+	u32 start_y_coord;
 	u32 input_tag;
 	u32 input_tag1;
 	enum hal_picture picture_type;
@@ -1009,6 +1015,7 @@
 	int (*core_release)(void *device);
 	int (*core_pc_prep)(void *device);
 	int (*core_ping)(void *device);
+	int (*core_trigger_ssr)(void *device, enum hal_ssr_trigger_type);
 	void *(*session_init)(void *device, u32 session_id,
 		enum hal_domain session_type, enum hal_video_codec codec_type);
 	int (*session_end)(void *session);
diff --git a/drivers/media/video/msm_vidc/vidc_hfi_helper.h b/drivers/media/video/msm_vidc/vidc_hfi_helper.h
index 7531811..37c051e 100644
--- a/drivers/media/video/msm_vidc/vidc_hfi_helper.h
+++ b/drivers/media/video/msm_vidc/vidc_hfi_helper.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -685,6 +685,11 @@
 #define HFI_MSG_SESSION_GET_SEQUENCE_HEADER_DONE	\
 	(HFI_MSG_SESSION_COMMON_START + 0x2)
 
+#define  HFI_CMD_SYS_TEST_SSR	(HFI_CMD_SYS_TEST_START + 0x1)
+#define HFI_TEST_SSR_SW_ERR_FATAL	0x1
+#define HFI_TEST_SSR_SW_DIV_BY_ZERO	0x2
+#define HFI_TEST_SSR_HW_WDOG_IRQ	0x3
+
 struct vidc_hal_msg_pkt_hdr {
 	u32 size;
 	u32 packet;
@@ -871,4 +876,10 @@
 	u8 rg_data[1];
 };
 
+struct hfi_cmd_sys_test_ssr_packet {
+	u32 size;
+	u32 packet_type;
+	u32 trigger_type;
+};
+
 #endif
diff --git a/drivers/media/video/msmb/isp/msm_buf_mgr.h b/drivers/media/video/msmb/isp/msm_buf_mgr.h
index a44b5ec..b96d9fe 100644
--- a/drivers/media/video/msmb/isp/msm_buf_mgr.h
+++ b/drivers/media/video/msmb/isp/msm_buf_mgr.h
@@ -17,9 +17,8 @@
 #include <mach/iommu_domains.h>
 #include "msm_sd.h"
 
-#define BUF_SRC_SHIFT 16
 /*Buffer source can be from userspace / HAL*/
-#define BUF_SRC(id) (id >> BUF_SRC_SHIFT)
+#define BUF_SRC(id) (id & ISP_NATIVE_BUF_BIT)
 
 struct msm_isp_buf_mgr;
 
diff --git a/drivers/media/video/msmb/isp/msm_isp.h b/drivers/media/video/msmb/isp/msm_isp.h
index c320a1a..1c82f45 100644
--- a/drivers/media/video/msmb/isp/msm_isp.h
+++ b/drivers/media/video/msmb/isp/msm_isp.h
@@ -132,6 +132,10 @@
 	int (*get_platform_data) (struct vfe_device *vfe_dev);
 };
 struct msm_vfe_stats_ops {
+	void (*cfg_framedrop) (struct vfe_device *vfe_dev,
+		struct msm_vfe_stats_stream *stream_info);
+	void (*clear_framedrop) (struct vfe_device *vfe_dev,
+		struct msm_vfe_stats_stream *stream_info);
 	void (*cfg_comp_mask) (struct vfe_device *vfe_dev,
 		struct msm_vfe_stats_stream *stream_info);
 	void (*clear_comp_mask) (struct vfe_device *vfe_dev,
@@ -142,7 +146,7 @@
 		struct msm_vfe_stats_stream *stream_info);
 
 	void (*cfg_wm_reg) (struct vfe_device *vfe_dev,
-		struct msm_vfe_stats_stream_request_cmd *stream_cfg_cmd);
+		struct msm_vfe_stats_stream *stream_info);
 	void (*clear_wm_reg) (struct vfe_device *vfe_dev,
 		struct msm_vfe_stats_stream *stream_info);
 
@@ -158,6 +162,10 @@
 	uint32_t (*get_frame_id) (struct vfe_device *vfe_dev);
 	uint32_t (*get_wm_mask) (uint32_t irq_status0, uint32_t irq_status1);
 	uint32_t (*get_comp_mask) (uint32_t irq_status0, uint32_t irq_status1);
+	uint32_t (*get_pingpong_status) (struct vfe_device *vfe_dev);
+	uint32_t (*get_active_pingpong_idx) (uint32_t pingpong_status,
+				enum msm_isp_stats_type stats_type);
+
 };
 
 struct msm_vfe_ops {
@@ -180,6 +188,7 @@
 	uint8_t num_rdi_master;
 	uint8_t num_comp_mask;
 	uint32_t min_wm_ub;
+	uint8_t num_stats_comp_mask;
 };
 
 enum msm_vfe_axi_state {
@@ -241,23 +250,33 @@
 	enum msm_vfe_inputmux input_mux;
 };
 
-
+enum msm_vfe_stats_state {
+	STATE_AVALIABLE,
+	STATE_INACTIVE,
+	STATE_ACTIVE,
+	STATE_START_PENDING,
+	STATE_STOP_PENDING,
+	STATE_STOPPING,
+};
 struct msm_vfe_stats_stream {
 	uint32_t frame_id;
 	uint8_t enable;
 	enum msm_isp_stats_type stats_type;
-	uint8_t comp_mask_index;
+	int8_t comp_mask_index;
 	struct msm_isp_buffer *buf[2];
 	uint32_t session_id;
 	uint32_t stream_id;
 	uint32_t bufq_handle;
 	uint32_t stream_handle;
 	uint32_t framedrop_pattern;
+	uint8_t comp_flag;
+	uint8_t comp_idx;
+	enum msm_vfe_stats_state state;
 };
 
 struct msm_vfe_stats_composite_info {
-	uint32_t stream_handle;
-	uint32_t stream_composite_mask;
+	uint32_t stats_mask;
+	uint8_t comp_flag;
 };
 
 enum msm_wm_ub_cfg_type {
@@ -288,7 +307,7 @@
 struct msm_vfe_stats_shared_data {
 	struct msm_vfe_stats_stream stream_info[MSM_ISP_STATS_MAX];
 	struct msm_vfe_stats_composite_info
-		comp_info[MAX_NUM_STATS_COMP_MASK];
+		composite_info[MAX_NUM_STATS_COMP_MASK];
 	uint8_t num_active_stream;
 	uint8_t num_used_composite_mask;
 	uint16_t stream_handle_cnt;
diff --git a/drivers/media/video/msmb/isp/msm_isp32.c b/drivers/media/video/msmb/isp/msm_isp32.c
index d7b62d1..d8ac4e0 100644
--- a/drivers/media/video/msmb/isp/msm_isp32.c
+++ b/drivers/media/video/msmb/isp/msm_isp32.c
@@ -530,7 +530,7 @@
 	/*WR_BUFFER_CFG*/
 	val =
 		msm_isp_cal_word_per_line(stream_cfg_cmd->output_format,
-		  stream_cfg_cmd->plane_cfg[plane_idx].output_width) << 16 |
+		  stream_cfg_cmd->plane_cfg[plane_idx].output_stride) << 16 |
 		(stream_cfg_cmd->plane_cfg[
 			plane_idx].output_scan_lines - 1) << 4 |
 		VFE32_BURST_LEN >> 2;
@@ -599,8 +599,8 @@
 	switch (stream_cfg_cmd->stream_src) {
 	case PIX_ENCODER:
 	case PIX_VIEWFINDER: {
-		if (plane_cfg->output_plane_format
-			!= CRCB_PLANE) {
+		if (plane_cfg->output_plane_format != CRCB_PLANE &&
+			plane_cfg->output_plane_format != CBCR_PLANE) {
 			/*SINGLE_STREAM_SEL*/
 			xbar_cfg |= plane_cfg->output_plane_format << 5;
 		} else {
diff --git a/drivers/media/video/msmb/isp/msm_isp40.c b/drivers/media/video/msmb/isp/msm_isp40.c
index 47abcef..6c90763 100644
--- a/drivers/media/video/msmb/isp/msm_isp40.c
+++ b/drivers/media/video/msmb/isp/msm_isp40.c
@@ -668,7 +668,7 @@
 	val =
 		msm_isp_cal_word_per_line(stream_cfg_cmd->output_format,
 		stream_cfg_cmd->plane_cfg[
-			plane_idx].output_width) << 16 |
+			plane_idx].output_stride) << 16 |
 		(stream_cfg_cmd->plane_cfg[
 			plane_idx].output_scan_lines - 1) << 4 |
 		VFE40_BURST_LEN >> 2;
@@ -750,8 +750,8 @@
 	switch (stream_cfg_cmd->stream_src) {
 	case PIX_ENCODER:
 	case PIX_VIEWFINDER: {
-		if (plane_cfg->output_plane_format
-				!= CRCB_PLANE) {
+		if (plane_cfg->output_plane_format != CRCB_PLANE &&
+			plane_cfg->output_plane_format != CBCR_PLANE) {
 			/*SINGLE_STREAM_SEL*/
 			xbar_cfg |= plane_cfg->output_plane_format << 8;
 		} else {
@@ -862,7 +862,7 @@
 static void msm_vfe40_cfg_axi_ub(struct vfe_device *vfe_dev)
 {
 	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
-
+	axi_data->wm_ub_cfg_policy = MSM_WM_UB_EQUAL_SLICING;
 	if (axi_data->wm_ub_cfg_policy == MSM_WM_UB_EQUAL_SLICING)
 		msm_vfe40_cfg_axi_ub_equal_slicing(vfe_dev);
 	else
@@ -937,7 +937,7 @@
 
 static void msm_vfe40_stats_cfg_wm_reg(
 	struct vfe_device *vfe_dev,
-	struct msm_vfe_stats_stream_request_cmd *stream_cfg_cmd)
+	struct msm_vfe_stats_stream *stream_info)
 {
 
 }
@@ -984,6 +984,56 @@
 {
 	return vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id;
 }
+
+static uint32_t msm_vfe40_stats_get_active_pingpong_idx(
+	uint32_t pingpong_status,
+	enum msm_isp_stats_type stats_type)
+{
+	int pingpong_bit = 0;
+	switch (stats_type) {
+	case MSM_ISP_STATS_AWB:
+		if (pingpong_status & (1 << 11))
+			pingpong_bit = 1; /* pong is active */
+			break;
+	case MSM_ISP_STATS_RS:
+		if (pingpong_status & (1 << 12))
+			pingpong_bit = 1; /* pong is active */
+			break;
+	case MSM_ISP_STATS_CS:
+		if (pingpong_status & (1 << 13))
+			pingpong_bit = 1; /* pong is active */
+			break;
+	case MSM_ISP_STATS_IHIST:
+		if (pingpong_status & (1 << 14))
+			pingpong_bit = 1; /* pong is active */
+			break;
+	case MSM_ISP_STATS_BG:
+		if (pingpong_status & (1 << 9))
+			pingpong_bit = 1; /* pong is active */
+			break;
+	case MSM_ISP_STATS_BF:
+		if (pingpong_status & (1 << 10))
+			pingpong_bit = 1; /* pong is active */
+			break;
+	case MSM_ISP_STATS_BE:
+		if (pingpong_status & (1 << 8))
+			pingpong_bit = 1; /* pong is active */
+			break;
+	case MSM_ISP_STATS_BHIST:
+		if (pingpong_status & (1 << 15))
+			pingpong_bit = 1; /* pong is active */
+			break;
+	case MSM_ISP_STATS_SKIN:
+	case MSM_ISP_STATS_AEC:
+	case MSM_ISP_STATS_AF:
+	default:
+		pr_err("%s: not supported stats type = %d\n",
+			__func__, stats_type);
+		return -EINVAL;
+	}
+	return pingpong_bit;
+}
+
 static int msm_vfe40_get_platform_data(struct vfe_device *vfe_dev)
 {
 	int rc = 0;
@@ -1041,6 +1091,7 @@
 	.num_rdi = 3,
 	.num_rdi_master = 3,
 	.min_wm_ub = 64,
+	.num_stats_comp_mask = 2,
 };
 
 static struct v4l2_subdev_core_ops msm_vfe40_subdev_core_ops = {
@@ -1118,6 +1169,9 @@
 			.get_comp_mask = msm_vfe40_stats_get_comp_mask,
 			.get_wm_mask = msm_vfe40_stats_get_wm_mask,
 			.get_frame_id = msm_vfe40_stats_get_frame_id,
+			.get_pingpong_status = msm_vfe40_get_pingpong_status,
+			.get_active_pingpong_idx =
+				msm_vfe40_stats_get_active_pingpong_idx,
 		},
 	},
 	.axi_hw_info = &msm_vfe40_axi_hw_info,
diff --git a/drivers/media/video/msmb/isp/msm_isp_axi_util.c b/drivers/media/video/msmb/isp/msm_isp_axi_util.c
index fe55b40..7e62071 100644
--- a/drivers/media/video/msmb/isp/msm_isp_axi_util.c
+++ b/drivers/media/video/msmb/isp/msm_isp_axi_util.c
@@ -637,7 +637,6 @@
 		complete(&vfe_dev->stream_config_complete);
 	}
 }
-
 #define VFE_PING_FLAG 0xFFFFFFFF
 #define VFE_PONG_FLAG 0x0
 
@@ -687,7 +686,7 @@
 		vfe_dev, stream_info->wm[i],
 		pingpong_status, buf->mapped_info[i].paddr);
 
-	if (stream_info->buf[pingpong_bit]) {
+	if (stream_info->buf[pingpong_bit] && tv) {
 		if (stream_info->buf_divert) {
 			buf_event.frame_id = stream_info->frame_id;
 			buf_event.timestamp = *tv;
diff --git a/drivers/media/video/msmb/isp/msm_isp_stats_util.c b/drivers/media/video/msmb/isp/msm_isp_stats_util.c
index 15f4c23..86a4a3d 100644
--- a/drivers/media/video/msmb/isp/msm_isp_stats_util.c
+++ b/drivers/media/video/msmb/isp/msm_isp_stats_util.c
@@ -13,6 +13,41 @@
 #include <media/v4l2-subdev.h>
 #include "msm_isp_util.h"
 #include "msm_isp_stats_util.h"
+#define VFE_PING_ACTIVE_FLAG 0xFFFFFFFF
+#define VFE_PONG_ACTIVE_FLAG 0x0
+
+int msm_isp_stats_cfg_ping_pong_address(struct vfe_device *vfe_dev,
+	struct msm_vfe_stats_stream *stream_info, uint32_t pingpong_status,
+	struct msm_isp_buffer *out_buf)
+{
+	int rc = -1;
+	struct msm_isp_buffer *buf;
+	int active_bit = 0;
+	int buf_idx;
+	uint32_t bufq_handle = stream_info->bufq_handle;
+
+	out_buf = NULL;
+	active_bit = vfe_dev->hw_info->vfe_ops.stats_ops.
+		get_active_pingpong_idx(pingpong_status,
+			stream_info->stats_type);
+	buf_idx = active_bit^0x1;
+
+	rc = vfe_dev->buf_mgr->ops->get_buf(
+		vfe_dev->buf_mgr, bufq_handle, &buf);
+	if (rc < 0) {
+		pr_err("%s: No free buffer, stats_type = %d\n",
+			__func__, stream_info->stats_type);
+		return rc;
+	}
+	vfe_dev->hw_info->vfe_ops.stats_ops.update_ping_pong_addr(
+		vfe_dev, stream_info->stats_type,
+		pingpong_status, buf->mapped_info[buf_idx].paddr);
+
+	if (stream_info->buf[buf_idx])
+		out_buf = stream_info->buf[buf_idx];
+	stream_info->buf[buf_idx] = buf;
+	return 0;
+}
 
 void msm_isp_process_stats_irq(struct vfe_device *vfe_dev,
 	uint32_t irq_status0, uint32_t irq_status1,
@@ -22,7 +57,7 @@
 	uint32_t stats_comp_mask = 0, stats_mask = 0;
 	ISP_DBG("%s: status: 0x%x\n", __func__, irq_status0);
 	stats_comp_mask = vfe_dev->hw_info->vfe_ops.stats_ops.
-	get_comp_mask(irq_status0, irq_status1);
+		get_comp_mask(irq_status0, irq_status1);
 	stats_mask = vfe_dev->hw_info->vfe_ops.stats_ops.
 		get_wm_mask(irq_status0, irq_status1);
 	if (!(stats_comp_mask || stats_mask))
@@ -31,10 +66,100 @@
 	/* TD: process comp/non comp stats */
 }
 
+static int msm_isp_stats_reserve_comp_mask(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_stats_shared_data *stats_data,
+	struct msm_vfe_stats_stream *stream_info)
+{
+	int i;
+	uint8_t num_stats_comp;
+	int8_t comp_idx = -1;
+	if (stream_info->comp_flag == 0)
+		return 0;
+
+	num_stats_comp = vfe_dev->axi_data.hw_info->num_stats_comp_mask;
+	for (i = 0; i < num_stats_comp; i++) {
+		if (!stats_data->composite_info[i].stats_mask == 0 &&
+				comp_idx < 0)
+			comp_idx = i;
+		if (stats_data->composite_info[i].comp_flag ==
+				stream_info->comp_flag) {
+			comp_idx = i;
+			break;
+		}
+	}
+	if (comp_idx < 0) {
+		pr_err("%s: no more stats comp idx\n", __func__);
+		return -EACCES;
+	}
+	stats_data->composite_info[comp_idx].stats_mask |=
+		(1 << stream_info->stats_type);
+	if (stats_data->composite_info[comp_idx].comp_flag == 0)
+		stats_data->composite_info[comp_idx].comp_flag =
+			stream_info->comp_flag;
+	stream_info->comp_idx = comp_idx;
+	return 0;
+}
+
+static int msm_isp_stats_unreserve_comp_mask(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_stats_shared_data *stats_data,
+	struct msm_vfe_stats_stream *stream_info)
+{
+	uint8_t comp_idx = stream_info->comp_idx;
+
+	if (stream_info->comp_flag == 0)
+		return 0;
+	stats_data->composite_info[comp_idx].stats_mask &=
+		~(1 << stream_info->stats_type);
+	if (stats_data->composite_info[comp_idx].stats_mask == 0)
+		memset(&stats_data->composite_info[comp_idx], 0,
+			sizeof(struct msm_vfe_stats_composite_info));
+	return 0;
+}
+
 int msm_isp_request_stats_stream(struct vfe_device *vfe_dev, void *arg)
 {
 	int rc = 0;
-	/*To Do*/
+	struct msm_vfe_stats_stream_request_cmd *stream_cfg_cmd = arg;
+	struct msm_vfe_stats_stream *stream_info = NULL;
+	struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data;
+
+	if (stream_cfg_cmd->stats_type < MSM_ISP_STATS_AEC ||
+			stream_cfg_cmd->stats_type >= MSM_ISP_STATS_MAX) {
+		pr_err("%s: invalid stats type %d received\n",
+		__func__, stream_cfg_cmd->stats_type);
+		return -EINVAL;
+	}
+	stream_info = &stats_data->stream_info[stream_cfg_cmd->stats_type];
+	if (stream_info->stream_handle != 0) {
+		pr_err("%s: stats type %d has been used already\n",
+			__func__, stream_cfg_cmd->stats_type);
+			return -EBUSY;
+	}
+
+	stats_data->stream_handle_cnt++;
+	if (stats_data->stream_handle_cnt == 0)
+		stats_data->stream_handle_cnt++;
+	stream_info->stream_handle =
+		stats_data->stream_handle_cnt << 16 |
+			stream_cfg_cmd->stats_type;
+	stream_info->enable = 0;
+	stream_info->stats_type = stream_cfg_cmd->stats_type;
+	stream_info->comp_flag = stream_cfg_cmd->comp_flag;
+	stream_info->session_id = stream_cfg_cmd->session_id;
+	stream_info->stream_id = stream_cfg_cmd->stream_id;
+	stream_info->framedrop_pattern = stream_cfg_cmd->framedrop_pattern;
+	stream_cfg_cmd->stream_handle =	stream_info->stream_handle;
+	msm_isp_stats_reserve_comp_mask(vfe_dev, stats_data, stream_info);
+	if (stream_info->comp_flag)
+		vfe_dev->hw_info->vfe_ops.stats_ops.
+			cfg_comp_mask(vfe_dev, stream_info);
+	else
+		vfe_dev->hw_info->vfe_ops.stats_ops.
+			cfg_wm_irq_mask(vfe_dev, stream_info);
+	vfe_dev->hw_info->vfe_ops.stats_ops.
+		cfg_wm_reg(vfe_dev, stream_info);
 	return rc;
 }
 
@@ -45,25 +170,94 @@
 	struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data;
 	struct msm_vfe_stats_stream *stream_info =
 		&stats_data->stream_info[
-			(stream_release_cmd->stream_handle & 0xFF)];
+		(stream_release_cmd->stream_handle & 0xFF)];
 
-	if (stream_info == NULL)
-		rc = -1;
+	if (stream_info == NULL ||
+			stream_info->stream_handle !=
+				stream_release_cmd->stream_handle) {
+		pr_err("%s: handle mismatch(0x%x, 0x%x\n",
+			__func__, stream_info->stream_handle,
+			stream_release_cmd->stream_handle);
+		rc = -EINVAL;
+	}
+	if (stream_info->enable) {
+		struct msm_vfe_stats_stream_cfg_cmd stop_cmd;
+		memset(&stop_cmd, 0, sizeof(stop_cmd));
+		stop_cmd.num_streams = 1;
+		stop_cmd.stream_handle[0] = stream_release_cmd->stream_handle;
+		stop_cmd.enable = 0;
+		rc = msm_isp_cfg_stats_stream(vfe_dev, (void *)&stop_cmd);
+		if (rc < 0) {
+			pr_err("%s: cannot stop stats type %d\n",
+				__func__, stream_info->stats_type);
+			return -EPERM;
+		}
+	}
+	if (stream_info->bufq_handle) {
+		vfe_dev->buf_mgr->ops->release_buf(vfe_dev->buf_mgr,
+			stream_info->bufq_handle);
+		stream_info->bufq_handle = 0;
+	}
+	vfe_dev->hw_info->vfe_ops.stats_ops.
+		clear_wm_reg(vfe_dev, stream_info);
+	if (stream_info->comp_flag) {
+		msm_isp_stats_unreserve_comp_mask(vfe_dev,
+			stats_data, stream_info);
+		vfe_dev->hw_info->vfe_ops.stats_ops.
+		clear_comp_mask(vfe_dev, stream_info);
+	} else {
+		vfe_dev->hw_info->vfe_ops.stats_ops.
+		clear_wm_irq_mask(vfe_dev, stream_info);
+	}
+	vfe_dev->hw_info->vfe_ops.stats_ops.
+		clear_framedrop(vfe_dev, stream_info);
+	memset(stream_info, 0, sizeof(struct msm_vfe_stats_stream));
 	return rc;
 }
 
 int msm_isp_cfg_stats_stream(struct vfe_device *vfe_dev, void *arg)
 {
-	int rc = 0;
-	uint32_t stats_mask = 0;
-	uint8_t enable = 0;
+	int i, rc = 0;
 	uint32_t pingpong_status = 0;
 	struct msm_isp_buffer *buf = NULL;
-	enum msm_isp_stats_type stats_type = MSM_ISP_STATS_BE;
+	struct msm_vfe_stats_stream_cfg_cmd *stream_cfg_cmd = arg;
+	struct msm_vfe_stats_stream *stream_info;
+	struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data;
+	int idx;
+	uint32_t stats_mask = 0;
+	uint8_t enable = stream_cfg_cmd->enable;
+
+	for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
+		idx = stream_cfg_cmd->stream_handle[i] & 0xF;
+		stream_info = &stats_data->stream_info[idx];
+		if (stream_info->stream_handle !=
+				stream_cfg_cmd->stream_handle[i]) {
+			pr_err("%s: invalid stream handle -0x%x received\n",
+				__func__, stream_cfg_cmd->stream_handle[i]);
+			continue;
+		}
+		if (enable) {
+			stream_info->bufq_handle =
+				vfe_dev->buf_mgr->ops->get_bufq_handle(
+				vfe_dev->buf_mgr, stream_info->session_id,
+				stream_info->stream_id);
+				if (stream_info->bufq_handle == 0) {
+					pr_err("%s: no buf configured for stats type = %d\n",
+						__func__,
+						stream_info->stats_type);
+					return -EINVAL;
+				}
+		}
+		/* config ping address */
+		pingpong_status = VFE_PONG_ACTIVE_FLAG;
+		stats_mask |= (1 << stream_info->stats_type);
+		msm_isp_stats_cfg_ping_pong_address(vfe_dev,
+			stream_info, pingpong_status, buf);
+		pingpong_status = VFE_PING_ACTIVE_FLAG;
+		msm_isp_stats_cfg_ping_pong_address(vfe_dev,
+			stream_info, pingpong_status, buf);
+	}
 	vfe_dev->hw_info->vfe_ops.stats_ops.
-	stats_enable(vfe_dev, stats_mask, enable);
-	vfe_dev->hw_info->vfe_ops.stats_ops.
-	update_ping_pong_addr(vfe_dev, stats_type,
-		pingpong_status, buf->mapped_info[0].paddr);
+		stats_enable(vfe_dev, stats_mask, enable);
 	return rc;
 }
diff --git a/drivers/media/video/msmb/sensor/msm_sensor.c b/drivers/media/video/msmb/sensor/msm_sensor.c
index 1f54951..78c3207 100644
--- a/drivers/media/video/msmb/sensor/msm_sensor.c
+++ b/drivers/media/video/msmb/sensor/msm_sensor.c
@@ -783,7 +783,7 @@
 
 int32_t msm_sensor_power_up(struct msm_sensor_ctrl_t *s_ctrl)
 {
-	int32_t rc = 0, index = 0, clk_index = 0;
+	int32_t rc = 0, index = 0;
 	struct msm_sensor_power_setting_array *power_setting_array = NULL;
 	struct msm_sensor_power_setting *power_setting = NULL;
 	struct msm_camera_sensor_board_info *data = s_ctrl->sensordata;
@@ -900,17 +900,22 @@
 	return 0;
 power_up_failed:
 	pr_err("%s:%d failed\n", __func__, __LINE__);
+	if (s_ctrl->sensor_device_type == MSM_SENSOR_PLATFORM_DEVICE) {
+		s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_util(
+			s_ctrl->sensor_i2c_client, MSM_CCI_RELEASE);
+	}
+
 	for (index--; index >= 0; index--) {
 		CDBG("%s index %d\n", __func__, index);
 		power_setting = &power_setting_array->power_setting[index];
 		CDBG("%s type %d\n", __func__, power_setting->seq_type);
 		switch (power_setting->seq_type) {
 		case SENSOR_CLK:
-			for (clk_index--; clk_index >= 0; clk_index--)
-				msm_cam_clk_enable(s_ctrl->dev,
-					&s_ctrl->clk_info[clk_index],
-					(struct clk **)&power_setting->data[0],
-					1, 0);
+			msm_cam_clk_enable(s_ctrl->dev,
+				&s_ctrl->clk_info[0],
+				(struct clk **)&power_setting->data[0],
+				s_ctrl->clk_info_size,
+				0);
 			break;
 		case SENSOR_GPIO:
 			gpio_set_value_cansleep(
diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c
index 4012fec..3222ea0 100644
--- a/drivers/media/video/v4l2-ctrls.c
+++ b/drivers/media/video/v4l2-ctrls.c
@@ -259,6 +259,7 @@
 		"Single",
 		"Max Macroblocks",
 		"Max Bytes",
+		"GOB",
 		NULL,
 	};
 	static const char * const entropy_mode[] = {
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index cc021c0..8953475 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -881,6 +881,7 @@
 		dev_set_drvdata(&client->dev, wcd9xxx);
 		wcd9xxx->dev = &client->dev;
 		wcd9xxx->reset_gpio = pdata->reset_gpio;
+		wcd9xxx->slim_device_bootup = true;
 		if (client->dev.of_node)
 			wcd9xxx->mclk_rate = pdata->mclk_rate;
 		ret = wcd9xxx_enable_supplies(wcd9xxx, pdata);
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 057e4e1..b11e30e 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -58,7 +58,7 @@
 #define QSEE_CE_CLK_100MHZ		100000000
 #define QSEE_CE_CLK_50MHZ		50000000
 
-#define QSEECOM_MAX_SG_ENTRY	10
+#define QSEECOM_MAX_SG_ENTRY	512
 
 enum qseecom_command_scm_resp_type {
 	QSEOS_APP_ID = 0xEE01,
@@ -1662,6 +1662,7 @@
 	/* Populate the structure for sending scm call to load image */
 	data->client.sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
 							data->client.ihandle);
+	data->client.user_virt_sb_base = (uint32_t)data->client.sb_virt;
 	data->client.sb_phys = pa;
 	(*handle)->dev = (void *)data;
 	(*handle)->sbuf = (unsigned char *)data->client.sb_virt;
diff --git a/drivers/misc/tspp.c b/drivers/misc/tspp.c
index 563a013..4e504da5 100644
--- a/drivers/misc/tspp.c
+++ b/drivers/misc/tspp.c
@@ -41,6 +41,8 @@
 #include <mach/dma.h>
 #include <mach/msm_tspp.h>
 #include <linux/debugfs.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
 
 /*
  * General defines
@@ -647,45 +649,19 @@
 }
 
 /*** GPIO functions ***/
-static void tspp_gpios_free(const struct msm_gpio *table, int size)
-{
-	int i;
-	const struct msm_gpio *g;
-	for (i = size-1; i >= 0; i--) {
-		g = table + i;
-		gpio_free(GPIO_PIN(g->gpio_cfg));
-	}
-}
-
-static int tspp_gpios_request(const struct msm_gpio *table, int size)
-{
-	int rc;
-	int i;
-	const struct msm_gpio *g;
-	for (i = 0; i < size; i++) {
-		g = table + i;
-		rc = gpio_request(GPIO_PIN(g->gpio_cfg), g->label);
-		if (rc) {
-			pr_err("tspp: gpio_request(%d) <%s> failed: %d\n",
-			       GPIO_PIN(g->gpio_cfg), g->label ?: "?", rc);
-			goto err;
-		}
-	}
-	return 0;
-err:
-	tspp_gpios_free(table, i);
-	return rc;
-}
-
 static int tspp_gpios_disable(const struct msm_gpio *table, int size)
 {
 	int rc = 0;
 	int i;
 	const struct msm_gpio *g;
+
 	for (i = size-1; i >= 0; i--) {
 		int tmp;
 		g = table + i;
-		tmp = gpio_tlmm_config(g->gpio_cfg, GPIO_CFG_DISABLE);
+
+		tmp = gpio_tlmm_config(GPIO_CFG(GPIO_PIN(g->gpio_cfg),
+			0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+			GPIO_CFG_DISABLE);
 		if (tmp) {
 			pr_err("tspp_gpios_disable(0x%08x, GPIO_CFG_DISABLE) <%s> failed: %d\n",
 			       g->gpio_cfg, g->label ?: "?", rc);
@@ -704,8 +680,9 @@
 static int tspp_gpios_enable(const struct msm_gpio *table, int size)
 {
 	int rc;
-	int i;
+	int i, j;
 	const struct msm_gpio *g;
+
 	for (i = 0; i < size; i++) {
 		g = table + i;
 		rc = gpio_tlmm_config(g->gpio_cfg, GPIO_CFG_ENABLE);
@@ -721,39 +698,26 @@
 	}
 	return 0;
 err:
-	tspp_gpios_disable(table, i);
-	return rc;
-}
+	for (j = 0; j < i; j++)
+		tspp_gpios_disable(table, j);
 
-static int tspp_gpios_request_enable(const struct msm_gpio *table, int size)
-{
-	int rc = tspp_gpios_request(table, size);
-	if (rc)
-		return rc;
-	rc = tspp_gpios_enable(table, size);
-	if (rc)
-		tspp_gpios_free(table, size);
 	return rc;
 }
 
-static void tspp_gpios_disable_free(const struct msm_gpio *table, int size)
-{
-	tspp_gpios_disable(table, size);
-	tspp_gpios_free(table, size);
-}
-
 static int tspp_start_gpios(struct tspp_device *device)
 {
 	struct msm_tspp_platform_data *pdata =
 		device->pdev->dev.platform_data;
-	return tspp_gpios_request_enable(pdata->gpios, pdata->num_gpios);
+
+	return tspp_gpios_enable(pdata->gpios, pdata->num_gpios);
 }
 
 static void tspp_stop_gpios(struct tspp_device *device)
 {
 	struct msm_tspp_platform_data *pdata =
 		device->pdev->dev.platform_data;
-	tspp_gpios_disable_free(pdata->gpios, pdata->num_gpios);
+
+	tspp_gpios_disable(pdata->gpios, pdata->num_gpios);
 }
 
 /*** Clock functions ***/
@@ -1427,9 +1391,10 @@
 	event = &channel->event;
 
 	/* start the clocks if needed */
-	tspp_clock_start(pdev);
-	if (tspp_channels_in_use(pdev) == 0)
+	if (tspp_channels_in_use(pdev) == 0) {
+		tspp_clock_start(pdev);
 		wake_lock(&pdev->wake_lock);
+	}
 
 	/* mark it as used */
 	channel->used = 1;
@@ -1604,9 +1569,10 @@
 	channel->locked = NULL;
 	channel->used = 0;
 
-	if (tspp_channels_in_use(pdev) == 0)
+	if (tspp_channels_in_use(pdev) == 0) {
 		wake_unlock(&pdev->wake_lock);
-	tspp_clock_stop(pdev);
+		tspp_clock_stop(pdev);
+	}
 
 	return 0;
 }
@@ -2554,6 +2520,137 @@
 	}
 }
 
+/* copy device-tree data to platfrom data struct */
+static __devinit struct msm_tspp_platform_data *
+msm_tspp_dt_to_pdata(struct platform_device *pdev)
+{
+	struct device_node *node = pdev->dev.of_node;
+	struct msm_tspp_platform_data *data;
+	struct msm_gpio *gpios;
+	int i, rc;
+	int gpio;
+	u32 gpio_func;
+
+	/* Note: memory allocated by devm_kzalloc is freed automatically */
+	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+	if (!data) {
+		pr_err("tspp: Unable to allocate platform data\n");
+		return NULL;
+	}
+	rc = of_property_read_string(node, "qcom,tsif-pclk", &data->tsif_pclk);
+	if (rc) {
+		pr_err("tspp: Could not find tsif-pclk property, err = %d\n",
+			rc);
+		return NULL;
+	}
+	rc = of_property_read_string(node, "qcom,tsif-ref-clk",
+			&data->tsif_ref_clk);
+	if (rc) {
+		pr_err("tspp: Could not find tsif-ref-clk property, err = %d\n",
+			rc);
+		return NULL;
+	}
+
+	data->num_gpios = of_gpio_count(node);
+	if (data->num_gpios == 0) {
+		pr_err("tspp: Could not find GPIO definitions\n");
+		return NULL;
+	}
+	gpios = devm_kzalloc(&pdev->dev,
+			(data->num_gpios * sizeof(struct msm_gpio)),
+			GFP_KERNEL);
+	if (!gpios) {
+		pr_err("tspp: Unable to allocate memory for GPIOs table\n");
+		return NULL;
+	}
+	/* Assuming GPIO FUNC property is the same for all GPIOs */
+	if (of_property_read_u32(node, "qcom,gpios-func", &gpio_func)) {
+		pr_err("tspp: Could not find gpios-func property\n");
+		return NULL;
+	}
+	for (i = 0; i < data->num_gpios; i++) {
+		gpio = of_get_gpio(node, i);
+		gpios[i].gpio_cfg = GPIO_CFG(gpio, gpio_func,
+						GPIO_CFG_INPUT,
+						GPIO_CFG_PULL_DOWN,
+						GPIO_CFG_2MA);
+		rc = of_property_read_string_index(node, "qcom,gpio-names",
+						i, &gpios[i].label);
+		if (rc)
+			pr_warn("tspp: Could not find gpio-names property\n");
+	}
+
+	data->gpios = gpios;
+
+	return data;
+}
+
+static int msm_tspp_map_irqs(struct platform_device *pdev,
+				struct tspp_device *device)
+{
+	int rc;
+	int i;
+
+	/* get IRQ numbers from platform information */
+
+	/* map TSPP IRQ */
+	rc = platform_get_irq_byname(pdev, "TSIF_TSPP_IRQ");
+	if (rc > 0) {
+		device->tspp_irq = rc;
+		rc = request_irq(device->tspp_irq, tspp_isr, IRQF_SHARED,
+				 dev_name(&pdev->dev), device);
+		if (rc) {
+			dev_err(&pdev->dev,
+				"failed to request TSPP IRQ %d : %d",
+				device->tspp_irq, rc);
+			device->tspp_irq = 0;
+			return -EINVAL;
+		}
+	} else {
+		dev_err(&pdev->dev, "failed to get TSPP IRQ");
+		return -EINVAL;
+	}
+
+	/* map TSIF IRQs */
+	rc = platform_get_irq_byname(pdev, "TSIF0_IRQ");
+	if (rc > 0) {
+		device->tsif[0].tsif_irq = rc;
+	} else {
+		dev_err(&pdev->dev, "failed to get TSIF0 IRQ");
+		return -EINVAL;
+	}
+
+	rc = platform_get_irq_byname(pdev, "TSIF1_IRQ");
+	if (rc > 0) {
+		device->tsif[1].tsif_irq = rc;
+	} else {
+		dev_err(&pdev->dev, "failed to get TSIF1 IRQ");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < TSPP_TSIF_INSTANCES; i++) {
+		rc = request_irq(device->tsif[i].tsif_irq,
+				tsif_isr, IRQF_SHARED,
+				dev_name(&pdev->dev), &device->tsif[i]);
+		if (rc) {
+			dev_warn(&pdev->dev, "failed to request TSIF%d IRQ: %d",
+				i, rc);
+			device->tsif[i].tsif_irq = 0;
+		}
+	}
+
+	/* map BAM IRQ */
+	rc = platform_get_irq_byname(pdev, "TSIF_BAM_IRQ");
+	if (rc > 0) {
+		device->bam_irq = rc;
+	} else {
+		dev_err(&pdev->dev, "failed to get TSPP BAM IRQ");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int __devinit msm_tspp_probe(struct platform_device *pdev)
 {
 	int rc = -ENODEV;
@@ -2567,8 +2664,20 @@
 	struct resource *mem_bam;
 	struct tspp_channel *channel;
 
-	/* must have platform data */
-	data = pdev->dev.platform_data;
+	if (pdev->dev.of_node) {
+		/* get information from device tree */
+		data = msm_tspp_dt_to_pdata(pdev);
+		/* get device ID */
+		rc = of_property_read_u32(pdev->dev.of_node,
+					"cell-index", &pdev->id);
+		if (rc)
+			pdev->id = -1;
+
+		pdev->dev.platform_data = data;
+	} else {
+		/* must have platform data */
+		data = pdev->dev.platform_data;
+	}
 	if (!data) {
 		pr_err("tspp: Platform data not available");
 		rc = -EINVAL;
@@ -2617,7 +2726,8 @@
 	}
 
 	/* map I/O memory */
-	mem_tsif0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	mem_tsif0 = platform_get_resource_byname(pdev,
+				IORESOURCE_MEM, "MSM_TSIF0_PHYS");
 	if (!mem_tsif0) {
 		pr_err("tspp: Missing tsif0 MEM resource");
 		rc = -ENXIO;
@@ -2630,7 +2740,8 @@
 		goto err_map_tsif0;
 	}
 
-	mem_tsif1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	mem_tsif1 = platform_get_resource_byname(pdev,
+				IORESOURCE_MEM, "MSM_TSIF1_PHYS");
 	if (!mem_tsif1) {
 		dev_err(&pdev->dev, "Missing tsif1 MEM resource");
 		rc = -ENXIO;
@@ -2643,7 +2754,8 @@
 		goto err_map_tsif1;
 	}
 
-	mem_tspp = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+	mem_tspp = platform_get_resource_byname(pdev,
+				IORESOURCE_MEM, "MSM_TSPP_PHYS");
 	if (!mem_tspp) {
 		dev_err(&pdev->dev, "Missing MEM resource");
 		rc = -ENXIO;
@@ -2655,7 +2767,8 @@
 		goto err_map_dev;
 	}
 
-	mem_bam = platform_get_resource(pdev, IORESOURCE_MEM, 3);
+	mem_bam = platform_get_resource_byname(pdev,
+				IORESOURCE_MEM, "MSM_TSPP_BAM_PHYS");
 	if (!mem_bam) {
 		pr_err("tspp: Missing bam MEM resource");
 		rc = -ENXIO;
@@ -2670,39 +2783,8 @@
 		goto err_map_bam;
 	}
 
-	/* map TSPP IRQ */
-	rc = platform_get_irq(pdev, 0);
-	if (rc > 0) {
-		device->tspp_irq = rc;
-		rc = request_irq(device->tspp_irq, tspp_isr, IRQF_SHARED,
-				 dev_name(&pdev->dev), device);
-		if (rc) {
-			dev_err(&pdev->dev, "failed to request IRQ %d : %d",
-				device->tspp_irq, rc);
-			goto err_irq;
-		}
-	} else {
-		dev_err(&pdev->dev, "failed to get tspp IRQ");
+	if (msm_tspp_map_irqs(pdev, device))
 		goto err_irq;
-	}
-
-	/* map TSIF IRQs */
-	device->tsif[0].tsif_irq = TSIF1_IRQ;
-	device->tsif[1].tsif_irq = TSIF2_IRQ;
-
-	for (i = 0; i < TSPP_TSIF_INSTANCES; i++) {
-		rc = request_irq(device->tsif[i].tsif_irq,
-				tsif_isr, IRQF_SHARED,
-				dev_name(&pdev->dev), &device->tsif[i]);
-		if (rc) {
-			dev_warn(&pdev->dev, "failed to request TSIF%d IRQ: %d",
-				i, rc);
-			device->tsif[i].tsif_irq = 0;
-		}
-	}
-
-	/* BAM IRQ */
-	device->bam_irq = TSIF_BAM_IRQ;
 
 	/* GPIOs */
 	rc = tspp_start_gpios(device);
@@ -2737,17 +2819,17 @@
 	device->bam_props.irq = device->bam_irq;
 	device->bam_props.manage = SPS_BAM_MGR_LOCAL;
 
+	if (tspp_clock_start(device) != 0) {
+		dev_err(&pdev->dev, "Can't start clocks");
+		goto err_clock;
+	}
+
 	if (sps_register_bam_device(&device->bam_props,
 		&device->bam_handle) != 0) {
 		pr_err("tspp: failed to register bam");
 		goto err_bam;
 	}
 
-	if (tspp_clock_start(device) != 0) {
-		dev_err(&pdev->dev, "Can't start clocks");
-		goto err_clock;
-	}
-
 	spin_lock_init(&device->spinlock);
 	tasklet_init(&device->tlet, tspp_sps_complete_tlet,
 			(unsigned long)device);
@@ -2756,7 +2838,11 @@
 	tspp_global_reset(device);
 
 	version = readl_relaxed(device->base + TSPP_VERSION);
-	if (version != 1)
+	/*
+	 * TSPP version can be bits [7:0] or alternatively,
+	 * TSPP major version is bits [31:28].
+	 */
+	if ((version != 0x1) && (((version >> 28) & 0xF) != 0x1))
 		pr_warn("tspp: unrecognized hw version=%i", version);
 
 	/* initialize the channels */
@@ -2776,21 +2862,30 @@
 	return 0;
 
 err_channel:
-	/* uninitialize channels */
+	/* un-initialize channels */
 	for (j = 0; j < i; j++) {
 		channel = &(device->channels[i]);
 		device_destroy(tspp_class, channel->cdev.dev);
 		cdev_del(&channel->cdev);
 	}
-err_clock:
+
 	sps_deregister_bam_device(device->bam_handle);
+err_clock:
 err_bam:
 	tspp_debugfs_exit(device);
 	for (i = 0; i < TSPP_TSIF_INSTANCES; i++)
 		tsif_debugfs_exit(&device->tsif[i]);
+
+	tspp_stop_gpios(device);
 err_gpio:
 err_irq:
-	tspp_stop_gpios(device);
+	for (i = 0; i < TSPP_TSIF_INSTANCES; i++) {
+		if (device->tsif[i].tsif_irq)
+			free_irq(device->tsif[i].tsif_irq,  &device->tsif[i]);
+	}
+	if (device->tspp_irq)
+		free_irq(device->tspp_irq, device);
+
 	iounmap(device->bam_props.virt_addr);
 err_map_bam:
 err_res_bam:
@@ -2830,7 +2925,10 @@
 		cdev_del(&channel->cdev);
 	}
 
+	/* de-registering BAM device requires clocks */
+	tspp_clock_start(device);
 	sps_deregister_bam_device(device->bam_handle);
+	tspp_clock_stop(device);
 
 	for (i = 0; i < TSPP_TSIF_INSTANCES; i++) {
 		tsif_debugfs_exit(&device->tsif[i]);
@@ -2879,12 +2977,18 @@
 	.runtime_resume = tspp_runtime_resume,
 };
 
+static struct of_device_id msm_match_table[] = {
+	{.compatible = "qcom,msm_tspp"},
+	{}
+};
+
 static struct platform_driver msm_tspp_driver = {
 	.probe          = msm_tspp_probe,
 	.remove         = __exit_p(msm_tspp_remove),
 	.driver         = {
 		.name   = "msm_tspp",
 		.pm     = &tspp_dev_pm_ops,
+		.of_match_table = msm_match_table,
 	},
 };
 
diff --git a/drivers/net/ethernet/msm/msm_rmnet_bam.c b/drivers/net/ethernet/msm/msm_rmnet_bam.c
index 295c55c..83f486c 100644
--- a/drivers/net/ethernet/msm/msm_rmnet_bam.c
+++ b/drivers/net/ethernet/msm/msm_rmnet_bam.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -746,6 +746,112 @@
 	return 0;
 }
 
+/* support for 9 new rmnet ports */
+#define RMNET_REV_DEVICE_COUNT (9)
+static struct net_device *netdevs_rev[RMNET_REV_DEVICE_COUNT];
+static struct platform_driver bam_rmnet_rev_drivers[RMNET_REV_DEVICE_COUNT];
+
+static int bam_rmnet_rev_probe(struct platform_device *pdev)
+{
+	int i;
+	char name[BAM_DMUX_CH_NAME_MAX_LEN];
+	struct rmnet_private *p;
+
+	for (i = 0; i < RMNET_REV_DEVICE_COUNT; ++i) {
+		scnprintf(name, BAM_DMUX_CH_NAME_MAX_LEN, "bam_dmux_ch_%d",
+					(i+BAM_DMUX_DATA_REV_RMNET_0));
+		if (!strncmp(pdev->name, name, BAM_DMUX_CH_NAME_MAX_LEN))
+			break;
+	}
+
+	if (i >= RMNET_REV_DEVICE_COUNT) {
+		pr_err("%s: wrong netdev %s\n", __func__, pdev->name);
+		return 0;
+	}
+
+	p = netdev_priv(netdevs_rev[i]);
+	if (p->in_reset) {
+		p->in_reset = 0;
+		msm_bam_dmux_open(p->ch_id, netdevs_rev[i], bam_notify);
+		netif_carrier_on(netdevs_rev[i]);
+		netif_start_queue(netdevs_rev[i]);
+	}
+
+	return 0;
+}
+
+static int bam_rmnet_rev_remove(struct platform_device *pdev)
+{
+	int i;
+	char name[BAM_DMUX_CH_NAME_MAX_LEN];
+	struct rmnet_private *p;
+
+	for (i = 0; i < RMNET_REV_DEVICE_COUNT; ++i) {
+		scnprintf(name, BAM_DMUX_CH_NAME_MAX_LEN, "bam_dmux_ch_%d",
+				(i+BAM_DMUX_DATA_REV_RMNET_0));
+		if (!strncmp(pdev->name, name, BAM_DMUX_CH_NAME_MAX_LEN))
+			break;
+	}
+
+	if (i >= RMNET_REV_DEVICE_COUNT) {
+		pr_err("%s: wrong netdev %s\n", __func__, pdev->name);
+		return 0;
+	}
+
+	p = netdev_priv(netdevs_rev[i]);
+	p->in_reset = 1;
+	if (p->waiting_for_ul_skb != NULL) {
+		dev_kfree_skb_any(p->waiting_for_ul_skb);
+		p->waiting_for_ul_skb = NULL;
+	}
+	msm_bam_dmux_close(p->ch_id);
+	netif_carrier_off(netdevs_rev[i]);
+	netif_stop_queue(netdevs_rev[i]);
+	return 0;
+}
+
+#ifdef CONFIG_MSM_RMNET_DEBUG
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static int rmnet_debug_init_timeout_suspend(struct net_device *dev)
+{
+	struct device *d;
+	d = &(dev->dev);
+	return device_create_file(d, &dev_attr_timeout_suspend);
+}
+#else
+static int rmnet_debug_init_timeout_suspend(struct net_device *dev)
+{
+	return 0;
+}
+#endif
+static int rmnet_debug_init(struct net_device *dev)
+{
+
+	struct device *d;
+	struct rmnet_private *p;
+	int err = 0;
+	d = &(dev->dev);
+	p = netdev_priv(dev);
+	p->timeout_us = 0;
+	p->wakeups_xmit = p->wakeups_rcv = 0;
+	err = device_create_file(d, &dev_attr_timeout);
+	if (err)
+		return err;
+	err = device_create_file(d, &dev_attr_wakeups_xmit);
+	if (err)
+		return err;
+	err = device_create_file(d, &dev_attr_wakeups_rcv);
+	if (err)
+		return err;
+	err = rmnet_debug_init_timeout_suspend(dev);
+	return err;
+}
+#else
+static int rmnet_debug_init(struct net_device *dev)
+{
+	return 0;
+}
+#endif
 static int __init rmnet_init(void)
 {
 	int ret;
@@ -828,6 +934,53 @@
 			return ret;
 		}
 	}
+	/*Support for new rmnet ports */
+	for (n = 0; n < RMNET_REV_DEVICE_COUNT; n++) {
+		dev = alloc_netdev(sizeof(struct rmnet_private),
+				   "rev_rmnet%d", rmnet_setup);
+
+		if (!dev) {
+			pr_err("%s: no memory for rev netdev %d\n",
+							__func__, n);
+			return -ENOMEM;
+		}
+
+		netdevs_rev[n] = dev;
+		d = &(dev->dev);
+		p = netdev_priv(dev);
+		/* Initial config uses Ethernet */
+		p->operation_mode = RMNET_MODE_LLP_ETH;
+		p->ch_id = n+BAM_DMUX_DATA_REV_RMNET_0;
+		p->waiting_for_ul_skb = NULL;
+		p->in_reset = 0;
+		spin_lock_init(&p->lock);
+		spin_lock_init(&p->tx_queue_lock);
+
+		ret = register_netdev(dev);
+		if (ret) {
+			pr_err("%s: unable to register rev netdev %d rc=%d\n",
+							__func__, n, ret);
+			free_netdev(dev);
+			return ret;
+		}
+		if (rmnet_debug_init(dev))
+			continue;
+		bam_rmnet_rev_drivers[n].probe = bam_rmnet_rev_probe;
+		bam_rmnet_rev_drivers[n].remove = bam_rmnet_rev_remove;
+		tempname = kmalloc(BAM_DMUX_CH_NAME_MAX_LEN, GFP_KERNEL);
+		if (tempname == NULL)
+			return -ENOMEM;
+		scnprintf(tempname, BAM_DMUX_CH_NAME_MAX_LEN, "bam_dmux_ch_%d",
+					(n+BAM_DMUX_DATA_REV_RMNET_0));
+		bam_rmnet_rev_drivers[n].driver.name = tempname;
+		bam_rmnet_rev_drivers[n].driver.owner = THIS_MODULE;
+		ret = platform_driver_register(&bam_rmnet_rev_drivers[n]);
+		if (ret) {
+			pr_err("%s: new rev driver registration failed n=%d rc=%d\n",
+					__func__, n, ret);
+			return ret;
+		}
+	}
 	return 0;
 }
 
diff --git a/drivers/platform/msm/sps/sps_bam.c b/drivers/platform/msm/sps/sps_bam.c
index a1ff7cb..729450d 100644
--- a/drivers/platform/msm/sps/sps_bam.c
+++ b/drivers/platform/msm/sps/sps_bam.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2013, 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
@@ -1049,6 +1049,13 @@
 		else {
 			pipe->sys.desc_cache =
 				vmalloc(pipe->desc_size + size);
+
+			if (pipe->sys.desc_cache == NULL) {
+				SPS_ERR("sps:No memory for pipe %d of BAM 0x%x",
+					pipe_index, BAM_ID(dev));
+				return -ENOMEM;
+			}
+
 			memset(pipe->sys.desc_cache, 0, pipe->desc_size + size);
 		}
 
diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index a808e0b..233ea99 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -943,6 +943,9 @@
 	pdata->ignore_core_reset_ack = of_property_read_bool(node,
 					"qcom,ignore-core-reset-ack");
 
+	pdata->disable_clk_gating = of_property_read_bool(node,
+					"qcom,disable-clk-gating");
+
 	for_each_child_of_node(pdev->dev.of_node, node)
 		pipe_entry++;
 
@@ -1103,6 +1106,8 @@
 	 */
 	if (pdata->ignore_core_reset_ack && pdata->usb_active_bam != SSUSB_BAM)
 		usb_props.options = SPS_BAM_NO_EXT_P_RST;
+	if (pdata->disable_clk_gating)
+		usb_props.options |= SPS_BAM_NO_LOCAL_CLK_GATING;
 
 	ret = sps_register_bam_device(&usb_props, &h_bam);
 	if (ret < 0) {
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index f9aff40..061be69 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -928,7 +928,7 @@
 	if (trim < 0)
 		trim = 0;
 
-	pr_err("trim_orig %d write 0x%x index=%d value 0x%x to USB_OVP_TRIM\n",
+	pr_debug("trim_orig %d write 0x%x index=%d value 0x%x to USB_OVP_TRIM\n",
 		usb_trim_reg_orig, trim, index, chip->usb_trim_table[index]);
 
 	rc = pm8xxx_readb(chip->dev->parent, REG_SBI_CONFIG, &sbi_config);
@@ -3994,8 +3994,6 @@
 
 #define ENUM_TIMER_STOP_BIT	BIT(1)
 #define BOOT_DONE_BIT		BIT(6)
-#define BOOT_TIMER_EN_BIT	BIT(1)
-#define BOOT_DONE_MASK		(BOOT_DONE_BIT | BOOT_TIMER_EN_BIT)
 #define CHG_BATFET_ON_BIT	BIT(3)
 #define CHG_VCP_EN		BIT(0)
 #define CHG_BAT_TEMP_DIS_BIT	BIT(2)
@@ -4018,7 +4016,7 @@
 	detect_battery_removal(chip);
 
 	rc = pm_chg_masked_write(chip, SYS_CONFIG_2,
-					BOOT_DONE_MASK, BOOT_DONE_MASK);
+					BOOT_DONE_BIT, BOOT_DONE_BIT);
 	if (rc) {
 		pr_err("Failed to set BOOT_DONE_BIT rc=%d\n", rc);
 		return rc;
diff --git a/drivers/slimbus/slim-msm-ctrl.c b/drivers/slimbus/slim-msm-ctrl.c
index d4fb02b..9b0b8b4 100644
--- a/drivers/slimbus/slim-msm-ctrl.c
+++ b/drivers/slimbus/slim-msm-ctrl.c
@@ -1061,7 +1061,7 @@
 			dev_err(dev->dev, "rx thread wait error:%d", ret);
 
 		/* 1 irq notification per message */
-		if (!dev->use_rx_msgqs) {
+		if (dev->use_rx_msgqs != MSM_MSGQ_ENABLED) {
 			msm_slim_rxwq(dev);
 			continue;
 		}
@@ -1255,9 +1255,9 @@
 	spin_lock_init(&dev->rx_lock);
 	dev->ee = 1;
 	if (rxreg_access)
-		dev->use_rx_msgqs = 0;
+		dev->use_rx_msgqs = MSM_MSGQ_DISABLED;
 	else
-		dev->use_rx_msgqs = 1;
+		dev->use_rx_msgqs = MSM_MSGQ_RESET;
 
 	dev->irq = irq->start;
 	dev->bam.irq = bam_irq->start;
@@ -1328,7 +1328,7 @@
 	 * Manager register initialization
 	 * If RX msg Q is used, disable RX_MSG_RCVD interrupt
 	 */
-	if (dev->use_rx_msgqs)
+	if (dev->use_rx_msgqs == MSM_MSGQ_ENABLED)
 		writel_relaxed((MGR_INT_RECFG_DONE | MGR_INT_TX_NACKED_2 |
 			MGR_INT_MSG_BUF_CONTE | /* MGR_INT_RX_MSG_RCVD | */
 			MGR_INT_TX_MSG_SENT), dev->base + MGR_INT_EN);
@@ -1357,7 +1357,7 @@
 	mb();
 
 	/* Enable RX msg Q */
-	if (dev->use_rx_msgqs)
+	if (dev->use_rx_msgqs == MSM_MSGQ_ENABLED)
 		writel_relaxed(MGR_CFG_ENABLE | MGR_CFG_RX_MSGQ_EN,
 					dev->base + MGR_CFG);
 	else
diff --git a/drivers/slimbus/slim-msm-ngd.c b/drivers/slimbus/slim-msm-ngd.c
index a37a7803..eb741ef 100644
--- a/drivers/slimbus/slim-msm-ngd.c
+++ b/drivers/slimbus/slim-msm-ngd.c
@@ -129,7 +129,7 @@
 		 * queuing work
 		 */
 		mb();
-		if (dev->use_rx_msgqs)
+		if (dev->use_rx_msgqs == MSM_MSGQ_ENABLED)
 			dev_err(dev->dev,
 				"direct message received even with RX MSGQs");
 		else
@@ -225,8 +225,17 @@
 	u8 wbuf[SLIM_RX_MSGQ_BUF_LEN];
 
 	if (txn->mc == (SLIM_MSG_CLK_PAUSE_SEQ_FLG |
-			SLIM_MSG_MC_RECONFIGURE_NOW))
-		return msm_slim_qmi_power_request(dev, false);
+			SLIM_MSG_MC_RECONFIGURE_NOW)) {
+		if (dev->use_rx_msgqs == MSM_MSGQ_ENABLED) {
+			ret = sps_disconnect(dev->rx_msgq.sps);
+			dev->use_rx_msgqs = MSM_MSGQ_RESET;
+		}
+		if (!ret)
+			ret = msm_slim_qmi_power_request(dev, false);
+		else
+			pr_err("SPS pipe disconnect error:%d", ret);
+		return ret;
+	}
 	else if (txn->mc & SLIM_MSG_CLK_PAUSE_SEQ_FLG)
 		return 0;
 
@@ -543,7 +552,7 @@
 			return ret;
 		txn.len = 0;
 	}
-	return ret;
+	return 0;
 }
 
 static int ngd_set_laddr(struct slim_controller *ctrl, const u8 *ea,
@@ -581,6 +590,24 @@
 	return ret;
 }
 
+static void ngd_slim_setup_rx_path(struct msm_slim_ctrl *dev)
+{
+	int ret;
+	if (dev->state == MSM_CTRL_DOWN) {
+		msm_slim_sps_init(dev, dev->bam_mem,
+			NGD_BASE(dev->ctrl.nr,
+			dev->ver) + NGD_STATUS, true);
+	} else {
+		if (dev->use_rx_msgqs == MSM_MSGQ_DISABLED)
+			return;
+		ret = msm_slim_connect_endp(dev, &dev->rx_msgq,
+				&dev->rx_msgq_notify);
+		if (!ret)
+			dev->use_rx_msgqs = MSM_MSGQ_ENABLED;
+		else
+			pr_err("RX msgq not being used:%d", ret);
+	}
+}
 static void ngd_slim_rx(struct msm_slim_ctrl *dev, u8 *buf)
 {
 	u8 mc, mt, len;
@@ -608,12 +635,9 @@
 		txn.wbuf = wbuf;
 		txn.len = 4;
 		pr_info("SLIM SAT: Received master capability");
-		if (dev->state == MSM_CTRL_DOWN) {
-			dev->use_rx_msgqs = 1;
-			msm_slim_sps_init(dev, dev->bam_mem,
-				NGD_BASE(dev->ctrl.nr, dev->ver) + NGD_STATUS,
-				true);
-			if (dev->use_rx_msgqs)
+		if (dev->state >= MSM_CTRL_ASLEEP) {
+			ngd_slim_setup_rx_path(dev);
+			if (dev->use_rx_msgqs == MSM_MSGQ_ENABLED)
 				msgq_en |= NGD_CFG_RX_MSGQ_EN;
 			writel_relaxed(msgq_en, dev->base +
 					NGD_BASE(dev->ctrl.nr, dev->ver));
@@ -691,8 +715,7 @@
 	int timeout, ret;
 	enum msm_ctrl_state cur_state = dev->state;
 	u32 laddr;
-	u32 msgq_en = 1;
-	u32 ngd_int = (NGD_INT_RECFG_DONE | NGD_INT_TX_NACKED_2 |
+	u32 ngd_int = (NGD_INT_TX_NACKED_2 |
 			NGD_INT_MSG_BUF_CONTE | NGD_INT_MSG_TX_INVAL |
 			NGD_INT_IE_VE_CHG | NGD_INT_DEV_ERR |
 			NGD_INT_TX_MSG_SENT | NGD_INT_RX_MSG_RCVD);
@@ -721,12 +744,11 @@
 		 * ADSP power collapse case, where HW wasn't reset.
 		 * Reconnect BAM pipes if disconnected
 		 */
+		ngd_slim_setup_rx_path(dev);
 		return 0;
 	} else if (cur_state != MSM_CTRL_DOWN) {
 		pr_info("ADSP P.C. CTRL state:%d NGD not enumerated:0x%x",
 					dev->state, laddr);
-		if (dev->use_rx_msgqs)
-			msgq_en |= NGD_CFG_RX_MSGQ_EN;
 	}
 
 	/*
@@ -739,7 +761,7 @@
 	 * Enable NGD. Configure NGD in register acc. mode until master
 	 * announcement is received
 	 */
-	writel_relaxed(msgq_en, dev->base + NGD_BASE(dev->ctrl.nr, dev->ver));
+	writel_relaxed(1, dev->base + NGD_BASE(dev->ctrl.nr, dev->ver));
 	/* make sure NGD enabling goes through */
 	mb();
 
@@ -815,7 +837,7 @@
 			continue;
 		}
 		/* 1 irq notification per message */
-		if (!dev->use_rx_msgqs) {
+		if (dev->use_rx_msgqs != MSM_MSGQ_ENABLED) {
 			msm_slim_rx_dequeue(dev, (u8 *)buffer);
 			ngd_slim_rx(dev, (u8 *)buffer);
 			continue;
@@ -879,7 +901,6 @@
 	ngd_slim_enable(dev, false);
 	/* disconnect BAM pipes */
 	msm_slim_sps_exit(dev, false);
-	dev->use_rx_msgqs = 0;
 	mutex_lock(&ctrl->m_ctrl);
 	/* device up should be called again after SSR */
 	list_for_each_entry(sbdev, &ctrl->devs, dev_list)
@@ -908,6 +929,7 @@
 	struct resource		*slim_mem;
 	struct resource		*irq, *bam_irq;
 	enum apr_subsys_state q6_state;
+	bool			rxreg_access = false;
 
 	q6_state = apr_get_q6_state();
 	if (q6_state == APR_SUBSYS_DOWN) {
@@ -970,6 +992,8 @@
 			dev_err(&pdev->dev, "Cell index not specified:%d", ret);
 			goto err_ctrl_failed;
 		}
+		rxreg_access = of_property_read_bool(pdev->dev.of_node,
+					"qcom,rxreg-access");
 	} else {
 		dev->ctrl.nr = pdev->id;
 	}
@@ -1000,6 +1024,10 @@
 	dev->irq = irq->start;
 	dev->bam.irq = bam_irq->start;
 
+	if (rxreg_access)
+		dev->use_rx_msgqs = MSM_MSGQ_DISABLED;
+	else
+		dev->use_rx_msgqs = MSM_MSGQ_RESET;
 	init_completion(&dev->rx_msgq_notify);
 
 	/* Register with framework */
diff --git a/drivers/slimbus/slim-msm.c b/drivers/slimbus/slim-msm.c
index 72a8669..3e19f9b 100644
--- a/drivers/slimbus/slim-msm.c
+++ b/drivers/slimbus/slim-msm.c
@@ -9,7 +9,6 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  */
-
 #include <linux/pm_runtime.h>
 #include <linux/dma-mapping.h>
 #include <linux/slimbus/slimbus.h>
@@ -378,53 +377,19 @@
 	return ret;
 }
 
-static int msm_slim_init_rx_msgq(struct msm_slim_ctrl *dev, u32 pipe_reg)
+int msm_slim_connect_endp(struct msm_slim_ctrl *dev,
+				struct msm_slim_endp *endpoint,
+				struct completion *notify)
 {
 	int i, ret;
-	u32 pipe_offset;
-	struct msm_slim_endp *endpoint = &dev->rx_msgq;
-	struct sps_connect *config = &endpoint->config;
-	struct sps_mem_buffer *descr = &config->desc;
-	struct sps_mem_buffer *mem = &endpoint->buf;
-	struct completion *notify = &dev->rx_msgq_notify;
-
 	struct sps_register_event sps_error_event; /* SPS_ERROR */
 	struct sps_register_event sps_descr_event; /* DESCR_DONE */
-
-	init_completion(notify);
-	if (!dev->use_rx_msgqs)
-		return 0;
-
-	/* Allocate the endpoint */
-	ret = msm_slim_init_endpoint(dev, endpoint);
-	if (ret) {
-		dev_err(dev->dev, "init_endpoint failed 0x%x\n", ret);
-		goto sps_init_endpoint_failed;
-	}
-
-	/* Get the pipe indices for the message queues */
-	pipe_offset = (readl_relaxed(dev->base + pipe_reg) & 0xfc) >> 2;
-	dev_dbg(dev->dev, "Message queue pipe offset %d\n", pipe_offset);
-
-	config->mode = SPS_MODE_SRC;
-	config->source = dev->bam.hdl;
-	config->destination = SPS_DEV_HANDLE_MEM;
-	config->src_pipe_index = pipe_offset;
-	config->options = SPS_O_DESC_DONE | SPS_O_ERROR |
-				SPS_O_ACK_TRANSFERS | SPS_O_AUTO_ENABLE;
-
-	/* Allocate memory for the FIFO descriptors */
-	ret = msm_slim_sps_mem_alloc(dev, descr,
-				MSM_SLIM_DESC_NUM * sizeof(struct sps_iovec));
-	if (ret) {
-		dev_err(dev->dev, "unable to allocate SPS descriptors\n");
-		goto alloc_descr_failed;
-	}
+	struct sps_connect *config = &endpoint->config;
 
 	ret = sps_connect(endpoint->sps, config);
 	if (ret) {
 		dev_err(dev->dev, "sps_connect failed 0x%x\n", ret);
-		goto sps_connect_failed;
+		return ret;
 	}
 
 	memset(&sps_descr_event, 0x00, sizeof(sps_descr_event));
@@ -453,13 +418,6 @@
 		goto sps_reg_event_failed;
 	}
 
-	/* Allocate memory for the message buffer(s), N descrs, 4-byte mesg */
-	ret = msm_slim_sps_mem_alloc(dev, mem, MSM_SLIM_DESC_NUM * 4);
-	if (ret) {
-		dev_err(dev->dev, "dma_alloc_coherent failed\n");
-		goto alloc_buffer_failed;
-	}
-
 	/*
 	 * Call transfer_one for each 4-byte buffer
 	 * Use (buf->size/4) - 1 for the number of buffer to post
@@ -475,20 +433,74 @@
 	}
 
 	return 0;
-
 sps_transfer_failed:
-	msm_slim_sps_mem_free(dev, mem);
-alloc_buffer_failed:
 	memset(&sps_error_event, 0x00, sizeof(sps_error_event));
 	sps_register_event(endpoint->sps, &sps_error_event);
 sps_reg_event_failed:
 	sps_disconnect(endpoint->sps);
-sps_connect_failed:
+	return ret;
+}
+static int msm_slim_init_rx_msgq(struct msm_slim_ctrl *dev, u32 pipe_reg)
+{
+	int ret;
+	u32 pipe_offset;
+	struct msm_slim_endp *endpoint = &dev->rx_msgq;
+	struct sps_connect *config = &endpoint->config;
+	struct sps_mem_buffer *descr = &config->desc;
+	struct sps_mem_buffer *mem = &endpoint->buf;
+	struct completion *notify = &dev->rx_msgq_notify;
+
+	init_completion(notify);
+	if (dev->use_rx_msgqs == MSM_MSGQ_DISABLED)
+		return 0;
+
+	/* Allocate the endpoint */
+	ret = msm_slim_init_endpoint(dev, endpoint);
+	if (ret) {
+		dev_err(dev->dev, "init_endpoint failed 0x%x\n", ret);
+		goto sps_init_endpoint_failed;
+	}
+
+	/* Get the pipe indices for the message queues */
+	pipe_offset = (readl_relaxed(dev->base + pipe_reg) & 0xfc) >> 2;
+	dev_dbg(dev->dev, "Message queue pipe offset %d\n", pipe_offset);
+
+	config->mode = SPS_MODE_SRC;
+	config->source = dev->bam.hdl;
+	config->destination = SPS_DEV_HANDLE_MEM;
+	config->src_pipe_index = pipe_offset;
+	config->options = SPS_O_DESC_DONE | SPS_O_ERROR |
+				SPS_O_ACK_TRANSFERS | SPS_O_AUTO_ENABLE;
+
+	/* Allocate memory for the FIFO descriptors */
+	ret = msm_slim_sps_mem_alloc(dev, descr,
+				MSM_SLIM_DESC_NUM * sizeof(struct sps_iovec));
+	if (ret) {
+		dev_err(dev->dev, "unable to allocate SPS descriptors\n");
+		goto alloc_descr_failed;
+	}
+
+	/* Allocate memory for the message buffer(s), N descrs, 4-byte mesg */
+	ret = msm_slim_sps_mem_alloc(dev, mem, MSM_SLIM_DESC_NUM * 4);
+	if (ret) {
+		dev_err(dev->dev, "dma_alloc_coherent failed\n");
+		goto alloc_buffer_failed;
+	}
+
+	ret = msm_slim_connect_endp(dev, endpoint, notify);
+
+	if (!ret) {
+		dev->use_rx_msgqs = MSM_MSGQ_ENABLED;
+		return 0;
+	}
+
+	msm_slim_sps_mem_free(dev, mem);
+alloc_buffer_failed:
 	msm_slim_sps_mem_free(dev, descr);
 alloc_descr_failed:
 	msm_slim_free_endpoint(endpoint);
 sps_init_endpoint_failed:
-	dev->use_rx_msgqs = 0;
+	dev->use_rx_msgqs = MSM_MSGQ_DISABLED;
 	return ret;
 }
 
@@ -550,7 +562,7 @@
 	ret = sps_register_bam_device(&bam_props, &bam_handle);
 	if (ret) {
 		dev_err(dev->dev, "disabling BAM: reg-bam failed 0x%x\n", ret);
-		dev->use_rx_msgqs = 0;
+		dev->use_rx_msgqs = MSM_MSGQ_DISABLED;
 		goto init_rx_msgq;
 	}
 	dev->bam.hdl = bam_handle;
@@ -569,7 +581,7 @@
 
 void msm_slim_sps_exit(struct msm_slim_ctrl *dev, bool dereg)
 {
-	if (dev->use_rx_msgqs) {
+	if (dev->use_rx_msgqs == MSM_MSGQ_ENABLED) {
 		struct msm_slim_endp *endpoint = &dev->rx_msgq;
 		struct sps_connect *config = &endpoint->config;
 		struct sps_mem_buffer *descr = &config->desc;
@@ -581,6 +593,7 @@
 		sps_disconnect(endpoint->sps);
 		msm_slim_sps_mem_free(dev, descr);
 		msm_slim_free_endpoint(endpoint);
+		dev->use_rx_msgqs = MSM_MSGQ_RESET;
 	}
 	if (dereg) {
 		sps_deregister_bam_device(dev->bam.hdl);
diff --git a/drivers/slimbus/slim-msm.h b/drivers/slimbus/slim-msm.h
index 1c6db32..6e329b3 100644
--- a/drivers/slimbus/slim-msm.h
+++ b/drivers/slimbus/slim-msm.h
@@ -155,6 +155,12 @@
 	MSM_CTRL_DOWN,
 };
 
+enum msm_slim_msgq {
+	MSM_MSGQ_DISABLED,
+	MSM_MSGQ_RESET,
+	MSM_MSGQ_ENABLED,
+};
+
 struct msm_slim_sps_bam {
 	u32			hdl;
 	void __iomem		*base;
@@ -209,7 +215,7 @@
 	struct clk		*hclk;
 	struct mutex		tx_lock;
 	u8			pgdla;
-	bool			use_rx_msgqs;
+	enum msm_slim_msgq	use_rx_msgqs;
 	int			pipe_b;
 	struct completion	reconf;
 	bool			reconf_busy;
@@ -273,6 +279,9 @@
 			u32 pipe_reg, bool remote);
 void msm_slim_sps_exit(struct msm_slim_ctrl *dev, bool dereg);
 
+int msm_slim_connect_endp(struct msm_slim_ctrl *dev,
+				struct msm_slim_endp *endpoint,
+				struct completion *notify);
 void msm_slim_qmi_exit(struct msm_slim_ctrl *dev);
 int msm_slim_qmi_init(struct msm_slim_ctrl *dev, bool apps_is_master);
 int msm_slim_qmi_power_request(struct msm_slim_ctrl *dev, bool active);
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index 8ff6cff..7645df4 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -64,6 +64,7 @@
 #include <mach/dma.h>
 #include <mach/sps.h>
 #include <mach/msm_serial_hs.h>
+#include <mach/msm_bus.h>
 
 #include "msm_serial_hs_hwreg.h"
 #define UART_SPS_CONS_PERIPHERAL 0
@@ -211,6 +212,10 @@
 	 * callback event object registered for an SPS connection end point.
 	 */
 	struct sps_event_notify notify;
+	/* bus client handler */
+	u32 bus_perf_client;
+	/* BLSP UART required BUS Scaling data */
+	struct msm_bus_scale_pdata *bus_scale_table;
 };
 
 #define MSM_UARTDM_BURST_SIZE 16   /* DM burst size (in bytes) */
@@ -1622,6 +1627,7 @@
 {
 	unsigned long sr_status;
 	unsigned long flags;
+	int ret;
 	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
 	struct circ_buf *tx_buf = &uport->state->xmit;
 
@@ -1702,6 +1708,15 @@
 	wake_unlock(&msm_uport->dma_wake_lock);
 
 	spin_unlock_irqrestore(&uport->lock, flags);
+
+	/* Reset PNOC Bus Scaling */
+	if (is_blsp_uart(msm_uport)) {
+		ret = msm_bus_scale_client_update_request(
+				msm_uport->bus_perf_client, 0);
+		if (ret)
+			pr_err("%s(): Failed to reset bus bw vote\n", __func__);
+	}
+
 	mutex_unlock(&msm_uport->clk_mutex);
 	return 1;
 }
@@ -1872,6 +1887,16 @@
 		wake_lock(&msm_uport->dma_wake_lock);
 		disable_irq_nosync(msm_uport->wakeup.irq);
 		spin_unlock_irqrestore(&uport->lock, flags);
+
+		/* Vote for PNOC BUS Scaling */
+		if (is_blsp_uart(msm_uport)) {
+			ret = msm_bus_scale_client_update_request(
+					msm_uport->bus_perf_client, 1);
+			if (ret)
+				pr_err("%s():Failed to vote for bus scaling.\n",
+								__func__);
+		}
+
 		ret = clk_prepare_enable(msm_uport->clk);
 		if (ret) {
 			dev_err(uport->dev, "Clock ON Failure"
@@ -2116,6 +2141,15 @@
 		disable_irq(msm_uport->wakeup.irq);
 	}
 
+	/* Vote for PNOC BUS Scaling */
+	if (is_blsp_uart(msm_uport)) {
+		ret = msm_bus_scale_client_update_request(
+				msm_uport->bus_perf_client, 1);
+		if (ret)
+			pr_err("%s(): Failed to vote for bus scaling\n",
+								__func__);
+	}
+
 	spin_lock_irqsave(&uport->lock, flags);
 
 	msm_hs_start_rx_locked(uport);
@@ -2555,7 +2589,7 @@
 
 static int __devinit msm_hs_probe(struct platform_device *pdev)
 {
-	int ret;
+	int ret = 0;
 	struct uart_port *uport;
 	struct msm_hs_port *msm_uport;
 	struct resource *core_resource;
@@ -2637,6 +2671,20 @@
 		uport->irq = core_irqres;
 		msm_uport->bam_irq = bam_irqres;
 
+		msm_uport->bus_scale_table = msm_bus_cl_get_pdata(pdev);
+		if (!msm_uport->bus_scale_table) {
+			pr_err("BLSP UART: Bus scaling is disabled\n");
+			goto unmap_memory;
+		} else {
+			msm_uport->bus_perf_client =
+				msm_bus_scale_register_client
+					(msm_uport->bus_scale_table);
+			if (IS_ERR(&msm_uport->bus_perf_client)) {
+				pr_err("%s(): Bus client register failed.\n",
+								__func__);
+				goto unmap_memory;
+			}
+		}
 	} else {
 
 		resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -2751,7 +2799,7 @@
 		ret = msm_hs_sps_init(msm_uport);
 		if (unlikely(ret)) {
 			pr_err("SPS Initialization failed ! err=%d", ret);
-			goto unmap_memory;
+			goto workqueue_destroy;
 		}
 	}
 
@@ -2761,18 +2809,12 @@
 
 	ret = uartdm_init_port(uport);
 	if (unlikely(ret)) {
-		clk_disable_unprepare(msm_uport->clk);
-		if (msm_uport->pclk)
-			clk_disable_unprepare(msm_uport->pclk);
-		goto unmap_memory;
+		goto err_clock;
 	}
 
 	/* 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
@@ -2789,7 +2831,7 @@
 
 	ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_clock.attr);
 	if (unlikely(ret))
-		goto unmap_memory;
+		goto err_clock;
 
 	msm_serial_debugfs_init(msm_uport, pdev->id);
 
@@ -2797,9 +2839,19 @@
 	if (pdata != NULL && pdata->userid && pdata->userid <= UARTDM_NR)
 		uport->line = pdata->userid;
 	ret = uart_add_one_port(&msm_hs_driver, uport);
-	if (!ret)
+	if (!ret) {
+		clk_disable_unprepare(msm_uport->clk);
+		if (msm_uport->pclk)
+			clk_disable_unprepare(msm_uport->pclk);
 		return ret;
+	}
 
+err_clock:
+	clk_disable_unprepare(msm_uport->clk);
+	if (msm_uport->pclk)
+		clk_disable_unprepare(msm_uport->pclk);
+workqueue_destroy:
+	destroy_workqueue(msm_uport->hsuart_wq);
 unmap_memory:
 	iounmap(uport->membase);
 	if (is_blsp_uart(msm_uport))
@@ -2903,6 +2955,15 @@
 	 * Hence mb() requires here.
 	 */
 	mb();
+
+	/* Reset PNOC Bus Scaling */
+	if (is_blsp_uart(msm_uport)) {
+		ret = msm_bus_scale_client_update_request(
+				msm_uport->bus_perf_client, 0);
+		if (ret)
+			pr_err("%s(): Failed to reset bus bw vote\n", __func__);
+	}
+
 	if (msm_uport->clk_state != MSM_HS_CLK_OFF) {
 		/* to balance clk_state */
 		clk_disable_unprepare(msm_uport->clk);
diff --git a/drivers/tty/serial/msm_serial_hs_hwreg.h b/drivers/tty/serial/msm_serial_hs_hwreg.h
index 20d6781..9fa4f55 100644
--- a/drivers/tty/serial/msm_serial_hs_hwreg.h
+++ b/drivers/tty/serial/msm_serial_hs_hwreg.h
@@ -215,7 +215,7 @@
 #ifdef CONFIG_MSM_UARTDM_Core_v14
 
 /* write only register */
-#define UARTDM_CSR_ADDR    0x0a
+#define UARTDM_CSR_ADDR    0xa0
 
 /* write only register */
 #define UARTDM_TF_ADDR   0x100
diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
index 0b46082..6875b74 100644
--- a/drivers/usb/dwc3/Makefile
+++ b/drivers/usb/dwc3/Makefile
@@ -1,6 +1,7 @@
 ccflags-$(CONFIG_USB_DWC3_DEBUG)	:= -DDEBUG
 ccflags-$(CONFIG_USB_DWC3_VERBOSE)	+= -DVERBOSE_DEBUG
 ccflags-y += -Idrivers/usb/host
+ccflags-y += -Idrivers/base/power
 
 obj-$(CONFIG_USB_DWC3)			+= dwc3.o
 
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 1ee0828..3ae6f22 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -1459,6 +1459,7 @@
 {
 	int ret;
 	bool dcp;
+	bool host_bus_suspend;
 
 	dev_dbg(mdwc->dev, "%s: entering lpm\n", __func__);
 
@@ -1481,17 +1482,7 @@
 	}
 
 	dcp = mdwc->charger.chg_type == DWC3_DCP_CHARGER;
-
-	/* Sequence to put hardware in low power state:
-	 * 1. Set OTGDISABLE to disable OTG block in HSPHY (saves power)
-	 * 2. Clear charger detection control fields (performed above)
-	 * 3. SUSPEND PHY and turn OFF core clock after some delay
-	 * 4. Clear interrupt latch register and enable BSV, ID HV interrupts
-	 * 5. Enable PHY retention
-	 */
-	dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG, 0x1000, 0x1000);
-	dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG,
-						0xC00000, 0x800000);
+	host_bus_suspend = mdwc->host_mode == 1;
 
 	/* Sequence to put SSPHY in low power state:
 	 * 1. Clear REF_SS_PHY_EN in SS_PHY_CTRL_REG
@@ -1507,10 +1498,43 @@
 	usleep_range(1000, 1200);
 	clk_disable_unprepare(mdwc->ref_clk);
 
-	dwc3_msm_write_reg(mdwc->base, HS_PHY_IRQ_STAT_REG, 0xFFF);
-	dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG, 0x18000, 0x18000);
-	if (!dcp)
+	if (host_bus_suspend) {
+		/* Sequence for host bus suspend case:
+		 * 1. Set suspend and sleep bits in GUSB2PHYCONFIG reg
+		 * 2. Clear interrupt latch register and enable BSV, ID HV intr
+		 * 3. Enable DP and DM HV interrupts in ALT_INTERRUPT_EN_REG
+		 * 4. Enable PHY retention
+		 */
+		dwc3_msm_write_reg(mdwc->base, DWC3_GUSB2PHYCFG(0),
+			dwc3_msm_read_reg(mdwc->base, DWC3_GUSB2PHYCFG(0)) |
+								0x00000140);
+		dwc3_msm_write_reg(mdwc->base, HS_PHY_IRQ_STAT_REG, 0xFFF);
+		if (mdwc->otg_xceiv && (!mdwc->ext_xceiv.otg_capability))
+			dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG,
+							 0x18000, 0x18000);
+		dwc3_msm_write_reg(mdwc->base, ALT_INTERRUPT_EN_REG, 0x00A);
 		dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG, 0x2, 0x0);
+		udelay(5);
+	} else {
+		/* Sequence to put hardware in low power state:
+		 * 1. Set OTGDISABLE to disable OTG block in HSPHY (saves power)
+		 * 2. Clear charger detection control fields (performed above)
+		 * 3. SUSPEND PHY and turn OFF core clock after some delay
+		 * 4. Clear interrupt latch register and enable BSV, ID HV intr
+		 * 5. Enable PHY retention
+		 */
+		dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG, 0x1000,
+									0x1000);
+		dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG,
+							0xC00000, 0x800000);
+		dwc3_msm_write_reg(mdwc->base, HS_PHY_IRQ_STAT_REG, 0xFFF);
+		if (mdwc->otg_xceiv && (!mdwc->ext_xceiv.otg_capability))
+			dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG,
+							0x18000, 0x18000);
+		if (!dcp)
+			dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG,
+								0x2, 0x0);
+	}
 
 	/* make sure above writes are completed before turning off clocks */
 	wmb();
@@ -1530,7 +1554,8 @@
 			dev_err(mdwc->dev, "Failed to reset bus bw vote\n");
 	}
 
-	if (mdwc->otg_xceiv && mdwc->ext_xceiv.otg_capability && !dcp)
+	if (mdwc->otg_xceiv && mdwc->ext_xceiv.otg_capability && !dcp &&
+							!host_bus_suspend)
 		dwc3_hsusb_ldo_enable(0);
 
 	dwc3_ssusb_ldo_enable(0);
@@ -1551,6 +1576,7 @@
 {
 	int ret;
 	bool dcp;
+	bool host_bus_suspend;
 
 	dev_dbg(mdwc->dev, "%s: exiting lpm\n", __func__);
 
@@ -1575,7 +1601,9 @@
 						__func__, ret);
 
 	dcp = mdwc->charger.chg_type == DWC3_DCP_CHARGER;
-	if (mdwc->otg_xceiv && mdwc->ext_xceiv.otg_capability && !dcp)
+	host_bus_suspend = mdwc->host_mode == 1;
+	if (mdwc->otg_xceiv && mdwc->ext_xceiv.otg_capability && !dcp &&
+							!host_bus_suspend)
 		dwc3_hsusb_ldo_enable(1);
 
 	dwc3_ssusb_ldo_enable(1);
@@ -1587,20 +1615,41 @@
 	clk_prepare_enable(mdwc->iface_clk);
 	clk_prepare_enable(mdwc->core_clk);
 
-	/* Disable HV interrupt */
-	dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG, 0x18000, 0x0);
-	/* Disable Retention */
-	dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG, 0x2, 0x2);
+	if (host_bus_suspend) {
+		/* Disable HV interrupt */
+		if (mdwc->otg_xceiv && (!mdwc->ext_xceiv.otg_capability))
+			dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG,
+							0x18000, 0x0);
+		/* Clear interrupt latch register */
+		dwc3_msm_write_reg(mdwc->base, HS_PHY_IRQ_STAT_REG, 0x000);
 
-	dwc3_msm_write_reg(mdwc->base, DWC3_GUSB2PHYCFG(0),
-	      dwc3_msm_read_reg(mdwc->base, DWC3_GUSB2PHYCFG(0)) | 0xF0000000);
-	/* 10usec delay required before de-asserting PHY RESET */
-	udelay(10);
-	dwc3_msm_write_reg(mdwc->base, DWC3_GUSB2PHYCFG(0),
-	      dwc3_msm_read_reg(mdwc->base, DWC3_GUSB2PHYCFG(0)) & 0x7FFFFFFF);
+		/* Disable DP and DM HV interrupt */
+		dwc3_msm_write_reg(mdwc->base, ALT_INTERRUPT_EN_REG, 0x000);
 
-	/* Bring PHY out of suspend */
-	dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG, 0xC00000, 0x0);
+		/* Disable Retention */
+		dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG, 0x2, 0x2);
+	} else {
+		/* Disable HV interrupt */
+		if (mdwc->otg_xceiv && (!mdwc->ext_xceiv.otg_capability))
+			dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG,
+								0x18000, 0x0);
+		/* Disable Retention */
+		dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG, 0x2, 0x2);
+
+		dwc3_msm_write_reg(mdwc->base, DWC3_GUSB2PHYCFG(0),
+			dwc3_msm_read_reg(mdwc->base, DWC3_GUSB2PHYCFG(0)) |
+								 0xF0000000);
+		/* 10usec delay required before de-asserting PHY RESET */
+		udelay(10);
+		dwc3_msm_write_reg(mdwc->base, DWC3_GUSB2PHYCFG(0),
+		      dwc3_msm_read_reg(mdwc->base, DWC3_GUSB2PHYCFG(0)) &
+								0x7FFFFFFF);
+
+		/* Bring PHY out of suspend */
+		dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG, 0xC00000,
+									0x0);
+
+	}
 
 	/* Assert SS PHY RESET */
 	dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 7),
@@ -2186,22 +2235,24 @@
 	msm->charger.charging_disabled = of_property_read_bool(node,
 				"qcom,charging-disabled");
 
-	if (!msm->ext_xceiv.otg_capability) {
-		/* DWC3 has separate IRQ line for OTG events (ID/BSV etc.) */
-		msm->hs_phy_irq = platform_get_irq_byname(pdev, "hs_phy_irq");
-		if (msm->hs_phy_irq < 0) {
-			dev_dbg(&pdev->dev, "pget_irq for hs_phy_irq failed\n");
-			msm->hs_phy_irq = 0;
-		} else {
-			ret = request_irq(msm->hs_phy_irq, msm_dwc3_irq,
-					IRQF_TRIGGER_RISING, "msm_dwc3", msm);
-			if (ret) {
-				dev_err(&pdev->dev, "irqreq HSPHYINT failed\n");
-				goto disable_hs_ldo;
-			}
-			enable_irq_wake(msm->hs_phy_irq);
-		}
+	/*
+	 * DWC3 has separate IRQ line for OTG events (ID/BSV) and for
+	 * DP and DM linestate transitions during low power mode.
+	 */
+	msm->hs_phy_irq = platform_get_irq_byname(pdev, "hs_phy_irq");
+	if (msm->hs_phy_irq < 0) {
+		dev_dbg(&pdev->dev, "pget_irq for hs_phy_irq failed\n");
+		msm->hs_phy_irq = 0;
 	} else {
+		ret = request_irq(msm->hs_phy_irq, msm_dwc3_irq,
+				IRQF_TRIGGER_RISING, "msm_dwc3", msm);
+		if (ret) {
+			dev_err(&pdev->dev, "irqreq HSPHYINT failed\n");
+			goto disable_hs_ldo;
+		}
+		enable_irq_wake(msm->hs_phy_irq);
+	}
+	if (msm->ext_xceiv.otg_capability) {
 		/* Use ADC for ID pin detection */
 		queue_delayed_work(system_nrt_wq, &msm->init_adc_work, 0);
 		device_create_file(&pdev->dev, &dev_attr_adc_enable);
diff --git a/drivers/usb/dwc3/dwc3_otg.c b/drivers/usb/dwc3/dwc3_otg.c
index eb879e3..4980337 100644
--- a/drivers/usb/dwc3/dwc3_otg.c
+++ b/drivers/usb/dwc3/dwc3_otg.c
@@ -1,7 +1,7 @@
 /**
  * dwc3_otg.c - DesignWare USB3 DRD Controller OTG
  *
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -55,6 +55,25 @@
 	}
 }
 
+static int dwc3_otg_set_suspend(struct usb_phy *phy, int suspend)
+{
+	struct usb_otg *otg = phy->otg;
+	struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg);
+
+	if (dotg->host_bus_suspend == suspend)
+		return 0;
+
+	dotg->host_bus_suspend = suspend;
+	if (suspend) {
+		pm_runtime_put_sync(phy->dev);
+	} else {
+		pm_runtime_get_noresume(phy->dev);
+		pm_runtime_resume(phy->dev);
+	}
+
+	return 0;
+}
+
 /**
  * dwc3_otg_set_host_power - Enable port power control for host operation
  *
@@ -149,6 +168,14 @@
 		 * anymore.
 		 */
 		dwc3_otg_set_host_regs(dotg);
+		/*
+		 * FIXME If micro A cable is disconnected during system suspend,
+		 * xhci platform device will be removed before runtime pm is
+		 * enabled for xhci device. Due to this, disable_depth becomes
+		 * greater than one and runtimepm is not enabled for next microA
+		 * connect. Fix this by calling pm_runtime_init for xhci device.
+		 */
+		pm_runtime_init(&dwc->xhci->dev);
 		ret = platform_device_add(dwc->xhci);
 		if (ret) {
 			dev_err(otg->phy->dev,
@@ -353,6 +380,9 @@
 			dev_dbg(phy->dev, "ext PHY_RESUME event received\n");
 			/* ext_xceiver would have taken h/w out of LPM by now */
 			ret = pm_runtime_get(phy->dev);
+			if ((phy->state == OTG_STATE_A_HOST) &&
+							dotg->host_bus_suspend)
+				dotg->host_bus_suspend = 0;
 			if (ret == -EACCES) {
 				/* pm_runtime_get may fail during system
 				   resume with -EACCES error */
@@ -852,6 +882,7 @@
 	dotg->otg.phy->otg = &dotg->otg;
 	dotg->otg.phy->dev = dwc->dev;
 	dotg->otg.phy->set_power = dwc3_otg_set_power;
+	dotg->otg.phy->set_suspend = dwc3_otg_set_suspend;
 
 	ret = usb_set_transceiver(dotg->otg.phy);
 	if (ret) {
diff --git a/drivers/usb/dwc3/dwc3_otg.h b/drivers/usb/dwc3/dwc3_otg.h
index 5a36a4f..07d6411 100644
--- a/drivers/usb/dwc3/dwc3_otg.h
+++ b/drivers/usb/dwc3/dwc3_otg.h
@@ -1,7 +1,7 @@
 /**
  * dwc3_otg.h - DesignWare USB3 DRD Controller OTG
  *
- * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -20,6 +20,7 @@
 #include <linux/power_supply.h>
 
 #include <linux/usb/otg.h>
+#include "power.h"
 
 #define DWC3_IDEV_CHG_MAX 1500
 
@@ -48,6 +49,7 @@
 	unsigned long inputs;
 	struct power_supply	*psy;
 	struct completion	dwc3_xcvr_vbus_init;
+	int			host_bus_suspend;
 };
 
 /**
diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c
index 644a779..d6d8a76 100644
--- a/drivers/usb/dwc3/host.c
+++ b/drivers/usb/dwc3/host.c
@@ -55,7 +55,6 @@
 
 	dma_set_coherent_mask(&xhci->dev, dwc->dev->coherent_dma_mask);
 
-	xhci->dev.parent	= dwc->dev;
 	xhci->dev.dma_mask	= dwc->dev->dma_mask;
 	xhci->dev.dma_parms	= dwc->dev->dma_parms;
 
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 9d231d6..0723416 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -69,6 +69,9 @@
 
 #include "ci13xxx_udc.h"
 
+/* Turns on streaming. overrides CI13XXX_DISABLE_STREAMING */
+static unsigned int streaming;
+module_param(streaming, uint, S_IRUGO | S_IWUSR);
 
 /******************************************************************************
  * DEFINE
@@ -332,9 +335,6 @@
 		udc->udc_driver->notify_event(udc,
 			CI13XXX_CONTROLLER_RESET_EVENT);
 
-	if (udc->udc_driver->flags & CI13XXX_DISABLE_STREAMING)
-		hw_cwrite(CAP_USBMODE, USBMODE_SDIS, USBMODE_SDIS);
-
 	/* USBMODE should be configured step by step */
 	hw_cwrite(CAP_USBMODE, USBMODE_CM, USBMODE_CM_IDLE);
 	hw_cwrite(CAP_USBMODE, USBMODE_CM, USBMODE_CM_DEVICE);
@@ -369,7 +369,15 @@
  */
 static int hw_device_state(u32 dma)
 {
+	struct ci13xxx *udc = _udc;
+
 	if (dma) {
+		if (streaming || !(udc->udc_driver->flags &
+				CI13XXX_DISABLE_STREAMING))
+			hw_cwrite(CAP_USBMODE, USBMODE_SDIS, 0);
+		else
+			hw_cwrite(CAP_USBMODE, USBMODE_SDIS, USBMODE_SDIS);
+
 		hw_cwrite(CAP_ENDPTLISTADDR, ~0, dma);
 		/* interrupt, error, port change, reset, sleep/suspend */
 		hw_cwrite(CAP_USBINTR, ~0,
@@ -980,16 +988,16 @@
  * dbg_done: prints a DONE event
  * @addr:   endpoint address
  * @td:     transfer descriptor
- * @status: status
  */
-static void dbg_done(u8 addr, const u32 token, int status)
+static void dbg_done(u8 addr, const struct usb_request *req)
 {
 	char msg[DBG_DATA_MSG];
 
-	scnprintf(msg, sizeof(msg), "%d %02X",
-		  (int)(token & TD_TOTAL_BYTES) >> ffs_nr(TD_TOTAL_BYTES),
-		  (int)(token & TD_STATUS)      >> ffs_nr(TD_STATUS));
-	dbg_print(addr, "DONE", status, msg);
+	if (req != NULL) {
+		scnprintf(msg, sizeof(msg),
+			  "%p %d %d", req, req->actual, req->length);
+		dbg_print(addr, "DONE", req->status, msg);
+	}
 }
 
 /**
@@ -1016,7 +1024,7 @@
 
 	if (req != NULL) {
 		scnprintf(msg, sizeof(msg),
-			  "%d %d", !req->no_interrupt, req->length);
+			  "%p %d %d", req, !req->no_interrupt, req->length);
 		dbg_print(addr, "QUEUE", status, msg);
 	}
 }
@@ -1049,6 +1057,7 @@
 {
 	char msg[DBG_DATA_MSG];
 	struct ci13xxx_req *req;
+	struct ci13xxx_td_wrapper *td;
 	struct list_head *ptr = NULL;
 
 	if (mep != NULL) {
@@ -1065,15 +1074,14 @@
 
 		list_for_each(ptr, &mep->qh.queue) {
 			req = list_entry(ptr, struct ci13xxx_req, queue);
-			scnprintf(msg, sizeof(msg),
-					"%08X:%08X:%08X\n",
-					req->dma, req->ptr->next,
-					req->ptr->token);
-			dbg_print(addr, "REQ", 0, msg);
-			scnprintf(msg, sizeof(msg), "%08X:%d\n",
-					req->ptr->page[0],
-					req->req.status);
-			dbg_print(addr, "REQPAGE", 0, msg);
+			list_for_each_entry(td, &req->td_list, list) {
+				scnprintf(msg, sizeof(msg),
+						"%08X:%08X:%08X:%08X\n",
+						td->dma, td->ptr->next,
+						td->ptr->token,
+						td->ptr->page[0]);
+				dbg_print(addr, "TD", 0, msg);
+			}
 		}
 	}
 }
@@ -1444,6 +1452,7 @@
 	unsigned long flags;
 	struct list_head   *ptr = NULL;
 	struct ci13xxx_req *req = NULL;
+	struct ci13xxx_td_wrapper *td;
 	unsigned i, j, n = 0, qSize = sizeof(struct ci13xxx_td)/sizeof(u32);
 
 	dbg_trace("[%s] %p\n", __func__, buf);
@@ -1458,15 +1467,18 @@
 		{
 			req = list_entry(ptr, struct ci13xxx_req, queue);
 
-			n += scnprintf(buf + n, PAGE_SIZE - n,
-					"EP=%02i: TD=%08X %s\n",
-					i % hw_ep_max/2, (u32)req->dma,
-					((i < hw_ep_max/2) ? "RX" : "TX"));
-
-			for (j = 0; j < qSize; j++)
+			list_for_each_entry(td, &req->td_list, list) {
 				n += scnprintf(buf + n, PAGE_SIZE - n,
-						" %04X:    %08X\n", j,
-						*((u32 *)req->ptr + j));
+						"EP=%02i: TD=%08X %s\n",
+						i % hw_ep_max/2, (u32)td->dma,
+						((i < hw_ep_max/2) ?
+						 "RX" : "TX"));
+
+				for (j = 0; j < qSize; j++)
+					n += scnprintf(buf + n, PAGE_SIZE - n,
+							" %04X:    %08X\n", j,
+							*((u32 *)td->ptr + j));
+			}
 		}
 	spin_unlock_irqrestore(udc->lock, flags);
 
@@ -1484,6 +1496,7 @@
 	unsigned int ep_num, dir;
 	int n;
 	struct ci13xxx_req *mReq = NULL;
+	struct ci13xxx_td_wrapper *td;
 
 	if (sscanf(buf, "%u %u", &ep_num, &dir) != 2) {
 		dev_err(dev, "<ep_num> <dir>: prime the ep");
@@ -1497,7 +1510,8 @@
 
 	n = hw_ep_bit(mEp->num, mEp->dir);
 	mReq =  list_entry(mEp->qh.queue.next, struct ci13xxx_req, queue);
-	mEp->qh.ptr->td.next   = mReq->dma;
+	td = list_first_entry(&mReq->td_list, struct ci13xxx_td_wrapper, list);
+	mEp->qh.ptr->td.next   = td->dma;
 	mEp->qh.ptr->td.token &= ~TD_STATUS;
 
 	wmb();
@@ -1527,12 +1541,15 @@
 	int n;
 	struct list_head   *ptr = NULL;
 	struct ci13xxx_req *req = NULL;
+	struct ci13xxx_td_wrapper *td;
+	unsigned long flags;
 
 	if (sscanf(buf, "%u %u", &ep_num, &dir) != 2) {
 		dev_err(dev, "<ep_num> <dir>: to print dtds");
 		goto done;
 	}
 
+	spin_lock_irqsave(udc->lock, flags);
 	if (dir)
 		mEp = &udc->ci13xxx_ep[ep_num + hw_ep_max/2];
 	else
@@ -1556,11 +1573,12 @@
 
 	list_for_each(ptr, &mEp->qh.queue) {
 		req = list_entry(ptr, struct ci13xxx_req, queue);
-
-		pr_info("\treq:%08x next:%08x token:%08x page0:%08x status:%d\n",
-				req->dma, req->ptr->next, req->ptr->token,
-				req->ptr->page[0], req->req.status);
+		list_for_each_entry(td, &req->td_list, list)
+			pr_info("\treq:%08x next:%08x token:%08x page0:%08x\n",
+				td->dma, td->ptr->next, td->ptr->token,
+				td->ptr->page[0]);
 	}
+	spin_unlock_irqrestore(udc->lock, flags);
 done:
 	return count;
 
@@ -1740,6 +1758,7 @@
 {
 	struct ci13xxx_ep *mep = (struct ci13xxx_ep *)data;
 	struct ci13xxx_req *req;
+	struct ci13xxx_td_wrapper *td;
 	struct list_head *ptr = NULL;
 	int n = hw_ep_bit(mep->num, mep->dir);
 	unsigned long flags;
@@ -1753,9 +1772,10 @@
 		goto out;
 
 	req = list_entry(mep->qh.queue.next, struct ci13xxx_req, queue);
+	td = list_first_entry(&req->td_list, struct ci13xxx_td_wrapper, list);
 
 	mb();
-	if (!(TD_STATUS_ACTIVE & req->ptr->token))
+	if (!(TD_STATUS_ACTIVE & td->ptr->token))
 		goto out;
 
 	mep->prime_timer_count++;
@@ -1767,10 +1787,10 @@
 				mep->qh.ptr->td.next, mep->qh.ptr->td.token);
 		list_for_each(ptr, &mep->qh.queue) {
 			req = list_entry(ptr, struct ci13xxx_req, queue);
-			pr_info("\treq:%08xnext:%08xtkn:%08xpage0:%08xsts:%d\n",
-					req->dma, req->ptr->next,
-					req->ptr->token, req->ptr->page[0],
-					req->req.status);
+			list_for_each_entry(td, &req->td_list, list)
+				pr_info("\treq:%08xnext:%08xtkn:%08xpage0:%08x\n",
+					td->dma, td->ptr->next,
+					td->ptr->token, td->ptr->page[0]);
 		}
 		dbg_usb_op_fail(0xFF, "PRIMEF", mep);
 		mep->prime_fail_count++;
@@ -1784,7 +1804,69 @@
 out:
 	mep->prime_timer_count = 0;
 	spin_unlock_irqrestore(mep->lock, flags);
+}
 
+static int prepare_dtds(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
+{
+	int i;
+	unsigned len;
+	unsigned remaining_len = mReq->req.length;
+	dma_addr_t dma = mReq->req.dma;
+	struct ci13xxx_td_wrapper *td = list_first_entry(&mReq->td_list,
+			struct ci13xxx_td_wrapper, list);
+	struct ci13xxx_td_wrapper *prev_td = NULL;
+	bool zlp = mReq->req.zero && remaining_len &&
+			(remaining_len % mEp->ep.maxpacket == 0);
+
+	do {
+		td = kmalloc(sizeof(*td), GFP_ATOMIC);
+		if (td == NULL) {
+			pr_err("td wrapper allocation failed\n");
+			goto free;
+		}
+		td->ptr = dma_pool_alloc(mEp->td_pool, GFP_ATOMIC,
+				&td->dma);
+		if (td->ptr == NULL) {
+			kfree(td);
+			pr_err("td allocation failed\n");
+			goto free;
+		}
+
+		list_add_tail(&td->list, &mReq->td_list);
+		if (zlp && !remaining_len)
+			zlp = false;
+
+		len = min_t(unsigned, remaining_len, CI13XXX_MAX_REQ_SIZE);
+		remaining_len -= len;
+		memset(td->ptr, 0, sizeof(*td->ptr));
+		td->ptr->token    = len << ffs_nr(TD_TOTAL_BYTES);
+		td->ptr->token   &= TD_TOTAL_BYTES;
+		td->ptr->token   |= TD_STATUS_ACTIVE;
+
+		td->ptr->page[0]  = dma;
+		for (i = 1; i < 5; i++)
+			td->ptr->page[i] = (dma + i * CI13XXX_PAGE_SIZE) &
+					~TD_RESERVED_MASK;
+		if (prev_td)
+			prev_td->ptr->next = td->dma;
+
+		dma += len;
+		prev_td = td;
+
+	} while (remaining_len || zlp);
+
+	td->ptr->next = TD_TERMINATE;
+	if (!mReq->req.no_interrupt)
+		td->ptr->token |= TD_IOC;
+
+	return 0;
+free:
+	list_for_each_entry_safe(td, prev_td, &mReq->td_list, list) {
+		list_del(&td->list);
+		dma_pool_free(mEp->td_pool, td->ptr, td->dma);
+		kfree(td);
+	}
+	return -ENOMEM;
 }
 
 /**
@@ -1799,7 +1881,7 @@
 	unsigned i;
 	int ret = 0;
 	unsigned length = mReq->req.length;
-	struct ci13xxx *udc = _udc;
+	struct ci13xxx_td_wrapper *td;
 
 	trace("%p, %p", mEp, mReq);
 
@@ -1819,40 +1901,23 @@
 		mReq->map = 1;
 	}
 
-	if (mReq->req.zero && length && (length % mEp->ep.maxpacket == 0)) {
-		mReq->zptr = dma_pool_alloc(mEp->td_pool, GFP_ATOMIC,
-					   &mReq->zdma);
-		if (mReq->zptr == NULL) {
-			if (mReq->map) {
-				dma_unmap_single(mEp->device, mReq->req.dma,
-					length, mEp->dir ? DMA_TO_DEVICE :
+	if (CI13XX_REQ_VENDOR_ID(mReq->req.udc_priv) == MSM_VENDOR_ID)
+		mReq->req.dma = 0;
+
+	ret = prepare_dtds(mEp, mReq);
+	if (ret) {
+		pr_err("dTD preparation failed\n");
+		if (mReq->map) {
+			dma_unmap_single(mEp->device, mReq->req.dma,
+					mReq->req.length,
+					mEp->dir ? DMA_TO_DEVICE :
 					DMA_FROM_DEVICE);
-				mReq->req.dma = DMA_ADDR_INVALID;
-				mReq->map     = 0;
-			}
-			return -ENOMEM;
+			mReq->req.dma = DMA_ADDR_INVALID;
+			mReq->map     = 0;
 		}
-		memset(mReq->zptr, 0, sizeof(*mReq->zptr));
-		mReq->zptr->next    = TD_TERMINATE;
-		mReq->zptr->token   = TD_STATUS_ACTIVE;
-		if (!mReq->req.no_interrupt)
-			mReq->zptr->token   |= TD_IOC;
+		return ret;
 	}
-	/*
-	 * TD configuration
-	 * TODO - handle requests which spawns into several TDs
-	 */
-	memset(mReq->ptr, 0, sizeof(*mReq->ptr));
-	mReq->ptr->token    = length << ffs_nr(TD_TOTAL_BYTES);
-	mReq->ptr->token   &= TD_TOTAL_BYTES;
-	mReq->ptr->token   |= TD_STATUS_ACTIVE;
-	if (mReq->zptr) {
-		mReq->ptr->next    = mReq->zdma;
-	} else {
-		mReq->ptr->next    = TD_TERMINATE;
-		if (!mReq->req.no_interrupt)
-			mReq->ptr->token  |= TD_IOC;
-	}
+	td = list_first_entry(&mReq->td_list, struct ci13xxx_td_wrapper, list);
 
 	/* MSM Specific: updating the request as required for
 	 * SPS mode. Enable MSM proprietary DMA engine acording
@@ -1860,46 +1925,28 @@
 	 */
 	if (CI13XX_REQ_VENDOR_ID(mReq->req.udc_priv) == MSM_VENDOR_ID) {
 		if (mReq->req.udc_priv & MSM_SPS_MODE) {
-			mReq->ptr->token = TD_STATUS_ACTIVE;
+			td->ptr->token = TD_STATUS_ACTIVE;
 			if (mReq->req.udc_priv & MSM_IS_FINITE_TRANSFER)
-				mReq->ptr->next = TD_TERMINATE;
+				td->ptr->next = TD_TERMINATE;
 			else
-				mReq->ptr->next = MSM_ETD_TYPE | mReq->dma;
+				td->ptr->next = MSM_ETD_TYPE | td->dma;
 			if (!mReq->req.no_interrupt)
-				mReq->ptr->token |= MSM_ETD_IOC;
+				td->ptr->token |= MSM_ETD_IOC;
 		}
-		mReq->req.dma = 0;
-	}
-
-	mReq->ptr->page[0]  = mReq->req.dma;
-	for (i = 1; i < 5; i++)
-		mReq->ptr->page[i] =
-			(mReq->req.dma + i * CI13XXX_PAGE_SIZE) & ~TD_RESERVED_MASK;
-
-	/* Remote Wakeup */
-	if (udc->suspended) {
-		if (!udc->remote_wakeup) {
-			mReq->req.status = -EAGAIN;
-			dev_dbg(mEp->device, "%s: queue failed (suspend) ept #%d\n",
-				__func__, mEp->num);
-			return -EAGAIN;
-		}
-		usb_phy_set_suspend(udc->transceiver, 0);
-		schedule_delayed_work(&udc->rw_work, REMOTE_WAKEUP_DELAY);
 	}
 
 	if (!list_empty(&mEp->qh.queue)) {
 		struct ci13xxx_req *mReqPrev;
+		struct ci13xxx_td_wrapper *prev_td;
 		int n = hw_ep_bit(mEp->num, mEp->dir);
 		int tmp_stat;
 		ktime_t start, diff;
 
 		mReqPrev = list_entry(mEp->qh.queue.prev,
 				struct ci13xxx_req, queue);
-		if (mReqPrev->zptr)
-			mReqPrev->zptr->next = mReq->dma & TD_ADDR_MASK;
-		else
-			mReqPrev->ptr->next = mReq->dma & TD_ADDR_MASK;
+		prev_td = list_entry(mReqPrev->td_list.prev,
+				struct ci13xxx_td_wrapper, list);
+		prev_td->ptr->next = td->dma & TD_ADDR_MASK;
 		wmb();
 		if (hw_cread(CAP_ENDPTPRIME, BIT(n)))
 			goto done;
@@ -1928,15 +1975,17 @@
 		struct ci13xxx_req *mReq = \
 			list_entry(mEp->qh.queue.next,
 				   struct ci13xxx_req, queue);
+		struct ci13xxx_td_wrapper *td = list_first_entry(&mReq->td_list,
+				struct ci13xxx_td_wrapper, list);
 
-		if (TD_STATUS_ACTIVE & mReq->ptr->token) {
-			mEp->qh.ptr->td.next   = mReq->dma;
+		if (TD_STATUS_ACTIVE & td->ptr->token) {
+			mEp->qh.ptr->td.next   = td->dma;
 			mEp->qh.ptr->td.token &= ~TD_STATUS;
 			goto prime;
 		}
 	}
 
-	mEp->qh.ptr->td.next   = mReq->dma;    /* TERMINATE = 0 */
+	mEp->qh.ptr->td.next   = td->dma;    /* TERMINATE = 0 */
 
 	if (CI13XX_REQ_VENDOR_ID(mReq->req.udc_priv) == MSM_VENDOR_ID) {
 		if (mReq->req.udc_priv & MSM_SPS_MODE) {
@@ -1993,27 +2042,27 @@
  */
 static int _hardware_dequeue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
 {
+	struct ci13xxx_td_wrapper *td, *temp_td;
+	unsigned rem, total_rem = 0;
+	int status;
+
 	trace("%p, %p", mEp, mReq);
 
 	if (mReq->req.status != -EALREADY)
 		return -EINVAL;
 
-	/* clean speculative fetches on req->ptr->token */
+	/* clean speculative fetches on td->ptr->token */
 	mb();
 
-	if ((TD_STATUS_ACTIVE & mReq->ptr->token) != 0)
+	td = list_entry(mReq->td_list.prev, struct ci13xxx_td_wrapper, list);
+
+	if ((TD_STATUS_ACTIVE & td->ptr->token) != 0)
 		return -EBUSY;
 
 	if (CI13XX_REQ_VENDOR_ID(mReq->req.udc_priv) == MSM_VENDOR_ID)
 		if ((mReq->req.udc_priv & MSM_SPS_MODE) &&
 			(mReq->req.udc_priv & MSM_IS_FINITE_TRANSFER))
 			return -EBUSY;
-	if (mReq->zptr) {
-		if ((TD_STATUS_ACTIVE & mReq->zptr->token) != 0)
-			return -EBUSY;
-		dma_pool_free(mEp->td_pool, mReq->zptr, mReq->zdma);
-		mReq->zptr = NULL;
-	}
 
 	mReq->req.status = 0;
 
@@ -2024,18 +2073,27 @@
 		mReq->map     = 0;
 	}
 
-	mReq->req.status = mReq->ptr->token & TD_STATUS;
-	if ((TD_STATUS_HALTED & mReq->req.status) != 0)
-		mReq->req.status = -1;
-	else if ((TD_STATUS_DT_ERR & mReq->req.status) != 0)
-		mReq->req.status = -1;
-	else if ((TD_STATUS_TR_ERR & mReq->req.status) != 0)
-		mReq->req.status = -1;
+	list_for_each_entry_safe(td, temp_td, &mReq->td_list, list) {
 
-	mReq->req.actual   = mReq->ptr->token & TD_TOTAL_BYTES;
-	mReq->req.actual >>= ffs_nr(TD_TOTAL_BYTES);
-	mReq->req.actual   = mReq->req.length - mReq->req.actual;
-	mReq->req.actual   = mReq->req.status ? 0 : mReq->req.actual;
+		status = td->ptr->token & TD_STATUS;
+		if ((status & TD_STATUS_HALTED) != 0)
+			mReq->req.status = -1;
+		else if ((status & TD_STATUS_DT_ERR) != 0)
+			mReq->req.status = -1;
+		else if ((status & TD_STATUS_TR_ERR) != 0)
+			mReq->req.status = -1;
+
+		rem = td->ptr->token & TD_TOTAL_BYTES;
+		rem >>= ffs_nr(TD_TOTAL_BYTES);
+		total_rem += rem;
+
+		list_del(&td->list);
+		dma_pool_free(mEp->td_pool, td->ptr, td->dma);
+		kfree(td);
+	}
+
+	mReq->req.actual = mReq->req.status ? 0 :
+			(mReq->req.length - total_rem);
 
 	return mReq->req.actual;
 }
@@ -2052,6 +2110,7 @@
 __acquires(mEp->lock)
 {
 	struct ci13xxx_ep *mEpTemp = mEp;
+	struct ci13xxx_td_wrapper *td, *temp_td;
 	unsigned val;
 
 	trace("%p", mEp);
@@ -2093,10 +2152,16 @@
 			mReq->map     = 0;
 		}
 
+		list_for_each_entry_safe(td, temp_td, &mReq->td_list, list) {
+			list_del(&td->list);
+			dma_pool_free(mEp->td_pool, td->ptr, td->dma);
+			kfree(td);
+		}
+
 		if (mReq->req.complete != NULL) {
 			spin_unlock(mEp->lock);
 			if ((mEp->type == USB_ENDPOINT_XFER_CONTROL) &&
-				mReq->req.length)
+					mReq->req.length)
 				mEpTemp = &_udc->ep0in;
 			mReq->req.complete(&mEpTemp->ep, &mReq->req);
 			if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
@@ -2442,7 +2507,7 @@
 		}
 		req_dequeue = 0;
 		list_del_init(&mReq->queue);
-		dbg_done(_usb_addr(mEp), mReq->ptr->token, retval);
+		dbg_done(_usb_addr(mEp), &mReq->req);
 		if (mReq->req.complete != NULL) {
 			spin_unlock(mEp->lock);
 			if ((mEp->type == USB_ENDPOINT_XFER_CONTROL) &&
@@ -2810,18 +2875,14 @@
 	}
 
 	mReq = kzalloc(sizeof(struct ci13xxx_req), gfp_flags);
-	if (mReq != NULL) {
-		INIT_LIST_HEAD(&mReq->queue);
-		mReq->req.dma = DMA_ADDR_INVALID;
+	if (mReq == NULL)
+		goto out;
 
-		mReq->ptr = dma_pool_alloc(mEp->td_pool, gfp_flags,
-					   &mReq->dma);
-		if (mReq->ptr == NULL) {
-			kfree(mReq);
-			mReq = NULL;
-		}
-	}
+	INIT_LIST_HEAD(&mReq->queue);
+	mReq->req.dma = DMA_ADDR_INVALID;
+	INIT_LIST_HEAD(&mReq->td_list);
 
+out:
 	dbg_event(_usb_addr(mEp), "ALLOC", mReq == NULL);
 
 	return (mReq == NULL) ? NULL : &mReq->req;
@@ -2850,8 +2911,6 @@
 
 	spin_lock_irqsave(mEp->lock, flags);
 
-	if (mReq->ptr)
-		dma_pool_free(mEp->td_pool, mReq->ptr, mReq->dma);
 	kfree(mReq);
 
 	dbg_event(_usb_addr(mEp), "FREE", 0);
@@ -2889,6 +2948,17 @@
 		return -ESHUTDOWN;
 	}
 
+	if (udc->suspended) {
+		if (!udc->remote_wakeup) {
+			mReq->req.status = -EAGAIN;
+			dev_dbg(mEp->device, "%s: queue failed (suspend) ept #%d\n",
+				__func__, mEp->num);
+			return -EAGAIN;
+		}
+		usb_phy_set_suspend(udc->transceiver, 0);
+		schedule_delayed_work(&udc->rw_work, REMOTE_WAKEUP_DELAY);
+	}
+
 	if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
 		if (req->length)
 			mEp = (_udc->ep0_dir == RX) ?
@@ -2907,11 +2977,9 @@
 		goto done;
 	}
 
-	if (req->length > (4 * CI13XXX_PAGE_SIZE)) {
-		req->length = (4 * CI13XXX_PAGE_SIZE);
-		retval = -EMSGSIZE;
-		warn("request length truncated");
-	}
+	/* REMOVE ME */
+	if (req->length > (CI13XXX_MAX_REQ_SIZE))
+		pr_warn_once("bigger request length\n");
 
 	dbg_queue(_usb_addr(mEp), req, retval);
 
@@ -2943,6 +3011,7 @@
 	struct ci13xxx_ep  *mEp  = container_of(ep,  struct ci13xxx_ep, ep);
 	struct ci13xxx_ep *mEpTemp = mEp;
 	struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
+	struct ci13xxx_td_wrapper *td, *temp_td;
 	unsigned long flags;
 
 	trace("%p, %p", ep, req);
@@ -2973,6 +3042,12 @@
 	}
 	req->status = -ECONNRESET;
 
+	list_for_each_entry_safe(td, temp_td, &mReq->td_list, list) {
+		list_del(&td->list);
+		dma_pool_free(mEp->td_pool, td->ptr, td->dma);
+		kfree(td);
+	}
+
 	if (mReq->req.complete != NULL) {
 		spin_unlock(mEp->lock);
 		if ((mEp->type == USB_ENDPOINT_XFER_CONTROL) &&
@@ -3502,8 +3577,7 @@
 		void __iomem *regs)
 {
 	struct ci13xxx *udc;
-	struct ci13xxx_platform_data *pdata =
-		(struct ci13xxx_platform_data *)(dev->platform_data);
+	struct ci13xxx_platform_data *pdata;
 	int retval = 0, i;
 
 	trace("%p, %p, %p", dev, regs, driver->name);
@@ -3532,6 +3606,7 @@
 	INIT_LIST_HEAD(&udc->gadget.ep_list);
 	udc->gadget.ep0 = NULL;
 
+	pdata = dev->platform_data;
 	if (pdata)
 		udc->gadget.usb_core_id = pdata->usb_core_id;
 
diff --git a/drivers/usb/gadget/ci13xxx_udc.h b/drivers/usb/gadget/ci13xxx_udc.h
index 6b3cad8..4f84d21 100644
--- a/drivers/usb/gadget/ci13xxx_udc.h
+++ b/drivers/usb/gadget/ci13xxx_udc.h
@@ -20,6 +20,7 @@
  * DEFINE
  *****************************************************************************/
 #define CI13XXX_PAGE_SIZE  4096ul /* page size for TD's */
+#define CI13XXX_MAX_REQ_SIZE  (4 * CI13XXX_PAGE_SIZE)
 #define ENDPT_MAX          (32)
 #define CTRL_PAYLOAD_MAX   (64)
 #define RX        (0)  /* similar to USB_DIR_OUT but can be used as an index */
@@ -77,15 +78,18 @@
 	struct usb_ctrlrequest   setup;
 } __attribute__ ((packed));
 
+struct ci13xxx_td_wrapper {
+	struct ci13xxx_td *ptr;
+	dma_addr_t dma;
+	struct list_head list;
+};
+
 /* Extension of usb_request */
 struct ci13xxx_req {
 	struct usb_request   req;
 	unsigned             map;
 	struct list_head     queue;
-	struct ci13xxx_td   *ptr;
-	dma_addr_t           dma;
-	struct ci13xxx_td   *zptr;
-	dma_addr_t           zdma;
+	struct list_head     td_list;
 };
 
 /* Extension of usb_ep */
diff --git a/drivers/usb/gadget/f_mtp.c b/drivers/usb/gadget/f_mtp.c
index 82ffbba..0c0d58a 100644
--- a/drivers/usb/gadget/f_mtp.c
+++ b/drivers/usb/gadget/f_mtp.c
@@ -67,6 +67,9 @@
 #define MTP_RESPONSE_OK             0x2001
 #define MTP_RESPONSE_DEVICE_BUSY    0x2019
 
+unsigned int mtp_rx_req_len = MTP_BULK_BUFFER_SIZE;
+module_param(mtp_rx_req_len, uint, S_IRUGO | S_IWUSR);
+
 static const char mtp_shortname[] = "mtp_usb";
 
 struct mtp_dev {
@@ -493,10 +496,27 @@
 		req->complete = mtp_complete_in;
 		mtp_req_put(dev, &dev->tx_idle, req);
 	}
+
+	/*
+	 * The RX buffer should be aligned to EP max packet for
+	 * some controllers.  At bind time, we don't know the
+	 * operational speed.  Hence assuming super speed max
+	 * packet size.
+	 */
+	if (mtp_rx_req_len % 1024)
+		mtp_rx_req_len = MTP_BULK_BUFFER_SIZE;
+
+retry_rx_alloc:
 	for (i = 0; i < RX_REQ_MAX; i++) {
-		req = mtp_request_new(dev->ep_out, MTP_BULK_BUFFER_SIZE);
-		if (!req)
-			goto fail;
+		req = mtp_request_new(dev->ep_out, mtp_rx_req_len);
+		if (!req) {
+			if (mtp_rx_req_len <= MTP_BULK_BUFFER_SIZE)
+				goto fail;
+			for (; i > 0; i--)
+				mtp_request_free(dev->rx_req[i], dev->ep_out);
+			mtp_rx_req_len = MTP_BULK_BUFFER_SIZE;
+			goto retry_rx_alloc;
+		}
 		req->complete = mtp_complete_out;
 		dev->rx_req[i] = req;
 	}
@@ -526,7 +546,7 @@
 
 	DBG(cdev, "mtp_read(%d)\n", count);
 
-	if (count > MTP_BULK_BUFFER_SIZE)
+	if (count > mtp_rx_req_len)
 		return -EINVAL;
 
 	if (!IS_ALIGNED(count, dev->ep_out->maxpacket))
@@ -554,7 +574,7 @@
 requeue_req:
 	/* queue a request */
 	req = dev->rx_req[0];
-	req->length = MTP_BULK_BUFFER_SIZE;
+	req->length = mtp_rx_req_len;
 	dev->rx_done = 0;
 	ret = usb_ep_queue(dev->ep_out, req, GFP_KERNEL);
 	if (ret < 0) {
@@ -832,7 +852,7 @@
 			cur_buf = (cur_buf + 1) % RX_REQ_MAX;
 
 			/* some h/w expects size to be aligned to ep's MTU */
-			read_req->length = MTP_BULK_BUFFER_SIZE;
+			read_req->length = mtp_rx_req_len;
 
 			dev->rx_done = 0;
 			ret = usb_ep_queue(dev->ep_out, read_req, GFP_KERNEL);
diff --git a/drivers/usb/gadget/f_qdss.c b/drivers/usb/gadget/f_qdss.c
index 085d0bd..70192de 100644
--- a/drivers/usb/gadget/f_qdss.c
+++ b/drivers/usb/gadget/f_qdss.c
@@ -408,6 +408,7 @@
 {
 	pr_debug("qdss_unbind\n");
 
+	clear_eps(f);
 	clear_desc(c->cdev->gadget, f);
 }
 
diff --git a/drivers/usb/gadget/u_bam.c b/drivers/usb/gadget/u_bam.c
index 00744fb..fe39700 100644
--- a/drivers/usb/gadget/u_bam.c
+++ b/drivers/usb/gadget/u_bam.c
@@ -652,7 +652,8 @@
 
 static void gbam2bam_disconnect_work(struct work_struct *w)
 {
-	struct gbam_port *port = container_of(w, struct gbam_port, connect_w);
+	struct gbam_port *port =
+			container_of(w, struct gbam_port, disconnect_w);
 	struct bam_ch_info *d = &port->data_ch;
 	int ret;
 
diff --git a/drivers/usb/gadget/u_data_hsic.c b/drivers/usb/gadget/u_data_hsic.c
index 746c041..575d85b 100644
--- a/drivers/usb/gadget/u_data_hsic.c
+++ b/drivers/usb/gadget/u_data_hsic.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2013, Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -634,10 +634,10 @@
 
 	ghsic_data_free_buffers(port);
 
-	data_bridge_close(port->brdg.ch_id);
-
+	cancel_work_sync(&port->connect_w);
+	if (test_and_clear_bit(CH_OPENED, &port->bridge_sts))
+		data_bridge_close(port->brdg.ch_id);
 	clear_bit(CH_READY, &port->bridge_sts);
-	clear_bit(CH_OPENED, &port->bridge_sts);
 
 	return 0;
 }
diff --git a/drivers/usb/gadget/u_rmnet_ctrl_smd.c b/drivers/usb/gadget/u_rmnet_ctrl_smd.c
index 169008b..5817779 100644
--- a/drivers/usb/gadget/u_rmnet_ctrl_smd.c
+++ b/drivers/usb/gadget/u_rmnet_ctrl_smd.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -32,6 +32,8 @@
 #define SMD_CH_MAX_LEN	20
 #define CH_OPENED	0
 #define CH_READY	1
+#define CH_PREPARE_READY 2
+
 struct smd_ch_info {
 	struct smd_channel	*ch;
 	char			*name;
@@ -60,6 +62,7 @@
 
 	spinlock_t		port_lock;
 	struct delayed_work	connect_w;
+	struct delayed_work	disconnect_w;
 };
 
 static struct rmnet_ctrl_ports {
@@ -324,6 +327,7 @@
 {
 	struct rmnet_ctrl_port *port =
 			container_of(w, struct rmnet_ctrl_port, connect_w.work);
+	struct rmnet_ctrl_ports *port_entry = &ctrl_smd_ports[port->port_num];
 	struct smd_ch_info *c = &port->ctrl_ch;
 	unsigned long flags;
 	int	set_bits = 0;
@@ -332,8 +336,13 @@
 
 	pr_debug("%s:\n", __func__);
 
-	if (!test_bit(CH_READY, &c->flags))
+	if (!test_bit(CH_READY, &c->flags)) {
+		if (!test_bit(CH_PREPARE_READY, &c->flags)) {
+			set_bit(CH_PREPARE_READY, &c->flags);
+			platform_driver_register(&(port_entry->pdrv));
+		}
 		return;
+	}
 
 	ret = smd_open(c->name, &c->ch, port, grmnet_ctrl_smd_notify);
 	if (ret) {
@@ -390,6 +399,23 @@
 	return 0;
 }
 
+static void grmnet_ctrl_smd_disconnect_w(struct work_struct *w)
+{
+	struct rmnet_ctrl_port *port =
+			container_of(w, struct rmnet_ctrl_port,
+					disconnect_w.work);
+	struct smd_ch_info *c;
+	struct platform_driver *pdrv;
+
+	c = &port->ctrl_ch;
+	if (test_bit(CH_READY, &c->flags) ||
+	    test_bit(CH_PREPARE_READY, &c->flags)) {
+		clear_bit(CH_PREPARE_READY, &c->flags);
+		pdrv = &ctrl_smd_ports[port->port_num].pdrv;
+		platform_driver_unregister(pdrv);
+	}
+}
+
 void gsmd_ctrl_disconnect(struct grmnet *gr, u8 port_num)
 {
 	struct rmnet_ctrl_port	*port;
@@ -435,6 +461,8 @@
 		smd_close(c->ch);
 		c->ch = NULL;
 	}
+
+	queue_delayed_work(grmnet_ctrl_wq, &port->disconnect_w, 0);
 }
 
 #define SMD_CH_MAX_LEN	20
@@ -452,6 +480,7 @@
 		c = &port->ctrl_ch;
 
 		if (!strncmp(c->name, pdev->name, SMD_CH_MAX_LEN)) {
+			clear_bit(CH_PREPARE_READY, &c->flags);
 			set_bit(CH_READY, &c->flags);
 
 			/* if usb is online, try opening smd_ch */
@@ -520,6 +549,7 @@
 
 	spin_lock_init(&port->port_lock);
 	INIT_DELAYED_WORK(&port->connect_w, grmnet_ctrl_smd_connect_w);
+	INIT_DELAYED_WORK(&port->disconnect_w, grmnet_ctrl_smd_disconnect_w);
 
 	c = &port->ctrl_ch;
 	c->name = rmnet_ctrl_names[portno];
@@ -537,8 +567,6 @@
 	pdrv->driver.name = c->name;
 	pdrv->driver.owner = THIS_MODULE;
 
-	platform_driver_register(pdrv);
-
 	pr_debug("%s: port:%p portno:%d\n", __func__, port, portno);
 
 	return 0;
diff --git a/drivers/usb/host/ehci-msm2.c b/drivers/usb/host/ehci-msm2.c
index 34d90fb..5c87691 100644
--- a/drivers/usb/host/ehci-msm2.c
+++ b/drivers/usb/host/ehci-msm2.c
@@ -1,6 +1,6 @@
 /* ehci-msm2.c - HSUSB Host Controller Driver Implementation
  *
- * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2013, The Linux Foundation. All rights reserved.
  *
  * Partly derived from ehci-fsl.c and ehci-hcd.c
  * Copyright (c) 2000-2004 by David Brownell
@@ -32,6 +32,7 @@
 #include <linux/usb/ulpi.h>
 #include <linux/usb/msm_hsusb_hw.h>
 #include <linux/usb/msm_hsusb.h>
+#include <linux/of.h>
 #include <mach/clk.h>
 #include <mach/msm_xo.h>
 #include <mach/msm_iomap.h>
@@ -42,10 +43,12 @@
 
 struct msm_hcd {
 	struct ehci_hcd				ehci;
+	spinlock_t				wakeup_lock;
 	struct device				*dev;
 	struct clk				*iface_clk;
 	struct clk				*core_clk;
 	struct clk				*alt_core_clk;
+	struct clk				*phy_sleep_clk;
 	struct regulator			*hsusb_vddcx;
 	struct regulator			*hsusb_3p3;
 	struct regulator			*hsusb_1p8;
@@ -60,6 +63,9 @@
 	atomic_t				pm_usage_cnt;
 	struct wake_lock			wlock;
 	struct work_struct			phy_susp_fail_work;
+	int					async_irq;
+	bool					async_irq_enabled;
+	uint32_t				async_int_cnt;
 };
 
 static inline struct msm_hcd *hcd_to_mhcd(struct usb_hcd *hcd)
@@ -272,6 +278,7 @@
 	int rc = 0;
 	struct usb_hcd *hcd = mhcd_to_hcd(mhcd);
 	const struct msm_usb_host_platform_data *pdata;
+	int ret = 0;
 
 	pdata = mhcd->dev->platform_data;
 
@@ -282,7 +289,11 @@
 	}
 
 	mhcd->vbus = devm_regulator_get(mhcd->dev, "vbus");
-	if (IS_ERR(mhcd->vbus)) {
+	ret = PTR_ERR(mhcd->vbus);
+	if (ret == -EPROBE_DEFER) {
+		pr_debug("failed to get vbus handle, defer probe\n");
+		return ret;
+	} else if (IS_ERR(mhcd->vbus)) {
 		pr_err("Unable to get vbus\n");
 		return -ENODEV;
 	}
@@ -435,18 +446,38 @@
 	return 0;
 }
 
+/**
+ * Do hard reset to USB hardware block using one of reset methodology based
+ * on availablity of alt_core_clk. There are two kinds of hardware resets.
+ * 1. Conventional synchronous reset where clocks to blocks to be ON while
+ * issuing the reset. 2. Asynchronous reset which requires clocks to be OFF.
+ */
 static int msm_ehci_link_clk_reset(struct msm_hcd *mhcd, bool assert)
 {
 	int ret;
 
 	if (assert) {
-		ret = clk_reset(mhcd->alt_core_clk, CLK_RESET_ASSERT);
+		if (!IS_ERR(mhcd->alt_core_clk)) {
+			ret = clk_reset(mhcd->alt_core_clk, CLK_RESET_ASSERT);
+		} else {
+			/* Using asynchronous block reset to the hardware */
+			clk_disable(mhcd->iface_clk);
+			clk_disable(mhcd->core_clk);
+			ret = clk_reset(mhcd->core_clk, CLK_RESET_ASSERT);
+		}
 		if (ret)
-			dev_err(mhcd->dev, "usb alt_core_clk assert failed\n");
+			dev_err(mhcd->dev, "usb clk assert failed\n");
 	} else {
-		ret = clk_reset(mhcd->alt_core_clk, CLK_RESET_DEASSERT);
+		if (!IS_ERR(mhcd->alt_core_clk)) {
+			ret = clk_reset(mhcd->alt_core_clk, CLK_RESET_DEASSERT);
+		} else {
+			ret = clk_reset(mhcd->core_clk, CLK_RESET_DEASSERT);
+			ndelay(200);
+			clk_enable(mhcd->core_clk);
+			clk_enable(mhcd->iface_clk);
+		}
 		if (ret)
-			dev_err(mhcd->dev, "usb alt_core_clk deassert failed\n");
+			dev_err(mhcd->dev, "usb clk deassert failed\n");
 	}
 
 	return ret;
@@ -455,6 +486,7 @@
 static int msm_ehci_phy_reset(struct msm_hcd *mhcd)
 {
 	struct usb_hcd *hcd = mhcd_to_hcd(mhcd);
+	struct msm_usb_host_platform_data *pdata;
 	u32 val;
 	int ret;
 	int retries;
@@ -463,12 +495,17 @@
 	if (ret)
 		return ret;
 
-	udelay(1);
+	usleep_range(10, 12);
 
 	ret = msm_ehci_link_clk_reset(mhcd, 0);
 	if (ret)
 		return ret;
 
+	pdata = mhcd->dev->platform_data;
+	if (pdata && pdata->use_sec_phy)
+		/* select secondary phy if offset is set for USB operation */
+		writel_relaxed(readl_relaxed(USB_PHY_CTRL2) | (1<<16),
+								USB_PHY_CTRL2);
 	val = readl_relaxed(USB_PORTSC) & ~PORTSC_PTS_MASK;
 	writel_relaxed(val | PORTSC_PTS_ULPI, USB_PORTSC);
 
@@ -499,10 +536,13 @@
 static int msm_hsusb_reset(struct msm_hcd *mhcd)
 {
 	struct usb_hcd *hcd = mhcd_to_hcd(mhcd);
+	struct msm_usb_host_platform_data *pdata;
 	unsigned long timeout;
 	int ret;
 
-	clk_prepare_enable(mhcd->alt_core_clk);
+	if (!IS_ERR(mhcd->alt_core_clk))
+		clk_prepare_enable(mhcd->alt_core_clk);
+
 	ret = msm_ehci_phy_reset(mhcd);
 	if (ret) {
 		dev_err(mhcd->dev, "phy_reset failed\n");
@@ -521,6 +561,11 @@
 	/* select ULPI phy */
 	writel_relaxed(0x80000000, USB_PORTSC);
 
+	pdata = mhcd->dev->platform_data;
+	if (pdata && pdata->use_sec_phy)
+		writel_relaxed(readl_relaxed(USB_PHY_CTRL2) | (1<<16),
+								USB_PHY_CTRL2);
+
 	msleep(100);
 
 	writel_relaxed(0x0, USB_AHBBURST);
@@ -528,7 +573,9 @@
 
 	/* Ensure that RESET operation is completed before turning off clock */
 	mb();
-	clk_disable_unprepare(mhcd->alt_core_clk);
+
+	if (!IS_ERR(mhcd->alt_core_clk))
+		clk_disable_unprepare(mhcd->alt_core_clk);
 
 	/*rising edge interrupts with Dp rise and fall enabled*/
 	msm_ulpi_write(mhcd, ULPI_INT_DP, ULPI_USB_INT_EN_RISE);
@@ -626,6 +673,11 @@
 		enable_irq_wake(mhcd->pmic_gpio_dp_irq);
 		enable_irq(mhcd->pmic_gpio_dp_irq);
 	}
+	if (mhcd->async_irq) {
+		mhcd->async_irq_enabled = 1;
+		enable_irq_wake(mhcd->async_irq);
+		enable_irq(mhcd->async_irq);
+	}
 	wake_unlock(&mhcd->wlock);
 
 	dev_info(mhcd->dev, "EHCI USB in low power mode\n");
@@ -639,6 +691,7 @@
 	unsigned long timeout;
 	unsigned temp;
 	int ret;
+	unsigned long flags;
 
 	if (!atomic_read(&mhcd->in_lpm)) {
 		dev_dbg(mhcd->dev, "%s called in !in_lpm\n", __func__);
@@ -650,6 +703,14 @@
 		disable_irq_nosync(mhcd->pmic_gpio_dp_irq);
 		mhcd->pmic_gpio_dp_irq_enabled = 0;
 	}
+	spin_lock_irqsave(&mhcd->wakeup_lock, flags);
+	if (mhcd->async_irq_enabled) {
+		disable_irq_wake(mhcd->async_irq);
+		disable_irq_nosync(mhcd->async_irq);
+		mhcd->async_irq_enabled = 0;
+	}
+	spin_unlock_irqrestore(&mhcd->wakeup_lock, flags);
+
 	wake_lock(&mhcd->wlock);
 
 	/* Vote for TCXO when waking up the phy */
@@ -722,6 +783,36 @@
 	return ehci_irq(hcd);
 }
 
+static irqreturn_t msm_async_irq(int irq, void *data)
+{
+	struct msm_hcd *mhcd = data;
+	int ret;
+
+	mhcd->async_int_cnt++;
+	dev_dbg(mhcd->dev, "%s: hsusb host remote wakeup interrupt cnt: %u\n",
+			__func__, mhcd->async_int_cnt);
+
+	wake_lock(&mhcd->wlock);
+
+	spin_lock(&mhcd->wakeup_lock);
+	if (mhcd->async_irq_enabled) {
+		mhcd->async_irq_enabled = 0;
+		disable_irq_wake(irq);
+		disable_irq_nosync(irq);
+	}
+	spin_unlock(&mhcd->wakeup_lock);
+
+	if (!atomic_read(&mhcd->pm_usage_cnt)) {
+		ret = pm_runtime_get(mhcd->dev);
+		if ((ret == 1) || (ret == -EINPROGRESS))
+			pm_runtime_put_noidle(mhcd->dev);
+		else
+			atomic_set(&mhcd->pm_usage_cnt, 1);
+	}
+
+	return IRQ_HANDLED;
+}
+
 static irqreturn_t msm_ehci_host_wakeup_irq(int irq, void *data)
 {
 
@@ -751,6 +842,8 @@
 static int msm_ehci_reset(struct usb_hcd *hcd)
 {
 	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+	struct msm_hcd *mhcd = hcd_to_mhcd(hcd);
+	struct msm_usb_host_platform_data *pdata;
 	int retval;
 
 	ehci->caps = USB_CAPLENGTH;
@@ -785,6 +878,11 @@
 	/* Disable streaming mode and select host mode */
 	writel_relaxed(0x13, USB_USBMODE);
 
+	pdata = mhcd->dev->platform_data;
+	if (pdata && pdata->use_sec_phy)
+		writel_relaxed(readl_relaxed(USB_PHY_CTRL2) | (1<<16),
+								USB_PHY_CTRL2);
+
 	ehci_port_power(ehci, 1);
 	return 0;
 }
@@ -844,12 +942,10 @@
 
 	/* 60MHz alt_core_clk is for LINK to be used during PHY RESET  */
 	mhcd->alt_core_clk = clk_get(mhcd->dev, "alt_core_clk");
-	if (IS_ERR(mhcd->alt_core_clk)) {
-		dev_err(mhcd->dev, "failed to get alt_core_clk\n");
-		ret = PTR_ERR(mhcd->alt_core_clk);
-		return ret;
-	}
-	clk_set_rate(mhcd->alt_core_clk, 60000000);
+	if (IS_ERR(mhcd->alt_core_clk))
+		dev_dbg(mhcd->dev, "failed to get alt_core_clk\n");
+	else
+		clk_set_rate(mhcd->alt_core_clk, 60000000);
 
 	/* iface_clk is required for data transfers */
 	mhcd->iface_clk = clk_get(mhcd->dev, "iface_clk");
@@ -871,6 +967,12 @@
 	}
 	clk_set_rate(mhcd->core_clk, INT_MAX);
 
+	mhcd->phy_sleep_clk = clk_get(mhcd->dev, "sleep_clk");
+	if (IS_ERR(mhcd->phy_sleep_clk))
+		dev_dbg(mhcd->dev, "failed to get sleep_clk\n");
+	else
+		clk_prepare_enable(mhcd->phy_sleep_clk);
+
 	clk_prepare_enable(mhcd->core_clk);
 	clk_prepare_enable(mhcd->iface_clk);
 
@@ -880,14 +982,39 @@
 	clk_disable_unprepare(mhcd->iface_clk);
 	clk_disable_unprepare(mhcd->core_clk);
 	clk_put(mhcd->core_clk);
+	if (!IS_ERR(mhcd->phy_sleep_clk)) {
+		clk_disable_unprepare(mhcd->phy_sleep_clk);
+		clk_put(mhcd->phy_sleep_clk);
+	}
 put_iface_clk:
 	clk_put(mhcd->iface_clk);
 put_alt_core_clk:
-	clk_put(mhcd->alt_core_clk);
+	if (!IS_ERR(mhcd->alt_core_clk))
+		clk_put(mhcd->alt_core_clk);
 
 	return ret;
 }
 
+struct msm_usb_host_platform_data *ehci_msm2_dt_to_pdata(
+				struct platform_device *pdev)
+{
+	struct device_node *node = pdev->dev.of_node;
+	struct msm_usb_host_platform_data *pdata;
+
+	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata) {
+		dev_err(&pdev->dev, "unable to allocate platform data\n");
+		return NULL;
+	}
+
+	pdata->use_sec_phy = of_property_read_bool(node,
+					"qcom,usb2-enable-hsphy2");
+	of_property_read_u32(node, "qcom,usb2-power-budget",
+					&pdata->power_budget);
+	return pdata;
+}
+
+static u64 ehci_msm_dma_mask = DMA_BIT_MASK(64);
 static int __devinit ehci_msm2_probe(struct platform_device *pdev)
 {
 	struct usb_hcd *hcd;
@@ -899,6 +1026,19 @@
 
 	dev_dbg(&pdev->dev, "ehci_msm2 probe\n");
 
+	if (pdev->dev.of_node) {
+		dev_dbg(&pdev->dev, "device tree enabled\n");
+		pdev->dev.platform_data = ehci_msm2_dt_to_pdata(pdev);
+	}
+
+	if (!pdev->dev.platform_data)
+		dev_dbg(&pdev->dev, "No platform data given\n");
+
+	if (!pdev->dev.dma_mask)
+		pdev->dev.dma_mask = &ehci_msm_dma_mask;
+	if (!pdev->dev.coherent_dma_mask)
+		pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+
 	hcd = usb_create_hcd(&msm_hc2_driver, &pdev->dev,
 				dev_name(&pdev->dev));
 	if (!hcd) {
@@ -932,13 +1072,29 @@
 	mhcd = hcd_to_mhcd(hcd);
 	mhcd->dev = &pdev->dev;
 
+	spin_lock_init(&mhcd->wakeup_lock);
+
+	mhcd->async_irq = platform_get_irq_byname(pdev, "async_irq");
+	if (mhcd->async_irq < 0) {
+		dev_dbg(&pdev->dev, "platform_get_irq for async_int failed\n");
+		mhcd->async_irq = 0;
+	} else {
+		ret = request_irq(mhcd->async_irq, msm_async_irq,
+				IRQF_TRIGGER_RISING, "msm_ehci_host", mhcd);
+		if (ret) {
+			dev_err(&pdev->dev, "request irq failed (ASYNC INT)\n");
+			goto unmap;
+		}
+		disable_irq(mhcd->async_irq);
+	}
+
 	snprintf(pdev_name, PDEV_NAME_LEN, "%s.%d", pdev->name, pdev->id);
 	mhcd->xo_handle = msm_xo_get(MSM_XO_TCXO_D0, pdev_name);
 	if (IS_ERR(mhcd->xo_handle)) {
 		dev_err(&pdev->dev, "%s not able to get the handle "
 			"to vote for TCXO D0 buffer\n", __func__);
 		ret = PTR_ERR(mhcd->xo_handle);
-		goto unmap;
+		goto free_async_irq;
 	}
 
 	ret = msm_xo_mode_vote(mhcd->xo_handle, MSM_XO_MODE_ON);
@@ -1047,6 +1203,9 @@
 	msm_xo_mode_vote(mhcd->xo_handle, MSM_XO_MODE_OFF);
 free_xo_handle:
 	msm_xo_put(mhcd->xo_handle);
+free_async_irq:
+	if (mhcd->async_irq)
+		free_irq(mhcd->async_irq, mhcd);
 unmap:
 	iounmap(hcd->regs);
 put_hcd:
@@ -1065,6 +1224,11 @@
 			disable_irq_wake(mhcd->pmic_gpio_dp_irq);
 		free_irq(mhcd->pmic_gpio_dp_irq, mhcd);
 	}
+	if (mhcd->async_irq) {
+		if (mhcd->async_irq_enabled)
+			disable_irq_wake(mhcd->async_irq);
+		free_irq(mhcd->async_irq, mhcd);
+	}
 	device_init_wakeup(&pdev->dev, 0);
 	pm_runtime_disable(&pdev->dev);
 	pm_runtime_set_suspended(&pdev->dev);
@@ -1160,6 +1324,12 @@
 };
 #endif
 
+static const struct of_device_id ehci_msm2_dt_match[] = {
+	{ .compatible = "qcom,ehci-host",
+	},
+	{}
+};
+
 static struct platform_driver ehci_msm2_driver = {
 	.probe	= ehci_msm2_probe,
 	.remove	= __devexit_p(ehci_msm2_remove),
@@ -1168,5 +1338,6 @@
 #ifdef CONFIG_PM
 		.pm = &ehci_msm2_dev_pm_ops,
 #endif
+		.of_match_table = ehci_msm2_dt_match,
 	},
 };
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index e55fed7..79dcf2f 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -122,6 +122,7 @@
 	if (!hcd)
 		return -ENOMEM;
 
+	hcd_to_bus(hcd)->skip_resume = true;
 	hcd->rsrc_start = res->start;
 	hcd->rsrc_len = resource_size(res);
 
@@ -153,6 +154,7 @@
 		goto dealloc_usb2_hcd;
 	}
 
+	hcd_to_bus(xhci->shared_hcd)->skip_resume = true;
 	/*
 	 * Set the xHCI pointer before xhci_plat_setup() (aka hcd_driver.reset)
 	 * is called by usb_add_hcd().
@@ -173,6 +175,8 @@
 			usb_put_transceiver(phy);
 			goto put_usb3_hcd;
 		}
+		pm_runtime_set_active(&pdev->dev);
+		pm_runtime_enable(&pdev->dev);
 	} else {
 		pm_runtime_no_callbacks(&pdev->dev);
 		pm_runtime_set_active(&pdev->dev);
@@ -205,6 +209,7 @@
 	struct usb_hcd	*hcd = platform_get_drvdata(dev);
 	struct xhci_hcd	*xhci = hcd_to_xhci(hcd);
 
+
 	usb_remove_hcd(xhci->shared_hcd);
 	usb_put_hcd(xhci->shared_hcd);
 
@@ -225,11 +230,74 @@
 	return 0;
 }
 
+#ifdef CONFIG_PM_RUNTIME
+static int xhci_msm_runtime_idle(struct device *dev)
+{
+	dev_dbg(dev, "xhci msm runtime idle\n");
+	return 0;
+}
+
+static int xhci_msm_runtime_suspend(struct device *dev)
+{
+	dev_dbg(dev, "xhci msm runtime suspend\n");
+	/*
+	 * Notify OTG about suspend.  It takes care of
+	 * putting the hardware in LPM.
+	 */
+	if (phy)
+		return usb_phy_set_suspend(phy, 1);
+
+	return 0;
+}
+
+static int xhci_msm_runtime_resume(struct device *dev)
+{
+	dev_dbg(dev, "xhci msm runtime resume\n");
+
+	if (phy)
+		return usb_phy_set_suspend(phy, 0);
+
+	return 0;
+}
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+static int xhci_msm_pm_suspend(struct device *dev)
+{
+	dev_dbg(dev, "xhci-msm PM suspend\n");
+
+	if (phy)
+		return usb_phy_set_suspend(phy, 1);
+
+	return 0;
+}
+
+static int xhci_msm_pm_resume(struct device *dev)
+{
+	dev_dbg(dev, "xhci-msm PM resume\n");
+
+	if (pm_runtime_suspended(dev))
+		return 0;
+
+	if (phy)
+		return usb_phy_set_suspend(phy, 0);
+
+	return 0;
+}
+#endif
+
+static const struct dev_pm_ops xhci_msm_dev_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(xhci_msm_pm_suspend, xhci_msm_pm_resume)
+	SET_RUNTIME_PM_OPS(xhci_msm_runtime_suspend, xhci_msm_runtime_resume,
+				xhci_msm_runtime_idle)
+};
+
 static struct platform_driver usb_xhci_driver = {
 	.probe	= xhci_plat_probe,
 	.remove	= xhci_plat_remove,
 	.driver	= {
 		.name = "xhci-hcd",
+		.pm = &xhci_msm_dev_pm_ops,
 	},
 };
 MODULE_ALIAS("platform:xhci-hcd");
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 2c26998..df41b4f 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -2464,7 +2464,7 @@
 	/* Wait for the configure endpoint command to complete */
 	timeleft = wait_for_completion_interruptible_timeout(
 			cmd_completion,
-			USB_CTRL_SET_TIMEOUT);
+			XHCI_CMD_DEFAULT_TIMEOUT);
 	if (timeleft <= 0) {
 		xhci_warn(xhci, "%s while waiting for %s command\n",
 				timeleft == 0 ? "Timeout" : "Signal",
@@ -3433,7 +3433,7 @@
 
 	/* XXX: how much time for xHC slot assignment? */
 	timeleft = wait_for_completion_interruptible_timeout(&xhci->addr_dev,
-			USB_CTRL_SET_TIMEOUT);
+			XHCI_CMD_DEFAULT_TIMEOUT);
 	if (timeleft <= 0) {
 		xhci_warn(xhci, "%s while waiting for a slot\n",
 				timeleft == 0 ? "Timeout" : "Signal");
@@ -3549,7 +3549,7 @@
 
 	/* ctrl tx can take up to 5 sec; XXX: need more time for xHC? */
 	timeleft = wait_for_completion_interruptible_timeout(&xhci->addr_dev,
-			USB_CTRL_SET_TIMEOUT);
+			XHCI_CMD_DEFAULT_TIMEOUT);
 	/* FIXME: From section 4.3.4: "Software shall be responsible for timing
 	 * the SetAddress() "recovery interval" required by USB and aborting the
 	 * command on a timeout.
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 127b0e9..8f3651b 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1248,6 +1248,9 @@
 	union xhci_trb		*last_trb;
 };
 
+/* xHCI command default timeout value */
+#define XHCI_CMD_DEFAULT_TIMEOUT	(5 * HZ)
+
 struct xhci_dequeue_state {
 	struct xhci_segment *new_deq_seg;
 	union xhci_trb *new_deq_ptr;
diff --git a/drivers/usb/misc/mdm_data_bridge.c b/drivers/usb/misc/mdm_data_bridge.c
index 655e2f6..fcbf0e1 100644
--- a/drivers/usb/misc/mdm_data_bridge.c
+++ b/drivers/usb/misc/mdm_data_bridge.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2013, Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -343,6 +343,9 @@
 
 	dev_dbg(&dev->intf->dev, "%s:\n", __func__);
 
+	cancel_work_sync(&dev->kevent);
+	cancel_work_sync(&dev->process_rx_w);
+
 	usb_unlink_anchored_urbs(&dev->tx_active);
 	usb_unlink_anchored_urbs(&dev->rx_active);
 	usb_unlink_anchored_urbs(&dev->delayed);
@@ -995,9 +998,6 @@
 	usb_set_intfdata(intf, NULL);
 	__dev[dev->id] = NULL;
 
-	cancel_work_sync(&dev->process_rx_w);
-	cancel_work_sync(&dev->kevent);
-
 	/*free rx urbs*/
 	head = &dev->rx_idle;
 	spin_lock_irqsave(&dev->rx_done.lock, flags);
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index 38fc969..2423de5 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -3087,14 +3087,11 @@
 	int ret = 0;
 	unsigned int ptr;
 
-	if (addr == NULL)
-		goto end;
-
 	ptr = (unsigned int) addr;
 
 	if (mdp_rev >= MDP_REV_30 && mdp_rev < MDP_REV_40) {
 		/* if request is outside the MDP reg-map or is not aligned 4 */
-		if (ptr > 0xF0600 || ptr % 0x4)
+		if (ptr == 0x0 || ptr > 0xF0600 || ptr % 0x4)
 			goto end;
 
 		if (ptr >= 0x90000 && ptr < 0x94000) {
@@ -3119,7 +3116,8 @@
 			goto end;
 
 		if (ptr < 0x90000) {
-			if (ptr == 0x4 || ptr == 0x28200 || ptr == 0x28204)
+			if (ptr == 0x0 || ptr == 0x4 || ptr == 0x28200 ||
+								ptr == 0x28204)
 				ret = 1;
 		} else if (ptr < 0x95000) {
 			if (ptr == 0x90000 || ptr == 0x90070)
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 4404b9d..80db0b2 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -370,9 +370,6 @@
 	mfd->suspend.op_enable = mfd->op_enable;
 	mfd->suspend.panel_power_on = mfd->panel_power_on;
 
-	del_timer(&mfd->no_update.timer);
-	complete(&mfd->no_update.comp);
-
 	if (mfd->op_enable) {
 		ret = mdss_fb_blank_sub(FB_BLANK_POWERDOWN, mfd->fbi,
 				mfd->suspend.op_enable);
@@ -581,6 +578,9 @@
 		if (mfd->panel_power_on) {
 			int curr_pwr_state;
 
+			del_timer(&mfd->no_update.timer);
+			complete(&mfd->no_update.comp);
+
 			mfd->op_enable = false;
 			curr_pwr_state = mfd->panel_power_on;
 			mfd->panel_power_on = false;
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 7ca06ff..cd836a0 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -1,7 +1,7 @@
 /*
  * MDSS MDP Interface (used by framebuffer core)
  *
- * Copyright (c) 2007-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2007-2013, The Linux Foundation. All rights reserved.
  * Copyright (C) 2007 Google Incorporated
  *
  * This software is licensed under the terms of the GNU General Public
@@ -1087,7 +1087,7 @@
 {
 	mdata->early_suspend.suspend = mdss_mdp_early_suspend;
 	mdata->early_suspend.resume = mdss_mdp_late_resume;
-	mdata->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN;
+	mdata->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
 	register_early_suspend(&mdata->early_suspend);
 
 	return 0;
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index ef6e5b4..40cca22 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -308,6 +308,7 @@
 int mdss_mdp_csc_setup_data(u32 block, u32 blk_idx, u32 tbl_idx,
 				   struct mdp_csc_cfg *data);
 
+int mdss_mdp_pipe_pp_setup(struct mdss_mdp_pipe *pipe, u32 *op);
 int mdss_mdp_pp_setup(struct mdss_mdp_ctl *ctl);
 int mdss_mdp_pcc_config(struct mdp_pcc_cfg_data *cfg_ptr, u32 *copyback);
 
diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h
index b6ac126..a7f0148 100644
--- a/drivers/video/msm/mdss/mdss_mdp_hwio.h
+++ b/drivers/video/msm/mdss/mdss_mdp_hwio.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -340,6 +340,7 @@
 #define MDSS_MDP_REG_DSPP_HIST_LUT_BASE			0x230
 #define MDSS_MDP_REG_DSPP_PA_BASE			0x238
 #define MDSS_MDP_REG_DSPP_GAMUT_BASE			0x2DC
+#define MDSS_MDP_REG_DSPP_GC_BASE			0x2B0
 
 enum mdss_mpd_intf_index {
 	MDSS_MDP_NO_INTF,
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 338cf87..3956228 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -263,11 +263,11 @@
 
 	pipe = mdss_mdp_mixer_stage_pipe(mfd->ctl, mixer_mux, req->z_order);
 	if (pipe && pipe->ndx != req->id) {
-		pr_err("stage %d taken by pnum=%d\n", req->z_order, pipe->num);
-		return -EBUSY;
+		pr_debug("replacing pnum=%d at stage=%d mux=%d\n",
+				pipe->num, req->z_order, mixer_mux);
+		pipe->params_changed = true;
 	}
 
-
 	if (req->id == MSMFB_NEW_REQUEST) {
 		mixer = mdss_mdp_mixer_get(mfd->ctl, mixer_mux);
 		if (!mixer) {
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index 89f3405..4ece15d 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -584,43 +584,6 @@
 	return 0;
 }
 
-static int mdss_mdp_vig_setup(struct mdss_mdp_pipe *pipe)
-{
-	u32 opmode = 0;
-
-	pr_debug("pnum=%x\n", pipe->num);
-
-	/* CSC Post Processing enabled? */
-	if (pipe->flags & MDP_OVERLAY_PP_CFG_EN) {
-		if (pipe->pp_cfg.config_ops & MDP_OVERLAY_PP_CSC_CFG) {
-			if (pipe->pp_cfg.csc_cfg.flags & MDP_CSC_FLAG_ENABLE)
-				opmode |= 1 << 17;	/* CSC_1_EN */
-			if (pipe->pp_cfg.csc_cfg.flags & MDP_CSC_FLAG_YUV_IN)
-				opmode |= 1 << 18;	/* SRC_DATA=YCBCR */
-			if (pipe->pp_cfg.csc_cfg.flags & MDP_CSC_FLAG_YUV_OUT)
-				opmode |= 1 << 19;	/* DST_DATA=YCBCR */
-			/* only need to program once */
-			if (pipe->play_cnt == 0)
-				mdss_mdp_csc_setup_data(MDSS_MDP_BLOCK_SSPP,
-				  pipe->num, 1, &pipe->pp_cfg.csc_cfg);
-		}
-	} else {
-		if (pipe->src_fmt->is_yuv)
-			opmode |= (0 << 19) |	/* DST_DATA=RGB */
-				  (1 << 18) |	/* SRC_DATA=YCBCR */
-				  (1 << 17);	/* CSC_1_EN */
-		/* only need to program once */
-		if (pipe->play_cnt == 0) {
-			mdss_mdp_csc_setup(MDSS_MDP_BLOCK_SSPP, pipe->num, 1,
-					   MDSS_MDP_CSC_YUV2RGB);
-		}
-	}
-
-	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_VIG_OP_MODE, opmode);
-
-	return 0;
-}
-
 static void mdss_mdp_addr_add_offset(struct mdss_mdp_pipe *pipe,
 				    struct mdss_mdp_data *data)
 {
@@ -678,7 +641,7 @@
 			     struct mdss_mdp_data *src_data)
 {
 	int ret = 0;
-	u32 params_changed;
+	u32 params_changed, opmode;
 
 	if (!pipe) {
 		pr_err("pipe not setup properly for queue\n");
@@ -712,8 +675,10 @@
 			goto done;
 		}
 
+		mdss_mdp_pipe_pp_setup(pipe, &opmode);
 		if (pipe->type == MDSS_MDP_PIPE_TYPE_VIG)
-			mdss_mdp_vig_setup(pipe);
+			mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_VIG_OP_MODE,
+			opmode);
 
 		ret = mdss_mdp_smp_reserve(pipe);
 		if (ret) {
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 1482935..42e7337 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -131,6 +131,7 @@
 	u32 enhist_sts;
 	u32 dither_sts;
 	u32 gamut_sts;
+	u32 pgc_sts;
 };
 
 #define PP_FLAGS_DIRTY_PA	0x1
@@ -141,6 +142,7 @@
 #define PP_FLAGS_DIRTY_DITHER	0x20
 #define PP_FLAGS_DIRTY_GAMUT	0x40
 #define PP_FLAGS_DIRTY_HIST_COL	0x80
+#define PP_FLAGS_DIRTY_PGC	0x100
 
 #define PP_STS_ENABLE	0x1
 #define PP_STS_GAMUT_FIRST	0x2
@@ -157,9 +159,10 @@
 	struct mdp_ar_gc_lut_data
 		gc_lut_b[MDSS_BLOCK_DISP_NUM][GC_LUT_SEGMENTS];
 	u32 enhist_lut[MDSS_BLOCK_DISP_NUM][ENHIST_LUT_ENTRIES];
-	struct mdp_pa_cfg_data pa_disp_cfg[MDSS_BLOCK_DISP_NUM];
+	struct mdp_pa_cfg pa_disp_cfg[MDSS_BLOCK_DISP_NUM];
 	struct mdp_pcc_cfg_data pcc_disp_cfg[MDSS_BLOCK_DISP_NUM];
 	struct mdp_igc_lut_data igc_disp_cfg[MDSS_BLOCK_DISP_NUM];
+	struct mdp_pgc_lut_data argc_disp_cfg[MDSS_BLOCK_DISP_NUM];
 	struct mdp_pgc_lut_data pgc_disp_cfg[MDSS_BLOCK_DISP_NUM];
 	struct mdp_hist_lut_data enhist_disp_cfg[MDSS_BLOCK_DISP_NUM];
 	struct mdp_dither_cfg_data dither_disp_cfg[MDSS_BLOCK_DISP_NUM];
@@ -178,19 +181,29 @@
 static DEFINE_MUTEX(mdss_mdp_hist_mutex);
 static struct mdss_pp_res_type *mdss_pp_res;
 
-
 static void pp_hist_read(u32 v_base, struct pp_hist_col_info *hist_info);
-
 static void pp_update_pcc_regs(u32 offset,
 				struct mdp_pcc_cfg_data *cfg_ptr);
 static void pp_update_igc_lut(struct mdp_igc_lut_data *cfg,
 				u32 offset, u32 blk_idx);
 static void pp_update_gc_one_lut(u32 offset,
-		struct mdp_ar_gc_lut_data *lut_data);
+				struct mdp_ar_gc_lut_data *lut_data);
 static void pp_update_argc_lut(u32 offset,
-		struct mdp_pgc_lut_data *config);
+				struct mdp_pgc_lut_data *config);
 static void pp_update_hist_lut(u32 offset, struct mdp_hist_lut_data *cfg);
-
+static void pp_pa_config(unsigned long flags, u32 base,
+				struct pp_sts_type *pp_sts,
+				struct mdp_pa_cfg *pa_config);
+static void pp_pcc_config(unsigned long flags, u32 base,
+				struct pp_sts_type *pp_sts,
+				struct mdp_pcc_cfg_data *pcc_config);
+static void pp_igc_config(unsigned long flags, u32 base,
+				struct pp_sts_type *pp_sts,
+				struct mdp_igc_lut_data *igc_config,
+				u32 pipe_num);
+static void pp_enhist_config(unsigned long flags, u32 base,
+				struct pp_sts_type *pp_sts,
+				struct mdp_hist_lut_data *enhist_cfg);
 
 int mdss_mdp_csc_setup_data(u32 block, u32 blk_idx, u32 tbl_idx,
 				   struct mdp_csc_cfg *data)
@@ -280,51 +293,9 @@
 	data = &mdp_csc_convert[csc_type];
 	return mdss_mdp_csc_setup_data(block, blk_idx, tbl_idx, data);
 }
-static int pp_mixer_setup(u32 disp_num, struct mdss_mdp_ctl *ctl,
-		struct mdss_mdp_mixer *mixer)
-{
-	u32 flags, offset, dspp_num, opmode = 0;
-	struct mdp_pgc_lut_data *pgc_config;
-	struct pp_sts_type *pp_sts;
-	dspp_num = mixer->num;
-	/* no corresponding dspp */
-	if ((mixer->type != MDSS_MDP_MIXER_TYPE_INTF) ||
-		(dspp_num >= MDSS_MDP_MAX_DSPP))
-		return 0;
-	if (disp_num < MDSS_BLOCK_DISP_NUM)
-		flags = mdss_pp_res->pp_disp_flags[disp_num];
-	else
-		flags = 0;
 
-	pp_sts = &mdss_pp_res->pp_dspp_sts[dspp_num];
-	/* GC_LUT is in layer mixer */
-	if (flags & PP_FLAGS_DIRTY_ARGC) {
-		pgc_config = &mdss_pp_res->pgc_disp_cfg[disp_num];
-		if (pgc_config->flags & MDP_PP_OPS_WRITE) {
-			offset = MDSS_MDP_REG_LM_OFFSET(disp_num) +
-				MDSS_MDP_REG_LM_GC_LUT_BASE;
-			pp_update_argc_lut(offset, pgc_config);
-		}
-		if (pgc_config->flags & MDP_PP_OPS_DISABLE)
-			pp_sts->argc_sts &= ~PP_STS_ENABLE;
-		else if (pgc_config->flags & MDP_PP_OPS_ENABLE)
-			pp_sts->argc_sts |= PP_STS_ENABLE;
-		ctl->flush_bits |= BIT(6) << dspp_num; /* LAYER_MIXER */
-	}
-	/* update LM opmode if LM needs flush */
-	if ((pp_sts->argc_sts & PP_STS_ENABLE) &&
-		(ctl->flush_bits & (BIT(6) << dspp_num))) {
-		offset = MDSS_MDP_REG_LM_OFFSET(dspp_num) +
-			MDSS_MDP_REG_LM_OP_MODE;
-		opmode = MDSS_MDP_REG_READ(offset);
-		opmode |= (1 << 0); /* GC_LUT_EN */
-		MDSS_MDP_REG_WRITE(offset, opmode);
-	}
-	return 0;
-}
 static void pp_gamut_config(struct mdp_gamut_cfg_data *gamut_cfg,
-							u32 base,
-							u32 *gamut_sts)
+				u32 base, u32 *gamut_sts)
 {
 	u32 offset;
 	int i, j;
@@ -358,30 +329,198 @@
 		*gamut_sts |= PP_STS_ENABLE;
 }
 
-/* Note: Assumes that its inputs have been checked by calling function */
-static void pp_update_hist_lut(u32 offset, struct mdp_hist_lut_data *cfg)
+static void pp_pa_config(unsigned long flags, u32 base,
+				struct pp_sts_type *pp_sts,
+				struct mdp_pa_cfg *pa_config)
 {
-	int i;
-	for (i = 0; i < ENHIST_LUT_ENTRIES; i++)
-		MDSS_MDP_REG_WRITE(offset, cfg->data[i]);
-	/* swap */
-	MDSS_MDP_REG_WRITE(offset + 4, 1);
+	if (flags & PP_FLAGS_DIRTY_PA) {
+		if (pa_config->flags & MDP_PP_OPS_WRITE) {
+			MDSS_MDP_REG_WRITE(base, pa_config->hue_adj);
+			base += 4;
+			MDSS_MDP_REG_WRITE(base, pa_config->sat_adj);
+			base += 4;
+			MDSS_MDP_REG_WRITE(base, pa_config->val_adj);
+			base += 4;
+			MDSS_MDP_REG_WRITE(base, pa_config->cont_adj);
+		}
+		if (pa_config->flags & MDP_PP_OPS_DISABLE)
+			pp_sts->pa_sts &= ~PP_STS_ENABLE;
+		else if (pa_config->flags & MDP_PP_OPS_ENABLE)
+			pp_sts->pa_sts |= PP_STS_ENABLE;
+	}
+}
+
+static void pp_pcc_config(unsigned long flags, u32 base,
+				struct pp_sts_type *pp_sts,
+				struct mdp_pcc_cfg_data *pcc_config)
+{
+	if (flags & PP_FLAGS_DIRTY_PCC) {
+		if (pcc_config->ops & MDP_PP_OPS_WRITE)
+			pp_update_pcc_regs(base, pcc_config);
+
+		if (pcc_config->ops & MDP_PP_OPS_DISABLE)
+			pp_sts->pcc_sts &= ~PP_STS_ENABLE;
+		else if (pcc_config->ops & MDP_PP_OPS_ENABLE)
+			pp_sts->pcc_sts |= PP_STS_ENABLE;
+	}
+}
+
+static void pp_igc_config(unsigned long flags, u32 base,
+				struct pp_sts_type *pp_sts,
+				struct mdp_igc_lut_data *igc_config,
+				u32 pipe_num)
+{
+	u32 tbl_idx;
+	if (flags & PP_FLAGS_DIRTY_IGC) {
+		if (igc_config->ops & MDP_PP_OPS_WRITE)
+			pp_update_igc_lut(igc_config, base, pipe_num);
+
+		if (igc_config->ops & MDP_PP_IGC_FLAG_ROM0) {
+			pp_sts->pcc_sts |= PP_STS_ENABLE;
+			tbl_idx = 1;
+		} else if (igc_config->ops & MDP_PP_IGC_FLAG_ROM1) {
+			pp_sts->pcc_sts |= PP_STS_ENABLE;
+			tbl_idx = 2;
+		} else {
+			tbl_idx = 0;
+		}
+		pp_sts->igc_tbl_idx = tbl_idx;
+		if (igc_config->ops & MDP_PP_OPS_DISABLE)
+			pp_sts->igc_sts &= ~PP_STS_ENABLE;
+		else if (igc_config->ops & MDP_PP_OPS_ENABLE)
+			pp_sts->igc_sts |= PP_STS_ENABLE;
+	}
+}
+
+static void pp_enhist_config(unsigned long flags, u32 base,
+				struct pp_sts_type *pp_sts,
+				struct mdp_hist_lut_data *enhist_cfg)
+{
+	if (flags & PP_FLAGS_DIRTY_ENHIST) {
+		if (enhist_cfg->ops & MDP_PP_OPS_WRITE)
+			pp_update_hist_lut(base, enhist_cfg);
+
+		if (enhist_cfg->ops & MDP_PP_OPS_DISABLE)
+			pp_sts->enhist_sts &= ~PP_STS_ENABLE;
+		else if (enhist_cfg->ops & MDP_PP_OPS_ENABLE)
+			pp_sts->enhist_sts |= PP_STS_ENABLE;
+	}
+}
+
+static int pp_vig_pipe_setup(struct mdss_mdp_pipe *pipe, u32 *op)
+{
+	u32 opmode = 0;
+
+	pr_debug("pnum=%x\n", pipe->num);
+
+	if (pipe->flags & MDP_OVERLAY_PP_CFG_EN) {
+		if (pipe->pp_cfg.config_ops & MDP_OVERLAY_PP_CSC_CFG) {
+			opmode |= !!(pipe->pp_cfg.csc_cfg.flags &
+						MDP_CSC_FLAG_ENABLE) << 17;
+			opmode |= !!(pipe->pp_cfg.csc_cfg.flags &
+						MDP_CSC_FLAG_YUV_IN) << 18;
+			opmode |= !!(pipe->pp_cfg.csc_cfg.flags &
+						MDP_CSC_FLAG_YUV_OUT) << 19;
+			/*
+			 * TODO: Allow pipe to be programmed whenever new CSC is
+			 * applied (i.e. dirty bit)
+			 */
+			if (pipe->play_cnt == 0)
+				mdss_mdp_csc_setup_data(MDSS_MDP_BLOCK_SSPP,
+				  pipe->num, 1, &pipe->pp_cfg.csc_cfg);
+		}
+	} else {
+		if (pipe->src_fmt->is_yuv)
+			opmode |= (0 << 19) |	/* DST_DATA=RGB */
+				  (1 << 18) |	/* SRC_DATA=YCBCR */
+				  (1 << 17);	/* CSC_1_EN */
+		/*
+		 * TODO: Needs to be part of dirty bit logic: if there is a
+		 * previously configured pipe need to re-configure CSC matrix
+		 */
+		if (pipe->play_cnt == 0) {
+			mdss_mdp_csc_setup(MDSS_MDP_BLOCK_SSPP, pipe->num, 1,
+					   MDSS_MDP_CSC_YUV2RGB);
+		}
+	}
+
+	*op = opmode;
+
+	return 0;
+}
+
+int mdss_mdp_pipe_pp_setup(struct mdss_mdp_pipe *pipe, u32 *op)
+{
+	int ret = 0;
+	if (!pipe)
+		return -ENODEV;
+
+	if (pipe->type == MDSS_MDP_PIPE_TYPE_VIG)
+		ret = pp_vig_pipe_setup(pipe, op);
+	else if (pipe->type == MDSS_MDP_PIPE_TYPE_RGB)
+		ret = -EINVAL;
+	else if (pipe->type == MDSS_MDP_PIPE_TYPE_DMA)
+		ret = -EINVAL;
+
+	return ret;
+}
+
+static int pp_mixer_setup(u32 disp_num, struct mdss_mdp_ctl *ctl,
+		struct mdss_mdp_mixer *mixer)
+{
+	u32 flags, offset, dspp_num, opmode = 0;
+	struct mdp_pgc_lut_data *pgc_config;
+	struct pp_sts_type *pp_sts;
+	dspp_num = mixer->num;
+
+	/* no corresponding dspp */
+	if ((mixer->type != MDSS_MDP_MIXER_TYPE_INTF) ||
+		(dspp_num >= MDSS_MDP_MAX_DSPP))
+		return 0;
+	if (disp_num < MDSS_BLOCK_DISP_NUM)
+		flags = mdss_pp_res->pp_disp_flags[disp_num];
+	else
+		flags = 0;
+
+	pp_sts = &mdss_pp_res->pp_dspp_sts[dspp_num];
+	/* GC_LUT is in layer mixer */
+	if (flags & PP_FLAGS_DIRTY_ARGC) {
+		pgc_config = &mdss_pp_res->argc_disp_cfg[disp_num];
+		if (pgc_config->flags & MDP_PP_OPS_WRITE) {
+			offset = MDSS_MDP_REG_LM_OFFSET(disp_num) +
+				MDSS_MDP_REG_LM_GC_LUT_BASE;
+			pp_update_argc_lut(offset, pgc_config);
+		}
+		if (pgc_config->flags & MDP_PP_OPS_DISABLE)
+			pp_sts->argc_sts &= ~PP_STS_ENABLE;
+		else if (pgc_config->flags & MDP_PP_OPS_ENABLE)
+			pp_sts->argc_sts |= PP_STS_ENABLE;
+		ctl->flush_bits |= BIT(6) << dspp_num; /* LAYER_MIXER */
+	}
+	/* update LM opmode if LM needs flush */
+	if ((pp_sts->argc_sts & PP_STS_ENABLE) &&
+		(ctl->flush_bits & (BIT(6) << dspp_num))) {
+		offset = MDSS_MDP_REG_LM_OFFSET(dspp_num) +
+			MDSS_MDP_REG_LM_OP_MODE;
+		opmode = MDSS_MDP_REG_READ(offset);
+		opmode |= (1 << 0); /* GC_LUT_EN */
+		MDSS_MDP_REG_WRITE(offset, opmode);
+	}
+	return 0;
 }
 
 static int pp_dspp_setup(u32 disp_num, struct mdss_mdp_ctl *ctl,
-		struct mdss_mdp_mixer *mixer)
+				struct mdss_mdp_mixer *mixer)
 {
 	u32 flags, base, offset, dspp_num, opmode = 0;
-	struct mdp_pa_cfg_data *pa_config;
-	struct mdp_pcc_cfg_data *pcc_config;
-	struct mdp_igc_lut_data *igc_config;
-	struct mdp_hist_lut_data *enhist_cfg;
 	struct mdp_dither_cfg_data *dither_cfg;
 	struct pp_hist_col_info *hist_info;
+	struct mdp_pgc_lut_data *pgc_config;
 	struct pp_sts_type *pp_sts;
-	u32 data, tbl_idx, col_state;
+	u32 data, col_state;
 	unsigned long flag;
 	int i;
+
 	dspp_num = mixer->num;
 	/* no corresponding dspp */
 	if ((mixer->type != MDSS_MDP_MIXER_TYPE_INTF) ||
@@ -417,76 +556,32 @@
 	/* nothing to update */
 	if ((!flags) && (!(hist_info->col_en)))
 		return 0;
+
 	pp_sts = &mdss_pp_res->pp_dspp_sts[dspp_num];
-	if (flags & PP_FLAGS_DIRTY_PA) {
-		pa_config = &mdss_pp_res->pa_disp_cfg[disp_num];
-		if (pa_config->pa_data.flags & MDP_PP_OPS_WRITE) {
-			offset = base + MDSS_MDP_REG_DSPP_PA_BASE;
-			MDSS_MDP_REG_WRITE(offset, pa_config->pa_data.hue_adj);
-			offset += 4;
-			MDSS_MDP_REG_WRITE(offset, pa_config->pa_data.sat_adj);
-			offset += 4;
-			MDSS_MDP_REG_WRITE(offset, pa_config->pa_data.val_adj);
-			offset += 4;
-			MDSS_MDP_REG_WRITE(offset, pa_config->pa_data.cont_adj);
-		}
-		if (pa_config->pa_data.flags & MDP_PP_OPS_DISABLE)
-			pp_sts->pa_sts &= ~PP_STS_ENABLE;
-		else if (pa_config->pa_data.flags & MDP_PP_OPS_ENABLE)
-			pp_sts->pa_sts |= PP_STS_ENABLE;
-	}
+
+	pp_pa_config(flags, base + MDSS_MDP_REG_DSPP_PA_BASE, pp_sts,
+					&mdss_pp_res->pa_disp_cfg[disp_num]);
+
+	pp_pcc_config(flags, base + MDSS_MDP_REG_DSPP_PCC_BASE, pp_sts,
+					&mdss_pp_res->pcc_disp_cfg[disp_num]);
+
+	pp_igc_config(flags, MDSS_MDP_REG_IGC_DSPP_BASE, pp_sts,
+				&mdss_pp_res->igc_disp_cfg[disp_num], dspp_num);
+
+	pp_enhist_config(flags, base + MDSS_MDP_REG_DSPP_HIST_LUT_BASE,
+			pp_sts, &mdss_pp_res->enhist_disp_cfg[disp_num]);
+
 	if (pp_sts->pa_sts & PP_STS_ENABLE)
 		opmode |= (1 << 20); /* PA_EN */
-	if (flags & PP_FLAGS_DIRTY_PCC) {
-		pcc_config = &mdss_pp_res->pcc_disp_cfg[disp_num];
-		if (pcc_config->ops & MDP_PP_OPS_WRITE) {
-			offset = base + MDSS_MDP_REG_DSPP_PCC_BASE;
-			pp_update_pcc_regs(offset, pcc_config);
-		}
-		if (pcc_config->ops & MDP_PP_OPS_DISABLE)
-			pp_sts->pcc_sts &= ~PP_STS_ENABLE;
-		else if (pcc_config->ops & MDP_PP_OPS_ENABLE)
-			pp_sts->pcc_sts |= PP_STS_ENABLE;
-	}
+
 	if (pp_sts->pcc_sts & PP_STS_ENABLE)
 		opmode |= (1 << 4); /* PCC_EN */
 
-	if (flags & PP_FLAGS_DIRTY_IGC) {
-		igc_config = &mdss_pp_res->igc_disp_cfg[disp_num];
-		if (igc_config->ops & MDP_PP_OPS_WRITE) {
-			offset = MDSS_MDP_REG_IGC_DSPP_BASE;
-			pp_update_igc_lut(igc_config, offset, dspp_num);
-		}
-		if (igc_config->ops & MDP_PP_IGC_FLAG_ROM0) {
-			pp_sts->pcc_sts |= PP_STS_ENABLE;
-			tbl_idx = 1;
-		} else if (igc_config->ops & MDP_PP_IGC_FLAG_ROM1) {
-			pp_sts->pcc_sts |= PP_STS_ENABLE;
-			tbl_idx = 2;
-		} else {
-			tbl_idx = 0;
-		}
-		pp_sts->igc_tbl_idx = tbl_idx;
-		if (igc_config->ops & MDP_PP_OPS_DISABLE)
-			pp_sts->igc_sts &= ~PP_STS_ENABLE;
-		else if (igc_config->ops & MDP_PP_OPS_ENABLE)
-			pp_sts->igc_sts |= PP_STS_ENABLE;
-	}
 	if (pp_sts->igc_sts & PP_STS_ENABLE) {
 		opmode |= (1 << 0) | /* IGC_LUT_EN */
 			      (pp_sts->igc_tbl_idx << 1);
 	}
-	if (flags & PP_FLAGS_DIRTY_ENHIST) {
-		enhist_cfg = &mdss_pp_res->enhist_disp_cfg[disp_num];
-		if (enhist_cfg->ops & MDP_PP_OPS_WRITE) {
-			offset = base + MDSS_MDP_REG_DSPP_HIST_LUT_BASE;
-			pp_update_hist_lut(offset, enhist_cfg);
-		}
-		if (enhist_cfg->ops & MDP_PP_OPS_DISABLE)
-			pp_sts->enhist_sts &= ~PP_STS_ENABLE;
-		else if (enhist_cfg->ops & MDP_PP_OPS_ENABLE)
-			pp_sts->enhist_sts |= PP_STS_ENABLE;
-	}
+
 	if (pp_sts->enhist_sts & PP_STS_ENABLE) {
 		opmode |= (1 << 19) | /* HIST_LUT_EN */
 				  (1 << 20); /* PA_EN */
@@ -533,10 +628,25 @@
 			opmode |= (1 << 24); /* GAMUT_ORDER */
 	}
 
+	if (flags & PP_FLAGS_DIRTY_PGC) {
+		pgc_config = &mdss_pp_res->pgc_disp_cfg[disp_num];
+		if (pgc_config->flags & MDP_PP_OPS_WRITE) {
+			offset = base + MDSS_MDP_REG_DSPP_GC_BASE;
+			pp_update_argc_lut(offset, pgc_config);
+		}
+		if (pgc_config->flags & MDP_PP_OPS_DISABLE)
+			pp_sts->pgc_sts &= ~PP_STS_ENABLE;
+		else if (pgc_config->flags & MDP_PP_OPS_ENABLE)
+			pp_sts->pgc_sts |= PP_STS_ENABLE;
+	}
+	if (pp_sts->pgc_sts & PP_STS_ENABLE)
+		opmode |= (1 << 22);
+
 	MDSS_MDP_REG_WRITE(base + MDSS_MDP_REG_DSPP_OP_MODE, opmode);
 	ctl->flush_bits |= BIT(13 + dspp_num); /* DSPP */
 	return 0;
 }
+
 int mdss_mdp_pp_setup(struct mdss_mdp_ctl *ctl)
 {
 	u32 disp_num;
@@ -656,7 +766,7 @@
 		*copyback = 1;
 		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 	} else {
-		mdss_pp_res->pa_disp_cfg[disp_num] = *config;
+		mdss_pp_res->pa_disp_cfg[disp_num] = config->pa_data;
 		mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_PA;
 	}
 
@@ -1036,21 +1146,54 @@
 	pp_read_gc_one_lut(offset, config->b_data);
 	return ret;
 }
+
+/* Note: Assumes that its inputs have been checked by calling function */
+static void pp_update_hist_lut(u32 offset, struct mdp_hist_lut_data *cfg)
+{
+	int i;
+	for (i = 0; i < ENHIST_LUT_ENTRIES; i++)
+		MDSS_MDP_REG_WRITE(offset, cfg->data[i]);
+	/* swap */
+	MDSS_MDP_REG_WRITE(offset + 4, 1);
+}
+
 int mdss_mdp_argc_config(struct mdp_pgc_lut_data *config, u32 *copyback)
 {
 	int ret = 0;
-	u32 argc_offset, disp_num, dspp_num = 0;
+	u32 argc_offset = 0, disp_num, dspp_num = 0;
 	struct mdp_pgc_lut_data local_cfg;
+	struct mdp_pgc_lut_data *pgc_ptr;
 	u32 tbl_size;
 
-	if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
-		(config->block >= MDP_BLOCK_MAX))
+	if ((PP_BLOCK(config->block) < MDP_LOGICAL_BLOCK_DISP_0) ||
+		(PP_BLOCK(config->block) >= MDP_BLOCK_MAX))
 		return -EINVAL;
 
 	mutex_lock(&mdss_pp_mutex);
-	disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
+
+	disp_num = PP_BLOCK(config->block) - MDP_LOGICAL_BLOCK_DISP_0;
+	switch (config->block & MDSS_PP_LOCATION_MASK) {
+	case MDSS_PP_LM_CFG:
+		argc_offset = MDSS_MDP_REG_LM_OFFSET(dspp_num) +
+			MDSS_MDP_REG_LM_GC_LUT_BASE;
+		pgc_ptr = &mdss_pp_res->argc_disp_cfg[disp_num];
+		mdss_pp_res->pp_disp_flags[disp_num] |=
+			PP_FLAGS_DIRTY_ARGC;
+		break;
+	case MDSS_PP_DSPP_CFG:
+		argc_offset = MDSS_MDP_REG_DSPP_OFFSET(dspp_num) +
+					MDSS_MDP_REG_DSPP_GC_BASE;
+		pgc_ptr = &mdss_pp_res->pgc_disp_cfg[disp_num];
+		mdss_pp_res->pp_disp_flags[disp_num] |=
+			PP_FLAGS_DIRTY_PGC;
+		break;
+	default:
+		goto argc_config_exit;
+		break;
+	}
 
 	tbl_size = GC_LUT_SEGMENTS * sizeof(struct mdp_ar_gc_lut_data);
+
 	if (config->flags & MDP_PP_OPS_READ) {
 		ret = pp_get_dspp_num(disp_num, &dspp_num);
 		if (ret) {
@@ -1059,10 +1202,6 @@
 			goto argc_config_exit;
 		}
 		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
-
-		argc_offset = MDSS_MDP_REG_LM_OFFSET(dspp_num) +
-				MDSS_MDP_REG_LM_GC_LUT_BASE;
-		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 		local_cfg = *config;
 		local_cfg.r_data =
 			&mdss_pp_res->gc_lut_r[disp_num][0];
@@ -1104,14 +1243,14 @@
 			ret = -EFAULT;
 			goto argc_config_exit;
 		}
-		mdss_pp_res->pgc_disp_cfg[disp_num] = *config;
-		mdss_pp_res->pgc_disp_cfg[disp_num].r_data =
+
+		*pgc_ptr = *config;
+		pgc_ptr->r_data =
 			&mdss_pp_res->gc_lut_r[disp_num][0];
-		mdss_pp_res->pgc_disp_cfg[disp_num].g_data =
+		pgc_ptr->g_data =
 			&mdss_pp_res->gc_lut_g[disp_num][0];
-		mdss_pp_res->pgc_disp_cfg[disp_num].b_data =
+		pgc_ptr->b_data =
 			&mdss_pp_res->gc_lut_b[disp_num][0];
-		mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_ARGC;
 	}
 argc_config_exit:
 	mutex_unlock(&mdss_pp_mutex);
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c
index 1b7bed6..582744c 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c
@@ -491,9 +491,6 @@
 	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", __func__, (u32)ddl->client_data);
 	if (encoder->slice_delivery_info.enable) {
 		return ddl_encode_frame_batch(ddl_handle,
 					input_frame,
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 729fb2e..77faee3 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2013, Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -506,6 +506,8 @@
 
 	width_round_up  = width;
 	height_round_up = height;
+	align = SZ_4K;
+
 	if (format == DDL_YUV_BUF_TYPE_TILE) {
 		width_round_up  = DDL_ALIGN(width, DDL_TILE_ALIGN_WIDTH);
 		height_round_up = DDL_ALIGN(height, DDL_TILE_ALIGN_HEIGHT);
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 163af21..64cc570 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
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2013, Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -1811,8 +1811,10 @@
 	slice_output = (struct vidc_1080p_enc_slice_batch_out_param *)
 		(encoder->batch_frame.slice_batch_out.align_virtual_addr);
 	DDL_MSG_LOW(" after get no of slices = %d\n", num_slices_comp);
-	if (slice_output == NULL)
+	if (slice_output == NULL) {
 		DDL_MSG_ERROR(" slice_output is NULL\n");
+		return; /* Bail out */
+	}
 	encoder->slice_delivery_info.num_slices_enc += num_slices_comp;
 	if (vidc_msg_timing) {
 		ddl_calc_core_proc_time_cnt(__func__, ENC_SLICE_OP_TIME,
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 d9cadef..c15218d 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
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2013, Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -160,9 +160,13 @@
 static void res_trk_pmem_free(struct ddl_buf_addr *addr)
 {
 	struct ddl_context *ddl_context;
+
+	if (!addr)
+		return;
+
 	ddl_context = ddl_get_context();
 	if (ddl_context->video_ion_client) {
-		if (addr && addr->alloc_handle) {
+		if (addr->alloc_handle) {
 			ion_free(ddl_context->video_ion_client,
 			 addr->alloc_handle);
 			addr->alloc_handle = NULL;
diff --git a/drivers/video/msm/vidc/common/dec/vdec.c b/drivers/video/msm/vidc/common/dec/vdec.c
index 48f127a..afc5130 100644
--- a/drivers/video/msm/vidc/common/dec/vdec.c
+++ b/drivers/video/msm/vidc/common/dec/vdec.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2013, Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -2485,7 +2485,7 @@
 	}
 
 	client_index = vid_dec_get_empty_client_index();
-	if (client_index == -1) {
+	if (client_index < 0) {
 		ERR("%s() : No free clients client_index == -1\n", __func__);
 		rc = -ENOMEM;
 		goto client_failure;
diff --git a/drivers/video/msm/vidc/common/enc/venc.c b/drivers/video/msm/vidc/common/enc/venc.c
index c18bb92..0648257 100644
--- a/drivers/video/msm/vidc/common/enc/venc.c
+++ b/drivers/video/msm/vidc/common/enc/venc.c
@@ -557,7 +557,7 @@
 
 	client_index = vid_enc_get_empty_client_index();
 
-	if (client_index == -1) {
+	if (client_index < 0) {
 		ERR("%s() : No free clients client_index == -1\n",
 			__func__);
 		rc = -ENODEV;
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 884050b..14c8030 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c
@@ -1628,6 +1628,7 @@
 	if (!cctxt || to_state >= VCD_CLIENT_STATE_MAX) {
 		VCD_MSG_ERROR("Bad parameters. cctxt=%p, to_state=%d",
 			      cctxt, to_state);
+		return;
 	}
 
 	state_ctxt = &cctxt->clnt_state;
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 f670a4a..9074358 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_device_sm.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_device_sm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2013, Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -36,6 +36,7 @@
 	if (!drv_ctxt || to_state >= VCD_DEVICE_STATE_MAX) {
 		VCD_MSG_ERROR("Bad parameters. drv_ctxt=%p, to_state=%d",
 				  drv_ctxt, to_state);
+		return;
 	}
 
 	state_ctxt = &drv_ctxt->dev_state;
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_scheduler.c b/drivers/video/msm/vidc/common/vcd/vcd_scheduler.c
index ab21bac..fe0e131 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_scheduler.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_scheduler.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2013, Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -88,8 +88,13 @@
 			prop_hdr.sz = sizeof(cctxt->frm_p_units);
 			rc = ddl_get_property(cctxt->ddl_handle, &prop_hdr,
 						  &cctxt->frm_p_units);
-			VCD_FAILED_RETURN(rc,
-				"Failed: Get DDL_I_FRAME_PROC_UNITS");
+			if (VCD_FAILED(rc)) {
+				kfree(sched_cctxt);
+				VCD_MSG_ERROR(
+					"Failed: Get DDL_I_FRAME_PROC_UNITS");
+				return rc;
+			}
+
 			if (cctxt->decoding) {
 				cctxt->frm_rate.fps_numerator =
 					VCD_DEC_INITIAL_FRAME_RATE;
@@ -99,8 +104,12 @@
 				prop_hdr.sz = sizeof(cctxt->frm_rate);
 				rc = ddl_get_property(cctxt->ddl_handle,
 						&prop_hdr, &cctxt->frm_rate);
-				VCD_FAILED_RETURN(rc,
-					"Failed: Get VCD_I_FRAME_RATE");
+				if (VCD_FAILED(rc)) {
+					kfree(sched_cctxt);
+					VCD_MSG_ERROR(
+						"Failed: Get VCD_I_FRAME_RATE");
+					return rc;
+				}
 			}
 			if (!cctxt->perf_set_by_client)
 				cctxt->reqd_perf_lvl = cctxt->frm_p_units *
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_sub.c b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
index 78d77d1..09cd91d 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_sub.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2013, Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -2022,6 +2022,11 @@
 	orig_frame = vcd_find_buffer_pool_entry(&cctxt->in_buf_pool,
 					 transc->ip_buf_entry->virtual);
 
+	if (!orig_frame) {
+		rc = VCD_ERR_ILLEGAL_PARM;
+		VCD_FAILED_RETURN(rc, "Couldn't find buffer");
+	}
+
 	if ((transc->ip_buf_entry->frame.virtual !=
 		 frame->vcd_frm.virtual)
 		|| !transc->ip_buf_entry->in_use) {
diff --git a/include/linux/dvb/dmx.h b/include/linux/dvb/dmx.h
index 460cba3..53bbd5e 100644
--- a/include/linux/dvb/dmx.h
+++ b/include/linux/dvb/dmx.h
@@ -5,7 +5,7 @@
  *                  & Ralph  Metzler <ralph@convergence.de>
  *                    for convergence integrated media GmbH
  *
- * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public License
@@ -250,6 +250,18 @@
 
 	/* Flags passed in filter events */
 	__u32 flags;
+
+	/*
+	 * Number of TS packets with Transport Error Indicator (TEI)
+	 * found while constructing the PES.
+	 */
+	__u32 transport_error_indicator_counter;
+
+	/* Number of continuity errors found while constructing the PES */
+	__u32 continuity_error_counter;
+
+	/* Total number of TS packets holding the PES */
+	__u32 ts_packets_num;
 };
 
 /* Section info associated with DMX_EVENT_NEW_SECTION event */
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index 8260ef7..4effce6 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -172,6 +172,7 @@
 	__s32		disable_ipv6;
 	__s32		accept_dad;
 	__s32		force_tllao;
+	__s32		accept_ra_prefix_route;
 	void		*sysctl;
 };
 
@@ -213,6 +214,7 @@
 	DEVCONF_DISABLE_IPV6,
 	DEVCONF_ACCEPT_DAD,
 	DEVCONF_FORCE_TLLAO,
+	DEVCONF_ACCEPT_RA_PREFIX_ROUTE,
 	DEVCONF_MAX
 };
 
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index fdb8fb6..56eda83 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -286,6 +286,18 @@
 #define MDP_PP_IGC_FLAG_ROM0	0x10
 #define MDP_PP_IGC_FLAG_ROM1	0x20
 
+#define MDSS_PP_DSPP_CFG	0x0000
+#define MDSS_PP_SSPP_CFG	0x4000
+#define MDSS_PP_LM_CFG	0x8000
+#define MDSS_PP_WB_CFG	0xC000
+
+#define MDSS_PP_LOCATION_MASK	0xC000
+#define MDSS_PP_LOGICAL_MASK	0x3FFF
+
+#define PP_LOCAT(var) ((var) & MDSS_PP_LOCATION_MASK)
+#define PP_BLOCK(var) ((var) & MDSS_PP_LOGICAL_MASK)
+
+
 struct mdp_qseed_cfg {
 	uint32_t table_num;
 	uint32_t ops;
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 9240277..c588420 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -412,6 +412,7 @@
 	unsigned int power_budget;
 	int pmic_gpio_dp_irq;
 	unsigned int dock_connect_irq;
+	bool use_sec_phy;
 };
 
 /**
@@ -473,6 +474,7 @@
  * @active_conn_num: number of active pipe connections.
  * @usb_base_address: BAM physical address.
  * @ignore_core_reset_ack: BAM can ignore ACK from USB core during PIPE RESET
+ * @disable_clk_gating: Disable clock gating
  */
 struct msm_usb_bam_platform_data {
 	struct usb_bam_pipe_connect *connections;
@@ -482,6 +484,7 @@
 	u32 usb_base_address;
 	bool ignore_core_reset_ack;
 	bool reset_on_connect[MAX_BAMS];
+	bool disable_clk_gating;
 };
 
 /**
diff --git a/include/linux/usb/msm_hsusb_hw.h b/include/linux/usb/msm_hsusb_hw.h
index 6e36f56..900fc00 100644
--- a/include/linux/usb/msm_hsusb_hw.h
+++ b/include/linux/usb/msm_hsusb_hw.h
@@ -28,6 +28,7 @@
 #define USB_OTGSC            (MSM_USB_BASE + 0x01A4)
 #define USB_USBMODE          (MSM_USB_BASE + 0x01A8)
 #define USB_PHY_CTRL         (MSM_USB_BASE + 0x0240)
+#define USB_PHY_CTRL2        (MSM_USB_BASE + 0x0278)
 
 #define USBCMD_RESET   2
 #define USB_USBINTR          (MSM_USB_BASE + 0x0148)
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index bc25e24..9d38db32 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -1498,6 +1498,7 @@
 	V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE		= 0,
 	V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB		= 1,
 	V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES	= 2,
+	V4L2_MPEG_VIDEO_MULTI_SLICE_GOB			= 3,
 };
 #define V4L2_CID_MPEG_VIDEO_VBV_SIZE			(V4L2_CID_MPEG_BASE+222)
 #define V4L2_CID_MPEG_VIDEO_DEC_PTS			(V4L2_CID_MPEG_BASE+223)
@@ -1845,7 +1846,8 @@
 	V4L2_CID_MPEG_VIDC_PERF_LEVEL_PERFORMANCE		= 0,
 	V4L2_CID_MPEG_VIDC_PERF_LEVEL_TURBO			= 1,
 };
-
+#define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_GOB		\
+		(V4L2_CID_MPEG_MSM_VIDC_BASE+27)
 /*  Camera class control IDs */
 #define V4L2_CID_CAMERA_CLASS_BASE 	(V4L2_CTRL_CLASS_CAMERA | 0x900)
 #define V4L2_CID_CAMERA_CLASS 		(V4L2_CTRL_CLASS_CAMERA | 1)
diff --git a/include/media/msmb_isp.h b/include/media/msmb_isp.h
index 01276bd..4e92f70 100644
--- a/include/media/msmb_isp.h
+++ b/include/media/msmb_isp.h
@@ -8,7 +8,8 @@
 
 #define ISP_VERSION_40        40
 #define ISP_VERSION_32        32
-
+#define ISP_NATIVE_BUF_BIT    0x10000
+#define ISP_STATS_STREAM_BIT  0x80000000
 
 enum ISP_START_PIXEL_PATTERN {
 	ISP_BAYER_RGRGRG,
@@ -160,6 +161,8 @@
 	uint32_t session_id;
 	uint32_t stream_id;
 	enum msm_isp_stats_type stats_type;
+	uint8_t comp_flag;
+	uint32_t framedrop_pattern;
 	uint32_t stream_handle;
 };
 struct msm_vfe_stats_stream_release_cmd {
diff --git a/include/media/vcap_fmt.h b/include/media/vcap_fmt.h
index 2787e8d..b2a8d10 100644
--- a/include/media/vcap_fmt.h
+++ b/include/media/vcap_fmt.h
@@ -1,16 +1,3 @@
-/* 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_FMT_H
 #define VCAP_FMT_H
 #include <linux/videodev2.h>
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index 88acdfc..3571fad 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -6369,4 +6369,135 @@
 
 /*bharath, adsp_error_codes.h */
 
+/* LPASS clock for I2S Interface */
+
+/* Supported OSR clock values */
+#define Q6AFE_LPASS_OSR_CLK_12_P288_MHZ		0xBB8000
+#define Q6AFE_LPASS_OSR_CLK_8_P192_MHZ		0x7D0000
+#define Q6AFE_LPASS_OSR_CLK_6_P144_MHZ		0x5DC000
+#define Q6AFE_LPASS_OSR_CLK_4_P096_MHZ		0x3E8000
+#define Q6AFE_LPASS_OSR_CLK_3_P072_MHZ		0x2EE000
+#define Q6AFE_LPASS_OSR_CLK_2_P048_MHZ		0x1F4000
+#define Q6AFE_LPASS_OSR_CLK_1_P536_MHZ		0x177000
+#define Q6AFE_LPASS_OSR_CLK_1_P024_MHZ		 0xFA000
+#define Q6AFE_LPASS_OSR_CLK_768_kHZ		 0xBB800
+#define Q6AFE_LPASS_OSR_CLK_512_kHZ		 0x7D000
+#define Q6AFE_LPASS_OSR_CLK_DISABLE		     0x0
+
+/* Supported Bit clock values */
+#define Q6AFE_LPASS_IBIT_CLK_8_P192_MHZ		0x7D0000
+#define Q6AFE_LPASS_IBIT_CLK_6_P144_MHZ		0x5DC000
+#define Q6AFE_LPASS_IBIT_CLK_4_P096_MHZ		0x3E8000
+#define Q6AFE_LPASS_IBIT_CLK_3_P072_MHZ		0x2EE000
+#define Q6AFE_LPASS_IBIT_CLK_2_P048_MHZ		0x1F4000
+#define Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ		0x177000
+#define Q6AFE_LPASS_IBIT_CLK_1_P024_MHZ		 0xFA000
+#define Q6AFE_LPASS_IBIT_CLK_768_KHZ		 0xBB800
+#define Q6AFE_LPASS_IBIT_CLK_512_KHZ		 0x7D000
+#define Q6AFE_LPASS_IBIT_CLK_DISABLE		     0x0
+
+/* Supported LPASS CLK sources */
+#define Q6AFE_LPASS_CLK_SRC_EXTERNAL 0
+#define Q6AFE_LPASS_CLK_SRC_INTERNAL 1
+
+/* Supported LPASS CLK root*/
+#define Q6AFE_LPASS_CLK_ROOT_DEFAULT 0
+
+enum afe_lpass_clk_mode {
+	Q6AFE_LPASS_MODE_BOTH_INVALID,
+	Q6AFE_LPASS_MODE_CLK1_VALID,
+	Q6AFE_LPASS_MODE_CLK2_VALID,
+	Q6AFE_LPASS_MODE_BOTH_VALID,
+} __packed;
+
+struct afe_clk_cfg {
+/* Minor version used for tracking the version of the I2S
+ * configuration interface.
+ * Supported values: #AFE_API_VERSION_I2S_CONFIG
+ */
+	u32                  i2s_cfg_minor_version;
+
+/* clk value 1 in MHz. */
+	u32                  clk_val1;
+
+/* clk value 2 in MHz. */
+	u32                  clk_val2;
+
+/* clk_src
+ * #Q6AFE_LPASS_CLK_SRC_EXTERNAL
+ * #Q6AFE_LPASS_CLK_SRC_INTERNAL
+ */
+
+	u16                  clk_src;
+
+/* clk_root -0 for default */
+	u16                  clk_root;
+
+/* clk_set_mode
+ * #Q6AFE_LPASS_MODE_BOTH_INVALID
+ * #Q6AFE_LPASS_MODE_CLK1_VALID
+ * #Q6AFE_LPASS_MODE_CLK2_VALID
+ * #Q6AFE_LPASS_MODE_BOTH_VALID
+ */
+	u16                  clk_set_mode;
+
+/* This param id is used to configure I2S clk */
+	u16                  reserved;
+} __packed;
+
+/* This param id is used to configure I2S clk */
+#define AFE_PARAM_ID_LPAIF_CLK_CONFIG	0x00010238
+
+
+struct afe_lpass_clk_config_command {
+	struct apr_hdr			 hdr;
+	struct afe_port_cmd_set_param_v2 param;
+	struct afe_port_param_data_v2    pdata;
+	struct afe_clk_cfg clk_cfg;
+} __packed;
+
+enum afe_lpass_digital_clk_src {
+	Q6AFE_LPASS_DIGITAL_ROOT_INVALID,
+	Q6AFE_LPASS_DIGITAL_ROOT_PRI_MI2S_OSR,
+	Q6AFE_LPASS_DIGITAL_ROOT_SEC_MI2S_OSR,
+	Q6AFE_LPASS_DIGITAL_ROOT_TER_MI2S_OSR,
+	Q6AFE_LPASS_DIGITAL_ROOT_QUAD_MI2S_OSR,
+	Q6AFE_LPASS_DIGITAL_ROOT_CDC_ROOT_CLK,
+} __packed;
+
+/* This param id is used to configure internal clk */
+#define AFE_PARAM_ID_INTERNAL_DIGIATL_CDC_CLK_CONFIG	0x00010239
+
+struct afe_digital_clk_cfg {
+/* Minor version used for tracking the version of the I2S
+ * configuration interface.
+ * Supported values: #AFE_API_VERSION_I2S_CONFIG
+ */
+	u32                  i2s_cfg_minor_version;
+
+/* clk value in MHz. */
+	u32                  clk_val;
+
+/*	INVALID
+ *	PRI_MI2S_OSR
+ *	SEC_MI2S_OSR
+ *	TER_MI2S_OSR
+ *	QUAD_MI2S_OSR
+ *	DIGT_CDC_ROOT
+ */
+	u16                  clk_root;
+
+/* This field must be set to zero. */
+	u16                  reserved;
+} __packed;
+
+
+struct afe_lpass_digital_clk_config_command {
+	struct apr_hdr			 hdr;
+	struct afe_port_cmd_set_param_v2 param;
+	struct afe_port_param_data_v2    pdata;
+	struct afe_digital_clk_cfg clk_cfg;
+} __packed;
+
+
 #endif /*_APR_AUDIO_V2_H_ */
diff --git a/include/sound/apr_audio.h b/include/sound/apr_audio.h
index c12cbbe..5afbfad 100644
--- a/include/sound/apr_audio.h
+++ b/include/sound/apr_audio.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright (c) 2010-2013, The Linux Foundation. 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
@@ -1453,23 +1453,6 @@
 	u32                read_format;
 } __attribute__((packed));
 
-#define ASM_STREAM_CMD_OPEN_LOOPBACK	0x00010D6E
-struct asm_stream_cmd_open_loopback {
-	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.
- */
-} __packed;
-
 #define ADM_CMD_CONNECT_AFE_PORT 0x00010320
 #define ADM_CMD_DISCONNECT_AFE_PORT 0x00010321
 
@@ -1915,4 +1898,5 @@
 
 int srs_ss3d_open(int port_id, int srs_tech_id, void *srs_params);
 /* SRS Studio Sound 3D end */
+
 #endif /*_APR_AUDIO_H_*/
diff --git a/include/sound/msm-dai-q6-v2.h b/include/sound/msm-dai-q6-v2.h
index c04cbfc..c34a397 100644
--- a/include/sound/msm-dai-q6-v2.h
+++ b/include/sound/msm-dai-q6-v2.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -40,7 +40,7 @@
 };
 
 struct msm_dai_auxpcm_pdata {
-	const char *clk;
+	void *clk_cfg;
 	struct msm_dai_auxpcm_config mode_8k;
 	struct msm_dai_auxpcm_config mode_16k;
 };
diff --git a/include/sound/q6adm-v2.h b/include/sound/q6adm-v2.h
index fdc3cb9..6e5e649 100644
--- a/include/sound/q6adm-v2.h
+++ b/include/sound/q6adm-v2.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -49,4 +49,8 @@
 
 int adm_get_copp_id(int port_id);
 
+void adm_set_multi_ch_map(char *channel_map);
+
+void adm_get_multi_ch_map(char *channel_map);
+
 #endif /* __Q6_ADM_V2_H__ */
diff --git a/include/sound/q6afe-v2.h b/include/sound/q6afe-v2.h
index 3da152c..e39d45c 100644
--- a/include/sound/q6afe-v2.h
+++ b/include/sound/q6afe-v2.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -155,4 +155,9 @@
 
 int afe_pseudo_port_start_nowait(u16 port_id);
 int afe_pseudo_port_stop_nowait(u16 port_id);
+int afe_set_lpass_clock(u16 port_id, struct afe_clk_cfg *cfg);
+int afe_set_lpass_internal_digital_codec_clock(u16 port_id,
+				struct afe_digital_clk_cfg *cfg);
+int q6afe_check_osr_clk_freq(u32 freq);
+
 #endif /* __Q6AFE_V2_H__ */
diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h
index a436a6e..876d815 100644
--- a/include/sound/q6asm-v2.h
+++ b/include/sound/q6asm-v2.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -262,7 +262,8 @@
 			uint32_t rate, uint32_t channels);
 
 int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
-				uint32_t rate, uint32_t channels);
+			uint32_t rate, uint32_t channels,
+			bool use_default_chmap, char *channel_map);
 
 int q6asm_media_format_block_aac(struct audio_client *ac,
 			struct asm_aac_cfg *cfg);
diff --git a/include/sound/q6asm.h b/include/sound/q6asm.h
index 275cdbe..dcdd816 100644
--- a/include/sound/q6asm.h
+++ b/include/sound/q6asm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2013, The Linux Foundation. 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
@@ -206,8 +206,6 @@
 			uint32_t rd_format,
 			uint32_t wr_format);
 
-int q6asm_open_loopack(struct audio_client *ac);
-
 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,
diff --git a/include/sound/q6audio-v2.h b/include/sound/q6audio-v2.h
index 1a5dce1..fd6a490 100644
--- a/include/sound/q6audio-v2.h
+++ b/include/sound/q6audio-v2.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -21,6 +21,8 @@
 
 int q6audio_validate_port(u16 port_id);
 
+int q6audio_is_digital_pcm_interface(u16 port_id);
+
 int q6audio_get_port_id(u16 port_id);
 
 #endif
diff --git a/kernel/panic.c b/kernel/panic.c
index 8c6babc..4716d16 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -23,6 +23,7 @@
 #include <linux/init.h>
 #include <linux/nmi.h>
 #include <linux/dmi.h>
+#include <linux/coresight.h>
 
 #define PANIC_TIMER_STEP 100
 #define PANIC_BLINK_SPD 18
@@ -80,6 +81,7 @@
 	long i, i_next = 0;
 	int state = 0;
 
+	coresight_abort();
 	/*
 	 * Disable local interrupts. This will prevent panic_smp_self_stop
 	 * from deadlocking the first cpu that invokes the panic, since
diff --git a/kernel/sysctl_binary.c b/kernel/sysctl_binary.c
index d42c279..acb60be 100644
--- a/kernel/sysctl_binary.c
+++ b/kernel/sysctl_binary.c
@@ -524,6 +524,7 @@
 	{ CTL_INT,	NET_IPV6_ACCEPT_RA_RT_INFO_MAX_PLEN,	"accept_ra_rt_info_max_plen" },
 	{ CTL_INT,	NET_IPV6_PROXY_NDP,			"proxy_ndp" },
 	{ CTL_INT,	NET_IPV6_ACCEPT_SOURCE_ROUTE,		"accept_source_route" },
+	{ CTL_INT,	NET_IPV6_ACCEPT_RA_PREFIX_ROUTE,	"accept_ra_prefix_route" },
 	{}
 };
 
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index f897841..5bb2847 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -36,6 +36,8 @@
  *	YOSHIFUJI Hideaki @USAGI	:	improved source address
  *						selection; consider scope,
  *						status etc.
+ *	Harout S. Hedeshian		:	procfs flag to toggle automatic
+ *						addition of prefix route
  */
 
 #include <linux/errno.h>
@@ -197,6 +199,7 @@
 	.accept_source_route	= 0,	/* we do not accept RH0 by default. */
 	.disable_ipv6		= 0,
 	.accept_dad		= 1,
+	.accept_ra_prefix_route = 1,
 };
 
 static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
@@ -231,6 +234,7 @@
 	.accept_source_route	= 0,	/* we do not accept RH0 by default. */
 	.disable_ipv6		= 0,
 	.accept_dad		= 1,
+	.accept_ra_prefix_route = 1,
 };
 
 /* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */
@@ -1908,8 +1912,10 @@
 				flags |= RTF_EXPIRES;
 				expires = jiffies_to_clock_t(rt_expires);
 			}
-			addrconf_prefix_route(&pinfo->prefix, pinfo->prefix_len,
-					      dev, expires, flags);
+			if (dev->ip6_ptr->cnf.accept_ra_prefix_route) {
+				addrconf_prefix_route(&pinfo->prefix,
+					pinfo->prefix_len, dev, expires, flags);
+			}
 		}
 		if (rt)
 			dst_release(&rt->dst);
@@ -4598,6 +4604,13 @@
 			.proc_handler   = proc_dointvec
 		},
 		{
+			.procname	= "accept_ra_prefix_route",
+			.data		= &ipv6_devconf.accept_ra_prefix_route,
+			.maxlen		= sizeof(int),
+			.mode		= 0644,
+			.proc_handler	= proc_dointvec,
+		},
+		{
 			/* sentinel */
 		}
 	},
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index d7521f8..85214ec 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -339,7 +339,7 @@
 
 	struct wcd9xxx_pdata *pdata;
 	u32 anc_slot;
-
+	bool anc_func;
 	bool no_mic_headset_override;
 	/* Delayed work to report long button press */
 	struct delayed_work mbhc_btn_dwork;
@@ -539,6 +539,48 @@
 	return 0;
 }
 
+static int tabla_get_anc_func(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+	ucontrol->value.integer.value[0] = (tabla->anc_func == true ? 1 : 0);
+	return 0;
+}
+
+static int tabla_put_anc_func(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+	mutex_lock(&dapm->codec->mutex);
+
+	tabla->anc_func = (!ucontrol->value.integer.value[0] ? false : true);
+
+	dev_dbg(codec->dev, "%s: anc_func %x", __func__, tabla->anc_func);
+
+	if (tabla->anc_func == true) {
+		snd_soc_dapm_enable_pin(dapm, "ANC HPHR");
+		snd_soc_dapm_enable_pin(dapm, "ANC HPHL");
+		snd_soc_dapm_enable_pin(dapm, "ANC HEADPHONE");
+		snd_soc_dapm_disable_pin(dapm, "HPHR");
+		snd_soc_dapm_disable_pin(dapm, "HPHL");
+		snd_soc_dapm_disable_pin(dapm, "HEADPHONE");
+	} else {
+		snd_soc_dapm_disable_pin(dapm, "ANC HPHR");
+		snd_soc_dapm_disable_pin(dapm, "ANC HPHL");
+		snd_soc_dapm_disable_pin(dapm, "ANC HEADPHONE");
+		snd_soc_dapm_enable_pin(dapm, "HPHR");
+		snd_soc_dapm_enable_pin(dapm, "HPHL");
+		snd_soc_dapm_enable_pin(dapm, "HEADPHONE");
+	}
+	snd_soc_dapm_sync(dapm);
+	mutex_unlock(&dapm->codec->mutex);
+	return 0;
+}
+
 static int tabla_pa_gain_get(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
@@ -987,6 +1029,10 @@
 	return 0;
 }
 
+static const char *const tabla_anc_func_text[] = {"OFF", "ON"};
+static const struct soc_enum tabla_anc_func_enum =
+	SOC_ENUM_SINGLE_EXT(2, tabla_anc_func_text);
+
 static const char *tabla_ear_pa_gain_text[] = {"POS_6_DB", "POS_2_DB"};
 static const struct soc_enum tabla_ear_pa_gain_enum[] = {
 		SOC_ENUM_SINGLE_EXT(2, tabla_ear_pa_gain_text),
@@ -1130,6 +1176,8 @@
 
 	SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 0, 100, tabla_get_anc_slot,
 		tabla_put_anc_slot),
+	SOC_ENUM_EXT("ANC Function", tabla_anc_func_enum, tabla_get_anc_func,
+		tabla_put_anc_func),
 	SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
 	SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
 	SOC_ENUM("TX3 HPF cut off", cf_dec3_enum),
@@ -2476,111 +2524,6 @@
 	return 0;
 }
 
-static int tabla_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 tabla_priv *tabla = 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:
-
-		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 (tabla->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 < TABLA_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 * TABLA_PACKED_REG_SIZE
-				> anc_size_remaining) {
-				dev_err(codec->dev, "Invalid register format\n");
-				release_firmware(fw);
-				return -ENOMEM;
-			}
-
-			if (tabla->anc_slot == i)
-				break;
-
-			anc_size_remaining -= (anc_writes_size *
-				TABLA_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++) {
-			TABLA_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);
-
-		TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
-		/* if MBHC polling is active, set TX7_MBHC_EN bit 7 */
-		if (tabla->mbhc_polling_active)
-			snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80,
-					    0x80);
-		TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
-		break;
-	case SND_SOC_DAPM_POST_PMD:
-		/* unset TX7_MBHC_EN bit 7 */
-		snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x00);
-
-		snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_RESET_CTL, 0xFF);
-		snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_CLK_EN_CTL, 0);
-		break;
-	}
-	return 0;
-}
 
 /* called under codec_resource_lock acquisition */
 static void tabla_codec_start_hs_polling(struct snd_soc_codec *codec)
@@ -3283,6 +3226,160 @@
 			  WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
 }
 
+static int tabla_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 tabla_priv *tabla = 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;
+	u8 mbhc_micb_ctl_val;
+
+	pr_debug("%s: DAPM Event %d ANC func is %d\n",
+		 __func__, event, tabla->anc_func);
+
+	if (tabla->anc_func == 0)
+		return 0;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		mbhc_micb_ctl_val = snd_soc_read(codec,
+			tabla->mbhc_bias_regs.ctl_reg);
+
+		if (!(mbhc_micb_ctl_val & 0x80)) {
+			TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
+			tabla_codec_switch_micbias(codec, 1);
+			TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
+		}
+
+		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 (tabla->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 < TABLA_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 * TABLA_PACKED_REG_SIZE
+				> anc_size_remaining) {
+				dev_err(codec->dev, "Invalid register format\n");
+				release_firmware(fw);
+				return -ENOMEM;
+			}
+
+			if (tabla->anc_slot == i)
+				break;
+
+			anc_size_remaining -= (anc_writes_size *
+				TABLA_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++) {
+			TABLA_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));
+		}
+		usleep_range(10000, 10000);
+		snd_soc_update_bits(codec, TABLA_A_RX_HPH_CNP_EN, 0x30, 0x30);
+		msleep(30);
+		release_firmware(fw);
+		TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
+		/* if MBHC polling is active, set TX7_MBHC_EN bit 7 */
+		if (tabla->mbhc_polling_active)
+			snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80,
+						0x80);
+		TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* schedule work is required because at the time HPH PA DAPM
+		 * event callback is called by DAPM framework, CODEC dapm mutex
+		 * would have been locked while snd_soc_jack_report also
+		 * attempts to acquire same lock.
+		*/
+		if (w->shift == 5) {
+			clear_bit(TABLA_HPHL_PA_OFF_ACK,
+				&tabla->hph_pa_dac_state);
+			clear_bit(TABLA_HPHL_DAC_OFF_ACK,
+				&tabla->hph_pa_dac_state);
+			if (tabla->hph_status & SND_JACK_OC_HPHL)
+				schedule_work(&tabla->hphlocp_work);
+		} else if (w->shift == 4) {
+			clear_bit(TABLA_HPHR_PA_OFF_ACK,
+				&tabla->hph_pa_dac_state);
+			clear_bit(TABLA_HPHR_DAC_OFF_ACK,
+				&tabla->hph_pa_dac_state);
+			if (tabla->hph_status & SND_JACK_OC_HPHR)
+				schedule_work(&tabla->hphrocp_work);
+		}
+
+		TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
+		tabla_codec_switch_micbias(codec, 0);
+		TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
+
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_update_bits(codec, TABLA_A_RX_HPH_CNP_EN, 0x30, 0x00);
+		msleep(40);
+		/* unset TX7_MBHC_EN bit 7 */
+		snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x00);
+		snd_soc_update_bits(codec, TABLA_A_CDC_ANC1_CTL, 0x01, 0x00);
+		snd_soc_update_bits(codec, TABLA_A_CDC_ANC2_CTL, 0x01, 0x00);
+		msleep(20);
+		snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_RESET_CTL, 0x0F);
+		snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_CLK_EN_CTL, 0);
+		snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_RESET_CTL, 0xFF);
+		break;
+	}
+	return 0;
+}
+
 static int tabla_hph_pa_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
@@ -3592,7 +3689,6 @@
 
 	{"ANC1 FB MUX", "EAR_HPH_L", "RX1 MIX2"},
 	{"ANC1 FB MUX", "EAR_LINE_1", "RX2 MIX2"},
-	{"ANC", NULL, "ANC1 FB MUX"},
 
 	/* Headset (RX MIX1 and RX MIX2) */
 	{"HEADPHONE", NULL, "HPHL"},
@@ -3607,19 +3703,26 @@
 	{"HPHL DAC", NULL, "CP"},
 	{"HPHR DAC", NULL, "CP"},
 
-	{"ANC", NULL, "ANC1 MUX"},
-	{"ANC", NULL, "ANC2 MUX"},
+	{"ANC HEADPHONE", NULL, "ANC HPHL"},
+	{"ANC HEADPHONE", NULL, "ANC HPHR"},
+
+	{"ANC HPHL", NULL, "HPHL_PA_MIXER"},
+	{"ANC HPHR", NULL, "HPHR_PA_MIXER"},
+
 	{"ANC1 MUX", "ADC1", "ADC1"},
 	{"ANC1 MUX", "ADC2", "ADC2"},
 	{"ANC1 MUX", "ADC3", "ADC3"},
 	{"ANC1 MUX", "ADC4", "ADC4"},
+	{"ANC1 MUX", "DMIC1", "DMIC1"},
+	{"ANC1 MUX", "DMIC2", "DMIC2"},
+	{"ANC1 MUX", "DMIC3", "DMIC3"},
+	{"ANC1 MUX", "DMIC4", "DMIC4"},
 	{"ANC2 MUX", "ADC1", "ADC1"},
 	{"ANC2 MUX", "ADC2", "ADC2"},
 	{"ANC2 MUX", "ADC3", "ADC3"},
 	{"ANC2 MUX", "ADC4", "ADC4"},
 
-	{"ANC", NULL, "CDC_CONN"},
-
+	{"ANC HPHR", NULL, "CDC_CONN"},
 	{"DAC1", "Switch", "RX1 CHAIN"},
 	{"HPHL DAC", "Switch", "RX1 CHAIN"},
 	{"HPHR DAC", NULL, "RX2 CHAIN"},
@@ -3646,8 +3749,8 @@
 
 	{"RX1 CHAIN", NULL, "RX1 MIX2"},
 	{"RX2 CHAIN", NULL, "RX2 MIX2"},
-	{"RX1 CHAIN", NULL, "ANC"},
-	{"RX2 CHAIN", NULL, "ANC"},
+	{"RX1 MIX2", NULL, "ANC1 MUX"},
+	{"RX2 MIX2", NULL, "ANC2 MUX"},
 
 	{"CP", NULL, "RX_BIAS"},
 	{"LINEOUT1 DAC", NULL, "RX_BIAS"},
@@ -4052,6 +4155,14 @@
 		(reg <= TABLA_A_CDC_IIR2_COEF_B5_CTL))
 		return 1;
 
+	/* ANC filter registers are not cacheable */
+	if ((reg >= TABLA_A_CDC_ANC1_FILT1_B1_CTL) &&
+		(reg <= TABLA_A_CDC_ANC1_FILT2_B3_CTL))
+		return 1;
+	if ((reg >= TABLA_A_CDC_ANC2_FILT1_B1_CTL) &&
+		(reg <= TABLA_A_CDC_ANC2_FILT2_B3_CTL))
+		return 1;
+
 	/* Digital gain register is not cacheable so we have to write
 	 * the setting even it is the same
 	 */
@@ -5284,9 +5395,13 @@
 	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,
-		tabla_codec_enable_anc, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_OUTPUT("ANC HEADPHONE"),
+	SND_SOC_DAPM_PGA_E("ANC HPHL", SND_SOC_NOPM, 0, 0, NULL, 0,
+		tabla_codec_enable_anc,
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("ANC HPHR", SND_SOC_NOPM, 0, 0, NULL, 0,
+		tabla_codec_enable_anc, SND_SOC_DAPM_PRE_PMU),
+
 
 	SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
 
@@ -6779,6 +6894,13 @@
 		 * only report the mic line
 		 */
 		tabla_codec_report_plug(codec, 1, SND_JACK_HEADSET);
+		if (!tabla->mbhc_micbias_switched &&
+			tabla_is_hph_pa_on(codec)) {
+			/*If the headphone path is on, switch the micbias
+			to VDDIO to avoid noise due to button polling */
+			tabla_codec_switch_micbias(codec, 1);
+			pr_debug("%s: HPH path is still up\n", __func__);
+		}
 		msleep(100);
 		tabla_codec_start_hs_polling(codec);
 	} else if (plug_type == PLUG_TYPE_HIGH_HPH) {
@@ -7201,7 +7323,6 @@
 	} else if (plug_type == PLUG_TYPE_HEADSET) {
 		pr_debug("%s: Headset detected\n", __func__);
 		tabla_codec_report_plug(codec, 1, SND_JACK_HEADSET);
-
 		/* avoid false button press detect */
 		msleep(50);
 		tabla_codec_start_hs_polling(codec);
@@ -7685,6 +7806,7 @@
 					    0x08, 0x00);
 			/* Turn off override */
 			tabla_turn_onoff_override(codec, false);
+			tabla_codec_switch_micbias(codec, 0);
 		}
 	}
 
@@ -8650,6 +8772,12 @@
 		       "tabla_gpio_irq_resend");
 	tabla->gpio_irq_resend = false;
 
+	mutex_lock(&dapm->codec->mutex);
+	snd_soc_dapm_disable_pin(dapm, "ANC HPHL");
+	snd_soc_dapm_disable_pin(dapm, "ANC HPHR");
+	snd_soc_dapm_disable_pin(dapm, "ANC HEADPHONE");
+	snd_soc_dapm_sync(dapm);
+	mutex_unlock(&dapm->codec->mutex);
 
 #ifdef CONFIG_DEBUG_FS
 	if (ret == 0) {
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index ad1546d..41a9cc5 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -4902,11 +4902,6 @@
 	taiko = snd_soc_codec_get_drvdata(codec);
 	mutex_lock(&codec->mutex);
 	WCD9XXX_BCL_LOCK(&taiko->resmgr);
-	if (spkr_drv_wrnd == 1) {
-		wcd9xxx_resmgr_post_ssr(&taiko->resmgr);
-		snd_soc_update_bits(codec, TAIKO_A_SPKR_DRV_EN, 0x80, 0x80);
-	}
-	WCD9XXX_BCL_UNLOCK(&taiko->resmgr);
 
 	if (codec->reg_def_copy) {
 		pr_debug("%s: Update ASOC cache", __func__);
@@ -4915,11 +4910,23 @@
 						codec->reg_size, GFP_KERNEL);
 	}
 
+	wcd9xxx_resmgr_post_ssr(&taiko->resmgr);
+	if (spkr_drv_wrnd == 1)
+		snd_soc_update_bits(codec, TAIKO_A_SPKR_DRV_EN, 0x80, 0x80);
+	WCD9XXX_BCL_UNLOCK(&taiko->resmgr);
+
 	taiko_update_reg_defaults(codec);
 	taiko_codec_init_reg(codec);
 	ret = taiko_handle_pdata(taiko);
 	if (IS_ERR_VALUE(ret))
 		pr_err("%s: bad pdata\n", __func__);
+
+	wcd9xxx_mbhc_deinit(&taiko->mbhc);
+	ret = wcd9xxx_mbhc_init(&taiko->mbhc, &taiko->resmgr, codec);
+	if (ret)
+		pr_err("%s: mbhc init failed %d\n", __func__, ret);
+	else
+		wcd9xxx_mbhc_start(&taiko->mbhc, taiko->mbhc.mbhc_cfg);
 	mutex_unlock(&codec->mutex);
 	return ret;
 }
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index 0f2a19c..8acc334 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -3177,23 +3177,28 @@
 	mbhc->resmgr = resmgr;
 	mbhc->resmgr->mbhc = mbhc;
 
-	ret = snd_soc_jack_new(codec, "Headset Jack", WCD9XXX_JACK_MASK,
-			       &mbhc->headset_jack);
-	if (ret) {
-		pr_err("%s: Failed to create new jack\n", __func__);
-		return ret;
-	}
+	if (mbhc->headset_jack.jack == NULL) {
+		ret = snd_soc_jack_new(codec, "Headset Jack", WCD9XXX_JACK_MASK,
+				       &mbhc->headset_jack);
+		if (ret) {
+			pr_err("%s: Failed to create new jack\n", __func__);
+			return ret;
+		}
 
-	ret = snd_soc_jack_new(codec, "Button Jack", WCD9XXX_JACK_BUTTON_MASK,
-			       &mbhc->button_jack);
-	if (ret) {
-		pr_err("Failed to create new jack\n");
-		return ret;
-	}
+		ret = snd_soc_jack_new(codec, "Button Jack",
+				       WCD9XXX_JACK_BUTTON_MASK,
+				       &mbhc->button_jack);
+		if (ret) {
+			pr_err("Failed to create new jack\n");
+			return ret;
+		}
 
-	INIT_DELAYED_WORK(&mbhc->mbhc_firmware_dwork, wcd9xxx_mbhc_fw_read);
-	INIT_DELAYED_WORK(&mbhc->mbhc_btn_dwork, wcd9xxx_btn_lpress_fn);
-	INIT_DELAYED_WORK(&mbhc->mbhc_insert_dwork, wcd9xxx_mbhc_insert_work);
+		INIT_DELAYED_WORK(&mbhc->mbhc_firmware_dwork,
+				  wcd9xxx_mbhc_fw_read);
+		INIT_DELAYED_WORK(&mbhc->mbhc_btn_dwork, wcd9xxx_btn_lpress_fn);
+		INIT_DELAYED_WORK(&mbhc->mbhc_insert_dwork,
+				  wcd9xxx_mbhc_insert_work);
+	}
 
 	/* Register event notifier */
 	mbhc->nblock.notifier_call = wcd9xxx_event_notify;
@@ -3294,6 +3299,11 @@
 	wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_MBHC_REMOVAL, mbhc);
 	wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_MBHC_INSERTION, mbhc);
 
+	wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_MBHC_JACK_SWITCH, mbhc);
+	wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT, mbhc);
+	wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT, mbhc);
+	wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_MBHC_RELEASE, mbhc);
+
 	if (mbhc->mbhc_fw)
 		release_firmware(mbhc->mbhc_fw);
 
diff --git a/sound/soc/codecs/wcd9xxx-resmgr.c b/sound/soc/codecs/wcd9xxx-resmgr.c
index 0ab650e..17edd4a 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr.c
+++ b/sound/soc/codecs/wcd9xxx-resmgr.c
@@ -198,19 +198,44 @@
 void wcd9xxx_resmgr_post_ssr(struct wcd9xxx_resmgr *resmgr)
 {
 	int old_bg_audio_users, old_bg_mbhc_users;
+	int old_clk_rco_users, old_clk_mclk_users;
 
+	pr_debug("%s: enter\n", __func__);
 	WCD9XXX_BCL_ASSERT_LOCKED(resmgr);
 
 	old_bg_audio_users = resmgr->bg_audio_users;
-	resmgr->bg_audio_users = 0;
 	old_bg_mbhc_users = resmgr->bg_mbhc_users;
+	old_clk_rco_users = resmgr->clk_rco_users;
+	old_clk_mclk_users = resmgr->clk_mclk_users;
+	resmgr->bg_audio_users = 0;
 	resmgr->bg_mbhc_users = 0;
+	resmgr->bandgap_type = WCD9XXX_BANDGAP_OFF;
+	resmgr->clk_rco_users = 0;
+	resmgr->clk_mclk_users = 0;
+	resmgr->clk_type = WCD9XXX_CLK_OFF;
 
-	while (old_bg_audio_users && --old_bg_audio_users)
-		wcd9xxx_resmgr_get_bandgap(resmgr, WCD9XXX_BANDGAP_AUDIO_MODE);
+	if (old_bg_audio_users) {
+		while (old_bg_audio_users--)
+			wcd9xxx_resmgr_get_bandgap(resmgr,
+						  WCD9XXX_BANDGAP_AUDIO_MODE);
+	}
 
-	while (old_bg_mbhc_users && --old_bg_mbhc_users)
-		wcd9xxx_resmgr_get_bandgap(resmgr, WCD9XXX_BANDGAP_MBHC_MODE);
+	if (old_bg_mbhc_users) {
+		while (old_bg_mbhc_users--)
+			wcd9xxx_resmgr_get_bandgap(resmgr,
+						  WCD9XXX_BANDGAP_MBHC_MODE);
+	}
+
+	if (old_clk_mclk_users) {
+		while (old_clk_mclk_users--)
+			wcd9xxx_resmgr_get_clk_block(resmgr, WCD9XXX_CLK_MCLK);
+	}
+
+	if (old_clk_rco_users) {
+		while (old_clk_rco_users--)
+			wcd9xxx_resmgr_get_clk_block(resmgr, WCD9XXX_CLK_RCO);
+	}
+	pr_debug("%s: leave\n", __func__);
 }
 
 /*
diff --git a/sound/soc/msm/Makefile b/sound/soc/msm/Makefile
index e5f0208..4c8d2e3 100644
--- a/sound/soc/msm/Makefile
+++ b/sound/soc/msm/Makefile
@@ -55,7 +55,8 @@
 # for MSM 8960 sound card driver
 
 obj-$(CONFIG_SND_SOC_MSM_QDSP6_INTF) += qdsp6/
-snd-soc-qdsp6-objs := msm-dai-q6.o msm-pcm-q6.o msm-multi-ch-pcm-q6.o msm-lowlatency-pcm-q6.o msm-pcm-loopback.o msm-pcm-routing.o msm-dai-fe.o msm-compr-q6.o msm-dai-stub.o
+
+snd-soc-qdsp6-objs := msm-dai-q6.o msm-pcm-q6.o msm-multi-ch-pcm-q6.o msm-lowlatency-pcm-q6.o msm-pcm-routing.o msm-dai-fe.o msm-compr-q6.o msm-dai-stub.o
 obj-$(CONFIG_SND_SOC_MSM_QDSP6_HDMI_AUDIO) += msm-dai-q6-hdmi.o
 obj-$(CONFIG_SND_SOC_VOICE) += msm-pcm-voice.o msm-pcm-voip.o msm-pcm-dtmf.o
 snd-soc-qdsp6-objs += msm-pcm-lpa.o msm-pcm-afe.o
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 784b650..cf0d4cd 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2013, The Linux Foundation. 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
@@ -229,17 +229,6 @@
 			.rate_min =	8000,
 			.rate_max = 48000,
 		},
-		.capture = {
-			.stream_name = "MultiMedia6 Capture",
-			.aif_name = "MM_UL6",
-			.rates = (SNDRV_PCM_RATE_8000_48000|
-					SNDRV_PCM_RATE_KNOT),
-			.formats = SNDRV_PCM_FMTBIT_S16_LE,
-			.channels_min = 1,
-			.channels_max = 8,
-			.rate_min =     8000,
-			.rate_max =	48000,
-		},
 		.ops = &msm_fe_Multimedia_dai_ops,
 		.name = "MultiMedia6",
 	},
diff --git a/sound/soc/msm/msm-pcm-loopback.c b/sound/soc/msm/msm-pcm-loopback.c
deleted file mode 100644
index 55f29a5..0000000
--- a/sound/soc/msm/msm-pcm-loopback.c
+++ /dev/null
@@ -1,327 +0,0 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
-
-* This program is free software; you can redistribute it and/or modify
-* it under the terms of the GNU General Public License version 2 and
-* only version 2 as published by the Free Software Foundation.
-
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-* GNU General Public License for more details.
-*/
-
-#include <linux/init.h>
-#include <linux/err.h>
-#include <linux/module.h>
-#include <linux/time.h>
-#include <linux/wait.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <sound/apr_audio.h>
-#include <sound/core.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-#include <sound/q6asm.h>
-#include <sound/pcm.h>
-#include <sound/initval.h>
-#include <sound/control.h>
-#include <asm/dma.h>
-#include <linux/dma-mapping.h>
-
-#include "msm-pcm-routing.h"
-
-struct msm_pcm {
-	struct snd_pcm_substream *playback_substream;
-	struct snd_pcm_substream *capture_substream;
-
-	int instance;
-
-	struct mutex lock;
-
-	uint32_t samp_rate;
-	uint32_t channel_mode;
-
-	int playback_start;
-	int capture_start;
-	int session_id;
-	struct audio_client *audio_client;
-};
-
-static void stop_pcm(struct msm_pcm *pcm);
-
-static struct msm_pcm pcm_info;
-
-static const struct snd_pcm_hardware dummy_pcm_hardware = {
-	.formats                = 0xffffffff,
-	.channels_min           = 1,
-	.channels_max           = UINT_MAX,
-
-	/* Random values to keep userspace happy when checking constraints */
-	.info                   = SNDRV_PCM_INFO_INTERLEAVED |
-				  SNDRV_PCM_INFO_BLOCK_TRANSFER,
-	.buffer_bytes_max       = 128*1024,
-	.period_bytes_min       = PAGE_SIZE,
-	.period_bytes_max       = PAGE_SIZE*2,
-	.periods_min            = 2,
-	.periods_max            = 128,
-};
-
-static void event_handler(uint32_t opcode,
-		uint32_t token, uint32_t *payload, void *priv)
-{
-	pr_debug("%s\n", __func__);
-	switch (opcode) {
-	case APR_BASIC_RSP_RESULT:
-		pr_debug("%s: opcode[0x%x]\n", __func__, opcode);
-		break;
-	default:
-		pr_err("Not Supported Event opcode[0x%x]\n", opcode);
-		break;
-	}
-}
-
-static int msm_pcm_open(struct snd_pcm_substream *substream)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct msm_pcm *pcm = &pcm_info;
-	int ret = 0;
-
-	mutex_lock(&pcm->lock);
-
-	snd_soc_set_runtime_hwparams(substream, &dummy_pcm_hardware);
-
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		pcm->playback_substream = substream;
-	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
-		pcm->capture_substream = substream;
-
-	pcm->instance++;
-	pr_debug("%s: pcm out open: %d,%d\n", __func__,
-			pcm->instance, substream->stream);
-	if (pcm->instance == 2) {
-		struct snd_soc_pcm_runtime *soc_pcm_rx =
-				pcm->playback_substream->private_data;
-		struct snd_soc_pcm_runtime *soc_pcm_tx =
-				pcm->capture_substream->private_data;
-		if (pcm->audio_client != NULL)
-			stop_pcm(pcm);
-
-		pcm->audio_client = q6asm_audio_client_alloc(
-				(app_cb)event_handler, pcm);
-		if (!pcm->audio_client) {
-			pr_err("%s: Could not allocate memory\n", __func__);
-			mutex_unlock(&pcm->lock);
-			return -ENOMEM;
-		}
-		pcm->session_id = pcm->audio_client->session;
-		pcm->audio_client->perf_mode = false;
-		ret = q6asm_open_loopack(pcm->audio_client);
-		if (ret < 0) {
-			pr_err("%s: pcm out open failed\n", __func__);
-			q6asm_audio_client_free(pcm->audio_client);
-			mutex_unlock(&pcm->lock);
-			return -ENOMEM;
-		}
-		msm_pcm_routing_reg_phy_stream(soc_pcm_tx->dai_link->be_id,
-			pcm->audio_client->perf_mode,
-			pcm->session_id, pcm->capture_substream->stream);
-		msm_pcm_routing_reg_phy_stream(soc_pcm_rx->dai_link->be_id,
-			pcm->audio_client->perf_mode,
-			pcm->session_id, pcm->playback_substream->stream);
-	}
-	pr_debug("%s: Instance = %d, Stream ID = %s\n",
-			__func__ , pcm->instance, substream->pcm->id);
-	runtime->private_data = pcm;
-
-	mutex_unlock(&pcm->lock);
-
-	return 0;
-}
-
-int msm_set_lb_volume(unsigned volume)
-{
-	int rc = 0;
-	if (pcm_info.audio_client != NULL) {
-		pr_debug("%s: apply loopback vol:%d\n", __func__, volume);
-		rc = q6asm_set_volume(pcm_info.audio_client, volume);
-		if (rc < 0) {
-			pr_err("%s: Send Volume command failed" \
-					" rc=%d\n", __func__, rc);
-		}
-	}
-	return rc;
-}
-
-static void stop_pcm(struct msm_pcm *pcm)
-{
-	struct snd_soc_pcm_runtime *soc_pcm_rx =
-		pcm->playback_substream->private_data;
-	struct snd_soc_pcm_runtime *soc_pcm_tx =
-		pcm->capture_substream->private_data;
-
-	if (pcm->audio_client == NULL)
-		return;
-	q6asm_cmd(pcm->audio_client, CMD_CLOSE);
-
-	msm_pcm_routing_dereg_phy_stream(soc_pcm_rx->dai_link->be_id,
-			SNDRV_PCM_STREAM_PLAYBACK);
-	msm_pcm_routing_dereg_phy_stream(soc_pcm_tx->dai_link->be_id,
-			SNDRV_PCM_STREAM_CAPTURE);
-	q6asm_audio_client_free(pcm->audio_client);
-	pcm->audio_client = NULL;
-}
-
-static int msm_pcm_close(struct snd_pcm_substream *substream)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct msm_pcm *pcm = runtime->private_data;
-	int ret = 0;
-
-	mutex_lock(&pcm->lock);
-
-	pr_debug("%s: end pcm call:%d\n", __func__, substream->stream);
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		pcm->playback_start = 0;
-	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
-		pcm->capture_start = 0;
-
-	pcm->instance--;
-	if (!pcm->playback_start || !pcm->capture_start) {
-		pr_debug("%s: end pcm call\n", __func__);
-		stop_pcm(pcm);
-	}
-
-	mutex_unlock(&pcm->lock);
-	return ret;
-}
-
-static int msm_pcm_prepare(struct snd_pcm_substream *substream)
-{
-	int ret = 0;
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct msm_pcm *pcm = runtime->private_data;
-
-	mutex_lock(&pcm->lock);
-
-	pr_debug("%s: ASM loopback stream:%d\n", __func__, substream->stream);
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		if (!pcm->playback_start)
-			pcm->playback_start = 1;
-	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
-		if (!pcm->capture_start)
-			pcm->capture_start = 1;
-	}
-	mutex_unlock(&pcm->lock);
-
-	return ret;
-}
-
-static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct msm_pcm *pcm = runtime->private_data;
-
-	switch (cmd) {
-	case SNDRV_PCM_TRIGGER_START:
-	case SNDRV_PCM_TRIGGER_RESUME:
-	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		pr_debug("%s: playback_start:%d,capture_start:%d\n", __func__,
-				pcm->playback_start, pcm->capture_start);
-		if (pcm->playback_start && pcm->capture_start)
-			q6asm_run_nowait(pcm->audio_client, 0, 0, 0);
-		break;
-	case SNDRV_PCM_TRIGGER_SUSPEND:
-	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-	case SNDRV_PCM_TRIGGER_STOP:
-		pr_debug("%s:Pause/Stop - playback_start:%d,capture_start:%d\n",
-			__func__, pcm->playback_start, pcm->capture_start);
-		if (pcm->playback_start && pcm->capture_start)
-			q6asm_cmd_nowait(pcm->audio_client, CMD_PAUSE);
-		break;
-	default:
-		break;
-	}
-
-	return 0;
-}
-
-static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
-				struct snd_pcm_hw_params *params)
-{
-
-	pr_debug("%s: ASM loopback\n", __func__);
-
-	return snd_pcm_lib_alloc_vmalloc_buffer(substream,
-		params_buffer_bytes(params));
-}
-
-static int msm_pcm_hw_free(struct snd_pcm_substream *substream)
-{
-	return snd_pcm_lib_free_vmalloc_buffer(substream);
-}
-
-static struct snd_pcm_ops msm_pcm_ops = {
-	.open           = msm_pcm_open,
-	.hw_params	= msm_pcm_hw_params,
-	.hw_free	= msm_pcm_hw_free,
-	.close          = msm_pcm_close,
-	.prepare        = msm_pcm_prepare,
-	.trigger        = msm_pcm_trigger,
-};
-
-
-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_debug("%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-loopback",
-		.owner = THIS_MODULE,
-	},
-	.probe = msm_pcm_probe,
-	.remove = __devexit_p(msm_pcm_remove),
-};
-
-static int __init msm_soc_platform_init(void)
-{
-	memset(&pcm_info, 0, sizeof(struct msm_pcm));
-	mutex_init(&pcm_info.lock);
-
-	return platform_driver_register(&msm_pcm_driver);
-}
-module_init(msm_soc_platform_init);
-
-static void __exit msm_soc_platform_exit(void)
-{
-	mutex_destroy(&pcm_info.lock);
-	platform_driver_unregister(&msm_pcm_driver);
-}
-module_exit(msm_soc_platform_exit);
-
-MODULE_DESCRIPTION("ASM loopback module platform driver");
-MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index aaae373..6cf74d5 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -1608,9 +1608,6 @@
 	SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_INT_BT_SCO_RX,
 	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
-	SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_INT_BT_SCO_RX,
-	MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
-	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new int_fm_rx_mixer_controls[] = {
@@ -1647,9 +1644,6 @@
 	SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_AFE_PCM_RX,
 	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
-	SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_AFE_PCM_RX,
-	MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
-	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new auxpcm_rx_mixer_controls[] = {
@@ -1668,9 +1662,6 @@
 	SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_AUXPCM_RX,
 	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
-	SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_AUXPCM_RX,
-	MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
-	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new sec_auxpcm_rx_mixer_controls[] = {
@@ -1767,12 +1758,6 @@
 	msm_routing_put_audio_mixer),
 };
 
-static const struct snd_kcontrol_new mmul6_mixer_controls[] = {
-	SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX,
-	MSM_FRONTEND_DAI_MULTIMEDIA6, 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,
@@ -2564,7 +2549,6 @@
 	SND_SOC_DAPM_AIF_OUT("MM_UL2", "MultiMedia2 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("MM_UL4", "MultiMedia4 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("MM_UL5", "MultiMedia5 Capture", 0, 0, 0, 0),
-	SND_SOC_DAPM_AIF_OUT("MM_UL6", "MultiMedia6 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("CS-VOICE_DL1", "CS-VOICE Playback", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("CS-VOICE_UL1", "CS-VOICE Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("VoLTE_DL", "VoLTE Playback", 0, 0, 0, 0),
@@ -2672,8 +2656,6 @@
 	mmul4_mixer_controls, ARRAY_SIZE(mmul4_mixer_controls)),
 	SND_SOC_DAPM_MIXER("MultiMedia5 Mixer", SND_SOC_NOPM, 0, 0,
 	mmul5_mixer_controls, ARRAY_SIZE(mmul5_mixer_controls)),
-	SND_SOC_DAPM_MIXER("MultiMedia6 Mixer", SND_SOC_NOPM, 0, 0,
-	mmul6_mixer_controls, ARRAY_SIZE(mmul6_mixer_controls)),
 	SND_SOC_DAPM_MIXER("AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
 	auxpcm_rx_mixer_controls, ARRAY_SIZE(auxpcm_rx_mixer_controls)),
 	SND_SOC_DAPM_MIXER("SEC_AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
@@ -2848,7 +2830,6 @@
 	{"MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
 	{"MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
 	{"MI2S_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
-	{"MI2S_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
 	{"MI2S_RX", NULL, "MI2S_RX Audio Mixer"},
 
 	{"MultiMedia1 Mixer", "PRI_TX", "PRI_I2S_TX"},
@@ -2867,7 +2848,6 @@
 	{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
 	{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
 	{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
-	{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
 	{"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX Audio Mixer"},
 
 	{"INTERNAL_FM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -2882,14 +2862,12 @@
 	{"AFE_PCM_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
 	{"AFE_PCM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
 	{"AFE_PCM_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
-	{"AFE_PCM_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
 	{"PCM_RX", NULL, "AFE_PCM_RX Audio Mixer"},
 
 	{"MultiMedia1 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
 	{"MultiMedia5 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
 	{"MultiMedia1 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
 	{"MultiMedia5 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
-	{"MultiMedia6 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
 
 	{"MultiMedia1 Mixer", "AFE_PCM_TX", "PCM_TX"},
 	{"MultiMedia5 Mixer", "AFE_PCM_TX", "PCM_TX"},
@@ -2898,14 +2876,12 @@
 	{"MM_UL2", NULL, "MultiMedia2 Mixer"},
 	{"MM_UL4", NULL, "MultiMedia4 Mixer"},
 	{"MM_UL5", NULL, "MultiMedia5 Mixer"},
-	{"MM_UL6", NULL, "MultiMedia6 Mixer"},
 
 	{"AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
 	{"AUX_PCM_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
 	{"AUX_PCM_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
 	{"AUX_PCM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
 	{"AUX_PCM_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
-	{"AUX_PCM_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
 	{"AUX_PCM_RX", NULL, "AUX_PCM_RX Audio Mixer"},
 
 	{"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
diff --git a/sound/soc/msm/msm-pcm-routing.h b/sound/soc/msm/msm-pcm-routing.h
index 202e7ea..b571483 100644
--- a/sound/soc/msm/msm-pcm-routing.h
+++ b/sound/soc/msm/msm-pcm-routing.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -145,8 +145,6 @@
 
 int lpa_set_volume(unsigned volume);
 
-int msm_set_lb_volume(unsigned volume);
-
 int msm_routing_check_backend_enabled(int fedai_id);
 
 int multi_ch_pcm_set_volume(unsigned volume);
diff --git a/sound/soc/msm/msm8930.c b/sound/soc/msm/msm8930.c
index 196cb44..d674b8b 100644
--- a/sound/soc/msm/msm8930.c
+++ b/sound/soc/msm/msm8930.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -1135,22 +1135,6 @@
 		.ignore_pmdown_time = 1,
 		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA5,
 	},
-	{
-		.name = "MSM8960 FM",
-		.stream_name = "MultiMedia6",
-		.cpu_dai_name	= "MultiMedia6",
-		.platform_name  = "msm-pcm-loopback",
-		.dynamic = 1,
-		.codec_dai_name = "snd-soc-dummy-dai",
-		.codec_name = "snd-soc-dummy",
-		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
-				SND_SOC_DPCM_TRIGGER_POST},
-		.ignore_suspend = 1,
-		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
-		/* this dainlink has playback support */
-		.ignore_pmdown_time = 1,
-		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA6,
-	},
 	/* Backend DAI Links */
 	{
 		.name = LPASS_BE_SLIMBUS_0_RX,
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 6712941..c5b2a52 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -137,6 +137,7 @@
 
 static int msm_btsco_rate = BTSCO_RATE_8KHZ;
 static int msm_btsco_ch = 1;
+static int msm_hdmi_rx_ch = 2;
 
 static struct mutex cdc_mclk_mutex;
 static struct q_clkdiv *codec_clk;
@@ -413,6 +414,8 @@
 static const char *const spk_function[] = {"Off", "On"};
 static const char *const slim0_rx_ch_text[] = {"One", "Two"};
 static const char *const slim0_tx_ch_text[] = {"One", "Two", "Three", "Four"};
+static char const *hdmi_rx_ch_text[] = {"Two", "Three", "Four", "Five",
+					"Six", "Seven", "Eight"};
 
 static const struct soc_enum msm_enum[] = {
 	SOC_ENUM_SINGLE_EXT(2, spk_function),
@@ -488,6 +491,30 @@
 	return 0;
 }
 
+static int msm_hdmi_rx_ch_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm_hdmi_rx_ch  = %d\n", __func__,
+			msm_hdmi_rx_ch);
+	ucontrol->value.integer.value[0] = msm_hdmi_rx_ch - 2;
+
+	return 0;
+}
+
+static int msm_hdmi_rx_ch_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	msm_hdmi_rx_ch = ucontrol->value.integer.value[0] + 2;
+	if (msm_hdmi_rx_ch > 8) {
+		pr_err("%s: channels exceeded 8.Limiting to max channels-8\n",
+			__func__);
+		msm_hdmi_rx_ch = 8;
+	}
+	pr_debug("%s: msm_hdmi_rx_ch = %d\n", __func__, msm_hdmi_rx_ch);
+
+	return 1;
+}
+
 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),
@@ -571,7 +598,10 @@
 	pr_debug("%s channels->min %u channels->max %u ()\n", __func__,
 			channels->min, channels->max);
 
+	if (channels->max < 2)
+		channels->min = channels->max = 2;
 	rate->min = rate->max = 48000;
+	channels->min = channels->max = msm_hdmi_rx_ch;
 
 	return 0;
 }
@@ -742,6 +772,7 @@
 	SOC_ENUM_SINGLE_EXT(2, spk_function),
 	SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
 	SOC_ENUM_SINGLE_EXT(4, slim0_tx_ch_text),
+	SOC_ENUM_SINGLE_EXT(7, hdmi_rx_ch_text),
 };
 
 static const struct snd_kcontrol_new msm_snd_controls[] = {
@@ -753,6 +784,8 @@
 			msm_slim_0_tx_ch_get, msm_slim_0_tx_ch_put),
 	SOC_ENUM_EXT("AUX PCM SampleRate", msm8974_auxpcm_enum[0],
 			msm8974_auxpcm_rate_get, msm8974_auxpcm_rate_put),
+	SOC_ENUM_EXT("HDMI_RX Channels", msm_snd_enum[3],
+			msm_hdmi_rx_ch_get, msm_hdmi_rx_ch_put),
 };
 
 static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
diff --git a/sound/soc/msm/qdsp6/q6adm.c b/sound/soc/msm/qdsp6/q6adm.c
index 58a07d6..4c50b53 100644
--- a/sound/soc/msm/qdsp6/q6adm.c
+++ b/sound/soc/msm/qdsp6/q6adm.c
@@ -1267,6 +1267,8 @@
 	int ret = 0, i = 0;
 	/* Assumes port_ids have already been validated during adm_open */
 	int index = afe_get_port_index(copp_id);
+	int copp_cnt;
+
 	if (index < 0 || index >= AFE_MAX_PORTS) {
 		pr_err("%s: invalid port idx %d token %d\n",
 					__func__, index, copp_id);
@@ -1289,9 +1291,19 @@
 	route.hdr.opcode = ADM_CMD_MATRIX_MAP_ROUTINGS;
 	route.num_sessions = 1;
 	route.session[0].id = session_id;
-	route.session[0].num_copps = num_copps;
 
-	for (i = 0; i < num_copps; i++) {
+	if (num_copps < ADM_MAX_COPPS) {
+		copp_cnt = num_copps;
+	} else {
+		copp_cnt = ADM_MAX_COPPS;
+		/* print out warning for now as playback/capture to/from
+		 * COPPs more than maximum allowed is extremely unlikely
+		 */
+		pr_warn("%s: max out routable COPPs\n", __func__);
+	}
+
+	route.session[0].num_copps = copp_cnt;
+	for (i = 0; i < copp_cnt; i++) {
 		int tmp;
 		port_id[i] = afe_convert_virtual_to_portid(port_id[i]);
 
@@ -1304,7 +1316,8 @@
 			route.session[0].copp_id[i] =
 					atomic_read(&this_adm.copp_id[tmp]);
 	}
-	if (num_copps % 2)
+
+	if (copp_cnt % 2)
 		route.session[0].copp_id[i] = 0;
 
 	switch (path) {
diff --git a/sound/soc/msm/qdsp6/q6afe.c b/sound/soc/msm/qdsp6/q6afe.c
index 2d44a41..f29f02e 100644
--- a/sound/soc/msm/qdsp6/q6afe.c
+++ b/sound/soc/msm/qdsp6/q6afe.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2013, .qualcomm.com. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -1587,7 +1587,7 @@
 				goto afe_error;
 			}
 
-			if (param[1] < 0 || param[1] > 100) {
+			if (param[1] > 100) {
 				pr_err("%s: Error, volume shoud be 0 to 100"
 					" percentage param = %lu\n",
 					__func__, param[1]);
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index 8ec2e94..8fd5840 100644
--- a/sound/soc/msm/qdsp6/q6asm.c
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -1,6 +1,6 @@
 
 /*
- * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-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
@@ -912,7 +912,6 @@
 		case ASM_STREAM_CMD_OPEN_WRITE:
 		case ASM_STREAM_CMD_OPEN_WRITE_V2_1:
 		case ASM_STREAM_CMD_OPEN_READWRITE:
-		case ASM_STREAM_CMD_OPEN_LOOPBACK:
 		case ASM_DATA_CMD_MEDIA_FORMAT_UPDATE:
 		case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
 		case ASM_STREAM_CMD_OPEN_WRITE_COMPRESSED:
@@ -1849,45 +1848,6 @@
 	return -EINVAL;
 }
 
-int q6asm_open_loopack(struct audio_client *ac)
-{
-	int rc = 0x00;
-	struct asm_stream_cmd_open_loopback open;
-
-	if ((ac == NULL) || (ac->apr == NULL)) {
-		pr_err("APR handle NULL\n");
-		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_LOOPBACK;
-
-	open.mode_flags = 0;
-	open.src_endpointype = 0;
-	open.sink_endpointype = 0;
-	/* source endpoint : matrix */
-	open.postprocopo_id = get_asm_topology();
-	if (open.postprocopo_id == 0)
-		open.postprocopo_id = DEFAULT_POPP_TOPOLOGY;
-
-	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_LOOPBACK 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)
 {
diff --git a/sound/soc/msm/qdsp6v2/audio_ocmem.c b/sound/soc/msm/qdsp6v2/audio_ocmem.c
index f151e51..145f095 100644
--- a/sound/soc/msm/qdsp6v2/audio_ocmem.c
+++ b/sound/soc/msm/qdsp6v2/audio_ocmem.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -590,7 +590,7 @@
 	pr_debug("%s\n", __func__);
 	audio_ocmem_lcl.audio_ocmem_workqueue =
 		alloc_workqueue("ocmem_audio_client_driver_audio",
-					WQ_NON_REENTRANT, 0);
+					WQ_NON_REENTRANT | WQ_UNBOUND, 0);
 	if (!audio_ocmem_lcl.audio_ocmem_workqueue) {
 		pr_err("%s: Failed to create ocmem audio work queue\n",
 			__func__);
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c
index 48d9e1e..329d293 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -24,11 +24,20 @@
 #include <sound/q6afe-v2.h>
 #include <sound/msm-dai-q6-v2.h>
 
+#define HDMI_RX_CA_MAX 0x32
+
 enum {
 	STATUS_PORT_STARTED, /* track if AFE port has started */
 	STATUS_MAX
 };
 
+struct msm_hdmi_ca {
+	bool set_ca;
+	u32 ca;
+};
+
+static struct msm_hdmi_ca hdmi_ca = { false, 0x0 };
+
 struct msm_dai_q6_hdmi_dai_data {
 	DECLARE_BITMAP(status_mask, STATUS_MAX);
 	u32 rate;
@@ -57,6 +66,20 @@
 	return 0;
 }
 
+static int msm_dai_q6_hdmi_ca_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	hdmi_ca.ca = ucontrol->value.integer.value[0];
+	hdmi_ca.set_ca = true;
+	return 0;
+}
+
+static int msm_dai_q6_hdmi_ca_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = hdmi_ca.ca;
+	return 0;
+}
 
 /* HDMI format field for AFE_PORT_MULTI_CHAN_HDMI_AUDIO_IF_CONFIG command
  *  0: linear PCM
@@ -75,6 +98,10 @@
 	SOC_ENUM_EXT("HDMI RX Format", hdmi_config_enum[0],
 				 msm_dai_q6_hdmi_format_get,
 				 msm_dai_q6_hdmi_format_put),
+	SOC_SINGLE_MULTI_EXT("HDMI RX CA", SND_SOC_NOPM, 0,
+				 HDMI_RX_CA_MAX, 0, 1,
+				 msm_dai_q6_hdmi_ca_get,
+				 msm_dai_q6_hdmi_ca_put),
 };
 
 /* Current implementation assumes hw_param is called once
@@ -152,6 +179,10 @@
 	struct msm_dai_q6_hdmi_dai_data *dai_data = dev_get_drvdata(dai->dev);
 	int rc = 0;
 
+	if (hdmi_ca.set_ca)
+		dai_data->port_config.hdmi_multi_ch.channel_allocation =
+								 hdmi_ca.ca;
+
 	if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
 		rc = afe_port_start(dai->id, &dai_data->port_config,
 				    dai_data->rate);
@@ -186,6 +217,12 @@
 
 	rc = snd_ctl_add(dai->card->snd_card,
 					 snd_ctl_new1(kcontrol, dai_data));
+
+	kcontrol = &hdmi_config_controls[1];
+
+	rc = snd_ctl_add(dai->card->snd_card,
+					 snd_ctl_new1(kcontrol, dai_data));
+
 	return rc;
 }
 
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index ab92269..cf7f182 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -28,6 +28,15 @@
 #include <sound/pcm_params.h>
 #include <mach/clk.h>
 
+static const struct afe_clk_cfg lpass_clk_cfg_default = {
+	AFE_API_VERSION_I2S_CONFIG,
+	Q6AFE_LPASS_OSR_CLK_2_P048_MHZ,
+	0,
+	Q6AFE_LPASS_CLK_SRC_INTERNAL,
+	Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+	Q6AFE_LPASS_MODE_CLK1_VALID,
+	0,
+};
 enum {
 	STATUS_PORT_STARTED, /* track if AFE port has started */
 	STATUS_MAX
@@ -76,11 +85,6 @@
 	SOC_ENUM_SINGLE_EXT(4, mi2s_format),
 };
 
-static struct clk *pcm_src_clk;
-static struct clk *pcm_branch_clk;
-static struct clk *pcm_oe_src_clk;
-static struct clk *pcm_oe_branch_clk;
-
 static DEFINE_MUTEX(aux_pcm_mutex);
 static int aux_pcm_count;
 
@@ -148,6 +152,9 @@
 				struct snd_soc_dai *dai)
 {
 	int rc = 0;
+	struct afe_clk_cfg *lpass_pcm_src_clk = NULL;
+	struct afe_clk_cfg lpass_pcm_oe_clk;
+	struct msm_dai_auxpcm_pdata *auxpcm_pdata = NULL;
 
 	mutex_lock(&aux_pcm_mutex);
 
@@ -176,6 +183,9 @@
 	pr_debug("%s: dai->id = %d aux_pcm_count = %d\n", __func__,
 			dai->id, aux_pcm_count);
 
+	auxpcm_pdata = (struct msm_dai_auxpcm_pdata *)dai->dev->platform_data;
+	lpass_pcm_src_clk = (struct afe_clk_cfg *)auxpcm_pdata->clk_cfg;
+
 	rc = afe_close(PCM_RX); /* can block */
 	if (IS_ERR_VALUE(rc))
 		dev_err(dai->dev, "fail to close PCM_RX  AFE port\n");
@@ -184,8 +194,14 @@
 	if (IS_ERR_VALUE(rc))
 		dev_err(dai->dev, "fail to close AUX PCM TX port\n");
 
-	clk_disable_unprepare(pcm_branch_clk);
-	clk_disable_unprepare(pcm_oe_branch_clk);
+	lpass_pcm_src_clk->clk_val1 = 0;
+	afe_set_lpass_clock(PCM_TX, lpass_pcm_src_clk);
+	afe_set_lpass_clock(PCM_RX, lpass_pcm_src_clk);
+
+	memcpy(&lpass_pcm_oe_clk, &lpass_clk_cfg_default,
+			 sizeof(struct afe_clk_cfg));
+	lpass_pcm_oe_clk.clk_val1 = 0;
+	afe_set_lpass_clock(PCM_RX, &lpass_pcm_oe_clk);
 
 	mutex_unlock(&aux_pcm_mutex);
 }
@@ -197,8 +213,11 @@
 	struct msm_dai_auxpcm_pdata *auxpcm_pdata = NULL;
 	int rc = 0;
 	unsigned long pcm_clk_rate;
+	struct afe_clk_cfg lpass_pcm_oe_clk;
+	struct afe_clk_cfg *lpass_pcm_src_clk = NULL;
 
 	auxpcm_pdata = dai->dev->platform_data;
+	lpass_pcm_src_clk = (struct afe_clk_cfg *)auxpcm_pdata->clk_cfg;
 
 	mutex_lock(&aux_pcm_mutex);
 
@@ -252,32 +271,32 @@
 		return -EINVAL;
 	}
 
-	rc = clk_set_rate(pcm_src_clk, pcm_clk_rate);
+	memcpy(lpass_pcm_src_clk, &lpass_clk_cfg_default,
+			sizeof(struct afe_clk_cfg));
+	lpass_pcm_src_clk->clk_val1 = pcm_clk_rate;
 
+	memcpy(&lpass_pcm_oe_clk, &lpass_clk_cfg_default,
+			sizeof(struct afe_clk_cfg));
+	lpass_pcm_oe_clk.clk_val1 = Q6AFE_LPASS_OSR_CLK_12_P288_MHZ;
+
+	rc = afe_set_lpass_clock(PCM_RX, lpass_pcm_src_clk);
 	if (rc < 0) {
-		pr_err("%s: clk_set_rate failed\n", __func__);
-		mutex_unlock(&aux_pcm_mutex);
+		pr_err("%s:afe_set_lpass_clock on RX pcm_src_clk failed\n",
+							__func__);
 		goto fail;
 	}
 
-	rc = clk_prepare_enable(pcm_branch_clk);
-	if (rc) {
-		pr_err("%s: clk enable failed\n", __func__);
-		mutex_unlock(&aux_pcm_mutex);
-		goto fail;
-	}
-
-	rc = clk_set_rate(pcm_oe_src_clk, 24576000>>1);
+	rc = afe_set_lpass_clock(PCM_TX, lpass_pcm_src_clk);
 	if (rc < 0) {
-		pr_err("%s: clk_set_rate on pcm oe failed\n", __func__);
-		mutex_unlock(&aux_pcm_mutex);
+		pr_err("%s:afe_set_lpass_clock on TX pcm_src_clk failed\n",
+							__func__);
 		goto fail;
 	}
 
-	rc = clk_prepare_enable(pcm_oe_branch_clk);
-	if (rc) {
-		pr_err("%s: clk enable pcm_oe_branch_clk failed\n", __func__);
-		mutex_unlock(&aux_pcm_mutex);
+	rc = afe_set_lpass_clock(PCM_RX, &lpass_pcm_oe_clk);
+	if (rc < 0) {
+		pr_err("%s:afe_set_lpass_clock on pcm_oe_clk failed\n",
+							__func__);
 		goto fail;
 	}
 
@@ -285,9 +304,8 @@
 
 	afe_open(PCM_TX, &dai_data->port_config, dai_data->rate);
 
-	mutex_unlock(&aux_pcm_mutex);
-
 fail:
+	mutex_unlock(&aux_pcm_mutex);
 	return rc;
 }
 
@@ -331,49 +349,6 @@
 	dai->dev->platform_data = auxpcm_pdata;
 	dai->id = dai->dev->id;
 
-	mutex_lock(&aux_pcm_mutex);
-
-	/*
-	 * 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_src_clk) || (!pcm_branch_clk)) {
-		pcm_src_clk = clk_get(dai->dev, auxpcm_pdata->clk);
-
-		if (IS_ERR(pcm_src_clk)) {
-			pr_err("%s: could not get pcm_src_clk\n", __func__);
-			pcm_src_clk = NULL;
-			return -ENODEV;
-		}
-
-		pcm_branch_clk = clk_get(dai->dev, "ibit_clk");
-
-		if (IS_ERR(pcm_branch_clk)) {
-			pr_err("%s: could not get pcm_branch_clk\n", __func__);
-			pcm_branch_clk = NULL;
-			return -ENODEV;
-		}
-	}
-
-	if ((!pcm_oe_src_clk) || (!pcm_oe_branch_clk)) {
-
-		pcm_oe_src_clk = clk_get(dai->dev, "core_oe_src_clk");
-
-		if (IS_ERR(pcm_oe_src_clk)) {
-			pr_err("%s: could not get pcm_oe_src_clk\n", __func__);
-			pcm_oe_src_clk = NULL;
-			return -ENODEV;
-		}
-
-		pcm_oe_branch_clk = clk_get(dai->dev, "core_oe_clk");
-		if (IS_ERR(pcm_oe_branch_clk)) {
-			pr_err("%s: could not get pcm_oe_clk\n", __func__);
-			pcm_oe_branch_clk = NULL;
-			return -ENODEV;
-		}
-	}
-	mutex_unlock(&aux_pcm_mutex);
 
 	dai_data = kzalloc(sizeof(struct msm_dai_q6_dai_data), GFP_KERNEL);
 
@@ -1107,6 +1082,7 @@
 {
 	int rc = 0;
 	struct msm_dai_auxpcm_pdata *auxpcm_pdata = NULL;
+	struct afe_clk_cfg *clk_cfg = NULL;
 	uint32_t val_array[RATE_MAX_NUM_OF_AUX_PCM_RATES];
 
 	auxpcm_pdata = kzalloc(sizeof(struct msm_dai_auxpcm_pdata),
@@ -1117,15 +1093,6 @@
 		return -ENOMEM;
 	}
 
-	rc = of_property_read_string(pdev->dev.of_node,
-			"qcom,msm-cpudai-auxpcm-clk",
-			&auxpcm_pdata->clk);
-	if (rc) {
-		dev_err(&pdev->dev, "%s: qcom,msm-cpudai-auxpcm-clk missing in DT node\n",
-			__func__);
-		goto fail_free_plat;
-	}
-
 	rc = of_property_read_u32_array(pdev->dev.of_node,
 			"qcom,msm-cpudai-auxpcm-mode",
 			val_array, RATE_MAX_NUM_OF_AUX_PCM_RATES);
@@ -1200,17 +1167,26 @@
 	auxpcm_pdata->mode_8k.pcm_clk_rate = (int)val_array[RATE_8KHZ];
 	auxpcm_pdata->mode_16k.pcm_clk_rate = (int)val_array[RATE_16KHZ];
 
+	clk_cfg = kzalloc(sizeof(struct afe_clk_cfg), GFP_KERNEL);
+	if (clk_cfg == NULL) {
+		pr_err("%s: Failed to allocate memory for clk cfg\n", __func__);
+		goto fail_free_plat;
+	}
+	auxpcm_pdata->clk_cfg = clk_cfg;
+
 	platform_set_drvdata(pdev, auxpcm_pdata);
 
 	rc = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
 	if (rc) {
 		dev_err(&pdev->dev, "%s: failed to add child nodes, rc=%d\n",
 				__func__, rc);
-		goto fail_free_plat;
+		goto fail_free_plat1;
 	}
 
 	return rc;
 
+fail_free_plat1:
+	kfree(clk_cfg);
 fail_free_plat:
 	kfree(auxpcm_pdata);
 	return rc;
@@ -1225,9 +1201,12 @@
 static int __devexit msm_auxpcm_resource_remove(
 				struct platform_device *pdev)
 {
-	void *auxpcm_pdata;
+	struct msm_dai_auxpcm_pdata *auxpcm_pdata;
+	struct afe_clk_cfg *clk_cfg;
 
 	auxpcm_pdata = dev_get_drvdata(&pdev->dev);
+	clk_cfg = (struct afe_clk_cfg *)auxpcm_pdata->clk_cfg;
+	kfree(clk_cfg);
 	kfree(auxpcm_pdata);
 
 	return 0;
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
index 1d6e106..fa8609e 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -40,6 +40,12 @@
 	struct snd_pcm *pcm;
 };
 
+struct snd_msm_volume {
+	struct msm_audio *prtd;
+	unsigned volume;
+};
+static struct snd_msm_volume pcm_audio = {NULL, 0x2000};
+
 #define PLAYBACK_NUM_PERIODS	8
 #define PLAYBACK_MAX_PERIOD_SIZE    12288
 #define PLAYBACK_MIN_PERIOD_SIZE    2048
@@ -213,8 +219,11 @@
 	if (prtd->enabled)
 		return 0;
 
-	ret = q6asm_media_format_block_pcm(prtd->audio_client, runtime->rate,
-				runtime->channels);
+	ret = q6asm_media_format_block_multi_ch_pcm(prtd->audio_client,
+							runtime->rate,
+							runtime->channels,
+							!prtd->set_channel_map,
+							prtd->channel_map);
 	if (ret < 0)
 		pr_info("%s: CMD Format block failed\n", __func__);
 
@@ -365,7 +374,9 @@
 	}
 
 	prtd->dsp_cnt = 0;
+	prtd->set_channel_map = false;
 	runtime->private_data = prtd;
+	pcm_audio.prtd = prtd;
 
 	return 0;
 }
@@ -449,7 +460,8 @@
 				prtd->audio_client);
 
 	msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
-	SNDRV_PCM_STREAM_PLAYBACK);
+						SNDRV_PCM_STREAM_PLAYBACK);
+	pcm_audio.prtd = NULL;
 	q6asm_audio_client_free(prtd->audio_client);
 	kfree(prtd);
 	return 0;
@@ -691,13 +703,49 @@
 	.mmap		= msm_pcm_mmap,
 };
 
+static int pcm_chmap_ctl_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	int i;
+	char channel_mapping[PCM_FORMAT_MAX_NUM_CHANNEL];
+
+	pr_debug("%s", __func__);
+	for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+		channel_mapping[i] = (char)(ucontrol->value.integer.value[i]);
+	if (pcm_audio.prtd) {
+		pcm_audio.prtd->set_channel_map = true;
+		memcpy(pcm_audio.prtd->channel_map, channel_mapping,
+			PCM_FORMAT_MAX_NUM_CHANNEL);
+	}
+	return 0;
+}
+
 static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
 	struct snd_card *card = rtd->card->snd_card;
-	int ret = 0;
+	struct snd_pcm *pcm = rtd->pcm->streams[0].pcm;
+	struct snd_pcm_chmap *chmap_info;
+	struct snd_kcontrol *kctl;
+	char device_num[3];
+	int i, ret = 0;
 
 	if (!card->dev->coherent_dma_mask)
 		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+	pr_debug("%s, Channel map cntrl add\n", __func__);
+	ret = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+					NULL, PCM_FORMAT_MAX_NUM_CHANNEL, 0,
+					&chmap_info);
+	if (ret < 0)
+		return ret;
+	kctl = chmap_info->kctl;
+	for (i = 0; i < kctl->count; i++)
+		kctl->vd[i].access |= SNDRV_CTL_ELEM_ACCESS_WRITE;
+	snprintf(device_num, sizeof(device_num), "%d", pcm->device);
+	strlcat(kctl->id.name, device_num, sizeof(kctl->id.name));
+	pr_debug("%s, Overwriting channel map control name to: %s",
+		__func__, kctl->id.name);
+	kctl->put = pcm_chmap_ctl_put;
 	return ret;
 }
 
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h
index e25d356..9a770bf 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h
@@ -1,7 +1,7 @@
 /*
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2012 Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -82,6 +82,8 @@
 	int periods;
 	int mmap_flag;
 	atomic_t pending_buffer;
+	bool set_channel_map;
+	char channel_map[8];
 };
 
 struct output_meta_data_st {
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 26f634b..6b957f6 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -805,6 +805,31 @@
 	return 0;
 }
 
+static int msm_routing_get_channel_map_mixer(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	char channel_map[PCM_FORMAT_MAX_NUM_CHANNEL];
+	int i;
+
+	adm_get_multi_ch_map(channel_map);
+	for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+		ucontrol->value.integer.value[i] = (unsigned) channel_map[i];
+	return 0;
+}
+
+static int msm_routing_put_channel_map_mixer(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	char channel_map[PCM_FORMAT_MAX_NUM_CHANNEL];
+	int i;
+
+	for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+		channel_map[i] = (char)(ucontrol->value.integer.value[i]);
+	adm_set_multi_ch_map(channel_map);
+
+	return 0;
+}
+
 static int msm_routing_get_srs_trumedia_control(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
@@ -1577,6 +1602,12 @@
 	msm_routing_set_compressed_vol_mixer, compressed_rx_vol_gain),
 };
 
+static const struct snd_kcontrol_new multi_ch_channel_map_mixer_controls[] = {
+	SOC_SINGLE_MULTI_EXT("Playback Channel Map", SND_SOC_NOPM, 0, 16,
+	0, 8, msm_routing_get_channel_map_mixer,
+	msm_routing_put_channel_map_mixer),
+};
+
 static const struct snd_kcontrol_new lpa_SRS_trumedia_controls[] = {
 	{.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "SRS TruMedia",
@@ -2491,6 +2522,10 @@
 	snd_soc_add_platform_controls(platform,
 				lpa_SRS_trumedia_controls_I2S,
 			ARRAY_SIZE(lpa_SRS_trumedia_controls_I2S));
+
+	snd_soc_add_platform_controls(platform,
+				multi_ch_channel_map_mixer_controls,
+			ARRAY_SIZE(multi_ch_channel_map_mixer_controls));
 	return 0;
 }
 
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index 660e6a8..bc11304 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -52,6 +52,15 @@
 
 static struct adm_ctl			this_adm;
 
+struct adm_multi_ch_map {
+	bool set_channel_map;
+	char channel_mapping[PCM_FORMAT_MAX_NUM_CHANNEL];
+};
+
+static struct adm_multi_ch_map multi_ch_map = { false,
+						{0, 0, 0, 0, 0, 0, 0, 0}
+					      };
+
 int srs_trumedia_open(int port_id, int srs_tech_id, void *srs_params)
 {
 	struct adm_cmd_set_pp_params_inband_v5 *adm_params = NULL;
@@ -266,6 +275,21 @@
 			__func__, data->opcode, data->payload_size);
 }
 
+void adm_set_multi_ch_map(char *channel_map)
+{
+	memcpy(multi_ch_map.channel_mapping, channel_map,
+		PCM_FORMAT_MAX_NUM_CHANNEL);
+	multi_ch_map.set_channel_map = true;
+}
+
+void adm_get_multi_ch_map(char *channel_map)
+{
+	if (multi_ch_map.set_channel_map) {
+		memcpy(channel_map, multi_ch_map.channel_mapping,
+			PCM_FORMAT_MAX_NUM_CHANNEL);
+	}
+}
+
 static int32_t adm_callback(struct apr_client_data *data, void *priv)
 {
 	uint32_t *payload;
@@ -743,6 +767,11 @@
 					channel_mode);
 			return -EINVAL;
 		}
+		if ((open.dev_num_channel > 2) &&
+			multi_ch_map.set_channel_map)
+			memcpy(open.dev_channel_mapping,
+				multi_ch_map.channel_mapping,
+				PCM_FORMAT_MAX_NUM_CHANNEL);
 
 		pr_debug("%s: port_id=%#x rate=%d topology_id=0x%X\n",
 			__func__, open.endpoint_id_1, open.sample_rate,
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 70339d1..846c80e 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -21,7 +21,6 @@
 #include <linux/msm_ion.h>
 #include <sound/apr_audio-v2.h>
 #include <sound/q6afe-v2.h>
-
 #include <sound/q6audio-v2.h>
 
 #include "audio_acdb.h"
@@ -2020,6 +2019,175 @@
 	return ret;
 }
 
+int afe_set_lpass_clock(u16 port_id, struct afe_clk_cfg *cfg)
+{
+	struct afe_lpass_clk_config_command clk_cfg;
+	int index = 0;
+	int ret = 0;
+
+	if (!cfg) {
+		pr_err("%s: clock cfg is NULL\n", __func__);
+		ret = -EINVAL;
+		return ret;
+	}
+	index = q6audio_get_port_index(port_id);
+	if (q6audio_is_digital_pcm_interface(port_id) < 0)
+		return -EINVAL;
+
+	ret = afe_q6_interface_prepare();
+	if (ret != 0)
+		return ret;
+
+	clk_cfg.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	clk_cfg.hdr.pkt_size = sizeof(clk_cfg);
+	clk_cfg.hdr.src_port = 0;
+	clk_cfg.hdr.dest_port = 0;
+	clk_cfg.hdr.token = index;
+
+	clk_cfg.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+	clk_cfg.param.port_id = q6audio_get_port_id(port_id);
+	clk_cfg.param.payload_size = sizeof(clk_cfg) - sizeof(struct apr_hdr)
+						- sizeof(clk_cfg.param);
+	clk_cfg.param.payload_address_lsw = 0x00;
+	clk_cfg.param.payload_address_msw = 0x00;
+	clk_cfg.param.mem_map_handle = 0x00;
+	clk_cfg.pdata.module_id = AFE_MODULE_AUDIO_DEV_INTERFACE;
+	clk_cfg.pdata.param_id = AFE_PARAM_ID_LPAIF_CLK_CONFIG;
+	clk_cfg.pdata.param_size =  sizeof(clk_cfg.clk_cfg);
+	clk_cfg.clk_cfg = *cfg;
+
+	pr_debug("%s: Minor version =%x clk val1 = %d\n"
+		 "clk val2 = %d, clk src = %x\n"
+		 "clk root = %x clk mode = %x resrv = %x\n"
+		 "port id = %x\n",
+		 __func__, cfg->i2s_cfg_minor_version,
+		 cfg->clk_val1, cfg->clk_val2, cfg->clk_src,
+		 cfg->clk_root, cfg->clk_set_mode,
+		 cfg->reserved, q6audio_get_port_id(port_id));
+
+	atomic_set(&this_afe.state, 1);
+	atomic_set(&this_afe.status, 0);
+	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &clk_cfg);
+	if (ret < 0) {
+		pr_err("%s: AFE enable 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) {
+		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;
+	}
+
+fail_cmd:
+	return ret;
+}
+
+int afe_set_lpass_internal_digital_codec_clock(u16 port_id,
+			struct afe_digital_clk_cfg *cfg)
+{
+	struct afe_lpass_digital_clk_config_command clk_cfg;
+	int index = 0;
+	int ret = 0;
+
+	if (!cfg) {
+		pr_err("%s: clock cfg is NULL\n", __func__);
+		ret = -EINVAL;
+		return ret;
+	}
+	index = q6audio_get_port_index(port_id);
+	if (q6audio_is_digital_pcm_interface(port_id) < 0)
+		return -EINVAL;
+
+	ret = afe_q6_interface_prepare();
+	if (ret != 0)
+		return ret;
+
+	clk_cfg.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	clk_cfg.hdr.pkt_size = sizeof(clk_cfg);
+	clk_cfg.hdr.src_port = 0;
+	clk_cfg.hdr.dest_port = 0;
+	clk_cfg.hdr.token = index;
+
+	clk_cfg.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+	clk_cfg.param.port_id = q6audio_get_port_id(port_id);
+	clk_cfg.param.payload_size = sizeof(clk_cfg) - sizeof(struct apr_hdr)
+						- sizeof(clk_cfg.param);
+	clk_cfg.param.payload_address_lsw = 0x00;
+	clk_cfg.param.payload_address_msw = 0x00;
+	clk_cfg.param.mem_map_handle = 0x00;
+	clk_cfg.pdata.module_id = AFE_MODULE_AUDIO_DEV_INTERFACE;
+	clk_cfg.pdata.param_id = AFE_PARAM_ID_INTERNAL_DIGIATL_CDC_CLK_CONFIG;
+	clk_cfg.pdata.param_size =  sizeof(clk_cfg.clk_cfg);
+	clk_cfg.clk_cfg = *cfg;
+
+	pr_debug("%s: Minor version =%x clk val = %d\n"
+		 "clk root = %x resrv = %x port id = %x\n",
+		 __func__, cfg->i2s_cfg_minor_version,
+		 cfg->clk_val, cfg->clk_root, cfg->reserved,
+		 q6audio_get_port_id(port_id));
+
+	atomic_set(&this_afe.state, 1);
+	atomic_set(&this_afe.status, 0);
+	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &clk_cfg);
+	if (ret < 0) {
+		pr_err("%s: AFE enable 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) {
+		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;
+	}
+
+fail_cmd:
+	return ret;
+}
+
+int q6afe_check_osr_clk_freq(u32 freq)
+{
+	int ret = 0;
+	switch (freq) {
+	case Q6AFE_LPASS_OSR_CLK_12_P288_MHZ:
+	case Q6AFE_LPASS_OSR_CLK_8_P192_MHZ:
+	case Q6AFE_LPASS_OSR_CLK_6_P144_MHZ:
+	case Q6AFE_LPASS_OSR_CLK_4_P096_MHZ:
+	case Q6AFE_LPASS_OSR_CLK_3_P072_MHZ:
+	case Q6AFE_LPASS_OSR_CLK_2_P048_MHZ:
+	case Q6AFE_LPASS_OSR_CLK_1_P536_MHZ:
+	case Q6AFE_LPASS_OSR_CLK_1_P024_MHZ:
+	case Q6AFE_LPASS_OSR_CLK_768_kHZ:
+	case Q6AFE_LPASS_OSR_CLK_512_kHZ:
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	return ret;
+}
+
 static int __init afe_init(void)
 {
 	int i = 0;
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 8d579c6..fc8bfeb 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -1851,12 +1851,12 @@
 		lchannel_mapping[3] = PCM_CHANNEL_LB;
 		lchannel_mapping[4] = PCM_CHANNEL_RB;
 	} 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;
+		lchannel_mapping[0] = PCM_CHANNEL_FC;
+		lchannel_mapping[1] = PCM_CHANNEL_FL;
+		lchannel_mapping[2] = PCM_CHANNEL_FR;
+		lchannel_mapping[3] = PCM_CHANNEL_LB;
+		lchannel_mapping[4] = PCM_CHANNEL_RB;
+		lchannel_mapping[5] = PCM_CHANNEL_LFE;
 	} else if (channels == 8) {
 		lchannel_mapping[0] = PCM_CHANNEL_FL;
 		lchannel_mapping[1] = PCM_CHANNEL_FR;
@@ -2166,6 +2166,56 @@
 	return -EINVAL;
 }
 
+int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
+				uint32_t rate, uint32_t channels,
+				bool use_default_chmap, char *channel_map)
+{
+	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 (use_default_chmap) {
+		if (q6asm_map_channels(channel_mapping, channels)) {
+			pr_err("%s: map channels failed", __func__);
+			return -EINVAL;
+		}
+	} else {
+		memcpy(channel_mapping, channel_map,
+			 PCM_FORMAT_MAX_NUM_CHANNEL);
+	}
+
+	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)
 {
diff --git a/sound/soc/msm/qdsp6v2/q6audio-v2.c b/sound/soc/msm/qdsp6v2/q6audio-v2.c
index 5e2e618..985a33d 100644
--- a/sound/soc/msm/qdsp6v2/q6audio-v2.c
+++ b/sound/soc/msm/qdsp6v2/q6audio-v2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -123,6 +123,31 @@
 	return ret;
 }
 
+int q6audio_is_digital_pcm_interface(u16 port_id)
+{
+	int ret = 0;
+
+	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 AFE_PORT_ID_TERTIARY_MI2S_TX:
+	case AFE_PORT_ID_TERTIARY_MI2S_RX:
+	case AFE_PORT_ID_QUATERNARY_MI2S_RX:
+	case AFE_PORT_ID_QUATERNARY_MI2S_TX:
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
 int q6audio_validate_port(u16 port_id)
 {
 	int ret;
diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c
index 63741ec..bd65213 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.c
+++ b/sound/soc/msm/qdsp6v2/q6voice.c
@@ -4005,7 +4005,7 @@
 		if (data->payload_size) {
 			ptr = data->payload;
 
-			pr_info("%x %x\n", ptr[0], ptr[1]);
+			pr_debug("%x %x\n", ptr[0], ptr[1]);
 			/* ping mvm service ACK */
 			switch (ptr[0]) {
 			case VSS_IMVM_CMD_CREATE_PASSIVE_CONTROL_SESSION:
@@ -4137,7 +4137,7 @@
 		if (data->payload_size) {
 			ptr = data->payload;
 
-			pr_info("%x %x\n", ptr[0], ptr[1]);
+			pr_debug("%x %x\n", ptr[0], ptr[1]);
 			if (ptr[1] != 0) {
 				pr_err("%s: cmd = 0x%x returned error = 0x%x\n",
 					__func__, ptr[0], ptr[1]);
@@ -4380,7 +4380,7 @@
 		if (data->payload_size) {
 			ptr = data->payload;
 
-			pr_info("%x %x\n", ptr[0], ptr[1]);
+			pr_debug("%x %x\n", ptr[0], ptr[1]);
 			if (ptr[1] != 0) {
 				pr_err("%s: cmd = 0x%x returned error = 0x%x\n",
 					__func__, ptr[0], ptr[1]);
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 5ac643416..99047178 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -78,7 +78,7 @@
 	[snd_soc_dapm_pre] = 0,
 	[snd_soc_dapm_aif_in] = 1,
 	[snd_soc_dapm_aif_out] = 1,
-	[snd_soc_dapm_adc] = 1,
+	[snd_soc_dapm_adc] = 5,
 	[snd_soc_dapm_hp] = 2,
 	[snd_soc_dapm_spk] = 2,
 	[snd_soc_dapm_out_drv] = 2,