Merge "defconfig: msm9625: enable display support"
diff --git a/Documentation/arm/msm/n_smux.txt b/Documentation/arm/msm/n_smux.txt
new file mode 100644
index 0000000..c9123ad
--- /dev/null
+++ b/Documentation/arm/msm/n_smux.txt
@@ -0,0 +1,630 @@
+Introduction
+============
+
+The Serial Mux (SMUX) is a TTY Line Discipline that multiplexes
+multiple logical channels onto a single TTY serial channel.  The
+logical channels are exposed through a kernel API.
+
+Companion adaptation drivers use the kernel API to expose logical
+channels as character devices (SMUX CTL - smux_ctl.c) to the user-space
+and as net devices (SMUX RMNET - msm_rmnet_smux.c) to the TCP/IP stack.
+
+Power control calls are supported to the physical serial driver to
+optimize power usage.
+
+
+Software description
+====================
+
+The Serial Mux driver will be similar in design to the SDIO DMUX and
+BAM DMUX drivers and will use the same multiplexing protocol with
+additional commands to support inactivity timeouts along with
+power-down and wake-up handshaking.  Companion adaptation drivers will
+support data-plane traffic through TCP/IP (SMUX_RMNET) and control
+plane traffic through SMUX_CTL.
+
+
+   ttyHS0     RMNET[0..N]            smuxctl[0..M]
+     |           |                        |
+     |           |                        |
+     |   ------------------      -------------------
+     |  |    IP Framework  |    |   VFS Framework   |
+     |   ------------------      -------------------
+     |     |           |            |           |
+     |     |           |            |           |
+     |  -------     -------      -------     -------
+     | | Rmnet |   | Rmnet |    | CDEV  |   | CDEV  |
+     | | Dev 0 |...| Dev N |    | Dev 0 |...| Dev M |
+     |  ---------------------   ---------------------   -------------
+     | |                     | |                     | |    Other    |
+     | |    msm_rmnet_smux   | |       smux_ctl      | | Kernel-only |
+     | |                     | |                     | |   Clients   |
+     |  ---------------------   ---------------------   -------------
+     |     |             |         |             |             |
+     |     |             |         |             |             |
+     |     |             |         |             |             |
+     |     |             |         |             |             |
+     |      ---------------------------------------------------
+     |                                               |
+     |                                               |
+     |                                               |
+     |                                               |
+   ---------------                         --------------------
+  |               |                       |                    |
+  | TTY Framework | <- Line Discipline -> |        SMUX        |
+  |               |                       |                    |
+   ---------------                         --------------------
+     |                                              |
+     |                                              |
+   ---------------                                  |
+  |               |                                 |
+  |    HS UART    |<---------- Power API -----------
+  |               |
+   ---------------
+         |
+         V
+   To Remote System
+
+
+Each logical channel will contain package management structures
+including a watermark to ensure fair usage of the physical layer by
+competing logical channels.  All data for logical channels will be
+processed in FIFO order.
+
+Once data has been queued with SMUX, processing, copying of data, and
+notification to clients will be done using a combination of the TTY
+framework notification context and a workqueue.  The lifetime of all
+buffers is controlled by the clients with SMUX taking temporary
+ownership of the buffers for read and write operations.
+
+The physical transport is assumed to be perfect and all errors will be
+handled by notifying the client of the failure.  Watermark support and
+round-robin scheduling ensure that individual logical channels do not
+starve other logical channels.
+
+Data stalls caused by failure of the remote system are handled by
+Subsystem Restart.  The restart logic will notify clients of the
+failure and all read and write buffers will be returned to the client
+with an error notification.
+
+Design
+======
+
+The goals for SMUX are to:
+	1) multiplex multiple logical channels into a single physical
+	   channel
+	2) support a kernel API
+	3) provide power control of the physical layer
+
+In addition, the companion adapter modules have the goals:
+	1) support userspace character-device clients (smux_ctl)
+	2) support net devices through the TCP/IP stack (msm_rmnet_smux)
+
+Alternate designs consider including 3GPP 27.010 MUX protocol
+implementations and existing SDIO CMUX/DMUX implementations.
+
+The 3GPP 27.010 MUX protocol as implemented in both n_gsm.c and OpenEZX
+looked promising at first glance.  However, upon further inspection,
+the implementations did not fully implement the power-control portions
+of the 27.010 MUX protocol.  They also did not support kernel clients
+as they were designed to work only with userspace through TTY devices.
+The code was reviewed to determine the effort to add power-control
+signaling to the physical transport driver and to add a kernel API, but
+it was deemed that adding the API to support both of these behaviors
+would be difficult to do in a generic way such that it would be
+accepted by the upstream community.
+
+The SDIO CMUX/DMUX drivers do not have power control in them and the
+CMUX and DMUX drivers both require a separate physical channel.  To use
+them, we would need to create an additional mux layer that would sit
+between CMUX/DMUX and the HS UART driver which would add another MUX
+header.
+
+Design - MUX Protocol
+=====================
+The MUX packet consists of a header (detailed below) and a payload.
+All values are in little-endian format and all reserved fields are set
+to zero unless otherwise mentioned in the individual command
+descriptions.
+
+Invalid commands and malformed commands will be logged to the kernel log
+as an error and ignored.
+
+	 -----------------------------------------
+	|31      24|       16|         8|        0|
+	|----------|---------|----------|---------|
+	|    Magic Number    |   Flags  |   CMD   |
+	|----------|---------|----------|---------|
+	| Pad Len  |   LCID  |  Packet Length (N) |
+	|-----------------------------------------|
+	|       Data Payload (0..N bytes)         |
+	|-----------------------------------------|
+	|        Pad Data (0..Pad Len bytes)      |
+	 -----------------------------------------
+
+Field definitions:
+ * Magic Number - always 0x33FC
+ * Flags - flags for individual commands
+ * CMD - SMUX command
+ * Pad Len - Padding in bytes at the end of the payload
+ * LCID - Logical channel ID
+ * Packet Length - Length of the data payload in bytes
+
+Commands
+ 0x0 - Data
+ 0x1 - Open Logical Channel
+ 0x2 - Close Logical Channel
+ 0x3 - Status
+ 0x4 - Power Control
+
+Data Command
+------------
+The Data command sends data on an already fully-opened logical channel.
+
+Flags:
+ * Bits 0:7 - Reserved
+
+Open Logical Channel Command
+----------------------------
+The Open command is a request to open a logical channel.  Each channel
+will have a local and remote open flag.  The remote open flag will be
+set to open when receiving an open command and responding with an open
+ACK.  The local open flag is set to open when sending an open command
+and receiving an ACK.
+
+               Remote Side  |  Local Side
+                            |
+ SMUX Client   SMUX                    SMUX                  SMUX Client
+     |          |                       |                        |
+     |  Open    |                       |                        |
+     |--------->|                       |                        |
+     |          |  Open Logical Channel |                        |
+     |          |---------------------->|                        |
+     |          |                       |---                     |
+     |          |                       |   | Set Remote Open    |
+     |          |                       |<--                     |
+     |          |        Open ACK       |                        |
+     |          |<----------------------|                        |
+     |          |---                    |                        |
+     |          |   | Set Local Open    |                        |
+     |          |<--                    |                        |
+     |         ...                     ...                      ...
+     |          |                       |    msm_smux_open()     |
+     |          |                       |<-----------------------|
+     |          |  Open Logical Channel |                        |
+     |          |<----------------------|                        |
+     |          |                       |                        |
+     |          |---                    |                        |
+     |          |   | Set Remote Open   |                        |
+     |          |<--                    |                        |
+     |          |        Open ACK       |                        |
+     |          |---------------------->|                        |
+     |          |                       |---                     |
+     |          |                       |   | Set Local Open     |
+     |          |                       |<--                     |
+     |          |                       | notify(SMUX_CONNECTED) |
+     |          |                       |----------------------->|
+
+
+          Logical channel is now fully open and can receive
+          and transmit data.
+
+No data shall be transmitted over the physical link for the logical
+channel unless the channel is open.
+
+Flags:
+ * Bit 0 - 1 = ACK
+ * Bit 1 - Power Collapse Enable
+ * Bit 2 - Remote Loopback Enable
+ * Bits 3:7 - Reserved
+
+Power Collapse Enable (bit 1) enables power-collapse handshaking when
+processing an open command.  The first logical channel open command
+received from the remote side will set the global power control state
+and all subsequent open commands should use the same value of the Power
+Collapse bit.  The value of this bit can be changed during runtime by
+closing all logical channels and then re-opening them with the new
+global state.
+
+If the protocol stack does not support power collapse and it receives
+an open command with the Power Collapse Enable bit set, then it
+shall respond with an open command with the Power Collapse Enable bit
+cleared.
+
+If Power Collapse is disabled, then Power Control Commands should not
+be sent.
+
+Remote Loopback Enable (bit 2) enables loopback support when data is
+received from the remote side.  In this case, SMUX should echo the
+received data packet back to the sender.
+
+Close Logical Channel Command
+-----------------------------
+The Close command closes the logical channel and updates the internal
+open state flags.  The remote open flag will be set to closed when
+receiving a close command and responding with an close ACK.  The local
+open flag is set to closed when sending a close command and receiving an
+ACK.
+
+No data shall be transmitted over the physical link for the logical
+channel after receiving a close command and responding with the close
+ACK.
+
+Flags:
+ * Bit 0 - ACK (when set to 1)
+ * Bits 1:7 - Reserved
+
+
+Status Command
+--------------
+The Status Command updates the channel status signals which include four
+ITU v.24 status bits in the lower nibble of the flags field along with a
+logical channel flow-control signal.  The v.24 signals are pass-through
+and do not affect the state of SMUX.
+
+The Logical Channel Flow Control bit will disable TX on the logical
+channel when set and send a flow-control notification to the logical
+channel client.  Any further attempts to transmit will result in an
+error return code.
+
+Flags:
+ * Bit 0 - RTC (DTR/DSR)
+ * Bit 1 - RTR (RTS/CTS)
+ * Bit 2 - RI
+ * Bit 3 - DCD
+ * Bit 4 - Logical Channel Flow Control
+ * Bits 5:7 - Reserved
+
+
+Power Control Command
+---------------------
+The physical layer requires a variable amount of time to wakeup from
+power collapse, reconfigure the hardware, and start processing data.
+Data may be lost until the wakeup has been completed.  Because of this,
+a character-based wakeup method will be used to ensure that the remote
+side is active and ready before sending SMUX commands.
+
+If the remote side has previously requested power-down (boot-up state),
+then a wakeup request character is sent at periodic intervals (1 ms or
+8 character-widths, whichever is larger) until a wakeup-acknowledge character
+has been received.  Normal transmit operations can then be performed.  Once an
+activity timeout occurs, then a sleep vote should be sent to the remote side to
+let it know that the channel is no longer needed.  The remote side should
+respond with an ACK.
+
+The following state diagram shows the full sequence of power state transitions.
+This state machine is identical on both the local and remote sides.  The states
+marked "(internal)" are transitional states used in this driver that are not
+part of the power states tracked by the remote side.  The edges are labeled
+using the format CONDITION:ACTION where condition is the guard condition that
+must be true for the edge to be taken and ACTION is the action that will be
+taken.
+
+                          +--------------+   RX Sleep ACK || RX Sleep Request
+  :Flush and power-down   |  Powering    |<---------+
+   UART         +---------+  Down Flush  |          |
+                |         |  (internal)  |          |
+                |         +--------------+          |
+                |                      ^            |
+                |                      |    +-------+------+
+                v                      |    |       |      |
+         +--------------+              |    |  Powering    |
+         |              |              |    |     Down     |<-----+
+Init --->|     OFF      |              |    |              |      |
+         |              |------+       |    +--------------+      |
+         |              |      |       |                          |
+         +------+-------+      |       |                  TX Sleep Request
+                |              |       |                      Complete
+                |              |       |                          |
+        Data ready to send     |       |                          |
+        :TX Wakeup Request     |       |RX Sleep Request          |
+                |              |       |:TX Sleep ACK             |
+                |              |       +------------+     +-------+------+
+                |              |                    |     |  Turning Off^|
+                |              |                    |     |     Flush    |
+                |              |                    |     |  (internal)  |
+                |              |RX Wakeup Request   |     +--------------+
+                |              |:TX Wakeup ACK      |             ^
+                |              |                    |             |
+                |              |                    |     Inactivity Timeout
+                |              +--------------+     |     :TX Sleep Request
+                |                             |     |             |
+                v                             v     |             |
+         +--------------+   RX Wakeup ACK   +-------+------+      |
+         |              +------------------>|     UP       |+-----+
+         |   Powering   |                   |              |
+         |      Up      +------------------>| Packet TX/RX |
+  +----->|              | RX Wakeup Request | is now active|<------+
+  |      +--+-----------+ :TX Wakeup ACK    +----------+---+       |
+  |         |                                          |           |
+  +---------+                                          +-----------+
+  Wakeup Request Timeout                                RX Wakeup Request
+  :TX Wakeup Request                                    :TX Wakeup ACK
+
+
+In-band wakeup bytes:
+ * 0xfd - Wakeup Request
+ * 0xfe - Wakeup Acknowledge
+
+Flags:
+ * Bit 0 - ACK (when set to 1)
+ * Bit 1 - 1 = Sleep Request
+ * Bits 2:7 - Reserved
+
+Initial SMUX State
+------------------
+The boot-up state of SMUX is in power-disabled mode and all logical
+channels closed.  Before sending any commands to open logical channels,
+the remote SMUX must be woken up.
+
+Power Management
+================
+
+Power management will consist of wakeup and shutdown control of the
+physical layer based upon an activity timeout.  Wakelocks will be
+utilized to prevent the system from going to sleep while the transport
+is active.  The activity timeout is anticipated to be 500 ms, but this
+is subject to tuning to meet power and performance specifications.
+
+SMP/multi-core
+==============
+
+Locking and synchronization will be done using mutexes or spinlocks
+where appropriate.  The software will be structured such that locking
+can be kept to a minimum by only locking when items are added and
+removed from lists.
+
+Security
+========
+
+No new security issues are anticipated as communication with userspace
+is done through the existing TCP/IP and CDEV frameworks.
+
+Performance
+===========
+
+The throughput requirements for this design are on the order of 250Kbps
+so throughput concerns are not expected to be an issue.  However, in
+the hope that this driver can be leveraged in the future instead of
+writing yet another multiplexing layer, performance will be considered
+when making design decisions.
+
+Interface
+=========
+
+The kernel API consists of commands to read and write data, vote for
+power, and verify the state of the logical channels.
+
+
+Open
+----
+int msm_smux_open(uint32_t lcid, void *priv,
+	void (*notify)(void *priv, int event_type, void *metadata),
+	int (*get_rx_buffer)(void *priv, void **pkt_priv,
+						void **buffer, int size))
+
+Open a logical channel.  The channel will be first opened locally and
+an open command will be sent to the remote processor.  Once the remote
+processor sends an open command, then the port will be fully open and
+ready for data operations -- the client will be notified with an
+SMUX_CONNECTED notification.
+
+For receive notifications, the driver will read the SMUX header into
+temporary storage and then when the logical channel and size are both
+known, the driver will call the get_rx_buffer() function to request a
+buffer for the data.  The client should return 0 upon success or < 0
+using standard Linux error codes if an error occurred.  If the error
+code is EAGAIN, then the call to get_rx_buffer() will be retried once,
+otherwise the data will be discarded by the driver and a kernel error
+message logged.
+
+Once the receive data has been processed, the notify() function will be
+called with metadata pointing to an instance of struct smux_meta_read
+and the event type will either be SMUX_READ_DONE for successful cases or
+SMUX_READ_FAIL for failure cases.
+
+/*
+ * Notification events that are passed to the notify() function.
+ *
+ * If the @metadata argument in the notifier is non-null, then it will
+ * point to the associated struct smux_meta_* structure.
+ */
+enum {
+	SMUX_CONNECTED,       /* @metadata is null */
+	SMUX_DISCONNECTED,
+	SMUX_READ_DONE,
+	SMUX_READ_FAIL,
+	SMUX_WRITE_DONE,
+	SMUX_WRITE_FAIL,
+	SMUX_TIOCM_UPDATE,
+	SMUX_LOW_WM_HIT,      /* @metadata is NULL */
+	SMUX_HIGH_WM_HIT,     /* @metadata is NULL */
+};
+
+/*
+ * Metadata for SMUX_READ_DONE/SMUX_READ_FAIL notification
+ *
+ * @pkt_priv: Packet-specific private data
+ * @buffer:   Buffer pointer passed into msm_smux_write
+ * @len:      Buffer length passed into  msm_smux_write
+ */
+struct smux_meta_read {
+	void *pkt_priv;
+	void *buffer;
+	int len;
+};
+
+Close
+-----
+int msm_smux_close(uint32_t lcid)
+
+Closes a logical channel locally and sends a close command to the
+remote host.
+
+If there is pending transmit or receive data, then SMUX_WRITE_FAIL and
+SMUX_READ_FAIL notifications will be made to return ownership of the
+buffers to the client.
+
+Once the remote side of the port has been closed, the notify function
+will be called with the event SMUX_DISCONNECTED and metadata pointing
+to a struct smux_meta_disconnected structure.  After this point, no
+further notifications will be performed.
+
+/*
+ * Metadata for SMUX_DISCONNECTED notification
+ *
+ * @is_ssr:  Disconnect caused by subsystem restart
+ */
+struct smux_meta_disconnected {
+	int is_ssr;
+};
+
+
+Write
+-----
+int msm_smux_write(uint32_t lcid, void *pkt_priv, void *data, int len)
+
+Queues data for transmit.  Once the data has been transmitted, the
+SMUX_WRITE_DONE or SMUX_WRITE_FAIL notifications will be sent with
+metadata pointing to an instance of struct smux_meta_write.
+
+If the high watermark has been exceeded, then further writes will
+return -EAGAIN.
+
+Data may be written as soon as the local side of the port has been
+opened, but the data will not be transmitted until the channel has been
+fully opened and the SMUX_CONNECTED event has been sent.
+
+/*
+ * Metadata for SMUX_WRITE_DONE/SMUX_WRITE_FAIL notification
+ *
+ * @pkt_priv: Packet-specific private data
+ * @buffer:   Buffer pointer returned by get_rx_buffer()
+ * @len:      Buffer length returned by get_rx_buffer()
+ */
+struct smux_meta_write {
+	void *pkt_priv;
+	void *buffer;
+	int len;
+};
+
+Watermark
+---------
+	int msm_smux_is_ch_full(uint32_t lcid)
+	int msm_smux_is_ch_low(uint32_t lcid)
+
+A channel watermark is used to keep individual clients from using
+excessive internal resources.  The client may call
+msm_smux_is_ch_full() after every msm_smux_write() operation and if the
+watermark is high, it should not queue any more packets for
+transmission.  As an alternative, the client may base this decision
+upon receiving an SMUX_HIGH_WM_HIT notification.
+
+Likewise, the client may call msm_smux_is_ch_low() after every
+SMUX_WRITE_DONE or SMUX_WRITE_FAIL notification and if the watermark is
+low, then new transmit operations can be started.  As an alternative,
+the client may base this decision upon receiving an SMUX_LOW_WM_HIT
+notification.
+
+Control Signals
+---------------
+	long msm_smux_tiocm_get(uint32_t lcid)
+	long msm_smux_tiocm_set(uint32_t lcid, uint32_t set, uint32_t clear)
+
+The TIOCM bits do not affect the SMUX internal state as they are
+pass-through for the clients.  The client can receive notifications of
+state changes through the SMUX_TIOCM_UPDATE command.
+
+See the "Status Command" section for details on the TIOCM bits.
+
+/*
+ * Metadata for SMUX_TIOCM_UPDATE notification
+ *
+ * @previous:  Previous TIOCM state
+ * @current:   Current TIOCM state
+ *
+ */
+struct smux_meta_tiocm {
+	uint32_t previous;
+	uint32_t current;
+};
+
+Subsystem Restart
+-----------------
+Subsystem restart is handled by sending a disconnect notification
+followed by sending read and write fail notifications to each client.
+This returns ownership of the read and write buffers to the clients for
+client-appropriate handling.
+
+The sequence of notifications shall be:
+	1) SMUX_DISCONNECTED notification with @metadata->is_ssr == 1
+	2) SMUX_WRITE_FAIL for each packet in TX queue
+	3) SMUX_READ_FAIL for any RX packet in progress
+
+After the completion of the sequence, the client should call msm_smux_close()
+followed by a call to msm_smux_open() to re-open the port.
+
+
+Debug / Testing
+---------------
+
+Several debugfs nodes will be exported under the n_gsm directory for
+testing and debugging.
+ * tbl - prints table of logical channels
+ * stats - prints transfer statistics
+ * enable_local_loopback - echo LCID to enable loopback
+ * disable_local_loopback - echo LCID to enable loopback
+ * enable_remote_loopback - echo LCID to enable loopback
+ * disable_remote_loopback - echo LCID to enable loopback
+
+Driver parameters
+=================
+
+A module parameter called debug_mask will be exported to allow a user
+to set the log level for debugging.
+
+Config options
+==============
+
+No configuration options are planned.
+
+Dependencies
+============
+
+The msm_rmnet_smux and smux_ctl drivers are part of this project and
+are used to interface with the Linux TCP/IP framework and user space.
+
+The physical transport is the HS UART driver which will be extended to
+add a kernel API (the current interface is a TTY interface).
+
+Initialization of dependency drivers is handled using the platform
+device framework.  When SMUX is loaded as a line discipline of the TTY
+Framework, it will register separate device drivers with the following
+device names:
+ * SMUX_CTL
+ * SMUX_RMNET
+ * SMUX_DUN_DATA_HSUART
+ * SMUX_RMNET_DATA_HSUART
+ * SMUX_RMNET_CTL_HSUART
+ * SMUX_DIAG
+
+The drivers are removed when SMUX is unloaded from the line discipline.
+
+
+User space utilities
+====================
+
+No userspace utilities are planned aside from testing and example
+applications.
+
+Known issues
+============
+
+None.
+
+To do
+=====
+Once completed, benchmark to determine if FIFO packet scheduling is
+sufficient or if a different scheduling algorithm such as deficit
+round-robin or deficit FIFO scheduling is needed to fairly handle
+variable-sized packets.
diff --git a/Documentation/devicetree/bindings/arm/msm/core_sleep_status.txt b/Documentation/devicetree/bindings/arm/msm/core_sleep_status.txt
new file mode 100644
index 0000000..6ac80f1
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/core_sleep_status.txt
@@ -0,0 +1,29 @@
+* MSM Sleep status
+
+MSM Sleep status device is used to check the power collapsed status of a
+offlined core. The core that initiates the hotplug would wait on the
+sleep status device before CPU_DEAD notifications are sent out. Some hardware
+devices require that the offlined core is power collapsed before turning off
+the resources that are used by the offlined core.
+
+This device is dependent on the pm-8x60 device, which configures the low power
+mode of respective cores. The sleep status is only valid when the core enters
+a low power mode. The device is a child node to pm-8x60 node which is documented
+in Documentation/devicetree/bindings/arm/msm/pm-8x60.txt
+
+The required properties of sleep status device are:
+
+- compatible: qcom,cpu-sleep-status
+- reg: physical address of the sleep status register for Core 0
+- qcom,cpu-alias-addr - On MSM chipset, the each cores registers are at a
+	fixed offset each other.
+- qcom,cpu-sleep-status-mask - The bit mask within the status register that
+	indicates the Core's sleep state.
+
+Example:
+	qcom,cpu-sleep-status@f9088008 {
+		compatible = "qcom,cpu-sleep-status";
+		reg = <0xf9088008 0x4>;
+		qcom,cpu-alias-addr = <0x10000>;
+		qcom,sleep-status-mask= <0x80000>;
+	};
diff --git a/Documentation/devicetree/bindings/media/video/msm-vidc.txt b/Documentation/devicetree/bindings/media/video/msm-vidc.txt
index f97e063..bebdb5a 100644
--- a/Documentation/devicetree/bindings/media/video/msm-vidc.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-vidc.txt
@@ -39,6 +39,7 @@
 - qcom,buffer-type-tz-usage-table : a key-value pair, mapping a buffer type
   (enum hal_buffer) to its corresponding TZ usage. The TZ usages are defined
   as "enum cp_mem_usage" in include/linux/msm_ion.h
+- qcom,has-ocmem: indicate the target has ocmem if this property exists
 
 Example:
 
@@ -55,6 +56,7 @@
 				<243000 133330000>,
 				<108000 100000000>,
 				<36000 50000000>;
+		qcom,has-ocmem;
 		qcom,hfi = "venus";
 		qcom,reg-presets = <0x80004 0x1>,
 			<0x80178 0x00001FFF>;
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 4cd9f99..a4c05d4 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -96,6 +96,12 @@
    is 8, which indicates the rx path used for audio playback
    on HDMI device.
 
+* msm-lsm-client
+
+Required properties:
+
+ - compatible : "qcom,msm-lsm-client"
+
 * msm-dai-q6
 
 [First Level Nodes]
diff --git a/arch/arm/boot/dts/msm8226-iommu-domains.dtsi b/arch/arm/boot/dts/msm8226-iommu-domains.dtsi
new file mode 100644
index 0000000..6ea5b9e
--- /dev/null
+++ b/arch/arm/boot/dts/msm8226-iommu-domains.dtsi
@@ -0,0 +1,31 @@
+/* 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,iommu-domains {
+		compatible = "qcom,iommu-domains";
+
+		venus_domain_ns: qcom,iommu-domain1 {
+			label = "venus_ns";
+			qcom,iommu-contexts = <&venus_ns>;
+			qcom,virtual-addr-pool = <0x40000000 0x3f000000
+						  0x7f000000 0x1000000>;
+		};
+
+		venus_domain_cp: qcom,iommu-domain2 {
+			label = "venus_cp";
+			qcom,iommu-contexts = <&venus_cp>;
+			qcom,virtual-addr-pool = <0x1000000 0x3f000000>;
+			qcom,secure-domain;
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/msm8226-pm.dtsi b/arch/arm/boot/dts/msm8226-pm.dtsi
index 2351d9c..34283e8 100644
--- a/arch/arm/boot/dts/msm8226-pm.dtsi
+++ b/arch/arm/boot/dts/msm8226-pm.dtsi
@@ -114,8 +114,8 @@
 		qcom,lpm-resources@0 {
 			reg = <0x0>;
 			qcom,name = "vdd-dig";
-			qcom,type = <0x62706d73>;	/* "smpb" */
-			qcom,id = <0x02>;
+			qcom,type = <0x61706d73>;	/* "smpa" */
+			qcom,id = <0x01>;
 			qcom,key = <0x6e726f63>;	/* "corn" */
 			qcom,init-value = <5>;		/* Super Turbo */
 		};
@@ -123,8 +123,8 @@
 		qcom,lpm-resources@1 {
 			reg = <0x1>;
 			qcom,name = "vdd-mem";
-			qcom,type = <0x62706d73>;	/* "smpb" */
-			qcom,id = <0x01>;
+			qcom,type = <0x616F646C>;	/* "ldoa" */
+			qcom,id = <0x03>;
 			qcom,key = <0x7675>;		/* "uv" */
 			qcom,init-value = <1050000>;	/* Super Turbo */
 		};
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index 1f51a37..7a27977 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -20,7 +20,7 @@
 /include/ "msm8226-bus.dtsi"
 /include/ "msm8226-mdss.dtsi"
 /include/ "msm8226-coresight.dtsi"
-
+/include/ "msm8226-iommu-domains.dtsi"
 / {
 	model = "Qualcomm MSM 8226";
 	compatible = "qcom,msm8226";
@@ -56,6 +56,43 @@
 		clock-frequency = <19200000>;
 	};
 
+	qcom,vidc@fdc00000 {
+		compatible = "qcom,msm-vidc";
+		reg = <0xfdc00000 0xff000>;
+		interrupts = <0 44 0>;
+		qcom,load-freq-tbl = <352800 160000000>,
+			<244800 133330000>,
+			<108000  66700000>;
+		qcom,hfi = "venus";
+		qcom,bus-ports = <1>;
+		qcom,reg-presets = <0xE0024 0x0>,
+			<0x80124 0x3>,
+			<0xE0020 0x5555556>,
+			<0x800B0 0x10101001>,
+			<0x800B4 0x00101010>,
+			<0x800C0 0x1010100f>,
+			<0x800C4 0x00101010>,
+			<0x800D0 0x00000010>,
+			<0x800D4 0x00000010>,
+			<0x800D8 0x00000707>;
+		qcom,enc-ddr-ab-ib = <0 0>,
+			<129000 142000>,
+			<384000 422000>,
+			<866000 953000>;
+		qcom,dec-ddr-ab-ib = <0 0>,
+			<103000 134000>,
+			<268000 348000>,
+			<505000 657000>;
+		qcom,iommu-groups = <&venus_domain_ns &venus_domain_cp>;
+		qcom,iommu-group-buffer-types = <0xfff 0x1ff>;
+		qcom,buffer-type-tz-usage-table = <0x1 0x1>,
+			<0x1fe 0x2>;
+	};
+
+	qcom,wfd {
+		compatible = "qcom,msm-wfd";
+	};
+
 	serial@f991f000 {
 		compatible = "qcom,msm-lsuart-v14";
 		reg = <0xf991f000 0x1000>;
@@ -422,7 +459,6 @@
 		compatible = "qcom,rpm-smd";
 		rpm-channel-name = "rpm_requests";
 		rpm-channel-type = <15>; /* SMD_APPS_RPM */
-		rpm-standalone;
 	};
 
 	sdcc1: qcom,sdcc@f9824000 {
@@ -465,7 +501,6 @@
 		/* 190,ee0_krait_hlos_spmi_periph_irq */
 		/* 187,channel_0_krait_hlos_trans_done_irq */
 		interrupts = <0 190 0>, <0 187 0>;
-		qcom,not-wakeup;
 		qcom,pmic-arb-ee = <0>;
 		qcom,pmic-arb-channel = <0>;
 	};
@@ -652,6 +687,34 @@
 		compatible = "qcom,tz-log";
 		reg = <0x0fc5b82c 0x1000>;
 	};
+
+	jtag_mm0: jtagmm@fc33c000 {
+		compatible = "qcom,jtag-mm";
+		reg = <0xfc33c000 0x1000>,
+		      <0xfc330000 0x1000>;
+		reg-names = "etm-base","debug-base";
+	};
+
+	jtag_mm1: jtagmm@fc33d000 {
+		compatible = "qcom,jtag-mm";
+		reg = <0xfc33d000 0x1000>,
+		      <0xfc332000 0x1000>;
+		reg-names = "etm-base","debug-base";
+	};
+
+	jtag_mm2: jtagmm@fc33e000 {
+		compatible = "qcom,jtag-mm";
+		reg = <0xfc33e000 0x1000>,
+		      <0xfc334000 0x1000>;
+		reg-names = "etm-base","debug-base";
+	};
+
+	jtag_mm3: jtagmm@fc33f000 {
+		compatible = "qcom,jtag-mm";
+		reg = <0xfc33f000 0x1000>,
+		      <0xfc336000 0x1000>;
+		reg-names = "etm-base","debug-base";
+	};
 };
 
 &gdsc_venus {
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index b258506..b78c3af 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -236,7 +236,6 @@
 		compatible = "qcom,rpm-smd";
 		rpm-channel-name = "rpm_requests";
 		rpm-channel-type = <15>; /* SMD_APPS_RPM */
-		rpm-standalone;
 	};
 
 	qcom,msm-mem-hole {
diff --git a/arch/arm/boot/dts/msm8974-cdp.dtsi b/arch/arm/boot/dts/msm8974-cdp.dtsi
index 45cbc89..2c513e8 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-cdp.dtsi
@@ -22,6 +22,7 @@
 
 	qcom,mdss_dsi_toshiba_720p_video {
 		status = "ok";
+		qcom,cont-splash-enabled;
 	};
 
 	qcom,mdss_dsi_orise_720p_video {
@@ -358,9 +359,6 @@
 &pm8941_chg {
 	status = "ok";
 
-	qcom,chg-charging-disabled;
-	qcom,chg-use-default-batt-values;
-
 	qcom,chg-chgr@1000 {
 		status = "ok";
 	};
@@ -369,10 +367,6 @@
 		status = "ok";
 	};
 
-	qcom,chg-bat-if@1200 {
-		status = "ok";
-	};
-
 	qcom,chg-usb-chgpth@1300 {
 		status = "ok";
 	};
diff --git a/arch/arm/boot/dts/msm8974-fluid.dtsi b/arch/arm/boot/dts/msm8974-fluid.dtsi
index d22c746..b18bf88 100644
--- a/arch/arm/boot/dts/msm8974-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-fluid.dtsi
@@ -21,6 +21,7 @@
 
 	qcom,mdss_dsi_toshiba_720p_video {
 		status = "ok";
+		qcom,cont-splash-enabled;
 	};
 
 	qcom,hdmi_tx@fd922100 {
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index 985b307..a35b9d2 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -370,6 +370,14 @@
 			hsic,ignore-cal-pad-config;
 			hsic,strobe-pad-offset = <0x2050>;
 			hsic,data-pad-offset = <0x2054>;
+
+			qcom,msm-bus,name = "hsic";
+			qcom,msm-bus,num-cases = <2>;
+			qcom,msm-bus,active-only = <0>;
+			qcom,msm-bus,num-paths = <1>;
+			qcom,msm-bus,vectors-KBps =
+					<85 512 0 0>,
+					<85 512 40000 160000>;
 		};
 	};
 };
diff --git a/arch/arm/boot/dts/msm8974-mtp.dtsi b/arch/arm/boot/dts/msm8974-mtp.dtsi
index 380ec20..4f0469c 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-mtp.dtsi
@@ -21,6 +21,7 @@
 
 	qcom,mdss_dsi_toshiba_720p_video {
 		status = "ok";
+		qcom,cont-splash-enabled;
 	};
 
 	qcom,hdmi_tx@fd922100 {
diff --git a/arch/arm/boot/dts/msm8974-v1-cdp.dts b/arch/arm/boot/dts/msm8974-v1-cdp.dts
index 8db99b2..33bd1fb 100644
--- a/arch/arm/boot/dts/msm8974-v1-cdp.dts
+++ b/arch/arm/boot/dts/msm8974-v1-cdp.dts
@@ -19,10 +19,6 @@
 	model = "Qualcomm MSM 8974 CDP";
 	compatible = "qcom,msm8974-cdp", "qcom,msm8974";
 	qcom,msm-id = <126 1 0>;
-
-	qcom,mdss_dsi_toshiba_720p_video {
-		qcom,cont-splash-enabled;
-	};
 };
 
 &ehci {
diff --git a/arch/arm/boot/dts/msm8974-v1-fluid.dts b/arch/arm/boot/dts/msm8974-v1-fluid.dts
index 683fe18..9fb287c 100644
--- a/arch/arm/boot/dts/msm8974-v1-fluid.dts
+++ b/arch/arm/boot/dts/msm8974-v1-fluid.dts
@@ -20,9 +20,6 @@
 	compatible = "qcom,msm8974-fluid", "qcom,msm8974";
 	qcom,msm-id = <126 3 0>;
 
-	qcom,mdss_dsi_toshiba_720p_video {
-		qcom,cont-splash-enabled;
-	};
 };
 
 &pm8941_chg {
diff --git a/arch/arm/boot/dts/msm8974-v1-mtp.dts b/arch/arm/boot/dts/msm8974-v1-mtp.dts
index 0e5d2ae..205ee24 100644
--- a/arch/arm/boot/dts/msm8974-v1-mtp.dts
+++ b/arch/arm/boot/dts/msm8974-v1-mtp.dts
@@ -19,10 +19,6 @@
 	model = "Qualcomm MSM 8974 MTP";
 	compatible = "qcom,msm8974-mtp", "qcom,msm8974";
 	qcom,msm-id = <126 8 0>;
-
-	qcom,mdss_dsi_toshiba_720p_video {
-		qcom,cont-splash-enabled;
-	};
 };
 
 &pm8941_chg {
diff --git a/arch/arm/boot/dts/msm8974-v1-pm.dtsi b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
index d8a1444..a0b9be6 100644
--- a/arch/arm/boot/dts/msm8974-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
@@ -420,9 +420,19 @@
 
 	qcom,pm-8x60@fe805664 {
 		compatible = "qcom,pm-8x60";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
 		reg = <0xfe805664 0x40>;
 		qcom,pc-mode = "tz_l2_int";
 		qcom,use-sync-timer;
+
+		qcom,cpu-sleep-status@f9088008 {
+			compatible = "qcom,cpu-sleep-status";
+			reg = <0xf9088008 0x4>;
+			qcom,cpu-alias-addr = <0x10000>;
+			qcom,sleep-status-mask= <0x80000>;
+		};
 	};
 
 	qcom,rpm-log@fc19dc00 {
diff --git a/arch/arm/boot/dts/msm8974-v2-pm.dtsi b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
index e020fa4..2cfb192 100644
--- a/arch/arm/boot/dts/msm8974-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
@@ -417,10 +417,20 @@
 
 	qcom,pm-8x60@fe805664 {
 		compatible = "qcom,pm-8x60";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
 		reg = <0xfe805664 0x40>;
 		qcom,pc-mode = "tz_l2_int";
 		qcom,use-sync-timer;
 		qcom,saw-turns-off-pll;
+
+		qcom,cpu-sleep-status@f9088008{
+			compatible = "qcom,cpu-sleep-status";
+			reg = <0xf9088008 0x100>;
+			qcom,cpu-alias-addr = <0x10000>;
+			qcom,sleep-status-mask= <0x80000>;
+		};
 	};
 
 	qcom,rpm-log@fc19dc00 {
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index ee79827..aa3742f 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -95,6 +95,7 @@
 		reg = <0xfdc00000 0xff000>;
 		interrupts = <0 44 0>;
 		qcom,hfi = "venus";
+		qcom,has-ocmem;
 	};
 
 	qcom,wfd {
@@ -590,6 +591,7 @@
 		qcom,audio-routing =
 			"RX_BIAS", "MCLK",
 			"LDO_H", "MCLK",
+			"AIF4 MAD", "MCLK",
 			"AMIC1", "MIC BIAS1 Internal1",
 			"MIC BIAS1 Internal1", "Handset Mic",
 			"AMIC2", "MIC BIAS2 External",
@@ -800,6 +802,10 @@
 		qcom,msm-dai-q6-dev-id = <8>;
 	};
 
+	qcom,msm-lsm-client {
+		compatible = "qcom,msm-lsm-client";
+	};
+
 	qcom,msm-dai-q6 {
 		compatible = "qcom,msm-dai-q6";
 		qcom,msm-dai-q6-sb-0-rx {
@@ -852,6 +858,11 @@
 			qcom,msm-dai-q6-dev-id = <16393>;
 		};
 
+		qcom,msm-dai-q6-sb-5-tx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <16395>;
+		};
+
 		qcom,msm-dai-q6-bt-sco-rx {
 			compatible = "qcom,msm-dai-q6-dev";
 			qcom,msm-dai-q6-dev-id = <12288>;
diff --git a/arch/arm/boot/dts/msm9625-v2-cdp.dts b/arch/arm/boot/dts/msm9625-v2-cdp.dts
index 244556d..09a89ab 100644
--- a/arch/arm/boot/dts/msm9625-v2-cdp.dts
+++ b/arch/arm/boot/dts/msm9625-v2-cdp.dts
@@ -42,7 +42,7 @@
 
 	wlan0: qca,wlan {
 		cell-index = <0>;
-		compatible = "qca,ar6004-sdio";
+		compatible = "qca,ar6004-hsic";
 		qca,chip-pwd-l-gpios = <&msmgpio 62 0>;
 		qca,pm-enable-gpios = <&pm8019_gpios 3 0x0>;
 		qca,ar6004-vdd-io-supply = <&pm8019_l11>;
diff --git a/arch/arm/boot/dts/msm9625-v2-mtp.dts b/arch/arm/boot/dts/msm9625-v2-mtp.dts
index bf0f539..7949080 100644
--- a/arch/arm/boot/dts/msm9625-v2-mtp.dts
+++ b/arch/arm/boot/dts/msm9625-v2-mtp.dts
@@ -42,7 +42,7 @@
 
 	wlan0: qca,wlan {
 		cell-index = <0>;
-		compatible = "qca,ar6004-sdio";
+		compatible = "qca,ar6004-hsic";
 		qca,chip-pwd-l-gpios = <&msmgpio 62 0>;
 		qca,pm-enable-gpios = <&pm8019_gpios 3 0x0>;
 		qca,ar6004-vdd-io-supply = <&pm8019_l11>;
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index a11398b..9172029 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -123,14 +123,17 @@
 		qcom,msm-bus,vectors-KBps =
 				<85 512 0 0>,
 				<85 512 40000 640000>;
+		qcom,pool-64-bit-align;
+		qcom,enable-hbm;
 	};
 
 	qcom,usbbam@f9a44000 {
 		compatible = "qcom,usb-bam-msm";
-		reg = <0xf9a44000 0x11000>;
-		reg-names = "hsusb";
-		interrupts = <0 135 0>;
-		interrupt-names = "hsusb";
+		reg = <0xf9a44000 0x11000>,
+		      <0xf9a04000 0x11000>;
+		reg-names = "hsusb", "hsic";
+		interrupts = <0 135 0 0 255 0>;
+		interrupt-names = "hsusb", "hsic";
 		qcom,usb-bam-num-pipes = <16>;
 		qcom,ignore-core-reset-ack;
 		qcom,disable-clk-gating;
@@ -179,6 +182,66 @@
 			qcom,descriptor-fifo-offset = <0x4000>;
 			qcom,descriptor-fifo-size = <0x400>;
 		};
+		qcom,pipe3 {
+			label = "hsic-ipa-in-0";
+			qcom,usb-bam-mem-type = <2>;
+			qcom,bam-type = <2>;
+			qcom,dir = <1>;
+			qcom,pipe-num = <0>;
+			qcom,peer-bam = <2>;
+			qcom,dst-bam-physical-address = <0xf9a04000>;
+			qcom,dst-bam-pipe-index = <3>;
+			qcom,data-fifo-size = <0xD480>;
+			qcom,descriptor-fifo-size = <0x1A80>;
+		};
+		qcom,pipe4 {
+			label = "hsic-ipa-in-1";
+			qcom,bam-type = <2>;
+			qcom,dir = <1>;
+			qcom,pipe-num = <1>;
+			qcom,peer-bam = <2>;
+			qcom,usb-bam-mem-type = <2>;
+			qcom,dst-bam-physical-address = <0xf9a04000>;
+			qcom,dst-bam-pipe-index = <4>;
+			qcom,data-fifo-size = <0xD480>;
+			qcom,descriptor-fifo-size = <0x1A80>;
+		};
+		qcom,pipe5 {
+			label = "hsic-ipa-in-2";
+			qcom,usb-bam-mem-type = <2>;
+			qcom,bam-type = <2>;
+			qcom,dir = <1>;
+			qcom,pipe-num = <2>;
+			qcom,peer-bam = <2>;
+			qcom,dst-bam-physical-address = <0xf9a04000>;
+			qcom,dst-bam-pipe-index = <5>;
+			qcom,data-fifo-size = <0xD480>;
+			qcom,descriptor-fifo-size = <0x1A80>;
+		};
+		qcom,pipe6 {
+			label = "hsic-ipa-in-3";
+			qcom,usb-bam-mem-type = <2>;
+			qcom,bam-type = <2>;
+			qcom,dir = <1>;
+			qcom,pipe-num = <3>;
+			qcom,peer-bam = <2>;
+			qcom,dst-bam-physical-address = <0xf9a04000>;
+			qcom,dst-bam-pipe-index = <6>;
+			qcom,data-fifo-size = <0xD480>;
+			qcom,descriptor-fifo-size = <0x1A80>;
+		};
+		qcom,pipe7 {
+			label = "hsic-ipa-out-0";
+			qcom,usb-bam-mem-type = <2>;
+			qcom,bam-type = <2>;
+			qcom,dir = <0>;
+			qcom,pipe-num = <0>;
+			qcom,peer-bam = <2>;
+			qcom,src-bam-physical-address = <0xf9a04000>;
+			qcom,src-bam-pipe-index = <7>;
+			qcom,data-fifo-size = <0xD480>;
+			qcom,descriptor-fifo-size = <0x1A80>;
+		};
 	};
 
 	qcom,nand@f9ac0000 {
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index d4abef2..cfdff6f 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -182,6 +182,7 @@
 CONFIG_NET_CLS_FW=y
 CONFIG_SYNC=y
 CONFIG_SW_SYNC=y
+CONFIG_CMA=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_MD=y
@@ -333,6 +334,7 @@
 CONFIG_CORESIGHT_FUNNEL=y
 CONFIG_CORESIGHT_REPLICATOR=y
 CONFIG_CORESIGHT_STM=y
+CONFIG_CORESIGHT_ETM=y
 CONFIG_CORESIGHT_EVENT=m
 CONFIG_ENABLE_DEFAULT_TRACERS=y
 CONFIG_PM_WAKELOCKS=y
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index b65016a..f7d993f 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -463,6 +463,7 @@
 	select ARM_HAS_SG_CHAIN
 	select REGULATOR
 	select MSM_RPM_REGULATOR_SMD
+	select MSM_JTAG_MM if CORESIGHT_ETM
 endmenu
 
 choice
diff --git a/arch/arm/mach-msm/clock-pll.c b/arch/arm/mach-msm/clock-pll.c
index c82058b..d2be1f9 100644
--- a/arch/arm/mach-msm/clock-pll.c
+++ b/arch/arm/mach-msm/clock-pll.c
@@ -529,6 +529,18 @@
 		BUG();
 	}
 
+	if (!pll_clk_is_enabled(c))
+		return HANDOFF_DISABLED_CLK;
+
+	/*
+	 * Do not call pll_clk_enable() since that function can assume
+	 * the PLL is not in use when it's called.
+	 */
+	remote_spin_lock(&pll_lock);
+	pll_control->pll[PLL_BASE + pll->id].votes |= BIT(1);
+	pll_control->pll[PLL_BASE + pll->id].on = 1;
+	remote_spin_unlock(&pll_lock);
+
 	return HANDOFF_ENABLED_CLK;
 }
 
@@ -572,10 +584,22 @@
 	spin_unlock_irqrestore(&soft_vote_lock, flags);
 }
 
+static enum handoff pll_acpu_vote_clk_handoff(struct clk *c)
+{
+	if (pll_vote_clk_handoff(c) == HANDOFF_DISABLED_CLK)
+		return HANDOFF_DISABLED_CLK;
+
+	if (pll_acpu_vote_clk_enable(c))
+		return HANDOFF_DISABLED_CLK;
+
+	return HANDOFF_ENABLED_CLK;
+}
+
 struct clk_ops clk_ops_pll_acpu_vote = {
 	.enable = pll_acpu_vote_clk_enable,
 	.disable = pll_acpu_vote_clk_disable,
 	.is_enabled = pll_vote_clk_is_enabled,
+	.handoff = pll_acpu_vote_clk_handoff,
 };
 
 static void __init __set_fsm_mode(void __iomem *mode_reg,
diff --git a/arch/arm/mach-msm/hotplug.c b/arch/arm/mach-msm/hotplug.c
index 5cd5057..0e97c27 100644
--- a/arch/arm/mach-msm/hotplug.c
+++ b/arch/arm/mach-msm/hotplug.c
@@ -70,6 +70,11 @@
 
 int platform_cpu_kill(unsigned int cpu)
 {
+	int ret;
+
+	ret = msm_pm_wait_cpu_shutdown(cpu);
+	if (ret)
+		return 0;
 	return 1;
 }
 
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/apr.h b/arch/arm/mach-msm/include/mach/qdsp6v2/apr.h
index 59908e6..c21f6e5 100644
--- a/arch/arm/mach-msm/include/mach/qdsp6v2/apr.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/apr.h
@@ -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
@@ -82,6 +82,7 @@
 #define APR_SVC_ADSP_CVS	0x0A
 #define APR_SVC_ADSP_CVP	0x0B
 #define APR_SVC_USM		0x0C
+#define APR_SVC_LSM		0x0D
 #define APR_SVC_VIDC		0x16
 #define APR_SVC_MAX		0x17
 
diff --git a/arch/arm/mach-msm/jtag-mm.c b/arch/arm/mach-msm/jtag-mm.c
index af05995..8a67614 100644
--- a/arch/arm/mach-msm/jtag-mm.c
+++ b/arch/arm/mach-msm/jtag-mm.c
@@ -124,6 +124,8 @@
 #define DBGBCRn(n)		(0x140 + (n * 4))
 #define DBGWVRn(n)		(0x180 + (n * 4))
 #define DBGWCRn(n)		(0x1C0 + (n * 4))
+#define DBGOSLAR		(0x300)
+#define DBGOSLSR		(0x304)
 #define DBGPRCR			(0x310)
 #define DBGITMISCOUT		(0xEF8)
 #define DBGITMISCIN		(0xEFC)
@@ -131,6 +133,7 @@
 #define DBGCLAIMCLR		(0xFA4)
 
 #define DBGDSCR_MASK		(0x6C30FC3C)
+#define OSLOCK_MAGIC		(0xC5ACCE55)
 
 #define MAX_DBG_STATE_SIZE	(90)
 #define MAX_ETM_STATE_SIZE	(78)
@@ -140,6 +143,7 @@
 
 #define ARCH_V3_5		(0x25)
 #define ARM_DEBUG_ARCH_V7B	(0x3)
+#define ARM_DEBUG_ARCH_V7p1	(0x5)
 
 #define etm_write(etm, val, off)	\
 			__raw_writel(val, etm->base + off)
@@ -221,12 +225,40 @@
 	uint8_t			nr_ctxid_cmp;
 	struct etm_cpu_ctx	*cpu_ctx[NR_CPUS];
 	bool			save_restore_enabled[NR_CPUS];
+	bool			os_lock_present;
 };
 
 static struct etm_ctx etm;
 
 static struct clk *clock[NR_CPUS];
 
+static void etm_os_lock(struct etm_cpu_ctx *etmdata)
+{
+	uint32_t count;
+
+	if (etm.os_lock_present) {
+		etm_write(etmdata, OSLOCK_MAGIC, ETMOSLAR);
+		/* Ensure OS lock is set before proceeding */
+		mb();
+		for (count = TIMEOUT_US; BVAL(etm_read(etmdata, ETMSR), 1) != 1
+							&& count > 0; count--)
+			udelay(1);
+		if (count == 0)
+			pr_err_ratelimited(
+				"timeout while setting prog bit, ETMSR: %#x\n",
+						etm_read(etmdata, ETMSR));
+	}
+}
+
+static void etm_os_unlock(struct etm_cpu_ctx *etmdata)
+{
+	if (etm.os_lock_present) {
+		/* Ensure all writes are complete before clearing OS lock */
+		mb();
+		etm_write(etmdata, 0x0, ETMOSLAR);
+	}
+}
+
 static void etm_set_pwrdwn(struct etm_cpu_ctx *etmdata)
 {
 	uint32_t etmcr;
@@ -273,6 +305,8 @@
 
 	switch (etm.arch) {
 	case ETM_ARCH_V3_5:
+		etm_os_lock(etmdata);
+
 		etmdata->state[i++] = etm_read(etmdata, ETMTRIGGER);
 		etmdata->state[i++] = etm_read(etmdata, ETMASICCTLR);
 		etmdata->state[i++] = etm_read(etmdata, ETMSR);
@@ -346,6 +380,8 @@
 
 	switch (etm.arch) {
 	case ETM_ARCH_V3_5:
+		etm_os_lock(etmdata);
+
 		etm_clr_pwrdwn(etmdata);
 		etm_write(etmdata, etmdata->state[i++], ETMTRIGGER);
 		etm_write(etmdata, etmdata->state[i++], ETMASICCTLR);
@@ -406,6 +442,8 @@
 		 * bit
 		 */
 		etm_write(etmdata, etmdata->state[i++], ETMCR);
+
+		etm_os_unlock(etmdata);
 		break;
 	default:
 		pr_err_ratelimited("unsupported etm arch %d in %s\n", etm.arch,
@@ -422,22 +460,46 @@
 	i = 0;
 	DBG_UNLOCK(dbgdata);
 
-	dbgdata->state[i++] =  dbg_read(dbgdata, DBGWFAR);
-	dbgdata->state[i++] =  dbg_read(dbgdata, DBGVCR);
-	for (j = 0; j < dbg.nr_bp; j++) {
-		dbgdata->state[i++] =  dbg_read(dbgdata, DBGBVRn(j));
-		dbgdata->state[i++] =  dbg_read(dbgdata, DBGBCRn(j));
+	switch (dbg.arch) {
+	case ARM_DEBUG_ARCH_V7B:
+		dbgdata->state[i++] =  dbg_read(dbgdata, DBGWFAR);
+		dbgdata->state[i++] =  dbg_read(dbgdata, DBGVCR);
+		for (j = 0; j < dbg.nr_bp; j++) {
+			dbgdata->state[i++] =  dbg_read(dbgdata, DBGBVRn(j));
+			dbgdata->state[i++] =  dbg_read(dbgdata, DBGBCRn(j));
+		}
+		for (j = 0; j < dbg.nr_wp; j++) {
+			dbgdata->state[i++] =  dbg_read(dbgdata, DBGWVRn(j));
+			dbgdata->state[i++] =  dbg_read(dbgdata, DBGWCRn(j));
+		}
+		dbgdata->state[i++] =  dbg_read(dbgdata, DBGPRCR);
+		dbgdata->state[i++] =  dbg_read(dbgdata, DBGDTRTXext);
+		dbgdata->state[i++] =  dbg_read(dbgdata, DBGDTRRXext);
+		dbgdata->state[i++] =  dbg_read(dbgdata, DBGDSCRext);
+		break;
+	case ARM_DEBUG_ARCH_V7p1:
+		/* Set OS Lock */
+		dbg_write(dbgdata, OSLOCK_MAGIC, DBGOSLAR);
+		/* Ensure OS lock is set before proceeding */
+		mb();
+
+		dbgdata->state[i++] =  dbg_read(dbgdata, DBGWFAR);
+		dbgdata->state[i++] =  dbg_read(dbgdata, DBGVCR);
+		for (j = 0; j < dbg.nr_bp; j++) {
+			dbgdata->state[i++] =  dbg_read(dbgdata, DBGBVRn(j));
+			dbgdata->state[i++] =  dbg_read(dbgdata, DBGBCRn(j));
+		}
+		for (j = 0; j < dbg.nr_wp; j++) {
+			dbgdata->state[i++] =  dbg_read(dbgdata, DBGWVRn(j));
+			dbgdata->state[i++] =  dbg_read(dbgdata, DBGWCRn(j));
+		}
+		dbgdata->state[i++] =  dbg_read(dbgdata, DBGPRCR);
+		dbgdata->state[i++] =  dbg_read(dbgdata, DBGCLAIMCLR);
+		dbgdata->state[i++] =  dbg_read(dbgdata, DBGDTRTXext);
+		dbgdata->state[i++] =  dbg_read(dbgdata, DBGDTRRXext);
+		dbgdata->state[i++] =  dbg_read(dbgdata, DBGDSCRext);
+		break;
 	}
-	for (j = 0; j < dbg.nr_wp; j++) {
-		dbgdata->state[i++] =  dbg_read(dbgdata, DBGWVRn(j));
-		dbgdata->state[i++] =  dbg_read(dbgdata, DBGWCRn(j));
-	}
-	dbgdata->state[i++] =  dbg_read(dbgdata, DBGPRCR);
-	dbgdata->state[i++] =  dbg_read(dbgdata, DBGCLAIMSET);
-	dbgdata->state[i++] =  dbg_read(dbgdata, DBGCLAIMCLR);
-	dbgdata->state[i++] =  dbg_read(dbgdata, DBGDTRTXext);
-	dbgdata->state[i++] =  dbg_read(dbgdata, DBGDTRRXext);
-	dbgdata->state[i++] =  dbg_read(dbgdata, DBGDSCRext);
 
 	DBG_LOCK(dbgdata);
 }
@@ -449,23 +511,55 @@
 	i = 0;
 	DBG_UNLOCK(dbgdata);
 
-	dbg_write(dbgdata, dbgdata->state[i++], DBGWFAR);
-	dbg_write(dbgdata, dbgdata->state[i++], DBGVCR);
-	for (j = 0; j < dbg.nr_bp; j++) {
-		dbg_write(dbgdata, dbgdata->state[i++], DBGBVRn(j));
-		dbg_write(dbgdata, dbgdata->state[i++], DBGBCRn(j));
-	}
-	for (j = 0; j < dbg.nr_wp; j++) {
-		dbg_write(dbgdata, dbgdata->state[i++], DBGWVRn(j));
-		dbg_write(dbgdata, dbgdata->state[i++], DBGWCRn(j));
-	}
-	dbg_write(dbgdata, dbgdata->state[i++], DBGPRCR);
-	dbg_write(dbgdata, dbgdata->state[i++], DBGCLAIMSET);
-	dbg_write(dbgdata, dbgdata->state[i++], DBGCLAIMCLR);
-	dbg_write(dbgdata, dbgdata->state[i++], DBGDTRTXext);
-	dbg_write(dbgdata, dbgdata->state[i++], DBGDTRRXext);
-	dbg_write(dbgdata, dbgdata->state[i++] & DBGDSCR_MASK,
+	switch (dbg.arch) {
+	case ARM_DEBUG_ARCH_V7B:
+		dbg_write(dbgdata, dbgdata->state[i++], DBGWFAR);
+		dbg_write(dbgdata, dbgdata->state[i++], DBGVCR);
+		for (j = 0; j < dbg.nr_bp; j++) {
+			dbg_write(dbgdata, dbgdata->state[i++], DBGBVRn(j));
+			dbg_write(dbgdata, dbgdata->state[i++], DBGBCRn(j));
+		}
+		for (j = 0; j < dbg.nr_wp; j++) {
+			dbg_write(dbgdata, dbgdata->state[i++], DBGWVRn(j));
+			dbg_write(dbgdata, dbgdata->state[i++], DBGWCRn(j));
+		}
+		dbg_write(dbgdata, dbgdata->state[i++], DBGPRCR);
+		dbg_write(dbgdata, dbgdata->state[i++], DBGDTRTXext);
+		dbg_write(dbgdata, dbgdata->state[i++], DBGDTRRXext);
+		dbg_write(dbgdata, dbgdata->state[i++] & DBGDSCR_MASK,
 								DBGDSCRext);
+		break;
+	case ARM_DEBUG_ARCH_V7p1:
+		/* Set OS lock. Lock will already be set after power collapse
+		 * but this write is included to ensure it is set.
+		 */
+		dbg_write(dbgdata, OSLOCK_MAGIC, DBGOSLAR);
+		/* Ensure OS lock is set before proceeding */
+		mb();
+
+		dbg_write(dbgdata, dbgdata->state[i++], DBGWFAR);
+		dbg_write(dbgdata, dbgdata->state[i++], DBGVCR);
+		for (j = 0; j < dbg.nr_bp; j++) {
+			dbg_write(dbgdata, dbgdata->state[i++], DBGBVRn(j));
+			dbg_write(dbgdata, dbgdata->state[i++], DBGBCRn(j));
+		}
+		for (j = 0; j < dbg.nr_wp; j++) {
+			dbg_write(dbgdata, dbgdata->state[i++], DBGWVRn(j));
+			dbg_write(dbgdata, dbgdata->state[i++], DBGWCRn(j));
+		}
+		dbg_write(dbgdata, dbgdata->state[i++], DBGPRCR);
+		dbg_write(dbgdata, dbgdata->state[i++], DBGCLAIMSET);
+		dbg_write(dbgdata, dbgdata->state[i++], DBGDTRTXext);
+		dbg_write(dbgdata, dbgdata->state[i++], DBGDTRRXext);
+		dbg_write(dbgdata, dbgdata->state[i++] & DBGDSCR_MASK,
+								DBGDSCRext);
+		/* Ensure all writes are completing before clearing OS lock */
+		mb();
+		dbg_write(dbgdata, 0x0, DBGOSLAR);
+		/* Ensure OS lock is cleared before proceeding */
+		mb();
+		break;
+	}
 
 	DBG_LOCK(dbgdata);
 }
@@ -529,6 +623,17 @@
 	return true;
 }
 
+static void __devinit etm_os_lock_init(struct etm_cpu_ctx *etmdata)
+{
+	uint32_t etmoslsr;
+
+	etmoslsr = etm_read(etmdata, ETMOSLSR);
+	if (!BVAL(etmoslsr, 0) && !BVAL(etmoslsr, 3))
+		etm.os_lock_present = false;
+	else
+		etm.os_lock_present = true;
+}
+
 static void __devinit etm_init_arch_data(void *info)
 {
 	uint32_t etmidr;
@@ -541,6 +646,8 @@
 	 */
 	ETM_UNLOCK(etmdata);
 
+	etm_os_lock_init(etmdata);
+
 	etm_clr_pwrdwn(etmdata);
 	/* Set prog bit. It will be set from reset but this is included to
 	 * ensure it is set
@@ -578,7 +685,7 @@
 
 	etm.cpu_ctx[cpu] = etmdata;
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "etm-base");
 
 	etmdata->base = devm_ioremap(dev, res->start, resource_size(res));
 	if (!etmdata->base)
@@ -590,8 +697,11 @@
 	if (!etmdata->state)
 		return -ENOMEM;
 
-	smp_call_function_single(0, etm_init_arch_data, etmdata, 1);
-
+	if (cpu == 0) {
+		if (smp_call_function_single(cpu, etm_init_arch_data,
+								etmdata, 1))
+			dev_err(dev, "Jtagmm: ETM arch init failed\n");
+	}
 	if (etm_arch_supported(etm.arch)) {
 		if (scm_get_feat_version(TZ_DBG_ETM_FEAT_ID) < TZ_DBG_ETM_VER)
 			etm.save_restore_enabled[cpu] = true;
@@ -606,6 +716,7 @@
 {
 	switch (arch) {
 	case ARM_DEBUG_ARCH_V7B:
+	case ARM_DEBUG_ARCH_V7p1:
 		break;
 	default:
 		return false;
@@ -642,7 +753,7 @@
 
 	dbg.cpu_ctx[cpu] = dbgdata;
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "debug-base");
 
 	dbgdata->base = devm_ioremap(dev, res->start, resource_size(res));
 	if (!dbgdata->base)
@@ -654,8 +765,11 @@
 	if (!dbgdata->state)
 		return -ENOMEM;
 
-	smp_call_function_single(0, dbg_init_arch_data, dbgdata, 1);
-
+	if (cpu == 0) {
+		if (smp_call_function_single(cpu, dbg_init_arch_data,
+								dbgdata, 1))
+			dev_err(dev, "Jtagmm: Dbg arch init failed\n");
+	}
 	if (dbg_arch_supported(dbg.arch)) {
 		if (scm_get_feat_version(TZ_DBG_ETM_FEAT_ID) < TZ_DBG_ETM_VER)
 			dbg.save_restore_enabled[cpu] = true;
diff --git a/arch/arm/mach-msm/msm_rtb.c b/arch/arm/mach-msm/msm_rtb.c
index e797e2e..fdf39be 100644
--- a/arch/arm/mach-msm/msm_rtb.c
+++ b/arch/arm/mach-msm/msm_rtb.c
@@ -55,7 +55,7 @@
 
 struct msm_rtb_state {
 	struct msm_rtb_layout *rtb;
-	unsigned long phys;
+	phys_addr_t phys;
 	int nentries;
 	int size;
 	int enabled;
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index a22d664..717c057 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -25,7 +25,9 @@
 #include <linux/smp.h>
 #include <linux/suspend.h>
 #include <linux/tick.h>
+#include <linux/delay.h>
 #include <linux/platform_device.h>
+#include <linux/of_platform.h>
 #include <linux/regulator/krait-regulator.h>
 #include <mach/msm_iomap.h>
 #include <mach/socinfo.h>
@@ -127,6 +129,7 @@
 static bool msm_pm_retention_calls_tz;
 static uint32_t msm_pm_max_sleep_time;
 static bool msm_no_ramp_down_pc;
+static struct msm_pm_sleep_status_data *msm_pm_slp_sts;
 
 static int msm_pm_get_pc_mode(struct device_node *node,
 		const char *key, uint32_t *pc_mode_val)
@@ -953,6 +956,32 @@
 	return sleep_mode;
 }
 
+int msm_pm_wait_cpu_shutdown(unsigned int cpu)
+{
+	int timeout = 10;
+
+	if (!msm_pm_slp_sts)
+		return 0;
+	if (!msm_pm_slp_sts[cpu].base_addr)
+		return 0;
+	while (timeout--) {
+		/*
+		 * Check for the SPM of the core being hotplugged to set
+		 * its sleep state.The SPM sleep state indicates that the
+		 * core has been power collapsed.
+		 */
+		int acc_sts = __raw_readl(msm_pm_slp_sts[cpu].base_addr);
+
+		if (acc_sts & msm_pm_slp_sts[cpu].mask)
+			return 0;
+		usleep(100);
+	}
+
+	pr_info("%s(): Timed out waiting for CPU %u SPM to enter sleep state",
+		__func__, cpu);
+	return -EBUSY;
+}
+
 void msm_pm_cpu_enter_lowpower(unsigned int cpu)
 {
 	int i;
@@ -1109,6 +1138,93 @@
 	.enter = msm_pm_enter,
 	.valid = suspend_valid_only_mem,
 };
+static int __devinit msm_cpu_status_probe(struct platform_device *pdev)
+{
+	struct msm_pm_sleep_status_data *pdata;
+	char *key;
+	u32 cpu;
+
+	if (!pdev)
+		return -EFAULT;
+
+	msm_pm_slp_sts =
+		kzalloc(sizeof(*msm_pm_slp_sts) * num_possible_cpus(),
+				GFP_KERNEL);
+
+	if (!msm_pm_slp_sts)
+		return -ENOMEM;
+
+	if (pdev->dev.of_node) {
+		struct resource *res;
+		u32 offset;
+		int rc;
+		u32 mask;
+
+		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+		if (!res)
+			goto fail_free_mem;
+
+		key = "qcom,cpu-alias-addr";
+		rc = of_property_read_u32(pdev->dev.of_node, key, &offset);
+
+		if (rc)
+			goto fail_free_mem;
+
+		key = "qcom,sleep-status-mask";
+		rc = of_property_read_u32(pdev->dev.of_node, key,
+					&mask);
+		if (rc)
+			goto fail_free_mem;
+
+		for_each_possible_cpu(cpu) {
+			msm_pm_slp_sts[cpu].base_addr =
+				ioremap(res->start + cpu * offset,
+					resource_size(res));
+			msm_pm_slp_sts[cpu].mask = mask;
+
+			if (!msm_pm_slp_sts[cpu].base_addr)
+				goto failed_of_node;
+		}
+
+	} else {
+		pdata = pdev->dev.platform_data;
+		if (!pdev->dev.platform_data)
+			goto fail_free_mem;
+
+		for_each_possible_cpu(cpu) {
+			msm_pm_slp_sts[cpu].base_addr =
+				pdata->base_addr + cpu * pdata->cpu_offset;
+			msm_pm_slp_sts[cpu].mask = pdata->mask;
+		}
+	}
+
+	return 0;
+
+failed_of_node:
+	pr_info("%s(): Failed to key=%s\n", __func__, key);
+	for_each_possible_cpu(cpu) {
+		if (msm_pm_slp_sts[cpu].base_addr)
+			iounmap(msm_pm_slp_sts[cpu].base_addr);
+	}
+fail_free_mem:
+	kfree(msm_pm_slp_sts);
+	return -EINVAL;
+
+};
+
+static struct of_device_id msm_slp_sts_match_tbl[] = {
+	{.compatible = "qcom,cpu-sleep-status"},
+	{},
+};
+
+static struct platform_driver msm_cpu_status_driver = {
+	.probe = msm_cpu_status_probe,
+	.driver = {
+		.name = "cpu_slp_status",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_slp_sts_match_tbl,
+	},
+};
 
 static int __devinit msm_pm_init(void)
 {
@@ -1378,6 +1494,9 @@
 
 pm_8x60_probe_done:
 	msm_pm_init();
+	if (pdev->dev.of_node)
+		of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+
 	return ret;
 }
 
@@ -1397,6 +1516,16 @@
 
 static int __init msm_pm_8x60_init(void)
 {
+	int rc;
+
+	rc = platform_driver_register(&msm_cpu_status_driver);
+
+	if (rc) {
+		pr_err("%s(): failed to register driver %s\n", __func__,
+				msm_cpu_status_driver.driver.name);
+		return rc;
+	}
+
 	return platform_driver_register(&msm_pm_8x60_driver);
 }
 device_initcall(msm_pm_8x60_init);
diff --git a/arch/arm/mach-msm/pm.h b/arch/arm/mach-msm/pm.h
index 793b778..8a043d8 100644
--- a/arch/arm/mach-msm/pm.h
+++ b/arch/arm/mach-msm/pm.h
@@ -135,9 +135,11 @@
 #ifdef CONFIG_MSM_PM8X60
 void msm_pm_set_rpm_wakeup_irq(unsigned int irq);
 void msm_pm_set_sleep_ops(struct msm_pm_sleep_ops *ops);
+int msm_pm_wait_cpu_shutdown(unsigned int cpu);
 #else
 static inline void msm_pm_set_rpm_wakeup_irq(unsigned int irq) {}
 static inline void msm_pm_set_sleep_ops(struct msm_pm_sleep_ops *ops) {}
+static inline int msm_pm_wait_cpu_shutdown(unsigned int cpu) { return 0; }
 #endif
 #ifdef CONFIG_HOTPLUG_CPU
 int msm_platform_secondary_init(unsigned int cpu);
diff --git a/arch/arm/mach-msm/qdsp6v2/apr.c b/arch/arm/mach-msm/qdsp6v2/apr.c
index 4c106c5..6e60db1 100644
--- a/arch/arm/mach-msm/qdsp6v2/apr.c
+++ b/arch/arm/mach-msm/qdsp6v2/apr.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
@@ -26,6 +26,7 @@
 #include <linux/sysfs.h>
 #include <linux/device.h>
 #include <linux/slab.h>
+#include <sound/apr_audio-v2.h>
 #include <asm/mach-types.h>
 #include <mach/subsystem_restart.h>
 #include <mach/msm_smd.h>
@@ -114,6 +115,11 @@
 		.name = "VIDC",
 		.idx = 9,
 		.id = APR_SVC_VIDC,
+	},
+	{
+		.name = "LSM",
+		.idx = 9,
+		.id = APR_SVC_LSM,
 		.client_id = APR_CLIENT_AUDIO,
 	},
 };
@@ -280,7 +286,6 @@
 		return -ENETRESET;
 	}
 
-
 	spin_lock_irqsave(&svc->w_lock, flags);
 	dest_id = svc->dest_id;
 	client_id = svc->client_id;
@@ -391,7 +396,8 @@
 		    svc == APR_SVC_ADM || svc == APR_SVC_ADSP_CORE ||
 		    svc == APR_SVC_USM ||
 		    svc == APR_SVC_TEST_CLIENT || svc == APR_SVC_ADSP_MVM ||
-		    svc == APR_SVC_ADSP_CVS || svc == APR_SVC_ADSP_CVP)
+		    svc == APR_SVC_ADSP_CVS || svc == APR_SVC_ADSP_CVP ||
+		    svc == APR_SVC_LSM)
 			clnt = APR_CLIENT_AUDIO;
 		else if (svc == APR_SVC_VIDC)
 			clnt = APR_CLIENT_AUDIO;
diff --git a/arch/arm/mach-msm/ramdump.h b/arch/arm/mach-msm/ramdump.h
index e43ca12..3a960a1 100644
--- a/arch/arm/mach-msm/ramdump.h
+++ b/arch/arm/mach-msm/ramdump.h
@@ -1,4 +1,4 @@
-/* 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
@@ -20,6 +20,7 @@
 	unsigned long size;
 };
 
+#ifdef CONFIG_MSM_SUBSYSTEM_RESTART
 void *create_ramdump_device(const char *dev_name, struct device *parent);
 void destroy_ramdump_device(void *dev);
 int do_ramdump(void *handle, struct ramdump_segment *segments,
@@ -27,4 +28,28 @@
 int do_elf_ramdump(void *handle, struct ramdump_segment *segments,
 		int nsegments);
 
+#else
+static inline void *create_ramdump_device(const char *dev_name,
+		struct device *parent)
+{
+	return NULL;
+}
+
+static inline void destroy_ramdump_device(void *dev)
+{
+}
+
+static inline int do_ramdump(void *handle, struct ramdump_segment *segments,
+		int nsegments)
+{
+	return -ENODEV;
+}
+
+static inline int do_elf_ramdump(void *handle, struct ramdump_segment *segments,
+		int nsegments)
+{
+	return -ENODEV;
+}
+#endif /* CONFIG_MSM_SUBSYSTEM_RESTART */
+
 #endif
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index cffb211..40ef20e 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -49,6 +49,7 @@
 
 #include "smd_private.h"
 #include "modem_notifier.h"
+#include "ramdump.h"
 
 #if defined(CONFIG_ARCH_QSD8X50) || defined(CONFIG_ARCH_MSM8X60) \
 	|| defined(CONFIG_ARCH_MSM8960) || defined(CONFIG_ARCH_FSM9XXX) \
@@ -178,7 +179,10 @@
 };
 static uint32_t num_smem_areas;
 static struct smem_area *smem_areas;
+static struct ramdump_segment *smem_ramdump_segments;
+static void *smem_ramdump_dev;
 static void *smem_range_check(phys_addr_t base, unsigned offset);
+static void *smd_dev;
 
 struct interrupt_stat interrupt_stats[NUM_SMD_SUBSYSTEMS];
 
@@ -977,10 +981,6 @@
 
 	SMx_POWER_INFO("%s: starting reset\n", __func__);
 
-	/* release any held spinlocks */
-	remote_spin_release(&remote_spinlock, restart_pid);
-	remote_spin_release_all(restart_pid);
-
 	shared = smem_find(ID_CH_ALLOC_TBL, sizeof(*shared) * 64);
 	if (!shared) {
 		pr_err("%s: allocation table not initialized\n", __func__);
@@ -3720,6 +3720,7 @@
 	struct device_node *node;
 	int ret;
 	const char *compatible;
+	struct ramdump_segment *ramdump_segments_tmp;
 	int subnode_num = 0;
 	resource_size_t irq_out_size;
 
@@ -3757,13 +3758,33 @@
 		}
 	}
 
+	/* initialize SSR ramdump regions */
+	key = "smem";
+	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, key);
+	if (!r) {
+		pr_err("%s: missing '%s'\n", __func__, key);
+		return -ENODEV;
+	}
+	ramdump_segments_tmp = kmalloc_array(num_smem_areas + 1,
+			sizeof(struct ramdump_segment), GFP_KERNEL);
+
+	if (!ramdump_segments_tmp) {
+		pr_err("%s: ramdump segment kmalloc failed\n", __func__);
+		ret = -ENOMEM;
+		goto free_smem_areas;
+	}
+	ramdump_segments_tmp[0].address = r->start;
+	ramdump_segments_tmp[0].size = resource_size(r);
+
 	if (num_smem_areas) {
+
 		smem_areas = kmalloc(sizeof(struct smem_area) * num_smem_areas,
 					GFP_KERNEL);
+
 		if (!smem_areas) {
 			pr_err("%s: smem areas kmalloc failed\n", __func__);
-			num_smem_areas = 0;
-			return -ENOMEM;
+			ret = -ENOMEM;
+			goto free_smem_areas;
 		}
 		count = 1;
 		while (1) {
@@ -3775,6 +3796,16 @@
 				break;
 			aux_mem_base = r->start;
 			aux_mem_size = resource_size(r);
+
+			/*
+			 * Add to ram-dumps segments.
+			 * ramdump_segments_tmp[0] is the main SMEM region,
+			 * so auxiliary segments are indexed by count
+			 * instead of count - 1.
+			 */
+			ramdump_segments_tmp[count].address = aux_mem_base;
+			ramdump_segments_tmp[count].size = aux_mem_size;
+
 			SMD_DBG("%s: %s = %pa %pa", __func__, temp_string,
 					&aux_mem_base, &aux_mem_size);
 			smem_areas[count - 1].phys_addr = aux_mem_base;
@@ -3822,6 +3853,7 @@
 		++subnode_num;
 	}
 
+	smem_ramdump_segments = ramdump_segments_tmp;
 	return 0;
 
 rollback_subnodes:
@@ -3838,6 +3870,7 @@
 	}
 free_smem_areas:
 	num_smem_areas = 0;
+	kfree(ramdump_segments_tmp);
 	kfree(smem_areas);
 	smem_areas = NULL;
 	return ret;
@@ -3869,6 +3902,7 @@
 								__func__);
 				return ret;
 			}
+			smd_dev = &pdev->dev;
 		} else if (pdev->dev.platform_data) {
 			ret = smd_core_platform_init(pdev);
 			if (ret) {
@@ -3928,6 +3962,26 @@
 				__func__, notifier->processor,
 				notifier->name);
 
+		remote_spin_release(&remote_spinlock, notifier->processor);
+		remote_spin_release_all(notifier->processor);
+
+		if (smem_ramdump_dev) {
+			int ret;
+
+			SMD_INFO("%s: saving ramdump\n", __func__);
+			/*
+			 * XPU protection does not currently allow the
+			 * auxiliary memory regions to be dumped.  If this
+			 * changes, then num_smem_areas + 1 should be passed
+			 * into do_elf_ramdump() to dump all regions.
+			 */
+			ret = do_elf_ramdump(smem_ramdump_dev,
+					smem_ramdump_segments, 1);
+			if (ret < 0)
+				pr_err("%s: unable to dump smem %d\n", __func__,
+						ret);
+		}
+
 		smd_channel_reset(notifier->processor);
 	}
 
@@ -3940,12 +3994,20 @@
 	void *handle;
 	struct restart_notifier_block *nb;
 
+	smem_ramdump_dev = create_ramdump_device("smem-smd", smd_dev);
+	if (IS_ERR_OR_NULL(smem_ramdump_dev)) {
+		pr_err("%s: Unable to create smem ramdump device.\n",
+			__func__);
+		smem_ramdump_dev = NULL;
+	}
+
 	for (i = 0; i < ARRAY_SIZE(restart_notifiers); i++) {
 		nb = &restart_notifiers[i];
 		handle = subsys_notif_register_notifier(nb->name, &nb->nb);
 		SMD_DBG("%s: registering notif for '%s', handle=%p\n",
 				__func__, nb->name, handle);
 	}
+
 	return 0;
 }
 late_initcall(modem_restart_late_init);
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index 73fe5d6..0f4d613 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -89,7 +89,7 @@
 	int n = -1, err = 0;
 
 	VERIFY(err, 0 != access_ok(access ? VERIFY_WRITE : VERIFY_READ,
-			      (void __user *)start, len));
+					(void __user *)start, len));
 	if (err)
 		goto bail;
 	VERIFY(err, 0 != (vma = find_vma(current->mm, start)));
@@ -611,27 +611,28 @@
 static int get_dev(struct fastrpc_apps *me, struct fastrpc_device **rdev)
 {
 	struct hlist_head *head;
-	struct fastrpc_device *dev = 0;
-	struct hlist_node *n;
+	struct fastrpc_device *dev = 0, *devfree = 0;
+	struct hlist_node *pos, *n;
 	uint32_t h = hash_32(current->tgid, RPC_HASH_BITS);
 	int err = 0;
 
 	spin_lock(&me->hlock);
 	head = &me->htbl[h];
-	hlist_for_each_entry(dev, n, head, hn) {
+	hlist_for_each_entry_safe(dev, pos, n, head, hn) {
 		if (dev->tgid == current->tgid) {
 			hlist_del(&dev->hn);
+			devfree = dev;
 			break;
 		}
 	}
 	spin_unlock(&me->hlock);
-	VERIFY(err, dev != 0);
+	VERIFY(err, devfree != 0);
 	if (err)
 		goto bail;
-	*rdev = dev;
+	*rdev = devfree;
  bail:
 	if (err) {
-		free_dev(dev);
+		free_dev(devfree);
 		err = alloc_dev(rdev);
 	}
 	return err;
@@ -756,22 +757,23 @@
 	struct fastrpc_apps *me = &gfa;
 	uint32_t h = hash_32(current->tgid, RPC_HASH_BITS);
 	struct hlist_head *head;
-	struct hlist_node *pos;
-	struct fastrpc_device *dev;
+	struct hlist_node *pos, *n;
+	struct fastrpc_device *dev, *devfree;
 
  rnext:
-	dev = 0;
+	devfree = dev = 0;
 	spin_lock(&me->hlock);
 	head = &me->htbl[h];
-	hlist_for_each_entry(dev, pos, head, hn) {
+	hlist_for_each_entry_safe(dev, pos, n, head, hn) {
 		if (dev->tgid == current->tgid) {
 			hlist_del(&dev->hn);
+			devfree = dev;
 			break;
 		}
 	}
 	spin_unlock(&me->hlock);
-	if (dev) {
-		free_dev(dev);
+	if (devfree) {
+		free_dev(devfree);
 		goto rnext;
 	}
 	return;
diff --git a/drivers/devfreq/governor_performance.c b/drivers/devfreq/governor_performance.c
index 574a06b..af75ddd 100644
--- a/drivers/devfreq/governor_performance.c
+++ b/drivers/devfreq/governor_performance.c
@@ -10,6 +10,7 @@
  */
 
 #include <linux/devfreq.h>
+#include "governor.h"
 
 static int devfreq_performance_func(struct devfreq *df,
 				    unsigned long *freq)
@@ -25,8 +26,14 @@
 	return 0;
 }
 
+static int performance_init(struct devfreq *devfreq)
+{
+	return update_devfreq(devfreq);
+}
+
 const struct devfreq_governor devfreq_performance = {
 	.name = "performance",
+	.init = performance_init,
 	.get_target_freq = devfreq_performance_func,
 	.no_central_polling = true,
 };
diff --git a/drivers/devfreq/governor_powersave.c b/drivers/devfreq/governor_powersave.c
index d742d4a..fec0cdb 100644
--- a/drivers/devfreq/governor_powersave.c
+++ b/drivers/devfreq/governor_powersave.c
@@ -10,6 +10,7 @@
  */
 
 #include <linux/devfreq.h>
+#include "governor.h"
 
 static int devfreq_powersave_func(struct devfreq *df,
 				  unsigned long *freq)
@@ -22,8 +23,14 @@
 	return 0;
 }
 
+static int powersave_init(struct devfreq *devfreq)
+{
+	return update_devfreq(devfreq);
+}
+
 const struct devfreq_governor devfreq_powersave = {
 	.name = "powersave",
+	.init = powersave_init,
 	.get_target_freq = devfreq_powersave_func,
 	.no_central_polling = true,
 };
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index 93b7e5d..cc01d37 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -722,17 +722,23 @@
 {
 	struct kgsl_iommu *iommu = mmu->priv;
 	struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[unit_id];
-	int i;
+	int i, j;
+	int found_ctx;
 
-	if (data->iommu_ctx_count > KGSL_IOMMU_MAX_DEVS_PER_UNIT) {
-		KGSL_CORE_ERR("Too many iommu devices defined for an "
-				"IOMMU unit\n");
-		return -EINVAL;
-	}
-
-	for (i = 0; i < data->iommu_ctx_count; i++) {
-		if (!data->iommu_ctxs[i].iommu_ctx_name)
-			continue;
+	for (j = 0; j < KGSL_IOMMU_MAX_DEVS_PER_UNIT; j++) {
+		found_ctx = 0;
+		for (i = 0; i < data->iommu_ctx_count; i++) {
+			if (j == data->iommu_ctxs[i].ctx_id) {
+				found_ctx = 1;
+				break;
+			}
+		}
+		if (!found_ctx)
+			break;
+		if (!data->iommu_ctxs[i].iommu_ctx_name) {
+			KGSL_CORE_ERR("Context name invalid\n");
+			return -EINVAL;
+		}
 
 		iommu_unit->dev[iommu_unit->dev_count].dev =
 			msm_iommu_get_ctx(data->iommu_ctxs[i].iommu_ctx_name);
@@ -741,12 +747,6 @@
 			"device %s\n", data->iommu_ctxs[i].iommu_ctx_name);
 			return -EINVAL;
 		}
-		if (KGSL_IOMMU_CONTEXT_USER != data->iommu_ctxs[i].ctx_id &&
-			KGSL_IOMMU_CONTEXT_PRIV != data->iommu_ctxs[i].ctx_id) {
-			KGSL_CORE_ERR("Invalid context ID defined: %d\n",
-					data->iommu_ctxs[i].ctx_id);
-			return -EINVAL;
-		}
 		iommu_unit->dev[iommu_unit->dev_count].ctx_id =
 						data->iommu_ctxs[i].ctx_id;
 		iommu_unit->dev[iommu_unit->dev_count].kgsldev = mmu->device;
@@ -758,6 +758,10 @@
 
 		iommu_unit->dev_count++;
 	}
+	if (!j) {
+		KGSL_CORE_ERR("No ctxts initialized, user ctxt absent\n ");
+		return -EINVAL;
+	}
 
 	return 0;
 }
diff --git a/drivers/media/platform/msm/dvb/video/mpq_dvb_video.c b/drivers/media/platform/msm/dvb/video/mpq_dvb_video.c
index 46002c3..b9fdc5e 100644
--- a/drivers/media/platform/msm/dvb/video/mpq_dvb_video.c
+++ b/drivers/media/platform/msm/dvb/video/mpq_dvb_video.c
@@ -28,7 +28,7 @@
 #include <linux/uaccess.h>
 #include <linux/wait.h>
 #include <linux/workqueue.h>
-#include <linux/android_pmem.h>
+
 #include <linux/clk.h>
 #include <linux/timer.h>
 #include <mach/msm_subsystem_map.h>
@@ -43,8 +43,6 @@
 #define ERR(x...) pr_err(x)
 
 #define MPQ_VID_DEC_NAME "mpq_vidc_dec"
-static unsigned int vidc_mmu_subsystem[] = {
-	MSM_SUBSYSTEM_VIDEO};
 
 static char vid_thread_names[DVB_MPQ_NUM_VIDEO_DEVICES][10] = {
 				"dvb-vid-0",
@@ -1060,10 +1058,7 @@
 {
 	struct vcd_property_hdr vcd_property_hdr;
 	struct vcd_property_h264_mv_buffer *vcd_h264_mv_buffer = NULL;
-	struct msm_mapped_buffer *mapped_buffer = NULL;
 	u32 vcd_status = VCD_ERR_FAIL;
-	u32 len = 0, flags = 0;
-	struct file *file;
 	int rc = 0;
 	unsigned long ionflag = 0;
 	unsigned long buffer_size = 0;
@@ -1084,28 +1079,8 @@
 	vcd_h264_mv_buffer->offset = mv_data->offset;
 
 	if (!vcd_get_ion_status()) {
-		if (get_pmem_file(vcd_h264_mv_buffer->pmem_fd,
-			(unsigned long *) (&(vcd_h264_mv_buffer->
-			physical_addr)),
-			(unsigned long *) (&vcd_h264_mv_buffer->
-						kernel_virtual_addr),
-			(unsigned long *) (&len), &file)) {
-			ERR("%s(): get_pmem_file failed\n", __func__);
-			return -EIO;
-		}
-		put_pmem_file(file);
-		flags = MSM_SUBSYSTEM_MAP_IOVA;
-		mapped_buffer = msm_subsystem_map_buffer(
-			(unsigned long)vcd_h264_mv_buffer->physical_addr, len,
-				flags, vidc_mmu_subsystem,
-				sizeof(vidc_mmu_subsystem)/
-				sizeof(unsigned int));
-		if (IS_ERR(mapped_buffer)) {
-			ERR("buffer map failed");
-			return PTR_ERR(mapped_buffer);
-		}
-		vcd_h264_mv_buffer->client_data = (void *) mapped_buffer;
-		vcd_h264_mv_buffer->dev_addr = (u8 *)mapped_buffer->iova[0];
+		pr_err("PMEM not available");
+		return -EINVAL;
 	} else {
 		client_ctx->h264_mv_ion_handle = ion_import_dma_buf(
 					client_ctx->user_ion_client,
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
index 65542bc..62158b0 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
@@ -18,7 +18,7 @@
 int msm_vidc_debug = 0x3;
 int msm_fw_debug = 0x18;
 int msm_fw_debug_mode = 0x1;
-int msm_fw_low_power_mode = 0x1;
+int msm_fw_low_power_mode = 0x0;
 
 struct debug_buffer {
 	char ptr[MAX_DBG_BUF_SIZE];
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 1b7ecf0..fb27b23 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -2002,12 +2002,8 @@
 		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
 		return;
 	}
-	if (device->clocks_enabled) {
-		cl = &device->resources.clock[VCODEC_CLK];
-		clk_disable_unprepare(cl->clk);
-	}
 
-	for (i = VCODEC_CLK; i < VCODEC_MAX_CLKS; i++) {
+	for (i = 0; i < VCODEC_MAX_CLKS; i++) {
 		cl = &device->resources.clock[i];
 		clk_disable_unprepare(cl->clk);
 	}
@@ -2022,17 +2018,7 @@
 		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
 		return -EINVAL;
 	}
-	if (!device->clocks_enabled) {
-		cl = &device->resources.clock[VCODEC_CLK];
-		rc = clk_prepare_enable(cl->clk);
-		if (rc) {
-			dprintk(VIDC_ERR, "Failed to enable clocks\n");
-			goto fail_clk_enable;
-		} else {
-			dprintk(VIDC_DBG, "Clock: %s enabled\n", cl->name);
-		}
-	}
-	for (i = VCODEC_CLK; i < VCODEC_MAX_CLKS; i++) {
+	for (i = 0; i < VCODEC_MAX_CLKS; i++) {
 		cl = &device->resources.clock[i];
 		rc = clk_prepare_enable(cl->clk);
 		if (rc) {
@@ -2672,8 +2658,8 @@
 	}
 	if (device->resources.fw.cookie) {
 		venus_hfi_disable_clks(device);
-		subsystem_put(device->resources.fw.cookie);
 		venus_hfi_iommu_detach(device);
+		subsystem_put(device->resources.fw.cookie);
 		device->resources.fw.cookie = NULL;
 	}
 }
diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index ef21b7b..f9ae3c2 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -416,14 +416,16 @@
 
 	if (pipe_connect->mem_type == SYSTEM_MEM) {
 		pr_debug("%s: Freeing system memory used by PIPE\n", __func__);
-		dma_free_coherent(&ctx.usb_bam_pdev->dev,
-				sps_connection->data.size,
-				sps_connection->data.base,
-				sps_connection->data.phys_base);
-		dma_free_coherent(&ctx.usb_bam_pdev->dev,
-				sps_connection->desc.size,
-				sps_connection->desc.base,
-				sps_connection->desc.phys_base);
+		if (sps_connection->data.phys_base)
+			dma_free_coherent(&ctx.usb_bam_pdev->dev,
+					sps_connection->data.size,
+					sps_connection->data.base,
+					sps_connection->data.phys_base);
+		if (sps_connection->desc.phys_base)
+			dma_free_coherent(&ctx.usb_bam_pdev->dev,
+					sps_connection->desc.size,
+					sps_connection->desc.base,
+					sps_connection->desc.phys_base);
 	} else if (pipe_connect->mem_type == USB_PRIVATE_MEM) {
 		pr_debug("Freeing USB private memory used by BAM PIPE\n");
 		writel_relaxed(0x0, ctx.qscratch_ram1_reg);
@@ -806,10 +808,11 @@
 	int ret;
 	u8 idx;
 	struct usb_bam_pipe_connect *pipe_connect;
+	struct sps_connect *sps_connection;
 
 	if (ipa_params->prod_clnt_hdl) {
 		/* close USB -> IPA pipe */
-		idx = ipa_params->src_idx;
+		idx = ipa_params->dst_idx;
 		ret = ipa_disconnect(ipa_params->prod_clnt_hdl);
 		if (ret) {
 			pr_err("%s: dst pipe disconnection failure\n",
@@ -817,11 +820,20 @@
 			return ret;
 		}
 		pipe_connect = &usb_bam_connections[idx];
-		pipe_connect->enabled = 0;
+		sps_connection = &ctx.usb_bam_sps.sps_connections[idx];
+		sps_connection->data.phys_base = 0;
+		sps_connection->desc.phys_base = 0;
+
+		ret = usb_bam_disconnect_pipe(idx);
+		if (ret) {
+			pr_err("%s: failure to disconnect pipe %d\n",
+				__func__, idx);
+			return ret;
+		}
 	}
 	if (ipa_params->cons_clnt_hdl) {
 		/* close IPA -> USB pipe */
-		idx = ipa_params->dst_idx;
+		idx = ipa_params->src_idx;
 		ret = ipa_disconnect(ipa_params->cons_clnt_hdl);
 		if (ret) {
 			pr_err("%s: src pipe disconnection failure\n",
@@ -829,7 +841,16 @@
 			return ret;
 		}
 		pipe_connect = &usb_bam_connections[idx];
-		pipe_connect->enabled = 0;
+		sps_connection = &ctx.usb_bam_sps.sps_connections[idx];
+		sps_connection->data.phys_base = 0;
+		sps_connection->desc.phys_base = 0;
+
+		ret = usb_bam_disconnect_pipe(idx);
+		if (ret) {
+			pr_err("%s: failure to disconnect pipe %d\n",
+				__func__, idx);
+			return ret;
+		}
 	}
 
 	ipa_rm_release_resource(IPA_CLIENT_USB_PROD);
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index eb0d6d4..180ca0d 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -525,6 +525,8 @@
 
 	if (chip->usb_present ^ usb_present) {
 		chip->usb_present = usb_present;
+		if (!usb_present)
+			qpnp_chg_iusbmax_set(chip, QPNP_CHG_I_MAX_MIN_100);
 		power_supply_set_present(chip->usb_psy,
 			chip->usb_present);
 	}
@@ -1015,17 +1017,15 @@
 	chip->usb_psy->get_property(chip->usb_psy,
 			  POWER_SUPPLY_PROP_ONLINE, &ret);
 
-	if (ret.intval && qpnp_chg_is_usb_chg_plugged_in(chip)) {
-		chip->usb_psy->get_property(chip->usb_psy,
-			  POWER_SUPPLY_PROP_CURRENT_MAX, &ret);
-		qpnp_chg_iusbmax_set(chip, ret.intval / 1000);
-		if ((ret.intval / 1000) <= QPNP_CHG_I_MAX_MIN_MA)
+	/* Only honour requests while USB is present */
+	if (qpnp_chg_is_usb_chg_plugged_in(chip)) {
+		if (ret.intval <= 2) {
 			qpnp_chg_usb_suspend_enable(chip, 1);
-		else
+			qpnp_chg_iusbmax_set(chip, QPNP_CHG_I_MAX_MIN_100);
+		} else {
+			qpnp_chg_iusbmax_set(chip, ret.intval / 1000);
 			qpnp_chg_usb_suspend_enable(chip, 0);
-	} else {
-		qpnp_chg_iusbmax_set(chip, QPNP_CHG_I_MAX_MIN_100);
-		qpnp_chg_usb_suspend_enable(chip, 0);
+		}
 	}
 
 	pr_debug("end of power supply changed\n");
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 98a8202..c6b3472 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -564,6 +564,8 @@
 	struct ion_client *iclient = mdss_get_ionclient();
 	struct mdss_panel_data *pdata;
 	int ret = 0, off;
+	int mdss_mdp_rev = MDSS_MDP_REG_READ(MDSS_MDP_REG_HW_VERSION);
+	int mdss_v2_intf_off = 0;
 
 	off = 0;
 
@@ -576,9 +578,13 @@
 	mdss_mdp_ctl_write(ctl, 0, MDSS_MDP_LM_BORDER_COLOR);
 	off = MDSS_MDP_REG_INTF_OFFSET(ctl->intf_num);
 
+	if (mdss_mdp_rev == MDSS_MDP_HW_REV_102)
+		mdss_v2_intf_off =  0xEC00;
+
 	/* wait for 1 VSYNC for the pipe to be unstaged */
 	msleep(20);
-	MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_TIMING_ENGINE_EN, 0);
+	MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_TIMING_ENGINE_EN -
+			mdss_v2_intf_off, 0);
 	ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_CONT_SPLASH_FINISH,
 			NULL);
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
diff --git a/include/sound/Kbuild b/include/sound/Kbuild
index ba75dca..edadaa9 100644
--- a/include/sound/Kbuild
+++ b/include/sound/Kbuild
@@ -11,3 +11,4 @@
 header-y += tlv.h
 header-y += compress_params.h
 header-y += compress_offload.h
+header-y += lsm_params.h
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index bc68c24..f88c817 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -658,6 +658,11 @@
 #define SLIMBUS_3_TX		0x4007
 #define SLIMBUS_4_RX		0x4008
 #define SLIMBUS_4_TX		0x4009		/* index = 24 */
+#define SLIMBUS_5_RX		0x400a
+#define SLIMBUS_5_TX		0x400b
+#define SLIMBUS_6_RX		0x400c
+#define SLIMBUS_6_TX		0x400d
+#define SLIMBUS_PORT_LAST	SLIMBUS_6_TX
 #define INT_BT_SCO_RX 0x3000		/* index = 25 */
 #define INT_BT_SCO_TX 0x3001		/* index = 26 */
 #define INT_BT_A2DP_RX 0x3002		/* index = 27 */
@@ -798,6 +803,15 @@
 #define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_4_RX      0x4008
 /* SLIMbus Tx port on channel 4. */
 #define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_4_TX      0x4009
+/* SLIMbus Rx port on channel 5. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_5_RX      0x400a
+/* SLIMbus Tx port on channel 5. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_5_TX      0x400b
+/* SLIMbus Rx port on channel 6. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_6_RX      0x400c
+/* SLIMbus Tx port on channel 6. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_6_TX      0x400d
+
 /* Generic pseudoport 1. */
 #define AFE_PORT_ID_PSEUDOPORT_01      0x8001
 /* Generic pseudoport 2. */
@@ -1972,7 +1986,6 @@
 	 */
 } __packed;
 
-
 union afe_port_config {
 	struct afe_param_id_pcm_cfg               pcm;
 	struct afe_param_id_i2s_cfg               i2s;
@@ -6442,6 +6455,56 @@
 } __packed;
 /* SRS TruMedia end */
 
+/* LSM Specific */
+#define VW_FEAT_DIM					(39)
+
+#define APRV2_IDS_SERVICE_ID_ADSP_LSM_V			(0xD)
+#define APRV2_IDS_DOMAIN_ID_ADSP_V			(0x4)
+#define APRV2_IDS_DOMAIN_ID_APPS_V			(0x5)
+
+#define LSM_SESSION_CMD_SHARED_MEM_MAP_REGIONS		(0x00012A7F)
+#define LSM_SESSION_CMDRSP_SHARED_MEM_MAP_REGIONS	(0x00012A80)
+#define LSM_SESSION_CMD_SHARED_MEM_UNMAP_REGIONS	(0x00012A81)
+#define LSM_SESSION_CMD_OPEN_TX				(0x00012A82)
+#define LSM_SESSION_CMD_CLOSE_TX			(0x00012A88)
+#define LSM_SESSION_CMD_SET_PARAMS			(0x00012A83)
+#define LSM_SESSION_CMD_REGISTER_SOUND_MODEL		(0x00012A84)
+#define LSM_SESSION_CMD_DEREGISTER_SOUND_MODEL		(0x00012A85)
+#define LSM_SESSION_CMD_START				(0x00012A86)
+#define LSM_SESSION_CMD_STOP				(0x00012A87)
+
+#define LSM_SESSION_EVENT_DETECTION_STATUS		(0x00012B00)
+
+#define LSM_MODULE_ID_VOICE_WAKEUP			(0x00012C00)
+#define LSM_PARAM_ID_ENDPOINT_DETECT_THRESHOLD		(0x00012C01)
+#define LSM_PARAM_ID_OPERATION_MODE			(0x00012C02)
+#define LSM_PARAM_ID_GAIN				(0x00012C03)
+#define LSM_PARAM_ID_CONNECT_TO_PORT			(0x00012C04)
+#define LSM_PARAM_ID_KEYWORD_DETECT_SENSITIVITY		(0x00012C05)
+#define LSM_PARAM_ID_USER_DETECT_SENSITIVITY		(0x00012C06)
+#define LSM_PARAM_ID_FEATURE_COMPENSATION_DATA		(0x00012C07)
+
+
+/* HW MAD specific */
+#define AFE_MODULE_HW_MAD				(0x00010230)
+#define AFE_PARAM_ID_HW_MAD_CFG				(0x00010231)
+#define AFE_PARAM_ID_HW_MAD_CTRL			(0x00010232)
+#define AFE_PARAM_ID_SLIMBUS_SLAVE_PORT_CFG		(0x00010233)
+
+/* SW MAD specific */
+#define AFE_MODULE_SW_MAD				(0x0001022D)
+#define AFE_PARAM_ID_SW_MAD_CFG				(0x0001022E)
+#define AFE_PARAM_ID_SVM_MODEL				(0x0001022F)
+
+/* Commands/Params to pass the codec/slimbus data to DSP */
+#define AFE_SVC_CMD_SET_PARAM				(0x000100f3)
+#define AFE_MODULE_CDC_DEV_CFG				(0x00010234)
+#define AFE_PARAM_ID_CDC_SLIMBUS_SLAVE_CFG		(0x00010235)
+#define AFE_PARAM_ID_CDC_REG_CFG			(0x00010236)
+#define AFE_PARAM_ID_CDC_REG_CFG_INIT			(0x00010237)
+
+#define AFE_MAX_CDC_REGISTERS_TO_CONFIG			(20)
+
 /* ERROR CODES */
 /* Success. The operation completed with no errors. */
 #define ADSP_EOK          0x00000000
@@ -6669,4 +6732,104 @@
 	uint16_t                  reserved;
 } __packed;
 
+enum afe_config_type {
+	AFE_SLIMBUS_SLAVE_PORT_CONFIG,
+	AFE_SLIMBUS_SLAVE_CONFIG,
+	AFE_CDC_REGISTERS_CONFIG,
+	AFE_MAX_CONFIG_TYPES,
+};
+
+struct afe_param_slimbus_slave_port_cfg {
+	uint32_t minor_version;
+	uint16_t slimbus_dev_id;
+	uint16_t slave_dev_pgd_la;
+	uint16_t slave_dev_intfdev_la;
+	uint16_t bit_width;
+	uint16_t data_format;
+	uint16_t num_channels;
+	uint16_t slave_port_mapping[AFE_PORT_MAX_AUDIO_CHAN_CNT];
+} __packed;
+
+struct afe_param_cdc_slimbus_slave_cfg {
+	uint32_t minor_version;
+	uint32_t device_enum_addr_lsw;
+	uint32_t device_enum_addr_msw;
+	uint16_t tx_slave_port_offset;
+	uint16_t rx_slave_port_offset;
+} __packed;
+
+struct afe_param_cdc_reg_cfg {
+	uint32_t minor_version;
+	uint32_t reg_logical_addr;
+	uint32_t reg_field_type;
+	uint32_t reg_field_bit_mask;
+	uint16_t reg_bit_width;
+	uint16_t reg_offset_scale;
+} __packed;
+
+struct afe_param_cdc_reg_cfg_data {
+	uint32_t num_registers;
+	struct afe_param_cdc_reg_cfg *reg_data;
+} __packed;
+
+struct afe_svc_cmd_set_param {
+	uint32_t payload_size;
+	uint32_t payload_address_lsw;
+	uint32_t payload_address_msw;
+	uint32_t mem_map_handle;
+} __packed;
+
+struct afe_param_hw_mad_ctrl {
+	uint32_t minor_version;
+	uint16_t mad_type;
+	uint16_t mad_enable;
+} __packed;
+
+struct afe_cmd_hw_mad_ctrl {
+	struct apr_hdr hdr;
+	struct afe_port_cmd_set_param_v2 param;
+	struct afe_port_param_data_v2 pdata;
+	struct afe_param_hw_mad_ctrl payload;
+} __packed;
+
+struct afe_cmd_hw_mad_slimbus_slave_port_cfg {
+	struct apr_hdr hdr;
+	struct afe_port_cmd_set_param_v2 param;
+	struct afe_port_param_data_v2 pdata;
+	struct afe_param_slimbus_slave_port_cfg sb_port_cfg;
+} __packed;
+
+struct afe_cmd_sw_mad_enable {
+	struct apr_hdr hdr;
+	struct afe_port_cmd_set_param_v2 param;
+	struct afe_port_param_data_v2 pdata;
+} __packed;
+
+struct afe_param_cdc_reg_cfg_payload {
+	struct afe_port_param_data_v2 common;
+	struct afe_param_cdc_reg_cfg  reg_cfg;
+} __packed;
+
+/*
+ * reg_data's size can be up to AFE_MAX_CDC_REGISTERS_TO_CONFIG
+ */
+struct afe_svc_cmd_cdc_reg_cfg {
+	struct apr_hdr hdr;
+	struct afe_svc_cmd_set_param param;
+	struct afe_param_cdc_reg_cfg_payload reg_data[0];
+} __packed;
+
+struct afe_svc_cmd_init_cdc_reg_cfg {
+	struct apr_hdr hdr;
+	struct afe_svc_cmd_set_param param;
+	struct afe_port_param_data_v2 init;
+} __packed;
+
+struct afe_svc_cmd_sb_slave_cfg {
+	struct apr_hdr hdr;
+	struct afe_svc_cmd_set_param param;
+	struct afe_port_param_data_v2 pdata;
+	struct afe_param_cdc_slimbus_slave_cfg sb_slave_cfg;
+} __packed;
+
 #endif /*_APR_AUDIO_V2_H_ */
diff --git a/include/sound/lsm_params.h b/include/sound/lsm_params.h
new file mode 100644
index 0000000..0edd8b5
--- /dev/null
+++ b/include/sound/lsm_params.h
@@ -0,0 +1,36 @@
+#ifndef __LSM_PARAMS_H__
+#define __LSM_PARAMS_H__
+
+#include <linux/types.h>
+#include <sound/asound.h>
+
+#define SNDRV_LSM_VERSION SNDRV_PROTOCOL_VERSION(0, 1, 0)
+
+enum lsm_detection_mode {
+	LSM_MODE_KEYWORD_ONLY_DETECTION = 1,
+	LSM_MODE_USER_KEYWORD_DETECTION
+};
+
+struct snd_lsm_sound_model {
+	__u8 *data;
+	__u32 data_size;
+	enum lsm_detection_mode detection_mode;
+	__u16 min_keyw_confidence;
+	__u16 min_user_confidence;
+	bool detect_failure;
+};
+
+struct snd_lsm_event_status {
+	__u16 status;
+	__u16 payload_size;
+	__u8 payload[0];
+};
+
+#define SNDRV_LSM_REG_SND_MODEL	 _IOW('U', 0x00, struct snd_lsm_sound_model)
+#define SNDRV_LSM_DEREG_SND_MODEL _IOW('U', 0x01, int)
+#define SNDRV_LSM_EVENT_STATUS	_IOW('U', 0x02, struct snd_lsm_event_status)
+#define SNDRV_LSM_ABORT_EVENT	_IOW('U', 0x03, int)
+#define SNDRV_LSM_START		_IOW('U', 0x04, int)
+#define SNDRV_LSM_STOP		_IOW('U', 0x05, int)
+
+#endif
diff --git a/include/sound/q6afe-v2.h b/include/sound/q6afe-v2.h
index feac314..22ddbbc 100644
--- a/include/sound/q6afe-v2.h
+++ b/include/sound/q6afe-v2.h
@@ -64,24 +64,34 @@
 	IDX_SLIMBUS_3_TX = 22,
 	IDX_SLIMBUS_4_RX = 23,
 	IDX_SLIMBUS_4_TX = 24,
-	IDX_INT_BT_SCO_RX = 25,
-	IDX_INT_BT_SCO_TX = 26,
-	IDX_INT_BT_A2DP_RX = 27,
-	IDX_INT_FM_RX = 28,
-	IDX_INT_FM_TX = 29,
-	IDX_RT_PROXY_PORT_001_RX = 30,
-	IDX_RT_PROXY_PORT_001_TX = 31,
-	IDX_AFE_PORT_ID_QUATERNARY_MI2S_RX = 32,
-	IDX_AFE_PORT_ID_QUATERNARY_MI2S_TX = 33,
-	IDX_AFE_PORT_ID_SECONDARY_MI2S_RX = 34,
-	IDX_AFE_PORT_ID_SECONDARY_MI2S_TX = 35,
-	IDX_AFE_PORT_ID_TERTIARY_MI2S_RX = 36,
-	IDX_AFE_PORT_ID_TERTIARY_MI2S_TX = 37,
-	IDX_AFE_PORT_ID_PRIMARY_MI2S_RX = 38,
-	IDX_AFE_PORT_ID_PRIMARY_MI2S_TX = 39,
+	IDX_SLIMBUS_5_RX = 25,
+	IDX_SLIMBUS_5_TX = 26,
+	IDX_INT_BT_SCO_RX = 27,
+	IDX_INT_BT_SCO_TX = 28,
+	IDX_INT_BT_A2DP_RX = 29,
+	IDX_INT_FM_RX = 30,
+	IDX_INT_FM_TX = 31,
+	IDX_RT_PROXY_PORT_001_RX = 32,
+	IDX_RT_PROXY_PORT_001_TX = 33,
+	IDX_AFE_PORT_ID_QUATERNARY_MI2S_RX = 34,
+	IDX_AFE_PORT_ID_QUATERNARY_MI2S_TX = 35,
+	IDX_AFE_PORT_ID_SECONDARY_MI2S_RX = 36,
+	IDX_AFE_PORT_ID_SECONDARY_MI2S_TX = 37,
+	IDX_AFE_PORT_ID_TERTIARY_MI2S_RX = 38,
+	IDX_AFE_PORT_ID_TERTIARY_MI2S_TX = 39,
+	IDX_AFE_PORT_ID_PRIMARY_MI2S_RX = 40,
+	IDX_AFE_PORT_ID_PRIMARY_MI2S_TX = 41,
+	IDX_GLOBAL_CFG,
 	AFE_MAX_PORTS
 };
 
+enum afe_mad_type {
+	MAD_HW_NONE = 0x00,
+	MAD_HW_AUDIO = 0x01,
+	MAD_HW_BEACON = 0x02,
+	MAD_HW_ULTRASOUND = 0x04
+};
+
 struct afe_audio_buffer {
 	dma_addr_t phys;
 	void       *data;
@@ -172,4 +182,10 @@
 				struct afe_digital_clk_cfg *cfg);
 int q6afe_check_osr_clk_freq(u32 freq);
 
+int afe_turn_onoff_hw_mad(u16 mad_type, u16 mad_enable);
+int afe_port_set_mad_type(u16 port_id, enum afe_mad_type mad_type);
+enum afe_mad_type afe_port_get_mad_type(u16 port_id);
+int afe_set_config(enum afe_config_type config_type, void *config_data,
+		   int arg);
+
 #endif /* __Q6AFE_V2_H__ */
diff --git a/include/sound/q6lsm.h b/include/sound/q6lsm.h
new file mode 100644
index 0000000..5c9d4b9
--- /dev/null
+++ b/include/sound/q6lsm.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 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
+ * 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 __Q6LSM_H__
+#define __Q6LSM_H__
+
+#include <linux/list.h>
+#include <linux/msm_ion.h>
+#include <sound/apr_audio-v2.h>
+#include <sound/lsm_params.h>
+#include <mach/qdsp6v2/apr.h>
+#include <mach/msm_subsystem_map.h>
+
+typedef void (*app_cb)(uint32_t opcode, uint32_t token,
+		       uint32_t *payload, void *priv);
+
+struct lsm_sound_model {
+	dma_addr_t      phys;
+	void		*data;
+	uint32_t	size; /* size of buffer */
+	uint32_t	actual_size; /* actual number of bytes read by DSP */
+	struct ion_handle *handle;
+	struct ion_client *client;
+	uint32_t	mem_map_handle;
+};
+
+struct lsm_client {
+	int		session;
+	app_cb		cb;
+	atomic_t	cmd_state;
+	void		*priv;
+	struct apr_svc  *apr;
+	struct apr_svc  *mmap_apr;
+	struct mutex    cmd_lock;
+	struct lsm_sound_model sound_model;
+	wait_queue_head_t cmd_wait;
+	uint16_t	mode;
+	uint16_t	connect_to_port;
+	uint16_t	user_sensitivity;
+	uint16_t	kw_sensitivity;
+	bool		started;
+};
+
+struct lsm_stream_cmd_open_tx {
+	struct apr_hdr  hdr;
+	uint16_t	app_id;
+	uint16_t	reserved;
+	uint32_t	sampling_rate;
+} __packed;
+
+struct lsm_param_payload_common {
+	uint32_t	module_id;
+	uint32_t	param_id;
+	uint16_t	param_size;
+	uint16_t	reserved;
+} __packed;
+
+struct lsm_param_op_mode {
+	struct lsm_param_payload_common common;
+	uint32_t	minor_version;
+	uint16_t	mode;
+	uint16_t	reserved;
+} __packed;
+
+struct lsm_param_connect_to_port {
+	struct lsm_param_payload_common common;
+	uint32_t	minor_version;
+	/* AFE port id that receives voice wake up data */
+	uint16_t	port_id;
+	uint16_t	reserved;
+} __packed;
+
+struct lsm_param_kw_detect_sensitivity {
+	struct lsm_param_payload_common common;
+	uint32_t	minor_version;
+	/* scale factor to change the keyword confidence thresholds */
+	uint16_t	keyword_sensitivity;
+	uint16_t	reserved;
+} __packed;
+
+struct lsm_param_user_detect_sensitivity {
+	struct lsm_param_payload_common common;
+	uint32_t	minor_version;
+	/* scale factor to change the user confidence thresholds */
+	uint16_t	user_sensitivity;
+	uint16_t	reserved;
+} __packed;
+
+struct lsm_params_payload {
+	struct lsm_param_connect_to_port connect_to_port;
+	struct lsm_param_op_mode	op_mode;
+	struct lsm_param_kw_detect_sensitivity kwds;
+	struct lsm_param_user_detect_sensitivity uds;
+} __packed;
+
+struct lsm_cmd_set_params {
+	struct apr_hdr  hdr;
+	uint32_t	data_payload_size;
+	uint32_t	data_payload_addr_lsw;
+	uint32_t	data_payload_addr_msw;
+	uint32_t	mem_map_handle;
+	struct lsm_params_payload payload;
+} __packed;
+
+struct lsm_cmd_reg_snd_model {
+	struct apr_hdr	hdr;
+	uint32_t	model_size;
+	uint32_t	model_addr_lsw;
+	uint32_t	model_addr_msw;
+	uint32_t	mem_map_handle;
+} __packed;
+
+struct lsm_client *q6lsm_client_alloc(app_cb cb, void *priv);
+void q6lsm_client_free(struct lsm_client *client);
+int q6lsm_open(struct lsm_client *client);
+int q6lsm_start(struct lsm_client *client, bool wait);
+int q6lsm_stop(struct lsm_client *client, bool wait);
+int q6lsm_snd_model_buf_alloc(struct lsm_client *client, uint32_t len);
+int q6lsm_close(struct lsm_client *client);
+int q6lsm_register_sound_model(struct lsm_client *client,
+			       enum lsm_detection_mode mode, u16 minkeyword,
+			       u16 minuser, bool detectfailure);
+int q6lsm_deregister_sound_model(struct lsm_client *client);
+
+#endif /* __Q6LSM_H__ */
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 4636247..7403b40 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -1534,6 +1534,20 @@
 	err = substream->ops->ioctl(substream, cmd, arg);
 	return err;
 }
+
+static int snd_user_ioctl(struct snd_pcm_substream *substream,
+			  unsigned int cmd, void __user *arg)
+{
+	struct snd_pcm_runtime *runtime;
+	int err = 0;
+
+	if (PCM_RUNTIME_CHECK(substream))
+		return -ENXIO;
+	runtime = substream->runtime;
+	err = substream->ops->ioctl(substream, cmd, arg);
+	return err;
+}
+
 /*
  * drop ioctl
  *
@@ -2605,6 +2619,9 @@
 	case SNDRV_COMPRESS_TSTAMP:
 	case SNDRV_COMPRESS_DRAIN:
 		return snd_compressed_ioctl(substream, cmd, arg);
+	default:
+		if (((cmd >> 8) & 0xff) == 'U')
+			return snd_user_ioctl(substream, cmd, arg);
 	}
 	snd_printd("unknown ioctl = 0x%x\n", cmd);
 	return -ENOTTY;
@@ -2788,10 +2805,12 @@
 				  unsigned long arg)
 {
 	struct snd_pcm_file *pcm_file;
+	unsigned char ioctl_magic;
 
 	pcm_file = file->private_data;
+	ioctl_magic = ((cmd >> 8) & 0xff);
 
-	if ((((cmd >> 8) & 0xff) != 'A') && (((cmd >> 8) & 0xff) != 'C'))
+	if (ioctl_magic != 'A' && ioctl_magic != 'C' && ioctl_magic != 'U')
 		return -ENOTTY;
 
 	return snd_pcm_capture_ioctl1(file, pcm_file->substream, cmd,
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 0c10548..78d1749 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -38,6 +38,9 @@
 #include "wcd9xxx-resmgr.h"
 #include "wcd9xxx-common.h"
 
+#define TAIKO_MAD_SLIMBUS_TX_PORT 12
+#define TAIKO_MAD_AUDIO_FIRMWARE_PATH "wcd9320/wcd9320_mad_audio.bin"
+
 static atomic_t kp_taiko_priv;
 static int spkr_drv_wrnd_param_set(const char *val,
 				   const struct kernel_param *kp);
@@ -47,6 +50,121 @@
 	.set = spkr_drv_wrnd_param_set,
 	.get = param_get_int,
 };
+
+static struct afe_param_slimbus_slave_port_cfg taiko_slimbus_slave_port_cfg = {
+	.minor_version = 1,
+	.slimbus_dev_id = AFE_SLIMBUS_DEVICE_1,
+	.slave_dev_pgd_la = 0,
+	.slave_dev_intfdev_la = 0,
+	.bit_width = 16,
+	.data_format = 0,
+	.num_channels = 1
+};
+
+enum {
+	RESERVED = 0,
+	AANC_LPF_FF_FB = 1,
+	AANC_LPF_COEFF_MSB,
+	AANC_LPF_COEFF_LSB,
+	HW_MAD_AUDIO_ENABLE,
+	HW_MAD_ULTR_ENABLE,
+	HW_MAD_BEACON_ENABLE,
+	HW_MAD_AUDIO_SLEEP_TIME,
+	HW_MAD_ULTR_SLEEP_TIME,
+	HW_MAD_BEACON_SLEEP_TIME,
+	HW_MAD_TX_AUDIO_SWITCH_OFF,
+	HW_MAD_TX_ULTR_SWITCH_OFF,
+	HW_MAD_TX_BEACON_SWITCH_OFF,
+	MAD_AUDIO_INT_DEST_SELECT_REG,
+	MAD_ULT_INT_DEST_SELECT_REG,
+	MAD_BEACON_INT_DEST_SELECT_REG,
+	MAD_CLIP_INT_DEST_SELECT_REG,
+	MAD_VBAT_INT_DEST_SELECT_REG,
+	MAD_AUDIO_INT_MASK_REG,
+	MAD_ULT_INT_MASK_REG,
+	MAD_BEACON_INT_MASK_REG,
+	MAD_CLIP_INT_MASK_REG,
+	MAD_VBAT_INT_MASK_REG,
+	MAD_AUDIO_INT_STATUS_REG,
+	MAD_ULT_INT_STATUS_REG,
+	MAD_BEACON_INT_STATUS_REG,
+	MAD_CLIP_INT_STATUS_REG,
+	MAD_VBAT_INT_STATUS_REG,
+	MAD_AUDIO_INT_CLEAR_REG,
+	MAD_ULT_INT_CLEAR_REG,
+	MAD_BEACON_INT_CLEAR_REG,
+	MAD_CLIP_INT_CLEAR_REG,
+	MAD_VBAT_INT_CLEAR_REG,
+	SB_PGD_PORT_TX_WATERMARK_n,
+	SB_PGD_PORT_TX_ENABLE_n,
+	SB_PGD_PORT_RX_WATERMARK_n,
+	SB_PGD_PORT_RX_ENABLE_n,
+	MAX_CFG_REGISTERS,
+};
+
+static struct afe_param_cdc_reg_cfg mad_audio_reg_cfg[] = {
+	{
+		1,
+		(TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_MAD_MAIN_CTL_1),
+		HW_MAD_AUDIO_ENABLE, 0x1, 8, 0
+	},
+	{
+		1,
+		(TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_MAD_AUDIO_CTL_3),
+		HW_MAD_AUDIO_SLEEP_TIME, 0xF, 8, 0
+	},
+	{
+		1,
+		(TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_MAD_AUDIO_CTL_4),
+		HW_MAD_TX_AUDIO_SWITCH_OFF, 0x1, 8, 0
+	},
+	{
+		1,
+		(TAIKO_REGISTER_START_OFFSET + TAIKO_A_INTR_DESTN3),
+		MAD_AUDIO_INT_DEST_SELECT_REG, 0x1, 8, 0
+	},
+	{
+		1,
+		(TAIKO_REGISTER_START_OFFSET + TAIKO_A_INTR_MASK3),
+		MAD_AUDIO_INT_MASK_REG, 0x1, 8, 0
+	},
+	{
+		1,
+		(TAIKO_REGISTER_START_OFFSET + TAIKO_A_INTR_STATUS3),
+		MAD_AUDIO_INT_STATUS_REG, 0x1, 8, 0
+	},
+	{
+		1,
+		(TAIKO_REGISTER_START_OFFSET + TAIKO_A_INTR_CLEAR3),
+		MAD_AUDIO_INT_CLEAR_REG, 0x1, 8, 0
+	},
+	{
+		1,
+		(TAIKO_REGISTER_START_OFFSET + TAIKO_SB_PGD_PORT_TX_BASE),
+		SB_PGD_PORT_TX_WATERMARK_n, 0x1E, 8, 0x1
+	},
+	{
+		1,
+		(TAIKO_REGISTER_START_OFFSET + TAIKO_SB_PGD_PORT_TX_BASE),
+		SB_PGD_PORT_TX_ENABLE_n, 0x1, 8, 0x1
+	},
+	{
+		1,
+		(TAIKO_REGISTER_START_OFFSET + TAIKO_SB_PGD_PORT_RX_BASE),
+		SB_PGD_PORT_RX_WATERMARK_n, 0x1E, 8, 0x1
+	},
+	{
+		1,
+		(TAIKO_REGISTER_START_OFFSET + TAIKO_SB_PGD_PORT_RX_BASE),
+		SB_PGD_PORT_RX_ENABLE_n, 0x1, 8, 0x1
+	}
+};
+
+static struct afe_param_cdc_reg_cfg_data taiko_mad_audio_reg_cfg = {
+	.num_registers = ARRAY_SIZE(mad_audio_reg_cfg),
+	.reg_data = mad_audio_reg_cfg,
+};
+
 module_param_cb(spkr_drv_wrnd, &spkr_drv_wrnd_param_ops, &spkr_drv_wrnd, 0644);
 MODULE_PARM_DESC(spkr_drv_wrnd,
 	       "Run software workaround to avoid leakage on the speaker drive");
@@ -84,6 +202,7 @@
 	AIF3_PB,
 	AIF3_CAP,
 	AIF4_VIFEED,
+	AIF4_MAD_TX,
 	NUM_CODEC_DAIS,
 };
 
@@ -237,6 +356,8 @@
 
 	bool spkr_pa_widget_on;
 
+	struct afe_param_cdc_slimbus_slave_cfg slimbus_slave_cfg;
+
 	/* resmgr module */
 	struct wcd9xxx_resmgr resmgr;
 	/* mbhc module */
@@ -1555,6 +1676,9 @@
 static const struct snd_kcontrol_new lineout4_ground_switch =
 	SOC_DAPM_SINGLE("Switch", TAIKO_A_RX_LINE_4_DAC_CTL, 6, 1, 0);
 
+static const struct snd_kcontrol_new aif4_mad_switch =
+	SOC_DAPM_SINGLE("Switch", TAIKO_A_CDC_CLK_OTHR_CTL, 4, 1, 0);
+
 /* virtual port entries */
 static int slim_tx_mixer_get(struct snd_kcontrol *kcontrol,
 			     struct snd_ctl_elem_value *ucontrol)
@@ -2155,6 +2279,108 @@
 	return 0;
 }
 
+static int taiko_codec_config_mad(struct snd_soc_codec *codec)
+{
+	int ret;
+	const struct firmware *fw;
+	struct mad_audio_cal *mad_cal;
+	const char *filename = TAIKO_MAD_AUDIO_FIRMWARE_PATH;
+
+	pr_debug("%s: enter\n", __func__);
+	ret = request_firmware(&fw, filename, codec->dev);
+	if (ret != 0) {
+		pr_err("Failed to acquire MAD firwmare data %s: %d\n", filename,
+		       ret);
+		return -ENODEV;
+	}
+
+	if (fw->size < sizeof(struct mad_audio_cal)) {
+		pr_err("%s: incorrect firmware size %u\n", __func__, fw->size);
+		release_firmware(fw);
+		return -ENOMEM;
+	}
+
+	mad_cal = (struct mad_audio_cal *)(fw->data);
+	if (!mad_cal) {
+		pr_err("%s: Invalid calibration data\n", __func__);
+		release_firmware(fw);
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(codec, TAIKO_A_CDC_CONN_MAD,
+			    0x0F, mad_cal->microphone_info.input_microphone);
+	snd_soc_write(codec, TAIKO_A_CDC_MAD_MAIN_CTL_2,
+		      mad_cal->microphone_info.cycle_time);
+	snd_soc_update_bits(codec, TAIKO_A_CDC_MAD_MAIN_CTL_1, 0xFF << 3,
+			    ((uint16_t)mad_cal->microphone_info.settle_time)
+			    << 3);
+
+	/* Audio */
+	snd_soc_write(codec, TAIKO_A_CDC_MAD_AUDIO_CTL_8,
+		      mad_cal->audio_info.rms_omit_samples);
+	snd_soc_update_bits(codec, TAIKO_A_CDC_MAD_AUDIO_CTL_1,
+			    0x07 << 4, mad_cal->audio_info.rms_comp_time << 4);
+	snd_soc_update_bits(codec, TAIKO_A_CDC_MAD_AUDIO_CTL_2, 0x03 << 2,
+			    mad_cal->audio_info.detection_mechanism << 2);
+	snd_soc_write(codec, TAIKO_A_CDC_MAD_AUDIO_CTL_7,
+		      mad_cal->audio_info.rms_diff_threshold & 0x3F);
+	snd_soc_write(codec, TAIKO_A_CDC_MAD_AUDIO_CTL_5,
+		      mad_cal->audio_info.rms_threshold_lsb);
+	snd_soc_write(codec, TAIKO_A_CDC_MAD_AUDIO_CTL_6,
+		      mad_cal->audio_info.rms_threshold_msb);
+
+
+	/* Beacon */
+	snd_soc_write(codec, TAIKO_A_CDC_MAD_BEACON_CTL_8,
+		      mad_cal->beacon_info.rms_omit_samples);
+	snd_soc_update_bits(codec, TAIKO_A_CDC_MAD_BEACON_CTL_1,
+			    0x07 << 4, mad_cal->beacon_info.rms_comp_time);
+	snd_soc_update_bits(codec, TAIKO_A_CDC_MAD_BEACON_CTL_2, 0x03 << 2,
+			    mad_cal->beacon_info.detection_mechanism << 2);
+	snd_soc_write(codec, TAIKO_A_CDC_MAD_BEACON_CTL_7,
+		      mad_cal->beacon_info.rms_diff_threshold & 0x1F);
+	snd_soc_write(codec, TAIKO_A_CDC_MAD_BEACON_CTL_5,
+		      mad_cal->beacon_info.rms_threshold_lsb);
+	snd_soc_write(codec, TAIKO_A_CDC_MAD_BEACON_CTL_6,
+		      mad_cal->beacon_info.rms_threshold_msb);
+
+	/* Ultrasound */
+	snd_soc_update_bits(codec, TAIKO_A_CDC_MAD_BEACON_CTL_1,
+			    0x07 << 4, mad_cal->beacon_info.rms_comp_time);
+	snd_soc_update_bits(codec, TAIKO_A_CDC_MAD_ULTR_CTL_2, 0x03 << 2,
+			    mad_cal->ultrasound_info.detection_mechanism);
+	snd_soc_write(codec, TAIKO_A_CDC_MAD_ULTR_CTL_7,
+		      mad_cal->ultrasound_info.rms_diff_threshold & 0x1F);
+	snd_soc_write(codec, TAIKO_A_CDC_MAD_ULTR_CTL_5,
+		      mad_cal->ultrasound_info.rms_threshold_lsb);
+	snd_soc_write(codec, TAIKO_A_CDC_MAD_ULTR_CTL_6,
+		      mad_cal->ultrasound_info.rms_threshold_msb);
+
+	release_firmware(fw);
+	pr_debug("%s: leave ret %d\n", __func__, ret);
+
+	return ret;
+}
+
+static int taiko_codec_enable_mad(struct snd_soc_dapm_widget *w,
+				  struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	int ret = 0;
+
+	pr_debug("%s %d\n", __func__, event);
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		ret = taiko_codec_config_mad(codec);
+		if (ret) {
+			pr_err("%s: Failed to config MAD\n", __func__);
+			break;
+		}
+		break;
+	}
+	return ret;
+}
+
 static int taiko_codec_enable_micbias(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
@@ -2674,6 +2900,11 @@
 	{"AIF3 CAP", NULL, "AIF3_CAP Mixer"},
 	{"AIF4 VI", NULL, "SPK_OUT"},
 
+	/* MAD */
+	{"AIF4 MAD", NULL, "CDC_CONN"},
+	{"MADONOFF", "Switch", "MADINPUT"},
+	{"AIF4 MAD", NULL, "MADONOFF"},
+
 	/* SLIM_MIXER("AIF1_CAP Mixer"),*/
 	{"AIF1_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
 	{"AIF1_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
@@ -3184,6 +3415,8 @@
 
 static int taiko_volatile(struct snd_soc_codec *ssc, unsigned int reg)
 {
+	int i;
+
 	/* Registers lower than 0x100 are top level registers which can be
 	 * written by the Taiko core driver.
 	 */
@@ -3222,6 +3455,11 @@
 		return 1;
 	}
 
+	for (i = 0; i < ARRAY_SIZE(mad_audio_reg_cfg); i++)
+		if (mad_audio_reg_cfg[i].reg_logical_addr -
+		    TAIKO_REGISTER_START_OFFSET == reg)
+			return 1;
+
 	return 0;
 }
 
@@ -3428,6 +3666,7 @@
 	case AIF2_CAP:
 	case AIF3_CAP:
 	case AIF4_VIFEED:
+	case AIF4_MAD_TX:
 		if (!tx_slot || !tx_num) {
 			pr_err("%s: Invalid tx_slot %d or tx_num %d\n",
 				 __func__, (u32) tx_slot, (u32) tx_num);
@@ -3858,6 +4097,20 @@
 	 },
 		.ops = &taiko_dai_ops,
 	},
+	{
+		.name = "taiko_mad1",
+		.id = AIF4_MAD_TX,
+		.capture = {
+			.stream_name = "AIF4 MAD TX",
+			.rates = SNDRV_PCM_RATE_16000,
+			.formats = TAIKO_FORMATS,
+			.rate_min = 16000,
+			.rate_max = 16000,
+			.channels_min = 1,
+			.channels_max = 1,
+		},
+		.ops = &taiko_dai_ops,
+	},
 };
 
 static struct snd_soc_dai_driver taiko_i2s_dai[] = {
@@ -4556,6 +4809,12 @@
 	SND_SOC_DAPM_AIF_OUT_E("AIF4 VI", "VIfeed", 0, SND_SOC_NOPM,
 		AIF4_VIFEED, 0, taiko_codec_enable_slimvi_feedback,
 		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_AIF_OUT_E("AIF4 MAD", "AIF4 MAD TX", 0,
+			       SND_SOC_NOPM, 0, 0,
+			       taiko_codec_enable_mad, SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_SWITCH("MADONOFF", SND_SOC_NOPM, 0, 0,
+			    &aif4_mad_switch),
+	SND_SOC_DAPM_INPUT("MADINPUT"),
 
 	SND_SOC_DAPM_MIXER("AIF1_CAP Mixer", SND_SOC_NOPM, AIF1_CAP, 0,
 		aif_cap_mixer, ARRAY_SIZE(aif_cap_mixer)),
@@ -4884,6 +5143,26 @@
 	TAIKO_REG_VAL(TAIKO_A_CDC_RX5_B6_CTL, 0x80),
 	TAIKO_REG_VAL(TAIKO_A_CDC_RX6_B6_CTL, 0x80),
 	TAIKO_REG_VAL(TAIKO_A_CDC_RX7_B6_CTL, 0x80),
+
+	/* MAD registers */
+	TAIKO_REG_VAL(TAIKO_A_MAD_ANA_CTRL, 0xF1),
+	TAIKO_REG_VAL(TAIKO_A_CDC_MAD_MAIN_CTL_1, 0x00),
+	TAIKO_REG_VAL(TAIKO_A_CDC_MAD_MAIN_CTL_2, 0x00),
+	TAIKO_REG_VAL(TAIKO_A_CDC_MAD_AUDIO_CTL_1, 0x00),
+	/* Set SAMPLE_TX_EN bit */
+	TAIKO_REG_VAL(TAIKO_A_CDC_MAD_AUDIO_CTL_2, 0x03),
+	TAIKO_REG_VAL(TAIKO_A_CDC_MAD_AUDIO_CTL_3, 0x00),
+	TAIKO_REG_VAL(TAIKO_A_CDC_MAD_AUDIO_CTL_4, 0x00),
+	TAIKO_REG_VAL(TAIKO_A_CDC_MAD_AUDIO_CTL_5, 0x00),
+	TAIKO_REG_VAL(TAIKO_A_CDC_MAD_AUDIO_CTL_6, 0x00),
+	TAIKO_REG_VAL(TAIKO_A_CDC_MAD_AUDIO_CTL_7, 0x00),
+	TAIKO_REG_VAL(TAIKO_A_CDC_MAD_AUDIO_CTL_8, 0x00),
+	TAIKO_REG_VAL(TAIKO_A_CDC_MAD_AUDIO_IIR_CTL_PTR, 0x00),
+	TAIKO_REG_VAL(TAIKO_A_CDC_MAD_AUDIO_IIR_CTL_VAL, 0x40),
+	TAIKO_REG_VAL(TAIKO_A_CDC_DEBUG_B7_CTL, 0x00),
+	TAIKO_REG_VAL(TAIKO_A_CDC_CLK_OTHR_RESET_B1_CTL, 0x00),
+	TAIKO_REG_VAL(TAIKO_A_CDC_CLK_OTHR_CTL, 0x00),
+	TAIKO_REG_VAL(TAIKO_A_CDC_CONN_MAD, 0x01),
 };
 
 static const struct wcd9xxx_reg_mask_val taiko_1_0_reg_defaults[] = {
@@ -5121,6 +5400,26 @@
 }
 EXPORT_SYMBOL_GPL(taiko_hs_detect);
 
+static void taiko_init_slim_slave_cfg(struct snd_soc_codec *codec)
+{
+	struct taiko_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct afe_param_cdc_slimbus_slave_cfg *cfg;
+	struct wcd9xxx *wcd9xxx = codec->control_data;
+	uint64_t eaddr = 0;
+
+	cfg = &priv->slimbus_slave_cfg;
+	cfg->minor_version = 1;
+	cfg->tx_slave_port_offset = 0;
+	cfg->rx_slave_port_offset = 16;
+
+	memcpy(&eaddr, &wcd9xxx->slim->e_addr, sizeof(wcd9xxx->slim->e_addr));
+	WARN_ON(sizeof(wcd9xxx->slim->e_addr) != 6);
+	cfg->device_enum_addr_lsw = eaddr & 0xFFFFFFFF;
+	cfg->device_enum_addr_msw = eaddr >> 32;
+
+	pr_debug("%s: slimbus logical address 0x%llx\n", __func__, eaddr);
+}
+
 static int taiko_post_reset_cb(struct wcd9xxx *wcd9xxx)
 {
 	int ret = 0;
@@ -5150,6 +5449,8 @@
 	if (IS_ERR_VALUE(ret))
 		pr_err("%s: bad pdata\n", __func__);
 
+	taiko_init_slim_slave_cfg(codec);
+
 	wcd9xxx_mbhc_deinit(&taiko->mbhc);
 	ret = wcd9xxx_mbhc_init(&taiko->mbhc, &taiko->resmgr, codec);
 	if (ret)
@@ -5160,6 +5461,23 @@
 	return ret;
 }
 
+void *taiko_get_afe_config(struct snd_soc_codec *codec,
+			   enum afe_config_type config_type)
+{
+	struct taiko_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+	switch (config_type) {
+	case AFE_SLIMBUS_SLAVE_CONFIG:
+		return &priv->slimbus_slave_cfg;
+	case AFE_CDC_REGISTERS_CONFIG:
+		return &taiko_mad_audio_reg_cfg;
+	case AFE_SLIMBUS_SLAVE_PORT_CONFIG:
+		return &taiko_slimbus_slave_port_cfg;
+	default:
+		pr_err("%s: Unknown config_type 0x%x\n", __func__, config_type);
+		return NULL;
+	}
+}
 
 static struct wcd9xxx_reg_address taiko_reg_address = {
 	.micb_4_mbhc = TAIKO_A_MICB_4_MBHC,
@@ -5353,6 +5671,14 @@
 			INIT_LIST_HEAD(&taiko->dai[i].wcd9xxx_ch_list);
 			init_waitqueue_head(&taiko->dai[i].dai_wait);
 		}
+		taiko_slimbus_slave_port_cfg.slave_dev_intfdev_la =
+		    control->slim_slave->laddr;
+		taiko_slimbus_slave_port_cfg.slave_dev_pgd_la =
+		    control->slim->laddr;
+		taiko_slimbus_slave_port_cfg.slave_port_mapping[0] =
+		    TAIKO_MAD_SLIMBUS_TX_PORT;
+
+		taiko_init_slim_slave_cfg(codec);
 	}
 
 	if (TAIKO_IS_1_0(control->version))
diff --git a/sound/soc/codecs/wcd9320.h b/sound/soc/codecs/wcd9320.h
index 89a0b9f..36310e5 100644
--- a/sound/soc/codecs/wcd9320.h
+++ b/sound/soc/codecs/wcd9320.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
@@ -14,6 +14,7 @@
 
 #include <sound/soc.h>
 #include <sound/jack.h>
+#include <sound/apr_audio-v2.h>
 #include <linux/mfd/wcd9xxx/wcd9xxx-slimslave.h>
 #include "wcd9xxx-mbhc.h"
 #include "wcd9xxx-resmgr.h"
@@ -25,6 +26,10 @@
 #define TAIKO_REG_VAL(reg, val)		{reg, 0, val}
 #define TAIKO_MCLK_ID 0
 
+#define TAIKO_REGISTER_START_OFFSET 0x800
+#define TAIKO_SB_PGD_PORT_RX_BASE   0x40
+#define TAIKO_SB_PGD_PORT_TX_BASE   0x50
+
 extern const u8 taiko_reg_readable[TAIKO_CACHE_SIZE];
 extern const u8 taiko_reset_reg_defaults[TAIKO_CACHE_SIZE];
 struct taiko_codec_dai_data {
@@ -90,9 +95,62 @@
 	u32 num_anc_slots;
 };
 
+struct mad_audio_header {
+	u32 reserved[3];
+	u32 num_reg_cfg;
+};
+
+struct mad_microphone_info {
+	uint8_t input_microphone;
+	uint8_t cycle_time;
+	uint8_t settle_time;
+	uint8_t padding;
+} __packed;
+
+struct mad_micbias_info {
+	uint8_t micbias;
+	uint8_t k_factor;
+	uint8_t external_bypass_capacitor;
+	uint8_t internal_biasing;
+	uint8_t cfilter;
+	uint8_t padding[3];
+} __packed;
+
+struct mad_rms_audio_beacon_info {
+	uint8_t rms_omit_samples;
+	uint8_t rms_comp_time;
+	uint8_t detection_mechanism;
+	uint8_t rms_diff_threshold;
+	uint8_t rms_threshold_lsb;
+	uint8_t rms_threshold_msb;
+	uint8_t padding[2];
+	uint8_t iir_coefficients[36];
+} __packed;
+
+struct mad_rms_ultrasound_info {
+	uint8_t rms_comp_time;
+	uint8_t detection_mechanism;
+	uint8_t rms_diff_threshold;
+	uint8_t rms_threshold_lsb;
+	uint8_t rms_threshold_msb;
+	uint8_t padding[3];
+	uint8_t iir_coefficients[36];
+} __packed;
+
+struct mad_audio_cal {
+	uint32_t version;
+	struct mad_microphone_info microphone_info;
+	struct mad_micbias_info micbias_info;
+	struct mad_rms_audio_beacon_info audio_info;
+	struct mad_rms_audio_beacon_info beacon_info;
+	struct mad_rms_ultrasound_info ultrasound_info;
+} __packed;
+
 extern int taiko_mclk_enable(struct snd_soc_codec *codec, int mclk_enable,
 			     bool dapm);
 extern int taiko_hs_detect(struct snd_soc_codec *codec,
 			   struct wcd9xxx_mbhc_config *mbhc_cfg);
+extern void *taiko_get_afe_config(struct snd_soc_codec *codec,
+				  enum afe_config_type config_type);
 
 #endif
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 96709be..e00e409 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -612,6 +612,20 @@
 		.ops = &msm_fe_dai_ops,
 		.name = "DTMF_RX_HOSTLESS",
 	},
+	{
+		.capture = {
+			.stream_name = "Listen Audio Service Capture",
+			.aif_name = "LSM_UL_HL",
+			.rates = SNDRV_PCM_RATE_16000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.channels_min = 1,
+			.channels_max = 1,
+			.rate_min = 16000,
+			.rate_max = 16000,
+		},
+		.ops = &msm_fe_dai_ops,
+		.name = "LSM",
+	},
 };
 
 static __devinit int msm_fe_dai_dev_probe(struct platform_device *pdev)
diff --git a/sound/soc/msm/msm8226.c b/sound/soc/msm/msm8226.c
index 235b527..328e287 100644
--- a/sound/soc/msm/msm8226.c
+++ b/sound/soc/msm/msm8226.c
@@ -982,6 +982,45 @@
 		.ops = &msm8226_be_ops,
 		.ignore_suspend = 1,
 	},
+	/* Incall Record Uplink BACK END DAI Link */
+	{
+		.name = LPASS_BE_INCALL_RECORD_TX,
+		.stream_name = "Voice Uplink Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.32772",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_INCALL_RECORD_TX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ignore_suspend = 1,
+	},
+	/* Incall Record Downlink BACK END DAI Link */
+	{
+		.name = LPASS_BE_INCALL_RECORD_RX,
+		.stream_name = "Voice Downlink Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.32771",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_INCALL_RECORD_RX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ignore_suspend = 1,
+	},
+	/* Incall Music BACK END DAI Link */
+	{
+		.name = LPASS_BE_VOICE_PLAYBACK_TX,
+		.stream_name = "Voice Farend Playback",
+		.cpu_dai_name = "msm-dai-q6-dev.32773",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ignore_suspend = 1,
+	},
 };
 
 struct snd_soc_card snd_soc_card_msm8226 = {
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 747e027..0dbe3f7 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -24,6 +24,7 @@
 #include <sound/soc-dapm.h>
 #include <sound/pcm.h>
 #include <sound/jack.h>
+#include <sound/q6afe-v2.h>
 #include <asm/mach-types.h>
 #include <mach/socinfo.h>
 #include <sound/pcm_params.h>
@@ -1003,6 +1004,33 @@
 	return 0;
 }
 
+static int msm_slim_5_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+					    struct snd_pcm_hw_params *params)
+{
+	int rc;
+	void *config;
+	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_interval *rate =
+	    hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+	struct snd_interval *channels =
+	    hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	pr_debug("%s enter\n", __func__);
+	rate->min = rate->max = 16000;
+	channels->min = channels->max = 1;
+
+	config = taiko_get_afe_config(codec, AFE_SLIMBUS_SLAVE_PORT_CONFIG);
+	rc = afe_set_config(AFE_SLIMBUS_SLAVE_PORT_CONFIG, config,
+			    SLIMBUS_5_TX);
+	if (rc) {
+		pr_err("%s: Failed to set slimbus slave port config %d\n",
+		       __func__, rc);
+		return rc;
+	}
+
+	return 0;
+}
+
 static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 				struct snd_pcm_hw_params *params)
 {
@@ -1054,6 +1082,7 @@
 static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
 {
 	int err;
+	void *config_data;
 	struct snd_soc_codec *codec = rtd->codec;
 	struct snd_soc_dapm_context *dapm = &codec->dapm;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
@@ -1108,6 +1137,23 @@
 	snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch),
 				    tx_ch, ARRAY_SIZE(rx_ch), rx_ch);
 
+
+	config_data = taiko_get_afe_config(codec, AFE_CDC_REGISTERS_CONFIG);
+	err = afe_set_config(AFE_CDC_REGISTERS_CONFIG, config_data, 0);
+	if (err) {
+		pr_err("%s: Failed to set codec registers config %d\n",
+		       __func__, err);
+		return err;
+	}
+
+	config_data = taiko_get_afe_config(codec, AFE_SLIMBUS_SLAVE_CONFIG);
+	err = afe_set_config(AFE_SLIMBUS_SLAVE_CONFIG, config_data, 0);
+	if (err) {
+		pr_err("%s: Failed to set slimbus slave config %d\n", __func__,
+		       err);
+		return err;
+	}
+
 	/* start mbhc */
 	mbhc_cfg.calibration = def_taiko_mbhc_cal();
 	if (mbhc_cfg.calibration)
@@ -1574,6 +1620,22 @@
 		.ignore_pmdown_time = 1,
 		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA5,
 	},
+	/* LSM FE */
+	{
+		.name = "Listen Audio Service",
+		.stream_name = "Listen Audio Service",
+		.cpu_dai_name = "LSM",
+		.platform_name = "msm-lsm-client",
+		.dynamic = 1,
+		.trigger = { SND_SOC_DPCM_TRIGGER_POST,
+			     SND_SOC_DPCM_TRIGGER_POST },
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.be_id = MSM_FRONTEND_DAI_LSM1,
+	},
 	/* Backend BT/FM DAI Links */
 	{
 		.name = LPASS_BE_INT_BT_SCO_RX,
@@ -1837,6 +1899,19 @@
 		.be_hw_params_fixup = msm_be_hw_params_fixup,
 		.ignore_suspend = 1,
 	},
+	/* MAD BE */
+	{
+		.name = LPASS_BE_SLIMBUS_5_TX,
+		.stream_name = "Slimbus5 Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.16395",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "taiko_codec",
+		.codec_dai_name = "taiko_mad1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_5_TX,
+		.be_hw_params_fixup = msm_slim_5_tx_be_hw_params_fixup,
+		.ops = &msm8974_be_ops,
+	},
 	/* Incall Music BACK END DAI Link */
 	{
 		.name = LPASS_BE_VOICE_PLAYBACK_TX,
diff --git a/sound/soc/msm/qdsp6v2/Makefile b/sound/soc/msm/qdsp6v2/Makefile
index 69c0976..391b3da 100644
--- a/sound/soc/msm/qdsp6v2/Makefile
+++ b/sound/soc/msm/qdsp6v2/Makefile
@@ -1,6 +1,11 @@
-snd-soc-qdsp6v2-objs += msm-dai-q6-v2.o msm-pcm-q6-v2.o msm-pcm-routing-v2.o msm-compr-q6-v2.o  msm-multi-ch-pcm-q6-v2.o
-snd-soc-qdsp6v2-objs += msm-pcm-lpa-v2.o msm-pcm-afe-v2.o msm-pcm-voip-v2.o msm-pcm-voice-v2.o msm-dai-q6-hdmi-v2.o
-obj-$(CONFIG_SND_SOC_QDSP6V2) += snd-soc-qdsp6v2.o msm-pcm-dtmf-v2.o msm-dai-stub-v2.o
-obj-y += q6adm.o q6afe.o q6asm.o q6audio-v2.o q6voice.o q6core.o audio_acdb.o rtac.o
+snd-soc-qdsp6v2-objs += msm-dai-q6-v2.o msm-pcm-q6-v2.o msm-pcm-routing-v2.o \
+			msm-compr-q6-v2.o msm-multi-ch-pcm-q6-v2.o \
+			msm-pcm-lpa-v2.o msm-pcm-afe-v2.o msm-pcm-voip-v2.o \
+			msm-pcm-voice-v2.o msm-dai-q6-hdmi-v2.o \
+			msm-lsm-client.o
+obj-$(CONFIG_SND_SOC_QDSP6V2) += snd-soc-qdsp6v2.o msm-pcm-dtmf-v2.o \
+				 msm-dai-stub-v2.o
+obj-y += q6adm.o q6afe.o q6asm.o q6audio-v2.o q6voice.o q6core.o audio_acdb.o \
+	 rtac.o q6lsm.o
 ocmem-audio-objs += audio_ocmem.o
 obj-$(CONFIG_AUDIO_OCMEM) += ocmem-audio.o
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index 557ec65..916be0b 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -701,6 +701,7 @@
 	case SLIMBUS_2_TX:
 	case SLIMBUS_3_TX:
 	case SLIMBUS_4_TX:
+	case SLIMBUS_5_TX:
 		rc = msm_dai_q6_slim_bus_hw_params(params, dai,
 				substream->stream);
 		break;
@@ -831,6 +832,7 @@
 	case SLIMBUS_2_TX:
 	case SLIMBUS_3_TX:
 	case SLIMBUS_4_TX:
+	case SLIMBUS_5_TX:
 		/*
 		 * channel number to be between 128 and 255.
 		 * For TX port use channel numbers
@@ -1980,6 +1982,7 @@
 		break;
 	case SLIMBUS_0_TX:
 	case SLIMBUS_2_TX:
+	case SLIMBUS_5_TX:
 		rc = snd_soc_register_dai(&pdev->dev,
 					  &msm_dai_q6_slimbus_tx_dai);
 		break;
diff --git a/sound/soc/msm/qdsp6v2/msm-lsm-client.c b/sound/soc/msm/qdsp6v2/msm-lsm-client.c
new file mode 100644
index 0000000..ea6f390
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-lsm-client.c
@@ -0,0 +1,370 @@
+/*
+ * Copyright (c) 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
+ * 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 <linux/dma-mapping.h>
+#include <linux/android_pmem.h>
+#include <linux/of.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/timer.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <sound/q6lsm.h>
+#include <sound/lsm_params.h>
+#include "msm-pcm-routing-v2.h"
+
+struct lsm_priv {
+	struct snd_pcm_substream *substream;
+	struct lsm_client *lsm_client;
+
+	struct snd_lsm_event_status *event_status;
+	spinlock_t event_lock;
+	wait_queue_head_t event_wait;
+	unsigned long event_avail;
+	atomic_t event_wait_stop;
+};
+
+static void lsm_event_handler(uint32_t opcode, uint32_t token,
+			      void *payload, void *priv)
+{
+	unsigned long flags;
+	struct snd_lsm_event_status *event_status;
+	struct lsm_priv *prtd = priv;
+	struct snd_pcm_substream *substream = prtd->substream;
+
+	pr_debug("%s: enter opcode 0x%x\n", __func__, opcode);
+	switch (opcode) {
+	case LSM_SESSION_EVENT_DETECTION_STATUS:
+		event_status = payload;
+
+		spin_lock_irqsave(&prtd->event_lock, flags);
+		prtd->event_status = krealloc(prtd->event_status,
+					      sizeof(*event_status) +
+					      event_status->payload_size,
+					      GFP_ATOMIC);
+		if (likely(prtd->event_status)) {
+			memcpy(prtd->event_status, event_status,
+			       sizeof(*event_status) +
+			       event_status->payload_size);
+			prtd->event_avail = 1;
+			spin_unlock_irqrestore(&prtd->event_lock, flags);
+			wake_up(&prtd->event_wait);
+		} else {
+			spin_unlock_irqrestore(&prtd->event_lock, flags);
+			pr_err("%s: Couldn't allocate %d bytes of memory\n",
+			       __func__, event_status->payload_size);
+		}
+		if (substream->timer_running)
+			snd_timer_interrupt(substream->timer, 1);
+		break;
+	default:
+		pr_debug("%s: Unsupported Event opcode 0x%x\n", __func__,
+			 opcode);
+		break;
+	}
+}
+
+static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
+			 unsigned int cmd, void *arg)
+{
+	unsigned long flags;
+	int ret;
+	struct snd_lsm_sound_model snd_model;
+	int rc = 0;
+	int xchg = 0;
+	int size = 0;
+	struct snd_lsm_event_status *event_status = NULL;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct lsm_priv *prtd = runtime->private_data;
+	struct snd_lsm_event_status *user = arg;
+
+	pr_debug("%s: enter cmd %x\n", __func__, cmd);
+	switch (cmd) {
+	case SNDRV_LSM_REG_SND_MODEL:
+		pr_debug("%s: Registering sound model\n", __func__);
+		if (copy_from_user(&snd_model, (void *)arg,
+				   sizeof(struct snd_lsm_sound_model))) {
+			rc = -EFAULT;
+			pr_err("%s: copy from user failed, size %d\n", __func__,
+			       sizeof(struct snd_lsm_sound_model));
+			break;
+		}
+
+		rc = q6lsm_snd_model_buf_alloc(prtd->lsm_client,
+					       snd_model.data_size);
+		if (rc) {
+			pr_err("%s: q6lsm buffer alloc failed, size %d\n",
+			       __func__, snd_model.data_size);
+			break;
+		}
+
+		if (copy_from_user(prtd->lsm_client->sound_model.data,
+				   snd_model.data, snd_model.data_size)) {
+			pr_err("%s: copy from user data failed size %d\n",
+			       __func__, snd_model.data_size);
+			rc = -EFAULT;
+			break;
+		}
+
+		rc = q6lsm_register_sound_model(prtd->lsm_client,
+						snd_model.detection_mode,
+						snd_model.min_keyw_confidence,
+						snd_model.min_user_confidence,
+						snd_model.detect_failure);
+		if (rc < 0)
+			pr_err("%s: q6lsm_register_sound_model failed =%d\n",
+			       __func__, rc);
+		break;
+
+	case SNDRV_LSM_DEREG_SND_MODEL:
+		pr_debug("%s: Deregistering sound model\n", __func__);
+		rc = q6lsm_deregister_sound_model(prtd->lsm_client);
+		break;
+
+	case SNDRV_LSM_EVENT_STATUS:
+		pr_debug("%s: Get event status\n", __func__);
+		atomic_set(&prtd->event_wait_stop, 0);
+		rc = wait_event_interruptible(prtd->event_wait,
+				(cmpxchg(&prtd->event_avail, 1, 0) ||
+				 (xchg = atomic_cmpxchg(&prtd->event_wait_stop,
+							1, 0))));
+		pr_debug("%s: wait_event_interruptible %d event_wait_stop %d\n",
+			 __func__, rc, xchg);
+		if (!rc && !xchg) {
+			pr_debug("%s: New event available %ld\n", __func__,
+				 prtd->event_avail);
+			spin_lock_irqsave(&prtd->event_lock, flags);
+			if (prtd->event_status) {
+				size = sizeof(*event_status) +
+				       prtd->event_status->payload_size;
+				event_status = kmemdup(prtd->event_status, size,
+						       GFP_ATOMIC);
+			}
+			spin_unlock_irqrestore(&prtd->event_lock, flags);
+			if (!event_status) {
+				pr_err("%s: Couldn't allocate %d bytes\n",
+				       __func__, size);
+				/*
+				 * Don't use -ENOMEM as userspace will check
+				 * it for increasing buffer
+				 */
+				rc = -EFAULT;
+			} else {
+				if (user->payload_size <
+				    event_status->payload_size) {
+					pr_debug("%s: provided %dbytes isn't enough, needs %dbytes\n",
+						 __func__, user->payload_size,
+						 size);
+					rc = -ENOMEM;
+				} else if (!access_ok(VERIFY_WRITE, arg,
+						      size)) {
+					rc = -EFAULT;
+				} else {
+					rc = copy_to_user(arg, event_status,
+							  size);
+					if (rc)
+						pr_err("%s: copy to user failed %d\n",
+						       __func__, rc);
+				}
+				kfree(event_status);
+			}
+		} else if (xchg) {
+			pr_debug("%s: Wait aborted\n", __func__);
+			rc = 0;
+		}
+		break;
+
+	case SNDRV_LSM_ABORT_EVENT:
+		pr_debug("%s: Aborting event status wait\n", __func__);
+		atomic_set(&prtd->event_wait_stop, 1);
+		wake_up(&prtd->event_wait);
+		break;
+
+	case SNDRV_LSM_START:
+		pr_debug("%s: Starting LSM client session\n", __func__);
+		if (!prtd->lsm_client->started) {
+			ret = q6lsm_start(prtd->lsm_client, true);
+			if (!ret) {
+				prtd->lsm_client->started = true;
+				pr_debug("%s: LSM client session started\n",
+					 __func__);
+			}
+		}
+		break;
+
+	case SNDRV_LSM_STOP:
+		pr_debug("%s: Stopping LSM client session\n", __func__);
+		if (prtd->lsm_client->started) {
+			ret = q6lsm_stop(prtd->lsm_client, true);
+			if (!ret) {
+				prtd->lsm_client->started = false;
+				pr_debug("%s: LSM client session stopped\n",
+					 __func__);
+			}
+		}
+		break;
+
+	default:
+		pr_debug("%s: Falling into default snd_lib_ioctl cmd 0x%x\n",
+			 __func__, cmd);
+		rc = snd_pcm_lib_ioctl(substream, cmd, arg);
+		break;
+	}
+
+	if (!rc)
+		pr_debug("%s: leave (%d)\n", __func__, rc);
+	else
+		pr_err("%s: cmd 0x%x failed %d\n", __func__, cmd, rc);
+
+	return rc;
+}
+
+static int msm_lsm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct lsm_priv *prtd;
+	int ret = 0;
+
+	pr_debug("%s\n", __func__);
+	prtd = kzalloc(sizeof(struct lsm_priv), GFP_KERNEL);
+	if (!prtd) {
+		pr_err("%s: Failed to allocate memory for lsm_priv\n",
+		       __func__);
+		return -ENOMEM;
+	}
+	prtd->substream = substream;
+	prtd->lsm_client = q6lsm_client_alloc((app_cb)lsm_event_handler, prtd);
+	if (!prtd->lsm_client) {
+		pr_err("%s: Could not allocate memory\n", __func__);
+		kfree(prtd);
+		return -ENOMEM;
+	}
+	ret = q6lsm_open(prtd->lsm_client);
+	if (ret < 0) {
+		pr_err("%s: lsm out open failed\n", __func__);
+		q6lsm_client_free(prtd->lsm_client);
+		kfree(prtd);
+		return -ENOMEM;
+	}
+
+	pr_debug("%s: Session ID %d\n", __func__, prtd->lsm_client->session);
+	prtd->lsm_client->started = false;
+	spin_lock_init(&prtd->event_lock);
+	init_waitqueue_head(&prtd->event_wait);
+	runtime->private_data = prtd;
+
+	return 0;
+}
+
+static int msm_lsm_close(struct snd_pcm_substream *substream)
+{
+	unsigned long flags;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct lsm_priv *prtd = runtime->private_data;
+
+	pr_debug("%s\n", __func__);
+
+	q6lsm_close(prtd->lsm_client);
+	q6lsm_client_free(prtd->lsm_client);
+
+	spin_lock_irqsave(&prtd->event_lock, flags);
+	kfree(prtd->event_status);
+	prtd->event_status = NULL;
+	spin_unlock_irqrestore(&prtd->event_lock, flags);
+	kfree(prtd);
+
+	return 0;
+}
+
+static struct snd_pcm_ops msm_lsm_ops = {
+	.open           = msm_lsm_open,
+	.close          = msm_lsm_close,
+	.ioctl          = msm_lsm_ioctl,
+};
+
+static int msm_asoc_lsm_new(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_card *card = rtd->card->snd_card;
+
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+	return 0;
+}
+
+static int msm_asoc_lsm_probe(struct snd_soc_platform *platform)
+{
+	pr_debug("enter %s\n", __func__);
+
+	return 0;
+}
+
+static struct snd_soc_platform_driver msm_soc_platform = {
+	.ops		= &msm_lsm_ops,
+	.pcm_new	= msm_asoc_lsm_new,
+	.probe		= msm_asoc_lsm_probe,
+};
+
+static __devinit int msm_lsm_probe(struct platform_device *pdev)
+{
+	if (pdev->dev.of_node)
+		dev_set_name(&pdev->dev, "%s", "msm-lsm-client");
+
+	return snd_soc_register_platform(&pdev->dev, &msm_soc_platform);
+}
+
+static int msm_lsm_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_platform(&pdev->dev);
+
+	return 0;
+}
+
+static const struct of_device_id msm_lsm_client_dt_match[] = {
+	{.compatible = "qcom,msm-lsm-client" },
+	{ }
+};
+
+static struct platform_driver msm_lsm_driver = {
+	.driver = {
+		.name = "msm-lsm-client",
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(msm_lsm_client_dt_match),
+	},
+	.probe = msm_lsm_probe,
+	.remove = __devexit_p(msm_lsm_remove),
+};
+
+static int __init msm_soc_platform_init(void)
+{
+	return platform_driver_register(&msm_lsm_driver);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+	platform_driver_unregister(&msm_lsm_driver);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("LSM client platform driver");
+MODULE_DEVICE_TABLE(of, msm_lsm_client_dt_match);
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 9fe438c..819512d 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -55,6 +55,27 @@
 static int fm_switch_enable;
 static int fm_pcmrx_switch_enable;
 static int srs_alsa_ctrl_ever_called;
+static int lsm_mux_slim_port;
+
+enum {
+	MADNONE,
+	MADAUDIO,
+	MADBEACON,
+	MADULTRASOUND
+};
+
+#define SLIMBUS_0_TX_TEXT "SLIMBUS_0_TX"
+#define SLIMBUS_1_TX_TEXT "SLIMBUS_1_TX"
+#define SLIMBUS_2_TX_TEXT "SLIMBUS_2_TX"
+#define SLIMBUS_3_TX_TEXT "SLIMBUS_3_TX"
+#define SLIMBUS_4_TX_TEXT "SLIMBUS_4_TX"
+#define SLIMBUS_5_TX_TEXT "SLIMBUS_5_TX"
+#define LSM_FUNCTION_TEXT "LSM Function"
+static const char * const mad_audio_mux_text[] = {
+	"None",
+	SLIMBUS_0_TX_TEXT, SLIMBUS_1_TX_TEXT, SLIMBUS_2_TX_TEXT,
+	SLIMBUS_3_TX_TEXT, SLIMBUS_4_TX_TEXT, SLIMBUS_5_TX_TEXT
+};
 
 #define INT_RX_VOL_MAX_STEPS 0x2000
 #define INT_RX_VOL_GAIN 0x2000
@@ -190,6 +211,7 @@
 	{ SLIMBUS_4_TX, 0, 0, 0, 0, 0},
 	{ SLIMBUS_3_RX, 0, 0, 0, 0, 0},
 	{ SLIMBUS_3_TX, 0, 0, 0, 0, 0},
+	{ SLIMBUS_5_TX, 0, 0, 0, 0, 0 },
 	{ SLIMBUS_EXTPROC_RX, 0, 0, 0, 0, 0},
 	{ SLIMBUS_EXTPROC_RX, 0, 0, 0, 0, 0},
 	{ SLIMBUS_EXTPROC_RX, 0, 0, 0, 0, 0},
@@ -731,6 +753,118 @@
 	return 1;
 }
 
+static int msm_routing_lsm_mux_get(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = lsm_mux_slim_port;
+	return 0;
+}
+
+static int msm_routing_lsm_mux_put(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	int mux = ucontrol->value.enumerated.item[0];
+
+	pr_debug("%s: LSM enable %ld\n", __func__,
+		 ucontrol->value.integer.value[0]);
+	if (ucontrol->value.integer.value[0]) {
+		lsm_mux_slim_port = ucontrol->value.integer.value[0];
+		snd_soc_dapm_mux_update_power(widget, kcontrol, 1, mux, e);
+	} else {
+		snd_soc_dapm_mux_update_power(widget, kcontrol, 1, mux, e);
+		lsm_mux_slim_port = ucontrol->value.integer.value[0];
+	}
+
+	return 0;
+}
+
+static int msm_routing_lsm_func_get(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	int i;
+	u16 port_id;
+	enum afe_mad_type mad_type;
+
+	pr_debug("%s: enter\n", __func__);
+	for (i = 0; i < ARRAY_SIZE(mad_audio_mux_text); i++)
+		if (!strncmp(kcontrol->id.name, mad_audio_mux_text[i],
+			    strlen(mad_audio_mux_text[i])))
+			break;
+
+	if (i-- == ARRAY_SIZE(mad_audio_mux_text)) {
+		WARN(1, "Invalid id name %s\n", kcontrol->id.name);
+		return -EINVAL;
+	}
+
+	port_id = i * 2 + 1 + SLIMBUS_0_RX;
+	mad_type = afe_port_get_mad_type(port_id);
+	pr_debug("%s: port_id 0x%x, mad_type %d\n", __func__, port_id,
+		 mad_type);
+	switch (mad_type) {
+	case MAD_HW_NONE:
+		ucontrol->value.integer.value[0] = MADNONE;
+		break;
+	case MAD_HW_AUDIO:
+		ucontrol->value.integer.value[0] = MADAUDIO;
+		break;
+	case MAD_HW_BEACON:
+		ucontrol->value.integer.value[0] = MADBEACON;
+		break;
+	case MAD_HW_ULTRASOUND:
+		ucontrol->value.integer.value[0] = MADULTRASOUND;
+		break;
+	default:
+		WARN(1, "Unknown\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int msm_routing_lsm_func_put(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	int i;
+	u16 port_id;
+	enum afe_mad_type mad_type;
+
+	pr_debug("%s: enter\n", __func__);
+	for (i = 0; i < ARRAY_SIZE(mad_audio_mux_text); i++)
+		if (!strncmp(kcontrol->id.name, mad_audio_mux_text[i],
+			    strlen(mad_audio_mux_text[i])))
+			break;
+
+	if (i-- == ARRAY_SIZE(mad_audio_mux_text)) {
+		WARN(1, "Invalid id name %s\n", kcontrol->id.name);
+		return -EINVAL;
+	}
+
+	port_id = i * 2 + 1 + SLIMBUS_0_RX;
+	switch (ucontrol->value.integer.value[0]) {
+	case MADNONE:
+		mad_type = MAD_HW_NONE;
+		break;
+	case MADAUDIO:
+		mad_type = MAD_HW_AUDIO;
+		break;
+	case MADBEACON:
+		mad_type = MAD_HW_BEACON;
+		break;
+	case MADULTRASOUND:
+		mad_type = MAD_HW_ULTRASOUND;
+		break;
+	default:
+		WARN(1, "Unknown\n");
+		return -EINVAL;
+	}
+
+	pr_debug("%s: port_id 0x%x, mad_type %d\n", __func__, port_id,
+		 mad_type);
+	return afe_port_set_mad_type(port_id, mad_type);
+}
+
 static int msm_routing_get_port_mixer(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
@@ -1734,6 +1868,33 @@
 	0, 1, 0, msm_routing_get_fm_pcmrx_switch_mixer,
 	msm_routing_put_fm_pcmrx_switch_mixer);
 
+static const struct soc_enum lsm_mux_enum =
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mad_audio_mux_text), mad_audio_mux_text);
+static const struct snd_kcontrol_new lsm_mux =
+	SOC_DAPM_ENUM_EXT("LSM1 MUX", lsm_mux_enum,
+			  msm_routing_lsm_mux_get,
+			  msm_routing_lsm_mux_put);
+
+static const char * const lsm_func_text[] = {
+	"None", "AUDIO", "BEACON", "ULTRASOUND"
+};
+static const struct soc_enum lsm_func_enum =
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(lsm_func_text), lsm_func_text);
+static const struct snd_kcontrol_new lsm_function[] = {
+	SOC_ENUM_EXT(SLIMBUS_0_TX_TEXT" "LSM_FUNCTION_TEXT, lsm_func_enum,
+		     msm_routing_lsm_func_get, msm_routing_lsm_func_put),
+	SOC_ENUM_EXT(SLIMBUS_1_TX_TEXT" "LSM_FUNCTION_TEXT, lsm_func_enum,
+		     msm_routing_lsm_func_get, msm_routing_lsm_func_put),
+	SOC_ENUM_EXT(SLIMBUS_2_TX_TEXT" "LSM_FUNCTION_TEXT, lsm_func_enum,
+		     msm_routing_lsm_func_get, msm_routing_lsm_func_put),
+	SOC_ENUM_EXT(SLIMBUS_3_TX_TEXT" "LSM_FUNCTION_TEXT, lsm_func_enum,
+		     msm_routing_lsm_func_get, msm_routing_lsm_func_put),
+	SOC_ENUM_EXT(SLIMBUS_4_TX_TEXT" "LSM_FUNCTION_TEXT, lsm_func_enum,
+		     msm_routing_lsm_func_get, msm_routing_lsm_func_put),
+	SOC_ENUM_EXT(SLIMBUS_5_TX_TEXT" "LSM_FUNCTION_TEXT, lsm_func_enum,
+		     msm_routing_lsm_func_get, msm_routing_lsm_func_put),
+};
+
 static const struct snd_kcontrol_new int_fm_vol_mixer_controls[] = {
 	SOC_SINGLE_EXT_TLV("Internal FM RX Volume", SND_SOC_NOPM, 0,
 	INT_RX_VOL_GAIN, 0, msm_routing_get_fm_vol_mixer,
@@ -2111,6 +2272,9 @@
 		0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("DTMF_DL_HL", "DTMF_RX_HOSTLESS Playback",
 		0, 0, 0, 0),
+	/* LSM */
+	SND_SOC_DAPM_AIF_OUT("LSM_UL_HL", "Listen Audio Service Capture",
+			     0, 0, 0, 0),
 	/* Backend AIF */
 	/* Stream name equals to backend dai link stream name
 	*/
@@ -2156,6 +2320,7 @@
 				0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("SLIMBUS_4_TX", "Slimbus4 Capture",
 				0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("SLIMBUS_5_TX", "Slimbus5 Capture", 0, 0, 0, 0),
 
 	SND_SOC_DAPM_AIF_OUT("AUX_PCM_RX", "AUX PCM Playback", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("AUX_PCM_TX", "AUX PCM Capture", 0, 0, 0, 0),
@@ -2180,6 +2345,10 @@
 				&fm_switch_mixer_controls),
 	SND_SOC_DAPM_SWITCH("PCM_RX_DL_HL", SND_SOC_NOPM, 0, 0,
 				&pcm_rx_switch_mixer_controls),
+
+	/* Mux Definitions */
+	SND_SOC_DAPM_MUX("LSM1 MUX", SND_SOC_NOPM, 0, 0, &lsm_mux),
+
 	/* Mixer definitions */
 	SND_SOC_DAPM_MIXER("PRI_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
 	pri_i2s_rx_mixer_controls, ARRAY_SIZE(pri_i2s_rx_mixer_controls)),
@@ -2514,6 +2683,14 @@
 	{"SLIM1_UL_HL", NULL, "SLIMBUS_1_TX"},
 	{"SLIM3_UL_HL", NULL, "SLIMBUS_3_TX"},
 	{"SLIM4_UL_HL", NULL, "SLIMBUS_4_TX"},
+
+	{"LSM1 MUX", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
+	{"LSM1 MUX", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
+	{"LSM1 MUX", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
+	{"LSM1 MUX", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
+	{"LSM1 MUX", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
+	{"LSM_UL_HL", NULL, "LSM1 MUX"},
+
 	{"INT_FM_RX", NULL, "INTFM_DL_HL"},
 	{"INTFM_UL_HL", NULL, "INT_FM_TX"},
 	{"AUX_PCM_RX", NULL, "AUXPCM_DL_HL"},
@@ -2600,6 +2777,7 @@
 	{"SLIMBUS_1_TX", NULL, "BE_IN" },
 	{"SLIMBUS_3_TX", NULL, "BE_IN" },
 	{"SLIMBUS_4_TX", NULL, "BE_IN" },
+	{"SLIMBUS_5_TX", NULL, "BE_IN" },
 	{"BE_OUT", NULL, "INT_BT_SCO_RX"},
 	{"INT_BT_SCO_TX", NULL, "BE_IN"},
 	{"BE_OUT", NULL, "INT_FM_RX"},
@@ -2821,6 +2999,9 @@
 	snd_soc_add_platform_controls(platform,
 				multi_ch_channel_map_mixer_controls,
 			ARRAY_SIZE(multi_ch_channel_map_mixer_controls));
+
+	snd_soc_add_platform_controls(platform, lsm_function,
+				      ARRAY_SIZE(lsm_function));
 	return 0;
 }
 
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
index 7ecdff3..798f676 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
@@ -51,6 +51,7 @@
 #define LPASS_BE_SLIMBUS_3_TX "SLIMBUS_3_TX"
 #define LPASS_BE_SLIMBUS_4_RX "SLIMBUS_4_RX"
 #define LPASS_BE_SLIMBUS_4_TX "SLIMBUS_4_TX"
+#define LPASS_BE_SLIMBUS_5_TX "SLIMBUS_5_TX"
 
 /* For multimedia front-ends, asm session is allocated dynamically.
  * Hence, asm session/multimedia front-end mapping has to be maintained.
@@ -71,6 +72,7 @@
 	MSM_FRONTEND_DAI_VOICE_STUB,
 	MSM_FRONTEND_DAI_VOLTE,
 	MSM_FRONTEND_DAI_DTMF_RX,
+	MSM_FRONTEND_DAI_LSM1,
 	MSM_FRONTEND_DAI_MAX,
 };
 
@@ -103,6 +105,7 @@
 	MSM_BACKEND_DAI_SLIMBUS_4_TX,
 	MSM_BACKEND_DAI_SLIMBUS_3_RX,
 	MSM_BACKEND_DAI_SLIMBUS_3_TX,
+	MSM_BACKEND_DAI_SLIMBUS_5_TX,
 	MSM_BACKEND_DAI_EXTPROC_RX,
 	MSM_BACKEND_DAI_EXTPROC_TX,
 	MSM_BACKEND_DAI_EXTPROC_EC_TX,
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.h
index d0b119c..a25fb2a 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.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
@@ -11,7 +11,7 @@
  */
 #ifndef _MSM_PCM_VOICE_H
 #define _MSM_PCM_VOICE_H
-#include <sound/apr_audio.h>
+#include <sound/apr_audio-v2.h>
 
 enum {
 	VOICE_SESSION_INDEX,
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 5e1da59..97cd3fc 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -9,7 +9,6 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  */
-
 #include <linux/slab.h>
 #include <linux/debugfs.h>
 #include <linux/kernel.h>
@@ -22,6 +21,7 @@
 #include <sound/apr_audio-v2.h>
 #include <sound/q6afe-v2.h>
 #include <sound/q6audio-v2.h>
+#include "msm-pcm-routing-v2.h"
 
 #include "audio_acdb.h"
 
@@ -47,6 +47,8 @@
 	int vi_tx_port;
 };
 
+static atomic_t afe_ports_mad_type[SLIMBUS_PORT_LAST - SLIMBUS_0_RX];
+
 static struct afe_ctl this_afe;
 
 #define TIMEOUT_MS 1000
@@ -121,6 +123,7 @@
 			case AFE_SERVICE_CMD_SHARED_MEM_UNMAP_REGIONS:
 			case AFE_SERVICE_CMD_UNREGISTER_RT_PORT_DRIVER:
 			case AFE_PORTS_CMD_DTMF_CTL:
+			case AFE_SVC_CMD_SET_PARAM:
 				atomic_set(&this_afe.state, 0);
 				wake_up(&this_afe.wait[data->token]);
 				break;
@@ -218,6 +221,7 @@
 	case SLIMBUS_2_TX:
 	case SLIMBUS_3_TX:
 	case SLIMBUS_4_TX:
+	case SLIMBUS_5_TX:
 	case INT_FM_TX:
 	case VOICE_RECORD_RX:
 	case INT_BT_SCO_TX:
@@ -298,6 +302,37 @@
 	return ret;
 }
 
+/*
+ * afe_apr_send_pkt : returns 0 on success, negative otherwise.
+ */
+static int afe_apr_send_pkt(void *data, wait_queue_head_t *wait)
+{
+	int ret;
+
+	atomic_set(&this_afe.state, 1);
+	atomic_set(&this_afe.status, 0);
+	ret = apr_send_pkt(this_afe.apr, data);
+	if (ret > 0) {
+		if (wait) {
+			ret = wait_event_timeout(*wait,
+					(atomic_read(&this_afe.state) == 0),
+					msecs_to_jiffies(TIMEOUT_MS));
+			if (ret)
+				ret = 0;
+			else
+				ret = -ETIMEDOUT;
+		} else {
+			ret = 0;
+		}
+	} else if (ret == 0) {
+		/* apr_send_pkt can return 0 when nothing is transmitted */
+		ret = -EINVAL;
+	}
+
+	pr_debug("%s: leave %d\n", __func__, ret);
+	return ret;
+}
+
 static void afe_send_cal_block(int32_t path, u16 port_id)
 {
 	int						result = 0;
@@ -350,22 +385,13 @@
 		__func__, port_id, path,
 		cal_block.cal_size, cal_block.cal_paddr);
 
-	atomic_set(&this_afe.state, 1);
-	result = apr_send_pkt(this_afe.apr, (uint32_t *) &afe_cal);
-	if (result < 0) {
-		pr_err("%s: AFE cal for port %d failed\n",
-			__func__, port_id);
-	}
-
-	result = wait_event_timeout(this_afe.wait[index],
-				 (atomic_read(&this_afe.state) == 0),
-				 msecs_to_jiffies(TIMEOUT_MS));
-	if (!result) {
-		pr_err("%s: wait_event timeout SET AFE CAL\n", __func__);
-		goto done;
-	}
-
-	pr_debug("%s: AFE cal sent for path %d device!\n", __func__, path);
+	result = afe_apr_send_pkt(&afe_cal, &this_afe.wait[index]);
+	if (result)
+		pr_err("%s: AFE cal for port %d failed %d\n",
+		       __func__, port_id, result);
+	else
+		pr_debug("%s: AFE cal sent for path %d device!\n", __func__,
+			 path);
 done:
 	return;
 }
@@ -506,14 +532,319 @@
 	}
 }
 
+int afe_turn_onoff_hw_mad(u16 mad_type, u16 enable)
+{
+	int ret;
+	struct afe_cmd_hw_mad_ctrl config;
+
+	pr_debug("%s: enter\n", __func__);
+	memset(&config, 0, sizeof(config));
+	config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					     APR_HDR_LEN(APR_HDR_SIZE),
+					     APR_PKT_VER);
+	config.hdr.pkt_size = sizeof(config);
+	config.hdr.src_port = 0;
+	config.hdr.dest_port = 0;
+	config.hdr.token = IDX_GLOBAL_CFG;
+	config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+	config.param.port_id = SLIMBUS_5_TX;
+	config.param.payload_size = sizeof(config) - sizeof(struct apr_hdr) -
+				    sizeof(config.param);
+	config.param.payload_address_lsw = 0x00;
+	config.param.payload_address_msw = 0x00;
+	config.param.mem_map_handle = 0x00;
+	config.pdata.module_id = AFE_MODULE_HW_MAD;
+	config.pdata.param_id = AFE_PARAM_ID_HW_MAD_CTRL;
+	config.pdata.param_size = sizeof(config.payload);
+	config.payload.minor_version = 1;
+	config.payload.mad_type = mad_type;
+	config.payload.mad_enable = enable;
+
+	ret = afe_apr_send_pkt(&config, &this_afe.wait[IDX_GLOBAL_CFG]);
+	if (ret)
+		pr_err("%s: AFE_PARAM_ID_HW_MAD_CTRL failed %d\n", __func__,
+		       ret);
+	return ret;
+}
+
+static int afe_send_slimbus_slave_cfg(
+	struct afe_param_cdc_slimbus_slave_cfg *sb_slave_cfg)
+{
+	int ret;
+	struct afe_svc_cmd_sb_slave_cfg config;
+
+	pr_debug("%s: enter\n", __func__);
+
+	config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					     APR_HDR_LEN(APR_HDR_SIZE),
+					     APR_PKT_VER);
+	config.hdr.pkt_size = sizeof(config);
+	config.hdr.src_port = 0;
+	config.hdr.dest_port = 0;
+	config.hdr.token = IDX_GLOBAL_CFG;
+	config.hdr.opcode = AFE_SVC_CMD_SET_PARAM;
+	config.param.payload_size = sizeof(config) - sizeof(struct apr_hdr) -
+				    sizeof(config.param);
+	config.param.payload_address_lsw = 0x00;
+	config.param.payload_address_msw = 0x00;
+	config.param.mem_map_handle = 0x00;
+	config.pdata.module_id = AFE_MODULE_CDC_DEV_CFG;
+	config.pdata.param_id = AFE_PARAM_ID_CDC_SLIMBUS_SLAVE_CFG;
+	config.pdata.param_size =
+	    sizeof(struct afe_param_cdc_slimbus_slave_cfg);
+	config.sb_slave_cfg = *sb_slave_cfg;
+
+	ret = afe_apr_send_pkt(&config, &this_afe.wait[IDX_GLOBAL_CFG]);
+	if (ret)
+		pr_err("%s: AFE_PARAM_ID_CDC_SLIMBUS_SLAVE_CFG failed %d\n",
+		       __func__, ret);
+
+	pr_debug("%s: leave %d\n", __func__, ret);
+	return ret;
+}
+
+static int afe_send_codec_reg_config(
+	struct afe_param_cdc_reg_cfg_data *cdc_reg_cfg)
+{
+	int i, ret;
+	int pkt_size, payload_size;
+	struct afe_svc_cmd_cdc_reg_cfg *config;
+	struct afe_svc_cmd_set_param *param;
+
+	pr_debug("%s: enter\n", __func__);
+	payload_size = sizeof(struct afe_param_cdc_reg_cfg_payload) *
+		       cdc_reg_cfg->num_registers;
+	pkt_size = sizeof(*config) + payload_size;
+
+	pr_debug("%s: pkt_size %d, payload %d\n", __func__, pkt_size,
+		 payload_size);
+	config = kzalloc(pkt_size, GFP_KERNEL);
+	if (!config) {
+		pr_warn("%s: Not enought memory, pkt_size %d\n", __func__,
+			pkt_size);
+		return -ENOMEM;
+	}
+
+	config->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					      APR_HDR_LEN(APR_HDR_SIZE),
+					      APR_PKT_VER);
+	config->hdr.pkt_size = pkt_size;
+	config->hdr.src_port = 0;
+	config->hdr.dest_port = 0;
+	config->hdr.token = IDX_GLOBAL_CFG;
+	config->hdr.opcode = AFE_SVC_CMD_SET_PARAM;
+
+	param = &config->param;
+	param->payload_size = payload_size;
+	param->payload_address_lsw = 0x00;
+	param->payload_address_msw = 0x00;
+	param->mem_map_handle = 0x00;
+
+	for (i = 0; i < cdc_reg_cfg->num_registers; i++) {
+		config->reg_data[i].common.module_id = AFE_MODULE_CDC_DEV_CFG;
+		config->reg_data[i].common.param_id = AFE_PARAM_ID_CDC_REG_CFG;
+		config->reg_data[i].common.param_size =
+		    sizeof(config->reg_data[i].reg_cfg);
+		config->reg_data[i].reg_cfg = cdc_reg_cfg->reg_data[i];
+	}
+
+	ret = afe_apr_send_pkt(config, &this_afe.wait[IDX_GLOBAL_CFG]);
+	if (ret)
+		pr_err("%s: AFE_PARAM_ID_CDC_REG_CFG failed %d\n", __func__,
+		       ret);
+
+	kfree(config);
+	pr_debug("%s: leave ret %d\n", __func__, ret);
+	return ret;
+}
+
+static int afe_init_cdc_reg_config(void)
+{
+	int ret;
+	struct afe_svc_cmd_init_cdc_reg_cfg config;
+
+	pr_debug("%s: enter\n", __func__);
+	config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					     APR_HDR_LEN(APR_HDR_SIZE),
+					     APR_PKT_VER);
+	config.hdr.pkt_size = sizeof(config);
+	config.hdr.src_port = 0;
+	config.hdr.dest_port = 0;
+	config.hdr.token = IDX_GLOBAL_CFG;
+	config.hdr.opcode = AFE_SVC_CMD_SET_PARAM;
+
+	config.param.payload_size = sizeof(struct afe_port_param_data_v2);
+	config.param.payload_address_lsw = 0x00;
+	config.param.payload_address_msw = 0x00;
+	config.param.mem_map_handle = 0x00;
+
+	config.init.module_id = AFE_MODULE_CDC_DEV_CFG;
+	config.init.param_id = AFE_PARAM_ID_CDC_REG_CFG_INIT;
+	config.init.param_size = 0;
+
+	ret = afe_apr_send_pkt(&config, &this_afe.wait[IDX_GLOBAL_CFG]);
+	if (ret) {
+		pr_err("%s: AFE_PARAM_ID_CDC_INIT_REG_CFG failed %d\n",
+		       __func__, ret);
+	} else if (atomic_read(&this_afe.status) != 0) {
+		pr_err("%s: config cmd failed\n", __func__);
+		ret = -EINVAL;
+	}
+
+	pr_debug("%s: leave ret %d\n", __func__, 0);
+	return ret;
+}
+
+static int afe_send_slimbus_slave_port_cfg(
+	struct afe_param_slimbus_slave_port_cfg *port_config, u16 port_id)
+{
+	int ret, index;
+	struct afe_cmd_hw_mad_slimbus_slave_port_cfg config;
+
+	pr_debug("%s: enter, port_id %u\n", __func__, port_id);
+	index = q6audio_get_port_index(port_id);
+	if (q6audio_validate_port(port_id) < 0) {
+		pr_err("%s: port id: %#x\n", __func__, port_id);
+		return -EINVAL;
+	}
+
+	config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					     APR_HDR_LEN(APR_HDR_SIZE),
+					     APR_PKT_VER);
+	config.hdr.pkt_size = sizeof(config);
+	config.hdr.src_port = 0;
+	config.hdr.dest_port = 0;
+	config.hdr.token = index;
+	config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+	config.param.port_id = port_id;
+	config.param.payload_size = sizeof(config) - sizeof(struct apr_hdr) -
+				    sizeof(config.param);
+	config.param.payload_address_lsw = 0x00;
+	config.param.payload_address_msw = 0x00;
+	config.param.mem_map_handle = 0x00;
+	config.pdata.module_id = AFE_MODULE_HW_MAD;
+	config.pdata.param_id = AFE_PARAM_ID_SLIMBUS_SLAVE_PORT_CFG;
+	config.pdata.param_size = sizeof(*port_config);
+	config.sb_port_cfg = *port_config;
+
+	ret = afe_apr_send_pkt(&config, &this_afe.wait[index]);
+	if (ret) {
+		pr_err("%s: AFE_PARAM_ID_SLIMBUS_SLAVE_PORT_CFG failed %d\n",
+			__func__, ret);
+	} else if (atomic_read(&this_afe.status) != 0) {
+		pr_err("%s: config cmd failed\n", __func__);
+		ret = -EINVAL;
+	}
+	pr_debug("%s: leave %d\n", __func__, ret);
+	return ret;
+}
+
+int afe_port_set_mad_type(u16 port_id, enum afe_mad_type mad_type)
+{
+	int i;
+
+	i = port_id - SLIMBUS_0_RX;
+	if (i < 0 || i > ARRAY_SIZE(afe_ports_mad_type)) {
+		pr_err("%s: Invalid port_id 0x%x\n", __func__, port_id);
+		return -EINVAL;
+	}
+	atomic_set(&afe_ports_mad_type[i], mad_type);
+	return 0;
+}
+
+enum afe_mad_type afe_port_get_mad_type(u16 port_id)
+{
+	int i;
+
+	i = port_id - SLIMBUS_0_RX;
+	if (i < 0 || i > ARRAY_SIZE(afe_ports_mad_type)) {
+		pr_err("%s: Invalid port_id 0x%x\n", __func__, port_id);
+		return MAD_HW_NONE;
+	}
+	return (enum afe_mad_type) atomic_read(&afe_ports_mad_type[i]);
+}
+
+int afe_set_config(enum afe_config_type config_type, void *config_data, int arg)
+{
+	int ret;
+
+	pr_debug("%s: enter config_type %d\n", __func__, config_type);
+	ret = afe_q6_interface_prepare();
+	if (ret) {
+		pr_err("%s: Q6 interface prepare failed %d\n", __func__, ret);
+		return ret;
+	}
+
+	switch (config_type) {
+	case AFE_SLIMBUS_SLAVE_CONFIG:
+		ret = afe_send_slimbus_slave_cfg(config_data);
+		if (!ret)
+			ret = afe_init_cdc_reg_config();
+		else
+			pr_err("%s: Sending slimbus slave config failed %d\n",
+			       __func__, ret);
+		break;
+	case AFE_CDC_REGISTERS_CONFIG:
+		ret = afe_send_codec_reg_config(config_data);
+		break;
+	case AFE_SLIMBUS_SLAVE_PORT_CONFIG:
+		ret = afe_send_slimbus_slave_port_cfg(config_data, arg);
+		break;
+	default:
+		pr_err("%s: unknown configuration type", __func__);
+		ret = -EINVAL;
+	}
+
+	pr_debug("%s: leave ret %d\n", __func__, ret);
+	return ret;
+}
+
+static int afe_send_cmd_port_start(u16 port_id)
+{
+	struct afe_port_cmd_device_start start;
+	int ret, index;
+
+	pr_debug("%s: enter\n", __func__);
+	index = q6audio_get_port_index(port_id);
+	if (q6audio_validate_port(port_id) < 0) {
+		pr_err("%s: port id: %#x\n", __func__, port_id);
+		return -EINVAL;
+	}
+
+	start.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					    APR_HDR_LEN(APR_HDR_SIZE),
+					    APR_PKT_VER);
+	start.hdr.pkt_size = sizeof(start);
+	start.hdr.src_port = 0;
+	start.hdr.dest_port = 0;
+	start.hdr.token = index;
+	start.hdr.opcode = AFE_PORT_CMD_DEVICE_START;
+	start.port_id = q6audio_get_port_id(port_id);
+	pr_debug("%s: cmd device start opcode[0x%x] port id[0x%x]\n",
+		 __func__, start.hdr.opcode, start.port_id);
+
+	ret = afe_apr_send_pkt(&start, &this_afe.wait[index]);
+	if (ret) {
+		pr_err("%s: AFE enable for port %#x failed %d\n", __func__,
+		       port_id, ret);
+	} else if (this_afe.task != current) {
+		this_afe.task = current;
+		pr_debug("task_name = %s pid = %d\n",
+			 this_afe.task->comm, this_afe.task->pid);
+	}
+
+	pr_debug("%s: leave %d\n", __func__, ret);
+	return ret;
+}
+
 int afe_port_start(u16 port_id, union afe_port_config *afe_config,
 	u32 rate) /* This function is no blocking */
 {
-	struct afe_port_cmd_device_start start;
 	struct afe_audioif_config_command config;
-	int ret;
+	int ret = 0;
 	int cfg_type;
 	int index = 0;
+	enum afe_mad_type mad_type;
 
 	if (!afe_config) {
 		pr_err("%s: Error, no configuration data\n", __func__);
@@ -529,6 +860,7 @@
 		port_id = VIRTUAL_ID_TO_PORTID(port_id);
 
 	pr_debug("%s: port id: %#x\n", __func__, port_id);
+
 	index = q6audio_get_port_index(port_id);
 	if (q6audio_validate_port(port_id) < 0) {
 		pr_err("%s: port id: %#x\n", __func__, port_id);
@@ -539,11 +871,19 @@
 	if (IS_ERR_VALUE(ret))
 		return ret;
 
-	if (q6audio_validate_port(port_id) < 0) {
-		pr_err("%s: Failed : Invalid Port id = %#x\n", __func__,
-				port_id);
-		ret = -EINVAL;
-		goto fail_cmd;
+	afe_send_cal(port_id);
+
+	/* Start SW MAD module */
+	mad_type = afe_port_get_mad_type(port_id);
+	pr_debug("%s: port_id 0x%x, mad_type %d\n", __func__, port_id,
+		 mad_type);
+	if (mad_type != MAD_HW_NONE) {
+		ret = afe_turn_onoff_hw_mad(mad_type, true);
+		if (ret) {
+			pr_err("%s: afe_turn_onoff_hw_mad failed %d\n",
+			       __func__, ret);
+			return ret;
+		}
 	}
 
 	config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
@@ -593,6 +933,7 @@
 	case SLIMBUS_3_TX:
 	case SLIMBUS_4_RX:
 	case SLIMBUS_4_TX:
+	case SLIMBUS_5_TX:
 		cfg_type = AFE_PARAM_ID_SLIMBUS_CONFIG;
 		break;
 	case RT_PROXY_PORT_001_RX:
@@ -623,69 +964,17 @@
 
 	config.port = *afe_config;
 
-	atomic_set(&this_afe.state, 1);
-	atomic_set(&this_afe.status, 0);
-	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &config);
-	if (ret < 0) {
+	ret = afe_apr_send_pkt(&config, &this_afe.wait[index]);
+	if (ret) {
 		pr_err("%s: AFE enable for port %#x failed\n", __func__,
 				port_id);
-		ret = -EINVAL;
 		goto fail_cmd;
-	}
-	ret = wait_event_timeout(this_afe.wait[index],
-				(atomic_read(&this_afe.state) == 0),
-					msecs_to_jiffies(TIMEOUT_MS));
-
-	if (!ret) {
-		pr_err("%s: wait_event timeout IF CONFIG\n", __func__);
-		ret = -EINVAL;
-		goto fail_cmd;
-	}
-	if (atomic_read(&this_afe.status) != 0) {
+	} else if (atomic_read(&this_afe.status) != 0) {
 		pr_err("%s: config cmd failed\n", __func__);
 		ret = -EINVAL;
 		goto fail_cmd;
 	}
-	/* send AFE cal */
-	afe_send_cal(port_id);
-
-	start.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
-				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
-	start.hdr.pkt_size = sizeof(start);
-	start.hdr.src_port = 0;
-	start.hdr.dest_port = 0;
-	start.hdr.token = index;
-	start.hdr.opcode = AFE_PORT_CMD_DEVICE_START;
-	start.port_id = q6audio_get_port_id(port_id);
-	pr_debug("%s: cmd device start opcode[0x%x] port id[0x%x]\n",
-		 __func__, start.hdr.opcode, start.port_id);
-
-	atomic_set(&this_afe.state, 1);
-	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
-
-	if (IS_ERR_VALUE(ret)) {
-		pr_err("%s: AFE enable for port %#x failed\n", __func__,
-				port_id);
-		ret = -EINVAL;
-		goto fail_cmd;
-	}
-
-	ret = wait_event_timeout(this_afe.wait[index],
-				(atomic_read(&this_afe.state) == 0),
-					msecs_to_jiffies(TIMEOUT_MS));
-
-	if (!ret) {
-		pr_err("%s: wait_event timeout PORT START\n", __func__);
-		 ret = -EINVAL;
-		goto fail_cmd;
-	}
-	if (this_afe.task != current)
-		this_afe.task = current;
-
-	pr_debug("task_name = %s pid = %d\n",
-		this_afe.task->comm, this_afe.task->pid);
-
-	return 0;
+	return afe_send_cmd_port_start(port_id);
 
 fail_cmd:
 	return ret;
@@ -725,6 +1014,7 @@
 	case RT_PROXY_PORT_001_TX: return IDX_RT_PROXY_PORT_001_TX;
 	case SLIMBUS_4_RX: return IDX_SLIMBUS_4_RX;
 	case SLIMBUS_4_TX: return IDX_SLIMBUS_4_TX;
+	case SLIMBUS_5_TX: return IDX_SLIMBUS_5_TX;
 	case AFE_PORT_ID_PRIMARY_MI2S_RX:
 		return IDX_AFE_PORT_ID_PRIMARY_MI2S_RX;
 	case AFE_PORT_ID_QUATERNARY_MI2S_RX:
@@ -837,25 +1127,13 @@
 		__func__, config.param.payload_size, config.pdata.param_size,
 		sizeof(config), sizeof(config.param), sizeof(config.port),
 		sizeof(struct apr_hdr), config.pdata.param_id);
-	atomic_set(&this_afe.state, 1);
-	atomic_set(&this_afe.status, 0);
-	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &config);
-	if (ret < 0) {
+
+	ret = afe_apr_send_pkt(&config, &this_afe.wait[index]);
+	if (ret) {
 		pr_err("%s: AFE enable for port %d opcode[0x%x]failed\n",
 			__func__, port_id, cfg_type);
-		ret = -EINVAL;
 		goto fail_cmd;
-	}
-
-	ret = wait_event_timeout(this_afe.wait[index],
-			(atomic_read(&this_afe.state) == 0),
-				msecs_to_jiffies(TIMEOUT_MS));
-	if (!ret) {
-		pr_err("%s: wait_event timeout\n", __func__);
-		ret = -EINVAL;
-		goto fail_cmd;
-	}
-	if (atomic_read(&this_afe.status) != 0) {
+	} else if (atomic_read(&this_afe.status) != 0) {
 		pr_err("%s: config cmd failed\n", __func__);
 		ret = -EINVAL;
 		goto fail_cmd;
@@ -870,24 +1148,14 @@
 	start.port_id = q6audio_get_port_id(port_id);
 	pr_debug("%s: cmd device start opcode[0x%x] port id[0x%x]\n",
 		__func__, start.hdr.opcode, start.port_id);
-	atomic_set(&this_afe.state, 1);
-	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
-	if (ret < 0) {
+
+	ret = afe_apr_send_pkt(&start, &this_afe.wait[index]);
+	if (ret) {
 		pr_err("%s: AFE enable for port %d failed\n", __func__,
 				port_id);
-		ret = -EINVAL;
-		goto fail_cmd;
-	}
-	ret = wait_event_timeout(this_afe.wait[index],
-			(atomic_read(&this_afe.state) == 0),
-				msecs_to_jiffies(TIMEOUT_MS));
-	if (!ret) {
-		pr_err("%s: wait_event timeout\n", __func__);
-		ret = -EINVAL;
 		goto fail_cmd;
 	}
 
-	return 0;
 fail_cmd:
 	return ret;
 }
@@ -934,23 +1202,10 @@
 	lb_cmd.routing_mode = LB_MODE_DEFAULT;
 	lb_cmd.enable = (enable ? 1 : 0);
 	lb_cmd.loopback_cfg_minor_version = AFE_API_VERSION_LOOPBACK_CONFIG;
-	atomic_set(&this_afe.state, 1);
 
-	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &lb_cmd);
-	if (ret < 0) {
-		pr_err("%s: AFE loopback failed\n", __func__);
-		ret = -EINVAL;
-		goto done;
-	}
-	pr_debug("%s: waiting for this_afe.wait[%d]\n", __func__, index);
-	ret = wait_event_timeout(this_afe.wait[index],
-				 (atomic_read(&this_afe.state) == 0),
-				 msecs_to_jiffies(TIMEOUT_MS));
-	if (!ret) {
-		pr_err("%s: wait_event timeout\n", __func__);
-		ret = -EINVAL;
-	}
-done:
+	ret = afe_apr_send_pkt(&lb_cmd, &this_afe.wait[index]);
+	if (ret)
+		pr_err("%s: AFE loopback failed %d\n", __func__, ret);
 	return ret;
 }
 
@@ -1016,24 +1271,13 @@
 	set_param.rx_port_id = port_id;
 	set_param.gain = volume;
 
-	atomic_set(&this_afe.state, 1);
-	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &set_param);
-	if (ret < 0) {
+	ret = afe_apr_send_pkt(&set_param, &this_afe.wait[index]);
+	if (ret) {
 		pr_err("%s: AFE param set failed for port %d\n",
 					__func__, port_id);
-		ret = -EINVAL;
 		goto fail_cmd;
 	}
 
-	ret = wait_event_timeout(this_afe.wait[index],
-				 (atomic_read(&this_afe.state) == 0),
-				 msecs_to_jiffies(TIMEOUT_MS));
-	if (ret < 0) {
-		pr_err("%s: wait_event timeout\n", __func__);
-		ret = -EINVAL;
-		goto fail_cmd;
-	}
-	return 0;
 fail_cmd:
 	return ret;
 }
@@ -1060,9 +1304,8 @@
 	start.port_id = port_id;
 	start.timing = 1;
 
-	atomic_set(&this_afe.state, 1);
-	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
-	if (ret < 0) {
+	ret = afe_apr_send_pkt(&start, NULL);
+	if (ret) {
 		pr_err("%s: AFE enable for port %d failed %d\n",
 		       __func__, port_id, ret);
 		return -EINVAL;
@@ -1095,25 +1338,13 @@
 	start.hdr.opcode = AFE_PSEUDOPORT_CMD_START;
 	start.port_id = port_id;
 	start.timing = 1;
-
 	start.hdr.token = index;
-	atomic_set(&this_afe.state, 1);
-	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
-	if (ret < 0) {
+
+	ret = afe_apr_send_pkt(&start, &this_afe.wait[index]);
+	if (ret)
 		pr_err("%s: AFE enable for port %d failed %d\n",
 		       __func__, port_id, ret);
-		return -EINVAL;
-	}
-
-	ret = wait_event_timeout(this_afe.wait[index],
-				 (atomic_read(&this_afe.state) == 0),
-				 msecs_to_jiffies(TIMEOUT_MS));
-	if (!ret) {
-		pr_err("%s: wait_event timeout\n", __func__);
-		return -EINVAL;
-	}
-
-	return 0;
+	return ret;
 }
 
 int afe_pseudo_port_stop_nowait(u16 port_id)
@@ -1141,17 +1372,13 @@
 	stop.hdr.opcode = AFE_PSEUDOPORT_CMD_STOP;
 	stop.port_id = port_id;
 	stop.reserved = 0;
-
 	stop.hdr.token = index;
-	atomic_set(&this_afe.state, 1);
-	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &stop);
-	if (ret < 0) {
+
+	ret = afe_apr_send_pkt(&stop, NULL);
+	if (ret)
 		pr_err("%s: AFE close failed %d\n", __func__, ret);
-		return -EINVAL;
-	}
 
-	return 0;
-
+	return ret;
 }
 
 int afe_stop_pseudo_port(u16 port_id)
@@ -1180,24 +1407,13 @@
 	stop.hdr.opcode = AFE_PSEUDOPORT_CMD_STOP;
 	stop.port_id = port_id;
 	stop.reserved = 0;
-
 	stop.hdr.token = index;
-	atomic_set(&this_afe.state, 1);
-	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &stop);
-	if (ret < 0) {
+
+	ret = afe_apr_send_pkt(&stop, &this_afe.wait[index]);
+	if (ret)
 		pr_err("%s: AFE close failed %d\n", __func__, ret);
-		return -EINVAL;
-	}
 
-	ret = wait_event_timeout(this_afe.wait[index],
-				 (atomic_read(&this_afe.state) == 0),
-				 msecs_to_jiffies(TIMEOUT_MS));
-	if (!ret) {
-		pr_err("%s: wait_event timeout\n", __func__);
-		return -EINVAL;
-	}
-
-	return 0;
+	return ret;
 }
 
 uint32_t afe_req_mmap_handle(struct afe_audio_client *ac)
@@ -1480,15 +1696,11 @@
 	mregion_pl->shm_addr_msw = 0x00;
 	mregion_pl->mem_size_bytes = dma_buf_sz;
 
-	atomic_set(&this_afe.state, 1);
-	ret = apr_send_pkt(this_afe.apr, (uint32_t *) mmap_region_cmd);
-	if (ret < 0) {
+	ret = afe_apr_send_pkt(mmap_region_cmd, NULL);
+	if (ret)
 		pr_err("%s: AFE memory map cmd failed %d\n",
 		       __func__, ret);
-		ret = -EINVAL;
-		return ret;
-	}
-	return 0;
+	return ret;
 }
 int q6afe_audio_client_buf_free_contiguous(unsigned int dir,
 			struct afe_audio_client *ac)
@@ -1576,24 +1788,11 @@
 	/* Todo */
 	index = mregion.hdr.token = IDX_RSVD_2;
 
-	atomic_set(&this_afe.state, 1);
-	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &mregion);
-	if (ret < 0) {
+	ret = afe_apr_send_pkt(&mregion, &this_afe.wait[index]);
+	if (ret)
 		pr_err("%s: AFE memory unmap cmd failed %d\n",
 		       __func__, ret);
-		ret = -EINVAL;
-		return ret;
-	}
-
-	ret = wait_event_timeout(this_afe.wait[index],
-				 (atomic_read(&this_afe.state) == 0),
-				 msecs_to_jiffies(TIMEOUT_MS));
-	if (!ret) {
-		pr_err("%s: wait_event timeout\n", __func__);
-		ret = -EINVAL;
-		return ret;
-	}
-	return 0;
+	return ret;
 }
 
 int afe_cmd_memory_unmap_nowait(u32 mem_map_handle)
@@ -1623,13 +1822,11 @@
 	mregion.hdr.opcode = AFE_SERVICE_CMD_SHARED_MEM_UNMAP_REGIONS;
 	mregion.mem_map_handle = mem_map_handle;
 
-	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &mregion);
-	if (ret < 0) {
+	ret = afe_apr_send_pkt(&mregion, NULL);
+	if (ret)
 		pr_err("%s: AFE memory unmap cmd failed %d\n",
 			__func__, ret);
-		ret = -EINVAL;
-	}
-	return 0;
+	return ret;
 }
 
 int afe_register_get_events(u16 port_id,
@@ -1675,14 +1872,11 @@
 	rtproxy.port_id = port_id;
 	rtproxy.reserved = 0;
 
-	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &rtproxy);
-	if (ret < 0) {
+	ret = afe_apr_send_pkt(&rtproxy, NULL);
+	if (ret)
 		pr_err("%s: AFE  reg. rtproxy_event failed %d\n",
 			   __func__, ret);
-		ret = -EINVAL;
-		return ret;
-	}
-	return 0;
+	return ret;
 }
 
 int afe_unregister_get_events(u16 port_id)
@@ -1734,24 +1928,11 @@
 		this_afe.rx_private_data = NULL;
 	}
 
-	atomic_set(&this_afe.state, 1);
-	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &rtproxy);
-	if (ret < 0) {
+	ret = afe_apr_send_pkt(&rtproxy, &this_afe.wait[index]);
+	if (ret)
 		pr_err("%s: AFE enable Unreg. rtproxy_event failed %d\n",
 			   __func__, ret);
-		ret = -EINVAL;
-		return ret;
-	}
-
-	ret = wait_event_timeout(this_afe.wait[index],
-				 (atomic_read(&this_afe.state) == 0),
-				 msecs_to_jiffies(TIMEOUT_MS));
-	if (!ret) {
-		pr_err("%s: wait_event timeout\n", __func__);
-		ret = -EINVAL;
-		return ret;
-	}
-	return 0;
+	return ret;
 }
 
 int afe_rt_proxy_port_write(u32 buf_addr_p, u32 mem_map_handle, int bytes)
@@ -1781,14 +1962,11 @@
 	afecmd_wr.available_bytes = bytes;
 	afecmd_wr.reserved = 0;
 
-	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &afecmd_wr);
-	if (ret < 0) {
+	ret = afe_apr_send_pkt(&afecmd_wr, NULL);
+	if (ret)
 		pr_err("%s: AFE rtproxy write to port 0x%x failed %d\n",
 			   __func__, afecmd_wr.port_id, ret);
-		ret = -EINVAL;
-		return ret;
-	}
-	return 0;
+	return ret;
 
 }
 
@@ -1818,14 +1996,11 @@
 	afecmd_rd.available_bytes = bytes;
 	afecmd_rd.mem_map_handle = mem_map_handle;
 
-	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &afecmd_rd);
-	if (ret < 0) {
+	ret = afe_apr_send_pkt(&afecmd_rd, NULL);
+	if (ret)
 		pr_err("%s: AFE rtproxy read  cmd to port 0x%x failed %d\n",
 			   __func__, afecmd_rd.port_id, ret);
-		ret = -EINVAL;
-		return ret;
-	}
-	return 0;
+	return ret;
 }
 
 #ifdef CONFIG_DEBUG_FS
@@ -2102,25 +2277,10 @@
 	cmd_sidetone.routing_mode = LB_MODE_SIDETONE;
 	cmd_sidetone.enable = enable;
 
-	atomic_set(&this_afe.state, 1);
-	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &cmd_sidetone);
-	if (ret < 0) {
+	ret = afe_apr_send_pkt(&cmd_sidetone, &this_afe.wait[index]);
+	if (ret)
 		pr_err("%s: AFE sidetone failed for tx_port:%d rx_port:%d\n",
 					__func__, tx_port_id, rx_port_id);
-		ret = -EINVAL;
-		goto fail_cmd;
-	}
-
-	ret = wait_event_timeout(this_afe.wait[index],
-		(atomic_read(&this_afe.state) == 0),
-			msecs_to_jiffies(TIMEOUT_MS));
-	if (ret < 0) {
-		pr_err("%s: wait_event timeout\n", __func__);
-		ret = -EINVAL;
-		goto fail_cmd;
-	}
-	return 0;
-fail_cmd:
 	return ret;
 }
 
@@ -2217,12 +2377,9 @@
 	stop.port_id = port_id;
 	stop.reserved = 0;
 
-	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &stop);
-
-	if (IS_ERR_VALUE(ret)) {
+	ret = afe_apr_send_pkt(&stop, NULL);
+	if (ret)
 		pr_err("%s: AFE close failed\n", __func__);
-		ret = -EINVAL;
-	}
 
 fail_cmd:
 	return ret;
@@ -2232,10 +2389,10 @@
 int afe_close(int port_id)
 {
 	struct afe_port_cmd_device_stop stop;
+	enum afe_mad_type mad_type;
 	int ret = 0;
 	int index = 0;
 
-
 	if (this_afe.apr == NULL) {
 		pr_err("AFE is already closed\n");
 		ret = -EINVAL;
@@ -2245,9 +2402,25 @@
 
 	port_id = q6audio_convert_virtual_to_portid(port_id);
 	index = q6audio_get_port_index(port_id);
-	if (q6audio_validate_port(port_id) < 0)
+	if (q6audio_validate_port(port_id) < 0) {
+		pr_warn("%s: Not a valid port id 0x0%x\n", __func__, port_id);
 		return -EINVAL;
+	}
 
+	mad_type = afe_port_get_mad_type(port_id);
+	pr_debug("%s: port_id 0x%x, mad_type %d\n", __func__, port_id,
+		 mad_type);
+	if (mad_type != MAD_HW_NONE) {
+		pr_debug("%s: Turn off MAD\n", __func__);
+		ret = afe_turn_onoff_hw_mad(mad_type, false);
+		if (ret) {
+			pr_err("%s: afe_turn_onoff_hw_mad failed %d\n",
+			       __func__, ret);
+			return ret;
+		}
+	} else {
+		pr_debug("%s: Not a MAD port\n", __func__);
+	}
 
 	stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
 				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
@@ -2259,23 +2432,10 @@
 	stop.port_id = q6audio_get_port_id(port_id);
 	stop.reserved = 0;
 
-	atomic_set(&this_afe.state, 1);
-	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &stop);
+	ret = afe_apr_send_pkt(&stop, &this_afe.wait[index]);
+	if (ret)
+		pr_err("%s: AFE close failed %d\n", __func__, ret);
 
-	if (ret < 0) {
-		pr_err("%s: AFE close failed\n", __func__);
-		ret = -EINVAL;
-		goto fail_cmd;
-	}
-
-	ret = wait_event_timeout(this_afe.wait[index],
-			(atomic_read(&this_afe.state) == 0),
-					msecs_to_jiffies(TIMEOUT_MS));
-	if (!ret) {
-		pr_err("%s: wait_event timeout\n", __func__);
-		ret = -EINVAL;
-		goto fail_cmd;
-	}
 fail_cmd:
 	return ret;
 }
diff --git a/sound/soc/msm/qdsp6v2/q6audio-v2.c b/sound/soc/msm/qdsp6v2/q6audio-v2.c
index 4ed0fb7..d3d335d 100644
--- a/sound/soc/msm/qdsp6v2/q6audio-v2.c
+++ b/sound/soc/msm/qdsp6v2/q6audio-v2.c
@@ -44,6 +44,7 @@
 	case SLIMBUS_2_RX: return IDX_SLIMBUS_2_RX;
 	case SLIMBUS_2_TX: return IDX_SLIMBUS_2_TX;
 	case SLIMBUS_4_TX: return IDX_SLIMBUS_4_TX;
+	case SLIMBUS_5_TX: return IDX_SLIMBUS_5_TX;
 	case INT_BT_SCO_RX: return IDX_INT_BT_SCO_RX;
 	case INT_BT_SCO_TX: return IDX_INT_BT_SCO_TX;
 	case INT_BT_A2DP_RX: return IDX_INT_BT_A2DP_RX;
@@ -91,6 +92,7 @@
 	case SLIMBUS_2_RX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_2_RX;
 	case SLIMBUS_2_TX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_2_TX;
 	case SLIMBUS_4_TX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_4_TX;
+	case SLIMBUS_5_TX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_5_TX;
 	case INT_BT_SCO_RX: return AFE_PORT_ID_INTERNAL_BT_SCO_RX;
 	case INT_BT_SCO_TX: return AFE_PORT_ID_INTERNAL_BT_SCO_TX;
 	case INT_BT_A2DP_RX: return AFE_PORT_ID_INTERNAL_BT_A2DP_RX;
@@ -109,7 +111,9 @@
 	case AFE_PORT_ID_SECONDARY_MI2S_TX:
 			     return AFE_PORT_ID_SECONDARY_MI2S_TX;
 
-	default: return -EINVAL;
+	default:
+		pr_warn("%s: Invalid port_id %d\n", __func__, port_id);
+		return -EINVAL;
 	}
 }
 int q6audio_convert_virtual_to_portid(u16 port_id)
@@ -185,6 +189,7 @@
 	case SLIMBUS_2_RX:
 	case SLIMBUS_2_TX:
 	case SLIMBUS_4_TX:
+	case SLIMBUS_5_TX:
 	case INT_BT_SCO_RX:
 	case INT_BT_SCO_TX:
 	case INT_BT_A2DP_RX:
diff --git a/sound/soc/msm/qdsp6v2/q6lsm.c b/sound/soc/msm/qdsp6v2/q6lsm.c
new file mode 100644
index 0000000..f2b531a
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/q6lsm.c
@@ -0,0 +1,813 @@
+/*
+ * Copyright (c) 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
+ * 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/fs.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/miscdevice.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/memory_alloc.h>
+#include <linux/debugfs.h>
+#include <linux/time.h>
+#include <linux/atomic.h>
+#include <sound/apr_audio-v2.h>
+#include <sound/lsm_params.h>
+#include <sound/q6lsm.h>
+#include <asm/ioctls.h>
+#include <mach/memory.h>
+#include <mach/debug_mm.h>
+#include <mach/msm_subsystem_map.h>
+#include "audio_acdb.h"
+
+#define APR_TIMEOUT	(5 * HZ)
+#define LSM_CAL_SIZE	4096
+
+enum {
+	CMD_STATE_CLEARED = 0,
+	CMD_STATE_WAIT_RESP = 1,
+};
+
+enum {
+	LSM_INVALID_SESSION_ID = 0,
+	LSM_MIN_SESSION_ID = 1,
+	LSM_MAX_SESSION_ID = 8,
+};
+
+struct lsm_common {
+	void *apr;
+	atomic_t apr_users;
+	uint32_t lsm_cal_addr;
+	uint32_t lsm_cal_size;
+	uint32_t mmap_handle_for_cal;
+	struct mutex apr_lock;
+};
+
+static struct lsm_common lsm_common;
+
+/*
+ * mmap_handle_p can point either client->sound_model.mem_map_handle or
+ * lsm_common.mmap_handle_for_cal.
+ * mmap_lock must be held while accessing this.
+ */
+static spinlock_t mmap_lock;
+static uint32_t *mmap_handle_p;
+
+static spinlock_t lsm_session_lock;
+static struct lsm_client *lsm_session[LSM_MAX_SESSION_ID + 1];
+
+static int q6lsm_mmapcallback(struct apr_client_data *data, void *priv);
+static int q6lsm_send_cal(struct lsm_client *client);
+static int q6lsm_snd_model_buf_free(struct lsm_client *client);
+
+static int q6lsm_callback(struct apr_client_data *data, void *priv)
+{
+	struct lsm_client *client = (struct lsm_client *)priv;
+	uint32_t token;
+	uint32_t *payload;
+
+	if (!client || !data) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+
+	payload = data->payload;
+	pr_debug("%s: Session %d opcode 0x%x token 0x%x payload size %d\n",
+		__func__, client->session,
+		data->opcode, data->token, data->payload_size);
+
+	if (data->opcode == APR_BASIC_RSP_RESULT) {
+		token = data->token;
+		switch (payload[0]) {
+		case LSM_SESSION_CMD_START:
+		case LSM_SESSION_CMD_STOP:
+		case LSM_SESSION_CMD_SET_PARAMS:
+		case LSM_SESSION_CMD_OPEN_TX:
+		case LSM_SESSION_CMD_CLOSE_TX:
+		case LSM_SESSION_CMD_REGISTER_SOUND_MODEL:
+		case LSM_SESSION_CMD_DEREGISTER_SOUND_MODEL:
+		case LSM_SESSION_CMD_SHARED_MEM_UNMAP_REGIONS:
+			if (token != client->session &&
+			    payload[0] !=
+				LSM_SESSION_CMD_DEREGISTER_SOUND_MODEL) {
+				pr_err("%s: Invalid session %d receivced expected %d\n",
+					__func__, token, client->session);
+				return -EINVAL;
+			}
+			if (atomic_cmpxchg(&client->cmd_state,
+					   CMD_STATE_WAIT_RESP,
+					   CMD_STATE_CLEARED) ==
+					       CMD_STATE_WAIT_RESP)
+				wake_up(&client->cmd_wait);
+			break;
+		default:
+			pr_debug("%s: Unknown command 0x%x\n",
+				__func__, payload[0]);
+			break;
+		}
+		return 0;
+	}
+
+	if (client->cb)
+		client->cb(data->opcode, data->token, data->payload,
+			   client->priv);
+
+	return 0;
+}
+
+static int q6lsm_session_alloc(struct lsm_client *client)
+{
+	unsigned long flags;
+	int n, ret = -ENOMEM;
+
+	spin_lock_irqsave(&lsm_session_lock, flags);
+	for (n = LSM_MIN_SESSION_ID; n <= LSM_MAX_SESSION_ID; n++) {
+		if (!lsm_session[n]) {
+			lsm_session[n] = client;
+			ret = n;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&lsm_session_lock, flags);
+	return ret;
+}
+
+static void q6lsm_session_free(struct lsm_client *client)
+{
+	unsigned long flags;
+
+	pr_debug("%s: Freeing session ID %d\n", __func__, client->session);
+	spin_lock_irqsave(&lsm_session_lock, flags);
+	lsm_session[client->session] = LSM_INVALID_SESSION_ID;
+	spin_unlock_irqrestore(&lsm_session_lock, flags);
+	client->session = LSM_INVALID_SESSION_ID;
+}
+
+static void *q6lsm_mmap_apr_reg(void)
+{
+	if (atomic_inc_return(&lsm_common.apr_users) == 1) {
+		lsm_common.apr =
+		    apr_register("ADSP", "LSM", q6lsm_mmapcallback,
+				 0x0FFFFFFFF, &lsm_common);
+		if (!lsm_common.apr) {
+			pr_debug("%s Unable to register APR LSM common port\n",
+				 __func__);
+			atomic_dec(&lsm_common.apr_users);
+		}
+	}
+
+	return lsm_common.apr;
+}
+
+static int q6lsm_mmap_apr_dereg(void)
+{
+	if (atomic_read(&lsm_common.apr_users) <= 0) {
+		WARN("%s: APR common port already closed\n", __func__);
+	} else {
+		if (atomic_dec_return(&lsm_common.apr_users) == 0) {
+			apr_deregister(lsm_common.apr);
+			pr_debug("%s:APR De-Register common port\n", __func__);
+		}
+	}
+	return 0;
+}
+
+struct lsm_client *q6lsm_client_alloc(app_cb cb, void *priv)
+{
+	struct lsm_client *client;
+	int n;
+
+	pr_debug("%s: enter\n", __func__);
+	client = kzalloc(sizeof(struct lsm_client), GFP_KERNEL);
+	if (!client)
+		return NULL;
+	n = q6lsm_session_alloc(client);
+	if (n <= 0) {
+		kfree(client);
+		return NULL;
+	}
+
+	pr_debug("%s: New client session %d\n", __func__, client->session);
+	client->session = n;
+	client->cb = cb;
+	client->priv = priv;
+	client->apr = apr_register("ADSP", "LSM", q6lsm_callback,
+				   ((client->session) << 8 | 0x0001), client);
+
+	if (client->apr == NULL) {
+		pr_err("%s: Registration with APR failed\n", __func__);
+		goto fail;
+	}
+
+	pr_debug("%s Registering the common port with APR\n", __func__);
+	client->mmap_apr = q6lsm_mmap_apr_reg();
+	if (!client->mmap_apr) {
+		pr_err("%s: APR registration failed\n", __func__);
+		goto fail;
+	}
+
+	init_waitqueue_head(&client->cmd_wait);
+	mutex_init(&client->cmd_lock);
+	atomic_set(&client->cmd_state, CMD_STATE_CLEARED);
+	pr_debug("%s: New client allocated\n", __func__);
+	return client;
+fail:
+	q6lsm_client_free(client);
+	return NULL;
+}
+
+void q6lsm_client_free(struct lsm_client *client)
+{
+	if (!client || !client->session)
+		return;
+
+	apr_deregister(client->apr);
+	client->mmap_apr = NULL;
+	q6lsm_session_free(client);
+	q6lsm_mmap_apr_dereg();
+	mutex_destroy(&client->cmd_lock);
+	kfree(client);
+}
+
+/*
+ * q6lsm_apr_send_pkt : If wait == true, hold mutex to prevent from preempting
+ *			other thread's wait.
+ *			If mmap_handle_p != NULL, disable irq and spin lock to
+ *			protect mmap_handle_p
+ */
+static int q6lsm_apr_send_pkt(struct lsm_client *client, void *handle,
+			      void *data, bool wait, uint32_t *mmap_p)
+{
+	int ret;
+	unsigned long flags = 0;
+
+	pr_debug("%s: enter wait %d\n", __func__, wait);
+	if (wait)
+		mutex_lock(&lsm_common.apr_lock);
+	if (mmap_p) {
+		WARN_ON(!wait);
+		spin_lock_irqsave(&mmap_lock, flags);
+		mmap_handle_p = mmap_p;
+	}
+	atomic_set(&client->cmd_state, CMD_STATE_WAIT_RESP);
+	ret = apr_send_pkt(client->apr, data);
+	if (mmap_p)
+		spin_unlock_irqrestore(&mmap_lock, flags);
+
+	if (ret < 0) {
+		pr_err("%s: apr_send_pkt failed %d\n", __func__, ret);
+	} else if (wait) {
+		ret = wait_event_timeout(client->cmd_wait,
+					 (atomic_read(&client->cmd_state) ==
+					      CMD_STATE_CLEARED),
+					 APR_TIMEOUT);
+		if (likely(ret))
+			ret = 0;
+		else
+			pr_err("%s: wait timedout\n", __func__);
+	} else {
+		ret = 0;
+	}
+	if (wait)
+		mutex_unlock(&lsm_common.apr_lock);
+
+	pr_debug("%s: leave ret %d\n", __func__, ret);
+	return ret;
+}
+
+static void q6lsm_add_hdr(struct lsm_client *client, struct apr_hdr *hdr,
+			uint32_t pkt_size, bool cmd_flg)
+{
+	pr_debug("%s: pkt_size %d cmd_flg %d session %d\n", __func__,
+		pkt_size, cmd_flg, client->session);
+	hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				       APR_HDR_LEN(sizeof(struct apr_hdr)),
+				       APR_PKT_VER);
+	hdr->src_svc = APR_SVC_LSM;
+	hdr->src_domain = APR_DOMAIN_APPS;
+	hdr->dest_svc = APR_SVC_LSM;
+	hdr->dest_domain = APR_DOMAIN_ADSP;
+	hdr->src_port = ((client->session << 8) & 0xFF00) | 0x01;
+	hdr->dest_port = ((client->session << 8) & 0xFF00) | 0x01;
+	hdr->pkt_size = pkt_size;
+	if (cmd_flg)
+		hdr->token = client->session;
+}
+
+int q6lsm_open(struct lsm_client *client)
+{
+	int rc;
+	struct lsm_stream_cmd_open_tx open;
+
+	memset(&open, 0, sizeof(open));
+	q6lsm_add_hdr(client, &open.hdr, sizeof(open), true);
+
+	open.hdr.opcode = LSM_SESSION_CMD_OPEN_TX;
+	open.app_id = 1;
+	open.sampling_rate = 16000;
+
+	rc = q6lsm_apr_send_pkt(client, client->apr, &open, true, NULL);
+	if (rc)
+		pr_err("%s: Open failed opcode 0x%x, rc %d\n",
+		       __func__, open.hdr.opcode, rc);
+
+	pr_debug("%s: leave %d\n", __func__, rc);
+	return rc;
+}
+
+static int q6lsm_set_params(struct lsm_client *client)
+{
+	int rc;
+	struct lsm_cmd_set_params params;
+	struct lsm_params_payload *payload = &params.payload;
+
+	pr_debug("%s: enter\n", __func__);
+	q6lsm_add_hdr(client, &params.hdr, sizeof(params), true);
+
+	params.hdr.opcode = LSM_SESSION_CMD_SET_PARAMS;
+	params.data_payload_addr_lsw = 0;
+	params.data_payload_addr_msw = 0;
+	params.mem_map_handle = 0;
+	params.data_payload_size = sizeof(struct lsm_params_payload);
+
+	payload->op_mode.common.module_id  = LSM_MODULE_ID_VOICE_WAKEUP;
+	payload->op_mode.common.param_id = LSM_PARAM_ID_OPERATION_MODE;
+	payload->op_mode.common.param_size =
+	    sizeof(struct lsm_param_op_mode) - sizeof(payload->op_mode.common);
+	payload->op_mode.common.reserved = 0;
+	payload->op_mode.minor_version = 1;
+	payload->op_mode.mode = client->mode;
+	payload->op_mode.reserved = 0;
+
+	payload->connect_to_port.common.module_id = LSM_MODULE_ID_VOICE_WAKEUP;
+	payload->connect_to_port.common.param_id = LSM_PARAM_ID_CONNECT_TO_PORT;
+	payload->connect_to_port.common.param_size =
+	    sizeof(payload->connect_to_port) - sizeof(payload->op_mode.common);
+	payload->connect_to_port.common.reserved = 0;
+	payload->connect_to_port.minor_version = 1;
+	payload->connect_to_port.port_id = client->connect_to_port;
+	payload->connect_to_port.reserved = 0;
+
+	payload->kwds.common.module_id = LSM_MODULE_ID_VOICE_WAKEUP;
+	payload->kwds.common.param_id = LSM_PARAM_ID_KEYWORD_DETECT_SENSITIVITY;
+	payload->kwds.common.param_size =
+	    sizeof(payload->kwds) - sizeof(payload->op_mode.common);
+	payload->kwds.common.reserved = 0;
+	payload->kwds.minor_version = 1;
+	payload->kwds.keyword_sensitivity = client->kw_sensitivity;
+	payload->kwds.reserved = 0;
+
+	payload->uds.common.module_id = LSM_MODULE_ID_VOICE_WAKEUP;
+	payload->uds.common.param_id = LSM_PARAM_ID_USER_DETECT_SENSITIVITY;
+	payload->uds.common.param_size =
+	    sizeof(payload->uds) - sizeof(payload->op_mode.common);
+	payload->uds.common.reserved = 0;
+	payload->uds.minor_version = 1;
+	payload->uds.user_sensitivity = client->user_sensitivity;
+	payload->uds.reserved = 0;
+
+	rc = q6lsm_apr_send_pkt(client, client->apr, &params, true, NULL);
+	if (rc)
+		pr_err("%s: Failed set_params opcode 0x%x, rc %d\n",
+		       __func__, params.hdr.opcode, rc);
+
+	pr_debug("%s: leave %d\n", __func__, rc);
+	return rc;
+}
+
+int q6lsm_register_sound_model(struct lsm_client *client,
+			       enum lsm_detection_mode mode, u16 minkeyword,
+			       u16 minuser, bool detectfailure)
+{
+	int rc;
+	struct lsm_cmd_reg_snd_model cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	if (mode == LSM_MODE_KEYWORD_ONLY_DETECTION) {
+		client->mode = 0x01;
+	} else if (mode == LSM_MODE_USER_KEYWORD_DETECTION) {
+		client->mode = 0x03;
+	} else {
+		pr_err("%s: Incorrect detection mode %d\n", __func__, mode);
+		return -EINVAL;
+	}
+	client->mode |= detectfailure << 2;
+	client->kw_sensitivity = minkeyword;
+	client->user_sensitivity = minuser;
+	client->connect_to_port = AFE_PORT_ID_SLIMBUS_MULTI_CHAN_5_TX;
+
+	rc = q6lsm_set_params(client);
+	if (rc < 0) {
+		pr_err("%s: Failed to set lsm config params\n", __func__);
+		return rc;
+	}
+	rc = q6lsm_send_cal(client);
+	if (rc < 0) {
+		pr_err("%s: Failed to send calibration data\n", __func__);
+		return rc;
+	}
+
+	q6lsm_add_hdr(client, &cmd.hdr, sizeof(cmd), true);
+	cmd.hdr.opcode = LSM_SESSION_CMD_REGISTER_SOUND_MODEL;
+	cmd.model_addr_lsw = client->sound_model.phys;
+	cmd.model_addr_msw = 0;
+	cmd.model_size = client->sound_model.size;
+	/* read updated mem_map_handle by q6lsm_mmapcallback */
+	rmb();
+	cmd.mem_map_handle = client->sound_model.mem_map_handle;
+
+	pr_debug("%s: lsw %x, size %d, handle %x\n", __func__,
+		 cmd.model_addr_lsw, cmd.model_size, cmd.mem_map_handle);
+	rc = q6lsm_apr_send_pkt(client, client->apr, &cmd, true, NULL);
+	if (rc)
+		pr_err("%s: Failed cmd op[0x%x]rc[%d]\n", __func__,
+		       cmd.hdr.opcode, rc);
+	else
+		pr_debug("%s: Register sound model succeeded\n", __func__);
+
+	return rc;
+}
+
+int q6lsm_deregister_sound_model(struct lsm_client *client)
+{
+	int rc;
+	struct lsm_cmd_reg_snd_model cmd;
+
+	if (!client || !client->apr) {
+		pr_err("APR handle NULL\n");
+		return -EINVAL;
+	}
+	pr_debug("%s: session[%d]", __func__, client->session);
+
+	memset(&cmd, 0, sizeof(cmd));
+	q6lsm_add_hdr(client, &cmd.hdr, sizeof(cmd.hdr), false);
+	cmd.hdr.opcode = LSM_SESSION_CMD_DEREGISTER_SOUND_MODEL;
+
+	rc = q6lsm_apr_send_pkt(client, client->apr, &cmd.hdr, true, NULL);
+	if (rc < 0) {
+		pr_err("%s: Failed cmd opcode 0x%x, rc %d\n", __func__,
+		       cmd.hdr.opcode, rc);
+	} else {
+		pr_debug("%s: Deregister sound model succeeded\n", __func__);
+		q6lsm_snd_model_buf_free(client);
+	}
+
+	return rc;
+}
+
+static void q6lsm_add_mmaphdr(struct lsm_client *client, struct apr_hdr *hdr,
+			      u32 pkt_size, u32 cmd_flg, u32 token)
+{
+	pr_debug("%s:pkt size=%d cmd_flg=%d session=%d\n", __func__, pkt_size,
+		 cmd_flg, client->session);
+	hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				       APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	hdr->src_port = 0x00;
+	hdr->dest_port = client->session;
+	if (cmd_flg)
+		hdr->token = token;
+	hdr->pkt_size = pkt_size;
+	return;
+}
+
+static int q6lsm_memory_map_regions(struct lsm_client *client,
+				    uint32_t dma_addr_p, uint32_t dma_buf_sz,
+				    uint32_t *mmap_p)
+{
+	struct avs_cmd_shared_mem_map_regions *mmap_regions = NULL;
+	struct avs_shared_map_region_payload *mregions = NULL;
+	void *mmap_region_cmd = NULL;
+	void *payload = NULL;
+	int rc;
+	int cmd_size = 0;
+
+	pr_debug("%s: dma_addr_p 0x%x, dma_buf_sz %d, session %d\n",
+		 __func__, dma_addr_p, dma_buf_sz, client->session);
+
+	cmd_size = sizeof(struct avs_cmd_shared_mem_map_regions) +
+		   sizeof(struct avs_shared_map_region_payload);
+
+	mmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL);
+	if (!mmap_region_cmd)
+		return -ENOMEM;
+
+	mmap_regions = (struct avs_cmd_shared_mem_map_regions *)mmap_region_cmd;
+	q6lsm_add_mmaphdr(client, &mmap_regions->hdr, cmd_size, true,
+			  (client->session << 8));
+
+	mmap_regions->hdr.opcode = LSM_SESSION_CMD_SHARED_MEM_MAP_REGIONS;
+	mmap_regions->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
+	mmap_regions->num_regions = 1;
+	mmap_regions->property_flag = 0x00;
+	payload = ((u8 *)mmap_region_cmd +
+		   sizeof(struct avs_cmd_shared_mem_map_regions));
+	mregions = (struct avs_shared_map_region_payload *)payload;
+
+	mregions->shm_addr_lsw = dma_addr_p;
+	mregions->shm_addr_msw = 0;
+	mregions->mem_size_bytes = dma_buf_sz;
+
+	rc = q6lsm_apr_send_pkt(client, client->mmap_apr, mmap_region_cmd,
+				true, mmap_p);
+	if (rc)
+		pr_err("%s: Failed mmap_regions opcode 0x%x, rc %d\n",
+			__func__, mmap_regions->hdr.opcode, rc);
+
+	pr_debug("%s: leave %d\n", __func__, rc);
+	kfree(mmap_region_cmd);
+	return rc;
+}
+
+static int q6lsm_send_cal(struct lsm_client *client)
+{
+	int rc;
+
+	struct lsm_cmd_set_params params;
+	struct acdb_cal_block lsm_cal;
+
+	pr_debug("%s: enter\n", __func__);
+
+	memset(&lsm_cal, 0, sizeof(lsm_cal));
+	get_lsm_cal(&lsm_cal);
+	if (!lsm_cal.cal_size) {
+		pr_err("%s: Could not get LSM calibration data\n", __func__);
+		rc = -EINVAL;
+		goto bail;
+	}
+
+	/* Cache mmap address, only map once or if new addr */
+	if ((lsm_common.lsm_cal_addr != lsm_cal.cal_paddr) ||
+	    (lsm_cal.cal_size > lsm_common.lsm_cal_size)) {
+		if (lsm_common.lsm_cal_addr != 0)
+			afe_cmd_memory_unmap(lsm_cal.cal_paddr);
+
+		rc = q6lsm_memory_map_regions(client, lsm_cal.cal_paddr,
+					      LSM_CAL_SIZE,
+					      &lsm_common.mmap_handle_for_cal);
+		if (rc < 0) {
+			pr_err("%s: Calibration data memory map failed\n",
+			       __func__);
+			goto bail;
+		}
+		lsm_common.lsm_cal_addr = lsm_cal.cal_paddr;
+		lsm_common.lsm_cal_size = LSM_CAL_SIZE;
+	}
+
+	q6lsm_add_hdr(client, &params.hdr, sizeof(params), true);
+	params.hdr.opcode = LSM_SESSION_CMD_SET_PARAMS;
+	params.data_payload_addr_lsw = lsm_cal.cal_paddr;
+	params.data_payload_addr_msw = 0;
+	/* read updated mem_map_handle by q6lsm_mmapcallback */
+	rmb();
+	params.mem_map_handle = lsm_common.mmap_handle_for_cal;
+	params.data_payload_size = lsm_cal.cal_size;
+
+	rc = q6lsm_apr_send_pkt(client, client->apr, &params, true, NULL);
+	if (rc)
+		pr_err("%s: Failed set_params opcode 0x%x, rc %d\n",
+		       __func__, params.hdr.opcode, rc);
+bail:
+	return rc;
+}
+
+static int q6lsm_memory_unmap_regions(struct lsm_client *client)
+{
+	struct avs_cmd_shared_mem_unmap_regions unmap;
+	int rc = 0;
+	int cmd_size = 0;
+
+	cmd_size = sizeof(struct avs_cmd_shared_mem_unmap_regions);
+	q6lsm_add_mmaphdr(client, &unmap.hdr, cmd_size,
+			  true, (client->session << 8));
+	unmap.hdr.opcode = LSM_SESSION_CMD_SHARED_MEM_UNMAP_REGIONS;
+	unmap.mem_map_handle = client->sound_model.mem_map_handle;
+
+	pr_debug("%s: unmap handle 0x%x\n", __func__, unmap.mem_map_handle);
+	rc = q6lsm_apr_send_pkt(client, client->mmap_apr, &unmap, true,
+				NULL);
+	if (rc)
+		pr_err("%s: Failed mmap_regions opcode 0x%x rc %d\n",
+		       __func__, unmap.hdr.opcode, rc);
+
+	return rc;
+}
+
+static int q6lsm_snd_model_buf_free(struct lsm_client *client)
+{
+	int rc;
+
+	pr_debug("%s: Session id %d\n", __func__, client->session);
+	mutex_lock(&client->cmd_lock);
+	rc = q6lsm_memory_unmap_regions(client);
+	if (rc < 0) {
+		pr_err("%s CMD Memory_unmap_regions failed\n", __func__);
+	} else if (client->sound_model.data) {
+		ion_unmap_kernel(client->sound_model.client,
+				 client->sound_model.handle);
+		ion_free(client->sound_model.client,
+			 client->sound_model.handle);
+		ion_client_destroy(client->sound_model.client);
+		client->sound_model.data = NULL;
+		client->sound_model.phys = 0;
+	}
+	mutex_unlock(&client->cmd_lock);
+	return rc;
+}
+
+static struct lsm_client *q6lsm_get_lsm_client(int session_id)
+{
+	unsigned long flags;
+	struct lsm_client *client = NULL;
+
+	spin_lock_irqsave(&lsm_session_lock, flags);
+	if (session_id < LSM_MIN_SESSION_ID || session_id > LSM_MAX_SESSION_ID)
+		pr_err("%s: Invalid session %d\n", __func__, session_id);
+	else if (!lsm_session[session_id])
+		pr_err("%s: Not an active session %d\n", __func__, session_id);
+	else
+		client = lsm_session[session_id];
+	spin_unlock_irqrestore(&lsm_session_lock, flags);
+
+	return client;
+}
+
+/*
+ * q6lsm_mmapcallback : atomic context
+ */
+static int q6lsm_mmapcallback(struct apr_client_data *data, void *priv)
+{
+	unsigned long flags;
+	uint32_t sid = 0;
+	const uint32_t *payload = data->payload;
+	const uint32_t command = payload[0];
+	const uint32_t retcode = payload[1];
+	struct lsm_client *client = NULL;
+
+	pr_debug("%s: opcode 0x%x command 0x%x return code 0x%x\n", __func__,
+		 data->opcode, command, retcode);
+
+	sid = (data->token >> 8) & 0x0F;
+	client = q6lsm_get_lsm_client(sid);
+	if (!client) {
+		pr_debug("%s: Session %d already freed\n", __func__, sid);
+		return 0;
+	}
+
+	switch (data->opcode) {
+	case LSM_SESSION_CMDRSP_SHARED_MEM_MAP_REGIONS:
+		if (atomic_read(&client->cmd_state) == CMD_STATE_WAIT_RESP) {
+			spin_lock_irqsave(&mmap_lock, flags);
+			*mmap_handle_p = command;
+			/* spin_unlock_irqrestore implies barrier */
+			spin_unlock_irqrestore(&mmap_lock, flags);
+			atomic_set(&client->cmd_state, CMD_STATE_CLEARED);
+			wake_up(&client->cmd_wait);
+		}
+		break;
+	case APR_BASIC_RSP_RESULT:
+		if (command == LSM_SESSION_CMD_SHARED_MEM_UNMAP_REGIONS) {
+			atomic_set(&client->cmd_state, CMD_STATE_CLEARED);
+			wake_up(&client->cmd_wait);
+		} else {
+			pr_warn("%s: Unexpected command 0x%x\n", __func__,
+				command);
+		}
+		break;
+	default:
+		pr_debug("%s: command 0x%x return code 0x%x\n",
+			 __func__, command, retcode);
+		break;
+	}
+	if (client->cb)
+		client->cb(data->opcode, data->token,
+			   data->payload, client->priv);
+	return 0;
+}
+
+int q6lsm_snd_model_buf_alloc(struct lsm_client *client, uint32_t len)
+{
+	int rc = -EINVAL;
+
+	if (!client)
+		goto fail;
+
+	mutex_lock(&client->cmd_lock);
+	if (!client->sound_model.data) {
+		client->sound_model.client =
+		    msm_ion_client_create(UINT_MAX, "lsm_client");
+		if (IS_ERR_OR_NULL(client->sound_model.client)) {
+			pr_err("%s: ION create client for AUDIO failed\n",
+			       __func__);
+			goto fail;
+		}
+		client->sound_model.handle =
+			ion_alloc(client->sound_model.client,
+				  len, SZ_4K, (0x1 << ION_AUDIO_HEAP_ID), 0);
+		if (IS_ERR_OR_NULL(client->sound_model.handle)) {
+			pr_err("%s: ION memory allocation for AUDIO failed\n",
+			       __func__);
+			goto fail;
+		}
+
+		rc = ion_phys(client->sound_model.client,
+			      client->sound_model.handle,
+			      (ion_phys_addr_t *)&client->sound_model.phys,
+			      (size_t *)&len);
+		if (rc) {
+			pr_err("%s: ION get physical mem failed, rc%d\n",
+			       __func__, rc);
+			goto fail;
+		}
+
+		client->sound_model.data =
+		    ion_map_kernel(client->sound_model.client,
+				   client->sound_model.handle);
+		if (IS_ERR_OR_NULL(client->sound_model.data)) {
+			pr_err("%s: ION memory mapping failed\n", __func__);
+			goto fail;
+		}
+		memset(client->sound_model.data, 0, len);
+		client->sound_model.size = len;
+	} else {
+		rc = -EBUSY;
+		goto fail;
+	}
+	mutex_unlock(&client->cmd_lock);
+
+	rc = q6lsm_memory_map_regions(client, client->sound_model.phys,
+				      client->sound_model.size,
+				      &client->sound_model.mem_map_handle);
+	if (rc < 0) {
+		pr_err("%s:CMD Memory_map_regions failed\n", __func__);
+		goto fail;
+	}
+
+	return 0;
+fail:
+	q6lsm_snd_model_buf_free(client);
+	return rc;
+}
+
+static int q6lsm_cmd(struct lsm_client *client, int opcode, bool wait)
+{
+	struct apr_hdr hdr;
+	int rc;
+
+	pr_debug("%s: enter opcode %d wait %d\n", __func__, opcode, wait);
+	q6lsm_add_hdr(client, &hdr, sizeof(hdr), true);
+	switch (opcode) {
+	case LSM_SESSION_CMD_START:
+	case LSM_SESSION_CMD_STOP:
+	case LSM_SESSION_CMD_CLOSE_TX:
+		hdr.opcode = opcode;
+		break;
+	default:
+		pr_err("%s: Invalid opcode %d\n", __func__, opcode);
+		return -EINVAL;
+	}
+	rc = q6lsm_apr_send_pkt(client, client->apr, &hdr, wait, NULL);
+	if (rc)
+		pr_err("%s: Failed commmand 0x%x\n", __func__, hdr.opcode);
+
+	pr_debug("%s: leave %d\n", __func__, rc);
+	return rc;
+}
+
+int q6lsm_start(struct lsm_client *client, bool wait)
+{
+	return q6lsm_cmd(client, LSM_SESSION_CMD_START, wait);
+}
+
+int q6lsm_stop(struct lsm_client *client, bool wait)
+{
+	return q6lsm_cmd(client, LSM_SESSION_CMD_STOP, wait);
+}
+
+int q6lsm_close(struct lsm_client *client)
+{
+	return q6lsm_cmd(client, LSM_SESSION_CMD_CLOSE_TX, true);
+}
+
+static int __init q6lsm_init(void)
+{
+	pr_debug("%s\n", __func__);
+	spin_lock_init(&lsm_session_lock);
+	spin_lock_init(&mmap_lock);
+	mutex_init(&lsm_common.apr_lock);
+	return 0;
+}
+
+device_initcall(q6lsm_init);